st/mesa: implement blit-based path for glCopyPixels
authorBrian Paul <brianp@vmware.com>
Fri, 18 Feb 2011 02:10:13 +0000 (19:10 -0700)
committerBrian Paul <brianp@vmware.com>
Fri, 18 Feb 2011 02:11:32 +0000 (19:11 -0700)
If doing a simple non-overlapping glCopyPixels with no per-fragment ops
we can use pipe_context::resource_copy_region().

src/mesa/state_tracker/st_cb_drawpixels.c

index a6935edb44cb157d76a4bc84b319c004fa59ed8d..aaa5bbff6794346117796e27ba5bd4aac18dbdda 100644 (file)
@@ -1142,6 +1142,109 @@ copy_stencil_pixels(struct gl_context *ctx, GLint srcx, GLint srcy,
 }
 
 
+/** Do the src/dest regions overlap? */
+static GLboolean
+regions_overlap(GLint srcX, GLint srcY, GLint dstX, GLint dstY,
+                GLsizei width, GLsizei height)
+{
+   if (srcX + width <= dstX ||
+       dstX + width <= srcX ||
+       srcY + height <= dstY ||
+       dstY + height <= srcY)
+      return GL_FALSE;
+   else
+      return GL_TRUE;
+}
+
+
+/**
+ * Try to do a glCopyPixels for simple cases with a blit by calling
+ * pipe->resource_copy_region().
+ *
+ * We can do this when we're copying color pixels (depth/stencil
+ * eventually) with no pixel zoom, no pixel transfer ops, no
+ * per-fragment ops, the src/dest regions don't overlap and the
+ * src/dest pixel formats are the same.
+ */
+static GLboolean
+blit_copy_pixels(struct gl_context *ctx, GLint srcx, GLint srcy,
+                 GLsizei width, GLsizei height,
+                 GLint dstx, GLint dsty, GLenum type)
+{
+   struct st_context *st = st_context(ctx);
+   struct pipe_context *pipe = st->pipe;
+   struct gl_pixelstore_attrib pack, unpack;
+   GLint readX, readY, readW, readH;
+
+   if (type == GL_COLOR &&
+       ctx->Pixel.ZoomX == 1.0 &&
+       ctx->Pixel.ZoomY == 1.0 &&
+       ctx->_ImageTransferState == 0x0 &&
+       !ctx->Color.BlendEnabled &&
+       !ctx->Color.AlphaEnabled &&
+       !ctx->Depth.Test &&
+       !ctx->Fog.Enabled &&
+       !ctx->Stencil.Enabled &&
+       !ctx->FragmentProgram.Enabled &&
+       !ctx->VertexProgram.Enabled &&
+       !ctx->Shader.CurrentFragmentProgram &&
+       ctx->DrawBuffer->_NumColorDrawBuffers == 1) {
+      struct st_renderbuffer *rbRead, *rbDraw;
+      GLint drawX, drawY;
+
+      /*
+       * Clip the read region against the src buffer bounds.
+       * We'll still allocate a temporary buffer/texture for the original
+       * src region size but we'll only read the region which is on-screen.
+       * This may mean that we draw garbage pixels into the dest region, but
+       * that's expected.
+       */
+      readX = srcx;
+      readY = srcy;
+      readW = width;
+      readH = height;
+      pack = ctx->DefaultPacking;
+      if (!_mesa_clip_readpixels(ctx, &readX, &readY, &readW, &readH, &pack))
+         return GL_TRUE; /* all done */
+
+      /* clip against dest buffer bounds and scissor box */
+      drawX = dstx + pack.SkipPixels;
+      drawY = dsty + pack.SkipRows;
+      unpack = pack;
+      if (!_mesa_clip_drawpixels(ctx, &drawX, &drawY, &readW, &readH, &unpack))
+         return GL_TRUE; /* all done */
+
+      readX = readX - pack.SkipPixels + unpack.SkipPixels;
+      readY = readY - pack.SkipRows + unpack.SkipRows;
+
+      rbRead = st_get_color_read_renderbuffer(ctx);
+      rbDraw = st_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]);
+
+      if ((rbRead != rbDraw ||
+           !regions_overlap(readX, readY, drawX, drawY, readW, readH)) &&
+          rbRead->Base.Format == rbDraw->Base.Format) {
+         struct pipe_box srcBox;
+
+         /* flip src/dst position if needed */
+         if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP)
+            readY = ctx->ReadBuffer->Height - readY - readH;
+
+         if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP)
+            drawY = ctx->DrawBuffer->Height - drawY - readH;
+
+         u_box_2d(readX, readY, readW, readH, &srcBox);
+
+         pipe->resource_copy_region(pipe,
+                                    rbDraw->texture, 0, drawX, drawY, 0,
+                                    rbRead->texture, 0, &srcBox);
+         return GL_TRUE;
+      }
+   }
+
+   return GL_FALSE;
+}
+
+
 static void
 st_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy,
               GLsizei width, GLsizei height,
@@ -1171,6 +1274,17 @@ st_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy,
       return;
    }
 
+   if (blit_copy_pixels(ctx, srcx, srcy, width, height, dstx, dsty, type))
+      return;
+
+   /*
+    * The subsequent code implements glCopyPixels by copying the source
+    * pixels into a temporary texture that's then applied to a textured quad.
+    * When we draw the textured quad, all the usual per-fragment operations
+    * are handled.
+    */
+
+
    /*
     * Get vertex/fragment shaders
     */