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

Commit

Permalink
[android] async rendering
Browse files Browse the repository at this point in the history
- introduces GLSurfaceView
- introduces Orchestration thread
- renders on the gl thread
  • Loading branch information
ivovandongen committed Jul 21, 2017
1 parent 4067c2a commit bc6e1bc
Show file tree
Hide file tree
Showing 7 changed files with 276 additions and 644 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package com.mapbox.mapboxsdk.maps;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.PointF;
import android.graphics.SurfaceTexture;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.support.annotation.CallSuper;
import android.support.annotation.IntDef;
Expand All @@ -15,10 +14,6 @@
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.TextureView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
Expand All @@ -43,8 +38,13 @@
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

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

import timber.log.Timber;

import static android.opengl.GLSurfaceView.RENDERMODE_WHEN_DIRTY;

/**
* <p>
* A {@code MapView} provides an embeddable map interface.
Expand All @@ -67,7 +67,6 @@ public class MapView extends FrameLayout {
private NativeMapView nativeMapView;
private MapboxMapOptions mapboxMapOptions;
private boolean destroyed;
private boolean hasSurface;

private MyLocationView myLocationView;
private CompassView compassView;
Expand All @@ -80,6 +79,8 @@ public class MapView extends FrameLayout {
private Bundle savedInstanceState;
private final CopyOnWriteArrayList<OnMapChangedListener> onMapChangedListeners = new CopyOnWriteArrayList<>();

private GLSurfaceView glSurfaceView;

@UiThread
public MapView(@NonNull Context context) {
super(context);
Expand Down Expand Up @@ -216,9 +217,37 @@ public void onCreate(@Nullable Bundle savedInstanceState) {
}

private void initialiseDrawingSurface() {
SurfaceView surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
surfaceView.getHolder().addCallback(new SurfaceCallback());
surfaceView.setVisibility(View.VISIBLE);
glSurfaceView = (GLSurfaceView) findViewById(R.id.surfaceView);
// TODO port config chooser from native code
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(GL10 gl, EGLConfig config) {
MapView.this.post(new Runnable() {
@Override
public void run() {
initialiseMap();
mapboxMap.onStart();
}
});

nativeMapView.onSurfaceCreated(gl, config);
}

@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
nativeMapView.onSurfaceChanged(gl, width, height);
}

@Override
public void onDrawFrame(GL10 gl) {
nativeMapView.onDrawFrame(gl);
}
});
glSurfaceView.setRenderMode(RENDERMODE_WHEN_DIRTY);
glSurfaceView.setVisibility(View.VISIBLE);
}

/**
Expand Down Expand Up @@ -249,15 +278,19 @@ public void onStart() {
*/
@UiThread
public void onResume() {
// replaced by onStart in v5.0.0
if (glSurfaceView != null) {
glSurfaceView.onResume();
}
}

/**
* You must call this method from the parent's Activity#onPause() or Fragment#onPause().
*/
@UiThread
public void onPause() {
// replaced by onStop in v5.0.0
if (glSurfaceView != null) {
glSurfaceView.onPause();
}
}

/**
Expand Down Expand Up @@ -399,24 +432,10 @@ public void setStyleUrl(@NonNull String url) {
// Called when the map needs to be rerendered
// Called via JNI from NativeMapView
protected void onInvalidate() {
postInvalidate();
}

@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (isInEditMode()) {
return;
}

if (destroyed) {
return;
}

if (!hasSurface) {
return;
if (glSurfaceView != null) {
glSurfaceView.requestRender();
}
nativeMapView.render();
// TODO: removable? postInvalidate();
}

@Override
Expand All @@ -430,103 +449,6 @@ protected void onSizeChanged(int width, int height, int oldw, int oldh) {
}
}

private class SurfaceCallback implements SurfaceHolder.Callback {

private Surface surface;

@Override
public void surfaceCreated(SurfaceHolder holder) {
if (nativeMapView == null) {
nativeMapView = new NativeMapView(MapView.this);
nativeMapView.createSurface(surface = holder.getSurface());
nativeMapView.resizeView(getWidth(), getHeight());
initialiseMap();
mapboxMap.onStart();
} else {
nativeMapView.createSurface(surface = holder.getSurface());
}

hasSurface = true;
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (destroyed) {
return;
}
nativeMapView.resizeFramebuffer(width, height);
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
hasSurface = false;

if (nativeMapView != null) {
// occurs when activity goes to background
nativeMapView.destroySurface();
}
surface.release();
}
}

// This class handles TextureView callbacks
private class SurfaceTextureListener implements TextureView.SurfaceTextureListener {

private Surface surface;

// Called when the native surface texture has been created
// Must do all EGL/GL ES initialization here
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
if (nativeMapView == null) {
nativeMapView = new NativeMapView(MapView.this);
nativeMapView.createSurface(this.surface = new Surface(surface));
nativeMapView.resizeFramebuffer(width, height);
nativeMapView.resizeView(width, height);
initialiseMap();
mapboxMap.onStart();
} else {
nativeMapView.createSurface(this.surface = new Surface(surface));
}

hasSurface = true;
}

// Called when the native surface texture has been destroyed
// Must do all EGL/GL ES destruction here
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
hasSurface = false;

if (nativeMapView != null) {
nativeMapView.destroySurface();
}
this.surface.release();
return true;
}

// Called when the format or size of the native surface texture has been changed
// Must handle window resizing here.
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
if (destroyed) {
return;
}

nativeMapView.resizeFramebuffer(width, height);
}

// Called when the SurfaceTexure frame is drawn to screen
// Must sync with UI here
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
if (destroyed) {
return;
}
mapboxMap.onUpdateRegionChange();
}
}

//
// View events
//
Expand All @@ -548,6 +470,7 @@ protected void onVisibilityChanged(@NonNull View changedView, int visibility) {
return;
}
if (visibility == View.VISIBLE && nativeMapView == null) {
nativeMapView = new NativeMapView(MapView.this);
initialiseDrawingSurface();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
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;
Expand Down Expand Up @@ -36,10 +37,13 @@
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 {
final class NativeMapView implements GLSurfaceView.Renderer {

// Flag to indicating destroy was called
private boolean destroyed = false;
Expand Down Expand Up @@ -97,20 +101,6 @@ public void destroy() {
destroyed = true;
}

public void createSurface(Surface surface) {
if (isDestroyedOn("createSurface")) {
return;
}
nativeCreateSurface(surface);
}

public void destroySurface() {
if (isDestroyedOn("destroySurface")) {
return;
}
nativeDestroySurface();
}

public void update() {
if (isDestroyedOn("update")) {
return;
Expand Down Expand Up @@ -156,7 +146,7 @@ public void resizeView(int width, int height) {
nativeResizeView(width, height);
}

public void resizeFramebuffer(int fbWidth, int fbHeight) {
private void resizeFramebuffer(int fbWidth, int fbHeight) {
if (isDestroyedOn("resizeFramebuffer")) {
return;
}
Expand Down Expand Up @@ -1123,6 +1113,33 @@ void removeOnMapChangedListener(@NonNull MapView.OnMapChangedListener listener)
void addSnapshotCallback(@NonNull MapboxMap.SnapshotReadyCallback callback) {
snapshotReadyCallback = callback;
scheduleTakeSnapshot();
render();
mapView.onInvalidate();
// TODO. this should do a request render
//render();
}

//
// 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?
}

@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) {
Timber.i("[%s] onDrawFrame", Thread.currentThread().getName());
nativeRender();
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">

<SurfaceView
<android.opengl.GLSurfaceView
android:id="@+id/surfaceView"
android:layout_width="match_parent"
android:layout_height="match_parent"
Expand Down
Loading

0 comments on commit bc6e1bc

Please sign in to comment.