util/blitter: add clamping during SINT <-> UINT blits
authorNicolai Hähnle <nicolai.haehnle@amd.com>
Mon, 7 Nov 2016 14:55:52 +0000 (15:55 +0100)
committerNicolai Hähnle <nicolai.haehnle@amd.com>
Wed, 16 Nov 2016 09:31:21 +0000 (10:31 +0100)
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 <marek.olsak@amd.com>
Reviewed-by: Edward O'Callaghan <funfunctor@folklore1984.net>
src/gallium/auxiliary/util/u_blit.c
src/gallium/auxiliary/util/u_blitter.c
src/gallium/auxiliary/util/u_simple_shaders.c
src/gallium/auxiliary/util/u_simple_shaders.h
src/gallium/auxiliary/util/u_tests.c
src/gallium/tests/trivial/quad-tex.c

index fbc9c77dfcc6bf4ac057e775fb9720428bf65832..6d8178ee5615c456842e74d3a0847ac1f2eaba42 100644 (file)
@@ -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]);
index eb3a97d3d4893164de8b314146ea219a31332bfe..98b54213c096d097d5d81ec5e5015eafdc37e778 100644 (file)
@@ -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,
+                                     PIPE_FORMAT_R32_UINT, target,
+                                     samples, samples, 0);
+         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_UINT, target,
+         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, target,
+         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));
    }
 
index 1220e187eac861850dc63034c2a3eb47d8828758..b46ec589eab7bcf42c2218405dfdd61a1e7ac143 100644 (file)
@@ -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", "", "");
 }
 
 
index fe1917f06c90ff15b2294bf22ffce89a1739c043..04810982024f2b232b0b4c28d678ced7255c4abd 100644 (file)
@@ -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 *
index f22ffceb6bc53232f491f5c904e0744d7a8f6cf6..c33c1f69e837a7514a32fc07e516cfd528ec16c7 100644 (file)
@@ -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);
 
index ddee2942af95226539ada6fc96120cc06c8705b6..c72c5fe2391a00024a79b8a3e4e71627de425457 100644 (file)
@@ -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);
 }