Add support for SPV_KHR_ray_tracing (#563)

* Add support for SPV_KHR_ray_tracing

* Update spirv_type_constraints.rs

* Update spirv_type_constraints.rs

* Update spirv_type_constraints.rs
This commit is contained in:
XAMPPRocky 2021-04-16 15:59:11 +02:00 committed by GitHub
parent bb7adc912f
commit a42a9f20e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 478 additions and 72 deletions

43
Cargo.lock generated
View File

@ -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",

View File

@ -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"] }

View File

@ -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) {

View File

@ -71,6 +71,7 @@ pub enum IntrinsicType {
access_qualifier: Option<AccessQualifier>,
},
Sampler,
AccelerationStructureKhr,
SampledImage,
}

View File

@ -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")
}
}
}

View File

@ -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"),
}
}
}

View File

@ -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 {

View File

@ -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 {

View File

@ -118,8 +118,9 @@ struct Region {
/// After structurizing a region, all paths through it must lead to a single
/// "merge" block (i.e. `merge` post-dominates the entire region).
/// The `merge` block must be terminated by one of `OpReturn`, `OpReturnValue`,
/// `OpKill`, or `OpUnreachable`. If `exits` isn't empty, `merge` will
/// receive an `OpBranch` from its parent region (to an outer merge block).
/// `OpKill`, `OpIgnoreIntersectionKHR`, `OpTerminateRayKHR` or
/// `OpUnreachable`. If `exits` isn't empty, `merge` will receive an
/// `OpBranch` from its parent region (to an outer merge block).
merge: BlockIdx,
merge_id: BlockId,
@ -168,7 +169,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! {},

View File

@ -86,7 +86,12 @@ pub fn outgoing_edges(block: &Block) -> impl Iterator<Item = Word> + '_ {
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())

View File

@ -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"),
}
}
}

View File

@ -727,7 +727,10 @@ 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 => {
// NOTE(eddyb) we actually use these despite not being in the standard yet.
// reserved!(SPV_KHR_ray_tracing)
}
// SPV_KHR_ray_query
Op::TypeRayQueryKHR
| Op::RayQueryInitializeKHR
@ -735,7 +738,10 @@ 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 => {
// NOTE(eddyb) we actually use these despite not being in the standard yet.
// reserved!(SPV_KHR_ray_query)
}
// SPV_AMD_shader_fragment_mask
Op::FragmentMaskFetchAMD | Op::FragmentFetchAMD => reserved!(SPV_AMD_shader_fragment_mask),
// SPV_KHR_shader_clock
@ -748,7 +754,10 @@ 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 => {
// NOTE(eddyb) Some KHR variants are aliased to the the NV instructions.
// reserved!(SPV_NV_ray_tracing)
}
// SPV_NV_cooperative_matrix
Op::TypeCooperativeMatrixNV
| Op::CooperativeMatrixLoadNV

View File

@ -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),

View File

@ -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" }

View File

@ -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.

View File

@ -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<T, const ID: usize>(data: &T) {
asm! {
"%u32 = OpTypeInt 32 0",
"%id = OpConstant %u32 {id}",
"OpExecuteCallableKHR %id {data}",
id = const ID,
data = in(reg) data,
};
}

View File

@ -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;

View File

@ -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<u32, 2>) -> 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<T>(
&self,
ray_flags: RayFlags,
cull_mask: i32,
sbt_offset: i32,
sbt_stride: i32,
miss_index: i32,
ray_origin: impl Vector<f32, 3>,
ray_tmin: f32,
ray_direction: impl Vector<f32, 3>,
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;
}
}

View File

@ -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,
);
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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,
);
}
}