[core] move HeadlessBackend extension initialization code into Impl

This commit is contained in:
Konstantin Käfer
2017-11-27 17:25:20 +01:00
parent 335f04f7e1
commit 2eec5a1980
20 changed files with 117 additions and 120 deletions

View File

@@ -41,7 +41,7 @@ protected:
// Called with the name of an OpenGL extension that should be loaded. RendererBackend 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;
virtual gl::ProcAddress getExtensionFunctionPointer(const char*) = 0;
// Called when the backend's GL context needs to be made active or inactive. These are called,
// as a matched pair, exclusively through BackendScope, in two situations:

View File

@@ -66,7 +66,6 @@ macro(mbgl_platform_core)
PRIVATE platform/default/mbgl/map/map_snapshotter.cpp
PRIVATE platform/default/mbgl/map/map_snapshotter.hpp
PRIVATE platform/linux/src/headless_backend_egl.cpp
PRIVATE platform/linux/src/headless_display_egl.cpp
)
target_include_directories(mbgl-core
@@ -341,15 +340,6 @@ macro(mbgl_platform_test)
# Main test entry point
platform/android/src/test/main.jni.cpp
# Headless view
platform/default/mbgl/gl/headless_frontend.cpp
platform/default/mbgl/gl/headless_frontend.hpp
platform/default/mbgl/gl/headless_backend.cpp
platform/default/mbgl/gl/headless_backend.hpp
platform/linux/src/headless_backend_egl.cpp
platform/linux/src/headless_display_egl.cpp
)
target_include_directories(mbgl-test

View File

@@ -21,7 +21,7 @@ void AndroidRendererBackend::bind() {
/**
* From mbgl::RendererBackend.
*/
gl::ProcAddress AndroidRendererBackend::initializeExtension(const char* name) {
gl::ProcAddress AndroidRendererBackend::getExtensionFunctionPointer(const char* name) {
assert(BackendScope::exists());
return eglGetProcAddress(name);
}

View File

@@ -24,7 +24,7 @@ public:
protected:
// mbgl::RendererBackend //
gl::ProcAddress initializeExtension(const char*) override;
gl::ProcAddress getExtensionFunctionPointer(const char*) override;
void activate() override {};
void deactivate() override {};

View File

@@ -65,8 +65,9 @@ public:
CGLPixelFormatObj pixelFormat = nullptr;
};
struct CGLImpl : public HeadlessBackend::Impl {
CGLImpl() {
class CGLBackendImpl : public HeadlessBackend::Impl {
public:
CGLBackendImpl() {
CGLError error = CGLCreateContext(cglDisplay->pixelFormat, nullptr, &glContext);
if (error != kCGLNoError) {
throw std::runtime_error(std::string("Error creating GL context object:") +
@@ -80,10 +81,24 @@ struct CGLImpl : public HeadlessBackend::Impl {
}
}
~CGLImpl() final {
~CGLBackendImpl() final {
CGLDestroyContext(glContext);
}
gl::ProcAddress getExtensionFunctionPointer(const char* name) final {
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<gl::ProcAddress>(symbol);
}
void activateContext() final {
CGLError error = CGLSetCurrentContext(glContext);
if (error != kCGLNoError) {
@@ -105,23 +120,9 @@ private:
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.");
}
CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingASCII);
void* symbol = CFBundleGetFunctionPointerForName(framework, str);
CFRelease(str);
return reinterpret_cast<gl::ProcAddress>(symbol);
}
void HeadlessBackend::createContext() {
assert(!hasContext());
impl = std::make_unique<CGLImpl>();
void HeadlessBackend::createImpl() {
assert(!impl);
impl = std::make_unique<CGLBackendImpl>();
}
} // namespace mbgl

View File

@@ -6,8 +6,9 @@
namespace mbgl {
struct EAGLImpl : public HeadlessBackend::Impl {
EAGLImpl() {
class EAGLBackendImpl : public HeadlessBackend::Impl {
public:
EAGLBackendImpl() {
glContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
if (glContext == nil) {
throw std::runtime_error("Error creating GL context object");
@@ -16,7 +17,21 @@ struct EAGLImpl : public HeadlessBackend::Impl {
}
// Required for ARC to deallocate correctly.
~EAGLImpl() final = default;
~EAGLBackendImpl() final = default;
gl::ProcAddress getExtensionFunctionPointer(const char* name) final {
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<gl::ProcAddress>(symbol);
}
void activateContext() final {
[EAGLContext setCurrentContext:glContext];
@@ -30,22 +45,9 @@ private:
EAGLContext* glContext = nullptr;
};
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.");
}
CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingASCII);
void* symbol = CFBundleGetFunctionPointerForName(framework, str);
CFRelease(str);
return reinterpret_cast<gl::ProcAddress>(symbol);
}
void HeadlessBackend::createContext() {
assert(!hasContext());
impl = std::make_unique<EAGLImpl>();
void HeadlessBackend::createImpl() {
assert(!impl);
impl = std::make_unique<EAGLBackendImpl>();
}
} // namespace mbgl

View File

@@ -7,8 +7,9 @@
namespace mbgl {
struct OSMesaImpl : public HeadlessBackend::Impl {
OSMesaImpl() {
class OSMesaBackendImpl : public HeadlessBackend::Impl {
public:
OSMesaBackendImpl() {
#if OSMESA_MAJOR_VERSION * 100 + OSMESA_MINOR_VERSION >= 305
glContext = OSMesaCreateContextExt(OSMESA_RGBA, 16, 0, 0, nullptr);
#else
@@ -19,10 +20,14 @@ struct OSMesaImpl : public HeadlessBackend::Impl {
}
}
~OSMesaImpl() final {
~OSMesaBackendImpl() final {
OSMesaDestroyContext(glContext);
}
gl::ProcAddress getExtensionFunctionPointer(const char* name) final {
return OSMesaGetProcAddress(name);
}
void activateContext() final {
if (!OSMesaMakeCurrent(glContext, &fakeBuffer, GL_UNSIGNED_BYTE, 1, 1)) {
throw std::runtime_error("Switching OpenGL context failed.\n");
@@ -34,13 +39,9 @@ private:
GLubyte fakeBuffer = 0;
};
gl::ProcAddress HeadlessBackend::initializeExtension(const char* name) {
return OSMesaGetProcAddress(name);
}
void HeadlessBackend::createContext() {
assert(!hasContext());
impl = std::make_unique<OSMesaImpl>();
void HeadlessBackend::createImpl() {
assert(!impl);
impl = std::make_unique<OSMesaBackendImpl>();
}
} // namespace mbgl

View File

@@ -31,19 +31,24 @@ HeadlessBackend::~HeadlessBackend() {
context.reset();
}
gl::ProcAddress HeadlessBackend::getExtensionFunctionPointer(const char* name) {
assert(impl);
return impl->getExtensionFunctionPointer(name);
}
void HeadlessBackend::activate() {
active = true;
if (!hasContext()) {
createContext();
if (!impl) {
createImpl();
}
assert(hasContext());
assert(impl);
impl->activateContext();
}
void HeadlessBackend::deactivate() {
assert(hasContext());
assert(impl);
impl->deactivateContext();
active = false;
}

View File

@@ -19,23 +19,24 @@ public:
void setSize(Size);
PremultipliedImage readStillImage();
struct Impl {
class Impl {
public:
virtual ~Impl() = default;
virtual gl::ProcAddress getExtensionFunctionPointer(const char*) = 0;
virtual void activateContext() = 0;
virtual void deactivateContext() {}
};
private:
// Implementation specific functions
gl::ProcAddress initializeExtension(const char*) override;
gl::ProcAddress getExtensionFunctionPointer(const char*) override;
void activate() override;
void deactivate() override;
bool hasContext() const { return bool(impl); }
void createContext();
void createImpl();
private:
std::unique_ptr<Impl> impl;
Size size;

View File

@@ -540,7 +540,7 @@ mbgl::Size GLFWView::getFramebufferSize() const {
return { static_cast<uint32_t>(fbWidth), static_cast<uint32_t>(fbHeight) };
}
mbgl::gl::ProcAddress GLFWView::initializeExtension(const char* name) {
mbgl::gl::ProcAddress GLFWView::getExtensionFunctionPointer(const char* name) {
return glfwGetProcAddress(name);
}

View File

@@ -52,7 +52,7 @@ public:
protected:
// mbgl::Backend implementation
mbgl::gl::ProcAddress initializeExtension(const char*) override;
mbgl::gl::ProcAddress getExtensionFunctionPointer(const char*) override;
void activate() override;
void deactivate() override;

View File

@@ -6031,7 +6031,7 @@ public:
[nativeView didFinishLoadingStyle];
}
mbgl::gl::ProcAddress initializeExtension(const char* name) override {
mbgl::gl::ProcAddress getExtensionFunctionPointer(const char* name) override {
static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengles"));
if (!framework) {
throw std::runtime_error("Failed to load OpenGL framework.");

View File

@@ -66,8 +66,9 @@ public:
EGLConfig config = 0;
};
struct EGLImpl : public HeadlessBackend::Impl {
EGLImpl() {
class EGLBackendImpl : public HeadlessBackend::Impl {
public:
EGLBackendImpl() {
// EGL initializes the context client version to 1 by default. We want to
// use OpenGL ES 2.0 which has the ability to create shader and program
// objects and also to write vertex and fragment shaders in the OpenGL ES
@@ -101,7 +102,7 @@ struct EGLImpl : public HeadlessBackend::Impl {
}
}
~EGLImpl() final {
~EGLBackendImpl() final {
if (eglSurface != EGL_NO_SURFACE) {
if (!eglDestroySurface(eglDisplay->display, eglSurface)) {
Log::Error(Event::OpenGL, "Failed to destroy EGL surface.");
@@ -113,6 +114,10 @@ struct EGLImpl : public HeadlessBackend::Impl {
}
}
gl::ProcAddress getExtensionFunctionPointer(const char* name) final {
return eglGetProcAddress(name);
}
void activateContext() final {
if (!eglMakeCurrent(eglDisplay->display, eglSurface, eglSurface, eglContext)) {
throw std::runtime_error("Switching OpenGL context failed.\n");
@@ -131,13 +136,9 @@ private:
EGLSurface eglSurface = EGL_NO_SURFACE;
};
gl::ProcAddress HeadlessBackend::initializeExtension(const char* name) {
return eglGetProcAddress(name);
}
void HeadlessBackend::createContext() {
assert(!hasContext());
impl = std::make_unique<EGLImpl>();
void HeadlessBackend::createImpl() {
assert(!impl);
impl = std::make_unique<EGLBackendImpl>();
}
} // namespace mbgl

View File

@@ -70,8 +70,9 @@ public:
GLXFBConfig* fbConfigs = nullptr;
};
struct GLXImpl : public HeadlessBackend::Impl {
GLXImpl() {
class GLXBackendImpl : public HeadlessBackend::Impl {
public:
GLXBackendImpl() {
// Try to create a legacy context.
glContext = glXCreateNewContext(glxDisplay->xDisplay, glxDisplay->fbConfigs[0],
GLX_RGBA_TYPE, None, True);
@@ -91,13 +92,17 @@ struct GLXImpl : public HeadlessBackend::Impl {
glXCreatePbuffer(glxDisplay->xDisplay, glxDisplay->fbConfigs[0], pbufferAttributes);
}
~GLXImpl() final {
~GLXBackendImpl() final {
if (glxPbuffer) {
glXDestroyPbuffer(glxDisplay->xDisplay, glxPbuffer);
}
glXDestroyContext(glxDisplay->xDisplay, glContext);
}
gl::ProcAddress getExtensionFunctionPointer(const char* name) final {
return glXGetProcAddress(reinterpret_cast<const GLubyte*>(name));
}
void activateContext() final {
if (!glXMakeContextCurrent(glxDisplay->xDisplay, glxPbuffer, glxPbuffer, glContext)) {
throw std::runtime_error("Switching OpenGL context failed.\n");
@@ -117,13 +122,9 @@ private:
GLXPbuffer glxPbuffer = 0;
};
gl::ProcAddress HeadlessBackend::initializeExtension(const char* name) {
return glXGetProcAddress(reinterpret_cast<const GLubyte*>(name));
}
void HeadlessBackend::createContext() {
assert(!hasContext());
impl = std::make_unique<GLXImpl>();
void HeadlessBackend::createImpl() {
assert(!impl);
impl = std::make_unique<GLXBackendImpl>();
}
} // namespace mbgl

View File

@@ -2887,7 +2887,7 @@ public:
[nativeView sourceDidChange:nativeSource];
}
mbgl::gl::ProcAddress initializeExtension(const char* name) override {
mbgl::gl::ProcAddress getExtensionFunctionPointer(const char* name) override {
static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
if (!framework) {
throw std::runtime_error("Failed to load OpenGL framework.");

View File

@@ -12,9 +12,19 @@
namespace mbgl {
class QtImpl : public HeadlessBackend::Impl {
class QtBackendImpl : public HeadlessBackend::Impl {
public:
~QtImpl() final = default;
~QtBackendImpl() final = default;
gl::ProcAddress getExtensionFunctionPointer(const char* name) final {
#if QT_VERSION >= 0x050000
QOpenGLContext* thisContext = QOpenGLContext::currentContext();
return thisContext->getProcAddress(name);
#else
const QGLContext* thisContext = QGLContext::currentContext();
return reinterpret_cast<gl::ProcAddress>(thisContext->getProcAddress(name));
#endif
}
void activateContext() final {
widget.makeCurrent();
@@ -28,19 +38,9 @@ private:
QGLWidget widget;
};
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<gl::ProcAddress>(thisContext->getProcAddress(name));
#endif
}
void HeadlessBackend::createContext() {
assert(!hasContext());
impl = std::make_unique<QtImpl>();
void HeadlessBackend::createImpl() {
assert(!impl);
impl = std::make_unique<QtBackendImpl>();
}
} // namespace mbgl

View File

@@ -1695,7 +1695,7 @@ void QMapboxGLPrivate::onSourceChanged(mbgl::style::Source&)
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) {
mbgl::gl::ProcAddress QMapboxGLPrivate::getExtensionFunctionPointer(const char* name) {
#if QT_VERSION >= 0x050000
QOpenGLContext* thisContext = QOpenGLContext::currentContext();
return thisContext->getProcAddress(name);

View File

@@ -61,7 +61,7 @@ public:
bool dirty { false };
private:
mbgl::gl::ProcAddress initializeExtension(const char*) override;
mbgl::gl::ProcAddress getExtensionFunctionPointer(const char*) override;
public slots:
void connectionEstablished();

View File

@@ -16,7 +16,7 @@ gl::Context& RendererBackend::getContext() {
context = std::make_unique<gl::Context>();
context->enableDebugging();
context->initializeExtensions(
std::bind(&RendererBackend::initializeExtension, this, std::placeholders::_1));
std::bind(&RendererBackend::getExtensionFunctionPointer, this, std::placeholders::_1));
});
return *context;
}

View File

@@ -28,18 +28,13 @@ public:
if (updateAssumedStateFunction) updateAssumedStateFunction();
}
gl::ProcAddress initializeExtension(const char* ext) override {
if (initializeExtensionFunction) {
return initializeExtensionFunction(ext);
} else {
return {};
}
gl::ProcAddress getExtensionFunctionPointer(const char*) override {
return {};
}
std::function<void ()> activateFunction;
std::function<void ()> deactivateFunction;
std::function<void ()> updateAssumedStateFunction;
std::function<gl::ProcAddress (const char*)> initializeExtensionFunction;
};
// A scope should activate on construction