Hey folks, I’ve been exploring how to integrate na...
# compose
s
Hey folks, I’ve been exploring how to integrate native renderer output into Compose Multiplatform. For example: an app rendering some content with Metal or Vulkan, then displaying that output inside Compose. For context, I maintain MapLibre Compose. Today the map is integrated to Compose through native interop views:
AndroidView
,
UIKitView
,
SwingPanel
, and
WebElementView
. That works, but it has compositor/input limitations: Compose modifiers don’t reliably apply to the native view (alpha, scale, rotation, clipping, etc.), desktop/web have layering constraints for Compose UI over the native content, and input behavior can get awkward. The quirks are tolerable on Android and iOS, but a dealbreaker on desktop and web. The path I’d like is: render native content into a GPU texture, then sample that texture directly from a Compose/Skiko Canvas. That would make the native rendering a normal part of the Compose scene, so
graphicsLayer
transforms and clipping work with full fidelity.
The hard part is texture sharing. The options seem to be: 1. CPU readback every frame: render native content, read the texture back to CPU memory, create a Skiko Image, then draw it. This is expensive and adds latency/stutter. 2. GPU texture sharing: create/import the texture in the same GPU context Compose/Skiko is using, then sample it directly without leaving GPU memory. This is the path I want for smooth interactive rendering. I prototyped option 2 on Compose Desktop + Metal (warning: ai slop). As far as I can tell, there isn’t currently a public API to access the live GPU context/device backing the Compose scene. But with a tiny bit of reflection into Skiko internals, it works! Native Metal renders into a
MTLTexture
, Skia samples that texture, and Compose applies
graphicsLayer
transforms normally. No
SwingPanel
interop involved.
Questions: 1. Has anyone else explored this path? 2. Is there an existing public way to integrate with Skiko’s live GPU context/device that I missed? 3. Any existing discussions / YouTrack tickets? 4. Would there be appetite for exposing this in Skiko behind an experimental API if I put together a PR? This would be useful beyond maps too: video, video calls, games, custom native renderers, streaming surfaces, etc.
🙌 4
🙌🏻 1
r
You don't have to go through
AndroidView
on Android, you can do the same thing you did here for Metal (render into a
Surface
backed by a hardware bitmap and just draw that as a regular
Bitmap
)
s
Yup, we have a path on Android I'm more wondering about Compose Multiplatform (this prototype is desktop macOS)
r
(you can also use a
TexureView
via
AndroidView
or the Compose wrapper)
👍 2
Anyway, the main thing you'd want to do to make your hack a reality is take an approach similar to what Android did with
Surface
, external textures, etc. and make sure the APIs are not backend-specific
s
Makes sense. I'd have to dig in to how the Surface API is designed internally (I've used it, but am not deeply familiar) to see how to adapt that design to multiplatform. Also unsure if my reflection hack can port to Kotlin Native, JS, and Web targets (but I'm hoping I can upstream it properly instead of shipping a hack on all targets)
k
I'd be happy to take a look on it. But in two weeks (vacation 😆 )
s
cool, enjoy your vacation! in the meantime I'll try to polish up my prototype a bit + explore what's needed on windows/linux/ios/web
k
@Ivan Matkov could maybe provide a bit of useful context here as well
i
in 🧑‍🚒 mode with 1.11 release now, will look at it in detail later in short - yes, there were similar investigations to provide proper interop out of the box yes, we're ok to open some API in skiko without compatibility guarantees
🙌 2
s
Two updates: • I fleshed out my proof of concept above into an example MapLibre Native integration, using the same reflection hack, for all three desktop OSs and render backends. So there's sample code there for Metal, EGL, WGL, and Vulkan maps rendering to a texture shared with a Compose host on macOS/Metal, Windows/Direct3D, and Linux/EGL. ◦ the full example project demoing maps in composethe file containing the reflection into skiko • I built my own Compose Desktop host that exposes gpu context so I don't need reflection, shared herethe RenderContext api I haven't looked at the best way to expose it in Compose/Skiko itself yet; is this something y'all have time to look at?
👍 1
i
Hey. Sorry for silence from my side. yes and no. Yes, I have a prototype of exposing it. It naturally fits into another thing that's required to be changed around that part of code. But it turned out that it became too large refactor for one shot, so I'll need to figure out how to split it. But no - It's not something that I'm actively working on. However I strive to finalize it in some reasonable time to avoid situation where all my changes are stale/outdated
s
Thanks for the update! Is there a YouTrack ticket I can follow or subscribe to?
i
I've done such experiment as part of CMP-9758 to extract vsync clock out of
SkiaLayer
. I probably need to create some subtasks to reflect actual state 😬 Can I ask you to file skiko issue with your use case to properly track it as external request? I'll link it to related work after that
👍 1
s
Yeah, will do
thank you color 1
I ended up using the reflection technique for https://kotlinlang.slack.com/archives/C0BJ0GTE2/p1786165745846429 for now Separately, I discovered an upcoming skiko release will have the ability to import an external WebGL texture, no reflection hacks required! Prototype using that with maplibre and compose here; I intend to use it for MapLibre Compose if I can get the runtime/threading story sorted out with workers on the browser. still, looking forward to a real api so I can banish the reflection on desktop!