From 53d5dda6f805f2bb6359872a7013b7c3293299f6 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 13 Nov 2017 14:10:25 +1000 Subject: [PATCH] r600: add gs tri strip adjacency fix. Like radeonsi: generate GS prolog to (partially) fix triangle strip adjacency rotation evergreen hw suffers from the same problem, so rotate the geometry inputs to fix this. This fixes: ./bin/glsl-1.50-geometry-primitive-types GL_TRIANGLE_STRIP_ADJACENCY on evergreen. Signed-off-by: Dave Airlie --- src/gallium/drivers/r600/r600_pipe.h | 1 + src/gallium/drivers/r600/r600_shader.c | 48 ++++++++++++++++++-- src/gallium/drivers/r600/r600_shader.h | 3 +- src/gallium/drivers/r600/r600_state_common.c | 15 ++++++ 4 files changed, 62 insertions(+), 5 deletions(-) diff --git a/src/gallium/drivers/r600/r600_pipe.h b/src/gallium/drivers/r600/r600_pipe.h index 3dae56e3054..4fbc82b43f2 100644 --- a/src/gallium/drivers/r600/r600_pipe.h +++ b/src/gallium/drivers/r600/r600_pipe.h @@ -510,6 +510,7 @@ struct r600_context { struct r600_rasterizer_state *rasterizer; bool alpha_to_one; bool force_blend_disable; + bool gs_tri_strip_adj_fix; boolean dual_src_blend; unsigned zwritemask; int ps_iter_samples; diff --git a/src/gallium/drivers/r600/r600_shader.c b/src/gallium/drivers/r600/r600_shader.c index 146c26ce1a6..f4bbb34ceb9 100644 --- a/src/gallium/drivers/r600/r600_shader.c +++ b/src/gallium/drivers/r600/r600_shader.c @@ -348,6 +348,7 @@ struct r600_shader_ctx { int gs_next_vertex; struct r600_shader *gs_for_vs; int gs_export_gpr_tregs[4]; + int gs_rotated_input[2]; const struct pipe_stream_output_info *gs_stream_output_info; unsigned enabled_stream_buffers_mask; unsigned tess_input_info; /* temp with tess input offsets */ @@ -760,7 +761,7 @@ static int single_alu_op3(struct r600_shader_ctx *ctx, int op, int r; /* validate this for other ops */ - assert(op == ALU_OP3_MULADD_UINT24); + assert(op == ALU_OP3_MULADD_UINT24 || op == ALU_OP3_CNDE_INT); memset(&alu, 0, sizeof(struct r600_bytecode_alu)); alu.op = op; alu.src[0].sel = src0_sel; @@ -1479,14 +1480,14 @@ static int fetch_gs_input(struct r600_shader_ctx *ctx, struct tgsi_full_src_regi int r; unsigned index = src->Register.Index; unsigned vtx_id = src->Dimension.Index; - int offset_reg = vtx_id / 3; + int offset_reg = ctx->gs_rotated_input[vtx_id / 3]; int offset_chan = vtx_id % 3; int t2 = 0; /* offsets of per-vertex data in ESGS ring are passed to GS in R0.x, R0.y, * R0.w, R1.x, R1.y, R1.z (it seems R0.z is used for PrimitiveID) */ - if (offset_reg == 0 && offset_chan == 2) + if (offset_reg == ctx->gs_rotated_input[0] && offset_chan == 2) offset_chan = 3; if (src->Dimension.Indirect || src->Register.Indirect) @@ -1517,7 +1518,7 @@ static int fetch_gs_input(struct r600_shader_ctx *ctx, struct tgsi_full_src_regi for (i = 0; i < 3; i++) { memset(&alu, 0, sizeof(struct r600_bytecode_alu)); alu.op = ALU_OP1_MOV; - alu.src[0].sel = 0; + alu.src[0].sel = ctx->gs_rotated_input[0]; alu.src[0].chan = i == 2 ? 3 : i; alu.dst.sel = treg[i]; alu.dst.chan = 0; @@ -2990,6 +2991,7 @@ static int r600_shader_from_tgsi(struct r600_context *rctx, case PIPE_SHADER_GEOMETRY: ring_outputs = true; shader->atomic_base = key.gs.first_atomic_counter; + shader->gs_tri_strip_adj_fix = key.gs.tri_strip_adj_fix; break; case PIPE_SHADER_TESS_CTRL: shader->tcs_prim_mode = key.tcs.prim_mode; @@ -3123,6 +3125,14 @@ static int r600_shader_from_tgsi(struct r600_context *rctx, ctx.gs_export_gpr_tregs[2] = ctx.bc->ar_reg + 5; ctx.gs_export_gpr_tregs[3] = ctx.bc->ar_reg + 6; ctx.temp_reg = ctx.bc->ar_reg + 7; + if (ctx.shader->gs_tri_strip_adj_fix) { + ctx.gs_rotated_input[0] = ctx.bc->ar_reg + 7; + ctx.gs_rotated_input[1] = ctx.bc->ar_reg + 8; + ctx.temp_reg += 2; + } else { + ctx.gs_rotated_input[0] = 0; + ctx.gs_rotated_input[1] = 1; + } } else { ctx.temp_reg = ctx.bc->ar_reg + 3; } @@ -3290,6 +3300,36 @@ static int r600_shader_from_tgsi(struct r600_context *rctx, if (r) return r; } + + if (ctx.shader->gs_tri_strip_adj_fix) { + r = single_alu_op2(&ctx, ALU_OP2_AND_INT, + ctx.gs_rotated_input[0], 2, + 0, 2, + V_SQ_ALU_SRC_LITERAL, 1); + if (r) + return r; + + for (i = 0; i < 6; i++) { + int rotated = (i + 4) % 6; + int offset_reg = i / 3; + int offset_chan = i % 3; + int rotated_offset_reg = rotated / 3; + int rotated_offset_chan = rotated % 3; + + if (offset_reg == 0 && offset_chan == 2) + offset_chan = 3; + if (rotated_offset_reg == 0 && rotated_offset_chan == 2) + rotated_offset_chan = 3; + + r = single_alu_op3(&ctx, ALU_OP3_CNDE_INT, + ctx.gs_rotated_input[offset_reg], offset_chan, + ctx.gs_rotated_input[0], 2, + offset_reg, offset_chan, + rotated_offset_reg, rotated_offset_chan); + if (r) + return r; + } + } } if (ctx.type == PIPE_SHADER_TESS_CTRL) diff --git a/src/gallium/drivers/r600/r600_shader.h b/src/gallium/drivers/r600/r600_shader.h index 3fecda4c800..40719d9be5e 100644 --- a/src/gallium/drivers/r600/r600_shader.h +++ b/src/gallium/drivers/r600/r600_shader.h @@ -96,7 +96,7 @@ struct r600_shader { boolean has_txq_cube_array_z_comp; boolean uses_tex_buffers; boolean gs_prim_id_input; - + boolean gs_tri_strip_adj_fix; uint8_t ps_conservative_z; /* Size in bytes of a data item in the ring(s) (single vertex data). @@ -143,6 +143,7 @@ union r600_shader_key { } tcs; struct { unsigned first_atomic_counter:4; + unsigned tri_strip_adj_fix:1; } gs; }; diff --git a/src/gallium/drivers/r600/r600_state_common.c b/src/gallium/drivers/r600/r600_state_common.c index 750fd411baf..ead5b86e0c5 100644 --- a/src/gallium/drivers/r600/r600_state_common.c +++ b/src/gallium/drivers/r600/r600_state_common.c @@ -753,6 +753,7 @@ static inline void r600_shader_selector_key(const struct pipe_context *ctx, } case PIPE_SHADER_GEOMETRY: key->gs.first_atomic_counter = r600_get_hw_atomic_count(ctx, PIPE_SHADER_GEOMETRY); + key->gs.tri_strip_adj_fix = rctx->gs_tri_strip_adj_fix; break; case PIPE_SHADER_FRAGMENT: { key->ps.first_atomic_counter = r600_get_hw_atomic_count(ctx, PIPE_SHADER_FRAGMENT); @@ -1767,6 +1768,20 @@ static void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info rctx->framebuffer.do_update_surf_dirtiness = true; } + if (rctx->gs_shader) { + /* Determine whether the GS triangle strip adjacency fix should + * be applied. Rotate every other triangle if + * - triangle strips with adjacency are fed to the GS and + * - primitive restart is disabled (the rotation doesn't help + * when the restart occurs after an odd number of triangles). + */ + bool gs_tri_strip_adj_fix = + !rctx->tes_shader && + info->mode == PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY && + !info->primitive_restart; + if (gs_tri_strip_adj_fix != rctx->gs_tri_strip_adj_fix) + rctx->gs_tri_strip_adj_fix = gs_tri_strip_adj_fix; + } if (!r600_update_derived_state(rctx)) { /* useless to render because current rendering command * can't be achieved -- 2.30.2