meta: Add an accelerated glCopyTexSubImage using glBlitFramebuffer.
authorEric Anholt <eric@anholt.net>
Fri, 28 Feb 2014 21:23:25 +0000 (13:23 -0800)
committerEric Anholt <eric@anholt.net>
Tue, 15 Apr 2014 21:34:22 +0000 (14:34 -0700)
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 <ian.d.romanick@intel.com> (v2)
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
src/mesa/drivers/common/meta.c
src/mesa/drivers/common/meta.h
src/mesa/drivers/common/meta_blit.c
src/mesa/drivers/common/meta_generate_mipmap.c

index 12d6f65d20623f7779cc8fc50a94aee6e17acff2..ddd0b1ad19ab608d20def36b3fea60c5780dc32f 100644 (file)
@@ -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);
index ad3da9cd8d4b88f296efd8d4ad073eebe1733894..fd8a385b644b3dc63f6e33b7bd178a6199cdab2f 100644 (file)
@@ -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 */
index d1c40f50c52ec5227ab554ca8588fb21cfc062f7..526295bacbd8160f5ba43af794b62db93974357c 100644 (file)
@@ -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;
 
index db469745d12cd1476c1cdf660df7a8f46b793049..3c9ac89afbaf80329c77f4e81334186d8b38e612 100644 (file)
@@ -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) !=