radeonsi: fix gl_BaseVertex in non-indexed draws
authorNicolai Hähnle <nicolai.haehnle@amd.com>
Wed, 12 Apr 2017 09:01:19 +0000 (11:01 +0200)
committerNicolai Hähnle <nicolai.haehnle@amd.com>
Thu, 13 Apr 2017 15:31:11 +0000 (17:31 +0200)
gl_BaseVertex is supposed to be 0 in non-indexed draws. Unfortunately, the
way they're implemented, the VGT always generates indices starting at 0,
and the VS prolog adds the start index.

There's a VGT_INDX_OFFSET register which causes the VGT to start at a
driver-defined index. However, this register cannot be written from
indirect draws.

So fix this unlikely case by setting a bit to tell the VS whether the
draw is indexed or not, so that gl_BaseVertex can be adjusted accordingly
when used.

Fixes a bug in
KHR-GL45.shader_draw_parameters_tests.ShaderMultiDrawArraysParameters.*

Reviewed-by: Marek Olšák <marek.olsak@amd.com>
src/gallium/drivers/radeonsi/si_shader.c
src/gallium/drivers/radeonsi/si_shader.h
src/gallium/drivers/radeonsi/si_state_draw.c

index 7adf76a0b03b791ec0e3c0c2617004aff84fa320..0bda187cfd2c2207128fa8379093f4841e778c08 100644 (file)
@@ -1401,9 +1401,22 @@ static void declare_system_value(struct si_shader_context *ctx,
                break;
 
        case TGSI_SEMANTIC_BASEVERTEX:
-               value = LLVMGetParam(ctx->main_fn,
-                                    SI_PARAM_BASE_VERTEX);
+       {
+               /* For non-indexed draws, the base vertex set by the driver
+                * (for direct draws) or the CP (for indirect draws) is the
+                * first vertex ID, but GLSL expects 0 to be returned.
+                */
+               LLVMValueRef vs_state = LLVMGetParam(ctx->main_fn, SI_PARAM_VS_STATE_BITS);
+               LLVMValueRef indexed;
+
+               indexed = LLVMBuildLShr(gallivm->builder, vs_state, ctx->i32_1, "");
+               indexed = LLVMBuildTrunc(gallivm->builder, indexed, ctx->i1, "");
+
+               value = LLVMBuildSelect(gallivm->builder, indexed,
+                                       LLVMGetParam(ctx->main_fn, SI_PARAM_BASE_VERTEX),
+                                       ctx->i32_0, "");
                break;
+       }
 
        case TGSI_SEMANTIC_BASEINSTANCE:
                value = LLVMGetParam(ctx->main_fn,
index fdb0dd482bc0759a55912a65c60466c9e4dd6293..f145eab14f31d23ecdcff1567137b1a47288fa47 100644 (file)
@@ -220,6 +220,8 @@ enum {
 /* Clamp vertex color output (only used in VS as VS). */
 #define S_VS_STATE_CLAMP_VERTEX_COLOR(x)       (((unsigned)(x) & 0x1) << 0)
 #define C_VS_STATE_CLAMP_VERTEX_COLOR          0xFFFFFFFE
+#define S_VS_STATE_INDEXED(x)                  (((unsigned)(x) & 0x1) << 1)
+#define C_VS_STATE_INDEXED                     0xFFFFFFFD
 #define S_VS_STATE_LS_OUT_PATCH_SIZE(x)                (((unsigned)(x) & 0x1FFF) << 8)
 #define C_VS_STATE_LS_OUT_PATCH_SIZE           0xFFE000FF
 #define S_VS_STATE_LS_OUT_VERTEX_SIZE(x)       (((unsigned)(x) & 0xFF) << 24)
index 0d70ea9d6d7e4208dbe666ad14e7e025a8bd03cf..aa528ce43933e1046878ee5403e74e006dedf94a 100644 (file)
@@ -494,8 +494,12 @@ static void si_emit_rasterizer_prim_state(struct si_context *sctx)
        sctx->last_sc_line_stipple = rs->pa_sc_line_stipple;
 }
 
-static void si_emit_vs_state(struct si_context *sctx)
+static void si_emit_vs_state(struct si_context *sctx,
+                            const struct pipe_draw_info *info)
 {
+       sctx->current_vs_state &= C_VS_STATE_INDEXED;
+       sctx->current_vs_state |= S_VS_STATE_INDEXED(!!info->indexed);
+
        if (sctx->current_vs_state != sctx->last_vs_state) {
                struct radeon_winsys_cs *cs = sctx->b.gfx.cs;
 
@@ -1305,7 +1309,7 @@ void si_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info *info)
        si_emit_rasterizer_prim_state(sctx);
        if (sctx->tes_shader.cso)
                si_emit_derived_tess_state(sctx, info, &num_patches);
-       si_emit_vs_state(sctx);
+       si_emit_vs_state(sctx, info);
        si_emit_draw_registers(sctx, info, num_patches);
 
        si_ce_pre_draw_synchronization(sctx);