2 // Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
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.
10 #include "libGLESv2/Program.h"
11 #include "libGLESv2/ProgramBinary.h"
12 #include "libGLESv2/ResourceManager.h"
13 #include "libGLESv2/renderer/Renderer.h"
17 const char * const g_fakepath = "C:\\fakepath";
19 AttributeBindings::AttributeBindings()
23 AttributeBindings::~AttributeBindings()
27 InfoLog::InfoLog() : mInfoLog(NULL)
37 int InfoLog::getLength() const
45 return strlen(mInfoLog) + 1;
49 void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog)
57 index = std::min(bufSize - 1, (int)strlen(mInfoLog));
58 memcpy(infoLog, mInfoLog, index);
61 infoLog[index] = '\0';
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.
73 void InfoLog::appendSanitized(const char *message)
75 std::string msg(message);
80 found = msg.find(g_fakepath);
81 if (found != std::string::npos)
83 msg.erase(found, strlen(g_fakepath));
86 while (found != std::string::npos);
88 append("%s", msg.c_str());
91 void InfoLog::append(const char *format, ...)
99 va_start(vararg, format);
100 size_t infoLength = vsnprintf(NULL, 0, format, vararg);
103 char *logPointer = NULL;
107 mInfoLog = new char[infoLength + 2];
108 logPointer = mInfoLog;
112 size_t currentlogLength = strlen(mInfoLog);
113 char *newLog = new char[currentlogLength + infoLength + 2];
114 strcpy(newLog, mInfoLog);
119 logPointer = mInfoLog + currentlogLength;
122 va_start(vararg, format);
123 vsnprintf(logPointer, infoLength, format, vararg);
126 logPointer[infoLength] = 0;
127 strcpy(logPointer + infoLength, "\n");
130 void InfoLog::reset()
139 Program::Program(rx::Renderer *renderer, ResourceManager *manager, GLuint handle) : mResourceManager(manager), mHandle(handle)
141 mFragmentShader = NULL;
142 mVertexShader = NULL;
143 mProgramBinary.set(NULL);
144 mDeleteStatus = false;
147 mRenderer = renderer;
149 resetUniformBlockBindings();
156 if (mVertexShader != NULL)
158 mVertexShader->release();
161 if (mFragmentShader != NULL)
163 mFragmentShader->release();
167 bool Program::attachShader(Shader *shader)
169 if (shader->getType() == GL_VERTEX_SHADER)
176 mVertexShader = shader;
177 mVertexShader->addRef();
179 else if (shader->getType() == GL_FRAGMENT_SHADER)
186 mFragmentShader = shader;
187 mFragmentShader->addRef();
194 bool Program::detachShader(Shader *shader)
196 if (shader->getType() == GL_VERTEX_SHADER)
198 if (mVertexShader != shader)
203 mVertexShader->release();
204 mVertexShader = NULL;
206 else if (shader->getType() == GL_FRAGMENT_SHADER)
208 if (mFragmentShader != shader)
213 mFragmentShader->release();
214 mFragmentShader = NULL;
221 int Program::getAttachedShadersCount() const
223 return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
226 void AttributeBindings::bindAttributeLocation(GLuint index, const char *name)
228 if (index < MAX_VERTEX_ATTRIBS)
230 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
232 mAttributeBinding[i].erase(name);
235 mAttributeBinding[index].insert(name);
239 void Program::bindAttributeLocation(GLuint index, const char *name)
241 mAttributeBindings.bindAttributeLocation(index, name);
244 // Links the HLSL code of the vertex and pixel shader by matching up their varyings,
245 // compiling them into binaries, determining the attribute mappings, and collecting
246 // a list of uniforms
247 Error Program::link(const Caps &caps)
252 resetUniformBlockBindings();
254 mProgramBinary.set(new ProgramBinary(mRenderer->createProgram()));
255 LinkResult result = mProgramBinary->link(mInfoLog, mAttributeBindings, mFragmentShader, mVertexShader,
256 mTransformFeedbackVaryings, mTransformFeedbackBufferMode, caps);
257 if (result.error.isError())
262 mLinked = result.linkSuccess;
263 return gl::Error(GL_NO_ERROR);
266 int AttributeBindings::getAttributeBinding(const std::string &name) const
268 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
270 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
279 // Returns the program object to an unlinked state, before re-linking, or at destruction
280 void Program::unlink(bool destroy)
282 if (destroy) // Object being destructed
286 mFragmentShader->release();
287 mFragmentShader = NULL;
292 mVertexShader->release();
293 mVertexShader = NULL;
297 mProgramBinary.set(NULL);
301 bool Program::isLinked()
306 ProgramBinary* Program::getProgramBinary() const
308 return mProgramBinary.get();
311 Error Program::setProgramBinary(GLenum binaryFormat, const void *binary, GLsizei length)
317 mProgramBinary.set(new ProgramBinary(mRenderer->createProgram()));
318 LinkResult result = mProgramBinary->load(mInfoLog, binaryFormat, binary, length);
319 if (result.error.isError())
321 mProgramBinary.set(NULL);
325 mLinked = result.linkSuccess;
326 return Error(GL_NO_ERROR);
329 void Program::release()
333 if (mRefCount == 0 && mDeleteStatus)
335 mResourceManager->deleteProgram(mHandle);
339 void Program::addRef()
344 unsigned int Program::getRefCount() const
349 GLint Program::getProgramBinaryLength() const
351 ProgramBinary *programBinary = mProgramBinary.get();
354 return programBinary->getLength();
362 int Program::getInfoLogLength() const
364 return mInfoLog.getLength();
367 void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
369 return mInfoLog.getLog(bufSize, length, infoLog);
372 void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
378 if (total < maxCount)
380 shaders[total] = mVertexShader->getHandle();
388 if (total < maxCount)
390 shaders[total] = mFragmentShader->getHandle();
402 void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
404 ProgramBinary *programBinary = getProgramBinary();
407 programBinary->getActiveAttribute(index, bufsize, length, size, type, name);
426 GLint Program::getActiveAttributeCount()
428 ProgramBinary *programBinary = getProgramBinary();
431 return programBinary->getActiveAttributeCount();
439 GLint Program::getActiveAttributeMaxLength()
441 ProgramBinary *programBinary = getProgramBinary();
444 return programBinary->getActiveAttributeMaxLength();
452 void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
454 ProgramBinary *programBinary = getProgramBinary();
457 return programBinary->getActiveUniform(index, bufsize, length, size, type, name);
476 GLint Program::getActiveUniformCount()
478 ProgramBinary *programBinary = getProgramBinary();
481 return programBinary->getActiveUniformCount();
489 GLint Program::getActiveUniformMaxLength()
491 ProgramBinary *programBinary = getProgramBinary();
494 return programBinary->getActiveUniformMaxLength();
502 void Program::flagForDeletion()
504 mDeleteStatus = true;
507 bool Program::isFlaggedForDeletion() const
509 return mDeleteStatus;
512 void Program::validate(const Caps &caps)
516 ProgramBinary *programBinary = getProgramBinary();
517 if (isLinked() && programBinary)
519 programBinary->validate(mInfoLog, caps);
523 mInfoLog.append("Program has not been successfully linked.");
527 bool Program::isValidated() const
529 ProgramBinary *programBinary = mProgramBinary.get();
532 return programBinary->isValidated();
540 GLint Program::getActiveUniformBlockCount()
542 ProgramBinary *programBinary = getProgramBinary();
545 return static_cast<GLint>(programBinary->getActiveUniformBlockCount());
553 GLint Program::getActiveUniformBlockMaxLength()
555 ProgramBinary *programBinary = getProgramBinary();
558 return static_cast<GLint>(programBinary->getActiveUniformBlockMaxLength());
566 void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
568 mUniformBlockBindings[uniformBlockIndex] = uniformBlockBinding;
571 GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
573 return mUniformBlockBindings[uniformBlockIndex];
576 void Program::resetUniformBlockBindings()
578 for (unsigned int blockId = 0; blockId < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; blockId++)
580 mUniformBlockBindings[blockId] = 0;
584 void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
586 mTransformFeedbackVaryings.resize(count);
587 for (GLsizei i = 0; i < count; i++)
589 mTransformFeedbackVaryings[i] = varyings[i];
592 mTransformFeedbackBufferMode = bufferMode;
595 void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const
597 ProgramBinary *programBinary = getProgramBinary();
598 if (programBinary && index < programBinary->getTransformFeedbackVaryingCount())
600 const LinkedVarying &varying = programBinary->getTransformFeedbackVarying(index);
601 GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varying.name.length()));
604 *length = lastNameIdx;
608 *size = varying.size;
612 *type = varying.type;
616 memcpy(name, varying.name.c_str(), lastNameIdx);
617 name[lastNameIdx] = '\0';
622 GLsizei Program::getTransformFeedbackVaryingCount() const
624 ProgramBinary *programBinary = getProgramBinary();
627 return static_cast<GLsizei>(programBinary->getTransformFeedbackVaryingCount());
635 GLsizei Program::getTransformFeedbackVaryingMaxLength() const
637 ProgramBinary *programBinary = getProgramBinary();
641 for (size_t i = 0; i < programBinary->getTransformFeedbackVaryingCount(); i++)
643 const LinkedVarying &varying = programBinary->getTransformFeedbackVarying(i);
644 maxSize = std::max(maxSize, static_cast<GLsizei>(varying.name.length() + 1));
655 GLenum Program::getTransformFeedbackBufferMode() const
657 ProgramBinary *programBinary = getProgramBinary();
660 return programBinary->getTransformFeedbackBufferMode();
664 return mTransformFeedbackBufferMode;