Repository navigation
fix(🤖): load react-native-skia's library before creating the Dawn instance - #584
Closed
wcandillon wants to merge 2 commits into
Closed
wcandillon wants to merge 2 commits into
wcandillon wants to merge 2 commits into
Conversation
System.loadLibrary loads librnskia.so with RTLD_LOCAL, so dlsym(RTLD_DEFAULT, "rnskia_getWGPUInstance") never finds it and react-native-webgpu creates its own instance. Look the getter up in librnskia.so with RTLD_NOLOAD when the global lookup fails. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tance createInstance() adopts Skia's Dawn instance so that work on a device imported with importDevice(Skia.getNativeDevice()) settles. With #582 it finds librnskia.so by name, but only once that library is loaded, which react-native-skia does when JS imports it: whether the instance was shared depended on which package the app imports first. WebGPUModule now loads librnskia.so before its own library when it is there, so the lookup no longer depends on the import order. iOS needs nothing of the kind: dlsym(RTLD_DEFAULT) searches every image in the process. SkiaSharedInstance.spec.ts checks the contract end to end on Android: mapAsync on the imported device settles. It skips on iOS until the example app picks up a react-native-skia release with wcandillon/react-native-skia#4306.
This was referenced Oct 23, 2026
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.
Stacked on #582: this branch contains its commit, and the diff shrinks to this change once it merges. It completes the Android half of adopting react-native-skia's Dawn instance (#581).
Problem
createInstance()runs when the native module installs, which is when JS importsreact-native-webgpu. With #582 it findslibrnskia.soby name, but only if that library is already loaded, and react-native-skia loads it when JS importsreact-native-skia. So whether the two packages share an instance depends on which import comes first in the app's bundle. The example app has the order backwards (App.tsximports the Tests screen before the MNIST screen, the only one importing Skia), and nothing documents the requirement.Fix
WebGPUModule's static initializer loadslibrnskia.sobefore this package's own library, inside atryblock:System.loadLibraryis a no-op when the library is already loaded, Skia's own later call is a no-op in turn, and an app without react-native-skia has no such library and gets theUnsatisfiedLinkErrorthe block ignores. From then on the lookup increateInstance()does not depend on the import order.iOS needs nothing of the kind:
dlsym(RTLD_DEFAULT)searches every Mach-O image in the process, so the symbol is found whenever it is present in the binary (wcandillon/react-native-skia#4306 covers that part).Test
SkiaSharedInstance.spec.tsis the end-to-end check of the contract: it imports Skia's device withimportDevice(Skia.getNativeDevice()), copies 16 bytes through it and racesmapAsyncagainst a 3 s timeout. With a second instancemapAsyncnever settles. The harness (Tests.tsx) exposesSkia.getNativeDeviceto the on-device eval, since the pointer cannot cross the eval boundary.The spec runs on Android only until the example app picks up a react-native-skia release with wcandillon/react-native-skia#4306; before it the getter is missing from the iOS binary for an unrelated reason.
Test plan
Locally, on an Android API 35 emulator (arm64, SwiftShader Vulkan, the adapter Skia selects there), Debug build of the example app with react-native-skia 3.7.0:
SkiaSharedInstance.spec.tsmapAsyncsettleslibrnskia.so, thenlibreact-native-webgpu.solibreact-native-webgpu.so, thenlibrnskia.soSix unrelated suites (Buffer, Device, GPU, ComputeShader, ArrayBuffer, ABuffer: 54 tests) pass on the same build. CI's
build-test-androidjob runs the new spec on its emulator; the iOS job skips it.