intel: Try using glCopyTexSubImage2D in _mesa_meta_BlitFramebuffer
authorNeil Roberts <neil@linux.intel.com>
Sat, 5 Feb 2011 10:21:11 +0000 (10:21 +0000)
committerChris Wilson <chris@chris-wilson.co.uk>
Thu, 24 Feb 2011 16:43:39 +0000 (16:43 +0000)
In the case where glBlitFramebuffer is being used to copy to a texture
without scaling it is faster if we can use the hardware to do a blit
rather than having to do a texture render. In most of the drivers
glCopyTexSubImage2D will use a blit so this patch makes it check for
when glBlitFramebuffer is doing a simple copy and then divert to
glCopyTexSubImage2D.

This was originally proposed as an extension to the common meta-ops.
However, it was rejected as using the BLT is only advantageous for Intel
hardware.

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=33934
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
src/mesa/drivers/dri/intel/intel_fbo.c
src/mesa/drivers/dri/intel/intel_tex.h
src/mesa/drivers/dri/intel/intel_tex_copy.c

index 886b25c23b41e8d403d9a29a315ddc5311214d46..8b57eb19f562fb9b11837cfb2519b091fc127d32 100644 (file)
@@ -34,6 +34,7 @@
 #include "main/framebuffer.h"
 #include "main/renderbuffer.h"
 #include "main/context.h"
+#include "main/teximage.h"
 #include "main/texrender.h"
 #include "drivers/common/meta.h"
 
@@ -647,6 +648,84 @@ intel_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb)
    }
 }
 
+/**
+ * Try to do a glBlitFramebuffer using glCopyTexSubImage2D
+ * We can do this when the dst renderbuffer is actually a texture and
+ * there is no scaling, mirroring or scissoring.
+ *
+ * \return new buffer mask indicating the buffers left to blit using the
+ *         normal path.
+ */
+static GLbitfield
+intel_blit_framebuffer_copy_tex_sub_image(struct gl_context *ctx,
+                                          GLint srcX0, GLint srcY0,
+                                          GLint srcX1, GLint srcY1,
+                                          GLint dstX0, GLint dstY0,
+                                          GLint dstX1, GLint dstY1,
+                                          GLbitfield mask, GLenum filter)
+{
+   if (mask & GL_COLOR_BUFFER_BIT) {
+      const struct gl_framebuffer *drawFb = ctx->DrawBuffer;
+      const struct gl_framebuffer *readFb = ctx->ReadBuffer;
+      const struct gl_renderbuffer_attachment *drawAtt =
+         &drawFb->Attachment[drawFb->_ColorDrawBufferIndexes[0]];
+
+      /* If the source and destination are the same size with no
+         mirroring, the rectangles are within the size of the
+         texture and there is no scissor then we can use
+         glCopyTexSubimage2D to implement the blit. This will end
+         up as a fast hardware blit on some drivers */
+      if (drawAtt && drawAtt->Texture &&
+          srcX0 - srcX1 == dstX0 - dstX1 &&
+          srcY0 - srcY1 == dstY0 - dstY1 &&
+          srcX1 >= srcX0 &&
+          srcY1 >= srcY0 &&
+          srcX0 >= 0 && srcX1 <= readFb->Width &&
+          srcY0 >= 0 && srcY1 <= readFb->Height &&
+          dstX0 >= 0 && dstX1 <= drawFb->Width &&
+          dstY0 >= 0 && dstY1 <= drawFb->Height &&
+          !ctx->Scissor.Enabled) {
+         const struct gl_texture_object *texObj = drawAtt->Texture;
+         const GLuint dstLevel = drawAtt->TextureLevel;
+         const GLenum target = texObj->Target;
+
+         struct gl_texture_image *texImage =
+            _mesa_select_tex_image(ctx, texObj, target, dstLevel);
+         GLenum internalFormat = texImage->InternalFormat;
+
+         if (intel_copy_texsubimage(intel_context(ctx), target,
+                                    intel_texture_image(texImage),
+                                    internalFormat,
+                                    dstX0, dstY0,
+                                    srcX0, srcY0,
+                                    srcX1 - srcX0, /* width */
+                                    srcY1 - srcY0))
+            mask &= ~GL_COLOR_BUFFER_BIT;
+      }
+   }
+
+   return mask;
+}
+
+static void
+intel_blit_framebuffer(struct gl_context *ctx,
+                       GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
+                       GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
+                       GLbitfield mask, GLenum filter)
+{
+   /* Try faster, glCopyTexSubImage2D approach first which uses the BLT. */
+   mask = intel_blit_framebuffer_copy_tex_sub_image(ctx,
+                                                    srcX0, srcY0, srcX1, srcY1,
+                                                    dstX0, dstY0, dstX1, dstY1,
+                                                    mask, filter);
+   if (mask == 0x0)
+      return;
+
+   _mesa_meta_BlitFramebuffer(ctx,
+                              srcX0, srcY0, srcX1, srcY1,
+                              dstX0, dstY0, dstX1, dstY1,
+                              mask, filter);
+}
 
 /**
  * Do one-time context initializations related to GL_EXT_framebuffer_object.
@@ -663,7 +742,7 @@ intel_fbo_init(struct intel_context *intel)
    intel->ctx.Driver.FinishRenderTexture = intel_finish_render_texture;
    intel->ctx.Driver.ResizeBuffers = intel_resize_buffers;
    intel->ctx.Driver.ValidateFramebuffer = intel_validate_framebuffer;
-   intel->ctx.Driver.BlitFramebuffer = _mesa_meta_BlitFramebuffer;
+   intel->ctx.Driver.BlitFramebuffer = intel_blit_framebuffer;
 
 #if FEATURE_OES_EGL_image
    intel->ctx.Driver.EGLImageTargetRenderbufferStorage =
index 6552ed0d332afb78926bc1bdf0ebae56d6972ddb..52462f39d54893252b967e83818bf336b9b60450 100644 (file)
@@ -65,4 +65,12 @@ void intel_tex_unmap_images(struct intel_context *intel,
 
 int intel_compressed_num_bytes(GLuint mesaFormat);
 
+GLboolean intel_copy_texsubimage(struct intel_context *intel,
+                                 GLenum target,
+                                 struct intel_texture_image *intelImage,
+                                 GLenum internalFormat,
+                                 GLint dstx, GLint dsty,
+                                 GLint x, GLint y,
+                                 GLsizei width, GLsizei height);
+
 #endif
index a40011ab40c396aad71a2873a2cb62ae2e4f4e0b..136d8e1d0a9e718a2fe15b163ead2c71bd12ee65 100644 (file)
@@ -67,13 +67,13 @@ get_teximage_readbuffer(struct intel_context *intel, GLenum internalFormat)
 }
 
 
-static GLboolean
-do_copy_texsubimage(struct intel_context *intel,
-                   GLenum target,
-                    struct intel_texture_image *intelImage,
-                    GLenum internalFormat,
-                    GLint dstx, GLint dsty,
-                    GLint x, GLint y, GLsizei width, GLsizei height)
+GLboolean
+intel_copy_texsubimage(struct intel_context *intel,
+                       GLenum target,
+                       struct intel_texture_image *intelImage,
+                       GLenum internalFormat,
+                       GLint dstx, GLint dsty,
+                       GLint x, GLint y, GLsizei width, GLsizei height)
 {
    struct gl_context *ctx = &intel->ctx;
    struct intel_renderbuffer *irb;
@@ -191,9 +191,9 @@ intelCopyTexImage1D(struct gl_context * ctx, GLenum target, GLint level,
                                   &width, &height))
       return;
 
-   if (!do_copy_texsubimage(intel_context(ctx), target,
-                            intel_texture_image(texImage),
-                            internalFormat, 0, 0, x, y, width, height))
+   if (!intel_copy_texsubimage(intel_context(ctx), target,
+                               intel_texture_image(texImage),
+                               internalFormat, 0, 0, x, y, width, height))
       goto fail;
 
    return;
@@ -239,9 +239,9 @@ intelCopyTexImage2D(struct gl_context * ctx, GLenum target, GLint level,
                                   &width, &height))
       return;
 
-   if (!do_copy_texsubimage(intel_context(ctx), target,
-                            intel_texture_image(texImage),
-                            internalFormat, 0, 0, x, y, width, height))
+   if (!intel_copy_texsubimage(intel_context(ctx), target,
+                               intel_texture_image(texImage),
+                               internalFormat, 0, 0, x, y, width, height))
       goto fail;
 
    return;
@@ -269,9 +269,9 @@ intelCopyTexSubImage1D(struct gl_context * ctx, GLenum target, GLint level,
    /* Need to check texture is compatible with source format. 
     */
 
-   if (!do_copy_texsubimage(intel_context(ctx), target,
-                            intel_texture_image(texImage),
-                            internalFormat, xoffset, 0, x, y, width, 1)) {
+   if (!intel_copy_texsubimage(intel_context(ctx), target,
+                               intel_texture_image(texImage),
+                               internalFormat, xoffset, 0, x, y, width, 1)) {
       fallback_debug("%s - fallback to swrast\n", __FUNCTION__);
       _mesa_meta_CopyTexSubImage1D(ctx, target, level, xoffset, x, y, width);
    }
@@ -293,11 +293,10 @@ intelCopyTexSubImage2D(struct gl_context * ctx, GLenum target, GLint level,
    /* Need to check texture is compatible with source format. 
     */
 
-   if (!do_copy_texsubimage(intel_context(ctx), target,
-                            intel_texture_image(texImage),
-                            internalFormat,
-                            xoffset, yoffset, x, y, width, height)) {
-
+   if (!intel_copy_texsubimage(intel_context(ctx), target,
+                               intel_texture_image(texImage),
+                               internalFormat,
+                               xoffset, yoffset, x, y, width, height)) {
       fallback_debug("%s - fallback to swrast\n", __FUNCTION__);
       _mesa_meta_CopyTexSubImage2D(ctx, target, level,
                                    xoffset, yoffset, x, y, width, height);