Add downlevel infrastructure

This commit is contained in:
Connor Fitzgerald
2021-03-31 00:59:38 -04:00
parent 41f106d7fc
commit 4db9a4522e
3 changed files with 114 additions and 7 deletions

View File

@@ -284,6 +284,7 @@ pub struct Device<B: hal::Backend> {
pub(crate) private_features: PrivateFeatures,
pub(crate) limits: wgt::Limits,
pub(crate) features: wgt::Features,
pub(crate) downlevel: wgt::DownlevelProperties,
spv_options: naga::back::spv::Options,
//TODO: move this behind another mutex. This would allow several methods to switch
// to borrow Device immutably, such as `write_buffer`, `write_texture`, and `buffer_unmap`.
@@ -307,6 +308,7 @@ impl<B: GfxBackend> Device<B> {
mem_props: hal::adapter::MemoryProperties,
hal_limits: hal::Limits,
private_features: PrivateFeatures,
downlevel: wgt::DownlevelProperties,
desc: &DeviceDescriptor,
trace_path: Option<&std::path::Path>,
) -> Result<Self, CreateDeviceError> {
@@ -376,6 +378,7 @@ impl<B: GfxBackend> Device<B> {
private_features,
limits: desc.limits.clone(),
features: desc.features,
downlevel,
spv_options,
pending_writes: queue::PendingWrites::new(),
})
@@ -1017,7 +1020,8 @@ impl<B: GfxBackend> Device<B> {
let (naga_result, interface) = match module {
// If succeeded, then validate it and attempt to give it to gfx-hal directly.
Some(module) if desc.flags.contains(wgt::ShaderFlags::VALIDATION) || spv.is_none() => {
let info = naga::valid::Validator::new(naga::valid::ValidationFlags::all()).validate(&module)?;
let info = naga::valid::Validator::new(naga::valid::ValidationFlags::all())
.validate(&module)?;
if !self.features.contains(wgt::Features::PUSH_CONSTANTS)
&& module
.global_variables
@@ -1060,12 +1064,8 @@ impl<B: GfxBackend> Device<B> {
None => {
// Produce a SPIR-V from the Naga module
let shader = maybe_shader.unwrap();
naga::back::spv::write_vec(
&shader.module,
&shader.info,
&self.spv_options,
)
.map(Cow::Owned)
naga::back::spv::write_vec(&shader.module, &shader.info, &self.spv_options)
.map(Cow::Owned)
}
};
match spv {
@@ -2656,6 +2656,20 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
Ok(device.limits.clone())
}
pub fn device_downlevel_properties<B: GfxBackend>(
&self,
device_id: id::DeviceId,
) -> Result<wgt::DownlevelProperties, InvalidDevice> {
profiling::scope!("Device::downlevel_properties");
let hub = B::hub(self);
let mut token = Token::root();
let (device_guard, _) = hub.devices.read(&mut token);
let device = device_guard.get(device_id).map_err(|_| InvalidDevice)?;
Ok(device.downlevel)
}
pub fn device_create_buffer<B: GfxBackend>(
&self,
device_id: id::DeviceId,

View File

@@ -122,6 +122,7 @@ pub struct Adapter<B: hal::Backend> {
features: wgt::Features,
pub(crate) private_features: PrivateFeatures,
limits: wgt::Limits,
downlevel: wgt::DownlevelProperties,
life_guard: LifeGuard,
}
@@ -274,11 +275,28 @@ impl<B: GfxBackend> Adapter<B> {
.max(MIN_PUSH_CONSTANT_SIZE), // As an extension, the default is always 0, so define a separate minimum.
};
let downlevel = wgt::DownlevelProperties {
compute_shaders: properties.downlevel.compute_shaders,
shader_model: match properties.downlevel.shader_model {
hal::DownlevelShaderModel::ShaderModel2 => wgt::ShaderModel::Sm2,
hal::DownlevelShaderModel::ShaderModel4 => wgt::ShaderModel::Sm4,
hal::DownlevelShaderModel::ShaderModel5 => wgt::ShaderModel::Sm5,
},
storage_images: properties.downlevel.storage_images,
read_only_depth_stencil: properties.downlevel.read_only_depth_stencil,
device_local_image_copies: properties.downlevel.device_local_image_copies,
non_power_of_two_mipmapped_textures: properties
.downlevel
.non_power_of_two_mipmapped_textures,
anisotropic_filtering: private_features.anisotropic_filtering,
};
Self {
raw,
features,
private_features,
limits,
downlevel,
life_guard: LifeGuard::new("<Adapter>"),
}
}
@@ -523,6 +541,7 @@ impl<B: GfxBackend> Adapter<B> {
mem_props,
limits,
self.private_features,
self.downlevel,
desc,
trace_path,
)
@@ -926,6 +945,21 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
.map_err(|_| InvalidAdapter)
}
pub fn adapter_downlevel_properties<B: GfxBackend>(
&self,
adapter_id: AdapterId,
) -> Result<wgt::DownlevelProperties, InvalidAdapter> {
profiling::scope!("Adapter::downlevel_properties");
let hub = B::hub(self);
let mut token = Token::root();
let (adapter_guard, _) = hub.adapters.read(&mut token);
adapter_guard
.get(adapter_id)
.map(|adapter| adapter.downlevel)
.map_err(|_| InvalidAdapter)
}
pub fn adapter_drop<B: GfxBackend>(&self, adapter_id: AdapterId) {
profiling::scope!("Adapter::drop");

View File

@@ -538,6 +538,65 @@ impl Default for Limits {
}
}
/// Lists various ways the underlying platform does not conform to the WebGPU standard.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DownlevelProperties {
/// The device supports compiling and using compute shaders.
pub compute_shaders: bool,
/// Which collections of features shaders support. Defined in terms of D3D's shader models.
pub shader_model: ShaderModel,
/// Supports creating storage images.
pub storage_images: bool,
/// Supports reading from a depth/stencil buffer while using as a read-only depth/stencil attachment.
pub read_only_depth_stencil: bool,
/// Supports:
/// - copy_image_to_image
/// - copy_buffer_to_image and copy_image_to_buffer with a buffer without a MAP_* usage
pub device_local_image_copies: bool,
/// Supports textures with mipmaps which have a non power of two size.
pub non_power_of_two_mipmapped_textures: bool,
/// Supports samplers with anisotropic filtering
pub anisotropic_filtering: bool,
}
impl Default for DownlevelProperties {
// Note, this defaults to all on, as that is the default assumption in wgpu.
// gfx-hal's equivalent structure defaults to all off.
fn default() -> Self {
Self {
compute_shaders: true,
shader_model: ShaderModel::Sm5,
storage_images: true,
read_only_depth_stencil: true,
device_local_image_copies: true,
non_power_of_two_mipmapped_textures: true,
anisotropic_filtering: true,
}
}
}
impl DownlevelProperties {
/// Returns true if the underlying platform offers complete support of the baseline WebGPU standard.
///
/// If this returns false, some parts of the API will result in validation errors where they would not normally.
/// These parts can be determined by the values in this structure.
pub fn is_webgpu_compliant(self) -> bool {
self == Self::default()
}
}
/// Collections of shader features a device supports if they support less than WebGPU normally allows.
// TODO: Fill out the differences between shader models more completely
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum ShaderModel {
/// Extremely limited shaders, including a total instruction limit.
Sm2,
/// Missing minor features and storage images.
Sm4,
/// WebGPU supports shader module 5.
Sm5,
}
/// Supported physical device types.
#[repr(u8)]
#[derive(Clone, Debug, PartialEq)]