glUniformMatrix4fv失败,错误代码为GL_INVALID_OPERATION

时间:2012-03-12 02:29:29

标签: c++ opengl glsl

我试图绑定一个统一的4x4矩阵运气不好。我用这个程序瞄准OpenGL 3.3,但我的环境是OpenGL 4.2。我有一个函数,它简单地将一个单位矩阵绑定到我的顶点着色器中的一个统一体,但是对glUniformMatrix4fv的调用因GL_INVALID_OPERATION而失败。

这是我的顶点着色器:

#version 330
in vec4 in_vertex;
uniform mat4 mvMatrix;
void main(void) {
    gl_Position = mvMatrix * in_vertex;
}

我知道矩阵换位和左/右乘法的缺陷,但我认为这是一场可以实际传递均匀矩阵的战斗。

这是一个在我遇到问题的函数中引用的简单函数。我现在只使用它来尝试确定发生错误的地方。由于glUniformMatrix4fv的评估全部在服务器端,我没有办法使用断点等。

inline void die_on_gl_error(const char* location) {
    GLenum error = GL_NO_ERROR;
    error = glGetError();
    if (GL_NO_ERROR != error) {
        printf("GL Error %x encountered in %s.\n", error, location);
        exit(1);
    }
}

SDK docs说glMatrixUniform4fv可以设置GL_INVALID_OPERATION的原因有几个:

  1. 如果没有当前程序对象,则生成GL_INVALID_OPERATION。
  2. 如果着色器中声明的统一变量的大小与glUniform命令指示的大小不匹配,则会生成GL_INVALID_OPERATION。
  3. 如果此函数的一个整数变量用于加载float,vec2,vec3,vec4或其数组的统一变量,或者如果此函数的某个浮点变体,则生成GL_INVALID_OPERATION用于加载int,ivec2,ivec3或ivec4类型的统一变量,或者这些变量的数组。
  4. 如果location是当前程序对象的无效统一位置且位置不等于-1,则会生成GL_INVALID_OPERATION。
  5. 如果count大于1且指示的统一变量不是数组变量,则生成GL_INVALID_OPERATION。
  6. 如果使用glUniform1i和glUniform1iv以外的命令加载采样器,则会生成GL_INVALID_OPERATION。
  7. 如果在执行glBegin和glEnd的相应执行之间执行glUniform,则会生成GL_INVALID_OPERATION。
  8. 对于上下文,调用此函数的对象具有一个名为active_program的参数,用于存储当前激活的GLSL程序的编号。 identity_matrix声明为:

    float identity_matrix[16];
    

    并定义为:

    identity_matrix = {
                1.0f, 0.0f, 0.0f, 0.0f,
                0.0f, 1.0f, 0.0f, 0.0f,
                0.0f, 0.0f, 1.0f, 0.0f,
                0.0f, 0.0f, 0.0f, 1.0f
    };
    

    不用多说,这就是给我带来麻烦的事情:

    void VSGL::load_identity_matrix() {
    // GL_INVALID_OPERATION is generated if there is no current program object.
    if (!glIsProgram(active_program)) {
        printf("Active program is not valid.\n");
        exit(1);
    }
    
    // ... active_program is a program, but is it valid?
    GLint program_valid = 0;
    glValidateProgram(active_program);
    glGetProgramiv(active_program, GL_VALIDATE_STATUS, &program_valid);
    if (GL_TRUE != program_valid) {
        printf("Program validation failed.\n");
        exit(1);
    }
    die_on_gl_error("GetProgram (Validate Status)");
    
    // ... makes sure there is a program active, and the current program matches
    // the value stored in active_program.
    GLint current_program = 0;
    glGetIntegerv(GL_CURRENT_PROGRAM, &current_program);
    if (0 == current_program) {
        printf("Error, no current program is set.\n");
        exit(1);
    } else if (current_program != active_program) {
        printf("Error, current program doesn't match active_program!\n");
    }
    die_on_gl_error("GetInteger");
    
    // ... ensures the program actually has an active uniform, as the docs
    // say that uniforms can be optimized out if they don't contribute to
    // out results.
    GLint num_active_uniforms = 0;
    glGetProgramiv(active_program, GL_ACTIVE_UNIFORMS, &num_active_uniforms);
    if (0 == num_active_uniforms) {
        printf("There are 0 uniforms active in program %d.\n", active_program);
        exit(1);
    } else {
        printf("There are %d uniform(s) active in program %d.\n", num_active_uniforms, active_program);
    }
    die_on_gl_error("GetProgram (Active Uniforms)");
    
    // GL_INVALID_OPERATION is generated if the size of the uniform variable
    // declared in the shader does not match the size indicated by the glUniform
    // command.
    
    // GL_INVALID_OPERATION is generated if location is an invalid uniform location
    // for the current program object and location is not equal to -1.
    
    // ... gets some basic information about the active uniforms, of which there
    // should be only one, a FLOAT_MAT4 of size 1.
    const GLchar *uniform_name = "mvMatrix";
    GLint location = glGetUniformLocation(active_program, uniform_name);
    die_on_gl_error("GetUniformLocation");
    
    GLchar *message;
    GLint max_uniform_length;
    glGetProgramiv(active_program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_uniform_length);
    message = new GLchar[max_uniform_length];
    GLint size;
    GLenum type;
    glGetActiveUniform(active_program, location, max_uniform_length, NULL, &size, &type, message);
    printf("Uniform %s:\tType:%x\tSize:%d\n", message, type, size);
    if (GL_FLOAT_MAT4 != type) {
        printf("Active uniform at location is not a 4x4 float matrix.\n");
    }
    die_on_gl_error("GetActiveUniform");
    
    // GL_INVALID_OPERATION is generated if count is greater than 1 and the indicated
    // uniform variable is not an array variable.
    
    // GL_INVALID_OPERATION is generated if a sampler is loaded using a command other than
    // glUniform1i and glUniform1iv.
    
    // GL_INVALID_OPERATION is generated if glUniform is executed between the execution
    // of glBegin and the corresponding execution of glEnd.
    
    // None of the above are true, and yet the following dies with GL_INVALID_OPERATION?
    glUniformMatrix4fv(location, 1, false, identity_matrix);
    die_on_gl_error("UniformMatrix4f");
    }
    

    毕竟,这是输出:

    There are 1 uniform(s) active in program 3.
    Uniform mvMatrix:   Type:8b5c   Size:1
    GL Error 502 encountered in UniformMatrix4f.
    

    类型8b5c当然是GL_FLOAT_MAT4,大小是1,当然,所以我看不出哪个无效的操作条件正在咬我!

    编辑:

    这是main中的循环,其中调用了UseProgram和这个函数:

        while (wm->update()) {
            wm->poll_input();
            handle_input(viewingmatrix);
            if (!gl->use_program(program))
                exit(-1);
            gl->load_identity_matrix();
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
            glDrawArrays(GL_TRIANGLES, 0, bananaNumVerts);
            glFlush();
            usleep(16667);
        }
    

    gl->use_program(program)只是一个包装器,用于检查传入的int的有效性并更新对象的active_program参数。

    编辑2: 感谢luke指向gDEBugger,它也检测到GL错误。在gDEBugger的调用信息中,我注意到只列出了三个参数。虽然我认为这可能是因为第四个是指向数组的指针(它是驻留在客户端,还是每次调用glUniform时都传递给服务器端?),它让我想到了其他可能是什么原因。

    如果它是证明,glUniformMatrix4fv当然是一个函数指针,它可以像这样获得它的地址:

    声明:

    PFNGLUNIFORMMATRIX4FV glUniformMatrix4fv;
    

    分配:

    glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)glXGetProcAddress((const GLubyte*)"glUniform4fv");
    

    这是我出于学术原因避免使用GLEW的原因。但是,当我查看glext.h时,我注意到一个PFNGLUNIFORMMATRIX4FVARBPROC,我认为它只是用于在此函数被采用到核心之前编写的代码库。如果情况并非如此,请告诉我。

1 个答案:

答案 0 :(得分:9)

查看glXGetProcAddress来电:

glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)glXGetProcAddress((const GLubyte*)"glUniform4fv");

您正在申请glUniform4fv而不是glUniformMatrix4fv

我知道你说你出于学术原因没有使用扩展包装库,但我仍然强烈推荐它们。