amd/common: add workaround for cube map array layer clamping
authorNicolai Hähnle <nicolai.haehnle@amd.com>
Wed, 13 Sep 2017 13:33:23 +0000 (15:33 +0200)
committerNicolai Hähnle <nicolai.haehnle@amd.com>
Mon, 18 Sep 2017 09:25:18 +0000 (11:25 +0200)
Fixes dEQP-GLES31.functional.texture.filtering.cube_array.*

Cc: mesa-stable@lists.freedesktop.org
Reviewed-by: Marek Olšák <marek.olsak@amd.com>
src/amd/common/ac_llvm_build.c

index 6c010e8c3a68a758d69829a22eae072f3c35daf7..8a329515b57b0877efea2e9c1cc8cf3a8cfbd836 100644 (file)
@@ -498,8 +498,35 @@ ac_prepare_cube_coords(struct ac_llvm_context *ctx,
        LLVMValueRef invma;
 
        if (is_array && !is_lod) {
-               coords_arg[3] = ac_build_intrinsic(ctx, "llvm.rint.f32", ctx->f32,
-                                                  &coords_arg[3], 1, 0);
+               LLVMValueRef tmp = coords_arg[3];
+               tmp = ac_build_intrinsic(ctx, "llvm.rint.f32", ctx->f32, &tmp, 1, 0);
+
+               /* Section 8.9 (Texture Functions) of the GLSL 4.50 spec says:
+                *
+                *    "For Array forms, the array layer used will be
+                *
+                *       max(0, min(d−1, floor(layer+0.5)))
+                *
+                *     where d is the depth of the texture array and layer
+                *     comes from the component indicated in the tables below.
+                *     Workaroudn for an issue where the layer is taken from a
+                *     helper invocation which happens to fall on a different
+                *     layer due to extrapolation."
+                *
+                * VI and earlier attempt to implement this in hardware by
+                * clamping the value of coords[2] = (8 * layer) + face.
+                * Unfortunately, this means that the we end up with the wrong
+                * face when clamping occurs.
+                *
+                * Clamp the layer earlier to work around the issue.
+                */
+               if (ctx->chip_class <= VI) {
+                       LLVMValueRef ge0;
+                       ge0 = LLVMBuildFCmp(builder, LLVMRealOGE, tmp, ctx->f32_0, "");
+                       tmp = LLVMBuildSelect(builder, ge0, tmp, ctx->f32_0, "");
+               }
+
+               coords_arg[3] = tmp;
        }
 
        build_cube_intrinsic(ctx, coords_arg, &selcoords);