| #include "precompiled.h" | |
| // | |
| // Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| // | |
| // Program.cpp: Implements the gl::Program class. Implements GL program objects | |
| // and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28. | |
| #include "libGLESv2/Program.h" | |
| #include "libGLESv2/ProgramBinary.h" | |
| #include "libGLESv2/ResourceManager.h" | |
| namespace gl | |
| { | |
| const char * const g_fakepath = "C:\\fakepath"; | |
| AttributeBindings::AttributeBindings() | |
| { | |
| } | |
| AttributeBindings::~AttributeBindings() | |
| { | |
| } | |
| InfoLog::InfoLog() : mInfoLog(NULL) | |
| { | |
| } | |
| InfoLog::~InfoLog() | |
| { | |
| delete[] mInfoLog; | |
| } | |
| int InfoLog::getLength() const | |
| { | |
| if (!mInfoLog) | |
| { | |
| return 0; | |
| } | |
| else | |
| { | |
| return strlen(mInfoLog) + 1; | |
| } | |
| } | |
| void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog) | |
| { | |
| int index = 0; | |
| if (bufSize > 0) | |
| { | |
| if (mInfoLog) | |
| { | |
| index = std::min(bufSize - 1, (int)strlen(mInfoLog)); | |
| memcpy(infoLog, mInfoLog, index); | |
| } | |
| infoLog[index] = '\0'; | |
| } | |
| if (length) | |
| { | |
| *length = index; | |
| } | |
| } | |
| // append a santized message to the program info log. | |
| // The D3D compiler includes a fake file path in some of the warning or error | |
| // messages, so lets remove all occurrences of this fake file path from the log. | |
| void InfoLog::appendSanitized(const char *message) | |
| { | |
| std::string msg(message); | |
| size_t found; | |
| do | |
| { | |
| found = msg.find(g_fakepath); | |
| if (found != std::string::npos) | |
| { | |
| msg.erase(found, strlen(g_fakepath)); | |
| } | |
| } | |
| while (found != std::string::npos); | |
| append("%s", msg.c_str()); | |
| } | |
| void InfoLog::append(const char *format, ...) | |
| { | |
| if (!format) | |
| { | |
| return; | |
| } | |
| char info[1024]; | |
| va_list vararg; | |
| va_start(vararg, format); | |
| vsnprintf(info, sizeof(info), format, vararg); | |
| va_end(vararg); | |
| size_t infoLength = strlen(info); | |
| if (!mInfoLog) | |
| { | |
| mInfoLog = new char[infoLength + 2]; | |
| strcpy(mInfoLog, info); | |
| strcpy(mInfoLog + infoLength, "\n"); | |
| } | |
| else | |
| { | |
| size_t logLength = strlen(mInfoLog); | |
| char *newLog = new char[logLength + infoLength + 2]; | |
| strcpy(newLog, mInfoLog); | |
| strcpy(newLog + logLength, info); | |
| strcpy(newLog + logLength + infoLength, "\n"); | |
| delete[] mInfoLog; | |
| mInfoLog = newLog; | |
| } | |
| } | |
| void InfoLog::reset() | |
| { | |
| if (mInfoLog) | |
| { | |
| delete [] mInfoLog; | |
| mInfoLog = NULL; | |
| } | |
| } | |
| Program::Program(rx::Renderer *renderer, ResourceManager *manager, GLuint handle) : mResourceManager(manager), mHandle(handle) | |
| { | |
| mFragmentShader = NULL; | |
| mVertexShader = NULL; | |
| mProgramBinary.set(NULL); | |
| mDeleteStatus = false; | |
| mLinked = false; | |
| mRefCount = 0; | |
| mRenderer = renderer; | |
| } | |
| Program::~Program() | |
| { | |
| unlink(true); | |
| if (mVertexShader != NULL) | |
| { | |
| mVertexShader->release(); | |
| } | |
| if (mFragmentShader != NULL) | |
| { | |
| mFragmentShader->release(); | |
| } | |
| } | |
| bool Program::attachShader(Shader *shader) | |
| { | |
| if (shader->getType() == GL_VERTEX_SHADER) | |
| { | |
| if (mVertexShader) | |
| { | |
| return false; | |
| } | |
| mVertexShader = (VertexShader*)shader; | |
| mVertexShader->addRef(); | |
| } | |
| else if (shader->getType() == GL_FRAGMENT_SHADER) | |
| { | |
| if (mFragmentShader) | |
| { | |
| return false; | |
| } | |
| mFragmentShader = (FragmentShader*)shader; | |
| mFragmentShader->addRef(); | |
| } | |
| else UNREACHABLE(); | |
| return true; | |
| } | |
| bool Program::detachShader(Shader *shader) | |
| { | |
| if (shader->getType() == GL_VERTEX_SHADER) | |
| { | |
| if (mVertexShader != shader) | |
| { | |
| return false; | |
| } | |
| mVertexShader->release(); | |
| mVertexShader = NULL; | |
| } | |
| else if (shader->getType() == GL_FRAGMENT_SHADER) | |
| { | |
| if (mFragmentShader != shader) | |
| { | |
| return false; | |
| } | |
| mFragmentShader->release(); | |
| mFragmentShader = NULL; | |
| } | |
| else UNREACHABLE(); | |
| return true; | |
| } | |
| int Program::getAttachedShadersCount() const | |
| { | |
| return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0); | |
| } | |
| void AttributeBindings::bindAttributeLocation(GLuint index, const char *name) | |
| { | |
| if (index < MAX_VERTEX_ATTRIBS) | |
| { | |
| for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) | |
| { | |
| mAttributeBinding[i].erase(name); | |
| } | |
| mAttributeBinding[index].insert(name); | |
| } | |
| } | |
| void Program::bindAttributeLocation(GLuint index, const char *name) | |
| { | |
| mAttributeBindings.bindAttributeLocation(index, name); | |
| } | |
| // Links the HLSL code of the vertex and pixel shader by matching up their varyings, | |
| // compiling them into binaries, determining the attribute mappings, and collecting | |
| // a list of uniforms | |
| bool Program::link() | |
| { | |
| unlink(false); | |
| mInfoLog.reset(); | |
| mProgramBinary.set(new ProgramBinary(mRenderer)); | |
| mLinked = mProgramBinary->link(mInfoLog, mAttributeBindings, mFragmentShader, mVertexShader); | |
| return mLinked; | |
| } | |
| int AttributeBindings::getAttributeBinding(const std::string &name) const | |
| { | |
| for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++) | |
| { | |
| if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end()) | |
| { | |
| return location; | |
| } | |
| } | |
| return -1; | |
| } | |
| // Returns the program object to an unlinked state, before re-linking, or at destruction | |
| void Program::unlink(bool destroy) | |
| { | |
| if (destroy) // Object being destructed | |
| { | |
| if (mFragmentShader) | |
| { | |
| mFragmentShader->release(); | |
| mFragmentShader = NULL; | |
| } | |
| if (mVertexShader) | |
| { | |
| mVertexShader->release(); | |
| mVertexShader = NULL; | |
| } | |
| } | |
| mProgramBinary.set(NULL); | |
| mLinked = false; | |
| } | |
| bool Program::isLinked() | |
| { | |
| return mLinked; | |
| } | |
| ProgramBinary* Program::getProgramBinary() | |
| { | |
| return mProgramBinary.get(); | |
| } | |
| bool Program::setProgramBinary(const void *binary, GLsizei length) | |
| { | |
| unlink(false); | |
| mInfoLog.reset(); | |
| mProgramBinary.set(new ProgramBinary(mRenderer)); | |
| mLinked = mProgramBinary->load(mInfoLog, binary, length); | |
| if (!mLinked) | |
| { | |
| mProgramBinary.set(NULL); | |
| } | |
| return mLinked; | |
| } | |
| void Program::release() | |
| { | |
| mRefCount--; | |
| if (mRefCount == 0 && mDeleteStatus) | |
| { | |
| mResourceManager->deleteProgram(mHandle); | |
| } | |
| } | |
| void Program::addRef() | |
| { | |
| mRefCount++; | |
| } | |
| unsigned int Program::getRefCount() const | |
| { | |
| return mRefCount; | |
| } | |
| GLint Program::getProgramBinaryLength() const | |
| { | |
| ProgramBinary *programBinary = mProgramBinary.get(); | |
| if (programBinary) | |
| { | |
| return programBinary->getLength(); | |
| } | |
| else | |
| { | |
| return 0; | |
| } | |
| } | |
| int Program::getInfoLogLength() const | |
| { | |
| return mInfoLog.getLength(); | |
| } | |
| void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) | |
| { | |
| return mInfoLog.getLog(bufSize, length, infoLog); | |
| } | |
| void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) | |
| { | |
| int total = 0; | |
| if (mVertexShader) | |
| { | |
| if (total < maxCount) | |
| { | |
| shaders[total] = mVertexShader->getHandle(); | |
| } | |
| total++; | |
| } | |
| if (mFragmentShader) | |
| { | |
| if (total < maxCount) | |
| { | |
| shaders[total] = mFragmentShader->getHandle(); | |
| } | |
| total++; | |
| } | |
| if (count) | |
| { | |
| *count = total; | |
| } | |
| } | |
| void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) | |
| { | |
| ProgramBinary *programBinary = getProgramBinary(); | |
| if (programBinary) | |
| { | |
| programBinary->getActiveAttribute(index, bufsize, length, size, type, name); | |
| } | |
| else | |
| { | |
| if (bufsize > 0) | |
| { | |
| name[0] = '\0'; | |
| } | |
| if (length) | |
| { | |
| *length = 0; | |
| } | |
| *type = GL_NONE; | |
| *size = 1; | |
| } | |
| } | |
| GLint Program::getActiveAttributeCount() | |
| { | |
| ProgramBinary *programBinary = getProgramBinary(); | |
| if (programBinary) | |
| { | |
| return programBinary->getActiveAttributeCount(); | |
| } | |
| else | |
| { | |
| return 0; | |
| } | |
| } | |
| GLint Program::getActiveAttributeMaxLength() | |
| { | |
| ProgramBinary *programBinary = getProgramBinary(); | |
| if (programBinary) | |
| { | |
| return programBinary->getActiveAttributeMaxLength(); | |
| } | |
| else | |
| { | |
| return 0; | |
| } | |
| } | |
| void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) | |
| { | |
| ProgramBinary *programBinary = getProgramBinary(); | |
| if (programBinary) | |
| { | |
| return programBinary->getActiveUniform(index, bufsize, length, size, type, name); | |
| } | |
| else | |
| { | |
| if (bufsize > 0) | |
| { | |
| name[0] = '\0'; | |
| } | |
| if (length) | |
| { | |
| *length = 0; | |
| } | |
| *size = 0; | |
| *type = GL_NONE; | |
| } | |
| } | |
| GLint Program::getActiveUniformCount() | |
| { | |
| ProgramBinary *programBinary = getProgramBinary(); | |
| if (programBinary) | |
| { | |
| return programBinary->getActiveUniformCount(); | |
| } | |
| else | |
| { | |
| return 0; | |
| } | |
| } | |
| GLint Program::getActiveUniformMaxLength() | |
| { | |
| ProgramBinary *programBinary = getProgramBinary(); | |
| if (programBinary) | |
| { | |
| return programBinary->getActiveUniformMaxLength(); | |
| } | |
| else | |
| { | |
| return 0; | |
| } | |
| } | |
| void Program::flagForDeletion() | |
| { | |
| mDeleteStatus = true; | |
| } | |
| bool Program::isFlaggedForDeletion() const | |
| { | |
| return mDeleteStatus; | |
| } | |
| void Program::validate() | |
| { | |
| mInfoLog.reset(); | |
| ProgramBinary *programBinary = getProgramBinary(); | |
| if (isLinked() && programBinary) | |
| { | |
| programBinary->validate(mInfoLog); | |
| } | |
| else | |
| { | |
| mInfoLog.append("Program has not been successfully linked."); | |
| } | |
| } | |
| bool Program::isValidated() const | |
| { | |
| ProgramBinary *programBinary = mProgramBinary.get(); | |
| if (programBinary) | |
| { | |
| return programBinary->isValidated(); | |
| } | |
| else | |
| { | |
| return false; | |
| } | |
| } | |
| } |