From: Keith Whitwell Date: Fri, 27 Aug 2010 16:14:49 +0000 (+0100) Subject: llvmpipe: rework fences and queries X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=18452c1e87f79327fbd5f27478028b481ee72a5d;p=mesa.git llvmpipe: rework fences and queries --- diff --git a/src/gallium/drivers/llvmpipe/lp_query.c b/src/gallium/drivers/llvmpipe/lp_query.c index 67fd797af22..76d0231fd1c 100644 --- a/src/gallium/drivers/llvmpipe/lp_query.c +++ b/src/gallium/drivers/llvmpipe/lp_query.c @@ -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++; diff --git a/src/gallium/drivers/llvmpipe/lp_query.h b/src/gallium/drivers/llvmpipe/lp_query.h index 721c41cb5c9..e93842a2fd0 100644 --- a/src/gallium/drivers/llvmpipe/lp_query.h +++ b/src/gallium/drivers/llvmpipe/lp_query.h @@ -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 */ }; diff --git a/src/gallium/drivers/llvmpipe/lp_rast.c b/src/gallium/drivers/llvmpipe/lp_rast.c index b1c306bbe94..ce6896d16e4 100644 --- a/src/gallium/drivers/llvmpipe/lp_rast.c +++ b/src/gallium/drivers/llvmpipe/lp_rast.c @@ -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), }; diff --git a/src/gallium/drivers/llvmpipe/lp_rast.h b/src/gallium/drivers/llvmpipe/lp_rast.h index ebe88182af4..9d3deb4e886 100644 --- a/src/gallium/drivers/llvmpipe/lp_rast.h +++ b/src/gallium/drivers/llvmpipe/lp_rast.h @@ -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 ); diff --git a/src/gallium/drivers/llvmpipe/lp_rast_priv.h b/src/gallium/drivers/llvmpipe/lp_rast_priv.h index fae7f6d3dc2..6bc10159120 100644 --- a/src/gallium/drivers/llvmpipe/lp_rast_priv.h +++ b/src/gallium/drivers/llvmpipe/lp_rast_priv.h @@ -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; diff --git a/src/gallium/drivers/llvmpipe/lp_setup.c b/src/gallium/drivers/llvmpipe/lp_setup.c index 3da9097154e..ae6d6785025 100644 --- a/src/gallium/drivers/llvmpipe/lp_setup.c +++ b/src/gallium/drivers/llvmpipe/lp_setup.c @@ -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); + } } + + diff --git a/src/gallium/drivers/llvmpipe/lp_setup_context.h b/src/gallium/drivers/llvmpipe/lp_setup_context.h index 877a492c6d8..91b5d4d79f0 100644 --- a/src/gallium/drivers/llvmpipe/lp_setup_context.h +++ b/src/gallium/drivers/llvmpipe/lp_setup_context.h @@ -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;