@shopify/react-native-skia 1.1.0 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
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
+ };