react-native-webgpu 0.5.14 → 0.5.15

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.
Files changed (79) hide show
  1. package/README.md +19 -6
  2. package/android/CMakeLists.txt +2 -2
  3. package/cpp/jsi/NativeObject.h +39 -0
  4. package/cpp/rnwgpu/RNWebGPUManager.cpp +8 -0
  5. package/cpp/rnwgpu/SurfaceRegistry.h +33 -1
  6. package/cpp/rnwgpu/api/GPU.cpp +14 -11
  7. package/cpp/rnwgpu/api/GPU.h +6 -4
  8. package/cpp/rnwgpu/api/GPUAdapter.cpp +5 -8
  9. package/cpp/rnwgpu/api/GPUAdapter.h +3 -3
  10. package/cpp/rnwgpu/api/GPUBuffer.cpp +23 -24
  11. package/cpp/rnwgpu/api/GPUBuffer.h +3 -3
  12. package/cpp/rnwgpu/api/GPUCanvasContext.cpp +13 -16
  13. package/cpp/rnwgpu/api/GPUCanvasContext.h +3 -0
  14. package/cpp/rnwgpu/api/GPUDevice.cpp +103 -19
  15. package/cpp/rnwgpu/api/GPUDevice.h +17 -3
  16. package/cpp/rnwgpu/api/GPUQueue.h +3 -3
  17. package/cpp/rnwgpu/api/GPUShaderModule.h +3 -3
  18. package/cpp/rnwgpu/api/GPUSharedFence.cpp +77 -0
  19. package/cpp/rnwgpu/api/GPUSharedFence.h +53 -0
  20. package/cpp/rnwgpu/api/GPUSharedTextureMemory.cpp +60 -11
  21. package/cpp/rnwgpu/api/GPUSharedTextureMemory.h +13 -9
  22. package/cpp/rnwgpu/api/descriptors/GPUSharedFenceDescriptor.h +58 -0
  23. package/cpp/rnwgpu/api/descriptors/GPUSharedFenceState.h +51 -0
  24. package/cpp/rnwgpu/async/AsyncTaskHandle.cpp +55 -23
  25. package/cpp/rnwgpu/async/AsyncTaskHandle.h +8 -5
  26. package/cpp/rnwgpu/async/RuntimeContext.cpp +193 -0
  27. package/cpp/rnwgpu/async/RuntimeContext.h +122 -0
  28. package/lib/commonjs/Canvas.js.map +1 -1
  29. package/lib/commonjs/Offscreen.js +1 -1
  30. package/lib/commonjs/WebPolyfillGPUModule.js +2 -0
  31. package/lib/commonjs/WebPolyfillGPUModule.js.map +1 -1
  32. package/lib/commonjs/constants.js +40 -0
  33. package/lib/commonjs/constants.js.map +1 -0
  34. package/lib/commonjs/index.js +22 -0
  35. package/lib/commonjs/index.js.map +1 -1
  36. package/lib/commonjs/install.js +63 -0
  37. package/lib/commonjs/install.js.map +1 -0
  38. package/lib/module/Canvas.js.map +1 -1
  39. package/lib/module/Offscreen.js +1 -1
  40. package/lib/module/WebPolyfillGPUModule.js +2 -0
  41. package/lib/module/WebPolyfillGPUModule.js.map +1 -1
  42. package/lib/module/constants.js +34 -0
  43. package/lib/module/constants.js.map +1 -0
  44. package/lib/module/index.js +2 -0
  45. package/lib/module/index.js.map +1 -1
  46. package/lib/module/install.js +57 -0
  47. package/lib/module/install.js.map +1 -0
  48. package/lib/typescript/lib/commonjs/constants.d.ts +3 -0
  49. package/lib/typescript/lib/commonjs/constants.d.ts.map +1 -0
  50. package/lib/typescript/lib/commonjs/install.d.ts +35 -0
  51. package/lib/typescript/lib/commonjs/install.d.ts.map +1 -0
  52. package/lib/typescript/lib/module/constants.d.ts +6 -0
  53. package/lib/typescript/lib/module/constants.d.ts.map +1 -0
  54. package/lib/typescript/lib/module/index.d.ts +2 -0
  55. package/lib/typescript/lib/module/install.d.ts +2 -0
  56. package/lib/typescript/lib/module/install.d.ts.map +1 -0
  57. package/lib/typescript/src/Canvas.d.ts +9 -0
  58. package/lib/typescript/src/Canvas.d.ts.map +1 -1
  59. package/lib/typescript/src/constants.d.ts +6 -0
  60. package/lib/typescript/src/constants.d.ts.map +1 -0
  61. package/lib/typescript/src/index.d.ts +5 -2
  62. package/lib/typescript/src/index.d.ts.map +1 -1
  63. package/lib/typescript/src/install.d.ts +34 -0
  64. package/lib/typescript/src/install.d.ts.map +1 -0
  65. package/lib/typescript/src/types.d.ts +34 -2
  66. package/lib/typescript/src/types.d.ts.map +1 -1
  67. package/package.json +1 -1
  68. package/src/Canvas.tsx +9 -0
  69. package/src/Offscreen.ts +1 -1
  70. package/src/WebPolyfillGPUModule.ts +3 -3
  71. package/src/constants.ts +37 -0
  72. package/src/index.tsx +13 -2
  73. package/src/install.ts +61 -0
  74. package/src/types.ts +69 -3
  75. package/cpp/rnwgpu/async/AsyncDispatcher.h +0 -28
  76. package/cpp/rnwgpu/async/AsyncRunner.cpp +0 -215
  77. package/cpp/rnwgpu/async/AsyncRunner.h +0 -53
  78. package/cpp/rnwgpu/async/JSIMicrotaskDispatcher.cpp +0 -23
  79. package/cpp/rnwgpu/async/JSIMicrotaskDispatcher.h +0 -22
@@ -0,0 +1,51 @@
1
+ #pragma once
2
+
3
+ #include <cstdint>
4
+ #include <memory>
5
+
6
+ #include "webgpu/webgpu_cpp.h"
7
+
8
+ #include "JSIConverter.h"
9
+
10
+ #include "GPUSharedFence.h"
11
+
12
+ namespace jsi = facebook::jsi;
13
+
14
+ namespace rnwgpu {
15
+
16
+ // A fence and the timeline value to wait for / signal at.
17
+ struct GPUSharedFenceState {
18
+ std::shared_ptr<GPUSharedFence> fence;
19
+ uint64_t signaledValue = 0;
20
+ };
21
+
22
+ } // namespace rnwgpu
23
+
24
+ namespace rnwgpu {
25
+
26
+ template <> struct JSIConverter<std::shared_ptr<rnwgpu::GPUSharedFenceState>> {
27
+ static std::shared_ptr<rnwgpu::GPUSharedFenceState>
28
+ fromJSI(jsi::Runtime &runtime, const jsi::Value &arg, bool outOfBounds) {
29
+ auto result = std::make_unique<rnwgpu::GPUSharedFenceState>();
30
+ if (!outOfBounds && arg.isObject()) {
31
+ auto value = arg.getObject(runtime);
32
+ if (value.hasProperty(runtime, "fence")) {
33
+ auto prop = value.getProperty(runtime, "fence");
34
+ result->fence = JSIConverter<std::shared_ptr<GPUSharedFence>>::fromJSI(
35
+ runtime, prop, false);
36
+ }
37
+ if (value.hasProperty(runtime, "signaledValue")) {
38
+ auto prop = value.getProperty(runtime, "signaledValue");
39
+ result->signaledValue =
40
+ JSIConverter<uint64_t>::fromJSI(runtime, prop, false);
41
+ }
42
+ }
43
+ return result;
44
+ }
45
+ static jsi::Value toJSI(jsi::Runtime &runtime,
46
+ std::shared_ptr<rnwgpu::GPUSharedFenceState> arg) {
47
+ throw std::runtime_error("Invalid GPUSharedFenceState::toJSI()");
48
+ }
49
+ };
50
+
51
+ } // namespace rnwgpu
@@ -1,11 +1,13 @@
1
1
  #include "AsyncTaskHandle.h"
2
2
 
3
+ #include <memory>
3
4
  #include <string>
4
5
  #include <utility>
5
6
 
6
- #include "Promise.h"
7
+ #include <ReactCommon/CallInvoker.h>
7
8
 
8
- #include "AsyncRunner.h"
9
+ #include "Promise.h"
10
+ #include "RuntimeContext.h"
9
11
 
10
12
  namespace rnwgpu::async {
11
13
 
@@ -13,8 +15,8 @@ using Action = std::function<void(jsi::Runtime &, rnwgpu::Promise &)>;
13
15
 
14
16
  struct AsyncTaskHandle::State
15
17
  : public std::enable_shared_from_this<AsyncTaskHandle::State> {
16
- State(std::shared_ptr<AsyncRunner> runner, bool keepPumping)
17
- : runner(std::move(runner)), keepPumping(keepPumping) {}
18
+ State(std::shared_ptr<RuntimeContext> context, bool keepPumping)
19
+ : context(std::move(context)), keepPumping(keepPumping) {}
18
20
 
19
21
  void settle(Action action);
20
22
  void attachPromise(const std::shared_ptr<rnwgpu::Promise> &promise);
@@ -26,12 +28,12 @@ struct AsyncTaskHandle::State
26
28
  std::shared_ptr<rnwgpu::Promise> currentPromise();
27
29
 
28
30
  std::mutex mutex;
29
- std::weak_ptr<AsyncRunner> runner;
31
+ std::shared_ptr<RuntimeContext> context;
32
+ bool keepPumping;
30
33
  std::shared_ptr<rnwgpu::Promise> promise;
31
34
  std::optional<Action> pendingAction;
32
35
  bool settled = false;
33
36
  std::shared_ptr<State> keepAlive;
34
- bool keepPumping;
35
37
  };
36
38
 
37
39
  // MARK: - State helpers
@@ -77,30 +79,60 @@ void AsyncTaskHandle::State::attachPromise(
77
79
  }
78
80
 
79
81
  void AsyncTaskHandle::State::schedule(Action action) {
80
- auto runnerRef = runner.lock();
81
- if (!runnerRef) {
82
+ auto promiseRef = currentPromise();
83
+ if (!promiseRef) {
82
84
  return;
83
85
  }
84
86
 
85
- auto promiseRef = currentPromise();
86
- if (!promiseRef) {
87
- runnerRef->onTaskSettled(keepPumping);
87
+ if (!context) {
88
+ // No context (shouldn't happen): best-effort inline settle.
89
+ action(promiseRef->runtime, *promiseRef);
90
+ std::lock_guard<std::mutex> lock(mutex);
91
+ keepAlive.reset();
88
92
  return;
89
93
  }
90
94
 
91
- auto dispatcherRef = runnerRef->dispatcher();
92
- if (!dispatcherRef) {
93
- runnerRef->onTaskSettled(keepPumping);
95
+ auto self = shared_from_this();
96
+
97
+ if (!keepPumping) {
98
+ // Spontaneous task (e.g. device.lost): not driven by the ProcessEvents pump.
99
+ // Settle on the owning runtime's JS thread via its CallInvoker, which is
100
+ // wired only for the main JS runtime. A device created on a worklet runtime
101
+ // has no invoker, so its device.lost is dropped (best-effort; see the README
102
+ // "Threading model"). invokeAsync runs the closure on the main JS thread,
103
+ // where promiseRef->runtime lives for a main-runtime device.
104
+ auto invoker = context->callInvoker();
105
+ if (invoker) {
106
+ invoker->invokeAsync(
107
+ [self, action = std::move(action), promiseRef]() mutable {
108
+ action(promiseRef->runtime, *promiseRef);
109
+ std::lock_guard<std::mutex> lock(self->mutex);
110
+ self->keepAlive.reset();
111
+ });
112
+ } else {
113
+ std::lock_guard<std::mutex> lock(mutex);
114
+ keepAlive.reset();
115
+ }
94
116
  return;
95
117
  }
96
118
 
97
- dispatcherRef->post([self = shared_from_this(), action = std::move(action),
98
- runnerRef, promiseRef](jsi::Runtime &runtime) mutable {
99
- runnerRef->onTaskSettled(self->keepPumping);
100
- action(runtime, *promiseRef);
101
- std::lock_guard<std::mutex> lock(self->mutex);
102
- self->keepAlive.reset();
103
- });
119
+ // Pumping task (request/response op). The resolve/reject callback may fire on
120
+ // a thread that is NOT the owning runtime's thread: with a shared
121
+ // wgpu::Instance, another runtime's ProcessEvents() pump can consume this Dawn
122
+ // event. Touching the Promise's runtime off-thread would corrupt Hermes. So we
123
+ // deposit the actual settle (the only JSI-touching work) into the owning
124
+ // context's mailbox; the context drains it on its own thread during its next
125
+ // tick. The deposited closure captures only C++ state and runs no JSI until
126
+ // drained, so depositing from any thread is safe.
127
+ context->postSettle(
128
+ [self, action = std::move(action), promiseRef]() mutable {
129
+ action(promiseRef->runtime, *promiseRef);
130
+ if (self->context) {
131
+ self->context->onTaskSettled(/*keepPumping=*/true);
132
+ }
133
+ std::lock_guard<std::mutex> lock(self->mutex);
134
+ self->keepAlive.reset();
135
+ });
104
136
  }
105
137
 
106
138
  AsyncTaskHandle::ResolveFunction
@@ -149,9 +181,9 @@ AsyncTaskHandle::AsyncTaskHandle(std::shared_ptr<State> state)
149
181
  bool AsyncTaskHandle::valid() const { return _state != nullptr; }
150
182
 
151
183
  AsyncTaskHandle
152
- AsyncTaskHandle::create(const std::shared_ptr<AsyncRunner> &runner,
184
+ AsyncTaskHandle::create(const std::shared_ptr<RuntimeContext> &context,
153
185
  bool keepPumping) {
154
- auto state = std::make_shared<State>(runner, keepPumping);
186
+ auto state = std::make_shared<State>(context, keepPumping);
155
187
  state->keepAlive = state;
156
188
  return AsyncTaskHandle(std::move(state));
157
189
  }
@@ -8,19 +8,22 @@
8
8
 
9
9
  #include <jsi/jsi.h>
10
10
 
11
- #include "AsyncDispatcher.h"
12
-
13
11
  namespace rnwgpu {
14
12
  class Promise;
15
13
  }
16
14
 
17
15
  namespace rnwgpu::async {
18
16
 
19
- class AsyncRunner;
17
+ class RuntimeContext;
20
18
 
21
19
  /**
22
20
  * Represents a pending asynchronous WebGPU operation that can be converted into
23
21
  * a JavaScript Promise.
22
+ *
23
+ * In the ProcessEvents model the resolve/reject callbacks are invoked on the
24
+ * owning runtime's own thread (synchronously from instance.ProcessEvents()
25
+ * during the RuntimeContext tick, or synchronously from postTask), so the
26
+ * Promise is settled directly without any thread marshalling.
24
27
  */
25
28
  class AsyncTaskHandle {
26
29
  public:
@@ -34,7 +37,7 @@ public:
34
37
  AsyncTaskHandle();
35
38
 
36
39
  /**
37
- * Internal constructor used by AsyncRunner.
40
+ * Internal constructor used by RuntimeContext.
38
41
  */
39
42
  explicit AsyncTaskHandle(std::shared_ptr<State> state);
40
43
 
@@ -45,7 +48,7 @@ public:
45
48
 
46
49
  void attachPromise(const std::shared_ptr<rnwgpu::Promise> &promise) const;
47
50
 
48
- static AsyncTaskHandle create(const std::shared_ptr<AsyncRunner> &runner,
51
+ static AsyncTaskHandle create(const std::shared_ptr<RuntimeContext> &context,
49
52
  bool keepPumping);
50
53
 
51
54
  private:
@@ -0,0 +1,193 @@
1
+ #include "RuntimeContext.h"
2
+
3
+ #include <memory>
4
+ #include <stdexcept>
5
+ #include <utility>
6
+
7
+ #include <ReactCommon/CallInvoker.h>
8
+
9
+ #include "AsyncTaskHandle.h"
10
+ #include "WGPULogger.h"
11
+
12
+ namespace rnwgpu::async {
13
+
14
+ namespace {
15
+ struct RuntimeData {
16
+ std::shared_ptr<RuntimeContext> context;
17
+ };
18
+ constexpr const char *TAG = "RuntimeContext";
19
+
20
+ // The main JS runtime and its CallInvoker, registered once on install. The
21
+ // context created for sMainRuntime gets sMainInvoker; spontaneous events
22
+ // (device.lost) on a main-runtime device are delivered through it without the
23
+ // pump. Worklet runtimes have no invoker (best-effort, see the header doc).
24
+ jsi::Runtime *sMainRuntime = nullptr;
25
+ std::shared_ptr<facebook::react::CallInvoker> sMainInvoker;
26
+
27
+ // Serializes ProcessEvents() across all runtimes that share a wgpu::Instance.
28
+ // Held only across the ProcessEvents call itself, never while running JS / mailbox
29
+ // settle-actions, so it cannot deadlock against the per-context mailbox mutex.
30
+ std::mutex &processEventsMutex() {
31
+ static std::mutex mutex;
32
+ return mutex;
33
+ }
34
+ } // namespace
35
+
36
+ void RuntimeContext::registerMainRuntime(
37
+ jsi::Runtime *runtime,
38
+ std::shared_ptr<facebook::react::CallInvoker> invoker) {
39
+ sMainRuntime = runtime;
40
+ sMainInvoker = std::move(invoker);
41
+ }
42
+
43
+ RuntimeContext::RuntimeContext(jsi::Runtime &runtime, wgpu::Instance instance)
44
+ : _runtime(runtime), _instance(std::move(instance)) {
45
+ Logger::logToConsole("[%s] Created (runtime=%p)", TAG, &runtime);
46
+ }
47
+
48
+ std::shared_ptr<RuntimeContext> RuntimeContext::get(jsi::Runtime &runtime) {
49
+ auto data = runtime.getRuntimeData(runtimeDataUUID());
50
+ if (!data) {
51
+ return nullptr;
52
+ }
53
+ return std::static_pointer_cast<RuntimeData>(data)->context;
54
+ }
55
+
56
+ std::shared_ptr<RuntimeContext>
57
+ RuntimeContext::getOrCreate(jsi::Runtime &runtime, wgpu::Instance instance) {
58
+ if (auto existing = get(runtime)) {
59
+ return existing;
60
+ }
61
+ auto context = std::make_shared<RuntimeContext>(runtime, std::move(instance));
62
+ // Only the main JS runtime's context carries the CallInvoker; it is used to
63
+ // deliver spontaneous events (device.lost) without the pump.
64
+ if (&runtime == sMainRuntime) {
65
+ context->_callInvoker = sMainInvoker;
66
+ }
67
+ auto data = std::make_shared<RuntimeData>();
68
+ data->context = context;
69
+ runtime.setRuntimeData(runtimeDataUUID(), data);
70
+ return context;
71
+ }
72
+
73
+ AsyncTaskHandle RuntimeContext::postTask(const TaskCallback &callback,
74
+ bool keepPumping) {
75
+ auto handle = AsyncTaskHandle::create(shared_from_this(), keepPumping);
76
+ if (!handle.valid()) {
77
+ throw std::runtime_error("Failed to create AsyncTaskHandle.");
78
+ }
79
+
80
+ // Only pumping tasks (request/response ops) drive the ProcessEvents pump.
81
+ // Spontaneous tasks (keepPumping == false, e.g. device.lost) never touch the
82
+ // pump: they settle via the CallInvoker (see AsyncTaskHandle::State::schedule).
83
+ if (keepPumping) {
84
+ _pumpTasks.fetch_add(1, std::memory_order_acq_rel);
85
+ requestTick();
86
+ }
87
+
88
+ auto resolve = handle.createResolveFunction();
89
+ auto reject = handle.createRejectFunction();
90
+ try {
91
+ callback(resolve, reject);
92
+ } catch (const std::exception &exception) {
93
+ reject(exception.what());
94
+ } catch (...) {
95
+ reject("Unknown native error in RuntimeContext::postTask.");
96
+ }
97
+ return handle;
98
+ }
99
+
100
+ void RuntimeContext::onTaskSettled(bool keepPumping) {
101
+ if (keepPumping) {
102
+ _pumpTasks.fetch_sub(1, std::memory_order_acq_rel);
103
+ }
104
+ }
105
+
106
+ void RuntimeContext::postSettle(std::function<void()> job) {
107
+ if (!job) {
108
+ return;
109
+ }
110
+ std::lock_guard<std::mutex> lock(_mailboxMutex);
111
+ _mailbox.push_back(std::move(job));
112
+ }
113
+
114
+ void RuntimeContext::drainMailbox() {
115
+ std::vector<std::function<void()>> jobs;
116
+ {
117
+ std::lock_guard<std::mutex> lock(_mailboxMutex);
118
+ jobs.swap(_mailbox);
119
+ }
120
+ // Run settle-actions on this (the owning) thread, NOT under the ProcessEvents
121
+ // mutex, so JS continuations never execute while the pump lock is held.
122
+ for (auto &job : jobs) {
123
+ job();
124
+ }
125
+ }
126
+
127
+ void RuntimeContext::requestTick() {
128
+ bool expected = false;
129
+ if (!_tickScheduled.compare_exchange_strong(expected, true,
130
+ std::memory_order_acq_rel)) {
131
+ return;
132
+ }
133
+
134
+ // The pump only ever runs while a request/response op is outstanding, so it
135
+ // always schedules as soon as possible (delay 0). postTask and tick both run
136
+ // on the owning runtime's thread, so we schedule the next tick directly via
137
+ // that runtime's own timer. setTimeout is available on the main RN runtime and
138
+ // on worklet runtimes (backed by the worklets EventLoop); setImmediate /
139
+ // queueMicrotask are fallbacks. We do NOT use queueMicrotask as the primary
140
+ // mechanism: a self-rescheduling microtask never yields the microtask
141
+ // checkpoint, starving the runtime's task loop.
142
+ auto self = shared_from_this();
143
+ jsi::Runtime &rt = _runtime;
144
+ auto tickCallback = jsi::Function::createFromHostFunction(
145
+ rt, jsi::PropNameID::forAscii(rt, "RNWGPUAsyncTick"), 0,
146
+ [self](jsi::Runtime & /*runtime*/, const jsi::Value & /*thisVal*/,
147
+ const jsi::Value * /*args*/, size_t /*count*/) -> jsi::Value {
148
+ self->tick();
149
+ return jsi::Value::undefined();
150
+ });
151
+
152
+ auto global = rt.global();
153
+ auto setTimeoutValue = global.getProperty(rt, "setTimeout");
154
+ if (setTimeoutValue.isObject() &&
155
+ setTimeoutValue.asObject(rt).isFunction(rt)) {
156
+ setTimeoutValue.asObject(rt).asFunction(rt).call(
157
+ rt, jsi::Value(rt, tickCallback), jsi::Value(0.0));
158
+ return;
159
+ }
160
+ auto setImmediateValue = global.getProperty(rt, "setImmediate");
161
+ if (setImmediateValue.isObject() &&
162
+ setImmediateValue.asObject(rt).isFunction(rt)) {
163
+ setImmediateValue.asObject(rt).asFunction(rt).call(
164
+ rt, jsi::Value(rt, tickCallback));
165
+ return;
166
+ }
167
+ rt.queueMicrotask(std::move(tickCallback));
168
+ }
169
+
170
+ void RuntimeContext::tick() {
171
+ _tickScheduled.store(false, std::memory_order_release);
172
+ {
173
+ // Serialize ProcessEvents across runtimes sharing this instance. Callbacks
174
+ // fired here only deposit into mailboxes (postSettle), they do not run JS.
175
+ std::lock_guard<std::mutex> lock(processEventsMutex());
176
+ _instance.ProcessEvents();
177
+ }
178
+ // Settle this runtime's ready promises on this thread, outside the pump lock.
179
+ drainMailbox();
180
+ // Keep pumping only while a "pumping" task (active async work) is outstanding.
181
+ // Non-pumping tasks (e.g. device.lost) intentionally do NOT keep the pump
182
+ // alive: we prioritise battery over catching a device.lost fired while idle.
183
+ if (_pumpTasks.load(std::memory_order_acquire) > 0) {
184
+ requestTick();
185
+ }
186
+ }
187
+
188
+ jsi::UUID RuntimeContext::runtimeDataUUID() {
189
+ static const auto uuid = jsi::UUID();
190
+ return uuid;
191
+ }
192
+
193
+ } // namespace rnwgpu::async
@@ -0,0 +1,122 @@
1
+ #pragma once
2
+
3
+ #include <atomic>
4
+ #include <cstddef>
5
+ #include <functional>
6
+ #include <memory>
7
+ #include <mutex>
8
+ #include <vector>
9
+
10
+ #include <jsi/jsi.h>
11
+
12
+ #include "AsyncTaskHandle.h"
13
+
14
+ #include "webgpu/webgpu_cpp.h"
15
+
16
+ namespace jsi = facebook::jsi;
17
+
18
+ namespace facebook::react {
19
+ class CallInvoker;
20
+ } // namespace facebook::react
21
+
22
+ namespace rnwgpu::async {
23
+
24
+ /**
25
+ * Per-runtime coordinator for asynchronous WebGPU operations.
26
+ *
27
+ * Each JS runtime that uses WebGPU gets its own RuntimeContext, stored in the
28
+ * runtime's runtimeData. Async Dawn operations are registered with
29
+ * CallbackMode::AllowProcessEvents and driven to completion by pumping
30
+ * `instance.ProcessEvents()` on the runtime's OWN thread via a self-
31
+ * rescheduling tick (scheduled through that runtime's setTimeout). Because
32
+ * ProcessEvents invokes the Dawn callbacks synchronously on the pumping thread,
33
+ * the JS Promise is settled directly on the owning runtime, with no background
34
+ * thread and no cross-thread hop.
35
+ *
36
+ * The pump only runs while at least one "pumping" task is outstanding, so it
37
+ * costs nothing when idle and stops cleanly.
38
+ *
39
+ * Spontaneous events (keepPumping = false): events that may fire at any time,
40
+ * independent of any request/response op (today only GPUDevice::getLost, whose
41
+ * Dawn callback is registered AllowSpontaneous). These are NOT driven by the
42
+ * pump. Instead their settle is marshalled onto the owning runtime's JS thread
43
+ * via that runtime's CallInvoker, which is wired only for the MAIN JS runtime
44
+ * (callInvoker()). A device created on a worklet runtime has no invoker, so its
45
+ * device.lost is best-effort and may never fire. See the README "Threading
46
+ * model" section.
47
+ *
48
+ * Shared-instance safety (mailbox): multiple runtimes may share one
49
+ * wgpu::Instance. ProcessEvents() drains the whole instance queue and fires
50
+ * callbacks on the calling thread, which may NOT be the owning runtime's thread
51
+ * for a given promise. So a settled callback never touches JSI inline; it
52
+ * deposits a settle-action (a plain C++ closure, no JSI) into the OWNING
53
+ * context's thread-safe mailbox via postSettle(), and each context drains its
54
+ * own mailbox on its own thread during tick(). ProcessEvents() itself is
55
+ * serialized across runtimes by a process-wide mutex, since concurrent
56
+ * ProcessEvents on one instance is not guaranteed reentrant.
57
+ *
58
+ * Threading contract: a RuntimeContext must only be pumped from the runtime it
59
+ * was created for. Create and use a GPUDevice (and the buffers/queues derived
60
+ * from it) on the same runtime that requested the adapter.
61
+ */
62
+ class RuntimeContext : public std::enable_shared_from_this<RuntimeContext> {
63
+ public:
64
+ using TaskCallback =
65
+ std::function<void(const AsyncTaskHandle::ResolveFunction &,
66
+ const AsyncTaskHandle::RejectFunction &)>;
67
+
68
+ RuntimeContext(jsi::Runtime &runtime, wgpu::Instance instance);
69
+
70
+ static std::shared_ptr<RuntimeContext> get(jsi::Runtime &runtime);
71
+ static std::shared_ptr<RuntimeContext> getOrCreate(jsi::Runtime &runtime,
72
+ wgpu::Instance instance);
73
+
74
+ // Register the main JS runtime and its CallInvoker. The RuntimeContext created
75
+ // for this runtime gets the invoker (callInvoker() returns it); every other
76
+ // runtime's context returns null. Called once from RNWebGPUManager on install.
77
+ static void
78
+ registerMainRuntime(jsi::Runtime *runtime,
79
+ std::shared_ptr<facebook::react::CallInvoker> invoker);
80
+
81
+ // CallInvoker for this runtime's JS thread, or null. Non-null only for the
82
+ // main JS runtime; used to deliver spontaneous events (device.lost) without
83
+ // the pump. See the class doc.
84
+ const std::shared_ptr<facebook::react::CallInvoker> &callInvoker() const {
85
+ return _callInvoker;
86
+ }
87
+
88
+ // The wgpu::Instance bound to this runtime.
89
+ wgpu::Instance instance() const { return _instance; }
90
+
91
+ AsyncTaskHandle postTask(const TaskCallback &callback,
92
+ bool keepPumping = true);
93
+
94
+ // Deposit a settle-action to run on THIS context's runtime thread. Thread-safe
95
+ // (callable from any thread, e.g. another runtime that pumped ProcessEvents).
96
+ // The job must not touch JSI until it runs (it runs during drainMailbox on the
97
+ // owning thread).
98
+ void postSettle(std::function<void()> job);
99
+
100
+ // Invoked by a drained settle-action when its task settles. Runs on the owning
101
+ // runtime's thread.
102
+ void onTaskSettled(bool keepPumping);
103
+
104
+ private:
105
+ static jsi::UUID runtimeDataUUID();
106
+
107
+ void requestTick();
108
+ void tick();
109
+ void drainMailbox();
110
+
111
+ jsi::Runtime &_runtime;
112
+ wgpu::Instance _instance;
113
+ // Non-null only for the main JS runtime's context (see registerMainRuntime).
114
+ std::shared_ptr<facebook::react::CallInvoker> _callInvoker;
115
+ std::atomic<std::size_t> _pumpTasks{0};
116
+ std::atomic<bool> _tickScheduled{false};
117
+
118
+ std::mutex _mailboxMutex;
119
+ std::vector<std::function<void()>> _mailbox;
120
+ };
121
+
122
+ } // namespace rnwgpu::async
@@ -1 +1 @@
1
- {"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","_WebGPUViewNativeComponent","_interopRequireDefault","e","__esModule","default","t","WeakMap","r","n","o","i","f","__proto__","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","_extends","assign","bind","arguments","length","apply","CONTEXT_COUNTER","generateContextId","Canvas","transparent","ref","props","viewRef","useRef","contextId","_","useState","useImperativeHandle","getContextId","getNativeSurface","RNWebGPU","getContext","contextName","Error","current","view","size","getBoundingClientRect","unstable_getBoundingClientRect","MakeWebGPUCanvasContext","width","height","createElement","View","collapsable","style","flex","exports"],"sourceRoot":"../../src","sources":["Canvas.tsx"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","_WebGPUViewNativeComponent","_interopRequireDefault","e","__esModule","default","t","WeakMap","r","n","o","i","f","__proto__","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","_extends","assign","bind","arguments","length","apply","CONTEXT_COUNTER","generateContextId","Canvas","transparent","ref","props","viewRef","useRef","contextId","_","useState","useImperativeHandle","getContextId","getNativeSurface","RNWebGPU","getContext","contextName","Error","current","view","size","getBoundingClientRect","unstable_getBoundingClientRect","MakeWebGPUCanvasContext","width","height","createElement","View","collapsable","style","flex","exports"],"sourceRoot":"../../src","sources":["Canvas.tsx"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,uBAAA,CAAAC,OAAA;AAEA,IAAAC,YAAA,GAAAD,OAAA;AAEA,IAAAE,0BAAA,GAAAC,sBAAA,CAAAH,OAAA;AAA2D,SAAAG,uBAAAC,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAAA,SAAAL,wBAAAK,CAAA,EAAAG,CAAA,6BAAAC,OAAA,MAAAC,CAAA,OAAAD,OAAA,IAAAE,CAAA,OAAAF,OAAA,YAAAT,uBAAA,YAAAA,CAAAK,CAAA,EAAAG,CAAA,SAAAA,CAAA,IAAAH,CAAA,IAAAA,CAAA,CAAAC,UAAA,SAAAD,CAAA,MAAAO,CAAA,EAAAC,CAAA,EAAAC,CAAA,KAAAC,SAAA,QAAAR,OAAA,EAAAF,CAAA,iBAAAA,CAAA,uBAAAA,CAAA,yBAAAA,CAAA,SAAAS,CAAA,MAAAF,CAAA,GAAAJ,CAAA,GAAAG,CAAA,GAAAD,CAAA,QAAAE,CAAA,CAAAI,GAAA,CAAAX,CAAA,UAAAO,CAAA,CAAAK,GAAA,CAAAZ,CAAA,GAAAO,CAAA,CAAAM,GAAA,CAAAb,CAAA,EAAAS,CAAA,gBAAAN,CAAA,IAAAH,CAAA,gBAAAG,CAAA,OAAAW,cAAA,CAAAC,IAAA,CAAAf,CAAA,EAAAG,CAAA,OAAAK,CAAA,IAAAD,CAAA,GAAAS,MAAA,CAAAC,cAAA,KAAAD,MAAA,CAAAE,wBAAA,CAAAlB,CAAA,EAAAG,CAAA,OAAAK,CAAA,CAAAI,GAAA,IAAAJ,CAAA,CAAAK,GAAA,IAAAN,CAAA,CAAAE,CAAA,EAAAN,CAAA,EAAAK,CAAA,IAAAC,CAAA,CAAAN,CAAA,IAAAH,CAAA,CAAAG,CAAA,WAAAM,CAAA,KAAAT,CAAA,EAAAG,CAAA;AAAA,SAAAgB,SAAA,WAAAA,QAAA,GAAAH,MAAA,CAAAI,MAAA,GAAAJ,MAAA,CAAAI,MAAA,CAAAC,IAAA,eAAAf,CAAA,aAAAN,CAAA,MAAAA,CAAA,GAAAsB,SAAA,CAAAC,MAAA,EAAAvB,CAAA,UAAAG,CAAA,GAAAmB,SAAA,CAAAtB,CAAA,YAAAK,CAAA,IAAAF,CAAA,OAAAW,cAAA,CAAAC,IAAA,CAAAZ,CAAA,EAAAE,CAAA,MAAAC,CAAA,CAAAD,CAAA,IAAAF,CAAA,CAAAE,CAAA,aAAAC,CAAA,KAAAa,QAAA,CAAAK,KAAA,OAAAF,SAAA;AAE3D,IAAIG,eAAe,GAAG,CAAC;AACvB,SAASC,iBAAiBA,CAAA,EAAG;EAC3B,OAAOD,eAAe,EAAE;AAC1B;AAoCO,MAAME,MAAM,GAAGA,CAAC;EAAEC,WAAW;EAAEC,GAAG;EAAE,GAAGC;AAAmB,CAAC,KAAK;EACrE,MAAMC,OAAO,GAAG,IAAAC,aAAM,EAAC,IAAI,CAAC;EAC5B,MAAM,CAACC,SAAS,EAAEC,CAAC,CAAC,GAAG,IAAAC,eAAQ,EAAC,MAAMT,iBAAiB,CAAC,CAAC,CAAC;EAC1D,IAAAU,0BAAmB,EAACP,GAAG,EAAE,OAAO;IAC9BQ,YAAY,EAAEA,CAAA,KAAMJ,SAAS;IAC7BK,gBAAgB,EAAEA,CAAA,KAAM;MACtB,OAAOC,QAAQ,CAACD,gBAAgB,CAACL,SAAS,CAAC;IAC7C,CAAC;IACDO,UAAUA,CAACC,WAAqB,EAA0B;MACxD,IAAIA,WAAW,KAAK,QAAQ,EAAE;QAC5B,MAAM,IAAIC,KAAK,CAAC,iCAAiCD,WAAW,EAAE,CAAC;MACjE;MACA,IAAI,CAACV,OAAO,CAACY,OAAO,EAAE;QACpB,MAAM,IAAID,KAAK,CAAC,0CAA0C,CAAC;MAC7D;MACA;MACA;MACA,MAAME,IAAI,GAAGb,OAAO,CAACY,OAAc;MACnC,MAAME,IAAI,GACR,uBAAuB,IAAID,IAAI,GAC3BA,IAAI,CAACE,qBAAqB,CAAC,CAAC,GAC5BF,IAAI,CAACG,8BAA8B,CAAC,CAAC;MAC3C,OAAOR,QAAQ,CAACS,uBAAuB,CACrCf,SAAS,EACTY,IAAI,CAACI,KAAK,EACVJ,IAAI,CAACK,MACP,CAAC;IACH;EACF,CAAC,CAAC,CAAC;EAEH,oBACExD,MAAA,CAAAQ,OAAA,CAAAiD,aAAA,CAACtD,YAAA,CAAAuD,IAAI,EAAAjC,QAAA;IAACkC,WAAW,EAAE,KAAM;IAACxB,GAAG,EAAEE;EAAQ,GAAKD,KAAK,gBAC/CpC,MAAA,CAAAQ,OAAA,CAAAiD,aAAA,CAACrD,0BAAA,CAAAI,OAAgB;IACfoD,KAAK,EAAE;MAAEC,IAAI,EAAE;IAAE,CAAE;IACnBtB,SAAS,EAAEA,SAAU;IACrBL,WAAW,EAAE,CAAC,CAACA;EAAY,CAC5B,CACG,CAAC;AAEX,CAAC;AAAC4B,OAAA,CAAA7B,MAAA,GAAAA,MAAA","ignoreList":[]}
@@ -62,7 +62,7 @@ class GPUOffscreenCanvasContext {
62
62
  throw new Error("Method not implemented.");
63
63
  }
64
64
  present() {
65
- // Do nothing
65
+ // Offscreen contexts have nothing to present; readback is via getImageData.
66
66
  }
67
67
  getDevice() {
68
68
  if (!this.device) {
@@ -26,6 +26,8 @@ function makeWebGPUCanvasContext(contextId, width, height) {
26
26
  canvas.setAttribute("height", pixelHeight);
27
27
  }
28
28
  const context = canvas.getContext("webgpu");
29
+ // On web there is no manual present; expose a no-op so RNCanvasContext's
30
+ // present() (called after queue.submit() on native) is callable here too.
29
31
  return Object.assign(context, {
30
32
  present: () => {}
31
33
  });
@@ -1 +1 @@
1
- {"version":3,"names":["_utils","require","fabric","getNativeSurface","contextId","canvas","document","getElementById","contextIdToId","height","width","getBoundingClientRect","surface","BigInt","clientHeight","clientWidth","makeWebGPUCanvasContext","dpr","window","devicePixelRatio","pixelWidth","toString","pixelHeight","getAttribute","setAttribute","context","getContext","Object","assign","present","RNWebGPU","MakeWebGPUCanvasContext"],"sourceRoot":"../../src","sources":["WebPolyfillGPUModule.ts"],"mappings":";;AAAA,IAAAA,MAAA,GAAAC,OAAA;AAEA,MAAMC,MAAM,GAAG,IAAI;AAEnB,SAASC,gBAAgBA,CAACC,SAAiB,EAAE;EAC3C,MAAMC,MAAM,GAAGC,QAAQ,CAACC,cAAc,CACpC,IAAAC,oBAAa,EAACJ,SAAS,CACzB,CAAsB;EAEtB,MAAM;IAAEK,MAAM;IAAEC;EAAM,CAAC,GAAGL,MAAM,CAACM,qBAAqB,CAAC,CAAE;EAEzD,OAAO;IACLC,OAAO,EAAEC,MAAM,CAACT,SAAS,CAAC;IAC1BK,MAAM;IACNC,KAAK;IACLI,YAAY,EAAEL,MAAM;IACpBM,WAAW,EAAEL;EACf,CAAC;AACH;AAEA,SAASM,uBAAuBA,CAC9BZ,SAAiB,EACjBM,KAAa,EACbD,MAAc,EACd;EACA,MAAMJ,MAAM,GAAGC,QAAQ,CAACC,cAAc,CACpC,IAAAC,oBAAa,EAACJ,SAAS,CACzB,CAAsB;EAEtB,MAAMa,GAAG,GAAGC,MAAM,CAACC,gBAAgB,IAAI,CAAC;EACxC,MAAMC,UAAU,GAAG,CAACV,KAAK,GAAGO,GAAG,EAAEI,QAAQ,CAAC,CAAC;EAC3C,MAAMC,WAAW,GAAG,CAACb,MAAM,GAAGQ,GAAG,EAAEI,QAAQ,CAAC,CAAC;EAE7C,IACEhB,MAAM,CAACkB,YAAY,CAAC,OAAO,CAAC,KAAKH,UAAU,IAC3Cf,MAAM,CAACkB,YAAY,CAAC,QAAQ,CAAC,KAAKD,WAAW,EAC7C;IACAjB,MAAM,CAACmB,YAAY,CAAC,OAAO,EAAEJ,UAAU,CAAC;IACxCf,MAAM,CAACmB,YAAY,CAAC,QAAQ,EAAEF,WAAW,CAAC;EAC5C;EAEA,MAAMG,OAAO,GAAGpB,MAAM,CAACqB,UAAU,CAAC,QAAQ,CAAE;EAC5C,OAAOC,MAAM,CAACC,MAAM,CAACH,OAAO,EAAE;IAC5BI,OAAO,EAAEA,CAAA,KAAM,CAAC;EAClB,CAAC,CAAC;AACJ;;AAEA;AACAX,MAAM,CAACY,QAAQ,GAAG;EAChB3B,gBAAgB;EAChB4B,uBAAuB,EAAEf,uBAAuB;EAChDd;AACF,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["_utils","require","fabric","getNativeSurface","contextId","canvas","document","getElementById","contextIdToId","height","width","getBoundingClientRect","surface","BigInt","clientHeight","clientWidth","makeWebGPUCanvasContext","dpr","window","devicePixelRatio","pixelWidth","toString","pixelHeight","getAttribute","setAttribute","context","getContext","Object","assign","present","RNWebGPU","MakeWebGPUCanvasContext"],"sourceRoot":"../../src","sources":["WebPolyfillGPUModule.ts"],"mappings":";;AAAA,IAAAA,MAAA,GAAAC,OAAA;AAEA,MAAMC,MAAM,GAAG,IAAI;AAEnB,SAASC,gBAAgBA,CAACC,SAAiB,EAAE;EAC3C,MAAMC,MAAM,GAAGC,QAAQ,CAACC,cAAc,CACpC,IAAAC,oBAAa,EAACJ,SAAS,CACzB,CAAsB;EAEtB,MAAM;IAAEK,MAAM;IAAEC;EAAM,CAAC,GAAGL,MAAM,CAACM,qBAAqB,CAAC,CAAE;EAEzD,OAAO;IACLC,OAAO,EAAEC,MAAM,CAACT,SAAS,CAAC;IAC1BK,MAAM;IACNC,KAAK;IACLI,YAAY,EAAEL,MAAM;IACpBM,WAAW,EAAEL;EACf,CAAC;AACH;AAEA,SAASM,uBAAuBA,CAC9BZ,SAAiB,EACjBM,KAAa,EACbD,MAAc,EACd;EACA,MAAMJ,MAAM,GAAGC,QAAQ,CAACC,cAAc,CACpC,IAAAC,oBAAa,EAACJ,SAAS,CACzB,CAAsB;EAEtB,MAAMa,GAAG,GAAGC,MAAM,CAACC,gBAAgB,IAAI,CAAC;EACxC,MAAMC,UAAU,GAAG,CAACV,KAAK,GAAGO,GAAG,EAAEI,QAAQ,CAAC,CAAC;EAC3C,MAAMC,WAAW,GAAG,CAACb,MAAM,GAAGQ,GAAG,EAAEI,QAAQ,CAAC,CAAC;EAE7C,IACEhB,MAAM,CAACkB,YAAY,CAAC,OAAO,CAAC,KAAKH,UAAU,IAC3Cf,MAAM,CAACkB,YAAY,CAAC,QAAQ,CAAC,KAAKD,WAAW,EAC7C;IACAjB,MAAM,CAACmB,YAAY,CAAC,OAAO,EAAEJ,UAAU,CAAC;IACxCf,MAAM,CAACmB,YAAY,CAAC,QAAQ,EAAEF,WAAW,CAAC;EAC5C;EAEA,MAAMG,OAAO,GAAGpB,MAAM,CAACqB,UAAU,CAAC,QAAQ,CAAE;EAC5C;EACA;EACA,OAAOC,MAAM,CAACC,MAAM,CAACH,OAAO,EAAE;IAAEI,OAAO,EAAEA,CAAA,KAAM,CAAC;EAAE,CAAC,CAAC;AACtD;;AAEA;AACAX,MAAM,CAACY,QAAQ,GAAG;EAChB3B,gBAAgB;EAChB4B,uBAAuB,EAAEf,uBAAuB;EAChDd;AACF,CAAC","ignoreList":[]}
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.GPUTextureUsage = exports.GPUShaderStage = exports.GPUMapMode = exports.GPUColorWrite = exports.GPUBufferUsage = void 0;
7
+ /// <reference types="@webgpu/types" />
8
+
9
+ // WebGPU flag constants as importable JS values.
10
+ //
11
+ // The native module installs `GPUBufferUsage`, `GPUTextureUsage`,
12
+ // `GPUShaderStage`, `GPUColorWrite` and `GPUMapMode` as globals, but only on the
13
+ // main JS runtime. Worklet runtimes (Reanimated UI, dedicated worklet runtimes,
14
+ // Vision Camera frame processors) do not get those globals, so referencing the
15
+ // bare global inside a worklet yields `undefined`.
16
+ //
17
+ // Rather than hardcode the bit values here (which could drift from the native
18
+ // `wgpu::*Usage` enums), we re-export the globals the native module already
19
+ // installed (see `GPUBufferUsage.h` and friends, which derive their values from
20
+ // the Dawn enums with `static_assert`s). This keeps a single source of truth.
21
+ // Importing them into a worklet lets the Worklets serializer capture them by
22
+ // closure (the same way module-level shader strings are captured), making them
23
+ // available on every runtime without passing them in by hand:
24
+ //
25
+ // import { GPUBufferUsage } from "react-native-webgpu";
26
+ // const work = () => {
27
+ // "worklet";
28
+ // device.createBuffer({ usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ });
29
+ // };
30
+ //
31
+ // These are read at module evaluation time. The package entry (`index.tsx`)
32
+ // re-exports `./main` before `./constants`, and `./main` installs the native
33
+ // module synchronously, so the globals always exist by the time this runs.
34
+
35
+ const GPUBufferUsage = exports.GPUBufferUsage = globalThis.GPUBufferUsage;
36
+ const GPUTextureUsage = exports.GPUTextureUsage = globalThis.GPUTextureUsage;
37
+ const GPUShaderStage = exports.GPUShaderStage = globalThis.GPUShaderStage;
38
+ const GPUColorWrite = exports.GPUColorWrite = globalThis.GPUColorWrite;
39
+ const GPUMapMode = exports.GPUMapMode = globalThis.GPUMapMode;
40
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["GPUBufferUsage","exports","globalThis","GPUTextureUsage","GPUShaderStage","GPUColorWrite","GPUMapMode"],"sourceRoot":"../../src","sources":["constants.ts"],"mappings":";;;;;;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEO,MAAMA,cAAc,GAAAC,OAAA,CAAAD,cAAA,GAAGE,UAAU,CAACF,cAAc;AAEhD,MAAMG,eAAe,GAAAF,OAAA,CAAAE,eAAA,GAAGD,UAAU,CAACC,eAAe;AAElD,MAAMC,cAAc,GAAAH,OAAA,CAAAG,cAAA,GAAGF,UAAU,CAACE,cAAc;AAEhD,MAAMC,aAAa,GAAAJ,OAAA,CAAAI,aAAA,GAAGH,UAAU,CAACG,aAAa;AAE9C,MAAMC,UAAU,GAAAL,OAAA,CAAAK,UAAA,GAAGJ,UAAU,CAACI,UAAU","ignoreList":[]}
@@ -14,4 +14,26 @@ Object.keys(_main).forEach(function (key) {
14
14
  }
15
15
  });
16
16
  });
17
+ var _constants = require("./constants");
18
+ Object.keys(_constants).forEach(function (key) {
19
+ if (key === "default" || key === "__esModule") return;
20
+ if (key in exports && exports[key] === _constants[key]) return;
21
+ Object.defineProperty(exports, key, {
22
+ enumerable: true,
23
+ get: function () {
24
+ return _constants[key];
25
+ }
26
+ });
27
+ });
28
+ var _install = require("./install");
29
+ Object.keys(_install).forEach(function (key) {
30
+ if (key === "default" || key === "__esModule") return;
31
+ if (key in exports && exports[key] === _install[key]) return;
32
+ Object.defineProperty(exports, key, {
33
+ enumerable: true,
34
+ get: function () {
35
+ return _install[key];
36
+ }
37
+ });
38
+ });
17
39
  //# sourceMappingURL=index.js.map