From 3817a7a1d7434ae5ae069599013cea81cf809aa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolai=20H=C3=A4hnle?= Date: Mon, 7 Nov 2016 15:55:52 +0100 Subject: [PATCH] util/blitter: add clamping during SINT <-> UINT blits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Even though glBlitFramebuffer cannot be used for SINT <-> UINT blits, we still need to handle this type of blit here because it can happen as part of texture uploads / downloads, e.g. uploading a GL_RGBA8I texture from GL_UNSIGNED_INT data. Fixes parts of GL45-CTS.gtf32.GL3Tests.packed_pixels.packed_pixels. Reviewed-by: Marek Olšák Reviewed-by: Edward O'Callaghan --- src/gallium/auxiliary/util/u_blit.c | 4 +- src/gallium/auxiliary/util/u_blitter.c | 73 ++++++++++++----- src/gallium/auxiliary/util/u_simple_shaders.c | 80 ++++++++++++++----- src/gallium/auxiliary/util/u_simple_shaders.h | 9 ++- src/gallium/auxiliary/util/u_tests.c | 1 + src/gallium/tests/trivial/quad-tex.c | 1 + 6 files changed, 125 insertions(+), 43 deletions(-) diff --git a/src/gallium/auxiliary/util/u_blit.c b/src/gallium/auxiliary/util/u_blit.c index fbc9c77dfcc..6d8178ee561 100644 --- a/src/gallium/auxiliary/util/u_blit.c +++ b/src/gallium/auxiliary/util/u_blit.c @@ -180,11 +180,13 @@ set_fragment_shader(struct blit_state *ctx, uint writemask, if (!ctx->fs[pipe_tex][writemask][idx]) { unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(pipe_tex, 0); + /* OpenGL does not allow blits from signed to unsigned integer + * or vice versa. */ ctx->fs[pipe_tex][writemask][idx] = util_make_fragment_tex_shader_writemask(ctx->pipe, tgsi_tex, TGSI_INTERPOLATE_LINEAR, writemask, - stype); + stype, stype); } cso_set_fragment_shader_handle(ctx->cso, ctx->fs[pipe_tex][writemask][idx]); diff --git a/src/gallium/auxiliary/util/u_blitter.c b/src/gallium/auxiliary/util/u_blitter.c index eb3a97d3d48..98b54213c09 100644 --- a/src/gallium/auxiliary/util/u_blitter.c +++ b/src/gallium/auxiliary/util/u_blitter.c @@ -78,9 +78,10 @@ struct blitter_context_priv void *fs_write_one_cbuf; void *fs_write_all_cbufs; - /* FS which outputs a color from a texture, - where the index is PIPE_TEXTURE_* to be sampled. */ - void *fs_texfetch_col[3][PIPE_MAX_TEXTURE_TYPES]; + /* FS which outputs a color from a texture. + * The first index indicates the texture type / destination type, + * the second index is the PIPE_TEXTURE_* to be sampled. */ + void *fs_texfetch_col[5][PIPE_MAX_TEXTURE_TYPES]; /* FS which outputs a depth from a texture, where the index is PIPE_TEXTURE_* to be sampled. */ @@ -89,7 +90,7 @@ struct blitter_context_priv void *fs_texfetch_stencil[PIPE_MAX_TEXTURE_TYPES]; /* FS which outputs one sample from a multisample texture. */ - void *fs_texfetch_col_msaa[3][PIPE_MAX_TEXTURE_TYPES]; + void *fs_texfetch_col_msaa[5][PIPE_MAX_TEXTURE_TYPES]; void *fs_texfetch_depth_msaa[PIPE_MAX_TEXTURE_TYPES]; void *fs_texfetch_depthstencil_msaa[PIPE_MAX_TEXTURE_TYPES]; void *fs_texfetch_stencil_msaa[PIPE_MAX_TEXTURE_TYPES]; @@ -863,7 +864,8 @@ static void blitter_set_dst_dimensions(struct blitter_context_priv *ctx, } static void *blitter_get_fs_texfetch_col(struct blitter_context_priv *ctx, - enum pipe_format format, + enum pipe_format src_format, + enum pipe_format dst_format, enum pipe_texture_target target, unsigned src_nr_samples, unsigned dst_nr_samples, @@ -872,19 +874,36 @@ static void *blitter_get_fs_texfetch_col(struct blitter_context_priv *ctx, struct pipe_context *pipe = ctx->base.pipe; unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(target, src_nr_samples); enum tgsi_return_type stype; + enum tgsi_return_type dtype; unsigned type; assert(target < PIPE_MAX_TEXTURE_TYPES); - if (util_format_is_pure_uint(format)) { + if (util_format_is_pure_uint(src_format)) { stype = TGSI_RETURN_TYPE_UINT; - type = 0; - } else if (util_format_is_pure_sint(format)) { + if (util_format_is_pure_uint(dst_format)) { + dtype = TGSI_RETURN_TYPE_UINT; + type = 0; + } else { + assert(util_format_is_pure_sint(dst_format)); + dtype = TGSI_RETURN_TYPE_SINT; + type = 1; + } + } else if (util_format_is_pure_sint(src_format)) { stype = TGSI_RETURN_TYPE_SINT; - type = 1; + if (util_format_is_pure_sint(dst_format)) { + dtype = TGSI_RETURN_TYPE_SINT; + type = 2; + } else { + assert(util_format_is_pure_uint(dst_format)); + dtype = TGSI_RETURN_TYPE_UINT; + type = 3; + } } else { - stype = TGSI_RETURN_TYPE_FLOAT; - type = 2; + assert(!util_format_is_pure_uint(dst_format) && + !util_format_is_pure_sint(dst_format)); + dtype = stype = TGSI_RETURN_TYPE_FLOAT; + type = 4; } if (src_nr_samples > 1) { @@ -926,7 +945,7 @@ static void *blitter_get_fs_texfetch_col(struct blitter_context_priv *ctx, /* Create the fragment shader on-demand. */ if (!*shader) { assert(!ctx->cached_all_shaders); - *shader = util_make_fs_blit_msaa_color(pipe, tgsi_tex, stype); + *shader = util_make_fs_blit_msaa_color(pipe, tgsi_tex, stype, dtype); } } @@ -939,7 +958,7 @@ static void *blitter_get_fs_texfetch_col(struct blitter_context_priv *ctx, assert(!ctx->cached_all_shaders); *shader = util_make_fragment_tex_shader(pipe, tgsi_tex, TGSI_INTERPOLATE_LINEAR, - stype); + stype, dtype); } return *shader; @@ -1101,11 +1120,20 @@ void util_blitter_cache_all_shaders(struct blitter_context *blitter) /* If samples == 1, the shaders read one texel. If samples >= 1, * they read one sample. */ - blitter_get_fs_texfetch_col(ctx, PIPE_FORMAT_R32_FLOAT, target, + blitter_get_fs_texfetch_col(ctx, PIPE_FORMAT_R32_FLOAT, + PIPE_FORMAT_R32_FLOAT, target, samples, samples, 0); - blitter_get_fs_texfetch_col(ctx, PIPE_FORMAT_R32_UINT, target, + blitter_get_fs_texfetch_col(ctx, PIPE_FORMAT_R32_UINT, + PIPE_FORMAT_R32_UINT, target, samples, samples, 0); - blitter_get_fs_texfetch_col(ctx, PIPE_FORMAT_R32_SINT, target, + blitter_get_fs_texfetch_col(ctx, PIPE_FORMAT_R32_UINT, + PIPE_FORMAT_R32_SINT, target, + samples, samples, 0); + blitter_get_fs_texfetch_col(ctx, PIPE_FORMAT_R32_SINT, + PIPE_FORMAT_R32_SINT, target, + samples, samples, 0); + blitter_get_fs_texfetch_col(ctx, PIPE_FORMAT_R32_SINT, + PIPE_FORMAT_R32_UINT, target, samples, samples, 0); blitter_get_fs_texfetch_depth(ctx, target, samples); if (ctx->has_stencil_export) { @@ -1125,11 +1153,14 @@ void util_blitter_cache_all_shaders(struct blitter_context *blitter) } for (f = 0; f < 2; f++) { - blitter_get_fs_texfetch_col(ctx, PIPE_FORMAT_R32_FLOAT, target, + blitter_get_fs_texfetch_col(ctx, PIPE_FORMAT_R32_FLOAT, + PIPE_FORMAT_R32_FLOAT, target, j, 1, f); - blitter_get_fs_texfetch_col(ctx, PIPE_FORMAT_R32_UINT, target, + blitter_get_fs_texfetch_col(ctx, PIPE_FORMAT_R32_UINT, + PIPE_FORMAT_R32_UINT, target, j, 1, f); - blitter_get_fs_texfetch_col(ctx, PIPE_FORMAT_R32_SINT, target, + blitter_get_fs_texfetch_col(ctx, PIPE_FORMAT_R32_SINT, + PIPE_FORMAT_R32_SINT, target, j, 1, f); } } @@ -1723,7 +1754,7 @@ void util_blitter_blit_generic(struct blitter_context *blitter, pipe->bind_blend_state(pipe, ctx->blend[colormask][alpha_blend]); pipe->bind_depth_stencil_alpha_state(pipe, ctx->dsa_keep_depth_stencil); ctx->bind_fs_state(pipe, - blitter_get_fs_texfetch_col(ctx, src->format, src_target, + blitter_get_fs_texfetch_col(ctx, src->format, dst->format, src_target, src_samples, dst_samples, filter)); } @@ -1876,7 +1907,7 @@ void util_blitter_generate_mipmap(struct blitter_context *blitter, pipe->bind_blend_state(pipe, ctx->blend[PIPE_MASK_RGBA][0]); pipe->bind_depth_stencil_alpha_state(pipe, ctx->dsa_keep_depth_stencil); ctx->bind_fs_state(pipe, - blitter_get_fs_texfetch_col(ctx, tex->format, tex->target, + blitter_get_fs_texfetch_col(ctx, tex->format, tex->format, tex->target, 1, 1, PIPE_TEX_FILTER_LINEAR)); } diff --git a/src/gallium/auxiliary/util/u_simple_shaders.c b/src/gallium/auxiliary/util/u_simple_shaders.c index 1220e187eac..b46ec589eab 100644 --- a/src/gallium/auxiliary/util/u_simple_shaders.c +++ b/src/gallium/auxiliary/util/u_simple_shaders.c @@ -207,8 +207,10 @@ void *util_make_layered_clear_geometry_shader(struct pipe_context *pipe) /** * Make simple fragment texture shader: * IMM {0,0,0,1} // (if writemask != 0xf) - * MOV OUT[0], IMM[0] // (if writemask != 0xf) - * TEX OUT[0].writemask, IN[0], SAMP[0], 2D; + * MOV TEMP[0], IMM[0] // (if writemask != 0xf) + * TEX TEMP[0].writemask, IN[0], SAMP[0], 2D; + * .. optional SINT <-> UINT clamping .. + * MOV OUT[0], TEMP[0] * END; * * \param tex_target one of PIPE_TEXTURE_x @@ -220,13 +222,16 @@ util_make_fragment_tex_shader_writemask(struct pipe_context *pipe, unsigned tex_target, unsigned interp_mode, unsigned writemask, - enum tgsi_return_type stype) + enum tgsi_return_type stype, + enum tgsi_return_type dtype) { struct ureg_program *ureg; struct ureg_src sampler; struct ureg_src tex; + struct ureg_dst temp; struct ureg_dst out; + assert((stype == TGSI_RETURN_TYPE_FLOAT) == (dtype == TGSI_RETURN_TYPE_FLOAT)); assert(interp_mode == TGSI_INTERPOLATE_LINEAR || interp_mode == TGSI_INTERPOLATE_PERSPECTIVE); @@ -246,6 +251,8 @@ util_make_fragment_tex_shader_writemask(struct pipe_context *pipe, TGSI_SEMANTIC_COLOR, 0 ); + temp = ureg_DECL_temporary(ureg); + if (writemask != TGSI_WRITEMASK_XYZW) { struct ureg_src imm = ureg_imm4f( ureg, 0, 0, 0, 1 ); @@ -254,13 +261,28 @@ util_make_fragment_tex_shader_writemask(struct pipe_context *pipe, if (tex_target == TGSI_TEXTURE_BUFFER) ureg_TXF(ureg, - ureg_writemask(out, writemask), + ureg_writemask(temp, writemask), tex_target, tex, sampler); else ureg_TEX(ureg, - ureg_writemask(out, writemask), + ureg_writemask(temp, writemask), tex_target, tex, sampler); + if (stype != dtype) { + if (stype == TGSI_RETURN_TYPE_SINT) { + assert(dtype == TGSI_RETURN_TYPE_UINT); + + ureg_IMAX(ureg, temp, ureg_src(temp), ureg_imm1i(ureg, 0)); + } else { + assert(stype == TGSI_RETURN_TYPE_UINT); + assert(dtype == TGSI_RETURN_TYPE_SINT); + + ureg_UMIN(ureg, temp, ureg_src(temp), ureg_imm1u(ureg, (1u << 31) - 1)); + } + } + + ureg_MOV(ureg, out, ureg_src(temp)); + ureg_END( ureg ); return ureg_create_shader_and_destroy( ureg, pipe ); @@ -275,13 +297,14 @@ util_make_fragment_tex_shader_writemask(struct pipe_context *pipe, void * util_make_fragment_tex_shader(struct pipe_context *pipe, unsigned tex_target, unsigned interp_mode, - enum tgsi_return_type stype) + enum tgsi_return_type stype, + enum tgsi_return_type dtype) { return util_make_fragment_tex_shader_writemask( pipe, tex_target, interp_mode, TGSI_WRITEMASK_XYZW, - stype ); + stype, dtype ); } @@ -545,7 +568,9 @@ util_make_fs_blit_msaa_gen(struct pipe_context *pipe, unsigned tgsi_tex, const char *samp_type, const char *output_semantic, - const char *output_mask) + const char *output_mask, + const char *conversion_decl, + const char *conversion) { static const char shader_templ[] = "FRAG\n" @@ -554,9 +579,12 @@ util_make_fs_blit_msaa_gen(struct pipe_context *pipe, "DCL SVIEW[0], %s, %s\n" "DCL OUT[0], %s\n" "DCL TEMP[0]\n" + "%s" "F2U TEMP[0], IN[0]\n" - "TXF OUT[0]%s, TEMP[0], SAMP[0], %s\n" + "TXF TEMP[0], TEMP[0], SAMP[0], %s\n" + "%s" + "MOV OUT[0]%s, TEMP[0]\n" "END\n"; const char *type = tgsi_texture_names[tgsi_tex]; @@ -567,8 +595,8 @@ util_make_fs_blit_msaa_gen(struct pipe_context *pipe, assert(tgsi_tex == TGSI_TEXTURE_2D_MSAA || tgsi_tex == TGSI_TEXTURE_2D_ARRAY_MSAA); - sprintf(text, shader_templ, type, samp_type, - output_semantic, output_mask, type); + snprintf(text, sizeof(text), shader_templ, type, samp_type, + output_semantic, conversion_decl, type, conversion, output_mask); if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) { puts(text); @@ -592,19 +620,35 @@ util_make_fs_blit_msaa_gen(struct pipe_context *pipe, void * util_make_fs_blit_msaa_color(struct pipe_context *pipe, unsigned tgsi_tex, - enum tgsi_return_type stype) + enum tgsi_return_type stype, + enum tgsi_return_type dtype) { const char *samp_type; + const char *conversion_decl = ""; + const char *conversion = ""; - if (stype == TGSI_RETURN_TYPE_UINT) + if (stype == TGSI_RETURN_TYPE_UINT) { samp_type = "UINT"; - else if (stype == TGSI_RETURN_TYPE_SINT) + + if (dtype == TGSI_RETURN_TYPE_SINT) { + conversion_decl = "IMM[0] UINT32 {2147483647, 0, 0, 0}\n"; + conversion = "UMIN TEMP[0], TEMP[0], IMM[0].x\n"; + } + } else if (stype == TGSI_RETURN_TYPE_SINT) { samp_type = "SINT"; - else + + if (dtype == TGSI_RETURN_TYPE_UINT) { + conversion_decl = "IMM[0] INT32 {0, 0, 0, 0}\n"; + conversion = "IMAX TEMP[0], TEMP[0], IMM[0].x\n"; + } + } else { + assert(dtype == TGSI_RETURN_TYPE_FLOAT); samp_type = "FLOAT"; + } return util_make_fs_blit_msaa_gen(pipe, tgsi_tex, samp_type, - "COLOR[0]", ""); + "COLOR[0]", "", conversion_decl, + conversion); } @@ -618,7 +662,7 @@ util_make_fs_blit_msaa_depth(struct pipe_context *pipe, unsigned tgsi_tex) { return util_make_fs_blit_msaa_gen(pipe, tgsi_tex, "FLOAT", - "POSITION", ".z"); + "POSITION", ".z", "", ""); } @@ -632,7 +676,7 @@ util_make_fs_blit_msaa_stencil(struct pipe_context *pipe, unsigned tgsi_tex) { return util_make_fs_blit_msaa_gen(pipe, tgsi_tex, "UINT", - "STENCIL", ".y"); + "STENCIL", ".y", "", ""); } diff --git a/src/gallium/auxiliary/util/u_simple_shaders.h b/src/gallium/auxiliary/util/u_simple_shaders.h index fe1917f06c9..04810982024 100644 --- a/src/gallium/auxiliary/util/u_simple_shaders.h +++ b/src/gallium/auxiliary/util/u_simple_shaders.h @@ -73,12 +73,14 @@ util_make_fragment_tex_shader_writemask(struct pipe_context *pipe, unsigned tex_target, unsigned interp_mode, unsigned writemask, - enum tgsi_return_type stype); + enum tgsi_return_type stype, + enum tgsi_return_type dtype); extern void * util_make_fragment_tex_shader(struct pipe_context *pipe, unsigned tex_target, unsigned interp_mode, - enum tgsi_return_type stype); + enum tgsi_return_type stype, + enum tgsi_return_type dtype); extern void * util_make_fragment_tex_shader_writedepth(struct pipe_context *pipe, @@ -118,7 +120,8 @@ util_make_fragment_cloneinput_shader(struct pipe_context *pipe, int num_cbufs, extern void * util_make_fs_blit_msaa_color(struct pipe_context *pipe, unsigned tgsi_tex, - enum tgsi_return_type stype); + enum tgsi_return_type stype, + enum tgsi_return_type dtype); extern void * diff --git a/src/gallium/auxiliary/util/u_tests.c b/src/gallium/auxiliary/util/u_tests.c index f22ffceb6bc..c33c1f69e83 100644 --- a/src/gallium/auxiliary/util/u_tests.c +++ b/src/gallium/auxiliary/util/u_tests.c @@ -374,6 +374,7 @@ null_sampler_view(struct pipe_context *ctx, unsigned tgsi_tex_target) /* Fragment shader. */ fs = util_make_fragment_tex_shader(ctx, tgsi_tex_target, TGSI_INTERPOLATE_LINEAR, + TGSI_RETURN_TYPE_FLOAT, TGSI_RETURN_TYPE_FLOAT); cso_set_fragment_shader_handle(cso, fs); diff --git a/src/gallium/tests/trivial/quad-tex.c b/src/gallium/tests/trivial/quad-tex.c index ddee2942af9..c72c5fe2391 100644 --- a/src/gallium/tests/trivial/quad-tex.c +++ b/src/gallium/tests/trivial/quad-tex.c @@ -272,6 +272,7 @@ static void init_prog(struct program *p) /* fragment shader */ p->fs = util_make_fragment_tex_shader(p->pipe, TGSI_TEXTURE_2D, TGSI_INTERPOLATE_LINEAR, + TGSI_RETURN_TYPE_FLOAT, TGSI_RETURN_TYPE_FLOAT); }