@shopify/react-native-skia 1.0.6 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (150) 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/JsiPlatformBuffer.h +51 -0
  10. package/cpp/api/JsiSkApi.h +4 -0
  11. package/cpp/api/JsiSkImage.h +1 -1
  12. package/cpp/api/JsiSkImageFactory.h +15 -2
  13. package/cpp/api/JsiSkSurface.h +9 -1
  14. package/cpp/rnskia/RNSkJsiViewApi.h +48 -0
  15. package/cpp/rnskia/RNSkPlatformContext.h +13 -0
  16. package/ios/RNSkia-iOS/RNSkiOSPlatformContext.h +6 -0
  17. package/ios/RNSkia-iOS/RNSkiOSPlatformContext.mm +115 -0
  18. package/ios/RNSkia-iOS/SkiaMetalSurfaceFactory.h +4 -0
  19. package/ios/RNSkia-iOS/SkiaMetalSurfaceFactory.mm +12 -0
  20. package/lib/commonjs/external/reanimated/textures.js +11 -2
  21. package/lib/commonjs/external/reanimated/textures.js.map +1 -1
  22. package/lib/commonjs/external/reanimated/useAnimatedImageValue.d.ts +2 -1
  23. package/lib/commonjs/external/reanimated/useAnimatedImageValue.js +8 -4
  24. package/lib/commonjs/external/reanimated/useAnimatedImageValue.js.map +1 -1
  25. package/lib/commonjs/mock/index.js +1 -0
  26. package/lib/commonjs/mock/index.js.map +1 -1
  27. package/lib/commonjs/renderer/Offscreen.d.ts +2 -2
  28. package/lib/commonjs/renderer/Offscreen.js +2 -2
  29. package/lib/commonjs/renderer/Offscreen.js.map +1 -1
  30. package/lib/commonjs/skia/types/Image/ImageFactory.d.ts +14 -0
  31. package/lib/commonjs/skia/types/Image/ImageFactory.js.map +1 -1
  32. package/lib/commonjs/skia/types/PlatformBuffer/PlatformBufferFactory.d.ts +12 -0
  33. package/lib/commonjs/skia/types/PlatformBuffer/PlatformBufferFactory.js +6 -0
  34. package/lib/commonjs/skia/types/PlatformBuffer/PlatformBufferFactory.js.map +1 -0
  35. package/lib/commonjs/skia/types/PlatformBuffer/index.d.ts +1 -0
  36. package/lib/commonjs/skia/types/PlatformBuffer/index.js +17 -0
  37. package/lib/commonjs/skia/types/PlatformBuffer/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 +2 -2
  49. package/lib/commonjs/skia/web/JsiSkImageFactory.js +3 -0
  50. package/lib/commonjs/skia/web/JsiSkImageFactory.js.map +1 -1
  51. package/lib/commonjs/skia/web/JsiSkPlatformBufferFactory.d.ts +8 -0
  52. package/lib/commonjs/skia/web/JsiSkPlatformBufferFactory.js +20 -0
  53. package/lib/commonjs/skia/web/JsiSkPlatformBufferFactory.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 +2 -17
  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/commonjs/views/SkiaDomView.d.ts +6 -0
  63. package/lib/commonjs/views/SkiaDomView.js +10 -0
  64. package/lib/commonjs/views/SkiaDomView.js.map +1 -1
  65. package/lib/commonjs/views/types.d.ts +1 -0
  66. package/lib/commonjs/views/types.js.map +1 -1
  67. package/lib/module/external/reanimated/textures.js +11 -2
  68. package/lib/module/external/reanimated/textures.js.map +1 -1
  69. package/lib/module/external/reanimated/useAnimatedImageValue.d.ts +2 -1
  70. package/lib/module/external/reanimated/useAnimatedImageValue.js +8 -4
  71. package/lib/module/external/reanimated/useAnimatedImageValue.js.map +1 -1
  72. package/lib/module/mock/index.js +1 -0
  73. package/lib/module/mock/index.js.map +1 -1
  74. package/lib/module/renderer/Offscreen.d.ts +2 -2
  75. package/lib/module/renderer/Offscreen.js +2 -2
  76. package/lib/module/renderer/Offscreen.js.map +1 -1
  77. package/lib/module/skia/types/Image/ImageFactory.d.ts +14 -0
  78. package/lib/module/skia/types/Image/ImageFactory.js.map +1 -1
  79. package/lib/module/skia/types/PlatformBuffer/PlatformBufferFactory.d.ts +12 -0
  80. package/lib/module/skia/types/PlatformBuffer/PlatformBufferFactory.js +2 -0
  81. package/lib/module/skia/types/PlatformBuffer/PlatformBufferFactory.js.map +1 -0
  82. package/lib/module/skia/types/PlatformBuffer/index.d.ts +1 -0
  83. package/lib/module/skia/types/PlatformBuffer/index.js +2 -0
  84. package/lib/module/skia/types/PlatformBuffer/index.js.map +1 -0
  85. package/lib/module/skia/types/Skia.d.ts +2 -0
  86. package/lib/module/skia/types/Skia.js.map +1 -1
  87. package/lib/module/skia/types/Surface/Surface.d.ts +8 -0
  88. package/lib/module/skia/types/Surface/Surface.js.map +1 -1
  89. package/lib/module/skia/types/index.d.ts +1 -0
  90. package/lib/module/skia/types/index.js +1 -0
  91. package/lib/module/skia/types/index.js.map +1 -1
  92. package/lib/module/skia/web/JsiSkImage.d.ts +1 -2
  93. package/lib/module/skia/web/JsiSkImage.js +5 -12
  94. package/lib/module/skia/web/JsiSkImage.js.map +1 -1
  95. package/lib/module/skia/web/JsiSkImageFactory.d.ts +2 -2
  96. package/lib/module/skia/web/JsiSkImageFactory.js +3 -0
  97. package/lib/module/skia/web/JsiSkImageFactory.js.map +1 -1
  98. package/lib/module/skia/web/JsiSkPlatformBufferFactory.d.ts +8 -0
  99. package/lib/module/skia/web/JsiSkPlatformBufferFactory.js +13 -0
  100. package/lib/module/skia/web/JsiSkPlatformBufferFactory.js.map +1 -0
  101. package/lib/module/skia/web/JsiSkSurface.d.ts +3 -2
  102. package/lib/module/skia/web/JsiSkSurface.js +8 -6
  103. package/lib/module/skia/web/JsiSkSurface.js.map +1 -1
  104. package/lib/module/skia/web/JsiSkSurfaceFactory.d.ts +1 -1
  105. package/lib/module/skia/web/JsiSkSurfaceFactory.js +2 -17
  106. package/lib/module/skia/web/JsiSkSurfaceFactory.js.map +1 -1
  107. package/lib/module/skia/web/JsiSkia.js +3 -1
  108. package/lib/module/skia/web/JsiSkia.js.map +1 -1
  109. package/lib/module/views/SkiaDomView.d.ts +6 -0
  110. package/lib/module/views/SkiaDomView.js +10 -0
  111. package/lib/module/views/SkiaDomView.js.map +1 -1
  112. package/lib/module/views/types.d.ts +1 -0
  113. package/lib/module/views/types.js.map +1 -1
  114. package/lib/typescript/src/external/reanimated/useAnimatedImageValue.d.ts +2 -1
  115. package/lib/typescript/src/renderer/Offscreen.d.ts +2 -2
  116. package/lib/typescript/src/skia/types/Image/ImageFactory.d.ts +14 -0
  117. package/lib/typescript/src/skia/types/PlatformBuffer/PlatformBufferFactory.d.ts +12 -0
  118. package/lib/typescript/src/skia/types/PlatformBuffer/index.d.ts +1 -0
  119. package/lib/typescript/src/skia/types/Skia.d.ts +2 -0
  120. package/lib/typescript/src/skia/types/Surface/Surface.d.ts +8 -0
  121. package/lib/typescript/src/skia/types/index.d.ts +1 -0
  122. package/lib/typescript/src/skia/web/JsiSkImage.d.ts +1 -2
  123. package/lib/typescript/src/skia/web/JsiSkImageFactory.d.ts +2 -2
  124. package/lib/typescript/src/skia/web/JsiSkPlatformBufferFactory.d.ts +8 -0
  125. package/lib/typescript/src/skia/web/JsiSkSurface.d.ts +3 -2
  126. package/lib/typescript/src/skia/web/JsiSkSurfaceFactory.d.ts +1 -1
  127. package/lib/typescript/src/views/SkiaDomView.d.ts +6 -0
  128. package/lib/typescript/src/views/types.d.ts +1 -0
  129. package/package.json +1 -1
  130. package/src/external/reanimated/textures.tsx +8 -2
  131. package/src/external/reanimated/useAnimatedImageValue.ts +12 -6
  132. package/src/mock/index.ts +1 -0
  133. package/src/renderer/Offscreen.tsx +3 -3
  134. package/src/skia/types/Image/ImageFactory.ts +15 -0
  135. package/src/skia/types/PlatformBuffer/PlatformBufferFactory.ts +14 -0
  136. package/src/skia/types/PlatformBuffer/index.ts +1 -0
  137. package/src/skia/types/Skia.ts +2 -1
  138. package/src/skia/types/Surface/Surface.ts +10 -0
  139. package/src/skia/types/index.ts +1 -0
  140. package/src/skia/web/JsiSkImage.ts +5 -22
  141. package/src/skia/web/JsiSkImageFactory.ts +13 -2
  142. package/src/skia/web/JsiSkPlatformBufferFactory.ts +22 -0
  143. package/src/skia/web/JsiSkSurface.ts +10 -9
  144. package/src/skia/web/JsiSkSurfaceFactory.ts +4 -20
  145. package/src/skia/web/JsiSkia.ts +2 -0
  146. package/src/views/SkiaDomView.tsx +10 -0
  147. package/src/views/types.ts +1 -0
  148. package/cpp/skia/include/third_party/vulkan/LICENSE +0 -29
  149. package/cpp/skia/modules/skcms/README.chromium +0 -6
  150. 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> makeImageFromPlatformBuffer(void *buffer) override {
57
+ return SkiaOpenGLSurfaceFactory::makeImageFromHardwareBuffer(buffer);
58
+ }
59
+
60
+ void releasePlatformBuffer(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 makePlatformBuffer(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,51 @@
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 JsiPlatformBufferFactory : public JsiSkHostObject {
19
+ public:
20
+ JSI_HOST_FUNCTION(MakeFromImage) {
21
+ auto image = JsiSkImage::fromValue(runtime, arguments[0]);
22
+ image->makeNonTextureImage();
23
+
24
+ uint64_t pointer = getContext()->makePlatformBuffer(image);
25
+ jsi::HostFunctionType deleteFunc =
26
+ [=](jsi::Runtime &runtime, const jsi::Value &thisArg,
27
+ const jsi::Value *args, size_t count) -> jsi::Value {
28
+ getContext()->releasePlatformBuffer(pointer);
29
+ return jsi::Value::undefined();
30
+ };
31
+ return jsi::BigInt::fromUint64(runtime, pointer);
32
+ }
33
+
34
+ JSI_HOST_FUNCTION(Release) {
35
+
36
+ jsi::BigInt pointer = arguments[0].asBigInt(runtime);
37
+ const uintptr_t platformBufferPointer = pointer.asUint64(runtime);
38
+
39
+ getContext()->releasePlatformBuffer(platformBufferPointer);
40
+ return jsi::Value::undefined();
41
+ }
42
+
43
+ JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiPlatformBufferFactory, Release),
44
+ JSI_EXPORT_FUNC(JsiPlatformBufferFactory, MakeFromImage))
45
+
46
+ explicit JsiPlatformBufferFactory(
47
+ std::shared_ptr<RNSkPlatformContext> context)
48
+ : JsiSkHostObject(std::move(context)) {}
49
+ };
50
+
51
+ } // namespace RNSkia
@@ -6,6 +6,7 @@
6
6
 
7
7
  #include "JsiSkHostObjects.h"
8
8
 
9
+ #include "JsiPlatformBuffer.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(
128
+ "PlatformBuffer", std::make_shared<JsiPlatformBufferFactory>(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(MakeImageFromPlatformBuffer) {
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()->makeImageFromPlatformBuffer(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]);
@@ -47,7 +59,6 @@ public:
47
59
  [context = std::move(context), viewTag](
48
60
  jsi::Runtime &runtime,
49
61
  std::shared_ptr<RNJsi::JsiPromises::Promise> promise) -> void {
50
- // Create a stream operation - this will be run on the main thread
51
62
  context->makeViewScreenshot(
52
63
  viewTag, [&runtime, context = std::move(context),
53
64
  promise = std::move(promise)](sk_sp<SkImage> image) {
@@ -69,7 +80,9 @@ public:
69
80
 
70
81
  JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkImageFactory, MakeImageFromEncoded),
71
82
  JSI_EXPORT_FUNC(JsiSkImageFactory, MakeImageFromViewTag),
72
- JSI_EXPORT_FUNC(JsiSkImageFactory, MakeImage), )
83
+ JSI_EXPORT_FUNC(JsiSkImageFactory,
84
+ MakeImageFromPlatformBuffer),
85
+ JSI_EXPORT_FUNC(JsiSkImageFactory, MakeImage))
73
86
 
74
87
  explicit JsiSkImageFactory(std::shared_ptr<RNSkPlatformContext> context)
75
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))
@@ -5,6 +5,7 @@
5
5
  #include <mutex>
6
6
  #include <string>
7
7
  #include <unordered_map>
8
+ #include <utility>
8
9
  #include <vector>
9
10
 
10
11
  #include "JsiHostObject.h"
@@ -177,9 +178,56 @@ public:
177
178
  return jsi::Value::undefined();
178
179
  }
179
180
 
181
+ JSI_HOST_FUNCTION(makeImageSnapshotAsync) {
182
+ if (count < 1) {
183
+ _platformContext->raiseError(std::string(
184
+ "makeImageSnapshotAsync: Expected at least 1 argument, got " +
185
+ std::to_string(count) + "."));
186
+ return jsi::Value::undefined();
187
+ }
188
+
189
+ if (!arguments[0].isNumber()) {
190
+ _platformContext->raiseError(
191
+ "makeImageSnapshot: First argument must be a number");
192
+ return jsi::Value::undefined();
193
+ }
194
+
195
+ // find Skia view
196
+ int nativeId = arguments[0].asNumber();
197
+ auto info = getEnsuredViewInfo(nativeId);
198
+ auto context = _platformContext;
199
+ auto bounds =
200
+ count > 1 && !arguments[1].isUndefined() && !arguments[1].isNull()
201
+ ? JsiSkRect::fromValue(runtime, arguments[1])
202
+ : nullptr;
203
+ return RNJsi::JsiPromises::createPromiseAsJSIValue(
204
+ runtime, [context = std::move(context), info, bounds](
205
+ jsi::Runtime &runtime,
206
+ std::shared_ptr<RNJsi::JsiPromises::Promise> promise) {
207
+ context->runOnMainThread([&runtime, info = std::move(info),
208
+ promise = std::move(promise),
209
+ context = std::move(context), bounds]() {
210
+ auto image = info->view->makeImageSnapshot(
211
+ bounds == nullptr ? nullptr : bounds.get());
212
+ context->runOnJavascriptThread(
213
+ [&runtime, context = std::move(context),
214
+ promise = std::move(promise), image = std::move(image)]() {
215
+ if (image == nullptr) {
216
+ promise->reject("Failed to make snapshot from view.");
217
+ return;
218
+ }
219
+ promise->resolve(jsi::Object::createFromHostObject(
220
+ runtime, std::make_shared<JsiSkImage>(std::move(context),
221
+ std::move(image))));
222
+ });
223
+ });
224
+ });
225
+ }
226
+
180
227
  JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(RNSkJsiViewApi, setJsiProperty),
181
228
  JSI_EXPORT_FUNC(RNSkJsiViewApi, callJsiMethod),
182
229
  JSI_EXPORT_FUNC(RNSkJsiViewApi, requestRedraw),
230
+ JSI_EXPORT_FUNC(RNSkJsiViewApi, makeImageSnapshotAsync),
183
231
  JSI_EXPORT_FUNC(RNSkJsiViewApi, makeImageSnapshot))
184
232
 
185
233
  /**
@@ -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 platform buffer.
138
+ * - On iOS, this is a `CMSampleBuffer`
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> makeImageFromPlatformBuffer(void *buffer) = 0;
144
+
145
+ virtual void releasePlatformBuffer(uint64_t pointer) = 0;
146
+
147
+ virtual uint64_t makePlatformBuffer(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> makeImageFromPlatformBuffer(void *buffer) override;
63
+
64
+ uint64_t makePlatformBuffer(sk_sp<SkImage> image) override;
65
+
66
+ void releasePlatformBuffer(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,5 +1,6 @@
1
1
  #include "RNSkiOSPlatformContext.h"
2
2
 
3
+ #import <CoreMedia/CMSampleBuffer.h>
3
4
  #import <React/RCTUtils.h>
4
5
  #include <thread>
5
6
  #include <utility>
@@ -56,6 +57,89 @@ void RNSkiOSPlatformContext::performStreamOperation(
56
57
  std::thread(loader).detach();
57
58
  }
58
59
 
60
+ void RNSkiOSPlatformContext::releasePlatformBuffer(uint64_t pointer) {
61
+ CMSampleBufferRef sampleBuffer = reinterpret_cast<CMSampleBufferRef>(pointer);
62
+ CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
63
+ if (sampleBuffer) {
64
+ CFRelease(sampleBuffer);
65
+ }
66
+ if (pixelBuffer) {
67
+ CFRelease(pixelBuffer);
68
+ }
69
+ }
70
+
71
+ uint64_t RNSkiOSPlatformContext::makePlatformBuffer(sk_sp<SkImage> image) {
72
+ auto bytesPerPixel = image->imageInfo().bytesPerPixel();
73
+ int bytesPerRow = image->width() * bytesPerPixel;
74
+ auto buf = SkData::MakeUninitialized(image->width() * image->height() *
75
+ bytesPerPixel);
76
+ SkImageInfo info = SkImageInfo::Make(image->width(), image->height(),
77
+ image->colorType(), image->alphaType());
78
+ image->readPixels(nullptr, info, const_cast<void *>(buf->data()), bytesPerRow,
79
+ 0, 0);
80
+ auto pixelData = const_cast<void *>(buf->data());
81
+
82
+ // Create a CVPixelBuffer from the raw pixel data
83
+ CVPixelBufferRef pixelBuffer = nullptr;
84
+ // OSType pixelFormatType = MapSkColorTypeToOSType(image->colorType());
85
+
86
+ // You will need to fill in the details for creating the pixel buffer
87
+ // CVPixelBufferCreateWithBytes or CVPixelBufferCreateWithPlanarBytes
88
+ // Create the CVPixelBuffer with the image data
89
+ void *context = static_cast<void *>(
90
+ new sk_sp<SkData>(buf)); // Create a copy for the context
91
+ CVReturn r = CVPixelBufferCreateWithBytes(
92
+ nullptr, // allocator
93
+ image->width(), image->height(), kCVPixelFormatType_32BGRA,
94
+ pixelData, // pixel data
95
+ bytesPerRow, // bytes per row
96
+ [](void *releaseRefCon, const void *baseAddress) { // release callback
97
+ auto buf = static_cast<sk_sp<SkData> *>(releaseRefCon);
98
+ buf->reset(); // This effectively calls unref on the SkData object
99
+ delete buf; // Cleanup the dynamically allocated context
100
+ },
101
+ context, // release callback context
102
+ nullptr, // pixel buffer attributes
103
+ &pixelBuffer // the newly created pixel buffer
104
+ );
105
+
106
+ if (r != kCVReturnSuccess) {
107
+ return 0; // or handle error appropriately
108
+ }
109
+
110
+ // Wrap the CVPixelBuffer in a CMSampleBuffer
111
+ CMSampleBufferRef sampleBuffer = nullptr;
112
+
113
+ CMFormatDescriptionRef formatDescription = nullptr;
114
+ CMVideoFormatDescriptionCreateForImageBuffer(kCFAllocatorDefault, pixelBuffer,
115
+ &formatDescription);
116
+
117
+ // Assuming no specific timing is required, we initialize the timing info to
118
+ // zero.
119
+ CMSampleTimingInfo timingInfo = {0};
120
+ timingInfo.duration = kCMTimeInvalid; // Indicate an unknown duration.
121
+ timingInfo.presentationTimeStamp = kCMTimeZero; // Start at time zero.
122
+ timingInfo.decodeTimeStamp = kCMTimeInvalid; // No specific decode time.
123
+
124
+ // Create the sample buffer.
125
+ OSStatus status = CMSampleBufferCreateReadyWithImageBuffer(
126
+ kCFAllocatorDefault, pixelBuffer, formatDescription, &timingInfo,
127
+ &sampleBuffer);
128
+
129
+ if (status != noErr) {
130
+ if (formatDescription) {
131
+ CFRelease(formatDescription);
132
+ }
133
+ if (pixelBuffer) {
134
+ CFRelease(pixelBuffer);
135
+ }
136
+ return 0;
137
+ }
138
+
139
+ // Return sampleBuffer casted to uint64_t
140
+ return reinterpret_cast<uint64_t>(sampleBuffer);
141
+ }
142
+
59
143
  void RNSkiOSPlatformContext::raiseError(const std::exception &err) {
60
144
  RCTFatal(RCTErrorWithMessage([NSString stringWithUTF8String:err.what()]));
61
145
  }
@@ -65,6 +149,37 @@ sk_sp<SkSurface> RNSkiOSPlatformContext::makeOffscreenSurface(int width,
65
149
  return SkiaMetalSurfaceFactory::makeOffscreenSurface(width, height);
66
150
  }
67
151
 
152
+ sk_sp<SkImage>
153
+ RNSkiOSPlatformContext::makeImageFromPlatformBuffer(void *buffer) {
154
+ CMSampleBufferRef sampleBuffer = (CMSampleBufferRef)buffer;
155
+ // DO the CPU transfer (debugging only)
156
+ // Step 1: Extract the CVPixelBufferRef from the CMSampleBufferRef
157
+ CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
158
+
159
+ // Step 2: Lock the pixel buffer to access the raw pixel data
160
+ CVPixelBufferLockBaseAddress(pixelBuffer, 0);
161
+
162
+ // Step 3: Get information about the image
163
+ void *baseAddress = CVPixelBufferGetBaseAddress(pixelBuffer);
164
+ size_t width = CVPixelBufferGetWidth(pixelBuffer);
165
+ size_t height = CVPixelBufferGetHeight(pixelBuffer);
166
+ size_t bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer);
167
+
168
+ // Assuming the pixel format is 32BGRA, which is common for iOS video frames.
169
+ // You might need to adjust this based on the actual pixel format.
170
+ SkImageInfo info = SkImageInfo::Make(width, height, kRGBA_8888_SkColorType,
171
+ kUnpremul_SkAlphaType);
172
+
173
+ // Step 4: Create an SkImage from the pixel buffer
174
+ sk_sp<SkData> data =
175
+ SkData::MakeWithoutCopy(baseAddress, height * bytesPerRow);
176
+ sk_sp<SkImage> image = SkImages::RasterFromData(info, data, bytesPerRow);
177
+ auto texture = SkiaMetalSurfaceFactory::makeTextureFromImage(image);
178
+ // Step 5: Unlock the pixel buffer
179
+ CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
180
+ return texture;
181
+ }
182
+
68
183
  sk_sp<SkFontMgr> RNSkiOSPlatformContext::createFontMgr() {
69
184
  return SkFontMgr_New_CoreText(nullptr);
70
185
  }
@@ -4,6 +4,8 @@
4
4
  #pragma clang diagnostic ignored "-Wdocumentation"
5
5
 
6
6
  #import "include/core/SkCanvas.h"
7
+ #import <CoreMedia/CMSampleBuffer.h>
8
+ #import <CoreVideo/CVMetalTextureCache.h>
7
9
  #import <include/gpu/GrDirectContext.h>
8
10
 
9
11
  #pragma clang diagnostic pop
@@ -24,6 +26,8 @@ public:
24
26
  int height);
25
27
  static sk_sp<SkSurface> makeOffscreenSurface(int width, int height);
26
28
 
29
+ static sk_sp<SkImage> makeTextureFromImage(sk_sp<SkImage> image);
30
+
27
31
  private:
28
32
  static id<MTLDevice> device;
29
33
  static bool
@@ -11,7 +11,9 @@
11
11
 
12
12
  #import <include/gpu/GrBackendSurface.h>
13
13
  #import <include/gpu/GrDirectContext.h>
14
+ #import <include/gpu/ganesh/SkImageGanesh.h>
14
15
  #import <include/gpu/ganesh/SkSurfaceGanesh.h>
16
+ #import <include/gpu/ganesh/mtl/SkSurfaceMetal.h>
15
17
 
16
18
  #pragma clang diagnostic pop
17
19
 
@@ -103,3 +105,13 @@ sk_sp<SkSurface> SkiaMetalSurfaceFactory::makeOffscreenSurface(int width,
103
105
 
104
106
  return surface;
105
107
  }
108
+
109
+ sk_sp<SkImage>
110
+ SkiaMetalSurfaceFactory::makeTextureFromImage(sk_sp<SkImage> image) {
111
+ if (!SkiaMetalSurfaceFactory::createSkiaDirectContextIfNecessary(
112
+ &ThreadContextHolder::ThreadSkiaMetalContext)) {
113
+ throw std::runtime_error("Failed to create Skia Context for this Thread!");
114
+ }
115
+ return SkImages::TextureFromImage(
116
+ ThreadContextHolder::ThreadSkiaMetalContext.skContext.get(), image);
117
+ }