summaryrefslogtreecommitdiff
path: root/src/gallium/drivers/softpipe
diff options
context:
space:
mode:
Diffstat (limited to 'src/gallium/drivers/softpipe')
-rw-r--r--src/gallium/drivers/softpipe/Makefile38
-rw-r--r--src/gallium/drivers/softpipe/SConscript40
-rw-r--r--src/gallium/drivers/softpipe/sp_clear.c84
-rw-r--r--src/gallium/drivers/softpipe/sp_clear.h42
-rw-r--r--src/gallium/drivers/softpipe/sp_context.c381
-rw-r--r--src/gallium/drivers/softpipe/sp_context.h199
-rw-r--r--src/gallium/drivers/softpipe/sp_draw_arrays.c298
-rw-r--r--src/gallium/drivers/softpipe/sp_fence.c70
-rw-r--r--src/gallium/drivers/softpipe/sp_fence.h40
-rw-r--r--src/gallium/drivers/softpipe/sp_flush.c177
-rw-r--r--src/gallium/drivers/softpipe/sp_flush.h50
-rw-r--r--src/gallium/drivers/softpipe/sp_fs.h54
-rw-r--r--src/gallium/drivers/softpipe/sp_fs_exec.c203
-rw-r--r--src/gallium/drivers/softpipe/sp_fs_sse.c243
-rw-r--r--src/gallium/drivers/softpipe/sp_prim_vbuf.c602
-rw-r--r--src/gallium/drivers/softpipe/sp_prim_vbuf.h38
-rw-r--r--src/gallium/drivers/softpipe/sp_public.h10
-rw-r--r--src/gallium/drivers/softpipe/sp_quad.h106
-rw-r--r--src/gallium/drivers/softpipe/sp_quad_blend.c1054
-rw-r--r--src/gallium/drivers/softpipe/sp_quad_depth_test.c889
-rw-r--r--src/gallium/drivers/softpipe/sp_quad_depth_test_tmp.h147
-rw-r--r--src/gallium/drivers/softpipe/sp_quad_fs.c175
-rw-r--r--src/gallium/drivers/softpipe/sp_quad_pipe.c68
-rw-r--r--src/gallium/drivers/softpipe/sp_quad_pipe.h72
-rw-r--r--src/gallium/drivers/softpipe/sp_quad_stipple.c81
-rw-r--r--src/gallium/drivers/softpipe/sp_query.c207
-rw-r--r--src/gallium/drivers/softpipe/sp_query.h43
-rw-r--r--src/gallium/drivers/softpipe/sp_screen.c330
-rw-r--r--src/gallium/drivers/softpipe/sp_screen.h62
-rw-r--r--src/gallium/drivers/softpipe/sp_setup.c1447
-rw-r--r--src/gallium/drivers/softpipe/sp_setup.h53
-rw-r--r--src/gallium/drivers/softpipe/sp_state.h300
-rw-r--r--src/gallium/drivers/softpipe/sp_state_blend.c120
-rw-r--r--src/gallium/drivers/softpipe/sp_state_clip.c79
-rw-r--r--src/gallium/drivers/softpipe/sp_state_derived.c281
-rw-r--r--src/gallium/drivers/softpipe/sp_state_fs.c266
-rw-r--r--src/gallium/drivers/softpipe/sp_state_rasterizer.c65
-rw-r--r--src/gallium/drivers/softpipe/sp_state_sampler.c416
-rw-r--r--src/gallium/drivers/softpipe/sp_state_so.c124
-rw-r--r--src/gallium/drivers/softpipe/sp_state_surface.c104
-rw-r--r--src/gallium/drivers/softpipe/sp_state_vertex.c90
-rw-r--r--src/gallium/drivers/softpipe/sp_surface.c38
-rw-r--r--src/gallium/drivers/softpipe/sp_surface.h42
-rw-r--r--src/gallium/drivers/softpipe/sp_tex_sample.c1986
-rw-r--r--src/gallium/drivers/softpipe/sp_tex_sample.h153
-rw-r--r--src/gallium/drivers/softpipe/sp_tex_tile_cache.c298
-rw-r--r--src/gallium/drivers/softpipe/sp_tex_tile_cache.h161
-rw-r--r--src/gallium/drivers/softpipe/sp_texture.c488
-rw-r--r--src/gallium/drivers/softpipe/sp_texture.h107
-rw-r--r--src/gallium/drivers/softpipe/sp_tile_cache.c457
-rw-r--r--src/gallium/drivers/softpipe/sp_tile_cache.h160
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 */
+