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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 64 additions & 1 deletion crates/canvas-2d/src/context/surface_vulkan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,53 @@ impl Context {
}
}

fn offscreen_vulkan_surface(&mut self, width: i32, height: i32, alpha: bool) -> Option<skia_safe::Surface> {
let info = skia_safe::ImageInfo::new(
skia_safe::ISize::new(width.max(1), height.max(1)),
ColorType::N32,
if alpha { skia_safe::AlphaType::Premul } else { skia_safe::AlphaType::Opaque },
<ColorSpace as Into<Option<skia_safe::ColorSpace>>>::into(self.surface_data.color_space),
);
gpu::surfaces::render_target(
self.direct_context.as_mut()?,
gpu::Budgeted::Yes,
&info,
None,
gpu::SurfaceOrigin::TopLeft,
None,
false,
None,
)
}

pub fn detach_vulkan_view(&mut self) {
if self.vulkan_context.is_none() {
return;
}
let bounds = self.surface_data.bounds;
let alpha = !self.surface_data.is_opaque;
let snapshot = self.surface.image_snapshot();
let Some(mut surface) =
self.offscreen_vulkan_surface(bounds.width() as i32, bounds.height() as i32, alpha)
else {
return;
};
let matrix = self.surface.canvas().local_to_device();
let canvas = surface.canvas();
canvas.draw_image(&snapshot, (0., 0.), None);
for _ in 0..self.state_stack.len() {
canvas.save();
}
canvas.set_matrix(&matrix);
self.surface = surface;
self.vulkan_texture = None;
// The snapshot draw still reads the swapchain image.
self.flush_submit_and_sync_cpu();
if let Some(vulkan_context) = self.vulkan_context.as_mut() {
vulkan_context.clear_view();
}
}

pub fn resize_vulkan(context: &mut Context, width: f32, height: f32, alpha: bool) {
// flush any pending draws before resizing
context.flush_and_render_to_surface();
Expand All @@ -199,11 +246,27 @@ impl Context {

let color_space = context.surface_data.color_space;

let Some(image) = image else {
let Some(surface) = context.offscreen_vulkan_surface(width as i32, height as i32, alpha)
else {
return;
};
context.surface_data.state = Default::default();
context.surface_data.is_opaque = !alpha;
context.surface_data.bounds = skia_safe::Rect::from_wh(width, height);
context.surface_state = SurfaceState::None;
context.surface = surface;
context.vulkan_texture = None;
context.path = Path::default();
context.reset_state();
return;
};

if let Some(direct_context) = context.direct_context.as_mut() {
let alloc = gpu::vk::Alloc::default();
let image_info = unsafe {
gpu::vk::ImageInfo::new(
image.unwrap() as gpu::vk::Image,
image as gpu::vk::Image,
alloc,
gpu::vk::ImageTiling::OPTIMAL,
gpu::vk::ImageLayout::UNDEFINED,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,57 @@ pub extern "system" fn nativeReleaseWebGPU(_: JNIEnv, _: JClass, context: jlong)
}
}

#[no_mangle]
pub extern "system" fn nativeDetachWebGPUSurface(_: JNIEnv, _: JClass, context: jlong) {
if context == 0 {
return;
}

unsafe {
canvas_c::webgpu::gpu_canvas_context::canvas_native_webgpu_context_detach_surface(
context as _,
);
}
}

#[no_mangle]
pub extern "system" fn nativeDetach2DSurface(_: JNIEnv, _: JClass, context: jlong) {
if context == 0 {
return;
}
let context = unsafe { &mut *(context as *mut canvas_c::CanvasRenderingContext2D) };
let context = context.get_context_mut();

if context.vulkan_context.is_some() {
context.detach_vulkan_view();
return;
}

let color_space = context.surface_data().color_space();
let alpha = !context.surface_data().is_opaque();
let width = context.surface_data().width() as i32;
let height = context.surface_data().height() as i32;
context.flush_and_render_to_surface();
if let Some(gl_context) = context.gl_context.as_mut() {
let mut attr = canvas_core::context_attributes::ContextAttributes::new(
alpha,
false,
false,
false,
PowerPreference::Default,
true,
false,
false,
false,
true,
false,
color_space,
);
gl_context.resize_pbuffer(&mut attr, width, height);
gl_context.make_current();
}
}

// #[cfg(feature = "vulkan")]
#[no_mangle]
pub extern "system" fn nativeCreate2dContextVulkan(
Expand Down Expand Up @@ -404,7 +455,6 @@ pub extern "system" fn nativeUpdate2DSurface(
context.make_current();
}

#[cfg(feature = "vulkan")]
if let Some(vulkan_context) = context.vulkan_context.as_mut() {
vulkan_context.set_view(
window.ptr().as_ptr() as *mut std::os::raw::c_void,
Expand Down
10 changes: 9 additions & 1 deletion crates/canvas-android/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use log::LevelFilter;
// #[cfg(feature = "vulkan")]
use crate::jni_compat::org_nativescript_canvas_NSCCanvas::{nativeCreate2dContextVulkan, nativeGetVulkanVersion, nativeContext2DSetRenderFunc, nativeContext2DClearRenderFunc};

use crate::jni_compat::org_nativescript_canvas_NSCCanvas::{nativeContext2DPathTest, nativeContext2DPathTestNormal, nativeContext2DRender, nativeContext2DTest, nativeContext2DTestNormal, nativeCreate2DContext, nativeCustomWithBitmapFlush, nativeInitWebGL, nativeInitWebGLNoSurface, nativeInitWebGPU, nativeMakeWebGLCurrent, nativeMakeWebGLCurrentNormal, nativeRelease2DContext, nativeRelease2DContextNormal, nativeReleaseWebGL, nativeReleaseWebGLNormal, nativeReleaseWebGPU, nativeResizeWebGPU, nativeUpdate2DSurface, nativeUpdate2DSurfaceNoSurface, nativeUpdate2DSurfaceNoSurfaceNormal, nativeUpdateGLNoSurface, nativeUpdateWebGLNoSurfaceNormal, nativeUpdateWebGLSurface, nativeWebGLC2DRender, nativeWriteCurrentWebGLContextToBitmap, nativeContext2DConicTest};
use crate::jni_compat::org_nativescript_canvas_NSCCanvas::{nativeContext2DPathTest, nativeContext2DPathTestNormal, nativeContext2DRender, nativeContext2DTest, nativeContext2DTestNormal, nativeCreate2DContext, nativeCustomWithBitmapFlush, nativeInitWebGL, nativeInitWebGLNoSurface, nativeInitWebGPU, nativeMakeWebGLCurrent, nativeMakeWebGLCurrentNormal, nativeRelease2DContext, nativeRelease2DContextNormal, nativeReleaseWebGL, nativeReleaseWebGLNormal, nativeReleaseWebGPU, nativeDetachWebGPUSurface, nativeDetach2DSurface, nativeResizeWebGPU, nativeUpdate2DSurface, nativeUpdate2DSurfaceNoSurface, nativeUpdate2DSurfaceNoSurfaceNormal, nativeUpdateGLNoSurface, nativeUpdateWebGLNoSurfaceNormal, nativeUpdateWebGLSurface, nativeWebGLC2DRender, nativeWriteCurrentWebGLContextToBitmap, nativeContext2DConicTest};
use crate::jni_compat::org_nativescript_canvas_NSCCanvasRenderingContext2D::{nativeCreatePattern, nativeDrawAtlasWithBitmap, nativeDrawImageDxDyDwDhWithAsset, nativeDrawImageDxDyDwDhWithBitmap, nativeDrawImageDxDyWithAsset, nativeDrawImageDxDyWithBitmap, nativeDrawImageWithAsset, nativeDrawImageWithBitmap, nativeScale};
use crate::jni_compat::org_nativescript_canvas_NSCImageAsset::{nativeCreateImageAsset, nativeDestroyImageAsset, nativeGetDimensions, nativeGetError, nativeLoadFromBitmap, nativeLoadFromBuffer, nativeLoadFromBytes, nativeLoadFromEncodedBuffer, nativeLoadFromEncodedBytes, nativeLoadFromPath, nativeLoadFromUrl};
use crate::jni_compat::org_nativescript_canvas_NSCImageBitmap::{nativeLoadBitmapFromBuffer, nativeLoadBitmapFromBufferOptions, nativeLoadBitmapFromBufferRectOptions, nativeLoadBitmapFromBytes, nativeLoadBitmapFromBytesOptions, nativeLoadBitmapFromBytesRectOptions};
Expand Down Expand Up @@ -105,6 +105,8 @@ pub extern "system" fn JNI_OnLoad(vm: JavaVM, _reserved: *const c_void) -> jint
// }
canvas_method_names.push("nativeContext2DSetRenderFunc");
canvas_method_names.push("nativeContext2DClearRenderFunc");
canvas_method_names.push("nativeDetachWebGPUSurface");
canvas_method_names.push("nativeDetach2DSurface");

let canvas_signatures = if ret >= ANDROID_O {
let mut ret = vec![
Expand Down Expand Up @@ -139,6 +141,8 @@ pub extern "system" fn JNI_OnLoad(vm: JavaVM, _reserved: *const c_void) -> jint

ret.push("(JLjava/lang/Object;)V");
ret.push("(J)V");
ret.push("(J)V");
ret.push("(J)V");

ret
} else {
Expand Down Expand Up @@ -174,6 +178,8 @@ pub extern "system" fn JNI_OnLoad(vm: JavaVM, _reserved: *const c_void) -> jint

ret.push("!(JLjava/lang/Object;)V");
ret.push("!(J)V");
ret.push("!(J)V");
ret.push("!(J)V");
ret
};

Expand Down Expand Up @@ -238,6 +244,8 @@ pub extern "system" fn JNI_OnLoad(vm: JavaVM, _reserved: *const c_void) -> jint

canvas_methods.push(nativeContext2DSetRenderFunc as *mut c_void);
canvas_methods.push(nativeContext2DClearRenderFunc as *mut c_void);
canvas_methods.push(nativeDetachWebGPUSurface as *mut c_void);
canvas_methods.push(nativeDetach2DSurface as *mut c_void);

let canvas_native_methods: Vec<NativeMethod> =
izip!(canvas_method_names, canvas_signatures, canvas_methods)
Expand Down
3 changes: 1 addition & 2 deletions crates/canvas-android/src/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,7 @@ pub extern "system" fn nativeDestroyContext(context: jlong) {
return;
}

let context = context as *mut canvas_c::CanvasRenderingContext2D;
let _ = Box::from_raw(context);
canvas_c::canvas_native_context_release(context as *mut canvas_c::CanvasRenderingContext2D);
}
}

Expand Down
22 changes: 21 additions & 1 deletion crates/canvas-c/src/c2d/context.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::cmp::PartialEq;
use std::ffi::{CStr, CString};
use std::os::raw::{c_char, c_void};
use std::sync::atomic::{AtomicUsize, Ordering};

use canvas_2d::context::compositing::composite_operation_type::CompositeOperationType;
use canvas_2d::context::fill_and_stroke_styles::paint::paint_style_set_color_with_string;
Expand Down Expand Up @@ -42,6 +43,7 @@ pub struct CanvasRenderingContext2D {
pub(crate) context: Context,
alpha: bool,
engine: Engine,
refs: AtomicUsize,
}

impl CanvasRenderingContext2D {
Expand Down Expand Up @@ -78,12 +80,22 @@ pub extern "C" fn canvas_native_context_clear_render_func(value: i64) {
context.context.cpu_context = None;
}

#[no_mangle]
pub extern "C" fn canvas_native_context_reference(value: *const CanvasRenderingContext2D) {
if value.is_null() {
return;
}
unsafe { &*value }.refs.fetch_add(1, Ordering::Relaxed);
}

#[no_mangle]
pub extern "C" fn canvas_native_context_release(value: *mut CanvasRenderingContext2D) {
if value.is_null() {
return;
}
unsafe { drop(Box::from_raw(value)) };
if unsafe { &*value }.refs.fetch_sub(1, Ordering::AcqRel) == 1 {
unsafe { drop(Box::from_raw(value)) };
}
}

fn to_data_url(context: &mut CanvasRenderingContext2D, format: &str, quality: u32) -> String {
Expand Down Expand Up @@ -180,6 +192,7 @@ impl CanvasRenderingContext2D {
context,
alpha,
engine: Engine::CPU,
refs: AtomicUsize::new(1),
}
}

Expand All @@ -189,6 +202,7 @@ impl CanvasRenderingContext2D {
context,
alpha,
engine: Engine::GL,
refs: AtomicUsize::new(1),
}
}

Expand All @@ -198,6 +212,7 @@ impl CanvasRenderingContext2D {
context,
alpha,
engine: Engine::Vulkan,
refs: AtomicUsize::new(1),
}
}

Expand All @@ -207,6 +222,7 @@ impl CanvasRenderingContext2D {
context,
alpha,
engine: Engine::Metal,
refs: AtomicUsize::new(1),
}
}

Expand Down Expand Up @@ -427,6 +443,7 @@ pub extern "C" fn canvas_native_context_create_d3d(
context,
alpha,
engine: Engine::D3D,
refs: AtomicUsize::new(1),
}));
// Boxed: it stays at this address until released.
unsafe { (*context).context.register_d3d() };
Expand Down Expand Up @@ -541,6 +558,7 @@ pub extern "C" fn canvas_native_context_create(
),
alpha,
engine: Engine::CPU,
refs: AtomicUsize::new(1),
}))
}

Expand Down Expand Up @@ -574,6 +592,7 @@ pub extern "C" fn canvas_native_context_create_gl(
context,
alpha,
engine: Engine::GL,
refs: AtomicUsize::new(1),
}))
}

Expand Down Expand Up @@ -618,6 +637,7 @@ pub extern "C" fn canvas_native_context_create_gl_no_window(
context,
alpha,
engine: Engine::GL,
refs: AtomicUsize::new(1),
}))
}

Expand Down
Loading
Loading