/* Copyright 2016-2024 melonDS team This file is part of melonDS. melonDS 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. melonDS 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 melonDS. If not, see http://www.gnu.org/licenses/. */ #ifndef EMUTHREAD_H #define EMUTHREAD_H #include #include #include #include #include #include #include #include #include #include "NDSCart.h" #include "GBACart.h" namespace melonDS { class NDS; } class EmuInstance; class MainWindow; class ScreenPanelGL; class EmuThread : public QThread { Q_OBJECT void run() override; public: explicit EmuThread(EmuInstance* inst, QObject* parent = nullptr); void attachWindow(MainWindow* window); void detachWindow(MainWindow* window); enum MessageType { msg_Exit, msg_EmuRun, msg_EmuPause, msg_EmuUnpause, msg_EmuStop, msg_EmuFrameStep, msg_EmuReset, msg_InitGL, msg_DeInitGL, msg_BootROM, msg_BootFirmware, msg_InsertCart, msg_EjectCart, msg_InsertGBACart, msg_InsertGBAAddon, msg_EjectGBACart, msg_LoadState, msg_SaveState, msg_UndoStateLoad, msg_ImportSavefile, msg_EnableCheats, }; struct Message { MessageType type; QVariant param; }; void sendMessage(Message msg); void waitMessage(int num = 1); void waitAllMessages(); void sendMessage(MessageType type) { return sendMessage({.type = type}); } void changeWindowTitle(char* title); // to be called from the UI thread void emuRun(); void emuPause(bool broadcast = true); void emuUnpause(bool broadcast = true); void emuTogglePause(bool broadcast = true); void emuStop(bool external); void emuExit(); void emuFrameStep(); void emuReset(); int bootROM(const QStringList& filename); int bootFirmware(); int insertCart(const QStringList& filename, bool gba); void ejectCart(bool gba); int insertGBAAddon(int type); int saveState(const QString& filename); int loadState(const QString& filename); int undoStateLoad(); int importSavefile(const QString& filename); void enableCheats(bool enable); bool emuIsRunning(); bool emuIsActive(); void initContext(int win); void deinitContext(int win); void updateVideoSettings() { videoSettingsDirty = true; } void updateVideoRenderer() { videoSettingsDirty = true; lastVideoRenderer = -1; } int frontBuffer = 0; QMutex frontBufferLock; signals: void windowUpdate(); void windowTitleChange(QString title); void windowEmuStart(); void windowEmuStop(); void windowEmuPause(bool pause); void windowEmuReset(); void windowLimitFPSChange(); void autoScreenSizingChange(int sizing); void windowFullscreenToggle(); void swapScreensToggle(); void screenEmphasisToggle(); void syncVolumeLevel(); private: void handleMessages(); void updateRenderer(); void compileShaders(); enum EmuStatusKind { emuStatus_Exit, emuStatus_Running, emuStatus_Paused, emuStatus_FrameStep, }; EmuStatusKind prevEmuStatus; EmuStatusKind emuStatus; bool emuActive; constexpr static int emuPauseStackRunning = 0; constexpr static int emuPauseStackPauseThreshold = 1; int emuPauseStack; int msgResult = 0; QMutex msgMutex; QSemaphore msgSemaphore; QQueue msgQueue; EmuInstance* emuInstance; int autoScreenSizing; int lastVideoRenderer = -1; double perfCountsSec; bool useOpenGL; int videoRenderer; bool videoSettingsDirty; }; #endif // EMUTHREAD_H