[Test] Added tests for CUtil::SplitParams
[xbmc.git] / xbmc / windowing / X11 / GLContextGLX.cpp
blob3c31c2248c04c78e59be599351a7089a345bc5aa
1 /*
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.
7 */
9 #include "GLContextGLX.h"
11 #include "utils/log.h"
13 #include <GL/glx.h>
15 #include "system_gl.h"
17 using namespace KODI::WINDOWING::X11;
19 CGLContextGLX::CGLContextGLX(Display *dpy) : CGLContext(dpy)
21 m_extPrefix = "GLX_";
22 m_vsyncMode = 0;
25 bool CGLContextGLX::Refresh(bool force, int screen, Window glWindow, bool &newContext)
27 bool retVal = false;
28 m_glxWindow = glWindow;
29 m_nScreen = screen;
31 // refresh context
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);
37 return true;
40 // create context
42 XVisualInfo vMask;
43 XVisualInfo *visuals;
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. */
52 vMask.depth = 24;
54 if (XGetWindowAttributes(m_dpy, glWindow, &winAttr))
56 vMask.visualid = XVisualIDFromVisual(winAttr.visual);
57 vInfo = XGetVisualInfo(m_dpy, VisualScreenMask | VisualIDMask, &vMask, &availableVisuals);
58 if (!vInfo)
59 CLog::Log(LOGWARNING, "Failed to get VisualInfo of visual 0x{:x}", (unsigned)vMask.visualid);
60 else if(!IsSuitableVisual(vInfo))
62 CLog::Log(LOGWARNING,
63 "Visual 0x{:x} of the window is not suitable, looking for another one...",
64 (unsigned)vInfo->visualid);
65 vMask.depth = vInfo->depth;
66 XFree(vInfo);
67 vInfo = NULL;
70 else
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. */
77 if (!vInfo)
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);
86 break;
89 XFree(visuals);
92 if (vInfo)
94 CLog::Log(LOGINFO, "Using visual 0x{:x}", (unsigned)vInfo->visualid);
95 if (m_glxContext)
97 glXMakeCurrent(m_dpy, None, NULL);
98 glXDestroyContext(m_dpy, m_glxContext);
99 XSync(m_dpy, False);
102 if ((m_glxContext = glXCreateContext(m_dpy, vInfo, NULL, True)))
104 // make this context current
105 glXMakeCurrent(m_dpy, glWindow, m_glxContext);
106 retVal = true;
107 newContext = true;
109 else
110 CLog::Log(LOGERROR, "GLX Error: Could not create context");
112 XFree(vInfo);
114 else
116 CLog::Log(LOGERROR, "GLX Error: vInfo is NULL!");
119 return retVal;
122 void CGLContextGLX::Destroy()
124 glXMakeCurrent(m_dpy, None, NULL);
125 glXDestroyContext(m_dpy, m_glxContext);
126 m_glxContext = 0;
129 void CGLContextGLX::Detach()
131 glXMakeCurrent(m_dpy, None, NULL);
134 bool CGLContextGLX::IsSuitableVisual(XVisualInfo *vInfo)
136 int value;
138 if (glXGetConfig(m_dpy, vInfo, GLX_RGBA, &value) || !value)
139 return false;
140 if (glXGetConfig(m_dpy, vInfo, GLX_DOUBLEBUFFER, &value) || !value)
141 return false;
142 if (glXGetConfig(m_dpy, vInfo, GLX_RED_SIZE, &value) || value < 8)
143 return false;
144 if (glXGetConfig(m_dpy, vInfo, GLX_GREEN_SIZE, &value) || value < 8)
145 return false;
146 if (glXGetConfig(m_dpy, vInfo, GLX_BLUE_SIZE, &value) || value < 8)
147 return false;
148 if (glXGetConfig(m_dpy, vInfo, GLX_DEPTH_SIZE, &value) || value < 24)
149 return false;
151 return true;
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);
162 m_iVSyncErrors = 0;
164 if(!enable)
165 return;
167 if (m_glXSwapIntervalEXT)
169 m_glXSwapIntervalEXT(m_dpy, m_glxWindow, 1);
170 m_vsyncMode = 6;
172 if (m_glXSwapIntervalMESA)
174 if(m_glXSwapIntervalMESA(1) == 0)
175 m_vsyncMode = 2;
176 else
177 CLog::Log(LOGWARNING, "{} - glXSwapIntervalMESA failed", __FUNCTION__);
179 if (m_glXWaitVideoSyncSGI && m_glXGetVideoSyncSGI && !m_vsyncMode)
181 unsigned int count;
182 if(m_glXGetVideoSyncSGI(&count) == 0)
183 m_vsyncMode = 3;
184 else
185 CLog::Log(LOGWARNING, "{} - glXGetVideoSyncSGI failed, glcontext probably not direct",
186 __FUNCTION__);
190 void CGLContextGLX::SwapBuffers()
192 if (m_vsyncMode == 3)
194 glFinish();
195 unsigned int before = 0, after = 0;
196 if (m_glXGetVideoSyncSGI(&before) != 0)
197 CLog::Log(LOGERROR, "{} - glXGetVideoSyncSGI - Failed to get current retrace count",
198 __FUNCTION__);
200 glXSwapBuffers(m_dpy, m_glxWindow);
201 glFinish();
203 if(m_glXGetVideoSyncSGI(&after) != 0)
204 CLog::Log(LOGERROR, "{} - glXGetVideoSyncSGI - Failed to get current retrace count",
205 __FUNCTION__);
207 if (after == before)
208 m_iVSyncErrors = 1;
209 else
210 m_iVSyncErrors--;
212 if (m_iVSyncErrors > 0)
214 CLog::Log(LOGINFO, "GL: retrace count didn't change after buffer swap, switching to vsync mode 4");
215 m_iVSyncErrors = 0;
216 m_vsyncMode = 4;
219 if (m_iVSyncErrors < -200)
221 CLog::Log(
222 LOGINFO,
223 "GL: retrace count change for {} consecutive buffer swap, switching to vsync mode 2",
224 -m_iVSyncErrors);
225 m_iVSyncErrors = 0;
226 m_vsyncMode = 2;
229 else if (m_vsyncMode == 4)
231 glFinish();
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",
235 __FUNCTION__);
237 if(m_glXWaitVideoSyncSGI(2, (before+1)%2, &swap) != 0)
238 CLog::Log(LOGERROR, "{} - glXWaitVideoSyncSGI - Returned error", __FUNCTION__);
240 glXSwapBuffers(m_dpy, m_glxWindow);
241 glFinish();
243 if (m_glXGetVideoSyncSGI(&after) != 0)
244 CLog::Log(LOGERROR, "{} - glXGetVideoSyncSGI - Failed to get current retrace count",
245 __FUNCTION__);
247 if (after == before)
248 CLog::Log(LOGERROR, "{} - glXWaitVideoSyncSGI - Woke up early", __FUNCTION__);
250 if (after > before + 1)
251 m_iVSyncErrors++;
252 else
253 m_iVSyncErrors = 0;
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");
258 m_vsyncMode = 3;
259 m_iVSyncErrors = 0;
262 else
263 glXSwapBuffers(m_dpy, m_glxWindow);
266 void CGLContextGLX::QueryExtensions()
268 m_extensions = " ";
269 m_extensions += glXQueryExtensionsString(m_dpy, m_nScreen);
270 m_extensions += " ";
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");
276 else
277 m_glXWaitVideoSyncSGI = NULL;
279 if (IsExtSupported("GLX_SGI_video_sync"))
280 m_glXGetVideoSyncSGI = (int (*)(unsigned int*))glXGetProcAddress((const GLubyte*)"glXGetVideoSyncSGI");
281 else
282 m_glXGetVideoSyncSGI = NULL;
284 if (IsExtSupported("GLX_MESA_swap_control"))
285 m_glXSwapIntervalMESA = (int (*)(int))glXGetProcAddress((const GLubyte*)"glXSwapIntervalMESA");
286 else
287 m_glXSwapIntervalMESA = NULL;
289 if (IsExtSupported("GLX_EXT_swap_control"))
290 m_glXSwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddress((const GLubyte*)"glXSwapIntervalEXT");
291 else
292 m_glXSwapIntervalEXT = NULL;