[android] schedule work on the gl thread using GLSurfaceView#queueEvent

This commit is contained in:
Ivo van Dongen
2017-09-11 11:04:53 +03:00
committed by Ivo van Dongen
parent 347d7c19c0
commit 15a47d116a
9 changed files with 124 additions and 49 deletions

View File

@@ -28,6 +28,7 @@ import com.mapbox.mapboxsdk.annotations.MarkerViewManager;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.egl.EGLConfigChooser;
import com.mapbox.mapboxsdk.maps.renderer.GlSurfaceViewRenderThread;
import com.mapbox.mapboxsdk.maps.widgets.CompassView;
import com.mapbox.mapboxsdk.maps.widgets.MyLocationView;
import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings;
@@ -312,6 +313,8 @@ public class MapView extends FrameLayout {
});
glSurfaceView.setRenderMode(RENDERMODE_WHEN_DIRTY);
glSurfaceView.setVisibility(View.VISIBLE);
nativeMapView.setRenderThread(new GlSurfaceViewRenderThread(glSurfaceView));
}
/**
@@ -494,15 +497,6 @@ public class MapView extends FrameLayout {
// Rendering
//
// Called when the map needs to be rerendered
// Called via JNI from NativeMapView
protected void onInvalidate() {
if (glSurfaceView != null) {
glSurfaceView.requestRender();
}
// TODO: removable? postInvalidate();
}
@Override
protected void onSizeChanged(int width, int height, int oldw, int oldh) {
if (destroyed) {

View File

@@ -20,6 +20,7 @@ import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
import com.mapbox.mapboxsdk.geometry.ProjectedMeters;
import com.mapbox.mapboxsdk.maps.renderer.RenderThread;
import com.mapbox.mapboxsdk.storage.FileSource;
import com.mapbox.mapboxsdk.style.layers.CannotAddLayerException;
import com.mapbox.mapboxsdk.style.layers.Filter;
@@ -52,6 +53,9 @@ final class NativeMapView implements GLSurfaceView.Renderer {
// Used for callbacks
private MapView mapView;
// Used to schedule work on the render thread
private RenderThread renderThread;
//Hold a reference to prevent it from being GC'd as long as it's used on the native side
private final FileSource fileSource;
@@ -69,7 +73,7 @@ final class NativeMapView implements GLSurfaceView.Renderer {
// Constructors
//
public NativeMapView(MapView mapView) {
public NativeMapView(final MapView mapView) {
Context context = mapView.getContext();
fileSource = FileSource.getInstance(context);
@@ -84,6 +88,10 @@ final class NativeMapView implements GLSurfaceView.Renderer {
// Methods
//
public void setRenderThread(RenderThread renderThread) {
this.renderThread = renderThread;
}
private boolean isDestroyedOn(String callingMethod) {
if (destroyed && !TextUtils.isEmpty(callingMethod)) {
Timber.e(
@@ -104,7 +112,8 @@ final class NativeMapView implements GLSurfaceView.Renderer {
if (isDestroyedOn("update")) {
return;
}
nativeUpdate();
requestRender();
}
public void render() {
@@ -864,9 +873,28 @@ final class NativeMapView implements GLSurfaceView.Renderer {
// Callbacks
//
protected void onInvalidate() {
if (mapView != null) {
mapView.onInvalidate();
/**
* Called from JNI whenever the native map
* needs rendering.
*/
protected void requestRender() {
if (renderThread != null) {
renderThread.requestRender();
}
}
/**
* Called from JNI when work needs to be processed on
* the Renderer Thread.
*/
protected void requestProcessing() {
if (renderThread != null) {
renderThread.queueEvent(new Runnable() {
@Override
public void run() {
nativeProcess();
}
});
}
}
@@ -905,6 +933,8 @@ final class NativeMapView implements GLSurfaceView.Renderer {
private native void nativeDestroy();
private native void nativeProcess();
private native void nativeInitializeDisplay();
private native void nativeTerminateDisplay();
@@ -1130,9 +1160,7 @@ final class NativeMapView implements GLSurfaceView.Renderer {
void addSnapshotCallback(@NonNull MapboxMap.SnapshotReadyCallback callback) {
snapshotReadyCallback = callback;
scheduleTakeSnapshot();
mapView.onInvalidate();
// TODO. this should do a request render
//render();
renderThread.requestRender();
}
//

View File

@@ -0,0 +1,25 @@
package com.mapbox.mapboxsdk.maps.renderer;
import android.opengl.GLSurfaceView;
/**
* {@link RenderThread} implementation that schedules using the
* {@link GLSurfaceView} thread.
*/
public class GlSurfaceViewRenderThread implements RenderThread {
private final GLSurfaceView surfaceView;
public GlSurfaceViewRenderThread(GLSurfaceView surfaceView) {
this.surfaceView = surfaceView;
}
@Override
public void requestRender() {
surfaceView.requestRender();
}
@Override
public void queueEvent(Runnable runnable) {
surfaceView.queueEvent(runnable);
}
}

View File

@@ -0,0 +1,12 @@
package com.mapbox.mapboxsdk.maps.renderer;
/**
* Created by ivo on 11/09/2017.
*/
public interface RenderThread {
void requestRender();
void queueEvent(Runnable runnable);
}

View File

@@ -44,20 +44,18 @@ public:
// Only safe on the GL Thread
void process() {
while (true) {
std::unique_lock<std::mutex> lock(mutex);
std::unique_lock<std::mutex> lock(mutex);
if (queue.empty()) {
return;
}
auto scheduled = queue.front();
queue.pop();
lock.unlock();
Mailbox::maybeReceive(scheduled);
if (queue.empty()) {
return;
}
auto scheduled = queue.front();
queue.pop();
lock.unlock();
Mailbox::maybeReceive(scheduled);
}
// Only safe to access on the GL Thread

View File

@@ -58,10 +58,11 @@ AndroidRendererFrontend::AndroidRendererFrontend(float pixelRatio,
FileSource& fileSource,
Scheduler& scheduler,
std::string programCacheDir,
InvalidateCallback invalidate)
RequestRenderCallback requestRender,
RequestProcessingCallback requestProcessing)
: backend(std::make_unique<AndroidRendererBackend>())
, glThread(std::make_unique<AndroidGLThread>(
invalidate,
std::move(requestProcessing),
*backend,
pixelRatio,
fileSource,
@@ -69,8 +70,8 @@ AndroidRendererFrontend::AndroidRendererFrontend(float pixelRatio,
GLContextMode::Unique,
programCacheDir
))
, asyncInvalidate([=]() {
invalidate();
, asyncInvalidate([requestRender=std::move(requestRender)]() {
requestRender();
})
, mapRunLoop(util::RunLoop::Get()) {
}
@@ -112,9 +113,6 @@ void AndroidRendererFrontend::render() {
params = updateParameters;
}
// Process the gl thread mailbox
glThread->process();
// Activate the backend
BackendScope backendGuard { *backend };
@@ -130,6 +128,11 @@ void AndroidRendererFrontend::render() {
glThread->renderer->render(*params);
}
void AndroidRendererFrontend::process() {
// Process the gl thread mailbox
glThread->process();
}
void AndroidRendererFrontend::onLowMemory() {
assert (glThread);
glThread->actor().invoke(&Renderer::onLowMemory);

View File

@@ -30,13 +30,15 @@ class AndroidRendererBackend;
class AndroidRendererFrontend : public RendererFrontend {
public:
using InvalidateCallback = std::function<void ()>;
using RequestRenderCallback = std::function<void ()>;
using RequestProcessingCallback = std::function<void ()>;
AndroidRendererFrontend(float pixelRatio,
mbgl::FileSource&,
mbgl::Scheduler&,
std::string programCacheDir,
InvalidateCallback);
RequestRenderCallback,
RequestProcessingCallback);
~AndroidRendererFrontend() override;
void reset() override;
@@ -46,6 +48,7 @@ public:
// Called from OpenGL Thread
void render();
void process();
// Feature querying
std::vector<Feature> queryRenderedFeatures(const ScreenCoordinate&, const RenderedQueryOptions&) const;

View File

@@ -78,7 +78,8 @@ NativeMapView::NativeMapView(jni::JNIEnv& _env,
*threadPool,
jni::Make<std::string>(_env,
_programCacheDir),
[this] { this->invalidate(); });
[this] { this->requestRender(); },
[this] { this->requestProcessing(); });
// Create the core map
map = std::make_unique<mbgl::Map>(*rendererFrontend, *this,
@@ -97,17 +98,23 @@ NativeMapView::~NativeMapView() {
}
/**
* Callback to java NativeMapView#onInvalidate().
* Callback to java NativeMapView#requestRender().
*
* Called to invalidate the View and schedule a render on the next
* Called to schedule a render on the next
* runloop iteration.
*/
void NativeMapView::invalidate() {
void NativeMapView::requestRender() {
android::UniqueEnv _env = android::AttachEnv();
static auto onInvalidate = javaClass.GetMethod<void ()>(*_env, "onInvalidate");
static auto onInvalidate = javaClass.GetMethod<void ()>(*_env, "requestRender");
javaPeer->Call(*_env, onInvalidate);
}
void NativeMapView::requestProcessing() {
android::UniqueEnv _env = android::AttachEnv();
static auto requestProcessing = javaClass.GetMethod<void ()>(*_env, "requestProcessing");
javaPeer->Call(*_env, requestProcessing);
}
/**
* From mbgl::RendererBackend. Callback to java NativeMapView#onMapChanged(int).
*
@@ -195,8 +202,9 @@ void NativeMapView::render(jni::JNIEnv& ) {
updateFps();
}
void NativeMapView::update(jni::JNIEnv&) {
invalidate();
// Called from the OpenGL renderer thread
void NativeMapView::process(jni::JNIEnv&) {
rendererFrontend->process();
}
void NativeMapView::resizeView(jni::JNIEnv&, int w, int h) {
@@ -1004,7 +1012,7 @@ void NativeMapView::registerNative(jni::JNIEnv& env) {
"nativeInitialize",
"nativeDestroy",
METHOD(&NativeMapView::render, "nativeRender"),
METHOD(&NativeMapView::update, "nativeUpdate"),
METHOD(&NativeMapView::process, "nativeProcess"),
METHOD(&NativeMapView::resizeView, "nativeResizeView"),
METHOD(&NativeMapView::resizeFramebuffer, "nativeResizeFramebuffer"),
METHOD(&NativeMapView::getStyleUrl, "nativeGetStyleUrl"),

View File

@@ -73,7 +73,10 @@ public:
void onSourceChanged(mbgl::style::Source&) override;
// Signal the view system, we want to redraw
void invalidate();
void requestRender();
// Request processing on the GL Thread
void requestProcessing();
// JNI //
@@ -81,9 +84,10 @@ public:
void onSurfaceCreated(jni::JNIEnv&);
// Called on OpenGL Thread
void render(jni::JNIEnv&);
void process(jni::JNIEnv&);
void update(jni::JNIEnv&);
// Called on OpenGL Thread
void render(jni::JNIEnv&);
void resizeView(jni::JNIEnv&, int, int);