From 954cbaaff36503d1336a99991adf37a6c3d53884 Mon Sep 17 00:00:00 2001 From: Patryk Wychowaniec Date: Wed, 25 Jan 2023 17:49:52 +0100 Subject: [PATCH] [spv-in] Support binding arrays (#2199) --- src/front/spv/error.rs | 7 +- src/front/spv/image.rs | 30 +++- src/front/spv/mod.rs | 191 +++++++++++++++------ tests/in/spv/binding-arrays.dynamic.spv | Bin 0 -> 720 bytes tests/in/spv/binding-arrays.dynamic.spvasm | 75 ++++++++ tests/in/spv/binding-arrays.static.spv | Bin 0 -> 760 bytes tests/in/spv/binding-arrays.static.spvasm | 78 +++++++++ tests/out/wgsl/binding-arrays.dynamic.wgsl | 18 ++ tests/out/wgsl/binding-arrays.static.wgsl | 18 ++ tests/snapshots.rs | 7 +- 10 files changed, 366 insertions(+), 58 deletions(-) create mode 100644 tests/in/spv/binding-arrays.dynamic.spv create mode 100644 tests/in/spv/binding-arrays.dynamic.spvasm create mode 100644 tests/in/spv/binding-arrays.static.spv create mode 100644 tests/in/spv/binding-arrays.static.spvasm create mode 100644 tests/out/wgsl/binding-arrays.dynamic.wgsl create mode 100644 tests/out/wgsl/binding-arrays.static.wgsl diff --git a/src/front/spv/error.rs b/src/front/spv/error.rs index 3877590c40..6c9cf384f1 100644 --- a/src/front/spv/error.rs +++ b/src/front/spv/error.rs @@ -118,5 +118,10 @@ pub enum Error { InvalidBarrierScope(spirv::Word), #[error("invalid barrier memory semantics %{0}")] InvalidBarrierMemorySemantics(spirv::Word), - // incomplete implementation errors + #[error( + "arrays of images / samplers are supported only through bindings for \ + now (i.e. you can't create an array of images or samplers that doesn't \ + come from a binding)" + )] + NonBindingArrayOfImageOrSamplers, } diff --git a/src/front/spv/image.rs b/src/front/spv/image.rs index c45288ab15..07681917b1 100644 --- a/src/front/spv/image.rs +++ b/src/front/spv/image.rs @@ -536,19 +536,47 @@ impl> super::Parser { ctx.global_arena[handle].ty } + crate::Expression::FunctionArgument(i) => { ctx.parameter_sampling[i as usize] |= sampling_bit; ctx.arguments[i as usize].ty } + + crate::Expression::Access { base, .. } => match ctx.expressions[base] { + crate::Expression::GlobalVariable(handle) => { + if let Some(flags) = self.handle_sampling.get_mut(&handle) { + *flags |= sampling_bit; + } + + match ctx.type_arena[ctx.global_arena[handle].ty].inner { + crate::TypeInner::BindingArray { base, .. } => base, + _ => return Err(Error::InvalidGlobalVar(ctx.expressions[base].clone())), + } + } + + ref other => return Err(Error::InvalidGlobalVar(other.clone())), + }, + ref other => return Err(Error::InvalidGlobalVar(other.clone())), }; + match ctx.expressions[si_lexp.sampler] { crate::Expression::GlobalVariable(handle) => { - *self.handle_sampling.get_mut(&handle).unwrap() |= sampling_bit + *self.handle_sampling.get_mut(&handle).unwrap() |= sampling_bit; } + crate::Expression::FunctionArgument(i) => { ctx.parameter_sampling[i as usize] |= sampling_bit; } + + crate::Expression::Access { base, .. } => match ctx.expressions[base] { + crate::Expression::GlobalVariable(handle) => { + *self.handle_sampling.get_mut(&handle).unwrap() |= sampling_bit; + } + + ref other => return Err(Error::InvalidGlobalVar(other.clone())), + }, + ref other => return Err(Error::InvalidGlobalVar(other.clone())), } diff --git a/src/front/spv/mod.rs b/src/front/spv/mod.rs index 944d685935..b51f10f231 100644 --- a/src/front/spv/mod.rs +++ b/src/front/spv/mod.rs @@ -106,7 +106,7 @@ impl Instruction { } impl crate::TypeInner { - const fn can_comparison_sample(&self) -> bool { + fn can_comparison_sample(&self, module: &crate::Module) -> bool { match *self { crate::TypeInner::Image { class: @@ -117,6 +117,9 @@ impl crate::TypeInner { .. } => true, crate::TypeInner::Sampler { .. } => true, + crate::TypeInner::BindingArray { base, .. } => { + module.types[base].inner.can_comparison_sample(module) + } _ => false, } } @@ -1428,17 +1431,38 @@ impl> Parser { let result_id = self.next()?; let base_id = self.next()?; log::trace!("\t\t\tlooking up expr {:?}", base_id); + let mut acex = { - // the base type has to be a pointer, - // so we dereference it here for the traversal let lexp = self.lookup_expression.lookup(base_id)?; let lty = self.lookup_type.lookup(lexp.type_id)?; + + // HACK `OpAccessChain` and `OpInBoundsAccessChain` + // require for the result type to be a pointer, but if + // we're given a pointer to an image / sampler, it will + // be *already* dereferenced, since we do that early + // during `parse_type_pointer()`. + // + // This can happen only through `BindingArray`, since + // that's the only case where one can obtain a pointer + // to an image / sampler, and so let's match on that: + let dereference = match ctx.type_arena[lty.handle].inner { + crate::TypeInner::BindingArray { .. } => false, + _ => true, + }; + + let type_id = if dereference { + lty.base_id.ok_or(Error::InvalidAccessType(lexp.type_id))? + } else { + lexp.type_id + }; + AccessExpression { base_handle: get_expr_handle!(base_id, lexp), - type_id: lty.base_id.ok_or(Error::InvalidAccessType(lexp.type_id))?, + type_id, load_override: self.lookup_load_override.get(&base_id).cloned(), } }; + for _ in 4..inst.wc { let access_id = self.next()?; log::trace!("\t\t\tlooking up index expr {:?}", access_id); @@ -4220,6 +4244,7 @@ impl> Parser { let decor = self.future_decor.remove(&id); let base_lookup_ty = self.lookup_type.lookup(type_id)?; let base_inner = &module.types[base_lookup_ty.handle].inner; + let space = if let Some(space) = base_inner.pointer_space() { space } else if self @@ -4289,17 +4314,60 @@ impl> Parser { let decor = self.future_decor.remove(&id).unwrap_or_default(); let base = self.lookup_type.lookup(type_id)?.handle; + self.layouter .update(&module.types, &module.constants) .unwrap(); - let inner = crate::TypeInner::Array { - base, - size: crate::ArraySize::Constant(length_const.handle), - stride: match decor.array_stride { - Some(stride) => stride.get(), - None => self.layouter[base].to_stride(), - }, + + // HACK if the underlying type is an image or a sampler, let's assume + // that we're dealing with a binding-array + // + // Note that it's not a strictly correct assumption, but rather a trade + // off caused by an impedance mismatch between SPIR-V's and Naga's type + // systems - Naga distinguishes between arrays and binding-arrays via + // types (i.e. both kinds of arrays are just different types), while + // SPIR-V distinguishes between them through usage - e.g. given: + // + // ``` + // %image = OpTypeImage %float 2D 2 0 0 2 Rgba16f + // %uint_256 = OpConstant %uint 256 + // %image_array = OpTypeArray %image %uint_256 + // ``` + // + // ``` + // %image = OpTypeImage %float 2D 2 0 0 2 Rgba16f + // %uint_256 = OpConstant %uint 256 + // %image_array = OpTypeArray %image %uint_256 + // %image_array_ptr = OpTypePointer UniformConstant %image_array + // ``` + // + // ... in the first case, `%image_array` should technically correspond + // to `TypeInner::Array`, while in the second case it should say + // `TypeInner::BindingArray` (kinda, depending on whether `%image_array` + // is ever used as a freestanding type or rather always through the + // pointer-indirection). + // + // Anyway, at the moment we don't support other kinds of image / sampler + // arrays than those binding-based, so this assumption is pretty safe + // for now. + let inner = if let crate::TypeInner::Image { .. } | crate::TypeInner::Sampler { .. } = + module.types[base].inner + { + crate::TypeInner::BindingArray { + base, + size: crate::ArraySize::Constant(length_const.handle), + } + } else { + crate::TypeInner::Array { + base, + size: crate::ArraySize::Constant(length_const.handle), + stride: match decor.array_stride { + Some(stride) => stride.get(), + None => self.layouter[base].to_stride(), + }, + } }; + self.lookup_type.insert( id, LookupType { @@ -4329,17 +4397,30 @@ impl> Parser { let decor = self.future_decor.remove(&id).unwrap_or_default(); let base = self.lookup_type.lookup(type_id)?.handle; + self.layouter .update(&module.types, &module.constants) .unwrap(); - let inner = crate::TypeInner::Array { - base: self.lookup_type.lookup(type_id)?.handle, - size: crate::ArraySize::Dynamic, - stride: match decor.array_stride { - Some(stride) => stride.get(), - None => self.layouter[base].to_stride(), - }, + + // HACK same case as in `parse_type_array()` + let inner = if let crate::TypeInner::Image { .. } | crate::TypeInner::Sampler { .. } = + module.types[base].inner + { + crate::TypeInner::BindingArray { + base: self.lookup_type.lookup(type_id)?.handle, + size: crate::ArraySize::Dynamic, + } + } else { + crate::TypeInner::Array { + base: self.lookup_type.lookup(type_id)?.handle, + size: crate::ArraySize::Dynamic, + stride: match decor.array_stride { + Some(stride) => stride.get(), + None => self.layouter[base].to_stride(), + }, + } }; + self.lookup_type.insert( id, LookupType { @@ -4793,32 +4874,45 @@ impl> Parser { let mut dec = self.future_decor.remove(&id).unwrap_or_default(); let original_ty = self.lookup_type.lookup(type_id)?.handle; - let mut effective_ty = original_ty; + let mut ty = original_ty; + if let crate::TypeInner::Pointer { base, space: _ } = module.types[original_ty].inner { - effective_ty = base; - }; + ty = base; + } + + if let crate::TypeInner::BindingArray { .. } = module.types[original_ty].inner { + // Inside `parse_type_array()` we guess that an array of images or + // samplers must be a binding array, and here we validate that guess + if dec.desc_set.is_none() || dec.desc_index.is_none() { + return Err(Error::NonBindingArrayOfImageOrSamplers); + } + } + if let crate::TypeInner::Image { dim, arrayed, class: crate::ImageClass::Storage { format, access: _ }, - } = module.types[effective_ty].inner + } = module.types[ty].inner { // Storage image types in IR have to contain the access, but not in the SPIR-V. // The same image type in SPIR-V can be used (and has to be used) for multiple images. // So we copy the type out and apply the variable access decorations. let access = dec.flags.to_storage_access(); - let ty = crate::Type { - name: None, - inner: crate::TypeInner::Image { - dim, - arrayed, - class: crate::ImageClass::Storage { format, access }, + + ty = module.types.insert( + crate::Type { + name: None, + inner: crate::TypeInner::Image { + dim, + arrayed, + class: crate::ImageClass::Storage { format, access }, + }, }, - }; - effective_ty = module.types.insert(ty, Default::default()); + Default::default(), + ); } - let ext_class = match self.lookup_storage_buffer_types.get(&effective_ty) { + let ext_class = match self.lookup_storage_buffer_types.get(&ty) { Some(&access) => ExtendedClass::Global(crate::AddressSpace::Storage { access }), None => map_storage_class(storage_class)?, }; @@ -4843,14 +4937,14 @@ impl> Parser { binding: dec.resource_binding(), name: dec.name, space, - ty: effective_ty, + ty, init, }; (Variable::Global, var) } ExtendedClass::Input => { let mut binding = dec.io_binding()?; - let mut unsigned_ty = effective_ty; + let mut unsigned_ty = ty; if let crate::Binding::BuiltIn(built_in) = binding { let needs_inner_uint = match built_in { crate::BuiltIn::BaseInstance @@ -4873,10 +4967,9 @@ impl> Parser { }), _ => None, }; - if let (Some(inner), Some(crate::ScalarKind::Sint)) = ( - needs_inner_uint, - module.types[effective_ty].inner.scalar_kind(), - ) { + if let (Some(inner), Some(crate::ScalarKind::Sint)) = + (needs_inner_uint, module.types[ty].inner.scalar_kind()) + { unsigned_ty = module .types .insert(crate::Type { name: None, inner }, Default::default()); @@ -4887,7 +4980,7 @@ impl> Parser { name: dec.name.clone(), space: crate::AddressSpace::Private, binding: None, - ty: effective_ty, + ty, init: None, }; @@ -4907,7 +5000,7 @@ impl> Parser { Some(crate::Binding::BuiltIn(built_in)) => { match null::generate_default_built_in( Some(built_in), - effective_ty, + ty, &module.types, &mut module.constants, span, @@ -4920,7 +5013,7 @@ impl> Parser { } } Some(crate::Binding::Location { .. }) => None, - None => match module.types[effective_ty].inner { + None => match module.types[ty].inner { crate::TypeInner::Struct { ref members, .. } => { // A temporary to avoid borrowing `module.types` let pairs = members @@ -4949,10 +5042,7 @@ impl> Parser { crate::Constant { name: None, specialization: None, - inner: crate::ConstantInner::Composite { - ty: effective_ty, - components, - }, + inner: crate::ConstantInner::Composite { ty, components }, }, span, )) @@ -4965,23 +5055,22 @@ impl> Parser { name: dec.name, space: crate::AddressSpace::Private, binding: None, - ty: effective_ty, + ty, init, }; if let Some(ref mut binding) = binding { - binding.apply_default_interpolation(&module.types[effective_ty].inner); + binding.apply_default_interpolation(&module.types[ty].inner); } - let inner = Variable::Output(crate::FunctionResult { - ty: effective_ty, - binding, - }); + let inner = Variable::Output(crate::FunctionResult { ty, binding }); (inner, var) } }; let handle = module.global_variables.append(var, span); - if module.types[effective_ty].inner.can_comparison_sample() { + + if module.types[ty].inner.can_comparison_sample(module) { log::debug!("\t\ttracking {:?} for sampling properties", handle); + self.handle_sampling .insert(handle, image::SamplingFlags::empty()); } diff --git a/tests/in/spv/binding-arrays.dynamic.spv b/tests/in/spv/binding-arrays.dynamic.spv new file mode 100644 index 0000000000000000000000000000000000000000..12bf2e00edf3048a9814efb67dedbf59fbe90ded GIT binary patch literal 720 zcmYk3%T5A85Jk&D8SueF1O!9}S;Cr_7$v~$!vF7*4|n0U@icS0q1s_(6?>O0-7 zVqHf2C?d+J_!`3~LZuh2n)~TTCyvSL-=AMUY6WnI`hZn4CE^X`1g)KFa@U94-g{tJ zm#=EpaOWP@<<>pJ{hoOXj1k=>d4h)yxdKymbjfmO%TE)xw}PLMovXfqyZ0Or`z?Q9 z{{>JJc~6hEF{YuU+@eWypSzN?!1J~-9)xdZCHhiCW(&rH^zwLhFafPY2) B5-I=y literal 0 HcmV?d00001 diff --git a/tests/in/spv/binding-arrays.dynamic.spvasm b/tests/in/spv/binding-arrays.dynamic.spvasm new file mode 100644 index 0000000000..d1c38a8324 --- /dev/null +++ b/tests/in/spv/binding-arrays.dynamic.spvasm @@ -0,0 +1,75 @@ +;; Make sure that we promote `OpTypeRuntimeArray` of textures and samplers into +;; `TypeInner::BindingArray` and support indexing it through `OpAccessChain` +;; and `OpInBoundsAccessChain`. +;; +;; Code in here corresponds to, more or less: +;; +;; ```rust +;; #[spirv(fragment)] +;; pub fn main( +;; #[spirv(descriptor_set = 0, binding = 0)] +;; images: &RuntimeArray, +;; #[spirv(descriptor_set = 0, binding = 1)] +;; samplers: &RuntimeArray, +;; out: &mut Vec4, +;; ) { +;; let image = images[1]; +;; let sampler = samplers[1]; +;; +;; *out = image.sample_by_lod(sampler, vec2(0.5, 0.5), 0.0); +;; } +;; ``` + + OpCapability Shader + OpMemoryModel Logical Simple + OpEntryPoint Fragment %main "main" %fn_param_images %fn_param_samplers %fn_param_out + OpExecutionMode %main OriginUpperLeft + OpDecorate %images ArrayStride 4 + OpDecorate %samplers ArrayStride 4 + OpDecorate %fn_param_images DescriptorSet 0 + OpDecorate %fn_param_images Binding 0 + OpDecorate %fn_param_samplers DescriptorSet 0 + OpDecorate %fn_param_samplers Binding 1 + OpDecorate %fn_param_out Location 0 + + %void = OpTypeVoid + + %float = OpTypeFloat 32 + %v2float = OpTypeVector %float 2 + %v4float = OpTypeVector %float 4 + %v4float_ptr = OpTypePointer Output %v4float + %float_0_5 = OpConstant %float 0.5 + %float_0_5_0_5 = OpConstantComposite %v2float %float_0_5 %float_0_5 + %float_0 = OpConstant %float 0 + + %int = OpTypeInt 32 1 + %int_1 = OpConstant %int 1 + + %image = OpTypeImage %float 2D 2 0 0 1 Unknown + %image_ptr = OpTypePointer UniformConstant %image + %images = OpTypeRuntimeArray %image + %images_ptr = OpTypePointer UniformConstant %images + + %sampler = OpTypeSampler + %sampler_ptr = OpTypePointer UniformConstant %sampler + %samplers = OpTypeRuntimeArray %sampler + %samplers_ptr = OpTypePointer UniformConstant %samplers + + %sampled_image = OpTypeSampledImage %image + + %fn_void = OpTypeFunction %void +%fn_param_images = OpVariable %images_ptr UniformConstant +%fn_param_samplers = OpVariable %samplers_ptr UniformConstant + %fn_param_out = OpVariable %v4float_ptr Output + + %main = OpFunction %void None %fn_void + %main_prelude = OpLabel + %1 = OpAccessChain %image_ptr %fn_param_images %int_1 + %2 = OpInBoundsAccessChain %sampler_ptr %fn_param_samplers %int_1 + %3 = OpLoad %sampler %2 + %4 = OpLoad %image %1 + %5 = OpSampledImage %sampled_image %4 %3 + %6 = OpImageSampleExplicitLod %v4float %5 %float_0_5_0_5 Lod %float_0 + OpStore %fn_param_out %6 + OpReturn + OpFunctionEnd diff --git a/tests/in/spv/binding-arrays.static.spv b/tests/in/spv/binding-arrays.static.spv new file mode 100644 index 0000000000000000000000000000000000000000..0d3c304af4221791cc5192332be859c6c4c677ab GIT binary patch literal 760 zcmYk3$xZ`73`ETYGGWU?HnIRcaD+2LiV_4D{s3|1$N|2e3li@o-BK*o*i~-3J?>U@ zS4aCGBI>y1s|}(Gm2R}Q+)pn$afny{{`~q;tAHoe`$W4g5pO6*XziSn8}D;#%YEkM z4bbHF-OtO-dxv@Nyaw8k>KZ?xs)J8p%86sV+}`q&%&krEQ@nlE@8O<31K9Hee_;JN zP!r`$mslH9)59m=T;}Ed%*_vo6VS}dFC-MqxM4`>z1BNtF}dcPqg}W?yM()2>+EBG zob&2)x=gY@&AQw=_itS4E^}Ue!6s&S`!>XLygOax{$)0~b?!}*yGM7b_Q-VBmHF-S z%S;RW3pxK~3GC;dUeTQM3RthUrkiv6zUp%4x&hX{Q{$`&sCn*#TYbj{B;dPwhi|o^ Mv-6qzW3ngk58vw(F#rGn literal 0 HcmV?d00001 diff --git a/tests/in/spv/binding-arrays.static.spvasm b/tests/in/spv/binding-arrays.static.spvasm new file mode 100644 index 0000000000..d08fe72061 --- /dev/null +++ b/tests/in/spv/binding-arrays.static.spvasm @@ -0,0 +1,78 @@ +;; Make sure that we promote `OpTypeArray` of textures and samplers into +;; `TypeInner::BindingArray` and support indexing it through `OpAccessChain` +;; and `OpInBoundsAccessChain`. +;; +;; Code in here corresponds to, more or less: +;; +;; ```rust +;; #[spirv(fragment)] +;; pub fn main( +;; #[spirv(descriptor_set = 0, binding = 0)] +;; images: &[Image!(2D, type=f32, sampled); 256], +;; #[spirv(descriptor_set = 0, binding = 1)] +;; samplers: &[Sampler; 256], +;; out: &mut Vec4, +;; ) { +;; let image = images[1]; +;; let sampler = samplers[1]; +;; +;; *out = image.sample_by_lod(sampler, vec2(0.5, 0.5), 0.0); +;; } +;; ``` + + OpCapability Shader + OpMemoryModel Logical Simple + OpEntryPoint Fragment %main "main" %fn_param_images %fn_param_samplers %fn_param_out + OpExecutionMode %main OriginUpperLeft + OpDecorate %images ArrayStride 4 + OpDecorate %samplers ArrayStride 4 + OpDecorate %fn_param_images DescriptorSet 0 + OpDecorate %fn_param_images Binding 0 + OpDecorate %fn_param_samplers DescriptorSet 0 + OpDecorate %fn_param_samplers Binding 1 + OpDecorate %fn_param_out Location 0 + + %void = OpTypeVoid + + %float = OpTypeFloat 32 + %v2float = OpTypeVector %float 2 + %v4float = OpTypeVector %float 4 + %v4float_ptr = OpTypePointer Output %v4float + %float_0_5 = OpConstant %float 0.5 + %float_0_5_0_5 = OpConstantComposite %v2float %float_0_5 %float_0_5 + %float_0 = OpConstant %float 0 + + %int = OpTypeInt 32 1 + %int_1 = OpConstant %int 1 + + %uint = OpTypeInt 32 0 + %uint_256 = OpConstant %uint 256 + + %image = OpTypeImage %float 2D 2 0 0 1 Unknown + %image_ptr = OpTypePointer UniformConstant %image + %images = OpTypeArray %image %uint_256 + %images_ptr = OpTypePointer UniformConstant %images + + %sampler = OpTypeSampler + %sampler_ptr = OpTypePointer UniformConstant %sampler + %samplers = OpTypeArray %sampler %uint_256 + %samplers_ptr = OpTypePointer UniformConstant %samplers + + %sampled_image = OpTypeSampledImage %image + + %fn_void = OpTypeFunction %void +%fn_param_images = OpVariable %images_ptr UniformConstant +%fn_param_samplers = OpVariable %samplers_ptr UniformConstant + %fn_param_out = OpVariable %v4float_ptr Output + + %main = OpFunction %void None %fn_void + %main_prelude = OpLabel + %1 = OpAccessChain %image_ptr %fn_param_images %int_1 + %2 = OpInBoundsAccessChain %sampler_ptr %fn_param_samplers %int_1 + %3 = OpLoad %sampler %2 + %4 = OpLoad %image %1 + %5 = OpSampledImage %sampled_image %4 %3 + %6 = OpImageSampleExplicitLod %v4float %5 %float_0_5_0_5 Lod %float_0 + OpStore %fn_param_out %6 + OpReturn + OpFunctionEnd diff --git a/tests/out/wgsl/binding-arrays.dynamic.wgsl b/tests/out/wgsl/binding-arrays.dynamic.wgsl new file mode 100644 index 0000000000..523b311276 --- /dev/null +++ b/tests/out/wgsl/binding-arrays.dynamic.wgsl @@ -0,0 +1,18 @@ +@group(0) @binding(0) +var global: binding_array>; +@group(0) @binding(1) +var global_1: binding_array; +var global_2: vec4; + +fn function() { + let _e13 = textureSampleLevel(global[1], global_1[1], vec2(0.5, 0.5), 0.0); + global_2 = _e13; + return; +} + +@fragment +fn main() -> @location(0) vec4 { + function(); + let _e1 = global_2; + return _e1; +} diff --git a/tests/out/wgsl/binding-arrays.static.wgsl b/tests/out/wgsl/binding-arrays.static.wgsl new file mode 100644 index 0000000000..c669e9aa6f --- /dev/null +++ b/tests/out/wgsl/binding-arrays.static.wgsl @@ -0,0 +1,18 @@ +@group(0) @binding(0) +var global: binding_array,256u>; +@group(0) @binding(1) +var global_1: binding_array; +var global_2: vec4; + +fn function() { + let _e14 = textureSampleLevel(global[1], global_1[1], vec2(0.5, 0.5), 0.0); + global_2 = _e14; + return; +} + +@fragment +fn main() -> @location(0) vec4 { + function(); + let _e1 = global_2; + return _e1; +} diff --git a/tests/snapshots.rs b/tests/snapshots.rs index 34c881f0b6..706e714b0a 100644 --- a/tests/snapshots.rs +++ b/tests/snapshots.rs @@ -607,12 +607,9 @@ fn convert_spv_all() { true, Targets::HLSL | Targets::WGSL | Targets::METAL, ); - convert_spv( - "empty-global-name", - true, - Targets::HLSL | Targets::WGSL | Targets::METAL, - ); convert_spv("degrees", false, Targets::empty()); + convert_spv("binding-arrays.dynamic", true, Targets::WGSL); + convert_spv("binding-arrays.static", true, Targets::WGSL); } #[cfg(feature = "glsl-in")]