I've found the problem with setting 2D-texture in shader on GPU Adreno 200(HTC Desire, LG P500). One shader is using in the scene for all objects: vertexs shader: ---------------------- attribute vec4 av4position; attribute vec2 av2texcoord; uniform mat4 mvp; varying vec2 vv2texcoord; void main() { vv2texcoord = av2texcoord; gl_Position = mvp*av4position; } ---------------------- fragment shader: ---------------------- precision mediump float; uniform sampler2D texture0; varying vec2 vv2texcoord; void main() { gl_FragColor = texture2D(texture0, vv2texcoord); } ---------------------- I'm calling glUseProgram once in program. Once in program I'm loading textures to texture units GL_TEXTURE0-GL_TEXTURE3 (Adreno profiler shows that they are correctly downloaded and installed). Next, for each object is setting the texture through glUniform1i(one of 0-3), setting matrix ModelView, vertex buffers and calling glDrawElements. The commands from the window API Calls in Adreno profiler for one object are below: ---------------------- glBindBuffer(target=GL_ARRAY_BUFFER, buffer=4) glBindBuffer(target=GL_ELEMET_ARRAY_BUFFER, buffer=5) glUniform1i(location=1. x=1) glUniformMatrix4fv(location=0. count=1. transpose=0) ( 0.056976. -0.007855. 0.065743. 0.065612) (-0.103458. -0.004326. 0.036206. 0.036134) ( 0.000000. 0.176937. 0.003804. 0.003796) (-30.800861.-29.093822. 113.769836. 115.540527) glVertexAttribPointer(indx=1. size=3.type=GL_FLOAT. normalized=0. stride=20. ptr=0x00000000) glEnableVertexAttribPointer(index=1) glVertexAttribPointer(indx=0. size=2.type=GL_FLOAT. normalized=0. stride=20. ptr=0x0000000C) glEnableVertexAttribPointer(index=0) glDraWElements(mode=GL_TRIANGLES. count=1638. type=GL_UNSIGNED_SHORT. indices=0x00000000. CurrentElementArrayBinding=5) ---------------------- As a result, all objects in the scene have the same texture as the first drawn object. The captured frame in Adreno profiler (Scrubber v2.x) is drawing correctly. On the other GPU (PowerVR 540, Tegra2, Mali400) the same scene is drawing correctly. If use your own copy of the shader for each object, it is drawn correctly. If for each object call glUseProgram(my_shader), and after drawing the set null-shader glUseProgram(0) the scene is drawn correctly. But the FPS goes down due to frequent changes of shaders. It looks like after calling glDrawElements driver remembers the number of texture for active shader. And it can not be changed after that. Can you tell me please where is the issue?
Problem with setting 2D-texture in shader on GPU Adreno 200 (Android)
Posted: Wed, 2012-01-18 12:52
You can confirm or deny that this is a problem in the driver?
Any ideas?
apk file https://docs.google.com/open?id=0ByhICHiEz2nsREFMU2dUcVJRQk9ZNzQwU01IbzYtdw
Ship and sky have same texture on device.
are there any news?
Hi Alex - I'm not seeing a call to glGetUniformLocation to get the uniform's location. Looks like it's possibly hardcoded to 1, but that could change depending on the shader compiler being used.
Also the example you pointed me to looks like it has 3 shaders (might want to simplfy a bit more).
-mark
I created simple test without using ndk. Link https://docs.google.com/open?id=0ByhICHiEz2nsMHMxSnFPUm9MZG8
Alex - appreciate your effort in creating this simple example. Having some problems pulling down the zip file (is there another location you can put it?), but was able to browse GLSurface.java Was able to run the apk (on more recent hardware) and saw 3 triangles (greem, red, and blue). Noticed in your code that you are using glGetUniformLocation.
1) Not able to run profiler since no network permissions set in the manifest
2) With this simple example, what are you seeing when you run on your hardware?
thanks,
mark
Sorry, I forgot about setting permissions in the manifest. Here is a link to a new apk https://docs.google.com/open?id=0ByhICHiEz2nsVWhwUGZ1TW5kdzQ
On Adreno200(HTC Desire) all 3 triangles have red color. On my NexusS(PowerVR540) or else non-adreno devices everything looks fine.
P.S. for easy downloading previous zip-file just press ctrl+s.
Was able to successfully run the apk and profile on one our current test devices, and also confirmed that on an Adreno 200 device the triangles are indeed all red.
Curious about your glGenTextures call - looks like there's a 3rd parameter - 0
Also profiler is showing the blue texture as RGBA and the red and green as RGB. Any reason they would be different?
One more item: Check out: http://www.opengl.org/wiki/GLSL_Sampler#Binding_textures_to_samplers
You probably need to add a glActiveTexture call before binding.
-mark
thanks,
mark f.
I modified the project. Format of textures now RGB. I added calls glActiveTexture and glBindTexture to drawObject function. Result is the same. In glGenTextures the 3rd parameter must be 0 - is the offset in the array. https://docs.google.com/open?id=0ByhICHiEz2nsTDBvVFdMSHY4Z2M
Alex - Could you verify the values of the 3 texture_id's created in loadTexture? It's not too common to use the offset parameter in glGenTextures... You could get by with:
int texture_id;
GLES20.glGenTextures(1, &texture_id);
For C++ we have void glGenTextures(GLsizei n, GLuint* textures) defined in "gl2.h" on example.
But for java-android available only public static void glGenTextures (int n, IntBuffer textures) or public static void glGenTextures (int n, int[] textures, int offset) in android.opengl.GLES20 class (http://developer.android.com/reference/android/opengl/GLES20.html#glGenT...)
We've looked at this more closely and believe it might actually be an issue in our Adreno 200 drivers. It's not a common way of using multiple textures in a shader, but still should work as you have noted.
Adding an addition glBindTexture(GL_TEXTURE_2D,0) call to reset the textures should be an easy workaround:
public void drawObject(Buffer vb, Buffer tb, int texture_bind_index, int texture_id)
{
GLES20.glUseProgram(program);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0+texture_bind_index);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture_id);
GLES20.glUniformMatrix4fv(loc_matrix, 1, false, matrix, 0);
GLES20.glUniform1i(loc_sampler, texture_bind_index);
GLES20.glVertexAttribPointer(loc_position, 3, GLES20.GL_FLOAT, false, 0, vb);
GLES20.glVertexAttribPointer(loc_texcoord, 2, GLES20.GL_FLOAT, false, 0, tb);
GLES20.glEnableVertexAttribArray(loc_position);
GLES20.glEnableVertexAttribArray(loc_texcoord);
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
GLES20.glDisableVertexAttribArray(loc_position);
GLES20.glDisableVertexAttribArray(loc_texcoord);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
}
Mark, thank you for your answers. In my case glBindTexture(GL_TEXTURE_2D,0) call nullify an attempt to reduce the number of installing of textures. I think better will be created for each object instance of a shader. glUseProgam is easier to glBindTexture for performance?