From 234384ece9c70f2a803ed2b1d1eb55b248ec43d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Mon, 27 Feb 2017 18:33:16 +0100 Subject: [PATCH] [core] Move OpenGL extension initialization to Backend --- include/mbgl/map/backend.hpp | 11 +++++++ platform/android/src/native_map_view.cpp | 9 +++--- platform/android/src/native_map_view.hpp | 1 + platform/darwin/src/headless_backend_cgl.cpp | 4 +-- platform/darwin/src/headless_backend_eagl.mm | 6 ++-- platform/default/headless_backend_osmesa.cpp | 2 +- platform/default/mbgl/gl/headless_backend.cpp | 5 ---- platform/default/mbgl/gl/headless_backend.hpp | 5 +--- platform/glfw/glfw_view.cpp | 7 +++-- platform/glfw/glfw_view.hpp | 6 +++- platform/ios/src/MGLMapView.mm | 30 +++++++++---------- platform/linux/src/headless_backend_egl.cpp | 2 +- platform/linux/src/headless_backend_glx.cpp | 2 +- platform/macos/src/MGLMapView.mm | 27 ++++++++--------- platform/qt/app/mapwindow.cpp | 2 -- platform/qt/include/qmapbox.hpp | 2 -- platform/qt/src/qmapbox.cpp | 23 -------------- platform/qt/src/qmapboxgl.cpp | 14 +++++++++ platform/qt/src/qmapboxgl_p.hpp | 3 ++ platform/qt/test/headless_backend_qt.cpp | 4 +-- platform/qt/test/qmapboxgl.cpp | 2 -- src/mbgl/gl/extension.cpp | 25 +++++++--------- src/mbgl/gl/extension.hpp | 7 +++-- src/mbgl/map/backend.cpp | 11 +++++-- src/mbgl/renderer/painter.cpp | 2 -- 25 files changed, 102 insertions(+), 110 deletions(-) diff --git a/include/mbgl/map/backend.hpp b/include/mbgl/map/backend.hpp index cd756abe4..876c19261 100644 --- a/include/mbgl/map/backend.hpp +++ b/include/mbgl/map/backend.hpp @@ -3,11 +3,13 @@ #include #include +#include namespace mbgl { namespace gl { class Context; +using ProcAddress = void (*)(); } // namespace gl class BackendScope; @@ -25,6 +27,11 @@ public: virtual void invalidate() = 0; protected: + // Called with the name of an OpenGL extension that should be loaded. Backend implementations + // must call the API-specific version that obtains the function pointer for this function, + // or a null pointer if unsupported/unavailable. + virtual gl::ProcAddress initializeExtension(const char*) = 0; + // Called when the backend's GL context needs to be made active or inactive. These are called, // as a matched pair, in four situations: // @@ -38,8 +45,12 @@ protected: virtual void activate() = 0; virtual void deactivate() = 0; +protected: std::unique_ptr context; +private: + std::once_flag initialized; + friend class BackendScope; }; diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp index c65c24145..eeb4620c2 100755 --- a/platform/android/src/native_map_view.cpp +++ b/platform/android/src/native_map_view.cpp @@ -15,7 +15,6 @@ #include #include -#include #include #include #include @@ -108,6 +107,10 @@ void NativeMapView::bind() { /** * From mbgl::Backend. */ +gl::ProcAddress NativeMapView::initializeExtension(const char* name) { + return eglGetProcAddress(name); +} + void NativeMapView::activate() { if (active++) { return; @@ -1394,10 +1397,6 @@ void NativeMapView::_createSurface(ANativeWindow *window_) { eglGetError()); throw std::runtime_error("eglMakeCurrent() failed"); } - - mbgl::gl::InitializeExtensions([] (const char * name) { - return reinterpret_cast(eglGetProcAddress(name)); - }); } } diff --git a/platform/android/src/native_map_view.hpp b/platform/android/src/native_map_view.hpp index 9a490ddba..af8c7dd66 100755 --- a/platform/android/src/native_map_view.hpp +++ b/platform/android/src/native_map_view.hpp @@ -262,6 +262,7 @@ public: protected: // mbgl::Backend // + gl::ProcAddress initializeExtension(const char*) override; void activate() override; void deactivate() override; diff --git a/platform/darwin/src/headless_backend_cgl.cpp b/platform/darwin/src/headless_backend_cgl.cpp index 7069738fb..6ad98f432 100644 --- a/platform/darwin/src/headless_backend_cgl.cpp +++ b/platform/darwin/src/headless_backend_cgl.cpp @@ -36,7 +36,7 @@ struct CGLImpl : public HeadlessBackend::Impl { CGLContextObj glContext = nullptr; }; -gl::glProc HeadlessBackend::initializeExtension(const char* name) { +gl::ProcAddress HeadlessBackend::initializeExtension(const char* name) { static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl")); if (!framework) { throw std::runtime_error("Failed to load OpenGL framework."); @@ -46,7 +46,7 @@ gl::glProc HeadlessBackend::initializeExtension(const char* name) { void* symbol = CFBundleGetFunctionPointerForName(framework, str); CFRelease(str); - return reinterpret_cast(symbol); + return reinterpret_cast(symbol); } bool HeadlessBackend::hasDisplay() { diff --git a/platform/darwin/src/headless_backend_eagl.mm b/platform/darwin/src/headless_backend_eagl.mm index bd4a202ec..1daaeaf54 100644 --- a/platform/darwin/src/headless_backend_eagl.mm +++ b/platform/darwin/src/headless_backend_eagl.mm @@ -1,7 +1,5 @@ #include -#include - #include #include @@ -29,7 +27,7 @@ struct EAGLImpl : public HeadlessBackend::Impl { EAGLContext* glContext = nullptr; }; -gl::glProc HeadlessBackend::initializeExtension(const char* name) { +gl::ProcAddress HeadlessBackend::initializeExtension(const char* name) { static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengles")); if (!framework) { throw std::runtime_error("Failed to load OpenGL framework."); @@ -39,7 +37,7 @@ gl::glProc HeadlessBackend::initializeExtension(const char* name) { void* symbol = CFBundleGetFunctionPointerForName(framework, str); CFRelease(str); - return reinterpret_cast(symbol); + return reinterpret_cast(symbol); } bool HeadlessBackend::hasDisplay() { diff --git a/platform/default/headless_backend_osmesa.cpp b/platform/default/headless_backend_osmesa.cpp index 8ec6079bd..5042f5ed1 100644 --- a/platform/default/headless_backend_osmesa.cpp +++ b/platform/default/headless_backend_osmesa.cpp @@ -25,7 +25,7 @@ struct OSMesaImpl : public HeadlessBackend::Impl { GLubyte fakeBuffer = 0; }; -gl::glProc HeadlessBackend::initializeExtension(const char* name) { +gl::ProcAddress HeadlessBackend::initializeExtension(const char* name) { return OSMesaGetProcAddress(name); } diff --git a/platform/default/mbgl/gl/headless_backend.cpp b/platform/default/mbgl/gl/headless_backend.cpp index 6ae19356f..798c8fe68 100644 --- a/platform/default/mbgl/gl/headless_backend.cpp +++ b/platform/default/mbgl/gl/headless_backend.cpp @@ -33,11 +33,6 @@ void HeadlessBackend::activate() { assert(hasContext()); impl->activateContext(); - - if (!extensionsLoaded) { - gl::InitializeExtensions(initializeExtension); - extensionsLoaded = true; - } } void HeadlessBackend::deactivate() { diff --git a/platform/default/mbgl/gl/headless_backend.hpp b/platform/default/mbgl/gl/headless_backend.hpp index 63e3cec9e..7e1749a25 100644 --- a/platform/default/mbgl/gl/headless_backend.hpp +++ b/platform/default/mbgl/gl/headless_backend.hpp @@ -1,7 +1,5 @@ #pragma once -#include - #include #include @@ -27,7 +25,7 @@ public: private: // Implementation specific functions - static gl::glProc initializeExtension(const char*); + gl::ProcAddress initializeExtension(const char*) override; void activate() override; void deactivate() override; @@ -40,7 +38,6 @@ private: std::unique_ptr impl; std::shared_ptr display; - bool extensionsLoaded = false; bool active = false; }; diff --git a/platform/glfw/glfw_view.cpp b/platform/glfw/glfw_view.cpp index d73b147de..812b0e32a 100644 --- a/platform/glfw/glfw_view.cpp +++ b/platform/glfw/glfw_view.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -86,8 +85,6 @@ GLFWView::GLFWView(bool fullscreen_, bool benchmark_) glfwSetScrollCallback(window, onScroll); glfwSetKeyCallback(window, onKey); - mbgl::gl::InitializeExtensions(glfwGetProcAddress); - glfwGetWindowSize(window, &width, &height); glfwGetFramebufferSize(window, &fbWidth, &fbHeight); pixelRatio = static_cast(fbWidth) / width; @@ -499,6 +496,10 @@ mbgl::Size GLFWView::getFramebufferSize() const { return { static_cast(fbWidth), static_cast(fbHeight) }; } +mbgl::gl::ProcAddress GLFWView::initializeExtension(const char* name) { + return glfwGetProcAddress(name); +} + void GLFWView::activate() { glfwMakeContextCurrent(window); } diff --git a/platform/glfw/glfw_view.hpp b/platform/glfw/glfw_view.hpp index bfabf6cc6..55f795cd3 100644 --- a/platform/glfw/glfw_view.hpp +++ b/platform/glfw/glfw_view.hpp @@ -44,9 +44,13 @@ public: mbgl::Size getFramebufferSize() const; // mbgl::Backend implementation + void invalidate() override; + +protected: + // mbgl::Backend implementation + mbgl::gl::ProcAddress initializeExtension(const char*) override; void activate() override; void deactivate() override; - void invalidate() override; private: // Window callbacks diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index 6bd309244..e8bc1b4b2 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -1,7 +1,6 @@ #import "MGLMapView_Private.h" #include -#include #include #import @@ -610,21 +609,6 @@ public: [_glView bindDrawable]; [self insertSubview:_glView atIndex:0]; _glView.contentMode = UIViewContentModeCenter; - - // load extensions - // - mbgl::gl::InitializeExtensions([](const char * name) { - static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengles")); - if (!framework) { - throw std::runtime_error("Failed to load OpenGL framework."); - } - - CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingASCII); - void* symbol = CFBundleGetFunctionPointerForName(framework, str); - CFRelease(str); - - return reinterpret_cast(symbol); - }); } - (UIImage *)compassImage @@ -5436,6 +5420,20 @@ public: [nativeView didFinishLoadingStyle]; } + mbgl::gl::ProcAddress initializeExtension(const char* name) override { + static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengles")); + if (!framework) { + throw std::runtime_error("Failed to load OpenGL framework."); + } + + CFStringRef str = + CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingASCII); + void* symbol = CFBundleGetFunctionPointerForName(framework, str); + CFRelease(str); + + return reinterpret_cast(symbol); + } + void invalidate() override { [nativeView setNeedsGLDisplay]; diff --git a/platform/linux/src/headless_backend_egl.cpp b/platform/linux/src/headless_backend_egl.cpp index df0ecc8df..696fa3065 100644 --- a/platform/linux/src/headless_backend_egl.cpp +++ b/platform/linux/src/headless_backend_egl.cpp @@ -60,7 +60,7 @@ struct EGLImpl : public HeadlessBackend::Impl { EGLSurface glSurface = EGL_NO_SURFACE; }; -gl::glProc HeadlessBackend::initializeExtension(const char* name) { +gl::ProcAddress HeadlessBackend::initializeExtension(const char* name) { return eglGetProcAddress(name); } diff --git a/platform/linux/src/headless_backend_glx.cpp b/platform/linux/src/headless_backend_glx.cpp index 5791f1892..36a60ec06 100644 --- a/platform/linux/src/headless_backend_glx.cpp +++ b/platform/linux/src/headless_backend_glx.cpp @@ -44,7 +44,7 @@ struct GLXImpl : public HeadlessBackend::Impl { GLXFBConfig* fbConfigs = nullptr; }; -gl::glProc HeadlessBackend::initializeExtension(const char* name) { +gl::ProcAddress HeadlessBackend::initializeExtension(const char* name) { return glXGetProcAddress(reinterpret_cast(name)); } diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm index ef1c0f3bc..45ac7c535 100644 --- a/platform/macos/src/MGLMapView.mm +++ b/platform/macos/src/MGLMapView.mm @@ -26,7 +26,6 @@ #import #import #import -#import #import #import #import @@ -768,19 +767,6 @@ public: - (void)renderSync { if (!self.dormant) { - // Enable vertex buffer objects. - mbgl::gl::InitializeExtensions([](const char *name) { - static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl")); - if (!framework) { - throw std::runtime_error("Failed to load OpenGL framework."); - } - - CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingASCII); - void *symbol = CFBundleGetFunctionPointerForName(framework, str); - CFRelease(str); - - return reinterpret_cast(symbol); - }); // The OpenGL implementation automatically enables the OpenGL context for us. mbgl::BackendScope scope { *_mbglView, mbgl::BackendScope::ScopeType::Implicit }; @@ -2846,6 +2832,19 @@ public: [nativeView sourceDidChange]; } + mbgl::gl::ProcAddress initializeExtension(const char* name) override { + static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl")); + if (!framework) { + throw std::runtime_error("Failed to load OpenGL framework."); + } + + CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingASCII); + void *symbol = CFBundleGetFunctionPointerForName(framework, str); + CFRelease(str); + + return reinterpret_cast(symbol); + } + void invalidate() override { [nativeView setNeedsGLDisplay]; } diff --git a/platform/qt/app/mapwindow.cpp b/platform/qt/app/mapwindow.cpp index 926d50490..345c5196b 100644 --- a/platform/qt/app/mapwindow.cpp +++ b/platform/qt/app/mapwindow.cpp @@ -372,8 +372,6 @@ void MapWindow::wheelEvent(QWheelEvent *ev) void MapWindow::initializeGL() { - QMapbox::initializeGLExtensions(); - m_map.reset(new QMapboxGL(nullptr, m_settings, size(), pixelRatio())); connect(m_map.data(), SIGNAL(needsRendering()), this, SLOT(update())); diff --git a/platform/qt/include/qmapbox.hpp b/platform/qt/include/qmapbox.hpp index f2d96412a..e69b37108 100644 --- a/platform/qt/include/qmapbox.hpp +++ b/platform/qt/include/qmapbox.hpp @@ -97,8 +97,6 @@ typedef void (*CustomLayerInitializeFunction)(void* context) ; typedef void (*CustomLayerRenderFunction)(void* context, const CustomLayerRenderParameters&); typedef void (*CustomLayerDeinitializeFunction)(void* context); -Q_DECL_EXPORT void initializeGLExtensions(); - } // namespace QMapbox Q_DECLARE_METATYPE(QMapbox::Coordinate); diff --git a/platform/qt/src/qmapbox.cpp b/platform/qt/src/qmapbox.cpp index 126ece1ef..410e11469 100644 --- a/platform/qt/src/qmapbox.cpp +++ b/platform/qt/src/qmapbox.cpp @@ -1,6 +1,5 @@ #include "qmapbox.hpp" -#include #include #include #include @@ -255,26 +254,4 @@ Q_DECL_EXPORT QList >& defaultStyles() return styles; } -/*! - \fn void QMapbox::initializeGLExtensions() - - Initializes the OpenGL extensions such as Vertex Array Objects (VAOs), - required by Mapbox GL Native engine. - - Should be called only once, after an OpenGL context is available. - Consecutive calls are ignored. -*/ -Q_DECL_EXPORT void initializeGLExtensions() -{ - mbgl::gl::InitializeExtensions([](const char* name) { -#if QT_VERSION >= 0x050000 - QOpenGLContext* thisContext = QOpenGLContext::currentContext(); - return thisContext->getProcAddress(name); -#else - const QGLContext* thisContext = QGLContext::currentContext(); - return reinterpret_cast(thisContext->getProcAddress(name)); -#endif - }); -} - } // namespace QMapbox diff --git a/platform/qt/src/qmapboxgl.cpp b/platform/qt/src/qmapboxgl.cpp index 384bdc8eb..5776502a5 100644 --- a/platform/qt/src/qmapboxgl.cpp +++ b/platform/qt/src/qmapboxgl.cpp @@ -1678,6 +1678,20 @@ void QMapboxGLPrivate::onSourceChanged(mbgl::style::Source&) emit mapChanged(QMapboxGL::MapChangeSourceDidChange); } +/*! + Initializes an OpenGL extension function such as Vertex Array Objects (VAOs), + required by Mapbox GL Native engine. +*/ +mbgl::gl::ProcAddress QMapboxGLPrivate::initializeExtension(const char* name) { +#if QT_VERSION >= 0x050000 + QOpenGLContext* thisContext = QOpenGLContext::currentContext(); + return thisContext->getProcAddress(name); +#else + const QGLContext* thisContext = QGLContext::currentContext(); + return reinterpret_cast(thisContext->getProcAddress(name)); +#endif +} + void QMapboxGLPrivate::connectionEstablished() { mbgl::NetworkStatus::Reachable(); diff --git a/platform/qt/src/qmapboxgl_p.hpp b/platform/qt/src/qmapboxgl_p.hpp index 411254243..464b66bd7 100644 --- a/platform/qt/src/qmapboxgl_p.hpp +++ b/platform/qt/src/qmapboxgl_p.hpp @@ -58,6 +58,9 @@ public: bool dirty { false }; +private: + mbgl::gl::ProcAddress initializeExtension(const char*) override; + public slots: void connectionEstablished(); diff --git a/platform/qt/test/headless_backend_qt.cpp b/platform/qt/test/headless_backend_qt.cpp index 401ce55a7..5f95b2f96 100644 --- a/platform/qt/test/headless_backend_qt.cpp +++ b/platform/qt/test/headless_backend_qt.cpp @@ -24,13 +24,13 @@ struct QtImpl : public HeadlessBackend::Impl { QGLWidget widget; }; -gl::glProc HeadlessBackend::initializeExtension(const char* name) { +gl::ProcAddress HeadlessBackend::initializeExtension(const char* name) { #if QT_VERSION >= 0x050000 QOpenGLContext* thisContext = QOpenGLContext::currentContext(); return thisContext->getProcAddress(name); #else const QGLContext* thisContext = QGLContext::currentContext(); - return reinterpret_cast(thisContext->getProcAddress(name)); + return reinterpret_cast(thisContext->getProcAddress(name)); #endif } diff --git a/platform/qt/test/qmapboxgl.cpp b/platform/qt/test/qmapboxgl.cpp index 650c635b9..453604076 100644 --- a/platform/qt/test/qmapboxgl.cpp +++ b/platform/qt/test/qmapboxgl.cpp @@ -20,8 +20,6 @@ public: this, SLOT(onMapChanged(QMapboxGL::MapChange))); connect(&map, SIGNAL(needsRendering()), this, SLOT(onNeedsRendering())); - QMapbox::initializeGLExtensions(); - map.resize(fbo.size(), fbo.size()); map.setFramebufferObject(fbo.handle()); map.setCoordinateZoom(QMapbox::Coordinate(60.170448, 24.942046), 14); diff --git a/src/mbgl/gl/extension.cpp b/src/mbgl/gl/extension.cpp index e6b4d9156..41a5ea175 100644 --- a/src/mbgl/gl/extension.cpp +++ b/src/mbgl/gl/extension.cpp @@ -1,7 +1,6 @@ #include #include -#include #include #include #include @@ -11,7 +10,7 @@ namespace gl { namespace detail { using Probes = std::vector; -using ExtensionFunctions = std::vector>; +using ExtensionFunctions = std::vector>; ExtensionFunctions& extensionFunctions() { static ExtensionFunctions functions; return functions; @@ -23,22 +22,18 @@ ExtensionFunctionBase::ExtensionFunctionBase(std::initializer_list probes } // namespace detail -static std::once_flag initializeExtensionsOnce; - -void InitializeExtensions(glProc (*getProcAddress)(const char*)) { - std::call_once(initializeExtensionsOnce, [getProcAddress] { - if (const char* extensions = - reinterpret_cast(MBGL_CHECK_ERROR(glGetString(GL_EXTENSIONS)))) { - for (auto fn : detail::extensionFunctions()) { - for (auto probe : fn.second) { - if (strstr(extensions, probe.first) != nullptr) { - *fn.first = getProcAddress(probe.second); - break; - } +void initializeExtensions(const std::function& getProcAddress) { + if (const char* extensions = + reinterpret_cast(MBGL_CHECK_ERROR(glGetString(GL_EXTENSIONS)))) { + for (auto fn : detail::extensionFunctions()) { + for (auto probe : fn.second) { + if (strstr(extensions, probe.first) != nullptr) { + *fn.first = getProcAddress(probe.second); + break; } } } - }); + } } } // namespace gl diff --git a/src/mbgl/gl/extension.hpp b/src/mbgl/gl/extension.hpp index ea5a1ae5f..7d1d9a4d7 100644 --- a/src/mbgl/gl/extension.hpp +++ b/src/mbgl/gl/extension.hpp @@ -2,12 +2,13 @@ #include #include +#include namespace mbgl { namespace gl { -using glProc = void (*)(); -void InitializeExtensions(glProc (*getProcAddress)(const char*)); +using ProcAddress = void (*)(); +void initializeExtensions(const std::function&); namespace detail { @@ -15,7 +16,7 @@ class ExtensionFunctionBase { public: using Probe = std::pair; ExtensionFunctionBase(std::initializer_list); - glProc ptr; + ProcAddress ptr; }; } // namespace detail diff --git a/src/mbgl/map/backend.cpp b/src/mbgl/map/backend.cpp index a1a2f8f3a..29f7522e4 100644 --- a/src/mbgl/map/backend.cpp +++ b/src/mbgl/map/backend.cpp @@ -1,16 +1,23 @@ #include #include #include +#include +#include #include namespace mbgl { -Backend::Backend() : context(std::make_unique()) { -} +Backend::Backend() = default; gl::Context& Backend::getContext() { assert(BackendScope::exists()); + std::call_once(initialized, [this] { + context = std::make_unique(); + gl::debugging::enable(); + gl::initializeExtensions( + std::bind(&Backend::initializeExtension, this, std::placeholders::_1)); + }); return *context; } diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp index 754959438..73a084c8c 100644 --- a/src/mbgl/renderer/painter.cpp +++ b/src/mbgl/renderer/painter.cpp @@ -94,8 +94,6 @@ Painter::Painter(gl::Context& context_, tileBorderSegments.emplace_back(0, 0, 4, 5); rasterSegments.emplace_back(0, 0, 4, 6); - gl::debugging::enable(); - programs = std::make_unique(context, ProgramParameters{ pixelRatio, false, programCacheDir }); #ifndef NDEBUG