Edit

kc3-lang/angle/src/libGLESv2/Program.cpp

Branch :

  • Show log

    Commit

  • Author : apatrick@chromium.org
    Date : 2012-07-09 22:15:33
    Hash : 90080e3b
    Message : Support for serializing a linked program to binary. The format has a text section followed by a binary section. The binary section contains an image of the device caps and the two shader executables. The text section has everything else newline deliminated. Ran WebGL conformance tests with temporary change to glLinkProgram that round trips all linked programs through glGetProgramBinary and glProgramBinary. No regressions. Review URL: https://codereview.appspot.com/6295092 git-svn-id: https://angleproject.googlecode.com/svn/trunk@1199 736b8ea6-26fd-11df-bfd4-992fa37f6226

  • src/libGLESv2/Program.cpp
  • //
    // Copyright (c) 2002-2012 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 "common/debug.h"
    
    #include "libGLESv2/main.h"
    #include "libGLESv2/Shader.h"
    #include "libGLESv2/utilities.h"
    
    #include <string>
    
    namespace gl
    {
    const char * const g_fakepath = "C:\\fakepath";
    
    unsigned int Program::mCurrentSerial = 1;
    
    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\n", 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 + 1];
            strcpy(mInfoLog, info);
        }
        else
        {
            size_t logLength = strlen(mInfoLog);
            char *newLog = new char[logLength + infoLength + 1];
            strcpy(newLog, mInfoLog);
            strcpy(newLog + logLength, info);
    
            delete[] mInfoLog;
            mInfoLog = newLog;
        }
    }
    
    void InfoLog::reset()
    {
        if (mInfoLog)
        {
            delete [] mInfoLog;
            mInfoLog = NULL;
        }
    }
    
    Program::Program(ResourceManager *manager, GLuint handle) : mResourceManager(manager), mHandle(handle), mSerial(issueSerial())
    {
        mFragmentShader = NULL;
        mVertexShader = NULL;
        mProgramBinary = NULL;
        mDeleteStatus = false;
        mRefCount = 0;
    }
    
    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
    void Program::link()
    {
        unlink(false);
    
        mInfoLog.reset();
    
        mProgramBinary = new ProgramBinary;
        if (!mProgramBinary->link(mInfoLog, mAttributeBindings, mFragmentShader, mVertexShader))
        {
            unlink(false);
        }
    }
    
    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;
            }
        }
    
        if (mProgramBinary)
        {
            delete mProgramBinary;
            mProgramBinary = NULL;
        }
    }
    
    ProgramBinary* Program::getProgramBinary()
    {
        return mProgramBinary;
    }
    
    void Program::setProgramBinary(const void *binary, GLsizei length)
    {
        unlink(false);
    
        mInfoLog.reset();
    
        mProgramBinary = new ProgramBinary;
        if (!mProgramBinary->load(mInfoLog, binary, length))
        {
            delete mProgramBinary;
            mProgramBinary = NULL;
        }
    }
    
    void Program::release()
    {
        mRefCount--;
    
        if (mRefCount == 0 && mDeleteStatus)
        {
            mResourceManager->deleteProgram(mHandle);
        }
    }
    
    void Program::addRef()
    {
        mRefCount++;
    }
    
    unsigned int Program::getRefCount() const
    {
        return mRefCount;
    }
    
    unsigned int Program::getSerial() const
    {
        return mSerial;
    }
    
    GLint Program::getProgramBinaryLength() const
    {
        if (mProgramBinary)
        {
            return mProgramBinary->getLength();
        }
        else
        {
            return 0;
        }
    }
    
    unsigned int Program::issueSerial()
    {
        return mCurrentSerial++;
    }
    
    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)
    {
        if (mProgramBinary)
        {
            mProgramBinary->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()
    {
        if (mProgramBinary)
        {
            return mProgramBinary->getActiveAttributeCount();
        }
        else
        {
            return 0;
        }
    }
    
    GLint Program::getActiveAttributeMaxLength()
    {
        if (mProgramBinary)
        {
            return mProgramBinary->getActiveAttributeMaxLength();
        }
        else
        {
            return 0;
        }
    }
    
    void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
    {
        if (mProgramBinary)
        {
            return mProgramBinary->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()
    {
        if (mProgramBinary)
        {
            return mProgramBinary->getActiveUniformCount();
        }
        else
        {
            return 0;
        }
    }
    
    GLint Program::getActiveUniformMaxLength()
    {
        if (mProgramBinary)
        {
            return mProgramBinary->getActiveUniformMaxLength();
        }
        else
        {
            return 0;
        }
    }
    
    void Program::flagForDeletion()
    {
        mDeleteStatus = true;
    }
    
    bool Program::isFlaggedForDeletion() const
    {
        return mDeleteStatus;
    }
    
    void Program::validate()
    {
        mInfoLog.reset();
    
        if (mProgramBinary)
        {
            mProgramBinary->validate(mInfoLog);
        }
        else
        {
            mInfoLog.append("Program has not been successfully linked.");
        }
    }
    
    bool Program::isValidated() const
    {
        if (mProgramBinary)
        {
            return mProgramBinary->isValidated();
        }
        else
        {
            return false;
        }
    }
    
    }