From 86e6d6695e815746e877f9a4234f6805d5a4c155 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 20 Jul 2015 13:27:46 +1000 Subject: GHOST/X11: Support GLX-Context flags GHOST_ContextGLX was incomplete, ignoring profile-mask and profile-flags. --- intern/ghost/intern/GHOST_ContextGLX.cpp | 186 ++++++++++++++++++++++++++++++- intern/ghost/intern/GHOST_ContextGLX.h | 7 +- intern/ghost/intern/GHOST_SystemX11.h | 1 + intern/ghost/intern/GHOST_WindowX11.cpp | 70 +++--------- 4 files changed, 201 insertions(+), 63 deletions(-) diff --git a/intern/ghost/intern/GHOST_ContextGLX.cpp b/intern/ghost/intern/GHOST_ContextGLX.cpp index c4e1346456e..487e4939f5d 100644 --- a/intern/ghost/intern/GHOST_ContextGLX.cpp +++ b/intern/ghost/intern/GHOST_ContextGLX.cpp @@ -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; +} diff --git a/intern/ghost/intern/GHOST_ContextGLX.h b/intern/ghost/intern/GHOST_ContextGLX.h index 04fe58a0e82..8c2231a0b01 100644 --- a/intern/ghost/intern/GHOST_ContextGLX.h +++ b/intern/ghost/intern/GHOST_ContextGLX.h @@ -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__ diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h index f4d4825a12a..a0088dbe8f0 100644 --- a/intern/ghost/intern/GHOST_SystemX11.h +++ b/intern/ghost/intern/GHOST_SystemX11.h @@ -52,6 +52,7 @@ int GHOST_X11_ApplicationErrorHandler(Display *display, XErrorEvent *theEvent); int GHOST_X11_ApplicationIOErrorHandler(Display *display); + class GHOST_WindowX11; /** diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp index f716e9b84f6..fe99a8bee1e 100644 --- a/intern/ghost/intern/GHOST_WindowX11.cpp +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -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; - - if (stereoVisual) { - attribs[iattr++] = GLX_STEREO; - } - - 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; + int glx_attribs[64]; - GHOST_ASSERT(iattr <= (sizeof(attribs) / sizeof(*attribs)), "Attribute size too small"); + GHOST_X11_GL_GetAttributes(glx_attribs, 64, actualSamples, stereoVisual, false); - 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 */ -- cgit v1.2.3