blob: 97d372a27a3bec6fc43376b8c7ce11e83b8bad20 [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
daniel@transgaming.com4fa08332010-05-11 02:29:27 +000025unsigned int Program::mCurrentSerial = 1;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +000026
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +000027AttributeBindings::AttributeBindings()
28{
29}
30
31AttributeBindings::~AttributeBindings()
32{
apatrick@chromium.org9a30b092012-06-06 20:21:55 +000033}
34
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000035InfoLog::InfoLog() : mInfoLog(NULL)
36{
37}
38
39InfoLog::~InfoLog()
40{
41 delete[] mInfoLog;
42}
43
44
45int InfoLog::getLength() const
46{
47 if (!mInfoLog)
48 {
49 return 0;
50 }
51 else
52 {
53 return strlen(mInfoLog) + 1;
54 }
55}
56
57void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog)
58{
59 int index = 0;
60
61 if (bufSize > 0)
62 {
63 if (mInfoLog)
64 {
65 index = std::min(bufSize - 1, (int)strlen(mInfoLog));
66 memcpy(infoLog, mInfoLog, index);
67 }
68
69 infoLog[index] = '\0';
70 }
71
72 if (length)
73 {
74 *length = index;
75 }
76}
77
78// append a santized message to the program info log.
79// The D3D compiler includes a fake file path in some of the warning or error
80// messages, so lets remove all occurrences of this fake file path from the log.
81void InfoLog::appendSanitized(const char *message)
82{
83 std::string msg(message);
84
85 size_t found;
86 do
87 {
88 found = msg.find(g_fakepath);
89 if (found != std::string::npos)
90 {
91 msg.erase(found, strlen(g_fakepath));
92 }
93 }
94 while (found != std::string::npos);
95
96 append("%s\n", msg.c_str());
97}
98
99void InfoLog::append(const char *format, ...)
100{
101 if (!format)
102 {
103 return;
104 }
105
106 char info[1024];
107
108 va_list vararg;
109 va_start(vararg, format);
110 vsnprintf(info, sizeof(info), format, vararg);
111 va_end(vararg);
112
113 size_t infoLength = strlen(info);
114
115 if (!mInfoLog)
116 {
117 mInfoLog = new char[infoLength + 1];
118 strcpy(mInfoLog, info);
119 }
120 else
121 {
122 size_t logLength = strlen(mInfoLog);
123 char *newLog = new char[logLength + infoLength + 1];
124 strcpy(newLog, mInfoLog);
125 strcpy(newLog + logLength, info);
126
127 delete[] mInfoLog;
128 mInfoLog = newLog;
129 }
130}
131
132void InfoLog::reset()
133{
134 if (mInfoLog)
135 {
136 delete [] mInfoLog;
137 mInfoLog = NULL;
138 }
139}
140
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000141Program::Program(ResourceManager *manager, GLuint handle) : mResourceManager(manager), mHandle(handle), mSerial(issueSerial())
142{
143 mFragmentShader = NULL;
144 mVertexShader = NULL;
145 mProgramBinary = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000146 mDeleteStatus = false;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000147 mRefCount = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000148}
149
150Program::~Program()
151{
152 unlink(true);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000153
154 if (mVertexShader != NULL)
155 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000156 mVertexShader->release();
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000157 }
158
159 if (mFragmentShader != NULL)
160 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000161 mFragmentShader->release();
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000162 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000163}
164
165bool Program::attachShader(Shader *shader)
166{
167 if (shader->getType() == GL_VERTEX_SHADER)
168 {
169 if (mVertexShader)
170 {
171 return false;
172 }
173
174 mVertexShader = (VertexShader*)shader;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000175 mVertexShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000176 }
177 else if (shader->getType() == GL_FRAGMENT_SHADER)
178 {
179 if (mFragmentShader)
180 {
181 return false;
182 }
183
184 mFragmentShader = (FragmentShader*)shader;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000185 mFragmentShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000186 }
187 else UNREACHABLE();
188
189 return true;
190}
191
192bool Program::detachShader(Shader *shader)
193{
194 if (shader->getType() == GL_VERTEX_SHADER)
195 {
196 if (mVertexShader != shader)
197 {
198 return false;
199 }
200
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000201 mVertexShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000202 mVertexShader = NULL;
203 }
204 else if (shader->getType() == GL_FRAGMENT_SHADER)
205 {
206 if (mFragmentShader != shader)
207 {
208 return false;
209 }
210
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000211 mFragmentShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000212 mFragmentShader = NULL;
213 }
214 else UNREACHABLE();
215
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000216 return true;
217}
218
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000219int Program::getAttachedShadersCount() const
220{
221 return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
222}
223
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000224void AttributeBindings::bindAttributeLocation(GLuint index, const char *name)
225{
226 if (index < MAX_VERTEX_ATTRIBS)
227 {
228 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
229 {
230 mAttributeBinding[i].erase(name);
231 }
232
233 mAttributeBinding[index].insert(name);
234 }
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000235}
236
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000237void Program::bindAttributeLocation(GLuint index, const char *name)
238{
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000239 mAttributeBindings.bindAttributeLocation(index, name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000240}
241
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000242// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
243// compiling them into binaries, determining the attribute mappings, and collecting
244// a list of uniforms
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000245void Program::link()
246{
247 unlink(false);
248
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000249 mInfoLog.reset();
250
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000251 mProgramBinary = new ProgramBinary;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000252 if (!mProgramBinary->link(mInfoLog, mAttributeBindings, mFragmentShader, mVertexShader))
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000253 {
254 unlink(false);
255 }
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000256}
257
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000258int AttributeBindings::getAttributeBinding(const std::string &name) const
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000259{
260 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
261 {
262 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
263 {
264 return location;
265 }
266 }
267
268 return -1;
269}
270
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +0000271// Returns the program object to an unlinked state, before re-linking, or at destruction
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000272void Program::unlink(bool destroy)
273{
274 if (destroy) // Object being destructed
275 {
276 if (mFragmentShader)
277 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000278 mFragmentShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000279 mFragmentShader = NULL;
280 }
281
282 if (mVertexShader)
283 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000284 mVertexShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000285 mVertexShader = NULL;
286 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000287 }
288
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000289 if (mProgramBinary)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000290 {
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000291 delete mProgramBinary;
292 mProgramBinary = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000293 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000294}
295
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000296ProgramBinary* Program::getProgramBinary()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000297{
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000298 return mProgramBinary;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000299}
300
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000301void Program::setProgramBinary(const void *binary, GLsizei length)
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000302{
303 unlink(false);
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000304
305 mInfoLog.reset();
306
307 mProgramBinary = new ProgramBinary;
308 if (!mProgramBinary->load(mInfoLog, binary, length))
309 {
310 delete mProgramBinary;
311 mProgramBinary = NULL;
312 }
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000313}
314
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000315void Program::release()
316{
317 mRefCount--;
318
319 if (mRefCount == 0 && mDeleteStatus)
320 {
321 mResourceManager->deleteProgram(mHandle);
322 }
323}
324
325void Program::addRef()
326{
327 mRefCount++;
328}
329
330unsigned int Program::getRefCount() const
331{
332 return mRefCount;
333}
334
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000335unsigned int Program::getSerial() const
336{
337 return mSerial;
338}
339
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000340GLint Program::getProgramBinaryLength() const
341{
342 if (mProgramBinary)
343 {
344 return mProgramBinary->getLength();
345 }
346 else
347 {
348 return 0;
349 }
350}
351
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000352unsigned int Program::issueSerial()
353{
354 return mCurrentSerial++;
355}
356
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000357int Program::getInfoLogLength() const
358{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000359 return mInfoLog.getLength();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000360}
361
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000362void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
363{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000364 return mInfoLog.getLog(bufSize, length, infoLog);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000365}
366
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000367void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
368{
369 int total = 0;
370
371 if (mVertexShader)
372 {
373 if (total < maxCount)
374 {
375 shaders[total] = mVertexShader->getHandle();
376 }
377
378 total++;
379 }
380
381 if (mFragmentShader)
382 {
383 if (total < maxCount)
384 {
385 shaders[total] = mFragmentShader->getHandle();
386 }
387
388 total++;
389 }
390
391 if (count)
392 {
393 *count = total;
394 }
395}
396
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000397void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
398{
399 if (mProgramBinary)
400 {
401 mProgramBinary->getActiveAttribute(index, bufsize, length, size, type, name);
402 }
403 else
404 {
405 if (bufsize > 0)
406 {
407 name[0] = '\0';
408 }
409
410 if (length)
411 {
412 *length = 0;
413 }
414
415 *type = GL_NONE;
416 *size = 1;
417 }
418}
419
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000420GLint Program::getActiveAttributeCount()
421{
422 if (mProgramBinary)
423 {
424 return mProgramBinary->getActiveAttributeCount();
425 }
426 else
427 {
428 return 0;
429 }
430}
431
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000432GLint Program::getActiveAttributeMaxLength()
433{
434 if (mProgramBinary)
435 {
436 return mProgramBinary->getActiveAttributeMaxLength();
437 }
438 else
439 {
440 return 0;
441 }
442}
443
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000444void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
445{
446 if (mProgramBinary)
447 {
448 return mProgramBinary->getActiveUniform(index, bufsize, length, size, type, name);
449 }
450 else
451 {
452 if (bufsize > 0)
453 {
454 name[0] = '\0';
455 }
456
457 if (length)
458 {
459 *length = 0;
460 }
461
462 *size = 0;
463 *type = GL_NONE;
464 }
465}
466
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000467GLint Program::getActiveUniformCount()
468{
469 if (mProgramBinary)
470 {
471 return mProgramBinary->getActiveUniformCount();
472 }
473 else
474 {
475 return 0;
476 }
477}
478
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000479GLint Program::getActiveUniformMaxLength()
480{
481 if (mProgramBinary)
482 {
483 return mProgramBinary->getActiveUniformMaxLength();
484 }
485 else
486 {
487 return 0;
488 }
489}
490
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000491void Program::flagForDeletion()
492{
493 mDeleteStatus = true;
494}
495
496bool Program::isFlaggedForDeletion() const
497{
498 return mDeleteStatus;
499}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +0000500
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000501void Program::validate()
502{
503 mInfoLog.reset();
504
505 if (mProgramBinary)
506 {
507 mProgramBinary->validate(mInfoLog);
508 }
509 else
510 {
511 mInfoLog.append("Program has not been successfully linked.");
512 }
513}
514
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000515bool Program::isValidated() const
516{
517 if (mProgramBinary)
518 {
519 return mProgramBinary->isValidated();
520 }
521 else
522 {
523 return false;
524 }
525}
526
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000527}