1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2021 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci#include "modules/androidkit/src/Surface.h"
8cb93a386Sopenharmony_ci
9cb93a386Sopenharmony_ci#include <android/bitmap.h>
10cb93a386Sopenharmony_ci#include <android/log.h>
11cb93a386Sopenharmony_ci
12cb93a386Sopenharmony_ci#include "tools/sk_app/Application.h"
13cb93a386Sopenharmony_ci#include "tools/sk_app/DisplayParams.h"
14cb93a386Sopenharmony_ci#include "tools/sk_app/android/WindowContextFactory_android.h"
15cb93a386Sopenharmony_ci
16cb93a386Sopenharmony_cinamespace sk_app {
17cb93a386Sopenharmony_ci// Required to appease the dynamic linker.
18cb93a386Sopenharmony_ci// TODO: split WindowContext from sk_app.
19cb93a386Sopenharmony_ciApplication* Application::Create(int argc, char** argv, void* platformData) {
20cb93a386Sopenharmony_ci    return nullptr;
21cb93a386Sopenharmony_ci}
22cb93a386Sopenharmony_ci}
23cb93a386Sopenharmony_ci
24cb93a386Sopenharmony_ciWindowSurface::WindowSurface(ANativeWindow* win, std::unique_ptr<sk_app::WindowContext> wctx)
25cb93a386Sopenharmony_ci    : fWindow(win)
26cb93a386Sopenharmony_ci    , fWindowContext(std::move(wctx))
27cb93a386Sopenharmony_ci{
28cb93a386Sopenharmony_ci    SkASSERT(fWindow);
29cb93a386Sopenharmony_ci    SkASSERT(fWindowContext);
30cb93a386Sopenharmony_ci
31cb93a386Sopenharmony_ci    fSurface = fWindowContext->getBackbufferSurface();
32cb93a386Sopenharmony_ci}
33cb93a386Sopenharmony_ci
34cb93a386Sopenharmony_civoid WindowSurface::release(JNIEnv* env) {
35cb93a386Sopenharmony_ci    fWindowContext.reset();
36cb93a386Sopenharmony_ci    ANativeWindow_release(fWindow);
37cb93a386Sopenharmony_ci}
38cb93a386Sopenharmony_ci
39cb93a386Sopenharmony_ciSkCanvas* WindowSurface::getCanvas() {
40cb93a386Sopenharmony_ci    if (fSurface) {
41cb93a386Sopenharmony_ci        return fSurface->getCanvas();
42cb93a386Sopenharmony_ci    }
43cb93a386Sopenharmony_ci    return nullptr;
44cb93a386Sopenharmony_ci}
45cb93a386Sopenharmony_ci
46cb93a386Sopenharmony_civoid WindowSurface::flushAndSubmit() {
47cb93a386Sopenharmony_ci    fSurface->flushAndSubmit();
48cb93a386Sopenharmony_ci    fWindowContext->swapBuffers();
49cb93a386Sopenharmony_ci    fSurface = fWindowContext->getBackbufferSurface();
50cb93a386Sopenharmony_ci}
51cb93a386Sopenharmony_ci
52cb93a386Sopenharmony_ci// SkSurface created from being passed an android.view.Surface
53cb93a386Sopenharmony_ci// For now, assume we are always rendering with OpenGL
54cb93a386Sopenharmony_ci// TODO: add option of choose backing
55cb93a386Sopenharmony_ciThreadedSurface::ThreadedSurface(JNIEnv* env, jobject surface)
56cb93a386Sopenharmony_ci      : fThread(std::make_unique<SurfaceThread>()) {
57cb93a386Sopenharmony_ci    ANativeWindow* window = ANativeWindow_fromSurface(env, surface);
58cb93a386Sopenharmony_ci    fWidth = ANativeWindow_getWidth(window);
59cb93a386Sopenharmony_ci    fHeight = ANativeWindow_getHeight(window);
60cb93a386Sopenharmony_ci
61cb93a386Sopenharmony_ci    Message message(kInitialize);
62cb93a386Sopenharmony_ci    message.fNativeWindow = window;
63cb93a386Sopenharmony_ci    message.fWindowSurface = &fWindowSurface;
64cb93a386Sopenharmony_ci    fThread->postMessage(message);
65cb93a386Sopenharmony_ci}
66cb93a386Sopenharmony_ci
67cb93a386Sopenharmony_civoid ThreadedSurface::release(JNIEnv* env) {
68cb93a386Sopenharmony_ci    Message message(kDestroy);
69cb93a386Sopenharmony_ci    message.fWindowSurface = &fWindowSurface;
70cb93a386Sopenharmony_ci    fThread->postMessage(message);
71cb93a386Sopenharmony_ci    fThread->release();
72cb93a386Sopenharmony_ci}
73cb93a386Sopenharmony_ci
74cb93a386Sopenharmony_ciSkCanvas* ThreadedSurface::getCanvas() {
75cb93a386Sopenharmony_ci    return fRecorder.beginRecording(fWidth,
76cb93a386Sopenharmony_ci                                    fHeight);
77cb93a386Sopenharmony_ci}
78cb93a386Sopenharmony_ci
79cb93a386Sopenharmony_civoid ThreadedSurface::flushAndSubmit() {
80cb93a386Sopenharmony_ci    Message message(kRenderPicture);
81cb93a386Sopenharmony_ci    message.fWindowSurface = &fWindowSurface;
82cb93a386Sopenharmony_ci    message.fPicture = fRecorder.finishRecordingAsPicture().release();
83cb93a386Sopenharmony_ci    fThread->postMessage(message);
84cb93a386Sopenharmony_ci}
85cb93a386Sopenharmony_ci
86cb93a386Sopenharmony_cinamespace {
87cb93a386Sopenharmony_ci
88cb93a386Sopenharmony_ciclass BitmapSurface final : public Surface {
89cb93a386Sopenharmony_cipublic:
90cb93a386Sopenharmony_ci    BitmapSurface(JNIEnv* env, jobject bitmap) {
91cb93a386Sopenharmony_ci        AndroidBitmapInfo bm_info;
92cb93a386Sopenharmony_ci        if (AndroidBitmap_getInfo(env, bitmap, &bm_info) != ANDROID_BITMAP_RESULT_SUCCESS) {
93cb93a386Sopenharmony_ci            return;
94cb93a386Sopenharmony_ci        }
95cb93a386Sopenharmony_ci
96cb93a386Sopenharmony_ci        const auto info = SkImageInfo::Make(bm_info.width, bm_info.height,
97cb93a386Sopenharmony_ci                                            color_type(bm_info.format), alpha_type(bm_info.flags));
98cb93a386Sopenharmony_ci
99cb93a386Sopenharmony_ci        void* pixels;
100cb93a386Sopenharmony_ci        if (AndroidBitmap_lockPixels(env, bitmap, &pixels) != ANDROID_BITMAP_RESULT_SUCCESS) {
101cb93a386Sopenharmony_ci            return;
102cb93a386Sopenharmony_ci        }
103cb93a386Sopenharmony_ci
104cb93a386Sopenharmony_ci        fSurface = SkSurface::MakeRasterDirect(info, pixels, bm_info.stride);
105cb93a386Sopenharmony_ci        if (!fSurface) {
106cb93a386Sopenharmony_ci            AndroidBitmap_unlockPixels(env, bitmap);
107cb93a386Sopenharmony_ci            return;
108cb93a386Sopenharmony_ci        }
109cb93a386Sopenharmony_ci
110cb93a386Sopenharmony_ci        fBitmap = env->NewGlobalRef(bitmap);
111cb93a386Sopenharmony_ci    }
112cb93a386Sopenharmony_ci
113cb93a386Sopenharmony_ciprivate:
114cb93a386Sopenharmony_ci    void release(JNIEnv* env) override {
115cb93a386Sopenharmony_ci        if (fSurface) {
116cb93a386Sopenharmony_ci            AndroidBitmap_unlockPixels(env, fBitmap);
117cb93a386Sopenharmony_ci            fSurface.reset();
118cb93a386Sopenharmony_ci            env->DeleteGlobalRef(fBitmap);
119cb93a386Sopenharmony_ci        }
120cb93a386Sopenharmony_ci    }
121cb93a386Sopenharmony_ci
122cb93a386Sopenharmony_ci    SkCanvas* getCanvas() override {
123cb93a386Sopenharmony_ci        if (fSurface) {
124cb93a386Sopenharmony_ci            return fSurface->getCanvas();
125cb93a386Sopenharmony_ci        }
126cb93a386Sopenharmony_ci        return nullptr;
127cb93a386Sopenharmony_ci    }
128cb93a386Sopenharmony_ci
129cb93a386Sopenharmony_ci    void flushAndSubmit() override {
130cb93a386Sopenharmony_ci        // Nothing to do.
131cb93a386Sopenharmony_ci    }
132cb93a386Sopenharmony_ci
133cb93a386Sopenharmony_ci    static SkColorType color_type(int32_t format) {
134cb93a386Sopenharmony_ci        switch (format) {
135cb93a386Sopenharmony_ci            case ANDROID_BITMAP_FORMAT_RGBA_8888: return kRGBA_8888_SkColorType;
136cb93a386Sopenharmony_ci            case ANDROID_BITMAP_FORMAT_RGB_565:   return kRGB_565_SkColorType;
137cb93a386Sopenharmony_ci            case ANDROID_BITMAP_FORMAT_RGBA_4444: return kARGB_4444_SkColorType;
138cb93a386Sopenharmony_ci            case ANDROID_BITMAP_FORMAT_RGBA_F16:  return kRGBA_F16_SkColorType;
139cb93a386Sopenharmony_ci            case ANDROID_BITMAP_FORMAT_A_8:       return kAlpha_8_SkColorType;
140cb93a386Sopenharmony_ci            default: break;
141cb93a386Sopenharmony_ci        }
142cb93a386Sopenharmony_ci
143cb93a386Sopenharmony_ci        return kUnknown_SkColorType;
144cb93a386Sopenharmony_ci    }
145cb93a386Sopenharmony_ci
146cb93a386Sopenharmony_ci    static SkAlphaType alpha_type(int32_t flags) {
147cb93a386Sopenharmony_ci        switch ((flags >> ANDROID_BITMAP_FLAGS_ALPHA_SHIFT) & ANDROID_BITMAP_FLAGS_ALPHA_MASK) {
148cb93a386Sopenharmony_ci            case ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE:   return kOpaque_SkAlphaType;
149cb93a386Sopenharmony_ci            case ANDROID_BITMAP_FLAGS_ALPHA_PREMUL:   return kPremul_SkAlphaType;
150cb93a386Sopenharmony_ci            case ANDROID_BITMAP_FLAGS_ALPHA_UNPREMUL: return kUnpremul_SkAlphaType;
151cb93a386Sopenharmony_ci            default: break;
152cb93a386Sopenharmony_ci        }
153cb93a386Sopenharmony_ci
154cb93a386Sopenharmony_ci        return kUnknown_SkAlphaType;
155cb93a386Sopenharmony_ci    }
156cb93a386Sopenharmony_ci
157cb93a386Sopenharmony_ci    jobject fBitmap;
158cb93a386Sopenharmony_ci};
159cb93a386Sopenharmony_ci
160cb93a386Sopenharmony_ci// *** JNI methods ***
161cb93a386Sopenharmony_ci
162cb93a386Sopenharmony_cistatic jlong Surface_CreateBitmap(JNIEnv* env, jobject, jobject bitmap) {
163cb93a386Sopenharmony_ci    return reinterpret_cast<jlong>(new BitmapSurface(env, bitmap));
164cb93a386Sopenharmony_ci}
165cb93a386Sopenharmony_ci
166cb93a386Sopenharmony_cistatic jlong Surface_CreateThreadedSurface(JNIEnv* env, jobject, jobject surface) {
167cb93a386Sopenharmony_ci    return reinterpret_cast<jlong>(new ThreadedSurface(env, surface));
168cb93a386Sopenharmony_ci}
169cb93a386Sopenharmony_ci
170cb93a386Sopenharmony_cistatic jlong Surface_CreateVK(JNIEnv* env, jobject, jobject jsurface) {
171cb93a386Sopenharmony_ci#ifdef SK_VULKAN
172cb93a386Sopenharmony_ci    auto* win = ANativeWindow_fromSurface(env, jsurface);
173cb93a386Sopenharmony_ci    if (!win) {
174cb93a386Sopenharmony_ci        return 0;
175cb93a386Sopenharmony_ci    }
176cb93a386Sopenharmony_ci
177cb93a386Sopenharmony_ci    // TODO: match window params?
178cb93a386Sopenharmony_ci    sk_app::DisplayParams params;
179cb93a386Sopenharmony_ci    auto winctx = sk_app::window_context_factory::MakeVulkanForAndroid(win, params);
180cb93a386Sopenharmony_ci    if (!winctx) {
181cb93a386Sopenharmony_ci        return 0;
182cb93a386Sopenharmony_ci    }
183cb93a386Sopenharmony_ci
184cb93a386Sopenharmony_ci    return reinterpret_cast<jlong>(sk_make_sp<WindowSurface>(win, std::move(winctx)).release());
185cb93a386Sopenharmony_ci#endif // SK_VULKAN
186cb93a386Sopenharmony_ci    return 0;
187cb93a386Sopenharmony_ci}
188cb93a386Sopenharmony_ci
189cb93a386Sopenharmony_cistatic jlong Surface_CreateGL(JNIEnv* env, jobject, jobject jsurface) {
190cb93a386Sopenharmony_ci#ifdef SK_GL
191cb93a386Sopenharmony_ci    auto* win = ANativeWindow_fromSurface(env, jsurface);
192cb93a386Sopenharmony_ci    if (!win) {
193cb93a386Sopenharmony_ci        return 0;
194cb93a386Sopenharmony_ci    }
195cb93a386Sopenharmony_ci
196cb93a386Sopenharmony_ci    // TODO: match window params?
197cb93a386Sopenharmony_ci    sk_app::DisplayParams params;
198cb93a386Sopenharmony_ci    auto winctx = sk_app::window_context_factory::MakeGLForAndroid(win, params);
199cb93a386Sopenharmony_ci    if (!winctx) {
200cb93a386Sopenharmony_ci        return 0;
201cb93a386Sopenharmony_ci    }
202cb93a386Sopenharmony_ci
203cb93a386Sopenharmony_ci    return reinterpret_cast<jlong>(sk_make_sp<WindowSurface>(win, std::move(winctx)).release());
204cb93a386Sopenharmony_ci#endif // SK_GL
205cb93a386Sopenharmony_ci    return 0;
206cb93a386Sopenharmony_ci}
207cb93a386Sopenharmony_ci
208cb93a386Sopenharmony_cistatic void Surface_Release(JNIEnv* env, jobject, jlong native_surface) {
209cb93a386Sopenharmony_ci    if (auto* surface = reinterpret_cast<Surface*>(native_surface)) {
210cb93a386Sopenharmony_ci        surface->release(env);
211cb93a386Sopenharmony_ci        SkSafeUnref(surface);
212cb93a386Sopenharmony_ci    }
213cb93a386Sopenharmony_ci}
214cb93a386Sopenharmony_ci
215cb93a386Sopenharmony_cistatic jlong Surface_GetNativeCanvas(JNIEnv* env, jobject, jlong native_surface) {
216cb93a386Sopenharmony_ci    auto* surface = reinterpret_cast<Surface*>(native_surface);
217cb93a386Sopenharmony_ci    return surface
218cb93a386Sopenharmony_ci        ? reinterpret_cast<jlong>(surface->getCanvas())
219cb93a386Sopenharmony_ci        : 0;
220cb93a386Sopenharmony_ci}
221cb93a386Sopenharmony_ci
222cb93a386Sopenharmony_cistatic void Surface_FlushAndSubmit(JNIEnv* env, jobject, jlong native_surface) {
223cb93a386Sopenharmony_ci    if (auto* surface = reinterpret_cast<Surface*>(native_surface)) {
224cb93a386Sopenharmony_ci        surface->flushAndSubmit();
225cb93a386Sopenharmony_ci    }
226cb93a386Sopenharmony_ci}
227cb93a386Sopenharmony_ci
228cb93a386Sopenharmony_cistatic jint Surface_GetWidth(JNIEnv* env, jobject, jlong native_surface) {
229cb93a386Sopenharmony_ci    const auto* surface = reinterpret_cast<Surface*>(native_surface);
230cb93a386Sopenharmony_ci    return surface ? surface->width() : 0;
231cb93a386Sopenharmony_ci}
232cb93a386Sopenharmony_ci
233cb93a386Sopenharmony_cistatic jint Surface_GetHeight(JNIEnv* env, jobject, jlong native_surface) {
234cb93a386Sopenharmony_ci    const auto* surface = reinterpret_cast<Surface*>(native_surface);
235cb93a386Sopenharmony_ci    return surface ? surface->height() : 0;
236cb93a386Sopenharmony_ci}
237cb93a386Sopenharmony_ci
238cb93a386Sopenharmony_cistatic jlong Surface_MakeSnapshot(JNIEnv* env, jobject, jlong native_surface) {
239cb93a386Sopenharmony_ci    if (const auto* surface = reinterpret_cast<Surface*>(native_surface)) {
240cb93a386Sopenharmony_ci        auto snapshot = surface->makeImageSnapshot();
241cb93a386Sopenharmony_ci        return reinterpret_cast<jlong>(snapshot.release());
242cb93a386Sopenharmony_ci    }
243cb93a386Sopenharmony_ci
244cb93a386Sopenharmony_ci    return 0;
245cb93a386Sopenharmony_ci}
246cb93a386Sopenharmony_ci
247cb93a386Sopenharmony_ci// *** End of JNI methods ***
248cb93a386Sopenharmony_ci
249cb93a386Sopenharmony_ci}  // namespace
250cb93a386Sopenharmony_ci
251cb93a386Sopenharmony_ciint register_androidkit_Surface(JNIEnv* env) {
252cb93a386Sopenharmony_ci    static const JNINativeMethod methods[] = {
253cb93a386Sopenharmony_ci        {"nCreateBitmap"     , "(Landroid/graphics/Bitmap;)J",
254cb93a386Sopenharmony_ci            reinterpret_cast<void*>(Surface_CreateBitmap)                              },
255cb93a386Sopenharmony_ci        {"nCreateThreadedSurface"  , "(Landroid/view/Surface;)J",
256cb93a386Sopenharmony_ci            reinterpret_cast<void*>(Surface_CreateThreadedSurface)                     },
257cb93a386Sopenharmony_ci        {"nCreateVKSurface"  , "(Landroid/view/Surface;)J",
258cb93a386Sopenharmony_ci            reinterpret_cast<void*>(Surface_CreateVK)                                  },
259cb93a386Sopenharmony_ci        {"nCreateGLSurface"  , "(Landroid/view/Surface;)J",
260cb93a386Sopenharmony_ci            reinterpret_cast<void*>(Surface_CreateGL)                                  },
261cb93a386Sopenharmony_ci        {"nRelease"          , "(J)V", reinterpret_cast<void*>(Surface_Release)        },
262cb93a386Sopenharmony_ci        {"nGetNativeCanvas"  , "(J)J", reinterpret_cast<void*>(Surface_GetNativeCanvas)},
263cb93a386Sopenharmony_ci        {"nFlushAndSubmit"   , "(J)V", reinterpret_cast<void*>(Surface_FlushAndSubmit) },
264cb93a386Sopenharmony_ci        {"nGetWidth"         , "(J)I", reinterpret_cast<void*>(Surface_GetWidth)       },
265cb93a386Sopenharmony_ci        {"nGetHeight"        , "(J)I", reinterpret_cast<void*>(Surface_GetHeight)      },
266cb93a386Sopenharmony_ci        {"nMakeImageSnapshot", "(J)J", reinterpret_cast<void*>(Surface_MakeSnapshot)   },
267cb93a386Sopenharmony_ci    };
268cb93a386Sopenharmony_ci
269cb93a386Sopenharmony_ci    const auto clazz = env->FindClass("org/skia/androidkit/Surface");
270cb93a386Sopenharmony_ci    return clazz
271cb93a386Sopenharmony_ci        ? env->RegisterNatives(clazz, methods, SK_ARRAY_COUNT(methods))
272cb93a386Sopenharmony_ci        : JNI_ERR;
273cb93a386Sopenharmony_ci}
274