// Create the OpenGL or OpenGL ES context // GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { int attribs[40]; GLXFBConfig native = NULL; GLXContext share = NULL; if (ctxconfig->share) share = ctxconfig->share->context.glx.handle; if (!chooseGLXFBConfig(fbconfig, &native)) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "GLX: Failed to find a suitable GLXFBConfig"); return GLFW_FALSE; } if (ctxconfig->client == GLFW_OPENGL_ES_API) { if (!_glfw.glx.ARB_create_context || !_glfw.glx.ARB_create_context_profile || !_glfw.glx.EXT_create_context_es2_profile) { _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: OpenGL ES requested but GLX_EXT_create_context_es2_profile is unavailable"); return GLFW_FALSE; } } if (ctxconfig->forward) { if (!_glfw.glx.ARB_create_context) { _glfwInputError(GLFW_VERSION_UNAVAILABLE, "GLX: Forward compatibility requested but GLX_ARB_create_context_profile is unavailable"); return GLFW_FALSE; } } if (ctxconfig->profile) { if (!_glfw.glx.ARB_create_context || !_glfw.glx.ARB_create_context_profile) { _glfwInputError(GLFW_VERSION_UNAVAILABLE, "GLX: An OpenGL profile requested but GLX_ARB_create_context_profile is unavailable"); return GLFW_FALSE; } } _glfwGrabErrorHandlerX11(); if (_glfw.glx.ARB_create_context) { int index = 0, mask = 0, flags = 0; if (ctxconfig->client == GLFW_OPENGL_API) { if (ctxconfig->forward) flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE) mask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB; else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE) mask |= GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; } else mask |= GLX_CONTEXT_ES2_PROFILE_BIT_EXT; if (ctxconfig->debug) flags |= GLX_CONTEXT_DEBUG_BIT_ARB; if (ctxconfig->noerror) flags |= GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR; if (ctxconfig->robustness) { if (_glfw.glx.ARB_create_context_robustness) { if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION) { setGLXattrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, GLX_NO_RESET_NOTIFICATION_ARB); } else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET) { setGLXattrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, GLX_LOSE_CONTEXT_ON_RESET_ARB); } flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB; } } if (ctxconfig->release) { if (_glfw.glx.ARB_context_flush_control) { if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE) { setGLXattrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); } else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH) { setGLXattrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); } } } // NOTE: Only request an explicitly versioned context when necessary, as // explicitly requesting version 1.0 does not always return the // highest version supported by the driver if (ctxconfig->major != 1 || ctxconfig->minor != 0) { setGLXattrib(GLX_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major); setGLXattrib(GLX_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor); } if (mask) setGLXattrib(GLX_CONTEXT_PROFILE_MASK_ARB, mask); if (flags) setGLXattrib(GLX_CONTEXT_FLAGS_ARB, flags); setGLXattrib(None, None); window->context.glx.handle = _glfw.glx.CreateContextAttribsARB(_glfw.x11.display, native, share, True, attribs); // HACK: This is a fallback for broken versions of the Mesa // implementation of GLX_ARB_create_context_profile that fail // default 1.0 context creation with a GLXBadProfileARB error in // violation of the extension spec if (!window->context.glx.handle) { if (_glfw.x11.errorCode == _glfw.glx.errorBase + GLXBadProfileARB && ctxconfig->client == GLFW_OPENGL_API && ctxconfig->profile == GLFW_OPENGL_ANY_PROFILE && ctxconfig->forward == GLFW_FALSE) { window->context.glx.handle = createLegacyContextGLX(window, native, share); } } } else { window->context.glx.handle = createLegacyContextGLX(window, native, share); } _glfwReleaseErrorHandlerX11(); if (!window->context.glx.handle) { _glfwInputErrorX11(GLFW_VERSION_UNAVAILABLE, "GLX: Failed to create context"); return GLFW_FALSE; } window->context.glx.window = glXCreateWindow(_glfw.x11.display, native, window->x11.handle, NULL); if (!window->context.glx.window) { _glfwInputError(GLFW_PLATFORM_ERROR, "GLX: Failed to create window"); return GLFW_FALSE; } window->context.makeCurrent = makeContextCurrentGLX; window->context.swapBuffers = swapBuffersGLX; window->context.swapInterval = swapIntervalGLX; window->context.extensionSupported = extensionSupportedGLX; window->context.getProcAddress = getProcAddressGLX; window->context.destroy = destroyContextGLX; return GLFW_TRUE; }
static int createContext(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, GLXFBConfigID fbconfigID) { int attribs[40]; GLXFBConfig* fbconfig; GLXContext share = NULL; if (wndconfig->share) share = wndconfig->share->GLX.context; // Retrieve the previously selected GLXFBConfig { int dummy, index = 0; setGLXattrib(GLX_FBCONFIG_ID, (int) fbconfigID); setGLXattrib(None, None); if (_glfwLibrary.GLX.SGIX_fbconfig) { fbconfig = _glfwLibrary.GLX.ChooseFBConfigSGIX(_glfwLibrary.X11.display, _glfwLibrary.X11.screen, attribs, &dummy); } else { fbconfig = glXChooseFBConfig(_glfwLibrary.X11.display, _glfwLibrary.X11.screen, attribs, &dummy); } if (fbconfig == NULL) { _glfwSetError(GLFW_PLATFORM_ERROR, "GLX: Failed to retrieve the selected GLXFBConfig"); return GL_FALSE; } } // Retrieve the corresponding visual if (_glfwLibrary.GLX.SGIX_fbconfig) { window->GLX.visual = _glfwLibrary.GLX.GetVisualFromFBConfigSGIX(_glfwLibrary.X11.display, *fbconfig); } else { window->GLX.visual = glXGetVisualFromFBConfig(_glfwLibrary.X11.display, *fbconfig); } if (window->GLX.visual == NULL) { XFree(fbconfig); _glfwSetError(GLFW_PLATFORM_ERROR, "GLX: Failed to retrieve visual for GLXFBConfig"); return GL_FALSE; } if (wndconfig->clientAPI == GLFW_OPENGL_ES_API) { if (!_glfwLibrary.GLX.ARB_create_context || !_glfwLibrary.GLX.ARB_create_context_profile || !_glfwLibrary.GLX.EXT_create_context_es2_profile) { _glfwSetError(GLFW_VERSION_UNAVAILABLE, "GLX: OpenGL ES requested but " "GLX_EXT_create_context_es2_profile is unavailable"); return GL_FALSE; } } if (wndconfig->glForward) { if (!_glfwLibrary.GLX.ARB_create_context) { _glfwSetError(GLFW_VERSION_UNAVAILABLE, "GLX: Forward compatibility requested but " "GLX_ARB_create_context_profile is unavailable"); return GL_FALSE; } } if (wndconfig->glProfile) { if (!_glfwLibrary.GLX.ARB_create_context || !_glfwLibrary.GLX.ARB_create_context_profile) { _glfwSetError(GLFW_VERSION_UNAVAILABLE, "GLX: An OpenGL profile requested but " "GLX_ARB_create_context_profile is unavailable"); return GL_FALSE; } } if (_glfwLibrary.GLX.ARB_create_context) { int index = 0, mask = 0, flags = 0, strategy = 0; if (wndconfig->clientAPI == GLFW_OPENGL_API) { if (wndconfig->glForward) flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; if (wndconfig->glDebug) flags |= GLX_CONTEXT_DEBUG_BIT_ARB; if (wndconfig->glProfile) { if (wndconfig->glProfile == GLFW_OPENGL_CORE_PROFILE) mask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB; else if (wndconfig->glProfile == GLFW_OPENGL_COMPAT_PROFILE) mask |= GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; } } else mask |= GLX_CONTEXT_ES2_PROFILE_BIT_EXT; if (wndconfig->glRobustness != GLFW_NO_ROBUSTNESS) { if (_glfwLibrary.GLX.ARB_create_context_robustness) { if (wndconfig->glRobustness == GLFW_NO_RESET_NOTIFICATION) strategy = GLX_NO_RESET_NOTIFICATION_ARB; else if (wndconfig->glRobustness == GLFW_LOSE_CONTEXT_ON_RESET) strategy = GLX_LOSE_CONTEXT_ON_RESET_ARB; flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB; } } if (wndconfig->glMajor != 1 || wndconfig->glMinor != 0) { // NOTE: Only request an explicitly versioned context when // necessary, as explicitly requesting version 1.0 does not always // return the highest available version setGLXattrib(GLX_CONTEXT_MAJOR_VERSION_ARB, wndconfig->glMajor); setGLXattrib(GLX_CONTEXT_MINOR_VERSION_ARB, wndconfig->glMinor); } if (mask) setGLXattrib(GLX_CONTEXT_PROFILE_MASK_ARB, mask); if (flags) setGLXattrib(GLX_CONTEXT_FLAGS_ARB, flags); if (strategy) setGLXattrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, strategy); setGLXattrib(None, None); // This is the only place we set an Xlib error handler, and we only do // it because glXCreateContextAttribsARB generates a BadMatch error if // the requested OpenGL version is unavailable (instead of a civilized // response like returning NULL) XSetErrorHandler(errorHandler); window->GLX.context = _glfwLibrary.GLX.CreateContextAttribsARB(_glfwLibrary.X11.display, *fbconfig, share, True, attribs); // We are done, so unset the error handler again (see above) XSetErrorHandler(NULL); } else { if (_glfwLibrary.GLX.SGIX_fbconfig) { window->GLX.context = _glfwLibrary.GLX.CreateContextWithConfigSGIX(_glfwLibrary.X11.display, *fbconfig, GLX_RGBA_TYPE, share, True); } else { window->GLX.context = glXCreateNewContext(_glfwLibrary.X11.display, *fbconfig, GLX_RGBA_TYPE, share, True); } } XFree(fbconfig); if (window->GLX.context == NULL) { // TODO: Handle all the various error codes here _glfwSetError(GLFW_PLATFORM_ERROR, "GLX: Failed to create context"); return GL_FALSE; } return GL_TRUE; }
// Prepare for creation of the OpenGL context // int _glfwCreateContext(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWfbconfig* fbconfig) { int attribs[40]; GLXFBConfig native; GLXContext share = NULL; if (wndconfig->share) share = wndconfig->share->glx.context; if (!chooseFBConfig(fbconfig, &native)) { _glfwInputError(GLFW_PLATFORM_ERROR, "GLX: Failed to find a suitable GLXFBConfig"); return GL_FALSE; } // Retrieve the corresponding visual if (_glfw.glx.SGIX_fbconfig) { window->glx.visual = _glfw.glx.GetVisualFromFBConfigSGIX(_glfw.x11.display, native); } else window->glx.visual = glXGetVisualFromFBConfig(_glfw.x11.display, native); if (window->glx.visual == NULL) { _glfwInputError(GLFW_PLATFORM_ERROR, "GLX: Failed to retrieve visual for GLXFBConfig"); return GL_FALSE; } if (wndconfig->clientAPI == GLFW_OPENGL_ES_API) { if (!_glfw.glx.ARB_create_context || !_glfw.glx.ARB_create_context_profile || !_glfw.glx.EXT_create_context_es2_profile) { _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: OpenGL ES requested but " "GLX_EXT_create_context_es2_profile is unavailable"); return GL_FALSE; } } if (wndconfig->glForward) { if (!_glfw.glx.ARB_create_context) { _glfwInputError(GLFW_VERSION_UNAVAILABLE, "GLX: Forward compatibility requested but " "GLX_ARB_create_context_profile is unavailable"); return GL_FALSE; } } if (wndconfig->glProfile) { if (!_glfw.glx.ARB_create_context || !_glfw.glx.ARB_create_context_profile) { _glfwInputError(GLFW_VERSION_UNAVAILABLE, "GLX: An OpenGL profile requested but " "GLX_ARB_create_context_profile is unavailable"); return GL_FALSE; } } _glfwGrabXErrorHandler(); if (_glfw.glx.ARB_create_context) { int index = 0, mask = 0, flags = 0, strategy = 0; if (wndconfig->clientAPI == GLFW_OPENGL_API) { if (wndconfig->glForward) flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; if (wndconfig->glDebug) flags |= GLX_CONTEXT_DEBUG_BIT_ARB; if (wndconfig->glProfile) { if (wndconfig->glProfile == GLFW_OPENGL_CORE_PROFILE) mask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB; else if (wndconfig->glProfile == GLFW_OPENGL_COMPAT_PROFILE) mask |= GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; } } else mask |= GLX_CONTEXT_ES2_PROFILE_BIT_EXT; if (wndconfig->glRobustness != GLFW_NO_ROBUSTNESS) { if (_glfw.glx.ARB_create_context_robustness) { if (wndconfig->glRobustness == GLFW_NO_RESET_NOTIFICATION) strategy = GLX_NO_RESET_NOTIFICATION_ARB; else if (wndconfig->glRobustness == GLFW_LOSE_CONTEXT_ON_RESET) strategy = GLX_LOSE_CONTEXT_ON_RESET_ARB; flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB; } } if (wndconfig->glMajor != 1 || wndconfig->glMinor != 0) { // NOTE: Only request an explicitly versioned context when // necessary, as explicitly requesting version 1.0 does not // always return the highest available version setGLXattrib(GLX_CONTEXT_MAJOR_VERSION_ARB, wndconfig->glMajor); setGLXattrib(GLX_CONTEXT_MINOR_VERSION_ARB, wndconfig->glMinor); } if (mask) setGLXattrib(GLX_CONTEXT_PROFILE_MASK_ARB, mask); if (flags) setGLXattrib(GLX_CONTEXT_FLAGS_ARB, flags); if (strategy) setGLXattrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, strategy); setGLXattrib(None, None); window->glx.context = _glfw.glx.CreateContextAttribsARB(_glfw.x11.display, native, share, True, attribs); if (window->glx.context == NULL) { // HACK: This is a fallback for the broken Mesa implementation of // GLX_ARB_create_context_profile, which fails default 1.0 // context creation with a GLXBadProfileARB error in violation // of the extension spec if (_glfw.x11.errorCode == _glfw.glx.errorBase + GLXBadProfileARB && wndconfig->clientAPI == GLFW_OPENGL_API && wndconfig->glProfile == GLFW_OPENGL_ANY_PROFILE && wndconfig->glForward == GL_FALSE) { window->glx.context = createLegacyContext(window, native, share); } } } else window->glx.context = createLegacyContext(window, native, share); _glfwReleaseXErrorHandler(); if (window->glx.context == NULL) { _glfwInputXError(GLFW_PLATFORM_ERROR, "GLX: Failed to create context"); return GL_FALSE; } return GL_TRUE; }
void OSGLContext_x11Private::createContextGLX(OSGLContext_glx_data* glxInfo, const FramebufferConfig& fbconfig, int /*major*/, int /*minor*/, bool coreProfile, int rendererID, const OSGLContext_x11* shareContext) { GLXFBConfig native = NULL; GLXContext share = shareContext ? shareContext->_imp->glxContextHandle : 0; chooseFBConfig(glxInfo, fbconfig, &native); GrabErrorHandlerX11(); if (!glxInfo->_imp->ARB_create_context) { glxContextHandle = createLegacyContext(glxInfo, native, share); } else { std::vector<int> attribs; int mask = 0, flags = 0; /*if (ctxconfig->forward) flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;*/ if (coreProfile) { mask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB; } else { mask |= GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; } // Note that we do NOT request a specific version. Sometimes a driver might report that its maximum compatibility //profile is 3.0 but we ask for 2.0, hence it will fail context creation whereas it should not. Instead we check //OpenGL version once context is created and check that we have at least 2.0 /*if ( (major != 1) || (minor != 0) ) { setGLXattrib(GLX_CONTEXT_MAJOR_VERSION_ARB, major); setGLXattrib(GLX_CONTEXT_MINOR_VERSION_ARB, minor); }*/ if (mask) { setGLXattrib(GLX_CONTEXT_PROFILE_MASK_ARB, mask); } if (flags) { setGLXattrib(GLX_CONTEXT_FLAGS_ARB, flags); } if ( glxInfo->_imp->MESA_query_renderer && (rendererID != -1) && (rendererID != 0) ) { setGLXattrib(GLX_RENDERER_ID_MESA, rendererID); } setGLXattrib(None, None); glxContextHandle = glxInfo->_imp->CreateContextAttribsARB(glxInfo->_imp->x11.display, native, share, True /*direct*/, &attribs[0]); // HACK: This is a fallback for broken versions of the Mesa // implementation of GLX_ARB_create_context_profile that fail // default 1.0 context creation with a GLXBadProfileARB error in // violation of the extension spec if (!glxContextHandle) { if (gX11ErrorCode == glxInfo->_imp->errorBase + GLXBadProfileARB /*&& ctxconfig->client == GLFW_OPENGL_API && ctxconfig->profile == GLFW_OPENGL_ANY_PROFILE && ctxconfig->forward == GLFW_FALSE*/) { glxContextHandle = createLegacyContext(glxInfo, native, share); } } } ReleaseErrorHandlerX11(glxInfo); if (!glxContextHandle) { throw std::runtime_error("GLX: Failed to create context"); } glxWindowHandle = glxInfo->_imp->CreateWindow(glxInfo->_imp->x11.display, native, x11Window.handle, NULL); if (!glxWindowHandle) { glxInfo->_imp->DestroyContext(glxInfo->_imp->x11.display, glxContextHandle); glxContextHandle = 0; throw std::runtime_error("GLX: Failed to create window"); } if ( !glxInfo->_imp->IsDirect(glxInfo->_imp->x11.display, glxContextHandle) ) { glxInfo->_imp->DestroyContext(glxInfo->_imp->x11.display, glxContextHandle); glxContextHandle = 0; glxInfo->_imp->DestroyWindow(glxInfo->_imp->x11.display, glxWindowHandle); glxWindowHandle = 0; throw std::runtime_error("GLX: Created context is not doing direct rendering"); } /*_window = glxInfo->CreateWindow(glxInfo->display, native, window->x11.handle, NULL); if (!_window) { throw std::runtime_error("GLX: Failed to create window"); }*/ } // createContextGLX