EDIT: figured it out, see answer below.
I'm having a problem trying to render to a texture in OpenGL ES 2.0 on Android (NDK) on Samsung Galaxy S
More specifically i am using a Framebuffer to render to a texture and then i draw from that texture onto the backbuffer - in the emulator (running 4.2.2) and on a Galaxy S2 it renders perfectly, and the same goes for running on a number of iOS devices with the same code.
The Galaxy S is running 2.3.3 (i can't convince the emulator to do this in 2.3.3).
When i set the texture size to 1024x1024 it looks as though it is still being stored in a 512x512 texture, or like some heavy compression is going on, this happens only on the Galaxy S, both an S2, the emulator and the iOS devices render flawlessly.
If i set the texture to 512x512 it seems to render pretty much ok on the Galaxy S, nothing glaring is wrong but you will notice some of the same blurring happing just to a much lesser extent
Screenshot of 1024x1024
Screenshot og 512x512
On both images the upper 4 items are drawn first to the texture and then from there unto the backbuffer (the flaw in the black one is also a Galaxy S only problem, but i'm not considdering it related)
I can load a 1024x1024 texture and render from that just fine, and if i use glReadPixels on the texture's render buffer it looks just fine too (GL ES unfortunately doesn't support reading the pixels off the underlying texture directly)
As you may note it suffers none of the blurryness not even the light kind of the 512x512 version.
To further mystify me i have an older project in Java running OpenGL ES 1.1 that renders to a 1024x1024 texture without any problems on the same Galaxy S device, i have not been desperate enough to write a complete ES 2.0 rendering in Java to see if that makes a difference and i haven't tried ES 1.1 with the NDK as the OES extension methods for the framebuffer create linker errors (it's possible there is a lib that could be linked, i may go there if no one has any better ideas)
I have however tried creating the framebuffer and texture in java and passing the handles to the native code but it makes no difference.
Any pointers, guesses, hunches, magic keywords for google, anything is very much appreciated i have spent 12 hours straight today trying to figure this out and i have made no progress what so ever, i'm nearing desperate.
Following is snippets of code that may be relevant, don't hesitate to ask for more (the entire project is thousands of lines spanning 3 platforms at this point so i have tried picking the most relevant parts.)
Code for creating the framebuffer:
glGenFramebuffers(1, &FFrameBufferID);
glBindFramebuffer(GL_FRAMEBUFFER, FFrameBufferID);
glGenRenderbuffers(1, &FDepthBufferID);
glBindRenderbuffer(GL_RENDERBUFFER, FDepthBufferID);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, FDepthBufferID);
glGenTextures(1, &FTextureID);
glBindTexture(GL_TEXTURE_2D, FTextureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//Tried both with and without:
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, FTextureID, 0);
GLenum OStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (OStatus != GL_FRAMEBUFFER_COMPLETE) {
Dev::Log(SGString("framebuffer creation failed: ") + (int) OStatus);
}
Vertex shader:
void main(void) {
gl_Position = Projection * vec4(Position, 1.0);
TextureCoordsOut = TextureCoords;
ParamOut = Param;
ColorOut = Color;
}
Projection matrix:
matrix[0] = 2.0 / (right - left);
matrix[1] = 0.0;
matrix[2] = 0.0;
matrix[3] = 0.0;
matrix[4] = 0.0;
matrix[5] = 2.0 / (top - bottom);
matrix[6] = 0.0;
matrix[7] = 0.0;
matrix[8] = 0.0;
matrix[9] = 0.0;
matrix[10] = -2.0 / (far - near);
matrix[11] = 0.0;
matrix[12] = -(right + left) / (right - left);
matrix[13] = -(top + bottom) / (top - bottom);
matrix[14] = -(far + near) / (far - near);
matrix[15] = 1.0;
Rendering:
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
glVertexAttribPointer(FPositionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(SGVertex), OVertextBuffer->Buffer());
glVertexAttribPointer(FTextureCoordsSlot, 2, GL_FLOAT, GL_FALSE, sizeof(SGVertex), OVertextBuffer->Buffer() + (sizeof(float) * 3));
glVertexAttribPointer(FParamSlot, 1, GL_FLOAT, GL_FALSE, sizeof(SGVertex), OVertextBuffer->Buffer()+ (sizeof(float) * 5));
glVertexAttribPointer(FColorSlot, 4, GL_FLOAT, GL_FALSE, sizeof(SGVertex), OVertextBuffer->Buffer()+ (sizeof(float) * 6));
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, OTexture->TextureID());
glUniform1i(FTextureUniform, 0);
glDrawArrays(GL_TRIANGLES, 0, count);
I stumbled over a tiny hint that lead me to the answer, the problem was the precision of the texture coordinates I had simply copied from a sample:
varying lowp vec2 TextureCoordsOut;
having no idea what lowp meant I just ignored it - big mistake - I changed it to
varying highp vec2 TextureCoordsOut;
and now it works perfectly, why it works on all the other devices in spite being lowp
is beyond me though
its possible mediump
will work too but I figured I'd just for go highp
to test it.