• 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/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