[rs] Convert Extensions + Capabilities into Features

This commit is contained in:
Connor Fitzgerald
2020-06-26 00:29:47 -04:00
parent d73d471085
commit cd4baab400
10 changed files with 114 additions and 123 deletions

View File

@@ -26,14 +26,14 @@ vulkan = ["wgc/gfx-backend-vulkan"]
package = "wgpu-core"
version = "0.5"
git = "https://github.com/gfx-rs/wgpu"
rev = "285b31a6a1d041cd8983f951817390a85191ac6d"
rev = "3b6e128877d74f8310967e377c5193fd4105ee13"
features = ["raw-window-handle"]
[dependencies.wgt]
package = "wgpu-types"
version = "0.5"
git = "https://github.com/gfx-rs/wgpu"
rev = "285b31a6a1d041cd8983f951817390a85191ac6d"
rev = "3b6e128877d74f8310967e377c5193fd4105ee13"
[dependencies]
arrayvec = "0.5"

View File

@@ -24,14 +24,17 @@ async fn run(png_output_path: &str) {
create_png(png_output_path, device, buffer, &buffer_dimensions).await;
}
async fn create_red_image_with_dimensions(width: usize, height: usize) -> (Device, Buffer, BufferDimensions) {
async fn create_red_image_with_dimensions(
width: usize,
height: usize,
) -> (Device, Buffer, BufferDimensions) {
let adapter = wgpu::Instance::new(wgpu::BackendBit::PRIMARY)
.request_adapter(
&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::Default,
compatible_surface: None,
},
wgpu::UnsafeExtensions::disallow(),
wgpu::UnsafeFeatures::disallow(),
)
.await
.unwrap();
@@ -39,7 +42,7 @@ async fn create_red_image_with_dimensions(width: usize, height: usize) -> (Devic
let (device, queue) = adapter
.request_device(
&wgpu::DeviceDescriptor {
extensions: wgpu::Extensions::empty(),
features: wgpu::Features::empty(),
limits: wgpu::Limits::default(),
shader_validation: true,
},
@@ -119,8 +122,13 @@ async fn create_red_image_with_dimensions(width: usize, height: usize) -> (Devic
(device, output_buffer, buffer_dimensions)
}
async fn create_png(png_output_path: &str, device: Device, output_buffer: Buffer, buffer_dimensions: &BufferDimensions) {
// Note that we're not calling `.await` here.
async fn create_png(
png_output_path: &str,
device: Device,
output_buffer: Buffer,
buffer_dimensions: &BufferDimensions,
) {
// Note that we're not calling `.await` here.
let buffer_slice = output_buffer.slice(..);
let buffer_future = buffer_slice.map_async(wgpu::MapMode::Read);
@@ -151,7 +159,9 @@ async fn create_png(png_output_path: &str, device: Device, output_buffer: Buffer
// from the padded_buffer we write just the unpadded bytes into the image
for chunk in padded_buffer.chunks(buffer_dimensions.padded_bytes_per_row) {
png_writer.write(&chunk[..buffer_dimensions.unpadded_bytes_per_row]).unwrap();
png_writer
.write(&chunk[..buffer_dimensions.unpadded_bytes_per_row])
.unwrap();
}
png_writer.finish().unwrap();
@@ -177,25 +187,29 @@ impl BufferDimensions {
let align = wgpu::COPY_BYTES_PER_ROW_ALIGNMENT as usize;
let padded_bytes_per_row_padding = (align - unpadded_bytes_per_row % align) % align;
let padded_bytes_per_row = unpadded_bytes_per_row + padded_bytes_per_row_padding;
Self { width, height, unpadded_bytes_per_row, padded_bytes_per_row }
Self {
width,
height,
unpadded_bytes_per_row,
padded_bytes_per_row,
}
}
}
fn main() {
#[cfg(not(target_arch = "wasm32"))]
{
env_logger::init();
futures::executor::block_on(run("red.png"));
}
{
env_logger::init();
futures::executor::block_on(run("red.png"));
}
#[cfg(target_arch = "wasm32")]
{
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
console_log::init().expect("could not initialize logger");
wasm_bindgen_futures::spawn_local(run("red.png"));
}
{
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
console_log::init().expect("could not initialize logger");
wasm_bindgen_futures::spawn_local(run("red.png"));
}
}
#[cfg(test)]
mod tests {
use super::*;
@@ -207,25 +221,30 @@ mod tests {
}
async fn assert_generated_data_matches_expected() {
let (device, output_buffer, dimensions) = create_red_image_with_dimensions(100usize, 200usize).await;
let (device, output_buffer, dimensions) =
create_red_image_with_dimensions(100usize, 200usize).await;
let buffer_slice = output_buffer.slice(..);
let buffer_future = buffer_slice.map_async(wgpu::MapMode::Read);
device.poll(wgpu::Maintain::Wait);
buffer_future.await.expect("failed to map buffer slice for capture test");
buffer_future
.await
.expect("failed to map buffer slice for capture test");
let padded_buffer = buffer_slice.get_mapped_range();
let expected_buffer_size = dimensions.padded_bytes_per_row*dimensions.height;
assert_eq!(padded_buffer.len(),expected_buffer_size);
let expected_buffer_size = dimensions.padded_bytes_per_row * dimensions.height;
assert_eq!(padded_buffer.len(), expected_buffer_size);
assert_that_content_is_all_red(&dimensions, padded_buffer);
}
fn assert_that_content_is_all_red(dimensions: &BufferDimensions, padded_buffer: BufferView) {
let red = [0xFFu8, 0, 0, 0xFFu8];
let single_rgba = 4;
padded_buffer.chunks(dimensions.padded_bytes_per_row)
padded_buffer
.chunks(dimensions.padded_bytes_per_row)
.map(|padded_buffer_row| &padded_buffer_row[..dimensions.unpadded_bytes_per_row])
.for_each(|unpadded_row|
unpadded_row.chunks(single_rgba)
.for_each(|unpadded_row| {
unpadded_row
.chunks(single_rgba)
.for_each(|chunk| assert_eq!(chunk, &red))
);
});
}
}
}

View File

@@ -30,8 +30,8 @@ pub enum ShaderStage {
}
pub trait Example: 'static + Sized {
fn needed_extensions() -> (wgt::Extensions, wgt::UnsafeExtensions) {
(wgpu::Extensions::empty(), wgt::UnsafeExtensions::disallow())
fn needed_features() -> (wgpu::Features, wgpu::UnsafeFeatures) {
(wgpu::Features::empty(), wgt::UnsafeFeatures::disallow())
}
fn init(
sc_desc: &wgpu::SwapChainDescriptor,
@@ -85,7 +85,7 @@ async fn setup<E: Example>(title: &str) -> Setup {
(size, surface)
};
let (needed_extensions, unsafe_extensions) = E::needed_extensions();
let (needed_features, unsafe_extensions) = E::needed_features();
let adapter = instance
.request_adapter(
@@ -98,13 +98,13 @@ async fn setup<E: Example>(title: &str) -> Setup {
.await
.unwrap();
let adapter_extensions = adapter.extensions();
let adapter_features = adapter.features();
let trace_dir = std::env::var("WGPU_TRACE");
let (device, queue) = adapter
.request_device(
&wgpu::DeviceDescriptor {
extensions: adapter_extensions & needed_extensions,
features: adapter_features & needed_features,
limits: wgpu::Limits::default(),
shader_validation: true,
},

View File

@@ -29,7 +29,7 @@ async fn execute_gpu(numbers: Vec<u32>) -> Vec<u32> {
power_preference: wgpu::PowerPreference::Default,
compatible_surface: None,
},
wgpu::UnsafeExtensions::disallow(),
wgpu::UnsafeFeatures::disallow(),
)
.await
.unwrap();
@@ -37,7 +37,7 @@ async fn execute_gpu(numbers: Vec<u32>) -> Vec<u32> {
let (device, queue) = adapter
.request_device(
&wgpu::DeviceDescriptor {
extensions: wgpu::Extensions::empty(),
features: wgpu::Features::empty(),
limits: wgpu::Limits::default(),
shader_validation: true,
},

View File

@@ -14,7 +14,7 @@ async fn run(event_loop: EventLoop<()>, window: Window, swapchain_format: wgpu::
power_preference: wgpu::PowerPreference::Default,
compatible_surface: Some(&surface),
},
wgpu::UnsafeExtensions::disallow(),
wgpu::UnsafeFeatures::disallow(),
)
.await
.unwrap();
@@ -22,7 +22,7 @@ async fn run(event_loop: EventLoop<()>, window: Window, swapchain_format: wgpu::
let (device, queue) = adapter
.request_device(
&wgpu::DeviceDescriptor {
extensions: wgpu::Extensions::empty(),
features: wgpu::Features::empty(),
limits: wgpu::Limits::default(),
shader_validation: true,
},

View File

@@ -6,7 +6,7 @@ async fn run() {
power_preference: wgpu::PowerPreference::Default,
compatible_surface: None,
},
unsafe { wgpu::UnsafeExtensions::allow() },
unsafe { wgpu::UnsafeFeatures::allow() },
)
.await
.unwrap();

View File

@@ -85,10 +85,13 @@ struct Example {
}
impl framework::Example for Example {
fn needed_extensions() -> (wgpu::Extensions, wgpu::UnsafeExtensions) {
fn needed_features() -> (wgpu::Features, wgpu::UnsafeFeatures) {
(
wgpu::Extensions::BINDING_INDEXING,
wgpu::UnsafeExtensions::disallow(),
wgpu::Features::UNSIZED_BINDING_ARRAY
| wgpu::Features::SAMPLED_TEXTURE_ARRAY_NON_UNIFORM_INDEXING
| wgpu::Features::SAMPLED_TEXTURE_ARRAY_DYNAMIC_INDEXING
| wgpu::Features::SAMPLED_TEXTURE_BINDING_ARRAY,
wgpu::UnsafeFeatures::disallow(),
)
}
fn init(
@@ -98,22 +101,24 @@ impl framework::Example for Example {
) -> Self {
let mut uniform_workaround = false;
let vs_module = device.create_shader_module(wgpu::include_spirv!("shader.vert.spv"));
let fs_bytes: Vec<u8> = match device.capabilities() {
c if c.contains(wgpu::Capabilities::UNSIZED_BINDING_ARRAY) => {
let fs_bytes: Vec<u8> = match device.features() {
f if f.contains(wgpu::Features::UNSIZED_BINDING_ARRAY) => {
include_bytes!("unsized-non-uniform.frag.spv").to_vec()
}
c if c.contains(wgpu::Capabilities::SAMPLED_TEXTURE_ARRAY_NON_UNIFORM_INDEXING) => {
f if f.contains(wgpu::Features::SAMPLED_TEXTURE_ARRAY_NON_UNIFORM_INDEXING) => {
include_bytes!("non-uniform.frag.spv").to_vec()
}
c if c.contains(wgpu::Capabilities::SAMPLED_TEXTURE_ARRAY_DYNAMIC_INDEXING) => {
f if f.contains(wgpu::Features::SAMPLED_TEXTURE_ARRAY_DYNAMIC_INDEXING) => {
uniform_workaround = true;
include_bytes!("uniform.frag.spv").to_vec()
}
c if c.contains(wgpu::Capabilities::SAMPLED_TEXTURE_BINDING_ARRAY) => {
f if f.contains(wgpu::Features::SAMPLED_TEXTURE_BINDING_ARRAY) => {
include_bytes!("constant.frag.spv").to_vec()
}
_ => {
panic!("Graphics adapter does not support any of the capabilities needed for this example");
panic!(
"Graphics adapter does not support any of the features needed for this example"
);
}
};
let fs_module = device.create_shader_module(wgpu::util::make_spirv(&fs_bytes));

View File

@@ -1,9 +1,9 @@
use crate::{
backend::native_gpu_future, BindGroupDescriptor, BindGroupLayoutDescriptor, BindingResource,
BufferDescriptor, Capabilities, CommandEncoderDescriptor, ComputePipelineDescriptor,
Extensions, Limits, LoadOp, MapMode, Operations, PipelineLayoutDescriptor,
RenderPipelineDescriptor, SamplerDescriptor, ShaderModuleSource, SwapChainStatus,
TextureDescriptor, TextureViewDescriptor,
BufferDescriptor, CommandEncoderDescriptor, ComputePipelineDescriptor, Features, Limits,
LoadOp, MapMode, Operations, PipelineLayoutDescriptor, RenderPipelineDescriptor,
SamplerDescriptor, ShaderModuleSource, SwapChainStatus, TextureDescriptor,
TextureViewDescriptor,
};
use arrayvec::ArrayVec;
@@ -365,14 +365,14 @@ impl crate::Context for Context {
fn instance_request_adapter(
&self,
options: &crate::RequestAdapterOptions<'_>,
unsafe_extensions: wgt::UnsafeExtensions,
unsafe_features: wgt::UnsafeFeatures,
) -> Self::RequestAdapterFuture {
let id = self.pick_adapter(
&wgc::instance::RequestAdapterOptions {
power_preference: options.power_preference,
compatible_surface: options.compatible_surface.map(|surface| surface.id),
},
unsafe_extensions,
unsafe_features,
wgc::instance::AdapterInputs::Mask(wgt::BackendBit::all(), |_| PhantomData),
);
ready(id)
@@ -388,30 +388,22 @@ impl crate::Context for Context {
ready(Ok((device_id, device_id)))
}
fn adapter_extensions(&self, adapter: &Self::AdapterId) -> Extensions {
gfx_select!(*adapter => self.adapter_extensions(*adapter))
fn adapter_features(&self, adapter: &Self::AdapterId) -> Features {
gfx_select!(*adapter => self.adapter_features(*adapter))
}
fn adapter_limits(&self, adapter: &Self::AdapterId) -> Limits {
gfx_select!(*adapter => self.adapter_limits(*adapter))
}
fn adapter_capabilities(&self, adapter: &Self::AdapterId) -> Capabilities {
gfx_select!(*adapter => self.adapter_capabilities(*adapter))
}
fn device_extensions(&self, device: &Self::DeviceId) -> Extensions {
gfx_select!(*device => self.device_extensions(*device))
fn device_features(&self, device: &Self::DeviceId) -> Features {
gfx_select!(*device => self.device_features(*device))
}
fn device_limits(&self, device: &Self::DeviceId) -> Limits {
gfx_select!(*device => self.device_limits(*device))
}
fn device_capabilities(&self, device: &Self::DeviceId) -> Capabilities {
gfx_select!(*device => self.device_capabilities(*device))
}
fn device_create_swap_chain(
&self,
device: &Self::DeviceId,

View File

@@ -687,7 +687,7 @@ impl crate::Context for Context {
fn instance_request_adapter(
&self,
options: &crate::RequestAdapterOptions<'_>,
_unsafe_extensions: wgt::UnsafeExtensions,
_unsafe_extensions: wgt::UnsafeFeatures,
) -> Self::RequestAdapterFuture {
//TODO: support this check, return `None` if the flag is not set.
// It's not trivial, since we need the Future logic to have this check,
@@ -717,9 +717,9 @@ impl crate::Context for Context {
//Error: Tracing isn't supported on the Web target
}
assert!(
!desc.extensions.intersects(crate::Extensions::ALL_NATIVE),
!desc.features.intersects(crate::Features::ALL_NATIVE),
"The web backend doesn't support any native extensions. Enabled native extensions: {:?}",
desc.extensions & crate::Extensions::ALL_NATIVE
desc.features & crate::Features::ALL_NATIVE
);
let mut mapped_desc = web_sys::GpuDeviceDescriptor::new();
// TODO: label, extensions
@@ -733,9 +733,9 @@ impl crate::Context for Context {
)
}
fn adapter_extensions(&self, _adapter: &Self::AdapterId) -> wgt::Extensions {
fn adapter_features(&self, _adapter: &Self::AdapterId) -> wgt::Features {
// TODO: web-sys has no way of getting extensions on adapters
wgt::Extensions::empty()
wgt::Features::empty()
}
fn adapter_limits(&self, _adapter: &Self::AdapterId) -> wgt::Limits {
@@ -743,14 +743,9 @@ impl crate::Context for Context {
wgt::Limits::default()
}
fn adapter_capabilities(&self, _adapter: &Self::AdapterId) -> wgt::Capabilities {
// TODO: webgpu doesn't support capabilities, so return an empty set of capabilities
wgt::Capabilities::default()
}
fn device_extensions(&self, _device: &Self::DeviceId) -> wgt::Extensions {
fn device_features(&self, _device: &Self::DeviceId) -> wgt::Features {
// TODO: web-sys has no way of getting extensions on devices
wgt::Extensions::empty()
wgt::Features::empty()
}
fn device_limits(&self, _device: &Self::DeviceId) -> wgt::Limits {
@@ -758,11 +753,6 @@ impl crate::Context for Context {
wgt::Limits::default()
}
fn device_capabilities(&self, _device: &Self::DeviceId) -> wgt::Capabilities {
// TODO: webgpu doesn't support capabilities, so return an empty set of capabilities
wgt::Capabilities::default()
}
fn device_create_swap_chain(
&self,
device: &Self::DeviceId,

View File

@@ -22,16 +22,15 @@ use parking_lot::Mutex;
pub use wgc::instance::{AdapterInfo, DeviceType};
pub use wgt::{
AddressMode, Backend, BackendBit, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingType,
BlendDescriptor, BlendFactor, BlendOperation, BufferAddress, BufferSize, BufferUsage,
Capabilities, Color, ColorStateDescriptor, ColorWrite, CommandBufferDescriptor,
CompareFunction, CullMode, DepthStencilStateDescriptor, DeviceDescriptor, DynamicOffset,
Extensions, Extent3d, FilterMode, FrontFace, IndexFormat, InputStepMode, Limits, Origin3d,
PowerPreference, PresentMode, PrimitiveTopology, RasterizationStateDescriptor,
RenderBundleEncoderDescriptor, ShaderLocation, ShaderStage, StencilOperation,
StencilStateFaceDescriptor, SwapChainDescriptor, SwapChainStatus, TextureAspect,
TextureComponentType, TextureDataLayout, TextureDimension, TextureFormat, TextureUsage,
TextureViewDimension, UnsafeExtensions, VertexAttributeDescriptor, VertexFormat,
BIND_BUFFER_ALIGNMENT, COPY_BUFFER_ALIGNMENT, COPY_BYTES_PER_ROW_ALIGNMENT,
BlendDescriptor, BlendFactor, BlendOperation, BufferAddress, BufferSize, BufferUsage, Color,
ColorStateDescriptor, ColorWrite, CommandBufferDescriptor, CompareFunction, CullMode,
DepthStencilStateDescriptor, DeviceDescriptor, DynamicOffset, Extent3d, Features, FilterMode,
FrontFace, IndexFormat, InputStepMode, Limits, Origin3d, PowerPreference, PresentMode,
PrimitiveTopology, RasterizationStateDescriptor, RenderBundleEncoderDescriptor, ShaderLocation,
ShaderStage, StencilOperation, StencilStateFaceDescriptor, SwapChainDescriptor,
SwapChainStatus, TextureAspect, TextureComponentType, TextureDataLayout, TextureDimension,
TextureFormat, TextureUsage, TextureViewDimension, UnsafeFeatures, VertexAttributeDescriptor,
VertexFormat, BIND_BUFFER_ALIGNMENT, COPY_BUFFER_ALIGNMENT, COPY_BYTES_PER_ROW_ALIGNMENT,
};
use backend::Context as C;
@@ -143,7 +142,7 @@ trait Context: Sized {
fn instance_request_adapter(
&self,
options: &RequestAdapterOptions<'_>,
unsafe_extensions: UnsafeExtensions,
unsafe_extensions: UnsafeFeatures,
) -> Self::RequestAdapterFuture;
fn adapter_request_device(
&self,
@@ -151,13 +150,11 @@ trait Context: Sized {
desc: &DeviceDescriptor,
trace_dir: Option<&std::path::Path>,
) -> Self::RequestDeviceFuture;
fn adapter_extensions(&self, adapter: &Self::AdapterId) -> Extensions;
fn adapter_features(&self, adapter: &Self::AdapterId) -> Features;
fn adapter_limits(&self, adapter: &Self::AdapterId) -> Limits;
fn adapter_capabilities(&self, adapter: &Self::AdapterId) -> Capabilities;
fn device_extensions(&self, device: &Self::DeviceId) -> Extensions;
fn device_features(&self, device: &Self::DeviceId) -> Features;
fn device_limits(&self, device: &Self::DeviceId) -> Limits;
fn device_capabilities(&self, device: &Self::DeviceId) -> Capabilities;
fn device_create_swap_chain(
&self,
device: &Self::DeviceId,
@@ -1016,13 +1013,13 @@ impl Instance {
#[cfg(not(target_arch = "wasm32"))]
pub fn enumerate_adapters(
&self,
unsafe_extensions: UnsafeExtensions,
unsafe_features: UnsafeFeatures,
backends: BackendBit,
) -> impl Iterator<Item = Adapter> {
let context = Arc::clone(&self.context);
self.context
.enumerate_adapters(
unsafe_extensions,
unsafe_features,
wgc::instance::AdapterInputs::Mask(backends, |_| PhantomData),
)
.into_iter()
@@ -1078,11 +1075,11 @@ impl Instance {
pub fn request_adapter(
&self,
options: &RequestAdapterOptions<'_>,
unsafe_extensions: UnsafeExtensions,
unsafe_features: UnsafeFeatures,
) -> impl Future<Output = Option<Adapter>> + Send {
let context = Arc::clone(&self.context);
self.context
.instance_request_adapter(options, unsafe_extensions)
.instance_request_adapter(options, unsafe_features)
.map(|option| option.map(|id| Adapter { context, id }))
}
}
@@ -1093,8 +1090,8 @@ impl Adapter {
///
/// # Panics
///
/// - Extensions specified by `desc` are not supported by this adapter.
/// - Unsafe extensions were requested but enabled when requesting the adapter.
/// - Features specified by `desc` are not supported by this adapter.
/// - Unsafe features were requested but not enabled when requesting the adapter.
/// - Limits requested exceed the values provided by the adapter.
/// - Adapter does not support all features wgpu requires to safely operate.
pub fn request_device(
@@ -1119,12 +1116,12 @@ impl Adapter {
})
}
/// List all extensions that are supported with this adapter.
/// List all features that are supported with this adapter.
///
/// Extensions must be explicitly requested in [`Adapter::request_device`] in order
/// Features must be explicitly requested in [`Adapter::request_device`] in order
/// to use them.
pub fn extensions(&self) -> Extensions {
Context::adapter_extensions(&*self.context, &self.id)
pub fn features(&self) -> Features {
Context::adapter_features(&*self.context, &self.id)
}
/// List the "best" limits that are supported by this adapter.
@@ -1135,11 +1132,6 @@ impl Adapter {
Context::adapter_limits(&*self.context, &self.id)
}
/// List all capabilities that may be used wth this adapter.
pub fn capabilities(&self) -> Capabilities {
Context::adapter_capabilities(&*self.context, &self.id)
}
/// Get info about the adapter itself.
#[cfg(not(target_arch = "wasm32"))]
pub fn get_info(&self) -> AdapterInfo {
@@ -1156,11 +1148,11 @@ impl Device {
Context::device_poll(&*self.context, &self.id, maintain);
}
/// List all extensions that may be used with this device.
/// List all features that may be used with this device.
///
/// Functions may panic if you use unsupported extensions.
pub fn extensions(&self) -> Extensions {
Context::device_extensions(&*self.context, &self.id)
/// Functions may panic if you use unsupported features.
pub fn features(&self) -> Features {
Context::device_features(&*self.context, &self.id)
}
/// List all limits that were requested of this device.
@@ -1170,13 +1162,6 @@ impl Device {
Context::device_limits(&*self.context, &self.id)
}
/// List all capabilities that may be used wth this device.
///
/// Functions may panic if you use unsupported capabilities.
pub fn capabilities(&self) -> Capabilities {
Context::device_capabilities(&*self.context, &self.id)
}
/// Creates a shader module from either SPIR-V or WGSL source code.
pub fn create_shader_module(&self, source: ShaderModuleSource) -> ShaderModule {
ShaderModule {