diff --git a/apps/magpie/Cargo.toml b/apps/magpie/Cargo.toml index ae5b420..86c3ebb 100644 --- a/apps/magpie/Cargo.toml +++ b/apps/magpie/Cargo.toml @@ -12,13 +12,25 @@ required-features = ["service"] anyhow = { version = "1", optional = true } byteorder = "1.4" canary = { path = "../..", optional = true } -glium = { version = "0.32", optional = true} +canary-wgpu = { path = "../../renderers/wgpu", optional = true } mio = { version = "0.8", features = ["net", "os-poll"], optional = true } mio-signals = { version = "0.2", optional = true } -parking_lot = { version = "0.12", optional = true} +parking_lot = { version = "0.12", optional = true } +pollster = { version = "0.2", optional = true } serde = { version = "1", features = ["derive"] } serde_json = "1" -slab = { version = "0.4", optional = true} +slab = { version = "0.4", optional = true } +winit = { version = "0.27", optional = true } [features] -service = ["dep:anyhow", "dep:canary", "dep:glium", "dep:mio", "dep:mio-signals", "dep:parking_lot", "dep:slab"] +service = [ + "dep:anyhow", + "dep:canary", + "dep:canary-wgpu", + "dep:mio", + "dep:mio-signals", + "dep:parking_lot", + "dep:pollster", + "dep:slab", + "dep:winit", +] diff --git a/apps/magpie/src/main.rs b/apps/magpie/src/main.rs index d53eb7a..2360243 100644 --- a/apps/magpie/src/main.rs +++ b/apps/magpie/src/main.rs @@ -1,4 +1,4 @@ -use glium::glutin::event_loop::EventLoopBuilder; +use winit::event_loop::EventLoopBuilder; use canary_magpie::service::*; use ipc::Ipc; diff --git a/apps/magpie/src/service/gl.rs b/apps/magpie/src/service/gl.rs deleted file mode 100644 index 9c0a620..0000000 --- a/apps/magpie/src/service/gl.rs +++ /dev/null @@ -1,117 +0,0 @@ -use canary::{DrawCommand, Vec2, PX_PER_MM}; -use glium::Surface; - -#[derive(Copy, Clone)] -pub struct Vertex { - pub position: [f32; 2], - pub color: [u8; 4], -} - -glium::implement_vertex!(Vertex, position normalize(false), color normalize(true)); - -impl Vertex { - pub fn from_canary(size: Vec2, v: &canary::MeshVertex) -> Self { - // TODO do this in the vertex shader with a size uniform - let (r, g, b, a) = v.color.to_rgba_unmultiplied(); - Self { - position: [ - (v.position.x / size.x) * 2.0 - 1.0, - (v.position.y / size.y) * -2.0 + 1.0, - ], - color: [r, g, b, a], - } - } -} - -const VERTEX_SHADER_SRC: &str = r#" - #version 330 - - in vec2 position; - in vec4 color; - - out vec4 frag_color; - - void main() { - gl_Position = vec4(position, 0.0, 1.0); - frag_color = color; - } -"#; - -const FRAGMENT_SHADER_SRC: &str = r#" - #version 330 - - in vec4 frag_color; - - out vec4 fb_color; - - void main() { - fb_color = frag_color; - } -"#; - -pub struct Graphics { - pub display: glium::Display, - pub program: glium::Program, -} - -impl Graphics { - pub fn new(display: glium::Display) -> Self { - let program = - glium::Program::from_source(&display, VERTEX_SHADER_SRC, FRAGMENT_SHADER_SRC, None) - .unwrap(); - Self { display, program } - } - - pub fn draw(&mut self, commands: &[DrawCommand]) { - let mut joined_vs: Vec = Vec::new(); - let mut joined_is = Vec::new(); - - let (width, height) = { - let size = self.display.gl_window().window().inner_size(); - let (width, height) = (size.width as f32, size.height as f32); - (width * PX_PER_MM, height * PX_PER_MM) - }; - - let size = Vec2 { - x: width, - y: height, - }; - - for command in commands.iter() { - match command { - canary::DrawCommand::Mesh { vertices, indices } => { - let voff = joined_vs.len() as canary::MeshIndex; - joined_vs.extend(vertices.iter().map(|v| Vertex::from_canary(size, v))); - joined_is.extend(indices.iter().map(|i| i + voff)); - } - _ => unimplemented!(), - } - } - - let vertex_buffer = glium::VertexBuffer::new(&self.display, &joined_vs).unwrap(); - let index_buffer = glium::IndexBuffer::new( - &self.display, - glium::index::PrimitiveType::TrianglesList, - &joined_is, - ) - .unwrap(); - - let params = glium::DrawParameters { - blend: glium::Blend::alpha_blending(), - ..Default::default() - }; - - let mut target = self.display.draw(); - target.clear_color(0.0, 0.0, 0.0, 1.0); - target - .draw( - &vertex_buffer, - &index_buffer, - &self.program, - &glium::uniforms::EmptyUniforms, - ¶ms, - ) - .unwrap(); - target.finish().unwrap(); - } -} diff --git a/apps/magpie/src/service/mod.rs b/apps/magpie/src/service/mod.rs index b57a6fe..89a30f7 100644 --- a/apps/magpie/src/service/mod.rs +++ b/apps/magpie/src/service/mod.rs @@ -1,3 +1,2 @@ -pub mod gl; pub mod ipc; pub mod window; diff --git a/apps/magpie/src/service/window.rs b/apps/magpie/src/service/window.rs index 624b7aa..b98d106 100644 --- a/apps/magpie/src/service/window.rs +++ b/apps/magpie/src/service/window.rs @@ -1,15 +1,17 @@ use std::collections::HashMap; use std::path::PathBuf; +use std::sync::Arc; use std::time::Instant; +use anyhow::anyhow; use canary::{CursorEventKind, Panel, Runtime, Vec2, PX_PER_MM}; -use glium::backend::glutin::DisplayCreationError; -use glium::{glutin, Surface}; -use glutin::event::{ElementState, Event, MouseButton, WindowEvent}; -use glutin::event_loop::{ControlFlow, EventLoop, EventLoopProxy, EventLoopWindowTarget}; -use glutin::window::WindowId; +use canary_wgpu::{wgpu, DrawTarget, Renderer}; +use pollster::FutureExt; +use winit::dpi::PhysicalSize; +use winit::event::{ElementState, Event, MouseButton, WindowEvent}; +use winit::event_loop::{ControlFlow, EventLoop, EventLoopProxy, EventLoopWindowTarget}; +use winit::window::{WindowBuilder, WindowId}; -use crate::service::gl::Graphics; use crate::service::ipc::{IpcMessage, IpcMessageSender}; #[derive(Clone, Debug)] @@ -23,7 +25,12 @@ pub enum WindowMessage { pub type WindowMessageSender = EventLoopProxy; pub struct Window { - pub graphics: Graphics, + pub window: winit::window::Window, + pub surface: wgpu::Surface, + pub surface_config: wgpu::SurfaceConfiguration, + pub device: Arc, + pub queue: Arc, + pub renderer: Renderer, pub panel: Panel, pub last_update: Instant, pub cursor_pos: Vec2, @@ -33,15 +40,42 @@ pub struct Window { impl Window { pub fn new( panel: Panel, + instance: &wgpu::Instance, + adapter: &wgpu::Adapter, + device: Arc, + queue: Arc, event_loop: &EventLoopWindowTarget, - ) -> Result { - let wb = glutin::window::WindowBuilder::new(); - let cb = glutin::ContextBuilder::new(); - let display = glium::Display::new(wb, cb, &event_loop)?; - let graphics = Graphics::new(display); + ) -> anyhow::Result { + let window = WindowBuilder::new().build(&event_loop)?; + let surface = unsafe { instance.create_surface(&window) }; let last_update = Instant::now(); + + let format = *surface + .get_supported_formats(&adapter) + .first() + .ok_or(anyhow!("Could not find surface format for new window"))?; + let size = window.inner_size(); + + let surface_config = wgpu::SurfaceConfiguration { + usage: wgpu::TextureUsages::RENDER_ATTACHMENT, + format, + width: size.width, + height: size.height, + present_mode: wgpu::PresentMode::Fifo, + alpha_mode: wgpu::CompositeAlphaMode::Auto, + }; + + surface.configure(&device, &surface_config); + + let renderer = Renderer::new(device.to_owned(), queue.to_owned()); + Ok(Self { - graphics, + window, + surface, + surface_config, + device, + queue, + renderer, panel, last_update, cursor_pos: Vec2::ZERO, @@ -50,11 +84,11 @@ impl Window { } pub fn get_id(&self) -> WindowId { - self.graphics.display.gl_window().window().id() + self.window.id() } pub fn request_redraw(&mut self) { - self.graphics.display.gl_window().window().request_redraw(); + self.window.request_redraw(); } pub fn update(&mut self) { @@ -65,24 +99,45 @@ impl Window { } pub fn draw(&mut self) { + let output = self.surface.get_current_texture().unwrap(); + let view = output.texture.create_view(&Default::default()); let commands = self.panel.draw(); - self.graphics.draw(&commands); + + let size = Vec2::new( + self.surface_config.width as f32, + self.surface_config.height as f32, + ) * PX_PER_MM; + + let target = DrawTarget { + texture: &view, + size, + }; + + self.renderer.render(target, &commands); + + output.present(); } pub fn send_message(&mut self, msg: Vec) { self.panel.on_message(msg); } - pub fn resize(&mut self, new_size: Vec2) { - self.panel.on_resize(new_size); + pub fn resize(&mut self, new_size: PhysicalSize) { + let mm = Vec2::new(new_size.width as f32, new_size.height as f32) * PX_PER_MM; + self.panel.on_resize(mm); + self.window.request_redraw(); + + if new_size.width > 0 && new_size.height > 0 { + self.surface_config.width = new_size.width; + self.surface_config.height = new_size.height; + self.surface.configure(&self.device, &self.surface_config); + } } pub fn on_event(&mut self, event: WindowEvent) { match event { - WindowEvent::Resized(size) => { - self.resize(Vec2::new(size.width as f32, size.height as f32) * PX_PER_MM); - self.request_redraw() - } + WindowEvent::Resized(size) => self.resize(size), + WindowEvent::ScaleFactorChanged { new_inner_size, .. } => self.resize(*new_inner_size), WindowEvent::CursorMoved { position, .. } => { let x = position.x as f32 * PX_PER_MM; let y = position.y as f32 * PX_PER_MM; @@ -124,6 +179,10 @@ pub struct WindowStore { pub ipc_to_window: HashMap, pub windows: HashMap, pub runtime: Runtime, + pub instance: wgpu::Instance, + pub adapter: wgpu::Adapter, + pub device: Arc, + pub queue: Arc, } impl WindowStore { @@ -131,11 +190,36 @@ impl WindowStore { let backend = canary::backend::make_default_backend().unwrap(); let runtime = Runtime::new(backend).unwrap(); + let instance = wgpu::Instance::new(wgpu::Backends::all()); + let adapter = instance + .request_adapter(&wgpu::RequestAdapterOptionsBase { + power_preference: wgpu::PowerPreference::HighPerformance, + force_fallback_adapter: false, + compatible_surface: None, + }) + .block_on() + .unwrap(); + let (device, queue) = adapter + .request_device( + &wgpu::DeviceDescriptor { + label: None, + features: wgpu::Features::empty(), + limits: wgpu::Limits::downlevel_defaults(), + }, + None, + ) + .block_on() + .unwrap(); + Self { ipc_sender, ipc_to_window: Default::default(), windows: Default::default(), runtime, + instance, + adapter, + device: Arc::new(device), + queue: Arc::new(queue), } } @@ -157,7 +241,14 @@ impl WindowStore { let module = std::fs::read(script)?; let mut script = self.runtime.load_module(&module)?; let panel = script.create_panel(vec![])?; - let window = Window::new(panel, &event_loop)?; + let window = Window::new( + panel, + &self.instance, + &self.adapter, + self.device.to_owned(), + self.queue.to_owned(), + &event_loop, + )?; let window_id = window.get_id(); self.windows.insert(window_id, window); self.ipc_to_window.insert(id, window_id);