[Mesa-dev] [PATCH 3/3] gallium/u_gen_mipmap: rewrite using pipe->blit

Roland Scheidegger sroland at vmware.com
Sat Mar 22 08:54:24 PDT 2014


Am 16.03.2014 15:47, schrieb Marek Olšák:
> From: Marek Olšák <marek.olsak at amd.com>
> 
> This replaces u_gen_mipmap with an extremely simple implementation based
> on pipe->blit. The diff speaks for itself. st/mesa is also cleaned up.
> 
> Pros:
> - less code
> - correct mipmap generation for NPOT 3D textures (u_blitter uses a better
>   formula)
> - queries are not affected by mipmap generation if drivers disable them
> ---
> 
> For easier reviewing, the new implementation is here:
> 
> +boolean
> +util_gen_mipmap(struct pipe_context *pipe, struct pipe_resource *pt,
> +                uint face, uint baseLevel, uint lastLevel, uint filter)
> +{
> +   struct pipe_screen *screen = pipe->screen;
> +   struct pipe_blit_info blit;
> +   uint dstLevel;
> +   boolean is_zs = util_format_is_depth_or_stencil(pt->format);
> +   boolean has_depth =
> +      util_format_has_depth(util_format_description(pt->format));
> +
> +   /* nothing to do for stencil-only formats */
> +   if (is_zs && !has_depth)
> +      return TRUE;
> +
> +   /* nothing to do for integer formats */
> +   if (!is_zs && util_format_is_pure_integer(pt->format))
> +      return TRUE;
> +
> +   if (!screen->is_format_supported(screen, pt->format, pt->target,
> +                                    pt->nr_samples,
> +                                    PIPE_BIND_SAMPLER_VIEW |
> +                                    (is_zs ? PIPE_BIND_DEPTH_STENCIL :
> +                                     PIPE_BIND_RENDER_TARGET))) {
> +      return FALSE;
> +   }
> +
> +   /* The texture object should have room for the levels which we're
> +    * about to generate.
> +    */
> +   assert(lastLevel <= pt->last_level);
> +
> +   /* If this fails, why are we here? */
> +   assert(lastLevel > baseLevel);
> +   assert(filter == PIPE_TEX_FILTER_LINEAR ||
> +          filter == PIPE_TEX_FILTER_NEAREST);
> +
> +   memset(&blit, 0, sizeof(blit));
> +   blit.src.resource = blit.dst.resource = pt;
> +   blit.src.format = blit.dst.format = pt->format;
> +   /* don't set the stencil mask, stencil shouldn't be changed */
> +   blit.mask = is_zs ? PIPE_MASK_Z : PIPE_MASK_RGBA;
> +   blit.filter = filter;
> +
> +   for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) {
> +      blit.src.level = dstLevel - 1;
> +      blit.dst.level = dstLevel;
> +
> +      blit.src.box.width = u_minify(pt->width0, blit.src.level);
> +      blit.src.box.height = u_minify(pt->height0, blit.src.level);
> +
> +      blit.dst.box.width = u_minify(pt->width0, blit.dst.level);
> +      blit.dst.box.height = u_minify(pt->height0, blit.dst.level);
> +
> +      if (pt->target == PIPE_TEXTURE_CUBE) {
> +         /* only generate one face */
> +         /* note: pipe->blit is capable of generating all faces at once */
> +         blit.src.box.z = blit.dst.box.z = face;
> +         blit.src.box.depth = blit.dst.box.depth = 1;
> +      }
> +      else {
> +         /* generate all layers/slices at once */
> +         blit.src.box.z = blit.dst.box.z = 0;
> +         blit.src.box.depth = util_max_layer(pt, blit.src.level)+1;
> +         blit.dst.box.depth = util_max_layer(pt, blit.dst.level)+1;
> +      }
> +
> +      pipe->blit(pipe, &blit);
> +   }
> +   return TRUE;
> +}
> 
> 
>  src/gallium/auxiliary/util/u_gen_mipmap.c | 524 ++++--------------------------
>  src/gallium/auxiliary/util/u_gen_mipmap.h |  20 +-
>  src/mesa/state_tracker/st_context.c       |   2 -
>  src/mesa/state_tracker/st_context.h       |   1 -
>  src/mesa/state_tracker/st_gen_mipmap.c    |  62 +---
>  src/mesa/state_tracker/st_gen_mipmap.h    |   8 -
>  6 files changed, 61 insertions(+), 556 deletions(-)
> 
> diff --git a/src/gallium/auxiliary/util/u_gen_mipmap.c b/src/gallium/auxiliary/util/u_gen_mipmap.c
> index a2f4218..902f544 100644
> --- a/src/gallium/auxiliary/util/u_gen_mipmap.c
> +++ b/src/gallium/auxiliary/util/u_gen_mipmap.c
> @@ -3,6 +3,7 @@
>   * Copyright 2008 VMware, Inc.
>   * All Rights Reserved.
>   * Copyright 2008  VMware, Inc.  All rights reserved.
> + * Copyright 2014 Advanced Micro Devices, Inc.
>   *
>   * Permission is hereby granted, free of charge, to any person obtaining a
>   * copy of this software and associated documentation files (the
> @@ -30,332 +31,52 @@
>   * @file
>   * Mipmap generation utility
>   *  
> - * @author Brian Paul
> + * @author Brian Paul, Marek Olšák
>   */
>  
>  
> -#include "pipe/p_context.h"
> -#include "util/u_debug.h"
> -#include "pipe/p_defines.h"
> -#include "util/u_inlines.h"
> -#include "pipe/p_shader_tokens.h"
> -#include "pipe/p_state.h"
> -
> -#include "util/u_format.h"
> -#include "util/u_memory.h"
> -#include "util/u_draw_quad.h"
>  #include "util/u_gen_mipmap.h"
> -#include "util/u_simple_shaders.h"
> -#include "util/u_math.h"
> -#include "util/u_texture.h"
> -#include "util/u_half.h"
> -#include "util/u_surface.h"
> -
> -#include "cso_cache/cso_context.h"
> -
> -
> -struct gen_mipmap_state
> -{
> -   struct pipe_context *pipe;
> -   struct cso_context *cso;
> -
> -   struct pipe_blend_state blend_keep_color, blend_write_color;
> -   struct pipe_depth_stencil_alpha_state dsa_keep_depth, dsa_write_depth;
> -   struct pipe_rasterizer_state rasterizer;
> -   struct pipe_sampler_state sampler;
> -   struct pipe_vertex_element velem[2];
> -
> -   void *vs;
> -
> -   /** Not all are used, but simplifies code */
> -   void *fs_color[TGSI_TEXTURE_COUNT];
> -   void *fs_depth[TGSI_TEXTURE_COUNT];
> -
> -   struct pipe_resource *vbuf;  /**< quad vertices */
> -   unsigned vbuf_slot;
> -
> -   float vertices[4][2][4];   /**< vertex/texcoords for quad */
> -};
> -
> -
> -/**
> - * Create a mipmap generation context.
> - * The idea is to create one of these and re-use it each time we need to
> - * generate a mipmap.
> - */
> -struct gen_mipmap_state *
> -util_create_gen_mipmap(struct pipe_context *pipe,
> -                       struct cso_context *cso)
> -{
> -   struct gen_mipmap_state *ctx;
> -   uint i;
> -
> -   ctx = CALLOC_STRUCT(gen_mipmap_state);
> -   if (!ctx)
> -      return NULL;
> -
> -   ctx->pipe = pipe;
> -   ctx->cso = cso;
> -
> -   /* disabled blending/masking */
> -   memset(&ctx->blend_keep_color, 0, sizeof(ctx->blend_keep_color));
> -   memset(&ctx->blend_write_color, 0, sizeof(ctx->blend_write_color));
> -   ctx->blend_write_color.rt[0].colormask = PIPE_MASK_RGBA;
> -
> -   /* no-op depth/stencil/alpha */
> -   memset(&ctx->dsa_keep_depth, 0, sizeof(ctx->dsa_keep_depth));
> -   memset(&ctx->dsa_write_depth, 0, sizeof(ctx->dsa_write_depth));
> -   ctx->dsa_write_depth.depth.enabled = 1;
> -   ctx->dsa_write_depth.depth.func = PIPE_FUNC_ALWAYS;
> -   ctx->dsa_write_depth.depth.writemask = 1;
> -
> -   /* rasterizer */
> -   memset(&ctx->rasterizer, 0, sizeof(ctx->rasterizer));
> -   ctx->rasterizer.cull_face = PIPE_FACE_NONE;
> -   ctx->rasterizer.half_pixel_center = 1;
> -   ctx->rasterizer.bottom_edge_rule = 1;
> -   ctx->rasterizer.depth_clip = 1;
> -
> -   /* sampler state */
> -   memset(&ctx->sampler, 0, sizeof(ctx->sampler));
> -   ctx->sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
> -   ctx->sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
> -   ctx->sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
> -   ctx->sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST;
> -   ctx->sampler.normalized_coords = 1;
> -
> -   /* vertex elements state */
> -   memset(&ctx->velem[0], 0, sizeof(ctx->velem[0]) * 2);
> -   for (i = 0; i < 2; i++) {
> -      ctx->velem[i].src_offset = i * 4 * sizeof(float);
> -      ctx->velem[i].instance_divisor = 0;
> -      ctx->velem[i].vertex_buffer_index = cso_get_aux_vertex_buffer_slot(cso);
> -      ctx->velem[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
> -   }
> -
> -   /* vertex data that doesn't change */
> -   for (i = 0; i < 4; i++) {
> -      ctx->vertices[i][0][2] = 0.0f; /* z */
> -      ctx->vertices[i][0][3] = 1.0f; /* w */
> -      ctx->vertices[i][1][3] = 1.0f; /* q */
> -   }
> -
> -   /* Note: the actual vertex buffer is allocated as needed below */
> -
> -   return ctx;
> -}
> -
> -
> -/**
> - * Helper function to set the fragment shaders.
> - */
> -static INLINE void
> -set_fragment_shader(struct gen_mipmap_state *ctx, uint type,
> -                    boolean output_depth)
> -{
> -   if (output_depth) {
> -      if (!ctx->fs_depth[type])
> -         ctx->fs_depth[type] =
> -            util_make_fragment_tex_shader_writedepth(ctx->pipe, type,
> -                                                     TGSI_INTERPOLATE_LINEAR);
> -
> -      cso_set_fragment_shader_handle(ctx->cso, ctx->fs_depth[type]);
> -   }
> -   else {
> -      if (!ctx->fs_color[type])
> -         ctx->fs_color[type] =
> -            util_make_fragment_tex_shader(ctx->pipe, type,
> -                                          TGSI_INTERPOLATE_LINEAR);
> -
> -      cso_set_fragment_shader_handle(ctx->cso, ctx->fs_color[type]);
> -   }
> -}
> -
> -
> -/**
> - * Helper function to set the vertex shader.
> - */
> -static INLINE void
> -set_vertex_shader(struct gen_mipmap_state *ctx)
> -{
> -   /* vertex shader - still required to provide the linkage between
> -    * fragment shader input semantics and vertex_element/buffers.
> -    */
> -   if (!ctx->vs)
> -   {
> -      const uint semantic_names[] = { TGSI_SEMANTIC_POSITION,
> -                                      TGSI_SEMANTIC_GENERIC };
> -      const uint semantic_indexes[] = { 0, 0 };
> -      ctx->vs = util_make_vertex_passthrough_shader(ctx->pipe, 2,
> -                                                    semantic_names,
> -                                                    semantic_indexes);
> -   }
> -
> -   cso_set_vertex_shader_handle(ctx->cso, ctx->vs);
> -}
> -
> -
> -/**
> - * Get next "slot" of vertex space in the vertex buffer.
> - * We're allocating one large vertex buffer and using it piece by piece.
> - */
> -static unsigned
> -get_next_slot(struct gen_mipmap_state *ctx)
> -{
> -   const unsigned max_slots = 4096 / sizeof ctx->vertices;
> -
> -   if (ctx->vbuf_slot >= max_slots) {
> -      pipe_resource_reference(&ctx->vbuf, NULL);
> -      ctx->vbuf_slot = 0;
> -   }
> -
> -   if (!ctx->vbuf) {
> -      ctx->vbuf = pipe_buffer_create(ctx->pipe->screen,
> -                                     PIPE_BIND_VERTEX_BUFFER,
> -                                     PIPE_USAGE_STREAM,
> -                                     max_slots * sizeof ctx->vertices);
> -   }
> -   
> -   return ctx->vbuf_slot++ * sizeof ctx->vertices;
> -}
> -
> -
> -static unsigned
> -set_vertex_data(struct gen_mipmap_state *ctx,
> -                enum pipe_texture_target tex_target,
> -                uint face, float r)
> -{
> -   unsigned offset;
> -
> -   /* vert[0].position */
> -   ctx->vertices[0][0][0] = -1.0f; /*x*/
> -   ctx->vertices[0][0][1] = -1.0f; /*y*/
> -
> -   /* vert[1].position */
> -   ctx->vertices[1][0][0] = 1.0f;
> -   ctx->vertices[1][0][1] = -1.0f;
> -
> -   /* vert[2].position */
> -   ctx->vertices[2][0][0] = 1.0f;
> -   ctx->vertices[2][0][1] = 1.0f;
> -
> -   /* vert[3].position */
> -   ctx->vertices[3][0][0] = -1.0f;
> -   ctx->vertices[3][0][1] = 1.0f;
> -
> -   /* Setup vertex texcoords.  This is a little tricky for cube maps. */
> -   if (tex_target == PIPE_TEXTURE_CUBE ||
> -       tex_target == PIPE_TEXTURE_CUBE_ARRAY) {
> -      static const float st[4][2] = {
> -         {0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f}, {0.0f, 1.0f}
> -      };
> -
> -      util_map_texcoords2d_onto_cubemap(face, &st[0][0], 2,
> -                                        &ctx->vertices[0][1][0], 8,
> -                                        FALSE);
> -
> -      /* set the layer for cube arrays */
> -      ctx->vertices[0][1][3] = r;
> -      ctx->vertices[1][1][3] = r;
> -      ctx->vertices[2][1][3] = r;
> -      ctx->vertices[3][1][3] = r;
> -   }
> -   else if (tex_target == PIPE_TEXTURE_1D_ARRAY) {
> -      /* 1D texture array  */
> -      ctx->vertices[0][1][0] = 0.0f; /*s*/
> -      ctx->vertices[0][1][1] = r; /*t*/
> -      ctx->vertices[0][1][2] = 0.0f;    /*r*/
> -
> -      ctx->vertices[1][1][0] = 1.0f;
> -      ctx->vertices[1][1][1] = r;
> -      ctx->vertices[1][1][2] = 0.0f;
> -
> -      ctx->vertices[2][1][0] = 1.0f;
> -      ctx->vertices[2][1][1] = r;
> -      ctx->vertices[2][1][2] = 0.0f;
> -
> -      ctx->vertices[3][1][0] = 0.0f;
> -      ctx->vertices[3][1][1] = r;
> -      ctx->vertices[3][1][2] = 0.0f;
> -   } else {
> -      /* 1D/2D/3D/2D array */
> -      ctx->vertices[0][1][0] = 0.0f; /*s*/
> -      ctx->vertices[0][1][1] = 0.0f; /*t*/
> -      ctx->vertices[0][1][2] = r;    /*r*/
> -
> -      ctx->vertices[1][1][0] = 1.0f;
> -      ctx->vertices[1][1][1] = 0.0f;
> -      ctx->vertices[1][1][2] = r;
> -
> -      ctx->vertices[2][1][0] = 1.0f;
> -      ctx->vertices[2][1][1] = 1.0f;
> -      ctx->vertices[2][1][2] = r;
> -
> -      ctx->vertices[3][1][0] = 0.0f;
> -      ctx->vertices[3][1][1] = 1.0f;
> -      ctx->vertices[3][1][2] = r;
> -   }
> -
> -   offset = get_next_slot( ctx );
> -
> -   pipe_buffer_write_nooverlap(ctx->pipe, ctx->vbuf,
> -                               offset, sizeof(ctx->vertices), ctx->vertices);
> -
> -   return offset;
> -}
> -
> -
> -
> -/**
> - * Destroy a mipmap generation context
> - */
> -void
> -util_destroy_gen_mipmap(struct gen_mipmap_state *ctx)
> -{
> -   struct pipe_context *pipe = ctx->pipe;
> -   unsigned i;
> -
> -   for (i = 0; i < Elements(ctx->fs_color); i++)
> -      if (ctx->fs_color[i])
> -         pipe->delete_fs_state(pipe, ctx->fs_color[i]);
> -
> -   for (i = 0; i < Elements(ctx->fs_depth); i++)
> -      if (ctx->fs_depth[i])
> -         pipe->delete_fs_state(pipe, ctx->fs_depth[i]);
> -
> -   if (ctx->vs)
> -      pipe->delete_vs_state(pipe, ctx->vs);
> -
> -   pipe_resource_reference(&ctx->vbuf, NULL);
> -
> -   FREE(ctx);
> -}
> +#include "util/u_format.h"
> +#include "util/u_inlines.h"
>  
>  
>  /**
>   * Generate mipmap images.  It's assumed all needed texture memory is
>   * already allocated.
>   *
> - * \param psv  the sampler view to the texture to generate mipmap levels for
> - * \param face  which cube face to generate mipmaps for (0 for non-cube maps)
> + * \param pt      the texture to generate mipmap levels for
> + * \param face    which cube face to generate mipmaps for (0 for non-cube maps)
>   * \param baseLevel  the first mipmap level to use as a src
>   * \param lastLevel  the last mipmap level to generate
>   * \param filter  the minification filter used to generate mipmap levels with
> - * \param filter  one of PIPE_TEX_FILTER_LINEAR, PIPE_TEX_FILTER_NEAREST
> + *                one of PIPE_TEX_FILTER_LINEAR, PIPE_TEX_FILTER_NEAREST
>   */
> -void
> -util_gen_mipmap(struct gen_mipmap_state *ctx,
> -                struct pipe_sampler_view *psv,
> +boolean
> +util_gen_mipmap(struct pipe_context *pipe, struct pipe_resource *pt,
>                  uint face, uint baseLevel, uint lastLevel, uint filter)
>  {
I think this is missing some parameters by not using a sampler view. In
particular can we please have a separate format here? It may not matter
for GL (srgb maybe, texture views?), but for this to work with d3d we
need to be able to specify the format separately in order to work with
typeless resources, since the resource format was just a guess. And,
similarly d3d10 wants to specify explicit first/last layer (not for cube
maps or 3d textures).
So maybe could just pass a pipe_sampler_view again, drop all the face,
baseLevel, lastLevel parameters and use the parameters from the view?
(I guess this doesn't work for cube maps with the mesa state tracker
since for some very odd reason mesa core wants to do this per-face and
sampler views with just one cube face are illegal but the GL API doesn't
allow to do this per face so I think this should be trivial to change in
mesa. FWIW this should probably be changed anyway in core mesa if you
want to be able to do mipmap generation for cube map arrays, which seems
to be broken actually now completely because _mesa_GenerateMipmap() will
outright reject cube map arrays.)
And I realize the code didn't exactly honor the layer parameter from the
view before, but if you change it completely can as well fix that too I
guess...

Otherwise the idea looks alright to me.


> -   struct pipe_context *pipe = ctx->pipe;
>     struct pipe_screen *screen = pipe->screen;
> -   struct pipe_framebuffer_state fb;
> -   struct pipe_resource *pt = psv->texture;
> +   struct pipe_blit_info blit;
>     uint dstLevel;
> -   uint offset;
> -   uint type;
> -   boolean is_depth = util_format_is_depth_or_stencil(psv->format);
> +   boolean is_zs = util_format_is_depth_or_stencil(pt->format);
> +   boolean has_depth =
> +      util_format_has_depth(util_format_description(pt->format));
> +
> +   /* nothing to do for stencil-only formats */
> +   if (is_zs && !has_depth)
> +      return TRUE;
> +
> +   /* nothing to do for integer formats */
> +   if (!is_zs && util_format_is_pure_integer(pt->format))
> +      return TRUE;
> +
> +   if (!screen->is_format_supported(screen, pt->format, pt->target,
> +                                    pt->nr_samples,
> +                                    PIPE_BIND_SAMPLER_VIEW |
> +                                    (is_zs ? PIPE_BIND_DEPTH_STENCIL :
> +                                     PIPE_BIND_RENDER_TARGET))) {
> +      return FALSE;
> +   }
>  
>     /* The texture object should have room for the levels which we're
>      * about to generate.
> @@ -364,175 +85,40 @@ util_gen_mipmap(struct gen_mipmap_state *ctx,
>  
>     /* If this fails, why are we here? */
>     assert(lastLevel > baseLevel);
> -
>     assert(filter == PIPE_TEX_FILTER_LINEAR ||
>            filter == PIPE_TEX_FILTER_NEAREST);
>  
> -   type = util_pipe_tex_to_tgsi_tex(pt->target, 1);
> -
> -   /* check if we can render in the texture's format */
> -   if (!screen->is_format_supported(screen, psv->format, pt->target,
> -                                    pt->nr_samples,
> -                                    is_depth ? PIPE_BIND_DEPTH_STENCIL :
> -                                               PIPE_BIND_RENDER_TARGET)) {
> -      /* The caller should check if the format is renderable. */
> -      assert(0);
> -      return;
> -   }
> -
> -   /* save state (restored below) */
> -   cso_save_blend(ctx->cso);
> -   cso_save_depth_stencil_alpha(ctx->cso);
> -   cso_save_rasterizer(ctx->cso);
> -   cso_save_sample_mask(ctx->cso);
> -   cso_save_samplers(ctx->cso, PIPE_SHADER_FRAGMENT);
> -   cso_save_sampler_views(ctx->cso, PIPE_SHADER_FRAGMENT);
> -   cso_save_stream_outputs(ctx->cso);
> -   cso_save_framebuffer(ctx->cso);
> -   cso_save_fragment_shader(ctx->cso);
> -   cso_save_vertex_shader(ctx->cso);
> -   cso_save_geometry_shader(ctx->cso);
> -   cso_save_viewport(ctx->cso);
> -   cso_save_vertex_elements(ctx->cso);
> -   cso_save_aux_vertex_buffer_slot(ctx->cso);
> -   cso_save_render_condition(ctx->cso);
> -
> -   /* bind our state */
> -   cso_set_blend(ctx->cso, is_depth ? &ctx->blend_keep_color :
> -                                      &ctx->blend_write_color);
> -   cso_set_depth_stencil_alpha(ctx->cso, is_depth ? &ctx->dsa_write_depth :
> -                                                    &ctx->dsa_keep_depth);
> -   cso_set_rasterizer(ctx->cso, &ctx->rasterizer);
> -   cso_set_sample_mask(ctx->cso, ~0);
> -   cso_set_vertex_elements(ctx->cso, 2, ctx->velem);
> -   cso_set_stream_outputs(ctx->cso, 0, NULL, NULL);
> -   cso_set_render_condition(ctx->cso, NULL, FALSE, 0);
> -
> -   set_fragment_shader(ctx, type, is_depth);
> -   set_vertex_shader(ctx);
> -   cso_set_geometry_shader_handle(ctx->cso, NULL);
> -
> -   /* init framebuffer state */
> -   memset(&fb, 0, sizeof(fb));
> -
> -   /* set min/mag to same filter for faster sw speed */
> -   ctx->sampler.mag_img_filter = filter;
> -   ctx->sampler.min_img_filter = filter;
> +   memset(&blit, 0, sizeof(blit));
> +   blit.src.resource = blit.dst.resource = pt;
> +   blit.src.format = blit.dst.format = pt->format;
> +   /* don't set the stencil mask, stencil shouldn't be changed */
> +   blit.mask = is_zs ? PIPE_MASK_Z : PIPE_MASK_RGBA;
> +   blit.filter = filter;
>  
>     for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) {
> -      const uint srcLevel = dstLevel - 1;
> -      struct pipe_viewport_state vp;
> -      unsigned nr_layers, layer, i;
> -      float rcoord = 0.0f;
> -
> -      if (pt->target == PIPE_TEXTURE_3D)
> -         nr_layers = u_minify(pt->depth0, dstLevel);
> -      else if (pt->target == PIPE_TEXTURE_2D_ARRAY ||
> -               pt->target == PIPE_TEXTURE_1D_ARRAY ||
> -               pt->target == PIPE_TEXTURE_CUBE_ARRAY)
> -	 nr_layers = pt->array_size;
> -      else
> -         nr_layers = 1;
> -
> -      for (i = 0; i < nr_layers; i++) {
> -         struct pipe_surface *surf, surf_templ;
> -         if (pt->target == PIPE_TEXTURE_3D) {
> -            /* in theory with geom shaders and driver with full layer support
> -               could do that in one go. */
> -            layer = i;
> -            /* XXX hmm really? */
> -            rcoord = (float)layer / (float)nr_layers + 1.0f / (float)(nr_layers * 2);
> -         } else if (pt->target == PIPE_TEXTURE_2D_ARRAY ||
> -                    pt->target == PIPE_TEXTURE_1D_ARRAY) {
> -	    layer = i;
> -	    rcoord = (float)layer;
> -         } else if (pt->target == PIPE_TEXTURE_CUBE_ARRAY) {
> -            layer = i;
> -            face = layer % 6;
> -            rcoord = layer / 6;
> -	 } else
> -            layer = face;
> -
> -         u_surface_default_template(&surf_templ, pt);
> -         surf_templ.u.tex.level = dstLevel;
> -         surf_templ.u.tex.first_layer = layer;
> -         surf_templ.u.tex.last_layer = layer;
> -         surf = pipe->create_surface(pipe, pt, &surf_templ);
> +      blit.src.level = dstLevel - 1;
> +      blit.dst.level = dstLevel;
>  
> -         /*
> -          * Setup framebuffer / dest surface
> -          */
> -         if (is_depth) {
> -            fb.nr_cbufs = 0;
> -            fb.zsbuf = surf;
> -         }
> -         else {
> -            fb.nr_cbufs = 1;
> -            fb.cbufs[0] = surf;
> -         }
> -         fb.width = u_minify(pt->width0, dstLevel);
> -         fb.height = u_minify(pt->height0, dstLevel);
> -         cso_set_framebuffer(ctx->cso, &fb);
> +      blit.src.box.width = u_minify(pt->width0, blit.src.level);
> +      blit.src.box.height = u_minify(pt->height0, blit.src.level);
>  
> -         /* viewport */
> -         vp.scale[0] = 0.5f * fb.width;
> -         vp.scale[1] = 0.5f * fb.height;
> -         vp.scale[2] = 1.0f;
> -         vp.scale[3] = 1.0f;
> -         vp.translate[0] = 0.5f * fb.width;
> -         vp.translate[1] = 0.5f * fb.height;
> -         vp.translate[2] = 0.0f;
> -         vp.translate[3] = 0.0f;
> -         cso_set_viewport(ctx->cso, &vp);
> +      blit.dst.box.width = u_minify(pt->width0, blit.dst.level);
> +      blit.dst.box.height = u_minify(pt->height0, blit.dst.level);
>  
> -         /*
> -          * Setup sampler state
> -          * Note: we should only have to set the min/max LOD clamps to ensure
> -          * we grab texels from the right mipmap level.  But some hardware
> -          * has trouble with min clamping so we also set the lod_bias to
> -          * try to work around that.
> -          */
> -         ctx->sampler.min_lod = ctx->sampler.max_lod = (float) srcLevel;
> -         ctx->sampler.lod_bias = (float) srcLevel;
> -         cso_single_sampler(ctx->cso, PIPE_SHADER_FRAGMENT, 0, &ctx->sampler);
> -         cso_single_sampler_done(ctx->cso, PIPE_SHADER_FRAGMENT);
> -
> -         cso_set_sampler_views(ctx->cso, PIPE_SHADER_FRAGMENT, 1, &psv);
> -
> -         /* quad coords in clip coords */
> -         offset = set_vertex_data(ctx,
> -                                  pt->target,
> -                                  face,
> -                                  rcoord);
> -
> -         util_draw_vertex_buffer(ctx->pipe,
> -                                 ctx->cso,
> -                                 ctx->vbuf,
> -                                 cso_get_aux_vertex_buffer_slot(ctx->cso),
> -                                 offset,
> -                                 PIPE_PRIM_TRIANGLE_FAN,
> -                                 4,  /* verts */
> -                                 2); /* attribs/vert */
> -
> -         /* need to signal that the texture has changed _after_ rendering to it */
> -         pipe_surface_reference( &surf, NULL );
> +      if (pt->target == PIPE_TEXTURE_CUBE) {
> +         /* only generate one face */
> +         /* note: pipe->blit is capable of generating all faces at once */
> +         blit.src.box.z = blit.dst.box.z = face;
> +         blit.src.box.depth = blit.dst.box.depth = 1;
> +      }
> +      else {
> +         /* generate all layers/slices at once */
> +         blit.src.box.z = blit.dst.box.z = 0;
> +         blit.src.box.depth = util_max_layer(pt, blit.src.level)+1;
> +         blit.dst.box.depth = util_max_layer(pt, blit.dst.level)+1;
>        }
> -   }
>  
> -   /* restore state we changed */
> -   cso_restore_blend(ctx->cso);
> -   cso_restore_depth_stencil_alpha(ctx->cso);
> -   cso_restore_rasterizer(ctx->cso);
> -   cso_restore_sample_mask(ctx->cso);
> -   cso_restore_samplers(ctx->cso, PIPE_SHADER_FRAGMENT);
> -   cso_restore_sampler_views(ctx->cso, PIPE_SHADER_FRAGMENT);
> -   cso_restore_framebuffer(ctx->cso);
> -   cso_restore_fragment_shader(ctx->cso);
> -   cso_restore_vertex_shader(ctx->cso);
> -   cso_restore_geometry_shader(ctx->cso);
> -   cso_restore_viewport(ctx->cso);
> -   cso_restore_vertex_elements(ctx->cso);
> -   cso_restore_stream_outputs(ctx->cso);
> -   cso_restore_aux_vertex_buffer_slot(ctx->cso);
> -   cso_restore_render_condition(ctx->cso);
> +      pipe->blit(pipe, &blit);
> +   }
> +   return TRUE;
>  }
> diff --git a/src/gallium/auxiliary/util/u_gen_mipmap.h b/src/gallium/auxiliary/util/u_gen_mipmap.h
> index ffeff42..93dac45 100644
> --- a/src/gallium/auxiliary/util/u_gen_mipmap.h
> +++ b/src/gallium/auxiliary/util/u_gen_mipmap.h
> @@ -35,25 +35,11 @@
>  extern "C" {
>  #endif
>  
> -   
> -struct pipe_context;
> -struct pipe_resource;
> -struct cso_context;
> -
> -struct gen_mipmap_state;
> -
> -
> -extern struct gen_mipmap_state *
> -util_create_gen_mipmap(struct pipe_context *pipe, struct cso_context *cso);
> -
> -
> -extern void
> -util_destroy_gen_mipmap(struct gen_mipmap_state *ctx);
>  
> +struct pipe_context;
>  
> -extern void
> -util_gen_mipmap(struct gen_mipmap_state *ctx,
> -                struct pipe_sampler_view *psv,
> +extern boolean
> +util_gen_mipmap(struct pipe_context *pipe, struct pipe_resource *pt,
>                  uint layer, uint baseLevel, uint lastLevel, uint filter);
>  
>  
> diff --git a/src/mesa/state_tracker/st_context.c b/src/mesa/state_tracker/st_context.c
> index 0ffc762..d62ca3d 100644
> --- a/src/mesa/state_tracker/st_context.c
> +++ b/src/mesa/state_tracker/st_context.c
> @@ -150,7 +150,6 @@ st_create_context_priv( struct gl_context *ctx, struct pipe_context *pipe,
>     st_init_bitmap(st);
>     st_init_clear(st);
>     st_init_draw( st );
> -   st_init_generate_mipmap(st);
>  
>     /* Choose texture target for glDrawPixels, glBitmap, renderbuffers */
>     if (pipe->screen->get_param(pipe->screen, PIPE_CAP_NPOT_TEXTURES))
> @@ -252,7 +251,6 @@ static void st_destroy_context_priv( struct st_context *st )
>  
>     st_destroy_atoms( st );
>     st_destroy_draw( st );
> -   st_destroy_generate_mipmap(st);
>     st_destroy_clear(st);
>     st_destroy_bitmap(st);
>     st_destroy_drawpix(st);
> diff --git a/src/mesa/state_tracker/st_context.h b/src/mesa/state_tracker/st_context.h
> index 0e00dd4..361a24b 100644
> --- a/src/mesa/state_tracker/st_context.h
> +++ b/src/mesa/state_tracker/st_context.h
> @@ -188,7 +188,6 @@ struct st_context
>     void *passthrough_fs;  /**< simple pass-through frag shader */
>  
>     enum pipe_texture_target internal_target;
> -   struct gen_mipmap_state *gen_mipmap;
>  
>     struct cso_context *cso_context;
>  
> diff --git a/src/mesa/state_tracker/st_gen_mipmap.c b/src/mesa/state_tracker/st_gen_mipmap.c
> index b615575..7a693e2 100644
> --- a/src/mesa/state_tracker/st_gen_mipmap.c
> +++ b/src/mesa/state_tracker/st_gen_mipmap.c
> @@ -44,64 +44,6 @@
>  
>  
>  /**
> - * one-time init for generate mipmap
> - * XXX Note: there may be other times we need no-op/simple state like this.
> - * In that case, some code refactoring would be good.
> - */
> -void
> -st_init_generate_mipmap(struct st_context *st)
> -{
> -   st->gen_mipmap = util_create_gen_mipmap(st->pipe, st->cso_context);
> -}
> -
> -
> -void
> -st_destroy_generate_mipmap(struct st_context *st)
> -{
> -   util_destroy_gen_mipmap(st->gen_mipmap);
> -   st->gen_mipmap = NULL;
> -}
> -
> -
> -/**
> - * Generate mipmap levels using hardware rendering.
> - * \return TRUE if successful, FALSE if not possible
> - */
> -static boolean
> -st_render_mipmap(struct st_context *st,
> -                 GLenum target,
> -                 struct st_texture_object *stObj,
> -                 uint baseLevel, uint lastLevel)
> -{
> -   struct pipe_context *pipe = st->pipe;
> -   struct pipe_screen *screen = pipe->screen;
> -   struct pipe_sampler_view *psv;
> -   const uint face = _mesa_tex_target_to_face(target);
> -
> -#if 0
> -   assert(target != GL_TEXTURE_3D); /* implemented but untested */
> -#endif
> -
> -   /* check if we can render in the texture's format */
> -   /* XXX should probably kill this and always use util_gen_mipmap
> -      since this implements a sw fallback as well */
> -   if (!screen->is_format_supported(screen, stObj->pt->format,
> -                                    stObj->pt->target,
> -                                    0, PIPE_BIND_RENDER_TARGET)) {
> -      return FALSE;
> -   }
> -
> -   psv = st_create_texture_sampler_view(pipe, stObj->pt);
> -
> -   util_gen_mipmap(st->gen_mipmap, psv, face, baseLevel, lastLevel,
> -                   PIPE_TEX_FILTER_LINEAR);
> -
> -   pipe_sampler_view_reference(&psv, NULL);
> -
> -   return TRUE;
> -}
> -
> -/**
>   * Compute the expected number of mipmap levels in the texture given
>   * the width/height/depth of the base image and the GL_TEXTURE_BASE_LEVEL/
>   * GL_TEXTURE_MAX_LEVEL settings.  This will tell us how many mipmap
> @@ -198,7 +140,9 @@ st_generate_mipmap(struct gl_context *ctx, GLenum target,
>     /* Try to generate the mipmap by rendering/texturing.  If that fails,
>      * use the software fallback.
>      */
> -   if (!st_render_mipmap(st, target, stObj, baseLevel, lastLevel)) {
> +   if (!util_gen_mipmap(st->pipe, stObj->pt,
> +                        _mesa_tex_target_to_face(target),
> +                        baseLevel, lastLevel, PIPE_TEX_FILTER_LINEAR)) {
>        /* since the util code actually also has a fallback, should
>           probably make it never fail and kill this */
>        _mesa_generate_mipmap(ctx, target, texObj);
> diff --git a/src/mesa/state_tracker/st_gen_mipmap.h b/src/mesa/state_tracker/st_gen_mipmap.h
> index 64eb397..4cc2089 100644
> --- a/src/mesa/state_tracker/st_gen_mipmap.h
> +++ b/src/mesa/state_tracker/st_gen_mipmap.h
> @@ -34,14 +34,6 @@
>  
>  struct gl_context;
>  struct gl_texture_object;
> -struct st_context;
> -
> -extern void
> -st_init_generate_mipmap(struct st_context *st);
> -
> -
> -extern void
> -st_destroy_generate_mipmap(struct st_context *st);
>  
>  
>  extern void
> 


More information about the mesa-dev mailing list