• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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