st/mesa: Do GL_RGBA->GL_RGB texsubimage on hardware
authorKeith Whitwell <keithw@vmware.com>
Wed, 2 Sep 2009 17:30:11 +0000 (18:30 +0100)
committerKeith Whitwell <keithw@vmware.com>
Wed, 2 Sep 2009 17:31:48 +0000 (18:31 +0100)
State tracker currently backs GL_RGB textures with RGBA almost always.
This means we need to maintain A==1 in these textures to give correct GL_RGB
sampling results.

This change offloads the RGBA->RGB copy to hardware using the new writemask
version of u_blit_pixels.

More src/dstLogical/dstActual triples could be shifted to hardware by
this technique in future patches.

src/mesa/state_tracker/st_cb_texture.c

index ee71c01..2d37d24 100644 (file)
@@ -56,6 +56,7 @@
 #include "pipe/p_context.h"
 #include "pipe/p_defines.h"
 #include "pipe/p_inlines.h"
+#include "pipe/p_shader_tokens.h"
 #include "util/u_tile.h"
 #include "util/u_blit.h"
 #include "util/u_surface.h"
@@ -1396,6 +1397,36 @@ fallback_copy_texsubimage(GLcontext *ctx, GLenum target, GLint level,
 }
 
 
+static unsigned
+compatible_src_dst_formats(const struct gl_renderbuffer *src,
+                           const struct gl_texture_image *dst)
+{
+   const GLenum srcFormat = src->_BaseFormat;
+   const GLenum dstLogicalFormat = dst->_BaseFormat;
+
+   if (srcFormat == dstLogicalFormat) {
+      /* This is the same as matching_base_formats, which should
+       * always pass, as it did previously.
+       */
+      return TGSI_WRITEMASK_XYZW;
+   }
+   else if (srcFormat == GL_RGBA &&
+            dstLogicalFormat == GL_RGB) {
+      /* Add a single special case to cope with RGBA->RGB transfers,
+       * setting A to 1.0 to cope with situations where the RGB
+       * destination is actually stored as RGBA.
+       */
+      return TGSI_WRITEMASK_XYZ; /* A ==> 1.0 */
+   }
+   else {
+      /* Otherwise fail.
+       */
+      return 0;
+   }
+}
+
+
+
 /**
  * Do a CopyTex[Sub]Image1/2/3D() using a hardware (blit) path if possible.
  * Note that the region to copy has already been clipped so we know we
@@ -1425,6 +1456,9 @@ st_copy_texsubimage(GLcontext *ctx,
    enum pipe_format dest_format, src_format;
    GLboolean use_fallback = GL_TRUE;
    GLboolean matching_base_formats;
+   GLuint format_writemask;
+   struct pipe_surface *dest_surface = NULL;
+   GLboolean do_flip = (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP);
 
    /* any rendering in progress must flushed before we grab the fb image */
    st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
@@ -1495,13 +1529,14 @@ st_copy_texsubimage(GLcontext *ctx,
     * textured-quad paths.
     */
    matching_base_formats = (strb->Base._BaseFormat == texImage->_BaseFormat);
+   format_writemask = compatible_src_dst_formats(&strb->Base, texImage);
 
-   if (matching_base_formats && ctx->_ImageTransferState == 0x0) {
-      /* try potential hardware path */
-      struct pipe_surface *dest_surface = NULL;
-      boolean do_flip = (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP);
+   if (ctx->_ImageTransferState == 0x0) {
 
-      if (src_format == dest_format && !do_flip) {
+      if (matching_base_formats && 
+          src_format == dest_format &&
+          !do_flip) 
+      {
          /* use surface_copy() / blit */
 
          dest_surface = screen->get_tex_surface(screen, stImage->pt,
@@ -1521,7 +1556,8 @@ st_copy_texsubimage(GLcontext *ctx,
                             width, height);
          use_fallback = GL_FALSE;
       }
-      else if (screen->is_format_supported(screen, src_format,
+      else if (format_writemask &&
+               screen->is_format_supported(screen, src_format,
                                            PIPE_TEXTURE_2D, 
                                            PIPE_TEXTURE_USAGE_SAMPLER,
                                            0) &&
@@ -1545,14 +1581,15 @@ st_copy_texsubimage(GLcontext *ctx,
             srcY0 = srcY;
             srcY1 = srcY0 + height;
          }
-         util_blit_pixels(ctx->st->blit,
-                          strb->surface,
-                          srcX, srcY0,
-                          srcX + width, srcY1,
-                          dest_surface,
-                          destX, destY,
-                          destX + width, destY + height,
-                          0.0, PIPE_TEX_MIPFILTER_NEAREST);
+         util_blit_pixels_writemask(ctx->st->blit,
+                                    strb->surface,
+                                    srcX, srcY0,
+                                    srcX + width, srcY1,
+                                    dest_surface,
+                                    destX, destY,
+                                    destX + width, destY + height,
+                                    0.0, PIPE_TEX_MIPFILTER_NEAREST,
+                                    format_writemask);
          use_fallback = GL_FALSE;
       }