@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.
- package/android/CMakeLists.txt +1 -0
- package/android/build.gradle +1 -0
- package/android/cpp/rnskia-android/AHardwareBufferUtils.cpp +31 -0
- package/android/cpp/rnskia-android/AHardwareBufferUtils.h +13 -0
- package/android/cpp/rnskia-android/RNSkAndroidPlatformContext.h +75 -0
- package/android/cpp/rnskia-android/SkiaOpenGLSurfaceFactory.cpp +29 -11
- package/android/cpp/rnskia-android/SkiaOpenGLSurfaceFactory.h +1 -2
- package/android/src/main/java/com/shopify/reactnative/skia/ViewScreenshotService.java +3 -2
- package/cpp/api/JsiNativeBuffer.h +43 -0
- package/cpp/api/JsiSkApi.h +4 -0
- package/cpp/api/JsiSkImage.h +1 -1
- package/cpp/api/JsiSkImageFactory.h +15 -1
- package/cpp/api/JsiSkSurface.h +9 -1
- package/cpp/rnskia/RNSkPlatformContext.h +13 -0
- package/ios/RNSkia-iOS/RNSkiOSPlatformContext.h +6 -0
- package/ios/RNSkia-iOS/RNSkiOSPlatformContext.mm +98 -2
- package/ios/RNSkia-iOS/SkiaCVPixelBufferUtils.h +84 -0
- package/ios/RNSkia-iOS/SkiaCVPixelBufferUtils.mm +159 -0
- package/ios/RNSkia-iOS/SkiaMetalSurfaceFactory.h +5 -0
- package/ios/RNSkia-iOS/SkiaMetalSurfaceFactory.mm +37 -1
- package/lib/commonjs/external/reanimated/textures.js +11 -2
- package/lib/commonjs/external/reanimated/textures.js.map +1 -1
- package/lib/commonjs/external/reanimated/useAnimatedImageValue.d.ts +2 -1
- package/lib/commonjs/external/reanimated/useAnimatedImageValue.js +8 -4
- package/lib/commonjs/external/reanimated/useAnimatedImageValue.js.map +1 -1
- package/lib/commonjs/renderer/Offscreen.d.ts +2 -2
- package/lib/commonjs/renderer/Offscreen.js +2 -2
- package/lib/commonjs/renderer/Offscreen.js.map +1 -1
- package/lib/commonjs/skia/types/Image/ImageFactory.d.ts +17 -10
- package/lib/commonjs/skia/types/Image/ImageFactory.js +1 -10
- package/lib/commonjs/skia/types/Image/ImageFactory.js.map +1 -1
- package/lib/commonjs/skia/types/NativeBuffer/NativeBufferFactory.d.ts +18 -0
- package/lib/commonjs/skia/types/NativeBuffer/NativeBufferFactory.js +13 -0
- package/lib/commonjs/skia/types/NativeBuffer/NativeBufferFactory.js.map +1 -0
- package/lib/commonjs/skia/types/NativeBuffer/index.d.ts +1 -0
- package/lib/commonjs/skia/types/NativeBuffer/index.js +17 -0
- package/lib/commonjs/skia/types/NativeBuffer/index.js.map +1 -0
- package/lib/commonjs/skia/types/Skia.d.ts +2 -0
- package/lib/commonjs/skia/types/Skia.js.map +1 -1
- package/lib/commonjs/skia/types/Surface/Surface.d.ts +8 -0
- package/lib/commonjs/skia/types/Surface/Surface.js.map +1 -1
- package/lib/commonjs/skia/types/index.d.ts +1 -0
- package/lib/commonjs/skia/types/index.js +11 -0
- package/lib/commonjs/skia/types/index.js.map +1 -1
- package/lib/commonjs/skia/web/JsiSkImage.d.ts +1 -2
- package/lib/commonjs/skia/web/JsiSkImage.js +5 -12
- package/lib/commonjs/skia/web/JsiSkImage.js.map +1 -1
- package/lib/commonjs/skia/web/JsiSkImageFactory.d.ts +3 -2
- package/lib/commonjs/skia/web/JsiSkImageFactory.js +19 -0
- package/lib/commonjs/skia/web/JsiSkImageFactory.js.map +1 -1
- package/lib/commonjs/skia/web/JsiSkNativeBufferFactory.d.ts +8 -0
- package/lib/commonjs/skia/web/JsiSkNativeBufferFactory.js +29 -0
- package/lib/commonjs/skia/web/JsiSkNativeBufferFactory.js.map +1 -0
- package/lib/commonjs/skia/web/JsiSkSurface.d.ts +3 -2
- package/lib/commonjs/skia/web/JsiSkSurface.js +8 -6
- package/lib/commonjs/skia/web/JsiSkSurface.js.map +1 -1
- package/lib/commonjs/skia/web/JsiSkSurfaceFactory.d.ts +1 -1
- package/lib/commonjs/skia/web/JsiSkSurfaceFactory.js +1 -16
- package/lib/commonjs/skia/web/JsiSkSurfaceFactory.js.map +1 -1
- package/lib/commonjs/skia/web/JsiSkia.js +3 -1
- package/lib/commonjs/skia/web/JsiSkia.js.map +1 -1
- package/lib/module/external/reanimated/textures.js +11 -2
- package/lib/module/external/reanimated/textures.js.map +1 -1
- package/lib/module/external/reanimated/useAnimatedImageValue.d.ts +2 -1
- package/lib/module/external/reanimated/useAnimatedImageValue.js +8 -4
- package/lib/module/external/reanimated/useAnimatedImageValue.js.map +1 -1
- package/lib/module/renderer/Offscreen.d.ts +2 -2
- package/lib/module/renderer/Offscreen.js +2 -2
- package/lib/module/renderer/Offscreen.js.map +1 -1
- package/lib/module/skia/types/Image/ImageFactory.d.ts +17 -10
- package/lib/module/skia/types/Image/ImageFactory.js +1 -10
- package/lib/module/skia/types/Image/ImageFactory.js.map +1 -1
- package/lib/module/skia/types/NativeBuffer/NativeBufferFactory.d.ts +18 -0
- package/lib/module/skia/types/NativeBuffer/NativeBufferFactory.js +4 -0
- package/lib/module/skia/types/NativeBuffer/NativeBufferFactory.js.map +1 -0
- package/lib/module/skia/types/NativeBuffer/index.d.ts +1 -0
- package/lib/module/skia/types/NativeBuffer/index.js +2 -0
- package/lib/module/skia/types/NativeBuffer/index.js.map +1 -0
- package/lib/module/skia/types/Skia.d.ts +2 -0
- package/lib/module/skia/types/Skia.js.map +1 -1
- package/lib/module/skia/types/Surface/Surface.d.ts +8 -0
- package/lib/module/skia/types/Surface/Surface.js.map +1 -1
- package/lib/module/skia/types/index.d.ts +1 -0
- package/lib/module/skia/types/index.js +1 -0
- package/lib/module/skia/types/index.js.map +1 -1
- package/lib/module/skia/web/JsiSkImage.d.ts +1 -2
- package/lib/module/skia/web/JsiSkImage.js +5 -12
- package/lib/module/skia/web/JsiSkImage.js.map +1 -1
- package/lib/module/skia/web/JsiSkImageFactory.d.ts +3 -2
- package/lib/module/skia/web/JsiSkImageFactory.js +19 -0
- package/lib/module/skia/web/JsiSkImageFactory.js.map +1 -1
- package/lib/module/skia/web/JsiSkNativeBufferFactory.d.ts +8 -0
- package/lib/module/skia/web/JsiSkNativeBufferFactory.js +22 -0
- package/lib/module/skia/web/JsiSkNativeBufferFactory.js.map +1 -0
- package/lib/module/skia/web/JsiSkSurface.d.ts +3 -2
- package/lib/module/skia/web/JsiSkSurface.js +8 -6
- package/lib/module/skia/web/JsiSkSurface.js.map +1 -1
- package/lib/module/skia/web/JsiSkSurfaceFactory.d.ts +1 -1
- package/lib/module/skia/web/JsiSkSurfaceFactory.js +1 -16
- package/lib/module/skia/web/JsiSkSurfaceFactory.js.map +1 -1
- package/lib/module/skia/web/JsiSkia.js +3 -1
- package/lib/module/skia/web/JsiSkia.js.map +1 -1
- package/lib/typescript/src/external/reanimated/useAnimatedImageValue.d.ts +2 -1
- package/lib/typescript/src/renderer/Offscreen.d.ts +2 -2
- package/lib/typescript/src/skia/types/Image/ImageFactory.d.ts +17 -10
- package/lib/typescript/src/skia/types/NativeBuffer/NativeBufferFactory.d.ts +18 -0
- package/lib/typescript/src/skia/types/NativeBuffer/index.d.ts +1 -0
- package/lib/typescript/src/skia/types/Skia.d.ts +2 -0
- package/lib/typescript/src/skia/types/Surface/Surface.d.ts +8 -0
- package/lib/typescript/src/skia/types/index.d.ts +1 -0
- package/lib/typescript/src/skia/web/JsiSkImage.d.ts +1 -2
- package/lib/typescript/src/skia/web/JsiSkImageFactory.d.ts +3 -2
- package/lib/typescript/src/skia/web/JsiSkNativeBufferFactory.d.ts +8 -0
- package/lib/typescript/src/skia/web/JsiSkSurface.d.ts +3 -2
- package/lib/typescript/src/skia/web/JsiSkSurfaceFactory.d.ts +1 -1
- package/package.json +1 -1
- package/src/external/reanimated/textures.tsx +8 -2
- package/src/external/reanimated/useAnimatedImageValue.ts +12 -6
- package/src/renderer/Offscreen.tsx +3 -3
- package/src/skia/types/Image/ImageFactory.ts +17 -18
- package/src/skia/types/NativeBuffer/NativeBufferFactory.ts +38 -0
- package/src/skia/types/NativeBuffer/index.ts +1 -0
- package/src/skia/types/Skia.ts +2 -1
- package/src/skia/types/Surface/Surface.ts +10 -0
- package/src/skia/types/index.ts +1 -0
- package/src/skia/web/JsiSkImage.ts +5 -22
- package/src/skia/web/JsiSkImageFactory.ts +36 -3
- package/src/skia/web/JsiSkNativeBufferFactory.ts +35 -0
- package/src/skia/web/JsiSkSurface.ts +10 -9
- package/src/skia/web/JsiSkSurfaceFactory.ts +3 -19
- package/src/skia/web/JsiSkia.ts +2 -0
- package/cpp/skia/include/third_party/vulkan/LICENSE +0 -29
- package/cpp/skia/modules/skcms/README.chromium +0 -6
- package/cpp/skia/readme.txt +0 -1
package/android/CMakeLists.txt
CHANGED
@@ -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"
|
package/android/build.gradle
CHANGED
@@ -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
|
@@ -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(
|
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),
|
29
|
-
|
30
|
-
|
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
|
-
|
54
|
+
kOpaque_SkAlphaType, nullptr);
|
37
55
|
return image;
|
38
56
|
#else
|
39
|
-
|
40
|
-
"
|
41
|
-
|
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(
|
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.
|
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
|
-
|
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
|
package/cpp/api/JsiSkApi.h
CHANGED
@@ -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
|
package/cpp/api/JsiSkImage.h
CHANGED
@@ -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,
|
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)) {}
|
package/cpp/api/JsiSkSurface.h
CHANGED
@@ -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,
|
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
|
-
#
|
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
|
-
#
|
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
|
+
};
|