[android] self-contained map renderer
- Isolates the GL thread in a MapRenderer class with a native peer
This commit is contained in:
committed by
Ivo van Dongen
parent
15a47d116a
commit
5d12503302
@@ -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);
|
||||
super.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.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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
Context context = mapView.getContext();
|
||||
fileSource = FileSource.getInstance(context);
|
||||
|
||||
pixelRatio = context.getResources().getDisplayMetrics().density;
|
||||
public NativeMapView(final MapView mapView, MapRenderer mapRenderer) {
|
||||
this.scheduler = mapRenderer;
|
||||
this.mapView = mapView;
|
||||
|
||||
String programCacheDir = context.getCacheDir().getAbsolutePath();
|
||||
nativeInitialize(this, fileSource, pixelRatio, programCacheDir);
|
||||
Context context = mapView.getContext();
|
||||
fileSource = FileSource.getInstance(context);
|
||||
pixelRatio = context.getResources().getDisplayMetrics().density;
|
||||
|
||||
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,33 +137,10 @@ 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);
|
||||
}
|
||||
|
||||
public void setStyleUrl(String url) {
|
||||
if (isDestroyedOn("setStyleUrl")) {
|
||||
return;
|
||||
@@ -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();
|
||||
scheduler.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?
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -205,6 +205,10 @@ add_library(mbgl-android STATIC
|
||||
# Native map
|
||||
platform/android/src/native_map_view.cpp
|
||||
platform/android/src/native_map_view.hpp
|
||||
platform/android/src/map_renderer.cpp
|
||||
platform/android/src/map_renderer.hpp
|
||||
platform/android/src/map_renderer_runnable.cpp
|
||||
platform/android/src/map_renderer_runnable.hpp
|
||||
|
||||
# Java core classes
|
||||
platform/android/src/java/util.cpp
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/actor/actor.hpp>
|
||||
#include <mbgl/actor/mailbox.hpp>
|
||||
#include <mbgl/actor/scheduler.hpp>
|
||||
#include <mbgl/renderer/renderer.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <utility>
|
||||
|
||||
namespace mbgl {
|
||||
namespace android {
|
||||
|
||||
class AndroidGLThread : public Scheduler {
|
||||
public:
|
||||
using InvalidateCallback = std::function<void ()>;
|
||||
|
||||
template <class... Args>
|
||||
AndroidGLThread(InvalidateCallback callback_, Args&&... args)
|
||||
: renderer(std::make_unique<Renderer>(std::forward<Args>(args)...))
|
||||
, mailbox(std::make_shared<Mailbox>(*this))
|
||||
, callback(callback_)
|
||||
, rendererRef(*renderer, mailbox) {
|
||||
}
|
||||
|
||||
~AndroidGLThread() override = default;
|
||||
|
||||
ActorRef<Renderer> actor() const {
|
||||
return rendererRef;
|
||||
}
|
||||
|
||||
void schedule(std::weak_ptr<Mailbox> scheduled) override {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
queue.push(scheduled);
|
||||
}
|
||||
|
||||
// Invalidate so we get processing time later
|
||||
callback();
|
||||
}
|
||||
|
||||
// Only safe on the GL Thread
|
||||
void process() {
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
|
||||
if (queue.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto scheduled = queue.front();
|
||||
queue.pop();
|
||||
|
||||
lock.unlock();
|
||||
|
||||
Mailbox::maybeReceive(scheduled);
|
||||
}
|
||||
|
||||
// Only safe to access on the GL Thread
|
||||
std::unique_ptr<Renderer> renderer;
|
||||
|
||||
private:
|
||||
std::mutex mutex;
|
||||
std::queue<std::weak_ptr<Mailbox>> queue;
|
||||
|
||||
std::shared_ptr<Mailbox> mailbox;
|
||||
InvalidateCallback callback;
|
||||
ActorRef<Renderer> rendererRef;
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
} // namespace mbgl
|
||||
@@ -54,124 +54,62 @@ private:
|
||||
ActorRef<RendererObserver> delegate;
|
||||
};
|
||||
|
||||
AndroidRendererFrontend::AndroidRendererFrontend(float pixelRatio,
|
||||
FileSource& fileSource,
|
||||
Scheduler& scheduler,
|
||||
std::string programCacheDir,
|
||||
RequestRenderCallback requestRender,
|
||||
RequestProcessingCallback requestProcessing)
|
||||
: backend(std::make_unique<AndroidRendererBackend>())
|
||||
, glThread(std::make_unique<AndroidGLThread>(
|
||||
std::move(requestProcessing),
|
||||
*backend,
|
||||
pixelRatio,
|
||||
fileSource,
|
||||
scheduler,
|
||||
GLContextMode::Unique,
|
||||
programCacheDir
|
||||
))
|
||||
, asyncInvalidate([requestRender=std::move(requestRender)]() {
|
||||
requestRender();
|
||||
})
|
||||
AndroidRendererFrontend::AndroidRendererFrontend(MapRenderer& mapRenderer_)
|
||||
: mapRenderer(mapRenderer_)
|
||||
, mapRunLoop(util::RunLoop::Get()) {
|
||||
}
|
||||
|
||||
AndroidRendererFrontend::~AndroidRendererFrontend() = default;
|
||||
|
||||
void AndroidRendererFrontend::reset() {
|
||||
assert(glThread);
|
||||
glThread.reset();
|
||||
mapRenderer.reset();
|
||||
rendererObserver.reset();
|
||||
}
|
||||
|
||||
void AndroidRendererFrontend::setObserver(RendererObserver& observer) {
|
||||
assert (glThread);
|
||||
assert (util::RunLoop::Get());
|
||||
rendererObserver = std::make_unique<ForwardingRendererObserver>(*mapRunLoop, observer);
|
||||
glThread->actor().invoke(&Renderer::setObserver, rendererObserver.get());
|
||||
mapRenderer.actor().invoke(&Renderer::setObserver, rendererObserver.get());
|
||||
}
|
||||
|
||||
void AndroidRendererFrontend::update(std::shared_ptr<UpdateParameters> params) {
|
||||
{
|
||||
// Lock on the parameters
|
||||
std::lock_guard<std::mutex> lock(updateMutex);
|
||||
updateParameters = std::move(params);
|
||||
}
|
||||
asyncInvalidate.send();
|
||||
}
|
||||
|
||||
// Called on OpenGL thread
|
||||
void AndroidRendererFrontend::render() {
|
||||
assert (glThread);
|
||||
|
||||
std::shared_ptr<UpdateParameters> params;
|
||||
{
|
||||
// Lock on the parameters
|
||||
std::unique_lock<std::mutex> lock(updateMutex);
|
||||
if (!updateParameters) return;
|
||||
|
||||
// Hold on to the update parameters during render
|
||||
params = updateParameters;
|
||||
}
|
||||
|
||||
// Activate the backend
|
||||
BackendScope backendGuard { *backend };
|
||||
|
||||
// Ensure that the "current" scheduler on the render thread is
|
||||
// actually the scheduler from the orchestration thread
|
||||
Scheduler::SetCurrent(glThread.get());
|
||||
|
||||
if (framebufferSizeChanged) {
|
||||
backend->updateViewPort();
|
||||
framebufferSizeChanged = false;
|
||||
}
|
||||
|
||||
glThread->renderer->render(*params);
|
||||
}
|
||||
|
||||
void AndroidRendererFrontend::process() {
|
||||
// Process the gl thread mailbox
|
||||
glThread->process();
|
||||
mapRenderer.update(std::move(params));
|
||||
mapRenderer.requestRender();
|
||||
}
|
||||
|
||||
void AndroidRendererFrontend::onLowMemory() {
|
||||
assert (glThread);
|
||||
glThread->actor().invoke(&Renderer::onLowMemory);
|
||||
mapRenderer.actor().invoke(&Renderer::onLowMemory);
|
||||
}
|
||||
|
||||
std::vector<Feature> AndroidRendererFrontend::querySourceFeatures(const std::string& sourceID,
|
||||
const SourceQueryOptions& options) const {
|
||||
assert (glThread);
|
||||
// Waits for the result from the orchestration thread and returns
|
||||
return glThread->actor().ask(&Renderer::querySourceFeatures, sourceID, options).get();
|
||||
return mapRenderer.actor().ask(&Renderer::querySourceFeatures, sourceID, options).get();
|
||||
}
|
||||
|
||||
std::vector<Feature> AndroidRendererFrontend::queryRenderedFeatures(const ScreenBox& box,
|
||||
const RenderedQueryOptions& options) const {
|
||||
assert (glThread);
|
||||
|
||||
// Select the right overloaded method
|
||||
std::vector<Feature> (Renderer::*fn)(const ScreenBox&, const RenderedQueryOptions&) const = &Renderer::queryRenderedFeatures;
|
||||
|
||||
// Waits for the result from the orchestration thread and returns
|
||||
return glThread->actor().ask(fn, box, options).get();
|
||||
return mapRenderer.actor().ask(fn, box, options).get();
|
||||
}
|
||||
|
||||
std::vector<Feature> AndroidRendererFrontend::queryRenderedFeatures(const ScreenCoordinate& point,
|
||||
const RenderedQueryOptions& options) const {
|
||||
assert (glThread);
|
||||
|
||||
// Select the right overloaded method
|
||||
std::vector<Feature> (Renderer::*fn)(const ScreenCoordinate&, const RenderedQueryOptions&) const = &Renderer::queryRenderedFeatures;
|
||||
|
||||
// Waits for the result from the orchestration thread and returns
|
||||
return glThread->actor().ask(fn, point, options).get();
|
||||
return mapRenderer.actor().ask(fn, point, options).get();
|
||||
}
|
||||
|
||||
AnnotationIDs AndroidRendererFrontend::queryPointAnnotations(const ScreenBox& box) const {
|
||||
assert (glThread);
|
||||
|
||||
// Waits for the result from the orchestration thread and returns
|
||||
return glThread->actor().ask(&Renderer::queryPointAnnotations, box).get();
|
||||
return mapRenderer.actor().ask(&Renderer::queryPointAnnotations, box).get();
|
||||
}
|
||||
|
||||
void AndroidRendererFrontend::requestSnapshot(SnapshotCallback callback_) {
|
||||
@@ -182,12 +120,6 @@ void AndroidRendererFrontend::requestSnapshot(SnapshotCallback callback_) {
|
||||
});
|
||||
}
|
||||
|
||||
void AndroidRendererFrontend::resizeFramebuffer(int width, int height) {
|
||||
backend->resizeFramebuffer(width, height);
|
||||
framebufferSizeChanged = true;
|
||||
asyncInvalidate.send();
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
} // namespace mbgl
|
||||
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "android_gl_thread.hpp"
|
||||
|
||||
#include <mbgl/actor/actor.hpp>
|
||||
#include <mbgl/annotation/annotation.hpp>
|
||||
#include <mbgl/renderer/renderer_backend.hpp>
|
||||
#include <mbgl/renderer/renderer_frontend.hpp>
|
||||
#include <mbgl/util/async_task.hpp>
|
||||
#include <mbgl/util/geo.hpp>
|
||||
#include <mbgl/util/image.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
@@ -17,6 +13,8 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "map_renderer.hpp"
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class FileSource;
|
||||
@@ -30,15 +28,8 @@ class AndroidRendererBackend;
|
||||
|
||||
class AndroidRendererFrontend : public RendererFrontend {
|
||||
public:
|
||||
using RequestRenderCallback = std::function<void ()>;
|
||||
using RequestProcessingCallback = std::function<void ()>;
|
||||
|
||||
AndroidRendererFrontend(float pixelRatio,
|
||||
mbgl::FileSource&,
|
||||
mbgl::Scheduler&,
|
||||
std::string programCacheDir,
|
||||
RequestRenderCallback,
|
||||
RequestProcessingCallback);
|
||||
AndroidRendererFrontend(MapRenderer&);
|
||||
~AndroidRendererFrontend() override;
|
||||
|
||||
void reset() override;
|
||||
@@ -46,19 +37,12 @@ public:
|
||||
|
||||
void update(std::shared_ptr<UpdateParameters>) override;
|
||||
|
||||
// Called from OpenGL Thread
|
||||
void render();
|
||||
void process();
|
||||
|
||||
// Feature querying
|
||||
std::vector<Feature> queryRenderedFeatures(const ScreenCoordinate&, const RenderedQueryOptions&) const;
|
||||
std::vector<Feature> queryRenderedFeatures(const ScreenBox&, const RenderedQueryOptions&) const;
|
||||
std::vector<Feature> querySourceFeatures(const std::string& sourceID, const SourceQueryOptions&) const;
|
||||
AnnotationIDs queryPointAnnotations(const ScreenBox& box) const;
|
||||
|
||||
// RenderBackend proxy - Called from OpenGL Thread
|
||||
void resizeFramebuffer(int width, int height);
|
||||
|
||||
// Memory
|
||||
void onLowMemory();
|
||||
|
||||
@@ -67,19 +51,12 @@ public:
|
||||
void requestSnapshot(SnapshotCallback);
|
||||
|
||||
private:
|
||||
std::unique_ptr<AndroidRendererBackend> backend;
|
||||
std::unique_ptr<AndroidGLThread> glThread;
|
||||
std::unique_ptr<RendererObserver> rendererObserver;
|
||||
|
||||
std::mutex updateMutex;
|
||||
std::shared_ptr<UpdateParameters> updateParameters;
|
||||
|
||||
|
||||
util::AsyncTask asyncInvalidate;
|
||||
MapRenderer& mapRenderer;
|
||||
|
||||
util::RunLoop* mapRunLoop;
|
||||
|
||||
bool framebufferSizeChanged = true;
|
||||
// TODO
|
||||
std::unique_ptr<SnapshotCallback> snapshotCallback;
|
||||
};
|
||||
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
#include "gson/json_object.hpp"
|
||||
#include "gson/json_primitive.hpp"
|
||||
#include "java_types.hpp"
|
||||
#include "map_renderer.hpp"
|
||||
#include "map_renderer_runnable.hpp"
|
||||
#include "native_map_view.hpp"
|
||||
#include "offline/offline_manager.hpp"
|
||||
#include "offline/offline_region.hpp"
|
||||
@@ -144,6 +146,8 @@ void registerNatives(JavaVM *vm) {
|
||||
Polyline::registerNative(env);
|
||||
|
||||
// Map
|
||||
MapRenderer::registerNative(env);
|
||||
MapRendererRunnable::registerNative(env);
|
||||
NativeMapView::registerNative(env);
|
||||
|
||||
// Http
|
||||
|
||||
137
platform/android/src/map_renderer.cpp
Normal file
137
platform/android/src/map_renderer.cpp
Normal file
@@ -0,0 +1,137 @@
|
||||
#include "map_renderer.hpp"
|
||||
|
||||
#include <mbgl/renderer/renderer.hpp>
|
||||
#include <mbgl/util/shared_thread_pool.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "attach_env.hpp"
|
||||
#include "android_renderer_backend.hpp"
|
||||
#include "map_renderer_runnable.hpp"
|
||||
#include "file_source.hpp"
|
||||
|
||||
namespace mbgl {
|
||||
namespace android {
|
||||
|
||||
MapRenderer::MapRenderer(jni::JNIEnv& _env,
|
||||
jni::Object<MapRenderer> obj,
|
||||
jni::Object<FileSource> fileSource,
|
||||
jni::jfloat pixelRatio,
|
||||
jni::String programCacheDir)
|
||||
: javaPeer(SeizeGenericWeakRef(_env, jni::Object<MapRenderer>(jni::NewWeakGlobalRef(_env, obj.Get()).release())))
|
||||
, threadPool(sharedThreadPool())
|
||||
, backend(std::make_unique<AndroidRendererBackend>())
|
||||
, renderer(std::make_unique<Renderer>(*backend, pixelRatio, FileSource::getDefaultFileSource(_env, fileSource),
|
||||
*threadPool, GLContextMode::Unique, jni::Make<std::string>(_env, programCacheDir)))
|
||||
, mailbox(std::make_shared<Mailbox>(*this))
|
||||
, rendererRef(*renderer, mailbox) {
|
||||
}
|
||||
|
||||
MapRenderer::~MapRenderer() = default;
|
||||
|
||||
void MapRenderer::reset() {
|
||||
assert (renderer);
|
||||
renderer.reset();
|
||||
}
|
||||
|
||||
ActorRef<Renderer> MapRenderer::actor() const {
|
||||
return rendererRef;
|
||||
}
|
||||
|
||||
void MapRenderer::schedule(std::weak_ptr<Mailbox> scheduled) {
|
||||
// Create a runnable and schedule it on the gl thread
|
||||
android::UniqueEnv _env = android::AttachEnv();
|
||||
auto runnable = std::make_unique<MapRendererRunnable>(*_env, std::move(scheduled));
|
||||
|
||||
static auto queueEvent = javaClass.GetMethod<void (jni::Object<MapRendererRunnable>)>(*_env, "queueEvent");
|
||||
javaPeer->Call(*_env, queueEvent, runnable->getPeer());
|
||||
|
||||
// Release the object as it will be destroyed on GC of the Java Peer
|
||||
runnable.release();
|
||||
}
|
||||
|
||||
void MapRenderer::requestRender() {
|
||||
android::UniqueEnv _env = android::AttachEnv();
|
||||
static auto onInvalidate = javaClass.GetMethod<void ()>(*_env, "requestRender");
|
||||
javaPeer->Call(*_env, onInvalidate);
|
||||
}
|
||||
|
||||
void MapRenderer::update(std::shared_ptr<UpdateParameters> params) {
|
||||
// Lock on the parameters
|
||||
std::lock_guard<std::mutex> lock(updateMutex);
|
||||
updateParameters = std::move(params);
|
||||
}
|
||||
|
||||
// Called on OpenGL thread //
|
||||
|
||||
void MapRenderer::render(JNIEnv&) {
|
||||
assert (renderer);
|
||||
|
||||
std::shared_ptr<UpdateParameters> params;
|
||||
{
|
||||
// Lock on the parameters
|
||||
std::unique_lock<std::mutex> lock(updateMutex);
|
||||
if (!updateParameters) return;
|
||||
|
||||
// Hold on to the update parameters during render
|
||||
params = updateParameters;
|
||||
}
|
||||
|
||||
// Activate the backend
|
||||
BackendScope backendGuard { *backend };
|
||||
|
||||
// Ensure that the "current" scheduler on the render thread is
|
||||
// this scheduler.
|
||||
Scheduler::SetCurrent(this);
|
||||
|
||||
if (framebufferSizeChanged) {
|
||||
backend->updateViewPort();
|
||||
framebufferSizeChanged = false;
|
||||
}
|
||||
|
||||
renderer->render(*params);
|
||||
}
|
||||
|
||||
void MapRenderer::onSurfaceCreated(JNIEnv&) {
|
||||
// TODO (re-)create Context, Backend and Renderer
|
||||
}
|
||||
|
||||
void MapRenderer::onSurfaceChanged(JNIEnv&, jint width, jint height) {
|
||||
backend->resizeFramebuffer(width, height);
|
||||
framebufferSizeChanged = true;
|
||||
requestRender();
|
||||
}
|
||||
|
||||
// Static methods //
|
||||
|
||||
jni::Class<MapRenderer> MapRenderer::javaClass;
|
||||
|
||||
void MapRenderer::registerNative(jni::JNIEnv& env) {
|
||||
// Lookup the class
|
||||
MapRenderer::javaClass = *jni::Class<MapRenderer>::Find(env).NewGlobalRef(env).release();
|
||||
|
||||
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
|
||||
|
||||
// Register the peer
|
||||
jni::RegisterNativePeer<MapRenderer>(
|
||||
env,
|
||||
MapRenderer::javaClass,
|
||||
"nativePtr",
|
||||
std::make_unique<MapRenderer, JNIEnv&, jni::Object<MapRenderer>, jni::Object<FileSource>, jni::jfloat, jni::String>,
|
||||
"nativeInitialize",
|
||||
"finalize",
|
||||
METHOD(&MapRenderer::render, "nativeRender"),
|
||||
METHOD(&MapRenderer::onSurfaceCreated, "nativeOnSurfaceCreated"),
|
||||
METHOD(&MapRenderer::onSurfaceChanged, "nativeOnSurfaceChanged")
|
||||
);
|
||||
}
|
||||
|
||||
MapRenderer& MapRenderer::getNativePeer(JNIEnv& env, jni::Object<MapRenderer> jObject) {
|
||||
static auto field = MapRenderer::javaClass.GetField<jlong>(env, "nativePtr");
|
||||
MapRenderer* mapRenderer = reinterpret_cast<MapRenderer *>(jObject.Get(env, field));
|
||||
assert(mapRenderer != nullptr);
|
||||
return *mapRenderer;
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
} // namespace mbgl
|
||||
95
platform/android/src/map_renderer.hpp
Normal file
95
platform/android/src/map_renderer.hpp
Normal file
@@ -0,0 +1,95 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/actor/actor_ref.hpp>
|
||||
#include <mbgl/actor/mailbox.hpp>
|
||||
#include <mbgl/actor/scheduler.hpp>
|
||||
#include <mbgl/renderer/renderer.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include <jni/jni.hpp>
|
||||
|
||||
#include "jni/generic_global_ref_deleter.hpp"
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class Renderer;
|
||||
class RendererBackend;
|
||||
class ThreadPool;
|
||||
class UpdateParameters;
|
||||
|
||||
namespace android {
|
||||
|
||||
class AndroidRendererBackend;
|
||||
class FileSource;
|
||||
|
||||
/**
|
||||
* The MapRenderer is a peer class that encapsulates the actions
|
||||
* performed on the GL Thread.
|
||||
*
|
||||
* The public methods are safe to call from the main thread, others are not.
|
||||
*/
|
||||
class MapRenderer : public Scheduler {
|
||||
public:
|
||||
|
||||
static constexpr auto Name() { return "com/mapbox/mapboxsdk/maps/renderer/MapRenderer"; };
|
||||
|
||||
static jni::Class<MapRenderer> javaClass;
|
||||
|
||||
static void registerNative(jni::JNIEnv&);
|
||||
|
||||
static MapRenderer& getNativePeer(JNIEnv&, jni::Object<MapRenderer>);
|
||||
|
||||
MapRenderer(jni::JNIEnv& _env,
|
||||
jni::Object<MapRenderer>,
|
||||
jni::Object<FileSource>,
|
||||
jni::jfloat pixelRatio,
|
||||
jni::String programCacheDir);
|
||||
|
||||
~MapRenderer() override;
|
||||
|
||||
// Resets the renderer to clean up on the calling thread
|
||||
void reset();
|
||||
|
||||
// Sets the new update parameters to use on subsequent
|
||||
// renders. Be sure to trigger a render with
|
||||
// requestRender().
|
||||
void update(std::shared_ptr<UpdateParameters>);
|
||||
|
||||
// Gives a handle to the Renderer to enable actions on
|
||||
// any thread.
|
||||
ActorRef<Renderer> actor() const;
|
||||
|
||||
// From Scheduler. Schedules by using callbacks to the
|
||||
// JVM to process the mailbox on the right thread.
|
||||
void schedule(std::weak_ptr<Mailbox> scheduled) override;
|
||||
|
||||
void requestRender();
|
||||
|
||||
private:
|
||||
// Called from the GL Thread //
|
||||
|
||||
// Renders a frame.
|
||||
void render(JNIEnv&);
|
||||
|
||||
void onSurfaceCreated(JNIEnv&);
|
||||
|
||||
void onSurfaceChanged(JNIEnv&, jint width, jint height);
|
||||
|
||||
private:
|
||||
GenericUniqueWeakObject<MapRenderer> javaPeer;
|
||||
std::shared_ptr<ThreadPool> threadPool;
|
||||
std::unique_ptr<AndroidRendererBackend> backend;
|
||||
std::unique_ptr<Renderer> renderer;
|
||||
std::shared_ptr<Mailbox> mailbox;
|
||||
ActorRef<Renderer> rendererRef;
|
||||
|
||||
std::shared_ptr<UpdateParameters> updateParameters;
|
||||
std::mutex updateMutex;
|
||||
|
||||
bool framebufferSizeChanged = false;
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
} // namespace mbgl
|
||||
49
platform/android/src/map_renderer_runnable.cpp
Normal file
49
platform/android/src/map_renderer_runnable.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
#include "map_renderer_runnable.hpp"
|
||||
|
||||
#include <mbgl/util/logging.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace android {
|
||||
|
||||
MapRendererRunnable::MapRendererRunnable(jni::JNIEnv& env, std::weak_ptr<Mailbox> mailbox_)
|
||||
: mailbox(std::move(mailbox_)) {
|
||||
|
||||
// Create the Java peer
|
||||
jni::UniqueLocalFrame frame = jni::PushLocalFrame(env, 5);
|
||||
static auto constructor = javaClass.GetConstructor<jlong>(env);
|
||||
auto instance = javaClass.New(env, constructor, reinterpret_cast<jlong>(this));
|
||||
javaPeer = SeizeGenericWeakRef(env, jni::Object<MapRendererRunnable>(jni::NewWeakGlobalRef(env, instance.Get()).release()));
|
||||
}
|
||||
|
||||
MapRendererRunnable::~MapRendererRunnable() = default;
|
||||
|
||||
void MapRendererRunnable::run(jni::JNIEnv&) {
|
||||
Mailbox::maybeReceive(mailbox);
|
||||
}
|
||||
|
||||
jni::Object<MapRendererRunnable> MapRendererRunnable::getPeer() {
|
||||
return *javaPeer;
|
||||
}
|
||||
|
||||
// Static methods //
|
||||
|
||||
jni::Class<MapRendererRunnable> MapRendererRunnable::javaClass;
|
||||
|
||||
void MapRendererRunnable::registerNative(jni::JNIEnv& env) {
|
||||
// Lookup the class
|
||||
MapRendererRunnable::javaClass = *jni::Class<MapRendererRunnable>::Find(env).NewGlobalRef(env).release();
|
||||
|
||||
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
|
||||
|
||||
jni::RegisterNativePeer<MapRendererRunnable>(
|
||||
env,
|
||||
MapRendererRunnable::javaClass,
|
||||
"nativePtr",
|
||||
std::make_unique<MapRendererRunnable, JNIEnv&>,
|
||||
"nativeInitialize",
|
||||
"finalize",
|
||||
METHOD(&MapRendererRunnable::run, "run"));
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
} // namespace mbgl
|
||||
50
platform/android/src/map_renderer_runnable.hpp
Normal file
50
platform/android/src/map_renderer_runnable.hpp
Normal file
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/actor/mailbox.hpp>
|
||||
#include <mbgl/actor/scheduler.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include <jni/jni.hpp>
|
||||
|
||||
#include "jni/generic_global_ref_deleter.hpp"
|
||||
|
||||
namespace mbgl {
|
||||
namespace android {
|
||||
|
||||
/**
|
||||
* The MapRendererRunnable is a peer class that encapsulates
|
||||
* a scheduled mailbox in a Java Runnable so it can be
|
||||
* scheduled on the map renderer thread.
|
||||
*
|
||||
*/
|
||||
class MapRendererRunnable {
|
||||
public:
|
||||
|
||||
static constexpr auto Name() { return "com/mapbox/mapboxsdk/maps/renderer/MapRendererRunnable"; };
|
||||
|
||||
static jni::Class<MapRendererRunnable> javaClass;
|
||||
|
||||
static void registerNative(jni::JNIEnv&);
|
||||
|
||||
MapRendererRunnable(jni::JNIEnv&, std::weak_ptr<Mailbox>);
|
||||
|
||||
// Only for jni registration, unused
|
||||
MapRendererRunnable(jni::JNIEnv&) {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
~MapRendererRunnable();
|
||||
|
||||
void run(jni::JNIEnv&);
|
||||
|
||||
jni::Object<MapRendererRunnable> getPeer();
|
||||
|
||||
private:
|
||||
GenericUniqueWeakObject<MapRendererRunnable> javaPeer;
|
||||
std::weak_ptr<Mailbox> mailbox;
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
} // namespace mbgl
|
||||
@@ -9,12 +9,10 @@
|
||||
|
||||
#include <sys/system_properties.h>
|
||||
|
||||
#include <EGL/egl.h>
|
||||
#include <android/native_window_jni.h>
|
||||
|
||||
#include <jni/jni.hpp>
|
||||
|
||||
#include <mbgl/renderer/backend_scope.hpp>
|
||||
#include <mbgl/math/minmax.hpp>
|
||||
#include <mbgl/util/constants.hpp>
|
||||
#include <mbgl/util/event.hpp>
|
||||
@@ -28,7 +26,6 @@
|
||||
#include <mbgl/style/style.hpp>
|
||||
#include <mbgl/style/image.hpp>
|
||||
#include <mbgl/style/filter.hpp>
|
||||
#include <mbgl/renderer/renderer.hpp>
|
||||
|
||||
// Java -> C++ conversion
|
||||
#include "style/android_conversion.hpp"
|
||||
@@ -43,8 +40,9 @@
|
||||
|
||||
#include "jni.hpp"
|
||||
#include "attach_env.hpp"
|
||||
#include "android_renderer_backend.hpp"
|
||||
#include "map_renderer.hpp"
|
||||
#include "android_renderer_frontend.hpp"
|
||||
#include "file_source.hpp"
|
||||
#include "bitmap.hpp"
|
||||
#include "run_loop_impl.hpp"
|
||||
#include "java/util.hpp"
|
||||
@@ -59,8 +57,8 @@ namespace android {
|
||||
NativeMapView::NativeMapView(jni::JNIEnv& _env,
|
||||
jni::Object<NativeMapView> _obj,
|
||||
jni::Object<FileSource> jFileSource,
|
||||
jni::jfloat _pixelRatio,
|
||||
jni::String _programCacheDir)
|
||||
jni::Object<MapRenderer> jMapRenderer,
|
||||
jni::jfloat _pixelRatio)
|
||||
: javaPeer(_obj.NewWeakGlobalRef(_env)),
|
||||
pixelRatio(_pixelRatio),
|
||||
threadPool(sharedThreadPool()) {
|
||||
@@ -71,15 +69,12 @@ NativeMapView::NativeMapView(jni::JNIEnv& _env,
|
||||
return;
|
||||
}
|
||||
|
||||
// Get native peers
|
||||
mbgl::FileSource& fileSource = mbgl::android::FileSource::getDefaultFileSource(_env, jFileSource);
|
||||
MapRenderer& mapRenderer = MapRenderer::getNativePeer(_env, jMapRenderer);
|
||||
|
||||
// Create a renderer frontend
|
||||
rendererFrontend = std::make_unique<AndroidRendererFrontend>(pixelRatio, fileSource,
|
||||
*threadPool,
|
||||
jni::Make<std::string>(_env,
|
||||
_programCacheDir),
|
||||
[this] { this->requestRender(); },
|
||||
[this] { this->requestProcessing(); });
|
||||
rendererFrontend = std::make_unique<AndroidRendererFrontend>(mapRenderer);
|
||||
|
||||
// Create the core map
|
||||
map = std::make_unique<mbgl::Map>(*rendererFrontend, *this,
|
||||
@@ -97,24 +92,6 @@ NativeMapView::~NativeMapView() {
|
||||
vm = nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to java NativeMapView#requestRender().
|
||||
*
|
||||
* Called to schedule a render on the next
|
||||
* runloop iteration.
|
||||
*/
|
||||
void NativeMapView::requestRender() {
|
||||
android::UniqueEnv _env = android::AttachEnv();
|
||||
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).
|
||||
*
|
||||
@@ -194,31 +171,12 @@ void NativeMapView::onSourceChanged(mbgl::style::Source&) {
|
||||
|
||||
// JNI Methods //
|
||||
|
||||
// Called from the OpenGL renderer thread
|
||||
void NativeMapView::render(jni::JNIEnv& ) {
|
||||
rendererFrontend->render();
|
||||
|
||||
// TODO
|
||||
updateFps();
|
||||
}
|
||||
|
||||
// Called from the OpenGL renderer thread
|
||||
void NativeMapView::process(jni::JNIEnv&) {
|
||||
rendererFrontend->process();
|
||||
}
|
||||
|
||||
void NativeMapView::resizeView(jni::JNIEnv&, int w, int h) {
|
||||
width = util::max(64, w);
|
||||
height = util::max(64, h);
|
||||
map->setSize({ static_cast<uint32_t>(width), static_cast<uint32_t>(height) });
|
||||
}
|
||||
|
||||
void NativeMapView::resizeFramebuffer(jni::JNIEnv&, int w, int h) {
|
||||
rendererFrontend->resizeFramebuffer(w, h);
|
||||
// framebufferSizeChanged = true;
|
||||
// invalidate();
|
||||
}
|
||||
|
||||
jni::String NativeMapView::getStyleUrl(jni::JNIEnv& env) {
|
||||
return jni::Make<jni::String>(env, map->getStyle().getURL());
|
||||
}
|
||||
@@ -969,6 +927,7 @@ jni::jboolean NativeMapView::getPrefetchesTiles(JNIEnv&) {
|
||||
|
||||
// Private methods //
|
||||
|
||||
// TODO
|
||||
void NativeMapView::updateFps() {
|
||||
if (!fpsEnabled) {
|
||||
return;
|
||||
@@ -1008,13 +967,10 @@ void NativeMapView::registerNative(jni::JNIEnv& env) {
|
||||
|
||||
// Register the peer
|
||||
jni::RegisterNativePeer<NativeMapView>(env, NativeMapView::javaClass, "nativePtr",
|
||||
std::make_unique<NativeMapView, JNIEnv&, jni::Object<NativeMapView>, jni::Object<FileSource>, jni::jfloat, jni::String>,
|
||||
std::make_unique<NativeMapView, JNIEnv&, jni::Object<NativeMapView>, jni::Object<FileSource>, jni::Object<MapRenderer>, jni::jfloat>,
|
||||
"nativeInitialize",
|
||||
"nativeDestroy",
|
||||
METHOD(&NativeMapView::render, "nativeRender"),
|
||||
METHOD(&NativeMapView::process, "nativeProcess"),
|
||||
METHOD(&NativeMapView::resizeView, "nativeResizeView"),
|
||||
METHOD(&NativeMapView::resizeFramebuffer, "nativeResizeFramebuffer"),
|
||||
METHOD(&NativeMapView::getStyleUrl, "nativeGetStyleUrl"),
|
||||
METHOD(&NativeMapView::setStyleUrl, "nativeSetStyleUrl"),
|
||||
METHOD(&NativeMapView::getStyleJson, "nativeGetStyleJson"),
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/renderer/renderer_backend.hpp>
|
||||
#include <mbgl/map/change.hpp>
|
||||
#include <mbgl/map/camera.hpp>
|
||||
#include <mbgl/map/map.hpp>
|
||||
@@ -10,7 +9,6 @@
|
||||
#include <mbgl/storage/default_file_source.hpp>
|
||||
#include <mbgl/storage/network_status.hpp>
|
||||
|
||||
#include "file_source.hpp"
|
||||
#include "annotation/marker.hpp"
|
||||
#include "annotation/polygon.hpp"
|
||||
#include "annotation/polyline.hpp"
|
||||
@@ -37,6 +35,8 @@ namespace mbgl {
|
||||
namespace android {
|
||||
|
||||
class AndroidRendererFrontend;
|
||||
class FileSource;
|
||||
class MapRenderer;
|
||||
|
||||
class NativeMapView : public MapObserver {
|
||||
public:
|
||||
@@ -50,8 +50,8 @@ public:
|
||||
NativeMapView(jni::JNIEnv&,
|
||||
jni::Object<NativeMapView>,
|
||||
jni::Object<FileSource>,
|
||||
jni::jfloat pixelRatio,
|
||||
jni::String programCacheDir);
|
||||
jni::Object<MapRenderer>,
|
||||
jni::jfloat pixelRatio);
|
||||
|
||||
virtual ~NativeMapView();
|
||||
|
||||
@@ -72,28 +72,10 @@ public:
|
||||
void onDidFinishLoadingStyle() override;
|
||||
void onSourceChanged(mbgl::style::Source&) override;
|
||||
|
||||
// Signal the view system, we want to redraw
|
||||
void requestRender();
|
||||
|
||||
// Request processing on the GL Thread
|
||||
void requestProcessing();
|
||||
|
||||
// JNI //
|
||||
|
||||
// Called on OpenGL Thread
|
||||
void onSurfaceCreated(jni::JNIEnv&);
|
||||
|
||||
// Called on OpenGL Thread
|
||||
void process(jni::JNIEnv&);
|
||||
|
||||
// Called on OpenGL Thread
|
||||
void render(jni::JNIEnv&);
|
||||
|
||||
void resizeView(jni::JNIEnv&, int, int);
|
||||
|
||||
// Called on OpenGL Thread
|
||||
void resizeFramebuffer(jni::JNIEnv&, int, int);
|
||||
|
||||
jni::String getStyleUrl(jni::JNIEnv&);
|
||||
|
||||
void setStyleUrl(jni::JNIEnv&, jni::String);
|
||||
|
||||
Reference in New Issue
Block a user