blob: 82f02702ddec3446b224fdbc0bee2b8620df822b [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
daniel@transgaming.comcde6a612012-02-17 18:01:10 +00002// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Program.cpp: Implements the gl::Program class. Implements GL program objects
8// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
9
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000010#include "libGLESv2/Program.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000011#include "libGLESv2/ProgramBinary.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000012
alokp@chromium.orgea0e1af2010-03-22 19:33:14 +000013#include "common/debug.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000014
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000015#include "libGLESv2/main.h"
16#include "libGLESv2/Shader.h"
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +000017#include "libGLESv2/utilities.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000018
daniel@transgaming.com87891f72011-06-01 15:28:35 +000019#include <string>
20
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000021namespace gl
22{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000023const char * const g_fakepath = "C:\\fakepath";
24
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +000025AttributeBindings::AttributeBindings()
26{
27}
28
29AttributeBindings::~AttributeBindings()
30{
apatrick@chromium.org9a30b092012-06-06 20:21:55 +000031}
32
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000033InfoLog::InfoLog() : mInfoLog(NULL)
34{
35}
36
37InfoLog::~InfoLog()
38{
39 delete[] mInfoLog;
40}
41
42
43int InfoLog::getLength() const
44{
45 if (!mInfoLog)
46 {
47 return 0;
48 }
49 else
50 {
51 return strlen(mInfoLog) + 1;
52 }
53}
54
55void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog)
56{
57 int index = 0;
58
59 if (bufSize > 0)
60 {
61 if (mInfoLog)
62 {
63 index = std::min(bufSize - 1, (int)strlen(mInfoLog));
64 memcpy(infoLog, mInfoLog, index);
65 }
66
67 infoLog[index] = '\0';
68 }
69
70 if (length)
71 {
72 *length = index;
73 }
74}
75
76// append a santized message to the program info log.
77// The D3D compiler includes a fake file path in some of the warning or error
78// messages, so lets remove all occurrences of this fake file path from the log.
79void InfoLog::appendSanitized(const char *message)
80{
81 std::string msg(message);
82
83 size_t found;
84 do
85 {
86 found = msg.find(g_fakepath);
87 if (found != std::string::npos)
88 {
89 msg.erase(found, strlen(g_fakepath));
90 }
91 }
92 while (found != std::string::npos);
93
94 append("%s\n", msg.c_str());
95}
96
97void InfoLog::append(const char *format, ...)
98{
99 if (!format)
100 {
101 return;
102 }
103
104 char info[1024];
105
106 va_list vararg;
107 va_start(vararg, format);
108 vsnprintf(info, sizeof(info), format, vararg);
109 va_end(vararg);
110
111 size_t infoLength = strlen(info);
112
113 if (!mInfoLog)
114 {
115 mInfoLog = new char[infoLength + 1];
116 strcpy(mInfoLog, info);
117 }
118 else
119 {
120 size_t logLength = strlen(mInfoLog);
121 char *newLog = new char[logLength + infoLength + 1];
122 strcpy(newLog, mInfoLog);
123 strcpy(newLog + logLength, info);
124
125 delete[] mInfoLog;
126 mInfoLog = newLog;
127 }
128}
129
130void InfoLog::reset()
131{
132 if (mInfoLog)
133 {
134 delete [] mInfoLog;
135 mInfoLog = NULL;
136 }
137}
138
daniel@transgaming.com39c9d952012-07-24 18:32:29 +0000139Program::Program(ResourceManager *manager, GLuint handle) : mResourceManager(manager), mHandle(handle)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000140{
141 mFragmentShader = NULL;
142 mVertexShader = NULL;
143 mProgramBinary = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000144 mDeleteStatus = false;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000145 mRefCount = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000146}
147
148Program::~Program()
149{
150 unlink(true);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000151
152 if (mVertexShader != NULL)
153 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000154 mVertexShader->release();
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000155 }
156
157 if (mFragmentShader != NULL)
158 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000159 mFragmentShader->release();
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000160 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000161}
162
163bool Program::attachShader(Shader *shader)
164{
165 if (shader->getType() == GL_VERTEX_SHADER)
166 {
167 if (mVertexShader)
168 {
169 return false;
170 }
171
172 mVertexShader = (VertexShader*)shader;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000173 mVertexShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000174 }
175 else if (shader->getType() == GL_FRAGMENT_SHADER)
176 {
177 if (mFragmentShader)
178 {
179 return false;
180 }
181
182 mFragmentShader = (FragmentShader*)shader;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000183 mFragmentShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000184 }
185 else UNREACHABLE();
186
187 return true;
188}
189
190bool Program::detachShader(Shader *shader)
191{
192 if (shader->getType() == GL_VERTEX_SHADER)
193 {
194 if (mVertexShader != shader)
195 {
196 return false;
197 }
198
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000199 mVertexShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000200 mVertexShader = NULL;
201 }
202 else if (shader->getType() == GL_FRAGMENT_SHADER)
203 {
204 if (mFragmentShader != shader)
205 {
206 return false;
207 }
208
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000209 mFragmentShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000210 mFragmentShader = NULL;
211 }
212 else UNREACHABLE();
213
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000214 return true;
215}
216
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000217int Program::getAttachedShadersCount() const
218{
219 return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
220}
221
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000222void AttributeBindings::bindAttributeLocation(GLuint index, const char *name)
223{
224 if (index < MAX_VERTEX_ATTRIBS)
225 {
226 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
227 {
228 mAttributeBinding[i].erase(name);
229 }
230
231 mAttributeBinding[index].insert(name);
232 }
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000233}
234
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000235void Program::bindAttributeLocation(GLuint index, const char *name)
236{
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000237 mAttributeBindings.bindAttributeLocation(index, name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000238}
239
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000240// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
241// compiling them into binaries, determining the attribute mappings, and collecting
242// a list of uniforms
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000243void Program::link()
244{
245 unlink(false);
246
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000247 mInfoLog.reset();
248
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000249 mProgramBinary = new ProgramBinary;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000250 if (!mProgramBinary->link(mInfoLog, mAttributeBindings, mFragmentShader, mVertexShader))
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000251 {
252 unlink(false);
253 }
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000254}
255
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000256int AttributeBindings::getAttributeBinding(const std::string &name) const
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000257{
258 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
259 {
260 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
261 {
262 return location;
263 }
264 }
265
266 return -1;
267}
268
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +0000269// Returns the program object to an unlinked state, before re-linking, or at destruction
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000270void Program::unlink(bool destroy)
271{
272 if (destroy) // Object being destructed
273 {
274 if (mFragmentShader)
275 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000276 mFragmentShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000277 mFragmentShader = NULL;
278 }
279
280 if (mVertexShader)
281 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000282 mVertexShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000283 mVertexShader = NULL;
284 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000285 }
286
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000287 if (mProgramBinary)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000288 {
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000289 delete mProgramBinary;
290 mProgramBinary = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000291 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000292}
293
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000294ProgramBinary* Program::getProgramBinary()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000295{
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000296 return mProgramBinary;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000297}
298
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000299void Program::setProgramBinary(const void *binary, GLsizei length)
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000300{
301 unlink(false);
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000302
303 mInfoLog.reset();
304
305 mProgramBinary = new ProgramBinary;
306 if (!mProgramBinary->load(mInfoLog, binary, length))
307 {
308 delete mProgramBinary;
309 mProgramBinary = NULL;
310 }
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000311}
312
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000313void Program::release()
314{
315 mRefCount--;
316
317 if (mRefCount == 0 && mDeleteStatus)
318 {
319 mResourceManager->deleteProgram(mHandle);
320 }
321}
322
323void Program::addRef()
324{
325 mRefCount++;
326}
327
328unsigned int Program::getRefCount() const
329{
330 return mRefCount;
331}
332
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000333GLint Program::getProgramBinaryLength() const
334{
335 if (mProgramBinary)
336 {
337 return mProgramBinary->getLength();
338 }
339 else
340 {
341 return 0;
342 }
343}
344
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000345int Program::getInfoLogLength() const
346{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000347 return mInfoLog.getLength();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000348}
349
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000350void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
351{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000352 return mInfoLog.getLog(bufSize, length, infoLog);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000353}
354
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000355void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
356{
357 int total = 0;
358
359 if (mVertexShader)
360 {
361 if (total < maxCount)
362 {
363 shaders[total] = mVertexShader->getHandle();
364 }
365
366 total++;
367 }
368
369 if (mFragmentShader)
370 {
371 if (total < maxCount)
372 {
373 shaders[total] = mFragmentShader->getHandle();
374 }
375
376 total++;
377 }
378
379 if (count)
380 {
381 *count = total;
382 }
383}
384
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000385void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
386{
387 if (mProgramBinary)
388 {
389 mProgramBinary->getActiveAttribute(index, bufsize, length, size, type, name);
390 }
391 else
392 {
393 if (bufsize > 0)
394 {
395 name[0] = '\0';
396 }
397
398 if (length)
399 {
400 *length = 0;
401 }
402
403 *type = GL_NONE;
404 *size = 1;
405 }
406}
407
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000408GLint Program::getActiveAttributeCount()
409{
410 if (mProgramBinary)
411 {
412 return mProgramBinary->getActiveAttributeCount();
413 }
414 else
415 {
416 return 0;
417 }
418}
419
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000420GLint Program::getActiveAttributeMaxLength()
421{
422 if (mProgramBinary)
423 {
424 return mProgramBinary->getActiveAttributeMaxLength();
425 }
426 else
427 {
428 return 0;
429 }
430}
431
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000432void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
433{
434 if (mProgramBinary)
435 {
436 return mProgramBinary->getActiveUniform(index, bufsize, length, size, type, name);
437 }
438 else
439 {
440 if (bufsize > 0)
441 {
442 name[0] = '\0';
443 }
444
445 if (length)
446 {
447 *length = 0;
448 }
449
450 *size = 0;
451 *type = GL_NONE;
452 }
453}
454
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000455GLint Program::getActiveUniformCount()
456{
457 if (mProgramBinary)
458 {
459 return mProgramBinary->getActiveUniformCount();
460 }
461 else
462 {
463 return 0;
464 }
465}
466
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000467GLint Program::getActiveUniformMaxLength()
468{
469 if (mProgramBinary)
470 {
471 return mProgramBinary->getActiveUniformMaxLength();
472 }
473 else
474 {
475 return 0;
476 }
477}
478
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000479void Program::flagForDeletion()
480{
481 mDeleteStatus = true;
482}
483
484bool Program::isFlaggedForDeletion() const
485{
486 return mDeleteStatus;
487}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +0000488
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000489void Program::validate()
490{
491 mInfoLog.reset();
492
493 if (mProgramBinary)
494 {
495 mProgramBinary->validate(mInfoLog);
496 }
497 else
498 {
499 mInfoLog.append("Program has not been successfully linked.");
500 }
501}
502
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000503bool Program::isValidated() const
504{
505 if (mProgramBinary)
506 {
507 return mProgramBinary->isValidated();
508 }
509 else
510 {
511 return false;
512 }
513}
514
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000515}