在 iOS 上的 OpenGL ES 2.0 程序中,我按如下方式编译我的着色器:
setShaderState(state);//enables or disables GL_BLEND
GLuint vertexShader = compileShaderPart(vertexShader, GL_VERTEX_SHADER, state);
GLuint fragmentShader = compileShaderPart(fragmentShader, GL_FRAGMENT_SHADER, state);
//linking
GLuint programHandle = glCreateProgram();
Assert(programHandle != 0, "Program handle 0");
for(auto shaderAttribute : shaderAttributeList){
if(isVertexAttribute(shaderAttribute.attribute())){
glBindAttribLocation(programHandle, shaderAttribute.attribute(), shaderAttribute.attributeName(1).c_str());
}
}
glAttachShader(programHandle, vertexShader);
glAttachShader(programHandle, fragmentShader);
glLinkProgram(programHandle);
Assert(glGetError() == GL_NO_ERROR, "Could not link program");
GLint linkSuccess;
glGetProgramiv(programHandle, GL_LINK_STATUS, &linkSuccess);
if (linkSuccess == GL_FALSE) {
GLchar messages[256];
glGetProgramInfoLog(programHandle, sizeof(messages), 0, &messages[0]);
ELog << messages;
Assert(0, "Error compiling shader");
}
ShaderUniformHandleMap shaderUniformMap;
Shader *shader = new Shader(programHandle, availableShader.name, shaderUniformMap, state);
glUseProgram(programHandle);
auto mesh = Mesh::load("quad");
shader->bindMesh(mesh);
auto temp_texture = Texture2D::load("checker");
for(auto uniform : shader->texture){
glUniform1i(uniform.handle, shader->bindTexture(temp_texture->textureId()));
}
glDrawElements(GL_TRIANGLES, mesh->indexDataSize(), GL_UNSIGNED_SHORT, 0);
为了便于阅读,我省略了统一读取部分,而 compileShaderPart 函数尽可能简单明了。
在仪器中的 openGL ES 分析器中运行应用程序会产生数百次“在预热阶段之外编译的着色器”问题。 glDrawElements 调用不应该处理这个问题吗?
我读到像 GL_Blend 这样改变状态会产生这种影响,所以我编译同一个着色器两次,一次启用 GL_Blend,一次禁用,但没有任何区别。
这里有什么问题?我也发现很难找到关于这个预热东西的信息,到目前为止我已经收集到着色器只在第一次绘制调用之后才真正编译,这就是为什么我最后要绘制那个四边形。
最佳答案
这是在您的主渲染循环中吗?您只需要编译一次着色器,然后在您需要再次使用它时使用带有着色器名称的 glUseProgram 调用来绑定(bind)它。从外观上看,您每次绘制调用都要编译一次,因此会出现数百条警告。另外,我很确定 OpenGL ES 着色器程序不包含渲染管道不同部分的状态,例如混合模式,因此您的第二次编译很可能也是不必要的。
关于iOS 着色器在预热阶段之外编译,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20007897/