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 */
7 #include "modules/androidkit/src/Surface.h"
8
9 #include <android/bitmap.h>
10 #include <android/log.h>
11
12 #include "tools/sk_app/Application.h"
13 #include "tools/sk_app/DisplayParams.h"
14 #include "tools/sk_app/android/WindowContextFactory_android.h"
15
16 namespace sk_app {
17 // Required to appease the dynamic linker.
18 // TODO: split WindowContext from sk_app.
Create(int argc,char ** argv,void * platformData)19 Application* Application::Create(int argc, char** argv, void* platformData) {
20 return nullptr;
21 }
22 }
23
WindowSurface(ANativeWindow * win,std::unique_ptr<sk_app::WindowContext> wctx)24 WindowSurface::WindowSurface(ANativeWindow* win, std::unique_ptr<sk_app::WindowContext> wctx)
25 : fWindow(win)
26 , fWindowContext(std::move(wctx))
27 {
28 SkASSERT(fWindow);
29 SkASSERT(fWindowContext);
30
31 fSurface = fWindowContext->getBackbufferSurface();
32 }
33
release(JNIEnv * env)34 void WindowSurface::release(JNIEnv* env) {
35 fWindowContext.reset();
36 ANativeWindow_release(fWindow);
37 }
38
getCanvas()39 SkCanvas* WindowSurface::getCanvas() {
40 if (fSurface) {
41 return fSurface->getCanvas();
42 }
43 return nullptr;
44 }
45
flushAndSubmit()46 void WindowSurface::flushAndSubmit() {
47 fSurface->flushAndSubmit();
48 fWindowContext->swapBuffers();
49 fSurface = fWindowContext->getBackbufferSurface();
50 }
51
52 // SkSurface created from being passed an android.view.Surface
53 // For now, assume we are always rendering with OpenGL
54 // TODO: add option of choose backing
ThreadedSurface(JNIEnv * env,jobject surface)55 ThreadedSurface::ThreadedSurface(JNIEnv* env, jobject surface)
56 : fThread(std::make_unique<SurfaceThread>()) {
57 ANativeWindow* window = ANativeWindow_fromSurface(env, surface);
58 fWidth = ANativeWindow_getWidth(window);
59 fHeight = ANativeWindow_getHeight(window);
60
61 Message message(kInitialize);
62 message.fNativeWindow = window;
63 message.fWindowSurface = &fWindowSurface;
64 fThread->postMessage(message);
65 }
66
release(JNIEnv * env)67 void ThreadedSurface::release(JNIEnv* env) {
68 Message message(kDestroy);
69 message.fWindowSurface = &fWindowSurface;
70 fThread->postMessage(message);
71 fThread->release();
72 }
73
getCanvas()74 SkCanvas* ThreadedSurface::getCanvas() {
75 return fRecorder.beginRecording(fWidth,
76 fHeight);
77 }
78
flushAndSubmit()79 void ThreadedSurface::flushAndSubmit() {
80 Message message(kRenderPicture);
81 message.fWindowSurface = &fWindowSurface;
82 message.fPicture = fRecorder.finishRecordingAsPicture().release();
83 fThread->postMessage(message);
84 }
85
86 namespace {
87
88 class BitmapSurface final : public Surface {
89 public:
BitmapSurface(JNIEnv * env,jobject bitmap)90 BitmapSurface(JNIEnv* env, jobject bitmap) {
91 AndroidBitmapInfo bm_info;
92 if (AndroidBitmap_getInfo(env, bitmap, &bm_info) != ANDROID_BITMAP_RESULT_SUCCESS) {
93 return;
94 }
95
96 const auto info = SkImageInfo::Make(bm_info.width, bm_info.height,
97 color_type(bm_info.format), alpha_type(bm_info.flags));
98
99 void* pixels;
100 if (AndroidBitmap_lockPixels(env, bitmap, &pixels) != ANDROID_BITMAP_RESULT_SUCCESS) {
101 return;
102 }
103
104 fSurface = SkSurface::MakeRasterDirect(info, pixels, bm_info.stride);
105 if (!fSurface) {
106 AndroidBitmap_unlockPixels(env, bitmap);
107 return;
108 }
109
110 fBitmap = env->NewGlobalRef(bitmap);
111 }
112
113 private:
release(JNIEnv * env)114 void release(JNIEnv* env) override {
115 if (fSurface) {
116 AndroidBitmap_unlockPixels(env, fBitmap);
117 fSurface.reset();
118 env->DeleteGlobalRef(fBitmap);
119 }
120 }
121
getCanvas()122 SkCanvas* getCanvas() override {
123 if (fSurface) {
124 return fSurface->getCanvas();
125 }
126 return nullptr;
127 }
128
flushAndSubmit()129 void flushAndSubmit() override {
130 // Nothing to do.
131 }
132
color_type(int32_t format)133 static SkColorType color_type(int32_t format) {
134 switch (format) {
135 case ANDROID_BITMAP_FORMAT_RGBA_8888: return kRGBA_8888_SkColorType;
136 case ANDROID_BITMAP_FORMAT_RGB_565: return kRGB_565_SkColorType;
137 case ANDROID_BITMAP_FORMAT_RGBA_4444: return kARGB_4444_SkColorType;
138 case ANDROID_BITMAP_FORMAT_RGBA_F16: return kRGBA_F16_SkColorType;
139 case ANDROID_BITMAP_FORMAT_A_8: return kAlpha_8_SkColorType;
140 default: break;
141 }
142
143 return kUnknown_SkColorType;
144 }
145
alpha_type(int32_t flags)146 static SkAlphaType alpha_type(int32_t flags) {
147 switch ((flags >> ANDROID_BITMAP_FLAGS_ALPHA_SHIFT) & ANDROID_BITMAP_FLAGS_ALPHA_MASK) {
148 case ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE: return kOpaque_SkAlphaType;
149 case ANDROID_BITMAP_FLAGS_ALPHA_PREMUL: return kPremul_SkAlphaType;
150 case ANDROID_BITMAP_FLAGS_ALPHA_UNPREMUL: return kUnpremul_SkAlphaType;
151 default: break;
152 }
153
154 return kUnknown_SkAlphaType;
155 }
156
157 jobject fBitmap;
158 };
159
160 // *** JNI methods ***
161
Surface_CreateBitmap(JNIEnv * env,jobject,jobject bitmap)162 static jlong Surface_CreateBitmap(JNIEnv* env, jobject, jobject bitmap) {
163 return reinterpret_cast<jlong>(new BitmapSurface(env, bitmap));
164 }
165
Surface_CreateThreadedSurface(JNIEnv * env,jobject,jobject surface)166 static jlong Surface_CreateThreadedSurface(JNIEnv* env, jobject, jobject surface) {
167 return reinterpret_cast<jlong>(new ThreadedSurface(env, surface));
168 }
169
Surface_CreateVK(JNIEnv * env,jobject,jobject jsurface)170 static jlong Surface_CreateVK(JNIEnv* env, jobject, jobject jsurface) {
171 #ifdef SK_VULKAN
172 auto* win = ANativeWindow_fromSurface(env, jsurface);
173 if (!win) {
174 return 0;
175 }
176
177 // TODO: match window params?
178 sk_app::DisplayParams params;
179 auto winctx = sk_app::window_context_factory::MakeVulkanForAndroid(win, params);
180 if (!winctx) {
181 return 0;
182 }
183
184 return reinterpret_cast<jlong>(sk_make_sp<WindowSurface>(win, std::move(winctx)).release());
185 #endif // SK_VULKAN
186 return 0;
187 }
188
Surface_CreateGL(JNIEnv * env,jobject,jobject jsurface)189 static jlong Surface_CreateGL(JNIEnv* env, jobject, jobject jsurface) {
190 #ifdef SK_GL
191 auto* win = ANativeWindow_fromSurface(env, jsurface);
192 if (!win) {
193 return 0;
194 }
195
196 // TODO: match window params?
197 sk_app::DisplayParams params;
198 auto winctx = sk_app::window_context_factory::MakeGLForAndroid(win, params);
199 if (!winctx) {
200 return 0;
201 }
202
203 return reinterpret_cast<jlong>(sk_make_sp<WindowSurface>(win, std::move(winctx)).release());
204 #endif // SK_GL
205 return 0;
206 }
207
Surface_Release(JNIEnv * env,jobject,jlong native_surface)208 static void Surface_Release(JNIEnv* env, jobject, jlong native_surface) {
209 if (auto* surface = reinterpret_cast<Surface*>(native_surface)) {
210 surface->release(env);
211 SkSafeUnref(surface);
212 }
213 }
214
Surface_GetNativeCanvas(JNIEnv * env,jobject,jlong native_surface)215 static jlong Surface_GetNativeCanvas(JNIEnv* env, jobject, jlong native_surface) {
216 auto* surface = reinterpret_cast<Surface*>(native_surface);
217 return surface
218 ? reinterpret_cast<jlong>(surface->getCanvas())
219 : 0;
220 }
221
Surface_FlushAndSubmit(JNIEnv * env,jobject,jlong native_surface)222 static void Surface_FlushAndSubmit(JNIEnv* env, jobject, jlong native_surface) {
223 if (auto* surface = reinterpret_cast<Surface*>(native_surface)) {
224 surface->flushAndSubmit();
225 }
226 }
227
Surface_GetWidth(JNIEnv * env,jobject,jlong native_surface)228 static jint Surface_GetWidth(JNIEnv* env, jobject, jlong native_surface) {
229 const auto* surface = reinterpret_cast<Surface*>(native_surface);
230 return surface ? surface->width() : 0;
231 }
232
Surface_GetHeight(JNIEnv * env,jobject,jlong native_surface)233 static jint Surface_GetHeight(JNIEnv* env, jobject, jlong native_surface) {
234 const auto* surface = reinterpret_cast<Surface*>(native_surface);
235 return surface ? surface->height() : 0;
236 }
237
Surface_MakeSnapshot(JNIEnv * env,jobject,jlong native_surface)238 static jlong Surface_MakeSnapshot(JNIEnv* env, jobject, jlong native_surface) {
239 if (const auto* surface = reinterpret_cast<Surface*>(native_surface)) {
240 auto snapshot = surface->makeImageSnapshot();
241 return reinterpret_cast<jlong>(snapshot.release());
242 }
243
244 return 0;
245 }
246
247 // *** End of JNI methods ***
248
249 } // namespace
250
register_androidkit_Surface(JNIEnv * env)251 int register_androidkit_Surface(JNIEnv* env) {
252 static const JNINativeMethod methods[] = {
253 {"nCreateBitmap" , "(Landroid/graphics/Bitmap;)J",
254 reinterpret_cast<void*>(Surface_CreateBitmap) },
255 {"nCreateThreadedSurface" , "(Landroid/view/Surface;)J",
256 reinterpret_cast<void*>(Surface_CreateThreadedSurface) },
257 {"nCreateVKSurface" , "(Landroid/view/Surface;)J",
258 reinterpret_cast<void*>(Surface_CreateVK) },
259 {"nCreateGLSurface" , "(Landroid/view/Surface;)J",
260 reinterpret_cast<void*>(Surface_CreateGL) },
261 {"nRelease" , "(J)V", reinterpret_cast<void*>(Surface_Release) },
262 {"nGetNativeCanvas" , "(J)J", reinterpret_cast<void*>(Surface_GetNativeCanvas)},
263 {"nFlushAndSubmit" , "(J)V", reinterpret_cast<void*>(Surface_FlushAndSubmit) },
264 {"nGetWidth" , "(J)I", reinterpret_cast<void*>(Surface_GetWidth) },
265 {"nGetHeight" , "(J)I", reinterpret_cast<void*>(Surface_GetHeight) },
266 {"nMakeImageSnapshot", "(J)J", reinterpret_cast<void*>(Surface_MakeSnapshot) },
267 };
268
269 const auto clazz = env->FindClass("org/skia/androidkit/Surface");
270 return clazz
271 ? env->RegisterNatives(clazz, methods, SK_ARRAY_COUNT(methods))
272 : JNI_ERR;
273 }
274