diff --git a/apps/example/ios/Podfile.lock b/apps/example/ios/Podfile.lock index 7a048fa41..1931bcb69 100644 --- a/apps/example/ios/Podfile.lock +++ b/apps/example/ios/Podfile.lock @@ -1865,7 +1865,7 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - react-native-wgpu (0.5.0): + - react-native-wgpu (0.5.2): - boost - DoubleConversion - fast_float @@ -2903,81 +2903,81 @@ SPEC CHECKSUMS: fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd glog: 5683914934d5b6e4240e497e0f4a3b42d1854183 hermes-engine: 35c763d57c9832d0eef764316ca1c4d043581394 - RCT-Folly: 846fda9475e61ec7bcbf8a3fe81edfcaeb090669 + RCT-Folly: 59ec0ac1f2f39672a0c6e6cecdd39383b764646f RCTDeprecation: c0ed3249a97243002615517dff789bf4666cf585 RCTRequired: 58719f5124f9267b5f9649c08bf23d9aea845b23 RCTTypeSafety: 4aefa8328ab1f86da273f08517f1f6b343f6c2cc React: 2073376f47c71b7e9a0af7535986a77522ce1049 React-callinvoker: 751b6f2c83347a0486391c3f266f291f0f53b27e - React-Core: dff5d29973349b11dd6631c9498456d75f846d5e - React-CoreModules: c0ae04452e4c5d30e06f8e94692a49107657f537 - React-cxxreact: 376fd672c95dfb64ad5cc246e6a1e9edb78dec4c + React-Core: 7195661f0b48e7ea46c3360ccb575288a20c932c + React-CoreModules: 14f0054ab46000dd3b816d6528af3bd600d82073 + React-cxxreact: 7f602425c63096c398dac13cd7a300efd7c281ae React-debug: 7b56a0a7da432353287d2eedac727903e35278f5 - React-defaultsnativemodule: 393b81aaa6211408f50a6ef00a277847256dd881 - React-domnativemodule: 5fb5829baa7a7a0f217019cbad1eb226d94f7062 - React-Fabric: a17c4ae35503673b57b91c2d1388429e7cbee452 - React-FabricComponents: a76572ddeba78ebe4ec58615291e9db4a55cd46a - React-FabricImage: d806eb2695d7ef355ec28d1a21f5a14ac26b1cae - React-featureflags: 1690ec3c453920b6308e23a4e24eb9c3632f9c75 - React-featureflagsnativemodule: 7b7e8483fc671c5a33aefd699b7c7a3c0bdfdfec - React-graphics: ea146ee799dc816524a3a0922fc7be0b5a52dcc1 - React-hermes: fcbdc45ecf38259fe3b12642bd0757c52270a107 - React-idlecallbacksnativemodule: a353f9162eaa7ad787e68aba9f52a1cfa8154098 - React-ImageManager: ec5cf55ce9cc81719eb5f1f51d23d04db851c86c - React-jserrorhandler: 594c593f3d60f527be081e2cace7710c2bd9f524 - React-jsi: 59ec3190dd364cca86a58869e7755477d2468948 - React-jsiexecutor: b87d78a2e8dd7a6f56e9cdac038da45de98c944f - React-jsinspector: b9204adf1af622c98e78af96ec1bca615c2ce2bd - React-jsinspectorcdp: 4a356fa69e412d35d3a38c44d4a6cc555c5931e8 - React-jsinspectornetwork: 7820056773178f321cbf18689e1ffcd38276a878 - React-jsinspectortracing: b341c5ef6e031a33e0bd462d67fd397e8e9cd612 - React-jsitooling: 401655e05cb966b0081225c5201d90734a567cb9 - React-jsitracing: 67eff6dea0cb58a1e7bd8b49243012d88c0f511e - React-logger: a3cb5b29c32b8e447b5a96919340e89334062b48 - React-Mapbuffer: 9d2434a42701d6144ca18f0ca1c4507808ca7696 - React-microtasksnativemodule: 75b6604b667d297292345302cc5bfb6b6aeccc1b - react-native-safe-area-context: c00143b4823773bba23f2f19f85663ae89ceb460 - react-native-skia: 5bf2b2107cd7f2d806fd364f5e16b1c7554ed3cd - react-native-wgpu: e54fcee5946cc2cee4814f63f425be358f097b14 - React-NativeModulesApple: 879fbdc5dcff7136abceb7880fe8a2022a1bd7c3 + React-defaultsnativemodule: 695d8a0b40f735edb3c4031e0f049e567fdac47a + React-domnativemodule: 6d66c1f61f277d008d98cae650ce2c025b89d3b9 + React-Fabric: 997d4115d688f483cb409a1290171bff3c93dab4 + React-FabricComponents: 8167e5e363ca3a3fe394d8afee355e4072bea1db + React-FabricImage: f8f9f2c97657116702acc670e3f4357bc842bed3 + React-featureflags: dfb4d0d527d55dd968231370f6832b9197ee653d + React-featureflagsnativemodule: c63cfd8fe95cd98f12ebb37daa919c4544810a45 + React-graphics: fd795f1c2a1133a08dde31725b20949edd545dca + React-hermes: 0a167bbb02c242664745e82154578c64e90a88e5 + React-idlecallbacksnativemodule: 1798c6aa33ddc7c2e9fa3c3d67729728639889e9 + React-ImageManager: c498ee6945dffacc82bfa175aa3264212f27c70b + React-jserrorhandler: 216951fea62fc26c600f4c96f0dc4fd53d1e7a9b + React-jsi: 9c27d27d3007b73c702ad3fd5a6166557c741020 + React-jsiexecutor: 2b24f4ed4026344a27f717bf947a434cbbeeff7a + React-jsinspector: 02394b059c48805780f7d977366317a24168d00e + React-jsinspectorcdp: f4b6d5c5c9db05ef44d082716714f90cfeed96bb + React-jsinspectornetwork: e7c77d01b5f0664e24c0bec1aea27d5e3d7fb746 + React-jsinspectortracing: aaa96a4e53abb88dc6d47da3b5744c710652fef9 + React-jsitooling: 226e5f4147c7b6f1ae1954a8406ffa713f3da828 + React-jsitracing: 8a2fbeaa9c53c3f0b23904ccffefc890eae48d71 + React-logger: 1767babce2d28c3251039ce05556714a2c8c6ded + React-Mapbuffer: 33f678ee25b6c0ee2b01b1ecec08e3e02424cefe + React-microtasksnativemodule: 44b44a4d3cd6ffb85d928abf741acdc26722de2e + react-native-safe-area-context: 54d812805f3c4e08a4580ad086cbde1d8780c2e4 + react-native-skia: 4df548eb44d05ce5e35679b15a9d765e5724126e + react-native-wgpu: b4dc1b3af4fb7e6169f504ad28a60508d530d06a + React-NativeModulesApple: b5d18bc109c45c9a1c6b71664991b5cc3adc4e48 React-oscompat: 93b5535ea7f7dff46aaee4f78309a70979bdde9d - React-perflogger: 5536d2df3d18fe0920263466f7b46a56351c0510 - React-performancetimeline: 9041c53efa07f537164dcfe7670a36642352f4c2 + React-perflogger: a03d913e3205b00aee4128082abe42fd45ce0c98 + React-performancetimeline: 9b5986cc15afafb9bf246d7dd55bdd138df94451 React-RCTActionSheet: 42195ae666e6d79b4af2346770f765b7c29435b9 - React-RCTAnimation: fa103ccc3503b1ed8dedca7e62e7823937748843 - React-RCTAppDelegate: 665d4baf19424cef08276e9ac0d8771eec4519f9 - React-RCTBlob: 0fa9530c255644db095f2c4fd8d89738d9d9ecc0 - React-RCTFabric: 1fcd8af6e25f92532f56b4ba092e58662c14d156 - React-RCTFBReactNativeSpec: db171247585774f9f0a30f75109cc51568686213 - React-RCTImage: ba824e61ce2e920a239a65d130b83c3a1d426dff - React-RCTLinking: d2dc199c37e71e6f505d9eca3e5c33be930014d4 - React-RCTNetwork: 87137d4b9bd77e5068f854dd5c1f30d4b072faf6 - React-RCTRuntime: 137fafaa808a8b7e76a510e8be45f9f827899daa - React-RCTSettings: 71f5c7fd7b5f4e725a4e2114a4b4373d0e46048f - React-RCTText: b94d4699b49285bee22b8ebf768924d607eccee3 - React-RCTVibration: 6e3993c4f6c36a3899059f9a9ead560ddaf5a7d7 + React-RCTAnimation: 5c10527683128c56ff2c09297fb080f7c35bd293 + React-RCTAppDelegate: c616bd5b0d12f0b21dfacee9cd2d512c6df013aa + React-RCTBlob: 6e3757bdd7dce6fd9788c0dd675fd6b6c432db9d + React-RCTFabric: e8f3b9da97477710bf0904a62eb5b5209c964694 + React-RCTFBReactNativeSpec: c042f8d60d44ad9e2c722da89323c0bdab7a37af + React-RCTImage: a3482fe1ae562d1bab08b42d4670a7c9a21813cd + React-RCTLinking: d82b9adb141aef9d2b38d446b837ae7017ab60aa + React-RCTNetwork: fa9350dd99354c5695964f589bd4790bdd4f6a85 + React-RCTRuntime: be99a38cd23388c08921d8969c82a1997a11ec90 + React-RCTSettings: b7f4a03f44dba1d3a4dc6770843547b203ca9129 + React-RCTText: 91dc597a5f6b27fd1048bb287c41ea05eeca9333 + React-RCTVibration: 27b09ddf74bddfa30a58d20e48f885ea6ed6c9d9 React-rendererconsistency: b4785e5ed837dc7c242bbc5fdd464b33ef5bfae7 - React-renderercss: e6fb0ba387b389c595ffa86b8b628716d31f58dc - React-rendererdebug: 60a03de5c7ea59bf2d39791eb43c4c0f5d8b24e3 - React-RuntimeApple: 3df6788cd9b938bb8cb28298d80b5fbd98a4d852 - React-RuntimeCore: fad8adb4172c414c00ff6980250caf35601a0f5d - React-runtimeexecutor: d2db7e72d97751855ea0bf5273d2ac84e5ea390c - React-RuntimeHermes: 04faa4cf9a285136a6d73738787fe36020170613 - React-runtimescheduler: f6a1c9555e7131b4a8b64cce01489ad0405f6e8d - React-timing: 1e6a8acb66e2b7ac9d418956617fd1fdb19322fd - React-utils: 52bbb03f130319ef82e4c3bc7a85eaacdb1fec87 - ReactAppDependencyProvider: 433ddfb4536948630aadd5bd925aff8a632d2fe3 - ReactCodegen: 7042ec4a7316b59e8f247b8fa312891179d24f5a - ReactCommon: 394c6b92765cf6d211c2c3f7f6bc601dffb316a6 - ReactNativeHost: f5e054387e917216a2a021a3f7fdc4f9f158e7e4 - ReactTestApp-DevSupport: 9b7bbba5e8fed998e763809171d9906a1375f9d3 + React-renderercss: cef3f26df2ddec558ce3c0790fc574b4fb62ce67 + React-rendererdebug: e68433ae67738caeb672a6c8cc993e9276b298a9 + React-RuntimeApple: dc1d4709bf847bc695dbe6e8aaf3e22ef25aef02 + React-RuntimeCore: ca3473c8b6578693fa3bad4d44240098d49d6723 + React-runtimeexecutor: 0db3ca0b09cd72489cef3a3729349b3c2cf13320 + React-RuntimeHermes: f92cabaf97ef2546a74360eddfc1c74a34cb9ff8 + React-runtimescheduler: 06aea75069e0d556a75d258bfc89eb0ebd5d557e + React-timing: 1a90df9a04d8e7fd165ff7fa0918b9595c776373 + React-utils: 92115441fb55ce01ded4abfb5e9336a74cd93e9c + ReactAppDependencyProvider: b20fba6c3d091a393925890009999472c8f94d95 + ReactCodegen: cf03d376a26d393f818d511240b026fc8c95313c + ReactCommon: 00df7b9f859c9d02181844255bb89a8bca544374 + ReactNativeHost: b63ce830e7c5b4e3adcf556b2ef41665da189da0 + ReactTestApp-DevSupport: c7bff1aee7663f2fb1eefcf60c41573f02916c41 ReactTestApp-Resources: 1bd9ff10e4c24f2ad87101a32023721ae923bccf - RNGestureHandler: e37bdb684df1ac17c7e1d8f71a3311b2793c186b - RNReanimated: 464375ff2caa801358547c44eca894ff0bf68e74 - RNWorklets: ee58e869ea579800ec5f2f1cb6ae195fd3537546 + RNGestureHandler: 92ad734ef0da16d69d0a325b7e1e9ae80bdce1f9 + RNReanimated: 52dad96755e908e80b403c5ccdd7e24451f0c42a + RNWorklets: 95eb4f990dd495be6bf35a2567b0351a6d7f73cf SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748 - Yoga: a3ed390a19db0459bd6839823a6ac6d9c6db198d + Yoga: 922d794dce2af9c437f864bf4093abfa7a131adb PODFILE CHECKSUM: b4c1d70c599aba416a49b6bad5eea5084b4e43d0 -COCOAPODS: 1.16.2 +COCOAPODS: 1.15.2 diff --git a/packages/webgpu/android/cpp/AndroidPlatformContext.h b/packages/webgpu/android/cpp/AndroidPlatformContext.h index 5a1ff4b28..7fe122f04 100644 --- a/packages/webgpu/android/cpp/AndroidPlatformContext.h +++ b/packages/webgpu/android/cpp/AndroidPlatformContext.h @@ -3,8 +3,10 @@ #include #include +#include #include #include +#include #include #include "webgpu/webgpu_cpp.h" @@ -128,6 +130,112 @@ class AndroidPlatformContext : public PlatformContext { result.data = imageData; return result; } + + void createImageBitmapAsync( + std::string blobId, double offset, double size, + std::function onSuccess, + std::function onError) override { + // Capture blobModule for the background thread + jobject blobModule = _blobModule; + + // Dispatch to a background thread + std::thread([blobModule, blobId = std::move(blobId), offset, size, + onSuccess = std::move(onSuccess), + onError = std::move(onError)]() { + jni::Environment::ensureCurrentThreadIsAttached(); + + JNIEnv *env = facebook::jni::Environment::current(); + if (!env) { + onError("Couldn't get JNI environment"); + return; + } + + if (!blobModule) { + onError("BlobModule instance is null"); + return; + } + + // Get the resolve method ID + jclass blobModuleClass = env->GetObjectClass(blobModule); + if (!blobModuleClass) { + onError("Couldn't find BlobModule class"); + return; + } + + jmethodID resolveMethod = env->GetMethodID(blobModuleClass, "resolve", + "(Ljava/lang/String;II)[B"); + if (!resolveMethod) { + onError("Couldn't find resolve method in BlobModule"); + return; + } + + // Resolve the blob data + jstring jBlobId = env->NewStringUTF(blobId.c_str()); + jbyteArray blobData = (jbyteArray)env->CallObjectMethod( + blobModule, resolveMethod, jBlobId, static_cast(offset), + static_cast(size)); + env->DeleteLocalRef(jBlobId); + + if (!blobData) { + onError("Couldn't retrieve blob data"); + return; + } + + // Create a Bitmap from the blob data + jclass bitmapFactoryClass = + env->FindClass("android/graphics/BitmapFactory"); + jmethodID decodeByteArrayMethod = + env->GetStaticMethodID(bitmapFactoryClass, "decodeByteArray", + "([BII)Landroid/graphics/Bitmap;"); + jint blobLength = env->GetArrayLength(blobData); + jobject bitmap = env->CallStaticObjectMethod( + bitmapFactoryClass, decodeByteArrayMethod, blobData, 0, blobLength); + + if (!bitmap) { + env->DeleteLocalRef(blobData); + onError("Couldn't decode image"); + return; + } + + // Get bitmap info + AndroidBitmapInfo bitmapInfo; + if (AndroidBitmap_getInfo(env, bitmap, &bitmapInfo) != + ANDROID_BITMAP_RESULT_SUCCESS) { + env->DeleteLocalRef(blobData); + env->DeleteLocalRef(bitmap); + onError("Couldn't get bitmap info"); + return; + } + + // Lock the bitmap pixels + void *bitmapPixels; + if (AndroidBitmap_lockPixels(env, bitmap, &bitmapPixels) != + ANDROID_BITMAP_RESULT_SUCCESS) { + env->DeleteLocalRef(blobData); + env->DeleteLocalRef(bitmap); + onError("Couldn't lock bitmap pixels"); + return; + } + + // Copy the bitmap data + std::vector imageData(bitmapInfo.height * bitmapInfo.stride); + memcpy(imageData.data(), bitmapPixels, imageData.size()); + + // Unlock the bitmap pixels + AndroidBitmap_unlockPixels(env, bitmap); + + // Clean up JNI references + env->DeleteLocalRef(blobData); + env->DeleteLocalRef(bitmap); + + ImageData result; + result.width = static_cast(bitmapInfo.width); + result.height = static_cast(bitmapInfo.height); + result.data = std::move(imageData); + + onSuccess(std::move(result)); + }).detach(); + } }; } // namespace rnwgpu diff --git a/packages/webgpu/apple/ApplePlatformContext.h b/packages/webgpu/apple/ApplePlatformContext.h index 395cac25a..730de3306 100644 --- a/packages/webgpu/apple/ApplePlatformContext.h +++ b/packages/webgpu/apple/ApplePlatformContext.h @@ -15,6 +15,11 @@ class ApplePlatformContext : public PlatformContext { ImageData createImageBitmap(std::string blobId, double offset, double size) override; + + void createImageBitmapAsync( + std::string blobId, double offset, double size, + std::function onSuccess, + std::function onError) override; }; } // namespace rnwgpu diff --git a/packages/webgpu/apple/ApplePlatformContext.mm b/packages/webgpu/apple/ApplePlatformContext.mm index 09200f493..00ff61a74 100644 --- a/packages/webgpu/apple/ApplePlatformContext.mm +++ b/packages/webgpu/apple/ApplePlatformContext.mm @@ -95,4 +95,73 @@ void checkIfUsingSimulatorWithAPIValidation() { return result; } +void ApplePlatformContext::createImageBitmapAsync( + std::string blobId, double offset, double size, + std::function onSuccess, + std::function onError) { + // Capture blob data on the current thread (requires RCTBridge access) + RCTBlobManager *blobManager = + [[RCTBridge currentBridge] moduleForClass:RCTBlobManager.class]; + NSData *blobData = + [blobManager resolve:[NSString stringWithUTF8String:blobId.c_str()] + offset:(long)offset + size:(long)size]; + + if (!blobData) { + onError("Couldn't retrieve blob data"); + return; + } + + // Retain the data for the background block + NSData *retainedData = [blobData copy]; + + // Dispatch heavy image decoding work to a background queue + dispatch_async( + dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{ + @autoreleasepool { +#if !TARGET_OS_OSX + UIImage *image = [UIImage imageWithData:retainedData]; +#else + NSImage *image = [[NSImage alloc] initWithData:retainedData]; +#endif + if (!image) { + onError("Couldn't decode image"); + return; + } + +#if !TARGET_OS_OSX + CGImageRef cgImage = image.CGImage; +#else + CGImageRef cgImage = [image CGImageForProposedRect:NULL + context:NULL + hints:NULL]; +#endif + size_t width = CGImageGetWidth(cgImage); + size_t height = CGImageGetHeight(cgImage); + size_t bitsPerComponent = 8; + size_t bytesPerRow = width * 4; + std::vector imageData(height * bytesPerRow); + + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGContextRef context = CGBitmapContextCreate( + imageData.data(), width, height, bitsPerComponent, bytesPerRow, + colorSpace, + kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); + + CGContextDrawImage(context, CGRectMake(0, 0, width, height), cgImage); + + CGContextRelease(context); + CGColorSpaceRelease(colorSpace); + + ImageData result; + result.width = static_cast(width); + result.height = static_cast(height); + result.data = std::move(imageData); + result.format = wgpu::TextureFormat::RGBA8Unorm; + + onSuccess(std::move(result)); + } + }); +} + } // namespace rnwgpu diff --git a/packages/webgpu/cpp/rnwgpu/PlatformContext.h b/packages/webgpu/cpp/rnwgpu/PlatformContext.h index 0911aa548..5dea59ed1 100644 --- a/packages/webgpu/cpp/rnwgpu/PlatformContext.h +++ b/packages/webgpu/cpp/rnwgpu/PlatformContext.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -24,6 +25,12 @@ class PlatformContext { int width, int height) = 0; virtual ImageData createImageBitmap(std::string blobId, double offset, double size) = 0; + + // Async version that performs image decoding on a background thread + virtual void createImageBitmapAsync( + std::string blobId, double offset, double size, + std::function onSuccess, + std::function onError) = 0; }; } // namespace rnwgpu diff --git a/packages/webgpu/cpp/rnwgpu/RNWebGPUManager.cpp b/packages/webgpu/cpp/rnwgpu/RNWebGPUManager.cpp index 10362bd35..bc6280be8 100644 --- a/packages/webgpu/cpp/rnwgpu/RNWebGPUManager.cpp +++ b/packages/webgpu/cpp/rnwgpu/RNWebGPUManager.cpp @@ -60,7 +60,7 @@ RNWebGPUManager::RNWebGPUManager( BaseRuntimeAwareCache::setMainJsRuntime(_jsRuntime); auto gpu = std::make_shared(*_jsRuntime); - auto rnWebGPU = std::make_shared(gpu, _platformContext); + auto rnWebGPU = std::make_shared(gpu, _platformContext, _jsCallInvoker); _gpu = gpu->get(); _jsRuntime->global().setProperty(*_jsRuntime, "RNWebGPU", RNWebGPU::create(*_jsRuntime, rnWebGPU)); diff --git a/packages/webgpu/cpp/rnwgpu/api/GPU.h b/packages/webgpu/cpp/rnwgpu/api/GPU.h index 27db1f903..f6bb4ede3 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPU.h +++ b/packages/webgpu/cpp/rnwgpu/api/GPU.h @@ -48,6 +48,7 @@ class GPU : public NativeObject { } inline const wgpu::Instance get() { return _instance; } + inline std::shared_ptr getAsyncRunner() { return _async; } private: wgpu::Instance _instance; diff --git a/packages/webgpu/cpp/rnwgpu/api/RNWebGPU.h b/packages/webgpu/cpp/rnwgpu/api/RNWebGPU.h index 8ae87a2ea..fbaee35c1 100644 --- a/packages/webgpu/cpp/rnwgpu/api/RNWebGPU.h +++ b/packages/webgpu/cpp/rnwgpu/api/RNWebGPU.h @@ -11,6 +11,11 @@ #include "ImageBitmap.h" #include "PlatformContext.h" +#include + +#include "JSIConverter.h" +#include "Promise.h" + namespace rnwgpu { namespace jsi = facebook::jsi; @@ -23,14 +28,41 @@ struct Blob { std::string name; }; +// JSIConverter specialization must be declared before use +template <> struct JSIConverter> { + static std::shared_ptr + fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { + if (!outOfBounds && arg.isObject()) { + auto result = std::make_unique(); + auto val = arg.asObject(runtime); + if (val.hasProperty(runtime, "_data")) { + auto value = val.getPropertyAsObject(runtime, "_data"); + result->blobId = JSIConverter::fromJSI( + runtime, value.getProperty(runtime, "blobId"), false); + result->size = JSIConverter::fromJSI( + runtime, value.getProperty(runtime, "size"), false); + result->offset = JSIConverter::fromJSI( + runtime, value.getProperty(runtime, "offset"), false); + } + return result; + } else { + throw std::runtime_error("Invalid Blob::fromJSI()"); + } + } + static jsi::Value toJSI(jsi::Runtime &runtime, std::shared_ptr arg) { + throw std::runtime_error("Invalid Blob::toJSI()"); + } +}; + class RNWebGPU : public NativeObject { public: static constexpr const char *CLASS_NAME = "RNWebGPU"; explicit RNWebGPU(std::shared_ptr gpu, - std::shared_ptr platformContext) - : NativeObject(CLASS_NAME), _gpu(gpu), _platformContext(platformContext) { - } + std::shared_ptr platformContext, + std::shared_ptr callInvoker) + : NativeObject(CLASS_NAME), _gpu(gpu), _platformContext(platformContext), + _callInvoker(callInvoker) {} std::shared_ptr getGPU() { return _gpu; } @@ -43,11 +75,41 @@ class RNWebGPU : public NativeObject { return ctx; } - std::shared_ptr createImageBitmap(std::shared_ptr blob) { - auto imageData = _platformContext->createImageBitmap( - blob->blobId, blob->offset, blob->size); - auto imageBitmap = std::make_shared(imageData); - return imageBitmap; + jsi::Value createImageBitmap(jsi::Runtime &runtime, + const jsi::Value & /*thisVal*/, + const jsi::Value *args, size_t count) { + if (count < 1) { + throw jsi::JSError(runtime, "createImageBitmap requires a Blob argument"); + } + + auto blob = + JSIConverter>::fromJSI(runtime, args[0], false); + auto platformContext = _platformContext; + auto callInvoker = _callInvoker; + std::string blobId = blob->blobId; + double offset = blob->offset; + double size = blob->size; + + return Promise::createPromise( + runtime, + [platformContext, callInvoker, blobId, offset, + size](jsi::Runtime & /*runtime*/, std::shared_ptr promise) { + platformContext->createImageBitmapAsync( + blobId, offset, size, + [callInvoker, promise](ImageData imageData) { + auto imageBitmap = std::make_shared(imageData); + callInvoker->invokeAsync( + [promise, imageBitmap]() { + promise->resolve( + JSIConverter>::toJSI( + promise->runtime, imageBitmap)); + }); + }, + [callInvoker, promise](std::string error) { + callInvoker->invokeAsync( + [promise, error]() { promise->reject(error); }); + }); + }); } std::shared_ptr getNativeSurface(int contextId) { @@ -75,35 +137,7 @@ class RNWebGPU : public NativeObject { private: std::shared_ptr _gpu; std::shared_ptr _platformContext; -}; - -template <> struct JSIConverter> { - static std::shared_ptr - fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) { - if (!outOfBounds && arg.isObject()) { - auto result = std::make_unique(); - auto val = arg.asObject(runtime); - if (val.hasProperty(runtime, "_data")) { - auto value = val.getPropertyAsObject(runtime, "_data"); - result->blobId = JSIConverter::fromJSI( - runtime, value.getProperty(runtime, "blobId"), false); - // result->type = JSIConverter::fromJSI( - // runtime, value.getProperty(runtime, "type"), false); - // result->name = JSIConverter::fromJSI( - // runtime, value.getProperty(runtime, "name"), false); - result->size = JSIConverter::fromJSI( - runtime, value.getProperty(runtime, "size"), false); - result->offset = JSIConverter::fromJSI( - runtime, value.getProperty(runtime, "offset"), false); - } - return result; - } else { - throw std::runtime_error("Invalid Blob::fromJSI()"); - } - } - static jsi::Value toJSI(jsi::Runtime &runtime, std::shared_ptr arg) { - throw std::runtime_error("Invalid Blob::toJSI()"); - } + std::shared_ptr _callInvoker; }; } // namespace rnwgpu diff --git a/packages/webgpu/package.json b/packages/webgpu/package.json index e225bd769..44656386c 100644 --- a/packages/webgpu/package.json +++ b/packages/webgpu/package.json @@ -1,6 +1,6 @@ { "name": "react-native-wgpu", - "version": "0.5.2", + "version": "0.5.3", "description": "React Native WebGPU", "main": "lib/commonjs/index", "module": "lib/module/index", diff --git a/packages/webgpu/src/main/index.tsx b/packages/webgpu/src/main/index.tsx index faa58e07d..83aa0e1bf 100644 --- a/packages/webgpu/src/main/index.tsx +++ b/packages/webgpu/src/main/index.tsx @@ -32,6 +32,4 @@ if (!navigator) { } global.createImageBitmap = - global.createImageBitmap ?? - ((...params: Parameters) => - new Promise((resolve) => resolve(RNWebGPU.createImageBitmap(...params)))); + global.createImageBitmap ?? RNWebGPU.createImageBitmap.bind(RNWebGPU);