react-native-wgpu 0.1.0
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/LICENSE +20 -0
- package/README.md +31 -0
- package/android/CMakeLists.txt +74 -0
- package/android/build.gradle +166 -0
- package/android/cpp/cpp-adapter.cpp +12 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/AndroidManifestNew.xml +2 -0
- package/android/src/main/java/com/webgpu/WebGPUModule.java +39 -0
- package/android/src/main/java/com/webgpu/WebGPUView.java +24 -0
- package/android/src/main/java/com/webgpu/WebGPUViewManager.java +31 -0
- package/android/src/main/java/com/webgpu/WebGPUViewPackage.java +26 -0
- package/android/src/newarch/WgpuViewManagerSpec.java +24 -0
- package/android/src/oldarch/WebGPUViewManagerSpec.java +11 -0
- package/cpp/Logger.h +82 -0
- package/cpp/dawn/dawn_proc_table.h +308 -0
- package/cpp/dawn/webgpu.h +4201 -0
- package/cpp/dawn/webgpu_cpp.h +8985 -0
- package/cpp/dawn/webgpu_cpp_print.h +2460 -0
- package/cpp/dawn/wire/client/webgpu.h +339 -0
- package/cpp/dawn/wire/client/webgpu_cpp.h +9140 -0
- package/cpp/jsi/RNFEnumMapper.h +49 -0
- package/cpp/jsi/RNFHybridObject.cpp +145 -0
- package/cpp/jsi/RNFHybridObject.h +162 -0
- package/cpp/jsi/RNFJSIConverter.h +412 -0
- package/cpp/jsi/RNFJSIHelper.h +49 -0
- package/cpp/jsi/RNFPointerHolder.h +95 -0
- package/cpp/jsi/RNFPromise.cpp +45 -0
- package/cpp/jsi/RNFPromise.h +38 -0
- package/cpp/jsi/RNFRuntimeCache.cpp +57 -0
- package/cpp/jsi/RNFRuntimeCache.h +79 -0
- package/cpp/jsi/RNFWorkletRuntimeCollector.h +43 -0
- package/cpp/jsi/RNFWorkletRuntimeRegistry.cpp +11 -0
- package/cpp/jsi/RNFWorkletRuntimeRegistry.h +44 -0
- package/cpp/rnwgpu/MutableBuffer.h +48 -0
- package/cpp/rnwgpu/RNWebGPUManager.cpp +60 -0
- package/cpp/rnwgpu/RNWebGPUManager.h +30 -0
- package/cpp/rnwgpu/api/GPU.cpp +40 -0
- package/cpp/rnwgpu/api/GPU.h +43 -0
- package/cpp/rnwgpu/api/GPUAdapter.cpp +33 -0
- package/cpp/rnwgpu/api/GPUAdapter.h +40 -0
- package/cpp/rnwgpu/api/GPUAdapterInfo.h +33 -0
- package/cpp/rnwgpu/api/GPUBindGroup.h +38 -0
- package/cpp/rnwgpu/api/GPUBindGroupLayout.h +39 -0
- package/cpp/rnwgpu/api/GPUBuffer.cpp +16 -0
- package/cpp/rnwgpu/api/GPUBuffer.h +44 -0
- package/cpp/rnwgpu/api/GPUCanvasContext.h +33 -0
- package/cpp/rnwgpu/api/GPUCommandBuffer.h +38 -0
- package/cpp/rnwgpu/api/GPUCommandEncoder.h +38 -0
- package/cpp/rnwgpu/api/GPUCompilationInfo.h +33 -0
- package/cpp/rnwgpu/api/GPUCompilationMessage.h +33 -0
- package/cpp/rnwgpu/api/GPUComputePassEncoder.h +40 -0
- package/cpp/rnwgpu/api/GPUComputePipeline.h +39 -0
- package/cpp/rnwgpu/api/GPUDevice.cpp +12 -0
- package/cpp/rnwgpu/api/GPUDevice.h +45 -0
- package/cpp/rnwgpu/api/GPUDeviceLostInfo.h +33 -0
- package/cpp/rnwgpu/api/GPUExternalTexture.h +39 -0
- package/cpp/rnwgpu/api/GPUPipelineLayout.h +38 -0
- package/cpp/rnwgpu/api/GPUQuerySet.h +38 -0
- package/cpp/rnwgpu/api/GPUQueue.h +38 -0
- package/cpp/rnwgpu/api/GPURenderBundle.h +38 -0
- package/cpp/rnwgpu/api/GPURenderBundleEncoder.h +40 -0
- package/cpp/rnwgpu/api/GPURenderPassEncoder.h +40 -0
- package/cpp/rnwgpu/api/GPURenderPipeline.h +38 -0
- package/cpp/rnwgpu/api/GPUSampler.h +38 -0
- package/cpp/rnwgpu/api/GPUShaderModule.h +38 -0
- package/cpp/rnwgpu/api/GPUSupportedLimits.h +33 -0
- package/cpp/rnwgpu/api/GPUTexture.h +38 -0
- package/cpp/rnwgpu/api/GPUTextureView.h +38 -0
- package/cpp/rnwgpu/api/GPUUncapturedErrorEvent.h +33 -0
- package/cpp/rnwgpu/api/descriptors/GPUBindGroupDescriptor.h +81 -0
- package/cpp/rnwgpu/api/descriptors/GPUBindGroupEntry.h +67 -0
- package/cpp/rnwgpu/api/descriptors/GPUBindGroupLayoutDescriptor.h +69 -0
- package/cpp/rnwgpu/api/descriptors/GPUBindGroupLayoutEntry.h +95 -0
- package/cpp/rnwgpu/api/descriptors/GPUBlendComponent.h +56 -0
- package/cpp/rnwgpu/api/descriptors/GPUBlendState.h +65 -0
- package/cpp/rnwgpu/api/descriptors/GPUBufferBinding.h +72 -0
- package/cpp/rnwgpu/api/descriptors/GPUBufferBindingLayout.h +62 -0
- package/cpp/rnwgpu/api/descriptors/GPUBufferDescriptor.h +85 -0
- package/cpp/rnwgpu/api/descriptors/GPUBufferUsage.h +43 -0
- package/cpp/rnwgpu/api/descriptors/GPUCanvasConfiguration.h +93 -0
- package/cpp/rnwgpu/api/descriptors/GPUColorDict.h +81 -0
- package/cpp/rnwgpu/api/descriptors/GPUColorTargetState.h +69 -0
- package/cpp/rnwgpu/api/descriptors/GPUColorWrite.h +31 -0
- package/cpp/rnwgpu/api/descriptors/GPUComputePassDescriptor.h +62 -0
- package/cpp/rnwgpu/api/descriptors/GPUComputePassTimestampWrites.h +80 -0
- package/cpp/rnwgpu/api/descriptors/GPUComputePipelineDescriptor.h +82 -0
- package/cpp/rnwgpu/api/descriptors/GPUDepthStencilState.h +126 -0
- package/cpp/rnwgpu/api/descriptors/GPUDeviceDescriptor.h +69 -0
- package/cpp/rnwgpu/api/descriptors/GPUExtent3DDict.h +76 -0
- package/cpp/rnwgpu/api/descriptors/GPUExtent3DDictStrict.h +91 -0
- package/cpp/rnwgpu/api/descriptors/GPUExternalTextureBindingLayout.h +44 -0
- package/cpp/rnwgpu/api/descriptors/GPUExternalTextureDescriptor.h +75 -0
- package/cpp/rnwgpu/api/descriptors/GPUFragmentState.h +85 -0
- package/cpp/rnwgpu/api/descriptors/GPUImageCopyBuffer.h +83 -0
- package/cpp/rnwgpu/api/descriptors/GPUImageCopyExternalImage.h +66 -0
- package/cpp/rnwgpu/api/descriptors/GPUImageCopyTexture.h +74 -0
- package/cpp/rnwgpu/api/descriptors/GPUImageCopyTextureTagged.h +88 -0
- package/cpp/rnwgpu/api/descriptors/GPUImageDataLayout.h +70 -0
- package/cpp/rnwgpu/api/descriptors/GPUMapMode.h +25 -0
- package/cpp/rnwgpu/api/descriptors/GPUMultisampleState.h +68 -0
- package/cpp/rnwgpu/api/descriptors/GPUOrigin2DDict.h +61 -0
- package/cpp/rnwgpu/api/descriptors/GPUOrigin2DDictStrict.h +75 -0
- package/cpp/rnwgpu/api/descriptors/GPUOrigin3DDict.h +71 -0
- package/cpp/rnwgpu/api/descriptors/GPUPipelineErrorInit.h +54 -0
- package/cpp/rnwgpu/api/descriptors/GPUPipelineLayoutDescriptor.h +72 -0
- package/cpp/rnwgpu/api/descriptors/GPUPrimitiveState.h +66 -0
- package/cpp/rnwgpu/api/descriptors/GPUProgrammableStage.h +72 -0
- package/cpp/rnwgpu/api/descriptors/GPUQuerySetDescriptor.h +81 -0
- package/cpp/rnwgpu/api/descriptors/GPURenderBundleEncoderDescriptor.h +102 -0
- package/cpp/rnwgpu/api/descriptors/GPURenderPassColorAttachment.h +105 -0
- package/cpp/rnwgpu/api/descriptors/GPURenderPassDepthStencilAttachment.h +118 -0
- package/cpp/rnwgpu/api/descriptors/GPURenderPassDescriptor.h +100 -0
- package/cpp/rnwgpu/api/descriptors/GPURenderPassLayout.h +83 -0
- package/cpp/rnwgpu/api/descriptors/GPURenderPassTimestampWrites.h +80 -0
- package/cpp/rnwgpu/api/descriptors/GPURenderPipelineDescriptor.h +104 -0
- package/cpp/rnwgpu/api/descriptors/GPURequestAdapterOptions.h +56 -0
- package/cpp/rnwgpu/api/descriptors/GPUSamplerBindingLayout.h +48 -0
- package/cpp/rnwgpu/api/descriptors/GPUSamplerDescriptor.h +116 -0
- package/cpp/rnwgpu/api/descriptors/GPUShaderModuleCompilationHint.h +64 -0
- package/cpp/rnwgpu/api/descriptors/GPUShaderModuleDescriptor.h +88 -0
- package/cpp/rnwgpu/api/descriptors/GPUShaderStage.h +27 -0
- package/cpp/rnwgpu/api/descriptors/GPUStencilFaceState.h +61 -0
- package/cpp/rnwgpu/api/descriptors/GPUStorageTextureBindingLayout.h +67 -0
- package/cpp/rnwgpu/api/descriptors/GPUTextureBindingLayout.h +58 -0
- package/cpp/rnwgpu/api/descriptors/GPUTextureDescriptor.h +123 -0
- package/cpp/rnwgpu/api/descriptors/GPUTextureUsage.h +40 -0
- package/cpp/rnwgpu/api/descriptors/GPUTextureViewDescriptor.h +113 -0
- package/cpp/rnwgpu/api/descriptors/GPUUncapturedErrorEventInit.h +71 -0
- package/cpp/rnwgpu/api/descriptors/GPUVertexAttribute.h +80 -0
- package/cpp/rnwgpu/api/descriptors/GPUVertexBufferLayout.h +73 -0
- package/cpp/rnwgpu/api/descriptors/GPUVertexState.h +77 -0
- package/cpp/rnwgpu/api/descriptors/Unions.h +1645 -0
- package/cpp/webgpu/webgpu.h +33 -0
- package/cpp/webgpu/webgpu_cpp.h +33 -0
- package/cpp/webgpu/webgpu_cpp_chained_struct.h +55 -0
- package/cpp/webgpu/webgpu_enum_class_bitmasks.h +161 -0
- package/ios/RNFAppleLogger.mm +22 -0
- package/ios/Utils.h +5 -0
- package/ios/Utils.m +26 -0
- package/ios/WebGPUModule.h +18 -0
- package/ios/WebGPUModule.mm +77 -0
- package/ios/WebGPUView.h +15 -0
- package/ios/WebGPUView.mm +58 -0
- package/ios/WebGPUViewManager.mm +21 -0
- package/lib/commonjs/WebGPUNativeModule.js +10 -0
- package/lib/commonjs/WebGPUNativeModule.js.map +1 -0
- package/lib/commonjs/WebGPUViewNativeComponent.js +11 -0
- package/lib/commonjs/WebGPUViewNativeComponent.js.map +1 -0
- package/lib/commonjs/index.js +45 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/module/WebGPUNativeModule.js +4 -0
- package/lib/module/WebGPUNativeModule.js.map +1 -0
- package/lib/module/WebGPUViewNativeComponent.js +4 -0
- package/lib/module/WebGPUViewNativeComponent.js.map +1 -0
- package/lib/module/index.js +9 -0
- package/lib/module/index.js.map +1 -0
- package/lib/typescript/babel.config.d.ts +2 -0
- package/lib/typescript/babel.config.d.ts.map +1 -0
- package/lib/typescript/jest.config.d.ts +5 -0
- package/lib/typescript/jest.config.d.ts.map +1 -0
- package/lib/typescript/lib/commonjs/WebGPUNativeModule.d.ts +5 -0
- package/lib/typescript/lib/commonjs/WebGPUNativeModule.d.ts.map +1 -0
- package/lib/typescript/lib/commonjs/WebGPUViewNativeComponent.d.ts +4 -0
- package/lib/typescript/lib/commonjs/WebGPUViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/lib/commonjs/index.d.ts +5 -0
- package/lib/typescript/lib/commonjs/index.d.ts.map +1 -0
- package/lib/typescript/lib/module/WebGPUNativeModule.d.ts +3 -0
- package/lib/typescript/lib/module/WebGPUNativeModule.d.ts.map +1 -0
- package/lib/typescript/lib/module/WebGPUViewNativeComponent.d.ts +4 -0
- package/lib/typescript/lib/module/WebGPUViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/lib/module/index.d.ts +5 -0
- package/lib/typescript/lib/module/index.d.ts.map +1 -0
- package/lib/typescript/scripts/build/copy-artifacts.d.ts +2 -0
- package/lib/typescript/scripts/build/copy-artifacts.d.ts.map +1 -0
- package/lib/typescript/scripts/build/dawn.d.ts +2 -0
- package/lib/typescript/scripts/build/dawn.d.ts.map +1 -0
- package/lib/typescript/scripts/build/util.d.ts +13 -0
- package/lib/typescript/scripts/build/util.d.ts.map +1 -0
- package/lib/typescript/scripts/codegen/codegen.d.ts +2 -0
- package/lib/typescript/scripts/codegen/codegen.d.ts.map +1 -0
- package/lib/typescript/scripts/codegen/model/dawn.d.ts +2 -0
- package/lib/typescript/scripts/codegen/model/dawn.d.ts.map +1 -0
- package/lib/typescript/scripts/codegen/model/model.d.ts +8 -0
- package/lib/typescript/scripts/codegen/model/model.d.ts.map +1 -0
- package/lib/typescript/scripts/codegen/templates/Descriptor.d.ts +4 -0
- package/lib/typescript/scripts/codegen/templates/Descriptor.d.ts.map +1 -0
- package/lib/typescript/scripts/codegen/templates/Enum.d.ts +3 -0
- package/lib/typescript/scripts/codegen/templates/Enum.d.ts.map +1 -0
- package/lib/typescript/scripts/codegen/templates/HybridObject.d.ts +3 -0
- package/lib/typescript/scripts/codegen/templates/HybridObject.d.ts.map +1 -0
- package/lib/typescript/scripts/codegen/templates/Unions.d.ts +6 -0
- package/lib/typescript/scripts/codegen/templates/Unions.d.ts.map +1 -0
- package/lib/typescript/scripts/codegen/templates/common.d.ts +9 -0
- package/lib/typescript/scripts/codegen/templates/common.d.ts.map +1 -0
- package/lib/typescript/scripts/codegen/util.d.ts +2 -0
- package/lib/typescript/scripts/codegen/util.d.ts.map +1 -0
- package/lib/typescript/src/WebGPUNativeModule.d.ts +7 -0
- package/lib/typescript/src/WebGPUNativeModule.d.ts.map +1 -0
- package/lib/typescript/src/WebGPUViewNativeComponent.d.ts +8 -0
- package/lib/typescript/src/WebGPUViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +9 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/package.json +120 -0
- package/react-native-webgpu.podspec +56 -0
- package/src/WebGPUNativeModule.ts +9 -0
- package/src/WebGPUViewNativeComponent.ts +9 -0
- package/src/index.tsx +13 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Created by Marc Rousavy on 22.02.24.
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
#pragma once
|
|
6
|
+
|
|
7
|
+
#include <stdexcept>
|
|
8
|
+
#include <string>
|
|
9
|
+
|
|
10
|
+
namespace margelo {
|
|
11
|
+
|
|
12
|
+
namespace EnumMapper {
|
|
13
|
+
// Add these two methods in namespace "EnumMapper" to allow parsing a custom enum:
|
|
14
|
+
// 1. `static void convertJSUnionToEnum(const std::string& inUnion, Enum* outEnum)`
|
|
15
|
+
// 2. `static void convertEnumToJSUnion(Enum inEnum, std::string* outUnion)`
|
|
16
|
+
|
|
17
|
+
static std::runtime_error invalidUnion(const std::string& passedUnion) {
|
|
18
|
+
return std::runtime_error("Cannot convert JS Value to Enum: Invalid Union value passed! (\"" + std::string(passedUnion) + "\")");
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
template <typename T> static std::runtime_error invalidEnum(T passedEnum) {
|
|
22
|
+
return std::runtime_error("Cannot convert Enum to JS Value: Invalid Enum passed! (Value #" +
|
|
23
|
+
std::to_string(static_cast<int>(passedEnum)) + ")");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Trait to check if a convertJSUnionToEnum function for enum type T exists
|
|
27
|
+
template <typename T, typename = void> struct has_js_union_to_enum : std::false_type {};
|
|
28
|
+
template <typename T>
|
|
29
|
+
struct has_js_union_to_enum<T, std::void_t<decltype(convertJSUnionToEnum(std::declval<std::string>(), std::declval<T*>()))>>
|
|
30
|
+
: std::true_type {};
|
|
31
|
+
|
|
32
|
+
// Trait to check if a convertEnumToJSUnion function for enum type T exists
|
|
33
|
+
template <typename T, typename = void> struct has_enum_to_js_union : std::false_type {};
|
|
34
|
+
template <typename T>
|
|
35
|
+
struct has_enum_to_js_union<T, std::void_t<decltype(convertEnumToJSUnion(std::declval<T>(), std::declval<std::string*>()))>>
|
|
36
|
+
: std::true_type {};
|
|
37
|
+
|
|
38
|
+
template <typename TEnum> static void convertJSUnionToEnum(const std::string&, TEnum*) {
|
|
39
|
+
static_assert(has_js_union_to_enum<TEnum>::value,
|
|
40
|
+
"Cannot convert a JS union to this enum type. Did you implement EnumMapper::convertJSUnionToEnum(...)?");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
template <typename TEnum> static void convertEnumToJSUnion(TEnum, std::string*) {
|
|
44
|
+
static_assert(has_enum_to_js_union<TEnum>::value,
|
|
45
|
+
"Cannot convert this enum type to a JS union. Did you implement EnumMapper::convertEnumToJSUnion(...)?");
|
|
46
|
+
}
|
|
47
|
+
} // namespace EnumMapper
|
|
48
|
+
|
|
49
|
+
} // namespace margelo
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Created by Marc Rousavy on 21.02.24.
|
|
3
|
+
//
|
|
4
|
+
#include "RNFHybridObject.h"
|
|
5
|
+
#include "RNFJSIConverter.h"
|
|
6
|
+
#include "Logger.h"
|
|
7
|
+
|
|
8
|
+
#include <vector>
|
|
9
|
+
#include <utility>
|
|
10
|
+
#include <string>
|
|
11
|
+
|
|
12
|
+
namespace margelo {
|
|
13
|
+
|
|
14
|
+
#if DEBUG && RNF_ENABLE_LOGS
|
|
15
|
+
static std::unordered_map<const char*, int> _instanceIds;
|
|
16
|
+
static std::mutex _mutex;
|
|
17
|
+
|
|
18
|
+
static int getId(const char* name) {
|
|
19
|
+
std::unique_lock lock(_mutex);
|
|
20
|
+
if (_instanceIds.find(name) == _instanceIds.end()) {
|
|
21
|
+
_instanceIds.insert({name, 1});
|
|
22
|
+
}
|
|
23
|
+
auto iterator = _instanceIds.find(name);
|
|
24
|
+
return iterator->second++;
|
|
25
|
+
}
|
|
26
|
+
#endif
|
|
27
|
+
|
|
28
|
+
HybridObject::HybridObject(const char* name) : _name(name) {
|
|
29
|
+
#if DEBUG && RNF_ENABLE_LOGS
|
|
30
|
+
_instanceId = getId(name);
|
|
31
|
+
Logger::logToConsole(TAG, "(MEMORY) Creating %s (#%i)... ✅", _name, _instanceId);
|
|
32
|
+
#endif
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
HybridObject::~HybridObject() {
|
|
36
|
+
#if DEBUG && RNF_ENABLE_LOGS
|
|
37
|
+
Logger::log(TAG, "(MEMORY) Deleting %s (#%i)... ❌", _name, _instanceId);
|
|
38
|
+
#endif
|
|
39
|
+
_functionCache.clear();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
std::string HybridObject::toString(jsi::Runtime& runtime) {
|
|
43
|
+
std::string result = std::string(_name) + " { ";
|
|
44
|
+
std::vector<jsi::PropNameID> props = getPropertyNames(runtime);
|
|
45
|
+
for (size_t i = 0; i < props.size(); i++) {
|
|
46
|
+
auto suffix = i < props.size() - 1 ? ", " : " ";
|
|
47
|
+
result += "\"" + props[i].utf8(runtime) + "\"" + suffix;
|
|
48
|
+
}
|
|
49
|
+
return result + "}";
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
std::vector<jsi::PropNameID> HybridObject::getPropertyNames(facebook::jsi::Runtime& runtime) {
|
|
53
|
+
std::unique_lock lock(_mutex);
|
|
54
|
+
ensureInitialized(runtime);
|
|
55
|
+
|
|
56
|
+
std::vector<jsi::PropNameID> result;
|
|
57
|
+
size_t totalSize = _methods.size() + _getters.size() + _setters.size();
|
|
58
|
+
result.reserve(totalSize);
|
|
59
|
+
|
|
60
|
+
for (const auto& item : _methods) {
|
|
61
|
+
result.push_back(jsi::PropNameID::forUtf8(runtime, item.first));
|
|
62
|
+
}
|
|
63
|
+
for (const auto& item : _getters) {
|
|
64
|
+
result.push_back(jsi::PropNameID::forUtf8(runtime, item.first));
|
|
65
|
+
}
|
|
66
|
+
for (const auto& item : _setters) {
|
|
67
|
+
result.push_back(jsi::PropNameID::forUtf8(runtime, item.first));
|
|
68
|
+
}
|
|
69
|
+
return result;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
jsi::Value HybridObject::get(facebook::jsi::Runtime& runtime, const facebook::jsi::PropNameID& propName) {
|
|
73
|
+
std::unique_lock lock(_mutex);
|
|
74
|
+
ensureInitialized(runtime);
|
|
75
|
+
|
|
76
|
+
std::string name = propName.utf8(runtime);
|
|
77
|
+
auto& functionCache = _functionCache[&runtime];
|
|
78
|
+
|
|
79
|
+
if (_getters.count(name) > 0) {
|
|
80
|
+
// it's a property getter
|
|
81
|
+
return _getters[name](runtime, jsi::Value::undefined(), nullptr, 0);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (functionCache.count(name) > 0) {
|
|
85
|
+
[[likely]];
|
|
86
|
+
// cache hit
|
|
87
|
+
return jsi::Value(runtime, *functionCache[name]);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (_methods.count(name) > 0) {
|
|
91
|
+
// cache miss - create jsi::Function and cache it.
|
|
92
|
+
HybridFunction& hybridFunction = _methods.at(name);
|
|
93
|
+
jsi::Function function = jsi::Function::createFromHostFunction(runtime, jsi::PropNameID::forUtf8(runtime, name),
|
|
94
|
+
hybridFunction.parameterCount, hybridFunction.function);
|
|
95
|
+
|
|
96
|
+
functionCache[name] = JSIHelper::createSharedJsiFunction(runtime, std::move(function));
|
|
97
|
+
return jsi::Value(runtime, *functionCache[name]);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (name == "toString") {
|
|
101
|
+
return jsi::Function::createFromHostFunction(
|
|
102
|
+
runtime, jsi::PropNameID::forUtf8(runtime, "toString"), 0,
|
|
103
|
+
[=](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* args, size_t count) -> jsi::Value {
|
|
104
|
+
std::string stringRepresentation = this->toString(runtime);
|
|
105
|
+
return jsi::String::createFromUtf8(runtime, stringRepresentation);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return jsi::HostObject::get(runtime, propName);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
void HybridObject::set(facebook::jsi::Runtime& runtime, const facebook::jsi::PropNameID& propName, const facebook::jsi::Value& value) {
|
|
113
|
+
std::unique_lock lock(_mutex);
|
|
114
|
+
ensureInitialized(runtime);
|
|
115
|
+
|
|
116
|
+
std::string name = propName.utf8(runtime);
|
|
117
|
+
|
|
118
|
+
if (_setters.count(name) > 0) {
|
|
119
|
+
// Call setter
|
|
120
|
+
_setters[name](runtime, jsi::Value::undefined(), &value, 1);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
HostObject::set(runtime, propName, value);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
void HybridObject::ensureInitialized(facebook::jsi::Runtime& runtime) {
|
|
128
|
+
if (!_didLoadMethods) {
|
|
129
|
+
[[unlikely]];
|
|
130
|
+
_creationRuntime = &runtime;
|
|
131
|
+
// lazy-load all exposed methods
|
|
132
|
+
loadHybridMethods();
|
|
133
|
+
_didLoadMethods = true;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
bool HybridObject::isRuntimeAlive() {
|
|
138
|
+
if (_creationRuntime == nullptr) {
|
|
139
|
+
[[unlikely]];
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
return RNFWorkletRuntimeRegistry::isRuntimeAlive(_creationRuntime);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
} // namespace margelo
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Created by Marc Rousavy on 21.02.24.
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
#pragma once
|
|
6
|
+
|
|
7
|
+
#include "RNFJSIConverter.h"
|
|
8
|
+
#include "Logger.h"
|
|
9
|
+
#include "RNFWorkletRuntimeRegistry.h"
|
|
10
|
+
#include <functional>
|
|
11
|
+
#include <jsi/jsi.h>
|
|
12
|
+
#include <memory>
|
|
13
|
+
#include <mutex>
|
|
14
|
+
#include <type_traits>
|
|
15
|
+
#include <unordered_map>
|
|
16
|
+
#include <vector>
|
|
17
|
+
#include <utility>
|
|
18
|
+
#include <string>
|
|
19
|
+
|
|
20
|
+
namespace margelo {
|
|
21
|
+
|
|
22
|
+
namespace jsi = facebook::jsi;
|
|
23
|
+
|
|
24
|
+
class HybridObject : public jsi::HostObject, public std::enable_shared_from_this<HybridObject> {
|
|
25
|
+
public:
|
|
26
|
+
struct HybridFunction {
|
|
27
|
+
jsi::HostFunctionType function;
|
|
28
|
+
size_t parameterCount;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
public:
|
|
32
|
+
explicit HybridObject(const char* name);
|
|
33
|
+
~HybridObject();
|
|
34
|
+
|
|
35
|
+
void set(jsi::Runtime&, const jsi::PropNameID& name, const jsi::Value& value) override;
|
|
36
|
+
jsi::Value get(jsi::Runtime& runtime, const jsi::PropNameID& propName) override;
|
|
37
|
+
std::vector<jsi::PropNameID> getPropertyNames(jsi::Runtime& runtime) override;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Get the `std::shared_ptr` instance of this HybridObject.
|
|
41
|
+
* The HybridObject must be managed inside a `shared_ptr` already, otherwise this will fail.
|
|
42
|
+
*/
|
|
43
|
+
template <typename Derived> std::shared_ptr<Derived> shared() {
|
|
44
|
+
return std::static_pointer_cast<Derived>(shared_from_this());
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Loads all native methods of this `HybridObject` to be exposed to JavaScript.
|
|
49
|
+
* Example:
|
|
50
|
+
*
|
|
51
|
+
* ```cpp
|
|
52
|
+
* int User::getAge() {
|
|
53
|
+
* return 23;
|
|
54
|
+
* }
|
|
55
|
+
*
|
|
56
|
+
* void User::loadHybridMethods() {
|
|
57
|
+
* registerHybridMethod("getAge", &User::getAge, this);
|
|
58
|
+
* }
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
virtual void loadHybridMethods() = 0;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Get a string representation of this HostObject, useful for logging or debugging.
|
|
65
|
+
*/
|
|
66
|
+
virtual std::string toString(jsi::Runtime& runtime);
|
|
67
|
+
|
|
68
|
+
private:
|
|
69
|
+
static constexpr auto TAG = "HybridObject";
|
|
70
|
+
int _instanceId = 1;
|
|
71
|
+
bool _didLoadMethods = false;
|
|
72
|
+
std::mutex _mutex;
|
|
73
|
+
std::unordered_map<std::string, HybridFunction> _methods;
|
|
74
|
+
std::unordered_map<std::string, jsi::HostFunctionType> _getters;
|
|
75
|
+
std::unordered_map<std::string, jsi::HostFunctionType> _setters;
|
|
76
|
+
std::unordered_map<jsi::Runtime*, std::unordered_map<std::string, std::shared_ptr<jsi::Function>>> _functionCache;
|
|
77
|
+
// Store a pointer to the runtime. Needed for checking if the runtime is still active, see WorkletRuntimeRegistry.
|
|
78
|
+
jsi::Runtime* _creationRuntime = nullptr;
|
|
79
|
+
|
|
80
|
+
protected:
|
|
81
|
+
const char* _name = TAG;
|
|
82
|
+
|
|
83
|
+
private:
|
|
84
|
+
inline void ensureInitialized(facebook::jsi::Runtime& runtime);
|
|
85
|
+
|
|
86
|
+
private:
|
|
87
|
+
template <typename Derived, typename ReturnType, typename... Args, size_t... Is>
|
|
88
|
+
static inline jsi::Value callMethod(Derived* obj, ReturnType (Derived::*method)(Args...), jsi::Runtime& runtime, const jsi::Value* args,
|
|
89
|
+
std::index_sequence<Is...>, size_t count) {
|
|
90
|
+
if constexpr (std::is_same_v<ReturnType, void>) {
|
|
91
|
+
// It's a void method.
|
|
92
|
+
(obj->*method)(JSIConverter<std::decay_t<Args>>::fromJSI(runtime, args[Is])...);
|
|
93
|
+
return jsi::Value::undefined();
|
|
94
|
+
} else {
|
|
95
|
+
// It's returning some C++ type, we need to convert that to a JSI value now.
|
|
96
|
+
ReturnType result = (obj->*method)(JSIConverter<std::decay_t<Args>>::fromJSI(runtime, args[Is], Is >= count)...);
|
|
97
|
+
return JSIConverter<std::decay_t<ReturnType>>::toJSI(runtime, std::move(result));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
template <typename Derived, typename ReturnType, typename... Args>
|
|
102
|
+
static jsi::HostFunctionType createHybridMethod(ReturnType (Derived::*method)(Args...), Derived* derivedInstance) {
|
|
103
|
+
|
|
104
|
+
return [derivedInstance, method](jsi::Runtime& runtime, const jsi::Value& thisVal, const jsi::Value* args, size_t count) -> jsi::Value {
|
|
105
|
+
if constexpr (std::is_same_v<ReturnType, jsi::Value>) {
|
|
106
|
+
// If the return type is a jsi::Value, we assume the user wants full JSI code control.
|
|
107
|
+
// The signature must be identical to jsi::HostFunction (jsi::Runtime&, jsi::Value& this, ...)
|
|
108
|
+
return (derivedInstance->*method)(runtime, thisVal, args, count);
|
|
109
|
+
} else {
|
|
110
|
+
// Call the actual method with JSI values as arguments and return a JSI value again.
|
|
111
|
+
// Internally, this method converts the JSI values to C++ values.
|
|
112
|
+
return callMethod(derivedInstance, method, runtime, args, std::index_sequence_for<Args...>{}, count);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
protected:
|
|
118
|
+
template <typename Derived, typename ReturnType, typename... Args>
|
|
119
|
+
void registerHybridMethod(std::string name, ReturnType (Derived::*method)(Args...), Derived* derivedInstance, bool override = false) {
|
|
120
|
+
if (!override && (_getters.count(name) > 0 || _setters.count(name) > 0)) {
|
|
121
|
+
[[unlikely]];
|
|
122
|
+
throw std::runtime_error("Cannot add Hybrid Method \"" + name + "\" - a property with that name already exists!");
|
|
123
|
+
}
|
|
124
|
+
if (!override && (_methods.count(name) > 0)) {
|
|
125
|
+
throw std::runtime_error("Cannot add Hybrid Method \"" + name + "\" - a method with that name already exists!");
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
_methods[name] = HybridFunction{.function = createHybridMethod(method, derivedInstance), .parameterCount = sizeof...(Args)};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
template <typename Derived, typename ReturnType>
|
|
132
|
+
void registerHybridGetter(std::string name, ReturnType (Derived::*method)(), Derived* derivedInstance) {
|
|
133
|
+
if (_getters.count(name) > 0) {
|
|
134
|
+
[[unlikely]];
|
|
135
|
+
throw std::runtime_error("Cannot add Hybrid Property Getter \"" + name + "\" - a getter with that name already exists!");
|
|
136
|
+
}
|
|
137
|
+
if (_methods.count(name) > 0) {
|
|
138
|
+
[[unlikely]];
|
|
139
|
+
throw std::runtime_error("Cannot add Hybrid Property Getter \"" + name + "\" - a method with that name already exists!");
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
_getters[name] = createHybridMethod(method, derivedInstance);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
template <typename Derived, typename ValueType>
|
|
146
|
+
void registerHybridSetter(std::string name, void (Derived::*method)(ValueType), Derived* derivedInstance) {
|
|
147
|
+
if (_setters.count(name) > 0) {
|
|
148
|
+
[[unlikely]];
|
|
149
|
+
throw std::runtime_error("Cannot add Hybrid Property Setter \"" + name + "\" - a setter with that name already exists!");
|
|
150
|
+
}
|
|
151
|
+
if (_methods.count(name) > 0) {
|
|
152
|
+
[[unlikely]];
|
|
153
|
+
throw std::runtime_error("Cannot add Hybrid Property Setter \"" + name + "\" - a method with that name already exists!");
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
_setters[name] = createHybridMethod(method, derivedInstance);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
bool isRuntimeAlive();
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
} // namespace margelo
|