mesa: track format swizzles on teximage objects
authorMike Blumenkrantz <michael.blumenkrantz@gmail.com>
Mon, 1 Aug 2022 14:00:01 +0000 (10:00 -0400)
committerMarge Bot <emma+marge@anholt.net>
Fri, 12 Aug 2022 14:24:52 +0000 (14:24 +0000)
this will only very rarely change, so stop calculating it during sampler update

Reviewed-by: Marek Olšák <marek.olsak@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/17687>

src/mesa/main/mtypes.h
src/mesa/main/teximage.c
src/mesa/main/teximage.h
src/mesa/main/texparam.c

index eea350f..85c6f1c 100644 (file)
@@ -789,6 +789,9 @@ struct gl_texture_image
    /** Cube map face: index into gl_texture_object::Image[] array */
    GLuint Face;
 
+   unsigned FormatSwizzle;
+   unsigned FormatSwizzleGLSL130; //for depth formats
+
    /** GL_ARB_texture_multisample */
    GLuint NumSamples;            /**< Sample count, or 0 for non-multisample */
    GLboolean FixedSampleLocations; /**< Same sample locations for all pixels? */
index b9f2e88..90ba413 100644 (file)
@@ -60,6 +60,8 @@
 
 #include "util/u_memory.h"
 
+#include "program/prog_instruction.h"
+
 #include "state_tracker/st_cb_texture.h"
 #include "state_tracker/st_context.h"
 #include "state_tracker/st_format.h"
@@ -803,6 +805,100 @@ clear_teximage_fields(struct gl_texture_image *img)
    img->FixedSampleLocations = GL_TRUE;
 }
 
+/**
+ * Given a user-specified texture base format, the actual gallium texture
+ * format and the current GL_DEPTH_MODE, return a texture swizzle.
+ *
+ * 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 unsigned
+compute_texture_format_swizzle(GLenum baseFormat, GLenum depthMode,
+                                     bool glsl130_or_later)
+{
+   switch (baseFormat) {
+   case GL_RGBA:
+      return SWIZZLE_XYZW;
+   case GL_RGB:
+      return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_ONE);
+   case GL_RG:
+      return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_ZERO, SWIZZLE_ONE);
+   case GL_RED:
+      return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_ZERO,
+                           SWIZZLE_ZERO, SWIZZLE_ONE);
+   case GL_ALPHA:
+      return MAKE_SWIZZLE4(SWIZZLE_ZERO, SWIZZLE_ZERO,
+                           SWIZZLE_ZERO, SWIZZLE_W);
+   case GL_LUMINANCE:
+      return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_ONE);
+   case GL_LUMINANCE_ALPHA:
+      return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_W);
+   case GL_INTENSITY:
+      return SWIZZLE_XXXX;
+   case GL_STENCIL_INDEX:
+   case GL_DEPTH_STENCIL:
+   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:
+         /* The texture(sampler*Shadow) functions from GLSL 1.30 ignore
+          * the depth mode and return float, while older shadow* functions
+          * and ARB_fp instructions return vec4 according to the depth mode.
+          *
+          * The problem with the GLSL 1.30 functions is that GL_ALPHA forces
+          * them to return 0, breaking them completely.
+          *
+          * A proper fix would increase code complexity and that's not worth
+          * it for a rarely used feature such as the GL_ALPHA depth mode
+          * in GL3. Therefore, change GL_ALPHA to GL_INTENSITY for all
+          * shaders that use GLSL 1.30 or later.
+          *
+          * BTW, it's required that sampler views are updated when
+          * shaders change (check_sampler_swizzle takes care of that).
+          */
+         if (glsl130_or_later)
+            return SWIZZLE_XXXX;
+         else
+            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;
+   }
+}
+
+void
+_mesa_update_teximage_format_swizzle(struct gl_context *ctx,
+                                     struct gl_texture_image *img,
+                                     GLenum depth_mode)
+{
+   if (!img)
+      return;
+   img->FormatSwizzle = compute_texture_format_swizzle(img->_BaseFormat, depth_mode, false);
+   img->FormatSwizzleGLSL130 = compute_texture_format_swizzle(img->_BaseFormat, depth_mode, true);
+}
 
 /**
  * Initialize basic fields of the gl_texture_image struct.
@@ -845,6 +941,22 @@ _mesa_init_teximage_fields_ms(struct gl_context *ctx,
    img->Height = height;
    img->Depth = depth;
 
+   GLenum depth_mode = ctx->API == API_OPENGL_CORE ? GL_RED : GL_LUMINANCE;
+
+   /* In ES 3.0, DEPTH_TEXTURE_MODE is expected to be GL_RED for textures
+    * with depth component data specified with a sized internal format.
+    */
+   if (_mesa_is_gles3(ctx) &&
+       (base_format == GL_DEPTH_COMPONENT ||
+        base_format == GL_DEPTH_STENCIL ||
+        base_format == GL_STENCIL_INDEX)) {
+      if (internalFormat != GL_DEPTH_COMPONENT &&
+          internalFormat != GL_DEPTH_STENCIL &&
+          internalFormat != GL_STENCIL_INDEX)
+         depth_mode = GL_RED;
+   }
+   _mesa_update_teximage_format_swizzle(ctx, img, depth_mode);
+
    img->Width2 = width - 2 * border;   /* == 1 << img->WidthLog2; */
    img->WidthLog2 = util_logbase2(img->Width2);
 
@@ -3172,6 +3284,10 @@ teximage(struct gl_context *ctx, GLboolean compressed, GLuint dims,
             _mesa_update_fbo_texture(ctx, texObj, face, level);
 
             _mesa_dirty_texobj(ctx, texObj);
+            /* only apply depthMode swizzle if it was explicitly changed */
+            GLenum depth_mode = ctx->API == API_OPENGL_CORE ? GL_RED : GL_LUMINANCE;
+            if (texObj->Attrib.DepthMode != depth_mode)
+               _mesa_update_teximage_format_swizzle(ctx, texObj->Image[0][texObj->Attrib.BaseLevel], texObj->Attrib.DepthMode);
          }
       }
       _mesa_unlock_texture(ctx, texObj);
index da8721d..12ba82a 100644 (file)
@@ -139,7 +139,10 @@ _mesa_init_teximage_fields_ms(struct gl_context *ctx,
                               GLuint numSamples,
                               GLboolean fixedSampleLocations);
 
-
+void
+_mesa_update_teximage_format_swizzle(struct gl_context *ctx,
+                                     struct gl_texture_image *img,
+                                     GLenum depth_mode);
 extern mesa_format
 _mesa_choose_texture_format(struct gl_context *ctx,
                             struct gl_texture_object *texObj,
index fd84515..7799ba9 100644 (file)
@@ -415,6 +415,8 @@ set_tex_parameteri(struct gl_context *ctx,
          texObj->Attrib.BaseLevel = MIN2(texObj->Attrib.ImmutableLevels - 1, params[0]);
       else
          texObj->Attrib.BaseLevel = params[0];
+      if (texObj->Attrib.BaseLevel < MAX_TEXTURE_LEVELS)
+         _mesa_update_teximage_format_swizzle(ctx, texObj->Image[0][texObj->Attrib.BaseLevel], texObj->Attrib.DepthMode);
 
       return GL_TRUE;
 
@@ -518,6 +520,8 @@ set_tex_parameteri(struct gl_context *ctx,
              (ctx->Extensions.ARB_texture_rg && params[0] == GL_RED)) {
             flush(ctx);
             texObj->Attrib.DepthMode = params[0];
+            if (texObj->Attrib.BaseLevel < MAX_TEXTURE_LEVELS)
+               _mesa_update_teximage_format_swizzle(ctx, texObj->Image[0][texObj->Attrib.BaseLevel], texObj->Attrib.DepthMode);
             return GL_TRUE;
          }
          goto invalid_param;