Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Page 1 of 2 12 LastLast
Results 1 to 10 of 12

Thread: Array Texture confusion

  1. #1
    Intern Newbie
    Join Date
    Oct 2011
    Posts
    48

    Array Texture confusion

    I want to make an array-texture from 2D textures with mipmaps, but Im confused.

    This is one of the "tutorials" I looked at:
    https://www.opengl.org/wiki/Array_Texture

    Here they use glTexStorage3D to allocate storage but I saw other code where they used glTexImage3D.
    In these functions what is specified by the parameters "depth" and "level"?

    Lets say I want an array from 2 textures which have 3 mip-map levels. Does that mean I have to call glTexSubImage3D six times? Why does this function have "depth" and "level" parameters too?
    Thanks!

  2. #2
    Senior Member OpenGL Pro Aleksandar's Avatar
    Join Date
    Jul 2009
    Posts
    1,144
    glTexImage*() is used when mutable textures are created or you are confined to GL 3.3. glTexStorage*() is used to make storage for immutable textures and requires GL 4.2+.
    It is a common story for all textures, not texture arrays only.

    "Level" specifies a layer in a texture array. Since there is no special function for texture arrays, they use higher order texture storage. That's why 2D texture array uses 3D texture interface.

    For more information take a look at the spec.

  3. #3
    Advanced Member Frequent Contributor arekkusu's Avatar
    Join Date
    Nov 2003
    Posts
    781
    See also Microsoft's D3D documentation, where they have a simple illustration that explains it better than 1000 words in the GL spec ever will.

  4. #4
    Advanced Member Frequent Contributor
    Join Date
    Dec 2007
    Location
    Hungary
    Posts
    985
    Quote Originally Posted by Aleksandar View Post
    "Level" specifies a layer in a texture array.
    No, "level" specifies the mip level, as usual. The Z direction, aka depth, zoffset, etc. are the ones that specify the layer.
    Disclaimer: This is my personal profile. Whatever I write here is my personal opinion and none of my statements or speculations are anyhow related to my employer and as such should not be treated as accurate or valid and in no case should those be considered to represent the opinions of my employer.
    Technical Blog: http://www.rastergrid.com/blog/

  5. #5
    Senior Member OpenGL Pro Aleksandar's Avatar
    Join Date
    Jul 2009
    Posts
    1,144
    I'm sorry for the mistake!
    I didn't take a look at the function header (usually I interchange both terms for the same thing). Mea culpa...

  6. #6
    Intern Newbie
    Join Date
    Oct 2011
    Posts
    48
    Thanks for the answers! I still dont understand the difference here between glTexImage and glTexSubImage. Does glTexImage define only 1 mip-map level for the given texture? It says "glTexImage3D — specify a three-dimensional texture image" but I see code that calls this many times for the same texture.
    So how many times should I call these functions for a 2-layer 3-mip-map-level texture array?

  7. #7
    Advanced Member Frequent Contributor arekkusu's Avatar
    Join Date
    Nov 2003
    Posts
    781

    Post

    The API differences here are about mutability and texture completeness. It helps to understand those concepts.

    TexImage defines the geometry of one mipmap level in a texture. That one level can be 1, 2, or 3 dimensional, depending on the texture target (TEXTURE_2D_ARRAY is a 3 dimensional target.) Also, if you pass a non-NULL <pixels> argument, you fill the geometry you just defined with the pixels you provide. These are two separate actions: defining the geometry (allocating memory), and then transferring pixels (writing data to that memory).

    TexSubImage only transfers pixels, into a single mipmap level. The geometry must have been previously defined.

    Now, here is a very common mistake made by every beginner OpenGL programmer:
    Code :
        ...gen and bind texture
        glTexImage2D(GL_TEXTURE_2D, level0... width, height... pixels)
        ...draw with that texture
    The result is all black, because this texture is incomplete. What is "complete"? It means a complex combination of the mipmap geometry, the mipmap image formats, the sampler filtering modes, and sampler wrap modes are all compatible and will make sense when the texture is sampled in a shader. Read the "Texture Completeness" chapter for full details. The short answer is: if you want mipmap filtering, you must define all levels, each one being half the size of the previous one. If you don't want mipmap filtering, turn it off.

    Textures defined by TexImage are mutable: after defining them (and drawing with them), there is nothing stopping you from re-defining the geometry of the same texture object. That's fine, but it's pretty easy to make a programming mistake and leave the texture in an incomplete state (for example, if you change the level0 size, and forget to change the rest of the levels. Or make the level0 <internalformat> different from the other levels. Or mix-and-match multiple sampler objects with multiple textures, and some wind up with incompatible filtering.) And, because defining a complete mipmap requires multiple TexImage calls, the texture will always be temporarily incomplete, during those few calls. This is a headache for driver implementors.

    TexStorage solves most of those problems, by defining the entire mipmap geometry (allocating memory) in one API call. And it makes the texture immutable so you can't accidentally break it afterwards. However, it does not transfer any pixel data. You must use TexSubImage to do that.



    So, with those definitions, these are (roughly) equivalent:

    1) TexImage(...level0... pixels);
    2) TexImage(...level0... NULL); TexSubImage(...level0... pixels);
    3) TexStorage(...1...); TexSubImage(...level0... pixels); // this also ensures mipmap completeness and makes the texture immutable


    And to re-answer your original question:
    Lets say I want an array from 2 textures which have 3 mip-map levels. Does that mean I have to call glTexSubImage3D six times? Why does this function have "depth" and "level" parameters too?
    "Level" always means the mipmap level. "Depth" only applies to 3D targets. It means the number of "slices" (or "layers") in the array.
    You will most likely have to transfer pixels six separate times, but it depends how your pixels are laid out in memory. Here is one way to do it:

    Code :
    TexStorage3D(...3... W, H, 2); // allocates W x H x 2 level0, W/2 x H/2 x 2 level1, W/4 x H/4 x 2 level2.  Contents are undefined at this point.
    TexSubImage3D(...level0, 0, 0, 0, W, H, 1... lod0_slice0_pixels);
    TexSubImage3D(...level0, 0, 0, 1, W, H, 1... lod0_slice1_pixels);
    TexSubImage3D(...level1, 0, 0, 0, W/2, H/2, 1... lod1_slice0_pixels);
    TexSubImage3D(...level1, 0, 0, 1, W/2, H/2, 1... lod1_slice1_pixels);
    TexSubImage3D(...level2, 0, 0, 0, W/4, H/4, 1... lod2_slice0_pixels);
    TexSubImage3D(...level2, 0, 0, 1, W/4, H/4, 1... lod2_slice1_pixels);   // all slices of all mipmaps now transferred
    With TexStorage, this is mipmap complete, even if W/4 != 1 or H/4 != 1. If you use TexImage, you would either have to provide all the mipmap levels down to 1x1xD, or change TEXTURE_MAX_LEVEL. TexStorage is generally a better API, but it requires fairly recent drivers and isn't available everywhere.


    Note that when you transfer a set of 3D pixels, the default PixelStorage settings will assume that the pixels for slice0 are immediately followed in memory by slice1. If that is true, then you could collapse the above sequence into only three TexSubImage calls, transferring two slices at a time:
    Code :
    TexSubImage3D(...level0, 0, 0, 0, W, H, 2... lod0_slice0and1_pixels);
    TexSubImage3D(...level1, 0, 0, 0, W/2, H/2, 2... lod1_slice0and1_pixels);
    TexSubImage3D(...level2, 0, 0, 0, W/4, H/4, 2... lod2_slice0and1_pixels);
    ...but if you started with 2D textures, then your pixels probably aren't arranged like that.

    And finally, if you don't care about the exact mipmap contents, then you could just transfer level0 and call glGenerateMipmap to automatically generate the rest by downsampling level0.
    Last edited by arekkusu; 03-04-2014 at 06:12 PM.

  8. #8
    Intern Newbie
    Join Date
    Oct 2011
    Posts
    48
    Thanks for the clarification! I see that glTexStorage is superior, I just want to stick to OpenGL3.3 for now.
    I didnt know about glGenerateMipmap. Is there any reason not to use it and upload the mip-maps manually instead?

  9. #9
    Advanced Member Frequent Contributor arekkusu's Avatar
    Join Date
    Nov 2003
    Posts
    781
    Most of the time the automatically generated mipmaps are "good enough".

    Certain applications want custom-generated mipmaps (extra sharpening, or specialized fog/colorization/alpha masking) so need to provide all of the levels.
    Applications using compressed texture formats also usually provide all of the levels since the compression process is usually better done off-line.

  10. #10
    Newbie Newbie
    Join Date
    Mar 2014
    Posts
    2
    Hey, I'm struggling with texture arrays, too.
    Is there anything wrong with my setup?
    In my fragment-shader my Sampler2DArray resolves to null and therefore i get a complete black screen.

    Code :
    ByteBuffer texels = ByteBuffer.allocateDirect(data.length);
    texels.put(data);
    texels.flip();
     
    id = glGenTextures();
     
    glBindTexture(GL_TEXTURE_2D_ARRAY, id);
     
    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
     
    glTexStorage3D(GL_TEXTURE_2D_ARRAY, mipmaps, GL_RGB, width, height, textures);
    glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, width, height, 1, GL_RGB, GL_UNSIGNED_BYTE, texels);
    glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 1, width, height, 1, GL_RGB, GL_UNSIGNED_BYTE, texels);
    glGenerateMipmap(id);

    i hope you can help me!
    Last edited by m2zer0; 03-10-2014 at 10:39 AM.

Posting Permissions

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