react-native-webgpu 0.10.5 → 0.11.1

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 (61) hide show
  1. package/android/cpp/AndroidPlatformContext.h +100 -9
  2. package/android/cpp/AndroidVideoPlayer.h +307 -0
  3. package/android/cpp/cpp-adapter.cpp +66 -6
  4. package/android/src/main/java/com/webgpu/ViewSnapshot.java +162 -0
  5. package/android/src/main/java/com/webgpu/WebGPUModule.java +78 -0
  6. package/android/src/main/java/com/webgpu/WebGPUVideoPlayer.java +420 -0
  7. package/apple/ApplePlatformContext.h +14 -1
  8. package/apple/ApplePlatformContext.mm +176 -1
  9. package/apple/AppleVideoPlayer.mm +157 -47
  10. package/apple/WebGPUModule.mm +20 -1
  11. package/cpp/rnwgpu/PlatformContext.h +76 -1
  12. package/cpp/rnwgpu/RNWebGPUManager.cpp +7 -0
  13. package/cpp/rnwgpu/api/GPUDevice.cpp +2 -1
  14. package/cpp/rnwgpu/api/GPUDevice.h +6 -0
  15. package/cpp/rnwgpu/api/GPUQueue.cpp +261 -4
  16. package/cpp/rnwgpu/api/GPUQueue.h +29 -2
  17. package/cpp/rnwgpu/api/VideoFrameBlit.h +355 -0
  18. package/cpp/rnwgpu/api/VideoPlayer.h +50 -3
  19. package/cpp/rnwgpu/api/descriptors/GPUDrawElementImageDestination.h +60 -0
  20. package/cpp/rnwgpu/api/descriptors/GPUDrawElementImageSource.h +106 -0
  21. package/cpp/rnwgpu/api/descriptors/GPUImageCopyExternalImage.h +30 -3
  22. package/lib/commonjs/importDevice.js +2 -2
  23. package/lib/commonjs/index.js.map +1 -1
  24. package/lib/commonjs/main/index.js +45 -0
  25. package/lib/commonjs/main/index.js.map +1 -1
  26. package/lib/commonjs/main/index.web.js +11 -0
  27. package/lib/commonjs/main/index.web.js.map +1 -1
  28. package/lib/commonjs/video.js +58 -0
  29. package/lib/commonjs/video.js.map +1 -0
  30. package/lib/module/importDevice.js +2 -2
  31. package/lib/module/index.js.map +1 -1
  32. package/lib/module/main/index.js +34 -0
  33. package/lib/module/main/index.js.map +1 -1
  34. package/lib/module/main/index.web.js +1 -0
  35. package/lib/module/main/index.web.js.map +1 -1
  36. package/lib/module/video.js +49 -0
  37. package/lib/module/video.js.map +1 -0
  38. package/lib/typescript/lib/commonjs/video.d.ts +30 -0
  39. package/lib/typescript/lib/commonjs/video.d.ts.map +1 -0
  40. package/lib/typescript/lib/module/main/index.d.ts +1 -0
  41. package/lib/typescript/lib/module/main/index.web.d.ts +1 -0
  42. package/lib/typescript/lib/module/video.d.ts +4 -0
  43. package/lib/typescript/lib/module/video.d.ts.map +1 -0
  44. package/lib/typescript/src/importDevice.d.ts +2 -2
  45. package/lib/typescript/src/index.d.ts +8 -3
  46. package/lib/typescript/src/index.d.ts.map +1 -1
  47. package/lib/typescript/src/main/index.d.ts +1 -0
  48. package/lib/typescript/src/main/index.d.ts.map +1 -1
  49. package/lib/typescript/src/main/index.web.d.ts +1 -0
  50. package/lib/typescript/src/main/index.web.d.ts.map +1 -1
  51. package/lib/typescript/src/types.d.ts +32 -0
  52. package/lib/typescript/src/types.d.ts.map +1 -1
  53. package/lib/typescript/src/video.d.ts +41 -0
  54. package/lib/typescript/src/video.d.ts.map +1 -0
  55. package/package.json +1 -1
  56. package/src/importDevice.ts +2 -2
  57. package/src/index.tsx +57 -3
  58. package/src/main/index.tsx +50 -0
  59. package/src/main/index.web.tsx +1 -0
  60. package/src/types.ts +89 -7
  61. package/src/video.ts +69 -0
@@ -13,6 +13,7 @@
13
13
 
14
14
  #include "webgpu/webgpu_cpp.h"
15
15
 
16
+ #include "AndroidVideoPlayer.h"
16
17
  #include "PlatformContext.h"
17
18
  #include "RNWebGPUManager.h"
18
19
 
@@ -21,9 +22,19 @@ namespace rnwgpu {
21
22
  namespace jsi = facebook::jsi;
22
23
  namespace jni = facebook::jni;
23
24
 
25
+ // The completion callbacks of one snapshotView request, heap-allocated and
26
+ // carried through Java as an opaque pointer (WebGPUModule.snapshotView ->
27
+ // onViewSnapshot), which hands them back exactly once.
28
+ struct ViewSnapshotCallbacks {
29
+ std::function<void(ImageData)> onSuccess;
30
+ std::function<void(std::string)> onError;
31
+ };
32
+
24
33
  class AndroidPlatformContext : public PlatformContext {
25
34
  private:
26
35
  jobject _blobModule;
36
+ // Global ref to the com.webgpu.WebGPUModule instance (view snapshots).
37
+ jobject _module;
27
38
 
28
39
  std::vector<uint8_t> resolveBlob(JNIEnv *env, const std::string &blobId,
29
40
  double offset, double size) {
@@ -63,14 +74,61 @@ private:
63
74
  }
64
75
 
65
76
  public:
66
- explicit AndroidPlatformContext(jobject blobModule)
67
- : _blobModule(blobModule) {}
77
+ // Both arguments are global refs; the context releases them.
78
+ AndroidPlatformContext(jobject blobModule, jobject module)
79
+ : _blobModule(blobModule), _module(module) {}
68
80
  ~AndroidPlatformContext() {
81
+ JNIEnv *env = facebook::jni::Environment::current();
69
82
  if (_blobModule) {
70
- JNIEnv *env = facebook::jni::Environment::current();
71
83
  env->DeleteGlobalRef(_blobModule);
72
84
  _blobModule = nullptr;
73
85
  }
86
+ if (_module) {
87
+ env->DeleteGlobalRef(_module);
88
+ _module = nullptr;
89
+ }
90
+ }
91
+
92
+ void snapshotView(const ViewSnapshotRequest &request,
93
+ std::function<void(ImageData)> onSuccess,
94
+ std::function<void(std::string)> onError) override {
95
+ if (!_module) {
96
+ onError("drawElementImageToTexture: the WebGPU module is gone");
97
+ return;
98
+ }
99
+ jni::Environment::ensureCurrentThreadIsAttached();
100
+ JNIEnv *env = facebook::jni::Environment::current();
101
+ if (!env) {
102
+ onError("drawElementImageToTexture: couldn't get the JNI environment");
103
+ return;
104
+ }
105
+ jclass moduleClass = env->GetObjectClass(_module);
106
+ jmethodID method =
107
+ env->GetMethodID(moduleClass, "snapshotView", "(IDDDDIIJ)V");
108
+ env->DeleteLocalRef(moduleClass);
109
+ if (!method) {
110
+ env->ExceptionClear();
111
+ onError("drawElementImageToTexture: WebGPUModule.snapshotView not found");
112
+ return;
113
+ }
114
+ // Ownership passes to Java; Java_com_webgpu_WebGPUModule_onViewSnapshot
115
+ // (cpp-adapter.cpp) reclaims it.
116
+ auto *callbacks =
117
+ new ViewSnapshotCallbacks{std::move(onSuccess), std::move(onError)};
118
+ env->CallVoidMethod(_module, method, static_cast<jint>(request.viewTag),
119
+ static_cast<jdouble>(request.sourceX),
120
+ static_cast<jdouble>(request.sourceY),
121
+ static_cast<jdouble>(request.sourceWidth),
122
+ static_cast<jdouble>(request.sourceHeight),
123
+ static_cast<jint>(request.width),
124
+ static_cast<jint>(request.height),
125
+ reinterpret_cast<jlong>(callbacks));
126
+ if (env->ExceptionCheck()) {
127
+ env->ExceptionClear();
128
+ auto fail = std::move(callbacks->onError);
129
+ delete callbacks;
130
+ fail("drawElementImageToTexture: WebGPUModule.snapshotView threw");
131
+ }
74
132
  }
75
133
 
76
134
  wgpu::Surface makeSurface(wgpu::Instance instance, void *window, int width,
@@ -179,8 +237,9 @@ public:
179
237
  result.height = static_cast<int>(bitmapInfo.height);
180
238
  result.data.resize(bitmapInfo.height * bitmapInfo.stride);
181
239
  memcpy(result.data.data(), bitmapPixels, result.data.size());
182
- // BitmapFactory hands back premultiplied ARGB_8888 pixels; createImageBitmap
183
- // converts to the representation requested by premultiplyAlpha.
240
+ // BitmapFactory hands back premultiplied ARGB_8888 pixels;
241
+ // createImageBitmap converts to the representation requested by
242
+ // premultiplyAlpha.
184
243
  result.premultiplied = true;
185
244
 
186
245
  AndroidBitmap_unlockPixels(env, bitmap);
@@ -282,12 +341,44 @@ public:
282
341
  return handle;
283
342
  }
284
343
 
344
+ // The decoder writes its native YUV layout whatever format is requested:
345
+ // the frames are sampled through importExternalTexture (see
346
+ // WebGPUVideoPlayer.java).
285
347
  std::unique_ptr<IVideoPlayer>
286
- createVideoPlayer(const std::string & /*path*/,
348
+ createVideoPlayer(const std::string &path,
287
349
  VideoPixelFormat /*format*/) override {
288
- // TODO: implement using MediaCodec -> ImageReader (AHardwareBuffer mode).
289
- throw std::runtime_error(
290
- "createVideoPlayer is not yet implemented on Android.");
350
+ if (!_module) {
351
+ throw std::runtime_error("createVideoPlayer: the WebGPU module is gone");
352
+ }
353
+ jni::Environment::ensureCurrentThreadIsAttached();
354
+ JNIEnv *env = facebook::jni::Environment::current();
355
+ if (!env) {
356
+ throw std::runtime_error(
357
+ "createVideoPlayer: couldn't get the JNI environment");
358
+ }
359
+ jclass moduleClass = env->GetObjectClass(_module);
360
+ jmethodID method =
361
+ env->GetMethodID(moduleClass, "createVideoPlayer",
362
+ "(Ljava/lang/String;)Lcom/webgpu/WebGPUVideoPlayer;");
363
+ env->DeleteLocalRef(moduleClass);
364
+ if (!method) {
365
+ env->ExceptionClear();
366
+ throw std::runtime_error(
367
+ "createVideoPlayer: WebGPUModule.createVideoPlayer not found");
368
+ }
369
+ jstring jPath = env->NewStringUTF(path.c_str());
370
+ jobject player = env->CallObjectMethod(_module, method, jPath);
371
+ env->DeleteLocalRef(jPath);
372
+ if (env->ExceptionCheck()) {
373
+ throw std::runtime_error("createVideoPlayer: " +
374
+ describeAndClearJavaException(env));
375
+ }
376
+ if (player == nullptr) {
377
+ throw std::runtime_error("createVideoPlayer: no player was created");
378
+ }
379
+ auto result = std::make_unique<AndroidVideoPlayer>(env, player);
380
+ env->DeleteLocalRef(player);
381
+ return result;
291
382
  }
292
383
 
293
384
  std::string writeTestVideoFile() override {
@@ -0,0 +1,307 @@
1
+ #pragma once
2
+
3
+ #include <android/hardware_buffer.h>
4
+ #include <android/hardware_buffer_jni.h>
5
+ #include <fbjni/fbjni.h>
6
+ #include <jni.h>
7
+
8
+ #include <memory>
9
+ #include <stdexcept>
10
+ #include <string>
11
+ #include <utility>
12
+
13
+ #include "PlatformContext.h"
14
+
15
+ namespace rnwgpu {
16
+
17
+ // The message of the pending Java exception, which is cleared.
18
+ inline std::string describeAndClearJavaException(JNIEnv *env) {
19
+ jthrowable throwable = env->ExceptionOccurred();
20
+ if (throwable == nullptr) {
21
+ return "unknown error";
22
+ }
23
+ env->ExceptionClear();
24
+ std::string message = "Java exception";
25
+ jclass throwableClass = env->GetObjectClass(throwable);
26
+ jmethodID getMessage =
27
+ env->GetMethodID(throwableClass, "getMessage", "()Ljava/lang/String;");
28
+ if (getMessage != nullptr) {
29
+ auto text =
30
+ static_cast<jstring>(env->CallObjectMethod(throwable, getMessage));
31
+ if (env->ExceptionCheck()) {
32
+ env->ExceptionClear();
33
+ } else if (text != nullptr) {
34
+ const char *chars = env->GetStringUTFChars(text, nullptr);
35
+ if (chars != nullptr) {
36
+ message = chars;
37
+ env->ReleaseStringUTFChars(text, chars);
38
+ }
39
+ env->DeleteLocalRef(text);
40
+ }
41
+ }
42
+ env->DeleteLocalRef(throwableClass);
43
+ env->DeleteLocalRef(throwable);
44
+ return message;
45
+ }
46
+
47
+ // A global reference to the Java player, shared between AndroidVideoPlayer
48
+ // and the deleters of the frames it handed out (they close each frame's
49
+ // Image through the player). The reference goes away with the last of them.
50
+ class JavaVideoPlayerRef {
51
+ public:
52
+ JavaVideoPlayerRef(JNIEnv *env, jobject local)
53
+ : _object(env->NewGlobalRef(local)) {}
54
+ ~JavaVideoPlayerRef() {
55
+ facebook::jni::Environment::ensureCurrentThreadIsAttached();
56
+ JNIEnv *env = facebook::jni::Environment::current();
57
+ if (env != nullptr && _object != nullptr) {
58
+ env->DeleteGlobalRef(_object);
59
+ }
60
+ }
61
+ JavaVideoPlayerRef(const JavaVideoPlayerRef &) = delete;
62
+ JavaVideoPlayerRef &operator=(const JavaVideoPlayerRef &) = delete;
63
+
64
+ jobject get() const { return _object; }
65
+
66
+ private:
67
+ jobject _object;
68
+ };
69
+
70
+ // IVideoPlayer backed by com.webgpu.WebGPUVideoPlayer: MediaPlayer decodes
71
+ // into an ImageReader whose buffers the GPU samples. The frames keep the
72
+ // decoder's native YUV layout (reported as NV12), for importExternalTexture.
73
+ class AndroidVideoPlayer : public IVideoPlayer {
74
+ public:
75
+ AndroidVideoPlayer(JNIEnv *env, jobject player)
76
+ : _player(std::make_shared<JavaVideoPlayerRef>(env, player)) {
77
+ jclass playerClass = env->GetObjectClass(player);
78
+ _copyLatestFrame =
79
+ method(env, playerClass, "copyLatestFrame", "()Landroid/media/Image;");
80
+ _closeImage =
81
+ method(env, playerClass, "closeImage", "(Landroid/media/Image;)V");
82
+ _play = method(env, playerClass, "play", "()V");
83
+ _pause = method(env, playerClass, "pause", "()V");
84
+ _getPaused = method(env, playerClass, "getPaused", "()Z");
85
+ _getCurrentTime = method(env, playerClass, "getCurrentTime", "()D");
86
+ _seek = method(env, playerClass, "seek", "(D)V");
87
+ _getDuration = method(env, playerClass, "getDuration", "()D");
88
+ _getVolume = method(env, playerClass, "getVolume", "()D");
89
+ _setVolume = method(env, playerClass, "setVolume", "(D)V");
90
+ _getLoop = method(env, playerClass, "getLoop", "()Z");
91
+ _setLoop = method(env, playerClass, "setLoop", "(Z)V");
92
+ _getVideoWidth = method(env, playerClass, "getVideoWidth", "()I");
93
+ _getVideoHeight = method(env, playerClass, "getVideoHeight", "()I");
94
+ _getRotation = method(env, playerClass, "getRotation", "()I");
95
+ _getFrameRate = method(env, playerClass, "getFrameRate", "()D");
96
+ _release = method(env, playerClass, "release", "()V");
97
+ env->DeleteLocalRef(playerClass);
98
+
99
+ jclass imageClass = env->FindClass("android/media/Image");
100
+ _getHardwareBuffer = method(env, imageClass, "getHardwareBuffer",
101
+ "()Landroid/hardware/HardwareBuffer;");
102
+ env->DeleteLocalRef(imageClass);
103
+ }
104
+
105
+ ~AndroidVideoPlayer() override {
106
+ JNIEnv *env = attach();
107
+ env->CallVoidMethod(_player->get(), _release);
108
+ if (env->ExceptionCheck()) {
109
+ env->ExceptionClear();
110
+ }
111
+ }
112
+
113
+ VideoFrameHandle copyLatestFrame() override {
114
+ JNIEnv *env = attach();
115
+ jobject image = env->CallObjectMethod(_player->get(), _copyLatestFrame);
116
+ if (env->ExceptionCheck()) {
117
+ throw std::runtime_error("copyLatestFrame: " +
118
+ describeAndClearJavaException(env));
119
+ }
120
+ if (image == nullptr) {
121
+ return {};
122
+ }
123
+
124
+ jobject hardwareBuffer = env->CallObjectMethod(image, _getHardwareBuffer);
125
+ if (env->ExceptionCheck() || hardwareBuffer == nullptr) {
126
+ env->ExceptionClear();
127
+ closeImage(env, image);
128
+ env->DeleteLocalRef(image);
129
+ throw std::runtime_error(
130
+ "copyLatestFrame: the decoded frame has no HardwareBuffer");
131
+ }
132
+ AHardwareBuffer *buffer =
133
+ AHardwareBuffer_fromHardwareBuffer(env, hardwareBuffer);
134
+ env->DeleteLocalRef(hardwareBuffer);
135
+
136
+ AHardwareBuffer_Desc desc = {};
137
+ AHardwareBuffer_describe(buffer, &desc);
138
+ if ((desc.usage & AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE) == 0) {
139
+ closeImage(env, image);
140
+ env->DeleteLocalRef(image);
141
+ throw std::runtime_error(
142
+ "copyLatestFrame: the decoder allocated frames without "
143
+ "AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE, so the GPU cannot sample "
144
+ "them");
145
+ }
146
+
147
+ // The frame owns a reference to the buffer and keeps the Image acquired
148
+ // until it is released; closing the Image hands the buffer back to the
149
+ // decoder.
150
+ AHardwareBuffer_acquire(buffer);
151
+ jobject imageRef = env->NewGlobalRef(image);
152
+ env->DeleteLocalRef(image);
153
+
154
+ VideoFrameHandle handle;
155
+ handle.handle = static_cast<void *>(buffer);
156
+ handle.width = desc.width;
157
+ handle.height = desc.height;
158
+ handle.pixelFormat = isRgbFormat(desc.format) ? VideoPixelFormat::BGRA8
159
+ : VideoPixelFormat::NV12;
160
+ auto player = _player;
161
+ jmethodID closeImageMethod = _closeImage;
162
+ handle.deleter = [player, closeImageMethod, imageRef, buffer]() {
163
+ JNIEnv *env = attach();
164
+ env->CallVoidMethod(player->get(), closeImageMethod, imageRef);
165
+ if (env->ExceptionCheck()) {
166
+ env->ExceptionClear();
167
+ }
168
+ env->DeleteGlobalRef(imageRef);
169
+ AHardwareBuffer_release(buffer);
170
+ };
171
+ return handle;
172
+ }
173
+
174
+ void play() override { callVoid(_play); }
175
+ void pause() override { callVoid(_pause); }
176
+ bool paused() override { return callBool(_getPaused); }
177
+
178
+ double currentTime() override { return callDouble(_getCurrentTime); }
179
+ void seek(double seconds) override {
180
+ JNIEnv *env = attach();
181
+ env->CallVoidMethod(_player->get(), _seek, static_cast<jdouble>(seconds));
182
+ clearException(env);
183
+ }
184
+ double duration() override { return callDouble(_getDuration); }
185
+
186
+ double volume() override { return callDouble(_getVolume); }
187
+ void setVolume(double volume) override {
188
+ JNIEnv *env = attach();
189
+ env->CallVoidMethod(_player->get(), _setVolume,
190
+ static_cast<jdouble>(volume));
191
+ clearException(env);
192
+ }
193
+
194
+ bool loop() override { return callBool(_getLoop); }
195
+ void setLoop(bool loop) override {
196
+ JNIEnv *env = attach();
197
+ env->CallVoidMethod(_player->get(), _setLoop, static_cast<jboolean>(loop));
198
+ clearException(env);
199
+ }
200
+
201
+ uint32_t videoWidth() override {
202
+ return static_cast<uint32_t>(callInt(_getVideoWidth));
203
+ }
204
+ uint32_t videoHeight() override {
205
+ return static_cast<uint32_t>(callInt(_getVideoHeight));
206
+ }
207
+ int rotation() override { return callInt(_getRotation); }
208
+ double frameRate() override { return callDouble(_getFrameRate); }
209
+
210
+ private:
211
+ static JNIEnv *attach() {
212
+ facebook::jni::Environment::ensureCurrentThreadIsAttached();
213
+ JNIEnv *env = facebook::jni::Environment::current();
214
+ if (env == nullptr) {
215
+ throw std::runtime_error("VideoPlayer: no JNI environment");
216
+ }
217
+ return env;
218
+ }
219
+
220
+ static jmethodID method(JNIEnv *env, jclass cls, const char *name,
221
+ const char *signature) {
222
+ jmethodID id = env->GetMethodID(cls, name, signature);
223
+ if (id == nullptr) {
224
+ env->ExceptionClear();
225
+ throw std::runtime_error(std::string("VideoPlayer: method ") + name +
226
+ " not found");
227
+ }
228
+ return id;
229
+ }
230
+
231
+ static void clearException(JNIEnv *env) {
232
+ if (env->ExceptionCheck()) {
233
+ env->ExceptionClear();
234
+ }
235
+ }
236
+
237
+ // Single-plane RGB buffers sample as regular textures; everything else
238
+ // (YUV 4:2:0, P010, implementation-defined codec formats) goes through
239
+ // Vulkan's YCbCr conversion as an external texture.
240
+ static bool isRgbFormat(uint32_t format) {
241
+ switch (format) {
242
+ case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
243
+ case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
244
+ case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
245
+ case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
246
+ case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
247
+ case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
248
+ return true;
249
+ default:
250
+ return false;
251
+ }
252
+ }
253
+
254
+ void closeImage(JNIEnv *env, jobject image) {
255
+ env->CallVoidMethod(_player->get(), _closeImage, image);
256
+ clearException(env);
257
+ }
258
+
259
+ void callVoid(jmethodID id) {
260
+ JNIEnv *env = attach();
261
+ env->CallVoidMethod(_player->get(), id);
262
+ clearException(env);
263
+ }
264
+
265
+ bool callBool(jmethodID id) {
266
+ JNIEnv *env = attach();
267
+ bool result = env->CallBooleanMethod(_player->get(), id) == JNI_TRUE;
268
+ clearException(env);
269
+ return result;
270
+ }
271
+
272
+ int callInt(jmethodID id) {
273
+ JNIEnv *env = attach();
274
+ int result = env->CallIntMethod(_player->get(), id);
275
+ clearException(env);
276
+ return result;
277
+ }
278
+
279
+ double callDouble(jmethodID id) {
280
+ JNIEnv *env = attach();
281
+ double result = env->CallDoubleMethod(_player->get(), id);
282
+ clearException(env);
283
+ return result;
284
+ }
285
+
286
+ std::shared_ptr<JavaVideoPlayerRef> _player;
287
+ jmethodID _copyLatestFrame;
288
+ jmethodID _closeImage;
289
+ jmethodID _play;
290
+ jmethodID _pause;
291
+ jmethodID _getPaused;
292
+ jmethodID _getCurrentTime;
293
+ jmethodID _seek;
294
+ jmethodID _getDuration;
295
+ jmethodID _getVolume;
296
+ jmethodID _setVolume;
297
+ jmethodID _getLoop;
298
+ jmethodID _setLoop;
299
+ jmethodID _getVideoWidth;
300
+ jmethodID _getVideoHeight;
301
+ jmethodID _getRotation;
302
+ jmethodID _getFrameRate;
303
+ jmethodID _release;
304
+ jmethodID _getHardwareBuffer;
305
+ };
306
+
307
+ } // namespace rnwgpu
@@ -1,11 +1,15 @@
1
+ #include <cstring>
1
2
  #include <memory>
3
+ #include <string>
2
4
  #include <unordered_map>
5
+ #include <utility>
3
6
 
4
7
  #include <fbjni/fbjni.h>
5
8
  #include <jni.h>
6
9
  #include <jsi/jsi.h>
7
10
 
8
11
  #include <ReactCommon/CallInvokerHolder.h>
12
+ #include <android/bitmap.h>
9
13
  #include <android/hardware_buffer_jni.h>
10
14
  #include <android/native_window_jni.h>
11
15
  #include <webgpu/webgpu_cpp.h>
@@ -19,21 +23,77 @@
19
23
  std::shared_ptr<rnwgpu::RNWebGPUManager> manager;
20
24
 
21
25
  extern "C" JNIEXPORT void JNICALL Java_com_webgpu_WebGPUModule_initializeNative(
22
- JNIEnv *env, jobject /* this */, jlong jsRuntime,
23
- jobject jsCallInvokerHolder, jobject blobModule) {
26
+ JNIEnv *env, jobject thiz, jlong jsRuntime, jobject jsCallInvokerHolder,
27
+ jobject blobModule) {
24
28
  auto runtime = reinterpret_cast<facebook::jsi::Runtime *>(jsRuntime);
25
29
  jobject globalBlobModule = env->NewGlobalRef(blobModule);
30
+ jobject globalModule = env->NewGlobalRef(thiz);
26
31
  auto jsCallInvoker{
27
32
  facebook::jni::alias_ref<facebook::react::CallInvokerHolder::javaobject>{
28
33
  reinterpret_cast<facebook::react::CallInvokerHolder::javaobject>(
29
- jsCallInvokerHolder)} -> cthis()
30
- ->getCallInvoker()};
31
- auto platformContext =
32
- std::make_shared<rnwgpu::AndroidPlatformContext>(globalBlobModule);
34
+ jsCallInvokerHolder)} -> cthis()->getCallInvoker()};
35
+ auto platformContext = std::make_shared<rnwgpu::AndroidPlatformContext>(
36
+ globalBlobModule, globalModule);
33
37
  manager = std::make_shared<rnwgpu::RNWebGPUManager>(runtime, jsCallInvoker,
34
38
  platformContext);
35
39
  }
36
40
 
41
+ // Completion of WebGPUModule.snapshotView (UI thread). Reclaims the callbacks
42
+ // handed to Java and delivers either the bitmap's pixels or the error.
43
+ extern "C" JNIEXPORT void JNICALL Java_com_webgpu_WebGPUModule_onViewSnapshot(
44
+ JNIEnv *env, jobject /* this */, jlong callbackPointer, jobject bitmap,
45
+ jstring error) {
46
+ std::unique_ptr<rnwgpu::ViewSnapshotCallbacks> callbacks(
47
+ reinterpret_cast<rnwgpu::ViewSnapshotCallbacks *>(callbackPointer));
48
+ if (!callbacks) {
49
+ return;
50
+ }
51
+ if (error != nullptr) {
52
+ const char *chars = env->GetStringUTFChars(error, nullptr);
53
+ std::string message(chars ? chars : "drawElementImageToTexture failed");
54
+ if (chars) {
55
+ env->ReleaseStringUTFChars(error, chars);
56
+ }
57
+ callbacks->onError(std::move(message));
58
+ return;
59
+ }
60
+ if (bitmap == nullptr) {
61
+ callbacks->onError("drawElementImageToTexture: no bitmap was produced");
62
+ return;
63
+ }
64
+ AndroidBitmapInfo info;
65
+ if (AndroidBitmap_getInfo(env, bitmap, &info) !=
66
+ ANDROID_BITMAP_RESULT_SUCCESS ||
67
+ info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
68
+ callbacks->onError(
69
+ "drawElementImageToTexture: unexpected snapshot bitmap format");
70
+ return;
71
+ }
72
+ void *pixels = nullptr;
73
+ if (AndroidBitmap_lockPixels(env, bitmap, &pixels) !=
74
+ ANDROID_BITMAP_RESULT_SUCCESS ||
75
+ pixels == nullptr) {
76
+ callbacks->onError(
77
+ "drawElementImageToTexture: couldn't lock the snapshot bitmap");
78
+ return;
79
+ }
80
+ rnwgpu::ImageData image;
81
+ image.width = info.width;
82
+ image.height = info.height;
83
+ image.format = wgpu::TextureFormat::RGBA8Unorm;
84
+ // Bitmap.Config.ARGB_8888 stores premultiplied RGBA bytes.
85
+ image.premultiplied = true;
86
+ const size_t rowBytes = static_cast<size_t>(info.width) * 4;
87
+ image.data.resize(rowBytes * info.height);
88
+ const auto *src = static_cast<const uint8_t *>(pixels);
89
+ for (uint32_t row = 0; row < info.height; ++row) {
90
+ std::memcpy(image.data.data() + row * rowBytes, src + row * info.stride,
91
+ rowBytes);
92
+ }
93
+ AndroidBitmap_unlockPixels(env, bitmap);
94
+ callbacks->onSuccess(std::move(image));
95
+ }
96
+
37
97
  extern "C" JNIEXPORT void JNICALL Java_com_webgpu_WebGPUView_onSurfaceChanged(
38
98
  JNIEnv *env, jobject thiz, jobject surface, jint contextId, jfloat width,
39
99
  jfloat height) {