WIP Magpie wgpu renderer

This commit is contained in:
mars 2022-11-08 20:40:56 -07:00
parent 51c8627755
commit c25449cbf9
5 changed files with 131 additions and 146 deletions

View File

@ -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",
]

View File

@ -1,4 +1,4 @@
use glium::glutin::event_loop::EventLoopBuilder;
use winit::event_loop::EventLoopBuilder;
use canary_magpie::service::*;
use ipc::Ipc;

View File

@ -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<Vertex> = 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,
&params,
)
.unwrap();
target.finish().unwrap();
}
}

View File

@ -1,3 +1,2 @@
pub mod gl;
pub mod ipc;
pub mod window;

View File

@ -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<WindowMessage>;
pub struct Window {
pub graphics: Graphics,
pub window: winit::window::Window,
pub surface: wgpu::Surface,
pub surface_config: wgpu::SurfaceConfiguration,
pub device: Arc<wgpu::Device>,
pub queue: Arc<wgpu::Queue>,
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<wgpu::Device>,
queue: Arc<wgpu::Queue>,
event_loop: &EventLoopWindowTarget<WindowMessage>,
) -> Result<Self, DisplayCreationError> {
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<Self> {
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<u8>) {
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<u32>) {
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<usize, WindowId>,
pub windows: HashMap<WindowId, Window>,
pub runtime: Runtime,
pub instance: wgpu::Instance,
pub adapter: wgpu::Adapter,
pub device: Arc<wgpu::Device>,
pub queue: Arc<wgpu::Queue>,
}
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);