st/mesa: simplify and improve CopyTexSubImage
authorMarek Olšák <maraeo@gmail.com>
Thu, 14 Feb 2013 11:08:33 +0000 (12:08 +0100)
committerMarek Olšák <maraeo@gmail.com>
Mon, 18 Feb 2013 16:57:41 +0000 (17:57 +0100)
It has become a bit messy.

Changes:

- finally correct checking for transfer ops depending on the base format

- making sure the base internal format and the texture format match
  (we were ignoring it, but it's important for correctness)

- the way-too-strict rule that both src and dst base formats must be the same
  was dropped; ensuring the simpler and more permissive rule mentioned above
  is enough

- stop using util_blit_pixels; pipe->blit is flexible enough, and now that we
  have RGBX and red-alpha formats, pipe->blit can be used for more cases

Reviewed-by: Brian Paul <brianp@vmware.com>
src/mesa/main/texstore.c
src/mesa/main/texstore.h
src/mesa/state_tracker/st_cb_texture.c

index 77222d6dfb615b1ffeed82fdbf413f214de06206..0e13d8903f936fd66cca489253ce3941e22860f7 100644 (file)
@@ -3792,26 +3792,21 @@ _mesa_get_texstore_func(gl_format format)
 
 
 GLboolean
-_mesa_texstore_can_use_memcpy(struct gl_context *ctx,
-                              GLenum baseInternalFormat, gl_format dstFormat,
-                              GLenum srcFormat, GLenum srcType,
-                              const struct gl_pixelstore_attrib *srcPacking)
+_mesa_texstore_needs_transfer_ops(struct gl_context *ctx,
+                                  GLenum baseInternalFormat,
+                                  gl_format dstFormat)
 {
    GLenum dstType;
 
-   /* There are different restrictions depending on the base format... */
+   /* There are different rules depending on the base format. */
    switch (baseInternalFormat) {
    case GL_DEPTH_COMPONENT:
    case GL_DEPTH_STENCIL:
-      /* Depth scale and bias are not allowed. */
-      if (ctx->Pixel.DepthScale != 1.0f ||
-          ctx->Pixel.DepthBias != 0.0f) {
-        return GL_FALSE;
-      }
-      break;
+      return ctx->Pixel.DepthScale != 1.0f ||
+             ctx->Pixel.DepthBias != 0.0f;
 
    case GL_STENCIL_INDEX:
-      break;
+      return GL_FALSE;
 
    default:
       /* Color formats.
@@ -3820,10 +3815,20 @@ _mesa_texstore_can_use_memcpy(struct gl_context *ctx,
        */
       dstType = _mesa_get_format_datatype(dstFormat);
 
-      if (dstType != GL_INT && dstType != GL_UNSIGNED_INT &&
-          ctx->_ImageTransferState) {
-         return GL_FALSE;
-      }
+      return dstType != GL_INT && dstType != GL_UNSIGNED_INT &&
+             ctx->_ImageTransferState;
+   }
+}
+
+
+GLboolean
+_mesa_texstore_can_use_memcpy(struct gl_context *ctx,
+                              GLenum baseInternalFormat, gl_format dstFormat,
+                              GLenum srcFormat, GLenum srcType,
+                              const struct gl_pixelstore_attrib *srcPacking)
+{
+   if (_mesa_texstore_needs_transfer_ops(ctx, baseInternalFormat, dstFormat)) {
+      return GL_FALSE;
    }
 
    /* The base internal format and the base Mesa format must match. */
index 107f21300156645daf5bd8f61308375ee21a8a67..75f24bd45ac8707dce6317642031b245bfff85a6 100644 (file)
 extern GLboolean
 _mesa_texstore(TEXSTORE_PARAMS);
 
+extern GLboolean
+_mesa_texstore_needs_transfer_ops(struct gl_context *ctx,
+                                  GLenum baseInternalFormat,
+                                  gl_format dstFormat);
 
 extern GLboolean
 _mesa_texstore_can_use_memcpy(struct gl_context *ctx,
index d2dccb41186b818425db12e6d12bd8e5874164ef..606bae010d3cd0a9ab6e680a3ab968a7625ea5bc 100644 (file)
@@ -1272,110 +1272,6 @@ fallback_copy_texsubimage(struct gl_context *ctx,
 }
 
 
-
-/**
- * If the format of the src renderbuffer and the format of the dest
- * texture are compatible (in terms of blitting), return a TGSI writemask
- * to be used during the blit.
- * If the src/dest are incompatible, return 0.
- */
-static unsigned
-compatible_src_dst_formats(struct gl_context *ctx,
-                           const struct gl_renderbuffer *src,
-                           const struct gl_texture_image *dst)
-{
-   /* Get logical base formats for the src and dest.
-    * That is, use the user-requested formats and not the actual, device-
-    * chosen formats.
-    * For example, the user may have requested an A8 texture but the
-    * driver may actually be using an RGBA texture format.  When we
-    * copy/blit to that texture, we only want to copy the Alpha channel
-    * and not the RGB channels.
-    *
-    * Similarly, when the src FBO was created an RGB format may have been
-    * requested but the driver actually chose an RGBA format.  In that case,
-    * we don't want to copy the undefined Alpha channel to the dest texture
-    * (it should be 1.0).
-    */
-   const GLenum srcFormat = _mesa_base_fbo_format(ctx, src->InternalFormat);
-   const GLenum dstFormat = _mesa_base_tex_format(ctx, dst->InternalFormat);
-
-   /**
-    * XXX when we have red-only and red/green renderbuffers we'll need
-    * to add more cases here (or implement a general-purpose routine that
-    * queries the existance of the R,G,B,A channels in the src and dest).
-    */
-   if (srcFormat == dstFormat) {
-      /* This is the same as matching_base_formats, which should
-       * always pass, as it did previously.
-       */
-      return TGSI_WRITEMASK_XYZW;
-   }
-   else if (srcFormat == GL_RGB && dstFormat == GL_RGBA) {
-      /* Make sure that A in the dest is 1.  The actual src format
-       * may be RGBA and have undefined A values.
-       */
-      return TGSI_WRITEMASK_XYZ;
-   }
-   else if (srcFormat == GL_RGBA && dstFormat == GL_RGB) {
-      /* Make sure that A in the dest is 1.  The actual dst format
-       * may be RGBA and will need A=1 to provide proper alpha values
-       * when sampled later.
-       */
-      return TGSI_WRITEMASK_XYZ;
-   }
-   else {
-      if (ST_DEBUG & DEBUG_FALLBACK)
-         debug_printf("%s failed for src %s, dst %s\n",
-                      __FUNCTION__, 
-                      _mesa_lookup_enum_by_nr(srcFormat),
-                      _mesa_lookup_enum_by_nr(dstFormat));
-
-      /* Otherwise fail.
-       */
-      return 0;
-   }
-}
-
-
-/**
- * Do pipe->blit. Return FALSE if the blitting is unsupported
- * for the given formats.
- */
-static GLboolean
-st_pipe_blit(struct pipe_context *pipe, struct pipe_blit_info *blit)
-{
-   struct pipe_screen *screen = pipe->screen;
-   unsigned dst_usage;
-
-   if (util_format_is_depth_or_stencil(blit->dst.format)) {
-      dst_usage = PIPE_BIND_DEPTH_STENCIL;
-   }
-   else {
-      dst_usage = PIPE_BIND_RENDER_TARGET;
-   }
-
-   /* try resource_copy_region in case the format is not supported
-    * for rendering */
-   if (util_try_blit_via_copy_region(pipe, blit)) {
-      return GL_TRUE; /* done */
-   }
-
-   /* check the format support */
-   if (!screen->is_format_supported(screen, blit->src.format,
-                                    PIPE_TEXTURE_2D, 0,
-                                    PIPE_BIND_SAMPLER_VIEW) ||
-       !screen->is_format_supported(screen, blit->dst.format,
-                                    PIPE_TEXTURE_2D, 0,
-                                    dst_usage)) {
-      return GL_FALSE;
-   }
-
-   pipe->blit(pipe, blit);
-   return GL_TRUE;
-}
-
-
 /**
  * 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
@@ -1391,184 +1287,118 @@ st_CopyTexSubImage(struct gl_context *ctx, GLuint dims,
                    GLint srcX, GLint srcY, GLsizei width, GLsizei height)
 {
    struct st_texture_image *stImage = st_texture_image(texImage);
-   const GLenum texBaseFormat = texImage->_BaseFormat;
+   struct st_texture_object *stObj = st_texture_object(texImage->TexObject);
    struct st_renderbuffer *strb = st_renderbuffer(rb);
    struct st_context *st = st_context(ctx);
    struct pipe_context *pipe = st->pipe;
    struct pipe_screen *screen = pipe->screen;
-   enum pipe_format dest_format, src_format;
-   GLuint color_writemask;
-   struct pipe_surface *dest_surface = NULL;
+   struct pipe_blit_info blit;
+   enum pipe_format dst_format;
    GLboolean do_flip = (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP);
-   struct pipe_surface surf_tmpl;
-   unsigned dst_usage;
-   unsigned blit_mask;
+   unsigned bind;
    GLint srcY0, srcY1, yStep;
 
-   /* make sure finalize_textures has been called? 
-    */
-   if (0) st_validate_state(st);
-
    if (!strb || !strb->surface || !stImage->pt) {
       debug_printf("%s: null strb or stImage\n", __FUNCTION__);
       return;
    }
 
-   assert(strb);
-   assert(strb->surface);
-   assert(stImage->pt);
-
-   src_format = util_format_linear(strb->surface->format);
-   dest_format = util_format_linear(stImage->pt->format);
-
-   if (do_flip) {
-      srcY1 = strb->Base.Height - srcY - height;
-      srcY0 = srcY1 + height;
-      yStep = -1;
-   }
-   else {
-      srcY0 = srcY;
-      srcY1 = srcY0 + height;
-      yStep = 1;
-   }
-
-   if (ctx->_ImageTransferState) {
+   if (_mesa_texstore_needs_transfer_ops(ctx, texImage->_BaseFormat,
+                                         texImage->TexFormat)) {
       goto fallback;
    }
 
-   /* Compressed and subsampled textures aren't supported for blitting. */
-   if (!util_format_is_plain(dest_format)) {
+   /* The base internal format must match the mesa format, so make sure
+    * e.g. an RGB internal format is really allocated as RGB and not as RGBA.
+    */
+   if (texImage->_BaseFormat !=
+       _mesa_get_format_base_format(texImage->TexFormat) ||
+       rb->_BaseFormat != _mesa_get_format_base_format(rb->Format)) {
       goto fallback;
    }
 
-   if (texBaseFormat == GL_DEPTH_STENCIL ||
-       texBaseFormat == GL_DEPTH_COMPONENT) {
-      dst_usage = PIPE_BIND_DEPTH_STENCIL;
+   /* Choose the destination format to match the TexImage behavior. */
+   dst_format = util_format_linear(stImage->pt->format);
+   dst_format = util_format_luminance_to_red(dst_format);
+   dst_format = util_format_intensity_to_red(dst_format);
+
+   /* See if the destination format is supported. */
+   if (texImage->_BaseFormat == GL_DEPTH_STENCIL ||
+       texImage->_BaseFormat == GL_DEPTH_COMPONENT) {
+      bind = PIPE_BIND_DEPTH_STENCIL;
    }
    else {
-      dst_usage = PIPE_BIND_RENDER_TARGET;
+      bind = PIPE_BIND_RENDER_TARGET;
    }
 
-   blit_mask = get_blit_mask(rb->_BaseFormat, texImage->_BaseFormat);
+   if (!dst_format ||
+       !screen->is_format_supported(screen, dst_format, stImage->pt->target,
+                                    stImage->pt->nr_samples, bind)) {
+      goto fallback;
+   }
 
-   /* Determine if the src framebuffer and dest texture have the same
-    * base format.  We need this to detect a case such as the framebuffer
-    * being GL_RGBA but the texture being GL_RGB.  If the actual hardware
-    * texture format stores RGBA we need to set A=1 (overriding the
-    * framebuffer's alpha values).
-    *
-    * XXX util_blit_pixels doesn't support MSAA resolve, so always use
-    *     pipe->blit for MSAA textures
-    */
-   if ((blit_mask & PIPE_MASK_RGBA) &&
-       texBaseFormat != strb->Base._BaseFormat &&
-       strb->texture->nr_samples <= 1) {
-      blit_mask = 0;
+   /* Y flipping for the main framebuffer. */
+   if (do_flip) {
+      srcY1 = strb->Base.Height - srcY - height;
+      srcY0 = srcY1 + height;
+      yStep = -1;
+   }
+   else {
+      srcY0 = srcY;
+      srcY1 = srcY0 + height;
+      yStep = 1;
    }
 
    /* Blit the texture.
     * This supports flipping, format conversions, and downsampling.
     */
-   if (blit_mask) {
-      /* If stImage->pt is an independent image (not a pointer into a full
-       * mipmap) stImage->pt.last_level will be zero and we need to use that
-       * as the dest level.
-       */
-      unsigned dstLevel = MIN2(stImage->base.Level, stImage->pt->last_level);
-      struct pipe_blit_info blit;
-
-      memset(&blit, 0, sizeof(blit));
-      blit.src.resource = strb->texture;
-      blit.src.format = src_format;
-      blit.src.level = strb->surface->u.tex.level;
-      blit.src.box.x = srcX;
-      blit.src.box.y = srcY0;
-      blit.src.box.z = strb->surface->u.tex.first_layer;
-      blit.src.box.width = width;
-      blit.src.box.height = srcY1 - srcY0;
-      blit.src.box.depth = 1;
-      blit.dst.resource = stImage->pt;
-      blit.dst.format = dest_format;
-      blit.dst.level = dstLevel;
-      blit.dst.box.x = destX;
-      blit.dst.box.y = destY;
-      blit.dst.box.z = stImage->base.Face + destZ;
-      blit.dst.box.width = width;
-      blit.dst.box.height = height;
-      blit.dst.box.depth = 1;
-      blit.mask = blit_mask;
-      blit.filter = PIPE_TEX_FILTER_NEAREST;
-
-      /* 1D array textures need special treatment.
-       * Blit rows from the source to layers in the destination. */
-      if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) {
-         int y, layer;
-
-         for (y = srcY0, layer = 0; layer < height; y += yStep, layer++) {
-            blit.src.box.y = y;
-            blit.src.box.height = 1;
-            blit.dst.box.y = 0;
-            blit.dst.box.height = 1;
-            blit.dst.box.z = destY + layer;
-
-            if (!st_pipe_blit(pipe, &blit)) {
-               goto fallback;
-            }
-         }
-      }
-      else {
-         /* All the other texture targets. */
-         if (!st_pipe_blit(pipe, &blit)) {
-            goto fallback;
-         }
-      }
-      return;
-   }
+   memset(&blit, 0, sizeof(blit));
+   blit.src.resource = strb->texture;
+   blit.src.format = util_format_linear(strb->surface->format);
+   blit.src.level = strb->surface->u.tex.level;
+   blit.src.box.x = srcX;
+   blit.src.box.y = srcY0;
+   blit.src.box.z = strb->surface->u.tex.first_layer;
+   blit.src.box.width = width;
+   blit.src.box.height = srcY1 - srcY0;
+   blit.src.box.depth = 1;
+   blit.dst.resource = stImage->pt;
+   blit.dst.format = dst_format;
+   blit.dst.level = stObj->pt != stImage->pt ? 0 : texImage->Level;
+   blit.dst.box.x = destX;
+   blit.dst.box.y = destY;
+   blit.dst.box.z = stImage->base.Face + destZ;
+   blit.dst.box.width = width;
+   blit.dst.box.height = height;
+   blit.dst.box.depth = 1;
+   blit.mask = get_blit_mask(rb->_BaseFormat, texImage->_BaseFormat);
+   blit.filter = PIPE_TEX_FILTER_NEAREST;
 
-   /* try u_blit */
+   /* 1D array textures need special treatment.
+    * Blit rows from the source to layers in the destination. */
    if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) {
-      /* u_blit cannot copy 1D array textures as required by CopyTexSubImage */
-      goto fallback;
-   }
+      int y, layer;
 
-   color_writemask = compatible_src_dst_formats(ctx, &strb->Base, texImage);
+      for (y = srcY0, layer = 0; layer < height; y += yStep, layer++) {
+         blit.src.box.y = y;
+         blit.src.box.height = 1;
+         blit.dst.box.y = 0;
+         blit.dst.box.height = 1;
+         blit.dst.box.z = destY + layer;
 
-   if (!color_writemask ||
-       !screen->is_format_supported(screen, src_format,
-                                    PIPE_TEXTURE_2D, 0,
-                                    PIPE_BIND_SAMPLER_VIEW) ||
-       !screen->is_format_supported(screen, dest_format,
-                                    PIPE_TEXTURE_2D, 0,
-                                    dst_usage)) {
-      goto fallback;
+         pipe->blit(pipe, &blit);
+      }
+   }
+   else {
+      /* All the other texture targets. */
+      pipe->blit(pipe, &blit);
    }
-
-   memset(&surf_tmpl, 0, sizeof(surf_tmpl));
-   surf_tmpl.format = util_format_linear(stImage->pt->format);
-   surf_tmpl.u.tex.level = stImage->base.Level;
-   surf_tmpl.u.tex.first_layer = stImage->base.Face + destZ;
-   surf_tmpl.u.tex.last_layer = stImage->base.Face + destZ;
-
-   dest_surface = pipe->create_surface(pipe, stImage->pt,
-                                       &surf_tmpl);
-   util_blit_pixels(st->blit,
-                    strb->texture,
-                    strb->surface->u.tex.level,
-                    srcX, srcY0,
-                    srcX + width, srcY1,
-                    strb->surface->u.tex.first_layer,
-                    dest_surface,
-                    destX, destY,
-                    destX + width, destY + height,
-                    0.0, PIPE_TEX_MIPFILTER_NEAREST,
-                    color_writemask, 0);
-   pipe_surface_reference(&dest_surface, NULL);
    return;
 
 fallback:
    /* software fallback */
    fallback_copy_texsubimage(ctx,
-                             strb, stImage, texBaseFormat,
+                             strb, stImage, texImage->_BaseFormat,
                              destX, destY, destZ,
                              srcX, srcY, width, height);
 }