iris: Properly support alpha and luminance-alpha formats
authorKenneth Graunke <kenneth@whitecape.org>
Fri, 22 Feb 2019 06:49:40 +0000 (22:49 -0800)
committerKenneth Graunke <kenneth@whitecape.org>
Thu, 7 Mar 2019 19:39:27 +0000 (11:39 -0800)
For texturing, we map alpha formats to the corresponding red format,
as many alpha formats are outright missing, and red is more efficient
when sampling anyway.

When rendering to A8_UNORM, we use that format directly, so the image
gets the shader output's .a/.w channel, rather than the .r/.x channel.

All other A* formats are non-renderable, so we can't do much and just
mark them as unsupported for rendering.  Fortunately, GL only requires
rendering to A8_UNORM, so that works out.

According to Andre Heider and Timur Kristóf, this fixes font rendering
in Witcher 1 (via nine).  Andre also reported that it fixes Unigine
Heaven (presumably via nine).

v2: Use the same swizzle for both sampler views and "render targets".
    BLORP expects the read swizzle, and will take the inverse when
    setting up the destination swizzle (and actually applying it in
    the shaders).  We ignore the format swizzle when setting up normal
    rendering SURFACE_STATEs, which is necessary because it would be
    an illegal shader channel select combination.  Thanks to Jason
    Ekstrand for pointing out that BLORP took an inverse swizzle.

Tested-by: Timur Kristóf <timur.kristof@gmail.com>
Tested-by: Andre Heider <a.heider@gmail.com>
Reviewed-by: Jason Ekstrand <jason@jlekstrand.net>
src/gallium/drivers/iris/iris_blit.c
src/gallium/drivers/iris/iris_clear.c
src/gallium/drivers/iris/iris_formats.c
src/gallium/drivers/iris/iris_state.c

index eb795a08cbe05758c7b4831a648f12ba1089567d..6562c7b60ec5b5eb5dcac3c8fb8cc33ba4230513 100644 (file)
@@ -406,7 +406,7 @@ iris_blit(struct pipe_context *ctx, const struct pipe_blit_info *info)
                     &src_surf, info->src.level, info->src.box.z + slice,
                     src_fmt.fmt, src_fmt.swizzle,
                     &dst_surf, info->dst.level, info->dst.box.z + slice,
-                    dst_fmt.fmt, ISL_SWIZZLE_IDENTITY,
+                    dst_fmt.fmt, dst_fmt.swizzle,
                     src_x0, src_y0, src_x1, src_y1,
                     dst_x0, dst_y0, dst_x1, dst_y1,
                     filter, mirror_x, mirror_y);
index e71d7f450bd1093460260534340277ebc3ce46f9..817087f496693886dc9dcd0531c3d89b4a3eb265 100644 (file)
@@ -42,6 +42,7 @@ clear_color(struct iris_context *ice,
             const struct pipe_box *box,
             bool render_condition_enabled,
             enum isl_format format,
+            struct isl_swizzle swizzle,
             union isl_color_value color)
 {
    struct iris_resource *res = (void *) p_res;
@@ -79,7 +80,7 @@ clear_color(struct iris_context *ice,
        isl_format_is_rgbx(format))
       format = isl_format_rgbx_to_rgba(format);
 
-   blorp_clear(&blorp_batch, &surf, format, ISL_SWIZZLE_IDENTITY,
+   blorp_clear(&blorp_batch, &surf, format, swizzle,
                level, box->z, box->depth, box->x, box->y,
                box->x + box->width, box->y + box->height,
                color, color_write_disable);
@@ -205,7 +206,8 @@ iris_clear(struct pipe_context *ctx,
             };
 
             clear_color(ice, psurf->texture, psurf->u.tex.level, &box,
-                        true, isurf->view.format, *color);
+                        true, isurf->view.format, isurf->view.swizzle,
+                        *color);
          }
       }
    }
@@ -270,7 +272,8 @@ iris_clear_texture(struct pipe_context *ctx,
 
       isl_color_value_unpack(&color, format, data);
 
-      clear_color(ice, p_res, level, box, true, format, color);
+      clear_color(ice, p_res, level, box, true, format,
+                  ISL_SWIZZLE_IDENTITY, color);
    }
 }
 
@@ -303,7 +306,7 @@ iris_clear_render_target(struct pipe_context *ctx,
 
    clear_color(ice, psurf->texture, psurf->u.tex.level, &box,
                render_condition_enabled,
-               isurf->view.format, *color);
+               isurf->view.format, isurf->view.swizzle, *color);
 }
 
 /**
index c160d19f4eac5d960c75ea3898b3223bdf3bbc00..91c86efca4df6cbebbb6b4a024156c41b37f50a5 100644 (file)
@@ -153,26 +153,8 @@ iris_isl_format_for_pipe_format(enum pipe_format pf)
       [PIPE_FORMAT_B10G10R10A2_UNORM]       = ISL_FORMAT_B10G10R10A2_UNORM,
       [PIPE_FORMAT_R8G8B8X8_UNORM]          = ISL_FORMAT_R8G8B8X8_UNORM,
 
-#if 0
-      /* Leave these disabled for now, we'd need border color hacks and
-       * we don't currently have the surface format in that code...
-       */
-      //[PIPE_FORMAT_A8_UINT]                 = ISL_FORMAT_A8_UINT,
-      //[PIPE_FORMAT_A8_SINT]                 = ISL_FORMAT_A8_SINT,
-      //[PIPE_FORMAT_A8_SNORM]                = ISL_FORMAT_A8_SNORM,
-      //[PIPE_FORMAT_A16_UINT]                = ISL_FORMAT_A16_UINT,
-      //[PIPE_FORMAT_A16_SINT]                = ISL_FORMAT_A16_SINT,
-      //[PIPE_FORMAT_A16_SNORM]               = ISL_FORMAT_A16_SNORM,
-      [PIPE_FORMAT_A16_FLOAT]               = ISL_FORMAT_A16_FLOAT,
-      //[PIPE_FORMAT_A32_UINT]                = ISL_FORMAT_A32_UINT,
-      //[PIPE_FORMAT_A32_SINT]                = ISL_FORMAT_A32_SINT,
-      [PIPE_FORMAT_A32_FLOAT]               = ISL_FORMAT_A32_FLOAT,
-#endif
-      [PIPE_FORMAT_A8_UNORM]                = ISL_FORMAT_A8_UNORM,
-      [PIPE_FORMAT_A16_UNORM]               = ISL_FORMAT_A16_UNORM,
-
       /* Just use red formats for these - they're actually renderable,
-       * and faster to sample than the legacy L/I formats.
+       * and faster to sample than the legacy L/I/A/LA formats.
        */
       [PIPE_FORMAT_I8_UNORM]                = ISL_FORMAT_R8_UNORM,
       [PIPE_FORMAT_I8_UINT]                 = ISL_FORMAT_R8_UINT,
@@ -200,26 +182,38 @@ iris_isl_format_for_pipe_format(enum pipe_format pf)
       [PIPE_FORMAT_L32_SINT]                = ISL_FORMAT_R32_SINT,
       [PIPE_FORMAT_L32_FLOAT]               = ISL_FORMAT_R32_FLOAT,
 
-      /* Sadly, there is no R8_SRGB format so we have to use luminance. */
+      /* We also map alpha and luminance-alpha formats to red as well,
+       * though most of these (other than A8_UNORM) will be non-renderable.
+       */
+      [PIPE_FORMAT_A8_UINT]                 = ISL_FORMAT_R8_UINT,
+      [PIPE_FORMAT_A8_UNORM]                = ISL_FORMAT_R8_UNORM,
+      [PIPE_FORMAT_A8_SINT]                 = ISL_FORMAT_R8_SINT,
+      [PIPE_FORMAT_A8_SNORM]                = ISL_FORMAT_R8_SNORM,
+      [PIPE_FORMAT_A16_UINT]                = ISL_FORMAT_R16_UINT,
+      [PIPE_FORMAT_A16_UNORM]               = ISL_FORMAT_R16_UNORM,
+      [PIPE_FORMAT_A16_SINT]                = ISL_FORMAT_R16_SINT,
+      [PIPE_FORMAT_A16_SNORM]               = ISL_FORMAT_R16_SNORM,
+      [PIPE_FORMAT_A16_FLOAT]               = ISL_FORMAT_R16_FLOAT,
+      [PIPE_FORMAT_A32_UINT]                = ISL_FORMAT_R32_UINT,
+      [PIPE_FORMAT_A32_SINT]                = ISL_FORMAT_R32_SINT,
+      [PIPE_FORMAT_A32_FLOAT]               = ISL_FORMAT_R32_FLOAT,
+
+      [PIPE_FORMAT_L8A8_UINT]               = ISL_FORMAT_R8G8_UINT,
+      [PIPE_FORMAT_L8A8_UNORM]              = ISL_FORMAT_R8G8_UNORM,
+      [PIPE_FORMAT_L8A8_SINT]               = ISL_FORMAT_R8G8_SINT,
+      [PIPE_FORMAT_L8A8_SNORM]              = ISL_FORMAT_R8G8_SNORM,
+      [PIPE_FORMAT_L16A16_UINT]             = ISL_FORMAT_R16G16_UINT,
+      [PIPE_FORMAT_L16A16_UNORM]            = ISL_FORMAT_R16G16_UNORM,
+      [PIPE_FORMAT_L16A16_SINT]             = ISL_FORMAT_R16G16_SINT,
+      [PIPE_FORMAT_L16A16_SNORM]            = ISL_FORMAT_R16G16_SNORM,
+      [PIPE_FORMAT_L16A16_FLOAT]            = ISL_FORMAT_R16G16_FLOAT,
+      [PIPE_FORMAT_L32A32_UINT]             = ISL_FORMAT_R32G32_UINT,
+      [PIPE_FORMAT_L32A32_SINT]             = ISL_FORMAT_R32G32_SINT,
+      [PIPE_FORMAT_L32A32_FLOAT]            = ISL_FORMAT_R32G32_FLOAT,
+
+      /* Sadly, we have to use luminance[-alpha] formats for sRGB decoding. */
       [PIPE_FORMAT_L8_SRGB]                 = ISL_FORMAT_L8_UNORM_SRGB,
-
-#if 0
-      /* Just fake these with RGBA at a higher level for now */
-      [PIPE_FORMAT_L8A8_UINT]               = ISL_FORMAT_L8A8_UINT,
-      [PIPE_FORMAT_L8A8_UNORM]              = ISL_FORMAT_L8A8_UNORM,
-      [PIPE_FORMAT_L8A8_SINT]               = ISL_FORMAT_L8A8_SINT,
-      //[PIPE_FORMAT_L8A8_SNORM]              = ISL_FORMAT_L8A8_SNORM,
-      //[PIPE_FORMAT_L16A16_UINT]             = ISL_FORMAT_L16A16_UINT,
-      [PIPE_FORMAT_L16A16_UNORM]            = ISL_FORMAT_L16A16_UNORM,
-      //[PIPE_FORMAT_L16A16_SINT]             = ISL_FORMAT_L16A16_SINT,
-      //[PIPE_FORMAT_L16A16_SNORM]            = ISL_FORMAT_L16A16_SNORM,
-      [PIPE_FORMAT_L16A16_FLOAT]            = ISL_FORMAT_L16A16_FLOAT,
-      //[PIPE_FORMAT_L32A32_UINT]             = ISL_FORMAT_L32A32_UINT,
-      //[PIPE_FORMAT_L32A32_SINT]             = ISL_FORMAT_L32A32_SINT,
-      [PIPE_FORMAT_L32A32_FLOAT]            = ISL_FORMAT_L32A32_FLOAT,
-
       [PIPE_FORMAT_L8A8_SRGB]               = ISL_FORMAT_L8A8_UNORM_SRGB,
-#endif
 
       [PIPE_FORMAT_R10G10B10A2_SSCALED]     = ISL_FORMAT_R10G10B10A2_SSCALED,
       [PIPE_FORMAT_R10G10B10A2_SNORM]       = ISL_FORMAT_R10G10B10A2_SNORM,
@@ -325,57 +319,45 @@ iris_isl_format_for_pipe_format(enum pipe_format pf)
    return table[pf];
 }
 
-// XXX: use RED for ALPHA textures
-UNUSED static enum pipe_format
-alpha_to_red(enum pipe_format pf)
-{
-   switch (pf) {
-   case PIPE_FORMAT_A8_UNORM:  return PIPE_FORMAT_R8_UNORM;
-   case PIPE_FORMAT_A16_UNORM: return PIPE_FORMAT_R16_UNORM;
-   case PIPE_FORMAT_A8_SNORM:  return PIPE_FORMAT_R8_SNORM;
-   case PIPE_FORMAT_A16_SNORM: return PIPE_FORMAT_R16_SNORM;
-   case PIPE_FORMAT_A16_FLOAT: return PIPE_FORMAT_R16_FLOAT;
-   case PIPE_FORMAT_A32_FLOAT: return PIPE_FORMAT_R32_FLOAT;
-   case PIPE_FORMAT_A8_UINT:   return PIPE_FORMAT_A8_UINT;
-   case PIPE_FORMAT_A8_SINT:   return PIPE_FORMAT_A8_SINT;
-   case PIPE_FORMAT_A16_UINT:  return PIPE_FORMAT_R16_UINT;
-   case PIPE_FORMAT_A16_SINT:  return PIPE_FORMAT_R16_SINT;
-   case PIPE_FORMAT_A32_UINT:  return PIPE_FORMAT_R32_UINT;
-   case PIPE_FORMAT_A32_SINT:  return PIPE_FORMAT_R32_SINT;
-   default:                    return pf;
-   }
-}
-
 struct iris_format_info
 iris_format_for_usage(const struct gen_device_info *devinfo,
                       enum pipe_format pformat,
                       isl_surf_usage_flags_t usage)
 {
+   enum isl_format format = iris_isl_format_for_pipe_format(pformat);
    struct isl_swizzle swizzle = ISL_SWIZZLE_IDENTITY;
 
-   if (usage & ISL_SURF_USAGE_TEXTURE_BIT) {
-      if (!util_format_is_srgb(pformat)) {
-         if (util_format_is_intensity(pformat)) {
-            swizzle = ISL_SWIZZLE(RED, RED, RED, RED);
-         } else if (util_format_is_luminance(pformat)) {
-            swizzle = ISL_SWIZZLE(RED, RED, RED, ONE);
-         //} else if (util_format_is_alpha(pformat)) {
-            //pformat = alpha_to_red(pformat);
-            //swizzle = ISL_SWIZZLE(ZERO, ZERO, ZERO, RED);
-         }
+   if (!util_format_is_srgb(pformat)) {
+      if (util_format_is_intensity(pformat)) {
+         swizzle = ISL_SWIZZLE(RED, RED, RED, RED);
+      } else if (util_format_is_luminance(pformat)) {
+         swizzle = ISL_SWIZZLE(RED, RED, RED, ONE);
+      } else if (util_format_is_luminance_alpha(pformat)) {
+         swizzle = ISL_SWIZZLE(RED, RED, RED, GREEN);
+      } else if (util_format_is_alpha(pformat)) {
+         swizzle = ISL_SWIZZLE(ZERO, ZERO, ZERO, RED);
       }
-      if (pformat == PIPE_FORMAT_DXT1_RGB ||
-          pformat == PIPE_FORMAT_DXT1_SRGB)
-         swizzle = ISL_SWIZZLE(RED, GREEN, BLUE, ONE);
    }
 
-   enum isl_format format = iris_isl_format_for_pipe_format(pformat);
+   if (pformat == PIPE_FORMAT_DXT1_RGB ||
+       pformat == PIPE_FORMAT_DXT1_SRGB) {
+      swizzle = ISL_SWIZZLE(RED, GREEN, BLUE, ONE);
+   }
 
-   /* Convert RGBX into RGBA for rendering */
-   if (isl_format_is_rgbx(format) &&
-       (usage & ISL_SURF_USAGE_RENDER_TARGET_BIT) &&
-       !isl_format_supports_rendering(devinfo, format)) {
-      format = isl_format_rgbx_to_rgba(format);
+   if (usage & ISL_SURF_USAGE_RENDER_TARGET_BIT) {
+      if (isl_format_is_rgbx(format) &&
+          !isl_format_supports_rendering(devinfo, format)) {
+         format = isl_format_rgbx_to_rgba(format);
+      } else if (pformat == PIPE_FORMAT_A8_UNORM) {
+         /* Most of the hardware A/LA formats are not renderable, except
+          * for A8_UNORM.  SURFACE_STATE's shader channel select fields
+          * cannot be used to swap RGB and A channels when rendering (as
+          * it could impact alpha blending), so we have to use the actual
+          * A8_UNORM format when rendering.
+          */
+         format = ISL_FORMAT_A8_UNORM;
+         swizzle = ISL_SWIZZLE_IDENTITY;
+      }
    }
 
    return (struct iris_format_info) { .fmt = format, .swizzle = swizzle };
@@ -427,6 +409,24 @@ iris_is_format_supported(struct pipe_screen *pscreen,
    }
 
    if (usage & PIPE_BIND_RENDER_TARGET) {
+      /* Alpha and luminance-alpha formats other than A8_UNORM are not
+       * renderable.  For texturing, we can use R or RG formats with
+       * shader channel selects (SCS) to swizzle the data into the correct
+       * channels.  But for render targets, the hardware prohibits using
+       * SCS to move shader outputs between the RGB and A channels, as it
+       * would alter what data is used for alpha blending.
+       *
+       * For BLORP, we can apply the swizzle in the shader.  But for
+       * general rendering, this would mean recompiling the shader, which
+       * we'd like to avoid doing.  So we mark these formats non-renderable.
+       *
+       * We do support A8_UNORM as it's required and is renderable.
+       */
+      if (pformat != PIPE_FORMAT_A8_UNORM &&
+          (util_format_is_alpha(pformat) ||
+           util_format_is_luminance_alpha(pformat)))
+         supported = false;
+
       enum isl_format rt_format = format;
 
       if (isl_format_is_rgbx(format) &&
index 0483bb8caa0f33da27b5b079b40fb55db862c126..f8d23dd784b67f4c6b9865152d566556daa0d5b9 100644 (file)
@@ -1498,6 +1498,7 @@ iris_upload_sampler_states(struct iris_context *ice, gl_shader_stage stage)
 
    for (int i = 0; i < count; i++) {
       struct iris_sampler_state *state = shs->samplers[i];
+      struct iris_sampler_view *tex = shs->textures[i];
 
       if (!state) {
          memset(map, 0, 4 * GENX(SAMPLER_STATE_length));
@@ -1506,9 +1507,37 @@ iris_upload_sampler_states(struct iris_context *ice, gl_shader_stage stage)
       } else {
          ice->state.need_border_colors |= 1 << stage;
 
+         /* We may need to swizzle the border color for format faking.
+          * A/LA formats are faked as R/RG with 000R or R00G swizzles.
+          * This means we need to move the border color's A channel into
+          * the R or G channels so that those read swizzles will move it
+          * back into A.
+          */
+         union pipe_color_union *color = &state->border_color;
+         if (tex) {
+            union pipe_color_union tmp;
+            enum pipe_format internal_format = tex->res->internal_format;
+
+            if (util_format_is_alpha(internal_format)) {
+               unsigned char swz[4] = {
+                  PIPE_SWIZZLE_W, PIPE_SWIZZLE_0,
+                  PIPE_SWIZZLE_0, PIPE_SWIZZLE_0
+               };
+               util_format_apply_color_swizzle(&tmp, color, swz, true);
+               color = &tmp;
+            } else if (util_format_is_luminance_alpha(internal_format) &&
+                       internal_format != PIPE_FORMAT_L8A8_SRGB) {
+               unsigned char swz[4] = {
+                  PIPE_SWIZZLE_X, PIPE_SWIZZLE_W,
+                  PIPE_SWIZZLE_0, PIPE_SWIZZLE_0
+               };
+               util_format_apply_color_swizzle(&tmp, color, swz, true);
+               color = &tmp;
+            }
+         }
+
          /* Stream out the border color and merge the pointer. */
-         uint32_t offset =
-            iris_upload_border_color(ice, &state->border_color);
+         uint32_t offset = iris_upload_border_color(ice, color);
 
          uint32_t dynamic[GENX(SAMPLER_STATE_length)];
          iris_pack_state(GENX(SAMPLER_STATE), dynamic, dyns) {
@@ -1709,7 +1738,7 @@ iris_create_sampler_view(struct pipe_context *ctx,
       }
    } else {
       fill_buffer_surface_state(&screen->isl_dev, isv->res->bo, map,
-                                isv->view.format, ISL_SWIZZLE_IDENTITY,
+                                isv->view.format, isv->view.swizzle,
                                 tmpl->u.buf.offset, tmpl->u.buf.size);
    }