diff options
author | Ivo van Dongen <info@ivovandongen.nl> | 2017-09-14 21:23:07 +0300 |
---|---|---|
committer | Ivo van Dongen <ivovandongen@users.noreply.github.com> | 2017-09-22 23:33:56 +0300 |
commit | 5d12503302dff168137d6f3b1444e4dc32ad44dd (patch) | |
tree | 98128bdddb287c30b2c1445eb88d44e9a97d57ab /platform/android/MapboxGLAndroidSDK/src | |
parent | 15a47d116a0fc15d249b37574fcd932ce88909df (diff) | |
download | qtlocation-mapboxgl-5d12503302dff168137d6f3b1444e4dc32ad44dd.tar.gz |
[android] self-contained map renderer
- Isolates the GL thread in a MapRenderer class with a native peer
Diffstat (limited to 'platform/android/MapboxGLAndroidSDK/src')
7 files changed, 190 insertions, 177 deletions
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 086f57abf6..6612110649 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,7 +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.renderer.MapRenderer; import com.mapbox.mapboxsdk.maps.widgets.CompassView; import com.mapbox.mapboxsdk.maps.widgets.MyLocationView; import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings; @@ -286,35 +286,31 @@ public class MapView extends FrameLayout { glSurfaceView.setZOrderMediaOverlay(mapboxMapOptions.getRenderSurfaceOnTop()); glSurfaceView.setEGLContextClientVersion(2); glSurfaceView.setEGLConfigChooser(new EGLConfigChooser()); - glSurfaceView.setRenderer(new GLSurfaceView.Renderer() { + MapRenderer mapRenderer = new MapRenderer(getContext(), glSurfaceView) { @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { MapView.this.post(new Runnable() { @Override public void run() { - initialiseMap(); - mapboxMap.onStart(); + // Initialise only once + if (mapboxMap == null) { + initialiseMap(); + mapboxMap.onStart(); + } } }); - nativeMapView.onSurfaceCreated(gl, config); - } - - @Override - public void onSurfaceChanged(GL10 gl, int width, int height) { - nativeMapView.onSurfaceChanged(gl, width, height); + super.onSurfaceCreated(gl, config); } + }; - @Override - public void onDrawFrame(GL10 gl) { - nativeMapView.onDrawFrame(gl); - } - }); + glSurfaceView.setRenderer(mapRenderer); glSurfaceView.setRenderMode(RENDERMODE_WHEN_DIRTY); glSurfaceView.setVisibility(View.VISIBLE); - nativeMapView.setRenderThread(new GlSurfaceViewRenderThread(glSurfaceView)); + nativeMapView = new NativeMapView(this, mapRenderer); + nativeMapView.resizeView(getMeasuredWidth(), getMeasuredHeight()); } /** @@ -527,9 +523,7 @@ public class MapView extends FrameLayout { return; } - if (nativeMapView == null) { - nativeMapView = new NativeMapView(this); - } else if (mapZoomButtonController != null) { + if (mapZoomButtonController != null) { mapZoomButtonController.setVisible(visibility == View.VISIBLE); } } 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 240e68bf13..62fe2be0c3 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 @@ -4,7 +4,6 @@ import android.content.Context; import android.graphics.Bitmap; import android.graphics.PointF; import android.graphics.RectF; -import android.opengl.GLSurfaceView; import android.support.annotation.IntRange; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -20,7 +19,8 @@ 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.maps.renderer.MapRenderer; +import com.mapbox.mapboxsdk.maps.renderer.MapRendererScheduler; import com.mapbox.mapboxsdk.storage.FileSource; import com.mapbox.mapboxsdk.style.layers.CannotAddLayerException; import com.mapbox.mapboxsdk.style.layers.Filter; @@ -36,13 +36,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import javax.microedition.khronos.egl.EGLConfig; -import javax.microedition.khronos.opengles.GL10; - import timber.log.Timber; // Class that wraps the native methods for convenience -final class NativeMapView implements GLSurfaceView.Renderer { +final class NativeMapView { // Flag to indicating destroy was called private boolean destroyed = false; @@ -53,12 +50,12 @@ 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; + // Used to schedule work on the MapRenderer Thread + private MapRendererScheduler scheduler; + // Device density private final float pixelRatio; @@ -73,25 +70,21 @@ final class NativeMapView implements GLSurfaceView.Renderer { // Constructors // - public NativeMapView(final MapView mapView) { + public NativeMapView(final MapView mapView, MapRenderer mapRenderer) { + this.scheduler = mapRenderer; + this.mapView = mapView; + Context context = mapView.getContext(); fileSource = FileSource.getInstance(context); - pixelRatio = context.getResources().getDisplayMetrics().density; - this.mapView = mapView; - String programCacheDir = context.getCacheDir().getAbsolutePath(); - nativeInitialize(this, fileSource, pixelRatio, programCacheDir); + nativeInitialize(this, fileSource, mapRenderer, pixelRatio); } // // Methods // - public void setRenderThread(RenderThread renderThread) { - this.renderThread = renderThread; - } - private boolean isDestroyedOn(String callingMethod) { if (destroyed && !TextUtils.isEmpty(callingMethod)) { Timber.e( @@ -113,14 +106,7 @@ final class NativeMapView implements GLSurfaceView.Renderer { return; } - requestRender(); - } - - public void render() { - if (isDestroyedOn("render")) { - return; - } - nativeRender(); + scheduler.requestRender(); } public void resizeView(int width, int height) { @@ -151,31 +137,8 @@ final class NativeMapView implements GLSurfaceView.Renderer { + "capping value at 65535 instead of %s", height); height = 65535; } - nativeResizeView(width, height); - } - - private void resizeFramebuffer(int fbWidth, int fbHeight) { - if (isDestroyedOn("resizeFramebuffer")) { - return; - } - if (fbWidth < 0) { - throw new IllegalArgumentException("fbWidth cannot be negative."); - } - if (fbHeight < 0) { - throw new IllegalArgumentException("fbHeight cannot be negative."); - } - - if (fbWidth > 65535) { - throw new IllegalArgumentException( - "fbWidth cannot be greater than 65535."); - } - - if (fbHeight > 65535) { - throw new IllegalArgumentException( - "fbHeight cannot be greater than 65535."); - } - nativeResizeFramebuffer(fbWidth, fbHeight); + nativeResizeView(width, height); } public void setStyleUrl(String url) { @@ -873,31 +836,6 @@ final class NativeMapView implements GLSurfaceView.Renderer { // Callbacks // - /** - * 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(); - } - }); - } - } - protected void onMapChanged(int rawChange) { if (mapView != null) { mapView.onMapChange(rawChange); @@ -928,33 +866,13 @@ final class NativeMapView implements GLSurfaceView.Renderer { private native void nativeInitialize(NativeMapView nativeMapView, FileSource fileSource, - float pixelRatio, - String programCacheDir); + MapRenderer mapRenderer, + float pixelRatio); private native void nativeDestroy(); - private native void nativeProcess(); - - private native void nativeInitializeDisplay(); - - private native void nativeTerminateDisplay(); - - private native void nativeInitializeContext(); - - private native void nativeTerminateContext(); - - private native void nativeCreateSurface(Object surface); - - private native void nativeDestroySurface(); - - private native void nativeUpdate(); - - private native void nativeRender(); - private native void nativeResizeView(int width, int height); - private native void nativeResizeFramebuffer(int fbWidth, int fbHeight); - private native void nativeSetStyleUrl(String url); private native String nativeGetStyleUrl(); @@ -1160,30 +1078,7 @@ final class NativeMapView implements GLSurfaceView.Renderer { void addSnapshotCallback(@NonNull MapboxMap.SnapshotReadyCallback callback) { snapshotReadyCallback = callback; scheduleTakeSnapshot(); - renderThread.requestRender(); - } - - // - // GLSurfaceView.Renderer - // - - @Override - public void onSurfaceCreated(GL10 gl, EGLConfig config) { - Timber.i("[%s] onSurfaceCreated", Thread.currentThread().getName()); - //TODO: callback to map to re-create renderer? + scheduler.requestRender(); } - @Override - public void onSurfaceChanged(GL10 gl, int width, int height) { - Timber.i("[%s] onSurfaceChanged %sx%s", Thread.currentThread().getName(), width, height); - // Sets the current view port to the new size. - gl.glViewport(0, 0, width, height); - resizeFramebuffer(width, height); - // resizeView(width, height); Done from MapView#onSizeChanged - } - - @Override - public void onDrawFrame(GL10 gl) { - nativeRender(); - } } 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 deleted file mode 100644 index 4b8df51dbe..0000000000 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/GlSurfaceViewRenderThread.java +++ /dev/null @@ -1,25 +0,0 @@ -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/MapRenderer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java new file mode 100644 index 0000000000..772ecb79fb --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java @@ -0,0 +1,119 @@ +package com.mapbox.mapboxsdk.maps.renderer; + +import android.content.Context; +import android.opengl.GLSurfaceView; + +import com.mapbox.mapboxsdk.storage.FileSource; + +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.opengles.GL10; + +/** + * The {@link MapRenderer} encapsulates the GL thread. + * <p> + * Performs actions on the GL thread to manage the GL resources and + * render on the one end and acts as a scheduler to request work to + * be performed on the GL thread on the other. + */ +public class MapRenderer implements GLSurfaceView.Renderer, MapRendererScheduler { + + // Holds the pointer to the native peer after initialisation + private long nativePtr = 0; + + private final GLSurfaceView glSurfaceView; + + public MapRenderer(Context context, GLSurfaceView glSurfaceView) { + this.glSurfaceView = glSurfaceView; + + FileSource fileSource = FileSource.getInstance(context); + float pixelRatio = context.getResources().getDisplayMetrics().density; + String programCacheDir = context.getCacheDir().getAbsolutePath(); + + // Initialise native peer + nativeInitialize(this, fileSource, pixelRatio, programCacheDir); + } + + @Override + public void onSurfaceCreated(GL10 gl, EGLConfig config) { + nativeOnSurfaceCreated(); + } + + @Override + public void onSurfaceChanged(GL10 gl, int width, int height) { + if (width < 0) { + throw new IllegalArgumentException("fbWidth cannot be negative."); + } + + if (height < 0) { + throw new IllegalArgumentException("fbHeight cannot be negative."); + } + + if (width > 65535) { + throw new IllegalArgumentException( + "fbWidth cannot be greater than 65535."); + } + + if (height > 65535) { + throw new IllegalArgumentException( + "fbHeight cannot be greater than 65535."); + } + + gl.glViewport(0, 0, width, height); + nativeOnSurfaceChanged(width, height); + } + + @Override + public void onDrawFrame(GL10 gl) { + nativeRender(); + } + + /** + * May be called from any thread. + * <p> + * Called from the renderer frontend to schedule a render. + */ + @Override + public void requestRender() { + glSurfaceView.requestRender(); + } + + /** + * May be called from any thread. + * <p> + * Schedules work to be performed on the MapRenderer thread. + * + * @param runnable the runnable to execute + */ + @Override + public void queueEvent(Runnable runnable) { + glSurfaceView.queueEvent(runnable); + } + + /** + * May be called from any thread. + * <p> + * Called from the native peer to schedule work on the GL + * thread. Explicit override for easier to read jni code. + * + * @param runnable the runnable to execute + * @see MapRendererRunnable + */ + void queueEvent(MapRendererRunnable runnable) { + this.queueEvent((Runnable) runnable); + } + + private native void nativeInitialize(MapRenderer self, + FileSource fileSource, + float pixelRatio, + String programCacheDir); + + @Override + protected native void finalize() throws Throwable; + + private native void nativeOnSurfaceCreated(); + + private native void nativeOnSurfaceChanged(int width, int height); + + private native void nativeRender(); + +} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRendererRunnable.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRendererRunnable.java new file mode 100644 index 0000000000..28246fe578 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRendererRunnable.java @@ -0,0 +1,29 @@ +package com.mapbox.mapboxsdk.maps.renderer; + +/** + * Peer class for {@link Runnable}s to be scheduled on the {@link MapRenderer} thread. + * The actual work is performed in the native peer. + */ +class MapRendererRunnable implements Runnable { + + // Holds the pointer to the native peer after initialisation + private final long nativePtr; + + /** + * Constructed from the native peer constructor + * + * @param nativePtr the native peer's memory address + */ + MapRendererRunnable(long nativePtr) { + this.nativePtr = nativePtr; + } + + @Override + public native void run(); + + @Override + protected native void finalize() throws Throwable; + + private native void nativeInitialize(); + +} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRendererScheduler.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRendererScheduler.java new file mode 100644 index 0000000000..7ad4f124d8 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRendererScheduler.java @@ -0,0 +1,13 @@ +package com.mapbox.mapboxsdk.maps.renderer; + +/** + * Can be used to schedule work on the map renderer + * thread or request a render. + */ +public interface MapRendererScheduler { + + void requestRender(); + + void queueEvent(Runnable 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 deleted file mode 100644 index 3b9f0f2151..0000000000 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/RenderThread.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.mapbox.mapboxsdk.maps.renderer; - -/** - * Created by ivo on 11/09/2017. - */ - -public interface RenderThread { - - void requestRender(); - - void queueEvent(Runnable runnable); -} |