【问题标题】:Can't link program, glLinkProgram() give me GL_INVALID_OPERATION无法链接程序,glLinkProgram() 给我 GL_INVALID_OPERATION
【发布时间】:2015-10-16 20:26:24
【问题描述】:

我目前正在学习 OpenGL 3.X,我正在使用 ubuntu 14.04。 我正在使用 C 语言创建我的应用程序和 SDL2 库。

命令

glxinfo | grep "OpenGL version"

给我以下输出

OpenGL version string: 3.0 Mesa 10.1.3

我的着色器创建有问题,这里是加载/编译/链接着色器的代码:

typedef struct  s_shader
{
   GLuint  vertex_id;
   GLuint  fragment_id;
   GLuint  program_id;
}               t_shader;

t_shader    *create_shader(const char *vertex_file, const char *fragment_file)
{
    t_shader    *new_shader;

    new_shader = (t_shader *)malloc(sizeof(t_shader));
    if (new_shader)
    {
        new_shader->vertex_id = glCreateShader(GL_VERTEX_SHADER);
        new_shader->fragment_id = glCreateShader(GL_FRAGMENT_SHADER);
        new_shader->program_id = glCreateProgram();
        load_shader(new_shader, vertex_file, fragment_file);
        glCompileShader(new_shader->vertex_id);
        glCompileShader(new_shader->fragment_id);
        glAttachShader(new_shader->program_id, new_shader->vertex_id);
        glAttachShader(new_shader->program_id, new_shader->fragment_id);
        glLinkProgram(new_shader->program_id);
    }
    return (new_shader);
}

void        load_shader(t_shader *shader,const char *vertex_file,const char *fragment_file)
{
    char    *vertex_file_content;
    char    *fragment_file_content;
    int     vertex_len;
    int     fragment_len;

    vertex_file_content = NULL;
    fragment_file_content = NULL;
    vertex_file_content = get_file_content(vertex_file);
    fragment_file_content = get_file_content(fragment_file);
    vertex_len = strlen(vertex_file_content);
    fragment_len = strlen(fragment_file_content);

    glShaderSource(shader->vertex_id, 1, (const GLchar **)&vertex_file_content, &vertex_len);
    glShaderSource(shader->fragment_id, 1, (const GLchar **)&fragment_file_content, &fragment_len);
}

我在每次 gl 调用后使用 glGetError(),我得到的第一个错误代码是 glLinkProgram() 调用,它给了我一个 GL_INVALID_OPERATION(错误 1282)。 我试图用这样的方式输出日志错误:

    GLchar    buff[1024];
    GLsizei     length;
    glGetProgramInfoLog(new_shader->program_id, 1024, &length, buff);
    printf("length:%i\nlog:'%s'\n", length, buff);

但是日志是空的。

我对片段和顶点着色器都使用了 glIsShader(),它返回 GL_TRUE。 我还在 glCompileShader() 之后使用 glGetShaderInfoLog() 并且片段和顶点着色器的日志都是空的。 我在文档中读到:

如果程序不是程序对象,则生成GL_INVALID_OPERATION。

如果 program 是当前活动的程序对象并且转换反馈模式处于活动状态,则生成 GL_INVALID_OPERATION。

我的程序似乎是一个程序对象,因为 glCreateProgram 返回一个非空值。 此时代码中没有活动的程序对象。

窗口和 OpenGL 上下文:

SDL_Init(SDL_INIT_VIDEO);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);

SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);

window = SDL_CreateWindow("My OpenGl", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
if (window)
{
  SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
  gl_context = SDL_GL_CreateContext(window);

这里是读取文件内容的函数:

char        *get_file_content(const char *file_name)
{
    FILE    *file;
    char    *file_content;
    long    file_size;

    file = NULL;
    file_content = NULL;
    file_size = 0;
    file = fopen(file_name, "r");
    if (file)
    {
        fseek(file, 0, SEEK_END);
        file_size = ftell(file);
        fseek(file, 0, SEEK_SET);
        file_content = (char *)malloc(sizeof(char) * file_size + 1);
        if (file_content)
        {
            memset(file_content, '\0', file_size);
            fread(file_content, sizeof(char), file_size, file);
            file_content[file_size + 1] = '\0';
        }
        fclose(file);
    }
    return (file_content);
}

片段着色器来源:

#version 150 core

in vec3 color;
out vec4 out_Color;

void main()
{
    out_Color = vec4(1.0f, 1.0f, 1.0f, 1.0);
}

顶点着色器来源:

#version 150 core

in vec3 in_Vertex;
in vec3 in_Color;

uniform mat4 projection;
uniform mat4 modelview;

out vec3 color;

void main()
{
    gl_Position = projection * modelview * vec4(in_Vertex, 1.0);
    color = in_Color;
}

还有其他方法可以调试 glLinkProgram 吗?

【问题讨论】:

  • 还有许多其他条件可能会触发该错误。检查着色器编译状态和日志。如果您真的 oosted 着色器源代码,它也可能会有所帮助。
  • 你能发布顶点和片段着色器的源代码吗?你用 glGetShaderInfoLog 检查过他们的编译日志吗?
  • 我编辑了问题,并添加了片段和顶点着色器源。我还使用 glGetShaderInfoLog() 和 glIsShader() 进行调试。
  • 这不太可能导致您的问题,但您正在写入超出get_file_content() 中分配内存的一个字节。零终止符应指定为file_content[file_size] = '\0';

标签: c opengl


【解决方案1】:

您的着色器可能无法编译,因为您尝试在 OpenGL 3.0 上下文中使用 GLSL #version 150(与 OpenGL 3.2 一起引入)。

由于您使用的是 mesa,因此您的 GPU 很可能实际上支持 3.2 或更高版本。但是在 mesa 上,您必须使用 core 配置文件才能访问 OpenGL >= 3.2 上下文。没有它,mesa 将被限制为 GL 3.0,而这正是你得到的。

所以你有两种选择:

  1. 将着色器降级为#version 130。使用您发布的着色器,我看不到任何不适用于该版本的内容,因此仅调整 #version 指令就足够了。

  2. 将您的上下文升级到现代 GL 3.2 核心配置文件。由于您使用的是 SDL2,因此相关函数为 SDL_GL_SetAttribute(),另请参见 the SDL_GLprofile documentation。使用核心配置文件意味着所有已弃用的功能不再可用。您没有发布代码,因此不清楚是否依赖已弃用的功能。

虽然替代方法 1 可能看起来更简单,但我强烈建议您选择变体 2。如果您现在正在学习 GL,您应该学习新方法,而不是十多年前已弃用的方法。

【讨论】:

  • 我尝试了您的第一个替代方案,但它没有改变任何东西。我还尝试了 SDL_GLprofile 以使用核心配置文件(我将代码添加到我的问题中)。但现在我的着色器编译失败:“错误:不支持 GLSL 1.50。支持的版本是:1.10、1.20、1.30 和 1.00 ES”
  • 嗯,您实际上需要另外请求 GL 版本 3.2。错误消息表明您仍在使用 GL 3.0。
  • 现在,我在着色器编译上没有任何错误了。此外,glGetString(GL_VERSION) 返回“3.3 (Core Profile) Mesa 10.1.3”,而 glGetString(GL_SHADING_LANGUAGE_VERSION) 返回“3.30”。所以我假设我现在是 3.3,不是吗?
  • 是的。现在的问题是,如果 a) GLSL 版本是唯一的问题,并且 b) 您的代码不依赖于核心配置文件中不可用的已弃用功能。
  • 我认为我没有使用任何已弃用的功能,但我该如何检查呢?不推荐使用的函数如何使我的 glLinkProgram() 失败?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-20
  • 2013-03-16
  • 2018-08-12
  • 2021-01-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多