| 
									
										
										
										
											2015-05-24 06:55:12 +02:00
										 |  |  | // Copyright 2012 Dolphin Emulator Project
 | 
					
						
							| 
									
										
										
										
											2015-05-18 01:08:10 +02:00
										 |  |  | // Licensed under GPLv2+
 | 
					
						
							| 
									
										
										
										
											2014-02-10 13:54:46 -05:00
										 |  |  | // Refer to the license.txt file included.
 | 
					
						
							| 
									
										
										
										
											2012-12-17 15:01:52 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-12 15:33:41 -04:00
										 |  |  | #include <string>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-19 04:40:00 +12:00
										 |  |  | #include "Common/GL/GLInterface/GLX.h"
 | 
					
						
							| 
									
										
										
										
											2015-09-19 05:53:32 +12:00
										 |  |  | #include "Common/Logging/Log.h"
 | 
					
						
							| 
									
										
										
										
											2012-12-17 15:01:52 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | #define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
 | 
					
						
							|  |  |  | #define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
 | 
					
						
							| 
									
										
										
										
											2014-12-20 10:57:34 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | typedef GLXContext (*PFNGLXCREATECONTEXTATTRIBSPROC)(Display*, GLXFBConfig, GLXContext, Bool, | 
					
						
							|  |  |  |                                                      const int*); | 
					
						
							|  |  |  | typedef int (*PFNGLXSWAPINTERVALSGIPROC)(int interval); | 
					
						
							| 
									
										
										
										
											2014-12-20 10:57:34 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | static PFNGLXCREATECONTEXTATTRIBSPROC glXCreateContextAttribs = nullptr; | 
					
						
							| 
									
										
										
										
											2014-07-08 15:58:25 +02:00
										 |  |  | static PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI = nullptr; | 
					
						
							| 
									
										
										
										
											2013-12-30 07:22:50 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-20 10:57:34 +01:00
										 |  |  | static bool s_glxError; | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | static int ctxErrorHandler(Display* dpy, XErrorEvent* ev) | 
					
						
							| 
									
										
										
										
											2014-12-20 10:57:34 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   s_glxError = true; | 
					
						
							|  |  |  |   return 0; | 
					
						
							| 
									
										
										
										
											2014-12-20 10:57:34 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-24 10:31:08 -06:00
										 |  |  | void cInterfaceGLX::SwapInterval(int Interval) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (glXSwapIntervalSGI) | 
					
						
							|  |  |  |     glXSwapIntervalSGI(Interval); | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     ERROR_LOG(VIDEO, "No support for SwapInterval (framerate clamped to monitor refresh rate)."); | 
					
						
							| 
									
										
										
										
											2013-01-24 10:31:08 -06:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-03-17 18:17:12 -05:00
										 |  |  | void* cInterfaceGLX::GetFuncAddress(const std::string& name) | 
					
						
							| 
									
										
										
										
											2013-12-30 07:22:50 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return (void*)glXGetProcAddress((const GLubyte*)name.c_str()); | 
					
						
							| 
									
										
										
										
											2013-12-30 07:22:50 -06:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-01-24 10:31:08 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-26 00:34:09 -06:00
										 |  |  | void cInterfaceGLX::Swap() | 
					
						
							| 
									
										
										
										
											2012-12-17 15:01:52 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   glXSwapBuffers(dpy, win); | 
					
						
							| 
									
										
										
										
											2012-12-17 15:01:52 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Create rendering window.
 | 
					
						
							| 
									
										
										
										
											2014-02-16 23:51:41 -05:00
										 |  |  | // Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize()
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | bool cInterfaceGLX::Create(void* window_handle, bool core) | 
					
						
							| 
									
										
										
										
											2012-12-17 15:01:52 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   dpy = XOpenDisplay(nullptr); | 
					
						
							|  |  |  |   int screen = DefaultScreen(dpy); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // checking glx version
 | 
					
						
							|  |  |  |   int glxMajorVersion, glxMinorVersion; | 
					
						
							|  |  |  |   glXQueryVersion(dpy, &glxMajorVersion, &glxMinorVersion); | 
					
						
							|  |  |  |   if (glxMajorVersion < 1 || (glxMajorVersion == 1 && glxMinorVersion < 4)) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     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
 | 
					
						
							|  |  |  |   XVisualInfo* vi = glXGetVisualFromFBConfig(dpy, fbconfig); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   s_glxError = false; | 
					
						
							|  |  |  |   XErrorHandler oldHandler = XSetErrorHandler(&ctxErrorHandler); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Create a GLX context.
 | 
					
						
							|  |  |  |   // We try to get a 4.0 core profile, else we try 3.3, else try it with anything we get.
 | 
					
						
							|  |  |  |   int context_attribs[] = {GLX_CONTEXT_MAJOR_VERSION_ARB, | 
					
						
							|  |  |  |                            4, | 
					
						
							|  |  |  |                            GLX_CONTEXT_MINOR_VERSION_ARB, | 
					
						
							|  |  |  |                            0, | 
					
						
							|  |  |  |                            GLX_CONTEXT_PROFILE_MASK_ARB, | 
					
						
							|  |  |  |                            GLX_CONTEXT_CORE_PROFILE_BIT_ARB, | 
					
						
							|  |  |  |                            GLX_CONTEXT_FLAGS_ARB, | 
					
						
							|  |  |  |                            GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, | 
					
						
							|  |  |  |                            None}; | 
					
						
							|  |  |  |   ctx = nullptr; | 
					
						
							|  |  |  |   if (core) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     ctx = glXCreateContextAttribs(dpy, fbconfig, 0, True, context_attribs); | 
					
						
							|  |  |  |     XSync(dpy, False); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (core && (!ctx || s_glxError)) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     int context_attribs_33[] = {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; | 
					
						
							|  |  |  |     ctx = glXCreateContextAttribs(dpy, fbconfig, 0, True, context_attribs_33); | 
					
						
							|  |  |  |     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; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   XWindowAttributes attribs; | 
					
						
							|  |  |  |   if (!XGetWindowAttributes(dpy, parent, &attribs)) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     ERROR_LOG(VIDEO, "Window attribute retrieval failed"); | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   s_backbuffer_width = attribs.width; | 
					
						
							|  |  |  |   s_backbuffer_height = attribs.height; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   win = XWindow.CreateXWindow(parent, vi); | 
					
						
							|  |  |  |   XFree(vi); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return true; | 
					
						
							| 
									
										
										
										
											2012-12-17 15:01:52 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool cInterfaceGLX::MakeCurrent() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   bool success = glXMakeCurrent(dpy, win, ctx); | 
					
						
							|  |  |  |   if (success) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     // load this function based on the current bound context
 | 
					
						
							|  |  |  |     glXSwapIntervalSGI = | 
					
						
							|  |  |  |         (PFNGLXSWAPINTERVALSGIPROC)GLInterface->GetFuncAddress("glXSwapIntervalSGI"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return success; | 
					
						
							| 
									
										
										
										
											2012-12-17 15:01:52 -06:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-04-11 03:32:07 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | bool cInterfaceGLX::ClearCurrent() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return glXMakeCurrent(dpy, None, nullptr); | 
					
						
							| 
									
										
										
										
											2013-04-11 03:32:07 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-17 15:01:52 -06:00
										 |  |  | // Close backend
 | 
					
						
							|  |  |  | void cInterfaceGLX::Shutdown() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   XWindow.DestroyXWindow(); | 
					
						
							|  |  |  |   if (ctx) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     glXDestroyContext(dpy, ctx); | 
					
						
							|  |  |  |     XCloseDisplay(dpy); | 
					
						
							|  |  |  |     ctx = nullptr; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2012-12-17 15:01:52 -06:00
										 |  |  | } |