-
-
Save tiagovignatti/7aaceebb220053bba7d171e4d8425d52 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
commit 23b366e4738a56b0fa9fc376f1241aec8f0c7cf4 | |
Author: Tiago Vignatti <[email protected]> | |
Date: Mon Aug 1 17:30:43 2016 +0300 | |
[linux] WIP: Implement EGL platform in for headless view | |
To call the X11 windowing system through GLX is superfluous for headless | |
rendering. This patch implements EGL platform using GBM, which should be | |
slightly more simple than the GLX. | |
TODO: | |
- Call two context in a row seems to be broken still. | |
- Remove GLX code all over | |
- Fix the remaining "XXX" in the code | |
--- | |
include/mbgl/platform/default/headless_display.hpp | 6 + | |
include/mbgl/platform/default/headless_view.hpp | 17 +++ | |
mbgl.gypi | 12 ++ | |
platform/default/headless_display.cpp | 50 +++++++++ | |
platform/default/headless_view_egl.cpp | 125 +++++++++++++++++++++ | |
platform/linux/platform.gyp | 2 +- | |
6 files changed, 211 insertions(+), 1 deletion(-) | |
diff --git a/include/mbgl/platform/default/headless_display.hpp b/include/mbgl/platform/default/headless_display.hpp | |
index edcc905..87b5f02 100644 | |
--- a/include/mbgl/platform/default/headless_display.hpp | |
+++ b/include/mbgl/platform/default/headless_display.hpp | |
@@ -13,6 +13,12 @@ public: | |
CGLPixelFormatObj pixelFormat = nullptr; | |
#endif | |
+#if MBGL_USE_EGL | |
+ int fd; | |
+ struct gbm_device *gbm = nullptr; | |
+ EGLDisplay dpy = 0; | |
+ EGLConfig config = 0; | |
+#endif | |
#if MBGL_USE_GLX | |
Display *xDisplay = nullptr; | |
GLXFBConfig *fbConfigs = nullptr; | |
diff --git a/include/mbgl/platform/default/headless_view.hpp b/include/mbgl/platform/default/headless_view.hpp | |
index e3acc8e..def927d 100644 | |
--- a/include/mbgl/platform/default/headless_view.hpp | |
+++ b/include/mbgl/platform/default/headless_view.hpp | |
@@ -8,6 +8,14 @@ | |
#define MBGL_USE_CGL 1 | |
#endif | |
#else | |
+#define MBGL_USE_EGL 1 | |
+struct gbm_surface {}; | |
+struct gbm_device {}; | |
+typedef void* EGLContext; | |
+typedef void* EGLDisplay; | |
+typedef void* EGLConfig; | |
+typedef void* EGLSurface; | |
+#if 0 | |
#define GL_GLEXT_PROTOTYPES | |
#define MBGL_USE_GLX 1 | |
typedef struct _XDisplay Display; | |
@@ -16,6 +24,7 @@ typedef struct __GLXFBConfigRec* GLXFBConfig; | |
typedef long unsigned int XID; | |
typedef XID GLXPbuffer; | |
#endif | |
+#endif | |
#include <mbgl/mbgl.hpp> | |
#include <mbgl/gl/gl.hpp> | |
@@ -71,6 +80,14 @@ private: | |
void *glContext = nullptr; | |
#endif | |
+#if MBGL_USE_EGL | |
+ EGLDisplay dpy; | |
+ EGLContext glContext = nullptr; | |
+ EGLConfig config; | |
+ EGLSurface surface; | |
+ struct gbm_surface *gs = nullptr; | |
+#endif | |
+ | |
#if MBGL_USE_GLX | |
Display *xDisplay = nullptr; | |
GLXFBConfig *fbConfigs = nullptr; | |
diff --git a/mbgl.gypi b/mbgl.gypi | |
index 7f31d46..64da35e 100644 | |
--- a/mbgl.gypi | |
+++ b/mbgl.gypi | |
@@ -264,6 +264,18 @@ | |
}, | |
}], | |
+ ['headless_lib == "egl"', { | |
+ 'sources': [ | |
+ 'platform/default/headless_display.cpp', | |
+ 'platform/default/headless_view.cpp', | |
+ 'platform/default/headless_view_egl.cpp', | |
+ ], | |
+ | |
+ 'link_settings': { | |
+ 'libraries': [ '-lGL -lEGL -lgbm -ldrm' ], | |
+ }, | |
+ }], | |
+ | |
['loop_lib == "darwin"', { | |
'sources': [ | |
'platform/darwin/src/async_task.cpp', | |
diff --git a/platform/default/headless_display.cpp b/platform/default/headless_display.cpp | |
index 8b9f3fe..20efbee 100644 | |
--- a/platform/default/headless_display.cpp | |
+++ b/platform/default/headless_display.cpp | |
@@ -3,12 +3,32 @@ | |
#include <cstring> | |
#include <stdexcept> | |
+#if MBGL_USE_EGL | |
+#include <EGL/egl.h> | |
+#include <fcntl.h> | |
+#include <gbm.h> | |
+#include <unistd.h> | |
+#endif | |
+ | |
#if MBGL_USE_GLX | |
#include <GL/glx.h> | |
#endif | |
namespace mbgl { | |
+#if MBGL_USE_EGL | |
+static const EGLint attribs[] = { | |
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT, | |
+ EGL_RED_SIZE, 1, | |
+ EGL_GREEN_SIZE, 1, | |
+ EGL_BLUE_SIZE, 1, | |
+ EGL_ALPHA_SIZE, 0, | |
+ EGL_DEPTH_SIZE, 1, | |
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, | |
+ EGL_NONE | |
+}; | |
+#endif | |
+ | |
HeadlessDisplay::HeadlessDisplay() { | |
#if MBGL_USE_CGL | |
// TODO: test if OpenGL 4.1 with GL_ARB_ES2_compatibility is supported | |
@@ -29,6 +49,32 @@ HeadlessDisplay::HeadlessDisplay() { | |
} | |
#endif | |
+#if MBGL_USE_EGL | |
+ /* XXX(vignatti): this code seems to leak everywhere */ | |
+ const char device_name[] = "/dev/dri/renderD128"; | |
+ fd = open(device_name, O_RDWR); | |
+ if (fd < 0) { | |
+ throw std::runtime_error("couldn't open drm device"); | |
+ } | |
+ | |
+ gbm = gbm_create_device(fd); | |
+ if (gbm == NULL) { | |
+ throw std::runtime_error("couldn't create gbm device"); | |
+ } | |
+ dpy = eglGetDisplay(reinterpret_cast<EGLNativeDisplayType>(gbm)); | |
+ if (dpy == EGL_NO_DISPLAY) { | |
+ throw std::runtime_error("eglGetDisplay() failed"); | |
+ } | |
+ EGLint major, minor, n; | |
+ if (!eglInitialize(dpy, &major, &minor)) { | |
+ throw std::runtime_error("eglInitialize() failed\n"); | |
+ } | |
+ eglBindAPI(EGL_OPENGL_API); | |
+ if (!eglChooseConfig(dpy, attribs, &config, 1, &n) || n != 1) { | |
+ throw std::runtime_error("failed to choose argb config\n"); | |
+ } | |
+#endif | |
+ | |
#if MBGL_USE_GLX | |
if (!XInitThreads()) { | |
throw std::runtime_error("Failed to XInitThreads."); | |
@@ -72,6 +118,10 @@ HeadlessDisplay::~HeadlessDisplay() { | |
CGLDestroyPixelFormat(pixelFormat); | |
#endif | |
+#if MBGL_USE_EGL | |
+ gbm_device_destroy(gbm); | |
+ close(fd); | |
+#endif | |
#if MBGL_USE_GLX | |
XFree(fbConfigs); | |
XCloseDisplay(xDisplay); | |
diff --git a/platform/default/headless_view_egl.cpp b/platform/default/headless_view_egl.cpp | |
new file mode 100644 | |
index 0000000..3eb749e | |
--- /dev/null | |
+++ b/platform/default/headless_view_egl.cpp | |
@@ -0,0 +1,125 @@ | |
+#include <mbgl/platform/default/headless_view.hpp> | |
+#include <mbgl/platform/default/headless_display.hpp> | |
+#include <mbgl/platform/log.hpp> | |
+ | |
+#include <cassert> | |
+ | |
+#include <GL/gl.h> | |
+#include <EGL/egl.h> | |
+#include <EGL/eglext.h> | |
+#include <gbm.h> | |
+ | |
+namespace mbgl { | |
+ | |
+gl::glProc HeadlessView::initializeExtension(const char* name) { | |
+ return eglGetProcAddress(name); | |
+} | |
+ | |
+void HeadlessView::createContext() { | |
+ dpy = display->dpy; | |
+ config = display->config; | |
+ | |
+ glContext = eglCreateContext(dpy, config, EGL_NO_CONTEXT, NULL); | |
+ if (glContext == NULL) { | |
+ throw std::runtime_error("Error creating GL context object."); | |
+ } | |
+ | |
+ /* XXX(vignatti): this size */ | |
+ gs = gbm_surface_create(display->gbm, 800, 600, | |
+ GBM_BO_FORMAT_XRGB8888, | |
+ GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); | |
+ if (gs == NULL) { | |
+ throw std::runtime_error("unable to create gbm surface\n"); | |
+ } | |
+ | |
+ surface = eglCreateWindowSurface(dpy, config, reinterpret_cast<EGLNativeWindowType>(gs), NULL); | |
+ if (surface == EGL_NO_SURFACE) { | |
+ throw std::runtime_error("failed to create surface\n"); | |
+ } | |
+} | |
+ | |
+void HeadlessView::destroyContext() { | |
+ eglDestroyContext(dpy, glContext); | |
+ | |
+ gbm_surface_destroy(gs); | |
+ if (surface) { | |
+ eglDestroySurface(dpy, surface); | |
+ surface = 0; | |
+ } | |
+} | |
+ | |
+void HeadlessView::resizeFramebuffer() { | |
+ const unsigned int w = dimensions[0] * pixelRatio; | |
+ const unsigned int h = dimensions[1] * pixelRatio; | |
+ | |
+ // Create depth/stencil buffer | |
+ MBGL_CHECK_ERROR(glGenRenderbuffersEXT(1, &fboDepthStencil)); | |
+ MBGL_CHECK_ERROR(glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fboDepthStencil)); | |
+ MBGL_CHECK_ERROR(glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, w, h)); | |
+ MBGL_CHECK_ERROR(glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0)); | |
+ | |
+ MBGL_CHECK_ERROR(glGenRenderbuffersEXT(1, &fboColor)); | |
+ MBGL_CHECK_ERROR(glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fboColor)); | |
+ MBGL_CHECK_ERROR(glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA8, w, h)); | |
+ MBGL_CHECK_ERROR(glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0)); | |
+ | |
+ MBGL_CHECK_ERROR(glGenFramebuffersEXT(1, &fbo)); | |
+ MBGL_CHECK_ERROR(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo)); | |
+ | |
+ MBGL_CHECK_ERROR(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, fboColor)); | |
+ MBGL_CHECK_ERROR(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER_EXT, fboDepthStencil)); | |
+ | |
+ GLenum status = MBGL_CHECK_ERROR(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT)); | |
+ | |
+ if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { | |
+ std::string error("Couldn't create framebuffer: "); | |
+ switch (status) { | |
+ case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: (error += "incomplete attachment"); break; | |
+ case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: error += "incomplete missing attachment"; break; | |
+ case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: error += "incomplete dimensions"; break; | |
+ case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: error += "incomplete formats"; break; | |
+ case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: error += "incomplete draw buffer"; break; | |
+ case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: error += "incomplete read buffer"; break; | |
+ case GL_FRAMEBUFFER_UNSUPPORTED: error += "unsupported"; break; | |
+ default: error += "other"; break; | |
+ } | |
+ throw std::runtime_error(error); | |
+ } | |
+ | |
+ MBGL_CHECK_ERROR(glViewport(0, 0, w, h)); | |
+} | |
+ | |
+void HeadlessView::clearBuffers() { | |
+ assert(active); | |
+ | |
+ MBGL_CHECK_ERROR(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)); | |
+ | |
+ if (fbo) { | |
+ MBGL_CHECK_ERROR(glDeleteFramebuffersEXT(1, &fbo)); | |
+ fbo = 0; | |
+ } | |
+ | |
+ if (fboColor) { | |
+ MBGL_CHECK_ERROR(glDeleteRenderbuffersEXT(1, &fboColor)); | |
+ fboColor = 0; | |
+ } | |
+ | |
+ if (fboDepthStencil) { | |
+ MBGL_CHECK_ERROR(glDeleteRenderbuffersEXT(1, &fboDepthStencil)); | |
+ fboDepthStencil = 0; | |
+ } | |
+} | |
+ | |
+void HeadlessView::activateContext() { | |
+ if (!eglMakeCurrent(dpy, surface, surface, glContext)) { | |
+ throw std::runtime_error("Switching OpenGL context failed.\n"); | |
+ } | |
+} | |
+ | |
+void HeadlessView::deactivateContext() { | |
+ if (!eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) { | |
+ throw std::runtime_error("Removing OpenGL context failed.\n"); | |
+ } | |
+} | |
+ | |
+} // namespace mbgl | |
diff --git a/platform/linux/platform.gyp b/platform/linux/platform.gyp | |
index 7adf533..7cf4652 100644 | |
--- a/platform/linux/platform.gyp | |
+++ b/platform/linux/platform.gyp | |
@@ -1,7 +1,7 @@ | |
{ | |
'variables': { | |
'loop_lib': 'uv', | |
- 'headless_lib': 'glx', | |
+ 'headless_lib': 'egl', | |
'coverage': '<!(echo $ENABLE_COVERAGE)>', | |
}, | |
'conditions': [ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment