diff --git a/src/front/glsl/ast.rs b/src/front/glsl/ast.rs index 4c2054bfe6..dec73eed01 100644 --- a/src/front/glsl/ast.rs +++ b/src/front/glsl/ast.rs @@ -55,6 +55,9 @@ pub struct Overload { pub kind: FunctionKind, /// Wheter this function was already defined or is just a prototype pub defined: bool, + /// Wheter this overload is the one provided by the language or has + /// been redeclared by the user (builtins only) + pub internal: bool, /// Wheter or not this function returns void (nothing) pub void: bool, } @@ -139,6 +142,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 +151,7 @@ pub enum QualifierValue { None, Uint(u32), Layout(StructLayout), + Format(crate::StorageFormat), } #[derive(Debug, Default)] diff --git a/src/front/glsl/builtins.rs b/src/front/glsl/builtins.rs index 41c29ecb2c..17eef65796 100644 --- a/src/front/glsl/builtins.rs +++ b/src/front/glsl/builtins.rs @@ -9,6 +9,16 @@ use crate::{ ScalarKind as Sk, Span, Type, TypeInner, VectorSize, }; +impl crate::ScalarKind { + fn dummy_storage_format(&self) -> crate::StorageFormat { + match *self { + Sk::Sint => crate::StorageFormat::R16Sint, + Sk::Uint => crate::StorageFormat::R16Uint, + _ => crate::StorageFormat::R16Float, + } + } +} + impl Module { /// Helper function, to create a function prototype for a builtin fn add_builtin(&mut self, args: Vec, builtin: MacroCall) -> Overload { @@ -34,6 +44,7 @@ impl Module { parameters_info, kind: FunctionKind::Macro(builtin), defined: false, + internal: true, void: false, } } @@ -231,8 +242,7 @@ pub fn inject_builtin(declaration: &mut FunctionDeclaration, module: &mut Module class, }; - let dim_value = image_dims_to_coords_size(dim); - let num_coords_from_dim = (dim_value + 1).min(3); + let num_coords_from_dim = image_dims_to_coords_size(dim).min(3); let mut num_coords = num_coords_from_dim; if shadow && proj { @@ -352,26 +362,8 @@ pub fn inject_builtin(declaration: &mut FunctionDeclaration, module: &mut Module class: ImageClass::Sampled { kind, multi }, }; - let coordinates = match (dim, arrayed) { - (Dim::D1, false) => TypeInner::Scalar { - kind: Sk::Sint, - width, - }, - _ => { - let dim_value = image_dims_to_coords_size(dim); - let size = match dim_value + arrayed as usize { - 1 => VectorSize::Bi, - 2 => VectorSize::Tri, - _ => VectorSize::Quad, - }; - - TypeInner::Vector { - size, - kind: Sk::Sint, - width, - } - } - }; + let dim_value = image_dims_to_coords_size(dim); + let coordinates = make_coords_arg(dim_value + arrayed as usize, Sk::Sint); let args = vec![ image, @@ -384,12 +376,122 @@ pub fn inject_builtin(declaration: &mut FunctionDeclaration, module: &mut Module declaration .overloads - .push(module.add_builtin(args, MacroCall::TexelFetch)) + .push(module.add_builtin(args, MacroCall::ImageLoad)) }; // Don't generate shadow images since they aren't supported texture_args_generator(TextureArgsOptions::MULTI, f) } + "imageSize" => { + let f = |kind: Sk, dim, arrayed, _, _| { + // Naga doesn't support cube images and it's usefulness + // is questionable, so they won't be supported for now + if dim == Dim::Cube { + return; + } + + let image = TypeInner::Image { + dim, + arrayed, + class: ImageClass::Storage { + format: kind.dummy_storage_format(), + access: crate::StorageAccess::empty(), + }, + }; + + declaration + .overloads + .push(module.add_builtin(vec![image], MacroCall::TextureSize { arrayed })) + }; + + texture_args_generator(TextureArgsOptions::empty(), f) + } + "imageLoad" => { + let f = |kind: Sk, dim, arrayed, _, _| { + // Naga doesn't support cube images and it's usefulness + // is questionable, so they won't be supported for now + if dim == Dim::Cube { + return; + } + + let image = TypeInner::Image { + dim, + arrayed, + class: ImageClass::Storage { + format: kind.dummy_storage_format(), + access: crate::StorageAccess::LOAD, + }, + }; + + let dim_value = image_dims_to_coords_size(dim); + let mut coord_size = dim_value + arrayed as usize; + // > Every OpenGL API call that operates on cubemap array + // > textures takes layer-faces, not array layers + // + // So this means that imageCubeArray only takes a three component + // vector coordinate and the third component is a layer index. + if Dim::Cube == dim && arrayed { + coord_size = 3 + } + let coordinates = make_coords_arg(coord_size, Sk::Sint); + + let args = vec![image, coordinates]; + + declaration + .overloads + .push(module.add_builtin(args, MacroCall::ImageLoad)) + }; + + // Don't generate shadow nor multisampled images since they aren't supported + texture_args_generator(TextureArgsOptions::empty(), f) + } + "imageStore" => { + let f = |kind: Sk, dim, arrayed, _, _| { + // Naga doesn't support cube images and it's usefulness + // is questionable, so they won't be supported for now + if dim == Dim::Cube { + return; + } + + let image = TypeInner::Image { + dim, + arrayed, + class: ImageClass::Storage { + format: kind.dummy_storage_format(), + access: crate::StorageAccess::STORE, + }, + }; + + let dim_value = image_dims_to_coords_size(dim); + let mut coord_size = dim_value + arrayed as usize; + // > Every OpenGL API call that operates on cubemap array + // > textures takes layer-faces, not array layers + // + // So this means that imageCubeArray only takes a three component + // vector coordinate and the third component is a layer index. + if Dim::Cube == dim && arrayed { + coord_size = 3 + } + let coordinates = make_coords_arg(coord_size, Sk::Sint); + + let args = vec![ + image, + coordinates, + TypeInner::Vector { + size: VectorSize::Quad, + kind, + width, + }, + ]; + + let mut overload = module.add_builtin(args, MacroCall::ImageStore); + overload.void = true; + declaration.overloads.push(overload) + }; + + // Don't generate shadow nor multisampled images since they aren't supported + texture_args_generator(TextureArgsOptions::empty(), f) + } "sin" | "exp" | "exp2" | "sinh" | "cos" | "cosh" | "tan" | "tanh" | "acos" | "asin" | "log" | "log2" | "radians" | "degrees" | "asinh" | "acosh" | "atanh" | "floatBitsToInt" | "floatBitsToUint" | "dFdx" | "dFdxFine" | "dFdxCoarse" | "dFdy" @@ -1244,6 +1346,7 @@ fn inject_common_builtin( ], kind: FunctionKind::Macro(fun), defined: false, + internal: true, void: false, }) } @@ -1434,7 +1537,8 @@ pub enum MacroCall { TextureSize { arrayed: bool, }, - TexelFetch, + ImageLoad, + ImageStore, MathFunction(MathFunction), BitfieldExtract, BitfieldInsert, @@ -1458,17 +1562,17 @@ impl MacroCall { body: &mut Block, args: &mut [Handle], meta: Span, - ) -> Result> { - match *self { + ) -> Result>> { + Ok(Some(match *self { MacroCall::Sampler => { ctx.samplers.insert(args[0], args[1]); - Ok(args[0]) + args[0] } MacroCall::SamplerShadow => { sampled_to_depth(&mut parser.module, ctx, args[0], meta, &mut parser.errors); parser.invalidate_expression(ctx, args[0], meta)?; ctx.samplers.insert(args[0], args[1]); - Ok(args[0]) + args[0] } MacroCall::Texture { proj, @@ -1591,7 +1695,7 @@ impl MacroCall { .map_or(SampleLevel::Auto, SampleLevel::Bias); } - texture_call(ctx, args[0], level, comps, texture_offset, body, meta) + texture_call(ctx, args[0], level, comps, texture_offset, body, meta)? } MacroCall::TextureSize { arrayed } => { @@ -1654,23 +1758,38 @@ impl MacroCall { expr = ctx.add_expression(Expression::Compose { components, ty }, meta, body) } - Ok(expr) + expr } - MacroCall::TexelFetch => { + MacroCall::ImageLoad => { let comps = parser.coordinate_components(ctx, args[0], args[1], None, meta, body)?; - Ok(ctx.add_expression( + ctx.add_expression( Expression::ImageLoad { image: args[0], coordinate: comps.coordinate, array_index: comps.array_index, - index: Some(args[2]), + index: args.get(2).copied(), }, Span::default(), body, - )) + ) + } + MacroCall::ImageStore => { + let comps = + parser.coordinate_components(ctx, args[0], args[1], None, meta, body)?; + ctx.emit_flush(body); + body.push( + crate::Statement::ImageStore { + image: args[0], + coordinate: comps.coordinate, + array_index: comps.array_index, + value: args[2], + }, + meta, + ); + return Ok(None); } - MacroCall::MathFunction(fun) => Ok(ctx.add_expression( + MacroCall::MathFunction(fun) => ctx.add_expression( Expression::Math { fun, arg: args[0], @@ -1680,7 +1799,7 @@ impl MacroCall { }, Span::default(), body, - )), + ), MacroCall::BitfieldInsert => { let conv_arg_2 = ctx.add_expression( Expression::As { @@ -1700,7 +1819,7 @@ impl MacroCall { Span::default(), body, ); - Ok(ctx.add_expression( + ctx.add_expression( Expression::Math { fun: MathFunction::InsertBits, arg: args[0], @@ -1710,7 +1829,7 @@ impl MacroCall { }, Span::default(), body, - )) + ) } MacroCall::BitfieldExtract => { let conv_arg_1 = ctx.add_expression( @@ -1731,7 +1850,7 @@ impl MacroCall { Span::default(), body, ); - Ok(ctx.add_expression( + ctx.add_expression( Expression::Math { fun: MathFunction::ExtractBits, arg: args[0], @@ -1741,17 +1860,17 @@ impl MacroCall { }, Span::default(), body, - )) + ) } - MacroCall::Relational(fun) => Ok(ctx.add_expression( + MacroCall::Relational(fun) => ctx.add_expression( Expression::Relational { fun, argument: args[0], }, Span::default(), body, - )), - MacroCall::Binary(op) => Ok(ctx.add_expression( + ), + MacroCall::Binary(op) => ctx.add_expression( Expression::Binary { op, left: args[0], @@ -1759,11 +1878,11 @@ impl MacroCall { }, Span::default(), body, - )), + ), MacroCall::Mod(size) => { ctx.implicit_splat(parser, &mut args[1], meta, size)?; - Ok(ctx.add_expression( + ctx.add_expression( Expression::Binary { op: BinaryOperator::Modulo, left: args[0], @@ -1771,12 +1890,12 @@ impl MacroCall { }, Span::default(), body, - )) + ) } MacroCall::Splatted(fun, size, i) => { ctx.implicit_splat(parser, &mut args[i], meta, size)?; - Ok(ctx.add_expression( + ctx.add_expression( Expression::Math { fun, arg: args[0], @@ -1786,9 +1905,9 @@ impl MacroCall { }, Span::default(), body, - )) + ) } - MacroCall::MixBoolean => Ok(ctx.add_expression( + MacroCall::MixBoolean => ctx.add_expression( Expression::Select { condition: args[2], accept: args[1], @@ -1796,12 +1915,12 @@ impl MacroCall { }, Span::default(), body, - )), + ), MacroCall::Clamp(size) => { ctx.implicit_splat(parser, &mut args[1], meta, size)?; ctx.implicit_splat(parser, &mut args[2], meta, size)?; - Ok(ctx.add_expression( + ctx.add_expression( Expression::Math { fun: MathFunction::Clamp, arg: args[0], @@ -1811,9 +1930,9 @@ impl MacroCall { }, Span::default(), body, - )) + ) } - MacroCall::BitCast(kind) => Ok(ctx.add_expression( + MacroCall::BitCast(kind) => ctx.add_expression( Expression::As { expr: args[0], kind, @@ -1821,16 +1940,16 @@ impl MacroCall { }, Span::default(), body, - )), - MacroCall::Derivate(axis) => Ok(ctx.add_expression( + ), + MacroCall::Derivate(axis) => ctx.add_expression( Expression::Derivative { axis, expr: args[0], }, Span::default(), body, - )), - } + ), + })) } } @@ -1910,9 +2029,10 @@ impl Parser { TypeInner::Vector { size, .. } => Some(size), _ => None, }; - let shadow = match class { - ImageClass::Depth { .. } => true, - _ => false, + let (shadow, storage) = match class { + ImageClass::Depth { .. } => (true, false), + ImageClass::Storage { .. } => (false, true), + _ => (false, false), }; let coordinate = match (image_size, coord_size) { @@ -1932,18 +2052,17 @@ impl Parser { let mut coord_index = image_size.map_or(1, |s| s as u32); - let array_index = match arrayed { - true => { - let index = coord_index; - coord_index += 1; + let array_index = if arrayed && !(storage && dim == ImageDimension::Cube) { + let index = coord_index; + coord_index += 1; - Some(ctx.add_expression( - Expression::AccessIndex { base: coord, index }, - Span::default(), - body, - )) - } - _ => None, + Some(ctx.add_expression( + Expression::AccessIndex { base: coord, index }, + Span::default(), + body, + )) + } else { + None }; let mut used_extra = false; let depth_ref = match shadow { @@ -2044,9 +2163,9 @@ bitflags::bitflags! { /// Influences the operation `texture_args_generator` struct TextureArgsOptions: u32 { /// Generates multisampled variants of images - const MULTI = 0; + const MULTI = 1 << 0; /// Generates shadow variants of images - const SHADOW = 1; + const SHADOW = 1 << 1; } } @@ -2092,11 +2211,11 @@ fn texture_args_generator( } /// Helper functions used to convert from a image dimension into a integer representing the -/// number of components needed for the coordinates vector (0 means scalar instead of vector) +/// number of components needed for the coordinates vector (1 means scalar instead of vector) fn image_dims_to_coords_size(dim: ImageDimension) -> usize { match dim { - ImageDimension::D1 => 0, - ImageDimension::D2 => 1, - _ => 2, + ImageDimension::D1 => 1, + ImageDimension::D2 => 2, + _ => 3, } } diff --git a/src/front/glsl/functions.rs b/src/front/glsl/functions.rs index 3751e63745..f9c3177a70 100644 --- a/src/front/glsl/functions.rs +++ b/src/front/glsl/functions.rs @@ -674,8 +674,63 @@ impl Parser { let overload_param_ty = &self.module.types[*overload_parameter].inner; let call_arg_ty = self.resolve_type(ctx, call_argument.0, call_argument.1)?; - // If the types match there's no need to check for conversions so continue - if overload_param_ty == call_arg_ty { + // Storage images cannot be directly compared since while the access is part of the + // type in naga's IR, in glsl they are a qualifier and don't enter in the match as + // long as the access needed is satisfied. + if let ( + &TypeInner::Image { + class: + crate::ImageClass::Storage { + format: overload_format, + access: overload_access, + }, + dim: overload_dim, + arrayed: overload_arrayed, + }, + &TypeInner::Image { + class: + crate::ImageClass::Storage { + format: call_format, + access: call_access, + }, + dim: call_dim, + arrayed: call_arrayed, + }, + ) = (overload_param_ty, call_arg_ty) + { + // Images size must match otherwise the overload isn't what we want + let good_size = call_dim == overload_dim && call_arrayed == overload_arrayed; + // Glsl requires the formats to strictly match unless you are builtin + // function overload and have not been replaced, in which case we only + // check that the format scalar kind matches + let good_format = overload_format == call_format + || (overload.internal + && ScalarKind::from(overload_format) == ScalarKind::from(call_format)); + if !(good_size && good_format) { + continue 'outer; + } + + // While storage access mismatch is an error it isn't one that causes + // the overload matching to fail so we defer the error and consider + // that the images match exactly + if !call_access.contains(overload_access) { + self.errors.push(Error { + kind: ErrorKind::SemanticError( + format!( + "'{}': image needs {:?} access but only {:?} was provided", + name, overload_access, call_access + ) + .into(), + ), + meta, + }); + } + + // The images satisfy the conditions to be considered as an exact match + new_conversions[i] = Conversion::Exact; + continue; + } else if overload_param_ty == call_arg_ty { + // If the types match there's no need to check for conversions so continue new_conversions[i] = Conversion::Exact; continue; } @@ -957,9 +1012,9 @@ impl Parser { Ok(result) } - FunctionKind::Macro(builtin) => builtin - .call(self, ctx, body, arguments.as_mut_slice(), meta) - .map(Some), + FunctionKind::Macro(builtin) => { + builtin.call(self, ctx, body, arguments.as_mut_slice(), meta) + } } } @@ -1055,6 +1110,7 @@ impl Parser { parameters_info, kind: FunctionKind::Call(handle), defined: true, + internal: false, void, }); } @@ -1130,6 +1186,7 @@ impl Parser { parameters_info, kind: FunctionKind::Call(handle), defined: false, + internal: false, void, }); } diff --git a/src/front/glsl/parser/types.rs b/src/front/glsl/parser/types.rs index 3fb1f355c4..47ad230d39 100644 --- a/src/front/glsl/parser/types.rs +++ b/src/front/glsl/parser/types.rs @@ -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,56 @@ impl<'source> ParsingContext<'source> { }) } } + +fn map_image_format(word: &str) -> Option { + use crate::StorageFormat as Sf; + + let format = match word { + // float-image-format-qualifier: + "rgba32f" => Sf::Rgba32Float, + "rgba16f" => Sf::Rgba16Float, + "rg32f" => Sf::Rg32Float, + "rg16f" => Sf::Rg16Float, + "r11f_g11f_b10f" => Sf::Rg11b10Float, + "r32f" => Sf::R32Float, + "r16f" => Sf::R16Float, + "rgba16" => Sf::Rgba16Float, + "rgb10_a2" => Sf::Rgb10a2Unorm, + "rgba8" => Sf::Rgba8Unorm, + "rg16" => Sf::Rg16Float, + "rg8" => Sf::Rg8Unorm, + "r16" => Sf::R16Float, + "r8" => Sf::R8Unorm, + "rgba8_snorm" => Sf::Rgba8Snorm, + "rg8_snorm" => Sf::Rg8Snorm, + "r8_snorm" => Sf::R8Snorm, + // int-image-format-qualifier: + "rgba32i" => Sf::Rgba32Sint, + "rgba16i" => Sf::Rgba16Sint, + "rgba8i" => Sf::Rgba8Sint, + "rg32i" => Sf::Rg32Sint, + "rg16i" => Sf::Rg16Sint, + "rg8i" => Sf::Rg8Sint, + "r32i" => Sf::R32Sint, + "r16i" => Sf::R16Sint, + "r8i" => Sf::R8Sint, + // uint-image-format-qualifier: + "rgba32ui" => Sf::Rgba32Uint, + "rgba16ui" => Sf::Rgba16Uint, + "rgba8ui" => Sf::Rgba8Uint, + "rg32ui" => Sf::Rg32Uint, + "rg16ui" => Sf::Rg16Uint, + "rg8ui" => Sf::Rg8Uint, + "r32ui" => Sf::R32Uint, + "r16ui" => Sf::R16Uint, + "r8ui" => Sf::R8Uint, + // TODO: These next ones seem incorrect to me + // "rgba16_snorm" => Sf::Rgba16Float, + // "rg16_snorm" => Sf::Rg16Float, + // "r16_snorm" => Sf::R16Float, + // "rgb10_a2ui" => Sf::Rgb10a2Unorm, + _ => return None, + }; + + Some(format) +} diff --git a/src/front/glsl/types.rs b/src/front/glsl/types.rs index becc53ad6c..3900fe12d8 100644 --- a/src/front/glsl/types.rs +++ b/src/front/glsl/types.rs @@ -150,9 +150,56 @@ pub fn parse_type(type_name: &str) -> Option { }) }; + 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()?; + // TODO: Check that the texture format and the kind match + let _ = texture_kind(kind)?; + + let class = ImageClass::Storage { + format: crate::StorageFormat::R8Uint, + 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)) } } } diff --git a/src/front/glsl/variables.rs b/src/front/glsl/variables.rs index 072b9f4740..182097b74b 100644 --- a/src/front/glsl/variables.rs +++ b/src/front/glsl/variables.rs @@ -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, _ => {} }; diff --git a/tests/in/glsl/images.frag b/tests/in/glsl/images.frag new file mode 100644 index 0000000000..41679b9218 --- /dev/null +++ b/tests/in/glsl/images.frag @@ -0,0 +1,55 @@ +#version 460 core + +layout(rgba8, binding = 0) uniform image1D img1D; +layout(rgba8, binding = 1) uniform image2D img2D; +layout(rgba8, binding = 2) uniform image3D img3D; +// layout(rgba8, binding = 3) uniform imageCube imgCube; +layout(rgba8, binding = 4) uniform image1DArray img1DArray; +layout(rgba8, binding = 5) uniform image2DArray img2DArray; +// layout(rgba8, binding = 6) uniform imageCubeArray imgCubeArray; + +void testImg1D(in int coord) { + int size = imageSize(img1D); + vec4 c = imageLoad(img1D, coord); + imageStore(img1D, coord, vec4(2)); +} + +void testImg1DArray(in ivec2 coord) { + vec2 size = imageSize(img1DArray); + vec4 c = imageLoad(img1DArray, coord); + imageStore(img1DArray, coord, vec4(2)); +} + +void testImg2D(in ivec2 coord) { + vec2 size = imageSize(img2D); + vec4 c = imageLoad(img2D, coord); + imageStore(img2D, coord, vec4(2)); +} + +void testImg2DArray(in ivec3 coord) { + vec3 size = imageSize(img2DArray); + vec4 c = imageLoad(img2DArray, coord); + imageStore(img2DArray, coord, vec4(2)); +} + +void testImg3D(in ivec3 coord) { + vec3 size = imageSize(img3D); + vec4 c = imageLoad(img3D, coord); + imageStore(img3D, coord, vec4(2)); +} + +// Naga doesn't support cube images and it's usefulness +// is questionable, so they won't be supported for now +// void testImgCube(in ivec3 coord) { +// vec2 size = imageSize(imgCube); +// vec4 c = imageLoad(imgCube, coord); +// imageStore(imgCube, coord, vec4(2)); +// } +// +// void testImgCubeArray(in ivec3 coord) { +// vec3 size = imageSize(imgCubeArray); +// vec4 c = imageLoad(imgCubeArray, coord); +// imageStore(imgCubeArray, coord, vec4(2)); +// } + +void main() {} diff --git a/tests/out/wgsl/images-frag.wgsl b/tests/out/wgsl/images-frag.wgsl new file mode 100644 index 0000000000..bd11927f01 --- /dev/null +++ b/tests/out/wgsl/images-frag.wgsl @@ -0,0 +1,102 @@ +@group(0) @binding(0) +var img1D: texture_storage_1d; +@group(0) @binding(1) +var img2D: texture_storage_2d; +@group(0) @binding(2) +var img3D: texture_storage_3d; +@group(0) @binding(4) +var img1DArray: texture_storage_1d_array; +@group(0) @binding(5) +var img2DArray: texture_storage_2d_array; + +fn testImg1D(coord: i32) { + var coord_1: i32; + var size: i32; + var c: vec4; + + coord_1 = coord; + let _e7 = textureDimensions(img1D); + size = _e7; + let _e10 = coord_1; + let _e11 = textureLoad(img1D, _e10); + c = _e11; + let _e17 = coord_1; + textureStore(img1D, _e17, vec4(f32(2))); + return; +} + +fn testImg1DArray(coord_2: vec2) { + var coord_3: vec2; + var size_1: vec2; + var c_1: vec4; + + coord_3 = coord_2; + let _e7 = textureDimensions(img1DArray); + let _e8 = textureNumLayers(img1DArray); + size_1 = vec2(vec2(_e7, _e8)); + let _e13 = coord_3; + let _e16 = textureLoad(img1DArray, _e13.x, _e13.y); + c_1 = _e16; + let _e22 = coord_3; + textureStore(img1DArray, _e22.x, _e22.y, vec4(f32(2))); + return; +} + +fn testImg2D(coord_4: vec2) { + var coord_5: vec2; + var size_2: vec2; + var c_2: vec4; + + coord_5 = coord_4; + let _e7 = textureDimensions(img2D); + size_2 = vec2(_e7); + let _e11 = coord_5; + let _e12 = textureLoad(img2D, _e11); + c_2 = _e12; + let _e18 = coord_5; + textureStore(img2D, _e18, vec4(f32(2))); + return; +} + +fn testImg2DArray(coord_6: vec3) { + var coord_7: vec3; + var size_3: vec3; + var c_3: vec4; + + coord_7 = coord_6; + let _e7 = textureDimensions(img2DArray); + let _e10 = textureNumLayers(img2DArray); + size_3 = vec3(vec3(_e7.x, _e7.y, _e10)); + let _e15 = coord_7; + let _e18 = textureLoad(img2DArray, _e15.xy, _e15.z); + c_3 = _e18; + let _e24 = coord_7; + textureStore(img2DArray, _e24.xy, _e24.z, vec4(f32(2))); + return; +} + +fn testImg3D(coord_8: vec3) { + var coord_9: vec3; + var size_4: vec3; + var c_4: vec4; + + coord_9 = coord_8; + let _e7 = textureDimensions(img3D); + size_4 = vec3(_e7); + let _e11 = coord_9; + let _e12 = textureLoad(img3D, _e11); + c_4 = _e12; + let _e18 = coord_9; + textureStore(img3D, _e18, vec4(f32(2))); + return; +} + +fn main_1() { + return; +} + +@stage(fragment) +fn main() { + main_1(); + return; +}