From e973236203292637eb7bd009a4cfbd6fd785181f Mon Sep 17 00:00:00 2001 From: Jesse Talavera-Greenberg Date: Tue, 28 Nov 2023 17:16:41 -0500 Subject: Refactor `NDS` and `DSi` to be objects (#1893) * First crack at refactoring NDS and DSi into objects - Remove all global/`static` variables in `NDS` and related classes - Rely more on virtual dispatch when we need to pick methods at runtime - Pass `NDS&` or `DSi&` to its constituent components where necessary - Introduce some headers or move some definitions to break `#include` cycles * Refactor the frontend to accommodate the core's changes * Move up `SchedList`'s declaration - Move it to before the components are initialized so the `map`s inside are initialized - Fields in C++ are initialized in the order they're declared * Fix a crash when allocating memory * Fix JIT-free builds * Fix GDB-free builds * Fix Linux builds - Explicitly qualify some member types in NDS, since they share the same name as their classes * Remove an unnecessary template argument - This was causing the build to fail on macOS * Fix ARM and Android builds * Rename `Constants.h` to `MemConstants.h` * Add `NDS::IsRunning()` * Use an `#include` guard instead of `#pragma once` --- src/frontend/FrontendUtil.h | 10 +- src/frontend/Util_Audio.cpp | 16 +- src/frontend/qt_sdl/AudioInOut.cpp | 22 +- src/frontend/qt_sdl/AudioInOut.h | 13 +- src/frontend/qt_sdl/AudioSettingsDialog.cpp | 23 +- src/frontend/qt_sdl/AudioSettingsDialog.h | 8 +- .../PowerManagement/PowerManagementDialog.cpp | 83 +++-- .../qt_sdl/PowerManagement/PowerManagementDialog.h | 8 +- src/frontend/qt_sdl/RAMInfoDialog.cpp | 22 +- src/frontend/qt_sdl/RAMInfoDialog.h | 18 +- src/frontend/qt_sdl/ROMInfoDialog.cpp | 7 +- src/frontend/qt_sdl/ROMInfoDialog.h | 8 +- src/frontend/qt_sdl/ROMManager.cpp | 400 ++++++++++++++++----- src/frontend/qt_sdl/ROMManager.h | 46 ++- src/frontend/qt_sdl/main.cpp | 222 +++++++----- src/frontend/qt_sdl/main.h | 9 +- 16 files changed, 629 insertions(+), 286 deletions(-) (limited to 'src/frontend') diff --git a/src/frontend/FrontendUtil.h b/src/frontend/FrontendUtil.h index 8d94b37..6f09d4b 100644 --- a/src/frontend/FrontendUtil.h +++ b/src/frontend/FrontendUtil.h @@ -24,6 +24,10 @@ #include #include +namespace melonDS +{ +class NDS; +} namespace Frontend { using namespace melonDS; @@ -105,14 +109,14 @@ int AudioOut_GetNumSamples(int outlen); void AudioOut_Resample(s16* inbuf, int inlen, s16* outbuf, int outlen, int volume); // feed silence to the microphone input -void Mic_FeedSilence(); +void Mic_FeedSilence(NDS& nds); // feed random noise to the microphone input -void Mic_FeedNoise(); +void Mic_FeedNoise(NDS& nds); // feed an external buffer to the microphone input // buffer should be mono -void Mic_FeedExternalBuffer(); +void Mic_FeedExternalBuffer(NDS& nds); void Mic_SetExternalBuffer(s16* buffer, u32 len); } diff --git a/src/frontend/Util_Audio.cpp b/src/frontend/Util_Audio.cpp index 4a1d089..02b3026 100644 --- a/src/frontend/Util_Audio.cpp +++ b/src/frontend/Util_Audio.cpp @@ -82,13 +82,13 @@ void AudioOut_Resample(s16* inbuf, int inlen, s16* outbuf, int outlen, int volum } -void Mic_FeedSilence() +void Mic_FeedSilence(NDS& nds) { MicBufferReadPos = 0; - NDS::MicInputFrame(NULL, 0); + nds.MicInputFrame(NULL, 0); } -void Mic_FeedNoise() +void Mic_FeedNoise(NDS& nds) { int sample_len = sizeof(mic_blow) / sizeof(u16); static int sample_pos = 0; @@ -102,12 +102,12 @@ void Mic_FeedNoise() if (sample_pos >= sample_len) sample_pos = 0; } - NDS::MicInputFrame(tmp, 735); + nds.MicInputFrame(tmp, 735); } -void Mic_FeedExternalBuffer() +void Mic_FeedExternalBuffer(NDS& nds) { - if (!MicBuffer) return Mic_FeedSilence(); + if (!MicBuffer) return Mic_FeedSilence(nds); if ((MicBufferReadPos + 735) > MicBufferLength) { @@ -116,12 +116,12 @@ void Mic_FeedExternalBuffer() memcpy(&tmp[0], &MicBuffer[MicBufferReadPos], len1*sizeof(s16)); memcpy(&tmp[len1], &MicBuffer[0], (735 - len1)*sizeof(s16)); - NDS::MicInputFrame(tmp, 735); + nds.MicInputFrame(tmp, 735); MicBufferReadPos = 735 - len1; } else { - NDS::MicInputFrame(&MicBuffer[MicBufferReadPos], 735); + nds.MicInputFrame(&MicBuffer[MicBufferReadPos], 735); MicBufferReadPos += 735; } } diff --git a/src/frontend/qt_sdl/AudioInOut.cpp b/src/frontend/qt_sdl/AudioInOut.cpp index 90708b2..ae5529d 100644 --- a/src/frontend/qt_sdl/AudioInOut.cpp +++ b/src/frontend/qt_sdl/AudioInOut.cpp @@ -55,8 +55,9 @@ void AudioCallback(void* data, Uint8* stream, int len) s16 buf_in[1024*2]; int num_in; + EmuThread* emuThread = (EmuThread*)data; SDL_LockMutex(audioSyncLock); - num_in = NDS::SPU->ReadOutput(buf_in, len_in); + num_in = emuThread->NDS->SPU.ReadOutput(buf_in, len_in); SDL_CondSignal(audioSync); SDL_UnlockMutex(audioSyncLock); @@ -244,7 +245,7 @@ void MicLoadWav(const std::string& name) SDL_FreeWAV(buf); } -void MicProcess() +void MicProcess(melonDS::NDS& nds) { int type = Config::MicInputType; bool cmd = Input::HotkeyDown(HK_Mic); @@ -257,16 +258,16 @@ void MicProcess() switch (type) { case micInputType_Silence: // no mic - Frontend::Mic_FeedSilence(); + Frontend::Mic_FeedSilence(nds); break; case micInputType_External: // host mic case micInputType_Wav: // WAV - Frontend::Mic_FeedExternalBuffer(); + Frontend::Mic_FeedExternalBuffer(nds); break; case micInputType_Noise: // blowing noise - Frontend::Mic_FeedNoise(); + Frontend::Mic_FeedNoise(nds); break; } } @@ -296,7 +297,7 @@ void SetupMicInputData() } } -void Init() +void Init(EmuThread* thread) { audioMuted = false; audioSync = SDL_CreateCond(); @@ -310,6 +311,7 @@ void Init() whatIwant.channels = 2; whatIwant.samples = 1024; whatIwant.callback = AudioCallback; + whatIwant.userdata = thread; audioDevice = SDL_OpenAudioDevice(NULL, 0, &whatIwant, &whatIget, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE); if (!audioDevice) { @@ -349,12 +351,12 @@ void DeInit() micWavBuffer = nullptr; } -void AudioSync() +void AudioSync(NDS& nds) { if (audioDevice) { SDL_LockMutex(audioSyncLock); - while (NDS::SPU->GetOutputSize() > 1024) + while (nds.SPU.GetOutputSize() > 1024) { int ret = SDL_CondWaitTimeout(audioSync, audioSyncLock, 500); if (ret == SDL_MUTEX_TIMEDOUT) break; @@ -363,11 +365,11 @@ void AudioSync() } } -void UpdateSettings() +void UpdateSettings(NDS& nds) { MicClose(); - NDS::SPU->SetInterpolation(Config::AudioInterp); + nds.SPU.SetInterpolation(Config::AudioInterp); SetupMicInputData(); MicOpen(); diff --git a/src/frontend/qt_sdl/AudioInOut.h b/src/frontend/qt_sdl/AudioInOut.h index cc38625..0bf3654 100644 --- a/src/frontend/qt_sdl/AudioInOut.h +++ b/src/frontend/qt_sdl/AudioInOut.h @@ -23,18 +23,23 @@ #include +class EmuThread; +namespace melonDS +{ +class NDS; +} namespace AudioInOut { -void Init(); +void Init(EmuThread* thread); void DeInit(); -void MicProcess(); +void MicProcess(melonDS::NDS& nds); void AudioMute(QMainWindow* mainWindow); -void AudioSync(); +void AudioSync(melonDS::NDS& nds); -void UpdateSettings(); +void UpdateSettings(melonDS::NDS& nds); void Enable(); void Disable(); diff --git a/src/frontend/qt_sdl/AudioSettingsDialog.cpp b/src/frontend/qt_sdl/AudioSettingsDialog.cpp index cb42e64..5e8812e 100644 --- a/src/frontend/qt_sdl/AudioSettingsDialog.cpp +++ b/src/frontend/qt_sdl/AudioSettingsDialog.cpp @@ -29,7 +29,7 @@ #include "AudioSettingsDialog.h" #include "ui_AudioSettingsDialog.h" - +#include "main.h" using namespace melonDS; AudioSettingsDialog* AudioSettingsDialog::currentDlg = nullptr; @@ -37,7 +37,7 @@ AudioSettingsDialog* AudioSettingsDialog::currentDlg = nullptr; extern std::string EmuDirectory; -AudioSettingsDialog::AudioSettingsDialog(QWidget* parent, bool emuActive) : QDialog(parent), ui(new Ui::AudioSettingsDialog) +AudioSettingsDialog::AudioSettingsDialog(QWidget* parent, bool emuActive, EmuThread* emuThread) : QDialog(parent), ui(new Ui::AudioSettingsDialog), emuThread(emuThread) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); @@ -65,7 +65,7 @@ AudioSettingsDialog::AudioSettingsDialog(QWidget* parent, bool emuActive) : QDia ui->chkSyncDSiVolume->setChecked(Config::DSiVolumeSync); // Setup volume slider accordingly - if (emuActive && NDS::ConsoleType == 1) + if (emuActive && emuThread->NDS->ConsoleType == 1) { on_chkSyncDSiVolume_clicked(Config::DSiVolumeSync); } @@ -125,10 +125,11 @@ AudioSettingsDialog::~AudioSettingsDialog() void AudioSettingsDialog::onSyncVolumeLevel() { - if (Config::DSiVolumeSync && NDS::ConsoleType == 1) + if (Config::DSiVolumeSync && emuThread->NDS->ConsoleType == 1) { + auto& dsi = static_cast(*emuThread->NDS); bool state = ui->slVolume->blockSignals(true); - ui->slVolume->setValue(DSi::I2C->GetBPTWL()->GetVolumeLevel()); + ui->slVolume->setValue(dsi.I2C.GetBPTWL()->GetVolumeLevel()); ui->slVolume->blockSignals(state); } } @@ -136,7 +137,7 @@ void AudioSettingsDialog::onSyncVolumeLevel() void AudioSettingsDialog::onConsoleReset() { on_chkSyncDSiVolume_clicked(Config::DSiVolumeSync); - ui->chkSyncDSiVolume->setEnabled(NDS::ConsoleType == 1); + ui->chkSyncDSiVolume->setEnabled(emuThread->NDS->ConsoleType == 1); } void AudioSettingsDialog::on_AudioSettingsDialog_accepted() @@ -181,9 +182,10 @@ void AudioSettingsDialog::on_cbInterpolation_currentIndexChanged(int idx) void AudioSettingsDialog::on_slVolume_valueChanged(int val) { - if (Config::DSiVolumeSync && NDS::ConsoleType == 1) + if (Config::DSiVolumeSync && emuThread->NDS->ConsoleType == 1) { - DSi::I2C->GetBPTWL()->SetVolumeLevel(val); + auto& dsi = static_cast(*emuThread->NDS); + dsi.I2C.GetBPTWL()->SetVolumeLevel(val); return; } @@ -195,10 +197,11 @@ void AudioSettingsDialog::on_chkSyncDSiVolume_clicked(bool checked) Config::DSiVolumeSync = checked; bool state = ui->slVolume->blockSignals(true); - if (Config::DSiVolumeSync && NDS::ConsoleType == 1) + if (Config::DSiVolumeSync && emuThread->NDS->ConsoleType == 1) { + auto& dsi = static_cast(*emuThread->NDS); ui->slVolume->setMaximum(31); - ui->slVolume->setValue(DSi::I2C->GetBPTWL()->GetVolumeLevel()); + ui->slVolume->setValue(dsi.I2C.GetBPTWL()->GetVolumeLevel()); ui->slVolume->setPageStep(4); ui->slVolume->setTickPosition(QSlider::TicksBelow); } diff --git a/src/frontend/qt_sdl/AudioSettingsDialog.h b/src/frontend/qt_sdl/AudioSettingsDialog.h index 98060b2..ced9bae 100644 --- a/src/frontend/qt_sdl/AudioSettingsDialog.h +++ b/src/frontend/qt_sdl/AudioSettingsDialog.h @@ -24,17 +24,18 @@ namespace Ui { class AudioSettingsDialog; } class AudioSettingsDialog; +class EmuThread; class AudioSettingsDialog : public QDialog { Q_OBJECT public: - explicit AudioSettingsDialog(QWidget* parent, bool emuActive); + explicit AudioSettingsDialog(QWidget* parent, bool emuActive, EmuThread* emuThread); ~AudioSettingsDialog(); static AudioSettingsDialog* currentDlg; - static AudioSettingsDialog* openDlg(QWidget* parent, bool emuActive) + static AudioSettingsDialog* openDlg(QWidget* parent, bool emuActive, EmuThread* emuThread) { if (currentDlg) { @@ -42,7 +43,7 @@ public: return currentDlg; } - currentDlg = new AudioSettingsDialog(parent, emuActive); + currentDlg = new AudioSettingsDialog(parent, emuActive, emuThread); currentDlg->show(); return currentDlg; } @@ -69,6 +70,7 @@ private slots: void on_btnMicWavBrowse_clicked(); private: + EmuThread* emuThread; Ui::AudioSettingsDialog* ui; int oldInterp; diff --git a/src/frontend/qt_sdl/PowerManagement/PowerManagementDialog.cpp b/src/frontend/qt_sdl/PowerManagement/PowerManagementDialog.cpp index 14ccd51..3d47c45 100644 --- a/src/frontend/qt_sdl/PowerManagement/PowerManagementDialog.cpp +++ b/src/frontend/qt_sdl/PowerManagement/PowerManagementDialog.cpp @@ -29,45 +29,59 @@ #include "types.h" #include +#include "main.h" using namespace melonDS; PowerManagementDialog* PowerManagementDialog::currentDlg = nullptr; -PowerManagementDialog::PowerManagementDialog(QWidget* parent) : QDialog(parent), ui(new Ui::PowerManagementDialog) +PowerManagementDialog::PowerManagementDialog(QWidget* parent, EmuThread* emuThread) : QDialog(parent), emuThread(emuThread), ui(new Ui::PowerManagementDialog) { inited = false; ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); - if (NDS::ConsoleType == 1) + if (emuThread->NDS->ConsoleType == 1) { ui->grpDSBattery->setEnabled(false); - oldDSiBatteryLevel = DSi::I2C->GetBPTWL()->GetBatteryLevel(); - oldDSiBatteryCharging = DSi::I2C->GetBPTWL()->GetBatteryCharging(); + auto& dsi = static_cast(*emuThread->NDS); + oldDSiBatteryLevel = dsi.I2C.GetBPTWL()->GetBatteryLevel(); + oldDSiBatteryCharging = dsi.I2C.GetBPTWL()->GetBatteryCharging(); } else { ui->grpDSiBattery->setEnabled(false); - oldDSBatteryLevel = NDS::SPI->GetPowerMan()->GetBatteryLevelOkay(); + oldDSBatteryLevel = emuThread->NDS->SPI.GetPowerMan()->GetBatteryLevelOkay(); } updateDSBatteryLevelControls(); - ui->cbDSiBatteryCharging->setChecked(DSi::I2C->GetBPTWL()->GetBatteryCharging()); - int dsiBatterySliderPos; - switch (DSi::I2C->GetBPTWL()->GetBatteryLevel()) + bool defaultDSiBatteryCharging = (emuThread->NDS->ConsoleType == 1) ? Config::DSiBatteryCharging : false; + + if (emuThread->NDS->ConsoleType == 1) { + auto& dsi = static_cast(*emuThread->NDS); + ui->cbDSiBatteryCharging->setChecked(dsi.I2C.GetBPTWL()->GetBatteryCharging()); + int dsiBatterySliderPos = 4; + switch (dsi.I2C.GetBPTWL()->GetBatteryLevel()) + { case DSi_BPTWL::batteryLevel_AlmostEmpty: dsiBatterySliderPos = 0; break; case DSi_BPTWL::batteryLevel_Low: dsiBatterySliderPos = 1; break; case DSi_BPTWL::batteryLevel_Half: dsiBatterySliderPos = 2; break; case DSi_BPTWL::batteryLevel_ThreeQuarters: dsiBatterySliderPos = 3; break; case DSi_BPTWL::batteryLevel_Full: dsiBatterySliderPos = 4; break; + } + ui->sliderDSiBatteryLevel->setValue(dsiBatterySliderPos); + } + else + { + ui->cbDSiBatteryCharging->setChecked(Config::DSiBatteryCharging); + ui->sliderDSiBatteryLevel->setValue(Config::DSiBatteryLevel); } - ui->sliderDSiBatteryLevel->setValue(dsiBatterySliderPos); + int inst = Platform::InstanceID(); if (inst > 0) @@ -87,26 +101,28 @@ void PowerManagementDialog::done(int r) { if (r == QDialog::Accepted) { - if (NDS::ConsoleType == 1) + if (emuThread->NDS->ConsoleType == 1) { - Config::DSiBatteryLevel = DSi::I2C->GetBPTWL()->GetBatteryLevel(); - Config::DSiBatteryCharging = DSi::I2C->GetBPTWL()->GetBatteryCharging(); + auto& dsi = static_cast(*emuThread->NDS); + Config::DSiBatteryLevel = dsi.I2C.GetBPTWL()->GetBatteryLevel(); + Config::DSiBatteryCharging = dsi.I2C.GetBPTWL()->GetBatteryCharging(); } else { - Config::DSBatteryLevelOkay = NDS::SPI->GetPowerMan()->GetBatteryLevelOkay(); + Config::DSBatteryLevelOkay = emuThread->NDS->SPI.GetPowerMan()->GetBatteryLevelOkay(); } } else { - if (NDS::ConsoleType == 1) + if (emuThread->NDS->ConsoleType == 1) { - DSi::I2C->GetBPTWL()->SetBatteryLevel(oldDSiBatteryLevel); - DSi::I2C->GetBPTWL()->SetBatteryCharging(oldDSiBatteryCharging); + auto& dsi = static_cast(*emuThread->NDS); + dsi.I2C.GetBPTWL()->SetBatteryLevel(oldDSiBatteryLevel); + dsi.I2C.GetBPTWL()->SetBatteryCharging(oldDSiBatteryCharging); } else { - NDS::SPI->GetPowerMan()->SetBatteryLevelOkay(oldDSBatteryLevel); + emuThread->NDS->SPI.GetPowerMan()->SetBatteryLevelOkay(oldDSBatteryLevel); } } @@ -117,17 +133,17 @@ void PowerManagementDialog::done(int r) void PowerManagementDialog::on_rbDSBatteryLow_clicked() { - NDS::SPI->GetPowerMan()->SetBatteryLevelOkay(false); + emuThread->NDS->SPI.GetPowerMan()->SetBatteryLevelOkay(false); } void PowerManagementDialog::on_rbDSBatteryOkay_clicked() { - NDS::SPI->GetPowerMan()->SetBatteryLevelOkay(true); + emuThread->NDS->SPI.GetPowerMan()->SetBatteryLevelOkay(true); } void PowerManagementDialog::updateDSBatteryLevelControls() { - if (NDS::SPI->GetPowerMan()->GetBatteryLevelOkay()) + if (emuThread->NDS->SPI.GetPowerMan()->GetBatteryLevelOkay()) ui->rbDSBatteryOkay->setChecked(true); else ui->rbDSBatteryLow->setChecked(true); @@ -135,23 +151,32 @@ void PowerManagementDialog::updateDSBatteryLevelControls() void PowerManagementDialog::on_cbDSiBatteryCharging_toggled() { - DSi::I2C->GetBPTWL()->SetBatteryCharging(ui->cbDSiBatteryCharging->isChecked()); + if (emuThread->NDS->ConsoleType == 1) + { + auto& dsi = static_cast(*emuThread->NDS); + dsi.I2C.GetBPTWL()->SetBatteryCharging(ui->cbDSiBatteryCharging->isChecked()); + } } void PowerManagementDialog::on_sliderDSiBatteryLevel_valueChanged(int value) { if (!inited) return; - u8 newBatteryLevel; - switch (value) + if (emuThread->NDS->ConsoleType == 1) { - case 0: newBatteryLevel = DSi::I2C->GetBPTWL()->batteryLevel_AlmostEmpty; break; - case 1: newBatteryLevel = DSi::I2C->GetBPTWL()->batteryLevel_Low; break; - case 2: newBatteryLevel = DSi::I2C->GetBPTWL()->batteryLevel_Half; break; - case 3: newBatteryLevel = DSi::I2C->GetBPTWL()->batteryLevel_ThreeQuarters; break; - case 4: newBatteryLevel = DSi::I2C->GetBPTWL()->batteryLevel_Full; break; + auto& dsi = static_cast(*emuThread->NDS); + u8 newBatteryLevel = DSi_BPTWL::batteryLevel_Full; + switch (value) + { + case 0: newBatteryLevel = DSi_BPTWL::batteryLevel_AlmostEmpty; break; + case 1: newBatteryLevel = DSi_BPTWL::batteryLevel_Low; break; + case 2: newBatteryLevel = DSi_BPTWL::batteryLevel_Half; break; + case 3: newBatteryLevel = DSi_BPTWL::batteryLevel_ThreeQuarters; break; + case 4: newBatteryLevel = DSi_BPTWL::batteryLevel_Full; break; + } + dsi.I2C.GetBPTWL()->SetBatteryLevel(newBatteryLevel); } - DSi::I2C->GetBPTWL()->SetBatteryLevel(newBatteryLevel); + updateDSBatteryLevelControls(); } diff --git a/src/frontend/qt_sdl/PowerManagement/PowerManagementDialog.h b/src/frontend/qt_sdl/PowerManagement/PowerManagementDialog.h index cd2954a..bc2abc3 100644 --- a/src/frontend/qt_sdl/PowerManagement/PowerManagementDialog.h +++ b/src/frontend/qt_sdl/PowerManagement/PowerManagementDialog.h @@ -25,6 +25,7 @@ #include "types.h" namespace Ui { class PowerManagementDialog; } +class EmuThread; class PowerManagementDialog; class PowerManagementDialog : public QDialog @@ -32,11 +33,11 @@ class PowerManagementDialog : public QDialog Q_OBJECT public: - explicit PowerManagementDialog(QWidget* parent); + explicit PowerManagementDialog(QWidget* parent, EmuThread* emu_thread); ~PowerManagementDialog(); static PowerManagementDialog* currentDlg; - static PowerManagementDialog* openDlg(QWidget* parent) + static PowerManagementDialog* openDlg(QWidget* parent, EmuThread* emu_thread) { if (currentDlg) { @@ -44,7 +45,7 @@ public: return currentDlg; } - currentDlg = new PowerManagementDialog(parent); + currentDlg = new PowerManagementDialog(parent, emu_thread); currentDlg->open(); return currentDlg; } @@ -64,6 +65,7 @@ private slots: private: Ui::PowerManagementDialog* ui; + EmuThread* emuThread; bool inited; bool oldDSBatteryLevel; diff --git a/src/frontend/qt_sdl/RAMInfoDialog.cpp b/src/frontend/qt_sdl/RAMInfoDialog.cpp index b58662c..5bff99a 100644 --- a/src/frontend/qt_sdl/RAMInfoDialog.cpp +++ b/src/frontend/qt_sdl/RAMInfoDialog.cpp @@ -24,16 +24,16 @@ using namespace melonDS; extern EmuThread* emuThread; -s32 GetMainRAMValue(const u32& addr, const ramInfo_ByteType& byteType) +s32 GetMainRAMValue(NDS& nds, const u32& addr, const ramInfo_ByteType& byteType) { switch (byteType) { case ramInfo_OneByte: - return *(s8*)(NDS::MainRAM + (addr&NDS::MainRAMMask)); + return *(s8*)(nds.MainRAM + (addr&nds.MainRAMMask)); case ramInfo_TwoBytes: - return *(s16*)(NDS::MainRAM + (addr&NDS::MainRAMMask)); + return *(s16*)(nds.MainRAM + (addr&nds.MainRAMMask)); case ramInfo_FourBytes: - return *(s32*)(NDS::MainRAM + (addr&NDS::MainRAMMask)); + return *(s32*)(nds.MainRAM + (addr&nds.MainRAMMask)); default: return 0; } @@ -41,7 +41,7 @@ s32 GetMainRAMValue(const u32& addr, const ramInfo_ByteType& byteType) RAMInfoDialog* RAMInfoDialog::currentDlg = nullptr; -RAMInfoDialog::RAMInfoDialog(QWidget* parent) : QDialog(parent), ui(new Ui::RAMInfoDialog) +RAMInfoDialog::RAMInfoDialog(QWidget* parent, EmuThread* emuThread) : QDialog(parent), emuThread(emuThread), ui(new Ui::RAMInfoDialog) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); @@ -91,7 +91,7 @@ void RAMInfoDialog::ShowRowsInTable() for (u32 row = scrollValue; row < std::min(scrollValue+25, RowDataVector->size()); row++) { ramInfo_RowData& rowData = RowDataVector->at(row); - rowData.Update(SearchThread->GetSearchByteType()); + rowData.Update(*emuThread->NDS, SearchThread->GetSearchByteType()); if (ui->ramTable->item(row, ramInfo_Address) == nullptr) { @@ -186,7 +186,7 @@ void RAMInfoDialog::on_ramTable_itemChanged(QTableWidgetItem *item) s32 itemValue = item->text().toInt(); if (rowData.Value != itemValue) - rowData.SetValue(itemValue); + rowData.SetValue(*emuThread->NDS, itemValue); } /** @@ -241,14 +241,14 @@ void RAMSearchThread::run() if (SearchMode == ramInfoSTh_SearchAll || RowDataVector->size() == 0) { // First search mode - for (u32 addr = 0x02000000; SearchRunning && addr < 0x02000000+NDS::MainRAMMaxSize; addr += SearchByteType) + for (u32 addr = 0x02000000; SearchRunning && addr < 0x02000000+MainRAMMaxSize; addr += SearchByteType) { - const s32& value = GetMainRAMValue(addr, SearchByteType); + const s32& value = GetMainRAMValue(*emuThread->NDS, addr, SearchByteType); RowDataVector->push_back({ addr, value, value }); // A solution to prevent to call too many slot. - u32 newProgress = (int)((addr-0x02000000) / (NDS::MainRAMMaxSize-1.0f) * 100); + u32 newProgress = (int)((addr-0x02000000) / (MainRAMMaxSize-1.0f) * 100); if (progress < newProgress) { progress = newProgress; @@ -264,7 +264,7 @@ void RAMSearchThread::run() for (u32 row = 0; SearchRunning && row < RowDataVector->size(); row++) { const u32& addr = RowDataVector->at(row).Address; - const s32& value = GetMainRAMValue(addr, SearchByteType); + const s32& value = GetMainRAMValue(*emuThread->NDS, addr, SearchByteType); if (SearchValue == value) newRowDataVector->push_back({ addr, value, value }); diff --git a/src/frontend/qt_sdl/RAMInfoDialog.h b/src/frontend/qt_sdl/RAMInfoDialog.h index adc9b28..2a5b162 100644 --- a/src/frontend/qt_sdl/RAMInfoDialog.h +++ b/src/frontend/qt_sdl/RAMInfoDialog.h @@ -32,6 +32,7 @@ namespace Ui { class RAMInfoDialog; } class RAMInfoDialog; class RAMSearchThread; class RAMUpdateThread; +class EmuThread; enum ramInfo_ByteType { @@ -53,7 +54,7 @@ enum ramInfo_Previous }; -melonDS::s32 GetMainRAMValue(const melonDS::u32& addr, const ramInfo_ByteType& byteType); +melonDS::s32 GetMainRAMValue(melonDS::NDS& nds, const melonDS::u32& addr, const ramInfo_ByteType& byteType); struct ramInfo_RowData { @@ -61,14 +62,14 @@ struct ramInfo_RowData melonDS::s32 Value; melonDS::s32 Previous; - void Update(const ramInfo_ByteType& byteType) + void Update(melonDS::NDS& nds, const ramInfo_ByteType& byteType) { - Value = GetMainRAMValue(Address, byteType); + Value = GetMainRAMValue(nds, Address, byteType); } - void SetValue(const melonDS::s32& value) + void SetValue(melonDS::NDS& nds, const melonDS::s32& value) { - melonDS::NDS::MainRAM[Address&melonDS::NDS::MainRAMMask] = (melonDS::u32)value; + nds.MainRAM[Address&nds.MainRAMMask] = (melonDS::u32)value; Value = value; } }; @@ -78,11 +79,11 @@ class RAMInfoDialog : public QDialog Q_OBJECT public: - explicit RAMInfoDialog(QWidget* parent); + explicit RAMInfoDialog(QWidget* parent, EmuThread* emuThread); ~RAMInfoDialog(); static RAMInfoDialog* currentDlg; - static RAMInfoDialog* openDlg(QWidget* parent) + static RAMInfoDialog* openDlg(QWidget* parent, EmuThread* emuThread) { if (currentDlg) { @@ -90,7 +91,7 @@ public: return currentDlg; } - currentDlg = new RAMInfoDialog(parent); + currentDlg = new RAMInfoDialog(parent, emuThread); currentDlg->show(); return currentDlg; } @@ -118,6 +119,7 @@ private slots: void SetProgressbarValue(const melonDS::u32& value); private: + EmuThread* emuThread; Ui::RAMInfoDialog* ui; RAMSearchThread* SearchThread; diff --git a/src/frontend/qt_sdl/ROMInfoDialog.cpp b/src/frontend/qt_sdl/ROMInfoDialog.cpp index 6a46b18..0f10b2f 100644 --- a/src/frontend/qt_sdl/ROMInfoDialog.cpp +++ b/src/frontend/qt_sdl/ROMInfoDialog.cpp @@ -42,14 +42,13 @@ QString QStringBytes(u64 num) ROMInfoDialog* ROMInfoDialog::currentDlg = nullptr; -ROMInfoDialog::ROMInfoDialog(QWidget* parent) : QDialog(parent), ui(new Ui::ROMInfoDialog) +ROMInfoDialog::ROMInfoDialog(QWidget* parent, const melonDS::NDSCart::CartCommon& rom) : QDialog(parent), ui(new Ui::ROMInfoDialog) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); - const NDSBanner* banner = NDS::NDSCartSlot->GetCart()->Banner(); - const NDSHeader& header = NDS::NDSCartSlot->GetCart()->GetHeader(); - + const NDSBanner* banner = rom.Banner(); + const NDSHeader& header = rom.GetHeader(); u32 iconData[32 * 32]; ROMManager::ROMIcon(banner->Icon, banner->Palette, iconData); iconImage = QImage(reinterpret_cast(iconData), 32, 32, QImage::Format_RGBA8888).copy(); diff --git a/src/frontend/qt_sdl/ROMInfoDialog.h b/src/frontend/qt_sdl/ROMInfoDialog.h index 7316e98..f7e3b5f 100644 --- a/src/frontend/qt_sdl/ROMInfoDialog.h +++ b/src/frontend/qt_sdl/ROMInfoDialog.h @@ -29,17 +29,17 @@ namespace Ui { class ROMInfoDialog; } class ROMInfoDialog; - +namespace melonDS::NDSCart { class CartCommon; } class ROMInfoDialog : public QDialog { Q_OBJECT public: - explicit ROMInfoDialog(QWidget* parent); + explicit ROMInfoDialog(QWidget* parent, const melonDS::NDSCart::CartCommon& rom); ~ROMInfoDialog(); static ROMInfoDialog* currentDlg; - static ROMInfoDialog* openDlg(QWidget* parent) + static ROMInfoDialog* openDlg(QWidget* parent, const melonDS::NDSCart::CartCommon& rom) { if (currentDlg) { @@ -47,7 +47,7 @@ public: return currentDlg; } - currentDlg = new ROMInfoDialog(parent); + currentDlg = new ROMInfoDialog(parent, rom); currentDlg->open(); return currentDlg; } diff --git a/src/frontend/qt_sdl/ROMManager.cpp b/src/frontend/qt_sdl/ROMManager.cpp index 9584c38..2c0cee2 100644 --- a/src/frontend/qt_sdl/ROMManager.cpp +++ b/src/frontend/qt_sdl/ROMManager.cpp @@ -44,6 +44,7 @@ #include "RTC.h" #include "DSi_I2C.h" #include "FreeBIOS.h" +#include "main.h" using std::make_unique; using std::pair; @@ -316,7 +317,7 @@ bool SavestateExists(int slot) return Platform::FileExists(ssfile); } -bool LoadState(const std::string& filename) +bool LoadState(NDS& nds, const std::string& filename) { FILE* file = fopen(filename.c_str(), "rb"); if (file == nullptr) @@ -333,7 +334,7 @@ bool LoadState(const std::string& filename) return false; } - if (!NDS::DoSavestate(backup.get()) || backup->Error) + if (!nds.DoSavestate(backup.get()) || backup->Error) { // Back up the emulator's state. If that failed... Platform::Log(Platform::LogLevel::Error, "Failed to back up state, aborting load (from \"%s\")\n", filename.c_str()); fclose(file); @@ -365,7 +366,7 @@ bool LoadState(const std::string& filename) // Get ready to load the state from the buffer into the emulator std::unique_ptr state = std::make_unique(buffer.data(), size, false); - if (!NDS::DoSavestate(state.get()) || state->Error) + if (!nds.DoSavestate(state.get()) || state->Error) { // If we couldn't load the savestate from the buffer... Platform::Log(Platform::LogLevel::Error, "Failed to load state file \"%s\" into emulator\n", filename.c_str()); return false; @@ -390,7 +391,7 @@ bool LoadState(const std::string& filename) return true; } -bool SaveState(const std::string& filename) +bool SaveState(NDS& nds, const std::string& filename) { FILE* file = fopen(filename.c_str(), "wb"); @@ -407,7 +408,7 @@ bool SaveState(const std::string& filename) } // Write the savestate to the in-memory buffer - NDS::DoSavestate(&state); + nds.DoSavestate(&state); if (state.Error) { @@ -439,7 +440,7 @@ bool SaveState(const std::string& filename) return true; } -void UndoStateLoad() +void UndoStateLoad(NDS& nds) { if (!SavestateLoaded || !BackupState) return; @@ -448,7 +449,7 @@ void UndoStateLoad() // pray that this works // what do we do if it doesn't??? // but it should work. - NDS::DoSavestate(BackupState.get()); + nds.DoSavestate(BackupState.get()); if (NDSSave && (!PreviousSaveFile.empty())) { @@ -457,36 +458,264 @@ void UndoStateLoad() } -void UnloadCheats() +void UnloadCheats(NDS& nds) { if (CheatFile) { delete CheatFile; CheatFile = nullptr; - NDS::AREngine->SetCodeFile(nullptr); + nds.AREngine.SetCodeFile(nullptr); } } -void LoadCheats() +void LoadCheats(NDS& nds) { - UnloadCheats(); + UnloadCheats(nds); std::string filename = GetAssetPath(false, Config::CheatFilePath, ".mch"); // TODO: check for error (malformed cheat file, ...) CheatFile = new ARCodeFile(filename); - NDS::AREngine->SetCodeFile(CheatsOn ? CheatFile : nullptr); + nds.AREngine.SetCodeFile(CheatsOn ? CheatFile : nullptr); } -void LoadBIOSFiles() +std::optional> LoadARM9BIOS() noexcept +{ + if (FileHandle* f = OpenLocalFile(Config::BIOS9Path, Read)) + { + std::array bios {}; + FileRewind(f); + FileRead(bios.data(), sizeof(bios), 1, f); + CloseFile(f); + Log(Info, "ARM9 BIOS loaded from %s\n", Config::BIOS9Path.c_str()); + return bios; + } + + Log(Warn, "ARM9 BIOS not found\n"); + return std::nullopt; +} + +std::optional> LoadARM7BIOS() noexcept +{ + if (FileHandle* f = OpenLocalFile(Config::BIOS7Path, Read)) + { + std::array bios {}; + FileRead(bios.data(), sizeof(bios), 1, f); + CloseFile(f); + Log(Info, "ARM7 BIOS loaded from %s\n", Config::BIOS7Path.c_str()); + return bios; + } + + Log(Warn, "ARM7 BIOS not found\n"); + return std::nullopt; +} + +std::optional> LoadDSiARM9BIOS() noexcept +{ + if (FileHandle* f = OpenLocalFile(Config::DSiBIOS9Path, Read)) + { + std::array bios {}; + FileRead(bios.data(), sizeof(bios), 1, f); + CloseFile(f); + Log(Info, "ARM9i BIOS loaded from %s\n", Config::DSiBIOS9Path.c_str()); + return bios; + } + + Log(Warn, "ARM9i BIOS not found\n"); + return std::nullopt; +} + +std::optional> LoadDSiARM7BIOS() noexcept +{ + if (FileHandle* f = OpenLocalFile(Config::DSiBIOS7Path, Read)) + { + std::array bios {}; + FileRead(bios.data(), sizeof(bios), 1, f); + CloseFile(f); + Log(Info, "ARM7i BIOS loaded from %s\n", Config::DSiBIOS7Path.c_str()); + return bios; + } + + Log(Warn, "ARM7i BIOS not found\n"); + return std::nullopt; +} + +Firmware GenerateFirmware(int type) noexcept +{ + // Construct the default firmware... + string settingspath; + Firmware firmware = Firmware(type); + assert(firmware.Buffer() != nullptr); + + // If using generated firmware, we keep the wi-fi settings on the host disk separately. + // Wi-fi access point data includes Nintendo WFC settings, + // and if we didn't keep them then the player would have to reset them in each session. + // We don't need to save the whole firmware, just the part that may actually change. + if (FileHandle* f = OpenLocalFile(Config::WifiSettingsPath, Read)) + {// If we have Wi-fi settings to load... + constexpr unsigned TOTAL_WFC_SETTINGS_SIZE = 3 * (sizeof(Firmware::WifiAccessPoint) + sizeof(Firmware::ExtendedWifiAccessPoint)); + + if (!FileRead(firmware.GetExtendedAccessPointPosition(), TOTAL_WFC_SETTINGS_SIZE, 1, f)) + { // If we couldn't read the Wi-fi settings from this file... + Log(Warn, "Failed to read Wi-fi settings from \"%s\"; using defaults instead\n", Config::WifiSettingsPath.c_str()); + + // The access point and extended access point segments might + // be in different locations depending on the firmware revision, + // but our generated firmware always keeps them next to each other. + // (Extended access points first, then regular ones.) + firmware.GetAccessPoints() = { + Firmware::WifiAccessPoint(type), + Firmware::WifiAccessPoint(), + Firmware::WifiAccessPoint(), + }; + + firmware.GetExtendedAccessPoints() = { + Firmware::ExtendedWifiAccessPoint(), + Firmware::ExtendedWifiAccessPoint(), + Firmware::ExtendedWifiAccessPoint(), + }; + firmware.UpdateChecksums(); + CloseFile(f); + } + } + + CustomizeFirmware(firmware); + + // If we don't have Wi-fi settings to load, + // then the defaults will have already been populated by the constructor. + return firmware; +} + +std::optional LoadFirmware(int type) noexcept +{ + const string& firmwarepath = type == 1 ? Config::DSiFirmwarePath : Config::FirmwarePath; + + Log(Debug, "SPI firmware: loading from file %s\n", firmwarepath.c_str()); + + FileHandle* file = OpenLocalFile(firmwarepath, Read); + + if (!file) + { + Log(Error, "SPI firmware: couldn't open firmware file!\n"); + return std::nullopt; + } + Firmware firmware(file); + CloseFile(file); + + if (!firmware.Buffer()) + { + Log(Error, "SPI firmware: couldn't read firmware file!\n"); + return std::nullopt; + } + + CustomizeFirmware(firmware); + + return firmware; +} + + +std::optional LoadNAND(const std::array& arm7ibios) noexcept +{ + FileHandle* nandfile = OpenLocalFile(Config::DSiNANDPath, ReadWriteExisting); + if (!nandfile) + return std::nullopt; + + DSi_NAND::NANDImage nandImage(nandfile, &arm7ibios[0x8308]); + if (!nandImage) + { + Log(Error, "Failed to parse DSi NAND\n"); + return std::nullopt; + // the NANDImage takes ownership of the FileHandle, no need to clean it up here + } + + // scoped so that mount isn't alive when we move the NAND image to DSi::NANDImage + { + auto mount = DSi_NAND::NANDMount(nandImage); + if (!mount) + { + Log(Error, "Failed to mount DSi NAND\n"); + return std::nullopt; + } + + DSi_NAND::DSiFirmwareSystemSettings settings {}; + if (!mount.ReadUserData(settings)) + { + Log(Error, "Failed to read DSi NAND user data\n"); + return std::nullopt; + } + + // override user settings, if needed + if (Config::FirmwareOverrideSettings) + { + // we store relevant strings as UTF-8, so we need to convert them to UTF-16 + auto converter = wstring_convert, char16_t>{}; + + // setting up username + std::u16string username = converter.from_bytes(Config::FirmwareUsername); + size_t usernameLength = std::min(username.length(), (size_t) 10); + memset(&settings.Nickname, 0, sizeof(settings.Nickname)); + memcpy(&settings.Nickname, username.data(), usernameLength * sizeof(char16_t)); + + // setting language + settings.Language = static_cast(Config::FirmwareLanguage); + + // setting up color + settings.FavoriteColor = Config::FirmwareFavouriteColour; + + // setting up birthday + settings.BirthdayMonth = Config::FirmwareBirthdayMonth; + settings.BirthdayDay = Config::FirmwareBirthdayDay; + + // setup message + std::u16string message = converter.from_bytes(Config::FirmwareMessage); + size_t messageLength = std::min(message.length(), (size_t) 26); + memset(&settings.Message, 0, sizeof(settings.Message)); + memcpy(&settings.Message, message.data(), messageLength * sizeof(char16_t)); + + // TODO: make other items configurable? + } + + // fix touchscreen coords + settings.TouchCalibrationADC1 = {0, 0}; + settings.TouchCalibrationPixel1 = {0, 0}; + settings.TouchCalibrationADC2 = {255 << 4, 191 << 4}; + settings.TouchCalibrationPixel2 = {255, 191}; + + settings.UpdateHash(); + + if (!mount.ApplyUserData(settings)) + { + Log(LogLevel::Error, "Failed to write patched DSi NAND user data\n"); + return std::nullopt; + } + } + + return nandImage; +} + +constexpr int imgsizes[] = {0, 256, 512, 1024, 2048, 4096}; +std::optional LoadDSiSDCard() noexcept +{ + if (!Config::DSiSDEnable) + return std::nullopt; + + return FATStorage( + Config::DSiSDPath, + imgsizes[Config::DSiSDSize], + Config::DSiSDReadOnly, + Config::DSiSDFolderSync ? Config::DSiSDFolderPath : "" + ); +} + +void LoadBIOSFiles(NDS& nds) { if (Config::ExternalBIOSEnable) { if (FileHandle* f = Platform::OpenLocalFile(Config::BIOS9Path, FileMode::Read)) { FileRewind(f); - FileRead(NDS::ARM9BIOS, sizeof(NDS::ARM9BIOS), 1, f); + FileRead(nds.ARM9BIOS, sizeof(NDS::ARM9BIOS), 1, f); Log(LogLevel::Info, "ARM9 BIOS loaded from %s\n", Config::BIOS9Path.c_str()); Platform::CloseFile(f); @@ -496,12 +725,12 @@ void LoadBIOSFiles() Log(LogLevel::Warn, "ARM9 BIOS not found\n"); for (int i = 0; i < 16; i++) - ((u32*)NDS::ARM9BIOS)[i] = 0xE7FFDEFF; + ((u32*)nds.ARM9BIOS)[i] = 0xE7FFDEFF; } if (FileHandle* f = Platform::OpenLocalFile(Config::BIOS7Path, FileMode::Read)) { - FileRead(NDS::ARM7BIOS, sizeof(NDS::ARM7BIOS), 1, f); + FileRead(nds.ARM7BIOS, sizeof(NDS::ARM7BIOS), 1, f); Log(LogLevel::Info, "ARM7 BIOS loaded from\n", Config::BIOS7Path.c_str()); Platform::CloseFile(f); @@ -511,21 +740,22 @@ void LoadBIOSFiles() Log(LogLevel::Warn, "ARM7 BIOS not found\n"); for (int i = 0; i < 16; i++) - ((u32*)NDS::ARM7BIOS)[i] = 0xE7FFDEFF; + ((u32*)nds.ARM7BIOS)[i] = 0xE7FFDEFF; } } else { Log(LogLevel::Info, "Using built-in ARM7 and ARM9 BIOSes\n"); - memcpy(NDS::ARM9BIOS, bios_arm9_bin, sizeof(bios_arm9_bin)); - memcpy(NDS::ARM7BIOS, bios_arm7_bin, sizeof(bios_arm7_bin)); + memcpy(nds.ARM9BIOS, bios_arm9_bin, sizeof(bios_arm9_bin)); + memcpy(nds.ARM7BIOS, bios_arm7_bin, sizeof(bios_arm7_bin)); } if (Config::ConsoleType == 1) { + DSi& dsi = static_cast(nds); if (FileHandle* f = Platform::OpenLocalFile(Config::DSiBIOS9Path, FileMode::Read)) { - FileRead(DSi::ARM9iBIOS, sizeof(DSi::ARM9iBIOS), 1, f); + FileRead(dsi.ARM9iBIOS, sizeof(DSi::ARM9iBIOS), 1, f); Log(LogLevel::Info, "ARM9i BIOS loaded from %s\n", Config::DSiBIOS9Path.c_str()); Platform::CloseFile(f); @@ -535,13 +765,13 @@ void LoadBIOSFiles() Log(LogLevel::Warn, "ARM9i BIOS not found\n"); for (int i = 0; i < 16; i++) - ((u32*)DSi::ARM9iBIOS)[i] = 0xE7FFDEFF; + ((u32*)dsi.ARM9iBIOS)[i] = 0xE7FFDEFF; } if (FileHandle* f = Platform::OpenLocalFile(Config::DSiBIOS7Path, FileMode::Read)) { // TODO: check if the first 32 bytes are crapoed - FileRead(DSi::ARM7iBIOS, sizeof(DSi::ARM7iBIOS), 1, f); + FileRead(dsi.ARM7iBIOS, sizeof(DSi::ARM7iBIOS), 1, f); Log(LogLevel::Info, "ARM7i BIOS loaded from %s\n", Config::DSiBIOS7Path.c_str()); CloseFile(f); @@ -551,14 +781,14 @@ void LoadBIOSFiles() Log(LogLevel::Warn, "ARM7i BIOS not found\n"); for (int i = 0; i < 16; i++) - ((u32*)DSi::ARM7iBIOS)[i] = 0xE7FFDEFF; + ((u32*)dsi.ARM7iBIOS)[i] = 0xE7FFDEFF; } if (!Config::DSiFullBIOSBoot) { // herp - *(u32*)&DSi::ARM9iBIOS[0] = 0xEAFFFFFE; - *(u32*)&DSi::ARM7iBIOS[0] = 0xEAFFFFFE; + *(u32*)&dsi.ARM9iBIOS[0] = 0xEAFFFFFE; + *(u32*)&dsi.ARM7iBIOS[0] = 0xEAFFFFFE; // TODO!!!! // hax the upper 32K out of the goddamn DSi @@ -567,11 +797,11 @@ void LoadBIOSFiles() } } -void EnableCheats(bool enable) +void EnableCheats(NDS& nds, bool enable) { CheatsOn = enable; if (CheatFile) - NDS::AREngine->SetCodeFile(CheatsOn ? CheatFile : nullptr); + nds.AREngine.SetCodeFile(CheatsOn ? CheatFile : nullptr); } ARCodeFile* GetCheatFile() @@ -580,42 +810,44 @@ ARCodeFile* GetCheatFile() } -void SetBatteryLevels() +void SetBatteryLevels(NDS& nds) { - if (NDS::ConsoleType == 1) + if (nds.ConsoleType == 1) { - DSi::I2C->GetBPTWL()->SetBatteryLevel(Config::DSiBatteryLevel); - DSi::I2C->GetBPTWL()->SetBatteryCharging(Config::DSiBatteryCharging); + auto& dsi = static_cast(nds); + dsi.I2C.GetBPTWL()->SetBatteryLevel(Config::DSiBatteryLevel); + dsi.I2C.GetBPTWL()->SetBatteryCharging(Config::DSiBatteryCharging); } else { - NDS::SPI->GetPowerMan()->SetBatteryLevelOkay(Config::DSBatteryLevelOkay); + nds.SPI.GetPowerMan()->SetBatteryLevelOkay(Config::DSBatteryLevelOkay); } } -void SetDateTime() +void SetDateTime(NDS& nds) { QDateTime hosttime = QDateTime::currentDateTime(); QDateTime time = hosttime.addSecs(Config::RTCOffset); - NDS::RTC->SetDateTime(time.date().year(), time.date().month(), time.date().day(), + nds.RTC.SetDateTime(time.date().year(), time.date().month(), time.date().day(), time.time().hour(), time.time().minute(), time.time().second()); } -void Reset() +void Reset(EmuThread* thread) { - NDS::SetConsoleType(Config::ConsoleType); - if (Config::ConsoleType == 1) EjectGBACart(); - LoadBIOSFiles(); + thread->RecreateConsole(); + + if (Config::ConsoleType == 1) EjectGBACart(*thread->NDS); + LoadBIOSFiles(*thread->NDS); - InstallFirmware(); + InstallFirmware(*thread->NDS); if (Config::ConsoleType == 1) { - InstallNAND(&DSi::ARM7iBIOS[0x8308]); + InstallNAND(static_cast(*thread->NDS)); } - NDS::Reset(); - SetBatteryLevels(); - SetDateTime(); + thread->NDS->Reset(); + SetBatteryLevels(*thread->NDS); + SetDateTime(*thread->NDS); if ((CartType != -1) && NDSSave) { @@ -659,27 +891,27 @@ void Reset() if (!BaseROMName.empty()) { - if (Config::DirectBoot || NDS::NeedsDirectBoot()) + if (Config::DirectBoot || thread->NDS->NeedsDirectBoot()) { - NDS::SetupDirectBoot(BaseROMName); + thread->NDS->SetupDirectBoot(BaseROMName); } } } -bool LoadBIOS() +bool LoadBIOS(EmuThread* thread) { - NDS::SetConsoleType(Config::ConsoleType); + thread->RecreateConsole(); - LoadBIOSFiles(); + LoadBIOSFiles(*thread->NDS); - if (!InstallFirmware()) + if (!InstallFirmware(*thread->NDS)) return false; - if (Config::ConsoleType == 1 && !InstallNAND(&DSi::ARM7iBIOS[0x8308])) + if (Config::ConsoleType == 1 && !InstallNAND(static_cast(*thread->NDS))) return false; - if (NDS::NeedsDirectBoot()) + if (thread->NDS->NeedsDirectBoot()) return false; /*if (NDSSave) delete NDSSave; @@ -690,9 +922,9 @@ bool LoadBIOS() BaseROMName = ""; BaseAssetName = "";*/ - NDS::Reset(); - SetBatteryLevels(); - SetDateTime(); + thread->NDS->Reset(); + SetBatteryLevels(*thread->NDS); + SetDateTime(*thread->NDS); return true; } @@ -884,7 +1116,7 @@ pair, string> GenerateDefaultFirmware() return std::make_pair(std::move(firmware), std::move(wfcsettingspath)); } -void LoadUserSettingsFromConfig(Firmware& firmware) +void CustomizeFirmware(Firmware& firmware) noexcept { auto& currentData = firmware.GetEffectiveUserData(); @@ -992,13 +1224,13 @@ static Platform::FileHandle* OpenNANDFile() noexcept return nandfile; } -bool InstallNAND(const u8* es_keyY) +bool InstallNAND(DSi& dsi) { Platform::FileHandle* nandfile = OpenNANDFile(); if (!nandfile) return false; - DSi_NAND::NANDImage nandImage(nandfile, es_keyY); + DSi_NAND::NANDImage nandImage(nandfile, &dsi.ARM7iBIOS[0x8308]); if (!nandImage) { Log(LogLevel::Error, "Failed to parse DSi NAND\n"); @@ -1067,11 +1299,11 @@ bool InstallNAND(const u8* es_keyY) } } - DSi::NANDImage = std::make_unique(std::move(nandImage)); + dsi.NANDImage = std::make_unique(std::move(nandImage)); return true; } -bool InstallFirmware() +bool InstallFirmware(NDS& nds) { FirmwareSave.reset(); unique_ptr firmware; @@ -1098,15 +1330,15 @@ bool InstallFirmware() if (Config::FirmwareOverrideSettings) { - LoadUserSettingsFromConfig(*firmware); + CustomizeFirmware(*firmware); } FirmwareSave = std::make_unique(firmwarepath); - return NDS::SPI->GetFirmwareMem()->InstallFirmware(std::move(firmware)); + return nds.SPI.GetFirmwareMem()->InstallFirmware(std::move(firmware)); } -bool LoadROM(QStringList filepath, bool reset) +bool LoadROM(EmuThread* emuthread, QStringList filepath, bool reset) { if (filepath.empty()) return false; @@ -1201,22 +1433,22 @@ bool LoadROM(QStringList filepath, bool reset) BaseROMName = romname; BaseAssetName = romname.substr(0, romname.rfind('.')); - if (!InstallFirmware()) + emuthread->RecreateConsole(); + if (!InstallFirmware(*emuthread->NDS)) { return false; } if (reset) { - NDS::SetConsoleType(Config::ConsoleType); - NDS::EjectCart(); - LoadBIOSFiles(); + emuthread->NDS->EjectCart(); + LoadBIOSFiles(*emuthread->NDS); if (Config::ConsoleType == 1) - InstallNAND(&DSi::ARM7iBIOS[0x8308]); + InstallNAND(static_cast(*emuthread->NDS)); - NDS::Reset(); - SetBatteryLevels(); - SetDateTime(); + emuthread->NDS->Reset(); + SetBatteryLevels(*emuthread->NDS); + SetDateTime(*emuthread->NDS); } u32 savelen = 0; @@ -1238,12 +1470,12 @@ bool LoadROM(QStringList filepath, bool reset) CloseFile(sav); } - bool res = NDS::LoadCart(filedata, filelen, savedata, savelen); + bool res = emuthread->NDS->LoadCart(filedata, filelen, savedata, savelen); if (res && reset) { - if (Config::DirectBoot || NDS::NeedsDirectBoot()) + if (Config::DirectBoot || emuthread->NDS->NeedsDirectBoot()) { - NDS::SetupDirectBoot(romname); + emuthread->NDS->SetupDirectBoot(romname); } } @@ -1252,7 +1484,7 @@ bool LoadROM(QStringList filepath, bool reset) CartType = 0; NDSSave = new SaveManager(savname); - LoadCheats(); + LoadCheats(*emuthread->NDS); } if (savedata) delete[] savedata; @@ -1260,14 +1492,14 @@ bool LoadROM(QStringList filepath, bool reset) return res; } -void EjectCart() +void EjectCart(NDS& nds) { if (NDSSave) delete NDSSave; NDSSave = nullptr; - UnloadCheats(); + UnloadCheats(nds); - NDS::EjectCart(); + nds.EjectCart(); CartType = -1; BaseROMDir = ""; @@ -1295,7 +1527,7 @@ QString CartLabel() } -bool LoadGBAROM(QStringList filepath) +bool LoadGBAROM(NDS& nds, QStringList filepath) { if (Config::ConsoleType == 1) return false; if (filepath.empty()) return false; @@ -1408,7 +1640,7 @@ bool LoadGBAROM(QStringList filepath) CloseFile(sav); } - bool res = NDS::LoadGBACart(filedata, filelen, savedata, savelen); + bool res = nds.LoadGBACart(filedata, filelen, savedata, savelen); if (res) { @@ -1421,14 +1653,14 @@ bool LoadGBAROM(QStringList filepath) return res; } -void LoadGBAAddon(int type) +void LoadGBAAddon(NDS& nds, int type) { if (Config::ConsoleType == 1) return; if (GBASave) delete GBASave; GBASave = nullptr; - NDS::LoadGBAAddon(type); + nds.LoadGBAAddon(type); GBACartType = type; BaseGBAROMDir = ""; @@ -1436,12 +1668,12 @@ void LoadGBAAddon(int type) BaseGBAAssetName = ""; } -void EjectGBACart() +void EjectGBACart(NDS& nds) { if (GBASave) delete GBASave; GBASave = nullptr; - NDS::EjectGBACart(); + nds.EjectGBACart(); GBACartType = -1; BaseGBAROMDir = ""; @@ -1471,7 +1703,7 @@ QString GBACartLabel() return ret; } - case NDS::GBAAddon_RAMExpansion: + case GBAAddon_RAMExpansion: return "Memory expansion"; } diff --git a/src/frontend/qt_sdl/ROMManager.h b/src/frontend/qt_sdl/ROMManager.h index 9228560..2163a68 100644 --- a/src/frontend/qt_sdl/ROMManager.h +++ b/src/frontend/qt_sdl/ROMManager.h @@ -24,10 +24,19 @@ #include "AREngine.h" #include "DSi_NAND.h" +#include "MemConstants.h" +#include #include #include #include +namespace melonDS +{ +class NDS; +class DSi; +class FATStorage; +} +class EmuThread; namespace ROMManager { @@ -37,30 +46,41 @@ extern SaveManager* GBASave; extern std::unique_ptr FirmwareSave; QString VerifySetup(); -void Reset(); -bool LoadBIOS(); +void Reset(EmuThread* thread); +bool LoadBIOS(EmuThread* thread); void ClearBackupState(); -bool InstallFirmware(); -bool InstallNAND(const u8* es_keyY); -bool LoadROM(QStringList filepath, bool reset); -void EjectCart(); +std::optional> LoadARM9BIOS() noexcept; +std::optional> LoadARM7BIOS() noexcept; +std::optional> LoadDSiARM9BIOS() noexcept; +std::optional> LoadDSiARM7BIOS() noexcept; +std::optional LoadDSiSDCard() noexcept; +void CustomizeFirmware(Firmware& firmware) noexcept; +Firmware GenerateFirmware(int type) noexcept; +/// Loads and customizes a firmware image based on the values in Config +std::optional LoadFirmware(int type) noexcept; +/// Loads and customizes a NAND image based on the values in Config +std::optional LoadNAND(const std::array& arm7ibios) noexcept; +bool InstallFirmware(NDS& nds); +bool InstallNAND(DSi& dsi); +bool LoadROM(EmuThread*, QStringList filepath, bool reset); +void EjectCart(NDS& nds); bool CartInserted(); QString CartLabel(); -bool LoadGBAROM(QStringList filepath); -void LoadGBAAddon(int type); -void EjectGBACart(); +bool LoadGBAROM(NDS& nds, QStringList filepath); +void LoadGBAAddon(NDS& nds, int type); +void EjectGBACart(NDS& nds); bool GBACartInserted(); QString GBACartLabel(); std::string GetSavestateName(int slot); bool SavestateExists(int slot); -bool LoadState(const std::string& filename); -bool SaveState(const std::string& filename); -void UndoStateLoad(); +bool LoadState(NDS& nds, const std::string& filename); +bool SaveState(NDS& nds, const std::string& filename); +void UndoStateLoad(NDS& nds); -void EnableCheats(bool enable); +void EnableCheats(NDS& nds, bool enable); ARCodeFile* GetCheatFile(); void ROMIcon(const u8 (&data)[512], const u16 (&palette)[16], u32 (&iconRef)[32*32]); diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp index 4286498..54a6f14 100644 --- a/src/frontend/qt_sdl/main.cpp +++ b/src/frontend/qt_sdl/main.cpp @@ -203,6 +203,30 @@ EmuThread::EmuThread(QObject* parent) : QThread(parent) static_cast(mainWindow->panel)->transferLayout(this); } +std::unique_ptr EmuThread::CreateConsole() +{ + if (Config::ConsoleType == 1) + { + return std::make_unique(); + } + + return std::make_unique(); +} + +void EmuThread::RecreateConsole() +{ + if (!NDS || NDS->ConsoleType != Config::ConsoleType) + { + NDS = nullptr; // To ensure the destructor is called before a new one is created + NDS::Current = nullptr; + + NDS = CreateConsole(); + // TODO: Insert ROMs + NDS::Current = NDS.get(); + } +} + + void EmuThread::updateScreenSettings(bool filter, const WindowInfo& windowInfo, int numScreens, int* screenKind, float* screenMatrix) { screenSettingsLock.lock(); @@ -318,7 +342,7 @@ void EmuThread::run() u32 mainScreenPos[3]; Platform::FileHandle* file; - NDS::Init(); + RecreateConsole(); mainScreenPos[0] = 0; mainScreenPos[1] = 0; @@ -340,10 +364,10 @@ void EmuThread::run() videoRenderer = 0; } - NDS::GPU->InitRenderer(videoRenderer); - NDS::GPU->SetRenderSettings(videoRenderer, videoSettings); + NDS->GPU.InitRenderer(videoRenderer); + NDS->GPU.SetRenderSettings(videoRenderer, videoSettings); - NDS::SPU->SetInterpolation(Config::AudioInterp); + NDS->SPU.SetInterpolation(Config::AudioInterp); Input::Init(); @@ -362,7 +386,7 @@ void EmuThread::run() RTC::StateData state; Platform::FileRead(&state, sizeof(state), 1, file); Platform::CloseFile(file); - NDS::RTC->SetState(state); + NDS->RTC.SetState(state); } char melontitle[100]; @@ -384,8 +408,7 @@ void EmuThread::run() if (Input::HotkeyPressed(HK_SolarSensorDecrease)) { - assert(NDS::GBACartSlot != nullptr); - int level = NDS::GBACartSlot->SetInput(GBACart::Input_SolarSensorDown, true); + int level = NDS->GBACartSlot.SetInput(GBACart::Input_SolarSensorDown, true); if (level != -1) { char msg[64]; @@ -395,8 +418,7 @@ void EmuThread::run() } if (Input::HotkeyPressed(HK_SolarSensorIncrease)) { - assert(NDS::GBACartSlot != nullptr); - int level = NDS::GBACartSlot->SetInput(GBACart::Input_SolarSensorUp, true); + int level = NDS->GBACartSlot.SetInput(GBACart::Input_SolarSensorUp, true); if (level != -1) { char msg[64]; @@ -405,40 +427,41 @@ void EmuThread::run() } } - if (NDS::ConsoleType == 1) + if (NDS->ConsoleType == 1) { + DSi& dsi = static_cast(*NDS); double currentTime = SDL_GetPerformanceCounter() * perfCountsSec; // Handle power button if (Input::HotkeyDown(HK_PowerButton)) { - DSi::I2C->GetBPTWL()->SetPowerButtonHeld(currentTime); + dsi.I2C.GetBPTWL()->SetPowerButtonHeld(currentTime); } else if (Input::HotkeyReleased(HK_PowerButton)) { - DSi::I2C->GetBPTWL()->SetPowerButtonReleased(currentTime); + dsi.I2C.GetBPTWL()->SetPowerButtonReleased(currentTime); } // Handle volume buttons if (Input::HotkeyDown(HK_VolumeUp)) { - DSi::I2C->GetBPTWL()->SetVolumeSwitchHeld(DSi::I2C->GetBPTWL()->volumeKey_Up); + dsi.I2C.GetBPTWL()->SetVolumeSwitchHeld(DSi_BPTWL::volumeKey_Up); } else if (Input::HotkeyReleased(HK_VolumeUp)) { - DSi::I2C->GetBPTWL()->SetVolumeSwitchReleased(DSi::I2C->GetBPTWL()->volumeKey_Up); + dsi.I2C.GetBPTWL()->SetVolumeSwitchReleased(DSi_BPTWL::volumeKey_Up); } if (Input::HotkeyDown(HK_VolumeDown)) { - DSi::I2C->GetBPTWL()->SetVolumeSwitchHeld(DSi::I2C->GetBPTWL()->volumeKey_Down); + dsi.I2C.GetBPTWL()->SetVolumeSwitchHeld(DSi_BPTWL::volumeKey_Down); } else if (Input::HotkeyReleased(HK_VolumeDown)) { - DSi::I2C->GetBPTWL()->SetVolumeSwitchReleased(DSi::I2C->GetBPTWL()->volumeKey_Down); + dsi.I2C.GetBPTWL()->SetVolumeSwitchReleased(DSi_BPTWL::volumeKey_Down); } - DSi::I2C->GetBPTWL()->ProcessVolumeSwitchInput(currentTime); + dsi.I2C.GetBPTWL()->ProcessVolumeSwitchInput(currentTime); } if (EmuRunning == emuStatus_Running || EmuRunning == emuStatus_FrameStep) @@ -472,28 +495,28 @@ void EmuThread::run() videoSettings.GL_ScaleFactor = Config::GL_ScaleFactor; videoSettings.GL_BetterPolygons = Config::GL_BetterPolygons; - NDS::GPU->SetRenderSettings(videoRenderer, videoSettings); + NDS->GPU.SetRenderSettings(videoRenderer, videoSettings); } // process input and hotkeys - NDS::SetKeyMask(Input::InputMask); + NDS->SetKeyMask(Input::InputMask); if (Input::HotkeyPressed(HK_Lid)) { - bool lid = !NDS::IsLidClosed(); - NDS::SetLidClosed(lid); + bool lid = !NDS->IsLidClosed(); + NDS->SetLidClosed(lid); OSD::AddMessage(0, lid ? "Lid closed" : "Lid opened"); } // microphone input - AudioInOut::MicProcess(); + AudioInOut::MicProcess(*NDS); // auto screen layout if (Config::ScreenSizing == Frontend::screenSizing_Auto) { mainScreenPos[2] = mainScreenPos[1]; mainScreenPos[1] = mainScreenPos[0]; - mainScreenPos[0] = NDS::PowerControl9 >> 15; + mainScreenPos[0] = NDS->PowerControl9 >> 15; int guess; if (mainScreenPos[0] == mainScreenPos[2] && @@ -520,7 +543,7 @@ void EmuThread::run() // emulate - u32 nlines = NDS::RunFrame(); + u32 nlines = NDS->RunFrame(); if (ROMManager::NDSSave) ROMManager::NDSSave->CheckFlush(); @@ -534,12 +557,12 @@ void EmuThread::run() if (!oglContext) { FrontBufferLock.lock(); - FrontBuffer = NDS::GPU->FrontBuffer; + FrontBuffer = NDS->GPU.FrontBuffer; FrontBufferLock.unlock(); } else { - FrontBuffer = NDS::GPU->FrontBuffer; + FrontBuffer = NDS->GPU.FrontBuffer; drawScreenGL(); } @@ -563,9 +586,10 @@ void EmuThread::run() oglContext->SetSwapInterval(0); } - if (Config::DSiVolumeSync && NDS::ConsoleType == 1) + if (Config::DSiVolumeSync && NDS->ConsoleType == 1) { - u8 volumeLevel = DSi::I2C->GetBPTWL()->GetVolumeLevel(); + DSi& dsi = static_cast(*NDS); + u8 volumeLevel = dsi.I2C.GetBPTWL()->GetVolumeLevel(); if (volumeLevel != dsiVolumeLevel) { dsiVolumeLevel = volumeLevel; @@ -576,7 +600,7 @@ void EmuThread::run() } if (Config::AudioSync && !fastforward) - AudioInOut::AudioSync(); + AudioInOut::AudioSync(*emuThread->NDS); double frametimeStep = nlines / (60.0 * 263.0); @@ -669,16 +693,15 @@ void EmuThread::run() if (file) { RTC::StateData state; - NDS::RTC->GetState(state); + NDS->RTC.GetState(state); Platform::FileWrite(&state, sizeof(state), 1, file); Platform::CloseFile(file); } EmuStatus = emuStatus_Exit; - NDS::GPU->DeInitRenderer(); - NDS::DeInit(); - //Platform::LAN_DeInit(); + NDS::Current = nullptr; + // nds is out of scope, so unique_ptr cleans it up for us } void EmuThread::changeWindowTitle(char* title) @@ -759,6 +782,7 @@ bool EmuThread::emuIsActive() void EmuThread::drawScreenGL() { + if (!NDS) return; int w = windowInfo.surface_width; int h = windowInfo.surface_height; float factor = windowInfo.surface_scale; @@ -780,10 +804,10 @@ void EmuThread::drawScreenGL() glActiveTexture(GL_TEXTURE0); #ifdef OGLRENDERER_ENABLED - if (NDS::GPU->Renderer != 0) + if (NDS->GPU.Renderer != 0) { // hardware-accelerated render - NDS::GPU->CurGLCompositor->BindOutputTexture(frontbuf); + NDS->GPU.CurGLCompositor->BindOutputTexture(frontbuf); } else #endif @@ -791,12 +815,12 @@ void EmuThread::drawScreenGL() // regular render glBindTexture(GL_TEXTURE_2D, screenTexture); - if (NDS::GPU->Framebuffer[frontbuf][0] && NDS::GPU->Framebuffer[frontbuf][1]) + if (NDS->GPU.Framebuffer[frontbuf][0] && NDS->GPU.Framebuffer[frontbuf][1]) { glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, 192, GL_RGBA, - GL_UNSIGNED_BYTE, NDS::GPU->Framebuffer[frontbuf][0]); + GL_UNSIGNED_BYTE, NDS->GPU.Framebuffer[frontbuf][0]); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 192+2, 256, 192, GL_RGBA, - GL_UNSIGNED_BYTE, NDS::GPU->Framebuffer[frontbuf][1]); + GL_UNSIGNED_BYTE, NDS->GPU.Framebuffer[frontbuf][1]); } } @@ -927,7 +951,8 @@ void ScreenHandler::screenOnMousePress(QMouseEvent* event) if (Frontend::GetTouchCoords(x, y, false)) { touching = true; - NDS::TouchScreen(x, y); + assert(emuThread->NDS != nullptr); + emuThread->NDS->TouchScreen(x, y); } } @@ -939,7 +964,8 @@ void ScreenHandler::screenOnMouseRelease(QMouseEvent* event) if (touching) { touching = false; - NDS::ReleaseScreen(); + assert(emuThread->NDS != nullptr); + emuThread->NDS->ReleaseScreen(); } } @@ -956,7 +982,10 @@ void ScreenHandler::screenOnMouseMove(QMouseEvent* event) int y = event->pos().y(); if (Frontend::GetTouchCoords(x, y, true)) - NDS::TouchScreen(x, y); + { + assert(emuThread->NDS != nullptr); + emuThread->NDS->TouchScreen(x, y); + } } void ScreenHandler::screenHandleTablet(QTabletEvent* event) @@ -974,14 +1003,16 @@ void ScreenHandler::screenHandleTablet(QTabletEvent* event) if (Frontend::GetTouchCoords(x, y, event->type()==QEvent::TabletMove)) { touching = true; - NDS::TouchScreen(x, y); + assert(emuThread->NDS != nullptr); + emuThread->NDS->TouchScreen(x, y); } } break; case QEvent::TabletRelease: if (touching) { - NDS::ReleaseScreen(); + assert(emuThread->NDS != nullptr); + emuThread->NDS->ReleaseScreen(); touching = false; } break; @@ -1007,14 +1038,16 @@ void ScreenHandler::screenHandleTouch(QTouchEvent* event) if (Frontend::GetTouchCoords(x, y, event->type()==QEvent::TouchUpdate)) { touching = true; - NDS::TouchScreen(x, y); + assert(emuThread->NDS != nullptr); + emuThread->NDS->TouchScreen(x, y); } } break; case QEvent::TouchEnd: if (touching) { - NDS::ReleaseScreen(); + assert(emuThread->NDS != nullptr); + emuThread->NDS->ReleaseScreen(); touching = false; } break; @@ -1080,16 +1113,17 @@ void ScreenPanelNative::paintEvent(QPaintEvent* event) if (emuThread->emuIsActive()) { + assert(emuThread->NDS != nullptr); emuThread->FrontBufferLock.lock(); int frontbuf = emuThread->FrontBuffer; - if (!NDS::GPU->Framebuffer[frontbuf][0] || !NDS::GPU->Framebuffer[frontbuf][1]) + if (!emuThread->NDS->GPU.Framebuffer[frontbuf][0] || !emuThread->NDS->GPU.Framebuffer[frontbuf][1]) { emuThread->FrontBufferLock.unlock(); return; } - memcpy(screen[0].scanLine(0), NDS::GPU->Framebuffer[frontbuf][0], 256 * 192 * 4); - memcpy(screen[1].scanLine(0), NDS::GPU->Framebuffer[frontbuf][1], 256 * 192 * 4); + memcpy(screen[0].scanLine(0), emuThread->NDS->GPU.Framebuffer[frontbuf][0], 256 * 192 * 4); + memcpy(screen[1].scanLine(0), emuThread->NDS->GPU.Framebuffer[frontbuf][1], 256 * 192 * 4); emuThread->FrontBufferLock.unlock(); QRect screenrc(0, 0, 256, 192); @@ -1472,7 +1506,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) QMenu* submenu = menu->addMenu("Insert add-on cart"); actInsertGBAAddon[0] = submenu->addAction("Memory expansion"); - actInsertGBAAddon[0]->setData(QVariant(NDS::GBAAddon_RAMExpansion)); + actInsertGBAAddon[0]->setData(QVariant(GBAAddon_RAMExpansion)); connect(actInsertGBAAddon[0], &QAction::triggered, this, &MainWindow::onInsertGBAAddon); } @@ -2025,7 +2059,7 @@ void MainWindow::dropEvent(QDropEvent* event) if (isNdsRom) { - if (!ROMManager::LoadROM(file, true)) + if (!ROMManager::LoadROM(emuThread, file, true)) { // TODO: better error reporting? QMessageBox::critical(this, "melonDS", "Failed to load the DS ROM."); @@ -2038,14 +2072,15 @@ void MainWindow::dropEvent(QDropEvent* event) recentFileList.prepend(barredFilename); updateRecentFilesMenu(); - NDS::Start(); + assert(emuThread->NDS != nullptr); + emuThread->NDS->Start(); emuThread->emuRun(); updateCartInserted(false); } else if (isGbaRom) { - if (!ROMManager::LoadGBAROM(file)) + if (!ROMManager::LoadGBAROM(*emuThread->NDS, file)) { // TODO: better error reporting? QMessageBox::critical(this, "melonDS", "Failed to load the GBA ROM."); @@ -2111,7 +2146,7 @@ bool MainWindow::preloadROMs(QStringList file, QStringList gbafile, bool boot) bool gbaloaded = false; if (!gbafile.isEmpty()) { - if (!ROMManager::LoadGBAROM(gbafile)) + if (!ROMManager::LoadGBAROM(*emuThread->NDS, gbafile)) { // TODO: better error reporting? QMessageBox::critical(this, "melonDS", "Failed to load the GBA ROM."); @@ -2124,7 +2159,7 @@ bool MainWindow::preloadROMs(QStringList file, QStringList gbafile, bool boot) bool ndsloaded = false; if (!file.isEmpty()) { - if (!ROMManager::LoadROM(file, true)) + if (!ROMManager::LoadROM(emuThread, file, true)) { // TODO: better error reporting? QMessageBox::critical(this, "melonDS", "Failed to load the ROM."); @@ -2140,7 +2175,7 @@ bool MainWindow::preloadROMs(QStringList file, QStringList gbafile, bool boot) { if (ndsloaded) { - NDS::Start(); + emuThread->NDS->Start(); emuThread->emuRun(); } else @@ -2333,7 +2368,7 @@ void MainWindow::onOpenFile() return; } - if (!ROMManager::LoadROM(file, true)) + if (!ROMManager::LoadROM(emuThread, file, true)) { // TODO: better error reporting? QMessageBox::critical(this, "melonDS", "Failed to load the ROM."); @@ -2346,7 +2381,8 @@ void MainWindow::onOpenFile() recentFileList.prepend(filename); updateRecentFilesMenu(); - NDS::Start(); + assert(emuThread->NDS != nullptr); + emuThread->NDS->Start(); emuThread->emuRun(); updateCartInserted(false); @@ -2431,7 +2467,7 @@ void MainWindow::onClickRecentFile() return; } - if (!ROMManager::LoadROM(file, true)) + if (!ROMManager::LoadROM(emuThread, file, true)) { // TODO: better error reporting? QMessageBox::critical(this, "melonDS", "Failed to load the ROM."); @@ -2443,7 +2479,8 @@ void MainWindow::onClickRecentFile() recentFileList.prepend(filename); updateRecentFilesMenu(); - NDS::Start(); + assert(emuThread->NDS != nullptr); + emuThread->NDS->Start(); emuThread->emuRun(); updateCartInserted(false); @@ -2459,7 +2496,7 @@ void MainWindow::onBootFirmware() return; } - if (!ROMManager::LoadBIOS()) + if (!ROMManager::LoadBIOS(emuThread)) { // TODO: better error reporting? QMessageBox::critical(this, "melonDS", "This firmware is not bootable."); @@ -2467,7 +2504,8 @@ void MainWindow::onBootFirmware() return; } - NDS::Start(); + assert(emuThread->NDS != nullptr); + emuThread->NDS->Start(); emuThread->emuRun(); } @@ -2482,7 +2520,7 @@ void MainWindow::onInsertCart() return; } - if (!ROMManager::LoadROM(file, false)) + if (!ROMManager::LoadROM(emuThread, file, false)) { // TODO: better error reporting? QMessageBox::critical(this, "melonDS", "Failed to load the ROM."); @@ -2499,7 +2537,7 @@ void MainWindow::onEjectCart() { emuThread->emuPause(); - ROMManager::EjectCart(); + ROMManager::EjectCart(*emuThread->NDS); emuThread->emuUnpause(); @@ -2517,7 +2555,7 @@ void MainWindow::onInsertGBACart() return; } - if (!ROMManager::LoadGBAROM(file)) + if (!ROMManager::LoadGBAROM(*emuThread->NDS, file)) { // TODO: better error reporting? QMessageBox::critical(this, "melonDS", "Failed to load the ROM."); @@ -2537,7 +2575,7 @@ void MainWindow::onInsertGBAAddon() emuThread->emuPause(); - ROMManager::LoadGBAAddon(type); + ROMManager::LoadGBAAddon(*emuThread->NDS, type); emuThread->emuUnpause(); @@ -2548,7 +2586,7 @@ void MainWindow::onEjectGBACart() { emuThread->emuPause(); - ROMManager::EjectGBACart(); + ROMManager::EjectGBACart(*emuThread->NDS); emuThread->emuUnpause(); @@ -2582,7 +2620,7 @@ void MainWindow::onSaveState() filename = qfilename.toStdString(); } - if (ROMManager::SaveState(filename)) + if (ROMManager::SaveState(*emuThread->NDS, filename)) { char msg[64]; if (slot > 0) sprintf(msg, "State saved to slot %d", slot); @@ -2637,7 +2675,7 @@ void MainWindow::onLoadState() return; } - if (ROMManager::LoadState(filename)) + if (ROMManager::LoadState(*emuThread->NDS, filename)) { char msg[64]; if (slot > 0) sprintf(msg, "State loaded from slot %d", slot); @@ -2657,7 +2695,7 @@ void MainWindow::onLoadState() void MainWindow::onUndoStateLoad() { emuThread->emuPause(); - ROMManager::UndoStateLoad(); + ROMManager::UndoStateLoad(*emuThread->NDS); emuThread->emuUnpause(); OSD::AddMessage(0, "State load undone"); @@ -2696,7 +2734,7 @@ void MainWindow::onImportSavefile() return; } - ROMManager::Reset(); + ROMManager::Reset(emuThread); } u32 len = FileLength(f); @@ -2705,7 +2743,8 @@ void MainWindow::onImportSavefile() Platform::FileRewind(f); Platform::FileRead(data, len, 1, f); - NDS::LoadSave(data, len); + assert(emuThread->NDS != nullptr); + emuThread->NDS->LoadSave(data, len); delete[] data; CloseFile(f); @@ -2747,7 +2786,7 @@ void MainWindow::onReset() actUndoStateLoad->setEnabled(false); - ROMManager::Reset(); + ROMManager::Reset(emuThread); OSD::AddMessage(0, "Reset"); emuThread->emuRun(); @@ -2758,7 +2797,7 @@ void MainWindow::onStop() if (!RunningSomething) return; emuThread->emuPause(); - NDS::Stop(); + emuThread->NDS->Stop(); } void MainWindow::onFrameStep() @@ -2775,13 +2814,13 @@ void MainWindow::onOpenDateTime() void MainWindow::onOpenPowerManagement() { - PowerManagementDialog* dlg = PowerManagementDialog::openDlg(this); + PowerManagementDialog* dlg = PowerManagementDialog::openDlg(this, emuThread); } void MainWindow::onEnableCheats(bool checked) { Config::EnableCheats = checked?1:0; - ROMManager::EnableCheats(Config::EnableCheats != 0); + ROMManager::EnableCheats(*emuThread->NDS, Config::EnableCheats != 0); } void MainWindow::onSetupCheats() @@ -2799,12 +2838,14 @@ void MainWindow::onCheatsDialogFinished(int res) void MainWindow::onROMInfo() { - ROMInfoDialog* dlg = ROMInfoDialog::openDlg(this); + auto cart = emuThread->NDS->NDSCartSlot.GetCart(); + if (cart) + ROMInfoDialog* dlg = ROMInfoDialog::openDlg(this, *cart); } void MainWindow::onRAMInfo() { - RAMInfoDialog* dlg = RAMInfoDialog::openDlg(this); + RAMInfoDialog* dlg = RAMInfoDialog::openDlg(this, emuThread); } void MainWindow::onOpenTitleManager() @@ -2907,7 +2948,7 @@ void MainWindow::onCameraSettingsFinished(int res) void MainWindow::onOpenAudioSettings() { - AudioSettingsDialog* dlg = AudioSettingsDialog::openDlg(this, emuThread->emuIsActive()); + AudioSettingsDialog* dlg = AudioSettingsDialog::openDlg(this, emuThread->emuIsActive(), emuThread); connect(emuThread, &EmuThread::syncVolumeLevel, dlg, &AudioSettingsDialog::onSyncVolumeLevel); connect(emuThread, &EmuThread::windowEmuStart, dlg, &AudioSettingsDialog::onConsoleReset); connect(dlg, &AudioSettingsDialog::updateAudioSettings, this, &MainWindow::onUpdateAudioSettings); @@ -2948,17 +2989,18 @@ void MainWindow::onPathSettingsFinished(int res) void MainWindow::onUpdateAudioSettings() { - NDS::SPU->SetInterpolation(Config::AudioInterp); + assert(emuThread->NDS != nullptr); + emuThread->NDS->SPU.SetInterpolation(Config::AudioInterp); if (Config::AudioBitDepth == 0) - NDS::SPU->SetDegrade10Bit(NDS::ConsoleType == 0); + emuThread->NDS->SPU.SetDegrade10Bit(emuThread->NDS->ConsoleType == 0); else - NDS::SPU->SetDegrade10Bit(Config::AudioBitDepth == 1); + emuThread->NDS->SPU.SetDegrade10Bit(Config::AudioBitDepth == 1); } void MainWindow::onAudioSettingsFinished(int res) { - AudioInOut::UpdateSettings(); + AudioInOut::UpdateSettings(*emuThread->NDS); } void MainWindow::onOpenMPSettings() @@ -3313,13 +3355,11 @@ int main(int argc, char** argv) #define SANITIZE(var, min, max) { var = std::clamp(var, min, max); } SANITIZE(Config::ConsoleType, 0, 1); - SANITIZE(Config::_3DRenderer, - 0, - 0 // Minimum, Software renderer - #ifdef OGLRENDERER_ENABLED - + 1 // OpenGL Renderer - #endif - ); +#ifdef OGLRENDERER_ENABLED + SANITIZE(Config::_3DRenderer, 0, 1); // 0 is the software renderer, 1 is the OpenGL renderer +#else + SANITIZE(Config::_3DRenderer, 0, 0); +#endif SANITIZE(Config::ScreenVSyncInterval, 1, 20); SANITIZE(Config::GL_ScaleFactor, 1, 16); SANITIZE(Config::AudioInterp, 0, 3); @@ -3333,7 +3373,6 @@ int main(int argc, char** argv) SANITIZE(Config::ScreenAspectBot, 0, AspectRatiosNum); #undef SANITIZE - AudioInOut::Init(); camStarted[0] = false; camStarted[1] = false; camManager[0] = new CameraManager(0, 640, 480, true); @@ -3341,7 +3380,6 @@ int main(int argc, char** argv) camManager[0]->setXFlip(Config::Camera[0].XFlip); camManager[1]->setXFlip(Config::Camera[1].XFlip); - ROMManager::EnableCheats(Config::EnableCheats != 0); Input::JoystickID = Config::JoystickID; Input::OpenJoystick(); @@ -3354,6 +3392,8 @@ int main(int argc, char** argv) emuThread->start(); emuThread->emuPause(); + AudioInOut::Init(emuThread); + ROMManager::EnableCheats(*emuThread->NDS, Config::EnableCheats != 0); AudioInOut::AudioMute(mainWindow); QObject::connect(&melon, &QApplication::applicationStateChanged, mainWindow, &MainWindow::onAppStateChanged); diff --git a/src/frontend/qt_sdl/main.h b/src/frontend/qt_sdl/main.h index 500aec1..72ebfb1 100644 --- a/src/frontend/qt_sdl/main.h +++ b/src/frontend/qt_sdl/main.h @@ -40,6 +40,11 @@ #include "FrontendUtil.h" #include "duckstation/gl/context.h" +namespace melonDS +{ +class NDS; +} + class EmuThread : public QThread { Q_OBJECT @@ -67,7 +72,8 @@ public: QMutex FrontBufferLock; void updateScreenSettings(bool filter, const WindowInfo& windowInfo, int numScreens, int* screenKind, float* screenMatrix); - + void RecreateConsole(); + std::unique_ptr NDS; // TODO: Proper encapsulation and synchronization signals: void windowUpdate(); void windowTitleChange(QString title); @@ -90,6 +96,7 @@ signals: void syncVolumeLevel(); private: + std::unique_ptr CreateConsole(); void drawScreenGL(); void initOpenGL(); void deinitOpenGL(); -- cgit v1.2.3