Edit

kc3-lang/angle/util/shader_utils.cpp

Branch :

  • Show log

    Commit

  • Author : Jamie Madill
    Date : 2016-12-13 15:08:19
    Hash : a7d12dc7
    Message : Store uniform block bindings in program binaries. This affects all back-ends - we weren't saving this. Note that bindings can only be set after program linking. The spec is fairly clear in that any programs saved must be loadable and runnable under the same set of state, which would include block bindings. Also add validation for zero binary formats in GetProgramBinary. Also add a workaround for AMD where the block bindings were not applied properly after link, similarly to our original bug. This CL also includes a few fixups for GLProgram (raii). BUG=angleproject:1637 Change-Id: Iae068eb4e1e4c763aa9f9332c033e38708026c8f Reviewed-on: https://chromium-review.googlesource.com/418393 Reviewed-by: Geoff Lang <geofflang@chromium.org> Reviewed-by: Corentin Wallez <cwallez@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>

  • util/shader_utils.cpp
  • //
    // Copyright (c) 2014 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.
    //
    
    #include "shader_utils.h"
    
    #include <vector>
    #include <iostream>
    #include <fstream>
    
    static std::string ReadFileToString(const std::string &source)
    {
        std::ifstream stream(source.c_str());
        if (!stream)
        {
            std::cerr << "Failed to load shader file: " << source;
            return "";
        }
    
        std::string result;
    
        stream.seekg(0, std::ios::end);
        result.reserve(static_cast<unsigned int>(stream.tellg()));
        stream.seekg(0, std::ios::beg);
    
        result.assign((std::istreambuf_iterator<char>(stream)), std::istreambuf_iterator<char>());
    
        return result;
    }
    
    GLuint CompileShader(GLenum type, const std::string &source)
    {
        GLuint shader = glCreateShader(type);
    
        const char *sourceArray[1] = { source.c_str() };
        glShaderSource(shader, 1, sourceArray, NULL);
        glCompileShader(shader);
    
        GLint compileResult;
        glGetShaderiv(shader, GL_COMPILE_STATUS, &compileResult);
    
        if (compileResult == 0)
        {
            GLint infoLogLength;
            glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
    
            // Info log length includes the null terminator, so 1 means that the info log is an empty
            // string.
            if (infoLogLength > 1)
            {
                std::vector<GLchar> infoLog(infoLogLength);
                glGetShaderInfoLog(shader, static_cast<GLsizei>(infoLog.size()), NULL, &infoLog[0]);
                std::cerr << "shader compilation failed: " << &infoLog[0];
            }
            else
            {
                std::cerr << "shader compilation failed. <Empty log message>";
            }
    
            glDeleteShader(shader);
            shader = 0;
        }
    
        return shader;
    }
    
    GLuint CompileShaderFromFile(GLenum type, const std::string &sourcePath)
    {
        std::string source = ReadFileToString(sourcePath);
        if (source.empty())
        {
            return 0;
        }
    
        return CompileShader(type, source);
    }
    
    GLuint CheckLinkStatusAndReturnProgram(GLuint program, bool outputErrorMessages)
    {
        if (glGetError() != GL_NO_ERROR)
            return 0;
    
        GLint linkStatus;
        glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
        if (linkStatus == 0)
        {
            if (outputErrorMessages)
            {
                GLint infoLogLength;
                glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength);
    
                // Info log length includes the null terminator, so 1 means that the info log is an
                // empty string.
                if (infoLogLength > 1)
                {
                    std::vector<GLchar> infoLog(infoLogLength);
                    glGetProgramInfoLog(program, static_cast<GLsizei>(infoLog.size()), nullptr,
                                        &infoLog[0]);
    
                    std::cerr << "program link failed: " << &infoLog[0];
                }
                else
                {
                    std::cerr << "program link failed. <Empty log message>";
                }
            }
    
            glDeleteProgram(program);
            return 0;
        }
    
        return program;
    }
    
    GLuint CompileProgramWithTransformFeedback(
        const std::string &vsSource,
        const std::string &fsSource,
        const std::vector<std::string> &transformFeedbackVaryings,
        GLenum bufferMode)
    {
        GLuint program = glCreateProgram();
    
        GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
        GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
    
        if (vs == 0 || fs == 0)
        {
            glDeleteShader(fs);
            glDeleteShader(vs);
            glDeleteProgram(program);
            return 0;
        }
    
        glAttachShader(program, vs);
        glDeleteShader(vs);
    
        glAttachShader(program, fs);
        glDeleteShader(fs);
    
        if (transformFeedbackVaryings.size() > 0)
        {
            std::vector<const char *> constCharTFVaryings;
    
            for (const std::string &transformFeedbackVarying : transformFeedbackVaryings)
            {
                constCharTFVaryings.push_back(transformFeedbackVarying.c_str());
            }
    
            glTransformFeedbackVaryings(program, static_cast<GLsizei>(transformFeedbackVaryings.size()),
                                        &constCharTFVaryings[0], bufferMode);
        }
    
        glLinkProgram(program);
    
        return CheckLinkStatusAndReturnProgram(program, true);
    }
    
    GLuint CompileProgram(const std::string &vsSource, const std::string &fsSource)
    {
        std::vector<std::string> emptyVector;
        return CompileProgramWithTransformFeedback(vsSource, fsSource, emptyVector, GL_NONE);
    }
    
    GLuint CompileProgramFromFiles(const std::string &vsPath, const std::string &fsPath)
    {
        std::string vsSource = ReadFileToString(vsPath);
        std::string fsSource = ReadFileToString(fsPath);
        if (vsSource.empty() || fsSource.empty())
        {
            return 0;
        }
    
        return CompileProgram(vsSource, fsSource);
    }
    
    GLuint CompileComputeProgram(const std::string &csSource, bool outputErrorMessages)
    {
        GLuint program = glCreateProgram();
    
        GLuint cs = CompileShader(GL_COMPUTE_SHADER, csSource);
        if (cs == 0)
        {
            glDeleteProgram(program);
            return 0;
        }
    
        glAttachShader(program, cs);
    
        glLinkProgram(program);
    
        return CheckLinkStatusAndReturnProgram(program, outputErrorMessages);
    }
    
    GLuint LoadBinaryProgramOES(const std::vector<uint8_t> &binary, GLenum binaryFormat)
    {
        GLuint program = glCreateProgram();
        glProgramBinaryOES(program, binaryFormat, binary.data(), static_cast<GLint>(binary.size()));
        return CheckLinkStatusAndReturnProgram(program, true);
    }
    
    GLuint LoadBinaryProgramES3(const std::vector<uint8_t> &binary, GLenum binaryFormat)
    {
        GLuint program = glCreateProgram();
        glProgramBinary(program, binaryFormat, binary.data(), static_cast<GLint>(binary.size()));
        return CheckLinkStatusAndReturnProgram(program, true);
    }