From 5db0a7ad9decd521b5d0a7f23d3b3e29c243f270 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Thu, 20 Aug 2020 15:58:51 -0700 Subject: [PATCH] reclaim wasm vertex/buffer memory, consolidate glow backends (#290) * Complete wasm backend memory mgmt, extract common glow code Similar to 3e8d2d7d, but for the wasm backend. Also takes a pass at consolidating some of the common code between the glow-native and glow-wasm backends. At this point, the backends just diverge in their window handling, and the data types of their OpenGL data types (e.g. vertex_buffer.id is WebBufferId vs. uint32 on native) * glow impls share prerender innards * coalesce vertex/buffer types * minimize diff * clarify module naming --- ezgui/Cargo.toml | 2 +- ezgui/README.md | 8 +- ezgui/src/backend_glium.rs | 4 + ezgui/src/backend_glow.rs | 168 ++++++--------- ezgui/src/backend_glow_native.rs | 90 ++++++++ ezgui/src/backend_glow_wasm.rs | 107 ++++++++++ ezgui/src/backend_wasm.rs | 342 ------------------------------- ezgui/src/event_ctx.rs | 2 +- ezgui/src/lib.rs | 11 +- ezgui/src/runner.rs | 2 +- 10 files changed, 271 insertions(+), 465 deletions(-) create mode 100644 ezgui/src/backend_glow_native.rs create mode 100644 ezgui/src/backend_glow_wasm.rs delete mode 100644 ezgui/src/backend_wasm.rs diff --git a/ezgui/Cargo.toml b/ezgui/Cargo.toml index 964f693f0d..9a30537342 100644 --- a/ezgui/Cargo.toml +++ b/ezgui/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Dustin Carlino "] edition = "2018" [features] -default = ["glium-backend"] +default = ["glow-backend"] glium-backend = ["glium", "glutin", "usvg/text"] glow-backend = ["glow", "glutin", "usvg/text"] wasm-backend = ["glow/stdweb", "instant/stdweb", "stdweb", "webgl_stdweb", "winit/stdweb"] diff --git a/ezgui/README.md b/ezgui/README.md index 7f1a4deb53..4fbacf885b 100644 --- a/ezgui/README.md +++ b/ezgui/README.md @@ -32,10 +32,10 @@ works in the browser using WebAssembly and Why OpenGL? My requirements are super simple; I don't need the power of Vulkan or other new stuff. I want something simple that runs everywhere. If you want to -make this work with WGPU or something else, it should be easy. The 3 backend -implementations ([glium](src/backend_glium.rs), -[glow on native](src/backend_glow.rs), [glow on wasm](src/backend_wasm.rs)) are -each about 300 lines. +make this work with WGPU or something else, it should be easy. The backends are +each about 300 lines — [Glium](src/backend_glium.rs) running on native OpenGL, +and [Glow](src/backend_glow.rs) running either [on +native](src/backend_glow_native.rs) or [on wasm](src/backend_glow_wasm.rs). ### 2D drawing diff --git a/ezgui/src/backend_glium.rs b/ezgui/src/backend_glium.rs index 6b78f13cb9..d4e7a21bea 100644 --- a/ezgui/src/backend_glium.rs +++ b/ezgui/src/backend_glium.rs @@ -298,4 +298,8 @@ impl PrerenderInnards { pub fn monitor_scale_factor(&self) -> f64 { self.display.gl_window().window().scale_factor() } + + pub fn draw_finished(&self, gfx_ctx_innards: GfxCtxInnards) { + gfx_ctx_innards.finish() + } } diff --git a/ezgui/src/backend_glow.rs b/ezgui/src/backend_glow.rs index cac1928d6d..48f5d6e678 100644 --- a/ezgui/src/backend_glow.rs +++ b/ezgui/src/backend_glow.rs @@ -4,90 +4,31 @@ use glow::HasContext; use std::cell::Cell; use std::rc::Rc; -pub fn setup(window_title: &str) -> (PrerenderInnards, winit::event_loop::EventLoop<()>) { - let event_loop = winit::event_loop::EventLoop::new(); - let window = winit::window::WindowBuilder::new() - .with_title(window_title) - .with_maximized(true); - // TODO Need the same fallback as backend_glium - // multisampling: 2 looks bad, 4 looks fine - let context = glutin::ContextBuilder::new() - .with_multisampling(4) - .with_depth_buffer(2) - .build_windowed(window, &event_loop) - .unwrap(); - let windowed_context = unsafe { context.make_current().unwrap() }; - let gl = - glow::Context::from_loader_function(|s| windowed_context.get_proc_address(s) as *const _); - let program = unsafe { gl.create_program().expect("Cannot create program") }; +#[cfg(feature = "glow-backend")] +pub use crate::backend_glow_native::setup; - unsafe { - let shaders = [ - (glow::VERTEX_SHADER, include_str!("shaders/vertex_140.glsl")), - ( - glow::FRAGMENT_SHADER, - include_str!("shaders/fragment_140.glsl"), - ), - ] - .iter() - .map(|(shader_type, source)| { - let shader = gl - .create_shader(*shader_type) - .expect("Cannot create shader"); - gl.shader_source(shader, source); - gl.compile_shader(shader); - if !gl.get_shader_compile_status(shader) { - panic!(gl.get_shader_info_log(shader)); - } - gl.attach_shader(program, shader); - shader - }) - .collect::>(); - gl.link_program(program); - if !gl.get_program_link_status(program) { - panic!(gl.get_program_info_log(program)); - } - for shader in shaders { - gl.detach_shader(program, shader); - gl.delete_shader(shader); - } - gl.use_program(Some(program)); - - gl.enable(glow::SCISSOR_TEST); - - gl.enable(glow::DEPTH_TEST); - gl.depth_func(glow::LEQUAL); - - gl.enable(glow::BLEND); - gl.blend_func_separate( - glow::SRC_ALPHA, - glow::ONE_MINUS_SRC_ALPHA, - glow::SRC_ALPHA, - glow::ONE_MINUS_SRC_ALPHA, - ); - } - - ( - PrerenderInnards { - gl: Rc::new(gl), - program, - windowed_context, - total_bytes_uploaded: Cell::new(0), - }, - event_loop, - ) -} +#[cfg(feature = "wasm-backend")] +pub use crate::backend_glow_wasm::setup; // Represents one frame that's gonna be drawn pub struct GfxCtxInnards<'a> { - gl: Rc, - windowed_context: &'a glutin::WindowedContext, + gl: &'a glow::Context, program: &'a ::Program, - current_clip: Option<[i32; 4]>, } impl<'a> GfxCtxInnards<'a> { + pub fn new( + gl: &'a glow::Context, + program: &'a ::Program, + ) -> Self { + GfxCtxInnards { + gl, + program, + current_clip: None, + } + } + pub fn clear(&mut self, color: Color) { unsafe { self.gl.clear_color(color.r, color.g, color.b, color.a); @@ -150,6 +91,7 @@ impl<'a> GfxCtxInnards<'a> { pub fn take_clip(&mut self) -> Option<[i32; 4]> { self.current_clip.take() } + pub fn restore_clip(&mut self, clip: Option<[i32; 4]>) { self.current_clip = clip; if let Some(c) = clip { @@ -158,10 +100,6 @@ impl<'a> GfxCtxInnards<'a> { } } } - - pub fn finish(self) { - self.windowed_context.swap_buffers().unwrap(); - } } // Something that's been sent to the GPU already. @@ -183,7 +121,7 @@ impl Drop for Drawable { } struct VertexArray { - id: u32, + id: ::VertexArray, was_destroyed: bool, } @@ -215,7 +153,7 @@ impl Drop for VertexArray { } struct Buffer { - id: u32, + id: ::Buffer, was_destroyed: bool, } @@ -244,9 +182,15 @@ impl Drop for Buffer { } } +#[cfg(feature = "wasm-backend")] +type WindowAdapter = crate::backend_glow_wasm::WindowAdapter; + +#[cfg(feature = "glow-backend")] +type WindowAdapter = crate::backend_glow_native::WindowAdapter; + pub struct PrerenderInnards { gl: Rc, - windowed_context: glutin::WindowedContext, + window_adapter: WindowAdapter, program: ::Program, // TODO Prerender doesn't know what things are temporary and permanent. Could make the API more @@ -255,6 +199,19 @@ pub struct PrerenderInnards { } impl PrerenderInnards { + pub fn new( + gl: glow::Context, + program: ::Program, + window_adapter: WindowAdapter, + ) -> PrerenderInnards { + PrerenderInnards { + gl: Rc::new(gl), + program, + window_adapter, + total_bytes_uploaded: Cell::new(0), + } + } + pub fn actually_upload(&self, permanent: bool, batch: GeomBatch) -> Drawable { let mut vertices: Vec<[f32; 6]> = Vec::new(); let mut indices: Vec = Vec::new(); @@ -346,56 +303,47 @@ impl PrerenderInnards { } } + fn window(&self) -> &winit::window::Window { + self.window_adapter.window() + } + pub fn request_redraw(&self) { - self.windowed_context.window().request_redraw(); + self.window().request_redraw(); } pub fn set_cursor_icon(&self, icon: winit::window::CursorIcon) { - self.windowed_context.window().set_cursor_icon(icon); + self.window().set_cursor_icon(icon); } pub fn draw_new_frame(&self) -> GfxCtxInnards { - GfxCtxInnards { - gl: self.gl.clone(), - windowed_context: &self.windowed_context, - program: &self.program, - current_clip: None, - } + GfxCtxInnards::new(&self.gl, &self.program) } pub fn window_resized(&self, new_size: ScreenDims, scale_factor: f64) { let physical_size = winit::dpi::LogicalSize::from(new_size).to_physical(scale_factor); - self.windowed_context.resize(physical_size); + self.window_adapter.window_resized(new_size, scale_factor); unsafe { - self.gl.viewport( - 0, - 0, - physical_size.width as i32, - physical_size.height as i32, - ); + self.gl + .viewport(0, 0, physical_size.width, physical_size.height); // I think it's safe to assume there's not a clip right now. - self.gl.scissor( - 0, - 0, - physical_size.width as i32, - physical_size.height as i32, - ); + self.gl + .scissor(0, 0, physical_size.width, physical_size.height); } } pub fn window_size(&self, scale_factor: f64) -> ScreenDims { - self.windowed_context - .window() - .inner_size() - .to_logical(scale_factor) - .into() + self.window().inner_size().to_logical(scale_factor).into() } pub fn set_window_icon(&self, icon: winit::window::Icon) { - self.windowed_context.window().set_window_icon(Some(icon)); + self.window().set_window_icon(Some(icon)); } pub fn monitor_scale_factor(&self) -> f64 { - self.windowed_context.window().scale_factor() + self.window().scale_factor() + } + + pub fn draw_finished(&self, gfc_ctx_innards: GfxCtxInnards) { + self.window_adapter.draw_finished(gfc_ctx_innards) } } diff --git a/ezgui/src/backend_glow_native.rs b/ezgui/src/backend_glow_native.rs new file mode 100644 index 0000000000..39a5114086 --- /dev/null +++ b/ezgui/src/backend_glow_native.rs @@ -0,0 +1,90 @@ +pub use crate::backend_glow::Drawable; +use crate::backend_glow::{GfxCtxInnards, PrerenderInnards}; +use crate::ScreenDims; +use glow::HasContext; + +pub fn setup(window_title: &str) -> (PrerenderInnards, winit::event_loop::EventLoop<()>) { + let event_loop = winit::event_loop::EventLoop::new(); + let window = winit::window::WindowBuilder::new() + .with_title(window_title) + .with_maximized(true); + // TODO Need the same fallback as backend_glium + // multisampling: 2 looks bad, 4 looks fine + let context = glutin::ContextBuilder::new() + .with_multisampling(4) + .with_depth_buffer(2) + .build_windowed(window, &event_loop) + .unwrap(); + let windowed_context = unsafe { context.make_current().unwrap() }; + let gl = + glow::Context::from_loader_function(|s| windowed_context.get_proc_address(s) as *const _); + let program = unsafe { gl.create_program().expect("Cannot create program") }; + + unsafe { + let shaders = [ + (glow::VERTEX_SHADER, include_str!("shaders/vertex_140.glsl")), + ( + glow::FRAGMENT_SHADER, + include_str!("shaders/fragment_140.glsl"), + ), + ] + .iter() + .map(|(shader_type, source)| { + let shader = gl + .create_shader(*shader_type) + .expect("Cannot create shader"); + gl.shader_source(shader, source); + gl.compile_shader(shader); + if !gl.get_shader_compile_status(shader) { + panic!(gl.get_shader_info_log(shader)); + } + gl.attach_shader(program, shader); + shader + }) + .collect::>(); + gl.link_program(program); + if !gl.get_program_link_status(program) { + panic!(gl.get_program_info_log(program)); + } + for shader in shaders { + gl.detach_shader(program, shader); + gl.delete_shader(shader); + } + gl.use_program(Some(program)); + + gl.enable(glow::SCISSOR_TEST); + + gl.enable(glow::DEPTH_TEST); + gl.depth_func(glow::LEQUAL); + + gl.enable(glow::BLEND); + gl.blend_func_separate( + glow::SRC_ALPHA, + glow::ONE_MINUS_SRC_ALPHA, + glow::SRC_ALPHA, + glow::ONE_MINUS_SRC_ALPHA, + ); + } + + ( + PrerenderInnards::new(gl, program, WindowAdapter(windowed_context)), + event_loop, + ) +} + +pub struct WindowAdapter(glutin::WindowedContext); + +impl WindowAdapter { + pub fn window(&self) -> &winit::window::Window { + &self.0.window() + } + + pub fn window_resized(&self, new_size: ScreenDims, scale_factor: f64) { + let physical_size = winit::dpi::LogicalSize::from(new_size).to_physical(scale_factor); + self.0.resize(physical_size); + } + + pub fn draw_finished(&self, _gfc_ctx_innards: GfxCtxInnards) { + self.0.swap_buffers().unwrap(); + } +} diff --git a/ezgui/src/backend_glow_wasm.rs b/ezgui/src/backend_glow_wasm.rs new file mode 100644 index 0000000000..6f867df9e0 --- /dev/null +++ b/ezgui/src/backend_glow_wasm.rs @@ -0,0 +1,107 @@ +pub use crate::backend_glow::Drawable; +use crate::backend_glow::{GfxCtxInnards, PrerenderInnards}; +use crate::ScreenDims; +use glow::HasContext; +use stdweb::traits::INode; +use webgl_stdweb::WebGL2RenderingContext; +use winit::platform::web::WindowExtStdweb; + +pub fn setup(window_title: &str) -> (PrerenderInnards, winit::event_loop::EventLoop<()>) { + stdweb::console!(log, "Setting up ezgui"); + + // This doesn't seem to work for the shader panics here, but later it does work. Huh. + std::panic::set_hook(Box::new(|info| { + stdweb::console!(log, "panicked: %s", format!("{}", info)); + })); + + let event_loop = winit::event_loop::EventLoop::new(); + let size = { + // TODO Not sure how to get scrollbar dims + let scrollbars = 30; + let win = stdweb::web::window(); + // `inner_width` corresponds to the browser's `self.innerWidth` function, which are in + // Logical, not Physical, pixels + winit::dpi::LogicalSize::new( + win.inner_width() - scrollbars, + win.inner_height() - scrollbars, + ) + }; + let window = winit::window::WindowBuilder::new() + .with_title(window_title) + .with_inner_size(size) + .build(&event_loop) + .unwrap(); + let canvas = window.canvas(); + let document = stdweb::web::document(); + let body: stdweb::web::Node = document.body().expect("Get HTML body").into(); + body.append_child(&canvas); + + let webgl2_context: WebGL2RenderingContext = canvas.get_context().unwrap(); + let gl = glow::Context::from_webgl2_context(webgl2_context); + + let program = unsafe { gl.create_program().expect("Cannot create program") }; + + unsafe { + let shaders = [ + (glow::VERTEX_SHADER, include_str!("shaders/vertex_300.glsl")), + ( + glow::FRAGMENT_SHADER, + include_str!("shaders/fragment_300.glsl"), + ), + ] + .iter() + .map(|(shader_type, source)| { + let shader = gl + .create_shader(*shader_type) + .expect("Cannot create shader"); + gl.shader_source(shader, source); + gl.compile_shader(shader); + if !gl.get_shader_compile_status(shader) { + stdweb::console!(log, "Shader error: %s", gl.get_shader_info_log(shader)); + panic!(gl.get_shader_info_log(shader)); + } + gl.attach_shader(program, shader); + shader + }) + .collect::>(); + gl.link_program(program); + if !gl.get_program_link_status(program) { + stdweb::console!(log, "Linking error: %s", gl.get_program_info_log(program)); + panic!(gl.get_program_info_log(program)); + } + for shader in shaders { + gl.detach_shader(program, shader); + gl.delete_shader(shader); + } + gl.use_program(Some(program)); + + gl.enable(glow::SCISSOR_TEST); + + gl.enable(glow::DEPTH_TEST); + gl.depth_func(glow::LEQUAL); + + gl.enable(glow::BLEND); + gl.blend_func_separate( + glow::SRC_ALPHA, + glow::ONE_MINUS_SRC_ALPHA, + glow::SRC_ALPHA, + glow::ONE_MINUS_SRC_ALPHA, + ); + } + + ( + PrerenderInnards::new(gl, program, WindowAdapter(window)), + event_loop, + ) +} + +pub struct WindowAdapter(winit::window::Window); + +impl WindowAdapter { + pub fn window(&self) -> &winit::window::Window { + &self.0 + } + + pub fn window_resized(&self, new_size: ScreenDims, scale_factor: f64) {} + pub fn draw_finished(&self, _gfc_ctx_innards: GfxCtxInnards) {} +} diff --git a/ezgui/src/backend_wasm.rs b/ezgui/src/backend_wasm.rs deleted file mode 100644 index c83fb48c9b..0000000000 --- a/ezgui/src/backend_wasm.rs +++ /dev/null @@ -1,342 +0,0 @@ -use crate::drawing::Uniforms; -use crate::{Canvas, Color, GeomBatch, ScreenDims, ScreenRectangle}; -use glow::HasContext; -use std::cell::Cell; -use stdweb::traits::INode; -use webgl_stdweb::WebGL2RenderingContext; -use winit::platform::web::WindowExtStdweb; - -pub fn setup(window_title: &str) -> (PrerenderInnards, winit::event_loop::EventLoop<()>) { - stdweb::console!(log, "Setting up ezgui"); - - // This doesn't seem to work for the shader panics here, but later it does work. Huh. - std::panic::set_hook(Box::new(|info| { - stdweb::console!(log, "panicked: %s", format!("{}", info)); - })); - - let event_loop = winit::event_loop::EventLoop::new(); - let size = { - // TODO Not sure how to get scrollbar dims - let scrollbars = 30; - let win = stdweb::web::window(); - // `inner_width` corresponds to the browser's `self.innerWidth` function, which are in - // Logical, not Physical, pixels - winit::dpi::LogicalSize::new( - win.inner_width() - scrollbars, - win.inner_height() - scrollbars, - ) - }; - let window = winit::window::WindowBuilder::new() - .with_title(window_title) - .with_inner_size(size) - .build(&event_loop) - .unwrap(); - let canvas = window.canvas(); - let document = stdweb::web::document(); - let body: stdweb::web::Node = document.body().expect("Get HTML body").into(); - body.append_child(&canvas); - - let webgl2_context: WebGL2RenderingContext = canvas.get_context().unwrap(); - let gl = glow::Context::from_webgl2_context(webgl2_context); - - let program = unsafe { gl.create_program().expect("Cannot create program") }; - - unsafe { - let shaders = [ - (glow::VERTEX_SHADER, include_str!("shaders/vertex_300.glsl")), - ( - glow::FRAGMENT_SHADER, - include_str!("shaders/fragment_300.glsl"), - ), - ] - .iter() - .map(|(shader_type, source)| { - let shader = gl - .create_shader(*shader_type) - .expect("Cannot create shader"); - gl.shader_source(shader, source); - gl.compile_shader(shader); - if !gl.get_shader_compile_status(shader) { - stdweb::console!(log, "Shader error: %s", gl.get_shader_info_log(shader)); - panic!(gl.get_shader_info_log(shader)); - } - gl.attach_shader(program, shader); - shader - }) - .collect::>(); - gl.link_program(program); - if !gl.get_program_link_status(program) { - stdweb::console!(log, "Linking error: %s", gl.get_program_info_log(program)); - panic!(gl.get_program_info_log(program)); - } - for shader in shaders { - gl.detach_shader(program, shader); - gl.delete_shader(shader); - } - gl.use_program(Some(program)); - - gl.enable(glow::SCISSOR_TEST); - - gl.enable(glow::DEPTH_TEST); - gl.depth_func(glow::LEQUAL); - - gl.enable(glow::BLEND); - gl.blend_func_separate( - glow::SRC_ALPHA, - glow::ONE_MINUS_SRC_ALPHA, - glow::SRC_ALPHA, - glow::ONE_MINUS_SRC_ALPHA, - ); - } - - ( - PrerenderInnards { - gl, - program, - window, - total_bytes_uploaded: Cell::new(0), - }, - event_loop, - ) -} - -// Represents one frame that's gonna be drawn -pub struct GfxCtxInnards<'a> { - gl: &'a glow::Context, - program: &'a ::Program, - - current_clip: Option<[i32; 4]>, -} - -impl<'a> GfxCtxInnards<'a> { - pub fn clear(&mut self, color: Color) { - unsafe { - self.gl.clear_color(color.r, color.g, color.b, color.a); - self.gl.clear(glow::COLOR_BUFFER_BIT); - - self.gl.clear_depth_f32(1.0); - self.gl.clear(glow::DEPTH_BUFFER_BIT); - } - } - - pub fn redraw(&mut self, obj: &Drawable, uniforms: &Uniforms, _: &PrerenderInnards) { - unsafe { - let transform_loc = self - .gl - .get_uniform_location(*self.program, "transform") - .unwrap(); - self.gl - .uniform_3_f32_slice(Some(&transform_loc), &uniforms.transform); - let window_loc = self - .gl - .get_uniform_location(*self.program, "window") - .unwrap(); - self.gl - .uniform_3_f32_slice(Some(&window_loc), &uniforms.window); - - self.gl.bind_vertex_array(Some(obj.vert_array)); - self.gl - .draw_elements(glow::TRIANGLES, obj.num_indices, glow::UNSIGNED_INT, 0); - self.gl.bind_vertex_array(None); - } - } - - pub fn enable_clipping(&mut self, rect: ScreenRectangle, scale_factor: f64, canvas: &Canvas) { - assert!(self.current_clip.is_none()); - // The scissor rectangle is in units of physical pixles, as opposed to logical pixels - let left = (rect.x1 * scale_factor) as i32; - // Y-inversion - let bottom = ((canvas.window_height - rect.y2) * scale_factor) as i32; - let width = ((rect.x2 - rect.x1) * scale_factor) as i32; - let height = ((rect.y2 - rect.y1) * scale_factor) as i32; - unsafe { - self.gl.scissor(left, bottom, width, height); - } - self.current_clip = Some([left, bottom, width, height]); - } - - pub fn disable_clipping(&mut self, scale_factor: f64, canvas: &Canvas) { - assert!(self.current_clip.is_some()); - self.current_clip = None; - unsafe { - self.gl.scissor( - 0, - 0, - (canvas.window_width * scale_factor) as i32, - (canvas.window_height * scale_factor) as i32, - ); - } - } - - pub fn take_clip(&mut self) -> Option<[i32; 4]> { - self.current_clip.take() - } - pub fn restore_clip(&mut self, clip: Option<[i32; 4]>) { - self.current_clip = clip; - if let Some(c) = clip { - unsafe { - self.gl.scissor(c[0], c[1], c[2], c[3]); - } - } - } - - pub fn finish(self) {} -} - -// Something that's been sent to the GPU already. -// TODO Implement Drop; have to keep a reference to gl. -pub struct Drawable { - _vert_buffer: glow::WebBufferKey, - vert_array: glow::WebVertexArrayKey, - _elem_buffer: glow::WebBufferKey, - num_indices: i32, -} - -pub struct PrerenderInnards { - gl: glow::Context, - window: winit::window::Window, - program: ::Program, - - // TODO Prerender doesn't know what things are temporary and permanent. Could make the API more - // detailed. - pub total_bytes_uploaded: Cell, -} - -impl PrerenderInnards { - pub fn actually_upload(&self, permanent: bool, batch: GeomBatch) -> Drawable { - let mut vertices: Vec<[f32; 6]> = Vec::new(); - let mut indices: Vec = Vec::new(); - - for (color, poly) in batch.consume() { - let idx_offset = vertices.len(); - let (pts, raw_indices) = poly.raw_for_rendering(); - for pt in pts { - let style = color.style(*pt); - vertices.push([ - pt.x() as f32, - pt.y() as f32, - style[0], - style[1], - style[2], - style[3], - ]); - } - for idx in raw_indices { - indices.push((idx_offset + *idx) as u32); - } - } - - let (vert_buffer, vert_array, elem_buffer) = unsafe { - let vert_array = self.gl.create_vertex_array().unwrap(); - let vert_buffer = self.gl.create_buffer().unwrap(); - let elem_buffer = self.gl.create_buffer().unwrap(); - - self.gl.bind_vertex_array(Some(vert_array)); - - self.gl.bind_buffer(glow::ARRAY_BUFFER, Some(vert_buffer)); - self.gl.buffer_data_u8_slice( - glow::ARRAY_BUFFER, - &vertices.align_to::().1, - // TODO Use permanent - glow::STATIC_DRAW, - ); - - self.gl - .bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(elem_buffer)); - self.gl.buffer_data_u8_slice( - glow::ELEMENT_ARRAY_BUFFER, - &indices.align_to::().1, - glow::STATIC_DRAW, - ); - - // TODO Can we have a single vertex array for everything, since there's an uber shader? - - let stride = 6 * std::mem::size_of::() as i32; - // position is vec2 - self.gl.enable_vertex_attrib_array(0); - self.gl - .vertex_attrib_pointer_f32(0, 2, glow::FLOAT, false, stride, 0); - // style is vec4 - self.gl.enable_vertex_attrib_array(1); - self.gl.vertex_attrib_pointer_f32( - 1, - 4, - glow::FLOAT, - false, - stride, - 2 * std::mem::size_of::() as i32, - ); - - // Safety? - self.gl.bind_vertex_array(None); - self.gl.bind_buffer(glow::ARRAY_BUFFER, None); - self.gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, None); - - (vert_buffer, vert_array, elem_buffer) - }; - let num_indices = indices.len() as i32; - - if permanent { - /*self.total_bytes_uploaded.set( - self.total_bytes_uploaded.get() - + vertex_buffer.get_size() - + index_buffer.get_size(), - );*/ - } - - Drawable { - _vert_buffer: vert_buffer, - vert_array, - _elem_buffer: elem_buffer, - num_indices, - } - } - - pub fn request_redraw(&self) { - self.window.request_redraw(); - } - - pub fn set_cursor_icon(&self, icon: winit::window::CursorIcon) { - self.window.set_cursor_icon(icon); - } - - pub fn draw_new_frame(&self) -> GfxCtxInnards { - GfxCtxInnards { - gl: &self.gl, - program: &self.program, - current_clip: None, - } - } - - pub fn window_resized(&self, new_size: ScreenDims, scale_factor: f64) { - let physical_size = - winit::dpi::LogicalSize::from(new_size).to_physical::(scale_factor); - unsafe { - self.gl.viewport( - 0, - 0, - physical_size.width as i32, - physical_size.height as i32, - ); - // I think it's safe to assume there's not a clip right now. - self.gl.scissor( - 0, - 0, - physical_size.width as i32, - physical_size.height as i32, - ); - } - } - - pub fn window_size(&self, scale_factor: f64) -> ScreenDims { - self.window.inner_size().to_logical(scale_factor).into() - } - - pub fn set_window_icon(&self, icon: winit::window::Icon) { - self.window.set_window_icon(Some(icon)); - } - - pub fn monitor_scale_factor(&self) -> f64 { - self.window.scale_factor() - } -} diff --git a/ezgui/src/event_ctx.rs b/ezgui/src/event_ctx.rs index 1250dc4074..63de0cde1d 100644 --- a/ezgui/src/event_ctx.rs +++ b/ezgui/src/event_ctx.rs @@ -184,7 +184,7 @@ impl<'a> LoadingScreen<'a> { &draw, ); - g.inner.finish(); + g.prerender.inner.draw_finished(g.inner); } } diff --git a/ezgui/src/lib.rs b/ezgui/src/lib.rs index 76af923133..01970a2c44 100644 --- a/ezgui/src/lib.rs +++ b/ezgui/src/lib.rs @@ -27,10 +27,12 @@ mod assets; #[cfg(feature = "glium-backend")] mod backend_glium; -#[cfg(feature = "glow-backend")] +#[cfg(any(feature = "glow-backend", feature = "wasm-backend"))] mod backend_glow; +#[cfg(feature = "glow-backend")] +mod backend_glow_native; #[cfg(feature = "wasm-backend")] -mod backend_wasm; +mod backend_glow_wasm; mod canvas; mod color; mod drawing; @@ -51,11 +53,8 @@ mod backend { #[cfg(feature = "glium-backend")] pub use crate::backend_glium::*; - #[cfg(feature = "glow-backend")] + #[cfg(any(feature = "glow-backend", feature = "wasm-backend"))] pub use crate::backend_glow::*; - - #[cfg(feature = "wasm-backend")] - pub use crate::backend_wasm::*; } pub use crate::backend::Drawable; diff --git a/ezgui/src/runner.rs b/ezgui/src/runner.rs index 3155ee3cc7..76b0781fed 100644 --- a/ezgui/src/runner.rs +++ b/ezgui/src/runner.rs @@ -146,7 +146,7 @@ impl State { ); } - g.inner.finish(); + prerender.inner.draw_finished(g.inner); naming_hint } }