From 0183e7d1e85ac95f2461426a910b2f86f5373119 Mon Sep 17 00:00:00 2001 From: Ibiyemi Abiodun Date: Sat, 15 Jan 2022 00:16:35 -0500 Subject: [PATCH] add AddressMode::ClampToZero (#2364) * add AddressMode::ClampToZero * add feature checks * oops * rustfmt * fix dx12 * change to use SamplerBorderColor * fix metal * update to use new config * update dx12 + docs * address nits * cargo fmt * fix dx12 --- wgpu-core/src/device/mod.rs | 4 ++++ wgpu-hal/src/dx12/adapter.rs | 1 + wgpu-hal/src/dx12/conv.rs | 2 +- wgpu-hal/src/dx12/device.rs | 4 +++- wgpu-hal/src/gles/adapter.rs | 2 +- wgpu-hal/src/gles/device.rs | 4 +++- wgpu-hal/src/metal/adapter.rs | 2 ++ wgpu-hal/src/metal/conv.rs | 1 + wgpu-hal/src/metal/device.rs | 25 ++++++++++++++++++++----- wgpu-hal/src/vulkan/adapter.rs | 1 + wgpu-hal/src/vulkan/conv.rs | 6 ++++-- wgpu-hal/src/vulkan/device.rs | 1 + wgpu-types/src/lib.rs | 22 +++++++++++++++++++++- 13 files changed, 63 insertions(+), 12 deletions(-) diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index 057f0751f4..9ab1e5e9ad 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -994,6 +994,10 @@ impl Device { self.require_features(wgt::Features::ADDRESS_MODE_CLAMP_TO_BORDER)?; } + if desc.border_color == Some(wgt::SamplerBorderColor::Zero) { + self.require_features(wgt::Features::ADDRESS_MODE_CLAMP_TO_ZERO)?; + } + let lod_clamp = if desc.lod_min_clamp > 0.0 || desc.lod_max_clamp < 32.0 { Some(desc.lod_min_clamp..desc.lod_max_clamp) } else { diff --git a/wgpu-hal/src/dx12/adapter.rs b/wgpu-hal/src/dx12/adapter.rs index 8f3ebbf152..51d40c8671 100644 --- a/wgpu-hal/src/dx12/adapter.rs +++ b/wgpu-hal/src/dx12/adapter.rs @@ -180,6 +180,7 @@ impl super::Adapter { | wgt::Features::MULTI_DRAW_INDIRECT | wgt::Features::MULTI_DRAW_INDIRECT_COUNT | wgt::Features::ADDRESS_MODE_CLAMP_TO_BORDER + | wgt::Features::ADDRESS_MODE_CLAMP_TO_ZERO | wgt::Features::POLYGON_MODE_LINE | wgt::Features::POLYGON_MODE_POINT | wgt::Features::VERTEX_WRITABLE_STORAGE diff --git a/wgpu-hal/src/dx12/conv.rs b/wgpu-hal/src/dx12/conv.rs index 3763d31671..45c648a6ab 100644 --- a/wgpu-hal/src/dx12/conv.rs +++ b/wgpu-hal/src/dx12/conv.rs @@ -276,7 +276,7 @@ pub fn map_comparison(func: wgt::CompareFunction) -> d3d12::D3D12_COMPARISON_FUN pub fn map_border_color(border_color: Option) -> [f32; 4] { use wgt::SamplerBorderColor as Sbc; match border_color { - Some(Sbc::TransparentBlack) | None => [0.0; 4], + Some(Sbc::TransparentBlack) | Some(Sbc::Zero) | None => [0.0; 4], Some(Sbc::OpaqueBlack) => [0.0, 0.0, 0.0, 1.0], Some(Sbc::OpaqueWhite) => [1.0; 4], } diff --git a/wgpu-hal/src/dx12/device.rs b/wgpu-hal/src/dx12/device.rs index 5294a16275..a29eeed45b 100644 --- a/wgpu-hal/src/dx12/device.rs +++ b/wgpu-hal/src/dx12/device.rs @@ -620,6 +620,8 @@ impl crate::Device for super::Device { .anisotropy_clamp .map_or(0, |_| d3d12::D3D12_FILTER_ANISOTROPIC); + let border_color = conv::map_border_color(desc.border_color); + self.raw.create_sampler( handle.raw, filter, @@ -631,7 +633,7 @@ impl crate::Device for super::Device { 0.0, desc.anisotropy_clamp.map_or(0, |aniso| aniso.get() as u32), conv::map_comparison(desc.compare.unwrap_or(wgt::CompareFunction::Always)), - conv::map_border_color(desc.border_color), + border_color, desc.lod_clamp.clone().unwrap_or(0.0..16.0), ); diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index e4bb5b60c9..42a8b5bccd 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -288,7 +288,7 @@ impl super::Adapter { | wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES | wgt::Features::CLEAR_TEXTURE; features.set( - wgt::Features::ADDRESS_MODE_CLAMP_TO_BORDER, + wgt::Features::ADDRESS_MODE_CLAMP_TO_BORDER | wgt::Features::ADDRESS_MODE_CLAMP_TO_ZERO, extensions.contains("GL_EXT_texture_border_clamp"), ); features.set( diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index a85301fa2c..93a582c265 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -721,7 +721,9 @@ impl crate::Device for super::Device { if let Some(border_color) = desc.border_color { let border = match border_color { - wgt::SamplerBorderColor::TransparentBlack => [0.0; 4], + wgt::SamplerBorderColor::TransparentBlack | wgt::SamplerBorderColor::Zero => { + [0.0; 4] + } wgt::SamplerBorderColor::OpaqueBlack => [0.0, 0.0, 0.0, 1.0], wgt::SamplerBorderColor::OpaqueWhite => [1.0; 4], }; diff --git a/wgpu-hal/src/metal/adapter.rs b/wgpu-hal/src/metal/adapter.rs index 8d0b7f275a..b48799b251 100644 --- a/wgpu-hal/src/metal/adapter.rs +++ b/wgpu-hal/src/metal/adapter.rs @@ -1018,10 +1018,12 @@ impl super::PrivateCapabilities { { features.insert(F::STORAGE_RESOURCE_BINDING_ARRAY); } + features.set( F::ADDRESS_MODE_CLAMP_TO_BORDER, self.sampler_clamp_to_border, ); + features.set(F::ADDRESS_MODE_CLAMP_TO_ZERO, true); features } diff --git a/wgpu-hal/src/metal/conv.rs b/wgpu-hal/src/metal/conv.rs index 8cc7dc67c9..f275a74ec9 100644 --- a/wgpu-hal/src/metal/conv.rs +++ b/wgpu-hal/src/metal/conv.rs @@ -73,6 +73,7 @@ pub fn map_border_color(border_color: wgt::SamplerBorderColor) -> mtl::MTLSample wgt::SamplerBorderColor::TransparentBlack => TransparentBlack, wgt::SamplerBorderColor::OpaqueBlack => OpaqueBlack, wgt::SamplerBorderColor::OpaqueWhite => OpaqueWhite, + wgt::SamplerBorderColor::Zero => unreachable!(), } } diff --git a/wgpu-hal/src/metal/device.rs b/wgpu-hal/src/metal/device.rs index cc6dc6ab93..5a24204125 100644 --- a/wgpu-hal/src/metal/device.rs +++ b/wgpu-hal/src/metal/device.rs @@ -392,15 +392,15 @@ impl crate::Device for super::Device { wgt::FilterMode::Linear => mtl::MTLSamplerMipFilter::Linear, }); - if let Some(aniso) = desc.anisotropy_clamp { - descriptor.set_max_anisotropy(aniso.get() as _); - } - let [s, t, r] = desc.address_modes; descriptor.set_address_mode_s(conv::map_address_mode(s)); descriptor.set_address_mode_t(conv::map_address_mode(t)); descriptor.set_address_mode_r(conv::map_address_mode(r)); + if let Some(aniso) = desc.anisotropy_clamp { + descriptor.set_max_anisotropy(aniso.get() as _); + } + if let Some(ref range) = desc.lod_clamp { descriptor.set_lod_min_clamp(range.start); descriptor.set_lod_max_clamp(range.end); @@ -413,8 +413,23 @@ impl crate::Device for super::Device { if let Some(fun) = desc.compare { descriptor.set_compare_function(conv::map_compare_function(fun)); } + if let Some(border_color) = desc.border_color { - descriptor.set_border_color(conv::map_border_color(border_color)); + if let wgt::SamplerBorderColor::Zero = border_color { + if s == wgt::AddressMode::ClampToBorder { + descriptor.set_address_mode_s(mtl::MTLSamplerAddressMode::ClampToZero); + } + + if t == wgt::AddressMode::ClampToBorder { + descriptor.set_address_mode_t(mtl::MTLSamplerAddressMode::ClampToZero); + } + + if r == wgt::AddressMode::ClampToBorder { + descriptor.set_address_mode_r(mtl::MTLSamplerAddressMode::ClampToZero); + } + } else { + descriptor.set_border_color(conv::map_border_color(border_color)); + } } if let Some(label) = desc.label { diff --git a/wgpu-hal/src/vulkan/adapter.rs b/wgpu-hal/src/vulkan/adapter.rs index e084d09afa..0a03780697 100644 --- a/wgpu-hal/src/vulkan/adapter.rs +++ b/wgpu-hal/src/vulkan/adapter.rs @@ -329,6 +329,7 @@ impl PhysicalDeviceFeatures { | F::MAPPABLE_PRIMARY_BUFFERS | F::PUSH_CONSTANTS | F::ADDRESS_MODE_CLAMP_TO_BORDER + | F::ADDRESS_MODE_CLAMP_TO_ZERO | F::TIMESTAMP_QUERY | F::PIPELINE_STATISTICS_QUERY | F::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES diff --git a/wgpu-hal/src/vulkan/conv.rs b/wgpu-hal/src/vulkan/conv.rs index 9d91ea054c..087af70594 100644 --- a/wgpu-hal/src/vulkan/conv.rs +++ b/wgpu-hal/src/vulkan/conv.rs @@ -589,13 +589,15 @@ pub fn map_address_mode(mode: wgt::AddressMode) -> vk::SamplerAddressMode { wgt::AddressMode::Repeat => vk::SamplerAddressMode::REPEAT, wgt::AddressMode::MirrorRepeat => vk::SamplerAddressMode::MIRRORED_REPEAT, wgt::AddressMode::ClampToBorder => vk::SamplerAddressMode::CLAMP_TO_BORDER, - //wgt::AddressMode::MirrorClamp => vk::SamplerAddressMode::MIRROR_CLAMP_TO_EDGE, + // wgt::AddressMode::MirrorClamp => vk::SamplerAddressMode::MIRROR_CLAMP_TO_EDGE, } } pub fn map_border_color(border_color: wgt::SamplerBorderColor) -> vk::BorderColor { match border_color { - wgt::SamplerBorderColor::TransparentBlack => vk::BorderColor::FLOAT_TRANSPARENT_BLACK, + wgt::SamplerBorderColor::TransparentBlack | wgt::SamplerBorderColor::Zero => { + vk::BorderColor::FLOAT_TRANSPARENT_BLACK + } wgt::SamplerBorderColor::OpaqueBlack => vk::BorderColor::FLOAT_OPAQUE_BLACK, wgt::SamplerBorderColor::OpaqueWhite => vk::BorderColor::FLOAT_OPAQUE_WHITE, } diff --git a/wgpu-hal/src/vulkan/device.rs b/wgpu-hal/src/vulkan/device.rs index 56354ef690..132393f4c9 100644 --- a/wgpu-hal/src/vulkan/device.rs +++ b/wgpu-hal/src/vulkan/device.rs @@ -974,6 +974,7 @@ impl crate::Device for super::Device { .max_anisotropy(aniso.get() as f32); } } + if let Some(color) = desc.border_color { vk_info = vk_info.border_color(conv::map_border_color(color)); } diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index e2a15ca440..d3290fe314 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -394,7 +394,8 @@ bitflags::bitflags! { /// /// This is a native only feature. const PUSH_CONSTANTS = 1 << 26; - /// Allows the use of [`AddressMode::ClampToBorder`]. + /// Allows the use of [`AddressMode::ClampToBorder`] with a border color + /// other than [`SamplerBorderColor::Zero`]. /// /// Supported platforms: /// - DX12 @@ -551,6 +552,18 @@ bitflags::bitflags! { /// /// This is a native only feature. const TEXTURE_FORMAT_16BIT_NORM = 1 << 41; + /// Allows the use of [`AddressMode::ClampToBorder`] with a border color + /// of [`SamplerBorderColor::Zero`]. + /// + /// Supported platforms: + /// - DX12 + /// - Vulkan + /// - Metal + /// - DX11 + /// - OpenGL + /// + /// This is a native only feature. + const ADDRESS_MODE_CLAMP_TO_ZERO = 1 << 42; } } @@ -3727,6 +3740,13 @@ pub enum SamplerBorderColor { OpaqueBlack, /// [1, 1, 1, 1] OpaqueWhite, + + /// On the Metal backend, this is equivalent to `TransparentBlack` for + /// textures that have an alpha component, and equivalent to `OpaqueBlack` + /// for textures that do not have an alpha component. On other backends, + /// this is equivalent to `TransparentBlack`. Requires + /// [`Features::ADDRESS_MODE_CLAMP_TO_ZERO`]. Not supported on the web. + Zero, } /// Describes how to create a QuerySet.