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