From baf51a8fcffc78e4ca20f7dcbba18ca3655f2840 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 31 Jan 2023 06:29:21 +0100 Subject: Draft `glyphon` implementation of text pipeline for `iced_wgpu` --- wgpu/src/window/compositor.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'wgpu/src/window') diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index 6d0c36f6..50231f7c 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -114,7 +114,7 @@ impl Compositor { /// Creates a new rendering [`Backend`] for this [`Compositor`]. pub fn create_backend(&self) -> Backend { - Backend::new(&self.device, self.settings, self.format) + Backend::new(&self.device, &self.queue, self.settings, self.format) } } @@ -227,6 +227,7 @@ impl iced_graphics::window::Compositor for Compositor { renderer.with_primitives(|backend, primitives| { backend.present( &self.device, + &self.queue, &mut self.staging_belt, &mut encoder, view, -- cgit From b8c1809ea101cece6943432fd3597f785c39af09 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 7 Feb 2023 23:55:16 +0100 Subject: Refactor `triangle::Pipeline` into `prepare` and `render` architecture And get rid of the staging belt! :tada: --- wgpu/src/window/compositor.rs | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'wgpu/src/window') diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index 50231f7c..6e1acc06 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -16,14 +16,11 @@ pub struct Compositor { adapter: wgpu::Adapter, device: wgpu::Device, queue: wgpu::Queue, - staging_belt: wgpu::util::StagingBelt, format: wgpu::TextureFormat, theme: PhantomData, } impl Compositor { - const CHUNK_SIZE: u64 = 10 * 1024; - /// Requests a new [`Compositor`] with the given [`Settings`]. /// /// Returns `None` if no compatible graphics adapter could be found. @@ -98,15 +95,12 @@ impl Compositor { .next() .await?; - let staging_belt = wgpu::util::StagingBelt::new(Self::CHUNK_SIZE); - Some(Compositor { instance, settings, adapter, device, queue, - staging_belt, format, theme: PhantomData, }) @@ -228,7 +222,6 @@ impl iced_graphics::window::Compositor for Compositor { backend.present( &self.device, &self.queue, - &mut self.staging_belt, &mut encoder, view, primitives, @@ -238,13 +231,9 @@ impl iced_graphics::window::Compositor for Compositor { }); // Submit work - self.staging_belt.finish(); let _submission = self.queue.submit(Some(encoder.finish())); frame.present(); - // Recall staging buffers - self.staging_belt.recall(); - Ok(()) } Err(error) => match error { -- cgit From 730d6a07564d014c470e02f233394ec98325d463 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 8 Feb 2023 00:47:16 +0100 Subject: Reuse a `RenderPass` as much as possible in `iced_wgpu` --- wgpu/src/window/compositor.rs | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) (limited to 'wgpu/src/window') diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index 6e1acc06..365cb603 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -190,39 +190,12 @@ impl iced_graphics::window::Compositor for Compositor { .texture .create_view(&wgpu::TextureViewDescriptor::default()); - let _ = - encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - label: Some( - "iced_wgpu::window::Compositor render pass", - ), - color_attachments: &[Some( - wgpu::RenderPassColorAttachment { - view, - resolve_target: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Clear({ - let [r, g, b, a] = - background_color.into_linear(); - - wgpu::Color { - r: f64::from(r), - g: f64::from(g), - b: f64::from(b), - a: f64::from(a), - } - }), - store: true, - }, - }, - )], - depth_stencil_attachment: None, - }); - renderer.with_primitives(|backend, primitives| { backend.present( &self.device, &self.queue, &mut encoder, + Some(background_color), view, primitives, viewport, -- cgit From 5100b5d0a1f654ec1254b7765ceadfb9091d6939 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 24 Feb 2023 23:24:48 +0100 Subject: Introduce `iced_renderer` subcrate featuring runtime renderer fallback --- wgpu/src/window/compositor.rs | 139 ++++++++++++++++++++++++++---------------- 1 file changed, 86 insertions(+), 53 deletions(-) (limited to 'wgpu/src/window') diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index 365cb603..7406bfb8 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -1,8 +1,9 @@ -use crate::{Backend, Color, Error, Renderer, Settings, Viewport}; +//! Connect a window with a renderer. +use crate::{Backend, Color, Error, Primitive, Renderer, Settings, Viewport}; use futures::stream::{self, StreamExt}; -use iced_graphics::compositor; +use iced_graphics::window::compositor; use iced_native::futures; use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle}; @@ -112,6 +113,77 @@ impl Compositor { } } +/// Creates a [`Compositor`] and its [`Backend`] for the given [`Settings`] and +/// window. +pub fn new( + settings: Settings, + compatible_window: Option<&W>, +) -> Result<(Compositor, Backend), Error> { + let compositor = futures::executor::block_on(Compositor::request( + settings, + compatible_window, + )) + .ok_or(Error::GraphicsAdapterNotFound)?; + + let backend = compositor.create_backend(); + + Ok((compositor, backend)) +} + +/// Presents the given primitives with the given [`Compositor`] and [`Backend`]. +pub fn present>( + compositor: &mut Compositor, + backend: &mut Backend, + surface: &mut wgpu::Surface, + primitives: &[Primitive], + viewport: &Viewport, + background_color: Color, + overlay: &[T], +) -> Result<(), compositor::SurfaceError> { + match surface.get_current_texture() { + Ok(frame) => { + let mut encoder = compositor.device.create_command_encoder( + &wgpu::CommandEncoderDescriptor { + label: Some("iced_wgpu encoder"), + }, + ); + + let view = &frame + .texture + .create_view(&wgpu::TextureViewDescriptor::default()); + + backend.present( + &compositor.device, + &compositor.queue, + &mut encoder, + Some(background_color), + view, + primitives, + viewport, + overlay, + ); + + // Submit work + let _submission = compositor.queue.submit(Some(encoder.finish())); + frame.present(); + + Ok(()) + } + Err(error) => match error { + wgpu::SurfaceError::Timeout => { + Err(compositor::SurfaceError::Timeout) + } + wgpu::SurfaceError::Outdated => { + Err(compositor::SurfaceError::Outdated) + } + wgpu::SurfaceError::Lost => Err(compositor::SurfaceError::Lost), + wgpu::SurfaceError::OutOfMemory => { + Err(compositor::SurfaceError::OutOfMemory) + } + }, + } +} + impl iced_graphics::window::Compositor for Compositor { type Settings = Settings; type Renderer = Renderer; @@ -121,13 +193,7 @@ impl iced_graphics::window::Compositor for Compositor { settings: Self::Settings, compatible_window: Option<&W>, ) -> Result<(Self, Self::Renderer), Error> { - let compositor = futures::executor::block_on(Self::request( - settings, - compatible_window, - )) - .ok_or(Error::GraphicsAdapterNotFound)?; - - let backend = compositor.create_backend(); + let (compositor, backend) = new(settings, compatible_window)?; Ok((compositor, Renderer::new(backend))) } @@ -178,49 +244,16 @@ impl iced_graphics::window::Compositor for Compositor { background_color: Color, overlay: &[T], ) -> Result<(), compositor::SurfaceError> { - match surface.get_current_texture() { - Ok(frame) => { - let mut encoder = self.device.create_command_encoder( - &wgpu::CommandEncoderDescriptor { - label: Some("iced_wgpu encoder"), - }, - ); - - let view = &frame - .texture - .create_view(&wgpu::TextureViewDescriptor::default()); - - renderer.with_primitives(|backend, primitives| { - backend.present( - &self.device, - &self.queue, - &mut encoder, - Some(background_color), - view, - primitives, - viewport, - overlay, - ); - }); - - // Submit work - let _submission = self.queue.submit(Some(encoder.finish())); - frame.present(); - - Ok(()) - } - Err(error) => match error { - wgpu::SurfaceError::Timeout => { - Err(compositor::SurfaceError::Timeout) - } - wgpu::SurfaceError::Outdated => { - Err(compositor::SurfaceError::Outdated) - } - wgpu::SurfaceError::Lost => Err(compositor::SurfaceError::Lost), - wgpu::SurfaceError::OutOfMemory => { - Err(compositor::SurfaceError::OutOfMemory) - } - }, - } + renderer.with_primitives(|backend, primitives| { + present( + self, + backend, + surface, + primitives, + viewport, + background_color, + overlay, + ) + }) } } -- cgit From 535d7a4d57e131e661587b36e41820dd6ccccc3e Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 25 Feb 2023 16:05:42 +0100 Subject: Implement basic presentation with `softbuffer` for `iced_tiny_skia` --- wgpu/src/window/compositor.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'wgpu/src/window') diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index 7406bfb8..3a4a7123 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -201,11 +201,15 @@ impl iced_graphics::window::Compositor for Compositor { fn create_surface( &mut self, window: &W, + width: u32, + height: u32, ) -> wgpu::Surface { #[allow(unsafe_code)] - unsafe { - self.instance.create_surface(window) - } + let mut surface = unsafe { self.instance.create_surface(window) }; + + self.configure_surface(&mut surface, width, height); + + surface } fn configure_surface( -- cgit From 3a0d34c0240f4421737a6a08761f99d6f8140d02 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 4 Mar 2023 05:37:11 +0100 Subject: Create `iced_widget` subcrate and re-organize the whole codebase --- wgpu/src/window/compositor.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'wgpu/src/window') diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index 3a4a7123..a67ac3c0 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -1,10 +1,12 @@ //! Connect a window with a renderer. -use crate::{Backend, Color, Error, Primitive, Renderer, Settings, Viewport}; +use crate::core::Color; +use crate::graphics; +use crate::graphics::compositor; +use crate::graphics::{Error, Primitive, Viewport}; +use crate::{Backend, Renderer, Settings}; use futures::stream::{self, StreamExt}; -use iced_graphics::window::compositor; -use iced_native::futures; use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle}; use std::marker::PhantomData; @@ -184,7 +186,7 @@ pub fn present>( } } -impl iced_graphics::window::Compositor for Compositor { +impl graphics::Compositor for Compositor { type Settings = Settings; type Renderer = Renderer; type Surface = wgpu::Surface; -- cgit From c0431aedd3bbef4161456f2fa5f29866e8f17fc5 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 8 Apr 2023 04:47:05 +0200 Subject: Update `wgpu` and `cosmic-text` --- wgpu/src/window/compositor.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'wgpu/src/window') diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index a67ac3c0..025cd43a 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -31,7 +31,10 @@ impl Compositor { settings: Settings, compatible_window: Option<&W>, ) -> Option { - let instance = wgpu::Instance::new(settings.internal_backend); + let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { + backends: settings.internal_backend, + ..Default::default() + }); log::info!("{:#?}", settings); @@ -46,7 +49,7 @@ impl Compositor { #[allow(unsafe_code)] let compatible_surface = compatible_window - .map(|window| unsafe { instance.create_surface(window) }); + .and_then(|window| unsafe { instance.create_surface(window).ok() }); let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { @@ -63,7 +66,7 @@ impl Compositor { log::info!("Selected: {:#?}", adapter.get_info()); let format = compatible_surface.as_ref().and_then(|surface| { - surface.get_supported_formats(&adapter).first().copied() + surface.get_capabilities(&adapter).formats.first().copied() })?; log::info!("Selected format: {:?}", format); @@ -207,7 +210,8 @@ impl graphics::Compositor for Compositor { height: u32, ) -> wgpu::Surface { #[allow(unsafe_code)] - let mut surface = unsafe { self.instance.create_surface(window) }; + let mut surface = unsafe { self.instance.create_surface(window) } + .expect("Create surface"); self.configure_surface(&mut surface, width, height); @@ -229,6 +233,7 @@ impl graphics::Compositor for Compositor { width, height, alpha_mode: wgpu::CompositeAlphaMode::Auto, + view_formats: vec![], }, ); } -- cgit From 1872f7fa6d7b9ca9fa0db8d14bf44dcd3513ffca Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 8 Apr 2023 06:14:25 +0200 Subject: Use `*_from_env` helpers from `wgpu` in `iced_wgpu` --- wgpu/src/window/compositor.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'wgpu/src/window') diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index 025cd43a..15bef60c 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -53,11 +53,12 @@ impl Compositor { let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { - power_preference: if settings.antialiasing.is_none() { - wgpu::PowerPreference::LowPower - } else { - wgpu::PowerPreference::HighPerformance - }, + power_preference: wgpu::util::power_preference_from_env() + .unwrap_or(if settings.antialiasing.is_none() { + wgpu::PowerPreference::LowPower + } else { + wgpu::PowerPreference::HighPerformance + }), compatible_surface: compatible_surface.as_ref(), force_fallback_adapter: false, }) -- cgit From d5453c62e9bdbf0cea030b009c41b892b700496d Mon Sep 17 00:00:00 2001 From: Elham Aryanpur Date: Wed, 12 Apr 2023 23:38:21 +0300 Subject: Update `wgpu` to `0.15` --- wgpu/src/window/compositor.rs | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) (limited to 'wgpu/src/window') diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index 6d0c36f6..d66aca71 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -31,7 +31,10 @@ impl Compositor { settings: Settings, compatible_window: Option<&W>, ) -> Option { - let instance = wgpu::Instance::new(settings.internal_backend); + let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { + backends: settings.internal_backend, + ..Default::default() + }); log::info!("{:#?}", settings); @@ -46,7 +49,7 @@ impl Compositor { #[allow(unsafe_code)] let compatible_surface = compatible_window - .map(|window| unsafe { instance.create_surface(window) }); + .and_then(|window| unsafe { instance.create_surface(window).ok() }); let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { @@ -63,7 +66,18 @@ impl Compositor { log::info!("Selected: {:#?}", adapter.get_info()); let format = compatible_surface.as_ref().and_then(|surface| { - surface.get_supported_formats(&adapter).first().copied() + surface + .get_capabilities(&adapter) + .formats + .iter() + .filter(|format| format.describe().srgb) + .copied() + .next() + .or_else(|| { + log::warn!("No sRGB format found!"); + + surface.get_capabilities(&adapter).formats.first().copied() + }) })?; log::info!("Selected format: {:?}", format); @@ -144,7 +158,9 @@ impl iced_graphics::window::Compositor for Compositor { ) -> wgpu::Surface { #[allow(unsafe_code)] unsafe { - self.instance.create_surface(window) + self.instance + .create_surface(window) + .expect("Create surface") } } @@ -163,6 +179,7 @@ impl iced_graphics::window::Compositor for Compositor { width, height, alpha_mode: wgpu::CompositeAlphaMode::Auto, + view_formats: vec![], }, ); } -- cgit From b677345ac1b1d087bc7f331c9c8c5be06933ba6e Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 13 Apr 2023 05:42:56 +0200 Subject: Get surface capabilities only once in `iced_wgpu` --- wgpu/src/window/compositor.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'wgpu/src/window') diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index d66aca71..d4a59471 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -66,8 +66,9 @@ impl Compositor { log::info!("Selected: {:#?}", adapter.get_info()); let format = compatible_surface.as_ref().and_then(|surface| { - surface - .get_capabilities(&adapter) + let capabilities = surface.get_capabilities(&adapter); + + capabilities .formats .iter() .filter(|format| format.describe().srgb) @@ -76,7 +77,7 @@ impl Compositor { .or_else(|| { log::warn!("No sRGB format found!"); - surface.get_capabilities(&adapter).formats.first().copied() + capabilities.formats.first().copied() }) })?; -- cgit From 8122904ca46b73ceda54bd73bd68cf4138d22f1b Mon Sep 17 00:00:00 2001 From: David Huculak Date: Thu, 20 Apr 2023 21:28:47 -0400 Subject: wgpu 0.16 --- wgpu/src/window/compositor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'wgpu/src/window') diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index d4a59471..8969ad6c 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -71,7 +71,7 @@ impl Compositor { capabilities .formats .iter() - .filter(|format| format.describe().srgb) + .filter(|format| format.is_srgb()) .copied() .next() .or_else(|| { -- cgit From 3f0c226b74c6d0271e550161b6542e652c1875ca Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 21 Apr 2023 21:36:30 +0200 Subject: Use point-free notation --- wgpu/src/window/compositor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'wgpu/src/window') diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index 8969ad6c..3c51768a 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -71,8 +71,8 @@ impl Compositor { capabilities .formats .iter() - .filter(|format| format.is_srgb()) .copied() + .filter(wgpu::TextureFormat::is_srgb) .next() .or_else(|| { log::warn!("No sRGB format found!"); -- cgit From cc20baad6f422271f052cf68474a4aee40dcdc82 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 21 Apr 2023 21:46:02 +0200 Subject: Use `find(..)` instead of `filter(..).next()` --- wgpu/src/window/compositor.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'wgpu/src/window') diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index 3c51768a..53af19bf 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -72,8 +72,7 @@ impl Compositor { .formats .iter() .copied() - .filter(wgpu::TextureFormat::is_srgb) - .next() + .find(wgpu::TextureFormat::is_srgb) .or_else(|| { log::warn!("No sRGB format found!"); -- cgit From faa7627ea41b1ce372bae7f0d2ae36e9b15a97a3 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 31 May 2023 21:31:58 +0200 Subject: Introduce `web-colors` feature flag to enable sRGB linear blending This is how browsers perform color management. They treat gamma-corrected sRGB colors as if they were linear RGB. Correctness aside, this mode is introduced for legacy reasons. Most UI/UX tooling uses this color management as well, and many have created an intuition about how color should behave from interacting with a browser. This feature flag should facilitate application development with `iced` in those cases. More details: https://webcolorisstillbroken.com/ --- wgpu/src/window/compositor.rs | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'wgpu/src/window') diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index 500458e8..2eaafde0 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -1,6 +1,7 @@ //! Connect a window with a renderer. use crate::core::Color; use crate::graphics; +use crate::graphics::color; use crate::graphics::compositor; use crate::graphics::{Error, Primitive, Viewport}; use crate::{Backend, Renderer, Settings}; @@ -69,16 +70,19 @@ impl Compositor { let format = compatible_surface.as_ref().and_then(|surface| { let capabilities = surface.get_capabilities(&adapter); - capabilities - .formats - .iter() - .copied() - .find(wgpu::TextureFormat::is_srgb) - .or_else(|| { - log::warn!("No sRGB format found!"); + let mut formats = capabilities.formats.iter().copied(); - capabilities.formats.first().copied() - }) + let format = if color::GAMMA_CORRECTION { + formats.find(wgpu::TextureFormat::is_srgb) + } else { + formats.find(|format| !wgpu::TextureFormat::is_srgb(format)) + }; + + format.or_else(|| { + log::warn!("No format found!"); + + capabilities.formats.first().copied() + }) })?; log::info!("Selected format: {:?}", format); -- cgit From 233196eb14b40f8bd5201ea0262571f82136ad53 Mon Sep 17 00:00:00 2001 From: Bingus Date: Sat, 25 Mar 2023 10:45:39 -0700 Subject: Added offscreen rendering support for wgpu & tiny-skia exposed with the window::screenshot command. --- wgpu/src/window/compositor.rs | 143 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 142 insertions(+), 1 deletion(-) (limited to 'wgpu/src/window') diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index 2eaafde0..43c3dce5 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -1,5 +1,5 @@ //! Connect a window with a renderer. -use crate::core::Color; +use crate::core::{Color, Size}; use crate::graphics; use crate::graphics::color; use crate::graphics::compositor; @@ -283,4 +283,145 @@ impl graphics::Compositor for Compositor { ) }) } + + fn screenshot>( + &mut self, + renderer: &mut Self::Renderer, + _surface: &mut Self::Surface, + viewport: &Viewport, + background_color: Color, + overlay: &[T], + ) -> Vec { + renderer.with_primitives(|backend, primitives| { + screenshot( + self, + backend, + primitives, + viewport, + background_color, + overlay, + ) + }) + } +} + +/// Renders the current surface to an offscreen buffer. +/// +/// Returns RGBA bytes of the texture data. +pub fn screenshot>( + compositor: &Compositor, + backend: &mut Backend, + primitives: &[Primitive], + viewport: &Viewport, + background_color: Color, + overlay: &[T], +) -> Vec { + let mut encoder = compositor.device.create_command_encoder( + &wgpu::CommandEncoderDescriptor { + label: Some("iced_wgpu.offscreen.encoder"), + }, + ); + + let dimensions = BufferDimensions::new(viewport.physical_size()); + + let texture_extent = wgpu::Extent3d { + width: dimensions.width, + height: dimensions.height, + depth_or_array_layers: 1, + }; + + let texture = compositor.device.create_texture(&wgpu::TextureDescriptor { + label: Some("iced_wgpu.offscreen.source_texture"), + size: texture_extent, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: compositor.format, + usage: wgpu::TextureUsages::RENDER_ATTACHMENT + | wgpu::TextureUsages::COPY_SRC + | wgpu::TextureUsages::TEXTURE_BINDING, + view_formats: &[], + }); + + let view = texture.create_view(&wgpu::TextureViewDescriptor::default()); + + let rgba_texture = backend.offscreen( + &compositor.device, + &compositor.queue, + &mut encoder, + Some(background_color), + &view, + compositor.format, + primitives, + viewport, + overlay, + texture_extent, + ); + + let output_buffer = + compositor.device.create_buffer(&wgpu::BufferDescriptor { + label: Some("iced_wgpu.offscreen.output_texture_buffer"), + size: (dimensions.padded_bytes_per_row * dimensions.height as usize) + as u64, + usage: wgpu::BufferUsages::MAP_READ | wgpu::BufferUsages::COPY_DST, + mapped_at_creation: false, + }); + + encoder.copy_texture_to_buffer( + rgba_texture.unwrap_or(texture).as_image_copy(), + wgpu::ImageCopyBuffer { + buffer: &output_buffer, + layout: wgpu::ImageDataLayout { + offset: 0, + bytes_per_row: Some(dimensions.padded_bytes_per_row as u32), + rows_per_image: None, + }, + }, + texture_extent, + ); + + let index = compositor.queue.submit(Some(encoder.finish())); + + let slice = output_buffer.slice(..); + slice.map_async(wgpu::MapMode::Read, |_| {}); + + let _ = compositor + .device + .poll(wgpu::Maintain::WaitForSubmissionIndex(index)); + + let mapped_buffer = slice.get_mapped_range(); + + mapped_buffer.chunks(dimensions.padded_bytes_per_row).fold( + vec![], + |mut acc, row| { + acc.extend(&row[..dimensions.unpadded_bytes_per_row]); + acc + }, + ) +} + +#[derive(Clone, Copy, Debug)] +struct BufferDimensions { + width: u32, + height: u32, + unpadded_bytes_per_row: usize, + padded_bytes_per_row: usize, +} + +impl BufferDimensions { + fn new(size: Size) -> Self { + let unpadded_bytes_per_row = size.width as usize * 4; //slice of buffer per row; always RGBA + let alignment = wgpu::COPY_BYTES_PER_ROW_ALIGNMENT as usize; //256 + let padded_bytes_per_row_padding = + (alignment - unpadded_bytes_per_row % alignment) % alignment; + let padded_bytes_per_row = + unpadded_bytes_per_row + padded_bytes_per_row_padding; + + Self { + width: size.width, + height: size.height, + unpadded_bytes_per_row, + padded_bytes_per_row, + } + } } -- cgit From 5b6e205e998cbb20b3c8aaff8b515d78315d6703 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 27 Jun 2023 20:26:13 +0200 Subject: Simplify `offscreen` API as `color` module in `iced_wgpu` --- wgpu/src/window/compositor.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'wgpu/src/window') diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index 43c3dce5..1cfd7b67 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -345,17 +345,26 @@ pub fn screenshot>( let view = texture.create_view(&wgpu::TextureViewDescriptor::default()); - let rgba_texture = backend.offscreen( + backend.present( &compositor.device, &compositor.queue, &mut encoder, Some(background_color), &view, - compositor.format, primitives, viewport, overlay, - texture_extent, + ); + + let texture = crate::color::convert( + &compositor.device, + &mut encoder, + texture, + if color::GAMMA_CORRECTION { + wgpu::TextureFormat::Rgba8UnormSrgb + } else { + wgpu::TextureFormat::Rgba8Unorm + }, ); let output_buffer = @@ -368,7 +377,7 @@ pub fn screenshot>( }); encoder.copy_texture_to_buffer( - rgba_texture.unwrap_or(texture).as_image_copy(), + texture.as_image_copy(), wgpu::ImageCopyBuffer { buffer: &output_buffer, layout: wgpu::ImageDataLayout { -- cgit From 0ae1baa37bd7b6607f79b33b8a6d8c5daafde0b2 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 22 Jun 2023 00:38:36 +0200 Subject: Introduce custom backend-specific primitives --- wgpu/src/window/compositor.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'wgpu/src/window') diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index 1cfd7b67..cd5b20cc 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -3,8 +3,8 @@ use crate::core::{Color, Size}; use crate::graphics; use crate::graphics::color; use crate::graphics::compositor; -use crate::graphics::{Error, Primitive, Viewport}; -use crate::{Backend, Renderer, Settings}; +use crate::graphics::{Error, Viewport}; +use crate::{Backend, Primitive, Renderer, Settings}; use futures::stream::{self, StreamExt}; -- cgit