summaryrefslogtreecommitdiffstats
path: root/xbmc/windowing/tvos
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 18:07:22 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 18:07:22 +0000
commitc04dcc2e7d834218ef2d4194331e383402495ae1 (patch)
tree7333e38d10d75386e60f336b80c2443c1166031d /xbmc/windowing/tvos
parentInitial commit. (diff)
downloadkodi-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.txt10
-rw-r--r--xbmc/windowing/tvos/OSScreenSaverTVOS.h19
-rw-r--r--xbmc/windowing/tvos/OSScreenSaverTVOS.mm21
-rw-r--r--xbmc/windowing/tvos/VideoSyncTVos.cpp93
-rw-r--r--xbmc/windowing/tvos/VideoSyncTVos.h44
-rw-r--r--xbmc/windowing/tvos/WinEventsTVOS.h35
-rw-r--r--xbmc/windowing/tvos/WinEventsTVOS.mm76
-rw-r--r--xbmc/windowing/tvos/WinSystemTVOS.h107
-rw-r--r--xbmc/windowing/tvos/WinSystemTVOS.mm453
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();
+}