Module: Mesa
Branch: main
Commit: f8eec4c4e3a11de7e4617d9e7d8c9a28105ca645
URL:    
http://cgit.freedesktop.org/mesa/mesa/commit/?id=f8eec4c4e3a11de7e4617d9e7d8c9a28105ca645

Author: Friedrich Vock <[email protected]>
Date:   Thu Jul 13 16:10:12 2023 +0200

radv/rt: Reject hits within 10ULP of previous hits in emulated RT

This is an alternative workaround that fixes double hits on shared edges
failing some watertightness CTS tests.

Fixes: e034ba1c44 ("radv/rt: Miss rays that hit the triangle's v edge")
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/24093>

---

 src/amd/vulkan/radv_rt_common.c | 25 +++++++++++++++++--------
 1 file changed, 17 insertions(+), 8 deletions(-)

diff --git a/src/amd/vulkan/radv_rt_common.c b/src/amd/vulkan/radv_rt_common.c
index 5aab4dc9e9c..22e950a18ef 100644
--- a/src/amd/vulkan/radv_rt_common.c
+++ b/src/amd/vulkan/radv_rt_common.c
@@ -258,13 +258,6 @@ intersect_ray_amd_software_tri(struct radv_device *device, 
nir_builder *b, nir_d
 
    nir_def *cond = nir_inot(b, nir_iand(b, cond_back, cond_front));
 
-   /* If the ray is exactly on the edge where v is 0, consider it a miss.
-    * This seems to correspond to what the hardware is doing.
-    * Also, it avoids invoking hit shaders twice on a shared edge, which is
-    * discouraged by the spec.
-    */
-   cond = nir_iand(b, cond, nir_fneu(b, v, nir_imm_float(b, 0.0f)));
-
    nir_push_if(b, cond);
    {
       nir_def *det = nir_fadd(b, u, nir_fadd(b, v, w));
@@ -373,7 +366,9 @@ insert_traversal_triangle_case(struct radv_device *device, 
nir_builder *b, const
    nir_def *div = nir_channel(b, result, 1);
    intersection.t = nir_fdiv(b, intersection.t, div);
 
-   nir_push_if(b, nir_flt(b, intersection.t, nir_load_deref(b, 
args->vars.tmax)));
+   nir_def *tmax = nir_load_deref(b, args->vars.tmax);
+
+   nir_push_if(b, nir_flt(b, intersection.t, tmax));
    {
       intersection.frontface = nir_fgt_imm(b, div, 0);
       nir_def *switch_ccw =
@@ -408,6 +403,20 @@ insert_traversal_triangle_case(struct radv_device *device, 
nir_builder *b, const
             nir_def *divs[2] = {div, div};
             intersection.barycentrics = nir_fdiv(b, nir_channels(b, result, 
0xc), nir_vec(b, divs, 2));
 
+            nir_def *hit_t = intersection.t;
+            /* t values within 10 ULP of the current hit t are most likely 
duplicate hits along shared edges, which
+             * might occur with emulated RT. The Vulkan spec discourages 
double-hits along shared-edges, so reject them
+             * here by subtracting 10 ULP from t.
+             */
+            if (radv_emulate_rt(device->physical_device)) {
+               nir_def *abs_t = nir_fabs(b, hit_t);
+               nir_def *sign_t = nir_fsign(b, hit_t);
+
+               nir_def *tm1 = nir_iadd(b, hit_t, nir_imul_imm(b, nir_f2i32(b, 
sign_t), -10));
+               nir_def *tm2 = nir_fmul(b, nir_isub_imm(b, 10, abs_t), 
nir_fneg(b, sign_t));
+               intersection.t = nir_bcsel(b, nir_ige_imm(b, abs_t, 10), tm1, 
tm2);
+            }
+
             args->triangle_cb(b, &intersection, args, ray_flags);
          }
          nir_pop_if(b, NULL);

Reply via email to