@shopify/react-native-skia 0.1.201 → 0.1.202
Sign up to get free protection for your applications and to get access to all the features.
- package/cpp/rnskia/RNSkView.h +5 -2
- package/ios/RNSkia-iOS/RNSkMetalCanvasProvider.h +5 -14
- package/ios/RNSkia-iOS/RNSkMetalCanvasProvider.mm +7 -56
- package/ios/RNSkia-iOS/RNSkiOSPlatformContext.mm +2 -2
- package/ios/RNSkia-iOS/SkiaMetalSurfaceFactory.h +31 -0
- package/ios/RNSkia-iOS/SkiaMetalSurfaceFactory.mm +105 -0
- package/package.json +1 -1
- package/ios/RNSkia-iOS/SkiaMetalRenderer.h +0 -5
- package/ios/RNSkia-iOS/SkiaMetalRenderer.mm +0 -55
package/cpp/rnskia/RNSkView.h
CHANGED
@@ -93,6 +93,7 @@ public:
|
|
93
93
|
float height)
|
94
94
|
: RNSkCanvasProvider(requestRedraw), _width(width), _height(height) {
|
95
95
|
_surface = context->makeOffscreenSurface(_width, _height);
|
96
|
+
_pd = context->getPixelDensity();
|
96
97
|
}
|
97
98
|
|
98
99
|
/**
|
@@ -101,8 +102,9 @@ public:
|
|
101
102
|
sk_sp<SkImage> makeSnapshot(SkRect *bounds) {
|
102
103
|
sk_sp<SkImage> image;
|
103
104
|
if (bounds != nullptr) {
|
104
|
-
SkIRect b =
|
105
|
-
|
105
|
+
SkIRect b =
|
106
|
+
SkIRect::MakeXYWH(bounds->x() * _pd, bounds->y() * _pd,
|
107
|
+
bounds->width() * _pd, bounds->height() * _pd);
|
106
108
|
image = _surface->makeImageSnapshot(b);
|
107
109
|
} else {
|
108
110
|
image = _surface->makeImageSnapshot();
|
@@ -131,6 +133,7 @@ public:
|
|
131
133
|
private:
|
132
134
|
float _width;
|
133
135
|
float _height;
|
136
|
+
float _pd = 1.0f;
|
134
137
|
sk_sp<SkSurface> _surface;
|
135
138
|
};
|
136
139
|
|
@@ -6,13 +6,12 @@
|
|
6
6
|
#import <MetalKit/MetalKit.h>
|
7
7
|
#import <QuartzCore/CAMetalLayer.h>
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
#pragma clang diagnostic push
|
10
|
+
#pragma clang diagnostic ignored "-Wdocumentation"
|
11
|
+
|
12
|
+
#import <include/gpu/GrDirectContext.h>
|
13
13
|
|
14
|
-
|
15
|
-
renderContexts;
|
14
|
+
#pragma clang diagnostic pop
|
16
15
|
|
17
16
|
class RNSkMetalCanvasProvider : public RNSkia::RNSkCanvasProvider {
|
18
17
|
public:
|
@@ -27,17 +26,9 @@ public:
|
|
27
26
|
bool renderToCanvas(const std::function<void(SkCanvas *)> &cb) override;
|
28
27
|
|
29
28
|
void setSize(int width, int height);
|
30
|
-
|
31
29
|
CALayer *getLayer();
|
32
30
|
|
33
31
|
private:
|
34
|
-
/**
|
35
|
-
* To be able to use static contexts (and avoid reloading the skia context for
|
36
|
-
* each new view, we track the Skia drawing context per thread.
|
37
|
-
* @return The drawing context for the current thread
|
38
|
-
*/
|
39
|
-
static std::shared_ptr<MetalRenderContext> getMetalRenderContext();
|
40
|
-
|
41
32
|
std::shared_ptr<RNSkia::RNSkPlatformContext> _context;
|
42
33
|
float _width = -1;
|
43
34
|
float _height = -1;
|
@@ -1,5 +1,6 @@
|
|
1
1
|
#import <RNSkLog.h>
|
2
2
|
#import <RNSkMetalCanvasProvider.h>
|
3
|
+
#import <SkiaMetalSurfaceFactory.h>
|
3
4
|
|
4
5
|
#pragma clang diagnostic push
|
5
6
|
#pragma clang diagnostic ignored "-Wdocumentation"
|
@@ -14,19 +15,6 @@
|
|
14
15
|
|
15
16
|
#pragma clang diagnostic pop
|
16
17
|
|
17
|
-
/** Static members */
|
18
|
-
std::shared_ptr<MetalRenderContext>
|
19
|
-
RNSkMetalCanvasProvider::getMetalRenderContext() {
|
20
|
-
auto threadId = std::this_thread::get_id();
|
21
|
-
if (renderContexts.count(threadId) == 0) {
|
22
|
-
auto drawingContext = std::make_shared<MetalRenderContext>();
|
23
|
-
drawingContext->commandQueue = nullptr;
|
24
|
-
drawingContext->skContext = nullptr;
|
25
|
-
renderContexts.emplace(threadId, drawingContext);
|
26
|
-
}
|
27
|
-
return renderContexts.at(threadId);
|
28
|
-
}
|
29
|
-
|
30
18
|
RNSkMetalCanvasProvider::RNSkMetalCanvasProvider(
|
31
19
|
std::function<void()> requestRedraw,
|
32
20
|
std::shared_ptr<RNSkia::RNSkPlatformContext> context)
|
@@ -35,11 +23,8 @@ RNSkMetalCanvasProvider::RNSkMetalCanvasProvider(
|
|
35
23
|
#pragma clang diagnostic ignored "-Wunguarded-availability-new"
|
36
24
|
_layer = [CAMetalLayer layer];
|
37
25
|
#pragma clang diagnostic pop
|
38
|
-
|
39
|
-
auto device = MTLCreateSystemDefaultDevice();
|
40
|
-
|
41
26
|
_layer.framebufferOnly = NO;
|
42
|
-
_layer.device =
|
27
|
+
_layer.device = MTLCreateSystemDefaultDevice();
|
43
28
|
_layer.opaque = false;
|
44
29
|
_layer.contentsScale = _context->getPixelDensity();
|
45
30
|
_layer.pixelFormat = MTLPixelFormatBGRA8Unorm;
|
@@ -87,52 +72,18 @@ bool RNSkMetalCanvasProvider::renderToCanvas(
|
|
87
72
|
return false;
|
88
73
|
}
|
89
74
|
}
|
90
|
-
|
91
|
-
// Get render context for current thread
|
92
|
-
auto renderContext = getMetalRenderContext();
|
93
|
-
|
94
|
-
if (renderContext->skContext == nullptr) {
|
95
|
-
auto device = MTLCreateSystemDefaultDevice();
|
96
|
-
renderContext->commandQueue =
|
97
|
-
id<MTLCommandQueue>(CFRetain((GrMTLHandle)[device newCommandQueue]));
|
98
|
-
renderContext->skContext = GrDirectContext::MakeMetal(
|
99
|
-
(__bridge void *)device, (__bridge void *)renderContext->commandQueue);
|
100
|
-
}
|
101
|
-
|
102
75
|
// Wrap in auto release pool since we want the system to clean up after
|
103
76
|
// rendering and not wait until later - we've seen some example of memory
|
104
77
|
// usage growing very fast in the simulator without this.
|
105
78
|
@autoreleasepool {
|
106
|
-
|
107
|
-
/* It is super important that we use the pattern of calling nextDrawable
|
108
|
-
inside this autoreleasepool and not depend on Skia's
|
109
|
-
SkSurface::MakeFromCAMetalLayer to encapsulate since we're seeing a lot of
|
110
|
-
drawables leaking if they're not done this way.
|
111
|
-
|
112
|
-
This is now reverted from:
|
113
|
-
(https://github.com/Shopify/react-native-skia/commit/2e2290f8e6dfc6921f97b79f779d920fbc1acceb)
|
114
|
-
back to the original implementation.
|
115
|
-
*/
|
116
79
|
id<CAMetalDrawable> currentDrawable = [_layer nextDrawable];
|
117
80
|
if (currentDrawable == nullptr) {
|
118
81
|
return false;
|
119
82
|
}
|
120
83
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
GrBackendRenderTarget backendRT(_layer.drawableSize.width,
|
125
|
-
_layer.drawableSize.height, 1, fbInfo);
|
126
|
-
|
127
|
-
auto skSurface = SkSurfaces::WrapBackendRenderTarget(
|
128
|
-
renderContext->skContext.get(), backendRT, kTopLeft_GrSurfaceOrigin,
|
129
|
-
kBGRA_8888_SkColorType, nullptr, nullptr);
|
130
|
-
|
131
|
-
if (skSurface == nullptr || skSurface->getCanvas() == nullptr) {
|
132
|
-
RNSkia::RNSkLogger::logToConsole(
|
133
|
-
"Skia surface could not be created from parameters.");
|
134
|
-
return false;
|
135
|
-
}
|
84
|
+
auto skSurface = SkiaMetalSurfaceFactory::makeWindowedSurface(
|
85
|
+
currentDrawable.texture, _layer.drawableSize.width,
|
86
|
+
_layer.drawableSize.height);
|
136
87
|
|
137
88
|
SkCanvas *canvas = skSurface->getCanvas();
|
138
89
|
cb(canvas);
|
@@ -140,11 +91,11 @@ bool RNSkMetalCanvasProvider::renderToCanvas(
|
|
140
91
|
skSurface->flushAndSubmit();
|
141
92
|
|
142
93
|
id<MTLCommandBuffer> commandBuffer(
|
143
|
-
[
|
94
|
+
[ThreadContextHolder::ThreadSkiaMetalContext
|
95
|
+
.commandQueue commandBuffer]);
|
144
96
|
[commandBuffer presentDrawable:currentDrawable];
|
145
97
|
[commandBuffer commit];
|
146
98
|
}
|
147
|
-
|
148
99
|
return true;
|
149
100
|
};
|
150
101
|
|
@@ -4,7 +4,7 @@
|
|
4
4
|
#include <thread>
|
5
5
|
#include <utility>
|
6
6
|
|
7
|
-
#include <
|
7
|
+
#include <SkiaMetalSurfaceFactory.h>
|
8
8
|
|
9
9
|
#pragma clang diagnostic push
|
10
10
|
#pragma clang diagnostic ignored "-Wdocumentation"
|
@@ -59,7 +59,7 @@ void RNSkiOSPlatformContext::raiseError(const std::exception &err) {
|
|
59
59
|
|
60
60
|
sk_sp<SkSurface> RNSkiOSPlatformContext::makeOffscreenSurface(int width,
|
61
61
|
int height) {
|
62
|
-
return
|
62
|
+
return SkiaMetalSurfaceFactory::makeOffscreenSurface(width, height);
|
63
63
|
}
|
64
64
|
|
65
65
|
void RNSkiOSPlatformContext::runOnMainThread(std::function<void()> func) {
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#import <MetalKit/MetalKit.h>
|
2
|
+
|
3
|
+
#pragma clang diagnostic push
|
4
|
+
#pragma clang diagnostic ignored "-Wdocumentation"
|
5
|
+
|
6
|
+
#import "SkCanvas.h"
|
7
|
+
#import <include/gpu/GrDirectContext.h>
|
8
|
+
|
9
|
+
#pragma clang diagnostic pop
|
10
|
+
|
11
|
+
using SkiaMetalContext = struct SkiaMetalContext {
|
12
|
+
id<MTLCommandQueue> commandQueue = nullptr;
|
13
|
+
sk_sp<GrDirectContext> skContext = nullptr;
|
14
|
+
};
|
15
|
+
|
16
|
+
class ThreadContextHolder {
|
17
|
+
public:
|
18
|
+
static thread_local SkiaMetalContext ThreadSkiaMetalContext;
|
19
|
+
};
|
20
|
+
|
21
|
+
class SkiaMetalSurfaceFactory {
|
22
|
+
public:
|
23
|
+
static sk_sp<SkSurface> makeWindowedSurface(id<MTLTexture> texture, int width,
|
24
|
+
int height);
|
25
|
+
static sk_sp<SkSurface> makeOffscreenSurface(int width, int height);
|
26
|
+
|
27
|
+
private:
|
28
|
+
static id<MTLDevice> device;
|
29
|
+
static bool
|
30
|
+
createSkiaDirectContextIfNecessary(SkiaMetalContext *threadContext);
|
31
|
+
};
|
@@ -0,0 +1,105 @@
|
|
1
|
+
#import <RNSkLog.h>
|
2
|
+
|
3
|
+
#include <SkiaMetalSurfaceFactory.h>
|
4
|
+
|
5
|
+
#pragma clang diagnostic push
|
6
|
+
#pragma clang diagnostic ignored "-Wdocumentation"
|
7
|
+
|
8
|
+
#import "SkCanvas.h"
|
9
|
+
#import "SkColorSpace.h"
|
10
|
+
#import "SkSurface.h"
|
11
|
+
|
12
|
+
#import <include/gpu/GrBackendSurface.h>
|
13
|
+
#import <include/gpu/GrDirectContext.h>
|
14
|
+
#import <include/gpu/ganesh/SkSurfaceGanesh.h>
|
15
|
+
|
16
|
+
#pragma clang diagnostic pop
|
17
|
+
|
18
|
+
thread_local SkiaMetalContext ThreadContextHolder::ThreadSkiaMetalContext;
|
19
|
+
|
20
|
+
struct OffscreenRenderContext {
|
21
|
+
id<MTLTexture> texture;
|
22
|
+
|
23
|
+
OffscreenRenderContext(id<MTLDevice> device,
|
24
|
+
sk_sp<GrDirectContext> skiaContext,
|
25
|
+
id<MTLCommandQueue> commandQueue, int width,
|
26
|
+
int height) {
|
27
|
+
// Create a Metal texture descriptor
|
28
|
+
MTLTextureDescriptor *textureDescriptor = [MTLTextureDescriptor
|
29
|
+
texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
|
30
|
+
width:width
|
31
|
+
height:height
|
32
|
+
mipmapped:NO];
|
33
|
+
textureDescriptor.usage =
|
34
|
+
MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead;
|
35
|
+
texture = [device newTextureWithDescriptor:textureDescriptor];
|
36
|
+
}
|
37
|
+
};
|
38
|
+
|
39
|
+
id<MTLDevice> SkiaMetalSurfaceFactory::device = MTLCreateSystemDefaultDevice();
|
40
|
+
|
41
|
+
bool SkiaMetalSurfaceFactory::createSkiaDirectContextIfNecessary(
|
42
|
+
SkiaMetalContext *skiaMetalContext) {
|
43
|
+
if (skiaMetalContext->skContext == nullptr) {
|
44
|
+
skiaMetalContext->commandQueue =
|
45
|
+
id<MTLCommandQueue>(CFRetain((GrMTLHandle)[device newCommandQueue]));
|
46
|
+
skiaMetalContext->skContext = GrDirectContext::MakeMetal(
|
47
|
+
(__bridge void *)device,
|
48
|
+
(__bridge void *)skiaMetalContext->commandQueue);
|
49
|
+
if (skiaMetalContext->skContext == nullptr) {
|
50
|
+
RNSkia::RNSkLogger::logToConsole("Couldn't create a Skia Metal Context");
|
51
|
+
return false;
|
52
|
+
}
|
53
|
+
}
|
54
|
+
return true;
|
55
|
+
}
|
56
|
+
|
57
|
+
sk_sp<SkSurface>
|
58
|
+
SkiaMetalSurfaceFactory::makeWindowedSurface(id<MTLTexture> texture, int width,
|
59
|
+
int height) {
|
60
|
+
// Get render context for current thread
|
61
|
+
if (!SkiaMetalSurfaceFactory::createSkiaDirectContextIfNecessary(
|
62
|
+
&ThreadContextHolder::ThreadSkiaMetalContext)) {
|
63
|
+
return nullptr;
|
64
|
+
}
|
65
|
+
GrMtlTextureInfo fbInfo;
|
66
|
+
fbInfo.fTexture.retain((__bridge void *)texture);
|
67
|
+
|
68
|
+
GrBackendRenderTarget backendRT(width, height, 1, fbInfo);
|
69
|
+
|
70
|
+
auto skSurface = SkSurfaces::WrapBackendRenderTarget(
|
71
|
+
ThreadContextHolder::ThreadSkiaMetalContext.skContext.get(), backendRT,
|
72
|
+
kTopLeft_GrSurfaceOrigin, kBGRA_8888_SkColorType, nullptr, nullptr);
|
73
|
+
|
74
|
+
if (skSurface == nullptr || skSurface->getCanvas() == nullptr) {
|
75
|
+
RNSkia::RNSkLogger::logToConsole(
|
76
|
+
"Skia surface could not be created from parameters.");
|
77
|
+
return nullptr;
|
78
|
+
}
|
79
|
+
return skSurface;
|
80
|
+
}
|
81
|
+
|
82
|
+
sk_sp<SkSurface> SkiaMetalSurfaceFactory::makeOffscreenSurface(int width,
|
83
|
+
int height) {
|
84
|
+
if (!SkiaMetalSurfaceFactory::createSkiaDirectContextIfNecessary(
|
85
|
+
&ThreadContextHolder::ThreadSkiaMetalContext)) {
|
86
|
+
return nullptr;
|
87
|
+
}
|
88
|
+
auto ctx = new OffscreenRenderContext(
|
89
|
+
device, ThreadContextHolder::ThreadSkiaMetalContext.skContext,
|
90
|
+
ThreadContextHolder::ThreadSkiaMetalContext.commandQueue, width, height);
|
91
|
+
|
92
|
+
// Create a GrBackendTexture from the Metal texture
|
93
|
+
GrMtlTextureInfo info;
|
94
|
+
info.fTexture.retain((__bridge void *)ctx->texture);
|
95
|
+
GrBackendTexture backendTexture(width, height, GrMipMapped::kNo, info);
|
96
|
+
|
97
|
+
// Create a SkSurface from the GrBackendTexture
|
98
|
+
auto surface = SkSurfaces::WrapBackendTexture(
|
99
|
+
ThreadContextHolder::ThreadSkiaMetalContext.skContext.get(),
|
100
|
+
backendTexture, kTopLeft_GrSurfaceOrigin, 0, kBGRA_8888_SkColorType,
|
101
|
+
nullptr, nullptr,
|
102
|
+
[](void *addr) { delete (OffscreenRenderContext *)addr; }, ctx);
|
103
|
+
|
104
|
+
return surface;
|
105
|
+
}
|
package/package.json
CHANGED
@@ -1,55 +0,0 @@
|
|
1
|
-
#pragma clang diagnostic push
|
2
|
-
#pragma clang diagnostic ignored "-Wdocumentation"
|
3
|
-
|
4
|
-
#import "SkCanvas.h"
|
5
|
-
#import "SkColorSpace.h"
|
6
|
-
#import "SkSurface.h"
|
7
|
-
|
8
|
-
#import <include/gpu/GrBackendSurface.h>
|
9
|
-
#import <include/gpu/GrDirectContext.h>
|
10
|
-
#import <include/gpu/ganesh/SkSurfaceGanesh.h>
|
11
|
-
|
12
|
-
#pragma clang diagnostic pop
|
13
|
-
|
14
|
-
#import <MetalKit/MetalKit.h>
|
15
|
-
|
16
|
-
struct OffscreenRenderContext {
|
17
|
-
id<MTLDevice> device;
|
18
|
-
id<MTLCommandQueue> commandQueue;
|
19
|
-
sk_sp<GrDirectContext> skiaContext;
|
20
|
-
id<MTLTexture> texture;
|
21
|
-
|
22
|
-
OffscreenRenderContext(int width, int height) {
|
23
|
-
device = MTLCreateSystemDefaultDevice();
|
24
|
-
commandQueue =
|
25
|
-
id<MTLCommandQueue>(CFRetain((GrMTLHandle)[device newCommandQueue]));
|
26
|
-
skiaContext = GrDirectContext::MakeMetal((__bridge void *)device,
|
27
|
-
(__bridge void *)commandQueue);
|
28
|
-
// Create a Metal texture descriptor
|
29
|
-
MTLTextureDescriptor *textureDescriptor = [MTLTextureDescriptor
|
30
|
-
texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
|
31
|
-
width:width
|
32
|
-
height:height
|
33
|
-
mipmapped:NO];
|
34
|
-
textureDescriptor.usage =
|
35
|
-
MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead;
|
36
|
-
texture = [device newTextureWithDescriptor:textureDescriptor];
|
37
|
-
}
|
38
|
-
};
|
39
|
-
|
40
|
-
sk_sp<SkSurface> MakeOffscreenMetalSurface(int width, int height) {
|
41
|
-
auto ctx = new OffscreenRenderContext(width, height);
|
42
|
-
|
43
|
-
// Create a GrBackendTexture from the Metal texture
|
44
|
-
GrMtlTextureInfo info;
|
45
|
-
info.fTexture.retain((__bridge void *)ctx->texture);
|
46
|
-
GrBackendTexture backendTexture(width, height, GrMipMapped::kNo, info);
|
47
|
-
|
48
|
-
// Create a SkSurface from the GrBackendTexture
|
49
|
-
auto surface = SkSurfaces::WrapBackendTexture(
|
50
|
-
ctx->skiaContext.get(), backendTexture, kTopLeft_GrSurfaceOrigin, 0,
|
51
|
-
kBGRA_8888_SkColorType, nullptr, nullptr,
|
52
|
-
[](void *addr) { delete (OffscreenRenderContext *)addr; }, ctx);
|
53
|
-
|
54
|
-
return surface;
|
55
|
-
}
|