c++ - shading - glUniformMatrix4fv falla con un código de error de GL_INVALID_OPERATION
textures in opengl (1)
Eche un vistazo a su llamada glXGetProcAddress
:
glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)glXGetProcAddress((const GLubyte*)"glUniform4fv");
¡Estás solicitando glUniform4fv
lugar de glUniformMatrix4fv
!
Sé que usted dijo que no está utilizando las bibliotecas de extensión de envoltura por razones académicas, pero aún así las recomiendo ampliamente.
Estoy teniendo algo de mala suerte al intentar unir una matriz uniforme de 4x4. Estoy apuntando a OpenGL 3.3 con este programa, pero mi entorno es OpenGL 4.2. Tengo una función que simplemente une una matriz de identidad a un uniforme en mi sombreado de vértice, pero la llamada a glUniformMatrix4fv falla con GL_INVALID_OPERATION.
Aquí está mi sombreado de vértice:
#version 330
in vec4 in_vertex;
uniform mat4 mvMatrix;
void main(void) {
gl_Position = mvMatrix * in_vertex;
}
Soy consciente de los inconvenientes de la transposición de la matriz y la multiplicación de la izquierda / derecha, pero me imagino que es una batalla para cuando realmente puedo pasar una matriz uniforme.
Aquí hay una función simple a la que se hace referencia en la función donde tengo problemas. Solo estoy usando esto por ahora para intentar localizar el lugar donde se produce el error. Dado que la evaluación de glUniformMatrix4fv está en el lado del servidor, no tengo una manera de usar puntos de interrupción, etc.
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);
}
}
Los documentos del SDK dicen que hay algunas razones por las que glMatrixUniform4fv podría establecer GL_INVALID_OPERATION:
- GL_INVALID_OPERATION se genera si no hay ningún objeto de programa actual.
- GL_INVALID_OPERATION se genera si el tamaño de la variable uniforme declarada en el sombreador no coincide con el tamaño indicado por el comando glUniform.
- GL_INVALID_OPERATION se genera si una de las variantes enteras de esta función se usa para cargar una variable uniforme de tipo float, vec2, vec3, vec4, o una matriz de estas, o si se usa una de las variantes de punto flotante de esta función para cargue una variable uniforme de tipo int, ivec2, ivec3 o ivec4, o una matriz de estos.
- GL_INVALID_OPERATION se genera si la ubicación es una ubicación uniforme no válida para el objeto de programa actual y la ubicación no es igual a -1.
- GL_INVALID_OPERATION se genera si el recuento es mayor que 1 y la variable uniforme indicada no es una variable de matriz.
- GL_INVALID_OPERATION se genera si se carga una muestra con un comando que no sea glUniform1i y glUniform1iv.
- GL_INVALID_OPERATION se genera si glUniform se ejecuta entre la ejecución de glBegin y la ejecución correspondiente de glEnd.
Para el contexto, el objeto desde el que se llama a esta función tiene un parámetro llamado active_program que almacena el número del programa GLSL actualmente activado. identity_matrix se declara como:
float identity_matrix[16];
y definido como:
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
};
Sin más preámbulos, aquí está lo que me está dando problemas:
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, ¤t_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");
}
Después de todo eso, aquí está la salida:
There are 1 uniform(s) active in program 3.
Uniform mvMatrix: Type:8b5c Size:1
GL Error 502 encountered in UniformMatrix4f.
El tipo 8b5c es GL_FLOAT_MAT4, por supuesto, y el tamaño es 1, por supuesto, ¡así que no puedo ver cuál de las condiciones de operación no válida me está mordiendo!
Editar:
Aquí está el bucle principal donde se llama UseProgram y esta función:
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)
es solo un contenedor que verifica la validez del int pasado y actualiza el parámetro active_program del objeto.
Edición 2: Gracias a luke por señalarme a gDEBugger, que también detectó el error GL. En la información de la llamada en gDEBugger, noté que solo se enumeraban tres argumentos. Si bien supongo que esto podría deberse a que el cuarto era un puntero a una matriz (¿reside en el lado del cliente o se pasa al lado del servidor cada vez que se llama glUniform?), Me hizo pensar en qué otra cosa podría ser la porque.
En caso de que sea probativo, glUniformMatrix4fv es, en realidad, un puntero de función que obtiene su dirección como tal:
Declaración:
PFNGLUNIFORMMATRIX4FV glUniformMatrix4fv;
Asignación:
glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)glXGetProcAddress((const GLubyte*)"glUniform4fv");
Esta soy yo evitando a GLEW por razones académicas. Sin embargo, cuando estaba mirando a través de glext.h
, noté que también había un PFNGLUNIFORMMATRIX4FVARBPROC, que supongo que está justo ahí para las bases de código escritas antes de que esta función fuera adoptada en el núcleo. Si ese no es el caso, por favor hágamelo saber.