react-native-wgpu 0.1.12 → 0.1.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/CMakeLists.txt +7 -0
- package/android/build.gradle +4 -4
- package/android/cpp/cpp-adapter.cpp +10 -4
- package/android/cpp/platform/ThreadUtils.cpp +41 -0
- package/apple/ApplePlatformContext.h +19 -0
- package/apple/ApplePlatformContext.mm +86 -0
- package/apple/MetalView.h +13 -0
- package/apple/MetalView.mm +58 -0
- package/apple/WebGPUModule.h +19 -0
- package/apple/WebGPUModule.mm +93 -0
- package/apple/WebGPUView.h +15 -0
- package/apple/WebGPUView.mm +68 -0
- package/apple/WebGPUViewManager.mm +23 -0
- package/apple/platform/ThreadUtils.cpp +33 -0
- package/cpp/jsi/RNFJSIConverter.h +47 -28
- package/cpp/platform/ThreadUtils.h +30 -0
- package/cpp/rnwgpu/RNWebGPUManager.cpp +8 -0
- package/cpp/rnwgpu/api/Convertors.h +13 -14
- package/cpp/rnwgpu/api/GPU.cpp +4 -4
- package/cpp/rnwgpu/api/GPUAdapter.cpp +15 -14
- package/cpp/rnwgpu/api/GPUAdapterInfo.h +25 -4
- package/cpp/rnwgpu/api/GPUCanvasContext.cpp +6 -4
- package/cpp/rnwgpu/api/GPUDevice.cpp +5 -5
- package/cpp/rnwgpu/api/GPUDevice.h +7 -1
- package/cpp/rnwgpu/api/GPUFeatures.h +4 -4
- package/cpp/rnwgpu/api/GPUShaderModule.cpp +2 -1
- package/cpp/rnwgpu/api/descriptors/GPUCanvasConfiguration.h +9 -0
- package/cpp/threading/CallInvokerDispatcher.h +37 -0
- package/cpp/threading/Dispatcher.cpp +54 -0
- package/cpp/threading/Dispatcher.h +93 -0
- package/cpp/threading/ThreadPool.cpp +86 -0
- package/cpp/threading/ThreadPool.h +53 -0
- package/cpp/webgpu/webgpu.h +762 -758
- package/cpp/webgpu/webgpu_cpp.h +1827 -1626
- package/cpp/webgpu/webgpu_cpp_chained_struct.h +2 -0
- package/lib/commonjs/hooks.js +4 -2
- package/lib/commonjs/hooks.js.map +1 -1
- package/lib/module/hooks.js +4 -2
- package/lib/module/hooks.js.map +1 -1
- package/lib/typescript/lib/commonjs/hooks.d.ts.map +1 -1
- package/lib/typescript/lib/module/hooks.d.ts.map +1 -1
- package/lib/typescript/src/__tests__/Alpha.spec.d.ts +2 -0
- package/lib/typescript/src/__tests__/Alpha.spec.d.ts.map +1 -0
- package/lib/typescript/src/hooks.d.ts.map +1 -1
- package/libs/android/arm64-v8a/libwebgpu_dawn.so +0 -0
- package/libs/android/armeabi-v7a/libwebgpu_dawn.so +0 -0
- package/libs/android/x86/libwebgpu_dawn.so +0 -0
- package/libs/android/x86_64/libwebgpu_dawn.so +0 -0
- package/libs/apple/arm64_iphoneos/libwebgpu_dawn.a +0 -0
- package/libs/apple/arm64_iphonesimulator/libwebgpu_dawn.a +0 -0
- package/libs/apple/arm64_xros/libwebgpu_dawn.a +0 -0
- package/libs/apple/arm64_xrsimulator/libwebgpu_dawn.a +0 -0
- package/libs/apple/iphonesimulator/libwebgpu_dawn.a +0 -0
- package/libs/apple/libwebgpu_dawn.xcframework/Info.plist +10 -10
- package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64/libwebgpu_dawn.a +0 -0
- package/libs/apple/libwebgpu_dawn.xcframework/ios-arm64_x86_64-simulator/libwebgpu_dawn.a +0 -0
- package/libs/apple/libwebgpu_dawn.xcframework/macos-arm64_x86_64/libwebgpu_dawn.a +0 -0
- package/libs/apple/libwebgpu_dawn.xcframework/xros-arm64/libwebgpu_dawn.a +0 -0
- package/libs/apple/libwebgpu_dawn.xcframework/xros-arm64-simulator/libwebgpu_dawn.a +0 -0
- package/libs/apple/universal_macosx/libwebgpu_dawn.a +0 -0
- package/libs/apple/x86_64_iphonesimulator/libwebgpu_dawn.a +0 -0
- package/libs/dawn.json +270 -251
- package/package.json +2 -2
- package/src/__tests__/Alpha.spec.ts +28 -0
- package/src/__tests__/Device.spec.ts +31 -0
- package/src/__tests__/snapshots/semi-opaque-cyan.png +0 -0
- package/src/hooks.tsx +3 -2
package/android/CMakeLists.txt
CHANGED
|
@@ -25,6 +25,7 @@ find_package(fbjni REQUIRED CONFIG)
|
|
|
25
25
|
|
|
26
26
|
add_library(${PACKAGE_NAME} SHARED
|
|
27
27
|
./cpp/cpp-adapter.cpp
|
|
28
|
+
./cpp/platform/ThreadUtils.cpp
|
|
28
29
|
../cpp/rnwgpu/api/GPU.cpp
|
|
29
30
|
../cpp/rnwgpu/api/GPUAdapter.cpp
|
|
30
31
|
../cpp/rnwgpu/api/GPUSupportedLimits.cpp
|
|
@@ -48,6 +49,8 @@ add_library(${PACKAGE_NAME} SHARED
|
|
|
48
49
|
../cpp/jsi/RNFHybridObject.cpp
|
|
49
50
|
../cpp/jsi/RNFRuntimeCache.cpp
|
|
50
51
|
../cpp/jsi/RNFWorkletRuntimeRegistry.cpp
|
|
52
|
+
../cpp/threading/Dispatcher.cpp
|
|
53
|
+
../cpp/threading/ThreadPool.cpp
|
|
51
54
|
)
|
|
52
55
|
|
|
53
56
|
target_include_directories(
|
|
@@ -61,6 +64,7 @@ target_include_directories(
|
|
|
61
64
|
"${NODE_MODULES_DIR}/react-native/ReactCommon/runtimeexecutor"
|
|
62
65
|
"${NODE_MODULES_DIR}/react-native/ReactAndroid/src/main/jni"
|
|
63
66
|
"${NODE_MODULES_DIR}/react-native/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni"
|
|
67
|
+
"${NODE_MODULES_DIR}/react-native/ReactAndroid/src/main/jni/react/turbomodule"
|
|
64
68
|
|
|
65
69
|
../cpp
|
|
66
70
|
../cpp/rnwgpu
|
|
@@ -68,6 +72,8 @@ target_include_directories(
|
|
|
68
72
|
../cpp/rnwgpu/api/descriptors
|
|
69
73
|
../cpp/jsi
|
|
70
74
|
../cpp/webgpu
|
|
75
|
+
../cpp/threading
|
|
76
|
+
../cpp/platform
|
|
71
77
|
|
|
72
78
|
${libfbjni_include_DIRS}
|
|
73
79
|
)
|
|
@@ -84,5 +90,6 @@ target_link_libraries(
|
|
|
84
90
|
android
|
|
85
91
|
fbjni::fbjni
|
|
86
92
|
ReactAndroid::jsi
|
|
93
|
+
ReactAndroid::reactnativejni
|
|
87
94
|
webgpu_dawn
|
|
88
95
|
)
|
package/android/build.gradle
CHANGED
|
@@ -87,10 +87,10 @@ android {
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
packagingOptions {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
90
|
+
excludes = [
|
|
91
|
+
"**/libjsi.so",
|
|
92
|
+
"**/libreactnativejni.so",
|
|
93
|
+
]
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
buildFeatures {
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
#include <jni.h>
|
|
6
6
|
#include <jsi/jsi.h>
|
|
7
7
|
|
|
8
|
+
#include <ReactCommon/CallInvokerHolder.h>
|
|
8
9
|
#include <android/native_window_jni.h>
|
|
9
10
|
#include <webgpu/webgpu_cpp.h>
|
|
10
11
|
|
|
@@ -17,13 +18,18 @@
|
|
|
17
18
|
std::shared_ptr<rnwgpu::RNWebGPUManager> manager;
|
|
18
19
|
|
|
19
20
|
extern "C" JNIEXPORT void JNICALL Java_com_webgpu_WebGPUModule_initializeNative(
|
|
20
|
-
JNIEnv *env, jobject /* this */, jlong jsRuntime,
|
|
21
|
-
jobject blobModule) {
|
|
21
|
+
JNIEnv *env, jobject /* this */, jlong jsRuntime,
|
|
22
|
+
jobject jsCallInvokerHolder, jobject blobModule) {
|
|
22
23
|
auto runtime = reinterpret_cast<facebook::jsi::Runtime *>(jsRuntime);
|
|
23
24
|
jobject globalBlobModule = env->NewGlobalRef(blobModule);
|
|
25
|
+
auto jsCallInvoker{
|
|
26
|
+
facebook::jni::alias_ref<facebook::react::CallInvokerHolder::javaobject>{
|
|
27
|
+
reinterpret_cast<facebook::react::CallInvokerHolder::javaobject>(
|
|
28
|
+
jsCallInvokerHolder)} -> cthis()
|
|
29
|
+
->getCallInvoker()};
|
|
24
30
|
auto platformContext =
|
|
25
31
|
std::make_shared<rnwgpu::AndroidPlatformContext>(globalBlobModule);
|
|
26
|
-
manager = std::make_shared<rnwgpu::RNWebGPUManager>(runtime,
|
|
32
|
+
manager = std::make_shared<rnwgpu::RNWebGPUManager>(runtime, jsCallInvoker,
|
|
27
33
|
platformContext);
|
|
28
34
|
}
|
|
29
35
|
|
|
@@ -55,7 +61,7 @@ Java_com_webgpu_WebGPUView_switchToOffscreenSurface(JNIEnv *env, jobject thiz,
|
|
|
55
61
|
jint contextId) {
|
|
56
62
|
auto ®istry = rnwgpu::SurfaceRegistry::getInstance();
|
|
57
63
|
auto nativeSurface = registry.getSurfaceInfo(contextId)->switchToOffscreen();
|
|
58
|
-
ANativeWindow_release(reinterpret_cast<ANativeWindow *>(nativeSurface));
|
|
64
|
+
// ANativeWindow_release(reinterpret_cast<ANativeWindow *>(nativeSurface));
|
|
59
65
|
}
|
|
60
66
|
|
|
61
67
|
extern "C" JNIEXPORT void JNICALL Java_com_webgpu_WebGPUView_onSurfaceDestroy(
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
//
|
|
2
|
+
// ThreadUtils.cpp
|
|
3
|
+
// react-native-nitro
|
|
4
|
+
//
|
|
5
|
+
// Created by Marc Rousavy on 14.07.24.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#include "ThreadUtils.h"
|
|
9
|
+
#include <pthread.h>
|
|
10
|
+
#include <sstream>
|
|
11
|
+
#include <string>
|
|
12
|
+
#include <sys/prctl.h>
|
|
13
|
+
#include <thread>
|
|
14
|
+
|
|
15
|
+
namespace margelo {
|
|
16
|
+
|
|
17
|
+
std::string ThreadUtils::getThreadName() {
|
|
18
|
+
#ifdef HAVE_ANDROID_PTHREAD_SETNAME_NP
|
|
19
|
+
// Try using pthread APIs
|
|
20
|
+
pthread_t this_thread = pthread_self();
|
|
21
|
+
char thread_name[16]; // Thread name length limit in Android is 16 characters
|
|
22
|
+
|
|
23
|
+
int result =
|
|
24
|
+
pthread_getname_np(this_thread, thread_name, sizeof(thread_name));
|
|
25
|
+
if (result == 0) {
|
|
26
|
+
return std::string(thread_name);
|
|
27
|
+
}
|
|
28
|
+
#endif
|
|
29
|
+
|
|
30
|
+
// Fall back to this_thread ID
|
|
31
|
+
std::stringstream stream;
|
|
32
|
+
stream << std::this_thread::get_id();
|
|
33
|
+
std::string threadId = stream.str();
|
|
34
|
+
return "Thread #" + threadId;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
void ThreadUtils::setThreadName(const std::string &name) {
|
|
38
|
+
prctl(PR_SET_NAME, name.c_str(), 0, 0, 0);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
} // namespace margelo
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "PlatformContext.h"
|
|
4
|
+
|
|
5
|
+
namespace rnwgpu {
|
|
6
|
+
|
|
7
|
+
class ApplePlatformContext : public PlatformContext {
|
|
8
|
+
public:
|
|
9
|
+
ApplePlatformContext();
|
|
10
|
+
~ApplePlatformContext() = default;
|
|
11
|
+
|
|
12
|
+
wgpu::Surface makeSurface(wgpu::Instance instance, void *surface, int width,
|
|
13
|
+
int height) override;
|
|
14
|
+
|
|
15
|
+
ImageData createImageBitmap(std::string blobId, double offset,
|
|
16
|
+
double size) override;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
} // namespace rnwgpu
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#include "ApplePlatformContext.h"
|
|
2
|
+
|
|
3
|
+
#include <TargetConditionals.h>
|
|
4
|
+
|
|
5
|
+
#import <React/RCTBlobManager.h>
|
|
6
|
+
#import <React/RCTBridge+Private.h>
|
|
7
|
+
#import <ReactCommon/RCTTurboModule.h>
|
|
8
|
+
|
|
9
|
+
#include "RNWebGPUManager.h"
|
|
10
|
+
#include "WebGPUModule.h"
|
|
11
|
+
|
|
12
|
+
namespace rnwgpu {
|
|
13
|
+
|
|
14
|
+
void isSimulatorWithAPIValidation() {
|
|
15
|
+
#if TARGET_OS_SIMULATOR
|
|
16
|
+
NSDictionary *environment = [[NSProcessInfo processInfo] environment];
|
|
17
|
+
NSString *metalDeviceWrapperType = environment[@"METAL_DEVICE_WRAPPER_TYPE"];
|
|
18
|
+
|
|
19
|
+
if ([metalDeviceWrapperType isEqualToString:@"1"]) {
|
|
20
|
+
throw std::runtime_error(
|
|
21
|
+
"To use React Native WebGPU project on the iOS simulator, you need to "
|
|
22
|
+
"disable the Metal validation API. In 'Edit Scheme,' uncheck 'Metal "
|
|
23
|
+
"Validation.'");
|
|
24
|
+
}
|
|
25
|
+
#endif
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
ApplePlatformContext::ApplePlatformContext() { isSimulatorWithAPIValidation(); }
|
|
29
|
+
|
|
30
|
+
wgpu::Surface ApplePlatformContext::makeSurface(wgpu::Instance instance,
|
|
31
|
+
void *surface, int width,
|
|
32
|
+
int height) {
|
|
33
|
+
wgpu::SurfaceDescriptorFromMetalLayer metalSurfaceDesc;
|
|
34
|
+
metalSurfaceDesc.layer = surface;
|
|
35
|
+
wgpu::SurfaceDescriptor surfaceDescriptor;
|
|
36
|
+
surfaceDescriptor.nextInChain = &metalSurfaceDesc;
|
|
37
|
+
return instance.CreateSurface(&surfaceDescriptor);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
ImageData ApplePlatformContext::createImageBitmap(std::string blobId,
|
|
41
|
+
double offset, double size) {
|
|
42
|
+
RCTBlobManager *blobManager =
|
|
43
|
+
[[RCTBridge currentBridge] moduleForClass:RCTBlobManager.class];
|
|
44
|
+
NSData *blobData =
|
|
45
|
+
[blobManager resolve:[NSString stringWithUTF8String:blobId.c_str()]
|
|
46
|
+
offset:(long)offset
|
|
47
|
+
size:(long)size];
|
|
48
|
+
|
|
49
|
+
if (!blobData) {
|
|
50
|
+
throw std::runtime_error("Couldn't retrive blob data");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
UIImage *image = [UIImage imageWithData:blobData];
|
|
54
|
+
if (!image) {
|
|
55
|
+
throw std::runtime_error("Couldn't decode image");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
CGImageRef cgImage = image.CGImage;
|
|
59
|
+
size_t width = CGImageGetWidth(cgImage);
|
|
60
|
+
size_t height = CGImageGetHeight(cgImage);
|
|
61
|
+
size_t bitsPerComponent = 8;
|
|
62
|
+
size_t bytesPerRow = width * 4;
|
|
63
|
+
std::vector<uint8_t> imageData(height * bytesPerRow);
|
|
64
|
+
|
|
65
|
+
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
|
66
|
+
CGContextRef context = CGBitmapContextCreate(
|
|
67
|
+
imageData.data(), width, height, bitsPerComponent, bytesPerRow,
|
|
68
|
+
colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
|
|
69
|
+
|
|
70
|
+
CGContextDrawImage(context, CGRectMake(0, 0, width, height), cgImage);
|
|
71
|
+
|
|
72
|
+
// Now imageData contains a copy of the bitmap data
|
|
73
|
+
|
|
74
|
+
CGContextRelease(context);
|
|
75
|
+
CGColorSpaceRelease(colorSpace);
|
|
76
|
+
|
|
77
|
+
// Use the copied data
|
|
78
|
+
ImageData result;
|
|
79
|
+
result.width = static_cast<int>(width);
|
|
80
|
+
result.height = static_cast<int>(height);
|
|
81
|
+
result.data = imageData;
|
|
82
|
+
result.format = wgpu::TextureFormat::RGBA8Unorm;
|
|
83
|
+
return result;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
} // namespace rnwgpu
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#import "MetalView.h"
|
|
2
|
+
#import "webgpu_cpp.h"
|
|
3
|
+
|
|
4
|
+
#ifndef RCT_NEW_ARCH_ENABLED
|
|
5
|
+
#import <React/RCTViewManager.h>
|
|
6
|
+
#endif // RCT_NEW_ARCH_ENABLED
|
|
7
|
+
|
|
8
|
+
@implementation MetalView {
|
|
9
|
+
BOOL _isConfigured;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
+ (Class)layerClass {
|
|
13
|
+
return [CAMetalLayer class];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
- (void)configure {
|
|
17
|
+
auto size = self.frame.size;
|
|
18
|
+
std::shared_ptr<rnwgpu::RNWebGPUManager> manager = [WebGPUModule getManager];
|
|
19
|
+
void *nativeSurface = (__bridge void *)self.layer;
|
|
20
|
+
auto ®istry = rnwgpu::SurfaceRegistry::getInstance();
|
|
21
|
+
auto gpu = manager->_gpu;
|
|
22
|
+
auto surface = manager->_platformContext->makeSurface(
|
|
23
|
+
gpu, nativeSurface, size.width, size.height);
|
|
24
|
+
registry
|
|
25
|
+
.getSurfaceInfoOrCreate([_contextId intValue], gpu, size.width,
|
|
26
|
+
size.height)
|
|
27
|
+
->switchToOnscreen(nativeSurface, surface);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
- (void)update {
|
|
31
|
+
auto size = self.frame.size;
|
|
32
|
+
auto ®istry = rnwgpu::SurfaceRegistry::getInstance();
|
|
33
|
+
registry.getSurfaceInfo([_contextId intValue])
|
|
34
|
+
->resize(size.width, size.height);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
- (void)dealloc {
|
|
38
|
+
auto ®istry = rnwgpu::SurfaceRegistry::getInstance();
|
|
39
|
+
// Remove the surface info from the registry
|
|
40
|
+
registry.removeSurfaceInfo([_contextId intValue]);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
#ifndef RCT_NEW_ARCH_ENABLED
|
|
44
|
+
// Paper only method
|
|
45
|
+
// TODO: this method is wrong, it appears to call configureSurface instead of
|
|
46
|
+
// updateSurface sometimes
|
|
47
|
+
- (void)reactSetFrame:(CGRect)frame {
|
|
48
|
+
[super reactSetFrame:frame];
|
|
49
|
+
if (!_isConfigured) {
|
|
50
|
+
[self configure];
|
|
51
|
+
_isConfigured = YES;
|
|
52
|
+
} else {
|
|
53
|
+
[self update];
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
#endif // RCT_NEW_ARCH_ENABLED
|
|
57
|
+
|
|
58
|
+
@end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#import "RNWebGPUManager.h"
|
|
4
|
+
#import <React/RCTBridgeModule.h>
|
|
5
|
+
#import <React/RCTEventEmitter.h>
|
|
6
|
+
|
|
7
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
8
|
+
#import <RNWgpuViewSpec/RNWgpuViewSpec.h>
|
|
9
|
+
@interface WebGPUModule : RCTEventEmitter <NativeWebGPUModuleSpec>
|
|
10
|
+
#else
|
|
11
|
+
@interface WebGPUModule : RCTEventEmitter <RCTBridgeModule>
|
|
12
|
+
#endif
|
|
13
|
+
|
|
14
|
+
@property(nonatomic, weak) RCTBridge *bridge;
|
|
15
|
+
@property(nonatomic, weak) RCTModuleRegistry *moduleRegistry;
|
|
16
|
+
|
|
17
|
+
+ (std::shared_ptr<rnwgpu::RNWebGPUManager>)getManager;
|
|
18
|
+
|
|
19
|
+
@end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#import "WebGPUModule.h"
|
|
2
|
+
#include "ApplePlatformContext.h"
|
|
3
|
+
#import "GPUCanvasContext.h"
|
|
4
|
+
|
|
5
|
+
#import <React/RCTBridge+Private.h>
|
|
6
|
+
#import <React/RCTLog.h>
|
|
7
|
+
#import <React/RCTUIManagerUtils.h>
|
|
8
|
+
#import <ReactCommon/RCTTurboModule.h>
|
|
9
|
+
#import <jsi/jsi.h>
|
|
10
|
+
#import <memory>
|
|
11
|
+
|
|
12
|
+
namespace jsi = facebook::jsi;
|
|
13
|
+
namespace react = facebook::react;
|
|
14
|
+
|
|
15
|
+
@implementation WebGPUModule
|
|
16
|
+
|
|
17
|
+
RCT_EXPORT_MODULE(WebGPUModule)
|
|
18
|
+
|
|
19
|
+
static std::shared_ptr<rnwgpu::RNWebGPUManager> webgpuManager;
|
|
20
|
+
|
|
21
|
+
+ (std::shared_ptr<rnwgpu::RNWebGPUManager>)getManager {
|
|
22
|
+
return webgpuManager;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
#pragma Setup and invalidation
|
|
26
|
+
|
|
27
|
+
+ (BOOL)requiresMainQueueSetup {
|
|
28
|
+
return YES;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
- (void)invalidate {
|
|
32
|
+
// if (_webgpuManager != nil) {
|
|
33
|
+
// [_webgpuManager invalidate];
|
|
34
|
+
// }
|
|
35
|
+
webgpuManager = nil;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
- (std::shared_ptr<rnwgpu::RNWebGPUManager>)getManager {
|
|
39
|
+
return webgpuManager;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(install) {
|
|
43
|
+
if (webgpuManager != nil) {
|
|
44
|
+
// Already initialized, ignore call.
|
|
45
|
+
return @true;
|
|
46
|
+
}
|
|
47
|
+
RCTCxxBridge *cxxBridge = (RCTCxxBridge *)[RCTBridge currentBridge];
|
|
48
|
+
if (!cxxBridge.runtime) {
|
|
49
|
+
NSLog(@"Failed to install react-native-filament: RCTBridge is not a "
|
|
50
|
+
@"RCTCxxBridge!");
|
|
51
|
+
return [NSNumber numberWithBool:NO];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
jsi::Runtime *runtime = (jsi::Runtime *)cxxBridge.runtime;
|
|
55
|
+
if (!runtime) {
|
|
56
|
+
NSLog(@"Failed to install react-native-filament: jsi::Runtime* was null!");
|
|
57
|
+
return [NSNumber numberWithBool:NO];
|
|
58
|
+
}
|
|
59
|
+
std::shared_ptr<react::CallInvoker> jsInvoker = cxxBridge.jsCallInvoker;
|
|
60
|
+
if (!jsInvoker) {
|
|
61
|
+
NSLog(@"Failed to install react-native-filament: react::CallInvoker was "
|
|
62
|
+
@"null!");
|
|
63
|
+
return [NSNumber numberWithBool:NO];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!jsInvoker) {
|
|
67
|
+
jsInvoker = cxxBridge.jsCallInvoker;
|
|
68
|
+
}
|
|
69
|
+
std::shared_ptr<rnwgpu::PlatformContext> platformContext =
|
|
70
|
+
std::make_shared<rnwgpu::ApplePlatformContext>();
|
|
71
|
+
// TODO: remove allocation here
|
|
72
|
+
webgpuManager = std::make_shared<rnwgpu::RNWebGPUManager>(runtime, jsInvoker,
|
|
73
|
+
platformContext);
|
|
74
|
+
return @true;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(createSurfaceContext
|
|
78
|
+
// : (double)contextId) {
|
|
79
|
+
// int contextIdInt = contextId;
|
|
80
|
+
// RCTCxxBridge *cxxBridge = (RCTCxxBridge *)self.bridge;
|
|
81
|
+
// auto runtime = (jsi::Runtime *)cxxBridge.runtime;
|
|
82
|
+
|
|
83
|
+
// return @true;
|
|
84
|
+
// }
|
|
85
|
+
|
|
86
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
87
|
+
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
|
|
88
|
+
(const facebook::react::ObjCTurboModule::InitParams &)params {
|
|
89
|
+
return std::make_shared<facebook::react::NativeWebGPUModuleSpecJSI>(params);
|
|
90
|
+
}
|
|
91
|
+
#endif
|
|
92
|
+
|
|
93
|
+
@end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
2
|
+
#pragma once
|
|
3
|
+
|
|
4
|
+
#import "MetalView.h"
|
|
5
|
+
#import <React/RCTViewComponentView.h>
|
|
6
|
+
#import <UIKit/UIKit.h>
|
|
7
|
+
|
|
8
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
9
|
+
|
|
10
|
+
@interface WebGPUView : RCTViewComponentView
|
|
11
|
+
@end
|
|
12
|
+
|
|
13
|
+
NS_ASSUME_NONNULL_END
|
|
14
|
+
|
|
15
|
+
#endif /* RCT_NEW_ARCH_ENABLED */
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
2
|
+
#import "WebGPUView.h"
|
|
3
|
+
|
|
4
|
+
#import <react/renderer/components/RNWgpuViewSpec/ComponentDescriptors.h>
|
|
5
|
+
#import <react/renderer/components/RNWgpuViewSpec/EventEmitters.h>
|
|
6
|
+
#import <react/renderer/components/RNWgpuViewSpec/Props.h>
|
|
7
|
+
#import <react/renderer/components/RNWgpuViewSpec/RCTComponentViewHelpers.h>
|
|
8
|
+
|
|
9
|
+
#import "MetalView.h"
|
|
10
|
+
#import "RCTFabricComponentsPlugins.h"
|
|
11
|
+
#import "Utils.h"
|
|
12
|
+
|
|
13
|
+
using namespace facebook::react;
|
|
14
|
+
|
|
15
|
+
@implementation WebGPUView
|
|
16
|
+
|
|
17
|
+
+ (ComponentDescriptorProvider)componentDescriptorProvider {
|
|
18
|
+
return concreteComponentDescriptorProvider<WebGPUViewComponentDescriptor>();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
- (void)prepareForRecycle {
|
|
22
|
+
[super prepareForRecycle];
|
|
23
|
+
/*
|
|
24
|
+
It's important to destroy the Metal Layer before releasing a view
|
|
25
|
+
to the recycled pool to prevent displaying outdated content from
|
|
26
|
+
the last usage in the new context.
|
|
27
|
+
*/
|
|
28
|
+
self.contentView = nil;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
- (MetalView *)getContentView {
|
|
32
|
+
if (!self.contentView) {
|
|
33
|
+
self.contentView = [MetalView new];
|
|
34
|
+
}
|
|
35
|
+
return (MetalView *)self.contentView;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
- (void)updateProps:(const Props::Shared &)props
|
|
39
|
+
oldProps:(const Props::Shared &)oldProps {
|
|
40
|
+
const auto &oldViewProps =
|
|
41
|
+
*std::static_pointer_cast<const WebGPUViewProps>(_props);
|
|
42
|
+
const auto &newViewProps =
|
|
43
|
+
*std::static_pointer_cast<const WebGPUViewProps>(props);
|
|
44
|
+
|
|
45
|
+
if (newViewProps.contextId != oldViewProps.contextId) {
|
|
46
|
+
/*
|
|
47
|
+
The context is set only once during mounting the component
|
|
48
|
+
and never changes because it isn't available for users to modify.
|
|
49
|
+
*/
|
|
50
|
+
MetalView *metalView = [MetalView new];
|
|
51
|
+
self.contentView = metalView;
|
|
52
|
+
[metalView setContextId:@(newViewProps.contextId)];
|
|
53
|
+
[metalView configure];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
[super updateProps:props oldProps:oldProps];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
- (void)updateLayoutMetrics:(const LayoutMetrics &)layoutMetrics
|
|
60
|
+
oldLayoutMetrics:(const LayoutMetrics &)oldLayoutMetrics {
|
|
61
|
+
[super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:oldLayoutMetrics];
|
|
62
|
+
[(MetalView *)self.contentView update];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
Class<RCTComponentViewProtocol> WebGPUViewCls(void) { return WebGPUView.class; }
|
|
66
|
+
|
|
67
|
+
@end
|
|
68
|
+
#endif
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#import "MetalView.h"
|
|
2
|
+
#import "RCTBridge.h"
|
|
3
|
+
#import "WebGPUModule.h"
|
|
4
|
+
#import <React/RCTUIManager.h>
|
|
5
|
+
#import <React/RCTViewManager.h>
|
|
6
|
+
|
|
7
|
+
@interface WebGPUViewManager : RCTViewManager
|
|
8
|
+
@end
|
|
9
|
+
|
|
10
|
+
@implementation WebGPUViewManager
|
|
11
|
+
|
|
12
|
+
RCT_EXPORT_MODULE(WebGPUView)
|
|
13
|
+
|
|
14
|
+
- (UIView *)view {
|
|
15
|
+
return [MetalView new];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
RCT_CUSTOM_VIEW_PROPERTY(contextId, NSNumber, UIView) {
|
|
19
|
+
NSNumber *contextId = [RCTConvert NSNumber:json];
|
|
20
|
+
[(MetalView *)view setContextId:contextId];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//
|
|
2
|
+
// ThreadUtils.cpp
|
|
3
|
+
// react-native-nitro
|
|
4
|
+
//
|
|
5
|
+
// Created by Marc Rousavy on 14.07.24.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#include "ThreadUtils.h"
|
|
9
|
+
#include <pthread.h>
|
|
10
|
+
#include <sstream>
|
|
11
|
+
#include <thread>
|
|
12
|
+
|
|
13
|
+
namespace margelo {
|
|
14
|
+
|
|
15
|
+
std::string ThreadUtils::getThreadName() {
|
|
16
|
+
// Try using pthread APIs
|
|
17
|
+
char name[256];
|
|
18
|
+
if (pthread_getname_np(pthread_self(), name, sizeof(name)) == 0) {
|
|
19
|
+
return std::string(name);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Fall back to this_thread ID
|
|
23
|
+
std::stringstream stream;
|
|
24
|
+
stream << std::this_thread::get_id();
|
|
25
|
+
std::string threadId = stream.str();
|
|
26
|
+
return "Thread #" + threadId;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
void ThreadUtils::setThreadName(const std::string &name) {
|
|
30
|
+
pthread_setname_np(name.c_str());
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
} // namespace margelo
|
|
@@ -25,6 +25,9 @@
|
|
|
25
25
|
#include "RNFPromise.h"
|
|
26
26
|
#include "RNFWorkletRuntimeRegistry.h"
|
|
27
27
|
|
|
28
|
+
#include "Dispatcher.h"
|
|
29
|
+
#include "ThreadPool.h"
|
|
30
|
+
|
|
28
31
|
#if __has_include(<cxxabi.h>)
|
|
29
32
|
#include <cxxabi.h>
|
|
30
33
|
#endif
|
|
@@ -207,39 +210,55 @@ template <typename TResult> struct JSIConverter<std::future<TResult>> {
|
|
|
207
210
|
}
|
|
208
211
|
static jsi::Value toJSI(jsi::Runtime& runtime, std::future<TResult>&& arg) {
|
|
209
212
|
auto sharedFuture = std::make_shared<std::future<TResult>>(std::move(arg));
|
|
210
|
-
|
|
213
|
+
std::shared_ptr<Dispatcher> strongDispatcher = Dispatcher::getRuntimeGlobalDispatcher(runtime);
|
|
214
|
+
std::weak_ptr<Dispatcher> weakDispatcher = strongDispatcher;
|
|
215
|
+
|
|
216
|
+
return Promise::createPromise(runtime, [sharedFuture = std::move(sharedFuture), weakDispatcher](jsi::Runtime& runtime,
|
|
211
217
|
std::shared_ptr<Promise> promise) {
|
|
212
|
-
|
|
213
|
-
|
|
218
|
+
// Spawn new async thread to synchronously wait for the `future<T>` to complete
|
|
219
|
+
std::shared_ptr<ThreadPool> pool = ThreadPool::getSharedPool();
|
|
220
|
+
pool->run([promise, &runtime, weakDispatcher, sharedFuture]() {
|
|
221
|
+
// synchronously wait until the `future<T>` completes. we are running on a background task here.
|
|
214
222
|
sharedFuture->wait();
|
|
215
223
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
} else {
|
|
221
|
-
// it's returning a custom type, convert it to a jsi::Value
|
|
222
|
-
TResult result = sharedFuture->get();
|
|
223
|
-
jsi::Value jsResult = JSIConverter<TResult>::toJSI(runtime, result);
|
|
224
|
-
promise->resolve(std::move(jsResult));
|
|
224
|
+
std::shared_ptr<Dispatcher> dispatcher = weakDispatcher.lock();
|
|
225
|
+
if (!dispatcher) {
|
|
226
|
+
throw std::runtime_error("Tried resolving Promise on JS Thread, but the `Dispatcher` has already been destroyed!");
|
|
227
|
+
return;
|
|
225
228
|
}
|
|
226
|
-
} catch (const std::exception& exception) {
|
|
227
|
-
// the async function threw an error, reject the promise
|
|
228
|
-
std::string what = exception.what();
|
|
229
|
-
promise->reject(what);
|
|
230
|
-
} catch (...) {
|
|
231
|
-
// the async function threw a non-std error, try getting it
|
|
232
|
-
#if __has_include(<cxxabi.h>)
|
|
233
|
-
std::string name = __cxxabiv1::__cxa_current_exception_type()->name();
|
|
234
|
-
#else
|
|
235
|
-
std::string name = "<unknown>";
|
|
236
|
-
#endif
|
|
237
|
-
promise->reject("Unknown non-std exception: " + name);
|
|
238
|
-
}
|
|
239
229
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
230
|
+
dispatcher->runAsync([&runtime, promise, sharedFuture]() mutable {
|
|
231
|
+
try {
|
|
232
|
+
if constexpr (std::is_same_v<TResult, void>) {
|
|
233
|
+
// it's returning void, just return undefined to JS
|
|
234
|
+
sharedFuture->get();
|
|
235
|
+
promise->resolve(jsi::Value::undefined());
|
|
236
|
+
} else {
|
|
237
|
+
// it's returning a custom type, convert it to a jsi::Value
|
|
238
|
+
TResult result = sharedFuture->get();
|
|
239
|
+
jsi::Value jsResult = JSIConverter<TResult>::toJSI(runtime, result);
|
|
240
|
+
promise->resolve(std::move(jsResult));
|
|
241
|
+
}
|
|
242
|
+
} catch (const std::exception& exception) {
|
|
243
|
+
// the async function threw an error, reject the promise
|
|
244
|
+
std::string what = exception.what();
|
|
245
|
+
promise->reject(what);
|
|
246
|
+
} catch (...) {
|
|
247
|
+
// the async function threw a non-std error, try getting it
|
|
248
|
+
#if __has_include(<cxxabi.h>)
|
|
249
|
+
std::string name = __cxxabiv1::__cxa_current_exception_type()->name();
|
|
250
|
+
#else
|
|
251
|
+
std::string name = "<unknown>";
|
|
252
|
+
#endif
|
|
253
|
+
promise->reject("Unknown non-std exception: " + name);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// This lambda owns the promise shared pointer, and we need to call its
|
|
257
|
+
// destructor correctly here - otherwise it might be called
|
|
258
|
+
// from the threadPool thread.
|
|
259
|
+
promise = nullptr;
|
|
260
|
+
});
|
|
261
|
+
});
|
|
243
262
|
});
|
|
244
263
|
}
|
|
245
264
|
};
|