blob: b0509ab9d62bb2e768cd5264da650ba276387fce [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.comda13f3e2010-07-28 19:20:56 +0000145 mRefCount = 0;
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();
248
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000249 mProgramBinary = new ProgramBinary;
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000250 if (!mProgramBinary->link(mInfoLog, mAttributeBindings, mFragmentShader, mVertexShader))
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000251 {
252 unlink(false);
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000253
254 return false;
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000255 }
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000256
257 return true;
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000258}
259
apatrick@chromium.org9a30b092012-06-06 20:21:55 +0000260int AttributeBindings::getAttributeBinding(const std::string &name) const
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000261{
262 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
263 {
264 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
265 {
266 return location;
267 }
268 }
269
270 return -1;
271}
272
daniel@transgaming.comaa5e59b2011-10-04 18:43:12 +0000273// Returns the program object to an unlinked state, before re-linking, or at destruction
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000274void Program::unlink(bool destroy)
275{
276 if (destroy) // Object being destructed
277 {
278 if (mFragmentShader)
279 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000280 mFragmentShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000281 mFragmentShader = NULL;
282 }
283
284 if (mVertexShader)
285 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000286 mVertexShader->release();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000287 mVertexShader = NULL;
288 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000289 }
290
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000291 if (mProgramBinary)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000292 {
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000293 delete mProgramBinary;
294 mProgramBinary = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000295 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000296}
297
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000298ProgramBinary* Program::getProgramBinary()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000299{
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000300 return mProgramBinary;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000301}
302
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000303bool Program::setProgramBinary(const void *binary, GLsizei length)
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000304{
305 unlink(false);
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000306
307 mInfoLog.reset();
308
309 mProgramBinary = new ProgramBinary;
310 if (!mProgramBinary->load(mInfoLog, binary, length))
311 {
312 delete mProgramBinary;
313 mProgramBinary = NULL;
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000314
315 return false;
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000316 }
daniel@transgaming.com4c962bf2012-07-24 18:37:02 +0000317
318 return true;
apatrick@chromium.org3ce8dbc2012-06-08 17:52:30 +0000319}
320
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000321void Program::release()
322{
323 mRefCount--;
324
325 if (mRefCount == 0 && mDeleteStatus)
326 {
327 mResourceManager->deleteProgram(mHandle);
328 }
329}
330
331void Program::addRef()
332{
333 mRefCount++;
334}
335
336unsigned int Program::getRefCount() const
337{
338 return mRefCount;
339}
340
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000341GLint Program::getProgramBinaryLength() const
342{
343 if (mProgramBinary)
344 {
345 return mProgramBinary->getLength();
346 }
347 else
348 {
349 return 0;
350 }
351}
352
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000353int Program::getInfoLogLength() const
354{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000355 return mInfoLog.getLength();
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000356}
357
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000358void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
359{
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000360 return mInfoLog.getLog(bufSize, length, infoLog);
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000361}
362
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000363void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
364{
365 int total = 0;
366
367 if (mVertexShader)
368 {
369 if (total < maxCount)
370 {
371 shaders[total] = mVertexShader->getHandle();
372 }
373
374 total++;
375 }
376
377 if (mFragmentShader)
378 {
379 if (total < maxCount)
380 {
381 shaders[total] = mFragmentShader->getHandle();
382 }
383
384 total++;
385 }
386
387 if (count)
388 {
389 *count = total;
390 }
391}
392
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000393void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
394{
395 if (mProgramBinary)
396 {
397 mProgramBinary->getActiveAttribute(index, bufsize, length, size, type, name);
398 }
399 else
400 {
401 if (bufsize > 0)
402 {
403 name[0] = '\0';
404 }
405
406 if (length)
407 {
408 *length = 0;
409 }
410
411 *type = GL_NONE;
412 *size = 1;
413 }
414}
415
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000416GLint Program::getActiveAttributeCount()
417{
418 if (mProgramBinary)
419 {
420 return mProgramBinary->getActiveAttributeCount();
421 }
422 else
423 {
424 return 0;
425 }
426}
427
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000428GLint Program::getActiveAttributeMaxLength()
429{
430 if (mProgramBinary)
431 {
432 return mProgramBinary->getActiveAttributeMaxLength();
433 }
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{
442 if (mProgramBinary)
443 {
444 return mProgramBinary->getActiveUniform(index, bufsize, length, size, type, name);
445 }
446 else
447 {
448 if (bufsize > 0)
449 {
450 name[0] = '\0';
451 }
452
453 if (length)
454 {
455 *length = 0;
456 }
457
458 *size = 0;
459 *type = GL_NONE;
460 }
461}
462
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000463GLint Program::getActiveUniformCount()
464{
465 if (mProgramBinary)
466 {
467 return mProgramBinary->getActiveUniformCount();
468 }
469 else
470 {
471 return 0;
472 }
473}
474
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000475GLint Program::getActiveUniformMaxLength()
476{
477 if (mProgramBinary)
478 {
479 return mProgramBinary->getActiveUniformMaxLength();
480 }
481 else
482 {
483 return 0;
484 }
485}
486
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000487void Program::flagForDeletion()
488{
489 mDeleteStatus = true;
490}
491
492bool Program::isFlaggedForDeletion() const
493{
494 return mDeleteStatus;
495}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +0000496
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000497void Program::validate()
498{
499 mInfoLog.reset();
500
501 if (mProgramBinary)
502 {
503 mProgramBinary->validate(mInfoLog);
504 }
505 else
506 {
507 mInfoLog.append("Program has not been successfully linked.");
508 }
509}
510
apatrick@chromium.orge2a59bb2012-06-07 21:09:53 +0000511bool Program::isValidated() const
512{
513 if (mProgramBinary)
514 {
515 return mProgramBinary->isValidated();
516 }
517 else
518 {
519 return false;
520 }
521}
522
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000523}