From 8cdbcc175561328c7906f17a5d0ff9238460fa89 Mon Sep 17 00:00:00 2001 From: Jamie Nicol Date: Fri, 16 May 2025 15:10:12 +0100 Subject: [PATCH] Add ExternalTexture BindingType behind new Feature flag Adds a new feature flag, `EXTERNAL_TEXTURE`, indicating device support for our implementation of WebGPU's `GPUExternalTexture` [1] which will land in upcoming patches. Conceptually this would make more sense as a downlevel flag, as it is a core part of the WebGPU spec which we do not yet support. We do not want, however, to cause applications to reject adapters because we have not finished implementing this, so for now we are making it an opt-in feature. As an initial step towards supporting this feature, this patch adds a new `BindingType` corresponding to WebGPU's `GPUExternalTextureBindingLayout` [2]. This binding type dictates that when creating a bind group the corresponding entry must be either an external texture or a texture view with certain additional requirements [3]. As of yet wgpu has no concept of an external texture (that will follow in later patches) but for now this patch ensures that texture views corresponding to an external texture binding type are validated correctly. Note that as the feature flag is not yet supported on any real backends, bind group layout creation will fail before getting the chance to attempt to create a bind group. But in the added tests using the noop backend we can see this validation taking place. [1] https://www.w3.org/TR/webgpu/#gpuexternaltexture [1] https://www.w3.org/TR/webgpu/#dictdef-gpuexternaltexturebindinglayout [2] https://gpuweb.github.io/gpuweb/#bind-group-creation --- .../wgpu-validation/api/external_texture.rs | 162 ++++++++++++++++++ tests/tests/wgpu-validation/api/mod.rs | 1 + wgpu-core/src/binding_model.rs | 20 +++ wgpu-core/src/device/resource.rs | 43 +++++ wgpu-core/src/validation.rs | 6 + wgpu-hal/src/dx12/conv.rs | 1 + wgpu-hal/src/dx12/device.rs | 2 + wgpu-hal/src/gles/device.rs | 2 + wgpu-hal/src/metal/device.rs | 2 + wgpu-hal/src/vulkan/conv.rs | 1 + wgpu-hal/src/vulkan/device.rs | 1 + wgpu-types/src/features.rs | 55 +++--- wgpu-types/src/lib.rs | 14 ++ wgpu/src/backend/webgpu.rs | 5 + 14 files changed, 295 insertions(+), 20 deletions(-) create mode 100644 tests/tests/wgpu-validation/api/external_texture.rs diff --git a/tests/tests/wgpu-validation/api/external_texture.rs b/tests/tests/wgpu-validation/api/external_texture.rs new file mode 100644 index 000000000..ece0e060f --- /dev/null +++ b/tests/tests/wgpu-validation/api/external_texture.rs @@ -0,0 +1,162 @@ +use wgpu::*; +use wgpu_test::{fail, valid}; + +/// Ensures a [`TextureView`] can be bound to a [`BindingType::ExternalTexture`] +/// resource binding. +#[test] +fn external_texture_binding_texture_view() { + let (device, _queue) = wgpu::Device::noop(&DeviceDescriptor { + required_features: Features::EXTERNAL_TEXTURE, + ..Default::default() + }); + + let bgl = device.create_bind_group_layout(&BindGroupLayoutDescriptor { + label: None, + entries: &[BindGroupLayoutEntry { + binding: 0, + visibility: ShaderStages::FRAGMENT, + ty: BindingType::ExternalTexture, + count: None, + }], + }); + + let texture_descriptor = TextureDescriptor { + label: None, + size: Extent3d { + width: 256, + height: 256, + depth_or_array_layers: 1, + }, + mip_level_count: 1, + sample_count: 1, + dimension: TextureDimension::D2, + format: TextureFormat::Rgba8Unorm, + usage: TextureUsages::TEXTURE_BINDING, + view_formats: &[], + }; + + let texture = device.create_texture(&texture_descriptor); + let view = texture.create_view(&TextureViewDescriptor::default()); + valid(&device, || { + device.create_bind_group(&BindGroupDescriptor { + label: None, + layout: &bgl, + entries: &[BindGroupEntry { + binding: 0, + resource: BindingResource::TextureView(&view), + }], + }) + }); + + // Invalid usages (must include TEXTURE_BINDING) + let texture = device.create_texture(&TextureDescriptor { + usage: TextureUsages::STORAGE_BINDING, + ..texture_descriptor + }); + let view = texture.create_view(&TextureViewDescriptor::default()); + fail( + &device, + || { + device.create_bind_group(&BindGroupDescriptor { + label: None, + layout: &bgl, + entries: &[BindGroupEntry { + binding: 0, + resource: BindingResource::TextureView(&view), + }], + }) + }, + Some("Usage flags TextureUsages(STORAGE_BINDING) of TextureView with '' label do not contain required usage flags TextureUsages(TEXTURE_BINDING"), + ); + + // Invalid dimension (must be D2) + let texture = device.create_texture(&TextureDescriptor { + dimension: TextureDimension::D3, + ..texture_descriptor + }); + let view = texture.create_view(&TextureViewDescriptor::default()); + fail( + &device, + || { + device.create_bind_group(&BindGroupDescriptor { + label: None, + layout: &bgl, + entries: &[BindGroupEntry { + binding: 0, + resource: BindingResource::TextureView(&view), + }], + }) + }, + Some("Texture binding 0 expects dimension = D2, but given a view with dimension = D3"), + ); + + // Invalid mip_level_count (must be 1) + let texture = device.create_texture(&TextureDescriptor { + mip_level_count: 2, + ..texture_descriptor + }); + let view = texture.create_view(&TextureViewDescriptor::default()); + fail( + &device, + || { + + device.create_bind_group(&BindGroupDescriptor { + label: None, + layout: &bgl, + entries: &[ + BindGroupEntry { + binding: 0, + resource: BindingResource::TextureView(&view), + }, + ], + }) + }, + Some("External texture bindings must have a single mip level, but given a view with mip_level_count = 2 at binding 0") + ); + + // Invalid format (must be Rgba8Unorm, Bgra8Unorm, or Rgba16float) + let texture = device.create_texture(&TextureDescriptor { + format: TextureFormat::Rgba8Uint, + ..texture_descriptor + }); + let view = texture.create_view(&TextureViewDescriptor::default()); + fail( + &device, + || { + + device.create_bind_group(&BindGroupDescriptor { + label: None, + layout: &bgl, + entries: &[ + BindGroupEntry { + binding: 0, + resource: BindingResource::TextureView(&view), + }, + ], + }) + }, + Some("External texture bindings must have a format of `rgba8unorm`, `bgra8unorm`, or `rgba16float, but given a view with format = Rgba8Uint at binding 0") + ); + + // Invalid sample count (must be 1) + let texture = device.create_texture(&TextureDescriptor { + sample_count: 4, + usage: TextureUsages::RENDER_ATTACHMENT | TextureUsages::TEXTURE_BINDING, + ..texture_descriptor + }); + let view = texture.create_view(&TextureViewDescriptor::default()); + fail( + &device, + || { + device.create_bind_group(&BindGroupDescriptor { + label: None, + layout: &bgl, + entries: &[BindGroupEntry { + binding: 0, + resource: BindingResource::TextureView(&view), + }], + }) + }, + Some("Texture binding 0 expects multisampled = false, but given a view with samples = 4"), + ); +} diff --git a/tests/tests/wgpu-validation/api/mod.rs b/tests/tests/wgpu-validation/api/mod.rs index 8c45d67bc..9ea34327b 100644 --- a/tests/tests/wgpu-validation/api/mod.rs +++ b/tests/tests/wgpu-validation/api/mod.rs @@ -1,5 +1,6 @@ mod binding_arrays; mod buffer; mod buffer_slice; +mod external_texture; mod instance; mod texture; diff --git a/wgpu-core/src/binding_model.rs b/wgpu-core/src/binding_model.rs index 1c584b972..6d99ef2f1 100644 --- a/wgpu-core/src/binding_model.rs +++ b/wgpu-core/src/binding_model.rs @@ -173,6 +173,13 @@ pub enum CreateBindGroupError { }, #[error("Storage texture bindings must have a single mip level, but given a view with mip_level_count = {mip_level_count:?} at binding {binding}")] InvalidStorageTextureMipLevelCount { binding: u32, mip_level_count: u32 }, + #[error("External texture bindings must have a single mip level, but given a view with mip_level_count = {mip_level_count:?} at binding {binding}")] + InvalidExternalTextureMipLevelCount { binding: u32, mip_level_count: u32 }, + #[error("External texture bindings must have a format of `rgba8unorm`, `bgra8unorm`, or `rgba16float, but given a view with format = {format:?} at binding {binding}")] + InvalidExternalTextureFormat { + binding: u32, + format: wgt::TextureFormat, + }, #[error("Sampler binding {binding} expects comparison = {layout_cmp}, but given a sampler with comparison = {sampler_cmp}")] WrongSamplerComparison { binding: u32, @@ -382,6 +389,19 @@ impl BindingTypeMaxCountValidator { wgt::BindingType::AccelerationStructure { .. } => { self.acceleration_structures.add(binding.visibility, count); } + wgt::BindingType::ExternalTexture => { + // https://www.w3.org/TR/webgpu/#gpuexternaltexture + // In order to account for many possible representations, + // the binding conservatively uses the following, for each + // external texture: + // * Three sampled textures for up to 3 planes + // * One additional sampled texture for a 3D LUT + // * One sampler to sample the LUT + // * One uniform buffer for metadata + self.sampled_textures.add(binding.visibility, count * 4); + self.samplers.add(binding.visibility, count); + self.uniform_buffers.add(binding.visibility, count); + } } } } diff --git a/wgpu-core/src/device/resource.rs b/wgpu-core/src/device/resource.rs index a5bbae722..53e9586da 100644 --- a/wgpu-core/src/device/resource.rs +++ b/wgpu-core/src/device/resource.rs @@ -2011,6 +2011,14 @@ impl Device { ) } Bt::AccelerationStructure { .. } => (None, WritableStorage::No), + Bt::ExternalTexture => { + self.require_features(wgt::Features::EXTERNAL_TEXTURE) + .map_err(|e| binding_model::CreateBindGroupLayoutError::Entry { + binding: entry.binding, + error: e.into(), + })?; + (None, WritableStorage::No) + } }; // Validate the count parameter @@ -2761,6 +2769,41 @@ impl Device { view.check_usage(wgt::TextureUsages::STORAGE_BINDING)?; Ok(internal_use) } + wgt::BindingType::ExternalTexture => { + if view.desc.dimension != TextureViewDimension::D2 { + return Err(Error::InvalidTextureDimension { + binding, + layout_dimension: TextureViewDimension::D2, + view_dimension: view.desc.dimension, + }); + } + let mip_level_count = view.selector.mips.end - view.selector.mips.start; + if mip_level_count != 1 { + return Err(Error::InvalidExternalTextureMipLevelCount { + binding, + mip_level_count, + }); + } + if view.desc.format != TextureFormat::Rgba8Unorm + && view.desc.format != TextureFormat::Bgra8Unorm + && view.desc.format != TextureFormat::Rgba16Float + { + return Err(Error::InvalidExternalTextureFormat { + binding, + format: view.desc.format, + }); + } + if view.samples != 1 { + return Err(Error::InvalidTextureMultisample { + binding, + layout_multisampled: false, + view_samples: view.samples, + }); + } + + view.check_usage(wgt::TextureUsages::TEXTURE_BINDING)?; + Ok(wgt::TextureUses::RESOURCE) + } _ => Err(Error::WrongBindingType { binding, actual: decl.ty, diff --git a/wgpu-core/src/validation.rs b/wgpu-core/src/validation.rs index 5a34cd77b..a7e1d4f1d 100644 --- a/wgpu-core/src/validation.rs +++ b/wgpu-core/src/validation.rs @@ -36,6 +36,7 @@ pub enum BindingTypeName { Texture, Sampler, AccelerationStructure, + ExternalTexture, } impl From<&ResourceType> for BindingTypeName { @@ -57,6 +58,7 @@ impl From<&BindingType> for BindingTypeName { BindingType::StorageTexture { .. } => BindingTypeName::Texture, BindingType::Sampler { .. } => BindingTypeName::Sampler, BindingType::AccelerationStructure { .. } => BindingTypeName::AccelerationStructure, + BindingType::ExternalTexture => BindingTypeName::ExternalTexture, } } } @@ -466,6 +468,7 @@ impl Resource { let view_dimension = match entry.ty { BindingType::Texture { view_dimension, .. } | BindingType::StorageTexture { view_dimension, .. } => view_dimension, + BindingType::ExternalTexture => wgt::TextureViewDimension::D2, _ => { return Err(BindingError::WrongTextureViewDimension { dim, @@ -1147,6 +1150,9 @@ impl Interface { ); let texture_sample_type = match texture_layout.ty { BindingType::Texture { sample_type, .. } => sample_type, + BindingType::ExternalTexture => { + wgt::TextureSampleType::Float { filterable: true } + } _ => unreachable!(), }; diff --git a/wgpu-hal/src/dx12/conv.rs b/wgpu-hal/src/dx12/conv.rs index 9c6300af9..2ccb96dd8 100644 --- a/wgpu-hal/src/dx12/conv.rs +++ b/wgpu-hal/src/dx12/conv.rs @@ -135,6 +135,7 @@ pub fn map_binding_type(ty: &wgt::BindingType) -> Direct3D12::D3D12_DESCRIPTOR_R } | Bt::StorageTexture { .. } => Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_UAV, Bt::AccelerationStructure { .. } => Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_SRV, + Bt::ExternalTexture => unimplemented!(), } } diff --git a/wgpu-hal/src/dx12/device.rs b/wgpu-hal/src/dx12/device.rs index c73780bc7..918dd5193 100644 --- a/wgpu-hal/src/dx12/device.rs +++ b/wgpu-hal/src/dx12/device.rs @@ -785,6 +785,7 @@ impl crate::Device for super::Device { | wgt::BindingType::StorageTexture { .. } | wgt::BindingType::AccelerationStructure { .. } => num_views += count, wgt::BindingType::Sampler { .. } => has_sampler_in_group = true, + wgt::BindingType::ExternalTexture => unimplemented!(), } } @@ -1550,6 +1551,7 @@ impl crate::Device for super::Device { inner.stage.push(handle); } } + wgt::BindingType::ExternalTexture => unimplemented!(), } } diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index 42ca63821..347904c6e 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -1203,6 +1203,7 @@ impl crate::Device for super::Device { .. } => &mut num_storage_buffers, wgt::BindingType::AccelerationStructure { .. } => unimplemented!(), + wgt::BindingType::ExternalTexture => unimplemented!(), }; binding_to_slot[entry.binding as usize] = *counter; @@ -1313,6 +1314,7 @@ impl crate::Device for super::Device { }) } wgt::BindingType::AccelerationStructure { .. } => unimplemented!(), + wgt::BindingType::ExternalTexture => unimplemented!(), }; contents.push(binding); } diff --git a/wgpu-hal/src/metal/device.rs b/wgpu-hal/src/metal/device.rs index b1300a31e..b74970e2b 100644 --- a/wgpu-hal/src/metal/device.rs +++ b/wgpu-hal/src/metal/device.rs @@ -747,6 +747,7 @@ impl crate::Device for super::Device { }; } wgt::BindingType::AccelerationStructure { .. } => unimplemented!(), + wgt::BindingType::ExternalTexture => unimplemented!(), } } @@ -979,6 +980,7 @@ impl crate::Device for super::Device { counter.textures += 1; } wgt::BindingType::AccelerationStructure { .. } => unimplemented!(), + wgt::BindingType::ExternalTexture => unimplemented!(), } } } diff --git a/wgpu-hal/src/vulkan/conv.rs b/wgpu-hal/src/vulkan/conv.rs index ee64d1175..c59c9ad4b 100644 --- a/wgpu-hal/src/vulkan/conv.rs +++ b/wgpu-hal/src/vulkan/conv.rs @@ -764,6 +764,7 @@ pub fn map_binding_type(ty: wgt::BindingType) -> vk::DescriptorType { wgt::BindingType::AccelerationStructure { .. } => { vk::DescriptorType::ACCELERATION_STRUCTURE_KHR } + wgt::BindingType::ExternalTexture => unimplemented!(), } } diff --git a/wgpu-hal/src/vulkan/device.rs b/wgpu-hal/src/vulkan/device.rs index 141d8ba5e..77b9ebe92 100644 --- a/wgpu-hal/src/vulkan/device.rs +++ b/wgpu-hal/src/vulkan/device.rs @@ -1493,6 +1493,7 @@ impl crate::Device for super::Device { wgt::BindingType::AccelerationStructure { .. } => { desc_count.acceleration_structure += count; } + wgt::BindingType::ExternalTexture => unimplemented!(), } } diff --git a/wgpu-types/src/features.rs b/wgpu-types/src/features.rs index d2142598a..b614b8cb6 100644 --- a/wgpu-types/src/features.rs +++ b/wgpu-types/src/features.rs @@ -997,6 +997,21 @@ bitflags_array! { /// This is a native-only feature. const EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE = 1 << 30; + /// Allows for the creation and usage of `ExternalTexture`s, and bind + /// group layouts containing external texture `BindingType`s. + /// + /// Conceptually this should really be a [`crate::DownlevelFlags`] as + /// it corresponds to WebGPU's [`GPUExternalTexture`]( + /// https://www.w3.org/TR/webgpu/#gpuexternaltexture). + /// However, the implementation is currently in-progress, and until it + /// is complete we do not want applications to ignore adapters due to + /// a missing downlevel flag, when they may not require this feature at + /// all. + /// + /// Supported platforms: + /// - None + const EXTERNAL_TEXTURE = 1 << 31; + // Shader: /// ***THIS IS EXPERIMENTAL:*** Features enabled by this may have @@ -1009,7 +1024,7 @@ bitflags_array! { /// - Vulkan /// /// This is a native-only feature. - const EXPERIMENTAL_RAY_QUERY = 1 << 31; + const EXPERIMENTAL_RAY_QUERY = 1 << 32; /// Enables 64-bit floating point types in SPIR-V shaders. /// /// Note: even when supported by GPU hardware, 64-bit floating point operations are @@ -1019,14 +1034,14 @@ bitflags_array! { /// - Vulkan /// /// This is a native only feature. - const SHADER_F64 = 1 << 32; + const SHADER_F64 = 1 << 33; /// Allows shaders to use i16. Not currently supported in `naga`, only available through `spirv-passthrough`. /// /// Supported platforms: /// - Vulkan /// /// This is a native only feature. - const SHADER_I16 = 1 << 33; + const SHADER_I16 = 1 << 34; /// Enables `builtin(primitive_index)` in fragment shaders. /// /// Note: enables geometry processing for pipelines using the builtin. @@ -1040,7 +1055,7 @@ bitflags_array! { /// - OpenGL (some) /// /// This is a native only feature. - const SHADER_PRIMITIVE_INDEX = 1 << 34; + const SHADER_PRIMITIVE_INDEX = 1 << 35; /// Allows shaders to use the `early_depth_test` attribute. /// /// The attribute is applied to the fragment shader entry point. It can be used in two @@ -1068,7 +1083,7 @@ bitflags_array! { /// This is a native only feature. /// /// [`EarlyDepthTest`]: https://docs.rs/naga/latest/naga/ir/enum.EarlyDepthTest.html - const SHADER_EARLY_DEPTH_TEST = 1 << 35; + const SHADER_EARLY_DEPTH_TEST = 1 << 36; /// Allows shaders to use i64 and u64. /// /// Supported platforms: @@ -1077,7 +1092,7 @@ bitflags_array! { /// - Metal (with MSL 2.3+) /// /// This is a native only feature. - const SHADER_INT64 = 1 << 36; + const SHADER_INT64 = 1 << 37; /// Allows compute and fragment shaders to use the subgroup operation built-ins /// /// Supported Platforms: @@ -1086,14 +1101,14 @@ bitflags_array! { /// - Metal /// /// This is a native only feature. - const SUBGROUP = 1 << 37; + const SUBGROUP = 1 << 38; /// Allows vertex shaders to use the subgroup operation built-ins /// /// Supported Platforms: /// - Vulkan /// /// This is a native only feature. - const SUBGROUP_VERTEX = 1 << 38; + const SUBGROUP_VERTEX = 1 << 39; /// Allows shaders to use the subgroup barrier /// /// Supported Platforms: @@ -1101,7 +1116,7 @@ bitflags_array! { /// - Metal /// /// This is a native only feature. - const SUBGROUP_BARRIER = 1 << 39; + const SUBGROUP_BARRIER = 1 << 40; /// Allows the use of pipeline cache objects /// /// Supported platforms: @@ -1110,7 +1125,7 @@ bitflags_array! { /// Unimplemented Platforms: /// - DX12 /// - Metal - const PIPELINE_CACHE = 1 << 40; + const PIPELINE_CACHE = 1 << 41; /// Allows shaders to use i64 and u64 atomic min and max. /// /// Supported platforms: @@ -1119,7 +1134,7 @@ bitflags_array! { /// - Metal (with MSL 2.4+) /// /// This is a native only feature. - const SHADER_INT64_ATOMIC_MIN_MAX = 1 << 41; + const SHADER_INT64_ATOMIC_MIN_MAX = 1 << 42; /// Allows shaders to use all i64 and u64 atomic operations. /// /// Supported platforms: @@ -1127,7 +1142,7 @@ bitflags_array! { /// - DX12 (with SM 6.6+) /// /// This is a native only feature. - const SHADER_INT64_ATOMIC_ALL_OPS = 1 << 42; + const SHADER_INT64_ATOMIC_ALL_OPS = 1 << 43; /// Allows using the [VK_GOOGLE_display_timing] Vulkan extension. /// /// This is used for frame pacing to reduce latency, and is generally only available on Android. @@ -1143,7 +1158,7 @@ bitflags_array! { /// /// [VK_GOOGLE_display_timing]: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_GOOGLE_display_timing.html /// [`Surface::as_hal()`]: https://docs.rs/wgpu/latest/wgpu/struct.Surface.html#method.as_hal - const VULKAN_GOOGLE_DISPLAY_TIMING = 1 << 43; + const VULKAN_GOOGLE_DISPLAY_TIMING = 1 << 44; /// Allows using the [VK_KHR_external_memory_win32] Vulkan extension. /// @@ -1153,7 +1168,7 @@ bitflags_array! { /// This is a native only feature. /// /// [VK_KHR_external_memory_win32]: https://registry.khronos.org/vulkan/specs/latest/man/html/VK_KHR_external_memory_win32.html - const VULKAN_EXTERNAL_MEMORY_WIN32 = 1 << 44; + const VULKAN_EXTERNAL_MEMORY_WIN32 = 1 << 45; /// Enables R64Uint image atomic min and max. /// @@ -1163,7 +1178,7 @@ bitflags_array! { /// - Metal (with MSL 3.1+) /// /// This is a native only feature. - const TEXTURE_INT64_ATOMIC = 1 << 45; + const TEXTURE_INT64_ATOMIC = 1 << 46; /// Allows uniform buffers to be bound as binding arrays. /// @@ -1180,7 +1195,7 @@ bitflags_array! { /// - Vulkan 1.2+ (or VK_EXT_descriptor_indexing)'s `shaderUniformBufferArrayNonUniformIndexing` feature) /// /// This is a native only feature. - const UNIFORM_BUFFER_BINDING_ARRAYS = 1 << 46; + const UNIFORM_BUFFER_BINDING_ARRAYS = 1 << 47; /// Enables mesh shaders and task shaders in mesh shader pipelines. /// @@ -1192,7 +1207,7 @@ bitflags_array! { /// - Metal /// /// This is a native only feature. - const EXPERIMENTAL_MESH_SHADER = 1 << 47; + const EXPERIMENTAL_MESH_SHADER = 1 << 48; /// ***THIS IS EXPERIMENTAL:*** Features enabled by this may have /// major bugs in them and are expected to be subject to breaking changes, suggestions @@ -1207,7 +1222,7 @@ bitflags_array! { /// This is a native only feature /// /// [`AccelerationStructureFlags::ALLOW_RAY_HIT_VERTEX_RETURN`]: super::AccelerationStructureFlags::ALLOW_RAY_HIT_VERTEX_RETURN - const EXPERIMENTAL_RAY_HIT_VERTEX_RETURN = 1 << 48; + const EXPERIMENTAL_RAY_HIT_VERTEX_RETURN = 1 << 49; /// Enables multiview in mesh shader pipelines /// @@ -1219,7 +1234,7 @@ bitflags_array! { /// - Metal /// /// This is a native only feature. - const EXPERIMENTAL_MESH_SHADER_MULTIVIEW = 1 << 49; + const EXPERIMENTAL_MESH_SHADER_MULTIVIEW = 1 << 50; /// Allows usage of additional vertex formats in [BlasTriangleGeometrySizeDescriptor::vertex_format] /// @@ -1228,7 +1243,7 @@ bitflags_array! { /// - DX12 /// /// [BlasTriangleGeometrySizeDescriptor::vertex_format]: super::BlasTriangleGeometrySizeDescriptor - const EXTENDED_ACCELERATION_STRUCTURE_VERTEX_FORMATS = 1 << 50; + const EXTENDED_ACCELERATION_STRUCTURE_VERTEX_FORMATS = 1 << 51; } /// Features that are not guaranteed to be supported. diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 422b91cca..3ba3bbe26 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -6799,6 +6799,20 @@ pub enum BindingType { /// If enabled requires [`Features::EXPERIMENTAL_RAY_HIT_VERTEX_RETURN`] vertex_return: bool, }, + + /// An external texture binding. + /// + /// Example WGSL syntax: + /// ```rust,ignore + /// @group(0) @binding(0) + /// var t: texture_external; + /// ``` + /// + /// Corresponds to [WebGPU `GPUExternalTextureBindingLayout`]( + /// https://gpuweb.github.io/gpuweb/#dictdef-gpuexternaltexturebindinglayout). + /// + /// Requires [`Features::EXTERNAL_TEXTURE`] + ExternalTexture, } impl BindingType { diff --git a/wgpu/src/backend/webgpu.rs b/wgpu/src/backend/webgpu.rs index 1755cd335..12662e7c0 100644 --- a/wgpu/src/backend/webgpu.rs +++ b/wgpu/src/backend/webgpu.rs @@ -1942,6 +1942,11 @@ impl dispatch::DeviceInterface for WebDevice { mapped_entry.set_storage_texture(&storage_texture); } wgt::BindingType::AccelerationStructure { .. } => todo!(), + wgt::BindingType::ExternalTexture => { + mapped_entry.set_external_texture( + &webgpu_sys::GpuExternalTextureBindingLayout::new(), + ); + } } mapped_entry