Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Commit

Permalink
[core] fold HeadlessDisplay into the headless RenderBackend implement…
Browse files Browse the repository at this point in the history
…ation
  • Loading branch information
kkaefer committed Nov 29, 2017
1 parent 772b909 commit 335f04f
Show file tree
Hide file tree
Showing 17 changed files with 285 additions and 442 deletions.
99 changes: 74 additions & 25 deletions platform/darwin/src/headless_backend_cgl.cpp
Original file line number Diff line number Diff line change
@@ -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>
Expand All @@ -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);
}

Expand All @@ -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.");
Expand All @@ -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
31 changes: 13 additions & 18 deletions platform/darwin/src/headless_backend_eagl.mm
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand All @@ -40,17 +43,9 @@ void deactivateContext() {
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
60 changes: 0 additions & 60 deletions platform/darwin/src/headless_display_cgl.cpp

This file was deleted.

29 changes: 12 additions & 17 deletions platform/default/headless_backend_osmesa.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,18 @@
namespace mbgl {

struct OSMesaImpl : public HeadlessBackend::Impl {
OSMesaImpl(OSMesaContext glContext_) : glContext(glContext_) {
OSMesaImpl() {
#if OSMESA_MAJOR_VERSION * 100 + OSMESA_MINOR_VERSION >= 305
glContext = OSMesaCreateContextExt(OSMESA_RGBA, 16, 0, 0, nullptr);
#else
glContext = OSMesaCreateContext(OSMESA_RGBA, nullptr);
#endif
if (glContext == nullptr) {
throw std::runtime_error("Error creating GL context object.");
}
}

~OSMesaImpl() {
~OSMesaImpl() final {
OSMesaDestroyContext(glContext);
}

Expand All @@ -21,6 +29,7 @@ struct OSMesaImpl : public HeadlessBackend::Impl {
}
}

private:
OSMesaContext glContext = nullptr;
GLubyte fakeBuffer = 0;
};
Expand All @@ -29,23 +38,9 @@ gl::ProcAddress HeadlessBackend::initializeExtension(const char* name) {
return OSMesaGetProcAddress(name);
}

bool HeadlessBackend::hasDisplay() {
return true;
};

void HeadlessBackend::createContext() {
assert(!hasContext());

#if OSMESA_MAJOR_VERSION * 100 + OSMESA_MINOR_VERSION >= 305
OSMesaContext glContext = OSMesaCreateContextExt(OSMESA_RGBA, 16, 0, 0, nullptr);
#else
OSMesaContext glContext = OSMesaCreateContext(OSMESA_RGBA, nullptr);
#endif
if (glContext == nullptr) {
throw std::runtime_error("Error creating GL context object.");
}

impl.reset(new OSMesaImpl(glContext));
impl = std::make_unique<OSMesaImpl>();
}

} // namespace mbgl
4 changes: 0 additions & 4 deletions platform/default/mbgl/gl/headless_backend.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#include <mbgl/gl/headless_backend.hpp>
#include <mbgl/gl/headless_display.hpp>
#include <mbgl/gl/context.hpp>
#include <mbgl/renderer/backend_scope.hpp>

Expand Down Expand Up @@ -36,9 +35,6 @@ void HeadlessBackend::activate() {
active = true;

if (!hasContext()) {
if (!hasDisplay()) {
throw std::runtime_error("Display is not set");
}
createContext();
}

Expand Down
4 changes: 0 additions & 4 deletions platform/default/mbgl/gl/headless_backend.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@

namespace mbgl {

class HeadlessDisplay;

class HeadlessBackend : public RendererBackend {
public:
HeadlessBackend(Size = { 256, 256 });
Expand All @@ -35,11 +33,9 @@ class HeadlessBackend : public RendererBackend {
void deactivate() override;

bool hasContext() const { return bool(impl); }
bool hasDisplay();

void createContext();

std::shared_ptr<HeadlessDisplay> display;
std::unique_ptr<Impl> impl;

Size size;
Expand Down
15 changes: 0 additions & 15 deletions platform/default/mbgl/gl/headless_display.cpp

This file was deleted.

34 changes: 0 additions & 34 deletions platform/default/mbgl/gl/headless_display.hpp

This file was deleted.

Loading

0 comments on commit 335f04f

Please sign in to comment.