@shopify/react-native-skia 0.1.199 → 0.1.201
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/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
|