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