From 58e04af824a64d9f712a2d6691d4283888d271d3 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector0193@gmail.com>
Date: Sat, 2 Nov 2019 19:58:49 +0100
Subject: Draft `Metrics` and improve `Target` abstraction

---
 native/src/lib.rs               |  2 +
 native/src/metrics.rs           | 11 ++++++
 native/src/renderer.rs          |  2 +-
 native/src/renderer/windowed.rs | 24 +++++++++---
 wgpu/src/renderer.rs            | 84 ++++++++++++++++++++++++++---------------
 winit/src/application.rs        | 18 ++++++---
 6 files changed, 99 insertions(+), 42 deletions(-)
 create mode 100644 native/src/metrics.rs

diff --git a/native/src/lib.rs b/native/src/lib.rs
index fa72a553..86bfb3ca 100644
--- a/native/src/lib.rs
+++ b/native/src/lib.rs
@@ -206,6 +206,7 @@ mod element;
 mod event;
 mod hasher;
 mod layout;
+mod metrics;
 mod mouse_cursor;
 mod node;
 mod style;
@@ -224,6 +225,7 @@ pub use element::Element;
 pub use event::Event;
 pub use hasher::Hasher;
 pub use layout::Layout;
+pub use metrics::Metrics;
 pub use mouse_cursor::MouseCursor;
 pub use node::Node;
 pub use renderer::Renderer;
diff --git a/native/src/metrics.rs b/native/src/metrics.rs
new file mode 100644
index 00000000..7c344b9b
--- /dev/null
+++ b/native/src/metrics.rs
@@ -0,0 +1,11 @@
+use std::time;
+
+/// A bunch of metrics about an Iced application.
+#[derive(Debug, Clone, Copy)]
+pub struct Metrics {
+    pub startup_time: time::Duration,
+    pub update_time: time::Duration,
+    pub view_time: time::Duration,
+    pub renderer_output_time: time::Duration,
+    pub message_count: usize,
+}
diff --git a/native/src/renderer.rs b/native/src/renderer.rs
index afe1b09a..5963d577 100644
--- a/native/src/renderer.rs
+++ b/native/src/renderer.rs
@@ -24,7 +24,7 @@ mod debugger;
 mod windowed;
 
 pub use debugger::Debugger;
-pub use windowed::Windowed;
+pub use windowed::{Target, Windowed};
 
 pub trait Renderer {
     type Output;
diff --git a/native/src/renderer/windowed.rs b/native/src/renderer/windowed.rs
index bcf37964..0499ca70 100644
--- a/native/src/renderer/windowed.rs
+++ b/native/src/renderer/windowed.rs
@@ -1,17 +1,29 @@
-use crate::MouseCursor;
+use crate::{Metrics, MouseCursor};
 
 use raw_window_handle::HasRawWindowHandle;
 
-pub trait Windowed: super::Renderer {
-    type Target;
+pub trait Windowed: super::Renderer + Sized {
+    type Target: Target<Renderer = Self>;
 
-    fn new<W: HasRawWindowHandle>(window: &W) -> Self;
-
-    fn target(&self, width: u16, height: u16) -> Self::Target;
+    fn new() -> Self;
 
     fn draw(
         &mut self,
         output: &Self::Output,
+        metrics: Option<Metrics>,
         target: &mut Self::Target,
     ) -> MouseCursor;
 }
+
+pub trait Target {
+    type Renderer;
+
+    fn new<W: HasRawWindowHandle>(
+        window: &W,
+        width: u16,
+        height: u16,
+        renderer: &Self::Renderer,
+    ) -> Self;
+
+    fn resize(&mut self, width: u16, height: u16, renderer: &Self::Renderer);
+}
diff --git a/wgpu/src/renderer.rs b/wgpu/src/renderer.rs
index fbc39327..6e90c129 100644
--- a/wgpu/src/renderer.rs
+++ b/wgpu/src/renderer.rs
@@ -1,6 +1,6 @@
 use crate::{quad, Image, Primitive, Quad, Transformation};
 use iced_native::{
-    renderer::Debugger, renderer::Windowed, Background, Color, Layout,
+    renderer::Debugger, renderer::Windowed, Background, Color, Layout, Metrics,
     MouseCursor, Point, Rectangle, Widget,
 };
 
@@ -26,7 +26,6 @@ mod text;
 mod text_input;
 
 pub struct Renderer {
-    surface: Surface,
     device: Device,
     queue: Queue,
     quad_pipeline: quad::Pipeline,
@@ -36,12 +35,61 @@ pub struct Renderer {
 }
 
 pub struct Target {
+    surface: Surface,
     width: u16,
     height: u16,
     transformation: Transformation,
     swap_chain: SwapChain,
 }
 
+impl iced_native::renderer::Target for Target {
+    type Renderer = Renderer;
+
+    fn new<W: HasRawWindowHandle>(
+        window: &W,
+        width: u16,
+        height: u16,
+        renderer: &Renderer,
+    ) -> Target {
+        let surface = Surface::create(window);
+
+        let swap_chain = renderer.device.create_swap_chain(
+            &surface,
+            &SwapChainDescriptor {
+                usage: TextureUsage::OUTPUT_ATTACHMENT,
+                format: TextureFormat::Bgra8UnormSrgb,
+                width: u32::from(width),
+                height: u32::from(height),
+                present_mode: wgpu::PresentMode::Vsync,
+            },
+        );
+
+        Target {
+            surface,
+            width,
+            height,
+            transformation: Transformation::orthographic(width, height),
+            swap_chain,
+        }
+    }
+
+    fn resize(&mut self, width: u16, height: u16, renderer: &Renderer) {
+        self.width = width;
+        self.height = height;
+        self.transformation = Transformation::orthographic(width, height);
+        self.swap_chain = renderer.device.create_swap_chain(
+            &self.surface,
+            &SwapChainDescriptor {
+                usage: TextureUsage::OUTPUT_ATTACHMENT,
+                format: TextureFormat::Bgra8UnormSrgb,
+                width: u32::from(width),
+                height: u32::from(height),
+                present_mode: wgpu::PresentMode::Vsync,
+            },
+        );
+    }
+}
+
 pub struct Layer<'a> {
     bounds: Rectangle<u32>,
     y_offset: u32,
@@ -63,7 +111,7 @@ impl<'a> Layer<'a> {
 }
 
 impl Renderer {
-    fn new<W: HasRawWindowHandle>(window: &W) -> Self {
+    fn new() -> Self {
         let adapter = Adapter::request(&RequestAdapterOptions {
             power_preference: PowerPreference::LowPower,
             backends: BackendBit::all(),
@@ -77,8 +125,6 @@ impl Renderer {
             limits: Limits { max_bind_groups: 2 },
         });
 
-        let surface = Surface::create(window);
-
         // TODO: Think about font loading strategy
         // Loading system fonts with fallback may be a good idea
         let font: &[u8] =
@@ -91,7 +137,6 @@ impl Renderer {
         let image_pipeline = crate::image::Pipeline::new(&mut device);
 
         Self {
-            surface,
             device,
             queue,
             quad_pipeline,
@@ -101,24 +146,6 @@ impl Renderer {
         }
     }
 
-    fn target(&self, width: u16, height: u16) -> Target {
-        Target {
-            width,
-            height,
-            transformation: Transformation::orthographic(width, height),
-            swap_chain: self.device.create_swap_chain(
-                &self.surface,
-                &SwapChainDescriptor {
-                    usage: TextureUsage::OUTPUT_ATTACHMENT,
-                    format: TextureFormat::Bgra8UnormSrgb,
-                    width: u32::from(width),
-                    height: u32::from(height),
-                    present_mode: wgpu::PresentMode::Vsync,
-                },
-            ),
-        }
-    }
-
     fn draw(
         &mut self,
         (primitive, mouse_cursor): &(Primitive, MouseCursor),
@@ -363,17 +390,14 @@ impl iced_native::Renderer for Renderer {
 impl Windowed for Renderer {
     type Target = Target;
 
-    fn new<W: HasRawWindowHandle>(window: &W) -> Self {
-        Self::new(window)
-    }
-
-    fn target(&self, width: u16, height: u16) -> Target {
-        self.target(width, height)
+    fn new() -> Self {
+        Self::new()
     }
 
     fn draw(
         &mut self,
         output: &Self::Output,
+        metrics: Option<Metrics>,
         target: &mut Target,
     ) -> MouseCursor {
         self.draw(output, target)
diff --git a/winit/src/application.rs b/winit/src/application.rs
index b90b5eef..8c7d8c37 100644
--- a/winit/src/application.rs
+++ b/winit/src/application.rs
@@ -1,7 +1,7 @@
 use crate::{
     column, conversion,
     input::{keyboard, mouse},
-    renderer::Windowed,
+    renderer::{Target, Windowed},
     Cache, Column, Element, Event, Length, MouseCursor, UserInterface,
 };
 
@@ -41,8 +41,14 @@ pub trait Application {
             .into();
         let mut new_size: Option<Size> = None;
 
-        let mut renderer = Self::Renderer::new(&window);
-        let mut target = renderer.target(size.width, size.height);
+        let mut renderer = Self::Renderer::new();
+
+        let mut target = <Self::Renderer as Windowed>::Target::new(
+            &window,
+            size.width,
+            size.height,
+            &renderer,
+        );
 
         let user_interface = UserInterface::build(
             document(&mut self, size),
@@ -103,11 +109,13 @@ pub trait Application {
             }
             event::Event::RedrawRequested(_) => {
                 if let Some(new_size) = new_size.take() {
-                    target = renderer.target(new_size.width, new_size.height);
+                    target.resize(new_size.width, new_size.height, &renderer);
+
                     size = new_size;
                 }
 
-                let new_mouse_cursor = renderer.draw(&primitive, &mut target);
+                let new_mouse_cursor =
+                    renderer.draw(&primitive, None, &mut target);
 
                 if new_mouse_cursor != mouse_cursor {
                     window.set_cursor_icon(conversion::mouse_cursor(
-- 
cgit