From 15a47d116a0fc15d249b37574fcd932ce88909df Mon Sep 17 00:00:00 2001 From: Ivo van Dongen Date: Mon, 11 Sep 2017 11:04:53 +0300 Subject: [android] schedule work on the gl thread using GLSurfaceView#queueEvent --- .../java/com/mapbox/mapboxsdk/maps/MapView.java | 12 ++---- .../com/mapbox/mapboxsdk/maps/NativeMapView.java | 44 ++++++++++++++++++---- .../maps/renderer/GlSurfaceViewRenderThread.java | 25 ++++++++++++ .../mapboxsdk/maps/renderer/RenderThread.java | 12 ++++++ platform/android/src/android_gl_thread.hpp | 18 ++++----- platform/android/src/android_renderer_frontend.cpp | 17 +++++---- platform/android/src/android_renderer_frontend.hpp | 7 +++- platform/android/src/native_map_view.cpp | 24 ++++++++---- platform/android/src/native_map_view.hpp | 10 +++-- 9 files changed, 122 insertions(+), 47 deletions(-) create mode 100644 platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/GlSurfaceViewRenderThread.java create mode 100644 platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/RenderThread.java diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java index a920bed720..086f57abf6 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java @@ -28,6 +28,7 @@ import com.mapbox.mapboxsdk.annotations.MarkerViewManager; import com.mapbox.mapboxsdk.constants.MapboxConstants; import com.mapbox.mapboxsdk.constants.Style; import com.mapbox.mapboxsdk.egl.EGLConfigChooser; +import com.mapbox.mapboxsdk.maps.renderer.GlSurfaceViewRenderThread; import com.mapbox.mapboxsdk.maps.widgets.CompassView; import com.mapbox.mapboxsdk.maps.widgets.MyLocationView; import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings; @@ -312,6 +313,8 @@ public class MapView extends FrameLayout { }); glSurfaceView.setRenderMode(RENDERMODE_WHEN_DIRTY); glSurfaceView.setVisibility(View.VISIBLE); + + nativeMapView.setRenderThread(new GlSurfaceViewRenderThread(glSurfaceView)); } /** @@ -494,15 +497,6 @@ public class MapView extends FrameLayout { // Rendering // - // Called when the map needs to be rerendered - // Called via JNI from NativeMapView - protected void onInvalidate() { - if (glSurfaceView != null) { - glSurfaceView.requestRender(); - } - // TODO: removable? postInvalidate(); - } - @Override protected void onSizeChanged(int width, int height, int oldw, int oldh) { if (destroyed) { diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java index a97b7cc8f2..240e68bf13 100755 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java @@ -20,6 +20,7 @@ import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.geometry.LatLngBounds; import com.mapbox.mapboxsdk.geometry.ProjectedMeters; +import com.mapbox.mapboxsdk.maps.renderer.RenderThread; import com.mapbox.mapboxsdk.storage.FileSource; import com.mapbox.mapboxsdk.style.layers.CannotAddLayerException; import com.mapbox.mapboxsdk.style.layers.Filter; @@ -52,6 +53,9 @@ final class NativeMapView implements GLSurfaceView.Renderer { // Used for callbacks private MapView mapView; + // Used to schedule work on the render thread + private RenderThread renderThread; + //Hold a reference to prevent it from being GC'd as long as it's used on the native side private final FileSource fileSource; @@ -69,7 +73,7 @@ final class NativeMapView implements GLSurfaceView.Renderer { // Constructors // - public NativeMapView(MapView mapView) { + public NativeMapView(final MapView mapView) { Context context = mapView.getContext(); fileSource = FileSource.getInstance(context); @@ -84,6 +88,10 @@ final class NativeMapView implements GLSurfaceView.Renderer { // Methods // + public void setRenderThread(RenderThread renderThread) { + this.renderThread = renderThread; + } + private boolean isDestroyedOn(String callingMethod) { if (destroyed && !TextUtils.isEmpty(callingMethod)) { Timber.e( @@ -104,7 +112,8 @@ final class NativeMapView implements GLSurfaceView.Renderer { if (isDestroyedOn("update")) { return; } - nativeUpdate(); + + requestRender(); } public void render() { @@ -864,9 +873,28 @@ final class NativeMapView implements GLSurfaceView.Renderer { // Callbacks // - protected void onInvalidate() { - if (mapView != null) { - mapView.onInvalidate(); + /** + * Called from JNI whenever the native map + * needs rendering. + */ + protected void requestRender() { + if (renderThread != null) { + renderThread.requestRender(); + } + } + + /** + * Called from JNI when work needs to be processed on + * the Renderer Thread. + */ + protected void requestProcessing() { + if (renderThread != null) { + renderThread.queueEvent(new Runnable() { + @Override + public void run() { + nativeProcess(); + } + }); } } @@ -905,6 +933,8 @@ final class NativeMapView implements GLSurfaceView.Renderer { private native void nativeDestroy(); + private native void nativeProcess(); + private native void nativeInitializeDisplay(); private native void nativeTerminateDisplay(); @@ -1130,9 +1160,7 @@ final class NativeMapView implements GLSurfaceView.Renderer { void addSnapshotCallback(@NonNull MapboxMap.SnapshotReadyCallback callback) { snapshotReadyCallback = callback; scheduleTakeSnapshot(); - mapView.onInvalidate(); - // TODO. this should do a request render - //render(); + renderThread.requestRender(); } // diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/GlSurfaceViewRenderThread.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/GlSurfaceViewRenderThread.java new file mode 100644 index 0000000000..4b8df51dbe --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/GlSurfaceViewRenderThread.java @@ -0,0 +1,25 @@ +package com.mapbox.mapboxsdk.maps.renderer; + +import android.opengl.GLSurfaceView; + +/** + * {@link RenderThread} implementation that schedules using the + * {@link GLSurfaceView} thread. + */ +public class GlSurfaceViewRenderThread implements RenderThread { + private final GLSurfaceView surfaceView; + + public GlSurfaceViewRenderThread(GLSurfaceView surfaceView) { + this.surfaceView = surfaceView; + } + + @Override + public void requestRender() { + surfaceView.requestRender(); + } + + @Override + public void queueEvent(Runnable runnable) { + surfaceView.queueEvent(runnable); + } +} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/RenderThread.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/RenderThread.java new file mode 100644 index 0000000000..3b9f0f2151 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/RenderThread.java @@ -0,0 +1,12 @@ +package com.mapbox.mapboxsdk.maps.renderer; + +/** + * Created by ivo on 11/09/2017. + */ + +public interface RenderThread { + + void requestRender(); + + void queueEvent(Runnable runnable); +} diff --git a/platform/android/src/android_gl_thread.hpp b/platform/android/src/android_gl_thread.hpp index 1c2412d594..78777aa475 100644 --- a/platform/android/src/android_gl_thread.hpp +++ b/platform/android/src/android_gl_thread.hpp @@ -44,20 +44,18 @@ public: // Only safe on the GL Thread void process() { - while (true) { - std::unique_lock lock(mutex); + std::unique_lock lock(mutex); - if (queue.empty()) { - return; - } + if (queue.empty()) { + return; + } - auto scheduled = queue.front(); - queue.pop(); + auto scheduled = queue.front(); + queue.pop(); - lock.unlock(); + lock.unlock(); - Mailbox::maybeReceive(scheduled); - } + Mailbox::maybeReceive(scheduled); } // Only safe to access on the GL Thread diff --git a/platform/android/src/android_renderer_frontend.cpp b/platform/android/src/android_renderer_frontend.cpp index cdcd8eddfe..0619ba4cb5 100644 --- a/platform/android/src/android_renderer_frontend.cpp +++ b/platform/android/src/android_renderer_frontend.cpp @@ -58,10 +58,11 @@ AndroidRendererFrontend::AndroidRendererFrontend(float pixelRatio, FileSource& fileSource, Scheduler& scheduler, std::string programCacheDir, - InvalidateCallback invalidate) + RequestRenderCallback requestRender, + RequestProcessingCallback requestProcessing) : backend(std::make_unique()) , glThread(std::make_unique( - invalidate, + std::move(requestProcessing), *backend, pixelRatio, fileSource, @@ -69,8 +70,8 @@ AndroidRendererFrontend::AndroidRendererFrontend(float pixelRatio, GLContextMode::Unique, programCacheDir )) - , asyncInvalidate([=]() { - invalidate(); + , asyncInvalidate([requestRender=std::move(requestRender)]() { + requestRender(); }) , mapRunLoop(util::RunLoop::Get()) { } @@ -112,9 +113,6 @@ void AndroidRendererFrontend::render() { params = updateParameters; } - // Process the gl thread mailbox - glThread->process(); - // Activate the backend BackendScope backendGuard { *backend }; @@ -130,6 +128,11 @@ void AndroidRendererFrontend::render() { glThread->renderer->render(*params); } +void AndroidRendererFrontend::process() { + // Process the gl thread mailbox + glThread->process(); +} + void AndroidRendererFrontend::onLowMemory() { assert (glThread); glThread->actor().invoke(&Renderer::onLowMemory); diff --git a/platform/android/src/android_renderer_frontend.hpp b/platform/android/src/android_renderer_frontend.hpp index f2e951bd05..57bfd62b26 100644 --- a/platform/android/src/android_renderer_frontend.hpp +++ b/platform/android/src/android_renderer_frontend.hpp @@ -30,13 +30,15 @@ class AndroidRendererBackend; class AndroidRendererFrontend : public RendererFrontend { public: - using InvalidateCallback = std::function; + using RequestRenderCallback = std::function; + using RequestProcessingCallback = std::function; AndroidRendererFrontend(float pixelRatio, mbgl::FileSource&, mbgl::Scheduler&, std::string programCacheDir, - InvalidateCallback); + RequestRenderCallback, + RequestProcessingCallback); ~AndroidRendererFrontend() override; void reset() override; @@ -46,6 +48,7 @@ public: // Called from OpenGL Thread void render(); + void process(); // Feature querying std::vector queryRenderedFeatures(const ScreenCoordinate&, const RenderedQueryOptions&) const; diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp index 1a0dc34bbc..51edd8079f 100755 --- a/platform/android/src/native_map_view.cpp +++ b/platform/android/src/native_map_view.cpp @@ -78,7 +78,8 @@ NativeMapView::NativeMapView(jni::JNIEnv& _env, *threadPool, jni::Make(_env, _programCacheDir), - [this] { this->invalidate(); }); + [this] { this->requestRender(); }, + [this] { this->requestProcessing(); }); // Create the core map map = std::make_unique(*rendererFrontend, *this, @@ -97,17 +98,23 @@ NativeMapView::~NativeMapView() { } /** - * Callback to java NativeMapView#onInvalidate(). + * Callback to java NativeMapView#requestRender(). * - * Called to invalidate the View and schedule a render on the next + * Called to schedule a render on the next * runloop iteration. */ -void NativeMapView::invalidate() { +void NativeMapView::requestRender() { android::UniqueEnv _env = android::AttachEnv(); - static auto onInvalidate = javaClass.GetMethod(*_env, "onInvalidate"); + static auto onInvalidate = javaClass.GetMethod(*_env, "requestRender"); javaPeer->Call(*_env, onInvalidate); } +void NativeMapView::requestProcessing() { + android::UniqueEnv _env = android::AttachEnv(); + static auto requestProcessing = javaClass.GetMethod(*_env, "requestProcessing"); + javaPeer->Call(*_env, requestProcessing); +} + /** * From mbgl::RendererBackend. Callback to java NativeMapView#onMapChanged(int). * @@ -195,8 +202,9 @@ void NativeMapView::render(jni::JNIEnv& ) { updateFps(); } -void NativeMapView::update(jni::JNIEnv&) { - invalidate(); +// Called from the OpenGL renderer thread +void NativeMapView::process(jni::JNIEnv&) { + rendererFrontend->process(); } void NativeMapView::resizeView(jni::JNIEnv&, int w, int h) { @@ -1004,7 +1012,7 @@ void NativeMapView::registerNative(jni::JNIEnv& env) { "nativeInitialize", "nativeDestroy", METHOD(&NativeMapView::render, "nativeRender"), - METHOD(&NativeMapView::update, "nativeUpdate"), + METHOD(&NativeMapView::process, "nativeProcess"), METHOD(&NativeMapView::resizeView, "nativeResizeView"), METHOD(&NativeMapView::resizeFramebuffer, "nativeResizeFramebuffer"), METHOD(&NativeMapView::getStyleUrl, "nativeGetStyleUrl"), diff --git a/platform/android/src/native_map_view.hpp b/platform/android/src/native_map_view.hpp index 0539a29b46..7376f82c24 100755 --- a/platform/android/src/native_map_view.hpp +++ b/platform/android/src/native_map_view.hpp @@ -73,7 +73,10 @@ public: void onSourceChanged(mbgl::style::Source&) override; // Signal the view system, we want to redraw - void invalidate(); + void requestRender(); + + // Request processing on the GL Thread + void requestProcessing(); // JNI // @@ -81,9 +84,10 @@ public: void onSurfaceCreated(jni::JNIEnv&); // Called on OpenGL Thread - void render(jni::JNIEnv&); + void process(jni::JNIEnv&); - void update(jni::JNIEnv&); + // Called on OpenGL Thread + void render(jni::JNIEnv&); void resizeView(jni::JNIEnv&, int, int); -- cgit v1.2.1