blob: f28a9d8112530834e92f68fb4a3d14f92ed48dd8 [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.org3ce8dbc2012-06-08 17:52:30 +0000301void Program::setProgramBinary(ProgramBinary *programBinary)
302{
303 unlink(false);
304 mProgramBinary = programBinary;
305}
306
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000307void Program::release()
308{
309 mRefCount--;
310
311 if (mRefCount == 0 && mDeleteStatus)
312 {
313 mResourceManager->deleteProgram(mHandle);
314 }
315}
316
317void Program::addRef()
318{
319 mRefCount++;
320}
321
322unsigned int Program::getRefCount() const
323{
324 return mRefCount;
325}
326
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000327unsigned int Program::getSerial() const
328{
329 return mSerial;
330}
331
332unsigned int Program::issueSerial()
333{
334 return mCurrentSerial++;
335}
336
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000337int Program::getInfoLogLength() const
338{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000339 return mInfoLog.getLength();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000340}
341
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000342void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
343{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000344 return mInfoLog.getLog(bufSize, length, infoLog);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000345}
346
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000347void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
348{
349 int total = 0;
350
351 if (mVertexShader)
352 {
353 if (total < maxCount)
354 {
355 shaders[total] = mVertexShader->getHandle();
356 }
357
358 total++;
359 }
360
361 if (mFragmentShader)
362 {
363 if (total < maxCount)
364 {
365 shaders[total] = mFragmentShader->getHandle();
366 }
367
368 total++;
369 }
370
371 if (count)
372 {
373 *count = total;
374 }
375}
376
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000377void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
378{
379 if (mProgramBinary)
380 {
381 mProgramBinary->getActiveAttribute(index, bufsize, length, size, type, name);
382 }
383 else
384 {
385 if (bufsize > 0)
386 {
387 name[0] = '\0';
388 }
389
390 if (length)
391 {
392 *length = 0;
393 }
394
395 *type = GL_NONE;
396 *size = 1;
397 }
398}
399
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000400GLint Program::getActiveAttributeCount()
401{
402 if (mProgramBinary)
403 {
404 return mProgramBinary->getActiveAttributeCount();
405 }
406 else
407 {
408 return 0;
409 }
410}
411
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000412GLint Program::getActiveAttributeMaxLength()
413{
414 if (mProgramBinary)
415 {
416 return mProgramBinary->getActiveAttributeMaxLength();
417 }
418 else
419 {
420 return 0;
421 }
422}
423
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000424void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
425{
426 if (mProgramBinary)
427 {
428 return mProgramBinary->getActiveUniform(index, bufsize, length, size, type, name);
429 }
430 else
431 {
432 if (bufsize > 0)
433 {
434 name[0] = '\0';
435 }
436
437 if (length)
438 {
439 *length = 0;
440 }
441
442 *size = 0;
443 *type = GL_NONE;
444 }
445}
446
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000447GLint Program::getActiveUniformCount()
448{
449 if (mProgramBinary)
450 {
451 return mProgramBinary->getActiveUniformCount();
452 }
453 else
454 {
455 return 0;
456 }
457}
458
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000459GLint Program::getActiveUniformMaxLength()
460{
461 if (mProgramBinary)
462 {
463 return mProgramBinary->getActiveUniformMaxLength();
464 }
465 else
466 {
467 return 0;
468 }
469}
470
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000471void Program::flagForDeletion()
472{
473 mDeleteStatus = true;
474}
475
476bool Program::isFlaggedForDeletion() const
477{
478 return mDeleteStatus;
479}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +0000480
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000481void Program::validate()
482{
483 mInfoLog.reset();
484
485 if (mProgramBinary)
486 {
487 mProgramBinary->validate(mInfoLog);
488 }
489 else
490 {
491 mInfoLog.append("Program has not been successfully linked.");
492 }
493}
494
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000495bool Program::isValidated() const
496{
497 if (mProgramBinary)
498 {
499 return mProgramBinary->isValidated();
500 }
501 else
502 {
503 return false;
504 }
505}
506
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000507}