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:
Dzmitry Malyshau
2020-07-03 18:27:16 -04:00
committed by Dzmitry Malyshau
parent 2ffbeba8c6
commit 5d6406b018
10 changed files with 380 additions and 132 deletions

View File

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

View File

@@ -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: _ } => {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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: _ } => {}
}
}