From bca19c8acee5190b2a67bb334eddab6d0cb1bc1d Mon Sep 17 00:00:00 2001 From: Max Ammann Date: Sat, 8 Apr 2023 22:54:40 -0400 Subject: [PATCH] Upgrade wgpu to 0.15.1 (#250) * Apply changes for wgpu 0.15 * Add msaa detection * Enable msaa by default * Add simplified diagram * Resolve some unwraps --- .../src/development-documents/architecture.md | 4 + .../simplified-render-stack.drawio.svg | 4 + maplibre-winit/Cargo.toml | 4 +- maplibre/Cargo.toml | 3 +- maplibre/src/raster/resource_system.rs | 2 +- maplibre/src/render/error.rs | 2 + maplibre/src/render/mod.rs | 37 ++++++--- maplibre/src/render/resource/surface.rs | 79 +++++++++++++++---- maplibre/src/render/resource/texture.rs | 1 + maplibre/src/render/resource/tile_pipeline.rs | 6 +- maplibre/src/render/settings.rs | 3 +- .../src/render/systems/resource_system.rs | 13 ++- maplibre/src/vector/resource_system.rs | 2 +- web/Cargo.toml | 6 +- 14 files changed, 125 insertions(+), 41 deletions(-) create mode 100644 docs/src/development-documents/figures/simplified-render-stack.drawio.svg diff --git a/docs/src/development-documents/architecture.md b/docs/src/development-documents/architecture.md index 8f67e2ff..1f62a256 100644 --- a/docs/src/development-documents/architecture.md +++ b/docs/src/development-documents/architecture.md @@ -10,6 +10,10 @@ A simplified version is shown below: ![](./figures/render-stack.drawio.svg) +A further simplified version: + +![](./figures/simplified-render-stack.drawio.svg) + Notes: * wgpu is able to create an interface through which we can reach any device with a GPU. diff --git a/docs/src/development-documents/figures/simplified-render-stack.drawio.svg b/docs/src/development-documents/figures/simplified-render-stack.drawio.svg new file mode 100644 index 00000000..c5f5d4c8 --- /dev/null +++ b/docs/src/development-documents/figures/simplified-render-stack.drawio.svg @@ -0,0 +1,4 @@ + + + +
maplibre-rs
maplibre-rs
Metal
Metal
WebGPU
WebGPU
DirectX
DirectX
Vulkan
Vulkan
OpenGL
OpenGL
WebGPU
WebGPU
OS Drivers
OS Drivers
WebGL
WebGL
Text is not SVG - cannot display
\ No newline at end of file diff --git a/maplibre-winit/Cargo.toml b/maplibre-winit/Cargo.toml index 9f67bc6c..26a60e34 100644 --- a/maplibre-winit/Cargo.toml +++ b/maplibre-winit/Cargo.toml @@ -20,8 +20,8 @@ winit = { version = "0.27.2", default-features = false, features = ["x11", "wayl [target.'cfg(target_arch = "wasm32")'.dependencies] web-sys = { version = "0.3.58", features = ["Window"] } -wasm-bindgen = "0.2.81" -wasm-bindgen-futures = "0.4.31" +wasm-bindgen = "0.2" +wasm-bindgen-futures = "0.4" [dependencies] maplibre = { path = "../maplibre", version = "0.1.0" } diff --git a/maplibre/Cargo.toml b/maplibre/Cargo.toml index e7960ceb..86142dfe 100644 --- a/maplibre/Cargo.toml +++ b/maplibre/Cargo.toml @@ -55,7 +55,8 @@ geozero = { version = "0.9.7", default-features = false, features = ["with-mvt", tile-grid = "0.3.0" # Rendering -wgpu = "0.14.0" +wgpu = "0.15.0" +# wgpu = { git = "https://github.com/gfx-rs/wgpu" } lyon = { version = "1.0.0", features = [] } raw-window-handle = "0.5.0" diff --git a/maplibre/src/raster/resource_system.rs b/maplibre/src/raster/resource_system.rs index 008535c3..56fa0ab0 100644 --- a/maplibre/src/raster/resource_system.rs +++ b/maplibre/src/raster/resource_system.rs @@ -46,7 +46,7 @@ pub fn resource_system( false, false, false, - true, + surface.is_multisampling_supported(settings.msaa), true, ) .describe_render_pipeline() diff --git a/maplibre/src/render/error.rs b/maplibre/src/render/error.rs index 2d866493..affb0966 100644 --- a/maplibre/src/render/error.rs +++ b/maplibre/src/render/error.rs @@ -6,6 +6,8 @@ use crate::render::graph::RenderGraphError; pub enum RenderError { #[error("error in surface")] Surface(#[from] wgpu::SurfaceError), + #[error("error during surface creation")] + CreateSurfaceError(#[from] wgpu::CreateSurfaceError), #[error("error in render graph")] Graph(#[from] RenderGraphError), #[error("error while requesting device")] diff --git a/maplibre/src/render/mod.rs b/maplibre/src/render/mod.rs index 95c99fd4..f4d12afd 100644 --- a/maplibre/src/render/mod.rs +++ b/maplibre/src/render/mod.rs @@ -124,11 +124,15 @@ impl RenderResources { } } - pub fn recreate_surface(&mut self, window: &MW, instance: &wgpu::Instance) + pub fn recreate_surface( + &mut self, + window: &MW, + instance: &wgpu::Instance, + ) -> Result<(), RenderError> where MW: MapWindow + HeadedMapWindow, { - self.surface.recreate::(window, instance); + self.surface.recreate::(window, instance) } pub fn surface(&self) -> &Surface { @@ -160,9 +164,12 @@ impl Renderer { where MW: MapWindow + HeadedMapWindow, { - let instance = wgpu::Instance::new(wgpu_settings.backends.unwrap_or(wgpu::Backends::all())); + let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { + backends: wgpu_settings.backends.unwrap_or(wgpu::Backends::all()), + dx12_shader_compiler: Default::default(), + }); - let surface: wgpu::Surface = unsafe { instance.create_surface(window.raw()) }; + let surface: wgpu::Surface = unsafe { instance.create_surface(window.raw())? }; let (adapter, device, queue) = Self::request_device( &instance, @@ -202,7 +209,10 @@ impl Renderer { where MW: MapWindow, { - let instance = wgpu::Instance::new(wgpu_settings.backends.unwrap_or(wgpu::Backends::all())); + let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { + backends: wgpu_settings.backends.unwrap_or(wgpu::Backends::all()), + dx12_shader_compiler: Default::default(), + }); let (adapter, device, queue) = Self::request_device( &instance, @@ -300,6 +310,9 @@ impl Renderer { max_bind_groups: limits .max_bind_groups .min(constrained_limits.max_bind_groups), + max_bindings_per_bind_group: limits + .max_bindings_per_bind_group + .min(constrained_limits.max_bindings_per_bind_group), max_dynamic_uniform_buffers_per_pipeline_layout: limits .max_dynamic_uniform_buffers_per_pipeline_layout .min(constrained_limits.max_dynamic_uniform_buffers_per_pipeline_layout), @@ -448,7 +461,10 @@ mod tests { let graph = RenderGraph::default(); let backends = wgpu::util::backend_bits_from_env().unwrap_or(wgpu::Backends::all()); - let instance = wgpu::Instance::new(backends); + let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { + backends, + dx12_shader_compiler: Default::default(), + }); let adapter = wgpu::util::initialize_adapter_from_env_or_default(&instance, backends, None) .await .expect("Unable to initialize adapter"); @@ -468,13 +484,14 @@ mod tests { let render_state = RenderResources::new(Surface::from_image( &device, &HeadlessMapWindow { - size: WindowSize::new(100, 100).unwrap(), + size: WindowSize::new(100, 100).expect("invalid headless map size"), }, &RendererSettings::default(), )); let world = World::default(); - RenderGraphRunner::run(&graph, &device, &queue, &render_state, &world).unwrap(); + RenderGraphRunner::run(&graph, &device, &queue, &render_state, &world) + .expect("failed to run graph runner"); } } @@ -534,7 +551,7 @@ impl Plugin for RenderPlugin { // Edges draw_graph .add_node_edge(input_node_id, draw_graph::node::MAIN_PASS) - .unwrap(); + .expect("main pass or draw node does not exist"); graph.add_sub_graph(draw_graph::NAME, draw_graph); graph.add_node(main_graph::node::MAIN_PASS_DEPENDENCIES, EmptyNode); @@ -544,7 +561,7 @@ impl Plugin for RenderPlugin { main_graph::node::MAIN_PASS_DEPENDENCIES, main_graph::node::MAIN_PASS_DRIVER, ) - .unwrap(); + .expect("main pass driver or dependencies do not exist"); // render graph dependency resources.init::>(); diff --git a/maplibre/src/render/resource/surface.rs b/maplibre/src/render/resource/surface.rs index b4f33064..c1435714 100644 --- a/maplibre/src/render/resource/surface.rs +++ b/maplibre/src/render/resource/surface.rs @@ -3,10 +3,15 @@ use std::{mem::size_of, num::NonZeroU32, sync::Arc}; -use log::debug; +use wgpu::TextureFormatFeatures; use crate::{ - render::{eventually::HasChanged, resource::texture::TextureView, settings::RendererSettings}, + render::{ + error::RenderError, + eventually::HasChanged, + resource::texture::TextureView, + settings::{Msaa, RendererSettings}, + }, window::{HeadedMapWindow, MapWindow, WindowSize}, }; @@ -38,8 +43,10 @@ impl BufferDimensions { pub struct WindowHead { surface: wgpu::Surface, size: WindowSize, - format: wgpu::TextureFormat, + + texture_format: wgpu::TextureFormat, present_mode: wgpu::PresentMode, + texture_format_features: TextureFormatFeatures, } impl WindowHead { @@ -52,20 +59,26 @@ impl WindowHead { let surface_config = wgpu::SurfaceConfiguration { alpha_mode: wgpu::CompositeAlphaMode::Auto, usage: wgpu::TextureUsages::RENDER_ATTACHMENT, - format: self.format, + format: self.texture_format, width: self.size.width(), height: self.size.height(), present_mode: self.present_mode, + view_formats: vec![self.texture_format], }; self.surface.configure(device, &surface_config); } - pub fn recreate_surface(&mut self, window: &MW, instance: &wgpu::Instance) + pub fn recreate_surface( + &mut self, + window: &MW, + instance: &wgpu::Instance, + ) -> Result<(), RenderError> where MW: MapWindow + HeadedMapWindow, { - self.surface = unsafe { instance.create_surface(window.raw()) }; + self.surface = unsafe { instance.create_surface(window.raw())? }; + Ok(()) } pub fn surface(&self) -> &wgpu::Surface { @@ -170,22 +183,25 @@ impl Surface { { let size = window.size(); - debug!( - "supported formats by adapter: {:?}", - surface.get_supported_formats(adapter) - ); + let capabilities = surface.get_capabilities(adapter); + log::info!("adapter capabilities on surface: {:?}", capabilities); - let format = settings + let texture_format = settings .texture_format - .or_else(|| surface.get_supported_formats(adapter).first().cloned()) + .or_else(|| capabilities.formats.first().cloned()) .unwrap_or(wgpu::TextureFormat::Rgba8Unorm); + log::info!("format description: {:?}", texture_format.describe()); + + let texture_format_features = adapter.get_texture_format_features(texture_format); + log::info!("format features: {:?}", texture_format_features); Self { size, head: Head::Headed(WindowHead { surface, size, - format, + texture_format, + texture_format_features, present_mode: settings.present_mode, }), } @@ -229,6 +245,7 @@ impl Surface { dimension: wgpu::TextureDimension::D2, format, usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC, + view_formats: &[format], }; let texture = device.create_texture(&texture_descriptor); @@ -245,7 +262,7 @@ impl Surface { pub fn surface_format(&self) -> wgpu::TextureFormat { match &self.head { - Head::Headed(headed) => headed.format, + Head::Headed(headed) => headed.texture_format, Head::Headless(headless) => headless.texture_format, } } @@ -294,18 +311,23 @@ impl Surface { } } - pub fn recreate(&mut self, window: &MW, instance: &wgpu::Instance) + pub fn recreate( + &mut self, + window: &MW, + instance: &wgpu::Instance, + ) -> Result<(), RenderError> where MW: MapWindow + HeadedMapWindow, { match &mut self.head { Head::Headed(window_head) => { if window_head.has_changed(&(self.size.width(), self.size.height())) { - window_head.recreate_surface(window, instance); + window_head.recreate_surface(window, instance)?; } } Head::Headless(_) => {} } + Ok(()) } pub fn head(&self) -> &Head { @@ -315,6 +337,31 @@ impl Surface { pub fn head_mut(&mut self) -> &mut Head { &mut self.head } + + pub fn is_multisampling_supported(&self, msaa: Msaa) -> bool { + match &self.head { + Head::Headed(headed) => { + let max_sample_count = { + let flags = headed.texture_format_features.flags; + if flags.contains(wgpu::TextureFormatFeatureFlags::MULTISAMPLE_X8) { + 8 + } else if flags.contains(wgpu::TextureFormatFeatureFlags::MULTISAMPLE_X4) { + 4 + } else if flags.contains(wgpu::TextureFormatFeatureFlags::MULTISAMPLE_X2) { + 2 + } else { + 1 + } + }; + let is_supported = msaa.samples <= max_sample_count; + if !is_supported { + log::debug!("Multisampling is not supported on surface"); + } + is_supported + } + Head::Headless(_) => false, // TODO: support multisampling on headless + } + } } impl HasChanged for WindowHead { diff --git a/maplibre/src/render/resource/texture.rs b/maplibre/src/render/resource/texture.rs index a06cb5f1..cec9957d 100644 --- a/maplibre/src/render/resource/texture.rs +++ b/maplibre/src/render/resource/texture.rs @@ -94,6 +94,7 @@ impl Texture { dimension: wgpu::TextureDimension::D2, format, usage, + view_formats: &[format], }); let view = texture.create_view(&wgpu::TextureViewDescriptor::default()); Self { diff --git a/maplibre/src/render/resource/tile_pipeline.rs b/maplibre/src/render/resource/tile_pipeline.rs index f1477525..26c42107 100644 --- a/maplibre/src/render/resource/tile_pipeline.rs +++ b/maplibre/src/render/resource/tile_pipeline.rs @@ -16,7 +16,7 @@ pub struct TilePipeline { /// Force a write and ignore stencil debug_stencil: bool, wireframe: bool, - multisampling: bool, + msaa: bool, raster: bool, settings: RendererSettings, @@ -43,7 +43,7 @@ impl TilePipeline { update_stencil, debug_stencil, wireframe, - multisampling, + msaa: multisampling, raster, settings, vertex_state, @@ -132,7 +132,7 @@ impl RenderPipeline for TilePipeline { }) }, multisample: wgpu::MultisampleState { - count: if self.multisampling { + count: if self.msaa { self.settings.msaa.samples } else { 1 diff --git a/maplibre/src/render/settings.rs b/maplibre/src/render/settings.rs index d8b7dbaf..4371db96 100644 --- a/maplibre/src/render/settings.rs +++ b/maplibre/src/render/settings.rs @@ -89,13 +89,14 @@ pub struct Msaa { } impl Msaa { - pub fn is_active(&self) -> bool { + pub fn is_multisampling(&self) -> bool { self.samples > 1 } } impl Default for Msaa { fn default() -> Self { + // By default we are trying to multisample Self { samples: 4 } } } diff --git a/maplibre/src/render/systems/resource_system.rs b/maplibre/src/render/systems/resource_system.rs index d951515b..4f596c4c 100644 --- a/maplibre/src/render/systems/resource_system.rs +++ b/maplibre/src/render/systems/resource_system.rs @@ -7,6 +7,7 @@ use crate::{ render::{ eventually::Eventually, resource::{BackingBufferDescriptor, RenderPipeline, Texture, TilePipeline}, + settings::Msaa, shaders, shaders::{Shader, ShaderTileMetadata}, tile_view_pattern::{TileViewPattern, WgpuTileViewPattern, DEFAULT_TILE_VIEW_PATTERN_SIZE}, @@ -63,7 +64,11 @@ impl System for ResourceSystem { settings.depth_texture_format, size.width(), size.height(), - settings.msaa, + if surface.is_multisampling_supported(settings.msaa) { + settings.msaa + } else { + Msaa { samples: 1 } + }, wgpu::TextureUsages::RENDER_ATTACHMENT, ) }, @@ -72,7 +77,9 @@ impl System for ResourceSystem { state.multisampling_texture.reinitialize( || { - if settings.msaa.is_active() { + if settings.msaa.is_multisampling() + && surface.is_multisampling_supported(settings.msaa) + { Some(Texture::new( Some("multisampling texture"), device, @@ -120,7 +127,7 @@ impl System for ResourceSystem { true, false, false, - true, + surface.is_multisampling_supported(settings.msaa), false, ) .describe_render_pipeline() diff --git a/maplibre/src/vector/resource_system.rs b/maplibre/src/vector/resource_system.rs index 7adca81d..23335b6d 100644 --- a/maplibre/src/vector/resource_system.rs +++ b/maplibre/src/vector/resource_system.rs @@ -48,7 +48,7 @@ pub fn resource_system( false, false, false, - true, + surface.is_multisampling_supported(settings.msaa), false, ) .describe_render_pipeline() diff --git a/web/Cargo.toml b/web/Cargo.toml index 30723ec2..c7bcafb6 100644 --- a/web/Cargo.toml +++ b/web/Cargo.toml @@ -41,8 +41,8 @@ web-sys = { version = "0.3.58", features = [ "ErrorEvent" ] } js-sys = "0.3.58" -wasm-bindgen = "0.2.81" -wasm-bindgen-futures = "0.4.31" +wasm-bindgen = "0.2" +wasm-bindgen-futures = "0.4" console_log = { version = "0.2.0", features = ["color"] } tracing-wasm = { version = "0.2.1", optional = true } # TODO: Low quality dependency (remove in a separate PR!) # For passing Inputs in AsyncProcedureCalls @@ -55,4 +55,4 @@ image = "*" # FIXME: Remove image, use browser capabilities flatc-rust = "0.2.0" [dev-dependencies] -wasm-bindgen-test = "0.3.31" +wasm-bindgen-test = "0.3"