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));
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 =
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);