diff --git a/wgpu-core/src/conv.rs b/wgpu-core/src/conv.rs index 101b50a5d8e..0cf4cd1ffaa 100644 --- a/wgpu-core/src/conv.rs +++ b/wgpu-core/src/conv.rs @@ -429,7 +429,7 @@ fn checked_u32_as_u16(value: u32) -> u16 { value as u16 } -fn is_power_of_two(val: u32) -> bool { +pub fn is_power_of_two(val: u32) -> bool { val != 0 && (val & (val - 1)) == 0 } diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index 0f8148645d9..52a34757a33 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -55,6 +55,7 @@ fn own_label(label: &Label) -> String { pub const MAX_COLOR_TARGETS: usize = 4; pub const MAX_MIP_LEVELS: usize = 16; pub const MAX_VERTEX_BUFFERS: usize = 16; +pub const MAX_ANISOTROPY: u8 = 16; pub fn all_buffer_stages() -> hal::pso::PipelineStage { use hal::pso::PipelineStage as Ps; @@ -541,6 +542,24 @@ impl Device { } impl Global { + pub fn device_extensions(&self, device_id: id::DeviceId) -> wgt::Extensions { + let hub = B::hub(self); + let mut token = Token::root(); + let (device_guard, _) = hub.devices.read(&mut token); + let device = &device_guard[device_id]; + + device.extensions.clone() + } + + pub fn device_limits(&self, device_id: id::DeviceId) -> wgt::Limits { + let hub = B::hub(self); + let mut token = Token::root(); + let (device_guard, _) = hub.devices.read(&mut token); + let device = &device_guard[device_id]; + + device.limits.clone() + } + pub fn device_create_buffer( &self, device_id: id::DeviceId, @@ -977,6 +996,19 @@ impl Global { let (device_guard, mut token) = hub.devices.read(&mut token); let device = &device_guard[device_id]; + if desc.anisotropy_clamp > 1 { + assert!( + device.extensions.anisotropic_filtering, + "Anisotropic clamp may only be used when the anisotropic filtering extension is enabled" + ); + let valid_clamp = desc.anisotropy_clamp <= MAX_ANISOTROPY + && conv::is_power_of_two(desc.anisotropy_clamp as u32); + assert!( + valid_clamp, + "Anisotropic clamp must be one of the values: 0, 1, 2, 4, 8, or 16" + ); + } + let info = hal::image::SamplerDesc { min_filter: conv::map_filter(desc.min_filter), mag_filter: conv::map_filter(desc.mag_filter), @@ -991,7 +1023,11 @@ impl Global { comparison: conv::map_compare_function(desc.compare), border: hal::image::PackedColor(0), normalized: true, - anisotropy_clamp: None, //TODO + anisotropy_clamp: if desc.anisotropy_clamp > 1 { + Some(desc.anisotropy_clamp) + } else { + None + }, }; let sampler = resource::Sampler { diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index a9223ec0f47..e99172de6ef 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -7,7 +7,7 @@ use crate::{ device::Device, hub::{GfxBackend, Global, GlobalIdentityHandlerFactory, Input, Token}, id::{AdapterId, DeviceId, SurfaceId}, - power, LifeGuard, Stored, + power, LifeGuard, Stored, MAX_BIND_GROUPS, }; use wgt::{Backend, BackendBit, DeviceDescriptor, PowerPreference, BIND_BUFFER_ALIGNMENT}; @@ -527,6 +527,32 @@ impl Global { AdapterInfo::from_gfx(adapter.raw.info.clone(), adapter_id.backend()) } + pub fn adapter_extensions(&self, adapter_id: AdapterId) -> wgt::Extensions { + let hub = B::hub(self); + let mut token = Token::root(); + let (adapter_guard, _) = hub.adapters.read(&mut token); + let adapter = &adapter_guard[adapter_id]; + + let features = adapter.raw.physical_device.features(); + + wgt::Extensions { + anisotropic_filtering: features.contains(hal::Features::SAMPLER_ANISOTROPY), + } + } + + pub fn adapter_limits(&self, adapter_id: AdapterId) -> wgt::Limits { + let hub = B::hub(self); + let mut token = Token::root(); + let (adapter_guard, _) = hub.adapters.read(&mut token); + let adapter = &adapter_guard[adapter_id]; + + let limits = adapter.raw.physical_device.limits(); + + wgt::Limits { + max_bind_groups: (limits.max_bound_descriptor_sets as u32).min(MAX_BIND_GROUPS as u32), + } + } + pub fn adapter_destroy(&self, adapter_id: AdapterId) { let hub = B::hub(self); let mut token = Token::root(); @@ -560,10 +586,14 @@ impl Global { let (adapter_guard, _) = hub.adapters.read(&mut token); let adapter = &adapter_guard[adapter_id]; let phd = &adapter.raw.physical_device; + + let available_features = adapter.raw.physical_device.features(); + + // Check features that are always needed let wishful_features = hal::Features::VERTEX_STORES_AND_ATOMICS | hal::Features::FRAGMENT_STORES_AND_ATOMICS | hal::Features::NDC_Y_UP; - let enabled_features = adapter.raw.physical_device.features() & wishful_features; + let mut enabled_features = available_features & wishful_features; if enabled_features != wishful_features { log::warn!( "Missing features: {:?}", @@ -571,6 +601,15 @@ impl Global { ); } + // Check features needed by extensions + if desc.extensions.anisotropic_filtering { + assert!( + available_features.contains(hal::Features::SAMPLER_ANISOTROPY), + "Missing feature SAMPLER_ANISOTROPY for anisotropic filtering extension" + ); + enabled_features |= hal::Features::SAMPLER_ANISOTROPY; + } + let family = adapter .raw .queue_families diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 83ba54782db..1059271f2bb 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -88,6 +88,10 @@ impl From for BackendBit { #[cfg_attr(feature = "trace", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct Extensions { + /// This is a native only extension. Support is planned to be added to webgpu, + /// but it is not yet implemented. + /// + /// https://github.com/gpuweb/gpuweb/issues/696 pub anisotropic_filtering: bool, } @@ -926,6 +930,11 @@ pub struct SamplerDescriptor { pub lod_min_clamp: f32, pub lod_max_clamp: f32, pub compare: CompareFunction, + /// Anisotropic filtering extension must be enabled if this value is + /// anything other than 0 and 1. + /// + /// Valid values are 0, 1, 2, 4, 8, and 16. + pub anisotropy_clamp: u8, } impl SamplerDescriptor { @@ -941,6 +950,7 @@ impl SamplerDescriptor { lod_min_clamp: self.lod_min_clamp, lod_max_clamp: self.lod_max_clamp, compare: self.compare, + anisotropy_clamp: self.anisotropy_clamp, } } }