summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2017-11-13 14:10:25 +1000
committerDave Airlie <airlied@redhat.com>2017-11-14 06:16:06 +1000
commit53d5dda6f805f2bb6359872a7013b7c3293299f6 (patch)
tree5049011d31236b512bda7db4a655c8e321bd5af1
parentf3f8615d76b20ad66466b172a600e06b9a833729 (diff)
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 <airlied@redhat.com>
-rw-r--r--src/gallium/drivers/r600/r600_pipe.h1
-rw-r--r--src/gallium/drivers/r600/r600_shader.c48
-rw-r--r--src/gallium/drivers/r600/r600_shader.h3
-rw-r--r--src/gallium/drivers/r600/r600_state_common.c15
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