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

Roland Scheidegger sroland at vmware.com
Tue May 30 22:59:27 UTC 2017


Am 31.05.2017 um 00:46 schrieb Marek Olšák:
> 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).

Not that I think using TXF isn't a good idea, but shouldn't you make
sure you end up with a blit which is guaranteed to preserve all bits
here by using an appropriate format in the first place?
That TXF isn't going to denorm flush with f32 formats merely sounds like
an implementation detail of radeonsi to me, but I wouldn't say you could
really count on it here for the blitter.

Roland


> ---
>  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);
> 



More information about the mesa-dev mailing list