llvmpipe: rework fences and queries
authorKeith Whitwell <keithw@vmware.com>
Fri, 27 Aug 2010 16:14:49 +0000 (17:14 +0100)
committerKeith Whitwell <keithw@vmware.com>
Tue, 7 Sep 2010 12:22:55 +0000 (13:22 +0100)
src/gallium/drivers/llvmpipe/lp_query.c
src/gallium/drivers/llvmpipe/lp_query.h
src/gallium/drivers/llvmpipe/lp_rast.c
src/gallium/drivers/llvmpipe/lp_rast.h
src/gallium/drivers/llvmpipe/lp_rast_priv.h
src/gallium/drivers/llvmpipe/lp_setup.c
src/gallium/drivers/llvmpipe/lp_setup_context.h

index 67fd797af228526827b2a001176008caf978587f..76d0231fd1cabd9da5b63d2ebd5ea36a1bfcb5df 100644 (file)
@@ -54,9 +54,6 @@ llvmpipe_create_query(struct pipe_context *pipe,
    assert(type == PIPE_QUERY_OCCLUSION_COUNTER);
 
    pq = CALLOC_STRUCT( llvmpipe_query );
-   if (pq) {
-      pipe_mutex_init(pq->mutex);
-   }
 
    return (struct pipe_query *) pq;
 }
@@ -66,12 +63,20 @@ static void
 llvmpipe_destroy_query(struct pipe_context *pipe, struct pipe_query *q)
 {
    struct llvmpipe_query *pq = llvmpipe_query(q);
-   /* query might still be in process if we never waited for the result */
-   if (!pq->done) {
-      llvmpipe_finish(pipe, __FUNCTION__);
+
+   /* Ideally we would refcount queries & not get destroyed until the
+    * last scene had finished with us.
+    */
+   if (pq->fence) {
+      if (!lp_fence_issued(pq->fence))
+         llvmpipe_flush(pipe, 0, NULL, __FUNCTION__);
+
+      if (!lp_fence_signalled(pq->fence))
+         lp_fence_wait(pq->fence);
+
+      lp_fence_reference(&pq->fence, NULL);
    }
 
-   pipe_mutex_destroy(pq->mutex);
    FREE(pq);
 }
 
@@ -84,22 +89,31 @@ llvmpipe_get_query_result(struct pipe_context *pipe,
 {
    struct llvmpipe_query *pq = llvmpipe_query(q);
    uint64_t *result = (uint64_t *)vresult;
+   int i;
 
-   if (!pq->done) {
-      if (wait) {
-         llvmpipe_finish(pipe, __FUNCTION__);
-      }
-      /* this is a bit inconsequent but should be ok */
-      else {
+   if (!pq->fence) {
+      assert(0);                /* query not in issued state */
+      return FALSE;
+   }
+
+   if (!lp_fence_signalled(pq->fence)) {
+      if (!lp_fence_issued(pq->fence))
          llvmpipe_flush(pipe, 0, NULL, __FUNCTION__);
-      }
+         
+      if (!wait)
+         return FALSE;
+
+      lp_fence_wait(pq->fence);
    }
 
-   if (pq->done) {
-      *result = pq->result;
+   /* Sum the results from each of the threads:
+    */
+   *result = 0;
+   for (i = 0; i < LP_MAX_THREADS; i++) {
+      *result += pq->count[i];
    }
 
-   return pq->done;
+   return TRUE;
 }
 
 
@@ -109,14 +123,6 @@ llvmpipe_begin_query(struct pipe_context *pipe, struct pipe_query *q)
    struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
    struct llvmpipe_query *pq = llvmpipe_query(q);
 
-   /* Check if the query is already in the scene.  If so, we need to
-    * flush the scene now.  Real apps shouldn't re-use a query in a
-    * frame of rendering.
-    */
-   if (pq->binned) {
-      llvmpipe_finish(pipe, __FUNCTION__);
-   }
-
    lp_setup_begin_query(llvmpipe->setup, pq);
 
    llvmpipe->active_query_count++;
index 721c41cb5c956531497705b0a7af2ab45b84c723..e93842a2fd060bef3f6ce6be163930a4641fb3d9 100644 (file)
@@ -43,13 +43,7 @@ struct llvmpipe_context;
 
 struct llvmpipe_query {
    uint64_t count[LP_MAX_THREADS];  /**< a counter for each thread */
-   uint64_t result;                 /**< total of all counters */
-
-   pipe_mutex mutex;
-   unsigned num_tiles, tile_count;
-
-   boolean done;
-   boolean binned;  /**< has this query been binned in the scene? */
+   struct lp_fence *fence;      /* fence from last scene this was binned in */
 };
 
 
index b1c306bbe948d6a6c3e64b32b7be7f8f64f0e091..ce6896d16e4dd4ff288ca8f62a58b227ae4f60b0 100644 (file)
@@ -568,6 +568,11 @@ lp_rast_tile_end(struct lp_rasterizer_task *task)
       lp_rast_store_linear_color(task, dummy);
    }
 
+   if (task->query) {
+      union lp_rast_cmd_arg dummy = {0};
+      lp_rast_end_query(task, dummy);
+   }
+
    /* debug */
    memset(task->color_tiles, 0, sizeof(task->color_tiles));
    task->depth_tile = NULL;
@@ -597,8 +602,26 @@ void
 lp_rast_begin_query(struct lp_rasterizer_task *task,
                     const union lp_rast_cmd_arg arg)
 {
-   /* Reset the per-task counter */
+   struct llvmpipe_query *pq = arg.query_obj;
+
+   assert(task->query == NULL);
    task->vis_counter = 0;
+   task->query = pq;
+   pq->count[task->thread_index] = 0;
+}
+
+
+/* Much like begin_query, but don't reset the counter to zero.
+ */
+void
+lp_rast_restart_query(struct lp_rasterizer_task *task,
+                      const union lp_rast_cmd_arg arg)
+{
+   struct llvmpipe_query *pq = arg.query_obj;
+
+   assert(task->query == NULL);
+   task->vis_counter = 0;
+   task->query = pq;
 }
  
 
@@ -611,35 +634,8 @@ void
 lp_rast_end_query(struct lp_rasterizer_task *task,
                   const union lp_rast_cmd_arg arg)
 {
-   struct llvmpipe_query *pq = arg.query_obj;
-
-   pipe_mutex_lock(pq->mutex);
-   {
-      /* Accumulate the visible fragment counter from this tile in
-       * the query object.
-       */
-      pq->count[task->thread_index] += task->vis_counter;
-
-      /* check if this is the last tile in the scene */
-      pq->tile_count++;
-      if (pq->tile_count == pq->num_tiles) {
-         uint i;
-
-         /* sum the per-thread counters for the query */
-         pq->result = 0;
-         for (i = 0; i < LP_MAX_THREADS; i++) {
-            pq->result += pq->count[i];
-         }
-
-         /* reset counters (in case this query is re-used in the scene) */
-         memset(pq->count, 0, sizeof(pq->count));
-
-         pq->tile_count = 0;
-         pq->binned = FALSE;
-         pq->done = TRUE;
-      }
-   }
-   pipe_mutex_unlock(pq->mutex);
+   task->query->count[task->thread_index] += task->vis_counter;
+   task->query = NULL;
 }
 
 
@@ -697,6 +693,7 @@ static struct {
    RAST(store_linear_color),
    RAST(fence),
    RAST(begin_query),
+   RAST(restart_query),
    RAST(end_query),
 };
 
index ebe88182af43abf49486d793acdbb71494dd08a9..9d3deb4e8862d325e4cf7be2b2757b72c8f3ff13 100644 (file)
@@ -210,6 +210,14 @@ lp_rast_arg_null( void )
    return arg;
 }
 
+static INLINE union lp_rast_cmd_arg
+lp_rast_arg_query( struct llvmpipe_query *pq )
+{
+   union lp_rast_cmd_arg arg;
+   arg.query_obj = pq;
+   return arg;
+}
+
 
 /**
  * Binnable Commands.
@@ -256,6 +264,9 @@ void lp_rast_store_linear_color( struct lp_rasterizer_task *,
 void lp_rast_begin_query(struct lp_rasterizer_task *,
                          const union lp_rast_cmd_arg );
 
+void lp_rast_restart_query(struct lp_rasterizer_task *,
+                         const union lp_rast_cmd_arg );
+
 void lp_rast_end_query(struct lp_rasterizer_task *,
                        const union lp_rast_cmd_arg );
 
index fae7f6d3dc2baddc23fa62505884f30a09cf37b0..6bc10159120abd414ccbb6bb97ba6c6785bee3ab 100644 (file)
@@ -89,6 +89,7 @@ struct lp_rasterizer_task
 
    /* occlude counter for visiable pixels */
    uint32_t vis_counter;
+   struct llvmpipe_query *query;
 
    pipe_semaphore work_ready;
    pipe_semaphore work_done;
index 3da9097154ef630a918087e6ac8cc882cf398c57..ae6d67850253fa94ddab24ef555adb89c501d100 100644 (file)
@@ -154,6 +154,11 @@ lp_setup_rasterize_scene( struct lp_setup_context *setup )
    struct lp_scene *scene = lp_setup_get_current_scene(setup);
    struct llvmpipe_screen *screen = llvmpipe_screen(scene->pipe->screen);
 
+   lp_fence_reference(&setup->last_fence, scene->fence);
+
+   if (setup->last_fence)
+      setup->last_fence->issued = TRUE;
+
    pipe_mutex_lock(screen->rast_mutex);
    lp_scene_rasterize(scene, screen->rast);
    pipe_mutex_unlock(screen->rast_mutex);
@@ -170,6 +175,12 @@ begin_binning( struct lp_setup_context *setup )
 {
    struct lp_scene *scene = lp_setup_get_current_scene(setup);
    boolean need_zsload = FALSE;
+
+   /* Always create a fence when threads are active:
+    */
+   if (setup->num_threads)
+      scene->fence = lp_fence_create(setup->num_threads);
+
    if (setup->fb.zsbuf &&
        ((setup->clear.flags & PIPE_CLEAR_DEPTHSTENCIL) != PIPE_CLEAR_DEPTHSTENCIL) &&
         util_format_is_depth_and_stencil(setup->fb.zsbuf->format))
@@ -198,6 +209,13 @@ begin_binning( struct lp_setup_context *setup )
       }
    }
 
+   if (setup->active_query) {
+      lp_scene_bin_everywhere( scene,
+                               lp_rast_restart_query,
+                               lp_rast_arg_query(setup->active_query) );
+   }
+      
+
    LP_DBG(DEBUG_SETUP, "%s done\n", __FUNCTION__);
 }
 
@@ -280,19 +298,11 @@ lp_setup_flush( struct lp_setup_context *setup,
 {
    LP_DBG(DEBUG_SETUP, "%s %s\n", __FUNCTION__, reason);
 
-   if (setup->scene) {
-      if (fence) {
-         /* if we're going to flush the setup/rasterization modules, emit
-          * a fence.
-          */
-         *fence = lp_setup_fence( setup );
-      }
+   set_scene_state( setup, SETUP_FLUSHED );
 
-      if (setup->scene->fence)
-         setup->scene->fence->issued = TRUE;
+   if (fence) {
+      lp_fence_reference((struct lp_fence **)fence, setup->last_fence);
    }
-
-   set_scene_state( setup, SETUP_FLUSHED );
 }
 
 
@@ -955,22 +965,16 @@ void
 lp_setup_begin_query(struct lp_setup_context *setup,
                      struct llvmpipe_query *pq)
 {
-   struct lp_scene * scene = lp_setup_get_current_scene(setup);
-   union lp_rast_cmd_arg cmd_arg;
-
    /* init the query to its beginning state */
-   pq->done = FALSE;
-   pq->tile_count = 0;
-   pq->num_tiles = scene->tiles_x * scene->tiles_y;
-   assert(pq->num_tiles > 0);
-
-   memset(pq->count, 0, sizeof(pq->count));  /* reset all counters */
-
-   set_scene_state( setup, SETUP_ACTIVE );
+   assert(setup->active_query == NULL);
+   
+   if (setup->scene) {
+      lp_scene_bin_everywhere(setup->scene,
+                              lp_rast_begin_query,
+                              lp_rast_arg_query(pq));
+   }
 
-   cmd_arg.query_obj = pq;
-   lp_scene_bin_everywhere(scene, lp_rast_begin_query, cmd_arg);
-   pq->binned = TRUE;
+   setup->active_query = pq;
 }
 
 
@@ -980,11 +984,27 @@ lp_setup_begin_query(struct lp_setup_context *setup,
 void
 lp_setup_end_query(struct lp_setup_context *setup, struct llvmpipe_query *pq)
 {
-   struct lp_scene * scene = lp_setup_get_current_scene(setup);
-   union lp_rast_cmd_arg cmd_arg;
+   union lp_rast_cmd_arg dummy = { 0 };
 
-   set_scene_state( setup, SETUP_ACTIVE );
+   assert(setup->active_query == pq);
+   setup->active_query = NULL;
 
-   cmd_arg.query_obj = pq;
-   lp_scene_bin_everywhere(scene, lp_rast_end_query, cmd_arg);
+   /* Setup will automatically re-issue any query which carried over a
+    * scene boundary, and the rasterizer automatically "ends" queries
+    * which are active at the end of a scene, so there is no need to
+    * retry this commands on failure.
+    */
+   if (setup->scene) {
+      /* pq->fence should be the fence of the *last* scene which
+       * contributed to the query result.
+       */
+      lp_fence_reference(&pq->fence, setup->scene->fence);
+
+      lp_scene_bin_everywhere(setup->scene, lp_rast_end_query, dummy);
+   }
+   else {
+      lp_fence_reference(&pq->fence, setup->last_fence);
+   }
 }
+
+
index 877a492c6d8e30190541816a37fb6f4718dc687a..91b5d4d79f09c14c30761792f83b98be1285e63e 100644 (file)
@@ -87,6 +87,9 @@ struct lp_setup_context
    struct lp_scene *scene;               /**< current scene being built */
    struct lp_scene_queue *empty_scenes;  /**< queue of empty scenes */
 
+   struct lp_fence *last_fence;
+   struct llvmpipe_query *active_query;
+
    boolean flatshade_first;
    boolean ccw_is_frontface;
    boolean scissor_test;