glReadPixels when using PBuffers is failing in some android devices

2k views Asked by At

I'm facing a problem with some opengl ES drivers, when calling glReadPixels for a Pbuffer some devices will just kill the app with no message at all. Others will give me the next trace and then freeze for around 10 seconds before killing the app.

Unable to Find Phys Addr for 0

So far the affected devices where the problem is reproducible are:

Galaxy Y, Galaxy Ace, Galaxy Mini, Galaxy Young

I've also tested the code in the next devices where it works correctly as expected, no problems at all:

Nexy 4, Nexus 7, Nexus Galaxy, SGI, SGII, SGIII, Motorola Mini-Defy, and some others more.

I've put together a quick test function which reproduces the problem. Maybe someone can spot the issue. Please this is only a test method, no reviews about it are necessary as I just put it together to allow testing the bug, if I missed something let me know.

private static void bugTest()
{
    EGL10 egl = (EGL10)EGLContext.getEGL();
    EGLDisplay eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);

    // Initialize
    int[] version = new int[2];
    egl.eglInitialize(eglDisplay, version);

    // Query total number of configurations
    int[] totalConfigurations = new int[1];
    egl.eglGetConfigs(eglDisplay, null, 0, totalConfigurations);

    EGLConfig[] configurationsList = new EGLConfig[totalConfigurations[0]];
    int attribs[] = { EGL10.EGL_RENDERABLE_TYPE, 4 /* EGL_OPENGL_ES2_BIT */, EGL10.EGL_RED_SIZE, 1, EGL10.EGL_GREEN_SIZE, 1, EGL10.EGL_BLUE_SIZE, 1, EGL10.EGL_NONE };

    if (egl.eglChooseConfig(eglDisplay, attribs, configurationsList, 1, totalConfigurations) == false)
    {
        Log.e(TAG, "Could not find config for GLES2");          
        egl.eglTerminate(eglDisplay);
        return;
    }

    // Create the PBuffer

    EGLSurface eglSurface = null;
    final int surfaceWidth = 512;
    final int surfaceHeight = 512;

    try
    {
        int[] attribList = new int[] { EGL10.EGL_WIDTH, surfaceWidth, EGL10.EGL_HEIGHT, surfaceHeight, EGL10.EGL_NONE };
        eglSurface = egl.eglCreatePbufferSurface(eglDisplay, configurationsList[0], attribList);
    }
    catch (Exception ex)
    {
        Log.e(TAG, "Failed to create surface");             
        egl.eglTerminate(eglDisplay);
        return;
    }

    // BUG Test for glReadPixels

    if (eglSurface != null)
    {
        // Create context

        final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
        final int GLES_VERSION = 2;
        int[] attribList = { EGL_CONTEXT_CLIENT_VERSION, GLES_VERSION, EGL10.EGL_NONE };
        EGLContext eglContext = egl.eglCreateContext(eglDisplay, configurationsList[0], EGL10.EGL_NO_CONTEXT, attribList);

        if (eglContext != null)
        {
            // Attach context to surface

            if (egl.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext) == true)
            {
                // Perform the actual bug test

                GL10 gl = (GL10)eglContext.getGL();
                int buffer[] = new int[surfaceWidth * surfaceHeight];
                IntBuffer wrappedBuffer = IntBuffer.wrap(buffer);
                wrappedBuffer.position(0);

                // BUG: Line of failure
                gl.glReadPixels(0, 0, surfaceWidth, surfaceHeight, GL10.GL_RGB, GL10.GL_UNSIGNED_BYTE, wrappedBuffer);

                // Also fails when using RGBA 
                //gl.glReadPixels(0, 0, surfaceWidth, surfaceHeight, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, wrappedBuffer);
            }

            egl.eglDestroyContext(eglDisplay, eglContext);
        }

        egl.eglDestroySurface(display, eglSurface);
    }

    egl.eglTerminate(eglDisplay);
}
1

There are 1 answers

2
ClayMontgomery On BEST ANSWER

Pbuffers are not supported on devices with Nvidia Tegra GPUs. The problem is their EGL driver, not your code. But there is really no good reason to use pbuffers anyway. They are obsolete. You should use FBOs instead, especially on Android. This article explains in detail why:

http://processors.wiki.ti.com/index.php/Render_to_Texture_with_OpenGL_ES

The best way to create an off-screen surface on Android is to construct a new SurfaceTexture() and pass that to eglCreateWindowSurface().