1 #include "precompiled.h"
2 //
3 // Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
4 // 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
11 #include "libGLESv2/Program.h"
12 #include "libGLESv2/ProgramBinary.h"
13 #include "libGLESv2/ResourceManager.h"
14
15 namespace gl
16 {
17 const char * const g_fakepath = "C:\\fakepath";
18
AttributeBindings()19 AttributeBindings::AttributeBindings()
20 {
21 }
22
~AttributeBindings()23 AttributeBindings::~AttributeBindings()
24 {
25 }
26
InfoLog()27 InfoLog::InfoLog() : mInfoLog(NULL)
28 {
29 }
30
~InfoLog()31 InfoLog::~InfoLog()
32 {
33 delete[] mInfoLog;
34 }
35
36
getLength() const37 int InfoLog::getLength() const
38 {
39 if (!mInfoLog)
40 {
41 return 0;
42 }
43 else
44 {
45 return strlen(mInfoLog) + 1;
46 }
47 }
48
getLog(GLsizei bufSize,GLsizei * length,char * infoLog)49 void 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.
appendSanitized(const char * message)73 void 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", msg.c_str());
89 }
90
append(const char * format,...)91 void 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 + 2];
110 strcpy(mInfoLog, info);
111 strcpy(mInfoLog + infoLength, "\n");
112 }
113 else
114 {
115 size_t logLength = strlen(mInfoLog);
116 char *newLog = new char[logLength + infoLength + 2];
117 strcpy(newLog, mInfoLog);
118 strcpy(newLog + logLength, info);
119 strcpy(newLog + logLength + infoLength, "\n");
120
121 delete[] mInfoLog;
122 mInfoLog = newLog;
123 }
124 }
125
reset()126 void InfoLog::reset()
127 {
128 if (mInfoLog)
129 {
130 delete [] mInfoLog;
131 mInfoLog = NULL;
132 }
133 }
134
Program(rx::Renderer * renderer,ResourceManager * manager,GLuint handle)135 Program::Program(rx::Renderer *renderer, ResourceManager *manager, GLuint handle) : mResourceManager(manager), mHandle(handle)
136 {
137 mFragmentShader = NULL;
138 mVertexShader = NULL;
139 mProgramBinary.set(NULL);
140 mDeleteStatus = false;
141 mLinked = false;
142 mRefCount = 0;
143 mRenderer = renderer;
144 }
145
~Program()146 Program::~Program()
147 {
148 unlink(true);
149
150 if (mVertexShader != NULL)
151 {
152 mVertexShader->release();
153 }
154
155 if (mFragmentShader != NULL)
156 {
157 mFragmentShader->release();
158 }
159 }
160
attachShader(Shader * shader)161 bool Program::attachShader(Shader *shader)
162 {
163 if (shader->getType() == GL_VERTEX_SHADER)
164 {
165 if (mVertexShader)
166 {
167 return false;
168 }
169
170 mVertexShader = (VertexShader*)shader;
171 mVertexShader->addRef();
172 }
173 else if (shader->getType() == GL_FRAGMENT_SHADER)
174 {
175 if (mFragmentShader)
176 {
177 return false;
178 }
179
180 mFragmentShader = (FragmentShader*)shader;
181 mFragmentShader->addRef();
182 }
183 else UNREACHABLE();
184
185 return true;
186 }
187
detachShader(Shader * shader)188 bool Program::detachShader(Shader *shader)
189 {
190 if (shader->getType() == GL_VERTEX_SHADER)
191 {
192 if (mVertexShader != shader)
193 {
194 return false;
195 }
196
197 mVertexShader->release();
198 mVertexShader = NULL;
199 }
200 else if (shader->getType() == GL_FRAGMENT_SHADER)
201 {
202 if (mFragmentShader != shader)
203 {
204 return false;
205 }
206
207 mFragmentShader->release();
208 mFragmentShader = NULL;
209 }
210 else UNREACHABLE();
211
212 return true;
213 }
214
getAttachedShadersCount() const215 int Program::getAttachedShadersCount() const
216 {
217 return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
218 }
219
bindAttributeLocation(GLuint index,const char * name)220 void AttributeBindings::bindAttributeLocation(GLuint index, const char *name)
221 {
222 if (index < MAX_VERTEX_ATTRIBS)
223 {
224 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
225 {
226 mAttributeBinding[i].erase(name);
227 }
228
229 mAttributeBinding[index].insert(name);
230 }
231 }
232
bindAttributeLocation(GLuint index,const char * name)233 void Program::bindAttributeLocation(GLuint index, const char *name)
234 {
235 mAttributeBindings.bindAttributeLocation(index, name);
236 }
237
238 // Links the HLSL code of the vertex and pixel shader by matching up their varyings,
239 // compiling them into binaries, determining the attribute mappings, and collecting
240 // a list of uniforms
link()241 bool Program::link()
242 {
243 unlink(false);
244
245 mInfoLog.reset();
246
247 mProgramBinary.set(new ProgramBinary(mRenderer));
248 mLinked = mProgramBinary->link(mInfoLog, mAttributeBindings, mFragmentShader, mVertexShader);
249
250 return mLinked;
251 }
252
getAttributeBinding(const std::string & name) const253 int AttributeBindings::getAttributeBinding(const std::string &name) const
254 {
255 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
256 {
257 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
258 {
259 return location;
260 }
261 }
262
263 return -1;
264 }
265
266 // Returns the program object to an unlinked state, before re-linking, or at destruction
unlink(bool destroy)267 void Program::unlink(bool destroy)
268 {
269 if (destroy) // Object being destructed
270 {
271 if (mFragmentShader)
272 {
273 mFragmentShader->release();
274 mFragmentShader = NULL;
275 }
276
277 if (mVertexShader)
278 {
279 mVertexShader->release();
280 mVertexShader = NULL;
281 }
282 }
283
284 mProgramBinary.set(NULL);
285 mLinked = false;
286 }
287
isLinked()288 bool Program::isLinked()
289 {
290 return mLinked;
291 }
292
getProgramBinary()293 ProgramBinary* Program::getProgramBinary()
294 {
295 return mProgramBinary.get();
296 }
297
setProgramBinary(const void * binary,GLsizei length)298 bool Program::setProgramBinary(const void *binary, GLsizei length)
299 {
300 unlink(false);
301
302 mInfoLog.reset();
303
304 mProgramBinary.set(new ProgramBinary(mRenderer));
305 mLinked = mProgramBinary->load(mInfoLog, binary, length);
306 if (!mLinked)
307 {
308 mProgramBinary.set(NULL);
309 }
310
311 return mLinked;
312 }
313
release()314 void Program::release()
315 {
316 mRefCount--;
317
318 if (mRefCount == 0 && mDeleteStatus)
319 {
320 mResourceManager->deleteProgram(mHandle);
321 }
322 }
323
addRef()324 void Program::addRef()
325 {
326 mRefCount++;
327 }
328
getRefCount() const329 unsigned int Program::getRefCount() const
330 {
331 return mRefCount;
332 }
333
getProgramBinaryLength() const334 GLint Program::getProgramBinaryLength() const
335 {
336 ProgramBinary *programBinary = mProgramBinary.get();
337 if (programBinary)
338 {
339 return programBinary->getLength();
340 }
341 else
342 {
343 return 0;
344 }
345 }
346
getInfoLogLength() const347 int Program::getInfoLogLength() const
348 {
349 return mInfoLog.getLength();
350 }
351
getInfoLog(GLsizei bufSize,GLsizei * length,char * infoLog)352 void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
353 {
354 return mInfoLog.getLog(bufSize, length, infoLog);
355 }
356
getAttachedShaders(GLsizei maxCount,GLsizei * count,GLuint * shaders)357 void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
358 {
359 int total = 0;
360
361 if (mVertexShader)
362 {
363 if (total < maxCount)
364 {
365 shaders[total] = mVertexShader->getHandle();
366 }
367
368 total++;
369 }
370
371 if (mFragmentShader)
372 {
373 if (total < maxCount)
374 {
375 shaders[total] = mFragmentShader->getHandle();
376 }
377
378 total++;
379 }
380
381 if (count)
382 {
383 *count = total;
384 }
385 }
386
getActiveAttribute(GLuint index,GLsizei bufsize,GLsizei * length,GLint * size,GLenum * type,GLchar * name)387 void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
388 {
389 ProgramBinary *programBinary = getProgramBinary();
390 if (programBinary)
391 {
392 programBinary->getActiveAttribute(index, bufsize, length, size, type, name);
393 }
394 else
395 {
396 if (bufsize > 0)
397 {
398 name[0] = '\0';
399 }
400
401 if (length)
402 {
403 *length = 0;
404 }
405
406 *type = GL_NONE;
407 *size = 1;
408 }
409 }
410
getActiveAttributeCount()411 GLint Program::getActiveAttributeCount()
412 {
413 ProgramBinary *programBinary = getProgramBinary();
414 if (programBinary)
415 {
416 return programBinary->getActiveAttributeCount();
417 }
418 else
419 {
420 return 0;
421 }
422 }
423
getActiveAttributeMaxLength()424 GLint Program::getActiveAttributeMaxLength()
425 {
426 ProgramBinary *programBinary = getProgramBinary();
427 if (programBinary)
428 {
429 return programBinary->getActiveAttributeMaxLength();
430 }
431 else
432 {
433 return 0;
434 }
435 }
436
getActiveUniform(GLuint index,GLsizei bufsize,GLsizei * length,GLint * size,GLenum * type,GLchar * name)437 void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
438 {
439 ProgramBinary *programBinary = getProgramBinary();
440 if (programBinary)
441 {
442 return programBinary->getActiveUniform(index, bufsize, length, size, type, name);
443 }
444 else
445 {
446 if (bufsize > 0)
447 {
448 name[0] = '\0';
449 }
450
451 if (length)
452 {
453 *length = 0;
454 }
455
456 *size = 0;
457 *type = GL_NONE;
458 }
459 }
460
getActiveUniformCount()461 GLint Program::getActiveUniformCount()
462 {
463 ProgramBinary *programBinary = getProgramBinary();
464 if (programBinary)
465 {
466 return programBinary->getActiveUniformCount();
467 }
468 else
469 {
470 return 0;
471 }
472 }
473
getActiveUniformMaxLength()474 GLint Program::getActiveUniformMaxLength()
475 {
476 ProgramBinary *programBinary = getProgramBinary();
477 if (programBinary)
478 {
479 return programBinary->getActiveUniformMaxLength();
480 }
481 else
482 {
483 return 0;
484 }
485 }
486
flagForDeletion()487 void Program::flagForDeletion()
488 {
489 mDeleteStatus = true;
490 }
491
isFlaggedForDeletion() const492 bool Program::isFlaggedForDeletion() const
493 {
494 return mDeleteStatus;
495 }
496
validate()497 void Program::validate()
498 {
499 mInfoLog.reset();
500
501 ProgramBinary *programBinary = getProgramBinary();
502 if (isLinked() && programBinary)
503 {
504 programBinary->validate(mInfoLog);
505 }
506 else
507 {
508 mInfoLog.append("Program has not been successfully linked.");
509 }
510 }
511
isValidated() const512 bool Program::isValidated() const
513 {
514 ProgramBinary *programBinary = mProgramBinary.get();
515 if (programBinary)
516 {
517 return programBinary->isValidated();
518 }
519 else
520 {
521 return false;
522 }
523 }
524
525 }
526