WIP Magpie wgpu renderer
This commit is contained in:
parent
51c8627755
commit
c25449cbf9
|
@ -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",
|
||||
]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use glium::glutin::event_loop::EventLoopBuilder;
|
||||
use winit::event_loop::EventLoopBuilder;
|
||||
|
||||
use canary_magpie::service::*;
|
||||
use ipc::Ipc;
|
||||
|
|
|
@ -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,
|
||||
¶ms,
|
||||
)
|
||||
.unwrap();
|
||||
target.finish().unwrap();
|
||||
}
|
||||
}
|
|
@ -1,3 +1,2 @@
|
|||
pub mod gl;
|
||||
pub mod ipc;
|
||||
pub mod window;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue