react-native-skia 2.15.0 → 3.0.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 (98) hide show
  1. package/android/CMakeLists.txt +1 -0
  2. package/android/build.gradle +17 -0
  3. package/android/cpp/jni/include/JniSkiaBaseView.h +9 -4
  4. package/android/cpp/jni/include/JniSkiaGraphiteView.h +2 -2
  5. package/android/cpp/jni/include/JniSkiaPictureView.h +1 -12
  6. package/cpp/api/recorder/ColorFilters.h +1 -0
  7. package/cpp/api/recorder/Convertor.h +39 -11
  8. package/cpp/api/recorder/DataTypes.h +12 -0
  9. package/cpp/api/recorder/DrawingCtx.h +14 -0
  10. package/cpp/api/recorder/Drawings.h +5 -0
  11. package/cpp/api/recorder/PathEffects.h +8 -0
  12. package/cpp/api/recorder/RNRecorder.h +68 -11
  13. package/cpp/api/recorder/Shaders.h +3 -0
  14. package/cpp/dawn/include/dawn/dawn_proc.h +53 -0
  15. package/cpp/dawn/include/dawn/dawn_proc_table.h +329 -0
  16. package/cpp/dawn/include/dawn/dawn_thread_dispatch_proc.h +47 -0
  17. package/cpp/dawn/include/dawn/dawn_version.h +41 -0
  18. package/cpp/dawn/include/dawn/native/D3D11Backend.h +65 -0
  19. package/cpp/dawn/include/dawn/native/D3D12Backend.h +104 -0
  20. package/cpp/dawn/include/dawn/native/D3DBackend.h +56 -0
  21. package/cpp/dawn/include/dawn/native/DawnNative.h +367 -0
  22. package/cpp/dawn/include/dawn/native/MetalBackend.h +56 -0
  23. package/cpp/dawn/include/dawn/native/NullBackend.h +39 -0
  24. package/cpp/dawn/include/dawn/native/OpenGLBackend.h +89 -0
  25. package/cpp/dawn/include/dawn/native/VulkanBackend.h +183 -0
  26. package/cpp/dawn/include/dawn/native/WebGPUBackend.h +49 -0
  27. package/cpp/dawn/include/dawn/native/dawn_native_export.h +49 -0
  28. package/cpp/dawn/include/dawn/platform/DawnPlatform.h +211 -0
  29. package/cpp/dawn/include/dawn/platform/dawn_platform_export.h +49 -0
  30. package/cpp/dawn/include/dawn/replay/Replay.h +99 -0
  31. package/cpp/dawn/include/dawn/replay/dawn_replay_export.h +49 -0
  32. package/cpp/dawn/include/dawn/webgpu_cpp_print.h +2868 -0
  33. package/cpp/dawn/include/tint/tint.h +91 -0
  34. package/cpp/dawn/include/webgpu/webgpu.h +5063 -0
  35. package/cpp/dawn/include/webgpu/webgpu_cpp.h +10401 -0
  36. package/cpp/dawn/include/webgpu/webgpu_cpp_chained_struct.h +57 -0
  37. package/cpp/dawn/include/webgpu/webgpu_enum_class_bitmasks.h +163 -0
  38. package/cpp/dawn/include/webgpu/webgpu_glfw.h +88 -0
  39. package/cpp/rnskia/RNDawnContext.h +6 -0
  40. package/cpp/rnskia/RNSkGraphiteProducer.cpp +189 -0
  41. package/cpp/rnskia/RNSkGraphiteProducer.h +116 -0
  42. package/cpp/rnskia/RNSkGraphiteView.h +129 -24
  43. package/cpp/rnskia/RNSkJsiViewApi.h +2 -6
  44. package/cpp/rnskia/RNSkPictureView.cpp +22 -11
  45. package/cpp/rnskia/RNSkPictureView.h +24 -11
  46. package/cpp/rnskia/RNSkThreadPool.h +91 -0
  47. package/cpp/rnskia/RNSkView.h +18 -0
  48. package/cpp/skia/src/gpu/graphite/ContextOptionsPriv.h +45 -0
  49. package/cpp/skia/src/gpu/graphite/ResourceTypes.h +362 -0
  50. package/cpp/skia/src/gpu/graphite/TextureProxyView.h +105 -0
  51. package/lib/commonjs/index.d.ts +4 -1
  52. package/lib/commonjs/index.js +31 -12
  53. package/lib/commonjs/index.js.map +1 -1
  54. package/lib/commonjs/mock/index.js +1 -0
  55. package/lib/commonjs/mock/index.js.map +1 -1
  56. package/lib/commonjs/renderer/Canvas.d.ts +10 -1
  57. package/lib/commonjs/renderer/Canvas.js +37 -10
  58. package/lib/commonjs/renderer/Canvas.js.map +1 -1
  59. package/lib/commonjs/renderer/DefaultCanvas.d.ts +8 -0
  60. package/lib/commonjs/renderer/DefaultCanvas.js +42 -0
  61. package/lib/commonjs/renderer/DefaultCanvas.js.map +1 -0
  62. package/lib/commonjs/renderer/GraphiteCanvas.d.ts +22 -0
  63. package/lib/commonjs/renderer/GraphiteCanvas.js +64 -0
  64. package/lib/commonjs/renderer/GraphiteCanvas.js.map +1 -0
  65. package/lib/commonjs/renderer/GraphiteCanvas.web.d.ts +1 -0
  66. package/lib/commonjs/renderer/GraphiteCanvas.web.js +13 -0
  67. package/lib/commonjs/renderer/GraphiteCanvas.web.js.map +1 -0
  68. package/lib/module/index.d.ts +4 -1
  69. package/lib/module/index.js +3 -1
  70. package/lib/module/index.js.map +1 -1
  71. package/lib/module/mock/index.js +1 -0
  72. package/lib/module/mock/index.js.map +1 -1
  73. package/lib/module/renderer/Canvas.d.ts +10 -1
  74. package/lib/module/renderer/Canvas.js +35 -9
  75. package/lib/module/renderer/Canvas.js.map +1 -1
  76. package/lib/module/renderer/DefaultCanvas.d.ts +8 -0
  77. package/lib/module/renderer/DefaultCanvas.js +34 -0
  78. package/lib/module/renderer/DefaultCanvas.js.map +1 -0
  79. package/lib/module/renderer/GraphiteCanvas.d.ts +22 -0
  80. package/lib/module/renderer/GraphiteCanvas.js +57 -0
  81. package/lib/module/renderer/GraphiteCanvas.js.map +1 -0
  82. package/lib/module/renderer/GraphiteCanvas.web.d.ts +1 -0
  83. package/lib/module/renderer/GraphiteCanvas.web.js +4 -0
  84. package/lib/module/renderer/GraphiteCanvas.web.js.map +1 -0
  85. package/lib/typescript/src/index.d.ts +4 -1
  86. package/lib/typescript/src/renderer/Canvas.d.ts +10 -1
  87. package/lib/typescript/src/renderer/DefaultCanvas.d.ts +8 -0
  88. package/lib/typescript/src/renderer/GraphiteCanvas.d.ts +22 -0
  89. package/lib/typescript/src/renderer/GraphiteCanvas.web.d.ts +1 -0
  90. package/libs/.graphite +1 -0
  91. package/package.json +7 -8
  92. package/react-native-skia.podspec +18 -1
  93. package/src/index.ts +4 -1
  94. package/src/mock/index.ts +1 -0
  95. package/src/renderer/Canvas.tsx +29 -9
  96. package/src/renderer/DefaultCanvas.tsx +41 -0
  97. package/src/renderer/GraphiteCanvas.tsx +61 -0
  98. package/src/renderer/GraphiteCanvas.web.tsx +3 -0
@@ -14,6 +14,7 @@
14
14
 
15
15
  #include "RNDawnContext.h"
16
16
  #include "RNDawnUtils.h"
17
+ #include "RNSkGraphiteProducer.h"
17
18
  #include "RNSkPlatformContext.h"
18
19
  #include "RNSkView.h"
19
20
  #include "jsi/ViewProperty.h"
@@ -59,14 +60,31 @@ public:
59
60
  skgpu::graphite::Recording *get() const { return _recording.get(); }
60
61
 
61
62
  /**
62
- Whether the recording can be replayed onto the given target: same format,
63
- and the target supports every usage the recording relies on.
63
+ Whether the recording was made for a texture of the given size. A deferred
64
+ canvas records against fixed dimensions: replaying it onto a texture of
65
+ another size makes Graphite copy and draw outside of it, which Dawn
66
+ rejects (the whole frame is then dropped). A view that was resized has
67
+ stale recordings in flight; they are skipped and the content is recorded
68
+ again for the new size.
64
69
  */
65
- bool isCompatibleWith(const RNSkGraphiteTargetInfo &target) const {
70
+ bool hasSizeOf(const RNSkGraphiteTargetInfo &target) const {
71
+ return _target.width == target.width && _target.height == target.height;
72
+ }
73
+
74
+ /**
75
+ Whether the recording has the format of the given target, and the target
76
+ supports every usage the recording relies on.
77
+ */
78
+ bool hasFormatOf(const RNSkGraphiteTargetInfo &target) const {
66
79
  return _target.colorType == target.colorType &&
67
80
  _target.textureInfo.canBeFulfilledBy(target.textureInfo);
68
81
  }
69
82
 
83
+ /** Whether the recording can be replayed onto the given target. */
84
+ bool isCompatibleWith(const RNSkGraphiteTargetInfo &target) const {
85
+ return hasSizeOf(target) && hasFormatOf(target);
86
+ }
87
+
70
88
  private:
71
89
  // Declared before the recording so that the recording is released first.
72
90
  std::shared_ptr<RNSkGraphiteRecorder> _recorder;
@@ -364,6 +382,20 @@ public:
364
382
  _target = std::move(target);
365
383
  }
366
384
 
385
+ /**
386
+ Called on the main thread after each presented frame (the producer paces
387
+ itself on it) and whenever the view asks for a redraw: a new surface, a
388
+ resize, or SkiaViewApi.requestRedraw. The latter returns whether a frame
389
+ is coming for it. Set once, at construction.
390
+ */
391
+ void setOnPresented(std::function<void()> callback) {
392
+ _onPresented = std::move(callback);
393
+ }
394
+
395
+ void setOnRedraw(std::function<bool()> callback) {
396
+ _onRedraw = std::move(callback);
397
+ }
398
+
367
399
  /**
368
400
  Presents everything submitted since the last frame. With nothing queued,
369
401
  presents the last frame again: a redraw after a resize or on a new
@@ -376,6 +408,8 @@ public:
376
408
  if (!canvasProvider->getGraphiteTargetInfo(&targetInfo)) {
377
409
  return;
378
410
  }
411
+ // Declarative content is recorded again for the surface as it is now.
412
+ const bool frameComing = _onRedraw && _onRedraw();
379
413
  std::shared_ptr<RNSkGraphiteTarget> target;
380
414
  std::shared_ptr<RNSkGraphiteRecording> lastPresented;
381
415
  {
@@ -388,24 +422,33 @@ public:
388
422
  recordings = target->takeQueued();
389
423
  }
390
424
  if (recordings.empty()) {
391
- if (lastPresented == nullptr) {
425
+ // With a frame on its way, the layer keeps showing the last one until
426
+ // it lands: presenting it again would only cost a second present. The
427
+ // same holds after a resize, when the last frame has the old size.
428
+ if (frameComing || lastPresented == nullptr ||
429
+ !lastPresented->hasSizeOf(targetInfo)) {
392
430
  return;
393
431
  }
394
- present(canvasProvider, targetInfo, {lastPresented},
395
- /* remember= */ true);
432
+ if (present(canvasProvider, targetInfo, {lastPresented},
433
+ /* remember= */ true)) {
434
+ notifyPresented();
435
+ }
396
436
  return;
397
437
  }
398
- if (!present(canvasProvider, targetInfo, recordings,
399
- /* remember= */ true) &&
400
- target) {
438
+ if (present(canvasProvider, targetInfo, recordings,
439
+ /* remember= */ true)) {
440
+ notifyPresented();
441
+ } else if (target) {
401
442
  target->requeue(recordings);
402
443
  }
403
444
  }
404
445
 
405
446
  /**
406
447
  Presents the queued recordings, if any. Returns whether more are waiting,
407
- so that the caller keeps its frame callback armed. Without a surface the
408
- queue is left alone: the surface presents it when it appears.
448
+ so that the caller keeps its frame callback armed: also when the present
449
+ failed (the app is in the background), so that the recordings are tried
450
+ again on the next frame rather than left waiting for a redraw. Without a
451
+ surface the queue is left alone: the surface presents it when it appears.
409
452
  */
410
453
  bool presentQueued(const std::shared_ptr<RNSkCanvasProvider> &provider) {
411
454
  std::shared_ptr<RNSkGraphiteTarget> target;
@@ -426,8 +469,9 @@ public:
426
469
  }
427
470
  if (!present(provider, targetInfo, recordings, /* remember= */ true)) {
428
471
  target->requeue(recordings);
429
- return false;
472
+ return true;
430
473
  }
474
+ notifyPresented();
431
475
  return target->hasQueued();
432
476
  }
433
477
 
@@ -460,9 +504,11 @@ public:
460
504
 
461
505
  private:
462
506
  /**
463
- Replays the recordings onto the provider's target. Returns false when the
464
- provider could not present (no surface, app in the background), in which
465
- case nothing was consumed and the caller keeps the recordings.
507
+ Replays the recordings onto the provider's target, and remembers the last
508
+ one for the next redraw when asked to (not for a snapshot). Returns false
509
+ when the provider could not present (no surface, app in the background),
510
+ in which case nothing was consumed and the caller keeps the recordings.
511
+ The on-screen callers tell the producer about a consumed frame.
466
512
  */
467
513
  bool
468
514
  present(const std::shared_ptr<RNSkCanvasProvider> &provider,
@@ -472,10 +518,15 @@ private:
472
518
  std::vector<skgpu::graphite::Recording *> raw;
473
519
  std::shared_ptr<RNSkGraphiteRecording> last;
474
520
  for (const auto &recording : recordings) {
521
+ // A recording made for the size the view had before a resize is
522
+ // dropped quietly: the next one is recorded for the new size.
523
+ if (!recording->hasSizeOf(targetInfo)) {
524
+ continue;
525
+ }
475
526
  // A recording made for another format (recorded before the surface
476
527
  // existed, with a bit depth the surface did not get) cannot be
477
528
  // replayed onto this one.
478
- if (!recording->isCompatibleWith(targetInfo)) {
529
+ if (!recording->hasFormatOf(targetInfo)) {
479
530
  RNSkLogger::logToConsole("SkiaGraphiteView: skipping a recording made "
480
531
  "for a different surface format");
481
532
  continue;
@@ -495,15 +546,26 @@ private:
495
546
  return success;
496
547
  }
497
548
 
549
+ void notifyPresented() {
550
+ if (_onPresented) {
551
+ _onPresented();
552
+ }
553
+ }
554
+
498
555
  std::mutex _mutex;
499
556
  std::shared_ptr<RNSkGraphiteTarget> _target;
500
557
  std::shared_ptr<RNSkGraphiteRecording> _lastPresented;
558
+ std::function<void()> _onPresented;
559
+ std::function<bool()> _onRedraw;
501
560
  };
502
561
 
503
562
  /**
504
- * A view that presents Graphite recordings. JS records frames through the
505
- * target (SkiaViewApi.makeGraphiteContext); the platform view presents them
506
- * on its display link. Only available with the Graphite backend.
563
+ * A view that presents Graphite recordings. Frames come from one of two
564
+ * producers: JS records them itself through the target
565
+ * (SkiaViewApi.makeGraphiteContext), or <GraphiteCanvas> hands over a recorder
566
+ * (or a picture) that the render thread pool records for the view. The
567
+ * platform view presents them on its display link. Only available with the
568
+ * Graphite backend.
507
569
  */
508
570
  class RNSkGraphiteView : public RNSkView {
509
571
  public:
@@ -511,7 +573,21 @@ public:
511
573
  std::shared_ptr<RNSkCanvasProvider> canvasProvider)
512
574
  : RNSkView(context, canvasProvider,
513
575
  std::make_shared<RNSkGraphiteRenderer>(
514
- std::bind(&RNSkGraphiteView::requestRedraw, this))) {}
576
+ std::bind(&RNSkGraphiteView::requestRedraw, this))),
577
+ _producer(std::make_shared<RNSkGraphiteProducer>()) {
578
+ std::weak_ptr<RNSkGraphiteProducer> weakProducer = _producer;
579
+ getGraphiteRenderer()->setOnPresented([weakProducer]() {
580
+ if (auto producer = weakProducer.lock()) {
581
+ producer->onFramePresented();
582
+ }
583
+ });
584
+ getGraphiteRenderer()->setOnRedraw([weakProducer]() {
585
+ if (auto producer = weakProducer.lock()) {
586
+ return producer->requestFrame();
587
+ }
588
+ return false;
589
+ });
590
+ }
515
591
 
516
592
  ~RNSkGraphiteView() override {
517
593
  if (_target) {
@@ -519,9 +595,26 @@ public:
519
595
  }
520
596
  }
521
597
 
522
- // No JSI properties: frames arrive through the target.
598
+ /** Declarative content: the recorder of <GraphiteCanvas>, or a picture. */
523
599
  void setJsiProperties(
524
- std::unordered_map<std::string, RNJsi::ViewProperty> &props) override {}
600
+ std::unordered_map<std::string, RNJsi::ViewProperty> &props) override {
601
+ for (auto &prop : props) {
602
+ if (prop.first == "recorder") {
603
+ _producer->setRecorder(
604
+ prop.second.isRecorder() ? prop.second.getRecorder() : nullptr);
605
+ } else if (prop.first == "picture") {
606
+ _producer->setPicture(prop.second.isPicture() ? prop.second.getPicture()
607
+ : nullptr);
608
+ }
609
+ }
610
+ }
611
+
612
+ bool applyUpdates(jsi::Runtime &runtime, double recorderId,
613
+ const jsi::Array &values) override {
614
+ return _producer->applyUpdates(runtime, recorderId, values);
615
+ }
616
+
617
+ void releaseContent() override { _producer->clear(); }
525
618
 
526
619
  void setNativeId(size_t nativeId) override {
527
620
  RNSkView::setNativeId(nativeId);
@@ -546,6 +639,7 @@ public:
546
639
  });
547
640
  };
548
641
  _target->attach(getCanvasProvider(), scheduleOnMainThread);
642
+ _producer->setTarget(_target);
549
643
  // Frames recorded before the view existed are presented now.
550
644
  if (_target->hasQueued()) {
551
645
  scheduleOnMainThread();
@@ -579,12 +673,22 @@ public:
579
673
 
580
674
  bool hasQueuedRecordings() { return _target && _target->hasQueued(); }
581
675
 
582
- /** Replays the current frame into an offscreen surface. */
676
+ /**
677
+ Renders the view into an offscreen surface: declarative content is
678
+ replayed on the calling thread with the latest values, so the snapshot
679
+ does not wait for a frame; otherwise the current frame is replayed.
680
+ */
583
681
  sk_sp<SkImage> makeImageSnapshot(SkRect *bounds) override {
584
682
  auto provider = std::make_shared<RNSkOffscreenCanvasProvider>(
585
683
  getPlatformContext(), std::bind(&RNSkView::requestRedraw, this),
586
684
  getScaledWidth(), getScaledHeight());
587
- getGraphiteRenderer()->renderLastFrame(provider);
685
+ if (_producer->hasContent()) {
686
+ auto pd = getPlatformContext()->getPixelDensity();
687
+ provider->renderToCanvas(
688
+ [this, pd](SkCanvas *canvas) { _producer->renderInto(canvas, pd); });
689
+ } else {
690
+ getGraphiteRenderer()->renderLastFrame(provider);
691
+ }
588
692
  return provider->makeSnapshot(bounds);
589
693
  }
590
694
 
@@ -593,6 +697,7 @@ private:
593
697
  return std::static_pointer_cast<RNSkGraphiteRenderer>(getRenderer());
594
698
  }
595
699
 
700
+ std::shared_ptr<RNSkGraphiteProducer> _producer;
596
701
  std::shared_ptr<RNSkGraphiteTarget> _target;
597
702
  size_t _targetId = 0;
598
703
  std::function<void()> _frameScheduler;
@@ -231,12 +231,8 @@ public:
231
231
  return jsi::Value::undefined();
232
232
  }
233
233
  // Outside the registry lock: the update must not hold up the commits
234
- // and registrations of other views.
235
- auto renderer =
236
- std::static_pointer_cast<RNSkPictureRenderer>(view->getRenderer());
237
- if (renderer->applyUpdates(runtime, recorderId, values)) {
238
- view->requestRedraw();
239
- }
234
+ // and registrations of other views. The view schedules its own frame.
235
+ view->applyUpdates(runtime, recorderId, values);
240
236
  return jsi::Value::undefined();
241
237
  }
242
238
 
@@ -1,15 +1,29 @@
1
- // The recorder headers depend on the include order established by
2
- // JsiSkApi.h, so everything that needs a complete Recorder lives here rather
3
- // than in RNSkPictureView.h (which platform views include on its own).
4
- #include "api/JsiSkApi.h"
5
-
1
+ // Everything that needs a complete Recorder lives here rather than in
2
+ // RNSkPictureView.h (which platform views include on its own).
6
3
  #include "RNSkPictureView.h"
7
4
 
5
+ #include <memory>
6
+ #include <utility>
7
+
8
8
  #include "api/recorder/DrawingCtx.h"
9
9
  #include "api/recorder/RNRecorder.h"
10
10
 
11
11
  namespace RNSkia {
12
12
 
13
+ void drawContent(SkCanvas *canvas, Recorder *recorder,
14
+ const sk_sp<SkPicture> &picture, float pixelDensity) {
15
+ canvas->clear(SK_ColorTRANSPARENT);
16
+ canvas->save();
17
+ canvas->scale(pixelDensity, pixelDensity);
18
+ if (recorder != nullptr) {
19
+ DrawingCtx ctx(canvas);
20
+ recorder->play(&ctx);
21
+ } else if (picture != nullptr) {
22
+ canvas->drawPicture(picture);
23
+ }
24
+ canvas->restore();
25
+ }
26
+
13
27
  void RNSkPictureRenderer::setRecorder(std::shared_ptr<Recorder> recorder) {
14
28
  sk_sp<SkPicture> picture;
15
29
  if (recorder != nullptr && recorder->variables.empty()) {
@@ -33,7 +47,9 @@ bool RNSkPictureRenderer::applyUpdatesTo(
33
47
  if (recorder == nullptr || recorder->id != recorderId) {
34
48
  return false;
35
49
  }
36
- recorder->applyUpdates(runtime, values);
50
+ // The values are written into the commands by the next replay, which the
51
+ // caller schedules: the mapper never waits for a draw.
52
+ recorder->readUpdates(runtime, values);
37
53
  return true;
38
54
  }
39
55
 
@@ -50,9 +66,4 @@ bool RNSkPictureRenderer::applyUpdates(jsi::Runtime &runtime, double recorderId,
50
66
  return applyUpdatesTo(recorder, runtime, recorderId, values);
51
67
  }
52
68
 
53
- void RNSkPictureRenderer::replay(SkCanvas *canvas, Recorder *recorder) {
54
- DrawingCtx ctx(canvas);
55
- recorder->play(&ctx);
56
- }
57
-
58
69
  } // namespace RNSkia
@@ -37,6 +37,14 @@ namespace jsi = facebook::jsi;
37
37
 
38
38
  class Recorder;
39
39
 
40
+ /**
41
+ * Replays declarative content, a recorder if there is one, else a picture,
42
+ * into a canvas that draws in pixels: clears it and applies the density.
43
+ * Shared by the picture renderer and the Graphite producer.
44
+ */
45
+ void drawContent(SkCanvas *canvas, Recorder *recorder,
46
+ const sk_sp<SkPicture> &picture, float pixelDensity);
47
+
40
48
  /**
41
49
  * Draws either an SkPicture (imperative API, or a recording without shared
42
50
  * values, played once into a picture) or a Recorder (declarative <Canvas>
@@ -142,20 +150,10 @@ public:
142
150
  recorder = _recorder;
143
151
  picture = _picture;
144
152
  }
145
- canvas->clear(SK_ColorTRANSPARENT);
146
- canvas->save();
147
- canvas->scale(pixelDensity, pixelDensity);
148
- if (recorder != nullptr) {
149
- replay(canvas, recorder.get());
150
- } else if (picture != nullptr) {
151
- canvas->drawPicture(picture);
152
- }
153
- canvas->restore();
153
+ drawContent(canvas, recorder.get(), picture, pixelDensity);
154
154
  }
155
155
 
156
156
  private:
157
- void replay(SkCanvas *canvas, Recorder *recorder);
158
-
159
157
  bool performDraw(std::shared_ptr<RNSkCanvasProvider> canvasProvider) {
160
158
  auto pd = _platformContext->getPixelDensity();
161
159
  return canvasProvider->renderToCanvas(
@@ -194,5 +192,20 @@ public:
194
192
  }
195
193
  }
196
194
  }
195
+
196
+ bool applyUpdates(jsi::Runtime &runtime, double recorderId,
197
+ const jsi::Array &values) override {
198
+ auto renderer =
199
+ std::static_pointer_cast<RNSkPictureRenderer>(getRenderer());
200
+ if (!renderer->applyUpdates(runtime, recorderId, values)) {
201
+ return false;
202
+ }
203
+ requestRedraw();
204
+ return true;
205
+ }
206
+
207
+ void releaseContent() override {
208
+ std::static_pointer_cast<RNSkPictureRenderer>(getRenderer())->clear();
209
+ }
197
210
  };
198
211
  } // namespace RNSkia
@@ -0,0 +1,91 @@
1
+ #pragma once
2
+
3
+ #include <algorithm>
4
+ #include <deque>
5
+ #include <functional>
6
+ #include <mutex>
7
+ #include <string>
8
+ #include <thread>
9
+
10
+ #include <condition_variable>
11
+
12
+ #if defined(__APPLE__)
13
+ #include <pthread.h>
14
+ #include <pthread/qos.h>
15
+ #elif defined(__ANDROID__)
16
+ #include <pthread.h>
17
+ #include <sys/resource.h>
18
+ #include <unistd.h>
19
+ #endif
20
+
21
+ namespace RNSkia {
22
+
23
+ /**
24
+ * The threads that replay recordings for SkiaGraphiteViews, so that neither
25
+ * the JS thread nor the UI thread pays for a frame. Jobs run in submission
26
+ * order on the first free thread; a view never has more than one job in
27
+ * flight, so views are what run in parallel.
28
+ */
29
+ class RNSkThreadPool {
30
+ public:
31
+ static RNSkThreadPool &getInstance() {
32
+ // Never destroyed: the threads are detached and the process takes them
33
+ // down, which spares the static destructor from joining them at exit.
34
+ static auto *instance = new RNSkThreadPool();
35
+ return *instance;
36
+ }
37
+
38
+ RNSkThreadPool(const RNSkThreadPool &) = delete;
39
+ RNSkThreadPool &operator=(const RNSkThreadPool &) = delete;
40
+
41
+ void post(std::function<void()> job) {
42
+ {
43
+ std::lock_guard<std::mutex> lock(_mutex);
44
+ _jobs.push_back(std::move(job));
45
+ }
46
+ _condition.notify_one();
47
+ }
48
+
49
+ private:
50
+ RNSkThreadPool() {
51
+ auto cores = std::thread::hardware_concurrency();
52
+ const unsigned size = cores == 0 ? 2u : std::clamp(cores / 2, 2u, 4u);
53
+ for (unsigned i = 0; i < size; i++) {
54
+ std::thread([this, i]() { run(i); }).detach();
55
+ }
56
+ }
57
+
58
+ static void configureThread(unsigned index) {
59
+ auto name = "RNSkia Render " + std::to_string(index + 1);
60
+ #if defined(__APPLE__)
61
+ pthread_setname_np(name.c_str());
62
+ // Frames are presented on the next vsync: the same class the UI uses.
63
+ pthread_set_qos_class_self_np(QOS_CLASS_USER_INTERACTIVE, 0);
64
+ #elif defined(__ANDROID__)
65
+ pthread_setname_np(pthread_self(), name.c_str());
66
+ // ANDROID_PRIORITY_DISPLAY; with PRIO_PROCESS and who = 0, Linux applies
67
+ // the nice value to the calling thread only.
68
+ setpriority(PRIO_PROCESS, 0, -4);
69
+ #endif
70
+ }
71
+
72
+ void run(unsigned index) {
73
+ configureThread(index);
74
+ for (;;) {
75
+ std::function<void()> job;
76
+ {
77
+ std::unique_lock<std::mutex> lock(_mutex);
78
+ _condition.wait(lock, [this]() { return !_jobs.empty(); });
79
+ job = std::move(_jobs.front());
80
+ _jobs.pop_front();
81
+ }
82
+ job();
83
+ }
84
+ }
85
+
86
+ std::mutex _mutex;
87
+ std::condition_variable _condition;
88
+ std::deque<std::function<void()>> _jobs;
89
+ };
90
+
91
+ } // namespace RNSkia
@@ -230,6 +230,24 @@ public:
230
230
  virtual void setJsiProperties(
231
231
  std::unordered_map<std::string, RNJsi::ViewProperty> &props) = 0;
232
232
 
233
+ /**
234
+ Reads the shared values on the calling runtime into the recording the
235
+ view owns and schedules a frame. Returns false when there is nothing to
236
+ update: no recording, or one other than recorderId (a stale mapper).
237
+ */
238
+ virtual bool applyUpdates(jsi::Runtime &runtime, double recorderId,
239
+ const jsi::Array &values) {
240
+ return false;
241
+ }
242
+
243
+ /**
244
+ Releases the content the view draws without scheduling a frame: the host
245
+ view is torn down. On Android the native view outlives the Java view
246
+ until it is finalized, so the resources go away here rather than with the
247
+ garbage collector.
248
+ */
249
+ virtual void releaseContent() {}
250
+
233
251
  void requestRedraw() {
234
252
  if (!_redrawRequested) {
235
253
  _redrawRequested = true;
@@ -0,0 +1,45 @@
1
+ /*
2
+ * Copyright 2023 Google LLC
3
+ *
4
+ * Use of this source code is governed by a BSD-style license that can be
5
+ * found in the LICENSE file.
6
+ */
7
+
8
+ #ifndef skgpu_graphite_ContextOptionsPriv_DEFINED
9
+ #define skgpu_graphite_ContextOptionsPriv_DEFINED
10
+
11
+ #include "include/private/SkMath.h"
12
+
13
+ #include <optional>
14
+
15
+ namespace skgpu::graphite {
16
+
17
+ enum class PathRendererStrategy;
18
+
19
+ /**
20
+ * Private options that are only meant for testing within Skia's tools.
21
+ */
22
+ struct ContextOptionsPriv {
23
+
24
+ int fMaxTextureSizeOverride = SK_MaxS32;
25
+
26
+ /**
27
+ * If true, will store a pointer in Recorder that points back to the Context
28
+ * that created it. Used by readPixels() and other methods that normally require a Context.
29
+ */
30
+ bool fStoreContextRefInRecorder = false;
31
+
32
+ /**
33
+ * If true, enables layer based draw ordering.
34
+ */
35
+ bool fDrawListLayer = false;
36
+
37
+ /**
38
+ * Override Caps' default strategy heuristics to prioritize this one if set *and* is supported.
39
+ */
40
+ std::optional<PathRendererStrategy> fPathRendererStrategy;
41
+ };
42
+
43
+ } // namespace skgpu::graphite
44
+
45
+ #endif // skgpu_graphite_ContextOptionsPriv_DEFINED