From 82d825080379f28fde8644792a551f8a7d3dbd12 Mon Sep 17 00:00:00 2001 From: Erin Power Date: Wed, 31 Mar 2021 11:13:02 +0200 Subject: [PATCH] Add support for SPV_KHR_ray_tracing --- Cargo.lock | 43 ++--- crates/rustc_codegen_spirv/Cargo.toml | 2 +- crates/rustc_codegen_spirv/src/abi.rs | 3 + crates/rustc_codegen_spirv/src/attr.rs | 1 + .../src/builder/builder_methods.rs | 6 + .../src/codegen_cx/constant.rs | 4 + .../src/codegen_cx/entry.rs | 5 +- .../src/codegen_cx/type_.rs | 8 +- .../src/linker/new_structurizer.rs | 7 +- .../src/linker/simple_passes.rs | 7 +- crates/rustc_codegen_spirv/src/spirv_type.rs | 19 ++- .../src/spirv_type_constraints.rs | 6 +- crates/rustc_codegen_spirv/src/symbols.rs | 63 ++++--- crates/spirv-std/Cargo.toml | 1 + crates/spirv-std/src/arch.rs | 2 + crates/spirv-std/src/arch/ray_tracing.rs | 85 +++++++++ crates/spirv-std/src/lib.rs | 1 + crates/spirv-std/src/ray_tracing.rs | 161 ++++++++++++++++++ ...convert_u_to_acceleration_structure_khr.rs | 39 +++++ tests/ui/arch/execute_callable.rs | 16 ++ tests/ui/arch/ignore_intersection_khr.rs | 10 ++ tests/ui/arch/report_intersection_khr.rs | 10 ++ tests/ui/arch/terminate_ray_khr.rs | 10 ++ tests/ui/arch/trace_ray_khr.rs | 27 +++ 24 files changed, 466 insertions(+), 70 deletions(-) create mode 100644 crates/spirv-std/src/arch/ray_tracing.rs create mode 100644 crates/spirv-std/src/ray_tracing.rs create mode 100644 tests/ui/arch/convert_u_to_acceleration_structure_khr.rs create mode 100644 tests/ui/arch/execute_callable.rs create mode 100644 tests/ui/arch/ignore_intersection_khr.rs create mode 100644 tests/ui/arch/report_intersection_khr.rs create mode 100644 tests/ui/arch/terminate_ray_khr.rs create mode 100644 tests/ui/arch/trace_ray_khr.rs diff --git a/Cargo.lock b/Cargo.lock index 32d8436f13..5b0d9871a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -531,9 +531,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775" +checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" dependencies = [ "cfg-if 1.0.0", "crossbeam-utils", @@ -853,9 +853,9 @@ checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" [[package]] name = "futures" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f55667319111d593ba876406af7c409c0ebb44dc4be6132a783ccf163ea14c1" +checksum = "a9d5813545e459ad3ca1bff9915e9ad7f1a47dc6a91b627ce321d5863b7dd253" dependencies = [ "futures-channel", "futures-core", @@ -868,9 +868,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c2dd2df839b57db9ab69c2c9d8f3e8c81984781937fe2807dc6dcf3b2ad2939" +checksum = "ce79c6a52a299137a6013061e0cf0e688fce5d7f1bc60125f520912fdb29ec25" dependencies = [ "futures-core", "futures-sink", @@ -878,15 +878,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15496a72fabf0e62bdc3df11a59a3787429221dd0710ba8ef163d6f7a9112c94" +checksum = "098cd1c6dda6ca01650f1a37a794245eb73181d0d4d4e955e2f3c37db7af1815" [[package]] name = "futures-executor" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891a4b7b96d84d5940084b2a37632dd65deeae662c114ceaa2c879629c9c0ad1" +checksum = "10f6cb7042eda00f0049b1d2080aa4b93442997ee507eb3828e8bd7577f94c9d" dependencies = [ "futures-core", "futures-task", @@ -895,27 +895,27 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71c2c65c57704c32f5241c1223167c2c3294fd34ac020c807ddbe6db287ba59" +checksum = "365a1a1fb30ea1c03a830fdb2158f5236833ac81fa0ad12fe35b29cddc35cb04" [[package]] name = "futures-sink" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85754d98985841b7d4f5e8e6fbfa4a4ac847916893ec511a2917ccd8525b8bb3" +checksum = "5c5629433c555de3d82861a7a4e3794a4c40040390907cfbfd7143a92a426c23" [[package]] name = "futures-task" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa189ef211c15ee602667a6fcfe1c1fd9e07d42250d2156382820fba33c9df80" +checksum = "ba7aa51095076f3ba6d9a1f702f74bd05ec65f555d70d2033d55ba8d69f581bc" [[package]] name = "futures-util" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1812c7ab8aedf8d6f2701a43e1243acdbcc2b36ab26e2ad421eb99ac963d96d1" +checksum = "3c144ad54d60f23927f0a6b6d816e4271278b64f005ad65e4e35291d2de9c025" dependencies = [ "futures-channel", "futures-core", @@ -2078,12 +2078,12 @@ dependencies = [ [[package]] name = "rspirv" version = "0.7.0" -source = "git+https://github.com/gfx-rs/rspirv.git?rev=ee1e913#ee1e9135845409b2a096d880286c865c4e2ac3d6" +source = "git+https://github.com/gfx-rs/rspirv.git?rev=719cf08#719cf08e4af0436242707479e3509add5ec3d514" dependencies = [ "derive_more", "fxhash", "num-traits", - "spirv_headers 1.5.0 (git+https://github.com/gfx-rs/rspirv.git?rev=ee1e913)", + "spirv_headers 1.5.0 (git+https://github.com/gfx-rs/rspirv.git?rev=719cf08)", ] [[package]] @@ -2348,6 +2348,7 @@ dependencies = [ name = "spirv-std" version = "0.4.0-alpha.5" dependencies = [ + "bitflags", "num-traits", "spirv-std-macros", ] @@ -2395,7 +2396,7 @@ dependencies = [ [[package]] name = "spirv_headers" version = "1.5.0" -source = "git+https://github.com/gfx-rs/rspirv.git?rev=ee1e913#ee1e9135845409b2a096d880286c865c4e2ac3d6" +source = "git+https://github.com/gfx-rs/rspirv.git?rev=719cf08#719cf08e4af0436242707479e3509add5ec3d514" dependencies = [ "bitflags", "num-traits", diff --git a/crates/rustc_codegen_spirv/Cargo.toml b/crates/rustc_codegen_spirv/Cargo.toml index b72758dd14..974abb49f0 100644 --- a/crates/rustc_codegen_spirv/Cargo.toml +++ b/crates/rustc_codegen_spirv/Cargo.toml @@ -37,7 +37,7 @@ syn = { version = "1", features = ["visit", "visit-mut"] } # Normal dependencies. bimap = "0.6" indexmap = "1.6.0" -rspirv = { git = "https://github.com/gfx-rs/rspirv.git", rev = "ee1e913" } +rspirv = { git = "https://github.com/gfx-rs/rspirv.git", rev = "719cf08" } rustc-demangle = "0.1.18" sanitize-filename = "0.3" serde = { version = "1.0", features = ["derive"] } diff --git a/crates/rustc_codegen_spirv/src/abi.rs b/crates/rustc_codegen_spirv/src/abi.rs index 8da069d8d3..3aaa9bd4f8 100644 --- a/crates/rustc_codegen_spirv/src/abi.rs +++ b/crates/rustc_codegen_spirv/src/abi.rs @@ -788,6 +788,9 @@ fn trans_intrinsic_type<'tcx>( } Ok(SpirvType::Sampler.def(span, cx)) } + IntrinsicType::AccelerationStructureKhr => { + Ok(SpirvType::AccelerationStructureKhr.def(span, cx)) + } IntrinsicType::SampledImage => { // see SpirvType::sizeof if ty.size != Size::from_bytes(4) { diff --git a/crates/rustc_codegen_spirv/src/attr.rs b/crates/rustc_codegen_spirv/src/attr.rs index dbf084815a..75d86053cd 100644 --- a/crates/rustc_codegen_spirv/src/attr.rs +++ b/crates/rustc_codegen_spirv/src/attr.rs @@ -71,6 +71,7 @@ pub enum IntrinsicType { access_qualifier: Option, }, Sampler, + AccelerationStructureKhr, SampledImage, } diff --git a/crates/rustc_codegen_spirv/src/builder/builder_methods.rs b/crates/rustc_codegen_spirv/src/builder/builder_methods.rs index d7c0964426..3081976df8 100644 --- a/crates/rustc_codegen_spirv/src/builder/builder_methods.rs +++ b/crates/rustc_codegen_spirv/src/builder/builder_methods.rs @@ -236,6 +236,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { SpirvType::Sampler => self.fatal("cannot memset sampler"), SpirvType::SampledImage { .. } => self.fatal("cannot memset sampled image"), SpirvType::InterfaceBlock { .. } => self.fatal("cannot memset interface block"), + SpirvType::AccelerationStructureKhr => { + self.fatal("cannot memset acceleration structure") + } } } @@ -293,6 +296,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { SpirvType::Sampler => self.fatal("cannot memset sampler"), SpirvType::SampledImage { .. } => self.fatal("cannot memset sampled image"), SpirvType::InterfaceBlock { .. } => self.fatal("cannot memset interface block"), + SpirvType::AccelerationStructureKhr => { + self.fatal("cannot memset acceleration structure") + } } } diff --git a/crates/rustc_codegen_spirv/src/codegen_cx/constant.rs b/crates/rustc_codegen_spirv/src/codegen_cx/constant.rs index e9f9df1283..b6d8f3228d 100644 --- a/crates/rustc_codegen_spirv/src/codegen_cx/constant.rs +++ b/crates/rustc_codegen_spirv/src/codegen_cx/constant.rs @@ -530,6 +530,10 @@ impl<'tcx> CodegenCx<'tcx> { .tcx .sess .fatal("Cannot create a constant interface block value"), + SpirvType::AccelerationStructureKhr => self + .tcx + .sess + .fatal("Cannot create a constant acceleration structure"), } } } diff --git a/crates/rustc_codegen_spirv/src/codegen_cx/entry.rs b/crates/rustc_codegen_spirv/src/codegen_cx/entry.rs index 9070c65853..6e6d00c6a6 100644 --- a/crates/rustc_codegen_spirv/src/codegen_cx/entry.rs +++ b/crates/rustc_codegen_spirv/src/codegen_cx/entry.rs @@ -176,7 +176,10 @@ impl<'tcx> CodegenCx<'tcx> { let spirv_ty = self.layout_of(value_ty).spirv_type(hir_param.ty_span, self); // Some types automatically specify a storage class. Compute that here. let inferred_storage_class_from_ty = match self.lookup_type(spirv_ty) { - SpirvType::Image { .. } | SpirvType::Sampler | SpirvType::SampledImage { .. } => { + SpirvType::Image { .. } + | SpirvType::Sampler + | SpirvType::SampledImage { .. } + | SpirvType::AccelerationStructureKhr => { if is_ref { Some(StorageClass::UniformConstant) } else { diff --git a/crates/rustc_codegen_spirv/src/codegen_cx/type_.rs b/crates/rustc_codegen_spirv/src/codegen_cx/type_.rs index 37ab330e37..4424a5f6c1 100644 --- a/crates/rustc_codegen_spirv/src/codegen_cx/type_.rs +++ b/crates/rustc_codegen_spirv/src/codegen_cx/type_.rs @@ -175,9 +175,11 @@ impl<'tcx> BaseTypeMethods<'tcx> for CodegenCx<'tcx> { SpirvType::Function { .. } => TypeKind::Function, // HACK(eddyb) this is probably the closest `TypeKind` (which is still // very much LLVM-specific, sadly) has to offer to "resource handle". - SpirvType::Image { .. } | SpirvType::Sampler | SpirvType::SampledImage { .. } => { - TypeKind::Token - } + | SpirvType::Image { .. } + | SpirvType::Sampler + | SpirvType::SampledImage { .. } + | SpirvType::AccelerationStructureKhr + => TypeKind::Token, } } fn type_ptr_to(&self, ty: Self::Type) -> Self::Type { diff --git a/crates/rustc_codegen_spirv/src/linker/new_structurizer.rs b/crates/rustc_codegen_spirv/src/linker/new_structurizer.rs index 860e2200b5..7313d257fd 100644 --- a/crates/rustc_codegen_spirv/src/linker/new_structurizer.rs +++ b/crates/rustc_codegen_spirv/src/linker/new_structurizer.rs @@ -168,7 +168,12 @@ impl Structurizer<'_> { let block_id = self.func.blocks()[block].label_id().unwrap(); let terminator = self.func.blocks()[block].instructions.last().unwrap(); let mut region = match terminator.class.opcode { - Op::Return | Op::ReturnValue | Op::Kill | Op::Unreachable => Region { + Op::Return + | Op::ReturnValue + | Op::Kill + | Op::IgnoreIntersectionKHR + | Op::TerminateRayKHR + | Op::Unreachable => Region { merge: block, merge_id: block_id, exits: indexmap! {}, diff --git a/crates/rustc_codegen_spirv/src/linker/simple_passes.rs b/crates/rustc_codegen_spirv/src/linker/simple_passes.rs index b7e4676126..5a4c5959f6 100644 --- a/crates/rustc_codegen_spirv/src/linker/simple_passes.rs +++ b/crates/rustc_codegen_spirv/src/linker/simple_passes.rs @@ -86,7 +86,12 @@ pub fn outgoing_edges(block: &Block) -> impl Iterator + '_ { Op::Branch => (0..1).step_by(1), Op::BranchConditional => (1..3).step_by(1), Op::Switch => (1..terminator.operands.len()).step_by(2), - Op::Return | Op::ReturnValue | Op::Kill | Op::Unreachable => (0..0).step_by(1), + Op::Return + | Op::ReturnValue + | Op::Kill + | Op::Unreachable + | Op::IgnoreIntersectionKHR + | Op::TerminateRayKHR => (0..0).step_by(1), _ => panic!("Invalid block terminator: {:?}", terminator), }; operand_indices.map(move |i| terminator.operands[i].unwrap_id_ref()) diff --git a/crates/rustc_codegen_spirv/src/spirv_type.rs b/crates/rustc_codegen_spirv/src/spirv_type.rs index 9a7e1d42b8..b94a8bf04f 100644 --- a/crates/rustc_codegen_spirv/src/spirv_type.rs +++ b/crates/rustc_codegen_spirv/src/spirv_type.rs @@ -85,6 +85,8 @@ pub enum SpirvType { InterfaceBlock { inner_type: Word, }, + + AccelerationStructureKhr, } impl SpirvType { @@ -248,6 +250,7 @@ impl SpirvType { access_qualifier, ), Self::Sampler => cx.emit_global().type_sampler(), + Self::AccelerationStructureKhr => cx.emit_global().type_acceleration_structure_khr(), Self::SampledImage { image_type } => cx.emit_global().type_sampled_image(image_type), Self::InterfaceBlock { inner_type } => { @@ -347,7 +350,10 @@ impl SpirvType { cx.lookup_type(element).sizeof(cx)? * cx.builder.lookup_const_u64(count).unwrap() } Self::Pointer { .. } => cx.tcx.data_layout.pointer_size, - Self::Image { .. } | Self::Sampler | Self::SampledImage { .. } => Size::from_bytes(4), + Self::Image { .. } + | Self::AccelerationStructureKhr + | Self::Sampler + | Self::SampledImage { .. } => Size::from_bytes(4), Self::InterfaceBlock { inner_type } => cx.lookup_type(inner_type).sizeof(cx)?, }; @@ -375,9 +381,10 @@ impl SpirvType { cx.lookup_type(element).alignof(cx) } Self::Pointer { .. } => cx.tcx.data_layout.pointer_align.abi, - Self::Image { .. } | Self::Sampler | Self::SampledImage { .. } => { - Align::from_bytes(4).unwrap() - } + Self::Image { .. } + | Self::AccelerationStructureKhr + | Self::Sampler + | Self::SampledImage { .. } => Align::from_bytes(4).unwrap(), Self::InterfaceBlock { inner_type } => cx.lookup_type(inner_type).alignof(cx), } @@ -516,12 +523,12 @@ impl fmt::Debug for SpirvTypePrinter<'_, '_> { .field("id", &self.id) .field("image_type", &self.cx.debug_type(image_type)) .finish(), - SpirvType::InterfaceBlock { inner_type } => f .debug_struct("InterfaceBlock") .field("id", &self.id) .field("inner_type", &self.cx.debug_type(inner_type)) .finish(), + SpirvType::AccelerationStructureKhr => f.debug_struct("AccelerationStructure").finish(), }; { let mut debug_stack = DEBUG_STACK.lock().unwrap(); @@ -671,12 +678,12 @@ impl SpirvTypePrinter<'_, '_> { .debug_struct("SampledImage") .field("image_type", &self.cx.debug_type(image_type)) .finish(), - SpirvType::InterfaceBlock { inner_type } => { f.write_str("interface block { ")?; ty(self.cx, stack, f, inner_type)?; f.write_str(" }") } + SpirvType::AccelerationStructureKhr => f.write_str("AccelerationStructureKhr"), } } } diff --git a/crates/rustc_codegen_spirv/src/spirv_type_constraints.rs b/crates/rustc_codegen_spirv/src/spirv_type_constraints.rs index 17edcdc84f..5519a77759 100644 --- a/crates/rustc_codegen_spirv/src/spirv_type_constraints.rs +++ b/crates/rustc_codegen_spirv/src/spirv_type_constraints.rs @@ -727,7 +727,7 @@ pub fn instruction_signatures(op: Op) -> Option<&'static [InstSig<'static>]> { | Op::ExecuteCallableKHR | Op::ConvertUToAccelerationStructureKHR | Op::IgnoreIntersectionKHR - | Op::TerminateRayKHR => reserved!(SPV_KHR_ray_tracing), + | Op::TerminateRayKHR => {} // SPV_KHR_ray_query Op::TypeRayQueryKHR | Op::RayQueryInitializeKHR @@ -735,7 +735,7 @@ pub fn instruction_signatures(op: Op) -> Option<&'static [InstSig<'static>]> { | Op::RayQueryGenerateIntersectionKHR | Op::RayQueryConfirmIntersectionKHR | Op::RayQueryProceedKHR - | Op::RayQueryGetIntersectionTypeKHR => reserved!(SPV_KHR_ray_query), + | Op::RayQueryGetIntersectionTypeKHR => {} // SPV_AMD_shader_fragment_mask Op::FragmentMaskFetchAMD | Op::FragmentFetchAMD => reserved!(SPV_AMD_shader_fragment_mask), // SPV_KHR_shader_clock @@ -748,7 +748,7 @@ pub fn instruction_signatures(op: Op) -> Option<&'static [InstSig<'static>]> { | Op::TerminateRayNV | Op::TraceNV | Op::TypeAccelerationStructureNV - | Op::ExecuteCallableNV => reserved!(SPV_NV_ray_tracing), + | Op::ExecuteCallableNV => {} // SPV_NV_cooperative_matrix Op::TypeCooperativeMatrixNV | Op::CooperativeMatrixLoadNV diff --git a/crates/rustc_codegen_spirv/src/symbols.rs b/crates/rustc_codegen_spirv/src/symbols.rs index 47e1f2f6fa..abaccb5c55 100644 --- a/crates/rustc_codegen_spirv/src/symbols.rs +++ b/crates/rustc_codegen_spirv/src/symbols.rs @@ -119,21 +119,20 @@ const BUILTINS: &[(&str, BuiltIn)] = { ("bary_coord_no_persp_nv", BaryCoordNoPerspNV), ("frag_size_ext", FragSizeEXT), ("frag_invocation_count_ext", FragInvocationCountEXT), - ("launch_id_nv", LaunchIdNV), - ("launch_size_nv", LaunchSizeNV), - ("world_ray_origin_nv", WorldRayOriginNV), - ("world_ray_direction_nv", WorldRayDirectionNV), - ("object_ray_origin_nv", ObjectRayOriginNV), - ("object_ray_direction_nv", ObjectRayDirectionNV), - ("ray_tmin_nv", RayTminNV), - ("ray_tmax_nv", RayTmaxNV), - ("instance_custom_index_nv", InstanceCustomIndexNV), - ("object_to_world_nv", ObjectToWorldNV), - ("world_to_object_nv", WorldToObjectNV), - ("hit_t_nv", HitTNV), - ("hit_kind_nv", HitKindNV), - ("incoming_ray_flags_nv", IncomingRayFlagsNV), - ("ray_geometry_index_khr", RayGeometryIndexKHR), + ("launch_id", BuiltIn::LaunchIdKHR), + ("launch_size", BuiltIn::LaunchSizeKHR), + ("instance_custom_index", BuiltIn::InstanceCustomIndexKHR), + ("ray_geometry_index", BuiltIn::RayGeometryIndexKHR), + ("world_ray_origin", BuiltIn::WorldRayOriginKHR), + ("world_ray_direction", BuiltIn::WorldRayDirectionKHR), + ("object_ray_origin", BuiltIn::ObjectRayOriginKHR), + ("object_ray_direction", BuiltIn::ObjectRayDirectionKHR), + ("ray_tmin", BuiltIn::RayTminKHR), + ("ray_tmax", BuiltIn::RayTmaxKHR), + ("object_to_world", BuiltIn::ObjectToWorldKHR), + ("world_to_object", BuiltIn::WorldToObjectKHR), + ("hit_kind", BuiltIn::HitKindKHR), + ("incoming_ray_flags", BuiltIn::IncomingRayFlagsKHR), ("warps_per_sm_nv", WarpsPerSMNV), ("sm_count_nv", SMCountNV), ("warp_id_nv", WarpIDNV), @@ -157,21 +156,15 @@ const STORAGE_CLASSES: &[(&str, StorageClass)] = { ("atomic_counter", AtomicCounter), ("image", Image), ("storage_buffer", StorageBuffer), - ("callable_data_khr", StorageClass::CallableDataKHR), + ("callable_data", StorageClass::CallableDataKHR), ( - "incoming_callable_data_khr", + "incoming_callable_data", StorageClass::IncomingCallableDataKHR, ), - ("ray_payload_khr", StorageClass::RayPayloadKHR), - ("hit_attribute_khr", StorageClass::HitAttributeKHR), - ( - "incoming_ray_payload_khr", - StorageClass::IncomingRayPayloadKHR, - ), - ( - "shader_record_buffer_khr", - StorageClass::ShaderRecordBufferKHR, - ), + ("ray_payload", StorageClass::RayPayloadKHR), + ("hit_attribute", StorageClass::HitAttributeKHR), + ("incoming_ray_payload", StorageClass::IncomingRayPayloadKHR), + ("shader_record_buffer", StorageClass::ShaderRecordBufferKHR), ("physical_storage_buffer", PhysicalStorageBuffer), ] }; @@ -188,12 +181,12 @@ const EXECUTION_MODELS: &[(&str, ExecutionModel)] = { ("kernel", Kernel), ("task_nv", TaskNV), ("mesh_nv", MeshNV), - ("ray_generation_nv", RayGenerationNV), - ("intersection_nv", IntersectionNV), - ("any_hit_nv", AnyHitNV), - ("closest_hit_nv", ClosestHitNV), - ("miss_nv", MissNV), - ("callable_nv", CallableNV), + ("ray_generation", ExecutionModel::RayGenerationKHR), + ("intersection", ExecutionModel::IntersectionKHR), + ("any_hit", ExecutionModel::AnyHitKHR), + ("closest_hit", ExecutionModel::ClosestHitKHR), + ("miss", ExecutionModel::MissKHR), + ("callable", ExecutionModel::CallableKHR), ] }; @@ -324,6 +317,10 @@ impl Symbols { "sampler", SpirvAttribute::IntrinsicType(IntrinsicType::Sampler), ), + ( + "acceleration_structure", + SpirvAttribute::IntrinsicType(IntrinsicType::AccelerationStructureKhr), + ), ("block", SpirvAttribute::Block), ("flat", SpirvAttribute::Flat), ("invariant", SpirvAttribute::Invariant), diff --git a/crates/spirv-std/Cargo.toml b/crates/spirv-std/Cargo.toml index be30d94c05..83a0808f1c 100644 --- a/crates/spirv-std/Cargo.toml +++ b/crates/spirv-std/Cargo.toml @@ -8,6 +8,7 @@ repository = "https://github.com/EmbarkStudios/rust-gpu" description = "Standard functions and types for SPIR-V" [dependencies] +bitflags = "1.2.1" num-traits = { version = "0.2.14", default-features = false, features = ["libm"] } spirv-std-macros = { path = "../spirv-std-macros", version = "0.4.0-alpha.0" } diff --git a/crates/spirv-std/src/arch.rs b/crates/spirv-std/src/arch.rs index 7c3ed1d1db..b4ee3bf13c 100644 --- a/crates/spirv-std/src/arch.rs +++ b/crates/spirv-std/src/arch.rs @@ -10,12 +10,14 @@ mod arithmetic; mod barrier; mod derivative; mod primitive; +mod ray_tracing; pub use arithmetic::*; #[cfg(feature = "const-generics")] pub use barrier::*; pub use derivative::*; pub use primitive::*; +pub use ray_tracing::*; /// Result is true if any component of `vector` is true, otherwise result is /// false. diff --git a/crates/spirv-std/src/arch/ray_tracing.rs b/crates/spirv-std/src/arch/ray_tracing.rs new file mode 100644 index 0000000000..55738f9470 --- /dev/null +++ b/crates/spirv-std/src/arch/ray_tracing.rs @@ -0,0 +1,85 @@ +/// Reports an intersection back to the traversal infrastructure. +/// +/// If the intersection occurred within the current ray interval, the +/// intersection confirmation is performed (see the API specification for more +/// details). If the value of Hit falls outside the current ray interval, the +/// hit is rejected. +/// +/// Returns True if the hit was accepted by the ray interval and the intersection was confirmed. Returns False otherwise. +/// +/// - `hit` is the floating point parametric value along ray for the intersection. +/// - `hit_kind` is the integer hit kind reported back to other shaders and +/// accessible by the `hit kind` builtin. +/// +/// This instruction is allowed only in IntersectionKHR execution model. +/// +/// This instruction is a shader call instruction which may invoke shaders with +/// the `any_hit` execution model. +#[spirv_std_macros::gpu_only] +#[doc(alias = "OpReportIntersectionKHR")] +#[inline] +pub unsafe fn report_intersection(hit: f32, hit_kind: u32) -> bool { + let result: u32; + + asm! { + "%bool = OpTypeBool", + "%u32 = OpTypeInt 32 0", + "%zero = OpConstant %u32 0", + "%one = OpConstant %u32 1", + "%result = OpReportIntersectionKHR %bool {hit} {hit_kind}", + "{result} = OpSelect %u32 %result %one %zero", + result = out(reg) result, + hit = in(reg) hit, + hit_kind = in(reg) hit_kind, + }; + + result != 0 +} + +/// Ignores the current potential intersection, terminating the invocation that +/// executes it, and continues the ray traversal. This instruction is allowed +/// only in `any_hit` execution model. This instruction must be the last +/// instruction in a block. +#[spirv_std_macros::gpu_only] +#[doc(alias = "OpIgnoreIntersectionKHR")] +#[inline] +pub unsafe fn ignore_intersection() { + asm!("OpIgnoreIntersectionKHR", "%unused = OpLabel") +} + +/// Terminates the invocation that executes it, stops the ray traversal, accepts +/// the current hit, and invokes the `closest_hit` execution model +/// (if active). This instruction is allowed only in the `any_hit` +/// execution model. This instruction must be the last instruction in a block. +#[spirv_std_macros::gpu_only] +#[doc(alias = "OpTerminateRayKHR")] +#[inline] +pub unsafe fn terminate_ray() { + asm!("OpTerminateRayKHR", "%unused = OpLabel") +} + +/// Invoke a callable shader. +/// +/// - `INDEX` is the index into the SBT table to select callable shader +/// to execute. +/// - `data` is a pointer to the callable data to pass into the called shader. +/// `data` must have a storage class of `callable_data` +/// or `incoming_callable_data`. +/// +/// This instruction is allowed only in `ray_generation`, `closest_hit`, +/// `miss` and `callable` execution models. +/// +/// This instruction is a shader call instruction which will invoke a shader +/// with the `callable` execution model. +#[spirv_std_macros::gpu_only] +#[doc(alias = "OpExecuteCallableKHR")] +#[inline] +pub unsafe fn execute_callable(data: &T) { + asm! { + "%u32 = OpTypeInt 32 0", + "%id = OpConstant %u32 {id}", + "OpExecuteCallableKHR %id {data}", + id = const ID, + data = in(reg) data, + }; +} diff --git a/crates/spirv-std/src/lib.rs b/crates/spirv-std/src/lib.rs index 5d5f7ebd72..c1f0b685cc 100644 --- a/crates/spirv-std/src/lib.rs +++ b/crates/spirv-std/src/lib.rs @@ -78,6 +78,7 @@ pub mod arch; pub mod float; pub mod integer; pub mod memory; +pub mod ray_tracing; pub mod scalar; pub(crate) mod sealed; mod textures; diff --git a/crates/spirv-std/src/ray_tracing.rs b/crates/spirv-std/src/ray_tracing.rs new file mode 100644 index 0000000000..9ae62a2e1e --- /dev/null +++ b/crates/spirv-std/src/ray_tracing.rs @@ -0,0 +1,161 @@ +//! Ray-tracing data types +use crate::vector::Vector; + +/// An acceleration structure type which is an opaque reference to an +/// acceleration structure handle as defined in the client API specification. +#[spirv(acceleration_structure)] +#[derive(Copy, Clone)] +pub struct AccelerationStructure { + pub(crate) _private: u32, +} + +impl AccelerationStructure { + /// Converts a 64-bit integer into an [`AccelerationStructureKHR`]. + /// # Safety + /// The 64-bit integer must point to a valid acceleration structure. + #[spirv_std_macros::gpu_only] + #[doc(alias = "OpConvertUToAccelerationStructureKHR")] + #[allow(clippy::empty_loop)] + #[inline] + pub unsafe fn from_u64(id: u64) -> AccelerationStructure { + // Since we can't represent an uninitalized opaque type in Rust at the + // moment, we need to create and return the acceleration structure entirely + // in assembly. + asm! { + "%ret = OpTypeAccelerationStructureKHR", + "%result = OpConvertUToAccelerationStructureKHR %ret {id}", + "OpReturnValue %result", + "%blah = OpLabel", + id = in(reg) id, + } + loop {} + } + + /// Converts a vector of two 32 bit integers into an [`AccelerationStructureKHR`]. + /// # Safety + /// The combination must point to a valid acceleration structure. + #[spirv_std_macros::gpu_only] + #[doc(alias = "OpConvertUToAccelerationStructureKHR")] + #[allow(clippy::empty_loop)] + #[inline] + pub unsafe fn from_vec(id: impl Vector) -> AccelerationStructure { + // Since we can't represent an uninitalized opaque type in Rust at the + // moment, we need to create and return the acceleration structure entirely + // in assembly. + asm! { + "%ret = OpTypeAccelerationStructureKHR", + "%id = OpLoad _ {id}", + "%result = OpConvertUToAccelerationStructureKHR %ret %id", + "OpReturnValue %result", + "%blah = OpLabel", + id = in(reg) &id, + } + loop {} + } + + #[spirv_std_macros::gpu_only] + /// Trace a ray into the acceleration structure. + /// + /// - `structure` is the descriptor for the acceleration structure to trace into. + /// - `ray_flags` contains one or more of the Ray Flag values. + /// - `cull_mask` is the mask to test against the instance mask. Only the 8 + /// least-significant bits of are used by this instruction - other bits + /// are ignored. + /// - `sbt_offset` and `sbt_stride` control indexing into the SBT (Shader + /// Binding Table) for hit shaders called from this trace. Only the 4 + /// least-significant bits of `sbt_offset` and `sbt_stride` are used by this + /// instruction - other bits are ignored. + /// - `miss_index` is the index of the miss shader to be called from this + /// trace call. Only the 16 least-significant bits are used by this + /// instruction - other bits are ignored. + /// - `ray_origin`, `ray_tmin`, `ray_direction`, and `ray_tmax` control the + /// basic parameters of the ray to be traced. + /// + /// - `payload` is a pointer to the ray payload structure to use for this trace. + /// `payload` must have a storage class of `ray_payload` + /// or `incoming_ray_payload`. + /// + /// This instruction is allowed only in `ray_generation`, `closest_hit` and + /// `miss` execution models. + /// + /// This instruction is a shader call instruction which may invoke shaders with + /// the `intersection`, `any_hit`, `closest_hit`, and `miss` + /// execution models. + #[doc(alias = "OpTraceRayKHR")] + #[inline] + #[allow(clippy::too_many_arguments)] + pub unsafe fn trace_ray( + &self, + ray_flags: RayFlags, + cull_mask: i32, + sbt_offset: i32, + sbt_stride: i32, + miss_index: i32, + ray_origin: impl Vector, + ray_tmin: f32, + ray_direction: impl Vector, + ray_tmax: f32, + payload: &mut T, + ) { + asm! { + "%ray_origin = OpLoad _ {ray_origin}", + "%ray_direction = OpLoad _ {ray_direction}", + "OpTraceRayKHR \ + {acceleration_structure} \ + {ray_flags} \ + {cull_mask} \ + {sbt_offset} \ + {sbt_stride} \ + {miss_index} \ + %ray_origin \ + {ray_tmin} \ + %ray_direction \ + {ray_tmax} \ + {payload}", + acceleration_structure = in(reg) self, + ray_flags = in(reg) ray_flags.bits(), + cull_mask = in(reg) cull_mask, + sbt_offset = in(reg) sbt_offset, + sbt_stride = in(reg) sbt_stride, + miss_index = in(reg) miss_index, + ray_origin = in(reg) &ray_origin, + ray_tmin = in(reg) ray_tmin, + ray_direction = in(reg) &ray_direction, + ray_tmax = in(reg) ray_tmax, + payload = in(reg) payload, + } + } +} + +bitflags::bitflags! { + /// Flags controlling the properties of an OpTraceRayKHR instruction. + /// Despite being a mask and allowing multiple bits to be combined, it is + /// invalid for more than one of these four bits to be set: `OPAQUE`, + /// `NO_OPAQUE`, `CULL_OPAQUE`, `CULL_NO_OPAQUE`, only one of + /// `CULL_BACK_FACING_TRIANGLES` and `CULL_FRONT_FACING_TRIANGLES` may + /// be set. + pub struct RayFlags: u32 { + /// No flags specified. + const NONE = 0; + /// Force all intersections with the trace to be opaque. + const OPAQUE = 1; + /// Force all intersections with the trace to be non-opaque. + const NO_OPAQUE = 2; + /// Accept the first hit discovered. + const TERMINATE_ON_FIRST_HIT = 4; + /// Do not execute a closest hit shader. + const SKIP_CLOSEST_HIT_SHADER = 8; + /// Do not intersect with the back face of triangles. + const CULL_BACK_FACING_TRIANGLES = 16; + /// Do not intersect with the front face of triangles. + const CULL_FRONT_FACING_TRIANGLES = 32; + /// Do not intersect with opaque geometry. + const CULL_OPAQUE = 64; + /// Do not intersect with non-opaque geometry. + const CULL_NO_OPAQUE = 128; + /// Do not intersect with any triangle geometries. + const SKIP_TRIANGLES = 256; + /// Do not intersect with any AABB (Axis Aligned Bounding Box) geometries. + const SKIP_AABBS = 512; + } +} diff --git a/tests/ui/arch/convert_u_to_acceleration_structure_khr.rs b/tests/ui/arch/convert_u_to_acceleration_structure_khr.rs new file mode 100644 index 0000000000..8c2356aedc --- /dev/null +++ b/tests/ui/arch/convert_u_to_acceleration_structure_khr.rs @@ -0,0 +1,39 @@ +// build-pass + +#[spirv(ray_generation)] +pub fn main(#[spirv(ray_payload)] payload: &mut glam::Vec3) { + unsafe { + asm!(r#"OpExtension "SPV_KHR_ray_tracing""#); + asm!("OpCapability RayTracingKHR"); + + let handle = spirv_std::ray_tracing::AccelerationStructure::from_u64(0xffff_ffff); + let handle2 = + spirv_std::ray_tracing::AccelerationStructure::from_vec(glam::UVec2::new(0, 0)); + + handle.trace_ray( + spirv_std::ray_tracing::RayFlags::NONE, + 0, + 0, + 0, + 0, + glam::vec3(1.0, 2.0, 3.0), + 0.5, + glam::vec3(3.0, 2.0, 1.0), + 1.0, + payload, + ); + + handle2.trace_ray( + spirv_std::ray_tracing::RayFlags::NONE, + 0, + 0, + 0, + 0, + glam::vec3(1.0, 2.0, 3.0), + 0.5, + glam::vec3(3.0, 2.0, 1.0), + 1.0, + payload, + ); + } +} diff --git a/tests/ui/arch/execute_callable.rs b/tests/ui/arch/execute_callable.rs new file mode 100644 index 0000000000..81c4fee848 --- /dev/null +++ b/tests/ui/arch/execute_callable.rs @@ -0,0 +1,16 @@ +// build-pass + +#[spirv(ray_generation)] +// Rustfmt will eat long attributes (https://github.com/rust-lang/rustfmt/issues/4579) +#[rustfmt::skip] +pub fn main( + #[spirv(descriptor_set = 0, binding = 0)] + acceleration_structure: &spirv_std::ray_tracing::AccelerationStructure, + #[spirv(incoming_callable_data)] payload: &glam::Vec3, +) { + unsafe { + asm!(r#"OpExtension "SPV_KHR_ray_tracing""#); + asm!("OpCapability RayTracingKHR"); + spirv_std::arch::execute_callable::<_, 5>(payload); + } +} diff --git a/tests/ui/arch/ignore_intersection_khr.rs b/tests/ui/arch/ignore_intersection_khr.rs new file mode 100644 index 0000000000..24342e87d9 --- /dev/null +++ b/tests/ui/arch/ignore_intersection_khr.rs @@ -0,0 +1,10 @@ +// build-pass + +#[spirv(any_hit)] +pub fn main() { + unsafe { + asm!(r#"OpExtension "SPV_KHR_ray_tracing""#); + asm!("OpCapability RayTracingKHR"); + spirv_std::arch::ignore_intersection(); + } +} diff --git a/tests/ui/arch/report_intersection_khr.rs b/tests/ui/arch/report_intersection_khr.rs new file mode 100644 index 0000000000..d63bc90e07 --- /dev/null +++ b/tests/ui/arch/report_intersection_khr.rs @@ -0,0 +1,10 @@ +// build-pass + +#[spirv(intersection)] +pub fn main() { + unsafe { + asm!(r#"OpExtension "SPV_KHR_ray_tracing""#); + asm!("OpCapability RayTracingKHR"); + spirv_std::arch::report_intersection(2.0, 4); + } +} diff --git a/tests/ui/arch/terminate_ray_khr.rs b/tests/ui/arch/terminate_ray_khr.rs new file mode 100644 index 0000000000..2caac13c6e --- /dev/null +++ b/tests/ui/arch/terminate_ray_khr.rs @@ -0,0 +1,10 @@ +// build-pass + +#[spirv(any_hit)] +pub fn main() { + unsafe { + asm!(r#"OpExtension "SPV_KHR_ray_tracing""#); + asm!("OpCapability RayTracingKHR"); + spirv_std::arch::terminate_ray(); + } +} diff --git a/tests/ui/arch/trace_ray_khr.rs b/tests/ui/arch/trace_ray_khr.rs new file mode 100644 index 0000000000..a4265a1a89 --- /dev/null +++ b/tests/ui/arch/trace_ray_khr.rs @@ -0,0 +1,27 @@ +// build-pass + +#[spirv(ray_generation)] +// Rustfmt will eat long attributes (https://github.com/rust-lang/rustfmt/issues/4579) +#[rustfmt::skip] +pub fn main( + #[spirv(descriptor_set = 0, binding = 0)] + acceleration_structure: &spirv_std::ray_tracing::AccelerationStructure, + #[spirv(ray_payload)] payload: &mut glam::Vec3, +) { + unsafe { + asm!(r#"OpExtension "SPV_KHR_ray_tracing""#); + asm!("OpCapability RayTracingKHR"); + acceleration_structure.trace_ray( + spirv_std::ray_tracing::RayFlags::NONE, + 0, + 0, + 0, + 0, + glam::vec3(1.0, 2.0, 3.0), + 0.5, + glam::vec3(3.0, 2.0, 1.0), + 1.0, + payload, + ); + } +}