llvmpipe/fs: hook up the interpolation APIs.
[mesa.git] / src / gallium / drivers / llvmpipe / lp_scene.c
index 0c51b52d1700fa39ed7e47786286e32d7dc77e7e..59eed4145504942a08f6250f37cb72dd2af5ebb3 100644 (file)
  *
  **************************************************************************/
 
+#include "util/u_framebuffer.h"
 #include "util/u_math.h"
 #include "util/u_memory.h"
 #include "util/u_inlines.h"
-#include "util/u_simple_list.h"
-#include "util/u_surface.h"
+#include "util/simple_list.h"
+#include "util/format/u_format.h"
 #include "lp_scene.h"
-#include "lp_scene_queue.h"
+#include "lp_fence.h"
 #include "lp_debug.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;
+};
+
+
+/**
+ * Create a new scene object.
+ * \param queue  the queue to put newly rendered/emptied scenes into
+ */
 struct lp_scene *
-lp_scene_create( struct pipe_context *pipe,
-                 struct lp_scene_queue *queue )
+lp_scene_create( struct pipe_context *pipe )
 {
-   unsigned i, j;
    struct lp_scene *scene = CALLOC_STRUCT(lp_scene);
    if (!scene)
       return NULL;
 
    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);
+      CALLOC_STRUCT(data_block);
 
-   make_empty_list(&scene->textures);
+   (void) mtx_init(&scene->mutex, mtx_plain);
 
-   pipe_mutex_init(scene->mutex);
+#ifdef DEBUG
+   /* Do some scene limit sanity checks here */
+   {
+      size_t maxBins = TILES_X * TILES_Y;
+      size_t maxCommandBytes = sizeof(struct cmd_block) * maxBins;
+      size_t maxCommandPlusData = maxCommandBytes + DATA_BLOCK_SIZE;
+      /* We'll need at least one command block per bin.  Make sure that's
+       * less than the max allowed scene size.
+       */
+      assert(maxCommandBytes < LP_SCENE_MAX_SIZE);
+      /* We'll also need space for at least one other data block */
+      assert(maxCommandPlusData <= LP_SCENE_MAX_SIZE);
+   }
+#endif
 
    return scene;
 }
 
 
 /**
- * Free all data associated with the given scene, and free(scene).
+ * Free all data associated with the given scene, and the scene itself.
  */
 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;
-      }
-
+   lp_fence_reference(&scene->fence, NULL);
+   mtx_destroy(&scene->mutex);
+   assert(scene->data.head->next == NULL);
    FREE(scene->data.head);
-   scene->data.head = NULL;
-
-   pipe_mutex_destroy(scene->mutex);
-
    FREE(scene);
 }
 
@@ -102,11 +106,10 @@ 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++) {
+   for (y = 0; y < scene->tiles_y; y++) {
+      for (x = 0; x < scene->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 (bin->head) {
             return FALSE;
          }
       }
@@ -115,77 +118,193 @@ 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 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);
+   bin->last_state = NULL;
+   bin->head = bin->tail;
+   if (bin->tail) {
+      bin->tail->next = NULL;
+      bin->tail->count = 0;
+   }
+}
+
+
+void
+lp_scene_begin_rasterization(struct lp_scene *scene)
+{
+   const struct pipe_framebuffer_state *fb = &scene->fb;
+   int i;
+
+   //LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
+
+   for (i = 0; i < scene->fb.nr_cbufs; i++) {
+      struct pipe_surface *cbuf = scene->fb.cbufs[i];
+
+      if (!cbuf) {
+         scene->cbufs[i].stride = 0;
+         scene->cbufs[i].layer_stride = 0;
+         scene->cbufs[i].sample_stride = 0;
+         scene->cbufs[i].nr_samples = 0;
+         scene->cbufs[i].map = NULL;
+         continue;
+      }
 
-   for (block = list->head; block != list->tail; block = tmp) {
-      tmp = block->next;
-      FREE(block);
+      if (llvmpipe_resource_is_texture(cbuf->texture)) {
+         scene->cbufs[i].stride = llvmpipe_resource_stride(cbuf->texture,
+                                                           cbuf->u.tex.level);
+         scene->cbufs[i].layer_stride = llvmpipe_layer_stride(cbuf->texture,
+                                                              cbuf->u.tex.level);
+         scene->cbufs[i].sample_stride = llvmpipe_sample_stride(cbuf->texture);
+
+         scene->cbufs[i].map = llvmpipe_resource_map(cbuf->texture,
+                                                     cbuf->u.tex.level,
+                                                     cbuf->u.tex.first_layer,
+                                                     LP_TEX_USAGE_READ_WRITE);
+         scene->cbufs[i].format_bytes = util_format_get_blocksize(cbuf->format);
+         scene->cbufs[i].nr_samples = util_res_sample_count(cbuf->texture);
+      }
+      else {
+         struct llvmpipe_resource *lpr = llvmpipe_resource(cbuf->texture);
+         unsigned pixstride = util_format_get_blocksize(cbuf->format);
+         scene->cbufs[i].stride = cbuf->texture->width0;
+         scene->cbufs[i].layer_stride = 0;
+         scene->cbufs[i].sample_stride = 0;
+         scene->cbufs[i].nr_samples = 1;
+         scene->cbufs[i].map = lpr->data;
+         scene->cbufs[i].map += cbuf->u.buf.first_element * pixstride;
+         scene->cbufs[i].format_bytes = util_format_get_blocksize(cbuf->format);
+      }
    }
 
-   assert(list->tail->next == NULL);
-   list->head = list->tail;
-   list->head->count = 0;
+   if (fb->zsbuf) {
+      struct pipe_surface *zsbuf = scene->fb.zsbuf;
+      scene->zsbuf.stride = llvmpipe_resource_stride(zsbuf->texture, zsbuf->u.tex.level);
+      scene->zsbuf.layer_stride = llvmpipe_layer_stride(zsbuf->texture, zsbuf->u.tex.level);
+      scene->zsbuf.sample_stride = llvmpipe_sample_stride(zsbuf->texture);
+      scene->zsbuf.nr_samples = util_res_sample_count(zsbuf->texture);
+      scene->zsbuf.map = llvmpipe_resource_map(zsbuf->texture,
+                                               zsbuf->u.tex.level,
+                                               zsbuf->u.tex.first_layer,
+                                               LP_TEX_USAGE_READ_WRITE);
+      scene->zsbuf.format_bytes = util_format_get_blocksize(zsbuf->format);
+   }
 }
 
 
+
+
 /**
- * Free all the temporary data in a scene.  May be called from the
- * rasterizer thread(s).
+ * Free all the temporary data in a scene.
  */
 void
-lp_scene_reset(struct lp_scene *scene )
+lp_scene_end_rasterization(struct lp_scene *scene )
 {
-   unsigned i, j;
+   int i, j;
+
+   /* Unmap color buffers */
+   for (i = 0; i < scene->fb.nr_cbufs; i++) {
+      if (scene->cbufs[i].map) {
+         struct pipe_surface *cbuf = scene->fb.cbufs[i];
+         if (llvmpipe_resource_is_texture(cbuf->texture)) {
+            llvmpipe_resource_unmap(cbuf->texture,
+                                    cbuf->u.tex.level,
+                                    cbuf->u.tex.first_layer);
+         }
+         scene->cbufs[i].map = NULL;
+      }
+   }
 
-   /* Free all but last binner command lists:
+   /* Unmap z/stencil buffer */
+   if (scene->zsbuf.map) {
+      struct pipe_surface *zsbuf = scene->fb.zsbuf;
+      llvmpipe_resource_unmap(zsbuf->texture,
+                              zsbuf->u.tex.level,
+                              zsbuf->u.tex.first_layer);
+      scene->zsbuf.map = NULL;
+   }
+
+   /* 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);
+         bin->head = NULL;
+         bin->tail = NULL;
+         bin->last_state = NULL;
       }
    }
 
+   /* If there are any bins which weren't cleared by the loop above,
+    * they will be caught (on debug builds at least) by this assert:
+    */
    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,
+                            (void *) 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->next; block; block = tmp) {
          tmp = block->next;
-         FREE(block);
+        FREE(block);
       }
-         
-      assert(list->tail->next == NULL);
-      list->head = list->tail;
+
+      list->head->next = NULL;
       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);
-   }
+   lp_fence_reference(&scene->fence, NULL);
+
+   scene->resources = NULL;
+   scene->scene_size = 0;
+   scene->resource_reference_size = 0;
+
+   scene->alloc_failed = FALSE;
+
+   util_unreference_framebuffer_state( &scene->fb );
 }
 
 
@@ -193,30 +312,57 @@ lp_scene_reset(struct lp_scene *scene )
 
 
 
-void
-lp_bin_new_cmd_block( struct cmd_block_list *list )
+struct cmd_block *
+lp_scene_new_cmd_block( struct lp_scene *scene,
+                        struct cmd_bin *bin )
 {
-   struct cmd_block *block = MALLOC_STRUCT(cmd_block);
-   list->tail->next = block;
-   list->tail = block;
-   block->next = NULL;
-   block->count = 0;
+   struct cmd_block *block = lp_scene_alloc(scene, sizeof(struct cmd_block));
+   if (block) {
+      if (bin->tail) {
+         bin->tail->next = block;
+         bin->tail = block;
+      }
+      else {
+         bin->head = block;
+         bin->tail = block;
+      }
+      //memset(block, 0, sizeof *block);
+      block->next = NULL;
+      block->count = 0;
+   }
+   return block;
 }
 
 
-void
-lp_bin_new_data_block( struct data_block_list *list )
+struct data_block *
+lp_scene_new_data_block( struct lp_scene *scene )
 {
-   struct data_block *block = MALLOC_STRUCT(data_block);
-   list->tail->next = block;
-   list->tail = block;
-   block->next = NULL;
-   block->used = 0;
+   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)
+         return NULL;
+      
+      scene->scene_size += sizeof *block;
+
+      block->used = 0;
+      block->next = scene->data.head;
+      scene->data.head = block;
+
+      return block;
+   }
 }
 
 
-/** Return number of bytes used for all bin data within a scene */
-unsigned
+/**
+ * Return number of bytes used for all bin data within a scene.
+ * This does not include resources (textures) referenced by the scene.
+ */
+static unsigned
 lp_scene_data_size( const struct lp_scene *scene )
 {
    unsigned size = 0;
@@ -228,110 +374,88 @@ lp_scene_data_size( const struct lp_scene *scene )
 }
 
 
-/** 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?
+ * Add a reference to a resource by the scene.
  */
 boolean
-lp_scene_is_texture_referenced( const struct lp_scene *scene,
-                                const struct pipe_texture *texture )
+lp_scene_add_resource_reference(struct lp_scene *scene,
+                                struct pipe_resource *resource,
+                                boolean initializing_scene)
 {
-   const struct texture_ref *ref_list = &scene->textures;
-   const struct texture_ref *ref;
-   foreach (ref, ref_list) {
-      if (ref->texture == texture)
-         return TRUE;
+   struct resource_ref *ref, **last = &scene->resources;
+   int i;
+
+   /* Look at existing resource blocks:
+    */
+   for (ref = scene->resources; ref; ref = ref->next) {
+      last = &ref->next;
+
+      /* Search for this resource:
+       */
+      for (i = 0; i < ref->count; i++)
+         if (ref->resource[i] == resource)
+            return TRUE;
+
+      if (ref->count < RESOURCE_REF_SZ) {
+         /* If the block is half-empty, then append the reference here.
+          */
+         break;
+      }
    }
-   return FALSE;
-}
 
+   /* Create a new block if no half-empty block was found.
+    */
+   if (!ref) {
+      assert(*last == NULL);
+      *last = lp_scene_alloc(scene, sizeof *ref);
+      if (*last == NULL)
+          return FALSE;
+
+      ref = *last;
+      memset(ref, 0, sizeof *ref);
+   }
 
-/**
- * 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;
-}
+   /* Append the reference to the reference block.
+    */
+   pipe_resource_reference(&ref->resource[ref->count++], resource);
+   scene->resource_reference_size += llvmpipe_resource_size(resource);
 
+   /* Heuristic to advise scene flushes.  This isn't helpful in the
+    * initial setup of the scene, but after that point flush on the
+    * next resource added which exceeds 64MB in referenced texture
+    * data.
+    */
+   if (!initializing_scene &&
+       scene->resource_reference_size >= LP_SCENE_MAX_RESOURCE_SIZE)
+      return FALSE;
 
-/**
- * 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;
+   return TRUE;
 }
 
 
-
 /**
- * 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.
+ * Does this scene have a reference to the given resource?
  */
-void
-lp_scene_bin_state_command( struct lp_scene *scene,
-                            lp_rast_cmd cmd,
-                            const union lp_rast_cmd_arg arg )
+boolean
+lp_scene_is_resource_referenced(const struct lp_scene *scene,
+                                const struct pipe_resource *resource)
 {
-   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 );
-         }
-      }
+   const struct resource_ref *ref;
+   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;
 }
 
 
+
+
 /** advance curr_x,y to the next bin */
 static boolean
 next_bin(struct lp_scene *scene)
@@ -363,11 +487,11 @@ lp_scene_bin_iter_begin( struct lp_scene *scene )
  * 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 )
+lp_scene_bin_iter_next( struct lp_scene *scene , int *x, int *y)
 {
    struct cmd_bin *bin = NULL;
 
-   pipe_mutex_lock(scene->mutex);
+   mtx_lock(&scene->mutex);
 
    if (scene->curr_x < 0) {
       /* first bin */
@@ -380,147 +504,74 @@ lp_scene_bin_iter_next( struct lp_scene *scene, int *bin_x, int *bin_y )
    }
 
    bin = lp_scene_get_bin(scene, scene->curr_x, scene->curr_y);
-   *bin_x = scene->curr_x;
-   *bin_y = scene->curr_y;
+   *x = scene->curr_x;
+   *y = scene->curr_y;
 
 end:
    /*printf("return bin %p at %d, %d\n", (void *) bin, *bin_x, *bin_y);*/
-   pipe_mutex_unlock(scene->mutex);
+   mtx_unlock(&scene->mutex);
    return bin;
 }
 
 
-/**
- * Prepare this scene for the rasterizer.
- * Map the framebuffer surfaces.  Initialize the 'rast' state.
- */
-static boolean
-lp_scene_map_buffers( struct lp_scene *scene )
+void lp_scene_begin_binning(struct lp_scene *scene,
+                            struct pipe_framebuffer_state *fb)
 {
-   struct pipe_surface *cbuf, *zsbuf;
    int i;
+   unsigned max_layer = ~0;
 
-   LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
+   assert(lp_scene_is_empty(scene));
 
+   util_copy_framebuffer_state(&scene->fb, fb);
 
-   /* Map all color buffers 
+   scene->tiles_x = align(fb->width, TILE_SIZE) / TILE_SIZE;
+   scene->tiles_y = align(fb->height, TILE_SIZE) / TILE_SIZE;
+   assert(scene->tiles_x <= TILES_X);
+   assert(scene->tiles_y <= TILES_Y);
+
+   /*
+    * Determine how many layers the fb has (used for clamping layer value).
+    * OpenGL (but not d3d10) permits different amount of layers per rt, however
+    * results are undefined if layer exceeds the amount of layers of ANY
+    * attachment hence don't need separate per cbuf and zsbuf max.
     */
    for (i = 0; i < scene->fb.nr_cbufs; i++) {
-      cbuf = scene->fb.cbufs[i];
+      struct pipe_surface *cbuf = scene->fb.cbufs[i];
       if (cbuf) {
-        scene->cbuf_map[i] = llvmpipe_texture_map(cbuf->texture,
-                                                  cbuf->face,
-                                                   cbuf->level,
-                                                   cbuf->zslice);
-        if (!scene->cbuf_map[i])
-           goto fail;
+         if (llvmpipe_resource_is_texture(cbuf->texture)) {
+            max_layer = MIN2(max_layer,
+                             cbuf->u.tex.last_layer - cbuf->u.tex.first_layer);
+         }
+         else {
+            max_layer = 0;
+         }
       }
    }
-
-   /* Map the zsbuffer
-    */
-   zsbuf = scene->fb.zsbuf;
-   if (zsbuf) {
-      scene->zsbuf_map = llvmpipe_texture_map(zsbuf->texture,
-                                              zsbuf->face,
-                                              zsbuf->level,
-                                              zsbuf->zslice);
-      if (!scene->zsbuf_map)
-        goto fail;
+   if (fb->zsbuf) {
+      struct pipe_surface *zsbuf = scene->fb.zsbuf;
+      max_layer = MIN2(max_layer, zsbuf->u.tex.last_layer - zsbuf->u.tex.first_layer);
    }
-
-   return TRUE;
-
-fail:
-   /* Unmap and release transfers?
-    */
-   return FALSE;
-}
-
-
-
-/**
- * Called after rasterizer as finished rasterizing a scene. 
- * 
- * We want to call this from the pipe_context's current thread to
- * avoid having to have mutexes on the transfer functions.
- */
-static void
-lp_scene_unmap_buffers( struct lp_scene *scene )
-{
-   unsigned i;
-
-   for (i = 0; i < scene->fb.nr_cbufs; i++) {
-      if (scene->cbuf_map[i]) {
-         struct pipe_surface *cbuf = scene->fb.cbufs[i];
-         llvmpipe_texture_unmap(cbuf->texture,
-                                cbuf->face,
-                                cbuf->level,
-                                cbuf->zslice);
-         scene->cbuf_map[i] = NULL;
+   scene->fb_max_layer = max_layer;
+   scene->fb_max_samples = util_framebuffer_get_num_samples(fb);
+   if (scene->fb_max_samples == 4) {
+      for (unsigned i = 0; i < 4; i++) {
+         scene->fixed_sample_pos[i][0] = util_iround(lp_sample_pos_4x[i][0] * FIXED_ONE);
+         scene->fixed_sample_pos[i][1] = util_iround(lp_sample_pos_4x[i][1] * FIXED_ONE);
       }
    }
-
-   if (scene->zsbuf_map) {
-      struct pipe_surface *zsbuf = scene->fb.zsbuf;
-      llvmpipe_texture_unmap(zsbuf->texture,
-                             zsbuf->face,
-                             zsbuf->level,
-                             zsbuf->zslice);
-      scene->zsbuf_map = NULL;
-   }
-
-   util_unreference_framebuffer_state( &scene->fb );
 }
 
 
-void lp_scene_begin_binning( struct lp_scene *scene,
-                             struct pipe_framebuffer_state *fb )
+void lp_scene_end_binning( struct lp_scene *scene )
 {
-   assert(lp_scene_is_empty(scene));
-
-   util_copy_framebuffer_state(&scene->fb, fb);
-
-   scene->tiles_x = align(fb->width, TILE_SIZE) / TILE_SIZE;
-   scene->tiles_y = align(fb->height, TILE_SIZE) / TILE_SIZE;
-
-   assert(scene->tiles_x <= TILES_X);
-   assert(scene->tiles_y <= TILES_Y);
-}
-
-
-void lp_scene_rasterize( struct lp_scene *scene,
-                         struct lp_rasterizer *rast,
-                         boolean write_depth )
-{
-   if (0) {
-      unsigned x, y;
+   if (LP_DEBUG & DEBUG_SCENE) {
       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++) {
-            debug_printf("  bin %u, %u size: %u\n", x, y,
-                         lp_scene_bin_size(scene, x, y));
-         }
-      }
-   }
-
-
-   scene->write_depth = (scene->fb.zsbuf != NULL &&
-                         write_depth);
+      debug_printf("  scene_size: %u\n",
+                   scene->scene_size);
+      debug_printf("  data size: %u\n",
+                   lp_scene_data_size(scene));
 
-   lp_scene_map_buffers( scene );
-
-   /* Enqueue the scene for rasterization, then immediately wait for
-    * it to finish.
-    */
-   lp_rast_queue_scene( rast, scene );
-
-   /* Currently just wait for the rasterizer to finish.  Some
-    * threading interactions need to be worked out, particularly once
-    * transfers become per-context:
-    */
-   lp_rast_finish( rast );
-   lp_scene_unmap_buffers( scene );
-   lp_scene_enqueue( scene->empty_queue, scene );
+      if (0)
+         lp_debug_bins( scene );
+   }
 }