Mesa (master): llvmpipe: enforce fixed memory limit on scenes

Keith Whitwell keithw at kemper.freedesktop.org
Tue Sep 7 13:03:39 UTC 2010


Module: Mesa
Branch: master
Commit: 6419ecd02ce43a2614822e228f306d4db589f317
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=6419ecd02ce43a2614822e228f306d4db589f317

Author: Keith Whitwell <keithw at vmware.com>
Date:   Fri Aug 27 17:49:40 2010 +0100

llvmpipe: enforce fixed memory limit on scenes

---

 src/gallium/drivers/llvmpipe/lp_rast.c          |   11 +-
 src/gallium/drivers/llvmpipe/lp_rast.h          |    1 +
 src/gallium/drivers/llvmpipe/lp_rast_tri_tmp.h  |    5 +
 src/gallium/drivers/llvmpipe/lp_scene.c         |  227 +++++++++++--------
 src/gallium/drivers/llvmpipe/lp_scene.h         |  140 ++++++------
 src/gallium/drivers/llvmpipe/lp_setup.c         |  280 ++++++++++++-----------
 src/gallium/drivers/llvmpipe/lp_setup.h         |    2 -
 src/gallium/drivers/llvmpipe/lp_setup_context.h |    5 +-
 src/gallium/drivers/llvmpipe/lp_setup_line.c    |   28 ++-
 src/gallium/drivers/llvmpipe/lp_setup_point.c   |   24 ++-
 src/gallium/drivers/llvmpipe/lp_setup_tri.c     |   77 ++++---
 11 files changed, 459 insertions(+), 341 deletions(-)

diff --git a/src/gallium/drivers/llvmpipe/lp_rast.c b/src/gallium/drivers/llvmpipe/lp_rast.c
index d8dc24e..c022153 100644
--- a/src/gallium/drivers/llvmpipe/lp_rast.c
+++ b/src/gallium/drivers/llvmpipe/lp_rast.c
@@ -369,6 +369,11 @@ lp_rast_shade_tile(struct lp_rasterizer_task *task,
    const unsigned tile_x = task->x, tile_y = task->y;
    unsigned x, y;
 
+   if (inputs->disable) {
+      /* This command was partially binned and has been disabled */
+      return;
+   }
+
    LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
 
    /* render the whole 64x64 tile in 4x4 chunks */
@@ -664,10 +669,6 @@ rasterize_bin(struct lp_rasterizer_task *task,
    }
 
    lp_rast_tile_end(task);
-
-   /* Free data for this bin.
-    */
-   lp_scene_bin_reset( task->rast->curr_scene, x, y);
 }
 
 
@@ -727,7 +728,7 @@ static boolean
 is_empty_bin( const struct cmd_bin *bin )
 {
    if (0) debug_bin(bin);
-   return bin->commands.head->count == 0;
+   return bin->commands.head == NULL;
 }
 
 
diff --git a/src/gallium/drivers/llvmpipe/lp_rast.h b/src/gallium/drivers/llvmpipe/lp_rast.h
index d6e53f3..f43e714 100644
--- a/src/gallium/drivers/llvmpipe/lp_rast.h
+++ b/src/gallium/drivers/llvmpipe/lp_rast.h
@@ -80,6 +80,7 @@ struct lp_rast_state {
 struct lp_rast_shader_inputs {
    float facing;     /** Positive for front-facing, negative for back-facing */
    boolean opaque:1;   /** Is opaque */
+   boolean disable:1;  /** Partially binned, disable this command */
 
    float (*a0)[4];
    float (*dadx)[4];
diff --git a/src/gallium/drivers/llvmpipe/lp_rast_tri_tmp.h b/src/gallium/drivers/llvmpipe/lp_rast_tri_tmp.h
index 99a0bae..eca25bb 100644
--- a/src/gallium/drivers/llvmpipe/lp_rast_tri_tmp.h
+++ b/src/gallium/drivers/llvmpipe/lp_rast_tri_tmp.h
@@ -165,6 +165,11 @@ TAG(lp_rast_triangle)(struct lp_rasterizer_task *task,
    outmask = 0;                 /* outside one or more trivial reject planes */
    partmask = 0;                /* outside one or more trivial accept planes */
 
+   if (tri->inputs.disable) {
+      /* This triangle was partially binned and has been disabled */
+      return;
+   }
+
    while (plane_mask) {
       int i = ffs(plane_mask) - 1;
       plane[j] = tri->plane[i];
diff --git a/src/gallium/drivers/llvmpipe/lp_scene.c b/src/gallium/drivers/llvmpipe/lp_scene.c
index 51389c2..67bc747 100644
--- a/src/gallium/drivers/llvmpipe/lp_scene.c
+++ b/src/gallium/drivers/llvmpipe/lp_scene.c
@@ -31,16 +31,19 @@
 #include "util/u_inlines.h"
 #include "util/u_simple_list.h"
 #include "lp_scene.h"
+#include "lp_debug.h"
 #include "lp_scene_queue.h"
 #include "lp_fence.h"
 
 
-/** List of texture references */
-struct texture_ref {
-   struct pipe_resource *texture;
-   struct texture_ref *prev, *next;  /**< linked list w/ u_simple_list.h */
-};
+#define RESOURCE_REF_SZ 32
 
+/** List of resource references */
+struct resource_ref {
+   struct pipe_resource *resource[RESOURCE_REF_SZ];
+   int count;
+   struct resource_ref *next;
+};
 
 
 /**
@@ -51,7 +54,6 @@ struct lp_scene *
 lp_scene_create( struct pipe_context *pipe,
                  struct lp_scene_queue *queue )
 {
-   unsigned i, j;
    struct lp_scene *scene = CALLOC_STRUCT(lp_scene);
    if (!scene)
       return NULL;
@@ -59,18 +61,6 @@ lp_scene_create( struct pipe_context *pipe,
    scene->pipe = pipe;
    scene->empty_queue = queue;
 
-   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->resources);
-
    pipe_mutex_init(scene->mutex);
 
    return scene;
@@ -83,24 +73,9 @@ lp_scene_create( struct pipe_context *pipe,
 void
 lp_scene_destroy(struct lp_scene *scene)
 {
-   unsigned i, j;
-
    lp_scene_reset(scene);
 
-   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);
-         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);
-
    FREE(scene);
 }
 
@@ -118,7 +93,7 @@ lp_scene_is_empty(struct lp_scene *scene )
       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) {
+         if (list->head) {
             return FALSE;
          }
       }
@@ -127,28 +102,31 @@ lp_scene_is_empty(struct lp_scene *scene )
 }
 
 
-/* Free data for one particular bin.  May be called from the
- * rasterizer thread(s).
+/* Returns true if there has ever been a failed allocation attempt in
+ * this scene.  Used in triangle/rectangle emit to avoid having to
+ * check success at each bin.
+ */
+boolean
+lp_scene_is_oom(struct lp_scene *scene)
+{
+   return scene->alloc_failed;
+}
+
+
+/* Remove all commands from a bin.  Tries to reuse some of the memory
+ * allocated to the bin, however.
  */
 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;
 
-   assert(x < TILES_X);
-   assert(y < TILES_Y);
-
-   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;
+   if (list->tail) {
+      list->tail->next = NULL;
+      list->tail->count = 0;
+   }
 }
 
 
@@ -159,13 +137,14 @@ lp_scene_bin_reset(struct lp_scene *scene, unsigned x, unsigned y)
 void
 lp_scene_reset(struct lp_scene *scene )
 {
-   unsigned i, j;
+   int i, j;
 
-   /* Free all but last binner command lists:
+   /* Reset all 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);
+         struct cmd_bin *bin = lp_scene_get_bin(scene, i, j);
+         memset(bin, 0, sizeof *bin);
       }
    }
 
@@ -174,39 +153,53 @@ lp_scene_reset(struct lp_scene *scene )
     */
    assert(lp_scene_is_empty(scene));
 
-   /* Free all but last binned data block:
+   /* Decrement texture ref counts
+    */
+   {
+      struct resource_ref *ref;
+      int i, j = 0;
+
+      for (ref = scene->resources; ref; ref = ref->next) {
+         for (i = 0; i < ref->count; i++) {
+            if (LP_DEBUG & DEBUG_SETUP)
+               debug_printf("resource %d: %p %dx%d sz %d\n",
+                            j,
+                            ref->resource[i],
+                            ref->resource[i]->width0,
+                            ref->resource[i]->height0,
+                            llvmpipe_resource_size(ref->resource[i]));
+            j++;
+            pipe_resource_reference(&ref->resource[i], NULL);
+         }
+      }
+
+      if (LP_DEBUG & DEBUG_SETUP)
+         debug_printf("scene %d resources, sz %d\n",
+                      j, scene->resource_reference_size);
+   }
+
+   /* Free all scene data blocks:
     */
    {
       struct data_block_list *list = &scene->data;
       struct data_block *block, *tmp;
 
-      for (block = list->head; block != list->tail; block = tmp) {
+      for (block = list->head; block; block = tmp) {
          tmp = block->next;
          FREE(block);
       }
-         
-      assert(list->tail->next == NULL);
-      list->head = list->tail;
-      list->head->used = 0;
-   }
 
-   /* Release texture refs
-    */
-   {
-      struct resource_ref *ref, *next, *ref_list = &scene->resources;
-      for (ref = ref_list->next; ref != ref_list; ref = next) {
-         next = next_elem(ref);
-         pipe_resource_reference(&ref->resource, NULL);
-         FREE(ref);
-      }
-      make_empty_list(ref_list);
+      list->head = NULL;
    }
 
    lp_fence_reference(&scene->fence, NULL);
 
+   scene->resources = NULL;
    scene->scene_size = 0;
+   scene->resource_reference_size = 0;
 
    scene->has_depthstencil_clear = FALSE;
+   scene->alloc_failed = FALSE;
 }
 
 
@@ -215,12 +208,20 @@ lp_scene_reset(struct lp_scene *scene )
 
 
 struct cmd_block *
-lp_bin_new_cmd_block( struct cmd_block_list *list )
+lp_scene_new_cmd_block( struct lp_scene *scene,
+                        struct cmd_bin *bin )
 {
-   struct cmd_block *block = MALLOC_STRUCT(cmd_block);
+   struct cmd_block *block = lp_scene_alloc(scene, sizeof(struct cmd_block));
    if (block) {
-      list->tail->next = block;
-      list->tail = block;
+      if (bin->commands.tail) {
+         bin->commands.tail->next = block;
+         bin->commands.tail = block;
+      }
+      else {
+         bin->commands.head = block;
+         bin->commands.tail = block;
+      }
+      //memset(block, 0, sizeof *block);
       block->next = NULL;
       block->count = 0;
    }
@@ -229,16 +230,26 @@ lp_bin_new_cmd_block( struct cmd_block_list *list )
 
 
 struct data_block *
-lp_bin_new_data_block( struct data_block_list *list )
+lp_scene_new_data_block( struct lp_scene *scene )
 {
-   struct data_block *block = MALLOC_STRUCT(data_block);
-   if (block) {
-      list->tail->next = block;
-      list->tail = block;
-      block->next = NULL;
+   if (scene->scene_size + DATA_BLOCK_SIZE > LP_SCENE_MAX_SIZE) {
+      if (0) debug_printf("%s: failed\n", __FUNCTION__);
+      scene->alloc_failed = TRUE;
+      return NULL;
+   }
+   else {
+      struct data_block *block = MALLOC_STRUCT(data_block);
+      if (block == NULL)
+         return NULL;
+      
+      scene->scene_size += sizeof *block;
+
       block->used = 0;
+      block->next = scene->data.head;
+      scene->data.head = block;
+
+      return block;
    }
-   return block;
 }
 
 
@@ -246,7 +257,7 @@ lp_bin_new_data_block( struct data_block_list *list )
  * Return number of bytes used for all bin data within a scene.
  * This does not include resources (textures) referenced by the scene.
  */
-unsigned
+static unsigned
 lp_scene_data_size( const struct lp_scene *scene )
 {
    unsigned size = 0;
@@ -259,7 +270,7 @@ lp_scene_data_size( const struct lp_scene *scene )
 
 
 /** Return number of bytes used for a single bin */
-unsigned
+static 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);
@@ -276,18 +287,47 @@ lp_scene_bin_size( const struct lp_scene *scene, unsigned x, unsigned y )
 /**
  * Add a reference to a resource by the scene.
  */
-void
+boolean
 lp_scene_add_resource_reference(struct lp_scene *scene,
                                 struct pipe_resource *resource)
 {
-   struct resource_ref *ref = CALLOC_STRUCT(resource_ref);
-   if (ref) {
-      struct resource_ref *ref_list = &scene->resources;
-      pipe_resource_reference(&ref->resource, resource);
-      insert_at_tail(ref_list, ref);
+   struct resource_ref *ref, **last = &scene->resources;
+   int i;
+
+   /* Look at existing resource blocks:
+    */
+   for (ref = scene->resources; ref; ref = ref->next) {
+
+      /* Search for this resource:
+       */
+      for (i = 0; i < ref->count; i++)
+         if (ref->resource[i] == resource)
+            return TRUE;
+
+      /* If the block is half-empty, this is the last block.  Append
+       * the reference here.
+       */
+      if (ref->count < RESOURCE_REF_SZ)
+         goto add_new_ref;
+
+      last = &ref->next;
    }
 
-   scene->scene_size += llvmpipe_resource_size(resource);
+   /* Otherwise, need to create a new block:
+    */
+   *last = lp_scene_alloc(scene, sizeof(struct resource_ref));
+   if (*last) {
+      ref = *last;
+      memset(ref, 0, sizeof *ref);
+      goto add_new_ref;
+   }
+
+   return FALSE;
+
+add_new_ref:
+   pipe_resource_reference(&ref->resource[ref->count++], resource);
+   scene->resource_reference_size += llvmpipe_resource_size(resource);
+   return scene->resource_reference_size < LP_SCENE_MAX_RESOURCE_SIZE;
 }
 
 
@@ -298,12 +338,15 @@ boolean
 lp_scene_is_resource_referenced(const struct lp_scene *scene,
                                 const struct pipe_resource *resource)
 {
-   const struct resource_ref *ref_list = &scene->resources;
    const struct resource_ref *ref;
-   foreach (ref, ref_list) {
-      if (ref->resource == resource)
-         return TRUE;
+   int i;
+
+   for (ref = scene->resources; ref; ref = ref->next) {
+      for (i = 0; i < ref->count; i++)
+         if (ref->resource[i] == resource)
+            return TRUE;
    }
+
    return FALSE;
 }
 
diff --git a/src/gallium/drivers/llvmpipe/lp_scene.h b/src/gallium/drivers/llvmpipe/lp_scene.h
index e933a84..d4f7b04 100644
--- a/src/gallium/drivers/llvmpipe/lp_scene.h
+++ b/src/gallium/drivers/llvmpipe/lp_scene.h
@@ -48,9 +48,17 @@ struct lp_scene_queue;
 #define TILES_Y (LP_MAX_HEIGHT / TILE_SIZE)
 
 
-#define CMD_BLOCK_MAX 128
-#define DATA_BLOCK_SIZE (16 * 1024 - sizeof(unsigned) - sizeof(void *))
-   
+#define CMD_BLOCK_MAX 16
+#define DATA_BLOCK_SIZE (64 * 1024 - 2 * sizeof(void *))
+
+/* Scene temporary storage is clamped to this size:
+ */
+#define LP_SCENE_MAX_SIZE (1024*1024)
+
+/* The maximum amount of texture storage referenced by a scene is
+ * clamped ot this size:
+ */
+#define LP_SCENE_MAX_RESOURCE_SIZE (64*1024*1024)
 
 
 /* switch to a non-pointer value for this:
@@ -65,16 +73,18 @@ struct cmd_block {
    struct cmd_block *next;
 };
 
+struct cmd_block_list {
+   struct cmd_block *head;
+   struct cmd_block *tail;
+};
+
 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.
@@ -85,22 +95,17 @@ struct cmd_bin {
    
 
 /**
- * This stores bulk data which is shared by all bins within a scene.
+ * This stores bulk data which is used for all memory allocations
+ * 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 resource references */
-struct resource_ref {
-   struct pipe_resource *resource;
-   struct resource_ref *prev, *next;  /**< linked list w/ u_simple_list.h */
 };
 
+struct resource_ref;
 
 /**
  * All bins and bin data are contained here.
@@ -118,13 +123,21 @@ struct lp_scene {
    struct pipe_framebuffer_state fb;
 
    /** list of resources referenced by the scene commands */
-   struct resource_ref resources;
+   struct resource_ref *resources;
 
-   /** Approx memory used by the scene (in bytes).  This includes the
-    * shared and per-tile bins plus any referenced resources/textures.
+   /** Total memory used by the scene (in bytes).  This sums all the
+    * data blocks and counts all bins, state, resource references and
+    * other random allocations within the scene.
     */
    unsigned scene_size;
 
+   /** Sum of sizes of all resources referenced by the scene.  Sums
+    * all the textures read by the scene:
+    */
+   unsigned resource_reference_size;
+
+   boolean alloc_failed;
+
    boolean has_depthstencil_clear;
 
    /**
@@ -151,22 +164,18 @@ struct lp_scene *lp_scene_create(struct pipe_context *pipe,
 
 void lp_scene_destroy(struct lp_scene *scene);
 
-
-
 boolean lp_scene_is_empty(struct lp_scene *scene );
+boolean lp_scene_is_oom(struct lp_scene *scene );
 
 void lp_scene_reset(struct lp_scene *scene );
 
 
-struct data_block *lp_bin_new_data_block( struct data_block_list *list );
-
-struct cmd_block *lp_bin_new_cmd_block( struct cmd_block_list *list );
+struct data_block *lp_scene_new_data_block( struct lp_scene *scene );
 
-unsigned lp_scene_data_size( const struct lp_scene *scene );
+struct cmd_block *lp_scene_new_cmd_block( struct lp_scene *scene,
+                                          struct cmd_bin *bin );
 
-unsigned lp_scene_bin_size( const struct lp_scene *scene, unsigned x, unsigned y );
-
-void lp_scene_add_resource_reference(struct lp_scene *scene,
+boolean lp_scene_add_resource_reference(struct lp_scene *scene,
                                      struct pipe_resource *resource);
 
 boolean lp_scene_is_resource_referenced(const struct lp_scene *scene,
@@ -181,21 +190,21 @@ static INLINE void *
 lp_scene_alloc( struct lp_scene *scene, unsigned size)
 {
    struct data_block_list *list = &scene->data;
-   struct data_block *tail = list->tail;
+   struct data_block *block = list->head;
 
-   if (tail->used + size > DATA_BLOCK_SIZE) {
-      tail = lp_bin_new_data_block( list );
-      if (!tail) {
+   assert(size <= DATA_BLOCK_SIZE);
+
+   if (block == NULL || block->used + size > DATA_BLOCK_SIZE) {
+      block = lp_scene_new_data_block( scene );
+      if (!block) {
          /* out of memory */
          return NULL;
       }
    }
 
-   scene->scene_size += size;
-
    {
-      ubyte *data = tail->data + tail->used;
-      tail->used += size;
+      ubyte *data = block->data + block->used;
+      block->used += size;
       return data;
    }
 }
@@ -209,20 +218,19 @@ lp_scene_alloc_aligned( struct lp_scene *scene, unsigned size,
 			unsigned alignment )
 {
    struct data_block_list *list = &scene->data;
-   struct data_block *tail = list->tail;
+   struct data_block *block = list->head;
 
-   if (tail->used + size + alignment - 1 > DATA_BLOCK_SIZE) {
-      tail = lp_bin_new_data_block( list );
-      if (!tail)
+   if (block == NULL ||
+       block->used + size + alignment - 1 > DATA_BLOCK_SIZE) {
+      block = lp_scene_new_data_block( scene );
+      if (!block)
          return NULL;
    }
 
-   scene->scene_size += size;
-
    {
-      ubyte *data = tail->data + tail->used;
+      ubyte *data = block->data + block->used;
       unsigned offset = (((uintptr_t)data + alignment - 1) & ~(alignment - 1)) - (uintptr_t)data;
-      tail->used += offset + size;
+      block->used += offset + size;
       return data + offset;
    }
 }
@@ -234,9 +242,8 @@ static INLINE void
 lp_scene_putback_data( struct lp_scene *scene, unsigned size)
 {
    struct data_block_list *list = &scene->data;
-   scene->scene_size -= size;
-   assert(list->tail->used >= size);
-   list->tail->used -= size;
+   assert(list->head && list->head->used >= size);
+   list->head->used -= size;
 }
 
 
@@ -255,24 +262,22 @@ lp_scene_bin_reset(struct lp_scene *scene, unsigned x, unsigned y);
 
 /* Add a command to bin[x][y].
  */
-static INLINE void
+static INLINE boolean
 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;
-   struct cmd_block *tail = list->tail;
+   struct cmd_block *tail = bin->commands.tail;
 
    assert(x < scene->tiles_x);
    assert(y < scene->tiles_y);
 
-   if (tail->count == CMD_BLOCK_MAX) {
-      tail = lp_bin_new_cmd_block( list );
+   if (tail == NULL || tail->count == CMD_BLOCK_MAX) {
+      tail = lp_scene_new_cmd_block( scene, bin );
       if (!tail) {
-         /* out of memory - simply ignore this command (for now) */
-         return;
+         return FALSE;
       }
       assert(tail->count == 0);
    }
@@ -283,27 +288,28 @@ lp_scene_bin_command( struct lp_scene *scene,
       tail->arg[i] = arg;
       tail->count++;
    }
+   
+   return TRUE;
 }
 
 
 /* Add a command to all active bins.
  */
-static INLINE void
+static INLINE boolean
 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 );
-}
-
+   for (i = 0; i < scene->tiles_x; i++) {
+      for (j = 0; j < scene->tiles_y; j++) {
+         if (!lp_scene_bin_command( scene, i, j, cmd, arg ))
+            return FALSE;
+      }
+   }
 
-void
-lp_scene_bin_state_command( struct lp_scene *scene,
-			    lp_rast_cmd cmd,
-			    const union lp_rast_cmd_arg arg );
+   return TRUE;
+}
 
 
 static INLINE unsigned
@@ -329,11 +335,5 @@ lp_scene_begin_binning( struct lp_scene *scene,
                         struct pipe_framebuffer_state *fb );
 
 
-static INLINE unsigned
-lp_scene_get_size(const struct lp_scene *scene)
-{
-   return scene->scene_size;
-}
-
 
 #endif /* LP_BIN_H */
diff --git a/src/gallium/drivers/llvmpipe/lp_setup.c b/src/gallium/drivers/llvmpipe/lp_setup.c
index 3bef620..476d23f 100644
--- a/src/gallium/drivers/llvmpipe/lp_setup.c
+++ b/src/gallium/drivers/llvmpipe/lp_setup.c
@@ -70,26 +70,6 @@ lp_setup_get_current_scene(struct lp_setup_context *setup)
 }
 
 
-/**
- * Check if the size of the current scene has exceeded the limit.
- * If so, flush/render it.
- */
-static void
-setup_check_scene_size_and_flush(struct lp_setup_context *setup)
-{
-   if (setup->scene) {
-      struct lp_scene *scene = lp_setup_get_current_scene(setup);
-      unsigned size = lp_scene_get_size(scene);
-
-      if (size > LP_MAX_SCENE_SIZE) {
-         /*printf("LLVMPIPE: scene size = %u, flushing.\n", size);*/
-         set_scene_state( setup, SETUP_FLUSHED );
-         /*assert(lp_scene_get_size(scene) == 0);*/
-      }
-   }
-}
-
-
 static void
 first_triangle( struct lp_setup_context *setup,
                 const float (*v0)[4],
@@ -191,9 +171,10 @@ begin_binning( struct lp_setup_context *setup )
 
    if (setup->fb.nr_cbufs) {
       if (setup->clear.flags & PIPE_CLEAR_COLOR) {
-         lp_scene_bin_everywhere( scene, 
-				  lp_rast_clear_color, 
-				  setup->clear.color );
+         ok = lp_scene_bin_everywhere( scene, 
+                                       lp_rast_clear_color, 
+                                       setup->clear.color );
+         assert(ok);
       }
    }
 
@@ -201,18 +182,20 @@ begin_binning( struct lp_setup_context *setup )
       if (setup->clear.flags & PIPE_CLEAR_DEPTHSTENCIL) {
          if (!need_zsload)
             scene->has_depthstencil_clear = TRUE;
-         lp_scene_bin_everywhere( scene,
-                                  lp_rast_clear_zstencil,
-                                  lp_rast_arg_clearzs(
-                                     setup->clear.zsmask,
-                                     setup->clear.zsvalue));
+         ok = lp_scene_bin_everywhere( scene,
+                                       lp_rast_clear_zstencil,
+                                       lp_rast_arg_clearzs(
+                                          setup->clear.zsmask,
+                                          setup->clear.zsvalue));
+         assert(ok);
       }
    }
 
    if (setup->active_query) {
-      lp_scene_bin_everywhere( scene,
-                               lp_rast_restart_query,
-                               lp_rast_arg_query(setup->active_query) );
+      ok = lp_scene_bin_everywhere( scene,
+                                    lp_rast_restart_query,
+                                    lp_rast_arg_query(setup->active_query) );
+      assert(ok);
    }
       
 
@@ -254,7 +237,6 @@ set_scene_state( struct lp_setup_context *setup,
       /* wait for a free/empty scene
        */
       setup->scene = lp_scene_dequeue(setup->empty_scenes, TRUE);
-      assert(lp_scene_is_empty(setup->scene));
       lp_scene_begin_binning(setup->scene,
                              &setup->fb );
       break;
@@ -333,12 +315,12 @@ lp_setup_bind_framebuffer( struct lp_setup_context *setup,
 }
 
 
-void
-lp_setup_clear( struct lp_setup_context *setup,
-                const float *color,
-                double depth,
-                unsigned stencil,
-                unsigned flags )
+static boolean
+lp_setup_try_clear( struct lp_setup_context *setup,
+                    const float *color,
+                    double depth,
+                    unsigned stencil,
+                    unsigned flags )
 {
    struct lp_scene *scene = lp_setup_get_current_scene(setup);
    uint32_t zsmask = 0;
@@ -371,15 +353,17 @@ lp_setup_clear( struct lp_setup_context *setup,
        * a common usage.
        */
       if (flags & PIPE_CLEAR_COLOR) {
-         lp_scene_bin_everywhere( scene, 
-                                  lp_rast_clear_color,
-                                  setup->clear.color );
+         if (!lp_scene_bin_everywhere( scene, 
+                                       lp_rast_clear_color,
+                                       setup->clear.color ))
+            return FALSE;
       }
 
       if (flags & PIPE_CLEAR_DEPTHSTENCIL) {
-         lp_scene_bin_everywhere( scene,
-                                  lp_rast_clear_zstencil,
-                                  lp_rast_arg_clearzs(zsmask, zsvalue) );
+         if (!lp_scene_bin_everywhere( scene,
+                                       lp_rast_clear_zstencil,
+                                       lp_rast_arg_clearzs(zsmask, zsvalue) ))
+            return FALSE;
       }
    }
    else {
@@ -404,38 +388,27 @@ lp_setup_clear( struct lp_setup_context *setup,
                 sizeof clear_color);
       }
    }
-}
 
+   return TRUE;
+}
 
-/**
- * Emit a fence.
- */
-struct pipe_fence_handle *
-lp_setup_fence( struct lp_setup_context *setup )
+void
+lp_setup_clear( struct lp_setup_context *setup,
+                const float *color,
+                double depth,
+                unsigned stencil,
+                unsigned flags )
 {
-   if (setup->scene == NULL)
-      return NULL;
-   else if (setup->num_threads == 0)
-      return NULL;
-   else
-   {
-      struct lp_scene *scene = lp_setup_get_current_scene(setup);
-      const unsigned rank = setup->num_threads;
+   if (!lp_setup_try_clear( setup, color, depth, stencil, flags )) {
+      lp_setup_flush(setup, 0, NULL, __FUNCTION__);
 
-      set_scene_state( setup, SETUP_ACTIVE );
-      
-      assert(scene->fence == NULL);
+      if (!lp_setup_try_clear( setup, color, depth, stencil, flags ))
+         assert(0);
+   }
+}
 
-      /* The caller gets a reference, we keep a copy too, so need to
-       * bump the refcount:
-       */
-      lp_fence_reference(&scene->fence, lp_fence_create(rank));
 
-      LP_DBG(DEBUG_SETUP, "%s rank %u\n", __FUNCTION__, rank);
 
-      return (struct pipe_fence_handle *) scene->fence;
-   }
-}
 
 
 void 
@@ -698,58 +671,34 @@ lp_setup_is_resource_referenced( const struct lp_setup_context *setup,
 /**
  * Called by vbuf code when we're about to draw something.
  */
-void
-lp_setup_update_state( struct lp_setup_context *setup )
+static boolean
+try_update_scene_state( struct lp_setup_context *setup )
 {
    struct lp_scene *scene;
 
    LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
 
-   setup_check_scene_size_and_flush(setup);
-
    scene = lp_setup_get_current_scene(setup);
 
    assert(setup->fs.current.variant);
 
-   /* Some of the 'draw' pipeline stages may have changed some driver state.
-    * Make sure we've processed those state changes before anything else.
-    *
-    * XXX this is the only place where llvmpipe_context is used in the
-    * setup code.  This may get refactored/changed...
-    */
-   {
-      struct llvmpipe_context *lp = llvmpipe_context(scene->pipe);
-
-      /* Will probably need to move this somewhere else, just need  
-       * to know about vertex shader point size attribute.
-       */
-      setup->psize = lp->psize_slot;
-
-      if (lp->dirty) {
-         llvmpipe_update_derived(lp);
-      }
-      assert(lp->dirty == 0);
-   }
-
    if(setup->dirty & LP_SETUP_NEW_BLEND_COLOR) {
       uint8_t *stored;
       unsigned i, j;
 
       stored = lp_scene_alloc_aligned(scene, 4 * 16, 16);
-
-      if (stored) {
-         /* smear each blend color component across 16 ubyte elements */
-         for (i = 0; i < 4; ++i) {
-            uint8_t c = float_to_ubyte(setup->blend_color.current.color[i]);
-            for (j = 0; j < 16; ++j)
-               stored[i*16 + j] = c;
-         }
-
-         setup->blend_color.stored = stored;
-
-         setup->fs.current.jit_context.blend_color = setup->blend_color.stored;
+      if (!stored)
+         return FALSE;
+
+      /* smear each blend color component across 16 ubyte elements */
+      for (i = 0; i < 4; ++i) {
+         uint8_t c = float_to_ubyte(setup->blend_color.current.color[i]);
+         for (j = 0; j < 16; ++j)
+            stored[i*16 + j] = c;
       }
 
+      setup->blend_color.stored = stored;
+      setup->fs.current.jit_context.blend_color = setup->blend_color.stored;
       setup->dirty |= LP_SETUP_NEW_FS;
    }
 
@@ -770,13 +719,14 @@ lp_setup_update_state( struct lp_setup_context *setup )
             void *stored;
 
             stored = lp_scene_alloc(scene, current_size);
-            if(stored) {
-               memcpy(stored,
-                      current_data,
-                      current_size);
-               setup->constants.stored_size = current_size;
-               setup->constants.stored_data = stored;
-            }
+            if (!stored)
+               return FALSE;
+
+            memcpy(stored,
+                   current_data,
+                   current_size);
+            setup->constants.stored_size = current_size;
+            setup->constants.stored_data = stored;
          }
       }
       else {
@@ -789,31 +739,37 @@ lp_setup_update_state( struct lp_setup_context *setup )
    }
 
 
-   if(setup->dirty & LP_SETUP_NEW_FS) {
-      if(!setup->fs.stored ||
-         memcmp(setup->fs.stored,
-                &setup->fs.current,
-                sizeof setup->fs.current) != 0) {
+   if (setup->dirty & LP_SETUP_NEW_FS) {
+      if (!setup->fs.stored ||
+          memcmp(setup->fs.stored,
+                 &setup->fs.current,
+                 sizeof setup->fs.current) != 0)
+      {
+         struct lp_rast_state *stored;
+         uint i;
+         
          /* The fs state that's been stored in the scene is different from
           * the new, current state.  So allocate a new lp_rast_state object
           * and append it to the bin's setup data buffer.
           */
-         uint i;
-         struct lp_rast_state *stored =
-            (struct lp_rast_state *) lp_scene_alloc(scene, sizeof *stored);
-         if(stored) {
-            memcpy(stored,
-                   &setup->fs.current,
-                   sizeof setup->fs.current);
-            setup->fs.stored = stored;
-         }
+         stored = (struct lp_rast_state *) lp_scene_alloc(scene, sizeof *stored);
+         if (!stored)
+            return FALSE;
 
+         memcpy(stored,
+                &setup->fs.current,
+                sizeof setup->fs.current);
+         setup->fs.stored = stored;
+         
          /* The scene now references the textures in the rasterization
           * state record.  Note that now.
           */
          for (i = 0; i < Elements(setup->fs.current_tex); i++) {
-            if (setup->fs.current_tex[i])
-               lp_scene_add_resource_reference(scene, setup->fs.current_tex[i]);
+            if (setup->fs.current_tex[i]) {
+               if (!lp_scene_add_resource_reference(scene,
+                                                    setup->fs.current_tex[i]))
+                  return FALSE;
+            }
          }
       }
    }
@@ -829,6 +785,40 @@ lp_setup_update_state( struct lp_setup_context *setup )
    setup->dirty = 0;
 
    assert(setup->fs.stored);
+   return TRUE;
+}
+
+void
+lp_setup_update_state( struct lp_setup_context *setup )
+{
+   /* Some of the 'draw' pipeline stages may have changed some driver state.
+    * Make sure we've processed those state changes before anything else.
+    *
+    * XXX this is the only place where llvmpipe_context is used in the
+    * setup code.  This may get refactored/changed...
+    */
+   {
+      struct llvmpipe_context *lp = llvmpipe_context(setup->pipe);
+      if (lp->dirty) {
+         llvmpipe_update_derived(lp);
+      }
+
+      /* Will probably need to move this somewhere else, just need  
+       * to know about vertex shader point size attribute.
+       */
+      setup->psize = lp->psize_slot;
+
+      assert(lp->dirty == 0);
+   }
+
+   /* XXX: only call into update_scene_state() if we already have a
+    * scene:
+    */
+   if (!try_update_scene_state(setup)) {
+      set_scene_state( setup, SETUP_FLUSHED );
+      if (!try_update_scene_state(setup))
+         assert(0);
+   }
 }
 
 
@@ -881,6 +871,10 @@ lp_setup_create( struct pipe_context *pipe,
       return NULL;
 
    lp_setup_init_vbuf(setup);
+   
+   /* Used only in update_state():
+    */
+   setup->pipe = pipe;
 
    setup->empty_scenes = lp_scene_queue_create();
    if (!setup->empty_scenes)
@@ -932,9 +926,18 @@ lp_setup_begin_query(struct lp_setup_context *setup,
    assert(setup->active_query == NULL);
    
    if (setup->scene) {
-      lp_scene_bin_everywhere(setup->scene,
-                              lp_rast_begin_query,
-                              lp_rast_arg_query(pq));
+      if (!lp_scene_bin_everywhere(setup->scene,
+                                   lp_rast_begin_query,
+                                   lp_rast_arg_query(pq))) {
+         lp_setup_flush_and_restart(setup);
+
+         if (!lp_scene_bin_everywhere(setup->scene,
+                                      lp_rast_begin_query,
+                                      lp_rast_arg_query(pq))) {
+            assert(0);
+            return;
+         }
+      }
    }
 
    setup->active_query = pq;
@@ -963,7 +966,9 @@ lp_setup_end_query(struct lp_setup_context *setup, struct llvmpipe_query *pq)
        */
       lp_fence_reference(&pq->fence, setup->scene->fence);
 
-      lp_scene_bin_everywhere(setup->scene, lp_rast_end_query, dummy);
+      if (!lp_scene_bin_everywhere(setup->scene, lp_rast_end_query, dummy)) {
+         lp_setup_flush(setup, 0, NULL, __FUNCTION__);
+      }
    }
    else {
       lp_fence_reference(&pq->fence, setup->last_fence);
@@ -971,3 +976,14 @@ lp_setup_end_query(struct lp_setup_context *setup, struct llvmpipe_query *pq)
 }
 
 
+void
+lp_setup_flush_and_restart(struct lp_setup_context *setup)
+{
+   if (0) debug_printf("%s\n", __FUNCTION__);
+
+   assert(setup->state == SETUP_ACTIVE);
+   set_scene_state(setup, SETUP_FLUSHED);
+   set_scene_state(setup, SETUP_EMPTY);
+   set_scene_state(setup, SETUP_ACTIVE);
+   lp_setup_update_state(setup);
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_setup.h b/src/gallium/drivers/llvmpipe/lp_setup.h
index 821ebb1..b5ae4ec 100644
--- a/src/gallium/drivers/llvmpipe/lp_setup.h
+++ b/src/gallium/drivers/llvmpipe/lp_setup.h
@@ -78,8 +78,6 @@ lp_setup_clear(struct lp_setup_context *setup,
                unsigned clear_stencil,
                unsigned flags);
 
-struct pipe_fence_handle *
-lp_setup_fence( struct lp_setup_context *setup );
 
 
 void
diff --git a/src/gallium/drivers/llvmpipe/lp_setup_context.h b/src/gallium/drivers/llvmpipe/lp_setup_context.h
index fa4e5e9..3126cf1 100644
--- a/src/gallium/drivers/llvmpipe/lp_setup_context.h
+++ b/src/gallium/drivers/llvmpipe/lp_setup_context.h
@@ -70,6 +70,7 @@ struct lp_setup_context
 {
    struct vbuf_render base;
 
+   struct pipe_context *pipe;
    struct vertex_info *vertex_info;
    uint prim;
    uint vertex_size;
@@ -186,11 +187,13 @@ lp_setup_alloc_triangle(struct lp_scene *scene,
                         unsigned nr_planes,
                         unsigned *tri_size);
 
-void
+boolean
 lp_setup_bin_triangle( struct lp_setup_context *setup,
                        struct lp_rast_triangle *tri,
                        const struct u_rect *bbox,
                        int nr_planes );
 
+void lp_setup_flush_and_restart(struct lp_setup_context *setup);
+
 #endif
 
diff --git a/src/gallium/drivers/llvmpipe/lp_setup_line.c b/src/gallium/drivers/llvmpipe/lp_setup_line.c
index ce2da55..c9d3d7a 100644
--- a/src/gallium/drivers/llvmpipe/lp_setup_line.c
+++ b/src/gallium/drivers/llvmpipe/lp_setup_line.c
@@ -263,8 +263,8 @@ static INLINE float fracf(float f)
 
 
 
-static void
-lp_setup_line( struct lp_setup_context *setup,
+static boolean
+try_setup_line( struct lp_setup_context *setup,
                const float (*v1)[4],
                const float (*v2)[4])
 {
@@ -536,13 +536,13 @@ lp_setup_line( struct lp_setup_context *setup,
        bbox.y1 < bbox.y0) {
       if (0) debug_printf("empty bounding box\n");
       LP_COUNT(nr_culled_tris);
-      return;
+      return TRUE;
    }
 
    if (!u_rect_test_intersection(&setup->draw_region, &bbox)) {
       if (0) debug_printf("offscreen\n");
       LP_COUNT(nr_culled_tris);
-      return;
+      return TRUE;
    }
 
    u_rect_find_intersection(&setup->draw_region, &bbox);
@@ -552,7 +552,7 @@ lp_setup_line( struct lp_setup_context *setup,
                                   nr_planes,
                                   &tri_bytes);
    if (!line)
-      return;
+      return FALSE;
 
 #ifdef DEBUG
    line->v[0][0] = v1[0][0];
@@ -687,9 +687,23 @@ lp_setup_line( struct lp_setup_context *setup,
       line->plane[7].eo = 0;
    }
 
-   lp_setup_bin_triangle(setup, line, &bbox, nr_planes);
+   return lp_setup_bin_triangle(setup, line, &bbox, nr_planes);
 }
-   
+
+
+static void lp_setup_line( struct lp_setup_context *setup,
+                           const float (*v0)[4],
+                           const float (*v1)[4] )
+{
+   if (!try_setup_line( setup, v0, v1 ))
+   {
+      lp_setup_flush_and_restart(setup);
+
+      if (!try_setup_line( setup, v0, v1 ))
+         assert(0);
+   }
+}
+
 
 void lp_setup_choose_line( struct lp_setup_context *setup ) 
 { 
diff --git a/src/gallium/drivers/llvmpipe/lp_setup_point.c b/src/gallium/drivers/llvmpipe/lp_setup_point.c
index 6ae318d..fd6b53e 100644
--- a/src/gallium/drivers/llvmpipe/lp_setup_point.c
+++ b/src/gallium/drivers/llvmpipe/lp_setup_point.c
@@ -210,8 +210,9 @@ subpixel_snap(float a)
 }
 
 
-static void lp_setup_point( struct lp_setup_context *setup,
-                            const float (*v0)[4] )
+static boolean
+try_setup_point( struct lp_setup_context *setup,
+                 const float (*v0)[4] )
 {
    /* x/y positions in fixed point */
    const int sizeAttr = setup->psize;
@@ -259,7 +260,7 @@ static void lp_setup_point( struct lp_setup_context *setup,
    if (!u_rect_test_intersection(&setup->draw_region, &bbox)) {
       if (0) debug_printf("offscreen\n");
       LP_COUNT(nr_culled_tris);
-      return;
+      return TRUE;
    }
 
    u_rect_find_intersection(&setup->draw_region, &bbox);
@@ -269,7 +270,7 @@ static void lp_setup_point( struct lp_setup_context *setup,
                                    nr_planes,
                                    &bytes);
    if (!point)
-      return;
+      return FALSE;
 
 #ifdef DEBUG
    point->v[0][0] = v0[0][0];
@@ -315,7 +316,20 @@ static void lp_setup_point( struct lp_setup_context *setup,
       point->plane[3].eo = 0;
    }
 
-   lp_setup_bin_triangle(setup, point, &bbox, nr_planes);
+   return lp_setup_bin_triangle(setup, point, &bbox, nr_planes);
+}
+
+
+static void lp_setup_point( struct lp_setup_context *setup,
+                           const float (*v0)[4] )
+{
+   if (!try_setup_point( setup, v0 ))
+   {
+      lp_setup_flush_and_restart(setup);
+
+      if (!try_setup_point( setup, v0 ))
+         assert(0);
+   }
 }
 
 
diff --git a/src/gallium/drivers/llvmpipe/lp_setup_tri.c b/src/gallium/drivers/llvmpipe/lp_setup_tri.c
index e5aacbc..d8dd9ab 100644
--- a/src/gallium/drivers/llvmpipe/lp_setup_tri.c
+++ b/src/gallium/drivers/llvmpipe/lp_setup_tri.c
@@ -179,7 +179,7 @@ lp_rast_cmd lp_rast_tri_tab[9] = {
  *
  * \param tx, ty  the tile position in tiles, not pixels
  */
-static void
+static boolean
 lp_setup_whole_tile(struct lp_setup_context *setup,
                     const struct lp_rast_shader_inputs *inputs,
                     int tx, int ty)
@@ -198,14 +198,14 @@ lp_setup_whole_tile(struct lp_setup_context *setup,
       }
 
       LP_COUNT(nr_shade_opaque_64);
-      lp_scene_bin_command( scene, tx, ty,
-                            lp_rast_shade_tile_opaque,
-                            lp_rast_arg_inputs(inputs) );
+      return lp_scene_bin_command( scene, tx, ty,
+                                  lp_rast_shade_tile_opaque,
+                                  lp_rast_arg_inputs(inputs) );
    } else {
       LP_COUNT(nr_shade_64);
-      lp_scene_bin_command( scene, tx, ty,
-                            lp_rast_shade_tile,
-                            lp_rast_arg_inputs(inputs) );
+      return lp_scene_bin_command( scene, tx, ty,
+                                   lp_rast_shade_tile,
+                                   lp_rast_arg_inputs(inputs) );
    }
 }
 
@@ -215,7 +215,7 @@ lp_setup_whole_tile(struct lp_setup_context *setup,
  * framebuffer tiles are touched.  Put the triangle in the scene's
  * bins for the tiles which we overlap.
  */
-static void
+static boolean
 do_triangle_ccw(struct lp_setup_context *setup,
 		const float (*v0)[4],
 		const float (*v1)[4],
@@ -280,13 +280,13 @@ do_triangle_ccw(struct lp_setup_context *setup,
        bbox.y1 < bbox.y0) {
       if (0) debug_printf("empty bounding box\n");
       LP_COUNT(nr_culled_tris);
-      return;
+      return FALSE;
    }
 
    if (!u_rect_test_intersection(&setup->draw_region, &bbox)) {
       if (0) debug_printf("offscreen\n");
       LP_COUNT(nr_culled_tris);
-      return;
+      return FALSE;
    }
 
    u_rect_find_intersection(&setup->draw_region, &bbox);
@@ -296,7 +296,7 @@ do_triangle_ccw(struct lp_setup_context *setup,
                                  nr_planes,
                                  &tri_bytes);
    if (!tri)
-      return;
+      return FALSE;
 
 #ifdef DEBUG
    tri->v[0][0] = v0[0][0];
@@ -327,7 +327,7 @@ do_triangle_ccw(struct lp_setup_context *setup,
    if (area <= 0) {
       lp_scene_putback_data( scene, tri_bytes );
       LP_COUNT(nr_culled_tris);
-      return;
+      return TRUE;
    }
 
 
@@ -356,6 +356,7 @@ do_triangle_ccw(struct lp_setup_context *setup,
 
    tri->inputs.facing = frontfacing ? 1.0F : -1.0F;
    tri->inputs.opaque = variant->opaque;
+   tri->inputs.disable = FALSE;
    tri->inputs.state = setup->fs.stored;
 
 
@@ -460,11 +461,11 @@ do_triangle_ccw(struct lp_setup_context *setup,
       tri->plane[6].eo = 0;
    }
 
-   lp_setup_bin_triangle( setup, tri, &bbox, nr_planes );
+   return lp_setup_bin_triangle( setup, tri, &bbox, nr_planes );
 }
 
 
-void
+boolean
 lp_setup_bin_triangle( struct lp_setup_context *setup,
                        struct lp_rast_triangle *tri,
                        const struct u_rect *bbox,
@@ -494,10 +495,9 @@ lp_setup_bin_triangle( struct lp_setup_context *setup,
 	  */
 	 int mask = (ix0 & 3) | ((iy0 & 3) << 4);
 
-	 lp_scene_bin_command( scene, ix0/4, iy0/4,
-			       lp_rast_triangle_3_16,
-			       lp_rast_arg_triangle(tri, mask) );
-	 return;
+	 return lp_scene_bin_command( scene, ix0/4, iy0/4,
+                                      lp_rast_triangle_3_16,
+                                      lp_rast_arg_triangle(tri, mask) );
       }
    }
 
@@ -520,9 +520,9 @@ lp_setup_bin_triangle( struct lp_setup_context *setup,
    {
       /* Triangle is contained in a single tile:
        */
-      lp_scene_bin_command( scene, ix0, iy0,
-                            lp_rast_tri_tab[nr_planes], 
-			    lp_rast_arg_triangle(tri, (1<<nr_planes)-1) );
+      return lp_scene_bin_command( scene, ix0, iy0,
+                                   lp_rast_tri_tab[nr_planes], 
+                                   lp_rast_arg_triangle(tri, (1<<nr_planes)-1) );
    }
    else
    {
@@ -583,9 +583,10 @@ lp_setup_bin_triangle( struct lp_setup_context *setup,
                 */
                int count = util_bitcount(partial);
                in = TRUE;
-               lp_scene_bin_command( scene, x, y,
-                                     lp_rast_tri_tab[count], 
-                                     lp_rast_arg_triangle(tri, partial) );
+               if (!lp_scene_bin_command( scene, x, y,
+                                          lp_rast_tri_tab[count], 
+                                          lp_rast_arg_triangle(tri, partial) ))
+                  goto fail;
 
                LP_COUNT(nr_partially_covered_64);
             }
@@ -593,7 +594,8 @@ lp_setup_bin_triangle( struct lp_setup_context *setup,
                /* triangle covers the whole tile- shade whole tile */
                LP_COUNT(nr_fully_covered_64);
                in = TRUE;
-               lp_setup_whole_tile(setup, &tri->inputs, x, y);
+               if (!lp_setup_whole_tile(setup, &tri->inputs, x, y))
+                  goto fail;
             }
 
 	    /* Iterate cx values across the region:
@@ -608,6 +610,16 @@ lp_setup_bin_triangle( struct lp_setup_context *setup,
             c[i] += ystep[i];
       }
    }
+
+   return TRUE;
+
+fail:
+   /* Need to disable any partially binned triangle.  This is easier
+    * than trying to locate all the triangle, shade-tile, etc,
+    * commands which may have been binned.
+    */
+   tri->inputs.disable = TRUE;
+   return FALSE;
 }
 
 
@@ -619,7 +631,13 @@ static void triangle_cw( struct lp_setup_context *setup,
 			 const float (*v1)[4],
 			 const float (*v2)[4] )
 {
-   do_triangle_ccw( setup, v1, v0, v2, !setup->ccw_is_frontface );
+   if (!do_triangle_ccw( setup, v1, v0, v2, !setup->ccw_is_frontface ))
+   {
+      lp_setup_flush_and_restart(setup);
+
+      if (!do_triangle_ccw( setup, v1, v0, v2, !setup->ccw_is_frontface ))
+         assert(0);
+   }
 }
 
 
@@ -631,7 +649,12 @@ static void triangle_ccw( struct lp_setup_context *setup,
 			 const float (*v1)[4],
 			 const float (*v2)[4] )
 {
-   do_triangle_ccw( setup, v0, v1, v2, setup->ccw_is_frontface );
+   if (!do_triangle_ccw( setup, v0, v1, v2, setup->ccw_is_frontface ))
+   {
+      lp_setup_flush_and_restart(setup);
+      if (!do_triangle_ccw( setup, v0, v1, v2, setup->ccw_is_frontface ))
+         assert(0);
+   }
 }
 
 




More information about the mesa-commit mailing list