From: Eric Anholt Date: Fri, 28 Feb 2014 21:23:25 +0000 (-0800) Subject: meta: Add an accelerated glCopyTexSubImage using glBlitFramebuffer. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=234db609544ee521458ce8b648e70cffe2fda6f9;p=mesa.git meta: Add an accelerated glCopyTexSubImage using glBlitFramebuffer. You'll note from the previous commits that there's something of a loop here: You call CTSI, which calls BlitFB, then if things go wrong that falls back to CTSI. As a result, meta CTSI reaches over into blitfb to tell it "no, don't try that fallback". v2: Drop the _mesa_update_state(), which was only necessary due to use of _mesa_clip_blit() in _mesa_meta_BlitFramebuffer() in another patch series. v3: Drop an _EXT suffix I copy-and-pasted. Reviewed-by: Ian Romanick (v2) Reviewed-by: Kenneth Graunke --- diff --git a/src/mesa/drivers/common/meta.c b/src/mesa/drivers/common/meta.c index 12d6f65d206..ddd0b1ad19a 100644 --- a/src/mesa/drivers/common/meta.c +++ b/src/mesa/drivers/common/meta.c @@ -37,6 +37,7 @@ #include "main/arbprogram.h" #include "main/arrayobj.h" #include "main/blend.h" +#include "main/blit.h" #include "main/bufferobj.h" #include "main/buffers.h" #include "main/colortab.h" @@ -94,7 +95,8 @@ static void meta_decompress_cleanup(struct decompress_state *decompress); static void meta_drawpix_cleanup(struct drawpix_state *drawpix); void -_mesa_meta_bind_fbo_image(struct gl_texture_image *texImage, GLuint layer) +_mesa_meta_bind_fbo_image(GLenum attachment, + struct gl_texture_image *texImage, GLuint layer) { struct gl_texture_object *texObj = texImage->TexObject; int level = texImage->Level; @@ -103,17 +105,18 @@ _mesa_meta_bind_fbo_image(struct gl_texture_image *texImage, GLuint layer) switch (target) { case GL_TEXTURE_1D: _mesa_FramebufferTexture1D(GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, + attachment, target, texObj->Name, level); break; case GL_TEXTURE_1D_ARRAY: case GL_TEXTURE_2D_ARRAY: + case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: case GL_TEXTURE_CUBE_MAP_ARRAY: case GL_TEXTURE_3D: _mesa_FramebufferTextureLayer(GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, + attachment, texObj->Name, level, layer); @@ -123,7 +126,7 @@ _mesa_meta_bind_fbo_image(struct gl_texture_image *texImage, GLuint layer) target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + texImage->Face; _mesa_FramebufferTexture2D(GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, + attachment, target, texObj->Name, level); @@ -2728,6 +2731,77 @@ get_temp_image_type(struct gl_context *ctx, mesa_format format) } } +/** + * Attempts to wrap the destination texture in an FBO and use + * glBlitFramebuffer() to implement glCopyTexSubImage(). + */ +static bool +copytexsubimage_using_blit_framebuffer(struct gl_context *ctx, GLuint dims, + struct gl_texture_image *texImage, + GLint xoffset, + GLint yoffset, + GLint zoffset, + struct gl_renderbuffer *rb, + GLint x, GLint y, + GLsizei width, GLsizei height) +{ + struct gl_texture_object *texObj = texImage->TexObject; + GLuint fbo; + bool success = false; + GLbitfield mask; + GLenum status; + + if (!ctx->Extensions.ARB_framebuffer_object) + return false; + + _mesa_unlock_texture(ctx, texObj); + + _mesa_meta_begin(ctx, MESA_META_ALL); + + _mesa_GenFramebuffers(1, &fbo); + _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); + + if (rb->_BaseFormat == GL_DEPTH_STENCIL || + rb->_BaseFormat == GL_DEPTH_COMPONENT) { + _mesa_meta_bind_fbo_image(GL_DEPTH_ATTACHMENT, texImage, zoffset); + mask = GL_DEPTH_BUFFER_BIT; + + if (rb->_BaseFormat == GL_DEPTH_STENCIL && + texImage->_BaseFormat == GL_DEPTH_STENCIL) { + _mesa_meta_bind_fbo_image(GL_STENCIL_ATTACHMENT, texImage, zoffset); + mask |= GL_STENCIL_BUFFER_BIT; + } + _mesa_DrawBuffer(GL_NONE); + } else { + _mesa_meta_bind_fbo_image(GL_COLOR_ATTACHMENT0, texImage, zoffset); + mask = GL_COLOR_BUFFER_BIT; + _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0); + } + + status = _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) + goto out; + + ctx->Meta->Blit.no_ctsi_fallback = true; + /* We skip the core BlitFramebuffer checks for format consistency, which + * are too strict for CopyTexImage. We know meta will be fine with format + * changes. + */ + _mesa_meta_BlitFramebuffer(ctx, x, y, + x + width, y + height, + xoffset, yoffset, + xoffset + width, yoffset + height, + mask, GL_NEAREST); + ctx->Meta->Blit.no_ctsi_fallback = false; + success = true; + + out: + _mesa_lock_texture(ctx, texObj); + _mesa_DeleteFramebuffers(1, &fbo); + _mesa_meta_end(ctx); + return success; +} + /** * Helper for _mesa_meta_CopyTexSubImage1/2/3D() functions. * Have to be careful with locking and meta state for pixel transfer. @@ -2745,11 +2819,14 @@ _mesa_meta_CopyTexSubImage(struct gl_context *ctx, GLuint dims, GLint bpp; void *buf; - /* The gl_renderbuffer is part of the interface for - * dd_function_table::CopyTexSubImage, but this implementation does not use - * it. - */ - (void) rb; + if (copytexsubimage_using_blit_framebuffer(ctx, dims, + texImage, + xoffset, yoffset, zoffset, + rb, + x, y, + width, height)) { + return; + } /* Choose format/type for temporary image buffer */ format = _mesa_get_format_base_format(texImage->TexFormat); diff --git a/src/mesa/drivers/common/meta.h b/src/mesa/drivers/common/meta.h index ad3da9cd8d4..fd8a385b644 100644 --- a/src/mesa/drivers/common/meta.h +++ b/src/mesa/drivers/common/meta.h @@ -253,6 +253,7 @@ struct blit_state struct blit_shader_table shaders; GLuint msaa_shaders[BLIT_MSAA_SHADER_COUNT]; struct temp_texture depthTex; + bool no_ctsi_fallback; }; @@ -505,6 +506,7 @@ void _mesa_meta_glsl_generate_mipmap_cleanup(struct gen_mipmap_state *mipmap); void -_mesa_meta_bind_fbo_image(struct gl_texture_image *texImage, GLuint layer); +_mesa_meta_bind_fbo_image(GLenum attachment, + struct gl_texture_image *texImage, GLuint layer); #endif /* META_H */ diff --git a/src/mesa/drivers/common/meta_blit.c b/src/mesa/drivers/common/meta_blit.c index d1c40f50c52..526295bacbd 100644 --- a/src/mesa/drivers/common/meta_blit.c +++ b/src/mesa/drivers/common/meta_blit.c @@ -419,6 +419,9 @@ blitframebuffer_texture(struct gl_context *ctx, /* Fall back to doing a CopyTexSubImage to get the destination * renderbuffer into a texture. */ + if (ctx->Meta->Blit.no_ctsi_fallback) + return false; + if (rb->NumSamples > 1) return false; diff --git a/src/mesa/drivers/common/meta_generate_mipmap.c b/src/mesa/drivers/common/meta_generate_mipmap.c index db469745d12..3c9ac89afba 100644 --- a/src/mesa/drivers/common/meta_generate_mipmap.c +++ b/src/mesa/drivers/common/meta_generate_mipmap.c @@ -103,7 +103,7 @@ fallback_required(struct gl_context *ctx, GLenum target, _mesa_GenFramebuffers(1, &mipmap->FBO); _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, mipmap->FBO); - _mesa_meta_bind_fbo_image(baseImage, 0); + _mesa_meta_bind_fbo_image(GL_COLOR_ATTACHMENT0, baseImage, 0); status = _mesa_CheckFramebufferStatus(GL_FRAMEBUFFER_EXT); @@ -317,7 +317,7 @@ _mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target, _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts), verts, GL_DYNAMIC_DRAW_ARB); - _mesa_meta_bind_fbo_image(dstImage, layer); + _mesa_meta_bind_fbo_image(GL_COLOR_ATTACHMENT0, dstImage, layer); /* sanity check */ if (_mesa_CheckFramebufferStatus(GL_FRAMEBUFFER) !=