diff options
Diffstat (limited to 'src/gallium/drivers/softpipe')
51 files changed, 13038 insertions, 0 deletions
diff --git a/src/gallium/drivers/softpipe/Makefile b/src/gallium/drivers/softpipe/Makefile new file mode 100644 index 0000000000..35d426aa3e --- /dev/null +++ b/src/gallium/drivers/softpipe/Makefile @@ -0,0 +1,38 @@ +TOP = ../../../.. +include $(TOP)/configs/current + +LIBNAME = softpipe + +C_SOURCES = \ + sp_fs_exec.c \ + sp_fs_sse.c \ + sp_clear.c \ + sp_fence.c \ + sp_flush.c \ + sp_query.c \ + sp_context.c \ + sp_draw_arrays.c \ + sp_prim_vbuf.c \ + sp_quad_pipe.c \ + sp_quad_stipple.c \ + sp_quad_depth_test.c \ + sp_quad_fs.c \ + sp_quad_blend.c \ + sp_screen.c \ + sp_setup.c \ + sp_state_blend.c \ + sp_state_clip.c \ + sp_state_derived.c \ + sp_state_fs.c \ + sp_state_sampler.c \ + sp_state_so.c \ + sp_state_rasterizer.c \ + sp_state_surface.c \ + sp_state_vertex.c \ + sp_texture.c \ + sp_tex_sample.c \ + sp_tex_tile_cache.c \ + sp_tile_cache.c \ + sp_surface.c + +include ../../Makefile.template diff --git a/src/gallium/drivers/softpipe/SConscript b/src/gallium/drivers/softpipe/SConscript new file mode 100644 index 0000000000..be5917a688 --- /dev/null +++ b/src/gallium/drivers/softpipe/SConscript @@ -0,0 +1,40 @@ +Import('*') + +env = env.Clone() + +softpipe = env.ConvenienceLibrary( + target = 'softpipe', + source = [ + 'sp_fs_exec.c', + 'sp_fs_sse.c', + 'sp_clear.c', + 'sp_context.c', + 'sp_draw_arrays.c', + 'sp_fence.c', + 'sp_flush.c', + 'sp_prim_vbuf.c', + 'sp_setup.c', + 'sp_quad_blend.c', + 'sp_quad_pipe.c', + 'sp_quad_depth_test.c', + 'sp_quad_fs.c', + 'sp_quad_stipple.c', + 'sp_query.c', + 'sp_screen.c', + 'sp_state_blend.c', + 'sp_state_clip.c', + 'sp_state_derived.c', + 'sp_state_fs.c', + 'sp_state_rasterizer.c', + 'sp_state_sampler.c', + 'sp_state_so.c', + 'sp_state_surface.c', + 'sp_state_vertex.c', + 'sp_surface.c', + 'sp_tex_sample.c', + 'sp_tex_tile_cache.c', + 'sp_texture.c', + 'sp_tile_cache.c', + ]) + +Export('softpipe') diff --git a/src/gallium/drivers/softpipe/sp_clear.c b/src/gallium/drivers/softpipe/sp_clear.c new file mode 100644 index 0000000000..ae3f00f338 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_clear.c @@ -0,0 +1,84 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* Author: + * Brian Paul + * Michel Dänzer + */ + + +#include "pipe/p_defines.h" +#include "util/u_pack_color.h" +#include "sp_clear.h" +#include "sp_context.h" +#include "sp_query.h" +#include "sp_tile_cache.h" + + +/** + * Clear the given buffers to the specified values. + * No masking, no scissor (clear entire buffer). + */ +void +softpipe_clear(struct pipe_context *pipe, unsigned buffers, const float *rgba, + double depth, unsigned stencil) +{ + struct softpipe_context *softpipe = softpipe_context(pipe); + union util_color uc; + unsigned cv; + uint i; + + if (softpipe->no_rast) + return; + + if (!softpipe_check_render_cond(softpipe)) + return; + +#if 0 + softpipe_update_derived(softpipe); /* not needed?? */ +#endif + + if (buffers & PIPE_CLEAR_COLOR) { + for (i = 0; i < softpipe->framebuffer.nr_cbufs; i++) { + struct pipe_surface *ps = softpipe->framebuffer.cbufs[i]; + + util_pack_color(rgba, ps->format, &uc); + sp_tile_cache_clear(softpipe->cbuf_cache[i], rgba, uc.ui); + } + } + + if (buffers & PIPE_CLEAR_DEPTHSTENCIL) { + static const float zero[4] = { 0.0F, 0.0F, 0.0F, 0.0F }; + struct pipe_surface *ps = softpipe->framebuffer.zsbuf; + + cv = util_pack_z_stencil(ps->format, depth, stencil); + sp_tile_cache_clear(softpipe->zsbuf_cache, zero, cv); + } + + softpipe->dirty_render_cache = TRUE; +} diff --git a/src/gallium/drivers/softpipe/sp_clear.h b/src/gallium/drivers/softpipe/sp_clear.h new file mode 100644 index 0000000000..9be3b86fe9 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_clear.h @@ -0,0 +1,42 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* Author: + * Brian Paul + */ + +#ifndef SP_CLEAR_H +#define SP_CLEAR_H + +struct pipe_context; + +extern void +softpipe_clear(struct pipe_context *pipe, unsigned buffers, const float *rgba, + double depth, unsigned stencil); + + +#endif /* SP_CLEAR_H */ diff --git a/src/gallium/drivers/softpipe/sp_context.c b/src/gallium/drivers/softpipe/sp_context.c new file mode 100644 index 0000000000..12ef98aac7 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_context.c @@ -0,0 +1,381 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * Copyright 2008 VMware, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* Author: + * Keith Whitwell <keith@tungstengraphics.com> + */ + +#include "draw/draw_context.h" +#include "draw/draw_vbuf.h" +#include "pipe/p_defines.h" +#include "util/u_math.h" +#include "util/u_memory.h" +#include "util/u_inlines.h" +#include "tgsi/tgsi_exec.h" +#include "sp_clear.h" +#include "sp_context.h" +#include "sp_flush.h" +#include "sp_prim_vbuf.h" +#include "sp_state.h" +#include "sp_surface.h" +#include "sp_tile_cache.h" +#include "sp_tex_tile_cache.h" +#include "sp_texture.h" +#include "sp_query.h" + + + +/** + * Map any drawing surfaces which aren't already mapped + */ +void +softpipe_map_transfers(struct softpipe_context *sp) +{ + unsigned i; + + for (i = 0; i < sp->framebuffer.nr_cbufs; i++) { + sp_tile_cache_map_transfers(sp->cbuf_cache[i]); + } + + sp_tile_cache_map_transfers(sp->zsbuf_cache); +} + + +/** + * Unmap any mapped drawing surfaces + */ +void +softpipe_unmap_transfers(struct softpipe_context *sp) +{ + uint i; + + for (i = 0; i < sp->framebuffer.nr_cbufs; i++) { + sp_tile_cache_unmap_transfers(sp->cbuf_cache[i]); + } + + sp_tile_cache_unmap_transfers(sp->zsbuf_cache); +} + + +static void +softpipe_destroy( struct pipe_context *pipe ) +{ + struct softpipe_context *softpipe = softpipe_context( pipe ); + uint i; + + if (softpipe->draw) + draw_destroy( softpipe->draw ); + + softpipe->quad.shade->destroy( softpipe->quad.shade ); + softpipe->quad.depth_test->destroy( softpipe->quad.depth_test ); + softpipe->quad.blend->destroy( softpipe->quad.blend ); + softpipe->quad.pstipple->destroy( softpipe->quad.pstipple ); + + for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) { + sp_destroy_tile_cache(softpipe->cbuf_cache[i]); + pipe_surface_reference(&softpipe->framebuffer.cbufs[i], NULL); + } + + sp_destroy_tile_cache(softpipe->zsbuf_cache); + pipe_surface_reference(&softpipe->framebuffer.zsbuf, NULL); + + for (i = 0; i < PIPE_MAX_SAMPLERS; i++) { + sp_destroy_tex_tile_cache(softpipe->tex_cache[i]); + pipe_sampler_view_reference(&softpipe->sampler_views[i], NULL); + } + + for (i = 0; i < PIPE_MAX_VERTEX_SAMPLERS; i++) { + sp_destroy_tex_tile_cache(softpipe->vertex_tex_cache[i]); + pipe_sampler_view_reference(&softpipe->vertex_sampler_views[i], NULL); + } + + for (i = 0; i < PIPE_MAX_GEOMETRY_SAMPLERS; i++) { + sp_destroy_tex_tile_cache(softpipe->geometry_tex_cache[i]); + pipe_sampler_view_reference(&softpipe->geometry_sampler_views[i], NULL); + } + + for (i = 0; i < PIPE_SHADER_TYPES; i++) { + uint j; + + for (j = 0; j < PIPE_MAX_CONSTANT_BUFFERS; j++) { + if (softpipe->constants[i][j]) { + pipe_resource_reference(&softpipe->constants[i][j], NULL); + } + } + } + + tgsi_exec_machine_destroy(softpipe->fs_machine); + + FREE( softpipe ); +} + + +/** + * if (the texture is being used as a framebuffer surface) + * return PIPE_REFERENCED_FOR_WRITE + * else if (the texture is a bound texture source) + * return PIPE_REFERENCED_FOR_READ + * else + * return PIPE_UNREFERENCED + */ +static unsigned int +softpipe_is_resource_referenced( struct pipe_context *pipe, + struct pipe_resource *texture, + unsigned face, unsigned level) +{ + struct softpipe_context *softpipe = softpipe_context( pipe ); + unsigned i; + + if (texture->target == PIPE_BUFFER) + return PIPE_UNREFERENCED; + + /* check if any of the bound drawing surfaces are this texture */ + if (softpipe->dirty_render_cache) { + for (i = 0; i < softpipe->framebuffer.nr_cbufs; i++) { + if (softpipe->framebuffer.cbufs[i] && + softpipe->framebuffer.cbufs[i]->texture == texture) { + return PIPE_REFERENCED_FOR_WRITE; + } + } + if (softpipe->framebuffer.zsbuf && + softpipe->framebuffer.zsbuf->texture == texture) { + return PIPE_REFERENCED_FOR_WRITE; + } + } + + /* check if any of the tex_cache textures are this texture */ + for (i = 0; i < PIPE_MAX_SAMPLERS; i++) { + if (softpipe->tex_cache[i] && + softpipe->tex_cache[i]->texture == texture) + return PIPE_REFERENCED_FOR_READ; + } + for (i = 0; i < PIPE_MAX_VERTEX_SAMPLERS; i++) { + if (softpipe->vertex_tex_cache[i] && + softpipe->vertex_tex_cache[i]->texture == texture) + return PIPE_REFERENCED_FOR_READ; + } + for (i = 0; i < PIPE_MAX_GEOMETRY_SAMPLERS; i++) { + if (softpipe->geometry_tex_cache[i] && + softpipe->geometry_tex_cache[i]->texture == texture) + return PIPE_REFERENCED_FOR_READ; + } + + return PIPE_UNREFERENCED; +} + + + + +static void +softpipe_render_condition( struct pipe_context *pipe, + struct pipe_query *query, + uint mode ) +{ + struct softpipe_context *softpipe = softpipe_context( pipe ); + + softpipe->render_cond_query = query; + softpipe->render_cond_mode = mode; +} + + + +struct pipe_context * +softpipe_create_context( struct pipe_screen *screen, + void *priv ) +{ + struct softpipe_context *softpipe = CALLOC_STRUCT(softpipe_context); + uint i; + + util_init_math(); + +#ifdef PIPE_ARCH_X86 + softpipe->use_sse = !debug_get_bool_option( "GALLIUM_NOSSE", FALSE ); +#else + softpipe->use_sse = FALSE; +#endif + + softpipe->dump_fs = debug_get_bool_option( "GALLIUM_DUMP_FS", FALSE ); + softpipe->dump_gs = debug_get_bool_option( "SOFTPIPE_DUMP_GS", FALSE ); + + softpipe->pipe.winsys = NULL; + softpipe->pipe.screen = screen; + softpipe->pipe.destroy = softpipe_destroy; + softpipe->pipe.priv = priv; + + /* state setters */ + softpipe->pipe.create_blend_state = softpipe_create_blend_state; + softpipe->pipe.bind_blend_state = softpipe_bind_blend_state; + softpipe->pipe.delete_blend_state = softpipe_delete_blend_state; + + softpipe->pipe.create_sampler_state = softpipe_create_sampler_state; + softpipe->pipe.bind_fragment_sampler_states = softpipe_bind_sampler_states; + softpipe->pipe.bind_vertex_sampler_states = softpipe_bind_vertex_sampler_states; + softpipe->pipe.bind_geometry_sampler_states = softpipe_bind_geometry_sampler_states; + softpipe->pipe.delete_sampler_state = softpipe_delete_sampler_state; + + softpipe->pipe.create_depth_stencil_alpha_state = softpipe_create_depth_stencil_state; + softpipe->pipe.bind_depth_stencil_alpha_state = softpipe_bind_depth_stencil_state; + softpipe->pipe.delete_depth_stencil_alpha_state = softpipe_delete_depth_stencil_state; + + softpipe->pipe.create_rasterizer_state = softpipe_create_rasterizer_state; + softpipe->pipe.bind_rasterizer_state = softpipe_bind_rasterizer_state; + softpipe->pipe.delete_rasterizer_state = softpipe_delete_rasterizer_state; + + softpipe->pipe.create_fs_state = softpipe_create_fs_state; + softpipe->pipe.bind_fs_state = softpipe_bind_fs_state; + softpipe->pipe.delete_fs_state = softpipe_delete_fs_state; + + softpipe->pipe.create_vs_state = softpipe_create_vs_state; + softpipe->pipe.bind_vs_state = softpipe_bind_vs_state; + softpipe->pipe.delete_vs_state = softpipe_delete_vs_state; + + softpipe->pipe.create_gs_state = softpipe_create_gs_state; + softpipe->pipe.bind_gs_state = softpipe_bind_gs_state; + softpipe->pipe.delete_gs_state = softpipe_delete_gs_state; + + softpipe->pipe.create_vertex_elements_state = softpipe_create_vertex_elements_state; + softpipe->pipe.bind_vertex_elements_state = softpipe_bind_vertex_elements_state; + softpipe->pipe.delete_vertex_elements_state = softpipe_delete_vertex_elements_state; + + softpipe->pipe.create_stream_output_state = softpipe_create_stream_output_state; + softpipe->pipe.bind_stream_output_state = softpipe_bind_stream_output_state; + softpipe->pipe.delete_stream_output_state = softpipe_delete_stream_output_state; + + softpipe->pipe.set_blend_color = softpipe_set_blend_color; + softpipe->pipe.set_stencil_ref = softpipe_set_stencil_ref; + softpipe->pipe.set_clip_state = softpipe_set_clip_state; + softpipe->pipe.set_sample_mask = softpipe_set_sample_mask; + softpipe->pipe.set_constant_buffer = softpipe_set_constant_buffer; + softpipe->pipe.set_framebuffer_state = softpipe_set_framebuffer_state; + softpipe->pipe.set_polygon_stipple = softpipe_set_polygon_stipple; + softpipe->pipe.set_scissor_state = softpipe_set_scissor_state; + softpipe->pipe.set_fragment_sampler_views = softpipe_set_sampler_views; + softpipe->pipe.set_vertex_sampler_views = softpipe_set_vertex_sampler_views; + softpipe->pipe.set_geometry_sampler_views = softpipe_set_geometry_sampler_views; + softpipe->pipe.create_sampler_view = softpipe_create_sampler_view; + softpipe->pipe.sampler_view_destroy = softpipe_sampler_view_destroy; + softpipe->pipe.set_viewport_state = softpipe_set_viewport_state; + softpipe->pipe.set_stream_output_buffers = softpipe_set_stream_output_buffers; + softpipe->pipe.set_vertex_buffers = softpipe_set_vertex_buffers; + + softpipe->pipe.draw_arrays = softpipe_draw_arrays; + softpipe->pipe.draw_elements = softpipe_draw_elements; + softpipe->pipe.draw_range_elements = softpipe_draw_range_elements; + softpipe->pipe.draw_arrays_instanced = softpipe_draw_arrays_instanced; + softpipe->pipe.draw_elements_instanced = softpipe_draw_elements_instanced; + softpipe->pipe.draw_stream_output = softpipe_draw_stream_output; + + softpipe->pipe.clear = softpipe_clear; + softpipe->pipe.flush = softpipe_flush; + + softpipe->pipe.is_resource_referenced = softpipe_is_resource_referenced; + + softpipe_init_query_funcs( softpipe ); + softpipe_init_texture_funcs( &softpipe->pipe ); + + softpipe->pipe.render_condition = softpipe_render_condition; + + /* + * Alloc caches for accessing drawing surfaces and textures. + * Must be before quad stage setup! + */ + for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) + softpipe->cbuf_cache[i] = sp_create_tile_cache( &softpipe->pipe ); + softpipe->zsbuf_cache = sp_create_tile_cache( &softpipe->pipe ); + + for (i = 0; i < PIPE_MAX_SAMPLERS; i++) + softpipe->tex_cache[i] = sp_create_tex_tile_cache( &softpipe->pipe ); + for (i = 0; i < PIPE_MAX_VERTEX_SAMPLERS; i++) { + softpipe->vertex_tex_cache[i] = sp_create_tex_tile_cache( &softpipe->pipe ); + } + for (i = 0; i < PIPE_MAX_GEOMETRY_SAMPLERS; i++) { + softpipe->geometry_tex_cache[i] = sp_create_tex_tile_cache( &softpipe->pipe ); + } + + softpipe->fs_machine = tgsi_exec_machine_create(); + + /* setup quad rendering stages */ + softpipe->quad.shade = sp_quad_shade_stage(softpipe); + softpipe->quad.depth_test = sp_quad_depth_test_stage(softpipe); + softpipe->quad.blend = sp_quad_blend_stage(softpipe); + softpipe->quad.pstipple = sp_quad_polygon_stipple_stage(softpipe); + + + /* + * Create drawing context and plug our rendering stage into it. + */ + softpipe->draw = draw_create(&softpipe->pipe); + if (!softpipe->draw) + goto fail; + + draw_texture_samplers(softpipe->draw, + PIPE_SHADER_VERTEX, + PIPE_MAX_VERTEX_SAMPLERS, + (struct tgsi_sampler **) + softpipe->tgsi.vert_samplers_list); + + draw_texture_samplers(softpipe->draw, + PIPE_SHADER_GEOMETRY, + PIPE_MAX_GEOMETRY_SAMPLERS, + (struct tgsi_sampler **) + softpipe->tgsi.geom_samplers_list); + + if (debug_get_bool_option( "SP_NO_RAST", FALSE )) + softpipe->no_rast = TRUE; + + softpipe->vbuf_backend = sp_create_vbuf_backend(softpipe); + if (!softpipe->vbuf_backend) + goto fail; + + softpipe->vbuf = draw_vbuf_stage(softpipe->draw, softpipe->vbuf_backend); + if (!softpipe->vbuf) + goto fail; + + draw_set_rasterize_stage(softpipe->draw, softpipe->vbuf); + draw_set_render(softpipe->draw, softpipe->vbuf_backend); + + + /* plug in AA line/point stages */ + draw_install_aaline_stage(softpipe->draw, &softpipe->pipe); + draw_install_aapoint_stage(softpipe->draw, &softpipe->pipe); + + /* Do polygon stipple w/ texture map + frag prog? */ +#if DO_PSTIPPLE_IN_DRAW_MODULE + draw_install_pstipple_stage(softpipe->draw, &softpipe->pipe); +#endif + + draw_wide_point_sprites(softpipe->draw, TRUE); + + sp_init_surface_functions(softpipe); + + return &softpipe->pipe; + + fail: + softpipe_destroy(&softpipe->pipe); + return NULL; +} diff --git a/src/gallium/drivers/softpipe/sp_context.h b/src/gallium/drivers/softpipe/sp_context.h new file mode 100644 index 0000000000..53115a827d --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_context.h @@ -0,0 +1,199 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* Authors: Keith Whitwell <keith@tungstengraphics.com> + */ + +#ifndef SP_CONTEXT_H +#define SP_CONTEXT_H + +#include "pipe/p_context.h" + +#include "draw/draw_vertex.h" + +#include "sp_quad_pipe.h" + + +/** Do polygon stipple in the driver here, or in the draw module? */ +#define DO_PSTIPPLE_IN_DRAW_MODULE 1 + + +struct softpipe_vbuf_render; +struct draw_context; +struct draw_stage; +struct softpipe_tile_cache; +struct softpipe_tex_tile_cache; +struct sp_fragment_shader; +struct sp_vertex_shader; +struct sp_velems_state; +struct sp_so_state; + + +struct softpipe_context { + struct pipe_context pipe; /**< base class */ + + /** Constant state objects */ + struct pipe_blend_state *blend; + struct pipe_sampler_state *sampler[PIPE_MAX_SAMPLERS]; + struct pipe_sampler_state *vertex_samplers[PIPE_MAX_VERTEX_SAMPLERS]; + struct pipe_sampler_state *geometry_samplers[PIPE_MAX_GEOMETRY_SAMPLERS]; + struct pipe_depth_stencil_alpha_state *depth_stencil; + struct pipe_rasterizer_state *rasterizer; + struct sp_fragment_shader *fs; + struct sp_vertex_shader *vs; + struct sp_geometry_shader *gs; + struct sp_velems_state *velems; + struct sp_so_state *so; + + /** Other rendering state */ + struct pipe_blend_color blend_color; + struct pipe_stencil_ref stencil_ref; + struct pipe_clip_state clip; + struct pipe_resource *constants[PIPE_SHADER_TYPES][PIPE_MAX_CONSTANT_BUFFERS]; + struct pipe_framebuffer_state framebuffer; + struct pipe_poly_stipple poly_stipple; + struct pipe_scissor_state scissor; + struct pipe_sampler_view *sampler_views[PIPE_MAX_SAMPLERS]; + struct pipe_sampler_view *vertex_sampler_views[PIPE_MAX_VERTEX_SAMPLERS]; + struct pipe_sampler_view *geometry_sampler_views[PIPE_MAX_GEOMETRY_SAMPLERS]; + struct pipe_viewport_state viewport; + struct pipe_vertex_buffer vertex_buffer[PIPE_MAX_ATTRIBS]; + struct { + struct softpipe_resource *buffer[PIPE_MAX_SO_BUFFERS]; + int offset[PIPE_MAX_SO_BUFFERS]; + int so_count[PIPE_MAX_SO_BUFFERS]; + int num_buffers; + } so_target; + struct pipe_query_data_so_statistics so_stats; + + unsigned num_samplers; + unsigned num_sampler_views; + unsigned num_vertex_samplers; + unsigned num_vertex_sampler_views; + unsigned num_geometry_samplers; + unsigned num_geometry_sampler_views; + unsigned num_vertex_buffers; + + unsigned dirty; /**< Mask of SP_NEW_x flags */ + + /* Counter for occlusion queries. Note this supports overlapping + * queries. + */ + uint64_t occlusion_count; + unsigned active_query_count; + + /** Mapped vertex buffers */ + ubyte *mapped_vbuffer[PIPE_MAX_ATTRIBS]; + + /** Mapped constant buffers */ + const void *mapped_constants[PIPE_SHADER_TYPES][PIPE_MAX_CONSTANT_BUFFERS]; + + /** Vertex format */ + struct vertex_info vertex_info; + struct vertex_info vertex_info_vbuf; + + /** Which vertex shader output slot contains point size */ + int psize_slot; + + /** The reduced version of the primitive supplied by the state tracker */ + unsigned reduced_api_prim; + + /** Derived information about which winding orders to cull */ + unsigned cull_mode; + + /** + * The reduced primitive after unfilled triangles, wide-line decomposition, + * etc, are taken into account. This is the primitive type that's actually + * rasterized. + */ + unsigned reduced_prim; + + /** Derived from scissor and surface bounds: */ + struct pipe_scissor_state cliprect; + + unsigned line_stipple_counter; + + /** Conditional query object and mode */ + struct pipe_query *render_cond_query; + uint render_cond_mode; + + /** Software quad rendering pipeline */ + struct { + struct quad_stage *shade; + struct quad_stage *depth_test; + struct quad_stage *blend; + struct quad_stage *pstipple; + struct quad_stage *first; /**< points to one of the above stages */ + } quad; + + /** TGSI exec things */ + struct { + struct sp_sampler_varient *geom_samplers_list[PIPE_MAX_GEOMETRY_SAMPLERS]; + struct sp_sampler_varient *vert_samplers_list[PIPE_MAX_VERTEX_SAMPLERS]; + struct sp_sampler_varient *frag_samplers_list[PIPE_MAX_SAMPLERS]; + } tgsi; + + struct tgsi_exec_machine *fs_machine; + + /** The primitive drawing context */ + struct draw_context *draw; + + /** Draw module backend */ + struct vbuf_render *vbuf_backend; + struct draw_stage *vbuf; + + boolean dirty_render_cache; + + struct softpipe_tile_cache *cbuf_cache[PIPE_MAX_COLOR_BUFS]; + struct softpipe_tile_cache *zsbuf_cache; + + unsigned tex_timestamp; + struct softpipe_tex_tile_cache *tex_cache[PIPE_MAX_SAMPLERS]; + struct softpipe_tex_tile_cache *vertex_tex_cache[PIPE_MAX_VERTEX_SAMPLERS]; + struct softpipe_tex_tile_cache *geometry_tex_cache[PIPE_MAX_GEOMETRY_SAMPLERS]; + + unsigned use_sse : 1; + unsigned dump_fs : 1; + unsigned dump_gs : 1; + unsigned no_rast : 1; +}; + + +static INLINE struct softpipe_context * +softpipe_context( struct pipe_context *pipe ) +{ + return (struct softpipe_context *)pipe; +} + +void +softpipe_reset_sampler_varients(struct softpipe_context *softpipe); + +struct pipe_context * +softpipe_create_context( struct pipe_screen *, void *priv ); + + +#endif /* SP_CONTEXT_H */ diff --git a/src/gallium/drivers/softpipe/sp_draw_arrays.c b/src/gallium/drivers/softpipe/sp_draw_arrays.c new file mode 100644 index 0000000000..79daa68f3b --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_draw_arrays.c @@ -0,0 +1,298 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* Author: + * Brian Paul + * Keith Whitwell + */ + + +#include "pipe/p_defines.h" +#include "pipe/p_context.h" +#include "util/u_inlines.h" +#include "util/u_prim.h" + +#include "sp_context.h" +#include "sp_query.h" +#include "sp_state.h" +#include "sp_texture.h" + +#include "draw/draw_context.h" + + + + + + +/** + * Draw vertex arrays, with optional indexing. + * Basically, map the vertex buffers (and drawing surfaces), then hand off + * the drawing to the 'draw' module. + */ +static void +softpipe_draw_range_elements_instanced(struct pipe_context *pipe, + struct pipe_resource *indexBuffer, + unsigned indexSize, + int indexBias, + unsigned minIndex, + unsigned maxIndex, + unsigned mode, + unsigned start, + unsigned count, + unsigned startInstance, + unsigned instanceCount); + + +void +softpipe_draw_arrays(struct pipe_context *pipe, unsigned mode, + unsigned start, unsigned count) +{ + softpipe_draw_range_elements_instanced(pipe, + NULL, + 0, + 0, + 0, + 0xffffffff, + mode, + start, + count, + 0, + 1); +} + +void +softpipe_draw_stream_output(struct pipe_context *pipe, unsigned mode) +{ + struct softpipe_context *sp = softpipe_context(pipe); + struct draw_context *draw = sp->draw; + const unsigned start = 0; + const unsigned count = sp->so_target.so_count[0]; + void *buf = sp->so_target.buffer[0]->data; + int offset = sp->so_target.offset[0]; + + if (!softpipe_check_render_cond(sp) || + sp->so_target.num_buffers != 1) + return; + + sp->reduced_api_prim = u_reduced_prim(mode); + + if (sp->dirty) { + softpipe_update_derived(sp); + } + + softpipe_map_transfers(sp); + + /* Map so buffers */ + if (offset < 0) /* we were appending so start from beginning */ + offset = 0; + buf = (void*)((int32_t*)buf + offset); + draw_set_mapped_vertex_buffer(draw, 0, buf); + + draw_set_mapped_element_buffer_range(draw, + 0, 0, + start, + start + count - 1, + NULL); + + /* draw! */ + draw_arrays_instanced(draw, mode, start, count, 0, 1); + + /* unmap vertex/index buffers - will cause draw module to flush */ + draw_set_mapped_vertex_buffer(draw, 0, NULL); + + /* + * TODO: Flush only when a user vertex/index buffer is present + * (or even better, modify draw module to do this + * internally when this condition is seen?) + */ + draw_flush(draw); + + /* Note: leave drawing surfaces mapped */ + sp->dirty_render_cache = TRUE; +} + + +void +softpipe_draw_range_elements(struct pipe_context *pipe, + struct pipe_resource *indexBuffer, + unsigned indexSize, + int indexBias, + unsigned min_index, + unsigned max_index, + unsigned mode, unsigned start, unsigned count) +{ + softpipe_draw_range_elements_instanced(pipe, + indexBuffer, + indexSize, + indexBias, + min_index, + max_index, + mode, + start, + count, + 0, + 1); +} + + +void +softpipe_draw_elements(struct pipe_context *pipe, + struct pipe_resource *indexBuffer, + unsigned indexSize, int indexBias, + unsigned mode, unsigned start, unsigned count) +{ + softpipe_draw_range_elements_instanced(pipe, + indexBuffer, + indexSize, + indexBias, + 0, + 0xffffffff, + mode, + start, + count, + 0, + 1); +} + +void +softpipe_draw_arrays_instanced(struct pipe_context *pipe, + unsigned mode, + unsigned start, + unsigned count, + unsigned startInstance, + unsigned instanceCount) +{ + softpipe_draw_range_elements_instanced(pipe, + NULL, + 0, + 0, + 0, + 0xffffffff, + mode, + start, + count, + startInstance, + instanceCount); +} + +void +softpipe_draw_elements_instanced(struct pipe_context *pipe, + struct pipe_resource *indexBuffer, + unsigned indexSize, + int indexBias, + unsigned mode, + unsigned start, + unsigned count, + unsigned startInstance, + unsigned instanceCount) +{ + softpipe_draw_range_elements_instanced(pipe, + indexBuffer, + indexSize, + indexBias, + 0, + 0xffffffff, + mode, + start, + count, + startInstance, + instanceCount); +} + +static void +softpipe_draw_range_elements_instanced(struct pipe_context *pipe, + struct pipe_resource *indexBuffer, + unsigned indexSize, + int indexBias, + unsigned minIndex, + unsigned maxIndex, + unsigned mode, + unsigned start, + unsigned count, + unsigned startInstance, + unsigned instanceCount) +{ + struct softpipe_context *sp = softpipe_context(pipe); + struct draw_context *draw = sp->draw; + unsigned i; + + if (!softpipe_check_render_cond(sp)) + return; + + sp->reduced_api_prim = u_reduced_prim(mode); + + if (sp->dirty) { + softpipe_update_derived(sp); + } + + softpipe_map_transfers(sp); + + /* Map vertex buffers */ + for (i = 0; i < sp->num_vertex_buffers; i++) { + void *buf = softpipe_resource(sp->vertex_buffer[i].buffer)->data; + draw_set_mapped_vertex_buffer(draw, i, buf); + } + + /* Map index buffer, if present */ + if (indexBuffer) { + void *mapped_indexes = softpipe_resource(indexBuffer)->data; + draw_set_mapped_element_buffer_range(draw, + indexSize, + indexBias, + minIndex, + maxIndex, + mapped_indexes); + } else { + /* no index/element buffer */ + draw_set_mapped_element_buffer_range(draw, + 0, 0, + start, + start + count - 1, + NULL); + } + + /* draw! */ + draw_arrays_instanced(draw, mode, start, count, startInstance, instanceCount); + + /* unmap vertex/index buffers - will cause draw module to flush */ + for (i = 0; i < sp->num_vertex_buffers; i++) { + draw_set_mapped_vertex_buffer(draw, i, NULL); + } + if (indexBuffer) { + draw_set_mapped_element_buffer(draw, 0, 0, NULL); + } + + /* + * TODO: Flush only when a user vertex/index buffer is present + * (or even better, modify draw module to do this + * internally when this condition is seen?) + */ + draw_flush(draw); + + /* Note: leave drawing surfaces mapped */ + sp->dirty_render_cache = TRUE; +} diff --git a/src/gallium/drivers/softpipe/sp_fence.c b/src/gallium/drivers/softpipe/sp_fence.c new file mode 100644 index 0000000000..66c5214113 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_fence.c @@ -0,0 +1,70 @@ +/************************************************************************** + * + * Copyright 2010 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + **************************************************************************/ + + +#include "pipe/p_screen.h" +#include "util/u_debug.h" +#include "sp_fence.h" + + +static void +softpipe_fence_reference(struct pipe_screen *screen, + struct pipe_fence_handle **ptr, + struct pipe_fence_handle *fence) +{ + assert(!*ptr); + assert(!fence); +} + + +static int +softpipe_fence_signalled(struct pipe_screen *screen, + struct pipe_fence_handle *fence, + unsigned flags) +{ + assert(!fence); + return 0; +} + + +static int +softpipe_fence_finish(struct pipe_screen *screen, + struct pipe_fence_handle *fence, + unsigned flags) +{ + assert(!fence); + return 0; +} + + +void +softpipe_init_screen_fence_funcs(struct pipe_screen *screen) +{ + screen->fence_reference = softpipe_fence_reference; + screen->fence_finish = softpipe_fence_finish; + screen->fence_signalled = softpipe_fence_signalled; +} diff --git a/src/gallium/drivers/softpipe/sp_fence.h b/src/gallium/drivers/softpipe/sp_fence.h new file mode 100644 index 0000000000..39c33243bd --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_fence.h @@ -0,0 +1,40 @@ +/************************************************************************** + * + * Copyright 2010 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + **************************************************************************/ + + +#ifndef SP_FENCE_H_ +#define SP_FENCE_H_ + + +struct pipe_screen; + + +void +softpipe_init_screen_fence_funcs(struct pipe_screen *screen); + + +#endif /* SP_FENCE_H_ */ diff --git a/src/gallium/drivers/softpipe/sp_flush.c b/src/gallium/drivers/softpipe/sp_flush.c new file mode 100644 index 0000000000..4a53ef048f --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_flush.c @@ -0,0 +1,177 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* Author: + * Keith Whitwell <keith@tungstengraphics.com> + */ + + +#include "pipe/p_defines.h" +#include "draw/draw_context.h" +#include "sp_flush.h" +#include "sp_context.h" +#include "sp_state.h" +#include "sp_tile_cache.h" +#include "sp_tex_tile_cache.h" + + +void +softpipe_flush( struct pipe_context *pipe, + unsigned flags, + struct pipe_fence_handle **fence ) +{ + struct softpipe_context *softpipe = softpipe_context(pipe); + uint i; + + draw_flush(softpipe->draw); + + if (flags & PIPE_FLUSH_TEXTURE_CACHE) { + for (i = 0; i < softpipe->num_sampler_views; i++) { + sp_flush_tex_tile_cache(softpipe->tex_cache[i]); + } + for (i = 0; i < softpipe->num_vertex_sampler_views; i++) { + sp_flush_tex_tile_cache(softpipe->vertex_tex_cache[i]); + } + for (i = 0; i < softpipe->num_geometry_sampler_views; i++) { + sp_flush_tex_tile_cache(softpipe->geometry_tex_cache[i]); + } + } + + if (flags & PIPE_FLUSH_SWAPBUFFERS) { + /* If this is a swapbuffers, just flush color buffers. + * + * The zbuffer changes are not discarded, but held in the cache + * in the hope that a later clear will wipe them out. + */ + for (i = 0; i < softpipe->framebuffer.nr_cbufs; i++) + if (softpipe->cbuf_cache[i]) + sp_flush_tile_cache(softpipe->cbuf_cache[i]); + + /* Need this call for hardware buffers before swapbuffers. + * + * there should probably be another/different flush-type function + * that's called before swapbuffers because we don't always want + * to unmap surfaces when flushing. + */ + softpipe_unmap_transfers(softpipe); + } + else if (flags & PIPE_FLUSH_RENDER_CACHE) { + for (i = 0; i < softpipe->framebuffer.nr_cbufs; i++) + if (softpipe->cbuf_cache[i]) + sp_flush_tile_cache(softpipe->cbuf_cache[i]); + + if (softpipe->zsbuf_cache) + sp_flush_tile_cache(softpipe->zsbuf_cache); + + softpipe->dirty_render_cache = FALSE; + } + + /* Enable to dump BMPs of the color/depth buffers each frame */ +#if 0 + if(flags & PIPE_FLUSH_FRAME) { + static unsigned frame_no = 1; + static char filename[256]; + util_snprintf(filename, sizeof(filename), "cbuf_%u.bmp", frame_no); + debug_dump_surface_bmp(softpipe, filename, softpipe->framebuffer.cbufs[0]); + util_snprintf(filename, sizeof(filename), "zsbuf_%u.bmp", frame_no); + debug_dump_surface_bmp(softpipe, filename, softpipe->framebuffer.zsbuf); + ++frame_no; + } +#endif + + if (fence) + *fence = NULL; +} + + +/** + * Flush context if necessary. + * + * Returns FALSE if it would have block, but do_not_block was set, TRUE + * otherwise. + * + * TODO: move this logic to an auxiliary library? + */ +boolean +softpipe_flush_resource(struct pipe_context *pipe, + struct pipe_resource *texture, + unsigned face, + unsigned level, + unsigned flush_flags, + boolean read_only, + boolean cpu_access, + boolean do_not_block) +{ + unsigned referenced; + + referenced = pipe->is_resource_referenced(pipe, texture, face, level); + + if ((referenced & PIPE_REFERENCED_FOR_WRITE) || + ((referenced & PIPE_REFERENCED_FOR_READ) && !read_only)) { + + /* + * TODO: The semantics of these flush flags are too obtuse. They should + * disappear and the pipe driver should just ensure that all visible + * side-effects happen when they need to happen. + */ + if (referenced & PIPE_REFERENCED_FOR_WRITE) + flush_flags |= PIPE_FLUSH_RENDER_CACHE; + + if (referenced & PIPE_REFERENCED_FOR_READ) + flush_flags |= PIPE_FLUSH_TEXTURE_CACHE; + + if (cpu_access) { + /* + * Flush and wait. + */ + + struct pipe_fence_handle *fence = NULL; + + if (do_not_block) + return FALSE; + + pipe->flush(pipe, flush_flags, &fence); + + if (fence) { + /* + * This is for illustrative purposes only, as softpipe does not + * have fences. + */ + pipe->screen->fence_finish(pipe->screen, fence, 0); + pipe->screen->fence_reference(pipe->screen, &fence, NULL); + } + } else { + /* + * Just flush. + */ + + pipe->flush(pipe, flush_flags, NULL); + } + } + + return TRUE; +} diff --git a/src/gallium/drivers/softpipe/sp_flush.h b/src/gallium/drivers/softpipe/sp_flush.h new file mode 100644 index 0000000000..cb97482a71 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_flush.h @@ -0,0 +1,50 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef SP_FLUSH_H +#define SP_FLUSH_H + +#include "pipe/p_compiler.h" + +struct pipe_context; +struct pipe_fence_handle; + +void +softpipe_flush(struct pipe_context *pipe, unsigned flags, + struct pipe_fence_handle **fence); + +boolean +softpipe_flush_resource(struct pipe_context *pipe, + struct pipe_resource *texture, + unsigned face, + unsigned level, + unsigned flush_flags, + boolean read_only, + boolean cpu_access, + boolean do_not_block); + +#endif diff --git a/src/gallium/drivers/softpipe/sp_fs.h b/src/gallium/drivers/softpipe/sp_fs.h new file mode 100644 index 0000000000..4792ace3a3 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_fs.h @@ -0,0 +1,54 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* Authors: Keith Whitwell <keith@tungstengraphics.com> + */ + +#ifndef SP_FS_H +#define SP_FS_H + +struct sp_fragment_shader * +softpipe_create_fs_exec(struct softpipe_context *softpipe, + const struct pipe_shader_state *templ); + +struct sp_fragment_shader * +softpipe_create_fs_sse(struct softpipe_context *softpipe, + const struct pipe_shader_state *templ); + +struct sp_fragment_shader * +softpipe_create_fs_llvm(struct softpipe_context *softpipe, + const struct pipe_shader_state *templ); + +struct tgsi_interp_coef; +struct tgsi_exec_vector; + +void sp_setup_pos_vector(const struct tgsi_interp_coef *coef, + float x, float y, + struct tgsi_exec_vector *quadpos); + + +#endif diff --git a/src/gallium/drivers/softpipe/sp_fs_exec.c b/src/gallium/drivers/softpipe/sp_fs_exec.c new file mode 100644 index 0000000000..67e2c8f8bc --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_fs_exec.c @@ -0,0 +1,203 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/** + * Execute fragment shader using the TGSI interpreter. + */ + +#include "sp_context.h" +#include "sp_state.h" +#include "sp_fs.h" +#include "sp_quad.h" + +#include "pipe/p_state.h" +#include "pipe/p_defines.h" +#include "util/u_memory.h" +#include "tgsi/tgsi_exec.h" +#include "tgsi/tgsi_parse.h" + + +/** + * Subclass of sp_fragment_shader + */ +struct sp_exec_fragment_shader +{ + struct sp_fragment_shader base; + /* No other members for now */ +}; + + +/** cast wrapper */ +static INLINE struct sp_exec_fragment_shader * +sp_exec_fragment_shader(const struct sp_fragment_shader *base) +{ + return (struct sp_exec_fragment_shader *) base; +} + + +static void +exec_prepare( const struct sp_fragment_shader *base, + struct tgsi_exec_machine *machine, + struct tgsi_sampler **samplers ) +{ + /* + * Bind tokens/shader to the interpreter's machine state. + * Avoid redundant binding. + */ + if (machine->Tokens != base->shader.tokens) { + tgsi_exec_machine_bind_shader( machine, + base->shader.tokens, + PIPE_MAX_SAMPLERS, + samplers ); + } +} + + + +/** + * Compute quad X,Y,Z,W for the four fragments in a quad. + * + * This should really be part of the compiled shader. + */ +static void +setup_pos_vector(const struct tgsi_interp_coef *coef, + float x, float y, + struct tgsi_exec_vector *quadpos) +{ + uint chan; + /* do X */ + quadpos->xyzw[0].f[0] = x; + quadpos->xyzw[0].f[1] = x + 1; + quadpos->xyzw[0].f[2] = x; + quadpos->xyzw[0].f[3] = x + 1; + + /* do Y */ + quadpos->xyzw[1].f[0] = y; + quadpos->xyzw[1].f[1] = y; + quadpos->xyzw[1].f[2] = y + 1; + quadpos->xyzw[1].f[3] = y + 1; + + /* do Z and W for all fragments in the quad */ + for (chan = 2; chan < 4; chan++) { + const float dadx = coef->dadx[chan]; + const float dady = coef->dady[chan]; + const float a0 = coef->a0[chan] + dadx * x + dady * y; + quadpos->xyzw[chan].f[0] = a0; + quadpos->xyzw[chan].f[1] = a0 + dadx; + quadpos->xyzw[chan].f[2] = a0 + dady; + quadpos->xyzw[chan].f[3] = a0 + dadx + dady; + } +} + + +/* TODO: hide the machine struct in here somewhere, remove from this + * interface: + */ +static unsigned +exec_run( const struct sp_fragment_shader *base, + struct tgsi_exec_machine *machine, + struct quad_header *quad ) +{ + /* Compute X, Y, Z, W vals for this quad */ + setup_pos_vector(quad->posCoef, + (float)quad->input.x0, (float)quad->input.y0, + &machine->QuadPos); + + /* convert 0 to 1.0 and 1 to -1.0 */ + machine->Face = (float) (quad->input.facing * -2 + 1); + + quad->inout.mask &= tgsi_exec_machine_run( machine ); + if (quad->inout.mask == 0) + return FALSE; + + /* store outputs */ + { + const ubyte *sem_name = base->info.output_semantic_name; + const ubyte *sem_index = base->info.output_semantic_index; + const uint n = base->info.num_outputs; + uint i; + for (i = 0; i < n; i++) { + switch (sem_name[i]) { + case TGSI_SEMANTIC_COLOR: + { + uint cbuf = sem_index[i]; + + assert(sizeof(quad->output.color[cbuf]) == + sizeof(machine->Outputs[i])); + + /* copy float[4][4] result */ + memcpy(quad->output.color[cbuf], + &machine->Outputs[i], + sizeof(quad->output.color[0]) ); + } + break; + case TGSI_SEMANTIC_POSITION: + { + uint j; + for (j = 0; j < 4; j++) { + quad->output.depth[j] = machine->Outputs[i].xyzw[2].f[j]; + } + } + break; + } + } + } + + return TRUE; +} + + +static void +exec_delete( struct sp_fragment_shader *base ) +{ + FREE((void *) base->shader.tokens); + FREE(base); +} + + +struct sp_fragment_shader * +softpipe_create_fs_exec(struct softpipe_context *softpipe, + const struct pipe_shader_state *templ) +{ + struct sp_exec_fragment_shader *shader; + + /* Decide whether we'll be codegenerating this shader and if so do + * that now. + */ + + shader = CALLOC_STRUCT(sp_exec_fragment_shader); + if (!shader) + return NULL; + + /* we need to keep a local copy of the tokens */ + shader->base.shader.tokens = tgsi_dup_tokens(templ->tokens); + shader->base.prepare = exec_prepare; + shader->base.run = exec_run; + shader->base.delete = exec_delete; + + return &shader->base; +} diff --git a/src/gallium/drivers/softpipe/sp_fs_sse.c b/src/gallium/drivers/softpipe/sp_fs_sse.c new file mode 100644 index 0000000000..daa158df7c --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_fs_sse.c @@ -0,0 +1,243 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/** + * Execute fragment shader using runtime SSE code generation. + */ + +#include "sp_context.h" +#include "sp_state.h" +#include "sp_fs.h" +#include "sp_quad.h" + +#include "pipe/p_state.h" +#include "pipe/p_defines.h" +#include "util/u_memory.h" +#include "tgsi/tgsi_exec.h" +#include "tgsi/tgsi_sse2.h" + + +#if defined(PIPE_ARCH_X86) + +#include "rtasm/rtasm_x86sse.h" + + + +/** + * Subclass of sp_fragment_shader + */ +struct sp_sse_fragment_shader +{ + struct sp_fragment_shader base; + struct x86_function sse2_program; + tgsi_sse2_fs_function func; + float immediates[TGSI_EXEC_NUM_IMMEDIATES][4]; +}; + + +/** cast wrapper */ +static INLINE struct sp_sse_fragment_shader * +sp_sse_fragment_shader(const struct sp_fragment_shader *base) +{ + return (struct sp_sse_fragment_shader *) base; +} + + +static void +fs_sse_prepare( const struct sp_fragment_shader *base, + struct tgsi_exec_machine *machine, + struct tgsi_sampler **samplers ) +{ + machine->Samplers = samplers; +} + + + +/** + * Compute quad X,Y,Z,W for the four fragments in a quad. + * + * This should really be part of the compiled shader. + */ +static void +setup_pos_vector(const struct tgsi_interp_coef *coef, + float x, float y, + struct tgsi_exec_vector *quadpos) +{ + uint chan; + /* do X */ + quadpos->xyzw[0].f[0] = x; + quadpos->xyzw[0].f[1] = x + 1; + quadpos->xyzw[0].f[2] = x; + quadpos->xyzw[0].f[3] = x + 1; + + /* do Y */ + quadpos->xyzw[1].f[0] = y; + quadpos->xyzw[1].f[1] = y; + quadpos->xyzw[1].f[2] = y + 1; + quadpos->xyzw[1].f[3] = y + 1; + + /* do Z and W for all fragments in the quad */ + for (chan = 2; chan < 4; chan++) { + const float dadx = coef->dadx[chan]; + const float dady = coef->dady[chan]; + const float a0 = coef->a0[chan] + dadx * x + dady * y; + quadpos->xyzw[chan].f[0] = a0; + quadpos->xyzw[chan].f[1] = a0 + dadx; + quadpos->xyzw[chan].f[2] = a0 + dady; + quadpos->xyzw[chan].f[3] = a0 + dadx + dady; + } +} + + +/* TODO: codegenerate the whole run function, skip this wrapper. + * TODO: break dependency on tgsi_exec_machine struct + * TODO: push Position calculation into the generated shader + * TODO: process >1 quad at a time + */ +static unsigned +fs_sse_run( const struct sp_fragment_shader *base, + struct tgsi_exec_machine *machine, + struct quad_header *quad ) +{ + struct sp_sse_fragment_shader *shader = sp_sse_fragment_shader(base); + + /* Compute X, Y, Z, W vals for this quad -- place in temp[0] for now */ + setup_pos_vector(quad->posCoef, + (float)quad->input.x0, (float)quad->input.y0, + machine->Temps); + + /* init kill mask */ + tgsi_set_kill_mask(machine, 0x0); + tgsi_set_exec_mask(machine, 1, 1, 1, 1); + + shader->func( machine, + (const float (*)[4])machine->Consts[0], + (const float (*)[4])shader->immediates, + machine->InterpCoefs + /*, &machine->QuadPos*/ + ); + + quad->inout.mask &= ~(machine->Temps[TGSI_EXEC_TEMP_KILMASK_I].xyzw[TGSI_EXEC_TEMP_KILMASK_C].u[0]); + if (quad->inout.mask == 0) + return FALSE; + + /* store outputs */ + { + const ubyte *sem_name = base->info.output_semantic_name; + const ubyte *sem_index = base->info.output_semantic_index; + const uint n = base->info.num_outputs; + uint i; + for (i = 0; i < n; i++) { + switch (sem_name[i]) { + case TGSI_SEMANTIC_COLOR: + { + uint cbuf = sem_index[i]; + + assert(sizeof(quad->output.color[cbuf]) == + sizeof(machine->Outputs[i])); + + /* copy float[4][4] result */ + memcpy(quad->output.color[cbuf], + &machine->Outputs[i], + sizeof(quad->output.color[0]) ); + } + break; + case TGSI_SEMANTIC_POSITION: + { + uint j; + for (j = 0; j < 4; j++) { + quad->output.depth[j] = machine->Outputs[0].xyzw[2].f[j]; + } + } + break; + } + } + } + + return TRUE; +} + + +static void +fs_sse_delete( struct sp_fragment_shader *base ) +{ + struct sp_sse_fragment_shader *shader = sp_sse_fragment_shader(base); + + x86_release_func( &shader->sse2_program ); + FREE(shader); +} + + +struct sp_fragment_shader * +softpipe_create_fs_sse(struct softpipe_context *softpipe, + const struct pipe_shader_state *templ) +{ + struct sp_sse_fragment_shader *shader; + + if (!softpipe->use_sse) + return NULL; + + shader = CALLOC_STRUCT(sp_sse_fragment_shader); + if (!shader) + return NULL; + + x86_init_func( &shader->sse2_program ); + + if (!tgsi_emit_sse2( templ->tokens, &shader->sse2_program, + shader->immediates, FALSE )) { + FREE(shader); + return NULL; + } + + shader->func = (tgsi_sse2_fs_function) x86_get_func( &shader->sse2_program ); + if (!shader->func) { + x86_release_func( &shader->sse2_program ); + FREE(shader); + return NULL; + } + + shader->base.shader.tokens = NULL; /* don't hold reference to templ->tokens */ + shader->base.prepare = fs_sse_prepare; + shader->base.run = fs_sse_run; + shader->base.delete = fs_sse_delete; + + return &shader->base; +} + + +#else + +/* Maybe put this variant in the header file. + */ +struct sp_fragment_shader * +softpipe_create_fs_sse(struct softpipe_context *softpipe, + const struct pipe_shader_state *templ) +{ + return NULL; +} + +#endif diff --git a/src/gallium/drivers/softpipe/sp_prim_vbuf.c b/src/gallium/drivers/softpipe/sp_prim_vbuf.c new file mode 100644 index 0000000000..c60249dbfb --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_prim_vbuf.c @@ -0,0 +1,602 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/** + * Interface between 'draw' module's output and the softpipe rasterizer/setup + * code. When the 'draw' module has finished filling a vertex buffer, the + * draw_arrays() functions below will be called. Loop over the vertices and + * call the point/line/tri setup functions. + * + * Authors + * Brian Paul + */ + + +#include "sp_context.h" +#include "sp_setup.h" +#include "sp_state.h" +#include "sp_prim_vbuf.h" +#include "draw/draw_context.h" +#include "draw/draw_vbuf.h" +#include "util/u_memory.h" +#include "util/u_prim.h" + + +#define SP_MAX_VBUF_INDEXES 1024 +#define SP_MAX_VBUF_SIZE 4096 + +typedef const float (*cptrf4)[4]; + +/** + * Subclass of vbuf_render. + */ +struct softpipe_vbuf_render +{ + struct vbuf_render base; + struct softpipe_context *softpipe; + struct setup_context *setup; + + uint prim; + uint vertex_size; + uint nr_vertices; + uint vertex_buffer_size; + void *vertex_buffer; +}; + + +/** cast wrapper */ +static struct softpipe_vbuf_render * +softpipe_vbuf_render(struct vbuf_render *vbr) +{ + return (struct softpipe_vbuf_render *) vbr; +} + + +/** This tells the draw module about our desired vertex layout */ +static const struct vertex_info * +sp_vbuf_get_vertex_info(struct vbuf_render *vbr) +{ + struct softpipe_vbuf_render *cvbr = softpipe_vbuf_render(vbr); + return softpipe_get_vbuf_vertex_info(cvbr->softpipe); +} + + +static boolean +sp_vbuf_allocate_vertices(struct vbuf_render *vbr, + ushort vertex_size, ushort nr_vertices) +{ + struct softpipe_vbuf_render *cvbr = softpipe_vbuf_render(vbr); + unsigned size = vertex_size * nr_vertices; + + if (cvbr->vertex_buffer_size < size) { + align_free(cvbr->vertex_buffer); + cvbr->vertex_buffer = align_malloc(size, 16); + cvbr->vertex_buffer_size = size; + } + + cvbr->vertex_size = vertex_size; + cvbr->nr_vertices = nr_vertices; + + return cvbr->vertex_buffer != NULL; +} + + +static void +sp_vbuf_release_vertices(struct vbuf_render *vbr) +{ + /* keep the old allocation for next time */ +} + + +static void * +sp_vbuf_map_vertices(struct vbuf_render *vbr) +{ + struct softpipe_vbuf_render *cvbr = softpipe_vbuf_render(vbr); + return cvbr->vertex_buffer; +} + + +static void +sp_vbuf_unmap_vertices(struct vbuf_render *vbr, + ushort min_index, + ushort max_index ) +{ + struct softpipe_vbuf_render *cvbr = softpipe_vbuf_render(vbr); + assert( cvbr->vertex_buffer_size >= (max_index+1) * cvbr->vertex_size ); + (void) cvbr; + /* do nothing */ +} + + +static boolean +sp_vbuf_set_primitive(struct vbuf_render *vbr, unsigned prim) +{ + struct softpipe_vbuf_render *cvbr = softpipe_vbuf_render(vbr); + struct setup_context *setup_ctx = cvbr->setup; + + sp_setup_prepare( setup_ctx ); + + cvbr->softpipe->reduced_prim = u_reduced_prim(prim); + cvbr->prim = prim; + return TRUE; +} + + +static INLINE cptrf4 get_vert( const void *vertex_buffer, + int index, + int stride ) +{ + return (cptrf4)((char *)vertex_buffer + index * stride); +} + + +/** + * draw elements / indexed primitives + */ +static void +sp_vbuf_draw_elements(struct vbuf_render *vbr, const ushort *indices, uint nr) +{ + struct softpipe_vbuf_render *cvbr = softpipe_vbuf_render(vbr); + struct softpipe_context *softpipe = cvbr->softpipe; + const unsigned stride = softpipe->vertex_info_vbuf.size * sizeof(float); + const void *vertex_buffer = cvbr->vertex_buffer; + struct setup_context *setup = cvbr->setup; + const boolean flatshade_first = softpipe->rasterizer->flatshade_first; + unsigned i; + + switch (cvbr->prim) { + case PIPE_PRIM_POINTS: + for (i = 0; i < nr; i++) { + sp_setup_point( setup, + get_vert(vertex_buffer, indices[i-0], stride) ); + } + break; + + case PIPE_PRIM_LINES: + for (i = 1; i < nr; i += 2) { + sp_setup_line( setup, + get_vert(vertex_buffer, indices[i-1], stride), + get_vert(vertex_buffer, indices[i-0], stride) ); + } + break; + + case PIPE_PRIM_LINE_STRIP: + for (i = 1; i < nr; i ++) { + sp_setup_line( setup, + get_vert(vertex_buffer, indices[i-1], stride), + get_vert(vertex_buffer, indices[i-0], stride) ); + } + break; + + case PIPE_PRIM_LINE_LOOP: + for (i = 1; i < nr; i ++) { + sp_setup_line( setup, + get_vert(vertex_buffer, indices[i-1], stride), + get_vert(vertex_buffer, indices[i-0], stride) ); + } + if (nr) { + sp_setup_line( setup, + get_vert(vertex_buffer, indices[nr-1], stride), + get_vert(vertex_buffer, indices[0], stride) ); + } + break; + + case PIPE_PRIM_TRIANGLES: + for (i = 2; i < nr; i += 3) { + sp_setup_tri( setup, + get_vert(vertex_buffer, indices[i-2], stride), + get_vert(vertex_buffer, indices[i-1], stride), + get_vert(vertex_buffer, indices[i-0], stride) ); + } + break; + + case PIPE_PRIM_TRIANGLE_STRIP: + if (flatshade_first) { + for (i = 2; i < nr; i += 1) { + /* emit first triangle vertex as first triangle vertex */ + sp_setup_tri( setup, + get_vert(vertex_buffer, indices[i-2], stride), + get_vert(vertex_buffer, indices[i+(i&1)-1], stride), + get_vert(vertex_buffer, indices[i-(i&1)], stride) ); + + } + } + else { + for (i = 2; i < nr; i += 1) { + /* emit last triangle vertex as last triangle vertex */ + sp_setup_tri( setup, + get_vert(vertex_buffer, indices[i+(i&1)-2], stride), + get_vert(vertex_buffer, indices[i-(i&1)-1], stride), + get_vert(vertex_buffer, indices[i-0], stride) ); + } + } + break; + + case PIPE_PRIM_TRIANGLE_FAN: + if (flatshade_first) { + for (i = 2; i < nr; i += 1) { + /* emit first non-spoke vertex as first vertex */ + sp_setup_tri( setup, + get_vert(vertex_buffer, indices[i-1], stride), + get_vert(vertex_buffer, indices[i-0], stride), + get_vert(vertex_buffer, indices[0], stride) ); + } + } + else { + for (i = 2; i < nr; i += 1) { + /* emit last non-spoke vertex as last vertex */ + sp_setup_tri( setup, + get_vert(vertex_buffer, indices[0], stride), + get_vert(vertex_buffer, indices[i-1], stride), + get_vert(vertex_buffer, indices[i-0], stride) ); + } + } + break; + + case PIPE_PRIM_QUADS: + /* GL quads don't follow provoking vertex convention */ + if (flatshade_first) { + /* emit last quad vertex as first triangle vertex */ + for (i = 3; i < nr; i += 4) { + sp_setup_tri( setup, + get_vert(vertex_buffer, indices[i-0], stride), + get_vert(vertex_buffer, indices[i-3], stride), + get_vert(vertex_buffer, indices[i-2], stride) ); + + sp_setup_tri( setup, + get_vert(vertex_buffer, indices[i-0], stride), + get_vert(vertex_buffer, indices[i-2], stride), + get_vert(vertex_buffer, indices[i-1], stride) ); + } + } + else { + /* emit last quad vertex as last triangle vertex */ + for (i = 3; i < nr; i += 4) { + sp_setup_tri( setup, + get_vert(vertex_buffer, indices[i-3], stride), + get_vert(vertex_buffer, indices[i-2], stride), + get_vert(vertex_buffer, indices[i-0], stride) ); + + sp_setup_tri( setup, + get_vert(vertex_buffer, indices[i-2], stride), + get_vert(vertex_buffer, indices[i-1], stride), + get_vert(vertex_buffer, indices[i-0], stride) ); + } + } + break; + + case PIPE_PRIM_QUAD_STRIP: + /* GL quad strips don't follow provoking vertex convention */ + if (flatshade_first) { + /* emit last quad vertex as first triangle vertex */ + for (i = 3; i < nr; i += 2) { + sp_setup_tri( setup, + get_vert(vertex_buffer, indices[i-0], stride), + get_vert(vertex_buffer, indices[i-3], stride), + get_vert(vertex_buffer, indices[i-2], stride) ); + sp_setup_tri( setup, + get_vert(vertex_buffer, indices[i-0], stride), + get_vert(vertex_buffer, indices[i-1], stride), + get_vert(vertex_buffer, indices[i-3], stride) ); + } + } + else { + /* emit last quad vertex as last triangle vertex */ + for (i = 3; i < nr; i += 2) { + sp_setup_tri( setup, + get_vert(vertex_buffer, indices[i-3], stride), + get_vert(vertex_buffer, indices[i-2], stride), + get_vert(vertex_buffer, indices[i-0], stride) ); + sp_setup_tri( setup, + get_vert(vertex_buffer, indices[i-1], stride), + get_vert(vertex_buffer, indices[i-3], stride), + get_vert(vertex_buffer, indices[i-0], stride) ); + } + } + break; + + case PIPE_PRIM_POLYGON: + /* Almost same as tri fan but the _first_ vertex specifies the flat + * shading color. + */ + if (flatshade_first) { + /* emit first polygon vertex as first triangle vertex */ + for (i = 2; i < nr; i += 1) { + sp_setup_tri( setup, + get_vert(vertex_buffer, indices[0], stride), + get_vert(vertex_buffer, indices[i-1], stride), + get_vert(vertex_buffer, indices[i-0], stride) ); + } + } + else { + /* emit first polygon vertex as last triangle vertex */ + for (i = 2; i < nr; i += 1) { + sp_setup_tri( setup, + get_vert(vertex_buffer, indices[i-1], stride), + get_vert(vertex_buffer, indices[i-0], stride), + get_vert(vertex_buffer, indices[0], stride) ); + } + } + break; + + default: + assert(0); + } +} + + +/** + * This function is hit when the draw module is working in pass-through mode. + * It's up to us to convert the vertex array into point/line/tri prims. + */ +static void +sp_vbuf_draw_arrays(struct vbuf_render *vbr, uint start, uint nr) +{ + struct softpipe_vbuf_render *cvbr = softpipe_vbuf_render(vbr); + struct softpipe_context *softpipe = cvbr->softpipe; + struct setup_context *setup = cvbr->setup; + const unsigned stride = softpipe->vertex_info_vbuf.size * sizeof(float); + const void *vertex_buffer = + (void *) get_vert(cvbr->vertex_buffer, start, stride); + const boolean flatshade_first = softpipe->rasterizer->flatshade_first; + unsigned i; + + switch (cvbr->prim) { + case PIPE_PRIM_POINTS: + for (i = 0; i < nr; i++) { + sp_setup_point( setup, + get_vert(vertex_buffer, i-0, stride) ); + } + break; + + case PIPE_PRIM_LINES: + for (i = 1; i < nr; i += 2) { + sp_setup_line( setup, + get_vert(vertex_buffer, i-1, stride), + get_vert(vertex_buffer, i-0, stride) ); + } + break; + + case PIPE_PRIM_LINE_STRIP: + for (i = 1; i < nr; i ++) { + sp_setup_line( setup, + get_vert(vertex_buffer, i-1, stride), + get_vert(vertex_buffer, i-0, stride) ); + } + break; + + case PIPE_PRIM_LINE_LOOP: + for (i = 1; i < nr; i ++) { + sp_setup_line( setup, + get_vert(vertex_buffer, i-1, stride), + get_vert(vertex_buffer, i-0, stride) ); + } + if (nr) { + sp_setup_line( setup, + get_vert(vertex_buffer, nr-1, stride), + get_vert(vertex_buffer, 0, stride) ); + } + break; + + case PIPE_PRIM_TRIANGLES: + for (i = 2; i < nr; i += 3) { + sp_setup_tri( setup, + get_vert(vertex_buffer, i-2, stride), + get_vert(vertex_buffer, i-1, stride), + get_vert(vertex_buffer, i-0, stride) ); + } + break; + + case PIPE_PRIM_TRIANGLE_STRIP: + if (flatshade_first) { + for (i = 2; i < nr; i++) { + /* emit first triangle vertex as first triangle vertex */ + sp_setup_tri( setup, + get_vert(vertex_buffer, i-2, stride), + get_vert(vertex_buffer, i+(i&1)-1, stride), + get_vert(vertex_buffer, i-(i&1), stride) ); + } + } + else { + for (i = 2; i < nr; i++) { + /* emit last triangle vertex as last triangle vertex */ + sp_setup_tri( setup, + get_vert(vertex_buffer, i+(i&1)-2, stride), + get_vert(vertex_buffer, i-(i&1)-1, stride), + get_vert(vertex_buffer, i-0, stride) ); + } + } + break; + + case PIPE_PRIM_TRIANGLE_FAN: + if (flatshade_first) { + for (i = 2; i < nr; i += 1) { + /* emit first non-spoke vertex as first vertex */ + sp_setup_tri( setup, + get_vert(vertex_buffer, i-1, stride), + get_vert(vertex_buffer, i-0, stride), + get_vert(vertex_buffer, 0, stride) ); + } + } + else { + for (i = 2; i < nr; i += 1) { + /* emit last non-spoke vertex as last vertex */ + sp_setup_tri( setup, + get_vert(vertex_buffer, 0, stride), + get_vert(vertex_buffer, i-1, stride), + get_vert(vertex_buffer, i-0, stride) ); + } + } + break; + + case PIPE_PRIM_QUADS: + /* GL quads don't follow provoking vertex convention */ + if (flatshade_first) { + /* emit last quad vertex as first triangle vertex */ + for (i = 3; i < nr; i += 4) { + sp_setup_tri( setup, + get_vert(vertex_buffer, i-0, stride), + get_vert(vertex_buffer, i-3, stride), + get_vert(vertex_buffer, i-2, stride) ); + sp_setup_tri( setup, + get_vert(vertex_buffer, i-0, stride), + get_vert(vertex_buffer, i-2, stride), + get_vert(vertex_buffer, i-1, stride) ); + } + } + else { + /* emit last quad vertex as last triangle vertex */ + for (i = 3; i < nr; i += 4) { + sp_setup_tri( setup, + get_vert(vertex_buffer, i-3, stride), + get_vert(vertex_buffer, i-2, stride), + get_vert(vertex_buffer, i-0, stride) ); + sp_setup_tri( setup, + get_vert(vertex_buffer, i-2, stride), + get_vert(vertex_buffer, i-1, stride), + get_vert(vertex_buffer, i-0, stride) ); + } + } + break; + + case PIPE_PRIM_QUAD_STRIP: + /* GL quad strips don't follow provoking vertex convention */ + if (flatshade_first) { + /* emit last quad vertex as first triangle vertex */ + for (i = 3; i < nr; i += 2) { + sp_setup_tri( setup, + get_vert(vertex_buffer, i-0, stride), + get_vert(vertex_buffer, i-3, stride), + get_vert(vertex_buffer, i-2, stride) ); + sp_setup_tri( setup, + get_vert(vertex_buffer, i-0, stride), + get_vert(vertex_buffer, i-1, stride), + get_vert(vertex_buffer, i-3, stride) ); + } + } + else { + /* emit last quad vertex as last triangle vertex */ + for (i = 3; i < nr; i += 2) { + sp_setup_tri( setup, + get_vert(vertex_buffer, i-3, stride), + get_vert(vertex_buffer, i-2, stride), + get_vert(vertex_buffer, i-0, stride) ); + sp_setup_tri( setup, + get_vert(vertex_buffer, i-1, stride), + get_vert(vertex_buffer, i-3, stride), + get_vert(vertex_buffer, i-0, stride) ); + } + } + break; + + case PIPE_PRIM_POLYGON: + /* Almost same as tri fan but the _first_ vertex specifies the flat + * shading color. + */ + if (flatshade_first) { + /* emit first polygon vertex as first triangle vertex */ + for (i = 2; i < nr; i += 1) { + sp_setup_tri( setup, + get_vert(vertex_buffer, 0, stride), + get_vert(vertex_buffer, i-1, stride), + get_vert(vertex_buffer, i-0, stride) ); + } + } + else { + /* emit first polygon vertex as last triangle vertex */ + for (i = 2; i < nr; i += 1) { + sp_setup_tri( setup, + get_vert(vertex_buffer, i-1, stride), + get_vert(vertex_buffer, i-0, stride), + get_vert(vertex_buffer, 0, stride) ); + } + } + break; + + default: + assert(0); + } +} + +static void +sp_vbuf_so_info(struct vbuf_render *vbr, uint primitives, uint vertices) +{ + struct softpipe_vbuf_render *cvbr = softpipe_vbuf_render(vbr); + struct softpipe_context *softpipe = cvbr->softpipe; + unsigned i; + + for (i = 0; i < softpipe->so_target.num_buffers; ++i) { + softpipe->so_target.so_count[i] += vertices; + } + + softpipe->so_stats.num_primitives_written = primitives; + softpipe->so_stats.primitives_storage_needed = + vertices * 4 /*sizeof(float|int32)*/ * 4 /*x,y,z,w*/; +} + + +static void +sp_vbuf_destroy(struct vbuf_render *vbr) +{ + struct softpipe_vbuf_render *cvbr = softpipe_vbuf_render(vbr); + if (cvbr->vertex_buffer) + align_free(cvbr->vertex_buffer); + sp_setup_destroy_context(cvbr->setup); + FREE(cvbr); +} + + +/** + * Create the post-transform vertex handler for the given context. + */ +struct vbuf_render * +sp_create_vbuf_backend(struct softpipe_context *sp) +{ + struct softpipe_vbuf_render *cvbr = CALLOC_STRUCT(softpipe_vbuf_render); + + assert(sp->draw); + + cvbr->base.max_indices = SP_MAX_VBUF_INDEXES; + cvbr->base.max_vertex_buffer_bytes = SP_MAX_VBUF_SIZE; + + cvbr->base.get_vertex_info = sp_vbuf_get_vertex_info; + cvbr->base.allocate_vertices = sp_vbuf_allocate_vertices; + cvbr->base.map_vertices = sp_vbuf_map_vertices; + cvbr->base.unmap_vertices = sp_vbuf_unmap_vertices; + cvbr->base.set_primitive = sp_vbuf_set_primitive; + cvbr->base.draw_elements = sp_vbuf_draw_elements; + cvbr->base.draw_arrays = sp_vbuf_draw_arrays; + cvbr->base.release_vertices = sp_vbuf_release_vertices; + cvbr->base.set_stream_output_info = sp_vbuf_so_info; + cvbr->base.destroy = sp_vbuf_destroy; + + cvbr->softpipe = sp; + + cvbr->setup = sp_setup_create_context(cvbr->softpipe); + + return &cvbr->base; +} diff --git a/src/gallium/drivers/softpipe/sp_prim_vbuf.h b/src/gallium/drivers/softpipe/sp_prim_vbuf.h new file mode 100644 index 0000000000..ad01cc2f28 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_prim_vbuf.h @@ -0,0 +1,38 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef SP_VBUF_H +#define SP_VBUF_H + + +struct softpipe_context; + +extern struct vbuf_render * +sp_create_vbuf_backend(struct softpipe_context *softpipe); + + +#endif /* SP_VBUF_H */ diff --git a/src/gallium/drivers/softpipe/sp_public.h b/src/gallium/drivers/softpipe/sp_public.h new file mode 100644 index 0000000000..62d0903d87 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_public.h @@ -0,0 +1,10 @@ +#ifndef SP_PUBLIC_H +#define SP_PUBLIC_H + +struct pipe_screen; +struct sw_winsys; + +struct pipe_screen * +softpipe_create_screen(struct sw_winsys *winsys); + +#endif diff --git a/src/gallium/drivers/softpipe/sp_quad.h b/src/gallium/drivers/softpipe/sp_quad.h new file mode 100644 index 0000000000..a3236bd116 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_quad.h @@ -0,0 +1,106 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* Authors: Keith Whitwell <keith@tungstengraphics.com> + */ + +#ifndef SP_QUAD_H +#define SP_QUAD_H + +#include "pipe/p_state.h" +#include "tgsi/tgsi_exec.h" + + +#define QUAD_PRIM_POINT 1 +#define QUAD_PRIM_LINE 2 +#define QUAD_PRIM_TRI 3 + + +/* The rasterizer generates 2x2 quads of fragment and feeds them to + * the current fp_machine (see below). + * Remember that Y=0=top with Y increasing down the window. + */ +#define QUAD_TOP_LEFT 0 +#define QUAD_TOP_RIGHT 1 +#define QUAD_BOTTOM_LEFT 2 +#define QUAD_BOTTOM_RIGHT 3 + +#define MASK_TOP_LEFT (1 << QUAD_TOP_LEFT) +#define MASK_TOP_RIGHT (1 << QUAD_TOP_RIGHT) +#define MASK_BOTTOM_LEFT (1 << QUAD_BOTTOM_LEFT) +#define MASK_BOTTOM_RIGHT (1 << QUAD_BOTTOM_RIGHT) +#define MASK_ALL 0xf + + +/** + * Quad stage inputs (pos, coverage, front/back face, etc) + */ +struct quad_header_input +{ + int x0, y0; /**< quad window pos, always even */ + float coverage[QUAD_SIZE]; /**< fragment coverage for antialiasing */ + unsigned facing:1; /**< Front (0) or back (1) facing? */ + unsigned prim:2; /**< QUAD_PRIM_POINT, LINE, TRI */ +}; + + +/** + * Quad stage inputs/outputs. + */ +struct quad_header_inout +{ + unsigned mask:4; +}; + + +/** + * Quad stage outputs (color & depth). + */ +struct quad_header_output +{ + /** colors in SOA format (rrrr, gggg, bbbb, aaaa) */ + float color[PIPE_MAX_COLOR_BUFS][NUM_CHANNELS][QUAD_SIZE]; + float depth[QUAD_SIZE]; +}; + + +/** + * Encodes everything we need to know about a 2x2 pixel block. Uses + * "Channel-Serial" or "SoA" layout. + */ +struct quad_header { + struct quad_header_input input; + struct quad_header_inout inout; + struct quad_header_output output; + + /* Redundant/duplicated: + */ + const struct tgsi_interp_coef *posCoef; + const struct tgsi_interp_coef *coef; +}; + +#endif /* SP_QUAD_H */ diff --git a/src/gallium/drivers/softpipe/sp_quad_blend.c b/src/gallium/drivers/softpipe/sp_quad_blend.c new file mode 100644 index 0000000000..00187febf0 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_quad_blend.c @@ -0,0 +1,1054 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/** + * quad blending + * \author Brian Paul + */ + +#include "pipe/p_defines.h" +#include "util/u_math.h" +#include "util/u_memory.h" +#include "util/u_format.h" +#include "sp_context.h" +#include "sp_quad.h" +#include "sp_tile_cache.h" +#include "sp_quad_pipe.h" + + +#define VEC4_COPY(DST, SRC) \ +do { \ + DST[0] = SRC[0]; \ + DST[1] = SRC[1]; \ + DST[2] = SRC[2]; \ + DST[3] = SRC[3]; \ +} while(0) + +#define VEC4_SCALAR(DST, SRC) \ +do { \ + DST[0] = SRC; \ + DST[1] = SRC; \ + DST[2] = SRC; \ + DST[3] = SRC; \ +} while(0) + +#define VEC4_ADD(R, A, B) \ +do { \ + R[0] = A[0] + B[0]; \ + R[1] = A[1] + B[1]; \ + R[2] = A[2] + B[2]; \ + R[3] = A[3] + B[3]; \ +} while (0) + +#define VEC4_SUB(R, A, B) \ +do { \ + R[0] = A[0] - B[0]; \ + R[1] = A[1] - B[1]; \ + R[2] = A[2] - B[2]; \ + R[3] = A[3] - B[3]; \ +} while (0) + +/** Add and limit result to ceiling of 1.0 */ +#define VEC4_ADD_SAT(R, A, B) \ +do { \ + R[0] = A[0] + B[0]; if (R[0] > 1.0f) R[0] = 1.0f; \ + R[1] = A[1] + B[1]; if (R[1] > 1.0f) R[1] = 1.0f; \ + R[2] = A[2] + B[2]; if (R[2] > 1.0f) R[2] = 1.0f; \ + R[3] = A[3] + B[3]; if (R[3] > 1.0f) R[3] = 1.0f; \ +} while (0) + +/** Subtract and limit result to floor of 0.0 */ +#define VEC4_SUB_SAT(R, A, B) \ +do { \ + R[0] = A[0] - B[0]; if (R[0] < 0.0f) R[0] = 0.0f; \ + R[1] = A[1] - B[1]; if (R[1] < 0.0f) R[1] = 0.0f; \ + R[2] = A[2] - B[2]; if (R[2] < 0.0f) R[2] = 0.0f; \ + R[3] = A[3] - B[3]; if (R[3] < 0.0f) R[3] = 0.0f; \ +} while (0) + +#define VEC4_MUL(R, A, B) \ +do { \ + R[0] = A[0] * B[0]; \ + R[1] = A[1] * B[1]; \ + R[2] = A[2] * B[2]; \ + R[3] = A[3] * B[3]; \ +} while (0) + +#define VEC4_MIN(R, A, B) \ +do { \ + R[0] = (A[0] < B[0]) ? A[0] : B[0]; \ + R[1] = (A[1] < B[1]) ? A[1] : B[1]; \ + R[2] = (A[2] < B[2]) ? A[2] : B[2]; \ + R[3] = (A[3] < B[3]) ? A[3] : B[3]; \ +} while (0) + +#define VEC4_MAX(R, A, B) \ +do { \ + R[0] = (A[0] > B[0]) ? A[0] : B[0]; \ + R[1] = (A[1] > B[1]) ? A[1] : B[1]; \ + R[2] = (A[2] > B[2]) ? A[2] : B[2]; \ + R[3] = (A[3] > B[3]) ? A[3] : B[3]; \ +} while (0) + + + +static void +logicop_quad(struct quad_stage *qs, + float (*quadColor)[4], + float (*dest)[4]) +{ + struct softpipe_context *softpipe = qs->softpipe; + ubyte src[4][4], dst[4][4], res[4][4]; + uint *src4 = (uint *) src; + uint *dst4 = (uint *) dst; + uint *res4 = (uint *) res; + uint j; + + + /* convert to ubyte */ + for (j = 0; j < 4; j++) { /* loop over R,G,B,A channels */ + dst[j][0] = float_to_ubyte(dest[j][0]); /* P0 */ + dst[j][1] = float_to_ubyte(dest[j][1]); /* P1 */ + dst[j][2] = float_to_ubyte(dest[j][2]); /* P2 */ + dst[j][3] = float_to_ubyte(dest[j][3]); /* P3 */ + + src[j][0] = float_to_ubyte(quadColor[j][0]); /* P0 */ + src[j][1] = float_to_ubyte(quadColor[j][1]); /* P1 */ + src[j][2] = float_to_ubyte(quadColor[j][2]); /* P2 */ + src[j][3] = float_to_ubyte(quadColor[j][3]); /* P3 */ + } + + switch (softpipe->blend->logicop_func) { + case PIPE_LOGICOP_CLEAR: + for (j = 0; j < 4; j++) + res4[j] = 0; + break; + case PIPE_LOGICOP_NOR: + for (j = 0; j < 4; j++) + res4[j] = ~(src4[j] | dst4[j]); + break; + case PIPE_LOGICOP_AND_INVERTED: + for (j = 0; j < 4; j++) + res4[j] = ~src4[j] & dst4[j]; + break; + case PIPE_LOGICOP_COPY_INVERTED: + for (j = 0; j < 4; j++) + res4[j] = ~src4[j]; + break; + case PIPE_LOGICOP_AND_REVERSE: + for (j = 0; j < 4; j++) + res4[j] = src4[j] & ~dst4[j]; + break; + case PIPE_LOGICOP_INVERT: + for (j = 0; j < 4; j++) + res4[j] = ~dst4[j]; + break; + case PIPE_LOGICOP_XOR: + for (j = 0; j < 4; j++) + res4[j] = dst4[j] ^ src4[j]; + break; + case PIPE_LOGICOP_NAND: + for (j = 0; j < 4; j++) + res4[j] = ~(src4[j] & dst4[j]); + break; + case PIPE_LOGICOP_AND: + for (j = 0; j < 4; j++) + res4[j] = src4[j] & dst4[j]; + break; + case PIPE_LOGICOP_EQUIV: + for (j = 0; j < 4; j++) + res4[j] = ~(src4[j] ^ dst4[j]); + break; + case PIPE_LOGICOP_NOOP: + for (j = 0; j < 4; j++) + res4[j] = dst4[j]; + break; + case PIPE_LOGICOP_OR_INVERTED: + for (j = 0; j < 4; j++) + res4[j] = ~src4[j] | dst4[j]; + break; + case PIPE_LOGICOP_COPY: + for (j = 0; j < 4; j++) + res4[j] = src4[j]; + break; + case PIPE_LOGICOP_OR_REVERSE: + for (j = 0; j < 4; j++) + res4[j] = src4[j] | ~dst4[j]; + break; + case PIPE_LOGICOP_OR: + for (j = 0; j < 4; j++) + res4[j] = src4[j] | dst4[j]; + break; + case PIPE_LOGICOP_SET: + for (j = 0; j < 4; j++) + res4[j] = ~0; + break; + default: + assert(0); + } + + for (j = 0; j < 4; j++) { + quadColor[j][0] = ubyte_to_float(res[j][0]); + quadColor[j][1] = ubyte_to_float(res[j][1]); + quadColor[j][2] = ubyte_to_float(res[j][2]); + quadColor[j][3] = ubyte_to_float(res[j][3]); + } +} + + + +static void +blend_quad(struct quad_stage *qs, + float (*quadColor)[4], + float (*dest)[4], + unsigned cbuf, + boolean has_dst_alpha) +{ + static const float zero[4] = { 0, 0, 0, 0 }; + static const float one[4] = { 1, 1, 1, 1 }; + struct softpipe_context *softpipe = qs->softpipe; + float source[4][QUAD_SIZE] = { { 0 } }; + + /* + * Compute src/first term RGB + */ + switch (softpipe->blend->rt[cbuf].rgb_src_factor) { + case PIPE_BLENDFACTOR_ONE: + VEC4_COPY(source[0], quadColor[0]); /* R */ + VEC4_COPY(source[1], quadColor[1]); /* G */ + VEC4_COPY(source[2], quadColor[2]); /* B */ + break; + case PIPE_BLENDFACTOR_SRC_COLOR: + VEC4_MUL(source[0], quadColor[0], quadColor[0]); /* R */ + VEC4_MUL(source[1], quadColor[1], quadColor[1]); /* G */ + VEC4_MUL(source[2], quadColor[2], quadColor[2]); /* B */ + break; + case PIPE_BLENDFACTOR_SRC_ALPHA: + { + const float *alpha = quadColor[3]; + VEC4_MUL(source[0], quadColor[0], alpha); /* R */ + VEC4_MUL(source[1], quadColor[1], alpha); /* G */ + VEC4_MUL(source[2], quadColor[2], alpha); /* B */ + } + break; + case PIPE_BLENDFACTOR_DST_COLOR: + VEC4_MUL(source[0], quadColor[0], dest[0]); /* R */ + VEC4_MUL(source[1], quadColor[1], dest[1]); /* G */ + VEC4_MUL(source[2], quadColor[2], dest[2]); /* B */ + break; + case PIPE_BLENDFACTOR_DST_ALPHA: + if (has_dst_alpha) { + const float *alpha = dest[3]; + VEC4_MUL(source[0], quadColor[0], alpha); /* R */ + VEC4_MUL(source[1], quadColor[1], alpha); /* G */ + VEC4_MUL(source[2], quadColor[2], alpha); /* B */ + } + else { + VEC4_COPY(source[0], quadColor[0]); /* R */ + VEC4_COPY(source[1], quadColor[1]); /* G */ + VEC4_COPY(source[2], quadColor[2]); /* B */ + } + break; + case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE: + if (has_dst_alpha) { + const float *alpha = quadColor[3]; + float diff[4], temp[4]; + VEC4_SUB(diff, one, dest[3]); + VEC4_MIN(temp, alpha, diff); + VEC4_MUL(source[0], quadColor[0], temp); /* R */ + VEC4_MUL(source[1], quadColor[1], temp); /* G */ + VEC4_MUL(source[2], quadColor[2], temp); /* B */ + } + else { + VEC4_COPY(source[0], zero); /* R */ + VEC4_COPY(source[1], zero); /* G */ + VEC4_COPY(source[2], zero); /* B */ + } + break; + case PIPE_BLENDFACTOR_CONST_COLOR: + { + float comp[4]; + VEC4_SCALAR(comp, softpipe->blend_color.color[0]); /* R */ + VEC4_MUL(source[0], quadColor[0], comp); /* R */ + VEC4_SCALAR(comp, softpipe->blend_color.color[1]); /* G */ + VEC4_MUL(source[1], quadColor[1], comp); /* G */ + VEC4_SCALAR(comp, softpipe->blend_color.color[2]); /* B */ + VEC4_MUL(source[2], quadColor[2], comp); /* B */ + } + break; + case PIPE_BLENDFACTOR_CONST_ALPHA: + { + float alpha[4]; + VEC4_SCALAR(alpha, softpipe->blend_color.color[3]); + VEC4_MUL(source[0], quadColor[0], alpha); /* R */ + VEC4_MUL(source[1], quadColor[1], alpha); /* G */ + VEC4_MUL(source[2], quadColor[2], alpha); /* B */ + } + break; + case PIPE_BLENDFACTOR_SRC1_COLOR: + assert(0); /* to do */ + break; + case PIPE_BLENDFACTOR_SRC1_ALPHA: + assert(0); /* to do */ + break; + case PIPE_BLENDFACTOR_ZERO: + VEC4_COPY(source[0], zero); /* R */ + VEC4_COPY(source[1], zero); /* G */ + VEC4_COPY(source[2], zero); /* B */ + break; + case PIPE_BLENDFACTOR_INV_SRC_COLOR: + { + float inv_comp[4]; + VEC4_SUB(inv_comp, one, quadColor[0]); /* R */ + VEC4_MUL(source[0], quadColor[0], inv_comp); /* R */ + VEC4_SUB(inv_comp, one, quadColor[1]); /* G */ + VEC4_MUL(source[1], quadColor[1], inv_comp); /* G */ + VEC4_SUB(inv_comp, one, quadColor[2]); /* B */ + VEC4_MUL(source[2], quadColor[2], inv_comp); /* B */ + } + break; + case PIPE_BLENDFACTOR_INV_SRC_ALPHA: + { + float inv_alpha[4]; + VEC4_SUB(inv_alpha, one, quadColor[3]); + VEC4_MUL(source[0], quadColor[0], inv_alpha); /* R */ + VEC4_MUL(source[1], quadColor[1], inv_alpha); /* G */ + VEC4_MUL(source[2], quadColor[2], inv_alpha); /* B */ + } + break; + case PIPE_BLENDFACTOR_INV_DST_ALPHA: + if (has_dst_alpha) { + float inv_alpha[4]; + VEC4_SUB(inv_alpha, one, dest[3]); + VEC4_MUL(source[0], quadColor[0], inv_alpha); /* R */ + VEC4_MUL(source[1], quadColor[1], inv_alpha); /* G */ + VEC4_MUL(source[2], quadColor[2], inv_alpha); /* B */ + } + else { + VEC4_COPY(source[0], zero); /* R */ + VEC4_COPY(source[1], zero); /* G */ + VEC4_COPY(source[2], zero); /* B */ + } + break; + case PIPE_BLENDFACTOR_INV_DST_COLOR: + { + float inv_comp[4]; + VEC4_SUB(inv_comp, one, dest[0]); /* R */ + VEC4_MUL(source[0], quadColor[0], inv_comp); /* R */ + VEC4_SUB(inv_comp, one, dest[1]); /* G */ + VEC4_MUL(source[1], quadColor[1], inv_comp); /* G */ + VEC4_SUB(inv_comp, one, dest[2]); /* B */ + VEC4_MUL(source[2], quadColor[2], inv_comp); /* B */ + } + break; + case PIPE_BLENDFACTOR_INV_CONST_COLOR: + { + float inv_comp[4]; + /* R */ + VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color.color[0]); + VEC4_MUL(source[0], quadColor[0], inv_comp); + /* G */ + VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color.color[1]); + VEC4_MUL(source[1], quadColor[1], inv_comp); + /* B */ + VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color.color[2]); + VEC4_MUL(source[2], quadColor[2], inv_comp); + } + break; + case PIPE_BLENDFACTOR_INV_CONST_ALPHA: + { + float inv_alpha[4]; + VEC4_SCALAR(inv_alpha, 1.0f - softpipe->blend_color.color[3]); + VEC4_MUL(source[0], quadColor[0], inv_alpha); /* R */ + VEC4_MUL(source[1], quadColor[1], inv_alpha); /* G */ + VEC4_MUL(source[2], quadColor[2], inv_alpha); /* B */ + } + break; + case PIPE_BLENDFACTOR_INV_SRC1_COLOR: + assert(0); /* to do */ + break; + case PIPE_BLENDFACTOR_INV_SRC1_ALPHA: + assert(0); /* to do */ + break; + default: + assert(0); + } + + /* + * Compute src/first term A + */ + switch (softpipe->blend->rt[cbuf].alpha_src_factor) { + case PIPE_BLENDFACTOR_ONE: + VEC4_COPY(source[3], quadColor[3]); /* A */ + break; + case PIPE_BLENDFACTOR_SRC_COLOR: + /* fall-through */ + case PIPE_BLENDFACTOR_SRC_ALPHA: + { + const float *alpha = quadColor[3]; + VEC4_MUL(source[3], quadColor[3], alpha); /* A */ + } + break; + case PIPE_BLENDFACTOR_DST_COLOR: + /* fall-through */ + case PIPE_BLENDFACTOR_DST_ALPHA: + if (has_dst_alpha) + VEC4_MUL(source[3], quadColor[3], dest[3]); /* A */ + else + VEC4_COPY(source[3], quadColor[3]); /* A */ + break; + case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE: + /* multiply alpha by 1.0 */ + VEC4_COPY(source[3], quadColor[3]); /* A */ + break; + case PIPE_BLENDFACTOR_CONST_COLOR: + /* fall-through */ + case PIPE_BLENDFACTOR_CONST_ALPHA: + { + float comp[4]; + VEC4_SCALAR(comp, softpipe->blend_color.color[3]); /* A */ + VEC4_MUL(source[3], quadColor[3], comp); /* A */ + } + break; + case PIPE_BLENDFACTOR_ZERO: + VEC4_COPY(source[3], zero); /* A */ + break; + case PIPE_BLENDFACTOR_INV_SRC_COLOR: + /* fall-through */ + case PIPE_BLENDFACTOR_INV_SRC_ALPHA: + { + float inv_alpha[4]; + VEC4_SUB(inv_alpha, one, quadColor[3]); + VEC4_MUL(source[3], quadColor[3], inv_alpha); /* A */ + } + break; + case PIPE_BLENDFACTOR_INV_DST_COLOR: + /* fall-through */ + case PIPE_BLENDFACTOR_INV_DST_ALPHA: + if (has_dst_alpha) { + float inv_alpha[4]; + VEC4_SUB(inv_alpha, one, dest[3]); + VEC4_MUL(source[3], quadColor[3], inv_alpha); /* A */ + } + else { + VEC4_COPY(source[3], zero); /* A */ + } + break; + case PIPE_BLENDFACTOR_INV_CONST_COLOR: + /* fall-through */ + case PIPE_BLENDFACTOR_INV_CONST_ALPHA: + { + float inv_comp[4]; + /* A */ + VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color.color[3]); + VEC4_MUL(source[3], quadColor[3], inv_comp); + } + break; + default: + assert(0); + } + + + /* + * Compute dest/second term RGB + */ + switch (softpipe->blend->rt[cbuf].rgb_dst_factor) { + case PIPE_BLENDFACTOR_ONE: + /* dest = dest * 1 NO-OP, leave dest as-is */ + break; + case PIPE_BLENDFACTOR_SRC_COLOR: + VEC4_MUL(dest[0], dest[0], quadColor[0]); /* R */ + VEC4_MUL(dest[1], dest[1], quadColor[1]); /* G */ + VEC4_MUL(dest[2], dest[2], quadColor[2]); /* B */ + break; + case PIPE_BLENDFACTOR_SRC_ALPHA: + VEC4_MUL(dest[0], dest[0], quadColor[3]); /* R * A */ + VEC4_MUL(dest[1], dest[1], quadColor[3]); /* G * A */ + VEC4_MUL(dest[2], dest[2], quadColor[3]); /* B * A */ + break; + case PIPE_BLENDFACTOR_DST_ALPHA: + if (has_dst_alpha) { + VEC4_MUL(dest[0], dest[0], dest[3]); /* R * A */ + VEC4_MUL(dest[1], dest[1], dest[3]); /* G * A */ + VEC4_MUL(dest[2], dest[2], dest[3]); /* B * A */ + } + else { + /* dest = dest * 1 NO-OP, leave dest as-is */ + } + break; + case PIPE_BLENDFACTOR_DST_COLOR: + VEC4_MUL(dest[0], dest[0], dest[0]); /* R */ + VEC4_MUL(dest[1], dest[1], dest[1]); /* G */ + VEC4_MUL(dest[2], dest[2], dest[2]); /* B */ + break; + case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE: + if (has_dst_alpha) { + const float *alpha = quadColor[3]; + float diff[4], temp[4]; + VEC4_SUB(diff, one, dest[3]); + VEC4_MIN(temp, alpha, diff); + VEC4_MUL(dest[0], quadColor[0], temp); /* R */ + VEC4_MUL(dest[1], quadColor[1], temp); /* G */ + VEC4_MUL(dest[2], quadColor[2], temp); /* B */ + } + else { + VEC4_COPY(dest[0], zero); /* R */ + VEC4_COPY(dest[1], zero); /* G */ + VEC4_COPY(dest[2], zero); /* B */ + } + break; + case PIPE_BLENDFACTOR_CONST_COLOR: + { + float comp[4]; + VEC4_SCALAR(comp, softpipe->blend_color.color[0]); /* R */ + VEC4_MUL(dest[0], dest[0], comp); /* R */ + VEC4_SCALAR(comp, softpipe->blend_color.color[1]); /* G */ + VEC4_MUL(dest[1], dest[1], comp); /* G */ + VEC4_SCALAR(comp, softpipe->blend_color.color[2]); /* B */ + VEC4_MUL(dest[2], dest[2], comp); /* B */ + } + break; + case PIPE_BLENDFACTOR_CONST_ALPHA: + { + float comp[4]; + VEC4_SCALAR(comp, softpipe->blend_color.color[3]); /* A */ + VEC4_MUL(dest[0], dest[0], comp); /* R */ + VEC4_MUL(dest[1], dest[1], comp); /* G */ + VEC4_MUL(dest[2], dest[2], comp); /* B */ + } + break; + case PIPE_BLENDFACTOR_ZERO: + VEC4_COPY(dest[0], zero); /* R */ + VEC4_COPY(dest[1], zero); /* G */ + VEC4_COPY(dest[2], zero); /* B */ + break; + case PIPE_BLENDFACTOR_SRC1_COLOR: + case PIPE_BLENDFACTOR_SRC1_ALPHA: + /* XXX what are these? */ + assert(0); + break; + case PIPE_BLENDFACTOR_INV_SRC_COLOR: + { + float inv_comp[4]; + VEC4_SUB(inv_comp, one, quadColor[0]); /* R */ + VEC4_MUL(dest[0], inv_comp, dest[0]); /* R */ + VEC4_SUB(inv_comp, one, quadColor[1]); /* G */ + VEC4_MUL(dest[1], inv_comp, dest[1]); /* G */ + VEC4_SUB(inv_comp, one, quadColor[2]); /* B */ + VEC4_MUL(dest[2], inv_comp, dest[2]); /* B */ + } + break; + case PIPE_BLENDFACTOR_INV_SRC_ALPHA: + { + float one_minus_alpha[QUAD_SIZE]; + VEC4_SUB(one_minus_alpha, one, quadColor[3]); + VEC4_MUL(dest[0], dest[0], one_minus_alpha); /* R */ + VEC4_MUL(dest[1], dest[1], one_minus_alpha); /* G */ + VEC4_MUL(dest[2], dest[2], one_minus_alpha); /* B */ + } + break; + case PIPE_BLENDFACTOR_INV_DST_ALPHA: + if (has_dst_alpha) { + float inv_comp[4]; + VEC4_SUB(inv_comp, one, dest[3]); /* A */ + VEC4_MUL(dest[0], inv_comp, dest[0]); /* R */ + VEC4_MUL(dest[1], inv_comp, dest[1]); /* G */ + VEC4_MUL(dest[2], inv_comp, dest[2]); /* B */ + } + else { + VEC4_COPY(dest[0], zero); /* R */ + VEC4_COPY(dest[1], zero); /* G */ + VEC4_COPY(dest[2], zero); /* B */ + } + break; + case PIPE_BLENDFACTOR_INV_DST_COLOR: + { + float inv_comp[4]; + VEC4_SUB(inv_comp, one, dest[0]); /* R */ + VEC4_MUL(dest[0], dest[0], inv_comp); /* R */ + VEC4_SUB(inv_comp, one, dest[1]); /* G */ + VEC4_MUL(dest[1], dest[1], inv_comp); /* G */ + VEC4_SUB(inv_comp, one, dest[2]); /* B */ + VEC4_MUL(dest[2], dest[2], inv_comp); /* B */ + } + break; + case PIPE_BLENDFACTOR_INV_CONST_COLOR: + { + float inv_comp[4]; + /* R */ + VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color.color[0]); + VEC4_MUL(dest[0], dest[0], inv_comp); + /* G */ + VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color.color[1]); + VEC4_MUL(dest[1], dest[1], inv_comp); + /* B */ + VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color.color[2]); + VEC4_MUL(dest[2], dest[2], inv_comp); + } + break; + case PIPE_BLENDFACTOR_INV_CONST_ALPHA: + { + float inv_comp[4]; + VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color.color[3]); + VEC4_MUL(dest[0], dest[0], inv_comp); + VEC4_MUL(dest[1], dest[1], inv_comp); + VEC4_MUL(dest[2], dest[2], inv_comp); + } + break; + case PIPE_BLENDFACTOR_INV_SRC1_COLOR: + case PIPE_BLENDFACTOR_INV_SRC1_ALPHA: + /* XXX what are these? */ + assert(0); + break; + default: + assert(0); + } + + /* + * Compute dest/second term A + */ + switch (softpipe->blend->rt[cbuf].alpha_dst_factor) { + case PIPE_BLENDFACTOR_ONE: + /* dest = dest * 1 NO-OP, leave dest as-is */ + break; + case PIPE_BLENDFACTOR_SRC_COLOR: + /* fall-through */ + case PIPE_BLENDFACTOR_SRC_ALPHA: + VEC4_MUL(dest[3], dest[3], quadColor[3]); /* A * A */ + break; + case PIPE_BLENDFACTOR_DST_COLOR: + /* fall-through */ + case PIPE_BLENDFACTOR_DST_ALPHA: + if (has_dst_alpha) { + VEC4_MUL(dest[3], dest[3], dest[3]); /* A */ + } + else { + /* dest = dest * 1 NO-OP, leave dest as-is */ + } + break; + case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE: + /* dest = dest * 1 NO-OP, leave dest as-is */ + break; + case PIPE_BLENDFACTOR_CONST_COLOR: + /* fall-through */ + case PIPE_BLENDFACTOR_CONST_ALPHA: + { + float comp[4]; + VEC4_SCALAR(comp, softpipe->blend_color.color[3]); /* A */ + VEC4_MUL(dest[3], dest[3], comp); /* A */ + } + break; + case PIPE_BLENDFACTOR_ZERO: + VEC4_COPY(dest[3], zero); /* A */ + break; + case PIPE_BLENDFACTOR_INV_SRC_COLOR: + /* fall-through */ + case PIPE_BLENDFACTOR_INV_SRC_ALPHA: + { + float one_minus_alpha[QUAD_SIZE]; + VEC4_SUB(one_minus_alpha, one, quadColor[3]); + VEC4_MUL(dest[3], dest[3], one_minus_alpha); /* A */ + } + break; + case PIPE_BLENDFACTOR_INV_DST_COLOR: + /* fall-through */ + case PIPE_BLENDFACTOR_INV_DST_ALPHA: + if (has_dst_alpha) { + float inv_comp[4]; + VEC4_SUB(inv_comp, one, dest[3]); /* A */ + VEC4_MUL(dest[3], inv_comp, dest[3]); /* A */ + } + else { + VEC4_COPY(dest[3], zero); /* A */ + } + break; + case PIPE_BLENDFACTOR_INV_CONST_COLOR: + /* fall-through */ + case PIPE_BLENDFACTOR_INV_CONST_ALPHA: + { + float inv_comp[4]; + VEC4_SCALAR(inv_comp, 1.0f - softpipe->blend_color.color[3]); + VEC4_MUL(dest[3], dest[3], inv_comp); + } + break; + default: + assert(0); + } + + /* + * Combine RGB terms + */ + switch (softpipe->blend->rt[cbuf].rgb_func) { + case PIPE_BLEND_ADD: + VEC4_ADD_SAT(quadColor[0], source[0], dest[0]); /* R */ + VEC4_ADD_SAT(quadColor[1], source[1], dest[1]); /* G */ + VEC4_ADD_SAT(quadColor[2], source[2], dest[2]); /* B */ + break; + case PIPE_BLEND_SUBTRACT: + VEC4_SUB_SAT(quadColor[0], source[0], dest[0]); /* R */ + VEC4_SUB_SAT(quadColor[1], source[1], dest[1]); /* G */ + VEC4_SUB_SAT(quadColor[2], source[2], dest[2]); /* B */ + break; + case PIPE_BLEND_REVERSE_SUBTRACT: + VEC4_SUB_SAT(quadColor[0], dest[0], source[0]); /* R */ + VEC4_SUB_SAT(quadColor[1], dest[1], source[1]); /* G */ + VEC4_SUB_SAT(quadColor[2], dest[2], source[2]); /* B */ + break; + case PIPE_BLEND_MIN: + VEC4_MIN(quadColor[0], source[0], dest[0]); /* R */ + VEC4_MIN(quadColor[1], source[1], dest[1]); /* G */ + VEC4_MIN(quadColor[2], source[2], dest[2]); /* B */ + break; + case PIPE_BLEND_MAX: + VEC4_MAX(quadColor[0], source[0], dest[0]); /* R */ + VEC4_MAX(quadColor[1], source[1], dest[1]); /* G */ + VEC4_MAX(quadColor[2], source[2], dest[2]); /* B */ + break; + default: + assert(0); + } + + /* + * Combine A terms + */ + switch (softpipe->blend->rt[cbuf].alpha_func) { + case PIPE_BLEND_ADD: + VEC4_ADD_SAT(quadColor[3], source[3], dest[3]); /* A */ + break; + case PIPE_BLEND_SUBTRACT: + VEC4_SUB_SAT(quadColor[3], source[3], dest[3]); /* A */ + break; + case PIPE_BLEND_REVERSE_SUBTRACT: + VEC4_SUB_SAT(quadColor[3], dest[3], source[3]); /* A */ + break; + case PIPE_BLEND_MIN: + VEC4_MIN(quadColor[3], source[3], dest[3]); /* A */ + break; + case PIPE_BLEND_MAX: + VEC4_MAX(quadColor[3], source[3], dest[3]); /* A */ + break; + default: + assert(0); + } +} + +static void +colormask_quad(unsigned colormask, + float (*quadColor)[4], + float (*dest)[4]) +{ + /* R */ + if (!(colormask & PIPE_MASK_R)) + COPY_4V(quadColor[0], dest[0]); + + /* G */ + if (!(colormask & PIPE_MASK_G)) + COPY_4V(quadColor[1], dest[1]); + + /* B */ + if (!(colormask & PIPE_MASK_B)) + COPY_4V(quadColor[2], dest[2]); + + /* A */ + if (!(colormask & PIPE_MASK_A)) + COPY_4V(quadColor[3], dest[3]); +} + + +static void +blend_fallback(struct quad_stage *qs, + struct quad_header *quads[], + unsigned nr) +{ + struct softpipe_context *softpipe = qs->softpipe; + const struct pipe_blend_state *blend = softpipe->blend; + unsigned cbuf; + + for (cbuf = 0; cbuf < softpipe->framebuffer.nr_cbufs; cbuf++) + { + /* which blend/mask state index to use: */ + const uint blend_buf = blend->independent_blend_enable ? cbuf : 0; + float dest[4][QUAD_SIZE]; + struct softpipe_cached_tile *tile + = sp_get_cached_tile(softpipe->cbuf_cache[cbuf], + quads[0]->input.x0, + quads[0]->input.y0); + boolean has_dst_alpha + = util_format_has_alpha(softpipe->framebuffer.cbufs[cbuf]->format); + uint q, i, j; + + for (q = 0; q < nr; q++) { + struct quad_header *quad = quads[q]; + float (*quadColor)[4] = quad->output.color[cbuf]; + const int itx = (quad->input.x0 & (TILE_SIZE-1)); + const int ity = (quad->input.y0 & (TILE_SIZE-1)); + + /* get/swizzle dest colors + */ + for (j = 0; j < QUAD_SIZE; j++) { + int x = itx + (j & 1); + int y = ity + (j >> 1); + for (i = 0; i < 4; i++) { + dest[i][j] = tile->data.color[y][x][i]; + } + } + + + if (blend->logicop_enable) { + logicop_quad( qs, quadColor, dest ); + } + else if (blend->rt[blend_buf].blend_enable) { + blend_quad( qs, quadColor, dest, cbuf, has_dst_alpha ); + } + + if (blend->rt[blend_buf].colormask != 0xf) + colormask_quad( blend->rt[cbuf].colormask, quadColor, dest); + + /* Output color values + */ + for (j = 0; j < QUAD_SIZE; j++) { + if (quad->inout.mask & (1 << j)) { + int x = itx + (j & 1); + int y = ity + (j >> 1); + for (i = 0; i < 4; i++) { /* loop over color chans */ + tile->data.color[y][x][i] = quadColor[i][j]; + } + } + } + } + } +} + + +static void +blend_single_add_src_alpha_inv_src_alpha(struct quad_stage *qs, + struct quad_header *quads[], + unsigned nr) +{ + static const float one[4] = { 1, 1, 1, 1 }; + float one_minus_alpha[QUAD_SIZE]; + float dest[4][QUAD_SIZE]; + float source[4][QUAD_SIZE]; + uint i, j, q; + + struct softpipe_cached_tile *tile + = sp_get_cached_tile(qs->softpipe->cbuf_cache[0], + quads[0]->input.x0, + quads[0]->input.y0); + + for (q = 0; q < nr; q++) { + struct quad_header *quad = quads[q]; + float (*quadColor)[4] = quad->output.color[0]; + const float *alpha = quadColor[3]; + const int itx = (quad->input.x0 & (TILE_SIZE-1)); + const int ity = (quad->input.y0 & (TILE_SIZE-1)); + + /* get/swizzle dest colors */ + for (j = 0; j < QUAD_SIZE; j++) { + int x = itx + (j & 1); + int y = ity + (j >> 1); + for (i = 0; i < 4; i++) { + dest[i][j] = tile->data.color[y][x][i]; + } + } + + VEC4_MUL(source[0], quadColor[0], alpha); /* R */ + VEC4_MUL(source[1], quadColor[1], alpha); /* G */ + VEC4_MUL(source[2], quadColor[2], alpha); /* B */ + VEC4_MUL(source[3], quadColor[3], alpha); /* A */ + + VEC4_SUB(one_minus_alpha, one, alpha); + VEC4_MUL(dest[0], dest[0], one_minus_alpha); /* R */ + VEC4_MUL(dest[1], dest[1], one_minus_alpha); /* G */ + VEC4_MUL(dest[2], dest[2], one_minus_alpha); /* B */ + VEC4_MUL(dest[3], dest[3], one_minus_alpha); /* B */ + + VEC4_ADD_SAT(quadColor[0], source[0], dest[0]); /* R */ + VEC4_ADD_SAT(quadColor[1], source[1], dest[1]); /* G */ + VEC4_ADD_SAT(quadColor[2], source[2], dest[2]); /* B */ + VEC4_ADD_SAT(quadColor[3], source[3], dest[3]); /* A */ + + for (j = 0; j < QUAD_SIZE; j++) { + if (quad->inout.mask & (1 << j)) { + int x = itx + (j & 1); + int y = ity + (j >> 1); + for (i = 0; i < 4; i++) { /* loop over color chans */ + tile->data.color[y][x][i] = quadColor[i][j]; + } + } + } + } +} + +static void +blend_single_add_one_one(struct quad_stage *qs, + struct quad_header *quads[], + unsigned nr) +{ + float dest[4][QUAD_SIZE]; + uint i, j, q; + + struct softpipe_cached_tile *tile + = sp_get_cached_tile(qs->softpipe->cbuf_cache[0], + quads[0]->input.x0, + quads[0]->input.y0); + + for (q = 0; q < nr; q++) { + struct quad_header *quad = quads[q]; + float (*quadColor)[4] = quad->output.color[0]; + const int itx = (quad->input.x0 & (TILE_SIZE-1)); + const int ity = (quad->input.y0 & (TILE_SIZE-1)); + + /* get/swizzle dest colors */ + for (j = 0; j < QUAD_SIZE; j++) { + int x = itx + (j & 1); + int y = ity + (j >> 1); + for (i = 0; i < 4; i++) { + dest[i][j] = tile->data.color[y][x][i]; + } + } + + VEC4_ADD_SAT(quadColor[0], quadColor[0], dest[0]); /* R */ + VEC4_ADD_SAT(quadColor[1], quadColor[1], dest[1]); /* G */ + VEC4_ADD_SAT(quadColor[2], quadColor[2], dest[2]); /* B */ + VEC4_ADD_SAT(quadColor[3], quadColor[3], dest[3]); /* A */ + + for (j = 0; j < QUAD_SIZE; j++) { + if (quad->inout.mask & (1 << j)) { + int x = itx + (j & 1); + int y = ity + (j >> 1); + for (i = 0; i < 4; i++) { /* loop over color chans */ + tile->data.color[y][x][i] = quadColor[i][j]; + } + } + } + } +} + + +static void +single_output_color(struct quad_stage *qs, + struct quad_header *quads[], + unsigned nr) +{ + uint i, j, q; + + struct softpipe_cached_tile *tile + = sp_get_cached_tile(qs->softpipe->cbuf_cache[0], + quads[0]->input.x0, + quads[0]->input.y0); + + for (q = 0; q < nr; q++) { + struct quad_header *quad = quads[q]; + float (*quadColor)[4] = quad->output.color[0]; + const int itx = (quad->input.x0 & (TILE_SIZE-1)); + const int ity = (quad->input.y0 & (TILE_SIZE-1)); + + for (j = 0; j < QUAD_SIZE; j++) { + if (quad->inout.mask & (1 << j)) { + int x = itx + (j & 1); + int y = ity + (j >> 1); + for (i = 0; i < 4; i++) { /* loop over color chans */ + tile->data.color[y][x][i] = quadColor[i][j]; + } + } + } + } +} + +static void +blend_noop(struct quad_stage *qs, + struct quad_header *quads[], + unsigned nr) +{ +} + + +static void +choose_blend_quad(struct quad_stage *qs, + struct quad_header *quads[], + unsigned nr) +{ + struct softpipe_context *softpipe = qs->softpipe; + const struct pipe_blend_state *blend = softpipe->blend; + + qs->run = blend_fallback; + + if (softpipe->framebuffer.nr_cbufs == 0) { + qs->run = blend_noop; + } + else if (!softpipe->blend->logicop_enable && + softpipe->blend->rt[0].colormask == 0xf && + softpipe->framebuffer.nr_cbufs == 1) + { + if (!blend->rt[0].blend_enable) { + qs->run = single_output_color; + } + else if (blend->rt[0].rgb_src_factor == blend->rt[0].alpha_src_factor && + blend->rt[0].rgb_dst_factor == blend->rt[0].alpha_dst_factor && + blend->rt[0].rgb_func == blend->rt[0].alpha_func) + { + if (blend->rt[0].alpha_func == PIPE_BLEND_ADD) { + if (blend->rt[0].rgb_src_factor == PIPE_BLENDFACTOR_ONE && + blend->rt[0].rgb_dst_factor == PIPE_BLENDFACTOR_ONE) { + qs->run = blend_single_add_one_one; + } + else if (blend->rt[0].rgb_src_factor == PIPE_BLENDFACTOR_SRC_ALPHA && + blend->rt[0].rgb_dst_factor == PIPE_BLENDFACTOR_INV_SRC_ALPHA) + qs->run = blend_single_add_src_alpha_inv_src_alpha; + + } + } + } + + qs->run(qs, quads, nr); +} + + +static void blend_begin(struct quad_stage *qs) +{ + qs->run = choose_blend_quad; +} + + +static void blend_destroy(struct quad_stage *qs) +{ + FREE( qs ); +} + + +struct quad_stage *sp_quad_blend_stage( struct softpipe_context *softpipe ) +{ + struct quad_stage *stage = CALLOC_STRUCT(quad_stage); + + stage->softpipe = softpipe; + stage->begin = blend_begin; + stage->run = choose_blend_quad; + stage->destroy = blend_destroy; + + return stage; +} diff --git a/src/gallium/drivers/softpipe/sp_quad_depth_test.c b/src/gallium/drivers/softpipe/sp_quad_depth_test.c new file mode 100644 index 0000000000..72117c233e --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_quad_depth_test.c @@ -0,0 +1,889 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * Copyright 2010 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/** + * \brief Quad depth / stencil testing + */ + +#include "pipe/p_defines.h" +#include "util/u_format.h" +#include "util/u_memory.h" +#include "tgsi/tgsi_scan.h" +#include "sp_context.h" +#include "sp_quad.h" +#include "sp_quad_pipe.h" +#include "sp_tile_cache.h" +#include "sp_state.h" /* for sp_fragment_shader */ + + +struct depth_data { + struct pipe_surface *ps; + enum pipe_format format; + unsigned bzzzz[QUAD_SIZE]; /**< Z values fetched from depth buffer */ + unsigned qzzzz[QUAD_SIZE]; /**< Z values from the quad */ + ubyte stencilVals[QUAD_SIZE]; + struct softpipe_cached_tile *tile; +}; + + + +static void +get_depth_stencil_values( struct depth_data *data, + const struct quad_header *quad ) +{ + unsigned j; + const struct softpipe_cached_tile *tile = data->tile; + + switch (data->format) { + case PIPE_FORMAT_Z16_UNORM: + for (j = 0; j < QUAD_SIZE; j++) { + int x = quad->input.x0 % TILE_SIZE + (j & 1); + int y = quad->input.y0 % TILE_SIZE + (j >> 1); + data->bzzzz[j] = tile->data.depth16[y][x]; + } + break; + case PIPE_FORMAT_Z32_UNORM: + for (j = 0; j < QUAD_SIZE; j++) { + int x = quad->input.x0 % TILE_SIZE + (j & 1); + int y = quad->input.y0 % TILE_SIZE + (j >> 1); + data->bzzzz[j] = tile->data.depth32[y][x]; + } + break; + case PIPE_FORMAT_Z24X8_UNORM: + case PIPE_FORMAT_Z24_UNORM_S8_USCALED: + for (j = 0; j < QUAD_SIZE; j++) { + int x = quad->input.x0 % TILE_SIZE + (j & 1); + int y = quad->input.y0 % TILE_SIZE + (j >> 1); + data->bzzzz[j] = tile->data.depth32[y][x] & 0xffffff; + data->stencilVals[j] = tile->data.depth32[y][x] >> 24; + } + break; + case PIPE_FORMAT_X8Z24_UNORM: + case PIPE_FORMAT_S8_USCALED_Z24_UNORM: + for (j = 0; j < QUAD_SIZE; j++) { + int x = quad->input.x0 % TILE_SIZE + (j & 1); + int y = quad->input.y0 % TILE_SIZE + (j >> 1); + data->bzzzz[j] = tile->data.depth32[y][x] >> 8; + data->stencilVals[j] = tile->data.depth32[y][x] & 0xff; + } + break; + default: + assert(0); + } +} + + +/** + * If the shader has not been run, interpolate the depth values + * ourselves. + */ +static void +interpolate_quad_depth( struct quad_header *quad ) +{ + const float fx = (float) quad->input.x0; + const float fy = (float) quad->input.y0; + const float dzdx = quad->posCoef->dadx[2]; + const float dzdy = quad->posCoef->dady[2]; + const float z0 = quad->posCoef->a0[2] + dzdx * fx + dzdy * fy; + + quad->output.depth[0] = z0; + quad->output.depth[1] = z0 + dzdx; + quad->output.depth[2] = z0 + dzdy; + quad->output.depth[3] = z0 + dzdx + dzdy; +} + + +/** + * Compute the depth_data::qzzzz[] values from the float fragment Z values. + */ +static void +convert_quad_depth( struct depth_data *data, + const struct quad_header *quad ) +{ + unsigned j; + + /* Convert quad's float depth values to int depth values (qzzzz). + * If the Z buffer stores integer values, we _have_ to do the depth + * compares with integers (not floats). Otherwise, the float->int->float + * conversion of Z values (which isn't an identity function) will cause + * Z-fighting errors. + */ + switch (data->format) { + case PIPE_FORMAT_Z16_UNORM: + { + float scale = 65535.0; + + for (j = 0; j < QUAD_SIZE; j++) { + data->qzzzz[j] = (unsigned) (quad->output.depth[j] * scale); + } + } + break; + case PIPE_FORMAT_Z32_UNORM: + { + double scale = (double) (uint) ~0UL; + + for (j = 0; j < QUAD_SIZE; j++) { + data->qzzzz[j] = (unsigned) (quad->output.depth[j] * scale); + } + } + break; + case PIPE_FORMAT_Z24X8_UNORM: + case PIPE_FORMAT_Z24_UNORM_S8_USCALED: + { + float scale = (float) ((1 << 24) - 1); + + for (j = 0; j < QUAD_SIZE; j++) { + data->qzzzz[j] = (unsigned) (quad->output.depth[j] * scale); + } + } + break; + case PIPE_FORMAT_X8Z24_UNORM: + case PIPE_FORMAT_S8_USCALED_Z24_UNORM: + { + float scale = (float) ((1 << 24) - 1); + + for (j = 0; j < QUAD_SIZE; j++) { + data->qzzzz[j] = (unsigned) (quad->output.depth[j] * scale); + } + } + break; + default: + assert(0); + } +} + + + +/** + * Write data->bzzzz[] values and data->stencilVals into the Z/stencil buffer. + */ +static void +write_depth_stencil_values( struct depth_data *data, + struct quad_header *quad ) +{ + struct softpipe_cached_tile *tile = data->tile; + unsigned j; + + /* put updated Z values back into cached tile */ + switch (data->format) { + case PIPE_FORMAT_Z16_UNORM: + for (j = 0; j < QUAD_SIZE; j++) { + int x = quad->input.x0 % TILE_SIZE + (j & 1); + int y = quad->input.y0 % TILE_SIZE + (j >> 1); + tile->data.depth16[y][x] = (ushort) data->bzzzz[j]; + } + break; + case PIPE_FORMAT_Z24X8_UNORM: + case PIPE_FORMAT_Z32_UNORM: + for (j = 0; j < QUAD_SIZE; j++) { + int x = quad->input.x0 % TILE_SIZE + (j & 1); + int y = quad->input.y0 % TILE_SIZE + (j >> 1); + tile->data.depth32[y][x] = data->bzzzz[j]; + } + break; + case PIPE_FORMAT_Z24_UNORM_S8_USCALED: + for (j = 0; j < QUAD_SIZE; j++) { + int x = quad->input.x0 % TILE_SIZE + (j & 1); + int y = quad->input.y0 % TILE_SIZE + (j >> 1); + tile->data.depth32[y][x] = (data->stencilVals[j] << 24) | data->bzzzz[j]; + } + break; + case PIPE_FORMAT_S8_USCALED_Z24_UNORM: + for (j = 0; j < QUAD_SIZE; j++) { + int x = quad->input.x0 % TILE_SIZE + (j & 1); + int y = quad->input.y0 % TILE_SIZE + (j >> 1); + tile->data.depth32[y][x] = (data->bzzzz[j] << 8) | data->stencilVals[j]; + } + break; + case PIPE_FORMAT_X8Z24_UNORM: + for (j = 0; j < QUAD_SIZE; j++) { + int x = quad->input.x0 % TILE_SIZE + (j & 1); + int y = quad->input.y0 % TILE_SIZE + (j >> 1); + tile->data.depth32[y][x] = data->bzzzz[j] << 8; + } + break; + default: + assert(0); + } +} + + + +/** Only 8-bit stencil supported */ +#define STENCIL_MAX 0xff + + +/** + * Do the basic stencil test (compare stencil buffer values against the + * reference value. + * + * \param data->stencilVals the stencil values from the stencil buffer + * \param func the stencil func (PIPE_FUNC_x) + * \param ref the stencil reference value + * \param valMask the stencil value mask indicating which bits of the stencil + * values and ref value are to be used. + * \return mask indicating which pixels passed the stencil test + */ +static unsigned +do_stencil_test(struct depth_data *data, + unsigned func, + unsigned ref, unsigned valMask) +{ + unsigned passMask = 0x0; + unsigned j; + + ref &= valMask; + + switch (func) { + case PIPE_FUNC_NEVER: + /* passMask = 0x0 */ + break; + case PIPE_FUNC_LESS: + for (j = 0; j < QUAD_SIZE; j++) { + if (ref < (data->stencilVals[j] & valMask)) { + passMask |= (1 << j); + } + } + break; + case PIPE_FUNC_EQUAL: + for (j = 0; j < QUAD_SIZE; j++) { + if (ref == (data->stencilVals[j] & valMask)) { + passMask |= (1 << j); + } + } + break; + case PIPE_FUNC_LEQUAL: + for (j = 0; j < QUAD_SIZE; j++) { + if (ref <= (data->stencilVals[j] & valMask)) { + passMask |= (1 << j); + } + } + break; + case PIPE_FUNC_GREATER: + for (j = 0; j < QUAD_SIZE; j++) { + if (ref > (data->stencilVals[j] & valMask)) { + passMask |= (1 << j); + } + } + break; + case PIPE_FUNC_NOTEQUAL: + for (j = 0; j < QUAD_SIZE; j++) { + if (ref != (data->stencilVals[j] & valMask)) { + passMask |= (1 << j); + } + } + break; + case PIPE_FUNC_GEQUAL: + for (j = 0; j < QUAD_SIZE; j++) { + if (ref >= (data->stencilVals[j] & valMask)) { + passMask |= (1 << j); + } + } + break; + case PIPE_FUNC_ALWAYS: + passMask = MASK_ALL; + break; + default: + assert(0); + } + + return passMask; +} + + +/** + * Apply the stencil operator to stencil values. + * + * \param data->stencilVals the stencil buffer values (read and written) + * \param mask indicates which pixels to update + * \param op the stencil operator (PIPE_STENCIL_OP_x) + * \param ref the stencil reference value + * \param wrtMask writemask controlling which bits are changed in the + * stencil values + */ +static void +apply_stencil_op(struct depth_data *data, + unsigned mask, unsigned op, ubyte ref, ubyte wrtMask) +{ + unsigned j; + ubyte newstencil[QUAD_SIZE]; + + for (j = 0; j < QUAD_SIZE; j++) { + newstencil[j] = data->stencilVals[j]; + } + + switch (op) { + case PIPE_STENCIL_OP_KEEP: + /* no-op */ + break; + case PIPE_STENCIL_OP_ZERO: + for (j = 0; j < QUAD_SIZE; j++) { + if (mask & (1 << j)) { + newstencil[j] = 0; + } + } + break; + case PIPE_STENCIL_OP_REPLACE: + for (j = 0; j < QUAD_SIZE; j++) { + if (mask & (1 << j)) { + newstencil[j] = ref; + } + } + break; + case PIPE_STENCIL_OP_INCR: + for (j = 0; j < QUAD_SIZE; j++) { + if (mask & (1 << j)) { + if (data->stencilVals[j] < STENCIL_MAX) { + newstencil[j] = data->stencilVals[j] + 1; + } + } + } + break; + case PIPE_STENCIL_OP_DECR: + for (j = 0; j < QUAD_SIZE; j++) { + if (mask & (1 << j)) { + if (data->stencilVals[j] > 0) { + newstencil[j] = data->stencilVals[j] - 1; + } + } + } + break; + case PIPE_STENCIL_OP_INCR_WRAP: + for (j = 0; j < QUAD_SIZE; j++) { + if (mask & (1 << j)) { + newstencil[j] = data->stencilVals[j] + 1; + } + } + break; + case PIPE_STENCIL_OP_DECR_WRAP: + for (j = 0; j < QUAD_SIZE; j++) { + if (mask & (1 << j)) { + newstencil[j] = data->stencilVals[j] - 1; + } + } + break; + case PIPE_STENCIL_OP_INVERT: + for (j = 0; j < QUAD_SIZE; j++) { + if (mask & (1 << j)) { + newstencil[j] = ~data->stencilVals[j]; + } + } + break; + default: + assert(0); + } + + /* + * update the stencil values + */ + if (wrtMask != STENCIL_MAX) { + /* apply bit-wise stencil buffer writemask */ + for (j = 0; j < QUAD_SIZE; j++) { + data->stencilVals[j] = (wrtMask & newstencil[j]) | (~wrtMask & data->stencilVals[j]); + } + } + else { + for (j = 0; j < QUAD_SIZE; j++) { + data->stencilVals[j] = newstencil[j]; + } + } +} + + + +/** + * To increase efficiency, we should probably have multiple versions + * of this function that are specifically for Z16, Z32 and FP Z buffers. + * Try to effectively do that with codegen... + */ +static boolean +depth_test_quad(struct quad_stage *qs, + struct depth_data *data, + struct quad_header *quad) +{ + struct softpipe_context *softpipe = qs->softpipe; + unsigned zmask = 0; + unsigned j; + + switch (softpipe->depth_stencil->depth.func) { + case PIPE_FUNC_NEVER: + /* zmask = 0 */ + break; + case PIPE_FUNC_LESS: + /* Note this is pretty much a single sse or cell instruction. + * Like this: quad->mask &= (quad->outputs.depth < zzzz); + */ + for (j = 0; j < QUAD_SIZE; j++) { + if (data->qzzzz[j] < data->bzzzz[j]) + zmask |= 1 << j; + } + break; + case PIPE_FUNC_EQUAL: + for (j = 0; j < QUAD_SIZE; j++) { + if (data->qzzzz[j] == data->bzzzz[j]) + zmask |= 1 << j; + } + break; + case PIPE_FUNC_LEQUAL: + for (j = 0; j < QUAD_SIZE; j++) { + if (data->qzzzz[j] <= data->bzzzz[j]) + zmask |= (1 << j); + } + break; + case PIPE_FUNC_GREATER: + for (j = 0; j < QUAD_SIZE; j++) { + if (data->qzzzz[j] > data->bzzzz[j]) + zmask |= (1 << j); + } + break; + case PIPE_FUNC_NOTEQUAL: + for (j = 0; j < QUAD_SIZE; j++) { + if (data->qzzzz[j] != data->bzzzz[j]) + zmask |= (1 << j); + } + break; + case PIPE_FUNC_GEQUAL: + for (j = 0; j < QUAD_SIZE; j++) { + if (data->qzzzz[j] >= data->bzzzz[j]) + zmask |= (1 << j); + } + break; + case PIPE_FUNC_ALWAYS: + zmask = MASK_ALL; + break; + default: + assert(0); + } + + quad->inout.mask &= zmask; + if (quad->inout.mask == 0) + return FALSE; + + /* Update our internal copy only if writemask set. Even if + * depth.writemask is FALSE, may still need to write out buffer + * data due to stencil changes. + */ + if (softpipe->depth_stencil->depth.writemask) { + for (j = 0; j < QUAD_SIZE; j++) { + if (quad->inout.mask & (1 << j)) { + data->bzzzz[j] = data->qzzzz[j]; + } + } + } + + return TRUE; +} + + + +/** + * Do stencil (and depth) testing. Stenciling depends on the outcome of + * depth testing. + */ +static void +depth_stencil_test_quad(struct quad_stage *qs, + struct depth_data *data, + struct quad_header *quad) +{ + struct softpipe_context *softpipe = qs->softpipe; + unsigned func, zFailOp, zPassOp, failOp; + ubyte ref, wrtMask, valMask; + uint face = quad->input.facing; + + if (!softpipe->depth_stencil->stencil[1].enabled) { + /* single-sided stencil test, use front (face=0) state */ + face = 0; + } + + /* 0 = front-face, 1 = back-face */ + assert(face == 0 || face == 1); + + /* choose front or back face function, operator, etc */ + /* XXX we could do these initializations once per primitive */ + func = softpipe->depth_stencil->stencil[face].func; + failOp = softpipe->depth_stencil->stencil[face].fail_op; + zFailOp = softpipe->depth_stencil->stencil[face].zfail_op; + zPassOp = softpipe->depth_stencil->stencil[face].zpass_op; + ref = softpipe->stencil_ref.ref_value[face]; + wrtMask = softpipe->depth_stencil->stencil[face].writemask; + valMask = softpipe->depth_stencil->stencil[face].valuemask; + + /* do the stencil test first */ + { + unsigned passMask, failMask; + passMask = do_stencil_test(data, func, ref, valMask); + failMask = quad->inout.mask & ~passMask; + quad->inout.mask &= passMask; + + if (failOp != PIPE_STENCIL_OP_KEEP) { + apply_stencil_op(data, failMask, failOp, ref, wrtMask); + } + } + + if (quad->inout.mask) { + /* now the pixels that passed the stencil test are depth tested */ + if (softpipe->depth_stencil->depth.enabled) { + const unsigned origMask = quad->inout.mask; + + depth_test_quad(qs, data, quad); /* quad->mask is updated */ + + /* update stencil buffer values according to z pass/fail result */ + if (zFailOp != PIPE_STENCIL_OP_KEEP) { + const unsigned zFailMask = origMask & ~quad->inout.mask; + apply_stencil_op(data, zFailMask, zFailOp, ref, wrtMask); + } + + if (zPassOp != PIPE_STENCIL_OP_KEEP) { + const unsigned zPassMask = origMask & quad->inout.mask; + apply_stencil_op(data, zPassMask, zPassOp, ref, wrtMask); + } + } + else { + /* no depth test, apply Zpass operator to stencil buffer values */ + apply_stencil_op(data, quad->inout.mask, zPassOp, ref, wrtMask); + } + } +} + + +#define ALPHATEST( FUNC, COMP ) \ + static int \ + alpha_test_quads_##FUNC( struct quad_stage *qs, \ + struct quad_header *quads[], \ + unsigned nr ) \ + { \ + const float ref = qs->softpipe->depth_stencil->alpha.ref_value; \ + const uint cbuf = 0; /* only output[0].alpha is tested */ \ + unsigned pass_nr = 0; \ + unsigned i; \ + \ + for (i = 0; i < nr; i++) { \ + const float *aaaa = quads[i]->output.color[cbuf][3]; \ + unsigned passMask = 0; \ + \ + if (aaaa[0] COMP ref) passMask |= (1 << 0); \ + if (aaaa[1] COMP ref) passMask |= (1 << 1); \ + if (aaaa[2] COMP ref) passMask |= (1 << 2); \ + if (aaaa[3] COMP ref) passMask |= (1 << 3); \ + \ + quads[i]->inout.mask &= passMask; \ + \ + if (quads[i]->inout.mask) \ + quads[pass_nr++] = quads[i]; \ + } \ + \ + return pass_nr; \ + } + + +ALPHATEST( LESS, < ) +ALPHATEST( EQUAL, == ) +ALPHATEST( LEQUAL, <= ) +ALPHATEST( GREATER, > ) +ALPHATEST( NOTEQUAL, != ) +ALPHATEST( GEQUAL, >= ) + + +/* XXX: Incorporate into shader using KILP. + */ +static int +alpha_test_quads(struct quad_stage *qs, + struct quad_header *quads[], + unsigned nr) +{ + switch (qs->softpipe->depth_stencil->alpha.func) { + case PIPE_FUNC_LESS: + return alpha_test_quads_LESS( qs, quads, nr ); + case PIPE_FUNC_EQUAL: + return alpha_test_quads_EQUAL( qs, quads, nr ); + break; + case PIPE_FUNC_LEQUAL: + return alpha_test_quads_LEQUAL( qs, quads, nr ); + case PIPE_FUNC_GREATER: + return alpha_test_quads_GREATER( qs, quads, nr ); + case PIPE_FUNC_NOTEQUAL: + return alpha_test_quads_NOTEQUAL( qs, quads, nr ); + case PIPE_FUNC_GEQUAL: + return alpha_test_quads_GEQUAL( qs, quads, nr ); + case PIPE_FUNC_ALWAYS: + return nr; + case PIPE_FUNC_NEVER: + default: + return 0; + } +} + + +static unsigned mask_count[16] = +{ + 0, /* 0x0 */ + 1, /* 0x1 */ + 1, /* 0x2 */ + 2, /* 0x3 */ + 1, /* 0x4 */ + 2, /* 0x5 */ + 2, /* 0x6 */ + 3, /* 0x7 */ + 1, /* 0x8 */ + 2, /* 0x9 */ + 2, /* 0xa */ + 3, /* 0xb */ + 2, /* 0xc */ + 3, /* 0xd */ + 3, /* 0xe */ + 4, /* 0xf */ +}; + + + +/** helper to get number of Z buffer bits */ +static unsigned +get_depth_bits(struct quad_stage *qs) +{ + struct pipe_surface *zsurf = qs->softpipe->framebuffer.zsbuf; + if (zsurf) + return util_format_get_component_bits(zsurf->format, + UTIL_FORMAT_COLORSPACE_ZS, 0); + else + return 0; +} + + + +/** + * General depth/stencil test function. Used when there's no fast-path. + */ +static void +depth_test_quads_fallback(struct quad_stage *qs, + struct quad_header *quads[], + unsigned nr) +{ + unsigned i, pass = 0; + const struct sp_fragment_shader *fs = qs->softpipe->fs; + boolean interp_depth = !fs->info.writes_z; + struct depth_data data; + + + if (qs->softpipe->depth_stencil->alpha.enabled) { + nr = alpha_test_quads(qs, quads, nr); + } + + if (get_depth_bits(qs) > 0 && + (qs->softpipe->depth_stencil->depth.enabled || + qs->softpipe->depth_stencil->stencil[0].enabled)) { + + data.ps = qs->softpipe->framebuffer.zsbuf; + data.format = data.ps->format; + data.tile = sp_get_cached_tile(qs->softpipe->zsbuf_cache, + quads[0]->input.x0, + quads[0]->input.y0); + + for (i = 0; i < nr; i++) { + get_depth_stencil_values(&data, quads[i]); + + if (qs->softpipe->depth_stencil->depth.enabled) { + if (interp_depth) + interpolate_quad_depth(quads[i]); + + convert_quad_depth(&data, quads[i]); + } + + if (qs->softpipe->depth_stencil->stencil[0].enabled) { + depth_stencil_test_quad(qs, &data, quads[i]); + write_depth_stencil_values(&data, quads[i]); + } + else { + if (!depth_test_quad(qs, &data, quads[i])) + continue; + + if (qs->softpipe->depth_stencil->depth.writemask) + write_depth_stencil_values(&data, quads[i]); + } + + quads[pass++] = quads[i]; + } + + nr = pass; + } + + if (qs->softpipe->active_query_count) { + for (i = 0; i < nr; i++) + qs->softpipe->occlusion_count += mask_count[quads[i]->inout.mask]; + } + + if (nr) + qs->next->run(qs->next, quads, nr); +} + + +/** + * Special-case Z testing for 16-bit Zbuffer and Z buffer writes enabled. + */ + +#define NAME depth_interp_z16_less_write +#define OPERATOR < +#include "sp_quad_depth_test_tmp.h" + +#define NAME depth_interp_z16_equal_write +#define OPERATOR == +#include "sp_quad_depth_test_tmp.h" + +#define NAME depth_interp_z16_lequal_write +#define OPERATOR <= +#include "sp_quad_depth_test_tmp.h" + +#define NAME depth_interp_z16_greater_write +#define OPERATOR > +#include "sp_quad_depth_test_tmp.h" + +#define NAME depth_interp_z16_notequal_write +#define OPERATOR != +#include "sp_quad_depth_test_tmp.h" + +#define NAME depth_interp_z16_gequal_write +#define OPERATOR >= +#include "sp_quad_depth_test_tmp.h" + +#define NAME depth_interp_z16_always_write +#define ALWAYS 1 +#include "sp_quad_depth_test_tmp.h" + + + +static void +depth_noop(struct quad_stage *qs, + struct quad_header *quads[], + unsigned nr) +{ + qs->next->run(qs->next, quads, nr); +} + + + +static void +choose_depth_test(struct quad_stage *qs, + struct quad_header *quads[], + unsigned nr) +{ + boolean interp_depth = !qs->softpipe->fs->info.writes_z; + + boolean alpha = qs->softpipe->depth_stencil->alpha.enabled; + + boolean depth = (get_depth_bits(qs) > 0 && + qs->softpipe->depth_stencil->depth.enabled); + + unsigned depthfunc = qs->softpipe->depth_stencil->depth.func; + + boolean stencil = qs->softpipe->depth_stencil->stencil[0].enabled; + + boolean depthwrite = qs->softpipe->depth_stencil->depth.writemask; + + boolean occlusion = qs->softpipe->active_query_count; + + /* default */ + qs->run = depth_test_quads_fallback; + + /* look for special cases */ + if (!alpha && + !depth && + !stencil) { + qs->run = depth_noop; + } + else if (!alpha && + interp_depth && + depth && + depthwrite && + !occlusion && + !stencil) + { + if (qs->softpipe->framebuffer.zsbuf->format == PIPE_FORMAT_Z16_UNORM) { + switch (depthfunc) { + case PIPE_FUNC_NEVER: + qs->run = depth_test_quads_fallback; + break; + case PIPE_FUNC_LESS: + qs->run = depth_interp_z16_less_write; + break; + case PIPE_FUNC_EQUAL: + qs->run = depth_interp_z16_equal_write; + break; + case PIPE_FUNC_LEQUAL: + qs->run = depth_interp_z16_lequal_write; + break; + case PIPE_FUNC_GREATER: + qs->run = depth_interp_z16_greater_write; + break; + case PIPE_FUNC_NOTEQUAL: + qs->run = depth_interp_z16_notequal_write; + break; + case PIPE_FUNC_GEQUAL: + qs->run = depth_interp_z16_gequal_write; + break; + case PIPE_FUNC_ALWAYS: + qs->run = depth_interp_z16_always_write; + break; + default: + qs->run = depth_test_quads_fallback; + break; + } + } + } + + /* next quad/fragment stage */ + qs->run( qs, quads, nr ); +} + + + +static void +depth_test_begin(struct quad_stage *qs) +{ + qs->run = choose_depth_test; + qs->next->begin(qs->next); +} + + +static void +depth_test_destroy(struct quad_stage *qs) +{ + FREE( qs ); +} + + +struct quad_stage * +sp_quad_depth_test_stage(struct softpipe_context *softpipe) +{ + struct quad_stage *stage = CALLOC_STRUCT(quad_stage); + + stage->softpipe = softpipe; + stage->begin = depth_test_begin; + stage->run = choose_depth_test; + stage->destroy = depth_test_destroy; + + return stage; +} diff --git a/src/gallium/drivers/softpipe/sp_quad_depth_test_tmp.h b/src/gallium/drivers/softpipe/sp_quad_depth_test_tmp.h new file mode 100644 index 0000000000..25af415c25 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_quad_depth_test_tmp.h @@ -0,0 +1,147 @@ +/************************************************************************** + * + * Copyright 2010 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +/* + * Template for generating Z test functions + * Only PIPE_FORMAT_Z16_UNORM supported at this time. + */ + + +#ifndef NAME +#error "NAME is not defined!" +#endif + +#if !defined(OPERATOR) && !defined(ALWAYS) +#error "neither OPERATOR nor ALWAYS is defined!" +#endif + + +/* + * NOTE: there's no guarantee that the quads are sequentially side by + * side. The fragment shader may have culled some quads, etc. Sliver + * triangles may generate non-sequential quads. + */ +static void +NAME(struct quad_stage *qs, + struct quad_header *quads[], + unsigned nr) +{ + unsigned i, pass = 0; + const unsigned ix = quads[0]->input.x0; + const unsigned iy = quads[0]->input.y0; + const float fx = (float) ix; + const float fy = (float) iy; + const float dzdx = quads[0]->posCoef->dadx[2]; + const float dzdy = quads[0]->posCoef->dady[2]; + const float z0 = quads[0]->posCoef->a0[2] + dzdx * fx + dzdy * fy; + struct softpipe_cached_tile *tile; + ushort (*depth16)[TILE_SIZE]; + ushort init_idepth[4], idepth[4], depth_step; + const float scale = 65535.0; + + /* compute scaled depth of the four pixels in first quad */ + init_idepth[0] = (ushort)((z0) * scale); + init_idepth[1] = (ushort)((z0 + dzdx) * scale); + init_idepth[2] = (ushort)((z0 + dzdy) * scale); + init_idepth[3] = (ushort)((z0 + dzdx + dzdy) * scale); + + depth_step = (ushort)(dzdx * scale); + + tile = sp_get_cached_tile(qs->softpipe->zsbuf_cache, ix, iy); + + for (i = 0; i < nr; i++) { + const unsigned outmask = quads[i]->inout.mask; + const int dx = quads[i]->input.x0 - ix; + unsigned mask = 0; + + /* compute depth for this quad */ + idepth[0] = init_idepth[0] + dx * depth_step; + idepth[1] = init_idepth[1] + dx * depth_step; + idepth[2] = init_idepth[2] + dx * depth_step; + idepth[3] = init_idepth[3] + dx * depth_step; + + depth16 = (ushort (*)[TILE_SIZE]) + &tile->data.depth16[iy % TILE_SIZE][(ix + dx)% TILE_SIZE]; + +#ifdef ALWAYS + if (outmask & 1) { + depth16[0][0] = idepth[0]; + mask |= (1 << 0); + } + + if (outmask & 2) { + depth16[0][1] = idepth[1]; + mask |= (1 << 1); + } + + if (outmask & 4) { + depth16[1][0] = idepth[2]; + mask |= (1 << 2); + } + + if (outmask & 8) { + depth16[1][1] = idepth[3]; + mask |= (1 << 3); + } +#else + /* Note: OPERATOR appears here: */ + if ((outmask & 1) && (idepth[0] OPERATOR depth16[0][0])) { + depth16[0][0] = idepth[0]; + mask |= (1 << 0); + } + + if ((outmask & 2) && (idepth[1] OPERATOR depth16[0][1])) { + depth16[0][1] = idepth[1]; + mask |= (1 << 1); + } + + if ((outmask & 4) && (idepth[2] OPERATOR depth16[1][0])) { + depth16[1][0] = idepth[2]; + mask |= (1 << 2); + } + + if ((outmask & 8) && (idepth[3] OPERATOR depth16[1][1])) { + depth16[1][1] = idepth[3]; + mask |= (1 << 3); + } +#endif + + depth16 = (ushort (*)[TILE_SIZE]) &depth16[0][2]; + + quads[i]->inout.mask = mask; + if (quads[i]->inout.mask) + quads[pass++] = quads[i]; + } + + if (pass) + qs->next->run(qs->next, quads, pass); +} + + +#undef NAME +#undef OPERATOR +#undef ALWAYS diff --git a/src/gallium/drivers/softpipe/sp_quad_fs.c b/src/gallium/drivers/softpipe/sp_quad_fs.c new file mode 100644 index 0000000000..907e94b59b --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_quad_fs.c @@ -0,0 +1,175 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * Copyright 2008 VMware, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* Vertices are just an array of floats, with all the attributes + * packed. We currently assume a layout like: + * + * attr[0][0..3] - window position + * attr[1..n][0..3] - remaining attributes. + * + * Attributes are assumed to be 4 floats wide but are packed so that + * all the enabled attributes run contiguously. + */ + +#include "util/u_math.h" +#include "util/u_memory.h" +#include "pipe/p_defines.h" +#include "pipe/p_shader_tokens.h" + +#include "sp_context.h" +#include "sp_state.h" +#include "sp_quad.h" +#include "sp_quad_pipe.h" + + +struct quad_shade_stage +{ + struct quad_stage stage; /**< base class */ + + /* no other fields at this time */ +}; + + +/** cast wrapper */ +static INLINE struct quad_shade_stage * +quad_shade_stage(struct quad_stage *qs) +{ + return (struct quad_shade_stage *) qs; +} + + +/** + * Execute fragment shader for the four fragments in the quad. + * \return TRUE if quad is alive, FALSE if all four pixels are killed + */ +static INLINE boolean +shade_quad(struct quad_stage *qs, struct quad_header *quad) +{ + struct softpipe_context *softpipe = qs->softpipe; + struct tgsi_exec_machine *machine = softpipe->fs_machine; + + /* run shader */ + return softpipe->fs->run( softpipe->fs, machine, quad ); +} + + + +static void +coverage_quad(struct quad_stage *qs, struct quad_header *quad) +{ + struct softpipe_context *softpipe = qs->softpipe; + uint cbuf; + + /* loop over colorbuffer outputs */ + for (cbuf = 0; cbuf < softpipe->framebuffer.nr_cbufs; cbuf++) { + float (*quadColor)[4] = quad->output.color[cbuf]; + unsigned j; + for (j = 0; j < QUAD_SIZE; j++) { + assert(quad->input.coverage[j] >= 0.0); + assert(quad->input.coverage[j] <= 1.0); + quadColor[3][j] *= quad->input.coverage[j]; + } + } +} + + +/** + * Shade/write an array of quads + * Called via quad_stage::run() + */ +static void +shade_quads(struct quad_stage *qs, + struct quad_header *quads[], + unsigned nr) +{ + struct softpipe_context *softpipe = qs->softpipe; + struct tgsi_exec_machine *machine = softpipe->fs_machine; + unsigned i, pass = 0; + + for (i = 0; i < PIPE_MAX_CONSTANT_BUFFERS; i++) { + machine->Consts[i] = softpipe->mapped_constants[PIPE_SHADER_FRAGMENT][i]; + } + machine->InterpCoefs = quads[0]->coef; + + for (i = 0; i < nr; i++) { + if (!shade_quad(qs, quads[i])) + continue; /* quad totally culled/killed */ + + if (/*do_coverage*/ 0) + coverage_quad( qs, quads[i] ); + + quads[pass++] = quads[i]; + } + + if (pass) + qs->next->run(qs->next, quads, pass); +} + + +/** + * Per-primitive (or per-begin?) setup + */ +static void +shade_begin(struct quad_stage *qs) +{ + struct softpipe_context *softpipe = qs->softpipe; + + softpipe->fs->prepare( softpipe->fs, + softpipe->fs_machine, + (struct tgsi_sampler **) + softpipe->tgsi.frag_samplers_list ); + + qs->next->begin(qs->next); +} + + +static void +shade_destroy(struct quad_stage *qs) +{ + FREE( qs ); +} + + +struct quad_stage * +sp_quad_shade_stage( struct softpipe_context *softpipe ) +{ + struct quad_shade_stage *qss = CALLOC_STRUCT(quad_shade_stage); + if (!qss) + goto fail; + + qss->stage.softpipe = softpipe; + qss->stage.begin = shade_begin; + qss->stage.run = shade_quads; + qss->stage.destroy = shade_destroy; + + return &qss->stage; + +fail: + FREE(qss); + return NULL; +} diff --git a/src/gallium/drivers/softpipe/sp_quad_pipe.c b/src/gallium/drivers/softpipe/sp_quad_pipe.c new file mode 100644 index 0000000000..43b8e88e33 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_quad_pipe.c @@ -0,0 +1,68 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#include "sp_context.h" +#include "sp_state.h" +#include "pipe/p_shader_tokens.h" + +static void +sp_push_quad_first( struct softpipe_context *sp, + struct quad_stage *quad ) +{ + quad->next = sp->quad.first; + sp->quad.first = quad; +} + + +void +sp_build_quad_pipeline(struct softpipe_context *sp) +{ + boolean early_depth_test = + sp->depth_stencil->depth.enabled && + sp->framebuffer.zsbuf && + !sp->depth_stencil->alpha.enabled && + !sp->fs->info.uses_kill && + !sp->fs->info.writes_z; + + sp->quad.first = sp->quad.blend; + + if (early_depth_test) { + sp_push_quad_first( sp, sp->quad.shade ); + sp_push_quad_first( sp, sp->quad.depth_test ); + } + else { + sp_push_quad_first( sp, sp->quad.depth_test ); + sp_push_quad_first( sp, sp->quad.shade ); + } + +#if !DO_PSTIPPLE_IN_DRAW_MODULE + if (sp->rasterizer->poly_stipple_enable) + sp_push_quad_first( sp, sp->quad.pstipple ); +#endif +} + diff --git a/src/gallium/drivers/softpipe/sp_quad_pipe.h b/src/gallium/drivers/softpipe/sp_quad_pipe.h new file mode 100644 index 0000000000..c0aa134831 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_quad_pipe.h @@ -0,0 +1,72 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* Authors: Keith Whitwell <keith@tungstengraphics.com> + */ + +#ifndef SP_QUAD_PIPE_H +#define SP_QUAD_PIPE_H + + +struct softpipe_context; +struct quad_header; + + +/** + * Fragment processing is performed on 2x2 blocks of pixels called "quads". + * Quad processing is performed with a pipeline of stages represented by + * this type. + */ +struct quad_stage { + struct softpipe_context *softpipe; + + struct quad_stage *next; + + void (*begin)(struct quad_stage *qs); + + /** the stage action */ + void (*run)(struct quad_stage *qs, struct quad_header *quad[], unsigned nr); + + void (*destroy)(struct quad_stage *qs); +}; + + +struct quad_stage *sp_quad_polygon_stipple_stage( struct softpipe_context *softpipe ); +struct quad_stage *sp_quad_earlyz_stage( struct softpipe_context *softpipe ); +struct quad_stage *sp_quad_shade_stage( struct softpipe_context *softpipe ); +struct quad_stage *sp_quad_alpha_test_stage( struct softpipe_context *softpipe ); +struct quad_stage *sp_quad_stencil_test_stage( struct softpipe_context *softpipe ); +struct quad_stage *sp_quad_depth_test_stage( struct softpipe_context *softpipe ); +struct quad_stage *sp_quad_occlusion_stage( struct softpipe_context *softpipe ); +struct quad_stage *sp_quad_coverage_stage( struct softpipe_context *softpipe ); +struct quad_stage *sp_quad_blend_stage( struct softpipe_context *softpipe ); +struct quad_stage *sp_quad_colormask_stage( struct softpipe_context *softpipe ); +struct quad_stage *sp_quad_output_stage( struct softpipe_context *softpipe ); + +void sp_build_quad_pipeline(struct softpipe_context *sp); + +#endif /* SP_QUAD_PIPE_H */ diff --git a/src/gallium/drivers/softpipe/sp_quad_stipple.c b/src/gallium/drivers/softpipe/sp_quad_stipple.c new file mode 100644 index 0000000000..a0527a596a --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_quad_stipple.c @@ -0,0 +1,81 @@ + +/** + * quad polygon stipple stage + */ + +#include "sp_context.h" +#include "sp_quad.h" +#include "sp_quad_pipe.h" +#include "pipe/p_defines.h" +#include "util/u_memory.h" + + +/** + * Apply polygon stipple to quads produced by triangle rasterization + */ +static void +stipple_quad(struct quad_stage *qs, struct quad_header *quads[], unsigned nr) +{ + static const uint bit31 = 1 << 31; + static const uint bit30 = 1 << 30; + unsigned pass = nr; + + struct softpipe_context *softpipe = qs->softpipe; + unsigned q; + + pass = 0; + + for (q = 0; q < nr; q++) { + struct quad_header *quad = quads[q]; + + const int col0 = quad->input.x0 % 32; + const int y0 = quad->input.y0; + const int y1 = y0 + 1; + const uint stipple0 = softpipe->poly_stipple.stipple[y0 % 32]; + const uint stipple1 = softpipe->poly_stipple.stipple[y1 % 32]; + + /* turn off quad mask bits that fail the stipple test */ + if ((stipple0 & (bit31 >> col0)) == 0) + quad->inout.mask &= ~MASK_TOP_LEFT; + + if ((stipple0 & (bit30 >> col0)) == 0) + quad->inout.mask &= ~MASK_TOP_RIGHT; + + if ((stipple1 & (bit31 >> col0)) == 0) + quad->inout.mask &= ~MASK_BOTTOM_LEFT; + + if ((stipple1 & (bit30 >> col0)) == 0) + quad->inout.mask &= ~MASK_BOTTOM_RIGHT; + + if (quad->inout.mask) + quads[pass++] = quad; + } + + qs->next->run(qs->next, quads, pass); +} + + +static void stipple_begin(struct quad_stage *qs) +{ + qs->next->begin(qs->next); +} + + +static void stipple_destroy(struct quad_stage *qs) +{ + FREE( qs ); +} + + +struct quad_stage * +sp_quad_polygon_stipple_stage( struct softpipe_context *softpipe ) +{ + struct quad_stage *stage = CALLOC_STRUCT(quad_stage); + + stage->softpipe = softpipe; + stage->begin = stipple_begin; + stage->run = stipple_quad; + stage->destroy = stipple_destroy; + + return stage; +} diff --git a/src/gallium/drivers/softpipe/sp_query.c b/src/gallium/drivers/softpipe/sp_query.c new file mode 100644 index 0000000000..4ae69c1c2b --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_query.c @@ -0,0 +1,207 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* Author: + * Keith Whitwell <keith@tungstengraphics.com> + */ + +#include "draw/draw_context.h" +#include "os/os_time.h" +#include "pipe/p_defines.h" +#include "util/u_memory.h" +#include "sp_context.h" +#include "sp_query.h" +#include "sp_state.h" + +struct softpipe_query { + unsigned type; + uint64_t start; + uint64_t end; + struct pipe_query_data_so_statistics so; +}; + + +static struct softpipe_query *softpipe_query( struct pipe_query *p ) +{ + return (struct softpipe_query *)p; +} + +static struct pipe_query * +softpipe_create_query(struct pipe_context *pipe, + unsigned type) +{ + struct softpipe_query* sq; + + assert(type == PIPE_QUERY_OCCLUSION_COUNTER || + type == PIPE_QUERY_TIME_ELAPSED || + type == PIPE_QUERY_SO_STATISTICS || + type == PIPE_QUERY_GPU_FINISHED || + type == PIPE_QUERY_TIMESTAMP_DISJOINT); + sq = CALLOC_STRUCT( softpipe_query ); + sq->type = type; + + return (struct pipe_query *)sq; +} + + +static void +softpipe_destroy_query(struct pipe_context *pipe, struct pipe_query *q) +{ + FREE(q); +} + + +static void +softpipe_begin_query(struct pipe_context *pipe, struct pipe_query *q) +{ + struct softpipe_context *softpipe = softpipe_context( pipe ); + struct softpipe_query *sq = softpipe_query(q); + + switch (sq->type) { + case PIPE_QUERY_OCCLUSION_COUNTER: + sq->start = softpipe->occlusion_count; + break; + case PIPE_QUERY_TIME_ELAPSED: + sq->start = 1000*os_time_get(); + break; + case PIPE_QUERY_SO_STATISTICS: + sq->so.num_primitives_written = 0; + sq->so.primitives_storage_needed = 0; + break; + case PIPE_QUERY_GPU_FINISHED: + break; + case PIPE_QUERY_TIMESTAMP_DISJOINT: + default: + assert(0); + break; + } + softpipe->active_query_count++; + softpipe->dirty |= SP_NEW_QUERY; +} + + +static void +softpipe_end_query(struct pipe_context *pipe, struct pipe_query *q) +{ + struct softpipe_context *softpipe = softpipe_context( pipe ); + struct softpipe_query *sq = softpipe_query(q); + + softpipe->active_query_count--; + switch (sq->type) { + case PIPE_QUERY_OCCLUSION_COUNTER: + sq->end = softpipe->occlusion_count; + break; + case PIPE_QUERY_TIME_ELAPSED: + sq->end = 1000*os_time_get(); + break; + case PIPE_QUERY_SO_STATISTICS: + sq->so.num_primitives_written = + softpipe->so_stats.num_primitives_written; + sq->so.primitives_storage_needed = + softpipe->so_stats.primitives_storage_needed; + break; + case PIPE_QUERY_GPU_FINISHED: + case PIPE_QUERY_TIMESTAMP_DISJOINT: + break; + default: + assert(0); + break; + } + softpipe->dirty |= SP_NEW_QUERY; +} + + +static boolean +softpipe_get_query_result(struct pipe_context *pipe, + struct pipe_query *q, + boolean wait, + void *vresult) +{ + struct softpipe_query *sq = softpipe_query(q); + uint64_t *result = (uint64_t*)vresult; + + switch (sq->type) { + case PIPE_QUERY_SO_STATISTICS: + memcpy(vresult, &sq->so, + sizeof(struct pipe_query_data_so_statistics)); + break; + case PIPE_QUERY_GPU_FINISHED: + *result = TRUE; + break; + case PIPE_QUERY_TIMESTAMP_DISJOINT: { + struct pipe_query_data_timestamp_disjoint td; + /*os_get_time is in microseconds*/ + td.frequency = 1000000; + td.disjoint = FALSE; + memcpy(vresult, &sq->so, + sizeof(struct pipe_query_data_timestamp_disjoint)); + } + break; + default: + *result = sq->end - sq->start; + break; + } + return TRUE; +} + + +/** + * Called by rendering function to check rendering is conditional. + * \return TRUE if we should render, FALSE if we should skip rendering + */ +boolean +softpipe_check_render_cond(struct softpipe_context *sp) +{ + struct pipe_context *pipe = &sp->pipe; + boolean b, wait; + uint64_t result; + + if (!sp->render_cond_query) { + return TRUE; /* no query predicate, draw normally */ + } + + wait = (sp->render_cond_mode == PIPE_RENDER_COND_WAIT || + sp->render_cond_mode == PIPE_RENDER_COND_BY_REGION_WAIT); + + b = pipe->get_query_result(pipe, sp->render_cond_query, wait, &result); + if (b) + return result > 0; + else + return TRUE; +} + + +void softpipe_init_query_funcs(struct softpipe_context *softpipe ) +{ + softpipe->pipe.create_query = softpipe_create_query; + softpipe->pipe.destroy_query = softpipe_destroy_query; + softpipe->pipe.begin_query = softpipe_begin_query; + softpipe->pipe.end_query = softpipe_end_query; + softpipe->pipe.get_query_result = softpipe_get_query_result; +} + + diff --git a/src/gallium/drivers/softpipe/sp_query.h b/src/gallium/drivers/softpipe/sp_query.h new file mode 100644 index 0000000000..736c033897 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_query.h @@ -0,0 +1,43 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* Author: + * Keith Whitwell + */ + +#ifndef SP_QUERY_H +#define SP_QUERY_H + +extern boolean +softpipe_check_render_cond(struct softpipe_context *sp); + + +struct softpipe_context; +extern void softpipe_init_query_funcs(struct softpipe_context * ); + + +#endif /* SP_QUERY_H */ diff --git a/src/gallium/drivers/softpipe/sp_screen.c b/src/gallium/drivers/softpipe/sp_screen.c new file mode 100644 index 0000000000..fc57d3eb61 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_screen.c @@ -0,0 +1,330 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#include "util/u_memory.h" +#include "util/u_format.h" +#include "util/u_format_s3tc.h" +#include "pipe/p_defines.h" +#include "pipe/p_screen.h" + +#include "state_tracker/sw_winsys.h" +#include "tgsi/tgsi_exec.h" + +#include "sp_texture.h" +#include "sp_screen.h" +#include "sp_context.h" +#include "sp_fence.h" +#include "sp_public.h" + + +static const char * +softpipe_get_vendor(struct pipe_screen *screen) +{ + return "VMware, Inc."; +} + + +static const char * +softpipe_get_name(struct pipe_screen *screen) +{ + return "softpipe"; +} + + +static int +softpipe_get_param(struct pipe_screen *screen, enum pipe_cap param) +{ + switch (param) { + case PIPE_CAP_MAX_TEXTURE_IMAGE_UNITS: + return PIPE_MAX_SAMPLERS; + case PIPE_CAP_MAX_VERTEX_TEXTURE_UNITS: + return PIPE_MAX_VERTEX_SAMPLERS; + case PIPE_CAP_MAX_COMBINED_SAMPLERS: + return PIPE_MAX_SAMPLERS + PIPE_MAX_VERTEX_SAMPLERS; + case PIPE_CAP_NPOT_TEXTURES: + return 1; + case PIPE_CAP_TWO_SIDED_STENCIL: + return 1; + case PIPE_CAP_GLSL: + return 1; + case PIPE_CAP_SM3: + return 1; + case PIPE_CAP_ANISOTROPIC_FILTER: + return 0; + case PIPE_CAP_POINT_SPRITE: + return 1; + case PIPE_CAP_MAX_RENDER_TARGETS: + return PIPE_MAX_COLOR_BUFS; + case PIPE_CAP_OCCLUSION_QUERY: + return 1; + case PIPE_CAP_TIMER_QUERY: + return 1; + case PIPE_CAP_TEXTURE_MIRROR_CLAMP: + return 1; + case PIPE_CAP_TEXTURE_MIRROR_REPEAT: + return 1; + case PIPE_CAP_TEXTURE_SHADOW_MAP: + return 1; + case PIPE_CAP_TEXTURE_SWIZZLE: + return 1; + case PIPE_CAP_MAX_TEXTURE_2D_LEVELS: + return SP_MAX_TEXTURE_2D_LEVELS; + case PIPE_CAP_MAX_TEXTURE_3D_LEVELS: + return SP_MAX_TEXTURE_3D_LEVELS; + case PIPE_CAP_MAX_TEXTURE_CUBE_LEVELS: + return SP_MAX_TEXTURE_2D_LEVELS; + case PIPE_CAP_TGSI_CONT_SUPPORTED: + return 1; + case PIPE_CAP_BLEND_EQUATION_SEPARATE: + return 1; + case PIPE_CAP_MAX_CONST_BUFFERS: + return PIPE_MAX_CONSTANT_BUFFERS; + case PIPE_CAP_MAX_CONST_BUFFER_SIZE: + return 4096 * 4 * sizeof(float); + case PIPE_CAP_INDEP_BLEND_ENABLE: + return 1; + case PIPE_CAP_INDEP_BLEND_FUNC: + return 1; + case PIPE_CAP_TGSI_FS_COORD_ORIGIN_UPPER_LEFT: + case PIPE_CAP_TGSI_FS_COORD_ORIGIN_LOWER_LEFT: + case PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_HALF_INTEGER: + case PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_INTEGER: + return 1; + case PIPE_CAP_STREAM_OUTPUT: + return 1; + + case PIPE_CAP_MAX_VS_INSTRUCTIONS: + case PIPE_CAP_MAX_FS_INSTRUCTIONS: + case PIPE_CAP_MAX_VS_ALU_INSTRUCTIONS: + case PIPE_CAP_MAX_FS_ALU_INSTRUCTIONS: + case PIPE_CAP_MAX_VS_TEX_INSTRUCTIONS: + case PIPE_CAP_MAX_FS_TEX_INSTRUCTIONS: + case PIPE_CAP_MAX_VS_TEX_INDIRECTIONS: + case PIPE_CAP_MAX_FS_TEX_INDIRECTIONS: + /* There is no limit in number of instructions beyond available memory */ + return 32768; + case PIPE_CAP_MAX_VS_CONTROL_FLOW_DEPTH: + case PIPE_CAP_MAX_FS_CONTROL_FLOW_DEPTH: + return TGSI_EXEC_MAX_NESTING; + case PIPE_CAP_MAX_VS_INPUTS: + case PIPE_CAP_MAX_FS_INPUTS: + return TGSI_EXEC_MAX_INPUT_ATTRIBS; + case PIPE_CAP_MAX_FS_CONSTS: + case PIPE_CAP_MAX_VS_CONSTS: + return TGSI_EXEC_MAX_CONST_BUFFER; + case PIPE_CAP_MAX_VS_TEMPS: + case PIPE_CAP_MAX_FS_TEMPS: + return TGSI_EXEC_NUM_TEMPS; + case PIPE_CAP_MAX_VS_ADDRS: + case PIPE_CAP_MAX_FS_ADDRS: + return TGSI_EXEC_NUM_ADDRS; + case PIPE_CAP_MAX_VS_PREDS: + case PIPE_CAP_MAX_FS_PREDS: + return TGSI_EXEC_NUM_PREDS; + + case PIPE_CAP_DEPTHSTENCIL_CLEAR_SEPARATE: + return 0; + default: + return 0; + } +} + + +static float +softpipe_get_paramf(struct pipe_screen *screen, enum pipe_cap param) +{ + switch (param) { + case PIPE_CAP_MAX_LINE_WIDTH: + /* fall-through */ + case PIPE_CAP_MAX_LINE_WIDTH_AA: + return 255.0; /* arbitrary */ + case PIPE_CAP_MAX_POINT_WIDTH: + /* fall-through */ + case PIPE_CAP_MAX_POINT_WIDTH_AA: + return 255.0; /* arbitrary */ + case PIPE_CAP_MAX_TEXTURE_ANISOTROPY: + return 16.0; /* not actually signficant at this time */ + case PIPE_CAP_MAX_TEXTURE_LOD_BIAS: + return 16.0; /* arbitrary */ + default: + return 0; + } +} + + +/** + * Query format support for creating a texture, drawing surface, etc. + * \param format the format to test + * \param type one of PIPE_TEXTURE, PIPE_SURFACE + */ +static boolean +softpipe_is_format_supported( struct pipe_screen *screen, + enum pipe_format format, + enum pipe_texture_target target, + unsigned sample_count, + unsigned bind, + unsigned geom_flags ) +{ + struct sw_winsys *winsys = softpipe_screen(screen)->winsys; + const struct util_format_description *format_desc; + + assert(target == PIPE_BUFFER || + target == PIPE_TEXTURE_1D || + target == PIPE_TEXTURE_2D || + target == PIPE_TEXTURE_3D || + target == PIPE_TEXTURE_CUBE); + + format_desc = util_format_description(format); + if (!format_desc) + return FALSE; + + if (sample_count > 1) + return FALSE; + + if (bind & (PIPE_BIND_DISPLAY_TARGET | + PIPE_BIND_SCANOUT | + PIPE_BIND_SHARED)) { + if(!winsys->is_displaytarget_format_supported(winsys, bind, format)) + return FALSE; + } + + if (bind & PIPE_BIND_RENDER_TARGET) { + if (format_desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS) + return FALSE; + + /* + * Although possible, it is unnatural to render into compressed or YUV + * surfaces. So disable these here to avoid going into weird paths + * inside the state trackers. + */ + if (format_desc->block.width != 1 || + format_desc->block.height != 1) + return FALSE; + + /* + * TODO: Unfortunately we cannot render into anything more than 32 bits + * because we encode color clear values into a 32bit word. + */ + if (format_desc->block.bits > 32) + return FALSE; + } + + if (bind & PIPE_BIND_DEPTH_STENCIL) { + if (format_desc->colorspace != UTIL_FORMAT_COLORSPACE_ZS) + return FALSE; + + /* + * TODO: Unfortunately we cannot render into anything more than 32 bits + * because we encode depth and stencil clear values into a 32bit word. + */ + if (format_desc->block.bits > 32) + return FALSE; + + /* + * TODO: eliminate this restriction + */ + if (format == PIPE_FORMAT_Z32_FLOAT) + return FALSE; + } + + /* + * All other operations (sampling, transfer, etc). + */ + + if (format_desc->layout == UTIL_FORMAT_LAYOUT_S3TC) { + return util_format_s3tc_enabled; + } + + /* + * Everything else should be supported by u_format. + */ + return TRUE; +} + + +static void +softpipe_destroy_screen( struct pipe_screen *screen ) +{ + struct softpipe_screen *sp_screen = softpipe_screen(screen); + struct sw_winsys *winsys = sp_screen->winsys; + + if(winsys->destroy) + winsys->destroy(winsys); + + FREE(screen); +} + + +/* This is often overriden by the co-state tracker. + */ +static void +softpipe_flush_frontbuffer(struct pipe_screen *_screen, + struct pipe_surface *surface, + void *context_private) +{ + struct softpipe_screen *screen = softpipe_screen(_screen); + struct sw_winsys *winsys = screen->winsys; + struct softpipe_resource *texture = softpipe_resource(surface->texture); + + assert(texture->dt); + if (texture->dt) + winsys->displaytarget_display(winsys, texture->dt, context_private); +} + +/** + * Create a new pipe_screen object + * Note: we're not presently subclassing pipe_screen (no softpipe_screen). + */ +struct pipe_screen * +softpipe_create_screen(struct sw_winsys *winsys) +{ + struct softpipe_screen *screen = CALLOC_STRUCT(softpipe_screen); + + if (!screen) + return NULL; + + screen->winsys = winsys; + + screen->base.winsys = NULL; + screen->base.destroy = softpipe_destroy_screen; + + screen->base.get_name = softpipe_get_name; + screen->base.get_vendor = softpipe_get_vendor; + screen->base.get_param = softpipe_get_param; + screen->base.get_paramf = softpipe_get_paramf; + screen->base.is_format_supported = softpipe_is_format_supported; + screen->base.context_create = softpipe_create_context; + screen->base.flush_frontbuffer = softpipe_flush_frontbuffer; + + util_format_s3tc_init(); + + softpipe_init_screen_texture_funcs(&screen->base); + softpipe_init_screen_fence_funcs(&screen->base); + + return &screen->base; +} diff --git a/src/gallium/drivers/softpipe/sp_screen.h b/src/gallium/drivers/softpipe/sp_screen.h new file mode 100644 index 0000000000..f741454c9e --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_screen.h @@ -0,0 +1,62 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* Authors: Keith Whitwell <keith@tungstengraphics.com> + */ + +#ifndef SP_SCREEN_H +#define SP_SCREEN_H + +#include "pipe/p_screen.h" +#include "pipe/p_defines.h" + + +struct sw_winsys; + +struct softpipe_screen { + struct pipe_screen base; + + struct sw_winsys *winsys; + + /* Increments whenever textures are modified. Contexts can track + * this. + */ + unsigned timestamp; +}; + + + + +static INLINE struct softpipe_screen * +softpipe_screen( struct pipe_screen *pipe ) +{ + return (struct softpipe_screen *)pipe; +} + + + +#endif /* SP_SCREEN_H */ diff --git a/src/gallium/drivers/softpipe/sp_setup.c b/src/gallium/drivers/softpipe/sp_setup.c new file mode 100644 index 0000000000..5d727dc00d --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_setup.c @@ -0,0 +1,1447 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/** + * \brief Primitive rasterization/rendering (points, lines, triangles) + * + * \author Keith Whitwell <keith@tungstengraphics.com> + * \author Brian Paul + */ + +#include "sp_context.h" +#include "sp_quad.h" +#include "sp_quad_pipe.h" +#include "sp_setup.h" +#include "sp_state.h" +#include "draw/draw_context.h" +#include "draw/draw_vertex.h" +#include "pipe/p_shader_tokens.h" +#include "util/u_math.h" +#include "util/u_memory.h" + + +#define DEBUG_VERTS 0 +#define DEBUG_FRAGS 0 + + +/** + * Triangle edge info + */ +struct edge { + float dx; /**< X(v1) - X(v0), used only during setup */ + float dy; /**< Y(v1) - Y(v0), used only during setup */ + float dxdy; /**< dx/dy */ + float sx, sy; /**< first sample point coord */ + int lines; /**< number of lines on this edge */ +}; + + +/** + * Max number of quads (2x2 pixel blocks) to process per batch. + * This can't be arbitrarily increased since we depend on some 32-bit + * bitmasks (two bits per quad). + */ +#define MAX_QUADS 16 + + +/** + * Triangle setup info. + * Also used for line drawing (taking some liberties). + */ +struct setup_context { + struct softpipe_context *softpipe; + + /* Vertices are just an array of floats making up each attribute in + * turn. Currently fixed at 4 floats, but should change in time. + * Codegen will help cope with this. + */ + const float (*vmax)[4]; + const float (*vmid)[4]; + const float (*vmin)[4]; + const float (*vprovoke)[4]; + + struct edge ebot; + struct edge etop; + struct edge emaj; + + float oneoverarea; + int facing; + + float pixel_offset; + + struct quad_header quad[MAX_QUADS]; + struct quad_header *quad_ptrs[MAX_QUADS]; + unsigned count; + + struct tgsi_interp_coef coef[PIPE_MAX_SHADER_INPUTS]; + struct tgsi_interp_coef posCoef; /* For Z, W */ + + struct { + int left[2]; /**< [0] = row0, [1] = row1 */ + int right[2]; + int y; + } span; + +#if DEBUG_FRAGS + uint numFragsEmitted; /**< per primitive */ + uint numFragsWritten; /**< per primitive */ +#endif + + unsigned cull_face; /* which faces cull */ + unsigned nr_vertex_attrs; +}; + + + + + + + +/** + * Clip setup->quad against the scissor/surface bounds. + */ +static INLINE void +quad_clip(struct setup_context *setup, struct quad_header *quad) +{ + const struct pipe_scissor_state *cliprect = &setup->softpipe->cliprect; + const int minx = (int) cliprect->minx; + const int maxx = (int) cliprect->maxx; + const int miny = (int) cliprect->miny; + const int maxy = (int) cliprect->maxy; + + if (quad->input.x0 >= maxx || + quad->input.y0 >= maxy || + quad->input.x0 + 1 < minx || + quad->input.y0 + 1 < miny) { + /* totally clipped */ + quad->inout.mask = 0x0; + return; + } + if (quad->input.x0 < minx) + quad->inout.mask &= (MASK_BOTTOM_RIGHT | MASK_TOP_RIGHT); + if (quad->input.y0 < miny) + quad->inout.mask &= (MASK_BOTTOM_LEFT | MASK_BOTTOM_RIGHT); + if (quad->input.x0 == maxx - 1) + quad->inout.mask &= (MASK_BOTTOM_LEFT | MASK_TOP_LEFT); + if (quad->input.y0 == maxy - 1) + quad->inout.mask &= (MASK_TOP_LEFT | MASK_TOP_RIGHT); +} + + +/** + * Emit a quad (pass to next stage) with clipping. + */ +static INLINE void +clip_emit_quad(struct setup_context *setup, struct quad_header *quad) +{ + quad_clip( setup, quad ); + + if (quad->inout.mask) { + struct softpipe_context *sp = setup->softpipe; + + sp->quad.first->run( sp->quad.first, &quad, 1 ); + } +} + + + +/** + * Given an X or Y coordinate, return the block/quad coordinate that it + * belongs to. + */ +static INLINE int +block(int x) +{ + return x & ~(2-1); +} + + +static INLINE int +block_x(int x) +{ + return x & ~(16-1); +} + + +/** + * Render a horizontal span of quads + */ +static void +flush_spans(struct setup_context *setup) +{ + const int step = MAX_QUADS; + const int xleft0 = setup->span.left[0]; + const int xleft1 = setup->span.left[1]; + const int xright0 = setup->span.right[0]; + const int xright1 = setup->span.right[1]; + struct quad_stage *pipe = setup->softpipe->quad.first; + + const int minleft = block_x(MIN2(xleft0, xleft1)); + const int maxright = MAX2(xright0, xright1); + int x; + + /* process quads in horizontal chunks of 16 */ + for (x = minleft; x < maxright; x += step) { + unsigned skip_left0 = CLAMP(xleft0 - x, 0, step); + unsigned skip_left1 = CLAMP(xleft1 - x, 0, step); + unsigned skip_right0 = CLAMP(x + step - xright0, 0, step); + unsigned skip_right1 = CLAMP(x + step - xright1, 0, step); + unsigned lx = x; + unsigned q = 0; + + unsigned skipmask_left0 = (1U << skip_left0) - 1U; + unsigned skipmask_left1 = (1U << skip_left1) - 1U; + + /* These calculations fail when step == 32 and skip_right == 0. + */ + unsigned skipmask_right0 = ~0U << (unsigned)(step - skip_right0); + unsigned skipmask_right1 = ~0U << (unsigned)(step - skip_right1); + + unsigned mask0 = ~skipmask_left0 & ~skipmask_right0; + unsigned mask1 = ~skipmask_left1 & ~skipmask_right1; + + if (mask0 | mask1) { + do { + unsigned quadmask = (mask0 & 3) | ((mask1 & 3) << 2); + if (quadmask) { + setup->quad[q].input.x0 = lx; + setup->quad[q].input.y0 = setup->span.y; + setup->quad[q].input.facing = setup->facing; + setup->quad[q].inout.mask = quadmask; + setup->quad_ptrs[q] = &setup->quad[q]; + q++; + } + mask0 >>= 2; + mask1 >>= 2; + lx += 2; + } while (mask0 | mask1); + + pipe->run( pipe, setup->quad_ptrs, q ); + } + } + + + setup->span.y = 0; + setup->span.right[0] = 0; + setup->span.right[1] = 0; + setup->span.left[0] = 1000000; /* greater than right[0] */ + setup->span.left[1] = 1000000; /* greater than right[1] */ +} + + +#if DEBUG_VERTS +static void +print_vertex(const struct setup_context *setup, + const float (*v)[4]) +{ + int i; + debug_printf(" Vertex: (%p)\n", (void *) v); + for (i = 0; i < setup->nr_vertex_attrs; i++) { + debug_printf(" %d: %f %f %f %f\n", i, + v[i][0], v[i][1], v[i][2], v[i][3]); + if (util_is_inf_or_nan(v[i][0])) { + debug_printf(" NaN!\n"); + } + } +} +#endif + + +/** + * Sort the vertices from top to bottom order, setting up the triangle + * edge fields (ebot, emaj, etop). + * \return FALSE if coords are inf/nan (cull the tri), TRUE otherwise + */ +static boolean +setup_sort_vertices(struct setup_context *setup, + float det, + const float (*v0)[4], + const float (*v1)[4], + const float (*v2)[4]) +{ + if (setup->softpipe->rasterizer->flatshade_first) + setup->vprovoke = v0; + else + setup->vprovoke = v2; + + /* determine bottom to top order of vertices */ + { + float y0 = v0[0][1]; + float y1 = v1[0][1]; + float y2 = v2[0][1]; + if (y0 <= y1) { + if (y1 <= y2) { + /* y0<=y1<=y2 */ + setup->vmin = v0; + setup->vmid = v1; + setup->vmax = v2; + } + else if (y2 <= y0) { + /* y2<=y0<=y1 */ + setup->vmin = v2; + setup->vmid = v0; + setup->vmax = v1; + } + else { + /* y0<=y2<=y1 */ + setup->vmin = v0; + setup->vmid = v2; + setup->vmax = v1; + } + } + else { + if (y0 <= y2) { + /* y1<=y0<=y2 */ + setup->vmin = v1; + setup->vmid = v0; + setup->vmax = v2; + } + else if (y2 <= y1) { + /* y2<=y1<=y0 */ + setup->vmin = v2; + setup->vmid = v1; + setup->vmax = v0; + } + else { + /* y1<=y2<=y0 */ + setup->vmin = v1; + setup->vmid = v2; + setup->vmax = v0; + } + } + } + + setup->ebot.dx = setup->vmid[0][0] - setup->vmin[0][0]; + setup->ebot.dy = setup->vmid[0][1] - setup->vmin[0][1]; + setup->emaj.dx = setup->vmax[0][0] - setup->vmin[0][0]; + setup->emaj.dy = setup->vmax[0][1] - setup->vmin[0][1]; + setup->etop.dx = setup->vmax[0][0] - setup->vmid[0][0]; + setup->etop.dy = setup->vmax[0][1] - setup->vmid[0][1]; + + /* + * Compute triangle's area. Use 1/area to compute partial + * derivatives of attributes later. + * + * The area will be the same as prim->det, but the sign may be + * different depending on how the vertices get sorted above. + * + * To determine whether the primitive is front or back facing we + * use the prim->det value because its sign is correct. + */ + { + const float area = (setup->emaj.dx * setup->ebot.dy - + setup->ebot.dx * setup->emaj.dy); + + setup->oneoverarea = 1.0f / area; + + /* + debug_printf("%s one-over-area %f area %f det %f\n", + __FUNCTION__, setup->oneoverarea, area, det ); + */ + if (util_is_inf_or_nan(setup->oneoverarea)) + return FALSE; + } + + /* We need to know if this is a front or back-facing triangle for: + * - the GLSL gl_FrontFacing fragment attribute (bool) + * - two-sided stencil test + * 0 = front-facing, 1 = back-facing + */ + setup->facing = + ((det < 0.0) ^ + (setup->softpipe->rasterizer->front_ccw)); + + { + unsigned face = setup->facing == 0 ? PIPE_FACE_FRONT : PIPE_FACE_BACK; + + if (face & setup->cull_face) + return FALSE; + } + + + /* Prepare pixel offset for rasterisation: + * - pixel center (0.5, 0.5) for GL, or + * - assume (0.0, 0.0) for other APIs. + */ + if (setup->softpipe->rasterizer->gl_rasterization_rules) { + setup->pixel_offset = 0.5f; + } else { + setup->pixel_offset = 0.0f; + } + + return TRUE; +} + + +/* Apply cylindrical wrapping to v0, v1, v2 coordinates, if enabled. + * Input coordinates must be in [0, 1] range, otherwise results are undefined. + * Some combinations of coordinates produce invalid results, + * but this behaviour is acceptable. + */ +static void +tri_apply_cylindrical_wrap(float v0, + float v1, + float v2, + uint cylindrical_wrap, + float output[3]) +{ + if (cylindrical_wrap) { + float delta; + + delta = v1 - v0; + if (delta > 0.5f) { + v0 += 1.0f; + } + else if (delta < -0.5f) { + v1 += 1.0f; + } + + delta = v2 - v1; + if (delta > 0.5f) { + v1 += 1.0f; + } + else if (delta < -0.5f) { + v2 += 1.0f; + } + + delta = v0 - v2; + if (delta > 0.5f) { + v2 += 1.0f; + } + else if (delta < -0.5f) { + v0 += 1.0f; + } + } + + output[0] = v0; + output[1] = v1; + output[2] = v2; +} + + +/** + * Compute a0 for a constant-valued coefficient (GL_FLAT shading). + * The value value comes from vertex[slot][i]. + * The result will be put into setup->coef[slot].a0[i]. + * \param slot which attribute slot + * \param i which component of the slot (0..3) + */ +static void +const_coeff(struct setup_context *setup, + struct tgsi_interp_coef *coef, + uint vertSlot, uint i) +{ + assert(i <= 3); + + coef->dadx[i] = 0; + coef->dady[i] = 0; + + /* need provoking vertex info! + */ + coef->a0[i] = setup->vprovoke[vertSlot][i]; +} + + +/** + * Compute a0, dadx and dady for a linearly interpolated coefficient, + * for a triangle. + * v[0], v[1] and v[2] are vmin, vmid and vmax, respectively. + */ +static void +tri_linear_coeff(struct setup_context *setup, + struct tgsi_interp_coef *coef, + uint i, + const float v[3]) +{ + float botda = v[1] - v[0]; + float majda = v[2] - v[0]; + float a = setup->ebot.dy * majda - botda * setup->emaj.dy; + float b = setup->emaj.dx * botda - majda * setup->ebot.dx; + float dadx = a * setup->oneoverarea; + float dady = b * setup->oneoverarea; + + assert(i <= 3); + + coef->dadx[i] = dadx; + coef->dady[i] = dady; + + /* calculate a0 as the value which would be sampled for the + * fragment at (0,0), taking into account that we want to sample at + * pixel centers, in other words (pixel_offset, pixel_offset). + * + * this is neat but unfortunately not a good way to do things for + * triangles with very large values of dadx or dady as it will + * result in the subtraction and re-addition from a0 of a very + * large number, which means we'll end up loosing a lot of the + * fractional bits and precision from a0. the way to fix this is + * to define a0 as the sample at a pixel center somewhere near vmin + * instead - i'll switch to this later. + */ + coef->a0[i] = (v[0] - + (dadx * (setup->vmin[0][0] - setup->pixel_offset) + + dady * (setup->vmin[0][1] - setup->pixel_offset))); + + /* + debug_printf("attr[%d].%c: %f dx:%f dy:%f\n", + slot, "xyzw"[i], + setup->coef[slot].a0[i], + setup->coef[slot].dadx[i], + setup->coef[slot].dady[i]); + */ +} + + +/** + * Compute a0, dadx and dady for a perspective-corrected interpolant, + * for a triangle. + * We basically multiply the vertex value by 1/w before computing + * the plane coefficients (a0, dadx, dady). + * Later, when we compute the value at a particular fragment position we'll + * divide the interpolated value by the interpolated W at that fragment. + * v[0], v[1] and v[2] are vmin, vmid and vmax, respectively. + */ +static void +tri_persp_coeff(struct setup_context *setup, + struct tgsi_interp_coef *coef, + uint i, + const float v[3]) +{ + /* premultiply by 1/w (v[0][3] is always W): + */ + float mina = v[0] * setup->vmin[0][3]; + float mida = v[1] * setup->vmid[0][3]; + float maxa = v[2] * setup->vmax[0][3]; + float botda = mida - mina; + float majda = maxa - mina; + float a = setup->ebot.dy * majda - botda * setup->emaj.dy; + float b = setup->emaj.dx * botda - majda * setup->ebot.dx; + float dadx = a * setup->oneoverarea; + float dady = b * setup->oneoverarea; + + /* + debug_printf("tri persp %d,%d: %f %f %f\n", vertSlot, i, + setup->vmin[vertSlot][i], + setup->vmid[vertSlot][i], + setup->vmax[vertSlot][i] + ); + */ + assert(i <= 3); + + coef->dadx[i] = dadx; + coef->dady[i] = dady; + coef->a0[i] = (mina - + (dadx * (setup->vmin[0][0] - setup->pixel_offset) + + dady * (setup->vmin[0][1] - setup->pixel_offset))); +} + + +/** + * Special coefficient setup for gl_FragCoord. + * X and Y are trivial, though Y may have to be inverted for OpenGL. + * Z and W are copied from posCoef which should have already been computed. + * We could do a bit less work if we'd examine gl_FragCoord's swizzle mask. + */ +static void +setup_fragcoord_coeff(struct setup_context *setup, uint slot) +{ + struct sp_fragment_shader* spfs = setup->softpipe->fs; + /*X*/ + setup->coef[slot].a0[0] = spfs->pixel_center_integer ? 0.0 : 0.5; + setup->coef[slot].dadx[0] = 1.0; + setup->coef[slot].dady[0] = 0.0; + /*Y*/ + setup->coef[slot].a0[1] = + (spfs->origin_lower_left ? setup->softpipe->framebuffer.height : 0) + + (spfs->pixel_center_integer ? 0.0 : 0.5); + setup->coef[slot].dadx[1] = 0.0; + setup->coef[slot].dady[1] = spfs->origin_lower_left ? -1.0 : 1.0; + /*Z*/ + setup->coef[slot].a0[2] = setup->posCoef.a0[2]; + setup->coef[slot].dadx[2] = setup->posCoef.dadx[2]; + setup->coef[slot].dady[2] = setup->posCoef.dady[2]; + /*W*/ + setup->coef[slot].a0[3] = setup->posCoef.a0[3]; + setup->coef[slot].dadx[3] = setup->posCoef.dadx[3]; + setup->coef[slot].dady[3] = setup->posCoef.dady[3]; +} + + + +/** + * Compute the setup->coef[] array dadx, dady, a0 values. + * Must be called after setup->vmin,vmid,vmax,vprovoke are initialized. + */ +static void +setup_tri_coefficients(struct setup_context *setup) +{ + struct softpipe_context *softpipe = setup->softpipe; + const struct sp_fragment_shader *spfs = softpipe->fs; + const struct vertex_info *vinfo = softpipe_get_vertex_info(softpipe); + uint fragSlot; + float v[3]; + + /* z and w are done by linear interpolation: + */ + v[0] = setup->vmin[0][2]; + v[1] = setup->vmid[0][2]; + v[2] = setup->vmax[0][2]; + tri_linear_coeff(setup, &setup->posCoef, 2, v); + + v[0] = setup->vmin[0][3]; + v[1] = setup->vmid[0][3]; + v[2] = setup->vmax[0][3]; + tri_linear_coeff(setup, &setup->posCoef, 3, v); + + /* setup interpolation for all the remaining attributes: + */ + for (fragSlot = 0; fragSlot < spfs->info.num_inputs; fragSlot++) { + const uint vertSlot = vinfo->attrib[fragSlot].src_index; + uint j; + + switch (vinfo->attrib[fragSlot].interp_mode) { + case INTERP_CONSTANT: + for (j = 0; j < NUM_CHANNELS; j++) + const_coeff(setup, &setup->coef[fragSlot], vertSlot, j); + break; + case INTERP_LINEAR: + for (j = 0; j < NUM_CHANNELS; j++) { + tri_apply_cylindrical_wrap(setup->vmin[vertSlot][j], + setup->vmid[vertSlot][j], + setup->vmax[vertSlot][j], + spfs->info.input_cylindrical_wrap[fragSlot] & (1 << j), + v); + tri_linear_coeff(setup, &setup->coef[fragSlot], j, v); + } + break; + case INTERP_PERSPECTIVE: + for (j = 0; j < NUM_CHANNELS; j++) { + tri_apply_cylindrical_wrap(setup->vmin[vertSlot][j], + setup->vmid[vertSlot][j], + setup->vmax[vertSlot][j], + spfs->info.input_cylindrical_wrap[fragSlot] & (1 << j), + v); + tri_persp_coeff(setup, &setup->coef[fragSlot], j, v); + } + break; + case INTERP_POS: + setup_fragcoord_coeff(setup, fragSlot); + break; + default: + assert(0); + } + + if (spfs->info.input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) { + /* convert 0 to 1.0 and 1 to -1.0 */ + setup->coef[fragSlot].a0[0] = setup->facing * -2.0f + 1.0f; + setup->coef[fragSlot].dadx[0] = 0.0; + setup->coef[fragSlot].dady[0] = 0.0; + } + } +} + + +static void +setup_tri_edges(struct setup_context *setup) +{ + float vmin_x = setup->vmin[0][0] + setup->pixel_offset; + float vmid_x = setup->vmid[0][0] + setup->pixel_offset; + + float vmin_y = setup->vmin[0][1] - setup->pixel_offset; + float vmid_y = setup->vmid[0][1] - setup->pixel_offset; + float vmax_y = setup->vmax[0][1] - setup->pixel_offset; + + setup->emaj.sy = ceilf(vmin_y); + setup->emaj.lines = (int) ceilf(vmax_y - setup->emaj.sy); + setup->emaj.dxdy = setup->emaj.dy ? setup->emaj.dx / setup->emaj.dy : .0f; + setup->emaj.sx = vmin_x + (setup->emaj.sy - vmin_y) * setup->emaj.dxdy; + + setup->etop.sy = ceilf(vmid_y); + setup->etop.lines = (int) ceilf(vmax_y - setup->etop.sy); + setup->etop.dxdy = setup->etop.dy ? setup->etop.dx / setup->etop.dy : .0f; + setup->etop.sx = vmid_x + (setup->etop.sy - vmid_y) * setup->etop.dxdy; + + setup->ebot.sy = ceilf(vmin_y); + setup->ebot.lines = (int) ceilf(vmid_y - setup->ebot.sy); + setup->ebot.dxdy = setup->ebot.dy ? setup->ebot.dx / setup->ebot.dy : .0f; + setup->ebot.sx = vmin_x + (setup->ebot.sy - vmin_y) * setup->ebot.dxdy; +} + + +/** + * Render the upper or lower half of a triangle. + * Scissoring/cliprect is applied here too. + */ +static void +subtriangle(struct setup_context *setup, + struct edge *eleft, + struct edge *eright, + int lines) +{ + const struct pipe_scissor_state *cliprect = &setup->softpipe->cliprect; + const int minx = (int) cliprect->minx; + const int maxx = (int) cliprect->maxx; + const int miny = (int) cliprect->miny; + const int maxy = (int) cliprect->maxy; + int y, start_y, finish_y; + int sy = (int)eleft->sy; + + assert((int)eleft->sy == (int) eright->sy); + assert(lines >= 0); + + /* clip top/bottom */ + start_y = sy; + if (start_y < miny) + start_y = miny; + + finish_y = sy + lines; + if (finish_y > maxy) + finish_y = maxy; + + start_y -= sy; + finish_y -= sy; + + /* + debug_printf("%s %d %d\n", __FUNCTION__, start_y, finish_y); + */ + + for (y = start_y; y < finish_y; y++) { + + /* avoid accumulating adds as floats don't have the precision to + * accurately iterate large triangle edges that way. luckily we + * can just multiply these days. + * + * this is all drowned out by the attribute interpolation anyway. + */ + int left = (int)(eleft->sx + y * eleft->dxdy); + int right = (int)(eright->sx + y * eright->dxdy); + + /* clip left/right */ + if (left < minx) + left = minx; + if (right > maxx) + right = maxx; + + if (left < right) { + int _y = sy + y; + if (block(_y) != setup->span.y) { + flush_spans(setup); + setup->span.y = block(_y); + } + + setup->span.left[_y&1] = left; + setup->span.right[_y&1] = right; + } + } + + + /* save the values so that emaj can be restarted: + */ + eleft->sx += lines * eleft->dxdy; + eright->sx += lines * eright->dxdy; + eleft->sy += lines; + eright->sy += lines; +} + + +/** + * Recalculate prim's determinant. This is needed as we don't have + * get this information through the vbuf_render interface & we must + * calculate it here. + */ +static float +calc_det(const float (*v0)[4], + const float (*v1)[4], + const float (*v2)[4]) +{ + /* edge vectors e = v0 - v2, f = v1 - v2 */ + const float ex = v0[0][0] - v2[0][0]; + const float ey = v0[0][1] - v2[0][1]; + const float fx = v1[0][0] - v2[0][0]; + const float fy = v1[0][1] - v2[0][1]; + + /* det = cross(e,f).z */ + return ex * fy - ey * fx; +} + + +/** + * Do setup for triangle rasterization, then render the triangle. + */ +void +sp_setup_tri(struct setup_context *setup, + const float (*v0)[4], + const float (*v1)[4], + const float (*v2)[4]) +{ + float det; + +#if DEBUG_VERTS + debug_printf("Setup triangle:\n"); + print_vertex(setup, v0); + print_vertex(setup, v1); + print_vertex(setup, v2); +#endif + + if (setup->softpipe->no_rast) + return; + + det = calc_det(v0, v1, v2); + /* + debug_printf("%s\n", __FUNCTION__ ); + */ + +#if DEBUG_FRAGS + setup->numFragsEmitted = 0; + setup->numFragsWritten = 0; +#endif + + if (!setup_sort_vertices( setup, det, v0, v1, v2 )) + return; + + setup_tri_coefficients( setup ); + setup_tri_edges( setup ); + + assert(setup->softpipe->reduced_prim == PIPE_PRIM_TRIANGLES); + + setup->span.y = 0; + setup->span.right[0] = 0; + setup->span.right[1] = 0; + /* setup->span.z_mode = tri_z_mode( setup->ctx ); */ + + /* init_constant_attribs( setup ); */ + + if (setup->oneoverarea < 0.0) { + /* emaj on left: + */ + subtriangle( setup, &setup->emaj, &setup->ebot, setup->ebot.lines ); + subtriangle( setup, &setup->emaj, &setup->etop, setup->etop.lines ); + } + else { + /* emaj on right: + */ + subtriangle( setup, &setup->ebot, &setup->emaj, setup->ebot.lines ); + subtriangle( setup, &setup->etop, &setup->emaj, setup->etop.lines ); + } + + flush_spans( setup ); + +#if DEBUG_FRAGS + printf("Tri: %u frags emitted, %u written\n", + setup->numFragsEmitted, + setup->numFragsWritten); +#endif +} + + +/* Apply cylindrical wrapping to v0, v1 coordinates, if enabled. + * Input coordinates must be in [0, 1] range, otherwise results are undefined. + */ +static void +line_apply_cylindrical_wrap(float v0, + float v1, + uint cylindrical_wrap, + float output[2]) +{ + if (cylindrical_wrap) { + float delta; + + delta = v1 - v0; + if (delta > 0.5f) { + v0 += 1.0f; + } + else if (delta < -0.5f) { + v1 += 1.0f; + } + } + + output[0] = v0; + output[1] = v1; +} + + +/** + * Compute a0, dadx and dady for a linearly interpolated coefficient, + * for a line. + * v[0] and v[1] are vmin and vmax, respectively. + */ +static void +line_linear_coeff(const struct setup_context *setup, + struct tgsi_interp_coef *coef, + uint i, + const float v[2]) +{ + const float da = v[1] - v[0]; + const float dadx = da * setup->emaj.dx * setup->oneoverarea; + const float dady = da * setup->emaj.dy * setup->oneoverarea; + coef->dadx[i] = dadx; + coef->dady[i] = dady; + coef->a0[i] = (v[0] - + (dadx * (setup->vmin[0][0] - setup->pixel_offset) + + dady * (setup->vmin[0][1] - setup->pixel_offset))); +} + + +/** + * Compute a0, dadx and dady for a perspective-corrected interpolant, + * for a line. + * v[0] and v[1] are vmin and vmax, respectively. + */ +static void +line_persp_coeff(const struct setup_context *setup, + struct tgsi_interp_coef *coef, + uint i, + const float v[2]) +{ + const float a0 = v[0] * setup->vmin[0][3]; + const float a1 = v[1] * setup->vmax[0][3]; + const float da = a1 - a0; + const float dadx = da * setup->emaj.dx * setup->oneoverarea; + const float dady = da * setup->emaj.dy * setup->oneoverarea; + coef->dadx[i] = dadx; + coef->dady[i] = dady; + coef->a0[i] = (a0 - + (dadx * (setup->vmin[0][0] - setup->pixel_offset) + + dady * (setup->vmin[0][1] - setup->pixel_offset))); +} + + +/** + * Compute the setup->coef[] array dadx, dady, a0 values. + * Must be called after setup->vmin,vmax are initialized. + */ +static boolean +setup_line_coefficients(struct setup_context *setup, + const float (*v0)[4], + const float (*v1)[4]) +{ + struct softpipe_context *softpipe = setup->softpipe; + const struct sp_fragment_shader *spfs = softpipe->fs; + const struct vertex_info *vinfo = softpipe_get_vertex_info(softpipe); + uint fragSlot; + float area; + float v[2]; + + /* use setup->vmin, vmax to point to vertices */ + if (softpipe->rasterizer->flatshade_first) + setup->vprovoke = v0; + else + setup->vprovoke = v1; + setup->vmin = v0; + setup->vmax = v1; + + setup->emaj.dx = setup->vmax[0][0] - setup->vmin[0][0]; + setup->emaj.dy = setup->vmax[0][1] - setup->vmin[0][1]; + + /* NOTE: this is not really area but something proportional to it */ + area = setup->emaj.dx * setup->emaj.dx + setup->emaj.dy * setup->emaj.dy; + if (area == 0.0f || util_is_inf_or_nan(area)) + return FALSE; + setup->oneoverarea = 1.0f / area; + + /* z and w are done by linear interpolation: + */ + v[0] = setup->vmin[0][2]; + v[1] = setup->vmax[0][2]; + line_linear_coeff(setup, &setup->posCoef, 2, v); + + v[0] = setup->vmin[0][3]; + v[1] = setup->vmax[0][3]; + line_linear_coeff(setup, &setup->posCoef, 3, v); + + /* setup interpolation for all the remaining attributes: + */ + for (fragSlot = 0; fragSlot < spfs->info.num_inputs; fragSlot++) { + const uint vertSlot = vinfo->attrib[fragSlot].src_index; + uint j; + + switch (vinfo->attrib[fragSlot].interp_mode) { + case INTERP_CONSTANT: + for (j = 0; j < NUM_CHANNELS; j++) + const_coeff(setup, &setup->coef[fragSlot], vertSlot, j); + break; + case INTERP_LINEAR: + for (j = 0; j < NUM_CHANNELS; j++) { + line_apply_cylindrical_wrap(setup->vmin[vertSlot][j], + setup->vmax[vertSlot][j], + spfs->info.input_cylindrical_wrap[fragSlot] & (1 << j), + v); + line_linear_coeff(setup, &setup->coef[fragSlot], j, v); + } + break; + case INTERP_PERSPECTIVE: + for (j = 0; j < NUM_CHANNELS; j++) { + line_apply_cylindrical_wrap(setup->vmin[vertSlot][j], + setup->vmax[vertSlot][j], + spfs->info.input_cylindrical_wrap[fragSlot] & (1 << j), + v); + line_persp_coeff(setup, &setup->coef[fragSlot], j, v); + } + break; + case INTERP_POS: + setup_fragcoord_coeff(setup, fragSlot); + break; + default: + assert(0); + } + + if (spfs->info.input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) { + /* convert 0 to 1.0 and 1 to -1.0 */ + setup->coef[fragSlot].a0[0] = setup->facing * -2.0f + 1.0f; + setup->coef[fragSlot].dadx[0] = 0.0; + setup->coef[fragSlot].dady[0] = 0.0; + } + } + return TRUE; +} + + +/** + * Plot a pixel in a line segment. + */ +static INLINE void +plot(struct setup_context *setup, int x, int y) +{ + const int iy = y & 1; + const int ix = x & 1; + const int quadX = x - ix; + const int quadY = y - iy; + const int mask = (1 << ix) << (2 * iy); + + if (quadX != setup->quad[0].input.x0 || + quadY != setup->quad[0].input.y0) + { + /* flush prev quad, start new quad */ + + if (setup->quad[0].input.x0 != -1) + clip_emit_quad( setup, &setup->quad[0] ); + + setup->quad[0].input.x0 = quadX; + setup->quad[0].input.y0 = quadY; + setup->quad[0].inout.mask = 0x0; + } + + setup->quad[0].inout.mask |= mask; +} + + +/** + * Do setup for line rasterization, then render the line. + * Single-pixel width, no stipple, etc. We rely on the 'draw' module + * to handle stippling and wide lines. + */ +void +sp_setup_line(struct setup_context *setup, + const float (*v0)[4], + const float (*v1)[4]) +{ + int x0 = (int) v0[0][0]; + int x1 = (int) v1[0][0]; + int y0 = (int) v0[0][1]; + int y1 = (int) v1[0][1]; + int dx = x1 - x0; + int dy = y1 - y0; + int xstep, ystep; + +#if DEBUG_VERTS + debug_printf("Setup line:\n"); + print_vertex(setup, v0); + print_vertex(setup, v1); +#endif + + if (setup->softpipe->no_rast) + return; + + if (dx == 0 && dy == 0) + return; + + if (!setup_line_coefficients(setup, v0, v1)) + return; + + assert(v0[0][0] < 1.0e9); + assert(v0[0][1] < 1.0e9); + assert(v1[0][0] < 1.0e9); + assert(v1[0][1] < 1.0e9); + + if (dx < 0) { + dx = -dx; /* make positive */ + xstep = -1; + } + else { + xstep = 1; + } + + if (dy < 0) { + dy = -dy; /* make positive */ + ystep = -1; + } + else { + ystep = 1; + } + + assert(dx >= 0); + assert(dy >= 0); + assert(setup->softpipe->reduced_prim == PIPE_PRIM_LINES); + + setup->quad[0].input.x0 = setup->quad[0].input.y0 = -1; + setup->quad[0].inout.mask = 0x0; + + /* XXX temporary: set coverage to 1.0 so the line appears + * if AA mode happens to be enabled. + */ + setup->quad[0].input.coverage[0] = + setup->quad[0].input.coverage[1] = + setup->quad[0].input.coverage[2] = + setup->quad[0].input.coverage[3] = 1.0; + + if (dx > dy) { + /*** X-major line ***/ + int i; + const int errorInc = dy + dy; + int error = errorInc - dx; + const int errorDec = error - dx; + + for (i = 0; i < dx; i++) { + plot(setup, x0, y0); + + x0 += xstep; + if (error < 0) { + error += errorInc; + } + else { + error += errorDec; + y0 += ystep; + } + } + } + else { + /*** Y-major line ***/ + int i; + const int errorInc = dx + dx; + int error = errorInc - dy; + const int errorDec = error - dy; + + for (i = 0; i < dy; i++) { + plot(setup, x0, y0); + + y0 += ystep; + if (error < 0) { + error += errorInc; + } + else { + error += errorDec; + x0 += xstep; + } + } + } + + /* draw final quad */ + if (setup->quad[0].inout.mask) { + clip_emit_quad( setup, &setup->quad[0] ); + } +} + + +static void +point_persp_coeff(const struct setup_context *setup, + const float (*vert)[4], + struct tgsi_interp_coef *coef, + uint vertSlot, uint i) +{ + assert(i <= 3); + coef->dadx[i] = 0.0F; + coef->dady[i] = 0.0F; + coef->a0[i] = vert[vertSlot][i] * vert[0][3]; +} + + +/** + * Do setup for point rasterization, then render the point. + * Round or square points... + * XXX could optimize a lot for 1-pixel points. + */ +void +sp_setup_point(struct setup_context *setup, + const float (*v0)[4]) +{ + struct softpipe_context *softpipe = setup->softpipe; + const struct sp_fragment_shader *spfs = softpipe->fs; + const int sizeAttr = setup->softpipe->psize_slot; + const float size + = sizeAttr > 0 ? v0[sizeAttr][0] + : setup->softpipe->rasterizer->point_size; + const float halfSize = 0.5F * size; + const boolean round = (boolean) setup->softpipe->rasterizer->point_smooth; + const float x = v0[0][0]; /* Note: data[0] is always position */ + const float y = v0[0][1]; + const struct vertex_info *vinfo = softpipe_get_vertex_info(softpipe); + uint fragSlot; + +#if DEBUG_VERTS + debug_printf("Setup point:\n"); + print_vertex(setup, v0); +#endif + + if (softpipe->no_rast) + return; + + assert(setup->softpipe->reduced_prim == PIPE_PRIM_POINTS); + + /* For points, all interpolants are constant-valued. + * However, for point sprites, we'll need to setup texcoords appropriately. + * XXX: which coefficients are the texcoords??? + * We may do point sprites as textured quads... + * + * KW: We don't know which coefficients are texcoords - ultimately + * the choice of what interpolation mode to use for each attribute + * should be determined by the fragment program, using + * per-attribute declaration statements that include interpolation + * mode as a parameter. So either the fragment program will have + * to be adjusted for pointsprite vs normal point behaviour, or + * otherwise a special interpolation mode will have to be defined + * which matches the required behaviour for point sprites. But - + * the latter is not a feature of normal hardware, and as such + * probably should be ruled out on that basis. + */ + setup->vprovoke = v0; + + /* setup Z, W */ + const_coeff(setup, &setup->posCoef, 0, 2); + const_coeff(setup, &setup->posCoef, 0, 3); + + for (fragSlot = 0; fragSlot < spfs->info.num_inputs; fragSlot++) { + const uint vertSlot = vinfo->attrib[fragSlot].src_index; + uint j; + + switch (vinfo->attrib[fragSlot].interp_mode) { + case INTERP_CONSTANT: + /* fall-through */ + case INTERP_LINEAR: + for (j = 0; j < NUM_CHANNELS; j++) + const_coeff(setup, &setup->coef[fragSlot], vertSlot, j); + break; + case INTERP_PERSPECTIVE: + for (j = 0; j < NUM_CHANNELS; j++) + point_persp_coeff(setup, setup->vprovoke, + &setup->coef[fragSlot], vertSlot, j); + break; + case INTERP_POS: + setup_fragcoord_coeff(setup, fragSlot); + break; + default: + assert(0); + } + + if (spfs->info.input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) { + /* convert 0 to 1.0 and 1 to -1.0 */ + setup->coef[fragSlot].a0[0] = setup->facing * -2.0f + 1.0f; + setup->coef[fragSlot].dadx[0] = 0.0; + setup->coef[fragSlot].dady[0] = 0.0; + } + } + + + if (halfSize <= 0.5 && !round) { + /* special case for 1-pixel points */ + const int ix = ((int) x) & 1; + const int iy = ((int) y) & 1; + setup->quad[0].input.x0 = (int) x - ix; + setup->quad[0].input.y0 = (int) y - iy; + setup->quad[0].inout.mask = (1 << ix) << (2 * iy); + clip_emit_quad( setup, &setup->quad[0] ); + } + else { + if (round) { + /* rounded points */ + const int ixmin = block((int) (x - halfSize)); + const int ixmax = block((int) (x + halfSize)); + const int iymin = block((int) (y - halfSize)); + const int iymax = block((int) (y + halfSize)); + const float rmin = halfSize - 0.7071F; /* 0.7071 = sqrt(2)/2 */ + const float rmax = halfSize + 0.7071F; + const float rmin2 = MAX2(0.0F, rmin * rmin); + const float rmax2 = rmax * rmax; + const float cscale = 1.0F / (rmax2 - rmin2); + int ix, iy; + + for (iy = iymin; iy <= iymax; iy += 2) { + for (ix = ixmin; ix <= ixmax; ix += 2) { + float dx, dy, dist2, cover; + + setup->quad[0].inout.mask = 0x0; + + dx = (ix + 0.5f) - x; + dy = (iy + 0.5f) - y; + dist2 = dx * dx + dy * dy; + if (dist2 <= rmax2) { + cover = 1.0F - (dist2 - rmin2) * cscale; + setup->quad[0].input.coverage[QUAD_TOP_LEFT] = MIN2(cover, 1.0f); + setup->quad[0].inout.mask |= MASK_TOP_LEFT; + } + + dx = (ix + 1.5f) - x; + dy = (iy + 0.5f) - y; + dist2 = dx * dx + dy * dy; + if (dist2 <= rmax2) { + cover = 1.0F - (dist2 - rmin2) * cscale; + setup->quad[0].input.coverage[QUAD_TOP_RIGHT] = MIN2(cover, 1.0f); + setup->quad[0].inout.mask |= MASK_TOP_RIGHT; + } + + dx = (ix + 0.5f) - x; + dy = (iy + 1.5f) - y; + dist2 = dx * dx + dy * dy; + if (dist2 <= rmax2) { + cover = 1.0F - (dist2 - rmin2) * cscale; + setup->quad[0].input.coverage[QUAD_BOTTOM_LEFT] = MIN2(cover, 1.0f); + setup->quad[0].inout.mask |= MASK_BOTTOM_LEFT; + } + + dx = (ix + 1.5f) - x; + dy = (iy + 1.5f) - y; + dist2 = dx * dx + dy * dy; + if (dist2 <= rmax2) { + cover = 1.0F - (dist2 - rmin2) * cscale; + setup->quad[0].input.coverage[QUAD_BOTTOM_RIGHT] = MIN2(cover, 1.0f); + setup->quad[0].inout.mask |= MASK_BOTTOM_RIGHT; + } + + if (setup->quad[0].inout.mask) { + setup->quad[0].input.x0 = ix; + setup->quad[0].input.y0 = iy; + clip_emit_quad( setup, &setup->quad[0] ); + } + } + } + } + else { + /* square points */ + const int xmin = (int) (x + 0.75 - halfSize); + const int ymin = (int) (y + 0.25 - halfSize); + const int xmax = xmin + (int) size; + const int ymax = ymin + (int) size; + /* XXX could apply scissor to xmin,ymin,xmax,ymax now */ + const int ixmin = block(xmin); + const int ixmax = block(xmax - 1); + const int iymin = block(ymin); + const int iymax = block(ymax - 1); + int ix, iy; + + /* + debug_printf("(%f, %f) -> X:%d..%d Y:%d..%d\n", x, y, xmin, xmax,ymin,ymax); + */ + for (iy = iymin; iy <= iymax; iy += 2) { + uint rowMask = 0xf; + if (iy < ymin) { + /* above the top edge */ + rowMask &= (MASK_BOTTOM_LEFT | MASK_BOTTOM_RIGHT); + } + if (iy + 1 >= ymax) { + /* below the bottom edge */ + rowMask &= (MASK_TOP_LEFT | MASK_TOP_RIGHT); + } + + for (ix = ixmin; ix <= ixmax; ix += 2) { + uint mask = rowMask; + + if (ix < xmin) { + /* fragment is past left edge of point, turn off left bits */ + mask &= (MASK_BOTTOM_RIGHT | MASK_TOP_RIGHT); + } + if (ix + 1 >= xmax) { + /* past the right edge */ + mask &= (MASK_BOTTOM_LEFT | MASK_TOP_LEFT); + } + + setup->quad[0].inout.mask = mask; + setup->quad[0].input.x0 = ix; + setup->quad[0].input.y0 = iy; + clip_emit_quad( setup, &setup->quad[0] ); + } + } + } + } +} + + +/** + * Called by vbuf code just before we start buffering primitives. + */ +void +sp_setup_prepare(struct setup_context *setup) +{ + struct softpipe_context *sp = setup->softpipe; + + if (sp->dirty) { + softpipe_update_derived(sp); + } + + /* Note: nr_attrs is only used for debugging (vertex printing) */ + setup->nr_vertex_attrs = draw_num_shader_outputs(sp->draw); + + sp->quad.first->begin( sp->quad.first ); + + if (sp->reduced_api_prim == PIPE_PRIM_TRIANGLES && + sp->rasterizer->fill_front == PIPE_POLYGON_MODE_FILL && + sp->rasterizer->fill_back == PIPE_POLYGON_MODE_FILL) { + /* we'll do culling */ + setup->cull_face = sp->rasterizer->cull_face; + } + else { + /* 'draw' will do culling */ + setup->cull_face = PIPE_FACE_NONE; + } +} + + +void +sp_setup_destroy_context(struct setup_context *setup) +{ + FREE( setup ); +} + + +/** + * Create a new primitive setup/render stage. + */ +struct setup_context * +sp_setup_create_context(struct softpipe_context *softpipe) +{ + struct setup_context *setup = CALLOC_STRUCT(setup_context); + unsigned i; + + setup->softpipe = softpipe; + + for (i = 0; i < MAX_QUADS; i++) { + setup->quad[i].coef = setup->coef; + setup->quad[i].posCoef = &setup->posCoef; + } + + setup->span.left[0] = 1000000; /* greater than right[0] */ + setup->span.left[1] = 1000000; /* greater than right[1] */ + + return setup; +} diff --git a/src/gallium/drivers/softpipe/sp_setup.h b/src/gallium/drivers/softpipe/sp_setup.h new file mode 100644 index 0000000000..9c8844d2e8 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_setup.h @@ -0,0 +1,53 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ +#ifndef SP_SETUP_H +#define SP_SETUP_H + +struct setup_context; +struct softpipe_context; + +void +sp_setup_tri( struct setup_context *setup, + const float (*v0)[4], + const float (*v1)[4], + const float (*v2)[4] ); + +void +sp_setup_line(struct setup_context *setup, + const float (*v0)[4], + const float (*v1)[4]); + +void +sp_setup_point( struct setup_context *setup, + const float (*v0)[4] ); + + +struct setup_context *sp_setup_create_context( struct softpipe_context *softpipe ); +void sp_setup_prepare( struct setup_context *setup ); +void sp_setup_destroy_context( struct setup_context *setup ); + +#endif diff --git a/src/gallium/drivers/softpipe/sp_state.h b/src/gallium/drivers/softpipe/sp_state.h new file mode 100644 index 0000000000..7d6b86dce0 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_state.h @@ -0,0 +1,300 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* Authors: Keith Whitwell <keith@tungstengraphics.com> + */ + +#ifndef SP_STATE_H +#define SP_STATE_H + +#include "pipe/p_state.h" +#include "tgsi/tgsi_scan.h" + + +#define SP_NEW_VIEWPORT 0x1 +#define SP_NEW_RASTERIZER 0x2 +#define SP_NEW_FS 0x4 +#define SP_NEW_BLEND 0x8 +#define SP_NEW_CLIP 0x10 +#define SP_NEW_SCISSOR 0x20 +#define SP_NEW_STIPPLE 0x40 +#define SP_NEW_FRAMEBUFFER 0x80 +#define SP_NEW_DEPTH_STENCIL_ALPHA 0x100 +#define SP_NEW_CONSTANTS 0x200 +#define SP_NEW_SAMPLER 0x400 +#define SP_NEW_TEXTURE 0x800 +#define SP_NEW_VERTEX 0x1000 +#define SP_NEW_VS 0x2000 +#define SP_NEW_QUERY 0x4000 +#define SP_NEW_GS 0x8000 +#define SP_NEW_SO 0x10000 +#define SP_NEW_SO_BUFFERS 0x20000 + + +struct tgsi_sampler; +struct tgsi_exec_machine; +struct vertex_info; + + +/** + * Subclass of pipe_shader_state (though it doesn't really need to be). + * + * This is starting to look an awful lot like a quad pipeline stage... + */ +struct sp_fragment_shader { + struct pipe_shader_state shader; + + struct tgsi_shader_info info; + + boolean origin_lower_left; /**< fragment shader uses lower left position origin? */ + boolean pixel_center_integer; /**< fragment shader uses integer pixel center? */ + + void (*prepare)( const struct sp_fragment_shader *shader, + struct tgsi_exec_machine *machine, + struct tgsi_sampler **samplers); + + /* Run the shader - this interface will get cleaned up in the + * future: + */ + unsigned (*run)( const struct sp_fragment_shader *shader, + struct tgsi_exec_machine *machine, + struct quad_header *quad ); + + + void (*delete)( struct sp_fragment_shader * ); +}; + + +/** Subclass of pipe_shader_state */ +struct sp_vertex_shader { + struct pipe_shader_state shader; + struct draw_vertex_shader *draw_data; + int max_sampler; /* -1 if no samplers */ +}; + +/** Subclass of pipe_shader_state */ +struct sp_geometry_shader { + struct pipe_shader_state shader; + struct draw_geometry_shader *draw_data; + int max_sampler; +}; + +struct sp_velems_state { + unsigned count; + struct pipe_vertex_element velem[PIPE_MAX_ATTRIBS]; +}; + +struct sp_so_state { + struct pipe_stream_output_state base; +}; + + +void * +softpipe_create_blend_state(struct pipe_context *, + const struct pipe_blend_state *); +void softpipe_bind_blend_state(struct pipe_context *, + void *); +void softpipe_delete_blend_state(struct pipe_context *, + void *); + +void * +softpipe_create_sampler_state(struct pipe_context *, + const struct pipe_sampler_state *); +void softpipe_bind_sampler_states(struct pipe_context *, unsigned, void **); +void +softpipe_bind_vertex_sampler_states(struct pipe_context *, + unsigned num_samplers, + void **samplers); +void +softpipe_bind_geometry_sampler_states(struct pipe_context *, + unsigned num_samplers, + void **samplers); +void softpipe_delete_sampler_state(struct pipe_context *, void *); + +void * +softpipe_create_depth_stencil_state(struct pipe_context *, + const struct pipe_depth_stencil_alpha_state *); +void softpipe_bind_depth_stencil_state(struct pipe_context *, void *); +void softpipe_delete_depth_stencil_state(struct pipe_context *, void *); + +void * +softpipe_create_rasterizer_state(struct pipe_context *, + const struct pipe_rasterizer_state *); +void softpipe_bind_rasterizer_state(struct pipe_context *, void *); +void softpipe_delete_rasterizer_state(struct pipe_context *, void *); + +void softpipe_set_framebuffer_state( struct pipe_context *, + const struct pipe_framebuffer_state * ); + +void softpipe_set_blend_color( struct pipe_context *pipe, + const struct pipe_blend_color *blend_color ); + +void softpipe_set_stencil_ref( struct pipe_context *pipe, + const struct pipe_stencil_ref *stencil_ref ); + +void softpipe_set_clip_state( struct pipe_context *, + const struct pipe_clip_state * ); + +void softpipe_set_sample_mask( struct pipe_context *, + unsigned sample_mask ); + +void softpipe_set_constant_buffer(struct pipe_context *, + uint shader, uint index, + struct pipe_resource *buf); + +void *softpipe_create_fs_state(struct pipe_context *, + const struct pipe_shader_state *); +void softpipe_bind_fs_state(struct pipe_context *, void *); +void softpipe_delete_fs_state(struct pipe_context *, void *); +void *softpipe_create_vs_state(struct pipe_context *, + const struct pipe_shader_state *); +void softpipe_bind_vs_state(struct pipe_context *, void *); +void softpipe_delete_vs_state(struct pipe_context *, void *); +void *softpipe_create_gs_state(struct pipe_context *, + const struct pipe_shader_state *); +void softpipe_bind_gs_state(struct pipe_context *, void *); +void softpipe_delete_gs_state(struct pipe_context *, void *); + +void *softpipe_create_vertex_elements_state(struct pipe_context *, + unsigned count, + const struct pipe_vertex_element *); +void softpipe_bind_vertex_elements_state(struct pipe_context *, void *); +void softpipe_delete_vertex_elements_state(struct pipe_context *, void *); + +void softpipe_set_polygon_stipple( struct pipe_context *, + const struct pipe_poly_stipple * ); + +void softpipe_set_scissor_state( struct pipe_context *, + const struct pipe_scissor_state * ); + +void softpipe_set_sampler_views( struct pipe_context *, + unsigned num, + struct pipe_sampler_view ** ); + +void +softpipe_set_vertex_sampler_views(struct pipe_context *, + unsigned num, + struct pipe_sampler_view **); + +void +softpipe_set_geometry_sampler_views(struct pipe_context *, + unsigned num, + struct pipe_sampler_view **); + +struct pipe_sampler_view * +softpipe_create_sampler_view(struct pipe_context *pipe, + struct pipe_resource *texture, + const struct pipe_sampler_view *templ); + +void +softpipe_sampler_view_destroy(struct pipe_context *pipe, + struct pipe_sampler_view *view); + +void softpipe_set_viewport_state( struct pipe_context *, + const struct pipe_viewport_state * ); + +void softpipe_set_vertex_buffers(struct pipe_context *, + unsigned count, + const struct pipe_vertex_buffer *); + + +void softpipe_update_derived( struct softpipe_context *softpipe ); + + +void softpipe_draw_arrays(struct pipe_context *pipe, unsigned mode, + unsigned start, unsigned count); + +void softpipe_draw_elements(struct pipe_context *pipe, + struct pipe_resource *indexBuffer, + unsigned indexSize, int indexBias, + unsigned mode, unsigned start, unsigned count); +void +softpipe_draw_range_elements(struct pipe_context *pipe, + struct pipe_resource *indexBuffer, + unsigned indexSize, + int indexBias, + unsigned min_index, + unsigned max_index, + unsigned mode, unsigned start, unsigned count); + +void +softpipe_draw_arrays_instanced(struct pipe_context *pipe, + unsigned mode, + unsigned start, + unsigned count, + unsigned startInstance, + unsigned instanceCount); + +void +softpipe_draw_elements_instanced(struct pipe_context *pipe, + struct pipe_resource *indexBuffer, + unsigned indexSize, + int indexBias, + unsigned mode, + unsigned start, + unsigned count, + unsigned startInstance, + unsigned instanceCount); + +void softpipe_draw_stream_output(struct pipe_context *pipe, unsigned mode); + +void +softpipe_map_transfers(struct softpipe_context *sp); + +void +softpipe_unmap_transfers(struct softpipe_context *sp); + +void +softpipe_map_texture_surfaces(struct softpipe_context *sp); + +void +softpipe_unmap_texture_surfaces(struct softpipe_context *sp); + + +struct vertex_info * +softpipe_get_vertex_info(struct softpipe_context *softpipe); + +struct vertex_info * +softpipe_get_vbuf_vertex_info(struct softpipe_context *softpipe); + +void * +softpipe_create_stream_output_state( + struct pipe_context *pipe, + const struct pipe_stream_output_state *templ); +void +softpipe_bind_stream_output_state(struct pipe_context *pipe, + void *so); +void +softpipe_delete_stream_output_state(struct pipe_context *pipe, void *so); + +void +softpipe_set_stream_output_buffers(struct pipe_context *pipe, + struct pipe_resource **buffers, + int *offsets, + int num_buffers); + +#endif diff --git a/src/gallium/drivers/softpipe/sp_state_blend.c b/src/gallium/drivers/softpipe/sp_state_blend.c new file mode 100644 index 0000000000..2a203f44e5 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_state_blend.c @@ -0,0 +1,120 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* Authors: Keith Whitwell <keith@tungstengraphics.com> + */ + +#include "util/u_memory.h" +#include "draw/draw_context.h" +#include "sp_context.h" +#include "sp_state.h" + + +void * +softpipe_create_blend_state(struct pipe_context *pipe, + const struct pipe_blend_state *blend) +{ + return mem_dup(blend, sizeof(*blend)); +} + +void softpipe_bind_blend_state( struct pipe_context *pipe, + void *blend ) +{ + struct softpipe_context *softpipe = softpipe_context(pipe); + + draw_flush(softpipe->draw); + + softpipe->blend = (struct pipe_blend_state *)blend; + + softpipe->dirty |= SP_NEW_BLEND; +} + +void softpipe_delete_blend_state(struct pipe_context *pipe, + void *blend) +{ + FREE( blend ); +} + + +void softpipe_set_blend_color( struct pipe_context *pipe, + const struct pipe_blend_color *blend_color ) +{ + struct softpipe_context *softpipe = softpipe_context(pipe); + + draw_flush(softpipe->draw); + + softpipe->blend_color = *blend_color; + + softpipe->dirty |= SP_NEW_BLEND; +} + + +/** XXX move someday? Or consolidate all these simple state setters + * into one file. + */ + + +void * +softpipe_create_depth_stencil_state(struct pipe_context *pipe, + const struct pipe_depth_stencil_alpha_state *depth_stencil) +{ + return mem_dup(depth_stencil, sizeof(*depth_stencil)); +} + +void +softpipe_bind_depth_stencil_state(struct pipe_context *pipe, + void *depth_stencil) +{ + struct softpipe_context *softpipe = softpipe_context(pipe); + + softpipe->depth_stencil = (struct pipe_depth_stencil_alpha_state *)depth_stencil; + + softpipe->dirty |= SP_NEW_DEPTH_STENCIL_ALPHA; +} + +void +softpipe_delete_depth_stencil_state(struct pipe_context *pipe, void *depth) +{ + FREE( depth ); +} + +void softpipe_set_stencil_ref( struct pipe_context *pipe, + const struct pipe_stencil_ref *stencil_ref ) +{ + struct softpipe_context *softpipe = softpipe_context(pipe); + + softpipe->stencil_ref = *stencil_ref; + + softpipe->dirty |= SP_NEW_DEPTH_STENCIL_ALPHA; +} + +void +softpipe_set_sample_mask(struct pipe_context *pipe, + unsigned sample_mask) +{ +} + diff --git a/src/gallium/drivers/softpipe/sp_state_clip.c b/src/gallium/drivers/softpipe/sp_state_clip.c new file mode 100644 index 0000000000..4946c776e3 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_state_clip.c @@ -0,0 +1,79 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* Authors: Keith Whitwell <keith@tungstengraphics.com> + */ +#include "sp_context.h" +#include "sp_state.h" +#include "draw/draw_context.h" + + +void softpipe_set_clip_state( struct pipe_context *pipe, + const struct pipe_clip_state *clip ) +{ + struct softpipe_context *softpipe = softpipe_context(pipe); + + /* pass the clip state to the draw module */ + draw_set_clip_state(softpipe->draw, clip); +} + + +void softpipe_set_viewport_state( struct pipe_context *pipe, + const struct pipe_viewport_state *viewport ) +{ + struct softpipe_context *softpipe = softpipe_context(pipe); + + /* pass the viewport info to the draw module */ + draw_set_viewport_state(softpipe->draw, viewport); + + softpipe->viewport = *viewport; /* struct copy */ + softpipe->dirty |= SP_NEW_VIEWPORT; +} + + +void softpipe_set_scissor_state( struct pipe_context *pipe, + const struct pipe_scissor_state *scissor ) +{ + struct softpipe_context *softpipe = softpipe_context(pipe); + + draw_flush(softpipe->draw); + + softpipe->scissor = *scissor; /* struct copy */ + softpipe->dirty |= SP_NEW_SCISSOR; +} + + +void softpipe_set_polygon_stipple( struct pipe_context *pipe, + const struct pipe_poly_stipple *stipple ) +{ + struct softpipe_context *softpipe = softpipe_context(pipe); + + draw_flush(softpipe->draw); + + softpipe->poly_stipple = *stipple; /* struct copy */ + softpipe->dirty |= SP_NEW_STIPPLE; +} diff --git a/src/gallium/drivers/softpipe/sp_state_derived.c b/src/gallium/drivers/softpipe/sp_state_derived.c new file mode 100644 index 0000000000..3ba4d934fd --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_state_derived.c @@ -0,0 +1,281 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "util/u_math.h" +#include "util/u_memory.h" +#include "pipe/p_shader_tokens.h" +#include "draw/draw_context.h" +#include "draw/draw_vertex.h" +#include "sp_context.h" +#include "sp_screen.h" +#include "sp_state.h" +#include "sp_texture.h" +#include "sp_tex_tile_cache.h" + + +/** + * Mark the current vertex layout as "invalid". + * We'll validate the vertex layout later, when we start to actually + * render a point or line or tri. + */ +static void +invalidate_vertex_layout(struct softpipe_context *softpipe) +{ + softpipe->vertex_info.num_attribs = 0; +} + + +/** + * The vertex info describes how to convert the post-transformed vertices + * (simple float[][4]) used by the 'draw' module into vertices for + * rasterization. + * + * This function validates the vertex layout and returns a pointer to a + * vertex_info object. + */ +struct vertex_info * +softpipe_get_vertex_info(struct softpipe_context *softpipe) +{ + struct vertex_info *vinfo = &softpipe->vertex_info; + + if (vinfo->num_attribs == 0) { + /* compute vertex layout now */ + const struct sp_fragment_shader *spfs = softpipe->fs; + struct vertex_info *vinfo_vbuf = &softpipe->vertex_info_vbuf; + const uint num = draw_num_shader_outputs(softpipe->draw); + uint i; + + /* Tell draw_vbuf to simply emit the whole post-xform vertex + * as-is. No longer any need to try and emit draw vertex_header + * info. + */ + vinfo_vbuf->num_attribs = 0; + for (i = 0; i < num; i++) { + draw_emit_vertex_attr(vinfo_vbuf, EMIT_4F, INTERP_PERSPECTIVE, i); + } + draw_compute_vertex_size(vinfo_vbuf); + + /* + * Loop over fragment shader inputs, searching for the matching output + * from the vertex shader. + */ + vinfo->num_attribs = 0; + for (i = 0; i < spfs->info.num_inputs; i++) { + int src; + enum interp_mode interp; + + switch (spfs->info.input_interpolate[i]) { + case TGSI_INTERPOLATE_CONSTANT: + interp = INTERP_CONSTANT; + break; + case TGSI_INTERPOLATE_LINEAR: + interp = INTERP_LINEAR; + break; + case TGSI_INTERPOLATE_PERSPECTIVE: + interp = INTERP_PERSPECTIVE; + break; + default: + assert(0); + interp = INTERP_LINEAR; + } + + switch (spfs->info.input_semantic_name[i]) { + case TGSI_SEMANTIC_POSITION: + interp = INTERP_POS; + break; + + case TGSI_SEMANTIC_COLOR: + if (softpipe->rasterizer->flatshade) { + interp = INTERP_CONSTANT; + } + break; + } + + /* this includes texcoords and varying vars */ + src = draw_find_shader_output(softpipe->draw, + spfs->info.input_semantic_name[i], + spfs->info.input_semantic_index[i]); + draw_emit_vertex_attr(vinfo, EMIT_4F, interp, src); + } + + softpipe->psize_slot = draw_find_shader_output(softpipe->draw, + TGSI_SEMANTIC_PSIZE, 0); + if (softpipe->psize_slot > 0) { + draw_emit_vertex_attr(vinfo, EMIT_4F, INTERP_CONSTANT, + softpipe->psize_slot); + } + + draw_compute_vertex_size(vinfo); + } + + return vinfo; +} + + +/** + * Called from vbuf module. + * + * Note that there's actually two different vertex layouts in softpipe. + * + * The normal one is computed in softpipe_get_vertex_info() above and is + * used by the point/line/tri "setup" code. + * + * The other one (this one) is only used by the vbuf module (which is + * not normally used by default but used in testing). For the vbuf module, + * we basically want to pass-through the draw module's vertex layout as-is. + * When the softpipe vbuf code begins drawing, the normal vertex layout + * will come into play again. + */ +struct vertex_info * +softpipe_get_vbuf_vertex_info(struct softpipe_context *softpipe) +{ + (void) softpipe_get_vertex_info(softpipe); + return &softpipe->vertex_info_vbuf; +} + + +/** + * Recompute cliprect from scissor bounds, scissor enable and surface size. + */ +static void +compute_cliprect(struct softpipe_context *sp) +{ + /* SP_NEW_FRAMEBUFFER + */ + uint surfWidth = sp->framebuffer.width; + uint surfHeight = sp->framebuffer.height; + + /* SP_NEW_RASTERIZER + */ + if (sp->rasterizer->scissor) { + + /* SP_NEW_SCISSOR + * + * clip to scissor rect: + */ + sp->cliprect.minx = MAX2(sp->scissor.minx, 0); + sp->cliprect.miny = MAX2(sp->scissor.miny, 0); + sp->cliprect.maxx = MIN2(sp->scissor.maxx, surfWidth); + sp->cliprect.maxy = MIN2(sp->scissor.maxy, surfHeight); + } + else { + /* clip to surface bounds */ + sp->cliprect.minx = 0; + sp->cliprect.miny = 0; + sp->cliprect.maxx = surfWidth; + sp->cliprect.maxy = surfHeight; + } +} + + +static void +update_tgsi_samplers( struct softpipe_context *softpipe ) +{ + unsigned i; + + softpipe_reset_sampler_varients( softpipe ); + + for (i = 0; i < PIPE_MAX_SAMPLERS; i++) { + struct softpipe_tex_tile_cache *tc = softpipe->tex_cache[i]; + if (tc->texture) { + struct softpipe_resource *spt = softpipe_resource(tc->texture); + if (spt->timestamp != tc->timestamp) { + sp_tex_tile_cache_validate_texture( tc ); + /* + _debug_printf("INV %d %d\n", tc->timestamp, spt->timestamp); + */ + tc->timestamp = spt->timestamp; + } + } + } + + for (i = 0; i < PIPE_MAX_VERTEX_SAMPLERS; i++) { + struct softpipe_tex_tile_cache *tc = softpipe->vertex_tex_cache[i]; + + if (tc->texture) { + struct softpipe_resource *spt = softpipe_resource(tc->texture); + + if (spt->timestamp != tc->timestamp) { + sp_tex_tile_cache_validate_texture(tc); + tc->timestamp = spt->timestamp; + } + } + } + + for (i = 0; i < PIPE_MAX_GEOMETRY_SAMPLERS; i++) { + struct softpipe_tex_tile_cache *tc = softpipe->geometry_tex_cache[i]; + + if (tc->texture) { + struct softpipe_resource *spt = softpipe_resource(tc->texture); + + if (spt->timestamp != tc->timestamp) { + sp_tex_tile_cache_validate_texture(tc); + tc->timestamp = spt->timestamp; + } + } + } +} + + +/* Hopefully this will remain quite simple, otherwise need to pull in + * something like the state tracker mechanism. + */ +void softpipe_update_derived( struct softpipe_context *softpipe ) +{ + struct softpipe_screen *sp_screen = softpipe_screen(softpipe->pipe.screen); + + /* Check for updated textures. + */ + if (softpipe->tex_timestamp != sp_screen->timestamp) { + softpipe->tex_timestamp = sp_screen->timestamp; + softpipe->dirty |= SP_NEW_TEXTURE; + } + + if (softpipe->dirty & (SP_NEW_SAMPLER | + SP_NEW_TEXTURE | + SP_NEW_FS | + SP_NEW_VS)) + update_tgsi_samplers( softpipe ); + + if (softpipe->dirty & (SP_NEW_RASTERIZER | + SP_NEW_FS | + SP_NEW_VS)) + invalidate_vertex_layout( softpipe ); + + if (softpipe->dirty & (SP_NEW_SCISSOR | + SP_NEW_RASTERIZER | + SP_NEW_FRAMEBUFFER)) + compute_cliprect(softpipe); + + if (softpipe->dirty & (SP_NEW_BLEND | + SP_NEW_DEPTH_STENCIL_ALPHA | + SP_NEW_FRAMEBUFFER | + SP_NEW_FS)) + sp_build_quad_pipeline(softpipe); + + softpipe->dirty = 0; +} diff --git a/src/gallium/drivers/softpipe/sp_state_fs.c b/src/gallium/drivers/softpipe/sp_state_fs.c new file mode 100644 index 0000000000..3fbf1f2578 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_state_fs.c @@ -0,0 +1,266 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "sp_context.h" +#include "sp_state.h" +#include "sp_fs.h" +#include "sp_texture.h" + +#include "pipe/p_defines.h" +#include "util/u_memory.h" +#include "util/u_inlines.h" +#include "draw/draw_context.h" +#include "draw/draw_vs.h" +#include "draw/draw_gs.h" +#include "tgsi/tgsi_dump.h" +#include "tgsi/tgsi_exec.h" +#include "tgsi/tgsi_scan.h" +#include "tgsi/tgsi_parse.h" + + +void * +softpipe_create_fs_state(struct pipe_context *pipe, + const struct pipe_shader_state *templ) +{ + struct softpipe_context *softpipe = softpipe_context(pipe); + struct sp_fragment_shader *state; + unsigned i; + + /* debug */ + if (softpipe->dump_fs) + tgsi_dump(templ->tokens, 0); + + /* codegen */ + state = softpipe_create_fs_sse( softpipe, templ ); + if (!state) { + state = softpipe_create_fs_exec( softpipe, templ ); + } + + assert(state); + + /* get/save the summary info for this shader */ + tgsi_scan_shader(templ->tokens, &state->info); + + for (i = 0; i < state->info.num_properties; ++i) { + if (state->info.properties[i].name == TGSI_PROPERTY_FS_COORD_ORIGIN) + state->origin_lower_left = state->info.properties[i].data[0]; + else if (state->info.properties[i].name == TGSI_PROPERTY_FS_COORD_PIXEL_CENTER) + state->pixel_center_integer = state->info.properties[i].data[0]; + } + + return state; +} + + +void +softpipe_bind_fs_state(struct pipe_context *pipe, void *fs) +{ + struct softpipe_context *softpipe = softpipe_context(pipe); + + draw_flush(softpipe->draw); + + if (softpipe->fs == fs) + return; + + draw_flush(softpipe->draw); + + softpipe->fs = fs; + + softpipe->dirty |= SP_NEW_FS; +} + + +void +softpipe_delete_fs_state(struct pipe_context *pipe, void *fs) +{ + struct softpipe_context *softpipe = softpipe_context(pipe); + struct sp_fragment_shader *state = fs; + + assert(fs != softpipe_context(pipe)->fs); + + if (softpipe->fs_machine->Tokens == state->shader.tokens) { + /* unbind the shader from the tgsi executor if we're + * deleting it. + */ + tgsi_exec_machine_bind_shader(softpipe->fs_machine, NULL, 0, NULL); + } + + state->delete( state ); +} + + +void * +softpipe_create_vs_state(struct pipe_context *pipe, + const struct pipe_shader_state *templ) +{ + struct softpipe_context *softpipe = softpipe_context(pipe); + struct sp_vertex_shader *state; + + state = CALLOC_STRUCT(sp_vertex_shader); + if (state == NULL ) + goto fail; + + /* copy shader tokens, the ones passed in will go away. + */ + state->shader.tokens = tgsi_dup_tokens(templ->tokens); + if (state->shader.tokens == NULL) + goto fail; + + state->draw_data = draw_create_vertex_shader(softpipe->draw, templ); + if (state->draw_data == NULL) + goto fail; + + state->max_sampler = state->draw_data->info.file_max[TGSI_FILE_SAMPLER]; + + return state; + +fail: + if (state) { + FREE( (void *)state->shader.tokens ); + FREE( state->draw_data ); + FREE( state ); + } + return NULL; +} + + +void +softpipe_bind_vs_state(struct pipe_context *pipe, void *vs) +{ + struct softpipe_context *softpipe = softpipe_context(pipe); + + softpipe->vs = (struct sp_vertex_shader *) vs; + + draw_bind_vertex_shader(softpipe->draw, + (softpipe->vs ? softpipe->vs->draw_data : NULL)); + + softpipe->dirty |= SP_NEW_VS; +} + + +void +softpipe_delete_vs_state(struct pipe_context *pipe, void *vs) +{ + struct softpipe_context *softpipe = softpipe_context(pipe); + + struct sp_vertex_shader *state = (struct sp_vertex_shader *) vs; + + draw_delete_vertex_shader(softpipe->draw, state->draw_data); + FREE( (void *)state->shader.tokens ); + FREE( state ); +} + +void +softpipe_set_constant_buffer(struct pipe_context *pipe, + uint shader, uint index, + struct pipe_resource *constants) +{ + struct softpipe_context *softpipe = softpipe_context(pipe); + unsigned size = constants ? constants->width0 : 0; + const void *data = constants ? softpipe_resource(constants)->data : NULL; + + assert(shader < PIPE_SHADER_TYPES); + + draw_flush(softpipe->draw); + + /* note: reference counting */ + pipe_resource_reference(&softpipe->constants[shader][index], constants); + + if (shader == PIPE_SHADER_VERTEX || shader == PIPE_SHADER_GEOMETRY) { + draw_set_mapped_constant_buffer(softpipe->draw, shader, index, data, size); + } + + softpipe->mapped_constants[shader][index] = data; + softpipe->dirty |= SP_NEW_CONSTANTS; +} + + +void * +softpipe_create_gs_state(struct pipe_context *pipe, + const struct pipe_shader_state *templ) +{ + struct softpipe_context *softpipe = softpipe_context(pipe); + struct sp_geometry_shader *state; + + state = CALLOC_STRUCT(sp_geometry_shader); + if (state == NULL ) + goto fail; + + /* debug */ + if (softpipe->dump_gs) + tgsi_dump(templ->tokens, 0); + + /* copy shader tokens, the ones passed in will go away. + */ + state->shader.tokens = tgsi_dup_tokens(templ->tokens); + if (state->shader.tokens == NULL) + goto fail; + + state->draw_data = draw_create_geometry_shader(softpipe->draw, templ); + if (state->draw_data == NULL) + goto fail; + + state->max_sampler = state->draw_data->info.file_max[TGSI_FILE_SAMPLER]; + + return state; + +fail: + if (state) { + FREE( (void *)state->shader.tokens ); + FREE( state->draw_data ); + FREE( state ); + } + return NULL; +} + + +void +softpipe_bind_gs_state(struct pipe_context *pipe, void *gs) +{ + struct softpipe_context *softpipe = softpipe_context(pipe); + + softpipe->gs = (struct sp_geometry_shader *)gs; + + draw_bind_geometry_shader(softpipe->draw, + (softpipe->gs ? softpipe->gs->draw_data : NULL)); + + softpipe->dirty |= SP_NEW_GS; +} + + +void +softpipe_delete_gs_state(struct pipe_context *pipe, void *gs) +{ + struct softpipe_context *softpipe = softpipe_context(pipe); + + struct sp_geometry_shader *state = + (struct sp_geometry_shader *)gs; + + draw_delete_geometry_shader(softpipe->draw, + (state) ? state->draw_data : 0); + FREE(state); +} diff --git a/src/gallium/drivers/softpipe/sp_state_rasterizer.c b/src/gallium/drivers/softpipe/sp_state_rasterizer.c new file mode 100644 index 0000000000..c9ede09f26 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_state_rasterizer.c @@ -0,0 +1,65 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "pipe/p_defines.h" +#include "util/u_memory.h" +#include "sp_context.h" +#include "sp_state.h" +#include "draw/draw_context.h" + + + +void * +softpipe_create_rasterizer_state(struct pipe_context *pipe, + const struct pipe_rasterizer_state *rast) +{ + return mem_dup(rast, sizeof(*rast)); +} + +void softpipe_bind_rasterizer_state(struct pipe_context *pipe, + void *rasterizer) +{ + struct softpipe_context *softpipe = softpipe_context(pipe); + + if (softpipe->rasterizer == rasterizer) + return; + + /* pass-through to draw module */ + draw_set_rasterizer_state(softpipe->draw, rasterizer, rasterizer); + + softpipe->rasterizer = rasterizer; + + softpipe->dirty |= SP_NEW_RASTERIZER; +} + +void softpipe_delete_rasterizer_state(struct pipe_context *pipe, + void *rasterizer) +{ + FREE( rasterizer ); +} + + diff --git a/src/gallium/drivers/softpipe/sp_state_sampler.c b/src/gallium/drivers/softpipe/sp_state_sampler.c new file mode 100644 index 0000000000..79d9516ad9 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_state_sampler.c @@ -0,0 +1,416 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* Authors: + * Brian Paul + */ + +#include "util/u_memory.h" +#include "util/u_inlines.h" + +#include "draw/draw_context.h" +#include "draw/draw_context.h" + +#include "sp_context.h" +#include "sp_state.h" +#include "sp_texture.h" +#include "sp_tex_sample.h" +#include "sp_tex_tile_cache.h" + + +struct sp_sampler { + struct pipe_sampler_state base; + struct sp_sampler_varient *varients; + struct sp_sampler_varient *current; +}; + +static struct sp_sampler *sp_sampler( struct pipe_sampler_state *sampler ) +{ + return (struct sp_sampler *)sampler; +} + + +void * +softpipe_create_sampler_state(struct pipe_context *pipe, + const struct pipe_sampler_state *sampler) +{ + struct sp_sampler *sp_sampler = CALLOC_STRUCT(sp_sampler); + + sp_sampler->base = *sampler; + sp_sampler->varients = NULL; + + return (void *)sp_sampler; +} + + +void +softpipe_bind_sampler_states(struct pipe_context *pipe, + unsigned num, void **sampler) +{ + struct softpipe_context *softpipe = softpipe_context(pipe); + unsigned i; + + assert(num <= PIPE_MAX_SAMPLERS); + + /* Check for no-op */ + if (num == softpipe->num_samplers && + !memcmp(softpipe->sampler, sampler, num * sizeof(void *))) + return; + + draw_flush(softpipe->draw); + + for (i = 0; i < num; ++i) + softpipe->sampler[i] = sampler[i]; + for (i = num; i < PIPE_MAX_SAMPLERS; ++i) + softpipe->sampler[i] = NULL; + + softpipe->num_samplers = num; + + softpipe->dirty |= SP_NEW_SAMPLER; +} + + +void +softpipe_bind_vertex_sampler_states(struct pipe_context *pipe, + unsigned num_samplers, + void **samplers) +{ + struct softpipe_context *softpipe = softpipe_context(pipe); + unsigned i; + + assert(num_samplers <= PIPE_MAX_VERTEX_SAMPLERS); + + /* Check for no-op */ + if (num_samplers == softpipe->num_vertex_samplers && + !memcmp(softpipe->vertex_samplers, samplers, num_samplers * sizeof(void *))) + return; + + draw_flush(softpipe->draw); + + for (i = 0; i < num_samplers; ++i) + softpipe->vertex_samplers[i] = samplers[i]; + for (i = num_samplers; i < PIPE_MAX_VERTEX_SAMPLERS; ++i) + softpipe->vertex_samplers[i] = NULL; + + softpipe->num_vertex_samplers = num_samplers; + + softpipe->dirty |= SP_NEW_SAMPLER; +} + +void +softpipe_bind_geometry_sampler_states(struct pipe_context *pipe, + unsigned num_samplers, + void **samplers) +{ + struct softpipe_context *softpipe = softpipe_context(pipe); + unsigned i; + + assert(num_samplers <= PIPE_MAX_GEOMETRY_SAMPLERS); + + /* Check for no-op */ + if (num_samplers == softpipe->num_geometry_samplers && + !memcmp(softpipe->geometry_samplers, samplers, num_samplers * sizeof(void *))) + return; + + draw_flush(softpipe->draw); + + for (i = 0; i < num_samplers; ++i) + softpipe->geometry_samplers[i] = samplers[i]; + for (i = num_samplers; i < PIPE_MAX_GEOMETRY_SAMPLERS; ++i) + softpipe->geometry_samplers[i] = NULL; + + softpipe->num_geometry_samplers = num_samplers; + + softpipe->dirty |= SP_NEW_SAMPLER; +} + + +struct pipe_sampler_view * +softpipe_create_sampler_view(struct pipe_context *pipe, + struct pipe_resource *resource, + const struct pipe_sampler_view *templ) +{ + struct pipe_sampler_view *view = CALLOC_STRUCT(pipe_sampler_view); + + if (view) { + *view = *templ; + view->reference.count = 1; + view->texture = NULL; + pipe_resource_reference(&view->texture, resource); + view->context = pipe; + } + + return view; +} + + +void +softpipe_sampler_view_destroy(struct pipe_context *pipe, + struct pipe_sampler_view *view) +{ + pipe_resource_reference(&view->texture, NULL); + FREE(view); +} + + +void +softpipe_set_sampler_views(struct pipe_context *pipe, + unsigned num, + struct pipe_sampler_view **views) +{ + struct softpipe_context *softpipe = softpipe_context(pipe); + uint i; + + assert(num <= PIPE_MAX_SAMPLERS); + + /* Check for no-op */ + if (num == softpipe->num_sampler_views && + !memcmp(softpipe->sampler_views, views, num * sizeof(struct pipe_sampler_view *))) + return; + + draw_flush(softpipe->draw); + + for (i = 0; i < PIPE_MAX_SAMPLERS; i++) { + struct pipe_sampler_view *view = i < num ? views[i] : NULL; + + pipe_sampler_view_reference(&softpipe->sampler_views[i], view); + sp_tex_tile_cache_set_sampler_view(softpipe->tex_cache[i], view); + } + + softpipe->num_sampler_views = num; + + softpipe->dirty |= SP_NEW_TEXTURE; +} + + +void +softpipe_set_vertex_sampler_views(struct pipe_context *pipe, + unsigned num, + struct pipe_sampler_view **views) +{ + struct softpipe_context *softpipe = softpipe_context(pipe); + uint i; + + assert(num <= PIPE_MAX_VERTEX_SAMPLERS); + + /* Check for no-op */ + if (num == softpipe->num_vertex_sampler_views && + !memcmp(softpipe->vertex_sampler_views, views, num * sizeof(struct pipe_sampler_view *))) { + return; + } + + draw_flush(softpipe->draw); + + for (i = 0; i < PIPE_MAX_VERTEX_SAMPLERS; i++) { + struct pipe_sampler_view *view = i < num ? views[i] : NULL; + + pipe_sampler_view_reference(&softpipe->vertex_sampler_views[i], view); + sp_tex_tile_cache_set_sampler_view(softpipe->vertex_tex_cache[i], view); + } + + softpipe->num_vertex_sampler_views = num; + + softpipe->dirty |= SP_NEW_TEXTURE; +} + +void +softpipe_set_geometry_sampler_views(struct pipe_context *pipe, + unsigned num, + struct pipe_sampler_view **views) +{ + struct softpipe_context *softpipe = softpipe_context(pipe); + uint i; + + assert(num <= PIPE_MAX_GEOMETRY_SAMPLERS); + + /* Check for no-op */ + if (num == softpipe->num_geometry_sampler_views && + !memcmp(softpipe->geometry_sampler_views, views, num * sizeof(struct pipe_sampler_view *))) { + return; + } + + draw_flush(softpipe->draw); + + for (i = 0; i < PIPE_MAX_GEOMETRY_SAMPLERS; i++) { + struct pipe_sampler_view *view = i < num ? views[i] : NULL; + + pipe_sampler_view_reference(&softpipe->geometry_sampler_views[i], view); + sp_tex_tile_cache_set_sampler_view(softpipe->geometry_tex_cache[i], view); + } + + softpipe->num_geometry_sampler_views = num; + + softpipe->dirty |= SP_NEW_TEXTURE; +} + + +/** + * Find/create an sp_sampler_varient object for sampling the given texture, + * sampler and tex unit. + * + * Note that the tex unit is significant. We can't re-use a sampler + * varient for multiple texture units because the sampler varient contains + * the texture object pointer. If the texture object pointer were stored + * somewhere outside the sampler varient, we could re-use samplers for + * multiple texture units. + */ +static struct sp_sampler_varient * +get_sampler_varient( unsigned unit, + struct sp_sampler *sampler, + struct pipe_resource *resource, + unsigned processor ) +{ + struct softpipe_resource *sp_texture = softpipe_resource(resource); + struct sp_sampler_varient *v = NULL; + union sp_sampler_key key; + + /* if this fails, widen the key.unit field and update this assertion */ + assert(PIPE_MAX_SAMPLERS <= 16); + + key.bits.target = sp_texture->base.target; + key.bits.is_pot = sp_texture->pot; + key.bits.processor = processor; + key.bits.unit = unit; + key.bits.pad = 0; + + if (sampler->current && + key.value == sampler->current->key.value) { + v = sampler->current; + } + + if (v == NULL) { + for (v = sampler->varients; v; v = v->next) + if (v->key.value == key.value) + break; + + if (v == NULL) { + v = sp_create_sampler_varient( &sampler->base, key ); + v->next = sampler->varients; + sampler->varients = v; + } + } + + sampler->current = v; + return v; +} + + + + +void +softpipe_reset_sampler_varients(struct softpipe_context *softpipe) +{ + int i; + + /* It's a bit hard to build these samplers ahead of time -- don't + * really know which samplers are going to be used for vertex and + * fragment programs. + */ + for (i = 0; i <= softpipe->vs->max_sampler; i++) { + if (softpipe->vertex_samplers[i]) { + struct pipe_resource *texture = NULL; + + if (softpipe->vertex_sampler_views[i]) { + texture = softpipe->vertex_sampler_views[i]->texture; + } + + softpipe->tgsi.vert_samplers_list[i] = + get_sampler_varient( i, + sp_sampler(softpipe->vertex_samplers[i]), + texture, + TGSI_PROCESSOR_VERTEX ); + + sp_sampler_varient_bind_texture( softpipe->tgsi.vert_samplers_list[i], + softpipe->vertex_tex_cache[i], + texture ); + } + } + + if (softpipe->gs) { + for (i = 0; i <= softpipe->gs->max_sampler; i++) { + if (softpipe->geometry_samplers[i]) { + struct pipe_resource *texture = NULL; + + if (softpipe->geometry_sampler_views[i]) { + texture = softpipe->geometry_sampler_views[i]->texture; + } + + softpipe->tgsi.geom_samplers_list[i] = + get_sampler_varient( + i, + sp_sampler(softpipe->geometry_samplers[i]), + texture, + TGSI_PROCESSOR_GEOMETRY ); + + sp_sampler_varient_bind_texture( + softpipe->tgsi.geom_samplers_list[i], + softpipe->geometry_tex_cache[i], + texture ); + } + } + } + + for (i = 0; i <= softpipe->fs->info.file_max[TGSI_FILE_SAMPLER]; i++) { + if (softpipe->sampler[i]) { + struct pipe_resource *texture = NULL; + + if (softpipe->sampler_views[i]) { + texture = softpipe->sampler_views[i]->texture; + } + + softpipe->tgsi.frag_samplers_list[i] = + get_sampler_varient( i, + sp_sampler(softpipe->sampler[i]), + texture, + TGSI_PROCESSOR_FRAGMENT ); + + sp_sampler_varient_bind_texture( softpipe->tgsi.frag_samplers_list[i], + softpipe->tex_cache[i], + texture ); + } + } +} + + + +void +softpipe_delete_sampler_state(struct pipe_context *pipe, + void *sampler) +{ + struct sp_sampler *sp_sampler = (struct sp_sampler *)sampler; + struct sp_sampler_varient *v, *tmp; + + for (v = sp_sampler->varients; v; v = tmp) { + tmp = v->next; + sp_sampler_varient_destroy(v); + } + + FREE( sampler ); +} + + + diff --git a/src/gallium/drivers/softpipe/sp_state_so.c b/src/gallium/drivers/softpipe/sp_state_so.c new file mode 100644 index 0000000000..cfe23f9e84 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_state_so.c @@ -0,0 +1,124 @@ +/************************************************************************** + * + * Copyright 2010 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "sp_context.h" +#include "sp_state.h" +#include "sp_texture.h" + +#include "util/u_format.h" +#include "util/u_memory.h" +#include "draw/draw_context.h" + + +void * +softpipe_create_stream_output_state(struct pipe_context *pipe, + const struct pipe_stream_output_state *templ) +{ + struct sp_so_state *so; + so = (struct sp_so_state *) CALLOC_STRUCT(sp_so_state); + + if (so) { + so->base.num_outputs = templ->num_outputs; + so->base.stride = templ->stride; + memcpy(so->base.output_buffer, + templ->output_buffer, + sizeof(int) * templ->num_outputs); + memcpy(so->base.register_index, + templ->register_index, + sizeof(int) * templ->num_outputs); + memcpy(so->base.register_mask, + templ->register_mask, + sizeof(ubyte) * templ->num_outputs); + } + return so; +} + +void +softpipe_bind_stream_output_state(struct pipe_context *pipe, + void *so) +{ + struct softpipe_context *softpipe = softpipe_context(pipe); + struct sp_so_state *sp_so = (struct sp_so_state *) so; + + softpipe->so = sp_so; + + softpipe->dirty |= SP_NEW_SO; + + if (sp_so) + draw_set_so_state(softpipe->draw, &sp_so->base); +} + +void +softpipe_delete_stream_output_state(struct pipe_context *pipe, void *so) +{ + FREE( so ); +} + +void +softpipe_set_stream_output_buffers(struct pipe_context *pipe, + struct pipe_resource **buffers, + int *offsets, + int num_buffers) +{ + struct softpipe_context *softpipe = softpipe_context(pipe); + int i; + void *map_buffers[PIPE_MAX_SO_BUFFERS]; + + assert(num_buffers <= PIPE_MAX_SO_BUFFERS); + if (num_buffers > PIPE_MAX_SO_BUFFERS) + num_buffers = PIPE_MAX_SO_BUFFERS; + + softpipe->dirty |= SP_NEW_SO_BUFFERS; + + for (i = 0; i < num_buffers; ++i) { + void *mapped; + struct softpipe_resource *res = softpipe_resource(buffers[i]); + + if (!res) { + /* the whole call is invalid, bail out */ + softpipe->so_target.num_buffers = 0; + draw_set_mapped_so_buffers(softpipe->draw, 0, 0); + return; + } + + softpipe->so_target.buffer[i] = res; + softpipe->so_target.offset[i] = offsets[i]; + softpipe->so_target.so_count[i] = 0; + + mapped = res->data; + if (offsets[i] >= 0) + map_buffers[i] = ((char*)mapped) + offsets[i]; + else { + /* this is a buffer append */ + assert(!"appending not implemented"); + map_buffers[i] = mapped; + } + } + softpipe->so_target.num_buffers = num_buffers; + + draw_set_mapped_so_buffers(softpipe->draw, map_buffers, num_buffers); +} diff --git a/src/gallium/drivers/softpipe/sp_state_surface.c b/src/gallium/drivers/softpipe/sp_state_surface.c new file mode 100644 index 0000000000..2db6faeca4 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_state_surface.c @@ -0,0 +1,104 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* Authors: Keith Whitwell <keith@tungstengraphics.com> + */ + +#include "sp_context.h" +#include "sp_state.h" +#include "sp_tile_cache.h" + +#include "draw/draw_context.h" + +#include "util/u_format.h" +#include "util/u_inlines.h" + + +/** + * XXX this might get moved someday + * Set the framebuffer surface info: color buffers, zbuffer, stencil buffer. + * Here, we flush the old surfaces and update the tile cache to point to the new + * surfaces. + */ +void +softpipe_set_framebuffer_state(struct pipe_context *pipe, + const struct pipe_framebuffer_state *fb) +{ + struct softpipe_context *sp = softpipe_context(pipe); + uint i; + + draw_flush(sp->draw); + + for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) { + /* check if changing cbuf */ + if (sp->framebuffer.cbufs[i] != fb->cbufs[i]) { + /* flush old */ + sp_flush_tile_cache(sp->cbuf_cache[i]); + + /* assign new */ + pipe_surface_reference(&sp->framebuffer.cbufs[i], fb->cbufs[i]); + + /* update cache */ + sp_tile_cache_set_surface(sp->cbuf_cache[i], fb->cbufs[i]); + } + } + + sp->framebuffer.nr_cbufs = fb->nr_cbufs; + + /* zbuf changing? */ + if (sp->framebuffer.zsbuf != fb->zsbuf) { + /* flush old */ + sp_flush_tile_cache(sp->zsbuf_cache); + + /* assign new */ + pipe_surface_reference(&sp->framebuffer.zsbuf, fb->zsbuf); + + /* update cache */ + sp_tile_cache_set_surface(sp->zsbuf_cache, fb->zsbuf); + + /* Tell draw module how deep the Z/depth buffer is */ + if (sp->framebuffer.zsbuf) { + int depth_bits; + double mrd; + depth_bits = util_format_get_component_bits(sp->framebuffer.zsbuf->format, + UTIL_FORMAT_COLORSPACE_ZS, + 0); + if (depth_bits > 16) { + mrd = 0.0000001; + } + else { + mrd = 0.00002; + } + draw_set_mrd(sp->draw, mrd); + } + } + + sp->framebuffer.width = fb->width; + sp->framebuffer.height = fb->height; + + sp->dirty |= SP_NEW_FRAMEBUFFER; +} diff --git a/src/gallium/drivers/softpipe/sp_state_vertex.c b/src/gallium/drivers/softpipe/sp_state_vertex.c new file mode 100644 index 0000000000..462f4d2655 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_state_vertex.c @@ -0,0 +1,90 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* Authors: Keith Whitwell <keith@tungstengraphics.com> + */ + + +#include "sp_context.h" +#include "sp_state.h" + +#include "util/u_memory.h" +#include "draw/draw_context.h" + + +void * +softpipe_create_vertex_elements_state(struct pipe_context *pipe, + unsigned count, + const struct pipe_vertex_element *attribs) +{ + struct sp_velems_state *velems; + assert(count <= PIPE_MAX_ATTRIBS); + velems = (struct sp_velems_state *) MALLOC(sizeof(struct sp_velems_state)); + if (velems) { + velems->count = count; + memcpy(velems->velem, attribs, sizeof(*attribs) * count); + } + return velems; +} + +void +softpipe_bind_vertex_elements_state(struct pipe_context *pipe, + void *velems) +{ + struct softpipe_context *softpipe = softpipe_context(pipe); + struct sp_velems_state *sp_velems = (struct sp_velems_state *) velems; + + softpipe->velems = sp_velems; + + softpipe->dirty |= SP_NEW_VERTEX; + + if (sp_velems) + draw_set_vertex_elements(softpipe->draw, sp_velems->count, sp_velems->velem); +} + +void +softpipe_delete_vertex_elements_state(struct pipe_context *pipe, void *velems) +{ + FREE( velems ); +} + +void +softpipe_set_vertex_buffers(struct pipe_context *pipe, + unsigned count, + const struct pipe_vertex_buffer *buffers) +{ + struct softpipe_context *softpipe = softpipe_context(pipe); + + assert(count <= PIPE_MAX_ATTRIBS); + + memcpy(softpipe->vertex_buffer, buffers, count * sizeof(buffers[0])); + softpipe->num_vertex_buffers = count; + + softpipe->dirty |= SP_NEW_VERTEX; + + draw_set_vertex_buffers(softpipe->draw, count, buffers); +} diff --git a/src/gallium/drivers/softpipe/sp_surface.c b/src/gallium/drivers/softpipe/sp_surface.c new file mode 100644 index 0000000000..55b27e6010 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_surface.c @@ -0,0 +1,38 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "util/u_surface.h" +#include "sp_context.h" +#include "sp_surface.h" + +void +sp_init_surface_functions(struct softpipe_context *sp) +{ + sp->pipe.resource_copy_region = util_resource_copy_region; + sp->pipe.clear_render_target = util_clear_render_target; + sp->pipe.clear_depth_stencil = util_clear_depth_stencil; +} diff --git a/src/gallium/drivers/softpipe/sp_surface.h b/src/gallium/drivers/softpipe/sp_surface.h new file mode 100644 index 0000000000..22de3ba43f --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_surface.h @@ -0,0 +1,42 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* Authors: Keith Whitwell <keith@tungstengraphics.com> + */ + +#ifndef SP_SURFACE_H +#define SP_SURFACE_H + + +struct softpipe_context; + + +extern void +sp_init_surface_functions(struct softpipe_context *sp); + + +#endif /* SP_SURFACE_H */ diff --git a/src/gallium/drivers/softpipe/sp_tex_sample.c b/src/gallium/drivers/softpipe/sp_tex_sample.c new file mode 100644 index 0000000000..ff83c66d8b --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_tex_sample.c @@ -0,0 +1,1986 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * Copyright 2008-2010 VMware, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/** + * Texture sampling + * + * Authors: + * Brian Paul + * Keith Whitwell + */ + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "pipe/p_shader_tokens.h" +#include "util/u_math.h" +#include "util/u_memory.h" +#include "sp_quad.h" /* only for #define QUAD_* tokens */ +#include "sp_tex_sample.h" +#include "sp_tex_tile_cache.h" + + + +/* + * Return fractional part of 'f'. Used for computing interpolation weights. + * Need to be careful with negative values. + * Note, if this function isn't perfect you'll sometimes see 1-pixel bands + * of improperly weighted linear-filtered textures. + * The tests/texwrap.c demo is a good test. + */ +static INLINE float +frac(float f) +{ + return f - floorf(f); +} + + + +/** + * Linear interpolation macro + */ +static INLINE float +lerp(float a, float v0, float v1) +{ + return v0 + a * (v1 - v0); +} + + +/** + * Do 2D/biliner interpolation of float values. + * v00, v10, v01 and v11 are typically four texture samples in a square/box. + * a and b are the horizontal and vertical interpolants. + * It's important that this function is inlined when compiled with + * optimization! If we find that's not true on some systems, convert + * to a macro. + */ +static INLINE float +lerp_2d(float a, float b, + float v00, float v10, float v01, float v11) +{ + const float temp0 = lerp(a, v00, v10); + const float temp1 = lerp(a, v01, v11); + return lerp(b, temp0, temp1); +} + + +/** + * As above, but 3D interpolation of 8 values. + */ +static INLINE float +lerp_3d(float a, float b, float c, + float v000, float v100, float v010, float v110, + float v001, float v101, float v011, float v111) +{ + const float temp0 = lerp_2d(a, b, v000, v100, v010, v110); + const float temp1 = lerp_2d(a, b, v001, v101, v011, v111); + return lerp(c, temp0, temp1); +} + + + +/** + * Compute coord % size for repeat wrap modes. + * Note that if coord is a signed integer, coord % size doesn't give + * the right value for coord < 0 (in terms of texture repeat). Just + * casting to unsigned fixes that. + */ +static INLINE int +repeat(int coord, unsigned size) +{ + return (int) ((unsigned) coord % size); +} + + +/** + * Apply texture coord wrapping mode and return integer texture indexes + * for a vector of four texcoords (S or T or P). + * \param wrapMode PIPE_TEX_WRAP_x + * \param s the incoming texcoords + * \param size the texture image size + * \param icoord returns the integer texcoords + * \return integer texture index + */ +static void +wrap_nearest_repeat(const float s[4], unsigned size, int icoord[4]) +{ + uint ch; + /* s limited to [0,1) */ + /* i limited to [0,size-1] */ + for (ch = 0; ch < 4; ch++) { + int i = util_ifloor(s[ch] * size); + icoord[ch] = repeat(i, size); + } +} + + +static void +wrap_nearest_clamp(const float s[4], unsigned size, int icoord[4]) +{ + uint ch; + /* s limited to [0,1] */ + /* i limited to [0,size-1] */ + for (ch = 0; ch < 4; ch++) { + if (s[ch] <= 0.0F) + icoord[ch] = 0; + else if (s[ch] >= 1.0F) + icoord[ch] = size - 1; + else + icoord[ch] = util_ifloor(s[ch] * size); + } +} + + +static void +wrap_nearest_clamp_to_edge(const float s[4], unsigned size, int icoord[4]) +{ + uint ch; + /* s limited to [min,max] */ + /* i limited to [0, size-1] */ + const float min = 1.0F / (2.0F * size); + const float max = 1.0F - min; + for (ch = 0; ch < 4; ch++) { + if (s[ch] < min) + icoord[ch] = 0; + else if (s[ch] > max) + icoord[ch] = size - 1; + else + icoord[ch] = util_ifloor(s[ch] * size); + } +} + + +static void +wrap_nearest_clamp_to_border(const float s[4], unsigned size, int icoord[4]) +{ + uint ch; + /* s limited to [min,max] */ + /* i limited to [-1, size] */ + const float min = -1.0F / (2.0F * size); + const float max = 1.0F - min; + for (ch = 0; ch < 4; ch++) { + if (s[ch] <= min) + icoord[ch] = -1; + else if (s[ch] >= max) + icoord[ch] = size; + else + icoord[ch] = util_ifloor(s[ch] * size); + } +} + + +static void +wrap_nearest_mirror_repeat(const float s[4], unsigned size, int icoord[4]) +{ + uint ch; + const float min = 1.0F / (2.0F * size); + const float max = 1.0F - min; + for (ch = 0; ch < 4; ch++) { + const int flr = util_ifloor(s[ch]); + float u = frac(s[ch]); + if (flr & 1) + u = 1.0F - u; + if (u < min) + icoord[ch] = 0; + else if (u > max) + icoord[ch] = size - 1; + else + icoord[ch] = util_ifloor(u * size); + } +} + + +static void +wrap_nearest_mirror_clamp(const float s[4], unsigned size, int icoord[4]) +{ + uint ch; + for (ch = 0; ch < 4; ch++) { + /* s limited to [0,1] */ + /* i limited to [0,size-1] */ + const float u = fabsf(s[ch]); + if (u <= 0.0F) + icoord[ch] = 0; + else if (u >= 1.0F) + icoord[ch] = size - 1; + else + icoord[ch] = util_ifloor(u * size); + } +} + + +static void +wrap_nearest_mirror_clamp_to_edge(const float s[4], unsigned size, + int icoord[4]) +{ + uint ch; + /* s limited to [min,max] */ + /* i limited to [0, size-1] */ + const float min = 1.0F / (2.0F * size); + const float max = 1.0F - min; + for (ch = 0; ch < 4; ch++) { + const float u = fabsf(s[ch]); + if (u < min) + icoord[ch] = 0; + else if (u > max) + icoord[ch] = size - 1; + else + icoord[ch] = util_ifloor(u * size); + } +} + + +static void +wrap_nearest_mirror_clamp_to_border(const float s[4], unsigned size, + int icoord[4]) +{ + uint ch; + /* s limited to [min,max] */ + /* i limited to [0, size-1] */ + const float min = -1.0F / (2.0F * size); + const float max = 1.0F - min; + for (ch = 0; ch < 4; ch++) { + const float u = fabsf(s[ch]); + if (u < min) + icoord[ch] = -1; + else if (u > max) + icoord[ch] = size; + else + icoord[ch] = util_ifloor(u * size); + } +} + + +/** + * Used to compute texel locations for linear sampling for four texcoords. + * \param wrapMode PIPE_TEX_WRAP_x + * \param s the texcoords + * \param size the texture image size + * \param icoord0 returns first texture indexes + * \param icoord1 returns second texture indexes (usually icoord0 + 1) + * \param w returns blend factor/weight between texture indexes + * \param icoord returns the computed integer texture coords + */ +static void +wrap_linear_repeat(const float s[4], unsigned size, + int icoord0[4], int icoord1[4], float w[4]) +{ + uint ch; + for (ch = 0; ch < 4; ch++) { + float u = s[ch] * size - 0.5F; + icoord0[ch] = repeat(util_ifloor(u), size); + icoord1[ch] = repeat(icoord0[ch] + 1, size); + w[ch] = frac(u); + } +} + + +static void +wrap_linear_clamp(const float s[4], unsigned size, + int icoord0[4], int icoord1[4], float w[4]) +{ + uint ch; + for (ch = 0; ch < 4; ch++) { + float u = CLAMP(s[ch], 0.0F, 1.0F); + u = u * size - 0.5f; + icoord0[ch] = util_ifloor(u); + icoord1[ch] = icoord0[ch] + 1; + w[ch] = frac(u); + } +} + + +static void +wrap_linear_clamp_to_edge(const float s[4], unsigned size, + int icoord0[4], int icoord1[4], float w[4]) +{ + uint ch; + for (ch = 0; ch < 4; ch++) { + float u = CLAMP(s[ch], 0.0F, 1.0F); + u = u * size - 0.5f; + icoord0[ch] = util_ifloor(u); + icoord1[ch] = icoord0[ch] + 1; + if (icoord0[ch] < 0) + icoord0[ch] = 0; + if (icoord1[ch] >= (int) size) + icoord1[ch] = size - 1; + w[ch] = frac(u); + } +} + + +static void +wrap_linear_clamp_to_border(const float s[4], unsigned size, + int icoord0[4], int icoord1[4], float w[4]) +{ + const float min = -1.0F / (2.0F * size); + const float max = 1.0F - min; + uint ch; + for (ch = 0; ch < 4; ch++) { + float u = CLAMP(s[ch], min, max); + u = u * size - 0.5f; + icoord0[ch] = util_ifloor(u); + icoord1[ch] = icoord0[ch] + 1; + w[ch] = frac(u); + } +} + + +static void +wrap_linear_mirror_repeat(const float s[4], unsigned size, + int icoord0[4], int icoord1[4], float w[4]) +{ + uint ch; + for (ch = 0; ch < 4; ch++) { + const int flr = util_ifloor(s[ch]); + float u = frac(s[ch]); + if (flr & 1) + u = 1.0F - u; + u = u * size - 0.5F; + icoord0[ch] = util_ifloor(u); + icoord1[ch] = icoord0[ch] + 1; + if (icoord0[ch] < 0) + icoord0[ch] = 0; + if (icoord1[ch] >= (int) size) + icoord1[ch] = size - 1; + w[ch] = frac(u); + } +} + + +static void +wrap_linear_mirror_clamp(const float s[4], unsigned size, + int icoord0[4], int icoord1[4], float w[4]) +{ + uint ch; + for (ch = 0; ch < 4; ch++) { + float u = fabsf(s[ch]); + if (u >= 1.0F) + u = (float) size; + else + u *= size; + u -= 0.5F; + icoord0[ch] = util_ifloor(u); + icoord1[ch] = icoord0[ch] + 1; + w[ch] = frac(u); + } +} + + +static void +wrap_linear_mirror_clamp_to_edge(const float s[4], unsigned size, + int icoord0[4], int icoord1[4], float w[4]) +{ + uint ch; + for (ch = 0; ch < 4; ch++) { + float u = fabsf(s[ch]); + if (u >= 1.0F) + u = (float) size; + else + u *= size; + u -= 0.5F; + icoord0[ch] = util_ifloor(u); + icoord1[ch] = icoord0[ch] + 1; + if (icoord0[ch] < 0) + icoord0[ch] = 0; + if (icoord1[ch] >= (int) size) + icoord1[ch] = size - 1; + w[ch] = frac(u); + } +} + + +static void +wrap_linear_mirror_clamp_to_border(const float s[4], unsigned size, + int icoord0[4], int icoord1[4], float w[4]) +{ + const float min = -1.0F / (2.0F * size); + const float max = 1.0F - min; + uint ch; + for (ch = 0; ch < 4; ch++) { + float u = fabsf(s[ch]); + if (u <= min) + u = min * size; + else if (u >= max) + u = max * size; + else + u *= size; + u -= 0.5F; + icoord0[ch] = util_ifloor(u); + icoord1[ch] = icoord0[ch] + 1; + w[ch] = frac(u); + } +} + + +/** + * PIPE_TEX_WRAP_CLAMP for nearest sampling, unnormalized coords. + */ +static void +wrap_nearest_unorm_clamp(const float s[4], unsigned size, int icoord[4]) +{ + uint ch; + for (ch = 0; ch < 4; ch++) { + int i = util_ifloor(s[ch]); + icoord[ch]= CLAMP(i, 0, (int) size-1); + } +} + + +/** + * PIPE_TEX_WRAP_CLAMP_TO_BORDER for nearest sampling, unnormalized coords. + */ +static void +wrap_nearest_unorm_clamp_to_border(const float s[4], unsigned size, + int icoord[4]) +{ + uint ch; + for (ch = 0; ch < 4; ch++) { + icoord[ch]= util_ifloor( CLAMP(s[ch], -0.5F, (float) size + 0.5F) ); + } +} + + +/** + * PIPE_TEX_WRAP_CLAMP_TO_EDGE for nearest sampling, unnormalized coords. + */ +static void +wrap_nearest_unorm_clamp_to_edge(const float s[4], unsigned size, + int icoord[4]) +{ + uint ch; + for (ch = 0; ch < 4; ch++) { + icoord[ch]= util_ifloor( CLAMP(s[ch], 0.5F, (float) size - 0.5F) ); + } +} + + +/** + * PIPE_TEX_WRAP_CLAMP for linear sampling, unnormalized coords. + */ +static void +wrap_linear_unorm_clamp(const float s[4], unsigned size, + int icoord0[4], int icoord1[4], float w[4]) +{ + uint ch; + for (ch = 0; ch < 4; ch++) { + /* Not exactly what the spec says, but it matches NVIDIA output */ + float u = CLAMP(s[ch] - 0.5F, 0.0f, (float) size - 1.0f); + icoord0[ch] = util_ifloor(u); + icoord1[ch] = icoord0[ch] + 1; + w[ch] = frac(u); + } +} + + +/** + * PIPE_TEX_WRAP_CLAMP_TO_BORDER for linear sampling, unnormalized coords. + */ +static void +wrap_linear_unorm_clamp_to_border(const float s[4], unsigned size, + int icoord0[4], int icoord1[4], float w[4]) +{ + uint ch; + for (ch = 0; ch < 4; ch++) { + float u = CLAMP(s[ch], -0.5F, (float) size + 0.5F); + u -= 0.5F; + icoord0[ch] = util_ifloor(u); + icoord1[ch] = icoord0[ch] + 1; + if (icoord1[ch] > (int) size - 1) + icoord1[ch] = size - 1; + w[ch] = frac(u); + } +} + + +/** + * PIPE_TEX_WRAP_CLAMP_TO_EDGE for linear sampling, unnormalized coords. + */ +static void +wrap_linear_unorm_clamp_to_edge(const float s[4], unsigned size, + int icoord0[4], int icoord1[4], float w[4]) +{ + uint ch; + for (ch = 0; ch < 4; ch++) { + float u = CLAMP(s[ch], +0.5F, (float) size - 0.5F); + u -= 0.5F; + icoord0[ch] = util_ifloor(u); + icoord1[ch] = icoord0[ch] + 1; + if (icoord1[ch] > (int) size - 1) + icoord1[ch] = size - 1; + w[ch] = frac(u); + } +} + + + +/** + * Examine the quad's texture coordinates to compute the partial + * derivatives w.r.t X and Y, then compute lambda (level of detail). + */ +static float +compute_lambda_1d(const struct sp_sampler_varient *samp, + const float s[QUAD_SIZE], + const float t[QUAD_SIZE], + const float p[QUAD_SIZE]) +{ + const struct pipe_resource *texture = samp->texture; + float dsdx = fabsf(s[QUAD_BOTTOM_RIGHT] - s[QUAD_BOTTOM_LEFT]); + float dsdy = fabsf(s[QUAD_TOP_LEFT] - s[QUAD_BOTTOM_LEFT]); + float rho = MAX2(dsdx, dsdy) * texture->width0; + + return util_fast_log2(rho); +} + + +static float +compute_lambda_2d(const struct sp_sampler_varient *samp, + const float s[QUAD_SIZE], + const float t[QUAD_SIZE], + const float p[QUAD_SIZE]) +{ + const struct pipe_resource *texture = samp->texture; + float dsdx = fabsf(s[QUAD_BOTTOM_RIGHT] - s[QUAD_BOTTOM_LEFT]); + float dsdy = fabsf(s[QUAD_TOP_LEFT] - s[QUAD_BOTTOM_LEFT]); + float dtdx = fabsf(t[QUAD_BOTTOM_RIGHT] - t[QUAD_BOTTOM_LEFT]); + float dtdy = fabsf(t[QUAD_TOP_LEFT] - t[QUAD_BOTTOM_LEFT]); + float maxx = MAX2(dsdx, dsdy) * texture->width0; + float maxy = MAX2(dtdx, dtdy) * texture->height0; + float rho = MAX2(maxx, maxy); + + return util_fast_log2(rho); +} + + +static float +compute_lambda_3d(const struct sp_sampler_varient *samp, + const float s[QUAD_SIZE], + const float t[QUAD_SIZE], + const float p[QUAD_SIZE]) +{ + const struct pipe_resource *texture = samp->texture; + float dsdx = fabsf(s[QUAD_BOTTOM_RIGHT] - s[QUAD_BOTTOM_LEFT]); + float dsdy = fabsf(s[QUAD_TOP_LEFT] - s[QUAD_BOTTOM_LEFT]); + float dtdx = fabsf(t[QUAD_BOTTOM_RIGHT] - t[QUAD_BOTTOM_LEFT]); + float dtdy = fabsf(t[QUAD_TOP_LEFT] - t[QUAD_BOTTOM_LEFT]); + float dpdx = fabsf(p[QUAD_BOTTOM_RIGHT] - p[QUAD_BOTTOM_LEFT]); + float dpdy = fabsf(p[QUAD_TOP_LEFT] - p[QUAD_BOTTOM_LEFT]); + float maxx = MAX2(dsdx, dsdy) * texture->width0; + float maxy = MAX2(dtdx, dtdy) * texture->height0; + float maxz = MAX2(dpdx, dpdy) * texture->depth0; + float rho; + + rho = MAX2(maxx, maxy); + rho = MAX2(rho, maxz); + + return util_fast_log2(rho); +} + + +/** + * Compute lambda for a vertex texture sampler. + * Since there aren't derivatives to use, just return 0. + */ +static float +compute_lambda_vert(const struct sp_sampler_varient *samp, + const float s[QUAD_SIZE], + const float t[QUAD_SIZE], + const float p[QUAD_SIZE]) +{ + return 0.0f; +} + + + +/** + * Get a texel from a texture, using the texture tile cache. + * + * \param addr the template tex address containing cube, z, face info. + * \param x the x coord of texel within 2D image + * \param y the y coord of texel within 2D image + * \param rgba the quad to put the texel/color into + * + * XXX maybe move this into sp_tex_tile_cache.c and merge with the + * sp_get_cached_tile_tex() function. Also, get 4 texels instead of 1... + */ + + + + +static INLINE const float * +get_texel_2d_no_border(const struct sp_sampler_varient *samp, + union tex_tile_address addr, int x, int y) +{ + const struct softpipe_tex_cached_tile *tile; + + addr.bits.x = x / TILE_SIZE; + addr.bits.y = y / TILE_SIZE; + y %= TILE_SIZE; + x %= TILE_SIZE; + + tile = sp_get_cached_tile_tex(samp->cache, addr); + + return &tile->data.color[y][x][0]; +} + + +static INLINE const float * +get_texel_2d(const struct sp_sampler_varient *samp, + union tex_tile_address addr, int x, int y) +{ + const struct pipe_resource *texture = samp->texture; + unsigned level = addr.bits.level; + + if (x < 0 || x >= (int) u_minify(texture->width0, level) || + y < 0 || y >= (int) u_minify(texture->height0, level)) { + return samp->sampler->border_color; + } + else { + return get_texel_2d_no_border( samp, addr, x, y ); + } +} + + +/* Gather a quad of adjacent texels within a tile: + */ +static INLINE void +get_texel_quad_2d_no_border_single_tile(const struct sp_sampler_varient *samp, + union tex_tile_address addr, + unsigned x, unsigned y, + const float *out[4]) +{ + const struct softpipe_tex_cached_tile *tile; + + addr.bits.x = x / TILE_SIZE; + addr.bits.y = y / TILE_SIZE; + y %= TILE_SIZE; + x %= TILE_SIZE; + + tile = sp_get_cached_tile_tex(samp->cache, addr); + + out[0] = &tile->data.color[y ][x ][0]; + out[1] = &tile->data.color[y ][x+1][0]; + out[2] = &tile->data.color[y+1][x ][0]; + out[3] = &tile->data.color[y+1][x+1][0]; +} + + +/* Gather a quad of potentially non-adjacent texels: + */ +static INLINE void +get_texel_quad_2d_no_border(const struct sp_sampler_varient *samp, + union tex_tile_address addr, + int x0, int y0, + int x1, int y1, + const float *out[4]) +{ + out[0] = get_texel_2d_no_border( samp, addr, x0, y0 ); + out[1] = get_texel_2d_no_border( samp, addr, x1, y0 ); + out[2] = get_texel_2d_no_border( samp, addr, x0, y1 ); + out[3] = get_texel_2d_no_border( samp, addr, x1, y1 ); +} + +/* Can involve a lot of unnecessary checks for border color: + */ +static INLINE void +get_texel_quad_2d(const struct sp_sampler_varient *samp, + union tex_tile_address addr, + int x0, int y0, + int x1, int y1, + const float *out[4]) +{ + out[0] = get_texel_2d( samp, addr, x0, y0 ); + out[1] = get_texel_2d( samp, addr, x1, y0 ); + out[3] = get_texel_2d( samp, addr, x1, y1 ); + out[2] = get_texel_2d( samp, addr, x0, y1 ); +} + + + +/* 3d varients: + */ +static INLINE const float * +get_texel_3d_no_border(const struct sp_sampler_varient *samp, + union tex_tile_address addr, int x, int y, int z) +{ + const struct softpipe_tex_cached_tile *tile; + + addr.bits.x = x / TILE_SIZE; + addr.bits.y = y / TILE_SIZE; + addr.bits.z = z; + y %= TILE_SIZE; + x %= TILE_SIZE; + + tile = sp_get_cached_tile_tex(samp->cache, addr); + + return &tile->data.color[y][x][0]; +} + + +static INLINE const float * +get_texel_3d(const struct sp_sampler_varient *samp, + union tex_tile_address addr, int x, int y, int z) +{ + const struct pipe_resource *texture = samp->texture; + unsigned level = addr.bits.level; + + if (x < 0 || x >= (int) u_minify(texture->width0, level) || + y < 0 || y >= (int) u_minify(texture->height0, level) || + z < 0 || z >= (int) u_minify(texture->depth0, level)) { + return samp->sampler->border_color; + } + else { + return get_texel_3d_no_border( samp, addr, x, y, z ); + } +} + + +/** + * Given the logbase2 of a mipmap's base level size and a mipmap level, + * return the size (in texels) of that mipmap level. + * For example, if level[0].width = 256 then base_pot will be 8. + * If level = 2, then we'll return 64 (the width at level=2). + * Return 1 if level > base_pot. + */ +static INLINE unsigned +pot_level_size(unsigned base_pot, unsigned level) +{ + return (base_pot >= level) ? (1 << (base_pot - level)) : 1; +} + + +/* Some image-filter fastpaths: + */ +static INLINE void +img_filter_2d_linear_repeat_POT(struct tgsi_sampler *tgsi_sampler, + const float s[QUAD_SIZE], + const float t[QUAD_SIZE], + const float p[QUAD_SIZE], + const float c0[QUAD_SIZE], + enum tgsi_sampler_control control, + float rgba[NUM_CHANNELS][QUAD_SIZE]) +{ + const struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler); + unsigned j; + unsigned level = samp->level; + unsigned xpot = pot_level_size(samp->xpot, level); + unsigned ypot = pot_level_size(samp->ypot, level); + unsigned xmax = (xpot - 1) & (TILE_SIZE - 1); /* MIN2(TILE_SIZE, xpot) - 1; */ + unsigned ymax = (ypot - 1) & (TILE_SIZE - 1); /* MIN2(TILE_SIZE, ypot) - 1; */ + union tex_tile_address addr; + + addr.value = 0; + addr.bits.level = samp->level; + + for (j = 0; j < QUAD_SIZE; j++) { + int c; + + float u = s[j] * xpot - 0.5F; + float v = t[j] * ypot - 0.5F; + + int uflr = util_ifloor(u); + int vflr = util_ifloor(v); + + float xw = u - (float)uflr; + float yw = v - (float)vflr; + + int x0 = uflr & (xpot - 1); + int y0 = vflr & (ypot - 1); + + const float *tx[4]; + + /* Can we fetch all four at once: + */ + if (x0 < xmax && y0 < ymax) { + get_texel_quad_2d_no_border_single_tile(samp, addr, x0, y0, tx); + } + else { + unsigned x1 = (x0 + 1) & (xpot - 1); + unsigned y1 = (y0 + 1) & (ypot - 1); + get_texel_quad_2d_no_border(samp, addr, x0, y0, x1, y1, tx); + } + + /* interpolate R, G, B, A */ + for (c = 0; c < 4; c++) { + rgba[c][j] = lerp_2d(xw, yw, + tx[0][c], tx[1][c], + tx[2][c], tx[3][c]); + } + } +} + + +static INLINE void +img_filter_2d_nearest_repeat_POT(struct tgsi_sampler *tgsi_sampler, + const float s[QUAD_SIZE], + const float t[QUAD_SIZE], + const float p[QUAD_SIZE], + const float c0[QUAD_SIZE], + enum tgsi_sampler_control control, + float rgba[NUM_CHANNELS][QUAD_SIZE]) +{ + const struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler); + unsigned j; + unsigned level = samp->level; + unsigned xpot = pot_level_size(samp->xpot, level); + unsigned ypot = pot_level_size(samp->ypot, level); + union tex_tile_address addr; + + addr.value = 0; + addr.bits.level = samp->level; + + for (j = 0; j < QUAD_SIZE; j++) { + int c; + + float u = s[j] * xpot; + float v = t[j] * ypot; + + int uflr = util_ifloor(u); + int vflr = util_ifloor(v); + + int x0 = uflr & (xpot - 1); + int y0 = vflr & (ypot - 1); + + const float *out = get_texel_2d_no_border(samp, addr, x0, y0); + + for (c = 0; c < 4; c++) { + rgba[c][j] = out[c]; + } + } +} + + +static INLINE void +img_filter_2d_nearest_clamp_POT(struct tgsi_sampler *tgsi_sampler, + const float s[QUAD_SIZE], + const float t[QUAD_SIZE], + const float p[QUAD_SIZE], + const float c0[QUAD_SIZE], + enum tgsi_sampler_control control, + float rgba[NUM_CHANNELS][QUAD_SIZE]) +{ + const struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler); + unsigned j; + unsigned level = samp->level; + unsigned xpot = pot_level_size(samp->xpot, level); + unsigned ypot = pot_level_size(samp->ypot, level); + union tex_tile_address addr; + + addr.value = 0; + addr.bits.level = samp->level; + + for (j = 0; j < QUAD_SIZE; j++) { + int c; + + float u = s[j] * xpot; + float v = t[j] * ypot; + + int x0, y0; + const float *out; + + x0 = util_ifloor(u); + if (x0 < 0) + x0 = 0; + else if (x0 > xpot - 1) + x0 = xpot - 1; + + y0 = util_ifloor(v); + if (y0 < 0) + y0 = 0; + else if (y0 > ypot - 1) + y0 = ypot - 1; + + out = get_texel_2d_no_border(samp, addr, x0, y0); + + for (c = 0; c < 4; c++) { + rgba[c][j] = out[c]; + } + } +} + + +static void +img_filter_1d_nearest(struct tgsi_sampler *tgsi_sampler, + const float s[QUAD_SIZE], + const float t[QUAD_SIZE], + const float p[QUAD_SIZE], + const float c0[QUAD_SIZE], + enum tgsi_sampler_control control, + float rgba[NUM_CHANNELS][QUAD_SIZE]) +{ + const struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler); + const struct pipe_resource *texture = samp->texture; + unsigned level0, j; + int width; + int x[4]; + union tex_tile_address addr; + + level0 = samp->level; + width = u_minify(texture->width0, level0); + + assert(width > 0); + + addr.value = 0; + addr.bits.level = samp->level; + + samp->nearest_texcoord_s(s, width, x); + + for (j = 0; j < QUAD_SIZE; j++) { + const float *out = get_texel_2d(samp, addr, x[j], 0); + int c; + for (c = 0; c < 4; c++) { + rgba[c][j] = out[c]; + } + } +} + + +static void +img_filter_2d_nearest(struct tgsi_sampler *tgsi_sampler, + const float s[QUAD_SIZE], + const float t[QUAD_SIZE], + const float p[QUAD_SIZE], + const float c0[QUAD_SIZE], + enum tgsi_sampler_control control, + float rgba[NUM_CHANNELS][QUAD_SIZE]) +{ + const struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler); + const struct pipe_resource *texture = samp->texture; + unsigned level0, j; + int width, height; + int x[4], y[4]; + union tex_tile_address addr; + + + level0 = samp->level; + width = u_minify(texture->width0, level0); + height = u_minify(texture->height0, level0); + + assert(width > 0); + assert(height > 0); + + addr.value = 0; + addr.bits.level = samp->level; + + samp->nearest_texcoord_s(s, width, x); + samp->nearest_texcoord_t(t, height, y); + + for (j = 0; j < QUAD_SIZE; j++) { + const float *out = get_texel_2d(samp, addr, x[j], y[j]); + int c; + for (c = 0; c < 4; c++) { + rgba[c][j] = out[c]; + } + } +} + + +static INLINE union tex_tile_address +face(union tex_tile_address addr, unsigned face ) +{ + addr.bits.face = face; + return addr; +} + + +static void +img_filter_cube_nearest(struct tgsi_sampler *tgsi_sampler, + const float s[QUAD_SIZE], + const float t[QUAD_SIZE], + const float p[QUAD_SIZE], + const float c0[QUAD_SIZE], + enum tgsi_sampler_control control, + float rgba[NUM_CHANNELS][QUAD_SIZE]) +{ + const struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler); + const struct pipe_resource *texture = samp->texture; + const unsigned *faces = samp->faces; /* zero when not cube-mapping */ + unsigned level0, j; + int width, height; + int x[4], y[4]; + union tex_tile_address addr; + + level0 = samp->level; + width = u_minify(texture->width0, level0); + height = u_minify(texture->height0, level0); + + assert(width > 0); + assert(height > 0); + + addr.value = 0; + addr.bits.level = samp->level; + + samp->nearest_texcoord_s(s, width, x); + samp->nearest_texcoord_t(t, height, y); + + for (j = 0; j < QUAD_SIZE; j++) { + const float *out = get_texel_2d(samp, face(addr, faces[j]), x[j], y[j]); + int c; + for (c = 0; c < 4; c++) { + rgba[c][j] = out[c]; + } + } +} + + +static void +img_filter_3d_nearest(struct tgsi_sampler *tgsi_sampler, + const float s[QUAD_SIZE], + const float t[QUAD_SIZE], + const float p[QUAD_SIZE], + const float c0[QUAD_SIZE], + enum tgsi_sampler_control control, + float rgba[NUM_CHANNELS][QUAD_SIZE]) +{ + const struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler); + const struct pipe_resource *texture = samp->texture; + unsigned level0, j; + int width, height, depth; + int x[4], y[4], z[4]; + union tex_tile_address addr; + + level0 = samp->level; + width = u_minify(texture->width0, level0); + height = u_minify(texture->height0, level0); + depth = u_minify(texture->depth0, level0); + + assert(width > 0); + assert(height > 0); + assert(depth > 0); + + samp->nearest_texcoord_s(s, width, x); + samp->nearest_texcoord_t(t, height, y); + samp->nearest_texcoord_p(p, depth, z); + + addr.value = 0; + addr.bits.level = samp->level; + + for (j = 0; j < QUAD_SIZE; j++) { + const float *out = get_texel_3d(samp, addr, x[j], y[j], z[j]); + int c; + for (c = 0; c < 4; c++) { + rgba[c][j] = out[c]; + } + } +} + + +static void +img_filter_1d_linear(struct tgsi_sampler *tgsi_sampler, + const float s[QUAD_SIZE], + const float t[QUAD_SIZE], + const float p[QUAD_SIZE], + const float c0[QUAD_SIZE], + enum tgsi_sampler_control control, + float rgba[NUM_CHANNELS][QUAD_SIZE]) +{ + const struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler); + const struct pipe_resource *texture = samp->texture; + unsigned level0, j; + int width; + int x0[4], x1[4]; + float xw[4]; /* weights */ + union tex_tile_address addr; + + level0 = samp->level; + width = u_minify(texture->width0, level0); + + assert(width > 0); + + addr.value = 0; + addr.bits.level = samp->level; + + samp->linear_texcoord_s(s, width, x0, x1, xw); + + for (j = 0; j < QUAD_SIZE; j++) { + const float *tx0 = get_texel_2d(samp, addr, x0[j], 0); + const float *tx1 = get_texel_2d(samp, addr, x1[j], 0); + int c; + + /* interpolate R, G, B, A */ + for (c = 0; c < 4; c++) { + rgba[c][j] = lerp(xw[j], tx0[c], tx1[c]); + } + } +} + + +static void +img_filter_2d_linear(struct tgsi_sampler *tgsi_sampler, + const float s[QUAD_SIZE], + const float t[QUAD_SIZE], + const float p[QUAD_SIZE], + const float c0[QUAD_SIZE], + enum tgsi_sampler_control control, + float rgba[NUM_CHANNELS][QUAD_SIZE]) +{ + const struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler); + const struct pipe_resource *texture = samp->texture; + unsigned level0, j; + int width, height; + int x0[4], y0[4], x1[4], y1[4]; + float xw[4], yw[4]; /* weights */ + union tex_tile_address addr; + + level0 = samp->level; + width = u_minify(texture->width0, level0); + height = u_minify(texture->height0, level0); + + assert(width > 0); + assert(height > 0); + + addr.value = 0; + addr.bits.level = samp->level; + + samp->linear_texcoord_s(s, width, x0, x1, xw); + samp->linear_texcoord_t(t, height, y0, y1, yw); + + for (j = 0; j < QUAD_SIZE; j++) { + const float *tx0 = get_texel_2d(samp, addr, x0[j], y0[j]); + const float *tx1 = get_texel_2d(samp, addr, x1[j], y0[j]); + const float *tx2 = get_texel_2d(samp, addr, x0[j], y1[j]); + const float *tx3 = get_texel_2d(samp, addr, x1[j], y1[j]); + int c; + + /* interpolate R, G, B, A */ + for (c = 0; c < 4; c++) { + rgba[c][j] = lerp_2d(xw[j], yw[j], + tx0[c], tx1[c], + tx2[c], tx3[c]); + } + } +} + + +static void +img_filter_cube_linear(struct tgsi_sampler *tgsi_sampler, + const float s[QUAD_SIZE], + const float t[QUAD_SIZE], + const float p[QUAD_SIZE], + const float c0[QUAD_SIZE], + enum tgsi_sampler_control control, + float rgba[NUM_CHANNELS][QUAD_SIZE]) +{ + const struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler); + const struct pipe_resource *texture = samp->texture; + const unsigned *faces = samp->faces; /* zero when not cube-mapping */ + unsigned level0, j; + int width, height; + int x0[4], y0[4], x1[4], y1[4]; + float xw[4], yw[4]; /* weights */ + union tex_tile_address addr; + + level0 = samp->level; + width = u_minify(texture->width0, level0); + height = u_minify(texture->height0, level0); + + assert(width > 0); + assert(height > 0); + + addr.value = 0; + addr.bits.level = samp->level; + + samp->linear_texcoord_s(s, width, x0, x1, xw); + samp->linear_texcoord_t(t, height, y0, y1, yw); + + for (j = 0; j < QUAD_SIZE; j++) { + union tex_tile_address addrj = face(addr, faces[j]); + const float *tx0 = get_texel_2d(samp, addrj, x0[j], y0[j]); + const float *tx1 = get_texel_2d(samp, addrj, x1[j], y0[j]); + const float *tx2 = get_texel_2d(samp, addrj, x0[j], y1[j]); + const float *tx3 = get_texel_2d(samp, addrj, x1[j], y1[j]); + int c; + + /* interpolate R, G, B, A */ + for (c = 0; c < 4; c++) { + rgba[c][j] = lerp_2d(xw[j], yw[j], + tx0[c], tx1[c], + tx2[c], tx3[c]); + } + } +} + + +static void +img_filter_3d_linear(struct tgsi_sampler *tgsi_sampler, + const float s[QUAD_SIZE], + const float t[QUAD_SIZE], + const float p[QUAD_SIZE], + const float c0[QUAD_SIZE], + enum tgsi_sampler_control control, + float rgba[NUM_CHANNELS][QUAD_SIZE]) +{ + const struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler); + const struct pipe_resource *texture = samp->texture; + unsigned level0, j; + int width, height, depth; + int x0[4], x1[4], y0[4], y1[4], z0[4], z1[4]; + float xw[4], yw[4], zw[4]; /* interpolation weights */ + union tex_tile_address addr; + + level0 = samp->level; + width = u_minify(texture->width0, level0); + height = u_minify(texture->height0, level0); + depth = u_minify(texture->depth0, level0); + + addr.value = 0; + addr.bits.level = level0; + + assert(width > 0); + assert(height > 0); + assert(depth > 0); + + samp->linear_texcoord_s(s, width, x0, x1, xw); + samp->linear_texcoord_t(t, height, y0, y1, yw); + samp->linear_texcoord_p(p, depth, z0, z1, zw); + + for (j = 0; j < QUAD_SIZE; j++) { + int c; + + const float *tx00 = get_texel_3d(samp, addr, x0[j], y0[j], z0[j]); + const float *tx01 = get_texel_3d(samp, addr, x1[j], y0[j], z0[j]); + const float *tx02 = get_texel_3d(samp, addr, x0[j], y1[j], z0[j]); + const float *tx03 = get_texel_3d(samp, addr, x1[j], y1[j], z0[j]); + + const float *tx10 = get_texel_3d(samp, addr, x0[j], y0[j], z1[j]); + const float *tx11 = get_texel_3d(samp, addr, x1[j], y0[j], z1[j]); + const float *tx12 = get_texel_3d(samp, addr, x0[j], y1[j], z1[j]); + const float *tx13 = get_texel_3d(samp, addr, x1[j], y1[j], z1[j]); + + /* interpolate R, G, B, A */ + for (c = 0; c < 4; c++) { + rgba[c][j] = lerp_3d(xw[j], yw[j], zw[j], + tx00[c], tx01[c], + tx02[c], tx03[c], + tx10[c], tx11[c], + tx12[c], tx13[c]); + } + } +} + + +/* Calculate level of detail for every fragment. + * Note that lambda has already been biased by global LOD bias. + */ +static INLINE void +compute_lod(const struct pipe_sampler_state *sampler, + const float biased_lambda, + const float lodbias[QUAD_SIZE], + float lod[QUAD_SIZE]) +{ + uint i; + + for (i = 0; i < QUAD_SIZE; i++) { + lod[i] = biased_lambda + lodbias[i]; + lod[i] = CLAMP(lod[i], sampler->min_lod, sampler->max_lod); + } +} + + +static void +mip_filter_linear(struct tgsi_sampler *tgsi_sampler, + const float s[QUAD_SIZE], + const float t[QUAD_SIZE], + const float p[QUAD_SIZE], + const float c0[QUAD_SIZE], + enum tgsi_sampler_control control, + float rgba[NUM_CHANNELS][QUAD_SIZE]) +{ + struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler); + const struct pipe_resource *texture = samp->texture; + int level0; + float lambda; + float lod[QUAD_SIZE]; + + if (control == tgsi_sampler_lod_bias) { + lambda = samp->compute_lambda(samp, s, t, p) + samp->sampler->lod_bias; + compute_lod(samp->sampler, lambda, c0, lod); + } else { + assert(control == tgsi_sampler_lod_explicit); + + memcpy(lod, c0, sizeof(lod)); + } + + /* XXX: Take into account all lod values. + */ + lambda = lod[0]; + level0 = (int)lambda; + + if (lambda < 0.0) { + samp->level = 0; + samp->mag_img_filter(tgsi_sampler, s, t, p, NULL, tgsi_sampler_lod_bias, rgba); + } + else if (level0 >= texture->last_level) { + samp->level = texture->last_level; + samp->min_img_filter(tgsi_sampler, s, t, p, NULL, tgsi_sampler_lod_bias, rgba); + } + else { + float levelBlend = lambda - level0; + float rgba0[4][4]; + float rgba1[4][4]; + int c,j; + + samp->level = level0; + samp->min_img_filter(tgsi_sampler, s, t, p, NULL, tgsi_sampler_lod_bias, rgba0); + + samp->level = level0+1; + samp->min_img_filter(tgsi_sampler, s, t, p, NULL, tgsi_sampler_lod_bias, rgba1); + + for (j = 0; j < QUAD_SIZE; j++) { + for (c = 0; c < 4; c++) { + rgba[c][j] = lerp(levelBlend, rgba0[c][j], rgba1[c][j]); + } + } + } +} + + +/** + * Compute nearest mipmap level from texcoords. + * Then sample the texture level for four elements of a quad. + * \param c0 the LOD bias factors, or absolute LODs (depending on control) + */ +static void +mip_filter_nearest(struct tgsi_sampler *tgsi_sampler, + const float s[QUAD_SIZE], + const float t[QUAD_SIZE], + const float p[QUAD_SIZE], + const float c0[QUAD_SIZE], + enum tgsi_sampler_control control, + float rgba[NUM_CHANNELS][QUAD_SIZE]) +{ + struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler); + const struct pipe_resource *texture = samp->texture; + float lambda; + float lod[QUAD_SIZE]; + + if (control == tgsi_sampler_lod_bias) { + lambda = samp->compute_lambda(samp, s, t, p) + samp->sampler->lod_bias; + compute_lod(samp->sampler, lambda, c0, lod); + } else { + assert(control == tgsi_sampler_lod_explicit); + + memcpy(lod, c0, sizeof(lod)); + } + + /* XXX: Take into account all lod values. + */ + lambda = lod[0]; + + if (lambda < 0.0) { + samp->level = 0; + samp->mag_img_filter(tgsi_sampler, s, t, p, NULL, tgsi_sampler_lod_bias, rgba); + } + else { + samp->level = (int)(lambda + 0.5) ; + samp->level = MIN2(samp->level, (int)texture->last_level); + samp->min_img_filter(tgsi_sampler, s, t, p, NULL, tgsi_sampler_lod_bias, rgba); + } + +#if 0 + printf("RGBA %g %g %g %g, %g %g %g %g, %g %g %g %g, %g %g %g %g\n", + rgba[0][0], rgba[1][0], rgba[2][0], rgba[3][0], + rgba[0][1], rgba[1][1], rgba[2][1], rgba[3][1], + rgba[0][2], rgba[1][2], rgba[2][2], rgba[3][2], + rgba[0][3], rgba[1][3], rgba[2][3], rgba[3][3]); +#endif +} + + +static void +mip_filter_none(struct tgsi_sampler *tgsi_sampler, + const float s[QUAD_SIZE], + const float t[QUAD_SIZE], + const float p[QUAD_SIZE], + const float c0[QUAD_SIZE], + enum tgsi_sampler_control control, + float rgba[NUM_CHANNELS][QUAD_SIZE]) +{ + struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler); + float lambda; + float lod[QUAD_SIZE]; + + if (control == tgsi_sampler_lod_bias) { + lambda = samp->compute_lambda(samp, s, t, p) + samp->sampler->lod_bias; + compute_lod(samp->sampler, lambda, c0, lod); + } else { + assert(control == tgsi_sampler_lod_explicit); + + memcpy(lod, c0, sizeof(lod)); + } + + /* XXX: Take into account all lod values. + */ + lambda = lod[0]; + + if (lambda < 0.0) { + samp->mag_img_filter(tgsi_sampler, s, t, p, NULL, tgsi_sampler_lod_bias, rgba); + } + else { + samp->min_img_filter(tgsi_sampler, s, t, p, NULL, tgsi_sampler_lod_bias, rgba); + } +} + + + +/** + * Specialized version of mip_filter_linear with hard-wired calls to + * 2d lambda calculation and 2d_linear_repeat_POT img filters. + */ +static void +mip_filter_linear_2d_linear_repeat_POT( + struct tgsi_sampler *tgsi_sampler, + const float s[QUAD_SIZE], + const float t[QUAD_SIZE], + const float p[QUAD_SIZE], + const float c0[QUAD_SIZE], + enum tgsi_sampler_control control, + float rgba[NUM_CHANNELS][QUAD_SIZE]) +{ + struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler); + const struct pipe_resource *texture = samp->texture; + int level0; + float lambda; + float lod[QUAD_SIZE]; + + if (control == tgsi_sampler_lod_bias) { + lambda = samp->compute_lambda(samp, s, t, p) + samp->sampler->lod_bias; + compute_lod(samp->sampler, lambda, c0, lod); + } else { + assert(control == tgsi_sampler_lod_explicit); + + memcpy(lod, c0, sizeof(lod)); + } + + /* XXX: Take into account all lod values. + */ + lambda = lod[0]; + level0 = (int)lambda; + + /* Catches both negative and large values of level0: + */ + if ((unsigned)level0 >= texture->last_level) { + if (level0 < 0) + samp->level = 0; + else + samp->level = texture->last_level; + + img_filter_2d_linear_repeat_POT(tgsi_sampler, s, t, p, NULL, tgsi_sampler_lod_bias, rgba); + } + else { + float levelBlend = lambda - level0; + float rgba0[4][4]; + float rgba1[4][4]; + int c,j; + + samp->level = level0; + img_filter_2d_linear_repeat_POT(tgsi_sampler, s, t, p, NULL, tgsi_sampler_lod_bias, rgba0); + + samp->level = level0+1; + img_filter_2d_linear_repeat_POT(tgsi_sampler, s, t, p, NULL, tgsi_sampler_lod_bias, rgba1); + + for (j = 0; j < QUAD_SIZE; j++) { + for (c = 0; c < 4; c++) { + rgba[c][j] = lerp(levelBlend, rgba0[c][j], rgba1[c][j]); + } + } + } +} + + + +/** + * Do shadow/depth comparisons. + */ +static void +sample_compare(struct tgsi_sampler *tgsi_sampler, + const float s[QUAD_SIZE], + const float t[QUAD_SIZE], + const float p[QUAD_SIZE], + const float c0[QUAD_SIZE], + enum tgsi_sampler_control control, + float rgba[NUM_CHANNELS][QUAD_SIZE]) +{ + struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler); + const struct pipe_sampler_state *sampler = samp->sampler; + int j, k0, k1, k2, k3; + float val; + + samp->mip_filter(tgsi_sampler, s, t, p, c0, control, rgba); + + /** + * Compare texcoord 'p' (aka R) against texture value 'rgba[0]' + * When we sampled the depth texture, the depth value was put into all + * RGBA channels. We look at the red channel here. + */ + + /* compare four texcoords vs. four texture samples */ + switch (sampler->compare_func) { + case PIPE_FUNC_LESS: + k0 = p[0] < rgba[0][0]; + k1 = p[1] < rgba[0][1]; + k2 = p[2] < rgba[0][2]; + k3 = p[3] < rgba[0][3]; + break; + case PIPE_FUNC_LEQUAL: + k0 = p[0] <= rgba[0][0]; + k1 = p[1] <= rgba[0][1]; + k2 = p[2] <= rgba[0][2]; + k3 = p[3] <= rgba[0][3]; + break; + case PIPE_FUNC_GREATER: + k0 = p[0] > rgba[0][0]; + k1 = p[1] > rgba[0][1]; + k2 = p[2] > rgba[0][2]; + k3 = p[3] > rgba[0][3]; + break; + case PIPE_FUNC_GEQUAL: + k0 = p[0] >= rgba[0][0]; + k1 = p[1] >= rgba[0][1]; + k2 = p[2] >= rgba[0][2]; + k3 = p[3] >= rgba[0][3]; + break; + case PIPE_FUNC_EQUAL: + k0 = p[0] == rgba[0][0]; + k1 = p[1] == rgba[0][1]; + k2 = p[2] == rgba[0][2]; + k3 = p[3] == rgba[0][3]; + break; + case PIPE_FUNC_NOTEQUAL: + k0 = p[0] != rgba[0][0]; + k1 = p[1] != rgba[0][1]; + k2 = p[2] != rgba[0][2]; + k3 = p[3] != rgba[0][3]; + break; + case PIPE_FUNC_ALWAYS: + k0 = k1 = k2 = k3 = 1; + break; + case PIPE_FUNC_NEVER: + k0 = k1 = k2 = k3 = 0; + break; + default: + k0 = k1 = k2 = k3 = 0; + assert(0); + break; + } + + /* convert four pass/fail values to an intensity in [0,1] */ + val = 0.25F * (k0 + k1 + k2 + k3); + + /* XXX returning result for default GL_DEPTH_TEXTURE_MODE = GL_LUMINANCE */ + for (j = 0; j < 4; j++) { + rgba[0][j] = rgba[1][j] = rgba[2][j] = val; + rgba[3][j] = 1.0F; + } +} + + +/** + * Use 3D texcoords to choose a cube face, then sample the 2D cube faces. + * Put face info into the sampler faces[] array. + */ +static void +sample_cube(struct tgsi_sampler *tgsi_sampler, + const float s[QUAD_SIZE], + const float t[QUAD_SIZE], + const float p[QUAD_SIZE], + const float c0[QUAD_SIZE], + enum tgsi_sampler_control control, + float rgba[NUM_CHANNELS][QUAD_SIZE]) +{ + struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler); + unsigned j; + float ssss[4], tttt[4]; + + /* + major axis + direction target sc tc ma + ---------- ------------------------------- --- --- --- + +rx TEXTURE_CUBE_MAP_POSITIVE_X_EXT -rz -ry rx + -rx TEXTURE_CUBE_MAP_NEGATIVE_X_EXT +rz -ry rx + +ry TEXTURE_CUBE_MAP_POSITIVE_Y_EXT +rx +rz ry + -ry TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT +rx -rz ry + +rz TEXTURE_CUBE_MAP_POSITIVE_Z_EXT +rx -ry rz + -rz TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT -rx -ry rz + */ + + /* Choose the cube face and compute new s/t coords for the 2D face. + * + * Use the same cube face for all four pixels in the quad. + * + * This isn't ideal, but if we want to use a different cube face + * per pixel in the quad, we'd have to also compute the per-face + * LOD here too. That's because the four post-face-selection + * texcoords are no longer related to each other (they're + * per-face!) so we can't use subtraction to compute the partial + * deriviates to compute the LOD. Doing so (near cube edges + * anyway) gives us pretty much random values. + */ + { + /* use the average of the four pixel's texcoords to choose the face */ + const float rx = 0.25 * (s[0] + s[1] + s[2] + s[3]); + const float ry = 0.25 * (t[0] + t[1] + t[2] + t[3]); + const float rz = 0.25 * (p[0] + p[1] + p[2] + p[3]); + const float arx = fabsf(rx), ary = fabsf(ry), arz = fabsf(rz); + + if (arx >= ary && arx >= arz) { + float sign = (rx >= 0.0F) ? 1.0F : -1.0F; + uint face = (rx >= 0.0F) ? PIPE_TEX_FACE_POS_X : PIPE_TEX_FACE_NEG_X; + for (j = 0; j < QUAD_SIZE; j++) { + const float ima = -0.5F / fabsf(s[j]); + ssss[j] = sign * p[j] * ima + 0.5F; + tttt[j] = t[j] * ima + 0.5F; + samp->faces[j] = face; + } + } + else if (ary >= arx && ary >= arz) { + float sign = (ry >= 0.0F) ? 1.0F : -1.0F; + uint face = (ry >= 0.0F) ? PIPE_TEX_FACE_POS_Y : PIPE_TEX_FACE_NEG_Y; + for (j = 0; j < QUAD_SIZE; j++) { + const float ima = -0.5F / fabsf(t[j]); + ssss[j] = -s[j] * ima + 0.5F; + tttt[j] = sign * -p[j] * ima + 0.5F; + samp->faces[j] = face; + } + } + else { + float sign = (rz >= 0.0F) ? 1.0F : -1.0F; + uint face = (rz >= 0.0F) ? PIPE_TEX_FACE_POS_Z : PIPE_TEX_FACE_NEG_Z; + for (j = 0; j < QUAD_SIZE; j++) { + const float ima = -0.5 / fabsf(p[j]); + ssss[j] = sign * -s[j] * ima + 0.5F; + tttt[j] = t[j] * ima + 0.5F; + samp->faces[j] = face; + } + } + } + + /* In our little pipeline, the compare stage is next. If compare + * is not active, this will point somewhere deeper into the + * pipeline, eg. to mip_filter or even img_filter. + */ + samp->compare(tgsi_sampler, ssss, tttt, NULL, c0, control, rgba); +} + + + +static wrap_nearest_func +get_nearest_unorm_wrap(unsigned mode) +{ + switch (mode) { + case PIPE_TEX_WRAP_CLAMP: + return wrap_nearest_unorm_clamp; + case PIPE_TEX_WRAP_CLAMP_TO_EDGE: + return wrap_nearest_unorm_clamp_to_edge; + case PIPE_TEX_WRAP_CLAMP_TO_BORDER: + return wrap_nearest_unorm_clamp_to_border; + default: + assert(0); + return wrap_nearest_unorm_clamp; + } +} + + +static wrap_nearest_func +get_nearest_wrap(unsigned mode) +{ + switch (mode) { + case PIPE_TEX_WRAP_REPEAT: + return wrap_nearest_repeat; + case PIPE_TEX_WRAP_CLAMP: + return wrap_nearest_clamp; + case PIPE_TEX_WRAP_CLAMP_TO_EDGE: + return wrap_nearest_clamp_to_edge; + case PIPE_TEX_WRAP_CLAMP_TO_BORDER: + return wrap_nearest_clamp_to_border; + case PIPE_TEX_WRAP_MIRROR_REPEAT: + return wrap_nearest_mirror_repeat; + case PIPE_TEX_WRAP_MIRROR_CLAMP: + return wrap_nearest_mirror_clamp; + case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: + return wrap_nearest_mirror_clamp_to_edge; + case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: + return wrap_nearest_mirror_clamp_to_border; + default: + assert(0); + return wrap_nearest_repeat; + } +} + + +static wrap_linear_func +get_linear_unorm_wrap(unsigned mode) +{ + switch (mode) { + case PIPE_TEX_WRAP_CLAMP: + return wrap_linear_unorm_clamp; + case PIPE_TEX_WRAP_CLAMP_TO_EDGE: + return wrap_linear_unorm_clamp_to_edge; + case PIPE_TEX_WRAP_CLAMP_TO_BORDER: + return wrap_linear_unorm_clamp_to_border; + default: + assert(0); + return wrap_linear_unorm_clamp; + } +} + + +static wrap_linear_func +get_linear_wrap(unsigned mode) +{ + switch (mode) { + case PIPE_TEX_WRAP_REPEAT: + return wrap_linear_repeat; + case PIPE_TEX_WRAP_CLAMP: + return wrap_linear_clamp; + case PIPE_TEX_WRAP_CLAMP_TO_EDGE: + return wrap_linear_clamp_to_edge; + case PIPE_TEX_WRAP_CLAMP_TO_BORDER: + return wrap_linear_clamp_to_border; + case PIPE_TEX_WRAP_MIRROR_REPEAT: + return wrap_linear_mirror_repeat; + case PIPE_TEX_WRAP_MIRROR_CLAMP: + return wrap_linear_mirror_clamp; + case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: + return wrap_linear_mirror_clamp_to_edge; + case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: + return wrap_linear_mirror_clamp_to_border; + default: + assert(0); + return wrap_linear_repeat; + } +} + + +static compute_lambda_func +get_lambda_func(const union sp_sampler_key key) +{ + if (key.bits.processor == TGSI_PROCESSOR_VERTEX) + return compute_lambda_vert; + + switch (key.bits.target) { + case PIPE_TEXTURE_1D: + return compute_lambda_1d; + case PIPE_TEXTURE_2D: + case PIPE_TEXTURE_CUBE: + return compute_lambda_2d; + case PIPE_TEXTURE_3D: + return compute_lambda_3d; + default: + assert(0); + return compute_lambda_1d; + } +} + + +static filter_func +get_img_filter(const union sp_sampler_key key, + unsigned filter, + const struct pipe_sampler_state *sampler) +{ + switch (key.bits.target) { + case PIPE_TEXTURE_1D: + if (filter == PIPE_TEX_FILTER_NEAREST) + return img_filter_1d_nearest; + else + return img_filter_1d_linear; + break; + case PIPE_TEXTURE_2D: + /* Try for fast path: + */ + if (key.bits.is_pot && + sampler->wrap_s == sampler->wrap_t && + sampler->normalized_coords) + { + switch (sampler->wrap_s) { + case PIPE_TEX_WRAP_REPEAT: + switch (filter) { + case PIPE_TEX_FILTER_NEAREST: + return img_filter_2d_nearest_repeat_POT; + case PIPE_TEX_FILTER_LINEAR: + return img_filter_2d_linear_repeat_POT; + default: + break; + } + break; + case PIPE_TEX_WRAP_CLAMP: + switch (filter) { + case PIPE_TEX_FILTER_NEAREST: + return img_filter_2d_nearest_clamp_POT; + default: + break; + } + } + } + /* Otherwise use default versions: + */ + if (filter == PIPE_TEX_FILTER_NEAREST) + return img_filter_2d_nearest; + else + return img_filter_2d_linear; + break; + case PIPE_TEXTURE_CUBE: + if (filter == PIPE_TEX_FILTER_NEAREST) + return img_filter_cube_nearest; + else + return img_filter_cube_linear; + break; + case PIPE_TEXTURE_3D: + if (filter == PIPE_TEX_FILTER_NEAREST) + return img_filter_3d_nearest; + else + return img_filter_3d_linear; + break; + default: + assert(0); + return img_filter_1d_nearest; + } +} + + +/** + * Bind the given texture object and texture cache to the sampler varient. + */ +void +sp_sampler_varient_bind_texture( struct sp_sampler_varient *samp, + struct softpipe_tex_tile_cache *tex_cache, + const struct pipe_resource *texture ) +{ + const struct pipe_sampler_state *sampler = samp->sampler; + + samp->texture = texture; + samp->cache = tex_cache; + samp->xpot = util_unsigned_logbase2( texture->width0 ); + samp->ypot = util_unsigned_logbase2( texture->height0 ); + samp->level = CLAMP((int) sampler->min_lod, 0, (int) texture->last_level); +} + + +void +sp_sampler_varient_destroy( struct sp_sampler_varient *samp ) +{ + FREE(samp); +} + + +/** + * Create a sampler varient for a given set of non-orthogonal state. + */ +struct sp_sampler_varient * +sp_create_sampler_varient( const struct pipe_sampler_state *sampler, + const union sp_sampler_key key ) +{ + struct sp_sampler_varient *samp = CALLOC_STRUCT(sp_sampler_varient); + if (!samp) + return NULL; + + samp->sampler = sampler; + samp->key = key; + + /* Note that (for instance) linear_texcoord_s and + * nearest_texcoord_s may be active at the same time, if the + * sampler min_img_filter differs from its mag_img_filter. + */ + if (sampler->normalized_coords) { + samp->linear_texcoord_s = get_linear_wrap( sampler->wrap_s ); + samp->linear_texcoord_t = get_linear_wrap( sampler->wrap_t ); + samp->linear_texcoord_p = get_linear_wrap( sampler->wrap_r ); + + samp->nearest_texcoord_s = get_nearest_wrap( sampler->wrap_s ); + samp->nearest_texcoord_t = get_nearest_wrap( sampler->wrap_t ); + samp->nearest_texcoord_p = get_nearest_wrap( sampler->wrap_r ); + } + else { + samp->linear_texcoord_s = get_linear_unorm_wrap( sampler->wrap_s ); + samp->linear_texcoord_t = get_linear_unorm_wrap( sampler->wrap_t ); + samp->linear_texcoord_p = get_linear_unorm_wrap( sampler->wrap_r ); + + samp->nearest_texcoord_s = get_nearest_unorm_wrap( sampler->wrap_s ); + samp->nearest_texcoord_t = get_nearest_unorm_wrap( sampler->wrap_t ); + samp->nearest_texcoord_p = get_nearest_unorm_wrap( sampler->wrap_r ); + } + + samp->compute_lambda = get_lambda_func( key ); + + samp->min_img_filter = get_img_filter(key, sampler->min_img_filter, sampler); + samp->mag_img_filter = get_img_filter(key, sampler->mag_img_filter, sampler); + + switch (sampler->min_mip_filter) { + case PIPE_TEX_MIPFILTER_NONE: + if (sampler->min_img_filter == sampler->mag_img_filter) + samp->mip_filter = samp->min_img_filter; + else + samp->mip_filter = mip_filter_none; + break; + + case PIPE_TEX_MIPFILTER_NEAREST: + samp->mip_filter = mip_filter_nearest; + break; + + case PIPE_TEX_MIPFILTER_LINEAR: + if (key.bits.is_pot && + sampler->min_img_filter == sampler->mag_img_filter && + sampler->normalized_coords && + sampler->wrap_s == PIPE_TEX_WRAP_REPEAT && + sampler->wrap_t == PIPE_TEX_WRAP_REPEAT && + sampler->min_img_filter == PIPE_TEX_FILTER_LINEAR) + { + samp->mip_filter = mip_filter_linear_2d_linear_repeat_POT; + } + else + { + samp->mip_filter = mip_filter_linear; + } + break; + } + + if (sampler->compare_mode != PIPE_TEX_COMPARE_NONE) { + samp->compare = sample_compare; + } + else { + /* Skip compare operation by promoting the mip_filter function + * pointer: + */ + samp->compare = samp->mip_filter; + } + + if (key.bits.target == PIPE_TEXTURE_CUBE) { + samp->base.get_samples = sample_cube; + } + else { + samp->faces[0] = 0; + samp->faces[1] = 0; + samp->faces[2] = 0; + samp->faces[3] = 0; + + /* Skip cube face determination by promoting the compare + * function pointer: + */ + samp->base.get_samples = samp->compare; + } + + return samp; +} diff --git a/src/gallium/drivers/softpipe/sp_tex_sample.h b/src/gallium/drivers/softpipe/sp_tex_sample.h new file mode 100644 index 0000000000..6114acf737 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_tex_sample.h @@ -0,0 +1,153 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * Copyright 2010 VMware, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef SP_TEX_SAMPLE_H +#define SP_TEX_SAMPLE_H + + +#include "tgsi/tgsi_exec.h" + +struct sp_sampler_varient; + +typedef void (*wrap_nearest_func)(const float s[4], + unsigned size, + int icoord[4]); + +typedef void (*wrap_linear_func)(const float s[4], + unsigned size, + int icoord0[4], + int icoord1[4], + float w[4]); + +typedef float (*compute_lambda_func)(const struct sp_sampler_varient *sampler, + const float s[QUAD_SIZE], + const float t[QUAD_SIZE], + const float p[QUAD_SIZE]); + +typedef void (*filter_func)(struct tgsi_sampler *tgsi_sampler, + const float s[QUAD_SIZE], + const float t[QUAD_SIZE], + const float p[QUAD_SIZE], + const float c0[QUAD_SIZE], + enum tgsi_sampler_control control, + float rgba[NUM_CHANNELS][QUAD_SIZE]); + + +union sp_sampler_key { + struct { + unsigned target:3; + unsigned is_pot:1; + unsigned processor:2; + unsigned unit:4; + unsigned pad:22; + } bits; + unsigned value; +}; + +/** + * Subclass of tgsi_sampler + */ +struct sp_sampler_varient +{ + struct tgsi_sampler base; /**< base class */ + + union sp_sampler_key key; + + /* The owner of this struct: + */ + const struct pipe_sampler_state *sampler; + + + /* Currently bound texture: + */ + const struct pipe_resource *texture; + struct softpipe_tex_tile_cache *cache; + + unsigned processor; + + /* For sp_get_samples_2d_linear_POT: + */ + unsigned xpot; + unsigned ypot; + unsigned level; + + unsigned faces[4]; + + wrap_nearest_func nearest_texcoord_s; + wrap_nearest_func nearest_texcoord_t; + wrap_nearest_func nearest_texcoord_p; + + wrap_linear_func linear_texcoord_s; + wrap_linear_func linear_texcoord_t; + wrap_linear_func linear_texcoord_p; + + filter_func min_img_filter; + filter_func mag_img_filter; + + compute_lambda_func compute_lambda; + + filter_func mip_filter; + filter_func compare; + + /* Linked list: + */ + struct sp_sampler_varient *next; +}; + +struct sp_sampler; + +/* Create a sampler varient for a given set of non-orthogonal state. Currently the + */ +struct sp_sampler_varient * +sp_create_sampler_varient( const struct pipe_sampler_state *sampler, + const union sp_sampler_key key ); + +void sp_sampler_varient_bind_texture( struct sp_sampler_varient *varient, + struct softpipe_tex_tile_cache *tex_cache, + const struct pipe_resource *tex ); + +void sp_sampler_varient_destroy( struct sp_sampler_varient * ); + + + +static INLINE struct sp_sampler_varient * +sp_sampler_varient(const struct tgsi_sampler *sampler) +{ + return (struct sp_sampler_varient *) sampler; +} + +extern void +sp_get_samples(struct tgsi_sampler *tgsi_sampler, + const float s[QUAD_SIZE], + const float t[QUAD_SIZE], + const float p[QUAD_SIZE], + float lodbias, + float rgba[NUM_CHANNELS][QUAD_SIZE]); + + +#endif /* SP_TEX_SAMPLE_H */ diff --git a/src/gallium/drivers/softpipe/sp_tex_tile_cache.c b/src/gallium/drivers/softpipe/sp_tex_tile_cache.c new file mode 100644 index 0000000000..b3e1c49406 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_tex_tile_cache.c @@ -0,0 +1,298 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/** + * Texture tile caching. + * + * Author: + * Brian Paul + */ + +#include "util/u_inlines.h" +#include "util/u_memory.h" +#include "util/u_tile.h" +#include "util/u_math.h" +#include "sp_context.h" +#include "sp_texture.h" +#include "sp_tex_tile_cache.h" + + + +struct softpipe_tex_tile_cache * +sp_create_tex_tile_cache( struct pipe_context *pipe ) +{ + struct softpipe_tex_tile_cache *tc; + uint pos; + + tc = CALLOC_STRUCT( softpipe_tex_tile_cache ); + if (tc) { + tc->pipe = pipe; + for (pos = 0; pos < NUM_ENTRIES; pos++) { + tc->entries[pos].addr.bits.invalid = 1; + } + tc->last_tile = &tc->entries[0]; /* any tile */ + } + return tc; +} + + +void +sp_destroy_tex_tile_cache(struct softpipe_tex_tile_cache *tc) +{ + uint pos; + + for (pos = 0; pos < NUM_ENTRIES; pos++) { + /*assert(tc->entries[pos].x < 0);*/ + } + if (tc->transfer) { + tc->pipe->transfer_destroy(tc->pipe, tc->transfer); + } + if (tc->tex_trans) { + tc->pipe->transfer_destroy(tc->pipe, tc->tex_trans); + } + + FREE( tc ); +} + + + + +void +sp_tex_tile_cache_map_transfers(struct softpipe_tex_tile_cache *tc) +{ + if (tc->tex_trans && !tc->tex_trans_map) + tc->tex_trans_map = tc->pipe->transfer_map(tc->pipe, tc->tex_trans); +} + + +void +sp_tex_tile_cache_unmap_transfers(struct softpipe_tex_tile_cache *tc) +{ + if (tc->tex_trans_map) { + tc->pipe->transfer_unmap(tc->pipe, tc->tex_trans); + tc->tex_trans_map = NULL; + } +} + +/** + * Invalidate all cached tiles for the cached texture. + * Should be called when the texture is modified. + */ +void +sp_tex_tile_cache_validate_texture(struct softpipe_tex_tile_cache *tc) +{ + unsigned i; + + assert(tc); + assert(tc->texture); + + for (i = 0; i < NUM_ENTRIES; i++) { + tc->entries[i].addr.bits.invalid = 1; + } +} + +static boolean +sp_tex_tile_is_compat_view(struct softpipe_tex_tile_cache *tc, + struct pipe_sampler_view *view) +{ + if (!view) + return FALSE; + return (tc->texture == view->texture && + tc->format == view->format && + tc->swizzle_r == view->swizzle_r && + tc->swizzle_g == view->swizzle_g && + tc->swizzle_b == view->swizzle_b && + tc->swizzle_a == view->swizzle_a); +} + +/** + * Specify the sampler view to cache. + */ +void +sp_tex_tile_cache_set_sampler_view(struct softpipe_tex_tile_cache *tc, + struct pipe_sampler_view *view) +{ + struct pipe_resource *texture = view ? view->texture : NULL; + uint i; + + assert(!tc->transfer); + + if (!sp_tex_tile_is_compat_view(tc, view)) { + pipe_resource_reference(&tc->texture, texture); + + if (tc->tex_trans) { + if (tc->tex_trans_map) { + tc->pipe->transfer_unmap(tc->pipe, tc->tex_trans); + tc->tex_trans_map = NULL; + } + + tc->pipe->transfer_destroy(tc->pipe, tc->tex_trans); + tc->tex_trans = NULL; + } + + if (view) { + tc->swizzle_r = view->swizzle_r; + tc->swizzle_g = view->swizzle_g; + tc->swizzle_b = view->swizzle_b; + tc->swizzle_a = view->swizzle_a; + tc->format = view->format; + } + + /* mark as entries as invalid/empty */ + /* XXX we should try to avoid this when the teximage hasn't changed */ + for (i = 0; i < NUM_ENTRIES; i++) { + tc->entries[i].addr.bits.invalid = 1; + } + + tc->tex_face = -1; /* any invalid value here */ + } +} + + + + +/** + * Flush the tile cache: write all dirty tiles back to the transfer. + * any tiles "flagged" as cleared will be "really" cleared. + */ +void +sp_flush_tex_tile_cache(struct softpipe_tex_tile_cache *tc) +{ + int pos; + + if (tc->texture) { + /* caching a texture, mark all entries as empty */ + for (pos = 0; pos < NUM_ENTRIES; pos++) { + tc->entries[pos].addr.bits.invalid = 1; + } + tc->tex_face = -1; + } + +} + + +/** + * Given the texture face, level, zslice, x and y values, compute + * the cache entry position/index where we'd hope to find the + * cached texture tile. + * This is basically a direct-map cache. + * XXX There's probably lots of ways in which we can improve this. + */ +static INLINE uint +tex_cache_pos( union tex_tile_address addr ) +{ + uint entry = (addr.bits.x + + addr.bits.y * 9 + + addr.bits.z * 3 + + addr.bits.face + + addr.bits.level * 7); + + return entry % NUM_ENTRIES; +} + +/** + * Similar to sp_get_cached_tile() but for textures. + * Tiles are read-only and indexed with more params. + */ +const struct softpipe_tex_cached_tile * +sp_find_cached_tile_tex(struct softpipe_tex_tile_cache *tc, + union tex_tile_address addr ) +{ + struct softpipe_tex_cached_tile *tile; + + tile = tc->entries + tex_cache_pos( addr ); + + if (addr.value != tile->addr.value) { + + /* cache miss. Most misses are because we've invaldiated the + * texture cache previously -- most commonly on binding a new + * texture. Currently we effectively flush the cache on texture + * bind. + */ +#if 0 + _debug_printf("miss at %u: x=%d y=%d z=%d face=%d level=%d\n" + " tile %u: x=%d y=%d z=%d face=%d level=%d\n", + pos, x/TILE_SIZE, y/TILE_SIZE, z, face, level, + pos, tile->addr.bits.x, tile->addr.bits.y, tile->z, tile->face, tile->level); +#endif + + /* check if we need to get a new transfer */ + if (!tc->tex_trans || + tc->tex_face != addr.bits.face || + tc->tex_level != addr.bits.level || + tc->tex_z != addr.bits.z) { + /* get new transfer (view into texture) */ + + if (tc->tex_trans) { + if (tc->tex_trans_map) { + tc->pipe->transfer_unmap(tc->pipe, tc->tex_trans); + tc->tex_trans_map = NULL; + } + + tc->pipe->transfer_destroy(tc->pipe, tc->tex_trans); + tc->tex_trans = NULL; + } + + tc->tex_trans = + pipe_get_transfer(tc->pipe, tc->texture, + addr.bits.face, + addr.bits.level, + addr.bits.z, + PIPE_TRANSFER_READ | PIPE_TRANSFER_UNSYNCHRONIZED, + 0, 0, + u_minify(tc->texture->width0, addr.bits.level), + u_minify(tc->texture->height0, addr.bits.level)); + + tc->tex_trans_map = tc->pipe->transfer_map(tc->pipe, tc->tex_trans); + + tc->tex_face = addr.bits.face; + tc->tex_level = addr.bits.level; + tc->tex_z = addr.bits.z; + } + + /* get tile from the transfer (view into texture) */ + pipe_get_tile_swizzle(tc->pipe, + tc->tex_trans, + addr.bits.x * TILE_SIZE, + addr.bits.y * TILE_SIZE, + TILE_SIZE, + TILE_SIZE, + tc->swizzle_r, + tc->swizzle_g, + tc->swizzle_b, + tc->swizzle_a, + tc->format, + (float *) tile->data.color); + tile->addr = addr; + } + + tc->last_tile = tile; + return tile; +} + + + diff --git a/src/gallium/drivers/softpipe/sp_tex_tile_cache.h b/src/gallium/drivers/softpipe/sp_tex_tile_cache.h new file mode 100644 index 0000000000..0794ffa0c5 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_tex_tile_cache.h @@ -0,0 +1,161 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef SP_TEX_TILE_CACHE_H +#define SP_TEX_TILE_CACHE_H + + +#include "pipe/p_compiler.h" + + +struct softpipe_context; +struct softpipe_tex_tile_cache; + + +/** + * Cache tile size (width and height). This needs to be a power of two. + */ +#define TILE_SIZE 64 + + +/* If we need to support > 4096, just expand this to be a 64 bit + * union, or consider tiling in Z as well. + */ +union tex_tile_address { + struct { + unsigned x:6; /* 4096 / TILE_SIZE */ + unsigned y:6; /* 4096 / TILE_SIZE */ + unsigned z:12; /* 4096 -- z not tiled */ + unsigned face:3; + unsigned level:4; + unsigned invalid:1; + } bits; + unsigned value; +}; + + +struct softpipe_tex_cached_tile +{ + union tex_tile_address addr; + union { + float color[TILE_SIZE][TILE_SIZE][4]; + } data; +}; + +#define NUM_ENTRIES 50 + +struct softpipe_tex_tile_cache +{ + struct pipe_context *pipe; + struct pipe_transfer *transfer; + void *transfer_map; + + struct pipe_resource *texture; /**< if caching a texture */ + unsigned timestamp; + + struct softpipe_tex_cached_tile entries[NUM_ENTRIES]; + + struct pipe_transfer *tex_trans; + void *tex_trans_map; + int tex_face, tex_level, tex_z; + + unsigned swizzle_r; + unsigned swizzle_g; + unsigned swizzle_b; + unsigned swizzle_a; + unsigned format; + + struct softpipe_tex_cached_tile *last_tile; /**< most recently retrieved tile */ +}; + + +extern struct softpipe_tex_tile_cache * +sp_create_tex_tile_cache( struct pipe_context *pipe ); + +extern void +sp_destroy_tex_tile_cache(struct softpipe_tex_tile_cache *tc); + + +extern void +sp_tex_tile_cache_map_transfers(struct softpipe_tex_tile_cache *tc); + +extern void +sp_tex_tile_cache_unmap_transfers(struct softpipe_tex_tile_cache *tc); + +extern void +sp_tex_tile_cache_set_sampler_view(struct softpipe_tex_tile_cache *tc, + struct pipe_sampler_view *view); + +void +sp_tex_tile_cache_validate_texture(struct softpipe_tex_tile_cache *tc); + +extern void +sp_flush_tex_tile_cache(struct softpipe_tex_tile_cache *tc); + + + +extern const struct softpipe_tex_cached_tile * +sp_find_cached_tile_tex(struct softpipe_tex_tile_cache *tc, + union tex_tile_address addr ); + +static INLINE union tex_tile_address +tex_tile_address( unsigned x, + unsigned y, + unsigned z, + unsigned face, + unsigned level ) +{ + union tex_tile_address addr; + + addr.value = 0; + addr.bits.x = x / TILE_SIZE; + addr.bits.y = y / TILE_SIZE; + addr.bits.z = z; + addr.bits.face = face; + addr.bits.level = level; + + return addr; +} + +/* Quickly retrieve tile if it matches last lookup. + */ +static INLINE const struct softpipe_tex_cached_tile * +sp_get_cached_tile_tex(struct softpipe_tex_tile_cache *tc, + union tex_tile_address addr ) +{ + if (tc->last_tile->addr.value == addr.value) + return tc->last_tile; + + return sp_find_cached_tile_tex( tc, addr ); +} + + + + + +#endif /* SP_TEX_TILE_CACHE_H */ + diff --git a/src/gallium/drivers/softpipe/sp_texture.c b/src/gallium/drivers/softpipe/sp_texture.c new file mode 100644 index 0000000000..4e6123fbd0 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_texture.c @@ -0,0 +1,488 @@ +/************************************************************************** + * + * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + /* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * Michel Dänzer <michel@tungstengraphics.com> + */ + +#include "pipe/p_defines.h" +#include "util/u_inlines.h" + +#include "util/u_format.h" +#include "util/u_math.h" +#include "util/u_memory.h" +#include "util/u_transfer.h" + +#include "sp_context.h" +#include "sp_flush.h" +#include "sp_texture.h" +#include "sp_screen.h" + +#include "state_tracker/sw_winsys.h" + + +/** + * Conventional allocation path for non-display textures: + * Use a simple, maximally packed layout. + */ +static boolean +softpipe_resource_layout(struct pipe_screen *screen, + struct softpipe_resource *spr) +{ + struct pipe_resource *pt = &spr->base; + unsigned level; + unsigned width = pt->width0; + unsigned height = pt->height0; + unsigned depth = pt->depth0; + unsigned buffer_size = 0; + + for (level = 0; level <= pt->last_level; level++) { + spr->stride[level] = util_format_get_stride(pt->format, width); + + spr->level_offset[level] = buffer_size; + + buffer_size += (util_format_get_nblocksy(pt->format, height) * + ((pt->target == PIPE_TEXTURE_CUBE) ? 6 : depth) * + spr->stride[level]); + + width = u_minify(width, 1); + height = u_minify(height, 1); + depth = u_minify(depth, 1); + } + + spr->data = align_malloc(buffer_size, 16); + + return spr->data != NULL; +} + + +/** + * Texture layout for simple color buffers. + */ +static boolean +softpipe_displaytarget_layout(struct pipe_screen *screen, + struct softpipe_resource *spr) +{ + struct sw_winsys *winsys = softpipe_screen(screen)->winsys; + + /* Round up the surface size to a multiple of the tile size? + */ + spr->dt = winsys->displaytarget_create(winsys, + spr->base.bind, + spr->base.format, + spr->base.width0, + spr->base.height0, + 16, + &spr->stride[0] ); + + return spr->dt != NULL; +} + + +/** + * Create new pipe_resource given the template information. + */ +static struct pipe_resource * +softpipe_resource_create(struct pipe_screen *screen, + const struct pipe_resource *templat) +{ + struct softpipe_resource *spr = CALLOC_STRUCT(softpipe_resource); + if (!spr) + return NULL; + + assert(templat->format != PIPE_FORMAT_NONE); + + spr->base = *templat; + pipe_reference_init(&spr->base.reference, 1); + spr->base.screen = screen; + + spr->pot = (util_is_power_of_two(templat->width0) && + util_is_power_of_two(templat->height0) && + util_is_power_of_two(templat->depth0)); + + if (spr->base.bind & (PIPE_BIND_DISPLAY_TARGET | + PIPE_BIND_SCANOUT | + PIPE_BIND_SHARED)) { + if (!softpipe_displaytarget_layout(screen, spr)) + goto fail; + } + else { + if (!softpipe_resource_layout(screen, spr)) + goto fail; + } + + return &spr->base; + + fail: + FREE(spr); + return NULL; +} + + +static void +softpipe_resource_destroy(struct pipe_screen *pscreen, + struct pipe_resource *pt) +{ + struct softpipe_screen *screen = softpipe_screen(pscreen); + struct softpipe_resource *spr = softpipe_resource(pt); + + if (spr->dt) { + /* display target */ + struct sw_winsys *winsys = screen->winsys; + winsys->displaytarget_destroy(winsys, spr->dt); + } + else if (!spr->userBuffer) { + /* regular texture */ + align_free(spr->data); + } + + FREE(spr); +} + + +static struct pipe_resource * +softpipe_resource_from_handle(struct pipe_screen *screen, + const struct pipe_resource *templat, + struct winsys_handle *whandle) +{ + struct sw_winsys *winsys = softpipe_screen(screen)->winsys; + struct softpipe_resource *spr = CALLOC_STRUCT(softpipe_resource); + if (!spr) + return NULL; + + spr->base = *templat; + pipe_reference_init(&spr->base.reference, 1); + spr->base.screen = screen; + + spr->pot = (util_is_power_of_two(templat->width0) && + util_is_power_of_two(templat->height0) && + util_is_power_of_two(templat->depth0)); + + spr->dt = winsys->displaytarget_from_handle(winsys, + templat, + whandle, + &spr->stride[0]); + if (!spr->dt) + goto fail; + + return &spr->base; + + fail: + FREE(spr); + return NULL; +} + + +static boolean +softpipe_resource_get_handle(struct pipe_screen *screen, + struct pipe_resource *pt, + struct winsys_handle *whandle) +{ + struct sw_winsys *winsys = softpipe_screen(screen)->winsys; + struct softpipe_resource *spr = softpipe_resource(pt); + + assert(spr->dt); + if (!spr->dt) + return FALSE; + + return winsys->displaytarget_get_handle(winsys, spr->dt, whandle); +} + + +/** + * Helper function to compute offset (in bytes) for a particular + * texture level/face/slice from the start of the buffer. + */ +static unsigned +sp_get_tex_image_offset(const struct softpipe_resource *spr, + unsigned level, unsigned face, unsigned zslice) +{ + const unsigned hgt = u_minify(spr->base.height0, level); + const unsigned nblocksy = util_format_get_nblocksy(spr->base.format, hgt); + unsigned offset = spr->level_offset[level]; + + if (spr->base.target == PIPE_TEXTURE_CUBE) { + assert(zslice == 0); + offset += face * nblocksy * spr->stride[level]; + } + else if (spr->base.target == PIPE_TEXTURE_3D) { + assert(face == 0); + offset += zslice * nblocksy * spr->stride[level]; + } + else { + assert(face == 0); + assert(zslice == 0); + } + + return offset; +} + + +/** + * Get a pipe_surface "view" into a texture resource. + */ +static struct pipe_surface * +softpipe_get_tex_surface(struct pipe_screen *screen, + struct pipe_resource *pt, + unsigned face, unsigned level, unsigned zslice, + unsigned usage) +{ + struct softpipe_resource *spr = softpipe_resource(pt); + struct pipe_surface *ps; + + assert(level <= pt->last_level); + + ps = CALLOC_STRUCT(pipe_surface); + if (ps) { + pipe_reference_init(&ps->reference, 1); + pipe_resource_reference(&ps->texture, pt); + ps->format = pt->format; + ps->width = u_minify(pt->width0, level); + ps->height = u_minify(pt->height0, level); + ps->offset = sp_get_tex_image_offset(spr, level, face, zslice); + ps->usage = usage; + + ps->face = face; + ps->level = level; + ps->zslice = zslice; + } + return ps; +} + + +/** + * Free a pipe_surface which was created with softpipe_get_tex_surface(). + */ +static void +softpipe_tex_surface_destroy(struct pipe_surface *surf) +{ + /* Effectively do the texture_update work here - if texture images + * needed post-processing to put them into hardware layout, this is + * where it would happen. For softpipe, nothing to do. + */ + assert(surf->texture); + pipe_resource_reference(&surf->texture, NULL); + FREE(surf); +} + + +/** + * Geta pipe_transfer object which is used for moving data in/out of + * a resource object. + * \param pipe rendering context + * \param resource the resource to transfer in/out of + * \param sr indicates cube face or 3D texture slice + * \param usage bitmask of PIPE_TRANSFER_x flags + * \param box the 1D/2D/3D region of interest + */ +static struct pipe_transfer * +softpipe_get_transfer(struct pipe_context *pipe, + struct pipe_resource *resource, + struct pipe_subresource sr, + unsigned usage, + const struct pipe_box *box) +{ + struct softpipe_resource *spr = softpipe_resource(resource); + struct softpipe_transfer *spt; + + assert(resource); + assert(sr.level <= resource->last_level); + + /* make sure the requested region is in the image bounds */ + assert(box->x + box->width <= u_minify(resource->width0, sr.level)); + assert(box->y + box->height <= u_minify(resource->height0, sr.level)); + assert(box->z + box->depth <= u_minify(resource->depth0, sr.level)); + + /* + * Transfers, like other pipe operations, must happen in order, so flush the + * context if necessary. + */ + if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) { + boolean read_only = !(usage & PIPE_TRANSFER_WRITE); + boolean do_not_block = !!(usage & PIPE_TRANSFER_DONTBLOCK); + if (!softpipe_flush_resource(pipe, resource, + sr.face, sr.level, + 0, /* flush_flags */ + read_only, + TRUE, /* cpu_access */ + do_not_block)) { + /* + * It would have blocked, but state tracker requested no to. + */ + assert(do_not_block); + return NULL; + } + } + + spt = CALLOC_STRUCT(softpipe_transfer); + if (spt) { + struct pipe_transfer *pt = &spt->base; + enum pipe_format format = resource->format; + const unsigned hgt = u_minify(spr->base.height0, sr.level); + const unsigned nblocksy = util_format_get_nblocksy(format, hgt); + + pipe_resource_reference(&pt->resource, resource); + pt->sr = sr; + pt->usage = usage; + pt->box = *box; + pt->stride = spr->stride[sr.level]; + pt->slice_stride = pt->stride * nblocksy; + + spt->offset = sp_get_tex_image_offset(spr, sr.level, sr.face, box->z); + + spt->offset += + box->y / util_format_get_blockheight(format) * spt->base.stride + + box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format); + + return pt; + } + return NULL; +} + + +/** + * Free a pipe_transfer object which was created with + * softpipe_get_transfer(). + */ +static void +softpipe_transfer_destroy(struct pipe_context *pipe, + struct pipe_transfer *transfer) +{ + pipe_resource_reference(&transfer->resource, NULL); + FREE(transfer); +} + + +/** + * Create memory mapping for given pipe_transfer object. + */ +static void * +softpipe_transfer_map(struct pipe_context *pipe, + struct pipe_transfer *transfer) +{ + struct softpipe_transfer *spt = softpipe_transfer(transfer); + struct softpipe_resource *spr = softpipe_resource(transfer->resource); + struct sw_winsys *winsys = softpipe_screen(pipe->screen)->winsys; + uint8_t *map; + + /* resources backed by display target treated specially: + */ + if (spr->dt) { + map = winsys->displaytarget_map(winsys, spr->dt, transfer->usage); + } + else { + map = spr->data; + } + + if (map == NULL) + return NULL; + else + return map + spt->offset; +} + + +/** + * Unmap memory mapping for given pipe_transfer object. + */ +static void +softpipe_transfer_unmap(struct pipe_context *pipe, + struct pipe_transfer *transfer) +{ + struct softpipe_resource *spr; + + assert(transfer->resource); + spr = softpipe_resource(transfer->resource); + + if (spr->dt) { + /* display target */ + struct sw_winsys *winsys = softpipe_screen(pipe->screen)->winsys; + winsys->displaytarget_unmap(winsys, spr->dt); + } + + if (transfer->usage & PIPE_TRANSFER_WRITE) { + /* Mark the texture as dirty to expire the tile caches. */ + spr->timestamp++; + } +} + +/** + * Create buffer which wraps user-space data. + */ +static struct pipe_resource * +softpipe_user_buffer_create(struct pipe_screen *screen, + void *ptr, + unsigned bytes, + unsigned bind_flags) +{ + struct softpipe_resource *spr; + + spr = CALLOC_STRUCT(softpipe_resource); + if (!spr) + return NULL; + + pipe_reference_init(&spr->base.reference, 1); + spr->base.screen = screen; + spr->base.format = PIPE_FORMAT_R8_UNORM; /* ?? */ + spr->base.bind = bind_flags; + spr->base.usage = PIPE_USAGE_IMMUTABLE; + spr->base.flags = 0; + spr->base.width0 = bytes; + spr->base.height0 = 1; + spr->base.depth0 = 1; + spr->userBuffer = TRUE; + spr->data = ptr; + + return &spr->base; +} + + +void +softpipe_init_texture_funcs(struct pipe_context *pipe) +{ + pipe->get_transfer = softpipe_get_transfer; + pipe->transfer_destroy = softpipe_transfer_destroy; + pipe->transfer_map = softpipe_transfer_map; + pipe->transfer_unmap = softpipe_transfer_unmap; + + pipe->transfer_flush_region = u_default_transfer_flush_region; + pipe->transfer_inline_write = u_default_transfer_inline_write; +} + + +void +softpipe_init_screen_texture_funcs(struct pipe_screen *screen) +{ + screen->resource_create = softpipe_resource_create; + screen->resource_destroy = softpipe_resource_destroy; + screen->resource_from_handle = softpipe_resource_from_handle; + screen->resource_get_handle = softpipe_resource_get_handle; + screen->user_buffer_create = softpipe_user_buffer_create; + + screen->get_tex_surface = softpipe_get_tex_surface; + screen->tex_surface_destroy = softpipe_tex_surface_destroy; +} diff --git a/src/gallium/drivers/softpipe/sp_texture.h b/src/gallium/drivers/softpipe/sp_texture.h new file mode 100644 index 0000000000..6b205dc532 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_texture.h @@ -0,0 +1,107 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef SP_TEXTURE_H +#define SP_TEXTURE_H + + +#include "pipe/p_state.h" + + +#define SP_MAX_TEXTURE_2D_LEVELS 13 /* 4K x 4K */ +#define SP_MAX_TEXTURE_3D_LEVELS 9 /* 512 x 512 x 512 */ + + +struct pipe_context; +struct pipe_screen; +struct softpipe_context; + + +/** + * Subclass of pipe_resource. + */ +struct softpipe_resource +{ + struct pipe_resource base; + + unsigned long level_offset[SP_MAX_TEXTURE_2D_LEVELS]; + unsigned stride[SP_MAX_TEXTURE_2D_LEVELS]; + + /** + * Display target, only valid for PIPE_TEXTURE_2D with the + * PIPE_BIND_DISPLAY_TARGET usage. + */ + struct sw_displaytarget *dt; + + /** + * Malloc'ed data for regular buffers and textures, or a mapping to dt above. + */ + void *data; + + /* True if texture images are power-of-two in all dimensions: + */ + boolean pot; + boolean userBuffer; + + unsigned timestamp; +}; + + +/** + * Subclass of pipe_transfer. + */ +struct softpipe_transfer +{ + struct pipe_transfer base; + + unsigned long offset; +}; + + + +/** cast wrappers */ +static INLINE struct softpipe_resource * +softpipe_resource(struct pipe_resource *pt) +{ + return (struct softpipe_resource *) pt; +} + +static INLINE struct softpipe_transfer * +softpipe_transfer(struct pipe_transfer *pt) +{ + return (struct softpipe_transfer *) pt; +} + + +extern void +softpipe_init_screen_texture_funcs(struct pipe_screen *screen); + +extern void +softpipe_init_texture_funcs(struct pipe_context *pipe); + + +#endif /* SP_TEXTURE */ diff --git a/src/gallium/drivers/softpipe/sp_tile_cache.c b/src/gallium/drivers/softpipe/sp_tile_cache.c new file mode 100644 index 0000000000..f4db6f6ef0 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_tile_cache.c @@ -0,0 +1,457 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/** + * Render target tile caching. + * + * Author: + * Brian Paul + */ + +#include "util/u_inlines.h" +#include "util/u_format.h" +#include "util/u_memory.h" +#include "util/u_tile.h" +#include "sp_tile_cache.h" + + + +/** + * Return the position in the cache for the tile that contains win pos (x,y). + * We currently use a direct mapped cache so this is like a hack key. + * At some point we should investige something more sophisticated, like + * a LRU replacement policy. + */ +#define CACHE_POS(x, y) \ + (((x) + (y) * 5) % NUM_ENTRIES) + + + +/** + * Is the tile at (x,y) in cleared state? + */ +static INLINE uint +is_clear_flag_set(const uint *bitvec, union tile_address addr) +{ + int pos, bit; + pos = addr.bits.y * (MAX_WIDTH / TILE_SIZE) + addr.bits.x; + assert(pos / 32 < (MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32); + bit = bitvec[pos / 32] & (1 << (pos & 31)); + return bit; +} + + +/** + * Mark the tile at (x,y) as not cleared. + */ +static INLINE void +clear_clear_flag(uint *bitvec, union tile_address addr) +{ + int pos; + pos = addr.bits.y * (MAX_WIDTH / TILE_SIZE) + addr.bits.x; + assert(pos / 32 < (MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32); + bitvec[pos / 32] &= ~(1 << (pos & 31)); +} + + +struct softpipe_tile_cache * +sp_create_tile_cache( struct pipe_context *pipe ) +{ + struct softpipe_tile_cache *tc; + uint pos; + int maxLevels, maxTexSize; + + /* sanity checking: max sure MAX_WIDTH/HEIGHT >= largest texture image */ + maxLevels = pipe->screen->get_param(pipe->screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS); + maxTexSize = 1 << (maxLevels - 1); + assert(MAX_WIDTH >= maxTexSize); + + tc = CALLOC_STRUCT( softpipe_tile_cache ); + if (tc) { + tc->pipe = pipe; + for (pos = 0; pos < NUM_ENTRIES; pos++) { + tc->entries[pos].addr.bits.invalid = 1; + } + tc->last_tile = &tc->entries[0]; /* any tile */ + + /* XXX this code prevents valgrind warnings about use of uninitialized + * memory in programs that don't clear the surface before rendering. + * However, it breaks clearing in other situations (such as in + * progs/tests/drawbuffers, see bug 24402). + */ +#if 0 + /* set flags to indicate all the tiles are cleared */ + memset(tc->clear_flags, 255, sizeof(tc->clear_flags)); +#endif + } + return tc; +} + + +void +sp_destroy_tile_cache(struct softpipe_tile_cache *tc) +{ + uint pos; + + for (pos = 0; pos < NUM_ENTRIES; pos++) { + /*assert(tc->entries[pos].x < 0);*/ + } + if (tc->transfer) { + tc->pipe->transfer_destroy(tc->pipe, tc->transfer); + } + + FREE( tc ); +} + + +/** + * Specify the surface to cache. + */ +void +sp_tile_cache_set_surface(struct softpipe_tile_cache *tc, + struct pipe_surface *ps) +{ + struct pipe_context *pipe = tc->pipe; + + if (tc->transfer) { + if (ps == tc->surface) + return; + + if (tc->transfer_map) { + pipe->transfer_unmap(pipe, tc->transfer); + tc->transfer_map = NULL; + } + + pipe->transfer_destroy(pipe, tc->transfer); + tc->transfer = NULL; + } + + tc->surface = ps; + + if (ps) { + tc->transfer = pipe_get_transfer(pipe, ps->texture, ps->face, + ps->level, ps->zslice, + PIPE_TRANSFER_READ_WRITE | + PIPE_TRANSFER_UNSYNCHRONIZED, + 0, 0, ps->width, ps->height); + + tc->depth_stencil = (ps->format == PIPE_FORMAT_Z24_UNORM_S8_USCALED || + ps->format == PIPE_FORMAT_Z24X8_UNORM || + ps->format == PIPE_FORMAT_S8_USCALED_Z24_UNORM || + ps->format == PIPE_FORMAT_X8Z24_UNORM || + ps->format == PIPE_FORMAT_Z16_UNORM || + ps->format == PIPE_FORMAT_Z32_UNORM || + ps->format == PIPE_FORMAT_S8_USCALED); + } +} + + +/** + * Return the transfer being cached. + */ +struct pipe_surface * +sp_tile_cache_get_surface(struct softpipe_tile_cache *tc) +{ + return tc->surface; +} + + +void +sp_tile_cache_map_transfers(struct softpipe_tile_cache *tc) +{ + if (tc->transfer && !tc->transfer_map) + tc->transfer_map = tc->pipe->transfer_map(tc->pipe, tc->transfer); +} + + +void +sp_tile_cache_unmap_transfers(struct softpipe_tile_cache *tc) +{ + if (tc->transfer_map) { + tc->pipe->transfer_unmap(tc->pipe, tc->transfer); + tc->transfer_map = NULL; + } +} + + +/** + * Set pixels in a tile to the given clear color/value, float. + */ +static void +clear_tile_rgba(struct softpipe_cached_tile *tile, + enum pipe_format format, + const float clear_value[4]) +{ + if (clear_value[0] == 0.0 && + clear_value[1] == 0.0 && + clear_value[2] == 0.0 && + clear_value[3] == 0.0) { + memset(tile->data.color, 0, sizeof(tile->data.color)); + } + else { + uint i, j; + for (i = 0; i < TILE_SIZE; i++) { + for (j = 0; j < TILE_SIZE; j++) { + tile->data.color[i][j][0] = clear_value[0]; + tile->data.color[i][j][1] = clear_value[1]; + tile->data.color[i][j][2] = clear_value[2]; + tile->data.color[i][j][3] = clear_value[3]; + } + } + } +} + + +/** + * Set a tile to a solid value/color. + */ +static void +clear_tile(struct softpipe_cached_tile *tile, + enum pipe_format format, + uint clear_value) +{ + uint i, j; + + switch (util_format_get_blocksize(format)) { + case 1: + memset(tile->data.any, clear_value, TILE_SIZE * TILE_SIZE); + break; + case 2: + if (clear_value == 0) { + memset(tile->data.any, 0, 2 * TILE_SIZE * TILE_SIZE); + } + else { + for (i = 0; i < TILE_SIZE; i++) { + for (j = 0; j < TILE_SIZE; j++) { + tile->data.depth16[i][j] = (ushort) clear_value; + } + } + } + break; + case 4: + if (clear_value == 0) { + memset(tile->data.any, 0, 4 * TILE_SIZE * TILE_SIZE); + } + else { + for (i = 0; i < TILE_SIZE; i++) { + for (j = 0; j < TILE_SIZE; j++) { + tile->data.color32[i][j] = clear_value; + } + } + } + break; + default: + assert(0); + } +} + + +/** + * Actually clear the tiles which were flagged as being in a clear state. + */ +static void +sp_tile_cache_flush_clear(struct softpipe_tile_cache *tc) +{ + struct pipe_transfer *pt = tc->transfer; + const uint w = tc->transfer->box.width; + const uint h = tc->transfer->box.height; + uint x, y; + uint numCleared = 0; + + assert(pt->resource); + /* clear the scratch tile to the clear value */ + clear_tile(&tc->tile, pt->resource->format, tc->clear_val); + + /* push the tile to all positions marked as clear */ + for (y = 0; y < h; y += TILE_SIZE) { + for (x = 0; x < w; x += TILE_SIZE) { + union tile_address addr = tile_address(x, y); + + if (is_clear_flag_set(tc->clear_flags, addr)) { + pipe_put_tile_raw(tc->pipe, + pt, + x, y, TILE_SIZE, TILE_SIZE, + tc->tile.data.color32, 0/*STRIDE*/); + + numCleared++; + } + } + } + + /* reset all clear flags to zero */ + memset(tc->clear_flags, 0, sizeof(tc->clear_flags)); + +#if 0 + debug_printf("num cleared: %u\n", numCleared); +#endif +} + + +/** + * Flush the tile cache: write all dirty tiles back to the transfer. + * any tiles "flagged" as cleared will be "really" cleared. + */ +void +sp_flush_tile_cache(struct softpipe_tile_cache *tc) +{ + struct pipe_transfer *pt = tc->transfer; + int inuse = 0, pos; + + if (pt) { + /* caching a drawing transfer */ + for (pos = 0; pos < NUM_ENTRIES; pos++) { + struct softpipe_cached_tile *tile = tc->entries + pos; + if (!tile->addr.bits.invalid) { + if (tc->depth_stencil) { + pipe_put_tile_raw(tc->pipe, pt, + tile->addr.bits.x * TILE_SIZE, + tile->addr.bits.y * TILE_SIZE, + TILE_SIZE, TILE_SIZE, + tile->data.depth32, 0/*STRIDE*/); + } + else { + pipe_put_tile_rgba(tc->pipe, pt, + tile->addr.bits.x * TILE_SIZE, + tile->addr.bits.y * TILE_SIZE, + TILE_SIZE, TILE_SIZE, + (float *) tile->data.color); + } + tile->addr.bits.invalid = 1; /* mark as empty */ + inuse++; + } + } + + sp_tile_cache_flush_clear(tc); + } + +#if 0 + debug_printf("flushed tiles in use: %d\n", inuse); +#endif +} + + +/** + * Get a tile from the cache. + * \param x, y position of tile, in pixels + */ +struct softpipe_cached_tile * +sp_find_cached_tile(struct softpipe_tile_cache *tc, + union tile_address addr ) +{ + struct pipe_transfer *pt = tc->transfer; + + /* cache pos/entry: */ + const int pos = CACHE_POS(addr.bits.x, + addr.bits.y); + struct softpipe_cached_tile *tile = tc->entries + pos; + + if (addr.value != tile->addr.value) { + + assert(pt->resource); + if (tile->addr.bits.invalid == 0) { + /* put dirty tile back in framebuffer */ + if (tc->depth_stencil) { + pipe_put_tile_raw(tc->pipe, pt, + tile->addr.bits.x * TILE_SIZE, + tile->addr.bits.y * TILE_SIZE, + TILE_SIZE, TILE_SIZE, + tile->data.depth32, 0/*STRIDE*/); + } + else { + pipe_put_tile_rgba(tc->pipe, pt, + tile->addr.bits.x * TILE_SIZE, + tile->addr.bits.y * TILE_SIZE, + TILE_SIZE, TILE_SIZE, + (float *) tile->data.color); + } + } + + tile->addr = addr; + + if (is_clear_flag_set(tc->clear_flags, addr)) { + /* don't get tile from framebuffer, just clear it */ + if (tc->depth_stencil) { + clear_tile(tile, pt->resource->format, tc->clear_val); + } + else { + clear_tile_rgba(tile, pt->resource->format, tc->clear_color); + } + clear_clear_flag(tc->clear_flags, addr); + } + else { + /* get new tile data from transfer */ + if (tc->depth_stencil) { + pipe_get_tile_raw(tc->pipe, pt, + tile->addr.bits.x * TILE_SIZE, + tile->addr.bits.y * TILE_SIZE, + TILE_SIZE, TILE_SIZE, + tile->data.depth32, 0/*STRIDE*/); + } + else { + pipe_get_tile_rgba(tc->pipe, pt, + tile->addr.bits.x * TILE_SIZE, + tile->addr.bits.y * TILE_SIZE, + TILE_SIZE, TILE_SIZE, + (float *) tile->data.color); + } + } + } + + tc->last_tile = tile; + return tile; +} + + + + + +/** + * When a whole surface is being cleared to a value we can avoid + * fetching tiles above. + * Save the color and set a 'clearflag' for each tile of the screen. + */ +void +sp_tile_cache_clear(struct softpipe_tile_cache *tc, const float *rgba, + uint clearValue) +{ + uint pos; + + tc->clear_color[0] = rgba[0]; + tc->clear_color[1] = rgba[1]; + tc->clear_color[2] = rgba[2]; + tc->clear_color[3] = rgba[3]; + + tc->clear_val = clearValue; + + /* set flags to indicate all the tiles are cleared */ + memset(tc->clear_flags, 255, sizeof(tc->clear_flags)); + + for (pos = 0; pos < NUM_ENTRIES; pos++) { + struct softpipe_cached_tile *tile = tc->entries + pos; + tile->addr.bits.invalid = 1; + } +} diff --git a/src/gallium/drivers/softpipe/sp_tile_cache.h b/src/gallium/drivers/softpipe/sp_tile_cache.h new file mode 100644 index 0000000000..e03d53eb24 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_tile_cache.h @@ -0,0 +1,160 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef SP_TILE_CACHE_H +#define SP_TILE_CACHE_H + + +#include "pipe/p_compiler.h" + + +struct softpipe_tile_cache; + + +/** + * Cache tile size (width and height). This needs to be a power of two. + */ +#define TILE_SIZE 64 + + +/* If we need to support > 4096, just expand this to be a 64 bit + * union, or consider tiling in Z as well. + */ +union tile_address { + struct { + unsigned x:6; /* 4096 / TILE_SIZE */ + unsigned y:6; /* 4096 / TILE_SIZE */ + unsigned invalid:1; + unsigned pad:19; + } bits; + unsigned value; +}; + + +struct softpipe_cached_tile +{ + union tile_address addr; + union { + float color[TILE_SIZE][TILE_SIZE][4]; + uint color32[TILE_SIZE][TILE_SIZE]; + uint depth32[TILE_SIZE][TILE_SIZE]; + ushort depth16[TILE_SIZE][TILE_SIZE]; + ubyte stencil8[TILE_SIZE][TILE_SIZE]; + ubyte any[1]; + } data; +}; + +#define NUM_ENTRIES 50 + + +/** XXX move these */ +#define MAX_WIDTH 4096 +#define MAX_HEIGHT 4096 + + +struct softpipe_tile_cache +{ + struct pipe_context *pipe; + struct pipe_surface *surface; /**< the surface we're caching */ + struct pipe_transfer *transfer; + void *transfer_map; + + struct softpipe_cached_tile entries[NUM_ENTRIES]; + uint clear_flags[(MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32]; + float clear_color[4]; /**< for color bufs */ + uint clear_val; /**< for z+stencil, or packed color clear value */ + boolean depth_stencil; /**< Is the surface a depth/stencil format? */ + + struct softpipe_cached_tile tile; /**< scratch tile for clears */ + + struct softpipe_cached_tile *last_tile; /**< most recently retrieved tile */ +}; + + +extern struct softpipe_tile_cache * +sp_create_tile_cache( struct pipe_context *pipe ); + +extern void +sp_destroy_tile_cache(struct softpipe_tile_cache *tc); + +extern void +sp_tile_cache_set_surface(struct softpipe_tile_cache *tc, + struct pipe_surface *sps); + +extern struct pipe_surface * +sp_tile_cache_get_surface(struct softpipe_tile_cache *tc); + +extern void +sp_tile_cache_map_transfers(struct softpipe_tile_cache *tc); + +extern void +sp_tile_cache_unmap_transfers(struct softpipe_tile_cache *tc); + +extern void +sp_flush_tile_cache(struct softpipe_tile_cache *tc); + +extern void +sp_tile_cache_clear(struct softpipe_tile_cache *tc, const float *rgba, + uint clearValue); + +extern struct softpipe_cached_tile * +sp_find_cached_tile(struct softpipe_tile_cache *tc, + union tile_address addr ); + + +static INLINE union tile_address +tile_address( unsigned x, + unsigned y ) +{ + union tile_address addr; + + addr.value = 0; + addr.bits.x = x / TILE_SIZE; + addr.bits.y = y / TILE_SIZE; + + return addr; +} + +/* Quickly retrieve tile if it matches last lookup. + */ +static INLINE struct softpipe_cached_tile * +sp_get_cached_tile(struct softpipe_tile_cache *tc, + int x, int y ) +{ + union tile_address addr = tile_address( x, y ); + + if (tc->last_tile->addr.value == addr.value) + return tc->last_tile; + + return sp_find_cached_tile( tc, addr ); +} + + + + +#endif /* SP_TILE_CACHE_H */ + |