[android] async rendering
- introduces GLSurfaceView - introduces Orchestration thread - renders on the gl thread
This commit is contained in:
committed by
Ivo van Dongen
parent
e780cdc29e
commit
347d7c19c0
@@ -61,8 +61,7 @@ NativeMapView::NativeMapView(jni::JNIEnv& _env,
|
||||
jni::Object<FileSource> jFileSource,
|
||||
jni::jfloat _pixelRatio,
|
||||
jni::String _programCacheDir)
|
||||
: rendererBackend(std::make_unique<AndroidRendererBackend>()),
|
||||
javaPeer(_obj.NewWeakGlobalRef(_env)),
|
||||
: javaPeer(_obj.NewWeakGlobalRef(_env)),
|
||||
pixelRatio(_pixelRatio),
|
||||
threadPool(sharedThreadPool()) {
|
||||
|
||||
@@ -72,16 +71,13 @@ NativeMapView::NativeMapView(jni::JNIEnv& _env,
|
||||
return;
|
||||
}
|
||||
|
||||
auto& fileSource = mbgl::android::FileSource::getDefaultFileSource(_env, jFileSource);
|
||||
|
||||
// Create a renderer
|
||||
auto renderer = std::make_unique<Renderer>(*rendererBackend, pixelRatio, fileSource,
|
||||
*threadPool, GLContextMode::Unique,
|
||||
jni::Make<std::string>(_env, _programCacheDir));
|
||||
mbgl::FileSource& fileSource = mbgl::android::FileSource::getDefaultFileSource(_env, jFileSource);
|
||||
|
||||
// Create a renderer frontend
|
||||
rendererFrontend = std::make_unique<AndroidRendererFrontend>(std::move(renderer),
|
||||
*rendererBackend,
|
||||
rendererFrontend = std::make_unique<AndroidRendererFrontend>(pixelRatio, fileSource,
|
||||
*threadPool,
|
||||
jni::Make<std::string>(_env,
|
||||
_programCacheDir),
|
||||
[this] { this->invalidate(); });
|
||||
|
||||
// Create the core map
|
||||
@@ -90,29 +86,21 @@ NativeMapView::NativeMapView(jni::JNIEnv& _env,
|
||||
static_cast<uint32_t>(height) }, pixelRatio,
|
||||
fileSource, *threadPool, MapMode::Continuous,
|
||||
ConstrainMode::HeightOnly, ViewportMode::Default);
|
||||
|
||||
// initialize egl components
|
||||
_initializeDisplay();
|
||||
_initializeContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called through NativeMapView#destroy()
|
||||
*/
|
||||
NativeMapView::~NativeMapView() {
|
||||
_terminateContext();
|
||||
_destroySurface();
|
||||
_terminateDisplay();
|
||||
|
||||
map.reset();
|
||||
|
||||
vm = nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to java NativeMapView#onInvalidate().
|
||||
*
|
||||
* May be called from any thread
|
||||
* Called to invalidate the View and schedule a render on the next
|
||||
* runloop iteration.
|
||||
*/
|
||||
void NativeMapView::invalidate() {
|
||||
android::UniqueEnv _env = android::AttachEnv();
|
||||
@@ -199,48 +187,12 @@ void NativeMapView::onSourceChanged(mbgl::style::Source&) {
|
||||
|
||||
// JNI Methods //
|
||||
|
||||
void NativeMapView::createSurface(jni::JNIEnv& env, jni::Object<> _surface) {
|
||||
_createSurface(ANativeWindow_fromSurface(&env, jni::Unwrap(*_surface)));
|
||||
}
|
||||
|
||||
void NativeMapView::destroySurface(jni::JNIEnv&) {
|
||||
_destroySurface();
|
||||
}
|
||||
|
||||
void NativeMapView::render(jni::JNIEnv& env) {
|
||||
BackendScope guard { *rendererBackend };
|
||||
|
||||
if (framebufferSizeChanged) {
|
||||
rendererBackend->updateViewPort();
|
||||
framebufferSizeChanged = false;
|
||||
}
|
||||
|
||||
// Called from the OpenGL renderer thread
|
||||
void NativeMapView::render(jni::JNIEnv& ) {
|
||||
rendererFrontend->render();
|
||||
|
||||
if(snapshot){
|
||||
snapshot = false;
|
||||
|
||||
// take snapshot
|
||||
auto image = rendererBackend->readFramebuffer();
|
||||
auto bitmap = Bitmap::CreateBitmap(env, std::move(image));
|
||||
|
||||
// invoke Mapview#OnSnapshotReady
|
||||
android::UniqueEnv _env = android::AttachEnv();
|
||||
static auto onSnapshotReady = javaClass.GetMethod<void (jni::Object<Bitmap>)>(*_env, "onSnapshotReady");
|
||||
javaPeer->Call(*_env, onSnapshotReady, bitmap);
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
// TODO
|
||||
updateFps();
|
||||
}
|
||||
|
||||
void NativeMapView::update(jni::JNIEnv&) {
|
||||
@@ -254,9 +206,9 @@ void NativeMapView::resizeView(jni::JNIEnv&, int w, int h) {
|
||||
}
|
||||
|
||||
void NativeMapView::resizeFramebuffer(jni::JNIEnv&, int w, int h) {
|
||||
rendererBackend->resizeFramebuffer(w, h);
|
||||
framebufferSizeChanged = true;
|
||||
invalidate();
|
||||
rendererFrontend->resizeFramebuffer(w, h);
|
||||
// framebufferSizeChanged = true;
|
||||
// invalidate();
|
||||
}
|
||||
|
||||
jni::String NativeMapView::getStyleUrl(jni::JNIEnv& env) {
|
||||
@@ -476,7 +428,15 @@ void NativeMapView::setContentPadding(JNIEnv&, double top, double left, double b
|
||||
}
|
||||
|
||||
void NativeMapView::scheduleSnapshot(jni::JNIEnv&) {
|
||||
snapshot = true;
|
||||
rendererFrontend->requestSnapshot([&](PremultipliedImage image) {
|
||||
auto _env = android::AttachEnv();
|
||||
// Convert image to bitmap
|
||||
auto bitmap = Bitmap::CreateBitmap(*_env, std::move(image));
|
||||
|
||||
// invoke Mapview#OnSnapshotReady
|
||||
static auto onSnapshotReady = javaClass.GetMethod<void (jni::Object<Bitmap>)>(*_env, "onSnapshotReady");
|
||||
javaPeer->Call(*_env, onSnapshotReady, bitmap);
|
||||
});
|
||||
}
|
||||
|
||||
void NativeMapView::enableFps(jni::JNIEnv&, jni::jboolean enable) {
|
||||
@@ -1001,371 +961,6 @@ jni::jboolean NativeMapView::getPrefetchesTiles(JNIEnv&) {
|
||||
|
||||
// Private methods //
|
||||
|
||||
void NativeMapView::_initializeDisplay() {
|
||||
assert(display == EGL_NO_DISPLAY);
|
||||
assert(config == nullptr);
|
||||
assert(format < 0);
|
||||
|
||||
display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
// 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::_terminateDisplay() {
|
||||
if (display != EGL_NO_DISPLAY) {
|
||||
// Destroy the surface first, if it still exists. This call needs a valid surface.
|
||||
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 (!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);
|
||||
|
||||
const EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
|
||||
context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
|
||||
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");
|
||||
}
|
||||
|
||||
if (context != EGL_NO_CONTEXT) {
|
||||
if (!eglDestroyContext(display, context)) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL, "eglDestroyContext() returned error %d",
|
||||
eglGetError());
|
||||
throw std::runtime_error("eglDestroyContext() 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);
|
||||
|
||||
const EGLint surfaceAttribs[] = {EGL_NONE};
|
||||
surface = eglCreateWindowSurface(display, config, window, surfaceAttribs);
|
||||
if (surface == EGL_NO_SURFACE) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL, "eglCreateWindowSurface() returned error %d",
|
||||
eglGetError());
|
||||
throw std::runtime_error("eglCreateWindowSurface() failed");
|
||||
}
|
||||
|
||||
if (firstRender) {
|
||||
firstRender = false;
|
||||
|
||||
BackendScope guard(*rendererBackend);
|
||||
|
||||
if (!eglMakeCurrent(display, surface, surface, context)) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL, "eglMakeCurrent() returned error %d",
|
||||
eglGetError());
|
||||
throw std::runtime_error("eglMakeCurrent() failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
firstRender = true;
|
||||
|
||||
if (window != nullptr) {
|
||||
ANativeWindow_release(window);
|
||||
window = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void NativeMapView::updateFps() {
|
||||
if (!fpsEnabled) {
|
||||
return;
|
||||
@@ -1412,8 +1007,6 @@ void NativeMapView::registerNative(jni::JNIEnv& env) {
|
||||
METHOD(&NativeMapView::update, "nativeUpdate"),
|
||||
METHOD(&NativeMapView::resizeView, "nativeResizeView"),
|
||||
METHOD(&NativeMapView::resizeFramebuffer, "nativeResizeFramebuffer"),
|
||||
METHOD(&NativeMapView::createSurface, "nativeCreateSurface"),
|
||||
METHOD(&NativeMapView::destroySurface, "nativeDestroySurface"),
|
||||
METHOD(&NativeMapView::getStyleUrl, "nativeGetStyleUrl"),
|
||||
METHOD(&NativeMapView::setStyleUrl, "nativeSetStyleUrl"),
|
||||
METHOD(&NativeMapView::getStyleJson, "nativeGetStyleJson"),
|
||||
@@ -1498,5 +1091,5 @@ void NativeMapView::registerNative(jni::JNIEnv& env) {
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace android
|
||||
} // namespace mbgl
|
||||
|
||||
Reference in New Issue
Block a user