diff --git a/crates/canvas-2d/src/context/surface_gl.rs b/crates/canvas-2d/src/context/surface_gl.rs index 09ca45485..96022407b 100644 --- a/crates/canvas-2d/src/context/surface_gl.rs +++ b/crates/canvas-2d/src/context/surface_gl.rs @@ -20,6 +20,17 @@ fn gl_interface() -> Option { } } +/// 8 bits a channel even when opaque, as on the web: at 5-6 bits (RGB565) a translucent fill never +/// converges on its colour, so a trail fading out leaves a permanent tint. Opaque is RGB888x, whose +/// alpha reads back as 255 whatever was drawn. +fn color_type_for(alpha: bool) -> ColorType { + if alpha { + ColorType::RGBA8888 + } else { + ColorType::RGB888x + } +} + fn with_offscreen( ctx: &mut gpu::DirectContext, window: skia_safe::Surface, @@ -28,11 +39,8 @@ fn with_offscreen( ) -> (skia_safe::Surface, Option) { #[cfg(target_os = "android")] { - let (color_type, alpha_type) = if alpha { - (ColorType::RGBA8888, AlphaType::Premul) - } else { - (ColorType::RGB565, AlphaType::Opaque) - }; + let color_type = color_type_for(alpha); + let alpha_type = if alpha { AlphaType::Premul } else { AlphaType::Opaque }; let info = ImageInfo::new( ISize::new(window.width(), window.height()), color_type, @@ -40,11 +48,15 @@ fn with_offscreen( color_space, ); let props = window.props().clone(); + // Multisampled, so Skia draws antialiased paths on the GPU instead of rasterizing their + // coverage on this thread and uploading it every frame; on a tiled GPU the samples mostly + // stay in tile memory. + let samples = ctx.max_surface_sample_count_for_color_type(color_type).min(4); if let Some(offscreen) = gpu::surfaces::render_target( ctx, gpu::Budgeted::Yes, &info, - Some(0), + Some(samples), gpu::SurfaceOrigin::TopLeft, Some(&props), false, @@ -69,8 +81,9 @@ fn draws_to_window(gl: &canvas_core::gpu::gl::GLContext) -> bool { } } -const GR_GL_RGB565: u32 = 0x8D62; const GR_GL_RGBA8: u32 = 0x8058; +/// An opaque config's buffer, which RGB888x wraps. +const GR_GL_RGB8: u32 = 0x8051; #[cfg(feature = "gl")] impl Context { @@ -150,11 +163,7 @@ impl Context { let mut frame_buffer = gpu::gl::FramebufferInfo::from_fboid(buffer_id[0] as u32); - if alpha { - frame_buffer.format = GR_GL_RGBA8; - } else { - frame_buffer.format = GR_GL_RGB565; - } + frame_buffer.format = if alpha { GR_GL_RGBA8 } else { GR_GL_RGB8 }; let target = gpu::backend_render_targets::make_gl( (width as i32, height as i32), @@ -166,10 +175,7 @@ impl Context { skia_safe::SurfacePropsFlags::default(), PixelGeometry::Unknown, ); - let mut color_type = ColorType::RGBA8888; - if !alpha { - color_type = ColorType::RGB565; - } + let color_type = color_type_for(alpha); let surface = gpu::surfaces::wrap_backend_render_target( &mut ctx, @@ -310,16 +316,12 @@ impl Context { let mut window_surface = None; let mut engine = SurfaceEngine::GL; let surface = if bounds.is_empty() { - let color_type = if alpha { - ColorType::RGBA8888 - } else { - ColorType::RGB565 - }; + let color_type = color_type_for(alpha); let alpha_type = if alpha { AlphaType::Unpremul } else { - AlphaType::Premul + AlphaType::Opaque }; let mut width = width; @@ -353,11 +355,7 @@ impl Context { let mut frame_buffer = gpu::gl::FramebufferInfo::from_fboid(buffer_id as u32); - if alpha { - frame_buffer.format = GR_GL_RGBA8; - } else { - frame_buffer.format = GR_GL_RGB565; - } + frame_buffer.format = if alpha { GR_GL_RGBA8 } else { GR_GL_RGB8 }; let target = gpu::backend_render_targets::make_gl( (width as i32, height as i32), @@ -370,11 +368,7 @@ impl Context { skia_safe::SurfacePropsFlags::default(), PixelGeometry::Unknown, ); - let mut color_type = ColorType::RGBA8888; - - if !alpha { - color_type = ColorType::RGB565; - } + let color_type = color_type_for(alpha); let surface = gpu::surfaces::wrap_backend_render_target( &mut ctx, diff --git a/crates/canvas-android/src/jni_compat/org_nativescript_canvas_NSCCanvas.rs b/crates/canvas-android/src/jni_compat/org_nativescript_canvas_NSCCanvas.rs index 7e1a16645..dce969759 100644 --- a/crates/canvas-android/src/jni_compat/org_nativescript_canvas_NSCCanvas.rs +++ b/crates/canvas-android/src/jni_compat/org_nativescript_canvas_NSCCanvas.rs @@ -250,6 +250,7 @@ pub extern "system" fn nativeInitWebGL( desynchronized: jboolean, xr_compatible: jboolean, version: jint, + threaded: jboolean, ) -> jlong { unsafe { let interface = env.get_native_interface(); @@ -261,7 +262,12 @@ pub extern "system" fn nativeInitWebGL( return 0; } if let Ok(power_preference) = PowerPreference::try_from(power_preference) { - let context = canvas_c::canvas_native_webgl_create( + let create = if threaded == JNI_TRUE { + canvas_c::canvas_native_webgl_create_threaded + } else { + canvas_c::canvas_native_webgl_create + }; + let context = create( window.ptr().as_ptr() as _, window.width(), window.height(), @@ -308,6 +314,7 @@ pub extern "system" fn nativeInitWebGLNoSurface( desynchronized: jboolean, xr_compatible: jboolean, version: jint, + threaded: jboolean, ) -> jlong { if version == 2 && !GLContext::has_gl2support() { return 0; @@ -317,7 +324,12 @@ pub extern "system" fn nativeInitWebGLNoSurface( let height = height.max(1); if let Ok(power_preference) = PowerPreference::try_from(power_preference) { - let context = canvas_c::canvas_native_webgl_create_no_window( + let create = if threaded == JNI_TRUE { + canvas_c::canvas_native_webgl_create_no_window_threaded + } else { + canvas_c::canvas_native_webgl_create_no_window + }; + let context = create( width, height, version as i32, @@ -458,19 +470,23 @@ pub extern "system" fn nativeUpdateWebGLSurface( return; } let context = context as *mut WebGLState; - let context = unsafe { &mut *context }; + let context = unsafe { &*context }; unsafe { if let Some(window) = NativeWindow::from_surface(env.get_native_interface(), surface) { - // NativeWindow::ptr() is NonNull; the as *mut c_void cast - // preserves non-nullness, but guard defensively to avoid a panic. - let Some(nn_ptr) = NonNull::new(window.ptr().as_ptr() as _) else { return }; - context.get_inner_mut().set_window_surface( - window.width(), - window.height(), - nn_ptr, - ); - context.get_inner().make_current(); drop(env); + let (width, height) = (window.width(), window.height()); + // Queued, not waited on: this runs from the view's surface callbacks, and blocking them + // on a thread that may be waiting for a buffer from this window can deadlock its queue. + // `window` holds a reference until the job is done with it. + context.post(move |state| { + // NativeWindow::ptr() is NonNull; the as *mut c_void cast + // preserves non-nullness, but guard defensively to avoid a panic. + let Some(nn_ptr) = NonNull::new(window.ptr().as_ptr() as _) else { + return; + }; + state.set_window_surface(width, height, nn_ptr); + state.make_current(); + }); } } } @@ -616,9 +632,12 @@ fn native_update_gl_no_surface(width: jint, height: jint, context: jlong) { return; } let context = context as *mut WebGLState; - let context = unsafe { &mut *context }; - context.get_inner().make_current(); - context.get_inner_mut().resize_pbuffer(width, height); + let context = unsafe { &*context }; + // Waited on: when the window is going away this is how the context lets go of it. + context.detach(|state| { + state.make_current(); + state.resize_pbuffer(width, height); + }); } #[no_mangle] @@ -676,7 +695,8 @@ pub extern "system" fn nativeMakeWebGLCurrent(gl_context: jlong) -> jboolean { } let gl_context = gl_context as *mut WebGLState; let gl_context = unsafe { &*gl_context }; - if gl_context.get_inner().make_current() { + // A threaded context is made current on its own thread, where everything that uses it runs. + if gl_context.sync(|state| state.make_current()) { return JNI_TRUE; } JNI_FALSE @@ -693,7 +713,8 @@ pub extern "system" fn nativeMakeWebGLCurrentNormal( } let gl_context = gl_context as *mut WebGLState; let gl_context = unsafe { &*gl_context }; - if gl_context.get_inner().make_current() { + // A threaded context is made current on its own thread, where everything that uses it runs. + if gl_context.sync(|state| state.make_current()) { return JNI_TRUE; } JNI_FALSE @@ -851,7 +872,7 @@ pub extern "system" fn nativeWriteCurrentWebGLContextToBitmap( } let context = context as *mut WebGLState; - let context = unsafe { &mut *context }; + let context = unsafe { &*context }; unsafe { crate::utils::image::bitmap_handler( @@ -859,24 +880,27 @@ pub extern "system" fn nativeWriteCurrentWebGLContextToBitmap( bitmap, Box::new(move |cb| { if let Some((image_data, info)) = cb { - context.get_inner().make_current(); - // Use checked arithmetic — width/height are u32 and can overflow on multiply. - let buf_size = (info.width() as usize) - .checked_mul(info.height() as usize) - .and_then(|n| n.checked_mul(4)); - let Some(buf_size) = buf_size else { return }; - let mut buf = vec![0u8; buf_size]; - gl_bindings::Flush(); - gl_bindings::ReadPixels( - 0, - 0, - info.width() as i32, - info.height() as i32, - gl_bindings::RGBA as std::os::raw::c_uint, - gl_bindings::UNSIGNED_BYTE as std::os::raw::c_uint, - buf.as_mut_ptr() as *mut c_void, - ); - image_data.copy_from_slice(buf.as_slice()); + // The bitmap stays locked while this waits for the read. + context.sync(|state| { + state.make_current(); + // Use checked arithmetic — width/height are u32 and can overflow on multiply. + let buf_size = (info.width() as usize) + .checked_mul(info.height() as usize) + .and_then(|n| n.checked_mul(4)); + let Some(buf_size) = buf_size else { return }; + let mut buf = vec![0u8; buf_size]; + gl_bindings::Flush(); + gl_bindings::ReadPixels( + 0, + 0, + info.width() as i32, + info.height() as i32, + gl_bindings::RGBA as std::os::raw::c_uint, + gl_bindings::UNSIGNED_BYTE as std::os::raw::c_uint, + buf.as_mut_ptr() as *mut c_void, + ); + image_data.copy_from_slice(buf.as_slice()); + }); } }), ) diff --git a/crates/canvas-android/src/jni_compat/org_nativescript_canvas_NSCWebGLRenderingContext.rs b/crates/canvas-android/src/jni_compat/org_nativescript_canvas_NSCWebGLRenderingContext.rs index 857c87e26..1786f735e 100644 --- a/crates/canvas-android/src/jni_compat/org_nativescript_canvas_NSCWebGLRenderingContext.rs +++ b/crates/canvas-android/src/jni_compat/org_nativescript_canvas_NSCWebGLRenderingContext.rs @@ -23,21 +23,23 @@ pub extern "system" fn nativeTexImage2D( } let context = context as *mut WebGLState; - let context = unsafe { &mut *context }; + let context = unsafe { &*context }; let bytes = crate::utils::image::get_bytes_from_bitmap(&env, bitmap); if let Some((bytes, info)) = bytes { - context.get_inner().make_current(); let width = info.width(); let height = info.height(); - unsafe { + let stride = info.stride(); + // The bitmap's bytes are a copy, so the upload can queue. + context.post(move |state| unsafe { + state.make_current(); if flip_y == JNI_TRUE { let mut buffer = bytes; canvas_webgl::utils::gl::flip_in_place( buffer.as_mut_ptr(), buffer.len(), - info.stride() as usize, + stride as usize, height as usize, ); @@ -65,7 +67,7 @@ pub extern "system" fn nativeTexImage2D( bytes.as_ptr() as *const c_void, ); } - } + }); } } @@ -88,21 +90,23 @@ pub extern "system" fn nativeTexSubImage2D( } let context = context as *mut WebGLState; - let context = unsafe { &mut *context }; + let context = unsafe { &*context }; let bytes = crate::utils::image::get_bytes_from_bitmap(&env, bitmap); if let Some((bytes, info)) = bytes { - unsafe { - context.get_inner().make_current(); - let width = info.width(); - let height = info.height(); + let width = info.width(); + let height = info.height(); + let stride = info.stride(); + // The bitmap's bytes are a copy, so the upload can queue. + context.post(move |state| unsafe { + state.make_current(); if flip_y == JNI_TRUE { let mut buffer = bytes; canvas_webgl::utils::gl::flip_in_place( buffer.as_mut_ptr(), buffer.len(), - info.stride() as usize, + stride as usize, height as usize, ); @@ -130,6 +134,6 @@ pub extern "system" fn nativeTexSubImage2D( bytes.as_ptr() as *const c_void, ); } - } + }); } } diff --git a/crates/canvas-android/src/lib.rs b/crates/canvas-android/src/lib.rs index 96381ddd2..04b492b8b 100644 --- a/crates/canvas-android/src/lib.rs +++ b/crates/canvas-android/src/lib.rs @@ -111,8 +111,8 @@ pub extern "system" fn JNI_OnLoad(vm: JavaVM, _reserved: *const c_void) -> jint let canvas_signatures = if ret >= ANDROID_O { let mut ret = vec![ - "(Landroid/view/Surface;ZZZZIZZZZZI)J", - "(IIZZZZIZZZZZI)J", + "(Landroid/view/Surface;ZZZZIZZZZZIZ)J", + "(IIZZZZIZZZZZIZ)J", "(IILandroid/view/Surface;ZFIFII)J", "(Landroid/view/Surface;J)V", "(Landroid/view/Surface;IIJ)V", @@ -149,8 +149,8 @@ pub extern "system" fn JNI_OnLoad(vm: JavaVM, _reserved: *const c_void) -> jint ret } else { let mut ret = vec![ - "!(Landroid/view/Surface;ZZZZIZZZZZI)J", - "!(IIZZZZIZZZZZI)J", + "(Landroid/view/Surface;ZZZZIZZZZZIZ)J", + "(IIZZZZIZZZZZIZ)J", "!(IILandroid/view/Surface;ZFIFII)J", "!(Landroid/view/Surface;J)V", "!(Landroid/view/Surface;IIJ)V", diff --git a/crates/canvas-android/src/utils/gl/mod.rs b/crates/canvas-android/src/utils/gl/mod.rs index ebea48ba2..bcb482e9b 100644 --- a/crates/canvas-android/src/utils/gl/mod.rs +++ b/crates/canvas-android/src/utils/gl/mod.rs @@ -26,14 +26,49 @@ pub unsafe extern "system" fn Java_org_nativescript_canvas_Utils_nativeMakeState if state.is_null() { return JNI_FALSE; } - let state = &mut *state; + let state = &*state; - if state.get_inner().make_current() { + if state.sync(|state| state.make_current()) { return JNI_TRUE; } JNI_FALSE } +/// Runs `block` (a `Runnable`) with `state` current, on the thread that owns it, and waits for it: +/// a threaded WebGL context can only be current on the WebGL thread, so Java that draws with it +/// (SurfaceTexture, GLES) has to run there too. +#[no_mangle] +pub unsafe extern "system" fn Java_org_nativescript_canvas_Utils_nativeRunWithWebGL( + mut env: JNIEnv, + _: jni::objects::JClass, + state: jlong, + block: jni::objects::JObject, +) { + if state == 0 { + return; + } + let state = &*(state as *const WebGLState); + if !state.is_threaded() { + state.sync(|state| state.make_current()); + let _ = env.call_method(&block, "run", "()V", &[]); + return; + } + let (Ok(block), Some(vm)) = (env.new_global_ref(block), crate::JVM.get()) else { + return; + }; + state.sync(|state| { + state.make_current(); + if let Ok(mut env) = vm.attach_current_thread_permanently() { + let _ = env.call_method(block.as_obj(), "run", "()V", &[]); + // Surface it here: nothing on this thread would otherwise. + if env.exception_check().unwrap_or(false) { + let _ = env.exception_describe(); + let _ = env.exception_clear(); + } + } + }); +} + /// Makes the EGL context of a 2D canvas context current on the calling thread. /// `context` is a pointer to `CanvasRenderingContext2D`. #[no_mangle] diff --git a/crates/canvas-c/src/c2d/context.rs b/crates/canvas-c/src/c2d/context.rs index 4793b9845..e4b5ca9b1 100644 --- a/crates/canvas-c/src/c2d/context.rs +++ b/crates/canvas-c/src/c2d/context.rs @@ -2452,19 +2452,18 @@ pub extern "C" fn canvas_native_context_draw_image_dx_dy_webgl( assert!(!source.is_null()); // let context = unsafe { &*context }; - let source = unsafe { &mut *source }; - let (width, height) = { - let state = source.get_inner_mut(); + let source = unsafe { &*source }; + // Read where the context lives: a threaded one is only touched on the WebGL thread. + let ((width, height), pixels) = source.sync(|state| { state.make_current(); let (w, h) = state.get_dimensions(); - (w as f32, h as f32) - }; - - let pixels = canvas_native_context_read_webgl_pixels( - &mut source.0, - gl_bindings::RGBA as i32, - gl_bindings::UNSIGNED_BYTE as i32, - ); + let pixels = canvas_native_context_read_webgl_pixels( + state, + gl_bindings::RGBA as i32, + gl_bindings::UNSIGNED_BYTE as i32, + ); + ((w as f32, h as f32), pixels) + }); let ptr = pixels.2.as_ptr(); let size = pixels.2.len(); @@ -2484,19 +2483,18 @@ pub extern "C" fn canvas_native_context_draw_image_dx_dy_dw_dh_webgl( assert!(!source.is_null()); // let context = unsafe { &*context }; - let source = unsafe { &mut *source }; - let (width, height) = { - let state = source.get_inner_mut(); + let source = unsafe { &*source }; + // Read where the context lives: a threaded one is only touched on the WebGL thread. + let ((width, height), pixels) = source.sync(|state| { state.make_current(); let (w, h) = state.get_dimensions(); - (w as f32, h as f32) - }; - - let pixels = canvas_native_context_read_webgl_pixels( - &mut source.0, - gl_bindings::RGBA as i32, - gl_bindings::UNSIGNED_BYTE as i32, - ); + let pixels = canvas_native_context_read_webgl_pixels( + state, + gl_bindings::RGBA as i32, + gl_bindings::UNSIGNED_BYTE as i32, + ); + ((w as f32, h as f32), pixels) + }); let ptr = pixels.2.as_ptr(); let size = pixels.2.len(); @@ -2523,19 +2521,18 @@ pub extern "C" fn canvas_native_context_draw_image_webgl( assert!(!source.is_null()); // let context = unsafe { &*context }; - let source = unsafe { &mut *source }; - let (width, height) = { - let state = source.get_inner_mut(); + let source = unsafe { &*source }; + // Read where the context lives: a threaded one is only touched on the WebGL thread. + let ((width, height), pixels) = source.sync(|state| { state.make_current(); let (w, h) = state.get_dimensions(); - (w as f32, h as f32) - }; - - let pixels = canvas_native_context_read_webgl_pixels( - &mut source.0, - gl_bindings::RGBA as i32, - gl_bindings::UNSIGNED_BYTE as i32, - ); + let pixels = canvas_native_context_read_webgl_pixels( + state, + gl_bindings::RGBA as i32, + gl_bindings::UNSIGNED_BYTE as i32, + ); + ((w as f32, h as f32), pixels) + }); let ptr = pixels.2.as_ptr(); let size = pixels.2.len(); diff --git a/crates/canvas-c/src/c2d/render_thread.rs b/crates/canvas-c/src/c2d/render_thread.rs index 15c57f73a..0f2eea613 100644 --- a/crates/canvas-c/src/c2d/render_thread.rs +++ b/crates/canvas-c/src/c2d/render_thread.rs @@ -2,7 +2,7 @@ //! make the JS thread wait on it. use std::collections::{HashMap, VecDeque}; -use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::atomic::{AtomicBool, AtomicU32, Ordering}; use std::sync::{mpsc, Arc, Condvar, Mutex, OnceLock}; use std::time::Duration; @@ -179,12 +179,20 @@ where rx.recv().ok() } +/// Frames that may merge into one this thread hasn't picked up before `commit` waits for it. +/// Merging keeps committing from blocking, but a frame that doesn't clear the whole canvas keeps +/// everything drawn before it, so an unbounded merge grows without limit and replays ever slower. +const MAX_MERGED_FRAMES: u32 = 4; + /// Drop waits for the real context to go, so its window can be released afterwards. pub struct RenderTarget { id: u64, worker: Arc, open: Mutex>, lost: Arc, + /// Frames merged into the open slot since this thread last took it. Non-zero means this canvas + /// is behind, which holds requestAnimationFrame back (`canvas_native_canvases_behind`). + merged: Arc, } impl RenderTarget { @@ -213,6 +221,7 @@ impl RenderTarget { worker, open: Mutex::new(None), lost, + merged: Arc::new(AtomicU32::new(0)), }) } @@ -225,6 +234,11 @@ impl RenderTarget { if frame.is_empty() { return; } + if self.merged.load(Ordering::Acquire) >= MAX_MERGED_FRAMES { + // Something is drawing faster than this thread can keep up, outside the + // requestAnimationFrame hold-back: wait for the pending frame to be drawn. + self.sync(|_| ()); + } let Ok(mut open) = self.open.lock() else { return; }; @@ -233,6 +247,9 @@ impl RenderTarget { if let Ok(mut pending) = slot.lock() { if let Some(queued) = pending.as_mut() { queued.append(frame.take().expect("set above")); + if self.merged.fetch_add(1, Ordering::AcqRel) == 0 { + crate::webgl::thread::canvas_behind(); + } return; } } @@ -240,8 +257,13 @@ impl RenderTarget { let slot: Slot = Arc::new(Mutex::new(frame)); *open = Some(Arc::clone(&slot)); let id = self.id; + let merged = Arc::clone(&self.merged); self.worker.push(Box::new(move |targets: &mut Targets| { let frame = slot.lock().ok().and_then(|mut pending| pending.take()); + // Taken under the slot's lock above, so a commit merging now lands in a new slot. + if merged.swap(0, Ordering::AcqRel) > 0 { + crate::webgl::thread::canvas_caught_up(); + } if let (Some(frame), Some(entry)) = (frame, targets.contexts.get_mut(&id)) { entry.context.get_context_mut().replay(frame); targets.presents.push(id); @@ -292,6 +314,9 @@ impl RenderTarget { impl Drop for RenderTarget { fn drop(&mut self) { + if self.merged.swap(0, Ordering::AcqRel) > 0 { + crate::webgl::thread::canvas_caught_up(); + } let (tx, rx) = mpsc::sync_channel::<()>(1); let id = self.id; self.worker.push(Box::new(move |targets: &mut Targets| { diff --git a/crates/canvas-c/src/webgl/gl.rs b/crates/canvas-c/src/webgl/gl.rs index cefccc0d4..15d1942ba 100644 --- a/crates/canvas-c/src/webgl/gl.rs +++ b/crates/canvas-c/src/webgl/gl.rs @@ -13,7 +13,8 @@ use canvas_webgl::prelude::WebGLVersion; use std::ffi::{CStr, CString}; use std::os::raw::{c_char, c_void}; use std::ptr::NonNull; -use std::sync::atomic::{AtomicUsize, Ordering}; +use std::cell::UnsafeCell; +use std::sync::atomic::{AtomicBool, AtomicU32, AtomicUsize, Ordering}; /* GL */ @@ -147,25 +148,27 @@ pub extern "C" fn canvas_native_context_create_pattern_webgl( let source = unsafe { &*source }; context.remove_if_current(); - let state = source.get_inner(); - state.make_current(); - let width = state.get_drawing_buffer_width(); - let height = state.get_drawing_buffer_height(); - - let mut buf = vec![0u8; (width * height * 4) as usize]; - - unsafe { - gl_bindings::Flush(); - gl_bindings::ReadPixels( - 0, - 0, - width, - height, - gl_bindings::RGBA, - gl_bindings::UNSIGNED_BYTE, - buf.as_mut_ptr() as *mut c_void, - ); - } + let (width, height, buf) = source.sync(|state| { + state.make_current(); + let width = state.get_drawing_buffer_width(); + let height = state.get_drawing_buffer_height(); + + let mut buf = vec![0u8; (width * height * 4) as usize]; + + unsafe { + gl_bindings::Flush(); + gl_bindings::ReadPixels( + 0, + 0, + width, + height, + gl_bindings::RGBA, + gl_bindings::UNSIGNED_BYTE, + buf.as_mut_ptr() as *mut c_void, + ); + } + (width, height, buf) + }); #[cfg(feature = "gl")] { @@ -189,15 +192,14 @@ pub extern "C" fn canvas_native_context_create_pattern_webgl( #[no_mangle] pub extern "C" fn canvas_native_webgl_make_current(state: *mut WebGLState) -> bool { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - state.get_inner().make_current() + let state = unsafe { &*state }; + state.sync(|state| state.make_current()) } #[no_mangle] pub extern "C" fn canvas_native_webgl_swap_buffers(state: *mut WebGLState) -> bool { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - state.get_inner().swap_buffers() + unsafe { &*state }.present() } #[no_mangle] @@ -205,8 +207,7 @@ pub extern "C" fn canvas_native_webgl_make_current_and_swap_buffers( state: *mut WebGLState, ) -> bool { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - state.get_inner().make_current_and_swap_buffers() + unsafe { &*state }.present() } /* GL */ @@ -228,52 +229,158 @@ pub extern "C" fn canvas_native_webgl_to_data_url( assert!(!format.is_null()); let format = unsafe { CStr::from_ptr(format) }; let format = format.to_string_lossy(); - let state = unsafe { &mut *state }; + let state = unsafe { &*state }; + state.sync(|state| { + let info = state; + info.make_current(); + let width = info.drawing_buffer_width(); + let height = info.drawing_buffer_height(); + // gl_bindings::PixelStorei(gl_bindings::UNPACK_ALIGNMENT, 1); + let mut buffer = vec![0u8; (width * height * 4) as usize]; + unsafe { + gl_bindings::ReadPixels( + 0, + 0, + width, + height, + gl_bindings::RGBA, + gl_bindings::UNSIGNED_BYTE, + buffer.as_mut_ptr() as *mut c_void, + ); + } - let info = state.get_inner(); - info.make_current(); - let width = info.drawing_buffer_width(); - let height = info.drawing_buffer_height(); - // gl_bindings::PixelStorei(gl_bindings::UNPACK_ALIGNMENT, 1); - let mut buffer = vec![0u8; (width * height * 4) as usize]; - unsafe { - gl_bindings::ReadPixels( - 0, - 0, + CString::new(canvas_2d::bytes_to_data_url( width, height, - gl_bindings::RGBA, - gl_bindings::UNSIGNED_BYTE, - buffer.as_mut_ptr() as *mut c_void, - ); - } - - CString::new(canvas_2d::bytes_to_data_url( - width, - height, - buffer.as_slice(), - format.as_ref(), - quality, - )) - .unwrap() - .into_raw() + buffer.as_slice(), + format.as_ref(), + quality, + )) + .unwrap() + .into_raw() + }) } +/// A WebGL context. A threaded one is built, used and dropped on the WebGL thread (`thread`), and +/// its inner state is only ever touched there: calls reach it through `post` and `sync`. #[derive(Debug)] -pub struct WebGLState(pub(crate) canvas_webgl::prelude::WebGLState, AtomicUsize); +pub struct WebGLState { + inner: UnsafeCell, + refs: AtomicUsize, + threaded: bool, + /// Presents queued and not yet made (threaded only). + in_flight: AtomicU32, + /// Queued presents are skipped: the context is letting go of its window (threaded only). + detaching: AtomicBool, +} + +/// Presents a threaded context may have queued before `present` waits for the oldest. +const MAX_QUEUED_FRAMES: u32 = 3; + +#[derive(Clone, Copy)] +struct StatePtr(*const WebGLState); + +// A threaded state is only dereferenced on the WebGL thread, and dropped there after every job +// that holds one of these. +unsafe impl Send for StatePtr {} impl WebGLState { pub fn get_dimensions(&self) -> (i32, i32) { - self.0.get_dimensions() + self.sync(|state| state.get_dimensions()) } pub fn get_version(&self) -> i32 { - match self.0.get_version() { + match self.sync(|state| state.get_version()) { WebGLVersion::V1 => 1, WebGLVersion::V2 => 2, WebGLVersion::NONE => 0, } } + + pub fn is_threaded(&self) -> bool { + self.threaded + } + + #[allow(clippy::mut_from_ref)] + fn inner_mut(&self) -> &mut canvas_webgl::prelude::WebGLState { + debug_assert!(!self.threaded || crate::webgl::thread::on_gl_thread()); + unsafe { &mut *self.inner.get() } + } + + /// Runs `f` against the context. A threaded context queues it behind earlier calls and + /// returns at once, so it must own what it uses: copy anything borrowed from the caller. + pub fn post(&self, f: impl FnOnce(&mut canvas_webgl::prelude::WebGLState) + Send + 'static) { + if !self.threaded { + return f(self.inner_mut()); + } + let state = StatePtr(self); + crate::webgl::thread::post(move || { + let state = state; + f(unsafe { &*state.0 }.inner_mut()) + }); + } + + /// Runs `f` against the context and returns its result; a threaded context runs it after every + /// queued call while the caller waits. + pub fn sync(&self, f: impl FnOnce(&mut canvas_webgl::prelude::WebGLState) -> R) -> R { + if !self.threaded { + return f(self.inner_mut()); + } + crate::webgl::thread::sync(|| f(self.inner_mut())) + } + + /// Ends a frame. A threaded context queues the present, waiting only once it has + /// `MAX_QUEUED_FRAMES` queued: something drawing outside requestAnimationFrame, which the JS + /// side holds back, would otherwise queue frames without limit. + pub fn present(&self) -> bool { + if !self.threaded { + return self.inner_mut().make_current_and_swap_buffers(); + } + if self.in_flight.load(Ordering::Acquire) >= MAX_QUEUED_FRAMES { + crate::webgl::thread::sync(|| ()); + } + crate::webgl::thread::frame_queued(self.in_flight.fetch_add(1, Ordering::AcqRel)); + let state = StatePtr(self); + crate::webgl::thread::post(move || { + let state = state; + let state = unsafe { &*state.0 }; + if !state.detaching.load(Ordering::Acquire) { + state.inner_mut().make_current_and_swap_buffers(); + } + crate::webgl::thread::frame_presented(state.in_flight.fetch_sub(1, Ordering::AcqRel)); + }); + true + } + + /// Runs `f` (which lets go of the window) after every queued call, skipping the presents queued + /// meanwhile: they are for a window that is going away, and waiting on each would stall the + /// caller for as many frames as the GPU is behind. + pub fn detach(&self, f: impl FnOnce(&mut canvas_webgl::prelude::WebGLState) -> R) -> R { + self.detaching.store(true, Ordering::Release); + let result = self.sync(f); + self.detaching.store(false, Ordering::Release); + result + } + + /// The drawing buffer as an image (`canvas_native_webgl_read_drawing_buffer`), read on the + /// thread that owns the context. + pub(crate) fn read_drawing_buffer(&self) -> (i32, i32, Vec) { + self.sync(|state| canvas_webgl::webgl::canvas_native_webgl_read_drawing_buffer(state)) + } + + /// Builds a context on the WebGL thread with `create`, which then owns it; falls back to + /// building it here if that thread couldn't start. + pub fn create_threaded(create: impl FnOnce() -> Option) -> *mut WebGLState { + if !crate::webgl::thread::available() { + return create().map_or(std::ptr::null_mut(), |state| Box::into_raw(Box::new(state))); + } + crate::webgl::thread::sync(|| { + create().map_or(std::ptr::null_mut(), |mut state| { + state.threaded = true; + Box::into_raw(Box::new(state)) + }) + }) + } } #[no_mangle] @@ -281,7 +388,7 @@ pub extern "C" fn canvas_native_webgl_state_reference(state: *const WebGLState) if state.is_null() { return; } - unsafe { &*state }.1.fetch_add(1, Ordering::Relaxed); + unsafe { &*state }.refs.fetch_add(1, Ordering::Relaxed); } #[no_mangle] @@ -289,14 +396,31 @@ pub extern "C" fn canvas_native_webgl_state_destroy(state: *mut WebGLState) { if state.is_null() { return; } - if unsafe { &*state }.1.fetch_sub(1, Ordering::AcqRel) == 1 { + if unsafe { &*state }.refs.fetch_sub(1, Ordering::AcqRel) != 1 { + return; + } + if unsafe { &*state }.threaded { + // Queued after every job that uses it. Not waited on: a view lets go of its window first + // (the no-surface update, which does wait), so nothing depends on this having run. + let state = StatePtr(state); + crate::webgl::thread::post(move || { + let state = state; + let _ = unsafe { Box::from_raw(state.0 as *mut WebGLState) }; + }); + } else { let _ = unsafe { Box::from_raw(state) }; } } impl WebGLState { fn wrap(state: canvas_webgl::prelude::WebGLState) -> Self { - Self(state, AtomicUsize::new(1)) + Self { + inner: UnsafeCell::new(state), + refs: AtomicUsize::new(1), + threaded: false, + in_flight: AtomicU32::new(0), + detaching: AtomicBool::new(false), + } } } @@ -449,12 +573,14 @@ impl WebGLState { ), ) } + /// The context itself, for a caller already on the thread that owns it (any thread for an + /// unthreaded one). Everything else goes through `post` or `sync`. pub fn get_inner(&self) -> &canvas_webgl::prelude::WebGLState { - &self.0 + self.inner_mut() } pub fn get_inner_mut(&mut self) -> &mut canvas_webgl::prelude::WebGLState { - &mut self.0 + self.inner_mut() } } @@ -583,12 +709,43 @@ impl WebGLShaderPrecisionFormat { } } -pub struct WebGLExtension(Option>); +/// `.1`: its context is threaded, so the typed extension's calls go to the WebGL thread too. +pub struct WebGLExtension(Option>, bool); impl WebGLExtension { pub fn new(extension: Option>) -> Self { - Self(extension) + Self(extension, false) + } +} + +/// Runs an extension call where its context lives: see `WebGLState::sync`. +fn ext_sync(threaded: bool, f: impl FnOnce() -> R) -> R { + if threaded { + crate::webgl::thread::sync(f) + } else { + f() + } +} + +#[derive(Clone, Copy)] +struct ExtPtr(*const T); + +// Only dereferenced on the WebGL thread, by a job that runs before the extension can be dropped: +// see `ext_post`. +unsafe impl Send for ExtPtr {} + +/// Queues an extension call behind its context's earlier calls. The JS wrapper keeps the extension +/// alive while its context lives, and the context is destroyed on the WebGL thread after queued +/// jobs, so the extension outlives the job. +fn ext_post(threaded: bool, ext: &T, f: impl FnOnce(&T) + Send + 'static) { + if !threaded { + return f(ext); } + let ext = ExtPtr(ext as *const T); + crate::webgl::thread::post(move || { + let ext = ext; + f(unsafe { &*ext.0 }) + }); } #[no_mangle] @@ -612,36 +769,41 @@ impl WebGLExtension { } pub fn into_ext_disjoint_timer_query(self) -> Box { + let threaded = self.1; let ext = Box::into_raw(self.0.unwrap()); let ext = unsafe { Box::from_raw(ext as *mut canvas_webgl::prelude::EXT_disjoint_timer_query) }; - Box::new(EXT_disjoint_timer_query(*ext)) + Box::new(EXT_disjoint_timer_query(*ext, threaded)) } pub fn into_angle_instanced_arrays(self) -> Box { + let threaded = self.1; let ext = Box::into_raw(self.0.unwrap()); let ext = unsafe { Box::from_raw(ext as *mut canvas_webgl::prelude::ANGLE_instanced_arrays) }; - Box::new(ANGLE_instanced_arrays(*ext)) + Box::new(ANGLE_instanced_arrays(*ext, threaded)) } pub fn into_lose_context(self) -> Box { + let threaded = self.1; let ext = Box::into_raw(self.0.unwrap()); let ext = unsafe { Box::from_raw(ext as *mut canvas_webgl::prelude::WEBGL_lose_context) }; - Box::new(WEBGL_lose_context(*ext)) + Box::new(WEBGL_lose_context(*ext, threaded)) } pub fn into_draw_buffers(self) -> Box { + let threaded = self.1; let ext = Box::into_raw(self.0.unwrap()); let ext = unsafe { Box::from_raw(ext as *mut canvas_webgl::prelude::WEBGL_draw_buffers) }; - Box::new(WEBGL_draw_buffers(*ext)) + Box::new(WEBGL_draw_buffers(*ext, threaded)) } pub fn into_oes_vertex_array_object(self) -> Box { + let threaded = self.1; let ext = Box::into_raw(self.0.unwrap()); let ext = unsafe { Box::from_raw(ext as *mut canvas_webgl::prelude::OES_vertex_array_object) }; - Box::new(OES_vertex_array_object(*ext)) + Box::new(OES_vertex_array_object(*ext, threaded)) } } @@ -670,7 +832,7 @@ pub extern "C" fn canvas_native_webgl_EXT_color_buffer_half_float_destroy( } #[allow(non_camel_case_types)] -pub struct EXT_disjoint_timer_query(canvas_webgl::prelude::EXT_disjoint_timer_query); +pub struct EXT_disjoint_timer_query(canvas_webgl::prelude::EXT_disjoint_timer_query, bool); #[no_mangle] pub extern "C" fn canvas_native_webgl_EXT_disjoint_timer_query_destroy( @@ -796,7 +958,7 @@ pub extern "C" fn canvas_native_webgl_OES_texture_half_float_linear_destroy( } #[allow(non_camel_case_types)] -pub struct OES_vertex_array_object(canvas_webgl::prelude::OES_vertex_array_object); +pub struct OES_vertex_array_object(canvas_webgl::prelude::OES_vertex_array_object, bool); #[no_mangle] pub extern "C" fn canvas_native_webgl_OES_vertex_array_object_destroy( @@ -900,7 +1062,7 @@ pub extern "C" fn canvas_native_webgl_WEBGL_compressed_texture_pvrtc_destroy( } #[allow(non_camel_case_types)] -pub struct WEBGL_lose_context(canvas_webgl::prelude::WEBGL_lose_context); +pub struct WEBGL_lose_context(canvas_webgl::prelude::WEBGL_lose_context, bool); #[no_mangle] pub extern "C" fn canvas_native_webgl_WEBGL_lose_context_destroy(value: *mut WEBGL_lose_context) { @@ -911,7 +1073,7 @@ pub extern "C" fn canvas_native_webgl_WEBGL_lose_context_destroy(value: *mut WEB } #[allow(non_camel_case_types)] -pub struct ANGLE_instanced_arrays(canvas_webgl::prelude::ANGLE_instanced_arrays); +pub struct ANGLE_instanced_arrays(canvas_webgl::prelude::ANGLE_instanced_arrays, bool); #[no_mangle] pub extern "C" fn canvas_native_webgl_ANGLE_instanced_arrays_destroy( @@ -935,7 +1097,7 @@ pub extern "C" fn canvas_native_webgl_WEBGL_depth_texture_destroy(value: *mut WE } #[allow(non_camel_case_types)] -pub struct WEBGL_draw_buffers(canvas_webgl::prelude::WEBGL_draw_buffers); +pub struct WEBGL_draw_buffers(canvas_webgl::prelude::WEBGL_draw_buffers, bool); #[no_mangle] pub extern "C" fn canvas_native_webgl_WEBGL_draw_buffers_destroy(value: *mut WEBGL_draw_buffers) { @@ -1417,13 +1579,13 @@ pub extern "C" fn canvas_native_webgl_state_get_unpack_colorspace_conversion_web state: *mut WebGLState, ) -> i32 { let state = unsafe { &*state }; - state.get_inner().get_unpack_colorspace_conversion_webgl() + state.sync(|state| state.get_unpack_colorspace_conversion_webgl()) } #[no_mangle] pub extern "C" fn canvas_native_webgl_state_get_flip_y(state: *mut WebGLState) -> bool { let state = unsafe { &*state }; - state.get_inner().get_flip_y() + state.sync(|state| state.get_flip_y()) } #[no_mangle] @@ -1431,7 +1593,7 @@ pub extern "C" fn canvas_native_webgl_state_get_premultiplied_alpha( state: *mut WebGLState, ) -> bool { let state = unsafe { &*state }; - state.get_inner().get_premultiplied_alpha() + state.sync(|state| state.get_premultiplied_alpha()) } #[no_mangle] @@ -1439,7 +1601,7 @@ pub extern "C" fn canvas_native_webgl_state_get_drawing_buffer_width( state: *mut WebGLState, ) -> i32 { let state = unsafe { &*state }; - state.get_inner().get_drawing_buffer_width() + state.sync(|state| state.get_drawing_buffer_width()) } #[no_mangle] @@ -1447,7 +1609,7 @@ pub extern "C" fn canvas_native_webgl_state_get_drawing_buffer_height( state: *mut WebGLState, ) -> i32 { let state = unsafe { &*state }; - state.get_inner().get_drawing_buffer_height() + state.sync(|state| state.get_drawing_buffer_height()) } /* WebGLState */ @@ -1458,7 +1620,7 @@ pub extern "C" fn canvas_native_webgl_ext_disjoint_timer_query_create_query_ext( query: *const EXT_disjoint_timer_query, ) -> u32 { let query = unsafe { &*query }; - query.0.create_query_ext() + ext_sync(query.1, || query.0.create_query_ext()) } #[no_mangle] @@ -1467,7 +1629,7 @@ pub extern "C" fn canvas_native_webgl_ext_disjoint_timer_query_delete_query_ext( query: *const EXT_disjoint_timer_query, ) { let query = unsafe { &*query }; - query.0.delete_query_ext(value) + ext_post(query.1, query, move |ext| ext.0.delete_query_ext(value)); } #[no_mangle] @@ -1476,7 +1638,7 @@ pub extern "C" fn canvas_native_webgl_ext_disjoint_timer_query_is_query_ext( query: *const EXT_disjoint_timer_query, ) -> bool { let query = unsafe { &*query }; - query.0.is_query_ext(value) + ext_sync(query.1, || query.0.is_query_ext(value)) } #[no_mangle] @@ -1486,7 +1648,9 @@ pub extern "C" fn canvas_native_webgl_ext_disjoint_timer_query_begin_query_ext( query: *const EXT_disjoint_timer_query, ) { let query = unsafe { &*query }; - query.0.begin_query_ext(target, value) + ext_post(query.1, query, move |ext| { + ext.0.begin_query_ext(target, value) + }); } #[no_mangle] @@ -1495,7 +1659,7 @@ pub extern "C" fn canvas_native_webgl_ext_disjoint_timer_query_end_query_ext( query: *const EXT_disjoint_timer_query, ) { let query = unsafe { &*query }; - query.0.end_query_ext(target) + ext_post(query.1, query, move |ext| ext.0.end_query_ext(target)); } #[no_mangle] @@ -1505,7 +1669,9 @@ pub extern "C" fn canvas_native_webgl_ext_disjoint_timer_query_query_counter_ext query: *const EXT_disjoint_timer_query, ) { let query = unsafe { &*query }; - query.0.query_counter_ext(value, target) + ext_post(query.1, query, move |ext| { + ext.0.query_counter_ext(value, target) + }); } #[no_mangle] @@ -1515,7 +1681,7 @@ pub extern "C" fn canvas_native_webgl_ext_disjoint_timer_query_get_query_ext( query: *const EXT_disjoint_timer_query, ) -> i32 { let query = unsafe { &*query }; - query.0.get_query_ext(target, pname) + ext_sync(query.1, || query.0.get_query_ext(target, pname)) } #[no_mangle] @@ -1525,9 +1691,11 @@ pub extern "C" fn canvas_native_webgl_ext_disjoint_timer_query_get_query_object_ query: *const EXT_disjoint_timer_query, ) -> *mut WebGLResult { let query = unsafe { &*query }; - Box::into_raw(Box::new(WebGLResult( - query.0.get_query_object_ext(target, pname), - ))) + ext_sync(query.1, || { + Box::into_raw(Box::new(WebGLResult( + query.0.get_query_object_ext(target, pname), + ))) + }) } /* EXT_disjoint_timer_query */ @@ -1542,9 +1710,10 @@ pub extern "C" fn canvas_native_webgl_angle_instanced_arrays_draw_arrays_instanc arrays: *const ANGLE_instanced_arrays, ) { let arrays = unsafe { &*arrays }; - arrays - .0 - .draw_arrays_instanced_angle(mode, first, count, primcount) + ext_post(arrays.1, arrays, move |ext| { + ext.0 + .draw_arrays_instanced_angle(mode, first, count, primcount) + }); } #[no_mangle] @@ -1557,9 +1726,10 @@ pub extern "C" fn canvas_native_webgl_angle_instanced_arrays_draw_elements_insta arrays: *const ANGLE_instanced_arrays, ) { let arrays = unsafe { &*arrays }; - arrays - .0 - .draw_elements_instanced_angle(mode, count, type_, offset, primcount) + ext_post(arrays.1, arrays, move |ext| { + ext.0 + .draw_elements_instanced_angle(mode, count, type_, offset, primcount) + }); } #[no_mangle] @@ -1569,7 +1739,9 @@ pub extern "C" fn canvas_native_webgl_angle_instanced_arrays_vertex_attrib_divis arrays: *const ANGLE_instanced_arrays, ) { let arrays = unsafe { &*arrays }; - arrays.0.vertex_attrib_divisor_angle(index, divisor) + ext_post(arrays.1, arrays, move |ext| { + ext.0.vertex_attrib_divisor_angle(index, divisor) + }); } /* ANGLE_instanced_arrays */ @@ -1579,8 +1751,7 @@ pub extern "C" fn canvas_native_webgl_lose_context_lose_context( context: *const WEBGL_lose_context, ) { let context = unsafe { &*context }; - - context.0.lose_context() + ext_post(context.1, context, move |ext| ext.0.lose_context()); } #[no_mangle] @@ -1588,7 +1759,7 @@ pub extern "C" fn canvas_native_webgl_lose_context_restore_context( context: *const WEBGL_lose_context, ) { let context = unsafe { &*context }; - context.0.restore_context() + ext_post(context.1, context, move |ext| ext.0.restore_context()); } /* WEBGL_lose_context */ @@ -1603,7 +1774,10 @@ pub extern "C" fn canvas_native_webgl_draw_buffers_draw_buffers_webgl( assert!(!context.is_null()); let buffers = unsafe { std::slice::from_raw_parts(buffers, size) }; let context = unsafe { &*context }; - context.0.draw_buffers_webgl(buffers); + let buffers = buffers.to_vec(); + ext_post(context.1, context, move |ext| { + ext.0.draw_buffers_webgl(&buffers) + }); } /* WEBGL_draw_buffers */ @@ -1615,7 +1789,7 @@ pub extern "C" fn canvas_native_webgl_oes_vertex_array_object_create_vertex_arra object: *const OES_vertex_array_object, ) -> u32 { let object = unsafe { &*object }; - object.0.create_vertex_array_oes() + ext_sync(object.1, || object.0.create_vertex_array_oes()) } #[no_mangle] @@ -1624,7 +1798,9 @@ pub extern "C" fn canvas_native_webgl_oes_vertex_array_object_delete_vertex_arra object: *const OES_vertex_array_object, ) { let object = unsafe { &*object }; - object.0.delete_vertex_array_oes(array_object) + ext_post(object.1, object, move |ext| { + ext.0.delete_vertex_array_oes(array_object) + }); } #[no_mangle] @@ -1633,7 +1809,7 @@ pub extern "C" fn canvas_native_webgl_oes_vertex_array_object_is_vertex_array_oe object: *const OES_vertex_array_object, ) -> bool { let object = unsafe { &*object }; - object.0.is_vertex_array_oes(array_object) + ext_sync(object.1, || object.0.is_vertex_array_oes(array_object)) } #[no_mangle] @@ -1642,7 +1818,9 @@ pub extern "C" fn canvas_native_webgl_oes_vertex_array_object_bind_vertex_array_ object: *const OES_vertex_array_object, ) { let object = unsafe { &*object }; - object.0.bind_vertex_array_oes(array_object) + ext_post(object.1, object, move |ext| { + ext.0.bind_vertex_array_oes(array_object) + }); } /* OES_vertex_array_object */ @@ -1785,6 +1963,95 @@ pub extern "C" fn canvas_native_webgl_create_no_window( } } +/// `canvas_native_webgl_create`, for a context that lives on the WebGL thread. +#[cfg(target_os = "android")] +pub extern "C" fn canvas_native_webgl_create_threaded( + view: *mut c_void, + width: i32, + height: i32, + version: i32, + alpha: bool, + antialias: bool, + depth: bool, + fail_if_major_performance_caveat: bool, + power_preference: i32, + premultiplied_alpha: bool, + preserve_drawing_buffer: bool, + stencil: bool, + desynchronized: bool, + xr_compatible: bool, +) -> *mut WebGLState { + let (Some(version), Some(power_preference)) = ( + WebGLVersion::try_from(version).ok(), + PowerPreference::try_from(power_preference).ok(), + ) else { + return std::ptr::null_mut(); + }; + WebGLState::create_threaded(|| { + WebGLState::new_with_view( + view, + width, + height, + version, + alpha, + antialias, + depth, + fail_if_major_performance_caveat, + power_preference, + premultiplied_alpha, + preserve_drawing_buffer, + stencil, + desynchronized, + xr_compatible, + false, + ) + }) +} + +/// `canvas_native_webgl_create_no_window`, for a context that lives on the WebGL thread. +#[cfg(target_os = "android")] +pub extern "C" fn canvas_native_webgl_create_no_window_threaded( + width: i32, + height: i32, + version: i32, + alpha: bool, + antialias: bool, + depth: bool, + fail_if_major_performance_caveat: bool, + power_preference: i32, + premultiplied_alpha: bool, + preserve_drawing_buffer: bool, + stencil: bool, + desynchronized: bool, + xr_compatible: bool, + is_canvas: bool, +) -> *mut WebGLState { + let (Some(version), Some(power_preference)) = ( + WebGLVersion::try_from(version).ok(), + PowerPreference::try_from(power_preference).ok(), + ) else { + return std::ptr::null_mut(); + }; + WebGLState::create_threaded(|| { + canvas_native_webgl_create_no_window_internal( + width, + height, + version, + alpha, + antialias, + depth, + fail_if_major_performance_caveat, + power_preference, + premultiplied_alpha, + preserve_drawing_buffer, + stencil, + desynchronized, + xr_compatible, + is_canvas, + ) + }) +} + /// Windows: a WebGL context whose drawing buffer can be shown in a `SwapChainPanel` /// (`canvas_native_webgl_attach_swap_chain_panel`). Null when ANGLE is unavailable. #[cfg(target_os = "windows")] @@ -1913,7 +2180,7 @@ pub extern "C" fn canvas_native_webgl_present(state: *mut WebGLState) -> bool { } #[cfg(not(target_os = "windows"))] { - state.get_inner().make_current_and_swap_buffers() + state.present() } } @@ -1970,8 +2237,8 @@ pub(crate) fn canvas_native_webgl_create_no_window_internal( #[no_mangle] pub extern "C" fn canvas_native_webgl_active_texture(texture: u32, state: *mut WebGLState) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_active_texture(texture, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| canvas_webgl::webgl::canvas_native_webgl_active_texture(texture, state)) } #[no_mangle] @@ -1980,8 +2247,10 @@ pub extern "C" fn canvas_native_webgl_attach_shader( shader: u32, state: *mut WebGLState, ) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_attach_shader(program, shader, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_attach_shader(program, shader, state) + }) } #[no_mangle] @@ -1995,14 +2264,11 @@ pub extern "C" fn canvas_native_webgl_bind_attrib_location( return; } let name = unsafe { CStr::from_ptr(name) }; - let name = name.to_string_lossy(); - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_bind_attrib_location( - program, - index, - name.as_ref(), - state.get_inner_mut(), - ) + let name = name.to_string_lossy().into_owned(); + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_bind_attrib_location(program, index, &name, state) + }) } #[no_mangle] @@ -2011,8 +2277,10 @@ pub extern "C" fn canvas_native_webgl_bind_buffer( buffer: u32, state: *mut WebGLState, ) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_bind_buffer(target, buffer, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_bind_buffer(target, buffer, state) + }) } #[no_mangle] @@ -2021,12 +2289,10 @@ pub extern "C" fn canvas_native_webgl_bind_frame_buffer( framebuffer: u32, state: *mut WebGLState, ) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_bind_frame_buffer( - target, - framebuffer, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_bind_frame_buffer(target, framebuffer, state) + }) } #[no_mangle] @@ -2035,12 +2301,10 @@ pub extern "C" fn canvas_native_webgl_bind_render_buffer( renderbuffer: u32, state: *mut WebGLState, ) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_bind_render_buffer( - target, - renderbuffer, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_bind_render_buffer(target, renderbuffer, state) + }) } #[no_mangle] @@ -2049,8 +2313,10 @@ pub extern "C" fn canvas_native_webgl_bind_texture( texture: u32, state: *mut WebGLState, ) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_bind_texture(target, texture, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_bind_texture(target, texture, state) + }) } #[no_mangle] @@ -2061,14 +2327,10 @@ pub extern "C" fn canvas_native_webgl_blend_color( alpha: f32, state: *mut WebGLState, ) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_blend_color( - red, - green, - blue, - alpha, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_blend_color(red, green, blue, alpha, state) + }) } #[no_mangle] @@ -2077,18 +2339,18 @@ pub extern "C" fn canvas_native_webgl_blend_equation_separate( mode_alpha: u32, state: *mut WebGLState, ) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_blend_equation_separate( - mode_rgb, - mode_alpha, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_blend_equation_separate( + mode_rgb, mode_alpha, state, + ) + }) } #[no_mangle] pub extern "C" fn canvas_native_webgl_blend_equation(mode: u32, state: *mut WebGLState) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_blend_equation(mode, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| canvas_webgl::webgl::canvas_native_webgl_blend_equation(mode, state)) } #[no_mangle] @@ -2099,14 +2361,12 @@ pub extern "C" fn canvas_native_webgl_blend_func_separate( dst_alpha: u32, state: *mut WebGLState, ) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_blend_func_separate( - src_rgb, - dst_rgb, - src_alpha, - dst_alpha, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_blend_func_separate( + src_rgb, dst_rgb, src_alpha, dst_alpha, state, + ) + }) } #[no_mangle] @@ -2115,8 +2375,10 @@ pub extern "C" fn canvas_native_webgl_blend_func( dfactor: u32, state: *mut WebGLState, ) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_blend_func(sfactor, dfactor, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_blend_func(sfactor, dfactor, state) + }) } #[no_mangle] @@ -2129,13 +2391,11 @@ pub extern "C" fn canvas_native_webgl_buffer_data( ) { assert!(!state.is_null()); let src_data = unsafe { std::slice::from_raw_parts(src_data, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_buffer_data( - target, - src_data, - usage, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let src_data = src_data.to_vec(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_buffer_data(target, &src_data, usage, state) + }) } #[no_mangle] @@ -2148,13 +2408,11 @@ pub extern "C" fn canvas_native_webgl_buffer_data_i8( ) { assert!(!state.is_null()); let src_data = unsafe { std::slice::from_raw_parts(src_data, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_buffer_data_i8( - target, - src_data, - usage, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let src_data = src_data.to_vec(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_buffer_data_i8(target, &src_data, usage, state) + }) } #[no_mangle] @@ -2167,13 +2425,11 @@ pub extern "C" fn canvas_native_webgl_buffer_data_u16( ) { assert!(!state.is_null()); let src_data = unsafe { std::slice::from_raw_parts(src_data, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_buffer_data_u16( - target, - src_data, - usage, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let src_data = src_data.to_vec(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_buffer_data_u16(target, &src_data, usage, state) + }) } #[no_mangle] @@ -2186,13 +2442,11 @@ pub extern "C" fn canvas_native_webgl_buffer_data_i16( ) { assert!(!state.is_null()); let src_data = unsafe { std::slice::from_raw_parts(src_data, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_buffer_data_i16( - target, - src_data, - usage, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let src_data = src_data.to_vec(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_buffer_data_i16(target, &src_data, usage, state) + }) } #[no_mangle] @@ -2205,13 +2459,11 @@ pub extern "C" fn canvas_native_webgl_buffer_data_u32( ) { assert!(!state.is_null()); let src_data = unsafe { std::slice::from_raw_parts(src_data, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_buffer_data_u32( - target, - src_data, - usage, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let src_data = src_data.to_vec(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_buffer_data_u32(target, &src_data, usage, state) + }) } #[no_mangle] @@ -2224,13 +2476,11 @@ pub extern "C" fn canvas_native_webgl_buffer_data_i32( ) { assert!(!state.is_null()); let src_data = unsafe { std::slice::from_raw_parts(src_data, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_buffer_data_i32( - target, - src_data, - usage, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let src_data = src_data.to_vec(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_buffer_data_i32(target, &src_data, usage, state) + }) } #[no_mangle] @@ -2242,13 +2492,11 @@ pub extern "C" fn canvas_native_webgl_buffer_data_f32( state: *mut WebGLState, ) { let src_data = unsafe { std::slice::from_raw_parts(src_data, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_buffer_data_f32( - target, - src_data, - usage, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let src_data = src_data.to_vec(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_buffer_data_f32(target, &src_data, usage, state) + }) } #[no_mangle] @@ -2260,13 +2508,11 @@ pub extern "C" fn canvas_native_webgl_buffer_data_f64( state: *mut WebGLState, ) { let src_data = unsafe { std::slice::from_raw_parts(src_data, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_buffer_data_f64( - target, - src_data, - usage, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let src_data = src_data.to_vec(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_buffer_data_f64(target, &src_data, usage, state) + }) } #[no_mangle] @@ -2276,13 +2522,10 @@ pub extern "C" fn canvas_native_webgl_buffer_data_none( usage: u32, state: *mut WebGLState, ) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_buffer_data_none( - target, - size, - usage, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_buffer_data_none(target, size, usage, state) + }) } #[no_mangle] @@ -2295,13 +2538,11 @@ pub extern "C" fn canvas_native_webgl_buffer_sub_data( ) { assert!(!state.is_null()); let src_data = unsafe { std::slice::from_raw_parts(src_data, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_buffer_sub_data( - target, - offset, - src_data, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let src_data = src_data.to_vec(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_buffer_sub_data(target, offset, &src_data, state) + }) } #[no_mangle] @@ -2314,13 +2555,13 @@ pub extern "C" fn canvas_native_webgl_buffer_sub_data_i8( ) { assert!(!state.is_null()); let src_data = unsafe { std::slice::from_raw_parts(src_data, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_buffer_sub_data_i8( - target, - offset, - src_data, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let src_data = src_data.to_vec(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_buffer_sub_data_i8( + target, offset, &src_data, state, + ) + }) } #[no_mangle] @@ -2333,13 +2574,13 @@ pub extern "C" fn canvas_native_webgl_buffer_sub_data_i16( ) { assert!(!state.is_null()); let src_data = unsafe { std::slice::from_raw_parts(src_data, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_buffer_sub_data_i16( - target, - offset, - src_data, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let src_data = src_data.to_vec(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_buffer_sub_data_i16( + target, offset, &src_data, state, + ) + }) } #[no_mangle] @@ -2352,13 +2593,13 @@ pub extern "C" fn canvas_native_webgl_buffer_sub_data_u16( ) { assert!(!state.is_null()); let src_data = unsafe { std::slice::from_raw_parts(src_data, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_buffer_sub_data_u16( - target, - offset, - src_data, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let src_data = src_data.to_vec(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_buffer_sub_data_u16( + target, offset, &src_data, state, + ) + }) } #[no_mangle] @@ -2371,13 +2612,13 @@ pub extern "C" fn canvas_native_webgl_buffer_sub_data_i32( ) { assert!(!state.is_null()); let src_data = unsafe { std::slice::from_raw_parts(src_data, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_buffer_sub_data_i32( - target, - offset, - src_data, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let src_data = src_data.to_vec(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_buffer_sub_data_i32( + target, offset, &src_data, state, + ) + }) } #[no_mangle] @@ -2390,13 +2631,13 @@ pub extern "C" fn canvas_native_webgl_buffer_sub_data_u32( ) { assert!(!state.is_null()); let src_data = unsafe { std::slice::from_raw_parts(src_data, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_buffer_sub_data_u32( - target, - offset, - src_data, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let src_data = src_data.to_vec(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_buffer_sub_data_u32( + target, offset, &src_data, state, + ) + }) } #[no_mangle] @@ -2409,13 +2650,13 @@ pub extern "C" fn canvas_native_webgl_buffer_sub_data_f32( ) { assert!(!state.is_null()); let src_data = unsafe { std::slice::from_raw_parts(src_data, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_buffer_sub_data_f32( - target, - offset, - src_data, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let src_data = src_data.to_vec(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_buffer_sub_data_f32( + target, offset, &src_data, state, + ) + }) } #[no_mangle] @@ -2428,13 +2669,13 @@ pub extern "C" fn canvas_native_webgl_buffer_sub_data_f64( ) { assert!(!state.is_null()); let src_data = unsafe { std::slice::from_raw_parts(src_data, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_buffer_sub_data_f64( - target, - offset, - src_data, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let src_data = src_data.to_vec(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_buffer_sub_data_f64( + target, offset, &src_data, state, + ) + }) } #[no_mangle] @@ -2443,12 +2684,10 @@ pub extern "C" fn canvas_native_webgl_buffer_sub_data_none( offset: isize, state: *mut WebGLState, ) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_buffer_sub_data_none( - target, - offset, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_buffer_sub_data_none(target, offset, state) + }) } #[no_mangle] @@ -2456,17 +2695,16 @@ pub extern "C" fn canvas_native_webgl_check_frame_buffer_status( target: u32, state: *mut WebGLState, ) -> u32 { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_check_frame_buffer_status( - target, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.sync(|state| { + canvas_webgl::webgl::canvas_native_webgl_check_frame_buffer_status(target, state) + }) } #[no_mangle] pub extern "C" fn canvas_native_webgl_clear(mask: u32, state: *mut WebGLState) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_clear(mask, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| canvas_webgl::webgl::canvas_native_webgl_clear(mask, state)) } #[no_mangle] @@ -2477,26 +2715,22 @@ pub extern "C" fn canvas_native_webgl_clear_color( alpha: f32, state: *mut WebGLState, ) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_clear_color( - red, - green, - blue, - alpha, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_clear_color(red, green, blue, alpha, state) + }) } #[no_mangle] pub extern "C" fn canvas_native_webgl_clear_depth(depth: f32, state: *mut WebGLState) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_clear_depth(depth, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| canvas_webgl::webgl::canvas_native_webgl_clear_depth(depth, state)) } #[no_mangle] pub extern "C" fn canvas_native_webgl_clear_stencil(stencil: i32, state: *mut WebGLState) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_clear_stencil(stencil, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| canvas_webgl::webgl::canvas_native_webgl_clear_stencil(stencil, state)) } #[no_mangle] @@ -2507,14 +2741,10 @@ pub extern "C" fn canvas_native_webgl_color_mask( alpha: bool, state: *mut WebGLState, ) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_color_mask( - red, - green, - blue, - alpha, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_color_mask(red, green, blue, alpha, state) + }) } #[no_mangle] @@ -2524,8 +2754,8 @@ pub extern "C" fn canvas_native_webgl_commit(_: *mut WebGLState) { #[no_mangle] pub extern "C" fn canvas_native_webgl_compile_shader(shader: u32, state: *mut WebGLState) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_compile_shader(shader, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| canvas_webgl::webgl::canvas_native_webgl_compile_shader(shader, state)) } #[no_mangle] @@ -2542,17 +2772,20 @@ pub extern "C" fn canvas_native_webgl_compressed_tex_image2d( ) { assert!(!state.is_null()); let pixels = unsafe { std::slice::from_raw_parts(pixels, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_compressed_tex_image2d( - target, - level, - internalformat, - width, - height, - border, - pixels, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let pixels = pixels.to_vec(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_compressed_tex_image2d( + target, + level, + internalformat, + width, + height, + border, + &pixels, + state, + ) + }) } #[no_mangle] @@ -2565,16 +2798,18 @@ pub extern "C" fn canvas_native_webgl_compressed_tex_image2d_none( border: i32, state: *mut WebGLState, ) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_compressed_tex_image2d_none( - target, - level, - internalformat, - width, - height, - border, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_compressed_tex_image2d_none( + target, + level, + internalformat, + width, + height, + border, + state, + ) + }) } #[no_mangle] @@ -2592,18 +2827,13 @@ pub extern "C" fn canvas_native_webgl_compressed_tex_sub_image2d( ) { assert!(!state.is_null()); let pixels = unsafe { std::slice::from_raw_parts(pixels, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_compressed_tex_sub_image2d( - target, - level, - xoffset, - yoffset, - width, - height, - format, - pixels, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let pixels = pixels.to_vec(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_compressed_tex_sub_image2d( + target, level, xoffset, yoffset, width, height, format, &pixels, state, + ) + }) } #[no_mangle] @@ -2618,18 +2848,20 @@ pub extern "C" fn canvas_native_webgl_copy_tex_image2d( border: i32, state: *mut WebGLState, ) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_copy_tex_image2d( - target, - level, - internalformat, - x, - y, - width, - height, - border, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_copy_tex_image2d( + target, + level, + internalformat, + x, + y, + width, + height, + border, + state, + ) + }) } #[no_mangle] @@ -2644,42 +2876,36 @@ pub extern "C" fn canvas_native_webgl_copy_tex_sub_image2d( height: i32, state: *mut WebGLState, ) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_copy_tex_sub_image2d( - target, - level, - xoffset, - yoffset, - x, - y, - width, - height, - state.get_inner_mut(), - ) -} + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_copy_tex_sub_image2d( + target, level, xoffset, yoffset, x, y, width, height, state, + ) + }) +} #[no_mangle] pub extern "C" fn canvas_native_webgl_create_buffer(state: *mut WebGLState) -> u32 { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_create_buffer(state.get_inner_mut()) + let state = unsafe { &*state }; + state.sync(|state| canvas_webgl::webgl::canvas_native_webgl_create_buffer(state)) } #[no_mangle] pub extern "C" fn canvas_native_webgl_create_framebuffer(state: *mut WebGLState) -> u32 { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_create_framebuffer(state.get_inner_mut()) + let state = unsafe { &*state }; + state.sync(|state| canvas_webgl::webgl::canvas_native_webgl_create_framebuffer(state)) } #[no_mangle] pub extern "C" fn canvas_native_webgl_create_program(state: *mut WebGLState) -> u32 { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_create_program(state.get_inner_mut()) + let state = unsafe { &*state }; + state.sync(|state| canvas_webgl::webgl::canvas_native_webgl_create_program(state)) } #[no_mangle] pub extern "C" fn canvas_native_webgl_create_renderbuffer(state: *mut WebGLState) -> u32 { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_create_renderbuffer(state.get_inner_mut()) + let state = unsafe { &*state }; + state.sync(|state| canvas_webgl::webgl::canvas_native_webgl_create_renderbuffer(state)) } #[no_mangle] @@ -2687,26 +2913,26 @@ pub extern "C" fn canvas_native_webgl_create_shader( shader_type: u32, state: *mut WebGLState, ) -> u32 { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_create_shader(shader_type, state.get_inner_mut()) + let state = unsafe { &*state }; + state.sync(|state| canvas_webgl::webgl::canvas_native_webgl_create_shader(shader_type, state)) } #[no_mangle] pub extern "C" fn canvas_native_webgl_create_texture(state: *mut WebGLState) -> u32 { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_create_texture(state.get_inner_mut()) + let state = unsafe { &*state }; + state.sync(|state| canvas_webgl::webgl::canvas_native_webgl_create_texture(state)) } #[no_mangle] pub extern "C" fn canvas_native_webgl_cull_face(mode: u32, state: *mut WebGLState) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_cull_face(mode, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| canvas_webgl::webgl::canvas_native_webgl_cull_face(mode, state)) } #[no_mangle] pub extern "C" fn canvas_native_webgl_delete_buffer(buffer: u32, state: *mut WebGLState) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_delete_buffer(buffer, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| canvas_webgl::webgl::canvas_native_webgl_delete_buffer(buffer, state)) } #[no_mangle] @@ -2714,14 +2940,16 @@ pub extern "C" fn canvas_native_webgl_delete_framebuffer( frame_buffer: u32, state: *mut WebGLState, ) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_delete_framebuffer(frame_buffer, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_delete_framebuffer(frame_buffer, state) + }) } #[no_mangle] pub extern "C" fn canvas_native_webgl_delete_program(program: u32, state: *mut WebGLState) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_delete_program(program, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| canvas_webgl::webgl::canvas_native_webgl_delete_program(program, state)) } #[no_mangle] @@ -2729,41 +2957,42 @@ pub extern "C" fn canvas_native_webgl_delete_renderbuffer( render_buffer: u32, state: *mut WebGLState, ) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_delete_renderbuffer( - render_buffer, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_delete_renderbuffer(render_buffer, state) + }) } #[no_mangle] pub extern "C" fn canvas_native_webgl_delete_shader(shader: u32, state: *mut WebGLState) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_delete_shader(shader, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| canvas_webgl::webgl::canvas_native_webgl_delete_shader(shader, state)) } #[no_mangle] pub extern "C" fn canvas_native_webgl_delete_texture(texture: u32, state: *mut WebGLState) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_delete_texture(texture, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| canvas_webgl::webgl::canvas_native_webgl_delete_texture(texture, state)) } #[no_mangle] pub extern "C" fn canvas_native_webgl_depth_func(func: u32, state: *mut WebGLState) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_depth_func(func, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| canvas_webgl::webgl::canvas_native_webgl_depth_func(func, state)) } #[no_mangle] pub extern "C" fn canvas_native_webgl_depth_mask(flag: bool, state: *mut WebGLState) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_depth_mask(flag, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| canvas_webgl::webgl::canvas_native_webgl_depth_mask(flag, state)) } #[no_mangle] pub extern "C" fn canvas_native_webgl_depth_range(z_near: f32, z_far: f32, state: *mut WebGLState) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_depth_range(z_near, z_far, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_depth_range(z_near, z_far, state) + }) } #[no_mangle] @@ -2772,14 +3001,16 @@ pub extern "C" fn canvas_native_webgl_detach_shader( shader: u32, state: *mut WebGLState, ) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_detach_shader(program, shader, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_detach_shader(program, shader, state) + }) } #[no_mangle] pub extern "C" fn canvas_native_webgl_disable(cap: u32, state: *mut WebGLState) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_disable(cap, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| canvas_webgl::webgl::canvas_native_webgl_disable(cap, state)) } #[no_mangle] @@ -2787,11 +3018,10 @@ pub extern "C" fn canvas_native_webgl_disable_vertex_attrib_array( index: u32, state: *mut WebGLState, ) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_disable_vertex_attrib_array( - index, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_disable_vertex_attrib_array(index, state) + }) } #[no_mangle] @@ -2801,9 +3031,10 @@ pub extern "C" fn canvas_native_webgl_draw_arrays( count: i32, state: *mut WebGLState, ) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_draw_arrays(mode, first, count, state.get_inner_mut()) - // Flush Context + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_draw_arrays(mode, first, count, state) + }) } #[no_mangle] @@ -2814,21 +3045,22 @@ pub extern "C" fn canvas_native_webgl_draw_elements( offset: isize, state: *mut WebGLState, ) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_draw_elements( - mode, - count, - element_type, - offset, - state.get_inner_mut(), - ) - // Flush Context + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_draw_elements( + mode, + count, + element_type, + offset, + state, + ) + }) } #[no_mangle] pub extern "C" fn canvas_native_webgl_enable(cap: u32, state: *mut WebGLState) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_enable(cap, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| canvas_webgl::webgl::canvas_native_webgl_enable(cap, state)) } #[no_mangle] @@ -2836,23 +3068,22 @@ pub extern "C" fn canvas_native_webgl_enable_vertex_attrib_array( index: u32, state: *mut WebGLState, ) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_enable_vertex_attrib_array( - index, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_enable_vertex_attrib_array(index, state) + }) } #[no_mangle] pub extern "C" fn canvas_native_webgl_finish(state: *mut WebGLState) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_finish(state.get_inner_mut()) + let state = unsafe { &*state }; + state.sync(|state| canvas_webgl::webgl::canvas_native_webgl_finish(state)) } #[no_mangle] pub extern "C" fn canvas_native_webgl_flush(state: *mut WebGLState) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_flush(state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| canvas_webgl::webgl::canvas_native_webgl_flush(state)) } #[no_mangle] @@ -2863,14 +3094,16 @@ pub extern "C" fn canvas_native_webgl_framebuffer_renderbuffer( renderbuffer: u32, state: *mut WebGLState, ) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_framebuffer_renderbuffer( - target, - attachment, - renderbuffertarget, - renderbuffer, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_framebuffer_renderbuffer( + target, + attachment, + renderbuffertarget, + renderbuffer, + state, + ) + }) } #[no_mangle] @@ -2882,27 +3115,24 @@ pub extern "C" fn canvas_native_webgl_framebuffer_texture2d( level: i32, state: *mut WebGLState, ) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_framebuffer_texture2d( - target, - attachment, - textarget, - texture, - level, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_framebuffer_texture2d( + target, attachment, textarget, texture, level, state, + ) + }) } #[no_mangle] pub extern "C" fn canvas_native_webgl_front_face(mode: u32, state: *mut WebGLState) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_front_face(mode, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| canvas_webgl::webgl::canvas_native_webgl_front_face(mode, state)) } #[no_mangle] pub extern "C" fn canvas_native_webgl_generate_mipmap(target: u32, state: *mut WebGLState) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_generate_mipmap(target, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| canvas_webgl::webgl::canvas_native_webgl_generate_mipmap(target, state)) } #[no_mangle] @@ -2911,14 +3141,13 @@ pub extern "C" fn canvas_native_webgl_get_active_attrib( index: u32, state: *mut WebGLState, ) -> *mut WebGLActiveInfo { - let state = unsafe { &mut *state }; - let info = canvas_webgl::webgl::canvas_native_webgl_get_active_attrib( - program, - index, - state.get_inner_mut(), - ); + let state = unsafe { &*state }; + state.sync(|state| { + let info = + canvas_webgl::webgl::canvas_native_webgl_get_active_attrib(program, index, state); - Box::into_raw(Box::new(WebGLActiveInfo(info))) + Box::into_raw(Box::new(WebGLActiveInfo(info))) + }) } #[no_mangle] @@ -2927,14 +3156,13 @@ pub extern "C" fn canvas_native_webgl_get_active_uniform( index: u32, state: *mut WebGLState, ) -> *mut WebGLActiveInfo { - let state = unsafe { &mut *state }; - let info = canvas_webgl::webgl::canvas_native_webgl_get_active_uniform( - program, - index, - state.get_inner_mut(), - ); + let state = unsafe { &*state }; + state.sync(|state| { + let info = + canvas_webgl::webgl::canvas_native_webgl_get_active_uniform(program, index, state); - Box::into_raw(Box::new(WebGLActiveInfo(info))) + Box::into_raw(Box::new(WebGLActiveInfo(info))) + }) } #[no_mangle] @@ -2942,13 +3170,12 @@ pub extern "C" fn canvas_native_webgl_get_attached_shaders( program: u32, state: *mut WebGLState, ) -> *mut U32Buffer { - let state = unsafe { &mut *state }; - Box::into_raw(Box::new(U32Buffer::from( - canvas_webgl::webgl::canvas_native_webgl_get_attached_shaders( - program, - state.get_inner_mut(), - ), - ))) + let state = unsafe { &*state }; + state.sync(|state| { + Box::into_raw(Box::new(U32Buffer::from( + canvas_webgl::webgl::canvas_native_webgl_get_attached_shaders(program, state), + ))) + }) } #[no_mangle] @@ -2960,12 +3187,10 @@ pub extern "C" fn canvas_native_webgl_get_attrib_location( assert!(!state.is_null()); let name = unsafe { CStr::from_ptr(name) }; let name = name.to_string_lossy(); - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_get_attrib_location( - program, - name.as_ref(), - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.sync(|state| { + canvas_webgl::webgl::canvas_native_webgl_get_attrib_location(program, name.as_ref(), state) + }) } #[no_mangle] @@ -2974,28 +3199,28 @@ pub extern "C" fn canvas_native_webgl_get_buffer_parameter( pname: u32, state: *mut WebGLState, ) -> i32 { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_get_buffer_parameter( - target, - pname, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.sync(|state| { + canvas_webgl::webgl::canvas_native_webgl_get_buffer_parameter(target, pname, state) + }) } #[no_mangle] pub extern "C" fn canvas_native_webgl_get_context_attributes( state: *mut WebGLState, ) -> *mut ContextAttributes { - let state = unsafe { &mut *state }; - Box::into_raw(Box::new(ContextAttributes( - canvas_webgl::webgl::canvas_native_webgl_get_context_attributes(state.get_inner()), - ))) + let state = unsafe { &*state }; + state.sync(|state| { + Box::into_raw(Box::new(ContextAttributes( + canvas_webgl::webgl::canvas_native_webgl_get_context_attributes(state), + ))) + }) } #[no_mangle] pub extern "C" fn canvas_native_webgl_get_error(state: *mut WebGLState) -> u32 { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_get_error(state.get_inner_mut()) + let state = unsafe { &*state }; + state.sync(|state| canvas_webgl::webgl::canvas_native_webgl_get_error(state)) } #[no_mangle] @@ -3006,13 +3231,10 @@ pub extern "C" fn canvas_native_webgl_get_extension( assert!(!state.is_null()); let name = unsafe { CStr::from_ptr(name) }; let name = name.to_string_lossy(); - let state = unsafe { &mut *state }; - Box::into_raw(Box::new(WebGLExtension( - canvas_webgl::webgl::canvas_native_webgl_get_extension( - name.as_ref(), - state.get_inner_mut(), - ), - ))) + let state = unsafe { &*state }; + let extension = state + .sync(|state| canvas_webgl::webgl::canvas_native_webgl_get_extension(name.as_ref(), state)); + Box::into_raw(Box::new(WebGLExtension(extension, state.is_threaded()))) } #[no_mangle] @@ -3022,15 +3244,14 @@ pub extern "C" fn canvas_native_webgl_get_framebuffer_attachment_parameter( pname: u32, state: *mut WebGLState, ) -> *mut WebGLFramebufferAttachmentParameter { - let state = unsafe { &mut *state }; - Box::into_raw(Box::new(WebGLFramebufferAttachmentParameter( - canvas_webgl::webgl::canvas_native_webgl_get_framebuffer_attachment_parameter( - target, - attachment, - pname, - state.get_inner_mut(), - ), - ))) + let state = unsafe { &*state }; + state.sync(|state| { + Box::into_raw(Box::new(WebGLFramebufferAttachmentParameter( + canvas_webgl::webgl::canvas_native_webgl_get_framebuffer_attachment_parameter( + target, attachment, pname, state, + ), + ))) + }) } #[no_mangle] @@ -3066,10 +3287,12 @@ pub extern "C" fn canvas_native_webgl_get_parameter( pname: u32, state: *mut WebGLState, ) -> *mut WebGLResult { - let state = unsafe { &mut *state }; - Box::into_raw(Box::new(WebGLResult( - canvas_webgl::webgl::canvas_native_webgl_get_parameter(pname, state.get_inner_mut()), - ))) + let state = unsafe { &*state }; + state.sync(|state| { + Box::into_raw(Box::new(WebGLResult( + canvas_webgl::webgl::canvas_native_webgl_get_parameter(pname, state), + ))) + }) } #[no_mangle] @@ -3077,15 +3300,12 @@ pub extern "C" fn canvas_native_webgl_get_program_info_log( program: u32, state: *mut WebGLState, ) -> *const c_char { - let state = unsafe { &mut *state }; - CString::new( - canvas_webgl::webgl::canvas_native_webgl_get_program_info_log( - program, - state.get_inner_mut(), - ), - ) - .unwrap() - .into_raw() + let state = unsafe { &*state }; + state.sync(|state| { + CString::new(canvas_webgl::webgl::canvas_native_webgl_get_program_info_log(program, state)) + .unwrap() + .into_raw() + }) } #[no_mangle] @@ -3094,14 +3314,12 @@ pub extern "C" fn canvas_native_webgl_get_program_parameter( pname: u32, state: *mut WebGLState, ) -> *mut WebGLResult { - let state = unsafe { &mut *state }; - Box::into_raw(Box::new(WebGLResult( - canvas_webgl::webgl::canvas_native_webgl_get_program_parameter( - program, - pname, - state.get_inner_mut(), - ), - ))) + let state = unsafe { &*state }; + state.sync(|state| { + Box::into_raw(Box::new(WebGLResult( + canvas_webgl::webgl::canvas_native_webgl_get_program_parameter(program, pname, state), + ))) + }) } #[no_mangle] @@ -3110,12 +3328,10 @@ pub extern "C" fn canvas_native_webgl_get_renderbuffer_parameter( pname: u32, state: *mut WebGLState, ) -> i32 { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_get_renderbuffer_parameter( - target, - pname, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.sync(|state| { + canvas_webgl::webgl::canvas_native_webgl_get_renderbuffer_parameter(target, pname, state) + }) } #[no_mangle] @@ -3123,12 +3339,12 @@ pub extern "C" fn canvas_native_webgl_get_shader_info_log( shader: u32, state: *mut WebGLState, ) -> *const c_char { - let state = unsafe { &mut *state }; - CString::new( - canvas_webgl::webgl::canvas_native_webgl_get_shader_info_log(shader, state.get_inner_mut()), - ) - .unwrap() - .into_raw() + let state = unsafe { &*state }; + state.sync(|state| { + CString::new(canvas_webgl::webgl::canvas_native_webgl_get_shader_info_log(shader, state)) + .unwrap() + .into_raw() + }) } #[no_mangle] @@ -3137,14 +3353,12 @@ pub extern "C" fn canvas_native_webgl_get_shader_parameter( pname: u32, state: *mut WebGLState, ) -> *mut WebGLResult { - let state = unsafe { &mut *state }; - Box::into_raw(Box::new(WebGLResult( - canvas_webgl::webgl::canvas_native_webgl_get_shader_parameter( - shader, - pname, - state.get_inner_mut(), - ), - ))) + let state = unsafe { &*state }; + state.sync(|state| { + Box::into_raw(Box::new(WebGLResult( + canvas_webgl::webgl::canvas_native_webgl_get_shader_parameter(shader, pname, state), + ))) + }) } #[no_mangle] @@ -3153,14 +3367,16 @@ pub extern "C" fn canvas_native_webgl_get_shader_precision_format( precision_type: u32, state: *mut WebGLState, ) -> *mut WebGLShaderPrecisionFormat { - let state = unsafe { &mut *state }; - Box::into_raw(Box::new(WebGLShaderPrecisionFormat( - canvas_webgl::webgl::canvas_native_webgl_get_shader_precision_format( - shader_type, - precision_type, - state.get_inner_mut(), - ), - ))) + let state = unsafe { &*state }; + state.sync(|state| { + Box::into_raw(Box::new(WebGLShaderPrecisionFormat( + canvas_webgl::webgl::canvas_native_webgl_get_shader_precision_format( + shader_type, + precision_type, + state, + ), + ))) + }) } #[no_mangle] @@ -3168,34 +3384,38 @@ pub extern "C" fn canvas_native_webgl_get_shader_source( shader: u32, state: *mut WebGLState, ) -> *const c_char { - let state = unsafe { &mut *state }; - CString::new(canvas_webgl::webgl::canvas_native_webgl_get_shader_source( - shader, - state.get_inner_mut(), - )) - .unwrap() - .into_raw() + let state = unsafe { &*state }; + state.sync(|state| { + CString::new(canvas_webgl::webgl::canvas_native_webgl_get_shader_source( + shader, state, + )) + .unwrap() + .into_raw() + }) } #[no_mangle] pub extern "C" fn canvas_native_webgl_get_supported_extensions( state: *mut WebGLState, ) -> *mut StringBuffer { - let state = unsafe { &mut *state }; - Box::into_raw(Box::new(StringBuffer::from( - canvas_webgl::webgl::canvas_native_webgl_get_supported_extensions(state.get_inner_mut()), - ))) + let state = unsafe { &*state }; + state.sync(|state| { + Box::into_raw(Box::new(StringBuffer::from( + canvas_webgl::webgl::canvas_native_webgl_get_supported_extensions(state), + ))) + }) } #[no_mangle] pub extern "C" fn canvas_native_webgl_get_supported_extensions_to_string( state: *mut WebGLState, ) -> *const c_char { - let state = unsafe { &mut *state }; - let ret = - canvas_webgl::webgl::canvas_native_webgl_get_supported_extensions(state.get_inner_mut()); + let state = unsafe { &*state }; + state.sync(|state| { + let ret = canvas_webgl::webgl::canvas_native_webgl_get_supported_extensions(state); - CString::new(ret.join(",").to_string()).unwrap().into_raw() + CString::new(ret.join(",").to_string()).unwrap().into_raw() + }) } #[no_mangle] @@ -3204,8 +3424,10 @@ pub extern "C" fn canvas_native_webgl_get_tex_parameter( pname: u32, state: *mut WebGLState, ) -> i32 { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_get_tex_parameter(target, pname, state.get_inner_mut()) + let state = unsafe { &*state }; + state.sync(|state| { + canvas_webgl::webgl::canvas_native_webgl_get_tex_parameter(target, pname, state) + }) } #[no_mangle] @@ -3218,12 +3440,10 @@ pub extern "C" fn canvas_native_webgl_get_uniform_location( assert!(!name.is_null()); let name = unsafe { CStr::from_ptr(name) }; let name = name.to_string_lossy(); - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_get_uniform_location( - program, - name.as_ref(), - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.sync(|state| { + canvas_webgl::webgl::canvas_native_webgl_get_uniform_location(program, name.as_ref(), state) + }) } #[no_mangle] @@ -3232,15 +3452,12 @@ pub extern "C" fn canvas_native_webgl_get_uniform( location: i32, state: *mut WebGLState, ) -> *mut WebGLResult { - let state = unsafe { &mut *state }; - - Box::into_raw(Box::new(WebGLResult( - canvas_webgl::webgl::canvas_native_webgl_get_uniform( - program, - location, - state.get_inner_mut(), - ), - ))) + let state = unsafe { &*state }; + state.sync(|state| { + Box::into_raw(Box::new(WebGLResult( + canvas_webgl::webgl::canvas_native_webgl_get_uniform(program, location, state), + ))) + }) } #[no_mangle] @@ -3249,12 +3466,10 @@ pub extern "C" fn canvas_native_webgl_get_vertex_attrib_offset( pname: u32, state: *mut WebGLState, ) -> usize { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_get_vertex_attrib_offset( - index, - pname, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.sync(|state| { + canvas_webgl::webgl::canvas_native_webgl_get_vertex_attrib_offset(index, pname, state) + }) } #[no_mangle] @@ -3263,14 +3478,12 @@ pub extern "C" fn canvas_native_webgl_get_vertex_attrib( pname: u32, state: *mut WebGLState, ) -> *mut WebGLResult { - let state = unsafe { &mut *state }; - Box::into_raw(Box::new(WebGLResult( - canvas_webgl::webgl::canvas_native_webgl_get_vertex_attrib( - index, - pname, - state.get_inner_mut(), - ), - ))) + let state = unsafe { &*state }; + state.sync(|state| { + Box::into_raw(Box::new(WebGLResult( + canvas_webgl::webgl::canvas_native_webgl_get_vertex_attrib(index, pname, state), + ))) + }) } #[no_mangle] @@ -3278,26 +3491,30 @@ pub extern "C" fn canvas_native_webgl_get_is_context_lost(state: *mut WebGLState if state.is_null() { return false; } - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_get_is_context_lost(state.get_inner_mut()) + let state = unsafe { &*state }; + // Only Android threads a context, and loss is only tracked on Windows: skip the round trip. + if state.is_threaded() { + return false; + } + state.sync(|state| canvas_webgl::webgl::canvas_native_webgl_get_is_context_lost(state)) } #[no_mangle] pub extern "C" fn canvas_native_webgl_hint(target: u32, mode: u32, state: *mut WebGLState) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_hint(target, mode, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| canvas_webgl::webgl::canvas_native_webgl_hint(target, mode, state)) } #[no_mangle] pub extern "C" fn canvas_native_webgl_is_buffer(buffer: u32, state: *mut WebGLState) -> bool { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_is_buffer(buffer, state.get_inner_mut()) + let state = unsafe { &*state }; + state.sync(|state| canvas_webgl::webgl::canvas_native_webgl_is_buffer(buffer, state)) } #[no_mangle] pub extern "C" fn canvas_native_webgl_is_enabled(cap: u32, state: *mut WebGLState) -> bool { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_is_enabled(cap, state.get_inner_mut()) + let state = unsafe { &*state }; + state.sync(|state| canvas_webgl::webgl::canvas_native_webgl_is_enabled(cap, state)) } #[no_mangle] @@ -3305,14 +3522,14 @@ pub extern "C" fn canvas_native_webgl_is_framebuffer( framebuffer: u32, state: *mut WebGLState, ) -> bool { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_is_framebuffer(framebuffer, state.get_inner_mut()) + let state = unsafe { &*state }; + state.sync(|state| canvas_webgl::webgl::canvas_native_webgl_is_framebuffer(framebuffer, state)) } #[no_mangle] pub extern "C" fn canvas_native_webgl_is_program(program: u32, state: *mut WebGLState) -> bool { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_is_program(program, state.get_inner_mut()) + let state = unsafe { &*state }; + state.sync(|state| canvas_webgl::webgl::canvas_native_webgl_is_program(program, state)) } #[no_mangle] @@ -3320,38 +3537,41 @@ pub extern "C" fn canvas_native_webgl_is_renderbuffer( renderbuffer: u32, state: *mut WebGLState, ) -> bool { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_is_renderbuffer(renderbuffer, state.get_inner_mut()) + let state = unsafe { &*state }; + state + .sync(|state| canvas_webgl::webgl::canvas_native_webgl_is_renderbuffer(renderbuffer, state)) } #[no_mangle] pub extern "C" fn canvas_native_webgl_is_shader(shader: u32, state: *mut WebGLState) -> bool { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_is_shader(shader, state.get_inner_mut()) + let state = unsafe { &*state }; + state.sync(|state| canvas_webgl::webgl::canvas_native_webgl_is_shader(shader, state)) } #[no_mangle] pub extern "C" fn canvas_native_webgl_is_texture(texture: u32, state: *mut WebGLState) -> bool { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_is_texture(texture, state.get_inner_mut()) + let state = unsafe { &*state }; + state.sync(|state| canvas_webgl::webgl::canvas_native_webgl_is_texture(texture, state)) } #[no_mangle] pub extern "C" fn canvas_native_webgl_line_width(width: f32, state: *mut WebGLState) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_line_width(width, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| canvas_webgl::webgl::canvas_native_webgl_line_width(width, state)) } #[no_mangle] pub extern "C" fn canvas_native_webgl_link_program(program: u32, state: *mut WebGLState) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_link_program(program, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| canvas_webgl::webgl::canvas_native_webgl_link_program(program, state)) } #[no_mangle] pub extern "C" fn canvas_native_webgl_pixel_storei(pname: u32, param: i32, state: *mut WebGLState) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_pixel_storei(pname, param, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_pixel_storei(pname, param, state) + }) } #[no_mangle] @@ -3361,8 +3581,10 @@ pub extern "C" fn canvas_native_webgl_polygon_offset( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_polygon_offset(factor, units, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_polygon_offset(factor, units, state) + }) } #[no_mangle] @@ -3378,18 +3600,13 @@ pub extern "C" fn canvas_native_webgl_read_pixels_u8( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; let pixels = unsafe { std::slice::from_raw_parts_mut(pixels, size) }; - canvas_webgl::webgl::canvas_native_webgl_read_pixels_u8( - x, - y, - width, - height, - format, - pixel_type, - pixels, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.sync(|state| { + canvas_webgl::webgl::canvas_native_webgl_read_pixels_u8( + x, y, width, height, format, pixel_type, pixels, state, + ) + }) } #[no_mangle] @@ -3405,18 +3622,13 @@ pub extern "C" fn canvas_native_webgl_read_pixels_u16( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; let pixels = unsafe { std::slice::from_raw_parts_mut(pixels, size) }; - canvas_webgl::webgl::canvas_native_webgl_read_pixels_u16( - x, - y, - width, - height, - format, - pixel_type, - pixels, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.sync(|state| { + canvas_webgl::webgl::canvas_native_webgl_read_pixels_u16( + x, y, width, height, format, pixel_type, pixels, state, + ) + }) } #[no_mangle] @@ -3432,18 +3644,13 @@ pub extern "C" fn canvas_native_webgl_read_pixels_f32( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; let pixels = unsafe { std::slice::from_raw_parts_mut(pixels, size) }; - canvas_webgl::webgl::canvas_native_webgl_read_pixels_f32( - x, - y, - width, - height, - format, - pixel_type, - pixels, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.sync(|state| { + canvas_webgl::webgl::canvas_native_webgl_read_pixels_f32( + x, y, width, height, format, pixel_type, pixels, state, + ) + }) } #[no_mangle] @@ -3455,14 +3662,16 @@ pub extern "C" fn canvas_native_webgl_renderbuffer_storage( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_renderbuffer_storage( - target, - internal_format, - width, - height, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_renderbuffer_storage( + target, + internal_format, + width, + height, + state, + ) + }) } #[no_mangle] @@ -3472,8 +3681,10 @@ pub extern "C" fn canvas_native_webgl_sample_coverage( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_sample_coverage(value, invert, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_sample_coverage(value, invert, state) + }) } #[no_mangle] @@ -3485,8 +3696,10 @@ pub extern "C" fn canvas_native_webgl_scissor( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_scissor(x, y, width, height, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_scissor(x, y, width, height, state) + }) } #[no_mangle] @@ -3498,13 +3711,11 @@ pub extern "C" fn canvas_native_webgl_shader_source( assert!(!state.is_null()); assert!(!source.is_null()); let source = unsafe { CStr::from_ptr(source) }; - let source = source.to_string_lossy(); - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_shader_source( - shader, - source.as_ref(), - state.get_inner_mut(), - ) + let source = source.to_string_lossy().into_owned(); + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_shader_source(shader, &source, state) + }) } #[no_mangle] @@ -3515,13 +3726,10 @@ pub extern "C" fn canvas_native_webgl_stencil_func( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_stencil_func( - func, - reference, - mask, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_stencil_func(func, reference, mask, state) + }) } #[no_mangle] @@ -3532,21 +3740,19 @@ pub extern "C" fn canvas_native_webgl_stencil_func_separate( mask: u32, state: *mut WebGLState, ) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_stencil_func_separate( - face, - func, - reference, - mask, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_stencil_func_separate( + face, func, reference, mask, state, + ) + }) } #[no_mangle] pub extern "C" fn canvas_native_webgl_stencil_mask(mask: u32, state: *mut WebGLState) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_stencil_mask(mask, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| canvas_webgl::webgl::canvas_native_webgl_stencil_mask(mask, state)) } #[no_mangle] @@ -3556,12 +3762,10 @@ pub extern "C" fn canvas_native_webgl_stencil_mask_separate( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_stencil_mask_separate( - face, - mask, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_stencil_mask_separate(face, mask, state) + }) } #[no_mangle] @@ -3573,7 +3777,9 @@ pub extern "C" fn canvas_native_webgl_stencil_op( ) { assert!(!state.is_null()); let state = unsafe { &*state }; - canvas_webgl::webgl::canvas_native_webgl_stencil_op(fail, zfail, zpass, state.get_inner()) + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_stencil_op(fail, zfail, zpass, state) + }) } #[no_mangle] @@ -3584,14 +3790,12 @@ pub extern "C" fn canvas_native_webgl_stencil_op_separate( zpass: u32, state: *mut WebGLState, ) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_stencil_op_separate( - face, - fail, - zfail, - zpass, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_stencil_op_separate( + face, fail, zfail, zpass, state, + ) + }) } #[no_mangle] @@ -3603,15 +3807,17 @@ pub extern "C" fn canvas_native_webgl_tex_image2d_image_none( image_type: i32, state: *mut WebGLState, ) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_tex_image2d_image_none( - target, - level, - internalformat, - format, - image_type, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_tex_image2d_image_none( + target, + level, + internalformat, + format, + image_type, + state, + ) + }) } #[no_mangle] @@ -3627,7 +3833,7 @@ pub extern "C" fn canvas_native_webgl_tex_image2d_canvas2d( assert!(!canvas.is_null()); assert!(!state.is_null()); let canvas = unsafe { &mut *canvas }; - let state = unsafe { &mut *state }; + let state = unsafe { &*state }; let (width, height) = canvas.context.dimensions(); @@ -3635,20 +3841,20 @@ pub extern "C" fn canvas_native_webgl_tex_image2d_canvas2d( canvas.read_pixels_into(bytes.as_mut_slice(), (0, 0), (width as i32, height as i32)); - state.0.make_current(); - - canvas_webgl::webgl::canvas_native_webgl_tex_image2d( - target, - level, - internalformat, - width as i32, - height as i32, - 0, - format, - image_type, - bytes.as_slice(), - state.get_inner_mut(), - ); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_tex_image2d( + target, + level, + internalformat, + width as i32, + height as i32, + 0, + format, + image_type, + bytes.as_slice(), + state, + ) + }); } #[no_mangle] @@ -3663,21 +3869,23 @@ pub extern "C" fn canvas_native_webgl_tex_image2d_webgl( ) { assert!(!state.is_null()); assert!(!webgl.is_null()); - let state = unsafe { &mut *state }; - let webgl = unsafe { &mut *webgl }; - let mut pixels = canvas_webgl::webgl::canvas_native_webgl_read_webgl_pixels(&mut webgl.0, &mut state.0); - canvas_webgl::webgl::canvas_native_webgl_tex_image2d( - target, - level, - internalformat, - pixels.0, - pixels.1, - 0, - format, - image_type, - pixels.2.as_mut_slice(), - state.get_inner_mut(), - ); + let state = unsafe { &*state }; + let webgl = unsafe { &*webgl }; + let (width, height, pixels) = webgl.read_drawing_buffer(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_tex_image2d( + target, + level, + internalformat, + width, + height, + 0, + format, + image_type, + pixels.as_slice(), + state, + ) + }); } #[no_mangle] @@ -3695,20 +3903,23 @@ pub extern "C" fn canvas_native_webgl_tex_image2d( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; let buf = unsafe { std::slice::from_raw_parts(buf, size) }; - canvas_webgl::webgl::canvas_native_webgl_tex_image2d( - target, - level, - internalformat, - width, - height, - border, - format, - image_type, - buf, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let buf = buf.to_vec(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_tex_image2d( + target, + level, + internalformat, + width, + height, + border, + format, + image_type, + &buf, + state, + ) + }) } #[no_mangle] @@ -3724,18 +3935,20 @@ pub extern "C" fn canvas_native_webgl_tex_image2d_none( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_tex_image2d_none( - target, - level, - internalformat, - width, - height, - border, - format, - image_type, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_tex_image2d_none( + target, + level, + internalformat, + width, + height, + border, + format, + image_type, + state, + ) + }) } #[no_mangle] @@ -3751,16 +3964,18 @@ pub extern "C" fn canvas_native_webgl_tex_image2d_image_asset( assert!(!state.is_null()); assert!(!image_asset.is_null()); let image_asset = unsafe { &*image_asset }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_tex_image2d_asset( - target, - level, - internalformat, - format, - image_type, - &image_asset.0, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.sync(|state| { + canvas_webgl::webgl::canvas_native_webgl_tex_image2d_asset( + target, + level, + internalformat, + format, + image_type, + &image_asset.0, + state, + ) + }) } #[no_mangle] @@ -3772,7 +3987,9 @@ pub extern "C" fn canvas_native_webgl_tex_parameterf( ) { assert!(!state.is_null()); let state = unsafe { &*state }; - canvas_webgl::webgl::canvas_native_webgl_tex_parameterf(target, pname, param, state.get_inner()) + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_tex_parameterf(target, pname, param, state) + }) } #[no_mangle] @@ -3784,7 +4001,9 @@ pub extern "C" fn canvas_native_webgl_tex_parameteri( ) { assert!(!state.is_null()); let state = unsafe { &*state }; - canvas_webgl::webgl::canvas_native_webgl_tex_parameteri(target, pname, param, state.get_inner()) + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_tex_parameteri(target, pname, param, state) + }) } #[no_mangle] @@ -3802,16 +4021,11 @@ pub extern "C" fn canvas_native_webgl_tex_sub_image2d_asset( assert!(!asset.is_null()); let asset = unsafe { &*asset }; let state = unsafe { &*state }; - canvas_webgl::webgl::canvas_native_webgl_tex_sub_image2d_asset( - target, - level, - xoffset, - yoffset, - format, - image_type, - &asset.0, - state.get_inner(), - ) + state.sync(|state| { + canvas_webgl::webgl::canvas_native_webgl_tex_sub_image2d_asset( + target, level, xoffset, yoffset, format, image_type, &asset.0, state, + ) + }) } #[no_mangle] @@ -3827,7 +4041,7 @@ pub extern "C" fn canvas_native_webgl_tex_sub_image2d_canvas2d( ) { assert!(!state.is_null()); assert!(!canvas.is_null()); - let state = unsafe { &mut *state }; + let state = unsafe { &*state }; let canvas = unsafe { &mut *canvas }; let (width, height) = canvas.context.dimensions(); @@ -3836,20 +4050,20 @@ pub extern "C" fn canvas_native_webgl_tex_sub_image2d_canvas2d( canvas.read_pixels_into(bytes.as_mut_slice(), (0, 0), (width as i32, height as i32)); - state.0.make_current(); - - canvas_webgl::webgl::canvas_native_webgl_tex_sub_image2d( - target, - level, - xoffset, - yoffset, - width as i32, - height as i32, - format, - image_type, - bytes.as_slice(), - state.get_inner_mut(), - ); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_tex_sub_image2d( + target, + level, + xoffset, + yoffset, + width as i32, + height as i32, + format, + image_type, + bytes.as_slice(), + state, + ) + }); } #[no_mangle] @@ -3865,31 +4079,23 @@ pub extern "C" fn canvas_native_webgl_tex_sub_image2d_webgl( ) { assert!(!state.is_null()); assert!(!webgl.is_null()); - let state = unsafe { &mut *state }; - let webgl = unsafe { &mut *webgl }; - { - let inner = &mut state.0; - inner.remove_if_current(); - } - let source = webgl.get_inner(); - source.make_current(); - let width = source.drawing_buffer_width(); - let height = source.drawing_buffer_height(); - - let mut pixels = canvas_webgl::webgl::canvas_native_webgl_read_webgl_pixels(&mut webgl.0, &mut state.0); - - canvas_webgl::webgl::canvas_native_webgl_tex_sub_image2d( - target, - level, - xoffset, - yoffset, - width, - height, - format, - image_type, - pixels.2.as_mut_slice(), - state.get_inner_mut(), - ); + let state = unsafe { &*state }; + let webgl = unsafe { &*webgl }; + let (width, height, pixels) = webgl.read_drawing_buffer(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_tex_sub_image2d( + target, + level, + xoffset, + yoffset, + width, + height, + format, + image_type, + pixels.as_slice(), + state, + ) + }); } #[no_mangle] @@ -3908,19 +4114,13 @@ pub extern "C" fn canvas_native_webgl_tex_sub_image2d( ) { assert!(!state.is_null()); let buf = unsafe { std::slice::from_raw_parts(buf, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_tex_sub_image2d( - target, - level, - xoffset, - yoffset, - width, - height, - format, - image_type, - buf, - state.get_inner(), - ) + let state = unsafe { &*state }; + let buf = buf.to_vec(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_tex_sub_image2d( + target, level, xoffset, yoffset, width, height, format, image_type, &buf, state, + ) + }) } #[no_mangle] @@ -3937,26 +4137,19 @@ pub extern "C" fn canvas_native_webgl_tex_sub_image2d_offset( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_tex_sub_image2d_offset( - target, - level, - xoffset, - yoffset, - width, - height, - format, - image_type, - offset, - state.get_inner(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_tex_sub_image2d_offset( + target, level, xoffset, yoffset, width, height, format, image_type, offset, state, + ) + }) } #[no_mangle] pub extern "C" fn canvas_native_webgl_uniform1f(location: i32, v0: f32, state: *mut WebGLState) { assert!(!state.is_null()); let state = unsafe { &*state }; - canvas_webgl::webgl::canvas_native_webgl_uniform1f(location, v0, state.get_inner()) + state.post(move |state| canvas_webgl::webgl::canvas_native_webgl_uniform1f(location, v0, state)) } #[no_mangle] @@ -3969,14 +4162,17 @@ pub extern "C" fn canvas_native_webgl_uniform1fv( assert!(!state.is_null()); let value = unsafe { std::slice::from_raw_parts(value, size) }; let state = unsafe { &*state }; - canvas_webgl::webgl::canvas_native_webgl_uniform1fv(location, value, state.get_inner()) + let value = value.to_vec(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_uniform1fv(location, &value, state) + }) } #[no_mangle] pub extern "C" fn canvas_native_webgl_uniform1i(location: i32, v0: i32, state: *mut WebGLState) { assert!(!state.is_null()); let state = unsafe { &*state }; - canvas_webgl::webgl::canvas_native_webgl_uniform1i(location, v0, state.get_inner()) + state.post(move |state| canvas_webgl::webgl::canvas_native_webgl_uniform1i(location, v0, state)) } #[no_mangle] @@ -3989,7 +4185,10 @@ pub extern "C" fn canvas_native_webgl_uniform1iv( assert!(!state.is_null()); let value = unsafe { std::slice::from_raw_parts(value, size) }; let state = unsafe { &*state }; - canvas_webgl::webgl::canvas_native_webgl_uniform1iv(location, value, state.get_inner()) + let value = value.to_vec(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_uniform1iv(location, &value, state) + }) } #[no_mangle] @@ -4001,7 +4200,9 @@ pub extern "C" fn canvas_native_webgl_uniform2f( ) { assert!(!state.is_null()); let state = unsafe { &*state }; - canvas_webgl::webgl::canvas_native_webgl_uniform2f(location, v0, v1, state.get_inner()) + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_uniform2f(location, v0, v1, state) + }) } #[no_mangle] @@ -4014,8 +4215,10 @@ pub extern "C" fn canvas_native_webgl_uniform2fv( assert!(!state.is_null()); let value = unsafe { std::slice::from_raw_parts(value, size) }; let state = unsafe { &*state }; - - canvas_webgl::webgl::canvas_native_webgl_uniform2fv(location, value, state.get_inner()) + let value = value.to_vec(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_uniform2fv(location, &value, state) + }) } #[no_mangle] @@ -4027,7 +4230,9 @@ pub extern "C" fn canvas_native_webgl_uniform2i( ) { assert!(!state.is_null()); let state = unsafe { &*state }; - canvas_webgl::webgl::canvas_native_webgl_uniform2i(location, v0, v1, state.get_inner()) + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_uniform2i(location, v0, v1, state) + }) } #[no_mangle] @@ -4040,7 +4245,10 @@ pub extern "C" fn canvas_native_webgl_uniform2iv( assert!(!state.is_null()); let value = unsafe { std::slice::from_raw_parts(value, size) }; let state = unsafe { &*state }; - canvas_webgl::webgl::canvas_native_webgl_uniform2iv(location, value, state.get_inner()) + let value = value.to_vec(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_uniform2iv(location, &value, state) + }) } #[no_mangle] @@ -4052,8 +4260,10 @@ pub extern "C" fn canvas_native_webgl_uniform3f( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_uniform3f(location, v0, v1, v2, state.get_inner()) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_uniform3f(location, v0, v1, v2, state) + }) } #[no_mangle] @@ -4066,7 +4276,10 @@ pub extern "C" fn canvas_native_webgl_uniform3fv( assert!(!state.is_null()); let value = unsafe { std::slice::from_raw_parts(value, size) }; let state = unsafe { &*state }; - canvas_webgl::webgl::canvas_native_webgl_uniform3fv(location, value, state.get_inner()) + let value = value.to_vec(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_uniform3fv(location, &value, state) + }) } #[no_mangle] @@ -4078,8 +4291,10 @@ pub extern "C" fn canvas_native_webgl_uniform3i( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_uniform3i(location, v0, v1, v2, state.get_inner()) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_uniform3i(location, v0, v1, v2, state) + }) } #[no_mangle] @@ -4092,7 +4307,10 @@ pub extern "C" fn canvas_native_webgl_uniform3iv( assert!(!state.is_null()); let value = unsafe { std::slice::from_raw_parts(value, size) }; let state = unsafe { &*state }; - canvas_webgl::webgl::canvas_native_webgl_uniform3iv(location, value, state.get_inner()) + let value = value.to_vec(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_uniform3iv(location, &value, state) + }) } #[no_mangle] @@ -4105,8 +4323,10 @@ pub extern "C" fn canvas_native_webgl_uniform4f( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_uniform4f(location, v0, v1, v2, v3, state.get_inner()) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_uniform4f(location, v0, v1, v2, v3, state) + }) } #[no_mangle] @@ -4118,8 +4338,11 @@ pub extern "C" fn canvas_native_webgl_uniform4fv( ) { assert!(!state.is_null()); let value = unsafe { std::slice::from_raw_parts(value, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_uniform4fv(location, value, state.get_inner_mut()) + let state = unsafe { &*state }; + let value = value.to_vec(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_uniform4fv(location, &value, state) + }) } #[no_mangle] @@ -4132,15 +4355,10 @@ pub extern "C" fn canvas_native_webgl_uniform4i( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_uniform4i( - location, - v0, - v1, - v2, - v3, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_uniform4i(location, v0, v1, v2, v3, state) + }) } #[no_mangle] @@ -4152,8 +4370,11 @@ pub extern "C" fn canvas_native_webgl_uniform4iv( ) { assert!(!state.is_null()); let value = unsafe { std::slice::from_raw_parts(value, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_uniform4iv(location, value, state.get_inner_mut()) + let state = unsafe { &*state }; + let value = value.to_vec(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_uniform4iv(location, &value, state) + }) } #[no_mangle] @@ -4166,13 +4387,13 @@ pub extern "C" fn canvas_native_webgl_uniform_matrix2fv( ) { assert!(!state.is_null()); let value = unsafe { std::slice::from_raw_parts(value, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_uniform_matrix2fv( - location, - transpose, - value, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let value = value.to_vec(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_uniform_matrix2fv( + location, transpose, &value, state, + ) + }) } #[no_mangle] @@ -4185,13 +4406,13 @@ pub extern "C" fn canvas_native_webgl_uniform_matrix3fv( ) { assert!(!state.is_null()); let value = unsafe { std::slice::from_raw_parts(value, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_uniform_matrix3fv( - location, - transpose, - value, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let value = value.to_vec(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_uniform_matrix3fv( + location, transpose, &value, state, + ) + }) } #[no_mangle] @@ -4204,34 +4425,38 @@ pub extern "C" fn canvas_native_webgl_uniform_matrix4fv( ) { assert!(!state.is_null()); let value = unsafe { std::slice::from_raw_parts(value, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_uniform_matrix4fv( - location, - transpose, - value, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let value = value.to_vec(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_uniform_matrix4fv( + location, transpose, &value, state, + ) + }) } #[no_mangle] pub extern "C" fn canvas_native_webgl_use_program(program: u32, state: *mut WebGLState) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_use_program(program, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| canvas_webgl::webgl::canvas_native_webgl_use_program(program, state)) } #[no_mangle] pub extern "C" fn canvas_native_webgl_validate_program(program: u32, state: *mut WebGLState) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_validate_program(program, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_validate_program(program, state) + }) } #[no_mangle] pub extern "C" fn canvas_native_webgl_vertex_attrib1f(index: u32, v0: f32, state: *mut WebGLState) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_vertex_attrib1f(index, v0, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_vertex_attrib1f(index, v0, state) + }) } #[no_mangle] @@ -4243,8 +4468,11 @@ pub extern "C" fn canvas_native_webgl_vertex_attrib1fv( ) { assert!(!state.is_null()); let value = unsafe { std::slice::from_raw_parts(value, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_vertex_attrib1fv(index, value, state.get_inner_mut()) + let state = unsafe { &*state }; + let value = value.to_vec(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_vertex_attrib1fv(index, &value, state) + }) } #[no_mangle] @@ -4255,8 +4483,10 @@ pub extern "C" fn canvas_native_webgl_vertex_attrib2f( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_vertex_attrib2f(index, v0, v1, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_vertex_attrib2f(index, v0, v1, state) + }) } #[no_mangle] @@ -4268,8 +4498,11 @@ pub extern "C" fn canvas_native_webgl_vertex_attrib2fv( ) { assert!(!state.is_null()); let value = unsafe { std::slice::from_raw_parts(value, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_vertex_attrib2fv(index, value, state.get_inner_mut()) + let state = unsafe { &*state }; + let value = value.to_vec(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_vertex_attrib2fv(index, &value, state) + }) } #[no_mangle] @@ -4281,14 +4514,10 @@ pub extern "C" fn canvas_native_webgl_vertex_attrib3f( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_vertex_attrib3f( - index, - v0, - v1, - v2, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_vertex_attrib3f(index, v0, v1, v2, state) + }) } #[no_mangle] @@ -4300,8 +4529,11 @@ pub extern "C" fn canvas_native_webgl_vertex_attrib3fv( ) { assert!(!state.is_null()); let value = unsafe { std::slice::from_raw_parts(value, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_vertex_attrib3fv(index, value, state.get_inner_mut()) + let state = unsafe { &*state }; + let value = value.to_vec(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_vertex_attrib3fv(index, &value, state) + }) } #[no_mangle] @@ -4314,15 +4546,10 @@ pub extern "C" fn canvas_native_webgl_vertex_attrib4f( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_vertex_attrib4f( - index, - v0, - v1, - v2, - v3, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_vertex_attrib4f(index, v0, v1, v2, v3, state) + }) } #[no_mangle] @@ -4334,8 +4561,11 @@ pub extern "C" fn canvas_native_webgl_vertex_attrib4fv( ) { assert!(!state.is_null()); let value = unsafe { std::slice::from_raw_parts(value, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_vertex_attrib4fv(index, value, state.get_inner_mut()) + let state = unsafe { &*state }; + let value = value.to_vec(); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_vertex_attrib4fv(index, &value, state) + }) } #[no_mangle] @@ -4349,16 +4579,12 @@ pub extern "C" fn canvas_native_webgl_vertex_attrib_pointer( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_vertex_attrib_pointer( - index, - size, - d_type, - normalized, - stride, - offset, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_vertex_attrib_pointer( + index, size, d_type, normalized, stride, offset, state, + ) + }) } #[no_mangle] @@ -4370,6 +4596,8 @@ pub extern "C" fn canvas_native_webgl_viewport( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl::canvas_native_webgl_viewport(x, y, width, height, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_viewport(x, y, width, height, state) + }) } diff --git a/crates/canvas-c/src/webgl/gl2.rs b/crates/canvas-c/src/webgl/gl2.rs index f0b586d2b..178cf5a8a 100644 --- a/crates/canvas-c/src/webgl/gl2.rs +++ b/crates/canvas-c/src/webgl/gl2.rs @@ -38,8 +38,10 @@ pub extern "C" fn canvas_native_webgl2_indexed_parameter_get_is_buffer( #[no_mangle] pub extern "C" fn canvas_native_webgl2_begin_query(target: u32, id: u32, state: *mut WebGLState) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_begin_query(target, id, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_begin_query(target, id, state) + }) } #[no_mangle] @@ -48,11 +50,10 @@ pub extern "C" fn canvas_native_webgl2_begin_transform_feedback( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_begin_transform_feedback( - primitive_mode, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_begin_transform_feedback(primitive_mode, state) + }) } #[no_mangle] @@ -63,13 +64,10 @@ pub extern "C" fn canvas_native_webgl2_bind_buffer_base( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_bind_buffer_base( - target, - index, - buffer, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_bind_buffer_base(target, index, buffer, state) + }) } #[no_mangle] @@ -82,15 +80,12 @@ pub extern "C" fn canvas_native_webgl2_bind_buffer_range( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_bind_buffer_range( - target, - index, - buffer, - offset, - size, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_bind_buffer_range( + target, index, buffer, offset, size, state, + ) + }) } #[no_mangle] @@ -100,8 +95,10 @@ pub extern "C" fn canvas_native_webgl2_bind_sampler( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_bind_sampler(unit, sampler, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_bind_sampler(unit, sampler, state) + }) } #[no_mangle] @@ -111,12 +108,10 @@ pub extern "C" fn canvas_native_webgl2_bind_transform_feedback( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_bind_sampler( - target, - transform_feedback, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_bind_sampler(target, transform_feedback, state) + }) } #[no_mangle] @@ -125,11 +120,10 @@ pub extern "C" fn canvas_native_webgl2_bind_vertex_array( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_bind_vertex_array( - vertex_array, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_bind_vertex_array(vertex_array, state) + }) } #[no_mangle] @@ -147,20 +141,12 @@ pub extern "C" fn canvas_native_webgl2_blit_framebuffer( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_blit_framebuffer( - src_x0, - src_y0, - src_x1, - src_y1, - dst_x0, - dst_y0, - dst_x1, - dst_y1, - mask, - filter, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_blit_framebuffer( + src_x0, src_y0, src_x1, src_y1, dst_x0, dst_y0, dst_x1, dst_y1, mask, filter, state, + ) + }) } #[no_mangle] @@ -172,14 +158,12 @@ pub extern "C" fn canvas_native_webgl2_clear_bufferfi( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_clear_bufferfi( - buffer, - drawbuffer, - depth, - stencil, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_clear_bufferfi( + buffer, drawbuffer, depth, stencil, state, + ) + }) } #[no_mangle] @@ -192,13 +176,13 @@ pub extern "C" fn canvas_native_webgl2_clear_bufferfv( ) { assert!(!state.is_null()); let values = unsafe { std::slice::from_raw_parts(values, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_clear_bufferfv( - buffer, - drawbuffer, - values, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let values = values.to_vec(); + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_clear_bufferfv( + buffer, drawbuffer, &values, state, + ) + }) } #[no_mangle] @@ -211,13 +195,13 @@ pub extern "C" fn canvas_native_webgl2_clear_bufferiv( ) { assert!(!state.is_null()); let values = unsafe { std::slice::from_raw_parts(values, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_clear_bufferiv( - buffer, - drawbuffer, - values, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let values = values.to_vec(); + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_clear_bufferiv( + buffer, drawbuffer, &values, state, + ) + }) } #[no_mangle] @@ -230,13 +214,13 @@ pub extern "C" fn canvas_native_webgl2_clear_bufferuiv( ) { assert!(!state.is_null()); let values = unsafe { std::slice::from_raw_parts(values, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_clear_bufferuiv( - buffer, - drawbuffer, - values, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let values = values.to_vec(); + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_clear_bufferuiv( + buffer, drawbuffer, &values, state, + ) + }) } #[no_mangle] @@ -248,14 +232,16 @@ pub extern "C" fn canvas_native_webgl2_client_wait_sync( ) -> u32 { assert!(!state.is_null()); assert!(!sync.is_null()); - let state = unsafe { &mut *state }; - let sync = unsafe { &*sync }; - canvas_webgl::webgl2::canvas_native_webgl2_client_wait_sync( - &sync.0, - flags, - timeout as c_ulong, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.sync(|state| { + let sync = unsafe { &*sync }; + canvas_webgl::webgl2::canvas_native_webgl2_client_wait_sync( + &sync.0, + flags, + timeout as c_ulong, + state, + ) + }) } #[no_mangle] @@ -272,19 +258,21 @@ pub extern "C" fn canvas_native_webgl2_compressed_tex_image3d_none( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_compressed_tex_image3d_none( - target, - level, - internalformat, - width, - height, - depth, - border, - image_size, - offset, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_compressed_tex_image3d_none( + target, + level, + internalformat, + width, + height, + depth, + border, + image_size, + offset, + state, + ) + }) } #[no_mangle] @@ -304,20 +292,23 @@ pub extern "C" fn canvas_native_webgl2_compressed_tex_image3d( ) { assert!(!state.is_null()); let src = unsafe { std::slice::from_raw_parts(src, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_compressed_tex_image3d( - target, - level, - internalformat, - width, - height, - depth, - border, - src, - src_offset, - src_length_override, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let src = src.to_vec(); + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_compressed_tex_image3d( + target, + level, + internalformat, + width, + height, + depth, + border, + &src, + src_offset, + src_length_override, + state, + ) + }) } @@ -337,21 +328,13 @@ pub extern "C" fn canvas_native_webgl2_compressed_tex_sub_image3d_none( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_compressed_tex_sub_image3d_none( - target, - level, - xoffset, - yoffset, - zoffset, - width, - height, - depth, - format, - image_size, - offset, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_compressed_tex_sub_image3d_none( + target, level, xoffset, yoffset, zoffset, width, height, depth, format, image_size, + offset, state, + ) + }) } #[no_mangle] @@ -373,22 +356,25 @@ pub extern "C" fn canvas_native_webgl2_compressed_tex_sub_image3d( ) { assert!(!state.is_null()); let src = unsafe { std::slice::from_raw_parts(src, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_compressed_tex_sub_image3d( - target, - level, - xoffset, - yoffset, - zoffset, - width, - height, - depth, - format, - src, - src_offset, - src_length_override, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let src = src.to_vec(); + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_compressed_tex_sub_image3d( + target, + level, + xoffset, + yoffset, + zoffset, + width, + height, + depth, + format, + &src, + src_offset, + src_length_override, + state, + ) + }) } #[no_mangle] @@ -401,15 +387,17 @@ pub extern "C" fn canvas_native_webgl2_copy_buffer_sub_data( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_copy_buffer_sub_data( - read_target, - write_target, - read_offset, - write_offset, - size, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_copy_buffer_sub_data( + read_target, + write_target, + read_offset, + write_offset, + size, + state, + ) + }) } #[no_mangle] @@ -426,54 +414,49 @@ pub extern "C" fn canvas_native_webgl2_copy_tex_sub_image3d( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_copy_tex_sub_image3d( - target, - level, - xoffset, - yoffset, - zoffset, - x, - y, - width, - height, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_copy_tex_sub_image3d( + target, level, xoffset, yoffset, zoffset, x, y, width, height, state, + ) + }) } #[no_mangle] pub extern "C" fn canvas_native_webgl2_create_query(state: *mut WebGLState) -> u32 { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_create_query(state.get_inner_mut()) + let state = unsafe { &*state }; + state.sync(|state| canvas_webgl::webgl2::canvas_native_webgl2_create_query(state)) } #[no_mangle] pub extern "C" fn canvas_native_webgl2_create_sampler(state: *mut WebGLState) -> u32 { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_create_sampler(state.get_inner_mut()) + let state = unsafe { &*state }; + state.sync(|state| canvas_webgl::webgl2::canvas_native_webgl2_create_sampler(state)) } #[no_mangle] pub extern "C" fn canvas_native_webgl2_create_transform_feedback(state: *mut WebGLState) -> u32 { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_create_transform_feedback(state.get_inner_mut()) + let state = unsafe { &*state }; + state.sync(|state| canvas_webgl::webgl2::canvas_native_webgl2_create_transform_feedback(state)) } #[no_mangle] pub extern "C" fn canvas_native_webgl2_create_vertex_array(state: *mut WebGLState) -> u32 { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_create_vertex_array(state.get_inner_mut()) + let state = unsafe { &*state }; + state.sync(|state| canvas_webgl::webgl2::canvas_native_webgl2_create_vertex_array(state)) } #[no_mangle] pub extern "C" fn canvas_native_webgl2_delete_query_with_query(id: u32, state: *mut WebGLState) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_delete_query_with_query(id, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_delete_query_with_query(id, state) + }) } #[no_mangle] @@ -482,11 +465,10 @@ pub extern "C" fn canvas_native_webgl2_delete_sampler_with_sampler( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_delete_sampler_with_sampler( - sampler, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_delete_sampler_with_sampler(sampler, state) + }) } #[no_mangle] @@ -505,9 +487,11 @@ pub extern "C" fn canvas_native_webgl2_delete_sync_with_sync( ) { assert!(!state.is_null()); assert!(!sync.is_null()); - let state = unsafe { &mut *state }; - let sync = unsafe { &*sync }; - canvas_webgl::webgl2::canvas_native_webgl2_delete_sync_with_sync(&sync.0, state.get_inner_mut()) + let state = unsafe { &*state }; + state.sync(|state| { + let sync = unsafe { &*sync }; + canvas_webgl::webgl2::canvas_native_webgl2_delete_sync_with_sync(&sync.0, state) + }) } #[no_mangle] @@ -516,11 +500,13 @@ pub extern "C" fn canvas_native_webgl2_delete_transform_feedback( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_delete_transform_feedback( - transform_feedback, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_delete_transform_feedback( + transform_feedback, + state, + ) + }) } #[no_mangle] @@ -529,11 +515,13 @@ pub extern "C" fn canvas_native_webgl2_delete_vertex_array_with_vertex_array( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_delete_vertex_array_with_vertex_array( - vertex_array, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_delete_vertex_array_with_vertex_array( + vertex_array, + state, + ) + }) } #[no_mangle] @@ -545,14 +533,16 @@ pub extern "C" fn canvas_native_webgl2_draw_arrays_instanced( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_draw_arrays_instanced( - mode, - first, - count, - instance_count, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_draw_arrays_instanced( + mode, + first, + count, + instance_count, + state, + ) + }) } #[no_mangle] @@ -563,8 +553,10 @@ pub extern "C" fn canvas_native_webgl2_draw_buffers( ) { assert!(!state.is_null()); let buffers = unsafe { std::slice::from_raw_parts(buffers, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_draw_buffers(buffers, state.get_inner_mut()) + let state = unsafe { &*state }; + let buffers = buffers.to_vec(); + state + .post(move |state| canvas_webgl::webgl2::canvas_native_webgl2_draw_buffers(&buffers, state)) } #[no_mangle] @@ -577,15 +569,17 @@ pub extern "C" fn canvas_native_webgl2_draw_elements_instanced( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_draw_elements_instanced( - mode, - count, - type_, - offset, - instance_count, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_draw_elements_instanced( + mode, + count, + type_, + offset, + instance_count, + state, + ) + }) } #[no_mangle] @@ -599,30 +593,27 @@ pub extern "C" fn canvas_native_webgl2_draw_range_elements( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_draw_range_elements( - mode, - start, - end, - count, - type_, - offset, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_draw_range_elements( + mode, start, end, count, type_, offset, state, + ) + }) } #[no_mangle] pub extern "C" fn canvas_native_webgl2_end_query(target: u32, state: *mut WebGLState) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_end_query(target, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| canvas_webgl::webgl2::canvas_native_webgl2_end_query(target, state)) } #[no_mangle] pub extern "C" fn canvas_native_webgl2_end_transform_feedback(state: *mut WebGLState) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_end_transform_feedback(state.get_inner_mut()) + let state = unsafe { &*state }; + state + .post(move |state| canvas_webgl::webgl2::canvas_native_webgl2_end_transform_feedback(state)) } #[no_mangle] @@ -632,14 +623,12 @@ pub extern "C" fn canvas_native_webgl2_fence_sync( state: *mut WebGLState, ) -> *mut WebGLSync { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - Box::into_raw(Box::new(WebGLSync( - canvas_webgl::webgl2::canvas_native_webgl2_fence_sync( - condition, - flags, - state.get_inner_mut(), - ), - ))) + let state = unsafe { &*state }; + state.sync(|state| { + Box::into_raw(Box::new(WebGLSync( + canvas_webgl::webgl2::canvas_native_webgl2_fence_sync(condition, flags, state), + ))) + }) } #[no_mangle] @@ -652,15 +641,12 @@ pub extern "C" fn canvas_native_webgl2_framebuffer_texture_layer( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_framebuffer_texture_layer( - target, - attachment, - texture, - level, - layer, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_framebuffer_texture_layer( + target, attachment, texture, level, layer, state, + ) + }) } #[no_mangle] @@ -670,16 +656,18 @@ pub extern "C" fn canvas_native_webgl2_get_active_uniform_block_name( state: *mut WebGLState, ) -> *const c_char { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - CString::new( - canvas_webgl::webgl2::canvas_native_webgl2_get_active_uniform_block_name( - program, - uniform_block_index, - state.get_inner_mut(), - ), - ) + let state = unsafe { &*state }; + state.sync(|state| { + CString::new( + canvas_webgl::webgl2::canvas_native_webgl2_get_active_uniform_block_name( + program, + uniform_block_index, + state, + ), + ) .unwrap() .into_raw() + }) } #[no_mangle] @@ -690,15 +678,17 @@ pub extern "C" fn canvas_native_webgl2_get_active_uniform_block_parameter( state: *mut WebGLState, ) -> *mut WebGLResult { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - Box::into_raw(Box::new(WebGLResult( - canvas_webgl::webgl2::canvas_native_webgl2_get_active_uniform_block_parameter( - program, - uniform_block_index, - pname, - state.get_inner_mut(), - ), - ))) + let state = unsafe { &*state }; + state.sync(|state| { + Box::into_raw(Box::new(WebGLResult( + canvas_webgl::webgl2::canvas_native_webgl2_get_active_uniform_block_parameter( + program, + uniform_block_index, + pname, + state, + ), + ))) + }) } #[no_mangle] @@ -711,15 +701,17 @@ pub extern "C" fn canvas_native_webgl2_get_active_uniforms( ) -> *mut WebGLResult { assert!(!state.is_null()); let uniform_indices = unsafe { std::slice::from_raw_parts(uniform_indices, size) }; - let state = unsafe { &mut *state }; - Box::into_raw(Box::new(WebGLResult( - canvas_webgl::webgl2::canvas_native_webgl2_get_active_uniforms( - program, - uniform_indices, - pname, - state.get_inner_mut(), - ), - ))) + let state = unsafe { &*state }; + state.sync(|state| { + Box::into_raw(Box::new(WebGLResult( + canvas_webgl::webgl2::canvas_native_webgl2_get_active_uniforms( + program, + uniform_indices, + pname, + state, + ), + ))) + }) } #[no_mangle] @@ -733,16 +725,18 @@ pub extern "C" fn canvas_native_webgl2_get_buffer_sub_data( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; let dst_data = unsafe { std::slice::from_raw_parts_mut(dst_data, size) }; - canvas_webgl::webgl2::canvas_native_webgl2_get_buffer_sub_data( - target, - src_byte_offset, - dst_data, - dst_offset, - length, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.sync(|state| { + canvas_webgl::webgl2::canvas_native_webgl2_get_buffer_sub_data( + target, + src_byte_offset, + dst_data, + dst_offset, + length, + state, + ) + }) } #[no_mangle] @@ -754,12 +748,14 @@ pub extern "C" fn canvas_native_webgl2_get_frag_data_location( assert!(!state.is_null()); let name = unsafe { CStr::from_ptr(name) }; let name = name.to_string_lossy(); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_get_frag_data_location( - program, - name.as_ref(), - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.sync(|state| { + canvas_webgl::webgl2::canvas_native_webgl2_get_frag_data_location( + program, + name.as_ref(), + state, + ) + }) } #[no_mangle] @@ -769,14 +765,12 @@ pub extern "C" fn canvas_native_webgl2_get_indexed_parameter( state: *mut WebGLState, ) -> *mut WebGLIndexedParameter { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - Box::into_raw(Box::new(WebGLIndexedParameter( - canvas_webgl::webgl2::canvas_native_webgl2_get_indexed_parameter( - target, - index, - state.get_inner_mut(), - ), - ))) + let state = unsafe { &*state }; + state.sync(|state| { + Box::into_raw(Box::new(WebGLIndexedParameter( + canvas_webgl::webgl2::canvas_native_webgl2_get_indexed_parameter(target, index, state), + ))) + }) } #[no_mangle] @@ -787,15 +781,17 @@ pub extern "C" fn canvas_native_webgl2_get_internalformat_parameter( state: *mut WebGLState, ) -> *mut WebGLResult { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - Box::into_raw(Box::new(WebGLResult( - canvas_webgl::webgl2::canvas_native_webgl2_get_internalformat_parameter( - target, - internalformat, - pname, - state.get_inner_mut(), - ), - ))) + let state = unsafe { &*state }; + state.sync(|state| { + Box::into_raw(Box::new(WebGLResult( + canvas_webgl::webgl2::canvas_native_webgl2_get_internalformat_parameter( + target, + internalformat, + pname, + state, + ), + ))) + }) } #[no_mangle] @@ -804,10 +800,12 @@ pub extern "C" fn canvas_native_webgl2_get_parameter( state: *mut WebGLState, ) -> *mut WebGLResult { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - Box::into_raw(Box::new(WebGLResult( - canvas_webgl::webgl2::canvas_native_webgl2_get_parameter(pname, state.get_inner_mut()), - ))) + let state = unsafe { &*state }; + state.sync(|state| { + Box::into_raw(Box::new(WebGLResult( + canvas_webgl::webgl2::canvas_native_webgl2_get_parameter(pname, state), + ))) + }) } #[no_mangle] @@ -817,14 +815,12 @@ pub extern "C" fn canvas_native_webgl2_get_query_parameter( state: *mut WebGLState, ) -> *mut WebGLResult { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - Box::into_raw(Box::new(WebGLResult( - canvas_webgl::webgl2::canvas_native_webgl2_get_query_parameter( - query, - pname, - state.get_inner_mut(), - ), - ))) + let state = unsafe { &*state }; + state.sync(|state| { + Box::into_raw(Box::new(WebGLResult( + canvas_webgl::webgl2::canvas_native_webgl2_get_query_parameter(query, pname, state), + ))) + }) } #[no_mangle] @@ -834,10 +830,12 @@ pub extern "C" fn canvas_native_webgl2_get_query( state: *mut WebGLState, ) -> *mut WebGLResult { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - Box::into_raw(Box::new(WebGLResult( - canvas_webgl::webgl2::canvas_native_webgl2_get_query(target, pname, state.get_inner_mut()), - ))) + let state = unsafe { &*state }; + state.sync(|state| { + Box::into_raw(Box::new(WebGLResult( + canvas_webgl::webgl2::canvas_native_webgl2_get_query(target, pname, state), + ))) + }) } #[no_mangle] @@ -847,14 +845,12 @@ pub extern "C" fn canvas_native_webgl2_get_sampler_parameter( state: *mut WebGLState, ) -> *mut WebGLResult { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - Box::into_raw(Box::new(WebGLResult( - canvas_webgl::webgl2::canvas_native_webgl2_get_sampler_parameter( - sampler, - pname, - state.get_inner_mut(), - ), - ))) + let state = unsafe { &*state }; + state.sync(|state| { + Box::into_raw(Box::new(WebGLResult( + canvas_webgl::webgl2::canvas_native_webgl2_get_sampler_parameter(sampler, pname, state), + ))) + }) } #[no_mangle] @@ -866,14 +862,12 @@ pub extern "C" fn canvas_native_webgl2_get_sync_parameter( assert!(!sync.is_null()); assert!(!state.is_null()); let sync = unsafe { &*sync }; - let state = unsafe { &mut *state }; - Box::into_raw(Box::new(WebGLResult( - canvas_webgl::webgl2::canvas_native_webgl2_get_sync_parameter( - &sync.0, - pname, - state.get_inner_mut(), - ), - ))) + let state = unsafe { &*state }; + state.sync(|state| { + Box::into_raw(Box::new(WebGLResult( + canvas_webgl::webgl2::canvas_native_webgl2_get_sync_parameter(&sync.0, pname, state), + ))) + }) } #[no_mangle] @@ -883,14 +877,14 @@ pub extern "C" fn canvas_native_webgl2_get_transform_feedback_varying( state: *mut WebGLState, ) -> *mut WebGLActiveInfo { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - Box::into_raw(Box::new(WebGLActiveInfo( - canvas_webgl::webgl2::canvas_native_webgl2_get_transform_feedback_varying( - program, - index, - state.get_inner_mut(), - ), - ))) + let state = unsafe { &*state }; + state.sync(|state| { + Box::into_raw(Box::new(WebGLActiveInfo( + canvas_webgl::webgl2::canvas_native_webgl2_get_transform_feedback_varying( + program, index, state, + ), + ))) + }) } #[no_mangle] @@ -902,12 +896,14 @@ pub extern "C" fn canvas_native_webgl2_get_uniform_block_index( assert!(!state.is_null()); let uniform_block_name = unsafe { CStr::from_ptr(uniform_block_name) }; let uniform_block_name = uniform_block_name.to_string_lossy(); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_get_uniform_block_index( - program, - uniform_block_name.as_ref(), - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.sync(|state| { + canvas_webgl::webgl2::canvas_native_webgl2_get_uniform_block_index( + program, + uniform_block_name.as_ref(), + state, + ) + }) } #[no_mangle] @@ -918,15 +914,17 @@ pub extern "C" fn canvas_native_webgl2_get_uniform_indices( state: *mut WebGLState, ) -> *mut U32Buffer { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - Box::into_raw(Box::new(U32Buffer::from( - canvas_webgl::webgl2::canvas_native_webgl2_get_uniform_indices_raw( - program, - uniform_names, - size, - state.get_inner_mut(), - ), - ))) + let state = unsafe { &*state }; + state.sync(|state| { + Box::into_raw(Box::new(U32Buffer::from( + canvas_webgl::webgl2::canvas_native_webgl2_get_uniform_indices_raw( + program, + uniform_names, + size, + state, + ), + ))) + }) } #[no_mangle] @@ -938,12 +936,15 @@ pub extern "C" fn canvas_native_webgl2_invalidate_framebuffer( ) { assert!(!state.is_null()); let attachments = unsafe { std::slice::from_raw_parts(attachments, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_invalidate_framebuffer( - target, - attachments, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let attachments = attachments.to_vec(); + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_invalidate_framebuffer( + target, + &attachments, + state, + ) + }) } #[no_mangle] @@ -959,30 +960,33 @@ pub extern "C" fn canvas_native_webgl2_invalidate_sub_framebuffer( ) { assert!(!state.is_null()); let attachments = unsafe { std::slice::from_raw_parts(attachments, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_invalidate_sub_framebuffer( - target, - attachments, - x, - y, - width, - height, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let attachments = attachments.to_vec(); + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_invalidate_sub_framebuffer( + target, + &attachments, + x, + y, + width, + height, + state, + ) + }) } #[no_mangle] pub extern "C" fn canvas_native_webgl2_is_query(query: u32, state: *mut WebGLState) -> bool { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_is_query(query, state.get_inner_mut()) + let state = unsafe { &*state }; + state.sync(|state| canvas_webgl::webgl2::canvas_native_webgl2_is_query(query, state)) } #[no_mangle] pub extern "C" fn canvas_native_webgl2_is_sampler(sampler: u32, state: *mut WebGLState) -> bool { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_is_sampler(sampler, state.get_inner_mut()) + let state = unsafe { &*state }; + state.sync(|state| canvas_webgl::webgl2::canvas_native_webgl2_is_sampler(sampler, state)) } #[no_mangle] @@ -991,9 +995,11 @@ pub extern "C" fn canvas_native_webgl2_is_sync( state: *mut WebGLState, ) -> bool { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - let sync = unsafe { &*sync }; - canvas_webgl::webgl2::canvas_native_webgl2_is_sync(&sync.0, state.get_inner_mut()) + let state = unsafe { &*state }; + state.sync(|state| { + let sync = unsafe { &*sync }; + canvas_webgl::webgl2::canvas_native_webgl2_is_sync(&sync.0, state) + }) } #[no_mangle] @@ -1002,11 +1008,10 @@ pub extern "C" fn canvas_native_webgl2_is_transform_feedback( state: *mut WebGLState, ) -> bool { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_is_transform_feedback( - transform_feedback, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.sync(|state| { + canvas_webgl::webgl2::canvas_native_webgl2_is_transform_feedback(transform_feedback, state) + }) } #[no_mangle] @@ -1015,22 +1020,26 @@ pub extern "C" fn canvas_native_webgl2_is_vertex_array( state: *mut WebGLState, ) -> bool { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_is_vertex_array(vertex_array, state.get_inner_mut()) + let state = unsafe { &*state }; + state.sync(|state| { + canvas_webgl::webgl2::canvas_native_webgl2_is_vertex_array(vertex_array, state) + }) } #[no_mangle] pub extern "C" fn canvas_native_webgl2_pause_transform_feedback(state: *mut WebGLState) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_pause_transform_feedback(state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_pause_transform_feedback(state) + }) } #[no_mangle] pub extern "C" fn canvas_native_webgl2_read_buffer(src: u32, state: *mut WebGLState) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_read_buffer(src, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| canvas_webgl::webgl2::canvas_native_webgl2_read_buffer(src, state)) } #[no_mangle] @@ -1043,22 +1052,26 @@ pub extern "C" fn canvas_native_webgl2_renderbuffer_storage_multisample( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_renderbuffer_storage_multisample( - target, - samples, - internal_format, - width, - height, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_renderbuffer_storage_multisample( + target, + samples, + internal_format, + width, + height, + state, + ) + }) } #[no_mangle] pub extern "C" fn canvas_native_webgl2_resume_transform_feedback(state: *mut WebGLState) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_resume_transform_feedback(state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_resume_transform_feedback(state) + }) } #[no_mangle] @@ -1069,13 +1082,10 @@ pub extern "C" fn canvas_native_webgl2_sampler_parameterf( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_sampler_parameterf( - sampler, - pname, - param, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_sampler_parameterf(sampler, pname, param, state) + }) } #[no_mangle] @@ -1086,13 +1096,10 @@ pub extern "C" fn canvas_native_webgl2_sampler_parameteri( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_sampler_parameteri( - sampler, - pname, - param, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_sampler_parameteri(sampler, pname, param, state) + }) } #[no_mangle] @@ -1110,20 +1117,22 @@ pub extern "C" fn canvas_native_webgl2_tex_image3d_none( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_tex_image3d_none( - target, - level, - internalformat, - width, - height, - depth, - border, - format, - type_, - offset, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_tex_image3d_none( + target, + level, + internalformat, + width, + height, + depth, + border, + format, + type_, + offset, + state, + ) + }) } #[no_mangle] @@ -1141,20 +1150,22 @@ pub extern "C" fn canvas_native_webgl2_tex_image3d_asset( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_tex_image3d_asset( - target, - level, - internalformat, - width, - height, - depth, - border, - format, - type_, - &asset.0, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.sync(|state| { + canvas_webgl::webgl2::canvas_native_webgl2_tex_image3d_asset( + target, + level, + internalformat, + width, + height, + depth, + border, + format, + type_, + &asset.0, + state, + ) + }) } #[no_mangle] @@ -1172,41 +1183,38 @@ pub extern "C" fn canvas_native_webgl2_tex_image3d_canvas2d( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; + let state = unsafe { &*state }; let canvas = unsafe { &mut *canvas }; - // let (width, height) = (canvas.context.width(), canvas.context.height()); // let snapshot = canvas.context.as_data(); - let (width, height) = canvas.context.dimensions(); let mut bytes = vec![0u8; (width * height * 4.) as usize]; canvas.read_pixels_into(bytes.as_mut_slice(), (0, 0), (width as i32, height as i32)); - // todo handle pre-multipied // let premultiply = state.get_inner().get_premultiplied_alpha(); // let buf = source_ctx.read_pixels_with_alpha_premultiply(&snapshot, format as i32, premultiply); - state.0.make_current(); - - canvas_webgl::webgl2::canvas_native_webgl2_tex_image3d( - target, - level, - internalformat, - width as i32, - height as i32, - depth, - border, - format, - type_, - bytes.as_slice(), - state.get_inner_mut(), - ) + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_tex_image3d( + target, + level, + internalformat, + width as i32, + height as i32, + depth, + border, + format, + type_, + bytes.as_slice(), + state, + ) + }); } @@ -1226,33 +1234,31 @@ pub extern "C" fn canvas_native_webgl2_tex_image3d_webgl( ) { assert!(!state.is_null()); assert!(!webgl.is_null()); - let state = unsafe { &mut *state }; - let webgl = unsafe { &mut *webgl }; + let state = unsafe { &*state }; + let webgl = unsafe { &*webgl }; - - - let (width, height, bytes) = canvas_webgl::webgl::canvas_native_webgl_read_webgl_pixels(&mut webgl.0, &mut state.0); + let (width, height, bytes) = webgl.read_drawing_buffer(); // todo handle pre-multipied // let premultiply = state.get_inner().get_premultiplied_alpha(); // let buf = source_ctx.read_pixels_with_alpha_premultiply(&snapshot, format as i32, premultiply); - state.0.make_current(); - - canvas_webgl::webgl2::canvas_native_webgl2_tex_image3d( - target, - level, - internalformat, - width as i32, - height as i32, - depth, - border, - format, - type_, - bytes.as_slice(), - state.get_inner_mut(), - ) + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_tex_image3d( + target, + level, + internalformat, + width as i32, + height as i32, + depth, + border, + format, + type_, + bytes.as_slice(), + state, + ) + }); } #[no_mangle] @@ -1272,20 +1278,23 @@ pub extern "C" fn canvas_native_webgl2_tex_image3d( ) { assert!(!state.is_null()); let buf = unsafe { std::slice::from_raw_parts(buf, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_tex_image3d( - target, - level, - internalformat, - width, - height, - depth, - border, - format, - type_, - buf, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let buf = buf.to_vec(); + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_tex_image3d( + target, + level, + internalformat, + width, + height, + depth, + border, + format, + type_, + &buf, + state, + ) + }) } #[no_mangle] @@ -1306,21 +1315,24 @@ pub extern "C" fn canvas_native_webgl2_tex_image3d_offset( ) { assert!(!state.is_null()); let buf = unsafe { std::slice::from_raw_parts(buf, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_tex_image3d_offset( - target, - level, - internalformat, - width, - height, - depth, - border, - format, - type_, - buf, - offset, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let buf = buf.to_vec(); + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_tex_image3d_offset( + target, + level, + internalformat, + width, + height, + depth, + border, + format, + type_, + &buf, + offset, + state, + ) + }) } #[no_mangle] @@ -1333,15 +1345,17 @@ pub extern "C" fn canvas_native_webgl2_tex_storage2d( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_tex_storage2d( - target, - levels, - internalformat, - width, - height, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_tex_storage2d( + target, + levels, + internalformat, + width, + height, + state, + ) + }) } #[no_mangle] @@ -1355,16 +1369,18 @@ pub extern "C" fn canvas_native_webgl2_tex_storage3d( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_tex_storage3d( - target, - levels, - internalformat, - width, - height, - depth, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_tex_storage3d( + target, + levels, + internalformat, + width, + height, + depth, + state, + ) + }) } #[no_mangle] @@ -1383,21 +1399,13 @@ pub extern "C" fn canvas_native_webgl2_tex_sub_image3d_none( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_tex_sub_image3d_none( - target, - level, - xoffset, - yoffset, - zoffset, - width, - height, - depth, - format, - type_, - offset, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_tex_sub_image3d_none( + target, level, xoffset, yoffset, zoffset, width, height, depth, format, type_, offset, + state, + ) + }) } #[no_mangle] @@ -1418,21 +1426,14 @@ pub extern "C" fn canvas_native_webgl2_tex_sub_image3d( ) { assert!(!state.is_null()); let buf = unsafe { std::slice::from_raw_parts(buf, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_tex_sub_image3d( - target, - level, - xoffset, - yoffset, - zoffset, - width, - height, - depth, - format, - type_, - buf, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let buf = buf.to_vec(); + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_tex_sub_image3d( + target, level, xoffset, yoffset, zoffset, width, height, depth, format, type_, &buf, + state, + ) + }) } #[no_mangle] @@ -1451,21 +1452,13 @@ pub extern "C" fn canvas_native_webgl2_tex_sub_image3d_asset( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_tex_sub_image3d_asset( - target, - level, - xoffset, - yoffset, - zoffset, - width, - height, - depth, - format, - type_, - &asset.0, - state.get_inner_mut(), - ); + let state = unsafe { &*state }; + state.sync(|state| { + canvas_webgl::webgl2::canvas_native_webgl2_tex_sub_image3d_asset( + target, level, xoffset, yoffset, zoffset, width, height, depth, format, type_, + &asset.0, state, + ) + }); } #[no_mangle] @@ -1484,7 +1477,7 @@ pub extern "C" fn canvas_native_webgl2_tex_sub_image3d_canvas2d( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; + let state = unsafe { &*state }; let canvas = unsafe { &mut *canvas }; let (width, height) = canvas.context.dimensions(); @@ -1493,8 +1486,6 @@ pub extern "C" fn canvas_native_webgl2_tex_sub_image3d_canvas2d( canvas.read_pixels_into(bytes.as_mut_slice(), (0, 0), (width as i32, height as i32)); - - // canvas.make_current(); // let (width, height) = (canvas.context.width(), canvas.context.height()); // let data = canvas.context.as_data(); @@ -1503,22 +1494,22 @@ pub extern "C" fn canvas_native_webgl2_tex_sub_image3d_canvas2d( // let buf = source_ctx.read_pixels_with_alpha_premultiply(&snapshot, format as i32, premultiply); - state.0.make_current(); - - canvas_webgl::webgl2::canvas_native_webgl2_tex_sub_image3d( - target, - level, - xoffset, - yoffset, - zoffset, - width as i32, - height as i32, - depth, - format, - type_, - bytes.as_slice(), - state.get_inner_mut(), - ); + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_tex_sub_image3d( + target, + level, + xoffset, + yoffset, + zoffset, + width as i32, + height as i32, + depth, + format, + type_, + bytes.as_slice(), + state, + ) + }); } #[no_mangle] @@ -1537,11 +1528,10 @@ pub extern "C" fn canvas_native_webgl2_tex_sub_image3d_webgl( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - let webgl = unsafe { &mut *webgl }; - - let (width, height, bytes) = canvas_webgl::webgl::canvas_native_webgl_read_webgl_pixels(&mut webgl.0, &mut state.0); + let state = unsafe { &*state }; + let webgl = unsafe { &*webgl }; + let (width, height, bytes) = webgl.read_drawing_buffer(); // canvas.make_current(); // let (width, height) = (canvas.context.width(), canvas.context.height()); @@ -1551,22 +1541,22 @@ pub extern "C" fn canvas_native_webgl2_tex_sub_image3d_webgl( // let buf = source_ctx.read_pixels_with_alpha_premultiply(&snapshot, format as i32, premultiply); - state.0.make_current(); - - canvas_webgl::webgl2::canvas_native_webgl2_tex_sub_image3d( - target, - level, - xoffset, - yoffset, - zoffset, - width, - height, - depth, - format, - type_, - bytes.as_slice(), - state.get_inner_mut(), - ); + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_tex_sub_image3d( + target, + level, + xoffset, + yoffset, + zoffset, + width, + height, + depth, + format, + type_, + bytes.as_slice(), + state, + ) + }); } #[no_mangle] @@ -1588,22 +1578,14 @@ pub extern "C" fn canvas_native_webgl2_tex_sub_image3d_offset( ) { assert!(!state.is_null()); let buf = unsafe { std::slice::from_raw_parts(buf, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_tex_sub_image3d_offset( - target, - level, - xoffset, - yoffset, - zoffset, - width, - height, - depth, - format, - type_, - buf, - offset, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let buf = buf.to_vec(); + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_tex_sub_image3d_offset( + target, level, xoffset, yoffset, zoffset, width, height, depth, format, type_, &buf, + offset, state, + ) + }) } #[no_mangle] @@ -1615,20 +1597,24 @@ pub extern "C" fn canvas_native_webgl2_transform_feedback_varyings( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_transform_feedback_varyings_raw( - program, - varyings, - size, - buffer_mode, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.sync(|state| { + canvas_webgl::webgl2::canvas_native_webgl2_transform_feedback_varyings_raw( + program, + varyings, + size, + buffer_mode, + state, + ) + }) } #[no_mangle] pub extern "C" fn canvas_native_webgl2_uniform1ui(location: i32, v0: u32, state: *mut WebGLState) { - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_uniform1ui(location, v0, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_uniform1ui(location, v0, state) + }) } #[no_mangle] @@ -1640,8 +1626,11 @@ pub extern "C" fn canvas_native_webgl2_uniform1uiv( ) { assert!(!state.is_null()); let data = unsafe { std::slice::from_raw_parts(data, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_uniform1uiv(location, data, state.get_inner_mut()) + let state = unsafe { &*state }; + let data = data.to_vec(); + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_uniform1uiv(location, &data, state) + }) } #[no_mangle] @@ -1652,8 +1641,10 @@ pub extern "C" fn canvas_native_webgl2_uniform2ui( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_uniform2ui(location, v0, v1, state.get_inner_mut()) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_uniform2ui(location, v0, v1, state) + }) } #[no_mangle] @@ -1665,8 +1656,11 @@ pub extern "C" fn canvas_native_webgl2_uniform2uiv( ) { assert!(!state.is_null()); let data = unsafe { std::slice::from_raw_parts(data, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_uniform2uiv(location, data, state.get_inner_mut()) + let state = unsafe { &*state }; + let data = data.to_vec(); + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_uniform2uiv(location, &data, state) + }) } #[no_mangle] @@ -1678,14 +1672,10 @@ pub extern "C" fn canvas_native_webgl2_uniform3ui( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_uniform3ui( - location, - v0, - v1, - v2, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_uniform3ui(location, v0, v1, v2, state) + }) } #[no_mangle] @@ -1697,8 +1687,11 @@ pub extern "C" fn canvas_native_webgl2_uniform3uiv( ) { assert!(!state.is_null()); let data = unsafe { std::slice::from_raw_parts(data, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_uniform3uiv(location, data, state.get_inner_mut()) + let state = unsafe { &*state }; + let data = data.to_vec(); + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_uniform3uiv(location, &data, state) + }) } #[no_mangle] @@ -1711,15 +1704,10 @@ pub extern "C" fn canvas_native_webgl2_uniform4ui( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_uniform4ui( - location, - v0, - v1, - v2, - v3, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_uniform4ui(location, v0, v1, v2, v3, state) + }) } #[no_mangle] @@ -1731,8 +1719,11 @@ pub extern "C" fn canvas_native_webgl2_uniform4uiv( ) { assert!(!state.is_null()); let data = unsafe { std::slice::from_raw_parts(data, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_uniform4uiv(location, data, state.get_inner_mut()) + let state = unsafe { &*state }; + let data = data.to_vec(); + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_uniform4uiv(location, &data, state) + }) } #[no_mangle] @@ -1743,13 +1734,15 @@ pub extern "C" fn canvas_native_webgl2_uniform_block_binding( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_uniform_block_binding( - program, - uniform_block_index, - uniform_block_binding, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_uniform_block_binding( + program, + uniform_block_index, + uniform_block_binding, + state, + ) + }) } #[no_mangle] @@ -1762,13 +1755,13 @@ pub extern "C" fn canvas_native_webgl2_uniform_matrix2x3fv( ) { assert!(!state.is_null()); let data = unsafe { std::slice::from_raw_parts(data, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_uniform_matrix2x3fv( - location, - transpose, - data, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let data = data.to_vec(); + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_uniform_matrix2x3fv( + location, transpose, &data, state, + ) + }) } #[no_mangle] @@ -1781,13 +1774,13 @@ pub extern "C" fn canvas_native_webgl2_uniform_matrix2x4fv( ) { assert!(!state.is_null()); let data = unsafe { std::slice::from_raw_parts(data, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_uniform_matrix2x4fv( - location, - transpose, - data, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let data = data.to_vec(); + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_uniform_matrix2x4fv( + location, transpose, &data, state, + ) + }) } #[no_mangle] @@ -1800,13 +1793,13 @@ pub extern "C" fn canvas_native_webgl2_uniform_matrix3x2fv( ) { assert!(!state.is_null()); let data = unsafe { std::slice::from_raw_parts(data, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_uniform_matrix3x2fv( - location, - transpose, - data, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let data = data.to_vec(); + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_uniform_matrix3x2fv( + location, transpose, &data, state, + ) + }) } #[no_mangle] @@ -1819,13 +1812,13 @@ pub extern "C" fn canvas_native_webgl2_uniform_matrix3x4fv( ) { assert!(!state.is_null()); let data = unsafe { std::slice::from_raw_parts(data, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_uniform_matrix3x4fv( - location, - transpose, - data, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let data = data.to_vec(); + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_uniform_matrix3x4fv( + location, transpose, &data, state, + ) + }) } #[no_mangle] @@ -1838,13 +1831,13 @@ pub extern "C" fn canvas_native_webgl2_uniform_matrix4x2fv( ) { assert!(!state.is_null()); let data = unsafe { std::slice::from_raw_parts(data, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_uniform_matrix4x2fv( - location, - transpose, - data, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let data = data.to_vec(); + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_uniform_matrix4x2fv( + location, transpose, &data, state, + ) + }) } #[no_mangle] @@ -1857,13 +1850,13 @@ pub extern "C" fn canvas_native_webgl2_uniform_matrix4x3fv( ) { assert!(!state.is_null()); let data = unsafe { std::slice::from_raw_parts(data, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_uniform_matrix4x3fv( - location, - transpose, - data, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let data = data.to_vec(); + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_uniform_matrix4x3fv( + location, transpose, &data, state, + ) + }) } #[no_mangle] @@ -1873,12 +1866,10 @@ pub extern "C" fn canvas_native_webgl2_vertex_attrib_divisor( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_vertex_attrib_divisor( - index, - divisor, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_vertex_attrib_divisor(index, divisor, state) + }) } #[no_mangle] @@ -1891,15 +1882,10 @@ pub extern "C" fn canvas_native_webgl2_vertex_attrib_i4i( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_vertex_attrib_i4i( - index, - x, - y, - z, - w, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_vertex_attrib_i4i(index, x, y, z, w, state) + }) } #[no_mangle] @@ -1911,12 +1897,11 @@ pub extern "C" fn canvas_native_webgl2_vertex_attrib_i4iv( ) { assert!(!state.is_null()); let value = unsafe { std::slice::from_raw_parts(value, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_vertex_attrib_i4iv( - index, - value, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let value = value.to_vec(); + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_vertex_attrib_i4iv(index, &value, state) + }) } #[no_mangle] @@ -1929,15 +1914,10 @@ pub extern "C" fn canvas_native_webgl2_vertex_attrib_i4ui( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_vertex_attrib_i4ui( - index, - x, - y, - z, - w, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_vertex_attrib_i4ui(index, x, y, z, w, state) + }) } #[no_mangle] @@ -1949,12 +1929,11 @@ pub extern "C" fn canvas_native_webgl2_vertex_attrib_i4uiv( ) { assert!(!state.is_null()); let value = unsafe { std::slice::from_raw_parts(value, size) }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_vertex_attrib_i4uiv( - index, - value, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + let value = value.to_vec(); + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_vertex_attrib_i4uiv(index, &value, state) + }) } #[no_mangle] @@ -1973,19 +1952,21 @@ pub extern "C" fn canvas_native_webgl2_tex_image2d_image_asset( assert!(!state.is_null()); assert!(!image_asset.is_null()); let image_asset = unsafe { &*image_asset }; - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_tex_image2d_asset( - target, - level, - internalformat, - width, - height, - border, - format, - type_, - &image_asset.0, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.sync(|state| { + canvas_webgl::webgl2::canvas_native_webgl2_tex_image2d_asset( + target, + level, + internalformat, + width, + height, + border, + format, + type_, + &image_asset.0, + state, + ) + }) } #[no_mangle] @@ -2004,21 +1985,23 @@ pub extern "C" fn canvas_native_webgl2_tex_image2d_src_data_offset( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_tex_image2d_src_data_offset( - target, - level, - internalformat, - width, - height, - border, - format, - type_, - src_data, - src_data_size, - offset, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.sync(|state| { + canvas_webgl::webgl2::canvas_native_webgl2_tex_image2d_src_data_offset( + target, + level, + internalformat, + width, + height, + border, + format, + type_, + src_data, + src_data_size, + offset, + state, + ) + }) } @@ -2036,19 +2019,21 @@ pub extern "C" fn canvas_native_webgl2_tex_image2d_offset( state: *mut WebGLState, ) { assert!(!state.is_null()); - let state = unsafe { &mut *state }; - canvas_webgl::webgl2::canvas_native_webgl2_tex_image2d_offset( - target, - level, - internalformat, - width, - height, - border, - format, - type_, - offset, - state.get_inner_mut(), - ) + let state = unsafe { &*state }; + state.post(move |state| { + canvas_webgl::webgl2::canvas_native_webgl2_tex_image2d_offset( + target, + level, + internalformat, + width, + height, + border, + format, + type_, + offset, + state, + ) + }) } @@ -2068,25 +2053,24 @@ pub extern "C" fn canvas_native_webgl2_tex_image2d_webgl( assert!(!state.is_null()); assert!(!webgl.is_null()); - let state = unsafe { &mut *state }; - let webgl = unsafe { &mut *webgl }; - let mut pixels = canvas_webgl::webgl::canvas_native_webgl_read_webgl_pixels(&mut webgl.0, &mut state.0); + let state = unsafe { &*state }; + let webgl = unsafe { &*webgl }; + let mut pixels = webgl.read_drawing_buffer(); - - state.0.make_current(); - - canvas_webgl::webgl::canvas_native_webgl_tex_image2d( - target, - level, - internalformat, - width as i32, - height as i32, - border, - format, - type_, - pixels.2.as_mut_slice(), - state.get_inner_mut(), - ); + state.post(move |state| { + canvas_webgl::webgl::canvas_native_webgl_tex_image2d( + target, + level, + internalformat, + width as i32, + height as i32, + border, + format, + type_, + pixels.2.as_mut_slice(), + state, + ) + }); } @@ -2107,7 +2091,7 @@ pub extern "C" fn canvas_native_webgl2_tex_image2d_canvas2d( assert!(!canvas.is_null()); let canvas = unsafe { &mut *canvas }; - let state = unsafe { &mut *state }; + let state = unsafe { &*state }; // canvas.make_current(); @@ -2115,68 +2099,114 @@ pub extern "C" fn canvas_native_webgl2_tex_image2d_canvas2d( let mut bytes = vec![0u8; (source_width * source_height * 4.) as usize]; - canvas.read_pixels_into(bytes.as_mut_slice(), (0, 0), (source_width as i32, source_height as i32)); - - state.0.make_current(); + canvas.read_pixels_into( + bytes.as_mut_slice(), + (0, 0), + (source_width as i32, source_height as i32), + ); - if format as u32 == gl_bindings::RGBA { - unsafe { - if state.0.get_flip_y() { - let mut buffer = bytes.to_vec(); - utils::gl::flip_in_place( - buffer.as_mut_ptr(), - buffer.len(), - (bytes_per_pixel(type_ as u32, format as u32) * source_width as u32) as usize, - source_height as usize, - ); + state.sync(|state| { + state.make_current(); + + if format as u32 == gl_bindings::RGBA { + unsafe { + if state.get_flip_y() { + let mut buffer = bytes.to_vec(); + utils::gl::flip_in_place( + buffer.as_mut_ptr(), + buffer.len(), + (bytes_per_pixel(type_ as u32, format as u32) * source_width as u32) + as usize, + source_height as usize, + ); + + gl_bindings::TexImage2D( + target as u32, + level, + internalformat, + width as i32, + height as i32, + border, + format as u32, + type_ as u32, + buffer.as_ptr() as *const c_void, + ); + + return; + } gl_bindings::TexImage2D( target as u32, level, internalformat, - width as i32, - height as i32, + source_width as i32, + source_height as i32, border, format as u32, type_ as u32, - buffer.as_ptr() as *const c_void, + bytes.as_ptr() as *const c_void, ); - - return; } - - gl_bindings::TexImage2D( - target as u32, - level, - internalformat, - source_width as i32, - source_height as i32, - border, - format as u32, - type_ as u32, - bytes.as_ptr() as *const c_void, - ); + return; } - return; - } - let integers = match format as u32 { - gl_bindings::RGBA_INTEGER => Some(canvas_core::image_asset::ImageAsset::rgba_to_rgba_integer(bytes.as_slice(), source_width as usize, source_height as usize)), - gl_bindings::RGB_INTEGER => Some(canvas_core::image_asset::ImageAsset::rgba_to_rgb_integer(bytes.as_slice(), source_width as usize, source_height as usize)), - gl_bindings::RED_INTEGER => Some(canvas_core::image_asset::ImageAsset::rgba_to_red_integer(bytes.as_slice(), source_width as usize, source_height as usize)), - gl_bindings::RG_INTEGER => Some(canvas_core::image_asset::ImageAsset::rgba_to_rg_integer(bytes.as_slice(), source_width as usize, source_height as usize)), - _ => None, - }; - - if let Some(mut integers) = integers { - unsafe { - if state.0.get_flip_y() { - utils::gl::flip_in_place_integer( - integers.as_mut_ptr(), - integers.len(), - (bytes_per_pixel(type_ as u32, format as u32) * source_width as u32) as usize, + let integers = match format as u32 { + gl_bindings::RGBA_INTEGER => { + Some(canvas_core::image_asset::ImageAsset::rgba_to_rgba_integer( + bytes.as_slice(), + source_width as usize, source_height as usize, - ); + )) + } + gl_bindings::RGB_INTEGER => { + Some(canvas_core::image_asset::ImageAsset::rgba_to_rgb_integer( + bytes.as_slice(), + source_width as usize, + source_height as usize, + )) + } + gl_bindings::RED_INTEGER => { + Some(canvas_core::image_asset::ImageAsset::rgba_to_red_integer( + bytes.as_slice(), + source_width as usize, + source_height as usize, + )) + } + gl_bindings::RG_INTEGER => { + Some(canvas_core::image_asset::ImageAsset::rgba_to_rg_integer( + bytes.as_slice(), + source_width as usize, + source_height as usize, + )) + } + _ => None, + }; + + if let Some(mut integers) = integers { + unsafe { + if state.get_flip_y() { + utils::gl::flip_in_place_integer( + integers.as_mut_ptr(), + integers.len(), + (bytes_per_pixel(type_ as u32, format as u32) * source_width as u32) + as usize, + source_height as usize, + ); + + gl_bindings::TexImage2D( + target as u32, + level, + internalformat, + width as i32, + height as i32, + border, + format as u32, + type_ as u32, + integers.as_ptr() as *const c_void, + ); + + return; + } gl_bindings::TexImage2D( target as u32, @@ -2189,45 +2219,74 @@ pub extern "C" fn canvas_native_webgl2_tex_image2d_canvas2d( type_ as u32, integers.as_ptr() as *const c_void, ); - return; } - - gl_bindings::TexImage2D( - target as u32, - level, - internalformat, - width as i32, - height as i32, - border, - format as u32, - type_ as u32, - integers.as_ptr() as *const c_void, - ); - return; } - } - let bytes = match format as u32 { - gl_bindings::RGB => Some(canvas_core::image_asset::ImageAsset::rgba_to_rgb(bytes.as_slice(), source_width as usize, source_height as usize)), - gl_bindings::LUMINANCE => Some(canvas_core::image_asset::ImageAsset::rgba_to_luminance(bytes.as_slice(), source_width as usize, source_height as usize)), - gl_bindings::LUMINANCE_ALPHA => Some(canvas_core::image_asset::ImageAsset::rgba_to_luminance_alpha(bytes.as_slice(), source_width as usize, source_height as usize)), - gl_bindings::ALPHA => Some(canvas_core::image_asset::ImageAsset::rgba_to_alpha(bytes.as_slice(), source_width as usize, source_height as usize)), - gl_bindings::RED => Some(canvas_core::image_asset::ImageAsset::rgba_to_red(bytes.as_slice(), source_width as usize, source_height as usize)), - gl_bindings::RG => Some(canvas_core::image_asset::ImageAsset::rgba_to_rg(bytes.as_slice(), source_width as usize, source_height as usize)), - _ => None, - }; - - if let Some(bytes) = bytes { - unsafe { - if state.0.get_flip_y() { - let mut buffer = bytes; - utils::gl::flip_in_place( - buffer.as_mut_ptr(), - buffer.len(), - (bytes_per_pixel(type_ as u32, format as u32) * source_width as u32) as usize, + let bytes = match format as u32 { + gl_bindings::RGB => Some(canvas_core::image_asset::ImageAsset::rgba_to_rgb( + bytes.as_slice(), + source_width as usize, + source_height as usize, + )), + gl_bindings::LUMINANCE => { + Some(canvas_core::image_asset::ImageAsset::rgba_to_luminance( + bytes.as_slice(), + source_width as usize, source_height as usize, - ); + )) + } + gl_bindings::LUMINANCE_ALPHA => Some( + canvas_core::image_asset::ImageAsset::rgba_to_luminance_alpha( + bytes.as_slice(), + source_width as usize, + source_height as usize, + ), + ), + gl_bindings::ALPHA => Some(canvas_core::image_asset::ImageAsset::rgba_to_alpha( + bytes.as_slice(), + source_width as usize, + source_height as usize, + )), + gl_bindings::RED => Some(canvas_core::image_asset::ImageAsset::rgba_to_red( + bytes.as_slice(), + source_width as usize, + source_height as usize, + )), + gl_bindings::RG => Some(canvas_core::image_asset::ImageAsset::rgba_to_rg( + bytes.as_slice(), + source_width as usize, + source_height as usize, + )), + _ => None, + }; + + if let Some(bytes) = bytes { + unsafe { + if state.get_flip_y() { + let mut buffer = bytes; + utils::gl::flip_in_place( + buffer.as_mut_ptr(), + buffer.len(), + (bytes_per_pixel(type_ as u32, format as u32) * source_width as u32) + as usize, + source_height as usize, + ); + + gl_bindings::TexImage2D( + target as u32, + level, + internalformat, + width as i32, + height as i32, + border, + format as u32, + type_ as u32, + buffer.as_ptr() as *const c_void, + ); + + return; + } gl_bindings::TexImage2D( target as u32, @@ -2238,26 +2297,12 @@ pub extern "C" fn canvas_native_webgl2_tex_image2d_canvas2d( border, format as u32, type_ as u32, - buffer.as_ptr() as *const c_void, + bytes.as_ptr() as *const c_void, ); - return; } - - gl_bindings::TexImage2D( - target as u32, - level, - internalformat, - width as i32, - height as i32, - border, - format as u32, - type_ as u32, - bytes.as_ptr() as *const c_void, - ); - return; } - } + }) } @@ -2278,72 +2323,114 @@ pub extern "C" fn canvas_native_webgl2_tex_image2d_image_data( assert!(!image_data.is_null()); let image_data = unsafe { &*image_data }; - let state = unsafe { &mut *state }; + let state = unsafe { &*state }; let (source_width, source_height) = image_data.0.dimensions(); - state.0.make_current(); - - let bytes = image_data.0.data(); - - if format as u32 == gl_bindings::RGBA { - unsafe { - if state.0.get_flip_y() { - let mut buffer = bytes.to_vec(); - utils::gl::flip_in_place( - buffer.as_mut_ptr(), - buffer.len(), - (bytes_per_pixel(type_ as u32, format as u32) * source_width as u32) as usize, - source_height as usize, - ); + state.sync(|state| { + state.make_current(); + + let bytes = image_data.0.data(); + + if format as u32 == gl_bindings::RGBA { + unsafe { + if state.get_flip_y() { + let mut buffer = bytes.to_vec(); + utils::gl::flip_in_place( + buffer.as_mut_ptr(), + buffer.len(), + (bytes_per_pixel(type_ as u32, format as u32) * source_width as u32) + as usize, + source_height as usize, + ); + + gl_bindings::TexImage2D( + target as u32, + level, + internalformat, + width as i32, + height as i32, + border, + format as u32, + type_ as u32, + buffer.as_ptr() as *const c_void, + ); + + return; + } gl_bindings::TexImage2D( target as u32, level, internalformat, - width as i32, - height as i32, + source_width, + source_height, border, format as u32, type_ as u32, - buffer.as_ptr() as *const c_void, + bytes.as_ptr() as *const c_void, ); - - return; } - - gl_bindings::TexImage2D( - target as u32, - level, - internalformat, - source_width, - source_height, - border, - format as u32, - type_ as u32, - bytes.as_ptr() as *const c_void, - ); + return; } - return; - } - let integers = match format as u32 { - gl_bindings::RGBA_INTEGER => Some(canvas_core::image_asset::ImageAsset::rgba_to_rgba_integer(bytes, source_width as usize, source_height as usize)), - gl_bindings::RGB_INTEGER => Some(canvas_core::image_asset::ImageAsset::rgba_to_rgb_integer(bytes, source_width as usize, source_height as usize)), - gl_bindings::RED_INTEGER => Some(canvas_core::image_asset::ImageAsset::rgba_to_red_integer(bytes, source_width as usize, source_height as usize)), - gl_bindings::RG_INTEGER => Some(canvas_core::image_asset::ImageAsset::rgba_to_rg_integer(bytes, source_width as usize, source_height as usize)), - _ => None, - }; - - if let Some(mut integers) = integers { - unsafe { - if state.0.get_flip_y() { - utils::gl::flip_in_place_integer( - integers.as_mut_ptr(), - integers.len(), - (bytes_per_pixel(type_ as u32, format as u32) * source_width as u32) as usize, + let integers = match format as u32 { + gl_bindings::RGBA_INTEGER => { + Some(canvas_core::image_asset::ImageAsset::rgba_to_rgba_integer( + bytes, + source_width as usize, source_height as usize, - ); + )) + } + gl_bindings::RGB_INTEGER => { + Some(canvas_core::image_asset::ImageAsset::rgba_to_rgb_integer( + bytes, + source_width as usize, + source_height as usize, + )) + } + gl_bindings::RED_INTEGER => { + Some(canvas_core::image_asset::ImageAsset::rgba_to_red_integer( + bytes, + source_width as usize, + source_height as usize, + )) + } + gl_bindings::RG_INTEGER => { + Some(canvas_core::image_asset::ImageAsset::rgba_to_rg_integer( + bytes, + source_width as usize, + source_height as usize, + )) + } + _ => None, + }; + + if let Some(mut integers) = integers { + unsafe { + if state.get_flip_y() { + utils::gl::flip_in_place_integer( + integers.as_mut_ptr(), + integers.len(), + (bytes_per_pixel(type_ as u32, format as u32) * source_width as u32) + as usize, + source_height as usize, + ); + + gl_bindings::TexImage2D( + target as u32, + level, + internalformat, + width as i32, + height as i32, + border, + format as u32, + type_ as u32, + integers.as_ptr() as *const c_void, + ); + + return; + } gl_bindings::TexImage2D( target as u32, @@ -2356,45 +2443,74 @@ pub extern "C" fn canvas_native_webgl2_tex_image2d_image_data( type_ as u32, integers.as_ptr() as *const c_void, ); - return; } - - gl_bindings::TexImage2D( - target as u32, - level, - internalformat, - width as i32, - height as i32, - border, - format as u32, - type_ as u32, - integers.as_ptr() as *const c_void, - ); - return; } - } - let bytes = match format as u32 { - gl_bindings::RGB => Some(canvas_core::image_asset::ImageAsset::rgba_to_rgb(bytes, source_width as usize, source_height as usize)), - gl_bindings::LUMINANCE => Some(canvas_core::image_asset::ImageAsset::rgba_to_luminance(bytes, source_width as usize, source_height as usize)), - gl_bindings::LUMINANCE_ALPHA => Some(canvas_core::image_asset::ImageAsset::rgba_to_luminance_alpha(bytes, source_width as usize, source_height as usize)), - gl_bindings::ALPHA => Some(canvas_core::image_asset::ImageAsset::rgba_to_alpha(bytes, source_width as usize, source_height as usize)), - gl_bindings::RED => Some(canvas_core::image_asset::ImageAsset::rgba_to_red(bytes, source_width as usize, source_height as usize)), - gl_bindings::RG => Some(canvas_core::image_asset::ImageAsset::rgba_to_rg(bytes, source_width as usize, source_height as usize)), - _ => None, - }; - - if let Some(bytes) = bytes { - unsafe { - if state.0.get_flip_y() { - let mut buffer = bytes; - utils::gl::flip_in_place( - buffer.as_mut_ptr(), - buffer.len(), - (bytes_per_pixel(type_ as u32, format as u32) * source_width as u32) as usize, + let bytes = match format as u32 { + gl_bindings::RGB => Some(canvas_core::image_asset::ImageAsset::rgba_to_rgb( + bytes, + source_width as usize, + source_height as usize, + )), + gl_bindings::LUMINANCE => { + Some(canvas_core::image_asset::ImageAsset::rgba_to_luminance( + bytes, + source_width as usize, source_height as usize, - ); + )) + } + gl_bindings::LUMINANCE_ALPHA => Some( + canvas_core::image_asset::ImageAsset::rgba_to_luminance_alpha( + bytes, + source_width as usize, + source_height as usize, + ), + ), + gl_bindings::ALPHA => Some(canvas_core::image_asset::ImageAsset::rgba_to_alpha( + bytes, + source_width as usize, + source_height as usize, + )), + gl_bindings::RED => Some(canvas_core::image_asset::ImageAsset::rgba_to_red( + bytes, + source_width as usize, + source_height as usize, + )), + gl_bindings::RG => Some(canvas_core::image_asset::ImageAsset::rgba_to_rg( + bytes, + source_width as usize, + source_height as usize, + )), + _ => None, + }; + + if let Some(bytes) = bytes { + unsafe { + if state.get_flip_y() { + let mut buffer = bytes; + utils::gl::flip_in_place( + buffer.as_mut_ptr(), + buffer.len(), + (bytes_per_pixel(type_ as u32, format as u32) * source_width as u32) + as usize, + source_height as usize, + ); + + gl_bindings::TexImage2D( + target as u32, + level, + internalformat, + width as i32, + height as i32, + border, + format as u32, + type_ as u32, + buffer.as_ptr() as *const c_void, + ); + + return; + } gl_bindings::TexImage2D( target as u32, @@ -2405,24 +2521,10 @@ pub extern "C" fn canvas_native_webgl2_tex_image2d_image_data( border, format as u32, type_ as u32, - buffer.as_ptr() as *const c_void, + bytes.as_ptr() as *const c_void, ); - return; } - - gl_bindings::TexImage2D( - target as u32, - level, - internalformat, - width as i32, - height as i32, - border, - format as u32, - type_ as u32, - bytes.as_ptr() as *const c_void, - ); - return; } - } + }) } diff --git a/crates/canvas-c/src/webgl/mod.rs b/crates/canvas-c/src/webgl/mod.rs index a9b2ea06a..2eee33562 100644 --- a/crates/canvas-c/src/webgl/mod.rs +++ b/crates/canvas-c/src/webgl/mod.rs @@ -4,6 +4,8 @@ mod gl2; pub use gl2::*; mod result; pub use result::*; +pub(crate) mod thread; +pub use thread::{canvas_native_canvases_behind, canvas_native_canvases_behind_address}; #[allow(non_camel_case_types)] #[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] diff --git a/crates/canvas-c/src/webgl/thread.rs b/crates/canvas-c/src/webgl/thread.rs new file mode 100644 index 000000000..190450cc9 --- /dev/null +++ b/crates/canvas-c/src/webgl/thread.rs @@ -0,0 +1,183 @@ +//! Runs every threaded WebGL context. Its GL context is created, used, presented and dropped on +//! this one thread, so the JS thread never waits on the driver: calls that return nothing queue up +//! behind each other, and the rest run here while the caller waits. One thread for all of them keeps +//! reads from one context into another (texImage2D from a WebGL canvas) on a single thread. + +use std::cell::Cell; +use std::collections::VecDeque; +use std::sync::atomic::{AtomicU32, Ordering}; +use std::sync::{mpsc, Arc, Condvar, Mutex, OnceLock}; + +type Job = Box; + +struct Worker { + queue: Mutex>, + signal: Condvar, +} + +impl Worker { + fn push(&self, job: Job) { + if let Ok(mut queue) = self.queue.lock() { + queue.push_back(job); + } + self.signal.notify_one(); + } +} + +static WORKER: OnceLock>> = OnceLock::new(); + +/// Threaded canvases (WebGL here, 2D on its render thread) with a frame waiting behind another +/// that hasn't reached the screen yet: the GPU is behind them. +static CANVASES_BEHIND: AtomicU32 = AtomicU32::new(0); + +thread_local! { + static ON_GL_THREAD: Cell = const { Cell::new(false) }; +} + +fn worker() -> Option> { + WORKER + .get_or_init(|| { + let worker = Arc::new(Worker { + queue: Mutex::new(VecDeque::new()), + signal: Condvar::new(), + }); + let shared = Arc::clone(&worker); + std::thread::Builder::new() + .name("nsc-webgl".to_owned()) + .spawn(move || run(shared)) + .ok() + .map(|_| worker) + }) + .clone() +} + +fn raise_priority() { + #[cfg(target_os = "android")] + unsafe { + // THREAD_PRIORITY_DISPLAY, for this thread only. + libc::setpriority(libc::PRIO_PROCESS, 0, -4); + } + #[cfg(any( + target_os = "ios", + target_os = "tvos", + target_os = "visionos", + target_os = "macos" + ))] + unsafe { + libc::pthread_set_qos_class_self_np(libc::qos_class_t::QOS_CLASS_USER_INTERACTIVE, 0); + } +} + +fn run(worker: Arc) { + raise_priority(); + ON_GL_THREAD.with(|on| on.set(true)); + loop { + let jobs: Vec = { + let Ok(mut queue) = worker.queue.lock() else { + return; + }; + while queue.is_empty() { + queue = match worker.signal.wait(queue) { + Ok(queue) => queue, + Err(_) => return, + }; + } + queue.drain(..).collect() + }; + for job in jobs { + job(); + } + } +} + +/// Whether contexts can be threaded at all: false if the thread could not be started. +pub(crate) fn available() -> bool { + worker().is_some() +} + +pub(crate) fn on_gl_thread() -> bool { + ON_GL_THREAD.with(|on| on.get()) +} + +/// Queues `job` behind every earlier one. On the GL thread itself (a job calling back into the +/// FFI) it runs at once: it belongs to the job that is running. +pub(crate) fn post(job: impl FnOnce() + Send + 'static) { + if on_gl_thread() { + job(); + return; + } + match worker() { + Some(worker) => worker.push(Box::new(job)), + None => job(), + } +} + +struct AssertSend(T); + +// Only built by `sync`, which blocks until the value has crossed back. +unsafe impl Send for AssertSend {} + +/// Runs `f` after every queued job and returns its result, blocking the caller until then. Because +/// the caller waits, `f` may borrow from its stack and needn't be `Send`: nothing else touches what +/// it captures while it runs. +pub(crate) fn sync(f: impl FnOnce() -> R) -> R { + if on_gl_thread() { + return f(); + } + let Some(worker) = worker() else { + return f(); + }; + let (tx, rx) = mpsc::sync_channel::>(1); + let f = AssertSend(f); + let job: Box = Box::new(move || { + let f = f; + let _ = tx.send(AssertSend((f.0)())); + }); + // SAFETY: `recv` below doesn't return until the job has run and dropped its captures, so the + // borrows it holds outlive it, and AssertSend covers the thread hop. + let job: Job = unsafe { std::mem::transmute::, Job>(job) }; + worker.push(job); + match rx.recv() { + Ok(value) => value.0, + // The job was dropped without running: only if it panicked. + Err(_) => panic!("webgl thread job failed"), + } +} + +/// Frames a context may have queued before it counts as behind: one being presented, one next. +pub(crate) const BEHIND_AT: u32 = 2; + +/// A context's queued presents went from `before` to `before + 1`. +pub(crate) fn frame_queued(before: u32) { + if before + 1 == BEHIND_AT { + canvas_behind(); + } +} + +/// A context's queued presents went from `before` to `before - 1`. +pub(crate) fn frame_presented(before: u32) { + if before == BEHIND_AT { + canvas_caught_up(); + } +} + +pub(crate) fn canvas_behind() { + CANVASES_BEHIND.fetch_add(1, Ordering::AcqRel); +} + +pub(crate) fn canvas_caught_up() { + CANVASES_BEHIND.fetch_sub(1, Ordering::AcqRel); +} + +/// How many threaded canvases are behind. The JS side holds requestAnimationFrame back while any +/// are, as a browser does when its compositor falls behind, rather than queue more work. +#[no_mangle] +pub extern "C" fn canvas_native_canvases_behind() -> u32 { + CANVASES_BEHIND.load(Ordering::Acquire) +} + +/// Where that count lives, for the JS side to read as memory every frame instead of calling in. +#[no_mangle] +pub extern "C" fn canvas_native_canvases_behind_address() -> *const u32 { + CANVASES_BEHIND.as_ptr() +} diff --git a/crates/canvas-c/src/webgpu/gpu_queue.rs b/crates/canvas-c/src/webgpu/gpu_queue.rs index bc5fe1d6b..51a1ec4f4 100644 --- a/crates/canvas-c/src/webgpu/gpu_queue.rs +++ b/crates/canvas-c/src/webgpu/gpu_queue.rs @@ -283,9 +283,7 @@ pub unsafe extern "C" fn canvas_native_webgpu_queue_copy_webgl_to_texture( return; } // An image: RGBA8, top row first (flip_y then flips it, as for the other sources). - let (width, height, mut bytes) = canvas_webgl::webgl::canvas_native_webgl_read_drawing_buffer( - &mut (*(source.source as *mut crate::webgl::WebGLState)).0, - ); + let (width, height, mut bytes) = (*source.source).read_drawing_buffer(); { let destination = &*destination; diff --git a/crates/canvas-core/src/gpu/gl/android.rs b/crates/canvas-core/src/gpu/gl/android.rs index 94073805a..a398d5e1f 100644 --- a/crates/canvas-core/src/gpu/gl/android.rs +++ b/crates/canvas-core/src/gpu/gl/android.rs @@ -16,7 +16,7 @@ use glutin::config::{ Api, ColorBufferType, ConfigSurfaceTypes, ConfigTemplate, ConfigTemplateBuilder, }; use glutin::context::AsRawContext; -use glutin::context::{ContextApi, RawContext, Version}; +use glutin::context::{ContextApi, ContextAttributesBuilder, Priority, RawContext, Version}; use glutin::display::AsRawDisplay; use glutin::display::{GetGlDisplay, RawDisplay}; use glutin::prelude::GlSurface; @@ -116,6 +116,17 @@ pub(crate) enum SurfaceHelper { Pixmap(Surface), } + +/// WebGL contexts (not a 2D canvas's) run at low GPU priority where the driver allows it, so the +/// UI's own rendering is scheduled ahead of a scene that saturates the GPU. +fn webgl_priority(builder: ContextAttributesBuilder, is_canvas: bool) -> ContextAttributesBuilder { + if is_canvas { + builder + } else { + builder.with_priority(Priority::Low) + } +} + #[derive(Debug, Clone)] pub struct GLContextRaw { surface: RawSurface, @@ -629,6 +640,7 @@ impl GLContext { .map(|v| SurfaceHelper::Window(v)) .ok(); + let context_attrs_is_canvas = context_attrs.get_is_canvas(); let mut context_attrs = glutin::context::ContextAttributesBuilder::new() .with_context_api(ContextApi::Gles(Some( if context_attrs.get_is_canvas() | context_attrs.get_gl_legacy() { @@ -644,7 +656,8 @@ impl GLContext { } } - let context_attrs = context_attrs.build(Some(window)); + let context_attrs = webgl_priority(context_attrs, context_attrs_is_canvas) + .build(Some(window)); let context = display .create_context(&config, &context_attrs) @@ -1077,15 +1090,19 @@ impl GLContext { .map(SurfaceHelper::Pbuffer) .ok(); - let context_attrs = glutin::context::ContextAttributesBuilder::new() - .with_context_api(ContextApi::Gles(Some( - if context_attrs.get_is_canvas() | context_attrs.get_gl_legacy() { - Version::new(2, 0) - } else { - Version::new(3, 0) - }, - ))) - .build(None); + let context_attrs = webgl_priority( + glutin::context::ContextAttributesBuilder::new().with_context_api( + ContextApi::Gles(Some( + if context_attrs.get_is_canvas() | context_attrs.get_gl_legacy() { + Version::new(2, 0) + } else { + Version::new(3, 0) + }, + )), + ), + context_attrs.get_is_canvas(), + ) + .build(None); let context = display .create_context(&config, &context_attrs) diff --git a/crates/canvas-core/src/gpu/vulkan.rs b/crates/canvas-core/src/gpu/vulkan.rs index 77a5d7ad6..46b299476 100644 --- a/crates/canvas-core/src/gpu/vulkan.rs +++ b/crates/canvas-core/src/gpu/vulkan.rs @@ -30,11 +30,22 @@ pub struct AshGraphics { impl Drop for AshGraphics { fn drop(&mut self) { unsafe { - self.device.device_wait_idle().unwrap(); + // A lost device fails this; teardown goes ahead regardless. + let _ = self.device.device_wait_idle(); - if let Some(surface) = self.surface { + for view in self.swap_chain_image_view.take().unwrap_or_default() { + self.device.destroy_image_view(view, None); + } + // Before the surface: a live swapchain keeps the window connected to Vulkan, and + // anything that later presents to it (a GL fallback) fails to connect. + if let Some(swap_chain) = self.swap_chain.take() { + self.swap_chain_loader.destroy_swapchain(swap_chain, None); + } + if let Some(surface) = self.surface.take() { self.surface_loader.destroy_surface(surface, None); } + self.device.destroy_semaphore(self.image_available_semaphore, None); + self.device.destroy_semaphore(self.present_semaphore, None); self.device.destroy_device(None); self.instance.destroy_instance(None); diff --git a/packages/canvas/Canvas/index.android.ts b/packages/canvas/Canvas/index.android.ts index 66183d331..0be2f39f9 100644 --- a/packages/canvas/Canvas/index.android.ts +++ b/packages/canvas/Canvas/index.android.ts @@ -6,7 +6,7 @@ import { WebGL2RenderingContext } from '../WebGL2/WebGL2RenderingContext'; import { Application, View, Screen, ImageSource, Utils, widthProperty, heightProperty, isUserInteractionEnabledProperty } from '@nativescript/core'; import { GPUCanvasContext } from '../WebGPU'; import { ImageBitmapRenderingContext } from '../ImageBitmapRenderingContext'; -import { handleContextOptions, microtask, CanvasContextType } from './utils'; +import { handleContextOptions, microtask, CanvasContextType, setParentPercentSize, holdBackAnimationFramesWhileBehind } from './utils'; export function createSVGMatrix(): DOMMatrix { return new DOMMatrix(); @@ -100,6 +100,12 @@ export class Canvas extends CanvasBase { /** Default for `getContext('2d', { threaded })`: rasterize on a shared render thread. */ static threaded2D = true; + /** + * Default for `getContext('webgl' | 'webgl2', { threaded })`: run the context on the WebGL + * thread, so GL work and presenting never block the UI thread. + */ + static threadedWebGL = true; + constructor(nativeInstance?) { super(); if (nativeInstance) { @@ -325,18 +331,20 @@ export class Canvas extends CanvasBase { [widthProperty.setNative](value) { this.__setLayoutLength(widthProperty.setNative, value); + setParentPercentSize(this, true, value); this.__setSurfaceWidth(fromCssLength(value)); } [heightProperty.setNative](value) { this.__setLayoutLength(heightProperty.setNative, value); + setParentPercentSize(this, false, value); this.__setSurfaceHeight(fromCssLength(value)); } /** * A fixed CSS size also goes to the view's layout params, as for any view: a parent that * measures the canvas natively (MasonKit) would otherwise size it to its surface. % and auto - * keep the layout params the canvas was given. + * keep the layout params the canvas was given; a % also goes to such a parent to resolve. */ private __setLayoutLength(setNative: symbol, value: any) { if (typeof value === 'number' || value?.unit === 'dip' || value?.unit === 'px') { @@ -501,6 +509,9 @@ export class Canvas extends CanvasBase { const threaded = !!(contextAttributes?.threaded ?? Canvas.threaded2D); this._canvas.setThreaded2D?.(threaded); + if (threaded) { + holdBackAnimationFramesWhileBehind(); + } const ctx = this._canvas.create2DContext(opts.alpha, opts.antialias, opts.depth, opts.failIfMajorPerformanceCaveat, opts.powerPreference, opts.premultipliedAlpha, opts.preserveDrawingBuffer, opts.stencil, opts.desynchronized, opts.xrCompatible, opts.willReadFrequently ?? false, opts.colorSpace ?? 0); const context = new (CanvasRenderingContext2D as any)(ctx, opts); // @ts-ignore @@ -513,6 +524,14 @@ export class Canvas extends CanvasBase { return context; } + private __setThreadedWebGL(contextAttributes?: any) { + const threaded = !!(contextAttributes?.threaded ?? Canvas.threadedWebGL); + this._canvas.setThreadedWebGL?.(threaded); + if (threaded) { + holdBackAnimationFramesWhileBehind(); + } + } + getContext(type: string, contextAttributes?: any): CanvasRenderingContext2D | WebGLRenderingContext | WebGL2RenderingContext | GPUCanvasContext | null { if (!this._canvas) { return null; @@ -551,6 +570,7 @@ export class Canvas extends CanvasBase { } if (!this._webglContext) { const opts = { version: 1, ...defaultOpts, ...handleContextOptions(type, contextAttributes) }; + this.__setThreadedWebGL(contextAttributes); this._canvas.initContext(type, opts.alpha, false, opts.depth, opts.failIfMajorPerformanceCaveat, opts.powerPreference, opts.premultipliedAlpha, opts.preserveDrawingBuffer, opts.stencil, opts.desynchronized, opts.xrCompatible); this._webglContext = new (WebGLRenderingContext as any)(this._canvas, opts); (this._webglContext as any)._canvas = this; @@ -566,6 +586,7 @@ export class Canvas extends CanvasBase { } if (!this._webgl2Context) { const opts = { version: 2, ...defaultOpts, ...handleContextOptions(type, contextAttributes) }; + this.__setThreadedWebGL(contextAttributes); this._canvas.initContext(type, opts.alpha, false, opts.depth, opts.failIfMajorPerformanceCaveat, opts.powerPreference, opts.premultipliedAlpha, opts.preserveDrawingBuffer, opts.stencil, opts.desynchronized, opts.xrCompatible); this._webgl2Context = new (WebGL2RenderingContext as any)(this._canvas, opts); (this._webgl2Context as any)._canvas = this; diff --git a/packages/canvas/Canvas/index.ios.ts b/packages/canvas/Canvas/index.ios.ts index 69e11f480..9168816de 100644 --- a/packages/canvas/Canvas/index.ios.ts +++ b/packages/canvas/Canvas/index.ios.ts @@ -6,7 +6,7 @@ import { WebGL2RenderingContext } from '../WebGL2/WebGL2RenderingContext'; import { ImageSource, Utils, Screen, isUserInteractionEnabledProperty, widthProperty, heightProperty } from '@nativescript/core'; import { GPUCanvasContext } from '../WebGPU'; import { ImageBitmapRenderingContext } from '../ImageBitmapRenderingContext'; -import { handleContextOptions, microtask, CanvasContextType } from './utils'; +import { handleContextOptions, microtask, CanvasContextType, setParentPercentSize, holdBackAnimationFramesWhileBehind } from './utils'; declare var NSCCanvas, NSCCanvasListener; export function createSVGMatrix(): DOMMatrix { @@ -192,6 +192,7 @@ export class Canvas extends CanvasBase { } [widthProperty.setNative](value: any) { + setParentPercentSize(this, true, value); this.__setSurfaceWidth(fromCssLength(value)); } @@ -260,6 +261,7 @@ export class Canvas extends CanvasBase { } [heightProperty.setNative](value: any) { + setParentPercentSize(this, false, value); this.__setSurfaceHeight(fromCssLength(value)); } @@ -499,6 +501,9 @@ export class Canvas extends CanvasBase { const opts = { ...defaultOpts, ...handleContextOptions(type, options), fontColor: this.parent?.style?.color?.android || -16777216 }; const threaded = !!(options?.threaded ?? Canvas.threaded2D); + if (threaded) { + holdBackAnimationFramesWhileBehind(); + } if ('threaded2D' in this._canvas) { this._canvas.threaded2D = threaded; } diff --git a/packages/canvas/Canvas/napi-host.ts b/packages/canvas/Canvas/napi-host.ts index ebf9142e1..182b9c57f 100644 --- a/packages/canvas/Canvas/napi-host.ts +++ b/packages/canvas/Canvas/napi-host.ts @@ -15,7 +15,7 @@ import { WebGL2RenderingContext } from '../WebGL2/WebGL2RenderingContext'; import { GPUCanvasContext } from '../WebGPU'; import { ImageBitmapRenderingContext } from '../ImageBitmapRenderingContext'; import { ImageSource, Screen, Utils, widthProperty, heightProperty } from '@nativescript/core'; -import { handleContextOptions, microtask, CanvasContextType } from './utils'; +import { handleContextOptions, microtask, CanvasContextType, isPercentLength, setParentPercentSize } from './utils'; import { Helpers } from '../helpers'; export function createSVGMatrix(): DOMMatrix { @@ -54,15 +54,6 @@ export const enum CanvasFit { ScaleDown = 4, } -function isPercentLength(value: any) { - return (typeof value === 'object' && value?.unit === '%') || (typeof value === 'string' && value.trim().endsWith('%')); -} - -/** A % length as a 0-1 fraction. */ -function percentFraction(value: any): number { - return typeof value === 'string' ? parseFloat(value) / 100 : value.value; -} - function isFixedLength(value: any) { return value?.unit === 'px' || value?.unit === 'dip'; } @@ -261,13 +252,13 @@ export abstract class NapiCanvas extends CanvasBase { // handed the % size (`_setChildPercentSize`), to resolve against its containing block. [widthProperty.setNative](value: any) { (Object.getPrototypeOf(NapiCanvas.prototype) as any)[widthProperty.setNative]?.call(this, isPercentLength(value) ? 'auto' : value); - if (isPercentLength(value)) (this.parent as any)?._setChildPercentSize?.(this, true, percentFraction(value)); + setParentPercentSize(this, true, value); this.__setSurfaceWidth(fromCssLength(value)); } [heightProperty.setNative](value: any) { (Object.getPrototypeOf(NapiCanvas.prototype) as any)[heightProperty.setNative]?.call(this, isPercentLength(value) ? 'auto' : value); - if (isPercentLength(value)) (this.parent as any)?._setChildPercentSize?.(this, false, percentFraction(value)); + setParentPercentSize(this, false, value); this.__setSurfaceHeight(fromCssLength(value)); } diff --git a/packages/canvas/Canvas/utils.ts b/packages/canvas/Canvas/utils.ts index e79bcfa50..3f9a01efc 100644 --- a/packages/canvas/Canvas/utils.ts +++ b/packages/canvas/Canvas/utils.ts @@ -95,3 +95,96 @@ export function removeItemFromArray(array: any[], item) { } export const microtask: (cb: () => void) => void = typeof queueMicrotask === 'function' ? queueMicrotask : (cb) => Promise.resolve().then(cb); + +export function isPercentLength(value: any) { + return (typeof value === 'object' && value?.unit === '%') || (typeof value === 'string' && value.trim().endsWith('%')); +} + +/** A % length as a 0-1 fraction. */ +export function percentFraction(value: any): number { + return typeof value === 'string' ? parseFloat(value) / 100 : value.value; +} + +const percentAxes_ = Symbol('percentAxes'); + +/** + * Hands a % width/height to a parent that lays out its children itself (MasonKit), so it resolves + * against the containing block rather than the canvas being sized to its surface. A size that + * stops being a % clears it again. + */ +export function setParentPercentSize(view: any, horizontal: boolean, value: any) { + const axis = horizontal ? 1 : 2; + const axes = view[percentAxes_] ?? 0; + if (isPercentLength(value)) { + if (view.parent?._setChildPercentSize?.(view, horizontal, percentFraction(value))) { + view[percentAxes_] = axes | axis; + } + } else if (axes & axis) { + view.parent?._setChildPercentSize?.(view, horizontal, null); + view[percentAxes_] = axes & ~axis; + } +} + +let behind: Uint32Array | null | undefined; + +/** The count of threaded canvases behind, read straight from native memory: this runs every frame. */ +function canvasesBehind(): Uint32Array | null { + if (behind === undefined) { + const buffer = (global as any).CanvasModule?.__canvasesBehind; + behind = buffer instanceof ArrayBuffer ? new Uint32Array(buffer) : null; + } + return behind; +} + +/** + * Holds requestAnimationFrame callbacks back a frame while a threaded canvas is behind (it has a + * frame waiting behind one that hasn't reached the screen), as a browser does when its compositor + * falls behind. The UI thread then stays free between the frames the GPU can take, instead of + * queueing more work for it every vsync. + * + * Installed with the first threaded context, over whatever requestAnimationFrame is global by then + * (core's, or a polyfill's). + */ +export function holdBackAnimationFramesWhileBehind() { + const target = global as any; + const request = target.requestAnimationFrame; + const cancel = target.cancelAnimationFrame; + if (typeof request !== 'function' || request.__holdsBack) { + return; + } + const count = canvasesBehind(); + // An older native library: leave requestAnimationFrame alone. + if (!count) { + return; + } + // Our ids stay put while a held-back callback is re-requested under a new one. + const pending = new Map(); + let nextId = 1; + const requestAnimationFrame = (callback: (time: number) => void) => { + const id = nextId++; + const run = (time: number) => { + if (count[0] > 0) { + pending.set(id, request(run)); + return; + } + pending.delete(id); + callback(time); + }; + pending.set(id, request(run)); + return id; + }; + requestAnimationFrame.__holdsBack = true; + const cancelAnimationFrame = (id: number) => { + const current = pending.get(id); + if (current !== undefined) { + pending.delete(id); + cancel?.(current); + } + }; + target.requestAnimationFrame = requestAnimationFrame; + target.cancelAnimationFrame = cancelAnimationFrame; + if (target.window && target.window !== target && target.window.requestAnimationFrame === request) { + target.window.requestAnimationFrame = requestAnimationFrame; + target.window.cancelAnimationFrame = cancelAnimationFrame; + } +} diff --git a/packages/canvas/platforms/ios/src/cpp/CanvasJSIModule.cpp b/packages/canvas/platforms/ios/src/cpp/CanvasJSIModule.cpp index bd45f0b9f..6e62c4562 100644 --- a/packages/canvas/platforms/ios/src/cpp/CanvasJSIModule.cpp +++ b/packages/canvas/platforms/ios/src/cpp/CanvasJSIModule.cpp @@ -149,6 +149,16 @@ void CanvasJSIModule::install(v8::Isolate *isolate) { GPUSupportedLimitsImpl::Init(canvasMod, isolate); GPUDeviceImpl::Init(canvasMod, isolate); GPUQueueImpl::Init(canvasMod, isolate); + + // The count of canvases behind (canvas_native_canvases_behind), as memory JS reads every + // frame without a call. The counter is static, so nothing frees it. + { + auto store = v8::ArrayBuffer::NewBackingStore( + (void *) canvas_native_canvases_behind_address(), sizeof(uint32_t), + [](void *, size_t, void *) {}, nullptr); + canvasMod->Set(context, ConvertToV8String(isolate, "__canvasesBehind"), + v8::ArrayBuffer::New(isolate, std::move(store))).FromJust(); + } v8Global->Set(context, ConvertToV8String(isolate, "CanvasModule"), canvasMod).FromJust(); canvasMod->Set(context, ConvertToV8String(isolate, "create2DContext"), diff --git a/packages/canvas/src-native/canvas-android/canvas/src/main/cpp/include/canvas_native.h b/packages/canvas/src-native/canvas-android/canvas/src/main/cpp/include/canvas_native.h index 38b344517..6f801742f 100644 --- a/packages/canvas/src-native/canvas-android/canvas/src/main/cpp/include/canvas_native.h +++ b/packages/canvas/src-native/canvas-android/canvas/src/main/cpp/include/canvas_native.h @@ -860,6 +860,9 @@ typedef struct WEBGL_lose_context WEBGL_lose_context; typedef struct WebGLActiveInfo WebGLActiveInfo; +/** + * `.1`: its context is threaded, so the typed extension's calls go to the WebGL thread too. + */ typedef struct WebGLExtension WebGLExtension; typedef struct WebGLFramebufferAttachmentParameter WebGLFramebufferAttachmentParameter; @@ -870,6 +873,10 @@ typedef struct WebGLResult WebGLResult; typedef struct WebGLShaderPrecisionFormat WebGLShaderPrecisionFormat; +/** + * A WebGL context. A threaded one is built, used and dropped on the WebGL thread (`thread`), and + * its inner state is only ever touched there: calls reach it through `post` and `sync`. + */ typedef struct WebGLState WebGLState; typedef struct WebGLSync WebGLSync; @@ -2127,6 +2134,72 @@ void canvas_native_context_resize(struct CanvasRenderingContext2D *context, float width, float height); +/** + * A 2D context on the shared Direct3D 12 device (Windows). Offscreen until + * `canvas_native_context_attach_swap_chain_panel`. Null when there is no usable device. + */ +struct CanvasRenderingContext2D *canvas_native_context_create_d3d(float width, + float height, + float density, + bool alpha, + int32_t font_color, + float ppi, + uint32_t direction, + enum CanvasColorSpace color_space); + +/** + * `canvas_native_context_create_d3d`, rasterized and presented on the shared render thread's + * Direct3D 12 device; the context returned only records. Null when that thread has no usable + * device. + */ +struct CanvasRenderingContext2D *canvas_native_context_create_d3d_threaded(float width, + float height, + float density, + bool alpha, + int32_t font_color, + float ppi, + uint32_t direction, + enum CanvasColorSpace color_space); + +/** + * Presents a D3D context in a WinUI `SwapChainPanel` (`panel`: any COM pointer to it). UI thread. + */ +bool canvas_native_context_attach_swap_chain_panel(struct CanvasRenderingContext2D *context, + void *panel); + +/** + * Presents a D3D context into a XAML `SurfaceImageSource` (any COM pointer to it, made at the + * context's size) instead of a swapchain, so it blends with the page. UI thread. + */ +bool canvas_native_context_attach_xaml_surface(struct CanvasRenderingContext2D *context, + void *source); + +/** + * Maps the context's swapchain into its panel: DIPs = pixels * scale + offset. + */ +bool canvas_native_context_set_swap_chain_transform(struct CanvasRenderingContext2D *context, + float scale_x, + float scale_y, + float offset_x, + float offset_y); + +/** + * The context's Direct3D 12 device was removed; it draws nothing until restored. + */ +bool canvas_native_context_is_lost(const struct CanvasRenderingContext2D *context); + +/** + * Moves a lost context to a new device, cleared and in its default state, shown in `panel` + * again (null offscreen). UI thread. + */ +bool canvas_native_context_restore_d3d(struct CanvasRenderingContext2D *context, void *panel); + +/** + * Removes this thread's and the render thread's shared Direct3D 12 devices, as a driver reset + * would (tests). + */ +bool canvas_native_d3d_simulate_device_removal(void); + struct CanvasRenderingContext2D *canvas_native_context_create(float width, float height, float density, @@ -2807,6 +2880,25 @@ const char *canvas_native_to_data_url(struct CanvasRenderingContext2D *context, const char *format, uint32_t quality); +/** + * Draws a video frame another device shares (canvas-media's `gpuFrame()`: a + * `CanvasD3DSharedFrame`) on the context's device, without a readback; threaded contexts draw it + * on the render thread's. `false` when it cannot (another adapter, not a D3D context), and the + * frame is then not consumed: the caller draws it some other way. + */ +bool canvas_native_context_draw_d3d_shared_frame(struct CanvasRenderingContext2D *context, + void *frame, + int32_t width, + int32_t height, + float sx, + float sy, + float sw, + float sh, + float dx, + float dy, + float dw, + float dh); + void canvas_native_image_filter_reference(const struct ImageFilter *value); void canvas_native_image_filter_release(const struct ImageFilter *value); @@ -3324,6 +3416,8 @@ void canvas_native_webgpu_buffer_map_async(const struct CanvasGPUBuffer *buffer, void (*callback)(enum CanvasGPUErrorType, char*, void*), void *callback_data); +void canvas_native_webgpu_context_detach_surface(const struct CanvasGPUCanvasContext *context); + char *canvas_native_webgpu_to_data_url_with_fallback(const struct CanvasGPUCanvasContext *context, const char *format, float quality); @@ -3358,6 +3452,31 @@ const struct CanvasGPUCanvasContext *canvas_native_webgpu_context_create(const s uint32_t height); #endif +/** + * Windows: a context presenting in a WinUI `SwapChainPanel` (any COM pointer to it). UI thread. + */ +const struct CanvasGPUCanvasContext *canvas_native_webgpu_context_create_swap_chain_panel(const struct CanvasWebGPUInstance *instance, + void *panel, + uint32_t width, + uint32_t height); + +/** + * Windows: maps the swapchain into its panel (DIPs = pixels * scale + offset). + */ +bool canvas_native_webgpu_context_set_swap_chain_transform(const struct CanvasGPUCanvasContext *context, + float scale_x, + float scale_y, + float offset_x, + float offset_y); + +/** + * Windows: a new drawing-buffer size. The surface is reconfigured in place (its swapchain is + * resized), keeping the configuration the page chose. + */ +void canvas_native_webgpu_context_resize_swap_chain_panel(const struct CanvasGPUCanvasContext *context, + uint32_t width, + uint32_t height); + #if (defined(TARGET_OS_IOS) || defined(TARGET_OS_VISION)) const struct CanvasGPUCanvasContext *canvas_native_webgpu_context_create_uiview(const struct CanvasWebGPUInstance *instance, void *view, @@ -3986,6 +4105,11 @@ uint64_t canvas_native_webgpu_compilation_message_get_offset(struct CanvasGPUCom uint64_t canvas_native_webgpu_compilation_message_get_length(struct CanvasGPUCompilationMessage *message); +/** + * Videos share frames only with devices on their adapter. 0 if unknown. + */ +uint64_t canvas_native_webgpu_device_get_adapter_luid(const struct CanvasGPUDevice *device); + struct CanvasGPUSupportedLimits *canvas_native_webgpu_create_limits(void); void canvas_native_webgpu_limits_release(struct CanvasGPUSupportedLimits *limits); @@ -4119,6 +4243,13 @@ bool canvas_native_image_asset_load_from_fd(const struct ImageAsset *asset, int bool canvas_native_image_asset_load_from_path(const struct ImageAsset *asset, const char *path); +/** + * Encodes the image to `path`; `format` 0 JPG, 1 PNG (`ImageAssetSaveFormat`). + */ +bool canvas_native_image_asset_save_path(const struct ImageAsset *asset, + const char *path, + uint32_t format); + bool canvas_native_image_asset_load_from_raw(const struct ImageAsset *asset, uint32_t width, uint32_t height, @@ -4425,7 +4556,7 @@ struct WebGLState *canvas_native_webgl_create(void *view, bool xr_compatible); #endif -#if !defined(TARGET_OS_ANDROID) +#if (defined(TARGET_OS_IOS) || defined(TARGET_OS_MACOS) || defined(TARGET_OS_VISION)) struct WebGLState *canvas_native_webgl_create(void *view, int32_t version, bool alpha, @@ -4455,6 +4586,56 @@ struct WebGLState *canvas_native_webgl_create_no_window(int32_t width, bool xr_compatible, bool is_canvas); +/** + * Windows: a WebGL context whose drawing buffer can be shown in a `SwapChainPanel` + * (`canvas_native_webgl_attach_swap_chain_panel`). Null when ANGLE is unavailable. + */ +struct WebGLState *canvas_native_webgl_create_d3d(int32_t width, + int32_t height, + int32_t version, + bool alpha, + bool antialias, + bool depth, + bool fail_if_major_performance_caveat, + int32_t power_preference, + bool premultiplied_alpha, + bool preserve_drawing_buffer, + bool stencil, + bool desynchronized, + bool xr_compatible); + +/** + * Windows: shows a `canvas_native_webgl_create_d3d` context in a `SwapChainPanel` (any COM + * pointer to it). UI thread. + */ +bool canvas_native_webgl_attach_swap_chain_panel(struct WebGLState *state, void *panel); + +/** + * Windows: presents a `canvas_native_webgl_create_d3d` context into a XAML `SurfaceImageSource` + * (any COM pointer to it, made at the drawing buffer's size) instead of a swapchain, so it blends + * with the page. The rows are bottom-up: the host flips the image. UI thread. + */ +bool canvas_native_webgl_attach_xaml_surface(struct WebGLState *state, void *source); + +/** + * Windows: maps the drawing buffer into its panel (DIPs = pixels * scale + offset). + */ +bool canvas_native_webgl_set_swap_chain_transform(struct WebGLState *state, + float scale_x, + float scale_y, + float offset_x, + float offset_y); + +/** + * Windows: resizes (and clears) a `canvas_native_webgl_create_d3d` drawing buffer. + */ +bool canvas_native_webgl_resize_d3d(struct WebGLState *state, int32_t width, int32_t height); + +/** + * Ends a frame: presents it where the context is on screen (Windows panels), else flushes. + */ +bool canvas_native_webgl_present(struct WebGLState *state); + void canvas_native_webgl_active_texture(uint32_t texture, struct WebGLState *state); void canvas_native_webgl_attach_shader(uint32_t program, uint32_t shader, struct WebGLState *state); @@ -4833,7 +5014,7 @@ struct WebGLResult *canvas_native_webgl_get_vertex_attrib(uint32_t index, uint32_t pname, struct WebGLState *state); -bool canvas_native_webgl_get_is_context_lost(struct WebGLState*); +bool canvas_native_webgl_get_is_context_lost(struct WebGLState *state); void canvas_native_webgl_hint(uint32_t target, uint32_t mode, struct WebGLState *state); @@ -5875,4 +6056,15 @@ void canvas_native_webgl2_tex_image2d_image_data(int32_t target, const struct ImageData *image_data, struct WebGLState *state); +/** + * How many threaded canvases are behind. The JS side holds requestAnimationFrame back while any + * are, as a browser does when its compositor falls behind, rather than queue more work. + */ +uint32_t canvas_native_canvases_behind(void); + +/** + * Where that count lives, for the JS side to read as memory every frame instead of calling in. + */ +const uint32_t *canvas_native_canvases_behind_address(void); + #endif /* CANVAS_C_H */ diff --git a/packages/canvas/src-native/canvas-android/canvas/src/main/java/org/nativescript/canvas/NSCCanvas.kt b/packages/canvas/src-native/canvas-android/canvas/src/main/java/org/nativescript/canvas/NSCCanvas.kt index 3edb136a7..a2191eb23 100644 --- a/packages/canvas/src-native/canvas-android/canvas/src/main/java/org/nativescript/canvas/NSCCanvas.kt +++ b/packages/canvas/src-native/canvas-android/canvas/src/main/java/org/nativescript/canvas/NSCCanvas.kt @@ -589,7 +589,8 @@ class NSCCanvas : FrameLayout { stencil, desynchronized, xrCompatible, - version + version, + threadedWebGL ) engine = Engine.GL } @@ -649,7 +650,8 @@ class NSCCanvas : FrameLayout { stencil, desynchronized, xrCompatible, - version + version, + threadedWebGL ) engine = Engine.GL } @@ -697,7 +699,8 @@ class NSCCanvas : FrameLayout { stencil, desynchronized, xrCompatible, - version + version, + threadedWebGL ) engine = Engine.GL } @@ -710,6 +713,9 @@ class NSCCanvas : FrameLayout { /** Read when the 2D context is created. */ var threaded2D = false + /** Read when a WebGL context is created: it then lives on, and is drawn from, the WebGL thread. */ + var threadedWebGL = false + private fun create2DNative( width: Int, height: Int, @@ -1253,8 +1259,8 @@ class NSCCanvas : FrameLayout { @FastNative external fun nativeDetach2DSurface(context: Long) + // Not @FastNative: a threaded context waits for the WebGL thread to build it. @JvmStatic - @FastNative external fun nativeInitWebGL( surface: Surface?, alpha: Boolean, @@ -1267,11 +1273,11 @@ class NSCCanvas : FrameLayout { stencil: Boolean, desynchronized: Boolean, xrCompatible: Boolean, - version: Int + version: Int, + threaded: Boolean ): Long @JvmStatic - @FastNative external fun nativeInitWebGLNoSurface( width: Int, height: Int, @@ -1285,7 +1291,8 @@ class NSCCanvas : FrameLayout { stencil: Boolean, desynchronized: Boolean, xrCompatible: Boolean, - version: Int + version: Int, + threaded: Boolean ): Long @JvmStatic diff --git a/packages/canvas/src-native/canvas-android/canvas/src/main/java/org/nativescript/canvas/Utils.kt b/packages/canvas/src-native/canvas-android/canvas/src/main/java/org/nativescript/canvas/Utils.kt index 2e02808f9..d63744ef0 100644 --- a/packages/canvas/src-native/canvas-android/canvas/src/main/java/org/nativescript/canvas/Utils.kt +++ b/packages/canvas/src-native/canvas-android/canvas/src/main/java/org/nativescript/canvas/Utils.kt @@ -40,6 +40,21 @@ object Utils { @JvmStatic private external fun nativeMakeStateContextCurrent(state: Long): Boolean + @JvmStatic + private external fun nativeRunWithWebGL(state: Long, block: Runnable) + + /** + * Runs [block] with the WebGL context [state] current, on the thread that owns it, and returns + * its result: a threaded context can only be current on the WebGL thread, so GLES and + * SurfaceTexture calls against it have to run there. + */ + private fun withWebGL(state: Long, block: () -> T): T { + var result: Any? = null + nativeRunWithWebGL(state) { result = block() } + @Suppress("UNCHECKED_CAST") + return result as T + } + @JvmStatic private external fun nativeMake2DContextCurrent(context: Long): Boolean @@ -186,11 +201,10 @@ object Utils { @JvmStatic - fun createSurfaceTexture(state: Long): Array { - nativeMakeStateContextCurrent(state) + fun createSurfaceTexture(state: Long): Array = withWebGL(state) { val render = TextureRender() render.surfaceCreated() - return arrayOf(SurfaceTexture(render.textureId), render) + arrayOf(SurfaceTexture(render.textureId), render) } @@ -258,12 +272,11 @@ object Utils { fun createRenderAndAttachToGLContext( state: Long, texture: SurfaceTexture, - ): TextureRender { - nativeMakeStateContextCurrent(state) + ): TextureRender = withWebGL(state) { val render = TextureRender() render.surfaceCreated() texture.attachToGLContext(render.textureId) - return render + render } @@ -272,14 +285,12 @@ object Utils { state: Long, texture: SurfaceTexture, render: TextureRender - ) { - nativeMakeStateContextCurrent(state) + ) = withWebGL(state) { texture.attachToGLContext(render.textureId) } @JvmStatic - fun detachFromGLContext(state: Long, texture: SurfaceTexture) { - nativeMakeStateContextCurrent(state) + fun detachFromGLContext(state: Long, texture: SurfaceTexture) = withWebGL(state) { texture.detachFromGLContext() } @@ -293,8 +304,7 @@ object Utils { height: Int, internalFormat: Int, format: Int - ) { - nativeMakeStateContextCurrent(state) + ) = withWebGL(state) { render.drawFrame(texture, width, height, internalFormat, format, flipY) if (render.width != width || render.height != width) { @@ -319,8 +329,7 @@ object Utils { depth: Int, border: Int, zoffset: Int, - ) { - nativeMakeStateContextCurrent(state) + ) = withWebGL(state) { render.drawFrameTexImage3D( texture, target, level, internalformat, width, height, depth, border, zoffset, flipY @@ -340,8 +349,7 @@ object Utils { zoffset: Int, width: Int, height: Int, - ) { - nativeMakeStateContextCurrent(state) + ) = withWebGL(state) { render.drawFrameTexSubImage3D( texture, target, level, xoffset, yoffset, zoffset, width, height, flipY ) diff --git a/packages/canvas/src-native/canvas-ios/CanvasNative/include/canvas_native.h b/packages/canvas/src-native/canvas-ios/CanvasNative/include/canvas_native.h index 0c5ed6288..6f801742f 100644 --- a/packages/canvas/src-native/canvas-ios/CanvasNative/include/canvas_native.h +++ b/packages/canvas/src-native/canvas-ios/CanvasNative/include/canvas_native.h @@ -860,6 +860,9 @@ typedef struct WEBGL_lose_context WEBGL_lose_context; typedef struct WebGLActiveInfo WebGLActiveInfo; +/** + * `.1`: its context is threaded, so the typed extension's calls go to the WebGL thread too. + */ typedef struct WebGLExtension WebGLExtension; typedef struct WebGLFramebufferAttachmentParameter WebGLFramebufferAttachmentParameter; @@ -870,6 +873,10 @@ typedef struct WebGLResult WebGLResult; typedef struct WebGLShaderPrecisionFormat WebGLShaderPrecisionFormat; +/** + * A WebGL context. A threaded one is built, used and dropped on the WebGL thread (`thread`), and + * its inner state is only ever touched there: calls reach it through `post` and `sync`. + */ typedef struct WebGLState WebGLState; typedef struct WebGLSync WebGLSync; @@ -6049,4 +6056,15 @@ void canvas_native_webgl2_tex_image2d_image_data(int32_t target, const struct ImageData *image_data, struct WebGLState *state); +/** + * How many threaded canvases are behind. The JS side holds requestAnimationFrame back while any + * are, as a browser does when its compositor falls behind, rather than queue more work. + */ +uint32_t canvas_native_canvases_behind(void); + +/** + * Where that count lives, for the JS side to read as memory every frame instead of calling in. + */ +const uint32_t *canvas_native_canvases_behind_address(void); + #endif /* CANVAS_C_H */ diff --git a/packages/canvas/typings/android.d.ts b/packages/canvas/typings/android.d.ts index 9817cc26f..32840ce0d 100644 --- a/packages/canvas/typings/android.d.ts +++ b/packages/canvas/typings/android.d.ts @@ -207,6 +207,8 @@ declare module org { public static TAG: string = 'CanvasView'; public getThreaded2D(): boolean; public setThreaded2D(value: boolean): void; + public getThreadedWebGL(): boolean; + public setThreadedWebGL(value: boolean): void; public create2DContext(alpha: boolean, antialias: boolean, depth: boolean, failIfMajorPerformanceCaveat: boolean, powerPreference: number, premultipliedAlpha: boolean, preserveDrawingBuffer: boolean, stencil: boolean, desynchronized: boolean, xrCompatible: boolean, willReadFrequently: boolean, colorSpace: number): number; public makeContextCurrent(): void; public setSurfaceView(value: org.nativescript.canvas.GLViewSV): void;