diff --git a/CMakeLists.txt b/CMakeLists.txt index 172bf1f48..c508d6493 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -138,6 +138,11 @@ if(BUILD_DEPRECATED) set(MAGNUM_BUILD_DEPRECATED 1) endif() +option(BUILD_MULTITHREADED "Build in a way that makes it possible to use multiple thread-local Magnum contexts" ON) +if(BUILD_MULTITHREADED) + set(MAGNUM_BUILD_MULTITHREADED 1) +endif() + option(BUILD_STATIC "Build static libraries (default are shared)" OFF) option(BUILD_STATIC_PIC "Build static libraries and plugins with position-independent code" ON) option(BUILD_PLUGINS_STATIC "Build static plugins (default are dynamic)" OFF) diff --git a/doc/building.dox b/doc/building.dox index 06d589a87..c95322d85 100644 --- a/doc/building.dox +++ b/doc/building.dox @@ -173,6 +173,11 @@ available for desktop OpenGL only, see @ref requires-gl. Supported mainly on OpenGL ES drivers, for desktop OpenGL the only driver that supports this configuration is NVidia >= 355. +By default the engine is built in a way that allows having multiple +thread-local Magnum contents. This might cause some performance penalties -- if +you are sure that you will never need such feature, you can disable it via the +`BUILD_MULTITHREADED` option. + The features used can be conveniently detected in depending projects both in CMake and C++ sources, see @ref cmake and @ref Magnum/Magnum.h for more information. See also @ref corrade-cmake and @ref Corrade/Corrade.h for @@ -542,6 +547,10 @@ static libraries. You might also have problems using dynamic plugins, enable `BUILD_PLUGINS_STATIC` to build also plugins as static. OpenGL ES 2.0 is enabled by default, switch to 3.0 by disabling `TARGET_GLES2`. +Please note that `BUILD_MULTITHREADED` is supported only since Xcode 7.3 and +doesn't work on `i386` iOS Simulator, you need to disable it in order to build +for older platforms. + mkdir build-ios && cd build-ios cmake .. \ -DCMAKE_TOOLCHAIN_FILE=../toolchains/generic/iOS.cmake \ diff --git a/doc/cmake.dox b/doc/cmake.dox index 972858b2c..6cfca2b53 100644 --- a/doc/cmake.dox +++ b/doc/cmake.dox @@ -180,6 +180,8 @@ are also available as preprocessor variables if including included - `MAGNUM_BUILD_STATIC` -- Defined if compiled as static libraries. Default are shared libraries. +- `MAGNUM_BUILD_MULTITHREADED` -- Defined if compiled in a way that allows + having multiple thread-local Magnum contexts. The default. - `MAGNUM_TARGET_GLES` -- Defined if compiled for OpenGL ES - `MAGNUM_TARGET_GLES2` -- Defined if compiled for OpenGL ES 2.0 - `MAGNUM_TARGET_GLES3` -- Defined if compiled for OpenGL ES 3.0 diff --git a/modules/FindMagnum.cmake b/modules/FindMagnum.cmake index ef0058348..949d54a28 100644 --- a/modules/FindMagnum.cmake +++ b/modules/FindMagnum.cmake @@ -105,6 +105,8 @@ # MAGNUM_BUILD_DEPRECATED - Defined if compiled with deprecated APIs # included # MAGNUM_BUILD_STATIC - Defined if compiled as static libraries +# MAGNUM_BUILD_MULTITHREADED - Defined if compiled in a way that allows +# having multiple thread-local Magnum contexts # MAGNUM_TARGET_GLES - Defined if compiled for OpenGL ES # MAGNUM_TARGET_GLES2 - Defined if compiled for OpenGL ES 2.0 # MAGNUM_TARGET_GLES3 - Defined if compiled for OpenGL ES 3.0 @@ -206,6 +208,7 @@ file(READ ${_MAGNUM_CONFIGURE_FILE} _magnumConfigure) set(_magnumFlags BUILD_DEPRECATED BUILD_STATIC + BUILD_MULTITHREADED TARGET_GLES TARGET_GLES2 TARGET_GLES3 diff --git a/package/ci/travis.yml b/package/ci/travis.yml index 2aff509ea..b5792db8e 100644 --- a/package/ci/travis.yml +++ b/package/ci/travis.yml @@ -14,10 +14,12 @@ matrix: compiler: clang env: TARGET=desktop - os: osx + osx_image: xcode7.3 env: - TARGET=ios-simulator - TARGET_GLES2=ON - os: osx + osx_image: xcode7.3 env: - TARGET=ios-simulator - TARGET_GLES2=OFF @@ -59,13 +61,14 @@ install: - if [ "$TRAVIS_OS_NAME" == "linux" ]; then export PLATFORM_GL_API=GLX; fi - if [ "$TRAVIS_OS_NAME" == "osx" ]; then export PLATFORM_GL_API=CGL; fi - if [ "$TRAVIS_OS_NAME" == "osx" ] && [ "$TARGET" == "ios-simulator" ]; then gem install xcpretty; fi -- if [ "$TRAVIS_OS_NAME" == "osx" ] && [ "$TARGET" == "ios-simulator" ]; then brew upgrade cmake; fi +# Xcode 7.2 image doesn't have cmake installed using Homebrew, so we can't use `upgrade` +- if [ "$TRAVIS_OS_NAME" == "osx" ] && [ "$TARGET" == "ios-simulator" ]; then brew install cmake; fi - if [ "$TRAVIS_OS_NAME" == "osx" ] && [ "$TARGET" == "emscripten" ]; then brew install emscripten && export LLVM=/usr/local/opt/emscripten/libexec/llvm/bin && emcc; fi - if [ "$TARGET" == "desktop" ]; then printf "[General]\ndrivers=null" > ~/.alsoftrc; fi # SDL (cached) - if [ "$TRAVIS_OS_NAME" == "osx" ] && [ "$TARGET" == "desktop" ]; then brew install sdl2; fi -- if [ "$TRAVIS_OS_NAME" == "osx" ] && [ "$TARGET" == "ios-simulator" ]; then curl -O https://www.libsdl.org/release/SDL2-2.0.4.tar.gz && tar -xzvf SDL2-2.0.4.tar.gz && cd SDL2-2.0.4/Xcode-iOS/SDL && xcodebuild -sdk iphonesimulator8.1 | xcpretty && mkdir -p ../../../sdl2/lib && cp build/Release-iphonesimulator/libSDL2.a ../../../sdl2/lib && mkdir -p ../../../sdl2/include/SDL2 && cp -R ../../include/* ../../../sdl2/include/SDL2 && cd ../../..; fi +- if [ "$TRAVIS_OS_NAME" == "osx" ] && [ "$TARGET" == "ios-simulator" ]; then curl -O https://www.libsdl.org/release/SDL2-2.0.4.tar.gz && tar -xzvf SDL2-2.0.4.tar.gz && cd SDL2-2.0.4/Xcode-iOS/SDL && xcodebuild -sdk iphonesimulator9.3 | xcpretty && mkdir -p ../../../sdl2/lib && cp build/Release-iphonesimulator/libSDL2.a ../../../sdl2/lib && mkdir -p ../../../sdl2/include/SDL2 && cp -R ../../include/* ../../../sdl2/include/SDL2 && cd ../../..; fi - if [ "$TRAVIS_OS_NAME" == "linux" ] && [ ! -e "$HOME/sdl2/include" ]; then curl -O http://www.libsdl.org/release/SDL2-2.0.4.tar.gz && tar -xzvf SDL2-2.0.4.tar.gz && cd SDL2-2.0.4 && mkdir build && cd build && cmake .. -DCMAKE_INSTALL_PREFIX=$HOME/sdl2 -DCMAKE_BUILD_TYPE=Release && cmake --build . --target install && cd ../..; fi # GLFW (cached) diff --git a/src/Magnum/Context.cpp b/src/Magnum/Context.cpp index b922a3991..37c2dcaa8 100644 --- a/src/Magnum/Context.cpp +++ b/src/Magnum/Context.cpp @@ -409,13 +409,22 @@ const std::vector& Extension::extensions(Version version) { CORRADE_ASSERT_UNREACHABLE(); } -Context* Context::_current = nullptr; +namespace { + #ifdef MAGNUM_BUILD_MULTITHREADED + #if !defined(CORRADE_GCC47_COMPATIBILITY) && !defined(CORRADE_TARGET_APPLE) + thread_local + #else + __thread + #endif + #endif + Context* currentContext = nullptr; +} -bool Context::hasCurrent() { return _current; } +bool Context::hasCurrent() { return currentContext; } Context& Context::current() { - CORRADE_ASSERT(_current, "Context::current(): no current context", *_current); - return *_current; + CORRADE_ASSERT(currentContext, "Context::current(): no current context", *currentContext); + return *currentContext; } Context::Context(NoCreateT, Int argc, char** argv, void functionLoader()): _functionLoader{functionLoader}, _version{Version::None} { @@ -448,13 +457,13 @@ Context::Context(Context&& other): _version{std::move(other._version)}, _detectedDrivers{std::move(other._detectedDrivers)} { other._state = nullptr; - if(_current == &other) _current = this; + if(currentContext == &other) currentContext = this; } Context::~Context() { delete _state; - if(_current == this) _current = nullptr; + if(currentContext == this) currentContext = nullptr; } void Context::create() { @@ -640,8 +649,8 @@ bool Context::tryCreate() { setupDriverWorkarounds(); /* Set this context as current */ - CORRADE_ASSERT(!_current, "Context: Another context currently active", false); - _current = this; + CORRADE_ASSERT(!currentContext, "Context: Another context currently active", false); + currentContext = this; /* Print some info and initialize state tracker (which also prints some more info) */ diff --git a/src/Magnum/Context.h b/src/Magnum/Context.h index 8ce3b2521..5fe83d2be 100644 --- a/src/Magnum/Context.h +++ b/src/Magnum/Context.h @@ -244,6 +244,8 @@ class MAGNUM_EXPORT Context { /** * @brief Whether there is any current context * + * If Magnum is built with @ref MAGNUM_BUILD_MULTITHREADED, current + * context is thread-local instead of global (the default). * @see @ref current() */ static bool hasCurrent(); @@ -251,7 +253,9 @@ class MAGNUM_EXPORT Context { /** * @brief Current context * - * Expect that there is current context. + * Expect that there is current context. If Magnum is built with + * @ref MAGNUM_BUILD_MULTITHREADED, current context is thread-local + * instead of global (the default). * @see @ref hasCurrent() */ static Context& current(); @@ -501,8 +505,6 @@ class MAGNUM_EXPORT Context { Implementation::State& state() { return *_state; } private: - MAGNUM_LOCAL static Context* _current; - explicit Context(NoCreateT, Int argc, char** argv, void functionLoader()); bool tryCreate(); diff --git a/src/Magnum/Magnum.h b/src/Magnum/Magnum.h index a55936625..832ecf98e 100644 --- a/src/Magnum/Magnum.h +++ b/src/Magnum/Magnum.h @@ -91,6 +91,16 @@ Defined if built as static libraries. Default are shared libraries. #define MAGNUM_BUILD_STATIC #undef MAGNUM_BUILD_STATIC +/** +@brief Multi-threaded build + +Defined if the library is built in a way that allows multiple thread-local +Magnum contexts. Enabled by default. +@see @ref building, @ref cmake, @ref Context::current() +*/ +#define MAGNUM_BUILD_MULTITHREADED +#undef MAGNUM_BUILD_MULTITHREADED + /** @brief OpenGL ES target diff --git a/src/Magnum/Platform/magnum-info.cpp b/src/Magnum/Platform/magnum-info.cpp index 0c38fa460..a7bc1a027 100644 --- a/src/Magnum/Platform/magnum-info.cpp +++ b/src/Magnum/Platform/magnum-info.cpp @@ -246,6 +246,9 @@ MagnumInfo::MagnumInfo(const Arguments& arguments): Platform::WindowlessApplicat #ifdef MAGNUM_BUILD_STATIC Debug() << " MAGNUM_BUILD_STATIC"; #endif + #ifdef MAGNUM_BUILD_MULTITHREADED + Debug() << " MAGNUM_BUILD_MULTITHREADED"; + #endif #ifdef MAGNUM_TARGET_GLES Debug() << " MAGNUM_TARGET_GLES"; #endif diff --git a/src/Magnum/configure.h.cmake b/src/Magnum/configure.h.cmake index 54abfa21d..0026bbee1 100644 --- a/src/Magnum/configure.h.cmake +++ b/src/Magnum/configure.h.cmake @@ -25,6 +25,7 @@ #cmakedefine MAGNUM_BUILD_DEPRECATED #cmakedefine MAGNUM_BUILD_STATIC +#cmakedefine MAGNUM_BUILD_MULTITHREADED #cmakedefine MAGNUM_TARGET_GLES #cmakedefine MAGNUM_TARGET_GLES2 #cmakedefine MAGNUM_TARGET_GLES3