mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	code: Cleanup and warning fixes from the Vulkan PR (#6163)
Co-authored-by: emufan4568 <geoster3d@gmail.com> Co-authored-by: Kyle Kienapfel <Docteh@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									aa84022704
								
							
						
					
					
						commit
						1ddea27ac8
					
				
					 72 changed files with 895 additions and 626 deletions
				
			
		
							
								
								
									
										6
									
								
								externals/microprofile/microprofile.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								externals/microprofile/microprofile.h
									
										
									
									
										vendored
									
									
								
							|  | @ -847,7 +847,7 @@ inline MicroProfileLogEntry MicroProfileMakeLogIndex(uint64_t nBegin, MicroProfi | ||||||
|     MicroProfileLogEntry Entry =  (nBegin<<62) | ((0x3fff&nToken)<<48) | (MP_LOG_TICK_MASK&nTick); |     MicroProfileLogEntry Entry =  (nBegin<<62) | ((0x3fff&nToken)<<48) | (MP_LOG_TICK_MASK&nTick); | ||||||
|     int t = MicroProfileLogType(Entry); |     int t = MicroProfileLogType(Entry); | ||||||
|     uint64_t nTimerIndex = MicroProfileLogTimerIndex(Entry); |     uint64_t nTimerIndex = MicroProfileLogTimerIndex(Entry); | ||||||
|     MP_ASSERT(t == nBegin); |     MP_ASSERT(static_cast<uint64_t>(t) == nBegin); | ||||||
|     MP_ASSERT(nTimerIndex == (nToken&0x3fff)); |     MP_ASSERT(nTimerIndex == (nToken&0x3fff)); | ||||||
|     return Entry; |     return Entry; | ||||||
| 
 | 
 | ||||||
|  | @ -1579,10 +1579,10 @@ void MicroProfileFlip() | ||||||
| 
 | 
 | ||||||
|         pFramePut->nFrameStartCpu = MP_TICK(); |         pFramePut->nFrameStartCpu = MP_TICK(); | ||||||
|         pFramePut->nFrameStartGpu = (uint32_t)MicroProfileGpuInsertTimeStamp(); |         pFramePut->nFrameStartGpu = (uint32_t)MicroProfileGpuInsertTimeStamp(); | ||||||
|         if(pFrameNext->nFrameStartGpu != (uint64_t)-1) |         if(static_cast<uint64_t>(pFrameNext->nFrameStartGpu) != (uint64_t)-1) | ||||||
|             pFrameNext->nFrameStartGpu = MicroProfileGpuGetTimeStamp((uint32_t)pFrameNext->nFrameStartGpu); |             pFrameNext->nFrameStartGpu = MicroProfileGpuGetTimeStamp((uint32_t)pFrameNext->nFrameStartGpu); | ||||||
| 
 | 
 | ||||||
|         if(pFrameCurrent->nFrameStartGpu == (uint64_t)-1) |         if(static_cast<uint64_t>(pFrameCurrent->nFrameStartGpu) == (uint64_t)-1) | ||||||
|             pFrameCurrent->nFrameStartGpu = pFrameNext->nFrameStartGpu + 1; |             pFrameCurrent->nFrameStartGpu = pFrameNext->nFrameStartGpu + 1; | ||||||
| 
 | 
 | ||||||
|         uint64_t nFrameStartCpu = pFrameCurrent->nFrameStartCpu; |         uint64_t nFrameStartCpu = pFrameCurrent->nFrameStartCpu; | ||||||
|  |  | ||||||
							
								
								
									
										12
									
								
								externals/microprofile/microprofileui.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								externals/microprofile/microprofileui.h
									
										
									
									
										vendored
									
									
								
							|  | @ -354,7 +354,7 @@ void MicroProfileInitUI() | ||||||
|     if(!bInitialized) |     if(!bInitialized) | ||||||
|     { |     { | ||||||
|         bInitialized = true; |         bInitialized = true; | ||||||
|         memset(&g_MicroProfileUI, 0, sizeof(g_MicroProfileUI)); |         g_MicroProfileUI = {}; | ||||||
|         UI.nActiveMenu = UINT32_MAX; |         UI.nActiveMenu = UINT32_MAX; | ||||||
|         UI.fDetailedOffsetTarget = UI.fDetailedOffset = 0.f; |         UI.fDetailedOffsetTarget = UI.fDetailedOffset = 0.f; | ||||||
|         UI.fDetailedRangeTarget = UI.fDetailedRange = 50.f; |         UI.fDetailedRangeTarget = UI.fDetailedRange = 50.f; | ||||||
|  | @ -845,8 +845,8 @@ void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int nBaseY, | ||||||
|     MicroProfile& S = *MicroProfileGet(); |     MicroProfile& S = *MicroProfileGet(); | ||||||
|     MP_DEBUG_DUMP_RANGE(); |     MP_DEBUG_DUMP_RANGE(); | ||||||
|     int nY = nBaseY - UI.nOffsetY; |     int nY = nBaseY - UI.nOffsetY; | ||||||
|     int64_t nNumBoxes = 0; |     [[maybe_unused]] int64_t nNumBoxes = 0; | ||||||
|     int64_t nNumLines = 0; |     [[maybe_unused]] int64_t nNumLines = 0; | ||||||
| 
 | 
 | ||||||
|     uint32_t nFrameNext = (S.nFrameCurrent+1) % MICROPROFILE_MAX_FRAME_HISTORY; |     uint32_t nFrameNext = (S.nFrameCurrent+1) % MICROPROFILE_MAX_FRAME_HISTORY; | ||||||
|     MicroProfileFrameState* pFrameCurrent = &S.Frames[S.nFrameCurrent]; |     MicroProfileFrameState* pFrameCurrent = &S.Frames[S.nFrameCurrent]; | ||||||
|  | @ -1988,7 +1988,7 @@ const char* MicroProfileUIMenuGroups(int nIndex, bool* bSelected) | ||||||
|     else |     else | ||||||
|     { |     { | ||||||
|         nIndex = nIndex-1; |         nIndex = nIndex-1; | ||||||
|         if(nIndex < UI.GroupMenuCount) |         if(static_cast<uint32_t>(nIndex) < UI.GroupMenuCount) | ||||||
|         { |         { | ||||||
|             MicroProfileGroupMenuItem& Item = UI.GroupMenu[nIndex]; |             MicroProfileGroupMenuItem& Item = UI.GroupMenu[nIndex]; | ||||||
|             static char buffer[MICROPROFILE_NAME_MAX_LEN+32]; |             static char buffer[MICROPROFILE_NAME_MAX_LEN+32]; | ||||||
|  | @ -2135,7 +2135,7 @@ const char* MicroProfileUIMenuCustom(int nIndex, bool* bSelected) | ||||||
|     case 1: return "--"; |     case 1: return "--"; | ||||||
|     default: |     default: | ||||||
|         nIndex -= 2; |         nIndex -= 2; | ||||||
|         if(nIndex < UI.nCustomCount) |         if(static_cast<uint32_t>(nIndex) < UI.nCustomCount) | ||||||
|         { |         { | ||||||
|             return UI.Custom[nIndex].pName; |             return UI.Custom[nIndex].pName; | ||||||
|         } |         } | ||||||
|  | @ -2185,7 +2185,7 @@ void MicroProfileUIClickGroups(int nIndex) | ||||||
|     else |     else | ||||||
|     { |     { | ||||||
|         nIndex -= 1; |         nIndex -= 1; | ||||||
|         if(nIndex < UI.GroupMenuCount) |         if(static_cast<uint32_t>(nIndex) < UI.GroupMenuCount) | ||||||
|         { |         { | ||||||
|             MicroProfileGroupMenuItem& Item = UI.GroupMenu[nIndex]; |             MicroProfileGroupMenuItem& Item = UI.GroupMenu[nIndex]; | ||||||
|             if(Item.nIsCategory) |             if(Item.nIsCategory) | ||||||
|  |  | ||||||
|  | @ -11,13 +11,6 @@ | ||||||
| // This needs to be included before getopt.h because the latter #defines symbols used by it
 | // This needs to be included before getopt.h because the latter #defines symbols used by it
 | ||||||
| #include "common/microprofile.h" | #include "common/microprofile.h" | ||||||
| 
 | 
 | ||||||
| #ifdef _WIN32 |  | ||||||
| // windows.h needs to be included before shellapi.h
 |  | ||||||
| #include <windows.h> |  | ||||||
| 
 |  | ||||||
| #include <shellapi.h> |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #include "citra/config.h" | #include "citra/config.h" | ||||||
| #include "citra/emu_window/emu_window_sdl2.h" | #include "citra/emu_window/emu_window_sdl2.h" | ||||||
| #include "citra/lodepng_image_interface.h" | #include "citra/lodepng_image_interface.h" | ||||||
|  | @ -52,6 +45,11 @@ | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef _WIN32 | #ifdef _WIN32 | ||||||
|  | // windows.h needs to be included before shellapi.h
 | ||||||
|  | #include <windows.h> | ||||||
|  | 
 | ||||||
|  | #include <shellapi.h> | ||||||
|  | 
 | ||||||
| extern "C" { | extern "C" { | ||||||
| // tells Nvidia drivers to use the dedicated GPU by default on laptops with switchable graphics
 | // tells Nvidia drivers to use the dedicated GPU by default on laptops with switchable graphics
 | ||||||
| __declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001; | __declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001; | ||||||
|  | @ -104,35 +102,35 @@ static void OnNetworkError(const Network::RoomMember::Error& error) { | ||||||
|         break; |         break; | ||||||
|     case Network::RoomMember::Error::CouldNotConnect: |     case Network::RoomMember::Error::CouldNotConnect: | ||||||
|         LOG_ERROR(Network, "Error: Could not connect"); |         LOG_ERROR(Network, "Error: Could not connect"); | ||||||
|         exit(1); |         std::exit(1); | ||||||
|         break; |         break; | ||||||
|     case Network::RoomMember::Error::NameCollision: |     case Network::RoomMember::Error::NameCollision: | ||||||
|         LOG_ERROR( |         LOG_ERROR( | ||||||
|             Network, |             Network, | ||||||
|             "You tried to use the same nickname as another user that is connected to the Room"); |             "You tried to use the same nickname as another user that is connected to the Room"); | ||||||
|         exit(1); |         std::exit(1); | ||||||
|         break; |         break; | ||||||
|     case Network::RoomMember::Error::MacCollision: |     case Network::RoomMember::Error::MacCollision: | ||||||
|         LOG_ERROR(Network, "You tried to use the same MAC-Address as another user that is " |         LOG_ERROR(Network, "You tried to use the same MAC-Address as another user that is " | ||||||
|                            "connected to the Room"); |                            "connected to the Room"); | ||||||
|         exit(1); |         std::exit(1); | ||||||
|         break; |         break; | ||||||
|     case Network::RoomMember::Error::ConsoleIdCollision: |     case Network::RoomMember::Error::ConsoleIdCollision: | ||||||
|         LOG_ERROR(Network, "Your Console ID conflicted with someone else in the Room"); |         LOG_ERROR(Network, "Your Console ID conflicted with someone else in the Room"); | ||||||
|         exit(1); |         std::exit(1); | ||||||
|         break; |         break; | ||||||
|     case Network::RoomMember::Error::WrongPassword: |     case Network::RoomMember::Error::WrongPassword: | ||||||
|         LOG_ERROR(Network, "Room replied with: Wrong password"); |         LOG_ERROR(Network, "Room replied with: Wrong password"); | ||||||
|         exit(1); |         std::exit(1); | ||||||
|         break; |         break; | ||||||
|     case Network::RoomMember::Error::WrongVersion: |     case Network::RoomMember::Error::WrongVersion: | ||||||
|         LOG_ERROR(Network, |         LOG_ERROR(Network, | ||||||
|                   "You are using a different version than the room you are trying to connect to"); |                   "You are using a different version than the room you are trying to connect to"); | ||||||
|         exit(1); |         std::exit(1); | ||||||
|         break; |         break; | ||||||
|     case Network::RoomMember::Error::RoomIsFull: |     case Network::RoomMember::Error::RoomIsFull: | ||||||
|         LOG_ERROR(Network, "The room is full"); |         LOG_ERROR(Network, "The room is full"); | ||||||
|         exit(1); |         std::exit(1); | ||||||
|         break; |         break; | ||||||
|     case Network::RoomMember::Error::HostKicked: |     case Network::RoomMember::Error::HostKicked: | ||||||
|         LOG_ERROR(Network, "You have been kicked by the host"); |         LOG_ERROR(Network, "You have been kicked by the host"); | ||||||
|  | @ -140,6 +138,8 @@ static void OnNetworkError(const Network::RoomMember::Error& error) { | ||||||
|     case Network::RoomMember::Error::HostBanned: |     case Network::RoomMember::Error::HostBanned: | ||||||
|         LOG_ERROR(Network, "You have been banned by the host"); |         LOG_ERROR(Network, "You have been banned by the host"); | ||||||
|         break; |         break; | ||||||
|  |     default: | ||||||
|  |         LOG_ERROR(Network, "Unknown network error {}", error); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -54,12 +54,12 @@ QtKeyboardDialog::QtKeyboardDialog(QWidget* parent, QtKeyboard* keyboard_) | ||||||
|     case ButtonConfig::None: |     case ButtonConfig::None: | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     connect(buttons, &QDialogButtonBox::accepted, this, [=] { Submit(); }); |     connect(buttons, &QDialogButtonBox::accepted, this, [this] { Submit(); }); | ||||||
|     connect(buttons, &QDialogButtonBox::rejected, this, [=] { |     connect(buttons, &QDialogButtonBox::rejected, this, [this] { | ||||||
|         button = QtKeyboard::cancel_id; |         button = QtKeyboard::cancel_id; | ||||||
|         accept(); |         accept(); | ||||||
|     }); |     }); | ||||||
|     connect(buttons, &QDialogButtonBox::helpRequested, this, [=] { |     connect(buttons, &QDialogButtonBox::helpRequested, this, [this] { | ||||||
|         button = QtKeyboard::forgot_id; |         button = QtKeyboard::forgot_id; | ||||||
|         accept(); |         accept(); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|  | @ -32,11 +32,13 @@ EmuThread::EmuThread(Frontend::GraphicsContext& core_context) : core_context(cor | ||||||
| EmuThread::~EmuThread() = default; | EmuThread::~EmuThread() = default; | ||||||
| 
 | 
 | ||||||
| static GMainWindow* GetMainWindow() { | static GMainWindow* GetMainWindow() { | ||||||
|     for (QWidget* w : qApp->topLevelWidgets()) { |     const auto widgets = qApp->topLevelWidgets(); | ||||||
|  |     for (QWidget* w : widgets) { | ||||||
|         if (GMainWindow* main = qobject_cast<GMainWindow*>(w)) { |         if (GMainWindow* main = qobject_cast<GMainWindow*>(w)) { | ||||||
|             return main; |             return main; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     return nullptr; |     return nullptr; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -46,7 +48,8 @@ void EmuThread::run() { | ||||||
| 
 | 
 | ||||||
|     emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); |     emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); | ||||||
| 
 | 
 | ||||||
|     Core::System::GetInstance().Renderer().Rasterizer()->LoadDiskResources( |     Core::System& system = Core::System::GetInstance(); | ||||||
|  |     system.Renderer().Rasterizer()->LoadDiskResources( | ||||||
|         stop_run, [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) { |         stop_run, [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) { | ||||||
|             emit LoadProgress(stage, value, total); |             emit LoadProgress(stage, value, total); | ||||||
|         }); |         }); | ||||||
|  | @ -55,18 +58,17 @@ void EmuThread::run() { | ||||||
| 
 | 
 | ||||||
|     core_context.MakeCurrent(); |     core_context.MakeCurrent(); | ||||||
| 
 | 
 | ||||||
|     if (Core::System::GetInstance().frame_limiter.IsFrameAdvancing()) { |     if (system.frame_limiter.IsFrameAdvancing()) { | ||||||
|         // Usually the loading screen is hidden after the first frame is drawn. In this case
 |         // Usually the loading screen is hidden after the first frame is drawn. In this case
 | ||||||
|         // we hide it immediately as we need to wait for user input to start the emulation.
 |         // we hide it immediately as we need to wait for user input to start the emulation.
 | ||||||
|         emit HideLoadingScreen(); |         emit HideLoadingScreen(); | ||||||
|         Core::System::GetInstance().frame_limiter.WaitOnce(); |         system.frame_limiter.WaitOnce(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Holds whether the cpu was running during the last iteration,
 |     // Holds whether the cpu was running during the last iteration,
 | ||||||
|     // so that the DebugModeLeft signal can be emitted before the
 |     // so that the DebugModeLeft signal can be emitted before the
 | ||||||
|     // next execution step.
 |     // next execution step.
 | ||||||
|     bool was_active = false; |     bool was_active = false; | ||||||
|     Core::System& system = Core::System::GetInstance(); |  | ||||||
|     while (!stop_run) { |     while (!stop_run) { | ||||||
|         if (running) { |         if (running) { | ||||||
|             if (!was_active) |             if (!was_active) | ||||||
|  | @ -423,7 +425,7 @@ void GRenderWindow::CaptureScreenshot(u32 res_scale, const QString& screenshot_p | ||||||
|     screenshot_image = QImage(QSize(layout.width, layout.height), QImage::Format_RGB32); |     screenshot_image = QImage(QSize(layout.width, layout.height), QImage::Format_RGB32); | ||||||
|     VideoCore::RequestScreenshot( |     VideoCore::RequestScreenshot( | ||||||
|         screenshot_image.bits(), |         screenshot_image.bits(), | ||||||
|         [=] { |         [this, &screenshot_path] { | ||||||
|             const std::string std_screenshot_path = screenshot_path.toStdString(); |             const std::string std_screenshot_path = screenshot_path.toStdString(); | ||||||
|             if (screenshot_image.mirrored(false, true).save(screenshot_path)) { |             if (screenshot_image.mirrored(false, true).save(screenshot_path)) { | ||||||
|                 LOG_INFO(Frontend, "Screenshot saved to \"{}\"", std_screenshot_path); |                 LOG_INFO(Frontend, "Screenshot saved to \"{}\"", std_screenshot_path); | ||||||
|  |  | ||||||
|  | @ -37,7 +37,7 @@ CheatDialog::CheatDialog(QWidget* parent) | ||||||
|     connect(ui->textNotes, &QPlainTextEdit::textChanged, this, &CheatDialog::OnTextEdited); |     connect(ui->textNotes, &QPlainTextEdit::textChanged, this, &CheatDialog::OnTextEdited); | ||||||
|     connect(ui->textCode, &QPlainTextEdit::textChanged, this, &CheatDialog::OnTextEdited); |     connect(ui->textCode, &QPlainTextEdit::textChanged, this, &CheatDialog::OnTextEdited); | ||||||
| 
 | 
 | ||||||
|     connect(ui->buttonSave, &QPushButton::clicked, |     connect(ui->buttonSave, &QPushButton::clicked, this, | ||||||
|             [this] { SaveCheat(ui->tableCheats->currentRow()); }); |             [this] { SaveCheat(ui->tableCheats->currentRow()); }); | ||||||
|     connect(ui->buttonDelete, &QPushButton::clicked, this, &CheatDialog::OnDeleteCheat); |     connect(ui->buttonDelete, &QPushButton::clicked, this, &CheatDialog::OnDeleteCheat); | ||||||
| 
 | 
 | ||||||
|  | @ -91,7 +91,7 @@ bool CheatDialog::SaveCheat(int row) { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Check if the cheat lines are valid
 |     // Check if the cheat lines are valid
 | ||||||
|     auto code_lines = ui->textCode->toPlainText().split(QLatin1Char{'\n'}, QString::SkipEmptyParts); |     auto code_lines = ui->textCode->toPlainText().split(QLatin1Char{'\n'}, Qt::SkipEmptyParts); | ||||||
|     for (int i = 0; i < code_lines.size(); ++i) { |     for (int i = 0; i < code_lines.size(); ++i) { | ||||||
|         Cheats::GatewayCheat::CheatLine cheat_line(code_lines[i].toStdString()); |         Cheats::GatewayCheat::CheatLine cheat_line(code_lines[i].toStdString()); | ||||||
|         if (cheat_line.valid) |         if (cheat_line.valid) | ||||||
|  | @ -190,8 +190,9 @@ void CheatDialog::OnDeleteCheat() { | ||||||
|     if (newly_created) { |     if (newly_created) { | ||||||
|         newly_created = false; |         newly_created = false; | ||||||
|     } else { |     } else { | ||||||
|         Core::System::GetInstance().CheatEngine().RemoveCheat(ui->tableCheats->currentRow()); |         auto& cheat_engine = Core::System::GetInstance().CheatEngine(); | ||||||
|         Core::System::GetInstance().CheatEngine().SaveCheatFile(); |         cheat_engine.RemoveCheat(ui->tableCheats->currentRow()); | ||||||
|  |         cheat_engine.SaveCheatFile(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     LoadCheats(); |     LoadCheats(); | ||||||
|  |  | ||||||
|  | @ -518,7 +518,7 @@ void Config::ReadRendererValues() { | ||||||
| void Config::ReadShortcutValues() { | void Config::ReadShortcutValues() { | ||||||
|     qt_config->beginGroup(QStringLiteral("Shortcuts")); |     qt_config->beginGroup(QStringLiteral("Shortcuts")); | ||||||
| 
 | 
 | ||||||
|     for (auto [name, group, shortcut] : default_hotkeys) { |     for (const auto& [name, group, shortcut] : default_hotkeys) { | ||||||
|         auto [keyseq, context] = shortcut; |         auto [keyseq, context] = shortcut; | ||||||
|         qt_config->beginGroup(group); |         qt_config->beginGroup(group); | ||||||
|         qt_config->beginGroup(name); |         qt_config->beginGroup(name); | ||||||
|  | @ -553,7 +553,7 @@ void Config::ReadSystemValues() { | ||||||
| // https://developers.google.com/media/vp9/live-encoding
 | // https://developers.google.com/media/vp9/live-encoding
 | ||||||
| const QString DEFAULT_VIDEO_ENCODER_OPTIONS = | const QString DEFAULT_VIDEO_ENCODER_OPTIONS = | ||||||
|     QStringLiteral("quality:realtime,speed:6,tile-columns:4,frame-parallel:1,threads:8,row-mt:1"); |     QStringLiteral("quality:realtime,speed:6,tile-columns:4,frame-parallel:1,threads:8,row-mt:1"); | ||||||
| const QString DEFAULT_AUDIO_ENCODER_OPTIONS = QString{}; | const QString DEFAULT_AUDIO_ENCODER_OPTIONS = QStringLiteral(""); | ||||||
| 
 | 
 | ||||||
| void Config::ReadVideoDumpingValues() { | void Config::ReadVideoDumpingValues() { | ||||||
|     qt_config->beginGroup(QStringLiteral("VideoDumping")); |     qt_config->beginGroup(QStringLiteral("VideoDumping")); | ||||||
|  | @ -1013,9 +1013,9 @@ void Config::SaveRendererValues() { | ||||||
|                  200); |                  200); | ||||||
| 
 | 
 | ||||||
|     // Cast to double because Qt's written float values are not human-readable
 |     // Cast to double because Qt's written float values are not human-readable
 | ||||||
|     WriteSetting(QStringLiteral("bg_red"), (double)Settings::values.bg_red, 0.0); |     WriteSetting(QStringLiteral("bg_red"), static_cast<double>(Settings::values.bg_red), 0.0); | ||||||
|     WriteSetting(QStringLiteral("bg_green"), (double)Settings::values.bg_green, 0.0); |     WriteSetting(QStringLiteral("bg_green"), static_cast<double>(Settings::values.bg_green), 0.0); | ||||||
|     WriteSetting(QStringLiteral("bg_blue"), (double)Settings::values.bg_blue, 0.0); |     WriteSetting(QStringLiteral("bg_blue"), static_cast<double>(Settings::values.bg_blue), 0.0); | ||||||
| 
 | 
 | ||||||
|     WriteSetting(QStringLiteral("texture_filter_name"), |     WriteSetting(QStringLiteral("texture_filter_name"), | ||||||
|                  QString::fromStdString(Settings::values.texture_filter_name), |                  QString::fromStdString(Settings::values.texture_filter_name), | ||||||
|  |  | ||||||
|  | @ -9,8 +9,6 @@ | ||||||
| #include <QMessageBox> | #include <QMessageBox> | ||||||
| #include <QWidget> | #include <QWidget> | ||||||
| #include "citra_qt/configuration/configure_camera.h" | #include "citra_qt/configuration/configure_camera.h" | ||||||
| #include "citra_qt/uisettings.h" |  | ||||||
| #include "core/core.h" |  | ||||||
| #include "core/frontend/camera/factory.h" | #include "core/frontend/camera/factory.h" | ||||||
| #include "core/frontend/camera/interface.h" | #include "core/frontend/camera/interface.h" | ||||||
| #include "core/hle/service/cam/cam.h" | #include "core/hle/service/cam/cam.h" | ||||||
|  | @ -91,7 +89,7 @@ void ConfigureCamera::ConnectEvents() { | ||||||
|                 SetConfiguration(); |                 SetConfiguration(); | ||||||
|             }); |             }); | ||||||
|     connect(ui->toolButton, &QToolButton::clicked, this, &ConfigureCamera::OnToolButtonClicked); |     connect(ui->toolButton, &QToolButton::clicked, this, &ConfigureCamera::OnToolButtonClicked); | ||||||
|     connect(ui->preview_button, &QPushButton::clicked, this, [=] { StartPreviewing(); }); |     connect(ui->preview_button, &QPushButton::clicked, this, [this] { StartPreviewing(); }); | ||||||
|     connect(ui->prompt_before_load, &QCheckBox::stateChanged, this, [this](int state) { |     connect(ui->prompt_before_load, &QCheckBox::stateChanged, this, [this](int state) { | ||||||
|         ui->camera_file->setDisabled(state == Qt::Checked); |         ui->camera_file->setDisabled(state == Qt::Checked); | ||||||
|         ui->toolButton->setDisabled(state == Qt::Checked); |         ui->toolButton->setDisabled(state == Qt::Checked); | ||||||
|  | @ -99,12 +97,11 @@ void ConfigureCamera::ConnectEvents() { | ||||||
|             ui->camera_file->setText(QString{}); |             ui->camera_file->setText(QString{}); | ||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
|     connect(ui->camera_file, &QLineEdit::textChanged, this, [=] { StopPreviewing(); }); |     connect(ui->camera_file, &QLineEdit::textChanged, this, [this] { StopPreviewing(); }); | ||||||
|     connect(ui->system_camera, |     connect(ui->system_camera, qOverload<int>(&QComboBox::currentIndexChanged), this, | ||||||
|             static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, |             [this] { StopPreviewing(); }); | ||||||
|             [=] { StopPreviewing(); }); |     connect(ui->camera_flip, qOverload<int>(&QComboBox::currentIndexChanged), this, | ||||||
|     connect(ui->camera_flip, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), |             [this] { StopPreviewing(); }); | ||||||
|             this, [=] { StopPreviewing(); }); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ConfigureCamera::UpdateCameraMode() { | void ConfigureCamera::UpdateCameraMode() { | ||||||
|  |  | ||||||
|  | @ -24,7 +24,9 @@ ConfigureDebug::ConfigureDebug(QWidget* parent) | ||||||
|         QString path = QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::LogDir)); |         QString path = QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::LogDir)); | ||||||
|         QDesktopServices::openUrl(QUrl::fromLocalFile(path)); |         QDesktopServices::openUrl(QUrl::fromLocalFile(path)); | ||||||
|     }); |     }); | ||||||
|     ui->toggle_cpu_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn()); | 
 | ||||||
|  |     const bool is_powered_on = Core::System::GetInstance().IsPoweredOn(); | ||||||
|  |     ui->toggle_cpu_jit->setEnabled(!is_powered_on); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ConfigureDebug::~ConfigureDebug() = default; | ConfigureDebug::~ConfigureDebug() = default; | ||||||
|  |  | ||||||
|  | @ -114,6 +114,9 @@ | ||||||
|      <layout class="QVBoxLayout" name="verticalLayout_4"> |      <layout class="QVBoxLayout" name="verticalLayout_4"> | ||||||
|       <item> |       <item> | ||||||
|        <widget class="QCheckBox" name="toggle_cpu_jit"> |        <widget class="QCheckBox" name="toggle_cpu_jit"> | ||||||
|  |         <property name="toolTip"> | ||||||
|  |          <string><html><head/><body><p>Enables the use of the ARM JIT compiler for emulating the 3DS CPUs. Don't disable unless for debugging purposes</p></body></html></string> | ||||||
|  |         </property> | ||||||
|         <property name="text"> |         <property name="text"> | ||||||
|          <string>Enable CPU JIT</string> |          <string>Enable CPU JIT</string> | ||||||
|         </property> |         </property> | ||||||
|  |  | ||||||
|  | @ -192,10 +192,10 @@ ConfigureInput::ConfigureInput(QWidget* parent) | ||||||
|         if (!button_map[button_id]) |         if (!button_map[button_id]) | ||||||
|             continue; |             continue; | ||||||
|         button_map[button_id]->setContextMenuPolicy(Qt::CustomContextMenu); |         button_map[button_id]->setContextMenuPolicy(Qt::CustomContextMenu); | ||||||
|         connect(button_map[button_id], &QPushButton::clicked, [=]() { |         connect(button_map[button_id], &QPushButton::clicked, [this, button_id]() { | ||||||
|             HandleClick( |             HandleClick( | ||||||
|                 button_map[button_id], |                 button_map[button_id], | ||||||
|                 [=](const Common::ParamPackage& params) { |                 [this, button_id](const Common::ParamPackage& params) { | ||||||
|                     buttons_param[button_id] = params; |                     buttons_param[button_id] = params; | ||||||
|                     // If the user closes the dialog, the changes are reverted in
 |                     // If the user closes the dialog, the changes are reverted in
 | ||||||
|                     // `GMainWindow::OnConfigure()`
 |                     // `GMainWindow::OnConfigure()`
 | ||||||
|  | @ -204,16 +204,16 @@ ConfigureInput::ConfigureInput(QWidget* parent) | ||||||
|                 }, |                 }, | ||||||
|                 InputCommon::Polling::DeviceType::Button); |                 InputCommon::Polling::DeviceType::Button); | ||||||
|         }); |         }); | ||||||
|         connect(button_map[button_id], &QPushButton::customContextMenuRequested, |         connect(button_map[button_id], &QPushButton::customContextMenuRequested, this, | ||||||
|                 [=](const QPoint& menu_location) { |                 [this, button_id](const QPoint& menu_location) { | ||||||
|                     QMenu context_menu; |                     QMenu context_menu; | ||||||
|                     context_menu.addAction(tr("Clear"), [&] { |                     context_menu.addAction(tr("Clear"), this, [&] { | ||||||
|                         buttons_param[button_id].Clear(); |                         buttons_param[button_id].Clear(); | ||||||
|                         button_map[button_id]->setText(tr("[not set]")); |                         button_map[button_id]->setText(tr("[not set]")); | ||||||
|                         ApplyConfiguration(); |                         ApplyConfiguration(); | ||||||
|                         Settings::SaveProfile(ui->profile->currentIndex()); |                         Settings::SaveProfile(ui->profile->currentIndex()); | ||||||
|                     }); |                     }); | ||||||
|                     context_menu.addAction(tr("Restore Default"), [&] { |                     context_menu.addAction(tr("Restore Default"), this, [&] { | ||||||
|                         buttons_param[button_id] = Common::ParamPackage{ |                         buttons_param[button_id] = Common::ParamPackage{ | ||||||
|                             InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])}; |                             InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])}; | ||||||
|                         button_map[button_id]->setText(ButtonToText(buttons_param[button_id])); |                         button_map[button_id]->setText(ButtonToText(buttons_param[button_id])); | ||||||
|  | @ -230,10 +230,11 @@ ConfigureInput::ConfigureInput(QWidget* parent) | ||||||
|                 continue; |                 continue; | ||||||
|             analog_map_buttons[analog_id][sub_button_id]->setContextMenuPolicy( |             analog_map_buttons[analog_id][sub_button_id]->setContextMenuPolicy( | ||||||
|                 Qt::CustomContextMenu); |                 Qt::CustomContextMenu); | ||||||
|             connect(analog_map_buttons[analog_id][sub_button_id], &QPushButton::clicked, [=]() { |             connect(analog_map_buttons[analog_id][sub_button_id], &QPushButton::clicked, this, | ||||||
|  |                     [this, analog_id, sub_button_id]() { | ||||||
|                         HandleClick( |                         HandleClick( | ||||||
|                             analog_map_buttons[analog_id][sub_button_id], |                             analog_map_buttons[analog_id][sub_button_id], | ||||||
|                     [=](const Common::ParamPackage& params) { |                             [this, analog_id, sub_button_id](const Common::ParamPackage& params) { | ||||||
|                                 SetAnalogButton(params, analogs_param[analog_id], |                                 SetAnalogButton(params, analogs_param[analog_id], | ||||||
|                                                 analog_sub_buttons[sub_button_id]); |                                                 analog_sub_buttons[sub_button_id]); | ||||||
|                                 ApplyConfiguration(); |                                 ApplyConfiguration(); | ||||||
|  | @ -242,15 +243,16 @@ ConfigureInput::ConfigureInput(QWidget* parent) | ||||||
|                             InputCommon::Polling::DeviceType::Button); |                             InputCommon::Polling::DeviceType::Button); | ||||||
|                     }); |                     }); | ||||||
|             connect(analog_map_buttons[analog_id][sub_button_id], |             connect(analog_map_buttons[analog_id][sub_button_id], | ||||||
|                     &QPushButton::customContextMenuRequested, [=](const QPoint& menu_location) { |                     &QPushButton::customContextMenuRequested, this, | ||||||
|  |                     [this, analog_id, sub_button_id](const QPoint& menu_location) { | ||||||
|                         QMenu context_menu; |                         QMenu context_menu; | ||||||
|                         context_menu.addAction(tr("Clear"), [&] { |                         context_menu.addAction(tr("Clear"), this, [&] { | ||||||
|                             analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]); |                             analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]); | ||||||
|                             analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]")); |                             analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]")); | ||||||
|                             ApplyConfiguration(); |                             ApplyConfiguration(); | ||||||
|                             Settings::SaveProfile(ui->profile->currentIndex()); |                             Settings::SaveProfile(ui->profile->currentIndex()); | ||||||
|                         }); |                         }); | ||||||
|                         context_menu.addAction(tr("Restore Default"), [&] { |                         context_menu.addAction(tr("Restore Default"), this, [&] { | ||||||
|                             Common::ParamPackage params{InputCommon::GenerateKeyboardParam( |                             Common::ParamPackage params{InputCommon::GenerateKeyboardParam( | ||||||
|                                 Config::default_analogs[analog_id][sub_button_id])}; |                                 Config::default_analogs[analog_id][sub_button_id])}; | ||||||
|                             SetAnalogButton(params, analogs_param[analog_id], |                             SetAnalogButton(params, analogs_param[analog_id], | ||||||
|  | @ -264,7 +266,7 @@ ConfigureInput::ConfigureInput(QWidget* parent) | ||||||
|                             menu_location)); |                             menu_location)); | ||||||
|                     }); |                     }); | ||||||
|         } |         } | ||||||
|         connect(analog_map_stick[analog_id], &QPushButton::clicked, [=]() { |         connect(analog_map_stick[analog_id], &QPushButton::clicked, this, [this, analog_id]() { | ||||||
|             if (QMessageBox::information( |             if (QMessageBox::information( | ||||||
|                     this, tr("Information"), |                     this, tr("Information"), | ||||||
|                     tr("After pressing OK, first move your joystick horizontally, " |                     tr("After pressing OK, first move your joystick horizontally, " | ||||||
|  | @ -272,7 +274,7 @@ ConfigureInput::ConfigureInput(QWidget* parent) | ||||||
|                     QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) { |                     QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) { | ||||||
|                 HandleClick( |                 HandleClick( | ||||||
|                     analog_map_stick[analog_id], |                     analog_map_stick[analog_id], | ||||||
|                     [=](const Common::ParamPackage& params) { |                     [this, analog_id](const Common::ParamPackage& params) { | ||||||
|                         analogs_param[analog_id] = params; |                         analogs_param[analog_id] = params; | ||||||
|                         ApplyConfiguration(); |                         ApplyConfiguration(); | ||||||
|                         Settings::SaveProfile(ui->profile->currentIndex()); |                         Settings::SaveProfile(ui->profile->currentIndex()); | ||||||
|  | @ -280,8 +282,10 @@ ConfigureInput::ConfigureInput(QWidget* parent) | ||||||
|                     InputCommon::Polling::DeviceType::Analog); |                     InputCommon::Polling::DeviceType::Analog); | ||||||
|             } |             } | ||||||
|         }); |         }); | ||||||
|         connect(analog_map_deadzone_and_modifier_slider[analog_id], &QSlider::valueChanged, [=] { |         connect(analog_map_deadzone_and_modifier_slider[analog_id], &QSlider::valueChanged, this, | ||||||
|             const int slider_value = analog_map_deadzone_and_modifier_slider[analog_id]->value(); |                 [this, analog_id] { | ||||||
|  |                     const int slider_value = | ||||||
|  |                         analog_map_deadzone_and_modifier_slider[analog_id]->value(); | ||||||
|                     const auto engine = analogs_param[analog_id].Get("engine", ""); |                     const auto engine = analogs_param[analog_id].Get("engine", ""); | ||||||
|                     if (engine == "sdl" || engine == "gcpad") { |                     if (engine == "sdl" || engine == "gcpad") { | ||||||
|                         analog_map_deadzone_and_modifier_slider_label[analog_id]->setText( |                         analog_map_deadzone_and_modifier_slider_label[analog_id]->setText( | ||||||
|  | @ -299,10 +303,10 @@ ConfigureInput::ConfigureInput(QWidget* parent) | ||||||
| 
 | 
 | ||||||
|     // The Circle Mod button is common for both the sticks, so update the modifier settings
 |     // The Circle Mod button is common for both the sticks, so update the modifier settings
 | ||||||
|     // for both the sticks.
 |     // for both the sticks.
 | ||||||
|     connect(ui->buttonCircleMod, &QPushButton::clicked, [=]() { |     connect(ui->buttonCircleMod, &QPushButton::clicked, this, [this]() { | ||||||
|         HandleClick( |         HandleClick( | ||||||
|             ui->buttonCircleMod, |             ui->buttonCircleMod, | ||||||
|             [=](const Common::ParamPackage& params) { |             [this](const Common::ParamPackage& params) { | ||||||
|                 for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; |                 for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; | ||||||
|                      analog_id++) { |                      analog_id++) { | ||||||
|                     SetAnalogButton(params, analogs_param[analog_id], "modifier"); |                     SetAnalogButton(params, analogs_param[analog_id], "modifier"); | ||||||
|  | @ -312,10 +316,10 @@ ConfigureInput::ConfigureInput(QWidget* parent) | ||||||
|             }, |             }, | ||||||
|             InputCommon::Polling::DeviceType::Button); |             InputCommon::Polling::DeviceType::Button); | ||||||
|     }); |     }); | ||||||
|     connect(ui->buttonCircleMod, &QPushButton::customContextMenuRequested, |     connect(ui->buttonCircleMod, &QPushButton::customContextMenuRequested, this, | ||||||
|             [&](const QPoint& menu_location) { |             [&](const QPoint& menu_location) { | ||||||
|                 QMenu context_menu; |                 QMenu context_menu; | ||||||
|                 context_menu.addAction(tr("Clear"), [&] { |                 context_menu.addAction(tr("Clear"), this, [&] { | ||||||
|                     for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; |                     for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; | ||||||
|                          analog_id++) { |                          analog_id++) { | ||||||
|                         analogs_param[analog_id].Erase("modifier"); |                         analogs_param[analog_id].Erase("modifier"); | ||||||
|  | @ -325,7 +329,7 @@ ConfigureInput::ConfigureInput(QWidget* parent) | ||||||
|                     Settings::SaveProfile(ui->profile->currentIndex()); |                     Settings::SaveProfile(ui->profile->currentIndex()); | ||||||
|                 }); |                 }); | ||||||
| 
 | 
 | ||||||
|                 context_menu.addAction(tr("Restore Default"), [&] { |                 context_menu.addAction(tr("Restore Default"), this, [&] { | ||||||
|                     for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; |                     for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; | ||||||
|                          analog_id++) { |                          analog_id++) { | ||||||
|                         Common::ParamPackage params{InputCommon::GenerateKeyboardParam( |                         Common::ParamPackage params{InputCommon::GenerateKeyboardParam( | ||||||
|  | @ -341,7 +345,7 @@ ConfigureInput::ConfigureInput(QWidget* parent) | ||||||
|                 context_menu.exec(ui->buttonCircleMod->mapToGlobal(menu_location)); |                 context_menu.exec(ui->buttonCircleMod->mapToGlobal(menu_location)); | ||||||
|             }); |             }); | ||||||
| 
 | 
 | ||||||
|     connect(ui->buttonMotionTouch, &QPushButton::clicked, [this] { |     connect(ui->buttonMotionTouch, &QPushButton::clicked, this, [this] { | ||||||
|         QDialog* motion_touch_dialog = new ConfigureMotionTouch(this); |         QDialog* motion_touch_dialog = new ConfigureMotionTouch(this); | ||||||
|         return motion_touch_dialog->exec(); |         return motion_touch_dialog->exec(); | ||||||
|     }); |     }); | ||||||
|  | @ -356,8 +360,7 @@ ConfigureInput::ConfigureInput(QWidget* parent) | ||||||
|     connect(ui->buttonDelete, &QPushButton::clicked, this, &ConfigureInput::DeleteProfile); |     connect(ui->buttonDelete, &QPushButton::clicked, this, &ConfigureInput::DeleteProfile); | ||||||
|     connect(ui->buttonRename, &QPushButton::clicked, this, &ConfigureInput::RenameProfile); |     connect(ui->buttonRename, &QPushButton::clicked, this, &ConfigureInput::RenameProfile); | ||||||
| 
 | 
 | ||||||
|     connect(ui->profile, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), |     connect(ui->profile, qOverload<int>(&QComboBox::currentIndexChanged), this, [this](int i) { | ||||||
|             [this](int i) { |  | ||||||
|         ApplyConfiguration(); |         ApplyConfiguration(); | ||||||
|         Settings::SaveProfile(Settings::values.current_input_profile_index); |         Settings::SaveProfile(Settings::values.current_input_profile_index); | ||||||
|         Settings::LoadProfile(i); |         Settings::LoadProfile(i); | ||||||
|  | @ -365,9 +368,9 @@ ConfigureInput::ConfigureInput(QWidget* parent) | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     timeout_timer->setSingleShot(true); |     timeout_timer->setSingleShot(true); | ||||||
|     connect(timeout_timer.get(), &QTimer::timeout, [this]() { SetPollingResult({}, true); }); |     connect(timeout_timer.get(), &QTimer::timeout, this, [this]() { SetPollingResult({}, true); }); | ||||||
| 
 | 
 | ||||||
|     connect(poll_timer.get(), &QTimer::timeout, [this]() { |     connect(poll_timer.get(), &QTimer::timeout, this, [this]() { | ||||||
|         Common::ParamPackage params; |         Common::ParamPackage params; | ||||||
|         for (auto& poller : device_pollers) { |         for (auto& poller : device_pollers) { | ||||||
|             params = poller->GetNextInput(); |             params = poller->GetNextInput(); | ||||||
|  | @ -554,7 +557,7 @@ void ConfigureInput::AutoMap() { | ||||||
|                                  QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel) { |                                  QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     input_setter = [=](const Common::ParamPackage& params) { |     input_setter = [this](const Common::ParamPackage& params) { | ||||||
|         MapFromButton(params); |         MapFromButton(params); | ||||||
|         ApplyConfiguration(); |         ApplyConfiguration(); | ||||||
|         Settings::SaveProfile(ui->profile->currentIndex()); |         Settings::SaveProfile(ui->profile->currentIndex()); | ||||||
|  |  | ||||||
|  | @ -47,6 +47,9 @@ CalibrationConfigurationDialog::CalibrationConfigurationDialog(QWidget* parent, | ||||||
|             case CalibrationConfigurationJob::Status::Completed: |             case CalibrationConfigurationJob::Status::Completed: | ||||||
|                 text = tr("Configuration completed!"); |                 text = tr("Configuration completed!"); | ||||||
|                 break; |                 break; | ||||||
|  |             default: | ||||||
|  |                 LOG_ERROR(Frontend, "Unknown calibration status {}", status); | ||||||
|  |                 break; | ||||||
|             } |             } | ||||||
|             QMetaObject::invokeMethod(this, "UpdateLabelText", Q_ARG(QString, text)); |             QMetaObject::invokeMethod(this, "UpdateLabelText", Q_ARG(QString, text)); | ||||||
|             if (status == CalibrationConfigurationJob::Status::Completed) { |             if (status == CalibrationConfigurationJob::Status::Completed) { | ||||||
|  | @ -102,9 +105,9 @@ ConfigureMotionTouch::ConfigureMotionTouch(QWidget* parent) | ||||||
|            "style=\"text-decoration: underline; color:#039be5;\">Learn More</span></a>")); |            "style=\"text-decoration: underline; color:#039be5;\">Learn More</span></a>")); | ||||||
| 
 | 
 | ||||||
|     timeout_timer->setSingleShot(true); |     timeout_timer->setSingleShot(true); | ||||||
|     connect(timeout_timer.get(), &QTimer::timeout, [this]() { SetPollingResult({}, true); }); |     connect(timeout_timer.get(), &QTimer::timeout, this, [this]() { SetPollingResult({}, true); }); | ||||||
| 
 | 
 | ||||||
|     connect(poll_timer.get(), &QTimer::timeout, [this]() { |     connect(poll_timer.get(), &QTimer::timeout, this, [this]() { | ||||||
|         Common::ParamPackage params; |         Common::ParamPackage params; | ||||||
|         for (auto& poller : device_pollers) { |         for (auto& poller : device_pollers) { | ||||||
|             params = poller->GetNextInput(); |             params = poller->GetNextInput(); | ||||||
|  | @ -202,7 +205,7 @@ void ConfigureMotionTouch::ConnectEvents() { | ||||||
|             [this]([[maybe_unused]] int index) { UpdateUiDisplay(); }); |             [this]([[maybe_unused]] int index) { UpdateUiDisplay(); }); | ||||||
|     connect(ui->touch_provider, qOverload<int>(&QComboBox::currentIndexChanged), this, |     connect(ui->touch_provider, qOverload<int>(&QComboBox::currentIndexChanged), this, | ||||||
|             [this]([[maybe_unused]] int index) { UpdateUiDisplay(); }); |             [this]([[maybe_unused]] int index) { UpdateUiDisplay(); }); | ||||||
|     connect(ui->motion_controller_button, &QPushButton::clicked, [=]() { |     connect(ui->motion_controller_button, &QPushButton::clicked, this, [this]() { | ||||||
|         if (QMessageBox::information(this, tr("Information"), |         if (QMessageBox::information(this, tr("Information"), | ||||||
|                                      tr("After pressing OK, press a button on the controller whose " |                                      tr("After pressing OK, press a button on the controller whose " | ||||||
|                                         "motion you want to track."), |                                         "motion you want to track."), | ||||||
|  | @ -210,7 +213,7 @@ void ConfigureMotionTouch::ConnectEvents() { | ||||||
|             ui->motion_controller_button->setText(tr("[press button]")); |             ui->motion_controller_button->setText(tr("[press button]")); | ||||||
|             ui->motion_controller_button->setFocus(); |             ui->motion_controller_button->setFocus(); | ||||||
| 
 | 
 | ||||||
|             input_setter = [=](const Common::ParamPackage& params) { |             input_setter = [this](const Common::ParamPackage& params) { | ||||||
|                 guid = params.Get("guid", "0"); |                 guid = params.Get("guid", "0"); | ||||||
|                 port = params.Get("port", 0); |                 port = params.Get("port", 0); | ||||||
|             }; |             }; | ||||||
|  |  | ||||||
|  | @ -511,7 +511,7 @@ void TouchScreenPreview::mouseMoveEvent(QMouseEvent* event) { | ||||||
|     } |     } | ||||||
|     const auto pos = MapToDeviceCoords(event->x(), event->y()); |     const auto pos = MapToDeviceCoords(event->x(), event->y()); | ||||||
|     if (pos) { |     if (pos) { | ||||||
|         coord_label->setText(QStringLiteral("X: %1, Y: %2").arg(pos->x()).arg(pos->y())); |         coord_label->setText(QStringLiteral("X: %1, Y: %2").arg(pos->x(), pos->y())); | ||||||
|     } else { |     } else { | ||||||
|         coord_label->clear(); |         coord_label->clear(); | ||||||
|     } |     } | ||||||
|  | @ -572,7 +572,7 @@ bool TouchScreenPreview::eventFilter(QObject* obj, QEvent* event) { | ||||||
|             emit DotMoved(drag_state.dot->property(PropId).toInt(), *device_coord); |             emit DotMoved(drag_state.dot->property(PropId).toInt(), *device_coord); | ||||||
|             if (coord_label) { |             if (coord_label) { | ||||||
|                 coord_label->setText( |                 coord_label->setText( | ||||||
|                     QStringLiteral("X: %1, Y: %2").arg(device_coord->x()).arg(device_coord->y())); |                     QStringLiteral("X: %1, Y: %2").arg(device_coord->x(), device_coord->y())); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         return true; |         return true; | ||||||
|  |  | ||||||
|  | @ -9,7 +9,6 @@ | ||||||
| #include <QVBoxLayout> | #include <QVBoxLayout> | ||||||
| #include "citra_qt/debugger/graphics/graphics_breakpoints.h" | #include "citra_qt/debugger/graphics/graphics_breakpoints.h" | ||||||
| #include "citra_qt/debugger/graphics/graphics_breakpoints_p.h" | #include "citra_qt/debugger/graphics/graphics_breakpoints_p.h" | ||||||
| #include "common/assert.h" |  | ||||||
| 
 | 
 | ||||||
| BreakPointModel::BreakPointModel(std::shared_ptr<Pica::DebugContext> debug_context, QObject* parent) | BreakPointModel::BreakPointModel(std::shared_ptr<Pica::DebugContext> debug_context, QObject* parent) | ||||||
|     : QAbstractListModel(parent), context_weak(debug_context), |     : QAbstractListModel(parent), context_weak(debug_context), | ||||||
|  | @ -60,12 +59,15 @@ QVariant BreakPointModel::data(const QModelIndex& index, int role) const { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Qt::ItemFlags BreakPointModel::flags(const QModelIndex& index) const { | Qt::ItemFlags BreakPointModel::flags(const QModelIndex& index) const { | ||||||
|     if (!index.isValid()) |     if (!index.isValid()) { | ||||||
|         return 0; |         return {}; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     Qt::ItemFlags flags = Qt::ItemIsEnabled; |     Qt::ItemFlags flags = Qt::ItemIsEnabled; | ||||||
|     if (index.column() == 0) |     if (index.column() == 0) { | ||||||
|         flags |= Qt::ItemIsUserCheckable; |         flags |= Qt::ItemIsUserCheckable; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     return flags; |     return flags; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -14,7 +14,6 @@ | ||||||
| #include <QTreeView> | #include <QTreeView> | ||||||
| #include <QVBoxLayout> | #include <QVBoxLayout> | ||||||
| #include "citra_qt/debugger/graphics/graphics_cmdlists.h" | #include "citra_qt/debugger/graphics/graphics_cmdlists.h" | ||||||
| #include "citra_qt/util/spinbox.h" |  | ||||||
| #include "citra_qt/util/util.h" | #include "citra_qt/util/util.h" | ||||||
| #include "common/vector_math.h" | #include "common/vector_math.h" | ||||||
| #include "core/core.h" | #include "core/core.h" | ||||||
|  | @ -130,7 +129,7 @@ void GPUCommandListWidget::OnCommandDoubleClicked(const QModelIndex& index) { | ||||||
|         COMMAND_IN_RANGE(command_id, texturing.texture1) || |         COMMAND_IN_RANGE(command_id, texturing.texture1) || | ||||||
|         COMMAND_IN_RANGE(command_id, texturing.texture2)) { |         COMMAND_IN_RANGE(command_id, texturing.texture2)) { | ||||||
| 
 | 
 | ||||||
|         unsigned texture_index; |         [[maybe_unused]] u32 texture_index; | ||||||
|         if (COMMAND_IN_RANGE(command_id, texturing.texture0)) { |         if (COMMAND_IN_RANGE(command_id, texturing.texture0)) { | ||||||
|             texture_index = 0; |             texture_index = 0; | ||||||
|         } else if (COMMAND_IN_RANGE(command_id, texturing.texture1)) { |         } else if (COMMAND_IN_RANGE(command_id, texturing.texture1)) { | ||||||
|  |  | ||||||
|  | @ -34,12 +34,15 @@ void SurfacePicture::mousePressEvent(QMouseEvent* event) { | ||||||
|     if (!(event->buttons() & Qt::LeftButton)) |     if (!(event->buttons() & Qt::LeftButton)) | ||||||
|         return; |         return; | ||||||
| 
 | 
 | ||||||
|     if (pixmap() == nullptr) |     const QPixmap pixmap = this->pixmap(Qt::ReturnByValue); | ||||||
|  |     if (pixmap.isNull()) { | ||||||
|         return; |         return; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     if (surface_widget) |     if (surface_widget) { | ||||||
|         surface_widget->Pick(event->x() * pixmap()->width() / width(), |         surface_widget->Pick(event->x() * pixmap.width() / width(), | ||||||
|                              event->y() * pixmap()->height() / height()); |                              event->y() * pixmap.height() / height()); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void SurfacePicture::mouseMoveEvent(QMouseEvent* event) { | void SurfacePicture::mouseMoveEvent(QMouseEvent* event) { | ||||||
|  | @ -314,57 +317,46 @@ void GraphicsSurfaceWidget::Pick(int x, int y) { | ||||||
|         case Format::RGBA8: { |         case Format::RGBA8: { | ||||||
|             auto value = Color::DecodeRGBA8(pixel) / 255.0f; |             auto value = Color::DecodeRGBA8(pixel) / 255.0f; | ||||||
|             return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4") |             return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4") | ||||||
|                 .arg(QString::number(value.r(), 'f', 2)) |                 .arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2), | ||||||
|                 .arg(QString::number(value.g(), 'f', 2)) |                      QString::number(value.b(), 'f', 2), QString::number(value.a(), 'f', 2)); | ||||||
|                 .arg(QString::number(value.b(), 'f', 2)) |  | ||||||
|                 .arg(QString::number(value.a(), 'f', 2)); |  | ||||||
|         } |         } | ||||||
|         case Format::RGB8: { |         case Format::RGB8: { | ||||||
|             auto value = Color::DecodeRGB8(pixel) / 255.0f; |             auto value = Color::DecodeRGB8(pixel) / 255.0f; | ||||||
|             return QStringLiteral("Red: %1, Green: %2, Blue: %3") |             return QStringLiteral("Red: %1, Green: %2, Blue: %3") | ||||||
|                 .arg(QString::number(value.r(), 'f', 2)) |                 .arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2), | ||||||
|                 .arg(QString::number(value.g(), 'f', 2)) |                      QString::number(value.b(), 'f', 2)); | ||||||
|                 .arg(QString::number(value.b(), 'f', 2)); |  | ||||||
|         } |         } | ||||||
|         case Format::RGB5A1: { |         case Format::RGB5A1: { | ||||||
|             auto value = Color::DecodeRGB5A1(pixel) / 255.0f; |             auto value = Color::DecodeRGB5A1(pixel) / 255.0f; | ||||||
|             return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4") |             return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4") | ||||||
|                 .arg(QString::number(value.r(), 'f', 2)) |                 .arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2), | ||||||
|                 .arg(QString::number(value.g(), 'f', 2)) |                      QString::number(value.b(), 'f', 2), QString::number(value.a(), 'f', 2)); | ||||||
|                 .arg(QString::number(value.b(), 'f', 2)) |  | ||||||
|                 .arg(QString::number(value.a(), 'f', 2)); |  | ||||||
|         } |         } | ||||||
|         case Format::RGB565: { |         case Format::RGB565: { | ||||||
|             auto value = Color::DecodeRGB565(pixel) / 255.0f; |             auto value = Color::DecodeRGB565(pixel) / 255.0f; | ||||||
|             return QStringLiteral("Red: %1, Green: %2, Blue: %3") |             return QStringLiteral("Red: %1, Green: %2, Blue: %3") | ||||||
|                 .arg(QString::number(value.r(), 'f', 2)) |                 .arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2), | ||||||
|                 .arg(QString::number(value.g(), 'f', 2)) |                      QString::number(value.b(), 'f', 2)); | ||||||
|                 .arg(QString::number(value.b(), 'f', 2)); |  | ||||||
|         } |         } | ||||||
|         case Format::RGBA4: { |         case Format::RGBA4: { | ||||||
|             auto value = Color::DecodeRGBA4(pixel) / 255.0f; |             auto value = Color::DecodeRGBA4(pixel) / 255.0f; | ||||||
|             return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4") |             return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4") | ||||||
|                 .arg(QString::number(value.r(), 'f', 2)) |                 .arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2), | ||||||
|                 .arg(QString::number(value.g(), 'f', 2)) |                      QString::number(value.b(), 'f', 2), QString::number(value.a(), 'f', 2)); | ||||||
|                 .arg(QString::number(value.b(), 'f', 2)) |  | ||||||
|                 .arg(QString::number(value.a(), 'f', 2)); |  | ||||||
|         } |         } | ||||||
|         case Format::IA8: |         case Format::IA8: | ||||||
|             return QStringLiteral("Index: %1, Alpha: %2").arg(pixel[0]).arg(pixel[1]); |             return QStringLiteral("Index: %1, Alpha: %2").arg(pixel[0], pixel[1]); | ||||||
|         case Format::RG8: { |         case Format::RG8: { | ||||||
|             auto value = Color::DecodeRG8(pixel) / 255.0f; |             auto value = Color::DecodeRG8(pixel) / 255.0f; | ||||||
|             return QStringLiteral("Red: %1, Green: %2") |             return QStringLiteral("Red: %1, Green: %2") | ||||||
|                 .arg(QString::number(value.r(), 'f', 2)) |                 .arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2)); | ||||||
|                 .arg(QString::number(value.g(), 'f', 2)); |  | ||||||
|         } |         } | ||||||
|         case Format::I8: |         case Format::I8: | ||||||
|             return QStringLiteral("Index: %1").arg(*pixel); |             return QStringLiteral("Index: %1").arg(*pixel); | ||||||
|         case Format::A8: |         case Format::A8: | ||||||
|             return QStringLiteral("Alpha: %1").arg(QString::number(*pixel / 255.0f, 'f', 2)); |             return QStringLiteral("Alpha: %1").arg(QString::number(*pixel / 255.0f, 'f', 2)); | ||||||
|         case Format::IA4: |         case Format::IA4: | ||||||
|             return QStringLiteral("Index: %1, Alpha: %2") |             return QStringLiteral("Index: %1, Alpha: %2").arg(*pixel & 0xF, (*pixel & 0xF0) >> 4); | ||||||
|                 .arg(*pixel & 0xF) |  | ||||||
|                 .arg((*pixel & 0xF0) >> 4); |  | ||||||
|         case Format::I4: { |         case Format::I4: { | ||||||
|             u8 i = (*pixel >> ((offset % 2) ? 4 : 0)) & 0xF; |             u8 i = (*pixel >> ((offset % 2) ? 4 : 0)) & 0xF; | ||||||
|             return QStringLiteral("Index: %1").arg(i); |             return QStringLiteral("Index: %1").arg(i); | ||||||
|  | @ -390,8 +382,7 @@ void GraphicsSurfaceWidget::Pick(int x, int y) { | ||||||
|         case Format::X24S8: { |         case Format::X24S8: { | ||||||
|             auto values = Color::DecodeD24S8(pixel); |             auto values = Color::DecodeD24S8(pixel); | ||||||
|             return QStringLiteral("Depth: %1, Stencil: %2") |             return QStringLiteral("Depth: %1, Stencil: %2") | ||||||
|                 .arg(QString::number(values[0] / (float)0xFFFFFF, 'f', 4)) |                 .arg(QString::number(values[0] / (float)0xFFFFFF, 'f', 4), values[1]); | ||||||
|                 .arg(values[1]); |  | ||||||
|         } |         } | ||||||
|         case Format::Unknown: |         case Format::Unknown: | ||||||
|             return QStringLiteral("Unknown format"); |             return QStringLiteral("Unknown format"); | ||||||
|  | @ -401,8 +392,8 @@ void GraphicsSurfaceWidget::Pick(int x, int y) { | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     QString nibbles; |     QString nibbles; | ||||||
|     for (unsigned i = 0; i < nibbles_per_pixel; i++) { |     for (u32 i = 0; i < nibbles_per_pixel; i++) { | ||||||
|         unsigned nibble_index = i; |         u32 nibble_index = i; | ||||||
|         if (nibble_mode) { |         if (nibble_mode) { | ||||||
|             nibble_index += (offset % 2) ? 0 : 1; |             nibble_index += (offset % 2) ? 0 : 1; | ||||||
|         } |         } | ||||||
|  | @ -412,7 +403,7 @@ void GraphicsSurfaceWidget::Pick(int x, int y) { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     surface_info_label->setText( |     surface_info_label->setText( | ||||||
|         QStringLiteral("Raw: 0x%3\n(%4)").arg(nibbles).arg(GetText(surface_format, pixel))); |         QStringLiteral("Raw: 0x%3\n(%4)").arg(nibbles, GetText(surface_format, pixel))); | ||||||
|     surface_info_label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); |     surface_info_label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -676,8 +667,8 @@ void GraphicsSurfaceWidget::SaveSurface() { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (selected_filter == png_filter) { |     if (selected_filter == png_filter) { | ||||||
|         const QPixmap* const pixmap = surface_picture_label->pixmap(); |         const QPixmap pixmap = surface_picture_label->pixmap(Qt::ReturnByValue); | ||||||
|         ASSERT_MSG(pixmap != nullptr, "No pixmap set"); |         ASSERT_MSG(!pixmap.isNull(), "No pixmap set"); | ||||||
| 
 | 
 | ||||||
|         QFile file{filename}; |         QFile file{filename}; | ||||||
|         if (!file.open(QIODevice::WriteOnly)) { |         if (!file.open(QIODevice::WriteOnly)) { | ||||||
|  | @ -685,7 +676,7 @@ void GraphicsSurfaceWidget::SaveSurface() { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (!pixmap->save(&file, "PNG")) { |         if (!pixmap.save(&file, "PNG")) { | ||||||
|             QMessageBox::warning(this, tr("Error"), |             QMessageBox::warning(this, tr("Error"), | ||||||
|                                  tr("Failed to save surface data to file '%1'").arg(filename)); |                                  tr("Failed to save surface data to file '%1'").arg(filename)); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -111,13 +111,13 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con | ||||||
|                 } |                 } | ||||||
|             }; |             }; | ||||||
| 
 | 
 | ||||||
|             const Instruction instr = par->info.code[index.row()]; |             const Instruction& instr = par->info.code[index.row()]; | ||||||
|             const OpCode opcode = instr.opcode; |             const OpCode opcode = instr.opcode; | ||||||
|             const OpCode::Info opcode_info = opcode.GetInfo(); |             const OpCode::Info opcode_info = opcode.GetInfo(); | ||||||
|             const u32 operand_desc_id = opcode_info.type == OpCode::Type::MultiplyAdd |             const u32 operand_desc_id = opcode_info.type == OpCode::Type::MultiplyAdd | ||||||
|                                             ? instr.mad.operand_desc_id.Value() |                                             ? instr.mad.operand_desc_id.Value() | ||||||
|                                             : instr.common.operand_desc_id.Value(); |                                             : instr.common.operand_desc_id.Value(); | ||||||
|             const SwizzlePattern swizzle = par->info.swizzle_info[operand_desc_id].pattern; |             const SwizzlePattern& swizzle = par->info.swizzle_info[operand_desc_id].pattern; | ||||||
| 
 | 
 | ||||||
|             // longest known instruction name: "setemit "
 |             // longest known instruction name: "setemit "
 | ||||||
|             int kOpcodeColumnWidth = 8; |             int kOpcodeColumnWidth = 8; | ||||||
|  | @ -407,8 +407,8 @@ GraphicsVertexShaderWidget::GraphicsVertexShaderWidget( | ||||||
|                 static_cast<void (QSignalMapper::*)()>(&QSignalMapper::map)); |                 static_cast<void (QSignalMapper::*)()>(&QSignalMapper::map)); | ||||||
|         input_data_mapper->setMapping(input_data[i], i); |         input_data_mapper->setMapping(input_data[i], i); | ||||||
|     } |     } | ||||||
|     connect(input_data_mapper, static_cast<void (QSignalMapper::*)(int)>(&QSignalMapper::mapped), |     connect(input_data_mapper, &QSignalMapper::mappedInt, this, | ||||||
|             this, &GraphicsVertexShaderWidget::OnInputAttributeChanged); |             &GraphicsVertexShaderWidget::OnInputAttributeChanged); | ||||||
| 
 | 
 | ||||||
|     auto main_widget = new QWidget; |     auto main_widget = new QWidget; | ||||||
|     auto main_layout = new QVBoxLayout; |     auto main_layout = new QVBoxLayout; | ||||||
|  | @ -514,8 +514,10 @@ void GraphicsVertexShaderWidget::Reload(bool replace_vertex_data, void* vertex_d | ||||||
|         info.code.push_back({instr}); |         info.code.push_back({instr}); | ||||||
|     int num_attributes = shader_config.max_input_attribute_index + 1; |     int num_attributes = shader_config.max_input_attribute_index + 1; | ||||||
| 
 | 
 | ||||||
|     for (auto pattern : shader_setup.swizzle_data) |     for (auto pattern : shader_setup.swizzle_data) { | ||||||
|         info.swizzle_info.push_back({pattern}); |         const nihstro::SwizzleInfo swizzle_info = {.pattern = nihstro::SwizzlePattern{pattern}}; | ||||||
|  |         info.swizzle_info.push_back(swizzle_info); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     u32 entry_point = Pica::g_state.regs.vs.main_offset; |     u32 entry_point = Pica::g_state.regs.vs.main_offset; | ||||||
|     info.labels.insert({entry_point, "main"}); |     info.labels.insert({entry_point, "main"}); | ||||||
|  |  | ||||||
|  | @ -57,6 +57,7 @@ QString IPCRecorderWidget::GetStatusStr(const IPCDebugger::RequestRecord& record | ||||||
|         return tr("HLE Unimplemented"); |         return tr("HLE Unimplemented"); | ||||||
|     default: |     default: | ||||||
|         UNREACHABLE(); |         UNREACHABLE(); | ||||||
|  |         return QLatin1String{}; | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -160,7 +160,8 @@ void MicroProfileWidget::mouseReleaseEvent(QMouseEvent* event) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void MicroProfileWidget::wheelEvent(QWheelEvent* event) { | void MicroProfileWidget::wheelEvent(QWheelEvent* event) { | ||||||
|     MicroProfileMousePosition(event->x() / x_scale, event->y() / y_scale, event->delta() / 120); |     MicroProfileMousePosition(event->position().x() / x_scale, event->position().y() / y_scale, | ||||||
|  |                               event->angleDelta().y() / 120); | ||||||
|     event->accept(); |     event->accept(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -114,7 +114,7 @@ void OptionSetDialog::InitializeUI(const std::string& initial_value) { | ||||||
|             ui->formatLabel->text().append(QStringLiteral("\n")); |             ui->formatLabel->text().append(QStringLiteral("\n")); | ||||||
|         } |         } | ||||||
|         ui->formatLabel->setText( |         ui->formatLabel->setText( | ||||||
|             ui->formatLabel->text().append(tr("Range: %1 - %2").arg(option.min).arg(option.max))); |             ui->formatLabel->text().append(tr("Range: %1 - %2").arg(option.min, option.max))); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Decide and initialize layout
 |     // Decide and initialize layout
 | ||||||
|  |  | ||||||
|  | @ -169,8 +169,7 @@ GameListSearchField::GameListSearchField(GameList* parent) : QWidget{parent} { | ||||||
|  * @return true if the haystack contains all words of userinput |  * @return true if the haystack contains all words of userinput | ||||||
|  */ |  */ | ||||||
| static bool ContainsAllWords(const QString& haystack, const QString& userinput) { | static bool ContainsAllWords(const QString& haystack, const QString& userinput) { | ||||||
|     const QStringList userinput_split = |     const QStringList userinput_split = userinput.split(QLatin1Char{' '}, Qt::SkipEmptyParts); | ||||||
|         userinput.split(QLatin1Char{' '}, QString::SplitBehavior::SkipEmptyParts); |  | ||||||
| 
 | 
 | ||||||
|     return std::all_of(userinput_split.begin(), userinput_split.end(), |     return std::all_of(userinput_split.begin(), userinput_split.end(), | ||||||
|                        [&haystack](const QString& s) { return haystack.contains(s); }); |                        [&haystack](const QString& s) { return haystack.contains(s); }); | ||||||
|  | @ -511,42 +510,42 @@ void GameList::AddGamePopup(QMenu& context_menu, const QString& path, u64 progra | ||||||
| 
 | 
 | ||||||
|     navigate_to_gamedb_entry->setVisible(it != compatibility_list.end()); |     navigate_to_gamedb_entry->setVisible(it != compatibility_list.end()); | ||||||
| 
 | 
 | ||||||
|     connect(open_save_location, &QAction::triggered, [this, program_id] { |     connect(open_save_location, &QAction::triggered, this, [this, program_id] { | ||||||
|         emit OpenFolderRequested(program_id, GameListOpenTarget::SAVE_DATA); |         emit OpenFolderRequested(program_id, GameListOpenTarget::SAVE_DATA); | ||||||
|     }); |     }); | ||||||
|     connect(open_extdata_location, &QAction::triggered, [this, extdata_id] { |     connect(open_extdata_location, &QAction::triggered, this, [this, extdata_id] { | ||||||
|         emit OpenFolderRequested(extdata_id, GameListOpenTarget::EXT_DATA); |         emit OpenFolderRequested(extdata_id, GameListOpenTarget::EXT_DATA); | ||||||
|     }); |     }); | ||||||
|     connect(open_application_location, &QAction::triggered, [this, program_id] { |     connect(open_application_location, &QAction::triggered, this, [this, program_id] { | ||||||
|         emit OpenFolderRequested(program_id, GameListOpenTarget::APPLICATION); |         emit OpenFolderRequested(program_id, GameListOpenTarget::APPLICATION); | ||||||
|     }); |     }); | ||||||
|     connect(open_update_location, &QAction::triggered, [this, program_id] { |     connect(open_update_location, &QAction::triggered, this, [this, program_id] { | ||||||
|         emit OpenFolderRequested(program_id, GameListOpenTarget::UPDATE_DATA); |         emit OpenFolderRequested(program_id, GameListOpenTarget::UPDATE_DATA); | ||||||
|     }); |     }); | ||||||
|     connect(open_texture_dump_location, &QAction::triggered, [this, program_id] { |     connect(open_texture_dump_location, &QAction::triggered, this, [this, program_id] { | ||||||
|         if (FileUtil::CreateFullPath(fmt::format("{}textures/{:016X}/", |         if (FileUtil::CreateFullPath(fmt::format("{}textures/{:016X}/", | ||||||
|                                                  FileUtil::GetUserPath(FileUtil::UserPath::DumpDir), |                                                  FileUtil::GetUserPath(FileUtil::UserPath::DumpDir), | ||||||
|                                                  program_id))) { |                                                  program_id))) { | ||||||
|             emit OpenFolderRequested(program_id, GameListOpenTarget::TEXTURE_DUMP); |             emit OpenFolderRequested(program_id, GameListOpenTarget::TEXTURE_DUMP); | ||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
|     connect(open_texture_load_location, &QAction::triggered, [this, program_id] { |     connect(open_texture_load_location, &QAction::triggered, this, [this, program_id] { | ||||||
|         if (FileUtil::CreateFullPath(fmt::format("{}textures/{:016X}/", |         if (FileUtil::CreateFullPath(fmt::format("{}textures/{:016X}/", | ||||||
|                                                  FileUtil::GetUserPath(FileUtil::UserPath::LoadDir), |                                                  FileUtil::GetUserPath(FileUtil::UserPath::LoadDir), | ||||||
|                                                  program_id))) { |                                                  program_id))) { | ||||||
|             emit OpenFolderRequested(program_id, GameListOpenTarget::TEXTURE_LOAD); |             emit OpenFolderRequested(program_id, GameListOpenTarget::TEXTURE_LOAD); | ||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
|     connect(open_mods_location, &QAction::triggered, [this, program_id] { |     connect(open_mods_location, &QAction::triggered, this, [this, program_id] { | ||||||
|         if (FileUtil::CreateFullPath(fmt::format("{}mods/{:016X}/", |         if (FileUtil::CreateFullPath(fmt::format("{}mods/{:016X}/", | ||||||
|                                                  FileUtil::GetUserPath(FileUtil::UserPath::LoadDir), |                                                  FileUtil::GetUserPath(FileUtil::UserPath::LoadDir), | ||||||
|                                                  program_id))) { |                                                  program_id))) { | ||||||
|             emit OpenFolderRequested(program_id, GameListOpenTarget::MODS); |             emit OpenFolderRequested(program_id, GameListOpenTarget::MODS); | ||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
|     connect(dump_romfs, &QAction::triggered, |     connect(dump_romfs, &QAction::triggered, this, | ||||||
|             [this, path, program_id] { emit DumpRomFSRequested(path, program_id); }); |             [this, path, program_id] { emit DumpRomFSRequested(path, program_id); }); | ||||||
|     connect(navigate_to_gamedb_entry, &QAction::triggered, [this, program_id]() { |     connect(navigate_to_gamedb_entry, &QAction::triggered, this, [this, program_id]() { | ||||||
|         emit NavigateToGamedbEntryRequested(program_id, compatibility_list); |         emit NavigateToGamedbEntryRequested(program_id, compatibility_list); | ||||||
|     }); |     }); | ||||||
| }; | }; | ||||||
|  | @ -561,11 +560,11 @@ void GameList::AddCustomDirPopup(QMenu& context_menu, QModelIndex selected) { | ||||||
|     deep_scan->setCheckable(true); |     deep_scan->setCheckable(true); | ||||||
|     deep_scan->setChecked(game_dir.deep_scan); |     deep_scan->setChecked(game_dir.deep_scan); | ||||||
| 
 | 
 | ||||||
|     connect(deep_scan, &QAction::triggered, [this, &game_dir] { |     connect(deep_scan, &QAction::triggered, this, [this, &game_dir] { | ||||||
|         game_dir.deep_scan = !game_dir.deep_scan; |         game_dir.deep_scan = !game_dir.deep_scan; | ||||||
|         PopulateAsync(UISettings::values.game_dirs); |         PopulateAsync(UISettings::values.game_dirs); | ||||||
|     }); |     }); | ||||||
|     connect(delete_dir, &QAction::triggered, [this, &game_dir, selected] { |     connect(delete_dir, &QAction::triggered, this, [this, &game_dir, selected] { | ||||||
|         UISettings::values.game_dirs.removeOne(game_dir); |         UISettings::values.game_dirs.removeOne(game_dir); | ||||||
|         item_model->invisibleRootItem()->removeRow(selected.row()); |         item_model->invisibleRootItem()->removeRow(selected.row()); | ||||||
|     }); |     }); | ||||||
|  | @ -583,7 +582,7 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) { | ||||||
|     move_up->setEnabled(row > 0); |     move_up->setEnabled(row > 0); | ||||||
|     move_down->setEnabled(row < item_model->rowCount() - 2); |     move_down->setEnabled(row < item_model->rowCount() - 2); | ||||||
| 
 | 
 | ||||||
|     connect(move_up, &QAction::triggered, [this, selected, row, game_dir_index] { |     connect(move_up, &QAction::triggered, this, [this, selected, row, game_dir_index] { | ||||||
|         const int other_index = selected.sibling(row - 1, 0).data(GameListDir::GameDirRole).toInt(); |         const int other_index = selected.sibling(row - 1, 0).data(GameListDir::GameDirRole).toInt(); | ||||||
|         // swap the items in the settings
 |         // swap the items in the settings
 | ||||||
|         std::swap(UISettings::values.game_dirs[game_dir_index], |         std::swap(UISettings::values.game_dirs[game_dir_index], | ||||||
|  | @ -598,7 +597,7 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) { | ||||||
|         tree_view->setExpanded(selected, UISettings::values.game_dirs[game_dir_index].expanded); |         tree_view->setExpanded(selected, UISettings::values.game_dirs[game_dir_index].expanded); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     connect(move_down, &QAction::triggered, [this, selected, row, game_dir_index] { |     connect(move_down, &QAction::triggered, this, [this, selected, row, game_dir_index] { | ||||||
|         const int other_index = selected.sibling(row + 1, 0).data(GameListDir::GameDirRole).toInt(); |         const int other_index = selected.sibling(row + 1, 0).data(GameListDir::GameDirRole).toInt(); | ||||||
|         // swap the items in the settings
 |         // swap the items in the settings
 | ||||||
|         std::swap(UISettings::values.game_dirs[game_dir_index], |         std::swap(UISettings::values.game_dirs[game_dir_index], | ||||||
|  | @ -613,7 +612,7 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) { | ||||||
|         tree_view->setExpanded(selected, UISettings::values.game_dirs[game_dir_index].expanded); |         tree_view->setExpanded(selected, UISettings::values.game_dirs[game_dir_index].expanded); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     connect(open_directory_location, &QAction::triggered, [this, game_dir_index] { |     connect(open_directory_location, &QAction::triggered, this, [this, game_dir_index] { | ||||||
|         emit OpenDirectory(UISettings::values.game_dirs[game_dir_index].path); |         emit OpenDirectory(UISettings::values.game_dirs[game_dir_index].path); | ||||||
|     }); |     }); | ||||||
| } | } | ||||||
|  | @ -640,7 +639,7 @@ void GameList::LoadCompatibilityList() { | ||||||
|     const QJsonDocument json = QJsonDocument::fromJson(content); |     const QJsonDocument json = QJsonDocument::fromJson(content); | ||||||
|     const QJsonArray arr = json.array(); |     const QJsonArray arr = json.array(); | ||||||
| 
 | 
 | ||||||
|     for (const QJsonValue value : arr) { |     for (const QJsonValue& value : arr) { | ||||||
|         const QJsonObject game = value.toObject(); |         const QJsonObject game = value.toObject(); | ||||||
|         const QString compatibility_key = QStringLiteral("compatibility"); |         const QString compatibility_key = QStringLiteral("compatibility"); | ||||||
| 
 | 
 | ||||||
|  | @ -652,7 +651,7 @@ void GameList::LoadCompatibilityList() { | ||||||
|         const QString directory = game[QStringLiteral("directory")].toString(); |         const QString directory = game[QStringLiteral("directory")].toString(); | ||||||
|         const QJsonArray ids = game[QStringLiteral("releases")].toArray(); |         const QJsonArray ids = game[QStringLiteral("releases")].toArray(); | ||||||
| 
 | 
 | ||||||
|         for (const QJsonValue id_ref : ids) { |         for (const QJsonValue& id_ref : ids) { | ||||||
|             const QJsonObject id_object = id_ref.toObject(); |             const QJsonObject id_object = id_ref.toObject(); | ||||||
|             const QString id = id_object[QStringLiteral("id")].toString(); |             const QString id = id_object[QStringLiteral("id")].toString(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -152,8 +152,8 @@ static void InitializeLogging() { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| GMainWindow::GMainWindow() | GMainWindow::GMainWindow() | ||||||
|     : config(std::make_unique<Config>()), emu_thread(nullptr), |     : ui{std::make_unique<Ui::MainWindow>()}, config{std::make_unique<Config>()}, emu_thread{ | ||||||
|       ui(std::make_unique<Ui::MainWindow>()) { |                                                                                       nullptr} { | ||||||
|     InitializeLogging(); |     InitializeLogging(); | ||||||
|     Debugger::ToggleConsole(); |     Debugger::ToggleConsole(); | ||||||
|     Settings::LogSettings(); |     Settings::LogSettings(); | ||||||
|  | @ -263,7 +263,7 @@ void GMainWindow::InitializeWidgets() { | ||||||
|     loading_screen = new LoadingScreen(this); |     loading_screen = new LoadingScreen(this); | ||||||
|     loading_screen->hide(); |     loading_screen->hide(); | ||||||
|     ui->horizontalLayout->addWidget(loading_screen); |     ui->horizontalLayout->addWidget(loading_screen); | ||||||
|     connect(loading_screen, &LoadingScreen::Hidden, [&] { |     connect(loading_screen, &LoadingScreen::Hidden, this, [&] { | ||||||
|         loading_screen->Clear(); |         loading_screen->Clear(); | ||||||
|         if (emulation_running) { |         if (emulation_running) { | ||||||
|             render_window->show(); |             render_window->show(); | ||||||
|  | @ -432,13 +432,13 @@ void GMainWindow::InitializeSaveStateMenuActions() { | ||||||
|         ui->menu_Save_State->addAction(actions_save_state[i]); |         ui->menu_Save_State->addAction(actions_save_state[i]); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     connect(ui->action_Load_from_Newest_Slot, &QAction::triggered, [this] { |     connect(ui->action_Load_from_Newest_Slot, &QAction::triggered, this, [this] { | ||||||
|         UpdateSaveStates(); |         UpdateSaveStates(); | ||||||
|         if (newest_slot != 0) { |         if (newest_slot != 0) { | ||||||
|             actions_load_state[newest_slot - 1]->trigger(); |             actions_load_state[newest_slot - 1]->trigger(); | ||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
|     connect(ui->action_Save_to_Oldest_Slot, &QAction::triggered, [this] { |     connect(ui->action_Save_to_Oldest_Slot, &QAction::triggered, this, [this] { | ||||||
|         UpdateSaveStates(); |         UpdateSaveStates(); | ||||||
|         actions_save_state[oldest_slot - 1]->trigger(); |         actions_save_state[oldest_slot - 1]->trigger(); | ||||||
|     }); |     }); | ||||||
|  | @ -677,7 +677,7 @@ void GMainWindow::ConnectWidgetEvents() { | ||||||
|     connect(game_list_placeholder, &GameListPlaceholder::AddDirectory, this, |     connect(game_list_placeholder, &GameListPlaceholder::AddDirectory, this, | ||||||
|             &GMainWindow::OnGameListAddDirectory); |             &GMainWindow::OnGameListAddDirectory); | ||||||
|     connect(game_list, &GameList::ShowList, this, &GMainWindow::OnGameListShowList); |     connect(game_list, &GameList::ShowList, this, &GMainWindow::OnGameListShowList); | ||||||
|     connect(game_list, &GameList::PopulatingCompleted, |     connect(game_list, &GameList::PopulatingCompleted, this, | ||||||
|             [this] { multiplayer_state->UpdateGameList(game_list->GetModel()); }); |             [this] { multiplayer_state->UpdateGameList(game_list->GetModel()); }); | ||||||
| 
 | 
 | ||||||
|     connect(this, &GMainWindow::EmulationStarting, render_window, |     connect(this, &GMainWindow::EmulationStarting, render_window, | ||||||
|  | @ -768,7 +768,7 @@ void GMainWindow::ConnectMenuEvents() { | ||||||
|     connect(ui->action_Close_Movie, &QAction::triggered, this, &GMainWindow::OnCloseMovie); |     connect(ui->action_Close_Movie, &QAction::triggered, this, &GMainWindow::OnCloseMovie); | ||||||
|     connect(ui->action_Save_Movie, &QAction::triggered, this, &GMainWindow::OnSaveMovie); |     connect(ui->action_Save_Movie, &QAction::triggered, this, &GMainWindow::OnSaveMovie); | ||||||
|     connect(ui->action_Movie_Read_Only_Mode, &QAction::toggled, this, |     connect(ui->action_Movie_Read_Only_Mode, &QAction::toggled, this, | ||||||
|             [this](bool checked) { Core::Movie::GetInstance().SetReadOnly(checked); }); |             [](bool checked) { Core::Movie::GetInstance().SetReadOnly(checked); }); | ||||||
|     connect(ui->action_Enable_Frame_Advancing, &QAction::triggered, this, [this] { |     connect(ui->action_Enable_Frame_Advancing, &QAction::triggered, this, [this] { | ||||||
|         if (emulation_running) { |         if (emulation_running) { | ||||||
|             Core::System::GetInstance().frame_limiter.SetFrameAdvancing( |             Core::System::GetInstance().frame_limiter.SetFrameAdvancing( | ||||||
|  | @ -1413,7 +1413,7 @@ void GMainWindow::OnGameListDumpRomFS(QString game_path, u64 program_id) { | ||||||
|                     program_id | 0x0004000e00000000); |                     program_id | 0x0004000e00000000); | ||||||
|     using FutureWatcher = QFutureWatcher<std::pair<Loader::ResultStatus, Loader::ResultStatus>>; |     using FutureWatcher = QFutureWatcher<std::pair<Loader::ResultStatus, Loader::ResultStatus>>; | ||||||
|     auto* future_watcher = new FutureWatcher(this); |     auto* future_watcher = new FutureWatcher(this); | ||||||
|     connect(future_watcher, &FutureWatcher::finished, |     connect(future_watcher, &FutureWatcher::finished, this, | ||||||
|             [this, dialog, base_path, update_path, future_watcher] { |             [this, dialog, base_path, update_path, future_watcher] { | ||||||
|                 dialog->hide(); |                 dialog->hide(); | ||||||
|                 const auto& [base, update] = future_watcher->result(); |                 const auto& [base, update] = future_watcher->result(); | ||||||
|  | @ -1515,7 +1515,7 @@ void GMainWindow::InstallCIA(QStringList filepaths) { | ||||||
|         const auto cia_progress = [&](std::size_t written, std::size_t total) { |         const auto cia_progress = [&](std::size_t written, std::size_t total) { | ||||||
|             emit UpdateProgress(written, total); |             emit UpdateProgress(written, total); | ||||||
|         }; |         }; | ||||||
|         for (const auto current_path : filepaths) { |         for (const auto& current_path : filepaths) { | ||||||
|             status = Service::AM::InstallCIA(current_path.toStdString(), cia_progress); |             status = Service::AM::InstallCIA(current_path.toStdString(), cia_progress); | ||||||
|             emit CIAInstallReport(status, current_path); |             emit CIAInstallReport(status, current_path); | ||||||
|         } |         } | ||||||
|  | @ -1553,6 +1553,10 @@ void GMainWindow::OnCIAInstallReport(Service::AM::InstallStatus status, QString | ||||||
|                                  "before being used with Citra. A real 3DS is required.") |                                  "before being used with Citra. A real 3DS is required.") | ||||||
|                                   .arg(filename)); |                                   .arg(filename)); | ||||||
|         break; |         break; | ||||||
|  |     case Service::AM::InstallStatus::ErrorFileNotFound: | ||||||
|  |         QMessageBox::critical(this, tr("Unable to find File"), | ||||||
|  |                               tr("Could not find %1").arg(filename)); | ||||||
|  |         break; | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1730,6 +1734,8 @@ void GMainWindow::ToggleScreenLayout() { | ||||||
|     case Settings::LayoutOption::SideScreen: |     case Settings::LayoutOption::SideScreen: | ||||||
|         new_layout = Settings::LayoutOption::Default; |         new_layout = Settings::LayoutOption::Default; | ||||||
|         break; |         break; | ||||||
|  |     default: | ||||||
|  |         LOG_ERROR(Frontend, "Unknown layout option {}", Settings::values.layout_option); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     Settings::values.layout_option = new_layout; |     Settings::values.layout_option = new_layout; | ||||||
|  | @ -1976,7 +1982,7 @@ void GMainWindow::OnCaptureScreenshot() { | ||||||
|     const QString filename = game_title.remove(QRegularExpression(QStringLiteral("[\\/:?\"<>|]"))); |     const QString filename = game_title.remove(QRegularExpression(QStringLiteral("[\\/:?\"<>|]"))); | ||||||
|     const QString timestamp = |     const QString timestamp = | ||||||
|         QDateTime::currentDateTime().toString(QStringLiteral("dd.MM.yy_hh.mm.ss.z")); |         QDateTime::currentDateTime().toString(QStringLiteral("dd.MM.yy_hh.mm.ss.z")); | ||||||
|     path.append(QStringLiteral("/%1_%2.png").arg(filename).arg(timestamp)); |     path.append(QStringLiteral("/%1_%2.png").arg(filename, timestamp)); | ||||||
|     render_window->CaptureScreenshot(UISettings::values.screenshot_resolution_factor, path); |     render_window->CaptureScreenshot(UISettings::values.screenshot_resolution_factor, path); | ||||||
|     OnStartGame(); |     OnStartGame(); | ||||||
| } | } | ||||||
|  | @ -2051,7 +2057,7 @@ void GMainWindow::UpdateStatusBar() { | ||||||
|         message_label_used_for_movie = true; |         message_label_used_for_movie = true; | ||||||
|         ui->action_Save_Movie->setEnabled(true); |         ui->action_Save_Movie->setEnabled(true); | ||||||
|     } else if (play_mode == Core::Movie::PlayMode::Playing) { |     } else if (play_mode == Core::Movie::PlayMode::Playing) { | ||||||
|         message_label->setText(tr("Playing %1 / %2").arg(current).arg(total)); |         message_label->setText(tr("Playing %1 / %2").arg(current, total)); | ||||||
|         message_label->setVisible(true); |         message_label->setVisible(true); | ||||||
|         message_label_used_for_movie = true; |         message_label_used_for_movie = true; | ||||||
|         ui->action_Save_Movie->setEnabled(false); |         ui->action_Save_Movie->setEnabled(false); | ||||||
|  |  | ||||||
|  | @ -5,6 +5,7 @@ | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include <memory> | #include <memory> | ||||||
|  | #include <unordered_map> | ||||||
| #include <unordered_set> | #include <unordered_set> | ||||||
| #include <QDialog> | #include <QDialog> | ||||||
| #include <QSortFilterProxyModel> | #include <QSortFilterProxyModel> | ||||||
|  |  | ||||||
|  | @ -7,7 +7,6 @@ | ||||||
| #include <QIcon> | #include <QIcon> | ||||||
| #include <QMessageBox> | #include <QMessageBox> | ||||||
| #include <QStandardItemModel> | #include <QStandardItemModel> | ||||||
| #include "citra_qt/game_list.h" |  | ||||||
| #include "citra_qt/multiplayer/client_room.h" | #include "citra_qt/multiplayer/client_room.h" | ||||||
| #include "citra_qt/multiplayer/direct_connect.h" | #include "citra_qt/multiplayer/direct_connect.h" | ||||||
| #include "citra_qt/multiplayer/host_room.h" | #include "citra_qt/multiplayer/host_room.h" | ||||||
|  | @ -16,7 +15,6 @@ | ||||||
| #include "citra_qt/multiplayer/state.h" | #include "citra_qt/multiplayer/state.h" | ||||||
| #include "citra_qt/uisettings.h" | #include "citra_qt/uisettings.h" | ||||||
| #include "citra_qt/util/clickable_label.h" | #include "citra_qt/util/clickable_label.h" | ||||||
| #include "common/announce_multiplayer_room.h" |  | ||||||
| #include "common/logging/log.h" | #include "common/logging/log.h" | ||||||
| 
 | 
 | ||||||
| MultiplayerState::MultiplayerState(QWidget* parent, QStandardItemModel* game_list_model, | MultiplayerState::MultiplayerState(QWidget* parent, QStandardItemModel* game_list_model, | ||||||
|  | @ -231,8 +229,9 @@ bool MultiplayerState::OnCloseRoom() { | ||||||
|         if (room->GetState() != Network::Room::State::Open) { |         if (room->GetState() != Network::Room::State::Open) { | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         // Save ban list
 |         // Save ban list
 | ||||||
|         UISettings::values.ban_list = std::move(room->GetBanList()); |         UISettings::values.ban_list = room->GetBanList(); | ||||||
| 
 | 
 | ||||||
|         room->Destroy(); |         room->Destroy(); | ||||||
|         announce_multiplayer_session->Stop(); |         announce_multiplayer_session->Stop(); | ||||||
|  |  | ||||||
|  | @ -78,6 +78,7 @@ add_library(common STATIC | ||||||
|     logging/backend.h |     logging/backend.h | ||||||
|     logging/filter.cpp |     logging/filter.cpp | ||||||
|     logging/filter.h |     logging/filter.h | ||||||
|  |     logging/formatter.h | ||||||
|     logging/log.h |     logging/log.h | ||||||
|     logging/text_formatter.cpp |     logging/text_formatter.cpp | ||||||
|     logging/text_formatter.h |     logging/text_formatter.h | ||||||
|  |  | ||||||
|  | @ -31,8 +31,10 @@ | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| // 64 bit offsets for MSVC and MinGW. MinGW also needs this for using _wstat64
 | // 64 bit offsets for MSVC and MinGW. MinGW also needs this for using _wstat64
 | ||||||
|  | #ifndef __MINGW64__ | ||||||
| #define stat _stat64 | #define stat _stat64 | ||||||
| #define fstat _fstat64 | #define fstat _fstat64 | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| #else | #else | ||||||
| #ifdef __APPLE__ | #ifdef __APPLE__ | ||||||
|  |  | ||||||
|  | @ -65,12 +65,16 @@ private: | ||||||
| 
 | 
 | ||||||
| BOOST_CLASS_EXPORT_KEY(BufferMem); | BOOST_CLASS_EXPORT_KEY(BufferMem); | ||||||
| 
 | 
 | ||||||
| /// A managed reference to host-side memory. Fast enough to be used everywhere instead of u8*
 | /**
 | ||||||
| /// Supports serialization.
 |  * A managed reference to host-side memory. | ||||||
|  |  * Fast enough to be used everywhere instead of u8* | ||||||
|  |  * Supports serialization. | ||||||
|  |  */ | ||||||
| class MemoryRef { | class MemoryRef { | ||||||
| public: | public: | ||||||
|     MemoryRef() = default; |     MemoryRef() = default; | ||||||
|     MemoryRef(std::nullptr_t) {} |     MemoryRef(std::nullptr_t) {} | ||||||
|  | 
 | ||||||
|     MemoryRef(std::shared_ptr<BackingMem> backing_mem_) |     MemoryRef(std::shared_ptr<BackingMem> backing_mem_) | ||||||
|         : backing_mem(std::move(backing_mem_)), offset(0) { |         : backing_mem(std::move(backing_mem_)), offset(0) { | ||||||
|         Init(); |         Init(); | ||||||
|  | @ -80,30 +84,38 @@ public: | ||||||
|         ASSERT(offset <= backing_mem->GetSize()); |         ASSERT(offset <= backing_mem->GetSize()); | ||||||
|         Init(); |         Init(); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     explicit operator bool() const { |     explicit operator bool() const { | ||||||
|         return cptr != nullptr; |         return cptr != nullptr; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     operator u8*() { |     operator u8*() { | ||||||
|         return cptr; |         return cptr; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     u8* GetPtr() { |     u8* GetPtr() { | ||||||
|         return cptr; |         return cptr; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     operator const u8*() const { |     operator const u8*() const { | ||||||
|         return cptr; |         return cptr; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     const u8* GetPtr() const { |     const u8* GetPtr() const { | ||||||
|         return cptr; |         return cptr; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     std::size_t GetSize() const { |     std::size_t GetSize() const { | ||||||
|         return csize; |         return csize; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     MemoryRef& operator+=(u32 offset_by) { |     MemoryRef& operator+=(u32 offset_by) { | ||||||
|         ASSERT(offset_by < csize); |         ASSERT(offset_by < csize); | ||||||
|         offset += offset_by; |         offset += offset_by; | ||||||
|         Init(); |         Init(); | ||||||
|         return *this; |         return *this; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     MemoryRef operator+(u32 offset_by) const { |     MemoryRef operator+(u32 offset_by) const { | ||||||
|         ASSERT(offset_by < csize); |         ASSERT(offset_by < csize); | ||||||
|         return MemoryRef(backing_mem, offset + offset_by); |         return MemoryRef(backing_mem, offset + offset_by); | ||||||
|  |  | ||||||
|  | @ -23,12 +23,3 @@ typedef void* HANDLE; | ||||||
| #include <microprofile.h> | #include <microprofile.h> | ||||||
| 
 | 
 | ||||||
| #define MP_RGB(r, g, b) ((r) << 16 | (g) << 8 | (b) << 0) | #define MP_RGB(r, g, b) ((r) << 16 | (g) << 8 | (b) << 0) | ||||||
| 
 |  | ||||||
| // On OS X, some Mach header included by MicroProfile defines these as macros, conflicting with
 |  | ||||||
| // identifiers we use.
 |  | ||||||
| #ifdef PAGE_SIZE |  | ||||||
| #undef PAGE_SIZE |  | ||||||
| #endif |  | ||||||
| #ifdef PAGE_MASK |  | ||||||
| #undef PAGE_MASK |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  | @ -228,6 +228,7 @@ u32 ARM_Dynarmic::GetVFPSystemReg(VFPSystemRegister reg) const { | ||||||
|     default: |     default: | ||||||
|         UNREACHABLE_MSG("Unknown VFP system register: {}", reg); |         UNREACHABLE_MSG("Unknown VFP system register: {}", reg); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     return UINT_MAX; |     return UINT_MAX; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -261,6 +262,8 @@ u32 ARM_Dynarmic::GetCP15Register(CP15Register reg) const { | ||||||
|     default: |     default: | ||||||
|         UNREACHABLE_MSG("Unknown CP15 register: {}", reg); |         UNREACHABLE_MSG("Unknown CP15 register: {}", reg); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ARM_Dynarmic::SetCP15Register(CP15Register reg, u32 value) { | void ARM_Dynarmic::SetCP15Register(CP15Register reg, u32 value) { | ||||||
|  |  | ||||||
|  | @ -849,17 +849,13 @@ static int InterpreterTranslateBlock(ARMul_State* cpu, std::size_t& bb_start, u3 | ||||||
|     // Save start addr of basicblock in CreamCache
 |     // Save start addr of basicblock in CreamCache
 | ||||||
|     ARM_INST_PTR inst_base = nullptr; |     ARM_INST_PTR inst_base = nullptr; | ||||||
|     TransExtData ret = TransExtData::NON_BRANCH; |     TransExtData ret = TransExtData::NON_BRANCH; | ||||||
|     int size = 0; // instruction size of basic block
 |  | ||||||
|     bb_start = trans_cache_buf_top; |     bb_start = trans_cache_buf_top; | ||||||
| 
 | 
 | ||||||
|     u32 phys_addr = addr; |     u32 phys_addr = addr; | ||||||
|     u32 pc_start = cpu->Reg[15]; |     u32 pc_start = cpu->Reg[15]; | ||||||
| 
 | 
 | ||||||
|     while (ret == TransExtData::NON_BRANCH) { |     while (ret == TransExtData::NON_BRANCH) { | ||||||
|         unsigned int inst_size = InterpreterTranslateInstruction(cpu, phys_addr, inst_base); |         u32 inst_size = InterpreterTranslateInstruction(cpu, phys_addr, inst_base); | ||||||
| 
 |  | ||||||
|         size++; |  | ||||||
| 
 |  | ||||||
|         phys_addr += inst_size; |         phys_addr += inst_size; | ||||||
| 
 | 
 | ||||||
|         if ((phys_addr & 0xfff) == 0) { |         if ((phys_addr & 0xfff) == 0) { | ||||||
|  | @ -972,7 +968,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | ||||||
| 
 | 
 | ||||||
| // GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback to a
 | // GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback to a
 | ||||||
| // clunky switch statement.
 | // clunky switch statement.
 | ||||||
| #if defined __GNUC__ || defined __clang__ | #if defined __GNUC__ || (defined __clang__ && !defined _MSC_VER) | ||||||
| #define GOTO_NEXT_INST                                                                             \ | #define GOTO_NEXT_INST                                                                             \ | ||||||
|     GDB_BP_CHECK;                                                                                  \ |     GDB_BP_CHECK;                                                                                  \ | ||||||
|     if (num_instrs >= cpu->NumInstrsToExecute)                                                     \ |     if (num_instrs >= cpu->NumInstrsToExecute)                                                     \ | ||||||
|  |  | ||||||
|  | @ -1218,7 +1218,7 @@ u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr) { | ||||||
| 
 | 
 | ||||||
|     for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) { |     for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) { | ||||||
|         u32 except; |         u32 except; | ||||||
|         char type; |         [[maybe_unused]] char type; | ||||||
| 
 | 
 | ||||||
|         type = (fop->flags & OP_SD) ? 's' : 'd'; |         type = (fop->flags & OP_SD) ? 's' : 'd'; | ||||||
|         if (op == FOP_EXT) |         if (op == FOP_EXT) | ||||||
|  |  | ||||||
|  | @ -1242,7 +1242,7 @@ u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr) { | ||||||
|     for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) { |     for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) { | ||||||
|         s32 m = vfp_get_float(state, sm); |         s32 m = vfp_get_float(state, sm); | ||||||
|         u32 except; |         u32 except; | ||||||
|         char type; |         [[maybe_unused]] char type; | ||||||
| 
 | 
 | ||||||
|         type = (fop->flags & OP_DD) ? 'd' : 's'; |         type = (fop->flags & OP_DD) ? 'd' : 's'; | ||||||
|         if (op == FOP_EXT) |         if (op == FOP_EXT) | ||||||
|  |  | ||||||
|  | @ -47,7 +47,7 @@ void CheatEngine::AddCheat(const std::shared_ptr<CheatBase>& cheat) { | ||||||
| 
 | 
 | ||||||
| void CheatEngine::RemoveCheat(int index) { | void CheatEngine::RemoveCheat(int index) { | ||||||
|     std::unique_lock<std::shared_mutex> lock(cheats_list_mutex); |     std::unique_lock<std::shared_mutex> lock(cheats_list_mutex); | ||||||
|     if (index < 0 || index >= cheats_list.size()) { |     if (index < 0 || index >= static_cast<int>(cheats_list.size())) { | ||||||
|         LOG_ERROR(Core_Cheats, "Invalid index {}", index); |         LOG_ERROR(Core_Cheats, "Invalid index {}", index); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  | @ -56,7 +56,7 @@ void CheatEngine::RemoveCheat(int index) { | ||||||
| 
 | 
 | ||||||
| void CheatEngine::UpdateCheat(int index, const std::shared_ptr<CheatBase>& new_cheat) { | void CheatEngine::UpdateCheat(int index, const std::shared_ptr<CheatBase>& new_cheat) { | ||||||
|     std::unique_lock<std::shared_mutex> lock(cheats_list_mutex); |     std::unique_lock<std::shared_mutex> lock(cheats_list_mutex); | ||||||
|     if (index < 0 || index >= cheats_list.size()) { |     if (index < 0 || index >= static_cast<int>(cheats_list.size())) { | ||||||
|         LOG_ERROR(Core_Cheats, "Invalid index {}", index); |         LOG_ERROR(Core_Cheats, "Invalid index {}", index); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -301,10 +301,6 @@ private: | ||||||
|     std::vector<std::shared_ptr<Timer>> timers; |     std::vector<std::shared_ptr<Timer>> timers; | ||||||
|     Timer* current_timer = nullptr; |     Timer* current_timer = nullptr; | ||||||
| 
 | 
 | ||||||
|     // Stores a scaling for the internal clockspeed. Changing this number results in
 |  | ||||||
|     // under/overclocking the guest cpu
 |  | ||||||
|     double cpu_clock_scale = 1.0; |  | ||||||
| 
 |  | ||||||
|     // When true, the event queue can't be modified. Used while deserializing to workaround
 |     // When true, the event queue can't be modified. Used while deserializing to workaround
 | ||||||
|     // destructor side effects.
 |     // destructor side effects.
 | ||||||
|     bool event_queue_locked = false; |     bool event_queue_locked = false; | ||||||
|  |  | ||||||
|  | @ -849,14 +849,14 @@ static void ReadMemory() { | ||||||
|         SendReply("E01"); |         SendReply("E01"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (!Memory::IsValidVirtualAddress(*Core::System::GetInstance().Kernel().GetCurrentProcess(), |     auto& memory = Core::System::GetInstance().Memory(); | ||||||
|  |     if (!memory.IsValidVirtualAddress(*Core::System::GetInstance().Kernel().GetCurrentProcess(), | ||||||
|                                       addr)) { |                                       addr)) { | ||||||
|         return SendReply("E00"); |         return SendReply("E00"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     std::vector<u8> data(len); |     std::vector<u8> data(len); | ||||||
|     Core::System::GetInstance().Memory().ReadBlock( |     memory.ReadBlock(addr, data.data(), len); | ||||||
|         *Core::System::GetInstance().Kernel().GetCurrentProcess(), addr, data.data(), len); |  | ||||||
| 
 | 
 | ||||||
|     MemToGdbHex(reply, data.data(), len); |     MemToGdbHex(reply, data.data(), len); | ||||||
|     reply[len * 2] = '\0'; |     reply[len * 2] = '\0'; | ||||||
|  | @ -873,7 +873,8 @@ static void WriteMemory() { | ||||||
|     auto len_pos = std::find(start_offset, command_buffer + command_length, ':'); |     auto len_pos = std::find(start_offset, command_buffer + command_length, ':'); | ||||||
|     u32 len = HexToInt(start_offset, static_cast<u32>(len_pos - start_offset)); |     u32 len = HexToInt(start_offset, static_cast<u32>(len_pos - start_offset)); | ||||||
| 
 | 
 | ||||||
|     if (!Memory::IsValidVirtualAddress(*Core::System::GetInstance().Kernel().GetCurrentProcess(), |     auto& memory = Core::System::GetInstance().Memory(); | ||||||
|  |     if (!memory.IsValidVirtualAddress(*Core::System::GetInstance().Kernel().GetCurrentProcess(), | ||||||
|                                       addr)) { |                                       addr)) { | ||||||
|         return SendReply("E00"); |         return SendReply("E00"); | ||||||
|     } |     } | ||||||
|  | @ -881,8 +882,7 @@ static void WriteMemory() { | ||||||
|     std::vector<u8> data(len); |     std::vector<u8> data(len); | ||||||
| 
 | 
 | ||||||
|     GdbHexToMem(data.data(), len_pos + 1, len); |     GdbHexToMem(data.data(), len_pos + 1, len); | ||||||
|     Core::System::GetInstance().Memory().WriteBlock( |     memory.WriteBlock(addr, data.data(), len); | ||||||
|         *Core::System::GetInstance().Kernel().GetCurrentProcess(), addr, data.data(), len); |  | ||||||
|     Core::GetRunningCore().ClearInstructionCache(); |     Core::GetRunningCore().ClearInstructionCache(); | ||||||
|     SendReply("OK"); |     SendReply("OK"); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -80,7 +80,7 @@ private: | ||||||
|     std::shared_ptr<Callback> timeout_callback; |     std::shared_ptr<Callback> timeout_callback; | ||||||
| 
 | 
 | ||||||
|     void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread, |     void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread, | ||||||
|                 std::shared_ptr<WaitObject> object); |                 std::shared_ptr<WaitObject> object) override; | ||||||
| 
 | 
 | ||||||
|     class DummyCallback : public WakeupCallback { |     class DummyCallback : public WakeupCallback { | ||||||
|     public: |     public: | ||||||
|  |  | ||||||
|  | @ -138,10 +138,10 @@ ResultCode TranslateCommandBuffer(Kernel::KernelSystem& kernel, Memory::MemorySy | ||||||
|             u32 size = static_cast<u32>(descInfo.size); |             u32 size = static_cast<u32>(descInfo.size); | ||||||
|             IPC::MappedBufferPermissions permissions = descInfo.perms; |             IPC::MappedBufferPermissions permissions = descInfo.perms; | ||||||
| 
 | 
 | ||||||
|             VAddr page_start = Common::AlignDown(source_address, Memory::PAGE_SIZE); |             VAddr page_start = Common::AlignDown(source_address, Memory::CITRA_PAGE_SIZE); | ||||||
|             u32 page_offset = source_address - page_start; |             u32 page_offset = source_address - page_start; | ||||||
|             u32 num_pages = |             u32 num_pages = Common::AlignUp(page_offset + size, Memory::CITRA_PAGE_SIZE) >> | ||||||
|                 Common::AlignUp(page_offset + size, Memory::PAGE_SIZE) >> Memory::PAGE_BITS; |                             Memory::CITRA_PAGE_BITS; | ||||||
| 
 | 
 | ||||||
|             // Skip when the size is zero and num_pages == 0
 |             // Skip when the size is zero and num_pages == 0
 | ||||||
|             if (size == 0) { |             if (size == 0) { | ||||||
|  | @ -171,8 +171,8 @@ ResultCode TranslateCommandBuffer(Kernel::KernelSystem& kernel, Memory::MemorySy | ||||||
|                                      found->target_address, size); |                                      found->target_address, size); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 VAddr prev_reserve = page_start - Memory::PAGE_SIZE; |                 VAddr prev_reserve = page_start - Memory::CITRA_PAGE_SIZE; | ||||||
|                 VAddr next_reserve = page_start + num_pages * Memory::PAGE_SIZE; |                 VAddr next_reserve = page_start + num_pages * Memory::CITRA_PAGE_SIZE; | ||||||
| 
 | 
 | ||||||
|                 auto& prev_vma = src_process->vm_manager.FindVMA(prev_reserve)->second; |                 auto& prev_vma = src_process->vm_manager.FindVMA(prev_reserve)->second; | ||||||
|                 auto& next_vma = src_process->vm_manager.FindVMA(next_reserve)->second; |                 auto& next_vma = src_process->vm_manager.FindVMA(next_reserve)->second; | ||||||
|  | @ -180,8 +180,9 @@ ResultCode TranslateCommandBuffer(Kernel::KernelSystem& kernel, Memory::MemorySy | ||||||
|                        next_vma.meminfo_state == MemoryState::Reserved); |                        next_vma.meminfo_state == MemoryState::Reserved); | ||||||
| 
 | 
 | ||||||
|                 // Unmap the buffer and guard pages from the source process
 |                 // Unmap the buffer and guard pages from the source process
 | ||||||
|                 ResultCode result = src_process->vm_manager.UnmapRange( |                 ResultCode result = | ||||||
|                     page_start - Memory::PAGE_SIZE, (num_pages + 2) * Memory::PAGE_SIZE); |                     src_process->vm_manager.UnmapRange(page_start - Memory::CITRA_PAGE_SIZE, | ||||||
|  |                                                        (num_pages + 2) * Memory::CITRA_PAGE_SIZE); | ||||||
|                 ASSERT(result == RESULT_SUCCESS); |                 ASSERT(result == RESULT_SUCCESS); | ||||||
| 
 | 
 | ||||||
|                 mapped_buffer_context.erase(found); |                 mapped_buffer_context.erase(found); | ||||||
|  | @ -196,13 +197,13 @@ ResultCode TranslateCommandBuffer(Kernel::KernelSystem& kernel, Memory::MemorySy | ||||||
| 
 | 
 | ||||||
|             // Reserve a page of memory before the mapped buffer
 |             // Reserve a page of memory before the mapped buffer
 | ||||||
|             std::shared_ptr<BackingMem> reserve_buffer = |             std::shared_ptr<BackingMem> reserve_buffer = | ||||||
|                 std::make_shared<BufferMem>(Memory::PAGE_SIZE); |                 std::make_shared<BufferMem>(Memory::CITRA_PAGE_SIZE); | ||||||
|             dst_process->vm_manager.MapBackingMemoryToBase( |             dst_process->vm_manager.MapBackingMemoryToBase( | ||||||
|                 Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE, reserve_buffer, |                 Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE, reserve_buffer, | ||||||
|                 Memory::PAGE_SIZE, Kernel::MemoryState::Reserved); |                 Memory::CITRA_PAGE_SIZE, Kernel::MemoryState::Reserved); | ||||||
| 
 | 
 | ||||||
|             std::shared_ptr<BackingMem> buffer = |             std::shared_ptr<BackingMem> buffer = | ||||||
|                 std::make_shared<BufferMem>(num_pages * Memory::PAGE_SIZE); |                 std::make_shared<BufferMem>(num_pages * Memory::CITRA_PAGE_SIZE); | ||||||
|             memory.ReadBlock(*src_process, source_address, buffer->GetPtr() + page_offset, size); |             memory.ReadBlock(*src_process, source_address, buffer->GetPtr() + page_offset, size); | ||||||
| 
 | 
 | ||||||
|             // Map the page(s) into the target process' address space.
 |             // Map the page(s) into the target process' address space.
 | ||||||
|  |  | ||||||
|  | @ -127,7 +127,7 @@ void Process::ParseKernelCaps(const u32* kernel_caps, std::size_t len) { | ||||||
|             // Mapped memory page
 |             // Mapped memory page
 | ||||||
|             AddressMapping mapping; |             AddressMapping mapping; | ||||||
|             mapping.address = descriptor << 12; |             mapping.address = descriptor << 12; | ||||||
|             mapping.size = Memory::PAGE_SIZE; |             mapping.size = Memory::CITRA_PAGE_SIZE; | ||||||
|             mapping.read_only = false; |             mapping.read_only = false; | ||||||
|             mapping.unk_flag = false; |             mapping.unk_flag = false; | ||||||
| 
 | 
 | ||||||
|  | @ -265,7 +265,7 @@ ResultCode Process::HeapFree(VAddr target, u32 size) { | ||||||
| 
 | 
 | ||||||
|     // Free heaps block by block
 |     // Free heaps block by block
 | ||||||
|     CASCADE_RESULT(auto backing_blocks, vm_manager.GetBackingBlocksForRange(target, size)); |     CASCADE_RESULT(auto backing_blocks, vm_manager.GetBackingBlocksForRange(target, size)); | ||||||
|     for (const auto [backing_memory, block_size] : backing_blocks) { |     for (const auto& [backing_memory, block_size] : backing_blocks) { | ||||||
|         memory_region->Free(kernel.memory.GetFCRAMOffset(backing_memory.GetPtr()), block_size); |         memory_region->Free(kernel.memory.GetFCRAMOffset(backing_memory.GetPtr()), block_size); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -396,7 +396,7 @@ ResultCode Process::Map(VAddr target, VAddr source, u32 size, VMAPermission perm | ||||||
| 
 | 
 | ||||||
|     CASCADE_RESULT(auto backing_blocks, vm_manager.GetBackingBlocksForRange(source, size)); |     CASCADE_RESULT(auto backing_blocks, vm_manager.GetBackingBlocksForRange(source, size)); | ||||||
|     VAddr interval_target = target; |     VAddr interval_target = target; | ||||||
|     for (const auto [backing_memory, block_size] : backing_blocks) { |     for (const auto& [backing_memory, block_size] : backing_blocks) { | ||||||
|         auto target_vma = |         auto target_vma = | ||||||
|             vm_manager.MapBackingMemory(interval_target, backing_memory, block_size, target_state); |             vm_manager.MapBackingMemory(interval_target, backing_memory, block_size, target_state); | ||||||
|         ASSERT(target_vma.Succeeded()); |         ASSERT(target_vma.Succeeded()); | ||||||
|  |  | ||||||
|  | @ -10,7 +10,6 @@ | ||||||
| #include "common/logging/log.h" | #include "common/logging/log.h" | ||||||
| #include "common/microprofile.h" | #include "common/microprofile.h" | ||||||
| #include "common/scm_rev.h" | #include "common/scm_rev.h" | ||||||
| #include "common/scope_exit.h" |  | ||||||
| #include "core/arm/arm_interface.h" | #include "core/arm/arm_interface.h" | ||||||
| #include "core/core.h" | #include "core/core.h" | ||||||
| #include "core/core_timing.h" | #include "core/core_timing.h" | ||||||
|  | @ -39,7 +38,6 @@ | ||||||
| #include "core/hle/kernel/wait_object.h" | #include "core/hle/kernel/wait_object.h" | ||||||
| #include "core/hle/lock.h" | #include "core/hle/lock.h" | ||||||
| #include "core/hle/result.h" | #include "core/hle/result.h" | ||||||
| #include "core/hle/service/service.h" |  | ||||||
| 
 | 
 | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
| 
 | 
 | ||||||
|  | @ -219,10 +217,10 @@ ResultCode SVC::ControlMemory(u32* out_addr, u32 addr0, u32 addr1, u32 size, u32 | ||||||
|               "size=0x{:X}, permissions=0x{:08X}", |               "size=0x{:X}, permissions=0x{:08X}", | ||||||
|               operation, addr0, addr1, size, permissions); |               operation, addr0, addr1, size, permissions); | ||||||
| 
 | 
 | ||||||
|     if ((addr0 & Memory::PAGE_MASK) != 0 || (addr1 & Memory::PAGE_MASK) != 0) { |     if ((addr0 & Memory::CITRA_PAGE_MASK) != 0 || (addr1 & Memory::CITRA_PAGE_MASK) != 0) { | ||||||
|         return ERR_MISALIGNED_ADDRESS; |         return ERR_MISALIGNED_ADDRESS; | ||||||
|     } |     } | ||||||
|     if ((size & Memory::PAGE_MASK) != 0) { |     if ((size & Memory::CITRA_PAGE_MASK) != 0) { | ||||||
|         return ERR_MISALIGNED_SIZE; |         return ERR_MISALIGNED_SIZE; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -374,7 +372,7 @@ ResultCode SVC::UnmapMemoryBlock(Handle handle, u32 addr) { | ||||||
| 
 | 
 | ||||||
| /// Connect to an OS service given the port name, returns the handle to the port to out
 | /// Connect to an OS service given the port name, returns the handle to the port to out
 | ||||||
| ResultCode SVC::ConnectToPort(Handle* out_handle, VAddr port_name_address) { | ResultCode SVC::ConnectToPort(Handle* out_handle, VAddr port_name_address) { | ||||||
|     if (!Memory::IsValidVirtualAddress(*kernel.GetCurrentProcess(), port_name_address)) |     if (!memory.IsValidVirtualAddress(*kernel.GetCurrentProcess(), port_name_address)) | ||||||
|         return ERR_NOT_FOUND; |         return ERR_NOT_FOUND; | ||||||
| 
 | 
 | ||||||
|     static constexpr std::size_t PortNameMaxLength = 11; |     static constexpr std::size_t PortNameMaxLength = 11; | ||||||
|  | @ -541,7 +539,7 @@ ResultCode SVC::WaitSynchronizationN(s32* out, VAddr handles_address, s32 handle | ||||||
|                                      bool wait_all, s64 nano_seconds) { |                                      bool wait_all, s64 nano_seconds) { | ||||||
|     Thread* thread = kernel.GetCurrentThreadManager().GetCurrentThread(); |     Thread* thread = kernel.GetCurrentThreadManager().GetCurrentThread(); | ||||||
| 
 | 
 | ||||||
|     if (!Memory::IsValidVirtualAddress(*kernel.GetCurrentProcess(), handles_address)) |     if (!memory.IsValidVirtualAddress(*kernel.GetCurrentProcess(), handles_address)) | ||||||
|         return ERR_INVALID_POINTER; |         return ERR_INVALID_POINTER; | ||||||
| 
 | 
 | ||||||
|     // NOTE: on real hardware, there is no nullptr check for 'out' (tested with firmware 4.4). If
 |     // NOTE: on real hardware, there is no nullptr check for 'out' (tested with firmware 4.4). If
 | ||||||
|  | @ -687,7 +685,7 @@ static ResultCode ReceiveIPCRequest(Kernel::KernelSystem& kernel, Memory::Memory | ||||||
| /// In a single operation, sends a IPC reply and waits for a new request.
 | /// In a single operation, sends a IPC reply and waits for a new request.
 | ||||||
| ResultCode SVC::ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_count, | ResultCode SVC::ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_count, | ||||||
|                                 Handle reply_target) { |                                 Handle reply_target) { | ||||||
|     if (!Memory::IsValidVirtualAddress(*kernel.GetCurrentProcess(), handles_address)) |     if (!memory.IsValidVirtualAddress(*kernel.GetCurrentProcess(), handles_address)) | ||||||
|         return ERR_INVALID_POINTER; |         return ERR_INVALID_POINTER; | ||||||
| 
 | 
 | ||||||
|     // Check if 'handle_count' is invalid
 |     // Check if 'handle_count' is invalid
 | ||||||
|  | @ -1288,7 +1286,7 @@ s64 SVC::GetSystemTick() { | ||||||
| /// Creates a memory block at the specified address with the specified permissions and size
 | /// Creates a memory block at the specified address with the specified permissions and size
 | ||||||
| ResultCode SVC::CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 my_permission, | ResultCode SVC::CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 my_permission, | ||||||
|                                   u32 other_permission) { |                                   u32 other_permission) { | ||||||
|     if (size % Memory::PAGE_SIZE != 0) |     if (size % Memory::CITRA_PAGE_SIZE != 0) | ||||||
|         return ERR_MISALIGNED_SIZE; |         return ERR_MISALIGNED_SIZE; | ||||||
| 
 | 
 | ||||||
|     std::shared_ptr<SharedMemory> shared_memory = nullptr; |     std::shared_ptr<SharedMemory> shared_memory = nullptr; | ||||||
|  | @ -1393,7 +1391,7 @@ ResultCode SVC::AcceptSession(Handle* out_server_session, Handle server_port_han | ||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void CopyStringPart(char* out, const char* in, int offset, int max_length) { | static void CopyStringPart(char* out, const char* in, size_t offset, size_t max_length) { | ||||||
|     size_t str_size = strlen(in); |     size_t str_size = strlen(in); | ||||||
|     if (offset < str_size) { |     if (offset < str_size) { | ||||||
|         strncpy(out, in + offset, max_length - 1); |         strncpy(out, in + offset, max_length - 1); | ||||||
|  | @ -1509,7 +1507,7 @@ ResultCode SVC::GetProcessInfo(s64* out, Handle process_handle, u32 type) { | ||||||
|         // TODO(yuriks): Type 0 returns a slightly higher number than type 2, but I'm not sure
 |         // TODO(yuriks): Type 0 returns a slightly higher number than type 2, but I'm not sure
 | ||||||
|         // what's the difference between them.
 |         // what's the difference between them.
 | ||||||
|         *out = process->memory_used; |         *out = process->memory_used; | ||||||
|         if (*out % Memory::PAGE_SIZE != 0) { |         if (*out % Memory::CITRA_PAGE_SIZE != 0) { | ||||||
|             LOG_ERROR(Kernel_SVC, "called, memory size not page-aligned"); |             LOG_ERROR(Kernel_SVC, "called, memory size not page-aligned"); | ||||||
|             return ERR_MISALIGNED_SIZE; |             return ERR_MISALIGNED_SIZE; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -105,9 +105,9 @@ void Thread::Stop() { | ||||||
|     ReleaseThreadMutexes(this); |     ReleaseThreadMutexes(this); | ||||||
| 
 | 
 | ||||||
|     // Mark the TLS slot in the thread's page as free.
 |     // Mark the TLS slot in the thread's page as free.
 | ||||||
|     u32 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE; |     u32 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::CITRA_PAGE_SIZE; | ||||||
|     u32 tls_slot = |     u32 tls_slot = | ||||||
|         ((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE; |         ((tls_address - Memory::TLS_AREA_VADDR) % Memory::CITRA_PAGE_SIZE) / Memory::TLS_ENTRY_SIZE; | ||||||
|     ASSERT(owner_process.lock()); |     ASSERT(owner_process.lock()); | ||||||
|     owner_process.lock()->tls_slots[tls_page].reset(tls_slot); |     owner_process.lock()->tls_slots[tls_page].reset(tls_slot); | ||||||
| } | } | ||||||
|  | @ -337,8 +337,7 @@ ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread( | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // TODO(yuriks): Other checks, returning 0xD9001BEA
 |     // TODO(yuriks): Other checks, returning 0xD9001BEA
 | ||||||
| 
 |     if (!memory.IsValidVirtualAddress(*owner_process, entry_point)) { | ||||||
|     if (!Memory::IsValidVirtualAddress(*owner_process, entry_point)) { |  | ||||||
|         LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:08x}", name, entry_point); |         LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:08x}", name, entry_point); | ||||||
|         // TODO: Verify error
 |         // TODO: Verify error
 | ||||||
|         return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, |         return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, | ||||||
|  | @ -374,13 +373,13 @@ ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread( | ||||||
|         auto memory_region = GetMemoryRegion(MemoryRegion::BASE); |         auto memory_region = GetMemoryRegion(MemoryRegion::BASE); | ||||||
| 
 | 
 | ||||||
|         // Allocate some memory from the end of the linear heap for this region.
 |         // Allocate some memory from the end of the linear heap for this region.
 | ||||||
|         auto offset = memory_region->LinearAllocate(Memory::PAGE_SIZE); |         auto offset = memory_region->LinearAllocate(Memory::CITRA_PAGE_SIZE); | ||||||
|         if (!offset) { |         if (!offset) { | ||||||
|             LOG_ERROR(Kernel_SVC, |             LOG_ERROR(Kernel_SVC, | ||||||
|                       "Not enough space in region to allocate a new TLS page for thread"); |                       "Not enough space in region to allocate a new TLS page for thread"); | ||||||
|             return ERR_OUT_OF_MEMORY; |             return ERR_OUT_OF_MEMORY; | ||||||
|         } |         } | ||||||
|         owner_process->memory_used += Memory::PAGE_SIZE; |         owner_process->memory_used += Memory::CITRA_PAGE_SIZE; | ||||||
| 
 | 
 | ||||||
|         tls_slots.emplace_back(0); // The page is completely available at the start
 |         tls_slots.emplace_back(0); // The page is completely available at the start
 | ||||||
|         available_page = tls_slots.size() - 1; |         available_page = tls_slots.size() - 1; | ||||||
|  | @ -390,14 +389,14 @@ ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread( | ||||||
| 
 | 
 | ||||||
|         // Map the page to the current process' address space.
 |         // Map the page to the current process' address space.
 | ||||||
|         vm_manager.MapBackingMemory( |         vm_manager.MapBackingMemory( | ||||||
|             Memory::TLS_AREA_VADDR + static_cast<VAddr>(available_page) * Memory::PAGE_SIZE, |             Memory::TLS_AREA_VADDR + static_cast<VAddr>(available_page) * Memory::CITRA_PAGE_SIZE, | ||||||
|             memory.GetFCRAMRef(*offset), Memory::PAGE_SIZE, MemoryState::Locked); |             memory.GetFCRAMRef(*offset), Memory::CITRA_PAGE_SIZE, MemoryState::Locked); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Mark the slot as used
 |     // Mark the slot as used
 | ||||||
|     tls_slots[available_page].set(available_slot); |     tls_slots[available_page].set(available_slot); | ||||||
|     thread->tls_address = Memory::TLS_AREA_VADDR + |     thread->tls_address = Memory::TLS_AREA_VADDR + | ||||||
|                           static_cast<VAddr>(available_page) * Memory::PAGE_SIZE + |                           static_cast<VAddr>(available_page) * Memory::CITRA_PAGE_SIZE + | ||||||
|                           static_cast<VAddr>(available_slot) * Memory::TLS_ENTRY_SIZE; |                           static_cast<VAddr>(available_slot) * Memory::TLS_ENTRY_SIZE; | ||||||
| 
 | 
 | ||||||
|     memory.ZeroBlock(*owner_process, thread->tls_address, Memory::TLS_ENTRY_SIZE); |     memory.ZeroBlock(*owner_process, thread->tls_address, Memory::TLS_ENTRY_SIZE); | ||||||
|  |  | ||||||
|  | @ -260,8 +260,8 @@ VMManager::VMAIter VMManager::StripIterConstness(const VMAHandle& iter) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultVal<VMManager::VMAIter> VMManager::CarveVMA(VAddr base, u32 size) { | ResultVal<VMManager::VMAIter> VMManager::CarveVMA(VAddr base, u32 size) { | ||||||
|     ASSERT_MSG((size & Memory::PAGE_MASK) == 0, "non-page aligned size: {:#10X}", size); |     ASSERT_MSG((size & Memory::CITRA_PAGE_MASK) == 0, "non-page aligned size: {:#10X}", size); | ||||||
|     ASSERT_MSG((base & Memory::PAGE_MASK) == 0, "non-page aligned base: {:#010X}", base); |     ASSERT_MSG((base & Memory::CITRA_PAGE_MASK) == 0, "non-page aligned base: {:#010X}", base); | ||||||
| 
 | 
 | ||||||
|     VMAIter vma_handle = StripIterConstness(FindVMA(base)); |     VMAIter vma_handle = StripIterConstness(FindVMA(base)); | ||||||
|     if (vma_handle == vma_map.end()) { |     if (vma_handle == vma_map.end()) { | ||||||
|  | @ -296,8 +296,8 @@ ResultVal<VMManager::VMAIter> VMManager::CarveVMA(VAddr base, u32 size) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultVal<VMManager::VMAIter> VMManager::CarveVMARange(VAddr target, u32 size) { | ResultVal<VMManager::VMAIter> VMManager::CarveVMARange(VAddr target, u32 size) { | ||||||
|     ASSERT_MSG((size & Memory::PAGE_MASK) == 0, "non-page aligned size: {:#10X}", size); |     ASSERT_MSG((size & Memory::CITRA_PAGE_MASK) == 0, "non-page aligned size: {:#10X}", size); | ||||||
|     ASSERT_MSG((target & Memory::PAGE_MASK) == 0, "non-page aligned base: {:#010X}", target); |     ASSERT_MSG((target & Memory::CITRA_PAGE_MASK) == 0, "non-page aligned base: {:#010X}", target); | ||||||
| 
 | 
 | ||||||
|     const VAddr target_end = target + size; |     const VAddr target_end = target + size; | ||||||
|     ASSERT(target_end >= target); |     ASSERT(target_end >= target); | ||||||
|  |  | ||||||
|  | @ -17,12 +17,9 @@ | ||||||
| #include "core/file_sys/errors.h" | #include "core/file_sys/errors.h" | ||||||
| #include "core/file_sys/ncch_container.h" | #include "core/file_sys/ncch_container.h" | ||||||
| #include "core/file_sys/title_metadata.h" | #include "core/file_sys/title_metadata.h" | ||||||
| #include "core/hle/ipc.h" |  | ||||||
| #include "core/hle/ipc_helpers.h" | #include "core/hle/ipc_helpers.h" | ||||||
| #include "core/hle/kernel/client_port.h" |  | ||||||
| #include "core/hle/kernel/client_session.h" | #include "core/hle/kernel/client_session.h" | ||||||
| #include "core/hle/kernel/errors.h" | #include "core/hle/kernel/errors.h" | ||||||
| #include "core/hle/kernel/handle_table.h" |  | ||||||
| #include "core/hle/kernel/server_session.h" | #include "core/hle/kernel/server_session.h" | ||||||
| #include "core/hle/kernel/session.h" | #include "core/hle/kernel/session.h" | ||||||
| #include "core/hle/service/am/am.h" | #include "core/hle/service/am/am.h" | ||||||
|  | @ -610,7 +607,6 @@ void Module::Interface::FindDLCContentInfos(Kernel::HLERequestContext& ctx) { | ||||||
| 
 | 
 | ||||||
|     std::string tmd_path = GetTitleMetadataPath(media_type, title_id); |     std::string tmd_path = GetTitleMetadataPath(media_type, title_id); | ||||||
| 
 | 
 | ||||||
|     u32 content_read = 0; |  | ||||||
|     FileSys::TitleMetadata tmd; |     FileSys::TitleMetadata tmd; | ||||||
|     if (tmd.Load(tmd_path) == Loader::ResultStatus::Success) { |     if (tmd.Load(tmd_path) == Loader::ResultStatus::Success) { | ||||||
|         std::size_t write_offset = 0; |         std::size_t write_offset = 0; | ||||||
|  | @ -642,7 +638,6 @@ void Module::Interface::FindDLCContentInfos(Kernel::HLERequestContext& ctx) { | ||||||
| 
 | 
 | ||||||
|             content_info_out.Write(&content_info, write_offset, sizeof(ContentInfo)); |             content_info_out.Write(&content_info, write_offset, sizeof(ContentInfo)); | ||||||
|             write_offset += sizeof(ContentInfo); |             write_offset += sizeof(ContentInfo); | ||||||
|             content_read++; |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2,7 +2,6 @@ | ||||||
| // Licensed under GPLv2 or any later version
 | // Licensed under GPLv2 or any later version
 | ||||||
| // Refer to the license.txt file included.
 | // Refer to the license.txt file included.
 | ||||||
| 
 | 
 | ||||||
| #include "common/common_paths.h" |  | ||||||
| #include "core/core.h" | #include "core/core.h" | ||||||
| #include "core/hle/applets/applet.h" | #include "core/hle/applets/applet.h" | ||||||
| #include "core/hle/service/apt/applet_manager.h" | #include "core/hle/service/apt/applet_manager.h" | ||||||
|  | @ -27,47 +26,66 @@ struct AppletTitleData { | ||||||
| 
 | 
 | ||||||
| static constexpr std::size_t NumApplets = 29; | static constexpr std::size_t NumApplets = 29; | ||||||
| static constexpr std::array<AppletTitleData, NumApplets> applet_titleids = {{ | static constexpr std::array<AppletTitleData, NumApplets> applet_titleids = {{ | ||||||
|     {AppletId::HomeMenu, AppletId::None, 0x4003000008202, 0x4003000008F02, 0x4003000009802, |     {{AppletId::HomeMenu, AppletId::None}, | ||||||
|      0x4003000008202, 0x400300000A102, 0x400300000A902, 0x400300000B102}, |      {0x4003000008202, 0x4003000008F02, 0x4003000009802, 0x4003000008202, 0x400300000A102, | ||||||
|     {AppletId::AlternateMenu, AppletId::None, 0x4003000008102, 0x4003000008102, 0x4003000008102, |       0x400300000A902, 0x400300000B102}}, | ||||||
|      0x4003000008102, 0x4003000008102, 0x4003000008102, 0x4003000008102}, |     {{AppletId::AlternateMenu, AppletId::None}, | ||||||
|     {AppletId::Camera, AppletId::None, 0x4003000008402, 0x4003000009002, 0x4003000009902, |      {0x4003000008102, 0x4003000008102, 0x4003000008102, 0x4003000008102, 0x4003000008102, | ||||||
|      0x4003000008402, 0x400300000A202, 0x400300000AA02, 0x400300000B202}, |       0x4003000008102, 0x4003000008102}}, | ||||||
|     {AppletId::FriendList, AppletId::None, 0x4003000008D02, 0x4003000009602, 0x4003000009F02, |     {{AppletId::Camera, AppletId::None}, | ||||||
|      0x4003000008D02, 0x400300000A702, 0x400300000AF02, 0x400300000B702}, |      {0x4003000008402, 0x4003000009002, 0x4003000009902, 0x4003000008402, 0x400300000A202, | ||||||
|     {AppletId::GameNotes, AppletId::None, 0x4003000008702, 0x4003000009302, 0x4003000009C02, |       0x400300000AA02, 0x400300000B202}}, | ||||||
|      0x4003000008702, 0x400300000A502, 0x400300000AD02, 0x400300000B502}, |     {{AppletId::FriendList, AppletId::None}, | ||||||
|     {AppletId::InternetBrowser, AppletId::None, 0x4003000008802, 0x4003000009402, 0x4003000009D02, |      {0x4003000008D02, 0x4003000009602, 0x4003000009F02, 0x4003000008D02, 0x400300000A702, | ||||||
|      0x4003000008802, 0x400300000A602, 0x400300000AE02, 0x400300000B602}, |       0x400300000AF02, 0x400300000B702}}, | ||||||
|     {AppletId::InstructionManual, AppletId::None, 0x4003000008602, 0x4003000009202, 0x4003000009B02, |     {{AppletId::GameNotes, AppletId::None}, | ||||||
|      0x4003000008602, 0x400300000A402, 0x400300000AC02, 0x400300000B402}, |      {0x4003000008702, 0x4003000009302, 0x4003000009C02, 0x4003000008702, 0x400300000A502, | ||||||
|     {AppletId::Notifications, AppletId::None, 0x4003000008E02, 0x4003000009702, 0x400300000A002, |       0x400300000AD02, 0x400300000B502}}, | ||||||
|      0x4003000008E02, 0x400300000A802, 0x400300000B002, 0x400300000B802}, |     {{AppletId::InternetBrowser, AppletId::None}, | ||||||
|     {AppletId::Miiverse, AppletId::None, 0x400300000BC02, 0x400300000BD02, 0x400300000BE02, |      {0x4003000008802, 0x4003000009402, 0x4003000009D02, 0x4003000008802, 0x400300000A602, | ||||||
|      0x400300000BC02, 0x4003000009E02, 0x4003000009502, 0x400300000B902}, |       0x400300000AE02, 0x400300000B602}}, | ||||||
|  |     {{AppletId::InstructionManual, AppletId::None}, | ||||||
|  |      {0x4003000008602, 0x4003000009202, 0x4003000009B02, 0x4003000008602, 0x400300000A402, | ||||||
|  |       0x400300000AC02, 0x400300000B402}}, | ||||||
|  |     {{AppletId::Notifications, AppletId::None}, | ||||||
|  |      {0x4003000008E02, 0x4003000009702, 0x400300000A002, 0x4003000008E02, 0x400300000A802, | ||||||
|  |       0x400300000B002, 0x400300000B802}}, | ||||||
|  |     {{AppletId::Miiverse, AppletId::None}, | ||||||
|  |      {0x400300000BC02, 0x400300000BD02, 0x400300000BE02, 0x400300000BC02, 0x4003000009E02, | ||||||
|  |       0x4003000009502, 0x400300000B902}}, | ||||||
|     // These values obtained from an older NS dump firmware 4.5
 |     // These values obtained from an older NS dump firmware 4.5
 | ||||||
|     {AppletId::MiiversePost, AppletId::None, 0x400300000BA02, 0x400300000BA02, 0x400300000BA02, |     {{AppletId::MiiversePost, AppletId::None}, | ||||||
|      0x400300000BA02, 0x400300000BA02, 0x400300000BA02, 0x400300000BA02}, |      {0x400300000BA02, 0x400300000BA02, 0x400300000BA02, 0x400300000BA02, 0x400300000BA02, | ||||||
|  |       0x400300000BA02, 0x400300000BA02}}, | ||||||
|     // {AppletId::MiiversePost, AppletId::None, 0x4003000008302, 0x4003000008B02, 0x400300000BA02,
 |     // {AppletId::MiiversePost, AppletId::None, 0x4003000008302, 0x4003000008B02, 0x400300000BA02,
 | ||||||
|     //  0x4003000008302, 0x0, 0x0, 0x0},
 |     //  0x4003000008302, 0x0, 0x0, 0x0},
 | ||||||
|     {AppletId::AmiiboSettings, AppletId::None, 0x4003000009502, 0x4003000009E02, 0x400300000B902, |     {{AppletId::AmiiboSettings, AppletId::None}, | ||||||
|      0x4003000009502, 0x0, 0x4003000008C02, 0x400300000BF02}, |      {0x4003000009502, 0x4003000009E02, 0x400300000B902, 0x4003000009502, 0x0, 0x4003000008C02, | ||||||
|     {AppletId::SoftwareKeyboard1, AppletId::SoftwareKeyboard2, 0x400300000C002, 0x400300000C802, |       0x400300000BF02}}, | ||||||
|      0x400300000D002, 0x400300000C002, 0x400300000D802, 0x400300000DE02, 0x400300000E402}, |     {{AppletId::SoftwareKeyboard1, AppletId::SoftwareKeyboard2}, | ||||||
|     {AppletId::Ed1, AppletId::Ed2, 0x400300000C102, 0x400300000C902, 0x400300000D102, |      {0x400300000C002, 0x400300000C802, 0x400300000D002, 0x400300000C002, 0x400300000D802, | ||||||
|      0x400300000C102, 0x400300000D902, 0x400300000DF02, 0x400300000E502}, |       0x400300000DE02, 0x400300000E402}}, | ||||||
|     {AppletId::PnoteApp, AppletId::PnoteApp2, 0x400300000C302, 0x400300000CB02, 0x400300000D302, |     {{AppletId::Ed1, AppletId::Ed2}, | ||||||
|      0x400300000C302, 0x400300000DB02, 0x400300000E102, 0x400300000E702}, |      {0x400300000C102, 0x400300000C902, 0x400300000D102, 0x400300000C102, 0x400300000D902, | ||||||
|     {AppletId::SnoteApp, AppletId::SnoteApp2, 0x400300000C402, 0x400300000CC02, 0x400300000D402, |       0x400300000DF02, 0x400300000E502}}, | ||||||
|      0x400300000C402, 0x400300000DC02, 0x400300000E202, 0x400300000E802}, |     {{AppletId::PnoteApp, AppletId::PnoteApp2}, | ||||||
|     {AppletId::Error, AppletId::Error2, 0x400300000C502, 0x400300000C502, 0x400300000C502, |      {0x400300000C302, 0x400300000CB02, 0x400300000D302, 0x400300000C302, 0x400300000DB02, | ||||||
|      0x400300000C502, 0x400300000CF02, 0x400300000CF02, 0x400300000CF02}, |       0x400300000E102, 0x400300000E702}}, | ||||||
|     {AppletId::Mint, AppletId::Mint2, 0x400300000C602, 0x400300000CE02, 0x400300000D602, |     {{AppletId::SnoteApp, AppletId::SnoteApp2}, | ||||||
|      0x400300000C602, 0x400300000DD02, 0x400300000E302, 0x400300000E902}, |      {0x400300000C402, 0x400300000CC02, 0x400300000D402, 0x400300000C402, 0x400300000DC02, | ||||||
|     {AppletId::Extrapad, AppletId::Extrapad2, 0x400300000CD02, 0x400300000CD02, 0x400300000CD02, |       0x400300000E202, 0x400300000E802}}, | ||||||
|      0x400300000CD02, 0x400300000D502, 0x400300000D502, 0x400300000D502}, |     {{AppletId::Error, AppletId::Error2}, | ||||||
|     {AppletId::Memolib, AppletId::Memolib2, 0x400300000F602, 0x400300000F602, 0x400300000F602, |      {0x400300000C502, 0x400300000C502, 0x400300000C502, 0x400300000C502, 0x400300000CF02, | ||||||
|      0x400300000F602, 0x400300000F602, 0x400300000F602, 0x400300000F602}, |       0x400300000CF02, 0x400300000CF02}}, | ||||||
|  |     {{AppletId::Mint, AppletId::Mint2}, | ||||||
|  |      {0x400300000C602, 0x400300000CE02, 0x400300000D602, 0x400300000C602, 0x400300000DD02, | ||||||
|  |       0x400300000E302, 0x400300000E902}}, | ||||||
|  |     {{AppletId::Extrapad, AppletId::Extrapad2}, | ||||||
|  |      {0x400300000CD02, 0x400300000CD02, 0x400300000CD02, 0x400300000CD02, 0x400300000D502, | ||||||
|  |       0x400300000D502, 0x400300000D502}}, | ||||||
|  |     {{AppletId::Memolib, AppletId::Memolib2}, | ||||||
|  |      {0x400300000F602, 0x400300000F602, 0x400300000F602, 0x400300000F602, 0x400300000F602, | ||||||
|  |       0x400300000F602, 0x400300000F602}}, | ||||||
|     // TODO(Subv): Fill in the rest of the titleids
 |     // TODO(Subv): Fill in the rest of the titleids
 | ||||||
| }}; | }}; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -10,7 +10,6 @@ | ||||||
| #include <cryptopp/osrng.h> | #include <cryptopp/osrng.h> | ||||||
| #include <cryptopp/sha.h> | #include <cryptopp/sha.h> | ||||||
| #include "common/archives.h" | #include "common/archives.h" | ||||||
| #include "common/common_paths.h" |  | ||||||
| #include "common/file_util.h" | #include "common/file_util.h" | ||||||
| #include "common/logging/log.h" | #include "common/logging/log.h" | ||||||
| #include "common/string_util.h" | #include "common/string_util.h" | ||||||
|  | @ -107,7 +106,7 @@ static_assert(sizeof(ConsoleCountryInfo) == 4, "ConsoleCountryInfo must be exact | ||||||
| 
 | 
 | ||||||
| constexpr EULAVersion MAX_EULA_VERSION{0x7F, 0x7F}; | constexpr EULAVersion MAX_EULA_VERSION{0x7F, 0x7F}; | ||||||
| constexpr ConsoleModelInfo CONSOLE_MODEL_OLD{NINTENDO_3DS_XL, {0, 0, 0}}; | constexpr ConsoleModelInfo CONSOLE_MODEL_OLD{NINTENDO_3DS_XL, {0, 0, 0}}; | ||||||
| constexpr ConsoleModelInfo CONSOLE_MODEL_NEW{NEW_NINTENDO_3DS_XL, {0, 0, 0}}; | [[maybe_unused]] constexpr ConsoleModelInfo CONSOLE_MODEL_NEW{NEW_NINTENDO_3DS_XL, {0, 0, 0}}; | ||||||
| constexpr u8 CONSOLE_LANGUAGE = LANGUAGE_EN; | constexpr u8 CONSOLE_LANGUAGE = LANGUAGE_EN; | ||||||
| constexpr UsernameBlock CONSOLE_USERNAME_BLOCK{u"CITRA", 0, 0}; | constexpr UsernameBlock CONSOLE_USERNAME_BLOCK{u"CITRA", 0, 0}; | ||||||
| constexpr BirthdayBlock PROFILE_BIRTHDAY{3, 25}; // March 25th, 2014
 | constexpr BirthdayBlock PROFILE_BIRTHDAY{3, 25}; // March 25th, 2014
 | ||||||
|  | @ -269,7 +268,7 @@ void Module::Interface::GetSystemModel(Kernel::HLERequestContext& ctx) { | ||||||
| void Module::Interface::GetModelNintendo2DS(Kernel::HLERequestContext& ctx) { | void Module::Interface::GetModelNintendo2DS(Kernel::HLERequestContext& ctx) { | ||||||
|     IPC::RequestParser rp(ctx, 0x06, 0, 0); |     IPC::RequestParser rp(ctx, 0x06, 0, 0); | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); |     IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||||||
|     u32 data; |     u32 data{}; | ||||||
| 
 | 
 | ||||||
|     // TODO(Subv): Find out the correct error codes
 |     // TODO(Subv): Find out the correct error codes
 | ||||||
|     rb.Push(cfg->GetConfigInfoBlock(ConsoleModelBlockID, 4, 0x8, reinterpret_cast<u8*>(&data))); |     rb.Push(cfg->GetConfigInfoBlock(ConsoleModelBlockID, 4, 0x8, reinterpret_cast<u8*>(&data))); | ||||||
|  | @ -370,7 +369,7 @@ ResultVal<void*> Module::GetConfigInfoBlockPointer(u32 block_id, u32 size, u32 f | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultCode Module::GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, void* output) { | ResultCode Module::GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, void* output) { | ||||||
|     void* pointer; |     void* pointer = nullptr; | ||||||
|     CASCADE_RESULT(pointer, GetConfigInfoBlockPointer(block_id, size, flag)); |     CASCADE_RESULT(pointer, GetConfigInfoBlockPointer(block_id, size, flag)); | ||||||
|     memcpy(output, pointer, size); |     memcpy(output, pointer, size); | ||||||
| 
 | 
 | ||||||
|  | @ -378,7 +377,7 @@ ResultCode Module::GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, void* ou | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultCode Module::SetConfigInfoBlock(u32 block_id, u32 size, u32 flag, const void* input) { | ResultCode Module::SetConfigInfoBlock(u32 block_id, u32 size, u32 flag, const void* input) { | ||||||
|     void* pointer; |     void* pointer = nullptr; | ||||||
|     CASCADE_RESULT(pointer, GetConfigInfoBlockPointer(block_id, size, flag)); |     CASCADE_RESULT(pointer, GetConfigInfoBlockPointer(block_id, size, flag)); | ||||||
|     memcpy(pointer, input, size); |     memcpy(pointer, input, size); | ||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
|  | @ -701,7 +700,7 @@ void Module::SetSystemLanguage(SystemLanguage language) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| SystemLanguage Module::GetSystemLanguage() { | SystemLanguage Module::GetSystemLanguage() { | ||||||
|     u8 block; |     u8 block{}; | ||||||
|     GetConfigInfoBlock(LanguageBlockID, sizeof(block), 8, &block); |     GetConfigInfoBlock(LanguageBlockID, sizeof(block), 8, &block); | ||||||
|     return static_cast<SystemLanguage>(block); |     return static_cast<SystemLanguage>(block); | ||||||
| } | } | ||||||
|  | @ -712,7 +711,7 @@ void Module::SetSoundOutputMode(SoundOutputMode mode) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| SoundOutputMode Module::GetSoundOutputMode() { | SoundOutputMode Module::GetSoundOutputMode() { | ||||||
|     u8 block; |     u8 block{}; | ||||||
|     GetConfigInfoBlock(SoundOutputModeBlockID, sizeof(block), 8, &block); |     GetConfigInfoBlock(SoundOutputModeBlockID, sizeof(block), 8, &block); | ||||||
|     return static_cast<SoundOutputMode>(block); |     return static_cast<SoundOutputMode>(block); | ||||||
| } | } | ||||||
|  | @ -723,7 +722,7 @@ void Module::SetCountryCode(u8 country_code) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| u8 Module::GetCountryCode() { | u8 Module::GetCountryCode() { | ||||||
|     ConsoleCountryInfo block; |     ConsoleCountryInfo block{}; | ||||||
|     GetConfigInfoBlock(CountryInfoBlockID, sizeof(block), 8, &block); |     GetConfigInfoBlock(CountryInfoBlockID, sizeof(block), 8, &block); | ||||||
|     return block.country_code; |     return block.country_code; | ||||||
| } | } | ||||||
|  | @ -734,7 +733,7 @@ void Module::SetCountryInfo(u8 country_code, u8 state_code) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| u8 Module::GetStateCode() { | u8 Module::GetStateCode() { | ||||||
|     ConsoleCountryInfo block; |     ConsoleCountryInfo block{}; | ||||||
|     GetConfigInfoBlock(CountryInfoBlockID, sizeof(block), 8, &block); |     GetConfigInfoBlock(CountryInfoBlockID, sizeof(block), 8, &block); | ||||||
|     return block.state_code; |     return block.state_code; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -192,7 +192,7 @@ static_assert(sizeof(CaptureState) == 0x8, "CaptureState structure size is wrong | ||||||
| 
 | 
 | ||||||
| void CSND_SND::Initialize(Kernel::HLERequestContext& ctx) { | void CSND_SND::Initialize(Kernel::HLERequestContext& ctx) { | ||||||
|     IPC::RequestParser rp(ctx, 0x01, 5, 0); |     IPC::RequestParser rp(ctx, 0x01, 5, 0); | ||||||
|     const u32 size = Common::AlignUp(rp.Pop<u32>(), Memory::PAGE_SIZE); |     const u32 size = Common::AlignUp(rp.Pop<u32>(), Memory::CITRA_PAGE_SIZE); | ||||||
|     master_state_offset = rp.Pop<u32>(); |     master_state_offset = rp.Pop<u32>(); | ||||||
|     channel_state_offset = rp.Pop<u32>(); |     channel_state_offset = rp.Pop<u32>(); | ||||||
|     capture_state_offset = rp.Pop<u32>(); |     capture_state_offset = rp.Pop<u32>(); | ||||||
|  |  | ||||||
|  | @ -95,6 +95,9 @@ void DSP_DSP::WriteProcessPipe(Kernel::HLERequestContext& ctx) { | ||||||
|         buffer[6] = 0; |         buffer[6] = 0; | ||||||
|         buffer[7] = 0; |         buffer[7] = 0; | ||||||
|         break; |         break; | ||||||
|  |     default: | ||||||
|  |         LOG_ERROR(Service_DSP, "Unknown pipe {}", pipe); | ||||||
|  |         break; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     system.DSP().PipeWrite(pipe, buffer); |     system.DSP().PipeWrite(pipe, buffer); | ||||||
|  |  | ||||||
|  | @ -884,6 +884,8 @@ ResultVal<u16> FS_USER::GetSpecialContentIndexFromTMD(MediaType media_type, u64 | ||||||
|     default: |     default: | ||||||
|         ASSERT(false); |         ASSERT(false); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     return ResultCode(-1); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| FS_USER::FS_USER(Core::System& system) | FS_USER::FS_USER(Core::System& system) | ||||||
|  |  | ||||||
|  | @ -8,9 +8,7 @@ | ||||||
| #include "common/microprofile.h" | #include "common/microprofile.h" | ||||||
| #include "common/swap.h" | #include "common/swap.h" | ||||||
| #include "core/core.h" | #include "core/core.h" | ||||||
| #include "core/hle/ipc.h" |  | ||||||
| #include "core/hle/ipc_helpers.h" | #include "core/hle/ipc_helpers.h" | ||||||
| #include "core/hle/kernel/handle_table.h" |  | ||||||
| #include "core/hle/kernel/shared_memory.h" | #include "core/hle/kernel/shared_memory.h" | ||||||
| #include "core/hle/kernel/shared_page.h" | #include "core/hle/kernel/shared_page.h" | ||||||
| #include "core/hle/result.h" | #include "core/hle/result.h" | ||||||
|  | @ -83,7 +81,9 @@ u32 GSP_GPU::GetUnusedThreadId() const { | ||||||
|         if (!used_thread_ids[id]) |         if (!used_thread_ids[id]) | ||||||
|             return id; |             return id; | ||||||
|     } |     } | ||||||
|     ASSERT_MSG(false, "All GSP threads are in use"); | 
 | ||||||
|  |     UNREACHABLE_MSG("All GSP threads are in use"); | ||||||
|  |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Gets a pointer to a thread command buffer in GSP shared memory
 | /// Gets a pointer to a thread command buffer in GSP shared memory
 | ||||||
|  |  | ||||||
|  | @ -1502,7 +1502,7 @@ u32 CROHelper::Fix(u32 fix_level) { | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fix_end = Common::AlignUp(fix_end, Memory::PAGE_SIZE); |     fix_end = Common::AlignUp(fix_end, Memory::CITRA_PAGE_SIZE); | ||||||
| 
 | 
 | ||||||
|     u32 fixed_size = fix_end - module_address; |     u32 fixed_size = fix_end - module_address; | ||||||
|     SetField(FixedSize, fixed_size); |     SetField(FixedSize, fixed_size); | ||||||
|  | @ -1525,8 +1525,8 @@ std::tuple<VAddr, u32> CROHelper::GetExecutablePages() const { | ||||||
|         SegmentEntry entry; |         SegmentEntry entry; | ||||||
|         GetEntry(system.Memory(), i, entry); |         GetEntry(system.Memory(), i, entry); | ||||||
|         if (entry.type == SegmentType::Code && entry.size != 0) { |         if (entry.type == SegmentType::Code && entry.size != 0) { | ||||||
|             VAddr begin = Common::AlignDown(entry.offset, Memory::PAGE_SIZE); |             VAddr begin = Common::AlignDown(entry.offset, Memory::CITRA_PAGE_SIZE); | ||||||
|             VAddr end = Common::AlignUp(entry.offset + entry.size, Memory::PAGE_SIZE); |             VAddr end = Common::AlignUp(entry.offset + entry.size, Memory::CITRA_PAGE_SIZE); | ||||||
|             return std::make_tuple(begin, end - begin); |             return std::make_tuple(begin, end - begin); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -87,19 +87,19 @@ void RO::Initialize(Kernel::HLERequestContext& ctx) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (crs_buffer_ptr & Memory::PAGE_MASK) { |     if (crs_buffer_ptr & Memory::CITRA_PAGE_MASK) { | ||||||
|         LOG_ERROR(Service_LDR, "CRS original address is not aligned"); |         LOG_ERROR(Service_LDR, "CRS original address is not aligned"); | ||||||
|         rb.Push(ERROR_MISALIGNED_ADDRESS); |         rb.Push(ERROR_MISALIGNED_ADDRESS); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (crs_address & Memory::PAGE_MASK) { |     if (crs_address & Memory::CITRA_PAGE_MASK) { | ||||||
|         LOG_ERROR(Service_LDR, "CRS mapping address is not aligned"); |         LOG_ERROR(Service_LDR, "CRS mapping address is not aligned"); | ||||||
|         rb.Push(ERROR_MISALIGNED_ADDRESS); |         rb.Push(ERROR_MISALIGNED_ADDRESS); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (crs_size & Memory::PAGE_MASK) { |     if (crs_size & Memory::CITRA_PAGE_MASK) { | ||||||
|         LOG_ERROR(Service_LDR, "CRS size is not aligned"); |         LOG_ERROR(Service_LDR, "CRS size is not aligned"); | ||||||
|         rb.Push(ERROR_MISALIGNED_SIZE); |         rb.Push(ERROR_MISALIGNED_SIZE); | ||||||
|         return; |         return; | ||||||
|  | @ -207,21 +207,21 @@ void RO::LoadCRO(Kernel::HLERequestContext& ctx, bool link_on_load_bug_fix) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (cro_buffer_ptr & Memory::PAGE_MASK) { |     if (cro_buffer_ptr & Memory::CITRA_PAGE_MASK) { | ||||||
|         LOG_ERROR(Service_LDR, "CRO original address is not aligned"); |         LOG_ERROR(Service_LDR, "CRO original address is not aligned"); | ||||||
|         rb.Push(ERROR_MISALIGNED_ADDRESS); |         rb.Push(ERROR_MISALIGNED_ADDRESS); | ||||||
|         rb.Push<u32>(0); |         rb.Push<u32>(0); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (cro_address & Memory::PAGE_MASK) { |     if (cro_address & Memory::CITRA_PAGE_MASK) { | ||||||
|         LOG_ERROR(Service_LDR, "CRO mapping address is not aligned"); |         LOG_ERROR(Service_LDR, "CRO mapping address is not aligned"); | ||||||
|         rb.Push(ERROR_MISALIGNED_ADDRESS); |         rb.Push(ERROR_MISALIGNED_ADDRESS); | ||||||
|         rb.Push<u32>(0); |         rb.Push<u32>(0); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (cro_size & Memory::PAGE_MASK) { |     if (cro_size & Memory::CITRA_PAGE_MASK) { | ||||||
|         LOG_ERROR(Service_LDR, "CRO size is not aligned"); |         LOG_ERROR(Service_LDR, "CRO size is not aligned"); | ||||||
|         rb.Push(ERROR_MISALIGNED_SIZE); |         rb.Push(ERROR_MISALIGNED_SIZE); | ||||||
|         rb.Push<u32>(0); |         rb.Push<u32>(0); | ||||||
|  | @ -354,7 +354,7 @@ void RO::UnloadCRO(Kernel::HLERequestContext& ctx) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (cro_address & Memory::PAGE_MASK) { |     if (cro_address & Memory::CITRA_PAGE_MASK) { | ||||||
|         LOG_ERROR(Service_LDR, "CRO address is not aligned"); |         LOG_ERROR(Service_LDR, "CRO address is not aligned"); | ||||||
|         rb.Push(ERROR_MISALIGNED_ADDRESS); |         rb.Push(ERROR_MISALIGNED_ADDRESS); | ||||||
|         return; |         return; | ||||||
|  | @ -421,7 +421,7 @@ void RO::LinkCRO(Kernel::HLERequestContext& ctx) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (cro_address & Memory::PAGE_MASK) { |     if (cro_address & Memory::CITRA_PAGE_MASK) { | ||||||
|         LOG_ERROR(Service_LDR, "CRO address is not aligned"); |         LOG_ERROR(Service_LDR, "CRO address is not aligned"); | ||||||
|         rb.Push(ERROR_MISALIGNED_ADDRESS); |         rb.Push(ERROR_MISALIGNED_ADDRESS); | ||||||
|         return; |         return; | ||||||
|  | @ -461,7 +461,7 @@ void RO::UnlinkCRO(Kernel::HLERequestContext& ctx) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (cro_address & Memory::PAGE_MASK) { |     if (cro_address & Memory::CITRA_PAGE_MASK) { | ||||||
|         LOG_ERROR(Service_LDR, "CRO address is not aligned"); |         LOG_ERROR(Service_LDR, "CRO address is not aligned"); | ||||||
|         rb.Push(ERROR_MISALIGNED_ADDRESS); |         rb.Push(ERROR_MISALIGNED_ADDRESS); | ||||||
|         return; |         return; | ||||||
|  |  | ||||||
|  | @ -92,7 +92,8 @@ u16 NWM_UDS::GetNextAvailableNodeId() { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Any connection attempts to an already full network should have been refused.
 |     // Any connection attempts to an already full network should have been refused.
 | ||||||
|     ASSERT_MSG(false, "No available connection slots in the network"); |     UNREACHABLE_MSG("No available connection slots in the network"); | ||||||
|  |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void NWM_UDS::BroadcastNodeMap() { | void NWM_UDS::BroadcastNodeMap() { | ||||||
|  |  | ||||||
|  | @ -15,9 +15,6 @@ | ||||||
| 
 | 
 | ||||||
| namespace Service::NWM { | namespace Service::NWM { | ||||||
| 
 | 
 | ||||||
| // 802.11 broadcast MAC address
 |  | ||||||
| constexpr MacAddress BroadcastMac = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; |  | ||||||
| 
 |  | ||||||
| constexpr u64 DefaultNetworkUptime = 900000000; // 15 minutes in microseconds.
 | constexpr u64 DefaultNetworkUptime = 900000000; // 15 minutes in microseconds.
 | ||||||
| 
 | 
 | ||||||
| // Note: These values were taken from a packet capture of an o3DS XL
 | // Note: These values were taken from a packet capture of an o3DS XL
 | ||||||
|  |  | ||||||
|  | @ -178,15 +178,6 @@ static const std::unordered_map<int, int> sockopt_map = {{ | ||||||
|     {0x1009, SO_ERROR}, |     {0x1009, SO_ERROR}, | ||||||
| }}; | }}; | ||||||
| 
 | 
 | ||||||
| /// Converts a socket option from 3ds-specific to platform-specific
 |  | ||||||
| static int TranslateSockOpt(int console_opt_name) { |  | ||||||
|     auto found = sockopt_map.find(console_opt_name); |  | ||||||
|     if (found != sockopt_map.end()) { |  | ||||||
|         return found->second; |  | ||||||
|     } |  | ||||||
|     return console_opt_name; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /// Structure to represent the 3ds' pollfd structure, which is different than most implementations
 | /// Structure to represent the 3ds' pollfd structure, which is different than most implementations
 | ||||||
| struct CTRPollFD { | struct CTRPollFD { | ||||||
|     u32 fd; ///< Socket handle
 |     u32 fd; ///< Socket handle
 | ||||||
|  |  | ||||||
|  | @ -68,9 +68,11 @@ struct Regs { | ||||||
|         case PixelFormat::RGB5A1: |         case PixelFormat::RGB5A1: | ||||||
|         case PixelFormat::RGBA4: |         case PixelFormat::RGBA4: | ||||||
|             return 2; |             return 2; | ||||||
|  |         default: | ||||||
|  |             UNREACHABLE(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         UNREACHABLE(); |         return 0; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     INSERT_PADDING_WORDS(0x4); |     INSERT_PADDING_WORDS(0x4); | ||||||
|  |  | ||||||
|  | @ -94,13 +94,13 @@ ResultStatus AppLoader_NCCH::LoadExec(std::shared_ptr<Kernel::Process>& process) | ||||||
|         codeset->CodeSegment().offset = 0; |         codeset->CodeSegment().offset = 0; | ||||||
|         codeset->CodeSegment().addr = overlay_ncch->exheader_header.codeset_info.text.address; |         codeset->CodeSegment().addr = overlay_ncch->exheader_header.codeset_info.text.address; | ||||||
|         codeset->CodeSegment().size = |         codeset->CodeSegment().size = | ||||||
|             overlay_ncch->exheader_header.codeset_info.text.num_max_pages * Memory::PAGE_SIZE; |             overlay_ncch->exheader_header.codeset_info.text.num_max_pages * Memory::CITRA_PAGE_SIZE; | ||||||
| 
 | 
 | ||||||
|         codeset->RODataSegment().offset = |         codeset->RODataSegment().offset = | ||||||
|             codeset->CodeSegment().offset + codeset->CodeSegment().size; |             codeset->CodeSegment().offset + codeset->CodeSegment().size; | ||||||
|         codeset->RODataSegment().addr = overlay_ncch->exheader_header.codeset_info.ro.address; |         codeset->RODataSegment().addr = overlay_ncch->exheader_header.codeset_info.ro.address; | ||||||
|         codeset->RODataSegment().size = |         codeset->RODataSegment().size = | ||||||
|             overlay_ncch->exheader_header.codeset_info.ro.num_max_pages * Memory::PAGE_SIZE; |             overlay_ncch->exheader_header.codeset_info.ro.num_max_pages * Memory::CITRA_PAGE_SIZE; | ||||||
| 
 | 
 | ||||||
|         // TODO(yuriks): Not sure if the bss size is added to the page-aligned .data size or just
 |         // TODO(yuriks): Not sure if the bss size is added to the page-aligned .data size or just
 | ||||||
|         //               to the regular size. Playing it safe for now.
 |         //               to the regular size. Playing it safe for now.
 | ||||||
|  | @ -111,7 +111,8 @@ ResultStatus AppLoader_NCCH::LoadExec(std::shared_ptr<Kernel::Process>& process) | ||||||
|             codeset->RODataSegment().offset + codeset->RODataSegment().size; |             codeset->RODataSegment().offset + codeset->RODataSegment().size; | ||||||
|         codeset->DataSegment().addr = overlay_ncch->exheader_header.codeset_info.data.address; |         codeset->DataSegment().addr = overlay_ncch->exheader_header.codeset_info.data.address; | ||||||
|         codeset->DataSegment().size = |         codeset->DataSegment().size = | ||||||
|             overlay_ncch->exheader_header.codeset_info.data.num_max_pages * Memory::PAGE_SIZE + |             overlay_ncch->exheader_header.codeset_info.data.num_max_pages * | ||||||
|  |                 Memory::CITRA_PAGE_SIZE + | ||||||
|             bss_page_size; |             bss_page_size; | ||||||
| 
 | 
 | ||||||
|         // Apply patches now that the entire codeset (including .bss) has been allocated
 |         // Apply patches now that the entire codeset (including .bss) has been allocated
 | ||||||
|  |  | ||||||
|  | @ -55,20 +55,20 @@ public: | ||||||
| private: | private: | ||||||
|     bool* At(VAddr addr) { |     bool* At(VAddr addr) { | ||||||
|         if (addr >= VRAM_VADDR && addr < VRAM_VADDR_END) { |         if (addr >= VRAM_VADDR && addr < VRAM_VADDR_END) { | ||||||
|             return &vram[(addr - VRAM_VADDR) / PAGE_SIZE]; |             return &vram[(addr - VRAM_VADDR) / CITRA_PAGE_SIZE]; | ||||||
|         } |         } | ||||||
|         if (addr >= LINEAR_HEAP_VADDR && addr < LINEAR_HEAP_VADDR_END) { |         if (addr >= LINEAR_HEAP_VADDR && addr < LINEAR_HEAP_VADDR_END) { | ||||||
|             return &linear_heap[(addr - LINEAR_HEAP_VADDR) / PAGE_SIZE]; |             return &linear_heap[(addr - LINEAR_HEAP_VADDR) / CITRA_PAGE_SIZE]; | ||||||
|         } |         } | ||||||
|         if (addr >= NEW_LINEAR_HEAP_VADDR && addr < NEW_LINEAR_HEAP_VADDR_END) { |         if (addr >= NEW_LINEAR_HEAP_VADDR && addr < NEW_LINEAR_HEAP_VADDR_END) { | ||||||
|             return &new_linear_heap[(addr - NEW_LINEAR_HEAP_VADDR) / PAGE_SIZE]; |             return &new_linear_heap[(addr - NEW_LINEAR_HEAP_VADDR) / CITRA_PAGE_SIZE]; | ||||||
|         } |         } | ||||||
|         return nullptr; |         return nullptr; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     std::array<bool, VRAM_SIZE / PAGE_SIZE> vram{}; |     std::array<bool, VRAM_SIZE / CITRA_PAGE_SIZE> vram{}; | ||||||
|     std::array<bool, LINEAR_HEAP_SIZE / PAGE_SIZE> linear_heap{}; |     std::array<bool, LINEAR_HEAP_SIZE / CITRA_PAGE_SIZE> linear_heap{}; | ||||||
|     std::array<bool, NEW_LINEAR_HEAP_SIZE / PAGE_SIZE> new_linear_heap{}; |     std::array<bool, NEW_LINEAR_HEAP_SIZE / CITRA_PAGE_SIZE> new_linear_heap{}; | ||||||
| 
 | 
 | ||||||
|     static_assert(sizeof(bool) == 1); |     static_assert(sizeof(bool) == 1); | ||||||
|     friend class boost::serialization::access; |     friend class boost::serialization::access; | ||||||
|  | @ -146,6 +146,145 @@ public: | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /**
 | ||||||
|  |      * This function should only be called for virtual addreses with attribute `PageType::Special`. | ||||||
|  |      */ | ||||||
|  |     MMIORegionPointer GetMMIOHandler(const PageTable& page_table, VAddr vaddr) { | ||||||
|  |         for (const auto& region : page_table.special_regions) { | ||||||
|  |             if (vaddr >= region.base && vaddr < (region.base + region.size)) { | ||||||
|  |                 return region.handler; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         ASSERT_MSG(false, "Mapped IO page without a handler @ {:08X}", vaddr); | ||||||
|  |         return nullptr; // Should never happen
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     template <bool UNSAFE> | ||||||
|  |     void ReadBlockImpl(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer, | ||||||
|  |                        const std::size_t size) { | ||||||
|  |         auto& page_table = *process.vm_manager.page_table; | ||||||
|  | 
 | ||||||
|  |         std::size_t remaining_size = size; | ||||||
|  |         std::size_t page_index = src_addr >> CITRA_PAGE_BITS; | ||||||
|  |         std::size_t page_offset = src_addr & CITRA_PAGE_MASK; | ||||||
|  | 
 | ||||||
|  |         while (remaining_size > 0) { | ||||||
|  |             const std::size_t copy_amount = std::min(CITRA_PAGE_SIZE - page_offset, remaining_size); | ||||||
|  |             const VAddr current_vaddr = | ||||||
|  |                 static_cast<VAddr>((page_index << CITRA_PAGE_BITS) + page_offset); | ||||||
|  | 
 | ||||||
|  |             switch (page_table.attributes[page_index]) { | ||||||
|  |             case PageType::Unmapped: { | ||||||
|  |                 LOG_ERROR( | ||||||
|  |                     HW_Memory, | ||||||
|  |                     "unmapped ReadBlock @ 0x{:08X} (start address = 0x{:08X}, size = {}) at PC " | ||||||
|  |                     "0x{:08X}", | ||||||
|  |                     current_vaddr, src_addr, size, Core::GetRunningCore().GetPC()); | ||||||
|  |                 std::memset(dest_buffer, 0, copy_amount); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             case PageType::Memory: { | ||||||
|  |                 DEBUG_ASSERT(page_table.pointers[page_index]); | ||||||
|  | 
 | ||||||
|  |                 const u8* src_ptr = page_table.pointers[page_index] + page_offset; | ||||||
|  |                 std::memcpy(dest_buffer, src_ptr, copy_amount); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             case PageType::Special: { | ||||||
|  |                 MMIORegionPointer handler = GetMMIOHandler(page_table, current_vaddr); | ||||||
|  |                 DEBUG_ASSERT(handler); | ||||||
|  |                 handler->ReadBlock(current_vaddr, dest_buffer, copy_amount); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             case PageType::RasterizerCachedMemory: { | ||||||
|  |                 if constexpr (!UNSAFE) { | ||||||
|  |                     RasterizerFlushVirtualRegion(current_vaddr, static_cast<u32>(copy_amount), | ||||||
|  |                                                  FlushMode::Flush); | ||||||
|  |                 } | ||||||
|  |                 std::memcpy(dest_buffer, GetPointerForRasterizerCache(current_vaddr), copy_amount); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             default: | ||||||
|  |                 UNREACHABLE(); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             page_index++; | ||||||
|  |             page_offset = 0; | ||||||
|  |             dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount; | ||||||
|  |             remaining_size -= copy_amount; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     template <bool UNSAFE> | ||||||
|  |     void WriteBlockImpl(const Kernel::Process& process, const VAddr dest_addr, | ||||||
|  |                         const void* src_buffer, const std::size_t size) { | ||||||
|  |         auto& page_table = *process.vm_manager.page_table; | ||||||
|  |         std::size_t remaining_size = size; | ||||||
|  |         std::size_t page_index = dest_addr >> CITRA_PAGE_BITS; | ||||||
|  |         std::size_t page_offset = dest_addr & CITRA_PAGE_MASK; | ||||||
|  | 
 | ||||||
|  |         while (remaining_size > 0) { | ||||||
|  |             const std::size_t copy_amount = std::min(CITRA_PAGE_SIZE - page_offset, remaining_size); | ||||||
|  |             const VAddr current_vaddr = | ||||||
|  |                 static_cast<VAddr>((page_index << CITRA_PAGE_BITS) + page_offset); | ||||||
|  | 
 | ||||||
|  |             switch (page_table.attributes[page_index]) { | ||||||
|  |             case PageType::Unmapped: { | ||||||
|  |                 LOG_ERROR( | ||||||
|  |                     HW_Memory, | ||||||
|  |                     "unmapped WriteBlock @ 0x{:08X} (start address = 0x{:08X}, size = {}) at PC " | ||||||
|  |                     "0x{:08X}", | ||||||
|  |                     current_vaddr, dest_addr, size, Core::GetRunningCore().GetPC()); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             case PageType::Memory: { | ||||||
|  |                 DEBUG_ASSERT(page_table.pointers[page_index]); | ||||||
|  | 
 | ||||||
|  |                 u8* dest_ptr = page_table.pointers[page_index] + page_offset; | ||||||
|  |                 std::memcpy(dest_ptr, src_buffer, copy_amount); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             case PageType::Special: { | ||||||
|  |                 MMIORegionPointer handler = GetMMIOHandler(page_table, current_vaddr); | ||||||
|  |                 DEBUG_ASSERT(handler); | ||||||
|  |                 handler->WriteBlock(current_vaddr, src_buffer, copy_amount); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             case PageType::RasterizerCachedMemory: { | ||||||
|  |                 if constexpr (!UNSAFE) { | ||||||
|  |                     RasterizerFlushVirtualRegion(current_vaddr, static_cast<u32>(copy_amount), | ||||||
|  |                                                  FlushMode::Invalidate); | ||||||
|  |                 } | ||||||
|  |                 std::memcpy(GetPointerForRasterizerCache(current_vaddr), src_buffer, copy_amount); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             default: | ||||||
|  |                 UNREACHABLE(); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             page_index++; | ||||||
|  |             page_offset = 0; | ||||||
|  |             src_buffer = static_cast<const u8*>(src_buffer) + copy_amount; | ||||||
|  |             remaining_size -= copy_amount; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     MemoryRef GetPointerForRasterizerCache(VAddr addr) const { | ||||||
|  |         if (addr >= LINEAR_HEAP_VADDR && addr < LINEAR_HEAP_VADDR_END) { | ||||||
|  |             return {fcram_mem, addr - LINEAR_HEAP_VADDR}; | ||||||
|  |         } | ||||||
|  |         if (addr >= NEW_LINEAR_HEAP_VADDR && addr < NEW_LINEAR_HEAP_VADDR_END) { | ||||||
|  |             return {fcram_mem, addr - NEW_LINEAR_HEAP_VADDR}; | ||||||
|  |         } | ||||||
|  |         if (addr >= VRAM_VADDR && addr < VRAM_VADDR_END) { | ||||||
|  |             return {vram_mem, addr - VRAM_VADDR}; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         UNREACHABLE(); | ||||||
|  |         return MemoryRef{}; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     friend class boost::serialization::access; |     friend class boost::serialization::access; | ||||||
|     template <class Archive> |     template <class Archive> | ||||||
|  | @ -221,10 +360,10 @@ std::shared_ptr<PageTable> MemorySystem::GetCurrentPageTable() const { | ||||||
| 
 | 
 | ||||||
| void MemorySystem::MapPages(PageTable& page_table, u32 base, u32 size, MemoryRef memory, | void MemorySystem::MapPages(PageTable& page_table, u32 base, u32 size, MemoryRef memory, | ||||||
|                             PageType type) { |                             PageType type) { | ||||||
|     LOG_DEBUG(HW_Memory, "Mapping {} onto {:08X}-{:08X}", (void*)memory.GetPtr(), base * PAGE_SIZE, |     LOG_DEBUG(HW_Memory, "Mapping {} onto {:08X}-{:08X}", (void*)memory.GetPtr(), | ||||||
|               (base + size) * PAGE_SIZE); |               base * CITRA_PAGE_SIZE, (base + size) * CITRA_PAGE_SIZE); | ||||||
| 
 | 
 | ||||||
|     RasterizerFlushVirtualRegion(base << PAGE_BITS, size * PAGE_SIZE, |     RasterizerFlushVirtualRegion(base << CITRA_PAGE_BITS, size * CITRA_PAGE_SIZE, | ||||||
|                                  FlushMode::FlushAndInvalidate); |                                  FlushMode::FlushAndInvalidate); | ||||||
| 
 | 
 | ||||||
|     u32 end = base + size; |     u32 end = base + size; | ||||||
|  | @ -235,49 +374,42 @@ void MemorySystem::MapPages(PageTable& page_table, u32 base, u32 size, MemoryRef | ||||||
|         page_table.pointers[base] = memory; |         page_table.pointers[base] = memory; | ||||||
| 
 | 
 | ||||||
|         // If the memory to map is already rasterizer-cached, mark the page
 |         // If the memory to map is already rasterizer-cached, mark the page
 | ||||||
|         if (type == PageType::Memory && impl->cache_marker.IsCached(base * PAGE_SIZE)) { |         if (type == PageType::Memory && impl->cache_marker.IsCached(base * CITRA_PAGE_SIZE)) { | ||||||
|             page_table.attributes[base] = PageType::RasterizerCachedMemory; |             page_table.attributes[base] = PageType::RasterizerCachedMemory; | ||||||
|             page_table.pointers[base] = nullptr; |             page_table.pointers[base] = nullptr; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         base += 1; |         base += 1; | ||||||
|         if (memory != nullptr && memory.GetSize() > PAGE_SIZE) |         if (memory != nullptr && memory.GetSize() > CITRA_PAGE_SIZE) | ||||||
|             memory += PAGE_SIZE; |             memory += CITRA_PAGE_SIZE; | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void MemorySystem::MapMemoryRegion(PageTable& page_table, VAddr base, u32 size, MemoryRef target) { | void MemorySystem::MapMemoryRegion(PageTable& page_table, VAddr base, u32 size, MemoryRef target) { | ||||||
|     ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:08X}", size); |     ASSERT_MSG((size & CITRA_PAGE_MASK) == 0, "non-page aligned size: {:08X}", size); | ||||||
|     ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:08X}", base); |     ASSERT_MSG((base & CITRA_PAGE_MASK) == 0, "non-page aligned base: {:08X}", base); | ||||||
|     MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, target, PageType::Memory); |     MapPages(page_table, base / CITRA_PAGE_SIZE, size / CITRA_PAGE_SIZE, target, PageType::Memory); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void MemorySystem::MapIoRegion(PageTable& page_table, VAddr base, u32 size, | void MemorySystem::MapIoRegion(PageTable& page_table, VAddr base, u32 size, | ||||||
|                                MMIORegionPointer mmio_handler) { |                                MMIORegionPointer mmio_handler) { | ||||||
|     ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:08X}", size); |     ASSERT_MSG((size & CITRA_PAGE_MASK) == 0, "non-page aligned size: {:08X}", size); | ||||||
|     ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:08X}", base); |     ASSERT_MSG((base & CITRA_PAGE_MASK) == 0, "non-page aligned base: {:08X}", base); | ||||||
|     MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Special); |     MapPages(page_table, base / CITRA_PAGE_SIZE, size / CITRA_PAGE_SIZE, nullptr, | ||||||
|  |              PageType::Special); | ||||||
| 
 | 
 | ||||||
|     page_table.special_regions.emplace_back(SpecialRegion{base, size, mmio_handler}); |     page_table.special_regions.emplace_back(SpecialRegion{base, size, mmio_handler}); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void MemorySystem::UnmapRegion(PageTable& page_table, VAddr base, u32 size) { | void MemorySystem::UnmapRegion(PageTable& page_table, VAddr base, u32 size) { | ||||||
|     ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:08X}", size); |     ASSERT_MSG((size & CITRA_PAGE_MASK) == 0, "non-page aligned size: {:08X}", size); | ||||||
|     ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:08X}", base); |     ASSERT_MSG((base & CITRA_PAGE_MASK) == 0, "non-page aligned base: {:08X}", base); | ||||||
|     MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Unmapped); |     MapPages(page_table, base / CITRA_PAGE_SIZE, size / CITRA_PAGE_SIZE, nullptr, | ||||||
|  |              PageType::Unmapped); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| MemoryRef MemorySystem::GetPointerForRasterizerCache(VAddr addr) const { | MemoryRef MemorySystem::GetPointerForRasterizerCache(VAddr addr) const { | ||||||
|     if (addr >= LINEAR_HEAP_VADDR && addr < LINEAR_HEAP_VADDR_END) { |     return impl->GetPointerForRasterizerCache(addr); | ||||||
|         return {impl->fcram_mem, addr - LINEAR_HEAP_VADDR}; |  | ||||||
|     } |  | ||||||
|     if (addr >= NEW_LINEAR_HEAP_VADDR && addr < NEW_LINEAR_HEAP_VADDR_END) { |  | ||||||
|         return {impl->fcram_mem, addr - NEW_LINEAR_HEAP_VADDR}; |  | ||||||
|     } |  | ||||||
|     if (addr >= VRAM_VADDR && addr < VRAM_VADDR_END) { |  | ||||||
|         return {impl->vram_mem, addr - VRAM_VADDR}; |  | ||||||
|     } |  | ||||||
|     UNREACHABLE(); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void MemorySystem::RegisterPageTable(std::shared_ptr<PageTable> page_table) { | void MemorySystem::RegisterPageTable(std::shared_ptr<PageTable> page_table) { | ||||||
|  | @ -291,33 +423,20 @@ void MemorySystem::UnregisterPageTable(std::shared_ptr<PageTable> page_table) { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 |  | ||||||
|  * This function should only be called for virtual addreses with attribute `PageType::Special`. |  | ||||||
|  */ |  | ||||||
| static MMIORegionPointer GetMMIOHandler(const PageTable& page_table, VAddr vaddr) { |  | ||||||
|     for (const auto& region : page_table.special_regions) { |  | ||||||
|         if (vaddr >= region.base && vaddr < (region.base + region.size)) { |  | ||||||
|             return region.handler; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     ASSERT_MSG(false, "Mapped IO page without a handler @ {:08X}", vaddr); |  | ||||||
|     return nullptr; // Should never happen
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template <typename T> | template <typename T> | ||||||
| T ReadMMIO(MMIORegionPointer mmio_handler, VAddr addr); | T ReadMMIO(MMIORegionPointer mmio_handler, VAddr addr); | ||||||
| 
 | 
 | ||||||
| template <typename T> | template <typename T> | ||||||
| T MemorySystem::Read(const VAddr vaddr) { | T MemorySystem::Read(const VAddr vaddr) { | ||||||
|     const u8* page_pointer = impl->current_page_table->pointers[vaddr >> PAGE_BITS]; |     const u8* page_pointer = impl->current_page_table->pointers[vaddr >> CITRA_PAGE_BITS]; | ||||||
|     if (page_pointer) { |     if (page_pointer) { | ||||||
|         // NOTE: Avoid adding any extra logic to this fast-path block
 |         // NOTE: Avoid adding any extra logic to this fast-path block
 | ||||||
|         T value; |         T value; | ||||||
|         std::memcpy(&value, &page_pointer[vaddr & PAGE_MASK], sizeof(T)); |         std::memcpy(&value, &page_pointer[vaddr & CITRA_PAGE_MASK], sizeof(T)); | ||||||
|         return value; |         return value; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     PageType type = impl->current_page_table->attributes[vaddr >> PAGE_BITS]; |     PageType type = impl->current_page_table->attributes[vaddr >> CITRA_PAGE_BITS]; | ||||||
|     switch (type) { |     switch (type) { | ||||||
|     case PageType::Unmapped: |     case PageType::Unmapped: | ||||||
|         LOG_ERROR(HW_Memory, "unmapped Read{} @ 0x{:08X} at PC 0x{:08X}", sizeof(T) * 8, vaddr, |         LOG_ERROR(HW_Memory, "unmapped Read{} @ 0x{:08X} at PC 0x{:08X}", sizeof(T) * 8, vaddr, | ||||||
|  | @ -334,10 +453,12 @@ T MemorySystem::Read(const VAddr vaddr) { | ||||||
|         return value; |         return value; | ||||||
|     } |     } | ||||||
|     case PageType::Special: |     case PageType::Special: | ||||||
|         return ReadMMIO<T>(GetMMIOHandler(*impl->current_page_table, vaddr), vaddr); |         return ReadMMIO<T>(impl->GetMMIOHandler(*impl->current_page_table, vaddr), vaddr); | ||||||
|     default: |     default: | ||||||
|         UNREACHABLE(); |         UNREACHABLE(); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     return T{}; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template <typename T> | template <typename T> | ||||||
|  | @ -345,14 +466,14 @@ void WriteMMIO(MMIORegionPointer mmio_handler, VAddr addr, const T data); | ||||||
| 
 | 
 | ||||||
| template <typename T> | template <typename T> | ||||||
| void MemorySystem::Write(const VAddr vaddr, const T data) { | void MemorySystem::Write(const VAddr vaddr, const T data) { | ||||||
|     u8* page_pointer = impl->current_page_table->pointers[vaddr >> PAGE_BITS]; |     u8* page_pointer = impl->current_page_table->pointers[vaddr >> CITRA_PAGE_BITS]; | ||||||
|     if (page_pointer) { |     if (page_pointer) { | ||||||
|         // NOTE: Avoid adding any extra logic to this fast-path block
 |         // NOTE: Avoid adding any extra logic to this fast-path block
 | ||||||
|         std::memcpy(&page_pointer[vaddr & PAGE_MASK], &data, sizeof(T)); |         std::memcpy(&page_pointer[vaddr & CITRA_PAGE_MASK], &data, sizeof(T)); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     PageType type = impl->current_page_table->attributes[vaddr >> PAGE_BITS]; |     PageType type = impl->current_page_table->attributes[vaddr >> CITRA_PAGE_BITS]; | ||||||
|     switch (type) { |     switch (type) { | ||||||
|     case PageType::Unmapped: |     case PageType::Unmapped: | ||||||
|         LOG_ERROR(HW_Memory, "unmapped Write{} 0x{:08X} @ 0x{:08X} at PC 0x{:08X}", |         LOG_ERROR(HW_Memory, "unmapped Write{} 0x{:08X} @ 0x{:08X} at PC 0x{:08X}", | ||||||
|  | @ -367,7 +488,7 @@ void MemorySystem::Write(const VAddr vaddr, const T data) { | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     case PageType::Special: |     case PageType::Special: | ||||||
|         WriteMMIO<T>(GetMMIOHandler(*impl->current_page_table, vaddr), vaddr, data); |         WriteMMIO<T>(impl->GetMMIOHandler(*impl->current_page_table, vaddr), vaddr, data); | ||||||
|         break; |         break; | ||||||
|     default: |     default: | ||||||
|         UNREACHABLE(); |         UNREACHABLE(); | ||||||
|  | @ -376,15 +497,15 @@ void MemorySystem::Write(const VAddr vaddr, const T data) { | ||||||
| 
 | 
 | ||||||
| template <typename T> | template <typename T> | ||||||
| bool MemorySystem::WriteExclusive(const VAddr vaddr, const T data, const T expected) { | bool MemorySystem::WriteExclusive(const VAddr vaddr, const T data, const T expected) { | ||||||
|     u8* page_pointer = impl->current_page_table->pointers[vaddr >> PAGE_BITS]; |     u8* page_pointer = impl->current_page_table->pointers[vaddr >> CITRA_PAGE_BITS]; | ||||||
| 
 | 
 | ||||||
|     if (page_pointer) { |     if (page_pointer) { | ||||||
|         const auto volatile_pointer = |         const auto volatile_pointer = | ||||||
|             reinterpret_cast<volatile T*>(&page_pointer[vaddr & PAGE_MASK]); |             reinterpret_cast<volatile T*>(&page_pointer[vaddr & CITRA_PAGE_MASK]); | ||||||
|         return Common::AtomicCompareAndSwap(volatile_pointer, data, expected); |         return Common::AtomicCompareAndSwap(volatile_pointer, data, expected); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     PageType type = impl->current_page_table->attributes[vaddr >> PAGE_BITS]; |     PageType type = impl->current_page_table->attributes[vaddr >> CITRA_PAGE_BITS]; | ||||||
|     switch (type) { |     switch (type) { | ||||||
|     case PageType::Unmapped: |     case PageType::Unmapped: | ||||||
|         LOG_ERROR(HW_Memory, "unmapped Write{} 0x{:08X} @ 0x{:08X} at PC 0x{:08X}", |         LOG_ERROR(HW_Memory, "unmapped Write{} 0x{:08X} @ 0x{:08X} at PC 0x{:08X}", | ||||||
|  | @ -400,7 +521,7 @@ bool MemorySystem::WriteExclusive(const VAddr vaddr, const T data, const T expec | ||||||
|         return Common::AtomicCompareAndSwap(volatile_pointer, data, expected); |         return Common::AtomicCompareAndSwap(volatile_pointer, data, expected); | ||||||
|     } |     } | ||||||
|     case PageType::Special: |     case PageType::Special: | ||||||
|         WriteMMIO<T>(GetMMIOHandler(*impl->current_page_table, vaddr), vaddr, data); |         WriteMMIO<T>(impl->GetMMIOHandler(*impl->current_page_table, vaddr), vaddr, data); | ||||||
|         return false; |         return false; | ||||||
|     default: |     default: | ||||||
|         UNREACHABLE(); |         UNREACHABLE(); | ||||||
|  | @ -408,20 +529,20 @@ bool MemorySystem::WriteExclusive(const VAddr vaddr, const T data, const T expec | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) { | bool MemorySystem::IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) { | ||||||
|     auto& page_table = *process.vm_manager.page_table; |     auto& page_table = *process.vm_manager.page_table; | ||||||
| 
 | 
 | ||||||
|     auto page_pointer = page_table.pointers[vaddr >> PAGE_BITS]; |     auto page_pointer = page_table.pointers[vaddr >> CITRA_PAGE_BITS]; | ||||||
|     if (page_pointer) |     if (page_pointer) | ||||||
|         return true; |         return true; | ||||||
| 
 | 
 | ||||||
|     if (page_table.attributes[vaddr >> PAGE_BITS] == PageType::RasterizerCachedMemory) |     if (page_table.attributes[vaddr >> CITRA_PAGE_BITS] == PageType::RasterizerCachedMemory) | ||||||
|         return true; |         return true; | ||||||
| 
 | 
 | ||||||
|     if (page_table.attributes[vaddr >> PAGE_BITS] != PageType::Special) |     if (page_table.attributes[vaddr >> CITRA_PAGE_BITS] != PageType::Special) | ||||||
|         return false; |         return false; | ||||||
| 
 | 
 | ||||||
|     MMIORegionPointer mmio_region = GetMMIOHandler(page_table, vaddr); |     MMIORegionPointer mmio_region = impl->GetMMIOHandler(page_table, vaddr); | ||||||
|     if (mmio_region) { |     if (mmio_region) { | ||||||
|         return mmio_region->IsValidAddress(vaddr); |         return mmio_region->IsValidAddress(vaddr); | ||||||
|     } |     } | ||||||
|  | @ -430,16 +551,16 @@ bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool MemorySystem::IsValidPhysicalAddress(const PAddr paddr) const { | bool MemorySystem::IsValidPhysicalAddress(const PAddr paddr) const { | ||||||
|     return GetPhysicalPointer(paddr) != nullptr; |     return GetPhysicalRef(paddr); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| u8* MemorySystem::GetPointer(const VAddr vaddr) { | u8* MemorySystem::GetPointer(const VAddr vaddr) { | ||||||
|     u8* page_pointer = impl->current_page_table->pointers[vaddr >> PAGE_BITS]; |     u8* page_pointer = impl->current_page_table->pointers[vaddr >> CITRA_PAGE_BITS]; | ||||||
|     if (page_pointer) { |     if (page_pointer) { | ||||||
|         return page_pointer + (vaddr & PAGE_MASK); |         return page_pointer + (vaddr & CITRA_PAGE_MASK); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (impl->current_page_table->attributes[vaddr >> PAGE_BITS] == |     if (impl->current_page_table->attributes[vaddr >> CITRA_PAGE_BITS] == | ||||||
|         PageType::RasterizerCachedMemory) { |         PageType::RasterizerCachedMemory) { | ||||||
|         return GetPointerForRasterizerCache(vaddr); |         return GetPointerForRasterizerCache(vaddr); | ||||||
|     } |     } | ||||||
|  | @ -450,12 +571,12 @@ u8* MemorySystem::GetPointer(const VAddr vaddr) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const u8* MemorySystem::GetPointer(const VAddr vaddr) const { | const u8* MemorySystem::GetPointer(const VAddr vaddr) const { | ||||||
|     const u8* page_pointer = impl->current_page_table->pointers[vaddr >> PAGE_BITS]; |     const u8* page_pointer = impl->current_page_table->pointers[vaddr >> CITRA_PAGE_BITS]; | ||||||
|     if (page_pointer) { |     if (page_pointer) { | ||||||
|         return page_pointer + (vaddr & PAGE_MASK); |         return page_pointer + (vaddr & CITRA_PAGE_MASK); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (impl->current_page_table->attributes[vaddr >> PAGE_BITS] == |     if (impl->current_page_table->attributes[vaddr >> CITRA_PAGE_BITS] == | ||||||
|         PageType::RasterizerCachedMemory) { |         PageType::RasterizerCachedMemory) { | ||||||
|         return GetPointerForRasterizerCache(vaddr); |         return GetPointerForRasterizerCache(vaddr); | ||||||
|     } |     } | ||||||
|  | @ -469,11 +590,14 @@ std::string MemorySystem::ReadCString(VAddr vaddr, std::size_t max_length) { | ||||||
|     string.reserve(max_length); |     string.reserve(max_length); | ||||||
|     for (std::size_t i = 0; i < max_length; ++i) { |     for (std::size_t i = 0; i < max_length; ++i) { | ||||||
|         char c = Read8(vaddr); |         char c = Read8(vaddr); | ||||||
|         if (c == '\0') |         if (c == '\0') { | ||||||
|             break; |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         string.push_back(c); |         string.push_back(c); | ||||||
|         ++vaddr; |         ++vaddr; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     string.shrink_to_fit(); |     string.shrink_to_fit(); | ||||||
|     return string; |     return string; | ||||||
| } | } | ||||||
|  | @ -482,40 +606,30 @@ u8* MemorySystem::GetPhysicalPointer(PAddr address) { | ||||||
|     return GetPhysicalRef(address); |     return GetPhysicalRef(address); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const u8* MemorySystem::GetPhysicalPointer(PAddr address) const { |  | ||||||
|     return GetPhysicalRef(address); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| MemoryRef MemorySystem::GetPhysicalRef(PAddr address) const { | MemoryRef MemorySystem::GetPhysicalRef(PAddr address) const { | ||||||
|     struct MemoryArea { |     constexpr std::array memory_areas = { | ||||||
|         PAddr paddr_base; |         std::make_pair(VRAM_PADDR, VRAM_SIZE), | ||||||
|         u32 size; |         std::make_pair(DSP_RAM_PADDR, DSP_RAM_SIZE), | ||||||
|  |         std::make_pair(FCRAM_PADDR, FCRAM_N3DS_SIZE), | ||||||
|  |         std::make_pair(N3DS_EXTRA_RAM_PADDR, N3DS_EXTRA_RAM_SIZE), | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     static constexpr MemoryArea memory_areas[] = { |     const auto area = std::find_if(memory_areas.begin(), memory_areas.end(), [&](const auto& area) { | ||||||
|         {VRAM_PADDR, VRAM_SIZE}, |  | ||||||
|         {DSP_RAM_PADDR, DSP_RAM_SIZE}, |  | ||||||
|         {FCRAM_PADDR, FCRAM_N3DS_SIZE}, |  | ||||||
|         {N3DS_EXTRA_RAM_PADDR, N3DS_EXTRA_RAM_SIZE}, |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     const auto area = |  | ||||||
|         std::find_if(std::begin(memory_areas), std::end(memory_areas), [&](const auto& area) { |  | ||||||
|         // Note: the region end check is inclusive because the user can pass in an address that
 |         // Note: the region end check is inclusive because the user can pass in an address that
 | ||||||
|         // represents an open right bound
 |         // represents an open right bound
 | ||||||
|             return address >= area.paddr_base && address <= area.paddr_base + area.size; |         return address >= area.first && address <= area.first + area.second; | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     if (area == std::end(memory_areas)) { |     if (area == memory_areas.end()) { | ||||||
|         LOG_ERROR(HW_Memory, "unknown GetPhysicalPointer @ 0x{:08X} at PC 0x{:08X}", address, |         LOG_ERROR(HW_Memory, "Unknown GetPhysicalPointer @ {:#08X} at PC {:#08X}", address, | ||||||
|                   Core::GetRunningCore().GetPC()); |                   Core::GetRunningCore().GetPC()); | ||||||
|         return nullptr; |         return nullptr; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     u32 offset_into_region = address - area->paddr_base; |     u32 offset_into_region = address - area->first; | ||||||
| 
 | 
 | ||||||
|     std::shared_ptr<BackingMem> target_mem = nullptr; |     std::shared_ptr<BackingMem> target_mem = nullptr; | ||||||
|     switch (area->paddr_base) { |     switch (area->first) { | ||||||
|     case VRAM_PADDR: |     case VRAM_PADDR: | ||||||
|         target_mem = impl->vram_mem; |         target_mem = impl->vram_mem; | ||||||
|         break; |         break; | ||||||
|  | @ -564,14 +678,14 @@ void MemorySystem::RasterizerMarkRegionCached(PAddr start, u32 size, bool cached | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     u32 num_pages = ((start + size - 1) >> PAGE_BITS) - (start >> PAGE_BITS) + 1; |     u32 num_pages = ((start + size - 1) >> CITRA_PAGE_BITS) - (start >> CITRA_PAGE_BITS) + 1; | ||||||
|     PAddr paddr = start; |     PAddr paddr = start; | ||||||
| 
 | 
 | ||||||
|     for (unsigned i = 0; i < num_pages; ++i, paddr += PAGE_SIZE) { |     for (unsigned i = 0; i < num_pages; ++i, paddr += CITRA_PAGE_SIZE) { | ||||||
|         for (VAddr vaddr : PhysicalToVirtualAddressForRasterizer(paddr)) { |         for (VAddr vaddr : PhysicalToVirtualAddressForRasterizer(paddr)) { | ||||||
|             impl->cache_marker.Mark(vaddr, cached); |             impl->cache_marker.Mark(vaddr, cached); | ||||||
|             for (auto page_table : impl->page_table_list) { |             for (auto page_table : impl->page_table_list) { | ||||||
|                 PageType& page_type = page_table->attributes[vaddr >> PAGE_BITS]; |                 PageType& page_type = page_table->attributes[vaddr >> CITRA_PAGE_BITS]; | ||||||
| 
 | 
 | ||||||
|                 if (cached) { |                 if (cached) { | ||||||
|                     // Switch page type to cached if now cached
 |                     // Switch page type to cached if now cached
 | ||||||
|  | @ -582,7 +696,7 @@ void MemorySystem::RasterizerMarkRegionCached(PAddr start, u32 size, bool cached | ||||||
|                         break; |                         break; | ||||||
|                     case PageType::Memory: |                     case PageType::Memory: | ||||||
|                         page_type = PageType::RasterizerCachedMemory; |                         page_type = PageType::RasterizerCachedMemory; | ||||||
|                         page_table->pointers[vaddr >> PAGE_BITS] = nullptr; |                         page_table->pointers[vaddr >> CITRA_PAGE_BITS] = nullptr; | ||||||
|                         break; |                         break; | ||||||
|                     default: |                     default: | ||||||
|                         UNREACHABLE(); |                         UNREACHABLE(); | ||||||
|  | @ -596,8 +710,8 @@ void MemorySystem::RasterizerMarkRegionCached(PAddr start, u32 size, bool cached | ||||||
|                         break; |                         break; | ||||||
|                     case PageType::RasterizerCachedMemory: { |                     case PageType::RasterizerCachedMemory: { | ||||||
|                         page_type = PageType::Memory; |                         page_type = PageType::Memory; | ||||||
|                         page_table->pointers[vaddr >> PAGE_BITS] = |                         page_table->pointers[vaddr >> CITRA_PAGE_BITS] = | ||||||
|                             GetPointerForRasterizerCache(vaddr & ~PAGE_MASK); |                             GetPointerForRasterizerCache(vaddr & ~CITRA_PAGE_MASK); | ||||||
|                         break; |                         break; | ||||||
|                     } |                     } | ||||||
|                     default: |                     default: | ||||||
|  | @ -702,53 +816,12 @@ u64 MemorySystem::Read64(const VAddr addr) { | ||||||
| 
 | 
 | ||||||
| void MemorySystem::ReadBlock(const Kernel::Process& process, const VAddr src_addr, | void MemorySystem::ReadBlock(const Kernel::Process& process, const VAddr src_addr, | ||||||
|                              void* dest_buffer, const std::size_t size) { |                              void* dest_buffer, const std::size_t size) { | ||||||
|     auto& page_table = *process.vm_manager.page_table; |     return impl->ReadBlockImpl<false>(process, src_addr, dest_buffer, size); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
|     std::size_t remaining_size = size; | void MemorySystem::ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size) { | ||||||
|     std::size_t page_index = src_addr >> PAGE_BITS; |     const auto& process = *Core::System::GetInstance().Kernel().GetCurrentProcess(); | ||||||
|     std::size_t page_offset = src_addr & PAGE_MASK; |     return impl->ReadBlockImpl<false>(process, src_addr, dest_buffer, size); | ||||||
| 
 |  | ||||||
|     while (remaining_size > 0) { |  | ||||||
|         const std::size_t copy_amount = std::min(PAGE_SIZE - page_offset, remaining_size); |  | ||||||
|         const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); |  | ||||||
| 
 |  | ||||||
|         switch (page_table.attributes[page_index]) { |  | ||||||
|         case PageType::Unmapped: { |  | ||||||
|             LOG_ERROR(HW_Memory, |  | ||||||
|                       "unmapped ReadBlock @ 0x{:08X} (start address = 0x{:08X}, size = {}) at PC " |  | ||||||
|                       "0x{:08X}", |  | ||||||
|                       current_vaddr, src_addr, size, Core::GetRunningCore().GetPC()); |  | ||||||
|             std::memset(dest_buffer, 0, copy_amount); |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         case PageType::Memory: { |  | ||||||
|             DEBUG_ASSERT(page_table.pointers[page_index]); |  | ||||||
| 
 |  | ||||||
|             const u8* src_ptr = page_table.pointers[page_index] + page_offset; |  | ||||||
|             std::memcpy(dest_buffer, src_ptr, copy_amount); |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         case PageType::Special: { |  | ||||||
|             MMIORegionPointer handler = GetMMIOHandler(page_table, current_vaddr); |  | ||||||
|             DEBUG_ASSERT(handler); |  | ||||||
|             handler->ReadBlock(current_vaddr, dest_buffer, copy_amount); |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         case PageType::RasterizerCachedMemory: { |  | ||||||
|             RasterizerFlushVirtualRegion(current_vaddr, static_cast<u32>(copy_amount), |  | ||||||
|                                          FlushMode::Flush); |  | ||||||
|             std::memcpy(dest_buffer, GetPointerForRasterizerCache(current_vaddr), copy_amount); |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         default: |  | ||||||
|             UNREACHABLE(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         page_index++; |  | ||||||
|         page_offset = 0; |  | ||||||
|         dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount; |  | ||||||
|         remaining_size -= copy_amount; |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void MemorySystem::Write8(const VAddr addr, const u8 data) { | void MemorySystem::Write8(const VAddr addr, const u8 data) { | ||||||
|  | @ -785,65 +858,28 @@ bool MemorySystem::WriteExclusive64(const VAddr addr, const u64 data, const u64 | ||||||
| 
 | 
 | ||||||
| void MemorySystem::WriteBlock(const Kernel::Process& process, const VAddr dest_addr, | void MemorySystem::WriteBlock(const Kernel::Process& process, const VAddr dest_addr, | ||||||
|                               const void* src_buffer, const std::size_t size) { |                               const void* src_buffer, const std::size_t size) { | ||||||
|     auto& page_table = *process.vm_manager.page_table; |     return impl->WriteBlockImpl<false>(process, dest_addr, src_buffer, size); | ||||||
|     std::size_t remaining_size = size; | } | ||||||
|     std::size_t page_index = dest_addr >> PAGE_BITS; |  | ||||||
|     std::size_t page_offset = dest_addr & PAGE_MASK; |  | ||||||
| 
 | 
 | ||||||
|     while (remaining_size > 0) { | void MemorySystem::WriteBlock(const VAddr dest_addr, const void* src_buffer, | ||||||
|         const std::size_t copy_amount = std::min(PAGE_SIZE - page_offset, remaining_size); |                               const std::size_t size) { | ||||||
|         const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); |     auto& process = *Core::System::GetInstance().Kernel().GetCurrentProcess(); | ||||||
| 
 |     return impl->WriteBlockImpl<false>(process, dest_addr, src_buffer, size); | ||||||
|         switch (page_table.attributes[page_index]) { |  | ||||||
|         case PageType::Unmapped: { |  | ||||||
|             LOG_ERROR(HW_Memory, |  | ||||||
|                       "unmapped WriteBlock @ 0x{:08X} (start address = 0x{:08X}, size = {}) at PC " |  | ||||||
|                       "0x{:08X}", |  | ||||||
|                       current_vaddr, dest_addr, size, Core::GetRunningCore().GetPC()); |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         case PageType::Memory: { |  | ||||||
|             DEBUG_ASSERT(page_table.pointers[page_index]); |  | ||||||
| 
 |  | ||||||
|             u8* dest_ptr = page_table.pointers[page_index] + page_offset; |  | ||||||
|             std::memcpy(dest_ptr, src_buffer, copy_amount); |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         case PageType::Special: { |  | ||||||
|             MMIORegionPointer handler = GetMMIOHandler(page_table, current_vaddr); |  | ||||||
|             DEBUG_ASSERT(handler); |  | ||||||
|             handler->WriteBlock(current_vaddr, src_buffer, copy_amount); |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         case PageType::RasterizerCachedMemory: { |  | ||||||
|             RasterizerFlushVirtualRegion(current_vaddr, static_cast<u32>(copy_amount), |  | ||||||
|                                          FlushMode::Invalidate); |  | ||||||
|             std::memcpy(GetPointerForRasterizerCache(current_vaddr), src_buffer, copy_amount); |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         default: |  | ||||||
|             UNREACHABLE(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         page_index++; |  | ||||||
|         page_offset = 0; |  | ||||||
|         src_buffer = static_cast<const u8*>(src_buffer) + copy_amount; |  | ||||||
|         remaining_size -= copy_amount; |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void MemorySystem::ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, | void MemorySystem::ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, | ||||||
|                              const std::size_t size) { |                              const std::size_t size) { | ||||||
|     auto& page_table = *process.vm_manager.page_table; |     auto& page_table = *process.vm_manager.page_table; | ||||||
|     std::size_t remaining_size = size; |     std::size_t remaining_size = size; | ||||||
|     std::size_t page_index = dest_addr >> PAGE_BITS; |     std::size_t page_index = dest_addr >> CITRA_PAGE_BITS; | ||||||
|     std::size_t page_offset = dest_addr & PAGE_MASK; |     std::size_t page_offset = dest_addr & CITRA_PAGE_MASK; | ||||||
| 
 | 
 | ||||||
|     static const std::array<u8, PAGE_SIZE> zeros = {}; |     static const std::array<u8, CITRA_PAGE_SIZE> zeros = {}; | ||||||
| 
 | 
 | ||||||
|     while (remaining_size > 0) { |     while (remaining_size > 0) { | ||||||
|         const std::size_t copy_amount = std::min(PAGE_SIZE - page_offset, remaining_size); |         const std::size_t copy_amount = std::min(CITRA_PAGE_SIZE - page_offset, remaining_size); | ||||||
|         const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); |         const VAddr current_vaddr = | ||||||
|  |             static_cast<VAddr>((page_index << CITRA_PAGE_BITS) + page_offset); | ||||||
| 
 | 
 | ||||||
|         switch (page_table.attributes[page_index]) { |         switch (page_table.attributes[page_index]) { | ||||||
|         case PageType::Unmapped: { |         case PageType::Unmapped: { | ||||||
|  | @ -861,7 +897,7 @@ void MemorySystem::ZeroBlock(const Kernel::Process& process, const VAddr dest_ad | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         case PageType::Special: { |         case PageType::Special: { | ||||||
|             MMIORegionPointer handler = GetMMIOHandler(page_table, current_vaddr); |             MMIORegionPointer handler = impl->GetMMIOHandler(page_table, current_vaddr); | ||||||
|             DEBUG_ASSERT(handler); |             DEBUG_ASSERT(handler); | ||||||
|             handler->WriteBlock(current_vaddr, zeros.data(), copy_amount); |             handler->WriteBlock(current_vaddr, zeros.data(), copy_amount); | ||||||
|             break; |             break; | ||||||
|  | @ -892,12 +928,13 @@ void MemorySystem::CopyBlock(const Kernel::Process& dest_process, | ||||||
|                              std::size_t size) { |                              std::size_t size) { | ||||||
|     auto& page_table = *src_process.vm_manager.page_table; |     auto& page_table = *src_process.vm_manager.page_table; | ||||||
|     std::size_t remaining_size = size; |     std::size_t remaining_size = size; | ||||||
|     std::size_t page_index = src_addr >> PAGE_BITS; |     std::size_t page_index = src_addr >> CITRA_PAGE_BITS; | ||||||
|     std::size_t page_offset = src_addr & PAGE_MASK; |     std::size_t page_offset = src_addr & CITRA_PAGE_MASK; | ||||||
| 
 | 
 | ||||||
|     while (remaining_size > 0) { |     while (remaining_size > 0) { | ||||||
|         const std::size_t copy_amount = std::min(PAGE_SIZE - page_offset, remaining_size); |         const std::size_t copy_amount = std::min(CITRA_PAGE_SIZE - page_offset, remaining_size); | ||||||
|         const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); |         const VAddr current_vaddr = | ||||||
|  |             static_cast<VAddr>((page_index << CITRA_PAGE_BITS) + page_offset); | ||||||
| 
 | 
 | ||||||
|         switch (page_table.attributes[page_index]) { |         switch (page_table.attributes[page_index]) { | ||||||
|         case PageType::Unmapped: { |         case PageType::Unmapped: { | ||||||
|  | @ -915,7 +952,7 @@ void MemorySystem::CopyBlock(const Kernel::Process& dest_process, | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         case PageType::Special: { |         case PageType::Special: { | ||||||
|             MMIORegionPointer handler = GetMMIOHandler(page_table, current_vaddr); |             MMIORegionPointer handler = impl->GetMMIOHandler(page_table, current_vaddr); | ||||||
|             DEBUG_ASSERT(handler); |             DEBUG_ASSERT(handler); | ||||||
|             std::vector<u8> buffer(copy_amount); |             std::vector<u8> buffer(copy_amount); | ||||||
|             handler->ReadBlock(current_vaddr, buffer.data(), buffer.size()); |             handler->ReadBlock(current_vaddr, buffer.data(), buffer.size()); | ||||||
|  |  | ||||||
|  | @ -3,12 +3,9 @@ | ||||||
| // Refer to the license.txt file included.
 | // Refer to the license.txt file included.
 | ||||||
| 
 | 
 | ||||||
| #pragma once | #pragma once | ||||||
| 
 |  | ||||||
| #include <array> | #include <array> | ||||||
| #include <cstddef> | #include <cstddef> | ||||||
| #include <memory> |  | ||||||
| #include <string> | #include <string> | ||||||
| #include <vector> |  | ||||||
| #include <boost/serialization/array.hpp> | #include <boost/serialization/array.hpp> | ||||||
| #include <boost/serialization/vector.hpp> | #include <boost/serialization/vector.hpp> | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
|  | @ -27,17 +24,14 @@ class DspInterface; | ||||||
| 
 | 
 | ||||||
| namespace Memory { | namespace Memory { | ||||||
| 
 | 
 | ||||||
| // Are defined in a system header
 |  | ||||||
| #undef PAGE_SIZE |  | ||||||
| #undef PAGE_MASK |  | ||||||
| /**
 | /**
 | ||||||
|  * Page size used by the ARM architecture. This is the smallest granularity with which memory can |  * Page size used by the ARM architecture. This is the smallest granularity with which memory can | ||||||
|  * be mapped. |  * be mapped. | ||||||
|  */ |  */ | ||||||
| const u32 PAGE_SIZE = 0x1000; | constexpr u32 CITRA_PAGE_SIZE = 0x1000; | ||||||
| const u32 PAGE_MASK = PAGE_SIZE - 1; | constexpr u32 CITRA_PAGE_MASK = CITRA_PAGE_SIZE - 1; | ||||||
| const int PAGE_BITS = 12; | constexpr int CITRA_PAGE_BITS = 12; | ||||||
| const std::size_t PAGE_TABLE_NUM_ENTRIES = 1 << (32 - PAGE_BITS); | constexpr std::size_t PAGE_TABLE_NUM_ENTRIES = 1 << (32 - CITRA_PAGE_BITS); | ||||||
| 
 | 
 | ||||||
| enum class PageType { | enum class PageType { | ||||||
|     /// Page is unmapped and should cause an access error.
 |     /// Page is unmapped and should cause an access error.
 | ||||||
|  | @ -106,11 +100,10 @@ struct PageTable { | ||||||
| 
 | 
 | ||||||
|     private: |     private: | ||||||
|         std::array<u8*, PAGE_TABLE_NUM_ENTRIES> raw; |         std::array<u8*, PAGE_TABLE_NUM_ENTRIES> raw; | ||||||
| 
 |  | ||||||
|         std::array<MemoryRef, PAGE_TABLE_NUM_ENTRIES> refs; |         std::array<MemoryRef, PAGE_TABLE_NUM_ENTRIES> refs; | ||||||
| 
 |  | ||||||
|         friend struct PageTable; |         friend struct PageTable; | ||||||
|     }; |     }; | ||||||
|  | 
 | ||||||
|     Pointers pointers; |     Pointers pointers; | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|  | @ -317,14 +310,108 @@ public: | ||||||
|     void SetCurrentPageTable(std::shared_ptr<PageTable> page_table); |     void SetCurrentPageTable(std::shared_ptr<PageTable> page_table); | ||||||
|     std::shared_ptr<PageTable> GetCurrentPageTable() const; |     std::shared_ptr<PageTable> GetCurrentPageTable() const; | ||||||
| 
 | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Gets a pointer to the given address. | ||||||
|  |      * | ||||||
|  |      * @param vaddr Virtual address to retrieve a pointer to. | ||||||
|  |      * | ||||||
|  |      * @returns The pointer to the given address, if the address is valid. | ||||||
|  |      *          If the address is not valid, nullptr will be returned. | ||||||
|  |      */ | ||||||
|  |     u8* GetPointer(VAddr vaddr); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Gets a pointer to the given address. | ||||||
|  |      * | ||||||
|  |      * @param vaddr Virtual address to retrieve a pointer to. | ||||||
|  |      * | ||||||
|  |      * @returns The pointer to the given address, if the address is valid. | ||||||
|  |      *          If the address is not valid, nullptr will be returned. | ||||||
|  |      */ | ||||||
|  |     const u8* GetPointer(VAddr vaddr) const; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Reads an 8-bit unsigned value from the current process' address space | ||||||
|  |      * at the given virtual address. | ||||||
|  |      * | ||||||
|  |      * @param addr The virtual address to read the 8-bit value from. | ||||||
|  |      * | ||||||
|  |      * @returns the read 8-bit unsigned value. | ||||||
|  |      */ | ||||||
|     u8 Read8(VAddr addr); |     u8 Read8(VAddr addr); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Reads a 16-bit unsigned value from the current process' address space | ||||||
|  |      * at the given virtual address. | ||||||
|  |      * | ||||||
|  |      * @param addr The virtual address to read the 16-bit value from. | ||||||
|  |      * | ||||||
|  |      * @returns the read 16-bit unsigned value. | ||||||
|  |      */ | ||||||
|     u16 Read16(VAddr addr); |     u16 Read16(VAddr addr); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Reads a 32-bit unsigned value from the current process' address space | ||||||
|  |      * at the given virtual address. | ||||||
|  |      * | ||||||
|  |      * @param addr The virtual address to read the 32-bit value from. | ||||||
|  |      * | ||||||
|  |      * @returns the read 32-bit unsigned value. | ||||||
|  |      */ | ||||||
|     u32 Read32(VAddr addr); |     u32 Read32(VAddr addr); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Reads a 64-bit unsigned value from the current process' address space | ||||||
|  |      * at the given virtual address. | ||||||
|  |      * | ||||||
|  |      * @param addr The virtual address to read the 64-bit value from. | ||||||
|  |      * | ||||||
|  |      * @returns the read 64-bit value. | ||||||
|  |      */ | ||||||
|     u64 Read64(VAddr addr); |     u64 Read64(VAddr addr); | ||||||
| 
 | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Writes an 8-bit unsigned integer to the given virtual address in | ||||||
|  |      * the current process' address space. | ||||||
|  |      * | ||||||
|  |      * @param addr The virtual address to write the 8-bit unsigned integer to. | ||||||
|  |      * @param data The 8-bit unsigned integer to write to the given virtual address. | ||||||
|  |      * | ||||||
|  |      * @post The memory at the given virtual address contains the specified data value. | ||||||
|  |      */ | ||||||
|     void Write8(VAddr addr, u8 data); |     void Write8(VAddr addr, u8 data); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Writes a 16-bit unsigned integer to the given virtual address in | ||||||
|  |      * the current process' address space. | ||||||
|  |      * | ||||||
|  |      * @param addr The virtual address to write the 16-bit unsigned integer to. | ||||||
|  |      * @param data The 16-bit unsigned integer to write to the given virtual address. | ||||||
|  |      * | ||||||
|  |      * @post The memory range [addr, sizeof(data)) contains the given data value. | ||||||
|  |      */ | ||||||
|     void Write16(VAddr addr, u16 data); |     void Write16(VAddr addr, u16 data); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Writes a 32-bit unsigned integer to the given virtual address in | ||||||
|  |      * the current process' address space. | ||||||
|  |      * | ||||||
|  |      * @param addr The virtual address to write the 32-bit unsigned integer to. | ||||||
|  |      * @param data The 32-bit unsigned integer to write to the given virtual address. | ||||||
|  |      * | ||||||
|  |      * @post The memory range [addr, sizeof(data)) contains the given data value. | ||||||
|  |      */ | ||||||
|     void Write32(VAddr addr, u32 data); |     void Write32(VAddr addr, u32 data); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Writes a 64-bit unsigned integer to the given virtual address in | ||||||
|  |      * the current process' address space. | ||||||
|  |      * | ||||||
|  |      * @param addr The virtual address to write the 64-bit unsigned integer to. | ||||||
|  |      * @param data The 64-bit unsigned integer to write to the given virtual address. | ||||||
|  |      * | ||||||
|  |      * @post The memory range [addr, sizeof(data)) contains the given data value. | ||||||
|  |      */ | ||||||
|     void Write64(VAddr addr, u64 data); |     void Write64(VAddr addr, u64 data); | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|  | @ -344,29 +431,155 @@ public: | ||||||
|     bool WriteExclusive32(const VAddr addr, const u32 data, const u32 expected); |     bool WriteExclusive32(const VAddr addr, const u32 data, const u32 expected); | ||||||
|     bool WriteExclusive64(const VAddr addr, const u64 data, const u64 expected); |     bool WriteExclusive64(const VAddr addr, const u64 data, const u64 expected); | ||||||
| 
 | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Reads a null-terminated string from the given virtual address. | ||||||
|  |      * This function will continually read characters until either: | ||||||
|  |      * | ||||||
|  |      * - A null character ('\0') is reached. | ||||||
|  |      * - max_length characters have been read. | ||||||
|  |      * | ||||||
|  |      * @note The final null-terminating character (if found) is not included | ||||||
|  |      *       in the returned string. | ||||||
|  |      * | ||||||
|  |      * @param vaddr      The address to begin reading the string from. | ||||||
|  |      * @param max_length The maximum length of the string to read in characters. | ||||||
|  |      * | ||||||
|  |      * @returns The read string. | ||||||
|  |      */ | ||||||
|  |     std::string ReadCString(VAddr vaddr, std::size_t max_length); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Reads a contiguous block of bytes from a specified process' address space. | ||||||
|  |      * | ||||||
|  |      * @param process     The process to read the data from. | ||||||
|  |      * @param src_addr    The virtual address to begin reading from. | ||||||
|  |      * @param dest_buffer The buffer to place the read bytes into. | ||||||
|  |      * @param size        The amount of data to read, in bytes. | ||||||
|  |      * | ||||||
|  |      * @note If a size of 0 is specified, then this function reads nothing and | ||||||
|  |      *       no attempts to access memory are made at all. | ||||||
|  |      * | ||||||
|  |      * @pre dest_buffer must be at least size bytes in length, otherwise a | ||||||
|  |      *      buffer overrun will occur. | ||||||
|  |      * | ||||||
|  |      * @post The range [dest_buffer, size) contains the read bytes from the | ||||||
|  |      *       process' address space. | ||||||
|  |      */ | ||||||
|     void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer, |     void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer, | ||||||
|                    std::size_t size); |                    std::size_t size); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Reads a contiguous block of bytes from the current process' address space. | ||||||
|  |      * | ||||||
|  |      * @param src_addr    The virtual address to begin reading from. | ||||||
|  |      * @param dest_buffer The buffer to place the read bytes into. | ||||||
|  |      * @param size        The amount of data to read, in bytes. | ||||||
|  |      * | ||||||
|  |      * @note If a size of 0 is specified, then this function reads nothing and | ||||||
|  |      *       no attempts to access memory are made at all. | ||||||
|  |      * | ||||||
|  |      * @pre dest_buffer must be at least size bytes in length, otherwise a | ||||||
|  |      *      buffer overrun will occur. | ||||||
|  |      * | ||||||
|  |      * @post The range [dest_buffer, size) contains the read bytes from the | ||||||
|  |      *       current process' address space. | ||||||
|  |      */ | ||||||
|  |     void ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Writes a range of bytes into a given process' address space at the specified | ||||||
|  |      * virtual address. | ||||||
|  |      * | ||||||
|  |      * @param process    The process to write data into the address space of. | ||||||
|  |      * @param dest_addr  The destination virtual address to begin writing the data at. | ||||||
|  |      * @param src_buffer The data to write into the process' address space. | ||||||
|  |      * @param size       The size of the data to write, in bytes. | ||||||
|  |      * | ||||||
|  |      * @post The address range [dest_addr, size) in the process' address space | ||||||
|  |      *       contains the data that was within src_buffer. | ||||||
|  |      * | ||||||
|  |      * @post If an attempt is made to write into an unmapped region of memory, the writes | ||||||
|  |      *       will be ignored and an error will be logged. | ||||||
|  |      * | ||||||
|  |      * @post If a write is performed into a region of memory that is considered cached | ||||||
|  |      *       rasterizer memory, will cause the currently active rasterizer to be notified | ||||||
|  |      *       and will mark that region as invalidated to caches that the active | ||||||
|  |      *       graphics backend may be maintaining over the course of execution. | ||||||
|  |      */ | ||||||
|     void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer, |     void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer, | ||||||
|                     std::size_t size); |                     std::size_t size); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Writes a range of bytes into a given process' address space at the specified | ||||||
|  |      * virtual address. | ||||||
|  |      * | ||||||
|  |      * @param dest_addr  The destination virtual address to begin writing the data at. | ||||||
|  |      * @param src_buffer The data to write into the process' address space. | ||||||
|  |      * @param size       The size of the data to write, in bytes. | ||||||
|  |      * | ||||||
|  |      * @post The address range [dest_addr, size) in the process' address space | ||||||
|  |      *       contains the data that was within src_buffer. | ||||||
|  |      * | ||||||
|  |      * @post If an attempt is made to write into an unmapped region of memory, the writes | ||||||
|  |      *       will be ignored and an error will be logged. | ||||||
|  |      * | ||||||
|  |      * @post If a write is performed into a region of memory that is considered cached | ||||||
|  |      *       rasterizer memory, will cause the currently active rasterizer to be notified | ||||||
|  |      *       and will mark that region as invalidated to caches that the active | ||||||
|  |      *       graphics backend may be maintaining over the course of execution. | ||||||
|  |      */ | ||||||
|  |     void WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Zeros a range of bytes within the current process' address space at the specified | ||||||
|  |      * virtual address. | ||||||
|  |      * | ||||||
|  |      * @param process   The process that will have data zeroed within its address space. | ||||||
|  |      * @param dest_addr The destination virtual address to zero the data from. | ||||||
|  |      * @param size      The size of the range to zero out, in bytes. | ||||||
|  |      * | ||||||
|  |      * @post The range [dest_addr, size) within the process' address space contains the | ||||||
|  |      *       value 0. | ||||||
|  |      */ | ||||||
|     void ZeroBlock(const Kernel::Process& process, VAddr dest_addr, const std::size_t size); |     void ZeroBlock(const Kernel::Process& process, VAddr dest_addr, const std::size_t size); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Copies data within a process' address space to another location within the | ||||||
|  |      * same address space. | ||||||
|  |      * | ||||||
|  |      * @param process   The process that will have data copied within its address space. | ||||||
|  |      * @param dest_addr The destination virtual address to begin copying the data into. | ||||||
|  |      * @param src_addr  The source virtual address to begin copying the data from. | ||||||
|  |      * @param size      The size of the data to copy, in bytes. | ||||||
|  |      * | ||||||
|  |      * @post The range [dest_addr, size) within the process' address space contains the | ||||||
|  |      *       same data within the range [src_addr, size). | ||||||
|  |      */ | ||||||
|     void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, |     void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, | ||||||
|                    std::size_t size); |                    std::size_t size); | ||||||
|     void CopyBlock(const Kernel::Process& dest_process, const Kernel::Process& src_process, |     void CopyBlock(const Kernel::Process& dest_process, const Kernel::Process& src_process, | ||||||
|                    VAddr dest_addr, VAddr src_addr, std::size_t size); |                    VAddr dest_addr, VAddr src_addr, std::size_t size); | ||||||
| 
 | 
 | ||||||
|     std::string ReadCString(VAddr vaddr, std::size_t max_length); |     /**
 | ||||||
|  |      * Marks each page within the specified address range as cached or uncached. | ||||||
|  |      * | ||||||
|  |      * @param vaddr  The virtual address indicating the start of the address range. | ||||||
|  |      * @param size   The size of the address range in bytes. | ||||||
|  |      * @param cached Whether or not any pages within the address range should be | ||||||
|  |      *               marked as cached or uncached. | ||||||
|  |      */ | ||||||
|  |     void RasterizerMarkRegionCached(PAddr start, u32 size, bool cached); | ||||||
| 
 | 
 | ||||||
|     /// Gets a pointer to the memory region beginning at the specified physical address.
 |     /// Gets a pointer to the memory region beginning at the specified physical address.
 | ||||||
|     u8* GetPhysicalPointer(PAddr address); |     u8* GetPhysicalPointer(PAddr address); | ||||||
| 
 | 
 | ||||||
|     /// Gets a pointer to the memory region beginning at the specified physical address.
 |     /// Returns a reference to the memory region beginning at the specified physical address
 | ||||||
|     const u8* GetPhysicalPointer(PAddr address) const; |  | ||||||
| 
 |  | ||||||
|     MemoryRef GetPhysicalRef(PAddr address) const; |     MemoryRef GetPhysicalRef(PAddr address) const; | ||||||
| 
 | 
 | ||||||
|     u8* GetPointer(VAddr vaddr); |     /// Determines if the given VAddr is valid for the specified process.
 | ||||||
|     const u8* GetPointer(VAddr vaddr) const; |     bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr); | ||||||
| 
 | 
 | ||||||
|  |     /// Returns true if the address refers to a valid memory region
 | ||||||
|     bool IsValidPhysicalAddress(PAddr paddr) const; |     bool IsValidPhysicalAddress(PAddr paddr) const; | ||||||
| 
 | 
 | ||||||
|     /// Gets offset in FCRAM from a pointer inside FCRAM range
 |     /// Gets offset in FCRAM from a pointer inside FCRAM range
 | ||||||
|  | @ -381,11 +594,6 @@ public: | ||||||
|     /// Gets a serializable ref to FCRAM with the given offset
 |     /// Gets a serializable ref to FCRAM with the given offset
 | ||||||
|     MemoryRef GetFCRAMRef(std::size_t offset) const; |     MemoryRef GetFCRAMRef(std::size_t offset) const; | ||||||
| 
 | 
 | ||||||
|     /**
 |  | ||||||
|      * Mark each page touching the region as cached. |  | ||||||
|      */ |  | ||||||
|     void RasterizerMarkRegionCached(PAddr start, u32 size, bool cached); |  | ||||||
| 
 |  | ||||||
|     /// Registers page table for rasterizer cache marking
 |     /// Registers page table for rasterizer cache marking
 | ||||||
|     void RegisterPageTable(std::shared_ptr<PageTable> page_table); |     void RegisterPageTable(std::shared_ptr<PageTable> page_table); | ||||||
| 
 | 
 | ||||||
|  | @ -415,7 +623,6 @@ private: | ||||||
|     void MapPages(PageTable& page_table, u32 base, u32 size, MemoryRef memory, PageType type); |     void MapPages(PageTable& page_table, u32 base, u32 size, MemoryRef memory, PageType type); | ||||||
| 
 | 
 | ||||||
|     class Impl; |     class Impl; | ||||||
| 
 |  | ||||||
|     std::unique_ptr<Impl> impl; |     std::unique_ptr<Impl> impl; | ||||||
| 
 | 
 | ||||||
|     friend class boost::serialization::access; |     friend class boost::serialization::access; | ||||||
|  | @ -427,9 +634,6 @@ public: | ||||||
|     class BackingMemImpl; |     class BackingMemImpl; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /// Determines if the given VAddr is valid for the specified process.
 |  | ||||||
| bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr); |  | ||||||
| 
 |  | ||||||
| } // namespace Memory
 | } // namespace Memory
 | ||||||
| 
 | 
 | ||||||
| BOOST_CLASS_EXPORT_KEY(Memory::MemorySystem::BackingMemImpl<Memory::Region::FCRAM>) | BOOST_CLASS_EXPORT_KEY(Memory::MemorySystem::BackingMemImpl<Memory::Region::FCRAM>) | ||||||
|  |  | ||||||
|  | @ -22,7 +22,6 @@ namespace Settings { | ||||||
| Values values = {}; | Values values = {}; | ||||||
| 
 | 
 | ||||||
| void Apply() { | void Apply() { | ||||||
| 
 |  | ||||||
|     GDBStub::SetServerPort(values.gdbstub_port); |     GDBStub::SetServerPort(values.gdbstub_port); | ||||||
|     GDBStub::ToggleServer(values.use_gdbstub); |     GDBStub::ToggleServer(values.use_gdbstub); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -137,7 +137,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     SECTION("translates StaticBuffer descriptors") { |     SECTION("translates StaticBuffer descriptors") { | ||||||
|         auto mem = std::make_shared<BufferMem>(Memory::PAGE_SIZE); |         auto mem = std::make_shared<BufferMem>(Memory::CITRA_PAGE_SIZE); | ||||||
|         MemoryRef buffer{mem}; |         MemoryRef buffer{mem}; | ||||||
|         std::fill(buffer.GetPtr(), buffer.GetPtr() + buffer.GetSize(), 0xAB); |         std::fill(buffer.GetPtr(), buffer.GetPtr() + buffer.GetSize(), 0xAB); | ||||||
| 
 | 
 | ||||||
|  | @ -161,7 +161,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     SECTION("translates MappedBuffer descriptors") { |     SECTION("translates MappedBuffer descriptors") { | ||||||
|         auto mem = std::make_shared<BufferMem>(Memory::PAGE_SIZE); |         auto mem = std::make_shared<BufferMem>(Memory::CITRA_PAGE_SIZE); | ||||||
|         MemoryRef buffer{mem}; |         MemoryRef buffer{mem}; | ||||||
|         std::fill(buffer.GetPtr(), buffer.GetPtr() + buffer.GetSize(), 0xCD); |         std::fill(buffer.GetPtr(), buffer.GetPtr() + buffer.GetSize(), 0xCD); | ||||||
| 
 | 
 | ||||||
|  | @ -187,11 +187,11 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     SECTION("translates mixed params") { |     SECTION("translates mixed params") { | ||||||
|         auto mem_static = std::make_shared<BufferMem>(Memory::PAGE_SIZE); |         auto mem_static = std::make_shared<BufferMem>(Memory::CITRA_PAGE_SIZE); | ||||||
|         MemoryRef buffer_static{mem_static}; |         MemoryRef buffer_static{mem_static}; | ||||||
|         std::fill(buffer_static.GetPtr(), buffer_static.GetPtr() + buffer_static.GetSize(), 0xCE); |         std::fill(buffer_static.GetPtr(), buffer_static.GetPtr() + buffer_static.GetSize(), 0xCE); | ||||||
| 
 | 
 | ||||||
|         auto mem_mapped = std::make_shared<BufferMem>(Memory::PAGE_SIZE); |         auto mem_mapped = std::make_shared<BufferMem>(Memory::CITRA_PAGE_SIZE); | ||||||
|         MemoryRef buffer_mapped{mem_mapped}; |         MemoryRef buffer_mapped{mem_mapped}; | ||||||
|         std::fill(buffer_mapped.GetPtr(), buffer_mapped.GetPtr() + buffer_mapped.GetSize(), 0xDF); |         std::fill(buffer_mapped.GetPtr(), buffer_mapped.GetPtr() + buffer_mapped.GetSize(), 0xDF); | ||||||
| 
 | 
 | ||||||
|  | @ -321,12 +321,12 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     SECTION("translates StaticBuffer descriptors") { |     SECTION("translates StaticBuffer descriptors") { | ||||||
|         std::vector<u8> input_buffer(Memory::PAGE_SIZE); |         std::vector<u8> input_buffer(Memory::CITRA_PAGE_SIZE); | ||||||
|         std::fill(input_buffer.begin(), input_buffer.end(), 0xAB); |         std::fill(input_buffer.begin(), input_buffer.end(), 0xAB); | ||||||
| 
 | 
 | ||||||
|         context.AddStaticBuffer(0, input_buffer); |         context.AddStaticBuffer(0, input_buffer); | ||||||
| 
 | 
 | ||||||
|         auto output_mem = std::make_shared<BufferMem>(Memory::PAGE_SIZE); |         auto output_mem = std::make_shared<BufferMem>(Memory::CITRA_PAGE_SIZE); | ||||||
|         MemoryRef output_buffer{output_mem}; |         MemoryRef output_buffer{output_mem}; | ||||||
| 
 | 
 | ||||||
|         VAddr target_address = 0x10000000; |         VAddr target_address = 0x10000000; | ||||||
|  | @ -355,10 +355,10 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     SECTION("translates StaticBuffer descriptors") { |     SECTION("translates StaticBuffer descriptors") { | ||||||
|         std::vector<u8> input_buffer(Memory::PAGE_SIZE); |         std::vector<u8> input_buffer(Memory::CITRA_PAGE_SIZE); | ||||||
|         std::fill(input_buffer.begin(), input_buffer.end(), 0xAB); |         std::fill(input_buffer.begin(), input_buffer.end(), 0xAB); | ||||||
| 
 | 
 | ||||||
|         auto output_mem = std::make_shared<BufferMem>(Memory::PAGE_SIZE); |         auto output_mem = std::make_shared<BufferMem>(Memory::CITRA_PAGE_SIZE); | ||||||
|         MemoryRef output_buffer{output_mem}; |         MemoryRef output_buffer{output_mem}; | ||||||
| 
 | 
 | ||||||
|         VAddr target_address = 0x10000000; |         VAddr target_address = 0x10000000; | ||||||
|  |  | ||||||
|  | @ -3,34 +3,31 @@ | ||||||
| // Refer to the license.txt file included.
 | // Refer to the license.txt file included.
 | ||||||
| 
 | 
 | ||||||
| #include <catch2/catch_test_macros.hpp> | #include <catch2/catch_test_macros.hpp> | ||||||
| #include "core/core.h" |  | ||||||
| #include "core/core_timing.h" | #include "core/core_timing.h" | ||||||
| #include "core/hle/kernel/memory.h" |  | ||||||
| #include "core/hle/kernel/process.h" | #include "core/hle/kernel/process.h" | ||||||
| #include "core/hle/kernel/shared_page.h" |  | ||||||
| #include "core/memory.h" | #include "core/memory.h" | ||||||
| 
 | 
 | ||||||
| TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") { | TEST_CASE("memory.IsValidVirtualAddress", "[core][memory]") { | ||||||
|     Core::Timing timing(1, 100); |     Core::Timing timing(1, 100); | ||||||
|     Memory::MemorySystem memory; |     Memory::MemorySystem memory; | ||||||
|     Kernel::KernelSystem kernel( |     Kernel::KernelSystem kernel( | ||||||
|         memory, timing, [] {}, 0, 1, 0); |         memory, timing, [] {}, 0, 1, 0); | ||||||
|     SECTION("these regions should not be mapped on an empty process") { |     SECTION("these regions should not be mapped on an empty process") { | ||||||
|         auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0)); |         auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0)); | ||||||
|         CHECK(Memory::IsValidVirtualAddress(*process, Memory::PROCESS_IMAGE_VADDR) == false); |         CHECK(memory.IsValidVirtualAddress(*process, Memory::PROCESS_IMAGE_VADDR) == false); | ||||||
|         CHECK(Memory::IsValidVirtualAddress(*process, Memory::HEAP_VADDR) == false); |         CHECK(memory.IsValidVirtualAddress(*process, Memory::HEAP_VADDR) == false); | ||||||
|         CHECK(Memory::IsValidVirtualAddress(*process, Memory::LINEAR_HEAP_VADDR) == false); |         CHECK(memory.IsValidVirtualAddress(*process, Memory::LINEAR_HEAP_VADDR) == false); | ||||||
|         CHECK(Memory::IsValidVirtualAddress(*process, Memory::VRAM_VADDR) == false); |         CHECK(memory.IsValidVirtualAddress(*process, Memory::VRAM_VADDR) == false); | ||||||
|         CHECK(Memory::IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == false); |         CHECK(memory.IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == false); | ||||||
|         CHECK(Memory::IsValidVirtualAddress(*process, Memory::SHARED_PAGE_VADDR) == false); |         CHECK(memory.IsValidVirtualAddress(*process, Memory::SHARED_PAGE_VADDR) == false); | ||||||
|         CHECK(Memory::IsValidVirtualAddress(*process, Memory::TLS_AREA_VADDR) == false); |         CHECK(memory.IsValidVirtualAddress(*process, Memory::TLS_AREA_VADDR) == false); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     SECTION("CONFIG_MEMORY_VADDR and SHARED_PAGE_VADDR should be valid after mapping them") { |     SECTION("CONFIG_MEMORY_VADDR and SHARED_PAGE_VADDR should be valid after mapping them") { | ||||||
|         auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0)); |         auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0)); | ||||||
|         kernel.MapSharedPages(process->vm_manager); |         kernel.MapSharedPages(process->vm_manager); | ||||||
|         CHECK(Memory::IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == true); |         CHECK(memory.IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == true); | ||||||
|         CHECK(Memory::IsValidVirtualAddress(*process, Memory::SHARED_PAGE_VADDR) == true); |         CHECK(memory.IsValidVirtualAddress(*process, Memory::SHARED_PAGE_VADDR) == true); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     SECTION("special regions should be valid after mapping them") { |     SECTION("special regions should be valid after mapping them") { | ||||||
|  | @ -38,13 +35,13 @@ TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") { | ||||||
|         SECTION("VRAM") { |         SECTION("VRAM") { | ||||||
|             kernel.HandleSpecialMapping(process->vm_manager, |             kernel.HandleSpecialMapping(process->vm_manager, | ||||||
|                                         {Memory::VRAM_VADDR, Memory::VRAM_SIZE, false, false}); |                                         {Memory::VRAM_VADDR, Memory::VRAM_SIZE, false, false}); | ||||||
|             CHECK(Memory::IsValidVirtualAddress(*process, Memory::VRAM_VADDR) == true); |             CHECK(memory.IsValidVirtualAddress(*process, Memory::VRAM_VADDR) == true); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         SECTION("IO (Not yet implemented)") { |         SECTION("IO (Not yet implemented)") { | ||||||
|             kernel.HandleSpecialMapping( |             kernel.HandleSpecialMapping( | ||||||
|                 process->vm_manager, {Memory::IO_AREA_VADDR, Memory::IO_AREA_SIZE, false, false}); |                 process->vm_manager, {Memory::IO_AREA_VADDR, Memory::IO_AREA_SIZE, false, false}); | ||||||
|             CHECK_FALSE(Memory::IsValidVirtualAddress(*process, Memory::IO_AREA_VADDR) == true); |             CHECK_FALSE(memory.IsValidVirtualAddress(*process, Memory::IO_AREA_VADDR) == true); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -52,6 +49,6 @@ TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") { | ||||||
|         auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0)); |         auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0)); | ||||||
|         kernel.MapSharedPages(process->vm_manager); |         kernel.MapSharedPages(process->vm_manager); | ||||||
|         process->vm_manager.UnmapRange(Memory::CONFIG_MEMORY_VADDR, Memory::CONFIG_MEMORY_SIZE); |         process->vm_manager.UnmapRange(Memory::CONFIG_MEMORY_VADDR, Memory::CONFIG_MEMORY_SIZE); | ||||||
|         CHECK(Memory::IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == false); |         CHECK(memory.IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == false); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -10,7 +10,7 @@ | ||||||
| #include "core/memory.h" | #include "core/memory.h" | ||||||
| 
 | 
 | ||||||
| TEST_CASE("Memory Basics", "[kernel][memory]") { | TEST_CASE("Memory Basics", "[kernel][memory]") { | ||||||
|     auto mem = std::make_shared<BufferMem>(Memory::PAGE_SIZE); |     auto mem = std::make_shared<BufferMem>(Memory::CITRA_PAGE_SIZE); | ||||||
|     MemoryRef block{mem}; |     MemoryRef block{mem}; | ||||||
|     Memory::MemorySystem memory; |     Memory::MemorySystem memory; | ||||||
|     SECTION("mapping memory") { |     SECTION("mapping memory") { | ||||||
|  |  | ||||||
|  | @ -255,7 +255,7 @@ public: | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     const Regs& regs; |     [[maybe_unused]] const Regs& regs; | ||||||
|     Shader::ShaderSetup& setup; |     Shader::ShaderSetup& setup; | ||||||
|     Common::Vec4<float24>* buffer_begin; |     Common::Vec4<float24>* buffer_begin; | ||||||
|     Common::Vec4<float24>* buffer_cur; |     Common::Vec4<float24>* buffer_cur; | ||||||
|  |  | ||||||
|  | @ -28,7 +28,7 @@ public: | ||||||
|          * @note All methods in this class are called from the GSP thread |          * @note All methods in this class are called from the GSP thread | ||||||
|          */ |          */ | ||||||
|         virtual void GXCommandProcessed(int total_command_count) { |         virtual void GXCommandProcessed(int total_command_count) { | ||||||
|             const Service::GSP::Command& cmd = |             [[maybe_unused]] const Service::GSP::Command& cmd = | ||||||
|                 observed->ReadGXCommandHistory(total_command_count - 1); |                 observed->ReadGXCommandHistory(total_command_count - 1); | ||||||
|             LOG_TRACE(Debug_GPU, "Received command: id={:x}", (int)cmd.id.Value()); |             LOG_TRACE(Debug_GPU, "Received command: id={:x}", (int)cmd.id.Value()); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -44,7 +44,8 @@ CachedSurface::~CachedSurface() { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 192, 64)); | MICROPROFILE_DEFINE(RasterizerCache_SurfaceLoad, "RasterizerCache", "Surface Load", | ||||||
|  |                     MP_RGB(128, 192, 64)); | ||||||
| void CachedSurface::LoadGLBuffer(PAddr load_start, PAddr load_end) { | void CachedSurface::LoadGLBuffer(PAddr load_start, PAddr load_end) { | ||||||
|     ASSERT(type != SurfaceType::Fill); |     ASSERT(type != SurfaceType::Fill); | ||||||
|     const bool need_swap = |     const bool need_swap = | ||||||
|  | @ -65,7 +66,7 @@ void CachedSurface::LoadGLBuffer(PAddr load_start, PAddr load_end) { | ||||||
|     if (load_start < Memory::VRAM_VADDR && load_end > Memory::VRAM_VADDR) |     if (load_start < Memory::VRAM_VADDR && load_end > Memory::VRAM_VADDR) | ||||||
|         load_start = Memory::VRAM_VADDR; |         load_start = Memory::VRAM_VADDR; | ||||||
| 
 | 
 | ||||||
|     MICROPROFILE_SCOPE(OpenGL_SurfaceLoad); |     MICROPROFILE_SCOPE(RasterizerCache_SurfaceLoad); | ||||||
| 
 | 
 | ||||||
|     ASSERT(load_start >= addr && load_end <= end); |     ASSERT(load_start >= addr && load_end <= end); | ||||||
|     const u32 start_offset = load_start - addr; |     const u32 start_offset = load_start - addr; | ||||||
|  | @ -121,7 +122,8 @@ void CachedSurface::LoadGLBuffer(PAddr load_start, PAddr load_end) { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64)); | MICROPROFILE_DEFINE(RasterizerCache_SurfaceFlush, "RasterizerCache", "Surface Flush", | ||||||
|  |                     MP_RGB(128, 192, 64)); | ||||||
| void CachedSurface::FlushGLBuffer(PAddr flush_start, PAddr flush_end) { | void CachedSurface::FlushGLBuffer(PAddr flush_start, PAddr flush_end) { | ||||||
|     u8* const dst_buffer = VideoCore::g_memory->GetPhysicalPointer(addr); |     u8* const dst_buffer = VideoCore::g_memory->GetPhysicalPointer(addr); | ||||||
|     if (dst_buffer == nullptr) |     if (dst_buffer == nullptr) | ||||||
|  | @ -137,7 +139,7 @@ void CachedSurface::FlushGLBuffer(PAddr flush_start, PAddr flush_end) { | ||||||
|     if (flush_start < Memory::VRAM_VADDR && flush_end > Memory::VRAM_VADDR) |     if (flush_start < Memory::VRAM_VADDR && flush_end > Memory::VRAM_VADDR) | ||||||
|         flush_start = Memory::VRAM_VADDR; |         flush_start = Memory::VRAM_VADDR; | ||||||
| 
 | 
 | ||||||
|     MICROPROFILE_SCOPE(OpenGL_SurfaceFlush); |     MICROPROFILE_SCOPE(RasterizerCache_SurfaceFlush); | ||||||
| 
 | 
 | ||||||
|     ASSERT(flush_start >= addr && flush_end <= end); |     ASSERT(flush_start >= addr && flush_end <= end); | ||||||
|     const u32 start_offset = flush_start - addr; |     const u32 start_offset = flush_start - addr; | ||||||
|  | @ -270,13 +272,14 @@ void CachedSurface::DumpTexture(GLuint target_tex, u64 tex_hash) { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 192, 64)); | MICROPROFILE_DEFINE(RasterizerCache_TextureUL, "RasterizerCache", "Texture Upload", | ||||||
|  |                     MP_RGB(128, 192, 64)); | ||||||
| void CachedSurface::UploadGLTexture(Common::Rectangle<u32> rect) { | void CachedSurface::UploadGLTexture(Common::Rectangle<u32> rect) { | ||||||
|     if (type == SurfaceType::Fill) { |     if (type == SurfaceType::Fill) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     MICROPROFILE_SCOPE(OpenGL_TextureUL); |     MICROPROFILE_SCOPE(RasterizerCache_TextureUL); | ||||||
|     ASSERT(gl_buffer.size() == width * height * GetBytesPerPixel(pixel_format)); |     ASSERT(gl_buffer.size() == width * height * GetBytesPerPixel(pixel_format)); | ||||||
| 
 | 
 | ||||||
|     u64 tex_hash = 0; |     u64 tex_hash = 0; | ||||||
|  | @ -374,13 +377,14 @@ void CachedSurface::UploadGLTexture(Common::Rectangle<u32> rect) { | ||||||
|     InvalidateAllWatcher(); |     InvalidateAllWatcher(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| MICROPROFILE_DEFINE(OpenGL_TextureDL, "OpenGL", "Texture Download", MP_RGB(128, 192, 64)); | MICROPROFILE_DEFINE(RasterizerCache_TextureDL, "RasterizerCache", "Texture Download", | ||||||
|  |                     MP_RGB(128, 192, 64)); | ||||||
| void CachedSurface::DownloadGLTexture(const Common::Rectangle<u32>& rect) { | void CachedSurface::DownloadGLTexture(const Common::Rectangle<u32>& rect) { | ||||||
|     if (type == SurfaceType::Fill) { |     if (type == SurfaceType::Fill) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     MICROPROFILE_SCOPE(OpenGL_TextureDL); |     MICROPROFILE_SCOPE(RasterizerCache_TextureDL); | ||||||
| 
 | 
 | ||||||
|     if (gl_buffer.empty()) { |     if (gl_buffer.empty()) { | ||||||
|         gl_buffer.resize(width * height * GetBytesPerPixel(pixel_format)); |         gl_buffer.resize(width * height * GetBytesPerPixel(pixel_format)); | ||||||
|  |  | ||||||
|  | @ -93,10 +93,11 @@ OGLTexture RasterizerCacheOpenGL::AllocateSurfaceTexture(const FormatTuple& tupl | ||||||
|     return texture; |     return texture; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| MICROPROFILE_DEFINE(OpenGL_CopySurface, "OpenGL", "CopySurface", MP_RGB(128, 192, 64)); | MICROPROFILE_DEFINE(RasterizerCache_CopySurface, "RasterizerCache", "CopySurface", | ||||||
|  |                     MP_RGB(128, 192, 64)); | ||||||
| void RasterizerCacheOpenGL::CopySurface(const Surface& src_surface, const Surface& dst_surface, | void RasterizerCacheOpenGL::CopySurface(const Surface& src_surface, const Surface& dst_surface, | ||||||
|                                         SurfaceInterval copy_interval) { |                                         SurfaceInterval copy_interval) { | ||||||
|     MICROPROFILE_SCOPE(OpenGL_CopySurface); |     MICROPROFILE_SCOPE(RasterizerCache_CopySurface); | ||||||
| 
 | 
 | ||||||
|     SurfaceParams subrect_params = dst_surface->FromInterval(copy_interval); |     SurfaceParams subrect_params = dst_surface->FromInterval(copy_interval); | ||||||
|     ASSERT(subrect_params.GetInterval() == copy_interval); |     ASSERT(subrect_params.GetInterval() == copy_interval); | ||||||
|  | @ -253,12 +254,13 @@ RasterizerCacheOpenGL::~RasterizerCacheOpenGL() { | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| MICROPROFILE_DEFINE(OpenGL_BlitSurface, "OpenGL", "BlitSurface", MP_RGB(128, 192, 64)); | MICROPROFILE_DEFINE(RasterizerCache_BlitSurface, "RasterizerCache", "BlitSurface", | ||||||
|  |                     MP_RGB(128, 192, 64)); | ||||||
| bool RasterizerCacheOpenGL::BlitSurfaces(const Surface& src_surface, | bool RasterizerCacheOpenGL::BlitSurfaces(const Surface& src_surface, | ||||||
|                                          const Common::Rectangle<u32>& src_rect, |                                          const Common::Rectangle<u32>& src_rect, | ||||||
|                                          const Surface& dst_surface, |                                          const Surface& dst_surface, | ||||||
|                                          const Common::Rectangle<u32>& dst_rect) { |                                          const Common::Rectangle<u32>& dst_rect) { | ||||||
|     MICROPROFILE_SCOPE(OpenGL_BlitSurface); |     MICROPROFILE_SCOPE(RasterizerCache_BlitSurface); | ||||||
| 
 | 
 | ||||||
|     if (CheckFormatsBlittable(src_surface->pixel_format, dst_surface->pixel_format)) { |     if (CheckFormatsBlittable(src_surface->pixel_format, dst_surface->pixel_format)) { | ||||||
|         dst_surface->InvalidateAllWatcher(); |         dst_surface->InvalidateAllWatcher(); | ||||||
|  | @ -917,8 +919,8 @@ void RasterizerCacheOpenGL::ClearAll(bool flush) { | ||||||
|     for (auto& pair : RangeFromInterval(cached_pages, flush_interval)) { |     for (auto& pair : RangeFromInterval(cached_pages, flush_interval)) { | ||||||
|         const auto interval = pair.first & flush_interval; |         const auto interval = pair.first & flush_interval; | ||||||
| 
 | 
 | ||||||
|         const PAddr interval_start_addr = boost::icl::first(interval) << Memory::PAGE_BITS; |         const PAddr interval_start_addr = boost::icl::first(interval) << Memory::CITRA_PAGE_BITS; | ||||||
|         const PAddr interval_end_addr = boost::icl::last_next(interval) << Memory::PAGE_BITS; |         const PAddr interval_end_addr = boost::icl::last_next(interval) << Memory::CITRA_PAGE_BITS; | ||||||
|         const u32 interval_size = interval_end_addr - interval_start_addr; |         const u32 interval_size = interval_end_addr - interval_start_addr; | ||||||
| 
 | 
 | ||||||
|         VideoCore::g_memory->RasterizerMarkRegionCached(interval_start_addr, interval_size, false); |         VideoCore::g_memory->RasterizerMarkRegionCached(interval_start_addr, interval_size, false); | ||||||
|  | @ -1069,8 +1071,8 @@ void RasterizerCacheOpenGL::UnregisterSurface(const Surface& surface) { | ||||||
| 
 | 
 | ||||||
| void RasterizerCacheOpenGL::UpdatePagesCachedCount(PAddr addr, u32 size, int delta) { | void RasterizerCacheOpenGL::UpdatePagesCachedCount(PAddr addr, u32 size, int delta) { | ||||||
|     const u32 num_pages = |     const u32 num_pages = | ||||||
|         ((addr + size - 1) >> Memory::PAGE_BITS) - (addr >> Memory::PAGE_BITS) + 1; |         ((addr + size - 1) >> Memory::CITRA_PAGE_BITS) - (addr >> Memory::CITRA_PAGE_BITS) + 1; | ||||||
|     const u32 page_start = addr >> Memory::PAGE_BITS; |     const u32 page_start = addr >> Memory::CITRA_PAGE_BITS; | ||||||
|     const u32 page_end = page_start + num_pages; |     const u32 page_end = page_start + num_pages; | ||||||
| 
 | 
 | ||||||
|     // Interval maps will erase segments if count reaches 0, so if delta is negative we have to
 |     // Interval maps will erase segments if count reaches 0, so if delta is negative we have to
 | ||||||
|  | @ -1083,8 +1085,8 @@ void RasterizerCacheOpenGL::UpdatePagesCachedCount(PAddr addr, u32 size, int del | ||||||
|         const auto interval = pair.first & pages_interval; |         const auto interval = pair.first & pages_interval; | ||||||
|         const int count = pair.second; |         const int count = pair.second; | ||||||
| 
 | 
 | ||||||
|         const PAddr interval_start_addr = boost::icl::first(interval) << Memory::PAGE_BITS; |         const PAddr interval_start_addr = boost::icl::first(interval) << Memory::CITRA_PAGE_BITS; | ||||||
|         const PAddr interval_end_addr = boost::icl::last_next(interval) << Memory::PAGE_BITS; |         const PAddr interval_end_addr = boost::icl::last_next(interval) << Memory::CITRA_PAGE_BITS; | ||||||
|         const u32 interval_size = interval_end_addr - interval_start_addr; |         const u32 interval_size = interval_end_addr - interval_start_addr; | ||||||
| 
 | 
 | ||||||
|         if (delta > 0 && count == delta) |         if (delta > 0 && count == delta) | ||||||
|  |  | ||||||
|  | @ -274,9 +274,11 @@ struct FramebufferRegs { | ||||||
|         case DepthFormat::D24: |         case DepthFormat::D24: | ||||||
|         case DepthFormat::D24S8: |         case DepthFormat::D24S8: | ||||||
|             return 24; |             return 24; | ||||||
|  |         default: | ||||||
|  |             UNREACHABLE_MSG("Unknown depth format {}", format); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         ASSERT_MSG(false, "Unknown depth format {}", format); |         return 0; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     INSERT_PADDING_WORDS(0x10); // Gas related registers
 |     INSERT_PADDING_WORDS(0x10); // Gas related registers
 | ||||||
|  |  | ||||||
|  | @ -129,6 +129,8 @@ struct LightingRegs { | ||||||
|                             "ReflectBlue, instead got %i", |                             "ReflectBlue, instead got %i", | ||||||
|                             config); |                             config); | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     struct LightSrc { |     struct LightSrc { | ||||||
|  |  | ||||||
|  | @ -428,6 +428,8 @@ static GLenum GetCurrentPrimitiveMode() { | ||||||
|     default: |     default: | ||||||
|         UNREACHABLE(); |         UNREACHABLE(); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     return GL_TRIANGLES; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool RasterizerOpenGL::AccelerateDrawBatchInternal(bool is_indexed) { | bool RasterizerOpenGL::AccelerateDrawBatchInternal(bool is_indexed) { | ||||||
|  |  | ||||||
|  | @ -89,7 +89,7 @@ void OGLTexture::CopyFrom(const OGLTexture& other, GLenum target, GLsizei levels | ||||||
|     glActiveTexture(GL_TEXTURE0); |     glActiveTexture(GL_TEXTURE0); | ||||||
|     glBindTexture(GL_TEXTURE_2D, handle); |     glBindTexture(GL_TEXTURE_2D, handle); | ||||||
| 
 | 
 | ||||||
|     for (u32 level = 0; level < levels; level++) { |     for (GLsizei level = 0; level < levels; level++) { | ||||||
|         glCopyImageSubData(other.handle, target, level, 0, 0, 0, handle, target, level, 0, 0, 0, |         glCopyImageSubData(other.handle, target, level, 0, 0, 0, handle, target, level, 0, 0, 0, | ||||||
|                            width >> level, height >> level, 1); |                            width >> level, height >> level, 1); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -744,7 +744,7 @@ void RendererOpenGL::ReloadShader() { | ||||||
| void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, | void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, | ||||||
|                                                  const GPU::Regs::FramebufferConfig& framebuffer) { |                                                  const GPU::Regs::FramebufferConfig& framebuffer) { | ||||||
|     GPU::Regs::PixelFormat format = framebuffer.color_format; |     GPU::Regs::PixelFormat format = framebuffer.color_format; | ||||||
|     GLint internal_format; |     GLint internal_format{}; | ||||||
| 
 | 
 | ||||||
|     texture.format = format; |     texture.format = format; | ||||||
|     texture.width = framebuffer.width; |     texture.width = framebuffer.width; | ||||||
|  |  | ||||||
|  | @ -208,7 +208,7 @@ GLuint TextureDownloaderES::ConvertDepthToColor(GLuint level, GLenum& format, GL | ||||||
| void TextureDownloaderES::GetTexImage(GLenum target, GLuint level, GLenum format, GLenum type, | void TextureDownloaderES::GetTexImage(GLenum target, GLuint level, GLenum format, GLenum type, | ||||||
|                                       GLint height, GLint width, void* pixels) { |                                       GLint height, GLint width, void* pixels) { | ||||||
|     OpenGLState state = OpenGLState::GetCurState(); |     OpenGLState state = OpenGLState::GetCurState(); | ||||||
|     GLuint texture; |     GLuint texture{}; | ||||||
|     const GLuint old_read_buffer = state.draw.read_framebuffer; |     const GLuint old_read_buffer = state.draw.read_framebuffer; | ||||||
|     switch (target) { |     switch (target) { | ||||||
|     case GL_TEXTURE_2D: |     case GL_TEXTURE_2D: | ||||||
|  |  | ||||||
|  | @ -46,7 +46,7 @@ public: | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     float24 pos; |     [[maybe_unused]] float24 pos; | ||||||
|     Common::Vec4<float24> coeffs; |     Common::Vec4<float24> coeffs; | ||||||
|     Common::Vec4<float24> bias; |     Common::Vec4<float24> bias; | ||||||
| }; | }; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue