【问题标题】:glGetProgramIv claims that shader linking failed, but glGetProgramInfoLog is emptyglGetProgramIv 声称着色器链接失败,但 glGetProgramInfoLog 为空
【发布时间】:2017-04-15 12:23:08
【问题描述】:

我目前正在尝试使用 OpenGL 和 C++ 编写一个基本的图形引擎。在这样做的过程中,OpenGl 的行为方式非常奇怪,没有明显的解释。它声称着色器无法编译,但拒绝给出任何类型的错误解释原因。具体来说,当我调用glGetProgramiv 时,返回值为0,但glGetProgramInfoLog 给出一个空字符串¹。

这是一个最小完整的可验证示例:

#include <SDL2/SDL.h>
#include <GL/glew.h>
#include <sstream>
#include <stdexcept>
#include <fstream>

GLuint loadShader(const std::string &path, GLenum type);

int main(int argc, char *argv[]){
    //show window & other housekeeping
    SDL_Init(SDL_INIT_EVERYTHING);
    SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32);
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
    SDL_Window *window = SDL_CreateWindow("test window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
    SDL_GLContext glContext = SDL_GL_CreateContext(window);
    SDL_GL_MakeCurrent(window, glContext);
    GLenum c = glewInit();
    if(c != GLEW_OK){
        std::ostringstream sout;
        sout << "Failed to initialize OpenGl: " << glewGetErrorString(c);
        throw std::runtime_error(sout.str());
    }

    //**** -- BEGIN IMPORTANT BIT -- ****//
    //This is where the shaders are loaded

    //load shaders
    GLuint vertexShader = loadShader("shader.vert", GL_VERTEX_SHADER);
    GLuint fragmentShader = loadShader("shader.frag", GL_FRAGMENT_SHADER);

    //create & link program
    GLuint program = glCreateProgram();
    glAttachShader(program, vertexShader);
    glAttachShader(program, fragmentShader);
    glLinkProgram(program);

    //check for errors
    GLint success;
    glGetProgramiv(program, GL_LINK_STATUS, &success);
    if(!success){
        GLchar infoLog[512];
        GLint size; //gives 0 when checked in debugger
        glGetProgramInfoLog(program, 512, &size, infoLog);
        throw std::runtime_error(std::string("Failed to link shader program: ") + infoLog);
    }

    //cleanup
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    //**** -- END IMPORTANT BIT -- ****//

    //update loop
    bool isClosed = false;
    while(!isClosed){
        SDL_GL_SwapWindow(window);

        SDL_Event e;
        while(SDL_PollEvent(&e)){
            switch(e.type){
                case SDL_QUIT:
                    isClosed = true;
                    break;
            }
        }
    }
}

GLuint loadShader(const std::string &path, GLenum type){
    //load file
    std::ifstream fin(path);
    std::string line, total = "";

    while(std::getline(fin, line)){
        total += (line + "\n");
    }

    //reformat source into OpenGl's ridiculous format
    const char *cArray = total.c_str();
    const char **pointerToCArray = &cArray;

    //create shader
    GLuint shader = glCreateShader(type);
    glShaderSource(shader, 1, pointerToCArray, nullptr);
    glCompileShader(shader);

    //check for erros
    GLint success;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
    if(!success){
        GLchar infoLog[512];
        glGetShaderInfoLog(shader, 512, nullptr, infoLog);
        throw std::runtime_error(std::string("Failed to compile shader: ") + infoLog);
    }
}

MCVE testshader.vert:

#version 330 core

layout (location = 0) in vec3 position;

void main()
{
    gl_Position = vec4(position.x, position.y, position.z, 1.0);
}

MCVE testshader.frag:

#version 330 core

out vec4 color;

void main()
{
    color = vec4(1.0f, 0.5f, 0.2f, 1.0f);
}

当我运行它时,除了窗口的短暂闪烁之外,我还会得到以下输出:

terminate called after throwing an instance of 'std::runtime_error'
  what():  Failed to link shader program: 
Aborted (core dumped)

补充说明:

  • 我使用的是 Ubuntu 16.10 x64
  • 我使用的是 Nvidia GTX 1070,驱动程序版本为 375.39
  • SDL 和 glew 版本分别是从 libsdl2-devlibglew-dev 软件包安装的。我正在使用 pkg-config 进行链接。

在解决此错误的研究过程中,我主要发现了各种论坛和 StackOverflow 帖子,这些帖子在其他人的代码中发现了特定错误。这些都不适用于我的代码,在发现此错误后,我将我的代码与this 据称可以工作的示例进行了比较。这个例子在我的电脑上也能正确编译和运行,排除了任何配置错误。

¹:glGetProgramInfoLog 不可能对外部后果不做任何事情,并且 infoLog 数组恰好在其第一个地址分配了一个空终止符,因为 glGetProgramInfoLog 的大小返回返回 0即使在调用 glGetProgramInfoLog 之前设置为不同的值。

【问题讨论】:

    标签: c++ opengl sdl-2 glew


    【解决方案1】:

    我发现了问题:loadShader() 方法中缺少返回语句。然而,正如我在尝试解决这个问题时所经历的那样,这并没有帮助。因此,我建议任何未来阅读本文的人找到一个工作示例(即this one),该示例执行与您尝试执行的操作类似的操作,并将其代码的较小部分逐步复制/粘贴到您的代码中(或反之亦然)进行一种二分搜索以找到您的错误。

    【讨论】:

    • 使用-Wall -Wextra 启用的警告会对您有所帮助。
    • 你确定吗?这是用于 shader 链接,而不是 c++ 链接。
    • @Luther 他的问题在于他的 c++。所以是的。他确定。 ;) “loadShader() 中缺少返回语句”,c++ 编译器本可以警告他的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多