diff options
Diffstat (limited to 'src/gallium')
-rw-r--r-- | src/gallium/auxiliary/util/u_gen_mipmap.c | 540 | ||||
-rw-r--r-- | src/gallium/auxiliary/util/u_gen_mipmap.h | 23 |
2 files changed, 70 insertions, 493 deletions
diff --git a/src/gallium/auxiliary/util/u_gen_mipmap.c b/src/gallium/auxiliary/util/u_gen_mipmap.c index a2f42189fcd..aa8eaebb679 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,98 @@ * @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 format format of texture + * \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, + enum pipe_format format, 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(format); + boolean has_depth = + util_format_has_depth(util_format_description(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(format)) + return TRUE; + + if (!screen->is_format_supported(screen, 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 = 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 ffeff425ec7..99d01788848 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, + enum pipe_format format, uint base_level, uint last_level, + uint first_layer, uint last_layer, uint filter); #ifdef __cplusplus |