fickerra
fickerra

Reputation: 80

Using FBOs bigger than 256x256 on Android is causing visual artifacts

I'm trying to port an iPhone app to Android and I'm stuck trying to get my Framebuffer code to work. I find that anytime I use 512x512 or 1024x1024 FBOs on Android, the buffer gets corrupted causing lots of artifacts to draw. 256x256 FBOs are working fine.

I've built a small project that reproduces the problem. You can download the entire repro project via this link, but I've also pasted the important part here:

class GLRenderer implements GLSurfaceView.Renderer {

    int TextureID;
    int FrameBufferID;

    public void onSurfaceCreated(GL10 gl, EGLConfig config) {

        //Create texture
        int[] buf = new int[1];
        gl.glGenTextures(1, buf, 0);
        TextureID = buf[0];

        gl.glBindTexture(GL11.GL_TEXTURE_2D, TextureID);
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);

        //Render our jpeg into the texture as the background
        GLUtils.texImage2D(GL11.GL_TEXTURE_2D, 0, FBOTestActivity.BackgroundBitmap, 0);

        GL11ExtensionPack gl11ep = (GL11ExtensionPack) gl;

        //Create a framebuffer
        gl11ep.glGenFramebuffersOES(1, buf, 0);
        FrameBufferID = buf[0];

        gl11ep.glBindFramebufferOES(GLES11Ext.GL_FRAMEBUFFER_OES, FrameBufferID);
        gl11ep.glFramebufferTexture2DOES(GLES11Ext.GL_FRAMEBUFFER_OES, GLES11Ext.GL_COLOR_ATTACHMENT0_OES, GL11.GL_TEXTURE_2D, TextureID, 0);

        //Render a rectangle into the framebuffer
        gl.glMatrixMode(GL11.GL_PROJECTION);
        gl.glLoadIdentity();
        gl.glOrthof(0, FBOTestActivity.Size, 0, FBOTestActivity.Size, -1, 1);
        gl.glMatrixMode(GL11.GL_MODELVIEW);
        gl.glViewport(0,0, FBOTestActivity.Size, FBOTestActivity.Size);

        gl.glVertexPointer(2, GL11.GL_FLOAT, 0, MakeBuffer(new float[] { 64, 64, 192, 64, 64, 192, 192,192 }));
        gl.glEnableClientState(GL11.GL_VERTEX_ARRAY); 
        gl.glDrawArrays(GL11.GL_TRIANGLE_STRIP, 0, 4);

        //Unbind
        gl11ep.glBindFramebufferOES(GLES11Ext.GL_FRAMEBUFFER_OES, 0);
    }

    public void onSurfaceChanged(GL10 gl, int w, int h) {
        gl.glViewport(0, 0, w, h);
    }

    private FloatBuffer MakeBuffer(float[] arr)
    {
        ByteBuffer vbb = ByteBuffer.allocateDirect(2 * 4 * 8);
        vbb.order(ByteOrder.nativeOrder());
        FloatBuffer fb = vbb.asFloatBuffer();
        fb.put(arr);
        fb.position(0);
        return fb;
    }

    public void onDrawFrame(GL10 gl) {
        gl.glMatrixMode(GL11.GL_PROJECTION); 
        gl.glLoadIdentity();
        gl.glOrthof(0f, 1.0f, 1f, 0f, -1.0f, 1.0f);
        gl.glMatrixMode(GL11.GL_MODELVIEW);

        gl.glClearColor(255, 0,0, 255);
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

        //Just render the texture.  It should show our background with a white rectangle in front.
        gl.glEnableClientState(GL11.GL_VERTEX_ARRAY);
        gl.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY);

        gl.glEnable(GL11.GL_TEXTURE_2D);
        gl.glBindTexture(GL11.GL_TEXTURE_2D, TextureID);
        gl.glVertexPointer(2, GL11.GL_FLOAT, 0, MakeBuffer(new float[] { 0, 0, 0, 1, 1, 0, 1, 1 }));
        gl.glTexCoordPointer(2, GL11.GL_FLOAT, 0, MakeBuffer(new float[] {0, 0, 0, 1, 1, 0, 1, 1}));
        gl.glDrawArrays(GL11.GL_TRIANGLE_STRIP, 0, 4);

    }
}

If I run this on a 256x256 texture, all is well and I see this:

If I run this with a 512x512 texture (or 1024x1024), I see this:

OpenGL is not returning any errors, and this code is working correctly on the iPhone. I've tried Android 2.1, 2.2, and 2.3 but they all behave the same. I'm doing my testing on a Nexus One running 2.3.6.

Rendering the 512x512 texture by itself without an FBO works fine, so the issue has to do with the FBO. I've been stuck on this for a while - I would greatly appreciate any help!

Upvotes: 2

Views: 1401

Answers (1)

Jörn Horstmann
Jörn Horstmann

Reputation: 34044

This is indeed strange behaviour. I can get the correct rendering on my HTC Desire if I add a call to glClear at the beginning of onSurfaceCreated. Even stranger is that it does not seem to matter if only the color or depth buffer are cleared, it even works when passing 0 as the bit mask. I'm guessing this is only hiding the real cause which is still unknown.

Upvotes: 2

Related Questions