mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
Add DepthImage IR type.
Fix all the usage of Bytes type to really mean bytes. Have logic in the SPIR-V front-end to detect the comparison properties of samplers and images.
This commit is contained in:
committed by
Dzmitry Malyshau
parent
2ffbeba8c6
commit
5d6406b018
@@ -139,6 +139,11 @@ impl<T> Arena<T> {
|
||||
self.append(value)
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a mutable reference to an element in the arena.
|
||||
pub fn mutate(&mut self, handle: Handle<T>) -> &mut T {
|
||||
self.data.get_mut(handle.index.get() as usize - 1).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> std::ops::Index<Handle<T>> for Arena<T> {
|
||||
|
||||
@@ -100,6 +100,15 @@ enum LocationMode {
|
||||
Uniform,
|
||||
}
|
||||
|
||||
fn dim_str(dim: crate::ImageDimension) -> &'static str {
|
||||
match dim {
|
||||
crate::ImageDimension::D1 => "1d",
|
||||
crate::ImageDimension::D2 => "2d",
|
||||
crate::ImageDimension::D3 => "3d",
|
||||
crate::ImageDimension::Cube => "Cube",
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Options<'a> {
|
||||
pub binding_map: &'a BindingMap,
|
||||
@@ -605,6 +614,7 @@ impl<W: Write> Writer<W> {
|
||||
image,
|
||||
sampler,
|
||||
coordinate,
|
||||
depth_ref: None,
|
||||
} => {
|
||||
let ty_image = self.put_expression(image, function, module)?;
|
||||
write!(self.out, ".sample(")?;
|
||||
@@ -617,6 +627,25 @@ impl<W: Write> Writer<W> {
|
||||
ref other => Err(Error::UnexpectedImageType(other.clone())),
|
||||
}
|
||||
}
|
||||
crate::Expression::ImageSample {
|
||||
image,
|
||||
sampler,
|
||||
coordinate,
|
||||
depth_ref: Some(dref),
|
||||
} => {
|
||||
self.put_expression(image, function, module)?;
|
||||
write!(self.out, ".sample_compare(")?;
|
||||
self.put_expression(sampler, function, module)?;
|
||||
write!(self.out, ", ")?;
|
||||
self.put_expression(coordinate, function, module)?;
|
||||
write!(self.out, ", ")?;
|
||||
self.put_expression(dref, function, module)?;
|
||||
write!(self.out, ")")?;
|
||||
Ok(MaybeOwned::Owned(crate::TypeInner::Scalar {
|
||||
kind: crate::ScalarKind::Float,
|
||||
width: 4,
|
||||
}))
|
||||
}
|
||||
crate::Expression::Call {
|
||||
ref name,
|
||||
ref arguments,
|
||||
@@ -887,11 +916,16 @@ impl<W: Write> Writer<W> {
|
||||
}
|
||||
crate::TypeInner::Image { base, dim, flags } => {
|
||||
let base_name = module.types[base].name.or_index(base);
|
||||
let dim = match dim {
|
||||
crate::ImageDimension::D1 => "1d",
|
||||
crate::ImageDimension::D2 => "2d",
|
||||
crate::ImageDimension::D3 => "3d",
|
||||
crate::ImageDimension::Cube => "Cube",
|
||||
let dim_str = dim_str(dim);
|
||||
let msaa_str = if flags.contains(crate::ImageFlags::MULTISAMPLED) {
|
||||
"_ms"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
let array_str = if flags.contains(crate::ImageFlags::ARRAYED) {
|
||||
"_array"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
let access = if flags.contains(crate::ImageFlags::SAMPLED) {
|
||||
if flags.intersects(crate::ImageFlags::CAN_STORE) {
|
||||
@@ -911,8 +945,17 @@ impl<W: Write> Writer<W> {
|
||||
};
|
||||
write!(
|
||||
self.out,
|
||||
"typedef texture{}<{}, access::{}> {}",
|
||||
dim, base_name, access, name
|
||||
"typedef texture{}{}{}<{}, access::{}> {}",
|
||||
dim_str, msaa_str, array_str, base_name, access, name
|
||||
)?;
|
||||
}
|
||||
crate::TypeInner::DepthImage { dim, arrayed } => {
|
||||
let dim_str = dim_str(dim);
|
||||
let array_str = if arrayed { "_array" } else { "" };
|
||||
write!(
|
||||
self.out,
|
||||
"typedef depth{}{}<float, access::sample> {}",
|
||||
dim_str, array_str, name
|
||||
)?;
|
||||
}
|
||||
crate::TypeInner::Sampler { comparison: _ } => {
|
||||
|
||||
@@ -40,6 +40,15 @@ impl<T> LookupHelper<T> for FastHashMap<Word, crate::Handle<T>> {
|
||||
}
|
||||
}
|
||||
|
||||
fn map_dim(dim: crate::ImageDimension) -> spirv::Dim {
|
||||
match dim {
|
||||
crate::ImageDimension::D1 => spirv::Dim::Dim1D,
|
||||
crate::ImageDimension::D2 => spirv::Dim::Dim2D,
|
||||
crate::ImageDimension::D3 => spirv::Dim::Dim2D,
|
||||
crate::ImageDimension::Cube => spirv::Dim::DimCube,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
struct LookupFunctionType {
|
||||
parameter_type_ids: Vec<Word>,
|
||||
@@ -413,14 +422,14 @@ impl Writer {
|
||||
sampled_type_id: Word,
|
||||
dim: spirv::Dim,
|
||||
flags: ImageFlags,
|
||||
comparison: bool,
|
||||
) -> Instruction {
|
||||
let mut instruction = Instruction::new(Op::TypeImage);
|
||||
instruction.set_result(id);
|
||||
instruction.add_operand(sampled_type_id);
|
||||
instruction.add_operand(dim as u32);
|
||||
|
||||
// TODO Add Depth, but how to determine? Not yet in the WGSL spec
|
||||
instruction.add_operand(1);
|
||||
instruction.add_operand(if comparison { 1 } else { 0 });
|
||||
|
||||
instruction.add_operand(if flags.contains(crate::ImageFlags::ARRAYED) {
|
||||
1
|
||||
@@ -765,17 +774,25 @@ impl Writer {
|
||||
}
|
||||
crate::TypeInner::Image { base, dim, flags } => {
|
||||
let type_id = self.get_type_id(arena, base);
|
||||
let dim = match dim {
|
||||
crate::ImageDimension::D1 => spirv::Dim::Dim1D,
|
||||
crate::ImageDimension::D2 => spirv::Dim::Dim2D,
|
||||
crate::ImageDimension::D3 => spirv::Dim::Dim2D,
|
||||
crate::ImageDimension::Cube => spirv::Dim::DimCube,
|
||||
};
|
||||
let dim = map_dim(dim);
|
||||
self.try_add_capabilities(dim.required_capabilities());
|
||||
|
||||
instruction = self.instruction_type_image(id, type_id, dim, flags);
|
||||
instruction = self.instruction_type_image(id, type_id, dim, flags, false);
|
||||
self.lookup_type.insert(id, base);
|
||||
}
|
||||
crate::TypeInner::DepthImage { dim, arrayed } => {
|
||||
let type_id = 0; //TODO!
|
||||
let dim = map_dim(dim);
|
||||
self.try_add_capabilities(dim.required_capabilities());
|
||||
|
||||
let flags = if arrayed {
|
||||
crate::ImageFlags::ARRAYED
|
||||
} else {
|
||||
crate::ImageFlags::empty()
|
||||
};
|
||||
instruction = self.instruction_type_image(id, type_id, dim, flags, true);
|
||||
//self.lookup_type.insert(id, base);
|
||||
}
|
||||
crate::TypeInner::Sampler { comparison: _ } => {
|
||||
instruction = self.instruction_type_sampler(id);
|
||||
self.lookup_type.insert(id, handle);
|
||||
@@ -845,8 +862,8 @@ impl Writer {
|
||||
|
||||
let instruction = match ty.inner {
|
||||
crate::TypeInner::Scalar { kind: _, width } => match width {
|
||||
32 => self.instruction_constant(type_id, id, &[val as u32]),
|
||||
64 => {
|
||||
4 => self.instruction_constant(type_id, id, &[val as u32]),
|
||||
8 => {
|
||||
let (low, high) = ((val >> 32) as u32, val as u32);
|
||||
self.instruction_constant(type_id, id, &[low, high])
|
||||
}
|
||||
@@ -862,8 +879,8 @@ impl Writer {
|
||||
|
||||
let instruction = match ty.inner {
|
||||
crate::TypeInner::Scalar { kind: _, width } => match width {
|
||||
32 => self.instruction_constant(type_id, id, &[val as u32]),
|
||||
64 => {
|
||||
4 => self.instruction_constant(type_id, id, &[val as u32]),
|
||||
8 => {
|
||||
let (low, high) = ((val >> 32) as u32, val as u32);
|
||||
self.instruction_constant(type_id, id, &[low, high])
|
||||
}
|
||||
@@ -880,8 +897,8 @@ impl Writer {
|
||||
|
||||
let instruction = match ty.inner {
|
||||
crate::TypeInner::Scalar { kind: _, width } => match width {
|
||||
32 => self.instruction_constant(type_id, id, &[(val as f32).to_bits()]),
|
||||
64 => {
|
||||
4 => self.instruction_constant(type_id, id, &[(val as f32).to_bits()]),
|
||||
8 => {
|
||||
let bits = f64::to_bits(val);
|
||||
let (low, high) = ((bits >> 32) as u32, bits as u32);
|
||||
self.instruction_constant(type_id, id, &[low, high])
|
||||
|
||||
@@ -47,49 +47,49 @@ pub fn glsl_to_spirv_type(ty: TypeSpecifierNonArray, types: &mut Arena<Type>) ->
|
||||
},
|
||||
Int => TypeInner::Scalar {
|
||||
kind: ScalarKind::Sint,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
UInt => TypeInner::Scalar {
|
||||
kind: ScalarKind::Uint,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
Float => TypeInner::Scalar {
|
||||
kind: ScalarKind::Float,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
Double => TypeInner::Scalar {
|
||||
kind: ScalarKind::Float,
|
||||
width: 64,
|
||||
width: 8,
|
||||
},
|
||||
Vec2 => TypeInner::Vector {
|
||||
size: VectorSize::Bi,
|
||||
kind: ScalarKind::Float,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
Vec3 => TypeInner::Vector {
|
||||
size: VectorSize::Tri,
|
||||
kind: ScalarKind::Float,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
Vec4 => TypeInner::Vector {
|
||||
size: VectorSize::Quad,
|
||||
kind: ScalarKind::Float,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
DVec2 => TypeInner::Vector {
|
||||
size: VectorSize::Bi,
|
||||
kind: ScalarKind::Float,
|
||||
width: 64,
|
||||
width: 8,
|
||||
},
|
||||
DVec3 => TypeInner::Vector {
|
||||
size: VectorSize::Tri,
|
||||
kind: ScalarKind::Float,
|
||||
width: 64,
|
||||
width: 8,
|
||||
},
|
||||
DVec4 => TypeInner::Vector {
|
||||
size: VectorSize::Quad,
|
||||
kind: ScalarKind::Float,
|
||||
width: 64,
|
||||
width: 8,
|
||||
},
|
||||
BVec2 => TypeInner::Vector {
|
||||
size: VectorSize::Bi,
|
||||
@@ -109,142 +109,142 @@ pub fn glsl_to_spirv_type(ty: TypeSpecifierNonArray, types: &mut Arena<Type>) ->
|
||||
IVec2 => TypeInner::Vector {
|
||||
size: VectorSize::Bi,
|
||||
kind: ScalarKind::Sint,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
IVec3 => TypeInner::Vector {
|
||||
size: VectorSize::Tri,
|
||||
kind: ScalarKind::Sint,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
IVec4 => TypeInner::Vector {
|
||||
size: VectorSize::Quad,
|
||||
kind: ScalarKind::Sint,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
UVec2 => TypeInner::Vector {
|
||||
size: VectorSize::Bi,
|
||||
kind: ScalarKind::Uint,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
UVec3 => TypeInner::Vector {
|
||||
size: VectorSize::Tri,
|
||||
kind: ScalarKind::Uint,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
UVec4 => TypeInner::Vector {
|
||||
size: VectorSize::Quad,
|
||||
kind: ScalarKind::Uint,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
// Float Matrices
|
||||
Mat2 => TypeInner::Matrix {
|
||||
columns: VectorSize::Bi,
|
||||
rows: VectorSize::Bi,
|
||||
kind: ScalarKind::Float,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
Mat3 => TypeInner::Matrix {
|
||||
columns: VectorSize::Tri,
|
||||
rows: VectorSize::Tri,
|
||||
kind: ScalarKind::Float,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
Mat4 => TypeInner::Matrix {
|
||||
columns: VectorSize::Quad,
|
||||
rows: VectorSize::Quad,
|
||||
kind: ScalarKind::Float,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
Mat23 => TypeInner::Matrix {
|
||||
columns: VectorSize::Bi,
|
||||
rows: VectorSize::Tri,
|
||||
kind: ScalarKind::Float,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
Mat24 => TypeInner::Matrix {
|
||||
columns: VectorSize::Bi,
|
||||
rows: VectorSize::Quad,
|
||||
kind: ScalarKind::Float,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
Mat32 => TypeInner::Matrix {
|
||||
columns: VectorSize::Tri,
|
||||
rows: VectorSize::Bi,
|
||||
kind: ScalarKind::Float,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
Mat34 => TypeInner::Matrix {
|
||||
columns: VectorSize::Tri,
|
||||
rows: VectorSize::Quad,
|
||||
kind: ScalarKind::Float,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
Mat42 => TypeInner::Matrix {
|
||||
columns: VectorSize::Quad,
|
||||
rows: VectorSize::Bi,
|
||||
kind: ScalarKind::Float,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
Mat43 => TypeInner::Matrix {
|
||||
columns: VectorSize::Quad,
|
||||
rows: VectorSize::Tri,
|
||||
kind: ScalarKind::Float,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
// Double Matrices
|
||||
DMat2 => TypeInner::Matrix {
|
||||
columns: VectorSize::Bi,
|
||||
rows: VectorSize::Bi,
|
||||
kind: ScalarKind::Float,
|
||||
width: 64,
|
||||
width: 8,
|
||||
},
|
||||
DMat3 => TypeInner::Matrix {
|
||||
columns: VectorSize::Tri,
|
||||
rows: VectorSize::Tri,
|
||||
kind: ScalarKind::Float,
|
||||
width: 64,
|
||||
width: 8,
|
||||
},
|
||||
DMat4 => TypeInner::Matrix {
|
||||
columns: VectorSize::Quad,
|
||||
rows: VectorSize::Quad,
|
||||
kind: ScalarKind::Float,
|
||||
width: 64,
|
||||
width: 8,
|
||||
},
|
||||
DMat23 => TypeInner::Matrix {
|
||||
columns: VectorSize::Bi,
|
||||
rows: VectorSize::Tri,
|
||||
kind: ScalarKind::Float,
|
||||
width: 64,
|
||||
width: 8,
|
||||
},
|
||||
DMat24 => TypeInner::Matrix {
|
||||
columns: VectorSize::Bi,
|
||||
rows: VectorSize::Quad,
|
||||
kind: ScalarKind::Float,
|
||||
width: 64,
|
||||
width: 8,
|
||||
},
|
||||
DMat32 => TypeInner::Matrix {
|
||||
columns: VectorSize::Tri,
|
||||
rows: VectorSize::Bi,
|
||||
kind: ScalarKind::Float,
|
||||
width: 64,
|
||||
width: 8,
|
||||
},
|
||||
DMat34 => TypeInner::Matrix {
|
||||
columns: VectorSize::Tri,
|
||||
rows: VectorSize::Quad,
|
||||
kind: ScalarKind::Float,
|
||||
width: 64,
|
||||
width: 8,
|
||||
},
|
||||
DMat42 => TypeInner::Matrix {
|
||||
columns: VectorSize::Quad,
|
||||
rows: VectorSize::Bi,
|
||||
kind: ScalarKind::Float,
|
||||
width: 64,
|
||||
width: 8,
|
||||
},
|
||||
DMat43 => TypeInner::Matrix {
|
||||
columns: VectorSize::Quad,
|
||||
rows: VectorSize::Tri,
|
||||
kind: ScalarKind::Float,
|
||||
width: 64,
|
||||
width: 8,
|
||||
},
|
||||
TypeName(ty_name) => {
|
||||
if let Some(t_pos) = ty_name.0.find("texture") {
|
||||
@@ -258,7 +258,7 @@ pub fn glsl_to_spirv_type(ty: TypeSpecifierNonArray, types: &mut Arena<Type>) ->
|
||||
name: None,
|
||||
inner: TypeInner::Scalar {
|
||||
kind: scalar_kind,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -558,7 +558,7 @@ impl<'a> Parser<'a> {
|
||||
name: None,
|
||||
inner: TypeInner::Scalar {
|
||||
kind: ScalarKind::Sint,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
}),
|
||||
}),
|
||||
@@ -572,7 +572,7 @@ impl<'a> Parser<'a> {
|
||||
name: None,
|
||||
inner: TypeInner::Scalar {
|
||||
kind: ScalarKind::Sint,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
}),
|
||||
}),
|
||||
@@ -586,7 +586,7 @@ impl<'a> Parser<'a> {
|
||||
name: None,
|
||||
inner: TypeInner::Scalar {
|
||||
kind: ScalarKind::Sint,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
}),
|
||||
}),
|
||||
@@ -600,7 +600,7 @@ impl<'a> Parser<'a> {
|
||||
name: None,
|
||||
inner: TypeInner::Scalar {
|
||||
kind: ScalarKind::Sint,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
}),
|
||||
}),
|
||||
@@ -619,7 +619,7 @@ impl<'a> Parser<'a> {
|
||||
inner: TypeInner::Vector {
|
||||
size: VectorSize::Quad,
|
||||
kind: ScalarKind::Float,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
}),
|
||||
},
|
||||
@@ -633,7 +633,7 @@ impl<'a> Parser<'a> {
|
||||
name: None,
|
||||
inner: TypeInner::Scalar {
|
||||
kind: ScalarKind::Float,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
}),
|
||||
},
|
||||
@@ -647,7 +647,7 @@ impl<'a> Parser<'a> {
|
||||
name: None,
|
||||
inner: TypeInner::Scalar {
|
||||
kind: ScalarKind::Float,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
}),
|
||||
}),
|
||||
@@ -684,7 +684,7 @@ impl<'a> Parser<'a> {
|
||||
name: None,
|
||||
inner: TypeInner::Scalar {
|
||||
kind: ScalarKind::Sint,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
}),
|
||||
},
|
||||
@@ -698,7 +698,7 @@ impl<'a> Parser<'a> {
|
||||
name: None,
|
||||
inner: TypeInner::Scalar {
|
||||
kind: ScalarKind::Uint,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
}),
|
||||
},
|
||||
@@ -726,7 +726,7 @@ impl<'a> Parser<'a> {
|
||||
name: None,
|
||||
inner: TypeInner::Scalar {
|
||||
kind: ScalarKind::Float,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
}),
|
||||
},
|
||||
@@ -740,7 +740,7 @@ impl<'a> Parser<'a> {
|
||||
name: None,
|
||||
inner: TypeInner::Scalar {
|
||||
kind: ScalarKind::Float,
|
||||
width: 64,
|
||||
width: 8,
|
||||
},
|
||||
}),
|
||||
},
|
||||
@@ -796,7 +796,7 @@ impl<'a> Parser<'a> {
|
||||
_ => panic!(),
|
||||
},
|
||||
kind: ScalarKind::Float,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
}),
|
||||
components: args
|
||||
@@ -858,6 +858,7 @@ impl<'a> Parser<'a> {
|
||||
image: expressions.append(image),
|
||||
sampler: expressions.append(sampler),
|
||||
coordinate: expressions.append(coordinate),
|
||||
depth_ref: None, //TODO
|
||||
})
|
||||
}
|
||||
_ => Ok(Expression::Call {
|
||||
|
||||
253
src/front/spv.rs
253
src/front/spv.rs
@@ -52,6 +52,13 @@ pub enum Error {
|
||||
InvalidLoadType(spirv::Word),
|
||||
InvalidStoreType(spirv::Word),
|
||||
InvalidBinding(spirv::Word),
|
||||
InvalidImageExpression(Handle<crate::Expression>),
|
||||
InvalidSamplerExpression(Handle<crate::Expression>),
|
||||
InvalidSampleImage(Handle<crate::Type>),
|
||||
InvalidSampleSampler(Handle<crate::Type>),
|
||||
InvalidSampleCoordinates(Handle<crate::Type>),
|
||||
InvalidDepthReference(Handle<crate::Type>),
|
||||
InconsistentComparisonSampling(Handle<crate::Type>),
|
||||
WrongFunctionResultType(spirv::Word),
|
||||
WrongFunctionParameterType(spirv::Word),
|
||||
MissingDecoration(spirv::Decoration),
|
||||
@@ -145,6 +152,49 @@ fn map_image_dim(word: spirv::Word) -> Result<crate::ImageDimension, Error> {
|
||||
}
|
||||
}
|
||||
|
||||
fn map_width(word: spirv::Word) -> Result<crate::Bytes, Error> {
|
||||
(word >> 3) // bits to bytes
|
||||
.try_into()
|
||||
.map_err(|_| Error::InvalidTypeWidth(word))
|
||||
}
|
||||
|
||||
//TODO: this method may need to be gone, depending on whether
|
||||
// WGSL allows treating images and samplers as expressions and pass them around.
|
||||
fn reach_global_type(
|
||||
expr_handle: Handle<crate::Expression>,
|
||||
expressions: &Arena<crate::Expression>,
|
||||
globals: &Arena<crate::GlobalVariable>,
|
||||
) -> Option<Handle<crate::Type>> {
|
||||
match expressions[expr_handle] {
|
||||
crate::Expression::GlobalVariable(var) => Some(globals[var].ty),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn check_sample_coordinates(
|
||||
ty: &crate::Type,
|
||||
expect_kind: crate::ScalarKind,
|
||||
dim: crate::ImageDimension,
|
||||
is_array: bool,
|
||||
) -> bool {
|
||||
let base_count = match dim {
|
||||
crate::ImageDimension::D1 => 1,
|
||||
crate::ImageDimension::D2 => 2,
|
||||
crate::ImageDimension::D3 | crate::ImageDimension::Cube => 3,
|
||||
};
|
||||
let extra_count = if is_array { 1 } else { 0 };
|
||||
let count = base_count + extra_count;
|
||||
match ty.inner {
|
||||
crate::TypeInner::Scalar { kind, width: _ } => count == 1 && kind == expect_kind,
|
||||
crate::TypeInner::Vector {
|
||||
size,
|
||||
kind,
|
||||
width: _,
|
||||
} => size as u8 == count && kind == expect_kind,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
type MemberIndex = u32;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
@@ -194,6 +244,16 @@ impl Decoration {
|
||||
}
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
/// Flags describing sampling method.
|
||||
pub struct SamplingFlags: u32 {
|
||||
/// Regular sampling.
|
||||
const REGULAR = 0x1;
|
||||
/// Comparison sampling.
|
||||
const COMPARISON = 0x2;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct LookupFunctionType {
|
||||
parameter_type_ids: Vec<spirv::Word>,
|
||||
@@ -245,8 +305,10 @@ pub struct Parser<I> {
|
||||
future_decor: FastHashMap<spirv::Word, Decoration>,
|
||||
future_member_decor: FastHashMap<(spirv::Word, MemberIndex), Decoration>,
|
||||
lookup_member_type_id: FastHashMap<(spirv::Word, MemberIndex), spirv::Word>,
|
||||
handle_sampling: FastHashMap<Handle<crate::Type>, SamplingFlags>,
|
||||
lookup_type: FastHashMap<spirv::Word, LookupType>,
|
||||
lookup_void_type: FastHashSet<spirv::Word>,
|
||||
// Lookup for samplers and sampled images, storing flags on how they are used.
|
||||
lookup_constant: FastHashMap<spirv::Word, LookupConstant>,
|
||||
lookup_variable: FastHashMap<spirv::Word, LookupVariable>,
|
||||
lookup_expression: FastHashMap<spirv::Word, LookupExpression>,
|
||||
@@ -263,6 +325,7 @@ impl<I: Iterator<Item = u32>> Parser<I> {
|
||||
temp_bytes: Vec::new(),
|
||||
future_decor: FastHashMap::default(),
|
||||
future_member_decor: FastHashMap::default(),
|
||||
handle_sampling: FastHashMap::default(),
|
||||
lookup_member_type_id: FastHashMap::default(),
|
||||
lookup_type: FastHashMap::default(),
|
||||
lookup_void_type: FastHashSet::default(),
|
||||
@@ -385,6 +448,7 @@ impl<I: Iterator<Item = u32>> Parser<I> {
|
||||
fun: &mut crate::Function,
|
||||
type_arena: &Arena<crate::Type>,
|
||||
const_arena: &Arena<crate::Constant>,
|
||||
global_arena: &Arena<crate::GlobalVariable>,
|
||||
) -> Result<(), Error> {
|
||||
loop {
|
||||
use spirv::Op;
|
||||
@@ -726,23 +790,113 @@ impl<I: Iterator<Item = u32>> Parser<I> {
|
||||
let coordinate_id = self.next()?;
|
||||
let si_lexp = self.lookup_sampled_image.lookup(sampled_image_id)?;
|
||||
let coord_lexp = self.lookup_expression.lookup(coordinate_id)?;
|
||||
let coord_type_lookup = self.lookup_type.lookup(coord_lexp.type_id)?;
|
||||
match type_arena[coord_type_lookup.handle].inner {
|
||||
crate::TypeInner::Scalar {
|
||||
kind: crate::ScalarKind::Float,
|
||||
..
|
||||
let coord_type_handle = self.lookup_type.lookup(coord_lexp.type_id)?.handle;
|
||||
|
||||
let sampler_type_handle =
|
||||
reach_global_type(si_lexp.sampler, &fun.expressions, global_arena)
|
||||
.ok_or(Error::InvalidSamplerExpression(si_lexp.sampler))?;
|
||||
let image_type_handle =
|
||||
reach_global_type(si_lexp.image, &fun.expressions, global_arena)
|
||||
.ok_or(Error::InvalidImageExpression(si_lexp.image))?;
|
||||
*self.handle_sampling.get_mut(&sampler_type_handle).unwrap() |=
|
||||
SamplingFlags::REGULAR;
|
||||
*self.handle_sampling.get_mut(&image_type_handle).unwrap() |=
|
||||
SamplingFlags::REGULAR;
|
||||
match type_arena[sampler_type_handle].inner {
|
||||
crate::TypeInner::Sampler { comparison: false } => (),
|
||||
_ => return Err(Error::InvalidSampleSampler(sampler_type_handle)),
|
||||
};
|
||||
match type_arena[image_type_handle].inner {
|
||||
//TODO: compare the result type
|
||||
crate::TypeInner::Image {
|
||||
base: _,
|
||||
dim,
|
||||
flags,
|
||||
} if flags
|
||||
& (crate::ImageFlags::MULTISAMPLED | crate::ImageFlags::SAMPLED)
|
||||
== crate::ImageFlags::SAMPLED =>
|
||||
{
|
||||
if !check_sample_coordinates(
|
||||
&type_arena[coord_type_handle],
|
||||
crate::ScalarKind::Float,
|
||||
dim,
|
||||
flags.contains(crate::ImageFlags::ARRAYED),
|
||||
) {
|
||||
return Err(Error::InvalidSampleCoordinates(coord_type_handle));
|
||||
}
|
||||
}
|
||||
| crate::TypeInner::Vector {
|
||||
kind: crate::ScalarKind::Float,
|
||||
..
|
||||
} => (),
|
||||
_ => return Err(Error::UnsupportedType(coord_type_lookup.handle)),
|
||||
}
|
||||
//TODO: compare the result type
|
||||
_ => return Err(Error::InvalidSampleImage(image_type_handle)),
|
||||
};
|
||||
|
||||
let expr = crate::Expression::ImageSample {
|
||||
image: si_lexp.image,
|
||||
sampler: si_lexp.sampler,
|
||||
coordinate: coord_lexp.handle,
|
||||
depth_ref: None,
|
||||
};
|
||||
self.lookup_expression.insert(
|
||||
result_id,
|
||||
LookupExpression {
|
||||
handle: fun.expressions.append(expr),
|
||||
type_id: result_type_id,
|
||||
},
|
||||
);
|
||||
}
|
||||
Op::ImageSampleDrefImplicitLod => {
|
||||
inst.expect_at_least(6)?;
|
||||
let result_type_id = self.next()?;
|
||||
let result_id = self.next()?;
|
||||
let sampled_image_id = self.next()?;
|
||||
let coordinate_id = self.next()?;
|
||||
let dref_id = self.next()?;
|
||||
|
||||
let si_lexp = self.lookup_sampled_image.lookup(sampled_image_id)?;
|
||||
let coord_lexp = self.lookup_expression.lookup(coordinate_id)?;
|
||||
let coord_type_handle = self.lookup_type.lookup(coord_lexp.type_id)?.handle;
|
||||
let sampler_type_handle =
|
||||
reach_global_type(si_lexp.sampler, &fun.expressions, global_arena)
|
||||
.ok_or(Error::InvalidSamplerExpression(si_lexp.sampler))?;
|
||||
let image_type_handle =
|
||||
reach_global_type(si_lexp.image, &fun.expressions, global_arena)
|
||||
.ok_or(Error::InvalidImageExpression(si_lexp.image))?;
|
||||
*self.handle_sampling.get_mut(&sampler_type_handle).unwrap() |=
|
||||
SamplingFlags::COMPARISON;
|
||||
*self.handle_sampling.get_mut(&image_type_handle).unwrap() |=
|
||||
SamplingFlags::COMPARISON;
|
||||
match type_arena[sampler_type_handle].inner {
|
||||
crate::TypeInner::Sampler { comparison: true } => (),
|
||||
_ => return Err(Error::InvalidSampleSampler(sampler_type_handle)),
|
||||
};
|
||||
match type_arena[image_type_handle].inner {
|
||||
//TODO: compare the result type
|
||||
crate::TypeInner::DepthImage { dim, arrayed } => {
|
||||
if !check_sample_coordinates(
|
||||
&type_arena[coord_type_handle],
|
||||
crate::ScalarKind::Float,
|
||||
dim,
|
||||
arrayed,
|
||||
) {
|
||||
return Err(Error::InvalidSampleCoordinates(coord_type_handle));
|
||||
}
|
||||
}
|
||||
_ => return Err(Error::InvalidSampleImage(image_type_handle)),
|
||||
};
|
||||
|
||||
let dref_lexp = self.lookup_expression.lookup(dref_id)?;
|
||||
let dref_type_handle = self.lookup_type.lookup(dref_lexp.type_id)?.handle;
|
||||
match type_arena[dref_type_handle].inner {
|
||||
crate::TypeInner::Scalar {
|
||||
kind: crate::ScalarKind::Float,
|
||||
width: _,
|
||||
} => (),
|
||||
_ => return Err(Error::InvalidDepthReference(dref_type_handle)),
|
||||
}
|
||||
|
||||
let expr = crate::Expression::ImageSample {
|
||||
image: si_lexp.image,
|
||||
sampler: si_lexp.sampler,
|
||||
coordinate: coord_lexp.handle,
|
||||
depth_ref: Some(dref_lexp.handle),
|
||||
};
|
||||
self.lookup_expression.insert(
|
||||
result_id,
|
||||
@@ -847,6 +1001,34 @@ impl<I: Iterator<Item = u32>> Parser<I> {
|
||||
}?;
|
||||
}
|
||||
|
||||
// Check all the images and samplers to have consistent comparison property.
|
||||
for (handle, flags) in self.handle_sampling.drain() {
|
||||
if !flags.contains(SamplingFlags::COMPARISON) {
|
||||
continue;
|
||||
}
|
||||
if flags == SamplingFlags::all() {
|
||||
return Err(Error::InconsistentComparisonSampling(handle));
|
||||
}
|
||||
let ty = module.types.mutate(handle);
|
||||
match ty.inner {
|
||||
crate::TypeInner::Sampler { ref mut comparison } => {
|
||||
assert!(!*comparison);
|
||||
*comparison = true;
|
||||
}
|
||||
crate::TypeInner::Image {
|
||||
base: _,
|
||||
dim,
|
||||
flags,
|
||||
} => {
|
||||
ty.inner = crate::TypeInner::DepthImage {
|
||||
dim,
|
||||
arrayed: flags.contains(crate::ImageFlags::ARRAYED),
|
||||
};
|
||||
}
|
||||
_ => panic!("Unexpected comparison type {:?}", ty),
|
||||
}
|
||||
}
|
||||
|
||||
if !self.future_decor.is_empty() {
|
||||
log::warn!("Unused item decorations: {:?}", self.future_decor);
|
||||
self.future_decor.clear();
|
||||
@@ -1044,9 +1226,7 @@ impl<I: Iterator<Item = u32>> Parser<I> {
|
||||
1 => crate::ScalarKind::Sint,
|
||||
_ => return Err(Error::InvalidSign(sign)),
|
||||
},
|
||||
width: width
|
||||
.try_into()
|
||||
.map_err(|_| Error::InvalidTypeWidth(width))?,
|
||||
width: map_width(width)?,
|
||||
};
|
||||
self.lookup_type.insert(
|
||||
id,
|
||||
@@ -1072,9 +1252,7 @@ impl<I: Iterator<Item = u32>> Parser<I> {
|
||||
let width = self.next()?;
|
||||
let inner = crate::TypeInner::Scalar {
|
||||
kind: crate::ScalarKind::Float,
|
||||
width: width
|
||||
.try_into()
|
||||
.map_err(|_| Error::InvalidTypeWidth(width))?,
|
||||
width: map_width(width)?,
|
||||
};
|
||||
self.lookup_type.insert(
|
||||
id,
|
||||
@@ -1346,13 +1524,15 @@ impl<I: Iterator<Item = u32>> Parser<I> {
|
||||
dim: map_image_dim(dim)?,
|
||||
flags,
|
||||
};
|
||||
let handle = module.types.append(crate::Type {
|
||||
name: decor.name,
|
||||
inner,
|
||||
});
|
||||
self.handle_sampling.insert(handle, SamplingFlags::empty());
|
||||
self.lookup_type.insert(
|
||||
id,
|
||||
LookupType {
|
||||
handle: module.types.append(crate::Type {
|
||||
name: decor.name,
|
||||
inner,
|
||||
}),
|
||||
handle,
|
||||
base_id: Some(sample_type_id),
|
||||
},
|
||||
);
|
||||
@@ -1383,14 +1563,18 @@ impl<I: Iterator<Item = u32>> Parser<I> {
|
||||
inst.expect(2)?;
|
||||
let id = self.next()?;
|
||||
let decor = self.future_decor.remove(&id).unwrap_or_default();
|
||||
let inner = crate::TypeInner::Sampler { comparison: false }; //TODO!
|
||||
// The comparison bit is temporary, will be overwritten based on the
|
||||
// accumulated sampling flags at the end.
|
||||
let inner = crate::TypeInner::Sampler { comparison: false };
|
||||
let handle = module.types.append(crate::Type {
|
||||
name: decor.name,
|
||||
inner,
|
||||
});
|
||||
self.handle_sampling.insert(handle, SamplingFlags::empty());
|
||||
self.lookup_type.insert(
|
||||
id,
|
||||
LookupType {
|
||||
handle: module.types.append(crate::Type {
|
||||
name: decor.name,
|
||||
inner,
|
||||
}),
|
||||
handle,
|
||||
base_id: None,
|
||||
},
|
||||
);
|
||||
@@ -1414,7 +1598,7 @@ impl<I: Iterator<Item = u32>> Parser<I> {
|
||||
width,
|
||||
} => {
|
||||
let low = self.next()?;
|
||||
let high = if width > 32 {
|
||||
let high = if width > 4 {
|
||||
inst.expect(4)?;
|
||||
self.next()?
|
||||
} else {
|
||||
@@ -1428,7 +1612,7 @@ impl<I: Iterator<Item = u32>> Parser<I> {
|
||||
} => {
|
||||
use std::cmp::Ordering;
|
||||
let low = self.next()?;
|
||||
let high = match width.cmp(&32) {
|
||||
let high = match width.cmp(&4) {
|
||||
Ordering::Less => return Err(Error::InvalidTypeWidth(u32::from(width))),
|
||||
Ordering::Greater => {
|
||||
inst.expect(4)?;
|
||||
@@ -1444,8 +1628,8 @@ impl<I: Iterator<Item = u32>> Parser<I> {
|
||||
} => {
|
||||
let low = self.next()?;
|
||||
let extended = match width {
|
||||
32 => f64::from(f32::from_bits(low)),
|
||||
64 => {
|
||||
4 => f64::from(f32::from_bits(low)),
|
||||
8 => {
|
||||
inst.expect(4)?;
|
||||
let high = self.next()?;
|
||||
f64::from_bits((u64::from(high) << 32) | u64::from(low))
|
||||
@@ -1635,7 +1819,12 @@ impl<I: Iterator<Item = u32>> Parser<I> {
|
||||
spirv::Op::Label => {
|
||||
fun_inst.expect(2)?;
|
||||
let _id = self.next()?;
|
||||
self.next_block(&mut fun, &module.types, &module.constants)?;
|
||||
self.next_block(
|
||||
&mut fun,
|
||||
&module.types,
|
||||
&module.constants,
|
||||
&module.global_variables,
|
||||
)?;
|
||||
}
|
||||
spirv::Op::FunctionEnd => {
|
||||
fun_inst.expect(1)?;
|
||||
|
||||
@@ -232,12 +232,12 @@ impl<'a> Lexer<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn next_scalar_generic(&mut self) -> Result<(crate::ScalarKind, u8), Error<'a>> {
|
||||
fn next_scalar_generic(&mut self) -> Result<(crate::ScalarKind, crate::Bytes), Error<'a>> {
|
||||
self.expect(Token::Paren('<'))?;
|
||||
let pair = match self.next() {
|
||||
Token::Word("f32") => (crate::ScalarKind::Float, 32),
|
||||
Token::Word("i32") => (crate::ScalarKind::Sint, 32),
|
||||
Token::Word("u32") => (crate::ScalarKind::Uint, 32),
|
||||
Token::Word("f32") => (crate::ScalarKind::Float, 4),
|
||||
Token::Word("i32") => (crate::ScalarKind::Sint, 4),
|
||||
Token::Word("u32") => (crate::ScalarKind::Uint, 4),
|
||||
other => return Err(Error::Unexpected(other)),
|
||||
};
|
||||
self.expect(Token::Paren('>'))?;
|
||||
@@ -524,7 +524,7 @@ impl Parser {
|
||||
specialization: None,
|
||||
inner,
|
||||
ty: Typifier::deduce_type_handle(
|
||||
crate::TypeInner::Scalar { kind, width: 32 },
|
||||
crate::TypeInner::Scalar { kind, width: 4 },
|
||||
ctx.types,
|
||||
),
|
||||
});
|
||||
@@ -991,15 +991,15 @@ impl Parser {
|
||||
let inner = match lexer.next() {
|
||||
Token::Word("f32") => crate::TypeInner::Scalar {
|
||||
kind: crate::ScalarKind::Float,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
Token::Word("i32") => crate::TypeInner::Scalar {
|
||||
kind: crate::ScalarKind::Sint,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
Token::Word("u32") => crate::TypeInner::Scalar {
|
||||
kind: crate::ScalarKind::Uint,
|
||||
width: 32,
|
||||
width: 4,
|
||||
},
|
||||
Token::Word("vec2") => {
|
||||
let (kind, width) = lexer.next_scalar_generic()?;
|
||||
|
||||
31
src/lib.rs
31
src/lib.rs
@@ -175,10 +175,7 @@ pub struct Type {
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum TypeInner {
|
||||
/// Number of integral or floating-point kind.
|
||||
Scalar {
|
||||
kind: ScalarKind,
|
||||
width: Bytes,
|
||||
},
|
||||
Scalar { kind: ScalarKind, width: Bytes },
|
||||
/// Vector of numbers.
|
||||
Vector {
|
||||
size: VectorSize,
|
||||
@@ -204,19 +201,17 @@ pub enum TypeInner {
|
||||
stride: Option<NonZeroU32>,
|
||||
},
|
||||
/// User-defined structure.
|
||||
Struct {
|
||||
members: Vec<StructMember>,
|
||||
},
|
||||
/// Possibly multidimensional array of pixels.
|
||||
Struct { members: Vec<StructMember> },
|
||||
/// Possibly multidimensional array of texels.
|
||||
Image {
|
||||
base: Handle<Type>,
|
||||
dim: ImageDimension,
|
||||
flags: ImageFlags,
|
||||
},
|
||||
/// Depth-comparison image.
|
||||
DepthImage { dim: ImageDimension, arrayed: bool },
|
||||
/// Can be used to sample values from images.
|
||||
Sampler {
|
||||
comparison: bool,
|
||||
},
|
||||
Sampler { comparison: bool },
|
||||
}
|
||||
|
||||
/// Constant value.
|
||||
@@ -361,14 +356,13 @@ pub enum Expression {
|
||||
/// Reference a local variable.
|
||||
LocalVariable(Handle<LocalVariable>),
|
||||
/// Load a value indirectly.
|
||||
Load {
|
||||
pointer: Handle<Expression>,
|
||||
},
|
||||
Load { pointer: Handle<Expression> },
|
||||
/// Sample a point from an image.
|
||||
ImageSample {
|
||||
image: Handle<Expression>,
|
||||
sampler: Handle<Expression>,
|
||||
coordinate: Handle<Expression>,
|
||||
depth_ref: Option<Handle<Expression>>,
|
||||
},
|
||||
/// Apply an unary operator.
|
||||
Unary {
|
||||
@@ -432,19 +426,14 @@ pub enum Statement {
|
||||
default: Block,
|
||||
},
|
||||
/// Executes a block repeatedly.
|
||||
Loop {
|
||||
body: Block,
|
||||
continuing: Block,
|
||||
},
|
||||
Loop { body: Block, continuing: Block },
|
||||
//TODO: move terminator variations into a separate enum?
|
||||
/// Exits the loop.
|
||||
Break,
|
||||
/// Skips execution to the next iteration of the loop.
|
||||
Continue,
|
||||
/// Returns from the function (possibly with a value).
|
||||
Return {
|
||||
value: Option<Handle<Expression>>,
|
||||
},
|
||||
Return { value: Option<Handle<Expression>> },
|
||||
/// Aborts the current shader execution.
|
||||
Kill,
|
||||
/// Stores a value at an address.
|
||||
|
||||
@@ -34,10 +34,14 @@ impl<'a> Interface<'a> {
|
||||
image,
|
||||
sampler,
|
||||
coordinate,
|
||||
depth_ref,
|
||||
} => {
|
||||
self.add_inputs(image);
|
||||
self.add_inputs(sampler);
|
||||
self.add_inputs(coordinate);
|
||||
if let Some(dref) = depth_ref {
|
||||
self.add_inputs(dref);
|
||||
}
|
||||
}
|
||||
E::Unary { expr, .. } => {
|
||||
self.add_inputs(expr);
|
||||
|
||||
@@ -26,7 +26,7 @@ impl Validator {
|
||||
Ti::Scalar { kind, width }
|
||||
| Ti::Vector { kind, width, .. }
|
||||
| Ti::Matrix { kind, width, .. } => {
|
||||
if width != 32 {
|
||||
if width != 4 {
|
||||
return Err(ValidationError::InvalidTypeWidth(kind, width));
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,7 @@ impl Validator {
|
||||
}
|
||||
}
|
||||
}
|
||||
Ti::Image { .. } => {}
|
||||
Ti::Image { .. } | Ti::DepthImage { .. } => {}
|
||||
Ti::Sampler { comparison: _ } => {}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user