From e78ea1b24e1de57f24fc761186d8e9d9e43d660a Mon Sep 17 00:00:00 2001 From: Samson <16504129+sagudev@users.noreply.github.com> Date: Tue, 14 Jan 2025 12:40:31 +0100 Subject: [PATCH] Use glow instead of gl_generator for GL/GLES bindings (#321) Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> --- Cargo.toml | 4 +- .../SurfmanInstrumentedTest.java | 6 +- android-example/rust/src/lib.rs | 4 +- build.rs | 11 - examples/common/mod.rs | 3 +- examples/offscreen.rs | 9 +- examples/threads.rs | 31 +- src/chains.rs | 13 +- src/context.rs | 22 +- src/device.rs | 6 +- src/gl_utils.rs | 35 +- src/info.rs | 31 +- src/lib.rs | 10 +- src/macros.rs | 9 +- src/platform/egl/context.rs | 26 +- src/platform/egl/surface/android_surface.rs | 198 ++++++----- src/platform/egl/surface/mod.rs | 4 +- src/platform/egl/surface/ohos_surface.rs | 177 +++++----- src/platform/generic/egl/context.rs | 14 +- src/platform/generic/egl/surface.rs | 108 +++--- src/platform/generic/multi/device.rs | 9 +- src/platform/generic/multi/surface.rs | 9 +- src/platform/macos/cgl/context.rs | 49 +-- src/platform/macos/cgl/surface.rs | 309 +++++++++--------- src/platform/unix/generic/context.rs | 38 +-- src/platform/unix/generic/surface.rs | 45 ++- src/platform/unix/wayland/context.rs | 47 ++- src/platform/unix/wayland/surface.rs | 53 ++- src/platform/unix/x11/context.rs | 47 ++- src/platform/unix/x11/surface.rs | 43 ++- src/platform/windows/angle/context.rs | 33 +- src/platform/windows/angle/surface.rs | 92 +++--- src/platform/windows/wgl/context.rs | 36 +- src/platform/windows/wgl/surface.rs | 80 +++-- src/renderbuffers.rs | 72 ++-- src/surface.rs | 3 +- src/tests.rs | 197 ++++++----- 37 files changed, 939 insertions(+), 944 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a47a35e1..6d2239ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ gl_generator = "0.14" cfg_aliases = "0.2.1" [features] -chains = ["fnv", "glow"] +chains = ["fnv"] default = ["sm-raw-window-handle-06"] sm-angle = [] sm-angle-builtin = ["mozangle"] @@ -37,7 +37,7 @@ euclid = "0.22" fnv = { version = "1.0", optional = true } libc = "0.2" log = "0.4" -glow = { version = "0.16", optional = true } +glow = "0.16" osmesa-sys = { version = "0.1", optional = true } rwh_05 = { package = "raw-window-handle", version = "0.5.2", features = ["std"], optional = true } rwh_06 = { package = "raw-window-handle", version = "0.6.2", features = ["std"], optional = true } diff --git a/android-example/app/src/androidTest/java/org/mozilla/surfmanthreadsexample/SurfmanInstrumentedTest.java b/android-example/app/src/androidTest/java/org/mozilla/surfmanthreadsexample/SurfmanInstrumentedTest.java index 455a73ff..d175ca15 100644 --- a/android-example/app/src/androidTest/java/org/mozilla/surfmanthreadsexample/SurfmanInstrumentedTest.java +++ b/android-example/app/src/androidTest/java/org/mozilla/surfmanthreadsexample/SurfmanInstrumentedTest.java @@ -23,7 +23,7 @@ public class SurfmanInstrumentedTest { private static native void testDeviceCreation(); private static native void testGenericSurfaceCreation(); private static native void testGL(); - private static native void testNewlyCreatedContextsAreNotCurrent(); + private static native void testNewlyCreatedContextsAreCurrent(); private static native void testSurfaceTextureBlitFramebuffer(); private static native void testSurfaceTextureRightSideUp(); @@ -75,8 +75,8 @@ public void gl() { } @Test - public void newlyCreatedContextsAreNotCurrent() { - testNewlyCreatedContextsAreNotCurrent(); + public void newlyCreatedContextsAreCurrent() { + testNewlyCreatedContextsAreCurrent(); } @Test diff --git a/android-example/rust/src/lib.rs b/android-example/rust/src/lib.rs index 1517b22a..3d9ed5af 100644 --- a/android-example/rust/src/lib.rs +++ b/android-example/rust/src/lib.rs @@ -128,11 +128,11 @@ pub unsafe extern "system" fn Java_org_mozilla_surfmanthreadsexample_SurfmanInst } #[no_mangle] -pub unsafe extern "system" fn Java_org_mozilla_surfmanthreadsexample_SurfmanInstrumentedTest_testNewlyCreatedContextsAreNotCurrent( +pub unsafe extern "system" fn Java_org_mozilla_surfmanthreadsexample_SurfmanInstrumentedTest_testNewlyCreatedContextsAreCurrent( _env: JNIEnv, _class: JClass, ) { - tests::test_newly_created_contexts_are_not_current(); + tests::test_newly_created_contexts_are_current(); } #[no_mangle] diff --git a/build.rs b/build.rs index b3504cb7..8e0c7810 100644 --- a/build.rs +++ b/build.rs @@ -50,15 +50,4 @@ fn main() { let registry = Registry::new(Api::Egl, (1, 5), Profile::Core, Fallbacks::All, []); registry.write_bindings(StructGenerator, &mut file).unwrap(); } - - // Generate GL bindings. - if target_os == "android" || target_env == "ohos" { - let mut file = File::create(dest.join("gl_bindings.rs")).unwrap(); - let registry = Registry::new(Api::Gles2, (3, 0), Profile::Core, Fallbacks::All, []); - registry.write_bindings(StructGenerator, &mut file).unwrap(); - } else { - let mut file = File::create(dest.join("gl_bindings.rs")).unwrap(); - let registry = Registry::new(Api::Gl, (3, 3), Profile::Core, Fallbacks::All, []); - registry.write_bindings(StructGenerator, &mut file).unwrap(); - } } diff --git a/examples/common/mod.rs b/examples/common/mod.rs index 9417cd7a..cef863a7 100644 --- a/examples/common/mod.rs +++ b/examples/common/mod.rs @@ -3,10 +3,9 @@ // OpenGL convenience wrappers used in the examples. use gl; -use gl::types::{GLchar, GLenum, GLint, GLuint}; +use gl::types::{GLenum, GLint, GLuint}; use std::fs::File; use std::io::Read; -use std::os::raw::c_void; use std::ptr; use surfman::GLApi; diff --git a/examples/offscreen.rs b/examples/offscreen.rs index 4eeeb42f..ba4799a9 100644 --- a/examples/offscreen.rs +++ b/examples/offscreen.rs @@ -129,7 +129,10 @@ fn main() { unsafe { let surface_info = device.context_surface_info(&context).unwrap().unwrap(); - gl::BindFramebuffer(gl::FRAMEBUFFER, surface_info.framebuffer_object); + gl::BindFramebuffer( + gl::FRAMEBUFFER, + surface_info.framebuffer_object.map_or(0, |fbo| fbo.0.get()), + ); gl::Viewport(0, 0, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT); ck(); gl::ClearColor(0.0, 0.0, 0.0, 1.0); @@ -200,7 +203,7 @@ impl TriVertexArray { gl::FLOAT, gl::FALSE, 12, - 0 as *const GLvoid, + 0 as _, ); ck(); gl::VertexAttribPointer( @@ -209,7 +212,7 @@ impl TriVertexArray { gl::UNSIGNED_BYTE, gl::TRUE, 12, - 8 as *const GLvoid, + 8 as _, ); ck(); gl::EnableVertexAttribArray(tri_program.position_attribute as GLuint); diff --git a/examples/threads.rs b/examples/threads.rs index 7d049795..2e573691 100644 --- a/examples/threads.rs +++ b/examples/threads.rs @@ -285,12 +285,17 @@ impl App { unsafe { self.device.make_context_current(&self.context).unwrap(); - let framebuffer_object = match self.device.context_surface_info(&self.context) { - Ok(Some(surface_info)) => surface_info.framebuffer_object, - _ => 0, - }; - - gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer_object); + let framebuffer_object = self + .device + .context_surface_info(&self.context) + .ok() + .flatten() + .and_then(|surface_info| surface_info.framebuffer_object); + + gl::BindFramebuffer( + gl::FRAMEBUFFER, + framebuffer_object.map_or(0, |fbo| fbo.0.get()), + ); gl::Viewport(0, 0, self.window_size.width, self.window_size.height); gl::ClearColor(0.0, 0.0, 1.0, 1.0); @@ -400,7 +405,8 @@ impl App { gl::BindTexture( self.device.surface_gl_texture_target(), self.device - .surface_texture_object(self.texture.as_ref().unwrap()), + .surface_texture_object(self.texture.as_ref().unwrap()) + .map_or(0, |tex| tex.0.get()), ); gl::Uniform1i(self.blit_vertex_array.blit_program.source_uniform, 0); ck(); @@ -498,7 +504,10 @@ fn worker_thread( .unwrap() .framebuffer_object; - gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer_object); + gl::BindFramebuffer( + gl::FRAMEBUFFER, + framebuffer_object.map_or(0, |fbo| fbo.0.get()), + ); gl::Viewport(0, 0, size.width, size.height); gl::ClearColor(0.0, 0.0, 0.0, 1.0); @@ -650,7 +659,7 @@ impl BlitVertexArray { gl::UNSIGNED_BYTE, gl::FALSE, 2, - 0 as *const GLvoid, + 0 as _, ); ck(); gl::EnableVertexAttribArray(blit_program.position_attribute as GLuint); @@ -695,7 +704,7 @@ impl GridVertexArray { gl::UNSIGNED_BYTE, gl::FALSE, 2, - 0 as *const GLvoid, + 0 as _, ); ck(); gl::EnableVertexAttribArray(grid_program.position_attribute as GLuint); @@ -740,7 +749,7 @@ impl CheckVertexArray { gl::UNSIGNED_BYTE, gl::FALSE, 2, - 0 as *const GLvoid, + 0 as _, ); ck(); gl::EnableVertexAttribArray(check_program.position_attribute as GLuint); diff --git a/src/chains.rs b/src/chains.rs index 5a8309ff..fbebdae5 100644 --- a/src/chains.rs +++ b/src/chains.rs @@ -34,15 +34,8 @@ use std::collections::hash_map::Entry; use std::fmt::Debug; use std::hash::Hash; use std::mem; -use std::num::NonZero; use std::sync::{Arc, Mutex, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard}; -impl crate::SurfaceInfo { - fn framebuffer(&self) -> Option { - NonZero::new(self.framebuffer_object).map(gl::NativeFramebuffer) - } -} - // The data stored for each swap chain. struct SwapChainData { // The size of the back buffer @@ -201,9 +194,9 @@ impl SwapChainData { if let PreserveBuffer::Yes(gl) = preserve_buffer { let front_info = device.surface_info(&new_front_buffer); unsafe { - gl.bind_framebuffer(gl::READ_FRAMEBUFFER, front_info.framebuffer()); + gl.bind_framebuffer(gl::READ_FRAMEBUFFER, front_info.framebuffer_object); debug_assert_eq!(gl.get_error(), gl::NO_ERROR); - gl.bind_framebuffer(gl::DRAW_FRAMEBUFFER, back_info.framebuffer()); + gl.bind_framebuffer(gl::DRAW_FRAMEBUFFER, back_info.framebuffer_object); debug_assert_eq!(gl.get_error(), gl::NO_ERROR); gl.blit_framebuffer( 0, @@ -398,7 +391,7 @@ impl SwapChainData { .context_surface_info(context) .unwrap() .unwrap() - .framebuffer(); + .framebuffer_object; unsafe { gl.bind_framebuffer(gl::FRAMEBUFFER, fbo); gl.clear_color(color[0], color[1], color[2], color[3]); diff --git a/src/context.rs b/src/context.rs index 55e7e8b2..2b15cd22 100644 --- a/src/context.rs +++ b/src/context.rs @@ -5,7 +5,6 @@ #![allow(unused_imports)] use crate::gl; -use crate::gl::types::GLuint; use crate::info::GLVersion; use crate::Gl; @@ -79,29 +78,18 @@ pub(crate) fn current_context_uses_compatibility_profile(_gl: &Gl) -> bool { #[cfg(not(any(target_os = "android", target_env = "ohos")))] #[allow(dead_code)] pub(crate) fn current_context_uses_compatibility_profile(gl: &Gl) -> bool { + use glow::HasContext; + unsafe { // First, try `GL_CONTEXT_PROFILE_MASK`. - let mut context_profile_mask = 0; - gl.GetIntegerv(gl::CONTEXT_PROFILE_MASK, &mut context_profile_mask); - if gl.GetError() == gl::NO_ERROR + let context_profile_mask = gl.get_parameter_i32(gl::CONTEXT_PROFILE_MASK); + if gl.get_error() == gl::NO_ERROR && (context_profile_mask & gl::CONTEXT_COMPATIBILITY_PROFILE_BIT as i32) != 0 { return true; } // Second, look for the `GL_ARB_compatibility` extension. - let mut num_extensions = 0; - gl.GetIntegerv(gl::NUM_EXTENSIONS, &mut num_extensions); - if gl.GetError() == gl::NO_ERROR { - for extension_index in 0..(num_extensions as GLuint) { - let extension = gl.GetStringi(gl::EXTENSIONS, extension_index) as *const c_char; - let extension = CStr::from_ptr(extension); - if extension.to_str() == Ok("GL_ARB_compatibility") { - return true; - } - } - } - - false + gl.supported_extensions().contains("GL_ARB_compatibility") } } diff --git a/src/device.rs b/src/device.rs index a684e680..99443cb7 100644 --- a/src/device.rs +++ b/src/device.rs @@ -3,9 +3,9 @@ //! The abstract interface that all devices conform to. use super::connection::Connection as ConnectionInterface; -use crate::gl::types::{GLenum, GLuint}; use crate::{ContextAttributes, ContextID, Error, GLApi, SurfaceAccess, SurfaceInfo, SurfaceType}; use euclid::default::Size2D; +use glow::Texture; use std::os::raw::c_void; @@ -200,7 +200,7 @@ where /// Returns the OpenGL texture target needed to read from this surface texture. /// /// This will be `GL_TEXTURE_2D` or `GL_TEXTURE_RECTANGLE`, depending on platform. - fn surface_gl_texture_target(&self) -> GLenum; + fn surface_gl_texture_target(&self) -> u32; /// Displays the contents of a widget surface on screen. /// @@ -234,5 +234,5 @@ where /// Returns the OpenGL texture object containing the contents of this surface. /// /// It is only legal to read from, not write to, this texture object. - fn surface_texture_object(&self, surface_texture: &Self::SurfaceTexture) -> GLuint; + fn surface_texture_object(&self, surface_texture: &Self::SurfaceTexture) -> Option; } diff --git a/src/gl_utils.rs b/src/gl_utils.rs index 0d1b2448..ab8d658d 100644 --- a/src/gl_utils.rs +++ b/src/gl_utils.rs @@ -2,21 +2,21 @@ // //! Various OpenGL utilities used by the different backends. +use glow::{HasContext, NativeFramebuffer}; + use crate::gl; -use crate::gl::types::{GLenum, GLint, GLuint}; use crate::Gl; #[allow(dead_code)] pub(crate) fn create_and_bind_framebuffer( gl: &Gl, - texture_target: GLenum, - texture_object: GLuint, -) -> GLuint { + texture_target: u32, + texture_object: Option, +) -> NativeFramebuffer { unsafe { - let mut framebuffer_object = 0; - gl.GenFramebuffers(1, &mut framebuffer_object); - gl.BindFramebuffer(gl::FRAMEBUFFER, framebuffer_object); - gl.FramebufferTexture2D( + let framebuffer_object = gl.create_framebuffer().unwrap(); + gl.bind_framebuffer(gl::FRAMEBUFFER, Some(framebuffer_object)); + gl.framebuffer_texture_2d( gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0, texture_target, @@ -27,25 +27,24 @@ pub(crate) fn create_and_bind_framebuffer( } } -pub(crate) fn unbind_framebuffer_if_necessary(gl: &Gl, framebuffer_object: GLuint) { +pub(crate) fn unbind_framebuffer_if_necessary(gl: &Gl, framebuffer_object: NativeFramebuffer) { unsafe { // Unbind the framebuffer if it's bound. - let (mut current_draw_framebuffer, mut current_read_framebuffer) = (0, 0); - gl.GetIntegerv(gl::DRAW_FRAMEBUFFER_BINDING, &mut current_draw_framebuffer); - gl.GetIntegerv(gl::READ_FRAMEBUFFER_BINDING, &mut current_read_framebuffer); - if current_draw_framebuffer == framebuffer_object as GLint { - gl.BindFramebuffer(gl::DRAW_FRAMEBUFFER, 0); + let current_draw_framebuffer = gl.get_parameter_framebuffer(gl::DRAW_FRAMEBUFFER_BINDING); + let current_read_framebuffer = gl.get_parameter_framebuffer(gl::READ_FRAMEBUFFER_BINDING); + if current_draw_framebuffer == Some(framebuffer_object) { + gl.bind_framebuffer(gl::DRAW_FRAMEBUFFER, None); } - if current_read_framebuffer == framebuffer_object as GLint { - gl.BindFramebuffer(gl::READ_FRAMEBUFFER, 0); + if current_read_framebuffer == Some(framebuffer_object) { + gl.bind_framebuffer(gl::READ_FRAMEBUFFER, None); } } } #[allow(dead_code)] -pub(crate) fn destroy_framebuffer(gl: &Gl, framebuffer_object: GLuint) { +pub(crate) fn destroy_framebuffer(gl: &Gl, framebuffer_object: NativeFramebuffer) { unbind_framebuffer_if_necessary(gl, framebuffer_object); unsafe { - gl.DeleteFramebuffers(1, &framebuffer_object); + gl.delete_framebuffer(framebuffer_object); } } diff --git a/src/info.rs b/src/info.rs index 679df63c..3e12bb22 100644 --- a/src/info.rs +++ b/src/info.rs @@ -2,11 +2,8 @@ // //! OpenGL information. -use crate::gl; use crate::Gl; - -use std::ffi::CStr; -use std::os::raw::c_char; +use glow::HasContext; /// The API (OpenGL or OpenGL ES). #[derive(Clone, Copy, Debug, PartialEq)] @@ -38,28 +35,10 @@ impl GLVersion { #[allow(dead_code)] pub(crate) fn current(gl: &Gl) -> GLVersion { - unsafe { - let version_string = gl.GetString(gl::VERSION) as *const c_char; - let version_string = CStr::from_ptr(version_string) - .to_string_lossy() - .trim_start_matches("OpenGL ES") - .trim_start() - .to_owned(); - let mut version_string_iter = version_string.split(|c| c == '.' || c == ' '); - let major_version: u8 = version_string_iter - .next() - .expect("Where's the major GL version?") - .parse() - .expect("Couldn't parse the major GL version!"); - let minor_version: u8 = version_string_iter - .next() - .expect("Where's the minor GL version?") - .parse() - .expect("Couldn't parse the minor GL version!"); - GLVersion { - major: major_version, - minor: minor_version, - } + let version = gl.version(); + Self { + major: version.major as u8, + minor: version.minor as u8, } } } diff --git a/src/lib.rs b/src/lib.rs index 93a6d682..b27aef90 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -54,19 +54,11 @@ pub use crate::surface::{SurfaceAccess, SurfaceID, SurfaceInfo, SurfaceType, Sys pub mod macros; pub(crate) use macros::implement_interfaces; -#[cfg(not(any(target_os = "android", target_env = "ohos")))] -pub(crate) use crate::gl::Gl; -#[cfg(any(target_os = "android", target_env = "ohos"))] -pub(crate) use crate::gl::Gles2 as Gl; +pub(crate) use glow::{self as gl, Context as Gl}; mod gl_utils; mod renderbuffers; -#[allow(clippy::all)] -mod gl { - include!(concat!(env!("OUT_DIR"), "/gl_bindings.rs")); -} - #[cfg(any( target_os = "android", target_env = "ohos", diff --git a/src/macros.rs b/src/macros.rs index 36dbbf83..d89040f3 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -41,10 +41,10 @@ macro_rules! implement_interfaces { use super::device::{Adapter, Device, NativeDevice}; use super::surface::{NativeWidget, Surface, SurfaceTexture}; use euclid::default::Size2D; + use glow::Texture; use std::os::raw::c_void; use $crate::connection::Connection as ConnectionInterface; use $crate::device::Device as DeviceInterface; - use $crate::gl::types::{GLenum, GLuint}; use $crate::info::GLApi; use $crate::Error; use $crate::{ContextAttributes, ContextID, SurfaceAccess, SurfaceInfo, SurfaceType}; @@ -318,7 +318,7 @@ macro_rules! implement_interfaces { } #[inline] - fn surface_gl_texture_target(&self) -> GLenum { + fn surface_gl_texture_target(&self) -> u32 { Device::surface_gl_texture_target(self) } @@ -347,7 +347,10 @@ macro_rules! implement_interfaces { } #[inline] - fn surface_texture_object(&self, surface_texture: &Self::SurfaceTexture) -> GLuint { + fn surface_texture_object( + &self, + surface_texture: &Self::SurfaceTexture, + ) -> Option { Device::surface_texture_object(self, surface_texture) } } diff --git a/src/platform/egl/context.rs b/src/platform/egl/context.rs index 2fe737bf..400c7f94 100644 --- a/src/platform/egl/context.rs +++ b/src/platform/egl/context.rs @@ -2,6 +2,8 @@ // //! OpenGL rendering contexts. +use glow::HasContext; + use super::device::Device; use super::surface::{Surface, SurfaceObjects}; use crate::context::{ContextID, CREATE_CONTEXT_MUTEX}; @@ -20,11 +22,6 @@ use std::thread; pub use crate::platform::generic::egl::context::{ContextDescriptor, NativeContext}; -thread_local! { - #[doc(hidden)] - pub static GL_FUNCTIONS: Gl = Gl::load_with(context::get_proc_address); -} - /// Represents an OpenGL rendering context. /// /// A context allows you to issue rendering commands to a surface. When initially created, a @@ -45,6 +42,7 @@ pub struct Context { pub(crate) egl_context: EGLContext, pub(crate) id: ContextID, pub(crate) pbuffer: EGLSurface, + pub(crate) gl: Gl, framebuffer: Framebuffer, context_is_owned: bool, } @@ -116,6 +114,7 @@ impl Device { pbuffer, framebuffer: Framebuffer::None, context_is_owned: true, + gl: Gl::from_loader_function(context::get_proc_address), }; next_context_id.0 += 1; Ok(context) @@ -146,6 +145,7 @@ impl Device { read: native_context.egl_read_surface, }), context_is_owned: false, + gl: Gl::from_loader_function(context::get_proc_address), }; next_context_id.0 += 1; @@ -193,9 +193,13 @@ impl Device { /// Returns the descriptor that this context was created with. pub fn context_descriptor(&self, context: &Context) -> ContextDescriptor { - GL_FUNCTIONS.with(|gl| unsafe { - ContextDescriptor::from_egl_context(gl, self.egl_display, context.egl_context) - }) + unsafe { + ContextDescriptor::from_egl_context( + context::get_proc_address, + self.egl_display, + context.egl_context, + ) + } } /// Makes the context the current OpenGL context for this thread. @@ -286,9 +290,9 @@ impl Device { // // FIXME(pcwalton): Is this necessary? let _guard = self.temporarily_make_context_current(context)?; - GL_FUNCTIONS.with(|gl| unsafe { - gl.Flush(); - }); + unsafe { + context.gl.flush(); + }; match mem::replace(&mut context.framebuffer, Framebuffer::None) { Framebuffer::Surface(surface) => return Ok(Some(surface)), diff --git a/src/platform/egl/surface/android_surface.rs b/src/platform/egl/surface/android_surface.rs index 6af938cc..96134d5c 100644 --- a/src/platform/egl/surface/android_surface.rs +++ b/src/platform/egl/surface/android_surface.rs @@ -13,13 +13,12 @@ use super::super::android_ffi::{ use super::super::android_ffi::{ AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER, AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER, }; -use super::super::context::{Context, GL_FUNCTIONS}; +use super::super::context::Context; use super::super::device::Device; use super::{Surface, SurfaceTexture}; use crate::egl; use crate::egl::types::{EGLSurface, EGLint}; use crate::gl; -use crate::gl::types::{GLenum, GLuint}; use crate::gl_utils; use crate::platform::generic; use crate::platform::generic::egl::device::EGL_FUNCTIONS; @@ -32,18 +31,19 @@ use crate::renderbuffers::Renderbuffers; use crate::{Error, SurfaceAccess, SurfaceID, SurfaceInfo, SurfaceType, WindowingApiError}; use euclid::default::Size2D; +use glow::{HasContext, Texture}; use std::marker::PhantomData; use std::os::raw::c_void; use std::ptr; -const SURFACE_GL_TEXTURE_TARGET: GLenum = crate::gl::TEXTURE_2D; +const SURFACE_GL_TEXTURE_TARGET: u32 = crate::gl::TEXTURE_2D; pub(crate) enum SurfaceObjects { HardwareBuffer { hardware_buffer: *mut AHardwareBuffer, egl_image: EGLImageKHR, - framebuffer_object: GLuint, - texture_object: GLuint, + framebuffer_object: Option, + texture_object: Option, renderbuffers: Renderbuffers, }, Window { @@ -81,68 +81,65 @@ impl Device { size: &Size2D, ) -> Result { let _guard = self.temporarily_make_context_current(context)?; + let gl = &context.gl; + unsafe { + // Create a native hardware buffer. + let hardware_buffer_desc = AHardwareBuffer_Desc { + format: AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + height: size.height as u32, + width: size.width as u32, + layers: 1, + rfu0: 0, + rfu1: 0, + stride: 10, + usage: AHARDWAREBUFFER_USAGE_CPU_READ_NEVER + | AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER + | AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER + | AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE, + }; + let mut hardware_buffer = ptr::null_mut(); + let result = AHardwareBuffer_allocate(&hardware_buffer_desc, &mut hardware_buffer); + if result != 0 { + return Err(Error::SurfaceCreationFailed(WindowingApiError::Failed)); + } - GL_FUNCTIONS.with(|gl| { - unsafe { - // Create a native hardware buffer. - let hardware_buffer_desc = AHardwareBuffer_Desc { - format: AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, - height: size.height as u32, - width: size.width as u32, - layers: 1, - rfu0: 0, - rfu1: 0, - stride: 10, - usage: AHARDWAREBUFFER_USAGE_CPU_READ_NEVER - | AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER - | AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER - | AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE, - }; - let mut hardware_buffer = ptr::null_mut(); - let result = AHardwareBuffer_allocate(&hardware_buffer_desc, &mut hardware_buffer); - if result != 0 { - return Err(Error::SurfaceCreationFailed(WindowingApiError::Failed)); - } + // Create an EGL image, and bind it to a texture. + let egl_image = self.create_egl_image(context, hardware_buffer); - // Create an EGL image, and bind it to a texture. - let egl_image = self.create_egl_image(context, hardware_buffer); - - // Initialize and bind the image to the texture. - let texture_object = - generic::egl::surface::bind_egl_image_to_gl_texture(gl, egl_image); - - // Create the framebuffer, and bind the texture to it. - let framebuffer_object = gl_utils::create_and_bind_framebuffer( - gl, - SURFACE_GL_TEXTURE_TARGET, - texture_object, - ); - - // Bind renderbuffers as appropriate. - let context_descriptor = self.context_descriptor(context); - let context_attributes = self.context_descriptor_attributes(&context_descriptor); - let renderbuffers = Renderbuffers::new(gl, size, &context_attributes); - renderbuffers.bind_to_current_framebuffer(gl); - - debug_assert_eq!( - gl.CheckFramebufferStatus(gl::FRAMEBUFFER), - gl::FRAMEBUFFER_COMPLETE - ); - - Ok(Surface { - size: *size, - context_id: context.id, - objects: SurfaceObjects::HardwareBuffer { - hardware_buffer, - egl_image, - framebuffer_object, - texture_object, - renderbuffers, - }, - destroyed: false, - }) - } - }) + // Initialize and bind the image to the texture. + let texture_object = generic::egl::surface::bind_egl_image_to_gl_texture(gl, egl_image); + + // Create the framebuffer, and bind the texture to it. + let framebuffer_object = gl_utils::create_and_bind_framebuffer( + gl, + SURFACE_GL_TEXTURE_TARGET, + Some(texture_object), + ); + + // Bind renderbuffers as appropriate. + let context_descriptor = self.context_descriptor(context); + let context_attributes = self.context_descriptor_attributes(&context_descriptor); + let renderbuffers = Renderbuffers::new(gl, size, &context_attributes); + renderbuffers.bind_to_current_framebuffer(gl); + + debug_assert_eq!( + gl.check_framebuffer_status(gl::FRAMEBUFFER), + gl::FRAMEBUFFER_COMPLETE + ); + + Ok(Surface { + size: *size, + context_id: context.id, + objects: SurfaceObjects::HardwareBuffer { + hardware_buffer, + egl_image, + framebuffer_object: Some(framebuffer_object), + texture_object: Some(texture_object), + renderbuffers, + }, + destroyed: false, + }) + } } unsafe fn create_window_surface( @@ -191,11 +188,12 @@ impl Device { SurfaceObjects::Window { .. } => return Err((Error::WidgetAttached, surface)), SurfaceObjects::HardwareBuffer { hardware_buffer, .. - } => GL_FUNCTIONS.with(|gl| { + } => { let _guard = match self.temporarily_make_context_current(context) { Ok(guard) => guard, Err(err) => return Err((err, surface)), }; + let gl = &context.gl; let local_egl_image = self.create_egl_image(context, hardware_buffer); let texture_object = @@ -203,10 +201,10 @@ impl Device { Ok(SurfaceTexture { surface, local_egl_image, - texture_object, + texture_object: Some(texture_object), phantom: PhantomData, }) - }), + } } } } @@ -304,25 +302,25 @@ impl Device { ref mut texture_object, ref mut renderbuffers, } => { - GL_FUNCTIONS.with(|gl| { - gl.BindFramebuffer(gl::FRAMEBUFFER, 0); - gl.DeleteFramebuffers(1, framebuffer_object); - *framebuffer_object = 0; + let gl = &context.gl; + gl.bind_framebuffer(gl::FRAMEBUFFER, None); + if let Some(framebuffer) = framebuffer_object.take() { + gl.delete_framebuffer(framebuffer); + } - renderbuffers.destroy(gl); + renderbuffers.destroy(gl); - gl.DeleteTextures(1, texture_object); - *texture_object = 0; + if let Some(texture) = texture_object.take() { + gl.delete_texture(texture); + } - let egl_display = self.egl_display; - let result = - (EGL_EXTENSION_FUNCTIONS.DestroyImageKHR)(egl_display, *egl_image); - assert_ne!(result, egl::FALSE); - *egl_image = EGL_NO_IMAGE_KHR; + let egl_display = self.egl_display; + let result = (EGL_EXTENSION_FUNCTIONS.DestroyImageKHR)(egl_display, *egl_image); + assert_ne!(result, egl::FALSE); + *egl_image = EGL_NO_IMAGE_KHR; - AHardwareBuffer_release(*hardware_buffer); - *hardware_buffer = ptr::null_mut(); - }); + AHardwareBuffer_release(*hardware_buffer); + *hardware_buffer = ptr::null_mut(); } SurfaceObjects::Window { ref mut egl_surface, @@ -350,22 +348,22 @@ impl Device { mut surface_texture: SurfaceTexture, ) -> Result { let _guard = self.temporarily_make_context_current(context); - GL_FUNCTIONS.with(|gl| { - unsafe { - gl.DeleteTextures(1, &surface_texture.texture_object); - surface_texture.texture_object = 0; - - let egl_display = self.egl_display; - let result = (EGL_EXTENSION_FUNCTIONS.DestroyImageKHR)( - egl_display, - surface_texture.local_egl_image, - ); - assert_ne!(result, egl::FALSE); - surface_texture.local_egl_image = EGL_NO_IMAGE_KHR; + let gl = &context.gl; + unsafe { + if let Some(texture) = surface_texture.texture_object.take() { + gl.delete_texture(texture); } - Ok(surface_texture.surface) - }) + let egl_display = self.egl_display; + let result = (EGL_EXTENSION_FUNCTIONS.DestroyImageKHR)( + egl_display, + surface_texture.local_egl_image, + ); + assert_ne!(result, egl::FALSE); + surface_texture.local_egl_image = EGL_NO_IMAGE_KHR; + } + + Ok(surface_texture.surface) } /// Returns a pointer to the underlying surface data for reading or writing by the CPU. @@ -379,7 +377,7 @@ impl Device { /// /// This will be `GL_TEXTURE_2D` or `GL_TEXTURE_RECTANGLE`, depending on platform. #[inline] - pub fn surface_gl_texture_target(&self) -> GLenum { + pub fn surface_gl_texture_target(&self) -> u32 { SURFACE_GL_TEXTURE_TARGET } @@ -398,7 +396,7 @@ impl Device { SurfaceObjects::HardwareBuffer { framebuffer_object, .. } => framebuffer_object, - SurfaceObjects::Window { .. } => 0, + SurfaceObjects::Window { .. } => None, }, } } @@ -407,7 +405,7 @@ impl Device { /// /// It is only legal to read from, not write to, this texture object. #[inline] - pub fn surface_texture_object(&self, surface_texture: &SurfaceTexture) -> GLuint { + pub fn surface_texture_object(&self, surface_texture: &SurfaceTexture) -> Option { surface_texture.texture_object } } diff --git a/src/platform/egl/surface/mod.rs b/src/platform/egl/surface/mod.rs index 020490ae..fc67bf9e 100644 --- a/src/platform/egl/surface/mod.rs +++ b/src/platform/egl/surface/mod.rs @@ -3,10 +3,10 @@ //! Surface management for Android and OpenHarmony using the `GraphicBuffer` class and EGL. use crate::context::ContextID; -use crate::gl::types::GLuint; use crate::platform::generic::egl::ffi::EGLImageKHR; use euclid::default::Size2D; +use glow::Texture; use std::fmt::{self, Debug, Formatter}; use std::marker::PhantomData; use std::thread; @@ -60,7 +60,7 @@ pub struct Surface { pub struct SurfaceTexture { pub(crate) surface: Surface, pub(crate) local_egl_image: EGLImageKHR, - pub(crate) texture_object: GLuint, + pub(crate) texture_object: Option, pub(crate) phantom: PhantomData<*const ()>, } diff --git a/src/platform/egl/surface/ohos_surface.rs b/src/platform/egl/surface/ohos_surface.rs index 0c767d51..adab7156 100644 --- a/src/platform/egl/surface/ohos_surface.rs +++ b/src/platform/egl/surface/ohos_surface.rs @@ -7,12 +7,12 @@ use std::os::raw::c_void; use std::ptr; use euclid::default::Size2D; +use glow::{HasContext, Texture}; use log::info; use crate::egl; use crate::egl::types::{EGLSurface, EGLint}; use crate::gl; -use crate::gl::types::{GLenum, GLuint}; use crate::gl_utils; use crate::platform::egl::ohos_ffi::{eglGetNativeClientBufferANDROID, EGL_NATIVE_BUFFER_OHOS}; use crate::platform::generic; @@ -24,7 +24,7 @@ use crate::platform::generic::egl::ffi::EGL_NO_IMAGE_KHR; use crate::renderbuffers::Renderbuffers; use crate::{Error, SurfaceAccess, SurfaceID, SurfaceInfo, SurfaceType}; -use super::super::context::{Context, GL_FUNCTIONS}; +use super::super::context::Context; use super::super::device::Device; use super::super::ohos_ffi::{ NativeWindowOperation, OHNativeWindow, OH_NativeBuffer, OH_NativeBuffer_Alloc, @@ -33,14 +33,14 @@ use super::super::ohos_ffi::{ }; use super::{Surface, SurfaceTexture}; -const SURFACE_GL_TEXTURE_TARGET: GLenum = gl::TEXTURE_2D; +const SURFACE_GL_TEXTURE_TARGET: u32 = gl::TEXTURE_2D; pub(crate) enum SurfaceObjects { HardwareBuffer { hardware_buffer: *mut OH_NativeBuffer, egl_image: EGLImageKHR, - framebuffer_object: GLuint, - texture_object: GLuint, + framebuffer_object: Option, + texture_object: Option, renderbuffers: Renderbuffers, }, Window { @@ -90,50 +90,48 @@ impl Device { stride: 10, // used same magic number as android. I have no idea }; - GL_FUNCTIONS.with(|gl| { - unsafe { - let hardware_buffer = OH_NativeBuffer_Alloc(&config as *const _); - assert!(!hardware_buffer.is_null(), "Failed to create native buffer"); - - // Create an EGL image, and bind it to a texture. - let egl_image = self.create_egl_image(context, hardware_buffer); - - // Initialize and bind the image to the texture. - let texture_object = - generic::egl::surface::bind_egl_image_to_gl_texture(gl, egl_image); - - // Create the framebuffer, and bind the texture to it. - let framebuffer_object = gl_utils::create_and_bind_framebuffer( - gl, - SURFACE_GL_TEXTURE_TARGET, - texture_object, - ); - - // Bind renderbuffers as appropriate. - let context_descriptor = self.context_descriptor(context); - let context_attributes = self.context_descriptor_attributes(&context_descriptor); - let renderbuffers = Renderbuffers::new(gl, size, &context_attributes); - renderbuffers.bind_to_current_framebuffer(gl); - - debug_assert_eq!( - gl.CheckFramebufferStatus(gl::FRAMEBUFFER), - gl::FRAMEBUFFER_COMPLETE - ); - - Ok(Surface { - size: *size, - context_id: context.id, - objects: SurfaceObjects::HardwareBuffer { - hardware_buffer, - egl_image, - framebuffer_object, - texture_object, - renderbuffers, - }, - destroyed: false, - }) - } - }) + let gl = &context.gl; + unsafe { + let hardware_buffer = OH_NativeBuffer_Alloc(&config as *const _); + assert!(!hardware_buffer.is_null(), "Failed to create native buffer"); + + // Create an EGL image, and bind it to a texture. + let egl_image = self.create_egl_image(context, hardware_buffer); + + // Initialize and bind the image to the texture. + let texture_object = generic::egl::surface::bind_egl_image_to_gl_texture(gl, egl_image); + + // Create the framebuffer, and bind the texture to it. + let framebuffer_object = gl_utils::create_and_bind_framebuffer( + gl, + SURFACE_GL_TEXTURE_TARGET, + Some(texture_object), + ); + + // Bind renderbuffers as appropriate. + let context_descriptor = self.context_descriptor(context); + let context_attributes = self.context_descriptor_attributes(&context_descriptor); + let renderbuffers = Renderbuffers::new(gl, size, &context_attributes); + renderbuffers.bind_to_current_framebuffer(gl); + + debug_assert_eq!( + gl.check_framebuffer_status(gl::FRAMEBUFFER), + gl::FRAMEBUFFER_COMPLETE + ); + + Ok(Surface { + size: *size, + context_id: context.id, + objects: SurfaceObjects::HardwareBuffer { + hardware_buffer, + egl_image, + framebuffer_object: Some(framebuffer_object), + texture_object: Some(texture_object), + renderbuffers, + }, + destroyed: false, + }) + } } unsafe fn create_window_surface( @@ -192,11 +190,12 @@ impl Device { SurfaceObjects::Window { .. } => return Err((Error::WidgetAttached, surface)), SurfaceObjects::HardwareBuffer { hardware_buffer, .. - } => GL_FUNCTIONS.with(|gl| { + } => { let _guard = match self.temporarily_make_context_current(context) { Ok(guard) => guard, Err(err) => return Err((err, surface)), }; + let gl = &context.gl; let local_egl_image = self.create_egl_image(context, hardware_buffer); let texture_object = @@ -204,10 +203,10 @@ impl Device { Ok(SurfaceTexture { surface, local_egl_image, - texture_object, + texture_object: Some(texture_object), phantom: PhantomData, }) - }), + } } } } @@ -299,26 +298,26 @@ impl Device { ref mut texture_object, ref mut renderbuffers, } => { - GL_FUNCTIONS.with(|gl| { - gl.BindFramebuffer(gl::FRAMEBUFFER, 0); - gl.DeleteFramebuffers(1, framebuffer_object); - *framebuffer_object = 0; - - renderbuffers.destroy(gl); - - gl.DeleteTextures(1, texture_object); - *texture_object = 0; - - let egl_display = self.egl_display; - let result = - (EGL_EXTENSION_FUNCTIONS.DestroyImageKHR)(egl_display, *egl_image); - assert_ne!(result, egl::FALSE); - *egl_image = EGL_NO_IMAGE_KHR; - - let res = OH_NativeBuffer_Unreference(*hardware_buffer); - assert_eq!(res, 0, "OH_NativeBuffer_Unreference failed"); - *hardware_buffer = ptr::null_mut(); - }); + let gl = &context.gl; + gl.bind_framebuffer(gl::FRAMEBUFFER, None); + if let Some(framebuffer) = framebuffer_object.take() { + gl.delete_framebuffer(framebuffer); + } + + renderbuffers.destroy(gl); + + if let Some(texture) = texture_object.take() { + gl.delete_texture(texture); + } + + let egl_display = self.egl_display; + let result = (EGL_EXTENSION_FUNCTIONS.DestroyImageKHR)(egl_display, *egl_image); + assert_ne!(result, egl::FALSE); + *egl_image = EGL_NO_IMAGE_KHR; + + let res = OH_NativeBuffer_Unreference(*hardware_buffer); + assert_eq!(res, 0, "OH_NativeBuffer_Unreference failed"); + *hardware_buffer = ptr::null_mut(); } SurfaceObjects::Window { ref mut egl_surface, @@ -346,22 +345,22 @@ impl Device { mut surface_texture: SurfaceTexture, ) -> Result { let _guard = self.temporarily_make_context_current(context); - GL_FUNCTIONS.with(|gl| { - unsafe { - gl.DeleteTextures(1, &surface_texture.texture_object); - surface_texture.texture_object = 0; - - let egl_display = self.egl_display; - let result = (EGL_EXTENSION_FUNCTIONS.DestroyImageKHR)( - egl_display, - surface_texture.local_egl_image, - ); - assert_ne!(result, egl::FALSE); - surface_texture.local_egl_image = EGL_NO_IMAGE_KHR; + let gl = &context.gl; + unsafe { + if let Some(texture) = surface_texture.texture_object.take() { + gl.delete_texture(texture); } - Ok(surface_texture.surface) - }) + let egl_display = self.egl_display; + let result = (EGL_EXTENSION_FUNCTIONS.DestroyImageKHR)( + egl_display, + surface_texture.local_egl_image, + ); + assert_ne!(result, egl::FALSE); + surface_texture.local_egl_image = EGL_NO_IMAGE_KHR; + } + + Ok(surface_texture.surface) } /// Returns a pointer to the underlying surface data for reading or writing by the CPU. @@ -375,7 +374,7 @@ impl Device { /// /// This will be `GL_TEXTURE_2D` or `GL_TEXTURE_RECTANGLE`, depending on platform. #[inline] - pub fn surface_gl_texture_target(&self) -> GLenum { + pub fn surface_gl_texture_target(&self) -> u32 { SURFACE_GL_TEXTURE_TARGET } @@ -394,7 +393,7 @@ impl Device { SurfaceObjects::HardwareBuffer { framebuffer_object, .. } => framebuffer_object, - SurfaceObjects::Window { .. } => 0, + SurfaceObjects::Window { .. } => None, }, } } @@ -403,7 +402,7 @@ impl Device { /// /// It is only legal to read from, not write to, this texture object. #[inline] - pub fn surface_texture_object(&self, surface_texture: &SurfaceTexture) -> GLuint { + pub fn surface_texture_object(&self, surface_texture: &SurfaceTexture) -> Option { surface_texture.texture_object } } diff --git a/src/platform/generic/egl/context.rs b/src/platform/generic/egl/context.rs index 605fab87..86d16ee4 100644 --- a/src/platform/generic/egl/context.rs +++ b/src/platform/generic/egl/context.rs @@ -377,18 +377,22 @@ impl ContextDescriptor { }) } - pub(crate) unsafe fn from_egl_context( - gl: &Gl, + pub(crate) unsafe fn from_egl_context( + get_proc_address: F, egl_display: EGLDisplay, egl_context: EGLContext, - ) -> ContextDescriptor { + ) -> ContextDescriptor + where + F: FnMut(&str) -> *const c_void, + { let egl_config_id = get_context_attr(egl_display, egl_context, egl::CONFIG_ID as EGLint); EGL_FUNCTIONS.with(|egl| { let _guard = CurrentContextGuard::new(); egl.MakeCurrent(egl_display, egl::NO_SURFACE, egl::NO_SURFACE, egl_context); - let gl_version = GLVersion::current(gl); - let compatibility_profile = context::current_context_uses_compatibility_profile(gl); + let gl = unsafe { Gl::from_loader_function(get_proc_address) }; + let gl_version = GLVersion::current(&gl); + let compatibility_profile = context::current_context_uses_compatibility_profile(&gl); ContextDescriptor { egl_config_id, diff --git a/src/platform/generic/egl/surface.rs b/src/platform/generic/egl/surface.rs index a39cee2e..2e6d5c02 100644 --- a/src/platform/generic/egl/surface.rs +++ b/src/platform/generic/egl/surface.rs @@ -7,7 +7,6 @@ use super::device::EGL_FUNCTIONS; use crate::egl; use crate::egl::types::{EGLAttrib, EGLConfig, EGLContext, EGLDisplay, EGLSurface, EGLint}; use crate::gl; -use crate::gl::types::{GLint, GLuint}; use crate::gl_utils; use crate::platform::generic::egl::error::ToWindowingApiError; use crate::platform::generic::egl::ffi::EGLClientBuffer; @@ -21,6 +20,7 @@ use crate::Gl; use crate::{ContextAttributes, ContextID, Error, SurfaceID, SurfaceInfo}; use euclid::default::Size2D; +use glow::{Framebuffer, HasContext, PixelUnpackData, Texture}; use std::fmt::{self, Debug, Formatter}; use std::marker::PhantomData; use std::mem; @@ -53,8 +53,8 @@ unsafe impl Send for EGLBackedSurface {} pub(crate) enum EGLSurfaceObjects { TextureImage { egl_image: EGLImageKHR, - framebuffer_object: GLuint, - texture_object: GLuint, + framebuffer_object: Option, + texture_object: Option, renderbuffers: Renderbuffers, }, Window { @@ -65,7 +65,7 @@ pub(crate) enum EGLSurfaceObjects { pub(crate) struct EGLSurfaceTexture { pub(crate) surface: EGLBackedSurface, - pub(crate) texture_object: GLuint, + pub(crate) texture_object: Option, pub(crate) phantom: PhantomData<*const ()>, } @@ -93,39 +93,37 @@ impl EGLBackedSurface { unsafe { // Create our texture. - let mut texture_object = 0; - gl.GenTextures(1, &mut texture_object); + let texture_object = gl.create_texture().ok(); // Save the current texture binding - let mut old_texture_object = 0; - gl.GetIntegerv(gl::TEXTURE_BINDING_2D, &mut old_texture_object); - gl.BindTexture(gl::TEXTURE_2D, texture_object); + let old_texture_object = gl.get_parameter_texture(gl::TEXTURE_BINDING_2D); + gl.bind_texture(gl::TEXTURE_2D, texture_object); // Unbind PIXEL_UNPACK_BUFFER, because if it is bound, // it can cause errors in glTexImage2D. // TODO: should this be inside a check for GL 2.0? - let mut unpack_buffer = 0; - gl.GetIntegerv(gl::PIXEL_UNPACK_BUFFER_BINDING, &mut unpack_buffer); - if unpack_buffer != 0 { - gl.BindBuffer(gl::PIXEL_UNPACK_BUFFER, 0); + let unpack_buffer = gl.get_parameter_buffer(gl::PIXEL_UNPACK_BUFFER_BINDING); + if unpack_buffer.is_some() { + gl.bind_buffer(gl::PIXEL_UNPACK_BUFFER, None); } - gl.TexImage2D( + gl.tex_image_2d( gl::TEXTURE_2D, 0, - gl::RGBA as GLint, + gl::RGBA as i32, size.width, size.height, 0, gl::RGBA, gl::UNSIGNED_BYTE, - ptr::null(), + PixelUnpackData::Slice(None), ); // Restore the old bindings - gl.BindTexture(gl::TEXTURE_2D, old_texture_object as _); - if unpack_buffer != 0 { - gl.BindBuffer(gl::PIXEL_UNPACK_BUFFER, unpack_buffer as _); + gl.bind_texture(gl::TEXTURE_2D, old_texture_object); + if unpack_buffer.is_some() { + gl.bind_buffer(gl::PIXEL_UNPACK_BUFFER, unpack_buffer); } // Create our image. - let egl_client_buffer = texture_object as usize as EGLClientBuffer; + let egl_client_buffer = + texture_object.map_or(0, |tex| tex.0.get()) as usize as EGLClientBuffer; let egl_image = (EGL_EXTENSION_FUNCTIONS.CreateImageKHR)( egl_display, egl_context, @@ -143,7 +141,7 @@ impl EGLBackedSurface { renderbuffers.bind_to_current_framebuffer(gl); debug_assert_eq!( - gl.CheckFramebufferStatus(gl::FRAMEBUFFER), + gl.check_framebuffer_status(gl::FRAMEBUFFER), gl::FRAMEBUFFER_COMPLETE ); @@ -152,7 +150,7 @@ impl EGLBackedSurface { size: *size, objects: EGLSurfaceObjects::TextureImage { egl_image, - framebuffer_object, + framebuffer_object: Some(framebuffer_object), texture_object, renderbuffers, }, @@ -202,7 +200,7 @@ impl EGLBackedSurface { let texture_object = bind_egl_image_to_gl_texture(gl, egl_image); Ok(EGLSurfaceTexture { surface: self, - texture_object, + texture_object: Some(texture_object), phantom: PhantomData, }) } @@ -226,17 +224,19 @@ impl EGLBackedSurface { ref mut texture_object, ref mut renderbuffers, } => { - gl.BindFramebuffer(gl::FRAMEBUFFER, 0); - gl.DeleteFramebuffers(1, framebuffer_object); - *framebuffer_object = 0; + gl.bind_framebuffer(gl::FRAMEBUFFER, None); + if let Some(framebuffer) = framebuffer_object.take() { + gl.delete_framebuffer(framebuffer); + } renderbuffers.destroy(gl); let result = (EGL_EXTENSION_FUNCTIONS.DestroyImageKHR)(egl_display, *egl_image); assert_ne!(result, egl::FALSE); *egl_image = EGL_NO_IMAGE_KHR; - gl.DeleteTextures(1, texture_object); - *texture_object = 0; + if let Some(texture) = texture_object.take() { + gl.delete_texture(texture); + } self.destroyed = true; Ok(None) @@ -297,7 +297,7 @@ impl EGLBackedSurface { EGLSurfaceObjects::TextureImage { framebuffer_object, .. } => framebuffer_object, - EGLSurfaceObjects::Window { .. } => 0, + EGLSurfaceObjects::Window { .. } => None, }, } } @@ -324,15 +324,19 @@ impl EGLBackedSurface { return; } + // Flush to avoid races on Mesa/Intel and possibly other GPUs. + gl.flush(); + egl.MakeCurrent(egl_display, egl::NO_SURFACE, egl::NO_SURFACE, egl_context); match self.objects { EGLSurfaceObjects::TextureImage { - framebuffer_object, .. + framebuffer_object: Some(framebuffer_object), + .. } => { gl_utils::unbind_framebuffer_if_necessary(gl, framebuffer_object); } - EGLSurfaceObjects::Window { .. } => {} + EGLSurfaceObjects::TextureImage { .. } | EGLSurfaceObjects::Window { .. } => {} } }) } @@ -351,11 +355,12 @@ impl EGLBackedSurface { impl EGLSurfaceTexture { pub(crate) fn destroy(mut self, gl: &Gl) -> EGLBackedSurface { - unsafe { - gl.DeleteTextures(1, &self.texture_object); - self.texture_object = 0; - self.surface + if let Some(texture) = self.texture_object.take() { + unsafe { + gl.delete_texture(texture); + } } + self.surface } } @@ -398,31 +403,20 @@ pub(crate) unsafe fn create_pbuffer_surface( } #[allow(dead_code)] -pub(crate) unsafe fn bind_egl_image_to_gl_texture(gl: &Gl, egl_image: EGLImageKHR) -> GLuint { - let mut texture = 0; - gl.GenTextures(1, &mut texture); - debug_assert_ne!(texture, 0); +pub(crate) unsafe fn bind_egl_image_to_gl_texture(gl: &Gl, egl_image: EGLImageKHR) -> Texture { + let texture = gl.create_texture().unwrap(); - let mut texture_binding = 0; - gl.GetIntegerv(gl::TEXTURE_BINDING_2D, &mut texture_binding); + let texture_binding = gl.get_parameter_texture(gl::TEXTURE_BINDING_2D); // FIXME(pcwalton): Should this be `GL_TEXTURE_EXTERNAL_OES`? - gl.BindTexture(gl::TEXTURE_2D, texture); + gl.bind_texture(gl::TEXTURE_2D, Some(texture)); (EGL_EXTENSION_FUNCTIONS.ImageTargetTexture2DOES)(gl::TEXTURE_2D, egl_image); - gl.TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as GLint); - gl.TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as GLint); - gl.TexParameteri( - gl::TEXTURE_2D, - gl::TEXTURE_WRAP_S, - gl::CLAMP_TO_EDGE as GLint, - ); - gl.TexParameteri( - gl::TEXTURE_2D, - gl::TEXTURE_WRAP_T, - gl::CLAMP_TO_EDGE as GLint, - ); - gl.BindTexture(gl::TEXTURE_2D, texture_binding as GLuint); - - debug_assert_eq!(gl.GetError(), gl::NO_ERROR); + gl.tex_parameter_i32(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as _); + gl.tex_parameter_i32(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as _); + gl.tex_parameter_i32(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as _); + gl.tex_parameter_i32(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as _); + gl.bind_texture(gl::TEXTURE_2D, texture_binding); + + debug_assert_eq!(gl.get_error(), gl::NO_ERROR); texture } diff --git a/src/platform/generic/multi/device.rs b/src/platform/generic/multi/device.rs index 92febbd6..fb852854 100644 --- a/src/platform/generic/multi/device.rs +++ b/src/platform/generic/multi/device.rs @@ -8,9 +8,9 @@ use super::surface::{NativeWidget, Surface, SurfaceTexture}; use crate::connection::Connection as ConnectionInterface; use crate::context::ContextAttributes; use crate::device::Device as DeviceInterface; -use crate::gl::types::{GLenum, GLuint}; use crate::{ContextID, Error, GLApi, SurfaceAccess, SurfaceInfo, SurfaceType}; use euclid::default::Size2D; +use glow::Texture; use std::os::raw::c_void; @@ -280,7 +280,7 @@ where } #[inline] - fn surface_gl_texture_target(&self) -> GLenum { + fn surface_gl_texture_target(&self) -> u32 { Device::surface_gl_texture_target(self) } @@ -309,7 +309,10 @@ where } #[inline] - fn surface_texture_object(&self, surface_texture: &SurfaceTexture) -> GLuint { + fn surface_texture_object( + &self, + surface_texture: &SurfaceTexture, + ) -> Option { Device::surface_texture_object(self, surface_texture) } } diff --git a/src/platform/generic/multi/surface.rs b/src/platform/generic/multi/surface.rs index 059caa44..25217ec7 100644 --- a/src/platform/generic/multi/surface.rs +++ b/src/platform/generic/multi/surface.rs @@ -6,9 +6,9 @@ use super::context::Context; use super::device::Device; use crate::connection::Connection as ConnectionInterface; use crate::device::Device as DeviceInterface; -use crate::gl::types::{GLenum, GLuint}; use crate::{Error, SurfaceAccess, SurfaceInfo, SurfaceType}; use euclid::default::Size2D; +use glow::Texture; use std::fmt::{self, Debug, Formatter}; @@ -299,7 +299,7 @@ where /// /// This will be `GL_TEXTURE_2D` or `GL_TEXTURE_RECTANGLE`, depending on platform. #[inline] - pub fn surface_gl_texture_target(&self) -> GLenum { + pub fn surface_gl_texture_target(&self) -> u32 { match *self { Device::Default(ref device) => device.surface_gl_texture_target(), Device::Alternate(ref device) => device.surface_gl_texture_target(), @@ -327,7 +327,10 @@ where /// Returns the OpenGL texture object containing the contents of this surface. /// /// It is only legal to read from, not write to, this texture object. - pub fn surface_texture_object(&self, surface_texture: &SurfaceTexture) -> GLuint { + pub fn surface_texture_object( + &self, + surface_texture: &SurfaceTexture, + ) -> Option { match (self, surface_texture) { (Device::Default(device), SurfaceTexture::Default(ref surface_texture)) => { device.surface_texture_object(surface_texture) diff --git a/src/platform/macos/cgl/context.rs b/src/platform/macos/cgl/context.rs index ebd44992..8469e010 100644 --- a/src/platform/macos/cgl/context.rs +++ b/src/platform/macos/cgl/context.rs @@ -23,9 +23,11 @@ use core_foundation::bundle::CFBundleGetBundleWithIdentifier; use core_foundation::bundle::CFBundleGetFunctionPointerForName; use core_foundation::bundle::CFBundleRef; use core_foundation::string::CFString; +use glow::HasContext; use std::mem; use std::os::raw::c_void; use std::ptr; +use std::rc::Rc; use std::str::FromStr; use std::thread; @@ -45,11 +47,6 @@ const kCGLOGLPVersion_GL4_Core: CGLPixelFormatAttribute = 0x4100; static OPENGL_FRAMEWORK_IDENTIFIER: &str = "com.apple.opengl"; -thread_local! { - #[doc(hidden)] - pub static GL_FUNCTIONS: Gl = Gl::load_with(get_proc_address); -} - thread_local! { static OPENGL_FRAMEWORK: CFBundleRef = { unsafe { @@ -83,6 +80,7 @@ pub struct Context { pub(crate) cgl_context: CGLContextObj, pub(crate) id: ContextID, framebuffer: Framebuffer, + pub(crate) gl: Rc, } /// Wraps a native CGL context object. @@ -125,6 +123,16 @@ impl Clone for ContextDescriptor { } } +fn make_cgl_context_current(cgl_context: CGLContextObj) -> Result<(), Error> { + unsafe { + let err = CGLSetCurrentContext(cgl_context); + if err != kCGLNoError { + return Err(Error::MakeCurrentFailed(err.to_windowing_api_error())); + } + Ok(()) + } +} + unsafe impl Send for ContextDescriptor {} impl Device { @@ -235,11 +243,13 @@ impl Device { } debug_assert_ne!(cgl_context, ptr::null_mut()); + make_cgl_context_current(cgl_context)?; // Wrap and return the context. let context = Context { cgl_context, id: *next_context_id, framebuffer: Framebuffer::None, + gl: Rc::new(Gl::from_loader_function(get_proc_address)), }; next_context_id.0 += 1; Ok(context) @@ -259,6 +269,7 @@ impl Device { cgl_context: native_context.0, id: *next_context_id, framebuffer: Framebuffer::None, + gl: Rc::new(Gl::from_loader_function(get_proc_address)), }; next_context_id.0 += 1; mem::forget(native_context); @@ -302,13 +313,7 @@ impl Device { /// /// After calling this function, it is valid to use OpenGL rendering commands. pub fn make_context_current(&self, context: &Context) -> Result<(), Error> { - unsafe { - let err = CGLSetCurrentContext(context.cgl_context); - if err != kCGLNoError { - return Err(Error::MakeCurrentFailed(err.to_windowing_api_error())); - } - Ok(()) - } + make_cgl_context_current(context.cgl_context) } /// Removes the current OpenGL context from this thread. @@ -384,15 +389,17 @@ impl Device { // // TODO(pcwalton): Use `glClientWaitSync` instead to avoid starving the window // server. - GL_FUNCTIONS.with(|gl| { - let _guard = self.temporarily_make_context_current(context)?; - unsafe { - gl.Flush(); - } - - gl_utils::unbind_framebuffer_if_necessary(gl, surface.framebuffer_object); - Ok(Some(surface)) - }) + + let _guard = self.temporarily_make_context_current(context)?; + let gl = &context.gl; + unsafe { + gl.flush(); + } + + if let Some(framebuffer) = surface.framebuffer_object { + gl_utils::unbind_framebuffer_if_necessary(gl, framebuffer); + } + Ok(Some(surface)) } } } diff --git a/src/platform/macos/cgl/surface.rs b/src/platform/macos/cgl/surface.rs index f3bda5b1..d321380b 100644 --- a/src/platform/macos/cgl/surface.rs +++ b/src/platform/macos/cgl/surface.rs @@ -2,24 +2,26 @@ // //! Surface management for macOS. -use super::context::{Context, GL_FUNCTIONS}; +use super::context::Context; use super::device::Device; use crate::context::ContextID; -use crate::gl::types::{GLenum, GLint, GLuint}; use crate::gl_utils; use crate::platform::macos::system::surface::Surface as SystemSurface; use crate::renderbuffers::Renderbuffers; use crate::{gl, Error, SurfaceAccess, SurfaceID, SurfaceInfo, SurfaceType, WindowingApiError}; +use glow::Context as Gl; use core_foundation::base::TCFType; use euclid::default::Size2D; +use glow::{HasContext, Texture}; use io_surface::{self, IOSurface}; use std::fmt::{self, Debug, Formatter}; use std::marker::PhantomData; +use std::rc::Rc; pub use crate::platform::macos::system::surface::{NativeSurface, NativeWidget}; -const SURFACE_GL_TEXTURE_TARGET: GLenum = gl::TEXTURE_RECTANGLE; +const SURFACE_GL_TEXTURE_TARGET: u32 = gl::TEXTURE_RECTANGLE; /// Represents a hardware buffer of pixels that can be rendered to via the CPU or GPU and either /// displayed in a native widget or bound to a texture for reading. @@ -40,8 +42,8 @@ const SURFACE_GL_TEXTURE_TARGET: GLenum = gl::TEXTURE_RECTANGLE; pub struct Surface { pub(crate) system_surface: SystemSurface, pub(crate) context_id: ContextID, - pub(crate) framebuffer_object: GLuint, - pub(crate) texture_object: GLuint, + pub(crate) framebuffer_object: Option, + pub(crate) texture_object: Option, pub(crate) renderbuffers: Renderbuffers, } @@ -56,7 +58,7 @@ pub struct Surface { /// `destroy_surface_texture()` method, or a panic will occur. pub struct SurfaceTexture { pub(crate) surface: Surface, - pub(crate) texture_object: GLuint, + pub(crate) texture_object: Option, pub(crate) phantom: PhantomData<*const ()>, } @@ -89,57 +91,52 @@ impl Device { self.0.set_surface_flipped(&mut system_surface, true); let _guard = self.temporarily_make_context_current(context); - GL_FUNCTIONS.with(|gl| { - unsafe { - let mut texture_object = - self.bind_to_gl_texture(&system_surface.io_surface, &system_surface.size); - - let mut framebuffer_object = 0; - gl.GenFramebuffers(1, &mut framebuffer_object); - let _guard = self.temporarily_bind_framebuffer(framebuffer_object); - - gl.FramebufferTexture2D( - gl::FRAMEBUFFER, - gl::COLOR_ATTACHMENT0, - SURFACE_GL_TEXTURE_TARGET, - texture_object, - 0, - ); - - let context_descriptor = self.context_descriptor(context); - let context_attributes = self.context_descriptor_attributes(&context_descriptor); - - let mut renderbuffers = - Renderbuffers::new(gl, &system_surface.size, &context_attributes); - renderbuffers.bind_to_current_framebuffer(gl); - - if gl.GetError() != gl::NO_ERROR - || gl.CheckFramebufferStatus(gl::FRAMEBUFFER) != gl::FRAMEBUFFER_COMPLETE - { - // On macos, surface creation can fail silently (e.g. due to OOM) and AFAICT - // the way to tell that it has failed is to look at the framebuffer status - // while the surface is attached. - renderbuffers.destroy(gl); - if framebuffer_object != 0 { - gl.DeleteFramebuffers(1, &mut framebuffer_object); - } - if texture_object != 0 { - gl.DeleteTextures(1, &mut texture_object); - } - let _ = self.0.destroy_surface(&mut system_surface); - // TODO: convert the GL error into a surfman error? - return Err(Error::SurfaceCreationFailed(WindowingApiError::Failed)); - } - - Ok(Surface { - system_surface, - context_id: context.id, - framebuffer_object, - texture_object, - renderbuffers, - }) + let gl = &context.gl; + unsafe { + let texture_object = + self.bind_to_gl_texture(gl, &system_surface.io_surface, &system_surface.size); + + let framebuffer_object = gl.create_framebuffer().unwrap(); + let _guard = + self.temporarily_bind_framebuffer(context.gl.clone(), Some(framebuffer_object)); + + gl.framebuffer_texture_2d( + gl::FRAMEBUFFER, + gl::COLOR_ATTACHMENT0, + SURFACE_GL_TEXTURE_TARGET, + Some(texture_object), + 0, + ); + + let context_descriptor = self.context_descriptor(context); + let context_attributes = self.context_descriptor_attributes(&context_descriptor); + + let mut renderbuffers = + Renderbuffers::new(gl, &system_surface.size, &context_attributes); + renderbuffers.bind_to_current_framebuffer(gl); + + if gl.get_error() != gl::NO_ERROR + || gl.check_framebuffer_status(gl::FRAMEBUFFER) != gl::FRAMEBUFFER_COMPLETE + { + // On macos, surface creation can fail silently (e.g. due to OOM) and AFAICT + // the way to tell that it has failed is to look at the framebuffer status + // while the surface is attached. + renderbuffers.destroy(gl); + gl.delete_framebuffer(framebuffer_object); + gl.delete_texture(texture_object); + let _ = self.0.destroy_surface(&mut system_surface); + // TODO: convert the GL error into a surfman error? + return Err(Error::SurfaceCreationFailed(WindowingApiError::Failed)); } - }) + + Ok(Surface { + system_surface, + context_id: context.id, + framebuffer_object: Some(framebuffer_object), + texture_object: Some(texture_object), + renderbuffers, + }) + } } /// Creates a surface texture from an existing generic surface for use with the given context. @@ -164,52 +161,51 @@ impl Device { let _guard = self.temporarily_make_context_current(context).unwrap(); let texture_object = self.bind_to_gl_texture( + &context.gl, &surface.system_surface.io_surface, &surface.system_surface.size, ); Ok(SurfaceTexture { surface, - texture_object, + texture_object: Some(texture_object), phantom: PhantomData, }) } - fn bind_to_gl_texture(&self, io_surface: &IOSurface, size: &Size2D) -> GLuint { - GL_FUNCTIONS.with(|gl| unsafe { - let mut texture = 0; - gl.GenTextures(1, &mut texture); - debug_assert_ne!(texture, 0); + fn bind_to_gl_texture(&self, gl: &Gl, io_surface: &IOSurface, size: &Size2D) -> Texture { + unsafe { + let texture = gl.create_texture().unwrap(); - gl.BindTexture(gl::TEXTURE_RECTANGLE, texture); + gl.bind_texture(gl::TEXTURE_RECTANGLE, Some(texture)); io_surface.bind_to_gl_texture(size.width, size.height, true); - gl.TexParameteri( + gl.tex_parameter_i32( gl::TEXTURE_RECTANGLE, gl::TEXTURE_MAG_FILTER, - gl::NEAREST as GLint, + gl::NEAREST as _, ); - gl.TexParameteri( + gl.tex_parameter_i32( gl::TEXTURE_RECTANGLE, gl::TEXTURE_MIN_FILTER, - gl::NEAREST as GLint, + gl::NEAREST as _, ); - gl.TexParameteri( + gl.tex_parameter_i32( gl::TEXTURE_RECTANGLE, gl::TEXTURE_WRAP_S, - gl::CLAMP_TO_EDGE as GLint, + gl::CLAMP_TO_EDGE as _, ); - gl.TexParameteri( + gl.tex_parameter_i32( gl::TEXTURE_RECTANGLE, gl::TEXTURE_WRAP_T, - gl::CLAMP_TO_EDGE as GLint, + gl::CLAMP_TO_EDGE as _, ); - gl.BindTexture(gl::TEXTURE_RECTANGLE, 0); + gl.bind_texture(gl::TEXTURE_RECTANGLE, None); - debug_assert_eq!(gl.GetError(), gl::NO_ERROR); + debug_assert_eq!(gl.get_error(), gl::NO_ERROR); texture - }) + } } /// Destroys a surface. @@ -224,22 +220,23 @@ impl Device { context: &mut Context, surface: &mut Surface, ) -> Result<(), Error> { - GL_FUNCTIONS.with(|gl| { - if context.id != surface.context_id { - return Err(Error::IncompatibleSurface); - } + let gl = &context.gl; + if context.id != surface.context_id { + return Err(Error::IncompatibleSurface); + } - unsafe { - gl_utils::destroy_framebuffer(gl, surface.framebuffer_object); - surface.framebuffer_object = 0; + unsafe { + if let Some(fbo) = surface.framebuffer_object.take() { + gl_utils::destroy_framebuffer(gl, fbo); + } - surface.renderbuffers.destroy(gl); - gl.DeleteTextures(1, &surface.texture_object); - surface.texture_object = 0; + surface.renderbuffers.destroy(gl); + if let Some(texture) = surface.texture_object.take() { + gl.delete_texture(texture); } + } - self.0.destroy_surface(&mut surface.system_surface) - }) + self.0.destroy_surface(&mut surface.system_surface) } /// Destroys a surface texture and returns the underlying surface. @@ -251,24 +248,24 @@ impl Device { /// occur. pub fn destroy_surface_texture( &self, - _: &mut Context, + context: &mut Context, mut surface_texture: SurfaceTexture, ) -> Result { - GL_FUNCTIONS.with(|gl| { + let gl = &context.gl; + if let Some(texture) = surface_texture.texture_object.take() { unsafe { - gl.DeleteTextures(1, &surface_texture.texture_object); - surface_texture.texture_object = 0; + gl.delete_texture(texture); } + } - Ok(surface_texture.surface) - }) + Ok(surface_texture.surface) } /// Returns the OpenGL texture object containing the contents of this surface. /// /// It is only legal to read from, not write to, this texture object. #[inline] - pub fn surface_texture_object(&self, surface_texture: &SurfaceTexture) -> GLuint { + pub fn surface_texture_object(&self, surface_texture: &SurfaceTexture) -> Option { surface_texture.texture_object } @@ -276,7 +273,7 @@ impl Device { /// /// This will be `GL_TEXTURE_2D` or `GL_TEXTURE_RECTANGLE`, depending on platform. #[inline] - pub fn surface_gl_texture_target(&self) -> GLenum { + pub fn surface_gl_texture_target(&self) -> u32 { SURFACE_GL_TEXTURE_TARGET } @@ -287,22 +284,21 @@ impl Device { /// /// The supplied context must match the context the surface was created with, or an /// `IncompatibleSurface` error is returned. - pub fn present_surface(&self, _: &Context, surface: &mut Surface) -> Result<(), Error> { + pub fn present_surface(&self, context: &Context, surface: &mut Surface) -> Result<(), Error> { self.0.present_surface(&mut surface.system_surface)?; - GL_FUNCTIONS.with(|gl| { - unsafe { - let size = surface.system_surface.size; - gl.BindTexture(gl::TEXTURE_RECTANGLE, surface.texture_object); - surface - .system_surface - .io_surface - .bind_to_gl_texture(size.width, size.height, true); - gl.BindTexture(gl::TEXTURE_RECTANGLE, 0); - } + let gl = &context.gl; + unsafe { + let size = surface.system_surface.size; + gl.bind_texture(gl::TEXTURE_RECTANGLE, surface.texture_object); + surface + .system_surface + .io_surface + .bind_to_gl_texture(size.width, size.height, true); + gl.bind_texture(gl::TEXTURE_RECTANGLE, None); + } - Ok(()) - }) + Ok(()) } /// Resizes a widget surface. @@ -317,57 +313,65 @@ impl Device { } let _guard = self.temporarily_make_context_current(context); - let _guard = self.temporarily_bind_framebuffer(surface.framebuffer_object); + let _guard = + self.temporarily_bind_framebuffer(context.gl.clone(), surface.framebuffer_object); self.0.resize_surface(&mut surface.system_surface, size)?; let context_descriptor = self.context_descriptor(context); let context_attributes = self.context_descriptor_attributes(&context_descriptor); - GL_FUNCTIONS.with(|gl| { - unsafe { - // Recreate the GL texture and bind it to the FBO - let texture_object = - self.bind_to_gl_texture(&surface.system_surface.io_surface, &size); - gl.FramebufferTexture2D( - gl::FRAMEBUFFER, - gl::COLOR_ATTACHMENT0, - SURFACE_GL_TEXTURE_TARGET, - texture_object, - 0, - ); - - // Recreate the GL renderbuffers and bind them to the FBO - let renderbuffers = Renderbuffers::new(gl, &size, &context_attributes); - renderbuffers.bind_to_current_framebuffer(gl); - - gl.DeleteTextures(1, &surface.texture_object); - surface.renderbuffers.destroy(gl); - - surface.texture_object = texture_object; - surface.renderbuffers = renderbuffers; - - debug_assert_eq!( - (gl.GetError(), gl.CheckFramebufferStatus(gl::FRAMEBUFFER)), - (gl::NO_ERROR, gl::FRAMEBUFFER_COMPLETE), - ); + let gl = &context.gl; + unsafe { + // Recreate the GL texture and bind it to the FBO + let texture_object = + self.bind_to_gl_texture(gl, &surface.system_surface.io_surface, &size); + gl.framebuffer_texture_2d( + gl::FRAMEBUFFER, + gl::COLOR_ATTACHMENT0, + SURFACE_GL_TEXTURE_TARGET, + Some(texture_object), + 0, + ); + + // Recreate the GL renderbuffers and bind them to the FBO + let renderbuffers = Renderbuffers::new(gl, &size, &context_attributes); + renderbuffers.bind_to_current_framebuffer(gl); + + if let Some(texture) = surface.texture_object { + gl.delete_texture(texture); } + surface.renderbuffers.destroy(gl); - Ok(()) - }) + surface.texture_object = Some(texture_object); + surface.renderbuffers = renderbuffers; + + debug_assert_eq!( + (gl.get_error(), gl.check_framebuffer_status(gl::FRAMEBUFFER)), + (gl::NO_ERROR, gl::FRAMEBUFFER_COMPLETE), + ); + } + + Ok(()) } - fn temporarily_bind_framebuffer(&self, new_framebuffer: GLuint) -> FramebufferGuard { - GL_FUNCTIONS.with(|gl| unsafe { - let (mut current_draw_framebuffer, mut current_read_framebuffer) = (0, 0); - gl.GetIntegerv(gl::DRAW_FRAMEBUFFER_BINDING, &mut current_draw_framebuffer); - gl.GetIntegerv(gl::READ_FRAMEBUFFER_BINDING, &mut current_read_framebuffer); - gl.BindFramebuffer(gl::FRAMEBUFFER, new_framebuffer); + fn temporarily_bind_framebuffer( + &self, + gl: Rc, + new_framebuffer: Option, + ) -> FramebufferGuard { + unsafe { + let current_draw_framebuffer = + gl.get_parameter_framebuffer(gl::DRAW_FRAMEBUFFER_BINDING); + let current_read_framebuffer = + gl.get_parameter_framebuffer(gl::READ_FRAMEBUFFER_BINDING); + gl.bind_framebuffer(gl::FRAMEBUFFER, new_framebuffer); FramebufferGuard { - draw: current_draw_framebuffer as GLuint, - read: current_read_framebuffer as GLuint, + gl, + draw: current_draw_framebuffer, + read: current_read_framebuffer, } - }) + } } /// Returns various information about the surface, including the framebuffer object needed to @@ -405,15 +409,16 @@ impl Surface { #[must_use] struct FramebufferGuard { - draw: GLuint, - read: GLuint, + gl: Rc, + draw: Option, + read: Option, } impl Drop for FramebufferGuard { fn drop(&mut self) { - GL_FUNCTIONS.with(|gl| unsafe { - gl.BindFramebuffer(gl::READ_FRAMEBUFFER, self.read); - gl.BindFramebuffer(gl::DRAW_FRAMEBUFFER, self.draw); - }) + unsafe { + self.gl.bind_framebuffer(gl::READ_FRAMEBUFFER, self.read); + self.gl.bind_framebuffer(gl::DRAW_FRAMEBUFFER, self.draw); + } } } diff --git a/src/platform/unix/generic/context.rs b/src/platform/unix/generic/context.rs index 5c720564..91e7d649 100644 --- a/src/platform/unix/generic/context.rs +++ b/src/platform/unix/generic/context.rs @@ -14,11 +14,6 @@ use std::os::raw::c_void; pub use crate::platform::generic::egl::context::{ContextDescriptor, NativeContext}; -thread_local! { - #[doc(hidden)] - pub static GL_FUNCTIONS: Gl = Gl::load_with(context::get_proc_address); -} - /// Represents an OpenGL rendering context. /// /// A context allows you to issue rendering commands to a surface. When initially created, a @@ -35,7 +30,7 @@ thread_local! { /// allow for sharing of texture data. Contexts are local to a single thread and device. /// /// A context must be explicitly destroyed with `destroy_context()`, or a panic will occur. -pub struct Context(pub(crate) EGLBackedContext); +pub struct Context(pub(crate) EGLBackedContext, pub(crate) Gl); impl Device { /// Creates a context descriptor with the given attributes. @@ -76,17 +71,21 @@ impl Device { share_with: Option<&Context>, ) -> Result { unsafe { - EGLBackedContext::new( + let context = EGLBackedContext::new( self.native_connection.egl_display, descriptor, share_with.map(|ctx| &ctx.0), self.gl_api(), - ) - .map(Context) + )?; + context.make_current(self.native_connection.egl_display)?; + Ok(Context( + context, + Gl::from_loader_function(context::get_proc_address), + )) } } - /// Wraps an `EGLContext` in a native context and returns it. + /// Wraps an `EGLContext` in a native context and returns it. The context must be current. /// /// The context is not retained, as there is no way to do this in the EGL API. Therefore, /// it is the caller's responsibility to ensure that the returned `Context` object remains @@ -96,9 +95,10 @@ impl Device { &self, native_context: NativeContext, ) -> Result { - Ok(Context(EGLBackedContext::from_native_context( - native_context, - ))) + Ok(Context( + EGLBackedContext::from_native_context(native_context), + Gl::from_loader_function(context::get_proc_address), + )) } /// Destroys a context. @@ -124,13 +124,13 @@ impl Device { /// Returns the descriptor that this context was created with. #[inline] pub fn context_descriptor(&self, context: &Context) -> ContextDescriptor { - GL_FUNCTIONS.with(|gl| unsafe { + unsafe { ContextDescriptor::from_egl_context( - gl, + context::get_proc_address, self.native_connection.egl_display, context.0.egl_context, ) - }) + } } /// Makes the context the current OpenGL context for this thread. @@ -213,12 +213,12 @@ impl Device { &self, context: &mut Context, ) -> Result, Error> { - GL_FUNCTIONS.with(|gl| unsafe { + unsafe { context .0 - .unbind_surface(gl, self.native_connection.egl_display) + .unbind_surface(&context.1, self.native_connection.egl_display) .map(|maybe_surface| maybe_surface.map(Surface)) - }) + } } /// Returns a unique ID representing a context. diff --git a/src/platform/unix/generic/surface.rs b/src/platform/unix/generic/surface.rs index ad15ba7b..b7de5e56 100644 --- a/src/platform/unix/generic/surface.rs +++ b/src/platform/unix/generic/surface.rs @@ -2,18 +2,18 @@ //! //! Wrapper for EGL surfaces on Mesa. -use super::context::{Context, GL_FUNCTIONS}; +use super::context::Context; use super::device::Device; use crate::gl; -use crate::gl::types::{GLenum, GLuint}; use crate::platform::generic::egl::surface::{EGLBackedSurface, EGLSurfaceTexture}; use crate::{Error, SurfaceAccess, SurfaceInfo, SurfaceType}; use euclid::default::Size2D; +use glow::Texture; use std::marker::PhantomData; // FIXME(pcwalton): Is this right, or should it be `TEXTURE_EXTERNAL_OES`? -const SURFACE_GL_TEXTURE_TARGET: GLenum = gl::TEXTURE_2D; +const SURFACE_GL_TEXTURE_TARGET: u32 = gl::TEXTURE_2D; /// Represents a hardware buffer of pixels that can be rendered to via the CPU or GPU and either /// displayed in a native widget or bound to a texture for reading. @@ -77,16 +77,15 @@ impl Device { let _guard = self.temporarily_make_context_current(context)?; let context_descriptor = self.context_descriptor(context); let context_attributes = self.context_descriptor_attributes(&context_descriptor); - GL_FUNCTIONS.with(|gl| { - Ok(Surface(EGLBackedSurface::new_generic( - gl, - self.native_connection.egl_display, - context.0.egl_context, - context.0.id, - &context_attributes, - size, - ))) - }) + + Ok(Surface(EGLBackedSurface::new_generic( + &context.1, + self.native_connection.egl_display, + context.0.egl_context, + context.0.id, + &context_attributes, + size, + ))) } /// Creates a surface texture from an existing generic surface for use with the given context. @@ -109,10 +108,10 @@ impl Device { Err(err) => return Err((err, surface)), }; - GL_FUNCTIONS.with(|gl| match surface.0.to_surface_texture(gl) { + match surface.0.to_surface_texture(&context.1) { Ok(surface_texture) => Ok(SurfaceTexture(surface_texture)), Err((err, surface)) => Err((err, Surface(surface))), - }) + } } /// Destroys a surface. @@ -127,12 +126,10 @@ impl Device { context: &mut Context, surface: &mut Surface, ) -> Result<(), Error> { - GL_FUNCTIONS.with(|gl| { - let egl_display = self.native_connection.egl_display; - let window = surface.0.destroy(gl, egl_display, context.0.id)?; - debug_assert!(window.is_none()); - Ok(()) - }) + let egl_display = self.native_connection.egl_display; + let window = surface.0.destroy(&context.1, egl_display, context.0.id)?; + debug_assert!(window.is_none()); + Ok(()) } /// Destroys a surface texture and returns the underlying surface. @@ -148,7 +145,7 @@ impl Device { surface_texture: SurfaceTexture, ) -> Result { match self.temporarily_make_context_current(context) { - Ok(_guard) => GL_FUNCTIONS.with(|gl| Ok(Surface(surface_texture.0.destroy(gl)))), + Ok(_guard) => Ok(Surface(surface_texture.0.destroy(&context.1))), Err(err) => Err((err, surface_texture)), } } @@ -187,7 +184,7 @@ impl Device { /// /// This will be `GL_TEXTURE_2D` or `GL_TEXTURE_RECTANGLE`, depending on platform. #[inline] - pub fn surface_gl_texture_target(&self) -> GLenum { + pub fn surface_gl_texture_target(&self) -> u32 { SURFACE_GL_TEXTURE_TARGET } @@ -205,7 +202,7 @@ impl Device { /// /// It is only legal to read from, not write to, this texture object. #[inline] - pub fn surface_texture_object(&self, surface_texture: &SurfaceTexture) -> GLuint { + pub fn surface_texture_object(&self, surface_texture: &SurfaceTexture) -> Option { surface_texture.0.texture_object } } diff --git a/src/platform/unix/wayland/context.rs b/src/platform/unix/wayland/context.rs index b8dcbc4f..16d2c274 100644 --- a/src/platform/unix/wayland/context.rs +++ b/src/platform/unix/wayland/context.rs @@ -14,11 +14,6 @@ use std::os::raw::c_void; pub use crate::platform::generic::egl::context::{ContextDescriptor, NativeContext}; -thread_local! { - #[doc(hidden)] - pub static GL_FUNCTIONS: Gl = Gl::load_with(context::get_proc_address); -} - /// Represents an OpenGL rendering context. /// /// A context allows you to issue rendering commands to a surface. When initially created, a @@ -35,7 +30,7 @@ thread_local! { /// allow for sharing of texture data. Contexts are local to a single thread and device. /// /// A context must be explicitly destroyed with `destroy_context()`, or a panic will occur. -pub struct Context(pub(crate) EGLBackedContext); +pub struct Context(pub(crate) EGLBackedContext, pub(crate) Gl); impl Device { /// Creates a context descriptor with the given attributes. @@ -74,13 +69,17 @@ impl Device { share_with: Option<&Context>, ) -> Result { unsafe { - EGLBackedContext::new( + let context = EGLBackedContext::new( self.native_connection.egl_display, descriptor, share_with.map(|ctx| &ctx.0), self.gl_api(), - ) - .map(Context) + )?; + context.make_current(self.native_connection.egl_display)?; + Ok(Context( + context, + Gl::from_loader_function(context::get_proc_address), + )) } } @@ -94,9 +93,10 @@ impl Device { &self, native_context: NativeContext, ) -> Result { - Ok(Context(EGLBackedContext::from_native_context( - native_context, - ))) + Ok(Context( + EGLBackedContext::from_native_context(native_context), + Gl::from_loader_function(context::get_proc_address), + )) } /// Destroys a context. @@ -122,13 +122,13 @@ impl Device { /// Returns the descriptor that this context was created with. #[inline] pub fn context_descriptor(&self, context: &Context) -> ContextDescriptor { - GL_FUNCTIONS.with(|gl| unsafe { + unsafe { ContextDescriptor::from_egl_context( - gl, + context::get_proc_address, self.native_connection.egl_display, context.0.egl_context, ) - }) + } } /// Makes the context the current OpenGL context for this thread. @@ -211,17 +211,12 @@ impl Device { &self, context: &mut Context, ) -> Result, Error> { - GL_FUNCTIONS.with(|gl| { - unsafe { - // Flush to avoid races on Mesa/Intel and possibly other GPUs. - gl.Flush(); - - context - .0 - .unbind_surface(gl, self.native_connection.egl_display) - .map(|maybe_surface| maybe_surface.map(Surface)) - } - }) + unsafe { + context + .0 + .unbind_surface(&context.1, self.native_connection.egl_display) + .map(|maybe_surface| maybe_surface.map(Surface)) + } } /// Returns a unique ID representing a context. diff --git a/src/platform/unix/wayland/surface.rs b/src/platform/unix/wayland/surface.rs index 7702ad85..e1bafbe1 100644 --- a/src/platform/unix/wayland/surface.rs +++ b/src/platform/unix/wayland/surface.rs @@ -2,22 +2,22 @@ // //! A surface implementation using Wayland surfaces backed by TextureImage. -use super::context::{Context, GL_FUNCTIONS}; +use super::context::Context; use super::device::Device; use crate::gl; -use crate::gl::types::{GLenum, GLuint}; use crate::platform::generic::egl::context; use crate::platform::generic::egl::surface::{EGLBackedSurface, EGLSurfaceTexture}; use crate::{Error, SurfaceAccess, SurfaceInfo, SurfaceType}; use euclid::default::Size2D; +use glow::Texture; use std::marker::PhantomData; use std::os::raw::c_void; use wayland_sys::client::wl_proxy; use wayland_sys::egl::{wl_egl_window, WAYLAND_EGL_HANDLE}; // FIXME(pcwalton): Is this right, or should it be `TEXTURE_EXTERNAL_OES`? -const SURFACE_GL_TEXTURE_TARGET: GLenum = gl::TEXTURE_2D; +const SURFACE_GL_TEXTURE_TARGET: u32 = gl::TEXTURE_2D; /// Represents a hardware buffer of pixels that can be rendered to via the CPU or GPU and either /// displayed in a native widget or bound to a texture for reading. @@ -90,16 +90,15 @@ impl Device { let _guard = self.temporarily_make_context_current(context)?; let context_descriptor = self.context_descriptor(context); let context_attributes = self.context_descriptor_attributes(&context_descriptor); - GL_FUNCTIONS.with(|gl| { - Ok(Surface(EGLBackedSurface::new_generic( - gl, - self.native_connection.egl_display, - context.0.egl_context, - context.0.id, - &context_attributes, - size, - ))) - }) + + Ok(Surface(EGLBackedSurface::new_generic( + &context.1, + self.native_connection.egl_display, + context.0.egl_context, + context.0.id, + &context_attributes, + size, + ))) } unsafe fn create_window_surface( @@ -147,10 +146,10 @@ impl Device { Err(err) => return Err((err, surface)), }; - GL_FUNCTIONS.with(|gl| match surface.0.to_surface_texture(gl) { + match surface.0.to_surface_texture(&context.1) { Ok(surface_texture) => Ok(SurfaceTexture(surface_texture)), Err((err, surface)) => Err((err, Surface(surface))), - }) + } } /// Destroys a surface. @@ -165,16 +164,16 @@ impl Device { context: &mut Context, surface: &mut Surface, ) -> Result<(), Error> { - GL_FUNCTIONS.with(|gl| { - let egl_display = self.native_connection.egl_display; - if let Some(wayland_egl_window) = surface.0.destroy(gl, egl_display, context.0.id)? { - unsafe { - let wayland_egl_window = wayland_egl_window as *mut wl_egl_window; - (WAYLAND_EGL_HANDLE.wl_egl_window_destroy)(wayland_egl_window); - } + let egl_display = self.native_connection.egl_display; + if let Some(wayland_egl_window) = + surface.0.destroy(&context.1, egl_display, context.0.id)? + { + unsafe { + let wayland_egl_window = wayland_egl_window as *mut wl_egl_window; + (WAYLAND_EGL_HANDLE.wl_egl_window_destroy)(wayland_egl_window); } - Ok(()) - }) + } + Ok(()) } /// Destroys a surface texture and returns the underlying surface. @@ -190,7 +189,7 @@ impl Device { surface_texture: SurfaceTexture, ) -> Result { match self.temporarily_make_context_current(context) { - Ok(_guard) => GL_FUNCTIONS.with(|gl| Ok(Surface(surface_texture.0.destroy(gl)))), + Ok(_guard) => Ok(Surface(surface_texture.0.destroy(&context.1))), Err(err) => Err((err, surface_texture)), } } @@ -239,7 +238,7 @@ impl Device { /// /// This will be `GL_TEXTURE_2D` or `GL_TEXTURE_RECTANGLE`, depending on platform. #[inline] - pub fn surface_gl_texture_target(&self) -> GLenum { + pub fn surface_gl_texture_target(&self) -> u32 { SURFACE_GL_TEXTURE_TARGET } @@ -257,7 +256,7 @@ impl Device { /// /// It is only legal to read from, not write to, this texture object. #[inline] - pub fn surface_texture_object(&self, surface_texture: &SurfaceTexture) -> GLuint { + pub fn surface_texture_object(&self, surface_texture: &SurfaceTexture) -> Option { surface_texture.0.texture_object } } diff --git a/src/platform/unix/x11/context.rs b/src/platform/unix/x11/context.rs index c3a0e32d..def50546 100644 --- a/src/platform/unix/x11/context.rs +++ b/src/platform/unix/x11/context.rs @@ -14,11 +14,6 @@ use std::os::raw::c_void; pub use crate::platform::generic::egl::context::{ContextDescriptor, NativeContext}; -thread_local! { - #[doc(hidden)] - pub static GL_FUNCTIONS: Gl = Gl::load_with(context::get_proc_address); -} - /// Represents an OpenGL rendering context. /// /// A context allows you to issue rendering commands to a surface. When initially created, a @@ -35,7 +30,7 @@ thread_local! { /// allow for sharing of texture data. Contexts are local to a single thread and device. /// /// A context must be explicitly destroyed with `destroy_context()`, or a panic will occur. -pub struct Context(pub(crate) EGLBackedContext); +pub struct Context(pub(crate) EGLBackedContext, pub(crate) Gl); impl Device { /// Creates a context descriptor with the given attributes. @@ -74,13 +69,17 @@ impl Device { share_with: Option<&Context>, ) -> Result { unsafe { - EGLBackedContext::new( + let context = EGLBackedContext::new( self.native_connection.egl_display, descriptor, share_with.map(|ctx| &ctx.0), self.gl_api(), - ) - .map(Context) + )?; + context.make_current(self.native_connection.egl_display)?; + Ok(Context( + context, + Gl::from_loader_function(context::get_proc_address), + )) } } @@ -94,9 +93,10 @@ impl Device { &self, native_context: NativeContext, ) -> Result { - Ok(Context(EGLBackedContext::from_native_context( - native_context, - ))) + Ok(Context( + EGLBackedContext::from_native_context(native_context), + Gl::from_loader_function(context::get_proc_address), + )) } /// Destroys a context. @@ -122,13 +122,13 @@ impl Device { /// Returns the descriptor that this context was created with. #[inline] pub fn context_descriptor(&self, context: &Context) -> ContextDescriptor { - GL_FUNCTIONS.with(|gl| unsafe { + unsafe { ContextDescriptor::from_egl_context( - gl, + context::get_proc_address, self.native_connection.egl_display, context.0.egl_context, ) - }) + } } /// Makes the context the current OpenGL context for this thread. @@ -211,17 +211,12 @@ impl Device { &self, context: &mut Context, ) -> Result, Error> { - GL_FUNCTIONS.with(|gl| { - unsafe { - // Flush to avoid races on Mesa/Intel and possibly other GPUs. - gl.Flush(); - - context - .0 - .unbind_surface(gl, self.native_connection.egl_display) - .map(|maybe_surface| maybe_surface.map(Surface)) - } - }) + unsafe { + context + .0 + .unbind_surface(&context.1, self.native_connection.egl_display) + .map(|maybe_surface| maybe_surface.map(Surface)) + } } /// Returns a unique ID representing a context. diff --git a/src/platform/unix/x11/surface.rs b/src/platform/unix/x11/surface.rs index 381e450f..8319229f 100644 --- a/src/platform/unix/x11/surface.rs +++ b/src/platform/unix/x11/surface.rs @@ -2,23 +2,23 @@ // //! A surface implementation using X11 surfaces backed by TextureImage. -use super::context::{Context, GL_FUNCTIONS}; +use super::context::Context; use super::device::Device; use crate::egl; use crate::egl::types::EGLint; use crate::gl; -use crate::gl::types::{GLenum, GLuint}; use crate::platform::generic::egl::context; use crate::platform::generic::egl::surface::{EGLBackedSurface, EGLSurfaceTexture}; use crate::{Error, SurfaceAccess, SurfaceInfo, SurfaceType}; use euclid::default::Size2D; +use glow::Texture; use std::marker::PhantomData; use std::os::raw::c_void; use x11::xlib::{Window, XGetGeometry}; // FIXME(pcwalton): Is this right, or should it be `TEXTURE_EXTERNAL_OES`? -const SURFACE_GL_TEXTURE_TARGET: GLenum = gl::TEXTURE_2D; +const SURFACE_GL_TEXTURE_TARGET: u32 = gl::TEXTURE_2D; /// Represents a hardware buffer of pixels that can be rendered to via the CPU or GPU and either /// displayed in a native widget or bound to a texture for reading. @@ -86,16 +86,15 @@ impl Device { let _guard = self.temporarily_make_context_current(context)?; let context_descriptor = self.context_descriptor(context); let context_attributes = self.context_descriptor_attributes(&context_descriptor); - GL_FUNCTIONS.with(|gl| { - Ok(Surface(EGLBackedSurface::new_generic( - gl, - self.native_connection.egl_display, - context.0.egl_context, - context.0.id, - &context_attributes, - size, - ))) - }) + + Ok(Surface(EGLBackedSurface::new_generic( + &context.1, + self.native_connection.egl_display, + context.0.egl_context, + context.0.id, + &context_attributes, + size, + ))) } unsafe fn create_window_surface( @@ -156,10 +155,10 @@ impl Device { Err(err) => return Err((err, surface)), }; - GL_FUNCTIONS.with(|gl| match surface.0.to_surface_texture(gl) { + match surface.0.to_surface_texture(&context.1) { Ok(surface_texture) => Ok(SurfaceTexture(surface_texture)), Err((err, surface)) => Err((err, Surface(surface))), - }) + } } /// Destroys a surface. @@ -174,11 +173,9 @@ impl Device { context: &mut Context, surface: &mut Surface, ) -> Result<(), Error> { - GL_FUNCTIONS.with(|gl| { - let egl_display = self.native_connection.egl_display; - surface.0.destroy(gl, egl_display, context.0.id)?; - Ok(()) - }) + let egl_display = self.native_connection.egl_display; + surface.0.destroy(&context.1, egl_display, context.0.id)?; + Ok(()) } /// Destroys a surface texture and returns the underlying surface. @@ -194,7 +191,7 @@ impl Device { surface_texture: SurfaceTexture, ) -> Result { match self.temporarily_make_context_current(context) { - Ok(_guard) => GL_FUNCTIONS.with(|gl| Ok(Surface(surface_texture.0.destroy(gl)))), + Ok(_guard) => Ok(Surface(surface_texture.0.destroy(&context.1))), Err(err) => Err((err, surface_texture)), } } @@ -233,7 +230,7 @@ impl Device { /// /// This will be `GL_TEXTURE_2D` or `GL_TEXTURE_RECTANGLE`, depending on platform. #[inline] - pub fn surface_gl_texture_target(&self) -> GLenum { + pub fn surface_gl_texture_target(&self) -> u32 { SURFACE_GL_TEXTURE_TARGET } @@ -251,7 +248,7 @@ impl Device { /// /// It is only legal to read from, not write to, this texture object. #[inline] - pub fn surface_texture_object(&self, surface_texture: &SurfaceTexture) -> GLuint { + pub fn surface_texture_object(&self, surface_texture: &SurfaceTexture) -> Option { surface_texture.0.texture_object } } diff --git a/src/platform/windows/angle/context.rs b/src/platform/windows/angle/context.rs index 86daafff..b7cd0a42 100644 --- a/src/platform/windows/angle/context.rs +++ b/src/platform/windows/angle/context.rs @@ -14,6 +14,7 @@ use crate::platform::generic::egl::surface::ExternalEGLSurfaces; use crate::surface::Framebuffer; use crate::{ContextAttributes, Error, Gl, SurfaceInfo}; +use glow::HasContext; use std::mem; use std::os::raw::c_void; use std::thread; @@ -22,11 +23,6 @@ use winapi::um::winbase::INFINITE; pub use crate::platform::generic::egl::context::{ContextDescriptor, NativeContext}; -thread_local! { - #[doc(hidden)] - pub static GL_FUNCTIONS: Gl = Gl::load_with(context::get_proc_address); -} - /// Represents an OpenGL rendering context. /// /// A context allows you to issue rendering commands to a surface. When initially created, a @@ -48,6 +44,7 @@ pub struct Context { pub(crate) id: ContextID, framebuffer: Framebuffer, context_is_owned: bool, + pub(crate) gl: Gl, } impl Drop for Context { @@ -102,11 +99,26 @@ impl Device { self.gl_api(), )?; + EGL_FUNCTIONS.with(|egl| { + let result = egl.MakeCurrent( + self.egl_display, + egl::NO_SURFACE, + egl::NO_SURFACE, + egl_context, + ); + if result == egl::FALSE { + let err = egl.GetError().to_windowing_api_error(); + return Err(Error::MakeCurrentFailed(err)); + } + Ok(()) + }); + let context = Context { egl_context, id: *next_context_id, framebuffer: Framebuffer::None, context_is_owned: true, + gl: Gl::from_loader_function(context::get_proc_address), }; next_context_id.0 += 1; Ok(context) @@ -133,6 +145,7 @@ impl Device { read: native_context.egl_read_surface, }), context_is_owned: false, + gl: Gl::from_loader_function(context::get_proc_address), }; next_context_id.0 += 1; @@ -174,9 +187,11 @@ impl Device { /// Returns the descriptor that this context was created with. pub fn context_descriptor(&self, context: &Context) -> ContextDescriptor { unsafe { - GL_FUNCTIONS.with(|gl| { - ContextDescriptor::from_egl_context(gl, self.egl_display, context.egl_context) - }) + ContextDescriptor::from_egl_context( + context::get_proc_address, + self.egl_display, + context.egl_context, + ) } } @@ -287,7 +302,7 @@ impl Device { if surface.uses_gl_finish() { if let Ok(_guard) = self.temporarily_make_context_current(context) { unsafe { - GL_FUNCTIONS.with(|gl| gl.Finish()); + context.gl.finish(); } } } diff --git a/src/platform/windows/angle/surface.rs b/src/platform/windows/angle/surface.rs index 57932ec6..f0278c47 100644 --- a/src/platform/windows/angle/surface.rs +++ b/src/platform/windows/angle/surface.rs @@ -2,14 +2,13 @@ // //! Surface management for Direct3D 11 on Windows using the ANGLE library as a frontend. -use super::context::{Context, ContextDescriptor, GL_FUNCTIONS}; +use super::context::{Context, ContextDescriptor}; use super::device::Device; use crate::context::ContextID; use crate::egl::types::EGLNativeWindowType; use crate::egl::types::EGLSurface; use crate::egl::{self, EGLint}; use crate::gl; -use crate::gl::types::{GLenum, GLint, GLuint}; use crate::platform::generic::egl::device::EGL_FUNCTIONS; use crate::platform::generic::egl::error::ToWindowingApiError; use crate::platform::generic::egl::ffi::EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE; @@ -19,6 +18,7 @@ use crate::platform::generic::egl::ffi::EGL_EXTENSION_FUNCTIONS; use crate::{Error, SurfaceAccess, SurfaceID, SurfaceInfo, SurfaceType}; use euclid::default::Size2D; +use glow::HasContext; use std::fmt::{self, Debug, Formatter}; use std::marker::PhantomData; use std::os::raw::c_void; @@ -32,7 +32,7 @@ use winapi::um::winbase::INFINITE; use winapi::um::winnt::HANDLE; use wio::com::ComPtr; -const SURFACE_GL_TEXTURE_TARGET: GLenum = gl::TEXTURE_2D; +const SURFACE_GL_TEXTURE_TARGET: u32 = gl::TEXTURE_2D; /// Represents a hardware buffer of pixels that can be rendered to via the CPU or GPU and either /// displayed in a native widget or bound to a texture for reading. @@ -71,7 +71,7 @@ pub struct SurfaceTexture { pub(crate) surface: Surface, pub(crate) local_egl_surface: EGLSurface, pub(crate) local_keyed_mutex: Option>, - pub(crate) gl_texture: GLuint, + pub(crate) gl_texture: Option, pub(crate) phantom: PhantomData<*const ()>, } @@ -386,50 +386,36 @@ impl Device { unsafe { let _guard = self.temporarily_make_context_current(context); - GL_FUNCTIONS.with(|gl| { - // Then bind that surface to the texture. - let mut texture = 0; - gl.GenTextures(1, &mut texture); - debug_assert_ne!(texture, 0); + let gl = &context.gl; + // Then bind that surface to the texture. + let mut texture = gl.create_texture().unwrap(); - gl.BindTexture(gl::TEXTURE_2D, texture); - if egl.BindTexImage( - self.egl_display, - local_egl_surface, - egl::BACK_BUFFER as GLint, - ) == egl::FALSE - { - let windowing_api_error = egl.GetError().to_windowing_api_error(); - return Err(( - Error::SurfaceTextureCreationFailed(windowing_api_error), - surface, - )); - } - - // Initialize the texture, for convenience. - gl.TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as GLint); - gl.TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as GLint); - gl.TexParameteri( - gl::TEXTURE_2D, - gl::TEXTURE_WRAP_S, - gl::CLAMP_TO_EDGE as GLint, - ); - gl.TexParameteri( - gl::TEXTURE_2D, - gl::TEXTURE_WRAP_T, - gl::CLAMP_TO_EDGE as GLint, - ); + gl.bind_texture(gl::TEXTURE_2D, Some(texture)); + if egl.BindTexImage(self.egl_display, local_egl_surface, egl::BACK_BUFFER as _) + == egl::FALSE + { + let windowing_api_error = egl.GetError().to_windowing_api_error(); + return Err(( + Error::SurfaceTextureCreationFailed(windowing_api_error), + surface, + )); + } - gl.BindTexture(gl::TEXTURE_2D, 0); - debug_assert_eq!(gl.GetError(), gl::NO_ERROR); + // Initialize the texture, for convenience. + gl.tex_parameter_i32(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as _); + gl.tex_parameter_i32(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as _); + gl.tex_parameter_i32(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as _); + gl.tex_parameter_i32(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as _); - Ok(SurfaceTexture { - surface, - local_egl_surface, - local_keyed_mutex, - gl_texture: texture, - phantom: PhantomData, - }) + gl.bind_texture(gl::TEXTURE_2D, None); + debug_assert_eq!(gl.get_error(), gl::NO_ERROR); + + Ok(SurfaceTexture { + surface, + local_egl_surface, + local_keyed_mutex, + gl_texture: Some(texture), + phantom: PhantomData, }) } }) @@ -500,12 +486,13 @@ impl Device { /// occur. pub fn destroy_surface_texture( &self, - _: &mut Context, + context: &mut Context, mut surface_texture: SurfaceTexture, ) -> Result { unsafe { - GL_FUNCTIONS.with(|gl| gl.DeleteTextures(1, &surface_texture.gl_texture)); - surface_texture.gl_texture = 0; + if let Some(texture) = surface_texture.gl_texture.take() { + context.gl.delete_texture(texture); + } if let Some(ref local_keyed_mutex) = surface_texture.local_keyed_mutex { let result = local_keyed_mutex.ReleaseSync(0); @@ -524,7 +511,7 @@ impl Device { /// /// This will be `GL_TEXTURE_2D` or `GL_TEXTURE_RECTANGLE`, depending on platform. #[inline] - pub fn surface_gl_texture_target(&self) -> GLenum { + pub fn surface_gl_texture_target(&self) -> u32 { SURFACE_GL_TEXTURE_TARGET } @@ -580,7 +567,7 @@ impl Device { size: surface.size, id: surface.id(), context_id: surface.context_id, - framebuffer_object: 0, + framebuffer_object: None, } } @@ -588,7 +575,10 @@ impl Device { /// /// It is only legal to read from, not write to, this texture object. #[inline] - pub fn surface_texture_object(&self, surface_texture: &SurfaceTexture) -> GLuint { + pub fn surface_texture_object( + &self, + surface_texture: &SurfaceTexture, + ) -> Option { surface_texture.gl_texture } } diff --git a/src/platform/windows/wgl/context.rs b/src/platform/windows/wgl/context.rs index 6a021b3c..f1865b51 100644 --- a/src/platform/windows/wgl/context.rs +++ b/src/platform/windows/wgl/context.rs @@ -10,12 +10,15 @@ use crate::{ContextAttributeFlags, ContextAttributes, ContextID, Error, GLVersio use crate::{SurfaceInfo, WindowingApiError}; use crate::gl; -use crate::gl::types::{GLenum, GLint, GLuint}; +type GLenum = c_uint; +type GLint = c_int; +type GLuint = c_uint; use crate::Gl; +use glow::HasContext; use std::borrow::Cow; use std::ffi::{CStr, CString}; use std::mem; -use std::os::raw::{c_char, c_int, c_void}; +use std::os::raw::{c_char, c_int, c_uint, c_void}; use std::ptr; use std::sync::LazyLock; use std::thread; @@ -295,7 +298,7 @@ impl Device { assert_ne!(ok, FALSE); // Load the GL functions. - gl = Gl::load_with(get_proc_address); + gl = Gl::from_loader_function(get_proc_address); } // Create the initial context. @@ -331,7 +334,7 @@ impl Device { let _guard = CurrentContextGuard::new(); let ok = wglMakeCurrent(dc, native_context.0); assert_ne!(ok, FALSE); - Gl::load_with(get_proc_address) + Gl::from_loader_function(get_proc_address) }; let context = Context { @@ -453,11 +456,11 @@ impl Device { pub(crate) fn temporarily_bind_framebuffer<'a>( &self, context: &'a Context, - framebuffer: GLuint, + framebuffer: Option, ) -> FramebufferGuard<'a> { unsafe { let guard = FramebufferGuard::new(context); - context.gl.BindFramebuffer(gl::FRAMEBUFFER, framebuffer); + context.gl.bind_framebuffer(gl::FRAMEBUFFER, framebuffer); guard } } @@ -805,8 +808,8 @@ extern "system" fn extension_loader_window_proc( #[must_use] pub(crate) struct FramebufferGuard<'a> { context: &'a Context, - old_read_framebuffer: GLuint, - old_draw_framebuffer: GLuint, + old_read_framebuffer: Option, + old_draw_framebuffer: Option, } impl<'a> Drop for FramebufferGuard<'a> { @@ -815,10 +818,10 @@ impl<'a> Drop for FramebufferGuard<'a> { unsafe { self.context .gl - .BindFramebuffer(gl::READ_FRAMEBUFFER, self.old_read_framebuffer); + .bind_framebuffer(gl::READ_FRAMEBUFFER, self.old_read_framebuffer); self.context .gl - .BindFramebuffer(gl::DRAW_FRAMEBUFFER, self.old_draw_framebuffer); + .bind_framebuffer(gl::DRAW_FRAMEBUFFER, self.old_draw_framebuffer); } } } @@ -826,18 +829,17 @@ impl<'a> Drop for FramebufferGuard<'a> { impl<'a> FramebufferGuard<'a> { fn new(context: &'a Context) -> FramebufferGuard<'a> { unsafe { - let (mut current_draw_framebuffer, mut current_read_framebuffer) = (0, 0); - context + let current_draw_framebuffer = context .gl - .GetIntegerv(gl::DRAW_FRAMEBUFFER_BINDING, &mut current_draw_framebuffer); - context + .get_parameter_framebuffer(gl::DRAW_FRAMEBUFFER_BINDING); + let current_read_framebuffer = context .gl - .GetIntegerv(gl::READ_FRAMEBUFFER_BINDING, &mut current_read_framebuffer); + .get_parameter_framebuffer(gl::READ_FRAMEBUFFER_BINDING); FramebufferGuard { context, - old_draw_framebuffer: current_draw_framebuffer as GLuint, - old_read_framebuffer: current_read_framebuffer as GLuint, + old_draw_framebuffer: current_draw_framebuffer, + old_read_framebuffer: current_read_framebuffer, } } } diff --git a/src/platform/windows/wgl/surface.rs b/src/platform/windows/wgl/surface.rs index a8e2d6f5..e93af983 100644 --- a/src/platform/windows/wgl/surface.rs +++ b/src/platform/windows/wgl/surface.rs @@ -9,9 +9,12 @@ use crate::renderbuffers::Renderbuffers; use crate::{ContextID, Error, SurfaceAccess, SurfaceID, SurfaceInfo, SurfaceType}; use crate::gl; -use crate::gl::types::{GLenum, GLint, GLuint}; +type GLenum = c_uint; +type GLint = c_int; use crate::gl_utils; use euclid::default::Size2D; +use glow::HasContext; +use std::ffi::{c_int, c_uint}; use std::fmt::{self, Debug, Formatter}; use std::marker::PhantomData; use std::mem; @@ -67,8 +70,8 @@ pub(crate) enum Win32Objects { d3d11_texture: ComPtr, dxgi_share_handle: HANDLE, gl_dx_interop_object: HANDLE, - gl_texture: GLuint, - gl_framebuffer: GLuint, + gl_texture: Option, + gl_framebuffer: Option, renderbuffers: Renderbuffers, }, Widget { @@ -90,7 +93,7 @@ pub struct SurfaceTexture { #[allow(dead_code)] pub(crate) local_d3d11_texture: ComPtr, local_gl_dx_interop_object: HANDLE, - pub(crate) gl_texture: GLuint, + pub(crate) gl_texture: Option, pub(crate) phantom: PhantomData<*const ()>, } @@ -209,14 +212,13 @@ impl Device { assert_ne!(ok, FALSE); // Make our texture object on the GL side. - let mut gl_texture = 0; - context.gl.GenTextures(1, &mut gl_texture); + let gl_texture = context.gl.create_texture().unwrap(); // Bind the GL texture to the D3D11 texture. let gl_dx_interop_object = (dx_interop_functions.DXRegisterObjectNV)( self.gl_dx_interop_device, d3d11_texture.as_raw() as *mut c_void, - gl_texture, + gl_texture.0.get(), gl::TEXTURE_2D, WGL_ACCESS_READ_WRITE_NV, ); @@ -231,16 +233,15 @@ impl Device { } // Build our FBO. - let mut gl_framebuffer = 0; - context.gl.GenFramebuffers(1, &mut gl_framebuffer); - let _guard = self.temporarily_bind_framebuffer(context, gl_framebuffer); + let gl_framebuffer = context.gl.create_framebuffer().unwrap(); + let _guard = self.temporarily_bind_framebuffer(context, Some(gl_framebuffer)); // Attach the reflected D3D11 texture to that FBO. - context.gl.FramebufferTexture2D( + context.gl.framebuffer_texture_2d( gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0, SURFACE_GL_TEXTURE_TARGET, - gl_texture, + Some(gl_texture), 0, ); @@ -260,8 +261,8 @@ impl Device { d3d11_texture, dxgi_share_handle, gl_dx_interop_object, - gl_texture, - gl_framebuffer, + gl_texture: Some(gl_texture), + gl_framebuffer: Some(gl_framebuffer), renderbuffers, }, destroyed: false, @@ -339,11 +340,13 @@ impl Device { } => { renderbuffers.destroy(&context.gl); - gl_utils::destroy_framebuffer(&context.gl, *gl_framebuffer); - *gl_framebuffer = 0; + if let Some(fbo) = gl_framebuffer.take() { + gl_utils::destroy_framebuffer(&context.gl, fbo); + } - context.gl.DeleteTextures(1, gl_texture); - *gl_texture = 0; + if let Some(texture) = gl_texture.take() { + context.gl.delete_texture(texture); + } let ok = (dx_interop_functions.DXUnregisterObjectNV)( self.gl_dx_interop_device, @@ -417,14 +420,13 @@ impl Device { assert_ne!(ok, FALSE); // Create a GL texture. - let mut gl_texture = 0; - context.gl.GenTextures(1, &mut gl_texture); + let gl_texture = context.gl.create_texture().unwrap(); // Register that texture with GL/DX interop. let mut local_gl_dx_interop_object = (dx_interop_functions.DXRegisterObjectNV)( self.gl_dx_interop_device, local_d3d11_texture.as_raw() as *mut c_void, - gl_texture, + gl_texture.0.get(), gl::TEXTURE_2D, WGL_ACCESS_READ_ONLY_NV, ); @@ -439,19 +441,23 @@ impl Device { // Initialize the texture, for convenience. // FIXME(pcwalton): We should probably reset the bound texture after this. - context.gl.BindTexture(gl::TEXTURE_2D, gl_texture); - context - .gl - .TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as GLint); - context - .gl - .TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as GLint); - context.gl.TexParameteri( + context.gl.bind_texture(gl::TEXTURE_2D, Some(gl_texture)); + context.gl.tex_parameter_i32( + gl::TEXTURE_2D, + gl::TEXTURE_MAG_FILTER, + gl::LINEAR as GLint, + ); + context.gl.tex_parameter_i32( + gl::TEXTURE_2D, + gl::TEXTURE_MIN_FILTER, + gl::LINEAR as GLint, + ); + context.gl.tex_parameter_i32( gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as GLint, ); - context.gl.TexParameteri( + context.gl.tex_parameter_i32( gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as GLint, @@ -462,7 +468,7 @@ impl Device { surface, local_d3d11_texture, local_gl_dx_interop_object, - gl_texture, + gl_texture: Some(gl_texture), phantom: PhantomData, }) } @@ -508,8 +514,9 @@ impl Device { surface_texture.local_gl_dx_interop_object = INVALID_HANDLE_VALUE; // Destroy the GL texture. - context.gl.DeleteTextures(1, &surface_texture.gl_texture); - surface_texture.gl_texture = 0; + if let Some(texture) = surface_texture.gl_texture.take() { + context.gl.delete_texture(texture); + } } Ok(surface_texture.surface) @@ -627,7 +634,7 @@ impl Device { context_id: surface.context_id, framebuffer_object: match surface.win32_objects { Win32Objects::Texture { gl_framebuffer, .. } => gl_framebuffer, - Win32Objects::Widget { .. } => 0, + Win32Objects::Widget { .. } => None, }, } } @@ -636,7 +643,10 @@ impl Device { /// /// It is only legal to read from, not write to, this texture object. #[inline] - pub fn surface_texture_object(&self, surface_texture: &SurfaceTexture) -> GLuint { + pub fn surface_texture_object( + &self, + surface_texture: &SurfaceTexture, + ) -> Option { surface_texture.gl_texture } } diff --git a/src/renderbuffers.rs b/src/renderbuffers.rs index 515313bb..45b5d200 100644 --- a/src/renderbuffers.rs +++ b/src/renderbuffers.rs @@ -4,25 +4,29 @@ use crate::context::{ContextAttributeFlags, ContextAttributes}; use crate::gl; -use crate::gl::types::GLuint; use crate::Gl; use std::thread; use euclid::default::Size2D; +use gl::Renderbuffer; +use glow::HasContext; pub(crate) enum Renderbuffers { - IndividualDepthStencil { depth: GLuint, stencil: GLuint }, - CombinedDepthStencil(GLuint), + IndividualDepthStencil { + depth: Option, + stencil: Option, + }, + CombinedDepthStencil(Option), } impl Drop for Renderbuffers { fn drop(&mut self) { match *self { Renderbuffers::IndividualDepthStencil { - depth: 0, - stencil: 0, + depth: None, + stencil: None, } - | Renderbuffers::CombinedDepthStencil(0) => {} + | Renderbuffers::CombinedDepthStencil(None) => {} _ => { if !thread::panicking() { panic!("Should have destroyed the FBO renderbuffers with `destroy()`!") @@ -43,24 +47,23 @@ impl Renderbuffers { .flags .contains(ContextAttributeFlags::DEPTH | ContextAttributeFlags::STENCIL) { - let mut renderbuffer = 0; - gl.GenRenderbuffers(1, &mut renderbuffer); - gl.BindRenderbuffer(gl::RENDERBUFFER, renderbuffer); - gl.RenderbufferStorage( + let renderbuffer = gl.create_renderbuffer().unwrap(); + gl.bind_renderbuffer(gl::RENDERBUFFER, Some(renderbuffer)); + gl.renderbuffer_storage( gl::RENDERBUFFER, gl::DEPTH24_STENCIL8, size.width, size.height, ); - gl.BindRenderbuffer(gl::RENDERBUFFER, 0); - return Renderbuffers::CombinedDepthStencil(renderbuffer); + gl.bind_renderbuffer(gl::RENDERBUFFER, None); + return Renderbuffers::CombinedDepthStencil(Some(renderbuffer)); } - let (mut depth_renderbuffer, mut stencil_renderbuffer) = (0, 0); + let (mut depth_renderbuffer, mut stencil_renderbuffer) = (None, None); if attributes.flags.contains(ContextAttributeFlags::DEPTH) { - gl.GenRenderbuffers(1, &mut depth_renderbuffer); - gl.BindRenderbuffer(gl::RENDERBUFFER, depth_renderbuffer); - gl.RenderbufferStorage( + depth_renderbuffer = Some(gl.create_renderbuffer().unwrap()); + gl.bind_renderbuffer(gl::RENDERBUFFER, depth_renderbuffer); + gl.renderbuffer_storage( gl::RENDERBUFFER, gl::DEPTH_COMPONENT24, size.width, @@ -68,16 +71,16 @@ impl Renderbuffers { ); } if attributes.flags.contains(ContextAttributeFlags::STENCIL) { - gl.GenRenderbuffers(1, &mut stencil_renderbuffer); - gl.BindRenderbuffer(gl::RENDERBUFFER, stencil_renderbuffer); - gl.RenderbufferStorage( + stencil_renderbuffer = Some(gl.create_renderbuffer().unwrap()); + gl.bind_renderbuffer(gl::RENDERBUFFER, stencil_renderbuffer); + gl.renderbuffer_storage( gl::RENDERBUFFER, gl::STENCIL_INDEX8, size.width, size.height, ); } - gl.BindRenderbuffer(gl::RENDERBUFFER, 0); + gl.bind_renderbuffer(gl::RENDERBUFFER, None); Renderbuffers::IndividualDepthStencil { depth: depth_renderbuffer, @@ -90,8 +93,8 @@ impl Renderbuffers { unsafe { match *self { Renderbuffers::CombinedDepthStencil(renderbuffer) => { - if renderbuffer != 0 { - gl.FramebufferRenderbuffer( + if renderbuffer.is_some() { + gl.framebuffer_renderbuffer( gl::FRAMEBUFFER, gl::DEPTH_STENCIL_ATTACHMENT, gl::RENDERBUFFER, @@ -103,16 +106,16 @@ impl Renderbuffers { depth: depth_renderbuffer, stencil: stencil_renderbuffer, } => { - if depth_renderbuffer != 0 { - gl.FramebufferRenderbuffer( + if depth_renderbuffer.is_some() { + gl.framebuffer_renderbuffer( gl::FRAMEBUFFER, gl::DEPTH_ATTACHMENT, gl::RENDERBUFFER, depth_renderbuffer, ); } - if stencil_renderbuffer != 0 { - gl.FramebufferRenderbuffer( + if stencil_renderbuffer.is_some() { + gl.framebuffer_renderbuffer( gl::FRAMEBUFFER, gl::STENCIL_ATTACHMENT, gl::RENDERBUFFER, @@ -126,26 +129,23 @@ impl Renderbuffers { pub(crate) fn destroy(&mut self, gl: &Gl) { unsafe { - gl.BindRenderbuffer(gl::RENDERBUFFER, 0); + gl.bind_renderbuffer(gl::RENDERBUFFER, None); match *self { Renderbuffers::CombinedDepthStencil(ref mut renderbuffer) => { - if *renderbuffer != 0 { - gl.DeleteRenderbuffers(1, renderbuffer); - *renderbuffer = 0; + if let Some(renderbuffer) = renderbuffer.take() { + gl.delete_renderbuffer(renderbuffer); } } Renderbuffers::IndividualDepthStencil { depth: ref mut depth_renderbuffer, stencil: ref mut stencil_renderbuffer, } => { - if *stencil_renderbuffer != 0 { - gl.DeleteRenderbuffers(1, stencil_renderbuffer); - *stencil_renderbuffer = 0; + if let Some(stencil_renderbuffer) = stencil_renderbuffer.take() { + gl.delete_renderbuffer(stencil_renderbuffer); } - if *depth_renderbuffer != 0 { - gl.DeleteRenderbuffers(1, depth_renderbuffer); - *depth_renderbuffer = 0; + if let Some(depth_renderbuffer) = depth_renderbuffer.take() { + gl.delete_renderbuffer(depth_renderbuffer); } } } diff --git a/src/surface.rs b/src/surface.rs index e984b85b..29262565 100644 --- a/src/surface.rs +++ b/src/surface.rs @@ -4,7 +4,6 @@ use crate::context::ContextID; -use crate::gl::types::GLuint; use euclid::default::Size2D; use std::fmt::{self, Display, Formatter}; @@ -27,7 +26,7 @@ pub struct SurfaceInfo { /// The OpenGL framebuffer object that can be used to render to this surface. /// /// This is only valid when the surface is actually attached to a context. - pub framebuffer_object: GLuint, + pub framebuffer_object: Option, } // The default framebuffer for a context. diff --git a/src/tests.rs b/src/tests.rs index 899a142f..72ee8199 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -13,14 +13,13 @@ use super::context::{Context, ContextDescriptor, NativeContext}; use super::device::{Adapter, Device}; use super::surface::Surface; use crate::gl; -use crate::gl::types::{GLenum, GLuint}; use crate::{ContextAttributeFlags, ContextAttributes, Error, GLApi, GLVersion, Gl, SurfaceAccess}; use crate::{SurfaceType, WindowingApiError}; use euclid::default::Size2D; +use glow::{Framebuffer, HasContext, PixelPackData, Texture}; #[cfg(not(feature = "sm-test"))] use serial_test::serial; -use std::os::raw::c_void; use std::sync::mpsc; use std::thread; @@ -172,10 +171,10 @@ pub fn test_context_creation() { } } -// Tests that newly-created contexts are not immediately made current (issue #7). +// Tests that newly-created contexts are made current (https://github.com/pcwalton/surfman/issues/7). #[cfg_attr(not(feature = "sm-test"), test)] #[cfg_attr(not(feature = "sm-test"), serial)] -pub fn test_newly_created_contexts_are_not_current() { +pub fn test_newly_created_contexts_are_current() { let connection = Connection::new().unwrap(); let adapter = connection .create_low_power_adapter() @@ -200,12 +199,17 @@ pub fn test_newly_created_contexts_are_not_current() { device.make_no_context_current().unwrap(); let mut context = device.create_context(&context_descriptor, None).unwrap(); - let gl = Gl::load_with(|symbol| device.get_proc_address(&context, symbol)); + // This fails if context is not current + let gl = + unsafe { Gl::from_loader_function(|symbol| device.get_proc_address(&context, symbol)) }; unsafe { - // Check to make sure GL calls don't work before a context is made current. + // Check to make sure GL calls don't work, because there is no surface. clear(&gl, &[255, 0, 0, 255]); + assert_eq!(gl.get_error(), glow::INVALID_FRAMEBUFFER_OPERATION); assert_ne!(get_pixel_from_bottom_row(&gl), [255, 0, 0, 255]); + assert_eq!(gl.get_error(), glow::INVALID_FRAMEBUFFER_OPERATION); + assert_eq!(gl.get_error(), glow::NO_ERROR); // Make a context current. let surface = make_surface(&mut device, &context); @@ -218,7 +222,7 @@ pub fn test_newly_created_contexts_are_not_current() { .unwrap() .unwrap() .framebuffer_object; - gl.BindFramebuffer(gl::FRAMEBUFFER, framebuffer_object); + gl.bind_framebuffer(gl::FRAMEBUFFER, framebuffer_object); // Now that a context is current, GL calls should work. clear(&gl, &[0, 255, 0, 255]); @@ -362,18 +366,18 @@ pub fn test_gl() { unsafe { // Check basic clear. - env.gl.ClearColor(0.0, 1.0, 0.0, 1.0); - env.gl.Clear(gl::COLOR_BUFFER_BIT); + env.gl.clear_color(0.0, 1.0, 0.0, 1.0); + env.gl.clear(gl::COLOR_BUFFER_BIT); assert_eq!(get_pixel_from_bottom_row(&env.gl), [0, 255, 0, 255]); // Check that GL commands don't work after `make_no_context_current()`. // // The `glGetError()` calls are there to clear any errors. env.device.make_no_context_current().unwrap(); - env.gl.ClearColor(1.0, 0.0, 0.0, 1.0); - env.gl.GetError(); - env.gl.Clear(gl::COLOR_BUFFER_BIT); - env.gl.GetError(); + env.gl.clear_color(1.0, 0.0, 0.0, 1.0); + env.gl.get_error(); + env.gl.clear(gl::COLOR_BUFFER_BIT); + env.gl.get_error(); env.device.make_context_current(&env.context).unwrap(); let framebuffer_object = env @@ -382,7 +386,7 @@ pub fn test_gl() { .unwrap() .unwrap() .framebuffer_object; - env.gl.BindFramebuffer(gl::FRAMEBUFFER, framebuffer_object); + env.gl.bind_framebuffer(gl::FRAMEBUFFER, framebuffer_object); assert_eq!(get_pixel_from_bottom_row(&env.gl), [0, 255, 0, 255]); // Make sure GL commands don't work when no surface is attached. @@ -393,15 +397,15 @@ pub fn test_gl() { .unbind_surface_from_context(&mut env.context) .unwrap() .unwrap(); - env.gl.BindFramebuffer(gl::FRAMEBUFFER, 0); - env.gl.ClearColor(1.0, 0.0, 0.0, 1.0); - env.gl.GetError(); - env.gl.Clear(gl::COLOR_BUFFER_BIT); - env.gl.GetError(); + env.gl.bind_framebuffer(gl::FRAMEBUFFER, None); + env.gl.clear_color(1.0, 0.0, 0.0, 1.0); + env.gl.get_error(); + env.gl.clear(gl::COLOR_BUFFER_BIT); + env.gl.get_error(); env.device .bind_surface_to_context(&mut env.context, green_surface) .unwrap(); - env.gl.BindFramebuffer(gl::FRAMEBUFFER, framebuffer_object); + env.gl.bind_framebuffer(gl::FRAMEBUFFER, framebuffer_object); assert_eq!(get_pixel_from_bottom_row(&env.gl), [0, 255, 0, 255]); // Make sure GL commands go to the right surface. @@ -421,9 +425,9 @@ pub fn test_gl() { .unwrap() .framebuffer_object; env.gl - .BindFramebuffer(gl::FRAMEBUFFER, red_framebuffer_object); - env.gl.ClearColor(1.0, 0.0, 0.0, 1.0); - env.gl.Clear(gl::COLOR_BUFFER_BIT); + .bind_framebuffer(gl::FRAMEBUFFER, red_framebuffer_object); + env.gl.clear_color(1.0, 0.0, 0.0, 1.0); + env.gl.clear(gl::COLOR_BUFFER_BIT); assert_eq!(get_pixel_from_bottom_row(&env.gl), [255, 0, 0, 255]); let mut red_surface = env @@ -434,7 +438,7 @@ pub fn test_gl() { env.device .bind_surface_to_context(&mut env.context, green_surface) .unwrap(); - env.gl.BindFramebuffer(gl::FRAMEBUFFER, framebuffer_object); + env.gl.bind_framebuffer(gl::FRAMEBUFFER, framebuffer_object); assert_eq!(get_pixel_from_bottom_row(&env.gl), [0, 255, 0, 255]); // Clean up. @@ -480,27 +484,31 @@ pub fn test_surface_texture_blit_framebuffer() { .unwrap() .framebuffer_object; env.gl - .BindFramebuffer(gl::FRAMEBUFFER, main_framebuffer_object); + .bind_framebuffer(gl::FRAMEBUFFER, main_framebuffer_object); clear(&env.gl, &[255, 0, 0, 255]); assert_eq!(get_pixel_from_bottom_row(&env.gl), [255, 0, 0, 255]); - let mut green_framebuffer_object = make_fbo( + let green_framebuffer_object = make_fbo( &env.gl, env.device.surface_gl_texture_target(), env.device.surface_texture_object(&green_surface_texture), ); // Blit to main framebuffer. - blit_fbo(&env.gl, main_framebuffer_object, green_framebuffer_object); + blit_fbo( + &env.gl, + main_framebuffer_object, + Some(green_framebuffer_object), + ); env.gl - .BindFramebuffer(gl::FRAMEBUFFER, main_framebuffer_object); + .bind_framebuffer(gl::FRAMEBUFFER, main_framebuffer_object); check_gl(&env.gl); assert_eq!(get_pixel_from_bottom_row(&env.gl), [0, 255, 0, 255]); // Clean up. - env.gl.BindFramebuffer(gl::FRAMEBUFFER, 0); + env.gl.bind_framebuffer(gl::FRAMEBUFFER, None); check_gl(&env.gl); - env.gl.DeleteFramebuffers(1, &mut green_framebuffer_object); + env.gl.delete_framebuffer(green_framebuffer_object); let mut green_surface = env .device @@ -552,7 +560,7 @@ pub fn test_cross_device_surface_texture_blit_framebuffer() { env.device.make_context_current(&env.context).unwrap(); assert_eq!(get_pixel_from_bottom_row(&env.gl), [255, 0, 0, 255]); - let mut green_framebuffer_object = make_fbo( + let green_framebuffer_object = make_fbo( &env.gl, env.device.surface_gl_texture_target(), env.device.surface_texture_object(&green_surface_texture), @@ -562,15 +570,15 @@ pub fn test_cross_device_surface_texture_blit_framebuffer() { blit_fbo( &env.gl, context_fbo(&env.device, &env.context), - green_framebuffer_object, + Some(green_framebuffer_object), ); bind_context_fbo(&env.gl, &env.device, &env.context); assert_eq!(get_pixel_from_bottom_row(&env.gl), [0, 255, 0, 255]); // Clean up. - env.gl.BindFramebuffer(gl::FRAMEBUFFER, 0); + env.gl.bind_framebuffer(gl::FRAMEBUFFER, None); check_gl(&env.gl); - env.gl.DeleteFramebuffers(1, &mut green_framebuffer_object); + env.gl.delete_framebuffer(green_framebuffer_object); let mut green_surface = env .device @@ -603,13 +611,14 @@ pub fn test_cross_thread_surface_texture_blit_framebuffer() { let mut context = device .create_context(&other_context_descriptor, None) .unwrap(); - let gl = Gl::load_with(|symbol| device.get_proc_address(&context, symbol)); let surface = make_surface(&mut device, &context); device .bind_surface_to_context(&mut context, surface) .unwrap(); device.make_context_current(&context).unwrap(); + let gl = + unsafe { Gl::from_loader_function(|symbol| device.get_proc_address(&context, symbol)) }; bind_context_fbo(&gl, &device, &context); clear(&gl, &[0, 255, 0, 255]); @@ -639,7 +648,7 @@ pub fn test_cross_thread_surface_texture_blit_framebuffer() { env.device.make_context_current(&env.context).unwrap(); assert_eq!(get_pixel_from_bottom_row(&env.gl), [255, 0, 0, 255]); - let mut green_framebuffer_object = make_fbo( + let green_framebuffer_object = make_fbo( &env.gl, env.device.surface_gl_texture_target(), env.device.surface_texture_object(&green_surface_texture), @@ -649,15 +658,15 @@ pub fn test_cross_thread_surface_texture_blit_framebuffer() { blit_fbo( &env.gl, context_fbo(&env.device, &env.context), - green_framebuffer_object, + Some(green_framebuffer_object), ); bind_context_fbo(&env.gl, &env.device, &env.context); assert_eq!(get_pixel_from_bottom_row(&env.gl), [0, 255, 0, 255]); // Clean up. - env.gl.BindFramebuffer(gl::FRAMEBUFFER, 0); + env.gl.bind_framebuffer(gl::FRAMEBUFFER, None); check_gl(&env.gl); - env.gl.DeleteFramebuffers(1, &mut green_framebuffer_object); + env.gl.delete_framebuffer(green_framebuffer_object); let green_surface = env .device @@ -705,7 +714,7 @@ pub fn test_surface_texture_right_side_up() { .unwrap() .framebuffer_object; env.gl - .BindFramebuffer(gl::FRAMEBUFFER, main_framebuffer_object); + .bind_framebuffer(gl::FRAMEBUFFER, main_framebuffer_object); clear(&env.gl, &[255, 0, 0, 255]); assert_eq!(get_pixel_from_bottom_row(&env.gl), [255, 0, 0, 255]); @@ -716,9 +725,13 @@ pub fn test_surface_texture_right_side_up() { ); // Blit to main framebuffer. - blit_fbo(&env.gl, main_framebuffer_object, subframebuffer_object); + blit_fbo( + &env.gl, + main_framebuffer_object, + Some(subframebuffer_object), + ); env.gl - .BindFramebuffer(gl::FRAMEBUFFER, main_framebuffer_object); + .bind_framebuffer(gl::FRAMEBUFFER, main_framebuffer_object); check_gl(&env.gl); assert_eq!(get_pixel_from_bottom_row(&env.gl), [0, 255, 0, 255]); assert_eq!( @@ -727,9 +740,9 @@ pub fn test_surface_texture_right_side_up() { ); // Clean up. - env.gl.BindFramebuffer(gl::FRAMEBUFFER, 0); + env.gl.bind_framebuffer(gl::FRAMEBUFFER, None); check_gl(&env.gl); - env.gl.DeleteFramebuffers(1, &mut subframebuffer_object); + env.gl.delete_framebuffer(subframebuffer_object); let mut subsurface = env .device @@ -746,6 +759,11 @@ pub fn test_surface_texture_right_side_up() { #[cfg_attr(not(feature = "sm-test"), test)] #[cfg_attr(not(feature = "sm-test"), serial)] pub fn test_depth_and_stencil() { + use core::slice; + use std::ptr::addr_of_mut; + + use glow::PixelPackData; + let connection = Connection::new().unwrap(); let adapter = connection .create_low_power_adapter() @@ -782,7 +800,9 @@ pub fn test_depth_and_stencil() { .unwrap(); device.make_context_current(&depth_context).unwrap(); - let gl = Gl::load_with(|symbol| device.get_proc_address(&depth_context, symbol)); + let gl = unsafe { + Gl::from_loader_function(|symbol| device.get_proc_address(&depth_context, symbol)) + }; unsafe { let framebuffer_object = device @@ -790,21 +810,24 @@ pub fn test_depth_and_stencil() { .unwrap() .unwrap() .framebuffer_object; - gl.BindFramebuffer(gl::FRAMEBUFFER, framebuffer_object); - gl.Viewport(0, 0, 640, 480); + gl.bind_framebuffer(gl::FRAMEBUFFER, framebuffer_object); + gl.viewport(0, 0, 640, 480); - gl.ClearDepth(0.5); - gl.Clear(gl::DEPTH_BUFFER_BIT); + gl.clear_depth(0.5); + gl.clear(gl::DEPTH_BUFFER_BIT); let mut depth_value: f32 = -1.0; - gl.ReadPixels( + gl.read_pixels( 0, 0, 1, 1, gl::DEPTH_COMPONENT, gl::FLOAT, - (&mut depth_value) as *mut f32 as *mut c_void, + PixelPackData::Slice(Some(slice::from_raw_parts_mut( + addr_of_mut!(depth_value) as *mut u8, + size_of_val(&depth_value), + ))), ); assert!( approx_eq(depth_value, 0.5), @@ -833,7 +856,9 @@ pub fn test_depth_and_stencil() { .unwrap(); device.make_context_current(&stencil_context).unwrap(); - let gl = Gl::load_with(|symbol| device.get_proc_address(&stencil_context, symbol)); + let gl = unsafe { + Gl::from_loader_function(|symbol| device.get_proc_address(&stencil_context, symbol)) + }; unsafe { let framebuffer_object = device @@ -841,21 +866,21 @@ pub fn test_depth_and_stencil() { .unwrap() .unwrap() .framebuffer_object; - gl.BindFramebuffer(gl::FRAMEBUFFER, framebuffer_object); - gl.Viewport(0, 0, 640, 480); + gl.bind_framebuffer(gl::FRAMEBUFFER, framebuffer_object); + gl.viewport(0, 0, 640, 480); - gl.ClearStencil(99); - gl.Clear(gl::STENCIL_BUFFER_BIT); + gl.clear_stencil(99); + gl.clear(gl::STENCIL_BUFFER_BIT); let mut stencil_value: u8 = 200; - gl.ReadPixels( + gl.read_pixels( 0, 0, 1, 1, gl::STENCIL_INDEX, gl::UNSIGNED_BYTE, - (&mut stencil_value) as *mut u8 as *mut c_void, + PixelPackData::Slice(Some(slice::from_raw_parts_mut(&mut stencil_value, 1))), ); assert_eq!(stencil_value, 99); } @@ -894,12 +919,12 @@ pub fn test_get_native_context() { fn bind_context_fbo(gl: &Gl, device: &Device, context: &Context) { unsafe { - gl.BindFramebuffer(gl::FRAMEBUFFER, context_fbo(device, context)); + gl.bind_framebuffer(gl::FRAMEBUFFER, context_fbo(device, context)); check_gl(gl); } } -fn context_fbo(device: &Device, context: &Context) -> GLuint { +fn context_fbo(device: &Device, context: &Context) -> Option { device .context_surface_info(context) .unwrap() @@ -919,13 +944,13 @@ fn make_surface(device: &mut Device, context: &Context) -> Surface { .unwrap() } -fn blit_fbo(gl: &Gl, dest_fbo: GLuint, src_fbo: GLuint) { +fn blit_fbo(gl: &Gl, dest_fbo: Option, src_fbo: Option) { unsafe { - gl.BindFramebuffer(gl::DRAW_FRAMEBUFFER, dest_fbo); + gl.bind_framebuffer(gl::DRAW_FRAMEBUFFER, dest_fbo); check_gl(gl); - gl.BindFramebuffer(gl::READ_FRAMEBUFFER, src_fbo); + gl.bind_framebuffer(gl::READ_FRAMEBUFFER, src_fbo); check_gl(gl); - gl.BlitFramebuffer( + gl.blit_framebuffer( 0, 0, 640, @@ -941,14 +966,13 @@ fn blit_fbo(gl: &Gl, dest_fbo: GLuint, src_fbo: GLuint) { } } -fn make_fbo(gl: &Gl, texture_target: GLenum, texture: GLuint) -> GLuint { +fn make_fbo(gl: &Gl, texture_target: u32, texture: Option) -> Framebuffer { unsafe { - let mut framebuffer_object = 0; - gl.GenFramebuffers(1, &mut framebuffer_object); + let framebuffer_object = gl.create_framebuffer().unwrap(); check_gl(gl); - gl.BindFramebuffer(gl::FRAMEBUFFER, framebuffer_object); + gl.bind_framebuffer(gl::FRAMEBUFFER, Some(framebuffer_object)); check_gl(gl); - gl.FramebufferTexture2D( + gl.framebuffer_texture_2d( gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0, texture_target, @@ -957,7 +981,7 @@ fn make_fbo(gl: &Gl, texture_target: GLenum, texture: GLuint) -> GLuint { ); check_gl(gl); assert_eq!( - gl.CheckFramebufferStatus(gl::FRAMEBUFFER), + gl.check_framebuffer_status(gl::FRAMEBUFFER), gl::FRAMEBUFFER_COMPLETE ); framebuffer_object @@ -1002,7 +1026,8 @@ impl BasicEnvironment { .unwrap(); device.make_context_current(&context).unwrap(); - let gl = Gl::load_with(|symbol| device.get_proc_address(&context, symbol)); + let gl = + unsafe { Gl::from_loader_function(|symbol| device.get_proc_address(&context, symbol)) }; unsafe { let framebuffer_object = device @@ -1010,8 +1035,8 @@ impl BasicEnvironment { .unwrap() .unwrap() .framebuffer_object; - gl.BindFramebuffer(gl::FRAMEBUFFER, framebuffer_object); - gl.Viewport(0, 0, 640, 480); + gl.bind_framebuffer(gl::FRAMEBUFFER, framebuffer_object); + gl.viewport(0, 0, 640, 480); } Some(BasicEnvironment { @@ -1027,43 +1052,43 @@ impl BasicEnvironment { fn clear(gl: &Gl, color: &[u8; 4]) { unsafe { - gl.ClearColor( + gl.clear_color( color[0] as f32 / 255.0, color[1] as f32 / 255.0, color[2] as f32 / 255.0, color[3] as f32 / 255.0, ); - gl.Clear(gl::COLOR_BUFFER_BIT); + gl.clear(gl::COLOR_BUFFER_BIT); } } fn clear_bottom_row(gl: &Gl, color: &[u8; 4]) { unsafe { - gl.Scissor(0, 0, 640, 1); - gl.Enable(gl::SCISSOR_TEST); - gl.ClearColor( + gl.scissor(0, 0, 640, 1); + gl.enable(gl::SCISSOR_TEST); + gl.clear_color( color[0] as f32 / 255.0, color[1] as f32 / 255.0, color[2] as f32 / 255.0, color[3] as f32 / 255.0, ); - gl.Clear(gl::COLOR_BUFFER_BIT); - gl.Disable(gl::SCISSOR_TEST); - gl.Scissor(0, 0, 640, 480); + gl.clear(gl::COLOR_BUFFER_BIT); + gl.disable(gl::SCISSOR_TEST); + gl.scissor(0, 0, 640, 480); } } fn get_pixel_from_bottom_row(gl: &Gl) -> [u8; 4] { unsafe { let mut pixel: [u8; 4] = [0; 4]; - gl.ReadPixels( + gl.read_pixels( 0, 0, 1, 1, gl::RGBA, gl::UNSIGNED_BYTE, - pixel.as_mut_ptr() as *mut c_void, + PixelPackData::Slice(Some(&mut pixel)), ); pixel } @@ -1072,14 +1097,14 @@ fn get_pixel_from_bottom_row(gl: &Gl) -> [u8; 4] { fn get_pixel_from_second_from_bottom_row(gl: &Gl) -> [u8; 4] { unsafe { let mut pixel: [u8; 4] = [0; 4]; - gl.ReadPixels( + gl.read_pixels( 0, 1, 1, 1, gl::RGBA, gl::UNSIGNED_BYTE, - pixel.as_mut_ptr() as *mut c_void, + PixelPackData::Slice(Some(&mut pixel)), ); pixel } @@ -1087,7 +1112,7 @@ fn get_pixel_from_second_from_bottom_row(gl: &Gl) -> [u8; 4] { fn check_gl(gl: &Gl) { unsafe { - assert_eq!(gl.GetError(), gl::NO_ERROR); + assert_eq!(gl.get_error(), gl::NO_ERROR); } }