feat(android): let a transparent canvas opt into a topmost SurfaceView - #457
Open
AlirezaHadjar wants to merge 1 commit into
Open
feat(android): let a transparent canvas opt into a topmost SurfaceView#457AlirezaHadjar wants to merge 1 commit into
AlirezaHadjar wants to merge 1 commit into
Conversation
A transparent canvas renders through a TextureView, so HWUI samples the whole canvas into the app window before SurfaceFlinger composes it. For a full-screen canvas that animates every vsync that second pass dominates. androidTransparencyMode="surface-overlay" puts the canvas on its own translucent SurfaceFlinger layer instead. The tradeoff is z-order: the layer sits above the app window, so no React Native view can draw over it. That is why it is opt-in and "texture" stays the default.
AlirezaHadjar
force-pushed
the
android/transparent-surfaceview
branch
from
August 27, 2026 15:59
b109de0 to
8c4ab49
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The problem
A transparent canvas renders through a
TextureView, so every frame takes this path:SurfaceTexture.Step 2 exists only to get the canvas into the app window, and it forces a window swap on every WebGPU present. On a full-screen canvas animating every vsync it dominates the frame, and it gets worse with canvas area and refresh rate even when the simulation is entirely GPU-resident.
Numbers
Same release build, same animation, same 60 Hz Android emulator, profiled with Perfetto. Only the presentation path changed:
TextureViewSurfaceViewQueuePresentKHRcadenceThe patched build also shows the canvas as its own
SurfaceView(BLAST)layer in SurfaceFlinger, so this was confirmed at the composition layer, not read off an FPS counter.This came out of a confetti library that draws a full-screen transparent canvas over app content. 45 FPS with a third of frames blowing the 20 ms budget is the difference between the effect looking smooth and looking cheap.
Why the surface has to be topmost
A plain
SurfaceViewsits behind the app window, and Android punches a hole in the window so it shows through. Right for opaque video, camera or game surfaces. It cannot do a transparent overlay. In a controlled test, dropping onlysetZOrderOnTop(true)moved the layer fromz=1toz=-2, the canvas region went black, and the React Native content underneath vanished into the hole. Putting it back returned the layer toz=1and transparency worked again.For a transparent canvas there are two workable configurations,
TextureViewor translucent-and-on-top. That's why this adds one value instead of a general view-type selector. A "plain transparent SurfaceView" mode would just be broken.The API
"texture" | "surface-overlay", default"texture", ignored whentransparentis false. Opaque canvases keep their plainSurfaceView.Default behavior is unchanged. With the prop absent, or set to
"texture",WebGPUViewbuilds aWebGPUTextureViewexactly as it does today.Verification
New example screen under Diagnostics, "Android Transparency Mode": a 50% red canvas over a blue backdrop with a yellow overlay view on top. On an API 36 arm64 emulator:
TextureView"texture"TextureView"surface-overlay"SurfaceView, z-order on topThe overlay turning orange is the z-order proof. The canvas layer is compositing over a view that sits above it in the React Native tree.
Related: #142 (introduced TextureView for transparency and noted the slower animation), #168, #170.