• 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 "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     skwindow::DisplayParams params;
172     auto winctx = skwindow::MakeVulkanForAndroid(win, params);
173     if (!winctx) {
174         return 0;
175     }
176 
177     return reinterpret_cast<jlong>(sk_make_sp<WindowSurface>(win, std::move(winctx)).release());
178 #else
179     return 0;
180 #endif // SK_VULKAN
181 }
182 
Surface_CreateGL(JNIEnv * env,jobject,jobject jsurface)183 static jlong Surface_CreateGL(JNIEnv* env, jobject, jobject jsurface) {
184 #ifdef SK_GL
185     auto* win = ANativeWindow_fromSurface(env, jsurface);
186     if (!win) {
187         return 0;
188     }
189 
190     // TODO: match window params?
191     skwindow::DisplayParams params;
192     auto winctx = skwindow::MakeGLForAndroid(win, params);
193     if (!winctx) {
194         return 0;
195     }
196 
197     return reinterpret_cast<jlong>(sk_make_sp<WindowSurface>(win, std::move(winctx)).release());
198 #else // SK_GL
199     return 0;
200 #endif
201 }
202 
Surface_Release(JNIEnv * env,jobject,jlong native_surface)203 static void Surface_Release(JNIEnv* env, jobject, jlong native_surface) {
204     if (auto* surface = reinterpret_cast<Surface*>(native_surface)) {
205         surface->release(env);
206         SkSafeUnref(surface);
207     }
208 }
209 
Surface_GetNativeCanvas(JNIEnv * env,jobject,jlong native_surface)210 static jlong Surface_GetNativeCanvas(JNIEnv* env, jobject, jlong native_surface) {
211     auto* surface = reinterpret_cast<Surface*>(native_surface);
212     return surface
213         ? reinterpret_cast<jlong>(surface->getCanvas())
214         : 0;
215 }
216 
Surface_FlushAndSubmit(JNIEnv * env,jobject,jlong native_surface)217 static void Surface_FlushAndSubmit(JNIEnv* env, jobject, jlong native_surface) {
218     if (auto* surface = reinterpret_cast<Surface*>(native_surface)) {
219         surface->flushAndSubmit();
220     }
221 }
222 
Surface_GetWidth(JNIEnv * env,jobject,jlong native_surface)223 static jint Surface_GetWidth(JNIEnv* env, jobject, jlong native_surface) {
224     const auto* surface = reinterpret_cast<Surface*>(native_surface);
225     return surface ? surface->width() : 0;
226 }
227 
Surface_GetHeight(JNIEnv * env,jobject,jlong native_surface)228 static jint Surface_GetHeight(JNIEnv* env, jobject, jlong native_surface) {
229     const auto* surface = reinterpret_cast<Surface*>(native_surface);
230     return surface ? surface->height() : 0;
231 }
232 
Surface_MakeSnapshot(JNIEnv * env,jobject,jlong native_surface)233 static jlong Surface_MakeSnapshot(JNIEnv* env, jobject, jlong native_surface) {
234     if (const auto* surface = reinterpret_cast<Surface*>(native_surface)) {
235         auto snapshot = surface->makeImageSnapshot();
236         return reinterpret_cast<jlong>(snapshot.release());
237     }
238 
239     return 0;
240 }
241 
242 // *** End of JNI methods ***
243 
244 }  // namespace
245 
register_jetski_Surface(JNIEnv * env)246 int register_jetski_Surface(JNIEnv* env) {
247     static const JNINativeMethod methods[] = {
248         {"nCreateBitmap"     , "(Landroid/graphics/Bitmap;)J",
249             reinterpret_cast<void*>(Surface_CreateBitmap)                              },
250         {"nCreateThreadedSurface"  , "(Landroid/view/Surface;)J",
251             reinterpret_cast<void*>(Surface_CreateThreadedSurface)                     },
252         {"nCreateVKSurface"  , "(Landroid/view/Surface;)J",
253             reinterpret_cast<void*>(Surface_CreateVK)                                  },
254         {"nCreateGLSurface"  , "(Landroid/view/Surface;)J",
255             reinterpret_cast<void*>(Surface_CreateGL)                                  },
256         {"nRelease"          , "(J)V", reinterpret_cast<void*>(Surface_Release)        },
257         {"nGetNativeCanvas"  , "(J)J", reinterpret_cast<void*>(Surface_GetNativeCanvas)},
258         {"nFlushAndSubmit"   , "(J)V", reinterpret_cast<void*>(Surface_FlushAndSubmit) },
259         {"nGetWidth"         , "(J)I", reinterpret_cast<void*>(Surface_GetWidth)       },
260         {"nGetHeight"        , "(J)I", reinterpret_cast<void*>(Surface_GetHeight)      },
261         {"nMakeImageSnapshot", "(J)J", reinterpret_cast<void*>(Surface_MakeSnapshot)   },
262     };
263 
264     const auto clazz = env->FindClass("org/skia/jetski/Surface");
265     return clazz
266         ? env->RegisterNatives(clazz, methods, std::size(methods))
267         : JNI_ERR;
268 }
269