From f7753bf97fd38720bf1e91cd8179dd3227a7bb12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Wed, 22 Apr 2020 21:22:07 +0200 Subject: 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. --- source/blender/gpu/GPU_texture.h | 2 + source/blender/gpu/intern/gpu_texture.c | 67 +++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) (limited to 'source/blender/gpu') diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index 892452a2738..d6e5866ae28 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -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); diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index 6d2d0f09a42..69ede4a9e13 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -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); -- cgit v1.2.3