Skip to content

fix(canvas): Android 2D presents nothing after a resize - #166

Merged
triniwiz merged 1 commit into
masterfrom
fix/android-2d-window-fbo
Sep 29, 2026
Merged

triniwiz merged 1 commit into
masterfrom
fix/android-2d-window-fbo

Conversation

@triniwiz

Copy link
Copy Markdown
Member

Since #165, every 2D canvas on Android stays blank once it has been resized, which is all of them after they are sized to their layout. This happens with the render thread on or off (Canvas.threaded2D = false).

Cause. On Android, 2D now draws into an offscreen Skia render target and copies it to the window when it presents. resize_gl (canvas-c) chose the window's framebuffer by reading GL_FRAMEBUFFER_BINDING right after flushing Skia. At that point the binding is Skia's offscreen framebuffer, not the window's (0). So the re-created window surface wrapped the offscreen framebuffer, and every present copied it onto itself. On-device logging showed bindings of 2, 3 and 10–12 at each resize.

Changes

  • crates/canvas-2d/src/context/surface_gl.rs: new Context::window_framebuffer(), which returns the framebuffer the existing window surface wraps, read from its backend render target.
  • crates/canvas-c/src/c2d/context.rs: resize_gl uses that framebuffer when 2D presents through a window. It still reads the GL binding otherwise (pbuffers, other platforms), so their behaviour is unchanged.

Testing

Android, Galaxy A53: in the starter app, the home hero, flow field, clock and live chart canvases all render, with the default threaded path and with threaded2D = false. Before the change they were black (pure 0,0,0, the empty surface).

Not tested: iOS and Windows are not affected by the offscreen path. Binaries under platforms/ are not rebuilt in this PR.

resize_gl read GL_FRAMEBUFFER_BINDING after a Skia flush to find the window's framebuffer. Since
2D on Android draws into an offscreen target (#165), that binding is Skia's offscreen framebuffer,
so the re-created "window" surface wrapped the offscreen and every present copied it onto itself.
Any canvas that was resized (all of them, once sized to their layout) stayed blank, threaded or not.

Take the framebuffer from the existing window surface instead; fall back to the binding when 2D
does not present through a window.
@coderabbitai

coderabbitai Bot commented Sep 29, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: e79d3ed4-c53e-416a-9d8a-150c5d923e45

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@triniwiz
triniwiz merged commit e97b31d into master Sep 29, 2026
12 of 21 checks passed
@triniwiz
triniwiz deleted the fix/android-2d-window-fbo branch September 29, 2026 23:58
triniwiz added a commit that referenced this pull request Sep 30, 2026
canvas-release.aar and CanvasNative.xcframework, canvassvg-release.aar and CanvasSVG.xcframework,
rebuilt from 3d465fb with the steps of build-native.yml, for #166, #167, #169, #170 and #171.
The two headers the builds regenerate catch up with declarations already in the source.

Windows modules are not rebuilt: canvasnative.node and canvassvg.node still predate these changes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant