wgpu/naga/tests/out/msl/ray-query.msl
Jim Blandy 3fda684eb9 [naga msl-out] Defeat the MSL compiler's infinite loop analysis.
See the comments in the code for details.

This patch emits the definition of the macro only when the first loop
is encountered. This does make that first loop's code look a bit odd:
it would be more natural to define the macro at the top of the
file. (See the modified files in `naga/tests/out/msl`.)

Rejected alternatives:

- We could emit the macro definition unconditionally at the top of the
  file. But this changes every MSL snapshot output file, whereas only
  eight of them actually contain loops.

- We could have the validator flag modules that contain loops. But the
  changes end up being not small, and spread across the validator, so
  this seems disproportionate. If we had other consumers of this
  information, it might make sense.

- We could change the MSL backend to allow text to be generated out of
  order, so that we can decide whether to define the macro after we've
  generated all the function bodies. But at the moment this seems like
  unnecessary complexity, although it might be worth doing in the
  future if we had additional uses for it - say, to conditionally emit
  helper function definitions.

Fixes #4972.
2024-09-18 11:01:51 -04:00

90 lines
3.7 KiB
Plaintext

// language: metal2.4
#include <metal_stdlib>
#include <simd/simd.h>
using metal::uint;
struct _RayQuery {
metal::raytracing::intersector<metal::raytracing::instancing, metal::raytracing::triangle_data, metal::raytracing::world_space_data> intersector;
metal::raytracing::intersector<metal::raytracing::instancing, metal::raytracing::triangle_data, metal::raytracing::world_space_data>::result_type intersection;
bool ready = false;
};
constexpr metal::uint _map_intersection_type(const metal::raytracing::intersection_type ty) {
return ty==metal::raytracing::intersection_type::triangle ? 1 :
ty==metal::raytracing::intersection_type::bounding_box ? 4 : 0;
}
struct RayIntersection {
uint kind;
float t;
uint instance_custom_index;
uint instance_id;
uint sbt_record_offset;
uint geometry_index;
uint primitive_index;
metal::float2 barycentrics;
bool front_face;
char _pad9[11];
metal::float4x3 object_to_world;
metal::float4x3 world_to_object;
};
struct RayDesc {
uint flags;
uint cull_mask;
float tmin;
float tmax;
metal::float3 origin;
metal::float3 dir;
};
struct Output {
uint visible;
char _pad1[12];
metal::float3 normal;
};
RayIntersection query_loop(
metal::float3 pos,
metal::float3 dir,
metal::raytracing::instance_acceleration_structure acs
) {
_RayQuery rq = {};
RayDesc _e8 = RayDesc {4u, 255u, 0.1, 100.0, pos, dir};
rq.intersector.assume_geometry_type(metal::raytracing::geometry_type::triangle);
rq.intersector.set_opacity_cull_mode((_e8.flags & 64) != 0 ? metal::raytracing::opacity_cull_mode::opaque : (_e8.flags & 128) != 0 ? metal::raytracing::opacity_cull_mode::non_opaque : metal::raytracing::opacity_cull_mode::none);
rq.intersector.force_opacity((_e8.flags & 1) != 0 ? metal::raytracing::forced_opacity::opaque : (_e8.flags & 2) != 0 ? metal::raytracing::forced_opacity::non_opaque : metal::raytracing::forced_opacity::none);
rq.intersector.accept_any_intersection((_e8.flags & 4) != 0);
rq.intersection = rq.intersector.intersect(metal::raytracing::ray(_e8.origin, _e8.dir, _e8.tmin, _e8.tmax), acs, _e8.cull_mask); rq.ready = true;
#define LOOP_IS_REACHABLE if (volatile bool unpredictable_jump_over_loop = true; unpredictable_jump_over_loop)
LOOP_IS_REACHABLE while(true) {
bool _e9 = rq.ready;
rq.ready = false;
if (_e9) {
} else {
break;
}
}
return RayIntersection {_map_intersection_type(rq.intersection.type), rq.intersection.distance, rq.intersection.user_instance_id, rq.intersection.instance_id, {}, rq.intersection.geometry_id, rq.intersection.primitive_id, rq.intersection.triangle_barycentric_coord, rq.intersection.triangle_front_facing, {}, rq.intersection.object_to_world_transform, rq.intersection.world_to_object_transform};
}
metal::float3 get_torus_normal(
metal::float3 world_point,
RayIntersection intersection
) {
metal::float3 local_point = intersection.world_to_object * metal::float4(world_point, 1.0);
metal::float2 point_on_guiding_line = metal::normalize(local_point.xy) * 2.4;
metal::float3 world_point_on_guiding_line = intersection.object_to_world * metal::float4(point_on_guiding_line, 0.0, 1.0);
return metal::normalize(world_point - world_point_on_guiding_line);
}
kernel void main_(
metal::raytracing::instance_acceleration_structure acc_struct [[user(fake0)]]
, device Output& output [[user(fake0)]]
) {
metal::float3 pos_1 = metal::float3(0.0);
metal::float3 dir_1 = metal::float3(0.0, 1.0, 0.0);
RayIntersection _e7 = query_loop(pos_1, dir_1, acc_struct);
output.visible = static_cast<uint>(_e7.kind == 0u);
metal::float3 _e18 = get_torus_normal(dir_1 * _e7.t, _e7);
output.normal = _e18;
return;
}