diff --git a/src/Magnum/Context.cpp b/src/Magnum/Context.cpp index a82b8ae7c..7818d1cad 100644 --- a/src/Magnum/Context.cpp +++ b/src/Magnum/Context.cpp @@ -402,10 +402,19 @@ const std::vector& Extension::extensions(Version version) { Context* Context::_current = nullptr; -Context::Context(void functionLoader()) { +Context::Context(NoCreateT, void functionLoader()) { /* Load GL function pointers */ if(functionLoader) functionLoader(); + /* Nothing else, waiting for create() to be called */ +} + +Context::Context(void functionLoader()): Context{NoCreateT{}, functionLoader} { + /* Hard exit if the context cannot be created */ + if(!create()) std::exit(1); +} + +bool Context::create() { GLint majorVersion, minorVersion; /* Get version on ES 3.0+/WebGL 2.0+ */ @@ -421,7 +430,7 @@ Context::Context(void functionLoader()) { const std::string version = versionString(); if(version.find("WebGL 2") == std::string::npos) { Error() << "Context: unsupported version string:" << version; - std::exit(65); + return false; } majorVersion = 3; minorVersion = 0; @@ -442,7 +451,7 @@ Context::Context(void functionLoader()) { { #ifndef MAGNUM_TARGET_GLES2 CORRADE_ASSERT(versionNumberError == Renderer::Error::InvalidEnum, - "Context: cannot retrieve OpenGL version:" << versionNumberError, ); + "Context: cannot retrieve OpenGL version:" << versionNumberError, false); #endif /* Allow ES2 context on driver that reports ES3 as supported */ @@ -467,7 +476,7 @@ Context::Context(void functionLoader()) { #endif } else { Error() << "Context: unsupported version string:" << version; - std::exit(65); + return false; } } #endif @@ -479,7 +488,7 @@ Context::Context(void functionLoader()) { #ifndef CORRADE_NO_ASSERT const auto error = Renderer::error(); CORRADE_ASSERT(error == Renderer::Error::NoError, - "Context: cannot retrieve OpenGL version:" << error, ); + "Context: cannot retrieve OpenGL version:" << error, false); #endif /* Check that the version is supported (now it probably is, but be sure) */ @@ -496,7 +505,7 @@ Context::Context(void functionLoader()) { #else Error() << "Context: unsupported OpenGL ES version" << std::make_pair(majorVersion, minorVersion); #endif - std::exit(66); + return false; } /* Context flags are supported since GL 3.0 */ @@ -572,7 +581,7 @@ Context::Context(void functionLoader()) { setupDriverWorkarounds(); /* Set this context as current */ - CORRADE_ASSERT(!_current, "Context: Another context currently active", ); + CORRADE_ASSERT(!_current, "Context: Another context currently active", false); _current = this; /* Print some info and initialize state tracker (which also prints some @@ -585,6 +594,9 @@ Context::Context(void functionLoader()) { /** @todo Get rid of these */ DefaultFramebuffer::initializeContextBasedFunctionality(*this); Renderer::initializeContextBasedFunctionality(); + + /* Everything okay */ + return true; } Context::Context(Context&& other): _version{std::move(other._version)}, diff --git a/src/Magnum/Context.h b/src/Magnum/Context.h index 239d34f9e..d0391a7e7 100644 --- a/src/Magnum/Context.h +++ b/src/Magnum/Context.h @@ -37,6 +37,7 @@ #include "Magnum/Magnum.h" #include "Magnum/OpenGL.h" +#include "Magnum/Tags.h" #include "Magnum/visibility.h" #include "MagnumExternal/Optional/optional.hpp" @@ -464,8 +465,11 @@ class MAGNUM_EXPORT Context { private: static Context* _current; + explicit Context(NoCreateT, void functionLoader()); explicit Context(void functionLoader()); + bool create(); + /* Defined in Implementation/driverSpecific.cpp */ MAGNUM_LOCAL void setupDriverWorkarounds(); diff --git a/src/Magnum/Platform/AbstractXApplication.cpp b/src/Magnum/Platform/AbstractXApplication.cpp index f926abc5f..d284b48ff 100644 --- a/src/Magnum/Platform/AbstractXApplication.cpp +++ b/src/Magnum/Platform/AbstractXApplication.cpp @@ -95,8 +95,8 @@ bool AbstractXApplication::tryCreateContext(const Configuration& configuration) /* Set OpenGL context as current */ _contextHandler->makeCurrent(); - _context.reset(new Platform::Context); - return true; + /* Return true if the initialization succeeds */ + return !!(_context = Platform::Context::tryCreate()); } AbstractXApplication::~AbstractXApplication() { diff --git a/src/Magnum/Platform/AndroidApplication.cpp b/src/Magnum/Platform/AndroidApplication.cpp index c61d2c379..bc5b5577e 100644 --- a/src/Magnum/Platform/AndroidApplication.cpp +++ b/src/Magnum/Platform/AndroidApplication.cpp @@ -136,8 +136,8 @@ bool AndroidApplication::tryCreateContext(const Configuration& configuration) { /* Make the context current */ CORRADE_INTERNAL_ASSERT_OUTPUT(eglMakeCurrent(_display, _surface, _surface, _glContext)); - _context.reset(new Platform::Context); - return true; + /* Return true if the initialization succeeds */ + return !!(_context = Platform::Context::tryCreate()); } void AndroidApplication::swapBuffers() { diff --git a/src/Magnum/Platform/Context.h b/src/Magnum/Platform/Context.h index 32c39c7dd..bfac9d7c6 100644 --- a/src/Magnum/Platform/Context.h +++ b/src/Magnum/Platform/Context.h @@ -41,12 +41,26 @@ information. */ class Context: public Magnum::Context { public: + /** + * @brief Try to create the context + * + * Unline @ref Context(), this function returns `nullptr` on error + * instead of application exit and thus is usable for context creation + * fallbacks. + */ + static std::unique_ptr tryCreate() { + std::unique_ptr c{new Context{NoCreate}}; + return c->create() ? std::move(c) : nullptr; + } + /** * @brief Constructor * * Does initial setup, loads OpenGL function pointers using * platform-specific API, detects available features and enables them - * throughout the engine. + * throughout the engine. If detected version is unsupported or any + * other error occurs, a message is printed to output and the + * application exits. See @ref tryCreate() for an alternative. * @see @fn_gl{Get} with @def_gl{MAJOR_VERSION}, @def_gl{MINOR_VERSION}, * @def_gl{CONTEXT_FLAGS}, @def_gl{NUM_EXTENSIONS}, * @fn_gl{GetString} with @def_gl{EXTENSIONS} @@ -57,6 +71,14 @@ class Context: public Magnum::Context { #else Magnum::Context{nullptr} {} #endif + + private: + explicit Context(NoCreateT): + #if !defined(CORRADE_TARGET_EMSCRIPTEN) && !defined(CORRADE_TARGET_NACL) + Magnum::Context{NoCreate, flextGLInit} {} + #else + Magnum::Context{NoCreate, nullptr} {} + #endif }; }} diff --git a/src/Magnum/Platform/GlutApplication.cpp b/src/Magnum/Platform/GlutApplication.cpp index f3a49ae70..6a65c4b4d 100644 --- a/src/Magnum/Platform/GlutApplication.cpp +++ b/src/Magnum/Platform/GlutApplication.cpp @@ -96,8 +96,8 @@ bool GlutApplication::tryCreateContext(const Configuration& configuration) { glutMotionFunc(staticMouseMoveEvent); glutDisplayFunc(staticDrawEvent); - _context.reset(new Platform::Context); - return true; + /* Return true if the initialization succeeds */ + return !!(_context = Platform::Context::tryCreate()); } GlutApplication::~GlutApplication() = default; diff --git a/src/Magnum/Platform/NaClApplication.cpp b/src/Magnum/Platform/NaClApplication.cpp index 4ad50972f..8cc096abc 100644 --- a/src/Magnum/Platform/NaClApplication.cpp +++ b/src/Magnum/Platform/NaClApplication.cpp @@ -112,8 +112,8 @@ bool NaClApplication::tryCreateContext(const Configuration& configuration) { RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE|PP_INPUTEVENT_CLASS_WHEEL); RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD); - _context.reset(new Platform::Context); - return true; + /* Return true if the initialization succeeds */ + return !!(_context = Platform::Context::tryCreate()); } NaClApplication::~NaClApplication() = default; diff --git a/src/Magnum/Platform/Sdl2Application.cpp b/src/Magnum/Platform/Sdl2Application.cpp index 4ca56e583..8cf2ce093 100644 --- a/src/Magnum/Platform/Sdl2Application.cpp +++ b/src/Magnum/Platform/Sdl2Application.cpp @@ -226,8 +226,8 @@ bool Sdl2Application::tryCreateContext(const Configuration& configuration) { _glContext = SDL_SetVideoMode(configuration.size().x(), configuration.size().y(), 24, SDL_OPENGL|SDL_HWSURFACE|SDL_DOUBLEBUF); #endif - _context.reset(new Platform::Context); - return true; + /* Return true if the initialization succeeds */ + return !!(_context = Platform::Context::tryCreate()); } void Sdl2Application::swapBuffers() { diff --git a/src/Magnum/Platform/WindowlessCglApplication.cpp b/src/Magnum/Platform/WindowlessCglApplication.cpp index b111c1a01..c24cccd43 100644 --- a/src/Magnum/Platform/WindowlessCglApplication.cpp +++ b/src/Magnum/Platform/WindowlessCglApplication.cpp @@ -96,8 +96,8 @@ bool WindowlessCglApplication::tryCreateContext(const Configuration&) { return false; } - _context.reset(new Platform::Context); - return true; + /* Return true if the initialization succeeds */ + return !!(_context = Platform::Context::tryCreate()); } WindowlessCglApplication::~WindowlessCglApplication() { diff --git a/src/Magnum/Platform/WindowlessGlxApplication.cpp b/src/Magnum/Platform/WindowlessGlxApplication.cpp index 731e70fa7..0155e91d2 100644 --- a/src/Magnum/Platform/WindowlessGlxApplication.cpp +++ b/src/Magnum/Platform/WindowlessGlxApplication.cpp @@ -145,8 +145,8 @@ bool WindowlessGlxApplication::tryCreateContext(const Configuration&) { return false; } - _context.reset(new Platform::Context); - return true; + /* Return true if the initialization succeeds */ + return !!(_context = Platform::Context::tryCreate()); } WindowlessGlxApplication::~WindowlessGlxApplication() { diff --git a/src/Magnum/Platform/WindowlessNaClApplication.cpp b/src/Magnum/Platform/WindowlessNaClApplication.cpp index b7dff7a45..9e34589c6 100644 --- a/src/Magnum/Platform/WindowlessNaClApplication.cpp +++ b/src/Magnum/Platform/WindowlessNaClApplication.cpp @@ -97,8 +97,8 @@ bool WindowlessNaClApplication::tryCreateContext(const Configuration&) { glSetCurrentContextPPAPI(graphics->pp_resource()); - c = new Platform::Context; - return true; + /* Return true if the initialization succeeds */ + return c = Platform::Context::tryCreate().release(); } WindowlessNaClApplication::~WindowlessNaClApplication() { diff --git a/src/Magnum/Platform/WindowlessWglApplication.cpp b/src/Magnum/Platform/WindowlessWglApplication.cpp index f4bad5cbf..a00983bfb 100644 --- a/src/Magnum/Platform/WindowlessWglApplication.cpp +++ b/src/Magnum/Platform/WindowlessWglApplication.cpp @@ -116,8 +116,8 @@ bool WindowlessWglApplication::tryCreateContext(const Configuration&) { return false; } - _context.reset(new Platform::Context); - return true; + /* Return true if the initialization succeeds */ + return !!(_context = Platform::Context::tryCreate()); } WindowlessWglApplication::~WindowlessWglApplication() { diff --git a/src/Magnum/Platform/WindowlessWindowsEglApplication.cpp b/src/Magnum/Platform/WindowlessWindowsEglApplication.cpp index 16807f8c5..30ccf4ee8 100644 --- a/src/Magnum/Platform/WindowlessWindowsEglApplication.cpp +++ b/src/Magnum/Platform/WindowlessWindowsEglApplication.cpp @@ -155,8 +155,8 @@ bool WindowlessWindowsEglApplication::tryCreateContext(const Configuration&) { return false; } - _context.reset(new Platform::Context); - return true; + /* Return true if the initialization succeeds */ + return !!(_context = Platform::Context::tryCreate()); } WindowlessWindowsEglApplication::~WindowlessWindowsEglApplication() {