Fixed requesting an unsupported OpenGL context version causing X to close the application, fixed GlContext initialization not updating settings properly, added error checks to GLLoader.cpp and fixed GL errors occurring when using a >= 3.0 OpenGL context.
This commit is contained in:
parent
c17486857f
commit
3996faa54c
@ -26,11 +26,24 @@
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/GLLoader.hpp>
|
||||
#include <SFML/Graphics/GLCheck.hpp>
|
||||
#include <SFML/Window/Context.hpp>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cstddef>
|
||||
|
||||
#if !defined(GL_MAJOR_VERSION)
|
||||
#define GL_MAJOR_VERSION 0x821B
|
||||
#endif
|
||||
|
||||
#if !defined(GL_MINOR_VERSION)
|
||||
#define GL_MINOR_VERSION 0x821C
|
||||
#endif
|
||||
|
||||
#if !defined(GL_NUM_EXTENSIONS)
|
||||
#define GL_NUM_EXTENSIONS 0x821D
|
||||
#endif
|
||||
|
||||
static sf::GlFunctionPointer IntGetProcAddress(const char* name)
|
||||
{
|
||||
return sf::Context::getFunction(name);
|
||||
@ -395,6 +408,9 @@ static void LoadExtByName(const char *extensionName)
|
||||
|
||||
static void ProcExtsFromExtString(const char *strExtList)
|
||||
{
|
||||
if (!strExtList)
|
||||
strExtList = "";
|
||||
|
||||
size_t iExtListLen = strlen(strExtList);
|
||||
const char *strExtListEnd = strExtList + iExtListLen;
|
||||
const char *strCurrPos = strExtList;
|
||||
@ -432,7 +448,38 @@ int sfogl_LoadFunctions()
|
||||
int numFailed = 0;
|
||||
ClearExtensionVars();
|
||||
|
||||
ProcExtsFromExtString((const char *)glGetString(GL_EXTENSIONS));
|
||||
const char* extensionString = NULL;
|
||||
|
||||
if(sfogl_GetMajorVersion() < 3)
|
||||
{
|
||||
// Try to load the < 3.0 way
|
||||
glCheck(extensionString = (const char *)glGetString(GL_EXTENSIONS));
|
||||
|
||||
ProcExtsFromExtString(extensionString);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try to load the >= 3.0 way
|
||||
const GLubyte* (CODEGEN_FUNCPTR *glGetStringiFunc)(GLenum, GLuint) = NULL;
|
||||
glGetStringiFunc = (const GLubyte* (CODEGEN_FUNCPTR *)(GLenum, GLuint))IntGetProcAddress("glGetStringi");
|
||||
|
||||
if (glGetStringiFunc)
|
||||
{
|
||||
int numExtensions = 0;
|
||||
glCheck(glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions));
|
||||
|
||||
if (numExtensions)
|
||||
{
|
||||
for (unsigned int i = 0; i < static_cast<unsigned int>(numExtensions); ++i)
|
||||
{
|
||||
glCheck(extensionString = (const char *)glGetStringiFunc(GL_EXTENSIONS, i));
|
||||
|
||||
ProcExtsFromExtString(extensionString);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
numFailed = Load_Version_1_2();
|
||||
|
||||
if(numFailed == 0)
|
||||
@ -481,7 +528,16 @@ static void ParseVersionFromString(int *pOutMajor, int *pOutMinor, const char *s
|
||||
|
||||
static void GetGLVersion()
|
||||
{
|
||||
ParseVersionFromString(&g_major_version, &g_minor_version, (const char*)glGetString(GL_VERSION));
|
||||
glGetIntegerv(GL_MAJOR_VERSION, &g_major_version);
|
||||
glGetIntegerv(GL_MINOR_VERSION, &g_minor_version);
|
||||
|
||||
// Check if we have to retrieve the context version using the legacy method
|
||||
if (glGetError() == GL_INVALID_ENUM)
|
||||
{
|
||||
const char* versionString = NULL;
|
||||
glCheck(versionString = (const char*)glGetString(GL_VERSION));
|
||||
ParseVersionFromString(&g_major_version, &g_minor_version, versionString);
|
||||
}
|
||||
}
|
||||
|
||||
int sfogl_GetMajorVersion()
|
||||
|
@ -73,6 +73,14 @@
|
||||
#define GL_MULTISAMPLE 0x809D
|
||||
#endif
|
||||
|
||||
#if !defined(GL_MAJOR_VERSION)
|
||||
#define GL_MAJOR_VERSION 0x821B
|
||||
#endif
|
||||
|
||||
#if !defined(GL_MINOR_VERSION)
|
||||
#define GL_MINOR_VERSION 0x821C
|
||||
#endif
|
||||
|
||||
#if !defined(GL_CONTEXT_FLAGS)
|
||||
#define GL_CONTEXT_FLAGS 0x821E
|
||||
#endif
|
||||
@ -333,42 +341,55 @@ void GlContext::initialize()
|
||||
setActive(true);
|
||||
|
||||
// Retrieve the context version number
|
||||
const GLubyte* version = glGetString(GL_VERSION);
|
||||
if (version)
|
||||
int majorVersion = 0;
|
||||
int minorVersion = 0;
|
||||
|
||||
// Try the new way first
|
||||
glGetIntegerv(GL_MAJOR_VERSION, &majorVersion);
|
||||
glGetIntegerv(GL_MINOR_VERSION, &minorVersion);
|
||||
|
||||
if (glGetError() != GL_INVALID_ENUM)
|
||||
{
|
||||
// The beginning of the returned string is "major.minor" (this is standard)
|
||||
m_settings.majorVersion = version[0] - '0';
|
||||
m_settings.minorVersion = version[2] - '0';
|
||||
m_settings.majorVersion = static_cast<unsigned int>(majorVersion);
|
||||
m_settings.minorVersion = static_cast<unsigned int>(minorVersion);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Can't get the version number, assume 2.1
|
||||
m_settings.majorVersion = 2;
|
||||
m_settings.minorVersion = 1;
|
||||
// Try the old way
|
||||
const GLubyte* version = glGetString(GL_VERSION);
|
||||
if (version)
|
||||
{
|
||||
// The beginning of the returned string is "major.minor" (this is standard)
|
||||
m_settings.majorVersion = version[0] - '0';
|
||||
m_settings.minorVersion = version[2] - '0';
|
||||
}
|
||||
else
|
||||
{
|
||||
// Can't get the version number, assume 2.1
|
||||
m_settings.majorVersion = 2;
|
||||
m_settings.minorVersion = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Verify non-default settings, just to be extra sure
|
||||
if (m_settings.attributeFlags & ContextSettings::Debug)
|
||||
m_settings.attributeFlags = ContextSettings::Default;
|
||||
|
||||
if (m_settings.majorVersion >= 3)
|
||||
{
|
||||
// Retrieve the context flags
|
||||
int flags = 0;
|
||||
glGetIntegerv(GL_CONTEXT_FLAGS, &flags);
|
||||
|
||||
if (!(flags & GL_CONTEXT_FLAG_DEBUG_BIT))
|
||||
{
|
||||
m_settings.attributeFlags ^= ContextSettings::Debug;
|
||||
}
|
||||
}
|
||||
if (flags & GL_CONTEXT_FLAG_DEBUG_BIT)
|
||||
m_settings.attributeFlags |= ContextSettings::Debug;
|
||||
|
||||
if (m_settings.attributeFlags & ContextSettings::Core)
|
||||
{
|
||||
// Retrieve the context profile
|
||||
int profile = 0;
|
||||
glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &profile);
|
||||
|
||||
if (!(profile & GL_CONTEXT_CORE_PROFILE_BIT))
|
||||
if ((m_settings.majorVersion > 3) || (m_settings.minorVersion >= 2))
|
||||
{
|
||||
m_settings.attributeFlags ^= ContextSettings::Core;
|
||||
// Retrieve the context profile
|
||||
int profile = 0;
|
||||
glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &profile);
|
||||
|
||||
if (profile & GL_CONTEXT_CORE_PROFILE_BIT)
|
||||
m_settings.attributeFlags |= ContextSettings::Core;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,8 +28,51 @@
|
||||
#include <SFML/Window/Unix/GlxContext.hpp>
|
||||
#include <SFML/Window/Unix/WindowImplX11.hpp>
|
||||
#include <SFML/Window/Unix/Display.hpp>
|
||||
#include <SFML/System/Mutex.hpp>
|
||||
#include <SFML/System/Lock.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
|
||||
#if !defined(GLX_DEBUGGING) && defined(SFML_DEBUG)
|
||||
// Enable this to print messages to err() everytime GLX produces errors
|
||||
//#define GLX_DEBUGGING
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
sf::Mutex glxErrorMutex;
|
||||
bool glxErrorOccurred = false;
|
||||
|
||||
int HandleXError(::Display*, XErrorEvent*)
|
||||
{
|
||||
glxErrorOccurred = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
class GlxErrorHandler
|
||||
{
|
||||
public:
|
||||
|
||||
GlxErrorHandler(::Display* display) :
|
||||
m_display(display),
|
||||
m_lock (glxErrorMutex)
|
||||
{
|
||||
glxErrorOccurred = false;
|
||||
m_previousHandler = XSetErrorHandler(HandleXError);
|
||||
}
|
||||
|
||||
~GlxErrorHandler()
|
||||
{
|
||||
XSync(m_display, False);
|
||||
XSetErrorHandler(m_previousHandler);
|
||||
}
|
||||
|
||||
private:
|
||||
sf::Lock m_lock;
|
||||
::Display* m_display;
|
||||
int (*m_previousHandler)(::Display*, XErrorEvent*);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
@ -160,9 +203,18 @@ GlxContext::~GlxContext()
|
||||
// Destroy the context
|
||||
if (m_context)
|
||||
{
|
||||
#if defined(GLX_DEBUGGING)
|
||||
GlxErrorHandler handler(m_display);
|
||||
#endif
|
||||
|
||||
if (glXGetCurrentContext() == m_context)
|
||||
glXMakeCurrent(m_display, None, NULL);
|
||||
glXDestroyContext(m_display, m_context);
|
||||
|
||||
#if defined(GLX_DEBUGGING)
|
||||
if (glxErrorOccurred)
|
||||
err() << "GLX error in GlxContext::~GlxContext()" << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Destroy the window if we own it
|
||||
@ -187,15 +239,38 @@ GlFunctionPointer GlxContext::getFunction(const char* name)
|
||||
////////////////////////////////////////////////////////////
|
||||
bool GlxContext::makeCurrent()
|
||||
{
|
||||
return m_context && glXMakeCurrent(m_display, m_window, m_context);
|
||||
if (!m_context)
|
||||
return false;
|
||||
|
||||
#if defined(GLX_DEBUGGING)
|
||||
GlxErrorHandler handler(m_display);
|
||||
#endif
|
||||
|
||||
bool result = glXMakeCurrent(m_display, m_window, m_context);
|
||||
|
||||
#if defined(GLX_DEBUGGING)
|
||||
if (glxErrorOccurred)
|
||||
err() << "GLX error in GlxContext::makeCurrent()" << std::endl;
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void GlxContext::display()
|
||||
{
|
||||
#if defined(GLX_DEBUGGING)
|
||||
GlxErrorHandler handler(m_display);
|
||||
#endif
|
||||
|
||||
if (m_window)
|
||||
glXSwapBuffers(m_display, m_window);
|
||||
|
||||
#if defined(GLX_DEBUGGING)
|
||||
if (glxErrorOccurred)
|
||||
err() << "GLX error in GlxContext::display()" << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -307,6 +382,10 @@ XVisualInfo GlxContext::selectBestVisual(::Display* display, unsigned int bitsPe
|
||||
XVisualInfo* visuals = XGetVisualInfo(display, 0, NULL, &count);
|
||||
if (visuals)
|
||||
{
|
||||
#if defined(GLX_DEBUGGING)
|
||||
GlxErrorHandler handler(display);
|
||||
#endif
|
||||
|
||||
// Evaluate all the returned visuals, and pick the best one
|
||||
int bestScore = 0xFFFF;
|
||||
XVisualInfo bestVisual;
|
||||
@ -341,6 +420,11 @@ XVisualInfo GlxContext::selectBestVisual(::Display* display, unsigned int bitsPe
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(GLX_DEBUGGING)
|
||||
if (glxErrorOccurred)
|
||||
err() << "GLX error in GlxContext::selectBestVisual()" << std::endl;
|
||||
#endif
|
||||
|
||||
// Free the array of visuals
|
||||
XFree(visuals);
|
||||
|
||||
@ -490,6 +574,11 @@ void GlxContext::createContext(GlxContext* shared, unsigned int bitsPerPixel, co
|
||||
GLX_CONTEXT_FLAGS_ARB, debug,
|
||||
0, 0
|
||||
};
|
||||
|
||||
// RAII GLX error handler (we simply ignore errors here)
|
||||
// On an error, glXCreateContextAttribsARB will return 0 anyway
|
||||
GlxErrorHandler handler(m_display);
|
||||
|
||||
m_context = glXCreateContextAttribsARB(m_display, *bestConfig, toShare, true, attributes);
|
||||
}
|
||||
else
|
||||
@ -507,11 +596,20 @@ void GlxContext::createContext(GlxContext* shared, unsigned int bitsPerPixel, co
|
||||
GLX_CONTEXT_MINOR_VERSION_ARB, static_cast<int>(m_settings.minorVersion),
|
||||
0, 0
|
||||
};
|
||||
|
||||
// RAII GLX error handler (we simply ignore errors here)
|
||||
// On an error, glXCreateContextAttribsARB will return 0 anyway
|
||||
GlxErrorHandler handler(m_display);
|
||||
|
||||
m_context = glXCreateContextAttribsARB(m_display, *bestConfig, toShare, true, attributes);
|
||||
}
|
||||
|
||||
if (m_context)
|
||||
{
|
||||
#if defined(GLX_DEBUGGING)
|
||||
GlxErrorHandler handler(m_display);
|
||||
#endif
|
||||
|
||||
// Update the creation settings from the chosen format
|
||||
int depth, stencil, multiSampling, samples;
|
||||
glXGetFBConfigAttrib(m_display, *bestConfig, GLX_DEPTH_SIZE, &depth);
|
||||
@ -521,6 +619,11 @@ void GlxContext::createContext(GlxContext* shared, unsigned int bitsPerPixel, co
|
||||
m_settings.depthBits = static_cast<unsigned int>(depth);
|
||||
m_settings.stencilBits = static_cast<unsigned int>(stencil);
|
||||
m_settings.antialiasingLevel = multiSampling ? samples : 0;
|
||||
|
||||
#if defined(GLX_DEBUGGING)
|
||||
if (glxErrorOccurred)
|
||||
err() << "GLX error in GlxContext::createContext()" << std::endl;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -554,6 +657,10 @@ void GlxContext::createContext(GlxContext* shared, unsigned int bitsPerPixel, co
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(GLX_DEBUGGING)
|
||||
GlxErrorHandler handler(m_display);
|
||||
#endif
|
||||
|
||||
// If glXCreateContextAttribsARB failed, use glXCreateContext
|
||||
if (!m_context)
|
||||
{
|
||||
@ -608,6 +715,11 @@ void GlxContext::createContext(GlxContext* shared, unsigned int bitsPerPixel, co
|
||||
// Free the visual info
|
||||
XFree(visualInfo);
|
||||
}
|
||||
|
||||
#if defined(GLX_DEBUGGING)
|
||||
if (glxErrorOccurred)
|
||||
err() << "GLX error in GlxContext::createContext()" << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace priv
|
||||
|
Loading…
Reference in New Issue
Block a user