web-dev-qa-db-ja.com

glUniformMatrix4fvは、GL_INVALID_OPERATIONのエラーコードで失敗します

均一な4x4マトリックスをバインドしようとして運が悪かった。このプログラムでOpenGL3.3をターゲットにしていますが、私の環境はOpenGL4.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. GL_INVALID_OPERATIONは、シェーダーで宣言された一様変数のサイズがglUniformコマンドで示されたサイズと一致しない場合に生成されます。
  3. GL_INVALID_OPERATIONは、この関数の整数バリアントの1つを使用して、float、vec2、vec3、vec4、またはこれらの配列型の均一変数をロードする場合、またはこの関数の浮動小数点バリアントの1つを使用してタイプint、ivec2、ivec3、またはivec4の均一変数、またはこれらの配列をロードします。
  4. GL_INVALID_OPERATIONは、locationが現在のプログラムオブジェクトの無効な均一ロケーションであり、locationが-1に等しくない場合に生成されます。
  5. GL_INVALID_OPERATIONは、カウントが1より大きく、示された一様変数が配列変数ではない場合に生成されます。
  6. GL_INVALID_OPERATIONは、glUniform1iおよびglUniform1iv以外のコマンドを使用してサンプラーがロードされた場合に生成されます。
  7. GL_INVALID_OPERATIONは、glBeginの実行と対応するglEndの実行の間にglUniformが実行された場合に生成されます。

コンテキストとして、この関数が呼び出されるオブジェクトには、現在アクティブ化されているGLSLプログラムの番号を格納するactive_programというパラメーターがあります。 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なので、どの無効な操作条件が私を噛んでいるのかわかりません。

編集:

UseProgramとこの関数が呼び出されるmainのループは次のとおりです。

_    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:gDEBuggerを指してくれた luke に感謝します。これはGLエラーも検出しました。gDEBuggerの呼び出し情報で、3つの引数のみがリストされていることに気付きました。これは4番目が配列へのポインターであったためかもしれないと思いますが(それはクライアント側にありますか、それともglUniformが呼び出されるたびにサーバー側に渡されますか?)、他に何が原因であるかを考えさせられました。

確率的な場合、glUniformMatrix4fvはもちろん、実際には次のようにアドレスを取得する関数ポインタです。

宣言:

_PFNGLUNIFORMMATRIX4FV glUniformMatrix4fv;
_

割り当て:

_glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)glXGetProcAddress((const GLubyte*)"glUniform4fv");
_

これは私が学術的な理由でGLEWを避けていることです。ただし、_glext.h_を調べていたときに、PFNGLUNIFORMMATRIX4FVARBPROCがあることに気付きました。これは、この関数がコアに採用される前に記述されたコードベース用にあると思います。 。そうでない場合は、私に知らせてください。

16
user530229

glXGetProcAddressの呼び出しを見てください。

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

glUniform4fvではなくglUniformMatrix4fvをリクエストしています!

学術的な理由で拡張ラッパーライブラリを使用していないとのことですが、それでも強くお勧めします。

9
luke