@@ -289,31 +289,26 @@ class JsiSkImage : public JsiSkWrappingSkPtrHostObject<SkImage> {
289289 std::move (image)) {
290290 // Get the dispatcher for the current thread
291291 _dispatcher = Dispatcher::getDispatcher ();
292- // Process any pending operations
292+ // Process any pending operations (e.g. deletions of previous resources)
293293 _dispatcher->processQueue ();
294294 }
295295
296- protected:
297- void releaseResources () override {
298- // Queue deletion on the creation thread if needed
299- auto image = getObjectUnchecked ();
300- if (image && _dispatcher) {
301- _dispatcher->run ([image]() {
302- // Image will be deleted when this lambda is destroyed
303- });
304- }
305- // Clear the object
306- JsiSkWrappingSkPtrHostObject<SkImage>::releaseResources ();
307- }
308-
309296public:
310297 ~JsiSkImage () override {
311- // If already disposed, resources were already cleaned up
312- if (isDisposed ()) {
313- return ;
298+ if (!isDisposed ()) {
299+ // This JSI Object is being deleted from a GC, which might happen
300+ // on a separate Thread. GPU resources (like SkImage) must be deleted
301+ // on the same Thread they were created on, so in this case we schedule
302+ // deletion to run on the Thread this Object was created on.
303+ auto image = getObjectUnchecked ();
304+ if (image && _dispatcher) {
305+ _dispatcher->run ([image]() {
306+ // Image will be deleted when this lambda is destroyed, on the
307+ // original Thread.
308+ });
309+ }
310+ releaseResources ();
314311 }
315- // Use the same cleanup path as dispose()
316- releaseResources ();
317312 }
318313
319314 size_t getMemoryPressure () const override {
0 commit comments