How to load cube map with glTextureStorage3D by loading each images data separately

I would like to load cube map using DSA. Previously I did it using the old method with glTexImage2D and passing GL_TEXTURE_CUBE_MAP_POSITIVE_X+imageIndex. From what I’ve gathered so far the new way of doing this is by creating GL_TEXTURE_2D_ARRAY texture and use glTextureStorage3D.

This khronos example shows how to load texture array, but they basically create one c array with the data from all the textures. I wonder if there’s a way to load the image data separately for each cube image side, since I store each side as separate image? Or should I merge all the data into single array?

No. A 2D array texture is a 2D array texture (well, you can create a cubemap view of an array texture…).

Cubemaps always have 6 faces, so you don’t need to specify how many “layers” are in the image. So you use glTextureStorage2D to create their storage.

If you want to upload non-contiguous data into it, you can just load data into each of the 6 array layers by using glTextureSubImage3D with a zoffset indicating the face and a depth of 1.

Okay so do I create the texture using GL_TEXTURE_2D or GL_TEXTURE_CUBE_MAP, and then load the texture data with something like below? I’m completely confused to be honest.

 for (int i = 0; i < 6; i++) {
      glTextureStorage2D(tbo, numMipMaps, GL_RGBA8, images[i].w, images[i].h);
      glTextureSubImage3D(tbo, level, 0, 0, i, images[i].w, images[i].h, 6, GL_RGBA, GL_UNSIGNED_BYTE, images[i].data);
 }

For any texture object, you get to call glTextureStorage* exactly once. No more, no less. It always allocates the entire texture. It’s not just a fancy glTexImage* that doesn’t let you upload; it’s a different way of allocating storage for textures.

A single call to this function allocates all layers, mipmap levels, and yes faces of a texture (as appropriate to the texture type).

So you create a GL_TEXTURE_CUBE_MAP with glCreateTextures (I don’t know if tbo is meant to be a “buffer texture” or if its just weirdly named. If it is a buffer texture, then that’s not a cube map texture, so I don’t know what you’re trying to do). Then you allocate the entire cubemap with a single call to glTextureStorage2D.

After that, you can upload to each of the individual faces. I don’t know why you passed 6 for the depth when you seem to want to only upload one face at a time.

Yeah makes complete sense sorry, we are allocating space with glTextureStorage2D and then loading data with glTextureSubImage3D. Not sure though why we are using the 3D alternative and not 2D. I think I need to get some sleep.

So I guess the code below how it should be done? Haven’t managed to make it work yet, maybe some other issue, will look into it tomorrow.

glCreateTextures(GL_TEXTURE_CUBE_MAP, 1, &texture)
...
glTextureStorage2D(texture, numMipMaps, GL_RGBA8, images[0].w, images[0].h);
for (int i = 0; i < 6; i++) {
      glTextureSubImage3D(texture, level, 0, 0, i, images[i].w, images[i].h, 1, GL_RGBA, GL_UNSIGNED_BYTE, images[i].data);
 }

You can upload texture data to a cube map with either

  • glTexSubImage2D and one of the GL_TEXTURE_CUBE_MAP_{POSITIVE,NEGATIVE}_{X,Y,Z} targets, or

  • glTextureSubImage3D.

The latter allows you to upload data for multiple faces at once, but the data must be in a single block of memory. If the data for each face is in its own memory block, you have to upload one face at a time, as in your example.

Note the disparity between the non-DSA glTexSubImage2D function and the DSA glTextureSubImage3D function. You can’t upload data to a cube map with either glTextureSubImage2D or glTexSubImage3D, so if you want to use the DSA functions you have to use glTextureSubImage3D.

1 Like