From 2233f981fb49f6cd000979bea01a483f1abd25bf Mon Sep 17 00:00:00 2001 From: Mike Morris Date: Tue, 26 Aug 2014 17:09:32 -0400 Subject: port curl_request to libuv 0.10.x --- common/curl_request.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'common') diff --git a/common/curl_request.cpp b/common/curl_request.cpp index 416ed90cd1..3370c0a859 100644 --- a/common/curl_request.cpp +++ b/common/curl_request.cpp @@ -216,7 +216,7 @@ int handle_socket(CURL * /*easy*/, curl_socket_t s, int action, void * /*userp*/ return 0; } -void on_timeout(uv_timer_t * /*req*/) { +void on_timeout(uv_timer_t *, int status /*req*/) { int running_handles; CURLMcode error = curl_multi_socket_action(curl_multi, CURL_SOCKET_TIMEOUT, 0, &running_handles); @@ -227,9 +227,9 @@ void on_timeout(uv_timer_t * /*req*/) { void start_timeout(CURLM * /*multi*/, long timeout_ms, void * /*userp*/) { if (timeout_ms <= 0) { - on_timeout(&timeout); + on_timeout(&timeout, -1); } else { - uv_timer_start(&timeout, on_timeout, timeout_ms, 0); + uv_timer_start(&timeout, &on_timeout, timeout_ms, 0); } } @@ -289,7 +289,7 @@ size_t curl_write_cb(void *contents, size_t size, size_t nmemb, void *userp) { // This callback is called in the request event loop (on the request thread). // It initializes newly queued up download requests and adds them to the CURL // multi handle. -void async_add_cb(uv_async_t * /*async*/) { +void async_add_cb(uv_async_t *, int status /*async*/) { std::shared_ptr *req = nullptr; while (add_queue.pop(req)) { // Make sure that we're not starting requests that have been cancelled @@ -321,7 +321,7 @@ void async_add_cb(uv_async_t * /*async*/) { } } -void async_cancel_cb(uv_async_t * /*async*/) { +void async_cancel_cb(uv_async_t *, int status /*async*/) { std::shared_ptr *req = nullptr; while (cancel_queue.pop(req)) { // It is possible that the request has not yet been started, but that it already has been @@ -343,8 +343,8 @@ void thread_init_cb() { curl_global_init(CURL_GLOBAL_ALL); loop = uv_loop_new(); - uv_async_init(loop, &async_add, async_add_cb); - uv_async_init(loop, &async_cancel, async_cancel_cb); + uv_async_init(loop, &async_add, &async_add_cb); + uv_async_init(loop, &async_cancel, &async_cancel_cb); uv_thread_create(&thread, thread_init, nullptr); } } // end namespace request -- cgit v1.2.1 From 4316d2c40585e3d0dcdb25fa6f2341531025e20e Mon Sep 17 00:00:00 2001 From: Mike Morris Date: Wed, 10 Sep 2014 14:24:29 -0400 Subject: make context active before clearing buffers --- common/headless_view.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'common') diff --git a/common/headless_view.cpp b/common/headless_view.cpp index f790d90cec..0fce223986 100644 --- a/common/headless_view.cpp +++ b/common/headless_view.cpp @@ -113,6 +113,8 @@ void HeadlessView::resize(int width, int height) { } void HeadlessView::clear_buffers() { + make_active(); + #if MBGL_USE_CGL glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); -- cgit v1.2.1 From c004c036964e9012b08aa4a2f8b16094630d62be Mon Sep 17 00:00:00 2001 From: Leith Bade Date: Tue, 24 Jun 2014 00:25:20 +1000 Subject: Add View::make_inactive() to remove context from rendering thread View::make_inactive() is called just before termination of the rendering thread. The implementation must clear the thread's GL context. This ensures there is no context still bound to a thread during GL shutdown. This is needed as GL will not actually delete a context until it is not active on any thread. Fixes mapbox/mapbox-gl-native#340 Conflicts: common/glfw_view.hpp include/llmr/map/view.hpp test/headless.cpp --- common/glfw_view.cpp | 4 ++++ common/glfw_view.hpp | 1 + common/headless_view.cpp | 13 +++++++++++++ common/headless_view.hpp | 1 + 4 files changed, 19 insertions(+) (limited to 'common') diff --git a/common/glfw_view.cpp b/common/glfw_view.cpp index f53090a000..724b8bf180 100644 --- a/common/glfw_view.cpp +++ b/common/glfw_view.cpp @@ -192,6 +192,10 @@ void GLFWView::make_active() { glfwMakeContextCurrent(window); } +void GLFWView::make_inactive() { + glfwMakeContextCurrent(nullptr); +} + void GLFWView::swap() { glfwPostEmptyEvent(); diff --git a/common/glfw_view.hpp b/common/glfw_view.hpp index d2f6872fc7..04085f7750 100644 --- a/common/glfw_view.hpp +++ b/common/glfw_view.hpp @@ -17,6 +17,7 @@ public: void initialize(mbgl::Map *map); void swap(); void make_active(); + void make_inactive(); void notify_map_change(mbgl::MapChange change, mbgl::timestamp delay = 0); static void key(GLFWwindow *window, int key, int scancode, int action, int mods); diff --git a/common/headless_view.cpp b/common/headless_view.cpp index f790d90cec..34326ae29c 100644 --- a/common/headless_view.cpp +++ b/common/headless_view.cpp @@ -179,6 +179,19 @@ void HeadlessView::make_active() { #endif } +void HeadlessView::make_inactive() { +#if MBGL_USE_CGL + CGLError error = CGLSetCurrentContext(nullptr); + if (error) { + fprintf(stderr, "Removing OpenGL context failed\n"); + } +#endif + +#if MBGL_USE_GLX + // no-op +#endif +} + void HeadlessView::swap() {} unsigned int HeadlessView::root_fbo() { diff --git a/common/headless_view.hpp b/common/headless_view.hpp index 0b255b4a38..a4432bbae3 100644 --- a/common/headless_view.hpp +++ b/common/headless_view.hpp @@ -23,6 +23,7 @@ public: void notify_map_change(MapChange change, timestamp delay = 0); void make_active(); + void make_inactive(); void swap(); unsigned int root_fbo(); -- cgit v1.2.1 From 71549e7b93b6b44ed38e8915d8735c136889c3f1 Mon Sep 17 00:00:00 2001 From: Leith Bade Date: Tue, 24 Jun 2014 00:41:28 +1000 Subject: Adds the function Map::terminate() to allow all GL resources held by the map to be released immediately. Map::terminate() will call any GL functions on the current thread without blocking or defering to the rendering thread. This function allows a GL context to be destroyed and recreated safely without having to delete the Map object. Fixes mapbox/mapbox-gl-native#341 Conflicts: include/llmr/renderer/painter.hpp test/headless.cpp --- common/glfw_view.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'common') diff --git a/common/glfw_view.cpp b/common/glfw_view.cpp index 724b8bf180..0908786bb6 100644 --- a/common/glfw_view.cpp +++ b/common/glfw_view.cpp @@ -8,7 +8,10 @@ GLFWView::GLFWView(bool fullscreen) : fullscreen(fullscreen) { #endif } -GLFWView::~GLFWView() { glfwTerminate(); } +GLFWView::~GLFWView() { + map->terminate(); + glfwTerminate(); +} void GLFWView::initialize(mbgl::Map *map) { View::initialize(map); -- cgit v1.2.1 From d9ccc501c3d61f928479faf78ee21eb81b8cbdf3 Mon Sep 17 00:00:00 2001 From: Mike Morris Date: Wed, 10 Sep 2014 19:42:06 -0400 Subject: add GLX support to HeadlessView::make_inactive --- common/headless_view.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'common') diff --git a/common/headless_view.cpp b/common/headless_view.cpp index 0b4d7ce64a..9fa75700ae 100644 --- a/common/headless_view.cpp +++ b/common/headless_view.cpp @@ -190,7 +190,9 @@ void HeadlessView::make_inactive() { #endif #if MBGL_USE_GLX - // no-op + if (!glXMakeCurrent(x_display, None, nullptr)) { + fprintf(stderr, "Removing OpenGL context failed\n"); + } #endif } -- cgit v1.2.1 From f93a230e977522eba42046a2f6511cb776861aa7 Mon Sep 17 00:00:00 2001 From: Mike Morris Date: Thu, 11 Sep 2014 09:48:12 -0400 Subject: drop clear_buffers and glx make_inactive from descrtuctor --- common/headless_view.cpp | 3 --- 1 file changed, 3 deletions(-) (limited to 'common') diff --git a/common/headless_view.cpp b/common/headless_view.cpp index 9fa75700ae..ff903939b7 100644 --- a/common/headless_view.cpp +++ b/common/headless_view.cpp @@ -148,14 +148,11 @@ void HeadlessView::clear_buffers() { } HeadlessView::~HeadlessView() { - clear_buffers(); - #if MBGL_USE_CGL CGLDestroyContext(gl_context); #endif #if MBGL_USE_GLX - glXMakeCurrent(x_display, None, NULL); glXDestroyContext(x_display, gl_context); XFree(x_info); XCloseDisplay(x_display); -- cgit v1.2.1 From 1f7c591bc45d95f9bdecc109fd4a3ddf6592e42d Mon Sep 17 00:00:00 2001 From: Mike Morris Date: Thu, 11 Sep 2014 09:59:08 -0400 Subject: clear_buffers in make_inactive, call make_inactive in destructor --- common/headless_view.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'common') diff --git a/common/headless_view.cpp b/common/headless_view.cpp index ff903939b7..563fd8f245 100644 --- a/common/headless_view.cpp +++ b/common/headless_view.cpp @@ -148,6 +148,8 @@ void HeadlessView::clear_buffers() { } HeadlessView::~HeadlessView() { + make_inactive(); + #if MBGL_USE_CGL CGLDestroyContext(gl_context); #endif @@ -179,6 +181,8 @@ void HeadlessView::make_active() { } void HeadlessView::make_inactive() { + clear_buffers(); + #if MBGL_USE_CGL CGLError error = CGLSetCurrentContext(nullptr); if (error) { -- cgit v1.2.1 From 70aaf8d343ab0dc80993038bd13148b20de0b83e Mon Sep 17 00:00:00 2001 From: Mike Morris Date: Thu, 11 Sep 2014 10:09:30 -0400 Subject: pass NULL instead of nullptr to glXMakdeCurrent --- common/headless_view.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'common') diff --git a/common/headless_view.cpp b/common/headless_view.cpp index 563fd8f245..355206a3ee 100644 --- a/common/headless_view.cpp +++ b/common/headless_view.cpp @@ -191,7 +191,7 @@ void HeadlessView::make_inactive() { #endif #if MBGL_USE_GLX - if (!glXMakeCurrent(x_display, None, nullptr)) { + if (!glXMakeCurrent(x_display, None, NULL)) { fprintf(stderr, "Removing OpenGL context failed\n"); } #endif -- cgit v1.2.1 From 9d369ec742f00e35fea97fe24415ecaaaad1f01a Mon Sep 17 00:00:00 2001 From: Mike Morris Date: Tue, 16 Sep 2014 18:00:52 -0400 Subject: dont make_active when clearing buffers, call make_inactive at end of Map::prepare() --- common/headless_view.cpp | 4 ---- 1 file changed, 4 deletions(-) (limited to 'common') diff --git a/common/headless_view.cpp b/common/headless_view.cpp index 355206a3ee..c2e402c0b6 100644 --- a/common/headless_view.cpp +++ b/common/headless_view.cpp @@ -113,8 +113,6 @@ void HeadlessView::resize(int width, int height) { } void HeadlessView::clear_buffers() { - make_active(); - #if MBGL_USE_CGL glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); @@ -181,8 +179,6 @@ void HeadlessView::make_active() { } void HeadlessView::make_inactive() { - clear_buffers(); - #if MBGL_USE_CGL CGLError error = CGLSetCurrentContext(nullptr); if (error) { -- cgit v1.2.1 From d48e5e72213851e4ffb443eae1b6243f491682c3 Mon Sep 17 00:00:00 2001 From: Mike Morris Date: Tue, 16 Sep 2014 18:06:24 -0400 Subject: make_active only for CGL in clear_buffers --- common/headless_view.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'common') diff --git a/common/headless_view.cpp b/common/headless_view.cpp index c2e402c0b6..8ea1b13709 100644 --- a/common/headless_view.cpp +++ b/common/headless_view.cpp @@ -114,6 +114,8 @@ void HeadlessView::resize(int width, int height) { void HeadlessView::clear_buffers() { #if MBGL_USE_CGL + make_active(); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); if (fbo) { -- cgit v1.2.1 From 65df83ce4c0ccb410f3d6a9841aeea621483f0be Mon Sep 17 00:00:00 2001 From: Mike Morris Date: Fri, 19 Sep 2014 16:16:44 -0400 Subject: bump mapnik-packaging, remove unnecessary view.make_active calls --- common/headless_view.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'common') diff --git a/common/headless_view.cpp b/common/headless_view.cpp index 8ea1b13709..4ad22da9a5 100644 --- a/common/headless_view.cpp +++ b/common/headless_view.cpp @@ -106,10 +106,7 @@ void HeadlessView::resize(int width, int height) { #if MBGL_USE_GLX x_pixmap = XCreatePixmap(x_display, DefaultRootWindow(x_display), width, height, 32); glx_pixmap = glXCreateGLXPixmap(x_display, x_info, x_pixmap); - - make_active(); #endif - } void HeadlessView::clear_buffers() { @@ -132,6 +129,8 @@ void HeadlessView::clear_buffers() { glDeleteRenderbuffersEXT(1, &fbo_depth_stencil); fbo_depth_stencil = 0; } + + make_inactive(); #endif #if MBGL_USE_GLX -- cgit v1.2.1 From 0cdaf58027b758650f4bb7ca7a006cb8568c080c Mon Sep 17 00:00:00 2001 From: Mike Morris Date: Wed, 24 Sep 2014 14:40:49 -0400 Subject: add debugging --- common/headless_view.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'common') diff --git a/common/headless_view.cpp b/common/headless_view.cpp index 0fce223986..d38a450070 100644 --- a/common/headless_view.cpp +++ b/common/headless_view.cpp @@ -2,6 +2,7 @@ #include #include +#include namespace mbgl { @@ -155,6 +156,10 @@ HeadlessView::~HeadlessView() { #endif #if MBGL_USE_GLX + std::cerr << "~HeadlessView()" << '\n'; + std::cerr << "x_display: " << x_display << '\n'; + std::cerr << "glx_pixmap: " << glx_pixmap << '\n'; + std::cerr << "gl_context: " << gl_context << '\n'; glXMakeCurrent(x_display, None, NULL); glXDestroyContext(x_display, gl_context); XFree(x_info); @@ -175,6 +180,10 @@ void HeadlessView::make_active() { #endif #if MBGL_USE_GLX + std::cerr << "make_active()" << '\n'; + std::cerr << "x_display: " << x_display << '\n'; + std::cerr << "glx_pixmap: " << glx_pixmap << '\n'; + std::cerr << "gl_context: " << gl_context << '\n'; if (!glXMakeCurrent(x_display, glx_pixmap, gl_context)) { fprintf(stderr, "Switching OpenGL context failed\n"); } -- cgit v1.2.1 From c5a7738dd640604a523e6e069cba92940d502614 Mon Sep 17 00:00:00 2001 From: Mike Morris Date: Wed, 24 Sep 2014 15:17:42 -0400 Subject: move make_active call into MBGL_USE_CGL block --- common/headless_view.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'common') diff --git a/common/headless_view.cpp b/common/headless_view.cpp index d38a450070..6ab005b6cf 100644 --- a/common/headless_view.cpp +++ b/common/headless_view.cpp @@ -114,9 +114,9 @@ void HeadlessView::resize(int width, int height) { } void HeadlessView::clear_buffers() { +#if MBGL_USE_CGL make_active(); -#if MBGL_USE_CGL glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); if (fbo) { -- cgit v1.2.1 From 86b7367994c933c1b91d571d348ec57620c7d26c Mon Sep 17 00:00:00 2001 From: Mike Morris Date: Wed, 24 Sep 2014 16:30:01 -0400 Subject: Revert "add debugging" This reverts commit 0cdaf58027b758650f4bb7ca7a006cb8568c080c. --- common/headless_view.cpp | 9 --------- 1 file changed, 9 deletions(-) (limited to 'common') diff --git a/common/headless_view.cpp b/common/headless_view.cpp index 94a6cd03bc..42d595310d 100644 --- a/common/headless_view.cpp +++ b/common/headless_view.cpp @@ -2,7 +2,6 @@ #include #include -#include namespace mbgl { @@ -159,10 +158,6 @@ HeadlessView::~HeadlessView() { #endif #if MBGL_USE_GLX - std::cerr << "~HeadlessView()" << '\n'; - std::cerr << "x_display: " << x_display << '\n'; - std::cerr << "glx_pixmap: " << glx_pixmap << '\n'; - std::cerr << "gl_context: " << gl_context << '\n'; glXMakeCurrent(x_display, None, NULL); glXDestroyContext(x_display, gl_context); XFree(x_info); @@ -183,10 +178,6 @@ void HeadlessView::make_active() { #endif #if MBGL_USE_GLX - std::cerr << "make_active()" << '\n'; - std::cerr << "x_display: " << x_display << '\n'; - std::cerr << "glx_pixmap: " << glx_pixmap << '\n'; - std::cerr << "gl_context: " << gl_context << '\n'; if (!glXMakeCurrent(x_display, glx_pixmap, gl_context)) { fprintf(stderr, "Switching OpenGL context failed\n"); } -- cgit v1.2.1 From dffeaa07877c59a6a586545e45c4f6339b789a6d Mon Sep 17 00:00:00 2001 From: Mike Morris Date: Wed, 24 Sep 2014 23:03:50 -0400 Subject: make active after resize --- common/headless_view.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'common') diff --git a/common/headless_view.cpp b/common/headless_view.cpp index 37982e6891..9dee14b393 100644 --- a/common/headless_view.cpp +++ b/common/headless_view.cpp @@ -109,6 +109,8 @@ void HeadlessView::resize(uint16_t width, uint16_t height, float pixelRatio) { #if MBGL_USE_GLX x_pixmap = XCreatePixmap(x_display, DefaultRootWindow(x_display), width, height, 32); glx_pixmap = glXCreateGLXPixmap(x_display, x_info, x_pixmap); + + make_active(); #endif } -- cgit v1.2.1 From 8e6967669a64d9bc38428fe59fae171a9ac02919 Mon Sep 17 00:00:00 2001 From: Mike Morris Date: Thu, 25 Sep 2014 18:06:55 -0400 Subject: make inactive at end of clear_buffers() --- common/headless_view.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'common') diff --git a/common/headless_view.cpp b/common/headless_view.cpp index 9dee14b393..3fc3816f07 100644 --- a/common/headless_view.cpp +++ b/common/headless_view.cpp @@ -148,11 +148,13 @@ void HeadlessView::clear_buffers() { XFreePixmap(x_display, x_pixmap); x_pixmap = 0; } + + make_inactive(); #endif } HeadlessView::~HeadlessView() { - make_inactive(); + clear_buffers(); #if MBGL_USE_CGL CGLDestroyContext(gl_context); -- cgit v1.2.1 From 8ebe1bc36033cfbfe9cad5a2a9ef6b5cc803c38e Mon Sep 17 00:00:00 2001 From: Mike Morris Date: Mon, 29 Sep 2014 16:33:26 -0400 Subject: add more possible errors returned by glCheckFramebufferStatusEXT from https://www.opengl.org/registry/specs/EXT/framebuffer_object.txt --- common/headless_view.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'common') diff --git a/common/headless_view.cpp b/common/headless_view.cpp index 3fc3816f07..e52bbf8b96 100644 --- a/common/headless_view.cpp +++ b/common/headless_view.cpp @@ -98,7 +98,10 @@ void HeadlessView::resize(uint16_t width, uint16_t height, float pixelRatio) { switch (status) { case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: fprintf(stderr, "incomplete attachment\n"); break; case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: fprintf(stderr, "incomplete missing attachment\n"); break; + case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: fprintf(stderr, "incomplete dimensions\n"); break; + case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: fprintf(stderr, "incomplete formats\n"); break; case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: fprintf(stderr, "incomplete draw buffer\n"); break; + case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: fprintf(stderr, "incomplete read buffer\n"); break; case GL_FRAMEBUFFER_UNSUPPORTED: fprintf(stderr, "unsupported\n"); break; default: fprintf(stderr, "other\n"); break; } -- cgit v1.2.1 From 848dccbcae8eb3ddf61b0d9344e150b721a8cf75 Mon Sep 17 00:00:00 2001 From: Mike Morris Date: Tue, 30 Sep 2014 12:06:51 -0400 Subject: make view active/inactive around Map::setup, don't leave active after view.resize() --- common/headless_view.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'common') diff --git a/common/headless_view.cpp b/common/headless_view.cpp index e52bbf8b96..61531bfd65 100644 --- a/common/headless_view.cpp +++ b/common/headless_view.cpp @@ -107,13 +107,13 @@ void HeadlessView::resize(uint16_t width, uint16_t height, float pixelRatio) { } return; } + + make_inactive(); #endif #if MBGL_USE_GLX x_pixmap = XCreatePixmap(x_display, DefaultRootWindow(x_display), width, height, 32); glx_pixmap = glXCreateGLXPixmap(x_display, x_info, x_pixmap); - - make_active(); #endif } -- cgit v1.2.1 From c4c4b3318a89c0a7548040f7182fb043704e230f Mon Sep 17 00:00:00 2001 From: Mike Morris Date: Tue, 30 Sep 2014 17:42:27 -0400 Subject: log CGLErrorString for CGLChoosePixelFormat, enable OpenGL multithreading https://developer.apple.com/library/mac/technotes/tn2085/_index.html --- common/headless_view.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'common') diff --git a/common/headless_view.cpp b/common/headless_view.cpp index 61531bfd65..10888f7a76 100644 --- a/common/headless_view.cpp +++ b/common/headless_view.cpp @@ -20,7 +20,7 @@ HeadlessView::HeadlessView() { GLint num; CGLError error = CGLChoosePixelFormat(attributes, &pixelFormat, &num); if (error) { - fprintf(stderr, "Error pixel format\n"); + fprintf(stderr, "Error pixel format: %s\n", CGLErrorString(error)); return; } @@ -30,6 +30,12 @@ HeadlessView::HeadlessView() { fprintf(stderr, "Error creating GL context object\n"); return; } + + error = CGLEnable(gl_context, kCGLCEMPEngine); + if (error != kCGLNoError ) { + fprintf(stderr, "Error enabling OpenGL multithreading\n"); + return; + } #endif #if MBGL_USE_GLX -- cgit v1.2.1 From 0f1d33f5ee29adf9b62c912339935fdde44b0b98 Mon Sep 17 00:00:00 2001 From: Mike Morris Date: Fri, 3 Oct 2014 18:31:38 -0400 Subject: break out HeadlessDisplay from HeadlessView, ref #478 --- common/headless_display.cpp | 65 +++++++++++++++++++++++++++++++++++++++++++++ common/headless_display.hpp | 32 ++++++++++++++++++++++ common/headless_view.cpp | 60 +++++++++-------------------------------- common/headless_view.hpp | 24 ++++++++--------- 4 files changed, 121 insertions(+), 60 deletions(-) create mode 100644 common/headless_display.cpp create mode 100644 common/headless_display.hpp (limited to 'common') diff --git a/common/headless_display.cpp b/common/headless_display.cpp new file mode 100644 index 0000000000..580d3ef587 --- /dev/null +++ b/common/headless_display.cpp @@ -0,0 +1,65 @@ +#include "headless_view.hpp" + +#include + +namespace mbgl { + +HeadlessDisplay::HeadlessDisplay() { +#if MBGL_USE_CGL + // 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, + (CGLPixelFormatAttribute) kCGLOGLPVersion_Legacy, + kCGLPFAAccelerated, + (CGLPixelFormatAttribute) 0 + }; + + GLint num; + CGLError error = CGLChoosePixelFormat(attributes, &pixelFormat, &num); + if (error) { + fprintf(stderr, "Error pixel format: %s\n", CGLErrorString(error)); + return; + } +#endif + +#if MBGL_USE_GLX + x_display = XOpenDisplay(0); + + if (x_display == nullptr) { + throw std::runtime_error("Failed to open X display"); + } + + static int pixelFormat[] = { + GLX_RGBA, + GLX_DOUBLEBUFFER, + GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + GLX_ALPHA_SIZE, 8, + GLX_DEPTH_SIZE, 24, + GLX_STENCIL_SIZE, 8, + None + }; + + x_info = glXChooseVisual(x_display, DefaultScreen(x_display), pixelFormat); + + if (x_info == nullptr) { + throw std::runtime_error("Error pixel format"); + } +#endif +} + +HeadlessDisplay::~HeadlessDisplay() { +#if MBGL_USE_CGL + CGLDestroyPixelFormat(pixelFormat); +#endif + +#if MBGL_USE_GLX + XFree(x_info); + XCloseDisplay(x_display); +#endif +} + +} + diff --git a/common/headless_display.hpp b/common/headless_display.hpp new file mode 100644 index 0000000000..4fc03da083 --- /dev/null +++ b/common/headless_display.hpp @@ -0,0 +1,32 @@ +#ifndef MBGL_COMMON_HEADLESS_DISPLAY +#define MBGL_COMMON_HEADLESS_DISPLAY + +#ifdef __APPLE__ +#define MBGL_USE_CGL 1 +#else +#include +#define MBGL_USE_GLX 1 +#endif + +#include + +namespace mbgl { + +class HeadlessDisplay { +public: + HeadlessDisplay(); + ~HeadlessDisplay(); + +#if MBGL_USE_CGL + CGLPixelFormatObj pixelFormat; +#endif + +#if MBGL_USE_GLX + Display *x_display = nullptr; + XVisualInfo *x_info = nullptr; +#endif +}; + +} + +#endif diff --git a/common/headless_view.cpp b/common/headless_view.cpp index 10888f7a76..47cf3bd661 100644 --- a/common/headless_view.cpp +++ b/common/headless_view.cpp @@ -1,31 +1,21 @@ #include "headless_view.hpp" -#include #include namespace mbgl { -HeadlessView::HeadlessView() { -#if MBGL_USE_CGL - // 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, - (CGLPixelFormatAttribute) kCGLOGLPVersion_Legacy, - kCGLPFAAccelerated, - (CGLPixelFormatAttribute) 0 - }; - - CGLPixelFormatObj pixelFormat; - GLint num; - CGLError error = CGLChoosePixelFormat(attributes, &pixelFormat, &num); - if (error) { - fprintf(stderr, "Error pixel format: %s\n", CGLErrorString(error)); - return; - } +HeadlessView::HeadlessView() : display_(new HeadlessDisplay()) { + createContext(); +} + +HeadlessView::HeadlessView(HeadlessDisplay *display) + : display_(display) { + createContext(); +} - error = CGLCreateContext(pixelFormat, NULL, &gl_context); - CGLDestroyPixelFormat(pixelFormat); +void HeadlessView::createContext() { +#if MBGL_USE_CGL + CGLError error = CGLCreateContext(display_->pixelFormat, NULL, &gl_context); if (error) { fprintf(stderr, "Error creating GL context object\n"); return; @@ -39,29 +29,8 @@ HeadlessView::HeadlessView() { #endif #if MBGL_USE_GLX - x_display = XOpenDisplay(0); - - if (x_display == nullptr) { - throw std::runtime_error("Failed to open X display"); - } - - static int pixelFormat[] = { - GLX_RGBA, - GLX_DOUBLEBUFFER, - GLX_RED_SIZE, 8, - GLX_GREEN_SIZE, 8, - GLX_BLUE_SIZE, 8, - GLX_ALPHA_SIZE, 8, - GLX_DEPTH_SIZE, 24, - GLX_STENCIL_SIZE, 8, - None - }; - - x_info = glXChooseVisual(x_display, DefaultScreen(x_display), pixelFormat); - - if (x_info == nullptr) { - throw std::runtime_error("Error pixel format"); - } + x_display = display_->x_display; + x_info = display_->x_info; gl_context = glXCreateContext(x_display, x_info, 0, GL_TRUE); if (gl_context == nullptr) { @@ -70,7 +39,6 @@ HeadlessView::HeadlessView() { #endif } - void HeadlessView::resize(uint16_t width, uint16_t height, float pixelRatio) { clear_buffers(); @@ -171,8 +139,6 @@ HeadlessView::~HeadlessView() { #if MBGL_USE_GLX glXDestroyContext(x_display, gl_context); - XFree(x_info); - XCloseDisplay(x_display); #endif } diff --git a/common/headless_view.hpp b/common/headless_view.hpp index c8475a2516..d1b09ce700 100644 --- a/common/headless_view.hpp +++ b/common/headless_view.hpp @@ -1,24 +1,20 @@ -#ifndef MBGL_COMMON_HEADLESS_CGL -#define MBGL_COMMON_HEADLESS_CGL - -#ifdef __APPLE__ -#define MBGL_USE_CGL 1 -#else -#include -#define MBGL_USE_GLX 1 -#endif +#ifndef MBGL_COMMON_HEADLESS_VIEW +#define MBGL_COMMON_HEADLESS_VIEW + +#include "headless_display.hpp" #include -#include -#include namespace mbgl { class HeadlessView : public View { public: HeadlessView(); + HeadlessView(HeadlessDisplay *display); ~HeadlessView(); + void createContext(); + void resize(uint16_t width, uint16_t height, float pixelRatio); void notify_map_change(MapChange change, timestamp delay = 0); @@ -32,6 +28,8 @@ private: private: + HeadlessDisplay *display_; + #if MBGL_USE_CGL CGLContextObj gl_context; GLuint fbo = 0; @@ -40,9 +38,9 @@ private: #endif #if MBGL_USE_GLX - GLXContext gl_context = nullptr; - XVisualInfo *x_info = nullptr; Display *x_display = nullptr; + XVisualInfo *x_info = nullptr; + GLXContext gl_context = nullptr; Pixmap x_pixmap = 0; GLXPixmap glx_pixmap = 0; #endif -- cgit v1.2.1 From 170ce422ceb20126cd7dc7b184b5edbc0685c7e7 Mon Sep 17 00:00:00 2001 From: Mike Morris Date: Mon, 6 Oct 2014 15:45:14 -0400 Subject: forward declare HeadlessDisplay in headless_view.hpp --- common/headless_display.cpp | 2 +- common/headless_display.hpp | 9 +-------- common/headless_view.cpp | 1 + common/headless_view.hpp | 10 +++++++++- 4 files changed, 12 insertions(+), 10 deletions(-) (limited to 'common') diff --git a/common/headless_display.cpp b/common/headless_display.cpp index 580d3ef587..38d123034b 100644 --- a/common/headless_display.cpp +++ b/common/headless_display.cpp @@ -1,4 +1,4 @@ -#include "headless_view.hpp" +#include "headless_display.hpp" #include diff --git a/common/headless_display.hpp b/common/headless_display.hpp index 4fc03da083..0eb41911ee 100644 --- a/common/headless_display.hpp +++ b/common/headless_display.hpp @@ -1,14 +1,7 @@ #ifndef MBGL_COMMON_HEADLESS_DISPLAY #define MBGL_COMMON_HEADLESS_DISPLAY -#ifdef __APPLE__ -#define MBGL_USE_CGL 1 -#else -#include -#define MBGL_USE_GLX 1 -#endif - -#include +#include "headless_view.hpp" namespace mbgl { diff --git a/common/headless_view.cpp b/common/headless_view.cpp index 47cf3bd661..86fa445fc8 100644 --- a/common/headless_view.cpp +++ b/common/headless_view.cpp @@ -1,4 +1,5 @@ #include "headless_view.hpp" +#include "headless_display.hpp" #include diff --git a/common/headless_view.hpp b/common/headless_view.hpp index d1b09ce700..381988ae94 100644 --- a/common/headless_view.hpp +++ b/common/headless_view.hpp @@ -1,12 +1,20 @@ #ifndef MBGL_COMMON_HEADLESS_VIEW #define MBGL_COMMON_HEADLESS_VIEW -#include "headless_display.hpp" +#ifdef __APPLE__ +#define MBGL_USE_CGL 1 +#else +#include +#define MBGL_USE_GLX 1 +#endif #include +#include namespace mbgl { +class HeadlessDisplay; + class HeadlessView : public View { public: HeadlessView(); -- cgit v1.2.1 From 8b06b65f35445a1dc8490ede523a23fab46529fa Mon Sep 17 00:00:00 2001 From: Mike Morris Date: Mon, 6 Oct 2014 16:53:57 -0400 Subject: wrap GL/glx.h with undef None, use 0 instead, h/t @jfirebaugh --- common/glx.h | 2 ++ common/headless_display.cpp | 2 +- common/headless_view.cpp | 2 +- common/headless_view.hpp | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 common/glx.h (limited to 'common') diff --git a/common/glx.h b/common/glx.h new file mode 100644 index 0000000000..6b7d9a3df9 --- /dev/null +++ b/common/glx.h @@ -0,0 +1,2 @@ +#include +#undef None diff --git a/common/headless_display.cpp b/common/headless_display.cpp index 38d123034b..b183b0a501 100644 --- a/common/headless_display.cpp +++ b/common/headless_display.cpp @@ -39,7 +39,7 @@ HeadlessDisplay::HeadlessDisplay() { GLX_ALPHA_SIZE, 8, GLX_DEPTH_SIZE, 24, GLX_STENCIL_SIZE, 8, - None + 0 }; x_info = glXChooseVisual(x_display, DefaultScreen(x_display), pixelFormat); diff --git a/common/headless_view.cpp b/common/headless_view.cpp index 86fa445fc8..cd8ee685d5 100644 --- a/common/headless_view.cpp +++ b/common/headless_view.cpp @@ -171,7 +171,7 @@ void HeadlessView::make_inactive() { #endif #if MBGL_USE_GLX - if (!glXMakeCurrent(x_display, None, NULL)) { + if (!glXMakeCurrent(x_display, 0, NULL)) { fprintf(stderr, "Removing OpenGL context failed\n"); } #endif diff --git a/common/headless_view.hpp b/common/headless_view.hpp index 381988ae94..cef4213e90 100644 --- a/common/headless_view.hpp +++ b/common/headless_view.hpp @@ -4,7 +4,7 @@ #ifdef __APPLE__ #define MBGL_USE_CGL 1 #else -#include +#include "glx.h" #define MBGL_USE_GLX 1 #endif -- cgit v1.2.1 From 41dac96408a08e3ad2fca7bbe1e7572db85acd13 Mon Sep 17 00:00:00 2001 From: Mike Morris Date: Mon, 6 Oct 2014 18:05:10 -0400 Subject: use shared_ptr for HeadlessDisplay in HeadlessView --- common/headless_view.cpp | 12 ++++++------ common/headless_view.hpp | 6 ++++-- 2 files changed, 10 insertions(+), 8 deletions(-) (limited to 'common') diff --git a/common/headless_view.cpp b/common/headless_view.cpp index cd8ee685d5..5e8770b7a7 100644 --- a/common/headless_view.cpp +++ b/common/headless_view.cpp @@ -5,18 +5,18 @@ namespace mbgl { -HeadlessView::HeadlessView() : display_(new HeadlessDisplay()) { +HeadlessView::HeadlessView() : display_ptr(std::make_shared()) { createContext(); } -HeadlessView::HeadlessView(HeadlessDisplay *display) - : display_(display) { +HeadlessView::HeadlessView(HeadlessDisplay &display) + : display_ptr(std::make_shared(display)) { createContext(); } void HeadlessView::createContext() { #if MBGL_USE_CGL - CGLError error = CGLCreateContext(display_->pixelFormat, NULL, &gl_context); + CGLError error = CGLCreateContext(display_ptr->pixelFormat, NULL, &gl_context); if (error) { fprintf(stderr, "Error creating GL context object\n"); return; @@ -30,8 +30,8 @@ void HeadlessView::createContext() { #endif #if MBGL_USE_GLX - x_display = display_->x_display; - x_info = display_->x_info; + x_display = display_ptr->x_display; + x_info = display_ptr->x_info; gl_context = glXCreateContext(x_display, x_info, 0, GL_TRUE); if (gl_context == nullptr) { diff --git a/common/headless_view.hpp b/common/headless_view.hpp index cef4213e90..5303f2c104 100644 --- a/common/headless_view.hpp +++ b/common/headless_view.hpp @@ -11,6 +11,8 @@ #include #include +#include + namespace mbgl { class HeadlessDisplay; @@ -18,7 +20,7 @@ class HeadlessDisplay; class HeadlessView : public View { public: HeadlessView(); - HeadlessView(HeadlessDisplay *display); + HeadlessView(HeadlessDisplay &display); ~HeadlessView(); void createContext(); @@ -36,7 +38,7 @@ private: private: - HeadlessDisplay *display_; + std::shared_ptr display_ptr; #if MBGL_USE_CGL CGLContextObj gl_context; -- cgit v1.2.1 From 5cc6b26229597ef78bd87d21367b75f2051b7314 Mon Sep 17 00:00:00 2001 From: Mike Morris Date: Mon, 6 Oct 2014 18:24:01 -0400 Subject: clean up shared_ptr usage --- common/headless_view.cpp | 12 ++++++------ common/headless_view.hpp | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'common') diff --git a/common/headless_view.cpp b/common/headless_view.cpp index 5e8770b7a7..b8a2fa360b 100644 --- a/common/headless_view.cpp +++ b/common/headless_view.cpp @@ -5,18 +5,18 @@ namespace mbgl { -HeadlessView::HeadlessView() : display_ptr(std::make_shared()) { +HeadlessView::HeadlessView() : display_ptr_(std::make_shared()) { createContext(); } -HeadlessView::HeadlessView(HeadlessDisplay &display) - : display_ptr(std::make_shared(display)) { +HeadlessView::HeadlessView(std::shared_ptr display_ptr) + : display_ptr_(display_ptr) { createContext(); } void HeadlessView::createContext() { #if MBGL_USE_CGL - CGLError error = CGLCreateContext(display_ptr->pixelFormat, NULL, &gl_context); + CGLError error = CGLCreateContext(display_ptr_->pixelFormat, NULL, &gl_context); if (error) { fprintf(stderr, "Error creating GL context object\n"); return; @@ -30,8 +30,8 @@ void HeadlessView::createContext() { #endif #if MBGL_USE_GLX - x_display = display_ptr->x_display; - x_info = display_ptr->x_info; + x_display = display_ptr_->x_display; + x_info = display_ptr_->x_info; gl_context = glXCreateContext(x_display, x_info, 0, GL_TRUE); if (gl_context == nullptr) { diff --git a/common/headless_view.hpp b/common/headless_view.hpp index 5303f2c104..3ad5a669a5 100644 --- a/common/headless_view.hpp +++ b/common/headless_view.hpp @@ -20,7 +20,7 @@ class HeadlessDisplay; class HeadlessView : public View { public: HeadlessView(); - HeadlessView(HeadlessDisplay &display); + HeadlessView(std::shared_ptr display_ptr); ~HeadlessView(); void createContext(); @@ -38,7 +38,7 @@ private: private: - std::shared_ptr display_ptr; + std::shared_ptr display_ptr_; #if MBGL_USE_CGL CGLContextObj gl_context; -- cgit v1.2.1 From 36b7bb0c0991b3c5c3a7d001139b120bee854484 Mon Sep 17 00:00:00 2001 From: Mike Morris Date: Tue, 7 Oct 2014 16:26:21 -0400 Subject: clean up shared_ptr usage in HeadlessView --- common/headless_view.cpp | 12 ++++++------ common/headless_view.hpp | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'common') diff --git a/common/headless_view.cpp b/common/headless_view.cpp index b8a2fa360b..d11f63dbd5 100644 --- a/common/headless_view.cpp +++ b/common/headless_view.cpp @@ -5,18 +5,18 @@ namespace mbgl { -HeadlessView::HeadlessView() : display_ptr_(std::make_shared()) { +HeadlessView::HeadlessView() : display_(std::make_shared()) { createContext(); } -HeadlessView::HeadlessView(std::shared_ptr display_ptr) - : display_ptr_(display_ptr) { +HeadlessView::HeadlessView(std::shared_ptr display) + : display_(display) { createContext(); } void HeadlessView::createContext() { #if MBGL_USE_CGL - CGLError error = CGLCreateContext(display_ptr_->pixelFormat, NULL, &gl_context); + CGLError error = CGLCreateContext(display_->pixelFormat, NULL, &gl_context); if (error) { fprintf(stderr, "Error creating GL context object\n"); return; @@ -30,8 +30,8 @@ void HeadlessView::createContext() { #endif #if MBGL_USE_GLX - x_display = display_ptr_->x_display; - x_info = display_ptr_->x_info; + x_display = display_->x_display; + x_info = display_->x_info; gl_context = glXCreateContext(x_display, x_info, 0, GL_TRUE); if (gl_context == nullptr) { diff --git a/common/headless_view.hpp b/common/headless_view.hpp index 3ad5a669a5..13a5b01099 100644 --- a/common/headless_view.hpp +++ b/common/headless_view.hpp @@ -20,7 +20,7 @@ class HeadlessDisplay; class HeadlessView : public View { public: HeadlessView(); - HeadlessView(std::shared_ptr display_ptr); + HeadlessView(std::shared_ptr display); ~HeadlessView(); void createContext(); @@ -38,7 +38,7 @@ private: private: - std::shared_ptr display_ptr_; + std::shared_ptr display_; #if MBGL_USE_CGL CGLContextObj gl_context; -- cgit v1.2.1 From 7aea160760a0ad8338d0b3e15419332c1794848c Mon Sep 17 00:00:00 2001 From: Mike Morris Date: Wed, 8 Oct 2014 14:47:41 -0400 Subject: throw std::runtime_error instead of fprintf in HeadlessView, closes #481 --- common/headless_view.cpp | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'common') diff --git a/common/headless_view.cpp b/common/headless_view.cpp index d11f63dbd5..d19db57483 100644 --- a/common/headless_view.cpp +++ b/common/headless_view.cpp @@ -2,6 +2,8 @@ #include "headless_display.hpp" #include +#include +#include namespace mbgl { @@ -18,14 +20,12 @@ void HeadlessView::createContext() { #if MBGL_USE_CGL CGLError error = CGLCreateContext(display_->pixelFormat, NULL, &gl_context); if (error) { - fprintf(stderr, "Error creating GL context object\n"); - return; + throw std::runtime_error("Error creating GL context object\n"); } error = CGLEnable(gl_context, kCGLCEMPEngine); if (error != kCGLNoError ) { - fprintf(stderr, "Error enabling OpenGL multithreading\n"); - return; + throw std::runtime_error("Error enabling OpenGL multithreading\n"); } #endif @@ -69,18 +69,18 @@ void HeadlessView::resize(uint16_t width, uint16_t height, float pixelRatio) { GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { - fprintf(stderr, "Couldn't create framebuffer: "); + std::stringstream error("Couldn't create framebuffer: "); switch (status) { - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: fprintf(stderr, "incomplete attachment\n"); break; - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: fprintf(stderr, "incomplete missing attachment\n"); break; - case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: fprintf(stderr, "incomplete dimensions\n"); break; - case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: fprintf(stderr, "incomplete formats\n"); break; - case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: fprintf(stderr, "incomplete draw buffer\n"); break; - case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: fprintf(stderr, "incomplete read buffer\n"); break; - case GL_FRAMEBUFFER_UNSUPPORTED: fprintf(stderr, "unsupported\n"); break; - default: fprintf(stderr, "other\n"); break; + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: (error << "incomplete attachment\n"); break; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: error << "incomplete missing attachment\n"; break; + case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: error << "incomplete dimensions\n"; break; + case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: error << "incomplete formats\n"; break; + case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: error << "incomplete draw buffer\n"; break; + case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: error << "incomplete read buffer\n"; break; + case GL_FRAMEBUFFER_UNSUPPORTED: error << "unsupported\n"; break; + default: error << "other\n"; break; } - return; + throw std::runtime_error(error.str()); } make_inactive(); @@ -151,13 +151,13 @@ void HeadlessView::make_active() { #if MBGL_USE_CGL CGLError error = CGLSetCurrentContext(gl_context); if (error) { - fprintf(stderr, "Switching OpenGL context failed\n"); + throw std::runtime_error("Switching OpenGL context failed\n"); } #endif #if MBGL_USE_GLX if (!glXMakeCurrent(x_display, glx_pixmap, gl_context)) { - fprintf(stderr, "Switching OpenGL context failed\n"); + throw std::runtime_error("Switching OpenGL context failed\n"); } #endif } @@ -166,13 +166,13 @@ void HeadlessView::make_inactive() { #if MBGL_USE_CGL CGLError error = CGLSetCurrentContext(nullptr); if (error) { - fprintf(stderr, "Removing OpenGL context failed\n"); + throw std::runtime_error("Removing OpenGL context failed\n"); } #endif #if MBGL_USE_GLX if (!glXMakeCurrent(x_display, 0, NULL)) { - fprintf(stderr, "Removing OpenGL context failed\n"); + throw std::runtime_error("Removing OpenGL context failed\n"); } #endif } -- cgit v1.2.1 From a1bc8c766d6e204a44e2c7171a80330e123b582b Mon Sep 17 00:00:00 2001 From: Mike Morris Date: Wed, 8 Oct 2014 15:31:41 -0400 Subject: add HeadlessView::readPixels, fixes #480 --- common/headless_view.cpp | 30 ++++++++++++++++++++++++------ common/headless_view.hpp | 5 ++++- 2 files changed, 28 insertions(+), 7 deletions(-) (limited to 'common') diff --git a/common/headless_view.cpp b/common/headless_view.cpp index d19db57483..9775da1d57 100644 --- a/common/headless_view.cpp +++ b/common/headless_view.cpp @@ -7,7 +7,8 @@ namespace mbgl { -HeadlessView::HeadlessView() : display_(std::make_shared()) { +HeadlessView::HeadlessView() + : display_(std::make_shared()) { createContext(); } @@ -43,8 +44,12 @@ void HeadlessView::createContext() { void HeadlessView::resize(uint16_t width, uint16_t height, float pixelRatio) { clear_buffers(); - width *= pixelRatio; - height *= pixelRatio; + width_ = width; + height_ = height; + pixelRatio_ = pixelRatio; + + const unsigned int w = width_ * pixelRatio_; + const unsigned int h = height_ * pixelRatio_; #if MBGL_USE_CGL make_active(); @@ -52,12 +57,12 @@ void HeadlessView::resize(uint16_t width, uint16_t height, float pixelRatio) { // Create depth/stencil buffer glGenRenderbuffersEXT(1, &fbo_depth_stencil); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fbo_depth_stencil); - glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, width, height); + glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, w, h); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); glGenRenderbuffersEXT(1, &fbo_color); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fbo_color); - glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA8, width, height); + glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA8, w, h); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); glGenFramebuffersEXT(1, &fbo); @@ -87,11 +92,24 @@ void HeadlessView::resize(uint16_t width, uint16_t height, float pixelRatio) { #endif #if MBGL_USE_GLX - x_pixmap = XCreatePixmap(x_display, DefaultRootWindow(x_display), width, height, 32); + x_pixmap = XCreatePixmap(x_display, DefaultRootWindow(x_display), w, h, 32); glx_pixmap = glXCreateGLXPixmap(x_display, x_info, x_pixmap); #endif } +const std::unique_ptr* HeadlessView::readPixels() { + const unsigned int w = width_ * pixelRatio_; + const unsigned int h = height_ * pixelRatio_; + + const std::unique_ptr pixels(new uint32_t[w * h]); + + make_active(); + glReadPixels(0, 0, width_, height_, GL_RGBA, GL_UNSIGNED_BYTE, pixels.get()); + make_inactive(); + + return &pixels; +} + void HeadlessView::clear_buffers() { #if MBGL_USE_CGL make_active(); diff --git a/common/headless_view.hpp b/common/headless_view.hpp index 13a5b01099..b59366349e 100644 --- a/common/headless_view.hpp +++ b/common/headless_view.hpp @@ -26,6 +26,7 @@ public: void createContext(); void resize(uint16_t width, uint16_t height, float pixelRatio); + const std::unique_ptr* readPixels(); void notify_map_change(MapChange change, timestamp delay = 0); void make_active(); @@ -36,9 +37,11 @@ public: private: void clear_buffers(); - private: std::shared_ptr display_; + uint16_t width_; + uint16_t height_; + float pixelRatio_; #if MBGL_USE_CGL CGLContextObj gl_context; -- cgit v1.2.1 From dfb81fe9ce796c06263c4b531cdba4d0e8571808 Mon Sep 17 00:00:00 2001 From: Mike Morris Date: Wed, 8 Oct 2014 16:04:13 -0400 Subject: fix HeadlessView::readPixels return value, ref #480 --- common/headless_view.cpp | 6 +++--- common/headless_view.hpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'common') diff --git a/common/headless_view.cpp b/common/headless_view.cpp index 9775da1d57..3f945ee6aa 100644 --- a/common/headless_view.cpp +++ b/common/headless_view.cpp @@ -97,17 +97,17 @@ void HeadlessView::resize(uint16_t width, uint16_t height, float pixelRatio) { #endif } -const std::unique_ptr* HeadlessView::readPixels() { +const std::unique_ptr HeadlessView::readPixels() { const unsigned int w = width_ * pixelRatio_; const unsigned int h = height_ * pixelRatio_; - const std::unique_ptr pixels(new uint32_t[w * h]); + std::unique_ptr pixels(new uint32_t[w * h]); make_active(); glReadPixels(0, 0, width_, height_, GL_RGBA, GL_UNSIGNED_BYTE, pixels.get()); make_inactive(); - return &pixels; + return pixels; } void HeadlessView::clear_buffers() { diff --git a/common/headless_view.hpp b/common/headless_view.hpp index b59366349e..600e9d51fa 100644 --- a/common/headless_view.hpp +++ b/common/headless_view.hpp @@ -26,7 +26,7 @@ public: void createContext(); void resize(uint16_t width, uint16_t height, float pixelRatio); - const std::unique_ptr* readPixels(); + const std::unique_ptr readPixels(); void notify_map_change(MapChange change, timestamp delay = 0); void make_active(); -- cgit v1.2.1 From 356cf956f413bbf4c4e69a849350f8fc0194356a Mon Sep 17 00:00:00 2001 From: Mike Morris Date: Thu, 9 Oct 2014 15:16:01 -0400 Subject: XInitThreads --- common/headless_display.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'common') diff --git a/common/headless_display.cpp b/common/headless_display.cpp index b183b0a501..bbb1c10f51 100644 --- a/common/headless_display.cpp +++ b/common/headless_display.cpp @@ -24,6 +24,10 @@ HeadlessDisplay::HeadlessDisplay() { #endif #if MBGL_USE_GLX + if (!XInitThreads()) { + throw std::runtime_error("Failed to XInitThreads"); + } + x_display = XOpenDisplay(0); if (x_display == nullptr) { -- cgit v1.2.1 From 35f2c7fe23fd9265e22897bbcb6bcef66e9e7032 Mon Sep 17 00:00:00 2001 From: Mike Morris Date: Fri, 10 Oct 2014 14:37:10 -0400 Subject: switch http_request_baton_curl to libuv 0.10 api --- common/http_request_baton_curl.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'common') diff --git a/common/http_request_baton_curl.cpp b/common/http_request_baton_curl.cpp index 772aeb86e1..726198d1dd 100644 --- a/common/http_request_baton_curl.cpp +++ b/common/http_request_baton_curl.cpp @@ -253,7 +253,7 @@ int handle_socket(CURL *handle, curl_socket_t sockfd, int action, void *, void * return 0; } -void on_timeout(uv_timer_t *) { +void on_timeout(uv_timer_t *, int status) { int running_handles; CURLMcode error = curl_multi_socket_action(multi, CURL_SOCKET_TIMEOUT, 0, &running_handles); if (error != CURLM_OK) { @@ -442,7 +442,6 @@ void stop_request(void *const ptr) { void create_thread() { uv_mutex_init(&share_mutex); - uv_loop_init(&loop); uv_messenger_init(&loop, &start_messenger, start_request); uv_messenger_init(&loop, &stop_messenger, stop_request); uv_thread_create(&thread, thread_init, nullptr); -- cgit v1.2.1 From 6e8e50e371b519e86955f004f53ce622923c5aa6 Mon Sep 17 00:00:00 2001 From: Mike Morris Date: Fri, 10 Oct 2014 14:47:33 -0400 Subject: call on_timeout with status 0 (success) --- common/http_request_baton_curl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'common') diff --git a/common/http_request_baton_curl.cpp b/common/http_request_baton_curl.cpp index 726198d1dd..3419dcc16d 100644 --- a/common/http_request_baton_curl.cpp +++ b/common/http_request_baton_curl.cpp @@ -263,7 +263,7 @@ void on_timeout(uv_timer_t *, int status) { void start_timeout(CURLM *, long timeout_ms, void *) { if (timeout_ms <= 0) { - on_timeout(&timeout); + on_timeout(&timeout, 0); } else { uv_timer_start(&timeout, on_timeout, timeout_ms, 0); } -- cgit v1.2.1 From 9ff1d9e3bdc05817d9f9de820e1d07dd17a699cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Wed, 15 Oct 2014 16:08:36 +0200 Subject: experimental pbuffer support [skip ci] --- common/headless_display.cpp | 32 ++++++++++++++++++++--------- common/headless_display.hpp | 2 +- common/headless_view.cpp | 50 +++++++++++++++++++++++++++++++-------------- common/headless_view.hpp | 5 ++--- 4 files changed, 60 insertions(+), 29 deletions(-) (limited to 'common') diff --git a/common/headless_display.cpp b/common/headless_display.cpp index bbb1c10f51..a938347527 100644 --- a/common/headless_display.cpp +++ b/common/headless_display.cpp @@ -27,30 +27,42 @@ HeadlessDisplay::HeadlessDisplay() { if (!XInitThreads()) { throw std::runtime_error("Failed to XInitThreads"); } - - x_display = XOpenDisplay(0); + x_display = XOpenDisplay(nullptr); if (x_display == nullptr) { throw std::runtime_error("Failed to open X display"); } + const char *extensions = (char *)glXQueryServerString(x_display, DefaultScreen(x_display), GLX_EXTENSIONS); + if (!extensions) { + throw std::runtime_error("Cannot read GLX extensions"); + } + if (!strstr(extensions,"GLX_SGIX_fbconfig")) { + throw std::runtime_error("Extension GLX_SGIX_fbconfig was not found"); + } + if (!strstr(extensions, "GLX_SGIX_pbuffer")) { + throw std::runtime_error("Cannot find glXCreateContextAttribsARB"); + } + + static int pixelFormat[] = { - GLX_RGBA, - GLX_DOUBLEBUFFER, + GLX_DOUBLEBUFFER, False, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_ALPHA_SIZE, 8, GLX_DEPTH_SIZE, 24, GLX_STENCIL_SIZE, 8, - 0 + None }; - x_info = glXChooseVisual(x_display, DefaultScreen(x_display), pixelFormat); - - if (x_info == nullptr) { - throw std::runtime_error("Error pixel format"); + int configs = 0; + fb_configs = glXChooseFBConfig(x_display, DefaultScreen(x_display), pixelFormat, &configs); + if (configs <= 0) { + throw std::runtime_error("No Framebuffer configurations"); } + + XSync(x_display, False); #endif } @@ -60,7 +72,7 @@ HeadlessDisplay::~HeadlessDisplay() { #endif #if MBGL_USE_GLX - XFree(x_info); + XFree(fb_configs); XCloseDisplay(x_display); #endif } diff --git a/common/headless_display.hpp b/common/headless_display.hpp index 0eb41911ee..5b33fd6990 100644 --- a/common/headless_display.hpp +++ b/common/headless_display.hpp @@ -16,7 +16,7 @@ public: #if MBGL_USE_GLX Display *x_display = nullptr; - XVisualInfo *x_info = nullptr; + GLXFBConfig *fb_configs = nullptr; #endif }; diff --git a/common/headless_view.cpp b/common/headless_view.cpp index c2084ac90d..dd62d9d23e 100644 --- a/common/headless_view.cpp +++ b/common/headless_view.cpp @@ -5,6 +5,11 @@ #include #include +#if MBGL_USE_GLX +typedef GLXContext (*glXCreateContextAttribsARBProc)(Display *, GLXFBConfig, GLXContext, Bool, const int *); +static glXCreateContextAttribsARBProc glXCreateContextAttribsARB = nullptr; +#endif + namespace mbgl { HeadlessView::HeadlessView() @@ -31,13 +36,29 @@ void HeadlessView::createContext() { #endif #if MBGL_USE_GLX + if (glXCreateContextAttribsARB == nullptr) { + glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)glXGetProcAddressARB((const GLubyte *)"glXCreateContextAttribsARB"); + } + if (glXCreateContextAttribsARB == nullptr) { + throw std::runtime_error("Cannot find glXCreateContextAttribsARB"); + } + x_display = display_->x_display; - x_info = display_->x_info; + fb_configs = display_->fb_configs; - gl_context = glXCreateContext(x_display, x_info, 0, GL_TRUE); + + int attributes[] = { + GLX_CONTEXT_MAJOR_VERSION_ARB, 2, + GLX_CONTEXT_MINOR_VERSION_ARB, 1, + GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB, + GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, + None + }; + gl_context = glXCreateContextAttribsARB(x_display, fb_configs[0], 0, True, attributes); if (gl_context == nullptr) { throw std::runtime_error("Error creating GL context object"); } + #endif } @@ -92,8 +113,12 @@ void HeadlessView::resize(uint16_t width, uint16_t height, float pixelRatio) { #endif #if MBGL_USE_GLX - x_pixmap = XCreatePixmap(x_display, DefaultRootWindow(x_display), w, h, 32); - glx_pixmap = glXCreateGLXPixmap(x_display, x_info, x_pixmap); + int attributes[] = { + GLX_PBUFFER_WIDTH, w, + GLX_PBUFFER_HEIGHT, h, + None + }; + GLXPbuffer pbuffer = glXCreatePbuffer(x_display, fg_configs[0], attributes); #endif } @@ -135,17 +160,12 @@ void HeadlessView::clear_buffers() { #endif #if MBGL_USE_GLX - if (glx_pixmap) { - glXDestroyGLXPixmap(x_display, glx_pixmap); - glx_pixmap = 0; - } + make_inactive(); - if (x_pixmap) { - XFreePixmap(x_display, x_pixmap); - x_pixmap = 0; + if (glx_pbuffer) { + glXDestroyPbuffer(x_display, glx_pbuffer); + glx_pbuffer = 0; } - - make_inactive(); #endif } @@ -178,7 +198,7 @@ void HeadlessView::make_active() { #endif #if MBGL_USE_GLX - if (!glXMakeCurrent(x_display, glx_pixmap, gl_context)) { + if (!glXMakeContextCurrent(x_display, glx_pbuffer, glx_pbuffer, gl_context)) { throw std::runtime_error("Switching OpenGL context failed\n"); } #endif @@ -193,7 +213,7 @@ void HeadlessView::make_inactive() { #endif #if MBGL_USE_GLX - if (!glXMakeCurrent(x_display, 0, NULL)) { + if (!glXMakeContextCurrent(x_display, 0, 0, nullptr)) { throw std::runtime_error("Removing OpenGL context failed\n"); } #endif diff --git a/common/headless_view.hpp b/common/headless_view.hpp index d2fe75382a..9ba25c73f0 100644 --- a/common/headless_view.hpp +++ b/common/headless_view.hpp @@ -53,10 +53,9 @@ private: #if MBGL_USE_GLX Display *x_display = nullptr; - XVisualInfo *x_info = nullptr; + GLXFBConfig *fb_configs = nullptr; GLXContext gl_context = nullptr; - Pixmap x_pixmap = 0; - GLXPixmap glx_pixmap = 0; + GLXPBuffer glx_pbuffer = 0; #endif }; -- cgit v1.2.1 From 8eda68dd8a24ee5025db82d02f952fdd5921eea3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Wed, 15 Oct 2014 14:20:28 +0000 Subject: fix errors that prevented compilation/running --- common/headless_display.cpp | 1 + common/headless_view.cpp | 2 +- common/headless_view.hpp | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'common') diff --git a/common/headless_display.cpp b/common/headless_display.cpp index a938347527..3e30d62749 100644 --- a/common/headless_display.cpp +++ b/common/headless_display.cpp @@ -1,5 +1,6 @@ #include "headless_display.hpp" +#include #include namespace mbgl { diff --git a/common/headless_view.cpp b/common/headless_view.cpp index dd62d9d23e..51196faede 100644 --- a/common/headless_view.cpp +++ b/common/headless_view.cpp @@ -118,7 +118,7 @@ void HeadlessView::resize(uint16_t width, uint16_t height, float pixelRatio) { GLX_PBUFFER_HEIGHT, h, None }; - GLXPbuffer pbuffer = glXCreatePbuffer(x_display, fg_configs[0], attributes); + glx_pbuffer = glXCreatePbuffer(x_display, fb_configs[0], attributes); #endif } diff --git a/common/headless_view.hpp b/common/headless_view.hpp index 9ba25c73f0..ec76f1a077 100644 --- a/common/headless_view.hpp +++ b/common/headless_view.hpp @@ -4,7 +4,7 @@ #ifdef __APPLE__ #define MBGL_USE_CGL 1 #else -#include "glx.h" +#include #define MBGL_USE_GLX 1 #endif @@ -55,7 +55,7 @@ private: Display *x_display = nullptr; GLXFBConfig *fb_configs = nullptr; GLXContext gl_context = nullptr; - GLXPBuffer glx_pbuffer = 0; + GLXPbuffer glx_pbuffer = 0; #endif }; -- cgit v1.2.1 From 5f40d27256b5da164bfdd19253ca4c2078b1800a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Wed, 15 Oct 2014 14:31:19 +0000 Subject: cast to correct int type --- common/headless_view.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'common') diff --git a/common/headless_view.cpp b/common/headless_view.cpp index 51196faede..c482bbd8b3 100644 --- a/common/headless_view.cpp +++ b/common/headless_view.cpp @@ -114,8 +114,8 @@ void HeadlessView::resize(uint16_t width, uint16_t height, float pixelRatio) { #if MBGL_USE_GLX int attributes[] = { - GLX_PBUFFER_WIDTH, w, - GLX_PBUFFER_HEIGHT, h, + GLX_PBUFFER_WIDTH, static_cast(w), + GLX_PBUFFER_HEIGHT, static_cast(h), None }; glx_pbuffer = glXCreatePbuffer(x_display, fb_configs[0], attributes); -- cgit v1.2.1 From ee54220c7df2863dbbda191ad666416a6c84531b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Wed, 15 Oct 2014 09:56:57 -0700 Subject: lower our expectations towards the pbuffer and use framebuffers instead --- common/headless_display.cpp | 12 ++---------- common/headless_view.cpp | 38 ++++++++++++++------------------------ common/headless_view.hpp | 8 +++++--- 3 files changed, 21 insertions(+), 37 deletions(-) (limited to 'common') diff --git a/common/headless_display.cpp b/common/headless_display.cpp index 3e30d62749..3aaf2020b9 100644 --- a/common/headless_display.cpp +++ b/common/headless_display.cpp @@ -45,15 +45,9 @@ HeadlessDisplay::HeadlessDisplay() { throw std::runtime_error("Cannot find glXCreateContextAttribsARB"); } - + // We're creating a dummy pbuffer anyway that we're not using. static int pixelFormat[] = { - GLX_DOUBLEBUFFER, False, - GLX_RED_SIZE, 8, - GLX_GREEN_SIZE, 8, - GLX_BLUE_SIZE, 8, - GLX_ALPHA_SIZE, 8, - GLX_DEPTH_SIZE, 24, - GLX_STENCIL_SIZE, 8, + GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT, None }; @@ -62,8 +56,6 @@ HeadlessDisplay::HeadlessDisplay() { if (configs <= 0) { throw std::runtime_error("No Framebuffer configurations"); } - - XSync(x_display, False); #endif } diff --git a/common/headless_view.cpp b/common/headless_view.cpp index c482bbd8b3..7b739e1d67 100644 --- a/common/headless_view.cpp +++ b/common/headless_view.cpp @@ -47,18 +47,25 @@ void HeadlessView::createContext() { fb_configs = display_->fb_configs; - int attributes[] = { + int context_attributes[] = { GLX_CONTEXT_MAJOR_VERSION_ARB, 2, GLX_CONTEXT_MINOR_VERSION_ARB, 1, GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB, GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, None }; - gl_context = glXCreateContextAttribsARB(x_display, fb_configs[0], 0, True, attributes); + gl_context = glXCreateContextAttribsARB(x_display, fb_configs[0], 0, True, context_attributes); if (gl_context == nullptr) { throw std::runtime_error("Error creating GL context object"); } + int pbuffer_attributes[] = { + GLX_PBUFFER_WIDTH, 32, + GLX_PBUFFER_HEIGHT, 32, + None + }; + glx_pbuffer = glXCreatePbuffer(x_display, fb_configs[0], pbuffer_attributes); + #endif } @@ -72,7 +79,6 @@ void HeadlessView::resize(uint16_t width, uint16_t height, float pixelRatio) { const unsigned int w = width_ * pixelRatio_; const unsigned int h = height_ * pixelRatio_; -#if MBGL_USE_CGL make_active(); // Create depth/stencil buffer @@ -110,16 +116,6 @@ void HeadlessView::resize(uint16_t width, uint16_t height, float pixelRatio) { } make_inactive(); -#endif - -#if MBGL_USE_GLX - int attributes[] = { - GLX_PBUFFER_WIDTH, static_cast(w), - GLX_PBUFFER_HEIGHT, static_cast(h), - None - }; - glx_pbuffer = glXCreatePbuffer(x_display, fb_configs[0], attributes); -#endif } const std::unique_ptr HeadlessView::readPixels() { @@ -136,7 +132,6 @@ const std::unique_ptr HeadlessView::readPixels() { } void HeadlessView::clear_buffers() { -#if MBGL_USE_CGL make_active(); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); @@ -157,16 +152,6 @@ void HeadlessView::clear_buffers() { } make_inactive(); -#endif - -#if MBGL_USE_GLX - make_inactive(); - - if (glx_pbuffer) { - glXDestroyPbuffer(x_display, glx_pbuffer); - glx_pbuffer = 0; - } -#endif } HeadlessView::~HeadlessView() { @@ -177,6 +162,11 @@ HeadlessView::~HeadlessView() { #endif #if MBGL_USE_GLX + if (glx_pbuffer) { + glXDestroyPbuffer(x_display, glx_pbuffer); + glx_pbuffer = 0; + } + glXDestroyContext(x_display, gl_context); #endif } diff --git a/common/headless_view.hpp b/common/headless_view.hpp index ec76f1a077..195364db6e 100644 --- a/common/headless_view.hpp +++ b/common/headless_view.hpp @@ -4,6 +4,7 @@ #ifdef __APPLE__ #define MBGL_USE_CGL 1 #else +#define GL_GLEXT_PROTOTYPES #include #define MBGL_USE_GLX 1 #endif @@ -46,9 +47,6 @@ private: #if MBGL_USE_CGL CGLContextObj gl_context; - GLuint fbo = 0; - GLuint fbo_depth_stencil = 0; - GLuint fbo_color = 0; #endif #if MBGL_USE_GLX @@ -57,6 +55,10 @@ private: GLXContext gl_context = nullptr; GLXPbuffer glx_pbuffer = 0; #endif + + GLuint fbo = 0; + GLuint fbo_depth_stencil = 0; + GLuint fbo_color = 0; }; } -- cgit v1.2.1 From 8b08772d33ae37f05cf0ed4c5ce5c884cb8fab2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Thu, 16 Oct 2014 03:49:29 -0700 Subject: first attempt to create an opengl core profile version before falling back to legacy opengl contexts --- common/headless_view.cpp | 99 +++++++++++++++++++++++++++++++++++++++--------- common/headless_view.hpp | 2 +- 2 files changed, 82 insertions(+), 19 deletions(-) (limited to 'common') diff --git a/common/headless_view.cpp b/common/headless_view.cpp index 7b739e1d67..f746d97c36 100644 --- a/common/headless_view.cpp +++ b/common/headless_view.cpp @@ -6,8 +6,9 @@ #include #if MBGL_USE_GLX -typedef GLXContext (*glXCreateContextAttribsARBProc)(Display *, GLXFBConfig, GLXContext, Bool, const int *); -static glXCreateContextAttribsARBProc glXCreateContextAttribsARB = nullptr; +#ifdef GLX_ARB_create_context +static PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = nullptr; +#endif #endif namespace mbgl { @@ -22,6 +23,59 @@ HeadlessView::HeadlessView(std::shared_ptr display) createContext(); } + +#if MBGL_USE_GLX +#ifdef GLX_ARB_create_context + +// These are all of the OpenGL Core profile version that we know about. +struct core_profile_version { int major, minor; }; +static const core_profile_version core_profile_versions[] = { + {4, 5}, + {4, 4}, + {4, 3}, + {4, 2}, + {4, 1}, + {4, 0}, + {3, 3}, + {3, 2}, + {3, 1}, + {3, 0}, + {0, 0}, +}; + +GLXContext createCoreProfile(Display *dpy, GLXFBConfig fbconfig) { + static bool context_creation_failed = false; + GLXContext ctx = 0; + + // Set the Error Handler to avoid crashing the program when the context creation fails. + // It is expected that some context creation attempts fail, e.g. because the OpenGL + // implementation does not support the version we're requesting. + int (*previous_error_handler)(Display *, XErrorEvent *) = XSetErrorHandler([](Display *, XErrorEvent *) { + context_creation_failed = true; + return 0; + }); + + // Try to create core profiles from the highest known version on down. + for (int i = 0; !ctx && core_profile_versions[i].major; i++) { + context_creation_failed = false; + const int context_flags[] = { + GLX_CONTEXT_MAJOR_VERSION_ARB, core_profile_versions[i].major, + GLX_CONTEXT_MINOR_VERSION_ARB, core_profile_versions[i].minor, + None + }; + ctx = glXCreateContextAttribsARB(dpy, fbconfig, 0, True, context_flags); + if (context_creation_failed) { + ctx = 0; + } + } + + // Restore the old error handler. + XSetErrorHandler(previous_error_handler); + return ctx; +} +#endif +#endif + void HeadlessView::createContext() { #if MBGL_USE_CGL CGLError error = CGLCreateContext(display_->pixelFormat, NULL, &gl_context); @@ -36,36 +90,45 @@ void HeadlessView::createContext() { #endif #if MBGL_USE_GLX +#ifdef GLX_ARB_create_context if (glXCreateContextAttribsARB == nullptr) { - glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)glXGetProcAddressARB((const GLubyte *)"glXCreateContextAttribsARB"); - } - if (glXCreateContextAttribsARB == nullptr) { - throw std::runtime_error("Cannot find glXCreateContextAttribsARB"); + glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddressARB((const GLubyte *)"glXCreateContextAttribsARB"); } +#endif x_display = display_->x_display; fb_configs = display_->fb_configs; +#ifdef GLX_ARB_create_context + if (glXCreateContextAttribsARB) { + // Try to create a core profile context. + gl_context = createCoreProfile(x_display, fb_configs[0]); + } +#endif - int context_attributes[] = { - GLX_CONTEXT_MAJOR_VERSION_ARB, 2, - GLX_CONTEXT_MINOR_VERSION_ARB, 1, - GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB, - GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, - None - }; - gl_context = glXCreateContextAttribsARB(x_display, fb_configs[0], 0, True, context_attributes); - if (gl_context == nullptr) { + if (!gl_context) { + // Try to create a legacy context + gl_context = glXCreateNewContext(x_display, fb_configs[0], GLX_RGBA_TYPE, 0, True); + if (gl_context) { + if (!glXIsDirect(x_display, gl_context)) { + glXDestroyContext(x_display, gl_context); + gl_context = 0; + } + } + } + + if (gl_context == 0) { throw std::runtime_error("Error creating GL context object"); } + // Create a dummy pbuffer. We will render to framebuffers anyway, but we need a pbuffer to + // activate the context. int pbuffer_attributes[] = { - GLX_PBUFFER_WIDTH, 32, - GLX_PBUFFER_HEIGHT, 32, + GLX_PBUFFER_WIDTH, 8, + GLX_PBUFFER_HEIGHT, 8, None }; glx_pbuffer = glXCreatePbuffer(x_display, fb_configs[0], pbuffer_attributes); - #endif } diff --git a/common/headless_view.hpp b/common/headless_view.hpp index 195364db6e..6e4ddcd9e6 100644 --- a/common/headless_view.hpp +++ b/common/headless_view.hpp @@ -52,7 +52,7 @@ private: #if MBGL_USE_GLX Display *x_display = nullptr; GLXFBConfig *fb_configs = nullptr; - GLXContext gl_context = nullptr; + GLXContext gl_context = 0; GLXPbuffer glx_pbuffer = 0; #endif -- cgit v1.2.1 From 4bc56eac24d399e5c58a7f9a936fe85a71180915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Thu, 16 Oct 2014 04:26:50 -0700 Subject: we now always use the fbo [skip ci] --- common/headless_view.cpp | 4 ---- 1 file changed, 4 deletions(-) (limited to 'common') diff --git a/common/headless_view.cpp b/common/headless_view.cpp index f746d97c36..6a5a2dc00b 100644 --- a/common/headless_view.cpp +++ b/common/headless_view.cpp @@ -275,11 +275,7 @@ void HeadlessView::make_inactive() { void HeadlessView::swap() {} unsigned int HeadlessView::root_fbo() { -#if MBGL_USE_CGL return fbo; -#endif - - return 0; } } -- cgit v1.2.1 From 97986f603f5af6b12deb4cdb4e91cd5035457c7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Thu, 16 Oct 2014 04:27:30 -0700 Subject: we don't need a root_fbo function anymore [skip ci] --- common/headless_view.cpp | 4 ---- common/headless_view.hpp | 1 - 2 files changed, 5 deletions(-) (limited to 'common') diff --git a/common/headless_view.cpp b/common/headless_view.cpp index 6a5a2dc00b..d1d13db5f8 100644 --- a/common/headless_view.cpp +++ b/common/headless_view.cpp @@ -274,9 +274,5 @@ void HeadlessView::make_inactive() { void HeadlessView::swap() {} -unsigned int HeadlessView::root_fbo() { - return fbo; -} - } diff --git a/common/headless_view.hpp b/common/headless_view.hpp index 6e4ddcd9e6..c0baddb884 100644 --- a/common/headless_view.hpp +++ b/common/headless_view.hpp @@ -34,7 +34,6 @@ public: void make_active(); void make_inactive(); void swap(); - unsigned int root_fbo(); private: void clear_buffers(); -- cgit v1.2.1 From 02e88e445d9960c3b248ea95d03d4a191ef91289 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Wed, 22 Oct 2014 15:29:28 +0200 Subject: fixes for libuv 0.11 --- common/curl_request.cpp | 383 ------------------------------------------------ 1 file changed, 383 deletions(-) delete mode 100644 common/curl_request.cpp (limited to 'common') diff --git a/common/curl_request.cpp b/common/curl_request.cpp deleted file mode 100644 index 3370c0a859..0000000000 --- a/common/curl_request.cpp +++ /dev/null @@ -1,383 +0,0 @@ - -#include -#include -#include -#include - -#include -#include - -#include - -// This file contains code from http://curl.haxx.se/libcurl/c/multi-uv.html: - -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -/* Example application code using the multi socket interface to download - multiple files at once, but instead of using curl_multi_perform and - curl_multi_wait, which uses select(), we use libuv. - It supports epoll, kqueue, etc. on unixes and fast IO completion ports on - Windows, which means, it should be very fast on all platforms.. - - Written by Clemens Gruber, based on an outdated example from uvbook and - some tests from libuv. - - Requires libuv and (of course) libcurl. - - See http://nikhilm.github.com/uvbook/ for more information on libuv. -*/ - -namespace mbgl { -namespace platform { -namespace request { - -struct curl_context { - uv_poll_t poll_handle; - curl_socket_t sockfd; -}; - -// Handles the request thread + messaging to the thread. -static uv_thread_t thread; -static uv::once init_thread_once; -static uv_loop_t *loop = nullptr; -static uv_async_t async_add; -static uv_async_t async_cancel; - -// Stores pointers (!) to shared_ptrs. We use shared_ptrs so that request objects don't get -// auto-destructed while they're in progress. The TileData object retains a weak_ptr to this -// request, so we have to use a shared_ptr here to ensure that this object stays alive. -static boost::lockfree::queue *> add_queue(8); -static boost::lockfree::queue *> cancel_queue(8); - -// Used as the CURL timer function to periodically check for socket updates. -static uv_timer_t timeout; - -// CURL multi handle that we use to request multiple URLs at the same time, without having to block -// and spawn threads. -static CURLM *curl_multi = nullptr; - -// CURL share handles are used for sharing session state (e.g.) -static uv::mutex curl_share_mutex; -static CURLSH *curl_share = nullptr; - -// A queue that we use for storing resuable CURL easy handles to avoid creating and destroying them -// all the time. -static std::queue curl_handle_cache; - - -class CURLRequest : public mbgl::platform::Request { -public: - CURLRequest(const std::string &url, - std::function callback, - std::shared_ptr loop) - : Request(url, callback, loop) {} - - CURL *curl = nullptr; -}; - - -// Implementation starts here. - -// Locks the CURL share handle -void curl_share_lock(CURL *, curl_lock_data, curl_lock_access, void *) { curl_share_mutex.lock(); } - -// Unlocks the CURL share handle -void curl_share_unlock(CURL *, curl_lock_data, void *) { curl_share_mutex.unlock(); } - -curl_context *create_curl_context(curl_socket_t sockfd) { - curl_context *context = new curl_context; - context->sockfd = sockfd; - - uv_poll_init_socket(loop, &context->poll_handle, sockfd); - context->poll_handle.data = context; - - return context; -} - -void curl_close_cb(uv_handle_t *handle) { - curl_context *context = (curl_context *)handle->data; - free(context); -} - -void destroy_curl_context(curl_context *context) { - uv_close((uv_handle_t *)&context->poll_handle, curl_close_cb); -} - -void remove_curl_handle(CURL *handle) { - CURLMcode error = curl_multi_remove_handle(curl_multi, handle); - if (error != CURLM_OK) { - throw std::runtime_error(std::string("CURL multi error: ") + curl_multi_strerror(error)); - } - - curl_easy_reset(handle); - curl_handle_cache.push(handle); -} - -void curl_perform(uv_poll_t *req, int /*status*/, int events) { - int running_handles; - int flags = 0; - curl_context *context; - CURLMsg *message; - int pending; - - uv_timer_stop(&timeout); - - if (events & UV_READABLE) - flags |= CURL_CSELECT_IN; - if (events & UV_WRITABLE) - flags |= CURL_CSELECT_OUT; - - context = (curl_context *)req; - - curl_multi_socket_action(curl_multi, context->sockfd, flags, &running_handles); - - while ((message = curl_multi_info_read(curl_multi, &pending))) { - switch (message->msg) { - case CURLMSG_DONE: { - std::shared_ptr *req = nullptr; - curl_easy_getinfo(message->easy_handle, CURLINFO_PRIVATE, (char *)&req); - - // Add human-readable error code - if (message->data.result != CURLE_OK) { - (*req)->res->error_message = curl_easy_strerror(message->data.result); - (*req)->res->code = -1; - } else { - curl_easy_getinfo(message->easy_handle, CURLINFO_RESPONSE_CODE, &(*req)->res->code); - } - - // We're currently in the CURL request thread. We're going to schedule a uv_work request - // that executes the background function in a threadpool, and tell it to call the - // after callback back in the main uv loop. - (*req)->complete(); - - CURL *handle = message->easy_handle; - remove_curl_handle(handle); - - // We're setting this to NULL because there might still be shared_ptrs around that could - // be cancelled. - ((CURLRequest *)req->get())->curl = nullptr; - - // Delete the shared_ptr pointer we created earlier. - delete req; - break; - } - - default: - // This should never happen, because there are no other message types. - throw std::runtime_error("CURLMSG returned unknown message type"); - } - } -} - -int handle_socket(CURL * /*easy*/, curl_socket_t s, int action, void * /*userp*/, void *socketp) { - curl_context *context = nullptr; - - if (socketp) { - context = (curl_context *)socketp; - } else if (action != CURL_POLL_REMOVE) { - context = create_curl_context(s); - } - - if (context) { - curl_multi_assign(curl_multi, s, (void *)context); - if (action == CURL_POLL_IN || action == CURL_POLL_INOUT) { - uv_poll_start(&context->poll_handle, UV_READABLE, curl_perform); - } - if (action == CURL_POLL_OUT || action == CURL_POLL_INOUT) { - uv_poll_start(&context->poll_handle, UV_WRITABLE, curl_perform); - } - if (action == CURL_POLL_REMOVE && socketp) { - uv_poll_stop(&context->poll_handle); - destroy_curl_context(context); - curl_multi_assign(curl_multi, s, NULL); - } - } - - return 0; -} - -void on_timeout(uv_timer_t *, int status /*req*/) { - int running_handles; - CURLMcode error = - curl_multi_socket_action(curl_multi, CURL_SOCKET_TIMEOUT, 0, &running_handles); - if (error != CURLM_OK) { - throw std::runtime_error(std::string("CURL multi error: ") + curl_multi_strerror(error)); - } -} - -void start_timeout(CURLM * /*multi*/, long timeout_ms, void * /*userp*/) { - if (timeout_ms <= 0) { - on_timeout(&timeout, -1); - } else { - uv_timer_start(&timeout, &on_timeout, timeout_ms, 0); - } -} - -// This function is the first function called in the request thread. It sets up the CURL share/multi -// handles and runs the thread loop. -void thread_init(void * /*ptr*/) { - uv_timer_init(loop, &timeout); - - CURLSHcode share_error; - curl_share = curl_share_init(); - - share_error = curl_share_setopt(curl_share, CURLSHOPT_LOCKFUNC, curl_share_lock); - if (share_error != CURLSHE_OK) { - throw std::runtime_error(std::string("CURL share error: ") + curl_share_strerror(share_error)); - } - - share_error = curl_share_setopt(curl_share, CURLSHOPT_UNLOCKFUNC, curl_share_unlock); - if (share_error != CURLSHE_OK) { - throw std::runtime_error(std::string("CURL share error: ") + curl_share_strerror(share_error)); - } - - CURLMcode multi_error; - curl_multi = curl_multi_init(); - - multi_error = curl_multi_setopt(curl_multi, CURLMOPT_SOCKETFUNCTION, handle_socket); - if (multi_error != CURLM_OK) { - throw std::runtime_error(std::string("CURL multi error: ") + curl_multi_strerror(multi_error)); - } - multi_error = curl_multi_setopt(curl_multi, CURLMOPT_TIMERFUNCTION, start_timeout); - if (multi_error != CURLM_OK) { - throw std::runtime_error(std::string("CURL multi error: ") + curl_multi_strerror(multi_error)); - - } - - // Main event loop. This will not return until the request loop is terminated. - uv_run(loop, UV_RUN_DEFAULT); - - curl_multi_cleanup(curl_multi); - curl_multi = nullptr; - curl_share_cleanup(curl_share); - curl_share = nullptr; - - // Clean up all the CURL easy handles that we kept around for potential future reuse. - while (!curl_handle_cache.empty()) { - curl_easy_cleanup(curl_handle_cache.front()); - curl_handle_cache.pop(); - } -} - -// This function is called when we have new data for a request. We just append it to the string -// containing the previous data. -size_t curl_write_cb(void *contents, size_t size, size_t nmemb, void *userp) { - ((std::string *)userp)->append((char *)contents, size * nmemb); - return size * nmemb; -} - -// This callback is called in the request event loop (on the request thread). -// It initializes newly queued up download requests and adds them to the CURL -// multi handle. -void async_add_cb(uv_async_t *, int status /*async*/) { - std::shared_ptr *req = nullptr; - while (add_queue.pop(req)) { - // Make sure that we're not starting requests that have been cancelled - // already by async_cancel_cb. - if ((*req)->cancelled) { - delete req; - continue; - } - - // Obtain a curl handle (and try to reuse existing handles before creating new ones). - CURL *handle = nullptr; - if (!curl_handle_cache.empty()) { - handle = curl_handle_cache.front(); - curl_handle_cache.pop(); - } else { - handle = curl_easy_init(); - } - - ((CURLRequest *)req->get())->curl = handle; - - curl_easy_setopt(handle, CURLOPT_PRIVATE, req); - curl_easy_setopt(handle, CURLOPT_CAINFO, "ca-bundle.crt"); - curl_easy_setopt(handle, CURLOPT_URL, (*req)->url.c_str()); - curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, curl_write_cb); - curl_easy_setopt(handle, CURLOPT_WRITEDATA, &(*req)->res->body); - curl_easy_setopt(handle, CURLOPT_ACCEPT_ENCODING, "gzip, deflate"); - curl_easy_setopt(handle, CURLOPT_SHARE, curl_share); - curl_multi_add_handle(curl_multi, handle); - } -} - -void async_cancel_cb(uv_async_t *, int status /*async*/) { - std::shared_ptr *req = nullptr; - while (cancel_queue.pop(req)) { - // It is possible that the request has not yet been started, but that it already has been - // added to the queue for scheduling new requests. In this case, the CURL handle is invalid - // and we manually mark the Request as cancelled. - CURL *handle = ((CURLRequest *)req->get())->curl; - if (handle && !(*req)->cancelled) { - remove_curl_handle(handle); - ((CURLRequest *)req->get())->curl = nullptr; - } - (*req)->cancelled = true; - - delete req; - req = nullptr; - } -} - -void thread_init_cb() { - curl_global_init(CURL_GLOBAL_ALL); - - loop = uv_loop_new(); - uv_async_init(loop, &async_add, &async_add_cb); - uv_async_init(loop, &async_cancel, &async_cancel_cb); - uv_thread_create(&thread, thread_init, nullptr); -} -} // end namespace request -} // end namespace platform - - -std::shared_ptr -platform::request_http(const std::string &url, - std::function callback, - std::shared_ptr loop) { - using namespace request; - init_thread_once(thread_init_cb); - std::shared_ptr req = std::make_shared(url, callback, loop); - - // Note that we are creating a new shared_ptr pointer(!) because the lockless queue can't store - // objects with nontrivial destructors. We have to make absolutely sure that we manually delete - // the shared_ptr when we pop it from the queue. - add_queue.push(new std::shared_ptr(req)); - uv_async_send(&async_add); - - return req; -} - -// Cancels an HTTP request. -void platform::cancel_request_http(const std::shared_ptr &req) { - if (req) { - using namespace request; - - // Note that we are creating a new shared_ptr pointer(!) because the lockless queue can't - // store objects with nontrivial destructors. We have to make absolutely shure that we - // manually delete the shared_ptr when we pop it from the queue. - cancel_queue.push(new std::shared_ptr(req)); - uv_async_send(&async_cancel); - } -} -} // end namespace mbgl -- cgit v1.2.1 From 214f99673f6f7480f9cc3bf9d6fa32ef8dd2ede5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Wed, 22 Oct 2014 18:06:11 +0200 Subject: fix variable shadowing --- common/glfw_view.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'common') diff --git a/common/glfw_view.cpp b/common/glfw_view.cpp index 120faf4df1..53cd068d09 100644 --- a/common/glfw_view.cpp +++ b/common/glfw_view.cpp @@ -2,7 +2,7 @@ #include -GLFWView::GLFWView(bool fullscreen) : fullscreen(fullscreen) { +GLFWView::GLFWView(bool fullscreen_) : fullscreen(fullscreen_) { #ifdef NVIDIA glDiscardFramebufferEXT = (PFNGLDISCARDFRAMEBUFFEREXTPROC)glfwGetProcAddress("glDiscardFramebufferEXT"); #endif -- cgit v1.2.1 From 10cb83579feb53e7524ec899c0bff19161877669 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Thu, 23 Oct 2014 02:46:15 -0700 Subject: gcc fixes --- common/glfw_view.cpp | 4 ++-- common/http_request_baton_curl.cpp | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'common') diff --git a/common/glfw_view.cpp b/common/glfw_view.cpp index 53cd068d09..92d1e19085 100644 --- a/common/glfw_view.cpp +++ b/common/glfw_view.cpp @@ -13,8 +13,8 @@ GLFWView::~GLFWView() { glfwTerminate(); } -void GLFWView::initialize(mbgl::Map *map) { - View::initialize(map); +void GLFWView::initialize(mbgl::Map *map_) { + View::initialize(map_); if (!glfwInit()) { fprintf(stderr, "Failed to initialize glfw\n"); diff --git a/common/http_request_baton_curl.cpp b/common/http_request_baton_curl.cpp index b5226e20ec..0c3d2b43fc 100644 --- a/common/http_request_baton_curl.cpp +++ b/common/http_request_baton_curl.cpp @@ -154,11 +154,11 @@ void curl_perform(uv_poll_t *req, int, int events) { while ((message = curl_multi_info_read(multi, &pending))) { switch (message->msg) { case CURLMSG_DONE: { - CURLContext *context = nullptr; - curl_easy_getinfo(message->easy_handle, CURLINFO_PRIVATE, (char *)&context); + CURLContext *ctx = nullptr; + curl_easy_getinfo(message->easy_handle, CURLINFO_PRIVATE, (char *)&ctx); // Make a copy so that the Baton stays around even after we are calling finish_request - util::ptr baton = context->baton; + util::ptr baton = ctx->baton; // Add human-readable error code if (message->data.result != CURLE_OK) { @@ -242,8 +242,8 @@ int handle_socket(CURL *handle, curl_socket_t sockfd, int action, void *, void * } if (action == CURL_POLL_REMOVE && socketp) { uv_poll_stop(context->poll_handle); - uv_close((uv_handle_t *)context->poll_handle, [](uv_handle_t *handle) { - delete (uv_poll_t *)handle; + uv_close((uv_handle_t *)context->poll_handle, [](uv_handle_t *poll_handle) { + delete (uv_poll_t *)poll_handle; }); context->poll_handle = nullptr; curl_multi_assign(multi, sockfd, NULL); -- cgit v1.2.1