1

I want to display an image as texture on a quad with OpenGL ES 2.0 using the Android NDK.

I have the following simple vertex and fragment shader:

#define DISP_SHADER_V_SRC "\
attribute vec4 aPos;\
attribute vec2 aTexCoord;\
varying vec2 vTexCoord;\
void main() {\
    gl_Position = aPos;\
    vTexCoord = aTexCoord;\
 }"

#define DISP_SHADER_F_SRC "\
precision mediump float;\n\
varying vec2 vTexCoord;\n\
uniform sampler2D sTexture;\n\
void main() {\n\
    gl_FragColor = texture2D(sTexture, vTexCoord);\n\
}"

At first, a native "create" method is called when the GLSurfaceView is created. It sets the clear color, builds the shader and gets me a texture id using glGenTextures. A "resize" method sets the current view size. Another method sets the texture data like this:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);

I don't believe that there's something wrong there. The important thing should be the "draw" method. After glClear, glViewport and glUseProgram I do the following:

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texId);

glEnableVertexAttribArray(shAPos);
glVertexAttribPointer(shAPos, 3, GL_FLOAT, false, 0, quadVertices);

glVertexAttribPointer(shATexCoord, 2, GL_FLOAT, false, 0, quadTexCoordsStd);
glEnableVertexAttribArray(shATexCoord);

glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// now glDisableVertex...

I can confirm that the shader basically works, since gl_FragColor=vec4(1.0); results in a white screen. It just does not work when I load a texture. I tried out setting the pixel data to "all white" using memset just to confirm that the issue is not related with my image data, but still the screen stays black. What am I missing?

5
  • Since you're able to draw with a modified shader, it sounds like the sampler is just finding zeroes in the texture image. Can you confirm that you're calling glBindTexture(GL_TEXTURE_2D, texId) before the glTexImage2D call? Is the texture using power-of-two sizes?
    – fadden
    Commented Jan 16, 2014 at 20:26
  • I can confirm that. I'm calling glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texId);, then I set GL_CLAMP_TO_EDGE and generate mipmaps. I also checked that vTexCoord has valid values by setting gl_FragColor = vec4(vTexCoord.s, vTexCoord.t, 1.0, 1.0). It all does what it should, besides drawing the damn texture :( Commented Jan 17, 2014 at 8:13
  • 1
    Wow, this took some time... Well I'm not completely sure what the problem was, but I solved it like this: I noticed that drawing the texture worked when I called the texture loading function via JNI directly inside onSurfaceCreated. However, I wanted that the texture changes when I touch the view. I guessed it had something to do with the calling thread. So I moved the code to call the texture loading function from an OnClickListener directly to the class that implements the GLSurfaceView.Renderer. Now it works. Tricky thing though, since no errors were thrown :( Commented Jan 17, 2014 at 9:13
  • Sounds like you moved it to a different thread (UI thread vs. GLSurfaceView render thread). Do you have the same EGL context current in both threads simultaneously?
    – fadden
    Commented Jan 17, 2014 at 15:37
  • I do not see any lines of code where you set the value of the uniform: sTexture to 0. Commented Jan 18, 2014 at 15:58

1 Answer 1

1

IsaacKleiner's own comment was correct, I have met with the same problem, I develop a android app with OpenGL ES 2.0 in C++, using NDK. The function to load texture was in the C++ part originally. For some reason, that did not work. Only after I move the load texture code to java part , did it work as normal. I load the texture in the java part, bind it as normal, and I pass the texture ID to the C++ JNI code. I do not know why there is such a problem. I can provide with a link, in which there is an example that use OpenGL ES 1.0 and NDK to show a cube. Although it is in Chinese, the code can explain itself. please pay attention to how the texture is generated and how the texture id is passed between Java and C++.

2
  • Yes, to make this clear again: The root of the problem is that you cannot use OpenGL functions from two different threads. No matter if they are in the Java or in the C++ JNI part of your application, you should always call the OpenGL functions from the same thread (the very thread that created the EGL context). In my situation, I was calling a GL function from the UI Thread (as @fadden explained), which did not work. After moving it to the GLSurfaceView rendering thread it works. Commented Apr 11, 2015 at 8:41
  • Sorry but this answer is wrong, you definitely can load the texture on the C++ side. As Isaac discovered, OpenGL calls need to be called on a opengl thread (which completely another matter). Commented Apr 1, 2021 at 9:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.