radv/gfx10: fix primitive indices orientation for NGG GS
authorSamuel Pitoiset <samuel.pitoiset@gmail.com>
Tue, 5 Nov 2019 11:04:57 +0000 (12:04 +0100)
committerSamuel Pitoiset <samuel.pitoiset@gmail.com>
Thu, 7 Nov 2019 19:21:15 +0000 (19:21 +0000)
The primitive indices have to be swapped to follow the drawing
order.

This fixes corruption with Overwatch when NGG GS is force enabled.

Signed-off-by: Samuel Pitoiset <samuel.pitoiset@gmail.com>
Reviewed-by: Bas Nieuwenhuizen <bas@basnieuwenhuizen.nl>
src/amd/vulkan/radv_nir_to_llvm.c
src/amd/vulkan/radv_pipeline.c

index 07c9d0e..1ed1a38 100644 (file)
@@ -3137,6 +3137,7 @@ static void build_sendmsg_gs_alloc_req(struct radv_shader_context *ctx,
 struct ngg_prim {
        unsigned num_vertices;
        LLVMValueRef isnull;
+       LLVMValueRef swap;
        LLVMValueRef index[3];
        LLVMValueRef edgeflag[3];
 };
@@ -3146,19 +3147,52 @@ static void build_export_prim(struct radv_shader_context *ctx,
 {
        LLVMBuilderRef builder = ctx->ac.builder;
        struct ac_export_args args;
+       LLVMValueRef vertices[3];
+       LLVMValueRef odd, even;
        LLVMValueRef tmp;
 
        tmp = LLVMBuildZExt(builder, prim->isnull, ctx->ac.i32, "");
        args.out[0] = LLVMBuildShl(builder, tmp, LLVMConstInt(ctx->ac.i32, 31, false), "");
 
        for (unsigned i = 0; i < prim->num_vertices; ++i) {
-               tmp = LLVMBuildShl(builder, prim->index[i],
-                                  LLVMConstInt(ctx->ac.i32, 10 * i, false), "");
-               args.out[0] = LLVMBuildOr(builder, args.out[0], tmp, "");
-               tmp = LLVMBuildZExt(builder, prim->edgeflag[i], ctx->ac.i32, "");
-               tmp = LLVMBuildShl(builder, tmp,
-                                  LLVMConstInt(ctx->ac.i32, 10 * i + 9, false), "");
-               args.out[0] = LLVMBuildOr(builder, args.out[0], tmp, "");
+               tmp = LLVMBuildZExt(builder, prim->edgeflag[i], ctx->ac.i32, "");
+               tmp = LLVMBuildShl(builder, tmp,
+                                  LLVMConstInt(ctx->ac.i32, 9, false), "");
+               vertices[i] = LLVMBuildOr(builder, prim->index[i], tmp, "");
+       }
+
+       switch (prim->num_vertices) {
+       case 1:
+               args.out[0] = LLVMBuildOr(builder, args.out[0], vertices[0], "");
+               break;
+       case 2:
+               tmp = LLVMBuildShl(builder, vertices[1],
+                                  LLVMConstInt(ctx->ac.i32, 10, false), "");
+               tmp = LLVMBuildOr(builder, args.out[0], tmp, "");
+               args.out[0] = LLVMBuildOr(builder, tmp, vertices[0], "");
+               break;
+       case 3:
+               /* Swap vertices if needed to follow drawing order. */
+               tmp = LLVMBuildShl(builder, vertices[2],
+                                  LLVMConstInt(ctx->ac.i32, 20, false), "");
+               even = LLVMBuildOr(builder, args.out[0], tmp, "");
+               tmp = LLVMBuildShl(builder, vertices[1],
+                                  LLVMConstInt(ctx->ac.i32, 10, false), "");
+               even = LLVMBuildOr(builder, even, tmp, "");
+               even = LLVMBuildOr(builder, even, vertices[0], "");
+
+               tmp = LLVMBuildShl(builder, vertices[1],
+                                  LLVMConstInt(ctx->ac.i32, 20, false), "");
+               odd = LLVMBuildOr(builder, args.out[0], tmp, "");
+               tmp = LLVMBuildShl(builder, vertices[2],
+                                  LLVMConstInt(ctx->ac.i32, 10, false), "");
+               odd = LLVMBuildOr(builder, odd, tmp, "");
+               odd = LLVMBuildOr(builder, odd, vertices[0], "");
+
+               args.out[0] = LLVMBuildSelect(builder, prim->swap, odd, even, "");
+               break;
+       default:
+               unreachable("invalid number of vertices");
        }
 
        args.out[0] = LLVMBuildBitCast(builder, args.out[0], ctx->ac.f32, "");
@@ -3784,6 +3818,7 @@ handle_ngg_outputs_post_2(struct radv_shader_context *ctx)
 
                prim.num_vertices = num_vertices;
                prim.isnull = ctx->ac.i1false;
+               prim.swap = ctx->ac.i1false;
                memcpy(prim.index, vtxindex, sizeof(vtxindex[0]) * 3);
 
                for (unsigned i = 0; i < num_vertices; ++i) {
@@ -4092,6 +4127,9 @@ static void gfx10_ngg_gs_emit_epilogue_2(struct radv_shader_context *ctx)
                tmp = LLVMBuildLoad(builder, tmp, "");
                prim.isnull = LLVMBuildICmp(builder, LLVMIntEQ, tmp,
                                            LLVMConstInt(ctx->ac.i8, 0, false), "");
+               prim.swap = LLVMBuildICmp(builder, LLVMIntEQ,
+                                         LLVMBuildAnd(builder, tid, LLVMConstInt(ctx->ac.i32, 1, false), ""),
+                                         LLVMConstInt(ctx->ac.i32, 1, false), "");
 
                for (unsigned i = 0; i < verts_per_prim; ++i) {
                        prim.index[i] = LLVMBuildSub(builder, vertlive_scan.result_exclusive,
index a2839b6..c187e3e 100644 (file)
@@ -2347,8 +2347,6 @@ radv_fill_shader_keys(struct radv_device *device,
                 * issues still:
                 *   * GS primitives in pipeline statistic queries do not get
                 *     updates. See dEQP-VK.query_pool.statistics_query.geometry_shader_primitives
-                *   * General issues with the last primitive missing/corrupt:
-                *     https://bugs.freedesktop.org/show_bug.cgi?id=111248
                 *
                 * Furthermore, XGL/AMDVLK also disables this as of 9b632ef.
                 */