2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "GLContextGLX.h"
11 #include "utils/log.h"
15 #include "system_gl.h"
17 using namespace KODI::WINDOWING::X11
;
19 CGLContextGLX::CGLContextGLX(Display
*dpy
) : CGLContext(dpy
)
25 bool CGLContextGLX::Refresh(bool force
, int screen
, Window glWindow
, bool &newContext
)
28 m_glxWindow
= glWindow
;
32 if (m_glxContext
&& !force
)
34 CLog::Log(LOGDEBUG
, "CWinSystemX11::RefreshGlxContext: refreshing context");
35 glXMakeCurrent(m_dpy
, None
, NULL
);
36 glXMakeCurrent(m_dpy
, glWindow
, m_glxContext
);
44 XVisualInfo
*vInfo
= NULL
;
45 int availableVisuals
= 0;
46 vMask
.screen
= screen
;
47 XWindowAttributes winAttr
;
49 /* Assume a depth of 24 in case the below calls to XGetWindowAttributes()
50 or XGetVisualInfo() fail. That shouldn't happen unless something is
51 fatally wrong, but lets prepare for everything. */
54 if (XGetWindowAttributes(m_dpy
, glWindow
, &winAttr
))
56 vMask
.visualid
= XVisualIDFromVisual(winAttr
.visual
);
57 vInfo
= XGetVisualInfo(m_dpy
, VisualScreenMask
| VisualIDMask
, &vMask
, &availableVisuals
);
59 CLog::Log(LOGWARNING
, "Failed to get VisualInfo of visual 0x{:x}", (unsigned)vMask
.visualid
);
60 else if(!IsSuitableVisual(vInfo
))
63 "Visual 0x{:x} of the window is not suitable, looking for another one...",
64 (unsigned)vInfo
->visualid
);
65 vMask
.depth
= vInfo
->depth
;
71 CLog::Log(LOGWARNING
, "Failed to get window attributes");
73 /* As per glXMakeCurrent documentation, we have to use the same visual as
74 m_glWindow. Since that was not suitable for use, we try to use another
75 one with the same depth and hope that the used implementation is less
76 strict than the documentation. */
79 visuals
= XGetVisualInfo(m_dpy
, VisualScreenMask
| VisualDepthMask
, &vMask
, &availableVisuals
);
80 for (int i
= 0; i
< availableVisuals
; i
++)
82 if (IsSuitableVisual(&visuals
[i
]))
84 vMask
.visualid
= visuals
[i
].visualid
;
85 vInfo
= XGetVisualInfo(m_dpy
, VisualScreenMask
| VisualIDMask
, &vMask
, &availableVisuals
);
94 CLog::Log(LOGINFO
, "Using visual 0x{:x}", (unsigned)vInfo
->visualid
);
97 glXMakeCurrent(m_dpy
, None
, NULL
);
98 glXDestroyContext(m_dpy
, m_glxContext
);
102 if ((m_glxContext
= glXCreateContext(m_dpy
, vInfo
, NULL
, True
)))
104 // make this context current
105 glXMakeCurrent(m_dpy
, glWindow
, m_glxContext
);
110 CLog::Log(LOGERROR
, "GLX Error: Could not create context");
116 CLog::Log(LOGERROR
, "GLX Error: vInfo is NULL!");
122 void CGLContextGLX::Destroy()
124 glXMakeCurrent(m_dpy
, None
, NULL
);
125 glXDestroyContext(m_dpy
, m_glxContext
);
129 void CGLContextGLX::Detach()
131 glXMakeCurrent(m_dpy
, None
, NULL
);
134 bool CGLContextGLX::IsSuitableVisual(XVisualInfo
*vInfo
)
138 if (glXGetConfig(m_dpy
, vInfo
, GLX_RGBA
, &value
) || !value
)
140 if (glXGetConfig(m_dpy
, vInfo
, GLX_DOUBLEBUFFER
, &value
) || !value
)
142 if (glXGetConfig(m_dpy
, vInfo
, GLX_RED_SIZE
, &value
) || value
< 8)
144 if (glXGetConfig(m_dpy
, vInfo
, GLX_GREEN_SIZE
, &value
) || value
< 8)
146 if (glXGetConfig(m_dpy
, vInfo
, GLX_BLUE_SIZE
, &value
) || value
< 8)
148 if (glXGetConfig(m_dpy
, vInfo
, GLX_DEPTH_SIZE
, &value
) || value
< 24)
154 void CGLContextGLX::SetVSync(bool enable
)
156 // turn of current setting first
157 if(m_glXSwapIntervalEXT
)
158 m_glXSwapIntervalEXT(m_dpy
, m_glxWindow
, 0);
159 else if(m_glXSwapIntervalMESA
)
160 m_glXSwapIntervalMESA(0);
167 if (m_glXSwapIntervalEXT
)
169 m_glXSwapIntervalEXT(m_dpy
, m_glxWindow
, 1);
172 if (m_glXSwapIntervalMESA
)
174 if(m_glXSwapIntervalMESA(1) == 0)
177 CLog::Log(LOGWARNING
, "{} - glXSwapIntervalMESA failed", __FUNCTION__
);
179 if (m_glXWaitVideoSyncSGI
&& m_glXGetVideoSyncSGI
&& !m_vsyncMode
)
182 if(m_glXGetVideoSyncSGI(&count
) == 0)
185 CLog::Log(LOGWARNING
, "{} - glXGetVideoSyncSGI failed, glcontext probably not direct",
190 void CGLContextGLX::SwapBuffers()
192 if (m_vsyncMode
== 3)
195 unsigned int before
= 0, after
= 0;
196 if (m_glXGetVideoSyncSGI(&before
) != 0)
197 CLog::Log(LOGERROR
, "{} - glXGetVideoSyncSGI - Failed to get current retrace count",
200 glXSwapBuffers(m_dpy
, m_glxWindow
);
203 if(m_glXGetVideoSyncSGI(&after
) != 0)
204 CLog::Log(LOGERROR
, "{} - glXGetVideoSyncSGI - Failed to get current retrace count",
212 if (m_iVSyncErrors
> 0)
214 CLog::Log(LOGINFO
, "GL: retrace count didn't change after buffer swap, switching to vsync mode 4");
219 if (m_iVSyncErrors
< -200)
223 "GL: retrace count change for {} consecutive buffer swap, switching to vsync mode 2",
229 else if (m_vsyncMode
== 4)
232 unsigned int before
= 0, swap
= 0, after
= 0;
233 if (m_glXGetVideoSyncSGI(&before
) != 0)
234 CLog::Log(LOGERROR
, "{} - glXGetVideoSyncSGI - Failed to get current retrace count",
237 if(m_glXWaitVideoSyncSGI(2, (before
+1)%2, &swap
) != 0)
238 CLog::Log(LOGERROR
, "{} - glXWaitVideoSyncSGI - Returned error", __FUNCTION__
);
240 glXSwapBuffers(m_dpy
, m_glxWindow
);
243 if (m_glXGetVideoSyncSGI(&after
) != 0)
244 CLog::Log(LOGERROR
, "{} - glXGetVideoSyncSGI - Failed to get current retrace count",
248 CLog::Log(LOGERROR
, "{} - glXWaitVideoSyncSGI - Woke up early", __FUNCTION__
);
250 if (after
> before
+ 1)
255 if (m_iVSyncErrors
> 30)
257 CLog::Log(LOGINFO
, "GL: retrace count seems to be changing due to the swapbuffers call, switching to vsync mode 3");
263 glXSwapBuffers(m_dpy
, m_glxWindow
);
266 void CGLContextGLX::QueryExtensions()
269 m_extensions
+= glXQueryExtensionsString(m_dpy
, m_nScreen
);
272 CLog::Log(LOGDEBUG
, "GLX_EXTENSIONS:{}", m_extensions
);
274 if (IsExtSupported("GLX_SGI_video_sync"))
275 m_glXWaitVideoSyncSGI
= (int (*)(int, int, unsigned int*))glXGetProcAddress((const GLubyte
*)"glXWaitVideoSyncSGI");
277 m_glXWaitVideoSyncSGI
= NULL
;
279 if (IsExtSupported("GLX_SGI_video_sync"))
280 m_glXGetVideoSyncSGI
= (int (*)(unsigned int*))glXGetProcAddress((const GLubyte
*)"glXGetVideoSyncSGI");
282 m_glXGetVideoSyncSGI
= NULL
;
284 if (IsExtSupported("GLX_MESA_swap_control"))
285 m_glXSwapIntervalMESA
= (int (*)(int))glXGetProcAddress((const GLubyte
*)"glXSwapIntervalMESA");
287 m_glXSwapIntervalMESA
= NULL
;
289 if (IsExtSupported("GLX_EXT_swap_control"))
290 m_glXSwapIntervalEXT
= (PFNGLXSWAPINTERVALEXTPROC
)glXGetProcAddress((const GLubyte
*)"glXSwapIntervalEXT");
292 m_glXSwapIntervalEXT
= NULL
;