glsl-in: Add support for image declarations

This commit is contained in:
João Capucho
2022-02-05 17:42:38 +00:00
parent e904d2bfd6
commit 27cbce5b5d
4 changed files with 176 additions and 26 deletions

View File

@@ -139,6 +139,8 @@ pub enum QualifierKey<'a> {
String(Cow<'a, str>),
/// Used for `std140` and `std430` layout qualifiers
Layout,
/// Used for image formats
Format,
}
#[derive(Debug)]
@@ -146,6 +148,7 @@ pub enum QualifierValue {
None,
Uint(u32),
Layout(StructLayout),
Format(crate::StorageFormat),
}
#[derive(Debug, Default)]

View File

@@ -285,24 +285,28 @@ impl<'source> ParsingContext<'source> {
QualifierKey::Layout,
QualifierValue::Layout(StructLayout::Std430),
),
_ => {
let key = QualifierKey::String(name.into());
let value = if self.bump_if(parser, TokenValue::Assign).is_some() {
let (value, end_meta) = match self.parse_uint_constant(parser) {
Ok(v) => v,
Err(e) => {
parser.errors.push(e);
(0, Span::default())
}
};
token.meta.subsume(end_meta);
QualifierValue::Uint(value)
word => {
if let Some(format) = map_image_format(word) {
(QualifierKey::Format, QualifierValue::Format(format))
} else {
QualifierValue::None
};
let key = QualifierKey::String(name.into());
let value = if self.bump_if(parser, TokenValue::Assign).is_some() {
let (value, end_meta) = match self.parse_uint_constant(parser) {
Ok(v) => v,
Err(e) => {
parser.errors.push(e);
(0, Span::default())
}
};
token.meta.subsume(end_meta);
(key, value)
QualifierValue::Uint(value)
} else {
QualifierValue::None
};
(key, value)
}
}
};
@@ -326,3 +330,54 @@ impl<'source> ParsingContext<'source> {
})
}
}
fn map_image_format(word: &str) -> Option<crate::StorageFormat> {
let format = match word {
// float-image-format-qualifier:
"rgba32f" => crate::StorageFormat::Rgba32Float,
"rgba16f" => crate::StorageFormat::Rgba16Float,
"rg32f" => crate::StorageFormat::Rg32Float,
"rg16f" => crate::StorageFormat::Rg16Float,
"r11f_g11f_b10f" => crate::StorageFormat::Rg11b10Float,
"r32f" => crate::StorageFormat::R32Float,
"r16f" => crate::StorageFormat::R16Float,
"rgba16" => crate::StorageFormat::Rgba16Float,
"rgb10_a2" => crate::StorageFormat::Rgb10a2Unorm,
"rgba8" => crate::StorageFormat::Rgba8Unorm,
"rg16" => crate::StorageFormat::Rg16Float,
"rg8" => crate::StorageFormat::Rg8Unorm,
"r16" => crate::StorageFormat::R16Float,
"r8" => crate::StorageFormat::R8Unorm,
"rgba8_snorm" => crate::StorageFormat::Rgba8Snorm,
"rg8_snorm" => crate::StorageFormat::Rg8Snorm,
"r8_snorm" => crate::StorageFormat::R8Snorm,
// int-image-format-qualifier:
"rgba32i" => crate::StorageFormat::Rgba32Sint,
"rgba16i" => crate::StorageFormat::Rgba16Sint,
"rgba8i" => crate::StorageFormat::Rgba8Sint,
"rg32i" => crate::StorageFormat::Rg32Sint,
"rg16i" => crate::StorageFormat::Rg16Sint,
"rg8i" => crate::StorageFormat::Rg8Sint,
"r32i" => crate::StorageFormat::R32Sint,
"r16i" => crate::StorageFormat::R16Sint,
"r8i" => crate::StorageFormat::R8Sint,
// uint-image-format-qualifier:
"rgba32ui" => crate::StorageFormat::Rgba32Uint,
"rgba16ui" => crate::StorageFormat::Rgba16Uint,
"rgba8ui" => crate::StorageFormat::Rgba8Uint,
"rg32ui" => crate::StorageFormat::Rg32Uint,
"rg16ui" => crate::StorageFormat::Rg16Uint,
"rg8ui" => crate::StorageFormat::Rg8Uint,
"r32ui" => crate::StorageFormat::R32Uint,
"r16ui" => crate::StorageFormat::R16Uint,
"r8ui" => crate::StorageFormat::R8Uint,
// TODO: These next ones seem incorrect to me
// "rgba16_snorm" => crate::StorageFormat::Rgba16Float,
// "rg16_snorm" => crate::StorageFormat::Rg16Float,
// "r16_snorm" => crate::StorageFormat::R16Float,
// "rgb10_a2ui" => crate::StorageFormat::Rgb10a2Unorm,
_ => return None,
};
Some(format)
}

View File

@@ -150,9 +150,60 @@ pub fn parse_type(type_name: &str) -> Option<Type> {
})
};
let image_parse = |word: &str| {
let mut iter = word.split("image");
let texture_kind = |ty| {
Some(match ty {
"" => ScalarKind::Float,
"i" => ScalarKind::Sint,
"u" => ScalarKind::Uint,
_ => return None,
})
};
let kind = iter.next()?;
let size = iter.next()?;
let kind = texture_kind(kind)?;
let class = ImageClass::Storage {
format: match kind {
ScalarKind::Sint => crate::StorageFormat::Rgba32Sint,
ScalarKind::Uint => crate::StorageFormat::Rgba32Uint,
ScalarKind::Float => crate::StorageFormat::Rgba32Float,
ScalarKind::Bool => unreachable!(),
},
access: crate::StorageAccess::all(),
};
// TODO: glsl support multisampled storage images, naga doesn't
let (dim, arrayed) = match size {
"1D" => (ImageDimension::D1, false),
"1DArray" => (ImageDimension::D1, true),
"2D" => (ImageDimension::D2, false),
"2DArray" => (ImageDimension::D2, true),
"3D" => (ImageDimension::D3, false),
// Naga doesn't support cube images and it's usefulness
// is questionable, so they won't be supported for now
// "Cube" => (ImageDimension::Cube, false),
// "CubeArray" => (ImageDimension::Cube, true),
_ => return None,
};
Some(Type {
name: None,
inner: TypeInner::Image {
dim,
arrayed,
class,
},
})
};
vec_parse(word)
.or_else(|| mat_parse(word))
.or_else(|| texture_parse(word))
.or_else(|| image_parse(word))
}
}
}

View File

@@ -393,7 +393,7 @@ impl Parser {
body: &mut Block,
VarDeclaration {
qualifiers,
ty,
mut ty,
name,
init,
meta,
@@ -469,17 +469,58 @@ impl Parser {
access.remove(restricted_access);
}
}
AddressSpace::Uniform => {
if let TypeInner::Image { .. } | TypeInner::Sampler { .. } =
self.module.types[ty].inner
{
AddressSpace::Uniform => match self.module.types[ty].inner {
TypeInner::Image {
class,
dim,
arrayed,
} => {
if let crate::ImageClass::Storage {
mut access,
mut format,
} = class
{
if let Some((restricted_access, _)) =
qualifiers.storage_acess.take()
{
access.remove(restricted_access);
}
match qualifiers.layout_qualifiers.remove(&QualifierKey::Format) {
Some((QualifierValue::Format(f), _)) => format = f,
// TODO: glsl supports images without format qualifier
// if they are `writeonly`
None => self.errors.push(Error {
kind: ErrorKind::SemanticError(
"image types require a format layout qualifier".into(),
),
meta,
}),
_ => unreachable!(),
}
ty = self.module.types.insert(
Type {
name: None,
inner: TypeInner::Image {
dim,
arrayed,
class: crate::ImageClass::Storage { format, access },
},
},
meta,
);
}
space = AddressSpace::Handle
} else if qualifiers
.none_layout_qualifier("push_constant", &mut self.errors)
{
space = AddressSpace::PushConstant
}
}
TypeInner::Sampler { .. } => space = AddressSpace::Handle,
_ => {
if qualifiers.none_layout_qualifier("push_constant", &mut self.errors) {
space = AddressSpace::PushConstant
}
}
},
AddressSpace::Function => space = AddressSpace::Private,
_ => {}
};