diff options
Diffstat (limited to 'platform/darwin')
-rw-r--r-- | platform/darwin/src/headless_backend_cgl.cpp | 99 | ||||
-rw-r--r-- | platform/darwin/src/headless_backend_eagl.mm | 31 | ||||
-rw-r--r-- | platform/darwin/src/headless_display_cgl.cpp | 60 |
3 files changed, 87 insertions, 103 deletions
diff --git a/platform/darwin/src/headless_backend_cgl.cpp b/platform/darwin/src/headless_backend_cgl.cpp index 3b0c3aaf35..6e19213f52 100644 --- a/platform/darwin/src/headless_backend_cgl.cpp +++ b/platform/darwin/src/headless_backend_cgl.cpp @@ -1,5 +1,5 @@ #include <mbgl/gl/headless_backend.hpp> -#include <mbgl/gl/headless_display.hpp> +#include <mbgl/util/logging.hpp> #include <OpenGL/OpenGL.h> #include <CoreFoundation/CoreFoundation.h> @@ -9,11 +9,78 @@ namespace mbgl { +// This class provides a singleton that contains information about the pixel format used for +// instantiating new headless rendering contexts. +class CGLDisplayConfig { +private: + // Key for singleton construction. + struct Key { explicit Key() = default; }; + +public: + CGLDisplayConfig(Key) { + // TODO: test if OpenGL 4.1 with GL_ARB_ES2_compatibility is supported + // If it is, use kCGLOGLPVersion_3_2_Core and enable that extension. + CGLPixelFormatAttribute attributes[] = { + kCGLPFAOpenGLProfile, static_cast<CGLPixelFormatAttribute>(kCGLOGLPVersion_Legacy), + // Not adding kCGLPFAAccelerated, as this will make headless rendering impossible when running in VMs. + kCGLPFAClosestPolicy, + kCGLPFAAccumSize, static_cast<CGLPixelFormatAttribute>(32), + kCGLPFAColorSize, static_cast<CGLPixelFormatAttribute>(24), + kCGLPFAAlphaSize, static_cast<CGLPixelFormatAttribute>(8), + kCGLPFADepthSize, static_cast<CGLPixelFormatAttribute>(16), + kCGLPFAStencilSize, static_cast<CGLPixelFormatAttribute>(8), + kCGLPFASupportsAutomaticGraphicsSwitching, + kCGLPFAAllowOfflineRenderers, // Allows using the integrated GPU + static_cast<CGLPixelFormatAttribute>(0) + }; + + GLint num; + // TODO: obtain all configurations and choose the best one. + const CGLError error = CGLChoosePixelFormat(attributes, &pixelFormat, &num); + if (error != kCGLNoError) { + throw std::runtime_error(std::string("Error choosing pixel format:") + CGLErrorString(error) + "\n"); + } + if (num <= 0) { + throw std::runtime_error("No pixel formats found."); + } + } + + ~CGLDisplayConfig() { + const CGLError error = CGLDestroyPixelFormat(pixelFormat); + if (error != kCGLNoError) { + Log::Error(Event::OpenGL, std::string("Error destroying pixel format:") + CGLErrorString(error)); + } + } + + static std::shared_ptr<const CGLDisplayConfig> create() { + static std::weak_ptr<const CGLDisplayConfig> instance; + auto shared = instance.lock(); + if (!shared) { + instance = shared = std::make_shared<CGLDisplayConfig>(Key{}); + } + return shared; + } + +public: + CGLPixelFormatObj pixelFormat = nullptr; +}; + struct CGLImpl : public HeadlessBackend::Impl { - CGLImpl(CGLContextObj glContext_) : glContext(glContext_) { + CGLImpl() { + CGLError error = CGLCreateContext(cglDisplay->pixelFormat, nullptr, &glContext); + if (error != kCGLNoError) { + throw std::runtime_error(std::string("Error creating GL context object:") + + CGLErrorString(error) + "\n"); + } + + error = CGLEnable(glContext, kCGLCEMPEngine); + if (error != kCGLNoError) { + throw std::runtime_error(std::string("Error enabling OpenGL multithreading:") + + CGLErrorString(error) + "\n"); + } } - ~CGLImpl() { + ~CGLImpl() final { CGLDestroyContext(glContext); } @@ -33,10 +100,13 @@ struct CGLImpl : public HeadlessBackend::Impl { } } +private: + const std::shared_ptr<const CGLDisplayConfig> cglDisplay = CGLDisplayConfig::create(); CGLContextObj glContext = nullptr; }; gl::ProcAddress HeadlessBackend::initializeExtension(const char* name) { + assert(hasContext()); static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl")); if (!framework) { throw std::runtime_error("Failed to load OpenGL framework."); @@ -49,30 +119,9 @@ gl::ProcAddress HeadlessBackend::initializeExtension(const char* name) { return reinterpret_cast<gl::ProcAddress>(symbol); } -bool HeadlessBackend::hasDisplay() { - if (!display) { - display = HeadlessDisplay::create(); - } - return bool(display); -} - void HeadlessBackend::createContext() { assert(!hasContext()); - - CGLContextObj glContext = nullptr; - CGLError error = CGLCreateContext(display->attribute<CGLPixelFormatObj>(), nullptr, &glContext); - if (error != kCGLNoError) { - throw std::runtime_error(std::string("Error creating GL context object:") + - CGLErrorString(error) + "\n"); - } - - error = CGLEnable(glContext, kCGLCEMPEngine); - if (error != kCGLNoError) { - throw std::runtime_error(std::string("Error enabling OpenGL multithreading:") + - CGLErrorString(error) + "\n"); - } - - impl.reset(new CGLImpl(glContext)); + impl = std::make_unique<CGLImpl>(); } } // namespace mbgl diff --git a/platform/darwin/src/headless_backend_eagl.mm b/platform/darwin/src/headless_backend_eagl.mm index 1daaeaf54c..6bf5787f60 100644 --- a/platform/darwin/src/headless_backend_eagl.mm +++ b/platform/darwin/src/headless_backend_eagl.mm @@ -7,23 +7,26 @@ namespace mbgl { struct EAGLImpl : public HeadlessBackend::Impl { - EAGLImpl(EAGLContext* glContext_) : glContext(glContext_) { - [reinterpret_cast<EAGLContext*>(glContext) retain]; - reinterpret_cast<EAGLContext*>(glContext).multiThreaded = YES; + EAGLImpl() { + glContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; + if (glContext == nil) { + throw std::runtime_error("Error creating GL context object"); + } + glContext.multiThreaded = YES; } - ~EAGLImpl() { - [glContext release]; - } + // Required for ARC to deallocate correctly. + ~EAGLImpl() final = default; - void activateContext() { + void activateContext() final { [EAGLContext setCurrentContext:glContext]; } - void deactivateContext() { + void deactivateContext() final { [EAGLContext setCurrentContext:nil]; } +private: EAGLContext* glContext = nullptr; }; @@ -40,17 +43,9 @@ gl::ProcAddress HeadlessBackend::initializeExtension(const char* name) { return reinterpret_cast<gl::ProcAddress>(symbol); } -bool HeadlessBackend::hasDisplay() { - return true; -} - void HeadlessBackend::createContext() { - EAGLContext* glContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; - if (glContext == nil) { - throw std::runtime_error("Error creating GL context object"); - } - - impl.reset(new EAGLImpl(glContext)); + assert(!hasContext()); + impl = std::make_unique<EAGLImpl>(); } } // namespace mbgl diff --git a/platform/darwin/src/headless_display_cgl.cpp b/platform/darwin/src/headless_display_cgl.cpp deleted file mode 100644 index 5b7a1f2bac..0000000000 --- a/platform/darwin/src/headless_display_cgl.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include <mbgl/gl/headless_display.hpp> - -#include <OpenGL/OpenGL.h> - -#include <stdexcept> -#include <string> - -namespace mbgl { - -class HeadlessDisplay::Impl { -public: - Impl(); - ~Impl(); - CGLPixelFormatObj pixelFormat = nullptr; -}; - -HeadlessDisplay::Impl::Impl() { - // TODO: test if OpenGL 4.1 with GL_ARB_ES2_compatibility is supported - // If it is, use kCGLOGLPVersion_3_2_Core and enable that extension. - CGLPixelFormatAttribute attributes[] = { - kCGLPFAOpenGLProfile, static_cast<CGLPixelFormatAttribute>(kCGLOGLPVersion_Legacy), - // Not adding kCGLPFAAccelerated, as this will make headless rendering impossible when running in VMs. - kCGLPFAClosestPolicy, - kCGLPFAAccumSize, static_cast<CGLPixelFormatAttribute>(32), - kCGLPFAColorSize, static_cast<CGLPixelFormatAttribute>(24), - kCGLPFAAlphaSize, static_cast<CGLPixelFormatAttribute>(8), - kCGLPFADepthSize, static_cast<CGLPixelFormatAttribute>(16), - kCGLPFAStencilSize, static_cast<CGLPixelFormatAttribute>(8), - kCGLPFASupportsAutomaticGraphicsSwitching, - kCGLPFAAllowOfflineRenderers, // Allows using the integrated GPU - static_cast<CGLPixelFormatAttribute>(0) - }; - - GLint num; - CGLError error = CGLChoosePixelFormat(attributes, &pixelFormat, &num); - if (error != kCGLNoError) { - throw std::runtime_error(std::string("Error choosing pixel format:") + CGLErrorString(error) + "\n"); - } - if (num <= 0) { - throw std::runtime_error("No pixel formats found."); - } -} - -HeadlessDisplay::Impl::~Impl() { - CGLDestroyPixelFormat(pixelFormat); -} - -template <> -CGLPixelFormatObj HeadlessDisplay::attribute() const { - return impl->pixelFormat; -} - -HeadlessDisplay::HeadlessDisplay() - : impl(std::make_unique<Impl>()) { -} - -HeadlessDisplay::~HeadlessDisplay() { -} - -} // namespace mbgl |