react-native-skia-webgpu-video 0.1.0-beta.3 → 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.
Files changed (81) hide show
  1. package/README.md +48 -43
  2. package/android/BUILD_VALIDATION.md +1 -1
  3. package/android/CMakeLists.txt +3 -2
  4. package/android/cpp/ExportHintSession.cpp +114 -0
  5. package/android/cpp/ExportHintSession.h +35 -0
  6. package/android/cpp/VideoEncoderHostObject.cpp +76 -101
  7. package/android/cpp/VideoEncoderHostObject.h +14 -9
  8. package/android/cpp/VideoFrame.cpp +3 -5
  9. package/android/cpp/cpp-adapter.cpp +7 -4
  10. package/android/src/main/java/com/azzapp/rnskv/GLFrameExtractor.java +3 -9
  11. package/android/src/main/java/com/azzapp/rnskv/VideoCompositionDecoder.java +8 -11
  12. package/android/src/main/java/com/azzapp/rnskv/VideoEncoder.java +68 -28
  13. package/docs/FRAME_PIXEL_FORMAT.md +17 -2
  14. package/docs/MIGRATION.md +1 -1
  15. package/docs/UPSTREAM_NOTES.md +42 -2
  16. package/ios/RNSVColorSpace.h +8 -3
  17. package/lib/module/canvas.js +3 -5
  18. package/lib/module/canvas.js.map +1 -1
  19. package/lib/module/exportFrames.js +8 -10
  20. package/lib/module/exportFrames.js.map +1 -1
  21. package/lib/module/exportTarget.js +183 -40
  22. package/lib/module/exportTarget.js.map +1 -1
  23. package/lib/module/exportVideoComposition.js +78 -35
  24. package/lib/module/exportVideoComposition.js.map +1 -1
  25. package/lib/module/frameInterop.js +323 -82
  26. package/lib/module/frameInterop.js.map +1 -1
  27. package/lib/module/gpu.js +1 -3
  28. package/lib/module/gpu.js.map +1 -1
  29. package/lib/module/gpuDevice.js +12 -0
  30. package/lib/module/gpuDevice.js.map +1 -1
  31. package/lib/module/memory.js +7 -0
  32. package/lib/module/memory.js.map +1 -1
  33. package/lib/module/previewLifecycle.js +2 -1
  34. package/lib/module/previewLifecycle.js.map +1 -1
  35. package/lib/module/videoCompositionPlayer.js +65 -14
  36. package/lib/module/videoCompositionPlayer.js.map +1 -1
  37. package/lib/module/videoFrameImage.js +1 -1
  38. package/lib/module/yuvBlit.js +31 -24
  39. package/lib/module/yuvBlit.js.map +1 -1
  40. package/lib/typescript/src/canvas.d.ts.map +1 -1
  41. package/lib/typescript/src/exportFrames.d.ts +3 -2
  42. package/lib/typescript/src/exportFrames.d.ts.map +1 -1
  43. package/lib/typescript/src/exportTarget.d.ts +53 -14
  44. package/lib/typescript/src/exportTarget.d.ts.map +1 -1
  45. package/lib/typescript/src/exportVideoComposition.d.ts +2 -1
  46. package/lib/typescript/src/exportVideoComposition.d.ts.map +1 -1
  47. package/lib/typescript/src/frameInterop.d.ts +16 -5
  48. package/lib/typescript/src/frameInterop.d.ts.map +1 -1
  49. package/lib/typescript/src/gpu.d.ts.map +1 -1
  50. package/lib/typescript/src/gpuDevice.d.ts +5 -1
  51. package/lib/typescript/src/gpuDevice.d.ts.map +1 -1
  52. package/lib/typescript/src/memory.d.ts +2 -0
  53. package/lib/typescript/src/memory.d.ts.map +1 -1
  54. package/lib/typescript/src/previewLifecycle.d.ts +2 -0
  55. package/lib/typescript/src/previewLifecycle.d.ts.map +1 -1
  56. package/lib/typescript/src/types.d.ts +18 -12
  57. package/lib/typescript/src/types.d.ts.map +1 -1
  58. package/lib/typescript/src/videoCompositionPlayer.d.ts +4 -5
  59. package/lib/typescript/src/videoCompositionPlayer.d.ts.map +1 -1
  60. package/lib/typescript/src/videoFrameImage.d.ts +1 -1
  61. package/lib/typescript/src/yuvBlit.d.ts +16 -14
  62. package/lib/typescript/src/yuvBlit.d.ts.map +1 -1
  63. package/package.json +6 -6
  64. package/patches/react-native-skia+3.10.0.patch +150 -0
  65. package/scripts/skia-canvas-patch.json +22 -258
  66. package/src/canvas.ts +3 -7
  67. package/src/exportFrames.ts +10 -11
  68. package/src/exportTarget.ts +217 -56
  69. package/src/exportVideoComposition.ts +130 -85
  70. package/src/frameInterop.ts +389 -96
  71. package/src/gpu.ts +1 -3
  72. package/src/gpuDevice.ts +26 -1
  73. package/src/memory.ts +6 -0
  74. package/src/previewLifecycle.ts +4 -1
  75. package/src/types.ts +18 -12
  76. package/src/videoCompositionPlayer.ts +76 -23
  77. package/src/videoFrameImage.ts +1 -1
  78. package/src/yuvBlit.ts +46 -31
  79. package/android/cpp/EncoderTargets.cpp +0 -226
  80. package/android/cpp/EncoderTargets.h +0 -70
  81. package/patches/react-native-skia+3.7.1.patch +0 -502
@@ -1,502 +0,0 @@
1
- --- a/node_modules/react-native-skia/cpp/api/JsiSkCanvas.h
2
- +++ b/node_modules/react-native-skia/cpp/api/JsiSkCanvas.h
3
- @@ -1,6 +1,7 @@
4
- #pragma once
5
-
6
- #include <memory>
7
- +#include <stdexcept>
8
- #include <string>
9
- #include <utility>
10
- #include <vector>
11
- @@ -51,15 +52,15 @@
12
- public:
13
- static constexpr const char *CLASS_NAME = "Canvas";
14
-
15
- - void drawPaint(std::shared_ptr<SkPaint> paint) { _canvas->drawPaint(*paint); }
16
- + void drawPaint(std::shared_ptr<SkPaint> paint) { getCanvas()->drawPaint(*paint); }
17
-
18
- void drawLine(double x1, double y1, double x2, double y2,
19
- std::shared_ptr<SkPaint> paint) {
20
- - _canvas->drawLine(x1, y1, x2, y2, *paint);
21
- + getCanvas()->drawLine(x1, y1, x2, y2, *paint);
22
- }
23
-
24
- void drawRect(std::shared_ptr<SkRect> rect, std::shared_ptr<SkPaint> paint) {
25
- - _canvas->drawRect(*rect, *paint);
26
- + getCanvas()->drawRect(*rect, *paint);
27
- }
28
-
29
- // The drawImage* variants stay raw: they dispatch on exact argument counts
30
- @@ -72,7 +73,7 @@
31
- if (count >= 4 && !arguments[3].isNull() && !arguments[3].isUndefined()) {
32
- paint = JsiSkPaint::fromValue(runtime, arguments[3]);
33
- }
34
- - _canvas->drawImage(image, x, y, SkSamplingOptions(), paint.get());
35
- + getCanvas()->drawImage(image, x, y, SkSamplingOptions(), paint.get());
36
- return jsi::Value::undefined();
37
- }
38
-
39
- @@ -82,7 +83,7 @@
40
- auto dest = JsiSkRect::fromValue(runtime, arguments[2]);
41
- auto paint = JsiSkPaint::fromValue(runtime, arguments[3]);
42
- auto fastSample = count >= 5 && arguments[4].getBool();
43
- - _canvas->drawImageRect(image, *src, *dest, SkSamplingOptions(), paint.get(),
44
- + getCanvas()->drawImageRect(image, *src, *dest, SkSamplingOptions(), paint.get(),
45
- fastSample ? SkCanvas::kFast_SrcRectConstraint
46
- : SkCanvas::kStrict_SrcRectConstraint);
47
- return jsi::Value::undefined();
48
- @@ -98,7 +99,7 @@
49
- if (count >= 6 && !arguments[5].isNull() && !arguments[5].isUndefined()) {
50
- paint = JsiSkPaint::fromValue(runtime, arguments[5]);
51
- }
52
- - _canvas->drawImage(image, x, y, SkSamplingOptions({B, C}), paint.get());
53
- + getCanvas()->drawImage(image, x, y, SkSamplingOptions({B, C}), paint.get());
54
- return jsi::Value::undefined();
55
- }
56
-
57
- @@ -112,7 +113,7 @@
58
- if (count >= 6 && !arguments[5].isNull() && !arguments[5].isUndefined()) {
59
- paint = JsiSkPaint::fromValue(runtime, arguments[5]);
60
- }
61
- - _canvas->drawImage(image, x, y, SkSamplingOptions(fm, mm), paint.get());
62
- + getCanvas()->drawImage(image, x, y, SkSamplingOptions(fm, mm), paint.get());
63
- return jsi::Value::undefined();
64
- }
65
-
66
- @@ -125,7 +126,7 @@
67
- if (count >= 5 && !arguments[4].isNull() && !arguments[4].isUndefined()) {
68
- paint = JsiSkPaint::fromValue(runtime, arguments[4]);
69
- }
70
- - _canvas->drawImageNine(image.get(), center->round(), *dest, fm,
71
- + getCanvas()->drawImageNine(image.get(), center->round(), *dest, fm,
72
- paint.get());
73
- return jsi::Value::undefined();
74
- }
75
- @@ -142,7 +143,7 @@
76
- }
77
- auto constraint =
78
- SkCanvas::kStrict_SrcRectConstraint; // TODO: get from caller
79
- - _canvas->drawImageRect(image.get(), *src, *dest, SkSamplingOptions({B, C}),
80
- + getCanvas()->drawImageRect(image.get(), *src, *dest, SkSamplingOptions({B, C}),
81
- paint.get(), constraint);
82
- return jsi::Value::undefined();
83
- }
84
- @@ -158,44 +159,44 @@
85
- paint = JsiSkPaint::fromValue(runtime, arguments[5]);
86
- }
87
- auto constraint = SkCanvas::kStrict_SrcRectConstraint;
88
- - _canvas->drawImageRect(image.get(), *src, *dest, {filter, mipmap},
89
- + getCanvas()->drawImageRect(image.get(), *src, *dest, {filter, mipmap},
90
- paint.get(), constraint);
91
- return jsi::Value::undefined();
92
- }
93
-
94
- void drawCircle(double cx, double cy, double radius,
95
- std::shared_ptr<SkPaint> paint) {
96
- - _canvas->drawCircle(cx, cy, radius, *paint);
97
- + getCanvas()->drawCircle(cx, cy, radius, *paint);
98
- }
99
-
100
- void drawArc(std::shared_ptr<SkRect> oval, double startAngle,
101
- double sweepAngle, bool useCenter,
102
- std::shared_ptr<SkPaint> paint) {
103
- - _canvas->drawArc(*oval, startAngle, sweepAngle, useCenter, *paint);
104
- + getCanvas()->drawArc(*oval, startAngle, sweepAngle, useCenter, *paint);
105
- }
106
-
107
- void drawRRect(std::shared_ptr<SkRRect> rect,
108
- std::shared_ptr<SkPaint> paint) {
109
- - _canvas->drawRRect(*rect, *paint);
110
- + getCanvas()->drawRRect(*rect, *paint);
111
- }
112
-
113
- void drawDRRect(std::shared_ptr<SkRRect> outer,
114
- std::shared_ptr<SkRRect> inner,
115
- std::shared_ptr<SkPaint> paint) {
116
- - _canvas->drawDRRect(*outer, *inner, *paint);
117
- + getCanvas()->drawDRRect(*outer, *inner, *paint);
118
- }
119
-
120
- void drawOval(std::shared_ptr<SkRect> rect, std::shared_ptr<SkPaint> paint) {
121
- - _canvas->drawOval(*rect, *paint);
122
- + getCanvas()->drawOval(*rect, *paint);
123
- }
124
-
125
- - void restoreToCount(double c) { _canvas->restoreToCount(c); }
126
- + void restoreToCount(double c) { getCanvas()->restoreToCount(c); }
127
-
128
- - int getSaveCount() { return static_cast<int>(_canvas->getSaveCount()); }
129
- + int getSaveCount() { return static_cast<int>(getCanvas()->getSaveCount()); }
130
-
131
- std::shared_ptr<JsiSkMatrix> getTotalMatrix() {
132
- return std::make_shared<JsiSkMatrix>(getContext(),
133
- - _canvas->getTotalMatrix());
134
- + getCanvas()->getTotalMatrix());
135
- }
136
-
137
- void drawPoints(double pointMode, std::vector<SkPoint> points,
138
- @@ -204,12 +205,12 @@
139
- return;
140
- }
141
- auto p = SkSpan(points.data(), points.size());
142
- - _canvas->drawPoints(static_cast<SkCanvas::PointMode>(pointMode), p, *paint);
143
- + getCanvas()->drawPoints(static_cast<SkCanvas::PointMode>(pointMode), p, *paint);
144
- }
145
-
146
- void drawVertices(sk_sp<SkVertices> vertices, double blendMode,
147
- std::shared_ptr<SkPaint> paint) {
148
- - _canvas->drawVertices(vertices, toBlendMode(blendMode), *paint);
149
- + getCanvas()->drawVertices(vertices, toBlendMode(blendMode), *paint);
150
- }
151
-
152
- JSI_HOST_FUNCTION(drawPatch) {
153
- @@ -279,7 +280,7 @@
154
- paint = JsiSkPaint::fromValue(runtime, arguments[4]);
155
- }
156
- SkPaint defaultPaint;
157
- - _canvas->drawPatch(cubics.data(), colors.empty() ? nullptr : colors.data(),
158
- + getCanvas()->drawPatch(cubics.data(), colors.empty() ? nullptr : colors.data(),
159
- texs.empty() ? nullptr : texs.data(), blendMode,
160
- paint ? *paint : defaultPaint);
161
- return jsi::Value::undefined();
162
- @@ -287,19 +288,19 @@
163
-
164
- void drawPath(std::shared_ptr<SkPathBuilder> path,
165
- std::shared_ptr<SkPaint> paint) {
166
- - _canvas->drawPath(path->snapshot(), *paint);
167
- + getCanvas()->drawPath(path->snapshot(), *paint);
168
- }
169
-
170
- void drawText(std::string textVal, double x, double y,
171
- std::shared_ptr<SkPaint> paint, std::shared_ptr<SkFont> font) {
172
- auto text = textVal.c_str();
173
- - _canvas->drawSimpleText(text, strlen(text), SkTextEncoding::kUTF8, x, y,
174
- + getCanvas()->drawSimpleText(text, strlen(text), SkTextEncoding::kUTF8, x, y,
175
- *font, *paint);
176
- }
177
-
178
- void drawTextBlob(sk_sp<SkTextBlob> blob, double x, double y,
179
- std::shared_ptr<SkPaint> paint) {
180
- - _canvas->drawTextBlob(blob, x, y, *paint);
181
- + getCanvas()->drawTextBlob(blob, x, y, *paint);
182
- }
183
-
184
- void drawGlyphs(std::vector<int> glyphIds, std::vector<SkPoint> positions,
185
- @@ -321,7 +322,7 @@
186
-
187
- auto g = SkSpan(glyphs.data(), glyphs.size());
188
- auto p = SkSpan(positions.data(), positions.size());
189
- - _canvas->drawGlyphs(g, p, origin, *font, *paint);
190
- + getCanvas()->drawGlyphs(g, p, origin, *font, *paint);
191
- }
192
-
193
- void drawSvg(sk_sp<SkSVGDOM> svgdom, JsiOptional<double> w,
194
- @@ -329,26 +330,26 @@
195
- if (w.has_value() && h.has_value()) {
196
- svgdom->setContainerSize(SkSize::Make(*w, *h));
197
- } else {
198
- - auto canvasSize = _canvas->getBaseLayerSize();
199
- + auto canvasSize = getCanvas()->getBaseLayerSize();
200
- svgdom->setContainerSize(SkSize::Make(canvasSize));
201
- }
202
- - svgdom->render(_canvas);
203
- + svgdom->render(getCanvas());
204
- }
205
-
206
- void clipPath(std::shared_ptr<SkPathBuilder> path, double op,
207
- bool doAntiAlias) {
208
- - _canvas->clipPath(path->snapshot(), static_cast<SkClipOp>(op), doAntiAlias);
209
- + getCanvas()->clipPath(path->snapshot(), static_cast<SkClipOp>(op), doAntiAlias);
210
- }
211
-
212
- void clipRect(std::shared_ptr<SkRect> rect, double op, bool doAntiAlias) {
213
- - _canvas->clipRect(*rect, static_cast<SkClipOp>(op), doAntiAlias);
214
- + getCanvas()->clipRect(*rect, static_cast<SkClipOp>(op), doAntiAlias);
215
- }
216
-
217
- void clipRRect(std::shared_ptr<SkRRect> rrect, double op, bool doAntiAlias) {
218
- - _canvas->clipRRect(*rrect, static_cast<SkClipOp>(op), doAntiAlias);
219
- + getCanvas()->clipRRect(*rrect, static_cast<SkClipOp>(op), doAntiAlias);
220
- }
221
-
222
- - int save() { return _canvas->save(); }
223
- + int save() { return getCanvas()->save(); }
224
-
225
- JSI_HOST_FUNCTION(saveLayer) {
226
- // Keep the wrapper smart pointers alive for the duration of the call:
227
- @@ -372,35 +373,35 @@
228
- count >= 4 && !arguments[3].isNull() && !arguments[3].isUndefined()
229
- ? static_cast<SkCanvas::SaveLayerFlags>(arguments[3].asNumber())
230
- : 0;
231
- - return jsi::Value(_canvas->saveLayer(SkCanvas::SaveLayerRec(
232
- + return jsi::Value(getCanvas()->saveLayer(SkCanvas::SaveLayerRec(
233
- boundsPtr.get(), paintPtr.get(), backdropPtr.get(), flags)));
234
- }
235
-
236
- - void restore() { _canvas->restore(); }
237
- + void restore() { getCanvas()->restore(); }
238
-
239
- void rotate(double degrees, double rx, double ry) {
240
- - _canvas->rotate(degrees, rx, ry);
241
- + getCanvas()->rotate(degrees, rx, ry);
242
- }
243
-
244
- - void translate(double dx, double dy) { _canvas->translate(dx, dy); }
245
- + void translate(double dx, double dy) { getCanvas()->translate(dx, dy); }
246
-
247
- - void scale(double sx, double sy) { _canvas->scale(sx, sy); }
248
- + void scale(double sx, double sy) { getCanvas()->scale(sx, sy); }
249
-
250
- - void skew(double sx, double sy) { _canvas->skew(sx, sy); }
251
- + void skew(double sx, double sy) { getCanvas()->skew(sx, sy); }
252
-
253
- void drawColor(JsiColor cl, JsiOptional<double> mode) {
254
- if (mode.has_value()) {
255
- - _canvas->drawColor(cl, toBlendMode(*mode));
256
- + getCanvas()->drawColor(cl, toBlendMode(*mode));
257
- } else {
258
- - _canvas->drawColor(cl);
259
- + getCanvas()->drawColor(cl);
260
- }
261
- }
262
-
263
- - void clear(JsiColor cl) { _canvas->clear(cl); }
264
- + void clear(JsiColor cl) { getCanvas()->clear(cl); }
265
-
266
- - void concat(std::shared_ptr<SkMatrix> matrix) { _canvas->concat(*matrix); }
267
- + void concat(std::shared_ptr<SkMatrix> matrix) { getCanvas()->concat(*matrix); }
268
-
269
- - void drawPicture(sk_sp<SkPicture> picture) { _canvas->drawPicture(picture); }
270
- + void drawPicture(sk_sp<SkPicture> picture) { getCanvas()->drawPicture(picture); }
271
-
272
- JSI_HOST_FUNCTION(drawAtlas) {
273
- auto atlas = JsiSkImage::fromValue(runtime, arguments[0]);
274
- @@ -473,13 +474,14 @@
275
- auto x = SkSpan(xforms.data(), xforms.size());
276
- auto t = SkSpan(skRects.data(), skRects.size());
277
- auto c = SkSpan(colors.data(), colors.size());
278
- - _canvas->drawAtlas(atlas.get(), x, t, c, blendMode, sampling, nullptr,
279
- + getCanvas()->drawAtlas(atlas.get(), x, t, c, blendMode, sampling, nullptr,
280
- paint.get());
281
-
282
- return jsi::Value::undefined();
283
- }
284
-
285
- JSI_HOST_FUNCTION(readPixels) {
286
- + getCanvas(); // Validate before allocating a readback buffer.
287
- auto srcX = static_cast<int>(arguments[0].asNumber());
288
- auto srcY = static_cast<int>(arguments[1].asNumber());
289
- auto info = JsiSkImageInfo::fromValue(runtime, arguments[2]);
290
- @@ -523,13 +525,14 @@
291
- return dest;
292
- }
293
-
294
- - if (!_canvas->readPixels(*info, bfrPtr, bytesPerRow, srcX, srcY)) {
295
- + if (!getCanvas()->readPixels(*info, bfrPtr, bytesPerRow, srcX, srcY)) {
296
- return jsi::Value::null();
297
- }
298
- return dest;
299
- }
300
-
301
- static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) {
302
- + installMethod(runtime, prototype, "dispose", &JsiSkCanvas::dispose);
303
- installMethod(runtime, prototype, "drawPaint", &JsiSkCanvas::drawPaint);
304
- installMethod(runtime, prototype, "drawLine", &JsiSkCanvas::drawLine);
305
- installMethod(runtime, prototype, "drawRect", &JsiSkCanvas::drawRect);
306
- @@ -606,7 +609,21 @@
307
- }
308
-
309
- void setCanvas(SkCanvas *canvas) { _canvas = canvas; }
310
- - SkCanvas *getCanvas() { return _canvas; }
311
- + SkCanvas *getCanvas() {
312
- + if (!_canvas) throw std::runtime_error("Canvas has been disposed");
313
- + return _canvas;
314
- + }
315
- + // Release the owning surface deterministically. The caller must
316
- + // submit/wait for its recording before disposal. Off the creating
317
- + // thread, the surface is handed to that thread's dispatcher.
318
- + void dispose() {
319
- + _canvas = nullptr;
320
- + if (_dispatcher) {
321
- + _dispatcher->release(std::move(_surface));
322
- + } else {
323
- + _surface.reset();
324
- + }
325
- + }
326
-
327
- // Optionally associate the canvas with its owning surface, keeping it alive
328
- // as long as the canvas. This lets readPixels fall back to a surface
329
- @@ -619,7 +636,7 @@
330
- }
331
-
332
- private:
333
- - SkCanvas *_canvas;
334
- + SkCanvas *_canvas = nullptr;
335
- sk_sp<SkSurface> _surface;
336
- std::shared_ptr<Dispatcher> _dispatcher;
337
- };
338
- --- a/node_modules/react-native-skia/src/skia/types/Canvas.ts
339
- +++ b/node_modules/react-native-skia/src/skia/types/Canvas.ts
340
- @@ -32,6 +32,8 @@
341
- }
342
-
343
- export interface SkCanvas {
344
- + /** Release the owning surface after flushing; idempotent. */
345
- + dispose(): void;
346
- /**
347
- * Draws the given image with its top-left corner at (left, top) using the current clip,
348
- * the current matrix, and optionally-provided paint.
349
- --- a/node_modules/react-native-skia/lib/typescript/src/skia/types/Canvas.d.ts
350
- +++ b/node_modules/react-native-skia/lib/typescript/src/skia/types/Canvas.d.ts
351
- @@ -23,6 +23,8 @@
352
- SaveLayerF16ColorType = 16
353
- }
354
- export interface SkCanvas {
355
- + /** Release the owning surface after flushing; idempotent. */
356
- + dispose(): void;
357
- /**
358
- * Draws the given image with its top-left corner at (left, top) using the current clip,
359
- * the current matrix, and optionally-provided paint.
360
- --- a/node_modules/react-native-skia/cpp/api/JsiSkSurface.h
361
- +++ b/node_modules/react-native-skia/cpp/api/JsiSkSurface.h
362
- @@ -44,6 +44,25 @@
363
- _dispatcher->processQueue();
364
- }
365
-
366
- + // Opt-in for consumers that release native buffers after GPU completion.
367
- + // Other Skia surfaces preserve their existing flush/snapshot behavior.
368
- + void enableCheckedSubmissions() {
369
- + if (!getObject()->recorder()) {
370
- + throw std::runtime_error("Checked GPU submissions require a Graphite surface");
371
- + }
372
- + _checkedSubmissions = true;
373
- + }
374
- +
375
- + void submitRecording(skgpu::graphite::Recording *recording,
376
- + skgpu::graphite::SyncToCpu syncToCpu =
377
- + skgpu::graphite::SyncToCpu::kNo) {
378
- + if (_checkedSubmissions) {
379
- + DawnContext::getInstance().submitRecordingChecked(recording, syncToCpu);
380
- + } else {
381
- + DawnContext::getInstance().submitRecording(recording, syncToCpu);
382
- + }
383
- + }
384
- +
385
- ~JsiSkSurface() override {
386
- if (!isDisposed()) {
387
- releaseResources();
388
- @@ -76,7 +95,7 @@
389
- // only Graphite-backed surfaces need to snap and submit a recording.
390
- if (auto *recorder = surface->recorder()) {
391
- auto recording = recorder->snap();
392
- - DawnContext::getInstance().submitRecording(
393
- + submitRecording(
394
- recording.get(), sync ? skgpu::graphite::SyncToCpu::kYes
395
- : skgpu::graphite::SyncToCpu::kNo);
396
- }
397
- @@ -111,11 +130,15 @@
398
- } else {
399
- image = surface->makeImageSnapshot();
400
- }
401
- + // Preserve the previously published image if snapshot allocation failed.
402
- + if (!image) {
403
- + throw jsi::JSError(runtime, "Cannot allocate Skia surface snapshot");
404
- + }
405
- // A raster surface (e.g. Skia.Surface.Make) has no Graphite recorder; its
406
- // snapshot is already a valid CPU image, so skip the recording submit.
407
- if (auto *recorder = surface->recorder()) {
408
- auto recording = recorder->snap();
409
- - DawnContext::getInstance().submitRecording(recording.get());
410
- + submitRecording(recording.get());
411
- }
412
- if (count > 1 && arguments[1].isObject()) {
413
- auto jsiImage = getJsiObject<JsiSkImage>(runtime, arguments[1]);
414
- @@ -188,6 +211,8 @@
415
- &JsiSkSurface::makeImageSnapshot);
416
- installMethod(runtime, prototype, "asImage", &JsiSkSurface::asImage);
417
- installMethod(runtime, prototype, "flush", &JsiSkSurface::flush);
418
- + installMethod(runtime, prototype, "enableCheckedSubmissions",
419
- + &JsiSkSurface::enableCheckedSubmissions);
420
- }
421
-
422
- protected:
423
- @@ -203,6 +228,7 @@
424
-
425
- private:
426
- std::shared_ptr<Dispatcher> _dispatcher;
427
- + bool _checkedSubmissions = false;
428
- };
429
-
430
- } // namespace RNSkia
431
- --- a/node_modules/react-native-skia/cpp/rnskia/RNDawnContext.h
432
- +++ b/node_modules/react-native-skia/cpp/rnskia/RNDawnContext.h
433
- @@ -301,6 +301,27 @@
434
- fGraphiteContext->submit(syncToCpu);
435
- }
436
-
437
- + // Checked only for surfaces that explicitly opt into this contract. A valid
438
- + // empty Recording is accepted; Recorder::snap() returns nullptr on failure.
439
- + void submitRecordingChecked(
440
- + skgpu::graphite::Recording *recording,
441
- + skgpu::graphite::SyncToCpu syncToCpu = skgpu::graphite::SyncToCpu::kNo) {
442
- + std::lock_guard<std::mutex> lock(_mutex);
443
- + if (!recording) {
444
- + throw std::runtime_error("Cannot create checked Graphite recording");
445
- + }
446
- + skgpu::graphite::InsertRecordingInfo info;
447
- + info.fRecording = recording;
448
- + auto status = fGraphiteContext->insertRecording(info);
449
- + if (!static_cast<bool>(status)) {
450
- + throw std::runtime_error("Graphite rejected a checked recording: " +
451
- + status.message());
452
- + }
453
- + if (!fGraphiteContext->submit(syncToCpu)) {
454
- + throw std::runtime_error("Graphite checked submission failed");
455
- + }
456
- + }
457
- +
458
- // Create offscreen surface
459
- sk_sp<SkSurface> MakeOffscreen(int width, int height,
460
- bool useP3ColorSpace = false) {
461
- --- a/node_modules/react-native-skia/cpp/rnskia/RNImageProvider.h
462
- +++ b/node_modules/react-native-skia/cpp/rnskia/RNImageProvider.h
463
- @@ -21,7 +21,7 @@
464
- ImageProvider() : fCache(kDefaultNumCachedImages) {}
465
- ~ImageProvider() override {}
466
-
467
- - static sk_sp<ImageProvider> Make() { return sk_ref_sp(new ImageProvider); }
468
- + static sk_sp<ImageProvider> Make() { return sk_make_sp<ImageProvider>(); }
469
-
470
- sk_sp<SkImage>
471
- findOrCreate(skgpu::graphite::Recorder *recorder, const SkImage *image,
472
- --- a/node_modules/react-native-skia/cpp/api/JsiSkApi.h
473
- +++ b/node_modules/react-native-skia/cpp/api/JsiSkApi.h
474
- @@ -156,6 +156,19 @@
475
- JSI_HOST_FUNCTION(Color) {
476
- return JsiSkColor::createCtor()(runtime, thisValue, arguments, count);
477
- }
478
- + // Private video-export cleanup. Only the calling thread's Recorder cache
479
- + // is trimmed; the shared Context cache and other Recorders are untouched.
480
- + JSI_HOST_FUNCTION(__rnskvTrimRecorderCache) {
481
- + auto &context = DawnContext::getInstance();
482
- + auto *recorder = context.getRecorder();
483
- + {
484
- + auto recording = recorder->snap();
485
- + context.submitRecordingChecked(recording.get(),
486
- + skgpu::graphite::SyncToCpu::kYes);
487
- + }
488
- + recorder->freeGpuResources();
489
- + return jsi::Value::undefined();
490
- + }
491
- JSI_HOST_FUNCTION(getNativeDevice) {
492
- // Raw WGPUDevice pointer of the Graphite device, as a BigInt. Consumed by
493
- // react-native-webgpu's importDevice(), which AddRefs it; the pointer
494
- @@ -249,6 +262,8 @@
495
- }
496
-
497
- static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) {
498
- + installHostMethod(runtime, prototype, "__rnskvTrimRecorderCache",
499
- + &JsiSkApi::__rnskvTrimRecorderCache);
500
- installHostMethod(runtime, prototype, "getNativeDevice",
501
- &JsiSkApi::getNativeDevice);
502
- installGetterWithRuntime(runtime, prototype, "gpu", &JsiSkApi::getGpu);