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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ members = [
"crates/playground",
"crates/canvas-c",
"crates/canvas-svg",
"crates/canvas-svg-c",
"crates/canvas-napi",
"crates/canvas-svg-ios",
"crates/canvas-svg-android",
Expand Down Expand Up @@ -72,9 +73,11 @@ canvas-2d = { path = "./crates/canvas-2d" }
canvas-core = { path = "./crates/canvas-core" }
canvas-webgl = { path = "./crates/canvas-webgl" }
canvas-svg = { path = "./crates/canvas-svg" }
canvas-svg-c = { path = "./crates/canvas-svg-c" }
gl-bindings = { path = "./crates/gl-bindings" }
canvas-c = { path = "./crates/canvas-c" }
skia-safe = { git = "https://github.com/triniwiz/rust-skia", rev = "1eafe30", features = ["textlayout"] }
quick-xml = "0.34"
skia-safe = { git = "https://github.com/triniwiz/rust-skia", rev = "b9d29071cd8876b2447d58a14346b9fe6a5d21e2", features = ["textlayout"] }
itertools = "0.14.0"
ustr = "1.1.0"
wgpu-core = { git = "https://github.com/triniwiz/wgpu", rev = "e5c0aa02", features = ["wgsl"] }
Expand Down
27 changes: 14 additions & 13 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ svg: GENERATE_IOS_SVG GENERATE_VISIONOS_SVG GENERATE_TVOS_SVG

android-svg: GENERATE_ANDROID_SVG

apple: ios visionos tvos

# Host-side tests. The workspace pins `-C panic=abort` for the Apple host
# targets in .cargo/config.toml (needed by the macOS dylib build) and libtest
# cannot link against that, so the rustflags are replaced for this run.
Expand All @@ -47,28 +49,28 @@ GENERATE_V8_HEADERS:
GENERATE_ANDROID_V8_STUB:
./tools/scripts/build-android-v8-stub.sh

# Match Xcode's pre-build env: cargo tracks SDKROOT and the deployment targets, so a mismatch
# rebuilds the whole tree (std too) on every switch. tvOS also needs it because cc has no default.
apple_sdk = $(if $(findstring visionos-sim,$1),xrsimulator,$(if $(findstring visionos,$1),xros,$(if $(findstring tvos-sim,$1),appletvsimulator,$(if $(findstring tvos,$1),appletvos,$(if $(or $(findstring ios-sim,$1),$(findstring x86_64-apple-ios,$1)),iphonesimulator,iphoneos)))))
apple_env = SDKROOT="$$(xcrun --sdk $(call apple_sdk,$1) --show-sdk-path)" IPHONEOS_DEPLOYMENT_TARGET=12.0 TVOS_DEPLOYMENT_TARGET=12.0 XROS_DEPLOYMENT_TARGET=1.0

.PHONY: $(ARCHS_IOS)
$(ARCHS_IOS): %:
RUSTFLAGS="-Zlocation-detail=none -Zunstable-options -Cpanic=immediate-abort" \
$(call apple_env,$@) RUSTFLAGS="-Zlocation-detail=none -Zunstable-options -Cpanic=immediate-abort" \
cargo +nightly build -Z build-std='std,panic_abort' \
--target $@ --release -p canvas-ios

$(XCFRAMEWORK): $(ARCHS_IOS)

.PHONY: $(ARCHS_VISIONOS)
$(ARCHS_VISIONOS): %:
RUSTFLAGS="-Zlocation-detail=none -Zunstable-options -Cpanic=immediate-abort" \
$(call apple_env,$@) RUSTFLAGS="-Zlocation-detail=none -Zunstable-options -Cpanic=immediate-abort" \
cargo +nightly build -Z build-std='std,panic_abort' \
--target $@ --release -p canvas-ios

# TVOS_DEPLOYMENT_TARGET must be set explicitly: rustc defaults to 12.0 but the
# `cc` crate has no built-in tvOS default and falls back to the SDK version, so
# ring's C/asm objects come out tagged minos 26.4 and the framework link (12.0)
# warns on every one of them. iOS/visionOS need no equivalent -- cc knows those.
.PHONY: $(ARCHS_TVOS)
$(ARCHS_TVOS): %:
TVOS_DEPLOYMENT_TARGET=12.0 \
RUSTFLAGS="-Zlocation-detail=none -Zunstable-options -Cpanic=immediate-abort" \
$(call apple_env,$@) RUSTFLAGS="-Zlocation-detail=none -Zunstable-options -Cpanic=immediate-abort" \
cargo +nightly build -Z build-std='std,panic_abort' \
--target $@ --release -p canvas-ios

Expand All @@ -81,7 +83,7 @@ GENERATE_ANDROID: $(ARCHS_ANDROID)

.PHONY: $(addsuffix _svg,$(ARCHS_IOS))
$(addsuffix _svg,$(ARCHS_IOS)): %_svg:
RUSTFLAGS="-Zlocation-detail=none -Zunstable-options -Cpanic=immediate-abort" \
$(call apple_env,$*) RUSTFLAGS="-Zlocation-detail=none -Zunstable-options -Cpanic=immediate-abort" \
cargo +nightly build -Z build-std='std,panic_abort' \
--target $* --release -p canvas-svg-ios

Expand All @@ -90,7 +92,7 @@ GENERATE_IOS_SVG: $(addsuffix _svg,$(ARCHS_IOS))

.PHONY: $(addsuffix _svg,$(ARCHS_VISIONOS))
$(addsuffix _svg,$(ARCHS_VISIONOS)): %_svg:
RUSTFLAGS="-Zlocation-detail=none -Zunstable-options -Cpanic=immediate-abort" \
$(call apple_env,$*) RUSTFLAGS="-Zlocation-detail=none -Zunstable-options -Cpanic=immediate-abort" \
cargo +nightly build -Z build-std='std,panic_abort' \
--target $* --release -p canvas-svg-ios

Expand All @@ -99,8 +101,7 @@ GENERATE_VISIONOS_SVG: $(addsuffix _svg,$(ARCHS_VISIONOS))

.PHONY: $(addsuffix _svg,$(ARCHS_TVOS))
$(addsuffix _svg,$(ARCHS_TVOS)): %_svg:
TVOS_DEPLOYMENT_TARGET=12.0 \
RUSTFLAGS="-Zlocation-detail=none -Zunstable-options -Cpanic=immediate-abort" \
$(call apple_env,$*) RUSTFLAGS="-Zlocation-detail=none -Zunstable-options -Cpanic=immediate-abort" \
cargo +nightly build -Z build-std='std,panic_abort' \
--target $* --release -p canvas-svg-ios

Expand All @@ -111,7 +112,7 @@ GENERATE_TVOS_SVG: $(addsuffix _svg,$(ARCHS_TVOS))

.PHONY: $(addsuffix _svg,$(ARCHS_ANDROID))
$(addsuffix _svg,$(ARCHS_ANDROID)): %_svg:
./tools/scripts/build-svg-android.sh $* svg
./tools/scripts/build-svg-android.sh $*

.PHONY: GENERATE_ANDROID_SVG
GENERATE_ANDROID_SVG: $(addsuffix _svg,$(ARCHS_ANDROID))
Expand Down
1 change: 1 addition & 0 deletions apps/demo/src/assets/file-assets/svg/rocket.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion apps/demo/src/plugin-demos/canvas-svg.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<ActionBar title="canvas-svg" icon="" class="action-bar">
</ActionBar>
</Page.actionBar>
<GridLayout columns="*,*" rows="*,*" loaded="{{ viewLoaded }}">
<GridLayout columns="*,*" rows="*,*,*,*,*" loaded="{{ viewLoaded }}">
<!-- <ui:Svg id="1" width="100%" height="100%" src="{{src1}}" loaded="{{svgViewLoaded}}"/> -->
<!--<ui:Svg id="2" col="1" width="100%" height="100%" src="{{src2}}" loaded="{{svgViewLoaded}}"/>
<ui:Svg id="3" row="1" width="100%" height="100%" src="{{src3}}" loaded="{{svgViewLoaded}}"/>
Expand Down
2 changes: 2 additions & 0 deletions crates/canvas-2d/src/context/drawing_images/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ use crate::context::Context;

impl Context {
#[cfg(feature = "2d")]
/// Uploads now, so it must bind first or the texture lands in another canvas's GL context.
fn promote_to_gpu(&mut self, img: Image) -> Image {
self.ensure_current();
if let Some(ctx) = self.direct_context.as_mut() {
img.new_texture_image(ctx, skia_safe::gpu::Mipmapped::No)
.unwrap_or(img)
Expand Down
24 changes: 15 additions & 9 deletions crates/canvas-2d/src/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,13 @@ impl Context {
// callback on tvOS. Keep the previous surface until the next operation needs
// to draw, then retain its contents when swapping the backing texture.
#[inline]
fn ensure_metal_drawable(&mut self) {
/// Runs before every draw. Skia uploads a raster image the moment a draw records it (a pattern
/// fill, say), so another canvas's GL context being current puts the texture in the wrong one.
pub(crate) fn ensure_current(&mut self) {
#[cfg(feature = "gl")]
if let Some(ref context) = self.gl_context {
context.make_current();
}
#[cfg(all(feature = "metal", target_os = "tvos"))]
if self.metal_context.as_ref().is_some_and(|c| !c.has_current_drawable()) {
Self::acquire_drawable(self);
Expand All @@ -368,7 +374,7 @@ impl Context {
where
F: FnOnce(&skia_safe::Canvas),
{
self.ensure_metal_drawable();
self.ensure_current();
f(self.surface.canvas());
}

Expand All @@ -377,7 +383,7 @@ impl Context {
where
F: FnOnce(&skia_safe::Canvas, &mut Path),
{
self.ensure_metal_drawable();
self.ensure_current();
f(self.surface.canvas(), &mut self.path);
self.surface_state = self.surface_state | SurfaceState::Pending;
}
Expand All @@ -387,7 +393,7 @@ impl Context {
where
F: FnOnce(&skia_safe::Canvas),
{
self.ensure_metal_drawable();
self.ensure_current();
f(self.surface.canvas());
self.surface_state = self.surface_state | SurfaceState::Pending;
}
Expand All @@ -397,7 +403,7 @@ impl Context {
where
F: FnOnce(&skia_safe::Canvas, &Paint),
{
self.ensure_metal_drawable();
self.ensure_current();
f(self.surface.canvas(), &self.state.paint);
self.surface_state = self.surface_state | SurfaceState::Pending;
}
Expand All @@ -414,7 +420,7 @@ impl Context {
where
F: FnOnce(&skia_safe::Canvas),
{
self.ensure_metal_drawable();
self.ensure_current();
f(self.surface.canvas());
self.surface_state = self.surface_state | SurfaceState::Pending;
}
Expand Down Expand Up @@ -572,7 +578,7 @@ impl Context {
where
F: Fn(&skia_safe::Canvas, &skia_safe::Paint, &mut Path),
{
self.ensure_metal_drawable();
self.ensure_current();
let blend = self.state.global_composite_operation.get_blend_mode();
// Fast path: most draw calls use SrcOver (the default)
if !matches!(
Expand Down Expand Up @@ -634,7 +640,7 @@ impl Context {
where
F: Fn(&skia_safe::Canvas, &skia_safe::Paint),
{
self.ensure_metal_drawable();
self.ensure_current();
let blend = self.state.global_composite_operation.get_blend_mode();
// Fast path: most draw calls use SrcOver (the default)
if !matches!(
Expand Down Expand Up @@ -692,7 +698,7 @@ impl Context {
where
F: Fn(&skia_safe::Canvas, &skia_safe::Paint),
{
self.ensure_metal_drawable();
self.ensure_current();
let blend = self.state.global_composite_operation.get_blend_mode();
if !matches!(
blend,
Expand Down
21 changes: 14 additions & 7 deletions crates/canvas-2d/src/context/surface_gl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,13 +192,18 @@ impl Context {

surfaces::raster(&info, None, None)
} else {
let interface = Interface::new_native();
let ctx = gpu::direct_contexts::make_gl(interface.unwrap(), None);
if ctx.is_none() {
return;
}
let mut ctx = ctx.unwrap();
// ctx.reset(None);
// Reuse the Skia context: the EGL context is unchanged, and a second Skia context on it
// would free GL names the first may still hold images for.
let mut ctx = match context.direct_context.take() {
Some(mut ctx) => {
ctx.reset(None);
ctx
}
None => match Interface::new_native().and_then(|i| gpu::direct_contexts::make_gl(i, None)) {
Some(ctx) => ctx,
None => return,
},
};

let mut frame_buffer = gpu::gl::FramebufferInfo::from_fboid(buffer_id as u32);

Expand Down Expand Up @@ -249,6 +254,8 @@ impl Context {
context.path = Path::default();
context.reset_state();
context.surface = surface;
} else if context.direct_context.is_none() {
context.direct_context = direct_context;
}
}
}
16 changes: 4 additions & 12 deletions crates/canvas-core/src/gpu/metal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ use std::os::raw::c_void;

#[derive(Debug)]
pub struct MetalTexture {
pool: Retained<NSAutoreleasePool>,
texture: Retained<ProtocolObject<dyn MTLTexture>>,
}

Expand All @@ -34,10 +33,7 @@ impl MetalTexture {
let obj = texture as *mut AnyObject;

match Retained::retain(obj.cast()) {
Some(texture) => Some(Self {
texture,
pool: NSAutoreleasePool::new(),
}),
Some(texture) => Some(Self { texture }),
None => None,
}
}
Expand All @@ -51,7 +47,6 @@ impl MetalTexture {
pub struct MetalContext {
queue: Retained<ProtocolObject<dyn MTLCommandQueue>>,
device: Retained<ProtocolObject<dyn MTLDevice>>,
pool: Retained<NSAutoreleasePool>,
layer: Retained<CAMetalLayer>,
view: Option<Retained<NSObject>>,
current_drawable: Option<Retained<ProtocolObject<dyn CAMetalDrawable>>>,
Expand All @@ -67,7 +62,7 @@ impl MetalContext {
self.is_offscreen
}
pub fn new(view: *mut c_void) -> Self {
let pool = unsafe { NSAutoreleasePool::new() };
let _pool = unsafe { NSAutoreleasePool::new() };
let device = MTLCreateSystemDefaultDevice().expect("no Metal device");
let queue = device.newCommandQueue().unwrap();
let view = unsafe { Retained::from_raw(view as _).unwrap() };
Expand Down Expand Up @@ -105,7 +100,6 @@ impl MetalContext {
Self {
queue,
device,
pool,
layer,
view: Some(view),
current_drawable,
Expand All @@ -114,7 +108,7 @@ impl MetalContext {
}

pub fn new_offscreen(width: f32, height: f32) -> Self {
let pool = unsafe { NSAutoreleasePool::new() };
let _pool = unsafe { NSAutoreleasePool::new() };
let device = MTLCreateSystemDefaultDevice().expect("no Metal device");
let queue = device.newCommandQueue().unwrap();
let layer = CAMetalLayer::new();
Expand All @@ -135,7 +129,6 @@ impl MetalContext {
Self {
queue,
device,
pool,
layer,
view: None,
current_drawable,
Expand All @@ -148,7 +141,7 @@ impl MetalContext {
device: *mut c_void,
queue: *mut c_void,
) -> Self {
let pool = NSAutoreleasePool::new();
let _pool = NSAutoreleasePool::new();
let device: Retained<ProtocolObject<dyn MTLDevice>> =
Retained::retain((device as *mut AnyObject).cast()).unwrap();
// view is non null
Expand All @@ -161,7 +154,6 @@ impl MetalContext {
Self {
queue,
device,
pool,
layer,
view: Some(view),
current_drawable,
Expand Down
Loading
Loading