I'm working on an OpenGL ES 3.0 app that works fine in the simulator, but one of the fragment shaders is failing to compile on my iPhone 6 Plus / iOS 9.0.1.
It seems that when multiple color buffer attachments are declared as 'inout', reading from any of them higher than index 0 causes a compiler failure.
Here is the fragment shader, stripped down to its essence:
#version 300 es
#extension GL_EXT_shader_framebuffer_fetch : require
precision highp float;
in vec2 v_texCoord;
layout (location = 0) inout vec4 buffer0;
layout (location = 1) inout vec4 buffer1;
void main()
{
vec4 v0 = buffer0;
vec4 v1 = buffer1;
v0.r += v_texCoord.x; // use v_texCoord in a trivial way to avoid warnings
v1.r += v_texCoord.x;
buffer0 = v0;
buffer1 = v1;
}(When I try to compile this fragment shader at runtime, no syntax errors are reported, but the validation log returned by glGetProgramInfoLog() reads:
Validation Failed: Fragment program failed to compile with current context state.
Validation Failed: Vertex program failed to compile with current context state.
When I change line 14 to "vec4 v1 = vec4(0.0);", the program compiles again.
For reference, here is the vertex shader:
#version 300 es
precision highp float;
in vec2 a_Position;
in vec2 a_texCoord;
out vec2 v_texCoord;
void main() {
v_texCoord = a_texCoord;
gl_Position = vec4(a_Position.x, a_Position.y, 0.0, 1.0);
}This is happening in an otherwise-working OpenGL ES 3.0 context, on an iPhone 6 Plus (A8 chip).
Any help would be appreciated. Thanks!
Wow, solved!
The utility file I was using to compile the shader (shaderUtil.c, by Apple) first compiles and links the shader, then attempts to validate it against the extant GL context. If this validation fails, the program is discarded.
What I didn't realize is that this validation is very sensitive to the GL state. For my particular combination of framebuffer fetch and MRT's, the validation only succeeds (on-device) if the multiple render framebuffer targets have been properly set up and attached in advance. If I first set up these targets, then call glValidateProgram(), it succeeds. But in the more typical case where the boilerplate GL context is created and the shaders are immediately compiled, it fails.
This begs the question of why glValidateProgram() succeeds for this shader in the simulator. (It shouldn't.)
Anyway, what I'm doing now is ignoring the initial validation result for my shaders that use MRT's + framebuffer fetch, and simply returning the shader ID, even if glValidateProgram() fails. I can validate it once again after the context is set up for MRT's, and then the validation succeeds and everything is fine.
Whew! OpenGL is really testing my Mettle... (pun intended :-)