diff options
Diffstat (limited to 'platform/android/src')
-rwxr-xr-x | platform/android/src/jni.cpp | 95 | ||||
-rw-r--r-- | platform/android/src/jni.hpp | 1 | ||||
-rwxr-xr-x | platform/android/src/native_map_view.cpp | 473 | ||||
-rwxr-xr-x | platform/android/src/native_map_view.hpp | 60 | ||||
-rw-r--r-- | platform/android/src/run_loop.cpp | 9 | ||||
-rw-r--r-- | platform/android/src/run_loop_impl.hpp | 6 |
6 files changed, 99 insertions, 545 deletions
diff --git a/platform/android/src/jni.cpp b/platform/android/src/jni.cpp index b6113e1d3c..3acb987445 100755 --- a/platform/android/src/jni.cpp +++ b/platform/android/src/jni.cpp @@ -59,6 +59,7 @@ std::string apkPath; std::string androidRelease; jni::jmethodID* onInvalidateId = nullptr; +jni::jmethodID* wakeCallbackId = nullptr; jni::jmethodID* onMapChangedId = nullptr; jni::jmethodID* onFpsChangedId = nullptr; jni::jmethodID* onSnapshotReadyId = nullptr; @@ -307,61 +308,21 @@ using namespace mbgl::android; using DebugOptions = mbgl::MapDebugOptions; jlong nativeCreate(JNIEnv *env, jni::jobject* obj, jni::jstring* cachePath_, jni::jstring* dataPath_, jni::jstring* apkPath_, jfloat pixelRatio, jint availableProcessors, jlong totalMemory) { - mbgl::Log::Debug(mbgl::Event::JNI, "nativeCreate"); + mbgl::Log::Info(mbgl::Event::JNI, "nativeCreate"); cachePath = std_string_from_jstring(env, cachePath_); dataPath = std_string_from_jstring(env, dataPath_); apkPath = std_string_from_jstring(env, apkPath_); + + mbgl::Log::Info(mbgl::Event::JNI, "Create NativeMapView"); return reinterpret_cast<jlong>(new NativeMapView(env, jni::Unwrap(obj), pixelRatio, availableProcessors, totalMemory)); } void nativeDestroy(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { - mbgl::Log::Debug(mbgl::Event::JNI, "nativeDestroy"); + mbgl::Log::Info(mbgl::Event::JNI, "nativeDestroy"); assert(nativeMapViewPtr != 0); delete reinterpret_cast<NativeMapView *>(nativeMapViewPtr); } -void nativeInitializeDisplay(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { - mbgl::Log::Debug(mbgl::Event::JNI, "nativeInitializeDisplay"); - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr); - nativeMapView->initializeDisplay(); -} - -void nativeTerminateDisplay(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { - mbgl::Log::Debug(mbgl::Event::JNI, "nativeTerminateDisplay"); - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr); - nativeMapView->terminateDisplay(); -} - -void nativeInitializeContext(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { - mbgl::Log::Debug(mbgl::Event::JNI, "nativeInitializeContext"); - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr); - nativeMapView->initializeContext(); -} - -void nativeTerminateContext(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { - mbgl::Log::Debug(mbgl::Event::JNI, "nativeTerminateContext"); - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr); - nativeMapView->terminateContext(); -} - -void nativeCreateSurface(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jobject* surface) { - mbgl::Log::Debug(mbgl::Event::JNI, "nativeCreateSurface"); - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr); - nativeMapView->createSurface(ANativeWindow_fromSurface(env, jni::Unwrap(surface))); -} - -void nativeDestroySurface(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { - mbgl::Log::Debug(mbgl::Event::JNI, "nativeDestroySurface"); - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr); - nativeMapView->destroySurface(); -} - void nativeUpdate(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr); @@ -369,31 +330,22 @@ void nativeUpdate(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { } void nativeRender(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { + mbgl::Log::Info(mbgl::Event::JNI, "nativeRender"); + mbgl::util::RunLoop::Get()->runOnce(); assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr); nativeMapView->render(); } -void nativeViewResize(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jint width, jint height) { - mbgl::Log::Debug(mbgl::Event::JNI, "nativeViewResize"); +void nativeOnViewportChanged(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jint width, jint height) { + mbgl::Log::Info(mbgl::Event::JNI, "nativeViewResize"); assert(nativeMapViewPtr != 0); assert(width >= 0); assert(height >= 0); assert(width <= UINT16_MAX); assert(height <= UINT16_MAX); NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr); - nativeMapView->resizeView(width, height); -} - -void nativeFramebufferResize(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jint fbWidth, jint fbHeight) { - mbgl::Log::Debug(mbgl::Event::JNI, "nativeFramebufferResize"); - assert(nativeMapViewPtr != 0); - assert(fbWidth >= 0); - assert(fbHeight >= 0); - assert(fbWidth <= UINT16_MAX); - assert(fbHeight <= UINT16_MAX); - NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr); - nativeMapView->resizeFramebuffer(fbWidth, fbHeight); + nativeMapView->onViewportChanged(width, height); } void nativeRemoveClass(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* clazz) { @@ -1149,7 +1101,7 @@ jni::jobject* nativeGetLayer(JNIEnv *env, jni::jobject* obj, jlong nativeMapView // Find the layer mbgl::style::Layer* coreLayer = nativeMapView->getMap().getLayer(std_string_from_jstring(env, layerId)); if (!coreLayer) { - mbgl::Log::Debug(mbgl::Event::JNI, "No layer found"); + mbgl::Log::Info(mbgl::Event::JNI, "No layer found"); return jni::Object<Layer>(); } @@ -1210,7 +1162,7 @@ jni::jobject* nativeGetSource(JNIEnv *env, jni::jobject* obj, jni::jlong nativeM // Find the source mbgl::style::Source* coreSource = nativeMapView->getMap().getSource(std_string_from_jstring(env, sourceId)); if (!coreSource) { - mbgl::Log::Debug(mbgl::Event::JNI, "No source found"); + mbgl::Log::Info(mbgl::Event::JNI, "No source found"); return jni::Object<Source>(); } @@ -1329,7 +1281,7 @@ void listOfflineRegions(JNIEnv *env, jni::jobject* obj, jlong defaultFileSourceP JNIEnv *env2; jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Offline Thread"); if (renderDetach) { - mbgl::Log::Debug(mbgl::Event::JNI, "Attached."); + mbgl::Log::Info(mbgl::Event::JNI, "Attached."); } if (error) { @@ -1419,7 +1371,7 @@ void createOfflineRegion(JNIEnv *env, jni::jobject* obj, jlong defaultFileSource JNIEnv *env2; jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Offline Thread"); if (renderDetach) { - mbgl::Log::Debug(mbgl::Event::JNI, "Attached."); + mbgl::Log::Info(mbgl::Event::JNI, "Attached."); } if (error) { @@ -1505,7 +1457,7 @@ void setOfflineRegionObserver(JNIEnv *env, jni::jobject* offlineRegion_, jni::jo } ~Observer() override { - mbgl::Log::Debug(mbgl::Event::JNI, "~Observer()"); + mbgl::Log::Info(mbgl::Event::JNI, "~Observer()"); // Env JNIEnv* env2; jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Offline Thread"); @@ -1650,7 +1602,7 @@ void getOfflineRegionStatus(JNIEnv *env, jni::jobject* offlineRegion_, jni::jobj JNIEnv *env2; jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Offline Thread"); if (renderDetach) { - mbgl::Log::Debug(mbgl::Event::JNI, "Attached."); + mbgl::Log::Info(mbgl::Event::JNI, "Attached."); } if (error) { @@ -1704,7 +1656,7 @@ void deleteOfflineRegion(JNIEnv *env, jni::jobject* offlineRegion_, jni::jobject JNIEnv *env2; jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Offline Thread"); if (renderDetach) { - mbgl::Log::Debug(mbgl::Event::JNI, "Attached."); + mbgl::Log::Info(mbgl::Event::JNI, "Attached."); } if (error) { @@ -1747,7 +1699,7 @@ void updateOfflineRegionMetadata(JNIEnv *env, jni::jobject* offlineRegion_, jni: JNIEnv *env2; jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Offline Thread"); if (renderDetach) { - mbgl::Log::Debug(mbgl::Event::JNI, "Attached."); + mbgl::Log::Info(mbgl::Event::JNI, "Attached."); } if (error) { @@ -1776,6 +1728,7 @@ void registerNatives(JavaVM *vm) { jni::JNIEnv& env = jni::GetEnv(*vm, jni::jni_version_1_6); + //For the DefaultFileSource static mbgl::util::RunLoop mainRunLoop; mbgl::android::RegisterNativeHTTPRequest(env); @@ -1861,6 +1814,7 @@ void registerNatives(JavaVM *vm) { jni::jclass& nativeMapViewClass = jni::FindClass(env, "com/mapbox/mapboxsdk/maps/NativeMapView"); onInvalidateId = &jni::GetMethodID(env, nativeMapViewClass, "onInvalidate", "()V"); + wakeCallbackId = &jni::GetMethodID(env, nativeMapViewClass, "wakeCallback","()V"); onMapChangedId = &jni::GetMethodID(env, nativeMapViewClass, "onMapChanged", "(I)V"); onFpsChangedId = &jni::GetMethodID(env, nativeMapViewClass, "onFpsChanged", "(D)V"); onSnapshotReadyId = &jni::GetMethodID(env, nativeMapViewClass, "onSnapshotReady","(Landroid/graphics/Bitmap;)V"); @@ -1870,16 +1824,9 @@ void registerNatives(JavaVM *vm) { jni::RegisterNatives(env, nativeMapViewClass, MAKE_NATIVE_METHOD(nativeCreate, "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;FIJ)J"), MAKE_NATIVE_METHOD(nativeDestroy, "(J)V"), - MAKE_NATIVE_METHOD(nativeInitializeDisplay, "(J)V"), - MAKE_NATIVE_METHOD(nativeTerminateDisplay, "(J)V"), - MAKE_NATIVE_METHOD(nativeInitializeContext, "(J)V"), - MAKE_NATIVE_METHOD(nativeTerminateContext, "(J)V"), - MAKE_NATIVE_METHOD(nativeCreateSurface, "(JLandroid/view/Surface;)V"), - MAKE_NATIVE_METHOD(nativeDestroySurface, "(J)V"), MAKE_NATIVE_METHOD(nativeUpdate, "(J)V"), MAKE_NATIVE_METHOD(nativeRender, "(J)V"), - MAKE_NATIVE_METHOD(nativeViewResize, "(JII)V"), - MAKE_NATIVE_METHOD(nativeFramebufferResize, "(JII)V"), + MAKE_NATIVE_METHOD(nativeOnViewportChanged, "(JII)V"), MAKE_NATIVE_METHOD(nativeAddClass, "(JLjava/lang/String;)V"), MAKE_NATIVE_METHOD(nativeRemoveClass, "(JLjava/lang/String;)V"), MAKE_NATIVE_METHOD(nativeHasClass, "(JLjava/lang/String;)Z"), diff --git a/platform/android/src/jni.hpp b/platform/android/src/jni.hpp index d12030f3c1..04bad003f6 100644 --- a/platform/android/src/jni.hpp +++ b/platform/android/src/jni.hpp @@ -17,6 +17,7 @@ extern std::string apkPath; extern std::string androidRelease; extern jmethodID onInvalidateId; +extern jmethodID wakeCallbackId; extern jmethodID onMapChangedId; extern jmethodID onFpsChangedId; extern jmethodID onSnapshotReadyId; diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp index e994afc7b8..50fa8944f7 100755 --- a/platform/android/src/native_map_view.cpp +++ b/platform/android/src/native_map_view.cpp @@ -1,5 +1,6 @@ #include "native_map_view.hpp" #include "jni.hpp" +#include <jni/jni.hpp> #include <cstdlib> #include <ctime> @@ -19,15 +20,23 @@ #include <mbgl/util/image.hpp> #include "bitmap.hpp" +#include "run_loop_impl.hpp" namespace mbgl { namespace android { -NativeMapView::NativeMapView(JNIEnv *env_, jobject obj_, float pixelRatio, int availableProcessors_, size_t totalMemory_) +NativeMapView::NativeMapView(JNIEnv *env_, jobject obj_, float _pixelRatio, int availableProcessors_, size_t totalMemory_) : env(env_), + pixelRatio(_pixelRatio), availableProcessors(availableProcessors_), totalMemory(totalMemory_), + runLoop(std::make_unique<mbgl::util::RunLoop>(mbgl::util::RunLoop::Type::New)), threadPool(4) { + mbgl::Log::Info(mbgl::Event::Android, "NativeMapView::NativeMapView"); + + //Add a wake function to wake the render thread when needed + mbgl::util::RunLoop::Impl* loop = reinterpret_cast<mbgl::util::RunLoop::Impl*>(mbgl::util::RunLoop::getLoopHandle()); + loop->setWakeFunction(std::bind(&NativeMapView::wake, this)); assert(env_ != nullptr); assert(obj_ != nullptr); @@ -63,9 +72,7 @@ NativeMapView::NativeMapView(JNIEnv *env_, jobject obj_, float pixelRatio, int a } NativeMapView::~NativeMapView() { - terminateContext(); - destroySurface(); - terminateDisplay(); + mbgl::Log::Info(mbgl::Event::Android, "NativeMapView::~NativeMapView"); assert(vm != nullptr); assert(obj != nullptr); @@ -81,9 +88,24 @@ NativeMapView::~NativeMapView() { } mbgl::Size NativeMapView::getFramebufferSize() const { + mbgl::Log::Info(mbgl::Event::Android, "FB size %dx%d", fbWidth, fbHeight); return { static_cast<uint32_t>(fbWidth), static_cast<uint32_t>(fbHeight) }; } +void NativeMapView::wake() { + mbgl::Log::Info(mbgl::Event::JNI, "Wake callback"); + + JNIEnv *env2; + jboolean detach = attach_jni_thread(theJVM, &env2, "GL Callback Thread"); + if (!detach) { + env2->CallVoidMethod(obj, wakeCallbackId); + if (env2->ExceptionCheck()) { + env2->ExceptionDescribe(); + } + } + detach_jni_thread(theJVM, &env2, detach); +} + void NativeMapView::updateViewBinding() { getContext().bindFramebuffer.setCurrentValue(0); assert(mbgl::gl::value::BindFramebuffer::Get() == getContext().bindFramebuffer.getCurrentValue()); @@ -96,59 +118,8 @@ void NativeMapView::bind() { getContext().viewport = { 0, 0, getFramebufferSize() }; } -void NativeMapView::activate() { - if (active++) { - return; - } - - oldDisplay = eglGetCurrentDisplay(); - oldReadSurface = eglGetCurrentSurface(EGL_READ); - oldDrawSurface = eglGetCurrentSurface(EGL_DRAW); - oldContext = eglGetCurrentContext(); - - assert(vm != nullptr); - - if ((display != EGL_NO_DISPLAY) && (surface != EGL_NO_SURFACE) && (context != EGL_NO_CONTEXT)) { - if (!eglMakeCurrent(display, surface, surface, context)) { - mbgl::Log::Error(mbgl::Event::OpenGL, "eglMakeCurrent() returned error %d", - eglGetError()); - throw std::runtime_error("eglMakeCurrent() failed"); - } - - if (!eglSwapInterval(display, 0)) { - mbgl::Log::Error(mbgl::Event::OpenGL, "eglSwapInterval() returned error %d", eglGetError()); - throw std::runtime_error("eglSwapInterval() failed"); - } - } else { - mbgl::Log::Info(mbgl::Event::Android, "Not activating as we are not ready"); - } -} - -void NativeMapView::deactivate() { - if (--active) { - return; - } - - assert(vm != nullptr); - - if (oldContext != context && oldContext != EGL_NO_CONTEXT) { - if (!eglMakeCurrent(oldDisplay, oldDrawSurface, oldReadSurface, oldContext)) { - mbgl::Log::Error(mbgl::Event::OpenGL, "eglMakeCurrent() returned error %d", - eglGetError()); - throw std::runtime_error("eglMakeCurrent() failed"); - } - } else if (display != EGL_NO_DISPLAY) { - if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) { - mbgl::Log::Error(mbgl::Event::OpenGL, "eglMakeCurrent(EGL_NO_CONTEXT) returned error %d", - eglGetError()); - throw std::runtime_error("eglMakeCurrent() failed"); - } - } else { - mbgl::Log::Info(mbgl::Event::Android, "Not deactivating as we are not ready"); - } -} - void NativeMapView::invalidate() { + Log::Info(mbgl::Event::Android, "NativeMapView::invalidate"); assert(vm != nullptr); assert(obj != nullptr); JNIEnv *env2; @@ -162,7 +133,7 @@ void NativeMapView::invalidate() { } void NativeMapView::render() { - BackendScope guard(*this); + mbgl::Log::Info(mbgl::Event::Android, "NativeMapView::render"); if (framebufferSizeChanged) { getContext().viewport = { 0, 0, getFramebufferSize() }; @@ -189,395 +160,20 @@ void NativeMapView::render() { } } - if ((display != EGL_NO_DISPLAY) && (surface != EGL_NO_SURFACE)) { - if (!eglSwapBuffers(display, surface)) { - mbgl::Log::Error(mbgl::Event::OpenGL, "eglSwapBuffers() returned error %d", - eglGetError()); - throw std::runtime_error("eglSwapBuffers() failed"); - } - - updateFps(); - } else { - mbgl::Log::Info(mbgl::Event::Android, "Not swapping as we are not ready"); - } + updateFps(); } mbgl::Map &NativeMapView::getMap() { return *map; } mbgl::DefaultFileSource &NativeMapView::getFileSource() { return *fileSource; } -void NativeMapView::initializeDisplay() { - assert(display == EGL_NO_DISPLAY); - assert(config == nullptr); - assert(format < 0); - - display = eglGetCurrentDisplay(); - if (display == EGL_NO_DISPLAY) { - mbgl::Log::Error(mbgl::Event::OpenGL, "eglGetDisplay() returned error %d", eglGetError()); - throw std::runtime_error("eglGetDisplay() failed"); - } - - EGLint major, minor; - if (!eglInitialize(display, &major, &minor)) { - mbgl::Log::Error(mbgl::Event::OpenGL, "eglInitialize() returned error %d", eglGetError()); - throw std::runtime_error("eglInitialize() failed"); - } - if ((major <= 1) && (minor < 3)) { - mbgl::Log::Error(mbgl::Event::OpenGL, "EGL version is too low, need 1.3, got %d.%d", major, - minor); - throw std::runtime_error("EGL version is too low"); - } - - // Detect if we are in emulator. - const bool inEmulator = []() { - char prop[PROP_VALUE_MAX]; - __system_property_get("ro.kernel.qemu", prop); - return strtol(prop, nullptr, 0) == 1; - }(); - - if (inEmulator) { - // XXX https://code.google.com/p/android/issues/detail?id=78977 - mbgl::Log::Warning(mbgl::Event::Android, "Running SDK in emulator!"); - } - - if (!eglBindAPI(EGL_OPENGL_ES_API)) { - mbgl::Log::Error(mbgl::Event::OpenGL, "eglBindAPI(EGL_OPENGL_ES_API) returned error %d", eglGetError()); - throw std::runtime_error("eglBindAPI() failed"); - } - - // Get all configs at least RGB 565 with 16 depth and 8 stencil - EGLint configAttribs[] = { - EGL_CONFIG_CAVEAT, EGL_NONE, - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_BUFFER_SIZE, 16, - EGL_RED_SIZE, 5, - EGL_GREEN_SIZE, 6, - EGL_BLUE_SIZE, 5, - EGL_DEPTH_SIZE, 16, - EGL_STENCIL_SIZE, 8, - (inEmulator ? EGL_NONE : EGL_CONFORMANT), EGL_OPENGL_ES2_BIT, - (inEmulator ? EGL_NONE : EGL_COLOR_BUFFER_TYPE), EGL_RGB_BUFFER, - EGL_NONE - }; - - EGLint numConfigs; - if (!eglChooseConfig(display, configAttribs, nullptr, 0, &numConfigs)) { - mbgl::Log::Error(mbgl::Event::OpenGL, "eglChooseConfig(NULL) returned error %d", - eglGetError()); - throw std::runtime_error("eglChooseConfig() failed"); - } - if (numConfigs < 1) { - mbgl::Log::Error(mbgl::Event::OpenGL, "eglChooseConfig() returned no configs."); - throw std::runtime_error("eglChooseConfig() failed"); - } - - const auto configs = std::make_unique<EGLConfig[]>(numConfigs); - if (!eglChooseConfig(display, configAttribs, configs.get(), numConfigs, &numConfigs)) { - mbgl::Log::Error(mbgl::Event::OpenGL, "eglChooseConfig() returned error %d", eglGetError()); - throw std::runtime_error("eglChooseConfig() failed"); - } - - config = chooseConfig(configs.get(), numConfigs); - if (config == nullptr) { - mbgl::Log::Error(mbgl::Event::OpenGL, "No config chosen"); - throw std::runtime_error("No config chosen"); - } - - if (!eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format)) { - mbgl::Log::Error(mbgl::Event::OpenGL, "eglGetConfigAttrib() returned error %d", - eglGetError()); - throw std::runtime_error("eglGetConfigAttrib() failed"); - } -} - -void NativeMapView::terminateDisplay() { - if (display != EGL_NO_DISPLAY) { - surface = EGL_NO_SURFACE; - - if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) { - mbgl::Log::Error(mbgl::Event::OpenGL, - "eglMakeCurrent(EGL_NO_CONTEXT) returned error %d", eglGetError()); - throw std::runtime_error("eglMakeCurrent() failed"); - } - - if (!eglTerminate(display)) { - mbgl::Log::Error(mbgl::Event::OpenGL, "eglTerminate() returned error %d", - eglGetError()); - throw std::runtime_error("eglTerminate() failed"); - } - } - - display = EGL_NO_DISPLAY; - config = nullptr; - format = -1; -} - -void NativeMapView::initializeContext() { - assert(display != EGL_NO_DISPLAY); - assert(context == EGL_NO_CONTEXT); - assert(config != nullptr); - - context = eglGetCurrentContext(); - if (context == EGL_NO_CONTEXT) { - mbgl::Log::Error(mbgl::Event::OpenGL, "eglCreateContext() returned error %d", - eglGetError()); - throw std::runtime_error("eglCreateContext() failed"); - } -} - -void NativeMapView::terminateContext() { - if (display != EGL_NO_DISPLAY) { - - if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) { - mbgl::Log::Error(mbgl::Event::OpenGL, - "eglMakeCurrent(EGL_NO_CONTEXT) returned error %d", eglGetError()); - throw std::runtime_error("eglMakeCurrent() failed"); - } - - } - - context = EGL_NO_CONTEXT; -} - -void NativeMapView::createSurface(ANativeWindow *window_) { - assert(window == nullptr); - assert(window_ != nullptr); - window = window_; - - assert(display != EGL_NO_DISPLAY); - assert(surface == EGL_NO_SURFACE); - assert(config != nullptr); - assert(format >= 0); - - ANativeWindow_setBuffersGeometry(window, 0, 0, format); - - surface = eglGetCurrentSurface(EGL_DRAW); - if (surface == EGL_NO_SURFACE) { - mbgl::Log::Error(mbgl::Event::OpenGL, "eglCreateWindowSurface() returned error %d", - eglGetError()); - throw std::runtime_error("eglCreateWindowSurface() failed"); - } - - if (!firstTime) { - firstTime = true; - - BackendScope guard(*this); - - if (!eglMakeCurrent(display, surface, surface, context)) { - mbgl::Log::Error(mbgl::Event::OpenGL, "eglMakeCurrent() returned error %d", - eglGetError()); - throw std::runtime_error("eglMakeCurrent() failed"); - } - - mbgl::gl::InitializeExtensions([] (const char * name) { - return reinterpret_cast<mbgl::gl::glProc>(eglGetProcAddress(name)); - }); - } -} - -void NativeMapView::destroySurface() { - if (surface != EGL_NO_SURFACE) { - if (!eglDestroySurface(display, surface)) { - mbgl::Log::Error(mbgl::Event::OpenGL, "eglDestroySurface() returned error %d", - eglGetError()); - throw std::runtime_error("eglDestroySurface() failed"); - } - } - - surface = EGL_NO_SURFACE; - - if (window != nullptr) { - ANativeWindow_release(window); - window = nullptr; - } -} - void NativeMapView::scheduleTakeSnapshot() { snapshot = true; } -// Speed -/* -typedef enum { - Format16Bit = 0, - Format32BitNoAlpha = 1, - Format32BitAlpha = 2, - Format24Bit = 3, - Unknown = 4 -} BufferFormat; - -typedef enum { - Format16Depth8Stencil = 0, - Format24Depth8Stencil = 1, -} DepthStencilFormat; -*/ - -// Quality -typedef enum { - Format16Bit = 3, - Format32BitNoAlpha = 1, - Format32BitAlpha = 2, - Format24Bit = 0, - Unknown = 4 -} BufferFormat; - -typedef enum { - Format16Depth8Stencil = 1, - Format24Depth8Stencil = 0, -} DepthStencilFormat; - -// Tuple is <buffer_format, depth_stencil_format, is_not_conformant, is_caveat, config_num, -// config_id> -typedef std::tuple<BufferFormat, DepthStencilFormat, bool, bool, int, EGLConfig> ConfigProperties; - -EGLConfig NativeMapView::chooseConfig(const EGLConfig configs[], EGLint numConfigs) { - // Create a list of configs that pass our filters - std::list<ConfigProperties> configList; - for (int i = 0; i < numConfigs; i++) { - EGLint caveat, conformant, bits, red, green, blue, alpha, alphaMask, depth, stencil, - sampleBuffers, samples; - - if (!eglGetConfigAttrib(display, configs[i], EGL_CONFIG_CAVEAT, &caveat)) { - mbgl::Log::Error(mbgl::Event::OpenGL, - "eglGetConfigAttrib(EGL_CONFIG_CAVEAT) returned error %d", - eglGetError()); - throw std::runtime_error("eglGetConfigAttrib() failed"); - } - - if (!eglGetConfigAttrib(display, configs[i], EGL_CONFORMANT, &conformant)) { - mbgl::Log::Error(mbgl::Event::OpenGL, - "eglGetConfigAttrib(EGL_CONFORMANT) returned error %d", eglGetError()); - throw std::runtime_error("eglGetConfigAttrib() failed"); - } - - if (!eglGetConfigAttrib(display, configs[i], EGL_BUFFER_SIZE, &bits)) { - mbgl::Log::Error(mbgl::Event::OpenGL, - "eglGetConfigAttrib(EGL_BUFFER_SIZE) returned error %d", - eglGetError()); - throw std::runtime_error("eglGetConfigAttrib() failed"); - } - - if (!eglGetConfigAttrib(display, configs[i], EGL_RED_SIZE, &red)) { - mbgl::Log::Error(mbgl::Event::OpenGL, - "eglGetConfigAttrib(EGL_RED_SIZE) returned error %d", eglGetError()); - throw std::runtime_error("eglGetConfigAttrib() failed"); - } - - if (!eglGetConfigAttrib(display, configs[i], EGL_GREEN_SIZE, &green)) { - mbgl::Log::Error(mbgl::Event::OpenGL, - "eglGetConfigAttrib(EGL_GREEN_SIZE) returned error %d", eglGetError()); - throw std::runtime_error("eglGetConfigAttrib() failed"); - } - - if (!eglGetConfigAttrib(display, configs[i], EGL_BLUE_SIZE, &blue)) { - mbgl::Log::Error(mbgl::Event::OpenGL, - "eglGetConfigAttrib(EGL_BLUE_SIZE) returned error %d", eglGetError()); - throw std::runtime_error("eglGetConfigAttrib() failed"); - } - - if (!eglGetConfigAttrib(display, configs[i], EGL_ALPHA_SIZE, &alpha)) { - mbgl::Log::Error(mbgl::Event::OpenGL, - "eglGetConfigAttrib(EGL_ALPHA_SIZE) returned error %d", eglGetError()); - throw std::runtime_error("eglGetConfigAttrib() failed"); - } - - if (!eglGetConfigAttrib(display, configs[i], EGL_ALPHA_MASK_SIZE, &alphaMask)) { - mbgl::Log::Error(mbgl::Event::OpenGL, - "eglGetConfigAttrib(EGL_ALPHA_MASK_SIZE) returned error %d", - eglGetError()); - throw std::runtime_error("eglGetConfigAttrib() failed"); - } - - if (!eglGetConfigAttrib(display, configs[i], EGL_DEPTH_SIZE, &depth)) { - mbgl::Log::Error(mbgl::Event::OpenGL, - "eglGetConfigAttrib(EGL_DEPTH_SIZE) returned error %d", eglGetError()); - throw std::runtime_error("eglGetConfigAttrib() failed"); - } - - if (!eglGetConfigAttrib(display, configs[i], EGL_STENCIL_SIZE, &stencil)) { - mbgl::Log::Error(mbgl::Event::OpenGL, - "eglGetConfigAttrib(EGL_STENCIL_SIZE) returned error %d", - eglGetError()); - throw std::runtime_error("eglGetConfigAttrib() failed"); - } - - if (!eglGetConfigAttrib(display, configs[i], EGL_SAMPLE_BUFFERS, &sampleBuffers)) { - mbgl::Log::Error(mbgl::Event::OpenGL, - "eglGetConfigAttrib(EGL_SAMPLE_BUFFERS) returned error %d", - eglGetError()); - throw std::runtime_error("eglGetConfigAttrib() failed"); - } - - if (!eglGetConfigAttrib(display, configs[i], EGL_SAMPLES, &samples)) { - mbgl::Log::Error(mbgl::Event::OpenGL, - "eglGetConfigAttrib(EGL_SAMPLES) returned error %d", eglGetError()); - throw std::runtime_error("eglGetConfigAttrib() failed"); - } - - bool configOk = true; - configOk &= (depth == 24) || (depth == 16); - configOk &= stencil == 8; - configOk &= sampleBuffers == 0; - configOk &= samples == 0; - - // Filter our configs first for depth, stencil and anti-aliasing - if (configOk) { - // Work out the config's buffer format - BufferFormat bufferFormat; - if ((bits == 16) && (red == 5) && (green == 6) && (blue == 5) && (alpha == 0)) { - bufferFormat = Format16Bit; - } else if ((bits == 32) && (red == 8) && (green == 8) && (blue == 8) && (alpha == 0)) { - bufferFormat = Format32BitNoAlpha; - } else if ((bits == 32) && (red == 8) && (green == 8) && (blue == 8) && (alpha == 8)) { - bufferFormat = Format32BitAlpha; - } else if ((bits == 24) && (red == 8) && (green == 8) && (blue == 8) && (alpha == 0)) { - bufferFormat = Format24Bit; - } else { - bufferFormat = Unknown; - } - - // Work out the config's depth stencil format - DepthStencilFormat depthStencilFormat; - if ((depth == 16) && (stencil == 8)) { - depthStencilFormat = Format16Depth8Stencil; - } else { - depthStencilFormat = Format24Depth8Stencil; - } - - bool isNotConformant = (conformant & EGL_OPENGL_ES2_BIT) != EGL_OPENGL_ES2_BIT; - bool isCaveat = caveat != EGL_NONE; - EGLConfig configId = configs[i]; - - // Ignore formats we don't recognise - if (bufferFormat != Unknown) { - configList.push_back(std::make_tuple(bufferFormat, depthStencilFormat, - isNotConformant, isCaveat, i, configId)); - } - } - } - - if (configList.empty()) { - mbgl::Log::Error(mbgl::Event::OpenGL, "Config list was empty."); - } - - // Sort the configs to find the best one - configList.sort(); - bool isConformant = !std::get<2>(configList.front()); - bool isCaveat = std::get<3>(configList.front()); - EGLConfig configId = std::get<5>(configList.front()); - - if (isCaveat) { - mbgl::Log::Warning(mbgl::Event::OpenGL, "Chosen config has a caveat."); - } - if (!isConformant) { - mbgl::Log::Warning(mbgl::Event::OpenGL, "Chosen config is not conformant."); - } - - return configId; -} void NativeMapView::notifyMapChange(mbgl::MapChange change) { + mbgl::Log::Info(mbgl::Event::Android, "notifyMapChange"); assert(vm != nullptr); assert(obj != nullptr); @@ -610,7 +206,7 @@ void NativeMapView::updateFps() { if (currentTime - timeElapsed >= 1) { fps = frames / ((currentTime - timeElapsed) / 1E9); - mbgl::Log::Debug(mbgl::Event::Render, "FPS: %4.2f", fps); + mbgl::Log::Info(mbgl::Event::Render, "FPS: %4.2f", fps); timeElapsed = currentTime; frames = 0; } @@ -628,13 +224,20 @@ void NativeMapView::updateFps() { } } +void NativeMapView::onViewportChanged(int w, int h) { + resizeView((int) w / pixelRatio, (int) h / pixelRatio); + resizeFramebuffer(w, h); +} + void NativeMapView::resizeView(int w, int h) { + mbgl::Log::Info(mbgl::Event::Android, "resizeView %ix%i", w, h); width = w; height = h; map->setSize({ static_cast<uint32_t>(width), static_cast<uint32_t>(height) }); } void NativeMapView::resizeFramebuffer(int w, int h) { + mbgl::Log::Info(mbgl::Event::Android, "resizeFramebuffer %ix%i", w, h); fbWidth = w; fbHeight = h; framebufferSizeChanged = true; diff --git a/platform/android/src/native_map_view.hpp b/platform/android/src/native_map_view.hpp index e7379700a9..81274f3a24 100755 --- a/platform/android/src/native_map_view.hpp +++ b/platform/android/src/native_map_view.hpp @@ -5,12 +5,11 @@ #include <mbgl/map/backend.hpp> #include <mbgl/util/noncopyable.hpp> #include <mbgl/util/default_thread_pool.hpp> +#include <mbgl/util/run_loop.hpp> #include <mbgl/storage/default_file_source.hpp> #include <string> #include <jni.h> -#include <android/native_window.h> -#include <EGL/egl.h> namespace mbgl { namespace android { @@ -20,68 +19,57 @@ public: NativeMapView(JNIEnv *env, jobject obj, float pixelRatio, int availableProcessors, size_t totalMemory); virtual ~NativeMapView(); - mbgl::Size getFramebufferSize() const; - void updateViewBinding(); + // mbgl::View // + void bind() override; - void invalidate() override; + // mbgl::Backend // + void invalidate() override; void notifyMapChange(mbgl::MapChange) override; + // JNI // + mbgl::Map &getMap(); mbgl::DefaultFileSource &getFileSource(); - void initializeDisplay(); - void terminateDisplay(); - - void initializeContext(); - void terminateContext(); - - void createSurface(ANativeWindow *window); - void destroySurface(); - void render(); void enableFps(bool enable); - void updateFps(); - void resizeView(int width, int height); - void resizeFramebuffer(int width, int height); + void onViewportChanged(int width, int height); + mbgl::EdgeInsets getInsets() { return insets;} void setInsets(mbgl::EdgeInsets insets_); void scheduleTakeSnapshot(); protected: - void activate() override; - void deactivate() override; + // Unused // -private: - EGLConfig chooseConfig(const EGLConfig configs[], EGLint numConfigs); + void activate() override {}; + void deactivate() override {}; private: - JavaVM *vm = nullptr; - JNIEnv *env = nullptr; - jweak obj = nullptr; + void wake(); + void updateViewBinding(); + mbgl::Size getFramebufferSize() const; - ANativeWindow *window = nullptr; + void resizeView(int width, int height); + void resizeFramebuffer(int width, int height); - EGLDisplay oldDisplay = EGL_NO_DISPLAY; - EGLSurface oldReadSurface = EGL_NO_SURFACE; - EGLSurface oldDrawSurface = EGL_NO_SURFACE; - EGLContext oldContext = EGL_NO_CONTEXT; + void updateFps(); - EGLDisplay display = EGL_NO_DISPLAY; - EGLSurface surface = EGL_NO_SURFACE; - EGLContext context = EGL_NO_CONTEXT; +private: - EGLConfig config = nullptr; - EGLint format = -1; + JavaVM *vm = nullptr; + JNIEnv *env = nullptr; + jweak obj = nullptr; std::string styleUrl; std::string apiKey; - bool firstTime = false; + float pixelRatio; bool fpsEnabled = false; bool snapshot = false; double fps = 0.0; @@ -96,12 +84,12 @@ private: size_t totalMemory = 0; // Ensure these are initialised last + std::unique_ptr<mbgl::util::RunLoop> runLoop; std::unique_ptr<mbgl::DefaultFileSource> fileSource; mbgl::ThreadPool threadPool; std::unique_ptr<mbgl::Map> map; mbgl::EdgeInsets insets; - unsigned active = 0; }; } } diff --git a/platform/android/src/run_loop.cpp b/platform/android/src/run_loop.cpp index 170b05c23c..9ad9aa1db7 100644 --- a/platform/android/src/run_loop.cpp +++ b/platform/android/src/run_loop.cpp @@ -4,6 +4,7 @@ #include <mbgl/util/thread_context.hpp> #include <mbgl/util/thread_local.hpp> #include <mbgl/util/timer.hpp> +#include <mbgl/util/logging.hpp> #include <android/looper.h> @@ -129,9 +130,16 @@ RunLoop::Impl::~Impl() { } void RunLoop::Impl::wake() { + mbgl::Log::Info(mbgl::Event::Android, "Waking...?"); if (write(fds[PIPE_IN], "\n", 1) == -1) { throw std::runtime_error("Failed to write to file descriptor."); } + + // If the loop has a wake function, call it (assumed to be thread safe) + if (wakeFunction) { + mbgl::Log::Info(mbgl::Event::Android, "Calling wake function"); + wakeFunction(); + } } void RunLoop::Impl::addRunnable(Runnable* runnable) { @@ -208,6 +216,7 @@ RunLoop::~RunLoop() { } LOOP_HANDLE RunLoop::getLoopHandle() { + assert (current.get() != nullptr); return current.get()->impl.get(); } diff --git a/platform/android/src/run_loop_impl.hpp b/platform/android/src/run_loop_impl.hpp index a3efa92a83..b37b597b12 100644 --- a/platform/android/src/run_loop_impl.hpp +++ b/platform/android/src/run_loop_impl.hpp @@ -33,6 +33,11 @@ public: Impl(RunLoop*, RunLoop::Type); ~Impl(); + // Optional wake function (for other wake mechanisms than pipes, eg no java run loop present) + void setWakeFunction(std::function<void()> callback) { + wakeFunction = callback; + } + void wake(); void addRunnable(Runnable*); @@ -49,6 +54,7 @@ private: friend RunLoop; int fds[2]; + std::function<void()> wakeFunction; JNIEnv *env = nullptr; bool detach = false; |