blob: 983495b2da11bdceb3ea73b69120aedc47aa04e8 [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
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000010#include "libGLESv2/Program.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000011#include "libGLESv2/ProgramBinary.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000012#include "libGLESv2/ResourceManager.h"
daniel@transgaming.com87891f72011-06-01 15:28:35 +000013
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000014namespace gl
15{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000016const char * const g_fakepath = "C:\\fakepath";
17
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +000018AttributeBindings::AttributeBindings()
19{
20}
21
22AttributeBindings::~AttributeBindings()
23{
apatrick@chromium.org9a30b092012-06-06 20:21:55 +000024}
25
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000026InfoLog::InfoLog() : mInfoLog(NULL)
27{
28}
29
30InfoLog::~InfoLog()
31{
32 delete[] mInfoLog;
33}
34
35
36int InfoLog::getLength() const
37{
38 if (!mInfoLog)
39 {
40 return 0;
41 }
42 else
43 {
44 return strlen(mInfoLog) + 1;
45 }
46}
47
48void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog)
49{
50 int index = 0;
51
52 if (bufSize > 0)
53 {
54 if (mInfoLog)
55 {
56 index = std::min(bufSize - 1, (int)strlen(mInfoLog));
57 memcpy(infoLog, mInfoLog, index);
58 }
59
60 infoLog[index] = '\0';
61 }
62
63 if (length)
64 {
65 *length = index;
66 }
67}
68
69// append a santized message to the program info log.
70// The D3D compiler includes a fake file path in some of the warning or error
71// messages, so lets remove all occurrences of this fake file path from the log.
72void InfoLog::appendSanitized(const char *message)
73{
74 std::string msg(message);
75
76 size_t found;
77 do
78 {
79 found = msg.find(g_fakepath);
80 if (found != std::string::npos)
81 {
82 msg.erase(found, strlen(g_fakepath));
83 }
84 }
85 while (found != std::string::npos);
86
87 append("%s\n", msg.c_str());
88}
89
90void InfoLog::append(const char *format, ...)
91{
92 if (!format)
93 {
94 return;
95 }
96
97 char info[1024];
98
99 va_list vararg;
100 va_start(vararg, format);
101 vsnprintf(info, sizeof(info), format, vararg);
102 va_end(vararg);
103
104 size_t infoLength = strlen(info);
105
106 if (!mInfoLog)
107 {
108 mInfoLog = new char[infoLength + 1];
109 strcpy(mInfoLog, info);
110 }
111 else
112 {
113 size_t logLength = strlen(mInfoLog);
114 char *newLog = new char[logLength + infoLength + 1];
115 strcpy(newLog, mInfoLog);
116 strcpy(newLog + logLength, info);
117
118 delete[] mInfoLog;
119 mInfoLog = newLog;
120 }
121}
122
123void InfoLog::reset()
124{
125 if (mInfoLog)
126 {
127 delete [] mInfoLog;
128 mInfoLog = NULL;
129 }
130}
131
daniel@transgaming.com70062c92012-11-28 19:32:30 +0000132Program::Program(rx::Renderer *renderer, ResourceManager *manager, GLuint handle) : mResourceManager(manager), mHandle(handle)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000133{
134 mFragmentShader = NULL;
135 mVertexShader = NULL;
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000136 mProgramBinary.set(NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000137 mDeleteStatus = false;
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000138 mLinked = false;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000139 mRefCount = 0;
daniel@transgaming.com70062c92012-11-28 19:32:30 +0000140 mRenderer = renderer;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000141}
142
143Program::~Program()
144{
145 unlink(true);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000146
147 if (mVertexShader != NULL)
148 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000149 mVertexShader->release();
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000150 }
151
152 if (mFragmentShader != NULL)
153 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000154 mFragmentShader->release();
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000155 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000156}
157
158bool Program::attachShader(Shader *shader)
159{
160 if (shader->getType() == GL_VERTEX_SHADER)
161 {
162 if (mVertexShader)
163 {
164 return false;
165 }
166
167 mVertexShader = (VertexShader*)shader;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000168 mVertexShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000169 }
170 else if (shader->getType() == GL_FRAGMENT_SHADER)
171 {
172 if (mFragmentShader)
173 {
174 return false;
175 }
176
177 mFragmentShader = (FragmentShader*)shader;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000178 mFragmentShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000179 }
180 else UNREACHABLE();
181
182 return true;
183}
184
185bool Program::detachShader(Shader *shader)
186{
187 if (shader->getType() == GL_VERTEX_SHADER)
188 {
189 if (mVertexShader != shader)
190 {
191 return false;
192 }
193
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000194 mVertexShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000195 mVertexShader = NULL;
196 }
197 else if (shader->getType() == GL_FRAGMENT_SHADER)
198 {
199 if (mFragmentShader != shader)
200 {
201 return false;
202 }
203
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000204 mFragmentShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000205 mFragmentShader = NULL;
206 }
207 else UNREACHABLE();
208
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000209 return true;
210}
211
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000212int Program::getAttachedShadersCount() const
213{
214 return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
215}
216
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000217void AttributeBindings::bindAttributeLocation(GLuint index, const char *name)
218{
219 if (index < MAX_VERTEX_ATTRIBS)
220 {
221 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
222 {
223 mAttributeBinding[i].erase(name);
224 }
225
226 mAttributeBinding[index].insert(name);
227 }
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000228}
229
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000230void Program::bindAttributeLocation(GLuint index, const char *name)
231{
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000232 mAttributeBindings.bindAttributeLocation(index, name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000233}
234
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000235// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
236// compiling them into binaries, determining the attribute mappings, and collecting
237// a list of uniforms
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000238bool Program::link()
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000239{
240 unlink(false);
241
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000242 mInfoLog.reset();
243
daniel@transgaming.com70062c92012-11-28 19:32:30 +0000244 mProgramBinary.set(new ProgramBinary(mRenderer));
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000245 mLinked = mProgramBinary->link(mInfoLog, mAttributeBindings, mFragmentShader, mVertexShader);
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000246
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000247 return mLinked;
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000248}
249
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000250int AttributeBindings::getAttributeBinding(const std::string &name) const
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000251{
252 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
253 {
254 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
255 {
256 return location;
257 }
258 }
259
260 return -1;
261}
262
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +0000263// Returns the program object to an unlinked state, before re-linking, or at destruction
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000264void Program::unlink(bool destroy)
265{
266 if (destroy) // Object being destructed
267 {
268 if (mFragmentShader)
269 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000270 mFragmentShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000271 mFragmentShader = NULL;
272 }
273
274 if (mVertexShader)
275 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000276 mVertexShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000277 mVertexShader = NULL;
278 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000279 }
280
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000281 mProgramBinary.set(NULL);
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000282 mLinked = false;
283}
284
285bool Program::isLinked()
286{
287 return mLinked;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000288}
289
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000290ProgramBinary* Program::getProgramBinary()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000291{
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000292 return mProgramBinary.get();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000293}
294
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000295bool Program::setProgramBinary(const void *binary, GLsizei length)
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000296{
297 unlink(false);
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000298
299 mInfoLog.reset();
300
daniel@transgaming.com70062c92012-11-28 19:32:30 +0000301 mProgramBinary.set(new ProgramBinary(mRenderer));
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000302 mLinked = mProgramBinary->load(mInfoLog, binary, length);
303 if (!mLinked)
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000304 {
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000305 mProgramBinary.set(NULL);
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000306 }
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000307
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000308 return mLinked;
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000309}
310
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000311void Program::release()
312{
313 mRefCount--;
314
315 if (mRefCount == 0 && mDeleteStatus)
316 {
317 mResourceManager->deleteProgram(mHandle);
318 }
319}
320
321void Program::addRef()
322{
323 mRefCount++;
324}
325
326unsigned int Program::getRefCount() const
327{
328 return mRefCount;
329}
330
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000331GLint Program::getProgramBinaryLength() const
332{
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000333 ProgramBinary *programBinary = mProgramBinary.get();
334 if (programBinary)
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000335 {
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000336 return programBinary->getLength();
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000337 }
338 else
339 {
340 return 0;
341 }
342}
343
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000344int Program::getInfoLogLength() const
345{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000346 return mInfoLog.getLength();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000347}
348
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000349void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
350{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000351 return mInfoLog.getLog(bufSize, length, infoLog);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000352}
353
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000354void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
355{
356 int total = 0;
357
358 if (mVertexShader)
359 {
360 if (total < maxCount)
361 {
362 shaders[total] = mVertexShader->getHandle();
363 }
364
365 total++;
366 }
367
368 if (mFragmentShader)
369 {
370 if (total < maxCount)
371 {
372 shaders[total] = mFragmentShader->getHandle();
373 }
374
375 total++;
376 }
377
378 if (count)
379 {
380 *count = total;
381 }
382}
383
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000384void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
385{
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000386 ProgramBinary *programBinary = getProgramBinary();
387 if (programBinary)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000388 {
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000389 programBinary->getActiveAttribute(index, bufsize, length, size, type, name);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000390 }
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{
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000410 ProgramBinary *programBinary = getProgramBinary();
411 if (programBinary)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000412 {
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000413 return programBinary->getActiveAttributeCount();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000414 }
415 else
416 {
417 return 0;
418 }
419}
420
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000421GLint Program::getActiveAttributeMaxLength()
422{
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000423 ProgramBinary *programBinary = getProgramBinary();
424 if (programBinary)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000425 {
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000426 return programBinary->getActiveAttributeMaxLength();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000427 }
428 else
429 {
430 return 0;
431 }
432}
433
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000434void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
435{
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000436 ProgramBinary *programBinary = getProgramBinary();
437 if (programBinary)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000438 {
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000439 return programBinary->getActiveUniform(index, bufsize, length, size, type, name);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000440 }
441 else
442 {
443 if (bufsize > 0)
444 {
445 name[0] = '\0';
446 }
447
448 if (length)
449 {
450 *length = 0;
451 }
452
453 *size = 0;
454 *type = GL_NONE;
455 }
456}
457
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000458GLint Program::getActiveUniformCount()
459{
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000460 ProgramBinary *programBinary = getProgramBinary();
461 if (programBinary)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000462 {
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000463 return programBinary->getActiveUniformCount();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000464 }
465 else
466 {
467 return 0;
468 }
469}
470
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000471GLint Program::getActiveUniformMaxLength()
472{
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000473 ProgramBinary *programBinary = getProgramBinary();
474 if (programBinary)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000475 {
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000476 return programBinary->getActiveUniformMaxLength();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000477 }
478 else
479 {
480 return 0;
481 }
482}
483
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000484void Program::flagForDeletion()
485{
486 mDeleteStatus = true;
487}
488
489bool Program::isFlaggedForDeletion() const
490{
491 return mDeleteStatus;
492}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +0000493
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000494void Program::validate()
495{
496 mInfoLog.reset();
497
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000498 ProgramBinary *programBinary = getProgramBinary();
499 if (isLinked() && programBinary)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000500 {
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000501 programBinary->validate(mInfoLog);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000502 }
503 else
504 {
505 mInfoLog.append("Program has not been successfully linked.");
506 }
507}
508
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000509bool Program::isValidated() const
510{
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000511 ProgramBinary *programBinary = mProgramBinary.get();
512 if (programBinary)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000513 {
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000514 return programBinary->isValidated();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000515 }
516 else
517 {
518 return false;
519 }
520}
521
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000522}