diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index 2045f22812..a8305d0c47 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -990,6 +990,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 b405d55da9..2027e000c1 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 9c882c8c41..601e9a8e80 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 287430a7fe..5568dfa0a7 100644 --- a/wgpu-hal/src/metal/adapter.rs +++ b/wgpu-hal/src/metal/adapter.rs @@ -940,10 +940,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 84a2caf362..0872cb3aa6 100644 --- a/wgpu-hal/src/metal/device.rs +++ b/wgpu-hal/src/metal/device.rs @@ -388,15 +388,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); @@ -409,8 +409,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 993d55538b..482befcb57 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 b77ef051b6..de5872e2c8 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 5af777e595..0bbc1b79a0 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 e356c1669a..7ce7257547 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; } } @@ -3532,6 +3545,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.