[Mesa-dev] [PATCH 7/9] meta: Add an accelerated glCopyTexSubImage using glBlitFramebuffer.

Eric Anholt eric at anholt.net
Tue Apr 8 14:03:18 PDT 2014


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.
---
 src/mesa/drivers/common/meta.c                 | 95 +++++++++++++++++++++++---
 src/mesa/drivers/common/meta.h                 |  4 +-
 src/mesa/drivers/common/meta_blit.c            |  3 +
 src/mesa/drivers/common/meta_generate_mipmap.c |  4 +-
 4 files changed, 94 insertions(+), 12 deletions(-)

diff --git a/src/mesa/drivers/common/meta.c b/src/mesa/drivers/common/meta.c
index 9e832f2..ab79e74 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"
@@ -97,7 +98,8 @@ static void meta_drawpix_cleanup(struct drawpix_state *drawpix);
  * Bind a particular texture level/layer to mipmap->FBO's GL_COLOR_ATTACHMENT0.
  */
 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;
@@ -106,17 +108,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);
@@ -126,7 +129,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);
@@ -2732,6 +2735,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_EXT);
+   }
+
+   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.
  */
@@ -2748,11 +2822,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 ad3da9c..fd8a385 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 d7bb7c8..0bd76a1 100644
--- a/src/mesa/drivers/common/meta_blit.c
+++ b/src/mesa/drivers/common/meta_blit.c
@@ -425,6 +425,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 db46974..3c9ac89 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) !=
-- 
1.9.1



More information about the mesa-dev mailing list