summaryrefslogtreecommitdiffstats
path: root/xbmc/cores/RetroPlayer/guibridge
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/cores/RetroPlayer/guibridge
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/cores/RetroPlayer/guibridge')
-rw-r--r--xbmc/cores/RetroPlayer/guibridge/CMakeLists.txt24
-rw-r--r--xbmc/cores/RetroPlayer/guibridge/GUIGameMessenger.cpp50
-rw-r--r--xbmc/cores/RetroPlayer/guibridge/GUIGameMessenger.h42
-rw-r--r--xbmc/cores/RetroPlayer/guibridge/GUIGameRenderManager.cpp310
-rw-r--r--xbmc/cores/RetroPlayer/guibridge/GUIGameRenderManager.h185
-rw-r--r--xbmc/cores/RetroPlayer/guibridge/GUIGameSettings.cpp70
-rw-r--r--xbmc/cores/RetroPlayer/guibridge/GUIGameSettings.h54
-rw-r--r--xbmc/cores/RetroPlayer/guibridge/GUIGameSettingsHandle.cpp59
-rw-r--r--xbmc/cores/RetroPlayer/guibridge/GUIGameSettingsHandle.h91
-rw-r--r--xbmc/cores/RetroPlayer/guibridge/GUIGameVideoHandle.cpp39
-rw-r--r--xbmc/cores/RetroPlayer/guibridge/GUIGameVideoHandle.h34
-rw-r--r--xbmc/cores/RetroPlayer/guibridge/GUIRenderHandle.cpp62
-rw-r--r--xbmc/cores/RetroPlayer/guibridge/GUIRenderHandle.h76
-rw-r--r--xbmc/cores/RetroPlayer/guibridge/GUIRenderTarget.cpp66
-rw-r--r--xbmc/cores/RetroPlayer/guibridge/GUIRenderTarget.h94
-rw-r--r--xbmc/cores/RetroPlayer/guibridge/GUIRenderTargetFactory.cpp29
-rw-r--r--xbmc/cores/RetroPlayer/guibridge/GUIRenderTargetFactory.h40
-rw-r--r--xbmc/cores/RetroPlayer/guibridge/IGUIRenderSettings.h64
-rw-r--r--xbmc/cores/RetroPlayer/guibridge/IGameCallback.h78
-rw-r--r--xbmc/cores/RetroPlayer/guibridge/IRenderCallback.h26
20 files changed, 1493 insertions, 0 deletions
diff --git a/xbmc/cores/RetroPlayer/guibridge/CMakeLists.txt b/xbmc/cores/RetroPlayer/guibridge/CMakeLists.txt
new file mode 100644
index 0000000..5ba7579
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/guibridge/CMakeLists.txt
@@ -0,0 +1,24 @@
+set(SOURCES GUIGameMessenger.cpp
+ GUIGameRenderManager.cpp
+ GUIGameSettings.cpp
+ GUIGameSettingsHandle.cpp
+ GUIGameVideoHandle.cpp
+ GUIRenderHandle.cpp
+ GUIRenderTarget.cpp
+ GUIRenderTargetFactory.cpp
+)
+
+set(HEADERS GUIGameMessenger.h
+ GUIGameRenderManager.h
+ GUIGameSettings.h
+ GUIGameSettingsHandle.h
+ GUIGameVideoHandle.h
+ GUIRenderHandle.h
+ GUIRenderTarget.h
+ GUIRenderTargetFactory.h
+ IGameCallback.h
+ IGUIRenderSettings.h
+ IRenderCallback.h
+)
+
+core_add_library(retroplayer_guibridge)
diff --git a/xbmc/cores/RetroPlayer/guibridge/GUIGameMessenger.cpp b/xbmc/cores/RetroPlayer/guibridge/GUIGameMessenger.cpp
new file mode 100644
index 0000000..ff7efa3
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/guibridge/GUIGameMessenger.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 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 "GUIGameMessenger.h"
+
+#include "FileItem.h"
+#include "cores/RetroPlayer/process/RPProcessInfo.h"
+#include "cores/RetroPlayer/rendering/RenderContext.h"
+#include "cores/RetroPlayer/savestates/SavestateDatabase.h"
+#include "guilib/GUIComponent.h"
+#include "guilib/GUIMessage.h"
+#include "guilib/GUIWindowManager.h"
+#include "guilib/WindowIDs.h"
+
+using namespace KODI;
+using namespace RETRO;
+
+CGUIGameMessenger::CGUIGameMessenger(CRPProcessInfo& processInfo)
+ : m_guiComponent(processInfo.GetRenderContext().GUI())
+{
+}
+
+void CGUIGameMessenger::RefreshSavestates(const std::string& savestatePath /* = "" */,
+ ISavestate* savestate /* = nullptr */)
+{
+ if (m_guiComponent != nullptr)
+ {
+ CGUIMessage message(GUI_MSG_REFRESH_THUMBS, 0, WINDOW_DIALOG_IN_GAME_SAVES);
+
+ // Add path, if given
+ if (!savestatePath.empty())
+ message.SetStringParam(savestatePath);
+
+ // Add savestate info, if given
+ if (savestate != nullptr)
+ {
+ CFileItemPtr item = std::make_shared<CFileItem>();
+ CSavestateDatabase::GetSavestateItem(*savestate, savestatePath, *item);
+ message.SetItem(std::static_pointer_cast<CGUIListItem>(item));
+ }
+
+ // Notify the in-game savestate dialog
+ m_guiComponent->GetWindowManager().SendThreadMessage(message, WINDOW_DIALOG_IN_GAME_SAVES);
+ }
+}
diff --git a/xbmc/cores/RetroPlayer/guibridge/GUIGameMessenger.h b/xbmc/cores/RetroPlayer/guibridge/GUIGameMessenger.h
new file mode 100644
index 0000000..7384f9a
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/guibridge/GUIGameMessenger.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 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 <string>
+
+class CGUIComponent;
+
+namespace KODI
+{
+namespace RETRO
+{
+class CRPProcessInfo;
+class ISavestate;
+
+/*!
+ * \brief Class to send messages to the GUI, if a GUI is present
+ */
+class CGUIGameMessenger
+{
+public:
+ CGUIGameMessenger(CRPProcessInfo& processInfo);
+
+ /*!
+ * \brief Refresh savestate GUI elements being displayed
+ *
+ * \param savestatePath The savestate to refresh, or empty to refresh all savestates
+ * \param savestate Optional savestate info to send with the message
+ */
+ void RefreshSavestates(const std::string& savestatePath = "", ISavestate* savestate = nullptr);
+
+private:
+ CGUIComponent* const m_guiComponent;
+};
+} // namespace RETRO
+} // namespace KODI
diff --git a/xbmc/cores/RetroPlayer/guibridge/GUIGameRenderManager.cpp b/xbmc/cores/RetroPlayer/guibridge/GUIGameRenderManager.cpp
new file mode 100644
index 0000000..4071d10
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/guibridge/GUIGameRenderManager.cpp
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2017-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 "GUIGameRenderManager.h"
+
+#include "GUIGameSettingsHandle.h"
+#include "GUIGameVideoHandle.h"
+#include "GUIRenderHandle.h"
+#include "GUIRenderTarget.h"
+#include "GUIRenderTargetFactory.h"
+#include "IGameCallback.h"
+#include "IRenderCallback.h"
+
+#include <mutex>
+
+using namespace KODI;
+using namespace RETRO;
+
+CGUIGameRenderManager::~CGUIGameRenderManager() = default;
+
+void CGUIGameRenderManager::RegisterPlayer(CGUIRenderTargetFactory* factory,
+ IRenderCallback* callback,
+ IGameCallback* gameCallback)
+{
+ // Set factory
+ {
+ std::unique_lock<CCriticalSection> lock(m_targetMutex);
+ m_factory = factory;
+ UpdateRenderTargets();
+ }
+
+ // Set callback
+ {
+ std::unique_lock<CCriticalSection> lock(m_callbackMutex);
+ m_callback = callback;
+ }
+
+ // Set game callback
+ {
+ std::unique_lock<CCriticalSection> lock(m_gameCallbackMutex);
+ m_gameCallback = gameCallback;
+ }
+}
+
+void CGUIGameRenderManager::UnregisterPlayer()
+{
+ // Reset game callback
+ {
+ std::unique_lock<CCriticalSection> lock(m_gameCallbackMutex);
+ m_gameCallback = nullptr;
+ }
+
+ // Reset callback
+ {
+ std::unique_lock<CCriticalSection> lock(m_callbackMutex);
+ m_callback = nullptr;
+ }
+
+ // Reset factory
+ {
+ std::unique_lock<CCriticalSection> lock(m_targetMutex);
+ m_factory = nullptr;
+ UpdateRenderTargets();
+ }
+}
+
+std::shared_ptr<CGUIRenderHandle> CGUIGameRenderManager::RegisterControl(CGUIGameControl& control)
+{
+ std::unique_lock<CCriticalSection> lock(m_targetMutex);
+
+ // Create handle for game control
+ std::shared_ptr<CGUIRenderHandle> renderHandle(new CGUIRenderControlHandle(*this, control));
+
+ std::shared_ptr<CGUIRenderTarget> renderTarget;
+ if (m_factory != nullptr)
+ renderTarget.reset(m_factory->CreateRenderControl(control));
+
+ m_renderTargets.insert(std::make_pair(renderHandle.get(), std::move(renderTarget)));
+
+ return renderHandle;
+}
+
+std::shared_ptr<CGUIRenderHandle> CGUIGameRenderManager::RegisterWindow(
+ CGameWindowFullScreen& window)
+{
+ std::unique_lock<CCriticalSection> lock(m_targetMutex);
+
+ // Create handle for game window
+ std::shared_ptr<CGUIRenderHandle> renderHandle(new CGUIRenderFullScreenHandle(*this, window));
+
+ std::shared_ptr<CGUIRenderTarget> renderTarget;
+ if (m_factory != nullptr)
+ renderTarget.reset(m_factory->CreateRenderFullScreen(window));
+
+ m_renderTargets.insert(std::make_pair(renderHandle.get(), std::move(renderTarget)));
+
+ return renderHandle;
+}
+
+std::shared_ptr<CGUIGameVideoHandle> CGUIGameRenderManager::RegisterDialog(
+ GAME::CDialogGameVideoSelect& dialog)
+{
+ return std::make_shared<CGUIGameVideoHandle>(*this);
+}
+
+std::shared_ptr<CGUIGameSettingsHandle> CGUIGameRenderManager::RegisterGameSettingsDialog()
+{
+ return std::make_shared<CGUIGameSettingsHandle>(*this);
+}
+
+void CGUIGameRenderManager::UnregisterHandle(CGUIRenderHandle* handle)
+{
+ std::unique_lock<CCriticalSection> lock(m_targetMutex);
+
+ m_renderTargets.erase(handle);
+}
+
+void CGUIGameRenderManager::Render(CGUIRenderHandle* handle)
+{
+ std::unique_lock<CCriticalSection> lock(m_targetMutex);
+
+ auto it = m_renderTargets.find(handle);
+ if (it != m_renderTargets.end())
+ {
+ const std::shared_ptr<CGUIRenderTarget>& renderTarget = it->second;
+ if (renderTarget)
+ renderTarget->Render();
+ }
+}
+
+void CGUIGameRenderManager::RenderEx(CGUIRenderHandle* handle)
+{
+ std::unique_lock<CCriticalSection> lock(m_targetMutex);
+
+ auto it = m_renderTargets.find(handle);
+ if (it != m_renderTargets.end())
+ {
+ const std::shared_ptr<CGUIRenderTarget>& renderTarget = it->second;
+ if (renderTarget)
+ renderTarget->RenderEx();
+ }
+}
+
+void CGUIGameRenderManager::ClearBackground(CGUIRenderHandle* handle)
+{
+ std::unique_lock<CCriticalSection> lock(m_targetMutex);
+
+ auto it = m_renderTargets.find(handle);
+ if (it != m_renderTargets.end())
+ {
+ const std::shared_ptr<CGUIRenderTarget>& renderTarget = it->second;
+ if (renderTarget)
+ renderTarget->ClearBackground();
+ }
+}
+
+bool CGUIGameRenderManager::IsDirty(CGUIRenderHandle* handle)
+{
+ std::unique_lock<CCriticalSection> lock(m_targetMutex);
+
+ auto it = m_renderTargets.find(handle);
+ if (it != m_renderTargets.end())
+ {
+ const std::shared_ptr<CGUIRenderTarget>& renderTarget = it->second;
+ if (renderTarget)
+ return renderTarget->IsDirty();
+ }
+
+ return false;
+}
+
+bool CGUIGameRenderManager::IsPlayingGame()
+{
+ std::unique_lock<CCriticalSection> lock(m_callbackMutex);
+
+ return m_callback != nullptr;
+}
+
+bool CGUIGameRenderManager::SupportsRenderFeature(RENDERFEATURE feature)
+{
+ std::unique_lock<CCriticalSection> lock(m_callbackMutex);
+
+ if (m_callback != nullptr)
+ return m_callback->SupportsRenderFeature(feature);
+
+ return false;
+}
+
+bool CGUIGameRenderManager::SupportsScalingMethod(SCALINGMETHOD method)
+{
+ std::unique_lock<CCriticalSection> lock(m_callbackMutex);
+
+ if (m_callback != nullptr)
+ return m_callback->SupportsScalingMethod(method);
+
+ return false;
+}
+
+std::string CGUIGameRenderManager::GameClientID()
+{
+ std::unique_lock<CCriticalSection> lock(m_callbackMutex);
+
+ if (m_gameCallback != nullptr)
+ return m_gameCallback->GameClientID();
+
+ return "";
+}
+
+std::string CGUIGameRenderManager::GetPlayingGame()
+{
+ std::unique_lock<CCriticalSection> lock(m_callbackMutex);
+
+ if (m_gameCallback != nullptr)
+ return m_gameCallback->GetPlayingGame();
+
+ return "";
+}
+
+std::string CGUIGameRenderManager::CreateSavestate(bool autosave)
+{
+ std::unique_lock<CCriticalSection> lock(m_callbackMutex);
+
+ if (m_gameCallback != nullptr)
+ return m_gameCallback->CreateSavestate(autosave);
+
+ return "";
+}
+
+bool CGUIGameRenderManager::UpdateSavestate(const std::string& savestatePath)
+{
+ std::unique_lock<CCriticalSection> lock(m_callbackMutex);
+
+ if (m_gameCallback != nullptr)
+ return m_gameCallback->UpdateSavestate(savestatePath);
+
+ return false;
+}
+
+bool CGUIGameRenderManager::LoadSavestate(const std::string& savestatePath)
+{
+ std::unique_lock<CCriticalSection> lock(m_callbackMutex);
+
+ if (m_gameCallback != nullptr)
+ return m_gameCallback->LoadSavestate(savestatePath);
+
+ return false;
+}
+
+void CGUIGameRenderManager::FreeSavestateResources(const std::string& savestatePath)
+{
+ std::unique_lock<CCriticalSection> lock(m_callbackMutex);
+
+ if (m_gameCallback != nullptr)
+ m_gameCallback->FreeSavestateResources(savestatePath);
+}
+
+void CGUIGameRenderManager::CloseOSD()
+{
+ std::unique_lock<CCriticalSection> lock(m_callbackMutex);
+
+ if (m_gameCallback != nullptr)
+ m_gameCallback->CloseOSDCallback();
+}
+
+void CGUIGameRenderManager::UpdateRenderTargets()
+{
+ if (m_factory != nullptr)
+ {
+ for (auto& it : m_renderTargets)
+ {
+ CGUIRenderHandle* handle = it.first;
+ std::shared_ptr<CGUIRenderTarget>& renderTarget = it.second;
+
+ if (!renderTarget)
+ renderTarget.reset(CreateRenderTarget(handle));
+ }
+ }
+ else
+ {
+ for (auto& it : m_renderTargets)
+ it.second.reset();
+ }
+}
+
+CGUIRenderTarget* CGUIGameRenderManager::CreateRenderTarget(CGUIRenderHandle* handle)
+{
+ switch (handle->Type())
+ {
+ case RENDER_HANDLE::CONTROL:
+ {
+ CGUIRenderControlHandle* controlHandle = static_cast<CGUIRenderControlHandle*>(handle);
+ return m_factory->CreateRenderControl(controlHandle->GetControl());
+ }
+ case RENDER_HANDLE::WINDOW:
+ {
+ CGUIRenderFullScreenHandle* fullScreenHandle =
+ static_cast<CGUIRenderFullScreenHandle*>(handle);
+ return m_factory->CreateRenderFullScreen(fullScreenHandle->GetWindow());
+ }
+ default:
+ break;
+ }
+
+ return nullptr;
+}
diff --git a/xbmc/cores/RetroPlayer/guibridge/GUIGameRenderManager.h b/xbmc/cores/RetroPlayer/guibridge/GUIGameRenderManager.h
new file mode 100644
index 0000000..0a974b7
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/guibridge/GUIGameRenderManager.h
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2017-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 "cores/GameSettings.h"
+#include "threads/CriticalSection.h"
+
+#include <map>
+#include <memory>
+
+namespace KODI
+{
+namespace GAME
+{
+class CDialogGameAdvancedSettings;
+class CDialogGameVideoSelect;
+} // namespace GAME
+
+namespace RETRO
+{
+class CGameWindowFullScreen;
+class CGUIGameControl;
+class CGUIGameSettingsHandle;
+class CGUIGameVideoHandle;
+class CGUIRenderTargetFactory;
+class CGUIRenderHandle;
+class CGUIRenderTarget;
+class IGameCallback;
+class IRenderCallback;
+class IPlayback;
+
+/*!
+ * \brief Class to safely route commands between the GUI and RetroPlayer
+ *
+ * This class is brought up before the GUI and player core factory. It
+ * provides the GUI with safe access to a registered player.
+ *
+ * Access to the player is done through handles. When a handle is no
+ * longer needed, it should be destroyed.
+ *
+ * Three kinds of handles are provided:
+ *
+ * - CGUIRenderHandle
+ * Allows the holder to invoke render events
+ *
+ * - CGUIGameVideoHandle
+ * Allows the holder to query video properties, such as the filter
+ * or view mode.
+ *
+ * - CGUIGameSettingsHandle
+ * Allows the holder to query game properties, such as the ID of the
+ * game client or the game's filename.
+ *
+ * Each manager fulfills the following design requirements:
+ *
+ * 1. No assumption of player lifetimes
+ *
+ * 2. No assumption of GUI element lifetimes, as long as handles are
+ * destroyed before this class is destructed
+ *
+ * 3. No limit on the number of handles
+ */
+class CGUIGameRenderManager
+{
+ // Classes that call into the protected interface
+ friend class CGUIGameSettingsHandle;
+ friend class CGUIGameVideoHandle;
+ friend class CGUIRenderHandle;
+
+public:
+ CGUIGameRenderManager() = default;
+ ~CGUIGameRenderManager();
+
+ /*!
+ * \brief Register a RetroPlayer instance
+ *
+ * \param factory The interface for creating render targets exposed to the GUI
+ * \param callback The interface for querying video properties
+ * \param gameCallback The interface for querying game properties
+ */
+ void RegisterPlayer(CGUIRenderTargetFactory* factory,
+ IRenderCallback* callback,
+ IGameCallback* gameCallback);
+
+ /*!
+ * \brief Unregister a RetroPlayer instance
+ */
+ void UnregisterPlayer();
+
+ /*!
+ * \brief Register a GUI game control ("gamewindow" skin control)
+ *
+ * \param control The game control
+ *
+ * \return A handle to invoke render events
+ */
+ std::shared_ptr<CGUIRenderHandle> RegisterControl(CGUIGameControl& control);
+
+ /*!
+ * \brief Register a fullscreen game window ("FullscreenGame" window)
+ *
+ * \param window The game window
+ *
+ * \return A handle to invoke render events
+ */
+ std::shared_ptr<CGUIRenderHandle> RegisterWindow(CGameWindowFullScreen& window);
+
+ /*!
+ * \brief Register a video select dialog (for selecting video filters,
+ * view modes, etc.)
+ *
+ * \param dialog The video select dialog
+ *
+ * \return A handle to query game and video properties
+ */
+ std::shared_ptr<CGUIGameVideoHandle> RegisterDialog(GAME::CDialogGameVideoSelect& dialog);
+
+ /*!
+ * \brief Register a game settings dialog
+ *
+ * \return A handle to query game properties
+ */
+ std::shared_ptr<CGUIGameSettingsHandle> RegisterGameSettingsDialog();
+
+protected:
+ // Functions exposed to friend class CGUIRenderHandle
+ void UnregisterHandle(CGUIRenderHandle* handle);
+ void Render(CGUIRenderHandle* handle);
+ void RenderEx(CGUIRenderHandle* handle);
+ void ClearBackground(CGUIRenderHandle* handle);
+ bool IsDirty(CGUIRenderHandle* handle);
+
+ // Functions exposed to friend class CGUIGameVideoHandle
+ void UnregisterHandle(CGUIGameVideoHandle* handle) {}
+ bool IsPlayingGame();
+ bool SupportsRenderFeature(RENDERFEATURE feature);
+ bool SupportsScalingMethod(SCALINGMETHOD method);
+
+ // Functions exposed to CGUIGameSettingsHandle
+ void UnregisterHandle(CGUIGameSettingsHandle* handle) {}
+ std::string GameClientID();
+ std::string GetPlayingGame();
+ std::string CreateSavestate(bool autosave);
+ bool UpdateSavestate(const std::string& savestatePath);
+ bool LoadSavestate(const std::string& savestatePath);
+ void FreeSavestateResources(const std::string& savestatePath);
+ void CloseOSD();
+
+private:
+ /*!
+ * \brief Helper function to create or destroy render targets when a
+ * factory is registered/unregistered
+ */
+ void UpdateRenderTargets();
+
+ /*!
+ * \brief Helper function to create a render target
+ *
+ * \param handle The handle given to the registered GUI element
+ *
+ * \return A target to receive rendering commands
+ */
+ CGUIRenderTarget* CreateRenderTarget(CGUIRenderHandle* handle);
+
+ // Render events
+ CGUIRenderTargetFactory* m_factory = nullptr;
+ std::map<CGUIRenderHandle*, std::shared_ptr<CGUIRenderTarget>> m_renderTargets;
+ CCriticalSection m_targetMutex;
+
+ // Video properties
+ IRenderCallback* m_callback = nullptr;
+ CCriticalSection m_callbackMutex;
+
+ // Game properties
+ IGameCallback* m_gameCallback = nullptr;
+ CCriticalSection m_gameCallbackMutex;
+};
+} // namespace RETRO
+} // namespace KODI
diff --git a/xbmc/cores/RetroPlayer/guibridge/GUIGameSettings.cpp b/xbmc/cores/RetroPlayer/guibridge/GUIGameSettings.cpp
new file mode 100644
index 0000000..4b030d8
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/guibridge/GUIGameSettings.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2017-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 "GUIGameSettings.h"
+
+#include "cores/RetroPlayer/process/RPProcessInfo.h"
+#include "cores/RetroPlayer/rendering/RenderContext.h"
+#include "settings/GameSettings.h"
+
+#include <mutex>
+
+using namespace KODI;
+using namespace RETRO;
+
+CGUIGameSettings::CGUIGameSettings(CRPProcessInfo& processInfo)
+ : m_processInfo(processInfo), m_guiSettings(processInfo.GetRenderContext().GetGameSettings())
+{
+ // Reset game settings
+ m_guiSettings = m_processInfo.GetRenderContext().GetDefaultGameSettings();
+
+ UpdateSettings();
+
+ m_guiSettings.RegisterObserver(this);
+}
+
+CGUIGameSettings::~CGUIGameSettings()
+{
+ m_guiSettings.UnregisterObserver(this);
+}
+
+CRenderSettings CGUIGameSettings::GetSettings() const
+{
+ std::unique_lock<CCriticalSection> lock(m_mutex);
+
+ return m_renderSettings;
+}
+
+void CGUIGameSettings::Notify(const Observable& obs, const ObservableMessage msg)
+{
+ switch (msg)
+ {
+ case ObservableMessageSettingsChanged:
+ {
+ UpdateSettings();
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+void CGUIGameSettings::UpdateSettings()
+{
+ std::unique_lock<CCriticalSection> lock(m_mutex);
+
+ // Get settings from GUI
+ std::string videoFilter = m_guiSettings.VideoFilter();
+ STRETCHMODE stretchMode = m_guiSettings.StretchMode();
+ unsigned int rotationDegCCW = m_guiSettings.RotationDegCCW();
+
+ // Save settings for renderer
+ m_renderSettings.VideoSettings().SetVideoFilter(videoFilter);
+ m_renderSettings.VideoSettings().SetRenderStretchMode(stretchMode);
+ m_renderSettings.VideoSettings().SetRenderRotation(rotationDegCCW);
+}
diff --git a/xbmc/cores/RetroPlayer/guibridge/GUIGameSettings.h b/xbmc/cores/RetroPlayer/guibridge/GUIGameSettings.h
new file mode 100644
index 0000000..6400b8d
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/guibridge/GUIGameSettings.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017-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 "IGUIRenderSettings.h"
+#include "cores/RetroPlayer/rendering/RenderSettings.h"
+#include "threads/CriticalSection.h"
+#include "utils/Observer.h"
+
+#include <memory>
+
+class CGameSettings;
+
+namespace KODI
+{
+namespace RETRO
+{
+class CRPProcessInfo;
+
+class CGUIGameSettings : public IGUIRenderSettings, public Observer
+{
+public:
+ CGUIGameSettings(CRPProcessInfo& processInfo);
+ ~CGUIGameSettings() override;
+
+ // implementation of IGUIRenderSettings
+ CRenderSettings GetSettings() const override;
+
+ // implementation of Observer
+ void Notify(const Observable& obs, const ObservableMessage msg) override;
+
+private:
+ void UpdateSettings();
+
+ // Construction parameters
+ CRPProcessInfo& m_processInfo;
+
+ // GUI parameters
+ CGameSettings& m_guiSettings;
+
+ // Render parameters
+ CRenderSettings m_renderSettings;
+
+ // Synchronization parameters
+ mutable CCriticalSection m_mutex;
+};
+} // namespace RETRO
+} // namespace KODI
diff --git a/xbmc/cores/RetroPlayer/guibridge/GUIGameSettingsHandle.cpp b/xbmc/cores/RetroPlayer/guibridge/GUIGameSettingsHandle.cpp
new file mode 100644
index 0000000..9edba41
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/guibridge/GUIGameSettingsHandle.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 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 "GUIGameSettingsHandle.h"
+
+#include "GUIGameRenderManager.h"
+
+using namespace KODI;
+using namespace RETRO;
+
+CGUIGameSettingsHandle::CGUIGameSettingsHandle(CGUIGameRenderManager& renderManager)
+ : m_renderManager(renderManager)
+{
+}
+
+CGUIGameSettingsHandle::~CGUIGameSettingsHandle()
+{
+ m_renderManager.UnregisterHandle(this);
+}
+
+std::string CGUIGameSettingsHandle::GameClientID()
+{
+ return m_renderManager.GameClientID();
+}
+
+std::string CGUIGameSettingsHandle::GetPlayingGame()
+{
+ return m_renderManager.GetPlayingGame();
+}
+
+std::string CGUIGameSettingsHandle::CreateSavestate(bool autosave)
+{
+ return m_renderManager.CreateSavestate(autosave);
+}
+
+bool CGUIGameSettingsHandle::UpdateSavestate(const std::string& savestatePath)
+{
+ return m_renderManager.UpdateSavestate(savestatePath);
+}
+
+bool CGUIGameSettingsHandle::LoadSavestate(const std::string& savestatePath)
+{
+ return m_renderManager.LoadSavestate(savestatePath);
+}
+
+void CGUIGameSettingsHandle::FreeSavestateResources(const std::string& savestatePath)
+{
+ return m_renderManager.FreeSavestateResources(savestatePath);
+}
+
+void CGUIGameSettingsHandle::CloseOSD()
+{
+ m_renderManager.CloseOSD();
+}
diff --git a/xbmc/cores/RetroPlayer/guibridge/GUIGameSettingsHandle.h b/xbmc/cores/RetroPlayer/guibridge/GUIGameSettingsHandle.h
new file mode 100644
index 0000000..beddb90
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/guibridge/GUIGameSettingsHandle.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 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 <string>
+
+namespace KODI
+{
+namespace RETRO
+{
+class CGUIGameRenderManager;
+class IPlayback;
+
+class CGUIGameSettingsHandle
+{
+public:
+ CGUIGameSettingsHandle(CGUIGameRenderManager& renderManager);
+ virtual ~CGUIGameSettingsHandle();
+
+ /*!
+ * \brief Get the ID of the active game client
+ *
+ * \return The ID of the active game client, or empty string if a game is
+ * not playing
+ */
+ std::string GameClientID();
+
+ /*!
+ * \brief Get the full path of the game being played
+ *
+ * \return The game's path, or empty string if a game is not playing
+ */
+ std::string GetPlayingGame();
+
+ /*!
+ * \brief Create a savestate of the current game being played
+ *
+ * \param autosave True if the save was invoked automatically, or false if
+ * the save was invoked by a player
+ *
+ * \return The path to the created savestate file, or empty string on
+ * failure or if a game is not playing
+ */
+ std::string CreateSavestate(bool autosave);
+
+ /*!
+ * \brief Update a savestate for the current game being played
+ *
+ * \param savestatePath The path to the created savestate file returned by
+ * CreateSavestate()
+ *
+ * \return True if the savestate was updated successfully, false otherwise
+ */
+ bool UpdateSavestate(const std::string& savestatePath);
+
+ /*!
+ * \brief Load a savestate for the current game being played
+ *
+ * \param savestatePath The path to the created savestate file returned by
+ * CreateSavestate()
+ *
+ * \return True if the savestate was loaded successfully, false otherwise
+ */
+ bool LoadSavestate(const std::string& savestatePath);
+
+ /*!
+ * \brief Clear the video frame stored for the given statestate
+ *
+ * Useful to reclaim memory if a savestate has been deleted.
+ *
+ * \param savestatePath The path to the savestate file
+ */
+ void FreeSavestateResources(const std::string& savestatePath);
+
+ /*!
+ * \brief Close the in-game OSD
+ */
+ void CloseOSD();
+
+private:
+ // Construction parameters
+ CGUIGameRenderManager& m_renderManager;
+};
+} // namespace RETRO
+} // namespace KODI
diff --git a/xbmc/cores/RetroPlayer/guibridge/GUIGameVideoHandle.cpp b/xbmc/cores/RetroPlayer/guibridge/GUIGameVideoHandle.cpp
new file mode 100644
index 0000000..521cf4b
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/guibridge/GUIGameVideoHandle.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017-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 "GUIGameVideoHandle.h"
+
+#include "GUIGameRenderManager.h"
+
+using namespace KODI;
+using namespace RETRO;
+
+CGUIGameVideoHandle::CGUIGameVideoHandle(CGUIGameRenderManager& renderManager)
+ : m_renderManager(renderManager)
+{
+}
+
+CGUIGameVideoHandle::~CGUIGameVideoHandle()
+{
+ m_renderManager.UnregisterHandle(this);
+}
+
+bool CGUIGameVideoHandle::IsPlayingGame()
+{
+ return m_renderManager.IsPlayingGame();
+}
+
+bool CGUIGameVideoHandle::SupportsRenderFeature(RENDERFEATURE feature)
+{
+ return m_renderManager.SupportsRenderFeature(feature);
+}
+
+bool CGUIGameVideoHandle::SupportsScalingMethod(SCALINGMETHOD method)
+{
+ return m_renderManager.SupportsScalingMethod(method);
+}
diff --git a/xbmc/cores/RetroPlayer/guibridge/GUIGameVideoHandle.h b/xbmc/cores/RetroPlayer/guibridge/GUIGameVideoHandle.h
new file mode 100644
index 0000000..4d26fe4
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/guibridge/GUIGameVideoHandle.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2017-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 "cores/GameSettings.h"
+
+namespace KODI
+{
+namespace RETRO
+{
+class CGUIGameRenderManager;
+
+class CGUIGameVideoHandle
+{
+public:
+ CGUIGameVideoHandle(CGUIGameRenderManager& renderManager);
+ virtual ~CGUIGameVideoHandle();
+
+ bool IsPlayingGame();
+ bool SupportsRenderFeature(RENDERFEATURE feature);
+ bool SupportsScalingMethod(SCALINGMETHOD method);
+
+private:
+ // Construction parameters
+ CGUIGameRenderManager& m_renderManager;
+};
+} // namespace RETRO
+} // namespace KODI
diff --git a/xbmc/cores/RetroPlayer/guibridge/GUIRenderHandle.cpp b/xbmc/cores/RetroPlayer/guibridge/GUIRenderHandle.cpp
new file mode 100644
index 0000000..a4b6403
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/guibridge/GUIRenderHandle.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017-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 "GUIRenderHandle.h"
+
+#include "GUIGameRenderManager.h"
+
+using namespace KODI;
+using namespace RETRO;
+
+// --- CGUIRenderHandle --------------------------------------------------------
+
+CGUIRenderHandle::CGUIRenderHandle(CGUIGameRenderManager& renderManager, RENDER_HANDLE type)
+ : m_renderManager(renderManager), m_type(type)
+{
+}
+
+CGUIRenderHandle::~CGUIRenderHandle()
+{
+ m_renderManager.UnregisterHandle(this);
+}
+
+void CGUIRenderHandle::Render()
+{
+ m_renderManager.Render(this);
+}
+
+void CGUIRenderHandle::RenderEx()
+{
+ m_renderManager.RenderEx(this);
+}
+
+bool CGUIRenderHandle::IsDirty()
+{
+ return m_renderManager.IsDirty(this);
+}
+
+void CGUIRenderHandle::ClearBackground()
+{
+ m_renderManager.ClearBackground(this);
+}
+
+// --- CGUIRenderControlHandle -------------------------------------------------
+
+CGUIRenderControlHandle::CGUIRenderControlHandle(CGUIGameRenderManager& renderManager,
+ CGUIGameControl& control)
+ : CGUIRenderHandle(renderManager, RENDER_HANDLE::CONTROL), m_control(control)
+{
+}
+
+// --- CGUIRenderFullScreenHandle ----------------------------------------------
+
+CGUIRenderFullScreenHandle::CGUIRenderFullScreenHandle(CGUIGameRenderManager& renderManager,
+ CGameWindowFullScreen& window)
+ : CGUIRenderHandle(renderManager, RENDER_HANDLE::WINDOW), m_window(window)
+{
+}
diff --git a/xbmc/cores/RetroPlayer/guibridge/GUIRenderHandle.h b/xbmc/cores/RetroPlayer/guibridge/GUIRenderHandle.h
new file mode 100644
index 0000000..f5b8d5b
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/guibridge/GUIRenderHandle.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2017-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
+
+namespace KODI
+{
+namespace RETRO
+{
+class CGameWindowFullScreen;
+class CGUIGameControl;
+class CGUIGameRenderManager;
+
+enum class RENDER_HANDLE
+{
+ CONTROL,
+ WINDOW,
+};
+
+// --- CGUIRenderHandle ------------------------------------------------------
+
+class CGUIRenderHandle
+{
+public:
+ CGUIRenderHandle(CGUIGameRenderManager& renderManager, RENDER_HANDLE type);
+ virtual ~CGUIRenderHandle();
+
+ RENDER_HANDLE Type() const { return m_type; }
+
+ void Render();
+ void RenderEx();
+ bool IsDirty();
+ void ClearBackground();
+
+private:
+ // Construction parameters
+ CGUIGameRenderManager& m_renderManager;
+ const RENDER_HANDLE m_type;
+};
+
+// --- CGUIRenderControlHandle -----------------------------------------------
+
+class CGUIRenderControlHandle : public CGUIRenderHandle
+{
+public:
+ CGUIRenderControlHandle(CGUIGameRenderManager& renderManager, CGUIGameControl& control);
+ ~CGUIRenderControlHandle() override = default;
+
+ CGUIGameControl& GetControl() { return m_control; }
+
+private:
+ // Construction parameters
+ CGUIGameControl& m_control;
+};
+
+// --- CGUIRenderFullScreenHandle --------------------------------------------
+
+class CGUIRenderFullScreenHandle : public CGUIRenderHandle
+{
+public:
+ CGUIRenderFullScreenHandle(CGUIGameRenderManager& renderManager, CGameWindowFullScreen& window);
+ ~CGUIRenderFullScreenHandle() override = default;
+
+ CGameWindowFullScreen& GetWindow() { return m_window; }
+
+private:
+ // Construction parameters
+ CGameWindowFullScreen& m_window;
+};
+} // namespace RETRO
+} // namespace KODI
diff --git a/xbmc/cores/RetroPlayer/guibridge/GUIRenderTarget.cpp b/xbmc/cores/RetroPlayer/guibridge/GUIRenderTarget.cpp
new file mode 100644
index 0000000..15993fc
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/guibridge/GUIRenderTarget.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2017-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 "GUIRenderTarget.h"
+
+#include "cores/RetroPlayer/guicontrols/GUIGameControl.h"
+#include "cores/RetroPlayer/guiwindows/GameWindowFullScreen.h"
+#include "cores/RetroPlayer/rendering/IRenderManager.h"
+
+using namespace KODI;
+using namespace RETRO;
+
+// --- CGUIRenderTarget --------------------------------------------------------
+
+CGUIRenderTarget::CGUIRenderTarget(IRenderManager* renderManager) : m_renderManager(renderManager)
+{
+}
+
+// --- CGUIRenderControl -------------------------------------------------------
+
+CGUIRenderControl::CGUIRenderControl(IRenderManager* renderManager, CGUIGameControl& gameControl)
+ : CGUIRenderTarget(renderManager), m_gameControl(gameControl)
+{
+}
+
+void CGUIRenderControl::Render()
+{
+ m_renderManager->RenderControl(true, true, m_gameControl.GetRenderRegion(),
+ m_gameControl.GetRenderSettings());
+}
+
+void CGUIRenderControl::RenderEx()
+{
+ //! @todo
+ // m_renderManager->RenderControl(false, false, m_gameControl.GetRenderRegion(),
+ // m_gameControl.GetRenderSettings());
+}
+
+// --- CGUIRenderFullScreen ----------------------------------------------------
+
+CGUIRenderFullScreen::CGUIRenderFullScreen(IRenderManager* renderManager,
+ CGameWindowFullScreen& window)
+ : CGUIRenderTarget(renderManager), m_window(window)
+{
+}
+
+void CGUIRenderFullScreen::Render()
+{
+ m_renderManager->RenderWindow(true, m_window.GetCoordsRes());
+}
+
+void CGUIRenderFullScreen::RenderEx()
+{
+ //! @todo
+ // m_renderManager->RenderWindow(false, m_window.GetCoordsRes());
+}
+
+void CGUIRenderFullScreen::ClearBackground()
+{
+ m_renderManager->ClearBackground();
+}
diff --git a/xbmc/cores/RetroPlayer/guibridge/GUIRenderTarget.h b/xbmc/cores/RetroPlayer/guibridge/GUIRenderTarget.h
new file mode 100644
index 0000000..574a13f
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/guibridge/GUIRenderTarget.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2017-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
+
+namespace KODI
+{
+namespace RETRO
+{
+class CGameWindowFullScreen;
+class CGUIGameControl;
+class IRenderManager;
+
+// --- CGUIRenderTarget ------------------------------------------------------
+
+/*!
+ * \brief A target of rendering commands
+ *
+ * This class abstracts the destination of rendering commands. As a result,
+ * controls and windows are given a unified API.
+ */
+class CGUIRenderTarget
+{
+public:
+ CGUIRenderTarget(IRenderManager* renderManager);
+
+ virtual ~CGUIRenderTarget() = default;
+
+ /*!
+ * \brief Draw the frame to the rendering area
+ */
+ virtual void Render() = 0;
+
+ /*!
+ * \brief Draw the frame to the rendering area differently somehow
+ */
+ virtual void RenderEx() = 0;
+
+ /*!
+ * \brief Clear the background of the rendering area
+ */
+ virtual void ClearBackground() {} //! @todo
+
+ /*!
+ * \brief Check of the rendering area is dirty
+ */
+ virtual bool IsDirty() { return true; } //! @todo
+
+protected:
+ // Construction parameters
+ IRenderManager* const m_renderManager;
+};
+
+// --- CGUIRenderControl -----------------------------------------------------
+
+class CGUIRenderControl : public CGUIRenderTarget
+{
+public:
+ CGUIRenderControl(IRenderManager* renderManager, CGUIGameControl& gameControl);
+ ~CGUIRenderControl() override = default;
+
+ // implementation of CGUIRenderTarget
+ void Render() override;
+ void RenderEx() override;
+
+private:
+ // Construction parameters
+ CGUIGameControl& m_gameControl;
+};
+
+// --- CGUIRenderFullScreen --------------------------------------------------
+
+class CGUIRenderFullScreen : public CGUIRenderTarget
+{
+public:
+ CGUIRenderFullScreen(IRenderManager* renderManager, CGameWindowFullScreen& window);
+ ~CGUIRenderFullScreen() override = default;
+
+ // implementation of CGUIRenderTarget
+ void Render() override;
+ void RenderEx() override;
+ void ClearBackground() override;
+
+private:
+ // Construction parameters
+ CGameWindowFullScreen& m_window;
+};
+} // namespace RETRO
+} // namespace KODI
diff --git a/xbmc/cores/RetroPlayer/guibridge/GUIRenderTargetFactory.cpp b/xbmc/cores/RetroPlayer/guibridge/GUIRenderTargetFactory.cpp
new file mode 100644
index 0000000..05675c3
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/guibridge/GUIRenderTargetFactory.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2017-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 "GUIRenderTargetFactory.h"
+
+#include "GUIRenderTarget.h"
+
+using namespace KODI;
+using namespace RETRO;
+
+CGUIRenderTargetFactory::CGUIRenderTargetFactory(IRenderManager* renderManager)
+ : m_renderManager(renderManager)
+{
+}
+
+CGUIRenderTarget* CGUIRenderTargetFactory::CreateRenderFullScreen(CGameWindowFullScreen& window)
+{
+ return new CGUIRenderFullScreen(m_renderManager, window);
+}
+
+CGUIRenderTarget* CGUIRenderTargetFactory::CreateRenderControl(CGUIGameControl& gameControl)
+{
+ return new CGUIRenderControl(m_renderManager, gameControl);
+}
diff --git a/xbmc/cores/RetroPlayer/guibridge/GUIRenderTargetFactory.h b/xbmc/cores/RetroPlayer/guibridge/GUIRenderTargetFactory.h
new file mode 100644
index 0000000..8066854
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/guibridge/GUIRenderTargetFactory.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017-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
+
+namespace KODI
+{
+namespace RETRO
+{
+class CGameWindowFullScreen;
+class CGUIGameControl;
+class IRenderManager;
+class CGUIRenderTarget;
+
+class CGUIRenderTargetFactory
+{
+public:
+ CGUIRenderTargetFactory(IRenderManager* renderManager);
+
+ /*!
+ * \brief Create a render target for the fullscreen window
+ */
+ CGUIRenderTarget* CreateRenderFullScreen(CGameWindowFullScreen& window);
+
+ /*!
+ * \brief Create a render target for a game control
+ */
+ CGUIRenderTarget* CreateRenderControl(CGUIGameControl& gameControl);
+
+private:
+ // Construction parameters
+ IRenderManager* m_renderManager;
+};
+} // namespace RETRO
+} // namespace KODI
diff --git a/xbmc/cores/RetroPlayer/guibridge/IGUIRenderSettings.h b/xbmc/cores/RetroPlayer/guibridge/IGUIRenderSettings.h
new file mode 100644
index 0000000..8fb0fd1
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/guibridge/IGUIRenderSettings.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2017-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 "cores/RetroPlayer/rendering/RenderSettings.h"
+#include "utils/Geometry.h"
+
+namespace KODI
+{
+namespace RETRO
+{
+/*!
+ * \brief Interface to pass render settings from the GUI to the renderer
+ */
+class IGUIRenderSettings
+{
+public:
+ virtual ~IGUIRenderSettings() = default;
+
+ /*!
+ * \brief Returns true if this render target has a video filter set
+ */
+ virtual bool HasVideoFilter() const { return true; }
+
+ /*!
+ * \brief Returns true if this render target has a stretch mode set
+ */
+ virtual bool HasStretchMode() const { return true; }
+
+ /*!
+ * \brief Returns true if this render target has a video rotation set
+ */
+ virtual bool HasRotation() const { return true; }
+
+ /*!
+ * \brief Returns true if this render target has a path to a savestate for
+ * showing pixel data
+ */
+ virtual bool HasPixels() const { return true; }
+
+ /*!
+ * \brief Get the settings used to render this target
+ *
+ * \return The render settings
+ */
+ virtual CRenderSettings GetSettings() const = 0;
+
+ /*!
+ * \brief Get the dimensions of this target
+ *
+ * Dimensions are ignored for fullscreen windows.
+ *
+ * \return The destination dimensions, or unused for fullscreen window
+ */
+ virtual CRect GetDimensions() const { return CRect{}; }
+};
+} // namespace RETRO
+} // namespace KODI
diff --git a/xbmc/cores/RetroPlayer/guibridge/IGameCallback.h b/xbmc/cores/RetroPlayer/guibridge/IGameCallback.h
new file mode 100644
index 0000000..057dd04
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/guibridge/IGameCallback.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 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 <string>
+
+namespace KODI
+{
+namespace RETRO
+{
+class IPlayback;
+
+class IGameCallback
+{
+public:
+ virtual ~IGameCallback() = default;
+
+ /*!
+ * \brief Get the game client being used to play the game
+ *
+ * \return The game client's ID, or empty if no game is being played
+ */
+ virtual std::string GameClientID() const = 0;
+
+ /*!
+ * \brief Get the game that is being played
+ *
+ * \return The path to the game, or empty if no game is being played
+ */
+ virtual std::string GetPlayingGame() const = 0;
+
+ /*!
+ * \brief Creates a savestate
+ *
+ * \param autosave Whether the save type is auto
+ *
+ * \return The path to the created savestate, or empty on error
+ */
+ virtual std::string CreateSavestate(bool autosave) = 0;
+
+ /*!
+ * \brief Updates a savestate with the current game being played
+ *
+ * \param savestatePath The path to the savestate
+ *
+ * \return True if the savestate was updated, false on error
+ */
+ virtual bool UpdateSavestate(const std::string& savestatePath) = 0;
+
+ /*!
+ * \brief Loads a savestate
+ *
+ * \param savestatePath The path to the savestate
+ *
+ * \return True if the savestate was loaded, false on error
+ */
+ virtual bool LoadSavestate(const std::string& savestatePath) = 0;
+
+ /*!
+ * \brief Frees resources allocated to the savestate, such as its video thumbnail
+ *
+ * \param savestatePath The path to the savestate
+ */
+ virtual void FreeSavestateResources(const std::string& savestatePath) = 0;
+
+ /*!
+ * \brief Closes the OSD
+ */
+ virtual void CloseOSDCallback() = 0;
+};
+} // namespace RETRO
+} // namespace KODI
diff --git a/xbmc/cores/RetroPlayer/guibridge/IRenderCallback.h b/xbmc/cores/RetroPlayer/guibridge/IRenderCallback.h
new file mode 100644
index 0000000..948c6cd
--- /dev/null
+++ b/xbmc/cores/RetroPlayer/guibridge/IRenderCallback.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2017-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 "cores/GameSettings.h"
+
+namespace KODI
+{
+namespace RETRO
+{
+class IRenderCallback
+{
+public:
+ virtual ~IRenderCallback() = default;
+
+ virtual bool SupportsRenderFeature(RENDERFEATURE feature) const = 0;
+ virtual bool SupportsScalingMethod(SCALINGMETHOD method) const = 0;
+};
+} // namespace RETRO
+} // namespace KODI