[Mesa-dev] [PATCH 4/5] gallium/u_blitter: use TXF if possible

Marek Olšák maraeo at gmail.com
Tue May 30 22:46:46 UTC 2017


From: Marek Olšák <marek.olsak at amd.com>

This fixes piglit:
    arb_texture_view-rendering-r32ui

TEX (image_sample) flushes denorms to 0 with FP32 textures on GCN, but such
a texture can contain integer data written using an integer render view.
If we do a transfer blit with TEX, denorms are flushed to 0. Luckily,
TXF (image_load) doesn't do that.

TXF also doesn't need to load the sampler state, so blit shaders don't have
to do s_load_dwordx4.

TXF doesn't do CLAMP_TO_EDGE, so it can only be used if the src box is
in bounds, or if we clamp manually (this commit doesn't).
---
 src/gallium/auxiliary/util/u_blitter.c | 292 +++++++++++++++++++++------------
 1 file changed, 190 insertions(+), 102 deletions(-)

diff --git a/src/gallium/auxiliary/util/u_blitter.c b/src/gallium/auxiliary/util/u_blitter.c
index 21f0686..b4f393e 100644
--- a/src/gallium/auxiliary/util/u_blitter.c
+++ b/src/gallium/auxiliary/util/u_blitter.c
@@ -69,30 +69,34 @@ struct blitter_context_priv
    /* Vertex shaders. */
    void *vs; /**< Vertex shader which passes {pos, generic} to the output.*/
    void *vs_pos_only[4]; /**< Vertex shader which passes pos to the output.*/
    void *vs_layered; /**< Vertex shader which sets LAYER = INSTANCEID. */
 
    /* Fragment shaders. */
    void *fs_empty;
    void *fs_write_one_cbuf;
    void *fs_write_all_cbufs;
 
-   /* 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 color from a texture where
+    * the 1st index indicates the texture type / destination type,
+    * the 2nd index is the PIPE_TEXTURE_* to be sampled,
+    * the 3rd index is 0 = use TEX, 1 = use TXF.
+    */
+   void *fs_texfetch_col[5][PIPE_MAX_TEXTURE_TYPES][2];
 
-   /* FS which outputs a depth from a texture,
-      where the index is PIPE_TEXTURE_* to be sampled. */
-   void *fs_texfetch_depth[PIPE_MAX_TEXTURE_TYPES];
-   void *fs_texfetch_depthstencil[PIPE_MAX_TEXTURE_TYPES];
-   void *fs_texfetch_stencil[PIPE_MAX_TEXTURE_TYPES];
+   /* FS which outputs a depth from a texture, where
+    * the 1st index is the PIPE_TEXTURE_* to be sampled,
+    * the 2nd index is 0 = use TEX, 1 = use TXF.
+    */
+   void *fs_texfetch_depth[PIPE_MAX_TEXTURE_TYPES][2];
+   void *fs_texfetch_depthstencil[PIPE_MAX_TEXTURE_TYPES][2];
+   void *fs_texfetch_stencil[PIPE_MAX_TEXTURE_TYPES][2];
 
    /* FS which outputs one sample from a multisample texture. */
    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];
 
    /* FS which outputs an average of all samples. */
    void *fs_resolve[PIPE_MAX_TEXTURE_TYPES][NUM_RESOLVE_FRAG_SHADERS][2];
 
@@ -126,20 +130,21 @@ struct blitter_context_priv
    unsigned dst_width;
    unsigned dst_height;
 
    boolean has_geometry_shader;
    boolean has_tessellation;
    boolean has_layered;
    boolean has_stream_out;
    boolean has_stencil_export;
    boolean has_texture_multisample;
    boolean has_tex_lz;
+   boolean has_txf;
    boolean cached_all_shaders;
 
    /* The Draw module overrides these functions.
     * Always create the blitter before Draw. */
    void   (*bind_fs_state)(struct pipe_context *, void *);
    void   (*delete_fs_state)(struct pipe_context *, void *);
 };
 
 static struct pipe_surface *
 util_blitter_get_next_surface_layer(struct pipe_context *pipe,
@@ -193,20 +198,22 @@ struct blitter_context *util_blitter_create(struct pipe_context *pipe)
 
    ctx->has_stencil_export =
          pipe->screen->get_param(pipe->screen,
                                  PIPE_CAP_SHADER_STENCIL_EXPORT);
 
    ctx->has_texture_multisample =
       pipe->screen->get_param(pipe->screen, PIPE_CAP_TEXTURE_MULTISAMPLE);
 
    ctx->has_tex_lz = pipe->screen->get_param(pipe->screen,
                                              PIPE_CAP_TGSI_TEX_TXF_LZ);
+   ctx->has_txf = pipe->screen->get_param(pipe->screen,
+                                          PIPE_CAP_GLSL_FEATURE_LEVEL) > 130;
 
    /* blend state objects */
    memset(&blend, 0, sizeof(blend));
 
    for (i = 0; i <= PIPE_MASK_RGBA; i++) {
       for (j = 0; j < 2; j++) {
          memset(&blend.rt[0], 0, sizeof(blend.rt[0]));
          blend.rt[0].colormask = i;
          if (j) {
             blend.rt[0].blend_enable = 1;
@@ -446,32 +453,36 @@ void util_blitter_destroy(struct blitter_context *blitter)
       pipe->delete_vs_state(pipe, ctx->vs_layered);
    pipe->delete_vertex_elements_state(pipe, ctx->velem_state);
    for (i = 0; i < 4; i++) {
       if (ctx->velem_state_readbuf[i]) {
          pipe->delete_vertex_elements_state(pipe, ctx->velem_state_readbuf[i]);
       }
    }
 
    for (i = 0; i < PIPE_MAX_TEXTURE_TYPES; i++) {
       for (unsigned type = 0; type < ARRAY_SIZE(ctx->fs_texfetch_col); ++type) {
-         if (ctx->fs_texfetch_col[type][i])
-            ctx->delete_fs_state(pipe, ctx->fs_texfetch_col[type][i]);
+         for (unsigned inst = 0; inst < 2; inst++) {
+            if (ctx->fs_texfetch_col[type][i][inst])
+               ctx->delete_fs_state(pipe, ctx->fs_texfetch_col[type][i][inst]);
+         }
          if (ctx->fs_texfetch_col_msaa[type][i])
             ctx->delete_fs_state(pipe, ctx->fs_texfetch_col_msaa[type][i]);
       }
 
-      if (ctx->fs_texfetch_depth[i])
-         ctx->delete_fs_state(pipe, ctx->fs_texfetch_depth[i]);
-      if (ctx->fs_texfetch_depthstencil[i])
-         ctx->delete_fs_state(pipe, ctx->fs_texfetch_depthstencil[i]);
-      if (ctx->fs_texfetch_stencil[i])
-         ctx->delete_fs_state(pipe, ctx->fs_texfetch_stencil[i]);
+      for (unsigned inst = 0; inst < 2; inst++) {
+         if (ctx->fs_texfetch_depth[i][inst])
+            ctx->delete_fs_state(pipe, ctx->fs_texfetch_depth[i][inst]);
+         if (ctx->fs_texfetch_depthstencil[i][inst])
+            ctx->delete_fs_state(pipe, ctx->fs_texfetch_depthstencil[i][inst]);
+         if (ctx->fs_texfetch_stencil[i][inst])
+            ctx->delete_fs_state(pipe, ctx->fs_texfetch_stencil[i][inst]);
+      }
 
       if (ctx->fs_texfetch_depth_msaa[i])
          ctx->delete_fs_state(pipe, ctx->fs_texfetch_depth_msaa[i]);
       if (ctx->fs_texfetch_depthstencil_msaa[i])
          ctx->delete_fs_state(pipe, ctx->fs_texfetch_depthstencil_msaa[i]);
       if (ctx->fs_texfetch_stencil_msaa[i])
          ctx->delete_fs_state(pipe, ctx->fs_texfetch_stencil_msaa[i]);
 
       for (j = 0; j< ARRAY_SIZE(ctx->fs_resolve[i]); j++)
          for (f = 0; f < 2; f++)
@@ -748,26 +759,27 @@ static void blitter_set_clear_color(struct blitter_context_priv *ctx,
          ctx->vertices[i][1][0] = 0;
          ctx->vertices[i][1][1] = 0;
          ctx->vertices[i][1][2] = 0;
          ctx->vertices[i][1][3] = 0;
       }
    }
 }
 
 static void get_texcoords(struct pipe_sampler_view *src,
                           unsigned src_width0, unsigned src_height0,
-                          int x1, int y1, int x2, int y2,
+                          int x1, int y1, int x2, int y2, bool uses_txf,
                           float out[4])
 {
    struct pipe_resource *tex = src->texture;
    unsigned level = src->u.tex.first_level;
-   boolean normalized = tex->target != PIPE_TEXTURE_RECT &&
+   boolean normalized = !uses_txf &&
+                        tex->target != PIPE_TEXTURE_RECT &&
                         tex->nr_samples <= 1;
 
    if (normalized) {
       out[0] = x1 / (float)u_minify(src_width0,  level);
       out[1] = y1 / (float)u_minify(src_height0, level);
       out[2] = x2 / (float)u_minify(src_width0,  level);
       out[3] = y2 / (float)u_minify(src_height0, level);
    } else {
       out[0] = (float) x1;
       out[1] = (float) y1;
@@ -789,46 +801,51 @@ static void set_texcoords_in_vertices(const float coord[4],
    out[1] = coord[3]; /*t2.t*/
    out += stride;
    out[0] = coord[0]; /*t3.s*/
    out[1] = coord[3]; /*t3.t*/
 }
 
 static void blitter_set_texcoords(struct blitter_context_priv *ctx,
                                   struct pipe_sampler_view *src,
                                   unsigned src_width0, unsigned src_height0,
                                   float layer, unsigned sample,
-                                  int x1, int y1, int x2, int y2)
+                                  int x1, int y1, int x2, int y2,
+                                  bool uses_txf)
 {
    unsigned i;
    float coord[4];
    float face_coord[4][2];
 
-   get_texcoords(src, src_width0, src_height0, x1, y1, x2, y2, coord);
+   get_texcoords(src, src_width0, src_height0, x1, y1, x2, y2, uses_txf,
+                 coord);
 
    if (src->texture->target == PIPE_TEXTURE_CUBE ||
        src->texture->target == PIPE_TEXTURE_CUBE_ARRAY) {
       set_texcoords_in_vertices(coord, &face_coord[0][0], 2);
       util_map_texcoords2d_onto_cubemap((unsigned)layer % 6,
                                         /* pointer, stride in floats */
                                         &face_coord[0][0], 2,
                                         &ctx->vertices[0][1][0], 8,
                                         FALSE);
    } else {
       set_texcoords_in_vertices(coord, &ctx->vertices[0][1][0], 8);
    }
 
    /* Set the layer. */
    switch (src->texture->target) {
    case PIPE_TEXTURE_3D:
       {
-         float r = layer / (float)u_minify(src->texture->depth0,
-                                           src->u.tex.first_level);
+         float r = layer;
+
+         if (!uses_txf)
+            r /= u_minify(src->texture->depth0, src->u.tex.first_level);
+
          for (i = 0; i < 4; i++)
             ctx->vertices[i][1][2] = r; /*r*/
       }
       break;
 
    case PIPE_TEXTURE_1D_ARRAY:
       for (i = 0; i < 4; i++)
          ctx->vertices[i][1][1] = (float) layer; /*t*/
       break;
 
@@ -860,21 +877,22 @@ static void blitter_set_dst_dimensions(struct blitter_context_priv *ctx,
    ctx->dst_width = width;
    ctx->dst_height = height;
 }
 
 static void *blitter_get_fs_texfetch_col(struct blitter_context_priv *ctx,
                                          enum pipe_format src_format,
                                          enum pipe_format dst_format,
                                          enum pipe_texture_target target,
                                          unsigned src_nr_samples,
                                          unsigned dst_nr_samples,
-                                         unsigned filter)
+                                         unsigned filter,
+                                         bool use_txf)
 {
    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(src_format)) {
@@ -942,236 +960,267 @@ 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, dtype);
          }
       }
 
       return *shader;
    } else {
-      void **shader = &ctx->fs_texfetch_col[type][target];
+      void **shader;
+
+      if (use_txf)
+         shader = &ctx->fs_texfetch_col[type][target][1];
+      else
+         shader = &ctx->fs_texfetch_col[type][target][0];
 
       /* Create the fragment shader on-demand. */
       if (!*shader) {
          assert(!ctx->cached_all_shaders);
          *shader = util_make_fragment_tex_shader(pipe, tgsi_tex,
                                                  TGSI_INTERPOLATE_LINEAR,
                                                  stype, dtype,
-                                                 ctx->has_tex_lz, false);
+                                                 ctx->has_tex_lz, use_txf);
       }
 
       return *shader;
    }
 }
 
 static inline
 void *blitter_get_fs_texfetch_depth(struct blitter_context_priv *ctx,
                                     enum pipe_texture_target target,
-                                    unsigned nr_samples)
+                                    unsigned nr_samples,
+                                    bool use_txf)
 {
    struct pipe_context *pipe = ctx->base.pipe;
 
    assert(target < PIPE_MAX_TEXTURE_TYPES);
 
    if (nr_samples > 1) {
       void **shader = &ctx->fs_texfetch_depth_msaa[target];
 
       /* Create the fragment shader on-demand. */
       if (!*shader) {
          unsigned tgsi_tex;
          assert(!ctx->cached_all_shaders);
          tgsi_tex = util_pipe_tex_to_tgsi_tex(target, nr_samples);
          *shader = util_make_fs_blit_msaa_depth(pipe, tgsi_tex);
       }
 
       return *shader;
    } else {
-      void **shader = &ctx->fs_texfetch_depth[target];
+      void **shader;
+
+      if (use_txf)
+         shader = &ctx->fs_texfetch_depth[target][1];
+      else
+         shader = &ctx->fs_texfetch_depth[target][0];
 
       /* Create the fragment shader on-demand. */
       if (!*shader) {
          unsigned tgsi_tex;
          assert(!ctx->cached_all_shaders);
          tgsi_tex = util_pipe_tex_to_tgsi_tex(target, 0);
          *shader =
             util_make_fragment_tex_shader_writedepth(pipe, tgsi_tex,
                                                      TGSI_INTERPOLATE_LINEAR,
-                                                     ctx->has_tex_lz, false);
+                                                     ctx->has_tex_lz, use_txf);
       }
 
       return *shader;
    }
 }
 
 static inline
 void *blitter_get_fs_texfetch_depthstencil(struct blitter_context_priv *ctx,
                                            enum pipe_texture_target target,
-                                           unsigned nr_samples)
+                                           unsigned nr_samples,
+                                           bool use_txf)
 {
    struct pipe_context *pipe = ctx->base.pipe;
 
    assert(target < PIPE_MAX_TEXTURE_TYPES);
 
    if (nr_samples > 1) {
       void **shader = &ctx->fs_texfetch_depthstencil_msaa[target];
 
       /* Create the fragment shader on-demand. */
       if (!*shader) {
          unsigned tgsi_tex;
          assert(!ctx->cached_all_shaders);
          tgsi_tex = util_pipe_tex_to_tgsi_tex(target, nr_samples);
          *shader = util_make_fs_blit_msaa_depthstencil(pipe, tgsi_tex);
       }
 
       return *shader;
    } else {
-      void **shader = &ctx->fs_texfetch_depthstencil[target];
+      void **shader;
+
+      if (use_txf)
+         shader = &ctx->fs_texfetch_depthstencil[target][1];
+      else
+         shader = &ctx->fs_texfetch_depthstencil[target][0];
 
       /* Create the fragment shader on-demand. */
       if (!*shader) {
          unsigned tgsi_tex;
          assert(!ctx->cached_all_shaders);
          tgsi_tex = util_pipe_tex_to_tgsi_tex(target, 0);
          *shader =
             util_make_fragment_tex_shader_writedepthstencil(pipe, tgsi_tex,
                                                             TGSI_INTERPOLATE_LINEAR,
                                                             ctx->has_tex_lz,
-                                                            false);
+                                                            use_txf);
       }
 
       return *shader;
    }
 }
 
 static inline
 void *blitter_get_fs_texfetch_stencil(struct blitter_context_priv *ctx,
                                       enum pipe_texture_target target,
-                                      unsigned nr_samples)
+                                      unsigned nr_samples,
+                                      bool use_txf)
 {
    struct pipe_context *pipe = ctx->base.pipe;
 
    assert(target < PIPE_MAX_TEXTURE_TYPES);
 
    if (nr_samples > 1) {
       void **shader = &ctx->fs_texfetch_stencil_msaa[target];
 
       /* Create the fragment shader on-demand. */
       if (!*shader) {
          unsigned tgsi_tex;
          assert(!ctx->cached_all_shaders);
          tgsi_tex = util_pipe_tex_to_tgsi_tex(target, nr_samples);
          *shader = util_make_fs_blit_msaa_stencil(pipe, tgsi_tex);
       }
 
       return *shader;
    } else {
-      void **shader = &ctx->fs_texfetch_stencil[target];
+      void **shader;
+
+      if (use_txf)
+         shader = &ctx->fs_texfetch_stencil[target][1];
+      else
+         shader = &ctx->fs_texfetch_stencil[target][0];
 
       /* Create the fragment shader on-demand. */
       if (!*shader) {
          unsigned tgsi_tex;
          assert(!ctx->cached_all_shaders);
          tgsi_tex = util_pipe_tex_to_tgsi_tex(target, 0);
          *shader =
             util_make_fragment_tex_shader_writestencil(pipe, tgsi_tex,
                                                        TGSI_INTERPOLATE_LINEAR,
-                                                       ctx->has_tex_lz, false);
+                                                       ctx->has_tex_lz, use_txf);
       }
 
       return *shader;
    }
 }
 
 
 /**
  * Generate and save all fragment shaders that we will ever need for
  * blitting.  Drivers which use the 'draw' fallbacks will typically use
  * this to make sure we generate/use shaders that don't go through the
  * draw module's wrapper functions.
  */
 void util_blitter_cache_all_shaders(struct blitter_context *blitter)
 {
    struct blitter_context_priv *ctx = (struct blitter_context_priv*)blitter;
    struct pipe_context *pipe = blitter->pipe;
    struct pipe_screen *screen = pipe->screen;
-   unsigned samples, j, f, target, max_samples;
+   unsigned samples, j, f, target, max_samples, use_txf;
    boolean has_arraytex, has_cubearraytex;
 
    max_samples = ctx->has_texture_multisample ? 2 : 1;
    has_arraytex = screen->get_param(screen,
                                     PIPE_CAP_MAX_TEXTURE_ARRAY_LAYERS) != 0;
    has_cubearraytex = screen->get_param(screen,
                                     PIPE_CAP_CUBE_MAP_ARRAY) != 0;
 
    /* It only matters if i <= 1 or > 1. */
    for (samples = 1; samples <= max_samples; samples++) {
       for (target = PIPE_TEXTURE_1D; target < PIPE_MAX_TEXTURE_TYPES; target++) {
-         if (!has_arraytex &&
-             (target == PIPE_TEXTURE_1D_ARRAY ||
-              target == PIPE_TEXTURE_2D_ARRAY)) {
-            continue;
-         }
-         if (!has_cubearraytex &&
-             (target == PIPE_TEXTURE_CUBE_ARRAY))
-            continue;
-
-	 if (samples > 1 &&
-	     (target != PIPE_TEXTURE_2D &&
-	      target != PIPE_TEXTURE_2D_ARRAY))
-	    continue;
+         for (use_txf = 0; use_txf <= ctx->has_txf; use_txf++) {
+            if (!has_arraytex &&
+                (target == PIPE_TEXTURE_1D_ARRAY ||
+                 target == PIPE_TEXTURE_2D_ARRAY)) {
+               continue;
+            }
+            if (!has_cubearraytex &&
+                (target == PIPE_TEXTURE_CUBE_ARRAY))
+               continue;
 
-         /* 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,
-                                     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_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) {
-            blitter_get_fs_texfetch_depthstencil(ctx, target, samples);
-            blitter_get_fs_texfetch_stencil(ctx, target, samples);
-         }
+            if (samples > 1 &&
+                (target != PIPE_TEXTURE_2D &&
+                 target != PIPE_TEXTURE_2D_ARRAY))
+               continue;
 
-         if (samples == 1)
-            continue;
+            if (samples > 1 && use_txf)
+               continue; /* TXF is the only option, use_txf has no effect */
+
+            /* 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,
+                                        PIPE_FORMAT_R32_FLOAT, target,
+                                        samples, samples, 0, use_txf);
+            blitter_get_fs_texfetch_col(ctx, PIPE_FORMAT_R32_UINT,
+                                        PIPE_FORMAT_R32_UINT, target,
+                                        samples, samples, 0, use_txf);
+            blitter_get_fs_texfetch_col(ctx, PIPE_FORMAT_R32_UINT,
+                                        PIPE_FORMAT_R32_SINT, target,
+                                        samples, samples, 0, use_txf);
+            blitter_get_fs_texfetch_col(ctx, PIPE_FORMAT_R32_SINT,
+                                        PIPE_FORMAT_R32_SINT, target,
+                                        samples, samples, 0, use_txf);
+            blitter_get_fs_texfetch_col(ctx, PIPE_FORMAT_R32_SINT,
+                                        PIPE_FORMAT_R32_UINT, target,
+                                        samples, samples, 0, use_txf);
+            blitter_get_fs_texfetch_depth(ctx, target, samples, use_txf);
+            if (ctx->has_stencil_export) {
+               blitter_get_fs_texfetch_depthstencil(ctx, target, samples, use_txf);
+               blitter_get_fs_texfetch_stencil(ctx, target, samples, use_txf);
+            }
 
-         /* MSAA resolve shaders. */
-         for (j = 2; j < 32; j++) {
-            if (!screen->is_format_supported(screen, PIPE_FORMAT_R32_FLOAT,
-                                             target, j,
-                                             PIPE_BIND_SAMPLER_VIEW)) {
+            if (samples == 1)
                continue;
-            }
 
-            for (f = 0; f < 2; f++) {
-               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,
-                                           PIPE_FORMAT_R32_UINT, target,
-                                           j, 1, f);
-               blitter_get_fs_texfetch_col(ctx, PIPE_FORMAT_R32_SINT,
-                                           PIPE_FORMAT_R32_SINT, target,
-                                           j, 1, f);
+            /* MSAA resolve shaders. */
+            for (j = 2; j < 32; j++) {
+               if (!screen->is_format_supported(screen, PIPE_FORMAT_R32_FLOAT,
+                                                target, j,
+                                                PIPE_BIND_SAMPLER_VIEW)) {
+                  continue;
+               }
+
+               for (f = 0; f < 2; f++) {
+                  if (f != PIPE_TEX_FILTER_NEAREST && use_txf)
+                     continue;
+
+                  blitter_get_fs_texfetch_col(ctx, PIPE_FORMAT_R32_FLOAT,
+                                              PIPE_FORMAT_R32_FLOAT, target,
+                                              j, 1, f, use_txf);
+                  blitter_get_fs_texfetch_col(ctx, PIPE_FORMAT_R32_UINT,
+                                              PIPE_FORMAT_R32_UINT, target,
+                                              j, 1, f, use_txf);
+                  blitter_get_fs_texfetch_col(ctx, PIPE_FORMAT_R32_SINT,
+                                              PIPE_FORMAT_R32_SINT, target,
+                                              j, 1, f, use_txf);
+               }
             }
          }
       }
    }
 
    ctx->fs_empty = util_make_empty_fragment_shader(pipe);
 
    ctx->fs_write_one_cbuf =
       util_make_fragment_passthrough_shader(pipe, TGSI_SEMANTIC_GENERIC,
                                             TGSI_INTERPOLATE_CONSTANT, FALSE);
@@ -1546,21 +1595,22 @@ void util_blitter_copy_texture(struct blitter_context *blitter,
    pipe_sampler_view_reference(&src_view, NULL);
 }
 
 static void do_blits(struct blitter_context_priv *ctx,
                      struct pipe_surface *dst,
                      const struct pipe_box *dstbox,
                      struct pipe_sampler_view *src,
                      unsigned src_width0,
                      unsigned src_height0,
                      const struct pipe_box *srcbox,
-                     bool is_zsbuf)
+                     bool is_zsbuf,
+                     bool uses_txf)
 {
    struct pipe_context *pipe = ctx->base.pipe;
    unsigned src_samples = src->texture->nr_samples;
    unsigned dst_samples = dst->texture->nr_samples;
    enum pipe_texture_target src_target = src->texture->target;
    struct pipe_framebuffer_state fb_state = {0};
 
    /* Initialize framebuffer state. */
    fb_state.width = dst->width;
    fb_state.height = dst->height;
@@ -1574,21 +1624,22 @@ static void do_blits(struct blitter_context_priv *ctx,
        src_samples <= 1) {
       /* Draw the quad with the draw_rectangle callback. */
 
       /* Set texture coordinates. - use a pipe color union
        * for interface purposes.
        * XXX pipe_color_union is a wrong name since we use that to set
        * texture coordinates too.
        */
       union pipe_color_union coord;
       get_texcoords(src, src_width0, src_height0, srcbox->x, srcbox->y,
-                    srcbox->x+srcbox->width, srcbox->y+srcbox->height, coord.f);
+                    srcbox->x+srcbox->width, srcbox->y+srcbox->height,
+                    uses_txf, coord.f);
 
       /* Set framebuffer state. */
       if (is_zsbuf) {
          fb_state.zsbuf = dst;
       } else {
          fb_state.cbufs[0] = dst;
       }
       pipe->set_framebuffer_state(pipe, &fb_state);
 
       /* Draw. */
@@ -1637,33 +1688,33 @@ static void do_blits(struct blitter_context_priv *ctx,
          if (src_samples == dst_samples && dst_samples > 1) {
             /* MSAA copy. */
             unsigned i, max_sample = dst_samples - 1;
 
             for (i = 0; i <= max_sample; i++) {
                pipe->set_sample_mask(pipe, 1 << i);
                blitter_set_texcoords(ctx, src, src_width0, src_height0,
                                      srcbox->z + src_z,
                                      i, srcbox->x, srcbox->y,
                                      srcbox->x + srcbox->width,
-                                     srcbox->y + srcbox->height);
+                                     srcbox->y + srcbox->height, uses_txf);
                blitter_draw(ctx, dstbox->x, dstbox->y,
                             dstbox->x + dstbox->width,
                             dstbox->y + dstbox->height, 0, 1);
             }
          } else {
             /* Normal copy, MSAA upsampling, or MSAA resolve. */
             pipe->set_sample_mask(pipe, ~0);
             blitter_set_texcoords(ctx, src, src_width0, src_height0,
                                   srcbox->z + src_z, 0,
                                   srcbox->x, srcbox->y,
                                   srcbox->x + srcbox->width,
-                                  srcbox->y + srcbox->height);
+                                  srcbox->y + srcbox->height, uses_txf);
             blitter_draw(ctx, dstbox->x, dstbox->y,
                          dstbox->x + dstbox->width,
                          dstbox->y + dstbox->height, 0, 1);
          }
 
          /* Get the next surface or (if this is the last iteration)
           * just unreference the last one. */
          old = dst;
          if (dst_z < dstbox->depth-1) {
             dst = ctx->base.get_next_surface_layer(ctx->base.pipe, dst);
@@ -1713,59 +1764,95 @@ void util_blitter_blit_generic(struct blitter_context *blitter,
    if (!blit_stencil && !blit_depth && !blit_color) {
       return;
    }
 
    if (blit_stencil ||
        (dstbox->width == abs(srcbox->width) &&
         dstbox->height == abs(srcbox->height))) {
       filter = PIPE_TEX_FILTER_NEAREST;
    }
 
+   bool use_txf = false;
+
+   if (ctx->has_txf &&
+       filter == PIPE_TEX_FILTER_NEAREST &&
+       src->target != PIPE_TEXTURE_CUBE &&
+       src->target != PIPE_TEXTURE_CUBE_ARRAY) {
+      int src_width = u_minify(src_width0, src->u.tex.first_level);
+      int src_height = u_minify(src_height0, src->u.tex.first_level);
+      int src_depth = src->u.tex.last_layer + 1;
+      struct pipe_box box = *srcbox;
+
+      /* Eliminate negative width/height/depth. */
+      if (box.width < 0) {
+         box.x += box.width;
+         box.width *= -1;
+      }
+      if (box.height < 0) {
+         box.y += box.height;
+         box.height *= -1;
+      }
+      if (box.depth < 0) {
+         box.z += box.depth;
+         box.depth *= -1;
+      }
+
+      /* See if srcbox is in bounds. TXF doesn't clamp the coordinates. */
+      use_txf =
+         box.x >= 0 && box.x < src_width &&
+         box.y >= 0 && box.y < src_height &&
+         box.z >= 0 && box.z < src_depth &&
+         box.x + box.width > 0 && box.x + box.width <= src_width &&
+         box.y + box.height > 0 && box.y + box.height <= src_height &&
+         box.z + box.depth > 0 && box.z + box.depth <= src_depth;
+   }
+
    /* Check whether the states are properly saved. */
    util_blitter_set_running_flag(blitter);
    blitter_check_saved_vertex_states(ctx);
    blitter_check_saved_fragment_states(ctx);
    blitter_check_saved_textures(ctx);
    blitter_check_saved_fb_state(ctx);
    blitter_disable_render_cond(ctx);
 
    if (blit_depth || blit_stencil) {
       pipe->bind_blend_state(pipe, ctx->blend[0][0]);
 
       if (blit_depth && blit_stencil) {
          pipe->bind_depth_stencil_alpha_state(pipe,
                                               ctx->dsa_write_depth_stencil);
          ctx->bind_fs_state(pipe,
                blitter_get_fs_texfetch_depthstencil(ctx, src_target,
-                                                    src_samples));
+                                                    src_samples, use_txf));
       } else if (blit_depth) {
          pipe->bind_depth_stencil_alpha_state(pipe,
                                               ctx->dsa_write_depth_keep_stencil);
          ctx->bind_fs_state(pipe,
                blitter_get_fs_texfetch_depth(ctx, src_target,
-                                             src_samples));
+                                             src_samples, use_txf));
       } else { /* is_stencil */
          pipe->bind_depth_stencil_alpha_state(pipe,
                                               ctx->dsa_keep_depth_write_stencil);
          ctx->bind_fs_state(pipe,
                blitter_get_fs_texfetch_stencil(ctx, src_target,
-                                               src_samples));
+                                               src_samples, use_txf));
       }
 
    } else {
       unsigned colormask = mask & PIPE_MASK_RGBA;
 
       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, dst->format, src_target,
-                                        src_samples, dst_samples, filter));
+                                        src_samples, dst_samples, filter,
+                                        use_txf));
    }
 
    /* Set the linear filter only for scaled color non-MSAA blits. */
    if (filter == PIPE_TEX_FILTER_LINEAR) {
       if (src_target == PIPE_TEXTURE_RECT) {
          sampler_state = ctx->sampler_state_rect_linear;
       } else {
          sampler_state = ctx->sampler_state_linear;
       }
    } else {
@@ -1817,21 +1904,21 @@ void util_blitter_blit_generic(struct blitter_context *blitter,
    }
 
    pipe->bind_vertex_elements_state(pipe, ctx->velem_state);
    if (scissor) {
       pipe->set_scissor_states(pipe, 0, 1, scissor);
    }
 
    blitter_set_common_draw_rect_state(ctx, scissor != NULL, FALSE);
 
    do_blits(ctx, dst, dstbox, src, src_width0, src_height0,
-            srcbox, blit_depth || blit_stencil);
+            srcbox, blit_depth || blit_stencil, use_txf);
 
    util_blitter_restore_vertex_states(blitter);
    util_blitter_restore_fragment_states(blitter);
    util_blitter_restore_textures(blitter);
    util_blitter_restore_fb_state(blitter);
    if (scissor) {
       pipe->set_scissor_states(pipe, 0, 1, &ctx->base.saved_scissor);
    }
    util_blitter_restore_render_cond(blitter);
    util_blitter_unset_running_flag(blitter);
@@ -1898,27 +1985,28 @@ void util_blitter_generate_mipmap(struct blitter_context *blitter,
    blitter_check_saved_textures(ctx);
    blitter_check_saved_fb_state(ctx);
    blitter_disable_render_cond(ctx);
 
    /* Set states. */
    if (is_depth) {
       pipe->bind_blend_state(pipe, ctx->blend[0][0]);
       pipe->bind_depth_stencil_alpha_state(pipe,
                                            ctx->dsa_write_depth_keep_stencil);
       ctx->bind_fs_state(pipe,
-                         blitter_get_fs_texfetch_depth(ctx, tex->target, 1));
+                         blitter_get_fs_texfetch_depth(ctx, tex->target, 1,
+                                                       false));
    } else {
       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->format, tex->target,
-                                        1, 1, PIPE_TEX_FILTER_LINEAR));
+                                        1, 1, PIPE_TEX_FILTER_LINEAR, false));
    }
 
    if (tex->target == PIPE_TEXTURE_RECT) {
       sampler_state = ctx->sampler_state_rect_linear;
    } else {
       sampler_state = ctx->sampler_state_linear;
    }
    pipe->bind_sampler_states(pipe, PIPE_SHADER_FRAGMENT,
                              0, 1, &sampler_state);
 
@@ -1950,21 +2038,21 @@ void util_blitter_generate_mipmap(struct blitter_context *blitter,
       dst_view = pipe->create_surface(pipe, tex, &dst_templ);
 
       /* Initialize the sampler view. */
       util_blitter_default_src_texture(&src_templ, tex, src_level);
       src_templ.format = format;
       src_view = pipe->create_sampler_view(pipe, tex, &src_templ);
 
       pipe->set_sampler_views(pipe, PIPE_SHADER_FRAGMENT, 0, 1, &src_view);
 
       do_blits(ctx, dst_view, &dstbox, src_view, tex->width0, tex->height0,
-               &srcbox, is_depth);
+               &srcbox, is_depth, false);
 
       pipe_surface_reference(&dst_view, NULL);
       pipe_sampler_view_reference(&src_view, NULL);
    }
 
    util_blitter_restore_vertex_states(blitter);
    util_blitter_restore_fragment_states(blitter);
    util_blitter_restore_textures(blitter);
    util_blitter_restore_fb_state(blitter);
    util_blitter_restore_render_cond(blitter);
-- 
2.7.4



More information about the mesa-dev mailing list