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