@shopify/react-native-skia 2.5.1 → 2.5.3

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 (138) hide show
  1. package/android/CMakeLists.txt +8 -6
  2. package/android/build.gradle +5 -32
  3. package/android/cpp/jni/JniWebGPUView.cpp +67 -0
  4. package/android/cpp/rnskia-android/OpenGLContext.h +9 -2
  5. package/android/cpp/rnskia-android/RNSkAndroidPlatformContext.h +6 -3
  6. package/android/cpp/rnskia-android/SkiaPlatformContext.h +26 -0
  7. package/android/src/main/java/com/shopify/reactnative/skia/RNSkiaPackage.java +4 -1
  8. package/android/src/main/java/com/shopify/reactnative/skia/WebGPUSurfaceView.java +41 -0
  9. package/android/src/main/java/com/shopify/reactnative/skia/WebGPUTextureView.java +44 -0
  10. package/android/src/main/java/com/shopify/reactnative/skia/WebGPUView.java +95 -0
  11. package/android/src/main/java/com/shopify/reactnative/skia/WebGPUViewAPI.java +14 -0
  12. package/android/src/main/java/com/shopify/reactnative/skia/WebGPUViewManager.java +58 -0
  13. package/apple/MetalContext.h +10 -2
  14. package/apple/MetalWindowContext.h +1 -0
  15. package/apple/MetalWindowContext.mm +8 -1
  16. package/apple/RNSkApplePlatformContext.h +2 -1
  17. package/apple/RNSkApplePlatformContext.mm +6 -4
  18. package/apple/RNSkUIKit.h +13 -0
  19. package/apple/SkiaPictureView.mm +3 -0
  20. package/apple/SkiaPlatformContext.h +20 -0
  21. package/apple/SkiaPlatformContext.mm +21 -0
  22. package/apple/WebGPUMetalView.h +12 -0
  23. package/apple/WebGPUMetalView.mm +93 -0
  24. package/apple/WebGPUView.h +20 -0
  25. package/apple/WebGPUView.mm +77 -0
  26. package/cpp/api/JsiSkImage.h +76 -0
  27. package/cpp/api/JsiSkSurfaceFactory.h +12 -1
  28. package/cpp/jsi2/JSIConverter.h +11 -0
  29. package/cpp/rnskia/RNDawnContext.h +24 -16
  30. package/cpp/rnskia/RNDawnUtils.h +12 -0
  31. package/cpp/rnskia/RNSkManager.cpp +11 -4
  32. package/cpp/rnskia/RNSkPlatformContext.h +3 -1
  33. package/cpp/rnwgpu/Canvas.h +45 -0
  34. package/cpp/rnwgpu/PlatformContext.h +18 -0
  35. package/cpp/rnwgpu/SurfaceRegistry.h +229 -0
  36. package/cpp/rnwgpu/api/GPUAdapter.cpp +26 -0
  37. package/cpp/rnwgpu/api/GPUCanvasContext.cpp +64 -0
  38. package/cpp/rnwgpu/api/GPUCanvasContext.h +65 -0
  39. package/cpp/rnwgpu/api/GPUDevice.cpp +52 -0
  40. package/cpp/rnwgpu/api/GPUDevice.h +62 -1
  41. package/cpp/rnwgpu/api/GPUUncapturedErrorEvent.h +61 -0
  42. package/cpp/rnwgpu/api/RNWebGPU.h +62 -0
  43. package/cpp/rnwgpu/api/descriptors/GPUBindGroupEntry.h +4 -0
  44. package/cpp/rnwgpu/api/descriptors/GPUCanvasConfiguration.h +76 -0
  45. package/lib/commonjs/external/reanimated/useVideo.js +1 -4
  46. package/lib/commonjs/external/reanimated/useVideo.js.map +1 -1
  47. package/lib/commonjs/mock/index.js +1 -0
  48. package/lib/commonjs/mock/index.js.map +1 -1
  49. package/lib/commonjs/skia/types/Surface/SurfaceFactory.d.ts +10 -1
  50. package/lib/commonjs/skia/types/Surface/SurfaceFactory.js +5 -0
  51. package/lib/commonjs/skia/types/Surface/SurfaceFactory.js.map +1 -1
  52. package/lib/commonjs/sksg/Container.native.js +4 -0
  53. package/lib/commonjs/sksg/Container.native.js.map +1 -1
  54. package/lib/commonjs/sksg/Container.web.js +4 -0
  55. package/lib/commonjs/sksg/Container.web.js.map +1 -1
  56. package/lib/commonjs/specs/WebGPUViewNativeComponent.d.ts +8 -0
  57. package/lib/commonjs/specs/WebGPUViewNativeComponent.js +11 -0
  58. package/lib/commonjs/specs/WebGPUViewNativeComponent.js.map +1 -0
  59. package/lib/commonjs/specs/WebGPUViewNativeComponent.web.d.ts +8 -0
  60. package/lib/commonjs/specs/WebGPUViewNativeComponent.web.js +101 -0
  61. package/lib/commonjs/specs/WebGPUViewNativeComponent.web.js.map +1 -0
  62. package/lib/commonjs/specs/utils.d.ts +1 -0
  63. package/lib/commonjs/specs/utils.js +11 -0
  64. package/lib/commonjs/specs/utils.js.map +1 -0
  65. package/lib/commonjs/views/WebGPUCanvas.d.ts +32 -0
  66. package/lib/commonjs/views/WebGPUCanvas.js +66 -0
  67. package/lib/commonjs/views/WebGPUCanvas.js.map +1 -0
  68. package/lib/commonjs/views/WebGPUCanvas.web.d.ts +23 -0
  69. package/lib/commonjs/views/WebGPUCanvas.web.js +20 -0
  70. package/lib/commonjs/views/WebGPUCanvas.web.js.map +1 -0
  71. package/lib/commonjs/views/index.d.ts +1 -0
  72. package/lib/commonjs/views/index.js +11 -0
  73. package/lib/commonjs/views/index.js.map +1 -1
  74. package/lib/module/external/reanimated/useVideo.js +1 -4
  75. package/lib/module/external/reanimated/useVideo.js.map +1 -1
  76. package/lib/module/mock/index.js +1 -0
  77. package/lib/module/mock/index.js.map +1 -1
  78. package/lib/module/skia/types/Surface/SurfaceFactory.d.ts +10 -1
  79. package/lib/module/skia/types/Surface/SurfaceFactory.js +4 -1
  80. package/lib/module/skia/types/Surface/SurfaceFactory.js.map +1 -1
  81. package/lib/module/sksg/Container.native.js +5 -0
  82. package/lib/module/sksg/Container.native.js.map +1 -1
  83. package/lib/module/sksg/Container.web.js +5 -0
  84. package/lib/module/sksg/Container.web.js.map +1 -1
  85. package/lib/module/specs/WebGPUViewNativeComponent.d.ts +8 -0
  86. package/lib/module/specs/WebGPUViewNativeComponent.js +4 -0
  87. package/lib/module/specs/WebGPUViewNativeComponent.js.map +1 -0
  88. package/lib/module/specs/WebGPUViewNativeComponent.web.d.ts +8 -0
  89. package/lib/module/specs/WebGPUViewNativeComponent.web.js +94 -0
  90. package/lib/module/specs/WebGPUViewNativeComponent.web.js.map +1 -0
  91. package/lib/module/specs/utils.d.ts +1 -0
  92. package/lib/module/specs/utils.js +5 -0
  93. package/lib/module/specs/utils.js.map +1 -0
  94. package/lib/module/views/WebGPUCanvas.d.ts +32 -0
  95. package/lib/module/views/WebGPUCanvas.js +57 -0
  96. package/lib/module/views/WebGPUCanvas.js.map +1 -0
  97. package/lib/module/views/WebGPUCanvas.web.d.ts +23 -0
  98. package/lib/module/views/WebGPUCanvas.web.js +12 -0
  99. package/lib/module/views/WebGPUCanvas.web.js.map +1 -0
  100. package/lib/module/views/index.d.ts +1 -0
  101. package/lib/module/views/index.js +1 -0
  102. package/lib/module/views/index.js.map +1 -1
  103. package/lib/typescript/lib/commonjs/mock/index.d.ts +1 -0
  104. package/lib/typescript/lib/commonjs/skia/types/Surface/SurfaceFactory.d.ts +4 -0
  105. package/lib/typescript/lib/commonjs/specs/WebGPUViewNativeComponent.d.ts +3 -0
  106. package/lib/typescript/lib/commonjs/specs/WebGPUViewNativeComponent.web.d.ts +3 -0
  107. package/lib/typescript/lib/commonjs/specs/utils.d.ts +2 -0
  108. package/lib/typescript/lib/commonjs/views/WebGPUCanvas.d.ts +6 -0
  109. package/lib/typescript/lib/commonjs/views/WebGPUCanvas.web.d.ts +6 -0
  110. package/lib/typescript/lib/module/mock/index.d.ts +7 -1
  111. package/lib/typescript/lib/module/skia/types/Surface/SurfaceFactory.d.ts +4 -1
  112. package/lib/typescript/lib/module/specs/WebGPUViewNativeComponent.d.ts +2 -0
  113. package/lib/typescript/lib/module/specs/WebGPUViewNativeComponent.web.d.ts +2 -0
  114. package/lib/typescript/lib/module/specs/utils.d.ts +1 -0
  115. package/lib/typescript/lib/module/views/WebGPUCanvas.d.ts +7 -0
  116. package/lib/typescript/lib/module/views/WebGPUCanvas.web.d.ts +8 -0
  117. package/lib/typescript/lib/module/views/index.d.ts +1 -0
  118. package/lib/typescript/src/skia/types/Surface/SurfaceFactory.d.ts +10 -1
  119. package/lib/typescript/src/specs/WebGPUViewNativeComponent.d.ts +8 -0
  120. package/lib/typescript/src/specs/WebGPUViewNativeComponent.web.d.ts +8 -0
  121. package/lib/typescript/src/specs/utils.d.ts +1 -0
  122. package/lib/typescript/src/views/WebGPUCanvas.d.ts +32 -0
  123. package/lib/typescript/src/views/WebGPUCanvas.web.d.ts +23 -0
  124. package/lib/typescript/src/views/index.d.ts +1 -0
  125. package/package.json +7 -3
  126. package/react-native-skia.podspec +16 -83
  127. package/scripts/install-libs.js +131 -0
  128. package/src/external/reanimated/useVideo.ts +1 -4
  129. package/src/mock/index.ts +1 -0
  130. package/src/skia/types/Surface/SurfaceFactory.ts +17 -1
  131. package/src/sksg/Container.native.ts +3 -0
  132. package/src/sksg/Container.web.ts +3 -0
  133. package/src/specs/WebGPUViewNativeComponent.ts +11 -0
  134. package/src/specs/WebGPUViewNativeComponent.web.ts +108 -0
  135. package/src/specs/utils.ts +4 -0
  136. package/src/views/WebGPUCanvas.tsx +109 -0
  137. package/src/views/WebGPUCanvas.web.tsx +36 -0
  138. package/src/views/index.ts +1 -0
@@ -0,0 +1,21 @@
1
+ #ifdef SK_GRAPHITE
2
+
3
+ #include "SkiaPlatformContext.h"
4
+
5
+ #include <TargetConditionals.h>
6
+
7
+ namespace rnwgpu {
8
+
9
+ wgpu::Surface SkiaPlatformContext::makeSurface(wgpu::Instance instance,
10
+ void *surface, int width,
11
+ int height) {
12
+ wgpu::SurfaceSourceMetalLayer metalSurfaceDesc;
13
+ metalSurfaceDesc.layer = surface;
14
+ wgpu::SurfaceDescriptor surfaceDescriptor;
15
+ surfaceDescriptor.nextInChain = &metalSurfaceDesc;
16
+ return instance.CreateSurface(&surfaceDescriptor);
17
+ }
18
+
19
+ } // namespace rnwgpu
20
+
21
+ #endif // SK_GRAPHITE
@@ -0,0 +1,12 @@
1
+ #pragma once
2
+
3
+ #import "RNSkUIKit.h"
4
+
5
+ @interface WebGPUMetalView : RNSkPlatformView
6
+
7
+ @property (nonatomic, strong) NSNumber *contextId;
8
+
9
+ - (void)configure;
10
+ - (void)update;
11
+
12
+ @end
@@ -0,0 +1,93 @@
1
+ #import "WebGPUMetalView.h"
2
+
3
+ #ifdef SK_GRAPHITE
4
+
5
+ #import "webgpu/webgpu_cpp.h"
6
+ #import <QuartzCore/CAMetalLayer.h>
7
+
8
+ #import "rnwgpu/SurfaceRegistry.h"
9
+ #import "rnskia/RNDawnContext.h"
10
+
11
+ @implementation WebGPUMetalView {
12
+ BOOL _isConfigured;
13
+ }
14
+
15
+ #if !TARGET_OS_OSX
16
+ + (Class)layerClass {
17
+ return [CAMetalLayer class];
18
+ }
19
+ #else // !TARGET_OS_OSX
20
+ - (instancetype)init {
21
+ self = [super init];
22
+ if (self) {
23
+ self.wantsLayer = true;
24
+ self.layer = [CAMetalLayer layer];
25
+ }
26
+ return self;
27
+ }
28
+ #endif // !TARGET_OS_OSX
29
+
30
+ - (void)configure {
31
+ auto size = self.frame.size;
32
+ void *nativeSurface = (__bridge void *)self.layer;
33
+ auto &registry = rnwgpu::SurfaceRegistry::getInstance();
34
+ auto &dawnContext = RNSkia::DawnContext::getInstance();
35
+ auto gpu = dawnContext.getWGPUInstance();
36
+
37
+ // Create the surface using Dawn's API directly
38
+ wgpu::SurfaceSourceMetalLayer metalSurfaceDesc;
39
+ metalSurfaceDesc.layer = nativeSurface;
40
+ wgpu::SurfaceDescriptor surfaceDescriptor;
41
+ surfaceDescriptor.nextInChain = &metalSurfaceDesc;
42
+ auto surface = gpu.CreateSurface(&surfaceDescriptor);
43
+
44
+ registry
45
+ .getSurfaceInfoOrCreate([_contextId intValue], gpu, size.width,
46
+ size.height)
47
+ ->switchToOnscreen(nativeSurface, surface);
48
+ }
49
+
50
+ - (void)update {
51
+ auto size = self.frame.size;
52
+ auto &registry = rnwgpu::SurfaceRegistry::getInstance();
53
+ auto surfaceInfo = registry.getSurfaceInfo([_contextId intValue]);
54
+ if (surfaceInfo) {
55
+ surfaceInfo->resize(size.width, size.height);
56
+ }
57
+ }
58
+
59
+ - (void)dealloc {
60
+ auto &registry = rnwgpu::SurfaceRegistry::getInstance();
61
+ // Remove the surface info from the registry
62
+ registry.removeSurfaceInfo([_contextId intValue]);
63
+ }
64
+
65
+ @end
66
+
67
+ #else // SK_GRAPHITE
68
+
69
+ // Stub implementation when GRAPHITE is not enabled
70
+ @implementation WebGPUMetalView
71
+
72
+ #if !TARGET_OS_OSX
73
+ + (Class)layerClass {
74
+ return [CAMetalLayer class];
75
+ }
76
+ #else // !TARGET_OS_OSX
77
+ - (instancetype)init {
78
+ self = [super init];
79
+ return self;
80
+ }
81
+ #endif // !TARGET_OS_OSX
82
+
83
+ - (void)configure {
84
+ // No-op when GRAPHITE is not enabled
85
+ }
86
+
87
+ - (void)update {
88
+ // No-op when GRAPHITE is not enabled
89
+ }
90
+
91
+ @end
92
+
93
+ #endif // SK_GRAPHITE
@@ -0,0 +1,20 @@
1
+ #pragma once
2
+
3
+ #ifdef RCT_NEW_ARCH_ENABLED
4
+
5
+ #import "WebGPUMetalView.h"
6
+ #import <React/RCTViewComponentView.h>
7
+ #if !TARGET_OS_OSX
8
+ #import <UIKit/UIKit.h>
9
+ #else
10
+ #import <AppKit/AppKit.h>
11
+ #endif
12
+
13
+ NS_ASSUME_NONNULL_BEGIN
14
+
15
+ @interface WebGPUView : RCTViewComponentView
16
+ @end
17
+
18
+ NS_ASSUME_NONNULL_END
19
+
20
+ #endif // RCT_NEW_ARCH_ENABLED
@@ -0,0 +1,77 @@
1
+ #ifdef RCT_NEW_ARCH_ENABLED
2
+
3
+ #import "WebGPUView.h"
4
+
5
+ #import <react/renderer/components/rnskia/ComponentDescriptors.h>
6
+ #import <react/renderer/components/rnskia/EventEmitters.h>
7
+ #import <react/renderer/components/rnskia/Props.h>
8
+ #import <react/renderer/components/rnskia/RCTComponentViewHelpers.h>
9
+
10
+ #import "WebGPUMetalView.h"
11
+ #import "RCTFabricComponentsPlugins.h"
12
+
13
+ using namespace facebook::react;
14
+
15
+ @implementation WebGPUView
16
+
17
+ - (instancetype)initWithFrame:(CGRect)frame {
18
+ if (self = [super initWithFrame:frame]) {
19
+ static const auto defaultProps = std::make_shared<const WebGPUViewProps>();
20
+ _props = defaultProps;
21
+ }
22
+ return self;
23
+ }
24
+
25
+ + (ComponentDescriptorProvider)componentDescriptorProvider {
26
+ return concreteComponentDescriptorProvider<WebGPUViewComponentDescriptor>();
27
+ }
28
+
29
+ - (void)prepareForRecycle {
30
+ [super prepareForRecycle];
31
+ /*
32
+ It's important to destroy the Metal Layer before releasing a view
33
+ to the recycled pool to prevent displaying outdated content from
34
+ the last usage in the new context.
35
+ */
36
+ self.contentView = nil;
37
+ }
38
+
39
+ - (WebGPUMetalView *)getContentView {
40
+ if (!self.contentView) {
41
+ self.contentView = [WebGPUMetalView new];
42
+ }
43
+ return (WebGPUMetalView *)self.contentView;
44
+ }
45
+
46
+ - (void)updateProps:(const Props::Shared &)props
47
+ oldProps:(const Props::Shared &)oldProps {
48
+ const auto &oldViewProps =
49
+ *std::static_pointer_cast<const WebGPUViewProps>(_props);
50
+ const auto &newViewProps =
51
+ *std::static_pointer_cast<const WebGPUViewProps>(props);
52
+
53
+ if (newViewProps.contextId != oldViewProps.contextId) {
54
+ /*
55
+ The context is set only once during mounting the component
56
+ and never changes because it isn't available for users to modify.
57
+ */
58
+ WebGPUMetalView *metalView = [WebGPUMetalView new];
59
+ self.contentView = metalView;
60
+ [metalView setContextId:@(newViewProps.contextId)];
61
+ [metalView configure];
62
+ }
63
+
64
+ [super updateProps:props oldProps:oldProps];
65
+ }
66
+
67
+ - (void)updateLayoutMetrics:(const LayoutMetrics &)layoutMetrics
68
+ oldLayoutMetrics:(const LayoutMetrics &)oldLayoutMetrics {
69
+ [super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:oldLayoutMetrics];
70
+ [(WebGPUMetalView *)self.contentView update];
71
+ }
72
+
73
+ @end
74
+
75
+ Class<RCTComponentViewProtocol> WebGPUViewCls(void) { return WebGPUView.class; }
76
+
77
+ #endif // RCT_NEW_ARCH_ENABLED
@@ -35,6 +35,75 @@
35
35
 
36
36
  #include <jsi/jsi.h>
37
37
 
38
+ #ifdef __APPLE__
39
+ #include <CoreFoundation/CoreFoundation.h>
40
+ #include <CoreGraphics/CoreGraphics.h>
41
+ #include <cstring>
42
+
43
+ // Replaces Skia's generated "Display P3 Gamut with sRGB Transfer" (Google/Skia
44
+ // copyright) ICC profile in a JPEG with Apple's canonical Display P3 ICC bytes
45
+ // from CGColorSpace.displayP3. This is needed because apps like Instagram only
46
+ // recognise the canonical Apple profile, not Skia's mathematically equivalent
47
+ // but non-standard one. Pixel values are untouched — zero quality loss.
48
+ static sk_sp<SkData> replaceJpegICCWithAppleP3(sk_sp<SkData> jpegData) {
49
+ if (!jpegData || jpegData->size() < 4) return jpegData;
50
+
51
+ const uint8_t *src = jpegData->bytes();
52
+ size_t srcLen = jpegData->size();
53
+ if (src[0] != 0xFF || src[1] != 0xD8) return jpegData; // not a JPEG
54
+
55
+ CGColorSpaceRef p3 = CGColorSpaceCreateWithName(kCGColorSpaceDisplayP3);
56
+ if (!p3) return jpegData;
57
+ CFDataRef cfICC = CGColorSpaceCopyICCData(p3);
58
+ CGColorSpaceRelease(p3);
59
+ if (!cfICC) return jpegData;
60
+
61
+ const uint8_t *iccBytes = CFDataGetBytePtr(cfICC);
62
+ size_t iccLen = (size_t)CFDataGetLength(cfICC);
63
+
64
+ // "ICC_PROFILE\0" APP2 marker signature (12 bytes)
65
+ static const uint8_t iccSig[] = {0x49, 0x43, 0x43, 0x5F, 0x50, 0x52,
66
+ 0x4F, 0x46, 0x49, 0x4C, 0x45, 0x00};
67
+
68
+ SkDynamicMemoryWStream out;
69
+
70
+ out.write(src, 2); // SOI
71
+
72
+ // Structure: marker(2) + length(2) + "ICC_PROFILE\0"(12) + chunk[1,1](2) + profile
73
+ size_t iccContentLen = sizeof(iccSig) + 2 + iccLen;
74
+ size_t segLen = iccContentLen + 2; // length field includes itself
75
+ uint8_t app2hdr[4] = {0xFF, 0xE2, (uint8_t)(segLen >> 8),
76
+ (uint8_t)(segLen & 0xFF)};
77
+ uint8_t chunkInfo[2] = {0x01, 0x01}; // chunk 1 of 1
78
+ out.write(app2hdr, 4);
79
+ out.write(iccSig, sizeof(iccSig));
80
+ out.write(chunkInfo, 2);
81
+ out.write(iccBytes, iccLen);
82
+
83
+ // Copy all header segments except any existing ICC APP2
84
+ size_t i = 2;
85
+ while (i + 3 < srcLen) {
86
+ if (src[i] != 0xFF) break;
87
+ uint8_t marker = src[i + 1];
88
+ if (marker == 0xDA || marker == 0xD9) break; // SOS / EOI
89
+ size_t segLenVal = (size_t(src[i + 2]) << 8) | src[i + 3];
90
+ size_t end = i + 2 + segLenVal;
91
+ if (end > srcLen) break;
92
+ bool isICC = marker == 0xE2 && end > i + 4 + sizeof(iccSig) &&
93
+ memcmp(src + i + 4, iccSig, sizeof(iccSig)) == 0;
94
+ if (!isICC) {
95
+ out.write(src + i, end - i);
96
+ }
97
+ i = end;
98
+ }
99
+
100
+ out.write(src + i, srcLen - i);
101
+
102
+ CFRelease(cfICC);
103
+ return out.detachAsData();
104
+ }
105
+ #endif // __APPLE__
106
+
38
107
  namespace RNSkia {
39
108
 
40
109
  namespace jsi = facebook::jsi;
@@ -138,6 +207,13 @@ public:
138
207
  SkJpegEncoder::Options options;
139
208
  options.fQuality = quality;
140
209
  data = SkJpegEncoder::Encode(nullptr, image.get(), options);
210
+ #ifdef __APPLE__
211
+ // Replace Skia's generated ICC with Apple's canonical Display P3 profile
212
+ // so apps like Instagram recognise the wide-gamut colour space.
213
+ if (data && image->colorSpace() && !image->colorSpace()->isSRGB()) {
214
+ data = replaceJpegICCWithAppleP3(data);
215
+ }
216
+ #endif
141
217
  } else if (format == SkEncodedImageFormat::kWEBP) {
142
218
  SkWebpEncoder::Options options;
143
219
  if (quality >= 100) {
@@ -39,8 +39,19 @@ public:
39
39
  JSI_HOST_FUNCTION(MakeOffscreen) {
40
40
  auto width = static_cast<int>(arguments[0].asNumber());
41
41
  auto height = static_cast<int>(arguments[1].asNumber());
42
+ bool useP3ColorSpace = false;
43
+ if (count >= 3 && arguments[2].isObject()) {
44
+ auto opts = arguments[2].asObject(runtime);
45
+ if (opts.hasProperty(runtime, "colorSpace")) {
46
+ auto colorSpaceVal = opts.getProperty(runtime, "colorSpace");
47
+ if (colorSpaceVal.isString()) {
48
+ useP3ColorSpace =
49
+ colorSpaceVal.asString(runtime).utf8(runtime) == "display-p3";
50
+ }
51
+ }
52
+ }
42
53
  auto context = getContext();
43
- auto surface = context->makeOffscreenSurface(width, height);
54
+ auto surface = context->makeOffscreenSurface(width, height, useP3ColorSpace);
44
55
  if (surface == nullptr) {
45
56
  return jsi::Value::null();
46
57
  }
@@ -238,6 +238,17 @@ template <> struct JSIConverter<rnwgpu::async::AsyncTaskHandle> {
238
238
  };
239
239
  #endif
240
240
 
241
+ // jsi::Function <> Function
242
+ template <> struct JSIConverter<jsi::Function> {
243
+ static jsi::Function fromJSI(jsi::Runtime &runtime, const jsi::Value &arg,
244
+ bool outOfBound) {
245
+ return arg.asObject(runtime).asFunction(runtime);
246
+ }
247
+ static jsi::Value toJSI(jsi::Runtime &runtime, jsi::Function &&arg) {
248
+ return std::move(arg);
249
+ }
250
+ };
251
+
241
252
  // std::map<std::string, T> <> Record<string, T>
242
253
  template <typename ValueType>
243
254
  struct JSIConverter<std::map<std::string, ValueType>> {
@@ -7,6 +7,7 @@
7
7
  #include "RNDawnWindowContext.h"
8
8
  #include "RNImageProvider.h"
9
9
 
10
+ #include "include/core/SkColorSpace.h"
10
11
  #include "include/core/SkData.h"
11
12
  #include "include/gpu/graphite/BackendTexture.h"
12
13
  #include "include/gpu/graphite/Context.h"
@@ -162,9 +163,16 @@ public:
162
163
  }
163
164
 
164
165
  // Create offscreen surface
165
- sk_sp<SkSurface> MakeOffscreen(int width, int height) {
166
+ sk_sp<SkSurface> MakeOffscreen(int width, int height,
167
+ bool useP3ColorSpace = false) {
168
+ sk_sp<SkColorSpace> colorSpace =
169
+ useP3ColorSpace
170
+ ? SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB,
171
+ SkNamedGamut::kDisplayP3)
172
+ : nullptr;
166
173
  SkImageInfo info = SkImageInfo::Make(
167
- width, height, DawnUtils::PreferedColorType, kPremul_SkAlphaType);
174
+ width, height, DawnUtils::PreferedColorType, kPremul_SkAlphaType,
175
+ colorSpace);
168
176
  sk_sp<SkSurface> surface = SkSurfaces::RenderTarget(getRecorder(), info);
169
177
 
170
178
  if (!surface) {
@@ -303,6 +311,20 @@ public:
303
311
  getRecorder(), backendContext.fDevice, surface, width, height);
304
312
  }
305
313
 
314
+ skgpu::graphite::Recorder *getRecorder() {
315
+ static thread_local skgpu::graphite::RecorderOptions recorderOptions;
316
+ if (!recorderOptions.fImageProvider) {
317
+ auto imageProvider = ImageProvider::Make();
318
+ recorderOptions.fImageProvider = imageProvider;
319
+ }
320
+ static thread_local auto recorder =
321
+ fGraphiteContext->makeRecorder(recorderOptions);
322
+ if (!recorder) {
323
+ throw std::runtime_error("Failed to create graphite context");
324
+ }
325
+ return recorder.get();
326
+ }
327
+
306
328
  private:
307
329
  std::unique_ptr<dawn::native::Instance> instance;
308
330
  std::unique_ptr<skgpu::graphite::Context> fGraphiteContext;
@@ -346,20 +368,6 @@ private:
346
368
  backendContext.fTick(backendContext.fInstance);
347
369
  }
348
370
  }
349
-
350
- skgpu::graphite::Recorder *getRecorder() {
351
- static thread_local skgpu::graphite::RecorderOptions recorderOptions;
352
- if (!recorderOptions.fImageProvider) {
353
- auto imageProvider = ImageProvider::Make();
354
- recorderOptions.fImageProvider = imageProvider;
355
- }
356
- static thread_local auto recorder =
357
- fGraphiteContext->makeRecorder(recorderOptions);
358
- if (!recorder) {
359
- throw std::runtime_error("Failed to create graphite context");
360
- }
361
- return recorder.get();
362
- }
363
371
  };
364
372
 
365
373
  } // namespace RNSkia
@@ -177,6 +177,18 @@ createDawnBackendContext(dawn::native::Instance *instance) {
177
177
  if (adapter.HasFeature(wgpu::FeatureName::SharedTextureMemoryIOSurface)) {
178
178
  features.push_back(wgpu::FeatureName::SharedTextureMemoryIOSurface);
179
179
  }
180
+ if (adapter.HasFeature(wgpu::FeatureName::DawnMultiPlanarFormats)) {
181
+ features.push_back(wgpu::FeatureName::DawnMultiPlanarFormats);
182
+ }
183
+ if (adapter.HasFeature(wgpu::FeatureName::MultiPlanarFormatP010)) {
184
+ features.push_back(wgpu::FeatureName::MultiPlanarFormatP010);
185
+ }
186
+ if (adapter.HasFeature(wgpu::FeatureName::MultiPlanarFormatP210)) {
187
+ features.push_back(wgpu::FeatureName::MultiPlanarFormatP210);
188
+ }
189
+ if (adapter.HasFeature(wgpu::FeatureName::MultiPlanarFormatExtendedUsages)) {
190
+ features.push_back(wgpu::FeatureName::MultiPlanarFormatExtendedUsages);
191
+ }
180
192
  #else
181
193
  if (adapter.HasFeature(
182
194
  wgpu::FeatureName::SharedTextureMemoryAHardwareBuffer)) {
@@ -14,6 +14,8 @@
14
14
  #ifdef SK_GRAPHITE
15
15
  #include "RNDawnContext.h"
16
16
  #include "rnwgpu/api/GPU.h"
17
+ #include "rnwgpu/api/GPUUncapturedErrorEvent.h"
18
+ #include "rnwgpu/api/RNWebGPU.h"
17
19
  #include "rnwgpu/api/descriptors/GPUBufferUsage.h"
18
20
  #include "rnwgpu/api/descriptors/GPUColorWrite.h"
19
21
  #include "rnwgpu/api/descriptors/GPUMapMode.h"
@@ -73,8 +75,9 @@ void RNSkManager::installBindings() {
73
75
  jsi::Object::createFromHostObject(*_jsRuntime, _viewApi));
74
76
 
75
77
  #ifdef SK_GRAPHITE
76
- // Install WebGPU GPU constructor
78
+ // Install WebGPU constructors
77
79
  rnwgpu::GPU::installConstructor(*_jsRuntime);
80
+ rnwgpu::GPUUncapturedErrorEvent::installConstructor(*_jsRuntime);
78
81
  // Create and expose navigator.gpu using DawnContext's instance
79
82
  auto &dawnContext = DawnContext::getInstance();
80
83
  auto gpu =
@@ -103,9 +106,13 @@ void RNSkManager::installBindings() {
103
106
  rnwgpu::GPUMapMode::create(*_jsRuntime));
104
107
  _jsRuntime->global().setProperty(*_jsRuntime, "GPUShaderStage",
105
108
  rnwgpu::GPUShaderStage::create(*_jsRuntime));
106
- _jsRuntime->global().setProperty(
107
- *_jsRuntime, "GPUTextureUsage",
108
- rnwgpu::GPUTextureUsage::create(*_jsRuntime));
109
+ _jsRuntime->global().setProperty(*_jsRuntime, "GPUTextureUsage",
110
+ rnwgpu::GPUTextureUsage::create(*_jsRuntime));
111
+
112
+ // Install RNWebGPU global object for WebGPU Canvas support
113
+ auto rnWebGPU = std::make_shared<rnwgpu::RNWebGPU>(gpu, nullptr);
114
+ _jsRuntime->global().setProperty(*_jsRuntime, "RNWebGPU",
115
+ rnwgpu::RNWebGPU::create(*_jsRuntime, rnWebGPU));
109
116
  #endif
110
117
  }
111
118
  } // namespace RNSkia
@@ -90,9 +90,11 @@ public:
90
90
  * Creates an offscreen surface
91
91
  * @param width Width of the offscreen surface
92
92
  * @param height Height of the offscreen surface
93
+ * @param useP3ColorSpace If true, surface will use Display P3 color space
93
94
  * @return sk_sp<SkSurface>
94
95
  */
95
- virtual sk_sp<SkSurface> makeOffscreenSurface(int width, int height) = 0;
96
+ virtual sk_sp<SkSurface> makeOffscreenSurface(int width, int height,
97
+ bool useP3ColorSpace = false) = 0;
96
98
 
97
99
  virtual std::shared_ptr<WindowContext>
98
100
  makeContextFromNativeSurface(void *surface, int width, int height) = 0;
@@ -0,0 +1,45 @@
1
+ #pragma once
2
+
3
+ #include <memory>
4
+
5
+ #include "jsi2/NativeObject.h"
6
+
7
+ namespace rnwgpu {
8
+
9
+ namespace jsi = facebook::jsi;
10
+
11
+ class Canvas : public NativeObject<Canvas> {
12
+ public:
13
+ static constexpr const char *CLASS_NAME = "Canvas";
14
+
15
+ Canvas(void *nativeSurface, int width, int height)
16
+ : NativeObject(CLASS_NAME), _nativeSurface(nativeSurface), _width(width),
17
+ _height(height), _clientWidth(width), _clientHeight(height) {}
18
+
19
+ void *getNativeSurface() { return _nativeSurface; }
20
+
21
+ int getWidth() { return _width; }
22
+ int getHeight() { return _height; }
23
+
24
+ int getClientWidth() { return _clientWidth; }
25
+ int getClientHeight() { return _clientHeight; }
26
+
27
+ void setClientWidth(int width) { _clientWidth = width; }
28
+ void setClientHeight(int height) { _clientHeight = height; }
29
+
30
+ static void definePrototype(jsi::Runtime &runtime, jsi::Object &prototype) {
31
+ installGetter(runtime, prototype, "width", &Canvas::getWidth);
32
+ installGetter(runtime, prototype, "height", &Canvas::getHeight);
33
+ installGetter(runtime, prototype, "clientWidth", &Canvas::getClientWidth);
34
+ installGetter(runtime, prototype, "clientHeight", &Canvas::getClientHeight);
35
+ }
36
+
37
+ private:
38
+ void *_nativeSurface;
39
+ int _width;
40
+ int _height;
41
+ int _clientWidth;
42
+ int _clientHeight;
43
+ };
44
+
45
+ } // namespace rnwgpu
@@ -0,0 +1,18 @@
1
+ #pragma once
2
+
3
+ #include <memory>
4
+
5
+ #include "webgpu/webgpu_cpp.h"
6
+
7
+ namespace rnwgpu {
8
+
9
+ class PlatformContext {
10
+ public:
11
+ PlatformContext() = default;
12
+ virtual ~PlatformContext() = default;
13
+
14
+ virtual wgpu::Surface makeSurface(wgpu::Instance instance, void *surface,
15
+ int width, int height) = 0;
16
+ };
17
+
18
+ } // namespace rnwgpu