mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30: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); | ||||
|     int t = MicroProfileLogType(Entry); | ||||
|     uint64_t nTimerIndex = MicroProfileLogTimerIndex(Entry); | ||||
|     MP_ASSERT(t == nBegin); | ||||
|     MP_ASSERT(static_cast<uint64_t>(t) == nBegin); | ||||
|     MP_ASSERT(nTimerIndex == (nToken&0x3fff)); | ||||
|     return Entry; | ||||
| 
 | ||||
|  | @ -1579,10 +1579,10 @@ void MicroProfileFlip() | |||
| 
 | ||||
|         pFramePut->nFrameStartCpu = MP_TICK(); | ||||
|         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); | ||||
| 
 | ||||
|         if(pFrameCurrent->nFrameStartGpu == (uint64_t)-1) | ||||
|         if(static_cast<uint64_t>(pFrameCurrent->nFrameStartGpu) == (uint64_t)-1) | ||||
|             pFrameCurrent->nFrameStartGpu = pFrameNext->nFrameStartGpu + 1; | ||||
| 
 | ||||
|         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) | ||||
|     { | ||||
|         bInitialized = true; | ||||
|         memset(&g_MicroProfileUI, 0, sizeof(g_MicroProfileUI)); | ||||
|         g_MicroProfileUI = {}; | ||||
|         UI.nActiveMenu = UINT32_MAX; | ||||
|         UI.fDetailedOffsetTarget = UI.fDetailedOffset = 0.f; | ||||
|         UI.fDetailedRangeTarget = UI.fDetailedRange = 50.f; | ||||
|  | @ -845,8 +845,8 @@ void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int nBaseY, | |||
|     MicroProfile& S = *MicroProfileGet(); | ||||
|     MP_DEBUG_DUMP_RANGE(); | ||||
|     int nY = nBaseY - UI.nOffsetY; | ||||
|     int64_t nNumBoxes = 0; | ||||
|     int64_t nNumLines = 0; | ||||
|     [[maybe_unused]] int64_t nNumBoxes = 0; | ||||
|     [[maybe_unused]] int64_t nNumLines = 0; | ||||
| 
 | ||||
|     uint32_t nFrameNext = (S.nFrameCurrent+1) % MICROPROFILE_MAX_FRAME_HISTORY; | ||||
|     MicroProfileFrameState* pFrameCurrent = &S.Frames[S.nFrameCurrent]; | ||||
|  | @ -1988,7 +1988,7 @@ const char* MicroProfileUIMenuGroups(int nIndex, bool* bSelected) | |||
|     else | ||||
|     { | ||||
|         nIndex = nIndex-1; | ||||
|         if(nIndex < UI.GroupMenuCount) | ||||
|         if(static_cast<uint32_t>(nIndex) < UI.GroupMenuCount) | ||||
|         { | ||||
|             MicroProfileGroupMenuItem& Item = UI.GroupMenu[nIndex]; | ||||
|             static char buffer[MICROPROFILE_NAME_MAX_LEN+32]; | ||||
|  | @ -2135,7 +2135,7 @@ const char* MicroProfileUIMenuCustom(int nIndex, bool* bSelected) | |||
|     case 1: return "--"; | ||||
|     default: | ||||
|         nIndex -= 2; | ||||
|         if(nIndex < UI.nCustomCount) | ||||
|         if(static_cast<uint32_t>(nIndex) < UI.nCustomCount) | ||||
|         { | ||||
|             return UI.Custom[nIndex].pName; | ||||
|         } | ||||
|  | @ -2185,7 +2185,7 @@ void MicroProfileUIClickGroups(int nIndex) | |||
|     else | ||||
|     { | ||||
|         nIndex -= 1; | ||||
|         if(nIndex < UI.GroupMenuCount) | ||||
|         if(static_cast<uint32_t>(nIndex) < UI.GroupMenuCount) | ||||
|         { | ||||
|             MicroProfileGroupMenuItem& Item = UI.GroupMenu[nIndex]; | ||||
|             if(Item.nIsCategory) | ||||
|  |  | |||
|  | @ -11,13 +11,6 @@ | |||
| // This needs to be included before getopt.h because the latter #defines symbols used by it
 | ||||
| #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/emu_window/emu_window_sdl2.h" | ||||
| #include "citra/lodepng_image_interface.h" | ||||
|  | @ -52,6 +45,11 @@ | |||
| #endif | ||||
| 
 | ||||
| #ifdef _WIN32 | ||||
| // windows.h needs to be included before shellapi.h
 | ||||
| #include <windows.h> | ||||
| 
 | ||||
| #include <shellapi.h> | ||||
| 
 | ||||
| extern "C" { | ||||
| // tells Nvidia drivers to use the dedicated GPU by default on laptops with switchable graphics
 | ||||
| __declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001; | ||||
|  | @ -104,35 +102,35 @@ static void OnNetworkError(const Network::RoomMember::Error& error) { | |||
|         break; | ||||
|     case Network::RoomMember::Error::CouldNotConnect: | ||||
|         LOG_ERROR(Network, "Error: Could not connect"); | ||||
|         exit(1); | ||||
|         std::exit(1); | ||||
|         break; | ||||
|     case Network::RoomMember::Error::NameCollision: | ||||
|         LOG_ERROR( | ||||
|             Network, | ||||
|             "You tried to use the same nickname as another user that is connected to the Room"); | ||||
|         exit(1); | ||||
|         std::exit(1); | ||||
|         break; | ||||
|     case Network::RoomMember::Error::MacCollision: | ||||
|         LOG_ERROR(Network, "You tried to use the same MAC-Address as another user that is " | ||||
|                            "connected to the Room"); | ||||
|         exit(1); | ||||
|         std::exit(1); | ||||
|         break; | ||||
|     case Network::RoomMember::Error::ConsoleIdCollision: | ||||
|         LOG_ERROR(Network, "Your Console ID conflicted with someone else in the Room"); | ||||
|         exit(1); | ||||
|         std::exit(1); | ||||
|         break; | ||||
|     case Network::RoomMember::Error::WrongPassword: | ||||
|         LOG_ERROR(Network, "Room replied with: Wrong password"); | ||||
|         exit(1); | ||||
|         std::exit(1); | ||||
|         break; | ||||
|     case Network::RoomMember::Error::WrongVersion: | ||||
|         LOG_ERROR(Network, | ||||
|                   "You are using a different version than the room you are trying to connect to"); | ||||
|         exit(1); | ||||
|         std::exit(1); | ||||
|         break; | ||||
|     case Network::RoomMember::Error::RoomIsFull: | ||||
|         LOG_ERROR(Network, "The room is full"); | ||||
|         exit(1); | ||||
|         std::exit(1); | ||||
|         break; | ||||
|     case Network::RoomMember::Error::HostKicked: | ||||
|         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: | ||||
|         LOG_ERROR(Network, "You have been banned by the host"); | ||||
|         break; | ||||
|     default: | ||||
|         LOG_ERROR(Network, "Unknown network error {}", error); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -54,12 +54,12 @@ QtKeyboardDialog::QtKeyboardDialog(QWidget* parent, QtKeyboard* keyboard_) | |||
|     case ButtonConfig::None: | ||||
|         break; | ||||
|     } | ||||
|     connect(buttons, &QDialogButtonBox::accepted, this, [=] { Submit(); }); | ||||
|     connect(buttons, &QDialogButtonBox::rejected, this, [=] { | ||||
|     connect(buttons, &QDialogButtonBox::accepted, this, [this] { Submit(); }); | ||||
|     connect(buttons, &QDialogButtonBox::rejected, this, [this] { | ||||
|         button = QtKeyboard::cancel_id; | ||||
|         accept(); | ||||
|     }); | ||||
|     connect(buttons, &QDialogButtonBox::helpRequested, this, [=] { | ||||
|     connect(buttons, &QDialogButtonBox::helpRequested, this, [this] { | ||||
|         button = QtKeyboard::forgot_id; | ||||
|         accept(); | ||||
|     }); | ||||
|  |  | |||
|  | @ -32,11 +32,13 @@ EmuThread::EmuThread(Frontend::GraphicsContext& core_context) : core_context(cor | |||
| EmuThread::~EmuThread() = default; | ||||
| 
 | ||||
| static GMainWindow* GetMainWindow() { | ||||
|     for (QWidget* w : qApp->topLevelWidgets()) { | ||||
|     const auto widgets = qApp->topLevelWidgets(); | ||||
|     for (QWidget* w : widgets) { | ||||
|         if (GMainWindow* main = qobject_cast<GMainWindow*>(w)) { | ||||
|             return main; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return nullptr; | ||||
| } | ||||
| 
 | ||||
|  | @ -46,7 +48,8 @@ void EmuThread::run() { | |||
| 
 | ||||
|     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) { | ||||
|             emit LoadProgress(stage, value, total); | ||||
|         }); | ||||
|  | @ -55,18 +58,17 @@ void EmuThread::run() { | |||
| 
 | ||||
|     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
 | ||||
|         // we hide it immediately as we need to wait for user input to start the emulation.
 | ||||
|         emit HideLoadingScreen(); | ||||
|         Core::System::GetInstance().frame_limiter.WaitOnce(); | ||||
|         system.frame_limiter.WaitOnce(); | ||||
|     } | ||||
| 
 | ||||
|     // Holds whether the cpu was running during the last iteration,
 | ||||
|     // so that the DebugModeLeft signal can be emitted before the
 | ||||
|     // next execution step.
 | ||||
|     bool was_active = false; | ||||
|     Core::System& system = Core::System::GetInstance(); | ||||
|     while (!stop_run) { | ||||
|         if (running) { | ||||
|             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); | ||||
|     VideoCore::RequestScreenshot( | ||||
|         screenshot_image.bits(), | ||||
|         [=] { | ||||
|         [this, &screenshot_path] { | ||||
|             const std::string std_screenshot_path = screenshot_path.toStdString(); | ||||
|             if (screenshot_image.mirrored(false, true).save(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->textCode, &QPlainTextEdit::textChanged, this, &CheatDialog::OnTextEdited); | ||||
| 
 | ||||
|     connect(ui->buttonSave, &QPushButton::clicked, | ||||
|     connect(ui->buttonSave, &QPushButton::clicked, this, | ||||
|             [this] { SaveCheat(ui->tableCheats->currentRow()); }); | ||||
|     connect(ui->buttonDelete, &QPushButton::clicked, this, &CheatDialog::OnDeleteCheat); | ||||
| 
 | ||||
|  | @ -91,7 +91,7 @@ bool CheatDialog::SaveCheat(int row) { | |||
|     } | ||||
| 
 | ||||
|     // 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) { | ||||
|         Cheats::GatewayCheat::CheatLine cheat_line(code_lines[i].toStdString()); | ||||
|         if (cheat_line.valid) | ||||
|  | @ -190,8 +190,9 @@ void CheatDialog::OnDeleteCheat() { | |||
|     if (newly_created) { | ||||
|         newly_created = false; | ||||
|     } else { | ||||
|         Core::System::GetInstance().CheatEngine().RemoveCheat(ui->tableCheats->currentRow()); | ||||
|         Core::System::GetInstance().CheatEngine().SaveCheatFile(); | ||||
|         auto& cheat_engine = Core::System::GetInstance().CheatEngine(); | ||||
|         cheat_engine.RemoveCheat(ui->tableCheats->currentRow()); | ||||
|         cheat_engine.SaveCheatFile(); | ||||
|     } | ||||
| 
 | ||||
|     LoadCheats(); | ||||
|  |  | |||
|  | @ -518,7 +518,7 @@ void Config::ReadRendererValues() { | |||
| void Config::ReadShortcutValues() { | ||||
|     qt_config->beginGroup(QStringLiteral("Shortcuts")); | ||||
| 
 | ||||
|     for (auto [name, group, shortcut] : default_hotkeys) { | ||||
|     for (const auto& [name, group, shortcut] : default_hotkeys) { | ||||
|         auto [keyseq, context] = shortcut; | ||||
|         qt_config->beginGroup(group); | ||||
|         qt_config->beginGroup(name); | ||||
|  | @ -553,7 +553,7 @@ void Config::ReadSystemValues() { | |||
| // https://developers.google.com/media/vp9/live-encoding
 | ||||
| const QString DEFAULT_VIDEO_ENCODER_OPTIONS = | ||||
|     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() { | ||||
|     qt_config->beginGroup(QStringLiteral("VideoDumping")); | ||||
|  | @ -1013,9 +1013,9 @@ void Config::SaveRendererValues() { | |||
|                  200); | ||||
| 
 | ||||
|     // 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_green"), (double)Settings::values.bg_green, 0.0); | ||||
|     WriteSetting(QStringLiteral("bg_blue"), (double)Settings::values.bg_blue, 0.0); | ||||
|     WriteSetting(QStringLiteral("bg_red"), static_cast<double>(Settings::values.bg_red), 0.0); | ||||
|     WriteSetting(QStringLiteral("bg_green"), static_cast<double>(Settings::values.bg_green), 0.0); | ||||
|     WriteSetting(QStringLiteral("bg_blue"), static_cast<double>(Settings::values.bg_blue), 0.0); | ||||
| 
 | ||||
|     WriteSetting(QStringLiteral("texture_filter_name"), | ||||
|                  QString::fromStdString(Settings::values.texture_filter_name), | ||||
|  |  | |||
|  | @ -9,8 +9,6 @@ | |||
| #include <QMessageBox> | ||||
| #include <QWidget> | ||||
| #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/interface.h" | ||||
| #include "core/hle/service/cam/cam.h" | ||||
|  | @ -91,7 +89,7 @@ void ConfigureCamera::ConnectEvents() { | |||
|                 SetConfiguration(); | ||||
|             }); | ||||
|     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) { | ||||
|         ui->camera_file->setDisabled(state == Qt::Checked); | ||||
|         ui->toolButton->setDisabled(state == Qt::Checked); | ||||
|  | @ -99,12 +97,11 @@ void ConfigureCamera::ConnectEvents() { | |||
|             ui->camera_file->setText(QString{}); | ||||
|         } | ||||
|     }); | ||||
|     connect(ui->camera_file, &QLineEdit::textChanged, this, [=] { StopPreviewing(); }); | ||||
|     connect(ui->system_camera, | ||||
|             static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, | ||||
|             [=] { StopPreviewing(); }); | ||||
|     connect(ui->camera_flip, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), | ||||
|             this, [=] { StopPreviewing(); }); | ||||
|     connect(ui->camera_file, &QLineEdit::textChanged, this, [this] { StopPreviewing(); }); | ||||
|     connect(ui->system_camera, qOverload<int>(&QComboBox::currentIndexChanged), this, | ||||
|             [this] { StopPreviewing(); }); | ||||
|     connect(ui->camera_flip, qOverload<int>(&QComboBox::currentIndexChanged), this, | ||||
|             [this] { StopPreviewing(); }); | ||||
| } | ||||
| 
 | ||||
| void ConfigureCamera::UpdateCameraMode() { | ||||
|  |  | |||
|  | @ -24,7 +24,9 @@ ConfigureDebug::ConfigureDebug(QWidget* parent) | |||
|         QString path = QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::LogDir)); | ||||
|         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; | ||||
|  |  | |||
|  | @ -114,6 +114,9 @@ | |||
|      <layout class="QVBoxLayout" name="verticalLayout_4"> | ||||
|       <item> | ||||
|        <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"> | ||||
|          <string>Enable CPU JIT</string> | ||||
|         </property> | ||||
|  |  | |||
|  | @ -192,10 +192,10 @@ ConfigureInput::ConfigureInput(QWidget* parent) | |||
|         if (!button_map[button_id]) | ||||
|             continue; | ||||
|         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( | ||||
|                 button_map[button_id], | ||||
|                 [=](const Common::ParamPackage& params) { | ||||
|                 [this, button_id](const Common::ParamPackage& params) { | ||||
|                     buttons_param[button_id] = params; | ||||
|                     // If the user closes the dialog, the changes are reverted in
 | ||||
|                     // `GMainWindow::OnConfigure()`
 | ||||
|  | @ -204,16 +204,16 @@ ConfigureInput::ConfigureInput(QWidget* parent) | |||
|                 }, | ||||
|                 InputCommon::Polling::DeviceType::Button); | ||||
|         }); | ||||
|         connect(button_map[button_id], &QPushButton::customContextMenuRequested, | ||||
|                 [=](const QPoint& menu_location) { | ||||
|         connect(button_map[button_id], &QPushButton::customContextMenuRequested, this, | ||||
|                 [this, button_id](const QPoint& menu_location) { | ||||
|                     QMenu context_menu; | ||||
|                     context_menu.addAction(tr("Clear"), [&] { | ||||
|                     context_menu.addAction(tr("Clear"), this, [&] { | ||||
|                         buttons_param[button_id].Clear(); | ||||
|                         button_map[button_id]->setText(tr("[not set]")); | ||||
|                         ApplyConfiguration(); | ||||
|                         Settings::SaveProfile(ui->profile->currentIndex()); | ||||
|                     }); | ||||
|                     context_menu.addAction(tr("Restore Default"), [&] { | ||||
|                     context_menu.addAction(tr("Restore Default"), this, [&] { | ||||
|                         buttons_param[button_id] = Common::ParamPackage{ | ||||
|                             InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])}; | ||||
|                         button_map[button_id]->setText(ButtonToText(buttons_param[button_id])); | ||||
|  | @ -230,27 +230,29 @@ ConfigureInput::ConfigureInput(QWidget* parent) | |||
|                 continue; | ||||
|             analog_map_buttons[analog_id][sub_button_id]->setContextMenuPolicy( | ||||
|                 Qt::CustomContextMenu); | ||||
|             connect(analog_map_buttons[analog_id][sub_button_id], &QPushButton::clicked, [=]() { | ||||
|                 HandleClick( | ||||
|                     analog_map_buttons[analog_id][sub_button_id], | ||||
|                     [=](const Common::ParamPackage& params) { | ||||
|                         SetAnalogButton(params, analogs_param[analog_id], | ||||
|                                         analog_sub_buttons[sub_button_id]); | ||||
|                         ApplyConfiguration(); | ||||
|                         Settings::SaveProfile(ui->profile->currentIndex()); | ||||
|                     }, | ||||
|                     InputCommon::Polling::DeviceType::Button); | ||||
|             }); | ||||
|             connect(analog_map_buttons[analog_id][sub_button_id], &QPushButton::clicked, this, | ||||
|                     [this, analog_id, sub_button_id]() { | ||||
|                         HandleClick( | ||||
|                             analog_map_buttons[analog_id][sub_button_id], | ||||
|                             [this, analog_id, sub_button_id](const Common::ParamPackage& params) { | ||||
|                                 SetAnalogButton(params, analogs_param[analog_id], | ||||
|                                                 analog_sub_buttons[sub_button_id]); | ||||
|                                 ApplyConfiguration(); | ||||
|                                 Settings::SaveProfile(ui->profile->currentIndex()); | ||||
|                             }, | ||||
|                             InputCommon::Polling::DeviceType::Button); | ||||
|                     }); | ||||
|             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; | ||||
|                         context_menu.addAction(tr("Clear"), [&] { | ||||
|                         context_menu.addAction(tr("Clear"), this, [&] { | ||||
|                             analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]); | ||||
|                             analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]")); | ||||
|                             ApplyConfiguration(); | ||||
|                             Settings::SaveProfile(ui->profile->currentIndex()); | ||||
|                         }); | ||||
|                         context_menu.addAction(tr("Restore Default"), [&] { | ||||
|                         context_menu.addAction(tr("Restore Default"), this, [&] { | ||||
|                             Common::ParamPackage params{InputCommon::GenerateKeyboardParam( | ||||
|                                 Config::default_analogs[analog_id][sub_button_id])}; | ||||
|                             SetAnalogButton(params, analogs_param[analog_id], | ||||
|  | @ -264,7 +266,7 @@ ConfigureInput::ConfigureInput(QWidget* parent) | |||
|                             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( | ||||
|                     this, tr("Information"), | ||||
|                     tr("After pressing OK, first move your joystick horizontally, " | ||||
|  | @ -272,7 +274,7 @@ ConfigureInput::ConfigureInput(QWidget* parent) | |||
|                     QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) { | ||||
|                 HandleClick( | ||||
|                     analog_map_stick[analog_id], | ||||
|                     [=](const Common::ParamPackage& params) { | ||||
|                     [this, analog_id](const Common::ParamPackage& params) { | ||||
|                         analogs_param[analog_id] = params; | ||||
|                         ApplyConfiguration(); | ||||
|                         Settings::SaveProfile(ui->profile->currentIndex()); | ||||
|  | @ -280,29 +282,31 @@ ConfigureInput::ConfigureInput(QWidget* parent) | |||
|                     InputCommon::Polling::DeviceType::Analog); | ||||
|             } | ||||
|         }); | ||||
|         connect(analog_map_deadzone_and_modifier_slider[analog_id], &QSlider::valueChanged, [=] { | ||||
|             const int slider_value = analog_map_deadzone_and_modifier_slider[analog_id]->value(); | ||||
|             const auto engine = analogs_param[analog_id].Get("engine", ""); | ||||
|             if (engine == "sdl" || engine == "gcpad") { | ||||
|                 analog_map_deadzone_and_modifier_slider_label[analog_id]->setText( | ||||
|                     tr("Deadzone: %1%").arg(slider_value)); | ||||
|                 analogs_param[analog_id].Set("deadzone", slider_value / 100.0f); | ||||
|             } else { | ||||
|                 analog_map_deadzone_and_modifier_slider_label[analog_id]->setText( | ||||
|                     tr("Modifier Scale: %1%").arg(slider_value)); | ||||
|                 analogs_param[analog_id].Set("modifier_scale", slider_value / 100.0f); | ||||
|             } | ||||
|             ApplyConfiguration(); | ||||
|             Settings::SaveProfile(ui->profile->currentIndex()); | ||||
|         }); | ||||
|         connect(analog_map_deadzone_and_modifier_slider[analog_id], &QSlider::valueChanged, this, | ||||
|                 [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", ""); | ||||
|                     if (engine == "sdl" || engine == "gcpad") { | ||||
|                         analog_map_deadzone_and_modifier_slider_label[analog_id]->setText( | ||||
|                             tr("Deadzone: %1%").arg(slider_value)); | ||||
|                         analogs_param[analog_id].Set("deadzone", slider_value / 100.0f); | ||||
|                     } else { | ||||
|                         analog_map_deadzone_and_modifier_slider_label[analog_id]->setText( | ||||
|                             tr("Modifier Scale: %1%").arg(slider_value)); | ||||
|                         analogs_param[analog_id].Set("modifier_scale", slider_value / 100.0f); | ||||
|                     } | ||||
|                     ApplyConfiguration(); | ||||
|                     Settings::SaveProfile(ui->profile->currentIndex()); | ||||
|                 }); | ||||
|     } | ||||
| 
 | ||||
|     // The Circle Mod button is common for both the sticks, so update the modifier settings
 | ||||
|     // for both the sticks.
 | ||||
|     connect(ui->buttonCircleMod, &QPushButton::clicked, [=]() { | ||||
|     connect(ui->buttonCircleMod, &QPushButton::clicked, this, [this]() { | ||||
|         HandleClick( | ||||
|             ui->buttonCircleMod, | ||||
|             [=](const Common::ParamPackage& params) { | ||||
|             [this](const Common::ParamPackage& params) { | ||||
|                 for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; | ||||
|                      analog_id++) { | ||||
|                     SetAnalogButton(params, analogs_param[analog_id], "modifier"); | ||||
|  | @ -312,10 +316,10 @@ ConfigureInput::ConfigureInput(QWidget* parent) | |||
|             }, | ||||
|             InputCommon::Polling::DeviceType::Button); | ||||
|     }); | ||||
|     connect(ui->buttonCircleMod, &QPushButton::customContextMenuRequested, | ||||
|     connect(ui->buttonCircleMod, &QPushButton::customContextMenuRequested, this, | ||||
|             [&](const QPoint& menu_location) { | ||||
|                 QMenu context_menu; | ||||
|                 context_menu.addAction(tr("Clear"), [&] { | ||||
|                 context_menu.addAction(tr("Clear"), this, [&] { | ||||
|                     for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; | ||||
|                          analog_id++) { | ||||
|                         analogs_param[analog_id].Erase("modifier"); | ||||
|  | @ -325,7 +329,7 @@ ConfigureInput::ConfigureInput(QWidget* parent) | |||
|                     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; | ||||
|                          analog_id++) { | ||||
|                         Common::ParamPackage params{InputCommon::GenerateKeyboardParam( | ||||
|  | @ -341,7 +345,7 @@ ConfigureInput::ConfigureInput(QWidget* parent) | |||
|                 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); | ||||
|         return motion_touch_dialog->exec(); | ||||
|     }); | ||||
|  | @ -356,18 +360,17 @@ ConfigureInput::ConfigureInput(QWidget* parent) | |||
|     connect(ui->buttonDelete, &QPushButton::clicked, this, &ConfigureInput::DeleteProfile); | ||||
|     connect(ui->buttonRename, &QPushButton::clicked, this, &ConfigureInput::RenameProfile); | ||||
| 
 | ||||
|     connect(ui->profile, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), | ||||
|             [this](int i) { | ||||
|                 ApplyConfiguration(); | ||||
|                 Settings::SaveProfile(Settings::values.current_input_profile_index); | ||||
|                 Settings::LoadProfile(i); | ||||
|                 LoadConfiguration(); | ||||
|             }); | ||||
|     connect(ui->profile, qOverload<int>(&QComboBox::currentIndexChanged), this, [this](int i) { | ||||
|         ApplyConfiguration(); | ||||
|         Settings::SaveProfile(Settings::values.current_input_profile_index); | ||||
|         Settings::LoadProfile(i); | ||||
|         LoadConfiguration(); | ||||
|     }); | ||||
| 
 | ||||
|     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; | ||||
|         for (auto& poller : device_pollers) { | ||||
|             params = poller->GetNextInput(); | ||||
|  | @ -554,7 +557,7 @@ void ConfigureInput::AutoMap() { | |||
|                                  QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel) { | ||||
|         return; | ||||
|     } | ||||
|     input_setter = [=](const Common::ParamPackage& params) { | ||||
|     input_setter = [this](const Common::ParamPackage& params) { | ||||
|         MapFromButton(params); | ||||
|         ApplyConfiguration(); | ||||
|         Settings::SaveProfile(ui->profile->currentIndex()); | ||||
|  |  | |||
|  | @ -47,6 +47,9 @@ CalibrationConfigurationDialog::CalibrationConfigurationDialog(QWidget* parent, | |||
|             case CalibrationConfigurationJob::Status::Completed: | ||||
|                 text = tr("Configuration completed!"); | ||||
|                 break; | ||||
|             default: | ||||
|                 LOG_ERROR(Frontend, "Unknown calibration status {}", status); | ||||
|                 break; | ||||
|             } | ||||
|             QMetaObject::invokeMethod(this, "UpdateLabelText", Q_ARG(QString, text)); | ||||
|             if (status == CalibrationConfigurationJob::Status::Completed) { | ||||
|  | @ -102,9 +105,9 @@ ConfigureMotionTouch::ConfigureMotionTouch(QWidget* parent) | |||
|            "style=\"text-decoration: underline; color:#039be5;\">Learn More</span></a>")); | ||||
| 
 | ||||
|     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; | ||||
|         for (auto& poller : device_pollers) { | ||||
|             params = poller->GetNextInput(); | ||||
|  | @ -202,7 +205,7 @@ void ConfigureMotionTouch::ConnectEvents() { | |||
|             [this]([[maybe_unused]] int index) { UpdateUiDisplay(); }); | ||||
|     connect(ui->touch_provider, qOverload<int>(&QComboBox::currentIndexChanged), this, | ||||
|             [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"), | ||||
|                                      tr("After pressing OK, press a button on the controller whose " | ||||
|                                         "motion you want to track."), | ||||
|  | @ -210,7 +213,7 @@ void ConfigureMotionTouch::ConnectEvents() { | |||
|             ui->motion_controller_button->setText(tr("[press button]")); | ||||
|             ui->motion_controller_button->setFocus(); | ||||
| 
 | ||||
|             input_setter = [=](const Common::ParamPackage& params) { | ||||
|             input_setter = [this](const Common::ParamPackage& params) { | ||||
|                 guid = params.Get("guid", "0"); | ||||
|                 port = params.Get("port", 0); | ||||
|             }; | ||||
|  |  | |||
|  | @ -511,7 +511,7 @@ void TouchScreenPreview::mouseMoveEvent(QMouseEvent* event) { | |||
|     } | ||||
|     const auto pos = MapToDeviceCoords(event->x(), event->y()); | ||||
|     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 { | ||||
|         coord_label->clear(); | ||||
|     } | ||||
|  | @ -572,7 +572,7 @@ bool TouchScreenPreview::eventFilter(QObject* obj, QEvent* event) { | |||
|             emit DotMoved(drag_state.dot->property(PropId).toInt(), *device_coord); | ||||
|             if (coord_label) { | ||||
|                 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; | ||||
|  |  | |||
|  | @ -9,7 +9,6 @@ | |||
| #include <QVBoxLayout> | ||||
| #include "citra_qt/debugger/graphics/graphics_breakpoints.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) | ||||
|     : 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 { | ||||
|     if (!index.isValid()) | ||||
|         return 0; | ||||
|     if (!index.isValid()) { | ||||
|         return {}; | ||||
|     } | ||||
| 
 | ||||
|     Qt::ItemFlags flags = Qt::ItemIsEnabled; | ||||
|     if (index.column() == 0) | ||||
|     if (index.column() == 0) { | ||||
|         flags |= Qt::ItemIsUserCheckable; | ||||
|     } | ||||
| 
 | ||||
|     return flags; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -14,7 +14,6 @@ | |||
| #include <QTreeView> | ||||
| #include <QVBoxLayout> | ||||
| #include "citra_qt/debugger/graphics/graphics_cmdlists.h" | ||||
| #include "citra_qt/util/spinbox.h" | ||||
| #include "citra_qt/util/util.h" | ||||
| #include "common/vector_math.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.texture2)) { | ||||
| 
 | ||||
|         unsigned texture_index; | ||||
|         [[maybe_unused]] u32 texture_index; | ||||
|         if (COMMAND_IN_RANGE(command_id, texturing.texture0)) { | ||||
|             texture_index = 0; | ||||
|         } else if (COMMAND_IN_RANGE(command_id, texturing.texture1)) { | ||||
|  |  | |||
|  | @ -34,12 +34,15 @@ void SurfacePicture::mousePressEvent(QMouseEvent* event) { | |||
|     if (!(event->buttons() & Qt::LeftButton)) | ||||
|         return; | ||||
| 
 | ||||
|     if (pixmap() == nullptr) | ||||
|     const QPixmap pixmap = this->pixmap(Qt::ReturnByValue); | ||||
|     if (pixmap.isNull()) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     if (surface_widget) | ||||
|         surface_widget->Pick(event->x() * pixmap()->width() / width(), | ||||
|                              event->y() * pixmap()->height() / height()); | ||||
|     if (surface_widget) { | ||||
|         surface_widget->Pick(event->x() * pixmap.width() / width(), | ||||
|                              event->y() * pixmap.height() / height()); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void SurfacePicture::mouseMoveEvent(QMouseEvent* event) { | ||||
|  | @ -314,57 +317,46 @@ void GraphicsSurfaceWidget::Pick(int x, int y) { | |||
|         case Format::RGBA8: { | ||||
|             auto value = Color::DecodeRGBA8(pixel) / 255.0f; | ||||
|             return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4") | ||||
|                 .arg(QString::number(value.r(), 'f', 2)) | ||||
|                 .arg(QString::number(value.g(), 'f', 2)) | ||||
|                 .arg(QString::number(value.b(), 'f', 2)) | ||||
|                 .arg(QString::number(value.a(), 'f', 2)); | ||||
|                 .arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2), | ||||
|                      QString::number(value.b(), 'f', 2), QString::number(value.a(), 'f', 2)); | ||||
|         } | ||||
|         case Format::RGB8: { | ||||
|             auto value = Color::DecodeRGB8(pixel) / 255.0f; | ||||
|             return QStringLiteral("Red: %1, Green: %2, Blue: %3") | ||||
|                 .arg(QString::number(value.r(), 'f', 2)) | ||||
|                 .arg(QString::number(value.g(), 'f', 2)) | ||||
|                 .arg(QString::number(value.b(), 'f', 2)); | ||||
|                 .arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2), | ||||
|                      QString::number(value.b(), 'f', 2)); | ||||
|         } | ||||
|         case Format::RGB5A1: { | ||||
|             auto value = Color::DecodeRGB5A1(pixel) / 255.0f; | ||||
|             return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4") | ||||
|                 .arg(QString::number(value.r(), 'f', 2)) | ||||
|                 .arg(QString::number(value.g(), 'f', 2)) | ||||
|                 .arg(QString::number(value.b(), 'f', 2)) | ||||
|                 .arg(QString::number(value.a(), 'f', 2)); | ||||
|                 .arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2), | ||||
|                      QString::number(value.b(), 'f', 2), QString::number(value.a(), 'f', 2)); | ||||
|         } | ||||
|         case Format::RGB565: { | ||||
|             auto value = Color::DecodeRGB565(pixel) / 255.0f; | ||||
|             return QStringLiteral("Red: %1, Green: %2, Blue: %3") | ||||
|                 .arg(QString::number(value.r(), 'f', 2)) | ||||
|                 .arg(QString::number(value.g(), 'f', 2)) | ||||
|                 .arg(QString::number(value.b(), 'f', 2)); | ||||
|                 .arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2), | ||||
|                      QString::number(value.b(), 'f', 2)); | ||||
|         } | ||||
|         case Format::RGBA4: { | ||||
|             auto value = Color::DecodeRGBA4(pixel) / 255.0f; | ||||
|             return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4") | ||||
|                 .arg(QString::number(value.r(), 'f', 2)) | ||||
|                 .arg(QString::number(value.g(), 'f', 2)) | ||||
|                 .arg(QString::number(value.b(), 'f', 2)) | ||||
|                 .arg(QString::number(value.a(), 'f', 2)); | ||||
|                 .arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2), | ||||
|                      QString::number(value.b(), 'f', 2), QString::number(value.a(), 'f', 2)); | ||||
|         } | ||||
|         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: { | ||||
|             auto value = Color::DecodeRG8(pixel) / 255.0f; | ||||
|             return QStringLiteral("Red: %1, Green: %2") | ||||
|                 .arg(QString::number(value.r(), 'f', 2)) | ||||
|                 .arg(QString::number(value.g(), 'f', 2)); | ||||
|                 .arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2)); | ||||
|         } | ||||
|         case Format::I8: | ||||
|             return QStringLiteral("Index: %1").arg(*pixel); | ||||
|         case Format::A8: | ||||
|             return QStringLiteral("Alpha: %1").arg(QString::number(*pixel / 255.0f, 'f', 2)); | ||||
|         case Format::IA4: | ||||
|             return QStringLiteral("Index: %1, Alpha: %2") | ||||
|                 .arg(*pixel & 0xF) | ||||
|                 .arg((*pixel & 0xF0) >> 4); | ||||
|             return QStringLiteral("Index: %1, Alpha: %2").arg(*pixel & 0xF, (*pixel & 0xF0) >> 4); | ||||
|         case Format::I4: { | ||||
|             u8 i = (*pixel >> ((offset % 2) ? 4 : 0)) & 0xF; | ||||
|             return QStringLiteral("Index: %1").arg(i); | ||||
|  | @ -390,8 +382,7 @@ void GraphicsSurfaceWidget::Pick(int x, int y) { | |||
|         case Format::X24S8: { | ||||
|             auto values = Color::DecodeD24S8(pixel); | ||||
|             return QStringLiteral("Depth: %1, Stencil: %2") | ||||
|                 .arg(QString::number(values[0] / (float)0xFFFFFF, 'f', 4)) | ||||
|                 .arg(values[1]); | ||||
|                 .arg(QString::number(values[0] / (float)0xFFFFFF, 'f', 4), values[1]); | ||||
|         } | ||||
|         case Format::Unknown: | ||||
|             return QStringLiteral("Unknown format"); | ||||
|  | @ -401,8 +392,8 @@ void GraphicsSurfaceWidget::Pick(int x, int y) { | |||
|     }; | ||||
| 
 | ||||
|     QString nibbles; | ||||
|     for (unsigned i = 0; i < nibbles_per_pixel; i++) { | ||||
|         unsigned nibble_index = i; | ||||
|     for (u32 i = 0; i < nibbles_per_pixel; i++) { | ||||
|         u32 nibble_index = i; | ||||
|         if (nibble_mode) { | ||||
|             nibble_index += (offset % 2) ? 0 : 1; | ||||
|         } | ||||
|  | @ -412,7 +403,7 @@ void GraphicsSurfaceWidget::Pick(int x, int y) { | |||
|     } | ||||
| 
 | ||||
|     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); | ||||
| } | ||||
| 
 | ||||
|  | @ -676,8 +667,8 @@ void GraphicsSurfaceWidget::SaveSurface() { | |||
|     } | ||||
| 
 | ||||
|     if (selected_filter == png_filter) { | ||||
|         const QPixmap* const pixmap = surface_picture_label->pixmap(); | ||||
|         ASSERT_MSG(pixmap != nullptr, "No pixmap set"); | ||||
|         const QPixmap pixmap = surface_picture_label->pixmap(Qt::ReturnByValue); | ||||
|         ASSERT_MSG(!pixmap.isNull(), "No pixmap set"); | ||||
| 
 | ||||
|         QFile file{filename}; | ||||
|         if (!file.open(QIODevice::WriteOnly)) { | ||||
|  | @ -685,7 +676,7 @@ void GraphicsSurfaceWidget::SaveSurface() { | |||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         if (!pixmap->save(&file, "PNG")) { | ||||
|         if (!pixmap.save(&file, "PNG")) { | ||||
|             QMessageBox::warning(this, tr("Error"), | ||||
|                                  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::Info opcode_info = opcode.GetInfo(); | ||||
|             const u32 operand_desc_id = opcode_info.type == OpCode::Type::MultiplyAdd | ||||
|                                             ? instr.mad.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 "
 | ||||
|             int kOpcodeColumnWidth = 8; | ||||
|  | @ -407,8 +407,8 @@ GraphicsVertexShaderWidget::GraphicsVertexShaderWidget( | |||
|                 static_cast<void (QSignalMapper::*)()>(&QSignalMapper::map)); | ||||
|         input_data_mapper->setMapping(input_data[i], i); | ||||
|     } | ||||
|     connect(input_data_mapper, static_cast<void (QSignalMapper::*)(int)>(&QSignalMapper::mapped), | ||||
|             this, &GraphicsVertexShaderWidget::OnInputAttributeChanged); | ||||
|     connect(input_data_mapper, &QSignalMapper::mappedInt, this, | ||||
|             &GraphicsVertexShaderWidget::OnInputAttributeChanged); | ||||
| 
 | ||||
|     auto main_widget = new QWidget; | ||||
|     auto main_layout = new QVBoxLayout; | ||||
|  | @ -514,8 +514,10 @@ void GraphicsVertexShaderWidget::Reload(bool replace_vertex_data, void* vertex_d | |||
|         info.code.push_back({instr}); | ||||
|     int num_attributes = shader_config.max_input_attribute_index + 1; | ||||
| 
 | ||||
|     for (auto pattern : shader_setup.swizzle_data) | ||||
|         info.swizzle_info.push_back({pattern}); | ||||
|     for (auto pattern : shader_setup.swizzle_data) { | ||||
|         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; | ||||
|     info.labels.insert({entry_point, "main"}); | ||||
|  |  | |||
|  | @ -57,6 +57,7 @@ QString IPCRecorderWidget::GetStatusStr(const IPCDebugger::RequestRecord& record | |||
|         return tr("HLE Unimplemented"); | ||||
|     default: | ||||
|         UNREACHABLE(); | ||||
|         return QLatin1String{}; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -160,7 +160,8 @@ void MicroProfileWidget::mouseReleaseEvent(QMouseEvent* 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(); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -114,7 +114,7 @@ void OptionSetDialog::InitializeUI(const std::string& initial_value) { | |||
|             ui->formatLabel->text().append(QStringLiteral("\n")); | ||||
|         } | ||||
|         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
 | ||||
|  |  | |||
|  | @ -169,8 +169,7 @@ GameListSearchField::GameListSearchField(GameList* parent) : QWidget{parent} { | |||
|  * @return true if the haystack contains all words of userinput | ||||
|  */ | ||||
| static bool ContainsAllWords(const QString& haystack, const QString& userinput) { | ||||
|     const QStringList userinput_split = | ||||
|         userinput.split(QLatin1Char{' '}, QString::SplitBehavior::SkipEmptyParts); | ||||
|     const QStringList userinput_split = userinput.split(QLatin1Char{' '}, Qt::SkipEmptyParts); | ||||
| 
 | ||||
|     return std::all_of(userinput_split.begin(), userinput_split.end(), | ||||
|                        [&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()); | ||||
| 
 | ||||
|     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); | ||||
|     }); | ||||
|     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); | ||||
|     }); | ||||
|     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); | ||||
|     }); | ||||
|     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); | ||||
|     }); | ||||
|     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}/", | ||||
|                                                  FileUtil::GetUserPath(FileUtil::UserPath::DumpDir), | ||||
|                                                  program_id))) { | ||||
|             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}/", | ||||
|                                                  FileUtil::GetUserPath(FileUtil::UserPath::LoadDir), | ||||
|                                                  program_id))) { | ||||
|             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}/", | ||||
|                                                  FileUtil::GetUserPath(FileUtil::UserPath::LoadDir), | ||||
|                                                  program_id))) { | ||||
|             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); }); | ||||
|     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); | ||||
|     }); | ||||
| }; | ||||
|  | @ -561,11 +560,11 @@ void GameList::AddCustomDirPopup(QMenu& context_menu, QModelIndex selected) { | |||
|     deep_scan->setCheckable(true); | ||||
|     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; | ||||
|         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); | ||||
|         item_model->invisibleRootItem()->removeRow(selected.row()); | ||||
|     }); | ||||
|  | @ -583,7 +582,7 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) { | |||
|     move_up->setEnabled(row > 0); | ||||
|     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(); | ||||
|         // swap the items in the settings
 | ||||
|         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); | ||||
|     }); | ||||
| 
 | ||||
|     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(); | ||||
|         // swap the items in the settings
 | ||||
|         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); | ||||
|     }); | ||||
| 
 | ||||
|     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); | ||||
|     }); | ||||
| } | ||||
|  | @ -640,7 +639,7 @@ void GameList::LoadCompatibilityList() { | |||
|     const QJsonDocument json = QJsonDocument::fromJson(content); | ||||
|     const QJsonArray arr = json.array(); | ||||
| 
 | ||||
|     for (const QJsonValue value : arr) { | ||||
|     for (const QJsonValue& value : arr) { | ||||
|         const QJsonObject game = value.toObject(); | ||||
|         const QString compatibility_key = QStringLiteral("compatibility"); | ||||
| 
 | ||||
|  | @ -652,7 +651,7 @@ void GameList::LoadCompatibilityList() { | |||
|         const QString directory = game[QStringLiteral("directory")].toString(); | ||||
|         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 QString id = id_object[QStringLiteral("id")].toString(); | ||||
| 
 | ||||
|  |  | |||
|  | @ -152,8 +152,8 @@ static void InitializeLogging() { | |||
| } | ||||
| 
 | ||||
| GMainWindow::GMainWindow() | ||||
|     : config(std::make_unique<Config>()), emu_thread(nullptr), | ||||
|       ui(std::make_unique<Ui::MainWindow>()) { | ||||
|     : ui{std::make_unique<Ui::MainWindow>()}, config{std::make_unique<Config>()}, emu_thread{ | ||||
|                                                                                       nullptr} { | ||||
|     InitializeLogging(); | ||||
|     Debugger::ToggleConsole(); | ||||
|     Settings::LogSettings(); | ||||
|  | @ -263,7 +263,7 @@ void GMainWindow::InitializeWidgets() { | |||
|     loading_screen = new LoadingScreen(this); | ||||
|     loading_screen->hide(); | ||||
|     ui->horizontalLayout->addWidget(loading_screen); | ||||
|     connect(loading_screen, &LoadingScreen::Hidden, [&] { | ||||
|     connect(loading_screen, &LoadingScreen::Hidden, this, [&] { | ||||
|         loading_screen->Clear(); | ||||
|         if (emulation_running) { | ||||
|             render_window->show(); | ||||
|  | @ -432,13 +432,13 @@ void GMainWindow::InitializeSaveStateMenuActions() { | |||
|         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(); | ||||
|         if (newest_slot != 0) { | ||||
|             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(); | ||||
|         actions_save_state[oldest_slot - 1]->trigger(); | ||||
|     }); | ||||
|  | @ -677,7 +677,7 @@ void GMainWindow::ConnectWidgetEvents() { | |||
|     connect(game_list_placeholder, &GameListPlaceholder::AddDirectory, this, | ||||
|             &GMainWindow::OnGameListAddDirectory); | ||||
|     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()); }); | ||||
| 
 | ||||
|     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_Save_Movie, &QAction::triggered, this, &GMainWindow::OnSaveMovie); | ||||
|     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] { | ||||
|         if (emulation_running) { | ||||
|             Core::System::GetInstance().frame_limiter.SetFrameAdvancing( | ||||
|  | @ -1413,7 +1413,7 @@ void GMainWindow::OnGameListDumpRomFS(QString game_path, u64 program_id) { | |||
|                     program_id | 0x0004000e00000000); | ||||
|     using FutureWatcher = QFutureWatcher<std::pair<Loader::ResultStatus, Loader::ResultStatus>>; | ||||
|     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] { | ||||
|                 dialog->hide(); | ||||
|                 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) { | ||||
|             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); | ||||
|             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.") | ||||
|                                   .arg(filename)); | ||||
|         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: | ||||
|         new_layout = Settings::LayoutOption::Default; | ||||
|         break; | ||||
|     default: | ||||
|         LOG_ERROR(Frontend, "Unknown layout option {}", Settings::values.layout_option); | ||||
|     } | ||||
| 
 | ||||
|     Settings::values.layout_option = new_layout; | ||||
|  | @ -1976,7 +1982,7 @@ void GMainWindow::OnCaptureScreenshot() { | |||
|     const QString filename = game_title.remove(QRegularExpression(QStringLiteral("[\\/:?\"<>|]"))); | ||||
|     const QString timestamp = | ||||
|         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); | ||||
|     OnStartGame(); | ||||
| } | ||||
|  | @ -2051,7 +2057,7 @@ void GMainWindow::UpdateStatusBar() { | |||
|         message_label_used_for_movie = true; | ||||
|         ui->action_Save_Movie->setEnabled(true); | ||||
|     } 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_used_for_movie = true; | ||||
|         ui->action_Save_Movie->setEnabled(false); | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <memory> | ||||
| #include <unordered_map> | ||||
| #include <unordered_set> | ||||
| #include <QDialog> | ||||
| #include <QSortFilterProxyModel> | ||||
|  |  | |||
|  | @ -7,7 +7,6 @@ | |||
| #include <QIcon> | ||||
| #include <QMessageBox> | ||||
| #include <QStandardItemModel> | ||||
| #include "citra_qt/game_list.h" | ||||
| #include "citra_qt/multiplayer/client_room.h" | ||||
| #include "citra_qt/multiplayer/direct_connect.h" | ||||
| #include "citra_qt/multiplayer/host_room.h" | ||||
|  | @ -16,7 +15,6 @@ | |||
| #include "citra_qt/multiplayer/state.h" | ||||
| #include "citra_qt/uisettings.h" | ||||
| #include "citra_qt/util/clickable_label.h" | ||||
| #include "common/announce_multiplayer_room.h" | ||||
| #include "common/logging/log.h" | ||||
| 
 | ||||
| MultiplayerState::MultiplayerState(QWidget* parent, QStandardItemModel* game_list_model, | ||||
|  | @ -231,8 +229,9 @@ bool MultiplayerState::OnCloseRoom() { | |||
|         if (room->GetState() != Network::Room::State::Open) { | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         // Save ban list
 | ||||
|         UISettings::values.ban_list = std::move(room->GetBanList()); | ||||
|         UISettings::values.ban_list = room->GetBanList(); | ||||
| 
 | ||||
|         room->Destroy(); | ||||
|         announce_multiplayer_session->Stop(); | ||||
|  |  | |||
|  | @ -78,6 +78,7 @@ add_library(common STATIC | |||
|     logging/backend.h | ||||
|     logging/filter.cpp | ||||
|     logging/filter.h | ||||
|     logging/formatter.h | ||||
|     logging/log.h | ||||
|     logging/text_formatter.cpp | ||||
|     logging/text_formatter.h | ||||
|  |  | |||
|  | @ -31,8 +31,10 @@ | |||
| #endif | ||||
| 
 | ||||
| // 64 bit offsets for MSVC and MinGW. MinGW also needs this for using _wstat64
 | ||||
| #ifndef __MINGW64__ | ||||
| #define stat _stat64 | ||||
| #define fstat _fstat64 | ||||
| #endif | ||||
| 
 | ||||
| #else | ||||
| #ifdef __APPLE__ | ||||
|  |  | |||
|  | @ -65,12 +65,16 @@ private: | |||
| 
 | ||||
| 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 { | ||||
| public: | ||||
|     MemoryRef() = default; | ||||
|     MemoryRef(std::nullptr_t) {} | ||||
| 
 | ||||
|     MemoryRef(std::shared_ptr<BackingMem> backing_mem_) | ||||
|         : backing_mem(std::move(backing_mem_)), offset(0) { | ||||
|         Init(); | ||||
|  | @ -80,30 +84,38 @@ public: | |||
|         ASSERT(offset <= backing_mem->GetSize()); | ||||
|         Init(); | ||||
|     } | ||||
| 
 | ||||
|     explicit operator bool() const { | ||||
|         return cptr != nullptr; | ||||
|     } | ||||
| 
 | ||||
|     operator u8*() { | ||||
|         return cptr; | ||||
|     } | ||||
| 
 | ||||
|     u8* GetPtr() { | ||||
|         return cptr; | ||||
|     } | ||||
| 
 | ||||
|     operator const u8*() const { | ||||
|         return cptr; | ||||
|     } | ||||
| 
 | ||||
|     const u8* GetPtr() const { | ||||
|         return cptr; | ||||
|     } | ||||
| 
 | ||||
|     std::size_t GetSize() const { | ||||
|         return csize; | ||||
|     } | ||||
| 
 | ||||
|     MemoryRef& operator+=(u32 offset_by) { | ||||
|         ASSERT(offset_by < csize); | ||||
|         offset += offset_by; | ||||
|         Init(); | ||||
|         return *this; | ||||
|     } | ||||
| 
 | ||||
|     MemoryRef operator+(u32 offset_by) const { | ||||
|         ASSERT(offset_by < csize); | ||||
|         return MemoryRef(backing_mem, offset + offset_by); | ||||
|  |  | |||
|  | @ -23,12 +23,3 @@ typedef void* HANDLE; | |||
| #include <microprofile.h> | ||||
| 
 | ||||
| #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: | ||||
|         UNREACHABLE_MSG("Unknown VFP system register: {}", reg); | ||||
|     } | ||||
| 
 | ||||
|     return UINT_MAX; | ||||
| } | ||||
| 
 | ||||
|  | @ -261,6 +262,8 @@ u32 ARM_Dynarmic::GetCP15Register(CP15Register reg) const { | |||
|     default: | ||||
|         UNREACHABLE_MSG("Unknown CP15 register: {}", reg); | ||||
|     } | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| 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
 | ||||
|     ARM_INST_PTR inst_base = nullptr; | ||||
|     TransExtData ret = TransExtData::NON_BRANCH; | ||||
|     int size = 0; // instruction size of basic block
 | ||||
|     bb_start = trans_cache_buf_top; | ||||
| 
 | ||||
|     u32 phys_addr = addr; | ||||
|     u32 pc_start = cpu->Reg[15]; | ||||
| 
 | ||||
|     while (ret == TransExtData::NON_BRANCH) { | ||||
|         unsigned int inst_size = InterpreterTranslateInstruction(cpu, phys_addr, inst_base); | ||||
| 
 | ||||
|         size++; | ||||
| 
 | ||||
|         u32 inst_size = InterpreterTranslateInstruction(cpu, phys_addr, inst_base); | ||||
|         phys_addr += inst_size; | ||||
| 
 | ||||
|         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
 | ||||
| // clunky switch statement.
 | ||||
| #if defined __GNUC__ || defined __clang__ | ||||
| #if defined __GNUC__ || (defined __clang__ && !defined _MSC_VER) | ||||
| #define GOTO_NEXT_INST                                                                             \ | ||||
|     GDB_BP_CHECK;                                                                                  \ | ||||
|     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) { | ||||
|         u32 except; | ||||
|         char type; | ||||
|         [[maybe_unused]] char type; | ||||
| 
 | ||||
|         type = (fop->flags & OP_SD) ? 's' : 'd'; | ||||
|         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) { | ||||
|         s32 m = vfp_get_float(state, sm); | ||||
|         u32 except; | ||||
|         char type; | ||||
|         [[maybe_unused]] char type; | ||||
| 
 | ||||
|         type = (fop->flags & OP_DD) ? 'd' : 's'; | ||||
|         if (op == FOP_EXT) | ||||
|  |  | |||
|  | @ -47,7 +47,7 @@ void CheatEngine::AddCheat(const std::shared_ptr<CheatBase>& cheat) { | |||
| 
 | ||||
| void CheatEngine::RemoveCheat(int index) { | ||||
|     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); | ||||
|         return; | ||||
|     } | ||||
|  | @ -56,7 +56,7 @@ void CheatEngine::RemoveCheat(int index) { | |||
| 
 | ||||
| void CheatEngine::UpdateCheat(int index, const std::shared_ptr<CheatBase>& new_cheat) { | ||||
|     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); | ||||
|         return; | ||||
|     } | ||||
|  |  | |||
|  | @ -301,10 +301,6 @@ private: | |||
|     std::vector<std::shared_ptr<Timer>> timers; | ||||
|     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
 | ||||
|     // destructor side effects.
 | ||||
|     bool event_queue_locked = false; | ||||
|  |  | |||
|  | @ -849,14 +849,14 @@ static void ReadMemory() { | |||
|         SendReply("E01"); | ||||
|     } | ||||
| 
 | ||||
|     if (!Memory::IsValidVirtualAddress(*Core::System::GetInstance().Kernel().GetCurrentProcess(), | ||||
|                                        addr)) { | ||||
|     auto& memory = Core::System::GetInstance().Memory(); | ||||
|     if (!memory.IsValidVirtualAddress(*Core::System::GetInstance().Kernel().GetCurrentProcess(), | ||||
|                                       addr)) { | ||||
|         return SendReply("E00"); | ||||
|     } | ||||
| 
 | ||||
|     std::vector<u8> data(len); | ||||
|     Core::System::GetInstance().Memory().ReadBlock( | ||||
|         *Core::System::GetInstance().Kernel().GetCurrentProcess(), addr, data.data(), len); | ||||
|     memory.ReadBlock(addr, data.data(), len); | ||||
| 
 | ||||
|     MemToGdbHex(reply, data.data(), len); | ||||
|     reply[len * 2] = '\0'; | ||||
|  | @ -873,16 +873,16 @@ static void WriteMemory() { | |||
|     auto len_pos = std::find(start_offset, command_buffer + command_length, ':'); | ||||
|     u32 len = HexToInt(start_offset, static_cast<u32>(len_pos - start_offset)); | ||||
| 
 | ||||
|     if (!Memory::IsValidVirtualAddress(*Core::System::GetInstance().Kernel().GetCurrentProcess(), | ||||
|                                        addr)) { | ||||
|     auto& memory = Core::System::GetInstance().Memory(); | ||||
|     if (!memory.IsValidVirtualAddress(*Core::System::GetInstance().Kernel().GetCurrentProcess(), | ||||
|                                       addr)) { | ||||
|         return SendReply("E00"); | ||||
|     } | ||||
| 
 | ||||
|     std::vector<u8> data(len); | ||||
| 
 | ||||
|     GdbHexToMem(data.data(), len_pos + 1, len); | ||||
|     Core::System::GetInstance().Memory().WriteBlock( | ||||
|         *Core::System::GetInstance().Kernel().GetCurrentProcess(), addr, data.data(), len); | ||||
|     memory.WriteBlock(addr, data.data(), len); | ||||
|     Core::GetRunningCore().ClearInstructionCache(); | ||||
|     SendReply("OK"); | ||||
| } | ||||
|  |  | |||
|  | @ -80,7 +80,7 @@ private: | |||
|     std::shared_ptr<Callback> timeout_callback; | ||||
| 
 | ||||
|     void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread, | ||||
|                 std::shared_ptr<WaitObject> object); | ||||
|                 std::shared_ptr<WaitObject> object) override; | ||||
| 
 | ||||
|     class DummyCallback : public WakeupCallback { | ||||
|     public: | ||||
|  |  | |||
|  | @ -138,10 +138,10 @@ ResultCode TranslateCommandBuffer(Kernel::KernelSystem& kernel, Memory::MemorySy | |||
|             u32 size = static_cast<u32>(descInfo.size); | ||||
|             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 num_pages = | ||||
|                 Common::AlignUp(page_offset + size, Memory::PAGE_SIZE) >> Memory::PAGE_BITS; | ||||
|             u32 num_pages = Common::AlignUp(page_offset + size, Memory::CITRA_PAGE_SIZE) >> | ||||
|                             Memory::CITRA_PAGE_BITS; | ||||
| 
 | ||||
|             // Skip when the size is zero and num_pages == 0
 | ||||
|             if (size == 0) { | ||||
|  | @ -171,8 +171,8 @@ ResultCode TranslateCommandBuffer(Kernel::KernelSystem& kernel, Memory::MemorySy | |||
|                                      found->target_address, size); | ||||
|                 } | ||||
| 
 | ||||
|                 VAddr prev_reserve = page_start - Memory::PAGE_SIZE; | ||||
|                 VAddr next_reserve = page_start + num_pages * Memory::PAGE_SIZE; | ||||
|                 VAddr prev_reserve = page_start - Memory::CITRA_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& 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); | ||||
| 
 | ||||
|                 // Unmap the buffer and guard pages from the source process
 | ||||
|                 ResultCode result = src_process->vm_manager.UnmapRange( | ||||
|                     page_start - Memory::PAGE_SIZE, (num_pages + 2) * Memory::PAGE_SIZE); | ||||
|                 ResultCode result = | ||||
|                     src_process->vm_manager.UnmapRange(page_start - Memory::CITRA_PAGE_SIZE, | ||||
|                                                        (num_pages + 2) * Memory::CITRA_PAGE_SIZE); | ||||
|                 ASSERT(result == RESULT_SUCCESS); | ||||
| 
 | ||||
|                 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
 | ||||
|             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( | ||||
|                 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::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); | ||||
| 
 | ||||
|             // 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
 | ||||
|             AddressMapping mapping; | ||||
|             mapping.address = descriptor << 12; | ||||
|             mapping.size = Memory::PAGE_SIZE; | ||||
|             mapping.size = Memory::CITRA_PAGE_SIZE; | ||||
|             mapping.read_only = false; | ||||
|             mapping.unk_flag = false; | ||||
| 
 | ||||
|  | @ -265,7 +265,7 @@ ResultCode Process::HeapFree(VAddr target, u32 size) { | |||
| 
 | ||||
|     // Free heaps block by block
 | ||||
|     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); | ||||
|     } | ||||
| 
 | ||||
|  | @ -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)); | ||||
|     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 = | ||||
|             vm_manager.MapBackingMemory(interval_target, backing_memory, block_size, target_state); | ||||
|         ASSERT(target_vma.Succeeded()); | ||||
|  |  | |||
|  | @ -10,7 +10,6 @@ | |||
| #include "common/logging/log.h" | ||||
| #include "common/microprofile.h" | ||||
| #include "common/scm_rev.h" | ||||
| #include "common/scope_exit.h" | ||||
| #include "core/arm/arm_interface.h" | ||||
| #include "core/core.h" | ||||
| #include "core/core_timing.h" | ||||
|  | @ -39,7 +38,6 @@ | |||
| #include "core/hle/kernel/wait_object.h" | ||||
| #include "core/hle/lock.h" | ||||
| #include "core/hle/result.h" | ||||
| #include "core/hle/service/service.h" | ||||
| 
 | ||||
| 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}", | ||||
|               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; | ||||
|     } | ||||
|     if ((size & Memory::PAGE_MASK) != 0) { | ||||
|     if ((size & Memory::CITRA_PAGE_MASK) != 0) { | ||||
|         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
 | ||||
| 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; | ||||
| 
 | ||||
|     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) { | ||||
|     Thread* thread = kernel.GetCurrentThreadManager().GetCurrentThread(); | ||||
| 
 | ||||
|     if (!Memory::IsValidVirtualAddress(*kernel.GetCurrentProcess(), handles_address)) | ||||
|     if (!memory.IsValidVirtualAddress(*kernel.GetCurrentProcess(), handles_address)) | ||||
|         return ERR_INVALID_POINTER; | ||||
| 
 | ||||
|     // 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.
 | ||||
| ResultCode SVC::ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_count, | ||||
|                                 Handle reply_target) { | ||||
|     if (!Memory::IsValidVirtualAddress(*kernel.GetCurrentProcess(), handles_address)) | ||||
|     if (!memory.IsValidVirtualAddress(*kernel.GetCurrentProcess(), handles_address)) | ||||
|         return ERR_INVALID_POINTER; | ||||
| 
 | ||||
|     // 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
 | ||||
| ResultCode SVC::CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 my_permission, | ||||
|                                   u32 other_permission) { | ||||
|     if (size % Memory::PAGE_SIZE != 0) | ||||
|     if (size % Memory::CITRA_PAGE_SIZE != 0) | ||||
|         return ERR_MISALIGNED_SIZE; | ||||
| 
 | ||||
|     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; | ||||
| } | ||||
| 
 | ||||
| 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); | ||||
|     if (offset < str_size) { | ||||
|         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
 | ||||
|         // what's the difference between them.
 | ||||
|         *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"); | ||||
|             return ERR_MISALIGNED_SIZE; | ||||
|         } | ||||
|  |  | |||
|  | @ -105,9 +105,9 @@ void Thread::Stop() { | |||
|     ReleaseThreadMutexes(this); | ||||
| 
 | ||||
|     // 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 = | ||||
|         ((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()); | ||||
|     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
 | ||||
| 
 | ||||
|     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); | ||||
|         // TODO: Verify error
 | ||||
|         return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, | ||||
|  | @ -374,13 +373,13 @@ ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread( | |||
|         auto memory_region = GetMemoryRegion(MemoryRegion::BASE); | ||||
| 
 | ||||
|         // 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) { | ||||
|             LOG_ERROR(Kernel_SVC, | ||||
|                       "Not enough space in region to allocate a new TLS page for thread"); | ||||
|             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
 | ||||
|         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.
 | ||||
|         vm_manager.MapBackingMemory( | ||||
|             Memory::TLS_AREA_VADDR + static_cast<VAddr>(available_page) * Memory::PAGE_SIZE, | ||||
|             memory.GetFCRAMRef(*offset), Memory::PAGE_SIZE, MemoryState::Locked); | ||||
|             Memory::TLS_AREA_VADDR + static_cast<VAddr>(available_page) * Memory::CITRA_PAGE_SIZE, | ||||
|             memory.GetFCRAMRef(*offset), Memory::CITRA_PAGE_SIZE, MemoryState::Locked); | ||||
|     } | ||||
| 
 | ||||
|     // Mark the slot as used
 | ||||
|     tls_slots[available_page].set(available_slot); | ||||
|     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; | ||||
| 
 | ||||
|     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) { | ||||
|     ASSERT_MSG((size & Memory::PAGE_MASK) == 0, "non-page aligned size: {:#10X}", size); | ||||
|     ASSERT_MSG((base & Memory::PAGE_MASK) == 0, "non-page aligned base: {:#010X}", base); | ||||
|     ASSERT_MSG((size & Memory::CITRA_PAGE_MASK) == 0, "non-page aligned size: {:#10X}", size); | ||||
|     ASSERT_MSG((base & Memory::CITRA_PAGE_MASK) == 0, "non-page aligned base: {:#010X}", base); | ||||
| 
 | ||||
|     VMAIter vma_handle = StripIterConstness(FindVMA(base)); | ||||
|     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) { | ||||
|     ASSERT_MSG((size & Memory::PAGE_MASK) == 0, "non-page aligned size: {:#10X}", size); | ||||
|     ASSERT_MSG((target & Memory::PAGE_MASK) == 0, "non-page aligned base: {:#010X}", target); | ||||
|     ASSERT_MSG((size & Memory::CITRA_PAGE_MASK) == 0, "non-page aligned size: {:#10X}", size); | ||||
|     ASSERT_MSG((target & Memory::CITRA_PAGE_MASK) == 0, "non-page aligned base: {:#010X}", target); | ||||
| 
 | ||||
|     const VAddr target_end = target + size; | ||||
|     ASSERT(target_end >= target); | ||||
|  |  | |||
|  | @ -17,12 +17,9 @@ | |||
| #include "core/file_sys/errors.h" | ||||
| #include "core/file_sys/ncch_container.h" | ||||
| #include "core/file_sys/title_metadata.h" | ||||
| #include "core/hle/ipc.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/errors.h" | ||||
| #include "core/hle/kernel/handle_table.h" | ||||
| #include "core/hle/kernel/server_session.h" | ||||
| #include "core/hle/kernel/session.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); | ||||
| 
 | ||||
|     u32 content_read = 0; | ||||
|     FileSys::TitleMetadata tmd; | ||||
|     if (tmd.Load(tmd_path) == Loader::ResultStatus::Success) { | ||||
|         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)); | ||||
|             write_offset += sizeof(ContentInfo); | ||||
|             content_read++; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,7 +2,6 @@ | |||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include "common/common_paths.h" | ||||
| #include "core/core.h" | ||||
| #include "core/hle/applets/applet.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::array<AppletTitleData, NumApplets> applet_titleids = {{ | ||||
|     {AppletId::HomeMenu, AppletId::None, 0x4003000008202, 0x4003000008F02, 0x4003000009802, | ||||
|      0x4003000008202, 0x400300000A102, 0x400300000A902, 0x400300000B102}, | ||||
|     {AppletId::AlternateMenu, AppletId::None, 0x4003000008102, 0x4003000008102, 0x4003000008102, | ||||
|      0x4003000008102, 0x4003000008102, 0x4003000008102, 0x4003000008102}, | ||||
|     {AppletId::Camera, AppletId::None, 0x4003000008402, 0x4003000009002, 0x4003000009902, | ||||
|      0x4003000008402, 0x400300000A202, 0x400300000AA02, 0x400300000B202}, | ||||
|     {AppletId::FriendList, AppletId::None, 0x4003000008D02, 0x4003000009602, 0x4003000009F02, | ||||
|      0x4003000008D02, 0x400300000A702, 0x400300000AF02, 0x400300000B702}, | ||||
|     {AppletId::GameNotes, AppletId::None, 0x4003000008702, 0x4003000009302, 0x4003000009C02, | ||||
|      0x4003000008702, 0x400300000A502, 0x400300000AD02, 0x400300000B502}, | ||||
|     {AppletId::InternetBrowser, AppletId::None, 0x4003000008802, 0x4003000009402, 0x4003000009D02, | ||||
|      0x4003000008802, 0x400300000A602, 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}, | ||||
|     {{AppletId::HomeMenu, AppletId::None}, | ||||
|      {0x4003000008202, 0x4003000008F02, 0x4003000009802, 0x4003000008202, 0x400300000A102, | ||||
|       0x400300000A902, 0x400300000B102}}, | ||||
|     {{AppletId::AlternateMenu, AppletId::None}, | ||||
|      {0x4003000008102, 0x4003000008102, 0x4003000008102, 0x4003000008102, 0x4003000008102, | ||||
|       0x4003000008102, 0x4003000008102}}, | ||||
|     {{AppletId::Camera, AppletId::None}, | ||||
|      {0x4003000008402, 0x4003000009002, 0x4003000009902, 0x4003000008402, 0x400300000A202, | ||||
|       0x400300000AA02, 0x400300000B202}}, | ||||
|     {{AppletId::FriendList, AppletId::None}, | ||||
|      {0x4003000008D02, 0x4003000009602, 0x4003000009F02, 0x4003000008D02, 0x400300000A702, | ||||
|       0x400300000AF02, 0x400300000B702}}, | ||||
|     {{AppletId::GameNotes, AppletId::None}, | ||||
|      {0x4003000008702, 0x4003000009302, 0x4003000009C02, 0x4003000008702, 0x400300000A502, | ||||
|       0x400300000AD02, 0x400300000B502}}, | ||||
|     {{AppletId::InternetBrowser, AppletId::None}, | ||||
|      {0x4003000008802, 0x4003000009402, 0x4003000009D02, 0x4003000008802, 0x400300000A602, | ||||
|       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
 | ||||
|     {AppletId::MiiversePost, AppletId::None, 0x400300000BA02, 0x400300000BA02, 0x400300000BA02, | ||||
|      0x400300000BA02, 0x400300000BA02, 0x400300000BA02, 0x400300000BA02}, | ||||
|     {{AppletId::MiiversePost, AppletId::None}, | ||||
|      {0x400300000BA02, 0x400300000BA02, 0x400300000BA02, 0x400300000BA02, 0x400300000BA02, | ||||
|       0x400300000BA02, 0x400300000BA02}}, | ||||
|     // {AppletId::MiiversePost, AppletId::None, 0x4003000008302, 0x4003000008B02, 0x400300000BA02,
 | ||||
|     //  0x4003000008302, 0x0, 0x0, 0x0},
 | ||||
|     {AppletId::AmiiboSettings, AppletId::None, 0x4003000009502, 0x4003000009E02, 0x400300000B902, | ||||
|      0x4003000009502, 0x0, 0x4003000008C02, 0x400300000BF02}, | ||||
|     {AppletId::SoftwareKeyboard1, AppletId::SoftwareKeyboard2, 0x400300000C002, 0x400300000C802, | ||||
|      0x400300000D002, 0x400300000C002, 0x400300000D802, 0x400300000DE02, 0x400300000E402}, | ||||
|     {AppletId::Ed1, AppletId::Ed2, 0x400300000C102, 0x400300000C902, 0x400300000D102, | ||||
|      0x400300000C102, 0x400300000D902, 0x400300000DF02, 0x400300000E502}, | ||||
|     {AppletId::PnoteApp, AppletId::PnoteApp2, 0x400300000C302, 0x400300000CB02, 0x400300000D302, | ||||
|      0x400300000C302, 0x400300000DB02, 0x400300000E102, 0x400300000E702}, | ||||
|     {AppletId::SnoteApp, AppletId::SnoteApp2, 0x400300000C402, 0x400300000CC02, 0x400300000D402, | ||||
|      0x400300000C402, 0x400300000DC02, 0x400300000E202, 0x400300000E802}, | ||||
|     {AppletId::Error, AppletId::Error2, 0x400300000C502, 0x400300000C502, 0x400300000C502, | ||||
|      0x400300000C502, 0x400300000CF02, 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}, | ||||
|     {{AppletId::AmiiboSettings, AppletId::None}, | ||||
|      {0x4003000009502, 0x4003000009E02, 0x400300000B902, 0x4003000009502, 0x0, 0x4003000008C02, | ||||
|       0x400300000BF02}}, | ||||
|     {{AppletId::SoftwareKeyboard1, AppletId::SoftwareKeyboard2}, | ||||
|      {0x400300000C002, 0x400300000C802, 0x400300000D002, 0x400300000C002, 0x400300000D802, | ||||
|       0x400300000DE02, 0x400300000E402}}, | ||||
|     {{AppletId::Ed1, AppletId::Ed2}, | ||||
|      {0x400300000C102, 0x400300000C902, 0x400300000D102, 0x400300000C102, 0x400300000D902, | ||||
|       0x400300000DF02, 0x400300000E502}}, | ||||
|     {{AppletId::PnoteApp, AppletId::PnoteApp2}, | ||||
|      {0x400300000C302, 0x400300000CB02, 0x400300000D302, 0x400300000C302, 0x400300000DB02, | ||||
|       0x400300000E102, 0x400300000E702}}, | ||||
|     {{AppletId::SnoteApp, AppletId::SnoteApp2}, | ||||
|      {0x400300000C402, 0x400300000CC02, 0x400300000D402, 0x400300000C402, 0x400300000DC02, | ||||
|       0x400300000E202, 0x400300000E802}}, | ||||
|     {{AppletId::Error, AppletId::Error2}, | ||||
|      {0x400300000C502, 0x400300000C502, 0x400300000C502, 0x400300000C502, 0x400300000CF02, | ||||
|       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
 | ||||
| }}; | ||||
| 
 | ||||
|  |  | |||
|  | @ -10,7 +10,6 @@ | |||
| #include <cryptopp/osrng.h> | ||||
| #include <cryptopp/sha.h> | ||||
| #include "common/archives.h" | ||||
| #include "common/common_paths.h" | ||||
| #include "common/file_util.h" | ||||
| #include "common/logging/log.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 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 UsernameBlock CONSOLE_USERNAME_BLOCK{u"CITRA", 0, 0}; | ||||
| 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) { | ||||
|     IPC::RequestParser rp(ctx, 0x06, 0, 0); | ||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||||
|     u32 data; | ||||
|     u32 data{}; | ||||
| 
 | ||||
|     // TODO(Subv): Find out the correct error codes
 | ||||
|     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) { | ||||
|     void* pointer; | ||||
|     void* pointer = nullptr; | ||||
|     CASCADE_RESULT(pointer, GetConfigInfoBlockPointer(block_id, size, flag)); | ||||
|     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) { | ||||
|     void* pointer; | ||||
|     void* pointer = nullptr; | ||||
|     CASCADE_RESULT(pointer, GetConfigInfoBlockPointer(block_id, size, flag)); | ||||
|     memcpy(pointer, input, size); | ||||
|     return RESULT_SUCCESS; | ||||
|  | @ -701,7 +700,7 @@ void Module::SetSystemLanguage(SystemLanguage language) { | |||
| } | ||||
| 
 | ||||
| SystemLanguage Module::GetSystemLanguage() { | ||||
|     u8 block; | ||||
|     u8 block{}; | ||||
|     GetConfigInfoBlock(LanguageBlockID, sizeof(block), 8, &block); | ||||
|     return static_cast<SystemLanguage>(block); | ||||
| } | ||||
|  | @ -712,7 +711,7 @@ void Module::SetSoundOutputMode(SoundOutputMode mode) { | |||
| } | ||||
| 
 | ||||
| SoundOutputMode Module::GetSoundOutputMode() { | ||||
|     u8 block; | ||||
|     u8 block{}; | ||||
|     GetConfigInfoBlock(SoundOutputModeBlockID, sizeof(block), 8, &block); | ||||
|     return static_cast<SoundOutputMode>(block); | ||||
| } | ||||
|  | @ -723,7 +722,7 @@ void Module::SetCountryCode(u8 country_code) { | |||
| } | ||||
| 
 | ||||
| u8 Module::GetCountryCode() { | ||||
|     ConsoleCountryInfo block; | ||||
|     ConsoleCountryInfo block{}; | ||||
|     GetConfigInfoBlock(CountryInfoBlockID, sizeof(block), 8, &block); | ||||
|     return block.country_code; | ||||
| } | ||||
|  | @ -734,7 +733,7 @@ void Module::SetCountryInfo(u8 country_code, u8 state_code) { | |||
| } | ||||
| 
 | ||||
| u8 Module::GetStateCode() { | ||||
|     ConsoleCountryInfo block; | ||||
|     ConsoleCountryInfo block{}; | ||||
|     GetConfigInfoBlock(CountryInfoBlockID, sizeof(block), 8, &block); | ||||
|     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) { | ||||
|     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>(); | ||||
|     channel_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[7] = 0; | ||||
|         break; | ||||
|     default: | ||||
|         LOG_ERROR(Service_DSP, "Unknown pipe {}", pipe); | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     system.DSP().PipeWrite(pipe, buffer); | ||||
|  |  | |||
|  | @ -884,6 +884,8 @@ ResultVal<u16> FS_USER::GetSpecialContentIndexFromTMD(MediaType media_type, u64 | |||
|     default: | ||||
|         ASSERT(false); | ||||
|     } | ||||
| 
 | ||||
|     return ResultCode(-1); | ||||
| } | ||||
| 
 | ||||
| FS_USER::FS_USER(Core::System& system) | ||||
|  |  | |||
|  | @ -8,9 +8,7 @@ | |||
| #include "common/microprofile.h" | ||||
| #include "common/swap.h" | ||||
| #include "core/core.h" | ||||
| #include "core/hle/ipc.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_page.h" | ||||
| #include "core/hle/result.h" | ||||
|  | @ -83,7 +81,9 @@ u32 GSP_GPU::GetUnusedThreadId() const { | |||
|         if (!used_thread_ids[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
 | ||||
|  |  | |||
|  | @ -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; | ||||
|     SetField(FixedSize, fixed_size); | ||||
|  | @ -1525,8 +1525,8 @@ std::tuple<VAddr, u32> CROHelper::GetExecutablePages() const { | |||
|         SegmentEntry entry; | ||||
|         GetEntry(system.Memory(), i, entry); | ||||
|         if (entry.type == SegmentType::Code && entry.size != 0) { | ||||
|             VAddr begin = Common::AlignDown(entry.offset, Memory::PAGE_SIZE); | ||||
|             VAddr end = Common::AlignUp(entry.offset + entry.size, Memory::PAGE_SIZE); | ||||
|             VAddr begin = Common::AlignDown(entry.offset, Memory::CITRA_PAGE_SIZE); | ||||
|             VAddr end = Common::AlignUp(entry.offset + entry.size, Memory::CITRA_PAGE_SIZE); | ||||
|             return std::make_tuple(begin, end - begin); | ||||
|         } | ||||
|     } | ||||
|  |  | |||
|  | @ -87,19 +87,19 @@ void RO::Initialize(Kernel::HLERequestContext& ctx) { | |||
|         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"); | ||||
|         rb.Push(ERROR_MISALIGNED_ADDRESS); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     if (crs_address & Memory::PAGE_MASK) { | ||||
|     if (crs_address & Memory::CITRA_PAGE_MASK) { | ||||
|         LOG_ERROR(Service_LDR, "CRS mapping address is not aligned"); | ||||
|         rb.Push(ERROR_MISALIGNED_ADDRESS); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     if (crs_size & Memory::PAGE_MASK) { | ||||
|     if (crs_size & Memory::CITRA_PAGE_MASK) { | ||||
|         LOG_ERROR(Service_LDR, "CRS size is not aligned"); | ||||
|         rb.Push(ERROR_MISALIGNED_SIZE); | ||||
|         return; | ||||
|  | @ -207,21 +207,21 @@ void RO::LoadCRO(Kernel::HLERequestContext& ctx, bool link_on_load_bug_fix) { | |||
|         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"); | ||||
|         rb.Push(ERROR_MISALIGNED_ADDRESS); | ||||
|         rb.Push<u32>(0); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     if (cro_address & Memory::PAGE_MASK) { | ||||
|     if (cro_address & Memory::CITRA_PAGE_MASK) { | ||||
|         LOG_ERROR(Service_LDR, "CRO mapping address is not aligned"); | ||||
|         rb.Push(ERROR_MISALIGNED_ADDRESS); | ||||
|         rb.Push<u32>(0); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     if (cro_size & Memory::PAGE_MASK) { | ||||
|     if (cro_size & Memory::CITRA_PAGE_MASK) { | ||||
|         LOG_ERROR(Service_LDR, "CRO size is not aligned"); | ||||
|         rb.Push(ERROR_MISALIGNED_SIZE); | ||||
|         rb.Push<u32>(0); | ||||
|  | @ -354,7 +354,7 @@ void RO::UnloadCRO(Kernel::HLERequestContext& ctx) { | |||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     if (cro_address & Memory::PAGE_MASK) { | ||||
|     if (cro_address & Memory::CITRA_PAGE_MASK) { | ||||
|         LOG_ERROR(Service_LDR, "CRO address is not aligned"); | ||||
|         rb.Push(ERROR_MISALIGNED_ADDRESS); | ||||
|         return; | ||||
|  | @ -421,7 +421,7 @@ void RO::LinkCRO(Kernel::HLERequestContext& ctx) { | |||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     if (cro_address & Memory::PAGE_MASK) { | ||||
|     if (cro_address & Memory::CITRA_PAGE_MASK) { | ||||
|         LOG_ERROR(Service_LDR, "CRO address is not aligned"); | ||||
|         rb.Push(ERROR_MISALIGNED_ADDRESS); | ||||
|         return; | ||||
|  | @ -461,7 +461,7 @@ void RO::UnlinkCRO(Kernel::HLERequestContext& ctx) { | |||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     if (cro_address & Memory::PAGE_MASK) { | ||||
|     if (cro_address & Memory::CITRA_PAGE_MASK) { | ||||
|         LOG_ERROR(Service_LDR, "CRO address is not aligned"); | ||||
|         rb.Push(ERROR_MISALIGNED_ADDRESS); | ||||
|         return; | ||||
|  |  | |||
|  | @ -92,7 +92,8 @@ u16 NWM_UDS::GetNextAvailableNodeId() { | |||
|     } | ||||
| 
 | ||||
|     // 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() { | ||||
|  |  | |||
|  | @ -15,9 +15,6 @@ | |||
| 
 | ||||
| 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.
 | ||||
| 
 | ||||
| // 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}, | ||||
| }}; | ||||
| 
 | ||||
| /// 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
 | ||||
| struct CTRPollFD { | ||||
|     u32 fd; ///< Socket handle
 | ||||
|  |  | |||
|  | @ -68,9 +68,11 @@ struct Regs { | |||
|         case PixelFormat::RGB5A1: | ||||
|         case PixelFormat::RGBA4: | ||||
|             return 2; | ||||
|         default: | ||||
|             UNREACHABLE(); | ||||
|         } | ||||
| 
 | ||||
|         UNREACHABLE(); | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     INSERT_PADDING_WORDS(0x4); | ||||
|  |  | |||
|  | @ -94,13 +94,13 @@ ResultStatus AppLoader_NCCH::LoadExec(std::shared_ptr<Kernel::Process>& process) | |||
|         codeset->CodeSegment().offset = 0; | ||||
|         codeset->CodeSegment().addr = overlay_ncch->exheader_header.codeset_info.text.address; | ||||
|         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->CodeSegment().offset + codeset->CodeSegment().size; | ||||
|         codeset->RODataSegment().addr = overlay_ncch->exheader_header.codeset_info.ro.address; | ||||
|         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
 | ||||
|         //               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->DataSegment().addr = overlay_ncch->exheader_header.codeset_info.data.address; | ||||
|         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; | ||||
| 
 | ||||
|         // Apply patches now that the entire codeset (including .bss) has been allocated
 | ||||
|  |  | |||
|  | @ -55,20 +55,20 @@ public: | |||
| private: | ||||
|     bool* At(VAddr addr) { | ||||
|         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) { | ||||
|             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) { | ||||
|             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; | ||||
|     } | ||||
| 
 | ||||
|     std::array<bool, VRAM_SIZE / PAGE_SIZE> vram{}; | ||||
|     std::array<bool, LINEAR_HEAP_SIZE / PAGE_SIZE> linear_heap{}; | ||||
|     std::array<bool, NEW_LINEAR_HEAP_SIZE / PAGE_SIZE> new_linear_heap{}; | ||||
|     std::array<bool, VRAM_SIZE / CITRA_PAGE_SIZE> vram{}; | ||||
|     std::array<bool, LINEAR_HEAP_SIZE / CITRA_PAGE_SIZE> linear_heap{}; | ||||
|     std::array<bool, NEW_LINEAR_HEAP_SIZE / CITRA_PAGE_SIZE> new_linear_heap{}; | ||||
| 
 | ||||
|     static_assert(sizeof(bool) == 1); | ||||
|     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: | ||||
|     friend class boost::serialization::access; | ||||
|     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, | ||||
|                             PageType type) { | ||||
|     LOG_DEBUG(HW_Memory, "Mapping {} onto {:08X}-{:08X}", (void*)memory.GetPtr(), base * PAGE_SIZE, | ||||
|               (base + size) * PAGE_SIZE); | ||||
|     LOG_DEBUG(HW_Memory, "Mapping {} onto {:08X}-{:08X}", (void*)memory.GetPtr(), | ||||
|               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); | ||||
| 
 | ||||
|     u32 end = base + size; | ||||
|  | @ -235,49 +374,42 @@ void MemorySystem::MapPages(PageTable& page_table, u32 base, u32 size, MemoryRef | |||
|         page_table.pointers[base] = memory; | ||||
| 
 | ||||
|         // 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.pointers[base] = nullptr; | ||||
|         } | ||||
| 
 | ||||
|         base += 1; | ||||
|         if (memory != nullptr && memory.GetSize() > PAGE_SIZE) | ||||
|             memory += PAGE_SIZE; | ||||
|         if (memory != nullptr && memory.GetSize() > CITRA_PAGE_SIZE) | ||||
|             memory += CITRA_PAGE_SIZE; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 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((base & PAGE_MASK) == 0, "non-page aligned base: {:08X}", base); | ||||
|     MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, target, PageType::Memory); | ||||
|     ASSERT_MSG((size & CITRA_PAGE_MASK) == 0, "non-page aligned size: {:08X}", size); | ||||
|     ASSERT_MSG((base & CITRA_PAGE_MASK) == 0, "non-page aligned base: {:08X}", base); | ||||
|     MapPages(page_table, base / CITRA_PAGE_SIZE, size / CITRA_PAGE_SIZE, target, PageType::Memory); | ||||
| } | ||||
| 
 | ||||
| void MemorySystem::MapIoRegion(PageTable& page_table, VAddr base, u32 size, | ||||
|                                MMIORegionPointer mmio_handler) { | ||||
|     ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:08X}", size); | ||||
|     ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:08X}", base); | ||||
|     MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Special); | ||||
|     ASSERT_MSG((size & CITRA_PAGE_MASK) == 0, "non-page aligned size: {:08X}", size); | ||||
|     ASSERT_MSG((base & CITRA_PAGE_MASK) == 0, "non-page aligned base: {:08X}", base); | ||||
|     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}); | ||||
| } | ||||
| 
 | ||||
| void MemorySystem::UnmapRegion(PageTable& page_table, VAddr base, u32 size) { | ||||
|     ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:08X}", size); | ||||
|     ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:08X}", base); | ||||
|     MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Unmapped); | ||||
|     ASSERT_MSG((size & CITRA_PAGE_MASK) == 0, "non-page aligned size: {:08X}", size); | ||||
|     ASSERT_MSG((base & CITRA_PAGE_MASK) == 0, "non-page aligned base: {:08X}", base); | ||||
|     MapPages(page_table, base / CITRA_PAGE_SIZE, size / CITRA_PAGE_SIZE, nullptr, | ||||
|              PageType::Unmapped); | ||||
| } | ||||
| 
 | ||||
| MemoryRef MemorySystem::GetPointerForRasterizerCache(VAddr addr) const { | ||||
|     if (addr >= LINEAR_HEAP_VADDR && addr < LINEAR_HEAP_VADDR_END) { | ||||
|         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(); | ||||
|     return impl->GetPointerForRasterizerCache(addr); | ||||
| } | ||||
| 
 | ||||
| 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> | ||||
| T ReadMMIO(MMIORegionPointer mmio_handler, VAddr addr); | ||||
| 
 | ||||
| template <typename T> | ||||
| 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) { | ||||
|         // NOTE: Avoid adding any extra logic to this fast-path block
 | ||||
|         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; | ||||
|     } | ||||
| 
 | ||||
|     PageType type = impl->current_page_table->attributes[vaddr >> PAGE_BITS]; | ||||
|     PageType type = impl->current_page_table->attributes[vaddr >> CITRA_PAGE_BITS]; | ||||
|     switch (type) { | ||||
|     case PageType::Unmapped: | ||||
|         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; | ||||
|     } | ||||
|     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: | ||||
|         UNREACHABLE(); | ||||
|     } | ||||
| 
 | ||||
|     return T{}; | ||||
| } | ||||
| 
 | ||||
| template <typename T> | ||||
|  | @ -345,14 +466,14 @@ void WriteMMIO(MMIORegionPointer mmio_handler, VAddr addr, const T data); | |||
| 
 | ||||
| template <typename T> | ||||
| 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) { | ||||
|         // 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; | ||||
|     } | ||||
| 
 | ||||
|     PageType type = impl->current_page_table->attributes[vaddr >> PAGE_BITS]; | ||||
|     PageType type = impl->current_page_table->attributes[vaddr >> CITRA_PAGE_BITS]; | ||||
|     switch (type) { | ||||
|     case PageType::Unmapped: | ||||
|         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; | ||||
|     } | ||||
|     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; | ||||
|     default: | ||||
|         UNREACHABLE(); | ||||
|  | @ -376,15 +497,15 @@ void MemorySystem::Write(const VAddr vaddr, const T data) { | |||
| 
 | ||||
| template <typename T> | ||||
| 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) { | ||||
|         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); | ||||
|     } | ||||
| 
 | ||||
|     PageType type = impl->current_page_table->attributes[vaddr >> PAGE_BITS]; | ||||
|     PageType type = impl->current_page_table->attributes[vaddr >> CITRA_PAGE_BITS]; | ||||
|     switch (type) { | ||||
|     case PageType::Unmapped: | ||||
|         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); | ||||
|     } | ||||
|     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; | ||||
|     default: | ||||
|         UNREACHABLE(); | ||||
|  | @ -408,20 +529,20 @@ bool MemorySystem::WriteExclusive(const VAddr vaddr, const T data, const T expec | |||
|     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_pointer = page_table.pointers[vaddr >> PAGE_BITS]; | ||||
|     auto page_pointer = page_table.pointers[vaddr >> CITRA_PAGE_BITS]; | ||||
|     if (page_pointer) | ||||
|         return true; | ||||
| 
 | ||||
|     if (page_table.attributes[vaddr >> PAGE_BITS] == PageType::RasterizerCachedMemory) | ||||
|     if (page_table.attributes[vaddr >> CITRA_PAGE_BITS] == PageType::RasterizerCachedMemory) | ||||
|         return true; | ||||
| 
 | ||||
|     if (page_table.attributes[vaddr >> PAGE_BITS] != PageType::Special) | ||||
|     if (page_table.attributes[vaddr >> CITRA_PAGE_BITS] != PageType::Special) | ||||
|         return false; | ||||
| 
 | ||||
|     MMIORegionPointer mmio_region = GetMMIOHandler(page_table, vaddr); | ||||
|     MMIORegionPointer mmio_region = impl->GetMMIOHandler(page_table, vaddr); | ||||
|     if (mmio_region) { | ||||
|         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 { | ||||
|     return GetPhysicalPointer(paddr) != nullptr; | ||||
|     return GetPhysicalRef(paddr); | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
|         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) { | ||||
|         return GetPointerForRasterizerCache(vaddr); | ||||
|     } | ||||
|  | @ -450,12 +571,12 @@ u8* MemorySystem::GetPointer(const VAddr vaddr) { | |||
| } | ||||
| 
 | ||||
| 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) { | ||||
|         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) { | ||||
|         return GetPointerForRasterizerCache(vaddr); | ||||
|     } | ||||
|  | @ -469,11 +590,14 @@ std::string MemorySystem::ReadCString(VAddr vaddr, std::size_t max_length) { | |||
|     string.reserve(max_length); | ||||
|     for (std::size_t i = 0; i < max_length; ++i) { | ||||
|         char c = Read8(vaddr); | ||||
|         if (c == '\0') | ||||
|         if (c == '\0') { | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         string.push_back(c); | ||||
|         ++vaddr; | ||||
|     } | ||||
| 
 | ||||
|     string.shrink_to_fit(); | ||||
|     return string; | ||||
| } | ||||
|  | @ -482,40 +606,30 @@ u8* MemorySystem::GetPhysicalPointer(PAddr address) { | |||
|     return GetPhysicalRef(address); | ||||
| } | ||||
| 
 | ||||
| const u8* MemorySystem::GetPhysicalPointer(PAddr address) const { | ||||
|     return GetPhysicalRef(address); | ||||
| } | ||||
| 
 | ||||
| MemoryRef MemorySystem::GetPhysicalRef(PAddr address) const { | ||||
|     struct MemoryArea { | ||||
|         PAddr paddr_base; | ||||
|         u32 size; | ||||
|     constexpr std::array memory_areas = { | ||||
|         std::make_pair(VRAM_PADDR, VRAM_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[] = { | ||||
|         {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(memory_areas.begin(), memory_areas.end(), [&](const auto& area) { | ||||
|         // Note: the region end check is inclusive because the user can pass in an address that
 | ||||
|         // represents an open right bound
 | ||||
|         return address >= area.first && address <= area.first + area.second; | ||||
|     }); | ||||
| 
 | ||||
|     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
 | ||||
|             // represents an open right bound
 | ||||
|             return address >= area.paddr_base && address <= area.paddr_base + area.size; | ||||
|         }); | ||||
| 
 | ||||
|     if (area == std::end(memory_areas)) { | ||||
|         LOG_ERROR(HW_Memory, "unknown GetPhysicalPointer @ 0x{:08X} at PC 0x{:08X}", address, | ||||
|     if (area == memory_areas.end()) { | ||||
|         LOG_ERROR(HW_Memory, "Unknown GetPhysicalPointer @ {:#08X} at PC {:#08X}", address, | ||||
|                   Core::GetRunningCore().GetPC()); | ||||
|         return nullptr; | ||||
|     } | ||||
| 
 | ||||
|     u32 offset_into_region = address - area->paddr_base; | ||||
|     u32 offset_into_region = address - area->first; | ||||
| 
 | ||||
|     std::shared_ptr<BackingMem> target_mem = nullptr; | ||||
|     switch (area->paddr_base) { | ||||
|     switch (area->first) { | ||||
|     case VRAM_PADDR: | ||||
|         target_mem = impl->vram_mem; | ||||
|         break; | ||||
|  | @ -564,14 +678,14 @@ void MemorySystem::RasterizerMarkRegionCached(PAddr start, u32 size, bool cached | |||
|         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; | ||||
| 
 | ||||
|     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)) { | ||||
|             impl->cache_marker.Mark(vaddr, cached); | ||||
|             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) { | ||||
|                     // Switch page type to cached if now cached
 | ||||
|  | @ -582,7 +696,7 @@ void MemorySystem::RasterizerMarkRegionCached(PAddr start, u32 size, bool cached | |||
|                         break; | ||||
|                     case PageType::Memory: | ||||
|                         page_type = PageType::RasterizerCachedMemory; | ||||
|                         page_table->pointers[vaddr >> PAGE_BITS] = nullptr; | ||||
|                         page_table->pointers[vaddr >> CITRA_PAGE_BITS] = nullptr; | ||||
|                         break; | ||||
|                     default: | ||||
|                         UNREACHABLE(); | ||||
|  | @ -596,8 +710,8 @@ void MemorySystem::RasterizerMarkRegionCached(PAddr start, u32 size, bool cached | |||
|                         break; | ||||
|                     case PageType::RasterizerCachedMemory: { | ||||
|                         page_type = PageType::Memory; | ||||
|                         page_table->pointers[vaddr >> PAGE_BITS] = | ||||
|                             GetPointerForRasterizerCache(vaddr & ~PAGE_MASK); | ||||
|                         page_table->pointers[vaddr >> CITRA_PAGE_BITS] = | ||||
|                             GetPointerForRasterizerCache(vaddr & ~CITRA_PAGE_MASK); | ||||
|                         break; | ||||
|                     } | ||||
|                     default: | ||||
|  | @ -702,53 +816,12 @@ u64 MemorySystem::Read64(const VAddr addr) { | |||
| 
 | ||||
| void MemorySystem::ReadBlock(const Kernel::Process& process, const VAddr src_addr, | ||||
|                              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; | ||||
|     std::size_t page_index = src_addr >> PAGE_BITS; | ||||
|     std::size_t page_offset = src_addr & PAGE_MASK; | ||||
| 
 | ||||
|     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::ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size) { | ||||
|     const auto& process = *Core::System::GetInstance().Kernel().GetCurrentProcess(); | ||||
|     return impl->ReadBlockImpl<false>(process, src_addr, dest_buffer, size); | ||||
| } | ||||
| 
 | ||||
| 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, | ||||
|                               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 >> PAGE_BITS; | ||||
|     std::size_t page_offset = dest_addr & PAGE_MASK; | ||||
|     return impl->WriteBlockImpl<false>(process, dest_addr, src_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 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::WriteBlock(const VAddr dest_addr, const void* src_buffer, | ||||
|                               const std::size_t size) { | ||||
|     auto& process = *Core::System::GetInstance().Kernel().GetCurrentProcess(); | ||||
|     return impl->WriteBlockImpl<false>(process, dest_addr, src_buffer, size); | ||||
| } | ||||
| 
 | ||||
| void MemorySystem::ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, | ||||
|                              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 >> PAGE_BITS; | ||||
|     std::size_t page_offset = dest_addr & PAGE_MASK; | ||||
|     std::size_t page_index = dest_addr >> CITRA_PAGE_BITS; | ||||
|     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) { | ||||
|         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); | ||||
|         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: { | ||||
|  | @ -861,7 +897,7 @@ void MemorySystem::ZeroBlock(const Kernel::Process& process, const VAddr dest_ad | |||
|             break; | ||||
|         } | ||||
|         case PageType::Special: { | ||||
|             MMIORegionPointer handler = GetMMIOHandler(page_table, current_vaddr); | ||||
|             MMIORegionPointer handler = impl->GetMMIOHandler(page_table, current_vaddr); | ||||
|             DEBUG_ASSERT(handler); | ||||
|             handler->WriteBlock(current_vaddr, zeros.data(), copy_amount); | ||||
|             break; | ||||
|  | @ -892,12 +928,13 @@ void MemorySystem::CopyBlock(const Kernel::Process& dest_process, | |||
|                              std::size_t size) { | ||||
|     auto& page_table = *src_process.vm_manager.page_table; | ||||
|     std::size_t remaining_size = size; | ||||
|     std::size_t page_index = src_addr >> PAGE_BITS; | ||||
|     std::size_t page_offset = src_addr & PAGE_MASK; | ||||
|     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(PAGE_SIZE - page_offset, remaining_size); | ||||
|         const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); | ||||
|         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: { | ||||
|  | @ -915,7 +952,7 @@ void MemorySystem::CopyBlock(const Kernel::Process& dest_process, | |||
|             break; | ||||
|         } | ||||
|         case PageType::Special: { | ||||
|             MMIORegionPointer handler = GetMMIOHandler(page_table, current_vaddr); | ||||
|             MMIORegionPointer handler = impl->GetMMIOHandler(page_table, current_vaddr); | ||||
|             DEBUG_ASSERT(handler); | ||||
|             std::vector<u8> buffer(copy_amount); | ||||
|             handler->ReadBlock(current_vaddr, buffer.data(), buffer.size()); | ||||
|  |  | |||
|  | @ -3,12 +3,9 @@ | |||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <array> | ||||
| #include <cstddef> | ||||
| #include <memory> | ||||
| #include <string> | ||||
| #include <vector> | ||||
| #include <boost/serialization/array.hpp> | ||||
| #include <boost/serialization/vector.hpp> | ||||
| #include "common/common_types.h" | ||||
|  | @ -27,17 +24,14 @@ class DspInterface; | |||
| 
 | ||||
| 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 | ||||
|  * be mapped. | ||||
|  */ | ||||
| const u32 PAGE_SIZE = 0x1000; | ||||
| const u32 PAGE_MASK = PAGE_SIZE - 1; | ||||
| const int PAGE_BITS = 12; | ||||
| const std::size_t PAGE_TABLE_NUM_ENTRIES = 1 << (32 - PAGE_BITS); | ||||
| constexpr u32 CITRA_PAGE_SIZE = 0x1000; | ||||
| constexpr u32 CITRA_PAGE_MASK = CITRA_PAGE_SIZE - 1; | ||||
| constexpr int CITRA_PAGE_BITS = 12; | ||||
| constexpr std::size_t PAGE_TABLE_NUM_ENTRIES = 1 << (32 - CITRA_PAGE_BITS); | ||||
| 
 | ||||
| enum class PageType { | ||||
|     /// Page is unmapped and should cause an access error.
 | ||||
|  | @ -106,11 +100,10 @@ struct PageTable { | |||
| 
 | ||||
|     private: | ||||
|         std::array<u8*, PAGE_TABLE_NUM_ENTRIES> raw; | ||||
| 
 | ||||
|         std::array<MemoryRef, PAGE_TABLE_NUM_ENTRIES> refs; | ||||
| 
 | ||||
|         friend struct PageTable; | ||||
|     }; | ||||
| 
 | ||||
|     Pointers pointers; | ||||
| 
 | ||||
|     /**
 | ||||
|  | @ -317,14 +310,108 @@ public: | |||
|     void SetCurrentPageTable(std::shared_ptr<PageTable> page_table); | ||||
|     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); | ||||
| 
 | ||||
|     /**
 | ||||
|      * 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); | ||||
| 
 | ||||
|     /**
 | ||||
|      * 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); | ||||
| 
 | ||||
|     /**
 | ||||
|      * 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); | ||||
| 
 | ||||
|     /**
 | ||||
|      * 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); | ||||
| 
 | ||||
|     /**
 | ||||
|      * 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); | ||||
| 
 | ||||
|     /**
 | ||||
|      * 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); | ||||
| 
 | ||||
|     /**
 | ||||
|      * 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); | ||||
| 
 | ||||
|     /**
 | ||||
|  | @ -344,29 +431,155 @@ public: | |||
|     bool WriteExclusive32(const VAddr addr, const u32 data, const u32 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, | ||||
|                    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, | ||||
|                     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); | ||||
| 
 | ||||
|     /**
 | ||||
|      * 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, | ||||
|                    std::size_t size); | ||||
|     void CopyBlock(const Kernel::Process& dest_process, const Kernel::Process& src_process, | ||||
|                    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.
 | ||||
|     u8* GetPhysicalPointer(PAddr address); | ||||
| 
 | ||||
|     /// Gets a pointer to the memory region beginning at the specified physical address.
 | ||||
|     const u8* GetPhysicalPointer(PAddr address) const; | ||||
| 
 | ||||
|     /// Returns a reference to the memory region beginning at the specified physical address
 | ||||
|     MemoryRef GetPhysicalRef(PAddr address) const; | ||||
| 
 | ||||
|     u8* GetPointer(VAddr vaddr); | ||||
|     const u8* GetPointer(VAddr vaddr) const; | ||||
|     /// Determines if the given VAddr is valid for the specified process.
 | ||||
|     bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr); | ||||
| 
 | ||||
|     /// Returns true if the address refers to a valid memory region
 | ||||
|     bool IsValidPhysicalAddress(PAddr paddr) const; | ||||
| 
 | ||||
|     /// 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
 | ||||
|     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
 | ||||
|     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); | ||||
| 
 | ||||
|     class Impl; | ||||
| 
 | ||||
|     std::unique_ptr<Impl> impl; | ||||
| 
 | ||||
|     friend class boost::serialization::access; | ||||
|  | @ -427,9 +634,6 @@ public: | |||
|     class BackingMemImpl; | ||||
| }; | ||||
| 
 | ||||
| /// Determines if the given VAddr is valid for the specified process.
 | ||||
| bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr); | ||||
| 
 | ||||
| } // namespace Memory
 | ||||
| 
 | ||||
| BOOST_CLASS_EXPORT_KEY(Memory::MemorySystem::BackingMemImpl<Memory::Region::FCRAM>) | ||||
|  |  | |||
|  | @ -22,7 +22,6 @@ namespace Settings { | |||
| Values values = {}; | ||||
| 
 | ||||
| void Apply() { | ||||
| 
 | ||||
|     GDBStub::SetServerPort(values.gdbstub_port); | ||||
|     GDBStub::ToggleServer(values.use_gdbstub); | ||||
| 
 | ||||
|  |  | |||
|  | @ -137,7 +137,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel | |||
|     } | ||||
| 
 | ||||
|     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}; | ||||
|         std::fill(buffer.GetPtr(), buffer.GetPtr() + buffer.GetSize(), 0xAB); | ||||
| 
 | ||||
|  | @ -161,7 +161,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel | |||
|     } | ||||
| 
 | ||||
|     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}; | ||||
|         std::fill(buffer.GetPtr(), buffer.GetPtr() + buffer.GetSize(), 0xCD); | ||||
| 
 | ||||
|  | @ -187,11 +187,11 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel | |||
|     } | ||||
| 
 | ||||
|     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}; | ||||
|         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}; | ||||
|         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") { | ||||
|         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); | ||||
| 
 | ||||
|         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}; | ||||
| 
 | ||||
|         VAddr target_address = 0x10000000; | ||||
|  | @ -355,10 +355,10 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") { | |||
|     } | ||||
| 
 | ||||
|     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); | ||||
| 
 | ||||
|         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}; | ||||
| 
 | ||||
|         VAddr target_address = 0x10000000; | ||||
|  |  | |||
|  | @ -3,34 +3,31 @@ | |||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <catch2/catch_test_macros.hpp> | ||||
| #include "core/core.h" | ||||
| #include "core/core_timing.h" | ||||
| #include "core/hle/kernel/memory.h" | ||||
| #include "core/hle/kernel/process.h" | ||||
| #include "core/hle/kernel/shared_page.h" | ||||
| #include "core/memory.h" | ||||
| 
 | ||||
| TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") { | ||||
| TEST_CASE("memory.IsValidVirtualAddress", "[core][memory]") { | ||||
|     Core::Timing timing(1, 100); | ||||
|     Memory::MemorySystem memory; | ||||
|     Kernel::KernelSystem kernel( | ||||
|         memory, timing, [] {}, 0, 1, 0); | ||||
|     SECTION("these regions should not be mapped on an empty process") { | ||||
|         auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0)); | ||||
|         CHECK(Memory::IsValidVirtualAddress(*process, Memory::PROCESS_IMAGE_VADDR) == false); | ||||
|         CHECK(Memory::IsValidVirtualAddress(*process, Memory::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::CONFIG_MEMORY_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::PROCESS_IMAGE_VADDR) == false); | ||||
|         CHECK(memory.IsValidVirtualAddress(*process, Memory::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::CONFIG_MEMORY_VADDR) == false); | ||||
|         CHECK(memory.IsValidVirtualAddress(*process, Memory::SHARED_PAGE_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") { | ||||
|         auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0)); | ||||
|         kernel.MapSharedPages(process->vm_manager); | ||||
|         CHECK(Memory::IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == true); | ||||
|         CHECK(Memory::IsValidVirtualAddress(*process, Memory::SHARED_PAGE_VADDR) == true); | ||||
|         CHECK(memory.IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == true); | ||||
|         CHECK(memory.IsValidVirtualAddress(*process, Memory::SHARED_PAGE_VADDR) == true); | ||||
|     } | ||||
| 
 | ||||
|     SECTION("special regions should be valid after mapping them") { | ||||
|  | @ -38,13 +35,13 @@ TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") { | |||
|         SECTION("VRAM") { | ||||
|             kernel.HandleSpecialMapping(process->vm_manager, | ||||
|                                         {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)") { | ||||
|             kernel.HandleSpecialMapping( | ||||
|                 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)); | ||||
|         kernel.MapSharedPages(process->vm_manager); | ||||
|         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" | ||||
| 
 | ||||
| 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}; | ||||
|     Memory::MemorySystem memory; | ||||
|     SECTION("mapping memory") { | ||||
|  |  | |||
|  | @ -255,7 +255,7 @@ public: | |||
|     } | ||||
| 
 | ||||
| private: | ||||
|     const Regs& regs; | ||||
|     [[maybe_unused]] const Regs& regs; | ||||
|     Shader::ShaderSetup& setup; | ||||
|     Common::Vec4<float24>* buffer_begin; | ||||
|     Common::Vec4<float24>* buffer_cur; | ||||
|  |  | |||
|  | @ -28,7 +28,7 @@ public: | |||
|          * @note All methods in this class are called from the GSP thread | ||||
|          */ | ||||
|         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); | ||||
|             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) { | ||||
|     ASSERT(type != SurfaceType::Fill); | ||||
|     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) | ||||
|         load_start = Memory::VRAM_VADDR; | ||||
| 
 | ||||
|     MICROPROFILE_SCOPE(OpenGL_SurfaceLoad); | ||||
|     MICROPROFILE_SCOPE(RasterizerCache_SurfaceLoad); | ||||
| 
 | ||||
|     ASSERT(load_start >= addr && load_end <= end); | ||||
|     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) { | ||||
|     u8* const dst_buffer = VideoCore::g_memory->GetPhysicalPointer(addr); | ||||
|     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) | ||||
|         flush_start = Memory::VRAM_VADDR; | ||||
| 
 | ||||
|     MICROPROFILE_SCOPE(OpenGL_SurfaceFlush); | ||||
|     MICROPROFILE_SCOPE(RasterizerCache_SurfaceFlush); | ||||
| 
 | ||||
|     ASSERT(flush_start >= addr && flush_end <= end); | ||||
|     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) { | ||||
|     if (type == SurfaceType::Fill) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     MICROPROFILE_SCOPE(OpenGL_TextureUL); | ||||
|     MICROPROFILE_SCOPE(RasterizerCache_TextureUL); | ||||
|     ASSERT(gl_buffer.size() == width * height * GetBytesPerPixel(pixel_format)); | ||||
| 
 | ||||
|     u64 tex_hash = 0; | ||||
|  | @ -374,13 +377,14 @@ void CachedSurface::UploadGLTexture(Common::Rectangle<u32> rect) { | |||
|     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) { | ||||
|     if (type == SurfaceType::Fill) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     MICROPROFILE_SCOPE(OpenGL_TextureDL); | ||||
|     MICROPROFILE_SCOPE(RasterizerCache_TextureDL); | ||||
| 
 | ||||
|     if (gl_buffer.empty()) { | ||||
|         gl_buffer.resize(width * height * GetBytesPerPixel(pixel_format)); | ||||
|  |  | |||
|  | @ -93,10 +93,11 @@ OGLTexture RasterizerCacheOpenGL::AllocateSurfaceTexture(const FormatTuple& tupl | |||
|     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, | ||||
|                                         SurfaceInterval copy_interval) { | ||||
|     MICROPROFILE_SCOPE(OpenGL_CopySurface); | ||||
|     MICROPROFILE_SCOPE(RasterizerCache_CopySurface); | ||||
| 
 | ||||
|     SurfaceParams subrect_params = dst_surface->FromInterval(copy_interval); | ||||
|     ASSERT(subrect_params.GetInterval() == copy_interval); | ||||
|  | @ -253,12 +254,13 @@ RasterizerCacheOpenGL::~RasterizerCacheOpenGL() { | |||
| #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, | ||||
|                                          const Common::Rectangle<u32>& src_rect, | ||||
|                                          const Surface& dst_surface, | ||||
|                                          const Common::Rectangle<u32>& dst_rect) { | ||||
|     MICROPROFILE_SCOPE(OpenGL_BlitSurface); | ||||
|     MICROPROFILE_SCOPE(RasterizerCache_BlitSurface); | ||||
| 
 | ||||
|     if (CheckFormatsBlittable(src_surface->pixel_format, dst_surface->pixel_format)) { | ||||
|         dst_surface->InvalidateAllWatcher(); | ||||
|  | @ -917,8 +919,8 @@ void RasterizerCacheOpenGL::ClearAll(bool flush) { | |||
|     for (auto& pair : RangeFromInterval(cached_pages, flush_interval)) { | ||||
|         const auto interval = pair.first & flush_interval; | ||||
| 
 | ||||
|         const PAddr interval_start_addr = boost::icl::first(interval) << Memory::PAGE_BITS; | ||||
|         const PAddr interval_end_addr = boost::icl::last_next(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::CITRA_PAGE_BITS; | ||||
|         const u32 interval_size = interval_end_addr - interval_start_addr; | ||||
| 
 | ||||
|         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) { | ||||
|     const u32 num_pages = | ||||
|         ((addr + size - 1) >> Memory::PAGE_BITS) - (addr >> Memory::PAGE_BITS) + 1; | ||||
|     const u32 page_start = addr >> Memory::PAGE_BITS; | ||||
|         ((addr + size - 1) >> Memory::CITRA_PAGE_BITS) - (addr >> Memory::CITRA_PAGE_BITS) + 1; | ||||
|     const u32 page_start = addr >> Memory::CITRA_PAGE_BITS; | ||||
|     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
 | ||||
|  | @ -1083,8 +1085,8 @@ void RasterizerCacheOpenGL::UpdatePagesCachedCount(PAddr addr, u32 size, int del | |||
|         const auto interval = pair.first & pages_interval; | ||||
|         const int count = pair.second; | ||||
| 
 | ||||
|         const PAddr interval_start_addr = boost::icl::first(interval) << Memory::PAGE_BITS; | ||||
|         const PAddr interval_end_addr = boost::icl::last_next(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::CITRA_PAGE_BITS; | ||||
|         const u32 interval_size = interval_end_addr - interval_start_addr; | ||||
| 
 | ||||
|         if (delta > 0 && count == delta) | ||||
|  |  | |||
|  | @ -274,9 +274,11 @@ struct FramebufferRegs { | |||
|         case DepthFormat::D24: | ||||
|         case DepthFormat::D24S8: | ||||
|             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
 | ||||
|  |  | |||
|  | @ -129,6 +129,8 @@ struct LightingRegs { | |||
|                             "ReflectBlue, instead got %i", | ||||
|                             config); | ||||
|         } | ||||
| 
 | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     struct LightSrc { | ||||
|  |  | |||
|  | @ -428,6 +428,8 @@ static GLenum GetCurrentPrimitiveMode() { | |||
|     default: | ||||
|         UNREACHABLE(); | ||||
|     } | ||||
| 
 | ||||
|     return GL_TRIANGLES; | ||||
| } | ||||
| 
 | ||||
| bool RasterizerOpenGL::AccelerateDrawBatchInternal(bool is_indexed) { | ||||
|  |  | |||
|  | @ -89,7 +89,7 @@ void OGLTexture::CopyFrom(const OGLTexture& other, GLenum target, GLsizei levels | |||
|     glActiveTexture(GL_TEXTURE0); | ||||
|     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, | ||||
|                            width >> level, height >> level, 1); | ||||
|     } | ||||
|  |  | |||
|  | @ -744,7 +744,7 @@ void RendererOpenGL::ReloadShader() { | |||
| void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, | ||||
|                                                  const GPU::Regs::FramebufferConfig& framebuffer) { | ||||
|     GPU::Regs::PixelFormat format = framebuffer.color_format; | ||||
|     GLint internal_format; | ||||
|     GLint internal_format{}; | ||||
| 
 | ||||
|     texture.format = format; | ||||
|     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, | ||||
|                                       GLint height, GLint width, void* pixels) { | ||||
|     OpenGLState state = OpenGLState::GetCurState(); | ||||
|     GLuint texture; | ||||
|     GLuint texture{}; | ||||
|     const GLuint old_read_buffer = state.draw.read_framebuffer; | ||||
|     switch (target) { | ||||
|     case GL_TEXTURE_2D: | ||||
|  |  | |||
|  | @ -46,7 +46,7 @@ public: | |||
|     } | ||||
| 
 | ||||
| private: | ||||
|     float24 pos; | ||||
|     [[maybe_unused]] float24 pos; | ||||
|     Common::Vec4<float24> coeffs; | ||||
|     Common::Vec4<float24> bias; | ||||
| }; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue