2021-12-13 12:12:54 +00:00
|
|
|
/* PCSX2 - PS2 Emulator for PCs
|
|
|
|
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
|
|
|
*
|
|
|
|
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
|
|
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
|
|
|
* ation, either version 3 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* PCSX2 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 PCSX2.
|
|
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
#include "pcsx2/Host.h"
|
|
|
|
#include "pcsx2/HostDisplay.h"
|
|
|
|
#include "pcsx2/Frontend/InputManager.h"
|
|
|
|
#include <QtCore/QList>
|
|
|
|
#include <QtCore/QEventLoop>
|
|
|
|
#include <QtCore/QPair>
|
|
|
|
#include <QtCore/QString>
|
|
|
|
#include <QtCore/QSemaphore>
|
|
|
|
#include <QtCore/QTimer>
|
|
|
|
#include <QtCore/QThread>
|
|
|
|
#include <atomic>
|
|
|
|
#include <memory>
|
|
|
|
|
|
|
|
class DisplayWidget;
|
|
|
|
struct VMBootParameters;
|
|
|
|
|
|
|
|
class EmuThread : public QThread
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
public:
|
|
|
|
explicit EmuThread(QThread* ui_thread);
|
|
|
|
~EmuThread();
|
|
|
|
|
|
|
|
static void start();
|
|
|
|
static void stop();
|
|
|
|
|
|
|
|
__fi QEventLoop* getEventLoop() const { return m_event_loop; }
|
2022-05-15 08:16:24 +00:00
|
|
|
__fi bool isFullscreen() const { return m_is_fullscreen; }
|
2021-12-13 12:12:54 +00:00
|
|
|
|
|
|
|
bool isOnEmuThread() const;
|
|
|
|
|
|
|
|
/// Called back from the GS thread when the display state changes (e.g. fullscreen, render to main).
|
|
|
|
HostDisplay* acquireHostDisplay(HostDisplay::RenderAPI api);
|
2022-04-15 08:45:41 +00:00
|
|
|
void connectDisplaySignals(DisplayWidget* widget);
|
2021-12-13 12:12:54 +00:00
|
|
|
void releaseHostDisplay();
|
|
|
|
void updateDisplay();
|
|
|
|
|
|
|
|
void startBackgroundControllerPollTimer();
|
|
|
|
void stopBackgroundControllerPollTimer();
|
2022-04-03 13:46:05 +00:00
|
|
|
void updatePerformanceMetrics(bool force);
|
2021-12-13 12:12:54 +00:00
|
|
|
|
|
|
|
public Q_SLOTS:
|
|
|
|
void startVM(std::shared_ptr<VMBootParameters> boot_params);
|
|
|
|
void resetVM();
|
|
|
|
void setVMPaused(bool paused);
|
2022-05-07 12:56:44 +00:00
|
|
|
void shutdownVM(bool save_state = true);
|
2021-12-13 12:12:54 +00:00
|
|
|
void loadState(const QString& filename);
|
|
|
|
void loadStateFromSlot(qint32 slot);
|
|
|
|
void saveState(const QString& filename);
|
|
|
|
void saveStateToSlot(qint32 slot);
|
|
|
|
void toggleFullscreen();
|
|
|
|
void setFullscreen(bool fullscreen);
|
2022-05-06 11:03:16 +00:00
|
|
|
void setSurfaceless(bool surfaceless);
|
2021-12-13 12:12:54 +00:00
|
|
|
void applySettings();
|
2022-03-07 09:37:23 +00:00
|
|
|
void reloadGameSettings();
|
2022-06-14 10:05:11 +00:00
|
|
|
void updateEmuFolders();
|
2021-12-13 12:12:54 +00:00
|
|
|
void toggleSoftwareRendering();
|
|
|
|
void switchRenderer(GSRendererType renderer);
|
|
|
|
void changeDisc(const QString& path);
|
|
|
|
void reloadPatches();
|
|
|
|
void reloadInputSources();
|
|
|
|
void reloadInputBindings();
|
|
|
|
void requestDisplaySize(float scale);
|
|
|
|
void enumerateInputDevices();
|
|
|
|
void enumerateVibrationMotors();
|
2022-04-06 10:42:23 +00:00
|
|
|
void runOnCPUThread(const std::function<void()>& func);
|
2022-05-16 11:10:34 +00:00
|
|
|
void queueSnapshot(quint32 gsdump_frames);
|
2021-12-13 12:12:54 +00:00
|
|
|
|
|
|
|
Q_SIGNALS:
|
|
|
|
DisplayWidget* onCreateDisplayRequested(bool fullscreen, bool render_to_main);
|
2022-05-06 11:03:16 +00:00
|
|
|
DisplayWidget* onUpdateDisplayRequested(bool fullscreen, bool render_to_main, bool surfaceless);
|
2021-12-13 12:12:54 +00:00
|
|
|
void onResizeDisplayRequested(qint32 width, qint32 height);
|
|
|
|
void onDestroyDisplayRequested();
|
2022-01-31 05:24:33 +00:00
|
|
|
|
|
|
|
/// Called when the VM is starting initialization, but has not been completed yet.
|
2021-12-13 12:12:54 +00:00
|
|
|
void onVMStarting();
|
2022-01-31 05:24:33 +00:00
|
|
|
|
|
|
|
/// Called when the VM is created.
|
2021-12-13 12:12:54 +00:00
|
|
|
void onVMStarted();
|
2022-01-31 05:24:33 +00:00
|
|
|
|
|
|
|
/// Called when the VM is paused.
|
2021-12-13 12:12:54 +00:00
|
|
|
void onVMPaused();
|
2022-01-31 05:24:33 +00:00
|
|
|
|
|
|
|
/// Called when the VM is resumed after being paused.
|
2021-12-13 12:12:54 +00:00
|
|
|
void onVMResumed();
|
2022-01-31 05:24:33 +00:00
|
|
|
|
|
|
|
/// Called when the VM is shut down or destroyed.
|
2021-12-13 12:12:54 +00:00
|
|
|
void onVMStopped();
|
2022-01-31 05:24:33 +00:00
|
|
|
|
|
|
|
/// Provided by the host; called when the running executable changes.
|
2021-12-13 12:12:54 +00:00
|
|
|
void onGameChanged(const QString& path, const QString& serial, const QString& name, quint32 crc);
|
2022-01-31 05:24:33 +00:00
|
|
|
|
2022-04-03 13:46:05 +00:00
|
|
|
/// Called when performance metrics are changed, approx. once a second.
|
|
|
|
void onPerformanceMetricsUpdated(const QString& fps_stats, const QString& gs_stats);
|
|
|
|
|
2021-12-13 12:12:54 +00:00
|
|
|
void onInputDevicesEnumerated(const QList<QPair<QString, QString>>& devices);
|
|
|
|
void onInputDeviceConnected(const QString& identifier, const QString& device_name);
|
|
|
|
void onInputDeviceDisconnected(const QString& identifier);
|
|
|
|
void onVibrationMotorsEnumerated(const QList<InputBindingKey>& motors);
|
|
|
|
|
2022-01-31 05:24:33 +00:00
|
|
|
/// Called when a save state is loading, before the file is processed.
|
|
|
|
void onSaveStateLoading(const QString& path);
|
|
|
|
|
|
|
|
/// Called after a save state is successfully loaded. If the save state was invalid, was_successful will be false.
|
|
|
|
void onSaveStateLoaded(const QString& path, bool was_successful);
|
|
|
|
|
|
|
|
/// Called when a save state is being created/saved. The compression/write to disk is asynchronous, so this callback
|
|
|
|
/// just signifies that the save has started, not necessarily completed.
|
|
|
|
void onSaveStateSaved(const QString& path);
|
|
|
|
|
2021-12-13 12:12:54 +00:00
|
|
|
protected:
|
|
|
|
void run();
|
|
|
|
|
|
|
|
private:
|
|
|
|
static constexpr u32 BACKGROUND_CONTROLLER_POLLING_INTERVAL =
|
|
|
|
100; /// Interval at which the controllers are polled when the system is not active.
|
|
|
|
|
|
|
|
void destroyVM();
|
|
|
|
void executeVM();
|
|
|
|
void checkForSettingChanges();
|
|
|
|
|
|
|
|
void createBackgroundControllerPollTimer();
|
|
|
|
void destroyBackgroundControllerPollTimer();
|
2022-04-03 13:46:05 +00:00
|
|
|
void loadOurSettings();
|
2021-12-13 12:12:54 +00:00
|
|
|
|
|
|
|
private Q_SLOTS:
|
|
|
|
void stopInThread();
|
|
|
|
void doBackgroundControllerPoll();
|
|
|
|
void onDisplayWindowResized(int width, int height, float scale);
|
|
|
|
void onDisplayWindowFocused();
|
|
|
|
|
|
|
|
private:
|
|
|
|
QThread* m_ui_thread;
|
|
|
|
QSemaphore m_started_semaphore;
|
|
|
|
QEventLoop* m_event_loop = nullptr;
|
|
|
|
QTimer* m_background_controller_polling_timer = nullptr;
|
|
|
|
|
|
|
|
std::atomic_bool m_shutdown_flag{false};
|
|
|
|
|
2022-04-03 13:46:05 +00:00
|
|
|
bool m_verbose_status = false;
|
2021-12-13 12:12:54 +00:00
|
|
|
bool m_is_rendering_to_main = false;
|
|
|
|
bool m_is_fullscreen = false;
|
2022-05-06 11:03:16 +00:00
|
|
|
bool m_is_surfaceless = false;
|
2022-05-07 12:56:44 +00:00
|
|
|
bool m_save_state_on_shutdown = false;
|
2022-04-03 13:46:05 +00:00
|
|
|
|
|
|
|
float m_last_speed = 0.0f;
|
|
|
|
float m_last_game_fps = 0.0f;
|
|
|
|
float m_last_video_fps = 0.0f;
|
|
|
|
int m_last_internal_width = 0;
|
|
|
|
int m_last_internal_height = 0;
|
2021-12-13 12:12:54 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
extern EmuThread* g_emu_thread;
|