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 "include/gpu/ganesh/SkSurfaceGanesh.h"
13 #include "include/core/SkPicture.h"
14 #include "tools/window/DisplayParams.h"
15 #include "tools/window/android/WindowContextFactory_android.h"
16
WindowSurface(ANativeWindow * win,std::unique_ptr<skwindow::WindowContext> wctx)17 WindowSurface::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
release(JNIEnv * env)27 void WindowSurface::release(JNIEnv* env) {
28 fWindowContext.reset();
29 ANativeWindow_release(fWindow);
30 }
31
getCanvas()32 SkCanvas* WindowSurface::getCanvas() {
33 if (fSurface) {
34 return fSurface->getCanvas();
35 }
36 return nullptr;
37 }
38
flushAndSubmit()39 void WindowSurface::flushAndSubmit() {
40 skgpu::ganesh::FlushAndSubmit(fSurface);
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
ThreadedSurface(JNIEnv * env,jobject surface)48 ThreadedSurface::ThreadedSurface(JNIEnv* env, jobject surface)
49 : fThread(std::make_unique<SurfaceThread>()) {
50 ANativeWindow* window = ANativeWindow_fromSurface(env, surface);
51 fWidth = ANativeWindow_getWidth(window);
52 fHeight = ANativeWindow_getHeight(window);
53
54 Message message(kInitialize);
55 message.fNativeWindow = window;
56 message.fWindowSurface = &fWindowSurface;
57 fThread->postMessage(message);
58 }
59
release(JNIEnv * env)60 void ThreadedSurface::release(JNIEnv* env) {
61 Message message(kDestroy);
62 message.fWindowSurface = &fWindowSurface;
63 fThread->postMessage(message);
64 fThread->release();
65 }
66
getCanvas()67 SkCanvas* ThreadedSurface::getCanvas() {
68 return fRecorder.beginRecording(fWidth,
69 fHeight);
70 }
71
flushAndSubmit()72 void ThreadedSurface::flushAndSubmit() {
73 Message message(kRenderPicture);
74 message.fWindowSurface = &fWindowSurface;
75 message.fPicture = fRecorder.finishRecordingAsPicture().release();
76 fThread->postMessage(message);
77 }
78
79 namespace {
80
81 class BitmapSurface final : public Surface {
82 public:
BitmapSurface(JNIEnv * env,jobject bitmap)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
106 private:
release(JNIEnv * env)107 void release(JNIEnv* env) override {
108 if (fSurface) {
109 AndroidBitmap_unlockPixels(env, fBitmap);
110 fSurface.reset();
111 env->DeleteGlobalRef(fBitmap);
112 }
113 }
114
getCanvas()115 SkCanvas* getCanvas() override {
116 if (fSurface) {
117 return fSurface->getCanvas();
118 }
119 return nullptr;
120 }
121
flushAndSubmit()122 void flushAndSubmit() override {
123 // Nothing to do.
124 }
125
color_type(int32_t format)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
136 return kUnknown_SkColorType;
137 }
138
alpha_type(int32_t flags)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
147 return kUnknown_SkAlphaType;
148 }
149
150 jobject fBitmap;
151 };
152
153 // *** JNI methods ***
154
Surface_CreateBitmap(JNIEnv * env,jobject,jobject bitmap)155 static jlong Surface_CreateBitmap(JNIEnv* env, jobject, jobject bitmap) {
156 return reinterpret_cast<jlong>(new BitmapSurface(env, bitmap));
157 }
158
Surface_CreateThreadedSurface(JNIEnv * env,jobject,jobject surface)159 static jlong Surface_CreateThreadedSurface(JNIEnv* env, jobject, jobject surface) {
160 return reinterpret_cast<jlong>(new ThreadedSurface(env, surface));
161 }
162
Surface_CreateVK(JNIEnv * env,jobject,jobject jsurface)163 static 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?
171 auto winctx = skwindow::MakeVulkanForAndroid(win, skwindow::DisplayParamsBuilder().build());
172 if (!winctx) {
173 return 0;
174 }
175
176 return reinterpret_cast<jlong>(sk_make_sp<WindowSurface>(win, std::move(winctx)).release());
177 #else
178 return 0;
179 #endif // SK_VULKAN
180 }
181
Surface_CreateGL(JNIEnv * env,jobject,jobject jsurface)182 static jlong Surface_CreateGL(JNIEnv* env, jobject, jobject jsurface) {
183 #ifdef SK_GL
184 auto* win = ANativeWindow_fromSurface(env, jsurface);
185 if (!win) {
186 return 0;
187 }
188
189 // TODO: match window params?
190 auto winctx = skwindow::MakeGLForAndroid(win, skwindow::DisplayParamsBuilder().build());
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