From 2825ac8a8e69b4c816e3ca67df2f841904ac7b69 Mon Sep 17 00:00:00 2001 From: Elabajaba Date: Fri, 14 Jun 2024 14:39:31 -0400 Subject: [PATCH] Wgpu 0.20 (#13186) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Co-authored-by: François Mockers --- crates/bevy_color/Cargo.toml | 2 +- crates/bevy_render/Cargo.toml | 8 +- crates/bevy_render/src/diagnostic/internal.rs | 8 + crates/bevy_render/src/mesh/mesh/mod.rs | 1 + crates/bevy_render/src/render_resource/mod.rs | 6 +- .../src/render_resource/pipeline_cache.rs | 172 +++++++++++------- crates/bevy_render/src/renderer/mod.rs | 12 ++ 7 files changed, 139 insertions(+), 70 deletions(-) diff --git a/crates/bevy_color/Cargo.toml b/crates/bevy_color/Cargo.toml index a7136770b691a..3d1efedcbe7de 100644 --- a/crates/bevy_color/Cargo.toml +++ b/crates/bevy_color/Cargo.toml @@ -17,7 +17,7 @@ bevy_reflect = { path = "../bevy_reflect", version = "0.14.0-dev", features = [ bytemuck = { version = "1", features = ["derive"] } serde = { version = "1.0", features = ["derive"], optional = true } 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 } [features] diff --git a/crates/bevy_render/Cargo.toml b/crates/bevy_render/Cargo.toml index 143fb1eb5ddf3..a70ddd6477847 100644 --- a/crates/bevy_render/Cargo.toml +++ b/crates/bevy_render/Cargo.toml @@ -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. # 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. -wgpu = { version = "0.19.3", default-features = false, features = [ +wgpu = { version = "0.20", default-features = false, features = [ "wgsl", "dx12", "metal", @@ -78,7 +78,7 @@ wgpu = { version = "0.19.3", default-features = false, features = [ "naga-ir", "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"] } bitflags = { version = "2.3", features = ["serde"] } 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] # 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", ] } [target.'cfg(target_arch = "wasm32")'.dependencies] -naga_oil = "0.13" +naga_oil = "0.14" js-sys = "0.3" web-sys = { version = "0.3.67", features = [ 'Blob', diff --git a/crates/bevy_render/src/diagnostic/internal.rs b/crates/bevy_render/src/diagnostic/internal.rs index c70b262cc0ee3..297e09863101b 100644 --- a/crates/bevy_render/src/diagnostic/internal.rs +++ b/crates/bevy_render/src/diagnostic/internal.rs @@ -159,6 +159,7 @@ struct FrameData { timestamps_query_set: Option, num_timestamps: u32, supports_timestamps_inside_passes: bool, + supports_timestamps_inside_encoders: bool, pipeline_statistics_query_set: Option, num_pipeline_statistics: u32, buffer_size: u64, @@ -225,6 +226,8 @@ impl FrameData { num_timestamps: 0, supports_timestamps_inside_passes: features .contains(Features::TIMESTAMP_QUERY_INSIDE_PASSES), + supports_timestamps_inside_encoders: features + .contains(Features::TIMESTAMP_QUERY_INSIDE_ENCODERS), pipeline_statistics_query_set, num_pipeline_statistics: 0, buffer_size, @@ -252,6 +255,11 @@ impl FrameData { encoder: &mut impl WriteTimestamp, is_inside_pass: bool, ) -> Option { + // `encoder.write_timestamp` is unsupported on WebGPU. + if !self.supports_timestamps_inside_encoders { + return None; + } + if is_inside_pass && !self.supports_timestamps_inside_passes { return None; } diff --git a/crates/bevy_render/src/mesh/mesh/mod.rs b/crates/bevy_render/src/mesh/mesh/mod.rs index becfb7fe8ee8e..14bb0510217d4 100644 --- a/crates/bevy_render/src/mesh/mesh/mod.rs +++ b/crates/bevy_render/src/mesh/mesh/mod.rs @@ -1237,6 +1237,7 @@ impl VertexFormatSize for VertexFormat { VertexFormat::Unorm8x4 => 4, VertexFormat::Snorm8x2 => 2, VertexFormat::Snorm8x4 => 4, + VertexFormat::Unorm10_10_10_2 => 4, VertexFormat::Uint16x2 => 2 * 2, VertexFormat::Uint16x4 => 2 * 4, VertexFormat::Sint16x2 => 2 * 2, diff --git a/crates/bevy_render/src/render_resource/mod.rs b/crates/bevy_render/src/render_resource/mod.rs index 388bf0fb08ea3..365acddc95128 100644 --- a/crates/bevy_render/src/render_resource/mod.rs +++ b/crates/bevy_render/src/render_resource/mod.rs @@ -42,9 +42,9 @@ pub use wgpu::{ Extent3d, Face, Features as WgpuFeatures, FilterMode, FragmentState as RawFragmentState, FrontFace, ImageCopyBuffer, ImageCopyBufferBase, ImageCopyTexture, ImageCopyTextureBase, ImageDataLayout, ImageSubresourceRange, IndexFormat, Limits as WgpuLimits, LoadOp, Maintain, - MapMode, MultisampleState, Operations, Origin3d, PipelineLayout, PipelineLayoutDescriptor, - PolygonMode, PrimitiveState, PrimitiveTopology, PushConstantRange, RenderPassColorAttachment, - RenderPassDepthStencilAttachment, RenderPassDescriptor, + MapMode, MultisampleState, Operations, Origin3d, PipelineCompilationOptions, PipelineLayout, + PipelineLayoutDescriptor, PolygonMode, PrimitiveState, PrimitiveTopology, PushConstantRange, + RenderPassColorAttachment, RenderPassDepthStencilAttachment, RenderPassDescriptor, RenderPipelineDescriptor as RawRenderPipelineDescriptor, SamplerBindingType, SamplerDescriptor, ShaderModule, ShaderModuleDescriptor, ShaderSource, ShaderStages, StencilFaceState, StencilOperation, StencilState, StorageTextureAccess, StoreOp, TextureAspect, diff --git a/crates/bevy_render/src/render_resource/pipeline_cache.rs b/crates/bevy_render/src/render_resource/pipeline_cache.rs index 22a95fd922749..70da7511c9b4d 100644 --- a/crates/bevy_render/src/render_resource/pipeline_cache.rs +++ b/crates/bevy_render/src/render_resource/pipeline_cache.rs @@ -25,7 +25,10 @@ use std::{ use thiserror::Error; #[cfg(feature = "shader_format_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::*; @@ -170,73 +173,17 @@ impl ShaderDefVal { impl ShaderCache { fn new(render_device: &RenderDevice, render_adapter: &RenderAdapter) -> Self { - const CAPABILITIES: &[(Features, Capabilities)] = &[ - (Features::PUSH_CONSTANTS, Capabilities::PUSH_CONSTANT), - (Features::SHADER_F64, Capabilities::FLOAT64), - ( - 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; - } - } + let (capabilities, subgroup_stages) = get_capabilities( + render_device.features(), + render_adapter.get_downlevel_capabilities().flags, + ); #[cfg(debug_assertions)] let composer = naga_oil::compose::Composer::default(); #[cfg(not(debug_assertions))] let composer = naga_oil::compose::Composer::non_validating(); - let composer = composer.with_capabilities(capabilities); + let composer = composer.with_capabilities(capabilities, subgroup_stages); Self { 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 { multiview: None, depth_stencil: descriptor.depth_stencil.clone(), @@ -802,6 +755,8 @@ impl PipelineCache { buffers: &vertex_buffer_layouts, entry_point: descriptor.vertex.entry_point.deref(), module: &vertex_module, + // TODO: Should this be the same as the fragment compilation options? + compilation_options: compilation_options.clone(), }, fragment: fragment_data .as_ref() @@ -809,6 +764,8 @@ impl PipelineCache { entry_point, module, targets, + // TODO: Should this be the same as the vertex compilation options? + compilation_options, }), }; @@ -861,6 +818,11 @@ impl PipelineCache { layout: layout.as_deref(), module: &compute_module, 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( @@ -1027,3 +989,89 @@ pub enum PipelineCacheError { #[error("Could not create shader module: {0}")] 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) +} diff --git a/crates/bevy_render/src/renderer/mod.rs b/crates/bevy_render/src/renderer/mod.rs index e4ed46f9b89d5..3fa3d51b7ffb6 100644 --- a/crates/bevy_render/src/renderer/mod.rs +++ b/crates/bevy_render/src/renderer/mod.rs @@ -326,6 +326,18 @@ pub async fn initialize_renderer( max_non_sampler_bindings: 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), }; }