Browse Source

Ability to do GL context creation fallbacks even from Context constructor.

In some cases the GL context creation might success without error, but
the created version is one that we don't want (e.g. software GDI
rasterizer on Windows). Previously the Context class constructor just
exited the application and it was impossible to react on that from the
application side (for example reducing some context feature
requirements).

Now there is Platform::Context::tryCreate(), which returns either
created instance or `nullptr` if the instance creation failed with some
error. That is now used in all Platform::*Application implementations.
pull/116/head
Vladimír Vondruš 11 years ago
parent
commit
277828ea44
  1. 26
      src/Magnum/Context.cpp
  2. 4
      src/Magnum/Context.h
  3. 4
      src/Magnum/Platform/AbstractXApplication.cpp
  4. 4
      src/Magnum/Platform/AndroidApplication.cpp
  5. 24
      src/Magnum/Platform/Context.h
  6. 4
      src/Magnum/Platform/GlutApplication.cpp
  7. 4
      src/Magnum/Platform/NaClApplication.cpp
  8. 4
      src/Magnum/Platform/Sdl2Application.cpp
  9. 4
      src/Magnum/Platform/WindowlessCglApplication.cpp
  10. 4
      src/Magnum/Platform/WindowlessGlxApplication.cpp
  11. 4
      src/Magnum/Platform/WindowlessNaClApplication.cpp
  12. 4
      src/Magnum/Platform/WindowlessWglApplication.cpp
  13. 4
      src/Magnum/Platform/WindowlessWindowsEglApplication.cpp

26
src/Magnum/Context.cpp

@ -402,10 +402,19 @@ const std::vector<Extension>& Extension::extensions(Version version) {
Context* Context::_current = nullptr; Context* Context::_current = nullptr;
Context::Context(void functionLoader()) { Context::Context(NoCreateT, void functionLoader()) {
/* Load GL function pointers */ /* Load GL function pointers */
if(functionLoader) functionLoader(); 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; GLint majorVersion, minorVersion;
/* Get version on ES 3.0+/WebGL 2.0+ */ /* Get version on ES 3.0+/WebGL 2.0+ */
@ -421,7 +430,7 @@ Context::Context(void functionLoader()) {
const std::string version = versionString(); const std::string version = versionString();
if(version.find("WebGL 2") == std::string::npos) { if(version.find("WebGL 2") == std::string::npos) {
Error() << "Context: unsupported version string:" << version; Error() << "Context: unsupported version string:" << version;
std::exit(65); return false;
} }
majorVersion = 3; majorVersion = 3;
minorVersion = 0; minorVersion = 0;
@ -442,7 +451,7 @@ Context::Context(void functionLoader()) {
{ {
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(versionNumberError == Renderer::Error::InvalidEnum, CORRADE_ASSERT(versionNumberError == Renderer::Error::InvalidEnum,
"Context: cannot retrieve OpenGL version:" << versionNumberError, ); "Context: cannot retrieve OpenGL version:" << versionNumberError, false);
#endif #endif
/* Allow ES2 context on driver that reports ES3 as supported */ /* Allow ES2 context on driver that reports ES3 as supported */
@ -467,7 +476,7 @@ Context::Context(void functionLoader()) {
#endif #endif
} else { } else {
Error() << "Context: unsupported version string:" << version; Error() << "Context: unsupported version string:" << version;
std::exit(65); return false;
} }
} }
#endif #endif
@ -479,7 +488,7 @@ Context::Context(void functionLoader()) {
#ifndef CORRADE_NO_ASSERT #ifndef CORRADE_NO_ASSERT
const auto error = Renderer::error(); const auto error = Renderer::error();
CORRADE_ASSERT(error == Renderer::Error::NoError, CORRADE_ASSERT(error == Renderer::Error::NoError,
"Context: cannot retrieve OpenGL version:" << error, ); "Context: cannot retrieve OpenGL version:" << error, false);
#endif #endif
/* Check that the version is supported (now it probably is, but be sure) */ /* Check that the version is supported (now it probably is, but be sure) */
@ -496,7 +505,7 @@ Context::Context(void functionLoader()) {
#else #else
Error() << "Context: unsupported OpenGL ES version" << std::make_pair(majorVersion, minorVersion); Error() << "Context: unsupported OpenGL ES version" << std::make_pair(majorVersion, minorVersion);
#endif #endif
std::exit(66); return false;
} }
/* Context flags are supported since GL 3.0 */ /* Context flags are supported since GL 3.0 */
@ -572,7 +581,7 @@ Context::Context(void functionLoader()) {
setupDriverWorkarounds(); setupDriverWorkarounds();
/* Set this context as current */ /* Set this context as current */
CORRADE_ASSERT(!_current, "Context: Another context currently active", ); CORRADE_ASSERT(!_current, "Context: Another context currently active", false);
_current = this; _current = this;
/* Print some info and initialize state tracker (which also prints some /* Print some info and initialize state tracker (which also prints some
@ -585,6 +594,9 @@ Context::Context(void functionLoader()) {
/** @todo Get rid of these */ /** @todo Get rid of these */
DefaultFramebuffer::initializeContextBasedFunctionality(*this); DefaultFramebuffer::initializeContextBasedFunctionality(*this);
Renderer::initializeContextBasedFunctionality(); Renderer::initializeContextBasedFunctionality();
/* Everything okay */
return true;
} }
Context::Context(Context&& other): _version{std::move(other._version)}, Context::Context(Context&& other): _version{std::move(other._version)},

4
src/Magnum/Context.h

@ -37,6 +37,7 @@
#include "Magnum/Magnum.h" #include "Magnum/Magnum.h"
#include "Magnum/OpenGL.h" #include "Magnum/OpenGL.h"
#include "Magnum/Tags.h"
#include "Magnum/visibility.h" #include "Magnum/visibility.h"
#include "MagnumExternal/Optional/optional.hpp" #include "MagnumExternal/Optional/optional.hpp"
@ -464,8 +465,11 @@ class MAGNUM_EXPORT Context {
private: private:
static Context* _current; static Context* _current;
explicit Context(NoCreateT, void functionLoader());
explicit Context(void functionLoader()); explicit Context(void functionLoader());
bool create();
/* Defined in Implementation/driverSpecific.cpp */ /* Defined in Implementation/driverSpecific.cpp */
MAGNUM_LOCAL void setupDriverWorkarounds(); MAGNUM_LOCAL void setupDriverWorkarounds();

4
src/Magnum/Platform/AbstractXApplication.cpp

@ -95,8 +95,8 @@ bool AbstractXApplication::tryCreateContext(const Configuration& configuration)
/* Set OpenGL context as current */ /* Set OpenGL context as current */
_contextHandler->makeCurrent(); _contextHandler->makeCurrent();
_context.reset(new Platform::Context); /* Return true if the initialization succeeds */
return true; return !!(_context = Platform::Context::tryCreate());
} }
AbstractXApplication::~AbstractXApplication() { AbstractXApplication::~AbstractXApplication() {

4
src/Magnum/Platform/AndroidApplication.cpp

@ -136,8 +136,8 @@ bool AndroidApplication::tryCreateContext(const Configuration& configuration) {
/* Make the context current */ /* Make the context current */
CORRADE_INTERNAL_ASSERT_OUTPUT(eglMakeCurrent(_display, _surface, _surface, _glContext)); CORRADE_INTERNAL_ASSERT_OUTPUT(eglMakeCurrent(_display, _surface, _surface, _glContext));
_context.reset(new Platform::Context); /* Return true if the initialization succeeds */
return true; return !!(_context = Platform::Context::tryCreate());
} }
void AndroidApplication::swapBuffers() { void AndroidApplication::swapBuffers() {

24
src/Magnum/Platform/Context.h

@ -41,12 +41,26 @@ information.
*/ */
class Context: public Magnum::Context { class Context: public Magnum::Context {
public: 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<Context> tryCreate() {
std::unique_ptr<Context> c{new Context{NoCreate}};
return c->create() ? std::move(c) : nullptr;
}
/** /**
* @brief Constructor * @brief Constructor
* *
* Does initial setup, loads OpenGL function pointers using * Does initial setup, loads OpenGL function pointers using
* platform-specific API, detects available features and enables them * 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}, * @see @fn_gl{Get} with @def_gl{MAJOR_VERSION}, @def_gl{MINOR_VERSION},
* @def_gl{CONTEXT_FLAGS}, @def_gl{NUM_EXTENSIONS}, * @def_gl{CONTEXT_FLAGS}, @def_gl{NUM_EXTENSIONS},
* @fn_gl{GetString} with @def_gl{EXTENSIONS} * @fn_gl{GetString} with @def_gl{EXTENSIONS}
@ -57,6 +71,14 @@ class Context: public Magnum::Context {
#else #else
Magnum::Context{nullptr} {} Magnum::Context{nullptr} {}
#endif #endif
private:
explicit Context(NoCreateT):
#if !defined(CORRADE_TARGET_EMSCRIPTEN) && !defined(CORRADE_TARGET_NACL)
Magnum::Context{NoCreate, flextGLInit} {}
#else
Magnum::Context{NoCreate, nullptr} {}
#endif
}; };
}} }}

4
src/Magnum/Platform/GlutApplication.cpp

@ -96,8 +96,8 @@ bool GlutApplication::tryCreateContext(const Configuration& configuration) {
glutMotionFunc(staticMouseMoveEvent); glutMotionFunc(staticMouseMoveEvent);
glutDisplayFunc(staticDrawEvent); glutDisplayFunc(staticDrawEvent);
_context.reset(new Platform::Context); /* Return true if the initialization succeeds */
return true; return !!(_context = Platform::Context::tryCreate());
} }
GlutApplication::~GlutApplication() = default; GlutApplication::~GlutApplication() = default;

4
src/Magnum/Platform/NaClApplication.cpp

@ -112,8 +112,8 @@ bool NaClApplication::tryCreateContext(const Configuration& configuration) {
RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE|PP_INPUTEVENT_CLASS_WHEEL); RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE|PP_INPUTEVENT_CLASS_WHEEL);
RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD); RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD);
_context.reset(new Platform::Context); /* Return true if the initialization succeeds */
return true; return !!(_context = Platform::Context::tryCreate());
} }
NaClApplication::~NaClApplication() = default; NaClApplication::~NaClApplication() = default;

4
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); _glContext = SDL_SetVideoMode(configuration.size().x(), configuration.size().y(), 24, SDL_OPENGL|SDL_HWSURFACE|SDL_DOUBLEBUF);
#endif #endif
_context.reset(new Platform::Context); /* Return true if the initialization succeeds */
return true; return !!(_context = Platform::Context::tryCreate());
} }
void Sdl2Application::swapBuffers() { void Sdl2Application::swapBuffers() {

4
src/Magnum/Platform/WindowlessCglApplication.cpp

@ -96,8 +96,8 @@ bool WindowlessCglApplication::tryCreateContext(const Configuration&) {
return false; return false;
} }
_context.reset(new Platform::Context); /* Return true if the initialization succeeds */
return true; return !!(_context = Platform::Context::tryCreate());
} }
WindowlessCglApplication::~WindowlessCglApplication() { WindowlessCglApplication::~WindowlessCglApplication() {

4
src/Magnum/Platform/WindowlessGlxApplication.cpp

@ -145,8 +145,8 @@ bool WindowlessGlxApplication::tryCreateContext(const Configuration&) {
return false; return false;
} }
_context.reset(new Platform::Context); /* Return true if the initialization succeeds */
return true; return !!(_context = Platform::Context::tryCreate());
} }
WindowlessGlxApplication::~WindowlessGlxApplication() { WindowlessGlxApplication::~WindowlessGlxApplication() {

4
src/Magnum/Platform/WindowlessNaClApplication.cpp

@ -97,8 +97,8 @@ bool WindowlessNaClApplication::tryCreateContext(const Configuration&) {
glSetCurrentContextPPAPI(graphics->pp_resource()); glSetCurrentContextPPAPI(graphics->pp_resource());
c = new Platform::Context; /* Return true if the initialization succeeds */
return true; return c = Platform::Context::tryCreate().release();
} }
WindowlessNaClApplication::~WindowlessNaClApplication() { WindowlessNaClApplication::~WindowlessNaClApplication() {

4
src/Magnum/Platform/WindowlessWglApplication.cpp

@ -116,8 +116,8 @@ bool WindowlessWglApplication::tryCreateContext(const Configuration&) {
return false; return false;
} }
_context.reset(new Platform::Context); /* Return true if the initialization succeeds */
return true; return !!(_context = Platform::Context::tryCreate());
} }
WindowlessWglApplication::~WindowlessWglApplication() { WindowlessWglApplication::~WindowlessWglApplication() {

4
src/Magnum/Platform/WindowlessWindowsEglApplication.cpp

@ -155,8 +155,8 @@ bool WindowlessWindowsEglApplication::tryCreateContext(const Configuration&) {
return false; return false;
} }
_context.reset(new Platform::Context); /* Return true if the initialization succeeds */
return true; return !!(_context = Platform::Context::tryCreate());
} }
WindowlessWindowsEglApplication::~WindowlessWindowsEglApplication() { WindowlessWindowsEglApplication::~WindowlessWindowsEglApplication() {

Loading…
Cancel
Save