OSDN Git Service

Merge remote branch 'origin/lp-binning'
authorJosé Fonseca <jfonseca@vmware.com>
Fri, 5 Feb 2010 13:48:35 +0000 (13:48 +0000)
committerJosé Fonseca <jfonseca@vmware.com>
Fri, 5 Feb 2010 13:48:35 +0000 (13:48 +0000)
Conflicts:
src/gallium/auxiliary/util/u_dl.c
src/gallium/auxiliary/util/u_time.h
src/gallium/drivers/llvmpipe/lp_state_derived.c
src/gallium/drivers/llvmpipe/lp_state_surface.c
src/gallium/drivers/llvmpipe/lp_tex_cache.c
src/gallium/drivers/llvmpipe/lp_tile_cache.c

21 files changed:
1  2 
src/gallium/auxiliary/os/os_thread.h
src/gallium/auxiliary/util/u_debug.c
src/gallium/auxiliary/util/u_debug.h
src/gallium/auxiliary/util/u_ringbuffer.c
src/gallium/auxiliary/util/u_surface.c
src/gallium/auxiliary/util/u_time.h
src/gallium/drivers/llvmpipe/SConscript
src/gallium/drivers/llvmpipe/lp_bld_logic.c
src/gallium/drivers/llvmpipe/lp_buffer.c
src/gallium/drivers/llvmpipe/lp_context.c
src/gallium/drivers/llvmpipe/lp_fence.c
src/gallium/drivers/llvmpipe/lp_fence.h
src/gallium/drivers/llvmpipe/lp_rast.c
src/gallium/drivers/llvmpipe/lp_rast_priv.h
src/gallium/drivers/llvmpipe/lp_scene.c
src/gallium/drivers/llvmpipe/lp_scene.h
src/gallium/drivers/llvmpipe/lp_setup.c
src/gallium/drivers/llvmpipe/lp_state_fs.c
src/gallium/drivers/llvmpipe/lp_state_sampler.c
src/gallium/drivers/llvmpipe/lp_state_surface.c
src/gallium/drivers/llvmpipe/lp_texture.c

@@@ -167,27 -235,9 +235,28 @@@ static INLINE void pipe_barrier_wait(pi
  /** Dummy definitions */
  
  typedef unsigned pipe_thread;
 +
 +#define PIPE_THREAD_ROUTINE( name, param ) \
 +   void * name( void *param )
 +
 +static INLINE pipe_thread pipe_thread_create( void *(* routine)( void *), void *param )
 +{
 +   return 0;
 +}
 +
 +static INLINE int pipe_thread_wait( pipe_thread thread )
 +{
 +   return -1;
 +}
 +
 +static INLINE int pipe_thread_destroy( pipe_thread thread )
 +{
 +   return -1;
 +}
 +
  typedef unsigned pipe_mutex;
  typedef unsigned pipe_condvar;
+ typedef unsigned pipe_barrier;
  
  #define pipe_static_mutex(mutex) \
     static pipe_mutex mutex = 0
Simple merge
Simple merge
@@@ -35,8 -35,8 +35,9 @@@
  #include "pipe/p_screen.h"
  #include "pipe/p_state.h"
  #include "pipe/p_defines.h"
 +#include "util/u_inlines.h"
  
+ #include "util/u_memory.h"
  #include "util/u_surface.h"
  
  
@@@ -59,76 -70,45 +59,88 @@@ struct util_tim
  };
     
  
 -void 
 -util_time_get(struct util_time *t);
 +PIPE_DEPRECATED
 +static INLINE void
 +util_time_get(struct util_time *t)
 +{
 +   t->counter = os_time_get();
 +}
 +
  
 -void 
+ /**
+  * Return t2 = t1 + usecs
+  */
 +PIPE_DEPRECATED
 +static INLINE void
  util_time_add(const struct util_time *t1,
                int64_t usecs,
 -              struct util_time *t2);
 +              struct util_time *t2)
 +{
 +   t2->counter = t1->counter + usecs;
 +}
  
 -/**
 - * Return current time in microseconds
 - */
 -uint64_t
 -util_time_micros( void );
  
 -int64_t
+ /**
+  * Return difference between times, in microseconds
+  */
 +PIPE_DEPRECATED
 +static INLINE int64_t
  util_time_diff(const struct util_time *t1, 
 -               const struct util_time *t2);
 +               const struct util_time *t2)
 +{
 +   return t2->counter - t1->counter;
 +}
 +
 +
 +/**
 + * Compare two time values.
 + *
 + * Not publicly available because it does not take in account wrap-arounds.
 + * Use util_time_timeout instead.
 + */
 +static INLINE int
 +_util_time_compare(const struct util_time *t1,
 +                   const struct util_time *t2)
 +{
 +   if (t1->counter < t2->counter)
 +      return -1;
 +   else if(t1->counter > t2->counter)
 +      return 1;
 +   else
 +      return 0;
 +}
 +
  
 -boolean 
+ /**
+  * Returns non-zero when the timeout expires.
+  */
 +PIPE_DEPRECATED
 +static INLINE boolean
  util_time_timeout(const struct util_time *start, 
                    const struct util_time *end,
 -                  const struct util_time *curr);
 +                  const struct util_time *curr)
 +{
 +   return os_time_timeout(start->counter, end->counter, curr->counter);
 +}
  
 -#if defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS) || defined(PIPE_OS_APPLE) || defined(PIPE_OS_HAIKU)
 -#define util_time_sleep usleep
 -#else
 -void
 -util_time_sleep(unsigned usecs);
 -#endif
 +
++/**
++ * Return current time in microseconds
++ */
 +PIPE_DEPRECATED
 +static INLINE int64_t
 +util_time_micros(void)
 +{
 +   return os_time_get();
 +}
 +
 +
 +PIPE_DEPRECATED
 +static INLINE void
 +util_time_sleep(int64_t usecs)
 +{
 +   os_time_sleep(usecs);
 +}
  
  
  #ifdef        __cplusplus
index 0000000,97c4608..525c117
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,109 +1,110 @@@
+ /**************************************************************************
+  *
+  * 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 VMWARE 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_screen.h"
+ #include "util/u_memory.h"
++#include "util/u_inlines.h"
+ #include "lp_fence.h"
+ struct lp_fence *
+ lp_fence_create(unsigned rank)
+ {
+    struct lp_fence *fence = CALLOC_STRUCT(lp_fence);
+    pipe_reference_init(&fence->reference, 1);
+    pipe_mutex_init(fence->mutex);
+    pipe_condvar_init(fence->signalled);
+    fence->rank = rank;
+    return fence;
+ }
+ static void
+ lp_fence_destroy(struct lp_fence *fence)
+ {
+    pipe_mutex_destroy(fence->mutex);
+    pipe_condvar_destroy(fence->signalled);
+    FREE(fence);
+ }
+ static void
+ llvmpipe_fence_reference(struct pipe_screen *screen,
+                          struct pipe_fence_handle **ptr,
+                          struct pipe_fence_handle *fence)
+ {
+    struct lp_fence *old = (struct lp_fence *) *ptr;
+    struct lp_fence *f = (struct lp_fence *) fence;
+    if (pipe_reference(&old->reference, &f->reference)) {
+       lp_fence_destroy(old);
+    }
+ }
+ static int
+ llvmpipe_fence_signalled(struct pipe_screen *screen,
+                          struct pipe_fence_handle *fence,
+                          unsigned flag)
+ {
+    struct lp_fence *f = (struct lp_fence *) fence;
+    return f->count == f->rank;
+ }
+ static int
+ llvmpipe_fence_finish(struct pipe_screen *screen,
+                       struct pipe_fence_handle *fence_handle,
+                       unsigned flag)
+ {
+    struct lp_fence *fence = (struct lp_fence *) fence_handle;
+    pipe_mutex_lock(fence->mutex);
+    while (fence->count < fence->rank) {
+       pipe_condvar_wait(fence->signalled, fence->mutex);
+    }
+    pipe_mutex_unlock(fence->mutex);
+    return 0;
+ }
+ void
+ llvmpipe_init_screen_fence_funcs(struct pipe_screen *screen)
+ {
+    screen->fence_reference = llvmpipe_fence_reference;
+    screen->fence_signalled = llvmpipe_fence_signalled;
+    screen->fence_finish = llvmpipe_fence_finish;
+ }
index 0000000,d45318f..c90e6de
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,60 +1,60 @@@
 -#include "pipe/p_refcnt.h"
 -#include "pipe/p_thread.h"
+ /**************************************************************************
+  *
+  * 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 VMWARE 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 LP_FENCE_H
+ #define LP_FENCE_H
++#include "os/os_thread.h"
++#include "pipe/p_state.h"
+ struct pipe_screen;
+ struct lp_fence
+ {
+    struct pipe_reference reference;
+    pipe_mutex mutex;
+    pipe_condvar signalled;
+    unsigned rank;
+    unsigned count;
+ };
+ struct lp_fence *
+ lp_fence_create(unsigned rank);
+ void
+ llvmpipe_init_screen_fence_funcs(struct pipe_screen *screen);
+ #endif /* LP_FENCE_H */
index 0000000,e27b652..54af850
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,1024 +1,1023 @@@
 -      printf("rasterize scene:\n");
 -      printf("  data size: %u\n", lp_scene_data_size(scene));
+ /**************************************************************************
+  *
+  * 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 VMWARE 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 <limits.h>
+ #include "util/u_memory.h"
+ #include "util/u_math.h"
+ #include "util/u_cpu_detect.h"
+ #include "util/u_surface.h"
+ #include "lp_scene_queue.h"
+ #include "lp_debug.h"
+ #include "lp_fence.h"
+ #include "lp_rast.h"
+ #include "lp_rast_priv.h"
+ #include "lp_tile_soa.h"
+ #include "lp_bld_debug.h"
+ #include "lp_scene.h"
+ /**
+  * Begin the rasterization phase.
+  * Map the framebuffer surfaces.  Initialize the 'rast' state.
+  */
+ static boolean
+ lp_rast_begin( struct lp_rasterizer *rast,
+                const struct pipe_framebuffer_state *fb,
+                boolean write_color,
+                boolean write_zstencil )
+ {
+    struct pipe_screen *screen = rast->screen;
+    struct pipe_surface *cbuf, *zsbuf;
+    int i;
+    LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
+    util_copy_framebuffer_state(&rast->state.fb, fb);
+    rast->state.write_zstencil = write_zstencil;
+    rast->state.write_color = write_color;
+    rast->check_for_clipped_tiles = (fb->width % TILE_SIZE != 0 ||
+                                     fb->height % TILE_SIZE != 0);
+    
+    for (i = 0; i < rast->state.fb.nr_cbufs; i++) {
+       cbuf = rast->state.fb.cbufs[i];
+       if (cbuf) {
+        rast->cbuf_transfer[i] = screen->get_tex_transfer(rast->screen,
+                                                          cbuf->texture,
+                                                          cbuf->face,
+                                                          cbuf->level,
+                                                          cbuf->zslice,
+                                                          PIPE_TRANSFER_READ_WRITE,
+                                                          0, 0,
+                                                          cbuf->width, 
+                                                          cbuf->height);
+        if (!rast->cbuf_transfer[i])
+           goto fail;
+        rast->cbuf_map[i] = screen->transfer_map(rast->screen, 
+                                                 rast->cbuf_transfer[i]);
+        if (!rast->cbuf_map[i])
+           goto fail;
+       }
+    }
+    zsbuf = rast->state.fb.zsbuf;
+    if (zsbuf) {
+       rast->zsbuf_transfer = screen->get_tex_transfer(rast->screen,
+                                                       zsbuf->texture,
+                                                       zsbuf->face,
+                                                       zsbuf->level,
+                                                       zsbuf->zslice,
+                                                       PIPE_TRANSFER_READ_WRITE,
+                                                       0, 0,
+                                                       zsbuf->width,
+                                                     zsbuf->height);
+       if (!rast->zsbuf_transfer)
+          goto fail;
+       rast->zsbuf_map = screen->transfer_map(rast->screen, 
+                                             rast->zsbuf_transfer);
+       if (!rast->zsbuf_map)
+        goto fail;
+    }
+    return TRUE;
+ fail:
+    /* Unmap and release transfers?
+     */
+    return FALSE;
+ }
+ /**
+  * Finish the rasterization phase.
+  * Unmap framebuffer surfaces.
+  */
+ static void
+ lp_rast_end( struct lp_rasterizer *rast )
+ {
+    struct pipe_screen *screen = rast->screen;
+    unsigned i;
+    for (i = 0; i < rast->state.fb.nr_cbufs; i++) {
+       if (rast->cbuf_map[i]) 
+        screen->transfer_unmap(screen, rast->cbuf_transfer[i]);
+       if (rast->cbuf_transfer[i])
+        screen->tex_transfer_destroy(rast->cbuf_transfer[i]);
+       rast->cbuf_transfer[i] = NULL;
+       rast->cbuf_map[i] = NULL;
+    }
+    if (rast->zsbuf_map) 
+       screen->transfer_unmap(screen, rast->zsbuf_transfer);
+    if (rast->zsbuf_transfer)
+       screen->tex_transfer_destroy(rast->zsbuf_transfer);
+    rast->zsbuf_transfer = NULL;
+    rast->zsbuf_map = NULL;
+ }
+ /**
+  * Begining rasterization of a tile.
+  * \param x  window X position of the tile, in pixels
+  * \param y  window Y position of the tile, in pixels
+  */
+ static void
+ lp_rast_start_tile( struct lp_rasterizer *rast,
+                     unsigned thread_index,
+                     unsigned x, unsigned y )
+ {
+    LP_DBG(DEBUG_RAST, "%s %d,%d\n", __FUNCTION__, x, y);
+    rast->tasks[thread_index].x = x;
+    rast->tasks[thread_index].y = y;
+ }
+ /**
+  * Clear the rasterizer's current color tile.
+  * This is a bin command called during bin processing.
+  */
+ void lp_rast_clear_color( struct lp_rasterizer *rast,
+                           unsigned thread_index,
+                           const union lp_rast_cmd_arg arg )
+ {
+    const uint8_t *clear_color = arg.clear_color;
+    uint8_t **color_tile = rast->tasks[thread_index].tile.color;
+    unsigned i;
+    LP_DBG(DEBUG_RAST, "%s 0x%x,0x%x,0x%x,0x%x\n", __FUNCTION__, 
+               clear_color[0],
+               clear_color[1],
+               clear_color[2],
+               clear_color[3]);
+    if (clear_color[0] == clear_color[1] &&
+        clear_color[1] == clear_color[2] &&
+        clear_color[2] == clear_color[3]) {
+       /* clear to grayscale value {x, x, x, x} */
+       for (i = 0; i < rast->state.fb.nr_cbufs; i++) {
+        memset(color_tile[i], clear_color[0], TILE_SIZE * TILE_SIZE * 4);
+       }
+    }
+    else {
+       /* Non-gray color.
+        * Note: if the swizzled tile layout changes (see TILE_PIXEL) this code
+        * will need to change.  It'll be pretty obvious when clearing no longer
+        * works.
+        */
+       const unsigned chunk = TILE_SIZE / 4;
+       for (i = 0; i < rast->state.fb.nr_cbufs; i++) {
+          uint8_t *c = color_tile[i];
+          unsigned j;
+          for (j = 0; j < 4 * TILE_SIZE; j++) {
+             memset(c, clear_color[0], chunk);
+             c += chunk;
+             memset(c, clear_color[1], chunk);
+             c += chunk;
+             memset(c, clear_color[2], chunk);
+             c += chunk;
+             memset(c, clear_color[3], chunk);
+             c += chunk;
+          }
+          assert(c - color_tile[i] == TILE_SIZE * TILE_SIZE * 4);
+       }
+    }
+ }
+ /**
+  * Clear the rasterizer's current z/stencil tile.
+  * This is a bin command called during bin processing.
+  */
+ void lp_rast_clear_zstencil( struct lp_rasterizer *rast,
+                              unsigned thread_index,
+                              const union lp_rast_cmd_arg arg)
+ {
+    unsigned i;
+    uint32_t *depth_tile = rast->tasks[thread_index].tile.depth;
+    
+    LP_DBG(DEBUG_RAST, "%s 0x%x\n", __FUNCTION__, arg.clear_zstencil);
+    for (i = 0; i < TILE_SIZE * TILE_SIZE; i++)
+       depth_tile[i] = arg.clear_zstencil;
+ }
+ /**
+  * Load tile color from the framebuffer surface.
+  * This is a bin command called during bin processing.
+  */
+ void lp_rast_load_color( struct lp_rasterizer *rast,
+                          unsigned thread_index,
+                          const union lp_rast_cmd_arg arg)
+ {
+    struct lp_rasterizer_task *task = &rast->tasks[thread_index];
+    const unsigned x = task->x;
+    const unsigned y = task->y;
+    unsigned i;
+    LP_DBG(DEBUG_RAST, "%s at %u, %u\n", __FUNCTION__, x, y);
+    for (i = 0; i < rast->state.fb.nr_cbufs; i++) {
+       struct pipe_transfer *transfer = rast->cbuf_transfer[i];
+       int w = TILE_SIZE;
+       int h = TILE_SIZE;
+       if (x >= transfer->width)
+        continue;
+       if (y >= transfer->height)
+        continue;
+       assert(w >= 0);
+       assert(h >= 0);
+       assert(w <= TILE_SIZE);
+       assert(h <= TILE_SIZE);
+       lp_tile_read_4ub(transfer->texture->format,
+                      task->tile.color[i],
+                      rast->cbuf_map[i], 
+                      transfer->stride,
+                      x, y,
+                      w, h);
+    }
+ }
+ static void
+ lp_tile_read_z32(uint32_t *tile,
+                  const uint8_t *map,
+                  unsigned map_stride,
+                  unsigned x0, unsigned y0, unsigned w, unsigned h)
+ {
+    unsigned x, y;
+    const uint8_t *map_row = map + y0*map_stride;
+    for (y = 0; y < h; ++y) {
+       const uint32_t *map_pixel = (uint32_t *)(map_row + x0*4);
+       for (x = 0; x < w; ++x) {
+          *tile++ = *map_pixel++;
+       }
+       map_row += map_stride;
+    }
+ }
+ /**
+  * Load tile z/stencil from the framebuffer surface.
+  * This is a bin command called during bin processing.
+  */
+ void lp_rast_load_zstencil( struct lp_rasterizer *rast,
+                             unsigned thread_index,
+                             const union lp_rast_cmd_arg arg )
+ {
+    struct lp_rasterizer_task *task = &rast->tasks[thread_index];
+    const unsigned x = task->x;
+    const unsigned y = task->y;
+    unsigned w = TILE_SIZE;
+    unsigned h = TILE_SIZE;
+    if (x + w > rast->state.fb.width)
+       w -= x + w - rast->state.fb.width;
+    if (y + h > rast->state.fb.height)
+       h -= y + h - rast->state.fb.height;
+    LP_DBG(DEBUG_RAST, "%s %d,%d %dx%d\n", __FUNCTION__, x, y, w, h);
+    assert(rast->zsbuf_transfer->texture->format == PIPE_FORMAT_Z32_UNORM);
+    lp_tile_read_z32(task->tile.depth,
+                     rast->zsbuf_map, 
+                     rast->zsbuf_transfer->stride,
+                     x, y, w, h);
+ }
+ void lp_rast_set_state( struct lp_rasterizer *rast,
+                         unsigned thread_index,
+                         const union lp_rast_cmd_arg arg )
+ {
+    const struct lp_rast_state *state = arg.set_state;
+    LP_DBG(DEBUG_RAST, "%s %p\n", __FUNCTION__, (void *) state);
+    /* just set the current state pointer for this rasterizer */
+    rast->tasks[thread_index].current_state = state;
+ }
+ /**
+  * Run the shader on all blocks in a tile.  This is used when a tile is
+  * completely contained inside a triangle.
+  * This is a bin command called during bin processing.
+  */
+ void lp_rast_shade_tile( struct lp_rasterizer *rast,
+                          unsigned thread_index,
+                          const union lp_rast_cmd_arg arg )
+ {
+    struct lp_rasterizer_task *task = &rast->tasks[thread_index];
+    const struct lp_rast_state *state = task->current_state;
+    struct lp_rast_tile *tile = &task->tile;
+    const struct lp_rast_shader_inputs *inputs = arg.shade_tile;
+    const unsigned tile_x = task->x;
+    const unsigned tile_y = task->y;
+    unsigned x, y;
+    LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
+    /* render the whole 64x64 tile in 4x4 chunks */
+    for (y = 0; y < TILE_SIZE; y += 4){
+       for (x = 0; x < TILE_SIZE; x += 4) {
+          uint8_t *color[PIPE_MAX_COLOR_BUFS];
+          uint32_t *depth;
+          unsigned block_offset, i;
+          /* offset of the 16x16 pixel block within the tile */
+          block_offset = ((y / 4) * (16 * 16) + (x / 4) * 16);
+          /* color buffer */
+          for (i = 0; i < rast->state.fb.nr_cbufs; i++)
+             color[i] = tile->color[i] + 4 * block_offset;
+          /* depth buffer */
+          depth = tile->depth + block_offset;
+          /* run shader */
+          state->jit_function[0]( &state->jit_context,
+                                  tile_x + x, tile_y + y,
+                                  inputs->a0,
+                                  inputs->dadx,
+                                  inputs->dady,
+                                  color,
+                                  depth,
+                                  INT_MIN, INT_MIN, INT_MIN,
+                                  NULL, NULL, NULL );
+       }
+    }
+ }
+ /**
+  * Compute shading for a 4x4 block of pixels.
+  * This is a bin command called during bin processing.
+  */
+ void lp_rast_shade_quads( struct lp_rasterizer *rast,
+                           unsigned thread_index,
+                           const struct lp_rast_shader_inputs *inputs,
+                           unsigned x, unsigned y,
+                           int32_t c1, int32_t c2, int32_t c3)
+ {
+    struct lp_rasterizer_task *task = &rast->tasks[thread_index];
+    const struct lp_rast_state *state = task->current_state;
+    struct lp_rast_tile *tile = &task->tile;
+    uint8_t *color[PIPE_MAX_COLOR_BUFS];
+    void *depth;
+    unsigned i;
+    unsigned ix, iy;
+    int block_offset;
+ #ifdef DEBUG
+    assert(state);
+    /* Sanity checks */
+    assert(x % TILE_VECTOR_WIDTH == 0);
+    assert(y % TILE_VECTOR_HEIGHT == 0);
+    assert((x % 4) == 0);
+    assert((y % 4) == 0);
+ #endif
+    ix = x % TILE_SIZE;
+    iy = y % TILE_SIZE;
+    /* offset of the 16x16 pixel block within the tile */
+    block_offset = ((iy / 4) * (16 * 16) + (ix / 4) * 16);
+    /* color buffer */
+    for (i = 0; i < rast->state.fb.nr_cbufs; i++)
+       color[i] = tile->color[i] + 4 * block_offset;
+    /* depth buffer */
+    depth = tile->depth + block_offset;
+ #ifdef DEBUG
+    assert(lp_check_alignment(tile->depth, 16));
+    assert(lp_check_alignment(tile->color[0], 16));
+    assert(lp_check_alignment(state->jit_context.blend_color, 16));
+    assert(lp_check_alignment(inputs->step[0], 16));
+    assert(lp_check_alignment(inputs->step[1], 16));
+    assert(lp_check_alignment(inputs->step[2], 16));
+ #endif
+    /* run shader */
+    state->jit_function[1]( &state->jit_context,
+                         x, y,
+                         inputs->a0,
+                         inputs->dadx,
+                         inputs->dady,
+                         color,
+                         depth,
+                         c1, c2, c3,
+                         inputs->step[0], inputs->step[1], inputs->step[2]);
+ }
+ /**
+  * Set top row and left column of the tile's pixels to white.  For debugging.
+  */
+ static void
+ outline_tile(uint8_t *tile)
+ {
+    const uint8_t val = 0xff;
+    unsigned i;
+    for (i = 0; i < TILE_SIZE; i++) {
+       TILE_PIXEL(tile, i, 0, 0) = val;
+       TILE_PIXEL(tile, i, 0, 1) = val;
+       TILE_PIXEL(tile, i, 0, 2) = val;
+       TILE_PIXEL(tile, i, 0, 3) = val;
+       TILE_PIXEL(tile, 0, i, 0) = val;
+       TILE_PIXEL(tile, 0, i, 1) = val;
+       TILE_PIXEL(tile, 0, i, 2) = val;
+       TILE_PIXEL(tile, 0, i, 3) = val;
+    }
+ }
+ /**
+  * Draw grid of gray lines at 16-pixel intervals across the tile to
+  * show the sub-tile boundaries.  For debugging.
+  */
+ static void
+ outline_subtiles(uint8_t *tile)
+ {
+    const uint8_t val = 0x80;
+    const unsigned step = 16;
+    unsigned i, j;
+    for (i = 0; i < TILE_SIZE; i += step) {
+       for (j = 0; j < TILE_SIZE; j++) {
+          TILE_PIXEL(tile, i, j, 0) = val;
+          TILE_PIXEL(tile, i, j, 1) = val;
+          TILE_PIXEL(tile, i, j, 2) = val;
+          TILE_PIXEL(tile, i, j, 3) = val;
+          TILE_PIXEL(tile, j, i, 0) = val;
+          TILE_PIXEL(tile, j, i, 1) = val;
+          TILE_PIXEL(tile, j, i, 2) = val;
+          TILE_PIXEL(tile, j, i, 3) = val;
+       }
+    }
+    outline_tile(tile);
+ }
+ /**
+  * Write the rasterizer's color tile to the framebuffer.
+  */
+ static void lp_rast_store_color( struct lp_rasterizer *rast,
+                                  unsigned thread_index)
+ {
+    struct lp_rasterizer_task *task = &rast->tasks[thread_index];
+    const unsigned x = task->x;
+    const unsigned y = task->y;
+    unsigned i;
+    for (i = 0; i < rast->state.fb.nr_cbufs; i++) {
+       struct pipe_transfer *transfer = rast->cbuf_transfer[i];
+       int w = TILE_SIZE;
+       int h = TILE_SIZE;
+       if (x >= transfer->width)
+        continue;
+       if (y >= transfer->height)
+        continue;
+       LP_DBG(DEBUG_RAST, "%s [%u] %d,%d %dx%d\n", __FUNCTION__,
+            thread_index, x, y, w, h);
+       if (LP_DEBUG & DEBUG_SHOW_SUBTILES)
+          outline_subtiles(task->tile.color[i]);
+       else if (LP_DEBUG & DEBUG_SHOW_TILES)
+          outline_tile(task->tile.color[i]);
+       lp_tile_write_4ub(transfer->texture->format,
+                       task->tile.color[i],
+                       rast->cbuf_map[i], 
+                       transfer->stride,
+                       x, y,
+                       w, h);
+    }
+ }
+ static void
+ lp_tile_write_z32(const uint32_t *src, uint8_t *dst, unsigned dst_stride,
+                   unsigned x0, unsigned y0, unsigned w, unsigned h)
+ {
+    unsigned x, y;
+    uint8_t *dst_row = dst + y0*dst_stride;
+    for (y = 0; y < h; ++y) {
+       uint32_t *dst_pixel = (uint32_t *)(dst_row + x0*4);
+       for (x = 0; x < w; ++x) {
+          *dst_pixel++ = *src++;
+       }
+       dst_row += dst_stride;
+    }
+ }
+ /**
+  * Write the rasterizer's z/stencil tile to the framebuffer.
+  */
+ static void lp_rast_store_zstencil( struct lp_rasterizer *rast,
+                                     unsigned thread_index )
+ {
+    struct lp_rasterizer_task *task = &rast->tasks[thread_index];
+    const unsigned x = task->x;
+    const unsigned y = task->y;
+    unsigned w = TILE_SIZE;
+    unsigned h = TILE_SIZE;
+    if (x + w > rast->state.fb.width)
+       w -= x + w - rast->state.fb.width;
+    if (y + h > rast->state.fb.height)
+       h -= y + h - rast->state.fb.height;
+    LP_DBG(DEBUG_RAST, "%s %d,%d %dx%d\n", __FUNCTION__, x, y, w, h);
+    assert(rast->zsbuf_transfer->texture->format == PIPE_FORMAT_Z32_UNORM);
+    lp_tile_write_z32(task->tile.depth,
+                      rast->zsbuf_map, 
+                      rast->zsbuf_transfer->stride,
+                      x, y, w, h);
+ }
+ /**
+  * Write the rasterizer's tiles to the framebuffer.
+  */
+ static void
+ lp_rast_end_tile( struct lp_rasterizer *rast,
+                   unsigned thread_index )
+ {
+    LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
+    if (rast->state.write_color)
+       lp_rast_store_color(rast, thread_index);
+    if (rast->state.write_zstencil)
+       lp_rast_store_zstencil(rast, thread_index);
+ }
+ /**
+  * Signal on a fence.  This is called during bin execution/rasterization.
+  * Called per thread.
+  */
+ void lp_rast_fence( struct lp_rasterizer *rast,
+                     unsigned thread_index,
+                     const union lp_rast_cmd_arg arg )
+ {
+    struct lp_fence *fence = arg.fence;
+    pipe_mutex_lock( fence->mutex );
+    fence->count++;
+    assert(fence->count <= fence->rank);
+    LP_DBG(DEBUG_RAST, "%s count=%u rank=%u\n", __FUNCTION__,
+           fence->count, fence->rank);
+    pipe_condvar_signal( fence->signalled );
+    pipe_mutex_unlock( fence->mutex );
+ }
+ /**
+  * When all the threads are done rasterizing a scene, one thread will
+  * call this function to reset the scene and put it onto the empty queue.
+  */
+ static void
+ release_scene( struct lp_rasterizer *rast,
+              struct lp_scene *scene )
+ {
+    util_unreference_framebuffer_state( &scene->fb );
+    lp_scene_reset( scene );
+    lp_scene_enqueue( rast->empty_scenes, scene );
+    rast->curr_scene = NULL;
+ }
+ /**
+  * Rasterize commands for a single bin.
+  * \param x, y  position of the bin's tile in the framebuffer
+  * Must be called between lp_rast_begin() and lp_rast_end().
+  * Called per thread.
+  */
+ static void
+ rasterize_bin( struct lp_rasterizer *rast,
+                unsigned thread_index,
+                const struct cmd_bin *bin,
+                int x, int y)
+ {
+    const struct cmd_block_list *commands = &bin->commands;
+    struct cmd_block *block;
+    unsigned k;
+    lp_rast_start_tile( rast, thread_index, x, y );
+    /* simply execute each of the commands in the block list */
+    for (block = commands->head; block; block = block->next) {
+       for (k = 0; k < block->count; k++) {
+          block->cmd[k]( rast, thread_index, block->arg[k] );
+       }
+    }
+    lp_rast_end_tile( rast, thread_index );
+ }
+ #define RAST(x) { lp_rast_##x, #x }
+ static struct {
+    lp_rast_cmd cmd;
+    const char *name;
+ } cmd_names[] = 
+ {
+    RAST(load_color),
+    RAST(load_zstencil),
+    RAST(clear_color),
+    RAST(clear_zstencil),
+    RAST(triangle),
+    RAST(shade_tile),
+    RAST(set_state),
+    RAST(fence),
+ };
+ static void
+ debug_bin( const struct cmd_bin *bin )
+ {
+    const struct cmd_block *head = bin->commands.head;
+    int i, j;
+    for (i = 0; i < head->count; i++) {
+       debug_printf("%d: ", i);
+       for (j = 0; j < Elements(cmd_names); j++) {
+          if (head->cmd[i] == cmd_names[j].cmd) {
+             debug_printf("%s\n", cmd_names[j].name);
+             break;
+          }
+       }
+       if (j == Elements(cmd_names))
+          debug_printf("...other\n");
+    }
+ }
+ /* An empty bin is one that just loads the contents of the tile and
+  * stores them again unchanged.  This typically happens when bins have
+  * been flushed for some reason in the middle of a frame, or when
+  * incremental updates are being made to a render target.
+  * 
+  * Try to avoid doing pointless work in this case.
+  */
+ static boolean
+ is_empty_bin( const struct cmd_bin *bin )
+ {
+    const struct cmd_block *head = bin->commands.head;
+    int i;
+    
+    if (0)
+       debug_bin(bin);
+    
+    /* We emit at most two load-tile commands at the start of the first
+     * command block.  In addition we seem to emit a couple of
+     * set-state commands even in empty bins.
+     *
+     * As a heuristic, if a bin has more than 4 commands, consider it
+     * non-empty.
+     */
+    if (head->next != NULL ||
+        head->count > 4) {
+       return FALSE;
+    }
+    for (i = 0; i < head->count; i++)
+       if (head->cmd[i] != lp_rast_load_color &&
+           head->cmd[i] != lp_rast_load_zstencil &&
+           head->cmd[i] != lp_rast_set_state) {
+          return FALSE;
+       }
+    return TRUE;
+ }
+ /**
+  * Rasterize/execute all bins within a scene.
+  * Called per thread.
+  */
+ static void
+ rasterize_scene( struct lp_rasterizer *rast,
+                 unsigned thread_index,
+                 struct lp_scene *scene,
+                 bool write_depth )
+ {
+    /* loop over scene bins, rasterize each */
+ #if 0
+    {
+       unsigned i, j;
+       for (i = 0; i < scene->tiles_x; i++) {
+          for (j = 0; j < scene->tiles_y; j++) {
+             struct cmd_bin *bin = lp_get_bin(scene, i, j);
+             rasterize_bin( rast, thread_index,
+                            bin, i * TILE_SIZE, j * TILE_SIZE );
+          }
+       }
+    }
+ #else
+    {
+       struct cmd_bin *bin;
+       int x, y;
+       assert(scene);
+       while ((bin = lp_scene_bin_iter_next(scene, &x, &y))) {
+          if (!is_empty_bin( bin ))
+             rasterize_bin( rast, thread_index, bin, x * TILE_SIZE, y * TILE_SIZE);
+       }
+    }
+ #endif
+ }
+ /**
+  * Called by setup module when it has something for us to render.
+  */
+ void
+ lp_rasterize_scene( struct lp_rasterizer *rast,
+                    struct lp_scene *scene,
+                    const struct pipe_framebuffer_state *fb,
+                    bool write_depth )
+ {
+    boolean debug = false;
+    LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
+    if (debug) {
+       unsigned x, y;
 -            printf("  bin %u, %u size: %u\n", x, y,
 -                   lp_scene_bin_size(scene, x, y));
++      debug_printf("rasterize scene:\n");
++      debug_printf("  data size: %u\n", lp_scene_data_size(scene));
+       for (y = 0; y < scene->tiles_y; y++) {
+          for (x = 0; x < scene->tiles_x; x++) {
 -static void *
 -thread_func( void *init_data )
++            debug_printf("  bin %u, %u size: %u\n", x, y,
++                         lp_scene_bin_size(scene, x, y));
+          }
+       }
+    }
+    /* save framebuffer state in the bin */
+    util_copy_framebuffer_state(&scene->fb, fb);
+    scene->write_depth = write_depth;
+    if (rast->num_threads == 0) {
+       /* no threading */
+       lp_rast_begin( rast, fb,
+                      fb->nr_cbufs != 0, /* always write color if cbufs present */
+                      fb->zsbuf != NULL && write_depth );
+       lp_scene_bin_iter_begin( scene );
+       rasterize_scene( rast, 0, scene, write_depth );
+       release_scene( rast, scene );
+       lp_rast_end( rast );
+    }
+    else {
+       /* threaded rendering! */
+       unsigned i;
+       lp_scene_enqueue( rast->full_scenes, scene );
+       /* signal the threads that there's work to do */
+       for (i = 0; i < rast->num_threads; i++) {
+          pipe_semaphore_signal(&rast->tasks[i].work_ready);
+       }
+       /* wait for work to complete */
+       for (i = 0; i < rast->num_threads; i++) {
+          pipe_semaphore_wait(&rast->tasks[i].work_done);
+       }
+    }
+    LP_DBG(DEBUG_SETUP, "%s done \n", __FUNCTION__);
+ }
+ /**
+  * This is the thread's main entrypoint.
+  * It's a simple loop:
+  *   1. wait for work
+  *   2. do work
+  *   3. signal that we're done
+  */
++static PIPE_THREAD_ROUTINE( thread_func, init_data )
+ {
+    struct lp_rasterizer_task *task = (struct lp_rasterizer_task *) init_data;
+    struct lp_rasterizer *rast = task->rast;
+    boolean debug = false;
+    while (1) {
+       /* wait for work */
+       if (debug)
+          debug_printf("thread %d waiting for work\n", task->thread_index);
+       pipe_semaphore_wait(&task->work_ready);
+       if (task->thread_index == 0) {
+          /* thread[0]:
+           *  - get next scene to rasterize
+           *  - map the framebuffer surfaces
+           */
+          const struct pipe_framebuffer_state *fb;
+          boolean write_depth;
+          rast->curr_scene = lp_scene_dequeue( rast->full_scenes, TRUE );
+          lp_scene_bin_iter_begin( rast->curr_scene );
+          fb = &rast->curr_scene->fb;
+          write_depth = rast->curr_scene->write_depth;
+          lp_rast_begin( rast, fb,
+                         fb->nr_cbufs != 0,
+                         fb->zsbuf != NULL && write_depth );
+       }
+       /* Wait for all threads to get here so that threads[1+] don't
+        * get a null rast->curr_scene pointer.
+        */
+       pipe_barrier_wait( &rast->barrier );
+       /* do work */
+       if (debug)
+          debug_printf("thread %d doing work\n", task->thread_index);
+       rasterize_scene(rast, 
+                    task->thread_index,
+                      rast->curr_scene, 
+                    rast->curr_scene->write_depth);
+       
+       /* wait for all threads to finish with this scene */
+       pipe_barrier_wait( &rast->barrier );
+       if (task->thread_index == 0) {
+          /* thread[0]:
+           * - release the scene object
+           * - unmap the framebuffer surfaces
+           */
+          release_scene( rast, rast->curr_scene );
+          lp_rast_end( rast );
+       }
+       /* signal done with work */
+       if (debug)
+          debug_printf("thread %d done working\n", task->thread_index);
+       pipe_semaphore_signal(&task->work_done);
+    }
+    return NULL;
+ }
+ /**
+  * Initialize semaphores and spawn the threads.
+  */
+ static void
+ create_rast_threads(struct lp_rasterizer *rast)
+ {
+    unsigned i;
+    rast->num_threads = util_cpu_caps.nr_cpus;
+    rast->num_threads = debug_get_num_option("LP_NUM_THREADS", rast->num_threads);
+    rast->num_threads = MIN2(rast->num_threads, MAX_THREADS);
+    /* NOTE: if num_threads is zero, we won't use any threads */
+    for (i = 0; i < rast->num_threads; i++) {
+       pipe_semaphore_init(&rast->tasks[i].work_ready, 0);
+       pipe_semaphore_init(&rast->tasks[i].work_done, 0);
+       rast->threads[i] = pipe_thread_create(thread_func,
+                                             (void *) &rast->tasks[i]);
+    }
+ }
+ /**
+  * Create new lp_rasterizer.
+  * \param empty  the queue to put empty scenes on after we've finished
+  *               processing them.
+  */
+ struct lp_rasterizer *
+ lp_rast_create( struct pipe_screen *screen, struct lp_scene_queue *empty )
+ {
+    struct lp_rasterizer *rast;
+    unsigned i, cbuf;
+    rast = CALLOC_STRUCT(lp_rasterizer);
+    if(!rast)
+       return NULL;
+    rast->screen = screen;
+    rast->empty_scenes = empty;
+    rast->full_scenes = lp_scene_queue_create();
+    for (i = 0; i < Elements(rast->tasks); i++) {
+       struct lp_rasterizer_task *task = &rast->tasks[i];
+       for (cbuf = 0; cbuf < PIPE_MAX_COLOR_BUFS; cbuf++ )
+        task->tile.color[cbuf] = align_malloc(TILE_SIZE * TILE_SIZE * 4, 16);
+       task->tile.depth = align_malloc(TILE_SIZE * TILE_SIZE * 4, 16);
+       task->rast = rast;
+       task->thread_index = i;
+    }
+    create_rast_threads(rast);
+    /* for synchronizing rasterization threads */
+    pipe_barrier_init( &rast->barrier, rast->num_threads );
+    return rast;
+ }
+ /* Shutdown:
+  */
+ void lp_rast_destroy( struct lp_rasterizer *rast )
+ {
+    unsigned i, cbuf;
+    util_unreference_framebuffer_state(&rast->state.fb);
+    for (i = 0; i < Elements(rast->tasks); i++) {
+       align_free(rast->tasks[i].tile.depth);
+       for (cbuf = 0; cbuf < PIPE_MAX_COLOR_BUFS; cbuf++ )
+        align_free(rast->tasks[i].tile.color[cbuf]);
+    }
+    /* for synchronizing rasterization threads */
+    pipe_barrier_destroy( &rast->barrier );
+    FREE(rast);
+ }
+ /** Return number of rasterization threads */
+ unsigned
+ lp_rast_get_num_threads( struct lp_rasterizer *rast )
+ {
+    return rast->num_threads;
+ }
index 0000000,607968e..71e3a30
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,172 +1,172 @@@
 -#include "pipe/p_thread.h"
+ /**************************************************************************
+  *
+  * 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 VMWARE 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 LP_RAST_PRIV_H
+ #define LP_RAST_PRIV_H
++#include "os/os_thread.h"
+ #include "lp_rast.h"
+ #include "lp_tile_soa.h"
+ #define MAX_THREADS 8  /* XXX probably temporary here */
+ struct pipe_transfer;
+ struct pipe_screen;
+ struct lp_rasterizer;
+ /**
+  * A tile's color and depth memory.
+  * We can choose whatever layout for the internal tile storage we prefer.
+  */
+ struct lp_rast_tile
+ {
+    uint8_t *color[PIPE_MAX_COLOR_BUFS];
+    uint32_t *depth;
+ };
+ /**
+  * Per-thread rasterization state
+  */
+ struct lp_rasterizer_task
+ {
+    struct lp_rast_tile tile;   /** Tile color/z/stencil memory */
+    unsigned x, y;          /**< Pos of this tile in framebuffer, in pixels */
+    const struct lp_rast_state *current_state;
+    /** "back" pointer */
+    struct lp_rasterizer *rast;
+    /** "my" index */
+    unsigned thread_index;
+    pipe_semaphore work_ready;
+    pipe_semaphore work_done;
+ };
+ /**
+  * This is the state required while rasterizing tiles.
+  * Note that this contains per-thread information too.
+  * The tile size is TILE_SIZE x TILE_SIZE pixels.
+  */
+ struct lp_rasterizer
+ {
+    boolean clipped_tile;
+    boolean check_for_clipped_tiles;
+    /* Framebuffer stuff
+     */
+    struct pipe_screen *screen;
+    struct pipe_transfer *cbuf_transfer[PIPE_MAX_COLOR_BUFS];
+    struct pipe_transfer *zsbuf_transfer;
+    void *cbuf_map[PIPE_MAX_COLOR_BUFS];
+    void *zsbuf_map;
+    struct {
+       struct pipe_framebuffer_state fb;
+       boolean write_color;
+       boolean write_zstencil;
+       unsigned clear_color;
+       unsigned clear_depth;
+       char clear_stencil;
+    } state;
+    /** The incoming queue of scenes ready to rasterize */
+    struct lp_scene_queue *full_scenes;
+    /** The outgoing queue of processed scenes to return to setup modulee */
+    struct lp_scene_queue *empty_scenes;
+    /** The scene currently being rasterized by the threads */
+    struct lp_scene *curr_scene;
+    /** A task object for each rasterization thread */
+    struct lp_rasterizer_task tasks[MAX_THREADS];
+    unsigned num_threads;
+    pipe_thread threads[MAX_THREADS];
+    /** For synchronizing the rasterization threads */
+    pipe_barrier barrier;
+ };
+ void lp_rast_shade_quads( struct lp_rasterizer *rast,
+                           unsigned thread_index,
+                           const struct lp_rast_shader_inputs *inputs,
+                           unsigned x, unsigned y,
+                           int32_t c1, int32_t c2, int32_t c3);
+ /**
+  * Shade all pixels in a 4x4 block.  The fragment code omits the
+  * triangle in/out tests.
+  * \param x, y location of 4x4 block in window coords
+  */
+ static INLINE void
+ lp_rast_shade_quads_all( struct lp_rasterizer *rast,
+                          unsigned thread_index,
+                          const struct lp_rast_shader_inputs *inputs,
+                          unsigned x, unsigned y )
+ {
+    const struct lp_rast_state *state = rast->tasks[thread_index].current_state;
+    struct lp_rast_tile *tile = &rast->tasks[thread_index].tile;
+    const unsigned ix = x % TILE_SIZE, iy = y % TILE_SIZE;
+    uint8_t *color[PIPE_MAX_COLOR_BUFS];
+    void *depth;
+    unsigned block_offset, i;
+    /* offset of the containing 16x16 pixel block within the tile */
+    block_offset = (iy / 4) * (16 * 16) + (ix / 4) * 16;
+    /* color buffer */
+    for (i = 0; i < rast->state.fb.nr_cbufs; i++)
+       color[i] = tile->color[i] + 4 * block_offset;
+    /* depth buffer */
+    depth = tile->depth + block_offset;
+    /* run shader */
+    state->jit_function[0]( &state->jit_context,
+                            x, y,
+                            inputs->a0,
+                            inputs->dadx,
+                            inputs->dady,
+                            color,
+                            depth,
+                            INT_MIN, INT_MIN, INT_MIN,
+                            NULL, NULL, NULL );
+ }
+ #endif
index 0000000,191122d..0421c50
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,391 +1,392 @@@
+ /**************************************************************************
+  *
+  * 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 VMWARE 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 "util/u_inlines.h"
+ #include "util/u_simple_list.h"
+ #include "lp_scene.h"
+ struct lp_scene *
+ lp_scene_create(void)
+ {
+    struct lp_scene *scene = CALLOC_STRUCT(lp_scene);
+    if (scene)
+       lp_scene_init(scene);
+    return scene;
+ }
+ void
+ lp_scene_destroy(struct lp_scene *scene)
+ {
+    lp_scene_reset(scene);
+    lp_scene_free_bin_data(scene);
+    FREE(scene);
+ }
+ void
+ lp_scene_init(struct lp_scene *scene)
+ {
+    unsigned i, j;
+    for (i = 0; i < TILES_X; i++)
+       for (j = 0; j < TILES_Y; j++) {
+          struct cmd_bin *bin = lp_scene_get_bin(scene, i, j);
+          bin->commands.head = bin->commands.tail = CALLOC_STRUCT(cmd_block);
+       }
+    scene->data.head =
+       scene->data.tail = CALLOC_STRUCT(data_block);
+    make_empty_list(&scene->textures);
+    pipe_mutex_init(scene->mutex);
+ }
+ /**
+  * Check if the scene's bins are all empty.
+  * For debugging purposes.
+  */
+ boolean
+ lp_scene_is_empty(struct lp_scene *scene )
+ {
+    unsigned x, y;
+    for (y = 0; y < TILES_Y; y++) {
+       for (x = 0; x < TILES_X; x++) {
+          const struct cmd_bin *bin = lp_scene_get_bin(scene, x, y);
+          const struct cmd_block_list *list = &bin->commands;
+          if (list->head != list->tail || list->head->count > 0) {
+             return FALSE;
+          }
+       }
+    }
+    return TRUE;
+ }
+ void
+ lp_scene_bin_reset(struct lp_scene *scene, unsigned x, unsigned y)
+ {
+    struct cmd_bin *bin = lp_scene_get_bin(scene, x, y);
+    struct cmd_block_list *list = &bin->commands;
+    struct cmd_block *block;
+    struct cmd_block *tmp;
+    for (block = list->head; block != list->tail; block = tmp) {
+       tmp = block->next;
+       FREE(block);
+    }
+    assert(list->tail->next == NULL);
+    list->head = list->tail;
+    list->head->count = 0;
+ }
+ /**
+  * Set scene to empty state.
+  */
+ void
+ lp_scene_reset(struct lp_scene *scene )
+ {
+    unsigned i, j;
+    /* Free all but last binner command lists:
+     */
+    for (i = 0; i < scene->tiles_x; i++) {
+       for (j = 0; j < scene->tiles_y; j++) {
+          lp_scene_bin_reset(scene, i, j);
+       }
+    }
+    assert(lp_scene_is_empty(scene));
+    /* Free all but last binned data block:
+     */
+    {
+       struct data_block_list *list = &scene->data;
+       struct data_block *block, *tmp;
+       for (block = list->head; block != list->tail; block = tmp) {
+          tmp = block->next;
+          FREE(block);
+       }
+          
+       assert(list->tail->next == NULL);
+       list->head = list->tail;
+       list->head->used = 0;
+    }
+    /* Release texture refs
+     */
+    {
+       struct texture_ref *ref, *next, *ref_list = &scene->textures;
+       for (ref = ref_list->next; ref != ref_list; ref = next) {
+          next = next_elem(ref);
+          pipe_texture_reference(&ref->texture, NULL);
+          FREE(ref);
+       }
+       make_empty_list(ref_list);
+    }
+ }
+ /**
+  * Free all data associated with the given bin, but don't free(scene).
+  */
+ void
+ lp_scene_free_bin_data(struct lp_scene *scene)
+ {
+    unsigned i, j;
+    for (i = 0; i < TILES_X; i++)
+       for (j = 0; j < TILES_Y; j++) {
+          struct cmd_bin *bin = lp_scene_get_bin(scene, i, j);
+          /* lp_reset_scene() should have been already called */
+          assert(bin->commands.head == bin->commands.tail);
+          FREE(bin->commands.head);
+          bin->commands.head = NULL;
+          bin->commands.tail = NULL;
+       }
+    FREE(scene->data.head);
+    scene->data.head = NULL;
+    pipe_mutex_destroy(scene->mutex);
+ }
+ void
+ lp_scene_set_framebuffer_size( struct lp_scene *scene,
+                                unsigned width, unsigned height )
+ {
+    assert(lp_scene_is_empty(scene));
+    scene->tiles_x = align(width, TILE_SIZE) / TILE_SIZE;
+    scene->tiles_y = align(height, TILE_SIZE) / TILE_SIZE;
+ }
+ void
+ lp_bin_new_cmd_block( struct cmd_block_list *list )
+ {
+    struct cmd_block *block = MALLOC_STRUCT(cmd_block);
+    list->tail->next = block;
+    list->tail = block;
+    block->next = NULL;
+    block->count = 0;
+ }
+ void
+ lp_bin_new_data_block( struct data_block_list *list )
+ {
+    struct data_block *block = MALLOC_STRUCT(data_block);
+    list->tail->next = block;
+    list->tail = block;
+    block->next = NULL;
+    block->used = 0;
+ }
+ /** Return number of bytes used for all bin data within a scene */
+ unsigned
+ lp_scene_data_size( const struct lp_scene *scene )
+ {
+    unsigned size = 0;
+    const struct data_block *block;
+    for (block = scene->data.head; block; block = block->next) {
+       size += block->used;
+    }
+    return size;
+ }
+ /** Return number of bytes used for a single bin */
+ unsigned
+ lp_scene_bin_size( const struct lp_scene *scene, unsigned x, unsigned y )
+ {
+    struct cmd_bin *bin = lp_scene_get_bin((struct lp_scene *) scene, x, y);
+    const struct cmd_block *cmd;
+    unsigned size = 0;
+    for (cmd = bin->commands.head; cmd; cmd = cmd->next) {
+       size += (cmd->count *
+                (sizeof(lp_rast_cmd) + sizeof(union lp_rast_cmd_arg)));
+    }
+    return size;
+ }
+ /**
+  * Add a reference to a texture by the scene.
+  */
+ void
+ lp_scene_texture_reference( struct lp_scene *scene,
+                             struct pipe_texture *texture )
+ {
+    struct texture_ref *ref = CALLOC_STRUCT(texture_ref);
+    if (ref) {
+       struct texture_ref *ref_list = &scene->textures;
+       pipe_texture_reference(&ref->texture, texture);
+       insert_at_tail(ref_list, ref);
+    }
+ }
+ /**
+  * Does this scene have a reference to the given texture?
+  */
+ boolean
+ lp_scene_is_textured_referenced( const struct lp_scene *scene,
+                                  const struct pipe_texture *texture )
+ {
+    const struct texture_ref *ref_list = &scene->textures;
+    const struct texture_ref *ref;
+    foreach (ref, ref_list) {
+       if (ref->texture == texture)
+          return TRUE;
+    }
+    return FALSE;
+ }
+ /**
+  * Return last command in the bin
+  */
+ static lp_rast_cmd
+ lp_get_last_command( const struct cmd_bin *bin )
+ {
+    const struct cmd_block *tail = bin->commands.tail;
+    const unsigned i = tail->count;
+    if (i > 0)
+       return tail->cmd[i - 1];
+    else
+       return NULL;
+ }
+ /**
+  * Replace the arg of the last command in the bin.
+  */
+ static void
+ lp_replace_last_command_arg( struct cmd_bin *bin,
+                              const union lp_rast_cmd_arg arg )
+ {
+    struct cmd_block *tail = bin->commands.tail;
+    const unsigned i = tail->count;
+    assert(i > 0);
+    tail->arg[i - 1] = arg;
+ }
+ /**
+  * Put a state-change command into all bins.
+  * If we find that the last command in a bin was also a state-change
+  * command, we can simply replace that one with the new one.
+  */
+ void
+ lp_scene_bin_state_command( struct lp_scene *scene,
+                             lp_rast_cmd cmd,
+                             const union lp_rast_cmd_arg arg )
+ {
+    unsigned i, j;
+    for (i = 0; i < scene->tiles_x; i++) {
+       for (j = 0; j < scene->tiles_y; j++) {
+          struct cmd_bin *bin = lp_scene_get_bin(scene, i, j);
+          lp_rast_cmd last_cmd = lp_get_last_command(bin);
+          if (last_cmd == cmd) {
+             lp_replace_last_command_arg(bin, arg);
+          }
+          else {
+             lp_scene_bin_command( scene, i, j, cmd, arg );
+          }
+       }
+    }
+ }
+ /** advance curr_x,y to the next bin */
+ static boolean
+ next_bin(struct lp_scene *scene)
+ {
+    scene->curr_x++;
+    if (scene->curr_x >= scene->tiles_x) {
+       scene->curr_x = 0;
+       scene->curr_y++;
+    }
+    if (scene->curr_y >= scene->tiles_y) {
+       /* no more bins */
+       return FALSE;
+    }
+    return TRUE;
+ }
+ void
+ lp_scene_bin_iter_begin( struct lp_scene *scene )
+ {
+    scene->curr_x = scene->curr_y = -1;
+ }
+ /**
+  * Return pointer to next bin to be rendered.
+  * The lp_scene::curr_x and ::curr_y fields will be advanced.
+  * Multiple rendering threads will call this function to get a chunk
+  * of work (a bin) to work on.
+  */
+ struct cmd_bin *
+ lp_scene_bin_iter_next( struct lp_scene *scene, int *bin_x, int *bin_y )
+ {
+    struct cmd_bin *bin = NULL;
+    pipe_mutex_lock(scene->mutex);
+    if (scene->curr_x < 0) {
+       /* first bin */
+       scene->curr_x = 0;
+       scene->curr_y = 0;
+    }
+    else if (!next_bin(scene)) {
+       /* no more bins left */
+       goto end;
+    }
+    bin = lp_scene_get_bin(scene, scene->curr_x, scene->curr_y);
+    *bin_x = scene->curr_x;
+    *bin_y = scene->curr_y;
+ end:
+    /*printf("return bin %p at %d, %d\n", (void *) bin, *bin_x, *bin_y);*/
+    pipe_mutex_unlock(scene->mutex);
+    return bin;
+ }
index 0000000,86facf8..7db2165
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,301 +1,301 @@@
 -#include "pipe/p_thread.h"
+ /**************************************************************************
+  *
+  * 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 VMWARE 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.
+  *
+  **************************************************************************/
+ /**
+  * Binner data structures and bin-related functions.
+  * Note: the "setup" code is concerned with building scenes while
+  * The "rast" code is concerned with consuming/executing scenes.
+  */
+ #ifndef LP_SCENE_H
+ #define LP_SCENE_H
++#include "os/os_thread.h"
+ #include "lp_tile_soa.h"
+ #include "lp_rast.h"
+ /* We're limited to 2K by 2K for 32bit fixed point rasterization.
+  * Will need a 64-bit version for larger framebuffers.
+  */
+ #define MAXHEIGHT 2048
+ #define MAXWIDTH 2048
+ #define TILES_X (MAXWIDTH / TILE_SIZE)
+ #define TILES_Y (MAXHEIGHT / TILE_SIZE)
+ #define CMD_BLOCK_MAX 128
+ #define DATA_BLOCK_SIZE (16 * 1024 - sizeof(unsigned) - sizeof(void *))
+    
+ /* switch to a non-pointer value for this:
+  */
+ typedef void (*lp_rast_cmd)( struct lp_rasterizer *,
+                              unsigned thread_index,
+                              const union lp_rast_cmd_arg );
+ struct cmd_block {
+    lp_rast_cmd cmd[CMD_BLOCK_MAX];
+    union lp_rast_cmd_arg arg[CMD_BLOCK_MAX];
+    unsigned count;
+    struct cmd_block *next;
+ };
+ struct data_block {
+    ubyte data[DATA_BLOCK_SIZE];
+    unsigned used;
+    struct data_block *next;
+ };
+ struct cmd_block_list {
+    struct cmd_block *head;
+    struct cmd_block *tail;
+ };
+ /**
+  * For each screen tile we have one of these bins.
+  */
+ struct cmd_bin {
+    struct cmd_block_list commands;
+ };
+    
+ /**
+  * This stores bulk data which is shared by all bins within a scene.
+  * Examples include triangle data and state data.  The commands in
+  * the per-tile bins will point to chunks of data in this structure.
+  */
+ struct data_block_list {
+    struct data_block *head;
+    struct data_block *tail;
+ };
+ /** List of texture references */
+ struct texture_ref {
+    struct pipe_texture *texture;
+    struct texture_ref *prev, *next;  /**< linked list w/ u_simple_list.h */
+ };
+ /**
+  * All bins and bin data are contained here.
+  * Per-bin data goes into the 'tile' bins.
+  * Shared data goes into the 'data' buffer.
+  *
+  * When there are multiple threads, will want to double-buffer between
+  * scenes:
+  */
+ struct lp_scene {
+    struct cmd_bin tile[TILES_X][TILES_Y];
+    struct data_block_list data;
+    /** the framebuffer to render the scene into */
+    struct pipe_framebuffer_state fb;
+    /** list of textures referenced by the scene commands */
+    struct texture_ref textures;
+    boolean write_depth;
+    /**
+     * Number of active tiles in each dimension.
+     * This basically the framebuffer size divided by tile size
+     */
+    unsigned tiles_x, tiles_y;
+    int curr_x, curr_y;  /**< for iterating over bins */
+    pipe_mutex mutex;
+ };
+ struct lp_scene *lp_scene_create(void);
+ void lp_scene_destroy(struct lp_scene *scene);
+ void lp_scene_init(struct lp_scene *scene);
+ boolean lp_scene_is_empty(struct lp_scene *scene );
+ void lp_scene_reset(struct lp_scene *scene );
+ void lp_scene_free_bin_data(struct lp_scene *scene);
+ void lp_scene_set_framebuffer_size( struct lp_scene *scene,
+                                   unsigned width, unsigned height );
+ void lp_bin_new_data_block( struct data_block_list *list );
+ void lp_bin_new_cmd_block( struct cmd_block_list *list );
+ unsigned lp_scene_data_size( const struct lp_scene *scene );
+ unsigned lp_scene_bin_size( const struct lp_scene *scene, unsigned x, unsigned y );
+ void lp_scene_texture_reference( struct lp_scene *scene,
+                                  struct pipe_texture *texture );
+ boolean lp_scene_is_textured_referenced( const struct lp_scene *scene,
+                                          const struct pipe_texture *texture );
+ /**
+  * Allocate space for a command/data in the bin's data buffer.
+  * Grow the block list if needed.
+  */
+ static INLINE void *
+ lp_scene_alloc( struct lp_scene *scene, unsigned size)
+ {
+    struct data_block_list *list = &scene->data;
+    if (list->tail->used + size > DATA_BLOCK_SIZE) {
+       lp_bin_new_data_block( list );
+    }
+    {
+       struct data_block *tail = list->tail;
+       ubyte *data = tail->data + tail->used;
+       tail->used += size;
+       return data;
+    }
+ }
+ /**
+  * As above, but with specific alignment.
+  */
+ static INLINE void *
+ lp_scene_alloc_aligned( struct lp_scene *scene, unsigned size,
+                       unsigned alignment )
+ {
+    struct data_block_list *list = &scene->data;
+    if (list->tail->used + size + alignment - 1 > DATA_BLOCK_SIZE) {
+       lp_bin_new_data_block( list );
+    }
+    {
+       struct data_block *tail = list->tail;
+       ubyte *data = tail->data + tail->used;
+       unsigned offset = (((uintptr_t)data + alignment - 1) & ~(alignment - 1)) - (uintptr_t)data;
+       tail->used += offset + size;
+       return data + offset;
+    }
+ }
+ /* Put back data if we decide not to use it, eg. culled triangles.
+  */
+ static INLINE void
+ lp_scene_putback_data( struct lp_scene *scene, unsigned size)
+ {
+    struct data_block_list *list = &scene->data;
+    assert(list->tail->used >= size);
+    list->tail->used -= size;
+ }
+ /** Return pointer to a particular tile's bin. */
+ static INLINE struct cmd_bin *
+ lp_scene_get_bin(struct lp_scene *scene, unsigned x, unsigned y)
+ {
+    return &scene->tile[x][y];
+ }
+ /** Remove all commands from a bin */
+ void
+ lp_scene_bin_reset(struct lp_scene *scene, unsigned x, unsigned y);
+ /* Add a command to bin[x][y].
+  */
+ static INLINE void
+ lp_scene_bin_command( struct lp_scene *scene,
+                 unsigned x, unsigned y,
+                 lp_rast_cmd cmd,
+                 union lp_rast_cmd_arg arg )
+ {
+    struct cmd_bin *bin = lp_scene_get_bin(scene, x, y);
+    struct cmd_block_list *list = &bin->commands;
+    assert(x < scene->tiles_x);
+    assert(y < scene->tiles_y);
+    if (list->tail->count == CMD_BLOCK_MAX) {
+       lp_bin_new_cmd_block( list );
+    }
+    {
+       struct cmd_block *tail = list->tail;
+       unsigned i = tail->count;
+       tail->cmd[i] = cmd;
+       tail->arg[i] = arg;
+       tail->count++;
+    }
+ }
+ /* Add a command to all active bins.
+  */
+ static INLINE void
+ lp_scene_bin_everywhere( struct lp_scene *scene,
+                        lp_rast_cmd cmd,
+                        const union lp_rast_cmd_arg arg )
+ {
+    unsigned i, j;
+    for (i = 0; i < scene->tiles_x; i++)
+       for (j = 0; j < scene->tiles_y; j++)
+          lp_scene_bin_command( scene, i, j, cmd, arg );
+ }
+ void
+ lp_scene_bin_state_command( struct lp_scene *scene,
+                           lp_rast_cmd cmd,
+                           const union lp_rast_cmd_arg arg );
+ static INLINE unsigned
+ lp_scene_get_num_bins( const struct lp_scene *scene )
+ {
+    return scene->tiles_x * scene->tiles_y;
+ }
+ void
+ lp_scene_bin_iter_begin( struct lp_scene *scene );
+ struct cmd_bin *
+ lp_scene_bin_iter_next( struct lp_scene *scene, int *bin_x, int *bin_y );
+ #endif /* LP_BIN_H */
   **************************************************************************/
  
  /**
-  * \brief  Primitive rasterization/rendering (points, lines, triangles)
+  * Tiling engine.
   *
-  * \author  Keith Whitwell <keith@tungstengraphics.com>
-  * \author  Brian Paul
+  * Builds per-tile display lists and executes them on calls to
+  * lp_setup_flush().
   */
  
- #include "lp_context.h"
- #include "lp_quad.h"
- #include "lp_setup.h"
- #include "lp_state.h"
- #include "draw/draw_context.h"
- #include "draw/draw_vertex.h"
- #include "pipe/p_shader_tokens.h"
- #include "util/u_format.h"
- #include "util/u_math.h"
+ #include "pipe/p_defines.h"
 -#include "pipe/p_inlines.h"
++#include "util/u_inlines.h"
  #include "util/u_memory.h"
- #include "lp_bld_debug.h"
- #include "lp_tile_cache.h"
- #include "lp_tile_soa.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 */
- };
- #define MAX_QUADS 16
+ #include "util/u_pack_color.h"
+ #include "util/u_surface.h"
+ #include "lp_scene.h"
+ #include "lp_scene_queue.h"
+ #include "lp_buffer.h"
+ #include "lp_texture.h"
+ #include "lp_debug.h"
+ #include "lp_fence.h"
+ #include "lp_rast.h"
+ #include "lp_setup_context.h"
  
- /**
-  * 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;
-    int facing;
+ #include "draw/draw_context.h"
+ #include "draw/draw_vbuf.h"
  
-    float pixel_offset;
  
-    struct quad_header quad[MAX_QUADS];
-    struct quad_header *quad_ptrs[MAX_QUADS];
-    unsigned count;
+ static void set_scene_state( struct setup_context *, unsigned );
  
-    struct quad_interp_coef coef;
  
-    struct {
-       int left[2];   /**< [0] = row0, [1] = row1 */
-       int right[2];
-       int y;
-    } span;
+ struct lp_scene *
+ lp_setup_get_current_scene(struct setup_context *setup)
+ {
+    if (!setup->scene) {
  
- #if DEBUG_FRAGS
-    uint numFragsEmitted;  /**< per primitive */
-    uint numFragsWritten;  /**< per primitive */
- #endif
+       /* wait for a free/empty scene
+        */
+       setup->scene = lp_scene_dequeue(setup->empty_scenes, TRUE);
  
-    unsigned winding;          /* which winding to cull */
- };
+       if(0)lp_scene_reset( setup->scene ); /* XXX temporary? */
  
+       lp_scene_set_framebuffer_size(setup->scene,
+                                     setup->fb.width, 
+                                     setup->fb.height);
+    }
+    return setup->scene;
+ }
  
  
- /**
-  * Execute fragment shader for the four fragments in the quad.
-  */
- PIPE_ALIGN_STACK
  static void
- shade_quads(struct llvmpipe_context *llvmpipe,
-             struct quad_header *quads[],
-             unsigned nr)
+ first_triangle( struct setup_context *setup,
+                 const float (*v0)[4],
+                 const float (*v1)[4],
+                 const float (*v2)[4])
  {
-    struct lp_fragment_shader *fs = llvmpipe->fs;
-    struct quad_header *quad = quads[0];
-    const unsigned x = quad->input.x0;
-    const unsigned y = quad->input.y0;
-    uint8_t *tile;
-    uint8_t *color;
-    void *depth;
-    PIPE_ALIGN_VAR(16) uint32_t mask[4][NUM_CHANNELS];
-    unsigned chan_index;
-    unsigned q;
-    assert(fs->current);
-    if(!fs->current)
-       return;
-    /* Sanity checks */
-    assert(nr * QUAD_SIZE == TILE_VECTOR_HEIGHT * TILE_VECTOR_WIDTH);
-    assert(x % TILE_VECTOR_WIDTH == 0);
-    assert(y % TILE_VECTOR_HEIGHT == 0);
-    for (q = 0; q < nr; ++q) {
-       assert(quads[q]->input.x0 == x + q*2);
-       assert(quads[q]->input.y0 == y);
-    }
-    /* mask */
-    for (q = 0; q < 4; ++q)
-       for (chan_index = 0; chan_index < NUM_CHANNELS; ++chan_index)
-          mask[q][chan_index] = quads[q]->inout.mask & (1 << chan_index) ? ~0 : 0;
+    set_scene_state( setup, SETUP_ACTIVE );
+    lp_setup_choose_triangle( setup );
+    setup->triangle( setup, v0, v1, v2 );
+ }
  
-    /* color buffer */
-    if(llvmpipe->framebuffer.nr_cbufs >= 1 &&
-       llvmpipe->framebuffer.cbufs[0]) {
-       tile = lp_get_cached_tile(llvmpipe->cbuf_cache[0], x, y);
-       color = &TILE_PIXEL(tile, x & (TILE_SIZE-1), y & (TILE_SIZE-1), 0);
-    }
-    else
-       color = NULL;
-    /* depth buffer */
-    if(llvmpipe->zsbuf_map) {
-       assert((x % 2) == 0);
-       assert((y % 2) == 0);
-       depth = llvmpipe->zsbuf_map +
-               y*llvmpipe->zsbuf_transfer->stride +
-               2*x*util_format_get_blocksize(llvmpipe->zsbuf_transfer->texture->format);
-    }
-    else
-       depth = NULL;
-    /* XXX: This will most likely fail on 32bit x86 without -mstackrealign */
-    assert(lp_check_alignment(mask, 16));
-    assert(lp_check_alignment(depth, 16));
-    assert(lp_check_alignment(color, 16));
-    assert(lp_check_alignment(llvmpipe->jit_context.blend_color, 16));
-    /* run shader */
-    fs->current->jit_function( &llvmpipe->jit_context,
-                               x, y,
-                               quad->coef->a0,
-                               quad->coef->dadx,
-                               quad->coef->dady,
-                               &mask[0][0],
-                               color,
-                               depth);
+ static void
+ first_line( struct setup_context *setup,
+           const float (*v0)[4],
+           const float (*v1)[4])
+ {
+    set_scene_state( setup, SETUP_ACTIVE );
+    lp_setup_choose_line( setup );
+    setup->line( setup, v0, v1 );
  }
  
+ static void
+ first_point( struct setup_context *setup,
+            const float (*v0)[4])
+ {
+    set_scene_state( setup, SETUP_ACTIVE );
+    lp_setup_choose_point( setup );
+    setup->point( setup, v0 );
+ }
  
+ static void reset_context( struct setup_context *setup )
+ {
+    LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
  
+    /* Reset derived state */
+    setup->constants.stored_size = 0;
+    setup->constants.stored_data = NULL;
+    setup->fs.stored = NULL;
+    setup->dirty = ~0;
  
- /**
-  * 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;
+    /* no current bin */
+    setup->scene = NULL;
  
-       if ((winding & setup->winding) == 0)
-        return FALSE;
-    }
+    /* Reset some state:
+     */
+    setup->clear.flags = 0;
  
-    /* Culled:
+    /* Have an explicit "start-binning" call and get rid of this
+     * pointer twiddling?
      */
-    return TRUE;
+    setup->line = first_line;
+    setup->point = first_point;
+    setup->triangle = first_triangle;
  }
  
  
@@@ -58,8 -60,8 +60,9 @@@
   * @author Jose Fonseca <jfonseca@vmware.com>
   */
  
+ #include <limits.h>
  #include "pipe/p_defines.h"
 +#include "util/u_inlines.h"
  #include "util/u_memory.h"
  #include "util/u_format.h"
  #include "util/u_debug_dump.h"
  /* Authors:  Keith Whitwell <keith@tungstengraphics.com>
   */
  
+ #include "pipe/p_state.h"
 +#include "util/u_inlines.h"
+ #include "util/u_surface.h"
  #include "lp_context.h"
  #include "lp_state.h"
- #include "lp_tile_cache.h"
+ #include "lp_setup.h"
  
  #include "draw/draw_context.h"