diff --git a/Source/Core/VideoBackends/OGL/GLInterface/GLX.cpp b/Source/Core/VideoBackends/OGL/GLInterface/GLX.cpp index 12912b0f5d..900a74b0c8 100644 --- a/Source/Core/VideoBackends/OGL/GLInterface/GLX.cpp +++ b/Source/Core/VideoBackends/OGL/GLInterface/GLX.cpp @@ -9,9 +9,22 @@ #include "VideoCommon/RenderBase.h" #include "VideoCommon/VideoConfig.h" +#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 + +typedef GLXContext (*PFNGLXCREATECONTEXTATTRIBSPROC)(Display*, GLXFBConfig, GLXContext, Bool, const int*); typedef int ( * PFNGLXSWAPINTERVALSGIPROC) (int interval); + +static PFNGLXCREATECONTEXTATTRIBSPROC glXCreateContextAttribs = nullptr; static PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI = nullptr; +static bool s_glxError; +static int ctxErrorHandler(Display *dpy, XErrorEvent *ev) +{ + s_glxError = true; + return 0; +} + void cInterfaceGLX::SwapInterval(int Interval) { if (glXSwapIntervalSGI) @@ -33,69 +46,87 @@ void cInterfaceGLX::Swap() // Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize() bool cInterfaceGLX::Create(void *window_handle) { - int glxMajorVersion, glxMinorVersion; - - // attributes for a single buffered visual in RGBA format with at least - // 8 bits per color - int attrListSgl[] = {GLX_RGBA, GLX_RED_SIZE, 8, - GLX_GREEN_SIZE, 8, - GLX_BLUE_SIZE, 8, - None}; - - // attributes for a double buffered visual in RGBA format with at least - // 8 bits per color - int attrListDbl[] = {GLX_RGBA, GLX_DOUBLEBUFFER, - GLX_RED_SIZE, 8, - GLX_GREEN_SIZE, 8, - GLX_BLUE_SIZE, 8, - None }; - - int attrListDefault[] = { - GLX_RGBA, - GLX_RED_SIZE, 1, - GLX_GREEN_SIZE, 1, - GLX_BLUE_SIZE, 1, - GLX_DOUBLEBUFFER, - None }; - dpy = XOpenDisplay(nullptr); int screen = DefaultScreen(dpy); + // checking glx version + int glxMajorVersion, glxMinorVersion; glXQueryVersion(dpy, &glxMajorVersion, &glxMinorVersion); - NOTICE_LOG(VIDEO, "glX-Version %d.%d", glxMajorVersion, glxMinorVersion); - - // Get an appropriate visual - vi = glXChooseVisual(dpy, screen, attrListDbl); - if (vi == nullptr) + if (glxMajorVersion < 1 || (glxMajorVersion == 1 && glxMinorVersion < 4)) { - vi = glXChooseVisual(dpy, screen, attrListSgl); - if (vi != nullptr) - { - ERROR_LOG(VIDEO, "Only single buffered visual!"); - } - else - { - vi = glXChooseVisual(dpy, screen, attrListDefault); - if (vi == nullptr) - { - ERROR_LOG(VIDEO, "Could not choose visual (glXChooseVisual)"); - return false; - } - } - } - else - { - NOTICE_LOG(VIDEO, "Got double buffered visual!"); - } - - // Create a GLX context. - ctx = glXCreateContext(dpy, vi, nullptr, GL_TRUE); - if (!ctx) - { - PanicAlert("Unable to create GLX context."); + ERROR_LOG(VIDEO, "glX-Version %d.%d detected, but need at least 1.4", + glxMajorVersion, glxMinorVersion); return false; } + // loading core context creation function + glXCreateContextAttribs = (PFNGLXCREATECONTEXTATTRIBSPROC)GetFuncAddress("glXCreateContextAttribsARB"); + if (!glXCreateContextAttribs) + { + ERROR_LOG(VIDEO, "glXCreateContextAttribsARB not found, do you support GLX_ARB_create_context?"); + return false; + } + + // choosing framebuffer + int visual_attribs[] = + { + GLX_X_RENDERABLE , True, + GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT, + GLX_X_VISUAL_TYPE , GLX_TRUE_COLOR, + GLX_RED_SIZE , 8, + GLX_GREEN_SIZE , 8, + GLX_BLUE_SIZE , 8, + GLX_DEPTH_SIZE , 0, + GLX_STENCIL_SIZE , 0, + GLX_DOUBLEBUFFER , True, + None + }; + int fbcount = 0; + GLXFBConfig* fbc = glXChooseFBConfig(dpy, screen, visual_attribs, &fbcount); + if (!fbc || !fbcount) + { + ERROR_LOG(VIDEO, "Failed to retrieve a framebuffer config"); + return false; + } + fbconfig = *fbc; + XFree(fbc); + + // Get an appropriate visual + vi = glXGetVisualFromFBConfig(dpy, fbconfig); + + // Create a GLX context. + // We try to get a 3.3 core profile, else we try it with anything we get. + int context_attribs[] = + { + GLX_CONTEXT_MAJOR_VERSION_ARB, 3, + GLX_CONTEXT_MINOR_VERSION_ARB, 3, + GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, + GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, + None + }; + s_glxError = false; + XErrorHandler oldHandler = XSetErrorHandler(&ctxErrorHandler); + ctx = glXCreateContextAttribs(dpy, fbconfig, 0, True, context_attribs); + XSync(dpy, False); + if (!ctx || s_glxError) + { + int context_attribs_legacy[] = + { + GLX_CONTEXT_MAJOR_VERSION_ARB, 1, + GLX_CONTEXT_MINOR_VERSION_ARB, 0, + None + }; + s_glxError = false; + ctx = glXCreateContextAttribs(dpy, fbconfig, 0, True, context_attribs_legacy); + XSync(dpy, False); + if (!ctx || s_glxError) + { + ERROR_LOG(VIDEO, "Unable to create GL context."); + return false; + } + } + XSetErrorHandler(oldHandler); + XWindow.Initialize(dpy); Window parent = (Window)window_handle; diff --git a/Source/Core/VideoBackends/OGL/GLInterface/GLX.h b/Source/Core/VideoBackends/OGL/GLInterface/GLX.h index fa97efdabf..8198ea9194 100644 --- a/Source/Core/VideoBackends/OGL/GLInterface/GLX.h +++ b/Source/Core/VideoBackends/OGL/GLInterface/GLX.h @@ -18,6 +18,7 @@ private: Window win; GLXContext ctx; XVisualInfo *vi; + GLXFBConfig fbconfig; public: friend class cX11Window; void SwapInterval(int Interval) override;