From 4f33344e7a6b988fbbc4a0802dacf5cab487e408 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 6 Nov 2017 15:41:40 -0800 Subject: [PATCH] broadcom/vc5: Add occlusion query support. Fixes all of piglit's OQ tests. --- src/broadcom/cle/v3d_packet_v33.xml | 4 ++ src/gallium/drivers/vc5/vc5_context.c | 1 + src/gallium/drivers/vc5/vc5_context.h | 11 +++ src/gallium/drivers/vc5/vc5_draw.c | 3 + src/gallium/drivers/vc5/vc5_emit.c | 9 +++ src/gallium/drivers/vc5/vc5_job.c | 20 ++++-- src/gallium/drivers/vc5/vc5_query.c | 97 ++++++++++++++++++++++----- 7 files changed, 125 insertions(+), 20 deletions(-) diff --git a/src/broadcom/cle/v3d_packet_v33.xml b/src/broadcom/cle/v3d_packet_v33.xml index 2b0665537e8..165e489d4cd 100644 --- a/src/broadcom/cle/v3d_packet_v33.xml +++ b/src/broadcom/cle/v3d_packet_v33.xml @@ -329,6 +329,10 @@ + + + + diff --git a/src/gallium/drivers/vc5/vc5_context.c b/src/gallium/drivers/vc5/vc5_context.c index f80020ab31e..d27f41bb5f8 100644 --- a/src/gallium/drivers/vc5/vc5_context.c +++ b/src/gallium/drivers/vc5/vc5_context.c @@ -162,6 +162,7 @@ vc5_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags) V3D_DEBUG |= saved_shaderdb_flag; vc5->sample_mask = (1 << VC5_MAX_SAMPLES) - 1; + vc5->active_queries = true; return &vc5->base; diff --git a/src/gallium/drivers/vc5/vc5_context.h b/src/gallium/drivers/vc5/vc5_context.h index 298dfacf872..2fec7a77da4 100644 --- a/src/gallium/drivers/vc5/vc5_context.h +++ b/src/gallium/drivers/vc5/vc5_context.h @@ -77,6 +77,7 @@ void vc5_job_add_bo(struct vc5_job *job, struct vc5_bo *bo); #define VC5_DIRTY_COMPILED_FS (1 << 25) #define VC5_DIRTY_FS_INPUTS (1 << 26) #define VC5_DIRTY_STREAMOUT (1 << 27) +#define VC5_DIRTY_OQ (1 << 28) #define VC5_MAX_FS_INPUTS 64 @@ -262,6 +263,13 @@ struct vc5_job { */ bool needs_flush; + /** + * Set if there is a nonzero address for OCCLUSION_QUERY_COUNTER. If + * so, we need to disable it and flush before ending the CL, to keep + * the next tile from starting with it enabled. + */ + bool oq_enabled; + bool uses_early_z; /** @@ -353,12 +361,15 @@ struct vc5_context { */ uint8_t blend_dst_alpha_one; + bool active_queries; + struct pipe_poly_stipple stipple; struct pipe_clip_state clip; struct pipe_viewport_state viewport; struct vc5_constbuf_stateobj constbuf[PIPE_SHADER_TYPES]; struct vc5_vertexbuf_stateobj vertexbuf; struct vc5_streamout_stateobj streamout; + struct vc5_bo *current_oq; /** @} */ }; diff --git a/src/gallium/drivers/vc5/vc5_draw.c b/src/gallium/drivers/vc5/vc5_draw.c index edc52859154..8020e26802a 100644 --- a/src/gallium/drivers/vc5/vc5_draw.c +++ b/src/gallium/drivers/vc5/vc5_draw.c @@ -93,6 +93,9 @@ vc5_start_draw(struct vc5_context *vc5) /* There's definitely nothing in the VCD cache we want. */ cl_emit(&job->bcl, FLUSH_VCD_CACHE, bin); + /* Disable any leftover OQ state from another job. */ + cl_emit(&job->bcl, OCCLUSION_QUERY_COUNTER, counter); + /* "Binning mode lists must have a Start Tile Binning item (6) after * any prefix state data before the binning list proper starts." */ diff --git a/src/gallium/drivers/vc5/vc5_emit.c b/src/gallium/drivers/vc5/vc5_emit.c index de4737eeec8..a4a1af7ddf4 100644 --- a/src/gallium/drivers/vc5/vc5_emit.c +++ b/src/gallium/drivers/vc5/vc5_emit.c @@ -492,4 +492,13 @@ vc5_emit_state(struct pipe_context *pctx) /* XXX? */ } } + + if (vc5->dirty & VC5_DIRTY_OQ) { + cl_emit(&job->bcl, OCCLUSION_QUERY_COUNTER, counter) { + job->oq_enabled = vc5->active_queries && vc5->current_oq; + if (job->oq_enabled) { + counter.address = cl_address(vc5->current_oq, 0); + } + } + } } diff --git a/src/gallium/drivers/vc5/vc5_job.c b/src/gallium/drivers/vc5/vc5_job.c index ed1a64be891..46c85e7edf4 100644 --- a/src/gallium/drivers/vc5/vc5_job.c +++ b/src/gallium/drivers/vc5/vc5_job.c @@ -381,7 +381,17 @@ vc5_job_submit(struct vc5_context *vc5, struct vc5_job *job) vc5_emit_rcl(job); if (cl_offset(&job->bcl) > 0) { - vc5_cl_ensure_space_with_branch(&job->bcl, 2); + vc5_cl_ensure_space_with_branch(&job->bcl, + 7 + + cl_packet_length(OCCLUSION_QUERY_COUNTER)); + + if (job->oq_enabled) { + /* Disable the OQ at the end of the CL, so that the + * draw calls at the start of the CL don't inherit the + * OQ counter. + */ + cl_emit(&job->bcl, OCCLUSION_QUERY_COUNTER, counter); + } /* Increment the semaphore indicating that binning is done and * unblocking the render thread. Note that this doesn't act @@ -389,10 +399,12 @@ vc5_job_submit(struct vc5_context *vc5, struct vc5_job *job) */ cl_emit(&job->bcl, INCREMENT_SEMAPHORE, incr); - /* The FLUSH caps all of our bin lists with a - * VC5_PACKET_RETURN. + /* The FLUSH_ALL emits any unwritten state changes in each + * tile. We can use this to reset any state that needs to be + * present at the start of the next tile, as we do with + * OCCLUSION_QUERY_COUNTER above. */ - cl_emit(&job->bcl, FLUSH, flush); + cl_emit(&job->bcl, FLUSH_ALL_STATE, flush); } job->submit.bcl_end = job->bcl.bo->offset + cl_offset(&job->bcl); diff --git a/src/gallium/drivers/vc5/vc5_query.c b/src/gallium/drivers/vc5/vc5_query.c index c114e76eef0..a412b384081 100644 --- a/src/gallium/drivers/vc5/vc5_query.c +++ b/src/gallium/drivers/vc5/vc5_query.c @@ -22,60 +22,125 @@ */ /** - * Stub support for occlusion queries. + * Gallium query object support. * - * Since we expose support for GL 2.0, we have to expose occlusion queries, - * but the spec allows you to expose 0 query counter bits, so we just return 0 - * as the result of all our queries. + * So far we just support occlusion queries. The HW has native support for + * them, with the query result being loaded and stored by the TLB unit. + * + * From a SW perspective, we have to be careful to make sure that the jobs + * that need to be tracking queries are bracketed by the start and end of + * counting, even across FBO transitions. */ + #include "vc5_context.h" +#include "broadcom/cle/v3d_packet_v33_pack.h" struct vc5_query { - uint8_t pad; + enum pipe_query_type type; + struct vc5_bo *bo; }; static struct pipe_query * -vc5_create_query(struct pipe_context *ctx, unsigned query_type, unsigned index) +vc5_create_query(struct pipe_context *pctx, unsigned query_type, unsigned index) { - struct vc5_query *query = calloc(1, sizeof(*query)); + struct vc5_query *q = calloc(1, sizeof(*q)); + + assert(query_type == PIPE_QUERY_OCCLUSION_COUNTER || + query_type == PIPE_QUERY_OCCLUSION_PREDICATE || + query_type == PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE); + + q->type = query_type; /* Note that struct pipe_query isn't actually defined anywhere. */ - return (struct pipe_query *)query; + return (struct pipe_query *)q; } static void -vc5_destroy_query(struct pipe_context *ctx, struct pipe_query *query) +vc5_destroy_query(struct pipe_context *pctx, struct pipe_query *query) { - free(query); + struct vc5_query *q = (struct vc5_query *)query; + + vc5_bo_unreference(&q->bo); + free(q); } static boolean -vc5_begin_query(struct pipe_context *ctx, struct pipe_query *query) +vc5_begin_query(struct pipe_context *pctx, struct pipe_query *query) { + struct vc5_context *vc5 = vc5_context(pctx); + struct vc5_query *q = (struct vc5_query *)query; + + q->bo = vc5_bo_alloc(vc5->screen, 4096, "query"); + + uint32_t *map = vc5_bo_map(q->bo); + *map = 0; + + vc5->current_oq = q->bo; + vc5->dirty |= VC5_DIRTY_OQ; + return true; } static bool -vc5_end_query(struct pipe_context *ctx, struct pipe_query *query) +vc5_end_query(struct pipe_context *pctx, struct pipe_query *query) { + struct vc5_context *vc5 = vc5_context(pctx); + + vc5->current_oq = NULL; + vc5->dirty |= VC5_DIRTY_OQ; + return true; } static boolean -vc5_get_query_result(struct pipe_context *ctx, struct pipe_query *query, +vc5_get_query_result(struct pipe_context *pctx, struct pipe_query *query, boolean wait, union pipe_query_result *vresult) { - uint64_t *result = &vresult->u64; + struct vc5_query *q = (struct vc5_query *)query; + uint32_t result = 0; + + if (q->bo) { + /* XXX: Only flush the jobs using this BO. */ + vc5_flush(pctx); - *result = 0; + if (wait) { + if (!vc5_bo_wait(q->bo, 0, "query")) + return false; + } else { + if (!vc5_bo_wait(q->bo, ~0ull, "query")) + return false; + } + + /* XXX: Sum up per-core values. */ + uint32_t *map = vc5_bo_map(q->bo); + result = *map; + + vc5_bo_unreference(&q->bo); + } + + switch (q->type) { + case PIPE_QUERY_OCCLUSION_COUNTER: + vresult->u64 = result; + break; + case PIPE_QUERY_OCCLUSION_PREDICATE: + case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE: + vresult->b = result != 0; + break; + default: + unreachable("unsupported query type"); + } return true; } static void -vc5_set_active_query_state(struct pipe_context *pipe, boolean enable) +vc5_set_active_query_state(struct pipe_context *pctx, boolean enable) { + struct vc5_context *vc5 = vc5_context(pctx); + + vc5->active_queries = enable; + vc5->dirty |= VC5_DIRTY_OQ; } void -- 2.30.2