Skip to content

Commit

Permalink
Use lazy gl context on linux
Browse files Browse the repository at this point in the history
Signed-off-by: sagudev <[email protected]>
  • Loading branch information
sagudev committed Dec 30, 2024
1 parent 26706ea commit 36d8fea
Show file tree
Hide file tree
Showing 10 changed files with 138 additions and 144 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"rust-analyzer.cargo.features": "all"
}
1 change: 1 addition & 0 deletions src/platform/egl/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ pub struct Context {
pub(crate) egl_context: EGLContext,
pub(crate) id: ContextID,
pub(crate) pbuffer: EGLSurface,
pub(crate) gl: LazyCell<Gl>,
framebuffer: Framebuffer<Surface, ExternalEGLSurfaces>,
context_is_owned: bool,
}
Expand Down
3 changes: 2 additions & 1 deletion src/platform/generic/egl/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use crate::surface::Framebuffer;
use crate::{ContextAttributeFlags, ContextAttributes, ContextID, Error, GLApi, GLVersion};
use crate::{Gl, SurfaceInfo};

use std::cell::LazyCell;
use std::ffi::CString;
use std::mem;
use std::os::raw::c_void;
Expand Down Expand Up @@ -211,7 +212,7 @@ impl EGLBackedContext {

pub(crate) unsafe fn unbind_surface(
&mut self,
gl: &Gl,
gl: &LazyCell<Gl>,
egl_display: EGLDisplay,
) -> Result<Option<EGLBackedSurface>, Error> {
match self.framebuffer {
Expand Down
13 changes: 11 additions & 2 deletions src/platform/generic/egl/surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use crate::{ContextAttributes, ContextID, Error, SurfaceID, SurfaceInfo};

use euclid::default::Size2D;
use glow::{Framebuffer, HasContext, PixelUnpackData, Texture};
use std::cell::LazyCell;
use std::fmt::{self, Debug, Formatter};
use std::marker::PhantomData;
use std::mem;
Expand Down Expand Up @@ -207,7 +208,7 @@ impl EGLBackedSurface {

pub(crate) fn destroy(
&mut self,
gl: &Gl,
gl: &LazyCell<Gl>,
egl_display: EGLDisplay,
context_id: ContextID,
) -> Result<Option<*const c_void>, Error> {
Expand Down Expand Up @@ -315,14 +316,22 @@ impl EGLBackedSurface {
}
}

pub(crate) fn unbind(&self, gl: &Gl, egl_display: EGLDisplay, egl_context: EGLContext) {
pub(crate) fn unbind(
&self,
gl: &LazyCell<Gl>,
egl_display: EGLDisplay,
egl_context: EGLContext,
) {
// If we're current, we stay current, but with no surface attached.
unsafe {
EGL_FUNCTIONS.with(|egl| {
if egl.GetCurrentContext() != egl_context {
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 {
Expand Down
41 changes: 20 additions & 21 deletions src/platform/unix/generic/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,11 @@ use crate::egl::types::EGLint;
use crate::platform::generic::egl::context::{self, CurrentContextGuard, EGLBackedContext};
use crate::{ContextAttributes, Error, Gl, SurfaceInfo};

use std::cell::LazyCell;
use std::os::raw::c_void;

pub use crate::platform::generic::egl::context::{ContextDescriptor, NativeContext};

thread_local! {
#[doc(hidden)]
pub static GL_FUNCTIONS: Gl = unsafe {Gl::from_loader_function(context::get_proc_address)};
}

/// Represents an OpenGL rendering context.
///
/// A context allows you to issue rendering commands to a surface. When initially created, a
Expand All @@ -35,7 +31,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) LazyCell<Gl>);

impl Device {
/// Creates a context descriptor with the given attributes.
Expand Down Expand Up @@ -75,15 +71,17 @@ impl Device {
descriptor: &ContextDescriptor,
share_with: Option<&Context>,
) -> Result<Context, Error> {
unsafe {
EGLBackedContext::new(
self.native_connection.egl_display,
descriptor,
share_with.map(|ctx| &ctx.0),
self.gl_api(),
)
.map(Context)
}
Ok(Context(
unsafe {
EGLBackedContext::new(
self.native_connection.egl_display,
descriptor,
share_with.map(|ctx| &ctx.0),
self.gl_api(),
)?
},
LazyCell::new(|| unsafe { Gl::from_loader_function(context::get_proc_address) }),
))
}

/// Wraps an `EGLContext` in a native context and returns it.
Expand All @@ -96,9 +94,10 @@ impl Device {
&self,
native_context: NativeContext,
) -> Result<Context, Error> {
Ok(Context(EGLBackedContext::from_native_context(
native_context,
)))
Ok(Context(
EGLBackedContext::from_native_context(native_context),
LazyCell::new(|| unsafe { Gl::from_loader_function(context::get_proc_address) }),
))
}

/// Destroys a context.
Expand Down Expand Up @@ -213,12 +212,12 @@ impl Device {
&self,
context: &mut Context,
) -> Result<Option<Surface>, 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.
Expand Down
37 changes: 17 additions & 20 deletions src/platform/unix/generic/surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//!
//! 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::platform::generic::egl::surface::{EGLBackedSurface, EGLSurfaceTexture};
Expand Down Expand Up @@ -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.
Expand All @@ -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.
Expand All @@ -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.
Expand All @@ -148,7 +145,7 @@ impl Device {
surface_texture: SurfaceTexture,
) -> Result<Surface, (Error, SurfaceTexture)> {
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)),
}
}
Expand Down
52 changes: 23 additions & 29 deletions src/platform/unix/wayland/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,11 @@ use crate::egl::types::EGLint;
use crate::platform::generic::egl::context::{self, CurrentContextGuard, EGLBackedContext};
use crate::{ContextAttributes, Error, Gl, SurfaceInfo};

use std::cell::LazyCell;
use std::os::raw::c_void;

pub use crate::platform::generic::egl::context::{ContextDescriptor, NativeContext};

thread_local! {
#[doc(hidden)]
pub static GL_FUNCTIONS: Gl = unsafe {Gl::from_loader_function(context::get_proc_address)};
}

/// Represents an OpenGL rendering context.
///
/// A context allows you to issue rendering commands to a surface. When initially created, a
Expand All @@ -37,7 +33,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) LazyCell<Gl>);

impl Device {
/// Creates a context descriptor with the given attributes.
Expand Down Expand Up @@ -75,15 +71,17 @@ impl Device {
descriptor: &ContextDescriptor,
share_with: Option<&Context>,
) -> Result<Context, Error> {
unsafe {
EGLBackedContext::new(
self.native_connection.egl_display,
descriptor,
share_with.map(|ctx| &ctx.0),
self.gl_api(),
)
.map(Context)
}
Ok(Context(
unsafe {
EGLBackedContext::new(
self.native_connection.egl_display,
descriptor,
share_with.map(|ctx| &ctx.0),
self.gl_api(),
)?
},
LazyCell::new(|| unsafe { Gl::from_loader_function(context::get_proc_address) }),
))
}

/// Wraps an `EGLContext` in a native context and returns it.
Expand All @@ -96,9 +94,10 @@ impl Device {
&self,
native_context: NativeContext,
) -> Result<Context, Error> {
Ok(Context(EGLBackedContext::from_native_context(
native_context,
)))
Ok(Context(
EGLBackedContext::from_native_context(native_context),
LazyCell::new(|| unsafe { Gl::from_loader_function(context::get_proc_address) }),
))
}

/// Destroys a context.
Expand Down Expand Up @@ -213,17 +212,12 @@ impl Device {
&self,
context: &mut Context,
) -> Result<Option<Surface>, 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.
Expand Down
Loading

0 comments on commit 36d8fea

Please sign in to comment.