st/mesa: overhaul texture / sample swizzle code
authorBrian Paul <brianp@vmware.com>
Tue, 25 Mar 2014 17:04:40 +0000 (11:04 -0600)
committerBrian Paul <brianp@vmware.com>
Thu, 27 Mar 2014 15:45:25 +0000 (09:45 -0600)
Previously we only examined the GL_DEPTH_MODE state to determine the
sampler view swizzle for depth textures.  Now we also consider the
texture base format for color textures too.

The basic idea is if we're sampling from a RGB texture we always
want to get A=1, even if the actual hardware format might be RGBA.
We had assumed that the texture's A values were always one since that's
what Mesa's texstore code does.  But if we render to the RGBA texture,
the A values might not be 1.  Subsequent sampling didn't return the
right values.

Now we examine the user-specified texture base format vs. the actual
gallium format to determine the right swizzle.

Fixes several fbo-blending-formats, fbo-clear-formats and fbo-tex-rgbx
failures with VMware/svga driver (and possibly other drivers).
No other piglit regressions with softpipe or VMware/svga.

Reviewed-by: Marek Olšák <maraeo@gmail.com>
src/mesa/state_tracker/st_atom_texture.c

index c4452134a2292e85201388aeb1de1d0b632a1c6b..c9bffce4f7e2cacd840ba631ace009d3de9f0e90 100644 (file)
@@ -83,67 +83,132 @@ swizzle_swizzle(unsigned swizzle1, unsigned swizzle2)
 
 
 /**
- * Combine depth texture mode with "swizzle" so that depth mode swizzling
- * takes place before texture swizzling, and return the resulting swizzle.
- * If the format is not a depth format, return "swizzle" unchanged.
+ * Given a user-specified texture base format, the actual gallium texture
+ * format and the current GL_DEPTH_MODE, return a texture swizzle.
  *
- * \param format     PIPE_FORMAT_*.
- * \param swizzle    Texture swizzle, a bitmask computed using MAKE_SWIZZLE4.
- * \param depthmode  One of GL_LUMINANCE, GL_INTENSITY, GL_ALPHA, GL_RED.
+ * Consider the case where the user requests a GL_RGB internal texture
+ * format the driver actually uses an RGBA format.  The A component should
+ * be ignored and sampling from the texture should always return (r,g,b,1).
+ * But if we rendered to the texture we might have written A values != 1.
+ * By sampling the texture with a ".xyz1" swizzle we'll get the expected A=1.
+ * This function computes the texture swizzle needed to get the expected
+ * values.
+ *
+ * In the case of depth textures, the GL_DEPTH_MODE state determines the
+ * texture swizzle.
+ *
+ * This result must be composed with the user-specified swizzle to get
+ * the final swizzle.
  */
-static GLuint
-apply_depthmode(enum pipe_format format, GLuint swizzle, GLenum depthmode)
+static unsigned
+compute_texture_format_swizzle(GLenum baseFormat, GLenum depthMode,
+                               enum pipe_format actualFormat)
 {
-   const struct util_format_description *desc =
-         util_format_description(format);
-   unsigned swz;
-
-   if (desc->colorspace != UTIL_FORMAT_COLORSPACE_ZS ||
-       desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_NONE) {
-      /* Not a depth format. */
-      return swizzle;
-   }
-
-   switch (depthmode) {
+   switch (baseFormat) {
+   case GL_RGBA:
+      return SWIZZLE_XYZW;
+   case GL_RGB:
+      if (util_format_has_alpha(actualFormat))
+         return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_ONE);
+      else
+         return SWIZZLE_XYZW;
+   case GL_RG:
+      if (util_format_get_nr_components(actualFormat) > 2)
+         return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_ZERO, SWIZZLE_ONE);
+      else
+         return SWIZZLE_XYZW;
+   case GL_RED:
+      if (util_format_get_nr_components(actualFormat) > 1)
+         return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_ZERO,
+                              SWIZZLE_ZERO, SWIZZLE_ONE);
+      else
+         return SWIZZLE_XYZW;
+   case GL_ALPHA:
+      if (util_format_get_nr_components(actualFormat) > 1)
+         return MAKE_SWIZZLE4(SWIZZLE_ZERO, SWIZZLE_ZERO,
+                              SWIZZLE_ZERO, SWIZZLE_W);
+      else
+         return SWIZZLE_XYZW;
    case GL_LUMINANCE:
-      swz = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_ONE);
-      break;
+      if (util_format_get_nr_components(actualFormat) > 1)
+         return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_ONE);
+      else
+         return SWIZZLE_XYZW;
+   case GL_LUMINANCE_ALPHA:
+      if (util_format_get_nr_components(actualFormat) > 2)
+         return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_W);
+      else
+         return SWIZZLE_XYZW;
    case GL_INTENSITY:
-      swz = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_X);
-      break;
-   case GL_ALPHA:
-      swz = MAKE_SWIZZLE4(SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_X);
-      break;
-   case GL_RED:
-      swz = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ONE);
-      break;
+      if (util_format_get_nr_components(actualFormat) > 1)
+         return SWIZZLE_XXXX;
+      else
+         return SWIZZLE_XYZW;
+   case GL_STENCIL_INDEX:
+      return SWIZZLE_XYZW;
+   case GL_DEPTH_STENCIL:
+      /* fall-through */
+   case GL_DEPTH_COMPONENT:
+      /* Now examine the depth mode */
+      switch (depthMode) {
+      case GL_LUMINANCE:
+         return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_ONE);
+      case GL_INTENSITY:
+         return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_X);
+      case GL_ALPHA:
+         return MAKE_SWIZZLE4(SWIZZLE_ZERO, SWIZZLE_ZERO,
+                              SWIZZLE_ZERO, SWIZZLE_X);
+      case GL_RED:
+         return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_ZERO,
+                              SWIZZLE_ZERO, SWIZZLE_ONE);
+      default:
+         assert(!"Unexpected depthMode");
+         return SWIZZLE_XYZW;
+      }
+   default:
+      assert(!"Unexpected baseFormat");
+      return SWIZZLE_XYZW;
    }
-
-   return swizzle_swizzle(swizzle, swz);
 }
 
 
+static unsigned
+get_texture_format_swizzle(const struct st_texture_object *stObj)
+{
+   const struct gl_texture_image *texImage =
+      stObj->base.Image[0][stObj->base.BaseLevel];
+   unsigned tex_swizzle;
+
+   if (texImage) {
+      tex_swizzle = compute_texture_format_swizzle(texImage->_BaseFormat,
+                                                   stObj->base.DepthMode,
+                                                   stObj->pt->format);
+   }
+   else {
+      tex_swizzle = SWIZZLE_XYZW;
+   }
+
+   /* Combine the texture format swizzle with user's swizzle */
+   return swizzle_swizzle(stObj->base._Swizzle, tex_swizzle);
+}
+
+                            
 /**
- * Return TRUE if the swizzling described by "swizzle" and
- * "depthmode" (for depth textures only) is different from the swizzling
- * set in the given sampler view.
+ * Return TRUE if the texture's sampler view swizzle is equal to
+ * the texture's swizzle.
  *
- * \param sv         A sampler view.
- * \param swizzle    Texture swizzle, a bitmask computed using MAKE_SWIZZLE4.
- * \param depthmode  One of GL_LUMINANCE, GL_INTENSITY, GL_ALPHA.
+ * \param stObj  the st texture object,
  */
 static boolean
-check_sampler_swizzle(struct pipe_sampler_view *sv,
-                      GLuint swizzle, GLenum depthmode)
+check_sampler_swizzle(const struct st_texture_object *stObj)
 {
-   swizzle = apply_depthmode(sv->texture->format, swizzle, depthmode);
-
-   if ((sv->swizzle_r != GET_SWZ(swizzle, 0)) ||
-       (sv->swizzle_g != GET_SWZ(swizzle, 1)) ||
-       (sv->swizzle_b != GET_SWZ(swizzle, 2)) ||
-       (sv->swizzle_a != GET_SWZ(swizzle, 3)))
-      return TRUE;
-   return FALSE;
+   const struct pipe_sampler_view *sv = stObj->sampler_view;
+   unsigned swizzle = get_texture_format_swizzle(stObj);
+
+   return ((sv->swizzle_r != GET_SWZ(swizzle, 0)) ||
+           (sv->swizzle_g != GET_SWZ(swizzle, 1)) ||
+           (sv->swizzle_b != GET_SWZ(swizzle, 2)) ||
+           (sv->swizzle_a != GET_SWZ(swizzle, 3)));
 }
 
 
@@ -154,9 +219,7 @@ st_create_texture_sampler_view_from_stobj(struct pipe_context *pipe,
                                          enum pipe_format format)
 {
    struct pipe_sampler_view templ;
-   GLuint swizzle = apply_depthmode(stObj->pt->format,
-                                    stObj->base._Swizzle,
-                                    stObj->base.DepthMode);
+   unsigned swizzle = get_texture_format_swizzle(stObj);
 
    u_sampler_view_default_template(&templ,
                                    stObj->pt,
@@ -269,9 +332,7 @@ update_single_texture(struct st_context *st,
 
    /* if sampler view has changed dereference it */
    if (stObj->sampler_view) {
-      if (check_sampler_swizzle(stObj->sampler_view,
-                               stObj->base._Swizzle,
-                               stObj->base.DepthMode) ||
+      if (check_sampler_swizzle(stObj) ||
          (view_format != stObj->sampler_view->format) ||
          stObj->base.BaseLevel != stObj->sampler_view->u.tex.first_level) {
         pipe_sampler_view_release(pipe, &stObj->sampler_view);