From ebfbde152c780d8dae73bb532ae866b403d5d3ab Mon Sep 17 00:00:00 2001 From: sagudev <16504129+sagudev@users.noreply.github.com> Date: Wed, 25 Sep 2024 10:51:00 +0200 Subject: [PATCH] Use glow instead of sparkle Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> --- webxr-api/layer.rs | 1 + webxr/Cargo.toml | 2 +- webxr/gl_utils.rs | 210 +++++++++-------- webxr/glwindow/mod.rs | 409 +++++++++++++++++---------------- webxr/openxr/mod.rs | 3 +- webxr/surfman_layer_manager.rs | 55 +++-- 6 files changed, 363 insertions(+), 317 deletions(-) diff --git a/webxr-api/layer.rs b/webxr-api/layer.rs index acf3778c..b0a607f2 100644 --- a/webxr-api/layer.rs +++ b/webxr-api/layer.rs @@ -289,6 +289,7 @@ pub struct SubImages { #[cfg_attr(feature = "ipc", derive(Deserialize, Serialize))] pub struct SubImage { pub color_texture: u32, + // TODO: make this Option pub depth_stencil_texture: Option, pub texture_array_index: Option, pub viewport: Rect, diff --git a/webxr/Cargo.toml b/webxr/Cargo.toml index a86fe028..d2dd9632 100644 --- a/webxr/Cargo.toml +++ b/webxr/Cargo.toml @@ -33,7 +33,7 @@ euclid = "0.22" log = "0.4.6" openxr = { version = "0.19", optional = true } serde = { version = "1.0", optional = true } -sparkle = "0.1" +glow = "0.14" surfman = { version = "0.9", features = ["chains"] } [target.'cfg(target_os = "windows")'.dependencies] diff --git a/webxr/gl_utils.rs b/webxr/gl_utils.rs index 28e3dd2f..29b1c90f 100644 --- a/webxr/gl_utils.rs +++ b/webxr/gl_utils.rs @@ -3,18 +3,30 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use crate::SurfmanGL; -use sparkle::gl; -use sparkle::gl::GLuint; -use sparkle::gl::Gl; +use glow as gl; +use glow::Context as Gl; +use glow::HasContext; use std::collections::HashMap; +use std::num::NonZero; use surfman::Device as SurfmanDevice; use webxr_api::ContextId; use webxr_api::GLContexts; use webxr_api::LayerId; +pub(crate) fn framebuffer(framebuffer: u32) -> Option { + NonZero::new(framebuffer).map(gl::NativeFramebuffer) +} + // A utility to clear a color texture and optional depth/stencil texture pub(crate) struct GlClearer { - fbos: HashMap<(LayerId, GLuint, Option), GLuint>, + fbos: HashMap< + ( + LayerId, + Option, + Option, + ), + Option, + >, should_reverse_winding: bool, } @@ -31,10 +43,10 @@ impl GlClearer { &mut self, gl: &Gl, layer_id: LayerId, - color: GLuint, - color_target: GLuint, - depth_stencil: Option, - ) -> GLuint { + color: Option, + color_target: u32, + depth_stencil: Option, + ) -> Option { let should_reverse_winding = self.should_reverse_winding; *self .fbos @@ -43,41 +55,41 @@ impl GlClearer { // Save the current GL state let mut bound_fbos = [0, 0]; unsafe { - gl.get_integer_v(gl::DRAW_FRAMEBUFFER_BINDING, &mut bound_fbos[0..]); - gl.get_integer_v(gl::READ_FRAMEBUFFER_BINDING, &mut bound_fbos[1..]); - } + gl.get_parameter_i32_slice(gl::DRAW_FRAMEBUFFER_BINDING, &mut bound_fbos[0..]); + gl.get_parameter_i32_slice(gl::READ_FRAMEBUFFER_BINDING, &mut bound_fbos[1..]); - // Generate and set attachments of a new FBO - let fbo = gl.gen_framebuffers(1)[0]; + // Generate and set attachments of a new FBO + let fbo = gl.create_framebuffer().ok(); - gl.bind_framebuffer(gl::FRAMEBUFFER, fbo); - gl.framebuffer_texture_2d( - gl::FRAMEBUFFER, - gl::COLOR_ATTACHMENT0, - color_target, - color, - 0, - ); - gl.framebuffer_texture_2d( - gl::FRAMEBUFFER, - gl::DEPTH_STENCIL_ATTACHMENT, - gl::TEXTURE_2D, - depth_stencil.unwrap_or(0), - 0, - ); + gl.bind_framebuffer(gl::FRAMEBUFFER, fbo); + gl.framebuffer_texture_2d( + gl::FRAMEBUFFER, + gl::COLOR_ATTACHMENT0, + color_target, + color, + 0, + ); + gl.framebuffer_texture_2d( + gl::FRAMEBUFFER, + gl::DEPTH_STENCIL_ATTACHMENT, + gl::TEXTURE_2D, + depth_stencil, + 0, + ); - // Necessary if using an OpenXR runtime that does not support mutable FOV, - // as flipping the projection matrix necessitates reversing the winding order. - if should_reverse_winding { - gl.front_face(gl::CW); - } + // Necessary if using an OpenXR runtime that does not support mutable FOV, + // as flipping the projection matrix necessitates reversing the winding order. + if should_reverse_winding { + gl.front_face(gl::CW); + } - // Restore the GL state - gl.bind_framebuffer(gl::DRAW_FRAMEBUFFER, bound_fbos[0] as GLuint); - gl.bind_framebuffer(gl::READ_FRAMEBUFFER, bound_fbos[1] as GLuint); - debug_assert_eq!(gl.get_error(), gl::NO_ERROR); + // Restore the GL state + gl.bind_framebuffer(gl::DRAW_FRAMEBUFFER, framebuffer(bound_fbos[0] as _)); + gl.bind_framebuffer(gl::READ_FRAMEBUFFER, framebuffer(bound_fbos[1] as _)); + debug_assert_eq!(gl.get_error(), gl::NO_ERROR); - fbo + fbo + } }) } @@ -87,75 +99,75 @@ impl GlClearer { contexts: &mut dyn GLContexts, context_id: ContextId, layer_id: LayerId, - color: GLuint, - color_target: GLuint, - depth_stencil: Option, + color: Option, + color_target: u32, + depth_stencil: Option, ) { let gl = match contexts.bindings(device, context_id) { None => return, Some(gl) => gl, }; let fbo = self.fbo(gl, layer_id, color, color_target, depth_stencil); - - // Save the current GL state - let mut bound_fbos = [0, 0]; - let mut clear_color = [0., 0., 0., 0.]; - let mut clear_depth = [0.]; - let mut clear_stencil = [0]; - let mut color_mask = [0, 0, 0, 0]; - let mut depth_mask = [0]; - let mut stencil_mask = [0]; - let scissor_enabled = gl.is_enabled(gl::SCISSOR_TEST); - let rasterizer_enabled = gl.is_enabled(gl::RASTERIZER_DISCARD); unsafe { - gl.get_integer_v(gl::DRAW_FRAMEBUFFER_BINDING, &mut bound_fbos[0..]); - gl.get_integer_v(gl::READ_FRAMEBUFFER_BINDING, &mut bound_fbos[1..]); - gl.get_float_v(gl::COLOR_CLEAR_VALUE, &mut clear_color[..]); - gl.get_float_v(gl::DEPTH_CLEAR_VALUE, &mut clear_depth[..]); - gl.get_integer_v(gl::STENCIL_CLEAR_VALUE, &mut clear_stencil[..]); - gl.get_boolean_v(gl::DEPTH_WRITEMASK, &mut depth_mask[..]); - gl.get_integer_v(gl::STENCIL_WRITEMASK, &mut stencil_mask[..]); - gl.get_boolean_v(gl::COLOR_WRITEMASK, &mut color_mask[..]); - } + // Save the current GL state + let mut bound_fbos = [0, 0]; + let mut clear_color = [0., 0., 0., 0.]; + let mut clear_depth = [0.]; + let mut clear_stencil = [0]; + let mut color_mask = [0, 0, 0, 0]; + let mut depth_mask = [0]; + let mut stencil_mask = [0]; + let scissor_enabled = gl.is_enabled(gl::SCISSOR_TEST); + let rasterizer_enabled = gl.is_enabled(gl::RASTERIZER_DISCARD); - // Clear it - gl.bind_framebuffer(gl::FRAMEBUFFER, fbo); - gl.clear_color(0., 0., 0., 1.); - gl.clear_depth(1.); - gl.clear_stencil(0); - gl.disable(gl::SCISSOR_TEST); - gl.disable(gl::RASTERIZER_DISCARD); - gl.depth_mask(true); - gl.stencil_mask(0xFFFFFFFF); - gl.color_mask(true, true, true, true); - gl.clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT | gl::STENCIL_BUFFER_BIT); + gl.get_parameter_i32_slice(gl::DRAW_FRAMEBUFFER_BINDING, &mut bound_fbos[0..]); + gl.get_parameter_i32_slice(gl::READ_FRAMEBUFFER_BINDING, &mut bound_fbos[1..]); + gl.get_parameter_f32_slice(gl::COLOR_CLEAR_VALUE, &mut clear_color[..]); + gl.get_parameter_f32_slice(gl::DEPTH_CLEAR_VALUE, &mut clear_depth[..]); + gl.get_parameter_i32_slice(gl::STENCIL_CLEAR_VALUE, &mut clear_stencil[..]); + gl.get_parameter_i32_slice(gl::DEPTH_WRITEMASK, &mut depth_mask[..]); + gl.get_parameter_i32_slice(gl::STENCIL_WRITEMASK, &mut stencil_mask[..]); + gl.get_parameter_i32_slice(gl::COLOR_WRITEMASK, &mut color_mask[..]); - // Restore the GL state - gl.bind_framebuffer(gl::DRAW_FRAMEBUFFER, bound_fbos[0] as GLuint); - gl.bind_framebuffer(gl::READ_FRAMEBUFFER, bound_fbos[1] as GLuint); - gl.clear_color( - clear_color[0], - clear_color[1], - clear_color[2], - clear_color[3], - ); - gl.color_mask( - color_mask[0] != 0, - color_mask[1] != 0, - color_mask[2] != 0, - color_mask[3] != 0, - ); - gl.clear_depth(clear_depth[0] as f64); - gl.clear_stencil(clear_stencil[0]); - gl.depth_mask(depth_mask[0] != 0); - gl.stencil_mask(stencil_mask[0] as gl::GLuint); - if scissor_enabled { - gl.enable(gl::SCISSOR_TEST); - } - if rasterizer_enabled { - gl.enable(gl::RASTERIZER_DISCARD); + // Clear it + gl.bind_framebuffer(gl::FRAMEBUFFER, fbo); + gl.clear_color(0., 0., 0., 1.); + gl.clear_depth_f64(1.); + gl.clear_stencil(0); + gl.disable(gl::SCISSOR_TEST); + gl.disable(gl::RASTERIZER_DISCARD); + gl.depth_mask(true); + gl.stencil_mask(0xFFFFFFFF); + gl.color_mask(true, true, true, true); + gl.clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT | gl::STENCIL_BUFFER_BIT); + + // Restore the GL state + gl.bind_framebuffer(gl::DRAW_FRAMEBUFFER, framebuffer(bound_fbos[0] as _)); + gl.bind_framebuffer(gl::READ_FRAMEBUFFER, framebuffer(bound_fbos[1] as _)); + gl.clear_color( + clear_color[0], + clear_color[1], + clear_color[2], + clear_color[3], + ); + gl.color_mask( + color_mask[0] != 0, + color_mask[1] != 0, + color_mask[2] != 0, + color_mask[3] != 0, + ); + gl.clear_depth_f64(clear_depth[0] as f64); + gl.clear_stencil(clear_stencil[0]); + gl.depth_mask(depth_mask[0] != 0); + gl.stencil_mask(stencil_mask[0] as _); + if scissor_enabled { + gl.enable(gl::SCISSOR_TEST); + } + if rasterizer_enabled { + gl.enable(gl::RASTERIZER_DISCARD); + } + debug_assert_eq!(gl.get_error(), gl::NO_ERROR); } - debug_assert_eq!(gl.get_error(), gl::NO_ERROR); } pub(crate) fn destroy_layer( @@ -173,7 +185,9 @@ impl GlClearer { if layer_id != other_id { true } else { - gl.delete_framebuffers(&[fbo]); + if let Some(fbo) = fbo { + unsafe { gl.delete_framebuffer(fbo) }; + } false } }) diff --git a/webxr/glwindow/mod.rs b/webxr/glwindow/mod.rs index 28eb76b0..28aee37d 100644 --- a/webxr/glwindow/mod.rs +++ b/webxr/glwindow/mod.rs @@ -2,12 +2,15 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +use crate::gl_utils::framebuffer; use crate::{SurfmanGL, SurfmanLayerManager}; +use core::slice; use euclid::{ Angle, Point2D, Rect, RigidTransform3D, Rotation3D, Size2D, Transform3D, UnknownUnit, Vector3D, }; -use sparkle::gl::{self, GLuint, Gl}; +use glow::{self as gl, Context as Gl, HasContext}; use std::ffi::c_void; +use std::num::NonZeroU32; use std::rc::Rc; use surfman::chains::{PreserveBuffer, SwapChain, SwapChainAPI, SwapChains, SwapChainsAPI}; use surfman::{ @@ -130,7 +133,7 @@ pub struct GlWindowDevice { layer_manager: Option, target_swap_chain: Option>, swap_chains: SwapChains, - read_fbo: GLuint, + read_fbo: Option, events: EventBuffer, clip_planes: ClipPlanes, granted_features: Vec, @@ -199,7 +202,7 @@ impl DeviceAPI for GlWindowDevice { fn end_animation_frame(&mut self, layers: &[(ContextId, LayerId)]) { log::debug!("End animation frame for layers {:?}", layers); self.device.make_context_current(&self.context).unwrap(); - debug_assert_eq!(self.gl.get_error(), gl::NO_ERROR); + debug_assert_eq!(unsafe { self.gl.get_error() }, gl::NO_ERROR); let _ = self.layer_manager().unwrap().end_frame(layers); @@ -212,19 +215,21 @@ impl DeviceAPI for GlWindowDevice { .unwrap() .map(|info| info.framebuffer_object) .unwrap_or(0); - self.gl - .bind_framebuffer(gl::FRAMEBUFFER, framebuffer_object); - debug_assert_eq!( - ( - self.gl.get_error(), - self.gl.check_framebuffer_status(gl::FRAMEBUFFER) - ), - (gl::NO_ERROR, gl::FRAMEBUFFER_COMPLETE) - ); + unsafe { + self.gl + .bind_framebuffer(gl::FRAMEBUFFER, framebuffer(framebuffer_object)); + debug_assert_eq!( + ( + self.gl.get_error(), + self.gl.check_framebuffer_status(gl::FRAMEBUFFER) + ), + (gl::NO_ERROR, gl::FRAMEBUFFER_COMPLETE) + ); - self.gl.clear_color(0.0, 0.0, 0.0, 0.0); - self.gl.clear(gl::COLOR_BUFFER_BIT); - debug_assert_eq!(self.gl.get_error(), gl::NO_ERROR); + self.gl.clear_color(0.0, 0.0, 0.0, 0.0); + self.gl.clear(gl::COLOR_BUFFER_BIT); + debug_assert_eq!(self.gl.get_error(), gl::NO_ERROR); + } for &(_, layer_id) in layers { let swap_chain = match self.swap_chains.get(layer_id) { @@ -240,9 +245,10 @@ impl DeviceAPI for GlWindowDevice { .device .create_surface_texture(&mut self.context, surface) .unwrap(); - let texture_id = self.device.surface_texture_object(&surface_texture); + let raw_texture_id = self.device.surface_texture_object(&surface_texture); + let texture_id = NonZeroU32::new(raw_texture_id).map(gl::NativeTexture); let texture_target = self.device.surface_gl_texture_target(); - log::debug!("Presenting texture {}", texture_id); + log::debug!("Presenting texture {}", raw_texture_id); if let Some(ref shader) = self.shader { shader.draw_texture( @@ -255,7 +261,7 @@ impl DeviceAPI for GlWindowDevice { } else { self.blit_texture(texture_id, texture_target, texture_size, window_size); } - debug_assert_eq!(self.gl.get_error(), gl::NO_ERROR); + debug_assert_eq!(unsafe { self.gl.get_error() }, gl::NO_ERROR); let surface = self .device @@ -287,7 +293,7 @@ impl DeviceAPI for GlWindowDevice { } } - debug_assert_eq!(self.gl.get_error(), gl::NO_ERROR); + debug_assert_eq!(unsafe { self.gl.get_error() }, gl::NO_ERROR); } fn initial_inputs(&self) -> Vec { @@ -319,7 +325,11 @@ impl DeviceAPI for GlWindowDevice { impl Drop for GlWindowDevice { fn drop(&mut self) { - self.gl.delete_framebuffers(&[self.read_fbo]); + if let Some(read_fbo) = self.read_fbo { + unsafe { + self.gl.delete_framebuffer(read_fbo); + } + } let _ = self.device.destroy_context(&mut self.context); } } @@ -340,14 +350,16 @@ impl GlWindowDevice { let mut context = device.create_context(&context_descriptor, None).unwrap(); device.make_context_current(&context).unwrap(); - let gl = match device.gl_api() { - GLApi::GL => Gl::gl_fns(gl::ffi_gl::Gl::load_with(|symbol_name| { - device.get_proc_address(&context, symbol_name) - })), - GLApi::GLES => Gl::gles_fns(gl::ffi_gles::Gles2::load_with(|symbol_name| { - device.get_proc_address(&context, symbol_name) - })), - }; + let gl = Rc::new(unsafe { + match device.gl_api() { + GLApi::GL => Gl::from_loader_function(|symbol_name| { + device.get_proc_address(&context, symbol_name) + }), + GLApi::GLES => Gl::from_loader_function(|symbol_name| { + device.get_proc_address(&context, symbol_name) + }), + } + }); let target_swap_chain = match window.get_render_target(&mut device, &mut context) { GlWindowRenderTarget::NativeWidget(native_widget) => { @@ -366,31 +378,33 @@ impl GlWindowDevice { } }; - let read_fbo = gl.gen_framebuffers(1)[0]; - let framebuffer_object = device - .context_surface_info(&context) - .unwrap() - .map(|info| info.framebuffer_object) - .unwrap_or(0); - gl.bind_framebuffer(gl::FRAMEBUFFER, framebuffer_object); - debug_assert_eq!( - (gl.get_error(), gl.check_framebuffer_status(gl::FRAMEBUFFER)), - (gl::NO_ERROR, gl::FRAMEBUFFER_COMPLETE) - ); - - gl.enable(gl::BLEND); - gl.blend_func_separate( - gl::SRC_ALPHA, - gl::ONE_MINUS_SRC_ALPHA, - gl::ONE, - gl::ONE_MINUS_SRC_ALPHA, - ); + let read_fbo = unsafe { gl.create_framebuffer().ok() }; + unsafe { + let framebuffer_object = device + .context_surface_info(&context) + .unwrap() + .map(|info| info.framebuffer_object) + .unwrap_or(0); + gl.bind_framebuffer(gl::FRAMEBUFFER, framebuffer(framebuffer_object)); + debug_assert_eq!( + (gl.get_error(), gl.check_framebuffer_status(gl::FRAMEBUFFER)), + (gl::NO_ERROR, gl::FRAMEBUFFER_COMPLETE) + ); + + gl.enable(gl::BLEND); + gl.blend_func_separate( + gl::SRC_ALPHA, + gl::ONE_MINUS_SRC_ALPHA, + gl::ONE, + gl::ONE_MINUS_SRC_ALPHA, + ); + } let swap_chains = SwapChains::new(); let layer_manager = None; let shader = GlWindowShader::new(gl.clone(), window.get_mode()); - debug_assert_eq!(gl.get_error(), gl::NO_ERROR); + debug_assert_eq!(unsafe { gl.get_error() }, gl::NO_ERROR); Ok(GlWindowDevice { gl, @@ -411,32 +425,34 @@ impl GlWindowDevice { fn blit_texture( &self, - texture_id: GLuint, - texture_target: GLuint, + texture_id: Option, + texture_target: u32, texture_size: Size2D, window_size: Size2D, ) { - self.gl - .bind_framebuffer(gl::READ_FRAMEBUFFER, self.read_fbo); - self.gl.framebuffer_texture_2d( - gl::READ_FRAMEBUFFER, - gl::COLOR_ATTACHMENT0, - texture_target, - texture_id, - 0, - ); - self.gl.blit_framebuffer( - 0, - 0, - texture_size.width, - texture_size.height, - 0, - 0, - window_size.width, - window_size.height, - gl::COLOR_BUFFER_BIT, - gl::NEAREST, - ); + unsafe { + self.gl + .bind_framebuffer(gl::READ_FRAMEBUFFER, self.read_fbo); + self.gl.framebuffer_texture_2d( + gl::READ_FRAMEBUFFER, + gl::COLOR_ATTACHMENT0, + texture_target, + texture_id, + 0, + ); + self.gl.blit_framebuffer( + 0, + 0, + texture_size.width, + texture_size.height, + 0, + 0, + window_size.width, + window_size.height, + gl::COLOR_BUFFER_BIT, + gl::NEAREST, + ); + } } fn layer_manager(&mut self) -> Result<&mut LayerManager, Error> { @@ -584,16 +600,16 @@ impl GlWindowDevice { struct GlWindowShader { gl: Rc, - buffer: GLuint, - vao: GLuint, - program: GLuint, + buffer: Option, + vao: Option, + program: gl::NativeProgram, mode: GlWindowMode, } -const VERTEX_ATTRIBUTE: GLuint = 0; +const VERTEX_ATTRIBUTE: u32 = 0; const VERTICES: &[[f32; 2]; 4] = &[[-1.0, -1.0], [-1.0, 1.0], [1.0, -1.0], [1.0, 1.0]]; -const PASSTHROUGH_VERTEX_SHADER: &[u8] = b" +const PASSTHROUGH_VERTEX_SHADER: &str = " #version 330 core layout(location=0) in vec2 coord; out vec2 vTexCoord; @@ -603,7 +619,7 @@ const PASSTHROUGH_VERTEX_SHADER: &[u8] = b" } "; -const PASSTHROUGH_FRAGMENT_SHADER: &[u8] = b" +const PASSTHROUGH_FRAGMENT_SHADER: &str = " #version 330 core layout(location=0) out vec4 color; uniform sampler2D image; @@ -613,7 +629,7 @@ const PASSTHROUGH_FRAGMENT_SHADER: &[u8] = b" } "; -const ANAGLYPH_VERTEX_SHADER: &[u8] = b" +const ANAGLYPH_VERTEX_SHADER: &str = " #version 330 core layout(location=0) in vec2 coord; uniform float wasted; // What fraction of the image is wasted? @@ -627,7 +643,7 @@ const ANAGLYPH_VERTEX_SHADER: &[u8] = b" } "; -const ANAGLYPH_RED_CYAN_FRAGMENT_SHADER: &[u8] = b" +const ANAGLYPH_RED_CYAN_FRAGMENT_SHADER: &str = " #version 330 core layout(location=0) out vec4 color; uniform sampler2D image; @@ -643,7 +659,7 @@ const ANAGLYPH_RED_CYAN_FRAGMENT_SHADER: &[u8] = b" } "; -const SPHERICAL_VERTEX_SHADER: &[u8] = b" +const SPHERICAL_VERTEX_SHADER: &str = " #version 330 core layout(location=0) in vec2 coord; out vec2 lon_lat; @@ -654,7 +670,7 @@ const SPHERICAL_VERTEX_SHADER: &[u8] = b" } "; -const SPHERICAL_FRAGMENT_SHADER: &[u8] = b" +const SPHERICAL_FRAGMENT_SHADER: &str = " #version 330 core layout(location=0) out vec4 color; uniform sampler2D image; @@ -716,137 +732,140 @@ impl GlWindowShader { log::warn!("XR shaders may not render on MacOS."); } - // The four corners of the window in a VAO, set to attribute 0 - let buffer = gl.gen_buffers(1)[0]; - let vao = gl.gen_vertex_arrays(1)[0]; - gl.bind_buffer(gl::ARRAY_BUFFER, buffer); unsafe { - gl.buffer_data( - gl::ARRAY_BUFFER, - std::mem::size_of_val(VERTICES) as isize, - VERTICES as *const _ as *const c_void, - gl::STATIC_DRAW, - ) - }; - gl.bind_vertex_array(vao); - gl.vertex_attrib_pointer( - VERTEX_ATTRIBUTE, - VERTICES[0].len() as i32, - gl::FLOAT, - false, - 0, - 0, - ); - gl.enable_vertex_attrib_array(VERTEX_ATTRIBUTE); - debug_assert_eq!(gl.get_error(), gl::NO_ERROR); - - // The shader program - let program = gl.create_program(); - let vertex_shader = gl.create_shader(gl::VERTEX_SHADER); - let fragment_shader = gl.create_shader(gl::FRAGMENT_SHADER); - gl.shader_source(vertex_shader, &[vertex_source]); - gl.compile_shader(vertex_shader); - gl.attach_shader(program, vertex_shader); - gl.shader_source(fragment_shader, &[fragment_source]); - gl.compile_shader(fragment_shader); - gl.attach_shader(program, fragment_shader); - gl.link_program(program); - debug_assert_eq!(gl.get_error(), gl::NO_ERROR); - - // Check for errors - // TODO: something other than panic? - let mut status = [0]; - unsafe { gl.get_shader_iv(vertex_shader, gl::COMPILE_STATUS, &mut status) }; - assert_eq!( - status[0], - gl::TRUE as i32, - "Failed to compile vertex shader: {}", - gl.get_shader_info_log(vertex_shader) - ); - unsafe { gl.get_shader_iv(fragment_shader, gl::COMPILE_STATUS, &mut status) }; - assert_eq!( - status[0], - gl::TRUE as i32, - "Failed to compile fragment shader: {}", - gl.get_shader_info_log(fragment_shader) - ); - unsafe { gl.get_program_iv(program, gl::LINK_STATUS, &mut status) }; - assert_eq!( - status[0], - gl::TRUE as i32, - "Failed to link: {}", - gl.get_program_info_log(program) - ); - - // Clean up - gl.delete_shader(vertex_shader); - debug_assert_eq!(gl.get_error(), gl::NO_ERROR); - gl.delete_shader(fragment_shader); - debug_assert_eq!(gl.get_error(), gl::NO_ERROR); - - // And we're done - Some(GlWindowShader { - gl, - buffer, - vao, - program, - mode, - }) + // The four corners of the window in a VAO, set to attribute 0 + let buffer = gl.create_buffer().ok(); + let vao = gl.create_vertex_array().ok(); + gl.bind_buffer(gl::ARRAY_BUFFER, buffer); + + let data = + slice::from_raw_parts(VERTICES as *const _ as _, std::mem::size_of_val(VERTICES)); + gl.buffer_data_u8_slice(gl::ARRAY_BUFFER, data, gl::STATIC_DRAW); + + gl.bind_vertex_array(vao); + gl.vertex_attrib_pointer_f32( + VERTEX_ATTRIBUTE, + VERTICES[0].len() as i32, + gl::FLOAT, + false, + 0, + 0, + ); + gl.enable_vertex_attrib_array(VERTEX_ATTRIBUTE); + debug_assert_eq!(gl.get_error(), gl::NO_ERROR); + + // The shader program + let program = gl.create_program().unwrap(); + let vertex_shader = gl.create_shader(gl::VERTEX_SHADER).unwrap(); + let fragment_shader = gl.create_shader(gl::FRAGMENT_SHADER).unwrap(); + gl.shader_source(vertex_shader, vertex_source); + gl.compile_shader(vertex_shader); + gl.attach_shader(program, vertex_shader); + gl.shader_source(fragment_shader, fragment_source); + gl.compile_shader(fragment_shader); + gl.attach_shader(program, fragment_shader); + gl.link_program(program); + debug_assert_eq!(gl.get_error(), gl::NO_ERROR); + + // Check for errors + // TODO: something other than panic? + let status = gl.get_shader_compile_status(vertex_shader); + assert!( + status, + "Failed to compile vertex shader: {}", + gl.get_shader_info_log(vertex_shader) + ); + let status = gl.get_shader_compile_status(fragment_shader); + assert!( + status, + "Failed to compile fragment shader: {}", + gl.get_shader_info_log(fragment_shader) + ); + let status = gl.get_program_link_status(program); + assert!( + status, + "Failed to link: {}", + gl.get_program_info_log(program) + ); + + // Clean up + gl.delete_shader(vertex_shader); + debug_assert_eq!(gl.get_error(), gl::NO_ERROR); + gl.delete_shader(fragment_shader); + debug_assert_eq!(gl.get_error(), gl::NO_ERROR); + + // And we're done + Some(GlWindowShader { + gl, + buffer, + vao, + program, + mode, + }) + } } fn draw_texture( &self, - texture_id: GLuint, - texture_target: GLuint, + texture_id: Option, + texture_target: u32, texture_size: Size2D, viewport_size: Size2D, window_size: Size2D, ) { - self.gl.use_program(self.program); - - self.gl.enable_vertex_attrib_array(VERTEX_ATTRIBUTE); - self.gl.vertex_attrib_pointer( - VERTEX_ATTRIBUTE, - VERTICES[0].len() as i32, - gl::FLOAT, - false, - 0, - 0, - ); - - debug_assert_eq!(self.gl.get_error(), gl::NO_ERROR); + unsafe { + self.gl.use_program(Some(self.program)); + + self.gl.enable_vertex_attrib_array(VERTEX_ATTRIBUTE); + self.gl.vertex_attrib_pointer_f32( + VERTEX_ATTRIBUTE, + VERTICES[0].len() as i32, + gl::FLOAT, + false, + 0, + 0, + ); - self.gl.active_texture(gl::TEXTURE0); - self.gl.bind_texture(texture_target, texture_id); + debug_assert_eq!(self.gl.get_error(), gl::NO_ERROR); - match self.mode { - GlWindowMode::StereoRedCyan => { - let wasted = 1.0 - - (texture_size.width as f32 / viewport_size.width as f32) - .max(0.0) - .min(1.0); - let wasted_location = self.gl.get_uniform_location(self.program, "wasted"); - self.gl.uniform_1f(wasted_location, wasted); + self.gl.active_texture(gl::TEXTURE0); + self.gl.bind_texture(texture_target, texture_id); + + match self.mode { + GlWindowMode::StereoRedCyan => { + let wasted = 1.0 + - (texture_size.width as f32 / viewport_size.width as f32) + .max(0.0) + .min(1.0); + let wasted_location = self.gl.get_uniform_location(self.program, "wasted"); + self.gl.uniform_1_f32(wasted_location.as_ref(), wasted); + } + GlWindowMode::Blit + | GlWindowMode::Cubemap + | GlWindowMode::Spherical + | GlWindowMode::StereoLeftRight => {} } - GlWindowMode::Blit - | GlWindowMode::Cubemap - | GlWindowMode::Spherical - | GlWindowMode::StereoLeftRight => {} - } - self.gl - .viewport(0, 0, window_size.width, window_size.height); - self.gl - .draw_arrays(gl::TRIANGLE_STRIP, 0, VERTICES.len() as i32); - self.gl.disable_vertex_attrib_array(VERTEX_ATTRIBUTE); - debug_assert_eq!(self.gl.get_error(), gl::NO_ERROR); + self.gl + .viewport(0, 0, window_size.width, window_size.height); + self.gl + .draw_arrays(gl::TRIANGLE_STRIP, 0, VERTICES.len() as i32); + self.gl.disable_vertex_attrib_array(VERTEX_ATTRIBUTE); + debug_assert_eq!(self.gl.get_error(), gl::NO_ERROR); + } } } impl Drop for GlWindowShader { fn drop(&mut self) { - self.gl.delete_buffers(&[self.buffer]); - self.gl.delete_vertex_arrays(&[self.vao]); - self.gl.delete_program(self.program); + unsafe { + if let Some(buffer) = self.buffer { + self.gl.delete_buffer(buffer); + } + if let Some(vao) = self.vao { + self.gl.delete_vertex_array(vao); + } + self.gl.delete_program(self.program); + } } } diff --git a/webxr/openxr/mod.rs b/webxr/openxr/mod.rs index 18218f97..3aa51b17 100644 --- a/webxr/openxr/mod.rs +++ b/webxr/openxr/mod.rs @@ -9,6 +9,7 @@ use euclid::Rotation3D; use euclid::Size2D; use euclid::Transform3D; use euclid::Vector3D; +use glow::{self as gl, HasContext}; use interaction_profiles::{get_profiles_from_path, get_supported_interaction_profiles}; use log::{error, warn}; use openxr::sys::CompositionLayerPassthroughFB; @@ -20,8 +21,6 @@ use openxr::{ ReferenceSpaceType, SecondaryEndInfo, Session, Space, Swapchain, SwapchainCreateFlags, SwapchainCreateInfo, SwapchainUsageFlags, SystemId, Vector3f, Version, ViewConfigurationType, }; -use sparkle::gl; -use sparkle::gl::GLuint; use std::collections::HashMap; use std::mem; use std::ops::Deref; diff --git a/webxr/surfman_layer_manager.rs b/webxr/surfman_layer_manager.rs index b24029fa..f55a9412 100644 --- a/webxr/surfman_layer_manager.rs +++ b/webxr/surfman_layer_manager.rs @@ -6,8 +6,9 @@ use crate::gl_utils::GlClearer; use euclid::{Point2D, Rect, Size2D}; -use sparkle::gl::{self, GLuint, Gl}; +use glow::{self as gl, Context as Gl, HasContext}; use std::collections::HashMap; +use std::num::NonZeroU32; use surfman::chains::{PreserveBuffer, SwapChains, SwapChainsAPI}; use surfman::{Context as SurfmanContext, Device as SurfmanDevice, SurfaceAccess, SurfaceTexture}; use webxr_api::{ @@ -28,7 +29,7 @@ pub struct SurfmanLayerManager { layers: Vec<(ContextId, LayerId)>, swap_chains: SwapChains, surface_textures: HashMap, - depth_stencil_textures: HashMap, + depth_stencil_textures: HashMap>, viewports: Viewports, clearer: GlClearer, } @@ -74,19 +75,21 @@ impl LayerManagerAPI for SurfmanLayerManager { let gl = contexts .bindings(device, context_id) .ok_or(Error::NoMatchingDevice)?; - let depth_stencil_texture = gl.gen_textures(1)[0]; - gl.bind_texture(gl::TEXTURE_2D, depth_stencil_texture); - gl.tex_image_2d( - gl::TEXTURE_2D, - 0, - gl::DEPTH24_STENCIL8 as _, - size.width, - size.height, - 0, - gl::DEPTH_STENCIL, - gl::UNSIGNED_INT_24_8, - gl::TexImageSource::Pixels(None), - ); + let depth_stencil_texture = unsafe { gl.create_texture().ok() }; + unsafe { + gl.bind_texture(gl::TEXTURE_2D, depth_stencil_texture); + gl.tex_image_2d( + gl::TEXTURE_2D, + 0, + gl::DEPTH24_STENCIL8 as _, + size.width, + size.height, + 0, + gl::DEPTH_STENCIL, + gl::UNSIGNED_INT_24_8, + None, + ); + } self.depth_stencil_textures .insert(layer_id, depth_stencil_texture); } @@ -118,7 +121,11 @@ impl LayerManagerAPI for SurfmanLayerManager { self.surface_textures.remove(&layer_id); if let Some(depth_stencil_texture) = self.depth_stencil_textures.remove(&layer_id) { let gl = contexts.bindings(device, context_id).unwrap(); - gl.delete_textures(&[depth_stencil_texture]); + if let Some(depth_stencil_texture) = depth_stencil_texture { + unsafe { + gl.delete_texture(depth_stencil_texture); + } + } } } @@ -148,12 +155,16 @@ impl LayerManagerAPI for SurfmanLayerManager { .map_err(|_| Error::NoMatchingDevice)?; let color_texture = device.surface_texture_object(&surface_texture); let color_target = device.surface_gl_texture_target(); - let depth_stencil_texture = self.depth_stencil_textures.get(&layer_id).cloned(); + let depth_stencil_texture = self + .depth_stencil_textures + .get(&layer_id) + .cloned() + .flatten(); let texture_array_index = None; let origin = Point2D::new(0, 0); let sub_image = Some(SubImage { color_texture, - depth_stencil_texture, + depth_stencil_texture: depth_stencil_texture.map(|nt| nt.0.get()), texture_array_index, viewport: Rect::new(origin, surface_size), }); @@ -163,7 +174,7 @@ impl LayerManagerAPI for SurfmanLayerManager { .iter() .map(|&viewport| SubImage { color_texture, - depth_stencil_texture, + depth_stencil_texture: depth_stencil_texture.map(|nt| nt.0.get()), texture_array_index, viewport, }) @@ -174,7 +185,7 @@ impl LayerManagerAPI for SurfmanLayerManager { contexts, context_id, layer_id, - color_texture, + NonZeroU32::new(color_texture).map(gl::NativeTexture), color_target, depth_stencil_texture, ); @@ -197,7 +208,9 @@ impl LayerManagerAPI for SurfmanLayerManager { let gl = contexts .bindings(device, context_id) .ok_or(Error::NoMatchingDevice)?; - gl.flush(); + unsafe { + gl.flush(); + } let context = contexts .context(device, context_id) .ok_or(Error::NoMatchingDevice)?;