diff options
author | Ivo van Dongen <info@ivovandongen.nl> | 2017-07-21 16:15:30 +0300 |
---|---|---|
committer | Ivo van Dongen <ivovandongen@users.noreply.github.com> | 2017-09-22 23:33:56 +0300 |
commit | 347d7c19c0a70f91252163b14e37583eea83fdd5 (patch) | |
tree | c46968ba9fb947be6b6387ab18b10a0fede35f59 /platform/android/src/native_map_view.cpp | |
parent | e780cdc29ee82459a75db5aba2e72c5536a2d1b0 (diff) | |
download | qtlocation-mapboxgl-347d7c19c0a70f91252163b14e37583eea83fdd5.tar.gz |
[android] async rendering
- introduces GLSurfaceView
- introduces Orchestration thread
- renders on the gl thread
Diffstat (limited to 'platform/android/src/native_map_view.cpp')
-rwxr-xr-x | platform/android/src/native_map_view.cpp | 459 |
1 files changed, 26 insertions, 433 deletions
diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp index a0d88e8cf1..1a0dc34bbc 100755 --- a/platform/android/src/native_map_view.cpp +++ b/platform/android/src/native_map_view.cpp @@ -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 |