diff options
Diffstat (limited to 'xbmc/windowing/X11/WinSystemX11GLContext.cpp')
-rw-r--r-- | xbmc/windowing/X11/WinSystemX11GLContext.cpp | 358 |
1 files changed, 358 insertions, 0 deletions
diff --git a/xbmc/windowing/X11/WinSystemX11GLContext.cpp b/xbmc/windowing/X11/WinSystemX11GLContext.cpp new file mode 100644 index 0000000..ad27aca --- /dev/null +++ b/xbmc/windowing/X11/WinSystemX11GLContext.cpp @@ -0,0 +1,358 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "WinSystemX11GLContext.h" + +#include "GLContextEGL.h" +#include "OptionalsReg.h" +#include "VideoSyncOML.h" +#include "X11DPMSSupport.h" +#include "application/ApplicationComponents.h" +#include "application/ApplicationSkinHandling.h" +#include "cores/RetroPlayer/process/X11/RPProcessInfoX11.h" +#include "cores/RetroPlayer/rendering/VideoRenderers/RPRendererOpenGL.h" +#include "cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.h" +#include "cores/VideoPlayer/Process/X11/ProcessInfoX11.h" +#include "cores/VideoPlayer/VideoRenderers/LinuxRendererGL.h" +#include "cores/VideoPlayer/VideoRenderers/RenderFactory.h" +#include "guilib/DispResource.h" +#include "rendering/gl/ScreenshotSurfaceGL.h" +#include "windowing/GraphicContext.h" +#include "windowing/WindowSystemFactory.h" + +#include <mutex> +#include <vector> + +#include <X11/Xlib.h> +#include <X11/Xutil.h> + +using namespace KODI; +using namespace KODI::WINDOWING::X11; + + +void CWinSystemX11GLContext::Register() +{ + KODI::WINDOWING::CWindowSystemFactory::RegisterWindowSystem(CreateWinSystem, "x11"); +} + +std::unique_ptr<CWinSystemBase> CWinSystemX11GLContext::CreateWinSystem() +{ + return std::make_unique<CWinSystemX11GLContext>(); +} + +CWinSystemX11GLContext::~CWinSystemX11GLContext() +{ + delete m_pGLContext; +} + +void CWinSystemX11GLContext::PresentRenderImpl(bool rendered) +{ + if (rendered) + m_pGLContext->SwapBuffers(); + + if (m_delayDispReset && m_dispResetTimer.IsTimePast()) + { + m_delayDispReset = false; + std::unique_lock<CCriticalSection> lock(m_resourceSection); + // tell any shared resources + for (std::vector<IDispResource *>::iterator i = m_resources.begin(); i != m_resources.end(); ++i) + (*i)->OnResetDisplay(); + } +} + +void CWinSystemX11GLContext::SetVSyncImpl(bool enable) +{ + m_pGLContext->SetVSync(enable); +} + +bool CWinSystemX11GLContext::IsExtSupported(const char* extension) const +{ + if(strncmp(extension, m_pGLContext->ExtPrefix().c_str(), 4) != 0) + return CRenderSystemGL::IsExtSupported(extension); + + return m_pGLContext->IsExtSupported(extension); +} + +XID CWinSystemX11GLContext::GetWindow() const +{ + return GLXGetWindow(m_pGLContext); +} + +void* CWinSystemX11GLContext::GetGlxContext() const +{ + return GLXGetContext(m_pGLContext); +} + +EGLDisplay CWinSystemX11GLContext::GetEGLDisplay() const +{ + return static_cast<CGLContextEGL*>(m_pGLContext)->m_eglDisplay; +} + +EGLSurface CWinSystemX11GLContext::GetEGLSurface() const +{ + return static_cast<CGLContextEGL*>(m_pGLContext)->m_eglSurface; +} + +EGLContext CWinSystemX11GLContext::GetEGLContext() const +{ + return static_cast<CGLContextEGL*>(m_pGLContext)->m_eglContext; +} + +EGLConfig CWinSystemX11GLContext::GetEGLConfig() const +{ + return static_cast<CGLContextEGL*>(m_pGLContext)->m_eglConfig; +} + +bool CWinSystemX11GLContext::SetWindow(int width, int height, bool fullscreen, const std::string &output, int *winstate) +{ + int newwin = 0; + + CWinSystemX11::SetWindow(width, height, fullscreen, output, &newwin); + if (newwin) + { + RefreshGLContext(m_currentOutput.compare(output) != 0); + XSync(m_dpy, False); + CServiceBroker::GetWinSystem()->GetGfxContext().Clear(0); + CServiceBroker::GetWinSystem()->GetGfxContext().Flip(true, false); + ResetVSync(); + + m_windowDirty = false; + m_bIsInternalXrr = false; + + if (!m_delayDispReset) + { + std::unique_lock<CCriticalSection> lock(m_resourceSection); + // tell any shared resources + for (std::vector<IDispResource *>::iterator i = m_resources.begin(); i != m_resources.end(); ++i) + (*i)->OnResetDisplay(); + } + } + return true; +} + +bool CWinSystemX11GLContext::CreateNewWindow(const std::string& name, bool fullScreen, RESOLUTION_INFO& res) +{ + if(!CWinSystemX11::CreateNewWindow(name, fullScreen, res)) + return false; + + m_pGLContext->QueryExtensions(); + return true; +} + +bool CWinSystemX11GLContext::ResizeWindow(int newWidth, int newHeight, int newLeft, int newTop) +{ + m_newGlContext = false; + CWinSystemX11::ResizeWindow(newWidth, newHeight, newLeft, newTop); + CRenderSystemGL::ResetRenderSystem(newWidth, newHeight); + + if (m_newGlContext) + { + auto& components = CServiceBroker::GetAppComponents(); + const auto appSkin = components.GetComponent<CApplicationSkinHandling>(); + appSkin->ReloadSkin(); + } + + return true; +} + +void CWinSystemX11GLContext::FinishWindowResize(int newWidth, int newHeight) +{ + m_newGlContext = false; + CWinSystemX11::FinishWindowResize(newWidth, newHeight); + CRenderSystemGL::ResetRenderSystem(newWidth, newHeight); + + if (m_newGlContext) + { + auto& components = CServiceBroker::GetAppComponents(); + const auto appSkin = components.GetComponent<CApplicationSkinHandling>(); + appSkin->ReloadSkin(); + } +} + +bool CWinSystemX11GLContext::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays) +{ + m_newGlContext = false; + CWinSystemX11::SetFullScreen(fullScreen, res, blankOtherDisplays); + CRenderSystemGL::ResetRenderSystem(res.iWidth, res.iHeight); + + if (m_newGlContext) + { + auto& components = CServiceBroker::GetAppComponents(); + const auto appSkin = components.GetComponent<CApplicationSkinHandling>(); + appSkin->ReloadSkin(); + } + + return true; +} + +bool CWinSystemX11GLContext::DestroyWindowSystem() +{ + if (m_pGLContext) + m_pGLContext->Destroy(); + return CWinSystemX11::DestroyWindowSystem(); +} + +bool CWinSystemX11GLContext::DestroyWindow() +{ + if (m_pGLContext) + m_pGLContext->Detach(); + return CWinSystemX11::DestroyWindow(); +} + +XVisualInfo* CWinSystemX11GLContext::GetVisual() +{ + int count = 0; + XVisualInfo vTemplate; + XVisualInfo *visual = nullptr; + + int vMask = VisualScreenMask | VisualDepthMask | VisualClassMask; + + vTemplate.screen = m_screen; + vTemplate.depth = 24; + vTemplate.c_class = TrueColor; + + visual = XGetVisualInfo(m_dpy, vMask, &vTemplate, &count); + + if (!visual) + { + vTemplate.depth = 30; + visual = XGetVisualInfo(m_dpy, vMask, &vTemplate, &count); + } + + return visual; +} + +bool CWinSystemX11GLContext::RefreshGLContext(bool force) +{ + bool success = false; + if (m_pGLContext) + { + if (force) + { + auto& components = CServiceBroker::GetAppComponents(); + const auto appSkin = components.GetComponent<CApplicationSkinHandling>(); + appSkin->UnloadSkin(); + CRenderSystemGL::DestroyRenderSystem(); + } + success = m_pGLContext->Refresh(force, m_screen, m_glWindow, m_newGlContext); + if (!success) + { + success = m_pGLContext->CreatePB(); + m_newGlContext = true; + } + if (force) + CRenderSystemGL::InitRenderSystem(); + return success; + } + + m_dpms = std::make_shared<CX11DPMSSupport>(); + VIDEOPLAYER::CProcessInfoX11::Register(); + RETRO::CRPProcessInfoX11::Register(); + RETRO::CRPProcessInfoX11::RegisterRendererFactory(new RETRO::CRendererFactoryOpenGL); + CDVDFactoryCodec::ClearHWAccels(); + VIDEOPLAYER::CRendererFactory::ClearRenderer(); + CLinuxRendererGL::Register(); + + CScreenshotSurfaceGL::Register(); + + std::string gpuvendor; + const char* vend = (const char*) glGetString(GL_VENDOR); + if (vend) + gpuvendor = vend; + std::transform(gpuvendor.begin(), gpuvendor.end(), gpuvendor.begin(), ::tolower); + bool isNvidia = (gpuvendor.compare(0, 6, "nvidia") == 0); + bool isIntel = (gpuvendor.compare(0, 5, "intel") == 0); + std::string gli = (getenv("KODI_GL_INTERFACE") != nullptr) ? getenv("KODI_GL_INTERFACE") : ""; + + if (gli != "GLX") + { + m_pGLContext = new CGLContextEGL(m_dpy, EGL_OPENGL_API); + success = m_pGLContext->Refresh(force, m_screen, m_glWindow, m_newGlContext); + if (success) + { + if (!isNvidia) + { + m_vaapiProxy.reset(VaapiProxyCreate()); + VaapiProxyConfig(m_vaapiProxy.get(), GetDisplay(), + static_cast<CGLContextEGL*>(m_pGLContext)->m_eglDisplay); + bool general = false; + bool deepColor = false; + VAAPIRegisterRenderGL(m_vaapiProxy.get(), general, deepColor); + if (general) + { + VAAPIRegister(m_vaapiProxy.get(), deepColor); + return true; + } + if (isIntel || gli == "EGL") + return true; + } + } + else if (gli == "EGL_PB") + { + success = m_pGLContext->CreatePB(); + if (success) + return true; + } + } + + delete m_pGLContext; + + // fallback for vdpau + m_pGLContext = GLXContextCreate(m_dpy); + success = m_pGLContext->Refresh(force, m_screen, m_glWindow, m_newGlContext); + if (success) + { + VDPAURegister(); + VDPAURegisterRender(); + } + return success; +} + +std::unique_ptr<CVideoSync> CWinSystemX11GLContext::GetVideoSync(void *clock) +{ + std::unique_ptr<CVideoSync> pVSync; + + if (dynamic_cast<CGLContextEGL*>(m_pGLContext)) + { + pVSync.reset(new CVideoSyncOML(clock, *this)); + } + else + { + pVSync.reset(GLXVideoSyncCreate(clock, *this)); + } + + return pVSync; +} + +float CWinSystemX11GLContext::GetFrameLatencyAdjustment() +{ + if (m_pGLContext) + { + uint64_t msc, interval; + float micros = m_pGLContext->GetVblankTiming(msc, interval); + return micros / 1000; + } + return 0; +} + +uint64_t CWinSystemX11GLContext::GetVblankTiming(uint64_t &msc, uint64_t &interval) +{ + if (m_pGLContext) + { + float micros = m_pGLContext->GetVblankTiming(msc, interval); + return micros; + } + msc = 0; + interval = 0; + return 0; +} + +void CWinSystemX11GLContext::delete_CVaapiProxy::operator()(CVaapiProxy *p) const +{ + VaapiProxyDelete(p); +} |