From 809a81ec3a0b8666ec426a88b86fb133ae5f1bcb Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Thu, 21 Feb 2019 22:49:40 -0800 Subject: [PATCH] iris: Properly support alpha and luminance-alpha formats MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 Tested-by: Andre Heider Reviewed-by: Jason Ekstrand --- src/gallium/drivers/iris/iris_blit.c | 2 +- src/gallium/drivers/iris/iris_clear.c | 11 +- src/gallium/drivers/iris/iris_formats.c | 154 ++++++++++++------------ src/gallium/drivers/iris/iris_state.c | 35 +++++- 4 files changed, 117 insertions(+), 85 deletions(-) diff --git a/src/gallium/drivers/iris/iris_blit.c b/src/gallium/drivers/iris/iris_blit.c index eb795a08cbe..6562c7b60ec 100644 --- a/src/gallium/drivers/iris/iris_blit.c +++ b/src/gallium/drivers/iris/iris_blit.c @@ -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); diff --git a/src/gallium/drivers/iris/iris_clear.c b/src/gallium/drivers/iris/iris_clear.c index e71d7f450bd..817087f4966 100644 --- a/src/gallium/drivers/iris/iris_clear.c +++ b/src/gallium/drivers/iris/iris_clear.c @@ -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); } /** diff --git a/src/gallium/drivers/iris/iris_formats.c b/src/gallium/drivers/iris/iris_formats.c index c160d19f4ea..91c86efca4d 100644 --- a/src/gallium/drivers/iris/iris_formats.c +++ b/src/gallium/drivers/iris/iris_formats.c @@ -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) && diff --git a/src/gallium/drivers/iris/iris_state.c b/src/gallium/drivers/iris/iris_state.c index 0483bb8caa0..f8d23dd784b 100644 --- a/src/gallium/drivers/iris/iris_state.c +++ b/src/gallium/drivers/iris/iris_state.c @@ -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); } -- 2.30.2