更新:谜团解决了……
我使用glGetActiveUniform调查了GLSL认为我的制服是什么类型的变量。
这是输出:
I/KGLT (21149): 2005266104: UNIFORM active_texture_count with size 1 and type 5126 (//kglt/kglt/gpu_program.cpp:368)
类型5126是GL_FLOAT!?!确实使用glUniform1f可以解决问题,但是为什么呢?当着色器中的定义绝对是int时?
以下是的原始问题
我正在将游戏引擎移植到Android。在桌面上,我正在使用OpenGL 3.x和GLSL 1.2,在Android上,我正在使用GLES 2.0。
由于某种原因,我在Android手机上从glUniform1i收到GL_INVALID_OPERATION错误,但我不知道是什么原因。
我添加了一些日志记录来显示问题:
E/KGLT (28500): 2006330776: Attempting to set uniform value of 0 at location 0 for name active_texture_count (//kglt/kglt/gpu_program.cpp:50)
W/Adreno-ES20(28500): <__load_uniform_int:351>: GL_INVALID_OPERATION
E/KGLT (28500): 2006330776: An OpenGL error occurred: void kglt::UniformManager::set_int(const unicode &, const int32_t) - GL_INVALID_OPERATION (//kglt/kglt/utils/gl_error.cpp:41)
您会注意到Adreno-ES20在我这样做之前以及在我致电glUniform1i之前都会记录问题,我记录的是我设置的值,从glGetUniformLocation返回的位置以及统一名称(这并不是很重要)。我已经验证了GL调用是在主线程中进行的,因此这里应该没有线程问题。
根据文档,在以下情况下,glUniformX可以引发INVALID_OPERATION,我将内联注释:
GL_INVALID_OPERATION is generated if there is no current program object.
我已经检查过,肯定有一个程序对象,这是我期望的对象。用
glGetIntegerv(GL_CURRENT_PROGRAM, ...)
检查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.
GLSL中的统一声明是这样的:
uniform int active_texture_count;
在我看来绝对像是一个整数,所以使用glUniform1i是正确的吗?这是我最怀疑的问题,这里涉及某种包装问题吗?
GL_INVALID_OPERATION is generated if one of the integer variants of this function is used to load a uniform variable of type float, vec2, vec3, vec4, or an array of these, or if one of the floating-point variants of this function is used to load a uniform variable of type int, ivec2, ivec3, or ivec4, or an array of these.
见上文,我认为我没有这样做。我绝对使用glUniform1i,该值绝对是整数,并且着色器变量一定是整数。
GL_INVALID_OPERATION is generated if location is an invalid uniform location for the current program object and location is not equal to -1.
我在调用glUniform1i之前立即调用glGetUniformLocation,具有相同的绑定(bind)程序ID。它返回零,这是有效位置(因为-1是错误值)。有什么方法可以验证位置是否引用了我认为是的变量名称?
GL_INVALID_OPERATION is generated if count is greater than 1 and the indicated uniform variable is not an array variable.
count
不是glUniform的1i
变体的参数,因此不适用。GL_INVALID_OPERATION is generated if a sampler is loaded using a command other than glUniform1i and glUniform1iv.
我没有设置采样器值,即使我设置了采样器值,也无论如何我都在使用正确的变体。
我在这里完全不知所措,我盯着这段代码已经好几个小时了,而Google却找不到任何可能表明问题所在的信息。我也不确定下一步应该如何调试它。
如果有帮助的话,下面是片段着色器的全部内容:
uniform sampler2D textures[2];
uniform vec4 global_ambient;
uniform int active_texture_count;
uniform vec4 material_ambient;
varying vec2 frag_texcoord0;
varying vec2 frag_texcoord1;
varying vec4 frag_diffuse;
void main() {
if(active_texture_count == 0) {
gl_FragColor = frag_diffuse * global_ambient * material_ambient;
} else {
vec4 t1 = texture2D(textures[0], frag_texcoord0.st);
vec4 t2 = texture2D(textures[1], frag_texcoord1.st);
if(active_texture_count < 2) {
t2 = vec4(1.0, 1.0, 1.0, 0.0);
}
gl_FragColor = (((1.0 - t2.a) * t1) + (t2.a * t2)) * frag_diffuse * global_ambient * material_ambient;
}
}
编辑:我已经将代码更新为非常明确的代码,因此这是当前代码
if(glGetError() != GL_NO_ERROR) {
L_DEBUG("There was an error before setting the uniform");
}
glUseProgram(program_.program_object_);
if(glGetError() != GL_NO_ERROR) {
L_DEBUG("There was an error after using the program");
}
GLint loc = glGetUniformLocation(program_.program_object_, name.c_str());//locate(uniform_name);
if(glGetError() != GL_NO_ERROR) {
L_DEBUG("There was an error after getting the uniform location");
}
L_DEBUG(_u("Setting value {0} for uniform at location {1}").format(value, loc));
glUniform1i(loc, value);
if(glGetError() != GL_NO_ERROR) {
L_DEBUG("There was an error after setting the uniform");
} else {
L_DEBUG("Uniform set sucessfully");
}
这是日志记录输出
I/KGLT (12770): 2005266248: Setting value 0 for uniform at location 0 (//kglt/kglt/gpu_program.cpp:64)
W/Adreno-ES20(12770): <__load_uniform_int:351>: GL_INVALID_OPERATION
I/KGLT (12770): 2005266248: There was an error after setting the uniform (//kglt/kglt/gpu_program.cpp:68)
如您所见,之前没有错误,程序处于 Activity 状态,位置是直接从GL返回的位置...有什么想法吗? :(
最佳答案
这与着色器中的版本声明或精度声明有关。
以前,我只是
#version 120
...因为此着色器是为桌面GL编写的。当我尝试在较旧的设备上进行测试时,着色器编译器抱怨不支持120版,因此我被迫将其更改为
#version 100
precision mediump float;
进行此更改后,变量现在可以在两个设备上正确地报告为整数。我相信这是在Nexus 5上使用120版时的驱动程序错误。无论如何,这是我的最佳猜测!