Search code examples
c++opengltexture-mappingopengl-3

Switching to glTexImage3D from glTexStorage3D


glBindTexture(GL_TEXTURE_2D_ARRAY, texture_id);
glTexStorage3D(GL_TEXTURE_2D_ARRAY,
               1,             // No mipmaps
               GL_RGBA8,      // Internal format
               width, height, // width,height
               1              // Number of layers
               );
glTexSubImage3D(GL_TEXTURE_2D_ARRAY,
                0,                // Mipmap number
                0, 0, 0,          // xoffset, yoffset, zoffset
                width, height, 1, // width, height, depth
                GL_RGBA8,         // format
                GL_UNSIGNED_BYTE, // type
                image);           // pointer to data

For testing I only create an array of length 1. I am currently using OpenGL 4.3 but I want to switch back to OpenGL 3.3 which means that I can not use glTexStorage3D.

So I tried to switch to glTexImage3D

glBindTexture(GL_TEXTURE_2D_ARRAY, texture_id);
glTexImage3D(GL_TEXTURE_2D_ARRAY,
             1,                // level
             GL_RGBA8,         // Internal format
             width, height, 1, // width,height,depth
             0,                // border?
             GL_RGBA,         // format
             GL_UNSIGNED_BYTE, // type
             0);               // pointer to data
glTexSubImage3D(GL_TEXTURE_2D_ARRAY,
                0,                // Mipmap number
                0, 0, 0,          // xoffset, yoffset, zoffset
                width, height, 1, // width, height, depth
                GL_RGBA8,         // format
                GL_UNSIGNED_BYTE, // type
                image);           // pointer to data

But it is not working and I am not sure what I am doing wrong.

Edit: I should probably add that it is working with glTexStorage3d.


Solution

  • The main problem is with the second argument you are using for glTexImage3D():

    glTexImage3D(GL_TEXTURE_2D_ARRAY,
                 1,                // level
                 GL_RGBA8,         // Internal format
                 width, height, 1, // width,height,depth
                 0,                // border?
                 GL_RGBA,         // format
                 GL_UNSIGNED_BYTE, // type
                 0);               // pointer to data
    

    For glTexImage3D(), the argument is named level, and is the 0-based index of the level you're specifying data for, or just allocating when the last argument is NULL. This is different from the levels (note plural) argument of glTexStorage3D(), which is the count of levels to be allocated.

    In fact, the second argument of glTexImage3D() directly corresponds to the second argument of glTexSubImage3D(), which you're already passing as 0.

    So the correct call simply uses 0 for the second argument:

    glTexImage3D(GL_TEXTURE_2D_ARRAY,
                 0,                // level
                 GL_RGBA8,         // Internal format
                 width, height, 1, // width,height,depth
                 0,                // border?
                 GL_RGBA,          // format
                 GL_UNSIGNED_BYTE, // type
                 0);               // pointer to data
    

    In addition, I'm surprised that your glTexSubImage3D() calls work. GL_RGBA8 is not valid as the 9th argument. In this case, this is a format, and not an internalFormat, meaning that it is an unsized format. The value in this case should be GL_RGBA:

    glTexSubImage3D(GL_TEXTURE_2D_ARRAY,
                    0,                // Mipmap number
                    0, 0, 0,          // xoffset, yoffset, zoffset
                    width, height, 1, // width, height, depth
                    GL_RGBA,          // format
                    GL_UNSIGNED_BYTE, // type
                    image);           // pointer to data