blob: cfaddf0a50ecdabe53a88f77966f6244c4f36e41 [file] [log] [blame]
shannon.woods@transgaming.combdf2d802013-02-28 23:16:20 +00001#include "precompiled.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002//
shannon.woods@transgaming.come16e6512013-02-28 23:19:02 +00003// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00004// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6//
7
8// Program.cpp: Implements the gl::Program class. Implements GL program objects
9// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
10
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000011#include "libGLESv2/Program.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000012#include "libGLESv2/ProgramBinary.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000013#include "libGLESv2/ResourceManager.h"
daniel@transgaming.com87891f72011-06-01 15:28:35 +000014
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000015namespace gl
16{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000017const char * const g_fakepath = "C:\\fakepath";
18
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +000019AttributeBindings::AttributeBindings()
20{
21}
22
23AttributeBindings::~AttributeBindings()
24{
apatrick@chromium.org9a30b092012-06-06 20:21:55 +000025}
26
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000027InfoLog::InfoLog() : mInfoLog(NULL)
28{
29}
30
31InfoLog::~InfoLog()
32{
33 delete[] mInfoLog;
34}
35
36
37int InfoLog::getLength() const
38{
39 if (!mInfoLog)
40 {
41 return 0;
42 }
43 else
44 {
45 return strlen(mInfoLog) + 1;
46 }
47}
48
49void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog)
50{
51 int index = 0;
52
53 if (bufSize > 0)
54 {
55 if (mInfoLog)
56 {
57 index = std::min(bufSize - 1, (int)strlen(mInfoLog));
58 memcpy(infoLog, mInfoLog, index);
59 }
60
61 infoLog[index] = '\0';
62 }
63
64 if (length)
65 {
66 *length = index;
67 }
68}
69
70// append a santized message to the program info log.
71// The D3D compiler includes a fake file path in some of the warning or error
72// messages, so lets remove all occurrences of this fake file path from the log.
73void InfoLog::appendSanitized(const char *message)
74{
75 std::string msg(message);
76
77 size_t found;
78 do
79 {
80 found = msg.find(g_fakepath);
81 if (found != std::string::npos)
82 {
83 msg.erase(found, strlen(g_fakepath));
84 }
85 }
86 while (found != std::string::npos);
87
shannon.woods@transgaming.come16e6512013-02-28 23:19:02 +000088 append("%s", msg.c_str());
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000089}
90
91void InfoLog::append(const char *format, ...)
92{
93 if (!format)
94 {
95 return;
96 }
97
98 char info[1024];
99
100 va_list vararg;
101 va_start(vararg, format);
102 vsnprintf(info, sizeof(info), format, vararg);
103 va_end(vararg);
104
105 size_t infoLength = strlen(info);
106
107 if (!mInfoLog)
108 {
shannon.woods@transgaming.come16e6512013-02-28 23:19:02 +0000109 mInfoLog = new char[infoLength + 2];
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000110 strcpy(mInfoLog, info);
shannon.woods@transgaming.come16e6512013-02-28 23:19:02 +0000111 strcpy(mInfoLog + infoLength, "\n");
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000112 }
113 else
114 {
115 size_t logLength = strlen(mInfoLog);
shannon.woods@transgaming.come16e6512013-02-28 23:19:02 +0000116 char *newLog = new char[logLength + infoLength + 2];
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000117 strcpy(newLog, mInfoLog);
118 strcpy(newLog + logLength, info);
shannon.woods@transgaming.come16e6512013-02-28 23:19:02 +0000119 strcpy(newLog + logLength + infoLength, "\n");
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000120
121 delete[] mInfoLog;
122 mInfoLog = newLog;
123 }
124}
125
126void InfoLog::reset()
127{
128 if (mInfoLog)
129 {
130 delete [] mInfoLog;
131 mInfoLog = NULL;
132 }
133}
134
daniel@transgaming.com70062c92012-11-28 19:32:30 +0000135Program::Program(rx::Renderer *renderer, ResourceManager *manager, GLuint handle) : mResourceManager(manager), mHandle(handle)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000136{
137 mFragmentShader = NULL;
138 mVertexShader = NULL;
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000139 mProgramBinary.set(NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000140 mDeleteStatus = false;
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000141 mLinked = false;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000142 mRefCount = 0;
daniel@transgaming.com70062c92012-11-28 19:32:30 +0000143 mRenderer = renderer;
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000144
145 resetUniformBlockBindings();
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
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000243bool Program::link()
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000244{
245 unlink(false);
246
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000247 mInfoLog.reset();
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000248 resetUniformBlockBindings();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000249
daniel@transgaming.com70062c92012-11-28 19:32:30 +0000250 mProgramBinary.set(new ProgramBinary(mRenderer));
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000251 mLinked = mProgramBinary->link(mInfoLog, mAttributeBindings, mFragmentShader, mVertexShader);
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000252
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000253 return mLinked;
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
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000287 mProgramBinary.set(NULL);
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000288 mLinked = false;
289}
290
291bool Program::isLinked()
292{
293 return mLinked;
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{
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000298 return mProgramBinary.get();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000299}
300
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000301bool 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
daniel@transgaming.com70062c92012-11-28 19:32:30 +0000307 mProgramBinary.set(new ProgramBinary(mRenderer));
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000308 mLinked = mProgramBinary->load(mInfoLog, binary, length);
309 if (!mLinked)
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000310 {
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000311 mProgramBinary.set(NULL);
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000312 }
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000313
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000314 return mLinked;
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000315}
316
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000317void Program::release()
318{
319 mRefCount--;
320
321 if (mRefCount == 0 && mDeleteStatus)
322 {
323 mResourceManager->deleteProgram(mHandle);
324 }
325}
326
327void Program::addRef()
328{
329 mRefCount++;
330}
331
332unsigned int Program::getRefCount() const
333{
334 return mRefCount;
335}
336
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000337GLint Program::getProgramBinaryLength() const
338{
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000339 ProgramBinary *programBinary = mProgramBinary.get();
340 if (programBinary)
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000341 {
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000342 return programBinary->getLength();
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000343 }
344 else
345 {
346 return 0;
347 }
348}
349
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000350int Program::getInfoLogLength() const
351{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000352 return mInfoLog.getLength();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000353}
354
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000355void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
356{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000357 return mInfoLog.getLog(bufSize, length, infoLog);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000358}
359
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000360void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
361{
362 int total = 0;
363
364 if (mVertexShader)
365 {
366 if (total < maxCount)
367 {
368 shaders[total] = mVertexShader->getHandle();
369 }
370
371 total++;
372 }
373
374 if (mFragmentShader)
375 {
376 if (total < maxCount)
377 {
378 shaders[total] = mFragmentShader->getHandle();
379 }
380
381 total++;
382 }
383
384 if (count)
385 {
386 *count = total;
387 }
388}
389
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000390void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
391{
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000392 ProgramBinary *programBinary = getProgramBinary();
393 if (programBinary)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000394 {
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000395 programBinary->getActiveAttribute(index, bufsize, length, size, type, name);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000396 }
397 else
398 {
399 if (bufsize > 0)
400 {
401 name[0] = '\0';
402 }
403
404 if (length)
405 {
406 *length = 0;
407 }
408
409 *type = GL_NONE;
410 *size = 1;
411 }
412}
413
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000414GLint Program::getActiveAttributeCount()
415{
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000416 ProgramBinary *programBinary = getProgramBinary();
417 if (programBinary)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000418 {
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000419 return programBinary->getActiveAttributeCount();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000420 }
421 else
422 {
423 return 0;
424 }
425}
426
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000427GLint Program::getActiveAttributeMaxLength()
428{
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000429 ProgramBinary *programBinary = getProgramBinary();
430 if (programBinary)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000431 {
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000432 return programBinary->getActiveAttributeMaxLength();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000433 }
434 else
435 {
436 return 0;
437 }
438}
439
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000440void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
441{
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000442 ProgramBinary *programBinary = getProgramBinary();
443 if (programBinary)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000444 {
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000445 return programBinary->getActiveUniform(index, bufsize, length, size, type, name);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000446 }
447 else
448 {
449 if (bufsize > 0)
450 {
451 name[0] = '\0';
452 }
453
454 if (length)
455 {
456 *length = 0;
457 }
458
459 *size = 0;
460 *type = GL_NONE;
461 }
462}
463
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000464GLint Program::getActiveUniformCount()
465{
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000466 ProgramBinary *programBinary = getProgramBinary();
467 if (programBinary)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000468 {
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000469 return programBinary->getActiveUniformCount();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000470 }
471 else
472 {
473 return 0;
474 }
475}
476
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000477GLint Program::getActiveUniformMaxLength()
478{
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000479 ProgramBinary *programBinary = getProgramBinary();
480 if (programBinary)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000481 {
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000482 return programBinary->getActiveUniformMaxLength();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000483 }
484 else
485 {
486 return 0;
487 }
488}
489
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000490void Program::flagForDeletion()
491{
492 mDeleteStatus = true;
493}
494
495bool Program::isFlaggedForDeletion() const
496{
497 return mDeleteStatus;
498}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +0000499
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000500void Program::validate()
501{
502 mInfoLog.reset();
503
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000504 ProgramBinary *programBinary = getProgramBinary();
505 if (isLinked() && programBinary)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000506 {
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000507 programBinary->validate(mInfoLog);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000508 }
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{
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000517 ProgramBinary *programBinary = mProgramBinary.get();
518 if (programBinary)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000519 {
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000520 return programBinary->isValidated();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000521 }
522 else
523 {
524 return false;
525 }
526}
527
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +0000528void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
529{
530 mUniformBlockBindings[uniformBlockIndex] = uniformBlockBinding;
531}
532
533GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
534{
535 return mUniformBlockBindings[uniformBlockIndex];
536}
537
538void Program::resetUniformBlockBindings()
539{
540 for (unsigned int blockId = 0; blockId < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; blockId++)
541 {
542 mUniformBlockBindings[blockId] = 0;
543 }
544}
545
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000546}