@shopify/react-native-skia 1.1.0 → 1.2.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 (134) hide show
  1. package/android/CMakeLists.txt +1 -0
  2. package/android/build.gradle +1 -0
  3. package/android/cpp/rnskia-android/AHardwareBufferUtils.cpp +31 -0
  4. package/android/cpp/rnskia-android/AHardwareBufferUtils.h +13 -0
  5. package/android/cpp/rnskia-android/RNSkAndroidPlatformContext.h +75 -0
  6. package/android/cpp/rnskia-android/SkiaOpenGLSurfaceFactory.cpp +29 -11
  7. package/android/cpp/rnskia-android/SkiaOpenGLSurfaceFactory.h +1 -2
  8. package/android/src/main/java/com/shopify/reactnative/skia/ViewScreenshotService.java +3 -2
  9. package/cpp/api/JsiNativeBuffer.h +43 -0
  10. package/cpp/api/JsiSkApi.h +4 -0
  11. package/cpp/api/JsiSkImage.h +1 -1
  12. package/cpp/api/JsiSkImageFactory.h +15 -1
  13. package/cpp/api/JsiSkSurface.h +9 -1
  14. package/cpp/rnskia/RNSkPlatformContext.h +13 -0
  15. package/ios/RNSkia-iOS/RNSkiOSPlatformContext.h +6 -0
  16. package/ios/RNSkia-iOS/RNSkiOSPlatformContext.mm +98 -2
  17. package/ios/RNSkia-iOS/SkiaCVPixelBufferUtils.h +84 -0
  18. package/ios/RNSkia-iOS/SkiaCVPixelBufferUtils.mm +159 -0
  19. package/ios/RNSkia-iOS/SkiaMetalSurfaceFactory.h +5 -0
  20. package/ios/RNSkia-iOS/SkiaMetalSurfaceFactory.mm +37 -1
  21. package/lib/commonjs/external/reanimated/textures.js +11 -2
  22. package/lib/commonjs/external/reanimated/textures.js.map +1 -1
  23. package/lib/commonjs/external/reanimated/useAnimatedImageValue.d.ts +2 -1
  24. package/lib/commonjs/external/reanimated/useAnimatedImageValue.js +8 -4
  25. package/lib/commonjs/external/reanimated/useAnimatedImageValue.js.map +1 -1
  26. package/lib/commonjs/renderer/Offscreen.d.ts +2 -2
  27. package/lib/commonjs/renderer/Offscreen.js +2 -2
  28. package/lib/commonjs/renderer/Offscreen.js.map +1 -1
  29. package/lib/commonjs/skia/types/Image/ImageFactory.d.ts +17 -10
  30. package/lib/commonjs/skia/types/Image/ImageFactory.js +1 -10
  31. package/lib/commonjs/skia/types/Image/ImageFactory.js.map +1 -1
  32. package/lib/commonjs/skia/types/NativeBuffer/NativeBufferFactory.d.ts +18 -0
  33. package/lib/commonjs/skia/types/NativeBuffer/NativeBufferFactory.js +13 -0
  34. package/lib/commonjs/skia/types/NativeBuffer/NativeBufferFactory.js.map +1 -0
  35. package/lib/commonjs/skia/types/NativeBuffer/index.d.ts +1 -0
  36. package/lib/commonjs/skia/types/NativeBuffer/index.js +17 -0
  37. package/lib/commonjs/skia/types/NativeBuffer/index.js.map +1 -0
  38. package/lib/commonjs/skia/types/Skia.d.ts +2 -0
  39. package/lib/commonjs/skia/types/Skia.js.map +1 -1
  40. package/lib/commonjs/skia/types/Surface/Surface.d.ts +8 -0
  41. package/lib/commonjs/skia/types/Surface/Surface.js.map +1 -1
  42. package/lib/commonjs/skia/types/index.d.ts +1 -0
  43. package/lib/commonjs/skia/types/index.js +11 -0
  44. package/lib/commonjs/skia/types/index.js.map +1 -1
  45. package/lib/commonjs/skia/web/JsiSkImage.d.ts +1 -2
  46. package/lib/commonjs/skia/web/JsiSkImage.js +5 -12
  47. package/lib/commonjs/skia/web/JsiSkImage.js.map +1 -1
  48. package/lib/commonjs/skia/web/JsiSkImageFactory.d.ts +3 -2
  49. package/lib/commonjs/skia/web/JsiSkImageFactory.js +19 -0
  50. package/lib/commonjs/skia/web/JsiSkImageFactory.js.map +1 -1
  51. package/lib/commonjs/skia/web/JsiSkNativeBufferFactory.d.ts +8 -0
  52. package/lib/commonjs/skia/web/JsiSkNativeBufferFactory.js +29 -0
  53. package/lib/commonjs/skia/web/JsiSkNativeBufferFactory.js.map +1 -0
  54. package/lib/commonjs/skia/web/JsiSkSurface.d.ts +3 -2
  55. package/lib/commonjs/skia/web/JsiSkSurface.js +8 -6
  56. package/lib/commonjs/skia/web/JsiSkSurface.js.map +1 -1
  57. package/lib/commonjs/skia/web/JsiSkSurfaceFactory.d.ts +1 -1
  58. package/lib/commonjs/skia/web/JsiSkSurfaceFactory.js +1 -16
  59. package/lib/commonjs/skia/web/JsiSkSurfaceFactory.js.map +1 -1
  60. package/lib/commonjs/skia/web/JsiSkia.js +3 -1
  61. package/lib/commonjs/skia/web/JsiSkia.js.map +1 -1
  62. package/lib/module/external/reanimated/textures.js +11 -2
  63. package/lib/module/external/reanimated/textures.js.map +1 -1
  64. package/lib/module/external/reanimated/useAnimatedImageValue.d.ts +2 -1
  65. package/lib/module/external/reanimated/useAnimatedImageValue.js +8 -4
  66. package/lib/module/external/reanimated/useAnimatedImageValue.js.map +1 -1
  67. package/lib/module/renderer/Offscreen.d.ts +2 -2
  68. package/lib/module/renderer/Offscreen.js +2 -2
  69. package/lib/module/renderer/Offscreen.js.map +1 -1
  70. package/lib/module/skia/types/Image/ImageFactory.d.ts +17 -10
  71. package/lib/module/skia/types/Image/ImageFactory.js +1 -10
  72. package/lib/module/skia/types/Image/ImageFactory.js.map +1 -1
  73. package/lib/module/skia/types/NativeBuffer/NativeBufferFactory.d.ts +18 -0
  74. package/lib/module/skia/types/NativeBuffer/NativeBufferFactory.js +4 -0
  75. package/lib/module/skia/types/NativeBuffer/NativeBufferFactory.js.map +1 -0
  76. package/lib/module/skia/types/NativeBuffer/index.d.ts +1 -0
  77. package/lib/module/skia/types/NativeBuffer/index.js +2 -0
  78. package/lib/module/skia/types/NativeBuffer/index.js.map +1 -0
  79. package/lib/module/skia/types/Skia.d.ts +2 -0
  80. package/lib/module/skia/types/Skia.js.map +1 -1
  81. package/lib/module/skia/types/Surface/Surface.d.ts +8 -0
  82. package/lib/module/skia/types/Surface/Surface.js.map +1 -1
  83. package/lib/module/skia/types/index.d.ts +1 -0
  84. package/lib/module/skia/types/index.js +1 -0
  85. package/lib/module/skia/types/index.js.map +1 -1
  86. package/lib/module/skia/web/JsiSkImage.d.ts +1 -2
  87. package/lib/module/skia/web/JsiSkImage.js +5 -12
  88. package/lib/module/skia/web/JsiSkImage.js.map +1 -1
  89. package/lib/module/skia/web/JsiSkImageFactory.d.ts +3 -2
  90. package/lib/module/skia/web/JsiSkImageFactory.js +19 -0
  91. package/lib/module/skia/web/JsiSkImageFactory.js.map +1 -1
  92. package/lib/module/skia/web/JsiSkNativeBufferFactory.d.ts +8 -0
  93. package/lib/module/skia/web/JsiSkNativeBufferFactory.js +22 -0
  94. package/lib/module/skia/web/JsiSkNativeBufferFactory.js.map +1 -0
  95. package/lib/module/skia/web/JsiSkSurface.d.ts +3 -2
  96. package/lib/module/skia/web/JsiSkSurface.js +8 -6
  97. package/lib/module/skia/web/JsiSkSurface.js.map +1 -1
  98. package/lib/module/skia/web/JsiSkSurfaceFactory.d.ts +1 -1
  99. package/lib/module/skia/web/JsiSkSurfaceFactory.js +1 -16
  100. package/lib/module/skia/web/JsiSkSurfaceFactory.js.map +1 -1
  101. package/lib/module/skia/web/JsiSkia.js +3 -1
  102. package/lib/module/skia/web/JsiSkia.js.map +1 -1
  103. package/lib/typescript/src/external/reanimated/useAnimatedImageValue.d.ts +2 -1
  104. package/lib/typescript/src/renderer/Offscreen.d.ts +2 -2
  105. package/lib/typescript/src/skia/types/Image/ImageFactory.d.ts +17 -10
  106. package/lib/typescript/src/skia/types/NativeBuffer/NativeBufferFactory.d.ts +18 -0
  107. package/lib/typescript/src/skia/types/NativeBuffer/index.d.ts +1 -0
  108. package/lib/typescript/src/skia/types/Skia.d.ts +2 -0
  109. package/lib/typescript/src/skia/types/Surface/Surface.d.ts +8 -0
  110. package/lib/typescript/src/skia/types/index.d.ts +1 -0
  111. package/lib/typescript/src/skia/web/JsiSkImage.d.ts +1 -2
  112. package/lib/typescript/src/skia/web/JsiSkImageFactory.d.ts +3 -2
  113. package/lib/typescript/src/skia/web/JsiSkNativeBufferFactory.d.ts +8 -0
  114. package/lib/typescript/src/skia/web/JsiSkSurface.d.ts +3 -2
  115. package/lib/typescript/src/skia/web/JsiSkSurfaceFactory.d.ts +1 -1
  116. package/package.json +1 -1
  117. package/src/external/reanimated/textures.tsx +8 -2
  118. package/src/external/reanimated/useAnimatedImageValue.ts +12 -6
  119. package/src/renderer/Offscreen.tsx +3 -3
  120. package/src/skia/types/Image/ImageFactory.ts +17 -18
  121. package/src/skia/types/NativeBuffer/NativeBufferFactory.ts +38 -0
  122. package/src/skia/types/NativeBuffer/index.ts +1 -0
  123. package/src/skia/types/Skia.ts +2 -1
  124. package/src/skia/types/Surface/Surface.ts +10 -0
  125. package/src/skia/types/index.ts +1 -0
  126. package/src/skia/web/JsiSkImage.ts +5 -22
  127. package/src/skia/web/JsiSkImageFactory.ts +36 -3
  128. package/src/skia/web/JsiSkNativeBufferFactory.ts +35 -0
  129. package/src/skia/web/JsiSkSurface.ts +10 -9
  130. package/src/skia/web/JsiSkSurfaceFactory.ts +3 -19
  131. package/src/skia/web/JsiSkia.ts +2 -0
  132. package/cpp/skia/include/third_party/vulkan/LICENSE +0 -29
  133. package/cpp/skia/modules/skcms/README.chromium +0 -6
  134. package/cpp/skia/readme.txt +0 -1
@@ -47,6 +47,7 @@ add_library(
47
47
  "${PROJECT_SOURCE_DIR}/cpp/rnskia-android/RNSkOpenGLCanvasProvider.cpp"
48
48
  "${PROJECT_SOURCE_DIR}/cpp/rnskia-android/SkiaOpenGLSurfaceFactory.cpp"
49
49
  "${PROJECT_SOURCE_DIR}/cpp/rnskia-android/GrAHardwareBufferUtils.cpp"
50
+ "${PROJECT_SOURCE_DIR}/cpp/rnskia-android/AHardwareBufferUtils.cpp"
50
51
 
51
52
  "${PROJECT_SOURCE_DIR}/../cpp/jsi/JsiHostObject.cpp"
52
53
  "${PROJECT_SOURCE_DIR}/../cpp/jsi/JsiValue.cpp"
@@ -137,6 +137,7 @@ android {
137
137
  targetSdkVersion safeExtGet('targetSdkVersion', DEFAULT_TARGET_SDK_VERSION)
138
138
  versionCode 1
139
139
  versionName "1.0"
140
+ buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
140
141
 
141
142
  externalNativeBuild {
142
143
  cmake {
@@ -0,0 +1,31 @@
1
+ #if __ANDROID_API__ >= 26
2
+
3
+ #include "AHardwareBufferUtils.h"
4
+ #include <android/hardware_buffer.h>
5
+
6
+ namespace RNSkia {
7
+
8
+ uint32_t GetBufferFormatFromSkColorType(SkColorType bufferFormat) {
9
+ switch (bufferFormat) {
10
+ case kRGBA_8888_SkColorType:
11
+ return AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
12
+ case kRGB_888x_SkColorType:
13
+ return AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM;
14
+ case kRGBA_F16_SkColorType:
15
+ return AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT;
16
+ case kRGB_565_SkColorType:
17
+ return AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
18
+ case kRGBA_1010102_SkColorType:
19
+ return AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM;
20
+ #if __ANDROID_API__ >= 33
21
+ case kAlpha_8_SkColorType:
22
+ return AHARDWAREBUFFER_FORMAT_R8_UNORM;
23
+ #endif
24
+ default:
25
+ return AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
26
+ }
27
+ }
28
+
29
+ } // namespace RNSkia
30
+
31
+ #endif
@@ -0,0 +1,13 @@
1
+ #pragma once
2
+
3
+ #include "include/core/SkColorType.h"
4
+
5
+ #if __ANDROID_API__ >= 26
6
+
7
+ namespace RNSkia {
8
+
9
+ uint32_t GetBufferFormatFromSkColorType(SkColorType bufferFormat);
10
+
11
+ } // namespace RNSkia
12
+
13
+ #endif
@@ -1,10 +1,15 @@
1
1
  #pragma once
2
2
 
3
+ // TODO: Add android flags
4
+ #if __ANDROID_API__ >= 26
5
+ #include <android/hardware_buffer.h>
6
+ #endif
3
7
  #include <exception>
4
8
  #include <functional>
5
9
  #include <memory>
6
10
  #include <string>
7
11
 
12
+ #include "AHardwareBufferUtils.h"
8
13
  #include "JniPlatformContext.h"
9
14
  #include "RNSkPlatformContext.h"
10
15
  #include "SkiaOpenGLSurfaceFactory.h"
@@ -48,6 +53,76 @@ public:
48
53
  return SkiaOpenGLSurfaceFactory::makeOffscreenSurface(width, height);
49
54
  }
50
55
 
56
+ sk_sp<SkImage> makeImageFromNativeBuffer(void *buffer) override {
57
+ return SkiaOpenGLSurfaceFactory::makeImageFromHardwareBuffer(buffer);
58
+ }
59
+
60
+ void releaseNativeBuffer(uint64_t pointer) override {
61
+ #if __ANDROID_API__ >= 26
62
+ AHardwareBuffer *buffer = reinterpret_cast<AHardwareBuffer *>(pointer);
63
+ AHardwareBuffer_release(buffer);
64
+ #endif
65
+ }
66
+
67
+ uint64_t makeNativeBuffer(sk_sp<SkImage> image) override {
68
+ #if __ANDROID_API__ >= 26
69
+ auto bytesPerPixel = image->imageInfo().bytesPerPixel();
70
+ int bytesPerRow = image->width() * bytesPerPixel;
71
+ auto buf = SkData::MakeUninitialized(image->width() * image->height() *
72
+ bytesPerPixel);
73
+ SkImageInfo info =
74
+ SkImageInfo::Make(image->width(), image->height(), image->colorType(),
75
+ image->alphaType());
76
+ image->readPixels(nullptr, info, const_cast<void *>(buf->data()),
77
+ bytesPerRow, 0, 0);
78
+ const void *pixelData = buf->data();
79
+
80
+ // Define the buffer description
81
+ AHardwareBuffer_Desc desc = {};
82
+ // TODO: use image info here
83
+ desc.width = image->width();
84
+ desc.height = image->height();
85
+ desc.layers = 1; // Single image layer
86
+ desc.format = GetBufferFormatFromSkColorType(
87
+ image->colorType()); // Assuming the image
88
+ // is in this format
89
+ desc.usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
90
+ AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN |
91
+ AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT |
92
+ AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
93
+ desc.stride = bytesPerRow; // Stride in pixels, not in bytes
94
+
95
+ // Allocate the buffer
96
+ AHardwareBuffer *buffer = nullptr;
97
+ if (AHardwareBuffer_allocate(&desc, &buffer) != 0) {
98
+ // Handle allocation failure
99
+ return 0;
100
+ }
101
+
102
+ // Map the buffer to gain access to its memory
103
+ void *mappedBuffer = nullptr;
104
+ AHardwareBuffer_lock(buffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN, -1,
105
+ nullptr, &mappedBuffer);
106
+ if (mappedBuffer == nullptr) {
107
+ // Handle mapping failure
108
+ AHardwareBuffer_release(buffer);
109
+ return 0;
110
+ }
111
+
112
+ // Copy the image data to the buffer
113
+ memcpy(mappedBuffer, pixelData, desc.height * bytesPerRow);
114
+
115
+ // Unmap the buffer
116
+ AHardwareBuffer_unlock(buffer, nullptr);
117
+
118
+ // Return the buffer pointer as a uint64_t. It's the caller's responsibility
119
+ // to manage this buffer.
120
+ return reinterpret_cast<uint64_t>(buffer);
121
+ #else
122
+ return 0;
123
+ #endif
124
+ }
125
+
51
126
  sk_sp<SkFontMgr> createFontMgr() override {
52
127
  return SkFontMgr_New_Android(nullptr);
53
128
  }
@@ -7,6 +7,7 @@
7
7
 
8
8
  #include "include/gpu/ganesh/SkImageGanesh.h"
9
9
  #include "include/gpu/ganesh/gl/GrGLBackendSurface.h"
10
+ #include "src/gpu/ganesh/gl/GrGLDefines.h"
10
11
 
11
12
  #pragma clang diagnostic pop
12
13
 
@@ -15,30 +16,47 @@ namespace RNSkia {
15
16
  thread_local SkiaOpenGLContext ThreadContextHolder::ThreadSkiaOpenGLContext;
16
17
 
17
18
  sk_sp<SkImage>
18
- SkiaOpenGLSurfaceFactory::makeImageFromHardwareBuffer(const SkImageInfo &info,
19
- void *buffer) {
19
+ SkiaOpenGLSurfaceFactory::makeImageFromHardwareBuffer(void *buffer) {
20
20
  #if __ANDROID_API__ >= 26
21
+ // Setup OpenGL and Skia:
22
+ if (!SkiaOpenGLHelper::createSkiaDirectContextIfNecessary(
23
+ &ThreadContextHolder::ThreadSkiaOpenGLContext)) {
24
+
25
+ RNSkLogger::logToConsole(
26
+ "Could not create Skia Surface from native window / surface. "
27
+ "Failed creating Skia Direct Context");
28
+ return nullptr;
29
+ }
21
30
  const AHardwareBuffer *hardwareBuffer =
22
31
  static_cast<AHardwareBuffer *>(buffer);
23
32
  DeleteImageProc deleteImageProc = nullptr;
24
33
  UpdateImageProc updateImageProc = nullptr;
25
34
  TexImageCtx deleteImageCtx = nullptr;
35
+
36
+ AHardwareBuffer_Desc description;
37
+ AHardwareBuffer_describe(hardwareBuffer, &description);
38
+ if (description.format != AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM) {
39
+ throw std::runtime_error("AHardwareBuffer has unknown format (" +
40
+ std::to_string(description.format) +
41
+ ") - cannot convert to SkImage!");
42
+ }
43
+ GrBackendFormat format =
44
+ GrBackendFormats::MakeGL(GR_GL_RGBA8, GR_GL_TEXTURE_EXTERNAL);
45
+
26
46
  auto backendTex = MakeGLBackendTexture(
27
47
  ThreadContextHolder::ThreadSkiaOpenGLContext.directContext.get(),
28
- const_cast<AHardwareBuffer *>(hardwareBuffer), info.width(),
29
- info.height(), &deleteImageProc, &updateImageProc, &deleteImageCtx, false,
30
- // GR_GL_RGBA8 0x8058
31
- // GR_GL_TEXTURE_EXTERNAL 0x8D65
32
- GrBackendFormats::MakeGL(0x8058, 0x8D65), false);
48
+ const_cast<AHardwareBuffer *>(hardwareBuffer), description.width,
49
+ description.height, &deleteImageProc, &updateImageProc, &deleteImageCtx,
50
+ false, format, false);
33
51
  sk_sp<SkImage> image = SkImages::BorrowTextureFrom(
34
52
  ThreadContextHolder::ThreadSkiaOpenGLContext.directContext.get(),
35
53
  backendTex, kTopLeft_GrSurfaceOrigin, kRGBA_8888_SkColorType,
36
- kPremul_SkAlphaType, nullptr);
54
+ kOpaque_SkAlphaType, nullptr);
37
55
  return image;
38
56
  #else
39
- RNSkLogger::logToConsole(
40
- "Hardware buffer in only supported on Android API level 26 and above.");
41
- return nullptr;
57
+ throw std::runtime_error(
58
+ "HardwareBuffers are only supported on Android API 26 or higher! Set "
59
+ "your minSdk to 26 (or higher) and try again.");
42
60
  #endif
43
61
  }
44
62
 
@@ -149,8 +149,7 @@ public:
149
149
  */
150
150
  static sk_sp<SkSurface> makeOffscreenSurface(int width, int height);
151
151
 
152
- static sk_sp<SkImage> makeImageFromHardwareBuffer(const SkImageInfo &info,
153
- void *buffer);
152
+ static sk_sp<SkImage> makeImageFromHardwareBuffer(void *buffer);
154
153
 
155
154
  /**
156
155
  * Creates a windowed Skia Surface holder.
@@ -17,7 +17,8 @@ import android.view.ViewGroup;
17
17
  import android.widget.ScrollView;
18
18
  import androidx.annotation.NonNull;
19
19
  import com.facebook.react.bridge.ReactContext;
20
- import com.facebook.react.uimanager.UIManagerModule;
20
+ import com.facebook.react.bridge.UIManager;
21
+ import com.facebook.react.uimanager.UIManagerHelper;
21
22
  import com.facebook.react.views.view.ReactViewGroup;
22
23
 
23
24
  import java.lang.reflect.Method;
@@ -29,7 +30,7 @@ public class ViewScreenshotService {
29
30
  private static final String TAG = "SkiaScreenshot";
30
31
 
31
32
  public static Bitmap makeViewScreenshotFromTag(ReactContext context, int tag) {
32
- UIManagerModule uiManager = context.getNativeModule(UIManagerModule.class);
33
+ UIManager uiManager = UIManagerHelper.getUIManagerForReactTag(context, tag);
33
34
  View view = null;
34
35
  try {
35
36
  view = uiManager.resolveView(tag);
@@ -0,0 +1,43 @@
1
+ #pragma once
2
+
3
+ #include <memory>
4
+ #include <utility>
5
+
6
+ #include <jsi/jsi.h>
7
+
8
+ #include "JsiSkImage.h"
9
+
10
+ namespace RNSkia {
11
+
12
+ namespace jsi = facebook::jsi;
13
+
14
+ /**
15
+ Implementation of the ParagraphBuilderFactory for making ParagraphBuilder JSI
16
+ object
17
+ */
18
+ class JsiNativeBufferFactory : public JsiSkHostObject {
19
+ public:
20
+ JSI_HOST_FUNCTION(MakeFromImage) {
21
+ auto image = JsiSkImage::fromValue(runtime, arguments[0]);
22
+ image->makeNonTextureImage();
23
+ uint64_t pointer = getContext()->makeNativeBuffer(image);
24
+ return jsi::BigInt::fromUint64(runtime, pointer);
25
+ }
26
+
27
+ JSI_HOST_FUNCTION(Release) {
28
+
29
+ jsi::BigInt pointer = arguments[0].asBigInt(runtime);
30
+ const uintptr_t nativeBufferPointer = pointer.asUint64(runtime);
31
+
32
+ getContext()->releaseNativeBuffer(nativeBufferPointer);
33
+ return jsi::Value::undefined();
34
+ }
35
+
36
+ JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiNativeBufferFactory, Release),
37
+ JSI_EXPORT_FUNC(JsiNativeBufferFactory, MakeFromImage))
38
+
39
+ explicit JsiNativeBufferFactory(std::shared_ptr<RNSkPlatformContext> context)
40
+ : JsiSkHostObject(std::move(context)) {}
41
+ };
42
+
43
+ } // namespace RNSkia
@@ -6,6 +6,7 @@
6
6
 
7
7
  #include "JsiSkHostObjects.h"
8
8
 
9
+ #include "JsiNativeBuffer.h"
9
10
  #include "JsiSkAnimatedImage.h"
10
11
  #include "JsiSkAnimatedImageFactory.h"
11
12
  #include "JsiSkColor.h"
@@ -122,6 +123,9 @@ public:
122
123
  installReadonlyProperty(
123
124
  "ParagraphBuilder",
124
125
  std::make_shared<JsiSkParagraphBuilderFactory>(context));
126
+
127
+ installReadonlyProperty("NativeBuffer",
128
+ std::make_shared<JsiNativeBufferFactory>(context));
125
129
  }
126
130
  };
127
131
  } // namespace RNSkia
@@ -177,7 +177,7 @@ public:
177
177
  if (!getObject()->readPixels(info, bfrPtr, bytesPerRow, srcX, srcY)) {
178
178
  return jsi::Value::null();
179
179
  }
180
- return std::move(dest);
180
+ return dest;
181
181
  }
182
182
 
183
183
  JSI_HOST_FUNCTION(makeNonTextureImage) {
@@ -27,6 +27,18 @@ public:
27
27
  runtime, std::make_shared<JsiSkImage>(getContext(), std::move(image)));
28
28
  }
29
29
 
30
+ JSI_HOST_FUNCTION(MakeImageFromNativeBuffer) {
31
+ jsi::BigInt pointer = arguments[0].asBigInt(runtime);
32
+ const uintptr_t platformBufferPointer = pointer.asUint64(runtime);
33
+ void *rawPointer = reinterpret_cast<void *>(platformBufferPointer);
34
+ auto image = getContext()->makeImageFromNativeBuffer(rawPointer);
35
+ if (image == nullptr) {
36
+ throw std::runtime_error("Failed to convert PlatformBuffer to SkImage!");
37
+ }
38
+ return jsi::Object::createFromHostObject(
39
+ runtime, std::make_shared<JsiSkImage>(getContext(), std::move(image)));
40
+ }
41
+
30
42
  JSI_HOST_FUNCTION(MakeImage) {
31
43
  auto imageInfo = JsiSkImageInfo::fromValue(runtime, arguments[0]);
32
44
  auto pixelData = JsiSkData::fromValue(runtime, arguments[1]);
@@ -68,7 +80,9 @@ public:
68
80
 
69
81
  JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkImageFactory, MakeImageFromEncoded),
70
82
  JSI_EXPORT_FUNC(JsiSkImageFactory, MakeImageFromViewTag),
71
- JSI_EXPORT_FUNC(JsiSkImageFactory, MakeImage), )
83
+ JSI_EXPORT_FUNC(JsiSkImageFactory,
84
+ MakeImageFromNativeBuffer),
85
+ JSI_EXPORT_FUNC(JsiSkImageFactory, MakeImage))
72
86
 
73
87
  explicit JsiSkImageFactory(std::shared_ptr<RNSkPlatformContext> context)
74
88
  : JsiSkHostObject(std::move(context)) {}
@@ -31,6 +31,12 @@ public:
31
31
 
32
32
  EXPORT_JSI_API_TYPENAME(JsiSkSurface, Surface)
33
33
 
34
+ // TODO-API: Properties?
35
+ JSI_HOST_FUNCTION(width) { return static_cast<double>(getObject()->width()); }
36
+ JSI_HOST_FUNCTION(height) {
37
+ return static_cast<double>(getObject()->height());
38
+ }
39
+
34
40
  JSI_HOST_FUNCTION(getCanvas) {
35
41
  return jsi::Object::createFromHostObject(
36
42
  runtime,
@@ -57,7 +63,9 @@ public:
57
63
  runtime, std::make_shared<JsiSkImage>(getContext(), std::move(image)));
58
64
  }
59
65
 
60
- JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkSurface, getCanvas),
66
+ JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkSurface, width),
67
+ JSI_EXPORT_FUNC(JsiSkSurface, height),
68
+ JSI_EXPORT_FUNC(JsiSkSurface, getCanvas),
61
69
  JSI_EXPORT_FUNC(JsiSkSurface, makeImageSnapshot),
62
70
  JSI_EXPORT_FUNC(JsiSkSurface, flush),
63
71
  JSI_EXPORT_FUNC(JsiSkSurface, dispose))
@@ -133,6 +133,19 @@ public:
133
133
  */
134
134
  virtual sk_sp<SkSurface> makeOffscreenSurface(int width, int height) = 0;
135
135
 
136
+ /**
137
+ * Creates an image from a native buffer. (for testing purposes only)
138
+ * - On iOS, this is a `CVPixelBufferRef*`
139
+ * - On Android, this is a `AHardwareBuffer*`
140
+ * @param buffer The native platform buffer.
141
+ * @return sk_sp<SkImage>
142
+ */
143
+ virtual sk_sp<SkImage> makeImageFromNativeBuffer(void *buffer) = 0;
144
+
145
+ virtual void releaseNativeBuffer(uint64_t pointer) = 0;
146
+
147
+ virtual uint64_t makeNativeBuffer(sk_sp<SkImage> image) = 0;
148
+
136
149
  /**
137
150
  * Return the Platform specific font manager
138
151
  */
@@ -59,6 +59,12 @@ public:
59
59
 
60
60
  sk_sp<SkImage> takeScreenshotFromViewTag(size_t tag) override;
61
61
 
62
+ sk_sp<SkImage> makeImageFromNativeBuffer(void *buffer) override;
63
+
64
+ uint64_t makeNativeBuffer(sk_sp<SkImage> image) override;
65
+
66
+ void releaseNativeBuffer(uint64_t pointer) override;
67
+
62
68
  virtual void performStreamOperation(
63
69
  const std::string &sourceUri,
64
70
  const std::function<void(std::unique_ptr<SkStreamAsset>)> &op) override;
@@ -1,10 +1,12 @@
1
- #include "RNSkiOSPlatformContext.h"
1
+ #import "RNSkiOSPlatformContext.h"
2
2
 
3
+ #import <CoreMedia/CMSampleBuffer.h>
3
4
  #import <React/RCTUtils.h>
4
5
  #include <thread>
5
6
  #include <utility>
6
7
 
7
- #include "SkiaMetalSurfaceFactory.h"
8
+ #import "SkiaCVPixelBufferUtils.h"
9
+ #import "SkiaMetalSurfaceFactory.h"
8
10
 
9
11
  #pragma clang diagnostic push
10
12
  #pragma clang diagnostic ignored "-Wdocumentation"
@@ -56,6 +58,95 @@ void RNSkiOSPlatformContext::performStreamOperation(
56
58
  std::thread(loader).detach();
57
59
  }
58
60
 
61
+ void RNSkiOSPlatformContext::releaseNativeBuffer(uint64_t pointer) {
62
+ CMSampleBufferRef sampleBuffer = reinterpret_cast<CMSampleBufferRef>(pointer);
63
+ CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
64
+ if (sampleBuffer) {
65
+ CFRelease(sampleBuffer);
66
+ }
67
+ if (pixelBuffer) {
68
+ CFRelease(pixelBuffer);
69
+ }
70
+ }
71
+
72
+ uint64_t RNSkiOSPlatformContext::makeNativeBuffer(sk_sp<SkImage> image) {
73
+ // 0. If Image is not in BGRA, convert to BGRA as only BGRA is supported.
74
+ if (image->colorType() != kBGRA_8888_SkColorType) {
75
+ // on iOS, 32_BGRA is the only supported RGB format for CVPixelBuffers.
76
+ image = image->makeColorTypeAndColorSpace(
77
+ ThreadContextHolder::ThreadSkiaMetalContext.skContext.get(),
78
+ kBGRA_8888_SkColorType, SkColorSpace::MakeSRGB());
79
+ if (image == nullptr) {
80
+ throw std::runtime_error(
81
+ "Failed to convert image to BGRA_8888 colortype! Only BGRA_8888 "
82
+ "PlatformBuffers are supported.");
83
+ }
84
+ }
85
+
86
+ // 1. Get image info
87
+ auto bytesPerPixel = image->imageInfo().bytesPerPixel();
88
+ int bytesPerRow = image->width() * bytesPerPixel;
89
+ auto buf = SkData::MakeUninitialized(image->width() * image->height() *
90
+ bytesPerPixel);
91
+ SkImageInfo info = SkImageInfo::Make(image->width(), image->height(),
92
+ image->colorType(), image->alphaType());
93
+ // 2. Copy pixels into our buffer
94
+ image->readPixels(nullptr, info, const_cast<void *>(buf->data()), bytesPerRow,
95
+ 0, 0);
96
+
97
+ // 3. Create an IOSurface (GPU + CPU memory)
98
+ CFMutableDictionaryRef dict = CFDictionaryCreateMutable(
99
+ kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks,
100
+ &kCFTypeDictionaryValueCallBacks);
101
+ int width = image->width();
102
+ int height = image->height();
103
+ int pitch = width * bytesPerPixel;
104
+ int size = width * height * bytesPerPixel;
105
+ OSType pixelFormat = kCVPixelFormatType_32BGRA;
106
+ CFDictionarySetValue(
107
+ dict, kIOSurfaceBytesPerRow,
108
+ CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &pitch));
109
+ CFDictionarySetValue(
110
+ dict, kIOSurfaceBytesPerElement,
111
+ CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &bytesPerPixel));
112
+ CFDictionarySetValue(
113
+ dict, kIOSurfaceWidth,
114
+ CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &width));
115
+ CFDictionarySetValue(
116
+ dict, kIOSurfaceHeight,
117
+ CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &height));
118
+ CFDictionarySetValue(
119
+ dict, kIOSurfacePixelFormat,
120
+ CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &pixelFormat));
121
+ CFDictionarySetValue(
122
+ dict, kIOSurfaceAllocSize,
123
+ CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &size));
124
+ IOSurfaceRef surface = IOSurfaceCreate(dict);
125
+ if (surface == nil) {
126
+ throw std::runtime_error("Failed to create " + std::to_string(width) + "x" +
127
+ std::to_string(height) + " IOSurface!");
128
+ }
129
+
130
+ // 4. Copy over the memory from the pixels into the IOSurface
131
+ IOSurfaceLock(surface, 0, nil);
132
+ void *base = IOSurfaceGetBaseAddress(surface);
133
+ memcpy(base, buf->data(), buf->size());
134
+ IOSurfaceUnlock(surface, 0, nil);
135
+
136
+ // 5. Create a CVPixelBuffer from the IOSurface
137
+ CVPixelBufferRef pixelBuffer = nullptr;
138
+ CVReturn result =
139
+ CVPixelBufferCreateWithIOSurface(nil, surface, nil, &pixelBuffer);
140
+ if (result != kCVReturnSuccess) {
141
+ throw std::runtime_error(
142
+ "Failed to create CVPixelBuffer from SkImage! Return value: " +
143
+ std::to_string(result));
144
+ }
145
+
146
+ // 8. Return CVPixelBuffer casted to uint64_t
147
+ return reinterpret_cast<uint64_t>(pixelBuffer);
148
+ }
149
+
59
150
  void RNSkiOSPlatformContext::raiseError(const std::exception &err) {
60
151
  RCTFatal(RCTErrorWithMessage([NSString stringWithUTF8String:err.what()]));
61
152
  }
@@ -65,6 +156,11 @@ sk_sp<SkSurface> RNSkiOSPlatformContext::makeOffscreenSurface(int width,
65
156
  return SkiaMetalSurfaceFactory::makeOffscreenSurface(width, height);
66
157
  }
67
158
 
159
+ sk_sp<SkImage> RNSkiOSPlatformContext::makeImageFromNativeBuffer(void *buffer) {
160
+ CVPixelBufferRef sampleBuffer = (CVPixelBufferRef)buffer;
161
+ return SkiaMetalSurfaceFactory::makeTextureFromCVPixelBuffer(sampleBuffer);
162
+ }
163
+
68
164
  sk_sp<SkFontMgr> RNSkiOSPlatformContext::createFontMgr() {
69
165
  return SkFontMgr_New_CoreText(nullptr);
70
166
  }
@@ -0,0 +1,84 @@
1
+ //
2
+ // SkiaCVPixelBufferUtils.h
3
+ // react-native-skia
4
+ //
5
+ // Created by Marc Rousavy on 10.04.24.
6
+ //
7
+
8
+ #pragma once
9
+ #import <CoreMedia/CMSampleBuffer.h>
10
+ #import <CoreVideo/CVMetalTextureCache.h>
11
+ #import <MetalKit/MetalKit.h>
12
+
13
+ #pragma clang diagnostic push
14
+ #pragma clang diagnostic ignored "-Wdocumentation"
15
+ #import "include/core/SkColorSpace.h"
16
+ #import <include/gpu/GrBackendSurface.h>
17
+ #pragma clang diagnostic pop
18
+
19
+ /**
20
+ Holds a Metal Texture.
21
+ When the `TextureHolder` is destroyed, the underlying Metal Texture
22
+ is marked as invalid and might be overwritten by the Texture Cache,
23
+ so make sure to delete the `TextureHolder` only when the `SkImage`
24
+ has been deleted.
25
+
26
+ For example, use the `releaseProc` parameter in `BorrowImageFromTexture`
27
+ to delete the `TextureHolder`.
28
+ */
29
+ class TextureHolder {
30
+ public:
31
+ /**
32
+ Create a new instance of TextureHolder which holds
33
+ the given `CVMetalTextureRef`.
34
+
35
+ The given `CVMetalTextureRef` is assumed to already be
36
+ retained with `CFRetain`, and will later be manually
37
+ released with `CFRelease`.
38
+ */
39
+ explicit TextureHolder(CVMetalTextureRef texture);
40
+ ~TextureHolder();
41
+
42
+ /**
43
+ Converts this Texture to a Skia GrBackendTexture.
44
+ */
45
+ GrBackendTexture toGrBackendTexture();
46
+
47
+ private:
48
+ CVMetalTextureRef _texture;
49
+ };
50
+
51
+ class SkiaCVPixelBufferUtils {
52
+ public:
53
+ enum class CVPixelBufferBaseFormat { rgb };
54
+
55
+ /**
56
+ Get the base format (currently only RGB) of the PixelBuffer.
57
+ Depending on the base-format, different methods have to be used to create
58
+ Skia buffers.
59
+ */
60
+ static CVPixelBufferBaseFormat
61
+ getCVPixelBufferBaseFormat(CVPixelBufferRef pixelBuffer);
62
+
63
+ class RGB {
64
+ public:
65
+ /**
66
+ Gets the Skia Color Type of the RGB pixel-buffer.
67
+ */
68
+ static SkColorType getCVPixelBufferColorType(CVPixelBufferRef pixelBuffer);
69
+ /**
70
+ Gets a GPU-backed Skia Texture for the given RGB CVPixelBuffer.
71
+ */
72
+ static TextureHolder *
73
+ getSkiaTextureForCVPixelBuffer(CVPixelBufferRef pixelBuffer);
74
+ };
75
+
76
+ private:
77
+ static CVMetalTextureCacheRef getTextureCache();
78
+ static TextureHolder *
79
+ getSkiaTextureForCVPixelBufferPlane(CVPixelBufferRef pixelBuffer,
80
+ size_t planeIndex);
81
+ static MTLPixelFormat
82
+ getMTLPixelFormatForCVPixelBufferPlane(CVPixelBufferRef pixelBuffer,
83
+ size_t planeIndex);
84
+ };