4 Replies Latest reply on Dec 22, 2014 2:55 AM by jzhou

    glCopyImageSubData for small compressed mips

    baldurk

      glCopyImageSubData thows a GL_INVALID_VALUE when copying mips of a block compressed texture that are smaller than the block size in any dimension.

       

      e.g.

      GLuint tex0 = ...; // 1x1 compressed texture
      GLuint tex1 = ...; // 1x1 compressed texture
      
      
      glCopyImageSubData(tex0, GL_TEXTURE_2D, 0,  0, 0, 0, tex1, GL_TEXTURE_2D, 0,  0, 0, 0,  1, 1, 1); // GL_INVALID_VALUE
      

       

      I think this is invalid behaviour. Note you also get an error if you 'align' the copy region to the nearest block size, e.g. replacing the last three parameters above with 4, 4, 1. The spec isn't entirely clear on how these mips should be treated, the language says:

       

      An INVALID_VALUE error is generated if the dimensions of either subregion exceeds the boundaries of the corresponding image object, or if the image format is compressed and the dimensions of the subregion fail to meet the alignment constraints of the format.

       

      So you could say that a 1x1 subregion doesn't meet the alignment constraints of the format (although I think that's intended as saying you can't copy the region from (5,5) to (6,6) on a 16x16 texture, for example). However you definitely cannot specify the lower mips as 'aligned' to the nearest 4x4 block size since those would exceed the boundaries of the image at that level. I think the only valid way that makes sense is if the subregion should be specified as the mip size in texels, regardless of if that's smaller than the block size in one dimension.

       

      I'm on the latest AMD drivers, 14.12 Omega, on an R9 290X. Note that nvidia doesn't complain and performs the copy when specifying the 'real' mip size in texels, but whether that is spec-correct or not I don't know.

       

      Baldur

        • Re: glCopyImageSubData for small compressed mips
          cgrant78@netzero.com

          I posted a similar issue a while back and still haven't receive a response. Possible driver bug with glCopyImageSubdata

          • Re: glCopyImageSubData for small compressed mips
            jzhou

            Hi Baldur,

             

            From your description, I think you are right, glCopyImageSubData shouldn't return GL_INVALID_VALUE. But the sample code you provide is too less. Would you please give me more code (such as glCompressedTexImage2D) ? I want to reproduce your issue and fix this bug in our driver.

             

            Thanks,

            Jin

              • Re: Re: glCopyImageSubData for small compressed mips
                baldurk

                Hi there, yes I can provide more source. Below I've written some example code that illustrates the problem in an easy-to-verify way with some colours. You can also check the code I have written for my original project to detect this bug and work around it, which is simpler and does not upload any data (as it's not necessary to generate the error and detect the bug): renderdoc/gl_common.cpp at master · baldurk/renderdoc · GitHub

                 

                  // single DXT1 4x4 compressed block = 8 bytes
                  // the data is random, as the contents aren't important, just that it's some colour data
                  unsigned char datablock[8] = {
                  0xcc, 0x84, 0x11, 0x28,
                  0x51, 0xba, 0x39, 0x00,
                  };
                
                  // single DXT1 4x4 compressed block = 8 bytes
                  // this block is completely black. Used to illustrate that the copy did not succeed
                  unsigned char blackblock[8] = {
                  0x00, 0x00, 0x00, 0x00,
                  0x00, 0x00, 0x00, 0x00,
                  };
                
                
                  GLuint texs[2];
                  glGenTextures(2, texs);
                  glBindTexture(GL_TEXTURE_2D, texs[0]);
                  glTexStorage2D(GL_TEXTURE_2D, 1, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 2, 2);
                  glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 2, 2, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 8, datablock);
                
                  glBindTexture(GL_TEXTURE_2D, texs[1]);
                  glTexStorage2D(GL_TEXTURE_2D, 1, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 2, 2);
                  glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 2, 2, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 8, blackblock);
                
                  // at this point, texs[0] has some colour data, texs[1] is completely black. This can be verified by
                  // binding the textures and rendering with them
                
                  GLenum err = glGetError(); // GL_NONE returned, no errors so far
                
                  // Perform a 2x2 copy from texs[0] (with data) to texs[1] (without colour data)
                  // same result happens if you specify width and height as 4x4 to align to block size.
                  glCopyImageSubData(texs[0], GL_TEXTURE_2D, 0, 0, 0, 0, texs[1], GL_TEXTURE_2D, 0, 0, 0, 0, 2, 2, 1);
                
                  err = glGetError(); // GL_INVALID_VALUE from above copy, and debug message is thrown to ARB_debug_output
                
                  glBindTexture(GL_TEXTURE_2D, texs[1]); // texs[1] remains black
                

                 

                This can be placed in any suitable codebase to verify the contents of the textures.