Merge pull request #26350 from jjd-uk/estuary_media_align
[xbmc.git] / xbmc / windowing / X11 / WinSystemX11GLContext.cpp
blob5bf3b7ae62bfc6a184378d97aeeb524a84067843
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 "WinSystemX11GLContext.h"
11 #include "GLContextEGL.h"
12 #include "OptionalsReg.h"
13 #include "ServiceBroker.h"
14 #include "VideoSyncOML.h"
15 #include "X11DPMSSupport.h"
16 #include "application/AppParams.h"
17 #include "application/ApplicationComponents.h"
18 #include "application/ApplicationSkinHandling.h"
19 #include "cores/RetroPlayer/process/X11/RPProcessInfoX11.h"
20 #include "cores/RetroPlayer/rendering/VideoRenderers/RPRendererOpenGL.h"
21 #include "cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.h"
22 #include "cores/VideoPlayer/Process/X11/ProcessInfoX11.h"
23 #include "cores/VideoPlayer/VideoReferenceClock.h"
24 #include "cores/VideoPlayer/VideoRenderers/LinuxRendererGL.h"
25 #include "cores/VideoPlayer/VideoRenderers/RenderFactory.h"
26 #include "guilib/DispResource.h"
27 #include "rendering/gl/ScreenshotSurfaceGL.h"
28 #include "windowing/GraphicContext.h"
29 #include "windowing/WindowSystemFactory.h"
31 #include <memory>
32 #include <mutex>
33 #include <vector>
35 #include <X11/Xlib.h>
36 #include <X11/Xutil.h>
38 using namespace KODI;
39 using namespace KODI::WINDOWING::X11;
42 void CWinSystemX11GLContext::Register()
44 KODI::WINDOWING::CWindowSystemFactory::RegisterWindowSystem(CreateWinSystem, "x11");
47 std::unique_ptr<CWinSystemBase> CWinSystemX11GLContext::CreateWinSystem()
49 return std::make_unique<CWinSystemX11GLContext>();
52 CWinSystemX11GLContext::~CWinSystemX11GLContext()
54 delete m_pGLContext;
57 void CWinSystemX11GLContext::PresentRenderImpl(bool rendered)
59 if (rendered)
60 m_pGLContext->SwapBuffers();
62 if (m_delayDispReset && m_dispResetTimer.IsTimePast())
64 m_delayDispReset = false;
65 std::unique_lock<CCriticalSection> lock(m_resourceSection);
66 // tell any shared resources
67 for (std::vector<IDispResource *>::iterator i = m_resources.begin(); i != m_resources.end(); ++i)
68 (*i)->OnResetDisplay();
72 void CWinSystemX11GLContext::SetVSyncImpl(bool enable)
74 m_pGLContext->SetVSync(enable);
77 bool CWinSystemX11GLContext::IsExtSupported(const char* extension) const
79 if(strncmp(extension, m_pGLContext->ExtPrefix().c_str(), 4) != 0)
80 return CRenderSystemGL::IsExtSupported(extension);
82 return m_pGLContext->IsExtSupported(extension);
85 XID CWinSystemX11GLContext::GetWindow() const
87 return GLXGetWindow(m_pGLContext);
90 void* CWinSystemX11GLContext::GetGlxContext() const
92 return GLXGetContext(m_pGLContext);
95 EGLDisplay CWinSystemX11GLContext::GetEGLDisplay() const
97 return static_cast<CGLContextEGL*>(m_pGLContext)->m_eglDisplay;
100 EGLSurface CWinSystemX11GLContext::GetEGLSurface() const
102 return static_cast<CGLContextEGL*>(m_pGLContext)->m_eglSurface;
105 EGLContext CWinSystemX11GLContext::GetEGLContext() const
107 return static_cast<CGLContextEGL*>(m_pGLContext)->m_eglContext;
110 EGLConfig CWinSystemX11GLContext::GetEGLConfig() const
112 return static_cast<CGLContextEGL*>(m_pGLContext)->m_eglConfig;
115 bool CWinSystemX11GLContext::BindTextureUploadContext()
117 if (m_pGLContext)
118 return static_cast<CGLContextEGL*>(m_pGLContext)->BindTextureUploadContext();
119 else
120 return false;
123 bool CWinSystemX11GLContext::UnbindTextureUploadContext()
125 if (m_pGLContext)
126 return static_cast<CGLContextEGL*>(m_pGLContext)->UnbindTextureUploadContext();
127 else
128 return false;
131 bool CWinSystemX11GLContext::HasContext()
133 if (m_pGLContext)
134 return static_cast<CGLContextEGL*>(m_pGLContext)->HasContext();
135 else
136 return false;
139 bool CWinSystemX11GLContext::SetWindow(int width, int height, bool fullscreen, const std::string &output, int *winstate)
141 int newwin = 0;
143 CWinSystemX11::SetWindow(width, height, fullscreen, output, &newwin);
144 if (newwin)
146 RefreshGLContext(m_currentOutput.compare(output) != 0);
147 XSync(m_dpy, False);
148 CServiceBroker::GetWinSystem()->GetGfxContext().Clear(0);
149 CServiceBroker::GetWinSystem()->GetGfxContext().Flip(true, false);
150 ResetVSync();
152 m_windowDirty = false;
153 m_bIsInternalXrr = false;
155 if (!m_delayDispReset)
157 std::unique_lock<CCriticalSection> lock(m_resourceSection);
158 // tell any shared resources
159 for (std::vector<IDispResource *>::iterator i = m_resources.begin(); i != m_resources.end(); ++i)
160 (*i)->OnResetDisplay();
163 return true;
166 bool CWinSystemX11GLContext::CreateNewWindow(const std::string& name, bool fullScreen, RESOLUTION_INFO& res)
168 if(!CWinSystemX11::CreateNewWindow(name, fullScreen, res))
169 return false;
171 m_pGLContext->QueryExtensions();
172 m_bufferAgeSupport = m_pGLContext->IsBufferAgeSupported();
173 return true;
176 bool CWinSystemX11GLContext::ResizeWindow(int newWidth, int newHeight, int newLeft, int newTop)
178 m_newGlContext = false;
179 CWinSystemX11::ResizeWindow(newWidth, newHeight, newLeft, newTop);
180 CRenderSystemGL::ResetRenderSystem(newWidth, newHeight);
182 if (m_newGlContext)
184 auto& components = CServiceBroker::GetAppComponents();
185 const auto appSkin = components.GetComponent<CApplicationSkinHandling>();
186 appSkin->ReloadSkin();
189 return true;
192 void CWinSystemX11GLContext::FinishWindowResize(int newWidth, int newHeight)
194 m_newGlContext = false;
195 CWinSystemX11::FinishWindowResize(newWidth, newHeight);
196 CRenderSystemGL::ResetRenderSystem(newWidth, newHeight);
198 if (m_newGlContext)
200 auto& components = CServiceBroker::GetAppComponents();
201 const auto appSkin = components.GetComponent<CApplicationSkinHandling>();
202 appSkin->ReloadSkin();
206 bool CWinSystemX11GLContext::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays)
208 m_newGlContext = false;
209 CWinSystemX11::SetFullScreen(fullScreen, res, blankOtherDisplays);
210 CRenderSystemGL::ResetRenderSystem(res.iWidth, res.iHeight);
212 if (m_newGlContext)
214 auto& components = CServiceBroker::GetAppComponents();
215 const auto appSkin = components.GetComponent<CApplicationSkinHandling>();
216 appSkin->ReloadSkin();
219 return true;
222 bool CWinSystemX11GLContext::DestroyWindowSystem()
224 if (m_pGLContext)
225 m_pGLContext->Destroy();
226 return CWinSystemX11::DestroyWindowSystem();
229 bool CWinSystemX11GLContext::DestroyWindow()
231 if (m_pGLContext)
232 m_pGLContext->Detach();
233 return CWinSystemX11::DestroyWindow();
236 XVisualInfo* CWinSystemX11GLContext::GetVisual()
238 int count = 0;
239 XVisualInfo vTemplate;
240 XVisualInfo *visual = nullptr;
242 int vMask = VisualScreenMask | VisualDepthMask | VisualClassMask;
244 vTemplate.screen = m_screen;
245 vTemplate.depth = 24;
246 vTemplate.c_class = TrueColor;
248 visual = XGetVisualInfo(m_dpy, vMask, &vTemplate, &count);
250 if (!visual)
252 vTemplate.depth = 30;
253 visual = XGetVisualInfo(m_dpy, vMask, &vTemplate, &count);
256 return visual;
259 bool CWinSystemX11GLContext::RefreshGLContext(bool force)
261 bool success = false;
262 if (m_pGLContext)
264 if (force)
266 auto& components = CServiceBroker::GetAppComponents();
267 const auto appSkin = components.GetComponent<CApplicationSkinHandling>();
268 appSkin->UnloadSkin();
269 CRenderSystemGL::DestroyRenderSystem();
271 success = m_pGLContext->Refresh(force, m_screen, m_glWindow, m_newGlContext);
272 if (!success)
274 success = m_pGLContext->CreatePB();
275 m_newGlContext = true;
277 if (force)
278 CRenderSystemGL::InitRenderSystem();
279 return success;
282 m_dpms = std::make_shared<CX11DPMSSupport>();
283 VIDEOPLAYER::CProcessInfoX11::Register();
284 RETRO::CRPProcessInfoX11::Register();
285 RETRO::CRPProcessInfoX11::RegisterRendererFactory(new RETRO::CRendererFactoryOpenGL);
286 CDVDFactoryCodec::ClearHWAccels();
287 VIDEOPLAYER::CRendererFactory::ClearRenderer();
288 CLinuxRendererGL::Register();
290 CScreenshotSurfaceGL::Register();
292 std::string gpuvendor;
293 const char* vend = (const char*) glGetString(GL_VENDOR);
294 if (vend)
295 gpuvendor = vend;
296 std::transform(gpuvendor.begin(), gpuvendor.end(), gpuvendor.begin(), ::tolower);
297 bool isNvidia = (gpuvendor.compare(0, 6, "nvidia") == 0);
298 bool isIntel = (gpuvendor.compare(0, 5, "intel") == 0);
300 std::string_view gli = CServiceBroker::GetAppParams()->GetGlInterface();
302 if (gli != "glx")
304 m_pGLContext = new CGLContextEGL(m_dpy, EGL_OPENGL_API);
305 success = m_pGLContext->Refresh(force, m_screen, m_glWindow, m_newGlContext);
306 if (success)
308 if (!isNvidia)
310 m_vaapiProxy.reset(VaapiProxyCreate());
311 VaapiProxyConfig(m_vaapiProxy.get(), GetDisplay(),
312 static_cast<CGLContextEGL*>(m_pGLContext)->m_eglDisplay);
313 bool general = false;
314 bool deepColor = false;
315 VAAPIRegisterRenderGL(m_vaapiProxy.get(), general, deepColor);
316 if (general)
318 VAAPIRegister(m_vaapiProxy.get(), deepColor);
319 return true;
321 if (isIntel || gli == "egl")
322 return true;
325 else if (gli == "egl-pb")
327 success = m_pGLContext->CreatePB();
328 if (success)
329 return true;
333 delete m_pGLContext;
335 // fallback for vdpau
336 m_pGLContext = GLXContextCreate(m_dpy);
337 success = m_pGLContext->Refresh(force, m_screen, m_glWindow, m_newGlContext);
338 if (success)
340 VDPAURegister();
341 VDPAURegisterRender();
343 return success;
346 std::unique_ptr<CVideoSync> CWinSystemX11GLContext::GetVideoSync(CVideoReferenceClock* clock)
348 std::unique_ptr<CVideoSync> pVSync;
350 if (dynamic_cast<CGLContextEGL*>(m_pGLContext))
352 pVSync = std::make_unique<CVideoSyncOML>(clock, *this);
354 else
356 pVSync.reset(GLXVideoSyncCreate(clock, *this));
359 return pVSync;
362 float CWinSystemX11GLContext::GetFrameLatencyAdjustment()
364 if (m_pGLContext)
366 uint64_t msc, interval;
367 float micros = m_pGLContext->GetVblankTiming(msc, interval);
368 return micros / 1000;
370 return 0;
373 uint64_t CWinSystemX11GLContext::GetVblankTiming(uint64_t &msc, uint64_t &interval)
375 if (m_pGLContext)
377 float micros = m_pGLContext->GetVblankTiming(msc, interval);
378 return micros;
380 msc = 0;
381 interval = 0;
382 return 0;
385 void CWinSystemX11GLContext::delete_CVaapiProxy::operator()(CVaapiProxy *p) const
387 VaapiProxyDelete(p);