GPU: Add GPU_texture_copy

This allow to copy entire texture in a faster way than using framebuffer
blitting.

This uses ARB_copy_image extension if available and fallback to
glCopyTexSubImage2D for older gl version.

Both method should be as fast if not faster than the framebuffer blitting.
This commit is contained in:
Clément Foucault 2020-04-22 21:22:07 +02:00
parent d17b371a83
commit f7753bf97f
2 changed files with 69 additions and 0 deletions

View File

@ -239,6 +239,8 @@ void GPU_texture_bind(GPUTexture *tex, int number);
void GPU_texture_unbind(GPUTexture *tex);
int GPU_texture_bound_number(GPUTexture *tex);
void GPU_texture_copy(GPUTexture *dst, GPUTexture *src);
void GPU_texture_generate_mipmap(GPUTexture *tex);
void GPU_texture_compare_mode(GPUTexture *tex, bool use_compare);
void GPU_texture_filter_mode(GPUTexture *tex, bool use_filter);

View File

@ -88,6 +88,9 @@ struct GPUTexture {
int fb_attachment[GPU_TEX_MAX_FBO_ATTACHED];
GPUFrameBuffer *fb[GPU_TEX_MAX_FBO_ATTACHED];
/* Legacy workaround for texture copy. */
GLuint copy_fb;
GPUContext *copy_fb_ctx;
};
static uint gpu_get_bytesize(eGPUTextureFormat data_type);
@ -1719,6 +1722,67 @@ void GPU_texture_generate_mipmap(GPUTexture *tex)
gpu_texture_memory_footprint_add(tex);
}
/* Copy a texture content to a similar texture. Only Mip 0 is copied. */
void GPU_texture_copy(GPUTexture *dst, GPUTexture *src)
{
BLI_assert(dst->target == src->target);
BLI_assert(dst->w == src->w);
BLI_assert(dst->h == src->h);
BLI_assert(!GPU_texture_cube(src) && !GPU_texture_cube(dst));
/* TODO support array / 3D textures. */
BLI_assert(dst->d == 0);
BLI_assert(dst->format == src->format);
if (GLEW_ARB_copy_image) {
/* Opengl 4.3 */
glCopyImageSubData(src->bindcode,
src->target,
0,
0,
0,
0,
dst->bindcode,
dst->target,
0,
0,
0,
0,
src->w,
src->h,
1);
}
else {
/* Fallback for older GL. */
GLenum attachment = !GPU_texture_depth(src) ?
GL_COLOR_ATTACHMENT0 :
(GPU_texture_stencil(src) ? GL_DEPTH_STENCIL_ATTACHMENT :
GL_DEPTH_ATTACHMENT);
if (src->copy_fb == 0) {
src->copy_fb = GPU_fbo_alloc();
src->copy_fb_ctx = GPU_context_active_get();
glBindFramebuffer(GL_READ_FRAMEBUFFER, src->copy_fb);
glFramebufferTexture(GL_READ_FRAMEBUFFER, attachment, src->bindcode, 0);
BLI_assert(glCheckFramebufferStatus(GL_READ_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
}
/* This means that this function can only be used in one context for each texture. */
BLI_assert(src->copy_fb_ctx == GPU_context_active_get());
glBindFramebuffer(GL_READ_FRAMEBUFFER, src->copy_fb);
glReadBuffer(attachment);
/* WATCH: glCopyTexSubImage2D might clamp the values to the [0,1] range
* where glCopyImageSubData would not. */
glBindTexture(dst->target, dst->bindcode);
glCopyTexSubImage2D(dst->target, 0, 0, 0, 0, 0, src->w, src->h);
glBindTexture(dst->target, 0);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
}
}
void GPU_texture_compare_mode(GPUTexture *tex, bool use_compare)
{
WARN_NOT_BOUND(tex);
@ -1838,6 +1902,9 @@ void GPU_texture_free(GPUTexture *tex)
if (tex->bindcode) {
GPU_tex_free(tex->bindcode);
}
if (tex->copy_fb) {
GPU_fbo_free(tex->copy_fb, tex->copy_fb_ctx);
}
gpu_texture_memory_footprint_remove(tex);