xref: /aosp_15_r20/external/skia/modules/jetski/src/Surface.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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