GPU: Add better support for texture copy fallback

Depth texture copy using glCopyTexSubImage2D is undefined behavior since
you cannot bind GL_DEPTH_ATTACHMENT to glReadBuffer.

Using glBlitFramebuffer as a fallback.
This commit is contained in:
Clément Foucault 2020-04-26 12:25:32 +02:00
parent f418eddf8e
commit 05b94c9c54
Notes: blender-bot 2023-02-14 11:08:33 +01:00
Referenced by issue #77572, Reference image opacity value doesn't work with Blender 2.83+ (Intel HD 630 with Mesa 20, regression from D6729)
Referenced by issue #76070, Anti-Aliasing possibly making viewport buggy
1 changed files with 46 additions and 19 deletions

View File

@ -1722,6 +1722,32 @@ void GPU_texture_generate_mipmap(GPUTexture *tex)
gpu_texture_memory_footprint_add(tex);
}
static GLenum gpu_texture_default_attachment(GPUTexture *tex)
{
return !GPU_texture_depth(tex) ?
GL_COLOR_ATTACHMENT0 :
(GPU_texture_stencil(tex) ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT);
}
static void gpu_texture_framebuffer_ensure(GPUTexture *tex)
{
if (tex->copy_fb == 0) {
tex->copy_fb = GPU_fbo_alloc();
tex->copy_fb_ctx = GPU_context_active_get();
GLenum attachment = gpu_texture_default_attachment(tex);
glBindFramebuffer(GL_FRAMEBUFFER, tex->copy_fb);
glFramebufferTexture(GL_FRAMEBUFFER, attachment, tex->bindcode, 0);
if (!GPU_texture_depth(tex)) {
glReadBuffer(GL_COLOR_ATTACHMENT0);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
}
BLI_assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
}
/* Copy a texture content to a similar texture. Only Mip 0 is copied. */
void GPU_texture_copy(GPUTexture *dst, GPUTexture *src)
{
@ -1753,33 +1779,34 @@ void GPU_texture_copy(GPUTexture *dst, GPUTexture *src)
}
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);
GPUFrameBuffer *prev_fb = GPU_framebuffer_active_get();
if (src->copy_fb == 0) {
src->copy_fb = GPU_fbo_alloc();
src->copy_fb_ctx = GPU_context_active_get();
gpu_texture_framebuffer_ensure(src);
gpu_texture_framebuffer_ensure(dst);
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());
BLI_assert(dst->copy_fb_ctx == GPU_context_active_get());
glBindFramebuffer(GL_READ_FRAMEBUFFER, src->copy_fb);
glReadBuffer(attachment);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dst->copy_fb);
/* 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);
GLbitfield mask = 0;
if (GPU_texture_stencil(src)) {
mask |= GL_STENCIL_BUFFER_BIT;
}
if (GPU_texture_depth(src)) {
mask |= GL_DEPTH_BUFFER_BIT;
}
else {
mask |= GL_COLOR_BUFFER_BIT;
}
glBindTexture(dst->target, 0);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, src->w, src->h, 0, 0, src->w, src->h, mask, GL_NEAREST);
if (prev_fb) {
GPU_framebuffer_bind(prev_fb);
}
}
}