Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Commit

Permalink
[android] reset the native renderer only when the GL thread exits
Browse files Browse the repository at this point in the history
  • Loading branch information
LukasPaczos authored and Łukasz Paczos committed Jun 4, 2019
1 parent f9796d2 commit 409ead6
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import android.graphics.Bitmap;
import android.graphics.PointF;
import android.graphics.drawable.ColorDrawable;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.support.annotation.CallSuper;
import android.support.annotation.NonNull;
Expand All @@ -19,6 +18,7 @@
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;

import com.mapbox.android.gestures.AndroidGesturesManager;
import com.mapbox.mapboxsdk.MapStrictMode;
import com.mapbox.mapboxsdk.Mapbox;
Expand All @@ -29,18 +29,20 @@
import com.mapbox.mapboxsdk.location.LocationComponent;
import com.mapbox.mapboxsdk.maps.renderer.MapRenderer;
import com.mapbox.mapboxsdk.maps.renderer.glsurfaceview.GLSurfaceViewMapRenderer;
import com.mapbox.mapboxsdk.maps.renderer.glsurfaceview.MapboxGLSurfaceView;
import com.mapbox.mapboxsdk.maps.renderer.textureview.TextureViewMapRenderer;
import com.mapbox.mapboxsdk.maps.widgets.CompassView;
import com.mapbox.mapboxsdk.net.ConnectivityReceiver;
import com.mapbox.mapboxsdk.storage.FileSource;
import com.mapbox.mapboxsdk.utils.BitmapUtils;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import static com.mapbox.mapboxsdk.maps.widgets.CompassView.TIME_MAP_NORTH_ANIMATION;
import static com.mapbox.mapboxsdk.maps.widgets.CompassView.TIME_WAIT_IDLE;

Expand Down Expand Up @@ -295,7 +297,7 @@ protected void onSurfaceCreated(GL10 gl, EGLConfig config) {

addView(textureView, 0);
} else {
GLSurfaceView glSurfaceView = new GLSurfaceView(getContext());
MapboxGLSurfaceView glSurfaceView = new MapboxGLSurfaceView(getContext());
glSurfaceView.setZOrderMediaOverlay(mapboxMapOptions.getRenderSurfaceOnTop());
mapRenderer = new GLSurfaceViewMapRenderer(getContext(), glSurfaceView, localFontFamily) {
@Override
Expand Down Expand Up @@ -505,7 +507,7 @@ public boolean onGenericMotionEvent(@NonNull MotionEvent event) {
*/
@UiThread
public void onLowMemory() {
if (nativeMapView != null && mapboxMap != null && !destroyed ) {
if (nativeMapView != null && mapboxMap != null && !destroyed) {
nativeMapView.onLowMemory();
}
}
Expand Down Expand Up @@ -745,7 +747,6 @@ public void removeOnDidBecomeIdleListener(@NonNull OnDidBecomeIdleListener liste
}

/**
*
* Set a callback that's invoked when the style has finished loading.
*
* @param listener The callback that's invoked when the style has finished loading
Expand Down Expand Up @@ -801,12 +802,14 @@ public void removeOnStyleImageMissingListener(@NonNull OnStyleImageMissingListen

/**
* Set a callback that's invoked when map needs to release unused image resources.
*
* <p>
* A callback will be called only for unused images that were provided by the client via
* {@link OnStyleImageMissingListener#onStyleImageMissing(String)} listener interface.
*
* </p>
* <p>
* By default, platform will remove unused images from the style. By adding listener, default
* behavior can be overridden and client can control whether to release unused resources.
* </p>
*
* @param listener The callback that's invoked when map needs to release unused image resources
*/
Expand All @@ -816,9 +819,10 @@ public void addOnCanRemoveUnusedStyleImageListener(@NonNull OnCanRemoveUnusedSty

/**
* Removes a callback that's invoked when map needs to release unused image resources.
*
* <p>
* When all listeners are removed, platform will fallback to default behavior, which is to remove
* unused images from the style.
* </p>
*
* @param listener The callback that's invoked when map needs to release unused image resources
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,7 @@ public void removeAnnotations(long[] ids) {
@Override
@NonNull
public long[] queryPointAnnotations(RectF rect) {
if (checkState("queryPointAnnotations") || !mapRenderer.hasSurface()) {
if (checkState("queryPointAnnotations")) {
return new long[] {};
}
return nativeQueryPointAnnotations(rect);
Expand All @@ -541,7 +541,7 @@ public long[] queryPointAnnotations(RectF rect) {
@Override
@NonNull
public long[] queryShapeAnnotations(RectF rectF) {
if (checkState("queryShapeAnnotations") || !mapRenderer.hasSurface()) {
if (checkState("queryShapeAnnotations")) {
return new long[] {};
}
return nativeQueryShapeAnnotations(rectF);
Expand Down Expand Up @@ -573,7 +573,7 @@ public void setVisibleCoordinateBounds(LatLng[] coordinates, RectF padding, doub

@Override
public void onLowMemory() {
if (checkState("onLowMemory") || !mapRenderer.hasSurface()) {
if (checkState("onLowMemory")) {
return;
}
nativeOnLowMemory();
Expand Down Expand Up @@ -890,7 +890,7 @@ public Bitmap getImage(String name) {
public List<Feature> queryRenderedFeatures(@NonNull PointF coordinates,
@Nullable String[] layerIds,
@Nullable Expression filter) {
if (checkState("queryRenderedFeatures") || !mapRenderer.hasSurface()) {
if (checkState("queryRenderedFeatures")) {
return new ArrayList<>();
}
Feature[] features = nativeQueryRenderedFeaturesForPoint(coordinates.x / pixelRatio,
Expand All @@ -903,7 +903,7 @@ public List<Feature> queryRenderedFeatures(@NonNull PointF coordinates,
public List<Feature> queryRenderedFeatures(@NonNull RectF coordinates,
@Nullable String[] layerIds,
@Nullable Expression filter) {
if (checkState("queryRenderedFeatures") || !mapRenderer.hasSurface()) {
if (checkState("queryRenderedFeatures")) {
return new ArrayList<>();
}
Feature[] features = nativeQueryRenderedFeaturesForBox(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@
import android.support.annotation.CallSuper;
import android.support.annotation.Keep;
import android.support.annotation.NonNull;

import com.mapbox.mapboxsdk.LibraryLoader;
import com.mapbox.mapboxsdk.log.Logger;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.storage.FileSource;

import java.util.concurrent.atomic.AtomicBoolean;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

Expand All @@ -34,7 +33,6 @@ public abstract class MapRenderer implements MapRendererScheduler {
private long nativePtr = 0;
private double expectedRenderTime = 0;
private MapboxMap.OnFpsChangedListener onFpsChangedListener;
protected AtomicBoolean hasSurface = new AtomicBoolean();

public MapRenderer(@NonNull Context context, String localIdeographFontFamily) {
float pixelRatio = context.getResources().getDisplayMetrics().density;
Expand Down Expand Up @@ -160,13 +158,4 @@ public void setMaximumFps(int maximumFps) {
}
expectedRenderTime = 1E9 / maximumFps;
}

/**
* Returns true if renderer has a surface to draw on.
*
* @return returns if renderer has a surface, false otherwise
*/
public boolean hasSurface() {
return hasSurface.get();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.support.annotation.NonNull;
import android.view.SurfaceHolder;

import com.mapbox.mapboxsdk.maps.renderer.MapRenderer;
import com.mapbox.mapboxsdk.maps.renderer.egl.EGLConfigChooser;
Expand All @@ -22,10 +21,10 @@
public class GLSurfaceViewMapRenderer extends MapRenderer implements GLSurfaceView.Renderer {

@NonNull
private final GLSurfaceView glSurfaceView;
private final MapboxGLSurfaceView glSurfaceView;

public GLSurfaceViewMapRenderer(Context context,
GLSurfaceView glSurfaceView,
MapboxGLSurfaceView glSurfaceView,
String localIdeographFontFamily) {
super(context, localIdeographFontFamily);
this.glSurfaceView = glSurfaceView;
Expand All @@ -34,18 +33,13 @@ public GLSurfaceViewMapRenderer(Context context,
glSurfaceView.setRenderer(this);
glSurfaceView.setRenderMode(RENDERMODE_WHEN_DIRTY);
glSurfaceView.setPreserveEGLContextOnPause(true);
glSurfaceView.getHolder().addCallback(new SurfaceHolderCallbackAdapter() {

@Override
public void surfaceCreated(SurfaceHolder holder) {
super.surfaceCreated(holder);
hasSurface.set(true);
}

glSurfaceView.setDetachedListener(new MapboxGLSurfaceView.OnGLSurfaceViewDetachedListener() {
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
super.surfaceDestroyed(holder);
hasSurface.set(false);
public void onGLSurfaceViewDetached() {
// because the GL thread is destroyed when the view is detached from window,
// we need to ensure releasing the native renderer as well.
// This avoids releasing it only when the view is being recreated, which is already on a new GL thread,
// and leads to JNI crashes like https://github.com/mapbox/mapbox-gl-native/issues/14618
nativeReset();
}
});
Expand Down Expand Up @@ -103,9 +97,6 @@ public void onDrawFrame(GL10 gl) {
*/
@Override
public void requestRender() {
if (!hasSurface.get()) {
return;
}
glSurfaceView.requestRender();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.mapbox.mapboxsdk.maps.renderer.glsurfaceview;

import android.content.Context;
import android.opengl.GLSurfaceView;
import android.support.annotation.NonNull;
import android.util.AttributeSet;

/**
* {@link GLSurfaceView} extension that notifies a listener when the view is detached from window,
* which is the point of destruction of the GL thread.
*/
public class MapboxGLSurfaceView extends GLSurfaceView {

private OnGLSurfaceViewDetachedListener detachedListener;

public MapboxGLSurfaceView(Context context) {
super(context);
}

public MapboxGLSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
}

@Override
protected void onDetachedFromWindow() {
if (detachedListener != null) {
detachedListener.onGLSurfaceViewDetached();
}
super.onDetachedFromWindow();
}

/**
* Set a listener that gets notified when the view is detached from window.
*
* @param detachedListener listener
*/
public void setDetachedListener(@NonNull OnGLSurfaceViewDetachedListener detachedListener) {
if (this.detachedListener != null) {
throw new IllegalArgumentException("Detached from window listener has been already set.");
}
this.detachedListener = detachedListener;
}

/**
* Listener interface that notifies when a {@link MapboxGLSurfaceView} is detached from window.
*/
public interface OnGLSurfaceViewDetachedListener {

/**
* Called when a {@link MapboxGLSurfaceView} is detached from window.
*/
void onGLSurfaceViewDetached();
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ public TextureViewMapRenderer(@NonNull Context context,
@Override
protected void onSurfaceCreated(GL10 gl, EGLConfig config) {
super.onSurfaceCreated(gl, config);
hasSurface.set(true);
}

/**
Expand All @@ -59,7 +58,6 @@ protected void onSurfaceChanged(GL10 gl, int width, int height) {
*/
@Override
protected void onSurfaceDestroyed() {
hasSurface.set(false);
super.onSurfaceDestroyed();
}

Expand Down

0 comments on commit 409ead6

Please sign in to comment.