[Mesa-dev] [PATCH 2/2] gallium/u_gen_mipmap: rewrite using pipe->blit (v2)

Roland Scheidegger sroland at vmware.com
Fri Apr 4 18:24:44 PDT 2014


Am 05.04.2014 03:10, 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. 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
> 
> v2: add "first_layer", "last_layer" parameters, drop "face"
> ---
>  src/gallium/auxiliary/util/u_gen_mipmap.c | 539 ++++--------------------------
>  src/gallium/auxiliary/util/u_gen_mipmap.h |  23 +-
>  src/mesa/state_tracker/st_context.c       |   2 -
>  src/mesa/state_tracker/st_context.h       |   1 -
>  src/mesa/state_tracker/st_gen_mipmap.c    |  73 +---
>  src/mesa/state_tracker/st_gen_mipmap.h    |   8 -
>  6 files changed, 80 insertions(+), 566 deletions(-)
> 
> diff --git a/src/gallium/auxiliary/util/u_gen_mipmap.c b/src/gallium/auxiliary/util/u_gen_mipmap.c
> index a2f4218..2bbdd27 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,509 +31,97 @@
>   * @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 baseLevel  the first mipmap level to use as a src
> - * \param lastLevel  the last mipmap level to generate
> + * \param pt      the texture to generate mipmap levels for
> + * \param first_layer  the first layer to generate mipmap levels for
> + *                     (ignored for 3D textures)
> + * \param last_layer  the last layer to generate mipmap levels for
> + *                    (ignored for 3D textures)
> + * \param base_level  the first mipmap level to use as a src
> + * \param last_level  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,
> -                uint face, uint baseLevel, uint lastLevel, uint filter)
> +boolean
> +util_gen_mipmap(struct pipe_context *pipe, struct pipe_resource *pt,
> +                uint base_level, uint last_level,
> +                uint first_layer, uint last_layer, uint filter)
>  {
> -   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.
>      */
> -   assert(lastLevel <= pt->last_level);
> +   assert(last_level <= pt->last_level);
>  
>     /* If this fails, why are we here? */
> -   assert(lastLevel > baseLevel);
> -
> +   assert(last_level > base_level);
>     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);
> +   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;
>  
> -   /* 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);
> +   for (dstLevel = base_level + 1; dstLevel <= last_level; dstLevel++) {
> +      blit.src.level = dstLevel - 1;
> +      blit.dst.level = dstLevel;
>  
> -   set_fragment_shader(ctx, type, is_depth);
> -   set_vertex_shader(ctx);
> -   cso_set_geometry_shader_handle(ctx->cso, NULL);
> +      blit.src.box.width = u_minify(pt->width0, blit.src.level);
> +      blit.src.box.height = u_minify(pt->height0, blit.src.level);
>  
> -   /* init framebuffer state */
> -   memset(&fb, 0, sizeof(fb));
> +      blit.dst.box.width = u_minify(pt->width0, blit.dst.level);
> +      blit.dst.box.height = u_minify(pt->height0, blit.dst.level);
>  
> -   /* set min/mag to same filter for faster sw speed */
> -   ctx->sampler.mag_img_filter = filter;
> -   ctx->sampler.min_img_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);
> -
> -         /*
> -          * 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);
> -
> -         /* 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);
> -
> -         /*
> -          * 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_3D) {
> +         /* 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;
> +      }
> +      else {
> +         blit.src.box.z = blit.dst.box.z = first_layer;
> +         blit.src.box.depth = blit.dst.box.depth =
> +            (last_layer + 1 - first_layer);
>        }
> -   }
>  
> -   /* 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..1e2dc6b 100644
> --- a/src/gallium/auxiliary/util/u_gen_mipmap.h
> +++ b/src/gallium/auxiliary/util/u_gen_mipmap.h
> @@ -35,26 +35,13 @@
>  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,
> -                uint layer, uint baseLevel, uint lastLevel, uint filter);
> +extern boolean
> +util_gen_mipmap(struct pipe_context *pipe, struct pipe_resource *pt,
> +                uint base_level, uint last_level,
> +                uint first_layer, uint last_layer, uint filter);
>  
>  
>  #ifdef __cplusplus
> diff --git a/src/mesa/state_tracker/st_context.c b/src/mesa/state_tracker/st_context.c
> index 807a86f..c7f3ec6 100644
> --- a/src/mesa/state_tracker/st_context.c
> +++ b/src/mesa/state_tracker/st_context.c
> @@ -152,7 +152,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))
> @@ -254,7 +253,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 f1864fc..28f1886 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
> @@ -136,7 +78,7 @@ st_generate_mipmap(struct gl_context *ctx, GLenum target,
>     struct st_texture_object *stObj = st_texture_object(texObj);
>     struct pipe_resource *pt = st_get_texobj_resource(texObj);
>     const uint baseLevel = texObj->BaseLevel;
> -   uint lastLevel;
> +   uint lastLevel, first_layer, last_layer;
>     uint dstLevel;
>  
>     if (!pt)
> @@ -195,12 +137,19 @@ st_generate_mipmap(struct gl_context *ctx, GLenum target,
>  
>     assert(pt->last_level >= lastLevel);
>  
> +   if (pt->target == PIPE_TEXTURE_CUBE) {
> +      first_layer = last_layer = _mesa_tex_target_to_face(target);
> +   }
> +   else {
> +      first_layer = 0;
> +      last_layer = util_max_layer(pt, baseLevel);
> +   }
> +
>     /* Try to generate the mipmap by rendering/texturing.  If that fails,
>      * use the software fallback.
>      */
> -   if (!st_render_mipmap(st, target, stObj, baseLevel, lastLevel)) {
> -      /* since the util code actually also has a fallback, should
> -         probably make it never fail and kill this */
> +   if (!util_gen_mipmap(st->pipe, pt, baseLevel, lastLevel,
> +                        first_layer, last_layer, PIPE_TEX_FILTER_LINEAR)) {
>        _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
> 

Could you also add a format parameter?
Otherwise looks good to me.

Roland


More information about the mesa-dev mailing list