From a81e822ef003c5618ababd720103e1b828276988 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Thu, 11 Dec 2014 17:58:36 +0100 Subject: [PATCH 01/12] add cli tool for rendering a map to an image --- Makefile | 8 ++++ bin/render.cpp | 109 +++++++++++++++++++++++++++++++++++++++++++ bin/render.gyp | 54 +++++++++++++++++++++ src/mbgl/map/map.cpp | 2 + 4 files changed, 173 insertions(+) create mode 100644 bin/render.cpp create mode 100644 bin/render.gyp diff --git a/Makefile b/Makefile index 539ab12bc..740fc0a39 100644 --- a/Makefile +++ b/Makefile @@ -53,6 +53,10 @@ build/linux/Makefile: linux/mapboxgl-app.gyp config.gypi build/macosx/Makefile: macosx/mapboxgl-app.gyp config.gypi deps/run_gyp macosx/mapboxgl-app.gyp -Iconfig.gypi -Dplatform=osx --depth=. -Goutput_dir=.. --generator-output=./build/macosx -f make +.PHONY: build/render/Makefile +build/render/Makefile: bin/render.gyp config.gypi + deps/run_gyp bin/render.gyp -Iconfig.gypi -Dplatform=osx --depth=. -Goutput_dir=.. --generator-output=./build/render -f make + .PHONY: build/test/test.xcodeproj build/test/test.xcodeproj: test/test.gyp config.gypi deps/run_gyp test/test.gyp -Iconfig.gypi -Dplatform=$(PLATFORM) --depth=. -Goutput_dir=.. --generator-output=./build -f xcode @@ -101,6 +105,10 @@ osx: build/macosx/Makefile run-osx: osx build/$(BUILDTYPE)/Mapbox\ GL.app/Contents/MacOS/MAPBOX\ GL +# Builds the CLI render app +render: build/render/Makefile + $(MAKE) -C build/render BUILDTYPE=$(BUILDTYPE) V=$(V) mbgl-render + ##### Xcode projects ########################################################### clear_xcode_cache: diff --git a/bin/render.cpp b/bin/render.cpp new file mode 100644 index 000000000..d545c0929 --- /dev/null +++ b/bin/render.cpp @@ -0,0 +1,109 @@ +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#if __APPLE__ +#include +#else +#include +#endif + +#include +namespace po = boost::program_options; + +#include +#include +#include + +int main(int argc, char *argv[]) { + + std::string style_path; + double lat = 0, lon = 0; + double zoom = 0; + double bearing = 0; + + int width = 256; + int height = 256; + double pixelRatio = 1.0; + const char *output = "out.png"; + std::vector classes; + std::string token; + + po::options_description desc("Allowed options"); + desc.add_options() + ("style,s", po::value(&style_path)->required()->value_name("json"),"Map stylesheet") + ("lon,x", po::value(&lon)->value_name("degrees"), "Longitude") + ("lat,y", po::value(&lat)->value_name("degrees"), "Latitude in degrees") + ("zoom,z", po::value(&zoom)->value_name("number"), "Zoom level") + ("bearing,b", po::value(&bearing)->value_name("degrees"), "Bearing") + ("width,w", po::value(&width)->value_name("pixels"), "Image width") + ("height,h", po::value(&height)->value_name("pixels"), "Image height") + ("class,c", po::value(&classes)->value_name("name"), "Class name") + ("token,t", po::value(&token)->value_name("key"), "Mapbox access token") + ; + + try { + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + } catch(std::exception& e) { + std::cout << "Error: " << e.what() << std::endl << desc; + exit(1); + } + + std::string style = mbgl::util::read_file(style_path); + + using namespace mbgl; + + +#if __APPLE__ + Log::Set(); +#else + Log::Set(); +#endif + + CachingHTTPFileSource fileSource(""); + + // Try to load the token from the environment. + if (!token.size()) { + token = getenv("MAPBOX_ACCESS_TOKEN"); + } + + // Set access token if present + if (token.size()) { + fileSource.setAccessToken(std::string(token)); + } + + HeadlessView view; + Map map(view, fileSource); + + map.setStyleJSON(style, "."); + map.setAppliedClasses(classes); + + view.resize(width, height, pixelRatio); + map.resize(width, height, pixelRatio); + map.setLonLatZoom(lon, lat, zoom); + map.setBearing(bearing); + + std::unique_ptr pixels; + + // Run the loop. It will terminate when we don't have any further listeners. + map.run(); + + // Get the data from the GPU. + pixels = view.readPixels(); + + const unsigned int w = width * pixelRatio; + const unsigned int h = height * pixelRatio; + const std::string image = util::compress_png(w, h, pixels.get()); + util::write_file(output, image); +} diff --git a/bin/render.gyp b/bin/render.gyp new file mode 100644 index 000000000..9fb6066eb --- /dev/null +++ b/bin/render.gyp @@ -0,0 +1,54 @@ +{ + 'includes': [ + '../gyp/common.gypi', + '../gyp/version.gypi', + '../gyp/mbgl-platform.gypi', + ], + 'targets': [ + { + 'target_name': 'mbgl-render', + 'product_name': 'mbgl-render', + 'type': 'executable', + 'sources': [ + './render.cpp', + ], + 'variables' : { + 'cflags': [ + '<@(uv_cflags)', + '<@(png_cflags)', + '-I<(boost_root)/include', + ], + 'ldflags': [ + '<@(glfw3_ldflags)', + '<@(uv_ldflags)', + '<@(sqlite3_ldflags)', + '<@(curl_ldflags)', + '<@(png_ldflags)', + '<@(uv_static_libs)', + '-L<(boost_root)/lib', + '-lboost_program_options' + ], + }, + 'conditions': [ + # add libuv include path and OpenGL libs + ['OS == "mac"', + { + 'xcode_settings': { + 'OTHER_CPLUSPLUSFLAGS': ['<@(cflags)'], + 'OTHER_LDFLAGS': ['<@(ldflags)'], + }, + }, + { + 'cflags': ['<@(cflags)'], + 'libraries': ['<@(ldflags)'], + }], + ], + 'include_dirs': [ '../src' ], + 'dependencies': [ + '../mapboxgl.gyp:mbgl-core', + '../mapboxgl.gyp:mbgl-headless', + '<(platform_library)', + ], + }, + ], +} diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index f46e0f558..7f6cbd3f4 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -253,6 +253,8 @@ void Map::rerender() { // (== async rendering). if (async) { asyncRender->send(); + } else { + prepare(); } } From 8b5bba08b31e854caadfa31a4a2cf465353f0fd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Thu, 11 Dec 2014 18:02:24 +0100 Subject: [PATCH 02/12] show default values and allow setting the output filename --- bin/render.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/bin/render.cpp b/bin/render.cpp index d545c0929..a56c00f7d 100644 --- a/bin/render.cpp +++ b/bin/render.cpp @@ -34,21 +34,22 @@ int main(int argc, char *argv[]) { int width = 256; int height = 256; double pixelRatio = 1.0; - const char *output = "out.png"; + std::string output = "out.png"; std::vector classes; std::string token; po::options_description desc("Allowed options"); desc.add_options() - ("style,s", po::value(&style_path)->required()->value_name("json"),"Map stylesheet") - ("lon,x", po::value(&lon)->value_name("degrees"), "Longitude") - ("lat,y", po::value(&lat)->value_name("degrees"), "Latitude in degrees") - ("zoom,z", po::value(&zoom)->value_name("number"), "Zoom level") - ("bearing,b", po::value(&bearing)->value_name("degrees"), "Bearing") - ("width,w", po::value(&width)->value_name("pixels"), "Image width") - ("height,h", po::value(&height)->value_name("pixels"), "Image height") + ("style,s", po::value(&style_path)->required()->value_name("json")->default_value(style_path),"Map stylesheet") + ("lon,x", po::value(&lon)->value_name("degrees")->default_value(lon), "Longitude") + ("lat,y", po::value(&lat)->value_name("degrees")->default_value(lat), "Latitude in degrees") + ("zoom,z", po::value(&zoom)->value_name("number")->default_value(zoom), "Zoom level") + ("bearing,b", po::value(&bearing)->value_name("degrees")->default_value(bearing), "Bearing") + ("width,w", po::value(&width)->value_name("pixels")->default_value(width), "Image width") + ("height,h", po::value(&height)->value_name("pixels")->default_value(height), "Image height") ("class,c", po::value(&classes)->value_name("name"), "Class name") - ("token,t", po::value(&token)->value_name("key"), "Mapbox access token") + ("token,t", po::value(&token)->value_name("key")->default_value(token), "Mapbox access token") + ("output,o", po::value(&output)->value_name("file")->default_value(output), "Output file name") ; try { From 41d9e7730f8e430a08a0181912e2f4749bff112d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Thu, 11 Dec 2014 18:31:32 +0100 Subject: [PATCH 03/12] add xcode project for render cli util --- Makefile | 9 ++++++++- bin/render.gyp | 6 ++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 740fc0a39..d429903db 100644 --- a/Makefile +++ b/Makefile @@ -55,7 +55,7 @@ build/macosx/Makefile: macosx/mapboxgl-app.gyp config.gypi .PHONY: build/render/Makefile build/render/Makefile: bin/render.gyp config.gypi - deps/run_gyp bin/render.gyp -Iconfig.gypi -Dplatform=osx --depth=. -Goutput_dir=.. --generator-output=./build/render -f make + deps/run_gyp bin/render.gyp -Iconfig.gypi -Dplatform=$(PLATFORM) --depth=. -Goutput_dir=.. --generator-output=./build/render -f make .PHONY: build/test/test.xcodeproj build/test/test.xcodeproj: test/test.gyp config.gypi @@ -73,6 +73,10 @@ build/ios/mapbox-gl-cocoa/app/mapboxgl-app.xcodeproj: ios/mapbox-gl-cocoa/app/ma build/linux/mapboxgl-app.xcodeproj: linux/mapboxgl-app.gyp config.gypi deps/run_gyp linux/mapboxgl-app.gyp -Iconfig.gypi -Dplatform=linux --depth=. --generator-output=./build -f xcode +.PHONY: build/bin/render.xcodeproj +build/bin/render.xcodeproj: bin/render.gyp config.gypi + deps/run_gyp bin/render.gyp -Iconfig.gypi -Dplatform=$(PLATFORM) --depth=. --generator-output=./build -f xcode + ##### Test cases ############################################################### test: build/test/Makefile @@ -128,6 +132,9 @@ xproj: build/macosx/mapboxgl-app.xcodeproj iproj: build/ios/mapbox-gl-cocoa/app/mapboxgl-app.xcodeproj open ./build/ios/mapbox-gl-cocoa/app/mapboxgl-app.xcodeproj +rproj: build/bin/render.xcodeproj + open ./build/bin/render.xcodeproj + # build Linux project for Xcode (Runs on Mac OS X too, but without platform-specific code) lproj: build/linux/mapboxgl-app.xcodeproj open ./build/linux/mapboxgl-app.xcodeproj diff --git a/bin/render.gyp b/bin/render.gyp index 9fb6066eb..9ad9e7481 100644 --- a/bin/render.gyp +++ b/bin/render.gyp @@ -1,8 +1,6 @@ { 'includes': [ '../gyp/common.gypi', - '../gyp/version.gypi', - '../gyp/mbgl-platform.gypi', ], 'targets': [ { @@ -45,9 +43,9 @@ ], 'include_dirs': [ '../src' ], 'dependencies': [ - '../mapboxgl.gyp:mbgl-core', + '../mapboxgl.gyp:mbgl-standalone', '../mapboxgl.gyp:mbgl-headless', - '<(platform_library)', + '../mapboxgl.gyp:mbgl-<(platform)', ], }, ], From 343fd4bcac6c6891608de99c1922655a4e405dc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Thu, 11 Dec 2014 18:31:56 +0100 Subject: [PATCH 04/12] allow setting the cache database --- bin/render.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/render.cpp b/bin/render.cpp index a56c00f7d..367fb5a88 100644 --- a/bin/render.cpp +++ b/bin/render.cpp @@ -35,6 +35,7 @@ int main(int argc, char *argv[]) { int height = 256; double pixelRatio = 1.0; std::string output = "out.png"; + std::string cache = "cache.sqlite"; std::vector classes; std::string token; @@ -50,6 +51,7 @@ int main(int argc, char *argv[]) { ("class,c", po::value(&classes)->value_name("name"), "Class name") ("token,t", po::value(&token)->value_name("key")->default_value(token), "Mapbox access token") ("output,o", po::value(&output)->value_name("file")->default_value(output), "Output file name") + ("cache,d", po::value(&cache)->value_name("file")->default_value(cache), "Cache database file name") ; try { @@ -72,7 +74,7 @@ int main(int argc, char *argv[]) { Log::Set(); #endif - CachingHTTPFileSource fileSource(""); + CachingHTTPFileSource fileSource(cache); // Try to load the token from the environment. if (!token.size()) { From a4ce5152e89eb1d5ae3582a043ac264eaaecad2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Thu, 11 Dec 2014 18:32:09 +0100 Subject: [PATCH 05/12] don't provide a default value for the stylesheet file --- bin/render.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/render.cpp b/bin/render.cpp index 367fb5a88..01d32b6db 100644 --- a/bin/render.cpp +++ b/bin/render.cpp @@ -41,7 +41,7 @@ int main(int argc, char *argv[]) { po::options_description desc("Allowed options"); desc.add_options() - ("style,s", po::value(&style_path)->required()->value_name("json")->default_value(style_path),"Map stylesheet") + ("style,s", po::value(&style_path)->required()->value_name("json"), "Map stylesheet") ("lon,x", po::value(&lon)->value_name("degrees")->default_value(lon), "Longitude") ("lat,y", po::value(&lat)->value_name("degrees")->default_value(lat), "Latitude in degrees") ("zoom,z", po::value(&zoom)->value_name("number")->default_value(zoom), "Zoom level") From 1fe545aee4c28f3a74dc365ca69b4725cd8daa77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Thu, 11 Dec 2014 18:32:25 +0100 Subject: [PATCH 06/12] fix crashes when running in non-continuous mode --- src/mbgl/map/map.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index 7f6cbd3f4..0af7d4851 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -91,6 +91,7 @@ Map::Map(View& view_, FileSource& fileSource_) view(view_), #ifndef NDEBUG mainThread(std::this_thread::get_id()), + mapThread(mainThread), #endif transform(view_), fileSource(fileSource_), @@ -119,6 +120,7 @@ Map::~Map() { style.reset(); texturePool.reset(); workers.reset(); + fileSource.clearLoop(); uv_run(**loop, UV_RUN_DEFAULT); } From 21e9e0a5eafe494a98ca19babcd650107906510a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Fri, 12 Dec 2014 15:01:09 +0100 Subject: [PATCH 07/12] set rendering mode so that we can skip intermediate renders for static images --- include/mbgl/map/map.hpp | 9 ++++++++- src/mbgl/map/map.cpp | 29 ++++++++++++++++------------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp index 245aaf9ea..45846170c 100644 --- a/include/mbgl/map/map.hpp +++ b/include/mbgl/map/map.hpp @@ -136,7 +136,14 @@ private: // Unconditionally performs a render with the current map state. void render(); - bool async = false; + enum class Mode : uint8_t { + None, // we're not doing any processing + Continuous, // continually updating map + Static, // a once-off static image. + }; + + Mode mode = Mode::None; + std::unique_ptr loop; std::unique_ptr workers; std::thread thread; diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index 0af7d4851..1cebb97db 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -109,7 +109,7 @@ Map::Map(View& view_, FileSource& fileSource_) } Map::~Map() { - if (async) { + if (mode == Mode::Continuous) { stop(); } @@ -120,7 +120,6 @@ Map::~Map() { style.reset(); texturePool.reset(); workers.reset(); - fileSource.clearLoop(); uv_run(**loop, UV_RUN_DEFAULT); } @@ -134,11 +133,11 @@ uv::worker &Map::getWorker() { void Map::start() { assert(std::this_thread::get_id() == mainThread); - assert(!async); + assert(mode == Mode::None); // When starting map rendering in another thread, we perform async/continuously // updated rendering. Only in these cases, we attach the async handlers. - async = true; + mode = Mode::Continuous; // Reset the flag. isStopped = false; @@ -202,7 +201,7 @@ void Map::start() { void Map::stop(std::function callback) { assert(std::this_thread::get_id() == mainThread); assert(mainThread != mapThread); - assert(async); + assert(mode == Mode::Continuous); asyncTerminate->send(); @@ -222,13 +221,14 @@ void Map::stop(std::function callback) { // already finished executing. thread.join(); - async = false; + mode = Mode::None; } void Map::run() { #ifndef NDEBUG - if (!async) { + if (mode == Mode::None) { mapThread = mainThread; + mode = Mode::Static; } #endif assert(std::this_thread::get_id() == mapThread); @@ -242,21 +242,24 @@ void Map::run() { // If the map rendering wasn't started asynchronously, we perform one render // *after* all events have been processed. - if (!async) { + if (mode == Mode::Static) { render(); #ifndef NDEBUG mapThread = std::thread::id(); #endif + mode = Mode::None; + fileSource.clearLoop(); } } void Map::rerender() { - // We only send render events if we want to continuously update the map - // (== async rendering). - if (async) { - asyncRender->send(); - } else { + if (mode == Mode::Static) { prepare(); + } else if (mode == Mode::Continuous) { + // We only send render events if we want to continuously update the map + // (== async rendering). + assert(asyncRender); + asyncRender->send(); } } From 57e6bc6e1b700c12552ed7b18817e9cfc53c834c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Mon, 15 Dec 2014 14:16:30 +0100 Subject: [PATCH 08/12] fix error in non-debug builds --- src/mbgl/map/map.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index 1cebb97db..ea4115f05 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -225,12 +225,12 @@ void Map::stop(std::function callback) { } void Map::run() { -#ifndef NDEBUG if (mode == Mode::None) { +#ifndef NDEBUG mapThread = mainThread; +#endif mode = Mode::Static; } -#endif assert(std::this_thread::get_id() == mapThread); setup(); From 9082a83d6ac2b990db04752a991d97f8d18d4e34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Tue, 16 Dec 2014 11:42:58 +0100 Subject: [PATCH 09/12] don't assing nullptr to std::string --- bin/render.cpp | 5 +++- platform/default/headless_view.cpp | 46 ++++++++++++++++-------------- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/bin/render.cpp b/bin/render.cpp index 01d32b6db..feeb4fe3f 100644 --- a/bin/render.cpp +++ b/bin/render.cpp @@ -78,7 +78,10 @@ int main(int argc, char *argv[]) { // Try to load the token from the environment. if (!token.size()) { - token = getenv("MAPBOX_ACCESS_TOKEN"); + const char *token_ptr = getenv("MAPBOX_ACCESS_TOKEN"); + if (token_ptr) { + token = token_ptr; + } } // Set access token if present diff --git a/platform/default/headless_view.cpp b/platform/default/headless_view.cpp index b0fa60fc1..d85910875 100644 --- a/platform/default/headless_view.cpp +++ b/platform/default/headless_view.cpp @@ -52,32 +52,36 @@ HeadlessView::HeadlessView(std::shared_ptr display) void HeadlessView::loadExtensions() { make_active(); - const std::string extensions = (char *)MBGL_CHECK_ERROR(glGetString(GL_EXTENSIONS)); + const char *extension_ptr = (char *)MBGL_CHECK_ERROR(glGetString(GL_EXTENSIONS)); + + if (extension_ptr) { + const std::string extensions = extension_ptr; #ifdef MBGL_USE_CGL - if (extensions.find("GL_APPLE_vertex_array_object") != std::string::npos) { - gl::BindVertexArray = (gl::PFNGLBINDVERTEXARRAYPROC)CGLGetProcAddress("glBindVertexArrayAPPLE"); - gl::DeleteVertexArrays = (gl::PFNGLDELETEVERTEXARRAYSPROC)CGLGetProcAddress("glDeleteVertexArraysAPPLE"); - gl::GenVertexArrays = (gl::PFNGLGENVERTEXARRAYSPROC)CGLGetProcAddress("glGenVertexArraysAPPLE"); - gl::IsVertexArray = (gl::PFNGLISVERTEXARRAYPROC)CGLGetProcAddress("glIsVertexArrayAPPLE"); - assert(gl::BindVertexArray != nullptr); - assert(gl::DeleteVertexArrays != nullptr); - assert(gl::GenVertexArrays != nullptr); - assert(gl::IsVertexArray != nullptr); - } + if (extensions.find("GL_APPLE_vertex_array_object") != std::string::npos) { + gl::BindVertexArray = (gl::PFNGLBINDVERTEXARRAYPROC)CGLGetProcAddress("glBindVertexArrayAPPLE"); + gl::DeleteVertexArrays = (gl::PFNGLDELETEVERTEXARRAYSPROC)CGLGetProcAddress("glDeleteVertexArraysAPPLE"); + gl::GenVertexArrays = (gl::PFNGLGENVERTEXARRAYSPROC)CGLGetProcAddress("glGenVertexArraysAPPLE"); + gl::IsVertexArray = (gl::PFNGLISVERTEXARRAYPROC)CGLGetProcAddress("glIsVertexArrayAPPLE"); + assert(gl::BindVertexArray != nullptr); + assert(gl::DeleteVertexArrays != nullptr); + assert(gl::GenVertexArrays != nullptr); + assert(gl::IsVertexArray != nullptr); + } #endif #ifdef MBGL_USE_GLX - if (extensions.find("GL_ARB_vertex_array_object") != std::string::npos) { - gl::BindVertexArray = (gl::PFNGLBINDVERTEXARRAYPROC)glXGetProcAddress((const GLubyte *)"glBindVertexArray"); - gl::DeleteVertexArrays = (gl::PFNGLDELETEVERTEXARRAYSPROC)glXGetProcAddress((const GLubyte *)"glDeleteVertexArrays"); - gl::GenVertexArrays = (gl::PFNGLGENVERTEXARRAYSPROC)glXGetProcAddress((const GLubyte *)"glGenVertexArrays"); - gl::IsVertexArray = (gl::PFNGLISVERTEXARRAYPROC)glXGetProcAddress((const GLubyte *)"glIsVertexArray"); - assert(gl::BindVertexArray != nullptr); - assert(gl::DeleteVertexArrays != nullptr); - assert(gl::GenVertexArrays != nullptr); - assert(gl::IsVertexArray != nullptr); - } + if (extensions.find("GL_ARB_vertex_array_object") != std::string::npos) { + gl::BindVertexArray = (gl::PFNGLBINDVERTEXARRAYPROC)glXGetProcAddress((const GLubyte *)"glBindVertexArray"); + gl::DeleteVertexArrays = (gl::PFNGLDELETEVERTEXARRAYSPROC)glXGetProcAddress((const GLubyte *)"glDeleteVertexArrays"); + gl::GenVertexArrays = (gl::PFNGLGENVERTEXARRAYSPROC)glXGetProcAddress((const GLubyte *)"glGenVertexArrays"); + gl::IsVertexArray = (gl::PFNGLISVERTEXARRAYPROC)glXGetProcAddress((const GLubyte *)"glIsVertexArray"); + assert(gl::BindVertexArray != nullptr); + assert(gl::DeleteVertexArrays != nullptr); + assert(gl::GenVertexArrays != nullptr); + assert(gl::IsVertexArray != nullptr); + } #endif + } make_inactive(); } From 40a5bcd7d39c9e83b59fe4149c56cc09793fb53b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Tue, 16 Dec 2014 11:10:41 +0000 Subject: [PATCH 10/12] never create core profile contexts; their API is subtly different (e.g. glGetString(GL_EXTENSIONS) doesn't work, you'd have to use glGetStringi(GL_EXTENSIONS, ...);) --- platform/default/headless_view.cpp | 74 +----------------------------- 1 file changed, 2 insertions(+), 72 deletions(-) diff --git a/platform/default/headless_view.cpp b/platform/default/headless_view.cpp index d85910875..4053af226 100644 --- a/platform/default/headless_view.cpp +++ b/platform/default/headless_view.cpp @@ -1,5 +1,6 @@ #include #include +#include #include @@ -9,12 +10,6 @@ #include #include -#if MBGL_USE_GLX -#ifdef GLX_ARB_create_context -static PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = nullptr; -#endif -#endif - #ifdef MBGL_USE_CGL #include @@ -86,59 +81,6 @@ void HeadlessView::loadExtensions() { make_inactive(); } - -#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 coreProfileVersions[] = { - {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 contextCreationFailed = 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 (*previousErrorHandler)(Display *, XErrorEvent *) = XSetErrorHandler([](Display *, XErrorEvent *) { - contextCreationFailed = true; - return 0; - }); - - // Try to create core profiles from the highest known version on down. - for (int i = 0; !ctx && coreProfileVersions[i].major; i++) { - contextCreationFailed = false; - const int contextFlags[] = { - GLX_CONTEXT_MAJOR_VERSION_ARB, coreProfileVersions[i].major, - GLX_CONTEXT_MINOR_VERSION_ARB, coreProfileVersions[i].minor, - 0 - }; - ctx = glXCreateContextAttribsARB(dpy, fbconfig, 0, True, contextFlags); - if (contextCreationFailed) { - ctx = 0; - } - } - - // Restore the old error handler. - XSetErrorHandler(previousErrorHandler); - return ctx; -} -#endif -#endif - void HeadlessView::createContext() { #if MBGL_USE_CGL CGLError error = CGLCreateContext(display_->pixelFormat, NULL, &glContext); @@ -153,27 +95,15 @@ void HeadlessView::createContext() { #endif #if MBGL_USE_GLX -#ifdef GLX_ARB_create_context - if (glXCreateContextAttribsARB == nullptr) { - glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddressARB((const GLubyte *)"glXCreateContextAttribsARB"); - } -#endif - xDisplay = display_->xDisplay; fbConfigs = display_->fbConfigs; -#ifdef GLX_ARB_create_context - if (glXCreateContextAttribsARB) { - // Try to create a core profile context. - glContext = createCoreProfile(xDisplay, fbConfigs[0]); - } -#endif - if (!glContext) { // Try to create a legacy context glContext = glXCreateNewContext(xDisplay, fbConfigs[0], GLX_RGBA_TYPE, 0, True); if (glContext) { if (!glXIsDirect(xDisplay, glContext)) { + mbgl::Log::Error(mbgl::Event::OpenGL, "Failed to create direct OpenGL Legacy context"); glXDestroyContext(xDisplay, glContext); glContext = 0; } From e57c57516fd3dd2513b6bae579f38f2f404fa545 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Tue, 16 Dec 2014 12:17:40 +0100 Subject: [PATCH 11/12] automatically copy the certificate bundle --- bin/render.gyp | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/render.gyp b/bin/render.gyp index 9ad9e7481..e9a259423 100644 --- a/bin/render.gyp +++ b/bin/render.gyp @@ -46,6 +46,7 @@ '../mapboxgl.gyp:mbgl-standalone', '../mapboxgl.gyp:mbgl-headless', '../mapboxgl.gyp:mbgl-<(platform)', + '../mapboxgl.gyp:copy_certificate_bundle', ], }, ], From 15b47197a79c05ca6fe4f604a7803ecbcb7a7e4d Mon Sep 17 00:00:00 2001 From: Leith Bade Date: Sat, 20 Dec 2014 14:15:33 +1300 Subject: [PATCH 12/12] Use iostream for saving GL program binary. Also check for GL_NUM_PROGRAM_BINARY_FORMATS > 0. --- platform/default/glfw_view.cpp | 16 +++++---- src/mbgl/shader/shader.cpp | 63 ++++++++++++++-------------------- 2 files changed, 35 insertions(+), 44 deletions(-) diff --git a/platform/default/glfw_view.cpp b/platform/default/glfw_view.cpp index e33f8eed1..21cd95c8b 100644 --- a/platform/default/glfw_view.cpp +++ b/platform/default/glfw_view.cpp @@ -152,12 +152,16 @@ void GLFWView::initialize(mbgl::Map *map_) { } if (extensions.find("GL_ARB_get_program_binary") != std::string::npos) { - gl::GetProgramBinary = (gl::PFNGLGETPROGRAMBINARYPROC)glfwGetProcAddress("glGetProgramBinary"); - gl::ProgramBinary = (gl::PFNGLPROGRAMBINARYPROC)glfwGetProcAddress("glProgramBinary"); - gl::ProgramParameteri = (gl::PFNGLPROGRAMPARAMETERIPROC)glfwGetProcAddress("glProgramParameteri"); - assert(gl::GetProgramBinary != nullptr); - assert(gl::ProgramBinary != nullptr); - assert(gl::ProgramParameteri != nullptr); + GLint numBinaryFormats; + MBGL_CHECK_ERROR(glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &numBinaryFormats)); + if (numBinaryFormats > 0) { + gl::GetProgramBinary = (gl::PFNGLGETPROGRAMBINARYPROC)glfwGetProcAddress("glGetProgramBinary"); + gl::ProgramBinary = (gl::PFNGLPROGRAMBINARYPROC)glfwGetProcAddress("glProgramBinary"); + gl::ProgramParameteri = (gl::PFNGLPROGRAMPARAMETERIPROC)glfwGetProcAddress("glProgramParameteri"); + assert(gl::GetProgramBinary != nullptr); + assert(gl::ProgramBinary != nullptr); + assert(gl::ProgramParameteri != nullptr); + } } } diff --git a/src/mbgl/shader/shader.cpp b/src/mbgl/shader/shader.cpp index c43863b52..62edf1d38 100644 --- a/src/mbgl/shader/shader.cpp +++ b/src/mbgl/shader/shader.cpp @@ -5,8 +5,9 @@ #include #include -#include #include +#include +#include using namespace mbgl; @@ -25,35 +26,26 @@ Shader::Shader(const char *name_, const GLchar *vertSource, const GLchar *fragSo // Load binary shader if it exists bool skipCompile = false; if (!binaryFileName.empty() && (gl::ProgramBinary != nullptr)) { - FILE *binaryFile = fopen(binaryFileName.c_str(), "rb"); - if (binaryFile != nullptr) { - GLsizei binaryLength; - GLenum binaryFormat; - bool lengthOk = fread(&binaryLength, sizeof(binaryLength), 1, binaryFile) == 1; - bool formatOk = fread(&binaryFormat, sizeof(binaryFormat), 1, binaryFile) == 1; + std::ifstream binaryFile(binaryFileName, std::ios::in | std::ios::binary); - if (lengthOk && formatOk && binaryLength > 0) { - std::unique_ptr binary = mbgl::util::make_unique(binaryLength); + GLsizei binaryLength; + GLenum binaryFormat; + binaryFile.read(reinterpret_cast(&binaryLength), sizeof(binaryLength)); + binaryFile.read(reinterpret_cast(&binaryFormat), sizeof(binaryFormat)); - if (binary != nullptr) { - bool binaryOk = fread(binary.get(), binaryLength, 1, binaryFile) == 1; + std::unique_ptr binary = mbgl::util::make_unique(binaryLength); + binaryFile.read(binary.get(), binaryLength); - if (binaryOk) { - MBGL_CHECK_ERROR(gl::ProgramBinary(program, binaryFormat, binary.get(), binaryLength)); + MBGL_CHECK_ERROR(gl::ProgramBinary(program, binaryFormat, binary.get(), binaryLength)); - // Check if the binary was valid - GLint status; - MBGL_CHECK_ERROR(glGetProgramiv(program, GL_LINK_STATUS, &status)); - if (status == GL_TRUE) { - skipCompile = true; - } - } - } - } - - fclose(binaryFile); - binaryFile = nullptr; + // Check if the binary was valid + GLint status; + MBGL_CHECK_ERROR(glGetProgramiv(program, GL_LINK_STATUS, &status)); + if (status == GL_TRUE) { + skipCompile = true; } + + binaryFile.close(); } GLuint vertShader = 0; @@ -150,7 +142,7 @@ bool Shader::compileShader(GLuint *shader, GLenum type, const GLchar *source) { *shader = MBGL_CHECK_ERROR(glCreateShader(type)); const GLchar *strings[] = { source }; - const GLsizei lengths[] = { (GLsizei)strlen(source) }; + const GLsizei lengths[] = { (GLsizei)std::strlen(source) }; MBGL_CHECK_ERROR(glShaderSource(*shader, 1, strings, lengths)); MBGL_CHECK_ERROR(glCompileShader(*shader)); @@ -189,19 +181,14 @@ Shader::~Shader() { MBGL_CHECK_ERROR(glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &binaryLength)); if (binaryLength > 0) { std::unique_ptr binary = mbgl::util::make_unique(binaryLength); - if (binary != nullptr) { - MBGL_CHECK_ERROR(gl::GetProgramBinary(program, binaryLength, NULL, &binaryFormat, binary.get())); + MBGL_CHECK_ERROR(gl::GetProgramBinary(program, binaryLength, NULL, &binaryFormat, binary.get())); - // Write the binary to a file - FILE *binaryFile = fopen(binaryFileName.c_str(), "wb"); - if (binaryFile != nullptr) { - fwrite(&binaryLength, sizeof(binaryLength), 1, binaryFile); - fwrite(&binaryFormat, sizeof(binaryFormat), 1, binaryFile); - fwrite(binary.get(), binaryLength, 1, binaryFile); - fclose(binaryFile); - binaryFile = nullptr; - } - } + // Write the binary to a file + std::ofstream binaryFile(binaryFileName, std::ios::out | std::ios::trunc | std::ios::binary); + binaryFile.write(reinterpret_cast(&binaryLength), sizeof(binaryLength)); + binaryFile.write(reinterpret_cast(&binaryFormat), sizeof(binaryFormat)); + binaryFile.write(binary.get(), binaryLength); + binaryFile.close(); } }