@shopify/react-native-skia 1.2.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/cpp/rnskia-android/RNSkAndroidPlatformContext.h +3 -3
- package/cpp/api/JsiNativeBuffer.h +43 -0
- package/cpp/api/JsiSkApi.h +3 -3
- package/cpp/api/JsiSkImageFactory.h +3 -3
- package/cpp/rnskia/RNSkPlatformContext.h +5 -5
- package/ios/RNSkia-iOS/RNSkiOSPlatformContext.h +3 -3
- package/ios/RNSkia-iOS/RNSkiOSPlatformContext.mm +69 -88
- package/ios/RNSkia-iOS/SkiaCVPixelBufferUtils.h +84 -0
- package/ios/RNSkia-iOS/SkiaCVPixelBufferUtils.mm +159 -0
- package/ios/RNSkia-iOS/SkiaMetalSurfaceFactory.h +2 -1
- package/ios/RNSkia-iOS/SkiaMetalSurfaceFactory.mm +30 -6
- package/lib/commonjs/skia/types/Image/ImageFactory.d.ts +8 -15
- 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 -2
- package/lib/commonjs/skia/types/Skia.js.map +1 -1
- package/lib/commonjs/skia/types/index.d.ts +1 -1
- package/lib/commonjs/skia/types/index.js +4 -4
- package/lib/commonjs/skia/types/index.js.map +1 -1
- package/lib/commonjs/skia/web/JsiSkImageFactory.d.ts +3 -2
- package/lib/commonjs/skia/web/JsiSkImageFactory.js +18 -2
- 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/JsiSkia.js +2 -2
- package/lib/commonjs/skia/web/JsiSkia.js.map +1 -1
- package/lib/module/skia/types/Image/ImageFactory.d.ts +8 -15
- 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 -2
- package/lib/module/skia/types/Skia.js.map +1 -1
- package/lib/module/skia/types/index.d.ts +1 -1
- package/lib/module/skia/types/index.js +1 -1
- package/lib/module/skia/types/index.js.map +1 -1
- package/lib/module/skia/web/JsiSkImageFactory.d.ts +3 -2
- package/lib/module/skia/web/JsiSkImageFactory.js +18 -2
- 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/JsiSkia.js +2 -2
- package/lib/module/skia/web/JsiSkia.js.map +1 -1
- package/lib/typescript/src/skia/types/Image/ImageFactory.d.ts +8 -15
- 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 -2
- package/lib/typescript/src/skia/types/index.d.ts +1 -1
- package/lib/typescript/src/skia/web/JsiSkImageFactory.d.ts +3 -2
- package/lib/typescript/src/skia/web/JsiSkNativeBufferFactory.d.ts +8 -0
- package/package.json +1 -1
- package/src/skia/types/Image/ImageFactory.ts +7 -23
- 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 -2
- package/src/skia/types/index.ts +1 -1
- package/src/skia/web/JsiSkImageFactory.ts +28 -6
- package/src/skia/web/JsiSkNativeBufferFactory.ts +35 -0
- package/src/skia/web/JsiSkia.ts +2 -2
- package/cpp/api/JsiPlatformBuffer.h +0 -51
- package/lib/commonjs/skia/types/PlatformBuffer/PlatformBufferFactory.d.ts +0 -12
- package/lib/commonjs/skia/types/PlatformBuffer/PlatformBufferFactory.js +0 -6
- package/lib/commonjs/skia/types/PlatformBuffer/PlatformBufferFactory.js.map +0 -1
- package/lib/commonjs/skia/types/PlatformBuffer/index.d.ts +0 -1
- package/lib/commonjs/skia/types/PlatformBuffer/index.js +0 -17
- package/lib/commonjs/skia/types/PlatformBuffer/index.js.map +0 -1
- package/lib/commonjs/skia/web/JsiSkPlatformBufferFactory.d.ts +0 -8
- package/lib/commonjs/skia/web/JsiSkPlatformBufferFactory.js +0 -20
- package/lib/commonjs/skia/web/JsiSkPlatformBufferFactory.js.map +0 -1
- package/lib/module/skia/types/PlatformBuffer/PlatformBufferFactory.d.ts +0 -12
- package/lib/module/skia/types/PlatformBuffer/PlatformBufferFactory.js +0 -2
- package/lib/module/skia/types/PlatformBuffer/PlatformBufferFactory.js.map +0 -1
- package/lib/module/skia/types/PlatformBuffer/index.d.ts +0 -1
- package/lib/module/skia/types/PlatformBuffer/index.js +0 -2
- package/lib/module/skia/types/PlatformBuffer/index.js.map +0 -1
- package/lib/module/skia/web/JsiSkPlatformBufferFactory.d.ts +0 -8
- package/lib/module/skia/web/JsiSkPlatformBufferFactory.js +0 -13
- package/lib/module/skia/web/JsiSkPlatformBufferFactory.js.map +0 -1
- package/lib/typescript/src/skia/types/PlatformBuffer/PlatformBufferFactory.d.ts +0 -12
- package/lib/typescript/src/skia/types/PlatformBuffer/index.d.ts +0 -1
- package/lib/typescript/src/skia/web/JsiSkPlatformBufferFactory.d.ts +0 -8
- package/src/skia/types/PlatformBuffer/PlatformBufferFactory.ts +0 -14
- package/src/skia/types/PlatformBuffer/index.ts +0 -1
- package/src/skia/web/JsiSkPlatformBufferFactory.ts +0 -22
|
@@ -53,18 +53,18 @@ public:
|
|
|
53
53
|
return SkiaOpenGLSurfaceFactory::makeOffscreenSurface(width, height);
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
sk_sp<SkImage>
|
|
56
|
+
sk_sp<SkImage> makeImageFromNativeBuffer(void *buffer) override {
|
|
57
57
|
return SkiaOpenGLSurfaceFactory::makeImageFromHardwareBuffer(buffer);
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
void
|
|
60
|
+
void releaseNativeBuffer(uint64_t pointer) override {
|
|
61
61
|
#if __ANDROID_API__ >= 26
|
|
62
62
|
AHardwareBuffer *buffer = reinterpret_cast<AHardwareBuffer *>(pointer);
|
|
63
63
|
AHardwareBuffer_release(buffer);
|
|
64
64
|
#endif
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
uint64_t
|
|
67
|
+
uint64_t makeNativeBuffer(sk_sp<SkImage> image) override {
|
|
68
68
|
#if __ANDROID_API__ >= 26
|
|
69
69
|
auto bytesPerPixel = image->imageInfo().bytesPerPixel();
|
|
70
70
|
int bytesPerRow = image->width() * bytesPerPixel;
|
|
@@ -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,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
#include "JsiSkHostObjects.h"
|
|
8
8
|
|
|
9
|
-
#include "
|
|
9
|
+
#include "JsiNativeBuffer.h"
|
|
10
10
|
#include "JsiSkAnimatedImage.h"
|
|
11
11
|
#include "JsiSkAnimatedImageFactory.h"
|
|
12
12
|
#include "JsiSkColor.h"
|
|
@@ -124,8 +124,8 @@ public:
|
|
|
124
124
|
"ParagraphBuilder",
|
|
125
125
|
std::make_shared<JsiSkParagraphBuilderFactory>(context));
|
|
126
126
|
|
|
127
|
-
installReadonlyProperty(
|
|
128
|
-
|
|
127
|
+
installReadonlyProperty("NativeBuffer",
|
|
128
|
+
std::make_shared<JsiNativeBufferFactory>(context));
|
|
129
129
|
}
|
|
130
130
|
};
|
|
131
131
|
} // namespace RNSkia
|
|
@@ -27,11 +27,11 @@ public:
|
|
|
27
27
|
runtime, std::make_shared<JsiSkImage>(getContext(), std::move(image)));
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
JSI_HOST_FUNCTION(
|
|
30
|
+
JSI_HOST_FUNCTION(MakeImageFromNativeBuffer) {
|
|
31
31
|
jsi::BigInt pointer = arguments[0].asBigInt(runtime);
|
|
32
32
|
const uintptr_t platformBufferPointer = pointer.asUint64(runtime);
|
|
33
33
|
void *rawPointer = reinterpret_cast<void *>(platformBufferPointer);
|
|
34
|
-
auto image = getContext()->
|
|
34
|
+
auto image = getContext()->makeImageFromNativeBuffer(rawPointer);
|
|
35
35
|
if (image == nullptr) {
|
|
36
36
|
throw std::runtime_error("Failed to convert PlatformBuffer to SkImage!");
|
|
37
37
|
}
|
|
@@ -81,7 +81,7 @@ public:
|
|
|
81
81
|
JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkImageFactory, MakeImageFromEncoded),
|
|
82
82
|
JSI_EXPORT_FUNC(JsiSkImageFactory, MakeImageFromViewTag),
|
|
83
83
|
JSI_EXPORT_FUNC(JsiSkImageFactory,
|
|
84
|
-
|
|
84
|
+
MakeImageFromNativeBuffer),
|
|
85
85
|
JSI_EXPORT_FUNC(JsiSkImageFactory, MakeImage))
|
|
86
86
|
|
|
87
87
|
explicit JsiSkImageFactory(std::shared_ptr<RNSkPlatformContext> context)
|
|
@@ -134,17 +134,17 @@ public:
|
|
|
134
134
|
virtual sk_sp<SkSurface> makeOffscreenSurface(int width, int height) = 0;
|
|
135
135
|
|
|
136
136
|
/**
|
|
137
|
-
* Creates an image from a native
|
|
138
|
-
* - On iOS, this is a `
|
|
137
|
+
* Creates an image from a native buffer. (for testing purposes only)
|
|
138
|
+
* - On iOS, this is a `CVPixelBufferRef*`
|
|
139
139
|
* - On Android, this is a `AHardwareBuffer*`
|
|
140
140
|
* @param buffer The native platform buffer.
|
|
141
141
|
* @return sk_sp<SkImage>
|
|
142
142
|
*/
|
|
143
|
-
virtual sk_sp<SkImage>
|
|
143
|
+
virtual sk_sp<SkImage> makeImageFromNativeBuffer(void *buffer) = 0;
|
|
144
144
|
|
|
145
|
-
virtual void
|
|
145
|
+
virtual void releaseNativeBuffer(uint64_t pointer) = 0;
|
|
146
146
|
|
|
147
|
-
virtual uint64_t
|
|
147
|
+
virtual uint64_t makeNativeBuffer(sk_sp<SkImage> image) = 0;
|
|
148
148
|
|
|
149
149
|
/**
|
|
150
150
|
* Return the Platform specific font manager
|
|
@@ -59,11 +59,11 @@ public:
|
|
|
59
59
|
|
|
60
60
|
sk_sp<SkImage> takeScreenshotFromViewTag(size_t tag) override;
|
|
61
61
|
|
|
62
|
-
sk_sp<SkImage>
|
|
62
|
+
sk_sp<SkImage> makeImageFromNativeBuffer(void *buffer) override;
|
|
63
63
|
|
|
64
|
-
uint64_t
|
|
64
|
+
uint64_t makeNativeBuffer(sk_sp<SkImage> image) override;
|
|
65
65
|
|
|
66
|
-
void
|
|
66
|
+
void releaseNativeBuffer(uint64_t pointer) override;
|
|
67
67
|
|
|
68
68
|
virtual void performStreamOperation(
|
|
69
69
|
const std::string &sourceUri,
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
#
|
|
1
|
+
#import "RNSkiOSPlatformContext.h"
|
|
2
2
|
|
|
3
3
|
#import <CoreMedia/CMSampleBuffer.h>
|
|
4
4
|
#import <React/RCTUtils.h>
|
|
5
5
|
#include <thread>
|
|
6
6
|
#include <utility>
|
|
7
7
|
|
|
8
|
-
#
|
|
8
|
+
#import "SkiaCVPixelBufferUtils.h"
|
|
9
|
+
#import "SkiaMetalSurfaceFactory.h"
|
|
9
10
|
|
|
10
11
|
#pragma clang diagnostic push
|
|
11
12
|
#pragma clang diagnostic ignored "-Wdocumentation"
|
|
@@ -57,7 +58,7 @@ void RNSkiOSPlatformContext::performStreamOperation(
|
|
|
57
58
|
std::thread(loader).detach();
|
|
58
59
|
}
|
|
59
60
|
|
|
60
|
-
void RNSkiOSPlatformContext::
|
|
61
|
+
void RNSkiOSPlatformContext::releaseNativeBuffer(uint64_t pointer) {
|
|
61
62
|
CMSampleBufferRef sampleBuffer = reinterpret_cast<CMSampleBufferRef>(pointer);
|
|
62
63
|
CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
|
|
63
64
|
if (sampleBuffer) {
|
|
@@ -68,76 +69,82 @@ void RNSkiOSPlatformContext::releasePlatformBuffer(uint64_t pointer) {
|
|
|
68
69
|
}
|
|
69
70
|
}
|
|
70
71
|
|
|
71
|
-
uint64_t RNSkiOSPlatformContext::
|
|
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
|
|
72
87
|
auto bytesPerPixel = image->imageInfo().bytesPerPixel();
|
|
73
88
|
int bytesPerRow = image->width() * bytesPerPixel;
|
|
74
89
|
auto buf = SkData::MakeUninitialized(image->width() * image->height() *
|
|
75
90
|
bytesPerPixel);
|
|
76
91
|
SkImageInfo info = SkImageInfo::Make(image->width(), image->height(),
|
|
77
92
|
image->colorType(), image->alphaType());
|
|
93
|
+
// 2. Copy pixels into our buffer
|
|
78
94
|
image->readPixels(nullptr, info, const_cast<void *>(buf->data()), bytesPerRow,
|
|
79
95
|
0, 0);
|
|
80
|
-
auto pixelData = const_cast<void *>(buf->data());
|
|
81
96
|
|
|
82
|
-
// Create
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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!");
|
|
108
128
|
}
|
|
109
129
|
|
|
110
|
-
//
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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);
|
|
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);
|
|
128
135
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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));
|
|
137
144
|
}
|
|
138
145
|
|
|
139
|
-
// Return
|
|
140
|
-
return reinterpret_cast<uint64_t>(
|
|
146
|
+
// 8. Return CVPixelBuffer casted to uint64_t
|
|
147
|
+
return reinterpret_cast<uint64_t>(pixelBuffer);
|
|
141
148
|
}
|
|
142
149
|
|
|
143
150
|
void RNSkiOSPlatformContext::raiseError(const std::exception &err) {
|
|
@@ -149,35 +156,9 @@ sk_sp<SkSurface> RNSkiOSPlatformContext::makeOffscreenSurface(int width,
|
|
|
149
156
|
return SkiaMetalSurfaceFactory::makeOffscreenSurface(width, height);
|
|
150
157
|
}
|
|
151
158
|
|
|
152
|
-
sk_sp<SkImage>
|
|
153
|
-
|
|
154
|
-
|
|
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;
|
|
159
|
+
sk_sp<SkImage> RNSkiOSPlatformContext::makeImageFromNativeBuffer(void *buffer) {
|
|
160
|
+
CVPixelBufferRef sampleBuffer = (CVPixelBufferRef)buffer;
|
|
161
|
+
return SkiaMetalSurfaceFactory::makeTextureFromCVPixelBuffer(sampleBuffer);
|
|
181
162
|
}
|
|
182
163
|
|
|
183
164
|
sk_sp<SkFontMgr> RNSkiOSPlatformContext::createFontMgr() {
|
|
@@ -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
|
+
};
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
//
|
|
2
|
+
// SkiaCVPixelBufferUtils.mm
|
|
3
|
+
// react-native-skia
|
|
4
|
+
//
|
|
5
|
+
// Created by Marc Rousavy on 10.04.24.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#import "SkiaCVPixelBufferUtils.h"
|
|
9
|
+
#import "SkiaMetalSurfaceFactory.h"
|
|
10
|
+
|
|
11
|
+
#pragma clang diagnostic push
|
|
12
|
+
#pragma clang diagnostic ignored "-Wdocumentation"
|
|
13
|
+
#import "include/core/SkColorSpace.h"
|
|
14
|
+
#import <include/gpu/GrBackendSurface.h>
|
|
15
|
+
#pragma clang diagnostic pop
|
|
16
|
+
|
|
17
|
+
#include <TargetConditionals.h>
|
|
18
|
+
#if TARGET_RT_BIG_ENDIAN
|
|
19
|
+
#define FourCC2Str(fourcc) \
|
|
20
|
+
(const char[]) { \
|
|
21
|
+
*((char *)&fourcc), *(((char *)&fourcc) + 1), *(((char *)&fourcc) + 2), \
|
|
22
|
+
*(((char *)&fourcc) + 3), 0 \
|
|
23
|
+
}
|
|
24
|
+
#else
|
|
25
|
+
#define FourCC2Str(fourcc) \
|
|
26
|
+
(const char[]) { \
|
|
27
|
+
*(((char *)&fourcc) + 3), *(((char *)&fourcc) + 2), \
|
|
28
|
+
*(((char *)&fourcc) + 1), *(((char *)&fourcc) + 0), 0 \
|
|
29
|
+
}
|
|
30
|
+
#endif
|
|
31
|
+
|
|
32
|
+
// pragma MARK: TextureHolder
|
|
33
|
+
|
|
34
|
+
TextureHolder::TextureHolder(CVMetalTextureRef texture) : _texture(texture) {}
|
|
35
|
+
TextureHolder::~TextureHolder() { CFRelease(_texture); }
|
|
36
|
+
|
|
37
|
+
GrBackendTexture TextureHolder::toGrBackendTexture() {
|
|
38
|
+
// Unwrap the underlying MTLTexture
|
|
39
|
+
id<MTLTexture> mtlTexture = CVMetalTextureGetTexture(_texture);
|
|
40
|
+
if (mtlTexture == nil) [[unlikely]] {
|
|
41
|
+
throw std::runtime_error(
|
|
42
|
+
"Failed to get MTLTexture from CVMetalTextureRef!");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Wrap MTLTexture in Skia's GrBackendTexture
|
|
46
|
+
GrMtlTextureInfo textureInfo;
|
|
47
|
+
textureInfo.fTexture.retain((__bridge void *)mtlTexture);
|
|
48
|
+
GrBackendTexture texture =
|
|
49
|
+
GrBackendTexture((int)mtlTexture.width, (int)mtlTexture.height,
|
|
50
|
+
skgpu::Mipmapped::kNo, textureInfo);
|
|
51
|
+
return texture;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// pragma MARK: Base
|
|
55
|
+
|
|
56
|
+
SkiaCVPixelBufferUtils::CVPixelBufferBaseFormat
|
|
57
|
+
SkiaCVPixelBufferUtils::getCVPixelBufferBaseFormat(
|
|
58
|
+
CVPixelBufferRef pixelBuffer) {
|
|
59
|
+
OSType format = CVPixelBufferGetPixelFormatType(pixelBuffer);
|
|
60
|
+
|
|
61
|
+
switch (format) {
|
|
62
|
+
case kCVPixelFormatType_32BGRA:
|
|
63
|
+
case kCVPixelFormatType_32RGBA:
|
|
64
|
+
return CVPixelBufferBaseFormat::rgb;
|
|
65
|
+
default:
|
|
66
|
+
[[unlikely]] throw std::runtime_error(
|
|
67
|
+
"CVPixelBuffer has unsupported pixel-format! " +
|
|
68
|
+
std::string(FourCC2Str(format)));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// pragma MARK: RGB
|
|
73
|
+
|
|
74
|
+
SkColorType SkiaCVPixelBufferUtils::RGB::getCVPixelBufferColorType(
|
|
75
|
+
CVPixelBufferRef pixelBuffer) {
|
|
76
|
+
OSType format = CVPixelBufferGetPixelFormatType(pixelBuffer);
|
|
77
|
+
|
|
78
|
+
switch (format) {
|
|
79
|
+
case kCVPixelFormatType_32BGRA:
|
|
80
|
+
[[likely]] return kBGRA_8888_SkColorType;
|
|
81
|
+
case kCVPixelFormatType_32RGBA:
|
|
82
|
+
return kRGBA_8888_SkColorType;
|
|
83
|
+
// This can be extended with branches for specific RGB formats if new Apple
|
|
84
|
+
// uses new formats.
|
|
85
|
+
default:
|
|
86
|
+
[[unlikely]] throw std::runtime_error(
|
|
87
|
+
"CVPixelBuffer has unknown RGB format! " +
|
|
88
|
+
std::string(FourCC2Str(format)));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
TextureHolder *SkiaCVPixelBufferUtils::RGB::getSkiaTextureForCVPixelBuffer(
|
|
93
|
+
CVPixelBufferRef pixelBuffer) {
|
|
94
|
+
return getSkiaTextureForCVPixelBufferPlane(pixelBuffer, /* planeIndex */ 0);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// pragma MARK: CVPixelBuffer -> Skia Texture
|
|
98
|
+
|
|
99
|
+
TextureHolder *SkiaCVPixelBufferUtils::getSkiaTextureForCVPixelBufferPlane(
|
|
100
|
+
CVPixelBufferRef pixelBuffer, size_t planeIndex) {
|
|
101
|
+
// 1. Get cache
|
|
102
|
+
CVMetalTextureCacheRef textureCache = getTextureCache();
|
|
103
|
+
|
|
104
|
+
// 2. Get MetalTexture from CMSampleBuffer
|
|
105
|
+
size_t width = CVPixelBufferGetWidthOfPlane(pixelBuffer, planeIndex);
|
|
106
|
+
size_t height = CVPixelBufferGetHeightOfPlane(pixelBuffer, planeIndex);
|
|
107
|
+
MTLPixelFormat pixelFormat =
|
|
108
|
+
getMTLPixelFormatForCVPixelBufferPlane(pixelBuffer, planeIndex);
|
|
109
|
+
|
|
110
|
+
CVMetalTextureRef textureHolder;
|
|
111
|
+
CVReturn result = CVMetalTextureCacheCreateTextureFromImage(
|
|
112
|
+
kCFAllocatorDefault, textureCache, pixelBuffer, nil, pixelFormat, width,
|
|
113
|
+
height, planeIndex, &textureHolder);
|
|
114
|
+
|
|
115
|
+
if (result != kCVReturnSuccess) [[unlikely]] {
|
|
116
|
+
throw std::runtime_error(
|
|
117
|
+
"Failed to create Metal Texture from CMSampleBuffer! Result: " +
|
|
118
|
+
std::to_string(result));
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return new TextureHolder(textureHolder);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// pragma MARK: getTextureCache()
|
|
125
|
+
|
|
126
|
+
CVMetalTextureCacheRef SkiaCVPixelBufferUtils::getTextureCache() {
|
|
127
|
+
static CVMetalTextureCacheRef textureCache = nil;
|
|
128
|
+
if (textureCache == nil) {
|
|
129
|
+
// Create a new Texture Cache
|
|
130
|
+
auto result = CVMetalTextureCacheCreate(kCFAllocatorDefault, nil,
|
|
131
|
+
MTLCreateSystemDefaultDevice(), nil,
|
|
132
|
+
&textureCache);
|
|
133
|
+
if (result != kCVReturnSuccess || textureCache == nil) {
|
|
134
|
+
throw std::runtime_error("Failed to create Metal Texture Cache!");
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return textureCache;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// pragma MARK: Get CVPixelBuffer MTLPixelFormat
|
|
141
|
+
|
|
142
|
+
MTLPixelFormat SkiaCVPixelBufferUtils::getMTLPixelFormatForCVPixelBufferPlane(
|
|
143
|
+
CVPixelBufferRef pixelBuffer, size_t planeIndex) {
|
|
144
|
+
size_t width = CVPixelBufferGetWidthOfPlane(pixelBuffer, planeIndex);
|
|
145
|
+
size_t bytesPerRow =
|
|
146
|
+
CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, planeIndex);
|
|
147
|
+
double bytesPerPixel = round(static_cast<double>(bytesPerRow) / width);
|
|
148
|
+
if (bytesPerPixel == 1) {
|
|
149
|
+
return MTLPixelFormatR8Unorm;
|
|
150
|
+
} else if (bytesPerPixel == 2) {
|
|
151
|
+
return MTLPixelFormatRG8Unorm;
|
|
152
|
+
} else if (bytesPerPixel == 4) {
|
|
153
|
+
return MTLPixelFormatBGRA8Unorm;
|
|
154
|
+
} else [[unlikely]] {
|
|
155
|
+
throw std::runtime_error("Invalid bytes per row! Expected 1 (R), 2 (RG) or "
|
|
156
|
+
"4 (RGBA), but received " +
|
|
157
|
+
std::to_string(bytesPerPixel));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
@@ -26,7 +26,8 @@ public:
|
|
|
26
26
|
int height);
|
|
27
27
|
static sk_sp<SkSurface> makeOffscreenSurface(int width, int height);
|
|
28
28
|
|
|
29
|
-
static sk_sp<SkImage>
|
|
29
|
+
static sk_sp<SkImage>
|
|
30
|
+
makeTextureFromCVPixelBuffer(CVPixelBufferRef pixelBuffer);
|
|
30
31
|
|
|
31
32
|
private:
|
|
32
33
|
static id<MTLDevice> device;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#import "RNSkLog.h"
|
|
2
2
|
|
|
3
|
-
#
|
|
3
|
+
#import "SkiaCVPixelBufferUtils.h"
|
|
4
|
+
#import "SkiaMetalSurfaceFactory.h"
|
|
4
5
|
|
|
5
6
|
#pragma clang diagnostic push
|
|
6
7
|
#pragma clang diagnostic ignored "-Wdocumentation"
|
|
@@ -106,12 +107,35 @@ sk_sp<SkSurface> SkiaMetalSurfaceFactory::makeOffscreenSurface(int width,
|
|
|
106
107
|
return surface;
|
|
107
108
|
}
|
|
108
109
|
|
|
109
|
-
sk_sp<SkImage>
|
|
110
|
-
|
|
110
|
+
sk_sp<SkImage> SkiaMetalSurfaceFactory::makeTextureFromCVPixelBuffer(
|
|
111
|
+
CVPixelBufferRef pixelBuffer) {
|
|
111
112
|
if (!SkiaMetalSurfaceFactory::createSkiaDirectContextIfNecessary(
|
|
112
|
-
&ThreadContextHolder::ThreadSkiaMetalContext)) {
|
|
113
|
+
&ThreadContextHolder::ThreadSkiaMetalContext)) [[unlikely]] {
|
|
113
114
|
throw std::runtime_error("Failed to create Skia Context for this Thread!");
|
|
114
115
|
}
|
|
115
|
-
|
|
116
|
-
|
|
116
|
+
const SkiaMetalContext &context = ThreadContextHolder::ThreadSkiaMetalContext;
|
|
117
|
+
|
|
118
|
+
SkiaCVPixelBufferUtils::CVPixelBufferBaseFormat format =
|
|
119
|
+
SkiaCVPixelBufferUtils::getCVPixelBufferBaseFormat(pixelBuffer);
|
|
120
|
+
switch (format) {
|
|
121
|
+
case SkiaCVPixelBufferUtils::CVPixelBufferBaseFormat::rgb: {
|
|
122
|
+
// CVPixelBuffer is in any RGB format.
|
|
123
|
+
SkColorType colorType =
|
|
124
|
+
SkiaCVPixelBufferUtils::RGB::getCVPixelBufferColorType(pixelBuffer);
|
|
125
|
+
TextureHolder *texture =
|
|
126
|
+
SkiaCVPixelBufferUtils::RGB::getSkiaTextureForCVPixelBuffer(
|
|
127
|
+
pixelBuffer);
|
|
128
|
+
return SkImages::BorrowTextureFrom(
|
|
129
|
+
context.skContext.get(), texture->toGrBackendTexture(),
|
|
130
|
+
kTopLeft_GrSurfaceOrigin, colorType, kOpaque_SkAlphaType, nullptr,
|
|
131
|
+
[](void *texture) { delete (TextureHolder *)texture; },
|
|
132
|
+
(void *)texture);
|
|
133
|
+
}
|
|
134
|
+
default:
|
|
135
|
+
[[unlikely]] {
|
|
136
|
+
throw std::runtime_error("Failed to convert PlatformBuffer to SkImage - "
|
|
137
|
+
"PlatformBuffer has unsupported PixelFormat! " +
|
|
138
|
+
std::to_string(static_cast<int>(format)));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
117
141
|
}
|