[Scummvm-git-logs] scummvm master -> 14335f50aa0f7b545202569fadb88adff9b7eabe

spleen1981 noreply at scummvm.org
Sun May 14 16:57:36 UTC 2023


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
14335f50aa LIBRETRO: refactor OSystem_libretro


Commit: 14335f50aa0f7b545202569fadb88adff9b7eabe
    https://github.com/scummvm/scummvm/commit/14335f50aa0f7b545202569fadb88adff9b7eabe
Author: Giovanni Cascione (ing.cascione at gmail.com)
Date: 2023-05-14T18:56:15+02:00

Commit Message:
LIBRETRO: refactor OSystem_libretro

Changed paths:
  A backends/platform/libretro/include/libretro-defs.h
  A backends/platform/libretro/include/libretro-os.h
  A backends/platform/libretro/src/libretro-os-base.cpp
  A backends/platform/libretro/src/libretro-os-events.cpp
  A backends/platform/libretro/src/libretro-os-graphics.cpp
  A backends/platform/libretro/src/libretro-os-inputs.cpp
  A backends/platform/libretro/src/libretro-os-utils.cpp
  R backends/platform/libretro/include/os.h
  R backends/platform/libretro/src/libretro-os.cpp
    backends/platform/libretro/Makefile.common
    backends/platform/libretro/include/libretro-timer.h
    backends/platform/libretro/src/libretro-threads.cpp
    backends/platform/libretro/src/libretro-timer.cpp
    backends/platform/libretro/src/libretro.cpp


diff --git a/backends/platform/libretro/Makefile.common b/backends/platform/libretro/Makefile.common
index ce6db4af520..06999793082 100644
--- a/backends/platform/libretro/Makefile.common
+++ b/backends/platform/libretro/Makefile.common
@@ -118,10 +118,14 @@ endif
 INCLUDES     += -I$(ROOT_PATH)/include
 MODULE_PATHS += $(CORE_PATH)
 
-LIBRETRO_OBJS := $(CORE_PATH)/libretro-os.o \
+LIBRETRO_OBJS := $(CORE_PATH)/libretro.o \
 	$(CORE_PATH)/libretro-fs.o \
 	$(CORE_PATH)/libretro-fs-factory.o \
-	$(CORE_PATH)/libretro.o \
+	$(CORE_PATH)/libretro-os-base.o \
+	$(CORE_PATH)/libretro-os-graphics.o \
+	$(CORE_PATH)/libretro-os-events.o \
+	$(CORE_PATH)/libretro-os-inputs.o \
+	$(CORE_PATH)/libretro-os-utils.o \
 	$(CORE_PATH)/libretro-threads.o \
 	$(CORE_PATH)/libretro-timer.o
 
diff --git a/backends/platform/libretro/include/os.h b/backends/platform/libretro/include/libretro-defs.h
similarity index 65%
rename from backends/platform/libretro/include/os.h
rename to backends/platform/libretro/include/libretro-defs.h
index 821af1436c7..d1c291740c4 100644
--- a/backends/platform/libretro/include/os.h
+++ b/backends/platform/libretro/include/libretro-defs.h
@@ -1,8 +1,4 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
+/* Copyright (C) 2023 Giovanni Cascione <ing.cascione at gmail.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -19,8 +15,8 @@
  *
  */
 
-#ifndef BACKENDS_LIBRETRO_OS_H
-#define BACKENDS_LIBRETRO_OS_H
+#ifndef LIBRETRO_DEFS_H
+#define LIBRETRO_DEFS_H
 
 #define SAMPLE_RATE     48000
 #define REFRESH_RATE    60
@@ -55,12 +51,6 @@
 #define TEST_GAME_KO_NOT_FOUND           3
 #define TEST_GAME_KO_MULTIPLE_RESULTS    4
 
-#define FORBIDDEN_SYMBOL_ALLOW_ALL
-#include "libretro.h"
-
-#include "base/main.h"
-#include "common/system.h"
-
 #ifndef F_OK
 #define F_OK 0
 #endif
@@ -73,25 +63,4 @@
 #define R_OK 4
 #endif
 
-extern char cmd_params[20][200];
-extern char cmd_params_num;
-
-#if (defined(GEKKO) && !defined(WIIU)) || defined(__CELLOS_LV2__)
-extern int access(const char *path, int amode);
-#endif
-
-OSystem *retroBuildOS();
-const Graphics::Surface &getScreen();
-
-void retroProcessMouse(retro_input_state_t aCallback, int device, float gamepad_cursor_speed, float gamepad_acceleration_time, bool analog_response_is_quadratic, int analog_deadzone, float mouse_speed);
-void retroQuit(void);
-void retroReset(void);
-int retroTestGame(const char *game_id, bool autodetect);
-
-void retroKeyEvent(bool down, unsigned keycode, uint32_t character, uint16_t key_modifiers);
-
-uint8 getThreadSwitchCaller(void);
-
-void retroDestroy(void);
-
 #endif
diff --git a/backends/platform/libretro/include/libretro-os.h b/backends/platform/libretro/include/libretro-os.h
new file mode 100644
index 00000000000..1f0955108ae
--- /dev/null
+++ b/backends/platform/libretro/include/libretro-os.h
@@ -0,0 +1,184 @@
+/* Copyright (C) 2023 Giovanni Cascione <ing.cascione at gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef BACKENDS_LIBRETRO_OS_H
+#define BACKENDS_LIBRETRO_OS_H
+
+#include <libretro.h>
+#include <retro_miscellaneous.h>
+
+#include "audio/mixer_intern.h"
+#include "base/main.h"
+#include "backends/base-backend.h"
+#include "common/system.h"
+#include "common/mutex.h"
+#include "common/list.h"
+#include "common/events.h"
+#include "graphics/palette.h"
+#include "graphics/surface.h"
+
+#define LIBRETRO_G_SYSTEM dynamic_cast<OSystem_libretro *>(g_system)
+
+extern retro_log_printf_t log_cb;
+extern bool timing_inaccuracies_is_enabled(void);
+extern bool consecutive_screen_updates_is_enabled(void);
+extern void reset_performance_tuner(void);
+extern void retro_osd_notification(const char* msg);
+extern float frame_rate;
+extern const char * retro_get_system_dir(void);
+extern const char * retro_get_save_dir(void);
+
+/**
+ *  Dummy mutex implementation
+ */
+class LibretroMutexInternal final : public Common::MutexInternal {
+public:
+	LibretroMutexInternal() {};
+	~LibretroMutexInternal() override {};
+	bool lock() override { return 0; }
+	bool unlock() override { return 0; };
+};
+
+class LibretroPalette {
+public:
+	unsigned char _colors[256 * 3];
+	LibretroPalette(void);
+	~LibretroPalette(void) {};
+	void set(const byte *colors, uint start, uint num);
+	void get(byte *colors, uint start, uint num) const;
+	unsigned char *getColor(uint aIndex) const;
+};
+
+class OSystem_libretro : public EventsBaseBackend, public PaletteManager {
+private:
+	int _mouseX;
+	int _mouseY;
+	int _relMouseX;
+	int _relMouseY;
+	int _mouseHotspotX;
+	int _mouseHotspotY;
+	int _mouseKeyColor;
+	float _mouseXAcc;
+	float _mouseYAcc;
+	float _dpadXAcc;
+	float _dpadYAcc;
+	float _dpadXVel;
+	float _dpadYVel;
+	unsigned _joypadnumpadLast;
+	uint32 _startTime;
+	uint8 _threadSwitchCaller;
+	Common::String s_systemDir;
+	Common::String s_saveDir;
+	Common::String s_extraDir;
+	Common::String s_themeDir;
+	Common::String s_lastDir;
+	static Common::List<Common::Event> _events;
+
+public:
+	Audio::MixerImpl *_mixer;
+	Graphics::Surface _screen;
+	Graphics::Surface _gameScreen;
+	Graphics::Surface _overlay;
+	Graphics::Surface _mouseImage;
+	LibretroPalette _mousePalette;
+	LibretroPalette _gamePalette;
+	bool _overlayVisible;
+	bool _overlayInGUI;
+	bool _mouseDontScale;
+	bool _mouseButtons[2];
+	bool _joypadmouseButtons[2];
+	bool _joypadkeyboardButtons[8];
+	bool _joypadnumpadActive;
+	bool _ptrmouseButton;
+	bool _mousePaletteEnabled;
+	bool _mouseVisible;
+
+	/* Base */
+	OSystem_libretro(void);
+	~OSystem_libretro(void) override;
+	void initBackend(void) override;
+	void engineInit(void) override;
+	void engineDone(void) override;
+	bool hasFeature(Feature f) override;
+	void setFeatureState(Feature f, bool enable) override;
+	bool getFeatureState(Feature f) override;
+	void destroy(void);
+	void quit() override {}
+
+	/* Graphics */
+	Common::List<Graphics::PixelFormat> getSupportedFormats() const override;
+	const GraphicsMode *getSupportedGraphicsModes(void) const override;
+	void initSize(uint width, uint height, const Graphics::PixelFormat *format) override;
+	int16 getHeight(void) override;
+	int16 getWidth(void) override;
+	Graphics::PixelFormat getScreenFormat(void) const override;
+	void copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h) override;
+	void updateScreen(void) override;
+	void showOverlay(bool inGUI) override;
+	void hideOverlay(void) override;
+	void clearOverlay(void) override;
+	void grabOverlay(Graphics::Surface &surface) override;
+	void copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h) override;
+	int16 getOverlayHeight(void) override;
+	int16 getOverlayWidth(void) override;
+	Graphics::PixelFormat getOverlayFormat() const override;
+	const Graphics::Surface &getScreen(void);
+	bool showMouse(bool visible) override;
+	void warpMouse(int x, int y) override;
+	void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor = 255, bool dontScale = false, const Graphics::PixelFormat *format = NULL, const byte *mask = nullptr) override;
+	void setCursorPalette(const byte *colors, uint start, uint num) override;
+	int getDefaultGraphicsMode() const override { return 0; }
+	bool isOverlayVisible() const override { return false; }
+	bool setGraphicsMode(int mode, uint flags = kGfxModeNoFlags) override { return true; }
+	int getGraphicsMode() const override { return 0; }
+	PaletteManager *getPaletteManager() override { return this; }
+	Graphics::Surface *lockScreen() override { return &_gameScreen; }
+	void unlockScreen() override {}
+protected:
+	void setPalette(const byte *colors, uint start, uint num) override;
+	void grabPalette(byte *colors, uint start, uint num) const override;
+
+	/* Events */
+public:
+	bool pollEvent(Common::Event &event) override;
+	uint8 getThreadSwitchCaller(void);
+	uint32 getMillis(bool skipRecord = false) override;
+	void delayMillis(uint msecs) override;
+	Common::MutexInternal *createMutex(void) override;
+	void requestQuit(void);
+	void resetQuit(void);
+
+	/* Utils */
+	void getTimeAndDate(TimeDate &t, bool skipRecord) const override;
+	Audio::Mixer *getMixer(void) override;
+	Common::String getDefaultConfigFileName(void) override;
+	void logMessage(LogMessageType::Type type, const char *message) override;
+	int testGame(const char *filedata, bool autodetect);
+	void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0) override {}
+private:
+	bool parseGameName(const Common::String &gameName, Common::String &engineId, Common::String &gameId);
+
+	/* Inputs */
+public:
+	void processMouse(retro_input_state_t aCallback, int device, float gampad_cursor_speed, float gamepad_acceleration_time, bool analog_response_is_quadratic, int analog_deadzone, float mouse_speed);
+	static void processKeyEvent(bool down, unsigned keycode, uint32_t character, uint16_t key_modifiers);
+	void setShakePos(int shakeXOffset, int shakeYOffset) override {}
+private:
+	void updateMouseXY(float deltaAcc, float * cumulativeXYAcc, int doing_x);
+
+};
+
+#endif
diff --git a/backends/platform/libretro/include/libretro-timer.h b/backends/platform/libretro/include/libretro-timer.h
index 4500d4d75bd..7c3cfee6f2f 100644
--- a/backends/platform/libretro/include/libretro-timer.h
+++ b/backends/platform/libretro/include/libretro-timer.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2022 Giovanni Cascione <ing.cascione at gmail.com>
+/* Copyright (C) 2023 Giovanni Cascione <ing.cascione at gmail.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -21,7 +21,7 @@
 #define EMU_THREAD_MIN_TIME 10
 
 #include "backends/timer/default/default-timer.h"
-#include "backends/platform/libretro/include/os.h"
+#include "backends/platform/libretro/include/libretro-defs.h"
 
 class LibretroTimerManager : public DefaultTimerManager {
 	uint32 _interval;
diff --git a/backends/platform/libretro/src/libretro-os-base.cpp b/backends/platform/libretro/src/libretro-os-base.cpp
new file mode 100644
index 00000000000..131ef9b1e22
--- /dev/null
+++ b/backends/platform/libretro/src/libretro-os-base.cpp
@@ -0,0 +1,126 @@
+/* Copyright (C) 2023 Giovanni Cascione <ing.cascione at gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#if defined(_WIN32)
+#include "backends/fs/windows/windows-fs-factory.h"
+#define FS_SYSTEM_FACTORY WindowsFilesystemFactory
+#else
+#include "backends/platform/libretro/include/libretro-fs-factory.h"
+#define FS_SYSTEM_FACTORY LibRetroFilesystemFactory
+#endif
+
+#include "audio/mixer_intern.h"
+#include "backends/base-backend.h"
+#include "common/config-manager.h"
+#include "common/system.h"
+#include "graphics/surface.h"
+#include "backends/saves/default/default-saves.h"
+#include "backends/platform/libretro/include/libretro-timer.h"
+#include "backends/platform/libretro/include/libretro-os.h"
+#include "backends/platform/libretro/include/libretro-defs.h"
+
+OSystem_libretro::OSystem_libretro() : _mousePaletteEnabled(false), _mouseVisible(false), _mouseX(0), _mouseY(0), _mouseXAcc(0.0), _mouseYAcc(0.0), _mouseHotspotX(0), _mouseHotspotY(0), _dpadXAcc(0.0), _dpadYAcc(0.0), _dpadXVel(0.0f), _dpadYVel(0.0f), _mouseKeyColor(0), _mouseDontScale(false), _joypadnumpadLast(8), _joypadnumpadActive(false), _mixer(0), _startTime(0), _threadSwitchCaller(0) {
+	_fsFactory = new FS_SYSTEM_FACTORY();
+	memset(_mouseButtons, 0, sizeof(_mouseButtons));
+	memset(_joypadmouseButtons, 0, sizeof(_joypadmouseButtons));
+	memset(_joypadkeyboardButtons, 0, sizeof(_joypadkeyboardButtons));
+
+	s_systemDir = Common::String(retro_get_system_dir());
+	s_saveDir = Common::String(retro_get_save_dir());
+	s_themeDir = s_systemDir + "/" + SCUMMVM_SYSTEM_SUBDIR + "/" + SCUMMVM_THEME_SUBDIR;
+	s_extraDir = s_systemDir + "/" + SCUMMVM_SYSTEM_SUBDIR + "/" + SCUMMVM_EXTRA_SUBDIR;
+	s_lastDir = s_systemDir;
+
+	_startTime = getMillis();
+}
+
+OSystem_libretro::~OSystem_libretro() {
+	_gameScreen.free();
+	_overlay.free();
+	_mouseImage.free();
+	_screen.free();
+
+	delete _mixer;
+}
+
+void OSystem_libretro::initBackend() {
+
+	_savefileManager = new DefaultSaveFileManager(s_saveDir);
+
+	if (! ConfMan.hasKey("themepath")) {
+		if (! Common::FSNode(s_themeDir).exists())
+			retro_osd_notification("ScummVM theme folder not found.");
+		else
+			ConfMan.set("themepath", s_themeDir);
+	}
+
+	if (! ConfMan.hasKey("extrapath")) {
+		if (! Common::FSNode(s_extraDir).exists())
+			retro_osd_notification("ScummVM datafiles folder not found. Some engines/features will not work.");
+		else
+			ConfMan.set("extrapath", s_extraDir);
+	}
+
+	if (! ConfMan.hasKey("browser_lastpath"))
+		ConfMan.set("browser_lastpath", s_lastDir);
+
+#ifdef FRONTEND_SUPPORTS_RGB565
+	_overlay.create(RES_W_OVERLAY, RES_H_OVERLAY, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
+#else
+	_overlay.create(RES_W_OVERLAY, RES_H_OVERLAY, Graphics::PixelFormat(2, 5, 5, 5, 1, 10, 5, 0, 15));
+#endif
+	_mixer = new Audio::MixerImpl(SAMPLE_RATE);
+
+	_timerManager = new LibretroTimerManager(frame_rate);
+
+	_mixer->setReady(true);
+
+	EventsBaseBackend::initBackend();
+}
+
+void OSystem_libretro::engineInit() {
+	Common::String engineId = ConfMan.get("engineid");
+	if (engineId.equalsIgnoreCase("scumm") && ConfMan.getBool("original_gui")) {
+		ConfMan.setBool("original_gui", false);
+		log_cb(RETRO_LOG_INFO, "\"original_gui\" setting forced to false\n");
+	}
+}
+
+void OSystem_libretro::engineDone() {
+	reset_performance_tuner();
+}
+
+bool OSystem_libretro::hasFeature(Feature f) {
+	return (f == OSystem::kFeatureCursorPalette);
+}
+
+void OSystem_libretro::setFeatureState(Feature f, bool enable) {
+	if (f == kFeatureCursorPalette)
+		_mousePaletteEnabled = enable;
+}
+
+bool OSystem_libretro::getFeatureState(Feature f) {
+	return (f == kFeatureCursorPalette) ? _mousePaletteEnabled : false;
+}
+
+Audio::Mixer *OSystem_libretro::getMixer() {
+        return _mixer;
+}
+
+void OSystem_libretro::destroy() {
+	delete this;
+}
diff --git a/backends/platform/libretro/src/libretro-os-events.cpp b/backends/platform/libretro/src/libretro-os-events.cpp
new file mode 100644
index 00000000000..385535ced23
--- /dev/null
+++ b/backends/platform/libretro/src/libretro-os-events.cpp
@@ -0,0 +1,116 @@
+/* Copyright (C) 2023 Giovanni Cascione <ing.cascione at gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <unistd.h>
+#include <features/features_cpu.h>
+
+#include <sys/time.h>
+#if defined(__CELLOS_LV2__)
+#include <sys/sys_time.h>
+#elif (defined(GEKKO) && !defined(WIIU))
+#include <ogc/lwp_watchdog.h>
+#else
+#include <time.h>
+#endif
+
+#include "common/list.h"
+#include "common/events.h"
+#include "backends/platform/libretro/include/libretro-os.h"
+#include "backends/platform/libretro/include/libretro-timer.h"
+#include "backends/platform/libretro/include/libretro-defs.h"
+
+Common::List<Common::Event> OSystem_libretro::_events;
+
+bool OSystem_libretro::pollEvent(Common::Event &event) {
+	_threadSwitchCaller = THREAD_SWITCH_POLL;
+	((LibretroTimerManager *)_timerManager)->checkThread();
+	((LibretroTimerManager *)_timerManager)->handler();
+	if (!_events.empty()) {
+		event = _events.front();
+		_events.pop_front();
+		return true;
+	}
+
+	return false;
+}
+
+uint8 OSystem_libretro::getThreadSwitchCaller(){
+	return _threadSwitchCaller;
+}
+
+uint32 OSystem_libretro::getMillis(bool skipRecord) {
+#if (defined(GEKKO) && !defined(WIIU))
+	return (ticks_to_microsecs(gettime()) / 1000.0) - _startTime;
+#elif defined(WIIU)
+	return ((cpu_features_get_time_usec()) / 1000) - _startTime;
+#elif defined(__CELLOS_LV2__)
+	return (sys_time_get_system_time() / 1000.0) - _startTime;
+#else
+	struct timeval t;
+	gettimeofday(&t, 0);
+
+	return ((t.tv_sec * 1000) + (t.tv_usec / 1000)) - _startTime;
+#endif
+}
+
+void OSystem_libretro::delayMillis(uint msecs) {
+	uint32 start_time = getMillis();
+	uint32 elapsed_time = 0;
+
+	_threadSwitchCaller = THREAD_SWITCH_DELAY;
+
+	if (timing_inaccuracies_is_enabled()) {
+		while (elapsed_time < msecs) {
+			/* When remaining delay would take us past the next thread switch time, we switch immediately
+			in order to burn as much as possible delay time in the main RetroArch thread as soon as possible. */
+			if (msecs - elapsed_time >= ((LibretroTimerManager *)_timerManager)->timeToNextSwitch())
+				((LibretroTimerManager *)_timerManager)->switchThread();
+			else
+				usleep(1000);
+
+			/* Actual delay provided will be lower than requested: elapsed time is calculated cumulatively.
+			i.e. the higher the requested delay, the higher the actual delay reduction */
+			elapsed_time += getMillis() - start_time;
+		}
+	} else {
+		while (elapsed_time < msecs) {
+			/* if remaining delay is lower than last amount of time spent on main thread, burn it in emu thread
+			to avoid exceeding requested delay */
+			if (msecs - elapsed_time >= ((LibretroTimerManager *)_timerManager)->spentOnMainThread() && !((LibretroTimerManager *)_timerManager)->timeToNextSwitch())
+				((LibretroTimerManager *)_timerManager)->switchThread();
+			else
+				usleep(1000);
+			elapsed_time = getMillis() - start_time;
+		}
+	}
+
+	((LibretroTimerManager *)_timerManager)->handler();
+}
+
+Common::MutexInternal *OSystem_libretro::createMutex(void) {
+	return new LibretroMutexInternal();
+}
+
+void OSystem_libretro::requestQuit() {
+        Common::Event ev;
+        ev.type = Common::EVENT_QUIT;
+        LIBRETRO_G_SYSTEM->getEventManager()->pushEvent(ev);
+}
+
+void OSystem_libretro::resetQuit() {
+        LIBRETRO_G_SYSTEM->getEventManager()->resetQuit();
+}
diff --git a/backends/platform/libretro/src/libretro-os-graphics.cpp b/backends/platform/libretro/src/libretro-os-graphics.cpp
new file mode 100644
index 00000000000..8d9ea0f9215
--- /dev/null
+++ b/backends/platform/libretro/src/libretro-os-graphics.cpp
@@ -0,0 +1,411 @@
+/* Copyright (C) 2023 Giovanni Cascione <ing.cascione at gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <retro_inline.h>
+
+//#include "common/system.h"
+#include "graphics/colormasks.h"
+#include "graphics/palette.h"
+#include "graphics/surface.h"
+#include "backends/platform/libretro/include/libretro-os.h"
+#include "backends/platform/libretro/include/libretro-timer.h"
+#include "backends/platform/libretro/include/libretro-defs.h"
+
+static INLINE void blit_uint8_uint16_fast(Graphics::Surface &aOut, const Graphics::Surface &aIn, const LibretroPalette &aColors) {
+	for (int i = 0; i < aIn.h; i++) {
+		if (i >= aOut.h)
+			continue;
+
+		uint8_t *const in = (uint8_t *)aIn.getPixels() + (i * aIn.w);
+		uint16_t *const out = (uint16_t *)aOut.getPixels() + (i * aOut.w);
+
+		for (int j = 0; j < aIn.w; j++) {
+			if (j >= aOut.w)
+				continue;
+
+			uint8 r, g, b;
+
+			const uint8_t val = in[j];
+			// if(val != 0xFFFFFFFF)
+			{
+				if (aIn.format.bytesPerPixel == 1) {
+					unsigned char *col = aColors.getColor(val);
+					r = *col++;
+					g = *col++;
+					b = *col++;
+				} else
+					aIn.format.colorToRGB(in[j], r, g, b);
+
+				out[j] = aOut.format.RGBToColor(r, g, b);
+			}
+		}
+	}
+}
+
+static INLINE void blit_uint32_uint16(Graphics::Surface &aOut, const Graphics::Surface &aIn, const LibretroPalette &aColors) {
+	for (int i = 0; i < aIn.h; i++) {
+		if (i >= aOut.h)
+			continue;
+
+		uint32_t *const in = (uint32_t *)aIn.getPixels() + (i * aIn.w);
+		uint16_t *const out = (uint16_t *)aOut.getPixels() + (i * aOut.w);
+
+		for (int j = 0; j < aIn.w; j++) {
+			if (j >= aOut.w)
+				continue;
+
+			uint8 r, g, b;
+
+			// const uint32_t val = in[j];
+			// if(val != 0xFFFFFFFF)
+			{
+				aIn.format.colorToRGB(in[j], r, g, b);
+				out[j] = aOut.format.RGBToColor(r, g, b);
+			}
+		}
+	}
+}
+
+static INLINE void blit_uint16_uint16(Graphics::Surface &aOut, const Graphics::Surface &aIn, const LibretroPalette &aColors) {
+	for (int i = 0; i < aIn.h; i++) {
+		if (i >= aOut.h)
+			continue;
+
+		uint16_t *const in = (uint16_t *)aIn.getPixels() + (i * aIn.w);
+		uint16_t *const out = (uint16_t *)aOut.getPixels() + (i * aOut.w);
+
+		for (int j = 0; j < aIn.w; j++) {
+			if (j >= aOut.w)
+				continue;
+
+			uint8 r, g, b;
+
+			// const uint16_t val = in[j];
+			// if(val != 0xFFFFFFFF)
+			{
+				aIn.format.colorToRGB(in[j], r, g, b);
+				out[j] = aOut.format.RGBToColor(r, g, b);
+			}
+		}
+	}
+}
+
+static void blit_uint8_uint16(Graphics::Surface &aOut, const Graphics::Surface &aIn, int aX, int aY, const LibretroPalette &aColors, uint32 aKeyColor) {
+	for (int i = 0; i < aIn.h; i++) {
+		if ((i + aY) < 0 || (i + aY) >= aOut.h)
+			continue;
+
+		uint8_t *const in = (uint8_t *)aIn.getPixels() + (i * aIn.w);
+		uint16_t *const out = (uint16_t *)aOut.getPixels() + ((i + aY) * aOut.w);
+
+		for (int j = 0; j < aIn.w; j++) {
+			if ((j + aX) < 0 || (j + aX) >= aOut.w)
+				continue;
+
+			uint8 r, g, b;
+
+			const uint8_t val = in[j];
+			if (val != aKeyColor) {
+				unsigned char *col = aColors.getColor(val);
+				r = *col++;
+				g = *col++;
+				b = *col++;
+				out[j + aX] = aOut.format.RGBToColor(r, g, b);
+			}
+		}
+	}
+}
+
+static void blit_uint16_uint16(Graphics::Surface &aOut, const Graphics::Surface &aIn, int aX, int aY, const LibretroPalette &aColors, uint32 aKeyColor) {
+	for (int i = 0; i < aIn.h; i++) {
+		if ((i + aY) < 0 || (i + aY) >= aOut.h)
+			continue;
+
+		uint16_t *const in = (uint16_t *)aIn.getPixels() + (i * aIn.w);
+		uint16_t *const out = (uint16_t *)aOut.getPixels() + ((i + aY) * aOut.w);
+
+		for (int j = 0; j < aIn.w; j++) {
+			if ((j + aX) < 0 || (j + aX) >= aOut.w)
+				continue;
+
+			uint8 r, g, b;
+
+			const uint16_t val = in[j];
+			if (val != aKeyColor) {
+				aIn.format.colorToRGB(in[j], r, g, b);
+				out[j + aX] = aOut.format.RGBToColor(r, g, b);
+			}
+		}
+	}
+}
+
+static void blit_uint32_uint16(Graphics::Surface &aOut, const Graphics::Surface &aIn, int aX, int aY, const LibretroPalette &aColors, uint32 aKeyColor) {
+	for (int i = 0; i < aIn.h; i++) {
+		if ((i + aY) < 0 || (i + aY) >= aOut.h)
+			continue;
+
+		uint32_t *const in = (uint32_t *)aIn.getPixels() + (i * aIn.w);
+		uint16_t *const out = (uint16_t *)aOut.getPixels() + ((i + aY) * aOut.w);
+
+		for (int j = 0; j < aIn.w; j++) {
+			if ((j + aX) < 0 || (j + aX) >= aOut.w)
+				continue;
+
+			uint8 in_a, in_r, in_g, in_b;
+			uint8 out_r, out_g, out_b;
+			uint32_t blend_r, blend_g, blend_b;
+
+			const uint32_t val = in[j];
+			if (val != aKeyColor) {
+				aIn.format.colorToARGB(in[j], in_a, in_r, in_g, in_b);
+
+				if (in_a) {
+					aOut.format.colorToRGB(out[j + aX], out_r, out_g, out_b);
+
+					blend_r = ((in_r * in_a) + (out_r * (255 - in_a))) / 255;
+					blend_g = ((in_g * in_a) + (out_g * (255 - in_a))) / 255;
+					blend_b = ((in_b * in_a) + (out_b * (255 - in_a))) / 255;
+
+					out[j + aX] = aOut.format.RGBToColor(blend_r, blend_g, blend_b);
+				}
+			}
+		}
+	}
+}
+
+static INLINE void copyRectToSurface(uint8_t *pixels, int out_pitch, const uint8_t *src, int pitch, int x, int y, int w, int h, int out_bpp) {
+	uint8_t *dst = pixels + y * out_pitch + x * out_bpp;
+
+	do {
+		memcpy(dst, src, w * out_bpp);
+		src += pitch;
+		dst += out_pitch;
+	} while (--h);
+}
+
+LibretroPalette::LibretroPalette() {
+	memset(_colors, 0, sizeof(_colors));
+}
+
+void LibretroPalette::set(const byte *colors, uint start, uint num) {
+	memcpy(_colors + start * 3, colors, num * 3);
+}
+
+void LibretroPalette::get(byte *colors, uint start, uint num) const {
+	memcpy(colors, _colors + start * 3, num * 3);
+}
+
+unsigned char * LibretroPalette::getColor(uint aIndex) const {
+	return (unsigned char *)&_colors[aIndex * 3];
+}
+
+Common::List<Graphics::PixelFormat> OSystem_libretro::getSupportedFormats() const {
+	Common::List<Graphics::PixelFormat> result;
+
+#ifdef SCUMM_LITTLE_ENDIAN
+	/* RGBA8888 */
+	result.push_back(Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0));
+#else
+	/* ABGR8888 */
+	result.push_back(Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24));
+#endif
+#ifdef FRONTEND_SUPPORTS_RGB565
+	/* RGB565 - overlay */
+	result.push_back(Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
+#endif
+	/* RGB555 - fmtowns */
+	result.push_back(Graphics::PixelFormat(2, 5, 5, 5, 1, 10, 5, 0, 15));
+
+	/* Palette - most games */
+	result.push_back(Graphics::PixelFormat::createFormatCLUT8());
+
+	return result;
+}
+
+const OSystem_libretro::GraphicsMode *OSystem_libretro::getSupportedGraphicsModes() const {
+	static const OSystem::GraphicsMode s_noGraphicsModes[] = {{0, 0, 0}};
+	return s_noGraphicsModes;
+}
+
+
+
+void OSystem_libretro::initSize(uint width, uint height, const Graphics::PixelFormat *format) {
+	_gameScreen.create(width, height, format ? *format : Graphics::PixelFormat::createFormatCLUT8());
+}
+
+int16 OSystem_libretro::getHeight() {
+	return _gameScreen.h;
+}
+
+int16 OSystem_libretro::getWidth() {
+	return _gameScreen.w;
+}
+
+Graphics::PixelFormat OSystem_libretro::getScreenFormat() const {
+	return _gameScreen.format;
+}
+
+void OSystem_libretro::copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h) {
+	const uint8_t *src = (const uint8_t *)buf;
+	uint8_t *pix = (uint8_t *)_gameScreen.getPixels();
+	copyRectToSurface(pix, _gameScreen.pitch, src, pitch, x, y, w, h, _gameScreen.format.bytesPerPixel);
+}
+
+void OSystem_libretro::updateScreen() {
+	const Graphics::Surface &srcSurface = (_overlayInGUI) ? _overlay : _gameScreen;
+	if (srcSurface.w && srcSurface.h) {
+		switch (srcSurface.format.bytesPerPixel) {
+		case 1:
+		case 3:
+			blit_uint8_uint16_fast(_screen, srcSurface, _gamePalette);
+			break;
+		case 2:
+			blit_uint16_uint16(_screen, srcSurface, _gamePalette);
+			break;
+		case 4:
+			blit_uint32_uint16(_screen, srcSurface, _gamePalette);
+			break;
+		}
+	}
+
+	// Draw Mouse
+	if (_mouseVisible && _mouseImage.w && _mouseImage.h) {
+		const int x = _mouseX - _mouseHotspotX;
+		const int y = _mouseY - _mouseHotspotY;
+
+		switch (_mouseImage.format.bytesPerPixel) {
+		case 1:
+		case 3:
+			blit_uint8_uint16(_screen, _mouseImage, x, y, _mousePaletteEnabled ? _mousePalette : _gamePalette, _mouseKeyColor);
+			break;
+		case 2:
+			blit_uint16_uint16(_screen, _mouseImage, x, y, _mousePaletteEnabled ? _mousePalette : _gamePalette, _mouseKeyColor);
+			break;
+		case 4:
+			blit_uint32_uint16(_screen, _mouseImage, x, y, _mousePaletteEnabled ? _mousePalette : _gamePalette, _mouseKeyColor);
+			break;
+		}
+	}
+
+	/* Switch directly to main thread in case of consecutive updateScreen, to avoid losing frames.
+	Non consecutive updateScreen are covered by thread switches triggered by pollEvent or delayMillis. */
+	if (! timing_inaccuracies_is_enabled() && consecutive_screen_updates_is_enabled()) {
+		if (_threadSwitchCaller & THREAD_SWITCH_UPDATE) {
+			((LibretroTimerManager *)_timerManager)->switchThread();
+		} else {
+			_threadSwitchCaller = THREAD_SWITCH_UPDATE;
+		}
+	}
+}
+
+void OSystem_libretro::showOverlay(bool inGUI) {
+	_overlayVisible = true;
+	_overlayInGUI = inGUI;
+}
+
+void OSystem_libretro::hideOverlay() {
+	_overlayVisible = false;
+	_overlayInGUI = false;
+}
+
+void OSystem_libretro::clearOverlay() {
+	_overlay.fillRect(Common::Rect(_overlay.w, _overlay.h), 0);
+}
+
+void OSystem_libretro::grabOverlay(Graphics::Surface &surface) {
+	const unsigned char *src = (unsigned char *)_overlay.getPixels();
+	unsigned char *dst = (byte *)surface.getPixels();
+	;
+	unsigned i = RES_H_OVERLAY;
+
+	do {
+		memcpy(dst, src, RES_W_OVERLAY << 1);
+		dst += surface.pitch;
+		src += RES_W_OVERLAY << 1;
+	} while (--i);
+}
+
+void OSystem_libretro::copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h) {
+	const uint8_t *src = (const uint8_t *)buf;
+	uint8_t *pix = (uint8_t *)_overlay.getPixels();
+	copyRectToSurface(pix, _overlay.pitch, src, pitch, x, y, w, h, _overlay.format.bytesPerPixel);
+}
+
+int16 OSystem_libretro::getOverlayHeight() {
+	return _overlay.h;
+}
+
+int16 OSystem_libretro::getOverlayWidth() {
+	return _overlay.w;
+}
+
+Graphics::PixelFormat OSystem_libretro::getOverlayFormat() const {
+	return _overlay.format;
+}
+
+bool OSystem_libretro::showMouse(bool visible) {
+	const bool wasVisible = _mouseVisible;
+	_mouseVisible = visible;
+	return wasVisible;
+}
+
+void OSystem_libretro::warpMouse(int x, int y) {
+	_mouseX = x;
+	_mouseY = y;
+}
+
+void OSystem_libretro::setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format, const byte *mask) {
+	const Graphics::PixelFormat mformat = format ? *format : Graphics::PixelFormat::createFormatCLUT8();
+
+	if (_mouseImage.w != w || _mouseImage.h != h || _mouseImage.format != mformat) {
+		_mouseImage.create(w, h, mformat);
+	}
+
+	memcpy(_mouseImage.getPixels(), buf, h * _mouseImage.pitch);
+
+	_mouseHotspotX = hotspotX;
+	_mouseHotspotY = hotspotY;
+	_mouseKeyColor = keycolor;
+	_mouseDontScale = dontScale;
+}
+
+void OSystem_libretro::setCursorPalette(const byte *colors, uint start, uint num) {
+	_mousePalette.set(colors, start, num);
+	_mousePaletteEnabled = true;
+}
+
+const Graphics::Surface &OSystem_libretro::getScreen() {
+	const Graphics::Surface &srcSurface = (_overlayInGUI) ? _overlay : _gameScreen;
+
+	if (srcSurface.w != _screen.w || srcSurface.h != _screen.h) {
+#ifdef FRONTEND_SUPPORTS_RGB565
+		_screen.create(srcSurface.w, srcSurface.h, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
+#else
+		_screen.create(srcSurface.w, srcSurface.h, Graphics::PixelFormat(2, 5, 5, 5, 1, 10, 5, 0, 15));
+#endif
+	}
+
+	return _screen;
+}
+
+void OSystem_libretro::setPalette(const byte *colors, uint start, uint num) {
+	_gamePalette.set(colors, start, num);
+}
+
+void OSystem_libretro::grabPalette(byte *colors, uint start, uint num) const {
+	_gamePalette.get(colors, start, num);
+}
diff --git a/backends/platform/libretro/src/libretro-os-inputs.cpp b/backends/platform/libretro/src/libretro-os-inputs.cpp
new file mode 100644
index 00000000000..9e838570e9a
--- /dev/null
+++ b/backends/platform/libretro/src/libretro-os-inputs.cpp
@@ -0,0 +1,437 @@
+/* Copyright (C) 2023 Giovanni Cascione <ing.cascione at gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <libretro.h>
+#include "backends/platform/libretro/include/libretro-os.h"
+
+#define ANALOG_RANGE 0x8000
+#define BASE_CURSOR_SPEED 4
+#define PI 3.141592653589793238
+
+void OSystem_libretro::updateMouseXY(float deltaAcc, float * cumulativeXYAcc, int doing_x){
+	int * mouseXY;
+	int16 * screen_wh;
+	int * relMouseXY;
+	int cumulativeXYAcc_int;
+	if (doing_x) {
+		mouseXY = &_mouseX;
+		screen_wh = &_screen.w;
+		relMouseXY = &_relMouseX;
+	} else {
+		mouseXY = &_mouseY;
+		screen_wh = &_screen.h;
+		relMouseXY = &_relMouseY;
+	}
+	*cumulativeXYAcc += deltaAcc;
+	cumulativeXYAcc_int = (int)*cumulativeXYAcc;
+	if (cumulativeXYAcc_int != 0) {
+		// Set mouse position
+		*mouseXY += cumulativeXYAcc_int;
+		*mouseXY = (*mouseXY < 0) ? 0 : *mouseXY;
+		*mouseXY = (*mouseXY >= *screen_wh) ? *screen_wh : *mouseXY;
+		// Update accumulator
+		*cumulativeXYAcc -= (float)cumulativeXYAcc_int;
+	}
+	*relMouseXY = (int)deltaAcc;
+}
+
+void OSystem_libretro::processMouse(retro_input_state_t aCallback, int device, float gampad_cursor_speed, float gamepad_acceleration_time, bool analog_response_is_quadratic, int analog_deadzone, float mouse_speed) {
+	enum processMouse_status {
+		STATUS_DOING_JOYSTICK  = (1 << 0),
+		STATUS_DOING_MOUSE     = (1 << 1),
+		STATUS_DOING_X         = (1 << 2),
+		STATUS_DOING_Y         = (1 << 3)
+	};
+	uint8_t status = 0;
+	int16_t joy_x, joy_y, joy_rx, joy_ry, x, y;
+	float analog_amplitude_x, analog_amplitude_y;
+	float deltaAcc;
+	bool  down;
+	float screen_adjusted_cursor_speed = (float)_screen.w / 320.0f; // Dpad cursor speed should always be based off a 320 wide screen, to keep speeds consistent
+	float adjusted_cursor_speed = (float)BASE_CURSOR_SPEED * gampad_cursor_speed * screen_adjusted_cursor_speed;
+	float inverse_acceleration_time = (gamepad_acceleration_time > 0.0) ? (1.0 / 60.0) * (1.0 / gamepad_acceleration_time) : 1.0;
+	int dpad_cursor_offset;
+	double rs_radius, rs_angle;
+	unsigned numpad_index;
+
+	static const uint32_t retroButtons[2] = {RETRO_DEVICE_ID_MOUSE_LEFT, RETRO_DEVICE_ID_MOUSE_RIGHT};
+	static const Common::EventType eventID[2][2] = {{Common::EVENT_LBUTTONDOWN, Common::EVENT_LBUTTONUP}, {Common::EVENT_RBUTTONDOWN, Common::EVENT_RBUTTONUP}};
+
+	static const unsigned gampad_key_map[8][4] = {
+		{RETRO_DEVICE_ID_JOYPAD_X, (unsigned)Common::KEYCODE_ESCAPE, (unsigned)Common::ASCII_ESCAPE, 0},           // Esc
+		{RETRO_DEVICE_ID_JOYPAD_Y, (unsigned)Common::KEYCODE_PERIOD, 46, 0},                                       // .
+		{RETRO_DEVICE_ID_JOYPAD_L, (unsigned)Common::KEYCODE_RETURN, (unsigned)Common::ASCII_RETURN, 0},           // Enter
+		{RETRO_DEVICE_ID_JOYPAD_R, (unsigned)Common::KEYCODE_KP5, 53, 0},                                          // Numpad 5
+		{RETRO_DEVICE_ID_JOYPAD_L2, (unsigned)Common::KEYCODE_BACKSPACE, (unsigned)Common::ASCII_BACKSPACE, 0},    // Backspace
+		{RETRO_DEVICE_ID_JOYPAD_L3, (unsigned)Common::KEYCODE_F10, (unsigned)Common::ASCII_F10, 0},                // F10
+		{RETRO_DEVICE_ID_JOYPAD_R3, (unsigned)Common::KEYCODE_KP0, 48, 0},                                         // Numpad 0
+		{RETRO_DEVICE_ID_JOYPAD_SELECT, (unsigned)Common::KEYCODE_F7, (unsigned)Common::ASCII_F7, RETROKMOD_CTRL}, // CTRL+F7 (virtual keyboard)
+	};
+
+	// Right stick circular wrap around: 1 -> 2 -> 3 -> 6 -> 9 -> 8 -> 7 -> 4
+	static const unsigned gampad_numpad_map[8][2] = {
+		{(unsigned)Common::KEYCODE_KP1, 49},
+		{(unsigned)Common::KEYCODE_KP2, 50},
+		{(unsigned)Common::KEYCODE_KP3, 51},
+		{(unsigned)Common::KEYCODE_KP6, 54},
+		{(unsigned)Common::KEYCODE_KP9, 57},
+		{(unsigned)Common::KEYCODE_KP8, 56},
+		{(unsigned)Common::KEYCODE_KP7, 55},
+		{(unsigned)Common::KEYCODE_KP4, 52},
+	};
+
+	// Reduce gamepad cursor speed, if required
+	if (device == RETRO_DEVICE_JOYPAD && aCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2)) {
+		adjusted_cursor_speed = adjusted_cursor_speed * (1.0f / 5.0f);
+	}
+
+	status = 0;
+	x = aCallback(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_X);
+	y = aCallback(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_Y);
+	joy_x = aCallback(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X);
+	joy_y = aCallback(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y);
+
+	// Left Analog X Axis
+	if (joy_x > analog_deadzone || joy_x < -analog_deadzone) {
+		status |= (STATUS_DOING_JOYSTICK | STATUS_DOING_X);
+		if (joy_x > analog_deadzone) {
+			// Reset accumulator when changing direction
+			_mouseXAcc = (_mouseXAcc < 0.0) ? 0.0 : _mouseXAcc;
+			joy_x = joy_x - analog_deadzone;
+		}
+		if (joy_x < -analog_deadzone) {
+			// Reset accumulator when changing direction
+			_mouseXAcc = (_mouseXAcc > 0.0) ? 0.0 : _mouseXAcc;
+			joy_x = joy_x + analog_deadzone;
+		}
+		// Update accumulator
+		analog_amplitude_x = (float)joy_x / (float)(ANALOG_RANGE - analog_deadzone);
+		if (analog_response_is_quadratic) {
+			if (analog_amplitude_x < 0.0)
+				analog_amplitude_x = -(analog_amplitude_x * analog_amplitude_x);
+			else
+				analog_amplitude_x = analog_amplitude_x * analog_amplitude_x;
+		}
+		// printf("analog_amplitude_x: %f\n", analog_amplitude_x);
+		deltaAcc = analog_amplitude_x * adjusted_cursor_speed;
+		updateMouseXY(deltaAcc, &_mouseXAcc, 1);
+	}
+
+	// Left Analog Y Axis
+	if (joy_y > analog_deadzone || joy_y < -analog_deadzone) {
+		status |= (STATUS_DOING_JOYSTICK | STATUS_DOING_Y);
+		if (joy_y > analog_deadzone) {
+			// Reset accumulator when changing direction
+			_mouseYAcc = (_mouseYAcc < 0.0) ? 0.0 : _mouseYAcc;
+			joy_y = joy_y - analog_deadzone;
+		}
+		if (joy_y < -analog_deadzone) {
+			// Reset accumulator when changing direction
+			_mouseYAcc = (_mouseYAcc > 0.0) ? 0.0 : _mouseYAcc;
+			joy_y = joy_y + analog_deadzone;
+		}
+		// Update accumulator
+		analog_amplitude_y = (float)joy_y / (float)(ANALOG_RANGE - analog_deadzone);
+		if (analog_response_is_quadratic) {
+			if (analog_amplitude_y < 0.0)
+				analog_amplitude_y = -(analog_amplitude_y * analog_amplitude_y);
+			else
+				analog_amplitude_y = analog_amplitude_y * analog_amplitude_y;
+		}
+		// printf("analog_amplitude_y: %f\n", analog_amplitude_y);
+		deltaAcc = analog_amplitude_y * adjusted_cursor_speed;
+		updateMouseXY(deltaAcc, &_mouseYAcc, 0);
+	}
+
+	if (device == RETRO_DEVICE_JOYPAD) {
+		bool dpadLeft = aCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT);
+		bool dpadRight = aCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT);
+		bool dpadUp = aCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP);
+		bool dpadDown = aCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN);
+
+		if (dpadLeft || dpadRight) {
+			status |= (STATUS_DOING_JOYSTICK | STATUS_DOING_X);
+			_dpadXVel = MIN(_dpadXVel + inverse_acceleration_time, 1.0f);
+
+			if (dpadLeft) {
+				deltaAcc = -(_dpadXVel * adjusted_cursor_speed);
+				_dpadXAcc = _dpadXAcc < deltaAcc ? _dpadXAcc : 0.0f;
+			} else { //dpadRight
+				deltaAcc = _dpadXVel * adjusted_cursor_speed;
+				_dpadXAcc = _dpadXAcc > deltaAcc ? _dpadXAcc : 0.0f;
+			}
+
+			updateMouseXY(deltaAcc, &_dpadXAcc, 1);
+		} else {
+			_dpadXVel = 0.0f;
+		}
+
+
+		if (dpadUp || dpadDown) {
+			status |= (STATUS_DOING_JOYSTICK | STATUS_DOING_Y);
+			_dpadYVel = MIN(_dpadYVel + inverse_acceleration_time, 1.0f);
+
+			if (dpadUp) {
+				deltaAcc = -(_dpadYVel * adjusted_cursor_speed);
+				_dpadYAcc = _dpadYAcc < deltaAcc ? _dpadYAcc : 0.0f;
+			} else { //dpadDown
+				deltaAcc = _dpadYVel * adjusted_cursor_speed;
+				_dpadYAcc = _dpadYAcc > deltaAcc ? _dpadYAcc : 0.0f;
+			}
+
+			updateMouseXY(deltaAcc, &_dpadYAcc, 0);
+
+
+		} else {
+			_dpadYVel = 0.0f;
+		}
+
+		if (aCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START)) {
+			Common::Event ev;
+			ev.type = Common::EVENT_MAINMENU;
+			_events.push_back(ev);
+		}
+	}
+
+#if defined(WIIU) || defined(__SWITCH__)
+	int p_x = aCallback(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_X);
+	int p_y = aCallback(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_Y);
+	int p_press = aCallback(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_PRESSED);
+	int px = (int)((p_x + 0x7fff) * _screen.w / 0xffff);
+	int py = (int)((p_y + 0x7fff) * _screen.h / 0xffff);
+	// printf("(%d,%d) p:%d\n",px,py,pp);
+
+	static int ptrhold = 0;
+
+	if (p_press)
+		ptrhold++;
+	else
+		ptrhold = 0;
+
+	if (ptrhold > 0) {
+		_mouseX = px;
+		_mouseY = py;
+
+		Common::Event ev;
+		ev.type = Common::EVENT_MOUSEMOVE;
+		ev.mouse.x = _mouseX;
+		ev.mouse.y = _mouseY;
+		_events.push_back(ev);
+	}
+
+	if (ptrhold > 10 && _ptrmouseButton == 0) {
+		_ptrmouseButton = 1;
+		Common::Event ev;
+		ev.type = eventID[0][_ptrmouseButton ? 0 : 1];
+		ev.mouse.x = _mouseX;
+		ev.mouse.y = _mouseY;
+		_events.push_back(ev);
+	} else if (ptrhold == 0 && _ptrmouseButton == 1) {
+		_ptrmouseButton = 0;
+		Common::Event ev;
+		ev.type = eventID[0][_ptrmouseButton ? 0 : 1];
+		ev.mouse.x = _mouseX;
+		ev.mouse.y = _mouseY;
+		_events.push_back(ev);
+	}
+
+#endif
+
+	if (status & STATUS_DOING_JOYSTICK) {
+		Common::Event ev;
+		ev.type = Common::EVENT_MOUSEMOVE;
+		ev.mouse.x = _mouseX;
+		ev.mouse.y = _mouseY;
+		ev.relMouse.x = status & STATUS_DOING_X ? _relMouseX : 0;
+		ev.relMouse.y = status & STATUS_DOING_Y ? _relMouseY : 0;
+		_events.push_back(ev);
+	}
+
+	// Gampad mouse buttons
+	down = aCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A);
+	if (down != _joypadmouseButtons[0]) {
+		_joypadmouseButtons[0] = down;
+
+		Common::Event ev;
+		ev.type = eventID[0][down ? 0 : 1];
+		ev.mouse.x = _mouseX;
+		ev.mouse.y = _mouseY;
+		_events.push_back(ev);
+	}
+
+	down = aCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B);
+	if (down != _joypadmouseButtons[1]) {
+		_joypadmouseButtons[1] = down;
+
+		Common::Event ev;
+		ev.type = eventID[1][down ? 0 : 1];
+		ev.mouse.x = _mouseX;
+		ev.mouse.y = _mouseY;
+		_events.push_back(ev);
+	}
+
+	// Gamepad keyboard buttons
+	for (int i = 0; i < 8; i++) {
+		down = aCallback(0, RETRO_DEVICE_JOYPAD, 0, gampad_key_map[i][0]);
+		if (down != _joypadkeyboardButtons[i]) {
+			_joypadkeyboardButtons[i] = down;
+			bool state = down ? true : false;
+			processKeyEvent(state, gampad_key_map[i][1], (uint32_t)gampad_key_map[i][2], (uint32_t)gampad_key_map[i][3]);
+		}
+	}
+
+	// Gamepad right stick numpad emulation
+	joy_rx = aCallback(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X);
+	joy_ry = aCallback(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y);
+
+	if (joy_rx > analog_deadzone)
+		joy_rx = joy_rx - analog_deadzone;
+	else if (joy_rx < -analog_deadzone)
+		joy_rx = joy_rx + analog_deadzone;
+	else
+		joy_rx = 0;
+
+	if (joy_ry > analog_deadzone)
+		joy_ry = joy_ry - analog_deadzone;
+	else if (joy_ry < -analog_deadzone)
+		joy_ry = joy_ry + analog_deadzone;
+	else
+		joy_ry = 0;
+
+	// This is very ugly, but I don't have time to make it nicer...
+	if (joy_rx != 0 || joy_ry != 0) {
+		analog_amplitude_x = (float)joy_rx / (float)(ANALOG_RANGE - analog_deadzone);
+		analog_amplitude_y = (float)joy_ry / (float)(ANALOG_RANGE - analog_deadzone);
+
+		// Convert to polar coordinates: part 1
+		rs_radius = sqrt((double)(analog_amplitude_x * analog_amplitude_x) + (double)(analog_amplitude_y * analog_amplitude_y));
+
+		// Check if radius is above threshold
+		if (rs_radius > 0.5) {
+			// Convert to polar coordinates: part 2
+			rs_angle = atan2((double)analog_amplitude_y, (double)analog_amplitude_x);
+
+			// Adjust rotation offset...
+			rs_angle = (2.0 * PI) - (rs_angle + PI);
+			rs_angle = fmod(rs_angle - (0.125 * PI), 2.0 * PI);
+			if (rs_angle < 0)
+				rs_angle += 2.0 * PI;
+
+			// Convert angle into numpad key index
+			numpad_index = (unsigned)((rs_angle / (2.0 * PI)) * 8.0);
+			// Unnecessary safety check...
+			numpad_index = (numpad_index > 7) ? 7 : numpad_index;
+			// printf("numpad_index: %u\n", numpad_index);
+
+			if (numpad_index != _joypadnumpadLast) {
+				// Unset last key, if required
+				if (_joypadnumpadActive)
+					processKeyEvent(false, gampad_numpad_map[_joypadnumpadLast][0], (uint32_t)gampad_numpad_map[_joypadnumpadLast][1], 0);
+
+				// Set new key
+				processKeyEvent(true, gampad_numpad_map[numpad_index][0], (uint32_t)gampad_numpad_map[numpad_index][1], 0);
+
+				_joypadnumpadLast = numpad_index;
+				_joypadnumpadActive = true;
+			}
+		} else if (_joypadnumpadActive) {
+			processKeyEvent(false, gampad_numpad_map[_joypadnumpadLast][0], (uint32_t)gampad_numpad_map[_joypadnumpadLast][1], 0);
+			_joypadnumpadActive = false;
+			_joypadnumpadLast = 8;
+		}
+	} else if (_joypadnumpadActive) {
+		processKeyEvent(false, gampad_numpad_map[_joypadnumpadLast][0], (uint32_t)gampad_numpad_map[_joypadnumpadLast][1], 0);
+		_joypadnumpadActive = false;
+		_joypadnumpadLast = 8;
+	}
+
+	// Process input from physical mouse
+	// > X Axis
+	if (x != 0) {
+		status |= (STATUS_DOING_MOUSE | STATUS_DOING_X);
+		if (x > 0) {
+			// Reset accumulator when changing direction
+			_mouseXAcc = (_mouseXAcc < 0.0) ? 0.0 : _mouseXAcc;
+		}
+		if (x < 0) {
+			// Reset accumulator when changing direction
+			_mouseXAcc = (_mouseXAcc > 0.0) ? 0.0 : _mouseXAcc;
+		}
+		deltaAcc = (float)x * mouse_speed;
+		updateMouseXY(deltaAcc, &_mouseXAcc, 1);
+	}
+	// > Y Axis
+	if (y != 0) {
+		status |= (STATUS_DOING_MOUSE | STATUS_DOING_Y);
+		if (y > 0) {
+			// Reset accumulator when changing direction
+			_mouseYAcc = (_mouseYAcc < 0.0) ? 0.0 : _mouseYAcc;
+		}
+		if (y < 0) {
+			// Reset accumulator when changing direction
+			_mouseYAcc = (_mouseYAcc > 0.0) ? 0.0 : _mouseYAcc;
+		}
+		deltaAcc = (float)y * mouse_speed;
+		updateMouseXY(deltaAcc, &_mouseYAcc, 0);
+	}
+
+	if (status & STATUS_DOING_MOUSE) {
+		Common::Event ev;
+		ev.type = Common::EVENT_MOUSEMOVE;
+		ev.mouse.x = _mouseX;
+		ev.mouse.y = _mouseY;
+		ev.relMouse.x = status & STATUS_DOING_X ? _relMouseX : 0;
+		ev.relMouse.y = status & STATUS_DOING_Y ? _relMouseY : 0;
+		_events.push_back(ev);
+	}
+
+	for (int i = 0; i < 2; i++) {
+		Common::Event ev;
+		bool down = aCallback(0, RETRO_DEVICE_MOUSE, 0, retroButtons[i]);
+		if (down != _mouseButtons[i]) {
+			_mouseButtons[i] = down;
+
+			ev.type = eventID[i][down ? 0 : 1];
+			ev.mouse.x = _mouseX;
+			ev.mouse.y = _mouseY;
+			_events.push_back(ev);
+		}
+	}
+}
+
+void OSystem_libretro::processKeyEvent(bool down, unsigned keycode, uint32_t character, uint16_t key_modifiers) {
+	int _keyflags = 0;
+	_keyflags |= (key_modifiers & RETROKMOD_CTRL) ? Common::KBD_CTRL : 0;
+	_keyflags |= (key_modifiers & RETROKMOD_ALT) ? Common::KBD_ALT : 0;
+	_keyflags |= (key_modifiers & RETROKMOD_SHIFT) ? Common::KBD_SHIFT : 0;
+	_keyflags |= (key_modifiers & RETROKMOD_META) ? Common::KBD_META : 0;
+	_keyflags |= (key_modifiers & RETROKMOD_CAPSLOCK) ? Common::KBD_CAPS : 0;
+	_keyflags |= (key_modifiers & RETROKMOD_NUMLOCK) ? Common::KBD_NUM : 0;
+	_keyflags |= (key_modifiers & RETROKMOD_SCROLLOCK) ? Common::KBD_SCRL : 0;
+
+	Common::Event ev;
+	ev.type = down ? Common::EVENT_KEYDOWN : Common::EVENT_KEYUP;
+	ev.kbd.keycode = (Common::KeyCode)keycode;
+	ev.kbd.flags = _keyflags;
+	ev.kbd.ascii = keycode;
+
+	/* If shift was down then send upper case letter to engine */
+	if (ev.kbd.ascii >= 97 && ev.kbd.ascii <= 122 && (_keyflags & Common::KBD_SHIFT))
+		ev.kbd.ascii = ev.kbd.ascii & ~0x20;
+
+	_events.push_back(ev);
+}
diff --git a/backends/platform/libretro/src/libretro-os-utils.cpp b/backends/platform/libretro/src/libretro-os-utils.cpp
new file mode 100644
index 00000000000..9a98b2d2648
--- /dev/null
+++ b/backends/platform/libretro/src/libretro-os-utils.cpp
@@ -0,0 +1,157 @@
+/* Copyright (C) 2023 Giovanni Cascione <ing.cascione at gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#define FORBIDDEN_SYMBOL_EXCEPTION_time
+
+#include <sys/time.h>
+#if defined(__CELLOS_LV2__)
+#include <sys/sys_time.h>
+#elif (defined(GEKKO) && !defined(WIIU))
+#include <ogc/lwp_watchdog.h>
+#else
+#include <time.h>
+#endif
+
+#include "common/tokenizer.h"
+#include "common/config-manager.h"
+#include "base/commandLine.h"
+#include "backends/platform/libretro/include/libretro-os.h"
+#include "backends/platform/libretro/include/libretro-defs.h"
+
+void OSystem_libretro::getTimeAndDate(TimeDate &t, bool skipRecord) const {
+	time_t curTime = time(NULL);
+
+#define YEAR0 1900
+#define EPOCH_YR 1970
+#define SECS_DAY (24L * 60L * 60L)
+#define LEAPYEAR(year) (!((year) % 4) && (((year) % 100) || !((year) % 400)))
+#define YEARSIZE(year) (LEAPYEAR(year) ? 366 : 365)
+	const int _ytab[2][12] = {{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
+	int year = EPOCH_YR;
+	unsigned long dayclock = (unsigned long)curTime % SECS_DAY;
+	unsigned long dayno = (unsigned long)curTime / SECS_DAY;
+	t.tm_sec = dayclock % 60;
+	t.tm_min = (dayclock % 3600) / 60;
+	t.tm_hour = dayclock / 3600;
+	t.tm_wday = (dayno + 4) % 7; /* day 0 was a thursday */
+	while (dayno >= YEARSIZE(year)) {
+		dayno -= YEARSIZE(year);
+		year++;
+	}
+	t.tm_year = year - YEAR0;
+	t.tm_mon = 0;
+	while (dayno >= _ytab[LEAPYEAR(year)][t.tm_mon]) {
+		dayno -= _ytab[LEAPYEAR(year)][t.tm_mon];
+		t.tm_mon++;
+	}
+	t.tm_mday = dayno + 1;
+}
+
+Common::String OSystem_libretro::getDefaultConfigFileName() {
+	return s_systemDir + "/scummvm.ini";
+}
+
+void OSystem_libretro::logMessage(LogMessageType::Type type, const char *message) {
+	retro_log_level loglevel = RETRO_LOG_INFO;
+	switch (type) {
+		case LogMessageType::kDebug:
+			loglevel = RETRO_LOG_DEBUG;
+			break;
+		case LogMessageType::kWarning:
+			loglevel = RETRO_LOG_WARN;
+			break;
+		case LogMessageType::kError:
+			loglevel = RETRO_LOG_ERROR;
+			break;
+	}
+
+	if (log_cb)
+		log_cb(loglevel, "%s\n", message);
+}
+
+
+bool OSystem_libretro::parseGameName(const Common::String &gameName, Common::String &engineId,
+				   Common::String &gameId) {
+	Common::StringTokenizer tokenizer(gameName, ":");
+	Common::String token1, token2;
+
+	if (!tokenizer.empty()) {
+		token1 = tokenizer.nextToken();
+	}
+
+	if (!tokenizer.empty()) {
+		token2 = tokenizer.nextToken();
+	}
+
+	if (!tokenizer.empty()) {
+		return false; // Stray colon
+	}
+
+	if (!token1.empty() && !token2.empty()) {
+		engineId = token1;
+		gameId = token2;
+		return true;
+	} else if (!token1.empty()) {
+		engineId.clear();
+		gameId = token1;
+		return true;
+	}
+
+	return false;
+}
+
+int OSystem_libretro::testGame(const char *filedata, bool autodetect) {
+	Common::String game_id;
+	Common::String engine_id;
+	Common::String data = filedata;
+	int res = TEST_GAME_KO_NOT_FOUND;
+
+	PluginManager::instance().init();
+	PluginManager::instance().loadAllPlugins();
+	PluginManager::instance().loadDetectionPlugin();
+
+	if (autodetect) {
+		Common::FSNode dir(data);
+		Common::FSList files;
+		dir.getChildren(files, Common::FSNode::kListAll);
+
+		DetectionResults detectionResults = EngineMan.detectGames(files);
+		if (!detectionResults.listRecognizedGames().empty()) {
+			res = TEST_GAME_OK_ID_AUTODETECTED;
+		}
+
+	} else {
+
+		ConfMan.loadDefaultConfigFile(getDefaultConfigFileName().c_str());
+		if (ConfMan.hasGameDomain(data)) {
+			res = TEST_GAME_OK_TARGET_FOUND;
+		} else {
+			parseGameName(data, engine_id, game_id);
+
+			QualifiedGameList games = EngineMan.findGamesMatching(engine_id, game_id);
+			if (games.size() == 1) {
+				res = TEST_GAME_OK_ID_FOUND;
+			} else if (games.size() > 1) {
+				res = TEST_GAME_KO_MULTIPLE_RESULTS;
+			}
+		}
+	}
+
+	PluginManager::instance().unloadDetectionPlugin();
+	PluginManager::instance().unloadAllPlugins();
+	PluginManager::destroy();
+	return res;
+}
diff --git a/backends/platform/libretro/src/libretro-os.cpp b/backends/platform/libretro/src/libretro-os.cpp
deleted file mode 100644
index adba7202528..00000000000
--- a/backends/platform/libretro/src/libretro-os.cpp
+++ /dev/null
@@ -1,1360 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#define FORBIDDEN_SYMBOL_ALLOW_ALL
-
-#include <sys/time.h>
-#include <unistd.h>
-
-#include <libretro.h>
-#include <retro_inline.h>
-#include <retro_miscellaneous.h>
-#include <features/features_cpu.h>
-
-#include "audio/mixer_intern.h"
-#include "backends/base-backend.h"
-#include "base/commandLine.h"
-#include "common/config-manager.h"
-#include "common/events.h"
-#include "common/tokenizer.h"
-#include "common/list.h"
-
-#if defined(_WIN32)
-#include "backends/fs/windows/windows-fs-factory.h"
-#define FS_SYSTEM_FACTORY WindowsFilesystemFactory
-#else
-#include "backends/platform/libretro/include/libretro-fs-factory.h"
-#define FS_SYSTEM_FACTORY LibRetroFilesystemFactory
-#endif
-
-#include "backends/saves/default/default-saves.h"
-#include "backends/platform/libretro/include/libretro-timer.h"
-#include "graphics/colormasks.h"
-#include "graphics/palette.h"
-#include "graphics/surface.h"
-#if defined(_WIN32)
-#include <direct.h>
-#ifdef _XBOX
-#include <xtl.h>
-#else
-#include <windows.h>
-#endif
-#elif defined(__CELLOS_LV2__)
-#include <sys/sys_time.h>
-#elif (defined(GEKKO) && !defined(WIIU))
-#include <ogc/lwp_watchdog.h>
-#else
-#include <time.h>
-#endif
-
-#include "backends/platform/libretro/include/libretro-threads.h"
-#include "backends/platform/libretro/include/os.h"
-
-extern retro_log_printf_t log_cb;
-
-extern bool timing_inaccuracies_is_enabled(void);
-extern bool consecutive_screen_updates_is_enabled(void);
-extern void reset_performance_tuner(void);
-extern void retro_osd_notification(const char* msg);
-extern float frame_rate;
-extern const char * retro_get_system_dir(void);
-extern const char * retro_get_save_dir(void);
-
-#include "common/mutex.h"
-
-/**
- *  Dummy mutex implementation
- */
-class LibretroMutexInternal final : public Common::MutexInternal {
-public:
-	LibretroMutexInternal() {};
-	~LibretroMutexInternal() override {};
-
-	bool lock() override {
-		return 0;
-	}
-	bool unlock() override {
-		return 0;
-	};
-};
-
-Common::MutexInternal *createLibretroMutexInternal() {
-	return new LibretroMutexInternal();
-}
-
-struct RetroPalette {
-	unsigned char _colors[256 * 3];
-
-	RetroPalette() {
-		memset(_colors, 0, sizeof(_colors));
-	}
-
-	void set(const byte *colors, uint start, uint num) {
-		memcpy(_colors + start * 3, colors, num * 3);
-	}
-
-	void get(byte *colors, uint start, uint num) const {
-		memcpy(colors, _colors + start * 3, num * 3);
-	}
-
-	unsigned char *getColor(uint aIndex) const {
-		return (unsigned char *)&_colors[aIndex * 3];
-	}
-};
-
-static INLINE void blit_uint8_uint16_fast(Graphics::Surface &aOut, const Graphics::Surface &aIn, const RetroPalette &aColors) {
-	for (int i = 0; i < aIn.h; i++) {
-		if (i >= aOut.h)
-			continue;
-
-		uint8_t *const in = (uint8_t *)aIn.getPixels() + (i * aIn.w);
-		uint16_t *const out = (uint16_t *)aOut.getPixels() + (i * aOut.w);
-
-		for (int j = 0; j < aIn.w; j++) {
-			if (j >= aOut.w)
-				continue;
-
-			uint8 r, g, b;
-
-			const uint8_t val = in[j];
-			// if(val != 0xFFFFFFFF)
-			{
-				if (aIn.format.bytesPerPixel == 1) {
-					unsigned char *col = aColors.getColor(val);
-					r = *col++;
-					g = *col++;
-					b = *col++;
-				} else
-					aIn.format.colorToRGB(in[j], r, g, b);
-
-				out[j] = aOut.format.RGBToColor(r, g, b);
-			}
-		}
-	}
-}
-
-static INLINE void blit_uint32_uint16(Graphics::Surface &aOut, const Graphics::Surface &aIn, const RetroPalette &aColors) {
-	for (int i = 0; i < aIn.h; i++) {
-		if (i >= aOut.h)
-			continue;
-
-		uint32_t *const in = (uint32_t *)aIn.getPixels() + (i * aIn.w);
-		uint16_t *const out = (uint16_t *)aOut.getPixels() + (i * aOut.w);
-
-		for (int j = 0; j < aIn.w; j++) {
-			if (j >= aOut.w)
-				continue;
-
-			uint8 r, g, b;
-
-			// const uint32_t val = in[j];
-			// if(val != 0xFFFFFFFF)
-			{
-				aIn.format.colorToRGB(in[j], r, g, b);
-				out[j] = aOut.format.RGBToColor(r, g, b);
-			}
-		}
-	}
-}
-
-static INLINE void blit_uint16_uint16(Graphics::Surface &aOut, const Graphics::Surface &aIn, const RetroPalette &aColors) {
-	for (int i = 0; i < aIn.h; i++) {
-		if (i >= aOut.h)
-			continue;
-
-		uint16_t *const in = (uint16_t *)aIn.getPixels() + (i * aIn.w);
-		uint16_t *const out = (uint16_t *)aOut.getPixels() + (i * aOut.w);
-
-		for (int j = 0; j < aIn.w; j++) {
-			if (j >= aOut.w)
-				continue;
-
-			uint8 r, g, b;
-
-			// const uint16_t val = in[j];
-			// if(val != 0xFFFFFFFF)
-			{
-				aIn.format.colorToRGB(in[j], r, g, b);
-				out[j] = aOut.format.RGBToColor(r, g, b);
-			}
-		}
-	}
-}
-
-static void blit_uint8_uint16(Graphics::Surface &aOut, const Graphics::Surface &aIn, int aX, int aY, const RetroPalette &aColors, uint32 aKeyColor) {
-	for (int i = 0; i < aIn.h; i++) {
-		if ((i + aY) < 0 || (i + aY) >= aOut.h)
-			continue;
-
-		uint8_t *const in = (uint8_t *)aIn.getPixels() + (i * aIn.w);
-		uint16_t *const out = (uint16_t *)aOut.getPixels() + ((i + aY) * aOut.w);
-
-		for (int j = 0; j < aIn.w; j++) {
-			if ((j + aX) < 0 || (j + aX) >= aOut.w)
-				continue;
-
-			uint8 r, g, b;
-
-			const uint8_t val = in[j];
-			if (val != aKeyColor) {
-				unsigned char *col = aColors.getColor(val);
-				r = *col++;
-				g = *col++;
-				b = *col++;
-				out[j + aX] = aOut.format.RGBToColor(r, g, b);
-			}
-		}
-	}
-}
-
-static void blit_uint16_uint16(Graphics::Surface &aOut, const Graphics::Surface &aIn, int aX, int aY, const RetroPalette &aColors, uint32 aKeyColor) {
-	for (int i = 0; i < aIn.h; i++) {
-		if ((i + aY) < 0 || (i + aY) >= aOut.h)
-			continue;
-
-		uint16_t *const in = (uint16_t *)aIn.getPixels() + (i * aIn.w);
-		uint16_t *const out = (uint16_t *)aOut.getPixels() + ((i + aY) * aOut.w);
-
-		for (int j = 0; j < aIn.w; j++) {
-			if ((j + aX) < 0 || (j + aX) >= aOut.w)
-				continue;
-
-			uint8 r, g, b;
-
-			const uint16_t val = in[j];
-			if (val != aKeyColor) {
-				aIn.format.colorToRGB(in[j], r, g, b);
-				out[j + aX] = aOut.format.RGBToColor(r, g, b);
-			}
-		}
-	}
-}
-
-static void blit_uint32_uint16(Graphics::Surface &aOut, const Graphics::Surface &aIn, int aX, int aY, const RetroPalette &aColors, uint32 aKeyColor) {
-	for (int i = 0; i < aIn.h; i++) {
-		if ((i + aY) < 0 || (i + aY) >= aOut.h)
-			continue;
-
-		uint32_t *const in = (uint32_t *)aIn.getPixels() + (i * aIn.w);
-		uint16_t *const out = (uint16_t *)aOut.getPixels() + ((i + aY) * aOut.w);
-
-		for (int j = 0; j < aIn.w; j++) {
-			if ((j + aX) < 0 || (j + aX) >= aOut.w)
-				continue;
-
-			uint8 in_a, in_r, in_g, in_b;
-			uint8 out_r, out_g, out_b;
-			uint32_t blend_r, blend_g, blend_b;
-
-			const uint32_t val = in[j];
-			if (val != aKeyColor) {
-				aIn.format.colorToARGB(in[j], in_a, in_r, in_g, in_b);
-
-				if (in_a) {
-					aOut.format.colorToRGB(out[j + aX], out_r, out_g, out_b);
-
-					blend_r = ((in_r * in_a) + (out_r * (255 - in_a))) / 255;
-					blend_g = ((in_g * in_a) + (out_g * (255 - in_a))) / 255;
-					blend_b = ((in_b * in_a) + (out_b * (255 - in_a))) / 255;
-
-					out[j + aX] = aOut.format.RGBToColor(blend_r, blend_g, blend_b);
-				}
-			}
-		}
-	}
-}
-
-static INLINE void copyRectToSurface(uint8_t *pixels, int out_pitch, const uint8_t *src, int pitch, int x, int y, int w, int h, int out_bpp) {
-	uint8_t *dst = pixels + y * out_pitch + x * out_bpp;
-
-	do {
-		memcpy(dst, src, w * out_bpp);
-		src += pitch;
-		dst += out_pitch;
-	} while (--h);
-}
-
-static Common::String s_systemDir;
-static Common::String s_saveDir;
-static Common::String s_extraDir;
-static Common::String s_themeDir;
-static Common::String s_lastDir;
-
-#ifdef FRONTEND_SUPPORTS_RGB565
-#define SURF_BPP 2
-#define SURF_RBITS 2
-#define SURF_GBITS 5
-#define SURF_BBITS 6
-#define SURF_ABITS 5
-#define SURF_ALOSS (8 - SURF_ABITS)
-#define SURF_RLOSS (8 - SURF_RBITS)
-#define SURF_GLOSS (8 - SURF_GBITS)
-#define SURF_BLOSS (8 - SURF_BBITS)
-#define SURF_RSHIFT 0
-#define SURF_GSHIFT 11
-#define SURF_BSHIFT 5
-#define SURF_ASHIFT 0
-#else
-#define SURF_BPP 2
-#define SURF_RBITS 5
-#define SURF_GBITS 5
-#define SURF_BBITS 5
-#define SURF_ABITS 1
-#define SURF_ALOSS (8 - SURF_ABITS)
-#define SURF_RLOSS (8 - SURF_RBITS)
-#define SURF_GLOSS (8 - SURF_GBITS)
-#define SURF_BLOSS (8 - SURF_BBITS)
-#define SURF_RSHIFT 10
-#define SURF_GSHIFT 5
-#define SURF_BSHIFT 0
-#define SURF_ASHIFT 15
-#endif
-
-Common::List<Common::Event> _events;
-
-class OSystem_RETRO : public EventsBaseBackend, public PaletteManager {
-public:
-	Graphics::Surface _screen;
-
-	Graphics::Surface _gameScreen;
-	RetroPalette _gamePalette;
-
-	Graphics::Surface _overlay;
-	bool _overlayVisible;
-	bool _overlayInGUI;
-
-	Graphics::Surface _mouseImage;
-	RetroPalette _mousePalette;
-	bool _mousePaletteEnabled;
-	bool _mouseVisible;
-	int _mouseX;
-	int _mouseY;
-	int _relMouseX;
-	int _relMouseY;
-	float _mouseXAcc;
-	float _mouseYAcc;
-	float _dpadXAcc;
-	float _dpadYAcc;
-	float _dpadXVel;
-	float _dpadYVel;
-	int _mouseHotspotX;
-	int _mouseHotspotY;
-	int _mouseKeyColor;
-	bool _mouseDontScale;
-	bool _mouseButtons[2];
-	bool _joypadmouseButtons[2];
-	bool _joypadkeyboardButtons[8];
-	unsigned _joypadnumpadLast;
-	bool _joypadnumpadActive;
-	bool _ptrmouseButton;
-
-	uint32 _startTime;
-	uint8 _threadSwitchCaller;
-
-	Audio::MixerImpl *_mixer;
-
-	OSystem_RETRO() : _mousePaletteEnabled(false), _mouseVisible(false), _mouseX(0), _mouseY(0), _mouseXAcc(0.0), _mouseYAcc(0.0), _mouseHotspotX(0), _mouseHotspotY(0), _dpadXAcc(0.0), _dpadYAcc(0.0), _dpadXVel(0.0f), _dpadYVel(0.0f), _mouseKeyColor(0), _mouseDontScale(false), _joypadnumpadLast(8), _joypadnumpadActive(false), _mixer(0), _startTime(0), _threadSwitchCaller(0) {
-		_fsFactory = new FS_SYSTEM_FACTORY();
-		memset(_mouseButtons, 0, sizeof(_mouseButtons));
-		memset(_joypadmouseButtons, 0, sizeof(_joypadmouseButtons));
-		memset(_joypadkeyboardButtons, 0, sizeof(_joypadkeyboardButtons));
-
-		s_systemDir = Common::String(retro_get_system_dir());
-		s_saveDir = Common::String(retro_get_save_dir());
-		s_themeDir = s_systemDir + "/" + SCUMMVM_SYSTEM_SUBDIR + "/" + SCUMMVM_THEME_SUBDIR;
-		s_extraDir = s_systemDir + "/" + SCUMMVM_SYSTEM_SUBDIR + "/" + SCUMMVM_EXTRA_SUBDIR;
-		s_lastDir = s_systemDir;
-
-		_startTime = getMillis();
-	}
-
-	virtual ~OSystem_RETRO() {
-		_gameScreen.free();
-		_overlay.free();
-		_mouseImage.free();
-		_screen.free();
-
-		delete _mixer;
-	}
-
-	virtual void initBackend() {
-
-		_savefileManager = new DefaultSaveFileManager(s_saveDir);
-
-		if (! ConfMan.hasKey("themepath")) {
-			if (! Common::FSNode(s_themeDir).exists())
-				retro_osd_notification("ScummVM theme folder not found.");
-			else
-				ConfMan.set("themepath", s_themeDir);
-		}
-
-		if (! ConfMan.hasKey("extrapath")) {
-			if (! Common::FSNode(s_extraDir).exists())
-				retro_osd_notification("ScummVM datafiles folder not found. Some engines/features will not work.");
-			else
-				ConfMan.set("extrapath", s_extraDir);
-		}
-
-		if (! ConfMan.hasKey("browser_lastpath"))
-			ConfMan.set("browser_lastpath", s_lastDir);
-
-#ifdef FRONTEND_SUPPORTS_RGB565
-		_overlay.create(RES_W_OVERLAY, RES_H_OVERLAY, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
-#else
-		_overlay.create(RES_W_OVERLAY, RES_H_OVERLAY, Graphics::PixelFormat(2, 5, 5, 5, 1, 10, 5, 0, 15));
-#endif
-		_mixer = new Audio::MixerImpl(SAMPLE_RATE);
-
-		_timerManager = new LibretroTimerManager(frame_rate);
-
-		_mixer->setReady(true);
-
-		EventsBaseBackend::initBackend();
-	}
-
-	virtual void engineInit() {
-		Common::String engineId = ConfMan.get("engineid");
-		if (engineId.equalsIgnoreCase("scumm") && ConfMan.getBool("original_gui")) {
-			ConfMan.setBool("original_gui", false);
-			log_cb(RETRO_LOG_INFO, "\"original_gui\" setting forced to false\n");
-		}
-	}
-
-	virtual void engineDone() {
-		reset_performance_tuner();
-	}
-
-	virtual bool hasFeature(Feature f) {
-		return (f == OSystem::kFeatureCursorPalette);
-	}
-
-	virtual void setFeatureState(Feature f, bool enable) {
-		if (f == kFeatureCursorPalette)
-			_mousePaletteEnabled = enable;
-	}
-
-	virtual bool getFeatureState(Feature f) {
-		return (f == kFeatureCursorPalette) ? _mousePaletteEnabled : false;
-	}
-
-	virtual const GraphicsMode *getSupportedGraphicsModes() const {
-		static const OSystem::GraphicsMode s_noGraphicsModes[] = {{0, 0, 0}};
-		return s_noGraphicsModes;
-	}
-
-	virtual int getDefaultGraphicsMode() const {
-		return 0;
-	}
-
-	virtual bool isOverlayVisible() const {
-		return false;
-	}
-
-	virtual bool setGraphicsMode(int mode) {
-		return true;
-	}
-
-	virtual int getGraphicsMode() const {
-		return 0;
-	}
-
-	virtual void initSize(uint width, uint height, const Graphics::PixelFormat *format) {
-		_gameScreen.create(width, height, format ? *format : Graphics::PixelFormat::createFormatCLUT8());
-	}
-
-	virtual int16 getHeight() {
-		return _gameScreen.h;
-	}
-
-	virtual int16 getWidth() {
-		return _gameScreen.w;
-	}
-
-	virtual Graphics::PixelFormat getScreenFormat() const {
-		return _gameScreen.format;
-	}
-
-	virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const {
-		Common::List<Graphics::PixelFormat> result;
-
-#ifdef SCUMM_LITTLE_ENDIAN
-		/* RGBA8888 */
-		result.push_back(Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0));
-#else
-		/* ABGR8888 */
-		result.push_back(Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24));
-#endif
-#ifdef FRONTEND_SUPPORTS_RGB565
-		/* RGB565 - overlay */
-		result.push_back(Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
-#endif
-		/* RGB555 - fmtowns */
-		result.push_back(Graphics::PixelFormat(2, 5, 5, 5, 1, 10, 5, 0, 15));
-
-		/* Palette - most games */
-		result.push_back(Graphics::PixelFormat::createFormatCLUT8());
-
-		return result;
-	}
-
-	virtual PaletteManager *getPaletteManager() {
-		return this;
-	}
-
-protected:
-	// PaletteManager API
-	virtual void setPalette(const byte *colors, uint start, uint num) {
-		_gamePalette.set(colors, start, num);
-	}
-
-	virtual void grabPalette(byte *colors, uint start, uint num) const {
-		_gamePalette.get(colors, start, num);
-	}
-
-public:
-	virtual void copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h) {
-		const uint8_t *src = (const uint8_t *)buf;
-		uint8_t *pix = (uint8_t *)_gameScreen.getPixels();
-		copyRectToSurface(pix, _gameScreen.pitch, src, pitch, x, y, w, h, _gameScreen.format.bytesPerPixel);
-	}
-
-	virtual void updateScreen() {
-		const Graphics::Surface &srcSurface = (_overlayInGUI) ? _overlay : _gameScreen;
-		if (srcSurface.w && srcSurface.h) {
-			switch (srcSurface.format.bytesPerPixel) {
-			case 1:
-			case 3:
-				blit_uint8_uint16_fast(_screen, srcSurface, _gamePalette);
-				break;
-			case 2:
-				blit_uint16_uint16(_screen, srcSurface, _gamePalette);
-				break;
-			case 4:
-				blit_uint32_uint16(_screen, srcSurface, _gamePalette);
-				break;
-			}
-		}
-
-		// Draw Mouse
-		if (_mouseVisible && _mouseImage.w && _mouseImage.h) {
-			const int x = _mouseX - _mouseHotspotX;
-			const int y = _mouseY - _mouseHotspotY;
-
-			switch (_mouseImage.format.bytesPerPixel) {
-			case 1:
-			case 3:
-				blit_uint8_uint16(_screen, _mouseImage, x, y, _mousePaletteEnabled ? _mousePalette : _gamePalette, _mouseKeyColor);
-				break;
-			case 2:
-				blit_uint16_uint16(_screen, _mouseImage, x, y, _mousePaletteEnabled ? _mousePalette : _gamePalette, _mouseKeyColor);
-				break;
-			case 4:
-				blit_uint32_uint16(_screen, _mouseImage, x, y, _mousePaletteEnabled ? _mousePalette : _gamePalette, _mouseKeyColor);
-				break;
-			}
-		}
-
-		/* Switch directly to main thread in case of consecutive updateScreen, to avoid losing frames.
-		Non consecutive updateScreen are covered by thread switches triggered by pollEvent or delayMillis. */
-		if (! timing_inaccuracies_is_enabled() && consecutive_screen_updates_is_enabled()) {
-			if (_threadSwitchCaller & THREAD_SWITCH_UPDATE) {
-				((LibretroTimerManager *)_timerManager)->switchThread();
-			} else {
-				_threadSwitchCaller = THREAD_SWITCH_UPDATE;
-			}
-		}
-	}
-
-	virtual Graphics::Surface *lockScreen() {
-		return &_gameScreen;
-	}
-
-	virtual void unlockScreen() { /* EMPTY */ }
-
-	virtual void setShakePos(int shakeXOffset, int shakeYOffset) {
-		// TODO
-	}
-
-	virtual void showOverlay(bool inGUI) {
-		_overlayVisible = true;
-		_overlayInGUI = inGUI;
-	}
-
-	virtual void hideOverlay() {
-		_overlayVisible = false;
-		_overlayInGUI = false;
-	}
-
-	virtual void clearOverlay() {
-		_overlay.fillRect(Common::Rect(_overlay.w, _overlay.h), 0);
-	}
-
-	virtual void grabOverlay(Graphics::Surface &surface) {
-		const unsigned char *src = (unsigned char *)_overlay.getPixels();
-		unsigned char *dst = (byte *)surface.getPixels();
-		;
-		unsigned i = RES_H_OVERLAY;
-
-		do {
-			memcpy(dst, src, RES_W_OVERLAY << 1);
-			dst += surface.pitch;
-			src += RES_W_OVERLAY << 1;
-		} while (--i);
-	}
-
-	virtual void copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h) {
-		const uint8_t *src = (const uint8_t *)buf;
-		uint8_t *pix = (uint8_t *)_overlay.getPixels();
-		copyRectToSurface(pix, _overlay.pitch, src, pitch, x, y, w, h, _overlay.format.bytesPerPixel);
-	}
-
-	virtual int16 getOverlayHeight() {
-		return _overlay.h;
-	}
-
-	virtual int16 getOverlayWidth() {
-		return _overlay.w;
-	}
-
-	virtual Graphics::PixelFormat getOverlayFormat() const {
-		return _overlay.format;
-	}
-
-	virtual bool showMouse(bool visible) {
-		const bool wasVisible = _mouseVisible;
-		_mouseVisible = visible;
-		return wasVisible;
-	}
-
-	virtual void warpMouse(int x, int y) {
-		_mouseX = x;
-		_mouseY = y;
-	}
-
-	virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor = 255, bool dontScale = false, const Graphics::PixelFormat *format = NULL, const byte *mask = nullptr) {
-		const Graphics::PixelFormat mformat = format ? *format : Graphics::PixelFormat::createFormatCLUT8();
-
-		if (_mouseImage.w != w || _mouseImage.h != h || _mouseImage.format != mformat) {
-			_mouseImage.create(w, h, mformat);
-		}
-
-		memcpy(_mouseImage.getPixels(), buf, h * _mouseImage.pitch);
-
-		_mouseHotspotX = hotspotX;
-		_mouseHotspotY = hotspotY;
-		_mouseKeyColor = keycolor;
-		_mouseDontScale = dontScale;
-	}
-
-	virtual void setCursorPalette(const byte *colors, uint start, uint num) {
-		_mousePalette.set(colors, start, num);
-		_mousePaletteEnabled = true;
-	}
-
-	uint8 getThreadSwitchCaller(){
-		return _threadSwitchCaller;
-	}
-
-	virtual bool pollEvent(Common::Event &event) {
-		_threadSwitchCaller = THREAD_SWITCH_POLL;
-		((LibretroTimerManager *)_timerManager)->checkThread();
-		((LibretroTimerManager *)_timerManager)->handler();
-		if (!_events.empty()) {
-			event = _events.front();
-			_events.pop_front();
-			return true;
-		}
-
-		return false;
-	}
-
-	virtual uint32 getMillis(bool skipRecord = false) {
-#if (defined(GEKKO) && !defined(WIIU))
-		return (ticks_to_microsecs(gettime()) / 1000.0) - _startTime;
-#elif defined(WIIU)
-		return ((cpu_features_get_time_usec()) / 1000) - _startTime;
-#elif defined(__CELLOS_LV2__)
-		return (sys_time_get_system_time() / 1000.0) - _startTime;
-#else
-		struct timeval t;
-		gettimeofday(&t, 0);
-
-		return ((t.tv_sec * 1000) + (t.tv_usec / 1000)) - _startTime;
-#endif
-	}
-
-	virtual void delayMillis(uint msecs) {
-		uint32 start_time = getMillis();
-		uint32 elapsed_time = 0;
-
-		_threadSwitchCaller = THREAD_SWITCH_DELAY;
-
-		if (timing_inaccuracies_is_enabled()) {
-			while (elapsed_time < msecs) {
-				/* When remaining delay would take us past the next thread switch time, we switch immediately
-				in order to burn as much as possible delay time in the main RetroArch thread as soon as possible. */
-				if (msecs - elapsed_time >= ((LibretroTimerManager *)_timerManager)->timeToNextSwitch())
-					((LibretroTimerManager *)_timerManager)->switchThread();
-				else
-					usleep(1000);
-
-				/* Actual delay provided will be lower than requested: elapsed time is calculated cumulatively.
-				i.e. the higher the requested delay, the higher the actual delay reduction */
-				elapsed_time += getMillis() - start_time;
-			}
-		} else {
-			while (elapsed_time < msecs) {
-				/* if remaining delay is lower than last amount of time spent on main thread, burn it in emu thread
-				to avoid exceeding requested delay */
-				if (msecs - elapsed_time >= ((LibretroTimerManager *)_timerManager)->spentOnMainThread() && !((LibretroTimerManager *)_timerManager)->timeToNextSwitch())
-					((LibretroTimerManager *)_timerManager)->switchThread();
-				else
-					usleep(1000);
-				elapsed_time = getMillis() - start_time;
-			}
-		}
-
-		((LibretroTimerManager *)_timerManager)->handler();
-	}
-
-	virtual Common::MutexInternal *createMutex(void) {
-		return createLibretroMutexInternal();
-	}
-
-	virtual void quit() {
-		// TODO:
-	}
-
-	virtual void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0) {
-		// TODO: NOTHING?
-	}
-
-	virtual void getTimeAndDate(TimeDate &t, bool skipRecord) const {
-		time_t curTime = time(NULL);
-
-#define YEAR0 1900
-#define EPOCH_YR 1970
-#define SECS_DAY (24L * 60L * 60L)
-#define LEAPYEAR(year) (!((year) % 4) && (((year) % 100) || !((year) % 400)))
-#define YEARSIZE(year) (LEAPYEAR(year) ? 366 : 365)
-		const int _ytab[2][12] = {{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
-		int year = EPOCH_YR;
-		unsigned long dayclock = (unsigned long)curTime % SECS_DAY;
-		unsigned long dayno = (unsigned long)curTime / SECS_DAY;
-		t.tm_sec = dayclock % 60;
-		t.tm_min = (dayclock % 3600) / 60;
-		t.tm_hour = dayclock / 3600;
-		t.tm_wday = (dayno + 4) % 7; /* day 0 was a thursday */
-		while (dayno >= YEARSIZE(year)) {
-			dayno -= YEARSIZE(year);
-			year++;
-		}
-		t.tm_year = year - YEAR0;
-		t.tm_mon = 0;
-		while (dayno >= _ytab[LEAPYEAR(year)][t.tm_mon]) {
-			dayno -= _ytab[LEAPYEAR(year)][t.tm_mon];
-			t.tm_mon++;
-		}
-		t.tm_mday = dayno + 1;
-	}
-
-	virtual Audio::Mixer *getMixer() {
-		return _mixer;
-	}
-
-	virtual Common::String getDefaultConfigFileName() {
-		return s_systemDir + "/scummvm.ini";
-	}
-
-	virtual void logMessage(LogMessageType::Type type, const char *message) {
-		retro_log_level loglevel = RETRO_LOG_INFO;
-		switch (type) {
-			case LogMessageType::kDebug:
-				loglevel = RETRO_LOG_DEBUG;
-				break;
-			case LogMessageType::kWarning:
-				loglevel = RETRO_LOG_WARN;
-				break;
-			case LogMessageType::kError:
-				loglevel = RETRO_LOG_ERROR;
-				break;
-		}
-
-		if (log_cb)
-			log_cb(loglevel, "%s\n", message);
-	}
-
-	const Graphics::Surface &getScreen() {
-		const Graphics::Surface &srcSurface = (_overlayInGUI) ? _overlay : _gameScreen;
-
-		if (srcSurface.w != _screen.w || srcSurface.h != _screen.h) {
-#ifdef FRONTEND_SUPPORTS_RGB565
-			_screen.create(srcSurface.w, srcSurface.h, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
-#else
-			_screen.create(srcSurface.w, srcSurface.h, Graphics::PixelFormat(2, 5, 5, 5, 1, 10, 5, 0, 15));
-#endif
-		}
-
-		return _screen;
-	}
-
-#define ANALOG_RANGE 0x8000
-#define BASE_CURSOR_SPEED 4
-#define PI 3.141592653589793238
-
-	void updateMouseXY(float deltaAcc, float * cumulativeXYAcc, int doing_x){
-		int * mouseXY;
-		int16 * screen_wh;
-		int * relMouseXY;
-		int cumulativeXYAcc_int;
-		if (doing_x) {
-			mouseXY = &_mouseX;
-			screen_wh = &_screen.w;
-			relMouseXY = &_relMouseX;
-		} else {
-			mouseXY = &_mouseY;
-			screen_wh = &_screen.h;
-			relMouseXY = &_relMouseY;
-		}
-		*cumulativeXYAcc += deltaAcc;
-		cumulativeXYAcc_int = (int)*cumulativeXYAcc;
-		if (cumulativeXYAcc_int != 0) {
-			// Set mouse position
-			*mouseXY += cumulativeXYAcc_int;
-			*mouseXY = (*mouseXY < 0) ? 0 : *mouseXY;
-			*mouseXY = (*mouseXY >= *screen_wh) ? *screen_wh : *mouseXY;
-			// Update accumulator
-			*cumulativeXYAcc -= (float)cumulativeXYAcc_int;
-		}
-		*relMouseXY = (int)deltaAcc;
-	}
-
-	void processMouse(retro_input_state_t aCallback, int device, float gampad_cursor_speed, float gamepad_acceleration_time, bool analog_response_is_quadratic, int analog_deadzone, float mouse_speed) {
-		enum processMouse_status {
-			STATUS_DOING_JOYSTICK  = (1 << 0),
-			STATUS_DOING_MOUSE     = (1 << 1),
-			STATUS_DOING_X         = (1 << 2),
-			STATUS_DOING_Y         = (1 << 3)
-		};
-		uint8_t status = 0;
-		int16_t joy_x, joy_y, joy_rx, joy_ry, x, y;
-		float analog_amplitude_x, analog_amplitude_y;
-		float deltaAcc;
-		bool  down;
-		float screen_adjusted_cursor_speed = (float)_screen.w / 320.0f; // Dpad cursor speed should always be based off a 320 wide screen, to keep speeds consistent
-		float adjusted_cursor_speed = (float)BASE_CURSOR_SPEED * gampad_cursor_speed * screen_adjusted_cursor_speed;
-		float inverse_acceleration_time = (gamepad_acceleration_time > 0.0) ? (1.0 / 60.0) * (1.0 / gamepad_acceleration_time) : 1.0;
-		int dpad_cursor_offset;
-		double rs_radius, rs_angle;
-		unsigned numpad_index;
-
-		static const uint32_t retroButtons[2] = {RETRO_DEVICE_ID_MOUSE_LEFT, RETRO_DEVICE_ID_MOUSE_RIGHT};
-		static const Common::EventType eventID[2][2] = {{Common::EVENT_LBUTTONDOWN, Common::EVENT_LBUTTONUP}, {Common::EVENT_RBUTTONDOWN, Common::EVENT_RBUTTONUP}};
-
-		static const unsigned gampad_key_map[8][4] = {
-			{RETRO_DEVICE_ID_JOYPAD_X, (unsigned)Common::KEYCODE_ESCAPE, (unsigned)Common::ASCII_ESCAPE, 0},           // Esc
-			{RETRO_DEVICE_ID_JOYPAD_Y, (unsigned)Common::KEYCODE_PERIOD, 46, 0},                                       // .
-			{RETRO_DEVICE_ID_JOYPAD_L, (unsigned)Common::KEYCODE_RETURN, (unsigned)Common::ASCII_RETURN, 0},           // Enter
-			{RETRO_DEVICE_ID_JOYPAD_R, (unsigned)Common::KEYCODE_KP5, 53, 0},                                          // Numpad 5
-			{RETRO_DEVICE_ID_JOYPAD_L2, (unsigned)Common::KEYCODE_BACKSPACE, (unsigned)Common::ASCII_BACKSPACE, 0},    // Backspace
-			{RETRO_DEVICE_ID_JOYPAD_L3, (unsigned)Common::KEYCODE_F10, (unsigned)Common::ASCII_F10, 0},                // F10
-			{RETRO_DEVICE_ID_JOYPAD_R3, (unsigned)Common::KEYCODE_KP0, 48, 0},                                         // Numpad 0
-			{RETRO_DEVICE_ID_JOYPAD_SELECT, (unsigned)Common::KEYCODE_F7, (unsigned)Common::ASCII_F7, RETROKMOD_CTRL}, // CTRL+F7 (virtual keyboard)
-		};
-
-		// Right stick circular wrap around: 1 -> 2 -> 3 -> 6 -> 9 -> 8 -> 7 -> 4
-		static const unsigned gampad_numpad_map[8][2] = {
-			{(unsigned)Common::KEYCODE_KP1, 49},
-			{(unsigned)Common::KEYCODE_KP2, 50},
-			{(unsigned)Common::KEYCODE_KP3, 51},
-			{(unsigned)Common::KEYCODE_KP6, 54},
-			{(unsigned)Common::KEYCODE_KP9, 57},
-			{(unsigned)Common::KEYCODE_KP8, 56},
-			{(unsigned)Common::KEYCODE_KP7, 55},
-			{(unsigned)Common::KEYCODE_KP4, 52},
-		};
-
-		// Reduce gamepad cursor speed, if required
-		if (device == RETRO_DEVICE_JOYPAD && aCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2)) {
-			adjusted_cursor_speed = adjusted_cursor_speed * (1.0f / 5.0f);
-		}
-
-		status = 0;
-		x = aCallback(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_X);
-		y = aCallback(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_Y);
-		joy_x = aCallback(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X);
-		joy_y = aCallback(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y);
-
-		// Left Analog X Axis
-		if (joy_x > analog_deadzone || joy_x < -analog_deadzone) {
-			status |= (STATUS_DOING_JOYSTICK | STATUS_DOING_X);
-			if (joy_x > analog_deadzone) {
-				// Reset accumulator when changing direction
-				_mouseXAcc = (_mouseXAcc < 0.0) ? 0.0 : _mouseXAcc;
-				joy_x = joy_x - analog_deadzone;
-			}
-			if (joy_x < -analog_deadzone) {
-				// Reset accumulator when changing direction
-				_mouseXAcc = (_mouseXAcc > 0.0) ? 0.0 : _mouseXAcc;
-				joy_x = joy_x + analog_deadzone;
-			}
-			// Update accumulator
-			analog_amplitude_x = (float)joy_x / (float)(ANALOG_RANGE - analog_deadzone);
-			if (analog_response_is_quadratic) {
-				if (analog_amplitude_x < 0.0)
-					analog_amplitude_x = -(analog_amplitude_x * analog_amplitude_x);
-				else
-					analog_amplitude_x = analog_amplitude_x * analog_amplitude_x;
-			}
-			// printf("analog_amplitude_x: %f\n", analog_amplitude_x);
-			deltaAcc = analog_amplitude_x * adjusted_cursor_speed;
-			updateMouseXY(deltaAcc, &_mouseXAcc, 1);
-		}
-
-		// Left Analog Y Axis
-		if (joy_y > analog_deadzone || joy_y < -analog_deadzone) {
-			status |= (STATUS_DOING_JOYSTICK | STATUS_DOING_Y);
-			if (joy_y > analog_deadzone) {
-				// Reset accumulator when changing direction
-				_mouseYAcc = (_mouseYAcc < 0.0) ? 0.0 : _mouseYAcc;
-				joy_y = joy_y - analog_deadzone;
-			}
-			if (joy_y < -analog_deadzone) {
-				// Reset accumulator when changing direction
-				_mouseYAcc = (_mouseYAcc > 0.0) ? 0.0 : _mouseYAcc;
-				joy_y = joy_y + analog_deadzone;
-			}
-			// Update accumulator
-			analog_amplitude_y = (float)joy_y / (float)(ANALOG_RANGE - analog_deadzone);
-			if (analog_response_is_quadratic) {
-				if (analog_amplitude_y < 0.0)
-					analog_amplitude_y = -(analog_amplitude_y * analog_amplitude_y);
-				else
-					analog_amplitude_y = analog_amplitude_y * analog_amplitude_y;
-			}
-			// printf("analog_amplitude_y: %f\n", analog_amplitude_y);
-			deltaAcc = analog_amplitude_y * adjusted_cursor_speed;
-			updateMouseXY(deltaAcc, &_mouseYAcc, 0);
-		}
-
-		if (device == RETRO_DEVICE_JOYPAD) {
-			bool dpadLeft = aCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT);
-			bool dpadRight = aCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT);
-			bool dpadUp = aCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP);
-			bool dpadDown = aCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN);
-
-			if (dpadLeft || dpadRight) {
-				status |= (STATUS_DOING_JOYSTICK | STATUS_DOING_X);
-				_dpadXVel = MIN(_dpadXVel + inverse_acceleration_time, 1.0f);
-
-				if (dpadLeft) {
-					deltaAcc = -(_dpadXVel * adjusted_cursor_speed);
-					_dpadXAcc = _dpadXAcc < deltaAcc ? _dpadXAcc : 0.0f;
-				} else { //dpadRight
-					deltaAcc = _dpadXVel * adjusted_cursor_speed;
-					_dpadXAcc = _dpadXAcc > deltaAcc ? _dpadXAcc : 0.0f;
-				}
-
-				updateMouseXY(deltaAcc, &_dpadXAcc, 1);
-			} else {
-				_dpadXVel = 0.0f;
-			}
-
-
-			if (dpadUp || dpadDown) {
-				status |= (STATUS_DOING_JOYSTICK | STATUS_DOING_Y);
-				_dpadYVel = MIN(_dpadYVel + inverse_acceleration_time, 1.0f);
-
-				if (dpadUp) {
-					deltaAcc = -(_dpadYVel * adjusted_cursor_speed);
-					_dpadYAcc = _dpadYAcc < deltaAcc ? _dpadYAcc : 0.0f;
-				} else { //dpadDown
-					deltaAcc = _dpadYVel * adjusted_cursor_speed;
-					_dpadYAcc = _dpadYAcc > deltaAcc ? _dpadYAcc : 0.0f;
-				}
-
-				updateMouseXY(deltaAcc, &_dpadYAcc, 0);
-
-
-			} else {
-				_dpadYVel = 0.0f;
-			}
-
-			if (aCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START)) {
-				Common::Event ev;
-				ev.type = Common::EVENT_MAINMENU;
-				_events.push_back(ev);
-			}
-		}
-
-#if defined(WIIU) || defined(__SWITCH__)
-		int p_x = aCallback(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_X);
-		int p_y = aCallback(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_Y);
-		int p_press = aCallback(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_PRESSED);
-		int px = (int)((p_x + 0x7fff) * _screen.w / 0xffff);
-		int py = (int)((p_y + 0x7fff) * _screen.h / 0xffff);
-		// printf("(%d,%d) p:%d\n",px,py,pp);
-
-		static int ptrhold = 0;
-
-		if (p_press)
-			ptrhold++;
-		else
-			ptrhold = 0;
-
-		if (ptrhold > 0) {
-			_mouseX = px;
-			_mouseY = py;
-
-			Common::Event ev;
-			ev.type = Common::EVENT_MOUSEMOVE;
-			ev.mouse.x = _mouseX;
-			ev.mouse.y = _mouseY;
-			_events.push_back(ev);
-		}
-
-		if (ptrhold > 10 && _ptrmouseButton == 0) {
-			_ptrmouseButton = 1;
-			Common::Event ev;
-			ev.type = eventID[0][_ptrmouseButton ? 0 : 1];
-			ev.mouse.x = _mouseX;
-			ev.mouse.y = _mouseY;
-			_events.push_back(ev);
-		} else if (ptrhold == 0 && _ptrmouseButton == 1) {
-			_ptrmouseButton = 0;
-			Common::Event ev;
-			ev.type = eventID[0][_ptrmouseButton ? 0 : 1];
-			ev.mouse.x = _mouseX;
-			ev.mouse.y = _mouseY;
-			_events.push_back(ev);
-		}
-
-#endif
-
-		if (status & STATUS_DOING_JOYSTICK) {
-			Common::Event ev;
-			ev.type = Common::EVENT_MOUSEMOVE;
-			ev.mouse.x = _mouseX;
-			ev.mouse.y = _mouseY;
-			ev.relMouse.x = status & STATUS_DOING_X ? _relMouseX : 0;
-			ev.relMouse.y = status & STATUS_DOING_Y ? _relMouseY : 0;
-			_events.push_back(ev);
-		}
-
-		// Gampad mouse buttons
-		down = aCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A);
-		if (down != _joypadmouseButtons[0]) {
-			_joypadmouseButtons[0] = down;
-
-			Common::Event ev;
-			ev.type = eventID[0][down ? 0 : 1];
-			ev.mouse.x = _mouseX;
-			ev.mouse.y = _mouseY;
-			_events.push_back(ev);
-		}
-
-		down = aCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B);
-		if (down != _joypadmouseButtons[1]) {
-			_joypadmouseButtons[1] = down;
-
-			Common::Event ev;
-			ev.type = eventID[1][down ? 0 : 1];
-			ev.mouse.x = _mouseX;
-			ev.mouse.y = _mouseY;
-			_events.push_back(ev);
-		}
-
-		// Gamepad keyboard buttons
-		for (int i = 0; i < 8; i++) {
-			down = aCallback(0, RETRO_DEVICE_JOYPAD, 0, gampad_key_map[i][0]);
-			if (down != _joypadkeyboardButtons[i]) {
-				_joypadkeyboardButtons[i] = down;
-				bool state = down ? true : false;
-				processKeyEvent(state, gampad_key_map[i][1], (uint32_t)gampad_key_map[i][2], (uint32_t)gampad_key_map[i][3]);
-			}
-		}
-
-		// Gamepad right stick numpad emulation
-		joy_rx = aCallback(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X);
-		joy_ry = aCallback(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y);
-
-		if (joy_rx > analog_deadzone)
-			joy_rx = joy_rx - analog_deadzone;
-		else if (joy_rx < -analog_deadzone)
-			joy_rx = joy_rx + analog_deadzone;
-		else
-			joy_rx = 0;
-
-		if (joy_ry > analog_deadzone)
-			joy_ry = joy_ry - analog_deadzone;
-		else if (joy_ry < -analog_deadzone)
-			joy_ry = joy_ry + analog_deadzone;
-		else
-			joy_ry = 0;
-
-		// This is very ugly, but I don't have time to make it nicer...
-		if (joy_rx != 0 || joy_ry != 0) {
-			analog_amplitude_x = (float)joy_rx / (float)(ANALOG_RANGE - analog_deadzone);
-			analog_amplitude_y = (float)joy_ry / (float)(ANALOG_RANGE - analog_deadzone);
-
-			// Convert to polar coordinates: part 1
-			rs_radius = sqrt((double)(analog_amplitude_x * analog_amplitude_x) + (double)(analog_amplitude_y * analog_amplitude_y));
-
-			// Check if radius is above threshold
-			if (rs_radius > 0.5) {
-				// Convert to polar coordinates: part 2
-				rs_angle = atan2((double)analog_amplitude_y, (double)analog_amplitude_x);
-
-				// Adjust rotation offset...
-				rs_angle = (2.0 * PI) - (rs_angle + PI);
-				rs_angle = fmod(rs_angle - (0.125 * PI), 2.0 * PI);
-				if (rs_angle < 0)
-					rs_angle += 2.0 * PI;
-
-				// Convert angle into numpad key index
-				numpad_index = (unsigned)((rs_angle / (2.0 * PI)) * 8.0);
-				// Unnecessary safety check...
-				numpad_index = (numpad_index > 7) ? 7 : numpad_index;
-				// printf("numpad_index: %u\n", numpad_index);
-
-				if (numpad_index != _joypadnumpadLast) {
-					// Unset last key, if required
-					if (_joypadnumpadActive)
-						processKeyEvent(false, gampad_numpad_map[_joypadnumpadLast][0], (uint32_t)gampad_numpad_map[_joypadnumpadLast][1], 0);
-
-					// Set new key
-					processKeyEvent(true, gampad_numpad_map[numpad_index][0], (uint32_t)gampad_numpad_map[numpad_index][1], 0);
-
-					_joypadnumpadLast = numpad_index;
-					_joypadnumpadActive = true;
-				}
-			} else if (_joypadnumpadActive) {
-				processKeyEvent(false, gampad_numpad_map[_joypadnumpadLast][0], (uint32_t)gampad_numpad_map[_joypadnumpadLast][1], 0);
-				_joypadnumpadActive = false;
-				_joypadnumpadLast = 8;
-			}
-		} else if (_joypadnumpadActive) {
-			processKeyEvent(false, gampad_numpad_map[_joypadnumpadLast][0], (uint32_t)gampad_numpad_map[_joypadnumpadLast][1], 0);
-			_joypadnumpadActive = false;
-			_joypadnumpadLast = 8;
-		}
-
-		// Process input from physical mouse
-		// > X Axis
-		if (x != 0) {
-			status |= (STATUS_DOING_MOUSE | STATUS_DOING_X);
-			if (x > 0) {
-				// Reset accumulator when changing direction
-				_mouseXAcc = (_mouseXAcc < 0.0) ? 0.0 : _mouseXAcc;
-			}
-			if (x < 0) {
-				// Reset accumulator when changing direction
-				_mouseXAcc = (_mouseXAcc > 0.0) ? 0.0 : _mouseXAcc;
-			}
-			deltaAcc = (float)x * mouse_speed;
-			updateMouseXY(deltaAcc, &_mouseXAcc, 1);
-		}
-		// > Y Axis
-		if (y != 0) {
-			status |= (STATUS_DOING_MOUSE | STATUS_DOING_Y);
-			if (y > 0) {
-				// Reset accumulator when changing direction
-				_mouseYAcc = (_mouseYAcc < 0.0) ? 0.0 : _mouseYAcc;
-			}
-			if (y < 0) {
-				// Reset accumulator when changing direction
-				_mouseYAcc = (_mouseYAcc > 0.0) ? 0.0 : _mouseYAcc;
-			}
-			deltaAcc = (float)y * mouse_speed;
-			updateMouseXY(deltaAcc, &_mouseYAcc, 0);
-		}
-
-		if (status & STATUS_DOING_MOUSE) {
-			Common::Event ev;
-			ev.type = Common::EVENT_MOUSEMOVE;
-			ev.mouse.x = _mouseX;
-			ev.mouse.y = _mouseY;
-			ev.relMouse.x = status & STATUS_DOING_X ? _relMouseX : 0;
-			ev.relMouse.y = status & STATUS_DOING_Y ? _relMouseY : 0;
-			_events.push_back(ev);
-		}
-
-		for (int i = 0; i < 2; i++) {
-			Common::Event ev;
-			bool down = aCallback(0, RETRO_DEVICE_MOUSE, 0, retroButtons[i]);
-			if (down != _mouseButtons[i]) {
-				_mouseButtons[i] = down;
-
-				ev.type = eventID[i][down ? 0 : 1];
-				ev.mouse.x = _mouseX;
-				ev.mouse.y = _mouseY;
-				_events.push_back(ev);
-			}
-		}
-	}
-
-	void processKeyEvent(bool down, unsigned keycode, uint32_t character, uint16_t key_modifiers) {
-		int _keyflags = 0;
-		_keyflags |= (key_modifiers & RETROKMOD_CTRL) ? Common::KBD_CTRL : 0;
-		_keyflags |= (key_modifiers & RETROKMOD_ALT) ? Common::KBD_ALT : 0;
-		_keyflags |= (key_modifiers & RETROKMOD_SHIFT) ? Common::KBD_SHIFT : 0;
-		_keyflags |= (key_modifiers & RETROKMOD_META) ? Common::KBD_META : 0;
-		_keyflags |= (key_modifiers & RETROKMOD_CAPSLOCK) ? Common::KBD_CAPS : 0;
-		_keyflags |= (key_modifiers & RETROKMOD_NUMLOCK) ? Common::KBD_NUM : 0;
-		_keyflags |= (key_modifiers & RETROKMOD_SCROLLOCK) ? Common::KBD_SCRL : 0;
-
-		Common::Event ev;
-		ev.type = down ? Common::EVENT_KEYDOWN : Common::EVENT_KEYUP;
-		ev.kbd.keycode = (Common::KeyCode)keycode;
-		ev.kbd.flags = _keyflags;
-		ev.kbd.ascii = keycode;
-
-		/* If shift was down then send upper case letter to engine */
-		if (ev.kbd.ascii >= 97 && ev.kbd.ascii <= 122 && (_keyflags & Common::KBD_SHIFT))
-			ev.kbd.ascii = ev.kbd.ascii & ~0x20;
-
-		_events.push_back(ev);
-	}
-
-	bool parseGameName(const Common::String &gameName, Common::String &engineId,
-	                   Common::String &gameId) {
-		Common::StringTokenizer tokenizer(gameName, ":");
-		Common::String token1, token2;
-
-		if (!tokenizer.empty()) {
-			token1 = tokenizer.nextToken();
-		}
-
-		if (!tokenizer.empty()) {
-			token2 = tokenizer.nextToken();
-		}
-
-		if (!tokenizer.empty()) {
-			return false; // Stray colon
-		}
-
-		if (!token1.empty() && !token2.empty()) {
-			engineId = token1;
-			gameId = token2;
-			return true;
-		} else if (!token1.empty()) {
-			engineId.clear();
-			gameId = token1;
-			return true;
-		}
-
-		return false;
-	}
-
-	int TestGame(const char *filedata, bool autodetect) {
-		Common::String game_id;
-		Common::String engine_id;
-		Common::String data = filedata;
-		int res = TEST_GAME_KO_NOT_FOUND;
-
-		PluginManager::instance().init();
-		PluginManager::instance().loadAllPlugins();
-		PluginManager::instance().loadDetectionPlugin();
-
-		if (autodetect) {
-			Common::FSNode dir(data);
-			Common::FSList files;
-			dir.getChildren(files, Common::FSNode::kListAll);
-
-			DetectionResults detectionResults = EngineMan.detectGames(files);
-			if (!detectionResults.listRecognizedGames().empty()) {
-				res = TEST_GAME_OK_ID_AUTODETECTED;
-			}
-
-		} else {
-
-			ConfMan.loadDefaultConfigFile(getDefaultConfigFileName().c_str());
-			if (ConfMan.hasGameDomain(data)) {
-				res = TEST_GAME_OK_TARGET_FOUND;
-			} else {
-				parseGameName(data, engine_id, game_id);
-
-				QualifiedGameList games = EngineMan.findGamesMatching(engine_id, game_id);
-				if (games.size() == 1) {
-					res = TEST_GAME_OK_ID_FOUND;
-				} else if (games.size() > 1) {
-					res = TEST_GAME_KO_MULTIPLE_RESULTS;
-				}
-			}
-		}
-
-		PluginManager::instance().unloadDetectionPlugin();
-		PluginManager::instance().unloadAllPlugins();
-		PluginManager::destroy();
-		return res;
-	}
-
-	void Quit() {
-		Common::Event ev;
-		ev.type = Common::EVENT_QUIT;
-		dynamic_cast<OSystem_RETRO *>(g_system)->getEventManager()->pushEvent(ev);
-	}
-
-	void Reset() {
-		dynamic_cast<OSystem_RETRO *>(g_system)->getEventManager()->resetQuit();
-	}
-
-	void destroy() {
-		delete this;
-	}
-
-};
-
-OSystem *retroBuildOS() {
-	return new OSystem_RETRO();
-}
-
-const Graphics::Surface &getScreen() {
-	return dynamic_cast<OSystem_RETRO *>(g_system)->getScreen();
-}
-
-void retroProcessMouse(retro_input_state_t aCallback, int device, float gamepad_cursor_speed, float gamepad_acceleration_time, bool analog_response_is_quadratic, int analog_deadzone, float mouse_speed) {
-	dynamic_cast<OSystem_RETRO *>(g_system)->processMouse(aCallback, device, gamepad_cursor_speed, gamepad_acceleration_time, analog_response_is_quadratic, analog_deadzone, mouse_speed);
-}
-
-void retroQuit() {
-	dynamic_cast<OSystem_RETRO *>(g_system)->Quit();
-}
-
-int retroTestGame(const char *game_id, bool autodetect) {
-	return dynamic_cast<OSystem_RETRO *>(g_system)->TestGame(game_id, autodetect);
-}
-
-void retroKeyEvent(bool down, unsigned keycode, uint32_t character, uint16_t key_modifiers) {
-	dynamic_cast<OSystem_RETRO *>(g_system)->processKeyEvent(down, keycode, character, key_modifiers);
-}
-
-void retroReset() {
-	dynamic_cast<OSystem_RETRO *>(g_system)->Reset();
-}
-
-uint8 getThreadSwitchCaller(){
-	return dynamic_cast<OSystem_RETRO *>(g_system)->getThreadSwitchCaller();
-}
-
-void retroDestroy() {
-	dynamic_cast<OSystem_RETRO *>(g_system)->destroy();
-}
diff --git a/backends/platform/libretro/src/libretro-threads.cpp b/backends/platform/libretro/src/libretro-threads.cpp
index 3f9d56b91d0..436043c7c26 100644
--- a/backends/platform/libretro/src/libretro-threads.cpp
+++ b/backends/platform/libretro/src/libretro-threads.cpp
@@ -15,9 +15,9 @@
 */
 
 #include <stdio.h>
-#include "backends/platform/libretro/include/libretro-threads.h"
-#include "backends/platform/libretro/include/os.h"
+#include <libretro.h>
 #include "base/main.h"
+#include "backends/platform/libretro/include/libretro-threads.h"
 
 #define EMU_WAITING    (1 << 0)
 #define MAIN_WAITING   (1 << 1)
@@ -39,13 +39,8 @@ static scond_t *emu_cond;
 static scond_t *main_cond;
 #endif
 
-static bool retro_current_thread_is_main() {
-#ifdef USE_LIBCO
-	return (co_active() == main_thread);
-#else
-	return (sthread_get_current_thread_id() == main_thread_id);
-#endif
-}
+extern char cmd_params[20][200];
+extern char cmd_params_num;
 
 static void retro_exit_to_main_thread() {
 #ifdef USE_LIBCO
diff --git a/backends/platform/libretro/src/libretro-timer.cpp b/backends/platform/libretro/src/libretro-timer.cpp
index 5ac523d33cb..9e98c860666 100644
--- a/backends/platform/libretro/src/libretro-timer.cpp
+++ b/backends/platform/libretro/src/libretro-timer.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2022 Giovanni Cascione <ing.cascione at gmail.com>
+/* Copyright (C) 2023 Giovanni Cascione <ing.cascione at gmail.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -20,7 +20,7 @@
 #include "common/timer.h"
 #include "backends/platform/libretro/include/libretro-threads.h"
 #include "backends/platform/libretro/include/libretro-timer.h"
-#include "backends/platform/libretro/include/os.h"
+#include "backends/platform/libretro/include/libretro-defs.h"
 
 LibretroTimerManager::LibretroTimerManager(uint32 refresh_rate) {
 	if (! refresh_rate > 0)
diff --git a/backends/platform/libretro/src/libretro.cpp b/backends/platform/libretro/src/libretro.cpp
index f8f4070e5d7..5e5970df4a2 100644
--- a/backends/platform/libretro/src/libretro.cpp
+++ b/backends/platform/libretro/src/libretro.cpp
@@ -52,7 +52,8 @@
 
 #include "backends/platform/libretro/include/libretro-threads.h"
 #include "backends/platform/libretro/include/libretro-core-options.h"
-#include "backends/platform/libretro/include/os.h"
+#include "backends/platform/libretro/include/libretro-os.h"
+#include "backends/platform/libretro/include/libretro-defs.h"
 
 static struct retro_game_info game_buf;
 static struct retro_game_info * game_buf_ptr;
@@ -377,7 +378,7 @@ static void exit_to_frontend(void) {
 
 static void close_emu_thread(void) {
 	while (!retro_emu_thread_exited()) {
-		retroQuit();
+		LIBRETRO_G_SYSTEM->requestQuit();
 		retro_switch_to_emu_thread();
 	}
 	retro_deinit_emu_thread();
@@ -583,14 +584,14 @@ void retro_init(void) {
 		log_cb(RETRO_LOG_INFO, "Frontend supports RGB565 -will use that instead of XRGB1555.\n");
 #endif
 
-	retro_keyboard_callback cb = {retroKeyEvent};
+	retro_keyboard_callback cb = {LIBRETRO_G_SYSTEM->processKeyEvent};
 	environ_cb(RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK, &cb);
 
-	g_system = retroBuildOS();
+	g_system = new OSystem_libretro();
 }
 
 void retro_deinit(void) {
-	retroDestroy();
+	LIBRETRO_G_SYSTEM->destroy();
 	free(sound_buffer);
 }
 
@@ -665,7 +666,7 @@ bool retro_load_game(const struct retro_game_info *game) {
 				return false;
 			}
 
-			test_game_status = retroTestGame(target_id, false);
+			test_game_status = LIBRETRO_G_SYSTEM->testGame(target_id, false);
 		} else {
 			if (detect_target.isDirectory()) {
 				parent_dir = detect_target;
@@ -677,7 +678,7 @@ bool retro_load_game(const struct retro_game_info *game) {
 				}
 			}
 
-			test_game_status = retroTestGame(parent_dir.getPath().c_str(), true);
+			test_game_status = LIBRETRO_G_SYSTEM->testGame(parent_dir.getPath().c_str(), true);
 		}
 
 		// Preliminary game scan results
@@ -770,7 +771,7 @@ void retro_run(void) {
 			/* No frame skipping if
 			- no incoming audio (e.g. GUI)
 			- doing a THREAD_SWITCH_UPDATE loop */
-			skip_frame = skip_frame && !(audio_status & AUDIO_STATUS_MUTE) && !(getThreadSwitchCaller() & THREAD_SWITCH_UPDATE);
+			skip_frame = skip_frame && !(audio_status & AUDIO_STATUS_MUTE) && !(LIBRETRO_G_SYSTEM->getThreadSwitchCaller() & THREAD_SWITCH_UPDATE);
 
 			/* Reset frameskip counter if not flagged */
 			if ((!skip_frame && frameskip_counter) || frameskip_counter >= FRAMESKIP_MAX) {
@@ -831,7 +832,7 @@ void retro_run(void) {
 
 			/* Retrieve video */
 			if ((audio_video_enable & 1) && !skip_frame) {
-				const Graphics::Surface &screen = getScreen();
+				const Graphics::Surface &screen = LIBRETRO_G_SYSTEM->getScreen();
 				video_cb(screen.getPixels(), screen.w, screen.h, screen.pitch);
 			}
 
@@ -850,10 +851,10 @@ void retro_run(void) {
 
 			current_frame++;
 
-		} while (getThreadSwitchCaller() & THREAD_SWITCH_UPDATE);
+		} while (LIBRETRO_G_SYSTEM->getThreadSwitchCaller() & THREAD_SWITCH_UPDATE);
 
 		poll_cb();
-		retroProcessMouse(input_cb, retro_device, gampad_cursor_speed, gamepad_acceleration_time, analog_response_is_quadratic, analog_deadzone, mouse_speed);
+		LIBRETRO_G_SYSTEM->processMouse(input_cb, retro_device, gampad_cursor_speed, gamepad_acceleration_time, analog_response_is_quadratic, analog_deadzone, mouse_speed);
 	}
 }
 
@@ -865,7 +866,7 @@ void retro_reset(void) {
 	close_emu_thread();
 	init_command_params();
 	retro_load_game(game_buf_ptr);
-	retroReset();
+	LIBRETRO_G_SYSTEM->resetQuit();
 }
 
 // Stubs




More information about the Scummvm-git-logs mailing list