From 5b7a73021cfa72a0e1bdccf5573b64b8b2e1eb97 Mon Sep 17 00:00:00 2001 From: "Kristian H. Kristensen" Date: Fri, 15 May 2020 13:07:38 -0700 Subject: [PATCH] freedreno/a6xx: Create shader dependent streamout state at compile time Part-of: --- src/gallium/drivers/freedreno/a6xx/fd6_emit.c | 42 +++++++--------- src/gallium/drivers/freedreno/a6xx/fd6_emit.h | 1 + .../drivers/freedreno/a6xx/fd6_program.c | 49 ++++++++++++++----- .../drivers/freedreno/a6xx/fd6_program.h | 11 +---- .../drivers/freedreno/freedreno_context.h | 1 + 5 files changed, 58 insertions(+), 46 deletions(-) diff --git a/src/gallium/drivers/freedreno/a6xx/fd6_emit.c b/src/gallium/drivers/freedreno/a6xx/fd6_emit.c index 2f96eebc5d6..42adf5df9a9 100644 --- a/src/gallium/drivers/freedreno/a6xx/fd6_emit.c +++ b/src/gallium/drivers/freedreno/a6xx/fd6_emit.c @@ -695,32 +695,26 @@ fd6_emit_streamout(struct fd_ringbuffer *ring, struct fd6_emit *emit, struct ir3 } if (emit->streamout_mask) { - const struct fd6_streamout_state *tf = &prog->tf; - - OUT_PKT7(ring, CP_CONTEXT_REG_BUNCH, 12 + (2 * tf->prog_count)); - OUT_RING(ring, REG_A6XX_VPC_SO_BUF_CNTL); - OUT_RING(ring, tf->vpc_so_buf_cntl); - OUT_RING(ring, REG_A6XX_VPC_SO_NCOMP(0)); - OUT_RING(ring, tf->ncomp[0]); - OUT_RING(ring, REG_A6XX_VPC_SO_NCOMP(1)); - OUT_RING(ring, tf->ncomp[1]); - OUT_RING(ring, REG_A6XX_VPC_SO_NCOMP(2)); - OUT_RING(ring, tf->ncomp[2]); - OUT_RING(ring, REG_A6XX_VPC_SO_NCOMP(3)); - OUT_RING(ring, tf->ncomp[3]); - OUT_RING(ring, REG_A6XX_VPC_SO_CNTL); - OUT_RING(ring, A6XX_VPC_SO_CNTL_ENABLE); - for (unsigned i = 0; i < tf->prog_count; i++) { - OUT_RING(ring, REG_A6XX_VPC_SO_PROG); - OUT_RING(ring, tf->prog[i]); - } + fd6_emit_add_group(emit, prog->streamout_stateobj, FD6_GROUP_SO, ENABLE_ALL); } else { - OUT_PKT7(ring, CP_CONTEXT_REG_BUNCH, 4); - OUT_RING(ring, REG_A6XX_VPC_SO_CNTL); - OUT_RING(ring, 0); - OUT_RING(ring, REG_A6XX_VPC_SO_BUF_CNTL); - OUT_RING(ring, 0); + /* If we transition from a draw with streamout to one without, turn + * off streamout. + */ + if (ctx->last.streamout_mask != 0) { + struct fd_ringbuffer *obj = fd_submit_new_ringbuffer(emit->ctx->batch->submit, + 5 * 4, FD_RINGBUFFER_STREAMING); + + OUT_PKT7(obj, CP_CONTEXT_REG_BUNCH, 4); + OUT_RING(obj, REG_A6XX_VPC_SO_CNTL); + OUT_RING(obj, 0); + OUT_RING(obj, REG_A6XX_VPC_SO_BUF_CNTL); + OUT_RING(obj, 0); + + fd6_emit_take_group(emit, obj, FD6_GROUP_SO, ENABLE_ALL); + } } + + ctx->last.streamout_mask = emit->streamout_mask; } void diff --git a/src/gallium/drivers/freedreno/a6xx/fd6_emit.h b/src/gallium/drivers/freedreno/a6xx/fd6_emit.h index bf62e34e232..9f4d1b4ce42 100644 --- a/src/gallium/drivers/freedreno/a6xx/fd6_emit.h +++ b/src/gallium/drivers/freedreno/a6xx/fd6_emit.h @@ -65,6 +65,7 @@ enum fd6_state_id { FD6_GROUP_BLEND, FD6_GROUP_SCISSOR, FD6_GROUP_BLEND_COLOR, + FD6_GROUP_SO, }; #define ENABLE_ALL (CP_SET_DRAW_STATE__0_BINNING | CP_SET_DRAW_STATE__0_GMEM | CP_SET_DRAW_STATE__0_SYSMEM) diff --git a/src/gallium/drivers/freedreno/a6xx/fd6_program.c b/src/gallium/drivers/freedreno/a6xx/fd6_program.c index 58613d105c4..24c8ab080e2 100644 --- a/src/gallium/drivers/freedreno/a6xx/fd6_program.c +++ b/src/gallium/drivers/freedreno/a6xx/fd6_program.c @@ -145,20 +145,24 @@ setup_stream_out(struct fd6_program_state *state, const struct ir3_shader_varian struct ir3_shader_linkage *l) { const struct ir3_stream_output_info *strmout = &v->shader->stream_output; - struct fd6_streamout_state *tf = &state->tf; - memset(tf, 0, sizeof(*tf)); + uint32_t ncomp[PIPE_MAX_SO_BUFFERS]; + uint32_t prog[256/2]; + uint32_t prog_count; - tf->prog_count = align(l->max_loc, 2) / 2; + memset(ncomp, 0, sizeof(ncomp)); + memset(prog, 0, sizeof(prog)); - debug_assert(tf->prog_count < ARRAY_SIZE(tf->prog)); + prog_count = align(l->max_loc, 2) / 2; + + debug_assert(prog_count < ARRAY_SIZE(prog)); for (unsigned i = 0; i < strmout->num_outputs; i++) { const struct ir3_stream_output *out = &strmout->output[i]; unsigned k = out->register_index; unsigned idx; - tf->ncomp[out->output_buffer] += out->num_components; + ncomp[out->output_buffer] += out->num_components; /* linkage map sorted by order frag shader wants things, so * a bit less ideal here.. @@ -175,22 +179,40 @@ setup_stream_out(struct fd6_program_state *state, const struct ir3_shader_varian unsigned off = j + out->dst_offset; /* in dwords */ if (loc & 1) { - tf->prog[loc/2] |= A6XX_VPC_SO_PROG_B_EN | + prog[loc/2] |= A6XX_VPC_SO_PROG_B_EN | A6XX_VPC_SO_PROG_B_BUF(out->output_buffer) | A6XX_VPC_SO_PROG_B_OFF(off * 4); } else { - tf->prog[loc/2] |= A6XX_VPC_SO_PROG_A_EN | + prog[loc/2] |= A6XX_VPC_SO_PROG_A_EN | A6XX_VPC_SO_PROG_A_BUF(out->output_buffer) | A6XX_VPC_SO_PROG_A_OFF(off * 4); } } } - tf->vpc_so_buf_cntl = A6XX_VPC_SO_BUF_CNTL_ENABLE | - COND(tf->ncomp[0] > 0, A6XX_VPC_SO_BUF_CNTL_BUF0) | - COND(tf->ncomp[1] > 0, A6XX_VPC_SO_BUF_CNTL_BUF1) | - COND(tf->ncomp[2] > 0, A6XX_VPC_SO_BUF_CNTL_BUF2) | - COND(tf->ncomp[3] > 0, A6XX_VPC_SO_BUF_CNTL_BUF3); + struct fd_ringbuffer *ring = state->streamout_stateobj; + + OUT_PKT7(ring, CP_CONTEXT_REG_BUNCH, 12 + (2 * prog_count)); + OUT_RING(ring, REG_A6XX_VPC_SO_BUF_CNTL); + OUT_RING(ring, A6XX_VPC_SO_BUF_CNTL_ENABLE | + COND(ncomp[0] > 0, A6XX_VPC_SO_BUF_CNTL_BUF0) | + COND(ncomp[1] > 0, A6XX_VPC_SO_BUF_CNTL_BUF1) | + COND(ncomp[2] > 0, A6XX_VPC_SO_BUF_CNTL_BUF2) | + COND(ncomp[3] > 0, A6XX_VPC_SO_BUF_CNTL_BUF3)); + OUT_RING(ring, REG_A6XX_VPC_SO_NCOMP(0)); + OUT_RING(ring, ncomp[0]); + OUT_RING(ring, REG_A6XX_VPC_SO_NCOMP(1)); + OUT_RING(ring, ncomp[1]); + OUT_RING(ring, REG_A6XX_VPC_SO_NCOMP(2)); + OUT_RING(ring, ncomp[2]); + OUT_RING(ring, REG_A6XX_VPC_SO_NCOMP(3)); + OUT_RING(ring, ncomp[3]); + OUT_RING(ring, REG_A6XX_VPC_SO_CNTL); + OUT_RING(ring, A6XX_VPC_SO_CNTL_ENABLE); + for (unsigned i = 0; i < prog_count; i++) { + OUT_RING(ring, REG_A6XX_VPC_SO_PROG); + OUT_RING(ring, prog[i]); + } } static void @@ -973,6 +995,8 @@ fd6_program_create(void *data, struct ir3_shader_variant *bs, state->config_stateobj = fd_ringbuffer_new_object(ctx->pipe, 0x1000); state->binning_stateobj = fd_ringbuffer_new_object(ctx->pipe, 0x1000); state->stateobj = fd_ringbuffer_new_object(ctx->pipe, 0x1000); + state->streamout_stateobj = fd_ringbuffer_new_object(ctx->pipe, 0x1000); + #ifdef DEBUG if (!ds) { @@ -1000,6 +1024,7 @@ fd6_program_destroy(void *data, struct ir3_program_state *state) fd_ringbuffer_del(so->binning_stateobj); fd_ringbuffer_del(so->config_stateobj); fd_ringbuffer_del(so->interp_stateobj); + fd_ringbuffer_del(so->streamout_stateobj); free(so); } diff --git a/src/gallium/drivers/freedreno/a6xx/fd6_program.h b/src/gallium/drivers/freedreno/a6xx/fd6_program.h index f1f4838fb38..54a7c1fb52c 100644 --- a/src/gallium/drivers/freedreno/a6xx/fd6_program.h +++ b/src/gallium/drivers/freedreno/a6xx/fd6_program.h @@ -34,13 +34,6 @@ #include "ir3/ir3_shader.h" #include "ir3_cache.h" -struct fd6_streamout_state { - uint32_t ncomp[PIPE_MAX_SO_BUFFERS]; - uint32_t prog[256/2]; - uint32_t prog_count; - uint32_t vpc_so_buf_cntl; -}; - struct fd6_emit; struct fd6_program_state { @@ -54,10 +47,8 @@ struct fd6_program_state { struct fd_ringbuffer *config_stateobj; struct fd_ringbuffer *interp_stateobj; struct fd_ringbuffer *binning_stateobj; + struct fd_ringbuffer *streamout_stateobj; struct fd_ringbuffer *stateobj; - - /* cached state about current emitted shader program (3d): */ - struct fd6_streamout_state tf; }; static inline struct fd6_program_state * diff --git a/src/gallium/drivers/freedreno/freedreno_context.h b/src/gallium/drivers/freedreno/freedreno_context.h index e756411d183..faafad5c672 100644 --- a/src/gallium/drivers/freedreno/freedreno_context.h +++ b/src/gallium/drivers/freedreno/freedreno_context.h @@ -410,6 +410,7 @@ struct fd_context { uint32_t index_start; uint32_t instance_start; uint32_t restart_index; + uint32_t streamout_mask; } last; }; -- 2.30.2