Question with glReadPixels ?

I am going to read a block of pixel from the screen and then bind with a texture. At first, I round width and height to the nearest 2n integer( the width and height will be used by the glReadPixel and glTexImage2D). The image of the screen is nicely capture with this method. Later, I would like to reduce the workload of glReadPixels by assigning the exact screen width and screen height (not a 2n integer) to the glReadPixels, and follow by the glTexImage2D (the width and height still rounded to the nearest 2*n) but this time the image that capture with this method is distorted. The code is as follow:

First Method

        Gl.glPixelStorei(Gl.GL_UNPACK_ALIGNMENT, 1);
        Gl.glPixelStorei(Gl.GL_PACK_ALIGNMENT, 1);
        Gl.glReadBuffer(Gl.GL_FRONT);

        if (view.width <= 256 && view.height <= 256)
        {
            saizView = 256;
        }
        else if (winWidth <= 512 && winHeight <= 512)
        {
            saizView = 512;
        }
        else if (winWidth <= 1024 && winHeight <= 1024)
        {
            saizView = 1024;
        }
        else
        {
            //				saizView=1024;
            saizView = 1024 * 2;
        }

        int[] sizeint = new int[1];
        Gl.glGetIntegerv(Gl.GL_MAX_TEXTURE_SIZE, sizeint);

        byte[] colorSave = new byte[3 * saizView * saizView];

               Gl.glReadPixels(0, 0, saizView, saizView, Gl.GL_RGB, Gl.GL_UNSIGNED_BYTE, colorSave);
       
        Gl.glBindTexture(Gl.GL_TEXTURE_2D, saveImage[0]);
        Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, Gl.GL_REPEAT);
        Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_REPEAT);
        Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_NEAREST);
        Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_NEAREST);
        Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGB, saizView, saizView, 0, Gl.GL_RGB, Gl.GL_UNSIGNED_BYTE, colorSave);
        colorSave = null;

Second Method

    Gl.glPixelStorei(Gl.GL_UNPACK_ALIGNMENT, 1);
        Gl.glPixelStorei(Gl.GL_PACK_ALIGNMENT, 1);
        Gl.glReadBuffer(Gl.GL_FRONT);
        //            Gl.glReadBuffer(Gl.GL_BACK);

        if (view.width <= 256 && view.height <= 256)
        {
            saizView = 256;
        }
        else if (winWidth <= 512 && winHeight <= 512)
        {
            saizView = 512;
        }
        else if (winWidth <= 1024 && winHeight <= 1024)
        {
            saizView = 1024;
        }
        else
        {
            //				saizView=1024;
            saizView = 1024 * 2;
        }

        int[] sizeint = new int[1];
        Gl.glGetIntegerv(Gl.GL_MAX_TEXTURE_SIZE, sizeint);

        byte[] colorSave = new byte[3 * saizView * saizView];

      for (int i = 0; i < colorSave.Length; i++)
        {
            colorSave[i] = 0;
        }

        Gl.glReadPixels(0, 0, view.width, view.height, Gl.GL_RGB, Gl.GL_UNSIGNED_BYTE, colorSave);
        
        Gl.glBindTexture(Gl.GL_TEXTURE_2D, saveImage[0]);
        Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, Gl.GL_REPEAT);
        Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_REPEAT);
        Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_NEAREST);
        Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_NEAREST);
        Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGB, saizView, saizView, 0, Gl.GL_RGB, Gl.GL_UNSIGNED_BYTE, colorSave);
        colorSave = null;

Can someone tell me where I am wrong? Thanks in advance.

This is not a direct answer to your question, but a couple of
remarks:

  1. You mean 2^n, not 2*n, right? If at runtime the GL_VERSION query returns something >=2.0 or if you have extension GL_ARB_texture_non_power_of_two in the string returned by the GL_EXTENSIONS query, textures already support any type of size, not just power-of-two.

  2. If your goal is to transfer data from the framebuffer to a texture, you’d better look at glCopyTexImage2D() or glCopyTexSubImage2D().

  • With glReadPixel()/glTexImage2D() you’re doing VRAM->RAM (slow), RAM->VRAM (slow)
  • With glCopyTexImage2D(), your doing VRAM->VRAM (fast)

Thanks for reminding me about the glCopyTexImage2D function, it is far more faster than my previous method.

Actually, use glCopyTexSubImage2D, because glCopyTexImage2D creates new texture every time, while the ‘Sub’ version only updates existing texture. Shouldn’t make much difference in performance, but it’s the right way to do it.
Also, you should consider using Framebuffer Object extension if available to render directly to texture (without any copying).