From e55ceb688f732dc050958b361cfe2bf33968d0cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Fri, 7 Apr 2017 15:45:54 +0200 Subject: [core] add support for SwiftShader --- CMakeLists.txt | 23 +++++-- Makefile | 34 ++++++---- cmake/benchmark.cmake | 4 ++ cmake/glfw.cmake | 4 ++ cmake/node.cmake | 13 ++-- cmake/offline.cmake | 4 ++ cmake/render.cmake | 4 ++ cmake/test.cmake | 4 ++ mapbox-gl-js | 2 +- platform/android/config.cmake | 6 +- platform/default/headless_backend_egl.cpp | 101 ++++++++++++++++++++++++++++ platform/default/headless_display_egl.cpp | 65 ++++++++++++++++++ platform/glfw/glfw_view.cpp | 10 ++- platform/ios/config.cmake | 2 +- platform/linux/config.cmake | 54 ++++++++++++--- platform/linux/src/headless_backend_egl.cpp | 101 ---------------------------- platform/linux/src/headless_display_egl.cpp | 65 ------------------ platform/macos/config.cmake | 48 +++++++++++-- platform/macos/scripts/create_scheme.sh | 7 +- scripts/generate-shaders.js | 9 ++- src/mbgl/gl/gl.hpp | 10 +-- src/mbgl/shaders/line.cpp | 6 +- src/mbgl/shaders/line_pattern.cpp | 6 +- src/mbgl/shaders/line_sdf.cpp | 6 +- src/mbgl/shaders/preludes.cpp | 5 +- 25 files changed, 361 insertions(+), 232 deletions(-) create mode 100644 platform/default/headless_backend_egl.cpp create mode 100644 platform/default/headless_display_egl.cpp delete mode 100644 platform/linux/src/headless_backend_egl.cpp delete mode 100644 platform/linux/src/headless_display_egl.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a6ed681bde..87b367d562 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,21 +5,26 @@ set(CMAKE_CXX_STANDARD 14) include(cmake/mbgl.cmake) include(cmake/mason.cmake) -option(WITH_CXX11ABI "Use cxx11abi mason packages" OFF) -option(WITH_COVERAGE "Enable coverage reports" OFF) -option(WITH_OSMESA "Use OSMesa headless backend" OFF) -option(WITH_EGL "Use EGL backend" OFF) +option(WITH_CXX11ABI "Use cxx11abi mason packages" OFF) +option(WITH_COVERAGE "Enable coverage reports" OFF) +option(WITH_OSMESA "Use OSMesa headless backend" OFF) +option(WITH_SWIFTSHADER "Use Swiftshader (implies WITH_EGL)" OFF) +option(WITH_EGL "Use EGL backend" OFF) if(WITH_CXX11ABI) set(MASON_CXXABI_SUFFIX -cxx11abi) endif() +if(WITH_SWIFTSHADER) + set(WITH_EGL ON) +endif() + if(WITH_OSMESA AND WITH_EGL) message(FATAL_ERROR "WITH_OSMESA and WITH_EGL are mutually exclusive.") endif() if(WITH_EGL) - add_definitions(-DMBGL_USE_GLES2=1) + set(USE_GLES2 ON) endif() if($ENV{CI}) @@ -82,6 +87,14 @@ include(cmake/loop-uv.cmake) include(platform/${MBGL_PLATFORM}/config.cmake) +if(WITH_EGL) + add_definitions(-DMBGL_WITH_EGL=1) +endif() + +if(USE_GLES2) + add_definitions(-DMBGL_USE_GLES2=1) +endif() + include(cmake/core-files.cmake) include(cmake/core.cmake) diff --git a/Makefile b/Makefile index 2eb2728b8a..19c618a55a 100644 --- a/Makefile +++ b/Makefile @@ -58,25 +58,28 @@ ifeq ($(HOST_PLATFORM), macos) export PATH := $(shell pwd)/platform/macos:$(PATH) -MACOS_OUTPUT_PATH = build/macos -MACOS_PROJ_PATH = $(MACOS_OUTPUT_PATH)/mbgl.xcodeproj -MACOS_WORK_PATH = platform/macos/macos.xcworkspace -MACOS_USER_DATA_PATH = $(MACOS_WORK_PATH)/xcuserdata/$(USER).xcuserdatad +MACOS_XCODEBUILD = xcodebuild -derivedDataPath $(MACOS_OUTPUT_PATH) -configuration $(BUILDTYPE) MACOS_COMPDB_PATH = $(MACOS_OUTPUT_PATH)/compdb/$(BUILDTYPE) - -MACOS_XCODEBUILD = xcodebuild \ - -derivedDataPath $(MACOS_OUTPUT_PATH) \ - -configuration $(BUILDTYPE) \ - -workspace $(MACOS_WORK_PATH) - +ifdef WITH_SWIFTSHADER + MACOS_OUTPUT_PATH = build/macos-swiftshader + WITH_SWIFTSHADER=ON + MACOS_XCODEBUILD += -project $(MACOS_PROJ_PATH) +else + MACOS_OUTPUT_PATH = build/macos + MACOS_WORK_PATH = platform/macos/macos.xcworkspace + MACOS_XCODEBUILD += -workspace $(MACOS_WORK_PATH) + MACOS_USER_DATA_PATH = $(MACOS_WORK_PATH)/xcuserdata/$(USER).xcuserdatad + BUILD_DEPS += $(MACOS_USER_DATA_PATH)/WorkspaceSettings.xcsettings +endif +export MACOS_PROJ_PATH = $(MACOS_OUTPUT_PATH)/mbgl.xcodeproj MACOS_XCSCHEMES += platform/macos/scripts/executable.xcscheme MACOS_XCSCHEMES += platform/macos/scripts/library.xcscheme MACOS_XCSCHEMES += platform/macos/scripts/node.xcscheme -$(MACOS_PROJ_PATH): $(BUILD_DEPS) $(MACOS_USER_DATA_PATH)/WorkspaceSettings.xcsettings $(MACOS_XCSCHEMES) +$(MACOS_PROJ_PATH): $(BUILD_DEPS) $(MACOS_XCSCHEMES) mkdir -p $(MACOS_OUTPUT_PATH) - (cd $(MACOS_OUTPUT_PATH) && cmake -G Xcode ../..) + (cd $(MACOS_OUTPUT_PATH) && cmake -G Xcode ../.. -DWITH_SWIFTSHADER=${WITH_SWIFTSHADER}) @# Create Xcode schemes so that we can use xcodebuild from the command line. CMake doesn't @# create these automatically. @@ -94,9 +97,11 @@ $(MACOS_PROJ_PATH): $(BUILD_DEPS) $(MACOS_USER_DATA_PATH)/WorkspaceSettings.xcse SCHEME_NAME="node render tests" SCHEME_TYPE=node BUILDABLE_NAME=mbgl-node.node BLUEPRINT_NAME=mbgl-node NODE_ARGUMENT="platform/node/test/render.test.js" platform/macos/scripts/create_scheme.sh SCHEME_NAME="node query tests" SCHEME_TYPE=node BUILDABLE_NAME=mbgl-node.node BLUEPRINT_NAME=mbgl-node NODE_ARGUMENT="platform/node/test/query.test.js" platform/macos/scripts/create_scheme.sh +ifndef WITH_SWIFTSHADER $(MACOS_USER_DATA_PATH)/WorkspaceSettings.xcsettings: platform/macos/WorkspaceSettings.xcsettings mkdir -p "$(MACOS_USER_DATA_PATH)" cp platform/macos/WorkspaceSettings.xcsettings "$@" +endif .PHONY: macos macos: $(MACOS_PROJ_PATH) @@ -104,7 +109,11 @@ macos: $(MACOS_PROJ_PATH) .PHONY: xproj xproj: $(MACOS_PROJ_PATH) +ifdef WITH_SWIFTSHADER + open $(MACOS_PROJ_PATH) +else open $(MACOS_WORK_PATH) +endif .PHONY: test test: $(MACOS_PROJ_PATH) @@ -296,6 +305,7 @@ $(LINUX_BUILD): $(BUILD_DEPS) -DWITH_CXX11ABI=$(shell scripts/check-cxx11abi.sh) \ -DWITH_COVERAGE=${WITH_COVERAGE} \ -DWITH_OSMESA=${WITH_OSMESA} \ + -DWITH_SWIFTSHADER=${WITH_SWIFTSHADER} \ -DWITH_EGL=${WITH_EGL}) .PHONY: linux diff --git a/cmake/benchmark.cmake b/cmake/benchmark.cmake index c298d8ee28..d616dba50d 100644 --- a/cmake/benchmark.cmake +++ b/cmake/benchmark.cmake @@ -22,4 +22,8 @@ target_add_mason_package(mbgl-benchmark PRIVATE rapidjson) mbgl_platform_benchmark() +if(WITH_SWIFTSHADER) + mbgl_platform_set_swiftshader_rpath(mbgl-benchmark) +endif() + create_source_groups(mbgl-benchmark) diff --git a/cmake/glfw.cmake b/cmake/glfw.cmake index ba6ba92e9f..04fca1dd17 100644 --- a/cmake/glfw.cmake +++ b/cmake/glfw.cmake @@ -27,4 +27,8 @@ target_add_mason_package(mbgl-glfw PRIVATE glfw) mbgl_platform_glfw() +if(WITH_SWIFTSHADER) + mbgl_platform_set_swiftshader_rpath(mbgl-glfw) +endif() + create_source_groups(mbgl-glfw) diff --git a/cmake/node.cmake b/cmake/node.cmake index 6833cb983f..20e8acc160 100644 --- a/cmake/node.cmake +++ b/cmake/node.cmake @@ -44,12 +44,17 @@ target_link_libraries(mbgl-node target_add_mason_package(mbgl-node PRIVATE geojson) -add_custom_command( - TARGET mbgl-node - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy $ ${CMAKE_SOURCE_DIR}/lib/mapbox_gl_native.node +set_target_properties(mbgl-node PROPERTIES + OUTPUT_NAME "mapbox_gl_native" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/lib" + LIBRARY_OUTPUT_DIRECTORY_DEBUG "${CMAKE_SOURCE_DIR}/lib" + LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_SOURCE_DIR}/lib" ) mbgl_platform_node() +if(WITH_SWIFTSHADER) + mbgl_platform_set_swiftshader_rpath(mbgl-node) +endif() + create_source_groups(mbgl-node) diff --git a/cmake/offline.cmake b/cmake/offline.cmake index d0124e661f..0efe821cee 100644 --- a/cmake/offline.cmake +++ b/cmake/offline.cmake @@ -24,4 +24,8 @@ target_add_mason_package(mbgl-offline PRIVATE boost_libprogram_options) mbgl_platform_offline() +if(WITH_SWIFTSHADER) + mbgl_platform_set_swiftshader_rpath(mbgl-offline) +endif() + create_source_groups(mbgl-offline) diff --git a/cmake/render.cmake b/cmake/render.cmake index 023b3c21e3..87215c7118 100644 --- a/cmake/render.cmake +++ b/cmake/render.cmake @@ -19,4 +19,8 @@ target_add_mason_package(mbgl-render PRIVATE boost_libprogram_options) mbgl_platform_render() +if(WITH_SWIFTSHADER) + mbgl_platform_set_swiftshader_rpath(mbgl-render) +endif() + create_source_groups(mbgl-render) diff --git a/cmake/test.cmake b/cmake/test.cmake index 5e77de2448..4efd3ac495 100644 --- a/cmake/test.cmake +++ b/cmake/test.cmake @@ -37,4 +37,8 @@ target_add_mason_package(mbgl-test PRIVATE geojsonvt) mbgl_platform_test() +if(WITH_SWIFTSHADER) + mbgl_platform_set_swiftshader_rpath(mbgl-test) +endif() + create_source_groups(mbgl-test) diff --git a/mapbox-gl-js b/mapbox-gl-js index e3b2df2807..4e0ad93ca8 160000 --- a/mapbox-gl-js +++ b/mapbox-gl-js @@ -1 +1 @@ -Subproject commit e3b2df28079f350747db177e0707698847d0bcd1 +Subproject commit 4e0ad93ca8f28f628424eb2ded27ffdfc8c3fec4 diff --git a/platform/android/config.cmake b/platform/android/config.cmake index de8d0bacb2..2c9bcdd31e 100644 --- a/platform/android/config.cmake +++ b/platform/android/config.cmake @@ -1,4 +1,4 @@ -add_definitions(-DMBGL_USE_GLES2=1) +set(USE_GLES2 ON) include(cmake/test-files.cmake) @@ -295,8 +295,8 @@ macro(mbgl_platform_test) platform/default/mbgl/gl/offscreen_view.cpp platform/default/mbgl/gl/offscreen_view.hpp - platform/linux/src/headless_backend_egl.cpp - platform/linux/src/headless_display_egl.cpp + platform/default/headless_backend_egl.cpp + platform/default/headless_display_egl.cpp ) target_compile_options(mbgl-test diff --git a/platform/default/headless_backend_egl.cpp b/platform/default/headless_backend_egl.cpp new file mode 100644 index 0000000000..d98b2edc03 --- /dev/null +++ b/platform/default/headless_backend_egl.cpp @@ -0,0 +1,101 @@ +#include +#include + +#include + +#include + +#include + +namespace mbgl { + +struct EGLImpl : public HeadlessBackend::Impl { + EGLImpl(EGLContext glContext_, EGLDisplay display_, EGLConfig config_) + : glContext(glContext_), + display(display_), + config(config_) { + // Create a dummy pbuffer. We will render to framebuffers anyway, but we need a pbuffer to + // activate the context. + // Note that to be able to create pbuffer surfaces, we need to choose a config that + // includes EGL_SURFACE_TYPE, EGL_PBUFFER_BIT in HeadlessDisplay. + const EGLint surfAttribs[] = { + EGL_WIDTH, 8, + EGL_HEIGHT, 8, + EGL_LARGEST_PBUFFER, EGL_TRUE, + EGL_NONE + }; + + glSurface = eglCreatePbufferSurface(display, config, surfAttribs); + if (glSurface == EGL_NO_SURFACE) { + throw std::runtime_error("Could not create surface: " + std::to_string(eglGetError())); + } + } + + ~EGLImpl() { + if (glSurface != EGL_NO_SURFACE) { + if (!eglDestroySurface(display, glSurface)) { + throw std::runtime_error("Failed to destroy EGL surface.\n"); + } + glSurface = EGL_NO_SURFACE; + } + if (!eglDestroyContext(display, glContext)) { + throw std::runtime_error("Failed to destroy EGL context.\n"); + } + } + + void activateContext() final { + if (!eglMakeCurrent(display, glSurface, glSurface, glContext)) { + throw std::runtime_error("Switching OpenGL context failed.\n"); + } + } + + void deactivateContext() final { + if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) { + throw std::runtime_error("Removing OpenGL context failed.\n"); + } + } + + EGLContext glContext = EGL_NO_CONTEXT; + EGLDisplay display = EGL_NO_DISPLAY; + EGLConfig config = 0; + EGLSurface glSurface = EGL_NO_SURFACE; +}; + +gl::ProcAddress HeadlessBackend::initializeExtension(const char* name) { + return eglGetProcAddress(name); +} + +bool HeadlessBackend::hasDisplay() { + if (!display) { + display.reset(new HeadlessDisplay); + } + return bool(display); +}; + +void HeadlessBackend::createContext() { + assert(!hasContext()); + assert(hasDisplay()); + + EGLDisplay display_ = display->attribute(); + EGLConfig& config = display->attribute(); + + // EGL initializes the context client version to 1 by default. We want to + // use OpenGL ES 2.0 which has the ability to create shader and program + // objects and also to write vertex and fragment shaders in the OpenGL ES + // Shading Language. + const EGLint attribs[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + + EGLContext glContext = eglCreateContext(display_, config, EGL_NO_CONTEXT, attribs); + if (glContext == EGL_NO_CONTEXT) { + mbgl::Log::Error(mbgl::Event::OpenGL, "eglCreateContext() returned error 0x%04x", + eglGetError()); + throw std::runtime_error("Error creating the EGL context object.\n"); + } + + impl.reset(new EGLImpl(glContext, display_, config)); +} + +} // namespace mbgl diff --git a/platform/default/headless_display_egl.cpp b/platform/default/headless_display_egl.cpp new file mode 100644 index 0000000000..03c8e16a59 --- /dev/null +++ b/platform/default/headless_display_egl.cpp @@ -0,0 +1,65 @@ +#include +#include +#include + +#include + +namespace mbgl { + +class HeadlessDisplay::Impl { +public: + Impl(); + ~Impl(); + + EGLDisplay display = EGL_NO_DISPLAY; + EGLConfig config = 0; +}; + +HeadlessDisplay::Impl::Impl() { + display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (display == EGL_NO_DISPLAY) { + throw std::runtime_error("Failed to obtain a valid EGL display.\n"); + } + + EGLint major, minor, numConfigs; + if (!eglInitialize(display, &major, &minor)) { + throw std::runtime_error("eglInitialize() failed.\n"); + } + + if (!eglBindAPI(EGL_OPENGL_ES_API)) { + mbgl::Log::Error(mbgl::Event::OpenGL, "eglBindAPI(EGL_OPENGL_ES_API) returned error %d", eglGetError()); + throw std::runtime_error("eglBindAPI() failed"); + } + + const EGLint attribs[] = { + EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, + EGL_NONE + }; + + if (!eglChooseConfig(display, attribs, &config, 1, &numConfigs) || numConfigs != 1) { + throw std::runtime_error("Failed to choose ARGB config.\n"); + } +} + +HeadlessDisplay::Impl::~Impl() { + eglTerminate(display); +} + +template <> +EGLDisplay HeadlessDisplay::attribute() const { + return impl->display; +} + +template <> +EGLConfig& HeadlessDisplay::attribute() const { + return impl->config; +} + +HeadlessDisplay::HeadlessDisplay() + : impl(std::make_unique()) { +} + +HeadlessDisplay::~HeadlessDisplay() { +} + +} // namespace mbgl diff --git a/platform/glfw/glfw_view.cpp b/platform/glfw/glfw_view.cpp index 9e21476485..78356dc651 100644 --- a/platform/glfw/glfw_view.cpp +++ b/platform/glfw/glfw_view.cpp @@ -37,13 +37,19 @@ GLFWView::GLFWView(bool fullscreen_, bool benchmark_) height = videoMode->height; } +#if __APPLE__ glfwWindowHint(GLFW_COCOA_GRAPHICS_SWITCHING, GL_TRUE); +#endif + +#if MBGL_WITH_EGL + glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API); +#endif #ifdef DEBUG glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE); #endif -#ifdef GL_ES_VERSION_2_0 +#if MBGL_USE_GLES2 glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); @@ -536,7 +542,7 @@ void GLFWView::setWindowTitle(const std::string& title) { namespace mbgl { namespace platform { -#ifndef GL_ES_VERSION_2_0 +#ifndef MBGL_USE_GLES2 void showDebugImage(std::string name, const char *data, size_t width, size_t height) { glfwInit(); diff --git a/platform/ios/config.cmake b/platform/ios/config.cmake index fdb286a6d1..16477c7d65 100644 --- a/platform/ios/config.cmake +++ b/platform/ios/config.cmake @@ -1,4 +1,4 @@ -add_definitions(-DMBGL_USE_GLES2=1) +set(USE_GLES2 ON) mason_use(icu VERSION 58.1-min-size) diff --git a/platform/linux/config.cmake b/platform/linux/config.cmake index 90b14a862d..827602366a 100644 --- a/platform/linux/config.cmake +++ b/platform/linux/config.cmake @@ -1,4 +1,4 @@ -mason_use(glfw VERSION 2017-02-09-77a8f10) +mason_use(glfw VERSION 2017-04-07-f40d085) mason_use(mesa VERSION 13.0.4) mason_use(boost_libprogram_options VERSION 1.62.0${MASON_CXXABI_SUFFIX}) mason_use(sqlite VERSION 3.14.2) @@ -10,15 +10,17 @@ mason_use(webp VERSION 0.5.1) mason_use(gtest VERSION 1.8.0${MASON_CXXABI_SUFFIX}) mason_use(benchmark VERSION 1.0.0-1) mason_use(icu VERSION 58.1-min-size) +if(WITH_SWIFTSHADER) + mason_use(swiftshader VERSION 2017-04-08) +endif() # Link with libuv. This is not part of loop-uv.cmake because loop-uv.cmake is also # used by node.cmake, where we want to link with the libuv provided by node itself. target_add_mason_package(mbgl-loop-uv PUBLIC libuv) macro(mbgl_platform_core) - target_add_mason_package(mbgl-core PUBLIC mesa) - if(WITH_OSMESA) + target_add_mason_package(mbgl-core PUBLIC mesa) target_sources(mbgl-core PRIVATE platform/default/headless_backend_osmesa.cpp PRIVATE platform/default/mbgl/gl/headless_display.cpp @@ -28,15 +30,21 @@ macro(mbgl_platform_core) ) elseif(WITH_EGL) target_sources(mbgl-core - PRIVATE platform/linux/src/headless_backend_egl.cpp - PRIVATE platform/linux/src/headless_display_egl.cpp - ) - target_link_libraries(mbgl-core - PUBLIC -lGLESv2 - PUBLIC -lEGL - PUBLIC -lgbm + PRIVATE platform/default/headless_backend_egl.cpp + PRIVATE platform/default/headless_display_egl.cpp ) + if(WITH_SWIFTSHADER) + target_add_mason_package(mbgl-core PRIVATE swiftshader) + else() + target_add_mason_package(mbgl-core PUBLIC mesa) + target_link_libraries(mbgl-core + PUBLIC -lGLESv2 + PUBLIC -lEGL + PUBLIC -lgbm + ) + endif() else() + target_add_mason_package(mbgl-core PUBLIC mesa) target_sources(mbgl-core PRIVATE platform/linux/src/headless_backend_glx.cpp PRIVATE platform/linux/src/headless_display_glx.cpp @@ -173,3 +181,29 @@ endmacro() macro(mbgl_platform_node) # Enabling node module by defining this macro endmacro() + + +macro(mbgl_platform_set_swiftshader_rpath TARGET) + # Add the GLES headers to the include path when building with SwiftShader. + target_include_directories(${TARGET} + PRIVATE "${MASON_PACKAGE_swiftshader_INCLUDE_DIRS}" + ) + + # Change the embedded rpath so that it looks in the folder where the executable is. + # CMake adds an absolute rpath by default and only removes it during the install phase. + # Instead, we're forcing it to use the actual "install" rpath. That means we also have to + # make sure that libEGL.so and libGLESv2.so actually exist in the binary location, hence the + # copy command below. + set_target_properties(${TARGET} PROPERTIES + BUILD_WITH_INSTALL_RPATH TRUE + INSTALL_RPATH "\$ORIGIN/" + ) + + # Copy libEGL.so and libGLESv2.so over to the executable's folder, because this is + # where ld.so will be looking for, given that we've set the rpath above. + add_custom_command( + TARGET ${TARGET} + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${MASON_PACKAGE_swiftshader_PREFIX}/lib/*.so $ + ) +endmacro() diff --git a/platform/linux/src/headless_backend_egl.cpp b/platform/linux/src/headless_backend_egl.cpp deleted file mode 100644 index d98b2edc03..0000000000 --- a/platform/linux/src/headless_backend_egl.cpp +++ /dev/null @@ -1,101 +0,0 @@ -#include -#include - -#include - -#include - -#include - -namespace mbgl { - -struct EGLImpl : public HeadlessBackend::Impl { - EGLImpl(EGLContext glContext_, EGLDisplay display_, EGLConfig config_) - : glContext(glContext_), - display(display_), - config(config_) { - // Create a dummy pbuffer. We will render to framebuffers anyway, but we need a pbuffer to - // activate the context. - // Note that to be able to create pbuffer surfaces, we need to choose a config that - // includes EGL_SURFACE_TYPE, EGL_PBUFFER_BIT in HeadlessDisplay. - const EGLint surfAttribs[] = { - EGL_WIDTH, 8, - EGL_HEIGHT, 8, - EGL_LARGEST_PBUFFER, EGL_TRUE, - EGL_NONE - }; - - glSurface = eglCreatePbufferSurface(display, config, surfAttribs); - if (glSurface == EGL_NO_SURFACE) { - throw std::runtime_error("Could not create surface: " + std::to_string(eglGetError())); - } - } - - ~EGLImpl() { - if (glSurface != EGL_NO_SURFACE) { - if (!eglDestroySurface(display, glSurface)) { - throw std::runtime_error("Failed to destroy EGL surface.\n"); - } - glSurface = EGL_NO_SURFACE; - } - if (!eglDestroyContext(display, glContext)) { - throw std::runtime_error("Failed to destroy EGL context.\n"); - } - } - - void activateContext() final { - if (!eglMakeCurrent(display, glSurface, glSurface, glContext)) { - throw std::runtime_error("Switching OpenGL context failed.\n"); - } - } - - void deactivateContext() final { - if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) { - throw std::runtime_error("Removing OpenGL context failed.\n"); - } - } - - EGLContext glContext = EGL_NO_CONTEXT; - EGLDisplay display = EGL_NO_DISPLAY; - EGLConfig config = 0; - EGLSurface glSurface = EGL_NO_SURFACE; -}; - -gl::ProcAddress HeadlessBackend::initializeExtension(const char* name) { - return eglGetProcAddress(name); -} - -bool HeadlessBackend::hasDisplay() { - if (!display) { - display.reset(new HeadlessDisplay); - } - return bool(display); -}; - -void HeadlessBackend::createContext() { - assert(!hasContext()); - assert(hasDisplay()); - - EGLDisplay display_ = display->attribute(); - EGLConfig& config = display->attribute(); - - // EGL initializes the context client version to 1 by default. We want to - // use OpenGL ES 2.0 which has the ability to create shader and program - // objects and also to write vertex and fragment shaders in the OpenGL ES - // Shading Language. - const EGLint attribs[] = { - EGL_CONTEXT_CLIENT_VERSION, 2, - EGL_NONE - }; - - EGLContext glContext = eglCreateContext(display_, config, EGL_NO_CONTEXT, attribs); - if (glContext == EGL_NO_CONTEXT) { - mbgl::Log::Error(mbgl::Event::OpenGL, "eglCreateContext() returned error 0x%04x", - eglGetError()); - throw std::runtime_error("Error creating the EGL context object.\n"); - } - - impl.reset(new EGLImpl(glContext, display_, config)); -} - -} // namespace mbgl diff --git a/platform/linux/src/headless_display_egl.cpp b/platform/linux/src/headless_display_egl.cpp deleted file mode 100644 index 03c8e16a59..0000000000 --- a/platform/linux/src/headless_display_egl.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include -#include -#include - -#include - -namespace mbgl { - -class HeadlessDisplay::Impl { -public: - Impl(); - ~Impl(); - - EGLDisplay display = EGL_NO_DISPLAY; - EGLConfig config = 0; -}; - -HeadlessDisplay::Impl::Impl() { - display = eglGetDisplay(EGL_DEFAULT_DISPLAY); - if (display == EGL_NO_DISPLAY) { - throw std::runtime_error("Failed to obtain a valid EGL display.\n"); - } - - EGLint major, minor, numConfigs; - if (!eglInitialize(display, &major, &minor)) { - throw std::runtime_error("eglInitialize() failed.\n"); - } - - if (!eglBindAPI(EGL_OPENGL_ES_API)) { - mbgl::Log::Error(mbgl::Event::OpenGL, "eglBindAPI(EGL_OPENGL_ES_API) returned error %d", eglGetError()); - throw std::runtime_error("eglBindAPI() failed"); - } - - const EGLint attribs[] = { - EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, - EGL_NONE - }; - - if (!eglChooseConfig(display, attribs, &config, 1, &numConfigs) || numConfigs != 1) { - throw std::runtime_error("Failed to choose ARGB config.\n"); - } -} - -HeadlessDisplay::Impl::~Impl() { - eglTerminate(display); -} - -template <> -EGLDisplay HeadlessDisplay::attribute() const { - return impl->display; -} - -template <> -EGLConfig& HeadlessDisplay::attribute() const { - return impl->config; -} - -HeadlessDisplay::HeadlessDisplay() - : impl(std::make_unique()) { -} - -HeadlessDisplay::~HeadlessDisplay() { -} - -} // namespace mbgl diff --git a/platform/macos/config.cmake b/platform/macos/config.cmake index 8dc3c38245..b732309c0d 100644 --- a/platform/macos/config.cmake +++ b/platform/macos/config.cmake @@ -1,10 +1,13 @@ set(CMAKE_OSX_DEPLOYMENT_TARGET 10.10) -mason_use(glfw VERSION 2017-02-09-77a8f10) +mason_use(glfw VERSION 2017-04-07-f40d085) mason_use(boost_libprogram_options VERSION 1.62.0) mason_use(gtest VERSION 1.8.0) mason_use(benchmark VERSION 1.0.0-1) mason_use(icu VERSION 58.1-min-size) +if(WITH_SWIFTSHADER) + mason_use(swiftshader VERSION 2017-04-08) +endif() include(cmake/loop-darwin.cmake) @@ -47,9 +50,7 @@ macro(mbgl_platform_core) # Headless view PRIVATE platform/default/mbgl/gl/headless_backend.cpp PRIVATE platform/default/mbgl/gl/headless_backend.hpp - PRIVATE platform/darwin/src/headless_backend_cgl.cpp PRIVATE platform/default/mbgl/gl/headless_display.hpp - PRIVATE platform/darwin/src/headless_display_cgl.cpp PRIVATE platform/default/mbgl/gl/offscreen_view.cpp PRIVATE platform/default/mbgl/gl/offscreen_view.hpp @@ -77,12 +78,25 @@ macro(mbgl_platform_core) PUBLIC "-lz" PUBLIC "-framework Foundation" PUBLIC "-framework CoreGraphics" - PUBLIC "-framework OpenGL" PUBLIC "-framework ImageIO" PUBLIC "-framework CoreServices" PUBLIC "-framework SystemConfiguration" PUBLIC "-lsqlite3" ) + + if(WITH_SWIFTSHADER) + target_sources(mbgl-core + PRIVATE platform/default/headless_backend_egl.cpp + PRIVATE platform/default/headless_display_egl.cpp + ) + target_add_mason_package(mbgl-core PRIVATE swiftshader) + else() + target_sources(mbgl-core + PRIVATE platform/darwin/src/headless_backend_cgl.cpp + PRIVATE platform/darwin/src/headless_display_cgl.cpp + ) + target_link_libraries(mbgl-core PUBLIC "-framework OpenGL") + endif() endmacro() @@ -127,6 +141,7 @@ macro(mbgl_platform_test) ) endmacro() + macro(mbgl_platform_benchmark) target_compile_options(mbgl-benchmark PRIVATE -fvisibility=hidden @@ -147,6 +162,7 @@ macro(mbgl_platform_benchmark) ) endmacro() + macro(mbgl_platform_node) target_compile_options(mbgl-node PRIVATE -fvisibility=hidden @@ -156,3 +172,27 @@ macro(mbgl_platform_node) PRIVATE "-Wl,-bind_at_load" ) endmacro() + + +macro(mbgl_platform_set_swiftshader_rpath TARGET) + # Add the GLES headers to the include path when building with SwiftShader. + target_include_directories(${TARGET} + PRIVATE "${MASON_PACKAGE_swiftshader_INCLUDE_DIRS}" + ) + + # Change the embedded rpath so that it looks in the folder where the executable is. + # However, node modules are loaded from another executable, so instead, we want the rpath to + # be the folder where the node module is located, so we're using @loader_path here instead. + # For applications, @loader_path is the same as @executable_path. + set_target_properties(${TARGET} PROPERTIES + XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@loader_path/" + ) + + # Copy libEGL.dylib and libGLESv2.dylib over to the executable's folder, because this is + # where dyld will be looking for, given that we've set the rpath above. + add_custom_command( + TARGET ${TARGET} + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${MASON_PACKAGE_swiftshader_PREFIX}/lib/*.dylib $ + ) +endmacro() diff --git a/platform/macos/scripts/create_scheme.sh b/platform/macos/scripts/create_scheme.sh index 5a609130d8..4424f1a747 100755 --- a/platform/macos/scripts/create_scheme.sh +++ b/platform/macos/scripts/create_scheme.sh @@ -2,8 +2,7 @@ set -u -XCODEPROJ=${XCODEPROJ:-build/macos/mbgl.xcodeproj} -OUTPUT="${XCODEPROJ}/xcshareddata/xcschemes/${SCHEME_NAME}.xcscheme" +OUTPUT="${MACOS_PROJ_PATH}/xcshareddata/xcschemes/${SCHEME_NAME}.xcscheme" # Required ENV vars: # - SCHEME_TYPE: type of the scheme @@ -26,13 +25,13 @@ BLUEPRINT_ID=${BLUEPRINT_ID:-$(hexdump -n 12 -v -e '/1 "%02X"' /dev/urandom)} BUILDABLE_NAME=${BUILDABLE_NAME:-${SCHEME_NAME}} BLUEPRINT_NAME=${BLUEPRINT_NAME:-${SCHEME_NAME}} -mkdir -p "${XCODEPROJ}/xcshareddata/xcschemes" +mkdir -p "${MACOS_PROJ_PATH}/xcshareddata/xcschemes" sed "\ s#{{BLUEPRINT_ID}}#${BLUEPRINT_ID}#;\ s#{{BLUEPRINT_NAME}}#${BLUEPRINT_NAME}#;\ s#{{BUILDABLE_NAME}}#${BUILDABLE_NAME}#;\ -s#{{CONTAINER}}#${XCODEPROJ}#;\ +s#{{CONTAINER}}#${MACOS_PROJ_PATH}#;\ s#{{MAPBOX_ACCESS_TOKEN}}#${MAPBOX_ACCESS_TOKEN}#;\ s#{{WORKING_DIRECTORY}}#$(pwd)#;\ s#{{NODE_PATH}}#$(dirname `which node`)#;\ diff --git a/scripts/generate-shaders.js b/scripts/generate-shaders.js index cffe9d3854..9207a0aac5 100755 --- a/scripts/generate-shaders.js +++ b/scripts/generate-shaders.js @@ -59,7 +59,7 @@ ${fragmentPrelude} 'symbol_sdf' ].forEach(function (shaderName) { function applyPragmas(source, pragmas) { - return source.replace(/#pragma mapbox: ([\w]+) ([\w]+) ([\w]+) ([\w]+)/g, (match, operation, precision, type, name) => { + return source.replace(/#pragma mapbox: ([\w_]+) ([\w]+) ([\w]+) ([\w]+)/g, (match, operation, precision, type, name) => { const a_type = type === "float" ? "vec2" : "vec4"; return pragmas[operation] .join("\n") @@ -78,8 +78,15 @@ ${fragmentPrelude} "attribute {precision} {a_type} a_{name};", "varying {precision} {type} {name};" ], + define_in: [ + "uniform lowp float a_{name}_t;", + "attribute {precision} {a_type} a_{name};", + ], initialize: [ "{name} = unpack_mix_{a_type}(a_{name}, a_{name}_t);" + ], + initialize_in: [ + "{precision} {type} {name} = unpack_mix_{a_type}(a_{name}, a_{name}_t);" ] }); } diff --git a/src/mbgl/gl/gl.hpp b/src/mbgl/gl/gl.hpp index 3e21731330..3bb3df4927 100644 --- a/src/mbgl/gl/gl.hpp +++ b/src/mbgl/gl/gl.hpp @@ -3,7 +3,11 @@ #include #include -#if __APPLE__ +#if MBGL_USE_GLES2 && (!__APPLE__ || MBGL_WITH_EGL) + #define GL_GLEXT_PROTOTYPES + #include + #include +#elif __APPLE__ #include "TargetConditionals.h" #if TARGET_OS_IPHONE #include @@ -18,10 +22,6 @@ #else #error Unsupported Apple platform #endif -#elif __ANDROID__ || MBGL_USE_GLES2 - #define GL_GLEXT_PROTOTYPES - #include - #include #elif __QT__ && QT_VERSION >= 0x050000 #define GL_GLEXT_PROTOTYPES #include diff --git a/src/mbgl/shaders/line.cpp b/src/mbgl/shaders/line.cpp index 4392bd051f..e101cf6ee1 100644 --- a/src/mbgl/shaders/line.cpp +++ b/src/mbgl/shaders/line.cpp @@ -44,17 +44,15 @@ attribute lowp vec2 a_opacity; varying lowp float opacity; uniform lowp float a_gapwidth_t; attribute mediump vec2 a_gapwidth; -varying mediump float gapwidth; uniform lowp float a_offset_t; attribute lowp vec2 a_offset; -varying lowp float offset; void main() { color = unpack_mix_vec4(a_color, a_color_t); blur = unpack_mix_vec2(a_blur, a_blur_t); opacity = unpack_mix_vec2(a_opacity, a_opacity_t); - gapwidth = unpack_mix_vec2(a_gapwidth, a_gapwidth_t); - offset = unpack_mix_vec2(a_offset, a_offset_t); + mediump float gapwidth = unpack_mix_vec2(a_gapwidth, a_gapwidth_t); + lowp float offset = unpack_mix_vec2(a_offset, a_offset_t); vec2 a_extrude = a_data.xy - 128.0; float a_direction = mod(a_data.z, 4.0) - 1.0; diff --git a/src/mbgl/shaders/line_pattern.cpp b/src/mbgl/shaders/line_pattern.cpp index f52a8e2157..79433b53a0 100644 --- a/src/mbgl/shaders/line_pattern.cpp +++ b/src/mbgl/shaders/line_pattern.cpp @@ -44,16 +44,14 @@ attribute lowp vec2 a_opacity; varying lowp float opacity; uniform lowp float a_offset_t; attribute lowp vec2 a_offset; -varying lowp float offset; uniform lowp float a_gapwidth_t; attribute mediump vec2 a_gapwidth; -varying mediump float gapwidth; void main() { blur = unpack_mix_vec2(a_blur, a_blur_t); opacity = unpack_mix_vec2(a_opacity, a_opacity_t); - offset = unpack_mix_vec2(a_offset, a_offset_t); - gapwidth = unpack_mix_vec2(a_gapwidth, a_gapwidth_t); + lowp float offset = unpack_mix_vec2(a_offset, a_offset_t); + mediump float gapwidth = unpack_mix_vec2(a_gapwidth, a_gapwidth_t); vec2 a_extrude = a_data.xy - 128.0; float a_direction = mod(a_data.z, 4.0) - 1.0; diff --git a/src/mbgl/shaders/line_sdf.cpp b/src/mbgl/shaders/line_sdf.cpp index 17a6a19739..4f6cf814f9 100644 --- a/src/mbgl/shaders/line_sdf.cpp +++ b/src/mbgl/shaders/line_sdf.cpp @@ -52,17 +52,15 @@ attribute lowp vec2 a_opacity; varying lowp float opacity; uniform lowp float a_gapwidth_t; attribute mediump vec2 a_gapwidth; -varying mediump float gapwidth; uniform lowp float a_offset_t; attribute lowp vec2 a_offset; -varying lowp float offset; void main() { color = unpack_mix_vec4(a_color, a_color_t); blur = unpack_mix_vec2(a_blur, a_blur_t); opacity = unpack_mix_vec2(a_opacity, a_opacity_t); - gapwidth = unpack_mix_vec2(a_gapwidth, a_gapwidth_t); - offset = unpack_mix_vec2(a_offset, a_offset_t); + mediump float gapwidth = unpack_mix_vec2(a_gapwidth, a_gapwidth_t); + lowp float offset = unpack_mix_vec2(a_offset, a_offset_t); vec2 a_extrude = a_data.xy - 128.0; float a_direction = mod(a_data.z, 4.0) - 1.0; diff --git a/src/mbgl/shaders/preludes.cpp b/src/mbgl/shaders/preludes.cpp index cca0f3e3f1..95fa624e8d 100644 --- a/src/mbgl/shaders/preludes.cpp +++ b/src/mbgl/shaders/preludes.cpp @@ -48,8 +48,9 @@ vec4 evaluate_zoom_function_4(const vec4 value0, const vec4 value1, const vec4 v // packed like so: // packedValue = floor(input[0]) * 256 + input[1], vec2 unpack_float(const float packedValue) { - float v0 = floor(packedValue / 256.0); - return vec2(v0, packedValue - v0 * 256.0); + int packedIntValue = int(packedValue); + int v0 = packedIntValue / 256; + return vec2(v0, packedIntValue - v0 * 256); } -- cgit v1.2.1