#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
*/
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;
/**
*/
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;
/** @} */
};
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
*/
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);
*/
/**
- * 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