mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
Add ray query types to the IR
This commit is contained in:
@@ -879,6 +879,8 @@ impl<'a, W: Write> Writer<'a, W> {
|
||||
| TypeInner::Struct { .. }
|
||||
| TypeInner::Image { .. }
|
||||
| TypeInner::Sampler { .. }
|
||||
| TypeInner::AccelerationStructure
|
||||
| TypeInner::RayQuery
|
||||
| TypeInner::BindingArray { .. } => {
|
||||
return Err(Error::Custom(format!("Unable to write type {inner:?}")))
|
||||
}
|
||||
|
||||
@@ -194,6 +194,9 @@ impl<'a> Display for TypeContext<'a> {
|
||||
crate::TypeInner::Sampler { comparison: _ } => {
|
||||
write!(out, "{NAMESPACE}::sampler")
|
||||
}
|
||||
crate::TypeInner::AccelerationStructure | crate::TypeInner::RayQuery => {
|
||||
unreachable!("Ray queries are not supported yet");
|
||||
}
|
||||
crate::TypeInner::BindingArray { base, size } => {
|
||||
let base_tyname = Self {
|
||||
handle: base,
|
||||
@@ -485,7 +488,11 @@ impl crate::Type {
|
||||
// composite types are better to be aliased, regardless of the name
|
||||
Ti::Struct { .. } | Ti::Array { .. } => true,
|
||||
// handle types may be different, depending on the global var access, so we always inline them
|
||||
Ti::Image { .. } | Ti::Sampler { .. } | Ti::BindingArray { .. } => false,
|
||||
Ti::Image { .. }
|
||||
| Ti::Sampler { .. }
|
||||
| Ti::AccelerationStructure
|
||||
| Ti::RayQuery
|
||||
| Ti::BindingArray { .. } => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1017,7 +1017,9 @@ impl Writer {
|
||||
| crate::TypeInner::Pointer { .. }
|
||||
| crate::TypeInner::ValuePointer { .. }
|
||||
| crate::TypeInner::Image { .. }
|
||||
| crate::TypeInner::Sampler { .. } => unreachable!(),
|
||||
| crate::TypeInner::Sampler { .. }
|
||||
| crate::TypeInner::AccelerationStructure
|
||||
| crate::TypeInner::RayQuery => unreachable!(),
|
||||
};
|
||||
|
||||
instruction.to_words(&mut self.logical_layout.declarations);
|
||||
|
||||
@@ -2245,6 +2245,8 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
|
||||
class,
|
||||
},
|
||||
ast::Type::Sampler { comparison } => crate::TypeInner::Sampler { comparison },
|
||||
ast::Type::AccelerationStructure => crate::TypeInner::AccelerationStructure,
|
||||
ast::Type::RayQuery => crate::TypeInner::RayQuery,
|
||||
ast::Type::BindingArray { base, size } => {
|
||||
let base = self.resolve_ast_type(base, ctx.reborrow())?;
|
||||
|
||||
|
||||
@@ -206,6 +206,8 @@ impl crate::TypeInner {
|
||||
format!("texture{class_suffix}{dim_suffix}{array_suffix}{type_in_brackets}")
|
||||
}
|
||||
Ti::Sampler { .. } => "sampler".to_string(),
|
||||
Ti::AccelerationStructure => "acceleration_structure".to_string(),
|
||||
Ti::RayQuery => "ray_query".to_string(),
|
||||
Ti::BindingArray { base, size, .. } => {
|
||||
let member_type = &types[base];
|
||||
let base = member_type.name.as_deref().unwrap_or("unknown");
|
||||
|
||||
@@ -229,6 +229,8 @@ pub enum Type<'a> {
|
||||
Sampler {
|
||||
comparison: bool,
|
||||
},
|
||||
AccelerationStructure,
|
||||
RayQuery,
|
||||
BindingArray {
|
||||
base: Handle<Type<'a>>,
|
||||
size: ArraySize<'a>,
|
||||
|
||||
@@ -1367,6 +1367,8 @@ impl Parser {
|
||||
class: crate::ImageClass::Storage { format, access },
|
||||
}
|
||||
}
|
||||
"acceleration_structure" => ast::Type::AccelerationStructure,
|
||||
"ray_query" => ast::Type::RayQuery,
|
||||
_ => return Ok(None),
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -721,6 +721,11 @@ pub enum TypeInner {
|
||||
/// Can be used to sample values from images.
|
||||
Sampler { comparison: bool },
|
||||
|
||||
/// Opaque object representing an acceleration structure of geometry.
|
||||
AccelerationStructure,
|
||||
/// Locally used handle for ray queries.
|
||||
RayQuery,
|
||||
|
||||
/// Array of bindings.
|
||||
///
|
||||
/// A `BindingArray` represents an array where each element draws its value
|
||||
|
||||
@@ -238,7 +238,11 @@ impl Layouter {
|
||||
alignment,
|
||||
}
|
||||
}
|
||||
Ti::Image { .. } | Ti::Sampler { .. } | Ti::BindingArray { .. } => TypeLayout {
|
||||
Ti::Image { .. }
|
||||
| Ti::Sampler { .. }
|
||||
| Ti::AccelerationStructure
|
||||
| Ti::RayQuery
|
||||
| Ti::BindingArray { .. } => TypeLayout {
|
||||
size,
|
||||
alignment: Alignment::ONE,
|
||||
},
|
||||
|
||||
@@ -134,7 +134,11 @@ impl super::TypeInner {
|
||||
count * stride
|
||||
}
|
||||
Self::Struct { span, .. } => span,
|
||||
Self::Image { .. } | Self::Sampler { .. } | Self::BindingArray { .. } => 0,
|
||||
Self::Image { .. }
|
||||
| Self::Sampler { .. }
|
||||
| Self::AccelerationStructure
|
||||
| Self::RayQuery
|
||||
| Self::BindingArray { .. } => 0,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1379,7 +1379,7 @@ impl super::Validator {
|
||||
_ => return Err(ExpressionError::InvalidCastArgument),
|
||||
};
|
||||
let width = convert.unwrap_or(base_width);
|
||||
if !self.check_width(kind, width) {
|
||||
if self.check_width(kind, width).is_err() {
|
||||
return Err(ExpressionError::InvalidCastArgument);
|
||||
}
|
||||
ShaderStages::all()
|
||||
@@ -1390,7 +1390,7 @@ impl super::Validator {
|
||||
&crate::TypeInner::Scalar {
|
||||
kind: kind @ (crate::ScalarKind::Uint | crate::ScalarKind::Sint),
|
||||
width,
|
||||
} => self.check_width(kind, width),
|
||||
} => self.check_width(kind, width).is_ok(),
|
||||
_ => false,
|
||||
};
|
||||
let good = match &module.types[ty].inner {
|
||||
|
||||
@@ -76,7 +76,9 @@ impl super::Validator {
|
||||
| crate::TypeInner::ValuePointer { .. }
|
||||
| crate::TypeInner::Atomic { .. }
|
||||
| crate::TypeInner::Image { .. }
|
||||
| crate::TypeInner::Sampler { .. } => (),
|
||||
| crate::TypeInner::Sampler { .. }
|
||||
| crate::TypeInner::AccelerationStructure
|
||||
| crate::TypeInner::RayQuery => (),
|
||||
crate::TypeInner::Pointer { base, space: _ } => {
|
||||
this_handle.check_dep(base)?;
|
||||
}
|
||||
|
||||
@@ -111,6 +111,8 @@ bitflags::bitflags! {
|
||||
const EARLY_DEPTH_TEST = 0x400;
|
||||
/// Support for [`Builtin::SampleIndex`] and [`Sampling::Sample`].
|
||||
const MULTISAMPLED_SHADING = 0x800;
|
||||
/// Support for ray queries and acceleration structures.
|
||||
const RAY_QUERY = 0x1000;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,6 +240,8 @@ impl crate::TypeInner {
|
||||
Self::Array { .. }
|
||||
| Self::Image { .. }
|
||||
| Self::Sampler { .. }
|
||||
| Self::AccelerationStructure
|
||||
| Self::RayQuery
|
||||
| Self::BindingArray { .. } => false,
|
||||
}
|
||||
}
|
||||
@@ -302,7 +306,7 @@ impl Validator {
|
||||
let con = &constants[handle];
|
||||
match con.inner {
|
||||
crate::ConstantInner::Scalar { width, ref value } => {
|
||||
if !self.check_width(value.scalar_kind(), width) {
|
||||
if self.check_width(value.scalar_kind(), width).is_err() {
|
||||
return Err(ConstantError::InvalidType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,6 +90,8 @@ pub enum Disalignment {
|
||||
|
||||
#[derive(Clone, Debug, thiserror::Error)]
|
||||
pub enum TypeError {
|
||||
#[error("Capability {0:?} is required")]
|
||||
MissingCapability(Capabilities),
|
||||
#[error("The {0:?} scalar width {1} is not supported")]
|
||||
InvalidWidth(crate::ScalarKind, crate::Bytes),
|
||||
#[error("The {0:?} scalar width {1} is not supported for an atomic")]
|
||||
@@ -203,13 +205,35 @@ impl TypeInfo {
|
||||
}
|
||||
|
||||
impl super::Validator {
|
||||
pub(super) const fn check_width(&self, kind: crate::ScalarKind, width: crate::Bytes) -> bool {
|
||||
match kind {
|
||||
fn require_type_capability(&self, capability: Capabilities) -> Result<(), TypeError> {
|
||||
if self.capabilities.contains(capability) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(TypeError::MissingCapability(capability))
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn check_width(
|
||||
&self,
|
||||
kind: crate::ScalarKind,
|
||||
width: crate::Bytes,
|
||||
) -> Result<(), TypeError> {
|
||||
let good = match kind {
|
||||
crate::ScalarKind::Bool => width == crate::BOOL_WIDTH,
|
||||
crate::ScalarKind::Float => {
|
||||
width == 4 || (width == 8 && self.capabilities.contains(Capabilities::FLOAT64))
|
||||
if width == 8 {
|
||||
self.require_type_capability(Capabilities::FLOAT64)?;
|
||||
true
|
||||
} else {
|
||||
width == 4
|
||||
}
|
||||
}
|
||||
crate::ScalarKind::Sint | crate::ScalarKind::Uint => width == 4,
|
||||
};
|
||||
if good {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(TypeError::InvalidWidth(kind, width))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,9 +252,7 @@ impl super::Validator {
|
||||
use crate::TypeInner as Ti;
|
||||
Ok(match types[handle].inner {
|
||||
Ti::Scalar { kind, width } => {
|
||||
if !self.check_width(kind, width) {
|
||||
return Err(TypeError::InvalidWidth(kind, width));
|
||||
}
|
||||
self.check_width(kind, width)?;
|
||||
let shareable = if kind.is_numeric() {
|
||||
TypeFlags::IO_SHAREABLE | TypeFlags::HOST_SHAREABLE
|
||||
} else {
|
||||
@@ -247,9 +269,7 @@ impl super::Validator {
|
||||
)
|
||||
}
|
||||
Ti::Vector { size, kind, width } => {
|
||||
if !self.check_width(kind, width) {
|
||||
return Err(TypeError::InvalidWidth(kind, width));
|
||||
}
|
||||
self.check_width(kind, width)?;
|
||||
let shareable = if kind.is_numeric() {
|
||||
TypeFlags::IO_SHAREABLE | TypeFlags::HOST_SHAREABLE
|
||||
} else {
|
||||
@@ -271,9 +291,7 @@ impl super::Validator {
|
||||
rows,
|
||||
width,
|
||||
} => {
|
||||
if !self.check_width(crate::ScalarKind::Float, width) {
|
||||
return Err(TypeError::InvalidWidth(crate::ScalarKind::Float, width));
|
||||
}
|
||||
self.check_width(crate::ScalarKind::Float, width)?;
|
||||
TypeInfo::new(
|
||||
TypeFlags::DATA
|
||||
| TypeFlags::SIZED
|
||||
@@ -355,9 +373,7 @@ impl super::Validator {
|
||||
// However, some cases are trivial: All our implicit base types
|
||||
// are DATA and SIZED, so we can never return
|
||||
// `InvalidPointerBase` or `InvalidPointerToUnsized`.
|
||||
if !self.check_width(kind, width) {
|
||||
return Err(TypeError::InvalidWidth(kind, width));
|
||||
}
|
||||
self.check_width(kind, width)?;
|
||||
|
||||
// `Validator::validate_function` actually checks the storage
|
||||
// space of pointer arguments explicitly before checking the
|
||||
@@ -606,6 +622,10 @@ impl super::Validator {
|
||||
Ti::Image { .. } | Ti::Sampler { .. } => {
|
||||
TypeInfo::new(TypeFlags::ARGUMENT, Alignment::ONE)
|
||||
}
|
||||
Ti::AccelerationStructure | Ti::RayQuery => {
|
||||
self.require_type_capability(Capabilities::RAY_QUERY)?;
|
||||
TypeInfo::new(TypeFlags::empty(), Alignment::ONE)
|
||||
}
|
||||
Ti::BindingArray { .. } => TypeInfo::new(TypeFlags::empty(), Alignment::ONE),
|
||||
})
|
||||
}
|
||||
|
||||
6
tests/in/ray-query.param.ron
Normal file
6
tests/in/ray-query.param.ron
Normal file
@@ -0,0 +1,6 @@
|
||||
(
|
||||
god_mode: true,
|
||||
spv: (
|
||||
version: (1, 4),
|
||||
),
|
||||
)
|
||||
17
tests/in/ray-query.wgsl
Normal file
17
tests/in/ray-query.wgsl
Normal file
@@ -0,0 +1,17 @@
|
||||
var acc_struct: acceleration_structure;
|
||||
|
||||
struct Output {
|
||||
visible: u32,
|
||||
}
|
||||
var<storage, read_write> output: Output;
|
||||
|
||||
@compute
|
||||
fn main() {
|
||||
var rq: ray_query;
|
||||
|
||||
rayQueryInitialize(rq, acceleration_structure, RAY_FLAGS_TERMINATE_ON_FIRST_HIT, 0xFF, vec3<f32>(0.0), 0.1, vec3<f32>(0.0, 1.0, 0.0), 100.0);
|
||||
|
||||
rayQueryProceed(rq);
|
||||
|
||||
output.visible = rayQueryGetCommittedIntersectionType(rq) == RAY_QUERY_COMMITTED_INTERSECTION_NONE;
|
||||
}
|
||||
@@ -571,6 +571,7 @@ fn convert_wgsl() {
|
||||
("sprite", Targets::SPIRV),
|
||||
("force_point_size_vertex_shader_webgl", Targets::GLSL),
|
||||
("invariant", Targets::GLSL),
|
||||
("ray-query", Targets::SPIRV),
|
||||
];
|
||||
|
||||
for &(name, targets) in inputs.iter() {
|
||||
|
||||
Reference in New Issue
Block a user