llvmpipe: Fork softpipe for experimentation with llvm.
authorJosé Fonseca <jfonseca@vmware.com>
Sun, 26 Jul 2009 22:44:38 +0000 (23:44 +0100)
committerJosé Fonseca <jfonseca@vmware.com>
Sat, 29 Aug 2009 08:21:15 +0000 (09:21 +0100)
57 files changed:
SConstruct
src/gallium/drivers/llvmpipe/Makefile [new file with mode: 0644]
src/gallium/drivers/llvmpipe/SConscript [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_clear.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_clear.h [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_context.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_context.h [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_draw_arrays.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_flush.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_flush.h [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_fs.h [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_fs_exec.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_fs_llvm.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_fs_sse.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_prim_setup.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_prim_setup.h [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_prim_vbuf.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_prim_vbuf.h [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_quad.h [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_quad_alpha_test.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_quad_blend.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_quad_bufloop.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_quad_colormask.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_quad_coverage.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_quad_depth_test.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_quad_earlyz.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_quad_fs.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_quad_occlusion.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_quad_output.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_quad_pipe.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_quad_pipe.h [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_quad_stencil.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_quad_stipple.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_query.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_query.h [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_screen.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_screen.h [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_setup.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_setup.h [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_state.h [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_state_blend.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_state_clip.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_state_derived.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_state_fs.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_state_rasterizer.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_state_sampler.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_state_surface.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_state_vertex.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_surface.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_surface.h [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_tex_sample.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_tex_sample.h [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_texture.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_texture.h [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_tile_cache.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_tile_cache.h [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_winsys.h [new file with mode: 0644]

index 59d05bc..e9baab0 100644 (file)
@@ -32,7 +32,7 @@ import common
 default_statetrackers = 'mesa'
 
 if common.default_platform in ('linux', 'freebsd', 'darwin'):
-       default_drivers = 'softpipe,failover,i915simple,trace,identity'
+       default_drivers = 'softpipe,failover,i915simple,trace,identity,llvmpipe'
        default_winsys = 'xlib'
 elif common.default_platform in ('winddk',):
        default_drivers = 'softpipe,i915simple,trace,identity'
@@ -46,7 +46,7 @@ common.AddOptions(opts)
 opts.Add(ListVariable('statetrackers', 'state trackers to build', default_statetrackers,
                      ['mesa', 'python', 'xorg']))
 opts.Add(ListVariable('drivers', 'pipe drivers to build', default_drivers,
-                     ['softpipe', 'failover', 'i915simple', 'i965simple', 'cell', 'trace', 'r300', 'identity']))
+                     ['softpipe', 'failover', 'i915simple', 'i965simple', 'cell', 'trace', 'r300', 'identity', 'llvmpipe']))
 opts.Add(ListVariable('winsys', 'winsys drivers to build', default_winsys,
                      ['xlib', 'intel', 'gdi', 'radeon']))
 
diff --git a/src/gallium/drivers/llvmpipe/Makefile b/src/gallium/drivers/llvmpipe/Makefile
new file mode 100644 (file)
index 0000000..c0c4306
--- /dev/null
@@ -0,0 +1,44 @@
+TOP = ../../../..
+include $(TOP)/configs/current
+
+LIBNAME = llvmpipe
+
+C_SOURCES = \
+       lp_fs_exec.c \
+       lp_fs_sse.c \
+       lp_fs_llvm.c \
+       lp_clear.c \
+       lp_flush.c \
+       lp_query.c \
+       lp_context.c \
+       lp_draw_arrays.c \
+       lp_prim_setup.c \
+       lp_prim_vbuf.c \
+       lp_quad_pipe.c \
+       lp_quad_alpha_test.c \
+       lp_quad_blend.c \
+       lp_quad_colormask.c \
+       lp_quad_coverage.c \
+       lp_quad_depth_test.c \
+       lp_quad_earlyz.c \
+       lp_quad_fs.c \
+       lp_quad_occlusion.c \
+       lp_quad_output.c \
+       lp_quad_stencil.c \
+       lp_quad_stipple.c \
+       lp_screen.c \
+        lp_setup.c \
+       lp_state_blend.c \
+       lp_state_clip.c \
+       lp_state_derived.c \
+       lp_state_fs.c \
+       lp_state_sampler.c \
+       lp_state_rasterizer.c \
+       lp_state_surface.c \
+       lp_state_vertex.c \
+       lp_texture.c \
+       lp_tex_sample.c \
+       lp_tile_cache.c \
+       lp_surface.c 
+
+include ../../Makefile.template
diff --git a/src/gallium/drivers/llvmpipe/SConscript b/src/gallium/drivers/llvmpipe/SConscript
new file mode 100644 (file)
index 0000000..f021549
--- /dev/null
@@ -0,0 +1,46 @@
+Import('*')
+
+env = env.Clone()
+
+llvmpipe = env.ConvenienceLibrary(
+       target = 'llvmpipe',
+       source = [
+               'lp_fs_exec.c',
+               'lp_fs_sse.c',
+               'lp_fs_llvm.c',
+               'lp_clear.c',
+               'lp_context.c',
+               'lp_draw_arrays.c',
+               'lp_flush.c',
+               'lp_prim_setup.c',
+               'lp_prim_vbuf.c',
+               'lp_setup.c',
+               'lp_quad_alpha_test.c',
+               'lp_quad_blend.c',
+               'lp_quad_pipe.c',
+               'lp_quad_colormask.c',
+               'lp_quad_coverage.c',
+               'lp_quad_depth_test.c',
+               'lp_quad_earlyz.c',
+               'lp_quad_fs.c',
+               'lp_quad_occlusion.c',
+               'lp_quad_output.c',
+               'lp_quad_stencil.c',
+               'lp_quad_stipple.c',
+               'lp_query.c',
+               'lp_screen.c',
+               'lp_state_blend.c',
+               'lp_state_clip.c',
+               'lp_state_derived.c',
+               'lp_state_fs.c',
+               'lp_state_rasterizer.c',
+               'lp_state_sampler.c',
+               'lp_state_surface.c',
+               'lp_state_vertex.c',
+               'lp_surface.c',
+               'lp_tex_sample.c',
+               'lp_texture.c',
+               'lp_tile_cache.c',
+       ])
+
+Export('softpipe')
\ No newline at end of file
diff --git a/src/gallium/drivers/llvmpipe/lp_clear.c b/src/gallium/drivers/llvmpipe/lp_clear.c
new file mode 100644 (file)
index 0000000..4a7ffde
--- /dev/null
@@ -0,0 +1,89 @@
+/**************************************************************************
+ * 
+ * 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 "lp_clear.h"
+#include "lp_context.h"
+#include "lp_surface.h"
+#include "lp_state.h"
+#include "lp_tile_cache.h"
+
+
+/**
+ * Clear the given buffers to the specified values.
+ * No masking, no scissor (clear entire buffer).
+ */
+void
+llvmpipe_clear(struct pipe_context *pipe, unsigned buffers, const float *rgba,
+               double depth, unsigned stencil)
+{
+   struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
+   unsigned cv;
+   uint i;
+
+   if (llvmpipe->no_rast)
+      return;
+
+#if 0
+   llvmpipe_update_derived(llvmpipe); /* not needed?? */
+#endif
+
+   if (buffers & PIPE_CLEAR_COLOR) {
+      for (i = 0; i < llvmpipe->framebuffer.nr_cbufs; i++) {
+         struct pipe_surface *ps = llvmpipe->framebuffer.cbufs[i];
+
+         util_pack_color(rgba, ps->format, &cv);
+         lp_tile_cache_clear(llvmpipe->cbuf_cache[i], rgba, cv);
+
+#if !TILE_CLEAR_OPTIMIZATION
+         /* non-cached surface */
+         pipe->surface_fill(pipe, ps, 0, 0, ps->width, ps->height, cv);
+#endif
+      }
+   }
+
+   if (buffers & PIPE_CLEAR_DEPTHSTENCIL) {
+      static const float zero[4] = { 0.0F, 0.0F, 0.0F, 0.0F };
+      struct pipe_surface *ps = llvmpipe->framebuffer.zsbuf;
+
+      cv = util_pack_z_stencil(ps->format, depth, stencil);
+      lp_tile_cache_clear(llvmpipe->zsbuf_cache, zero, cv);
+
+#if !TILE_CLEAR_OPTIMIZATION
+      /* non-cached surface */
+      pipe->surface_fill(pipe, ps, 0, 0, ps->width, ps->height, cv);
+#endif
+      }
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_clear.h b/src/gallium/drivers/llvmpipe/lp_clear.h
new file mode 100644 (file)
index 0000000..781a867
--- /dev/null
@@ -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:
+ *    Brian Paul
+ */
+
+#ifndef SP_CLEAR_H
+#define SP_CLEAR_H
+
+#include "pipe/p_state.h"
+struct pipe_context;
+
+extern void
+llvmpipe_clear(struct pipe_context *pipe, unsigned buffers, const float *rgba,
+               double depth, unsigned stencil);
+
+
+#endif /* SP_CLEAR_H */
diff --git a/src/gallium/drivers/llvmpipe/lp_context.c b/src/gallium/drivers/llvmpipe/lp_context.c
new file mode 100644 (file)
index 0000000..cad74d3
--- /dev/null
@@ -0,0 +1,317 @@
+/**************************************************************************
+ * 
+ * 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 "pipe/p_defines.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
+#include "lp_clear.h"
+#include "lp_context.h"
+#include "lp_flush.h"
+#include "lp_prim_setup.h"
+#include "lp_prim_vbuf.h"
+#include "lp_state.h"
+#include "lp_surface.h"
+#include "lp_tile_cache.h"
+#include "lp_texture.h"
+#include "lp_winsys.h"
+#include "lp_query.h"
+
+
+
+/**
+ * Map any drawing surfaces which aren't already mapped
+ */
+void
+llvmpipe_map_transfers(struct llvmpipe_context *lp)
+{
+   unsigned i;
+
+   for (i = 0; i < lp->framebuffer.nr_cbufs; i++) {
+      lp_tile_cache_map_transfers(lp->cbuf_cache[i]);
+   }
+
+   lp_tile_cache_map_transfers(lp->zsbuf_cache);
+}
+
+
+/**
+ * Unmap any mapped drawing surfaces
+ */
+void
+llvmpipe_unmap_transfers(struct llvmpipe_context *lp)
+{
+   uint i;
+
+   for (i = 0; i < lp->framebuffer.nr_cbufs; i++)
+      lp_flush_tile_cache(lp, lp->cbuf_cache[i]);
+   lp_flush_tile_cache(lp, lp->zsbuf_cache);
+
+   for (i = 0; i < lp->framebuffer.nr_cbufs; i++) {
+      lp_tile_cache_unmap_transfers(lp->cbuf_cache[i]);
+   }
+   lp_tile_cache_unmap_transfers(lp->zsbuf_cache);
+}
+
+
+static void llvmpipe_destroy( struct pipe_context *pipe )
+{
+   struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
+   uint i;
+
+   if (llvmpipe->draw)
+      draw_destroy( llvmpipe->draw );
+
+   for (i = 0; i < SP_NUM_QUAD_THREADS; i++) {
+      llvmpipe->quad[i].polygon_stipple->destroy( llvmpipe->quad[i].polygon_stipple );
+      llvmpipe->quad[i].earlyz->destroy( llvmpipe->quad[i].earlyz );
+      llvmpipe->quad[i].shade->destroy( llvmpipe->quad[i].shade );
+      llvmpipe->quad[i].alpha_test->destroy( llvmpipe->quad[i].alpha_test );
+      llvmpipe->quad[i].depth_test->destroy( llvmpipe->quad[i].depth_test );
+      llvmpipe->quad[i].stencil_test->destroy( llvmpipe->quad[i].stencil_test );
+      llvmpipe->quad[i].occlusion->destroy( llvmpipe->quad[i].occlusion );
+      llvmpipe->quad[i].coverage->destroy( llvmpipe->quad[i].coverage );
+      llvmpipe->quad[i].blend->destroy( llvmpipe->quad[i].blend );
+      llvmpipe->quad[i].colormask->destroy( llvmpipe->quad[i].colormask );
+      llvmpipe->quad[i].output->destroy( llvmpipe->quad[i].output );
+   }
+
+   for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++)
+      lp_destroy_tile_cache(llvmpipe->cbuf_cache[i]);
+   lp_destroy_tile_cache(llvmpipe->zsbuf_cache);
+
+   for (i = 0; i < PIPE_MAX_SAMPLERS; i++)
+      lp_destroy_tile_cache(llvmpipe->tex_cache[i]);
+
+   for (i = 0; i < Elements(llvmpipe->constants); i++) {
+      if (llvmpipe->constants[i].buffer) {
+         pipe_buffer_reference(&llvmpipe->constants[i].buffer, NULL);
+      }
+   }
+
+   FREE( llvmpipe );
+}
+
+static unsigned int
+llvmpipe_is_texture_referenced( struct pipe_context *pipe,
+                               struct pipe_texture *texture,
+                               unsigned face, unsigned level)
+{
+   struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
+   unsigned i;
+
+   if(llvmpipe->dirty_render_cache) {
+      for (i = 0; i < llvmpipe->framebuffer.nr_cbufs; i++) {
+         if(llvmpipe->framebuffer.cbufs[i] && 
+            llvmpipe->framebuffer.cbufs[i]->texture == texture)
+            return PIPE_REFERENCED_FOR_WRITE;
+      }
+      if(llvmpipe->framebuffer.zsbuf && 
+         llvmpipe->framebuffer.zsbuf->texture == texture)
+         return PIPE_REFERENCED_FOR_WRITE;
+   }
+   
+   /* FIXME: we also need to do the same for the texture cache */
+   
+   return PIPE_UNREFERENCED;
+}
+
+static unsigned int
+llvmpipe_is_buffer_referenced( struct pipe_context *pipe,
+                              struct pipe_buffer *buf)
+{
+   return PIPE_UNREFERENCED;
+}
+
+struct pipe_context *
+llvmpipe_create( struct pipe_screen *screen )
+{
+   struct llvmpipe_context *llvmpipe = CALLOC_STRUCT(llvmpipe_context);
+   uint i;
+
+   util_init_math();
+
+#ifdef PIPE_ARCH_X86
+   llvmpipe->use_sse = !debug_get_bool_option( "GALLIUM_NOSSE", FALSE );
+#else
+   llvmpipe->use_sse = FALSE;
+#endif
+
+   llvmpipe->dump_fs = debug_get_bool_option( "GALLIUM_DUMP_FS", FALSE );
+
+   llvmpipe->pipe.winsys = screen->winsys;
+   llvmpipe->pipe.screen = screen;
+   llvmpipe->pipe.destroy = llvmpipe_destroy;
+
+   /* state setters */
+   llvmpipe->pipe.create_blend_state = llvmpipe_create_blend_state;
+   llvmpipe->pipe.bind_blend_state   = llvmpipe_bind_blend_state;
+   llvmpipe->pipe.delete_blend_state = llvmpipe_delete_blend_state;
+
+   llvmpipe->pipe.create_sampler_state = llvmpipe_create_sampler_state;
+   llvmpipe->pipe.bind_sampler_states  = llvmpipe_bind_sampler_states;
+   llvmpipe->pipe.delete_sampler_state = llvmpipe_delete_sampler_state;
+
+   llvmpipe->pipe.create_depth_stencil_alpha_state = llvmpipe_create_depth_stencil_state;
+   llvmpipe->pipe.bind_depth_stencil_alpha_state   = llvmpipe_bind_depth_stencil_state;
+   llvmpipe->pipe.delete_depth_stencil_alpha_state = llvmpipe_delete_depth_stencil_state;
+
+   llvmpipe->pipe.create_rasterizer_state = llvmpipe_create_rasterizer_state;
+   llvmpipe->pipe.bind_rasterizer_state   = llvmpipe_bind_rasterizer_state;
+   llvmpipe->pipe.delete_rasterizer_state = llvmpipe_delete_rasterizer_state;
+
+   llvmpipe->pipe.create_fs_state = llvmpipe_create_fs_state;
+   llvmpipe->pipe.bind_fs_state   = llvmpipe_bind_fs_state;
+   llvmpipe->pipe.delete_fs_state = llvmpipe_delete_fs_state;
+
+   llvmpipe->pipe.create_vs_state = llvmpipe_create_vs_state;
+   llvmpipe->pipe.bind_vs_state   = llvmpipe_bind_vs_state;
+   llvmpipe->pipe.delete_vs_state = llvmpipe_delete_vs_state;
+
+   llvmpipe->pipe.set_blend_color = llvmpipe_set_blend_color;
+   llvmpipe->pipe.set_clip_state = llvmpipe_set_clip_state;
+   llvmpipe->pipe.set_constant_buffer = llvmpipe_set_constant_buffer;
+   llvmpipe->pipe.set_framebuffer_state = llvmpipe_set_framebuffer_state;
+   llvmpipe->pipe.set_polygon_stipple = llvmpipe_set_polygon_stipple;
+   llvmpipe->pipe.set_scissor_state = llvmpipe_set_scissor_state;
+   llvmpipe->pipe.set_sampler_textures = llvmpipe_set_sampler_textures;
+   llvmpipe->pipe.set_viewport_state = llvmpipe_set_viewport_state;
+
+   llvmpipe->pipe.set_vertex_buffers = llvmpipe_set_vertex_buffers;
+   llvmpipe->pipe.set_vertex_elements = llvmpipe_set_vertex_elements;
+
+   llvmpipe->pipe.draw_arrays = llvmpipe_draw_arrays;
+   llvmpipe->pipe.draw_elements = llvmpipe_draw_elements;
+   llvmpipe->pipe.draw_range_elements = llvmpipe_draw_range_elements;
+   llvmpipe->pipe.set_edgeflags = llvmpipe_set_edgeflags;
+
+
+   llvmpipe->pipe.clear = llvmpipe_clear;
+   llvmpipe->pipe.flush = llvmpipe_flush;
+
+   llvmpipe->pipe.is_texture_referenced = llvmpipe_is_texture_referenced;
+   llvmpipe->pipe.is_buffer_referenced = llvmpipe_is_buffer_referenced;
+
+   llvmpipe_init_query_funcs( llvmpipe );
+   llvmpipe_init_texture_funcs( llvmpipe );
+
+   /*
+    * Alloc caches for accessing drawing surfaces and textures.
+    * Must be before quad stage setup!
+    */
+   for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++)
+      llvmpipe->cbuf_cache[i] = lp_create_tile_cache( screen );
+   llvmpipe->zsbuf_cache = lp_create_tile_cache( screen );
+
+   for (i = 0; i < PIPE_MAX_SAMPLERS; i++)
+      llvmpipe->tex_cache[i] = lp_create_tile_cache( screen );
+
+
+   /* setup quad rendering stages */
+   for (i = 0; i < SP_NUM_QUAD_THREADS; i++) {
+      llvmpipe->quad[i].polygon_stipple = lp_quad_polygon_stipple_stage(llvmpipe);
+      llvmpipe->quad[i].earlyz = lp_quad_earlyz_stage(llvmpipe);
+      llvmpipe->quad[i].shade = lp_quad_shade_stage(llvmpipe);
+      llvmpipe->quad[i].alpha_test = lp_quad_alpha_test_stage(llvmpipe);
+      llvmpipe->quad[i].depth_test = lp_quad_depth_test_stage(llvmpipe);
+      llvmpipe->quad[i].stencil_test = lp_quad_stencil_test_stage(llvmpipe);
+      llvmpipe->quad[i].occlusion = lp_quad_occlusion_stage(llvmpipe);
+      llvmpipe->quad[i].coverage = lp_quad_coverage_stage(llvmpipe);
+      llvmpipe->quad[i].blend = lp_quad_blend_stage(llvmpipe);
+      llvmpipe->quad[i].colormask = lp_quad_colormask_stage(llvmpipe);
+      llvmpipe->quad[i].output = lp_quad_output_stage(llvmpipe);
+   }
+
+   /* vertex shader samplers */
+   for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
+      llvmpipe->tgsi.vert_samplers[i].base.get_samples = lp_get_samples_vertex;
+      llvmpipe->tgsi.vert_samplers[i].unit = i;
+      llvmpipe->tgsi.vert_samplers[i].lp = llvmpipe;
+      llvmpipe->tgsi.vert_samplers[i].cache = llvmpipe->tex_cache[i];
+      llvmpipe->tgsi.vert_samplers_list[i] = &llvmpipe->tgsi.vert_samplers[i];
+   }
+
+   /* fragment shader samplers */
+   for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
+      llvmpipe->tgsi.frag_samplers[i].base.get_samples = lp_get_samples_fragment;
+      llvmpipe->tgsi.frag_samplers[i].unit = i;
+      llvmpipe->tgsi.frag_samplers[i].lp = llvmpipe;
+      llvmpipe->tgsi.frag_samplers[i].cache = llvmpipe->tex_cache[i];
+      llvmpipe->tgsi.frag_samplers_list[i] = &llvmpipe->tgsi.frag_samplers[i];
+   }
+
+   /*
+    * Create drawing context and plug our rendering stage into it.
+    */
+   llvmpipe->draw = draw_create();
+   if (!llvmpipe->draw) 
+      goto fail;
+
+   draw_texture_samplers(llvmpipe->draw,
+                         PIPE_MAX_SAMPLERS,
+                         (struct tgsi_sampler **)
+                            llvmpipe->tgsi.vert_samplers_list);
+
+   llvmpipe->setup = lp_draw_render_stage(llvmpipe);
+   if (!llvmpipe->setup)
+      goto fail;
+
+   if (debug_get_bool_option( "SP_NO_RAST", FALSE ))
+      llvmpipe->no_rast = TRUE;
+
+   if (debug_get_bool_option( "SP_NO_VBUF", FALSE )) {
+      /* Deprecated path -- vbuf is the intended interface to the draw module:
+       */
+      draw_set_rasterize_stage(llvmpipe->draw, llvmpipe->setup);
+   }
+   else {
+      lp_init_vbuf(llvmpipe);
+   }
+
+   /* plug in AA line/point stages */
+   draw_install_aaline_stage(llvmpipe->draw, &llvmpipe->pipe);
+   draw_install_aapoint_stage(llvmpipe->draw, &llvmpipe->pipe);
+
+#if USE_DRAW_STAGE_PSTIPPLE
+   /* Do polygon stipple w/ texture map + frag prog? */
+   draw_install_pstipple_stage(llvmpipe->draw, &llvmpipe->pipe);
+#endif
+
+   lp_init_surface_functions(llvmpipe);
+
+   return &llvmpipe->pipe;
+
+ fail:
+   llvmpipe_destroy(&llvmpipe->pipe);
+   return NULL;
+}
+
diff --git a/src/gallium/drivers/llvmpipe/lp_context.h b/src/gallium/drivers/llvmpipe/lp_context.h
new file mode 100644 (file)
index 0000000..32b1925
--- /dev/null
@@ -0,0 +1,168 @@
+/**************************************************************************
+ * 
+ * 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 "lp_quad_pipe.h"
+#include "lp_tex_sample.h"
+
+
+/**
+ * This is a temporary variable for testing draw-stage polygon stipple.
+ * If zero, do stipple in lp_quad_stipple.c
+ */
+#define USE_DRAW_STAGE_PSTIPPLE 1
+
+/* Number of threads working on individual quads.
+ * Setting to 1 disables this feature.
+ */
+#define SP_NUM_QUAD_THREADS 1
+
+struct llvmpipe_vbuf_render;
+struct draw_context;
+struct draw_stage;
+struct llvmpipe_tile_cache;
+struct lp_fragment_shader;
+struct lp_vertex_shader;
+
+
+struct llvmpipe_context {
+   struct pipe_context pipe;  /**< base class */
+
+   /** Constant state objects */
+   const struct pipe_blend_state *blend;
+   const struct pipe_sampler_state *sampler[PIPE_MAX_SAMPLERS];
+   const struct pipe_depth_stencil_alpha_state *depth_stencil;
+   const struct pipe_rasterizer_state *rasterizer;
+   const struct lp_fragment_shader *fs;
+   const struct lp_vertex_shader *vs;
+
+   /** Other rendering state */
+   struct pipe_blend_color blend_color;
+   struct pipe_clip_state clip;
+   struct pipe_constant_buffer constants[PIPE_SHADER_TYPES];
+   struct pipe_framebuffer_state framebuffer;
+   struct pipe_poly_stipple poly_stipple;
+   struct pipe_scissor_state scissor;
+   struct pipe_texture *texture[PIPE_MAX_SAMPLERS];
+   struct pipe_viewport_state viewport;
+   struct pipe_vertex_buffer vertex_buffer[PIPE_MAX_ATTRIBS];
+   struct pipe_vertex_element vertex_element[PIPE_MAX_ATTRIBS];
+
+   unsigned num_samplers;
+   unsigned num_textures;
+   unsigned num_vertex_elements;
+   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 */
+   void *mapped_constants[PIPE_SHADER_TYPES];
+
+   /** Vertex format */
+   struct vertex_info vertex_info;
+   struct vertex_info vertex_info_vbuf;
+
+   /** Which vertex shader output slot contains point size */
+   int psize_slot;
+
+   unsigned reduced_api_prim;  /**< PIPE_PRIM_POINTS, _LINES or _TRIANGLES */
+
+   /** Derived from scissor and surface bounds: */
+   struct pipe_scissor_state cliprect;
+
+   unsigned line_stipple_counter;
+
+   /** Software quad rendering pipeline */
+   struct {
+      struct quad_stage *polygon_stipple;
+      struct quad_stage *earlyz;
+      struct quad_stage *shade;
+      struct quad_stage *alpha_test;
+      struct quad_stage *stencil_test;
+      struct quad_stage *depth_test;
+      struct quad_stage *occlusion;
+      struct quad_stage *coverage;
+      struct quad_stage *blend;
+      struct quad_stage *colormask;
+      struct quad_stage *output;
+
+      struct quad_stage *first; /**< points to one of the above stages */
+   } quad[SP_NUM_QUAD_THREADS];
+
+   /** TGSI exec things */
+   struct {
+      struct lp_shader_sampler vert_samplers[PIPE_MAX_SAMPLERS];
+      struct lp_shader_sampler *vert_samplers_list[PIPE_MAX_SAMPLERS];
+      struct lp_shader_sampler frag_samplers[PIPE_MAX_SAMPLERS];
+      struct lp_shader_sampler *frag_samplers_list[PIPE_MAX_SAMPLERS];
+   } tgsi;
+
+   /** The primitive drawing context */
+   struct draw_context *draw;
+   struct draw_stage *setup;
+   struct draw_stage *vbuf;
+   struct llvmpipe_vbuf_render *vbuf_render;
+
+   boolean dirty_render_cache;
+   
+   struct llvmpipe_tile_cache *cbuf_cache[PIPE_MAX_COLOR_BUFS];
+   struct llvmpipe_tile_cache *zsbuf_cache;
+
+   struct llvmpipe_tile_cache *tex_cache[PIPE_MAX_SAMPLERS];
+
+   unsigned use_sse : 1;
+   unsigned dump_fs : 1;
+   unsigned no_rast : 1;
+};
+
+
+static INLINE struct llvmpipe_context *
+llvmpipe_context( struct pipe_context *pipe )
+{
+   return (struct llvmpipe_context *)pipe;
+}
+
+#endif /* SP_CONTEXT_H */
+
diff --git a/src/gallium/drivers/llvmpipe/lp_draw_arrays.c b/src/gallium/drivers/llvmpipe/lp_draw_arrays.c
new file mode 100644 (file)
index 0000000..87e8623
--- /dev/null
@@ -0,0 +1,194 @@
+/**************************************************************************
+ * 
+ * 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 "pipe/internal/p_winsys_screen.h"
+#include "pipe/p_inlines.h"
+#include "util/u_prim.h"
+
+#include "lp_context.h"
+#include "lp_state.h"
+
+#include "draw/draw_context.h"
+
+
+
+static void
+llvmpipe_map_constant_buffers(struct llvmpipe_context *lp)
+{
+   struct pipe_winsys *ws = lp->pipe.winsys;
+   uint i, size;
+
+   for (i = 0; i < PIPE_SHADER_TYPES; i++) {
+      if (lp->constants[i].buffer && lp->constants[i].buffer->size)
+         lp->mapped_constants[i] = ws->buffer_map(ws, lp->constants[i].buffer,
+                                                  PIPE_BUFFER_USAGE_CPU_READ);
+   }
+
+   if (lp->constants[PIPE_SHADER_VERTEX].buffer)
+      size = lp->constants[PIPE_SHADER_VERTEX].buffer->size;
+   else
+      size = 0;
+
+   draw_set_mapped_constant_buffer(lp->draw,
+                                   lp->mapped_constants[PIPE_SHADER_VERTEX],
+                                   size);
+}
+
+
+static void
+llvmpipe_unmap_constant_buffers(struct llvmpipe_context *lp)
+{
+   struct pipe_winsys *ws = lp->pipe.winsys;
+   uint i;
+
+   /* really need to flush all prims since the vert/frag shaders const buffers
+    * are going away now.
+    */
+   draw_flush(lp->draw);
+
+   draw_set_mapped_constant_buffer(lp->draw, NULL, 0);
+
+   for (i = 0; i < 2; i++) {
+      if (lp->constants[i].buffer && lp->constants[i].buffer->size)
+         ws->buffer_unmap(ws, lp->constants[i].buffer);
+      lp->mapped_constants[i] = NULL;
+   }
+}
+
+
+boolean
+llvmpipe_draw_arrays(struct pipe_context *pipe, unsigned mode,
+                     unsigned start, unsigned count)
+{
+   return llvmpipe_draw_elements(pipe, NULL, 0, mode, start, count);
+}
+
+
+/**
+ * Draw vertex arrays, with optional indexing.
+ * Basically, map the vertex buffers (and drawing surfaces), then hand off
+ * the drawing to the 'draw' module.
+ */
+boolean
+llvmpipe_draw_range_elements(struct pipe_context *pipe,
+                             struct pipe_buffer *indexBuffer,
+                             unsigned indexSize,
+                             unsigned min_index,
+                             unsigned max_index,
+                             unsigned mode, unsigned start, unsigned count)
+{
+   struct llvmpipe_context *lp = llvmpipe_context(pipe);
+   struct draw_context *draw = lp->draw;
+   unsigned i;
+
+   lp->reduced_api_prim = u_reduced_prim(mode);
+
+   if (lp->dirty)
+      llvmpipe_update_derived( lp );
+
+   llvmpipe_map_transfers(lp);
+   llvmpipe_map_constant_buffers(lp);
+
+   /*
+    * Map vertex buffers
+    */
+   for (i = 0; i < lp->num_vertex_buffers; i++) {
+      void *buf
+         = pipe_buffer_map(pipe->screen,
+                                    lp->vertex_buffer[i].buffer,
+                                    PIPE_BUFFER_USAGE_CPU_READ);
+      draw_set_mapped_vertex_buffer(draw, i, buf);
+   }
+
+   /* Map index buffer, if present */
+   if (indexBuffer) {
+      void *mapped_indexes
+         = pipe_buffer_map(pipe->screen, indexBuffer,
+                                    PIPE_BUFFER_USAGE_CPU_READ);
+      draw_set_mapped_element_buffer_range(draw, indexSize,
+                                           min_index,
+                                           max_index,
+                                           mapped_indexes);
+   }
+   else {
+      /* no index/element buffer */
+      draw_set_mapped_element_buffer_range(draw, 0, start,
+                                           start + count - 1, NULL);
+   }
+
+   /* draw! */
+   draw_arrays(draw, mode, start, count);
+
+   /*
+    * unmap vertex/index buffers - will cause draw module to flush
+    */
+   for (i = 0; i < lp->num_vertex_buffers; i++) {
+      draw_set_mapped_vertex_buffer(draw, i, NULL);
+      pipe_buffer_unmap(pipe->screen, lp->vertex_buffer[i].buffer);
+   }
+   if (indexBuffer) {
+      draw_set_mapped_element_buffer(draw, 0, NULL);
+      pipe_buffer_unmap(pipe->screen, indexBuffer);
+   }
+
+
+   /* Note: leave drawing surfaces mapped */
+   llvmpipe_unmap_constant_buffers(lp);
+
+   lp->dirty_render_cache = TRUE;
+   
+   return TRUE;
+}
+
+
+boolean
+llvmpipe_draw_elements(struct pipe_context *pipe,
+                       struct pipe_buffer *indexBuffer,
+                       unsigned indexSize,
+                       unsigned mode, unsigned start, unsigned count)
+{
+   return llvmpipe_draw_range_elements( pipe, indexBuffer,
+                                        indexSize,
+                                        0, 0xffffffff,
+                                        mode, start, count );
+}
+
+
+void
+llvmpipe_set_edgeflags(struct pipe_context *pipe, const unsigned *edgeflags)
+{
+   struct llvmpipe_context *lp = llvmpipe_context(pipe);
+   draw_set_edgeflags(lp->draw, edgeflags);
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_flush.c b/src/gallium/drivers/llvmpipe/lp_flush.c
new file mode 100644 (file)
index 0000000..2bb6414
--- /dev/null
@@ -0,0 +1,94 @@
+/**************************************************************************
+ * 
+ * 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 "lp_flush.h"
+#include "lp_context.h"
+#include "lp_surface.h"
+#include "lp_state.h"
+#include "lp_tile_cache.h"
+#include "lp_winsys.h"
+
+
+void
+llvmpipe_flush( struct pipe_context *pipe,
+               unsigned flags,
+                struct pipe_fence_handle **fence )
+{
+   struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
+   uint i;
+
+   draw_flush(llvmpipe->draw);
+
+   if (flags & PIPE_FLUSH_TEXTURE_CACHE) {
+      for (i = 0; i < llvmpipe->num_textures; i++) {
+         lp_flush_tile_cache(llvmpipe, llvmpipe->tex_cache[i]);
+      }
+   }
+
+   if (flags & PIPE_FLUSH_RENDER_CACHE) {
+      for (i = 0; i < llvmpipe->framebuffer.nr_cbufs; i++)
+         if (llvmpipe->cbuf_cache[i])
+            lp_flush_tile_cache(llvmpipe, llvmpipe->cbuf_cache[i]);
+
+      if (llvmpipe->zsbuf_cache)
+         lp_flush_tile_cache(llvmpipe, llvmpipe->zsbuf_cache);
+
+      /* 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.
+       */
+      llvmpipe_unmap_transfers(llvmpipe);
+      
+      llvmpipe->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(filename, llvmpipe->framebuffer.cbufs[0]);
+      util_snprintf(filename, sizeof(filename), "zsbuf_%u.bmp", frame_no);
+      debug_dump_surface_bmp(filename, llvmpipe->framebuffer.zsbuf);
+      ++frame_no;
+   }
+#endif
+   
+   if (fence)
+      *fence = NULL;
+}
+
diff --git a/src/gallium/drivers/llvmpipe/lp_flush.h b/src/gallium/drivers/llvmpipe/lp_flush.h
new file mode 100644 (file)
index 0000000..787bc5f
--- /dev/null
@@ -0,0 +1,37 @@
+/**************************************************************************
+ * 
+ * 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
+
+struct pipe_context;
+struct pipe_fence_handle;
+
+void llvmpipe_flush(struct pipe_context *pipe, unsigned flags,
+                    struct pipe_fence_handle **fence);
+
+#endif
diff --git a/src/gallium/drivers/llvmpipe/lp_fs.h b/src/gallium/drivers/llvmpipe/lp_fs.h
new file mode 100644 (file)
index 0000000..4081670
--- /dev/null
@@ -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 lp_fragment_shader *
+llvmpipe_create_fs_exec(struct llvmpipe_context *llvmpipe,
+                      const struct pipe_shader_state *templ);
+
+struct lp_fragment_shader *
+llvmpipe_create_fs_sse(struct llvmpipe_context *llvmpipe,
+                      const struct pipe_shader_state *templ);
+
+struct lp_fragment_shader *
+llvmpipe_create_fs_llvm(struct llvmpipe_context *llvmpipe,
+                       const struct pipe_shader_state *templ);
+
+struct tgsi_interp_coef;
+struct tgsi_exec_vector;
+
+void lp_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/llvmpipe/lp_fs_exec.c b/src/gallium/drivers/llvmpipe/lp_fs_exec.c
new file mode 100644 (file)
index 0000000..ea85697
--- /dev/null
@@ -0,0 +1,162 @@
+/**************************************************************************
+ * 
+ * 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 "lp_context.h"
+#include "lp_state.h"
+#include "lp_fs.h"
+#include "lp_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 lp_fragment_shader
+ */
+struct lp_exec_fragment_shader
+{
+   struct lp_fragment_shader base;
+   /* No other members for now */
+};
+
+
+/** cast wrapper */
+static INLINE struct lp_exec_fragment_shader *
+lp_exec_fragment_shader(const struct lp_fragment_shader *base)
+{
+   return (struct lp_exec_fragment_shader *) base;
+}
+
+
+/**
+ * Compute quad X,Y,Z,W for the four fragments in a quad.
+ *
+ * This should really be part of the compiled shader.
+ */
+void
+lp_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;
+   }
+}
+
+
+static void
+exec_prepare( const struct lp_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 );
+   }
+}
+
+
+/* TODO: hide the machine struct in here somewhere, remove from this
+ * interface:
+ */
+static unsigned 
+exec_run( const struct lp_fragment_shader *base,
+         struct tgsi_exec_machine *machine,
+         struct quad_header *quad )
+{
+   /* Compute X, Y, Z, W vals for this quad */
+   lp_setup_pos_vector(quad->posCoef, 
+                      (float)quad->input.x0, (float)quad->input.y0, 
+                      &machine->QuadPos);
+   
+   return tgsi_exec_machine_run( machine );
+}
+
+
+static void 
+exec_delete( struct lp_fragment_shader *base )
+{
+   FREE((void *) base->shader.tokens);
+   FREE(base);
+}
+
+
+struct lp_fragment_shader *
+llvmpipe_create_fs_exec(struct llvmpipe_context *llvmpipe,
+                       const struct pipe_shader_state *templ)
+{
+   struct lp_exec_fragment_shader *shader;
+
+   /* Decide whether we'll be codegenerating this shader and if so do
+    * that now.
+    */
+
+   shader = CALLOC_STRUCT(lp_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/llvmpipe/lp_fs_llvm.c b/src/gallium/drivers/llvmpipe/lp_fs_llvm.c
new file mode 100644 (file)
index 0000000..8c186ba
--- /dev/null
@@ -0,0 +1,205 @@
+/**************************************************************************
+ * 
+ * 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 LLVM code generation.
+ * Authors:
+ *   Zack Rusin
+ */
+
+#include "lp_context.h"
+#include "lp_state.h"
+#include "lp_fs.h"
+
+#include "pipe/p_state.h"
+#include "pipe/p_defines.h"
+#include "util/u_memory.h"
+#include "tgsi/tgsi_sse2.h"
+
+#if 0
+
+/**
+ * Subclass of lp_fragment_shader
+ */
+struct lp_llvm_fragment_shader
+{
+   struct lp_fragment_shader base;
+   struct gallivm_prog *llvm_prog;
+};
+
+
+static void
+shade_quad_llvm(struct quad_stage *qs,
+                struct quad_header *quad)
+{
+   struct quad_shade_stage *qss = quad_shade_stage(qs);
+   struct llvmpipe_context *llvmpipe = qs->llvmpipe;
+   float dests[4][16][4] ALIGN16_ATTRIB;
+   float inputs[4][16][4] ALIGN16_ATTRIB;
+   const float fx = (float) quad->x0;
+   const float fy = (float) quad->y0;
+   struct gallivm_prog *llvm = qss->llvm_prog;
+
+   inputs[0][0][0] = fx;
+   inputs[1][0][0] = fx + 1.0f;
+   inputs[2][0][0] = fx;
+   inputs[3][0][0] = fx + 1.0f;
+
+   inputs[0][0][1] = fy;
+   inputs[1][0][1] = fy;
+   inputs[2][0][1] = fy + 1.0f;
+   inputs[3][0][1] = fy + 1.0f;
+
+
+   gallivm_prog_inputs_interpolate(llvm, inputs, quad->coef);
+
+#if DLLVM
+   debug_printf("MASK = %d\n", quad->mask);
+   for (int i = 0; i < 4; ++i) {
+      for (int j = 0; j < 2; ++j) {
+         debug_printf("IN(%d,%d) [%f %f %f %f]\n", i, j, 
+                inputs[i][j][0], inputs[i][j][1], inputs[i][j][2], inputs[i][j][3]);
+      }
+   }
+#endif
+
+   quad->mask &=
+      gallivm_fragment_shader_exec(llvm, fx, fy, dests, inputs,
+                                   llvmpipe->mapped_constants[PIPE_SHADER_FRAGMENT],
+                                   qss->samplers);
+#if DLLVM
+   debug_printf("OUT LLVM = 1[%f %f %f %f], 2[%f %f %f %f]\n",
+          dests[0][0][0], dests[0][0][1], dests[0][0][2], dests[0][0][3], 
+          dests[0][1][0], dests[0][1][1], dests[0][1][2], dests[0][1][3]);
+#endif
+
+   /* store result color */
+   if (qss->colorOutSlot >= 0) {
+      unsigned i;
+      /* XXX need to handle multiple color outputs someday */
+      allvmrt(qss->stage.llvmpipe->fs->info.output_semantic_name[qss->colorOutSlot]
+             == TGSI_SEMANTIC_COLOR);
+      for (i = 0; i < QUAD_SIZE; ++i) {
+         quad->outputs.color[0][0][i] = dests[i][qss->colorOutSlot][0];
+         quad->outputs.color[0][1][i] = dests[i][qss->colorOutSlot][1];
+         quad->outputs.color[0][2][i] = dests[i][qss->colorOutSlot][2];
+         quad->outputs.color[0][3][i] = dests[i][qss->colorOutSlot][3];
+      }
+   }
+#if DLLVM
+   for (int i = 0; i < QUAD_SIZE; ++i) {
+      debug_printf("QLLVM%d(%d) [%f, %f, %f, %f]\n", i, qss->colorOutSlot,
+             quad->outputs.color[0][0][i],
+             quad->outputs.color[0][1][i],
+             quad->outputs.color[0][2][i],
+             quad->outputs.color[0][3][i]);
+   }
+#endif
+
+   /* store result Z */
+   if (qss->depthOutSlot >= 0) {
+      /* output[slot] is new Z */
+      uint i;
+      for (i = 0; i < 4; i++) {
+         quad->outputs.depth[i] = dests[i][0][2];
+      }
+   }
+   else {
+      /* copy input Z (which was interpolated by the executor) to output Z */
+      uint i;
+      for (i = 0; i < 4; i++) {
+         quad->outputs.depth[i] = inputs[i][0][2];
+      }
+   }
+#if DLLVM
+   debug_printf("D [%f, %f, %f, %f] mask = %d\n",
+             quad->outputs.depth[0],
+             quad->outputs.depth[1],
+             quad->outputs.depth[2],
+             quad->outputs.depth[3], quad->mask);
+#endif
+
+   /* shader may cull fragments */
+   if( quad->mask ) {
+      qs->next->run( qs->next, quad );
+   }
+}
+
+
+unsigned 
+run_llvm_fs( const struct lp_fragment_shader *base,
+            struct foo *machine )
+{
+}
+
+
+void 
+delete_llvm_fs( struct lp_fragment_shader *base )
+{
+   FREE(base);
+}
+
+
+struct lp_fragment_shader *
+llvmpipe_create_fs_llvm(struct llvmpipe_context *llvmpipe,
+                        const struct pipe_shader_state *templ)
+{
+   struct lp_llvm_fragment_shader *shader = NULL;
+
+   /* LLVM fragment shaders currently disabled:
+    */
+   state = CALLOC_STRUCT(lp_llvm_shader_state);
+   if (!state)
+      return NULL;
+
+   state->llvm_prog = 0;
+
+   if (!gallivm_global_cpu_engine()) {
+      gallivm_cpu_engine_create(state->llvm_prog);
+   }
+   else
+      gallivm_cpu_jit_compile(gallivm_global_cpu_engine(), state->llvm_prog);
+   
+   if (shader) {
+      shader->base.run = run_llvm_fs;
+      shader->base.delete = delete_llvm_fs;
+   }
+
+   return shader;
+}
+
+
+#else
+
+struct lp_fragment_shader *
+llvmpipe_create_fs_llvm(struct llvmpipe_context *llvmpipe,
+                      const struct pipe_shader_state *templ)
+{
+   return NULL;
+}
+
+#endif
diff --git a/src/gallium/drivers/llvmpipe/lp_fs_sse.c b/src/gallium/drivers/llvmpipe/lp_fs_sse.c
new file mode 100644 (file)
index 0000000..61c40dd
--- /dev/null
@@ -0,0 +1,169 @@
+/**************************************************************************
+ * 
+ * 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 "lp_context.h"
+#include "lp_state.h"
+#include "lp_fs.h"
+#include "lp_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 lp_fragment_shader
+ */
+struct lp_sse_fragment_shader
+{
+   struct lp_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 lp_sse_fragment_shader *
+lp_sse_fragment_shader(const struct lp_fragment_shader *base)
+{
+   return (struct lp_sse_fragment_shader *) base;
+}
+
+
+static void
+fs_sse_prepare( const struct lp_fragment_shader *base,
+               struct tgsi_exec_machine *machine,
+               struct tgsi_sampler **samplers )
+{
+   machine->Samplers = samplers;
+}
+
+
+/* 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 lp_fragment_shader *base,
+           struct tgsi_exec_machine *machine,
+           struct quad_header *quad )
+{
+   struct lp_sse_fragment_shader *shader = lp_sse_fragment_shader(base);
+
+   /* Compute X, Y, Z, W vals for this quad -- place in temp[0] for now */
+   lp_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,
+                machine->Consts,
+                 (const float (*)[4])shader->immediates,
+                machine->InterpCoefs
+                //      , &machine->QuadPos
+      );
+
+   return ~(machine->Temps[TGSI_EXEC_TEMP_KILMASK_I].xyzw[TGSI_EXEC_TEMP_KILMASK_C].u[0]);
+}
+
+
+static void 
+fs_sse_delete( struct lp_fragment_shader *base )
+{
+   struct lp_sse_fragment_shader *shader = lp_sse_fragment_shader(base);
+
+   x86_release_func( &shader->sse2_program );
+   FREE(shader);
+}
+
+
+struct lp_fragment_shader *
+llvmpipe_create_fs_sse(struct llvmpipe_context *llvmpipe,
+                      const struct pipe_shader_state *templ)
+{
+   struct lp_sse_fragment_shader *shader;
+
+   if (!llvmpipe->use_sse)
+      return NULL;
+
+   shader = CALLOC_STRUCT(lp_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 lp_fragment_shader *
+llvmpipe_create_fs_sse(struct llvmpipe_context *llvmpipe,
+                      const struct pipe_shader_state *templ)
+{
+   return NULL;
+}
+
+#endif
diff --git a/src/gallium/drivers/llvmpipe/lp_prim_setup.c b/src/gallium/drivers/llvmpipe/lp_prim_setup.c
new file mode 100644 (file)
index 0000000..5a5a617
--- /dev/null
@@ -0,0 +1,190 @@
+/**************************************************************************
+ * 
+ * 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 A draw stage that drives our triangle setup routines from
+ * within the draw pipeline.  One of two ways to drive setup, the
+ * other being in lp_prim_vbuf.c.
+ *
+ * \author  Keith Whitwell <keith@tungstengraphics.com>
+ * \author  Brian Paul
+ */
+
+
+#include "lp_context.h"
+#include "lp_setup.h"
+#include "lp_state.h"
+#include "lp_prim_setup.h"
+#include "draw/draw_pipe.h"
+#include "draw/draw_vertex.h"
+#include "util/u_memory.h"
+
+/**
+ * Triangle setup info (derived from draw_stage).
+ * Also used for line drawing (taking some liberties).
+ */
+struct setup_stage {
+   struct draw_stage stage; /**< This must be first (base class) */
+
+   struct setup_context *setup;
+};
+
+
+
+/**
+ * Basically a cast wrapper.
+ */
+static INLINE struct setup_stage *setup_stage( struct draw_stage *stage )
+{
+   return (struct setup_stage *)stage;
+}
+
+
+typedef const float (*cptrf4)[4];
+
+static void
+do_tri(struct draw_stage *stage, struct prim_header *prim)
+{
+   struct setup_stage *setup = setup_stage( stage );
+   
+   setup_tri( setup->setup,
+              (cptrf4)prim->v[0]->data,
+              (cptrf4)prim->v[1]->data,
+              (cptrf4)prim->v[2]->data );
+}
+
+static void
+do_line(struct draw_stage *stage, struct prim_header *prim)
+{
+   struct setup_stage *setup = setup_stage( stage );
+
+   setup_line( setup->setup,
+               (cptrf4)prim->v[0]->data,
+               (cptrf4)prim->v[1]->data );
+}
+
+static void
+do_point(struct draw_stage *stage, struct prim_header *prim)
+{
+   struct setup_stage *setup = setup_stage( stage );
+
+   setup_point( setup->setup,
+                (cptrf4)prim->v[0]->data );
+}
+
+
+
+
+static void setup_begin( struct draw_stage *stage )
+{
+   struct setup_stage *setup = setup_stage(stage);
+
+   setup_prepare( setup->setup );
+
+   stage->point = do_point;
+   stage->line = do_line;
+   stage->tri = do_tri;
+}
+
+
+static void setup_first_point( struct draw_stage *stage,
+                              struct prim_header *header )
+{
+   setup_begin(stage);
+   stage->point( stage, header );
+}
+
+static void setup_first_line( struct draw_stage *stage,
+                              struct prim_header *header )
+{
+   setup_begin(stage);
+   stage->line( stage, header );
+}
+
+
+static void setup_first_tri( struct draw_stage *stage,
+                              struct prim_header *header )
+{
+   setup_begin(stage);
+   stage->tri( stage, header );
+}
+
+
+
+static void setup_flush( struct draw_stage *stage,
+                        unsigned flags )
+{
+   stage->point = setup_first_point;
+   stage->line = setup_first_line;
+   stage->tri = setup_first_tri;
+}
+
+
+static void reset_stipple_counter( struct draw_stage *stage )
+{
+}
+
+
+static void render_destroy( struct draw_stage *stage )
+{
+   struct setup_stage *ssetup = setup_stage(stage);
+   setup_destroy_context(ssetup->setup);
+   FREE( stage );
+}
+
+
+/**
+ * Create a new primitive setup/render stage.
+ */
+struct draw_stage *lp_draw_render_stage( struct llvmpipe_context *llvmpipe )
+{
+   struct setup_stage *sstage = CALLOC_STRUCT(setup_stage);
+
+   sstage->setup = setup_create_context(llvmpipe);
+   sstage->stage.draw = llvmpipe->draw;
+   sstage->stage.point = setup_first_point;
+   sstage->stage.line = setup_first_line;
+   sstage->stage.tri = setup_first_tri;
+   sstage->stage.flush = setup_flush;
+   sstage->stage.reset_stipple_counter = reset_stipple_counter;
+   sstage->stage.destroy = render_destroy;
+
+   return (struct draw_stage *)sstage;
+}
+
+struct setup_context *
+lp_draw_setup_context( struct draw_stage *stage )
+{
+   struct setup_stage *ssetup = setup_stage(stage);
+   return ssetup->setup;
+}
+
+void
+lp_draw_flush( struct draw_stage *stage )
+{
+   stage->flush( stage, 0 );
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_prim_setup.h b/src/gallium/drivers/llvmpipe/lp_prim_setup.h
new file mode 100644 (file)
index 0000000..9cd3439
--- /dev/null
@@ -0,0 +1,85 @@
+/**************************************************************************
+ * 
+ * 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_PRIM_SETUP_H
+#define SP_PRIM_SETUP_H
+
+
+/**
+ * vbuf is a special stage to gather the stream of triangles, lines, points
+ * together and reconstruct vertex buffers for hardware upload.
+ *
+ * First attempt, work in progress.
+ * 
+ * TODO:
+ *    - separate out vertex buffer building and primitive emit, ie >1 draw per vb.
+ *    - tell vbuf stage how to build hw vertices directly
+ *    - pass vbuf stage a buffer pointer for direct emit to agp/vram.
+ *
+ *
+ *
+ * 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.
+ */
+
+
+struct draw_stage;
+struct llvmpipe_context;
+
+
+typedef void (*vbuf_draw_func)( struct pipe_context *pipe,
+                                unsigned prim,
+                                const ushort *elements,
+                                unsigned nr_elements,
+                                const void *vertex_buffer,
+                                unsigned nr_vertices );
+
+
+extern struct draw_stage *
+lp_draw_render_stage( struct llvmpipe_context *llvmpipe );
+
+extern struct setup_context *
+lp_draw_setup_context( struct draw_stage * );
+
+extern void
+lp_draw_flush( struct draw_stage * );
+
+
+extern struct draw_stage *
+lp_draw_vbuf_stage( struct draw_context *draw_context,
+                    struct pipe_context *pipe,
+                    vbuf_draw_func draw );
+
+
+#endif /* SP_PRIM_SETUP_H */
diff --git a/src/gallium/drivers/llvmpipe/lp_prim_vbuf.c b/src/gallium/drivers/llvmpipe/lp_prim_vbuf.c
new file mode 100644 (file)
index 0000000..e6d9e37
--- /dev/null
@@ -0,0 +1,585 @@
+/**************************************************************************
+ *
+ * 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 llvmpipe 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 "lp_context.h"
+#include "lp_state.h"
+#include "lp_prim_vbuf.h"
+#include "lp_prim_setup.h"
+#include "lp_setup.h"
+#include "draw/draw_context.h"
+#include "draw/draw_vbuf.h"
+#include "util/u_memory.h"
+
+
+#define SP_MAX_VBUF_INDEXES 1024
+#define SP_MAX_VBUF_SIZE    4096
+
+typedef const float (*cptrf4)[4];
+
+/**
+ * Subclass of vbuf_render.
+ */
+struct llvmpipe_vbuf_render
+{
+   struct vbuf_render base;
+   struct llvmpipe_context *llvmpipe;
+   uint prim;
+   uint vertex_size;
+   uint nr_vertices;
+   uint vertex_buffer_size;
+   void *vertex_buffer;
+};
+
+
+/** cast wrapper */
+static struct llvmpipe_vbuf_render *
+llvmpipe_vbuf_render(struct vbuf_render *vbr)
+{
+   return (struct llvmpipe_vbuf_render *) vbr;
+}
+
+
+static const struct vertex_info *
+lp_vbuf_get_vertex_info(struct vbuf_render *vbr)
+{
+   struct llvmpipe_vbuf_render *cvbr = llvmpipe_vbuf_render(vbr);
+   return llvmpipe_get_vbuf_vertex_info(cvbr->llvmpipe);
+}
+
+
+static boolean
+lp_vbuf_allocate_vertices(struct vbuf_render *vbr,
+                          ushort vertex_size, ushort nr_vertices)
+{
+   struct llvmpipe_vbuf_render *cvbr = llvmpipe_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
+lp_vbuf_release_vertices(struct vbuf_render *vbr)
+{
+#if 0
+   {
+      struct llvmpipe_vbuf_render *cvbr = llvmpipe_vbuf_render(vbr);
+      const struct vertex_info *info = 
+         llvmpipe_get_vbuf_vertex_info(cvbr->llvmpipe);
+      const float *vtx = (const float *) cvbr->vertex_buffer;
+      uint i, j;
+      debug_printf("%s (vtx_size = %u,  vtx_used = %u)\n",
+             __FUNCTION__, cvbr->vertex_size, cvbr->nr_vertices);
+      for (i = 0; i < cvbr->nr_vertices; i++) {
+         for (j = 0; j < info->num_attribs; j++) {
+            uint k;
+            switch (info->attrib[j].emit) {
+            case EMIT_4F:  k = 4;   break;
+            case EMIT_3F:  k = 3;   break;
+            case EMIT_2F:  k = 2;   break;
+            case EMIT_1F:  k = 1;   break;
+            default: assert(0);
+            }
+            debug_printf("Vert %u attr %u: ", i, j);
+            while (k-- > 0) {
+               debug_printf("%g ", vtx[0]);
+               vtx++;
+            }
+            debug_printf("\n");
+         }
+      }
+   }
+#endif
+
+   /* keep the old allocation for next time */
+}
+
+static void *
+lp_vbuf_map_vertices(struct vbuf_render *vbr)
+{
+   struct llvmpipe_vbuf_render *cvbr = llvmpipe_vbuf_render(vbr);
+   return cvbr->vertex_buffer;
+}
+
+static void 
+lp_vbuf_unmap_vertices(struct vbuf_render *vbr, 
+                       ushort min_index,
+                       ushort max_index )
+{
+   struct llvmpipe_vbuf_render *cvbr = llvmpipe_vbuf_render(vbr);
+   assert( cvbr->vertex_buffer_size >= (max_index+1) * cvbr->vertex_size );
+   /* do nothing */
+}
+
+
+static boolean
+lp_vbuf_set_primitive(struct vbuf_render *vbr, unsigned prim)
+{
+   struct llvmpipe_vbuf_render *cvbr = llvmpipe_vbuf_render(vbr);
+
+   /* XXX: break this dependency - make setup_context live under
+    * llvmpipe, rename the old "setup" draw stage to something else.
+    */
+   struct setup_context *setup_ctx = lp_draw_setup_context(cvbr->llvmpipe->setup);
+   
+   setup_prepare( setup_ctx );
+
+   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
+lp_vbuf_draw(struct vbuf_render *vbr, const ushort *indices, uint nr)
+{
+   struct llvmpipe_vbuf_render *cvbr = llvmpipe_vbuf_render(vbr);
+   struct llvmpipe_context *llvmpipe = cvbr->llvmpipe;
+   const unsigned stride = llvmpipe->vertex_info_vbuf.size * sizeof(float);
+   const void *vertex_buffer = cvbr->vertex_buffer;
+   unsigned i;
+
+   /* XXX: break this dependency - make setup_context live under
+    * llvmpipe, rename the old "setup" draw stage to something else.
+    */
+   struct draw_stage *setup = llvmpipe->setup;
+   struct setup_context *setup_ctx = lp_draw_setup_context(setup);
+
+   switch (cvbr->prim) {
+   case PIPE_PRIM_POINTS:
+      for (i = 0; i < nr; i++) {
+         setup_point( setup_ctx,
+                      get_vert(vertex_buffer, indices[i-0], stride) );
+      }
+      break;
+
+   case PIPE_PRIM_LINES:
+      for (i = 1; i < nr; i += 2) {
+         setup_line( setup_ctx,
+                     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 ++) {
+         setup_line( setup_ctx,
+                     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 ++) {
+         setup_line( setup_ctx,
+                     get_vert(vertex_buffer, indices[i-1], stride),
+                     get_vert(vertex_buffer, indices[i-0], stride) );
+      }
+      if (nr) {
+         setup_line( setup_ctx,
+                     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) {
+         if (llvmpipe->rasterizer->flatshade_first) {
+            setup_tri( setup_ctx,
+                       get_vert(vertex_buffer, indices[i-1], stride),
+                       get_vert(vertex_buffer, indices[i-0], stride),
+                       get_vert(vertex_buffer, indices[i-2], stride) );
+         }
+         else {
+            setup_tri( setup_ctx,
+                       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:
+      for (i = 2; i < nr; i += 1) {
+         if (llvmpipe->rasterizer->flatshade_first) {
+            setup_tri( setup_ctx,
+                       get_vert(vertex_buffer, indices[i+(i&1)-1], stride),
+                       get_vert(vertex_buffer, indices[i-(i&1)], stride),
+                       get_vert(vertex_buffer, indices[i-2], stride) );
+         }
+         else {
+            setup_tri( setup_ctx,
+                       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:
+      for (i = 2; i < nr; i += 1) {
+         if (llvmpipe->rasterizer->flatshade_first) {
+            setup_tri( setup_ctx,
+                       get_vert(vertex_buffer, indices[i-0], stride),
+                       get_vert(vertex_buffer, indices[0], stride),
+                       get_vert(vertex_buffer, indices[i-1], stride) );
+         }
+         else {
+            setup_tri( setup_ctx,
+                       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:
+      for (i = 3; i < nr; i += 4) {
+         if (llvmpipe->rasterizer->flatshade_first) {
+            setup_tri( setup_ctx,
+                       get_vert(vertex_buffer, indices[i-2], stride),
+                       get_vert(vertex_buffer, indices[i-1], stride),
+                       get_vert(vertex_buffer, indices[i-3], stride) );
+            setup_tri( setup_ctx,
+                       get_vert(vertex_buffer, indices[i-1], stride),
+                       get_vert(vertex_buffer, indices[i-0], stride),
+                       get_vert(vertex_buffer, indices[i-3], stride) );
+         }
+         else {
+            setup_tri( setup_ctx,
+                       get_vert(vertex_buffer, indices[i-3], stride),
+                       get_vert(vertex_buffer, indices[i-2], stride),
+                       get_vert(vertex_buffer, indices[i-0], stride) );
+
+            setup_tri( setup_ctx,
+                       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:
+      for (i = 3; i < nr; i += 2) {
+         if (llvmpipe->rasterizer->flatshade_first) {
+            setup_tri( setup_ctx,
+                       get_vert(vertex_buffer, indices[i-0], stride),
+                       get_vert(vertex_buffer, indices[i-1], stride),
+                       get_vert(vertex_buffer, indices[i-3], stride));
+            setup_tri( setup_ctx,
+                       get_vert(vertex_buffer, indices[i-2], stride),
+                       get_vert(vertex_buffer, indices[i-0], stride),
+                       get_vert(vertex_buffer, indices[i-3], stride) );
+         }
+         else {
+            setup_tri( setup_ctx,
+                       get_vert(vertex_buffer, indices[i-3], stride),
+                       get_vert(vertex_buffer, indices[i-2], stride),
+                       get_vert(vertex_buffer, indices[i-0], stride) );
+            setup_tri( setup_ctx,
+                       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.  Note that the first polygon vertex is passed as
+       * the last triangle vertex here.
+       * flatshade_first state makes no difference.
+       */
+      for (i = 2; i < nr; i += 1) {
+         setup_tri( setup_ctx,
+                    get_vert(vertex_buffer, indices[i-0], stride),
+                    get_vert(vertex_buffer, indices[i-1], stride),
+                    get_vert(vertex_buffer, indices[0], stride) );
+      }
+      break;
+
+   default:
+      assert(0);
+   }
+
+   /* XXX: why are we calling this???  If we had to call something, it
+    * would be a function in lp_setup.c:
+    */
+   lp_draw_flush( setup );
+}
+
+
+/**
+ * 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
+lp_vbuf_draw_arrays(struct vbuf_render *vbr, uint start, uint nr)
+{
+   struct llvmpipe_vbuf_render *cvbr = llvmpipe_vbuf_render(vbr);
+   struct llvmpipe_context *llvmpipe = cvbr->llvmpipe;
+   const unsigned stride = llvmpipe->vertex_info_vbuf.size * sizeof(float);
+   const void *vertex_buffer =
+      (void *) get_vert(cvbr->vertex_buffer, start, stride);
+   unsigned i;
+
+   /* XXX: break this dependency - make setup_context live under
+    * llvmpipe, rename the old "setup" draw stage to something else.
+    */
+   struct draw_stage *setup = llvmpipe->setup;
+   struct setup_context *setup_ctx = lp_draw_setup_context(setup);
+
+   switch (cvbr->prim) {
+   case PIPE_PRIM_POINTS:
+      for (i = 0; i < nr; i++) {
+         setup_point( setup_ctx,
+                      get_vert(vertex_buffer, i-0, stride) );
+      }
+      break;
+
+   case PIPE_PRIM_LINES:
+      for (i = 1; i < nr; i += 2) {
+         setup_line( setup_ctx,
+                     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 ++) {
+         setup_line( setup_ctx,
+                     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 ++) {
+         setup_line( setup_ctx,
+                     get_vert(vertex_buffer, i-1, stride),
+                     get_vert(vertex_buffer, i-0, stride) );
+      }
+      if (nr) {
+         setup_line( setup_ctx,
+                     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) {
+         if (llvmpipe->rasterizer->flatshade_first) {
+            setup_tri( setup_ctx,
+                       get_vert(vertex_buffer, i-1, stride),
+                       get_vert(vertex_buffer, i-0, stride),
+                       get_vert(vertex_buffer, i-2, stride) );
+         }
+         else {
+            setup_tri( setup_ctx,
+                       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:
+      for (i = 2; i < nr; i++) {
+         if (llvmpipe->rasterizer->flatshade_first) {
+            setup_tri( setup_ctx,
+                       get_vert(vertex_buffer, i+(i&1)-1, stride),
+                       get_vert(vertex_buffer, i-(i&1), stride),
+                       get_vert(vertex_buffer, i-2, stride) );
+         }
+         else {
+            setup_tri( setup_ctx,
+                       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:
+      for (i = 2; i < nr; i += 1) {
+         if (llvmpipe->rasterizer->flatshade_first) {
+            setup_tri( setup_ctx,
+                       get_vert(vertex_buffer, i-0, stride),
+                       get_vert(vertex_buffer, 0, stride),
+                       get_vert(vertex_buffer, i-1, stride) );
+         }
+         else {
+            setup_tri( setup_ctx,
+                       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:
+      for (i = 3; i < nr; i += 4) {
+         if (llvmpipe->rasterizer->flatshade_first) {
+            setup_tri( setup_ctx,
+                       get_vert(vertex_buffer, i-2, stride),
+                       get_vert(vertex_buffer, i-1, stride),
+                       get_vert(vertex_buffer, i-3, stride) );
+            setup_tri( setup_ctx,
+                       get_vert(vertex_buffer, i-1, stride),
+                       get_vert(vertex_buffer, i-0, stride),
+                       get_vert(vertex_buffer, i-3, stride) );
+         }
+         else {
+            setup_tri( setup_ctx,
+                       get_vert(vertex_buffer, i-3, stride),
+                       get_vert(vertex_buffer, i-2, stride),
+                       get_vert(vertex_buffer, i-0, stride) );
+            setup_tri( setup_ctx,
+                       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:
+      for (i = 3; i < nr; i += 2) {
+         if (llvmpipe->rasterizer->flatshade_first) {
+            setup_tri( setup_ctx,
+                       get_vert(vertex_buffer, i-0, stride),
+                       get_vert(vertex_buffer, i-1, stride),
+                       get_vert(vertex_buffer, i-3, stride) );
+            setup_tri( setup_ctx,
+                       get_vert(vertex_buffer, i-2, stride),
+                       get_vert(vertex_buffer, i-0, stride),
+                       get_vert(vertex_buffer, i-3, stride) );
+         }
+         else {
+            setup_tri( setup_ctx,
+                       get_vert(vertex_buffer, i-3, stride),
+                       get_vert(vertex_buffer, i-2, stride),
+                       get_vert(vertex_buffer, i-0, stride) );
+            setup_tri( setup_ctx,
+                       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.  Note that the first polygon vertex is passed as
+       * the last triangle vertex here.
+       * flatshade_first state makes no difference.
+       */
+      for (i = 2; i < nr; i += 1) {
+         setup_tri( setup_ctx,
+                    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
+lp_vbuf_destroy(struct vbuf_render *vbr)
+{
+   struct llvmpipe_vbuf_render *cvbr = llvmpipe_vbuf_render(vbr);
+   cvbr->llvmpipe->vbuf_render = NULL;
+   FREE(cvbr);
+}
+
+
+/**
+ * Initialize the post-transform vertex buffer information for the given
+ * context.
+ */
+void
+lp_init_vbuf(struct llvmpipe_context *lp)
+{
+   assert(lp->draw);
+
+   lp->vbuf_render = CALLOC_STRUCT(llvmpipe_vbuf_render);
+
+   lp->vbuf_render->base.max_indices = SP_MAX_VBUF_INDEXES;
+   lp->vbuf_render->base.max_vertex_buffer_bytes = SP_MAX_VBUF_SIZE;
+
+   lp->vbuf_render->base.get_vertex_info = lp_vbuf_get_vertex_info;
+   lp->vbuf_render->base.allocate_vertices = lp_vbuf_allocate_vertices;
+   lp->vbuf_render->base.map_vertices = lp_vbuf_map_vertices;
+   lp->vbuf_render->base.unmap_vertices = lp_vbuf_unmap_vertices;
+   lp->vbuf_render->base.set_primitive = lp_vbuf_set_primitive;
+   lp->vbuf_render->base.draw = lp_vbuf_draw;
+   lp->vbuf_render->base.draw_arrays = lp_vbuf_draw_arrays;
+   lp->vbuf_render->base.release_vertices = lp_vbuf_release_vertices;
+   lp->vbuf_render->base.destroy = lp_vbuf_destroy;
+
+   lp->vbuf_render->llvmpipe = lp;
+
+   lp->vbuf = draw_vbuf_stage(lp->draw, &lp->vbuf_render->base);
+
+   draw_set_rasterize_stage(lp->draw, lp->vbuf);
+
+   draw_set_render(lp->draw, &lp->vbuf_render->base);
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_prim_vbuf.h b/src/gallium/drivers/llvmpipe/lp_prim_vbuf.h
new file mode 100644 (file)
index 0000000..6405c58
--- /dev/null
@@ -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 llvmpipe_context;
+
+extern void
+lp_init_vbuf(struct llvmpipe_context *llvmpipe);
+
+
+#endif /* SP_VBUF_H */
diff --git a/src/gallium/drivers/llvmpipe/lp_quad.h b/src/gallium/drivers/llvmpipe/lp_quad.h
new file mode 100644 (file)
index 0000000..bd6c6cb
--- /dev/null
@@ -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;
+
+   const struct tgsi_interp_coef *coef;
+   const struct tgsi_interp_coef *posCoef;
+
+   unsigned nr_attrs;
+};
+
+#endif /* SP_QUAD_H */
diff --git a/src/gallium/drivers/llvmpipe/lp_quad_alpha_test.c b/src/gallium/drivers/llvmpipe/lp_quad_alpha_test.c
new file mode 100644 (file)
index 0000000..eea4ef9
--- /dev/null
@@ -0,0 +1,108 @@
+
+/**
+ * quad alpha test
+ */
+
+#include "lp_context.h"
+#include "lp_quad.h"
+#include "lp_quad_pipe.h"
+#include "pipe/p_defines.h"
+#include "util/u_memory.h"
+
+
+static void
+alpha_test_quad(struct quad_stage *qs, struct quad_header *quad)
+{
+   struct llvmpipe_context *llvmpipe = qs->llvmpipe;
+   const float ref = llvmpipe->depth_stencil->alpha.ref_value;
+   unsigned passMask = 0x0, j;
+   const uint cbuf = 0; /* only output[0].alpha is tested */
+   const float *aaaa = quad->output.color[cbuf][3];
+
+   switch (llvmpipe->depth_stencil->alpha.func) {
+   case PIPE_FUNC_NEVER:
+      break;
+   case PIPE_FUNC_LESS:
+      /*
+       * If mask were an array [4] we could do this SIMD-style:
+       * passMask = (quad->outputs.color[0][3] <= vec4(ref));
+       */
+      for (j = 0; j < QUAD_SIZE; j++) {
+         if (aaaa[j] < ref) {
+            passMask |= (1 << j);
+         }
+      }
+      break;
+   case PIPE_FUNC_EQUAL:
+      for (j = 0; j < QUAD_SIZE; j++) {
+         if (aaaa[j] == ref) {
+            passMask |= (1 << j);
+         }
+      }
+      break;
+   case PIPE_FUNC_LEQUAL:
+      for (j = 0; j < QUAD_SIZE; j++) {
+         if (aaaa[j] <= ref) {
+            passMask |= (1 << j);
+         }
+      }
+      break;
+   case PIPE_FUNC_GREATER:
+      for (j = 0; j < QUAD_SIZE; j++) {
+         if (aaaa[j] > ref) {
+            passMask |= (1 << j);
+         }
+      }
+      break;
+   case PIPE_FUNC_NOTEQUAL:
+      for (j = 0; j < QUAD_SIZE; j++) {
+         if (aaaa[j] != ref) {
+            passMask |= (1 << j);
+         }
+      }
+      break;
+   case PIPE_FUNC_GEQUAL:
+      for (j = 0; j < QUAD_SIZE; j++) {
+         if (aaaa[j] >= ref) {
+            passMask |= (1 << j);
+         }
+      }
+      break;
+   case PIPE_FUNC_ALWAYS:
+      passMask = MASK_ALL;
+      break;
+   default:
+      assert(0);
+   }
+
+   quad->inout.mask &= passMask;
+
+   if (quad->inout.mask)
+      qs->next->run(qs->next, quad);
+}
+
+
+static void alpha_test_begin(struct quad_stage *qs)
+{
+   qs->next->begin(qs->next);
+}
+
+
+static void alpha_test_destroy(struct quad_stage *qs)
+{
+   FREE( qs );
+}
+
+
+struct quad_stage *
+lp_quad_alpha_test_stage( struct llvmpipe_context *llvmpipe )
+{
+   struct quad_stage *stage = CALLOC_STRUCT(quad_stage);
+
+   stage->llvmpipe = llvmpipe;
+   stage->begin = alpha_test_begin;
+   stage->run = alpha_test_quad;
+   stage->destroy = alpha_test_destroy;
+
+   return stage;
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_quad_blend.c b/src/gallium/drivers/llvmpipe/lp_quad_blend.c
new file mode 100644 (file)
index 0000000..b281d76
--- /dev/null
@@ -0,0 +1,777 @@
+/**************************************************************************
+ * 
+ * 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 "lp_context.h"
+#include "lp_quad.h"
+#include "lp_surface.h"
+#include "lp_tile_cache.h"
+#include "lp_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, struct quad_header *quad)
+{
+   struct llvmpipe_context *llvmpipe = qs->llvmpipe;
+   uint cbuf;
+
+   /* loop over colorbuffer outputs */
+   for (cbuf = 0; cbuf < llvmpipe->framebuffer.nr_cbufs; cbuf++) {
+      float dest[4][QUAD_SIZE];
+      ubyte src[4][4], dst[4][4], res[4][4];
+      uint *src4 = (uint *) src;
+      uint *dst4 = (uint *) dst;
+      uint *res4 = (uint *) res;
+      struct llvmpipe_cached_tile *
+         tile = lp_get_cached_tile(llvmpipe,
+                                   llvmpipe->cbuf_cache[cbuf],
+                                   quad->input.x0, quad->input.y0);
+      float (*quadColor)[4] = quad->output.color[cbuf];
+      uint i, j;
+
+      /* get/swizzle dest colors */
+      for (j = 0; j < QUAD_SIZE; j++) {
+         int x = (quad->input.x0 & (TILE_SIZE-1)) + (j & 1);
+         int y = (quad->input.y0 & (TILE_SIZE-1)) + (j >> 1);
+         for (i = 0; i < 4; i++) {
+            dest[i][j] = tile->data.color[y][x][i];
+         }
+      }
+
+      /* 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 (llvmpipe->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]);
+      }
+   }
+
+   /* pass quad to next stage */
+   qs->next->run(qs->next, quad);
+}
+
+
+
+
+static void
+blend_quad(struct quad_stage *qs, struct quad_header *quad)
+{
+   static const float zero[4] = { 0, 0, 0, 0 };
+   static const float one[4] = { 1, 1, 1, 1 };
+
+   struct llvmpipe_context *llvmpipe = qs->llvmpipe;
+   uint cbuf;
+
+   if (llvmpipe->blend->logicop_enable) {
+      logicop_quad(qs, quad);
+      return;
+   }
+
+   /* loop over colorbuffer outputs */
+   for (cbuf = 0; cbuf < llvmpipe->framebuffer.nr_cbufs; cbuf++) {
+      float source[4][QUAD_SIZE], dest[4][QUAD_SIZE];
+      struct llvmpipe_cached_tile *tile
+         = lp_get_cached_tile(llvmpipe,
+                              llvmpipe->cbuf_cache[cbuf],
+                              quad->input.x0, quad->input.y0);
+      float (*quadColor)[4] = quad->output.color[cbuf];
+      uint i, j;
+
+      /* get/swizzle dest colors */
+      for (j = 0; j < QUAD_SIZE; j++) {
+         int x = (quad->input.x0 & (TILE_SIZE-1)) + (j & 1);
+         int y = (quad->input.y0 & (TILE_SIZE-1)) + (j >> 1);
+         for (i = 0; i < 4; i++) {
+            dest[i][j] = tile->data.color[y][x][i];
+         }
+      }
+
+      /*
+       * Compute src/first term RGB
+       */
+      switch (llvmpipe->blend->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:
+         {
+            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 */
+         }
+         break;
+      case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:
+         {
+            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 */
+         }
+         break;
+      case PIPE_BLENDFACTOR_CONST_COLOR:
+         {
+            float comp[4];
+            VEC4_SCALAR(comp, llvmpipe->blend_color.color[0]); /* R */
+            VEC4_MUL(source[0], quadColor[0], comp); /* R */
+            VEC4_SCALAR(comp, llvmpipe->blend_color.color[1]); /* G */
+            VEC4_MUL(source[1], quadColor[1], comp); /* G */
+            VEC4_SCALAR(comp, llvmpipe->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, llvmpipe->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:
+         {
+            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 */
+         }
+         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 - llvmpipe->blend_color.color[0]);
+            VEC4_MUL(source[0], quadColor[0], inv_comp);
+            /* G */
+            VEC4_SCALAR(inv_comp, 1.0f - llvmpipe->blend_color.color[1]);
+            VEC4_MUL(source[1], quadColor[1], inv_comp);
+            /* B */
+            VEC4_SCALAR(inv_comp, 1.0f - llvmpipe->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 - llvmpipe->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 (llvmpipe->blend->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:
+         VEC4_MUL(source[3], quadColor[3], dest[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, llvmpipe->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:
+         {
+            float inv_alpha[4];
+            VEC4_SUB(inv_alpha, one, dest[3]);
+            VEC4_MUL(source[3], quadColor[3], inv_alpha); /* 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 - llvmpipe->blend_color.color[3]);
+            VEC4_MUL(source[3], quadColor[3], inv_comp);
+         }
+         break;
+      default:
+         assert(0);
+      }
+
+
+      /*
+       * Compute dest/second term RGB
+       */
+      switch (llvmpipe->blend->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:
+         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 */
+         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:
+         assert(0); /* illegal */
+         break;
+      case PIPE_BLENDFACTOR_CONST_COLOR:
+         {
+            float comp[4];
+            VEC4_SCALAR(comp, llvmpipe->blend_color.color[0]); /* R */
+            VEC4_MUL(dest[0], dest[0], comp); /* R */
+            VEC4_SCALAR(comp, llvmpipe->blend_color.color[1]); /* G */
+            VEC4_MUL(dest[1], dest[1], comp); /* G */
+            VEC4_SCALAR(comp, llvmpipe->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, llvmpipe->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:
+         {
+            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 */
+         }
+         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 - llvmpipe->blend_color.color[0]);
+            VEC4_MUL(dest[0], dest[0], inv_comp);
+            /* G */
+            VEC4_SCALAR(inv_comp, 1.0f - llvmpipe->blend_color.color[1]);
+            VEC4_MUL(dest[1], dest[1], inv_comp);
+            /* B */
+            VEC4_SCALAR(inv_comp, 1.0f - llvmpipe->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 - llvmpipe->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 (llvmpipe->blend->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:
+         VEC4_MUL(dest[3], dest[3], dest[3]); /* A */
+         break;
+      case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:
+         assert(0); /* illegal */
+         break;
+      case PIPE_BLENDFACTOR_CONST_COLOR:
+         /* fall-through */
+      case PIPE_BLENDFACTOR_CONST_ALPHA:
+         {
+            float comp[4];
+            VEC4_SCALAR(comp, llvmpipe->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:
+         {
+            float inv_comp[4];
+            VEC4_SUB(inv_comp, one, dest[3]); /* A */
+            VEC4_MUL(dest[3], inv_comp, dest[3]); /* 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 - llvmpipe->blend_color.color[3]);
+            VEC4_MUL(dest[3], dest[3], inv_comp);
+         }
+         break;
+      default:
+         assert(0);
+      }
+
+      /*
+       * Combine RGB terms
+       */
+      switch (llvmpipe->blend->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 (llvmpipe->blend->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);
+      }
+
+   } /* cbuf loop */
+
+   /* pass blended quad to next stage */
+   qs->next->run(qs->next, quad);
+}
+
+
+static void blend_begin(struct quad_stage *qs)
+{
+   qs->next->begin(qs->next);
+}
+
+
+static void blend_destroy(struct quad_stage *qs)
+{
+   FREE( qs );
+}
+
+
+struct quad_stage *lp_quad_blend_stage( struct llvmpipe_context *llvmpipe )
+{
+   struct quad_stage *stage = CALLOC_STRUCT(quad_stage);
+
+   stage->llvmpipe = llvmpipe;
+   stage->begin = blend_begin;
+   stage->run = blend_quad;
+   stage->destroy = blend_destroy;
+
+   return stage;
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_quad_bufloop.c b/src/gallium/drivers/llvmpipe/lp_quad_bufloop.c
new file mode 100644 (file)
index 0000000..2522c3c
--- /dev/null
@@ -0,0 +1,74 @@
+
+#include "util/u_memory.h"
+#include "lp_context.h"
+#include "lp_quad.h"
+#include "lp_surface.h"
+#include "lp_quad_pipe.h"
+
+
+/**
+ * Loop over colorbuffers, passing quad to next stage each time.
+ */
+static void
+cbuf_loop_quad(struct quad_stage *qs, struct quad_header *quad)
+{
+   struct llvmpipe_context *llvmpipe = qs->llvmpipe;
+   float tmp[PIPE_MAX_COLOR_BUFS][4][QUAD_SIZE];
+   unsigned i;
+
+   assert(sizeof(quad->outputs.color) == sizeof(tmp));
+   assert(llvmpipe->framebuffer.nr_cbufs <= PIPE_MAX_COLOR_BUFS);
+
+   /* make copy of original colors since they can get modified
+    * by blending and masking.
+    * XXX we won't have to do this if the fragment program actually emits
+    * N separate colors and we're drawing to N color buffers (MRT).
+    * But if we emitted one color and glDrawBuffer(GL_FRONT_AND_BACK) is
+    * in effect, we need to save/restore colors like this.
+    */
+   memcpy(tmp, quad->outputs.color, sizeof(tmp));
+
+   for (i = 0; i < llvmpipe->framebuffer.nr_cbufs; i++) {
+      /* set current cbuffer */
+#if 0 /* obsolete & going away */
+      llvmpipe->current_cbuf = i;
+#endif
+
+      /* pass blended quad to next stage */
+      qs->next->run(qs->next, quad);
+
+      /* restore quad's colors for next buffer */
+      memcpy(quad->outputs.color, tmp, sizeof(tmp));
+   }
+}
+
+
+static void cbuf_loop_begin(struct quad_stage *qs)
+{
+   qs->next->begin(qs->next);
+}
+
+
+static void cbuf_loop_destroy(struct quad_stage *qs)
+{
+   FREE( qs );
+}
+
+
+/**
+ * Create the colorbuffer loop stage.
+ * This is used to implement multiple render targets and GL_FRONT_AND_BACK
+ * rendering.
+ */
+struct quad_stage *lp_quad_bufloop_stage( struct llvmpipe_context *llvmpipe )
+{
+   struct quad_stage *stage = CALLOC_STRUCT(quad_stage);
+
+   stage->llvmpipe = llvmpipe;
+   stage->begin = cbuf_loop_begin;
+   stage->run = cbuf_loop_quad;
+   stage->destroy = cbuf_loop_destroy;
+
+   return stage;
+}
+
diff --git a/src/gallium/drivers/llvmpipe/lp_quad_colormask.c b/src/gallium/drivers/llvmpipe/lp_quad_colormask.c
new file mode 100644 (file)
index 0000000..ef95eae
--- /dev/null
@@ -0,0 +1,116 @@
+/**************************************************************************
+ * 
+ * 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  quad colormask stage
+ * \author Brian Paul
+ */
+
+#include "pipe/p_defines.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
+#include "lp_context.h"
+#include "lp_quad.h"
+#include "lp_surface.h"
+#include "lp_quad_pipe.h"
+#include "lp_tile_cache.h"
+
+
+
+/**
+ * XXX colormask could be rolled into blending...
+ */
+static void
+colormask_quad(struct quad_stage *qs, struct quad_header *quad)
+{
+   struct llvmpipe_context *llvmpipe = qs->llvmpipe;
+   uint cbuf;
+
+   /* loop over colorbuffer outputs */
+   for (cbuf = 0; cbuf < llvmpipe->framebuffer.nr_cbufs; cbuf++) {
+      float dest[4][QUAD_SIZE];
+      struct llvmpipe_cached_tile *tile
+         = lp_get_cached_tile(llvmpipe,
+                              llvmpipe->cbuf_cache[cbuf],
+                              quad->input.x0, quad->input.y0);
+      float (*quadColor)[4] = quad->output.color[cbuf];
+      uint i, j;
+
+      /* get/swizzle dest colors */
+      for (j = 0; j < QUAD_SIZE; j++) {
+         int x = (quad->input.x0 & (TILE_SIZE-1)) + (j & 1);
+         int y = (quad->input.y0 & (TILE_SIZE-1)) + (j >> 1);
+         for (i = 0; i < 4; i++) {
+            dest[i][j] = tile->data.color[y][x][i];
+         }
+      }
+
+      /* R */
+      if (!(llvmpipe->blend->colormask & PIPE_MASK_R))
+          COPY_4V(quadColor[0], dest[0]);
+
+      /* G */
+      if (!(llvmpipe->blend->colormask & PIPE_MASK_G))
+          COPY_4V(quadColor[1], dest[1]);
+
+      /* B */
+      if (!(llvmpipe->blend->colormask & PIPE_MASK_B))
+          COPY_4V(quadColor[2], dest[2]);
+
+      /* A */
+      if (!(llvmpipe->blend->colormask & PIPE_MASK_A))
+          COPY_4V(quadColor[3], dest[3]);
+   }
+
+   /* pass quad to next stage */
+   qs->next->run(qs->next, quad);
+}
+
+
+static void colormask_begin(struct quad_stage *qs)
+{
+   qs->next->begin(qs->next);
+}
+
+
+static void colormask_destroy(struct quad_stage *qs)
+{
+   FREE( qs );
+}
+
+
+struct quad_stage *lp_quad_colormask_stage( struct llvmpipe_context *llvmpipe )
+{
+   struct quad_stage *stage = CALLOC_STRUCT(quad_stage);
+
+   stage->llvmpipe = llvmpipe;
+   stage->begin = colormask_begin;
+   stage->run = colormask_quad;
+   stage->destroy = colormask_destroy;
+
+   return stage;
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_quad_coverage.c b/src/gallium/drivers/llvmpipe/lp_quad_coverage.c
new file mode 100644 (file)
index 0000000..01c5982
--- /dev/null
@@ -0,0 +1,94 @@
+/**************************************************************************
+ * 
+ * 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  Apply AA coverage to quad alpha valus
+ * \author  Brian Paul
+ */
+
+
+#include "pipe/p_defines.h"
+#include "util/u_memory.h"
+#include "lp_context.h"
+#include "lp_quad.h"
+#include "lp_quad_pipe.h"
+
+
+/**
+ * Multiply quad's alpha values by the fragment coverage.
+ */
+static void
+coverage_quad(struct quad_stage *qs, struct quad_header *quad)
+{
+   struct llvmpipe_context *llvmpipe = qs->llvmpipe;
+   const uint prim = quad->input.prim;
+
+   if ((llvmpipe->rasterizer->poly_smooth && prim == QUAD_PRIM_TRI) ||
+       (llvmpipe->rasterizer->line_smooth && prim == QUAD_PRIM_LINE) ||
+       (llvmpipe->rasterizer->point_smooth && prim == QUAD_PRIM_POINT)) {
+      uint cbuf;
+
+      /* loop over colorbuffer outputs */
+      for (cbuf = 0; cbuf < llvmpipe->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];
+         }
+      }
+   }
+
+   qs->next->run(qs->next, quad);
+}
+
+
+static void coverage_begin(struct quad_stage *qs)
+{
+   qs->next->begin(qs->next);
+}
+
+
+static void coverage_destroy(struct quad_stage *qs)
+{
+   FREE( qs );
+}
+
+
+struct quad_stage *lp_quad_coverage_stage( struct llvmpipe_context *llvmpipe )
+{
+   struct quad_stage *stage = CALLOC_STRUCT(quad_stage);
+
+   stage->llvmpipe = llvmpipe;
+   stage->begin = coverage_begin;
+   stage->run = coverage_quad;
+   stage->destroy = coverage_destroy;
+
+   return stage;
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_quad_depth_test.c b/src/gallium/drivers/llvmpipe/lp_quad_depth_test.c
new file mode 100644 (file)
index 0000000..5a1daf0
--- /dev/null
@@ -0,0 +1,290 @@
+/**************************************************************************
+ * 
+ * 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  Quad depth testing
+ */
+
+#include "pipe/p_defines.h"
+#include "util/u_memory.h"
+#include "lp_context.h"
+#include "lp_quad.h"
+#include "lp_surface.h"
+#include "lp_quad_pipe.h"
+#include "lp_tile_cache.h"
+
+
+/**
+ * Do depth testing for a quad.
+ * Not static since it's used by the stencil code.
+ */
+
+/*
+ * 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...
+ */
+
+void
+lp_depth_test_quad(struct quad_stage *qs, struct quad_header *quad)
+{
+   struct llvmpipe_context *llvmpipe = qs->llvmpipe;
+   struct pipe_surface *ps = llvmpipe->framebuffer.zsbuf;
+   const enum pipe_format format = ps->format;
+   unsigned bzzzz[QUAD_SIZE];  /**< Z values fetched from depth buffer */
+   unsigned qzzzz[QUAD_SIZE];  /**< Z values from the quad */
+   unsigned zmask = 0;
+   unsigned j;
+   struct llvmpipe_cached_tile *tile
+      = lp_get_cached_tile(llvmpipe, llvmpipe->zsbuf_cache, quad->input.x0, quad->input.y0);
+
+   assert(ps); /* shouldn't get here if there's no zbuffer */
+
+   /*
+    * 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.
+    *
+    * Also, get the zbuffer values (bzzzz) from the cached tile.
+    */
+   switch (format) {
+   case PIPE_FORMAT_Z16_UNORM:
+      {
+         float scale = 65535.0;
+
+         for (j = 0; j < QUAD_SIZE; j++) {
+            qzzzz[j] = (unsigned) (quad->output.depth[j] * scale);
+         }
+
+         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);
+            bzzzz[j] = tile->data.depth16[y][x];
+         }
+      }
+      break;
+   case PIPE_FORMAT_Z32_UNORM:
+      {
+         double scale = (double) (uint) ~0UL;
+
+         for (j = 0; j < QUAD_SIZE; j++) {
+            qzzzz[j] = (unsigned) (quad->output.depth[j] * scale);
+         }
+
+         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);
+            bzzzz[j] = tile->data.depth32[y][x];
+         }
+      }
+      break;
+   case PIPE_FORMAT_X8Z24_UNORM:
+      /* fall-through */
+   case PIPE_FORMAT_S8Z24_UNORM:
+      {
+         float scale = (float) ((1 << 24) - 1);
+
+         for (j = 0; j < QUAD_SIZE; j++) {
+            qzzzz[j] = (unsigned) (quad->output.depth[j] * scale);
+         }
+
+         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);
+            bzzzz[j] = tile->data.depth32[y][x] & 0xffffff;
+         }
+      }
+      break;
+   case PIPE_FORMAT_Z24X8_UNORM:
+      /* fall-through */
+   case PIPE_FORMAT_Z24S8_UNORM:
+      {
+         float scale = (float) ((1 << 24) - 1);
+
+         for (j = 0; j < QUAD_SIZE; j++) {
+            qzzzz[j] = (unsigned) (quad->output.depth[j] * scale);
+         }
+
+         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);
+            bzzzz[j] = tile->data.depth32[y][x] >> 8;
+         }
+      }
+      break;
+   default:
+      assert(0);
+   }
+
+   switch (llvmpipe->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 (qzzzz[j] < bzzzz[j]) 
+           zmask |= 1 << j;
+      }
+      break;
+   case PIPE_FUNC_EQUAL:
+      for (j = 0; j < QUAD_SIZE; j++) {
+        if (qzzzz[j] == bzzzz[j]) 
+           zmask |= 1 << j;
+      }
+      break;
+   case PIPE_FUNC_LEQUAL:
+      for (j = 0; j < QUAD_SIZE; j++) {
+        if (qzzzz[j] <= bzzzz[j]) 
+           zmask |= (1 << j);
+      }
+      break;
+   case PIPE_FUNC_GREATER:
+      for (j = 0; j < QUAD_SIZE; j++) {
+        if (qzzzz[j] > bzzzz[j]) 
+           zmask |= (1 << j);
+      }
+      break;
+   case PIPE_FUNC_NOTEQUAL:
+      for (j = 0; j < QUAD_SIZE; j++) {
+        if (qzzzz[j] != bzzzz[j]) 
+           zmask |= (1 << j);
+      }
+      break;
+   case PIPE_FUNC_GEQUAL:
+      for (j = 0; j < QUAD_SIZE; j++) {
+        if (qzzzz[j] >= bzzzz[j]) 
+           zmask |= (1 << j);
+      }
+      break;
+   case PIPE_FUNC_ALWAYS:
+      zmask = MASK_ALL;
+      break;
+   default:
+      assert(0);
+   }
+
+   quad->inout.mask &= zmask;
+
+   if (llvmpipe->depth_stencil->depth.writemask) {
+      
+      /* This is also efficient with sse / spe instructions: 
+       */
+      for (j = 0; j < QUAD_SIZE; j++) {
+        if (quad->inout.mask & (1 << j)) {
+           bzzzz[j] = qzzzz[j];
+        }
+      }
+
+      /* put updated Z values back into cached tile */
+      switch (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) bzzzz[j];
+         }
+         break;
+      case PIPE_FORMAT_X8Z24_UNORM:
+         /* fall-through */
+         /* (yes, this falls through to a different case than above) */
+      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] = bzzzz[j];
+         }
+         break;
+      case PIPE_FORMAT_S8Z24_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);
+            uint s8z24 = tile->data.depth32[y][x];
+            s8z24 = (s8z24 & 0xff000000) | bzzzz[j];
+            tile->data.depth32[y][x] = s8z24;
+         }
+         break;
+      case PIPE_FORMAT_Z24S8_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);
+            uint z24s8 = tile->data.depth32[y][x];
+            z24s8 = (z24s8 & 0xff) | (bzzzz[j] << 8);
+            tile->data.depth32[y][x] = z24s8;
+         }
+         break;
+      case PIPE_FORMAT_Z24X8_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] = bzzzz[j] << 8;
+         }
+         break;
+      default:
+         assert(0);
+      }
+   }
+}
+
+
+static void
+depth_test_quad(struct quad_stage *qs, struct quad_header *quad)
+{
+   lp_depth_test_quad(qs, quad);
+
+   if (quad->inout.mask)
+      qs->next->run(qs->next, quad);
+}
+
+
+static void depth_test_begin(struct quad_stage *qs)
+{
+   qs->next->begin(qs->next);
+}
+
+
+static void depth_test_destroy(struct quad_stage *qs)
+{
+   FREE( qs );
+}
+
+
+struct quad_stage *lp_quad_depth_test_stage( struct llvmpipe_context *llvmpipe )
+{
+   struct quad_stage *stage = CALLOC_STRUCT(quad_stage);
+
+   stage->llvmpipe = llvmpipe;
+   stage->begin = depth_test_begin;
+   stage->run = depth_test_quad;
+   stage->destroy = depth_test_destroy;
+
+   return stage;
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_quad_earlyz.c b/src/gallium/drivers/llvmpipe/lp_quad_earlyz.c
new file mode 100644 (file)
index 0000000..e4b4c3b
--- /dev/null
@@ -0,0 +1,88 @@
+/**************************************************************************
+ * 
+ * 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  Quad early-z testing
+ */
+
+#include "pipe/p_defines.h"
+#include "util/u_memory.h"
+#include "lp_quad.h"
+#include "lp_quad_pipe.h"
+
+
+/**
+ * All this stage does is compute the quad's Z values (which is normally
+ * done by the shading stage).
+ * The next stage will do the actual depth test.
+ */
+static void
+earlyz_quad(
+   struct quad_stage    *qs,
+   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;
+
+   qs->next->run( qs->next, quad );
+}
+
+static void
+earlyz_begin(
+   struct quad_stage *qs )
+{
+   qs->next->begin( qs->next );
+}
+
+static void
+earlyz_destroy(
+   struct quad_stage *qs )
+{
+   FREE( qs );
+}
+
+struct quad_stage *
+lp_quad_earlyz_stage(
+   struct llvmpipe_context *llvmpipe )
+{
+   struct quad_stage *stage = CALLOC_STRUCT( quad_stage );
+
+   stage->llvmpipe = llvmpipe;
+   stage->begin = earlyz_begin;
+   stage->run = earlyz_quad;
+   stage->destroy = earlyz_destroy;
+
+   return stage;
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_quad_fs.c b/src/gallium/drivers/llvmpipe/lp_quad_fs.c
new file mode 100644 (file)
index 0000000..cabc541
--- /dev/null
@@ -0,0 +1,192 @@
+/**************************************************************************
+ * 
+ * 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 "lp_context.h"
+#include "lp_state.h"
+#include "lp_quad.h"
+#include "lp_quad_pipe.h"
+#include "lp_texture.h"
+#include "lp_tex_sample.h"
+
+
+struct quad_shade_stage
+{
+   struct quad_stage stage;  /**< base class */
+   struct tgsi_exec_machine *machine;
+   struct tgsi_exec_vector *inputs, *outputs;
+};
+
+
+/** 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.
+ */
+static void
+shade_quad(struct quad_stage *qs, struct quad_header *quad)
+{
+   struct quad_shade_stage *qss = quad_shade_stage( qs );
+   struct llvmpipe_context *llvmpipe = qs->llvmpipe;
+   struct tgsi_exec_machine *machine = qss->machine;
+   boolean z_written;
+   
+   /* Consts do not require 16 byte alignment. */
+   machine->Consts = llvmpipe->mapped_constants[PIPE_SHADER_FRAGMENT];
+
+   machine->InterpCoefs = quad->coef;
+
+   /* run shader */
+   quad->inout.mask &= llvmpipe->fs->run( llvmpipe->fs, machine, quad );
+
+   /* store outputs */
+   z_written = FALSE;
+   {
+      const ubyte *sem_name = llvmpipe->fs->info.output_semantic_name;
+      const ubyte *sem_index = llvmpipe->fs->info.output_semantic_index;
+      const uint n = qss->stage.llvmpipe->fs->info.num_outputs;
+      uint i;
+      for (i = 0; i < n; i++) {
+         switch (sem_name[i]) {
+         case TGSI_SEMANTIC_COLOR:
+            {
+               uint cbuf = sem_index[i];
+               memcpy(quad->output.color[cbuf],
+                      &machine->Outputs[i].xyzw[0].f[0],
+                      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];
+               }
+               z_written = TRUE;
+            }
+            break;
+         }
+      }
+   }
+
+   if (!z_written) {
+      /* compute Z values now, as in the quad earlyz stage */
+      /* XXX we should really only do this if the earlyz stage is not used */
+      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;
+   }
+
+   /* shader may cull fragments */
+   if (quad->inout.mask) {
+      qs->next->run( qs->next, quad );
+   }
+}
+
+
+/**
+ * Per-primitive (or per-begin?) setup
+ */
+static void
+shade_begin(struct quad_stage *qs)
+{
+   struct quad_shade_stage *qss = quad_shade_stage(qs);
+   struct llvmpipe_context *llvmpipe = qs->llvmpipe;
+
+   llvmpipe->fs->prepare( llvmpipe->fs, 
+                         qss->machine,
+                         (struct tgsi_sampler **)
+                             llvmpipe->tgsi.frag_samplers_list );
+
+   qs->next->begin(qs->next);
+}
+
+
+static void
+shade_destroy(struct quad_stage *qs)
+{
+   struct quad_shade_stage *qss = (struct quad_shade_stage *) qs;
+
+   tgsi_exec_machine_destroy(qss->machine);
+
+   FREE( qs );
+}
+
+
+struct quad_stage *
+lp_quad_shade_stage( struct llvmpipe_context *llvmpipe )
+{
+   struct quad_shade_stage *qss = CALLOC_STRUCT(quad_shade_stage);
+   if (!qss)
+      goto fail;
+
+   qss->stage.llvmpipe = llvmpipe;
+   qss->stage.begin = shade_begin;
+   qss->stage.run = shade_quad;
+   qss->stage.destroy = shade_destroy;
+
+   qss->machine = tgsi_exec_machine_create();
+   if (!qss->machine)
+      goto fail;
+
+   return &qss->stage;
+
+fail:
+   if (qss && qss->machine)
+      tgsi_exec_machine_destroy(qss->machine);
+
+   FREE(qss);
+   return NULL;
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_quad_occlusion.c b/src/gallium/drivers/llvmpipe/lp_quad_occlusion.c
new file mode 100644 (file)
index 0000000..6441ca3
--- /dev/null
@@ -0,0 +1,85 @@
+/**************************************************************************
+ * 
+ * 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  Quad occlusion counter stage
+ * \author  Brian Paul
+ */
+
+
+#include "pipe/p_defines.h"
+#include "util/u_memory.h"
+#include "lp_context.h"
+#include "lp_quad.h"
+#include "lp_surface.h"
+#include "lp_quad_pipe.h"
+
+static unsigned count_bits( unsigned val )
+{
+   unsigned i;
+
+   for (i = 0; val ; val >>= 1)
+      i += (val & 1);
+
+   return i;
+}
+
+static void
+occlusion_count_quad(struct quad_stage *qs, struct quad_header *quad)
+{
+   struct llvmpipe_context *llvmpipe = qs->llvmpipe;
+
+   llvmpipe->occlusion_count += count_bits(quad->inout.mask);
+
+   qs->next->run(qs->next, quad);
+}
+
+
+static void occlusion_begin(struct quad_stage *qs)
+{
+   qs->next->begin(qs->next);
+}
+
+
+static void occlusion_destroy(struct quad_stage *qs)
+{
+   FREE( qs );
+}
+
+
+struct quad_stage *lp_quad_occlusion_stage( struct llvmpipe_context *llvmpipe )
+{
+   struct quad_stage *stage = CALLOC_STRUCT(quad_stage);
+
+   stage->llvmpipe = llvmpipe;
+   stage->begin = occlusion_begin;
+   stage->run = occlusion_count_quad;
+   stage->destroy = occlusion_destroy;
+
+   return stage;
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_quad_output.c b/src/gallium/drivers/llvmpipe/lp_quad_output.c
new file mode 100644 (file)
index 0000000..94d5f5a
--- /dev/null
@@ -0,0 +1,103 @@
+/**************************************************************************
+ * 
+ * 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_memory.h"
+#include "lp_context.h"
+#include "lp_quad.h"
+#include "lp_surface.h"
+#include "lp_quad_pipe.h"
+#include "lp_tile_cache.h"
+
+
+/**
+ * Last step of quad processing: write quad colors to the framebuffer,
+ * taking mask into account.
+ */
+static void
+output_quad(struct quad_stage *qs, struct quad_header *quad)
+{
+   /* in-tile pos: */
+   const int itx = quad->input.x0 % TILE_SIZE;
+   const int ity = quad->input.y0 % TILE_SIZE;
+
+   struct llvmpipe_context *llvmpipe = qs->llvmpipe;
+   uint cbuf;
+
+   /* loop over colorbuffer outputs */
+   for (cbuf = 0; cbuf < llvmpipe->framebuffer.nr_cbufs; cbuf++) {
+      struct llvmpipe_cached_tile *tile
+         = lp_get_cached_tile(llvmpipe,
+                              llvmpipe->cbuf_cache[cbuf],
+                              quad->input.x0, quad->input.y0);
+      float (*quadColor)[4] = quad->output.color[cbuf];
+      int i, j;
+
+      /* get/swizzle dest colors */
+      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];
+            }
+            if (0) {
+               debug_printf("lp write pixel %d,%d: %g, %g, %g\n",
+                            quad->input.x0 + x,
+                            quad->input.y0 + y,
+                            quadColor[0][j],
+                            quadColor[1][j],
+                            quadColor[2][j]);
+            }
+         }
+      }
+   }
+}
+
+
+static void output_begin(struct quad_stage *qs)
+{
+   assert(qs->next == NULL);
+}
+
+
+static void output_destroy(struct quad_stage *qs)
+{
+   FREE( qs );
+}
+
+
+struct quad_stage *lp_quad_output_stage( struct llvmpipe_context *llvmpipe )
+{
+   struct quad_stage *stage = CALLOC_STRUCT(quad_stage);
+
+   stage->llvmpipe = llvmpipe;
+   stage->begin = output_begin;
+   stage->run = output_quad;
+   stage->destroy = output_destroy;
+
+   return stage;
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_quad_pipe.c b/src/gallium/drivers/llvmpipe/lp_quad_pipe.c
new file mode 100644 (file)
index 0000000..378acf8
--- /dev/null
@@ -0,0 +1,118 @@
+/**************************************************************************
+ * 
+ * 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 "lp_context.h"
+#include "lp_state.h"
+#include "pipe/p_shader_tokens.h"
+
+static void
+lp_push_quad_first(
+   struct llvmpipe_context *lp,
+   struct quad_stage *quad,
+   uint i )
+{
+   quad->next = lp->quad[i].first;
+   lp->quad[i].first = quad;
+}
+
+static void
+lp_build_depth_stencil(
+   struct llvmpipe_context *lp,
+   uint i )
+{
+   if (lp->depth_stencil->stencil[0].enabled ||
+       lp->depth_stencil->stencil[1].enabled) {
+      lp_push_quad_first( lp, lp->quad[i].stencil_test, i );
+   }
+   else if (lp->depth_stencil->depth.enabled &&
+            lp->framebuffer.zsbuf) {
+      lp_push_quad_first( lp, lp->quad[i].depth_test, i );
+   }
+}
+
+void
+lp_build_quad_pipeline(struct llvmpipe_context *lp)
+{
+   uint i;
+
+   boolean early_depth_test =
+               lp->depth_stencil->depth.enabled &&
+               lp->framebuffer.zsbuf &&
+               !lp->depth_stencil->alpha.enabled &&
+               !lp->fs->info.uses_kill &&
+               !lp->fs->info.writes_z;
+
+   /* build up the pipeline in reverse order... */
+   for (i = 0; i < SP_NUM_QUAD_THREADS; i++) {
+      lp->quad[i].first = lp->quad[i].output;
+
+      if (lp->blend->colormask != 0xf) {
+         lp_push_quad_first( lp, lp->quad[i].colormask, i );
+      }
+
+      if (lp->blend->blend_enable ||
+          lp->blend->logicop_enable) {
+         lp_push_quad_first( lp, lp->quad[i].blend, i );
+      }
+
+      if (lp->active_query_count) {
+         lp_push_quad_first( lp, lp->quad[i].occlusion, i );
+      }
+
+      if (lp->rasterizer->poly_smooth ||
+          lp->rasterizer->line_smooth ||
+          lp->rasterizer->point_smooth) {
+         lp_push_quad_first( lp, lp->quad[i].coverage, i );
+      }
+
+      if (!early_depth_test) {
+         lp_build_depth_stencil( lp, i );
+      }
+
+      if (lp->depth_stencil->alpha.enabled) {
+         lp_push_quad_first( lp, lp->quad[i].alpha_test, i );
+      }
+
+      /* XXX always enable shader? */
+      if (1) {
+         lp_push_quad_first( lp, lp->quad[i].shade, i );
+      }
+
+      if (early_depth_test) {
+         lp_build_depth_stencil( lp, i );
+         lp_push_quad_first( lp, lp->quad[i].earlyz, i );
+      }
+
+#if !USE_DRAW_STAGE_PSTIPPLE
+      if (lp->rasterizer->poly_stipple_enable) {
+         lp_push_quad_first( lp, lp->quad[i].polygon_stipple, i );
+      }
+#endif
+   }
+}
+
diff --git a/src/gallium/drivers/llvmpipe/lp_quad_pipe.h b/src/gallium/drivers/llvmpipe/lp_quad_pipe.h
new file mode 100644 (file)
index 0000000..5995fdb
--- /dev/null
@@ -0,0 +1,74 @@
+/**************************************************************************
+ * 
+ * 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 llvmpipe_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 llvmpipe_context *llvmpipe;
+
+   struct quad_stage *next;
+
+   void (*begin)(struct quad_stage *qs);
+
+   /** the stage action */
+   void (*run)(struct quad_stage *qs, struct quad_header *quad);
+
+   void (*destroy)(struct quad_stage *qs);
+};
+
+
+struct quad_stage *lp_quad_polygon_stipple_stage( struct llvmpipe_context *llvmpipe );
+struct quad_stage *lp_quad_earlyz_stage( struct llvmpipe_context *llvmpipe );
+struct quad_stage *lp_quad_shade_stage( struct llvmpipe_context *llvmpipe );
+struct quad_stage *lp_quad_alpha_test_stage( struct llvmpipe_context *llvmpipe );
+struct quad_stage *lp_quad_stencil_test_stage( struct llvmpipe_context *llvmpipe );
+struct quad_stage *lp_quad_depth_test_stage( struct llvmpipe_context *llvmpipe );
+struct quad_stage *lp_quad_occlusion_stage( struct llvmpipe_context *llvmpipe );
+struct quad_stage *lp_quad_coverage_stage( struct llvmpipe_context *llvmpipe );
+struct quad_stage *lp_quad_blend_stage( struct llvmpipe_context *llvmpipe );
+struct quad_stage *lp_quad_colormask_stage( struct llvmpipe_context *llvmpipe );
+struct quad_stage *lp_quad_output_stage( struct llvmpipe_context *llvmpipe );
+
+void lp_build_quad_pipeline(struct llvmpipe_context *lp);
+
+void lp_depth_test_quad(struct quad_stage *qs, struct quad_header *quad);
+
+#endif /* SP_QUAD_PIPE_H */
diff --git a/src/gallium/drivers/llvmpipe/lp_quad_stencil.c b/src/gallium/drivers/llvmpipe/lp_quad_stencil.c
new file mode 100644 (file)
index 0000000..4c99067
--- /dev/null
@@ -0,0 +1,352 @@
+
+/**
+ * \brief Quad stencil testing
+ */
+
+
+#include "lp_context.h"
+#include "lp_quad.h"
+#include "lp_surface.h"
+#include "lp_tile_cache.h"
+#include "lp_quad_pipe.h"
+#include "pipe/p_defines.h"
+#include "util/u_memory.h"
+
+
+/** Only 8-bit stencil supported */
+#define STENCIL_MAX 0xff
+
+
+/**
+ * Do the basic stencil test (compare stencil buffer values against the
+ * reference value.
+ *
+ * \param 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(const ubyte stencilVals[QUAD_SIZE], 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 < (stencilVals[j] & valMask)) {
+            passMask |= (1 << j);
+         }
+      }
+      break;
+   case PIPE_FUNC_EQUAL:
+      for (j = 0; j < QUAD_SIZE; j++) {
+         if (ref == (stencilVals[j] & valMask)) {
+            passMask |= (1 << j);
+         }
+      }
+      break;
+   case PIPE_FUNC_LEQUAL:
+      for (j = 0; j < QUAD_SIZE; j++) {
+         if (ref <= (stencilVals[j] & valMask)) {
+            passMask |= (1 << j);
+         }
+      }
+      break;
+   case PIPE_FUNC_GREATER:
+      for (j = 0; j < QUAD_SIZE; j++) {
+         if (ref > (stencilVals[j] & valMask)) {
+            passMask |= (1 << j);
+         }
+      }
+      break;
+   case PIPE_FUNC_NOTEQUAL:
+      for (j = 0; j < QUAD_SIZE; j++) {
+         if (ref != (stencilVals[j] & valMask)) {
+            passMask |= (1 << j);
+         }
+      }
+      break;
+   case PIPE_FUNC_GEQUAL:
+      for (j = 0; j < QUAD_SIZE; j++) {
+         if (ref >= (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 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(ubyte stencilVals[QUAD_SIZE],
+                 unsigned mask, unsigned op, ubyte ref, ubyte wrtMask)
+{
+   unsigned j;
+   ubyte newstencil[QUAD_SIZE];
+
+   for (j = 0; j < QUAD_SIZE; j++) {
+      newstencil[j] = 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 (stencilVals[j] < STENCIL_MAX) {
+               newstencil[j] = stencilVals[j] + 1;
+            }
+         }
+      }
+      break;
+   case PIPE_STENCIL_OP_DECR:
+      for (j = 0; j < QUAD_SIZE; j++) {
+         if (mask & (1 << j)) {
+            if (stencilVals[j] > 0) {
+               newstencil[j] = stencilVals[j] - 1;
+            }
+         }
+      }
+      break;
+   case PIPE_STENCIL_OP_INCR_WRAP:
+      for (j = 0; j < QUAD_SIZE; j++) {
+         if (mask & (1 << j)) {
+            newstencil[j] = stencilVals[j] + 1;
+         }
+      }
+      break;
+   case PIPE_STENCIL_OP_DECR_WRAP:
+      for (j = 0; j < QUAD_SIZE; j++) {
+         if (mask & (1 << j)) {
+            newstencil[j] = stencilVals[j] - 1;
+         }
+      }
+      break;
+   case PIPE_STENCIL_OP_INVERT:
+      for (j = 0; j < QUAD_SIZE; j++) {
+         if (mask & (1 << j)) {
+            newstencil[j] = ~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++) {
+         stencilVals[j] = (wrtMask & newstencil[j]) | (~wrtMask & stencilVals[j]);
+      }
+   }
+   else {
+      for (j = 0; j < QUAD_SIZE; j++) {
+         stencilVals[j] = newstencil[j];
+      }
+   }
+}
+
+
+/**
+ * Do stencil (and depth) testing.  Stenciling depends on the outcome of
+ * depth testing.
+ */
+static void
+stencil_test_quad(struct quad_stage *qs, struct quad_header *quad)
+{
+   struct llvmpipe_context *llvmpipe = qs->llvmpipe;
+   struct pipe_surface *ps = llvmpipe->framebuffer.zsbuf;
+   unsigned func, zFailOp, zPassOp, failOp;
+   ubyte ref, wrtMask, valMask;
+   ubyte stencilVals[QUAD_SIZE];
+   struct llvmpipe_cached_tile *tile
+      = lp_get_cached_tile(llvmpipe, llvmpipe->zsbuf_cache, quad->input.x0, quad->input.y0);
+   uint j;
+   uint face = quad->input.facing;
+
+   if (!llvmpipe->depth_stencil->stencil[1].enabled) {
+      /* single-sided stencil test, use front (face=0) state */
+      face = 0;
+   }
+
+   /* choose front or back face function, operator, etc */
+   /* XXX we could do these initializations once per primitive */
+   func    = llvmpipe->depth_stencil->stencil[face].func;
+   failOp  = llvmpipe->depth_stencil->stencil[face].fail_op;
+   zFailOp = llvmpipe->depth_stencil->stencil[face].zfail_op;
+   zPassOp = llvmpipe->depth_stencil->stencil[face].zpass_op;
+   ref     = llvmpipe->depth_stencil->stencil[face].ref_value;
+   wrtMask = llvmpipe->depth_stencil->stencil[face].writemask;
+   valMask = llvmpipe->depth_stencil->stencil[face].valuemask;
+
+   assert(ps); /* shouldn't get here if there's no stencil buffer */
+
+   /* get stencil values from cached tile */
+   switch (ps->format) {
+   case PIPE_FORMAT_S8Z24_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);
+         stencilVals[j] = tile->data.depth32[y][x] >> 24;
+      }
+      break;
+   case PIPE_FORMAT_Z24S8_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);
+         stencilVals[j] = tile->data.depth32[y][x] & 0xff;
+      }
+      break;
+   case PIPE_FORMAT_S8_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);
+         stencilVals[j] = tile->data.stencil8[y][x];
+      }
+      break;
+   default:
+      assert(0);
+   }
+
+   /* do the stencil test first */
+   {
+      unsigned passMask, failMask;
+      passMask = do_stencil_test(stencilVals, func, ref, valMask);
+      failMask = quad->inout.mask & ~passMask;
+      quad->inout.mask &= passMask;
+
+      if (failOp != PIPE_STENCIL_OP_KEEP) {
+         apply_stencil_op(stencilVals, failMask, failOp, ref, wrtMask);
+      }
+   }
+
+   if (quad->inout.mask) {
+      /* now the pixels that passed the stencil test are depth tested */
+      if (llvmpipe->depth_stencil->depth.enabled) {
+         const unsigned origMask = quad->inout.mask;
+
+         lp_depth_test_quad(qs, quad);  /* quad->mask is updated */
+
+         /* update stencil buffer values according to z pass/fail result */
+         if (zFailOp != PIPE_STENCIL_OP_KEEP) {
+            const unsigned failMask = origMask & ~quad->inout.mask;
+            apply_stencil_op(stencilVals, failMask, zFailOp, ref, wrtMask);
+         }
+
+         if (zPassOp != PIPE_STENCIL_OP_KEEP) {
+            const unsigned passMask = origMask & quad->inout.mask;
+            apply_stencil_op(stencilVals, passMask, zPassOp, ref, wrtMask);
+         }
+      }
+      else {
+         /* no depth test, apply Zpass operator to stencil buffer values */
+         apply_stencil_op(stencilVals, quad->inout.mask, zPassOp, ref, wrtMask);
+      }
+
+   }
+
+   /* put new stencil values into cached tile */
+   switch (ps->format) {
+   case PIPE_FORMAT_S8Z24_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);
+         uint s8z24 = tile->data.depth32[y][x];
+         s8z24 = (stencilVals[j] << 24) | (s8z24 & 0xffffff);
+         tile->data.depth32[y][x] = s8z24;
+      }
+      break;
+   case PIPE_FORMAT_Z24S8_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);
+         uint z24s8 = tile->data.depth32[y][x];
+         z24s8 = (z24s8 & 0xffffff00) | stencilVals[j];
+         tile->data.depth32[y][x] = z24s8;
+      }
+      break;
+   case PIPE_FORMAT_S8_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.stencil8[y][x] = stencilVals[j];
+      }
+      break;
+   default:
+      assert(0);
+   }
+
+   if (quad->inout.mask)
+      qs->next->run(qs->next, quad);
+}
+
+
+static void stencil_begin(struct quad_stage *qs)
+{
+   qs->next->begin(qs->next);
+}
+
+
+static void stencil_destroy(struct quad_stage *qs)
+{
+   FREE( qs );
+}
+
+
+struct quad_stage *lp_quad_stencil_test_stage( struct llvmpipe_context *llvmpipe )
+{
+   struct quad_stage *stage = CALLOC_STRUCT(quad_stage);
+
+   stage->llvmpipe = llvmpipe;
+   stage->begin = stencil_begin;
+   stage->run = stencil_test_quad;
+   stage->destroy = stencil_destroy;
+
+   return stage;
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_quad_stipple.c b/src/gallium/drivers/llvmpipe/lp_quad_stipple.c
new file mode 100644 (file)
index 0000000..6163946
--- /dev/null
@@ -0,0 +1,77 @@
+
+/**
+ * quad polygon stipple stage
+ */
+
+#include "lp_context.h"
+#include "lp_quad.h"
+#include "lp_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 *quad)
+{
+   static const uint bit31 = 1 << 31;
+   static const uint bit30 = 1 << 30;
+
+   if (quad->input.prim == QUAD_PRIM_TRI) {
+      struct llvmpipe_context *llvmpipe = qs->llvmpipe;
+      /* need to invert Y to index into OpenGL's stipple pattern */
+      const int col0 = quad->input.x0 % 32;
+      const int y0 = quad->input.y0;
+      const int y1 = y0 + 1;
+      const uint stipple0 = llvmpipe->poly_stipple.stipple[y0 % 32];
+      const uint stipple1 = llvmpipe->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) {
+         /* all fragments failed stipple test, end of quad pipeline */
+         return;
+      }
+   }
+
+   qs->next->run(qs->next, quad);
+}
+
+
+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 *
+lp_quad_polygon_stipple_stage( struct llvmpipe_context *llvmpipe )
+{
+   struct quad_stage *stage = CALLOC_STRUCT(quad_stage);
+
+   stage->llvmpipe = llvmpipe;
+   stage->begin = stipple_begin;
+   stage->run = stipple_quad;
+   stage->destroy = stipple_destroy;
+
+   return stage;
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_query.c b/src/gallium/drivers/llvmpipe/lp_query.c
new file mode 100644 (file)
index 0000000..7aa8e9d
--- /dev/null
@@ -0,0 +1,111 @@
+/**************************************************************************
+ * 
+ * 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 "pipe/p_defines.h"
+#include "util/u_memory.h"
+#include "lp_context.h"
+#include "lp_query.h"
+#include "lp_state.h"
+
+struct llvmpipe_query {
+   uint64_t start;
+   uint64_t end;
+};
+
+
+static struct llvmpipe_query *llvmpipe_query( struct pipe_query *p )
+{
+   return (struct llvmpipe_query *)p;
+}
+
+static struct pipe_query *
+llvmpipe_create_query(struct pipe_context *pipe, 
+                     unsigned type)
+{
+   assert(type == PIPE_QUERY_OCCLUSION_COUNTER);
+   return (struct pipe_query *)CALLOC_STRUCT( llvmpipe_query );
+}
+
+
+static void
+llvmpipe_destroy_query(struct pipe_context *pipe, struct pipe_query *q)
+{
+   FREE(q);
+}
+
+
+static void
+llvmpipe_begin_query(struct pipe_context *pipe, struct pipe_query *q)
+{
+   struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
+   struct llvmpipe_query *sq = llvmpipe_query(q);
+   
+   sq->start = llvmpipe->occlusion_count;
+   llvmpipe->active_query_count++;
+   llvmpipe->dirty |= SP_NEW_QUERY;
+}
+
+
+static void
+llvmpipe_end_query(struct pipe_context *pipe, struct pipe_query *q)
+{
+   struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
+   struct llvmpipe_query *sq = llvmpipe_query(q);
+
+   llvmpipe->active_query_count--;
+   sq->end = llvmpipe->occlusion_count;
+   llvmpipe->dirty |= SP_NEW_QUERY;
+}
+
+
+static boolean
+llvmpipe_get_query_result(struct pipe_context *pipe, 
+                         struct pipe_query *q,
+                         boolean wait,
+                         uint64_t *result )
+{
+   struct llvmpipe_query *sq = llvmpipe_query(q);
+   *result = sq->end - sq->start;
+   return TRUE;
+}
+
+
+void llvmpipe_init_query_funcs(struct llvmpipe_context *llvmpipe )
+{
+   llvmpipe->pipe.create_query = llvmpipe_create_query;
+   llvmpipe->pipe.destroy_query = llvmpipe_destroy_query;
+   llvmpipe->pipe.begin_query = llvmpipe_begin_query;
+   llvmpipe->pipe.end_query = llvmpipe_end_query;
+   llvmpipe->pipe.get_query_result = llvmpipe_get_query_result;
+}
+
+
diff --git a/src/gallium/drivers/llvmpipe/lp_query.h b/src/gallium/drivers/llvmpipe/lp_query.h
new file mode 100644 (file)
index 0000000..58eba08
--- /dev/null
@@ -0,0 +1,39 @@
+/**************************************************************************
+ * 
+ * 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
+
+struct llvmpipe_context;
+extern void llvmpipe_init_query_funcs(struct llvmpipe_context * );
+
+
+#endif /* SP_QUERY_H */
diff --git a/src/gallium/drivers/llvmpipe/lp_screen.c b/src/gallium/drivers/llvmpipe/lp_screen.c
new file mode 100644 (file)
index 0000000..b71f156
--- /dev/null
@@ -0,0 +1,190 @@
+/**************************************************************************
+ * 
+ * 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_simple_screen.h"
+#include "pipe/internal/p_winsys_screen.h"
+#include "pipe/p_defines.h"
+#include "pipe/p_screen.h"
+
+#include "lp_texture.h"
+#include "lp_winsys.h"
+#include "lp_screen.h"
+
+
+static const char *
+llvmpipe_get_vendor(struct pipe_screen *screen)
+{
+   return "Tungsten Graphics, Inc.";
+}
+
+
+static const char *
+llvmpipe_get_name(struct pipe_screen *screen)
+{
+   return "llvmpipe";
+}
+
+
+static int
+llvmpipe_get_param(struct pipe_screen *screen, int param)
+{
+   switch (param) {
+   case PIPE_CAP_MAX_TEXTURE_IMAGE_UNITS:
+      return PIPE_MAX_SAMPLERS;
+   case PIPE_CAP_MAX_VERTEX_TEXTURE_UNITS:
+      return PIPE_MAX_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_S3TC:
+      return 0;
+   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_TEXTURE_MIRROR_CLAMP:
+      return 1;
+   case PIPE_CAP_TEXTURE_MIRROR_REPEAT:
+      return 1;
+   case PIPE_CAP_TEXTURE_SHADOW_MAP:
+      return 1;
+   case PIPE_CAP_MAX_TEXTURE_2D_LEVELS:
+      return 13; /* max 4Kx4K */
+   case PIPE_CAP_MAX_TEXTURE_3D_LEVELS:
+      return 8;  /* max 128x128x128 */
+   case PIPE_CAP_MAX_TEXTURE_CUBE_LEVELS:
+      return 13; /* max 4Kx4K */
+   case PIPE_CAP_TGSI_CONT_SUPPORTED:
+      return 1;
+   case PIPE_CAP_BLEND_EQUATION_SEPARATE:
+      return 1;
+   default:
+      return 0;
+   }
+}
+
+
+static float
+llvmpipe_get_paramf(struct pipe_screen *screen, int 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
+llvmpipe_is_format_supported( struct pipe_screen *screen,
+                              enum pipe_format format, 
+                              enum pipe_texture_target target,
+                              unsigned tex_usage, 
+                              unsigned geom_flags )
+{
+   assert(target == PIPE_TEXTURE_1D ||
+          target == PIPE_TEXTURE_2D ||
+          target == PIPE_TEXTURE_3D ||
+          target == PIPE_TEXTURE_CUBE);
+
+   switch(format) {
+   case PIPE_FORMAT_DXT1_RGB:
+   case PIPE_FORMAT_DXT1_RGBA:
+   case PIPE_FORMAT_DXT3_RGBA:
+   case PIPE_FORMAT_DXT5_RGBA:
+      return FALSE;
+   default:
+      return TRUE;
+   }
+}
+
+
+static void
+llvmpipe_destroy_screen( struct pipe_screen *screen )
+{
+   struct pipe_winsys *winsys = screen->winsys;
+
+   if(winsys->destroy)
+      winsys->destroy(winsys);
+
+   FREE(screen);
+}
+
+
+
+/**
+ * Create a new pipe_screen object
+ * Note: we're not presently subclassing pipe_screen (no llvmpipe_screen).
+ */
+struct pipe_screen *
+llvmpipe_create_screen(struct pipe_winsys *winsys)
+{
+   struct llvmpipe_screen *screen = CALLOC_STRUCT(llvmpipe_screen);
+
+   if (!screen)
+      return NULL;
+
+   screen->base.winsys = winsys;
+
+   screen->base.destroy = llvmpipe_destroy_screen;
+
+   screen->base.get_name = llvmpipe_get_name;
+   screen->base.get_vendor = llvmpipe_get_vendor;
+   screen->base.get_param = llvmpipe_get_param;
+   screen->base.get_paramf = llvmpipe_get_paramf;
+   screen->base.is_format_supported = llvmpipe_is_format_supported;
+
+   llvmpipe_init_screen_texture_funcs(&screen->base);
+   u_simple_screen_init(&screen->base);
+
+   return &screen->base;
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_screen.h b/src/gallium/drivers/llvmpipe/lp_screen.h
new file mode 100644 (file)
index 0000000..9f79510
--- /dev/null
@@ -0,0 +1,58 @@
+/**************************************************************************
+ * 
+ * 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 llvmpipe_screen {
+   struct pipe_screen base;
+
+   /* Increments whenever textures are modified.  Contexts can track
+    * this.
+    */
+   unsigned timestamp;          
+};
+
+
+
+
+static INLINE struct llvmpipe_screen *
+llvmpipe_screen( struct pipe_screen *pipe )
+{
+   return (struct llvmpipe_screen *)pipe;
+}
+
+
+#endif /* SP_SCREEN_H */
diff --git a/src/gallium/drivers/llvmpipe/lp_setup.c b/src/gallium/drivers/llvmpipe/lp_setup.c
new file mode 100644 (file)
index 0000000..1bfe9d4
--- /dev/null
@@ -0,0 +1,1550 @@
+/**************************************************************************
+ *
+ * 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 "lp_context.h"
+#include "lp_prim_setup.h"
+#include "lp_quad.h"
+#include "lp_quad_pipe.h"
+#include "lp_setup.h"
+#include "lp_state.h"
+#include "draw/draw_context.h"
+#include "draw/draw_private.h"
+#include "draw/draw_vertex.h"
+#include "pipe/p_shader_tokens.h"
+#include "pipe/p_thread.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 */
+};
+
+#if SP_NUM_QUAD_THREADS > 1
+
+/* Set to 1 if you want other threads to be instantly
+ * notified of pending jobs.
+ */
+#define INSTANT_NOTEMPTY_NOTIFY 0
+
+struct thread_info
+{
+   struct setup_context *setup;
+   uint id;
+   pipe_thread handle;
+};
+
+struct quad_job;
+
+typedef void (* quad_job_routine)( struct setup_context *setup, uint thread, struct quad_job *job );
+
+struct quad_job
+{
+   struct quad_header_input input;
+   struct quad_header_inout inout;
+   quad_job_routine routine;
+};
+
+#define NUM_QUAD_JOBS 64
+
+struct quad_job_que
+{
+   struct quad_job jobs[NUM_QUAD_JOBS];
+   uint first;
+   uint last;
+   pipe_mutex que_mutex;
+   pipe_condvar que_notfull_condvar;
+   pipe_condvar que_notempty_condvar;
+   uint jobs_added;
+   uint jobs_done;
+   pipe_condvar que_done_condvar;
+};
+
+static void
+add_quad_job( struct quad_job_que *que, struct quad_header *quad, quad_job_routine routine )
+{
+#if INSTANT_NOTEMPTY_NOTIFY
+   boolean empty;
+#endif
+
+   /* Wait for empty slot, see if the que is empty.
+    */
+   pipe_mutex_lock( que->que_mutex );
+   while ((que->last + 1) % NUM_QUAD_JOBS == que->first) {
+#if !INSTANT_NOTEMPTY_NOTIFY
+      pipe_condvar_broadcast( que->que_notempty_condvar );
+#endif
+      pipe_condvar_wait( que->que_notfull_condvar, que->que_mutex );
+   }
+#if INSTANT_NOTEMPTY_NOTIFY
+   empty = que->last == que->first;
+#endif
+   que->jobs_added++;
+   pipe_mutex_unlock( que->que_mutex );
+
+   /* Submit new job.
+    */
+   que->jobs[que->last].input = quad->input;
+   que->jobs[que->last].inout = quad->inout;
+   que->jobs[que->last].routine = routine;
+   que->last = (que->last + 1) % NUM_QUAD_JOBS;
+
+#if INSTANT_NOTEMPTY_NOTIFY
+   /* If the que was empty, notify consumers there's a job to be done.
+    */
+   if (empty) {
+      pipe_mutex_lock( que->que_mutex );
+      pipe_condvar_broadcast( que->que_notempty_condvar );
+      pipe_mutex_unlock( que->que_mutex );
+   }
+#endif
+}
+
+#endif
+
+/**
+ * Triangle setup info (derived from draw_stage).
+ * Also used for line drawing (taking some liberties).
+ */
+struct setup_context {
+   struct llvmpipe_context *llvmpipe;
+
+   /* 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;
+
+   struct tgsi_interp_coef coef[PIPE_MAX_SHADER_INPUTS];
+   struct tgsi_interp_coef posCoef;  /* For Z, W */
+   struct quad_header quad;
+
+#if SP_NUM_QUAD_THREADS > 1
+   struct quad_job_que que;
+   struct thread_info threads[SP_NUM_QUAD_THREADS];
+#endif
+
+   struct {
+      int left[2];   /**< [0] = row0, [1] = row1 */
+      int right[2];
+      int y;
+      unsigned y_flags;
+      unsigned mask;     /**< mask of MASK_BOTTOM/TOP_LEFT/RIGHT bits */
+   } span;
+
+#if DEBUG_FRAGS
+   uint numFragsEmitted;  /**< per primitive */
+   uint numFragsWritten;  /**< per primitive */
+#endif
+
+   unsigned winding;           /* which winding to cull */
+};
+
+#if SP_NUM_QUAD_THREADS > 1
+
+static PIPE_THREAD_ROUTINE( quad_thread, param )
+{
+   struct thread_info *info = (struct thread_info *) param;
+   struct quad_job_que *que = &info->setup->que;
+
+   for (;;) {
+      struct quad_job job;
+      boolean full;
+
+      /* Wait for an available job.
+       */
+      pipe_mutex_lock( que->que_mutex );
+      while (que->last == que->first)
+         pipe_condvar_wait( que->que_notempty_condvar, que->que_mutex );
+
+      /* See if the que is full.
+       */
+      full = (que->last + 1) % NUM_QUAD_JOBS == que->first;
+
+      /* Take a job and remove it from que.
+       */
+      job = que->jobs[que->first];
+      que->first = (que->first + 1) % NUM_QUAD_JOBS;
+
+      /* Notify the producer if the que is not full.
+       */
+      if (full)
+         pipe_condvar_signal( que->que_notfull_condvar );
+      pipe_mutex_unlock( que->que_mutex );
+
+      job.routine( info->setup, info->id, &job );
+
+      /* Notify the producer if that's the last finished job.
+       */
+      pipe_mutex_lock( que->que_mutex );
+      que->jobs_done++;
+      if (que->jobs_added == que->jobs_done)
+         pipe_condvar_signal( que->que_done_condvar );
+      pipe_mutex_unlock( que->que_mutex );
+   }
+
+   return NULL;
+}
+
+#define WAIT_FOR_COMPLETION(setup) \
+   do {\
+      pipe_mutex_lock( setup->que.que_mutex );\
+      if (!INSTANT_NOTEMPTY_NOTIFY)\
+         pipe_condvar_broadcast( setup->que.que_notempty_condvar );\
+      while (setup->que.jobs_added != setup->que.jobs_done)\
+         pipe_condvar_wait( setup->que.que_done_condvar, setup->que.que_mutex );\
+      pipe_mutex_unlock( setup->que.que_mutex );\
+   } while (0)
+
+#else
+
+#define WAIT_FOR_COMPLETION(setup) ((void) 0)
+
+#endif
+
+
+
+/**
+ * Do triangle cull test using tri determinant (sign indicates orientation)
+ * \return true if triangle is to be culled.
+ */
+static INLINE boolean
+cull_tri(const struct setup_context *setup, float det)
+{
+   if (det != 0) {   
+      /* if (det < 0 then Z points toward camera and triangle is 
+       * counter-clockwise winding.
+       */
+      unsigned winding = (det < 0) ? PIPE_WINDING_CCW : PIPE_WINDING_CW;
+
+      if ((winding & setup->winding) == 0)
+        return FALSE;
+   }
+
+   /* Culled:
+    */
+   return TRUE;
+}
+
+
+
+/**
+ * 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->llvmpipe->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, uint thread )
+{
+   quad_clip( setup, quad );
+   if (quad->inout.mask) {
+      struct llvmpipe_context *lp = setup->llvmpipe;
+
+      lp->quad[thread].first->run( lp->quad[thread].first, quad );
+   }
+}
+
+#if SP_NUM_QUAD_THREADS > 1
+
+static void
+clip_emit_quad_job( struct setup_context *setup, uint thread, struct quad_job *job )
+{
+   struct quad_header quad;
+
+   quad.input = job->input;
+   quad.inout = job->inout;
+   quad.coef = setup->quad.coef;
+   quad.posCoef = setup->quad.posCoef;
+   quad.nr_attrs = setup->quad.nr_attrs;
+   clip_emit_quad( setup, &quad, thread );
+}
+
+#define CLIP_EMIT_QUAD(setup) add_quad_job( &setup->que, &setup->quad, clip_emit_quad_job )
+
+#else
+
+#define CLIP_EMIT_QUAD(setup) clip_emit_quad( setup, &setup->quad, 0 )
+
+#endif
+
+/**
+ * Emit a quad (pass to next stage).  No clipping is done.
+ */
+static INLINE void
+emit_quad( struct setup_context *setup, struct quad_header *quad, uint thread )
+{
+   struct llvmpipe_context *lp = setup->llvmpipe;
+#if DEBUG_FRAGS
+   uint mask = quad->inout.mask;
+#endif
+
+#if DEBUG_FRAGS
+   if (mask & 1) setup->numFragsEmitted++;
+   if (mask & 2) setup->numFragsEmitted++;
+   if (mask & 4) setup->numFragsEmitted++;
+   if (mask & 8) setup->numFragsEmitted++;
+#endif
+   lp->quad[thread].first->run( lp->quad[thread].first, quad );
+#if DEBUG_FRAGS
+   mask = quad->inout.mask;
+   if (mask & 1) setup->numFragsWritten++;
+   if (mask & 2) setup->numFragsWritten++;
+   if (mask & 4) setup->numFragsWritten++;
+   if (mask & 8) setup->numFragsWritten++;
+#endif
+}
+
+#if SP_NUM_QUAD_THREADS > 1
+
+static void
+emit_quad_job( struct setup_context *setup, uint thread, struct quad_job *job )
+{
+   struct quad_header quad;
+
+   quad.input = job->input;
+   quad.inout = job->inout;
+   quad.coef = setup->quad.coef;
+   quad.posCoef = setup->quad.posCoef;
+   quad.nr_attrs = setup->quad.nr_attrs;
+   emit_quad( setup, &quad, thread );
+}
+
+#define EMIT_QUAD(setup,x,y,mask) do {\
+      setup->quad.input.x0 = x;\
+      setup->quad.input.y0 = y;\
+      setup->quad.inout.mask = mask;\
+      add_quad_job( &setup->que, &setup->quad, emit_quad_job );\
+   } while (0)
+
+#else
+
+#define EMIT_QUAD(setup,x,y,mask) do {\
+      setup->quad.input.x0 = x;\
+      setup->quad.input.y0 = y;\
+      setup->quad.inout.mask = mask;\
+      emit_quad( setup, &setup->quad, 0 );\
+   } while (0)
+
+#endif
+
+/**
+ * Given an X or Y coordinate, return the block/quad coordinate that it
+ * belongs to.
+ */
+static INLINE int block( int x )
+{
+   return x & ~1;
+}
+
+
+/**
+ * Render a horizontal span of quads
+ */
+static void flush_spans( struct setup_context *setup )
+{
+   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];
+   int minleft, maxright;
+   int x;
+
+   switch (setup->span.y_flags) {
+   case 0x3:
+      /* both odd and even lines written (both quad rows) */
+      minleft = block(MIN2(xleft0, xleft1));
+      maxright = block(MAX2(xright0, xright1));
+      for (x = minleft; x <= maxright; x += 2) {
+         /* determine which of the four pixels is inside the span bounds */
+         uint mask = 0x0;
+         if (x >= xleft0 && x < xright0)
+            mask |= MASK_TOP_LEFT;
+         if (x >= xleft1 && x < xright1)
+            mask |= MASK_BOTTOM_LEFT;
+         if (x+1 >= xleft0 && x+1 < xright0)
+            mask |= MASK_TOP_RIGHT;
+         if (x+1 >= xleft1 && x+1 < xright1)
+            mask |= MASK_BOTTOM_RIGHT;
+         if (mask)
+            EMIT_QUAD( setup, x, setup->span.y, mask );
+      }
+      break;
+
+   case 0x1:
+      /* only even line written (quad top row) */
+      minleft = block(xleft0);
+      maxright = block(xright0);
+      for (x = minleft; x <= maxright; x += 2) {
+         uint mask = 0x0;
+         if (x >= xleft0 && x < xright0)
+            mask |= MASK_TOP_LEFT;
+         if (x+1 >= xleft0 && x+1 < xright0)
+            mask |= MASK_TOP_RIGHT;
+         if (mask)
+            EMIT_QUAD( setup, x, setup->span.y, mask );
+      }
+      break;
+
+   case 0x2:
+      /* only odd line written (quad bottom row) */
+      minleft = block(xleft1);
+      maxright = block(xright1);
+      for (x = minleft; x <= maxright; x += 2) {
+         uint mask = 0x0;
+         if (x >= xleft1 && x < xright1)
+            mask |= MASK_BOTTOM_LEFT;
+         if (x+1 >= xleft1 && x+1 < xright1)
+            mask |= MASK_BOTTOM_RIGHT;
+         if (mask)
+            EMIT_QUAD( setup, x, setup->span.y, mask );
+      }
+      break;
+
+   default:
+      return;
+   }
+
+   setup->span.y = 0;
+   setup->span.y_flags = 0;
+   setup->span.right[0] = 0;
+   setup->span.right[1] = 0;
+}
+
+
+#if DEBUG_VERTS
+static void print_vertex(const struct setup_context *setup,
+                         const float (*v)[4])
+{
+   int i;
+   debug_printf("   Vertex: (%p)\n", v);
+   for (i = 0; i < setup->quad.nr_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] )
+{
+   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
+    */
+   setup->quad.input.facing = (det > 0.0) ^ (setup->llvmpipe->rasterizer->front_winding == PIPE_WINDING_CW);
+
+   return TRUE;
+}
+
+
+/**
+ * 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.
+ */
+static void tri_linear_coeff( struct setup_context *setup,
+                              struct tgsi_interp_coef *coef,
+                              uint vertSlot, uint i)
+{
+   float botda = setup->vmid[vertSlot][i] - setup->vmin[vertSlot][i];
+   float majda = setup->vmax[vertSlot][i] - setup->vmin[vertSlot][i];
+   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 (0.5, 0.5).
+    *
+    * 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] = (setup->vmin[vertSlot][i] -
+                  (dadx * (setup->vmin[0][0] - 0.5f) +
+                   dady * (setup->vmin[0][1] - 0.5f)));
+
+   /*
+   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.
+ */
+static void tri_persp_coeff( struct setup_context *setup,
+                             struct tgsi_interp_coef *coef,
+                             uint vertSlot, uint i)
+{
+   /* premultiply by 1/w  (v[0][3] is always W):
+    */
+   float mina = setup->vmin[vertSlot][i] * setup->vmin[0][3];
+   float mida = setup->vmid[vertSlot][i] * setup->vmid[0][3];
+   float maxa = setup->vmax[vertSlot][i] * 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] - 0.5f) +
+                   dady * (setup->vmin[0][1] - 0.5f)));
+}
+
+
+/**
+ * Special coefficient setup for gl_FragCoord.
+ * X and Y are trivial, though Y has 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)
+{
+   /*X*/
+   setup->coef[slot].a0[0] = 0;
+   setup->coef[slot].dadx[0] = 1.0;
+   setup->coef[slot].dady[0] = 0.0;
+   /*Y*/
+   setup->coef[slot].a0[1] = 0.0;
+   setup->coef[slot].dadx[1] = 0.0;
+   setup->coef[slot].dady[1] = 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 llvmpipe_context *llvmpipe = setup->llvmpipe;
+   const struct lp_fragment_shader *lpfs = llvmpipe->fs;
+   const struct vertex_info *vinfo = llvmpipe_get_vertex_info(llvmpipe);
+   uint fragSlot;
+
+   /* z and w are done by linear interpolation:
+    */
+   tri_linear_coeff(setup, &setup->posCoef, 0, 2);
+   tri_linear_coeff(setup, &setup->posCoef, 0, 3);
+
+   /* setup interpolation for all the remaining attributes:
+    */
+   for (fragSlot = 0; fragSlot < lpfs->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_linear_coeff(setup, &setup->coef[fragSlot], vertSlot, j);
+         break;
+      case INTERP_PERSPECTIVE:
+         for (j = 0; j < NUM_CHANNELS; j++)
+            tri_persp_coeff(setup, &setup->coef[fragSlot], vertSlot, j);
+         break;
+      case INTERP_POS:
+         setup_fragcoord_coeff(setup, fragSlot);
+         break;
+      default:
+         assert(0);
+      }
+
+      if (lpfs->info.input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) {
+         setup->coef[fragSlot].a0[0] = 1.0f - setup->quad.input.facing;
+         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] + 0.5f;
+   float vmid_x = setup->vmid[0][0] + 0.5f;
+
+   float vmin_y = setup->vmin[0][1] - 0.5f;
+   float vmid_y = setup->vmid[0][1] - 0.5f;
+   float vmax_y = setup->vmax[0][1] - 0.5f;
+
+   setup->emaj.sy = ceilf(vmin_y);
+   setup->emaj.lines = (int) ceilf(vmax_y - setup->emaj.sy);
+   setup->emaj.dxdy = setup->emaj.dx / setup->emaj.dy;
+   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.dx / setup->etop.dy;
+   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.dx / setup->ebot.dy;
+   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,
+                        unsigned lines )
+{
+   const struct pipe_scissor_state *cliprect = &setup->llvmpipe->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);
+
+   /* clip top/bottom */
+   start_y = sy;
+   finish_y = sy + lines;
+
+   if (start_y < miny)
+      start_y = miny;
+
+   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;
+         setup->span.y_flags |= 1<<(_y&1);
+      }
+   }
+
+
+   /* 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 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->llvmpipe->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 (cull_tri( setup, det ))
+      return;
+
+   if (!setup_sort_vertices( setup, det, v0, v1, v2 ))
+      return;
+   setup_tri_coefficients( setup );
+   setup_tri_edges( setup );
+
+   setup->quad.input.prim = QUAD_PRIM_TRI;
+
+   setup->span.y = 0;
+   setup->span.y_flags = 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 );
+
+   WAIT_FOR_COMPLETION(setup);
+
+#if DEBUG_FRAGS
+   printf("Tri: %u frags emitted, %u written\n",
+          setup->numFragsEmitted,
+          setup->numFragsWritten);
+#endif
+}
+
+
+
+/**
+ * Compute a0, dadx and dady for a linearly interpolated coefficient,
+ * for a line.
+ */
+static void
+line_linear_coeff(const struct setup_context *setup,
+                  struct tgsi_interp_coef *coef,
+                  uint vertSlot, uint i)
+{
+   const float da = setup->vmax[vertSlot][i] - setup->vmin[vertSlot][i];
+   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] = (setup->vmin[vertSlot][i] -
+                  (dadx * (setup->vmin[0][0] - 0.5f) +
+                   dady * (setup->vmin[0][1] - 0.5f)));
+}
+
+
+/**
+ * Compute a0, dadx and dady for a perspective-corrected interpolant,
+ * for a line.
+ */
+static void
+line_persp_coeff(const struct setup_context *setup,
+                 struct tgsi_interp_coef *coef,
+                 uint vertSlot, uint i)
+{
+   /* XXX double-check/verify this arithmetic */
+   const float a0 = setup->vmin[vertSlot][i] * setup->vmin[0][3];
+   const float a1 = setup->vmax[vertSlot][i] * 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] = (setup->vmin[vertSlot][i] -
+                  (dadx * (setup->vmin[0][0] - 0.5f) +
+                   dady * (setup->vmin[0][1] - 0.5f)));
+}
+
+
+/**
+ * Compute the setup->coef[] array dadx, dady, a0 values.
+ * Must be called after setup->vmin,vmax are initialized.
+ */
+static INLINE boolean
+setup_line_coefficients(struct setup_context *setup,
+                        const float (*v0)[4],
+                        const float (*v1)[4])
+{
+   struct llvmpipe_context *llvmpipe = setup->llvmpipe;
+   const struct lp_fragment_shader *lpfs = llvmpipe->fs;
+   const struct vertex_info *vinfo = llvmpipe_get_vertex_info(llvmpipe);
+   uint fragSlot;
+   float area;
+
+   /* use setup->vmin, vmax to point to vertices */
+   if (llvmpipe->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:
+    */
+   line_linear_coeff(setup, &setup->posCoef, 0, 2);
+   line_linear_coeff(setup, &setup->posCoef, 0, 3);
+
+   /* setup interpolation for all the remaining attributes:
+    */
+   for (fragSlot = 0; fragSlot < lpfs->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_linear_coeff(setup, &setup->coef[fragSlot], vertSlot, j);
+         break;
+      case INTERP_PERSPECTIVE:
+         for (j = 0; j < NUM_CHANNELS; j++)
+            line_persp_coeff(setup, &setup->coef[fragSlot], vertSlot, j);
+         break;
+      case INTERP_POS:
+         setup_fragcoord_coeff(setup, fragSlot);
+         break;
+      default:
+         assert(0);
+      }
+
+      if (lpfs->info.input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) {
+         setup->coef[fragSlot].a0[0] = 1.0f - setup->quad.input.facing;
+         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.input.x0 ||
+       quadY != setup->quad.input.y0)
+   {
+      /* flush prev quad, start new quad */
+
+      if (setup->quad.input.x0 != -1)
+         CLIP_EMIT_QUAD(setup);
+
+      setup->quad.input.x0 = quadX;
+      setup->quad.input.y0 = quadY;
+      setup->quad.inout.mask = 0x0;
+   }
+
+   setup->quad.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
+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->llvmpipe->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);
+
+   setup->quad.input.x0 = setup->quad.input.y0 = -1;
+   setup->quad.inout.mask = 0x0;
+   setup->quad.input.prim = QUAD_PRIM_LINE;
+   /* XXX temporary: set coverage to 1.0 so the line appears
+    * if AA mode happens to be enabled.
+    */
+   setup->quad.input.coverage[0] =
+   setup->quad.input.coverage[1] =
+   setup->quad.input.coverage[2] =
+   setup->quad.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.inout.mask) {
+      CLIP_EMIT_QUAD(setup);
+   }
+
+   WAIT_FOR_COMPLETION(setup);
+}
+
+
+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
+setup_point( struct setup_context *setup,
+             const float (*v0)[4] )
+{
+   struct llvmpipe_context *llvmpipe = setup->llvmpipe;
+   const struct lp_fragment_shader *lpfs = llvmpipe->fs;
+   const int sizeAttr = setup->llvmpipe->psize_slot;
+   const float size
+      = sizeAttr > 0 ? v0[sizeAttr][0]
+      : setup->llvmpipe->rasterizer->point_size;
+   const float halfSize = 0.5F * size;
+   const boolean round = (boolean) setup->llvmpipe->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 = llvmpipe_get_vertex_info(llvmpipe);
+   uint fragSlot;
+
+#if DEBUG_VERTS
+   debug_printf("Setup point:\n");
+   print_vertex(setup, v0);
+#endif
+
+   if (llvmpipe->no_rast)
+      return;
+
+   /* 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 < lpfs->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 (lpfs->info.input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) {
+         setup->coef[fragSlot].a0[0] = 1.0f - setup->quad.input.facing;
+         setup->coef[fragSlot].dadx[0] = 0.0;
+         setup->coef[fragSlot].dady[0] = 0.0;
+      }
+   }
+
+   setup->quad.input.prim = QUAD_PRIM_POINT;
+
+   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.input.x0 = (int) x - ix;
+      setup->quad.input.y0 = (int) y - iy;
+      setup->quad.inout.mask = (1 << ix) << (2 * iy);
+      CLIP_EMIT_QUAD(setup);
+   }
+   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.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.input.coverage[QUAD_TOP_LEFT] = MIN2(cover, 1.0f);
+                  setup->quad.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.input.coverage[QUAD_TOP_RIGHT] = MIN2(cover, 1.0f);
+                  setup->quad.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.input.coverage[QUAD_BOTTOM_LEFT] = MIN2(cover, 1.0f);
+                  setup->quad.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.input.coverage[QUAD_BOTTOM_RIGHT] = MIN2(cover, 1.0f);
+                  setup->quad.inout.mask |= MASK_BOTTOM_RIGHT;
+               }
+
+               if (setup->quad.inout.mask) {
+                  setup->quad.input.x0 = ix;
+                  setup->quad.input.y0 = iy;
+                  CLIP_EMIT_QUAD(setup);
+               }
+            }
+         }
+      }
+      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.inout.mask = mask;
+               setup->quad.input.x0 = ix;
+               setup->quad.input.y0 = iy;
+               CLIP_EMIT_QUAD(setup);
+            }
+         }
+      }
+   }
+
+   WAIT_FOR_COMPLETION(setup);
+}
+
+void setup_prepare( struct setup_context *setup )
+{
+   struct llvmpipe_context *lp = setup->llvmpipe;
+   unsigned i;
+
+   if (lp->dirty) {
+      llvmpipe_update_derived(lp);
+   }
+
+   /* Note: nr_attrs is only used for debugging (vertex printing) */
+   setup->quad.nr_attrs = draw_num_vs_outputs(lp->draw);
+
+   for (i = 0; i < SP_NUM_QUAD_THREADS; i++) {
+      lp->quad[i].first->begin( lp->quad[i].first );
+   }
+
+   if (lp->reduced_api_prim == PIPE_PRIM_TRIANGLES &&
+       lp->rasterizer->fill_cw == PIPE_POLYGON_MODE_FILL &&
+       lp->rasterizer->fill_ccw == PIPE_POLYGON_MODE_FILL) {
+      /* we'll do culling */
+      setup->winding = lp->rasterizer->cull_mode;
+   }
+   else {
+      /* 'draw' will do culling */
+      setup->winding = PIPE_WINDING_NONE;
+   }
+}
+
+
+
+void setup_destroy_context( struct setup_context *setup )
+{
+   FREE( setup );
+}
+
+
+/**
+ * Create a new primitive setup/render stage.
+ */
+struct setup_context *setup_create_context( struct llvmpipe_context *llvmpipe )
+{
+   struct setup_context *setup = CALLOC_STRUCT(setup_context);
+#if SP_NUM_QUAD_THREADS > 1
+   uint i;
+#endif
+
+   setup->llvmpipe = llvmpipe;
+
+   setup->quad.coef = setup->coef;
+   setup->quad.posCoef = &setup->posCoef;
+
+#if SP_NUM_QUAD_THREADS > 1
+   setup->que.first = 0;
+   setup->que.last = 0;
+   pipe_mutex_init( setup->que.que_mutex );
+   pipe_condvar_init( setup->que.que_notfull_condvar );
+   pipe_condvar_init( setup->que.que_notempty_condvar );
+   setup->que.jobs_added = 0;
+   setup->que.jobs_done = 0;
+   pipe_condvar_init( setup->que.que_done_condvar );
+   for (i = 0; i < SP_NUM_QUAD_THREADS; i++) {
+      setup->threads[i].setup = setup;
+      setup->threads[i].id = i;
+      setup->threads[i].handle = pipe_thread_create( quad_thread, &setup->threads[i] );
+   }
+#endif
+
+   return setup;
+}
+
diff --git a/src/gallium/drivers/llvmpipe/lp_setup.h b/src/gallium/drivers/llvmpipe/lp_setup.h
new file mode 100644 (file)
index 0000000..0e84dfc
--- /dev/null
@@ -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 llvmpipe_context;
+
+void 
+setup_tri( struct setup_context *setup,
+          const float (*v0)[4],
+          const float (*v1)[4],
+          const float (*v2)[4] );
+
+void
+setup_line(struct setup_context *setup,
+           const float (*v0)[4],
+           const float (*v1)[4]);
+
+void
+setup_point( struct setup_context *setup,
+             const float (*v0)[4] );
+
+
+struct setup_context *setup_create_context( struct llvmpipe_context *llvmpipe );
+void setup_prepare( struct setup_context *setup );
+void setup_destroy_context( struct setup_context *setup );
+
+#endif
diff --git a/src/gallium/drivers/llvmpipe/lp_state.h b/src/gallium/drivers/llvmpipe/lp_state.h
new file mode 100644 (file)
index 0000000..778b3a5
--- /dev/null
@@ -0,0 +1,206 @@
+/**************************************************************************
+ * 
+ * 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
+
+
+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 lp_fragment_shader {
+   struct pipe_shader_state shader;
+
+   struct tgsi_shader_info info;
+
+   void (*prepare)( const struct lp_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 lp_fragment_shader *shader,
+                   struct tgsi_exec_machine *machine,
+                   struct quad_header *quad );
+
+
+   void (*delete)( struct lp_fragment_shader * );
+};
+
+
+/** Subclass of pipe_shader_state */
+struct lp_vertex_shader {
+   struct pipe_shader_state shader;
+   struct draw_vertex_shader *draw_data;
+};
+
+
+
+void *
+llvmpipe_create_blend_state(struct pipe_context *,
+                            const struct pipe_blend_state *);
+void llvmpipe_bind_blend_state(struct pipe_context *,
+                               void *);
+void llvmpipe_delete_blend_state(struct pipe_context *,
+                                 void *);
+
+void *
+llvmpipe_create_sampler_state(struct pipe_context *,
+                              const struct pipe_sampler_state *);
+void llvmpipe_bind_sampler_states(struct pipe_context *, unsigned, void **);
+void llvmpipe_delete_sampler_state(struct pipe_context *, void *);
+
+void *
+llvmpipe_create_depth_stencil_state(struct pipe_context *,
+                                    const struct pipe_depth_stencil_alpha_state *);
+void llvmpipe_bind_depth_stencil_state(struct pipe_context *, void *);
+void llvmpipe_delete_depth_stencil_state(struct pipe_context *, void *);
+
+void *
+llvmpipe_create_rasterizer_state(struct pipe_context *,
+                                 const struct pipe_rasterizer_state *);
+void llvmpipe_bind_rasterizer_state(struct pipe_context *, void *);
+void llvmpipe_delete_rasterizer_state(struct pipe_context *, void *);
+
+void llvmpipe_set_framebuffer_state( struct pipe_context *,
+                            const struct pipe_framebuffer_state * );
+
+void llvmpipe_set_blend_color( struct pipe_context *pipe,
+                               const struct pipe_blend_color *blend_color );
+
+void llvmpipe_set_clip_state( struct pipe_context *,
+                            const struct pipe_clip_state * );
+
+void llvmpipe_set_constant_buffer(struct pipe_context *,
+                                  uint shader, uint index,
+                                  const struct pipe_constant_buffer *buf);
+
+void *llvmpipe_create_fs_state(struct pipe_context *,
+                               const struct pipe_shader_state *);
+void llvmpipe_bind_fs_state(struct pipe_context *, void *);
+void llvmpipe_delete_fs_state(struct pipe_context *, void *);
+void *llvmpipe_create_vs_state(struct pipe_context *,
+                               const struct pipe_shader_state *);
+void llvmpipe_bind_vs_state(struct pipe_context *, void *);
+void llvmpipe_delete_vs_state(struct pipe_context *, void *);
+
+void llvmpipe_set_polygon_stipple( struct pipe_context *,
+                                 const struct pipe_poly_stipple * );
+
+void llvmpipe_set_scissor_state( struct pipe_context *,
+                                 const struct pipe_scissor_state * );
+
+void llvmpipe_set_sampler_textures( struct pipe_context *,
+                                    unsigned num,
+                                    struct pipe_texture ** );
+
+void llvmpipe_set_viewport_state( struct pipe_context *,
+                                  const struct pipe_viewport_state * );
+
+void llvmpipe_set_vertex_elements(struct pipe_context *,
+                                  unsigned count,
+                                  const struct pipe_vertex_element *);
+
+void llvmpipe_set_vertex_buffers(struct pipe_context *,
+                                 unsigned count,
+                                 const struct pipe_vertex_buffer *);
+
+
+void llvmpipe_update_derived( struct llvmpipe_context *llvmpipe );
+
+
+boolean llvmpipe_draw_arrays(struct pipe_context *pipe, unsigned mode,
+                            unsigned start, unsigned count);
+
+boolean llvmpipe_draw_elements(struct pipe_context *pipe,
+                              struct pipe_buffer *indexBuffer,
+                              unsigned indexSize,
+                              unsigned mode, unsigned start, unsigned count);
+boolean
+llvmpipe_draw_range_elements(struct pipe_context *pipe,
+                             struct pipe_buffer *indexBuffer,
+                             unsigned indexSize,
+                             unsigned min_index,
+                             unsigned max_index,
+                             unsigned mode, unsigned start, unsigned count);
+
+void
+llvmpipe_set_edgeflags(struct pipe_context *pipe, const unsigned *edgeflags);
+
+
+void
+llvmpipe_map_transfers(struct llvmpipe_context *lp);
+
+void
+llvmpipe_unmap_transfers(struct llvmpipe_context *lp);
+
+void
+llvmpipe_map_texture_surfaces(struct llvmpipe_context *lp);
+
+void
+llvmpipe_unmap_texture_surfaces(struct llvmpipe_context *lp);
+
+
+struct vertex_info *
+llvmpipe_get_vertex_info(struct llvmpipe_context *llvmpipe);
+
+struct vertex_info *
+llvmpipe_get_vbuf_vertex_info(struct llvmpipe_context *llvmpipe);
+
+
+#endif
diff --git a/src/gallium/drivers/llvmpipe/lp_state_blend.c b/src/gallium/drivers/llvmpipe/lp_state_blend.c
new file mode 100644 (file)
index 0000000..420615b
--- /dev/null
@@ -0,0 +1,98 @@
+/**************************************************************************
+ * 
+ * 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 "lp_context.h"
+#include "lp_state.h"
+
+
+void *
+llvmpipe_create_blend_state(struct pipe_context *pipe,
+                            const struct pipe_blend_state *blend)
+{
+   return mem_dup(blend, sizeof(*blend));
+}
+
+void llvmpipe_bind_blend_state( struct pipe_context *pipe,
+                                void *blend )
+{
+   struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
+
+   llvmpipe->blend = (const struct pipe_blend_state *)blend;
+
+   llvmpipe->dirty |= SP_NEW_BLEND;
+}
+
+void llvmpipe_delete_blend_state(struct pipe_context *pipe,
+                                 void *blend)
+{
+   FREE( blend );
+}
+
+
+void llvmpipe_set_blend_color( struct pipe_context *pipe,
+                            const struct pipe_blend_color *blend_color )
+{
+   struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
+
+   llvmpipe->blend_color = *blend_color;
+
+   llvmpipe->dirty |= SP_NEW_BLEND;
+}
+
+
+/** XXX move someday?  Or consolidate all these simple state setters
+ * into one file.
+ */
+
+
+void *
+llvmpipe_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
+llvmpipe_bind_depth_stencil_state(struct pipe_context *pipe,
+                                  void *depth_stencil)
+{
+   struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
+
+   llvmpipe->depth_stencil = (const struct pipe_depth_stencil_alpha_state *)depth_stencil;
+
+   llvmpipe->dirty |= SP_NEW_DEPTH_STENCIL_ALPHA;
+}
+
+void
+llvmpipe_delete_depth_stencil_state(struct pipe_context *pipe, void *depth)
+{
+   FREE( depth );
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_state_clip.c b/src/gallium/drivers/llvmpipe/lp_state_clip.c
new file mode 100644 (file)
index 0000000..b5408f7
--- /dev/null
@@ -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 "lp_context.h"
+#include "lp_state.h"
+#include "draw/draw_context.h"
+
+
+void llvmpipe_set_clip_state( struct pipe_context *pipe,
+                            const struct pipe_clip_state *clip )
+{
+   struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
+
+   /* pass the clip state to the draw module */
+   draw_set_clip_state(llvmpipe->draw, clip);
+}
+
+
+void llvmpipe_set_viewport_state( struct pipe_context *pipe,
+                                  const struct pipe_viewport_state *viewport )
+{
+   struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
+
+   /* pass the viewport info to the draw module */
+   draw_set_viewport_state(llvmpipe->draw, viewport);
+
+   llvmpipe->viewport = *viewport; /* struct copy */
+   llvmpipe->dirty |= SP_NEW_VIEWPORT;
+}
+
+
+void llvmpipe_set_scissor_state( struct pipe_context *pipe,
+                                 const struct pipe_scissor_state *scissor )
+{
+   struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
+
+   draw_flush(llvmpipe->draw);
+
+   llvmpipe->scissor = *scissor; /* struct copy */
+   llvmpipe->dirty |= SP_NEW_SCISSOR;
+}
+
+
+void llvmpipe_set_polygon_stipple( struct pipe_context *pipe,
+                                   const struct pipe_poly_stipple *stipple )
+{
+   struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
+
+   draw_flush(llvmpipe->draw);
+
+   llvmpipe->poly_stipple = *stipple; /* struct copy */
+   llvmpipe->dirty |= SP_NEW_STIPPLE;
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_state_derived.c b/src/gallium/drivers/llvmpipe/lp_state_derived.c
new file mode 100644 (file)
index 0000000..3fd3c40
--- /dev/null
@@ -0,0 +1,211 @@
+/**************************************************************************
+ * 
+ * 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 "draw/draw_private.h"
+#include "lp_context.h"
+#include "lp_state.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 llvmpipe_context *llvmpipe)
+{
+   llvmpipe->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 *
+llvmpipe_get_vertex_info(struct llvmpipe_context *llvmpipe)
+{
+   struct vertex_info *vinfo = &llvmpipe->vertex_info;
+
+   if (vinfo->num_attribs == 0) {
+      /* compute vertex layout now */
+      const struct lp_fragment_shader *lpfs = llvmpipe->fs;
+      const enum interp_mode colorInterp
+         = llvmpipe->rasterizer->flatshade ? INTERP_CONSTANT : INTERP_LINEAR;
+      uint i;
+
+      if (llvmpipe->vbuf) {
+         /* if using the post-transform vertex buffer, tell draw_vbuf to
+          * simply emit the whole post-xform vertex as-is:
+          */
+         struct vertex_info *vinfo_vbuf = &llvmpipe->vertex_info_vbuf;
+         const uint num = draw_num_vs_outputs(llvmpipe->draw);
+         uint i;
+
+         /* 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 < lpfs->info.num_inputs; i++) {
+         int src;
+         switch (lpfs->info.input_semantic_name[i]) {
+         case TGSI_SEMANTIC_POSITION:
+            src = draw_find_vs_output(llvmpipe->draw,
+                                      TGSI_SEMANTIC_POSITION, 0);
+            draw_emit_vertex_attr(vinfo, EMIT_4F, INTERP_POS, src);
+            break;
+
+         case TGSI_SEMANTIC_COLOR:
+            src = draw_find_vs_output(llvmpipe->draw, TGSI_SEMANTIC_COLOR, 
+                                 lpfs->info.input_semantic_index[i]);
+            draw_emit_vertex_attr(vinfo, EMIT_4F, colorInterp, src);
+            break;
+
+         case TGSI_SEMANTIC_FOG:
+            src = draw_find_vs_output(llvmpipe->draw, TGSI_SEMANTIC_FOG, 0);
+            draw_emit_vertex_attr(vinfo, EMIT_4F, INTERP_PERSPECTIVE, src);
+            break;
+
+         case TGSI_SEMANTIC_GENERIC:
+         case TGSI_SEMANTIC_FACE:
+            /* this includes texcoords and varying vars */
+            src = draw_find_vs_output(llvmpipe->draw, TGSI_SEMANTIC_GENERIC,
+                                      lpfs->info.input_semantic_index[i]);
+            draw_emit_vertex_attr(vinfo, EMIT_4F, INTERP_PERSPECTIVE, src);
+            break;
+
+         default:
+            assert(0);
+         }
+      }
+
+      llvmpipe->psize_slot = draw_find_vs_output(llvmpipe->draw,
+                                                 TGSI_SEMANTIC_PSIZE, 0);
+      if (llvmpipe->psize_slot > 0) {
+         draw_emit_vertex_attr(vinfo, EMIT_4F, INTERP_CONSTANT,
+                               llvmpipe->psize_slot);
+      }
+
+      draw_compute_vertex_size(vinfo);
+   }
+
+   return vinfo;
+}
+
+
+/**
+ * Called from vbuf module.
+ *
+ * Note that there's actually two different vertex layouts in llvmpipe.
+ *
+ * The normal one is computed in llvmpipe_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 llvmpipe vbuf code begins drawing, the normal vertex layout
+ * will come into play again.
+ */
+struct vertex_info *
+llvmpipe_get_vbuf_vertex_info(struct llvmpipe_context *llvmpipe)
+{
+   (void) llvmpipe_get_vertex_info(llvmpipe);
+   return &llvmpipe->vertex_info_vbuf;
+}
+
+
+/**
+ * Recompute cliprect from scissor bounds, scissor enable and surface size.
+ */
+static void
+compute_cliprect(struct llvmpipe_context *lp)
+{
+   uint surfWidth = lp->framebuffer.width;
+   uint surfHeight = lp->framebuffer.height;
+
+   if (lp->rasterizer->scissor) {
+      /* clip to scissor rect */
+      lp->cliprect.minx = MAX2(lp->scissor.minx, 0);
+      lp->cliprect.miny = MAX2(lp->scissor.miny, 0);
+      lp->cliprect.maxx = MIN2(lp->scissor.maxx, surfWidth);
+      lp->cliprect.maxy = MIN2(lp->scissor.maxy, surfHeight);
+   }
+   else {
+      /* clip to surface bounds */
+      lp->cliprect.minx = 0;
+      lp->cliprect.miny = 0;
+      lp->cliprect.maxx = surfWidth;
+      lp->cliprect.maxy = surfHeight;
+   }
+}
+
+
+/* Hopefully this will remain quite simple, otherwise need to pull in
+ * something like the state tracker mechanism.
+ */
+void llvmpipe_update_derived( struct llvmpipe_context *llvmpipe )
+{
+   if (llvmpipe->dirty & (SP_NEW_RASTERIZER |
+                          SP_NEW_FS |
+                          SP_NEW_VS))
+      invalidate_vertex_layout( llvmpipe );
+
+   if (llvmpipe->dirty & (SP_NEW_SCISSOR |
+                          SP_NEW_DEPTH_STENCIL_ALPHA |
+                          SP_NEW_FRAMEBUFFER))
+      compute_cliprect(llvmpipe);
+
+   if (llvmpipe->dirty & (SP_NEW_BLEND |
+                          SP_NEW_DEPTH_STENCIL_ALPHA |
+                          SP_NEW_FRAMEBUFFER |
+                          SP_NEW_RASTERIZER |
+                          SP_NEW_FS | 
+                         SP_NEW_QUERY))
+      lp_build_quad_pipeline(llvmpipe);
+
+   llvmpipe->dirty = 0;
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_state_fs.c b/src/gallium/drivers/llvmpipe/lp_state_fs.c
new file mode 100644 (file)
index 0000000..dcc73f4
--- /dev/null
@@ -0,0 +1,169 @@
+/**************************************************************************
+ * 
+ * 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 "lp_context.h"
+#include "lp_state.h"
+#include "lp_fs.h"
+
+#include "pipe/p_defines.h"
+#include "util/u_memory.h"
+#include "pipe/internal/p_winsys_screen.h"
+#include "pipe/p_shader_tokens.h"
+#include "draw/draw_context.h"
+#include "tgsi/tgsi_dump.h"
+#include "tgsi/tgsi_scan.h"
+#include "tgsi/tgsi_parse.h"
+
+
+void *
+llvmpipe_create_fs_state(struct pipe_context *pipe,
+                         const struct pipe_shader_state *templ)
+{
+   struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
+   struct lp_fragment_shader *state;
+
+   /* debug */
+   if (llvmpipe->dump_fs) 
+      tgsi_dump(templ->tokens, 0);
+
+   /* codegen */
+   state = llvmpipe_create_fs_llvm( llvmpipe, templ );
+   if (!state) {
+      state = llvmpipe_create_fs_sse( llvmpipe, templ );
+      if (!state) {
+         state = llvmpipe_create_fs_exec( llvmpipe, templ );
+      }
+   }
+
+   assert(state);
+
+   /* get/save the summary info for this shader */
+   tgsi_scan_shader(templ->tokens, &state->info);
+
+   return state;
+}
+
+
+void
+llvmpipe_bind_fs_state(struct pipe_context *pipe, void *fs)
+{
+   struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
+
+   llvmpipe->fs = (struct lp_fragment_shader *) fs;
+
+   llvmpipe->dirty |= SP_NEW_FS;
+}
+
+
+void
+llvmpipe_delete_fs_state(struct pipe_context *pipe, void *fs)
+{
+   struct lp_fragment_shader *state = fs;
+
+   assert(fs != llvmpipe_context(pipe)->fs);
+   
+   state->delete( state );
+}
+
+
+void *
+llvmpipe_create_vs_state(struct pipe_context *pipe,
+                         const struct pipe_shader_state *templ)
+{
+   struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
+   struct lp_vertex_shader *state;
+
+   state = CALLOC_STRUCT(lp_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(llvmpipe->draw, templ);
+   if (state->draw_data == NULL) 
+      goto fail;
+
+   return state;
+
+fail:
+   if (state) {
+      FREE( (void *)state->shader.tokens );
+      FREE( state->draw_data );
+      FREE( state );
+   }
+   return NULL;
+}
+
+
+void
+llvmpipe_bind_vs_state(struct pipe_context *pipe, void *vs)
+{
+   struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
+
+   llvmpipe->vs = (const struct lp_vertex_shader *)vs;
+
+   draw_bind_vertex_shader(llvmpipe->draw,
+                           (llvmpipe->vs ? llvmpipe->vs->draw_data : NULL));
+
+   llvmpipe->dirty |= SP_NEW_VS;
+}
+
+
+void
+llvmpipe_delete_vs_state(struct pipe_context *pipe, void *vs)
+{
+   struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
+
+   struct lp_vertex_shader *state =
+      (struct lp_vertex_shader *)vs;
+
+   draw_delete_vertex_shader(llvmpipe->draw, state->draw_data);
+   FREE( state );
+}
+
+
+
+void
+llvmpipe_set_constant_buffer(struct pipe_context *pipe,
+                             uint shader, uint index,
+                             const struct pipe_constant_buffer *buf)
+{
+   struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
+
+   assert(shader < PIPE_SHADER_TYPES);
+   assert(index == 0);
+
+   /* note: reference counting */
+   pipe_buffer_reference(&llvmpipe->constants[shader].buffer,
+                        buf ? buf->buffer : NULL);
+
+   llvmpipe->dirty |= SP_NEW_CONSTANTS;
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_state_rasterizer.c b/src/gallium/drivers/llvmpipe/lp_state_rasterizer.c
new file mode 100644 (file)
index 0000000..9e38606
--- /dev/null
@@ -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.
+ * 
+ **************************************************************************/
+
+#include "pipe/p_defines.h"
+#include "util/u_memory.h"
+#include "lp_context.h"
+#include "lp_state.h"
+#include "draw/draw_context.h"
+
+
+
+void *
+llvmpipe_create_rasterizer_state(struct pipe_context *pipe,
+                                 const struct pipe_rasterizer_state *rast)
+{
+   return mem_dup(rast, sizeof(*rast));
+}
+
+void llvmpipe_bind_rasterizer_state(struct pipe_context *pipe,
+                                    void *setup)
+{
+   struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
+
+   /* pass-through to draw module */
+   draw_set_rasterizer_state(llvmpipe->draw, setup);
+
+   llvmpipe->rasterizer = (struct pipe_rasterizer_state *)setup;
+
+   llvmpipe->dirty |= SP_NEW_RASTERIZER;
+}
+
+void llvmpipe_delete_rasterizer_state(struct pipe_context *pipe,
+                                      void *rasterizer)
+{
+   FREE( rasterizer );
+}
+
+
diff --git a/src/gallium/drivers/llvmpipe/lp_state_sampler.c b/src/gallium/drivers/llvmpipe/lp_state_sampler.c
new file mode 100644 (file)
index 0000000..790c123
--- /dev/null
@@ -0,0 +1,117 @@
+/**************************************************************************
+ * 
+ * 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 "draw/draw_context.h"
+
+#include "lp_context.h"
+#include "lp_context.h"
+#include "lp_state.h"
+#include "lp_texture.h"
+#include "lp_tile_cache.h"
+#include "draw/draw_context.h"
+
+
+
+void *
+llvmpipe_create_sampler_state(struct pipe_context *pipe,
+                              const struct pipe_sampler_state *sampler)
+{
+   return mem_dup(sampler, sizeof(*sampler));
+}
+
+
+void
+llvmpipe_bind_sampler_states(struct pipe_context *pipe,
+                             unsigned num, void **sampler)
+{
+   struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
+   unsigned i;
+
+   assert(num <= PIPE_MAX_SAMPLERS);
+
+   /* Check for no-op */
+   if (num == llvmpipe->num_samplers &&
+       !memcmp(llvmpipe->sampler, sampler, num * sizeof(void *)))
+      return;
+
+   draw_flush(llvmpipe->draw);
+
+   for (i = 0; i < num; ++i)
+      llvmpipe->sampler[i] = sampler[i];
+   for (i = num; i < PIPE_MAX_SAMPLERS; ++i)
+      llvmpipe->sampler[i] = NULL;
+
+   llvmpipe->num_samplers = num;
+
+   llvmpipe->dirty |= SP_NEW_SAMPLER;
+}
+
+
+void
+llvmpipe_set_sampler_textures(struct pipe_context *pipe,
+                              unsigned num, struct pipe_texture **texture)
+{
+   struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
+   uint i;
+
+   assert(num <= PIPE_MAX_SAMPLERS);
+
+   /* Check for no-op */
+   if (num == llvmpipe->num_textures &&
+       !memcmp(llvmpipe->texture, texture, num * sizeof(struct pipe_texture *)))
+      return;
+
+   draw_flush(llvmpipe->draw);
+
+   for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
+      struct pipe_texture *tex = i < num ? texture[i] : NULL;
+
+      pipe_texture_reference(&llvmpipe->texture[i], tex);
+      lp_tile_cache_set_texture(pipe, llvmpipe->tex_cache[i], tex);
+   }
+
+   llvmpipe->num_textures = num;
+
+   llvmpipe->dirty |= SP_NEW_TEXTURE;
+}
+
+
+void
+llvmpipe_delete_sampler_state(struct pipe_context *pipe,
+                              void *sampler)
+{
+   FREE( sampler );
+}
+
+
+
diff --git a/src/gallium/drivers/llvmpipe/lp_state_surface.c b/src/gallium/drivers/llvmpipe/lp_state_surface.c
new file mode 100644 (file)
index 0000000..d71e1a7
--- /dev/null
@@ -0,0 +1,129 @@
+/**************************************************************************
+ * 
+ * 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 "lp_context.h"
+#include "lp_state.h"
+#include "lp_surface.h"
+#include "lp_tile_cache.h"
+
+#include "draw/draw_context.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
+llvmpipe_set_framebuffer_state(struct pipe_context *pipe,
+                               const struct pipe_framebuffer_state *fb)
+{
+   struct llvmpipe_context *lp = llvmpipe_context(pipe);
+   uint i;
+
+   for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) {
+      /* check if changing cbuf */
+      if (lp->framebuffer.cbufs[i] != fb->cbufs[i]) {
+         /* flush old */
+         lp_flush_tile_cache(lp, lp->cbuf_cache[i]);
+
+         /* assign new */
+         lp->framebuffer.cbufs[i] = fb->cbufs[i];
+
+         /* update cache */
+         lp_tile_cache_set_surface(lp->cbuf_cache[i], fb->cbufs[i]);
+      }
+   }
+
+   lp->framebuffer.nr_cbufs = fb->nr_cbufs;
+
+   /* zbuf changing? */
+   if (lp->framebuffer.zsbuf != fb->zsbuf) {
+      /* flush old */
+      lp_flush_tile_cache(lp, lp->zsbuf_cache);
+
+      /* assign new */
+      lp->framebuffer.zsbuf = fb->zsbuf;
+
+      /* update cache */
+      lp_tile_cache_set_surface(lp->zsbuf_cache, fb->zsbuf);
+   }
+
+#if 0
+   /* XXX combined depth/stencil here */
+
+   /* sbuf changing? */
+   if (lp->framebuffer.sbuf != fb->sbuf) {
+      /* flush old */
+      lp_flush_tile_cache(lp, lp->sbuf_cache_sep);
+
+      /* assign new */
+      lp->framebuffer.sbuf = fb->sbuf;
+
+      /* update cache */
+      if (fb->sbuf != fb->zbuf) {
+         /* separate stencil buf */
+         lp->sbuf_cache = lp->sbuf_cache_sep;
+         lp_tile_cache_set_surface(lp->sbuf_cache, fb->sbuf);
+      }
+      else {
+         /* combined depth/stencil */
+         lp->sbuf_cache = lp->zbuf_cache;
+         lp_tile_cache_set_surface(lp->sbuf_cache, fb->sbuf);
+      }
+   }
+#endif
+
+   /* Tell draw module how deep the Z/depth buffer is */
+   {
+      int depth_bits;
+      double mrd;
+      if (lp->framebuffer.zsbuf) {
+         depth_bits = pf_get_component_bits(lp->framebuffer.zsbuf->format,
+                                            PIPE_FORMAT_COMP_Z);
+      }
+      else {
+         depth_bits = 0;
+      }
+      if (depth_bits > 16) {
+         mrd = 0.0000001;
+      }
+      else {
+         mrd = 0.00002;
+      }
+      draw_set_mrd(lp->draw, mrd);
+   }
+
+   lp->framebuffer.width = fb->width;
+   lp->framebuffer.height = fb->height;
+
+   lp->dirty |= SP_NEW_FRAMEBUFFER;
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_state_vertex.c b/src/gallium/drivers/llvmpipe/lp_state_vertex.c
new file mode 100644 (file)
index 0000000..68c0e94
--- /dev/null
@@ -0,0 +1,73 @@
+/**************************************************************************
+ * 
+ * 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 "lp_context.h"
+#include "lp_state.h"
+#include "lp_surface.h"
+
+#include "draw/draw_context.h"
+
+
+void
+llvmpipe_set_vertex_elements(struct pipe_context *pipe,
+                             unsigned count,
+                             const struct pipe_vertex_element *attribs)
+{
+   struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
+
+   assert(count <= PIPE_MAX_ATTRIBS);
+
+   memcpy(llvmpipe->vertex_element, attribs,
+          count * sizeof(struct pipe_vertex_element));
+   llvmpipe->num_vertex_elements = count;
+
+   llvmpipe->dirty |= SP_NEW_VERTEX;
+
+   draw_set_vertex_elements(llvmpipe->draw, count, attribs);
+}
+
+
+void
+llvmpipe_set_vertex_buffers(struct pipe_context *pipe,
+                            unsigned count,
+                            const struct pipe_vertex_buffer *buffers)
+{
+   struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
+
+   assert(count <= PIPE_MAX_ATTRIBS);
+
+   memcpy(llvmpipe->vertex_buffer, buffers, count * sizeof(buffers[0]));
+   llvmpipe->num_vertex_buffers = count;
+
+   llvmpipe->dirty |= SP_NEW_VERTEX;
+
+   draw_set_vertex_buffers(llvmpipe->draw, count, buffers);
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_surface.c b/src/gallium/drivers/llvmpipe/lp_surface.c
new file mode 100644 (file)
index 0000000..6110b0a
--- /dev/null
@@ -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.
+ * 
+ **************************************************************************/
+
+#include "util/u_rect.h"
+#include "lp_context.h"
+#include "lp_surface.h"
+
+
+static void
+lp_surface_copy(struct pipe_context *pipe,
+                struct pipe_surface *dest, unsigned destx, unsigned desty,
+                struct pipe_surface *src, unsigned srcx, unsigned srcy,
+                unsigned width, unsigned height)
+{
+   util_surface_copy(pipe, FALSE,
+                     dest, destx, desty,
+                     src, srcx, srcy,
+                     width, height);
+}
+
+void
+lp_init_surface_functions(struct llvmpipe_context *lp)
+{
+   lp->pipe.surface_copy = lp_surface_copy;
+   lp->pipe.surface_fill = util_surface_fill;
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_surface.h b/src/gallium/drivers/llvmpipe/lp_surface.h
new file mode 100644 (file)
index 0000000..8ed8f55
--- /dev/null
@@ -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 llvmpipe_context;
+
+
+extern void
+lp_init_surface_functions(struct llvmpipe_context *lp);
+
+
+#endif /* SP_SURFACE_H */
diff --git a/src/gallium/drivers/llvmpipe/lp_tex_sample.c b/src/gallium/drivers/llvmpipe/lp_tex_sample.c
new file mode 100644 (file)
index 0000000..f9f20ac
--- /dev/null
@@ -0,0 +1,1295 @@
+/**************************************************************************
+ * 
+ * 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.
+ * 
+ **************************************************************************/
+
+/**
+ * Texture sampling
+ *
+ * Authors:
+ *   Brian Paul
+ */
+
+#include "lp_context.h"
+#include "lp_quad.h"
+#include "lp_surface.h"
+#include "lp_texture.h"
+#include "lp_tex_sample.h"
+#include "lp_tile_cache.h"
+#include "pipe/p_context.h"
+#include "pipe/p_defines.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
+
+
+
+/*
+ * Note, the FRAC macro has to work perfectly.  Otherwise you'll sometimes
+ * see 1-pixel bands of improperly weighted linear-filtered textures.
+ * The tests/texwrap.c demo is a good test.
+ * Also note, FRAC(x) doesn't truly return the fractional part of x for x < 0.
+ * Instead, if x < 0 then FRAC(x) = 1 - true_frac(x).
+ */
+#define FRAC(f)  ((f) - util_ifloor(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);
+}
+
+
+
+/**
+ * If A is a signed integer, A % B doesn't give the right value for A < 0
+ * (in terms of texture repeat).  Just casting to unsigned fixes that.
+ */
+#define REMAINDER(A, B) ((unsigned) (A) % (unsigned) (B))
+
+
+/**
+ * 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 INLINE void
+nearest_texcoord_4(unsigned wrapMode, const float s[4], unsigned size,
+                   int icoord[4])
+{
+   uint ch;
+   switch (wrapMode) {
+   case PIPE_TEX_WRAP_REPEAT:
+      /* 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] = REMAINDER(i, size);
+      }
+      return;
+   case PIPE_TEX_WRAP_CLAMP:
+      /* 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);
+      }
+      return;
+   case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
+      {
+         /* 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);
+         }
+      }
+      return;
+   case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
+      {
+         /* 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);
+         }
+      }
+      return;
+   case PIPE_TEX_WRAP_MIRROR_REPEAT:
+      {
+         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;
+            if (flr & 1)
+               u = 1.0F - (s[ch] - (float) flr);
+            else
+               u = s[ch] - (float) flr;
+            if (u < min)
+               icoord[ch] = 0;
+            else if (u > max)
+               icoord[ch] = size - 1;
+            else
+               icoord[ch] = util_ifloor(u * size);
+         }
+      }
+      return;
+   case PIPE_TEX_WRAP_MIRROR_CLAMP:
+      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);
+      }
+      return;
+   case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
+      {
+         /* 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);
+         }
+      }
+      return;
+   case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
+      {
+         /* 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);
+         }
+      }
+      return;
+   default:
+      assert(0);
+   }
+}
+
+
+/**
+ * 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 INLINE void
+linear_texcoord_4(unsigned wrapMode, const float s[4], unsigned size,
+                  int icoord0[4], int icoord1[4], float w[4])
+{
+   uint ch;
+
+   switch (wrapMode) {
+   case PIPE_TEX_WRAP_REPEAT:
+      for (ch = 0; ch < 4; ch++) {
+         float u = s[ch] * size - 0.5F;
+         icoord0[ch] = REMAINDER(util_ifloor(u), size);
+         icoord1[ch] = REMAINDER(icoord0[ch] + 1, size);
+         w[ch] = FRAC(u);
+      }
+      break;;
+   case PIPE_TEX_WRAP_CLAMP:
+      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);
+      }
+      break;;
+   case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
+      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);
+      }
+      break;;
+   case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
+      {
+         const float min = -1.0F / (2.0F * size);
+         const float max = 1.0F - min;
+         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);
+         }
+      }
+      break;;
+   case PIPE_TEX_WRAP_MIRROR_REPEAT:
+      for (ch = 0; ch < 4; ch++) {
+         const int flr = util_ifloor(s[ch]);
+         float u;
+         if (flr & 1)
+            u = 1.0F - (s[ch] - (float) flr);
+         else
+            u = s[ch] - (float) flr;
+         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);
+      }
+      break;;
+   case PIPE_TEX_WRAP_MIRROR_CLAMP:
+      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);
+      }
+      break;;
+   case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
+      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);
+      }
+      break;;
+   case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
+      {
+         const float min = -1.0F / (2.0F * size);
+         const float max = 1.0F - min;
+         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);
+         }
+      }
+      break;;
+   default:
+      assert(0);
+   }
+}
+
+
+/**
+ * For RECT textures / unnormalized texcoords
+ * Only a subset of wrap modes supported.
+ */
+static INLINE void
+nearest_texcoord_unnorm_4(unsigned wrapMode, const float s[4], unsigned size,
+                          int icoord[4])
+{
+   uint ch;
+   switch (wrapMode) {
+   case PIPE_TEX_WRAP_CLAMP:
+      for (ch = 0; ch < 4; ch++) {
+         int i = util_ifloor(s[ch]);
+         icoord[ch]= CLAMP(i, 0, (int) size-1);
+      }
+      return;
+   case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
+      /* fall-through */
+   case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
+      for (ch = 0; ch < 4; ch++) {
+         icoord[ch]= util_ifloor( CLAMP(s[ch], 0.5F, (float) size - 0.5F) );
+      }
+      return;
+   default:
+      assert(0);
+   }
+}
+
+
+/**
+ * For RECT textures / unnormalized texcoords.
+ * Only a subset of wrap modes supported.
+ */
+static INLINE void
+linear_texcoord_unnorm_4(unsigned wrapMode, const float s[4], unsigned size,
+                         int icoord0[4], int icoord1[4], float w[4])
+{
+   uint ch;
+   switch (wrapMode) {
+   case PIPE_TEX_WRAP_CLAMP:
+      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);
+      }
+      return;
+   case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
+      /* fall-through */
+   case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
+      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);
+      }
+      break;
+   default:
+      assert(0);
+   }
+}
+
+
+static unsigned
+choose_cube_face(float rx, float ry, float rz, float *newS, float *newT)
+{
+   /*
+      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
+   */
+   const float arx = fabsf(rx), ary = fabsf(ry), arz = fabsf(rz);
+   unsigned face;
+   float sc, tc, ma;
+
+   if (arx > ary && arx > arz) {
+      if (rx >= 0.0F) {
+         face = PIPE_TEX_FACE_POS_X;
+         sc = -rz;
+         tc = -ry;
+         ma = arx;
+      }
+      else {
+         face = PIPE_TEX_FACE_NEG_X;
+         sc = rz;
+         tc = -ry;
+         ma = arx;
+      }
+   }
+   else if (ary > arx && ary > arz) {
+      if (ry >= 0.0F) {
+         face = PIPE_TEX_FACE_POS_Y;
+         sc = rx;
+         tc = rz;
+         ma = ary;
+      }
+      else {
+         face = PIPE_TEX_FACE_NEG_Y;
+         sc = rx;
+         tc = -rz;
+         ma = ary;
+      }
+   }
+   else {
+      if (rz > 0.0F) {
+         face = PIPE_TEX_FACE_POS_Z;
+         sc = rx;
+         tc = -ry;
+         ma = arz;
+      }
+      else {
+         face = PIPE_TEX_FACE_NEG_Z;
+         sc = -rx;
+         tc = -ry;
+         ma = arz;
+      }
+   }
+
+   *newS = ( sc / ma + 1.0F ) * 0.5F;
+   *newT = ( tc / ma + 1.0F ) * 0.5F;
+
+   return face;
+}
+
+
+/**
+ * Examine the quad's texture coordinates to compute the partial
+ * derivatives w.r.t X and Y, then compute lambda (level of detail).
+ *
+ * This is only done for fragment shaders, not vertex shaders.
+ */
+static float
+compute_lambda(const struct pipe_texture *tex,
+               const struct pipe_sampler_state *sampler,
+               const float s[QUAD_SIZE],
+               const float t[QUAD_SIZE],
+               const float p[QUAD_SIZE],
+               float lodbias)
+{
+   float rho, lambda;
+
+   assert(sampler->normalized_coords);
+
+   assert(s);
+   {
+      float dsdx = s[QUAD_BOTTOM_RIGHT] - s[QUAD_BOTTOM_LEFT];
+      float dsdy = s[QUAD_TOP_LEFT]     - s[QUAD_BOTTOM_LEFT];
+      dsdx = fabsf(dsdx);
+      dsdy = fabsf(dsdy);
+      rho = MAX2(dsdx, dsdy) * tex->width[0];
+   }
+   if (t) {
+      float dtdx = t[QUAD_BOTTOM_RIGHT] - t[QUAD_BOTTOM_LEFT];
+      float dtdy = t[QUAD_TOP_LEFT]     - t[QUAD_BOTTOM_LEFT];
+      float max;
+      dtdx = fabsf(dtdx);
+      dtdy = fabsf(dtdy);
+      max = MAX2(dtdx, dtdy) * tex->height[0];
+      rho = MAX2(rho, max);
+   }
+   if (p) {
+      float dpdx = p[QUAD_BOTTOM_RIGHT] - p[QUAD_BOTTOM_LEFT];
+      float dpdy = p[QUAD_TOP_LEFT]     - p[QUAD_BOTTOM_LEFT];
+      float max;
+      dpdx = fabsf(dpdx);
+      dpdy = fabsf(dpdy);
+      max = MAX2(dpdx, dpdy) * tex->depth[0];
+      rho = MAX2(rho, max);
+   }
+
+   lambda = util_fast_log2(rho);
+   lambda += lodbias + sampler->lod_bias;
+   lambda = CLAMP(lambda, sampler->min_lod, sampler->max_lod);
+
+   return lambda;
+}
+
+
+/**
+ * Do several things here:
+ * 1. Compute lambda from the texcoords, if needed
+ * 2. Determine if we're minifying or magnifying
+ * 3. If minifying, choose mipmap levels
+ * 4. Return image filter to use within mipmap images
+ * \param level0  Returns first mipmap level to sample from
+ * \param level1  Returns second mipmap level to sample from
+ * \param levelBlend  Returns blend factor between levels, in [0,1]
+ * \param imgFilter  Returns either the min or mag filter, depending on lambda
+ */
+static void
+choose_mipmap_levels(const struct pipe_texture *texture,
+                     const struct pipe_sampler_state *sampler,
+                     const float s[QUAD_SIZE],
+                     const float t[QUAD_SIZE],
+                     const float p[QUAD_SIZE],
+                     boolean computeLambda,
+                     float lodbias,
+                     unsigned *level0, unsigned *level1, float *levelBlend,
+                     unsigned *imgFilter)
+{
+   if (sampler->min_mip_filter == PIPE_TEX_MIPFILTER_NONE) {
+      /* no mipmap selection needed */
+      *level0 = *level1 = CLAMP((int) sampler->min_lod,
+                                0, (int) texture->last_level);
+
+      if (sampler->min_img_filter != sampler->mag_img_filter) {
+         /* non-mipmapped texture, but still need to determine if doing
+          * minification or magnification.
+          */
+         float lambda = compute_lambda(texture, sampler, s, t, p, lodbias);
+         if (lambda <= 0.0) {
+            *imgFilter = sampler->mag_img_filter;
+         }
+         else {
+            *imgFilter = sampler->min_img_filter;
+         }
+      }
+      else {
+         *imgFilter = sampler->mag_img_filter;
+      }
+   }
+   else {
+      float lambda;
+
+      if (computeLambda)
+         /* fragment shader */
+         lambda = compute_lambda(texture, sampler, s, t, p, lodbias);
+      else
+         /* vertex shader */
+         lambda = lodbias; /* not really a bias, but absolute LOD */
+
+      if (lambda <= 0.0) { /* XXX threshold depends on the filter */
+         /* magnifying */
+         *imgFilter = sampler->mag_img_filter;
+         *level0 = *level1 = 0;
+      }
+      else {
+         /* minifying */
+         *imgFilter = sampler->min_img_filter;
+
+         /* choose mipmap level(s) and compute the blend factor between them */
+         if (sampler->min_mip_filter == PIPE_TEX_MIPFILTER_NEAREST) {
+            /* Nearest mipmap level */
+            const int lvl = (int) (lambda + 0.5);
+            *level0 =
+            *level1 = CLAMP(lvl, 0, (int) texture->last_level);
+         }
+         else {
+            /* Linear interpolation between mipmap levels */
+            const int lvl = (int) lambda;
+            *level0 = CLAMP(lvl,     0, (int) texture->last_level);
+            *level1 = CLAMP(lvl + 1, 0, (int) texture->last_level);
+            *levelBlend = FRAC(lambda);  /* blending weight between levels */
+         }
+      }
+   }
+}
+
+
+/**
+ * Get a texel from a texture, using the texture tile cache.
+ *
+ * \param face  the cube face in 0..5
+ * \param level  the mipmap level
+ * \param x  the x coord of texel within 2D image
+ * \param y  the y coord of texel within 2D image
+ * \param z  which slice of a 3D texture
+ * \param rgba  the quad to put the texel/color into
+ * \param j  which element of the rgba quad to write to
+ *
+ * XXX maybe move this into lp_tile_cache.c and merge with the
+ * lp_get_cached_tile_tex() function.  Also, get 4 texels instead of 1...
+ */
+static void
+get_texel(const struct tgsi_sampler *tgsi_sampler,
+          unsigned face, unsigned level, int x, int y, int z,
+          float rgba[NUM_CHANNELS][QUAD_SIZE], unsigned j)
+{
+   const struct lp_shader_sampler *samp = lp_shader_sampler(tgsi_sampler);
+   struct llvmpipe_context *lp = samp->lp;
+   const uint unit = samp->unit;
+   const struct pipe_texture *texture = lp->texture[unit];
+   const struct pipe_sampler_state *sampler = lp->sampler[unit];
+
+   if (x < 0 || x >= (int) texture->width[level] ||
+       y < 0 || y >= (int) texture->height[level] ||
+       z < 0 || z >= (int) texture->depth[level]) {
+      rgba[0][j] = sampler->border_color[0];
+      rgba[1][j] = sampler->border_color[1];
+      rgba[2][j] = sampler->border_color[2];
+      rgba[3][j] = sampler->border_color[3];
+   }
+   else {
+      const int tx = x % TILE_SIZE;
+      const int ty = y % TILE_SIZE;
+      const struct llvmpipe_cached_tile *tile
+         = lp_get_cached_tile_tex(lp, samp->cache,
+                                  x, y, z, face, level);
+      rgba[0][j] = tile->data.color[ty][tx][0];
+      rgba[1][j] = tile->data.color[ty][tx][1];
+      rgba[2][j] = tile->data.color[ty][tx][2];
+      rgba[3][j] = tile->data.color[ty][tx][3];
+      if (0)
+      {
+         debug_printf("Get texel %f %f %f %f from %s\n",
+                      rgba[0][j], rgba[1][j], rgba[2][j], rgba[3][j],
+                      pf_name(texture->format));
+      }
+   }
+}
+
+
+/**
+ * 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.
+ * \param rgba  quad of (depth) texel values
+ * \param p  texture 'P' components for four pixels in quad
+ * \param j  which pixel in the quad to test [0..3]
+ */
+static INLINE void
+shadow_compare(const struct pipe_sampler_state *sampler,
+               float rgba[NUM_CHANNELS][QUAD_SIZE],
+               const float p[QUAD_SIZE],
+               uint j)
+{
+   int k;
+   switch (sampler->compare_func) {
+   case PIPE_FUNC_LESS:
+      k = p[j] < rgba[0][j];
+      break;
+   case PIPE_FUNC_LEQUAL:
+      k = p[j] <= rgba[0][j];
+      break;
+   case PIPE_FUNC_GREATER:
+      k = p[j] > rgba[0][j];
+      break;
+   case PIPE_FUNC_GEQUAL:
+      k = p[j] >= rgba[0][j];
+      break;
+   case PIPE_FUNC_EQUAL:
+      k = p[j] == rgba[0][j];
+      break;
+   case PIPE_FUNC_NOTEQUAL:
+      k = p[j] != rgba[0][j];
+      break;
+   case PIPE_FUNC_ALWAYS:
+      k = 1;
+      break;
+   case PIPE_FUNC_NEVER:
+      k = 0;
+      break;
+   default:
+      k = 0;
+      assert(0);
+      break;
+   }
+
+   /* XXX returning result for default GL_DEPTH_TEXTURE_MODE = GL_LUMINANCE */
+   rgba[0][j] = rgba[1][j] = rgba[2][j] = (float) k;
+   rgba[3][j] = 1.0F;
+}
+
+
+/**
+ * As above, but do four z/texture comparisons.
+ */
+static INLINE void
+shadow_compare4(const struct pipe_sampler_state *sampler,
+                float rgba[NUM_CHANNELS][QUAD_SIZE],
+                const float p[QUAD_SIZE])
+{
+   int j, k0, k1, k2, k3;
+   float val;
+
+   /* 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;
+   }
+}
+
+
+/**
+ * Common code for sampling 1D/2D/cube textures.
+ * Could probably extend for 3D...
+ */
+static void
+lp_get_samples_2d_common(const struct tgsi_sampler *tgsi_sampler,
+                         const float s[QUAD_SIZE],
+                         const float t[QUAD_SIZE],
+                         const float p[QUAD_SIZE],
+                         boolean computeLambda,
+                         float lodbias,
+                         float rgba[NUM_CHANNELS][QUAD_SIZE],
+                         const unsigned faces[4])
+{
+   const struct lp_shader_sampler *samp = lp_shader_sampler(tgsi_sampler);
+   const struct llvmpipe_context *lp = samp->lp;
+   const uint unit = samp->unit;
+   const struct pipe_texture *texture = lp->texture[unit];
+   const struct pipe_sampler_state *sampler = lp->sampler[unit];
+   unsigned level0, level1, j, imgFilter;
+   int width, height;
+   float levelBlend;
+
+   choose_mipmap_levels(texture, sampler, s, t, p, computeLambda, lodbias,
+                        &level0, &level1, &levelBlend, &imgFilter);
+
+   assert(sampler->normalized_coords);
+
+   width = texture->width[level0];
+   height = texture->height[level0];
+
+   assert(width > 0);
+
+   switch (imgFilter) {
+   case PIPE_TEX_FILTER_NEAREST:
+      {
+         int x[4], y[4];
+         nearest_texcoord_4(sampler->wrap_s, s, width, x);
+         nearest_texcoord_4(sampler->wrap_t, t, height, y);
+
+         for (j = 0; j < QUAD_SIZE; j++) {
+            get_texel(tgsi_sampler, faces[j], level0, x[j], y[j], 0, rgba, j);
+            if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
+               shadow_compare(sampler, rgba, p, j);
+            }
+
+            if (level0 != level1) {
+               /* get texels from second mipmap level and blend */
+               float rgba2[4][4];
+               unsigned c;
+               x[j] /= 2;
+               y[j] /= 2;
+               get_texel(tgsi_sampler, faces[j], level1, x[j], y[j], 0,
+                         rgba2, j);
+               if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE){
+                  shadow_compare(sampler, rgba2, p, j);
+               }
+
+               for (c = 0; c < NUM_CHANNELS; c++) {
+                  rgba[c][j] = lerp(levelBlend, rgba[c][j], rgba2[c][j]);
+               }
+            }
+         }
+      }
+      break;
+   case PIPE_TEX_FILTER_LINEAR:
+   case PIPE_TEX_FILTER_ANISO:
+      {
+         int x0[4], y0[4], x1[4], y1[4];
+         float xw[4], yw[4]; /* weights */
+
+         linear_texcoord_4(sampler->wrap_s, s, width, x0, x1, xw);
+         linear_texcoord_4(sampler->wrap_t, t, height, y0, y1, yw);
+
+         for (j = 0; j < QUAD_SIZE; j++) {
+            float tx[4][4]; /* texels */
+            int c;
+            get_texel(tgsi_sampler, faces[j], level0, x0[j], y0[j], 0, tx, 0);
+            get_texel(tgsi_sampler, faces[j], level0, x1[j], y0[j], 0, tx, 1);
+            get_texel(tgsi_sampler, faces[j], level0, x0[j], y1[j], 0, tx, 2);
+            get_texel(tgsi_sampler, faces[j], level0, x1[j], y1[j], 0, tx, 3);
+            if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
+               shadow_compare4(sampler, tx, p);
+            }
+
+            /* interpolate R, G, B, A */
+            for (c = 0; c < 4; c++) {
+               rgba[c][j] = lerp_2d(xw[j], yw[j],
+                                    tx[c][0], tx[c][1],
+                                    tx[c][2], tx[c][3]);
+            }
+
+            if (level0 != level1) {
+               /* get texels from second mipmap level and blend */
+               float rgba2[4][4];
+               x0[j] /= 2;
+               y0[j] /= 2;
+               x1[j] /= 2;
+               y1[j] /= 2;
+               get_texel(tgsi_sampler, faces[j], level1, x0[j], y0[j], 0, tx, 0);
+               get_texel(tgsi_sampler, faces[j], level1, x1[j], y0[j], 0, tx, 1);
+               get_texel(tgsi_sampler, faces[j], level1, x0[j], y1[j], 0, tx, 2);
+               get_texel(tgsi_sampler, faces[j], level1, x1[j], y1[j], 0, tx, 3);
+               if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE){
+                  shadow_compare4(sampler, tx, p);
+               }
+
+               /* interpolate R, G, B, A */
+               for (c = 0; c < 4; c++) {
+                  rgba2[c][j] = lerp_2d(xw[j], yw[j],
+                                        tx[c][0], tx[c][1], tx[c][2], tx[c][3]);
+               }
+
+               for (c = 0; c < NUM_CHANNELS; c++) {
+                  rgba[c][j] = lerp(levelBlend, rgba[c][j], rgba2[c][j]);
+               }
+            }
+         }
+      }
+      break;
+   default:
+      assert(0);
+   }
+}
+
+
+static INLINE void
+lp_get_samples_1d(const struct tgsi_sampler *sampler,
+                  const float s[QUAD_SIZE],
+                  const float t[QUAD_SIZE],
+                  const float p[QUAD_SIZE],
+                  boolean computeLambda,
+                  float lodbias,
+                  float rgba[NUM_CHANNELS][QUAD_SIZE])
+{
+   static const unsigned faces[4] = {0, 0, 0, 0};
+   static const float tzero[4] = {0, 0, 0, 0};
+   lp_get_samples_2d_common(sampler, s, tzero, NULL,
+                            computeLambda, lodbias, rgba, faces);
+}
+
+
+static INLINE void
+lp_get_samples_2d(const struct tgsi_sampler *sampler,
+                  const float s[QUAD_SIZE],
+                  const float t[QUAD_SIZE],
+                  const float p[QUAD_SIZE],
+                  boolean computeLambda,
+                  float lodbias,
+                  float rgba[NUM_CHANNELS][QUAD_SIZE])
+{
+   static const unsigned faces[4] = {0, 0, 0, 0};
+   lp_get_samples_2d_common(sampler, s, t, p,
+                            computeLambda, lodbias, rgba, faces);
+}
+
+
+static INLINE void
+lp_get_samples_3d(const struct tgsi_sampler *tgsi_sampler,
+                  const float s[QUAD_SIZE],
+                  const float t[QUAD_SIZE],
+                  const float p[QUAD_SIZE],
+                  boolean computeLambda,
+                  float lodbias,
+                  float rgba[NUM_CHANNELS][QUAD_SIZE])
+{
+   const struct lp_shader_sampler *samp = lp_shader_sampler(tgsi_sampler);
+   const struct llvmpipe_context *lp = samp->lp;
+   const uint unit = samp->unit;
+   const struct pipe_texture *texture = lp->texture[unit];
+   const struct pipe_sampler_state *sampler = lp->sampler[unit];
+   /* get/map pipe_surfaces corresponding to 3D tex slices */
+   unsigned level0, level1, j, imgFilter;
+   int width, height, depth;
+   float levelBlend;
+   const uint face = 0;
+
+   choose_mipmap_levels(texture, sampler, s, t, p, computeLambda, lodbias,
+                        &level0, &level1, &levelBlend, &imgFilter);
+
+   assert(sampler->normalized_coords);
+
+   width = texture->width[level0];
+   height = texture->height[level0];
+   depth = texture->depth[level0];
+
+   assert(width > 0);
+   assert(height > 0);
+   assert(depth > 0);
+
+   switch (imgFilter) {
+   case PIPE_TEX_FILTER_NEAREST:
+      {
+         int x[4], y[4], z[4];
+         nearest_texcoord_4(sampler->wrap_s, s, width, x);
+         nearest_texcoord_4(sampler->wrap_t, t, height, y);
+         nearest_texcoord_4(sampler->wrap_r, p, depth, z);
+         for (j = 0; j < QUAD_SIZE; j++) {
+            get_texel(tgsi_sampler, face, level0, x[j], y[j], z[j], rgba, j);
+            if (level0 != level1) {
+               /* get texels from second mipmap level and blend */
+               float rgba2[4][4];
+               unsigned c;
+               x[j] /= 2;
+               y[j] /= 2;
+               z[j] /= 2;
+               get_texel(tgsi_sampler, face, level1, x[j], y[j], z[j], rgba2, j);
+               for (c = 0; c < NUM_CHANNELS; c++) {
+                  rgba[c][j] = lerp(levelBlend, rgba2[c][j], rgba[c][j]);
+               }
+            }
+         }
+      }
+      break;
+   case PIPE_TEX_FILTER_LINEAR:
+   case PIPE_TEX_FILTER_ANISO:
+      {
+         int x0[4], x1[4], y0[4], y1[4], z0[4], z1[4];
+         float xw[4], yw[4], zw[4]; /* interpolation weights */
+         linear_texcoord_4(sampler->wrap_s, s, width,  x0, x1, xw);
+         linear_texcoord_4(sampler->wrap_t, t, height, y0, y1, yw);
+         linear_texcoord_4(sampler->wrap_r, p, depth,  z0, z1, zw);
+
+         for (j = 0; j < QUAD_SIZE; j++) {
+            int c;
+            float tx0[4][4], tx1[4][4];
+            get_texel(tgsi_sampler, face, level0, x0[j], y0[j], z0[j], tx0, 0);
+            get_texel(tgsi_sampler, face, level0, x1[j], y0[j], z0[j], tx0, 1);
+            get_texel(tgsi_sampler, face, level0, x0[j], y1[j], z0[j], tx0, 2);
+            get_texel(tgsi_sampler, face, level0, x1[j], y1[j], z0[j], tx0, 3);
+            get_texel(tgsi_sampler, face, level0, x0[j], y0[j], z1[j], tx1, 0);
+            get_texel(tgsi_sampler, face, level0, x1[j], y0[j], z1[j], tx1, 1);
+            get_texel(tgsi_sampler, face, level0, x0[j], y1[j], z1[j], tx1, 2);
+            get_texel(tgsi_sampler, face, level0, x1[j], y1[j], z1[j], tx1, 3);
+
+            /* interpolate R, G, B, A */
+            for (c = 0; c < 4; c++) {
+               rgba[c][j] = lerp_3d(xw[j], yw[j], zw[j],
+                                    tx0[c][0], tx0[c][1],
+                                    tx0[c][2], tx0[c][3],
+                                    tx1[c][0], tx1[c][1],
+                                    tx1[c][2], tx1[c][3]);
+            }
+
+            if (level0 != level1) {
+               /* get texels from second mipmap level and blend */
+               float rgba2[4][4];
+               x0[j] /= 2;
+               y0[j] /= 2;
+               z0[j] /= 2;
+               x1[j] /= 2;
+               y1[j] /= 2;
+               z1[j] /= 2;
+               get_texel(tgsi_sampler, face, level1, x0[j], y0[j], z0[j], tx0, 0);
+               get_texel(tgsi_sampler, face, level1, x1[j], y0[j], z0[j], tx0, 1);
+               get_texel(tgsi_sampler, face, level1, x0[j], y1[j], z0[j], tx0, 2);
+               get_texel(tgsi_sampler, face, level1, x1[j], y1[j], z0[j], tx0, 3);
+               get_texel(tgsi_sampler, face, level1, x0[j], y0[j], z1[j], tx1, 0);
+               get_texel(tgsi_sampler, face, level1, x1[j], y0[j], z1[j], tx1, 1);
+               get_texel(tgsi_sampler, face, level1, x0[j], y1[j], z1[j], tx1, 2);
+               get_texel(tgsi_sampler, face, level1, x1[j], y1[j], z1[j], tx1, 3);
+
+               /* interpolate R, G, B, A */
+               for (c = 0; c < 4; c++) {
+                  rgba2[c][j] = lerp_3d(xw[j], yw[j], zw[j],
+                                        tx0[c][0], tx0[c][1],
+                                        tx0[c][2], tx0[c][3],
+                                        tx1[c][0], tx1[c][1],
+                                        tx1[c][2], tx1[c][3]);
+               }
+
+               /* blend mipmap levels */
+               for (c = 0; c < NUM_CHANNELS; c++) {
+                  rgba[c][j] = lerp(levelBlend, rgba[c][j], rgba2[c][j]);
+               }
+            }
+         }
+      }
+      break;
+   default:
+      assert(0);
+   }
+}
+
+
+static void
+lp_get_samples_cube(const struct tgsi_sampler *sampler,
+                    const float s[QUAD_SIZE],
+                    const float t[QUAD_SIZE],
+                    const float p[QUAD_SIZE],
+                    boolean computeLambda,
+                    float lodbias,
+                    float rgba[NUM_CHANNELS][QUAD_SIZE])
+{
+   unsigned faces[QUAD_SIZE], j;
+   float ssss[4], tttt[4];
+   for (j = 0; j < QUAD_SIZE; j++) {
+      faces[j] = choose_cube_face(s[j], t[j], p[j], ssss + j, tttt + j);
+   }
+   lp_get_samples_2d_common(sampler, ssss, tttt, NULL,
+                            computeLambda, lodbias, rgba, faces);
+}
+
+
+static void
+lp_get_samples_rect(const struct tgsi_sampler *tgsi_sampler,
+                    const float s[QUAD_SIZE],
+                    const float t[QUAD_SIZE],
+                    const float p[QUAD_SIZE],
+                    boolean computeLambda,
+                    float lodbias,
+                    float rgba[NUM_CHANNELS][QUAD_SIZE])
+{
+   const struct lp_shader_sampler *samp = lp_shader_sampler(tgsi_sampler);
+   const struct llvmpipe_context *lp = samp->lp;
+   const uint unit = samp->unit;
+   const struct pipe_texture *texture = lp->texture[unit];
+   const struct pipe_sampler_state *sampler = lp->sampler[unit];
+   const uint face = 0;
+   unsigned level0, level1, j, imgFilter;
+   int width, height;
+   float levelBlend;
+
+   choose_mipmap_levels(texture, sampler, s, t, p, computeLambda, lodbias,
+                        &level0, &level1, &levelBlend, &imgFilter);
+
+   /* texture RECTS cannot be mipmapped */
+   assert(level0 == level1);
+
+   width = texture->width[level0];
+   height = texture->height[level0];
+
+   assert(width > 0);
+
+   switch (imgFilter) {
+   case PIPE_TEX_FILTER_NEAREST:
+      {
+         int x[4], y[4];
+         nearest_texcoord_unnorm_4(sampler->wrap_s, s, width, x);
+         nearest_texcoord_unnorm_4(sampler->wrap_t, t, height, y);
+         for (j = 0; j < QUAD_SIZE; j++) {
+            get_texel(tgsi_sampler, face, level0, x[j], y[j], 0, rgba, j);
+            if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
+               shadow_compare(sampler, rgba, p, j);
+            }
+         }
+      }
+      break;
+   case PIPE_TEX_FILTER_LINEAR:
+   case PIPE_TEX_FILTER_ANISO:
+      {
+         int x0[4], y0[4], x1[4], y1[4];
+         float xw[4], yw[4]; /* weights */
+         linear_texcoord_unnorm_4(sampler->wrap_s, s, width,  x0, x1, xw);
+         linear_texcoord_unnorm_4(sampler->wrap_t, t, height, y0, y1, yw);
+         for (j = 0; j < QUAD_SIZE; j++) {
+            float tx[4][4]; /* texels */
+            int c;
+            get_texel(tgsi_sampler, face, level0, x0[j], y0[j], 0, tx, 0);
+            get_texel(tgsi_sampler, face, level0, x1[j], y0[j], 0, tx, 1);
+            get_texel(tgsi_sampler, face, level0, x0[j], y1[j], 0, tx, 2);
+            get_texel(tgsi_sampler, face, level0, x1[j], y1[j], 0, tx, 3);
+            if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
+               shadow_compare4(sampler, tx, p);
+            }
+            for (c = 0; c < 4; c++) {
+               rgba[c][j] = lerp_2d(xw[j], yw[j],
+                                    tx[c][0], tx[c][1], tx[c][2], tx[c][3]);
+            }
+         }
+      }
+      break;
+   default:
+      assert(0);
+   }
+}
+
+
+/**
+ * Common code for vertex/fragment program texture sampling.
+ */
+static INLINE void
+lp_get_samples(struct tgsi_sampler *tgsi_sampler,
+               const float s[QUAD_SIZE],
+               const float t[QUAD_SIZE],
+               const float p[QUAD_SIZE],
+               boolean computeLambda,
+               float lodbias,
+               float rgba[NUM_CHANNELS][QUAD_SIZE])
+{
+   const struct lp_shader_sampler *samp = lp_shader_sampler(tgsi_sampler);
+   const struct llvmpipe_context *lp = samp->lp;
+   const uint unit = samp->unit;
+   const struct pipe_texture *texture = lp->texture[unit];
+   const struct pipe_sampler_state *sampler = lp->sampler[unit];
+
+   if (!texture)
+      return;
+
+   switch (texture->target) {
+   case PIPE_TEXTURE_1D:
+      assert(sampler->normalized_coords);
+      lp_get_samples_1d(tgsi_sampler, s, t, p, computeLambda, lodbias, rgba);
+      break;
+   case PIPE_TEXTURE_2D:
+      if (sampler->normalized_coords)
+         lp_get_samples_2d(tgsi_sampler, s, t, p, computeLambda, lodbias, rgba);
+      else
+         lp_get_samples_rect(tgsi_sampler, s, t, p, computeLambda, lodbias, rgba);
+      break;
+   case PIPE_TEXTURE_3D:
+      assert(sampler->normalized_coords);
+      lp_get_samples_3d(tgsi_sampler, s, t, p, computeLambda, lodbias, rgba);
+      break;
+   case PIPE_TEXTURE_CUBE:
+      assert(sampler->normalized_coords);
+      lp_get_samples_cube(tgsi_sampler, s, t, p, computeLambda, lodbias, rgba);
+      break;
+   default:
+      assert(0);
+   }
+
+#if 0 /* DEBUG */
+   {
+      int i;
+      printf("Sampled at %f, %f, %f:\n", s[0], t[0], p[0]);
+      for (i = 0; i < 4; i++) {
+         printf("Frag %d: %f %f %f %f\n", i,
+                rgba[0][i],
+                rgba[1][i],
+                rgba[2][i],
+                rgba[3][i]);
+      }
+   }
+#endif
+}
+
+
+/**
+ * Called via tgsi_sampler::get_samples() when running a fragment shader.
+ * Get four filtered RGBA values from the sampler's texture.
+ */
+void
+lp_get_samples_fragment(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])
+{
+   lp_get_samples(tgsi_sampler, s, t, p, TRUE, lodbias, rgba);
+}
+
+
+/**
+ * Called via tgsi_sampler::get_samples() when running a vertex shader.
+ * Get four filtered RGBA values from the sampler's texture.
+ */
+void
+lp_get_samples_vertex(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])
+{
+   lp_get_samples(tgsi_sampler, s, t, p, FALSE, lodbias, rgba);
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_tex_sample.h b/src/gallium/drivers/llvmpipe/lp_tex_sample.h
new file mode 100644 (file)
index 0000000..3cf292d
--- /dev/null
@@ -0,0 +1,73 @@
+/**************************************************************************
+ * 
+ * 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_SAMPLE_H
+#define SP_TEX_SAMPLE_H
+
+
+#include "tgsi/tgsi_exec.h"
+
+
+/**
+ * Subclass of tgsi_sampler
+ */
+struct lp_shader_sampler
+{
+   struct tgsi_sampler base;  /**< base class */
+
+   uint unit;
+   struct llvmpipe_context *lp;
+   struct llvmpipe_tile_cache *cache;
+};
+
+
+
+static INLINE const struct lp_shader_sampler *
+lp_shader_sampler(const struct tgsi_sampler *sampler)
+{
+   return (const struct lp_shader_sampler *) sampler;
+}
+
+
+extern void
+lp_get_samples_fragment(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]);
+
+extern void
+lp_get_samples_vertex(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/llvmpipe/lp_texture.c b/src/gallium/drivers/llvmpipe/lp_texture.c
new file mode 100644 (file)
index 0000000..fd9b518
--- /dev/null
@@ -0,0 +1,421 @@
+/**************************************************************************
+ * 
+ * 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_context.h"
+#include "pipe/p_defines.h"
+#include "pipe/p_inlines.h"
+#include "pipe/internal/p_winsys_screen.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
+
+#include "lp_context.h"
+#include "lp_state.h"
+#include "lp_texture.h"
+#include "lp_tile_cache.h"
+#include "lp_screen.h"
+#include "lp_winsys.h"
+
+
+/* Simple, maximally packed layout.
+ */
+
+static unsigned minify( unsigned d )
+{
+   return MAX2(1, d>>1);
+}
+
+
+/* Conventional allocation path for non-display textures:
+ */
+static boolean
+llvmpipe_texture_layout(struct pipe_screen *screen,
+                        struct llvmpipe_texture * lpt)
+{
+   struct pipe_texture *pt = &lpt->base;
+   unsigned level;
+   unsigned width = pt->width[0];
+   unsigned height = pt->height[0];
+   unsigned depth = pt->depth[0];
+
+   unsigned buffer_size = 0;
+
+   for (level = 0; level <= pt->last_level; level++) {
+      pt->width[level] = width;
+      pt->height[level] = height;
+      pt->depth[level] = depth;
+      pt->nblocksx[level] = pf_get_nblocksx(&pt->block, width);  
+      pt->nblocksy[level] = pf_get_nblocksy(&pt->block, height);  
+      lpt->stride[level] = pt->nblocksx[level]*pt->block.size;
+
+      lpt->level_offset[level] = buffer_size;
+
+      buffer_size += (pt->nblocksy[level] *
+                      ((pt->target == PIPE_TEXTURE_CUBE) ? 6 : depth) *
+                      lpt->stride[level]);
+
+      width  = minify(width);
+      height = minify(height);
+      depth = minify(depth);
+   }
+
+   lpt->buffer = screen->buffer_create(screen, 32,
+                                       PIPE_BUFFER_USAGE_PIXEL,
+                                       buffer_size);
+
+   return lpt->buffer != NULL;
+}
+
+static boolean
+llvmpipe_displaytarget_layout(struct pipe_screen *screen,
+                              struct llvmpipe_texture * lpt)
+{
+   unsigned usage = (PIPE_BUFFER_USAGE_CPU_READ_WRITE |
+                     PIPE_BUFFER_USAGE_GPU_READ_WRITE);
+
+   lpt->base.nblocksx[0] = pf_get_nblocksx(&lpt->base.block, lpt->base.width[0]);  
+   lpt->base.nblocksy[0] = pf_get_nblocksy(&lpt->base.block, lpt->base.height[0]);  
+
+   lpt->buffer = screen->surface_buffer_create( screen, 
+                                                lpt->base.width[0], 
+                                                lpt->base.height[0],
+                                                lpt->base.format,
+                                                usage,
+                                                &lpt->stride[0]);
+
+   return lpt->buffer != NULL;
+}
+
+
+
+
+
+static struct pipe_texture *
+llvmpipe_texture_create(struct pipe_screen *screen,
+                        const struct pipe_texture *templat)
+{
+   struct llvmpipe_texture *lpt = CALLOC_STRUCT(llvmpipe_texture);
+   if (!lpt)
+      return NULL;
+
+   lpt->base = *templat;
+   pipe_reference_init(&lpt->base.reference, 1);
+   lpt->base.screen = screen;
+
+   if (lpt->base.tex_usage & PIPE_TEXTURE_USAGE_DISPLAY_TARGET) {
+      if (!llvmpipe_displaytarget_layout(screen, lpt))
+         goto fail;
+   }
+   else {
+      if (!llvmpipe_texture_layout(screen, lpt))
+         goto fail;
+   }
+    
+   return &lpt->base;
+
+ fail:
+   FREE(lpt);
+   return NULL;
+}
+
+
+static struct pipe_texture *
+llvmpipe_texture_blanket(struct pipe_screen * screen,
+                         const struct pipe_texture *base,
+                         const unsigned *stride,
+                         struct pipe_buffer *buffer)
+{
+   struct llvmpipe_texture *lpt;
+   assert(screen);
+
+   /* Only supports one type */
+   if (base->target != PIPE_TEXTURE_2D ||
+       base->last_level != 0 ||
+       base->depth[0] != 1) {
+      return NULL;
+   }
+
+   lpt = CALLOC_STRUCT(llvmpipe_texture);
+   if (!lpt)
+      return NULL;
+
+   lpt->base = *base;
+   pipe_reference_init(&lpt->base.reference, 1);
+   lpt->base.screen = screen;
+   lpt->base.nblocksx[0] = pf_get_nblocksx(&lpt->base.block, lpt->base.width[0]);  
+   lpt->base.nblocksy[0] = pf_get_nblocksy(&lpt->base.block, lpt->base.height[0]);  
+   lpt->stride[0] = stride[0];
+
+   pipe_buffer_reference(&lpt->buffer, buffer);
+
+   return &lpt->base;
+}
+
+
+static void
+llvmpipe_texture_destroy(struct pipe_texture *pt)
+{
+   struct llvmpipe_texture *lpt = llvmpipe_texture(pt);
+
+   pipe_buffer_reference(&lpt->buffer, NULL);
+   FREE(lpt);
+}
+
+
+static struct pipe_surface *
+llvmpipe_get_tex_surface(struct pipe_screen *screen,
+                         struct pipe_texture *pt,
+                         unsigned face, unsigned level, unsigned zslice,
+                         unsigned usage)
+{
+   struct llvmpipe_texture *lpt = llvmpipe_texture(pt);
+   struct pipe_surface *ps;
+
+   assert(level <= pt->last_level);
+
+   ps = CALLOC_STRUCT(pipe_surface);
+   if (ps) {
+      pipe_reference_init(&ps->reference, 1);
+      pipe_texture_reference(&ps->texture, pt);
+      ps->format = pt->format;
+      ps->width = pt->width[level];
+      ps->height = pt->height[level];
+      ps->offset = lpt->level_offset[level];
+      ps->usage = usage;
+
+      /* Because we are llvmpipe, anything that the state tracker
+       * thought was going to be done with the GPU will actually get
+       * done with the CPU.  Let's adjust the flags to take that into
+       * account.
+       */
+      if (ps->usage & PIPE_BUFFER_USAGE_GPU_WRITE) {
+         /* GPU_WRITE means "render" and that can involve reads (blending) */
+         ps->usage |= PIPE_BUFFER_USAGE_CPU_WRITE | PIPE_BUFFER_USAGE_CPU_READ;
+      }
+
+      if (ps->usage & PIPE_BUFFER_USAGE_GPU_READ)
+         ps->usage |= PIPE_BUFFER_USAGE_CPU_READ;
+
+      if (ps->usage & (PIPE_BUFFER_USAGE_CPU_WRITE |
+                       PIPE_BUFFER_USAGE_GPU_WRITE)) {
+         /* Mark the surface as dirty.  The tile cache will look for this. */
+         lpt->modified = TRUE;
+      }
+
+      ps->face = face;
+      ps->level = level;
+      ps->zslice = zslice;
+
+      if (pt->target == PIPE_TEXTURE_CUBE) {
+         ps->offset += face * pt->nblocksy[level] * lpt->stride[level];
+      }
+      else if (pt->target == PIPE_TEXTURE_3D) {
+         ps->offset += zslice * pt->nblocksy[level] * lpt->stride[level];
+      }
+      else {
+         assert(face == 0);
+         assert(zslice == 0);
+      }
+   }
+   return ps;
+}
+
+
+static void 
+llvmpipe_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 llvmpipe, nothing to do.
+    */
+   assert(surf->texture);
+   pipe_texture_reference(&surf->texture, NULL);
+   FREE(surf);
+}
+
+
+static struct pipe_transfer *
+llvmpipe_get_tex_transfer(struct pipe_screen *screen,
+                          struct pipe_texture *texture,
+                          unsigned face, unsigned level, unsigned zslice,
+                          enum pipe_transfer_usage usage,
+                          unsigned x, unsigned y, unsigned w, unsigned h)
+{
+   struct llvmpipe_texture *lptex = llvmpipe_texture(texture);
+   struct llvmpipe_transfer *lpt;
+
+   assert(texture);
+   assert(level <= texture->last_level);
+
+   lpt = CALLOC_STRUCT(llvmpipe_transfer);
+   if (lpt) {
+      struct pipe_transfer *pt = &lpt->base;
+      pipe_texture_reference(&pt->texture, texture);
+      pt->format = texture->format;
+      pt->block = texture->block;
+      pt->x = x;
+      pt->y = y;
+      pt->width = w;
+      pt->height = h;
+      pt->nblocksx = texture->nblocksx[level];
+      pt->nblocksy = texture->nblocksy[level];
+      pt->stride = lptex->stride[level];
+      pt->usage = usage;
+      pt->face = face;
+      pt->level = level;
+      pt->zslice = zslice;
+
+      lpt->offset = lptex->level_offset[level];
+
+      if (texture->target == PIPE_TEXTURE_CUBE) {
+         lpt->offset += face * pt->nblocksy * pt->stride;
+      }
+      else if (texture->target == PIPE_TEXTURE_3D) {
+         lpt->offset += zslice * pt->nblocksy * pt->stride;
+      }
+      else {
+         assert(face == 0);
+         assert(zslice == 0);
+      }
+      return pt;
+   }
+   return NULL;
+}
+
+
+static void 
+llvmpipe_tex_transfer_destroy(struct pipe_transfer *transfer)
+{
+   /* 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 llvmpipe, nothing to do.
+    */
+   assert (transfer->texture);
+   pipe_texture_reference(&transfer->texture, NULL);
+   FREE(transfer);
+}
+
+
+static void *
+llvmpipe_transfer_map( struct pipe_screen *screen,
+                       struct pipe_transfer *transfer )
+{
+   ubyte *map, *xfer_map;
+   struct llvmpipe_texture *lpt;
+   unsigned flags = 0;
+
+   assert(transfer->texture);
+   lpt = llvmpipe_texture(transfer->texture);
+
+   if (transfer->usage != PIPE_TRANSFER_READ) {
+      flags |= PIPE_BUFFER_USAGE_CPU_WRITE;
+   }
+
+   if (transfer->usage != PIPE_TRANSFER_WRITE) {
+      flags |= PIPE_BUFFER_USAGE_CPU_READ;
+   }
+
+   map = pipe_buffer_map(screen, lpt->buffer, flags);
+   if (map == NULL)
+      return NULL;
+
+   /* May want to different things here depending on read/write nature
+    * of the map:
+    */
+   if (transfer->texture && transfer->usage != PIPE_TRANSFER_READ) 
+   {
+      /* Do something to notify sharing contexts of a texture change.
+       * In llvmpipe, that would mean flushing the texture cache.
+       */
+      llvmpipe_screen(screen)->timestamp++;
+   }
+   
+   xfer_map = map + llvmpipe_transfer(transfer)->offset +
+      transfer->y / transfer->block.height * transfer->stride +
+      transfer->x / transfer->block.width * transfer->block.size;
+   /*printf("map = %p  xfer map = %p\n", map, xfer_map);*/
+   return xfer_map;
+}
+
+
+static void
+llvmpipe_transfer_unmap(struct pipe_screen *screen,
+                       struct pipe_transfer *transfer)
+{
+   struct llvmpipe_texture *lpt;
+
+   assert(transfer->texture);
+   lpt = llvmpipe_texture(transfer->texture);
+
+   pipe_buffer_unmap( screen, lpt->buffer );
+}
+
+
+void
+llvmpipe_init_texture_funcs(struct llvmpipe_context *lp)
+{
+}
+
+
+void
+llvmpipe_init_screen_texture_funcs(struct pipe_screen *screen)
+{
+   screen->texture_create = llvmpipe_texture_create;
+   screen->texture_blanket = llvmpipe_texture_blanket;
+   screen->texture_destroy = llvmpipe_texture_destroy;
+
+   screen->get_tex_surface = llvmpipe_get_tex_surface;
+   screen->tex_surface_destroy = llvmpipe_tex_surface_destroy;
+
+   screen->get_tex_transfer = llvmpipe_get_tex_transfer;
+   screen->tex_transfer_destroy = llvmpipe_tex_transfer_destroy;
+   screen->transfer_map = llvmpipe_transfer_map;
+   screen->transfer_unmap = llvmpipe_transfer_unmap;
+}
+
+
+boolean
+llvmpipe_get_texture_buffer( struct pipe_texture *texture,
+                             struct pipe_buffer **buf,
+                             unsigned *stride )
+{
+   struct llvmpipe_texture *tex = (struct llvmpipe_texture *)texture;
+
+   if (!tex)
+      return FALSE;
+
+   pipe_buffer_reference(buf, tex->buffer);
+
+   if (stride)
+      *stride = tex->stride[0];
+
+   return TRUE;
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_texture.h b/src/gallium/drivers/llvmpipe/lp_texture.h
new file mode 100644 (file)
index 0000000..23b37c6
--- /dev/null
@@ -0,0 +1,83 @@
+/**************************************************************************
+ * 
+ * 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"
+
+
+struct pipe_context;
+struct pipe_screen;
+struct llvmpipe_context;
+
+
+struct llvmpipe_texture
+{
+   struct pipe_texture base;
+
+   unsigned long level_offset[PIPE_MAX_TEXTURE_LEVELS];
+   unsigned stride[PIPE_MAX_TEXTURE_LEVELS];
+
+   /* The data is held here:
+    */
+   struct pipe_buffer *buffer;
+
+   boolean modified;
+};
+
+struct llvmpipe_transfer
+{
+   struct pipe_transfer base;
+
+   unsigned long offset;
+};
+
+
+/** cast wrappers */
+static INLINE struct llvmpipe_texture *
+llvmpipe_texture(struct pipe_texture *pt)
+{
+   return (struct llvmpipe_texture *) pt;
+}
+
+static INLINE struct llvmpipe_transfer *
+llvmpipe_transfer(struct pipe_transfer *pt)
+{
+   return (struct llvmpipe_transfer *) pt;
+}
+
+
+extern void
+llvmpipe_init_texture_funcs( struct llvmpipe_context *llvmpipe );
+
+extern void
+llvmpipe_init_screen_texture_funcs(struct pipe_screen *screen);
+
+
+#endif /* SP_TEXTURE */
diff --git a/src/gallium/drivers/llvmpipe/lp_tile_cache.c b/src/gallium/drivers/llvmpipe/lp_tile_cache.c
new file mode 100644 (file)
index 0000000..870fa8a
--- /dev/null
@@ -0,0 +1,626 @@
+/**************************************************************************
+ * 
+ * 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 "pipe/p_inlines.h"
+#include "util/u_memory.h"
+#include "util/u_tile.h"
+#include "lp_context.h"
+#include "lp_surface.h"
+#include "lp_texture.h"
+#include "lp_tile_cache.h"
+
+#define NUM_ENTRIES 50
+
+
+/** XXX move these */
+#define MAX_WIDTH 2048
+#define MAX_HEIGHT 2048
+
+
+struct llvmpipe_tile_cache
+{
+   struct pipe_screen *screen;
+   struct pipe_surface *surface;  /**< the surface we're caching */
+   struct pipe_transfer *transfer;
+   void *transfer_map;
+   struct pipe_texture *texture;  /**< if caching a texture */
+   struct llvmpipe_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 pipe_transfer *tex_trans;
+   void *tex_trans_map;
+   int tex_face, tex_level, tex_z;
+
+   struct llvmpipe_cached_tile tile;  /**< scratch tile for clears */
+};
+
+
+/**
+ * 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) / TILE_SIZE + ((y) / TILE_SIZE) * 5) % NUM_ENTRIES)
+
+
+
+/**
+ * Is the tile at (x,y) in cleared state?
+ */
+static INLINE uint
+is_clear_flag_set(const uint *bitvec, int x, int y)
+{
+   int pos, bit;
+   x /= TILE_SIZE;
+   y /= TILE_SIZE;
+   pos = y * (MAX_WIDTH / TILE_SIZE) + 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, int x, int y)
+{
+   int pos;
+   x /= TILE_SIZE;
+   y /= TILE_SIZE;
+   pos = y * (MAX_WIDTH / TILE_SIZE) + x;
+   assert(pos / 32 < (MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32);
+   bitvec[pos / 32] &= ~(1 << (pos & 31));
+}
+   
+
+struct llvmpipe_tile_cache *
+lp_create_tile_cache( struct pipe_screen *screen )
+{
+   struct llvmpipe_tile_cache *tc;
+   uint pos;
+
+   tc = CALLOC_STRUCT( llvmpipe_tile_cache );
+   if (tc) {
+      tc->screen = screen;
+      for (pos = 0; pos < NUM_ENTRIES; pos++) {
+         tc->entries[pos].x =
+         tc->entries[pos].y = -1;
+      }
+   }
+   return tc;
+}
+
+
+void
+lp_destroy_tile_cache(struct llvmpipe_tile_cache *tc)
+{
+   struct pipe_screen *screen;
+   uint pos;
+
+   for (pos = 0; pos < NUM_ENTRIES; pos++) {
+      /*assert(tc->entries[pos].x < 0);*/
+   }
+   if (tc->transfer) {
+      screen = tc->transfer->texture->screen;
+      screen->tex_transfer_destroy(tc->transfer);
+   }
+   if (tc->tex_trans) {
+      screen = tc->tex_trans->texture->screen;
+      screen->tex_transfer_destroy(tc->tex_trans);
+   }
+
+   FREE( tc );
+}
+
+
+/**
+ * Specify the surface to cache.
+ */
+void
+lp_tile_cache_set_surface(struct llvmpipe_tile_cache *tc,
+                          struct pipe_surface *ps)
+{
+   assert(!tc->texture);
+
+   if (tc->transfer) {
+      struct pipe_screen *screen = tc->transfer->texture->screen;
+
+      if (ps == tc->surface)
+         return;
+
+      if (tc->transfer_map) {
+         screen->transfer_unmap(screen, tc->transfer);
+         tc->transfer_map = NULL;
+      }
+
+      screen->tex_transfer_destroy(tc->transfer);
+      tc->transfer = NULL;
+   }
+
+   tc->surface = ps;
+
+   if (ps) {
+      struct pipe_screen *screen = ps->texture->screen;
+
+      tc->transfer = screen->get_tex_transfer(screen, ps->texture, ps->face,
+                                              ps->level, ps->zslice,
+                                              PIPE_TRANSFER_READ_WRITE,
+                                              0, 0, ps->width, ps->height);
+
+      tc->depth_stencil = (ps->format == PIPE_FORMAT_S8Z24_UNORM ||
+                           ps->format == PIPE_FORMAT_X8Z24_UNORM ||
+                           ps->format == PIPE_FORMAT_Z24S8_UNORM ||
+                           ps->format == PIPE_FORMAT_Z24X8_UNORM ||
+                           ps->format == PIPE_FORMAT_Z16_UNORM ||
+                           ps->format == PIPE_FORMAT_Z32_UNORM ||
+                           ps->format == PIPE_FORMAT_S8_UNORM);
+   }
+}
+
+
+/**
+ * Return the transfer being cached.
+ */
+struct pipe_surface *
+lp_tile_cache_get_surface(struct llvmpipe_tile_cache *tc)
+{
+   return tc->surface;
+}
+
+
+void
+lp_tile_cache_map_transfers(struct llvmpipe_tile_cache *tc)
+{
+   if (tc->transfer && !tc->transfer_map)
+      tc->transfer_map = tc->screen->transfer_map(tc->screen, tc->transfer);
+
+   if (tc->tex_trans && !tc->tex_trans_map)
+      tc->tex_trans_map = tc->screen->transfer_map(tc->screen, tc->tex_trans);
+}
+
+
+void
+lp_tile_cache_unmap_transfers(struct llvmpipe_tile_cache *tc)
+{
+   if (tc->transfer_map) {
+      tc->screen->transfer_unmap(tc->screen, tc->transfer);
+      tc->transfer_map = NULL;
+   }
+
+   if (tc->tex_trans_map) {
+      tc->screen->transfer_unmap(tc->screen, tc->tex_trans);
+      tc->tex_trans_map = NULL;
+   }
+}
+
+
+/**
+ * Specify the texture to cache.
+ */
+void
+lp_tile_cache_set_texture(struct pipe_context *pipe,
+                          struct llvmpipe_tile_cache *tc,
+                          struct pipe_texture *texture)
+{
+   uint i;
+
+   assert(!tc->transfer);
+
+   pipe_texture_reference(&tc->texture, texture);
+
+   if (tc->tex_trans) {
+      struct pipe_screen *screen = tc->tex_trans->texture->screen;
+
+      if (tc->tex_trans_map) {
+         screen->transfer_unmap(screen, tc->tex_trans);
+         tc->tex_trans_map = NULL;
+      }
+
+      screen->tex_transfer_destroy(tc->tex_trans);
+      tc->tex_trans = NULL;
+   }
+
+   /* 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].x = -1;
+   }
+
+   tc->tex_face = -1; /* any invalid value here */
+}
+
+
+/**
+ * Set pixels in a tile to the given clear color/value, float.
+ */
+static void
+clear_tile_rgba(struct llvmpipe_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 llvmpipe_cached_tile *tile,
+           enum pipe_format format,
+           uint clear_value)
+{
+   uint i, j;
+
+   switch (pf_get_size(format)) {
+   case 1:
+      memset(tile->data.any, 0, 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
+lp_tile_cache_flush_clear(struct pipe_context *pipe,
+                          struct llvmpipe_tile_cache *tc)
+{
+   struct pipe_transfer *pt = tc->transfer;
+   const uint w = tc->transfer->width;
+   const uint h = tc->transfer->height;
+   uint x, y;
+   uint numCleared = 0;
+
+   /* clear the scratch tile to the clear value */
+   clear_tile(&tc->tile, pt->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) {
+         if (is_clear_flag_set(tc->clear_flags, x, y)) {
+            pipe_put_tile_raw(pt,
+                              x, y, TILE_SIZE, TILE_SIZE,
+                              tc->tile.data.color32, 0/*STRIDE*/);
+
+            /* do this? */
+            clear_clear_flag(tc->clear_flags, x, y);
+
+            numCleared++;
+         }
+      }
+   }
+#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
+lp_flush_tile_cache(struct llvmpipe_context *llvmpipe,
+                    struct llvmpipe_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 llvmpipe_cached_tile *tile = tc->entries + pos;
+         if (tile->x >= 0) {
+            if (tc->depth_stencil) {
+               pipe_put_tile_raw(pt,
+                                 tile->x, tile->y, TILE_SIZE, TILE_SIZE,
+                                 tile->data.depth32, 0/*STRIDE*/);
+            }
+            else {
+               pipe_put_tile_rgba(pt,
+                                  tile->x, tile->y, TILE_SIZE, TILE_SIZE,
+                                  (float *) tile->data.color);
+            }
+            tile->x = tile->y = -1;  /* mark as empty */
+            inuse++;
+         }
+      }
+
+#if TILE_CLEAR_OPTIMIZATION
+      lp_tile_cache_flush_clear(&llvmpipe->pipe, tc);
+#endif
+   }
+   else if (tc->texture) {
+      /* caching a texture, mark all entries as empty */
+      for (pos = 0; pos < NUM_ENTRIES; pos++) {
+         tc->entries[pos].x = -1;
+      }
+      tc->tex_face = -1;
+   }
+
+#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 llvmpipe_cached_tile *
+lp_get_cached_tile(struct llvmpipe_context *llvmpipe,
+                   struct llvmpipe_tile_cache *tc, int x, int y)
+{
+   struct pipe_transfer *pt = tc->transfer;
+
+   /* tile pos in framebuffer: */
+   const int tile_x = x & ~(TILE_SIZE - 1);
+   const int tile_y = y & ~(TILE_SIZE - 1);
+
+   /* cache pos/entry: */
+   const int pos = CACHE_POS(x, y);
+   struct llvmpipe_cached_tile *tile = tc->entries + pos;
+
+   if (tile_x != tile->x ||
+       tile_y != tile->y) {
+
+      if (tile->x != -1) {
+         /* put dirty tile back in framebuffer */
+         if (tc->depth_stencil) {
+            pipe_put_tile_raw(pt,
+                              tile->x, tile->y, TILE_SIZE, TILE_SIZE,
+                              tile->data.depth32, 0/*STRIDE*/);
+         }
+         else {
+            pipe_put_tile_rgba(pt,
+                               tile->x, tile->y, TILE_SIZE, TILE_SIZE,
+                               (float *) tile->data.color);
+         }
+      }
+
+      tile->x = tile_x;
+      tile->y = tile_y;
+
+      if (is_clear_flag_set(tc->clear_flags, x, y)) {
+         /* don't get tile from framebuffer, just clear it */
+         if (tc->depth_stencil) {
+            clear_tile(tile, pt->format, tc->clear_val);
+         }
+         else {
+            clear_tile_rgba(tile, pt->format, tc->clear_color);
+         }
+         clear_clear_flag(tc->clear_flags, x, y);
+      }
+      else {
+         /* get new tile data from transfer */
+         if (tc->depth_stencil) {
+            pipe_get_tile_raw(pt,
+                              tile->x, tile->y, TILE_SIZE, TILE_SIZE,
+                              tile->data.depth32, 0/*STRIDE*/);
+         }
+         else {
+            pipe_get_tile_rgba(pt,
+                               tile->x, tile->y, TILE_SIZE, TILE_SIZE,
+                               (float *) tile->data.color);
+         }
+      }
+   }
+
+   return tile;
+}
+
+
+/**
+ * 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(int x, int y, int z, int face, int level)
+{
+   uint entry = x + y * 9 + z * 3 + face + level * 7;
+   return entry % NUM_ENTRIES;
+}
+
+
+/**
+ * Similar to lp_get_cached_tile() but for textures.
+ * Tiles are read-only and indexed with more params.
+ */
+const struct llvmpipe_cached_tile *
+lp_get_cached_tile_tex(struct llvmpipe_context *lp,
+                       struct llvmpipe_tile_cache *tc, int x, int y, int z,
+                       int face, int level)
+{
+   struct pipe_screen *screen = lp->pipe.screen;
+   /* tile pos in framebuffer: */
+   const int tile_x = x & ~(TILE_SIZE - 1);
+   const int tile_y = y & ~(TILE_SIZE - 1);
+   /* cache pos/entry: */
+   const uint pos = tex_cache_pos(x / TILE_SIZE, y / TILE_SIZE, z,
+                                  face, level);
+   struct llvmpipe_cached_tile *tile = tc->entries + pos;
+
+   if (tc->texture) {
+      struct llvmpipe_texture *lpt = llvmpipe_texture(tc->texture);
+      if (lpt->modified) {
+         /* texture was modified, invalidate all cached tiles */
+         uint p;
+         for (p = 0; p < NUM_ENTRIES; p++) {
+            tile = tc->entries + p;
+            tile->x = -1;
+         }
+         lpt->modified = FALSE;
+      }
+   }
+
+   if (tile_x != tile->x ||
+       tile_y != tile->y ||
+       z != tile->z ||
+       face != tile->face ||
+       level != tile->level) {
+      /* cache miss */
+
+#if 0
+      printf("miss at %u  x=%d y=%d z=%d face=%d level=%d\n", pos,
+             x/TILE_SIZE, y/TILE_SIZE, z, face, level);
+#endif
+      /* check if we need to get a new transfer */
+      if (!tc->tex_trans ||
+          tc->tex_face != face ||
+          tc->tex_level != level ||
+          tc->tex_z != z) {
+         /* get new transfer (view into texture) */
+
+         if (tc->tex_trans) {
+            if (tc->tex_trans_map) {
+               tc->screen->transfer_unmap(tc->screen, tc->tex_trans);
+               tc->tex_trans_map = NULL;
+            }
+
+            screen->tex_transfer_destroy(tc->tex_trans);
+            tc->tex_trans = NULL;
+         }
+
+         tc->tex_trans = screen->get_tex_transfer(screen, tc->texture, face, level, z, 
+                                                  PIPE_TRANSFER_READ, 0, 0,
+                                                  tc->texture->width[level],
+                                                  tc->texture->height[level]);
+         tc->tex_trans_map = screen->transfer_map(screen, tc->tex_trans);
+
+         tc->tex_face = face;
+         tc->tex_level = level;
+         tc->tex_z = z;
+      }
+
+      /* get tile from the transfer (view into texture) */
+      pipe_get_tile_rgba(tc->tex_trans,
+                         tile_x, tile_y, TILE_SIZE, TILE_SIZE,
+                         (float *) tile->data.color);
+      tile->x = tile_x;
+      tile->y = tile_y;
+      tile->z = z;
+      tile->face = face;
+      tile->level = level;
+   }
+
+   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
+lp_tile_cache_clear(struct llvmpipe_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;
+
+#if TILE_CLEAR_OPTIMIZATION
+   /* set flags to indicate all the tiles are cleared */
+   memset(tc->clear_flags, 255, sizeof(tc->clear_flags));
+#else
+   /* disable the optimization */
+   memset(tc->clear_flags, 0, sizeof(tc->clear_flags));
+#endif
+
+   for (pos = 0; pos < NUM_ENTRIES; pos++) {
+      struct llvmpipe_cached_tile *tile = tc->entries + pos;
+      tile->x = tile->y = -1;
+   }
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_tile_cache.h b/src/gallium/drivers/llvmpipe/lp_tile_cache.h
new file mode 100644 (file)
index 0000000..ac3b17c
--- /dev/null
@@ -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.
+ * 
+ **************************************************************************/
+
+#ifndef SP_TILE_CACHE_H
+#define SP_TILE_CACHE_H
+
+#define TILE_CLEAR_OPTIMIZATION 1
+
+
+#include "pipe/p_compiler.h"
+
+
+struct llvmpipe_context;
+struct llvmpipe_tile_cache;
+
+
+/**
+ * Cache tile size (width and height). This needs to be a power of two.
+ */
+#define TILE_SIZE 64
+
+
+
+struct llvmpipe_cached_tile
+{
+   int x, y;           /**< pos of tile in window coords */
+   int z, face, level; /**< Extra texture indexes */
+   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;
+};
+
+
+extern struct llvmpipe_tile_cache *
+lp_create_tile_cache( struct pipe_screen *screen );
+
+extern void
+lp_destroy_tile_cache(struct llvmpipe_tile_cache *tc);
+
+extern void
+lp_tile_cache_set_surface(struct llvmpipe_tile_cache *tc,
+                          struct pipe_surface *lps);
+
+extern struct pipe_surface *
+lp_tile_cache_get_surface(struct llvmpipe_tile_cache *tc);
+
+extern void
+lp_tile_cache_map_transfers(struct llvmpipe_tile_cache *tc);
+
+extern void
+lp_tile_cache_unmap_transfers(struct llvmpipe_tile_cache *tc);
+
+extern void
+lp_tile_cache_set_texture(struct pipe_context *pipe,
+                          struct llvmpipe_tile_cache *tc,
+                          struct pipe_texture *texture);
+
+extern void
+lp_flush_tile_cache(struct llvmpipe_context *llvmpipe,
+                    struct llvmpipe_tile_cache *tc);
+
+extern void
+lp_tile_cache_clear(struct llvmpipe_tile_cache *tc, const float *rgba,
+                    uint clearValue);
+
+extern struct llvmpipe_cached_tile *
+lp_get_cached_tile(struct llvmpipe_context *llvmpipe,
+                   struct llvmpipe_tile_cache *tc, int x, int y);
+
+extern const struct llvmpipe_cached_tile *
+lp_get_cached_tile_tex(struct llvmpipe_context *llvmpipe,
+                       struct llvmpipe_tile_cache *tc, int x, int y, int z,
+                       int face, int level);
+
+
+#endif /* SP_TILE_CACHE_H */
+
diff --git a/src/gallium/drivers/llvmpipe/lp_winsys.h b/src/gallium/drivers/llvmpipe/lp_winsys.h
new file mode 100644 (file)
index 0000000..ec371c0
--- /dev/null
@@ -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.
+ * 
+ **************************************************************************/
+
+/* This is the interface that llvmpipe requires any window system
+ * hosting it to implement.  This is the only include file in llvmpipe
+ * which is public.
+ */
+
+
+#ifndef SP_WINSYS_H
+#define SP_WINSYS_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+struct pipe_screen;
+struct pipe_winsys;
+struct pipe_context;
+
+
+struct pipe_context *llvmpipe_create( struct pipe_screen * );
+
+
+struct pipe_screen *
+llvmpipe_create_screen(struct pipe_winsys *);
+
+
+boolean
+llvmpipe_get_texture_buffer( struct pipe_texture *texture,
+                             struct pipe_buffer **buf,
+                             unsigned *stride );
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SP_WINSYS_H */