blob: 48a0850ff51771f23c2f48813c1ffe353482aed4 [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//
daniel@transgaming.comcde6a612012-02-17 18:01:10 +00003// Copyright (c) 2002-2012 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
88 append("%s\n", msg.c_str());
89}
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 {
109 mInfoLog = new char[infoLength + 1];
110 strcpy(mInfoLog, info);
111 }
112 else
113 {
114 size_t logLength = strlen(mInfoLog);
115 char *newLog = new char[logLength + infoLength + 1];
116 strcpy(newLog, mInfoLog);
117 strcpy(newLog + logLength, info);
118
119 delete[] mInfoLog;
120 mInfoLog = newLog;
121 }
122}
123
124void InfoLog::reset()
125{
126 if (mInfoLog)
127 {
128 delete [] mInfoLog;
129 mInfoLog = NULL;
130 }
131}
132
daniel@transgaming.com70062c92012-11-28 19:32:30 +0000133Program::Program(rx::Renderer *renderer, ResourceManager *manager, GLuint handle) : mResourceManager(manager), mHandle(handle)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000134{
135 mFragmentShader = NULL;
136 mVertexShader = NULL;
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000137 mProgramBinary.set(NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000138 mDeleteStatus = false;
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000139 mLinked = false;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000140 mRefCount = 0;
daniel@transgaming.com70062c92012-11-28 19:32:30 +0000141 mRenderer = renderer;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000142}
143
144Program::~Program()
145{
146 unlink(true);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000147
148 if (mVertexShader != NULL)
149 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000150 mVertexShader->release();
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000151 }
152
153 if (mFragmentShader != NULL)
154 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000155 mFragmentShader->release();
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000156 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000157}
158
159bool Program::attachShader(Shader *shader)
160{
161 if (shader->getType() == GL_VERTEX_SHADER)
162 {
163 if (mVertexShader)
164 {
165 return false;
166 }
167
168 mVertexShader = (VertexShader*)shader;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000169 mVertexShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000170 }
171 else if (shader->getType() == GL_FRAGMENT_SHADER)
172 {
173 if (mFragmentShader)
174 {
175 return false;
176 }
177
178 mFragmentShader = (FragmentShader*)shader;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000179 mFragmentShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000180 }
181 else UNREACHABLE();
182
183 return true;
184}
185
186bool Program::detachShader(Shader *shader)
187{
188 if (shader->getType() == GL_VERTEX_SHADER)
189 {
190 if (mVertexShader != shader)
191 {
192 return false;
193 }
194
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000195 mVertexShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000196 mVertexShader = NULL;
197 }
198 else if (shader->getType() == GL_FRAGMENT_SHADER)
199 {
200 if (mFragmentShader != shader)
201 {
202 return false;
203 }
204
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000205 mFragmentShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000206 mFragmentShader = NULL;
207 }
208 else UNREACHABLE();
209
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000210 return true;
211}
212
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000213int Program::getAttachedShadersCount() const
214{
215 return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
216}
217
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000218void AttributeBindings::bindAttributeLocation(GLuint index, const char *name)
219{
220 if (index < MAX_VERTEX_ATTRIBS)
221 {
222 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
223 {
224 mAttributeBinding[i].erase(name);
225 }
226
227 mAttributeBinding[index].insert(name);
228 }
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000229}
230
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000231void Program::bindAttributeLocation(GLuint index, const char *name)
232{
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000233 mAttributeBindings.bindAttributeLocation(index, name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000234}
235
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000236// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
237// compiling them into binaries, determining the attribute mappings, and collecting
238// a list of uniforms
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000239bool Program::link()
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000240{
241 unlink(false);
242
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000243 mInfoLog.reset();
244
daniel@transgaming.com70062c92012-11-28 19:32:30 +0000245 mProgramBinary.set(new ProgramBinary(mRenderer));
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000246 mLinked = mProgramBinary->link(mInfoLog, mAttributeBindings, mFragmentShader, mVertexShader);
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000247
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000248 return mLinked;
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000249}
250
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000251int AttributeBindings::getAttributeBinding(const std::string &name) const
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000252{
253 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
254 {
255 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
256 {
257 return location;
258 }
259 }
260
261 return -1;
262}
263
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +0000264// Returns the program object to an unlinked state, before re-linking, or at destruction
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000265void Program::unlink(bool destroy)
266{
267 if (destroy) // Object being destructed
268 {
269 if (mFragmentShader)
270 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000271 mFragmentShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000272 mFragmentShader = NULL;
273 }
274
275 if (mVertexShader)
276 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000277 mVertexShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000278 mVertexShader = NULL;
279 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000280 }
281
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000282 mProgramBinary.set(NULL);
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000283 mLinked = false;
284}
285
286bool Program::isLinked()
287{
288 return mLinked;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000289}
290
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000291ProgramBinary* Program::getProgramBinary()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000292{
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000293 return mProgramBinary.get();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000294}
295
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000296bool Program::setProgramBinary(const void *binary, GLsizei length)
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000297{
298 unlink(false);
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000299
300 mInfoLog.reset();
301
daniel@transgaming.com70062c92012-11-28 19:32:30 +0000302 mProgramBinary.set(new ProgramBinary(mRenderer));
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000303 mLinked = mProgramBinary->load(mInfoLog, binary, length);
304 if (!mLinked)
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000305 {
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000306 mProgramBinary.set(NULL);
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000307 }
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000308
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000309 return mLinked;
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000310}
311
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000312void Program::release()
313{
314 mRefCount--;
315
316 if (mRefCount == 0 && mDeleteStatus)
317 {
318 mResourceManager->deleteProgram(mHandle);
319 }
320}
321
322void Program::addRef()
323{
324 mRefCount++;
325}
326
327unsigned int Program::getRefCount() const
328{
329 return mRefCount;
330}
331
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000332GLint Program::getProgramBinaryLength() const
333{
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000334 ProgramBinary *programBinary = mProgramBinary.get();
335 if (programBinary)
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000336 {
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000337 return programBinary->getLength();
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000338 }
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{
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000387 ProgramBinary *programBinary = getProgramBinary();
388 if (programBinary)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000389 {
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000390 programBinary->getActiveAttribute(index, bufsize, length, size, type, name);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000391 }
392 else
393 {
394 if (bufsize > 0)
395 {
396 name[0] = '\0';
397 }
398
399 if (length)
400 {
401 *length = 0;
402 }
403
404 *type = GL_NONE;
405 *size = 1;
406 }
407}
408
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000409GLint Program::getActiveAttributeCount()
410{
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000411 ProgramBinary *programBinary = getProgramBinary();
412 if (programBinary)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000413 {
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000414 return programBinary->getActiveAttributeCount();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000415 }
416 else
417 {
418 return 0;
419 }
420}
421
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000422GLint Program::getActiveAttributeMaxLength()
423{
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000424 ProgramBinary *programBinary = getProgramBinary();
425 if (programBinary)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000426 {
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000427 return programBinary->getActiveAttributeMaxLength();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000428 }
429 else
430 {
431 return 0;
432 }
433}
434
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000435void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
436{
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000437 ProgramBinary *programBinary = getProgramBinary();
438 if (programBinary)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000439 {
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000440 return programBinary->getActiveUniform(index, bufsize, length, size, type, name);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000441 }
442 else
443 {
444 if (bufsize > 0)
445 {
446 name[0] = '\0';
447 }
448
449 if (length)
450 {
451 *length = 0;
452 }
453
454 *size = 0;
455 *type = GL_NONE;
456 }
457}
458
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000459GLint Program::getActiveUniformCount()
460{
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000461 ProgramBinary *programBinary = getProgramBinary();
462 if (programBinary)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000463 {
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000464 return programBinary->getActiveUniformCount();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000465 }
466 else
467 {
468 return 0;
469 }
470}
471
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000472GLint Program::getActiveUniformMaxLength()
473{
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000474 ProgramBinary *programBinary = getProgramBinary();
475 if (programBinary)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000476 {
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000477 return programBinary->getActiveUniformMaxLength();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000478 }
479 else
480 {
481 return 0;
482 }
483}
484
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000485void Program::flagForDeletion()
486{
487 mDeleteStatus = true;
488}
489
490bool Program::isFlaggedForDeletion() const
491{
492 return mDeleteStatus;
493}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +0000494
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000495void Program::validate()
496{
497 mInfoLog.reset();
498
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000499 ProgramBinary *programBinary = getProgramBinary();
500 if (isLinked() && programBinary)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000501 {
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000502 programBinary->validate(mInfoLog);
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000503 }
504 else
505 {
506 mInfoLog.append("Program has not been successfully linked.");
507 }
508}
509
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000510bool Program::isValidated() const
511{
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000512 ProgramBinary *programBinary = mProgramBinary.get();
513 if (programBinary)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000514 {
daniel@transgaming.com989c1c82012-07-24 18:40:38 +0000515 return programBinary->isValidated();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000516 }
517 else
518 {
519 return false;
520 }
521}
522
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000523}