summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvo van Dongen <info@ivovandongen.nl>2017-01-31 13:43:37 +0200
committerTobrun <tobrun.van.nuland@gmail.com>2017-02-10 16:37:53 +0100
commit35b810dd6ddfc5e6f1a635b2682b3add5ec5d5bb (patch)
tree12a453473e605f389a963cc4a752eb667ff28316
parent9b05af8f45f669dc1f79938a1112adac3db7ca00 (diff)
downloadqtlocation-mapboxgl-35b810dd6ddfc5e6f1a635b2682b3add5ec5d5bb.tar.gz
[android] render on gl thread
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java216
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java155
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/build.gradle7
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxApplication.java3
-rwxr-xr-xplatform/android/src/jni.cpp95
-rw-r--r--platform/android/src/jni.hpp1
-rwxr-xr-xplatform/android/src/native_map_view.cpp473
-rwxr-xr-xplatform/android/src/native_map_view.hpp60
-rw-r--r--platform/android/src/run_loop.cpp9
-rw-r--r--platform/android/src/run_loop_impl.hpp6
10 files changed, 301 insertions, 724 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 efc1001467..11928615d6 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
@@ -53,6 +53,8 @@ import java.util.List;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
+import timber.log.Timber;
+
import static android.opengl.GLSurfaceView.RENDERMODE_WHEN_DIRTY;
/**
@@ -69,15 +71,18 @@ import static android.opengl.GLSurfaceView.RENDERMODE_WHEN_DIRTY;
* <strong>Warning:</strong> Please note that you are responsible for getting permission to use the map data,
* and for ensuring your use adheres to the relevant terms of use.
*/
-public class MapView extends FrameLayout implements GLSurfaceView.Renderer {
+public class MapView extends FrameLayout {
private NativeMapView nativeMapView;
private boolean destroyed;
- private boolean hasSurface = false;
private GLSurfaceView glSurfaceView;
+ private CompassView compassView;
+ private ImageView attrView;
+ private View logoView;
+ private MyLocationView myLocationView;
private MapboxMap mapboxMap;
- private MapCallback mapCallback;
+ private MapCallback mapCallback = new MapCallback();
private boolean onStartCalled;
private boolean onStopCalled;
@@ -87,6 +92,8 @@ public class MapView extends FrameLayout implements GLSurfaceView.Renderer {
private ConnectivityReceiver connectivityReceiver;
+ private MapboxMapOptions mapboxMapOptions;
+
@UiThread
public MapView(@NonNull Context context) {
super(context);
@@ -112,21 +119,89 @@ public class MapView extends FrameLayout implements GLSurfaceView.Renderer {
}
private void initialise(@NonNull final Context context, @NonNull final MapboxMapOptions options) {
+ Timber.i("Initialize");
+ this.mapboxMapOptions = options;
+
+ // in IDE, show preview map
if (isInEditMode()) {
- // in IDE, show preview map
LayoutInflater.from(context).inflate(R.layout.mapbox_mapview_preview, this);
return;
}
+ //Setup basic view properties
+ setupViewProperties();
+
// inflate view
View view = LayoutInflater.from(context).inflate(R.layout.mapbox_mapview_internal, this);
- CompassView compassView = (CompassView) view.findViewById(R.id.compassView);
- MyLocationView myLocationView = (MyLocationView) view.findViewById(R.id.userLocationView);
- ImageView attrView = (ImageView) view.findViewById(R.id.attributionView);
- initialiseDrawingSurface();
+ compassView = (CompassView) view.findViewById(R.id.compassView);
+ myLocationView = (MyLocationView) view.findViewById(R.id.userLocationView);
+ attrView = (ImageView) view.findViewById(R.id.attributionView);
+ logoView = view.findViewById(R.id.logoView);
+
+ glSurfaceView = (GLSurfaceView) findViewById(R.id.surfaceView);
+ glSurfaceView.setEGLConfigChooser(8, 8, 8, 0 /** TODO: What alpha value do we need here?? */, 16, 8);
+ glSurfaceView.setEGLContextClientVersion(2);
+ glSurfaceView.setRenderer(new GLSurfaceView.Renderer() {
+ @Override
+ public void onSurfaceCreated(final GL10 gl, EGLConfig eglConfig) {
+ Timber.i("[%s] onSurfaceCreated", Thread.currentThread().getName());
+ glSurfaceView.setRenderMode(RENDERMODE_WHEN_DIRTY);
+
+ // Create native Map object
+ nativeMapView = new NativeMapView(MapView.this);
+
+ //Continue configuring the map view on the main thread
+ MapView.this.post(new Runnable() {
+ @Override
+ public void run() {
+ onNativeMapViewReady();
+ }
+ });
+ }
+
+ @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);
+ nativeMapView.onViewportChanged(width, height);
+ }
+
+ @Override
+ public void onDrawFrame(GL10 gl) {
+ Timber.i("[%s] onDrawFrame", Thread.currentThread().getName());
+ nativeMapView.render();
+ }
+ });
+
+ }
+
+ private void setupViewProperties() {
+ // allow onDraw invocation
+ setWillNotDraw(false);
+
+ // Ensure this view is interactable
+ setClickable(true);
+ setLongClickable(true);
+ setFocusable(true);
+ setFocusableInTouchMode(true);
+ requestDisallowInterceptTouchEvent(true);
+ }
- // create native Map object
- nativeMapView = new NativeMapView(this);
+// private void loopRender() {
+// postDelayed(new Runnable() {
+// @Override
+// public void run() {
+// //glSurfaceView.queueEvent(renderRunnable);
+// onInvalidate();
+//// nativeMapView.update();
+// //onInvalidate();
+// loopRender();
+// }
+// }, 500);
+// }
+
+ protected void onNativeMapViewReady() {
// callback for focal point invalidation
FocalPointInvalidator focalPoint = new FocalPointInvalidator(compassView);
@@ -139,7 +214,7 @@ public class MapView extends FrameLayout implements GLSurfaceView.Renderer {
// setup components for MapboxMap creation
Projection proj = new Projection(nativeMapView);
- UiSettings uiSettings = new UiSettings(proj, focalPoint, compassView, attrView, view.findViewById(R.id.logoView));
+ UiSettings uiSettings = new UiSettings(proj, focalPoint, compassView, attrView, logoView);
TrackingSettings trackingSettings = new TrackingSettings(myLocationView, uiSettings, focalPoint, zoomInvalidator);
MyLocationViewSettings myLocationViewSettings = new MyLocationViewSettings(myLocationView, proj, focalPoint);
MarkerViewManager markerViewManager = new MarkerViewManager((ViewGroup) findViewById(R.id.markerViewContainer));
@@ -149,56 +224,23 @@ public class MapView extends FrameLayout implements GLSurfaceView.Renderer {
registerTouchListener, annotations);
// user input
- mapGestureDetector = new MapGestureDetector(context, transform, proj, uiSettings, trackingSettings, annotations);
+ mapGestureDetector = new MapGestureDetector(getContext(), transform, proj, uiSettings, trackingSettings, annotations);
mapKeyListener = new MapKeyListener(transform, trackingSettings, uiSettings);
mapZoomButtonController = new MapZoomButtonController(this, uiSettings, transform);
// inject widgets with MapboxMap
compassView.setMapboxMap(mapboxMap);
myLocationView.setMapboxMap(mapboxMap);
- attrView.setOnClickListener(new AttributionOnClickListener(context, transform));
-
- // Ensure this view is interactable
- setClickable(true);
- setLongClickable(true);
- setFocusable(true);
- setFocusableInTouchMode(true);
- requestDisallowInterceptTouchEvent(true);
-
- // allow onDraw invocation
- setWillNotDraw(false);
+ attrView.setOnClickListener(new AttributionOnClickListener(getContext(), transform));
// notify Map object about current connectivity state
nativeMapView.setReachability(isConnected());
// initialise MapboxMap
- mapboxMap.initialise(context, options);
- }
-
- private void initialiseDrawingSurface() {
- glSurfaceView = (GLSurfaceView) findViewById(R.id.surfaceView);
- glSurfaceView.setEGLContextClientVersion(2);
- glSurfaceView.setRenderer(this);
- glSurfaceView.setRenderMode(RENDERMODE_WHEN_DIRTY);
- }
-
- @Override
- public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
- nativeMapView.initializeDisplay();
- nativeMapView.initializeContext();
- nativeMapView.createSurface(glSurfaceView.getHolder().getSurface());
- hasSurface = true;
- }
-
- @Override
- public void onSurfaceChanged(GL10 gl10, int i, int i1) {
- nativeMapView.resizeView(i, i1);
- nativeMapView.resizeFramebuffer(i, i1);
- }
-
- @Override
- public void onDrawFrame(GL10 gl10) {
+ mapboxMap.initialise(getContext(), mapboxMapOptions);
+ addOnMapChangedListener(mapCallback);
+ mapboxMap.onStart();
}
//
@@ -218,7 +260,7 @@ public class MapView extends FrameLayout implements GLSurfaceView.Renderer {
*/
@UiThread
public void onCreate(@Nullable Bundle savedInstanceState) {
- nativeMapView.setAccessToken(Mapbox.getAccessToken());
+ //nativeMapView.setAccessToken(Mapbox.getAccessToken());
if (savedInstanceState == null) {
MapboxTelemetry.getInstance().pushEvent(MapboxEvent.buildMapLoadEvent());
@@ -226,7 +268,6 @@ public class MapView extends FrameLayout implements GLSurfaceView.Renderer {
mapboxMap.onRestoreInstanceState(savedInstanceState);
}
- addOnMapChangedListener(mapCallback = new MapCallback(mapboxMap));
}
/**
@@ -249,7 +290,6 @@ public class MapView extends FrameLayout implements GLSurfaceView.Renderer {
public void onStart() {
onStartCalled = true;
registerConnectivityReceiver();
- mapboxMap.onStart();
glSurfaceView.onResume();
}
@@ -296,12 +336,17 @@ public class MapView extends FrameLayout implements GLSurfaceView.Renderer {
}
destroyed = true;
- hasSurface = false;
- nativeMapView.terminateContext();
- nativeMapView.terminateDisplay();
- nativeMapView.destroySurface();
- nativeMapView.destroy();
- nativeMapView = null;
+ //nativeMapView.terminateContext();
+ //nativeMapView.terminateDisplay();
+ //nativeMapView.destroySurface();
+
+ glSurfaceView.queueEvent(new Runnable() {
+ @Override
+ public void run() {
+ nativeMapView.destroy();
+ nativeMapView = null;
+ }
+ });
}
private void registerConnectivityReceiver() {
@@ -435,28 +480,34 @@ public class MapView extends FrameLayout implements GLSurfaceView.Renderer {
// Rendering
//
- // Called when the map needs to be rerendered
- // Called via JNI from NativeMapView
+ /**
+ * Called when the map needs to be re-rendered
+ * Called via JNI from NativeMapView
+ * <p>
+ * May be called from any thread
+ */
protected void onInvalidate() {
+ Timber.i("onInvalidate");
+ //glSurfaceView.onInvalidate();
+ //XXX Don't need this right? postInvalidate();
postInvalidate();
}
+ protected void requestRender() {
+ if (glSurfaceView != null) {
+ glSurfaceView.requestRender();
+ }
+ }
+
@Override
public void onDraw(Canvas canvas) {
+ Timber.i("onDraw");
super.onDraw(canvas);
if (isInEditMode()) {
return;
}
- if (destroyed) {
- return;
- }
-
- if (!hasSurface) {
- return;
- }
-
- nativeMapView.render();
+ //glSurfaceView.queueEvent(renderRunnable);
}
@Override
@@ -466,7 +517,9 @@ public class MapView extends FrameLayout implements GLSurfaceView.Renderer {
}
if (!isInEditMode()) {
- nativeMapView.resizeView(width, height);
+ if (nativeMapView != null) {
+ //XXX This should happen through GLSurfaceView#Renderer callbacks nativeMapView.resizeView(width, height);
+ }
}
}
@@ -488,7 +541,9 @@ public class MapView extends FrameLayout implements GLSurfaceView.Renderer {
if (isInEditMode()) {
return;
}
- mapZoomButtonController.setVisible(visibility == View.VISIBLE);
+ if (mapZoomButtonController != null) {
+ mapZoomButtonController.setVisible(visibility == View.VISIBLE);
+ }
}
//
@@ -501,7 +556,7 @@ public class MapView extends FrameLayout implements GLSurfaceView.Renderer {
// Called when an action we are listening to in the manifest has been sent
@Override
public void onReceive(Context context, Intent intent) {
- if (!destroyed && intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
+ if (nativeMapView != null && !destroyed && intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
nativeMapView.setReachability(!intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false));
}
}
@@ -929,16 +984,11 @@ public class MapView extends FrameLayout implements GLSurfaceView.Renderer {
}
}
- private static class MapCallback implements OnMapChangedListener {
+ private class MapCallback implements OnMapChangedListener {
- private final MapboxMap mapboxMap;
private final List<OnMapReadyCallback> onMapReadyCallbackList = new ArrayList<>();
private boolean initialLoad = true;
- MapCallback(MapboxMap mapboxMap) {
- this.mapboxMap = mapboxMap;
- }
-
@Override
public void onMapChanged(@MapChange int change) {
if (change == DID_FINISH_LOADING_STYLE && initialLoad) {
@@ -971,4 +1021,14 @@ public class MapView extends FrameLayout implements GLSurfaceView.Renderer {
onMapReadyCallbackList.add(callback);
}
}
+
+ private class RenderRunnable implements Runnable {
+ @Override
+ public void run() {
+ if (destroyed) {
+ return;
+ }
+ nativeMapView.render();
+ }
+ }
}
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 1d260cacf3..5069a25d69 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
@@ -68,6 +68,8 @@ final class NativeMapView {
//
public NativeMapView(MapView mapView) {
+ this.mapView = mapView;
+
Context context = mapView.getContext();
String dataPath = OfflineManager.getDatabasePath(context);
@@ -95,7 +97,10 @@ final class NativeMapView {
throw new IllegalArgumentException("totalMemory cannot be negative.");
}
onMapChangedListeners = new CopyOnWriteArrayList<>();
- this.mapView = mapView;
+
+// if (Looper.myLooper() == null) {
+// Looper.prepare();
+// }
nativeMapViewPtr = nativeCreate(cachePath, dataPath, apkPath, pixelRatio, availableProcessors, totalMemory);
}
@@ -103,84 +108,10 @@ final class NativeMapView {
// Methods
//
- private boolean isDestroyedOn(String callingMethod) {
- if (destroyed && !TextUtils.isEmpty(callingMethod)) {
- Timber.e(String.format(MapboxConstants.MAPBOX_LOCALE,
- "You're calling `%s` after the `MapView` was destroyed, were you invoking it after `onDestroy()`?",
- callingMethod));
- }
- return destroyed;
- }
-
- public void destroy() {
- nativeDestroy(nativeMapViewPtr);
- nativeMapViewPtr = 0;
- mapView = null;
- destroyed = true;
- }
-
- public void initializeDisplay() {
- if (isDestroyedOn("initializeDisplay")) {
- return;
- }
- nativeInitializeDisplay(nativeMapViewPtr);
- }
-
- public void terminateDisplay() {
- if (isDestroyedOn("terminateDisplay")) {
- return;
- }
- nativeTerminateDisplay(nativeMapViewPtr);
- }
-
- public void initializeContext() {
- if (isDestroyedOn("initializeContext")) {
- return;
- }
- nativeInitializeContext(nativeMapViewPtr);
- }
-
- public void terminateContext() {
- if (isDestroyedOn("terminateContext")) {
- return;
- }
- nativeTerminateContext(nativeMapViewPtr);
- }
-
- public void createSurface(Surface surface) {
- if (isDestroyedOn("createSurface")) {
+ public void onViewportChanged(int width, int height) {
+ if (isDestroyedOn("onViewportChanged")) {
return;
}
- nativeCreateSurface(nativeMapViewPtr, surface);
- }
-
- public void destroySurface() {
- if (isDestroyedOn("destroySurface")) {
- return;
- }
- nativeDestroySurface(nativeMapViewPtr);
- }
-
- public void update() {
- if (isDestroyedOn("update")) {
- return;
- }
- nativeUpdate(nativeMapViewPtr);
- }
-
- public void render() {
- if (isDestroyedOn("render")) {
- return;
- }
- nativeRender(nativeMapViewPtr);
- }
-
- public void resizeView(int width, int height) {
- if (isDestroyedOn("resizeView")) {
- return;
- }
- width = (int) (width / pixelRatio);
- height = (int) (height / pixelRatio);
if (width < 0) {
throw new IllegalArgumentException("width cannot be negative.");
@@ -203,31 +134,39 @@ final class NativeMapView {
+ "capping value at 65535 instead of " + height);
height = 65535;
}
- nativeViewResize(nativeMapViewPtr, width, height);
+
+ nativeOnViewportChanged(nativeMapViewPtr, width, height);
}
- public void resizeFramebuffer(int fbWidth, int fbHeight) {
- if (isDestroyedOn("resizeFramebuffer")) {
- return;
- }
- if (fbWidth < 0) {
- throw new IllegalArgumentException("fbWidth cannot be negative.");
+ private boolean isDestroyedOn(String callingMethod) {
+ if (destroyed && !TextUtils.isEmpty(callingMethod)) {
+ Timber.e(String.format(MapboxConstants.MAPBOX_LOCALE,
+ "You're calling `%s` after the `MapView` was destroyed, were you invoking it after `onDestroy()`?",
+ callingMethod));
}
+ return destroyed;
+ }
- if (fbHeight < 0) {
- throw new IllegalArgumentException("fbHeight cannot be negative.");
- }
+ public void destroy() {
+ nativeDestroy(nativeMapViewPtr);
+ nativeMapViewPtr = 0;
+ mapView = null;
+ destroyed = true;
+ }
- if (fbWidth > 65535) {
- throw new IllegalArgumentException(
- "fbWidth cannot be greater than 65535.");
+ public void update() {
+ if (isDestroyedOn("update")) {
+ return;
}
+ nativeUpdate(nativeMapViewPtr);
+ }
- if (fbHeight > 65535) {
- throw new IllegalArgumentException(
- "fbHeight cannot be greater than 65535.");
+ public void render() {
+ Timber.i("Render");
+ if (isDestroyedOn("render")) {
+ return;
}
- nativeFramebufferResize(nativeMapViewPtr, fbWidth, fbHeight);
+ nativeRender(nativeMapViewPtr);
}
public void addClass(String clazz) {
@@ -329,6 +268,7 @@ final class NativeMapView {
}
public void moveBy(double dx, double dy, long duration) {
+ Timber.i("Move by %sx%s - %s", dx, dy, duration);
if (isDestroyedOn("moveBy")) {
return;
}
@@ -343,6 +283,7 @@ final class NativeMapView {
}
public void setLatLng(LatLng latLng, long duration) {
+ Timber.i("setLatLng %sx%s - %s", latLng.getLatitude(), latLng.getLongitude(), duration);
if (isDestroyedOn("setLatLng")) {
return;
}
@@ -372,6 +313,7 @@ final class NativeMapView {
}
public void setPitch(double pitch, long duration) {
+ Timber.i("setLatLng %s - %s", pitch, duration);
if (isDestroyedOn("setPitch")) {
return;
}
@@ -926,14 +868,29 @@ final class NativeMapView {
// Callbacks
//
+ /**
+ * Called through JNI when the map needs to be re-rendered
+ */
protected void onInvalidate() {
+ Timber.i("onInvalidate");
mapView.onInvalidate();
}
- protected void onMapChanged(int rawChange) {
+ protected void wakeCallback() {
+ Timber.i("wake!");
+ mapView.requestRender();
+ }
+
+ protected void onMapChanged(final int rawChange) {
+ Timber.i("onMapChanged: %s", rawChange);
if (onMapChangedListeners != null) {
- for (MapView.OnMapChangedListener onMapChangedListener : onMapChangedListeners) {
- onMapChangedListener.onMapChanged(rawChange);
+ for (final MapView.OnMapChangedListener onMapChangedListener : onMapChangedListeners) {
+ mapView.post(new Runnable() {
+ @Override
+ public void run() {
+ onMapChangedListener.onMapChanged(rawChange);
+ }
+ });
}
}
}
@@ -974,9 +931,7 @@ final class NativeMapView {
private native void nativeRender(long nativeMapViewPtr);
- private native void nativeViewResize(long nativeMapViewPtr, int width, int height);
-
- private native void nativeFramebufferResize(long nativeMapViewPtr, int fbWidth, int fbHeight);
+ private native void nativeOnViewportChanged(long nativeMapViewPtr, int width, int height);
private native void nativeAddClass(long nativeMapViewPtr, String clazz);
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
index 318f891127..fee8f93e90 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
+++ b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
@@ -13,7 +13,7 @@ android {
defaultConfig {
applicationId "com.mapbox.mapboxsdk.testapp"
- minSdkVersion 15
+ minSdkVersion 16
targetSdkVersion 25
versionCode 11
versionName "5.0.0"
@@ -86,6 +86,11 @@ dependencies {
androidTestCompile "com.android.support.test:rules:${testRunnerVersion}"
androidTestCompile "com.android.support.test.espresso:espresso-core:${espressoVersion}"
androidTestCompile "com.android.support.test.espresso:espresso-intents:${espressoVersion}"
+
+ //FPS Meter
+ debugCompile "com.github.brianPlummer:tinydancer:0.1.0"
+ releaseCompile "com.github.brianPlummer:tinydancer-noop:0.1.0"
+ testCompile "com.github.brianPlummer:tinydancer-noop:0.1.0"
}
apply from: 'gradle-make.gradle'
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxApplication.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxApplication.java
index a10c6eaad3..c6d95ecfd5 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxApplication.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxApplication.java
@@ -3,6 +3,7 @@ package com.mapbox.mapboxsdk.testapp;
import android.app.Application;
import android.os.StrictMode;
+import com.codemonkeylabs.fpslibrary.TinyDancer;
import com.mapbox.mapboxsdk.Mapbox;
import com.squareup.leakcanary.LeakCanary;
@@ -38,6 +39,8 @@ public class MapboxApplication extends Application {
.build());
Mapbox.getInstance(getApplicationContext(), getString(R.string.mapbox_access_token));
+
+ TinyDancer.create().show(this);
}
private void initializeLogger() {
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;