diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 18:07:22 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 18:07:22 +0000 |
commit | c04dcc2e7d834218ef2d4194331e383402495ae1 (patch) | |
tree | 7333e38d10d75386e60f336b80c2443c1166031d /xbmc/windowing/tvos | |
parent | Initial commit. (diff) | |
download | kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.tar.xz kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.zip |
Adding upstream version 2:20.4+dfsg.upstream/2%20.4+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'xbmc/windowing/tvos')
-rw-r--r-- | xbmc/windowing/tvos/CMakeLists.txt | 10 | ||||
-rw-r--r-- | xbmc/windowing/tvos/OSScreenSaverTVOS.h | 19 | ||||
-rw-r--r-- | xbmc/windowing/tvos/OSScreenSaverTVOS.mm | 21 | ||||
-rw-r--r-- | xbmc/windowing/tvos/VideoSyncTVos.cpp | 93 | ||||
-rw-r--r-- | xbmc/windowing/tvos/VideoSyncTVos.h | 44 | ||||
-rw-r--r-- | xbmc/windowing/tvos/WinEventsTVOS.h | 35 | ||||
-rw-r--r-- | xbmc/windowing/tvos/WinEventsTVOS.mm | 76 | ||||
-rw-r--r-- | xbmc/windowing/tvos/WinSystemTVOS.h | 107 | ||||
-rw-r--r-- | xbmc/windowing/tvos/WinSystemTVOS.mm | 453 |
9 files changed, 858 insertions, 0 deletions
diff --git a/xbmc/windowing/tvos/CMakeLists.txt b/xbmc/windowing/tvos/CMakeLists.txt new file mode 100644 index 0000000..d9aa9cc --- /dev/null +++ b/xbmc/windowing/tvos/CMakeLists.txt @@ -0,0 +1,10 @@ +set(SOURCES OSScreenSaverTVOS.mm + WinEventsTVOS.mm + WinSystemTVOS.mm + VideoSyncTVos.cpp) +set(HEADERS OSScreenSaverTVOS.h + WinEventsTVOS.h + WinSystemTVOS.h + VideoSyncTVos.h) + +core_add_library(windowing_tvos) diff --git a/xbmc/windowing/tvos/OSScreenSaverTVOS.h b/xbmc/windowing/tvos/OSScreenSaverTVOS.h new file mode 100644 index 0000000..2b5d3bd --- /dev/null +++ b/xbmc/windowing/tvos/OSScreenSaverTVOS.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2017-2019 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. + */ + +#pragma once + +#include "windowing/OSScreenSaver.h" + +class COSScreenSaverTVOS : public KODI::WINDOWING::IOSScreenSaver +{ +public: + COSScreenSaverTVOS() = default; + void Inhibit() override; + void Uninhibit() override; +}; diff --git a/xbmc/windowing/tvos/OSScreenSaverTVOS.mm b/xbmc/windowing/tvos/OSScreenSaverTVOS.mm new file mode 100644 index 0000000..7af5580 --- /dev/null +++ b/xbmc/windowing/tvos/OSScreenSaverTVOS.mm @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2017-2019 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. + */ + +#import "OSScreenSaverTVOS.h" + +#import "platform/darwin/tvos/XBMCController.h" + +void COSScreenSaverTVOS::Inhibit() +{ + [g_xbmcController disableScreenSaver]; +} + +void COSScreenSaverTVOS::Uninhibit() +{ + [g_xbmcController enableScreenSaver]; +} diff --git a/xbmc/windowing/tvos/VideoSyncTVos.cpp b/xbmc/windowing/tvos/VideoSyncTVos.cpp new file mode 100644 index 0000000..c00aa60 --- /dev/null +++ b/xbmc/windowing/tvos/VideoSyncTVos.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2015-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 "VideoSyncTVos.h" + +#include "cores/VideoPlayer/VideoReferenceClock.h" +#include "utils/MathUtils.h" +#include "utils/TimeUtils.h" +#include "utils/log.h" +#include "windowing/GraphicContext.h" +#import "windowing/tvos/WinSystemTVOS.h" + +bool CVideoSyncTVos::Setup(PUPDATECLOCK func) +{ + CLog::Log(LOGDEBUG, "CVideoSyncTVos::{} setting up TVOS", __FUNCTION__); + + //init the vblank timestamp + m_LastVBlankTime = CurrentHostCounter(); + UpdateClock = func; + m_abortEvent.Reset(); + + bool setupOk = InitDisplayLink(); + if (setupOk) + { + m_winSystem.Register(this); + } + + return setupOk; +} + +void CVideoSyncTVos::Run(CEvent& stopEvent) +{ + //because cocoa has a vblank callback, we just keep sleeping until we're asked to stop the thread + XbmcThreads::CEventGroup waitGroup{&stopEvent, &m_abortEvent}; + waitGroup.wait(); +} + +void CVideoSyncTVos::Cleanup() +{ + CLog::Log(LOGDEBUG, "CVideoSyncTVos::{} cleaning up TVOS", __FUNCTION__); + DeinitDisplayLink(); + m_winSystem.Unregister(this); +} + +float CVideoSyncTVos::GetFps() +{ + m_fps = CServiceBroker::GetWinSystem()->GetGfxContext().GetFPS(); + CLog::Log(LOGDEBUG, "CVideoSyncTVos::{} Detected refreshrate: {} hertz", __FUNCTION__, m_fps); + return m_fps; +} + +void CVideoSyncTVos::OnResetDisplay() +{ + m_abortEvent.Set(); +} + +void CVideoSyncTVos::TVosVblankHandler() +{ + int64_t nowtime = CurrentHostCounter(); + + //calculate how many vblanks happened + double VBlankTime = + static_cast<double>(nowtime - m_LastVBlankTime) / static_cast<double>(CurrentHostFrequency()); + int NrVBlanks = MathUtils::round_int(VBlankTime * static_cast<double>(m_fps)); + + //save the timestamp of this vblank so we can calculate how many happened next time + m_LastVBlankTime = nowtime; + + //update the vblank timestamp, update the clock and send a signal that we got a vblank + UpdateClock(NrVBlanks, nowtime, m_refClock); +} + +bool CVideoSyncTVos::InitDisplayLink() +{ + bool ret = true; + CLog::Log(LOGDEBUG, "CVideoSyncTVos: setting up displaylink"); + if (!m_winSystem.InitDisplayLink(this)) + { + CLog::Log(LOGDEBUG, "CVideoSyncTVos: InitDisplayLink failed"); + ret = false; + } + return ret; +} + +void CVideoSyncTVos::DeinitDisplayLink() +{ + m_winSystem.DeinitDisplayLink(); +} diff --git a/xbmc/windowing/tvos/VideoSyncTVos.h b/xbmc/windowing/tvos/VideoSyncTVos.h new file mode 100644 index 0000000..de78226 --- /dev/null +++ b/xbmc/windowing/tvos/VideoSyncTVos.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2015-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. + */ + +#pragma once + +#include "guilib/DispResource.h" +#include "windowing/VideoSync.h" + +class CWinSystemTVOS; + +class CVideoSyncTVos : public CVideoSync, IDispResource +{ +public: + CVideoSyncTVos(void* clock, CWinSystemTVOS& winSystem) : CVideoSync(clock), m_winSystem(winSystem) + { + } + + // CVideoSync interface + bool Setup(PUPDATECLOCK func) override; + void Run(CEvent& stopEvent) override; + void Cleanup() override; + float GetFps() override; + + // IDispResource interface + void OnResetDisplay() override; + + // used in the displaylink callback + void TVosVblankHandler(); + +private: + // CVideoSyncDarwin interface + virtual bool InitDisplayLink(); + virtual void DeinitDisplayLink(); + + //timestamp of the last vblank, used for calculating how many vblanks happened + int64_t m_LastVBlankTime = 0; + CEvent m_abortEvent; + CWinSystemTVOS& m_winSystem; +}; diff --git a/xbmc/windowing/tvos/WinEventsTVOS.h b/xbmc/windowing/tvos/WinEventsTVOS.h new file mode 100644 index 0000000..fa30665 --- /dev/null +++ b/xbmc/windowing/tvos/WinEventsTVOS.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2012-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. + */ + +#pragma once + +#include "threads/CriticalSection.h" +#include "threads/Event.h" +#include "threads/Thread.h" +#include "windowing/WinEvents.h" + +#include <list> +#include <queue> +#include <string> +#include <vector> + +class CWinEventsTVOS : public IWinEvents, public CThread +{ +public: + CWinEventsTVOS(); + ~CWinEventsTVOS(); + + void MessagePush(XBMC_Event* newEvent); + size_t GetQueueSize(); + + bool MessagePump(); + +private: + CCriticalSection m_eventsCond; + std::list<XBMC_Event> m_events; +}; diff --git a/xbmc/windowing/tvos/WinEventsTVOS.mm b/xbmc/windowing/tvos/WinEventsTVOS.mm new file mode 100644 index 0000000..67e9e54 --- /dev/null +++ b/xbmc/windowing/tvos/WinEventsTVOS.mm @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2012-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 "WinEventsTVOS.h" + +#include "ServiceBroker.h" +#include "application/AppInboundProtocol.h" +#include "guilib/GUIWindowManager.h" +#include "input/InputManager.h" +#include "input/XBMC_vkeys.h" +#include "threads/CriticalSection.h" +#include "utils/log.h" + +#include <list> +#include <mutex> + +static CCriticalSection g_inputCond; + +static std::list<XBMC_Event> events; + +CWinEventsTVOS::CWinEventsTVOS() : CThread("CWinEventsTVOS") +{ + CLog::Log(LOGDEBUG, "CWinEventsTVOS::CWinEventsTVOS"); + Create(); +} + +CWinEventsTVOS::~CWinEventsTVOS() +{ + m_bStop = true; + StopThread(true); +} + +void CWinEventsTVOS::MessagePush(XBMC_Event* newEvent) +{ + std::unique_lock<CCriticalSection> lock(m_eventsCond); + + m_events.push_back(*newEvent); +} + +size_t CWinEventsTVOS::GetQueueSize() +{ + std::unique_lock<CCriticalSection> lock(g_inputCond); + return events.size(); +} + + +bool CWinEventsTVOS::MessagePump() +{ + bool ret = false; + std::shared_ptr<CAppInboundProtocol> appPort = CServiceBroker::GetAppPort(); + + // Do not always loop, only pump the initial queued count events. else if ui keep pushing + // events the loop won't finish then it will block xbmc main message loop. + for (size_t pumpEventCount = GetQueueSize(); pumpEventCount > 0; --pumpEventCount) + { + // Pop up only one event per time since in App::OnEvent it may init modal dialog which init + // deeper message loop and call the deeper MessagePump from there. + XBMC_Event pumpEvent; + { + std::unique_lock<CCriticalSection> lock(g_inputCond); + if (events.empty()) + return ret; + pumpEvent = events.front(); + events.pop_front(); + } + + if (appPort) + ret = appPort->OnEvent(pumpEvent); + } + return ret; +} diff --git a/xbmc/windowing/tvos/WinSystemTVOS.h b/xbmc/windowing/tvos/WinSystemTVOS.h new file mode 100644 index 0000000..774b7e9 --- /dev/null +++ b/xbmc/windowing/tvos/WinSystemTVOS.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2010-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. + */ + +#pragma once + +#include "rendering/gles/RenderSystemGLES.h" +#include "threads/CriticalSection.h" +#include "threads/Timer.h" +#include "windowing/OSScreenSaver.h" +#include "windowing/WinSystem.h" + +#include <memory> +#include <string> +#include <vector> + +#include <CoreVideo/CVOpenGLESTextureCache.h> + +class IDispResource; +class CVideoSyncTVos; +struct CADisplayLinkWrapper; + +class CWinSystemTVOS : public CWinSystemBase, public CRenderSystemGLES, public ITimerCallback +{ +public: + CWinSystemTVOS(); + virtual ~CWinSystemTVOS(); + + static void Register(); + static std::unique_ptr<CWinSystemBase> CreateWinSystem(); + + // ITimerCallback interface + virtual void OnTimeout() override {} + + void MessagePush(XBMC_Event* newEvent); + size_t GetQueueSize(); + void AnnounceOnLostDevice(); + void AnnounceOnResetDevice(); + void StartLostDeviceTimer(); + void StopLostDeviceTimer(); + int GetDisplayIndexFromSettings(); + // Implementation of CWinSystemBase + CRenderSystemBase* GetRenderSystem() override { return this; } + bool InitWindowSystem() override; + bool DestroyWindowSystem() override; + bool CreateNewWindow(const std::string& name, bool fullScreen, RESOLUTION_INFO& res) override; + bool DestroyWindow() override; + bool ResizeWindow(int newWidth, int newHeight, int newLeft, int newTop) override; + bool SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays) override; + void UpdateResolutions() override; + bool CanDoWindowed() override { return false; } + + void ShowOSMouse(bool show) override {} + bool HasCursor() override; + + void NotifyAppActiveChange(bool bActivated) override; + + bool Minimize() override; + bool Restore() override; + bool Hide() override; + bool Show(bool raise = true) override; + + bool IsExtSupported(const char* extension) const override; + + bool BeginRender() override; + bool EndRender() override; + + void Register(IDispResource* resource) override; + void Unregister(IDispResource* resource) override; + + //virtual std::unique_ptr<CVideoSync> GetVideoSync(void* clock) override; + + std::vector<std::string> GetConnectedOutputs() override; + + bool InitDisplayLink(CVideoSyncTVos* syncImpl); + void DeinitDisplayLink(void); + void OnAppFocusChange(bool focus); + bool IsBackgrounded() const { return m_bIsBackgrounded; } + CVEAGLContext GetEAGLContextObj(); + + // winevents override + bool MessagePump() override; + +protected: + virtual std::unique_ptr<KODI::WINDOWING::IOSScreenSaver> GetOSScreenSaverImpl() override; + void PresentRenderImpl(bool rendered) override; + void SetVSyncImpl(bool enable) override {} + + void* m_glView; // EAGLView opaque + void* m_WorkingContext; // shared EAGLContext opaque + bool m_bWasFullScreenBeforeMinimize; + std::string m_eglext; + CCriticalSection m_resourceSection; + std::vector<IDispResource*> m_resources; + bool m_bIsBackgrounded; + CTimer m_lostDeviceTimer; + +private: + bool GetScreenResolution(int* w, int* h, double* fps, int screenIdx); + void FillInVideoModes(int screenIdx); + bool SwitchToVideoMode(int width, int height, double refreshrate); + CADisplayLinkWrapper* m_pDisplayLink; +}; diff --git a/xbmc/windowing/tvos/WinSystemTVOS.mm b/xbmc/windowing/tvos/WinSystemTVOS.mm new file mode 100644 index 0000000..bd47c6f --- /dev/null +++ b/xbmc/windowing/tvos/WinSystemTVOS.mm @@ -0,0 +1,453 @@ +/* + * Copyright (C) 2010-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 "WinSystemTVOS.h" + +#include "ServiceBroker.h" +#import "cores/AudioEngine/Sinks/AESinkDARWINTVOS.h" +#include "cores/RetroPlayer/process/ios/RPProcessInfoIOS.h" +#include "cores/RetroPlayer/rendering/VideoRenderers/RPRendererOpenGLES.h" +#include "cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.h" +#include "cores/VideoPlayer/DVDCodecs/Video/VTB.h" +#include "cores/VideoPlayer/Process/ios/ProcessInfoIOS.h" +#include "cores/VideoPlayer/VideoRenderers/HwDecRender/RendererVTBGLES.h" +#include "cores/VideoPlayer/VideoRenderers/LinuxRendererGLES.h" +#include "cores/VideoPlayer/VideoRenderers/RenderFactory.h" +#include "filesystem/SpecialProtocol.h" +#include "guilib/DispResource.h" +#include "guilib/Texture.h" +#include "messaging/ApplicationMessenger.h" +#include "settings/DisplaySettings.h" +#include "settings/Settings.h" +#include "settings/SettingsComponent.h" +#include "utils/StringUtils.h" +#include "utils/log.h" +#include "windowing/GraphicContext.h" +#include "windowing/OSScreenSaver.h" +#include "windowing/WindowSystemFactory.h" +#import "windowing/tvos/OSScreenSaverTVOS.h" +#import "windowing/tvos/VideoSyncTVos.h" +#import "windowing/tvos/WinEventsTVOS.h" + +#import "platform/darwin/DarwinUtils.h" +#import "platform/darwin/tvos/TVOSDisplayManager.h" +#import "platform/darwin/tvos/XBMCController.h" + +#include <memory> +#include <mutex> +#include <vector> + +#import <Foundation/Foundation.h> +#import <OpenGLES/ES2/gl.h> +#import <OpenGLES/ES2/glext.h> +#import <QuartzCore/CADisplayLink.h> + +using namespace std::chrono_literals; + +#define CONST_HDMI "HDMI" + +// if there was a devicelost callback +// but no device reset for 3 secs +// a timeout fires the reset callback +// (for ensuring that e.x. AE isn't stuck) +constexpr auto LOST_DEVICE_TIMEOUT_MS{3000ms}; + +// TVOSDisplayLinkCallback is defined in the lower part of the file +@interface TVOSDisplayLinkCallback : NSObject +{ +@private + CVideoSyncTVos* videoSyncImpl; +} +@property(nonatomic, setter=SetVideoSyncImpl:) CVideoSyncTVos* videoSyncImpl; +- (void)runDisplayLink; +@end + +using namespace KODI; +using namespace MESSAGING; + +struct CADisplayLinkWrapper +{ + CADisplayLink* impl; + TVOSDisplayLinkCallback* callbackClass; +}; + +void CWinSystemTVOS::Register() +{ + KODI::WINDOWING::CWindowSystemFactory::RegisterWindowSystem(CreateWinSystem); +} + +std::unique_ptr<CWinSystemBase> CWinSystemTVOS::CreateWinSystem() +{ + return std::make_unique<CWinSystemTVOS>(); +} + +void CWinSystemTVOS::MessagePush(XBMC_Event* newEvent) +{ + dynamic_cast<CWinEventsTVOS&>(*m_winEvents).MessagePush(newEvent); +} + +size_t CWinSystemTVOS::GetQueueSize() +{ + return dynamic_cast<CWinEventsTVOS&>(*m_winEvents).GetQueueSize(); +} + +void CWinSystemTVOS::AnnounceOnLostDevice() +{ + std::unique_lock<CCriticalSection> lock(m_resourceSection); + // tell any shared resources + CLog::Log(LOGDEBUG, "CWinSystemTVOS::AnnounceOnLostDevice"); + for (auto dispResource : m_resources) + dispResource->OnLostDisplay(); +} + +void CWinSystemTVOS::AnnounceOnResetDevice() +{ + std::unique_lock<CCriticalSection> lock(m_resourceSection); + // tell any shared resources + CLog::Log(LOGDEBUG, "CWinSystemTVOS::AnnounceOnResetDevice"); + for (auto dispResource : m_resources) + dispResource->OnResetDisplay(); +} + +void CWinSystemTVOS::StartLostDeviceTimer() +{ + if (m_lostDeviceTimer.IsRunning()) + m_lostDeviceTimer.Restart(); + else + m_lostDeviceTimer.Start(LOST_DEVICE_TIMEOUT_MS, false); +} + +void CWinSystemTVOS::StopLostDeviceTimer() +{ + m_lostDeviceTimer.Stop(); +} + + +int CWinSystemTVOS::GetDisplayIndexFromSettings() +{ + // ATV only supports 1 screen with id = 0 + return 0; +} + +CWinSystemTVOS::CWinSystemTVOS() : CWinSystemBase(), m_lostDeviceTimer(this) +{ + m_bIsBackgrounded = false; + m_pDisplayLink = new CADisplayLinkWrapper; + m_pDisplayLink->callbackClass = [[TVOSDisplayLinkCallback alloc] init]; + + m_winEvents.reset(new CWinEventsTVOS()); + + CAESinkDARWINTVOS::Register(); +} + +CWinSystemTVOS::~CWinSystemTVOS() +{ + m_pDisplayLink->callbackClass = nil; + delete m_pDisplayLink; +} + +bool CWinSystemTVOS::InitWindowSystem() +{ + return CWinSystemBase::InitWindowSystem(); +} + +bool CWinSystemTVOS::DestroyWindowSystem() +{ + return true; +} + +std::unique_ptr<KODI::WINDOWING::IOSScreenSaver> CWinSystemTVOS::GetOSScreenSaverImpl() +{ + std::unique_ptr<KODI::WINDOWING::IOSScreenSaver> screensaver = + std::make_unique<COSScreenSaverTVOS>(); + return screensaver; +} + +bool CWinSystemTVOS::CreateNewWindow(const std::string& name, bool fullScreen, RESOLUTION_INFO& res) +{ + if (!SetFullScreen(fullScreen, res, false)) + return false; + + [g_xbmcController setFramebuffer]; + + m_bWindowCreated = true; + + m_eglext = " "; + + const char* tmpExtensions = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)); + if (tmpExtensions != nullptr) + { + m_eglext += tmpExtensions; + m_eglext += " "; + } + + CLog::Log(LOGDEBUG, "EGL_EXTENSIONS: {}", m_eglext); + + // register platform dependent objects + CDVDFactoryCodec::ClearHWAccels(); + VTB::CDecoder::Register(); + VIDEOPLAYER::CRendererFactory::ClearRenderer(); + CLinuxRendererGLES::Register(); + CRendererVTB::Register(); + VIDEOPLAYER::CProcessInfoIOS::Register(); + RETRO::CRPProcessInfoIOS::Register(); + RETRO::CRPProcessInfoIOS::RegisterRendererFactory(new RETRO::CRendererFactoryOpenGLES); + + return true; +} + +bool CWinSystemTVOS::DestroyWindow() +{ + return true; +} + +bool CWinSystemTVOS::ResizeWindow(int newWidth, int newHeight, int newLeft, int newTop) +{ + if (m_nWidth != newWidth || m_nHeight != newHeight) + { + m_nWidth = newWidth; + m_nHeight = newHeight; + } + + CRenderSystemGLES::ResetRenderSystem(newWidth, newHeight); + + return true; +} + +bool CWinSystemTVOS::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays) +{ + m_nWidth = res.iWidth; + m_nHeight = res.iHeight; + m_bFullScreen = fullScreen; + + CLog::Log(LOGDEBUG, "About to switch to {} x {} @ {}", m_nWidth, m_nHeight, res.fRefreshRate); + SwitchToVideoMode(res.iWidth, res.iHeight, static_cast<double>(res.fRefreshRate)); + CRenderSystemGLES::ResetRenderSystem(res.iWidth, res.iHeight); + + return true; +} + +bool CWinSystemTVOS::SwitchToVideoMode(int width, int height, double refreshrate) +{ + /*! @todo Currently support SDR dynamic range only. HDR shouldn't be done during + * a modeswitch. Look to create supplemental method to handle sdr/hdr enable + */ + [g_xbmcController.displayManager displayRateSwitch:refreshrate + withDynamicRange:0 /*dynamicRange*/]; + return true; +} + +bool CWinSystemTVOS::GetScreenResolution(int* w, int* h, double* fps, int screenIdx) +{ + *w = [g_xbmcController.displayManager getScreenSize].width; + *h = [g_xbmcController.displayManager getScreenSize].height; + *fps = static_cast<double>([g_xbmcController.displayManager getDisplayRate]); + + CLog::Log(LOGDEBUG, "Current resolution Screen: {} with {} x {} @ {}", screenIdx, *w, *h, *fps); + return true; +} + +void CWinSystemTVOS::UpdateResolutions() +{ + // Add display resolution + int w, h; + double fps; + CWinSystemBase::UpdateResolutions(); + + int screenIdx = GetDisplayIndexFromSettings(); + + //first screen goes into the current desktop mode + if (GetScreenResolution(&w, &h, &fps, screenIdx)) + UpdateDesktopResolution(CDisplaySettings::GetInstance().GetResolutionInfo(RES_DESKTOP), + CONST_HDMI, w, h, fps, 0); + + CDisplaySettings::GetInstance().ClearCustomResolutions(); + + //now just fill in the possible resolutions for the attached screens + //and push to the resolution info vector + FillInVideoModes(screenIdx); +} + +void CWinSystemTVOS::FillInVideoModes(int screenIdx) +{ + // Potential refresh rates + std::vector<float> supportedDispRefreshRates = {23.976f, 24.000f, 25.000f, 29.970f, + 30.000f, 50.000f, 59.940f, 60.000f}; + + UIScreen* aScreen = UIScreen.screens[screenIdx]; + UIScreenMode* mode = aScreen.currentMode; + int w = mode.size.width; + int h = mode.size.height; + + //! @Todo handle different resolutions than native (ie 720p/1080p on a 4k display) + + for (float refreshrate : supportedDispRefreshRates) + { + RESOLUTION_INFO res; + UpdateDesktopResolution(res, CONST_HDMI, w, h, refreshrate, 0); + CLog::Log(LOGINFO, "Found possible resolution for display {} with {} x {} RefreshRate:{} ", + screenIdx, w, h, refreshrate); + + CServiceBroker::GetWinSystem()->GetGfxContext().ResetOverscan(res); + CDisplaySettings::GetInstance().AddResolutionInfo(res); + } +} + +bool CWinSystemTVOS::IsExtSupported(const char* extension) const +{ + if (strncmp(extension, "EGL_", 4) != 0) + return CRenderSystemGLES::IsExtSupported(extension); + + std::string name = ' ' + std::string(extension) + ' '; + + return m_eglext.find(name) != std::string::npos; +} + + +bool CWinSystemTVOS::BeginRender() +{ + bool rtn; + + [g_xbmcController setFramebuffer]; + + rtn = CRenderSystemGLES::BeginRender(); + return rtn; +} + +bool CWinSystemTVOS::EndRender() +{ + bool rtn; + + rtn = CRenderSystemGLES::EndRender(); + return rtn; +} + +void CWinSystemTVOS::Register(IDispResource* resource) +{ + std::unique_lock<CCriticalSection> lock(m_resourceSection); + m_resources.push_back(resource); +} + +void CWinSystemTVOS::Unregister(IDispResource* resource) +{ + std::unique_lock<CCriticalSection> lock(m_resourceSection); + std::vector<IDispResource*>::iterator i = find(m_resources.begin(), m_resources.end(), resource); + if (i != m_resources.end()) + m_resources.erase(i); +} + +void CWinSystemTVOS::OnAppFocusChange(bool focus) +{ + std::unique_lock<CCriticalSection> lock(m_resourceSection); + m_bIsBackgrounded = !focus; + CLog::Log(LOGDEBUG, "CWinSystemTVOS::OnAppFocusChange: {}", focus ? 1 : 0); + for (auto dispResource : m_resources) + dispResource->OnAppFocusChange(focus); +} + +//-------------------------------------------------------------- +//-------------------DisplayLink stuff +@implementation TVOSDisplayLinkCallback +@synthesize videoSyncImpl; +//-------------------------------------------------------------- +- (void)runDisplayLink +{ + @autoreleasepool + { + if (videoSyncImpl != nullptr) + videoSyncImpl->TVosVblankHandler(); + } +} +@end + +bool CWinSystemTVOS::InitDisplayLink(CVideoSyncTVos* syncImpl) +{ + unsigned int currentScreenIdx = GetDisplayIndexFromSettings(); + UIScreen* currentScreen = UIScreen.screens[currentScreenIdx]; + m_pDisplayLink->callbackClass.videoSyncImpl = syncImpl; + m_pDisplayLink->impl = [currentScreen displayLinkWithTarget:m_pDisplayLink->callbackClass + selector:@selector(runDisplayLink)]; + + [m_pDisplayLink->impl addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes]; + return m_pDisplayLink->impl != nil; +} + +void CWinSystemTVOS::DeinitDisplayLink(void) +{ + if (m_pDisplayLink->impl) + { + [m_pDisplayLink->impl invalidate]; + m_pDisplayLink->impl = nil; + [m_pDisplayLink->callbackClass SetVideoSyncImpl:nil]; + } +} +//------------DisplayLink stuff end +//-------------------------------------------------------------- + +void CWinSystemTVOS::PresentRenderImpl(bool rendered) +{ + //glFlush; + if (rendered) + [g_xbmcController presentFramebuffer]; +} + +bool CWinSystemTVOS::HasCursor() +{ + return false; +} + +void CWinSystemTVOS::NotifyAppActiveChange(bool bActivated) +{ + if (bActivated && m_bWasFullScreenBeforeMinimize && + !CServiceBroker::GetWinSystem()->GetGfxContext().IsFullScreenRoot()) + CServiceBroker::GetAppMessenger()->PostMsg(TMSG_TOGGLEFULLSCREEN); +} + +bool CWinSystemTVOS::Minimize() +{ + m_bWasFullScreenBeforeMinimize = + CServiceBroker::GetWinSystem()->GetGfxContext().IsFullScreenRoot(); + if (m_bWasFullScreenBeforeMinimize) + CServiceBroker::GetAppMessenger()->PostMsg(TMSG_TOGGLEFULLSCREEN); + + return true; +} + +bool CWinSystemTVOS::Restore() +{ + return false; +} + +bool CWinSystemTVOS::Hide() +{ + return true; +} + +bool CWinSystemTVOS::Show(bool raise) +{ + return true; +} + +CVEAGLContext CWinSystemTVOS::GetEAGLContextObj() +{ + return [g_xbmcController getEAGLContextObj]; +} + +std::vector<std::string> CWinSystemTVOS::GetConnectedOutputs() +{ + std::vector<std::string> outputs; + outputs.emplace_back("Default"); + outputs.emplace_back(CONST_HDMI); + + return outputs; +} + +bool CWinSystemTVOS::MessagePump() +{ + return m_winEvents->MessagePump(); +} |