Flutter Engine
The Flutter Engine
Surface.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2021 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
8
9#include <android/bitmap.h>
10#include <android/log.h>
11
16
17WindowSurface::WindowSurface(ANativeWindow* win, std::unique_ptr<skwindow::WindowContext> wctx)
18 : fWindow(win)
19 , fWindowContext(std::move(wctx))
20{
21 SkASSERT(fWindow);
22 SkASSERT(fWindowContext);
23
24 fSurface = fWindowContext->getBackbufferSurface();
25}
26
27void WindowSurface::release(JNIEnv* env) {
28 fWindowContext.reset();
29 ANativeWindow_release(fWindow);
30}
31
32SkCanvas* WindowSurface::getCanvas() {
33 if (fSurface) {
34 return fSurface->getCanvas();
35 }
36 return nullptr;
37}
38
39void WindowSurface::flushAndSubmit() {
41 fWindowContext->swapBuffers();
42 fSurface = fWindowContext->getBackbufferSurface();
43}
44
45// SkSurface created from being passed an android.view.Surface
46// For now, assume we are always rendering with OpenGL
47// TODO: add option of choose backing
49 : fThread(std::make_unique<SurfaceThread>()) {
50 ANativeWindow* window = ANativeWindow_fromSurface(env, surface);
51 fWidth = ANativeWindow_getWidth(window);
52 fHeight = ANativeWindow_getHeight(window);
53
55 message.fNativeWindow = window;
56 message.fWindowSurface = &fWindowSurface;
57 fThread->postMessage(message);
58}
59
60void ThreadedSurface::release(JNIEnv* env) {
62 message.fWindowSurface = &fWindowSurface;
63 fThread->postMessage(message);
64 fThread->release();
65}
66
67SkCanvas* ThreadedSurface::getCanvas() {
68 return fRecorder.beginRecording(fWidth,
69 fHeight);
70}
71
72void ThreadedSurface::flushAndSubmit() {
74 message.fWindowSurface = &fWindowSurface;
75 message.fPicture = fRecorder.finishRecordingAsPicture().release();
76 fThread->postMessage(message);
77}
78
79namespace {
80
81class BitmapSurface final : public Surface {
82public:
83 BitmapSurface(JNIEnv* env, jobject bitmap) {
84 AndroidBitmapInfo bm_info;
85 if (AndroidBitmap_getInfo(env, bitmap, &bm_info) != ANDROID_BITMAP_RESULT_SUCCESS) {
86 return;
87 }
88
89 const auto info = SkImageInfo::Make(bm_info.width, bm_info.height,
90 color_type(bm_info.format), alpha_type(bm_info.flags));
91
92 void* pixels;
93 if (AndroidBitmap_lockPixels(env, bitmap, &pixels) != ANDROID_BITMAP_RESULT_SUCCESS) {
94 return;
95 }
96
97 fSurface = SkSurfaces::WrapPixels(info, pixels, bm_info.stride);
98 if (!fSurface) {
99 AndroidBitmap_unlockPixels(env, bitmap);
100 return;
101 }
102
103 fBitmap = env->NewGlobalRef(bitmap);
104 }
105
106private:
107 void release(JNIEnv* env) override {
108 if (fSurface) {
109 AndroidBitmap_unlockPixels(env, fBitmap);
110 fSurface.reset();
111 env->DeleteGlobalRef(fBitmap);
112 }
113 }
114
115 SkCanvas* getCanvas() override {
116 if (fSurface) {
117 return fSurface->getCanvas();
118 }
119 return nullptr;
120 }
121
122 void flushAndSubmit() override {
123 // Nothing to do.
124 }
125
126 static SkColorType color_type(int32_t format) {
127 switch (format) {
128 case ANDROID_BITMAP_FORMAT_RGBA_8888: return kRGBA_8888_SkColorType;
129 case ANDROID_BITMAP_FORMAT_RGB_565: return kRGB_565_SkColorType;
130 case ANDROID_BITMAP_FORMAT_RGBA_4444: return kARGB_4444_SkColorType;
131 case ANDROID_BITMAP_FORMAT_RGBA_F16: return kRGBA_F16_SkColorType;
132 case ANDROID_BITMAP_FORMAT_A_8: return kAlpha_8_SkColorType;
133 default: break;
134 }
135
137 }
138
139 static SkAlphaType alpha_type(int32_t flags) {
140 switch ((flags >> ANDROID_BITMAP_FLAGS_ALPHA_SHIFT) & ANDROID_BITMAP_FLAGS_ALPHA_MASK) {
141 case ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE: return kOpaque_SkAlphaType;
142 case ANDROID_BITMAP_FLAGS_ALPHA_PREMUL: return kPremul_SkAlphaType;
143 case ANDROID_BITMAP_FLAGS_ALPHA_UNPREMUL: return kUnpremul_SkAlphaType;
144 default: break;
145 }
146
148 }
149
150 jobject fBitmap;
151};
152
153// *** JNI methods ***
154
155static jlong Surface_CreateBitmap(JNIEnv* env, jobject, jobject bitmap) {
156 return reinterpret_cast<jlong>(new BitmapSurface(env, bitmap));
157}
158
159static jlong Surface_CreateThreadedSurface(JNIEnv* env, jobject, jobject surface) {
160 return reinterpret_cast<jlong>(new ThreadedSurface(env, surface));
161}
162
163static jlong Surface_CreateVK(JNIEnv* env, jobject, jobject jsurface) {
164#ifdef SK_VULKAN
165 auto* win = ANativeWindow_fromSurface(env, jsurface);
166 if (!win) {
167 return 0;
168 }
169
170 // TODO: match window params?
172 auto winctx = skwindow::MakeVulkanForAndroid(win, params);
173 if (!winctx) {
174 return 0;
175 }
176
177 return reinterpret_cast<jlong>(sk_make_sp<WindowSurface>(win, std::move(winctx)).release());
178#else
179 return 0;
180#endif // SK_VULKAN
181}
182
183static jlong Surface_CreateGL(JNIEnv* env, jobject, jobject jsurface) {
184#ifdef SK_GL
185 auto* win = ANativeWindow_fromSurface(env, jsurface);
186 if (!win) {
187 return 0;
188 }
189
190 // TODO: match window params?
192 auto winctx = skwindow::MakeGLForAndroid(win, params);
193 if (!winctx) {
194 return 0;
195 }
196
197 return reinterpret_cast<jlong>(sk_make_sp<WindowSurface>(win, std::move(winctx)).release());
198#else // SK_GL
199 return 0;
200#endif
201}
202
203static void Surface_Release(JNIEnv* env, jobject, jlong native_surface) {
204 if (auto* surface = reinterpret_cast<Surface*>(native_surface)) {
205 surface->release(env);
207 }
208}
209
210static jlong Surface_GetNativeCanvas(JNIEnv* env, jobject, jlong native_surface) {
211 auto* surface = reinterpret_cast<Surface*>(native_surface);
212 return surface
213 ? reinterpret_cast<jlong>(surface->getCanvas())
214 : 0;
215}
216
217static void Surface_FlushAndSubmit(JNIEnv* env, jobject, jlong native_surface) {
218 if (auto* surface = reinterpret_cast<Surface*>(native_surface)) {
219 surface->flushAndSubmit();
220 }
221}
222
223static jint Surface_GetWidth(JNIEnv* env, jobject, jlong native_surface) {
224 const auto* surface = reinterpret_cast<Surface*>(native_surface);
225 return surface ? surface->width() : 0;
226}
227
228static jint Surface_GetHeight(JNIEnv* env, jobject, jlong native_surface) {
229 const auto* surface = reinterpret_cast<Surface*>(native_surface);
230 return surface ? surface->height() : 0;
231}
232
233static jlong Surface_MakeSnapshot(JNIEnv* env, jobject, jlong native_surface) {
234 if (const auto* surface = reinterpret_cast<Surface*>(native_surface)) {
235 auto snapshot = surface->makeImageSnapshot();
236 return reinterpret_cast<jlong>(snapshot.release());
237 }
238
239 return 0;
240}
241
242// *** End of JNI methods ***
243
244} // namespace
245
247 static const JNINativeMethod methods[] = {
248 {"nCreateBitmap" , "(Landroid/graphics/Bitmap;)J",
249 reinterpret_cast<void*>(Surface_CreateBitmap) },
250 {"nCreateThreadedSurface" , "(Landroid/view/Surface;)J",
251 reinterpret_cast<void*>(Surface_CreateThreadedSurface) },
252 {"nCreateVKSurface" , "(Landroid/view/Surface;)J",
253 reinterpret_cast<void*>(Surface_CreateVK) },
254 {"nCreateGLSurface" , "(Landroid/view/Surface;)J",
255 reinterpret_cast<void*>(Surface_CreateGL) },
256 {"nRelease" , "(J)V", reinterpret_cast<void*>(Surface_Release) },
257 {"nGetNativeCanvas" , "(J)J", reinterpret_cast<void*>(Surface_GetNativeCanvas)},
258 {"nFlushAndSubmit" , "(J)V", reinterpret_cast<void*>(Surface_FlushAndSubmit) },
259 {"nGetWidth" , "(J)I", reinterpret_cast<void*>(Surface_GetWidth) },
260 {"nGetHeight" , "(J)I", reinterpret_cast<void*>(Surface_GetHeight) },
261 {"nMakeImageSnapshot", "(J)J", reinterpret_cast<void*>(Surface_MakeSnapshot) },
262 };
263
264 const auto clazz = env->FindClass("org/skia/jetski/Surface");
265 return clazz
266 ? env->RegisterNatives(clazz, methods, std::size(methods))
267 : JNI_ERR;
268}
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
kUnpremul_SkAlphaType
SkAlphaType
Definition: SkAlphaType.h:26
@ kUnknown_SkAlphaType
uninitialized
Definition: SkAlphaType.h:27
@ kOpaque_SkAlphaType
pixel is opaque
Definition: SkAlphaType.h:28
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
#define SkASSERT(cond)
Definition: SkAssert.h:116
SkColorType
Definition: SkColorType.h:19
@ kARGB_4444_SkColorType
pixel with 4 bits for alpha, red, green, blue; in 16-bit word
Definition: SkColorType.h:23
@ kRGBA_F16_SkColorType
pixel with half floats for red, green, blue, alpha;
Definition: SkColorType.h:38
@ kAlpha_8_SkColorType
pixel with alpha in 8-bit byte
Definition: SkColorType.h:21
@ kRGB_565_SkColorType
pixel with 5 bits red, 6 bits green, 5 bits blue, in 16-bit word
Definition: SkColorType.h:22
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition: SkColorType.h:24
@ kUnknown_SkColorType
uninitialized
Definition: SkColorType.h:20
static void SkSafeUnref(T *obj)
Definition: SkRefCnt.h:149
@ kRenderPicture
Definition: SurfaceThread.h:25
@ kInitialize
Definition: SurfaceThread.h:23
@ kDestroy
Definition: SurfaceThread.h:24
int register_jetski_Surface(JNIEnv *env)
Definition: Surface.cpp:246
SkCanvas * beginRecording(const SkRect &bounds, sk_sp< SkBBoxHierarchy > bbh)
sk_sp< SkPicture > finishRecordingAsPicture()
SkCanvas * getCanvas()
Definition: SkSurface.cpp:82
virtual SkCanvas * getCanvas()=0
virtual void release(JNIEnv *)=0
sk_sp< SkSurface > fSurface
Definition: Surface.h:43
virtual void flushAndSubmit()=0
ThreadedSurface(JNIEnv *env, jobject surface)
Definition: Surface.cpp:48
WindowSurface(ANativeWindow *win, std::unique_ptr< skwindow::WindowContext > wctx)
Definition: Surface.cpp:17
T * release()
Definition: SkRefCnt.h:324
const EmbeddedViewParams * params
GLFWwindow * window
Definition: main.cc:45
VkSurfaceKHR surface
Definition: main.cc:49
FlutterSemanticsFlag flags
uint32_t uint32_t * format
Win32Message message
SK_API sk_sp< SkSurface > WrapPixels(const SkImageInfo &imageInfo, void *pixels, size_t rowBytes, const SkSurfaceProps *surfaceProps=nullptr)
Definition: bitmap.py:1
Definition: __init__.py:1
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
SK_API void FlushAndSubmit(sk_sp< SkSurface >)
std::unique_ptr< WindowContext > MakeGLForAndroid(ANativeWindow *window, const DisplayParams &params)
std::unique_ptr< WindowContext > MakeVulkanForAndroid(ANativeWindow *window, const DisplayParams &params)
Definition: ref_ptr.h:256
uint32_t color_type
uint32_t alpha_type
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
struct ANativeWindow ANativeWindow