From 2f7ebf1401abcc8a3cd53c32ab71a3a0794c1f5e Mon Sep 17 00:00:00 2001 From: Nils Hasenbanck Date: Thu, 25 Sep 2025 14:25:04 +0200 Subject: [PATCH] (Naga) Add support for Descriptor Runtime Indexing when ingesting SPIR-V (#8256) --- CHANGELOG.md | 1 + naga/src/front/spv/mod.rs | 2 + .../tests/in/spv/binding-arrays.runtime.slang | 19 ++++++ .../in/spv/binding-arrays.runtime.spvasm | 60 +++++++++++++++++++ naga/tests/in/spv/binding-arrays.runtime.toml | 4 ++ .../out/wgsl/spv-binding-arrays.runtime.wgsl | 24 ++++++++ 6 files changed, 110 insertions(+) create mode 100644 naga/tests/in/spv/binding-arrays.runtime.slang create mode 100644 naga/tests/in/spv/binding-arrays.runtime.spvasm create mode 100644 naga/tests/in/spv/binding-arrays.runtime.toml create mode 100644 naga/tests/out/wgsl/spv-binding-arrays.runtime.wgsl diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c138ac1d..f57189c3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -198,6 +198,7 @@ By @cwfitzgerald in [#8162](https://github.com/gfx-rs/wgpu/pull/8162). - For custom Naga backend authors: `naga::proc::Namer` now accepts reserved keywords using two new dedicated types, `proc::{KeywordSet, CaseInsensitiveKeywordSet}`. By @kpreid in [#8136](https://github.com/gfx-rs/wgpu/pull/8136). - **BREAKING**: Previously the WGSL storage-texture format `rg11b10float` was incorrectly accepted and generated by naga, but now only accepts the the correct name `rg11b10ufloat` instead. By @ErikWDev in [#8219](https://github.com/gfx-rs/wgpu/pull/8219). - The [`source()`](https://doc.rust-lang.org/std/error/trait.Error.html#method.source) method of `ShaderError` no longer reports the error as its own source. By @andyleiserson in [#8258](https://github.com/gfx-rs/wgpu/pull/8258). +- naga correctly ingests SPIR-V that use descriptor runtime indexing, which in turn is correctly converted into WGSLs binding array. By @hasenbanck in [8256](https://github.com/gfx-rs/wgpu/pull/8256). #### DX12 diff --git a/naga/src/front/spv/mod.rs b/naga/src/front/spv/mod.rs index 2e54c74a2..803e52553 100644 --- a/naga/src/front/spv/mod.rs +++ b/naga/src/front/spv/mod.rs @@ -82,6 +82,7 @@ pub const SUPPORTED_CAPABILITIES: &[spirv::Capability] = &[ spirv::Capability::GroupNonUniformBallot, spirv::Capability::GroupNonUniformShuffle, spirv::Capability::GroupNonUniformShuffleRelative, + spirv::Capability::RuntimeDescriptorArray, // tricky ones spirv::Capability::UniformBufferArrayDynamicIndexing, spirv::Capability::StorageBufferArrayDynamicIndexing, @@ -90,6 +91,7 @@ pub const SUPPORTED_EXTENSIONS: &[&str] = &[ "SPV_KHR_storage_buffer_storage_class", "SPV_KHR_vulkan_memory_model", "SPV_KHR_multiview", + "SPV_EXT_descriptor_indexing", "SPV_EXT_shader_atomic_float_add", "SPV_KHR_16bit_storage", ]; diff --git a/naga/tests/in/spv/binding-arrays.runtime.slang b/naga/tests/in/spv/binding-arrays.runtime.slang new file mode 100644 index 000000000..6230fc9ce --- /dev/null +++ b/naga/tests/in/spv/binding-arrays.runtime.slang @@ -0,0 +1,19 @@ +// Compiled with: +// slangc -target spirv -profile spirv_1_5 -o naga/tests/in/spv/binding-arrays.runtime.spv naga/tests/in/spv/binding-arrays.runtime.slang +// Disassembled with: +// spirv-dis naga/tests/in/spv/binding-arrays.runtime.spv -o naga/tests/in/spv/binding-arrays.runtime.spvasm + +#language slang 2026 + +[[vk::binding(0, 0)]] var textures: Texture2D[]; +[[vk::binding(1, 0)]] var linear_sampler: SamplerState; + +struct VertexOutput { + var texture_coordinates: float2; + var texture_index: uint; +}; + +[[shader("pixel")]] +func main(input: VertexOutput) -> float4 { + return textures[input.texture_index].Sample(linear_sampler, input.texture_coordinates); +} diff --git a/naga/tests/in/spv/binding-arrays.runtime.spvasm b/naga/tests/in/spv/binding-arrays.runtime.spvasm new file mode 100644 index 000000000..41fc2db6d --- /dev/null +++ b/naga/tests/in/spv/binding-arrays.runtime.spvasm @@ -0,0 +1,60 @@ +; SPIR-V +; Version: 1.5 +; Generator: Khronos Slang Compiler; 0 +; Bound: 33 +; Schema: 0 + OpCapability RuntimeDescriptorArray + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %textures %linear_sampler %entryPointParam_main %input_texture_coordinates %input_texture_index + OpExecutionMode %main OriginUpperLeft + OpSource Slang 1 + OpName %input_texture_coordinates "input.texture_coordinates" + OpName %input_texture_index "input.texture_index" + OpName %textures "textures" + OpName %linear_sampler "linear_sampler" + OpName %sampledImage "sampledImage" + OpName %sampled "sampled" + OpName %entryPointParam_main "entryPointParam_main" + OpName %main "main" + OpDecorate %input_texture_coordinates Location 0 + OpDecorate %input_texture_index Location 1 + OpDecorate %input_texture_index Flat + OpDecorate %textures Binding 0 + OpDecorate %textures DescriptorSet 0 + OpDecorate %linear_sampler Binding 1 + OpDecorate %linear_sampler DescriptorSet 0 + OpDecorate %entryPointParam_main Location 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v2float = OpTypeVector %float 2 +%_ptr_Input_v2float = OpTypePointer Input %v2float + %uint = OpTypeInt 32 0 +%_ptr_Input_uint = OpTypePointer Input %uint + %15 = OpTypeImage %float 2D 2 0 0 1 Unknown +%_runtimearr_15 = OpTypeRuntimeArray %15 +%_ptr_UniformConstant__runtimearr_15 = OpTypePointer UniformConstant %_runtimearr_15 +%_ptr_UniformConstant_15 = OpTypePointer UniformConstant %15 + %22 = OpTypeSampler +%_ptr_UniformConstant_22 = OpTypePointer UniformConstant %22 + %26 = OpTypeSampledImage %15 + %v4float = OpTypeVector %float 4 +%_ptr_Output_v4float = OpTypePointer Output %v4float +%input_texture_coordinates = OpVariable %_ptr_Input_v2float Input +%input_texture_index = OpVariable %_ptr_Input_uint Input + %textures = OpVariable %_ptr_UniformConstant__runtimearr_15 UniformConstant +%linear_sampler = OpVariable %_ptr_UniformConstant_22 UniformConstant +%entryPointParam_main = OpVariable %_ptr_Output_v4float Output + %main = OpFunction %void None %3 + %4 = OpLabel + %7 = OpLoad %v2float %input_texture_coordinates + %11 = OpLoad %uint %input_texture_index + %19 = OpAccessChain %_ptr_UniformConstant_15 %textures %11 + %21 = OpLoad %15 %19 + %23 = OpLoad %22 %linear_sampler +%sampledImage = OpSampledImage %26 %21 %23 + %sampled = OpImageSampleImplicitLod %v4float %sampledImage %7 None + OpStore %entryPointParam_main %sampled + OpReturn + OpFunctionEnd diff --git a/naga/tests/in/spv/binding-arrays.runtime.toml b/naga/tests/in/spv/binding-arrays.runtime.toml new file mode 100644 index 000000000..fd5664c63 --- /dev/null +++ b/naga/tests/in/spv/binding-arrays.runtime.toml @@ -0,0 +1,4 @@ +god_mode = true + +[spv-in] +adjust_coordinate_space = true diff --git a/naga/tests/out/wgsl/spv-binding-arrays.runtime.wgsl b/naga/tests/out/wgsl/spv-binding-arrays.runtime.wgsl new file mode 100644 index 000000000..d3d1ebd0f --- /dev/null +++ b/naga/tests/out/wgsl/spv-binding-arrays.runtime.wgsl @@ -0,0 +1,24 @@ +var inputtexture_coordinates_1: vec2; +var inputtexture_index_1: u32; +@group(0) @binding(0) +var textures: binding_array>; +@group(0) @binding(1) +var linear_sampler: sampler; +var entryPointParam_main: vec4; + +fn main_1() { + let _e5 = inputtexture_coordinates_1; + let _e6 = inputtexture_index_1; + let _e8 = textureSample(textures[_e6], linear_sampler, _e5); + entryPointParam_main = _e8; + return; +} + +@fragment +fn main(@location(0) inputtexture_coordinates: vec2, @location(1) @interpolate(flat) inputtexture_index: u32) -> @location(0) vec4 { + inputtexture_coordinates_1 = inputtexture_coordinates; + inputtexture_index_1 = inputtexture_index; + main_1(); + let _e5 = entryPointParam_main; + return _e5; +}