Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
714 views
in Technique[技术] by (71.8m points)

opengl es - Writing to gl_FragColor causes INVALID_OPERATION on Android

I'm trying to master OGLES2 for NDK and stuck with GLSL shaders. The situation is similar to the one already highlighted here, but it seems the reason behind it is somewhat different.

I have the simpliest shaders possible.

Vertex:

#version 110
attribute vec3 vPosition;
void main(void)
{
    gl_Position = vec4(vPosition, 1.0);
    gl_FrontColor = gl_BackColor = vec4(0.3, 0.3, 0.3, 1); // ***
}

Fragment:

#version 110
void main(void)
{
    gl_FragColor = gl_Color;
}

Easy and straight-forward. I even define my triangles straight in the clip space. The starred(***) line in the VS source makes the glUseProgram call to throw the GL_INVALID_OPERATION error (and all subsequent glGetAttribLocation calls do the same) when I run the app on my Android 403 device. I can write to gl_FragColor in FS (some hardcoded vec4 value), but can't even touch the gl_FrontColor/gl_BackColor values in VS.

E/Adreno200-ES20(16211): <qgl2DrvAPI_glUseProgram:1344>: GL_INVALID_OPERATION
E/Adreno200-ES20(16211): <qgl2DrvAPI_glGetAttribLocation:531>: GL_INVALID_OPERATION

I check every possible error (glGetError and glGetShaderInfoLog) during shader compilation and linkage, everything is clear there.

The application works fine on windows when I switch my OGL implementation to a JOGL one (all the bootstrapping and rendering code remains the same). I can use even a vertex attributes containing a color, no problems at all.

Is there a way to fix this behaviour? I don't believe Android OGLES implementation is that sick, probably I'm just missing some of its features...

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

OpenGL ES 2.0 does not have a front/back color. This was removed from core OpenGL 3.x and at the same time never introduced into OpenGL ES 2.0. Likewise, gl_Color is invalid in your fragment shader.

Technically, I think #version 110 is also invalid, as I have never come across a formal specification for GLSL 110 in OpenGL ES. This is very likely a bad habit that people carried over from desktop GL (GLSL was introduced in OpenGL 2.0 starting at #version 110). GLSL 100 does exist but not as a properly ratified specification; it uses very old ARB extensions.

OpenGL ES 2.0 introduced GLSL ES with #version 100, proper GLSL ES shaders should begin with either #version 100 (OpenGL ES 2.0) or #version 300 (OpenGL ES 3.0).


Below are some pre-declared variables that you might encounter when working with shaders that were originally designed for desktop OpenGL (compatibility profile):

Vertex

  • gl_FrontColor
  • gl_BackColor
  • gl_FrontSecondaryColor
  • gl_BackSecondaryColor

Fragment

  • gl_Color
  • gl_SecondaryColor

None of these are valid in core OpenGL 3.x or OpenGL ES 2.0; you will have to create your own varying that is shared between your vertex shader and fragment shader for this purpose.


To correct your situation, I have updated your vertex and fragment shaders to avoid using gl_FrontColor, gl_Color, etc..

Modified Vertex Shader:

#version 100

attribute vec3 vPosition;

// Vertex and Fragment Shaders will both use this varying to communicate
//   interpolated color between vertices...
varying   vec4 color;

void main (void)
{
    gl_Position = vec4 (vPosition, 1.0);
    color       = vec4 (0.3, 0.3, 0.3, 1.0);
}

Modified Fragment Shader:

#version 100

/* This takes the place of the old *gl_Color*, but it does not handle
 *   polygon side. If you _really_ do need a different color for
 *     front and back, then you will have to do things a little
 *       differently (SEE BELOW).
 */
varying vec4 color;

void main(void)
{
    gl_FragColor = color;
}


It is rare that you truly need a different color per-side, but if you actually do, here is how you can achieve this. In order to implement a per-side color in OpenGL ES 2.0, you can use the built-in gl_FrontFacing. This variable is a boolean that tells you which side of the polygon is being shaded.

Hypothetical Two-sided Fragment Shader:

#version 100

varying vec4 front_color;
varying vec4 back_color;

void main (void) {
  gl_FragColor = gl_FrontFacing ? front_color : back_color;
}

If you are using a tutorial to learn GLSL, I suspect you are following one that is based on desktop OpenGL. There are slight differences between OpenGL's GLSL and OpenGL|ES's GLSL, and in ES 2.0 the GLSL syntax is roughly equivalent to OpenGL's GLSL 120.

The biggest difference overall, is that most things that are merely deprecated in desktop OpenGL are actually removed from OpenGL|ES. This is why following a desktop GL tutorial may not be so great - OpenGL 3.0 introduced GLSL version 130, which has syntax ES 2.0 does not understand. At the same time, tutorials written for OpenGL 3.0 are the ones most likely to avoid using deprecated features.

Even though OpenGL and OpenGL|ES are derived from the same API, little nuances like this make it difficult to take tutorials written for one API and apply them to the other :-

I have included links to the specifications for each version of OpenGL, OpenGL ES, GLSL and GLSL ES discussed in the first part of the answer to help you truly "master" OGLES2.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...