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.
- package/android/CMakeLists.txt +1 -0
- package/android/build.gradle +17 -0
- package/android/cpp/jni/include/JniSkiaBaseView.h +9 -4
- package/android/cpp/jni/include/JniSkiaGraphiteView.h +2 -2
- package/android/cpp/jni/include/JniSkiaPictureView.h +1 -12
- package/cpp/api/recorder/ColorFilters.h +1 -0
- package/cpp/api/recorder/Convertor.h +39 -11
- package/cpp/api/recorder/DataTypes.h +12 -0
- package/cpp/api/recorder/DrawingCtx.h +14 -0
- package/cpp/api/recorder/Drawings.h +5 -0
- package/cpp/api/recorder/PathEffects.h +8 -0
- package/cpp/api/recorder/RNRecorder.h +68 -11
- package/cpp/api/recorder/Shaders.h +3 -0
- package/cpp/dawn/include/dawn/dawn_proc.h +53 -0
- package/cpp/dawn/include/dawn/dawn_proc_table.h +329 -0
- package/cpp/dawn/include/dawn/dawn_thread_dispatch_proc.h +47 -0
- package/cpp/dawn/include/dawn/dawn_version.h +41 -0
- package/cpp/dawn/include/dawn/native/D3D11Backend.h +65 -0
- package/cpp/dawn/include/dawn/native/D3D12Backend.h +104 -0
- package/cpp/dawn/include/dawn/native/D3DBackend.h +56 -0
- package/cpp/dawn/include/dawn/native/DawnNative.h +367 -0
- package/cpp/dawn/include/dawn/native/MetalBackend.h +56 -0
- package/cpp/dawn/include/dawn/native/NullBackend.h +39 -0
- package/cpp/dawn/include/dawn/native/OpenGLBackend.h +89 -0
- package/cpp/dawn/include/dawn/native/VulkanBackend.h +183 -0
- package/cpp/dawn/include/dawn/native/WebGPUBackend.h +49 -0
- package/cpp/dawn/include/dawn/native/dawn_native_export.h +49 -0
- package/cpp/dawn/include/dawn/platform/DawnPlatform.h +211 -0
- package/cpp/dawn/include/dawn/platform/dawn_platform_export.h +49 -0
- package/cpp/dawn/include/dawn/replay/Replay.h +99 -0
- package/cpp/dawn/include/dawn/replay/dawn_replay_export.h +49 -0
- package/cpp/dawn/include/dawn/webgpu_cpp_print.h +2868 -0
- package/cpp/dawn/include/tint/tint.h +91 -0
- package/cpp/dawn/include/webgpu/webgpu.h +5063 -0
- package/cpp/dawn/include/webgpu/webgpu_cpp.h +10401 -0
- package/cpp/dawn/include/webgpu/webgpu_cpp_chained_struct.h +57 -0
- package/cpp/dawn/include/webgpu/webgpu_enum_class_bitmasks.h +163 -0
- package/cpp/dawn/include/webgpu/webgpu_glfw.h +88 -0
- package/cpp/rnskia/RNDawnContext.h +6 -0
- package/cpp/rnskia/RNSkGraphiteProducer.cpp +189 -0
- package/cpp/rnskia/RNSkGraphiteProducer.h +116 -0
- package/cpp/rnskia/RNSkGraphiteView.h +129 -24
- package/cpp/rnskia/RNSkJsiViewApi.h +2 -6
- package/cpp/rnskia/RNSkPictureView.cpp +22 -11
- package/cpp/rnskia/RNSkPictureView.h +24 -11
- package/cpp/rnskia/RNSkThreadPool.h +91 -0
- package/cpp/rnskia/RNSkView.h +18 -0
- package/cpp/skia/src/gpu/graphite/ContextOptionsPriv.h +45 -0
- package/cpp/skia/src/gpu/graphite/ResourceTypes.h +362 -0
- package/cpp/skia/src/gpu/graphite/TextureProxyView.h +105 -0
- package/lib/commonjs/index.d.ts +4 -1
- package/lib/commonjs/index.js +31 -12
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/mock/index.js +1 -0
- package/lib/commonjs/mock/index.js.map +1 -1
- package/lib/commonjs/renderer/Canvas.d.ts +10 -1
- package/lib/commonjs/renderer/Canvas.js +37 -10
- package/lib/commonjs/renderer/Canvas.js.map +1 -1
- package/lib/commonjs/renderer/DefaultCanvas.d.ts +8 -0
- package/lib/commonjs/renderer/DefaultCanvas.js +42 -0
- package/lib/commonjs/renderer/DefaultCanvas.js.map +1 -0
- package/lib/commonjs/renderer/GraphiteCanvas.d.ts +22 -0
- package/lib/commonjs/renderer/GraphiteCanvas.js +64 -0
- package/lib/commonjs/renderer/GraphiteCanvas.js.map +1 -0
- package/lib/commonjs/renderer/GraphiteCanvas.web.d.ts +1 -0
- package/lib/commonjs/renderer/GraphiteCanvas.web.js +13 -0
- package/lib/commonjs/renderer/GraphiteCanvas.web.js.map +1 -0
- package/lib/module/index.d.ts +4 -1
- package/lib/module/index.js +3 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/mock/index.js +1 -0
- package/lib/module/mock/index.js.map +1 -1
- package/lib/module/renderer/Canvas.d.ts +10 -1
- package/lib/module/renderer/Canvas.js +35 -9
- package/lib/module/renderer/Canvas.js.map +1 -1
- package/lib/module/renderer/DefaultCanvas.d.ts +8 -0
- package/lib/module/renderer/DefaultCanvas.js +34 -0
- package/lib/module/renderer/DefaultCanvas.js.map +1 -0
- package/lib/module/renderer/GraphiteCanvas.d.ts +22 -0
- package/lib/module/renderer/GraphiteCanvas.js +57 -0
- package/lib/module/renderer/GraphiteCanvas.js.map +1 -0
- package/lib/module/renderer/GraphiteCanvas.web.d.ts +1 -0
- package/lib/module/renderer/GraphiteCanvas.web.js +4 -0
- package/lib/module/renderer/GraphiteCanvas.web.js.map +1 -0
- package/lib/typescript/src/index.d.ts +4 -1
- package/lib/typescript/src/renderer/Canvas.d.ts +10 -1
- package/lib/typescript/src/renderer/DefaultCanvas.d.ts +8 -0
- package/lib/typescript/src/renderer/GraphiteCanvas.d.ts +22 -0
- package/lib/typescript/src/renderer/GraphiteCanvas.web.d.ts +1 -0
- package/libs/.graphite +1 -0
- package/package.json +7 -8
- package/react-native-skia.podspec +18 -1
- package/src/index.ts +4 -1
- package/src/mock/index.ts +1 -0
- package/src/renderer/Canvas.tsx +29 -9
- package/src/renderer/DefaultCanvas.tsx +41 -0
- package/src/renderer/GraphiteCanvas.tsx +61 -0
- 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
|
|
63
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
432
|
+
if (present(canvasProvider, targetInfo, {lastPresented},
|
|
433
|
+
/* remember= */ true)) {
|
|
434
|
+
notifyPresented();
|
|
435
|
+
}
|
|
396
436
|
return;
|
|
397
437
|
}
|
|
398
|
-
if (
|
|
399
|
-
|
|
400
|
-
|
|
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
|
|
408
|
-
|
|
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
|
|
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
|
|
464
|
-
|
|
465
|
-
|
|
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->
|
|
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.
|
|
505
|
-
*
|
|
506
|
-
*
|
|
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
|
-
|
|
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
|
-
/**
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
2
|
-
//
|
|
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
|
-
|
|
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
|
|
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
|
package/cpp/rnskia/RNSkView.h
CHANGED
|
@@ -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
|