summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Anholt <[email protected]>2017-11-06 15:41:40 -0800
committerEric Anholt <[email protected]>2017-11-07 12:56:40 -0800
commit4f33344e7a6b988fbbc4a0802dacf5cab487e408 (patch)
tree5c489236b7b2e50098015f4e04879533f3933505
parentd002950e5491f971cbaa77ac80a698e5d746295a (diff)
broadcom/vc5: Add occlusion query support.
Fixes all of piglit's OQ tests.
-rw-r--r--src/broadcom/cle/v3d_packet_v33.xml4
-rw-r--r--src/gallium/drivers/vc5/vc5_context.c1
-rw-r--r--src/gallium/drivers/vc5/vc5_context.h11
-rw-r--r--src/gallium/drivers/vc5/vc5_draw.c3
-rw-r--r--src/gallium/drivers/vc5/vc5_emit.c9
-rw-r--r--src/gallium/drivers/vc5/vc5_job.c20
-rw-r--r--src/gallium/drivers/vc5/vc5_query.c97
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 @@
<field name="Render Target 0 per colour component write masks" size="4" start="0" type="uint"/>
</packet>
+ <packet code="92" name="Occlusion Query Counter">
+ <field name="address" size="32" start="0" type="address"/>
+ </packet>
+
<packet code="96" name="Configuration Bits">
<field name="Direct3D Provoking Vertex" size="1" start="21" type="bool"/>
<field name="Direct3D 'Point-fill' mode" size="1" start="20" type="bool"/>
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