GHOST/X11: Support GLX-Context flags

GHOST_ContextGLX was incomplete, ignoring profile-mask and profile-flags.
This commit is contained in:
Campbell Barton 2015-07-20 13:27:46 +10:00
parent b368724464
commit 86e6d6695e
4 changed files with 201 additions and 63 deletions

@ -152,7 +152,102 @@ GHOST_TSuccess GHOST_ContextGLX::initializeDrawingContext()
XIOErrorHandler old_handler_io = XSetIOErrorHandler(GHOST_X11_ApplicationIOErrorHandler);
#endif
m_context = glXCreateContext(m_display, m_visualInfo, s_sharedContext, True);
/* needed so 'GLXEW_ARB_create_context' is valid */
initContextGLXEW();
if (GLXEW_ARB_create_context) {
int profileBitCore = m_contextProfileMask & GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
int profileBitCompat = m_contextProfileMask & GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
#ifdef WITH_GLEW_ES
int profileBitES = m_contextProfileMask & GLX_CONTEXT_ES_PROFILE_BIT_EXT;
#endif
if (!GLXEW_ARB_create_context_profile && profileBitCore)
fprintf(stderr, "Warning! OpenGL core profile not available.\n");
if (!GLXEW_ARB_create_context_profile && profileBitCompat)
fprintf(stderr, "Warning! OpenGL compatibility profile not available.\n");
#ifdef WITH_GLEW_ES
if (!GLXEW_EXT_create_context_es_profile && profileBitES && m_contextMajorVersion == 1)
fprintf(stderr, "Warning! OpenGL ES profile not available.\n");
if (!GLXEW_EXT_create_context_es2_profile && profileBitES && m_contextMajorVersion == 2)
fprintf(stderr, "Warning! OpenGL ES2 profile not available.\n");
#endif
int profileMask = 0;
if (GLXEW_ARB_create_context_profile && profileBitCore)
profileMask |= profileBitCore;
if (GLXEW_ARB_create_context_profile && profileBitCompat)
profileMask |= profileBitCompat;
#ifdef WITH_GLEW_ES
if (GLXEW_EXT_create_context_es_profile && profileBitES)
profileMask |= profileBitES;
#endif
if (profileMask != m_contextProfileMask)
fprintf(stderr, "Warning! Ignoring untested OpenGL context profile mask bits.");
/* max 10 attributes plus terminator */
int attribs[11];
int i = 0;
if (profileMask) {
attribs[i++] = GLX_CONTEXT_PROFILE_MASK_ARB;
attribs[i++] = profileMask;
}
if (m_contextMajorVersion != 0) {
attribs[i++] = GLX_CONTEXT_MAJOR_VERSION_ARB;
attribs[i++] = m_contextMajorVersion;
}
if (m_contextMinorVersion != 0) {
attribs[i++] = GLX_CONTEXT_MINOR_VERSION_ARB;
attribs[i++] = m_contextMinorVersion;
}
if (m_contextFlags != 0) {
attribs[i++] = GLX_CONTEXT_FLAGS_ARB;
attribs[i++] = m_contextFlags;
}
if (m_contextResetNotificationStrategy != 0) {
if (GLXEW_ARB_create_context_robustness) {
attribs[i++] = GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB;
attribs[i++] = m_contextResetNotificationStrategy;
}
else {
fprintf(stderr, "Warning! Cannot set the reset notification strategy.");
}
}
attribs[i++] = 0;
/* Create a GL 3.x context */
GLXFBConfig *framebuffer_config = NULL;
{
int glx_attribs[64];
int fbcount = 0;
GHOST_X11_GL_GetAttributes(glx_attribs, 64, m_numOfAASamples, m_stereoVisual, true);
framebuffer_config = glXChooseFBConfig(m_display, DefaultScreen(m_display), glx_attribs, &fbcount);
}
if (framebuffer_config) {
m_context = glXCreateContextAttribsARB(m_display, framebuffer_config[0], s_sharedContext, True, attribs);
}
}
else {
/* Create legacy context */
m_context = glXCreateContext(m_display, m_visualInfo, s_sharedContext, True);
}
GHOST_TSuccess success;
@ -164,16 +259,13 @@ GHOST_TSuccess GHOST_ContextGLX::initializeDrawingContext()
glXMakeCurrent(m_display, m_window, m_context);
// Seems that this has to be called after MakeCurrent,
// which means we cannot use glX extensions until after we create a context
initContextGLXEW();
initClearGL();
::glXSwapBuffers(m_display, m_window);
success = GHOST_kSuccess;
}
else {
/* freeing well clean up the context initialized above */
success = GHOST_kFailure;
}
@ -223,3 +315,87 @@ GHOST_TSuccess GHOST_ContextGLX::getSwapInterval(int &intervalOut)
return GHOST_kFailure;
}
}
/**
* Utility function to get GLX attributes.
*
* \param for_fb_config: There are some small differences in
* #glXChooseVisual and #glXChooseFBConfig's attribute encoding.
*
* \note Similar to SDL's 'X11_GL_GetAttributes'
*/
int GHOST_X11_GL_GetAttributes(
int *attribs, int attribs_max,
int samples, bool is_stereo_visual,
bool for_fb_config)
{
int i = 0;
#ifdef GHOST_OPENGL_ALPHA
const bool need_alpha = true;
#else
const bool need_alpha = false;
#endif
#ifdef GHOST_OPENGL_STENCIL
const bool need_stencil = true;
#else
const bool need_stencil = false;
#endif
if (is_stereo_visual) {
attribs[i++] = GLX_STEREO;
if (for_fb_config) {
attribs[i++] = True;
}
}
if (for_fb_config) {
attribs[i++] = GLX_RENDER_TYPE;
attribs[i++] = GLX_RGBA_BIT;
}
else {
attribs[i++] = GLX_RGBA;
}
attribs[i++] = GLX_DOUBLEBUFFER;
if (for_fb_config) {
attribs[i++] = True;
}
attribs[i++] = GLX_RED_SIZE;
attribs[i++] = True;
attribs[i++] = GLX_BLUE_SIZE;
attribs[i++] = True;
attribs[i++] = GLX_GREEN_SIZE;
attribs[i++] = True;
attribs[i++] = GLX_DEPTH_SIZE;
attribs[i++] = True;
if (need_alpha) {
attribs[i++] = GLX_ALPHA_SIZE;
attribs[i++] = True;
}
if (need_stencil) {
attribs[i++] = GLX_STENCIL_SIZE;
attribs[i++] = True;
}
if (samples) {
attribs[i++] = GLX_SAMPLE_BUFFERS_ARB;
attribs[i++] = True;
attribs[i++] = GLX_SAMPLES_ARB;
attribs[i++] = samples;
}
attribs[i++] = 0;
GHOST_ASSERT(i <= attribs_max, "attribute size too small");
return i;
}

@ -54,7 +54,6 @@ extern "C" GLXEWContext *glxewContext;
#define GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY 0
#endif
class GHOST_ContextGLX : public GHOST_Context
{
public:
@ -148,4 +147,10 @@ private:
static int s_sharedCount;
};
/* used to get GLX info */
int GHOST_X11_GL_GetAttributes(
int *attribs, int attribs_max,
int samples, bool is_stereo_visual,
bool for_fb_config);
#endif // __GHOST_CONTEXTGLX_H__

@ -52,6 +52,7 @@
int GHOST_X11_ApplicationErrorHandler(Display *display, XErrorEvent *theEvent);
int GHOST_X11_ApplicationIOErrorHandler(Display *display);
class GHOST_WindowX11;
/**

@ -164,6 +164,8 @@ static XVisualInfo *x11_visualinfo_from_glx(
{
XVisualInfo *visualInfo = NULL;
GHOST_TUns16 numOfAASamples = *r_numOfAASamples;
GHOST_TUns16 actualSamples;
/* Set up the minimum attributes that we require and see if
* X can find us a visual matching those requirements. */
int glx_major, glx_minor; /* GLX version: major.minor */
@ -177,68 +179,22 @@ static XVisualInfo *x11_visualinfo_from_glx(
return NULL;
}
#ifdef GHOST_OPENGL_ALPHA
const bool needAlpha = true;
#else
const bool needAlpha = false;
#endif
#ifdef GHOST_OPENGL_STENCIL
const bool needStencil = true;
#else
const bool needStencil = false;
#endif
/* GLX >= 1.4 required for multi-sample */
if ((glx_major > 1) || (glx_major == 1 && glx_minor >= 4)) {
actualSamples = numOfAASamples;
}
else {
numOfAASamples = 0;
actualSamples = 0;
}
/* Find the display with highest samples, starting at level requested */
GHOST_TUns16 actualSamples = numOfAASamples;
for (;;) {
int attribs[20];
int iattr = 0;
int glx_attribs[64];
if (stereoVisual) {
attribs[iattr++] = GLX_STEREO;
}
GHOST_X11_GL_GetAttributes(glx_attribs, 64, actualSamples, stereoVisual, false);
attribs[iattr++] = GLX_RGBA;
attribs[iattr++] = GLX_DOUBLEBUFFER;
attribs[iattr++] = GLX_RED_SIZE;
attribs[iattr++] = 1;
attribs[iattr++] = GLX_BLUE_SIZE;
attribs[iattr++] = 1;
attribs[iattr++] = GLX_GREEN_SIZE;
attribs[iattr++] = 1;
attribs[iattr++] = GLX_DEPTH_SIZE;
attribs[iattr++] = 1;
if (needAlpha) {
attribs[iattr++] = GLX_ALPHA_SIZE;
attribs[iattr++] = 1;
}
if (needStencil) {
attribs[iattr++] = GLX_STENCIL_SIZE;
attribs[iattr++] = 1;
}
/* GLX >= 1.4 required for multi-sample */
if (actualSamples > 0 && ((glx_major > 1) || (glx_major == 1 && glx_minor >= 4))) {
attribs[iattr++] = GLX_SAMPLE_BUFFERS;
attribs[iattr++] = 1;
attribs[iattr++] = GLX_SAMPLES;
attribs[iattr++] = actualSamples;
}
attribs[iattr++] = None;
GHOST_ASSERT(iattr <= (sizeof(attribs) / sizeof(*attribs)), "Attribute size too small");
visualInfo = glXChooseVisual(display, DefaultScreen(display), attribs);
visualInfo = glXChooseVisual(display, DefaultScreen(display), glx_attribs);
/* Any sample level or even zero, which means oversampling disabled, is good
* but we need a valid visual to continue */