diff options
Diffstat (limited to 'wgpu/src/window')
-rw-r--r-- | wgpu/src/window/backend.rs | 113 | ||||
-rw-r--r-- | wgpu/src/window/compositor.rs | 177 | ||||
-rw-r--r-- | wgpu/src/window/swap_chain.rs | 57 |
3 files changed, 177 insertions, 170 deletions
diff --git a/wgpu/src/window/backend.rs b/wgpu/src/window/backend.rs deleted file mode 100644 index 5b269f36..00000000 --- a/wgpu/src/window/backend.rs +++ /dev/null @@ -1,113 +0,0 @@ -use crate::{window::SwapChain, Renderer, Settings, Target}; - -use iced_native::MouseCursor; -use raw_window_handle::HasRawWindowHandle; - -/// A window graphics backend for iced powered by `wgpu`. -#[derive(Debug)] -pub struct Backend { - device: wgpu::Device, - queue: wgpu::Queue, - format: wgpu::TextureFormat, -} - -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: if settings.antialiasing.is_none() { - wgpu::PowerPreference::Default - } else { - wgpu::PowerPreference::HighPerformance - }, - 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(&mut device, settings); - - ( - Backend { - device, - queue, - format: settings.format, - }, - 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, - ) -> SwapChain { - SwapChain::new(&self.device, surface, self.format, width, height) - } - - fn draw<T: AsRef<str>>( - &mut self, - renderer: &mut Self::Renderer, - swap_chain: &mut SwapChain, - output: &<Self::Renderer as iced_native::Renderer>::Output, - scale_factor: f64, - 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, - scale_factor, - overlay, - ); - - self.queue.submit(&[encoder.finish()]); - - mouse_cursor - } -} diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs new file mode 100644 index 00000000..492efb42 --- /dev/null +++ b/wgpu/src/window/compositor.rs @@ -0,0 +1,177 @@ +use crate::{Backend, Color, Error, Renderer, Settings, Viewport}; + +use futures::task::SpawnExt; +use iced_native::{futures, mouse}; +use raw_window_handle::HasRawWindowHandle; + +/// A window graphics backend for iced powered by `wgpu`. +#[allow(missing_debug_implementations)] +pub struct Compositor { + settings: Settings, + instance: wgpu::Instance, + device: wgpu::Device, + queue: wgpu::Queue, + staging_belt: wgpu::util::StagingBelt, + local_pool: futures::executor::LocalPool, +} + +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. + pub async fn request(settings: Settings) -> Option<Self> { + let instance = wgpu::Instance::new(wgpu::BackendBit::PRIMARY); + + let adapter = instance + .request_adapter(&wgpu::RequestAdapterOptions { + power_preference: if settings.antialiasing.is_none() { + wgpu::PowerPreference::Default + } else { + wgpu::PowerPreference::HighPerformance + }, + compatible_surface: None, + }) + .await?; + + let (device, queue) = adapter + .request_device( + &wgpu::DeviceDescriptor { + features: wgpu::Features::empty(), + limits: wgpu::Limits { + max_bind_groups: 2, + ..wgpu::Limits::default() + }, + shader_validation: false, + }, + None, + ) + .await + .ok()?; + + let staging_belt = wgpu::util::StagingBelt::new(Self::CHUNK_SIZE); + let local_pool = futures::executor::LocalPool::new(); + + Some(Compositor { + instance, + settings, + device, + queue, + staging_belt, + local_pool, + }) + } + + /// Creates a new rendering [`Backend`] for this [`Compositor`]. + pub fn create_backend(&self) -> Backend { + Backend::new(&self.device, self.settings) + } +} + +impl iced_graphics::window::Compositor for Compositor { + type Settings = Settings; + type Renderer = Renderer; + type Surface = wgpu::Surface; + type SwapChain = wgpu::SwapChain; + + fn new(settings: Self::Settings) -> Result<(Self, Renderer), Error> { + let compositor = futures::executor::block_on(Self::request(settings)) + .ok_or(Error::AdapterNotFound)?; + + let backend = compositor.create_backend(); + + Ok((compositor, Renderer::new(backend))) + } + + fn create_surface<W: HasRawWindowHandle>( + &mut self, + window: &W, + ) -> wgpu::Surface { + #[allow(unsafe_code)] + unsafe { + self.instance.create_surface(window) + } + } + + fn create_swap_chain( + &mut self, + surface: &Self::Surface, + width: u32, + height: u32, + ) -> Self::SwapChain { + self.device.create_swap_chain( + surface, + &wgpu::SwapChainDescriptor { + usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, + format: self.settings.format, + present_mode: self.settings.present_mode, + width, + height, + }, + ) + } + + fn draw<T: AsRef<str>>( + &mut self, + renderer: &mut Self::Renderer, + swap_chain: &mut Self::SwapChain, + viewport: &Viewport, + background_color: Color, + output: &<Self::Renderer as iced_native::Renderer>::Output, + overlay: &[T], + ) -> mouse::Interaction { + let frame = swap_chain.get_current_frame().expect("Next frame"); + + let mut encoder = self.device.create_command_encoder( + &wgpu::CommandEncoderDescriptor { + label: Some("iced_wgpu encoder"), + }, + ); + + let _ = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { + attachment: &frame.output.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, + }); + + let mouse_interaction = renderer.backend_mut().draw( + &mut self.device, + &mut self.staging_belt, + &mut encoder, + &frame.output.view, + viewport, + output, + overlay, + ); + + // Submit work + self.staging_belt.finish(); + self.queue.submit(Some(encoder.finish())); + + // Recall staging buffers + self.local_pool + .spawner() + .spawn(self.staging_belt.recall()) + .expect("Recall staging belt"); + + self.local_pool.run_until_stalled(); + + mouse_interaction + } +} diff --git a/wgpu/src/window/swap_chain.rs b/wgpu/src/window/swap_chain.rs deleted file mode 100644 index 4ca2901b..00000000 --- a/wgpu/src/window/swap_chain.rs +++ /dev/null @@ -1,57 +0,0 @@ -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 { - /// Creates a new [`SwapChain`] for the given surface. - /// - /// [`SwapChain`]: struct.SwapChain.html - pub fn new( - device: &wgpu::Device, - surface: &wgpu::Surface, - format: wgpu::TextureFormat, - width: u32, - height: u32, - ) -> SwapChain { - SwapChain { - raw: new_swap_chain(surface, format, width, height, device), - viewport: Viewport::new(width, height), - } - } - - /// Returns the next frame of the [`SwapChain`] alongside its [`Viewport`]. - /// - /// [`SwapChain`]: struct.SwapChain.html - /// [`Viewport`]: ../struct.Viewport.html - pub fn next_frame(&mut self) -> (wgpu::SwapChainOutput<'_>, &Viewport) { - (self.raw.get_next_texture(), &self.viewport) - } -} - -fn new_swap_chain( - surface: &wgpu::Surface, - format: wgpu::TextureFormat, - width: u32, - height: u32, - device: &wgpu::Device, -) -> wgpu::SwapChain { - device.create_swap_chain( - &surface, - &wgpu::SwapChainDescriptor { - usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, - format, - width, - height, - present_mode: wgpu::PresentMode::Vsync, - }, - ) -} |