ac/nir: Fix gather4 integer wa with unnormalized coordinates
authorConnor Abbott <cwabbott0@gmail.com>
Thu, 6 Jun 2019 14:28:48 +0000 (16:28 +0200)
committerConnor Abbott <cwabbott0@gmail.com>
Tue, 3 Sep 2019 13:50:54 +0000 (13:50 +0000)
This adds a bit of unneccesary code on radeonsi, since whether
unnormalized coordinates are used is known at compile time with GL, but
I wasn't sure if it was worth the few instructions to plumb everything
through, especially for something so rare -- my shader-db doesn't have
any instances where this changes anything.

Fixes CTS tests I created at
https://github.com/cwabbott0/VK-GL-CTS/tree/unnorm-gather-tests

Acked-by: Marek Olšák <marek.olsak@amd.com>
Reviewed-by: Bas Nieuwenhuizen <bas@basnieuwenhuizen.nl>
src/amd/common/ac_nir_to_llvm.c

index 5d6531558aa7ac7ca01e16399eb8642486f7875c..baac8e5ec97a8369d0f7e6468692b66341bfe968 100644 (file)
@@ -1248,10 +1248,32 @@ static LLVMValueRef lower_gather4_integer(struct ac_llvm_context *ctx,
                struct ac_image_args resinfo = {};
                LLVMBasicBlockRef bbs[2];
 
+               LLVMValueRef unnorm = NULL;
+               LLVMValueRef default_offset = ctx->f32_0;
+               if (instr->sampler_dim == GLSL_SAMPLER_DIM_2D &&
+                   !instr->is_array) {
+                       /* In vulkan, whether the sampler uses unnormalized
+                        * coordinates or not is a dynamic property of the
+                        * sampler. Hence, to figure out whether or not we
+                        * need to divide by the texture size, we need to test
+                        * the sampler at runtime. This tests the bit set by
+                        * radv_init_sampler().
+                        */
+                       LLVMValueRef sampler0 =
+                               LLVMBuildExtractElement(ctx->builder, args->sampler, ctx->i32_0, "");
+                       sampler0 = LLVMBuildLShr(ctx->builder, sampler0,
+                                                LLVMConstInt(ctx->i32, 15, false), "");
+                       sampler0 = LLVMBuildAnd(ctx->builder, sampler0, ctx->i32_1, "");
+                       unnorm = LLVMBuildICmp(ctx->builder, LLVMIntEQ, sampler0, ctx->i32_1, "");
+                       default_offset = LLVMConstReal(ctx->f32, -0.5);
+               }
+
                bbs[0] = LLVMGetInsertBlock(ctx->builder);
-               if (wa_8888) {
+               if (wa_8888 || unnorm) {
+                       assert(!(wa_8888 && unnorm));
+                       LLVMValueRef not_needed = wa_8888 ? wa_8888 : unnorm;
                        /* Skip the texture size query entirely if we don't need it. */
-                       ac_build_ifcc(ctx, LLVMBuildNot(ctx->builder, wa_8888, ""), 2000);
+                       ac_build_ifcc(ctx, LLVMBuildNot(ctx->builder, not_needed, ""), 2000);
                        bbs[1] = LLVMGetInsertBlock(ctx->builder);
                }
 
@@ -1275,11 +1297,11 @@ static LLVMValueRef lower_gather4_integer(struct ac_llvm_context *ctx,
                                                      LLVMConstReal(ctx->f32, -0.5), "");
                }
 
-               if (wa_8888) {
+               if (wa_8888 || unnorm) {
                        ac_build_endif(ctx, 2000);
 
                        for (unsigned c = 0; c < 2; c++) {
-                               LLVMValueRef values[2] = { ctx->f32_0, half_texel[c] };
+                               LLVMValueRef values[2] = { default_offset, half_texel[c] };
                                half_texel[c] = ac_build_phi(ctx, ctx->f32, 2,
                                                             values, bbs);
                        }