Maik Klein
Maik Klein

Reputation: 16148

How to grow a GL_TEXTURE_2D_ARRAY?

I have created 2d texture array like this

glTexImage3D(GL_TEXTURE_2D_ARRAY,
             0,                // No mipmaps
             GL_RGBA8,         // Internal format
             width, height, 100, // width,height,layer count
             0,                // border?
             GL_RGBA,         // format
             GL_UNSIGNED_BYTE, // type
             0);               // pointer to data

How do I increase its size from 100 to 200 for example? I guess I would have to create a new 2d array with size 200 and copy the images with glCopyTexSubImage3D over?

glBindTexture(GL_TEXTURE_2D_ARRAY, texture_id);
glCopyTexSubImage3D(GL_TEXTURE_2D_ARRAY,
                         0,
                         0, 0, 0,
                         0, 0,
                         width, height
                         );
glDeleteTextures(1, &texture_id);

GLuint new_tex_id;
glGenTextures(1, &new_tex_id);
glBindTexture(GL_TEXTURE_2D_ARRAY, new_tex_id);

glTexImage3D(GL_TEXTURE_2D_ARRAY,
             0,                
             GL_RGBA8,         
             width, height, 200, 
             0,                
             GL_RGBA,         
             GL_UNSIGNED_BYTE, 
             0);               

//How do I get the data in `GL_READ_BUFFER` into my newly bound texture? 

texture_id = new_tex_id;

But how do I actually get the data out of the GL_READ_BUFFER?

Upvotes: 0

Views: 1038

Answers (2)

Reto Koradi
Reto Koradi

Reputation: 54572

The glCopyImageSubData() function that @NicolBolas pointed out is the easiest solution if you're ok with requiring OpenGL 4.3 or later.

You can use glCopyTexSubImage3D() for this purpose. But since the source for this function is the current read framebuffer, you need to bind your original texture as a framebuffer attachment. The code could roughly look like this:

GLuint fbo = 0;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);

glBindTexture(GL_TEXTURE_2D_ARRAY, new_tex_id);

for (int layer = 0; layer < 100; ++layer) {
    glFramebufferTextureLayer(GL_READ_FRAMEBUFFER,
        GL_COLOR_ATTACHMENT0, tex_id, 0, layer);
    glCopyTexSubImage3D(GL_TEXTURE_2D_ARRAY,
        0, 0, 0, layer, 0, 0, width, height);
}

You can also use glBlitFramebuffer() instead:

GLuint fbos[2] = {0, 0};
glGenFramebuffers(2, fbos);
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]);

for (int layer = 0; layer < 100; ++layer) {
    glFramebufferTextureLayer(GL_READ_FRAMEBUFFER,
        GL_COLOR_ATTACHMENT0, tex_id, 0, layer);
    glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER,
        GL_COLOR_ATTACHMENT0, new_tex_id, 0, layer);
    glBlitFramebuffer(
        0, 0, width, height, 0, 0, width, height,
        GL_COLOR_BUFFER_BIT, GL_NEAREST);
}

The two options should be more or less equivalent. I would probably go with glBlitFramebuffer() since it's a newer function (introduced in 3.0), and it might be much more commonly used. So it might be more optimized. But if this is performance critical in your application, you should try both, and compare.

Upvotes: 1

Nicol Bolas
Nicol Bolas

Reputation: 473212

glCopyTexSubImage copies data from the framebuffer, not from a texture. That's why it doesn't take two texture objects to copy with.

Copying from a texture into another texture requires glCopyImageSubData. This is an OpenGL 4.3 function, from ARB_copy_image. A similar function can also be found in NV_copy_image, which may be more widely supported.

BTW, you should generally avoid doing this operation at all. If you needed a 200 element array texture, you should have allocated that the first time.

Upvotes: 2

Related Questions