blob: 3923035a22222ca6b0cbd1ff06b25b70ca58164c [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
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +000025AttributeBindings::AttributeBindings()
26{
27}
28
29AttributeBindings::~AttributeBindings()
30{
apatrick@chromium.org9a30b092012-06-06 20:21:55 +000031}
32
apatrick@chromium.org253b8d22012-06-22 19:27:21 +000033InfoLog::InfoLog() : mInfoLog(NULL)
34{
35}
36
37InfoLog::~InfoLog()
38{
39 delete[] mInfoLog;
40}
41
42
43int InfoLog::getLength() const
44{
45 if (!mInfoLog)
46 {
47 return 0;
48 }
49 else
50 {
51 return strlen(mInfoLog) + 1;
52 }
53}
54
55void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog)
56{
57 int index = 0;
58
59 if (bufSize > 0)
60 {
61 if (mInfoLog)
62 {
63 index = std::min(bufSize - 1, (int)strlen(mInfoLog));
64 memcpy(infoLog, mInfoLog, index);
65 }
66
67 infoLog[index] = '\0';
68 }
69
70 if (length)
71 {
72 *length = index;
73 }
74}
75
76// append a santized message to the program info log.
77// The D3D compiler includes a fake file path in some of the warning or error
78// messages, so lets remove all occurrences of this fake file path from the log.
79void InfoLog::appendSanitized(const char *message)
80{
81 std::string msg(message);
82
83 size_t found;
84 do
85 {
86 found = msg.find(g_fakepath);
87 if (found != std::string::npos)
88 {
89 msg.erase(found, strlen(g_fakepath));
90 }
91 }
92 while (found != std::string::npos);
93
94 append("%s\n", msg.c_str());
95}
96
97void InfoLog::append(const char *format, ...)
98{
99 if (!format)
100 {
101 return;
102 }
103
104 char info[1024];
105
106 va_list vararg;
107 va_start(vararg, format);
108 vsnprintf(info, sizeof(info), format, vararg);
109 va_end(vararg);
110
111 size_t infoLength = strlen(info);
112
113 if (!mInfoLog)
114 {
115 mInfoLog = new char[infoLength + 1];
116 strcpy(mInfoLog, info);
117 }
118 else
119 {
120 size_t logLength = strlen(mInfoLog);
121 char *newLog = new char[logLength + infoLength + 1];
122 strcpy(newLog, mInfoLog);
123 strcpy(newLog + logLength, info);
124
125 delete[] mInfoLog;
126 mInfoLog = newLog;
127 }
128}
129
130void InfoLog::reset()
131{
132 if (mInfoLog)
133 {
134 delete [] mInfoLog;
135 mInfoLog = NULL;
136 }
137}
138
daniel@transgaming.com39c9d952012-07-24 18:32:29 +0000139Program::Program(ResourceManager *manager, GLuint handle) : mResourceManager(manager), mHandle(handle)
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000140{
141 mFragmentShader = NULL;
142 mVertexShader = NULL;
143 mProgramBinary = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000144 mDeleteStatus = false;
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000145 mLinked = false;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000146 mRefCount = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000147}
148
149Program::~Program()
150{
151 unlink(true);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000152
153 if (mVertexShader != NULL)
154 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000155 mVertexShader->release();
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000156 }
157
158 if (mFragmentShader != NULL)
159 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000160 mFragmentShader->release();
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000161 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000162}
163
164bool Program::attachShader(Shader *shader)
165{
166 if (shader->getType() == GL_VERTEX_SHADER)
167 {
168 if (mVertexShader)
169 {
170 return false;
171 }
172
173 mVertexShader = (VertexShader*)shader;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000174 mVertexShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000175 }
176 else if (shader->getType() == GL_FRAGMENT_SHADER)
177 {
178 if (mFragmentShader)
179 {
180 return false;
181 }
182
183 mFragmentShader = (FragmentShader*)shader;
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000184 mFragmentShader->addRef();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000185 }
186 else UNREACHABLE();
187
188 return true;
189}
190
191bool Program::detachShader(Shader *shader)
192{
193 if (shader->getType() == GL_VERTEX_SHADER)
194 {
195 if (mVertexShader != shader)
196 {
197 return false;
198 }
199
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000200 mVertexShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000201 mVertexShader = NULL;
202 }
203 else if (shader->getType() == GL_FRAGMENT_SHADER)
204 {
205 if (mFragmentShader != shader)
206 {
207 return false;
208 }
209
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000210 mFragmentShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000211 mFragmentShader = NULL;
212 }
213 else UNREACHABLE();
214
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000215 return true;
216}
217
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000218int Program::getAttachedShadersCount() const
219{
220 return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
221}
222
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000223void AttributeBindings::bindAttributeLocation(GLuint index, const char *name)
224{
225 if (index < MAX_VERTEX_ATTRIBS)
226 {
227 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
228 {
229 mAttributeBinding[i].erase(name);
230 }
231
232 mAttributeBinding[index].insert(name);
233 }
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000234}
235
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000236void Program::bindAttributeLocation(GLuint index, const char *name)
237{
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000238 mAttributeBindings.bindAttributeLocation(index, name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000239}
240
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000241// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
242// compiling them into binaries, determining the attribute mappings, and collecting
243// a list of uniforms
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000244bool Program::link()
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000245{
246 unlink(false);
247
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000248 mInfoLog.reset();
249
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000250 mProgramBinary = new ProgramBinary;
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
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000287 if (mProgramBinary)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000288 {
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000289 delete mProgramBinary;
290 mProgramBinary = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000291 }
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000292 mLinked = false;
293}
294
295bool Program::isLinked()
296{
297 return mLinked;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000298}
299
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000300ProgramBinary* Program::getProgramBinary()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000301{
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000302 return mProgramBinary;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000303}
304
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000305bool Program::setProgramBinary(const void *binary, GLsizei length)
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000306{
307 unlink(false);
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000308
309 mInfoLog.reset();
310
311 mProgramBinary = new ProgramBinary;
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000312 mLinked = mProgramBinary->load(mInfoLog, binary, length);
313 if (!mLinked)
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000314 {
315 delete mProgramBinary;
316 mProgramBinary = NULL;
317 }
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000318
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000319 return mLinked;
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000320}
321
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000322void Program::release()
323{
324 mRefCount--;
325
326 if (mRefCount == 0 && mDeleteStatus)
327 {
328 mResourceManager->deleteProgram(mHandle);
329 }
330}
331
332void Program::addRef()
333{
334 mRefCount++;
335}
336
337unsigned int Program::getRefCount() const
338{
339 return mRefCount;
340}
341
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000342GLint Program::getProgramBinaryLength() const
343{
344 if (mProgramBinary)
345 {
346 return mProgramBinary->getLength();
347 }
348 else
349 {
350 return 0;
351 }
352}
353
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000354int Program::getInfoLogLength() const
355{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000356 return mInfoLog.getLength();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000357}
358
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000359void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
360{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000361 return mInfoLog.getLog(bufSize, length, infoLog);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000362}
363
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000364void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
365{
366 int total = 0;
367
368 if (mVertexShader)
369 {
370 if (total < maxCount)
371 {
372 shaders[total] = mVertexShader->getHandle();
373 }
374
375 total++;
376 }
377
378 if (mFragmentShader)
379 {
380 if (total < maxCount)
381 {
382 shaders[total] = mFragmentShader->getHandle();
383 }
384
385 total++;
386 }
387
388 if (count)
389 {
390 *count = total;
391 }
392}
393
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000394void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
395{
396 if (mProgramBinary)
397 {
398 mProgramBinary->getActiveAttribute(index, bufsize, length, size, type, name);
399 }
400 else
401 {
402 if (bufsize > 0)
403 {
404 name[0] = '\0';
405 }
406
407 if (length)
408 {
409 *length = 0;
410 }
411
412 *type = GL_NONE;
413 *size = 1;
414 }
415}
416
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000417GLint Program::getActiveAttributeCount()
418{
419 if (mProgramBinary)
420 {
421 return mProgramBinary->getActiveAttributeCount();
422 }
423 else
424 {
425 return 0;
426 }
427}
428
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000429GLint Program::getActiveAttributeMaxLength()
430{
431 if (mProgramBinary)
432 {
433 return mProgramBinary->getActiveAttributeMaxLength();
434 }
435 else
436 {
437 return 0;
438 }
439}
440
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000441void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
442{
443 if (mProgramBinary)
444 {
445 return mProgramBinary->getActiveUniform(index, bufsize, length, size, type, name);
446 }
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{
466 if (mProgramBinary)
467 {
468 return mProgramBinary->getActiveUniformCount();
469 }
470 else
471 {
472 return 0;
473 }
474}
475
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000476GLint Program::getActiveUniformMaxLength()
477{
478 if (mProgramBinary)
479 {
480 return mProgramBinary->getActiveUniformMaxLength();
481 }
482 else
483 {
484 return 0;
485 }
486}
487
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000488void Program::flagForDeletion()
489{
490 mDeleteStatus = true;
491}
492
493bool Program::isFlaggedForDeletion() const
494{
495 return mDeleteStatus;
496}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +0000497
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000498void Program::validate()
499{
500 mInfoLog.reset();
501
daniel@transgaming.com716056c2012-07-24 18:38:59 +0000502 if (isLinked() && mProgramBinary)
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000503 {
504 mProgramBinary->validate(mInfoLog);
505 }
506 else
507 {
508 mInfoLog.append("Program has not been successfully linked.");
509 }
510}
511
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000512bool Program::isValidated() const
513{
514 if (mProgramBinary)
515 {
516 return mProgramBinary->isValidated();
517 }
518 else
519 {
520 return false;
521 }
522}
523
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000524}