Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 8 of 8

Thread: How can I compress textures on the fly while using TexSubImage?

  1. #1
    Junior Member Newbie
    Join Date
    Apr 2013
    Posts
    17

    How can I compress textures on the fly while using TexSubImage?

    Due to the nature of my application, most of the textures being loaded aren't packaged with the application itself and are loaded on the fly. Therefore, they can't be compressed before-hand. When I load new textures, I package everything onto atlases with glTexSubImage2D. I've recently found out the amount of textures I have can take up quite a bit of memory and so I'm trying to get "on the fly" texture compression working.

    Here's the simple version of my (C#) code:

    Code :
    // Load textures from disk
    //...
     
    // Create the atlas
    GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, width, height, 0, PixelFormat.Bgra, PixelType.UnsignedByte, IntPtr.Zero);
     
    // Copy the textures to the atlas
    GL.TexSubImage2D(TextureTarget.Texture2D, 0, (int)x, (int)y, (int)Width, (int)Height, PixelFormat.Bgra, PixelType.UnsignedByte, bmpData.Scan0);

    Now what I've tried doing is switching the atlas' internal format to CompressedRgbaS3tcDxt3Ext instead of Rgba. That works fine, it's only after I try subbing the texture into the atlas is when I get a GL_INVALID_OPERATION error.

    I've googled the issue and there doesn't seem to be anything out there explaining this situation and how to properly sub uncompressed images into a compressed format.

  2. #2
    Senior Member OpenGL Pro
    Join Date
    Jan 2007
    Posts
    1,135
    Can you be more specific about what you mean by "quite a bit of memory" (and how you're measuring it)? It's normal enough for texture memory usage to be high-ish, and you may be worrying over (and putting significant effort into) something that isn't actually a problem at all.

  3. #3
    Junior Member Newbie
    Join Date
    Apr 2013
    Posts
    17
    I've been measuring memory usage with GPU-Z by watching the "Memory Usage (Dynamic)" as highlighted here: http://i.imgur.com/yEA5KhW.png (this image was taken at idle without the application running)

    I can fully expect the memory usage to go beyond 2gb as there's no limit to how many textures are loaded (I'd expect no more than 4gb, though). I'd like for this application to be 32bit compatible but I was running into GL_OUT_OF_MEMORY errors whenever it tried allocating past 2gb. I got around that by switching to 64bit but, like I said, I'd like to support 32bit. Sure, I can set the /LARGEADDRESSAWARE flag to keep it 32bit and allow up to 4gb of system memory but I feel like I should be compressing the textures anyway if at all possible.

    Also, due to the nature of the application, it's not viable to only load textures that are needed at the time because any of the textures could be used at any point.

  4. #4
    Senior Member OpenGL Guru Dark Photon's Avatar
    Join Date
    Oct 2004
    Location
    Druidia
    Posts
    3,123
    Quote Originally Posted by inlinevoid View Post
    Now what I've tried doing is switching the atlas' internal format to CompressedRgbaS3tcDxt3Ext instead of Rgba. That works fine, it's only after I try subbing the texture into the atlas is when I get a GL_INVALID_OPERATION error. I've googled the issue and there doesn't seem to be anything out there explaining this situation and how to properly sub uncompressed images into a compressed format.
    See the EXT_texture_compression_s3tc spec for details. But are you subloading on 4x4 texel boundaries? You need to.

  5. #5
    Junior Member Newbie
    Join Date
    Apr 2013
    Posts
    17
    Quote Originally Posted by Dark Photon View Post
    See the EXT_texture_compression_s3tc spec for details. But are you subloading on 4x4 texel boundaries? You need to.
    Apparently I hadn't read far enough into the spec to find the section detailing that the texture dimensions do indeed need to be multiples of 4, which mine are not. Any ideal solutions for converting my textures to multiples of 4?

    EDIT: I'm guessing I should pad the textures with enough opaque black pixels to convert the dimensions to multiples of 4. But then how would that be accomplished? Is there some OpenGL magic or would I be better off padding the byte array myself?
    Last edited by inlinevoid; 12-02-2013 at 07:40 PM.

  6. #6
    Intern Contributor
    Join Date
    Sep 2013
    Posts
    70
    You could probably just initialize the textures dimensions with glTexImage but without uploading any texel data, and then use glTexSubImage to upload the texel data you got. All texels that are not covered by glTexSubImage will remain the default color, which is 0,0,0,0 if I remember correctly.

  7. #7
    Senior Member OpenGL Guru Dark Photon's Avatar
    Join Date
    Oct 2004
    Location
    Druidia
    Posts
    3,123
    Quote Originally Posted by inlinevoid View Post
    EDIT: I'm guessing I should pad the textures with enough opaque black pixels to convert the dimensions to multiples of 4. But then how would that be accomplished?
    From the extension spec, I think this may answer your question:

    Quote Originally Posted by EXT_texture_compression_s3tc
    If the internal format of the texture image being modified is [DXT1, DXT3, or DXT5], the
    texture is stored using one of the several S3TC compressed texture image
    formats. Such images are easily edited along 4x4 texel boundaries, so the
    limitations on TexSubImage2D or CopyTexSubImage2D parameters are relaxed.
    TexSubImage2D and CopyTexSubImage2D will result in an INVALID_OPERATION
    error only if one of the following conditions occurs:

    * <width> is not a multiple of four, <width> plus <xoffset> is not
    equal to TEXTURE_WIDTH, and either <xoffset> or <yoffset> is
    non-zero;

    * <height> is not a multiple of four, <height> plus <yoffset> is not
    equal to TEXTURE_HEIGHT, and either <xoffset> or <yoffset> is
    non-zero; or

    * <xoffset> or <yoffset> is not a multiple of four.
    So what it sounds like is, while xoffset and yoffset must be a multiple of 4, the width and/or height of the subload can be less than 4 for that last row and/or column of 4x4 texel blocks, if your texture doesn't use all texels in that 4x4 block (e.g. a 6x6 MIP level, or a 2x2 MIP level).

  8. #8
    Junior Member Newbie
    Join Date
    Apr 2013
    Posts
    17
    OpenGL still throws an invalid operation if the image dimensions aren't a multiple of 4, even if the image offset is a multiple of 4 (or in my test case: 0,0). It's only after I manually edit the image and extend the dimensions to fit the multiple of 4 that the image loads and draws without any error. It doesn't seem like I can get away without doing some pre-processing to the image before copying it to the atlas.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •