Currently blocked on https://github.com/gfx-rs/wgpu/issues/5774

# Objective

Update to wgpu 0.20

## Solution

Update to wgpu 0.20 and naga_oil 0.14.

## Testing

Tested a few different examples on linux (vulkan, webgl2, webgpu) and
windows (dx12 + vulkan) and they worked.

---

## Changelog

- Updated to wgpu 0.20. Note that we don't currently support wgpu's new
pipeline overridable constants, as they don't work on web currently and
need some more changes to naga_oil (and are somewhat redundant with
naga_oil's shader defs). See wgpu's changelog for more
https://github.com/gfx-rs/wgpu/blob/trunk/CHANGELOG.md#v0200-2024-04-28

## Migration Guide

TODO

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: François Mockers <mockersf@gmail.com>
This commit is contained in:
Elabajaba 2024-06-14 14:39:31 -04:00 committed by GitHub
parent 004ba585b2
commit 2825ac8a8e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 139 additions and 70 deletions

View file

@ -17,7 +17,7 @@ bevy_reflect = { path = "../bevy_reflect", version = "0.14.0-dev", features = [
bytemuck = { version = "1", features = ["derive"] } bytemuck = { version = "1", features = ["derive"] }
serde = { version = "1.0", features = ["derive"], optional = true } serde = { version = "1.0", features = ["derive"], optional = true }
thiserror = "1.0" thiserror = "1.0"
wgpu-types = { version = "0.19", default-features = false, optional = true } wgpu-types = { version = "0.20", default-features = false, optional = true }
encase = { version = "0.8", default-features = false } encase = { version = "0.8", default-features = false }
[features] [features]

View file

@ -70,7 +70,7 @@ codespan-reporting = "0.11.0"
# It is enabled for now to avoid having to do a significant overhaul of the renderer just for wasm. # It is enabled for now to avoid having to do a significant overhaul of the renderer just for wasm.
# When the 'atomics' feature is enabled `fragile-send-sync-non-atomic` does nothing # When the 'atomics' feature is enabled `fragile-send-sync-non-atomic` does nothing
# and Bevy instead wraps `wgpu` types to verify they are not used off their origin thread. # and Bevy instead wraps `wgpu` types to verify they are not used off their origin thread.
wgpu = { version = "0.19.3", default-features = false, features = [ wgpu = { version = "0.20", default-features = false, features = [
"wgsl", "wgsl",
"dx12", "dx12",
"metal", "metal",
@ -78,7 +78,7 @@ wgpu = { version = "0.19.3", default-features = false, features = [
"naga-ir", "naga-ir",
"fragile-send-sync-non-atomic-wasm", "fragile-send-sync-non-atomic-wasm",
] } ] }
naga = { version = "0.19", features = ["wgsl-in"] } naga = { version = "0.20", features = ["wgsl-in"] }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
bitflags = { version = "2.3", features = ["serde"] } bitflags = { version = "2.3", features = ["serde"] }
bytemuck = { version = "1.5", features = ["derive", "must_cast"] } bytemuck = { version = "1.5", features = ["derive", "must_cast"] }
@ -104,12 +104,12 @@ smallvec = { version = "1.11", features = ["const_new"] }
[target.'cfg(not(target_arch = "wasm32"))'.dependencies] [target.'cfg(not(target_arch = "wasm32"))'.dependencies]
# Omit the `glsl` feature in non-WebAssembly by default. # Omit the `glsl` feature in non-WebAssembly by default.
naga_oil = { version = "0.13", default-features = false, features = [ naga_oil = { version = "0.14", default-features = false, features = [
"test_shader", "test_shader",
] } ] }
[target.'cfg(target_arch = "wasm32")'.dependencies] [target.'cfg(target_arch = "wasm32")'.dependencies]
naga_oil = "0.13" naga_oil = "0.14"
js-sys = "0.3" js-sys = "0.3"
web-sys = { version = "0.3.67", features = [ web-sys = { version = "0.3.67", features = [
'Blob', 'Blob',

View file

@ -159,6 +159,7 @@ struct FrameData {
timestamps_query_set: Option<QuerySet>, timestamps_query_set: Option<QuerySet>,
num_timestamps: u32, num_timestamps: u32,
supports_timestamps_inside_passes: bool, supports_timestamps_inside_passes: bool,
supports_timestamps_inside_encoders: bool,
pipeline_statistics_query_set: Option<QuerySet>, pipeline_statistics_query_set: Option<QuerySet>,
num_pipeline_statistics: u32, num_pipeline_statistics: u32,
buffer_size: u64, buffer_size: u64,
@ -225,6 +226,8 @@ impl FrameData {
num_timestamps: 0, num_timestamps: 0,
supports_timestamps_inside_passes: features supports_timestamps_inside_passes: features
.contains(Features::TIMESTAMP_QUERY_INSIDE_PASSES), .contains(Features::TIMESTAMP_QUERY_INSIDE_PASSES),
supports_timestamps_inside_encoders: features
.contains(Features::TIMESTAMP_QUERY_INSIDE_ENCODERS),
pipeline_statistics_query_set, pipeline_statistics_query_set,
num_pipeline_statistics: 0, num_pipeline_statistics: 0,
buffer_size, buffer_size,
@ -252,6 +255,11 @@ impl FrameData {
encoder: &mut impl WriteTimestamp, encoder: &mut impl WriteTimestamp,
is_inside_pass: bool, is_inside_pass: bool,
) -> Option<u32> { ) -> Option<u32> {
// `encoder.write_timestamp` is unsupported on WebGPU.
if !self.supports_timestamps_inside_encoders {
return None;
}
if is_inside_pass && !self.supports_timestamps_inside_passes { if is_inside_pass && !self.supports_timestamps_inside_passes {
return None; return None;
} }

View file

@ -1237,6 +1237,7 @@ impl VertexFormatSize for VertexFormat {
VertexFormat::Unorm8x4 => 4, VertexFormat::Unorm8x4 => 4,
VertexFormat::Snorm8x2 => 2, VertexFormat::Snorm8x2 => 2,
VertexFormat::Snorm8x4 => 4, VertexFormat::Snorm8x4 => 4,
VertexFormat::Unorm10_10_10_2 => 4,
VertexFormat::Uint16x2 => 2 * 2, VertexFormat::Uint16x2 => 2 * 2,
VertexFormat::Uint16x4 => 2 * 4, VertexFormat::Uint16x4 => 2 * 4,
VertexFormat::Sint16x2 => 2 * 2, VertexFormat::Sint16x2 => 2 * 2,

View file

@ -42,9 +42,9 @@ pub use wgpu::{
Extent3d, Face, Features as WgpuFeatures, FilterMode, FragmentState as RawFragmentState, Extent3d, Face, Features as WgpuFeatures, FilterMode, FragmentState as RawFragmentState,
FrontFace, ImageCopyBuffer, ImageCopyBufferBase, ImageCopyTexture, ImageCopyTextureBase, FrontFace, ImageCopyBuffer, ImageCopyBufferBase, ImageCopyTexture, ImageCopyTextureBase,
ImageDataLayout, ImageSubresourceRange, IndexFormat, Limits as WgpuLimits, LoadOp, Maintain, ImageDataLayout, ImageSubresourceRange, IndexFormat, Limits as WgpuLimits, LoadOp, Maintain,
MapMode, MultisampleState, Operations, Origin3d, PipelineLayout, PipelineLayoutDescriptor, MapMode, MultisampleState, Operations, Origin3d, PipelineCompilationOptions, PipelineLayout,
PolygonMode, PrimitiveState, PrimitiveTopology, PushConstantRange, RenderPassColorAttachment, PipelineLayoutDescriptor, PolygonMode, PrimitiveState, PrimitiveTopology, PushConstantRange,
RenderPassDepthStencilAttachment, RenderPassDescriptor, RenderPassColorAttachment, RenderPassDepthStencilAttachment, RenderPassDescriptor,
RenderPipelineDescriptor as RawRenderPipelineDescriptor, SamplerBindingType, SamplerDescriptor, RenderPipelineDescriptor as RawRenderPipelineDescriptor, SamplerBindingType, SamplerDescriptor,
ShaderModule, ShaderModuleDescriptor, ShaderSource, ShaderStages, StencilFaceState, ShaderModule, ShaderModuleDescriptor, ShaderSource, ShaderStages, StencilFaceState,
StencilOperation, StencilState, StorageTextureAccess, StoreOp, TextureAspect, StencilOperation, StencilState, StorageTextureAccess, StoreOp, TextureAspect,

View file

@ -25,7 +25,10 @@ use std::{
use thiserror::Error; use thiserror::Error;
#[cfg(feature = "shader_format_spirv")] #[cfg(feature = "shader_format_spirv")]
use wgpu::util::make_spirv; use wgpu::util::make_spirv;
use wgpu::{DownlevelFlags, Features, VertexBufferLayout as RawVertexBufferLayout}; use wgpu::{
DownlevelFlags, Features, PipelineCompilationOptions,
VertexBufferLayout as RawVertexBufferLayout,
};
use crate::render_resource::resource_macros::*; use crate::render_resource::resource_macros::*;
@ -170,73 +173,17 @@ impl ShaderDefVal {
impl ShaderCache { impl ShaderCache {
fn new(render_device: &RenderDevice, render_adapter: &RenderAdapter) -> Self { fn new(render_device: &RenderDevice, render_adapter: &RenderAdapter) -> Self {
const CAPABILITIES: &[(Features, Capabilities)] = &[ let (capabilities, subgroup_stages) = get_capabilities(
(Features::PUSH_CONSTANTS, Capabilities::PUSH_CONSTANT), render_device.features(),
(Features::SHADER_F64, Capabilities::FLOAT64), render_adapter.get_downlevel_capabilities().flags,
( );
Features::SHADER_PRIMITIVE_INDEX,
Capabilities::PRIMITIVE_INDEX,
),
(
Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
Capabilities::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
),
(
Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
Capabilities::SAMPLER_NON_UNIFORM_INDEXING,
),
(
Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING,
Capabilities::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING,
),
(
Features::TEXTURE_FORMAT_16BIT_NORM,
Capabilities::STORAGE_TEXTURE_16BIT_NORM_FORMATS,
),
(Features::MULTIVIEW, Capabilities::MULTIVIEW),
(
Features::SHADER_EARLY_DEPTH_TEST,
Capabilities::EARLY_DEPTH_TEST,
),
];
let features = render_device.features();
let mut capabilities = Capabilities::empty();
for (feature, capability) in CAPABILITIES {
if features.contains(*feature) {
capabilities |= *capability;
}
}
const DOWNLEVEL_FLAGS_CAPABILITIES: &[(DownlevelFlags, Capabilities)] = &[
(
DownlevelFlags::CUBE_ARRAY_TEXTURES,
Capabilities::CUBE_ARRAY_TEXTURES,
),
(
DownlevelFlags::MULTISAMPLED_SHADING,
Capabilities::MULTISAMPLED_SHADING,
),
(
DownlevelFlags::CUBE_ARRAY_TEXTURES,
Capabilities::CUBE_ARRAY_TEXTURES,
),
];
for (downlevel_flag, capability) in DOWNLEVEL_FLAGS_CAPABILITIES {
if render_adapter
.get_downlevel_capabilities()
.flags
.contains(*downlevel_flag)
{
capabilities |= *capability;
}
}
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
let composer = naga_oil::compose::Composer::default(); let composer = naga_oil::compose::Composer::default();
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
let composer = naga_oil::compose::Composer::non_validating(); let composer = naga_oil::compose::Composer::non_validating();
let composer = composer.with_capabilities(capabilities); let composer = composer.with_capabilities(capabilities, subgroup_stages);
Self { Self {
composer, composer,
@ -791,6 +738,12 @@ impl PipelineCache {
) )
}); });
// TODO: Expose this somehow
let compilation_options = PipelineCompilationOptions {
constants: &std::collections::HashMap::new(),
zero_initialize_workgroup_memory: false,
};
let descriptor = RawRenderPipelineDescriptor { let descriptor = RawRenderPipelineDescriptor {
multiview: None, multiview: None,
depth_stencil: descriptor.depth_stencil.clone(), depth_stencil: descriptor.depth_stencil.clone(),
@ -802,6 +755,8 @@ impl PipelineCache {
buffers: &vertex_buffer_layouts, buffers: &vertex_buffer_layouts,
entry_point: descriptor.vertex.entry_point.deref(), entry_point: descriptor.vertex.entry_point.deref(),
module: &vertex_module, module: &vertex_module,
// TODO: Should this be the same as the fragment compilation options?
compilation_options: compilation_options.clone(),
}, },
fragment: fragment_data fragment: fragment_data
.as_ref() .as_ref()
@ -809,6 +764,8 @@ impl PipelineCache {
entry_point, entry_point,
module, module,
targets, targets,
// TODO: Should this be the same as the vertex compilation options?
compilation_options,
}), }),
}; };
@ -861,6 +818,11 @@ impl PipelineCache {
layout: layout.as_deref(), layout: layout.as_deref(),
module: &compute_module, module: &compute_module,
entry_point: &descriptor.entry_point, entry_point: &descriptor.entry_point,
// TODO: Expose this somehow
compilation_options: PipelineCompilationOptions {
constants: &std::collections::HashMap::new(),
zero_initialize_workgroup_memory: false,
},
}; };
Ok(Pipeline::ComputePipeline( Ok(Pipeline::ComputePipeline(
@ -1027,3 +989,89 @@ pub enum PipelineCacheError {
#[error("Could not create shader module: {0}")] #[error("Could not create shader module: {0}")]
CreateShaderModule(String), CreateShaderModule(String),
} }
// TODO: This needs to be kept up to date with the capabilities in the `create_validator` function in wgpu-core
// https://github.com/gfx-rs/wgpu/blob/trunk/wgpu-core/src/device/mod.rs#L449
// We use a modified version of the `create_validator` function because `naga_oil`'s composer stores the capabilities
// and subgroup shader stages instead of a `Validator`.
// We also can't use that function because `wgpu-core` isn't included in WebGPU builds.
/// Get the device capabilities and subgroup support for use in `naga_oil`.
fn get_capabilities(
features: Features,
downlevel: DownlevelFlags,
) -> (Capabilities, naga::valid::ShaderStages) {
let mut capabilities = Capabilities::empty();
capabilities.set(
Capabilities::PUSH_CONSTANT,
features.contains(Features::PUSH_CONSTANTS),
);
capabilities.set(
Capabilities::FLOAT64,
features.contains(Features::SHADER_F64),
);
capabilities.set(
Capabilities::PRIMITIVE_INDEX,
features.contains(Features::SHADER_PRIMITIVE_INDEX),
);
capabilities.set(
Capabilities::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
features.contains(Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING),
);
capabilities.set(
Capabilities::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING,
features.contains(Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING),
);
// TODO: This needs a proper wgpu feature
capabilities.set(
Capabilities::SAMPLER_NON_UNIFORM_INDEXING,
features.contains(Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING),
);
capabilities.set(
Capabilities::STORAGE_TEXTURE_16BIT_NORM_FORMATS,
features.contains(Features::TEXTURE_FORMAT_16BIT_NORM),
);
capabilities.set(
Capabilities::MULTIVIEW,
features.contains(Features::MULTIVIEW),
);
capabilities.set(
Capabilities::EARLY_DEPTH_TEST,
features.contains(Features::SHADER_EARLY_DEPTH_TEST),
);
capabilities.set(
Capabilities::SHADER_INT64,
features.contains(Features::SHADER_INT64),
);
capabilities.set(
Capabilities::MULTISAMPLED_SHADING,
downlevel.contains(DownlevelFlags::MULTISAMPLED_SHADING),
);
capabilities.set(
Capabilities::DUAL_SOURCE_BLENDING,
features.contains(Features::DUAL_SOURCE_BLENDING),
);
capabilities.set(
Capabilities::CUBE_ARRAY_TEXTURES,
downlevel.contains(DownlevelFlags::CUBE_ARRAY_TEXTURES),
);
capabilities.set(
Capabilities::SUBGROUP,
features.intersects(Features::SUBGROUP | Features::SUBGROUP_VERTEX),
);
capabilities.set(
Capabilities::SUBGROUP_BARRIER,
features.intersects(Features::SUBGROUP_BARRIER),
);
let mut subgroup_stages = naga::valid::ShaderStages::empty();
subgroup_stages.set(
naga::valid::ShaderStages::COMPUTE | naga::valid::ShaderStages::FRAGMENT,
features.contains(Features::SUBGROUP),
);
subgroup_stages.set(
naga::valid::ShaderStages::VERTEX,
features.contains(Features::SUBGROUP_VERTEX),
);
(capabilities, subgroup_stages)
}

View file

@ -326,6 +326,18 @@ pub async fn initialize_renderer(
max_non_sampler_bindings: limits max_non_sampler_bindings: limits
.max_non_sampler_bindings .max_non_sampler_bindings
.min(constrained_limits.max_non_sampler_bindings), .min(constrained_limits.max_non_sampler_bindings),
max_color_attachments: limits
.max_color_attachments
.min(constrained_limits.max_color_attachments),
max_color_attachment_bytes_per_sample: limits
.max_color_attachment_bytes_per_sample
.min(constrained_limits.max_color_attachment_bytes_per_sample),
min_subgroup_size: limits
.min_subgroup_size
.max(constrained_limits.min_subgroup_size),
max_subgroup_size: limits
.max_subgroup_size
.min(constrained_limits.max_subgroup_size),
}; };
} }