From 33ae9751505020f122504c0a6ebae4c0ef399697 Mon Sep 17 00:00:00 2001 From: Filipe Rodrigues Date: Sun, 27 Nov 2022 16:11:16 +0000 Subject: [PATCH] Added `WgpuResizeReceiver` to receive notifications on wgpu resizes. --- Cargo.lock | 1 + zsw-panels/src/lib.rs | 5 +++-- zsw-panels/src/renderer.rs | 36 ++++++++++++++++++++++++++++-------- zsw-renderer/src/lib.rs | 1 + zsw-wgpu/Cargo.toml | 1 + zsw-wgpu/src/lib.rs | 36 +++++++++++++++++++++++++++++++++++- zsw/src/app.rs | 10 ++++++---- 7 files changed, 75 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index aeb908c..4129a01 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3739,6 +3739,7 @@ dependencies = [ "futures", "parking_lot", "pollster", + "tokio", "tracing", "wgpu", "winit", diff --git a/zsw-panels/src/lib.rs b/zsw-panels/src/lib.rs index 0524297..7bc502f 100644 --- a/zsw-panels/src/lib.rs +++ b/zsw-panels/src/lib.rs @@ -18,7 +18,7 @@ pub use self::{ }; // Imports -use zsw_wgpu::{Wgpu, WgpuSurfaceResource}; +use zsw_wgpu::{Wgpu, WgpuResizeReceiver, WgpuSurfaceResource}; /// Panels editor @@ -122,9 +122,10 @@ impl PanelsShader { pub fn create( wgpu: &Wgpu, surface_resource: &mut WgpuSurfaceResource, + wgpu_resize_receiver: WgpuResizeReceiver, ) -> (PanelsRenderer, PanelsEditor, PanelsResource) { ( - PanelsRenderer::new(wgpu, surface_resource), + PanelsRenderer::new(wgpu, surface_resource, wgpu_resize_receiver), PanelsEditor {}, PanelsResource { panels: vec![], diff --git a/zsw-panels/src/renderer.rs b/zsw-panels/src/renderer.rs index 97b3be7..09d1c87 100644 --- a/zsw-panels/src/renderer.rs +++ b/zsw-panels/src/renderer.rs @@ -14,7 +14,8 @@ use { wgpu::util::DeviceExt, winit::dpi::PhysicalSize, zsw_img::{ImageReceiver, RawImageProvider}, - zsw_wgpu::{Wgpu, WgpuSurfaceResource}, + zsw_util::Services, + zsw_wgpu::{Wgpu, WgpuResizeReceiver, WgpuSurfaceResource}, }; /// Panels renderer @@ -48,12 +49,19 @@ pub struct PanelsRenderer { /// Msaa frame-buffer // TODO: Resize this on resize? msaa_framebuffer: wgpu::TextureView, + + /// Wgpu resizer + wgpu_resize_receiver: WgpuResizeReceiver, } impl PanelsRenderer { /// Creates a new renderer for the panels #[must_use] - pub fn new(wgpu: &Wgpu, surface_resource: &mut WgpuSurfaceResource) -> Self { + pub fn new( + wgpu: &Wgpu, + surface_resource: &mut WgpuSurfaceResource, + wgpu_resize_receiver: WgpuResizeReceiver, + ) -> Self { // Create the index buffer let indices = self::create_indices(wgpu); @@ -79,7 +87,7 @@ impl PanelsRenderer { ); // Create the framebuffer - let msaa_framebuffer = self::create_msaa_framebuffer(wgpu, surface_resource); + let msaa_framebuffer = self::create_msaa_framebuffer(wgpu, wgpu.surface_size(surface_resource)); Self { pipelines: PanelsPipelines { @@ -91,6 +99,7 @@ impl PanelsRenderer { uniforms_bind_group_layout, image_bind_group_layout, msaa_framebuffer, + wgpu_resize_receiver, } } @@ -120,15 +129,27 @@ impl PanelsRenderer { } /// Renders all panels - pub fn render( - &self, + #[allow(clippy::too_many_arguments)] // TODO: Refactor + pub fn render( + &mut self, + services: &S, resource: &PanelsResource, cursor_pos: Point2, queue: &wgpu::Queue, encoder: &mut wgpu::CommandEncoder, surface_view: &wgpu::TextureView, surface_size: PhysicalSize, - ) -> Result<(), anyhow::Error> { + ) -> Result<(), anyhow::Error> + where + S: Services, + { + // Resize out msaa framebuffer if needed + let last_resize = std::iter::from_fn(|| self.wgpu_resize_receiver.on_resize()).last(); + if let Some(size) = last_resize { + tracing::debug!("Resizing msaa framebuffer to {}x{}", size.width, size.height); + self.msaa_framebuffer = self::create_msaa_framebuffer(services.service::(), size); + } + // Create the render pass for all panels let render_pass_color_attachment = match MSAA_SAMPLES { 1 => wgpu::RenderPassColorAttachment { @@ -344,8 +365,7 @@ fn create_render_pipeline( } /// Creates the msaa framebuffer -fn create_msaa_framebuffer(wgpu: &Wgpu, surface_resource: &mut WgpuSurfaceResource) -> wgpu::TextureView { - let size = wgpu.surface_size(surface_resource); +fn create_msaa_framebuffer(wgpu: &Wgpu, size: PhysicalSize) -> wgpu::TextureView { let msaa_texture_extent = wgpu::Extent3d { width: size.width, height: size.height, diff --git a/zsw-renderer/src/lib.rs b/zsw-renderer/src/lib.rs index ab8cb90..d3ba67f 100644 --- a/zsw-renderer/src/lib.rs +++ b/zsw-renderer/src/lib.rs @@ -130,6 +130,7 @@ impl Renderer { panels_renderer .render( + services, &panels_resource, cursor_pos, wgpu.queue(), diff --git a/zsw-wgpu/Cargo.toml b/zsw-wgpu/Cargo.toml index fc4c086..a167472 100644 --- a/zsw-wgpu/Cargo.toml +++ b/zsw-wgpu/Cargo.toml @@ -20,6 +20,7 @@ wgpu = { version = "0.14.0", features = ["serde", "replay"] } # Async futures = "0.3.25" pollster = "0.2.5" +tokio = { version = "1.22.0", features = ["full", "tracing"] } # Error handling anyhow = "1.0.66" diff --git a/zsw-wgpu/src/lib.rs b/zsw-wgpu/src/lib.rs index e7751c3..281ec9a 100644 --- a/zsw-wgpu/src/lib.rs +++ b/zsw-wgpu/src/lib.rs @@ -13,6 +13,7 @@ use { anyhow::Context, std::sync::Arc, + tokio::sync::broadcast, wgpu::TextureFormat, winit::{dpi::PhysicalSize, window::Window}, zsw_input::InputReceiver, @@ -84,6 +85,9 @@ pub struct WgpuRenderer { /// Surface texture format surface_texture_format: Arc, + + /// On resize sender + on_resize_tx: broadcast::Sender>, } impl WgpuRenderer { @@ -126,6 +130,9 @@ impl WgpuRenderer { let config = self::window_surface_configuration(*self.surface_texture_format, size); surface_resource.surface.configure(&self.device, &config); surface_resource.size = size; + + // Then send an event + let _ = self.on_resize_tx.send(size); } } } @@ -146,6 +153,28 @@ impl WgpuRenderer { } } +/// Wgpu resize receiver +#[derive(Debug)] +pub struct WgpuResizeReceiver { + /// On resize receiver + on_resize_rx: broadcast::Receiver>, +} + +impl Clone for WgpuResizeReceiver { + fn clone(&self) -> Self { + Self { + on_resize_rx: self.on_resize_rx.resubscribe(), + } + } +} + +impl WgpuResizeReceiver { + /// Returns any last on-resize event, if any + pub fn on_resize(&mut self) -> Option> { + self.on_resize_rx.try_recv().ok() + } +} + /// A frame's rendering #[derive(Debug)] pub struct FrameRender { @@ -273,7 +302,9 @@ const fn window_surface_configuration( /// Creates the `wgpu` services -pub async fn create(window: Arc) -> Result<(Wgpu, WgpuRenderer, WgpuSurfaceResource), anyhow::Error> { +pub async fn create( + window: Arc, +) -> Result<(Wgpu, WgpuRenderer, WgpuResizeReceiver, WgpuSurfaceResource), anyhow::Error> { // Create the surface and adapter // SAFETY: Due to the window being arced, and we storing it, we ensure the window outlives us and thus the surface let (surface, adapter) = unsafe { self::create_surface_and_adapter(&window).await? }; @@ -288,6 +319,7 @@ pub async fn create(window: Arc) -> Result<(Wgpu, WgpuRenderer, WgpuSurf let surface_texture_format = Arc::new(surface_texture_format); tracing::info!("Successfully initialized"); + let (on_resize_tx, on_resize_rx) = broadcast::channel(16); Ok(( Wgpu { device: Arc::clone(&device), @@ -298,7 +330,9 @@ pub async fn create(window: Arc) -> Result<(Wgpu, WgpuRenderer, WgpuSurf device, queue, surface_texture_format, + on_resize_tx, }, + WgpuResizeReceiver { on_resize_rx }, WgpuSurfaceResource { surface, size: surface_size, diff --git a/zsw/src/app.rs b/zsw/src/app.rs index dc3ed57..779c386 100644 --- a/zsw/src/app.rs +++ b/zsw/src/app.rs @@ -50,12 +50,14 @@ pub async fn run(config: &Arc) -> Result<(), anyhow::Error> { // Create all services and resources // TODO: Execute futures in background and continue initializing - let (wgpu, mut wgpu_renderer, mut wgpu_surface_resource) = zsw_wgpu::create(Arc::clone(&window)) - .await - .context("Unable to create renderer")?; + let (wgpu, mut wgpu_renderer, wgpu_resize_receiver, mut wgpu_surface_resource) = + zsw_wgpu::create(Arc::clone(&window)) + .await + .context("Unable to create renderer")?; let (playlist_runner, playlist_receiver, playlist_manager) = zsw_playlist::create(); let (image_loader, image_resizer, image_receiver) = zsw_img::loader::create(); - let (mut panels_renderer, panels_editor, panels_resource) = zsw_panels::create(&wgpu, &mut wgpu_surface_resource); + let (mut panels_renderer, panels_editor, panels_resource) = + zsw_panels::create(&wgpu, &mut wgpu_surface_resource, wgpu_resize_receiver); let (mut egui_renderer, mut egui_painter, mut egui_event_handler) = zsw_egui::create(&window, &wgpu); let profiles_manager = zsw_profiles::create(); let (mut input_updater, mut input_receiver) = zsw_input::create();