summaryrefslogtreecommitdiffstats
path: root/wgpu/src/window
diff options
context:
space:
mode:
Diffstat (limited to 'wgpu/src/window')
-rw-r--r--wgpu/src/window/backend.rs113
-rw-r--r--wgpu/src/window/compositor.rs177
-rw-r--r--wgpu/src/window/swap_chain.rs57
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,
- },
- )
-}