duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

qthost.h (11167B)


      1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
      2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
      3 
      4 #pragma once
      5 
      6 #include "qtutils.h"
      7 
      8 #include "core/game_list.h"
      9 #include "core/host.h"
     10 #include "core/system.h"
     11 #include "core/types.h"
     12 
     13 #include "util/gpu_device.h"
     14 #include "util/input_manager.h"
     15 
     16 #include <QtCore/QByteArray>
     17 #include <QtCore/QMetaType>
     18 #include <QtCore/QObject>
     19 #include <QtCore/QSemaphore>
     20 #include <QtCore/QString>
     21 #include <QtCore/QThread>
     22 #include <QtGui/QIcon>
     23 
     24 #include <atomic>
     25 #include <functional>
     26 #include <map>
     27 #include <memory>
     28 #include <mutex>
     29 #include <optional>
     30 #include <string>
     31 #include <utility>
     32 #include <vector>
     33 
     34 class ByteStream;
     35 
     36 class QActionGroup;
     37 class QEventLoop;
     38 class QMenu;
     39 class QWidget;
     40 class QTimer;
     41 class QTranslator;
     42 
     43 class INISettingsInterface;
     44 
     45 class GPUDevice;
     46 
     47 class MainWindow;
     48 class DisplayWidget;
     49 
     50 namespace Achievements {
     51 enum class LoginRequestReason;
     52 }
     53 
     54 Q_DECLARE_METATYPE(std::optional<bool>);
     55 Q_DECLARE_METATYPE(std::shared_ptr<SystemBootParameters>);
     56 
     57 class EmuThread : public QThread
     58 {
     59   Q_OBJECT
     60 
     61 public:
     62   /// This class is a scoped lock on the system, which prevents it from running while
     63   /// the object exists. Its purpose is to be used for blocking/modal popup boxes,
     64   /// where the VM needs to exit fullscreen temporarily.
     65   class SystemLock
     66   {
     67   public:
     68     SystemLock(SystemLock&& lock);
     69     SystemLock(const SystemLock&) = delete;
     70     ~SystemLock();
     71 
     72     /// Cancels any pending unpause/fullscreen transition.
     73     /// Call when you're going to destroy the system anyway.
     74     void cancelResume();
     75 
     76   private:
     77     SystemLock(bool was_paused, bool was_fullscreen);
     78     friend EmuThread;
     79 
     80     bool m_was_paused;
     81     bool m_was_fullscreen;
     82   };
     83 
     84 public:
     85   explicit EmuThread(QThread* ui_thread);
     86   ~EmuThread();
     87 
     88   static void start();
     89   static void stop();
     90 
     91   ALWAYS_INLINE bool isOnThread() const { return QThread::currentThread() == this; }
     92   ALWAYS_INLINE bool isOnUIThread() const { return QThread::currentThread() == m_ui_thread; }
     93 
     94   ALWAYS_INLINE QEventLoop* getEventLoop() const { return m_event_loop; }
     95 
     96   ALWAYS_INLINE bool isFullscreen() const { return m_is_fullscreen; }
     97   ALWAYS_INLINE bool isRenderingToMain() const { return m_is_rendering_to_main; }
     98   ALWAYS_INLINE bool isSurfaceless() const { return m_is_surfaceless; }
     99   ALWAYS_INLINE bool isRunningFullscreenUI() const { return m_run_fullscreen_ui; }
    100 
    101   std::optional<WindowInfo> acquireRenderWindow(bool recreate_window);
    102   void connectDisplaySignals(DisplayWidget* widget);
    103   void releaseRenderWindow();
    104 
    105   void startBackgroundControllerPollTimer();
    106   void stopBackgroundControllerPollTimer();
    107   void wakeThread();
    108 
    109   bool shouldRenderToMain() const;
    110   void loadSettings(SettingsInterface& si);
    111   void checkForSettingsChanges(const Settings& old_settings);
    112 
    113   void bootOrLoadState(std::string path);
    114 
    115   void updatePerformanceCounters();
    116   void resetPerformanceCounters();
    117 
    118   /// Locks the system by pausing it, while a popup dialog is displayed.
    119   /// This version is **only** for the system thread. UI thread should use the MainWindow variant.
    120   SystemLock pauseAndLockSystem();
    121 
    122 Q_SIGNALS:
    123   void errorReported(const QString& title, const QString& message);
    124   bool messageConfirmed(const QString& title, const QString& message);
    125   void statusMessage(const QString& message);
    126   void debuggerMessageReported(const QString& message);
    127   void settingsResetToDefault(bool system, bool controller);
    128   void onInputDevicesEnumerated(const std::vector<std::pair<std::string, std::string>>& devices);
    129   void onInputDeviceConnected(const std::string& identifier, const std::string& device_name);
    130   void onInputDeviceDisconnected(const std::string& identifier);
    131   void onVibrationMotorsEnumerated(const QList<InputBindingKey>& motors);
    132   void systemStarting();
    133   void systemStarted();
    134   void systemDestroyed();
    135   void systemPaused();
    136   void systemResumed();
    137   void gameListRefreshed();
    138   std::optional<WindowInfo> onAcquireRenderWindowRequested(bool recreate_window, bool fullscreen, bool render_to_main,
    139                                                            bool surfaceless, bool use_main_window_pos);
    140   void onResizeRenderWindowRequested(qint32 width, qint32 height);
    141   void onReleaseRenderWindowRequested();
    142   void focusDisplayWidgetRequested();
    143   void runningGameChanged(const QString& filename, const QString& game_serial, const QString& game_title);
    144   void inputProfileLoaded();
    145   void mouseModeRequested(bool relative, bool hide_cursor);
    146   void fullscreenUIStateChange(bool running);
    147   void achievementsLoginRequested(Achievements::LoginRequestReason reason);
    148   void achievementsRefreshed(quint32 id, const QString& game_info_string);
    149   void achievementsChallengeModeChanged(bool enabled);
    150   void cheatEnabled(quint32 index, bool enabled);
    151   void mediaCaptureStarted();
    152   void mediaCaptureStopped();
    153 
    154   /// Big Picture UI requests.
    155   void onCoverDownloaderOpenRequested();
    156 
    157 public Q_SLOTS:
    158   void setDefaultSettings(bool system = true, bool controller = true);
    159   void applySettings(bool display_osd_messages = false);
    160   void reloadGameSettings(bool display_osd_messages = false);
    161   void updateEmuFolders();
    162   void updateControllerSettings();
    163   void reloadInputSources();
    164   void reloadInputBindings();
    165   void reloadInputDevices();
    166   void closeInputSources();
    167   void enumerateInputDevices();
    168   void enumerateVibrationMotors();
    169   void startFullscreenUI();
    170   void stopFullscreenUI();
    171   void bootSystem(std::shared_ptr<SystemBootParameters> params);
    172   void resumeSystemFromMostRecentState();
    173   void shutdownSystem(bool save_state, bool check_memcard_busy);
    174   void resetSystem(bool check_memcard_busy);
    175   void setSystemPaused(bool paused, bool wait_until_paused = false);
    176   void changeDisc(const QString& new_disc_filename, bool reset_system, bool check_memcard_busy);
    177   void changeDiscFromPlaylist(quint32 index);
    178   void loadState(const QString& filename);
    179   void loadState(bool global, qint32 slot);
    180   void saveState(const QString& filename, bool block_until_done = false);
    181   void saveState(bool global, qint32 slot, bool block_until_done = false);
    182   void undoLoadState();
    183   void setAudioOutputVolume(int volume, int fast_forward_volume);
    184   void setAudioOutputMuted(bool muted);
    185   void startDumpingAudio();
    186   void stopDumpingAudio();
    187   void singleStepCPU();
    188   void dumpRAM(const QString& filename);
    189   void dumpVRAM(const QString& filename);
    190   void dumpSPURAM(const QString& filename);
    191   void saveScreenshot();
    192   void redrawDisplayWindow();
    193   void toggleFullscreen();
    194   void setFullscreen(bool fullscreen, bool allow_render_to_main);
    195   void setSurfaceless(bool surfaceless);
    196   void requestDisplaySize(float scale);
    197   void setCheatEnabled(quint32 index, bool enabled);
    198   void applyCheat(quint32 index);
    199   void reloadPostProcessingShaders();
    200   void updatePostProcessingSettings();
    201   void clearInputBindStateFromSource(InputBindingKey key);
    202 
    203 private Q_SLOTS:
    204   void stopInThread();
    205   void onDisplayWindowMouseButtonEvent(int button, bool pressed);
    206   void onDisplayWindowMouseWheelEvent(const QPoint& delta_angle);
    207   void onDisplayWindowResized(int width, int height, float scale);
    208   void onDisplayWindowKeyEvent(int key, bool pressed);
    209   void onDisplayWindowTextEntered(const QString& text);
    210   void doBackgroundControllerPoll();
    211   void runOnEmuThread(std::function<void()> callback);
    212 
    213 protected:
    214   void run() override;
    215 
    216 private:
    217   using InputButtonHandler = std::function<void(bool)>;
    218   using InputAxisHandler = std::function<void(float)>;
    219 
    220   void createBackgroundControllerPollTimer();
    221   void destroyBackgroundControllerPollTimer();
    222   void setInitialState(std::optional<bool> override_fullscreen);
    223   void confirmActionIfMemoryCardBusy(const QString& action, bool cancel_resume_on_accept,
    224                                      std::function<void(bool)> callback) const;
    225 
    226   QThread* m_ui_thread;
    227   QSemaphore m_started_semaphore;
    228   QEventLoop* m_event_loop = nullptr;
    229   QTimer* m_background_controller_polling_timer = nullptr;
    230 
    231   bool m_shutdown_flag = false;
    232   bool m_run_fullscreen_ui = false;
    233   bool m_is_rendering_to_main = false;
    234   bool m_is_fullscreen = false;
    235   bool m_is_exclusive_fullscreen = false;
    236   bool m_lost_exclusive_fullscreen = false;
    237   bool m_is_surfaceless = false;
    238   bool m_save_state_on_shutdown = false;
    239 
    240   bool m_was_paused_by_focus_loss = false;
    241 
    242   float m_last_speed = std::numeric_limits<float>::infinity();
    243   float m_last_game_fps = std::numeric_limits<float>::infinity();
    244   float m_last_video_fps = std::numeric_limits<float>::infinity();
    245   u32 m_last_render_width = std::numeric_limits<u32>::max();
    246   u32 m_last_render_height = std::numeric_limits<u32>::max();
    247   RenderAPI m_last_render_api = RenderAPI::None;
    248   bool m_last_hardware_renderer = false;
    249 };
    250 
    251 extern EmuThread* g_emu_thread;
    252 
    253 namespace QtHost {
    254 /// Default theme name for the platform.
    255 const char* GetDefaultThemeName();
    256 
    257 /// Default language for the platform.
    258 const char* GetDefaultLanguage();
    259 
    260 /// Sets application theme according to settings.
    261 void UpdateApplicationTheme();
    262 
    263 /// Returns true if the application theme is using dark colours.
    264 bool IsDarkApplicationTheme();
    265 
    266 /// Sets the icon theme, based on the current style (light/dark).
    267 void SetIconThemeFromStyle();
    268 
    269 /// Sets batch mode (exit after game shutdown).
    270 bool InBatchMode();
    271 
    272 /// Sets NoGUI mode (implys batch mode, does not display main window, exits on shutdown).
    273 bool InNoGUIMode();
    274 
    275 /// Executes a function on the UI thread.
    276 void RunOnUIThread(const std::function<void()>& func, bool block = false);
    277 
    278 /// Default language for the platform.
    279 const char* GetDefaultLanguage();
    280 
    281 /// Call when the language changes.
    282 void UpdateApplicationLanguage(QWidget* dialog_parent);
    283 
    284 /// Returns the application name and version, optionally including debug/devel config indicator.
    285 QString GetAppNameAndVersion();
    286 
    287 /// Returns the debug/devel config indicator.
    288 QString GetAppConfigSuffix();
    289 
    290 /// Returns the main application icon.
    291 const QIcon& GetAppIcon();
    292 
    293 /// Returns the base path for resources. This may be : prefixed, if we're using embedded resources.
    294 QString GetResourcesBasePath();
    295 
    296 /// Returns the base settings interface. Should lock before manipulating.
    297 INISettingsInterface* GetBaseSettingsInterface();
    298 
    299 /// Saves a game settings interface.
    300 bool SaveGameSettings(SettingsInterface* sif, bool delete_if_empty);
    301 
    302 /// Downloads the specified URL to the provided path.
    303 bool DownloadFile(QWidget* parent, const QString& title, std::string url, const char* path);
    304 
    305 /// Downloads the specified URL, and extracts the specified file from a zip to a provided path.
    306 bool DownloadFileFromZip(QWidget* parent, const QString& title, std::string url, const char* zip_filename,
    307                          const char* output_path);
    308 
    309 /// Thread-safe settings access.
    310 void QueueSettingsSave();
    311 
    312 /// Returns true if the debug menu and functionality should be shown.
    313 bool ShouldShowDebugOptions();
    314 
    315 /// VM state, safe to access on UI thread.
    316 bool IsSystemValid();
    317 bool IsSystemPaused();
    318 
    319 /// Accessors for game information.
    320 const QString& GetCurrentGameTitle();
    321 const QString& GetCurrentGameSerial();
    322 const QString& GetCurrentGamePath();
    323 } // namespace QtHost