@shopify/react-native-skia 0.1.199 → 0.1.201
Sign up to get free protection for your applications and to get access to all the features.
- package/android/CMakeLists.txt +1 -1
- package/android/cpp/jni/include/JniSkiaBaseView.h +74 -13
- package/android/cpp/jni/include/JniSkiaDomView.h +20 -12
- package/android/cpp/jni/include/JniSkiaDrawView.h +20 -14
- package/android/cpp/jni/include/JniSkiaPictureView.h +24 -15
- package/android/cpp/rnskia-android/RNSkAndroidPlatformContext.h +2 -2
- package/android/cpp/rnskia-android/RNSkOpenGLCanvasProvider.cpp +41 -44
- package/android/cpp/rnskia-android/RNSkOpenGLCanvasProvider.h +4 -6
- package/android/cpp/rnskia-android/SkiaOpenGLHelper.h +310 -0
- package/android/cpp/rnskia-android/SkiaOpenGLSurfaceFactory.cpp +132 -0
- package/android/cpp/rnskia-android/SkiaOpenGLSurfaceFactory.h +125 -0
- package/android/src/main/java/com/shopify/reactnative/skia/SkiaBaseView.java +80 -11
- package/android/src/main/java/com/shopify/reactnative/skia/SkiaDomView.java +2 -0
- package/android/src/main/java/com/shopify/reactnative/skia/SkiaDrawView.java +2 -0
- package/android/src/main/java/com/shopify/reactnative/skia/SkiaPictureView.java +3 -0
- package/android/src/main/java/com/shopify/reactnative/skia/ViewScreenshotService.java +7 -5
- package/cpp/api/JsiSkHostObjects.h +0 -10
- package/cpp/rnskia/RNSkJsView.cpp +35 -10
- package/cpp/rnskia/RNSkJsiViewApi.h +1 -1
- package/cpp/rnskia/RNSkView.h +9 -9
- package/ios/RNSkia-iOS/ViewScreenshotService.mm +1 -0
- package/package.json +2 -3
- package/android/cpp/rnskia-android/SkiaOpenGLRenderer.cpp +0 -347
- package/android/cpp/rnskia-android/SkiaOpenGLRenderer.h +0 -124
@@ -0,0 +1,310 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
#include "EGL/egl.h"
|
4
|
+
#include "GLES2/gl2.h"
|
5
|
+
#include <fbjni/fbjni.h>
|
6
|
+
#include <jni.h>
|
7
|
+
|
8
|
+
#include <atomic>
|
9
|
+
|
10
|
+
#include "RNSkLog.h"
|
11
|
+
|
12
|
+
#pragma clang diagnostic push
|
13
|
+
#pragma clang diagnostic ignored "-Wdocumentation"
|
14
|
+
|
15
|
+
#include "SkCanvas.h"
|
16
|
+
#include "SkColorSpace.h"
|
17
|
+
#include "SkSurface.h"
|
18
|
+
#include "include/gpu/GrDirectContext.h"
|
19
|
+
#include "include/gpu/gl/GrGLInterface.h"
|
20
|
+
|
21
|
+
#pragma clang diagnostic pop
|
22
|
+
|
23
|
+
namespace RNSkia {
|
24
|
+
|
25
|
+
/**
|
26
|
+
* Singleton holding the default display and shared eglContext that will be the
|
27
|
+
* first context we create so that we can share data between contexts.
|
28
|
+
*/
|
29
|
+
class OpenGLResourceHolder {
|
30
|
+
private:
|
31
|
+
OpenGLResourceHolder() {
|
32
|
+
// Initialize OpenGL
|
33
|
+
glDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
34
|
+
if (glDisplay == EGL_NO_DISPLAY) {
|
35
|
+
RNSkLogger::logToConsole("eglGetDisplay failed : %i", glGetError());
|
36
|
+
return;
|
37
|
+
}
|
38
|
+
|
39
|
+
EGLint major;
|
40
|
+
EGLint minor;
|
41
|
+
if (eglInitialize(glDisplay, &major, &minor) != EGL_TRUE) {
|
42
|
+
RNSkLogger::logToConsole("eglInitialize failed : %i", glGetError());
|
43
|
+
return;
|
44
|
+
}
|
45
|
+
|
46
|
+
// Create a default shared context
|
47
|
+
glConfig = getConfig(glDisplay);
|
48
|
+
|
49
|
+
// Create OpenGL context attributes
|
50
|
+
EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
|
51
|
+
|
52
|
+
// Initialize the offscreen context for this thread
|
53
|
+
glContext =
|
54
|
+
eglCreateContext(glDisplay, glConfig, glContext, contextAttribs);
|
55
|
+
if (glContext == EGL_NO_CONTEXT) {
|
56
|
+
RNSkLogger::logToConsole("eglCreateContext failed : %i", glGetError());
|
57
|
+
}
|
58
|
+
}
|
59
|
+
|
60
|
+
~OpenGLResourceHolder() {
|
61
|
+
if (glContext != EGL_NO_CONTEXT) {
|
62
|
+
eglDestroyContext(glDisplay, glContext);
|
63
|
+
glContext = EGL_NO_CONTEXT;
|
64
|
+
}
|
65
|
+
|
66
|
+
if (glDisplay != EGL_NO_DISPLAY) {
|
67
|
+
eglTerminate(glDisplay);
|
68
|
+
glDisplay = EGL_NO_DISPLAY;
|
69
|
+
}
|
70
|
+
}
|
71
|
+
/* Explicitly disallow copying. */
|
72
|
+
OpenGLResourceHolder(const OpenGLResourceHolder &) = delete;
|
73
|
+
OpenGLResourceHolder &operator=(const OpenGLResourceHolder &) = delete;
|
74
|
+
|
75
|
+
public:
|
76
|
+
static OpenGLResourceHolder &getInstance() {
|
77
|
+
static OpenGLResourceHolder Instance;
|
78
|
+
return Instance;
|
79
|
+
}
|
80
|
+
|
81
|
+
/**
|
82
|
+
* The first context created will be considered the parent / shared context
|
83
|
+
* and will be used as the parent / shareable context when creating subsequent
|
84
|
+
* contexts.
|
85
|
+
*/
|
86
|
+
std::atomic<EGLContext> glContext = EGL_NO_CONTEXT;
|
87
|
+
/**
|
88
|
+
* Shared egl display
|
89
|
+
*/
|
90
|
+
std::atomic<EGLDisplay> glDisplay = EGL_NO_DISPLAY;
|
91
|
+
|
92
|
+
/**
|
93
|
+
* Shared eglConfig
|
94
|
+
*/
|
95
|
+
std::atomic<EGLConfig> glConfig = 0;
|
96
|
+
|
97
|
+
private:
|
98
|
+
/**
|
99
|
+
* Finds the correct EGL Config for the given parameters
|
100
|
+
* @param glDisplay
|
101
|
+
* @return Config or zero if no matching context could be found.
|
102
|
+
*/
|
103
|
+
static EGLConfig getConfig(EGLDisplay glDisplay) {
|
104
|
+
|
105
|
+
EGLint att[] = {EGL_RENDERABLE_TYPE,
|
106
|
+
EGL_OPENGL_ES2_BIT,
|
107
|
+
EGL_ALPHA_SIZE,
|
108
|
+
8,
|
109
|
+
EGL_BLUE_SIZE,
|
110
|
+
8,
|
111
|
+
EGL_GREEN_SIZE,
|
112
|
+
8,
|
113
|
+
EGL_RED_SIZE,
|
114
|
+
8,
|
115
|
+
EGL_DEPTH_SIZE,
|
116
|
+
0,
|
117
|
+
EGL_STENCIL_SIZE,
|
118
|
+
0,
|
119
|
+
EGL_SAMPLE_BUFFERS,
|
120
|
+
0,
|
121
|
+
EGL_NONE};
|
122
|
+
|
123
|
+
EGLint numConfigs;
|
124
|
+
EGLConfig glConfig = 0;
|
125
|
+
if (eglChooseConfig(glDisplay, att, &glConfig, 1, &numConfigs) !=
|
126
|
+
EGL_TRUE ||
|
127
|
+
numConfigs == 0) {
|
128
|
+
RNSkLogger::logToConsole(
|
129
|
+
"Failed to choose a config for %s surface. Error code: %d\n",
|
130
|
+
eglGetError());
|
131
|
+
return 0;
|
132
|
+
}
|
133
|
+
|
134
|
+
return glConfig;
|
135
|
+
}
|
136
|
+
};
|
137
|
+
|
138
|
+
struct SkiaOpenGLContext {
|
139
|
+
SkiaOpenGLContext() {
|
140
|
+
glContext = EGL_NO_CONTEXT;
|
141
|
+
gl1x1Surface = EGL_NO_SURFACE;
|
142
|
+
directContext = nullptr;
|
143
|
+
}
|
144
|
+
~SkiaOpenGLContext() {
|
145
|
+
if (gl1x1Surface != EGL_NO_SURFACE) {
|
146
|
+
eglDestroySurface(OpenGLResourceHolder::getInstance().glDisplay,
|
147
|
+
gl1x1Surface);
|
148
|
+
gl1x1Surface = EGL_NO_SURFACE;
|
149
|
+
}
|
150
|
+
|
151
|
+
if (directContext) {
|
152
|
+
directContext->releaseResourcesAndAbandonContext();
|
153
|
+
directContext = nullptr;
|
154
|
+
}
|
155
|
+
|
156
|
+
if (glContext != EGL_NO_CONTEXT) {
|
157
|
+
eglDestroyContext(OpenGLResourceHolder::getInstance().glDisplay,
|
158
|
+
glContext);
|
159
|
+
glContext = EGL_NO_CONTEXT;
|
160
|
+
}
|
161
|
+
}
|
162
|
+
EGLContext glContext;
|
163
|
+
EGLSurface gl1x1Surface;
|
164
|
+
sk_sp<GrDirectContext> directContext;
|
165
|
+
};
|
166
|
+
|
167
|
+
class SkiaOpenGLHelper {
|
168
|
+
public:
|
169
|
+
/**
|
170
|
+
* Calls eglMakeCurrent on the surface provided using the provided
|
171
|
+
* thread context.
|
172
|
+
* @param context Skia OpenGL context to use
|
173
|
+
* @param surface Surface to set as current
|
174
|
+
* @return true if eglMakeCurrent was successfull
|
175
|
+
*/
|
176
|
+
static bool makeCurrent(SkiaOpenGLContext *context, EGLSurface glSurface) {
|
177
|
+
// We don't need to call make current if we already are current:
|
178
|
+
if (eglGetCurrentSurface(EGL_DRAW) != glSurface ||
|
179
|
+
eglGetCurrentSurface(EGL_READ) != glSurface ||
|
180
|
+
eglGetCurrentContext() != context->glContext) {
|
181
|
+
|
182
|
+
// Make current!
|
183
|
+
if (eglMakeCurrent(OpenGLResourceHolder::getInstance().glDisplay,
|
184
|
+
glSurface, glSurface,
|
185
|
+
context->glContext) != EGL_TRUE) {
|
186
|
+
RNSkLogger::logToConsole("eglMakeCurrent failed: %d\n", eglGetError());
|
187
|
+
return false;
|
188
|
+
}
|
189
|
+
return true;
|
190
|
+
}
|
191
|
+
return true;
|
192
|
+
}
|
193
|
+
|
194
|
+
/**
|
195
|
+
* Creates a new windowed surface
|
196
|
+
* @param window ANativeWindow to create surface in
|
197
|
+
* @return EGLSurface or EGL_NO_SURFACE if the call failed
|
198
|
+
*/
|
199
|
+
static EGLSurface createWindowedSurface(ANativeWindow *window) {
|
200
|
+
const EGLint attribs[] = {EGL_NONE};
|
201
|
+
return eglCreateWindowSurface(OpenGLResourceHolder::getInstance().glDisplay,
|
202
|
+
OpenGLResourceHolder::getInstance().glConfig,
|
203
|
+
window, attribs);
|
204
|
+
}
|
205
|
+
|
206
|
+
/**
|
207
|
+
* Destroys an egl surface
|
208
|
+
* @param glSurface
|
209
|
+
* @return
|
210
|
+
*/
|
211
|
+
static bool destroySurface(EGLSurface glSurface) {
|
212
|
+
if (eglMakeCurrent(OpenGLResourceHolder::getInstance().glDisplay,
|
213
|
+
EGL_NO_SURFACE, EGL_NO_SURFACE,
|
214
|
+
EGL_NO_CONTEXT) != EGL_TRUE) {
|
215
|
+
RNSkLogger::logToConsole(
|
216
|
+
"destroySurface: Could not clear selected surface");
|
217
|
+
return false;
|
218
|
+
}
|
219
|
+
return eglDestroySurface(OpenGLResourceHolder::getInstance().glDisplay,
|
220
|
+
glSurface) == EGL_TRUE;
|
221
|
+
}
|
222
|
+
|
223
|
+
/**
|
224
|
+
* Calls the eglSwapBuffer in the current thread with the provided surface
|
225
|
+
* @param context Thread context
|
226
|
+
* @param glSurface surface to present
|
227
|
+
* @return true if eglSwapBuffers succeeded.
|
228
|
+
*/
|
229
|
+
static bool swapBuffers(SkiaOpenGLContext *context, EGLSurface glSurface) {
|
230
|
+
if (eglSwapBuffers(OpenGLResourceHolder::getInstance().glDisplay,
|
231
|
+
glSurface) != EGL_TRUE) {
|
232
|
+
RNSkLogger::logToConsole("eglSwapBuffers failed: %d\n", eglGetError());
|
233
|
+
return false;
|
234
|
+
}
|
235
|
+
return true;
|
236
|
+
}
|
237
|
+
|
238
|
+
/***
|
239
|
+
* Creates a new Skia direct context backed by the provided eglContext in the
|
240
|
+
* SkiaOpenGLContext.
|
241
|
+
* @param context Context to store results in
|
242
|
+
* @param sharedContext Shared Context
|
243
|
+
* @return true if the call to create a skia direct context suceeded.
|
244
|
+
*/
|
245
|
+
static bool createSkiaDirectContextIfNecessary(SkiaOpenGLContext *context) {
|
246
|
+
if (context->directContext == nullptr) {
|
247
|
+
|
248
|
+
// Create OpenGL context
|
249
|
+
createOpenGLContext(context);
|
250
|
+
|
251
|
+
// Create attributes for a simple 1x1 pbuffer surface that we can
|
252
|
+
// use to activate and create Skia direct context for
|
253
|
+
const EGLint offScreenSurfaceAttribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1,
|
254
|
+
EGL_NONE};
|
255
|
+
|
256
|
+
context->gl1x1Surface =
|
257
|
+
eglCreatePbufferSurface(OpenGLResourceHolder::getInstance().glDisplay,
|
258
|
+
OpenGLResourceHolder::getInstance().glConfig,
|
259
|
+
offScreenSurfaceAttribs);
|
260
|
+
|
261
|
+
if (context->gl1x1Surface == EGL_NO_SURFACE) {
|
262
|
+
RNSkLogger::logToConsole("Failed creating a 1x1 pbuffer surface");
|
263
|
+
return false;
|
264
|
+
}
|
265
|
+
|
266
|
+
// Activate
|
267
|
+
if (!makeCurrent(context, context->gl1x1Surface)) {
|
268
|
+
return false;
|
269
|
+
}
|
270
|
+
|
271
|
+
// Create the Skia context
|
272
|
+
auto backendInterface = GrGLMakeNativeInterface();
|
273
|
+
context->directContext = GrDirectContext::MakeGL(backendInterface);
|
274
|
+
|
275
|
+
if (context->directContext == nullptr) {
|
276
|
+
RNSkLogger::logToConsole("GrDirectContext::MakeGL failed");
|
277
|
+
return false;
|
278
|
+
}
|
279
|
+
}
|
280
|
+
|
281
|
+
// It all went well!
|
282
|
+
return true;
|
283
|
+
}
|
284
|
+
|
285
|
+
private:
|
286
|
+
/**
|
287
|
+
* Creates a new GLContext.
|
288
|
+
* @param context Context to save results in
|
289
|
+
* @return True if the call to eglCreateContext returned a valid OpenGL
|
290
|
+
* Context or if the context already is setup.
|
291
|
+
*/
|
292
|
+
static bool createOpenGLContext(SkiaOpenGLContext *context) {
|
293
|
+
// Create OpenGL context attributes
|
294
|
+
EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
|
295
|
+
|
296
|
+
// Initialize the offscreen context for this thread
|
297
|
+
context->glContext = eglCreateContext(
|
298
|
+
OpenGLResourceHolder::getInstance().glDisplay,
|
299
|
+
OpenGLResourceHolder::getInstance().glConfig,
|
300
|
+
OpenGLResourceHolder::getInstance().glContext, contextAttribs);
|
301
|
+
|
302
|
+
if (context->glContext == EGL_NO_CONTEXT) {
|
303
|
+
RNSkLogger::logToConsole("eglCreateContext failed: %d\n", eglGetError());
|
304
|
+
return EGL_NO_CONTEXT;
|
305
|
+
}
|
306
|
+
|
307
|
+
return true;
|
308
|
+
}
|
309
|
+
};
|
310
|
+
} // namespace RNSkia
|
@@ -0,0 +1,132 @@
|
|
1
|
+
#include "SkiaOpenGLHelper.h"
|
2
|
+
#include <SkiaOpenGLSurfaceFactory.h>
|
3
|
+
|
4
|
+
namespace RNSkia {
|
5
|
+
|
6
|
+
thread_local SkiaOpenGLContext ThreadContextHolder::ThreadSkiaOpenGLContext;
|
7
|
+
|
8
|
+
sk_sp<SkSurface> SkiaOpenGLSurfaceFactory::makeOffscreenSurface(int width,
|
9
|
+
int height) {
|
10
|
+
// Setup OpenGL and Skia:
|
11
|
+
if (!SkiaOpenGLHelper::createSkiaDirectContextIfNecessary(
|
12
|
+
&ThreadContextHolder::ThreadSkiaOpenGLContext)) {
|
13
|
+
|
14
|
+
RNSkLogger::logToConsole(
|
15
|
+
"Could not create Skia Surface from native window / surface. "
|
16
|
+
"Failed creating Skia Direct Context");
|
17
|
+
return nullptr;
|
18
|
+
}
|
19
|
+
|
20
|
+
auto colorType = kN32_SkColorType;
|
21
|
+
|
22
|
+
SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
|
23
|
+
|
24
|
+
// Create texture
|
25
|
+
auto texture =
|
26
|
+
ThreadContextHolder::ThreadSkiaOpenGLContext.directContext
|
27
|
+
->createBackendTexture(width, height, colorType, GrMipMapped::kNo,
|
28
|
+
GrRenderable::kYes);
|
29
|
+
|
30
|
+
struct ReleaseContext {
|
31
|
+
SkiaOpenGLContext *context;
|
32
|
+
GrBackendTexture texture;
|
33
|
+
};
|
34
|
+
|
35
|
+
auto releaseCtx = new ReleaseContext(
|
36
|
+
{&ThreadContextHolder::ThreadSkiaOpenGLContext, texture});
|
37
|
+
|
38
|
+
// Create a SkSurface from the GrBackendTexture
|
39
|
+
return SkSurfaces::WrapBackendTexture(
|
40
|
+
ThreadContextHolder::ThreadSkiaOpenGLContext.directContext.get(), texture,
|
41
|
+
kTopLeft_GrSurfaceOrigin, 0, colorType, nullptr, &props,
|
42
|
+
[](void *addr) {
|
43
|
+
auto releaseCtx = reinterpret_cast<ReleaseContext *>(addr);
|
44
|
+
|
45
|
+
releaseCtx->context->directContext->deleteBackendTexture(
|
46
|
+
releaseCtx->texture);
|
47
|
+
},
|
48
|
+
releaseCtx);
|
49
|
+
}
|
50
|
+
|
51
|
+
sk_sp<SkSurface> WindowSurfaceHolder::getSurface() {
|
52
|
+
if (_skSurface == nullptr) {
|
53
|
+
|
54
|
+
// Setup OpenGL and Skia
|
55
|
+
if (!SkiaOpenGLHelper::createSkiaDirectContextIfNecessary(
|
56
|
+
&ThreadContextHolder::ThreadSkiaOpenGLContext)) {
|
57
|
+
RNSkLogger::logToConsole(
|
58
|
+
"Could not create Skia Surface from native window / surface. "
|
59
|
+
"Failed creating Skia Direct Context");
|
60
|
+
return nullptr;
|
61
|
+
}
|
62
|
+
|
63
|
+
// Now we can create a surface
|
64
|
+
_glSurface = SkiaOpenGLHelper::createWindowedSurface(_window);
|
65
|
+
if (_glSurface == EGL_NO_SURFACE) {
|
66
|
+
RNSkLogger::logToConsole(
|
67
|
+
"Could not create EGL Surface from native window / surface.");
|
68
|
+
return nullptr;
|
69
|
+
}
|
70
|
+
|
71
|
+
// Now make this one current
|
72
|
+
if (!SkiaOpenGLHelper::makeCurrent(
|
73
|
+
&ThreadContextHolder::ThreadSkiaOpenGLContext, _glSurface)) {
|
74
|
+
RNSkLogger::logToConsole(
|
75
|
+
"Could not create EGL Surface from native window / surface. Could "
|
76
|
+
"not set new surface as current surface.");
|
77
|
+
return nullptr;
|
78
|
+
}
|
79
|
+
|
80
|
+
// Set up parameters for the render target so that it
|
81
|
+
// matches the underlying OpenGL context.
|
82
|
+
GrGLFramebufferInfo fboInfo;
|
83
|
+
|
84
|
+
// We pass 0 as the framebuffer id, since the
|
85
|
+
// underlying Skia GrGlGpu will read this when wrapping the context in the
|
86
|
+
// render target and the GrGlGpu object.
|
87
|
+
fboInfo.fFBOID = 0;
|
88
|
+
fboInfo.fFormat = 0x8058; // GL_RGBA8
|
89
|
+
|
90
|
+
GLint stencil;
|
91
|
+
glGetIntegerv(GL_STENCIL_BITS, &stencil);
|
92
|
+
|
93
|
+
GLint samples;
|
94
|
+
glGetIntegerv(GL_SAMPLES, &samples);
|
95
|
+
|
96
|
+
auto colorType = kN32_SkColorType;
|
97
|
+
|
98
|
+
auto maxSamples =
|
99
|
+
ThreadContextHolder::ThreadSkiaOpenGLContext.directContext
|
100
|
+
->maxSurfaceSampleCountForColorType(colorType);
|
101
|
+
|
102
|
+
if (samples > maxSamples) {
|
103
|
+
samples = maxSamples;
|
104
|
+
}
|
105
|
+
|
106
|
+
GrBackendRenderTarget renderTarget(_width, _height, samples, stencil,
|
107
|
+
fboInfo);
|
108
|
+
|
109
|
+
SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
|
110
|
+
|
111
|
+
struct ReleaseContext {
|
112
|
+
EGLSurface glSurface;
|
113
|
+
};
|
114
|
+
|
115
|
+
auto releaseCtx = new ReleaseContext({_glSurface});
|
116
|
+
|
117
|
+
// Create surface object
|
118
|
+
_skSurface = SkSurfaces::WrapBackendRenderTarget(
|
119
|
+
ThreadContextHolder::ThreadSkiaOpenGLContext.directContext.get(),
|
120
|
+
renderTarget, kBottomLeft_GrSurfaceOrigin, colorType, nullptr, &props,
|
121
|
+
[](void *addr) {
|
122
|
+
auto releaseCtx = reinterpret_cast<ReleaseContext *>(addr);
|
123
|
+
SkiaOpenGLHelper::destroySurface(releaseCtx->glSurface);
|
124
|
+
delete releaseCtx;
|
125
|
+
},
|
126
|
+
reinterpret_cast<void *>(releaseCtx));
|
127
|
+
}
|
128
|
+
|
129
|
+
return _skSurface;
|
130
|
+
}
|
131
|
+
|
132
|
+
} // namespace RNSkia
|
@@ -0,0 +1,125 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
#include <RNSkLog.h>
|
4
|
+
|
5
|
+
#include <fbjni/fbjni.h>
|
6
|
+
#include <jni.h>
|
7
|
+
|
8
|
+
#include <android/native_window_jni.h>
|
9
|
+
#include <condition_variable>
|
10
|
+
#include <memory>
|
11
|
+
#include <thread>
|
12
|
+
#include <unordered_map>
|
13
|
+
|
14
|
+
#include "SkiaOpenGLHelper.h"
|
15
|
+
|
16
|
+
#pragma clang diagnostic push
|
17
|
+
#pragma clang diagnostic ignored "-Wdocumentation"
|
18
|
+
|
19
|
+
#include "SkCanvas.h"
|
20
|
+
#include "SkColorSpace.h"
|
21
|
+
#include "SkSurface.h"
|
22
|
+
#include "include/gpu/GrBackendSurface.h"
|
23
|
+
#include "include/gpu/GrDirectContext.h"
|
24
|
+
#include "include/gpu/ganesh/SkSurfaceGanesh.h"
|
25
|
+
#include "include/gpu/gl/GrGLInterface.h"
|
26
|
+
|
27
|
+
#pragma clang diagnostic pop
|
28
|
+
|
29
|
+
namespace RNSkia {
|
30
|
+
|
31
|
+
/**
|
32
|
+
* Holder of the thread local SkiaOpenGLContext member
|
33
|
+
*/
|
34
|
+
class ThreadContextHolder {
|
35
|
+
public:
|
36
|
+
static thread_local SkiaOpenGLContext ThreadSkiaOpenGLContext;
|
37
|
+
};
|
38
|
+
|
39
|
+
/**
|
40
|
+
* Holder of the Windowed SkSurface with support for making current
|
41
|
+
* and presenting to screen
|
42
|
+
*/
|
43
|
+
class WindowSurfaceHolder {
|
44
|
+
public:
|
45
|
+
WindowSurfaceHolder(jobject surface, int width, int height)
|
46
|
+
: _width(width), _height(height),
|
47
|
+
_window(ANativeWindow_fromSurface(facebook::jni::Environment::current(),
|
48
|
+
surface)) {}
|
49
|
+
|
50
|
+
~WindowSurfaceHolder() { ANativeWindow_release(_window); }
|
51
|
+
|
52
|
+
int getWidth() { return _width; }
|
53
|
+
int getHeight() { return _height; }
|
54
|
+
|
55
|
+
/*
|
56
|
+
* Ensures that the holder has a valid surface and returns the surface.
|
57
|
+
*/
|
58
|
+
sk_sp<SkSurface> getSurface();
|
59
|
+
|
60
|
+
/**
|
61
|
+
* Resizes the surface
|
62
|
+
* @param width
|
63
|
+
* @param height
|
64
|
+
*/
|
65
|
+
void resize(int width, int height) {
|
66
|
+
_width = width;
|
67
|
+
_height = height;
|
68
|
+
_skSurface = nullptr;
|
69
|
+
}
|
70
|
+
|
71
|
+
/**
|
72
|
+
* Sets the current surface as the active surface
|
73
|
+
* @return true if make current succeeds
|
74
|
+
*/
|
75
|
+
bool makeCurrent() {
|
76
|
+
return SkiaOpenGLHelper::makeCurrent(
|
77
|
+
&ThreadContextHolder::ThreadSkiaOpenGLContext, _glSurface);
|
78
|
+
}
|
79
|
+
|
80
|
+
/**
|
81
|
+
* Presents the current drawing operations by swapping buffers
|
82
|
+
* @return true if make current succeeds
|
83
|
+
*/
|
84
|
+
bool present() {
|
85
|
+
// Flush and submit the direct context
|
86
|
+
ThreadContextHolder::ThreadSkiaOpenGLContext.directContext
|
87
|
+
->flushAndSubmit();
|
88
|
+
|
89
|
+
// Swap buffers
|
90
|
+
return SkiaOpenGLHelper::swapBuffers(
|
91
|
+
&ThreadContextHolder::ThreadSkiaOpenGLContext, _glSurface);
|
92
|
+
}
|
93
|
+
|
94
|
+
private:
|
95
|
+
ANativeWindow *_window = nullptr;
|
96
|
+
sk_sp<SkSurface> _skSurface = nullptr;
|
97
|
+
EGLSurface _glSurface = EGL_NO_SURFACE;
|
98
|
+
int _width = 0;
|
99
|
+
int _height = 0;
|
100
|
+
};
|
101
|
+
|
102
|
+
class SkiaOpenGLSurfaceFactory {
|
103
|
+
public:
|
104
|
+
/**
|
105
|
+
* Creates a new Skia surface that is backed by a texture.
|
106
|
+
* @param width Width of surface
|
107
|
+
* @param height Height of surface
|
108
|
+
* @return An SkSurface backed by a texture.
|
109
|
+
*/
|
110
|
+
static sk_sp<SkSurface> makeOffscreenSurface(int width, int height);
|
111
|
+
|
112
|
+
/**
|
113
|
+
* Creates a windowed Skia Surface holder.
|
114
|
+
* @param width Initial width of surface
|
115
|
+
* @param height Initial height of surface
|
116
|
+
* @param window Window coming from Java
|
117
|
+
* @return A Surface holder
|
118
|
+
*/
|
119
|
+
static std::unique_ptr<WindowSurfaceHolder>
|
120
|
+
makeWindowedSurface(jobject window, int width, int height) {
|
121
|
+
return std::make_unique<WindowSurfaceHolder>(window, width, height);
|
122
|
+
}
|
123
|
+
};
|
124
|
+
|
125
|
+
} // namespace RNSkia
|