Skip to content

Commit d84618b

Browse files
authored
fix(tvos): defer Metal drawable acquisition until drawing (#146)
1 parent 2bc5637 commit d84618b

3 files changed

Lines changed: 32 additions & 3 deletions

File tree

‎crates/canvas-2d/src/context/mod.rs‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,11 +341,23 @@ impl Context {
341341
self.surface_data.scale
342342
}
343343

344+
// Acquiring the next drawable during presentation can block the display-link
345+
// callback on tvOS. Keep the previous surface until the next operation needs
346+
// to draw, then retain its contents when swapping the backing texture.
347+
#[inline]
348+
fn ensure_metal_drawable(&mut self) {
349+
#[cfg(all(feature = "metal", target_os = "tvos"))]
350+
if self.metal_context.as_ref().is_some_and(|c| !c.has_current_drawable()) {
351+
Self::acquire_drawable(self);
352+
}
353+
}
354+
344355
#[inline]
345356
pub fn with_canvas<F>(&mut self, f: F)
346357
where
347358
F: FnOnce(&skia_safe::Canvas),
348359
{
360+
self.ensure_metal_drawable();
349361
f(self.surface.canvas());
350362
}
351363

@@ -354,6 +366,7 @@ impl Context {
354366
where
355367
F: FnOnce(&skia_safe::Canvas, &mut Path),
356368
{
369+
self.ensure_metal_drawable();
357370
f(self.surface.canvas(), &mut self.path);
358371
self.surface_state = self.surface_state | SurfaceState::Pending;
359372
}
@@ -363,6 +376,7 @@ impl Context {
363376
where
364377
F: FnOnce(&skia_safe::Canvas),
365378
{
379+
self.ensure_metal_drawable();
366380
f(self.surface.canvas());
367381
self.surface_state = self.surface_state | SurfaceState::Pending;
368382
}
@@ -372,6 +386,7 @@ impl Context {
372386
where
373387
F: FnOnce(&skia_safe::Canvas, &Paint),
374388
{
389+
self.ensure_metal_drawable();
375390
f(self.surface.canvas(), &self.state.paint);
376391
self.surface_state = self.surface_state | SurfaceState::Pending;
377392
}
@@ -388,6 +403,7 @@ impl Context {
388403
where
389404
F: FnOnce(&skia_safe::Canvas),
390405
{
406+
self.ensure_metal_drawable();
391407
f(self.surface.canvas());
392408
self.surface_state = self.surface_state | SurfaceState::Pending;
393409
}
@@ -545,6 +561,7 @@ impl Context {
545561
where
546562
F: Fn(&skia_safe::Canvas, &skia_safe::Paint, &mut Path),
547563
{
564+
self.ensure_metal_drawable();
548565
let blend = self.state.global_composite_operation.get_blend_mode();
549566
// Fast path: most draw calls use SrcOver (the default)
550567
if !matches!(
@@ -606,6 +623,7 @@ impl Context {
606623
where
607624
F: Fn(&skia_safe::Canvas, &skia_safe::Paint),
608625
{
626+
self.ensure_metal_drawable();
609627
let blend = self.state.global_composite_operation.get_blend_mode();
610628
// Fast path: most draw calls use SrcOver (the default)
611629
if !matches!(
@@ -663,6 +681,7 @@ impl Context {
663681
where
664682
F: Fn(&skia_safe::Canvas, &skia_safe::Paint, &Font),
665683
{
684+
self.ensure_metal_drawable();
666685
let blend = self.state.global_composite_operation.get_blend_mode();
667686
if !matches!(
668687
blend,

‎crates/canvas-2d/src/context/surface_metal.rs‎

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -349,13 +349,21 @@ impl Context {
349349

350350
pub fn present(context: &mut Context) {
351351
let _ = MetalContext::new_release_pool();
352-
let mut info: Option<TextureInfo> = None;
353-
let mut width = 0;
354-
let mut height = 0;
352+
355353
if let Some(context) = context.metal_context.as_mut() {
356354
context.present_drawable();
357355
}
358356

357+
#[cfg(not(target_os = "tvos"))]
358+
Self::acquire_drawable(context);
359+
}
360+
361+
pub(crate) fn acquire_drawable(context: &mut Context) {
362+
#[cfg(target_os = "tvos")]
363+
let _pool = MetalContext::new_release_pool();
364+
let mut info: Option<TextureInfo> = None;
365+
let mut width = 0;
366+
let mut height = 0;
359367
if let Some(context) = context.metal_context.as_mut() {
360368
if let Some(drawable) = context.next_drawable() {
361369
let texture = drawable.texture();

‎crates/canvas-core/src/gpu/metal.rs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,8 @@ impl MetalContext {
276276
}
277277
}
278278

279+
pub fn has_current_drawable(&self) -> bool { self.current_drawable.is_some() }
280+
279281
pub fn current_drawable(&mut self) -> Option<&Retained<ProtocolObject<dyn CAMetalDrawable>>> {
280282
if self.current_drawable.is_none() {
281283
self.current_drawable = unsafe {

0 commit comments

Comments
 (0)