Edit

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

Branch :

  • Show log

    Commit

  • Author : Jamie Madill
    Date : 2013-07-08 14:02:55
    Hash : 2aeb26a4
    Message : Added support for EXT_frag_depth This change also required that support be added for associating built-in variables with an extension, similar to how functions could be associated with extensions previously. R=alokp@chromium.org Review URL: https://codereview.appspot.com/9827044 git-svn-id: https://angleproject.googlecode.com/svn/trunk@2248 736b8ea6-26fd-11df-bfd4-992fa37f6226 TRAC #23333 Authored-by: bajones@chromium.org Signed-off-by: Shannon Woods Signed-off-by Nicolas Capens Merged-by: Jamie Madill

  • src/libGLESv2/Shader.cpp
  • #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.
    //
    
    // 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 "GLSLANG/ShaderLang.h"
    #include "common/utilities.h"
    #include "libGLESv2/renderer/Renderer.h"
    #include "libGLESv2/Constants.h"
    #include "libGLESv2/ResourceManager.h"
    
    namespace gl
    {
    void *Shader::mFragmentCompiler = NULL;
    void *Shader::mVertexCompiler = NULL;
    
    Shader::Shader(ResourceManager *manager, const rx::Renderer *renderer, GLuint handle)
        : mHandle(handle), mRenderer(renderer), mResourceManager(manager)
    {
        mSource = NULL;
        mHlsl = NULL;
        mInfoLog = NULL;
    
        uncompile();
        initializeCompiler();
    
        mRefCount = 0;
        mDeleteStatus = false;
        mShaderVersion = 100;
    }
    
    Shader::~Shader()
    {
        delete[] mSource;
        delete[] mHlsl;
        delete[] mInfoLog;
    }
    
    GLuint Shader::getHandle() const
    {
        return mHandle;
    }
    
    void Shader::setSource(GLsizei count, const char *const *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 (bufSize > 0)
        {
            if (mInfoLog)
            {
                index = std::min(bufSize - 1, (int)strlen(mInfoLog));
                memcpy(infoLog, mInfoLog, index);
            }
    
            infoLog[index] = '\0';
        }
    
        if (length)
        {
            *length = index;
        }
    }
    
    int Shader::getSourceLength() const
    {
        if (!mSource)
        {
            return 0;
        }
        else
        {
           return strlen(mSource) + 1;
        }
    }
    
    int Shader::getTranslatedSourceLength() const
    {
        if (!mHlsl)
        {
            return 0;
        }
        else
        {
           return strlen(mHlsl) + 1;
        }
    }
    
    void Shader::getSourceImpl(char *source, GLsizei bufSize, GLsizei *length, char *buffer)
    {
        int index = 0;
    
        if (bufSize > 0)
        {
            if (source)
            {
                index = std::min(bufSize - 1, (int)strlen(source));
                memcpy(buffer, source, index);
            }
    
            buffer[index] = '\0';
        }
    
        if (length)
        {
            *length = index;
        }
    }
    
    void Shader::getSource(GLsizei bufSize, GLsizei *length, char *buffer)
    {
        getSourceImpl(mSource, bufSize, length, buffer);
    }
    
    void Shader::getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer)
    {
        getSourceImpl(mHlsl, bufSize, length, buffer);
    }
    
    const sh::ActiveUniforms &Shader::getUniforms()
    {
        return mActiveUniforms;
    }
    
    const sh::ActiveInterfaceBlocks &Shader::getInterfaceBlocks()
    {
        return mActiveInterfaceBlocks;
    }
    
    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;
    }
    
    // Perform a one-time initialization of the shader compiler (or after being destructed by releaseCompiler)
    void Shader::initializeCompiler()
    {
        if (!mFragmentCompiler)
        {
            int result = ShInitialize();
    
            if (result)
            {
                ShShaderOutput hlslVersion = (mRenderer->getMajorShaderModel() >= 4) ? SH_HLSL11_OUTPUT : SH_HLSL9_OUTPUT;
    
                ShBuiltInResources resources;
                ShInitBuiltInResources(&resources);
    
                resources.MaxVertexAttribs = MAX_VERTEX_ATTRIBS;
                resources.MaxVertexUniformVectors = mRenderer->getMaxVertexUniformVectors();
                resources.MaxVaryingVectors = mRenderer->getMaxVaryingVectors();
                resources.MaxVertexTextureImageUnits = mRenderer->getMaxVertexTextureImageUnits();
                resources.MaxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
                resources.MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS;
                resources.MaxFragmentUniformVectors = mRenderer->getMaxFragmentUniformVectors();
                resources.MaxDrawBuffers = mRenderer->getMaxRenderTargets();
                resources.OES_standard_derivatives = mRenderer->getDerivativeInstructionSupport();
                resources.EXT_draw_buffers = mRenderer->getMaxRenderTargets() > 1;
                // resources.OES_EGL_image_external = mRenderer->getShareHandleSupport() ? 1 : 0; // TODO: commented out until the extension is actually supported.
                resources.FragmentPrecisionHigh = 1;   // Shader Model 2+ always supports FP24 (s16e7) which corresponds to highp
                resources.EXT_frag_depth = 1; // Shader Model 2+ always supports explicit depth output
                // GLSL ES 3.0 constants
                resources.MaxVertexOutputVectors = mRenderer->getMaxVaryingVectors();
                resources.MaxFragmentInputVectors = mRenderer->getMaxVaryingVectors();
                resources.MinProgramTexelOffset = -8;   // D3D10_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE
                resources.MaxProgramTexelOffset = 7;    // D3D10_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE
    
                mFragmentCompiler = ShConstructCompiler(SH_FRAGMENT_SHADER, SH_GLES2_SPEC, hlslVersion, &resources);
                mVertexCompiler = ShConstructCompiler(SH_VERTEX_SHADER, SH_GLES2_SPEC, hlslVersion, &resources);
            }
        }
    }
    
    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 string1[256];
                char string2[256];
                char string3[256];
    
                int matches = sscanf(input, "static %255s %255s %255s", string1, string2, string3);
    
                char *interpolation = "linear";   // Default
                char *type = string1;
                char *name = string2;
    
                if (matches == 0)
                {
                    break;
                }
                else if (matches == 3)
                {
                    if (string3[0] != '=')   // Explicit interpolation qualifier
                    {
                        type = string2;
                        name = string3;
                    }
                }
                else UNREACHABLE();
    
                char *array = strstr(name, "[");
                int size = 1;
    
                if (array)
                {
                    size = atoi(array + 1);
                    *array = '\0';
                }
    
                mVaryings.push_back(Varying(parseInterpolation(interpolation), parseType(type), name, size, array != NULL));
    
                input = strstr(input, ";") + 2;
            }
    
            mUsesMultipleRenderTargets = strstr(mHlsl, "GL_USES_MRT") != NULL;
            mUsesFragColor = strstr(mHlsl, "GL_USES_FRAG_COLOR") != NULL;
            mUsesFragData = strstr(mHlsl, "GL_USES_FRAG_DATA") != NULL;
            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;
            mUsesDepthRange = strstr(mHlsl, "GL_USES_DEPTH_RANGE") != NULL;
            mUsesFragDepth = strstr(mHlsl, "GL_USES_FRAG_DEPTH") != NULL;
        }
    }
    
    void Shader::resetVaryingsRegisterAssignment()
    {
        for (VaryingList::iterator var = mVaryings.begin(); var != mVaryings.end(); var++)
        {
            var->reg = -1;
            var->col = -1;
        }
    }
    
    // initialize/clean up previous state
    void Shader::uncompile()
    {
        // set by compileToHLSL
        delete[] mHlsl;
        mHlsl = NULL;
        delete[] mInfoLog;
        mInfoLog = NULL;
    
        // set by parseVaryings
        mVaryings.clear();
    
        mUsesMultipleRenderTargets = false;
        mUsesFragColor = false;
        mUsesFragData = false;
        mUsesFragCoord = false;
        mUsesFrontFacing = false;
        mUsesPointSize = false;
        mUsesPointCoord = false;
        mUsesDepthRange = false;
        mUsesFragDepth = false;
        mShaderVersion = 100;
    
        mActiveUniforms.clear();
        mActiveInterfaceBlocks.clear();
    }
    
    void Shader::compileToHLSL(void *compiler)
    {
        // ensure we don't pass a NULL source to the compiler
        const char *source = "\0";
        if (mSource)
        {
            source = mSource;
        }
    
        // ensure the compiler is loaded
        initializeCompiler();
    
        int compileOptions = SH_OBJECT_CODE;
        std::string sourcePath;
        if (perfActive())
        {
            sourcePath = getTempPath();
            writeFile(sourcePath.c_str(), source, strlen(source));
            compileOptions |= SH_LINE_DIRECTIVES;
        }
    
        int result;
        if (sourcePath.empty())
        {
            result = ShCompile(compiler, &source, 1, compileOptions);
        }
        else
        {
            const char* sourceStrings[2] =
            {
                sourcePath.c_str(),
                source
            };
    
            result = ShCompile(compiler, sourceStrings, 2, compileOptions | SH_SOURCE_PATH);
        }
    
        size_t shaderVersion = 100;
        ShGetInfo(compiler, SH_SHADER_VERSION, &shaderVersion);
    
        mShaderVersion = static_cast<int>(shaderVersion);
    
        if (shaderVersion == 300 && mRenderer->getCurrentClientVersion() < 3)
        {
            const char versionError[] = "GLSL ES 3.00 is not supported by OpenGL ES 2.0 contexts";
            mInfoLog = new char[sizeof(versionError) + 1];
            strcpy(mInfoLog, versionError);
    
            TRACE("\n%s", mInfoLog);
        }
        else if (result)
        {
            size_t objCodeLen = 0;
            ShGetInfo(compiler, SH_OBJECT_CODE_LENGTH, &objCodeLen);
            mHlsl = new char[objCodeLen];
            ShGetObjectCode(compiler, mHlsl);
    
            void *activeUniforms;
            ShGetInfoPointer(compiler, SH_ACTIVE_UNIFORMS_ARRAY, &activeUniforms);
            mActiveUniforms = *(sh::ActiveUniforms*)activeUniforms;
    
            void *activeInterfaceBlocks;
            ShGetInfoPointer(compiler, SH_ACTIVE_INTERFACE_BLOCKS_ARRAY, &activeInterfaceBlocks);
            mActiveInterfaceBlocks = *(sh::ActiveInterfaceBlocks*)activeInterfaceBlocks;
        }
        else
        {
            size_t infoLogLen = 0;
            ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &infoLogLen);
            mInfoLog = new char[infoLogLen];
            ShGetInfoLog(compiler, mInfoLog);
    
            TRACE("\n%s", mInfoLog);
        }
    }
    
    Interpolation Shader::parseInterpolation(const std::string &type)
    {
        if (type == "linear")
        {
            return Smooth;
        }
        else if (type == "centroid")
        {
            return Centroid;
        }
        else if (type == "nointerpolation")
        {
            return Flat;
        }
        else UNREACHABLE();
    
        return Smooth;
    }
    
    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 if (type == "float2x3")
        {
            return GL_FLOAT_MAT2x3;
        }
        else if (type == "float3x2")
        {
            return GL_FLOAT_MAT3x2;
        }
        else if (type == "float2x4")
        {
            return GL_FLOAT_MAT2x4;
        }
        else if (type == "float4x2")
        {
            return GL_FLOAT_MAT4x2;
        }
        else if (type == "float3x4")
        {
            return GL_FLOAT_MAT3x4;
        }
        else if (type == "float4x3")
        {
            return GL_FLOAT_MAT4x3;
        }
        else if (type == "int")
        {
            return GL_INT;
        }
        else if (type == "int2")
        {
            return GL_INT_VEC2;
        }
        else if (type == "int3")
        {
            return GL_INT_VEC3;
        }
        else if (type == "int4")
        {
            return GL_INT_VEC4;
        }
        else if (type == "uint")
        {
            return GL_UNSIGNED_INT;
        }
        else if (type == "uint2")
        {
            return GL_UNSIGNED_INT_VEC2;
        }
        else if (type == "uint3")
        {
            return GL_UNSIGNED_INT_VEC3;
        }
        else if (type == "uint4")
        {
            return GL_UNSIGNED_INT_VEC4;
        }
        else UNREACHABLE();
    
        return GL_NONE;
    }
    
    typedef std::map<GLenum, int> VaryingPriorityMap;
    static VaryingPriorityMap varyingPriorities;
    
    static void makeVaryingPriorityMap()
    {
        varyingPriorities[GL_FLOAT_MAT4]    = 0;
        varyingPriorities[GL_FLOAT_MAT3x4]  = 10;
        varyingPriorities[GL_FLOAT_MAT4x3]  = 20;
        varyingPriorities[GL_FLOAT_MAT2x4]  = 30;
        varyingPriorities[GL_FLOAT_MAT4x2]  = 40;
        varyingPriorities[GL_FLOAT_MAT2]    = 50;
        varyingPriorities[GL_FLOAT_VEC4]    = 60;
        varyingPriorities[GL_INT_VEC4]      = 61;
        varyingPriorities[GL_UNSIGNED_INT_VEC4] = 62;
        varyingPriorities[GL_FLOAT_MAT3]    = 70;
        varyingPriorities[GL_FLOAT_MAT2x3]  = 80;
        varyingPriorities[GL_FLOAT_MAT3x2]  = 90;
        varyingPriorities[GL_FLOAT_VEC3]    = 100;
        varyingPriorities[GL_INT_VEC3]      = 101;
        varyingPriorities[GL_UNSIGNED_INT_VEC3] = 102;
        varyingPriorities[GL_FLOAT_VEC2]    = 110;
        varyingPriorities[GL_INT_VEC2]      = 111;
        varyingPriorities[GL_UNSIGNED_INT_VEC2] = 112;
        varyingPriorities[GL_FLOAT]         = 120;
        varyingPriorities[GL_INT]           = 125;
        varyingPriorities[GL_UNSIGNED_INT]  = 130;
    }
    
    // true if varying x has a higher priority in packing than y
    bool Shader::compareVarying(const Varying &x, const Varying &y)
    {
        if (varyingPriorities.empty())
        {
            makeVaryingPriorityMap();
        }
    
        if(x.type == y.type)
        {
            return x.size > y.size;
        }
    
        VaryingPriorityMap::iterator xPriority = varyingPriorities.find(x.type);
        VaryingPriorityMap::iterator yPriority = varyingPriorities.find(y.type);
    
        ASSERT(xPriority != varyingPriorities.end());
        ASSERT(yPriority != varyingPriorities.end());
    
        return xPriority->second <= yPriority->second;
    }
    
    int Shader::getShaderVersion() const
    {
        return mShaderVersion;
    }
    
    VertexShader::VertexShader(ResourceManager *manager, const rx::Renderer *renderer, GLuint handle)
        : Shader(manager, renderer, handle)
    {
    }
    
    VertexShader::~VertexShader()
    {
    }
    
    GLenum VertexShader::getType()
    {
        return GL_VERTEX_SHADER;
    }
    
    void VertexShader::uncompile()
    {
        Shader::uncompile();
    
        // set by ParseAttributes
        mActiveAttributes.clear();
    }
    
    void VertexShader::compile()
    {
        uncompile();
    
        compileToHLSL(mVertexCompiler);
        parseAttributes();
        parseVaryings();
    }
    
    int VertexShader::getSemanticIndex(const std::string &attributeName)
    {
        if (!attributeName.empty())
        {
            int semanticIndex = 0;
            for (unsigned int attributeIndex = 0; attributeIndex < mActiveAttributes.size(); attributeIndex++)
            {
                const sh::ShaderVariable &attribute = mActiveAttributes[attributeIndex];
    
                if (attribute.name == attributeName)
                {
                    return semanticIndex;
                }
    
                semanticIndex += AttributeRegisterCount(attribute.type);
            }
        }
    
        return -1;
    }
    
    void VertexShader::parseAttributes()
    {
        const char *hlsl = getHLSL();
        if (hlsl)
        {
            void *activeAttributes;
            ShGetInfoPointer(mVertexCompiler, SH_ACTIVE_ATTRIBUTES_ARRAY, &activeAttributes);
            mActiveAttributes = *(sh::ActiveShaderVariables*)activeAttributes;
        }
    }
    
    FragmentShader::FragmentShader(ResourceManager *manager, const rx::Renderer *renderer, GLuint handle)
        : Shader(manager, renderer, handle)
    {
    }
    
    FragmentShader::~FragmentShader()
    {
    }
    
    GLenum FragmentShader::getType()
    {
        return GL_FRAGMENT_SHADER;
    }
    
    void FragmentShader::compile()
    {
        uncompile();
    
        compileToHLSL(mFragmentCompiler);
        parseVaryings();
        mVaryings.sort(compareVarying);
    
        const char *hlsl = getHLSL();
        if (hlsl)
        {
            void *activeOutputVariables;
            ShGetInfoPointer(mFragmentCompiler, SH_ACTIVE_OUTPUT_VARIABLES_ARRAY, &activeOutputVariables);
            mActiveOutputVariables = *(sh::ActiveShaderVariables*)activeOutputVariables;
        }
    }
    
    void FragmentShader::uncompile()
    {
        Shader::uncompile();
    
        mActiveOutputVariables.clear();
    }
    
    const sh::ActiveShaderVariables &FragmentShader::getOutputVariables() const
    {
        return mActiveOutputVariables;
    }
    
    }