openglfboatipbo

OpenGL + PBO + FBO + some ATI cards - color and pixel shifting


We are developing software for slide show creation and use OpenGL. We use FBO + PBO for fast data reading from VGA to RAM but on some video cards from ATI we faced with the following problems:

  1. swapping RGB components
  2. pixel shifting

There are no problems if we do not use PBO. Also we have noticed that the aspect ratio of PBO/FBO (4:3) solve the pixel shifting problem.

Any thoughts or suggestions?

Here are more details:

PBO code:

public bool PBO_Initialize(
        int bgl_size_w,
        int bgl_size_h)
    {
        PBO_Release();
        if (mCSGL12Control1 != null)
        {
            GL mGL = mCSGL12Control1.GetGL();
            mCSGL12Control1.wgl_MakeCurrent();
            //
            // check PBO is supported by your video card
            if (mGL.bglGenBuffersARB == true &&
                mGL.bglBindBufferARB == true &&
                mGL.bglBufferDataARB == true &&
                mGL.bglBufferSubDataARB == true &&
               mGL.bglMapBufferARB == true &&
               mGL.bglUnmapBufferARB == true &&
               mGL.bglDeleteBuffersARB == true &&
               mGL.bglGetBufferParameterivARB == true)
            {
                mGL.glGenBuffersARB(2, _pbo_imageBuffers);
                int clientHeight1 = bgl_size_h / 2;
                int clientHeight2 = bgl_size_h - clientHeight1;
                int clientSize1 = bgl_size_w * clientHeight1 * 4;
                int clientSize2 = bgl_size_w * clientHeight2 * 4;


                mGL.glBindBufferARB(GL.GL_PIXEL_PACK_BUFFER_ARB, _pbo_imageBuffers[0]);
                mGL.glBufferDataARB(GL.GL_PIXEL_PACK_BUFFER_ARB, clientSize1, IntPtr.Zero,
                                GL.GL_STREAM_READ_ARB);

                mGL.glBindBufferARB(GL.GL_PIXEL_PACK_BUFFER_ARB, _pbo_imageBuffers[1]);
                mGL.glBufferDataARB(GL.GL_PIXEL_PACK_BUFFER_ARB, clientSize2, IntPtr.Zero,
                                GL.GL_STREAM_READ_ARB);

                return true;
            }
        }
        return false;
    }

... PBO read data back to memory

                    int clientHeight1 = _bgl_size_h / 2;
                    int clientHeight2 = _bgl_size_h - clientHeight1;
                    int clientSize1 = _bgl_size_w * clientHeight1 * 4;
                    int clientSize2 = _bgl_size_w * clientHeight2 * 4;
                    //mGL.glPushAttrib(GL.GL_VIEWPORT_BIT | GL.GL_COLOR_BUFFER_BIT);

                    // Bind two different buffer objects and start the glReadPixels
                    // asynchronously. Each call will return directly after
                    // starting the DMA transfer.
                    mGL.glBindBufferARB(GL.GL_PIXEL_PACK_BUFFER_ARB, _pbo_imageBuffers[0]);
                    mGL.glReadPixels(0, 0, _bgl_size_w, clientHeight1, imageFormat,
                                    pixelTransferMethod, IntPtr.Zero);

                    mGL.glBindBufferARB(GL.GL_PIXEL_PACK_BUFFER_ARB, _pbo_imageBuffers[1]);
                    mGL.glReadPixels(0, clientHeight1, _bgl_size_w, clientHeight2, imageFormat,
                                    pixelTransferMethod, IntPtr.Zero);

                    //mGL.glPopAttrib();
                    mGL.glBindFramebufferEXT(GL.GL_FRAMEBUFFER_EXT, 0);

                    // Process partial images.  Mapping the buffer waits for
                    // outstanding DMA transfers into the buffer to finish.
                    mGL.glBindBufferARB(GL.GL_PIXEL_PACK_BUFFER_ARB, _pbo_imageBuffers[0]);
                    IntPtr pboMemory1 = mGL.glMapBufferARB(GL.GL_PIXEL_PACK_BUFFER_ARB,
                                                GL.GL_READ_ONLY_ARB);

                    mGL.glBindBufferARB(GL.GL_PIXEL_PACK_BUFFER_ARB, _pbo_imageBuffers[1]);
                    IntPtr pboMemory2 = mGL.glMapBufferARB(GL.GL_PIXEL_PACK_BUFFER_ARB,
                                                GL.GL_READ_ONLY_ARB);


                    System.Runtime.InteropServices.Marshal.Copy(pboMemory1, _bgl_rgbaData_out, 0, clientSize1);
                    System.Runtime.InteropServices.Marshal.Copy(pboMemory2, _bgl_rgbaData_out, clientSize1, clientSize2);


                    // Unmap the image buffers
                    mGL.glBindBufferARB(GL.GL_PIXEL_PACK_BUFFER_ARB, _pbo_imageBuffers[0]);
                    mGL.glUnmapBufferARB(GL.GL_PIXEL_PACK_BUFFER_ARB);
                    mGL.glBindBufferARB(GL.GL_PIXEL_PACK_BUFFER_ARB, _pbo_imageBuffers[1]);
                    mGL.glUnmapBufferARB(GL.GL_PIXEL_PACK_BUFFER_ARB);

FBO initialization

private static void FBO_Initialize(GL mGL,
        ref int[] bgl_texture,
        ref int[] bgl_framebuffer,
        ref int[] bgl_renderbuffer,
        ref byte[] bgl_rgbaData,
        int bgl_size_w,
        int bgl_size_h)
    {
        // Texture
        mGL.glGenTextures(1, bgl_texture);
        mGL.glBindTexture(GL.GL_TEXTURE_2D, bgl_texture[0]);

        mGL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST);
        mGL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST);
        mGL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE);
        mGL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE);
        IntPtr null_ptr = new IntPtr(0);
        // <null> means reserve texture memory, but texels are undefined
        mGL.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA, bgl_size_w, bgl_size_h, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, null_ptr);
        //
        mGL.glGenFramebuffersEXT(1, bgl_framebuffer);
        mGL.glBindFramebufferEXT(GL.GL_FRAMEBUFFER_EXT, bgl_framebuffer[0]);

        mGL.glGenRenderbuffersEXT(1, bgl_renderbuffer);
        mGL.glBindRenderbufferEXT(GL.GL_RENDERBUFFER_EXT, bgl_renderbuffer[0]);
        mGL.glRenderbufferStorageEXT(GL.GL_RENDERBUFFER_EXT, GL.GL_DEPTH_COMPONENT24, bgl_size_w, bgl_size_h);


        mGL.glFramebufferTexture2DEXT(GL.GL_FRAMEBUFFER_EXT, GL.GL_COLOR_ATTACHMENT0_EXT,
            GL.GL_TEXTURE_2D, bgl_texture[0], 0);
        mGL.glFramebufferRenderbufferEXT(GL.GL_FRAMEBUFFER_EXT, GL.GL_DEPTH_ATTACHMENT_EXT,
            GL.GL_RENDERBUFFER_EXT, bgl_renderbuffer[0]);

        // Errors?
        int status = mGL.glCheckFramebufferStatusEXT(GL.GL_FRAMEBUFFER_EXT);
        if (status != GL.GL_FRAMEBUFFER_COMPLETE_EXT || mGL.glGetError() != GL.GL_NO_ERROR)
        {
            mGL.glFramebufferTexture2DEXT(GL.GL_FRAMEBUFFER_EXT, GL.GL_COLOR_ATTACHMENT0_EXT,
                GL.GL_TEXTURE_2D, 0, 0);
            mGL.glFramebufferRenderbufferEXT(GL.GL_FRAMEBUFFER_EXT, GL.GL_DEPTH_ATTACHMENT_EXT,
                GL.GL_RENDERBUFFER_EXT, 0);

            mGL.glBindTexture(GL.GL_TEXTURE_2D, 0);
            mGL.glDeleteTextures(1, bgl_texture);
            mGL.glBindRenderbufferEXT(GL.GL_RENDERBUFFER_EXT, 0);
            mGL.glDeleteRenderbuffersEXT(1, bgl_renderbuffer);
            mGL.glBindFramebufferEXT(GL.GL_FRAMEBUFFER_EXT, 0);
            mGL.glDeleteFramebuffersEXT(1, bgl_framebuffer);

            throw new Exception("Bad framebuffer.");
        }

        mGL.glDrawBuffer(GL.GL_COLOR_ATTACHMENT0_EXT);
        mGL.glReadBuffer(GL.GL_COLOR_ATTACHMENT0_EXT); // For glReadPixels()

        mGL.glBindFramebufferEXT(GL.GL_FRAMEBUFFER_EXT, 0);

        mGL.glDrawBuffer(GL.GL_BACK);
        mGL.glReadBuffer(GL.GL_BACK);
        mGL.glBindTexture(GL.GL_TEXTURE_2D, 0);

        bgl_rgbaData = new byte[bgl_size_w * bgl_size_h * 4];
    }

enter image description here


Solution

  • It seems that re-installing/updating VGA Driver does solve this problem.

    Really strange behaviour (also, it may be that the official notebook driver is old/buggy/etc. and causes the problem, so updating with the latest driver from AMD, for this vga-chip series, seems affect/solve the problem. Also I'm not sure if the previouse driver was set up correct thus I say re-installing/updating)

    Thank you all for help.