diff options
-rw-r--r-- | native/src/window.rs | 4 | ||||
-rw-r--r-- | native/src/window/backend.rs | 55 | ||||
-rw-r--r-- | native/src/window/renderer.rs | 73 | ||||
-rw-r--r-- | src/application.rs | 2 | ||||
-rw-r--r-- | wgpu/src/lib.rs | 10 | ||||
-rw-r--r-- | wgpu/src/renderer.rs | 116 | ||||
-rw-r--r-- | wgpu/src/renderer/target.rs | 91 | ||||
-rw-r--r-- | wgpu/src/target.rs | 8 | ||||
-rw-r--r-- | wgpu/src/viewport.rs | 32 | ||||
-rw-r--r-- | wgpu/src/window.rs | 5 | ||||
-rw-r--r-- | wgpu/src/window/backend.rs | 99 | ||||
-rw-r--r-- | wgpu/src/window/swap_chain.rs | 49 | ||||
-rw-r--r-- | winit/src/application.rs | 39 |
13 files changed, 349 insertions, 234 deletions
diff --git a/native/src/window.rs b/native/src/window.rs index db9226dc..4dcae62f 100644 --- a/native/src/window.rs +++ b/native/src/window.rs @@ -1,6 +1,6 @@ //! Build window-based GUI applications. +mod backend; mod event; -mod renderer; +pub use backend::Backend; pub use event::Event; -pub use renderer::{Renderer, Target}; diff --git a/native/src/window/backend.rs b/native/src/window/backend.rs new file mode 100644 index 00000000..690dbdab --- /dev/null +++ b/native/src/window/backend.rs @@ -0,0 +1,55 @@ +use crate::MouseCursor; + +use raw_window_handle::HasRawWindowHandle; + +/// A graphics backend that can render to windows. +pub trait Backend: Sized { + /// The settings of the backend. + type Settings: Default; + + /// The iced renderer of the backend. + type Renderer: crate::Renderer; + + /// The surface of the backend. + type Surface; + + /// The swap chain of the backend. + type SwapChain; + + /// Creates a new [`Backend`] and an associated iced renderer. + /// + /// [`Backend`]: trait.Backend.html + fn new(settings: Self::Settings) -> (Self, Self::Renderer); + + /// Crates a new [`Surface`] for the given window. + /// + /// [`Surface`]: #associatedtype.Surface + fn create_surface<W: HasRawWindowHandle>( + &mut self, + window: &W, + ) -> Self::Surface; + + /// Crates a new [`SwapChain`] for the given [`Surface`]. + /// + /// [`SwapChain`]: #associatedtype.SwapChain + /// [`Surface`]: #associatedtype.Surface + fn create_swap_chain( + &mut self, + surface: &Self::Surface, + width: u32, + height: u32, + scale_factor: f64, + ) -> Self::SwapChain; + + /// Draws the output primitives to the next frame of the given [`SwapChain`]. + /// + /// [`SwapChain`]: #associatedtype.SwapChain + /// [`Surface`]: #associatedtype.Surface + fn draw<T: AsRef<str>>( + &mut self, + renderer: &mut Self::Renderer, + swap_chain: &mut Self::SwapChain, + output: &<Self::Renderer as crate::Renderer>::Output, + overlay: &[T], + ) -> MouseCursor; +} diff --git a/native/src/window/renderer.rs b/native/src/window/renderer.rs index a3cbb8ce..b0cc0134 100644 --- a/native/src/window/renderer.rs +++ b/native/src/window/renderer.rs @@ -2,57 +2,54 @@ use crate::MouseCursor; use raw_window_handle::HasRawWindowHandle; -/// A renderer that can target windows. -pub trait Renderer: crate::Renderer + Sized { - /// The settings of the renderer. +/// A graphics backend that can render to windows. +pub trait Backend: Sized { + /// The settings of the backend. type Settings: Default; - /// The type of target. - type Target: Target<Renderer = Self>; + /// The iced renderer of the backend. + type Renderer: crate::Renderer; - /// Creates a new window [`Renderer`]. + /// The surface of the backend. + type Surface; + + /// The target of the backend. + type Target; + + /// Creates a new [`Gpu`] and an associated iced renderer. /// - /// [`Renderer`]: trait.Renderer.html - fn new(settings: Self::Settings) -> Self; + /// [`Gpu`]: trait.Gpu.html + fn new(settings: Self::Settings) -> (Self, Self::Renderer); - /// Performs the drawing operations described in the output on the given - /// target. + /// Crates a new [`Surface`] for the given window. /// - /// The overlay can be a bunch of debug text logs. It should be rendered on - /// top of the GUI on most scenarios. - fn draw<T: AsRef<str>>( + /// [`Surface`]: #associatedtype.Surface + fn create_surface<W: HasRawWindowHandle>( &mut self, - output: &Self::Output, - overlay: &[T], - target: &mut Self::Target, - ) -> MouseCursor; -} - -/// A rendering target. -pub trait Target { - /// The renderer of this target. - type Renderer; + window: &W, + ) -> Self::Surface; - /// Creates a new rendering [`Target`] from the given window handle, width, - /// height and dpi factor. + /// Crates a new [`Target`] for the given [`Surface`]. /// - /// [`Target`]: trait.Target.html - fn new<W: HasRawWindowHandle>( - window: &W, + /// [`Target`]: #associatedtype.Target + /// [`Surface`]: #associatedtype.Surface + fn create_target( + &mut self, + surface: &Self::Surface, width: u32, height: u32, scale_factor: f64, - renderer: &Self::Renderer, - ) -> Self; + ) -> Self::Target; - /// Resizes the current [`Target`]. + /// Draws the output primitives to the given [`Target`]. /// - /// [`Target`]: trait.Target.html - fn resize( + /// [`Target`]: #associatedtype.Target + /// [`Surface`]: #associatedtype.Surface + fn draw<T: AsRef<str>>( &mut self, - width: u32, - height: u32, - scale_factor: f64, - renderer: &Self::Renderer, - ); + renderer: &mut Self::Renderer, + target: &mut Self::Target, + output: &<Self::Renderer as crate::Renderer>::Output, + overlay: &[T], + ) -> MouseCursor; } diff --git a/src/application.rs b/src/application.rs index 926a2986..0a4b6d9e 100644 --- a/src/application.rs +++ b/src/application.rs @@ -193,7 +193,7 @@ impl<A> iced_winit::Application for Instance<A> where A: Application, { - type Renderer = iced_wgpu::Renderer; + type Backend = iced_wgpu::window::Backend; type Executor = A::Executor; type Message = A::Message; diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index b8cd3fce..9c1739b2 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -19,7 +19,7 @@ //! [`wgpu`]: https://github.com/gfx-rs/wgpu-rs //! [WebGPU API]: https://gpuweb.github.io/gpuweb/ //! [`wgpu_glyph`]: https://github.com/hecrj/wgpu_glyph -#![deny(missing_docs)] +//#![deny(missing_docs)] #![deny(missing_debug_implementations)] #![deny(unused_results)] #![forbid(unsafe_code)] @@ -27,19 +27,25 @@ pub mod defaults; pub mod triangle; pub mod widget; +pub mod window; mod image; mod primitive; mod quad; mod renderer; mod settings; +mod target; mod text; mod transformation; +mod viewport; pub use defaults::Defaults; pub use primitive::Primitive; -pub use renderer::{Renderer, Target}; +pub use renderer::Renderer; pub use settings::Settings; +pub use target::Target; +pub use viewport::Viewport; + #[doc(no_inline)] pub use widget::*; diff --git a/wgpu/src/renderer.rs b/wgpu/src/renderer.rs index 93d2bb13..a99080f4 100644 --- a/wgpu/src/renderer.rs +++ b/wgpu/src/renderer.rs @@ -1,29 +1,20 @@ use crate::{ image, quad, text, triangle, Defaults, Image, Primitive, Quad, Settings, - Transformation, + Target, Transformation, }; use iced_native::{ - layout, window, Background, Color, Layout, MouseCursor, Point, Rectangle, - Vector, Widget, + layout, Background, Color, Layout, MouseCursor, Point, Rectangle, Vector, + Widget, }; use std::sync::Arc; -use wgpu::{ - Adapter, BackendBit, CommandEncoderDescriptor, Device, DeviceDescriptor, - Extensions, Limits, PowerPreference, Queue, RequestAdapterOptions, -}; -mod target; mod widget; -pub use target::Target; - /// A [`wgpu`] renderer. /// /// [`wgpu`]: https://github.com/gfx-rs/wgpu-rs #[derive(Debug)] pub struct Renderer { - device: Device, - queue: Queue, quad_pipeline: quad::Pipeline, image_pipeline: image::Pipeline, text_pipeline: text::Pipeline, @@ -53,29 +44,16 @@ impl<'a> Layer<'a> { } impl Renderer { - fn new(settings: Settings) -> Self { - let adapter = Adapter::request(&RequestAdapterOptions { - power_preference: PowerPreference::Default, - backends: BackendBit::all(), - }) - .expect("Request adapter"); - - let (mut device, queue) = adapter.request_device(&DeviceDescriptor { - extensions: Extensions { - anisotropic_filtering: false, - }, - limits: Limits { max_bind_groups: 2 }, - }); - - let text_pipeline = - text::Pipeline::new(&mut device, settings.default_font); - let quad_pipeline = quad::Pipeline::new(&mut device); - let image_pipeline = crate::image::Pipeline::new(&mut device); - let triangle_pipeline = triangle::Pipeline::new(&mut device); + /// Creates a new [`Renderer`]. + /// + /// [`Renderer`]: struct.Renderer.html + pub fn new(settings: Settings, device: &mut wgpu::Device) -> Self { + let text_pipeline = text::Pipeline::new(device, settings.default_font); + let quad_pipeline = quad::Pipeline::new(device); + let image_pipeline = crate::image::Pipeline::new(device); + let triangle_pipeline = triangle::Pipeline::new(device); Self { - device, - queue, quad_pipeline, image_pipeline, text_pipeline, @@ -83,38 +61,25 @@ impl Renderer { } } - fn draw<T: AsRef<str>>( + /// Draws the provided primitives in the given [`Target`]. + /// + /// The text provided as overlay will be renderer on top of the primitives. + /// This is useful for rendering debug information. + /// + /// [`Target`]: struct.Target.html + pub fn draw<T: AsRef<str>>( &mut self, + device: &mut wgpu::Device, + encoder: &mut wgpu::CommandEncoder, + target: Target<'_>, (primitive, mouse_cursor): &(Primitive, MouseCursor), overlay: &[T], - target: &mut Target, ) -> MouseCursor { log::debug!("Drawing"); - let (width, height) = target.dimensions(); - let scale_factor = target.scale_factor(); - let transformation = target.transformation(); - let frame = target.next_frame(); - - let mut encoder = self - .device - .create_command_encoder(&CommandEncoderDescriptor { todo: 0 }); - - let _ = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { - attachment: &frame.view, - resolve_target: None, - load_op: wgpu::LoadOp::Clear, - store_op: wgpu::StoreOp::Store, - clear_color: wgpu::Color { - r: 1.0, - g: 1.0, - b: 1.0, - a: 1.0, - }, - }], - depth_stencil_attachment: None, - }); + let (width, height) = target.viewport.dimensions(); + let scale_factor = target.viewport.scale_factor(); + let transformation = target.viewport.transformation(); let mut layers = Vec::new(); @@ -133,15 +98,15 @@ impl Renderer { for layer in layers { self.flush( + device, scale_factor, transformation, &layer, - &mut encoder, - &frame.view, + encoder, + target.texture, ); } - self.queue.submit(&[encoder.finish()]); self.image_pipeline.trim_cache(); *mouse_cursor @@ -336,6 +301,7 @@ impl Renderer { fn flush( &mut self, + device: &mut wgpu::Device, scale_factor: f32, transformation: Transformation, layer: &Layer<'_>, @@ -352,7 +318,7 @@ impl Renderer { ); self.triangle_pipeline.draw( - &mut self.device, + device, encoder, target, translated, @@ -364,7 +330,7 @@ impl Renderer { if layer.quads.len() > 0 { self.quad_pipeline.draw( - &mut self.device, + device, encoder, &layer.quads, transformation, @@ -383,7 +349,7 @@ impl Renderer { ); self.image_pipeline.draw( - &mut self.device, + device, encoder, &layer.images, translated_and_scaled, @@ -429,7 +395,7 @@ impl Renderer { } self.text_pipeline.draw_queued( - &mut self.device, + device, encoder, target, transformation, @@ -461,24 +427,6 @@ impl iced_native::Renderer for Renderer { } } -impl window::Renderer for Renderer { - type Settings = Settings; - type Target = Target; - - fn new(settings: Settings) -> Self { - Self::new(settings) - } - - fn draw<T: AsRef<str>>( - &mut self, - output: &Self::Output, - overlay: &[T], - target: &mut Target, - ) -> MouseCursor { - self.draw(output, overlay, target) - } -} - impl layout::Debugger for Renderer { fn explain<Message>( &mut self, diff --git a/wgpu/src/renderer/target.rs b/wgpu/src/renderer/target.rs deleted file mode 100644 index 20974976..00000000 --- a/wgpu/src/renderer/target.rs +++ /dev/null @@ -1,91 +0,0 @@ -use crate::{Renderer, Transformation}; -use iced_native::window; - -use raw_window_handle::HasRawWindowHandle; - -/// A rendering target. -#[derive(Debug)] -pub struct Target { - surface: wgpu::Surface, - width: u32, - height: u32, - scale_factor: f32, - transformation: Transformation, - swap_chain: wgpu::SwapChain, -} - -impl Target { - pub(crate) fn dimensions(&self) -> (u32, u32) { - (self.width, self.height) - } - - pub(crate) fn scale_factor(&self) -> f32 { - self.scale_factor - } - - pub(crate) fn transformation(&self) -> Transformation { - self.transformation - } - - pub(crate) fn next_frame(&mut self) -> wgpu::SwapChainOutput<'_> { - self.swap_chain.get_next_texture() - } -} - -impl window::Target for Target { - type Renderer = Renderer; - - fn new<W: HasRawWindowHandle>( - window: &W, - width: u32, - height: u32, - scale_factor: f64, - renderer: &Renderer, - ) -> Target { - let surface = wgpu::Surface::create(window); - let swap_chain = - new_swap_chain(&surface, width, height, &renderer.device); - - Target { - surface, - width, - height, - scale_factor: scale_factor as f32, - transformation: Transformation::orthographic(width, height), - swap_chain, - } - } - - fn resize( - &mut self, - width: u32, - height: u32, - scale_factor: f64, - renderer: &Renderer, - ) { - self.width = width; - self.height = height; - self.scale_factor = scale_factor as f32; - self.transformation = Transformation::orthographic(width, height); - self.swap_chain = - new_swap_chain(&self.surface, width, height, &renderer.device); - } -} - -fn new_swap_chain( - surface: &wgpu::Surface, - width: u32, - height: u32, - device: &wgpu::Device, -) -> wgpu::SwapChain { - device.create_swap_chain( - &surface, - &wgpu::SwapChainDescriptor { - usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, - format: wgpu::TextureFormat::Bgra8UnormSrgb, - width, - height, - present_mode: wgpu::PresentMode::Vsync, - }, - ) -} diff --git a/wgpu/src/target.rs b/wgpu/src/target.rs new file mode 100644 index 00000000..544e83d1 --- /dev/null +++ b/wgpu/src/target.rs @@ -0,0 +1,8 @@ +use crate::Viewport; + +/// A rendering target. +#[derive(Debug)] +pub struct Target<'a> { + pub texture: &'a wgpu::TextureView, + pub viewport: &'a Viewport, +} diff --git a/wgpu/src/viewport.rs b/wgpu/src/viewport.rs new file mode 100644 index 00000000..a4bcb704 --- /dev/null +++ b/wgpu/src/viewport.rs @@ -0,0 +1,32 @@ +use crate::Transformation; + +#[derive(Debug)] +pub struct Viewport { + width: u32, + height: u32, + scale_factor: f32, + transformation: Transformation, +} + +impl Viewport { + pub fn new(width: u32, height: u32, scale_factor: f64) -> Viewport { + Viewport { + width, + height, + scale_factor: scale_factor as f32, + transformation: Transformation::orthographic(width, height), + } + } + + pub fn dimensions(&self) -> (u32, u32) { + (self.width, self.height) + } + + pub fn scale_factor(&self) -> f32 { + self.scale_factor + } + + pub(crate) fn transformation(&self) -> Transformation { + self.transformation + } +} diff --git a/wgpu/src/window.rs b/wgpu/src/window.rs new file mode 100644 index 00000000..97cac9b7 --- /dev/null +++ b/wgpu/src/window.rs @@ -0,0 +1,5 @@ +mod backend; +mod swap_chain; + +pub use backend::Backend; +pub use swap_chain::SwapChain; diff --git a/wgpu/src/window/backend.rs b/wgpu/src/window/backend.rs new file mode 100644 index 00000000..fda34a0a --- /dev/null +++ b/wgpu/src/window/backend.rs @@ -0,0 +1,99 @@ +use crate::{window::SwapChain, Renderer, Settings, Target}; + +use iced_native::MouseCursor; +use raw_window_handle::HasRawWindowHandle; + +#[derive(Debug)] +pub struct Backend { + device: wgpu::Device, + queue: wgpu::Queue, +} + +impl iced_native::window::Backend for Backend { + type Settings = Settings; + type Renderer = Renderer; + type Surface = wgpu::Surface; + type SwapChain = SwapChain; + + fn new(settings: Self::Settings) -> (Backend, Renderer) { + let adapter = wgpu::Adapter::request(&wgpu::RequestAdapterOptions { + power_preference: wgpu::PowerPreference::Default, + backends: wgpu::BackendBit::all(), + }) + .expect("Request adapter"); + + let (mut device, queue) = + adapter.request_device(&wgpu::DeviceDescriptor { + extensions: wgpu::Extensions { + anisotropic_filtering: false, + }, + limits: wgpu::Limits { max_bind_groups: 2 }, + }); + + let renderer = Renderer::new(settings, &mut device); + + (Backend { device, queue }, renderer) + } + + fn create_surface<W: HasRawWindowHandle>( + &mut self, + window: &W, + ) -> wgpu::Surface { + wgpu::Surface::create(window) + } + + fn create_swap_chain( + &mut self, + surface: &Self::Surface, + width: u32, + height: u32, + scale_factor: f64, + ) -> SwapChain { + SwapChain::new(&self.device, surface, width, height, scale_factor) + } + + fn draw<T: AsRef<str>>( + &mut self, + renderer: &mut Self::Renderer, + swap_chain: &mut SwapChain, + output: &<Self::Renderer as iced_native::Renderer>::Output, + overlay: &[T], + ) -> MouseCursor { + let (frame, viewport) = swap_chain.next_frame(); + + let mut encoder = self.device.create_command_encoder( + &wgpu::CommandEncoderDescriptor { todo: 0 }, + ); + + let _ = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { + attachment: &frame.view, + resolve_target: None, + load_op: wgpu::LoadOp::Clear, + store_op: wgpu::StoreOp::Store, + clear_color: wgpu::Color { + r: 1.0, + g: 1.0, + b: 1.0, + a: 1.0, + }, + }], + depth_stencil_attachment: None, + }); + + let mouse_cursor = renderer.draw( + &mut self.device, + &mut encoder, + Target { + texture: &frame.view, + viewport, + }, + output, + overlay, + ); + + self.queue.submit(&[encoder.finish()]); + + mouse_cursor + } +} diff --git a/wgpu/src/window/swap_chain.rs b/wgpu/src/window/swap_chain.rs new file mode 100644 index 00000000..46aaa869 --- /dev/null +++ b/wgpu/src/window/swap_chain.rs @@ -0,0 +1,49 @@ +use crate::Viewport; + +/// The rendering target of a window. +/// +/// It represents a series of virtual framebuffers with a scale factor. +#[derive(Debug)] +pub struct SwapChain { + raw: wgpu::SwapChain, + viewport: Viewport, +} + +impl SwapChain {} + +impl SwapChain { + pub fn new( + device: &wgpu::Device, + surface: &wgpu::Surface, + width: u32, + height: u32, + scale_factor: f64, + ) -> SwapChain { + SwapChain { + raw: new_swap_chain(surface, width, height, device), + viewport: Viewport::new(width, height, scale_factor), + } + } + + pub fn next_frame(&mut self) -> (wgpu::SwapChainOutput<'_>, &Viewport) { + (self.raw.get_next_texture(), &self.viewport) + } +} + +fn new_swap_chain( + surface: &wgpu::Surface, + width: u32, + height: u32, + device: &wgpu::Device, +) -> wgpu::SwapChain { + device.create_swap_chain( + &surface, + &wgpu::SwapChainDescriptor { + usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, + format: wgpu::TextureFormat::Bgra8UnormSrgb, + width, + height, + present_mode: wgpu::PresentMode::Vsync, + }, + ) +} diff --git a/winit/src/application.rs b/winit/src/application.rs index 3c0332ed..0d90525a 100644 --- a/winit/src/application.rs +++ b/winit/src/application.rs @@ -14,10 +14,10 @@ use crate::{ /// An [`Application`](trait.Application.html) can execute asynchronous actions /// by returning a [`Command`](struct.Command.html) in some of its methods. pub trait Application: Sized { - /// The renderer to use to draw the [`Application`]. + /// The graphics backend to use to draw the [`Application`]. /// /// [`Application`]: trait.Application.html - type Renderer: window::Renderer; + type Backend: window::Backend; /// The [`Executor`] that will run commands and subscriptions. /// @@ -75,7 +75,9 @@ pub trait Application: Sized { /// These widgets can produce __messages__ based on user interaction. /// /// [`Application`]: trait.Application.html - fn view(&mut self) -> Element<'_, Self::Message, Self::Renderer>; + fn view( + &mut self, + ) -> Element<'_, Self::Message, <Self::Backend as window::Backend>::Renderer>; /// Returns the current [`Application`] mode. /// @@ -99,11 +101,11 @@ pub trait Application: Sized { /// [`Application`]: trait.Application.html fn run( settings: Settings, - renderer_settings: <Self::Renderer as window::Renderer>::Settings, + backend_settings: <Self::Backend as window::Backend>::Settings, ) where Self: 'static, { - use window::{Renderer as _, Target as _}; + use window::Backend as _; use winit::{ event::{self, WindowEvent}, event_loop::{ControlFlow, EventLoop}, @@ -162,17 +164,18 @@ pub trait Application: Sized { let mut resized = false; let clipboard = Clipboard::new(&window); - let mut renderer = Self::Renderer::new(renderer_settings); + let (mut backend, mut renderer) = Self::Backend::new(backend_settings); - let mut target = { + let surface = backend.create_surface(&window); + + let mut swap_chain = { let physical_size = size.physical(); - <Self::Renderer as window::Renderer>::Target::new( - &window, + backend.create_swap_chain( + &surface, physical_size.width, physical_size.height, size.scale_factor(), - &renderer, ) }; @@ -306,18 +309,22 @@ pub trait Application: Sized { if resized { let physical_size = size.physical(); - target.resize( + swap_chain = backend.create_swap_chain( + &surface, physical_size.width, physical_size.height, size.scale_factor(), - &renderer, ); resized = false; } - let new_mouse_cursor = - renderer.draw(&primitive, &debug.overlay(), &mut target); + let new_mouse_cursor = backend.draw( + &mut renderer, + &mut swap_chain, + &primitive, + &debug.overlay(), + ); debug.render_finished(); @@ -451,10 +458,10 @@ pub trait Application: Sized { fn build_user_interface<'a, A: Application>( application: &'a mut A, cache: Cache, - renderer: &mut A::Renderer, + renderer: &mut <A::Backend as window::Backend>::Renderer, size: winit::dpi::LogicalSize<f64>, debug: &mut Debug, -) -> UserInterface<'a, A::Message, A::Renderer> { +) -> UserInterface<'a, A::Message, <A::Backend as window::Backend>::Renderer> { debug.view_started(); let view = application.view(); debug.view_finished(); |