mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-05 05:18:08 +02:00
lavapipe/rt: Fix watertightness for real this time
Reviewed-by: Mike Blumenkrantz <michael.blumenkrantz@gmail.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36197>
This commit is contained in:
parent
9313a16e24
commit
a8cc143044
3 changed files with 96 additions and 17 deletions
|
|
@ -11,7 +11,10 @@ test_planar_video_formats,Fail
|
|||
# The test expect lod=0.5 to load level 1 with nearest sampling
|
||||
test_sample_instructions,Fail
|
||||
|
||||
# The test messes up creating quad primitives and lavapipe misses some primitives
|
||||
# because of reduced instance transform precision.
|
||||
test_rayquery,Fail
|
||||
|
||||
test_raytracing,Fail
|
||||
test_raytracing_mismatch_global_rs_link,Fail
|
||||
test_sampler_rounding,Fail
|
||||
|
|
|
|||
|
|
@ -509,6 +509,13 @@ lvp_encode_as(struct vk_acceleration_structure *dst, VkDeviceAddress intermediat
|
|||
const struct vk_ir_node *ir_child = (const void *)(ir_bvh + ir_child_offset);
|
||||
|
||||
output_box->bounds[child_index] = ir_child->aabb;
|
||||
/* Increase the bounding box size a bit for watertightness. */
|
||||
output_box->bounds[child_index].min.x -= MAX2(fabsf(output_box->bounds[child_index].min.x), 1.0) * FLT_EPSILON;
|
||||
output_box->bounds[child_index].min.y -= MAX2(fabsf(output_box->bounds[child_index].min.y), 1.0) * FLT_EPSILON;
|
||||
output_box->bounds[child_index].min.z -= MAX2(fabsf(output_box->bounds[child_index].min.z), 1.0) * FLT_EPSILON;
|
||||
output_box->bounds[child_index].max.x += MAX2(fabsf(output_box->bounds[child_index].max.x), 1.0) * FLT_EPSILON;
|
||||
output_box->bounds[child_index].max.y += MAX2(fabsf(output_box->bounds[child_index].max.y), 1.0) * FLT_EPSILON;
|
||||
output_box->bounds[child_index].max.z += MAX2(fabsf(output_box->bounds[child_index].max.z), 1.0) * FLT_EPSILON;
|
||||
|
||||
if (ir_child_offset < root_offset) {
|
||||
output_box->children[child_index] =
|
||||
|
|
|
|||
|
|
@ -150,6 +150,27 @@ lvp_build_intersect_ray_box(nir_builder *b, nir_def **node_data, nir_def *ray_tm
|
|||
return nir_load_var(b, child_indices);
|
||||
}
|
||||
|
||||
static nir_def *
|
||||
lvp_build_intersect_edge(nir_builder *b, nir_def *v0_x, nir_def *v0_y, nir_def *v1_x, nir_def *v1_y)
|
||||
{
|
||||
/* Test (1 0 0) direction: t = <v1-v0, (1 0 0)> */
|
||||
nir_def *t_x = nir_fsub(b, v1_x, v0_x);
|
||||
nir_def *test_y = nir_feq_imm(b, t_x, 0.0);
|
||||
/* Test (0 1 0) direction: t = <v1-v0, (0 1 0)> */
|
||||
nir_def *t_y = nir_fsub(b, v1_y, v0_y);
|
||||
|
||||
return nir_bcsel(b, test_y, nir_flt_imm(b, t_y, 0.0), nir_flt_imm(b, t_x, 0.0));
|
||||
}
|
||||
|
||||
static nir_def *
|
||||
lvp_build_intersect_vertex(nir_builder *b, nir_def *v0_x, nir_def *v1_x, nir_def *v2_x)
|
||||
{
|
||||
/* Choose n=(1 0 0) to simplify the dot product. */
|
||||
nir_def *edge0 = nir_fsub(b, v1_x, v0_x);
|
||||
nir_def *edge1 = nir_fsub(b, v2_x, v0_x);
|
||||
return nir_iand(b, nir_fle_imm(b, edge0, 0.0), nir_fgt_imm(b, edge1, 0.0));
|
||||
}
|
||||
|
||||
static nir_def *
|
||||
lvp_build_intersect_ray_tri(nir_builder *b, nir_def **node_data, nir_def *ray_tmax,
|
||||
nir_def *origin, nir_def *dir, nir_def *inv_dir)
|
||||
|
|
@ -237,13 +258,6 @@ lvp_build_intersect_ray_tri(nir_builder *b, nir_def **node_data, nir_def *ray_tm
|
|||
nir_def *cy =
|
||||
nir_fsub(b, nir_vector_extract(b, v_c, ky), nir_fmul(b, sy, nir_vector_extract(b, v_c, kz)));
|
||||
|
||||
ax = nir_f2f64(b, ax);
|
||||
ay = nir_f2f64(b, ay);
|
||||
bx = nir_f2f64(b, bx);
|
||||
by = nir_f2f64(b, by);
|
||||
cx = nir_f2f64(b, cx);
|
||||
cy = nir_f2f64(b, cy);
|
||||
|
||||
nir_def *u = nir_fsub(b, nir_fmul(b, cx, by), nir_fmul(b, cy, bx));
|
||||
nir_def *v = nir_fsub(b, nir_fmul(b, ax, cy), nir_fmul(b, ay, cx));
|
||||
nir_def *w = nir_fsub(b, nir_fmul(b, bx, ay), nir_fmul(b, by, ax));
|
||||
|
|
@ -257,16 +271,72 @@ lvp_build_intersect_ray_tri(nir_builder *b, nir_def **node_data, nir_def *ray_tm
|
|||
|
||||
nir_def *cond = nir_inot(b, nir_iand(b, cond_back, cond_front));
|
||||
|
||||
/* When an edge is hit, we have to ensure that it is not hit twice in case it is shared.
|
||||
*
|
||||
* Vulkan 1.4.322, Section 40.1.1 Watertightness:
|
||||
*
|
||||
* Any set of two triangles with two shared vertices that were specified in the same
|
||||
* winding order in each triangle have a shared edge defined by those vertices.
|
||||
*
|
||||
* This means we can decide which triangle should intersect by comparing the shared edge
|
||||
* to two arbitrary directions because the shared edges are antiparallel. The triangle
|
||||
* vertices are transformed so the ray direction is (0 0 1). Therefore it makes sense to
|
||||
* choose (1 0 0) and (0 1 0) as reference directions.
|
||||
*
|
||||
* Hitting edges is extremely rare so an if should be worth.
|
||||
*/
|
||||
nir_def *is_edge_a = nir_feq_imm(b, u, 0.0f);
|
||||
nir_def *is_edge_b = nir_feq_imm(b, v, 0.0f);
|
||||
nir_def *is_edge_c = nir_feq_imm(b, w, 0.0f);
|
||||
nir_def *cond_edge = nir_ior(b, is_edge_a, nir_ior(b, is_edge_b, is_edge_c));
|
||||
nir_def *intersect_edge = cond;
|
||||
nir_push_if(b, cond_edge);
|
||||
{
|
||||
nir_def *intersect_edge_a = nir_iand(b, is_edge_a, lvp_build_intersect_edge(b, bx, by, cx, cy));
|
||||
nir_def *intersect_edge_b = nir_iand(b, is_edge_b, lvp_build_intersect_edge(b, cx, cy, ax, ay));
|
||||
nir_def *intersect_edge_c = nir_iand(b, is_edge_c, lvp_build_intersect_edge(b, ax, ay, bx, by));
|
||||
intersect_edge = nir_iand(b, intersect_edge, nir_ior(b, nir_ior(b, intersect_edge_a, intersect_edge_b), intersect_edge_c));
|
||||
|
||||
/* For vertices, special handling is needed to avoid double hits. The spec defines
|
||||
* shared vertices as follows (Vulkan 1.4.322, Section 40.1.1 Watertightness):
|
||||
*
|
||||
* Any set of two or more triangles where all triangles have one vertex with an
|
||||
* identical position value, that vertex is a shared vertex.
|
||||
*
|
||||
* Since the no double hit/miss requirement of a shared vertex is only formulated for
|
||||
* closed fans
|
||||
*
|
||||
* Implementations should not double-hit or miss when a ray intersects a shared edge,
|
||||
* or a shared vertex of a closed fan.
|
||||
*
|
||||
* it is possible to choose an arbitrary direction n that defines which triangle in the
|
||||
* closed fan should intersect the shared vertex with the ray.
|
||||
*
|
||||
* All edges that include the above vertex are shared edges.
|
||||
*
|
||||
* Implies that all triangles have the same winding order. It is therefore sufficiant
|
||||
* to choose the triangle where the other vertices are on both sides of a plane
|
||||
* perpendicular to n (relying on winding order to get one instead of two triangles
|
||||
* that meet said condition).
|
||||
*/
|
||||
nir_def *is_vertex_a = nir_iand(b, is_edge_b, is_edge_c);
|
||||
nir_def *is_vertex_b = nir_iand(b, is_edge_a, is_edge_c);
|
||||
nir_def *is_vertex_c = nir_iand(b, is_edge_a, is_edge_b);
|
||||
nir_def *intersect_vertex_a = nir_iand(b, is_vertex_a, lvp_build_intersect_vertex(b, ax, bx, cx));
|
||||
nir_def *intersect_vertex_b = nir_iand(b, is_vertex_b, lvp_build_intersect_vertex(b, bx, cx, ax));
|
||||
nir_def *intersect_vertex_c = nir_iand(b, is_vertex_c, lvp_build_intersect_vertex(b, cx, ax, bx));
|
||||
nir_def *is_vertex = nir_ior(b, nir_ior(b, is_vertex_a, is_vertex_b), is_vertex_c);
|
||||
nir_def *intersect_vertex = nir_ior(b, nir_ior(b, intersect_vertex_a, intersect_vertex_b), intersect_vertex_c);
|
||||
intersect_vertex = nir_ior(b, nir_inot(b, is_vertex), intersect_vertex);
|
||||
intersect_edge = nir_iand(b, intersect_edge, intersect_vertex);
|
||||
}
|
||||
nir_pop_if(b, NULL);
|
||||
cond = nir_if_phi(b, intersect_edge, cond);
|
||||
|
||||
nir_push_if(b, cond);
|
||||
{
|
||||
nir_def *det = nir_fadd(b, u, nir_fadd(b, v, w));
|
||||
|
||||
sz = nir_f2f64(b, sz);
|
||||
|
||||
v_a = nir_f2f64(b, v_a);
|
||||
v_b = nir_f2f64(b, v_b);
|
||||
v_c = nir_f2f64(b, v_c);
|
||||
|
||||
nir_def *az = nir_fmul(b, sz, nir_vector_extract(b, v_a, kz));
|
||||
nir_def *bz = nir_fmul(b, sz, nir_vector_extract(b, v_b, kz));
|
||||
nir_def *cz = nir_fmul(b, sz, nir_vector_extract(b, v_c, kz));
|
||||
|
|
@ -280,10 +350,9 @@ lvp_build_intersect_ray_tri(nir_builder *b, nir_def **node_data, nir_def *ray_tm
|
|||
|
||||
nir_push_if(b, det_cond_front);
|
||||
{
|
||||
t = nir_f2f32(b, nir_fdiv(b, t, det));
|
||||
det = nir_f2f32(b, det);
|
||||
v = nir_fdiv(b, nir_f2f32(b, v), det);
|
||||
w = nir_fdiv(b, nir_f2f32(b, w), det);
|
||||
t = nir_fdiv(b, t, det);
|
||||
v = nir_fdiv(b, v, det);
|
||||
w = nir_fdiv(b, w, det);
|
||||
|
||||
nir_def *indices[4] = {t, det, v, w};
|
||||
nir_store_var(b, result, nir_vec(b, indices, 4), 0xf);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue