Skip to content

Commit

Permalink
Merge #690
Browse files Browse the repository at this point in the history
690: Implement Anisotropic Filtering Extension and Expose Extension Interface r=kvark a=cwfitzgerald

**Connections**

Resolves #568.

**Description**

This PR solves two tightly related problems:
 - Adds the ability to create a sampler with anisotropic filtering
 - Adds the webgpu interface for getting the limits/extensions on adapters and devies.

**Testing**

I have tested this against my codebase which uses it. Adding an example in wgpu-rs on how to use extensions/limits would be good, especially as we have native/webgpu extensions, but can come as a future enhancement, once we feel the extension situation has stabilized a bit.

**TODO**

- [x] Allow wgpu-rs to call limit/extension interface (gfx-rs/wgpu-rs#338)
- [ ] Determine how wgpu-native is going to adopt this functionality.
- [ ] After discussing #691, what changes need to be made. 

Co-authored-by: Connor Fitzgerald <connorwadefitzgerald@gmail.com>
  • Loading branch information
bors[bot] and cwfitzgerald authored Jun 1, 2020
2 parents 1a569eb + 415ce97 commit 3a6cdee
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 4 deletions.
2 changes: 1 addition & 1 deletion wgpu-core/src/conv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
38 changes: 37 additions & 1 deletion wgpu-core/src/device/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -541,6 +542,24 @@ impl<B: hal::Backend> Device<B> {
}

impl<G: GlobalIdentityHandlerFactory> Global<G> {
pub fn device_extensions<B: GfxBackend>(&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<B: GfxBackend>(&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<B: GfxBackend>(
&self,
device_id: id::DeviceId,
Expand Down Expand Up @@ -977,6 +996,19 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
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),
Expand All @@ -991,7 +1023,11 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
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 {
Expand Down
43 changes: 41 additions & 2 deletions wgpu-core/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -527,6 +527,32 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
AdapterInfo::from_gfx(adapter.raw.info.clone(), adapter_id.backend())
}

pub fn adapter_extensions<B: GfxBackend>(&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<B: GfxBackend>(&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<B: GfxBackend>(&self, adapter_id: AdapterId) {
let hub = B::hub(self);
let mut token = Token::root();
Expand Down Expand Up @@ -560,17 +586,30 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
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: {:?}",
wishful_features - enabled_features
);
}

// 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
Expand Down
10 changes: 10 additions & 0 deletions wgpu-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ impl From<Backend> 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,
}

Expand Down Expand Up @@ -926,6 +930,11 @@ pub struct SamplerDescriptor<L> {
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<L> SamplerDescriptor<L> {
Expand All @@ -941,6 +950,7 @@ impl<L> SamplerDescriptor<L> {
lod_min_clamp: self.lod_min_clamp,
lod_max_clamp: self.lod_max_clamp,
compare: self.compare,
anisotropy_clamp: self.anisotropy_clamp,
}
}
}
Expand Down

0 comments on commit 3a6cdee

Please sign in to comment.