Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/graphics/gl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,11 @@ pub struct GlContext {
pub(crate) cache: GlCache,
pub(crate) info: ContextInfo,
}
impl Drop for GlContext {
fn drop(&mut self) {
crate::drop_display();
}
}

impl GlContext {
pub fn new() -> GlContext {
Expand Down Expand Up @@ -1455,8 +1460,7 @@ impl RenderingBackend for GlContext {
TextureOrRenderbuffer::Renderbuffer(id) => id,
};
unsafe {
self.cache
.bind_texture(n, texture.params.kind.into(), raw);
self.cache.bind_texture(n, texture.params.kind.into(), raw);
glUniform1i(gl_loc, n as i32);
}
}
Expand Down
4 changes: 1 addition & 3 deletions src/graphics/gl/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,7 @@ impl GlCache {
let cached_attr = &mut self.attributes[attr_index];

if cached_attr.is_some() {
unsafe {
glDisableVertexAttribArray(attr_index as GLuint)
};
unsafe { glDisableVertexAttribArray(attr_index as GLuint) };
}
*cached_attr = None;
}
Expand Down
5 changes: 5 additions & 0 deletions src/graphics/metal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,22 +280,27 @@
current_pipeline: Option<Pipeline>,
current_ub_offset: u64,
}
impl Drop for MetalContext {
fn drop(&mut self) {
crate::drop_display();
}
}

impl MetalContext {
pub fn new() -> MetalContext {
unsafe {
let view = crate::window::apple_view();
assert!(!view.is_null());
let device: ObjcId = msg_send![view, device];

Check warning on line 294 in src/graphics/metal.rs

View workflow job for this annotation

GitHub Actions / Build (macos-latest, x86_64-apple-darwin)

unexpected `cfg` condition value: `cargo-clippy`

Check warning on line 294 in src/graphics/metal.rs

View workflow job for this annotation

GitHub Actions / Build (macos-latest, x86_64-apple-ios)

unexpected `cfg` condition value: `cargo-clippy`

Check warning on line 294 in src/graphics/metal.rs

View workflow job for this annotation

GitHub Actions / Build (macos-latest, aarch64-apple-ios)

unexpected `cfg` condition value: `cargo-clippy`
assert!(!device.is_null());
let command_queue: ObjcId = msg_send![device, newCommandQueue];

Check warning on line 296 in src/graphics/metal.rs

View workflow job for this annotation

GitHub Actions / Build (macos-latest, x86_64-apple-darwin)

unexpected `cfg` condition value: `cargo-clippy`

Check warning on line 296 in src/graphics/metal.rs

View workflow job for this annotation

GitHub Actions / Build (macos-latest, x86_64-apple-ios)

unexpected `cfg` condition value: `cargo-clippy`

Check warning on line 296 in src/graphics/metal.rs

View workflow job for this annotation

GitHub Actions / Build (macos-latest, aarch64-apple-ios)

unexpected `cfg` condition value: `cargo-clippy`

if false {
let capture_manager = msg_send_![class![MTLCaptureManager], sharedCaptureManager];

Check warning on line 299 in src/graphics/metal.rs

View workflow job for this annotation

GitHub Actions / Build (macos-latest, x86_64-apple-darwin)

unexpected `cfg` condition value: `cargo-clippy`

Check warning on line 299 in src/graphics/metal.rs

View workflow job for this annotation

GitHub Actions / Build (macos-latest, x86_64-apple-darwin)

unexpected `cfg` condition value: `cargo-clippy`

Check warning on line 299 in src/graphics/metal.rs

View workflow job for this annotation

GitHub Actions / Build (macos-latest, x86_64-apple-ios)

unexpected `cfg` condition value: `cargo-clippy`

Check warning on line 299 in src/graphics/metal.rs

View workflow job for this annotation

GitHub Actions / Build (macos-latest, x86_64-apple-ios)

unexpected `cfg` condition value: `cargo-clippy`

Check warning on line 299 in src/graphics/metal.rs

View workflow job for this annotation

GitHub Actions / Build (macos-latest, aarch64-apple-ios)

unexpected `cfg` condition value: `cargo-clippy`

Check warning on line 299 in src/graphics/metal.rs

View workflow job for this annotation

GitHub Actions / Build (macos-latest, aarch64-apple-ios)

unexpected `cfg` condition value: `cargo-clippy`
assert!(!capture_manager.is_null());

let MTLCaptureDestinationGPUTraceDocument = 2u64;
if !msg_send![

Check warning on line 303 in src/graphics/metal.rs

View workflow job for this annotation

GitHub Actions / Build (macos-latest, x86_64-apple-darwin)

unexpected `cfg` condition value: `cargo-clippy`

Check warning on line 303 in src/graphics/metal.rs

View workflow job for this annotation

GitHub Actions / Build (macos-latest, x86_64-apple-ios)

unexpected `cfg` condition value: `cargo-clippy`

Check warning on line 303 in src/graphics/metal.rs

View workflow job for this annotation

GitHub Actions / Build (macos-latest, aarch64-apple-ios)

unexpected `cfg` condition value: `cargo-clippy`
capture_manager,
supportsDestination: MTLCaptureDestinationGPUTraceDocument
] {
Expand All @@ -314,9 +319,9 @@
}

let capture_descriptor =
msg_send_![msg_send_![class![MTLCaptureDescriptor], alloc], init];

Check warning on line 322 in src/graphics/metal.rs

View workflow job for this annotation

GitHub Actions / Build (macos-latest, x86_64-apple-darwin)

unexpected `cfg` condition value: `cargo-clippy`

Check warning on line 322 in src/graphics/metal.rs

View workflow job for this annotation

GitHub Actions / Build (macos-latest, x86_64-apple-darwin)

unexpected `cfg` condition value: `cargo-clippy`

Check warning on line 322 in src/graphics/metal.rs

View workflow job for this annotation

GitHub Actions / Build (macos-latest, x86_64-apple-darwin)

unexpected `cfg` condition value: `cargo-clippy`

Check warning on line 322 in src/graphics/metal.rs

View workflow job for this annotation

GitHub Actions / Build (macos-latest, x86_64-apple-ios)

unexpected `cfg` condition value: `cargo-clippy`

Check warning on line 322 in src/graphics/metal.rs

View workflow job for this annotation

GitHub Actions / Build (macos-latest, x86_64-apple-ios)

unexpected `cfg` condition value: `cargo-clippy`

Check warning on line 322 in src/graphics/metal.rs

View workflow job for this annotation

GitHub Actions / Build (macos-latest, x86_64-apple-ios)

unexpected `cfg` condition value: `cargo-clippy`

Check warning on line 322 in src/graphics/metal.rs

View workflow job for this annotation

GitHub Actions / Build (macos-latest, aarch64-apple-ios)

unexpected `cfg` condition value: `cargo-clippy`

Check warning on line 322 in src/graphics/metal.rs

View workflow job for this annotation

GitHub Actions / Build (macos-latest, aarch64-apple-ios)

unexpected `cfg` condition value: `cargo-clippy`

Check warning on line 322 in src/graphics/metal.rs

View workflow job for this annotation

GitHub Actions / Build (macos-latest, aarch64-apple-ios)

unexpected `cfg` condition value: `cargo-clippy`
msg_send_![capture_descriptor, setCaptureObject: device];

Check warning on line 323 in src/graphics/metal.rs

View workflow job for this annotation

GitHub Actions / Build (macos-latest, x86_64-apple-darwin)

unexpected `cfg` condition value: `cargo-clippy`

Check warning on line 323 in src/graphics/metal.rs

View workflow job for this annotation

GitHub Actions / Build (macos-latest, x86_64-apple-ios)

unexpected `cfg` condition value: `cargo-clippy`

Check warning on line 323 in src/graphics/metal.rs

View workflow job for this annotation

GitHub Actions / Build (macos-latest, aarch64-apple-ios)

unexpected `cfg` condition value: `cargo-clippy`
msg_send_![

Check warning on line 324 in src/graphics/metal.rs

View workflow job for this annotation

GitHub Actions / Build (macos-latest, x86_64-apple-darwin)

unexpected `cfg` condition value: `cargo-clippy`

Check warning on line 324 in src/graphics/metal.rs

View workflow job for this annotation

GitHub Actions / Build (macos-latest, x86_64-apple-ios)

unexpected `cfg` condition value: `cargo-clippy`

Check warning on line 324 in src/graphics/metal.rs

View workflow job for this annotation

GitHub Actions / Build (macos-latest, aarch64-apple-ios)

unexpected `cfg` condition value: `cargo-clippy`
capture_descriptor,
setDestination: MTLCaptureDestinationGPUTraceDocument
];
Expand Down
119 changes: 86 additions & 33 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,19 +80,72 @@

pub type Context = dyn RenderingBackend;

use std::sync::{Mutex, OnceLock};
use std::ptr::null_mut;
use std::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
use std::sync::{Mutex, MutexGuard};

static NATIVE_DISPLAY: OnceLock<Mutex<native::NativeDisplayData>> = OnceLock::new();
/// Atomic pointer to the global display instance, enabling safe concurrent access and resetting.
static NATIVE_DISPLAY: AtomicPtr<Mutex<native::NativeDisplayData>> = AtomicPtr::new(null_mut());
/// Atomic flag indicating whether `NATIVE_DISPLAY` is initialized and safe to access.
static NATIVE_DISPLAY_READY: AtomicBool = AtomicBool::new(false);

/// Sets the global display, replacing any previous instance and ensuring visibility to all threads.
fn set_display(display: native::NativeDisplayData) {
NATIVE_DISPLAY
.set(Mutex::new(display))
.unwrap_or_else(|_| panic!("NATIVE_DISPLAY already set"));
let new_data = Box::new(Mutex::new(display));
let ptr = Box::into_raw(new_data);

let old = NATIVE_DISPLAY.swap(ptr, Ordering::AcqRel);
if !old.is_null() {
// SAFETY: `old` was originally created using `Box::into_raw()`, meaning it must be
// properly deallocated using `Box::from_raw()` to prevent memory leaks.
unsafe { drop(Box::from_raw(old)) };
}
// Ensure all threads see the updated pointer before marking it as ready.
NATIVE_DISPLAY_READY.store(true, Ordering::Release);
}

/// Returns a reference to the global display mutex, or `None` if uninitialized.
fn native_display() -> Option<&'static Mutex<native::NativeDisplayData>> {
// Ensure this thread sees the latest pointer update before dereferencing.
if !NATIVE_DISPLAY_READY.load(Ordering::Acquire) {
return None;
}
let ptr = NATIVE_DISPLAY.load(Ordering::Acquire);
if ptr.is_null() {
return None;
}
// SAFETY: The pointer was allocated using `Box::into_raw()` and is valid
// as long as `drop_display()` has not been called. Since `NATIVE_DISPLAY_READY`
// was checked, it is safe to assume `ptr` is not currently being deallocated.
unsafe { Some(&*ptr) }
}
fn native_display() -> &'static Mutex<native::NativeDisplayData> {
NATIVE_DISPLAY
.get()
.expect("Backend has not initialized NATIVE_DISPLAY yet.") //|| Mutex::new(Default::default()))

/// Returns a blocking lock on the global display, panicking if uninitialized.
fn native_display_blocking() -> MutexGuard<'static, native::NativeDisplayData> {
native_display()
.expect("Global display not initialized")
.lock()
.expect("Failed to acquire blocking lock on the global display")
}

/// Returns a non-blocking lock on the global display, panicking if unavailable.
fn native_display_nonblocking() -> MutexGuard<'static, native::NativeDisplayData> {

Check warning on line 132 in src/lib.rs

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest, x86_64-pc-windows-gnu)

function `native_display_nonblocking` is never used

Check warning on line 132 in src/lib.rs

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest, wasm32-unknown-unknown)

function `native_display_nonblocking` is never used

Check warning on line 132 in src/lib.rs

View workflow job for this annotation

GitHub Actions / Build (windows-latest, x86_64-pc-windows-msvc)

function `native_display_nonblocking` is never used
native_display()
.expect("Global display not initialized")
.try_lock()
.expect("Failed to acquire non-blocking lock on the global display")
}

/// Drops the global display, ensuring it is safely deallocated and preventing further access.
fn drop_display() {
// Prevent further access before deallocating.
NATIVE_DISPLAY_READY.store(false, Ordering::Release);
let old = NATIVE_DISPLAY.swap(null_mut(), Ordering::AcqRel);
if !old.is_null() {
// SAFETY: `swap(null_mut())` ensures that no other thread will access `old`
// after this point, so it is safe to drop it without causing a use-after-free.
unsafe { drop(Box::from_raw(old)) };
}
}

/// Window and associated to window rendering context related functions.
Expand Down Expand Up @@ -125,26 +178,26 @@
/// The current framebuffer size in pixels
/// NOTE: [High DPI Rendering](../conf/index.html#high-dpi-rendering)
pub fn screen_size() -> (f32, f32) {
let d = native_display().lock().unwrap();
let d = native_display_blocking();
(d.screen_width as f32, d.screen_height as f32)
}

/// The dpi scaling factor (window pixels to framebuffer pixels)
/// NOTE: [High DPI Rendering](../conf/index.html#high-dpi-rendering)
pub fn dpi_scale() -> f32 {
let d = native_display().lock().unwrap();
let d = native_display_blocking();
d.dpi_scale
}

/// True when high_dpi was requested and actually running in a high-dpi scenario
/// NOTE: [High DPI Rendering](../conf/index.html#high-dpi-rendering)
pub fn high_dpi() -> bool {
let d = native_display().lock().unwrap();
let d = native_display_blocking();
d.high_dpi
}

pub fn blocking_event_loop() -> bool {
let d = native_display().lock().unwrap();
let d = native_display_blocking();
d.blocking_event_loop
}

Expand All @@ -156,7 +209,7 @@
/// happen in the order_quit implmentation) and execution might continue for some time after
/// But the window is going to be inevitably closed at some point.
pub fn order_quit() {
let mut d = native_display().lock().unwrap();
let mut d = native_display_blocking();
d.quit_ordered = true;
}

Expand All @@ -171,7 +224,7 @@
/// If the event handler callback does nothing, the application will be quit as usual.
/// To prevent this, call the function "cancel_quit()"" from inside the event handler.
pub fn request_quit() {
let mut d = native_display().lock().unwrap();
let mut d = native_display_blocking();
d.quit_requested = true;
}

Expand All @@ -181,7 +234,7 @@
/// function makes sense is from inside the event handler callback when
/// the "quit_requested_event" event has been received
pub fn cancel_quit() {
let mut d = native_display().lock().unwrap();
let mut d = native_display_blocking();
d.quit_requested = false;
}
/// Capture mouse cursor to the current window
Expand All @@ -191,7 +244,7 @@
/// so set_cursor_grab(false) on window's focus lost is recommended.
/// TODO: implement window focus events
pub fn set_cursor_grab(grab: bool) {
let d = native_display().lock().unwrap();
let d = native_display_blocking();
d.native_requests
.send(native::Request::SetCursorGrab(grab))
.unwrap();
Expand All @@ -205,7 +258,7 @@
pub fn schedule_update() {
#[cfg(not(target_arch = "wasm32"))]
{
let d = native_display().lock().unwrap();
let d = native_display_blocking();
d.native_requests
.send(native::Request::ScheduleUpdate)
.unwrap();
Expand All @@ -219,23 +272,23 @@

/// Show or hide the mouse cursor
pub fn show_mouse(shown: bool) {
let d = native_display().lock().unwrap();
let d = native_display_blocking();
d.native_requests
.send(native::Request::ShowMouse(shown))
.unwrap();
}

/// Set the mouse cursor icon.
pub fn set_mouse_cursor(cursor_icon: CursorIcon) {
let d = native_display().lock().unwrap();
let d = native_display_blocking();
d.native_requests
.send(native::Request::SetMouseCursor(cursor_icon))
.unwrap();
}

/// Set the application's window size.
pub fn set_window_size(new_width: u32, new_height: u32) {
let d = native_display().lock().unwrap();
let d = native_display_blocking();
d.native_requests
.send(native::Request::SetWindowSize {
new_width,
Expand All @@ -245,7 +298,7 @@
}

pub fn set_window_position(new_x: u32, new_y: u32) {
let d = native_display().lock().unwrap();
let d = native_display_blocking();
d.native_requests
.send(native::Request::SetWindowPosition { new_x, new_y })
.unwrap();
Expand All @@ -255,63 +308,63 @@
/// TODO: implement for other platforms
#[cfg(any(target_os = "windows", target_os = "linux"))]
pub fn get_window_position() -> (u32, u32) {
let d = native_display().lock().unwrap();
let d = native_display_blocking();
d.screen_position
}

pub fn set_fullscreen(fullscreen: bool) {
let d = native_display().lock().unwrap();
let d = native_display_blocking();
d.native_requests
.send(native::Request::SetFullscreen(fullscreen))
.unwrap();
}

/// Get current OS clipboard value
pub fn clipboard_get() -> Option<String> {
let mut d = native_display().lock().unwrap();
let mut d = native_display_blocking();
d.clipboard.get()
}

/// Save value to OS clipboard
pub fn clipboard_set(data: &str) {
let mut d = native_display().lock().unwrap();
let mut d = native_display_blocking();
d.clipboard.set(data)
}
pub fn dropped_file_count() -> usize {
let d = native_display().lock().unwrap();
let d = native_display_blocking();
d.dropped_files.bytes.len()
}
pub fn dropped_file_bytes(index: usize) -> Option<Vec<u8>> {
let d = native_display().lock().unwrap();
let d = native_display_blocking();
d.dropped_files.bytes.get(index).cloned()
}
pub fn dropped_file_path(index: usize) -> Option<std::path::PathBuf> {
let d = native_display().lock().unwrap();
let d = native_display_blocking();
d.dropped_files.paths.get(index).cloned()
}

/// Show/hide onscreen keyboard.
/// Only works on Android right now.
pub fn show_keyboard(show: bool) {
let d = native_display().lock().unwrap();
let d = native_display_blocking();
d.native_requests
.send(native::Request::ShowKeyboard(show))
.unwrap();
}

#[cfg(target_vendor = "apple")]
pub fn apple_gfx_api() -> crate::conf::AppleGfxApi {
let d = native_display().lock().unwrap();
let d = native_display_blocking();
d.gfx_api
}
#[cfg(target_vendor = "apple")]
pub fn apple_view() -> crate::native::apple::frameworks::ObjcId {
let d = native_display().lock().unwrap();
let d = native_display_blocking();
d.view
}
#[cfg(target_os = "ios")]
pub fn apple_view_ctrl() -> crate::native::apple::frameworks::ObjcId {
let d = native_display().lock().unwrap();
let d = native_display_blocking();
d.view_ctrl
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/native/android.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ impl MainThreadState {
}

{
let mut d = crate::native_display().lock().unwrap();
let mut d = crate::native_display_blocking();
d.screen_width = width as _;
d.screen_height = height as _;
}
Expand Down
12 changes: 6 additions & 6 deletions src/native/ios.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use {
},
NativeDisplayData,
},
native_display,
native_display_blocking,
},
std::{
cell::RefCell,
Expand Down Expand Up @@ -143,7 +143,7 @@ pub fn define_glk_or_mtk_view(superclass: &Class) -> *const Class {
let ios_touch: ObjcId = msg_send![enumerator, nextObject];
let mut ios_pos: NSPoint = msg_send![ios_touch, locationInView: this];

if native_display().lock().unwrap().high_dpi {
if native_display_blocking().high_dpi {
ios_pos.x *= 2.;
ios_pos.y *= 2.;
} else {
Expand Down Expand Up @@ -317,7 +317,7 @@ pub fn define_glk_or_mtk_view_dlg(superclass: &Class) -> *const Class {

let main_screen: ObjcId = unsafe { msg_send![class!(UIScreen), mainScreen] };
let screen_rect: NSRect = unsafe { msg_send![main_screen, bounds] };
let high_dpi = native_display().lock().unwrap().high_dpi;
let high_dpi = native_display_blocking().high_dpi;

let (screen_width, screen_height) = if high_dpi {
(
Expand All @@ -332,11 +332,11 @@ pub fn define_glk_or_mtk_view_dlg(superclass: &Class) -> *const Class {
)
};

if native_display().lock().unwrap().screen_width != screen_width
|| native_display().lock().unwrap().screen_height != screen_height
if native_display_blocking().screen_width != screen_width
|| native_display_blocking().screen_height != screen_height
{
{
let mut d = native_display().lock().unwrap();
let mut d = native_display_blocking();
d.screen_width = screen_width;
d.screen_height = screen_height;
}
Expand Down
2 changes: 1 addition & 1 deletion src/native/linux_wayland.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@
EVENTS.push(WaylandEvent::KeyboardLeave);
}
unsafe extern "C" fn keyboard_handle_key(
data: *mut ::core::ffi::c_void,

Check warning on line 203 in src/native/linux_wayland.rs

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest, aarch64-unknown-linux-gnu)

unused variable: `data`

Check warning on line 203 in src/native/linux_wayland.rs

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest, armv7-unknown-linux-gnueabihf)

unused variable: `data`

Check warning on line 203 in src/native/linux_wayland.rs

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest, x86_64-unknown-linux-gnu)

unused variable: `data`
_wl_keyboard: *mut wl_keyboard,
_serial: u32,
_time: u32,
Expand Down Expand Up @@ -483,7 +483,7 @@
) -> () {
assert!(!data.is_null());
let payload: &mut WaylandPayload = &mut *(data as *mut _);
let mut d = crate::native_display().lock().unwrap();
let mut d = crate::native_display_blocking();

if width != 0 && height != 0 {
let (egl_w, egl_h) = if payload.decorations.is_some() {
Expand Down
Loading
Loading