summaryrefslogtreecommitdiffstats
path: root/src/gallium
diff options
context:
space:
mode:
Diffstat (limited to 'src/gallium')
-rw-r--r--src/gallium/drivers/v3d/v3d_context.c37
-rw-r--r--src/gallium/drivers/v3d/v3d_context.h4
-rw-r--r--src/gallium/drivers/v3d/v3d_job.c21
-rw-r--r--src/gallium/drivers/v3d/v3d_query.c11
-rw-r--r--src/gallium/drivers/v3d/v3dx_draw.c34
-rw-r--r--src/gallium/drivers/v3d/v3dx_job.c14
-rw-r--r--src/gallium/drivers/v3d/v3dx_state.c17
7 files changed, 122 insertions, 16 deletions
diff --git a/src/gallium/drivers/v3d/v3d_context.c b/src/gallium/drivers/v3d/v3d_context.c
index fcd2d5ec69b..8dc8dd63581 100644
--- a/src/gallium/drivers/v3d/v3d_context.c
+++ b/src/gallium/drivers/v3d/v3d_context.c
@@ -31,6 +31,7 @@
#include "util/u_memory.h"
#include "util/u_blitter.h"
#include "util/u_upload_mgr.h"
+#include "util/u_prim.h"
#include "indices/u_primconvert.h"
#include "pipe/p_screen.h"
@@ -109,6 +110,39 @@ v3d_invalidate_resource(struct pipe_context *pctx, struct pipe_resource *prsc)
job->store &= ~(PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL);
}
+/**
+ * Flushes the current job to get up-to-date primive counts written to the
+ * primitive counts BO, then accumulates the transform feedback primitive count
+ * in the context and the corresponding vertex counts in the bound stream
+ * output targets.
+ */
+void
+v3d_tf_update_counters(struct v3d_context *v3d)
+{
+ struct v3d_job *job = v3d_get_job_for_fbo(v3d);
+ if (job->draw_calls_queued == 0)
+ return;
+
+ /* In order to get up-to-date primitive counts we need to submit
+ * the job for execution so we get the counts written to memory.
+ * Notice that this will require a sync wait for the buffer write.
+ */
+ uint32_t prims_before = v3d->tf_prims_generated;
+ v3d_job_submit(v3d, job);
+ uint32_t prims_after = v3d->tf_prims_generated;
+ if (prims_before == prims_after)
+ return;
+
+ enum pipe_prim_type prim_type = u_base_prim_type(v3d->prim_mode);
+ uint32_t num_verts = u_vertices_for_prims(prim_type,
+ prims_after - prims_before);
+ for (int i = 0; i < v3d->streamout.num_targets; i++) {
+ struct v3d_stream_output_target *so =
+ v3d_stream_output_target(v3d->streamout.targets[i]);
+ so->recorded_vertex_count += num_verts;
+ }
+}
+
static void
v3d_context_destroy(struct pipe_context *pctx)
{
@@ -127,6 +161,9 @@ v3d_context_destroy(struct pipe_context *pctx)
if (v3d->state_uploader)
u_upload_destroy(v3d->state_uploader);
+ if (v3d->prim_counts)
+ pipe_resource_reference(&v3d->prim_counts, NULL);
+
slab_destroy_child(&v3d->transfer_pool);
pipe_surface_reference(&v3d->framebuffer.cbufs[0], NULL);
diff --git a/src/gallium/drivers/v3d/v3d_context.h b/src/gallium/drivers/v3d/v3d_context.h
index 5f19504dbae..b2c917df240 100644
--- a/src/gallium/drivers/v3d/v3d_context.h
+++ b/src/gallium/drivers/v3d/v3d_context.h
@@ -498,6 +498,8 @@ struct v3d_context {
struct v3d_vertexbuf_stateobj vertexbuf;
struct v3d_streamout_stateobj streamout;
struct v3d_bo *current_oq;
+ struct pipe_resource *prim_counts;
+ uint32_t prim_counts_offset;
struct pipe_debug_callback debug;
/** @} */
};
@@ -652,6 +654,8 @@ bool v3d_generate_mipmap(struct pipe_context *pctx,
struct v3d_fence *v3d_fence_create(struct v3d_context *v3d);
+void v3d_tf_update_counters(struct v3d_context *v3d);
+
#ifdef v3dX
# include "v3dx_context.h"
#else
diff --git a/src/gallium/drivers/v3d/v3d_job.c b/src/gallium/drivers/v3d/v3d_job.c
index 3226059161a..17fc41d317a 100644
--- a/src/gallium/drivers/v3d/v3d_job.c
+++ b/src/gallium/drivers/v3d/v3d_job.c
@@ -429,6 +429,19 @@ v3d_clif_dump(struct v3d_context *v3d, struct v3d_job *job)
clif_dump_destroy(clif);
}
+static void
+v3d_read_and_accumulate_primitive_counters(struct v3d_context *v3d)
+{
+ assert(v3d->prim_counts);
+
+ perf_debug("stalling on TF counts readback");
+ struct v3d_resource *rsc = v3d_resource(v3d->prim_counts);
+ if (v3d_bo_wait(rsc->bo, PIPE_TIMEOUT_INFINITE, "prim-counts")) {
+ uint32_t *map = v3d_bo_map(rsc->bo);
+ v3d->tf_prims_generated += map[V3D_PRIM_COUNTS_TF_WRITTEN];
+ }
+}
+
/**
* Submits the job to the kernel and then reinitializes it.
*/
@@ -488,6 +501,14 @@ v3d_job_submit(struct v3d_context *v3d, struct v3d_job *job)
"Expect corruption.\n", strerror(errno));
warned = true;
}
+
+ /* If we are submitting a job in the middle of transform
+ * feedback we need to read the primitive counts and accumulate
+ * them, otherwise they will be reset at the start of the next
+ * draw when we emit the Tile Binning Mode Configuration packet.
+ */
+ if (v3d->streamout.num_targets)
+ v3d_read_and_accumulate_primitive_counters(v3d);
}
done:
diff --git a/src/gallium/drivers/v3d/v3d_query.c b/src/gallium/drivers/v3d/v3d_query.c
index d31b9dd896b..72bb2e43c51 100644
--- a/src/gallium/drivers/v3d/v3d_query.c
+++ b/src/gallium/drivers/v3d/v3d_query.c
@@ -75,6 +75,11 @@ v3d_begin_query(struct pipe_context *pctx, struct pipe_query *query)
q->start = v3d->prims_generated;
break;
case PIPE_QUERY_PRIMITIVES_EMITTED:
+ /* If we are inside transform feedback we need to update the
+ * primitive counts to skip primtives recorded before this.
+ */
+ if (v3d->streamout.num_targets > 0)
+ v3d_tf_update_counters(v3d);
q->start = v3d->tf_prims_generated;
break;
case PIPE_QUERY_OCCLUSION_COUNTER:
@@ -105,6 +110,12 @@ v3d_end_query(struct pipe_context *pctx, struct pipe_query *query)
q->end = v3d->prims_generated;
break;
case PIPE_QUERY_PRIMITIVES_EMITTED:
+ /* If transform feedback has ended, then we have already
+ * updated the primitive counts at glEndTransformFeedback()
+ * time. Otherwise, we have to do it now.
+ */
+ if (v3d->streamout.num_targets > 0)
+ v3d_tf_update_counters(v3d);
q->end = v3d->tf_prims_generated;
break;
case PIPE_QUERY_OCCLUSION_COUNTER:
diff --git a/src/gallium/drivers/v3d/v3dx_draw.c b/src/gallium/drivers/v3d/v3dx_draw.c
index c2b3ecd8a13..fec9d54c25b 100644
--- a/src/gallium/drivers/v3d/v3dx_draw.c
+++ b/src/gallium/drivers/v3d/v3dx_draw.c
@@ -545,29 +545,20 @@ v3d_emit_gl_shader_state(struct v3d_context *v3d,
}
/**
- * Computes the various transform feedback statistics, since they can't be
- * recorded by CL packets.
+ * Updates the number of primitvies generated from the number of vertices
+ * to draw. We do this here instead of using PRIMITIVE_COUNTS_FEEDBACK because
+ * using the GPU packet for this might require sync waits and this is trivial
+ * to handle in the CPU instead.
*/
static void
-v3d_tf_statistics_record(struct v3d_context *v3d,
- const struct pipe_draw_info *info)
+v3d_update_primitives_generated_counter(struct v3d_context *v3d,
+ const struct pipe_draw_info *info)
{
if (!v3d->active_queries)
return;
uint32_t prims = u_prims_for_vertices(info->mode, info->count);
v3d->prims_generated += prims;
-
- if (v3d->streamout.num_targets <= 0)
- return;
-
- /* XXX: Only count if we didn't overflow. */
- v3d->tf_prims_generated += prims;
- for (int i = 0; i < v3d->streamout.num_targets; i++) {
- struct v3d_stream_output_target *target =
- v3d_stream_output_target(v3d->streamout.targets[i]);
- target->recorded_vertex_count += info->count;
- }
}
static void
@@ -665,6 +656,17 @@ v3d_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
v3d_predraw_check_outputs(pctx);
+ /* If transform feedback is active and we are switching primitive type
+ * we need to submit the job before drawing and update the vertex count
+ * written to TF based on the primitive type since we will need to
+ * know the exact vertex count if the application decides to call
+ * glDrawTransformFeedback() later.
+ */
+ if (v3d->streamout.num_targets > 0 &&
+ u_base_prim_type(info->mode) != u_base_prim_type(v3d->prim_mode)) {
+ v3d_tf_update_counters(v3d);
+ }
+
struct v3d_job *job = v3d_get_job_for_fbo(v3d);
/* If vertex texturing depends on the output of rendering, we need to
@@ -762,7 +764,7 @@ v3d_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
prim_tf_enable = (V3D_PRIM_POINTS_TF - V3D_PRIM_POINTS);
#endif
- v3d_tf_statistics_record(v3d, info);
+ v3d_update_primitives_generated_counter(v3d, info);
/* Note that the primitive type fields match with OpenGL/gallium
* definitions, up to but not including QUADS.
diff --git a/src/gallium/drivers/v3d/v3dx_job.c b/src/gallium/drivers/v3d/v3dx_job.c
index 1dbd20b2251..84228a48760 100644
--- a/src/gallium/drivers/v3d/v3dx_job.c
+++ b/src/gallium/drivers/v3d/v3dx_job.c
@@ -38,6 +38,20 @@ void v3dX(bcl_epilogue)(struct v3d_context *v3d, struct v3d_job *job)
#endif
cl_packet_length(FLUSH));
+ if (job->tf_enabled) {
+ /* Write primitive counts to memory. */
+ assert(v3d->prim_counts);
+ struct v3d_resource *rsc =
+ v3d_resource(v3d->prim_counts);
+ cl_emit(&job->bcl, PRIMITIVE_COUNTS_FEEDBACK, counter) {
+ counter.address =
+ cl_address(rsc->bo,
+ v3d->prim_counts_offset);
+ counter.read_write_64byte = false;
+ counter.op = 0;
+ }
+ }
+
/* Disable TF at the end of the CL, so that the TF block
* cleans up and finishes before it gets reset by the next
* frame's tile binning mode cfg packet. (SWVC5-718).
diff --git a/src/gallium/drivers/v3d/v3dx_state.c b/src/gallium/drivers/v3d/v3dx_state.c
index b6a57249044..c709b476f99 100644
--- a/src/gallium/drivers/v3d/v3dx_state.c
+++ b/src/gallium/drivers/v3d/v3dx_state.c
@@ -1222,6 +1222,14 @@ v3d_set_stream_output_targets(struct pipe_context *pctx,
assert(num_targets <= ARRAY_SIZE(so->targets));
+ /* Update recorded vertex counts when we are ending the recording of
+ * transform feedback. We do this when we switch primitive types
+ * at draw time, but if we haven't switched primitives in our last
+ * draw we need to do it here as well.
+ */
+ if (num_targets == 0 && so->num_targets > 0)
+ v3d_tf_update_counters(ctx);
+
for (i = 0; i < num_targets; i++) {
if (offsets[i] != -1)
so->offsets[i] = offsets[i];
@@ -1234,6 +1242,15 @@ v3d_set_stream_output_targets(struct pipe_context *pctx,
so->num_targets = num_targets;
+ /* Create primitive counters BO if needed */
+ if (num_targets > 0 && !ctx->prim_counts) {
+ uint32_t zeroes[7] = { 0 }; /* Init all 7 counters to 0 */
+ u_upload_data(ctx->uploader,
+ 0, sizeof(zeroes), 32, zeroes,
+ &ctx->prim_counts_offset,
+ &ctx->prim_counts);
+ }
+
ctx->dirty |= VC5_DIRTY_STREAMOUT;
}