Edit

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

Branch :

  • Show log

    Commit

  • Author : apatrick@chromium.org
    Date : 2011-01-26 19:30:57
    Hash : 0f4cefe9
    Message : Map D3D calls and HLSL shaders back to GLES2 calls and GLSL ES shaders in PIX. This makes debugging and profiling using PIX a lot more convenient. The top level of events are the GLES calls with their arguments. Those can be expanded to see the D3D calls that were issued for a particular GLES call. When PIX is attached, the shaders are saved out to temporary files and referenced from the translated HLSL shaders via #line directives. This enabled source level debugging of the original GLSL from PIX for pixel and vertex shaders. The HLSL is also saved to a temporary file so that intrinsic functions like texture2D can be stepped into. It also avoids creating a text file in the current working directory, which has continued to be an issue. I made the dependency on d3d9.dll static again so it can be accessed by GetModuleHandle witihin DllMain. I added an EVENT macro that issues D3DPERF_BeginEvent and D3DPERF_EndEvent around a C++ block. I replaced TRACE with EVENT for all the entry points. I removed the tracing of shader source since the source is visible in PIX. The means by which the filename of the temporary shader file is passed into the shader compiler is a little clunky. I did it that way to avoid changing the function signatures and breaking folks using the translator. I plan to make the compiler respect #pragma optimize so that optimization can be disabled for debugging purposes. For now it just disables shader optimization in debug builds of ANGLE. Review URL: http://codereview.appspot.com/3945043 git-svn-id: https://angleproject.googlecode.com/svn/trunk@541 736b8ea6-26fd-11df-bfd4-992fa37f6226

  • src/libGLESv2/Shader.cpp
  • //
    // Copyright (c) 2002-2010 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.
    //
    
    // Shader.cpp: Implements the gl::Shader class and its  derived classes
    // VertexShader and FragmentShader. Implements GL shader objects and related
    // functionality. [OpenGL ES 2.0.24] section 2.10 page 24 and section 3.8 page 84.
    
    #include "libGLESv2/Shader.h"
    
    #include <string>
    
    #include "GLSLANG/Shaderlang.h"
    #include "libGLESv2/main.h"
    #include "libGLESv2/utilities.h"
    
    namespace gl
    {
    void *Shader::mFragmentCompiler = NULL;
    void *Shader::mVertexCompiler = NULL;
    
    Shader::Shader(ResourceManager *manager, GLuint handle) : mHandle(handle), mResourceManager(manager)
    {
        mSource = NULL;
        mHlsl = NULL;
        mInfoLog = NULL;
    
        // Perform a one-time initialization of the shader compiler (or after being destructed by releaseCompiler)
        if (!mFragmentCompiler)
        {
            int result = ShInitialize();
    
            if (result)
            {
                ShBuiltInResources resources;
                ShInitBuiltInResources(&resources);
                Context *context = getContext();            
    
                resources.MaxVertexAttribs = MAX_VERTEX_ATTRIBS;
                resources.MaxVertexUniformVectors = MAX_VERTEX_UNIFORM_VECTORS;
                resources.MaxVaryingVectors = context->getMaximumVaryingVectors();
                resources.MaxVertexTextureImageUnits = MAX_VERTEX_TEXTURE_IMAGE_UNITS;
                resources.MaxCombinedTextureImageUnits = MAX_COMBINED_TEXTURE_IMAGE_UNITS;
                resources.MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS;
                resources.MaxFragmentUniformVectors = context->getMaximumFragmentUniformVectors();
                resources.MaxDrawBuffers = MAX_DRAW_BUFFERS;
                resources.OES_standard_derivatives = 1;
    
                mFragmentCompiler = ShConstructCompiler(SH_FRAGMENT_SHADER, SH_GLES2_SPEC, &resources);
                mVertexCompiler = ShConstructCompiler(SH_VERTEX_SHADER, SH_GLES2_SPEC, &resources);
            }
        }
    
        mRefCount = 0;
        mDeleteStatus = false;
    }
    
    Shader::~Shader()
    {
        delete[] mSource;
        delete[] mHlsl;
        delete[] mInfoLog;
    }
    
    GLuint Shader::getHandle() const
    {
        return mHandle;
    }
    
    void Shader::setSource(GLsizei count, const char **string, const GLint *length)
    {
        delete[] mSource;
        int totalLength = 0;
    
        for (int i = 0; i < count; i++)
        {
            if (length && length[i] >= 0)
            {
                totalLength += length[i];
            }
            else
            {
                totalLength += (int)strlen(string[i]);
            }
        }
    
        mSource = new char[totalLength + 1];
        char *code = mSource;
    
        for (int i = 0; i < count; i++)
        {
            int stringLength;
    
            if (length && length[i] >= 0)
            {
                stringLength = length[i];
            }
            else
            {
                stringLength = (int)strlen(string[i]);
            }
    
            strncpy(code, string[i], stringLength);
            code += stringLength;
        }
    
        mSource[totalLength] = '\0';
    }
    
    int Shader::getInfoLogLength() const
    {
        if (!mInfoLog)
        {
            return 0;
        }
        else
        {
           return strlen(mInfoLog) + 1;
        }
    }
    
    void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
    {
        int index = 0;
    
        if (mInfoLog)
        {
            while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
            {
                infoLog[index] = mInfoLog[index];
                index++;
            }
        }
    
        if (bufSize)
        {
            infoLog[index] = '\0';
        }
    
        if (length)
        {
            *length = index;
        }
    }
    
    int Shader::getSourceLength() const
    {
        if (!mSource)
        {
            return 0;
        }
        else
        {
           return strlen(mSource) + 1;
        }
    }
    
    void Shader::getSource(GLsizei bufSize, GLsizei *length, char *source)
    {
        int index = 0;
    
        if (mSource)
        {
            while (index < bufSize - 1 && index < (int)strlen(mSource))
            {
                source[index] = mSource[index];
                index++;
            }
        }
    
        if (bufSize)
        {
            source[index] = '\0';
        }
    
        if (length)
        {
            *length = index;
        }
    }
    
    bool Shader::isCompiled()
    {
        return mHlsl != NULL;
    }
    
    const char *Shader::getHLSL()
    {
        return mHlsl;
    }
    
    void Shader::addRef()
    {
        mRefCount++;
    }
    
    void Shader::release()
    {
        mRefCount--;
    
        if (mRefCount == 0 && mDeleteStatus)
        {
            mResourceManager->deleteShader(mHandle);
        }
    }
    
    unsigned int Shader::getRefCount() const
    {
        return mRefCount;
    }
    
    bool Shader::isFlaggedForDeletion() const
    {
        return mDeleteStatus;
    }
    
    void Shader::flagForDeletion()
    {
        mDeleteStatus = true;
    }
    
    void Shader::releaseCompiler()
    {
        ShDestruct(mFragmentCompiler);
        ShDestruct(mVertexCompiler);
    
        mFragmentCompiler = NULL;
        mVertexCompiler = NULL;
    
        ShFinalize();
    }
    
    void Shader::parseVaryings()
    {
        if (mHlsl)
        {
            const char *input = strstr(mHlsl, "// Varyings") + 12;
    
            while(true)
            {
                char varyingType[256];
                char varyingName[256];
    
                int matches = sscanf(input, "static %255s %255s", varyingType, varyingName);
    
                if (matches != 2)
                {
                    break;
                }
    
                char *array = strstr(varyingName, "[");
                int size = 1;
    
                if (array)
                {
                    size = atoi(array + 1);
                    *array = '\0';
                }
    
                varyings.push_back(Varying(parseType(varyingType), varyingName, size, array != NULL));
    
                input = strstr(input, ";") + 2;
            }
    
            mUsesFragCoord = strstr(mHlsl, "GL_USES_FRAG_COORD") != NULL;
            mUsesFrontFacing = strstr(mHlsl, "GL_USES_FRONT_FACING") != NULL;
            mUsesPointSize = strstr(mHlsl, "GL_USES_POINT_SIZE") != NULL;
            mUsesPointCoord = strstr(mHlsl, "GL_USES_POINT_COORD") != NULL;
        }
    }
    
    void Shader::compileToHLSL(void *compiler)
    {
        if (isCompiled() || !mSource)
        {
            return;
        }
    
        delete[] mInfoLog;
        mInfoLog = NULL;
    
        int compileOptions = SH_OBJECT_CODE;
        std::string sourcePath;
        if (perfActive())
        {
            sourcePath = getTempPath();
            writeFile(sourcePath.c_str(), mSource, strlen(mSource));
            compileOptions |= SH_LINE_DIRECTIVES;
        }
    
        int result;
        if (sourcePath.empty())
        {
            result = ShCompile(compiler, &mSource, 1, compileOptions);
        }
        else
        {
            const char* sourceStrings[2] =
            {
                sourcePath.c_str(),
                mSource
            };
    
            result = ShCompile(compiler, sourceStrings, 2, compileOptions | SH_SOURCE_PATH);
        }
    
        if (result)
        {
            int objCodeLen = 0;
            ShGetInfo(compiler, SH_OBJECT_CODE_LENGTH, &objCodeLen);
            mHlsl = new char[objCodeLen];
            ShGetObjectCode(compiler, mHlsl);
        }
        else
        {
            int infoLogLen = 0;
            ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &infoLogLen);
            mInfoLog = new char[infoLogLen];
            ShGetInfoLog(compiler, mInfoLog);
    
            TRACE("\n%s", mInfoLog);
        }
    }
    
    GLenum Shader::parseType(const std::string &type)
    {
        if (type == "float")
        {
            return GL_FLOAT;
        }
        else if (type == "float2")
        {
            return GL_FLOAT_VEC2;
        }
        else if (type == "float3")
        {
            return GL_FLOAT_VEC3;
        }
        else if (type == "float4")
        {
            return GL_FLOAT_VEC4;
        }
        else if (type == "float2x2")
        {
            return GL_FLOAT_MAT2;
        }
        else if (type == "float3x3")
        {
            return GL_FLOAT_MAT3;
        }
        else if (type == "float4x4")
        {
            return GL_FLOAT_MAT4;
        }
        else UNREACHABLE();
    
        return GL_NONE;
    }
    
    // true if varying x has a higher priority in packing than y
    bool Shader::compareVarying(const Varying &x, const Varying &y)
    {
        if(x.type == y.type)
        {
            return x.size > y.size;
        }
    
        switch (x.type)
        {
          case GL_FLOAT_MAT4: return true;
          case GL_FLOAT_MAT2:
            switch(y.type)
            {
              case GL_FLOAT_MAT4: return false;
              case GL_FLOAT_MAT2: return true;
              case GL_FLOAT_VEC4: return true;
              case GL_FLOAT_MAT3: return true;
              case GL_FLOAT_VEC3: return true;
              case GL_FLOAT_VEC2: return true;
              case GL_FLOAT:      return true;
              default: UNREACHABLE();
            }
            break;
          case GL_FLOAT_VEC4:
            switch(y.type)
            {
              case GL_FLOAT_MAT4: return false;
              case GL_FLOAT_MAT2: return false;
              case GL_FLOAT_VEC4: return true;
              case GL_FLOAT_MAT3: return true;
              case GL_FLOAT_VEC3: return true;
              case GL_FLOAT_VEC2: return true;
              case GL_FLOAT:      return true;
              default: UNREACHABLE();
            }
            break;
          case GL_FLOAT_MAT3:
            switch(y.type)
            {
              case GL_FLOAT_MAT4: return false;
              case GL_FLOAT_MAT2: return false;
              case GL_FLOAT_VEC4: return false;
              case GL_FLOAT_MAT3: return true;
              case GL_FLOAT_VEC3: return true;
              case GL_FLOAT_VEC2: return true;
              case GL_FLOAT:      return true;
              default: UNREACHABLE();
            }
            break;
          case GL_FLOAT_VEC3:
            switch(y.type)
            {
              case GL_FLOAT_MAT4: return false;
              case GL_FLOAT_MAT2: return false;
              case GL_FLOAT_VEC4: return false;
              case GL_FLOAT_MAT3: return false;
              case GL_FLOAT_VEC3: return true;
              case GL_FLOAT_VEC2: return true;
              case GL_FLOAT:      return true;
              default: UNREACHABLE();
            }
            break;
          case GL_FLOAT_VEC2:
            switch(y.type)
            {
              case GL_FLOAT_MAT4: return false;
              case GL_FLOAT_MAT2: return false;
              case GL_FLOAT_VEC4: return false;
              case GL_FLOAT_MAT3: return false;
              case GL_FLOAT_VEC3: return false;
              case GL_FLOAT_VEC2: return true;
              case GL_FLOAT:      return true;
              default: UNREACHABLE();
            }
            break;
          case GL_FLOAT: return false;
          default: UNREACHABLE();
        }
    
        return false;
    }
    
    VertexShader::VertexShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle)
    {
    }
    
    VertexShader::~VertexShader()
    {
    }
    
    GLenum VertexShader::getType()
    {
        return GL_VERTEX_SHADER;
    }
    
    void VertexShader::compile()
    {
        compileToHLSL(mVertexCompiler);
        parseAttributes();
        parseVaryings();
    }
    
    int VertexShader::getSemanticIndex(const std::string &attributeName)
    {
        if (!attributeName.empty())
        {
            int semanticIndex = 0;
            for (AttributeArray::iterator attribute = mAttributes.begin(); attribute != mAttributes.end(); attribute++)
            {
                if (attribute->name == attributeName)
                {
                    return semanticIndex;
                }
    
                semanticIndex += VariableRowCount(attribute->type);
            }
        }
    
        return -1;
    }
    
    void VertexShader::parseAttributes()
    {
        if (mHlsl)
        {
            const char *input = strstr(mHlsl, "// Attributes") + 14;
    
            while(true)
            {
                char attributeType[256];
                char attributeName[256];
    
                int matches = sscanf(input, "static %255s _%255s", attributeType, attributeName);
    
                if (matches != 2)
                {
                    break;
                }
    
                mAttributes.push_back(Attribute(parseType(attributeType), attributeName));
    
                input = strstr(input, ";") + 2;
            }
        }
    }
    
    FragmentShader::FragmentShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle)
    {
    }
    
    FragmentShader::~FragmentShader()
    {
    }
    
    GLenum FragmentShader::getType()
    {
        return GL_FRAGMENT_SHADER;
    }
    
    void FragmentShader::compile()
    {
        compileToHLSL(mFragmentCompiler);
        parseVaryings();
        varyings.sort(compareVarying);
    }
    }