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:
Tobias 2022-11-04 23:32:57 +01:00 committed by GitHub
parent aa84022704
commit 1ddea27ac8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
72 changed files with 895 additions and 626 deletions

View File

@ -847,7 +847,7 @@ inline MicroProfileLogEntry MicroProfileMakeLogIndex(uint64_t nBegin, MicroProfi
MicroProfileLogEntry Entry = (nBegin<<62) | ((0x3fff&nToken)<<48) | (MP_LOG_TICK_MASK&nTick); MicroProfileLogEntry Entry = (nBegin<<62) | ((0x3fff&nToken)<<48) | (MP_LOG_TICK_MASK&nTick);
int t = MicroProfileLogType(Entry); int t = MicroProfileLogType(Entry);
uint64_t nTimerIndex = MicroProfileLogTimerIndex(Entry); uint64_t nTimerIndex = MicroProfileLogTimerIndex(Entry);
MP_ASSERT(t == nBegin); MP_ASSERT(static_cast<uint64_t>(t) == nBegin);
MP_ASSERT(nTimerIndex == (nToken&0x3fff)); MP_ASSERT(nTimerIndex == (nToken&0x3fff));
return Entry; return Entry;
@ -1579,10 +1579,10 @@ void MicroProfileFlip()
pFramePut->nFrameStartCpu = MP_TICK(); pFramePut->nFrameStartCpu = MP_TICK();
pFramePut->nFrameStartGpu = (uint32_t)MicroProfileGpuInsertTimeStamp(); pFramePut->nFrameStartGpu = (uint32_t)MicroProfileGpuInsertTimeStamp();
if(pFrameNext->nFrameStartGpu != (uint64_t)-1) if(static_cast<uint64_t>(pFrameNext->nFrameStartGpu) != (uint64_t)-1)
pFrameNext->nFrameStartGpu = MicroProfileGpuGetTimeStamp((uint32_t)pFrameNext->nFrameStartGpu); pFrameNext->nFrameStartGpu = MicroProfileGpuGetTimeStamp((uint32_t)pFrameNext->nFrameStartGpu);
if(pFrameCurrent->nFrameStartGpu == (uint64_t)-1) if(static_cast<uint64_t>(pFrameCurrent->nFrameStartGpu) == (uint64_t)-1)
pFrameCurrent->nFrameStartGpu = pFrameNext->nFrameStartGpu + 1; pFrameCurrent->nFrameStartGpu = pFrameNext->nFrameStartGpu + 1;
uint64_t nFrameStartCpu = pFrameCurrent->nFrameStartCpu; uint64_t nFrameStartCpu = pFrameCurrent->nFrameStartCpu;

View File

@ -354,7 +354,7 @@ void MicroProfileInitUI()
if(!bInitialized) if(!bInitialized)
{ {
bInitialized = true; bInitialized = true;
memset(&g_MicroProfileUI, 0, sizeof(g_MicroProfileUI)); g_MicroProfileUI = {};
UI.nActiveMenu = UINT32_MAX; UI.nActiveMenu = UINT32_MAX;
UI.fDetailedOffsetTarget = UI.fDetailedOffset = 0.f; UI.fDetailedOffsetTarget = UI.fDetailedOffset = 0.f;
UI.fDetailedRangeTarget = UI.fDetailedRange = 50.f; UI.fDetailedRangeTarget = UI.fDetailedRange = 50.f;
@ -845,8 +845,8 @@ void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int nBaseY,
MicroProfile& S = *MicroProfileGet(); MicroProfile& S = *MicroProfileGet();
MP_DEBUG_DUMP_RANGE(); MP_DEBUG_DUMP_RANGE();
int nY = nBaseY - UI.nOffsetY; int nY = nBaseY - UI.nOffsetY;
int64_t nNumBoxes = 0; [[maybe_unused]] int64_t nNumBoxes = 0;
int64_t nNumLines = 0; [[maybe_unused]] int64_t nNumLines = 0;
uint32_t nFrameNext = (S.nFrameCurrent+1) % MICROPROFILE_MAX_FRAME_HISTORY; uint32_t nFrameNext = (S.nFrameCurrent+1) % MICROPROFILE_MAX_FRAME_HISTORY;
MicroProfileFrameState* pFrameCurrent = &S.Frames[S.nFrameCurrent]; MicroProfileFrameState* pFrameCurrent = &S.Frames[S.nFrameCurrent];
@ -1988,7 +1988,7 @@ const char* MicroProfileUIMenuGroups(int nIndex, bool* bSelected)
else else
{ {
nIndex = nIndex-1; nIndex = nIndex-1;
if(nIndex < UI.GroupMenuCount) if(static_cast<uint32_t>(nIndex) < UI.GroupMenuCount)
{ {
MicroProfileGroupMenuItem& Item = UI.GroupMenu[nIndex]; MicroProfileGroupMenuItem& Item = UI.GroupMenu[nIndex];
static char buffer[MICROPROFILE_NAME_MAX_LEN+32]; static char buffer[MICROPROFILE_NAME_MAX_LEN+32];
@ -2135,7 +2135,7 @@ const char* MicroProfileUIMenuCustom(int nIndex, bool* bSelected)
case 1: return "--"; case 1: return "--";
default: default:
nIndex -= 2; nIndex -= 2;
if(nIndex < UI.nCustomCount) if(static_cast<uint32_t>(nIndex) < UI.nCustomCount)
{ {
return UI.Custom[nIndex].pName; return UI.Custom[nIndex].pName;
} }
@ -2185,7 +2185,7 @@ void MicroProfileUIClickGroups(int nIndex)
else else
{ {
nIndex -= 1; nIndex -= 1;
if(nIndex < UI.GroupMenuCount) if(static_cast<uint32_t>(nIndex) < UI.GroupMenuCount)
{ {
MicroProfileGroupMenuItem& Item = UI.GroupMenu[nIndex]; MicroProfileGroupMenuItem& Item = UI.GroupMenu[nIndex];
if(Item.nIsCategory) if(Item.nIsCategory)

View File

@ -11,13 +11,6 @@
// This needs to be included before getopt.h because the latter #defines symbols used by it // This needs to be included before getopt.h because the latter #defines symbols used by it
#include "common/microprofile.h" #include "common/microprofile.h"
#ifdef _WIN32
// windows.h needs to be included before shellapi.h
#include <windows.h>
#include <shellapi.h>
#endif
#include "citra/config.h" #include "citra/config.h"
#include "citra/emu_window/emu_window_sdl2.h" #include "citra/emu_window/emu_window_sdl2.h"
#include "citra/lodepng_image_interface.h" #include "citra/lodepng_image_interface.h"
@ -52,6 +45,11 @@
#endif #endif
#ifdef _WIN32 #ifdef _WIN32
// windows.h needs to be included before shellapi.h
#include <windows.h>
#include <shellapi.h>
extern "C" { extern "C" {
// tells Nvidia drivers to use the dedicated GPU by default on laptops with switchable graphics // tells Nvidia drivers to use the dedicated GPU by default on laptops with switchable graphics
__declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001; __declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001;
@ -104,35 +102,35 @@ static void OnNetworkError(const Network::RoomMember::Error& error) {
break; break;
case Network::RoomMember::Error::CouldNotConnect: case Network::RoomMember::Error::CouldNotConnect:
LOG_ERROR(Network, "Error: Could not connect"); LOG_ERROR(Network, "Error: Could not connect");
exit(1); std::exit(1);
break; break;
case Network::RoomMember::Error::NameCollision: case Network::RoomMember::Error::NameCollision:
LOG_ERROR( LOG_ERROR(
Network, Network,
"You tried to use the same nickname as another user that is connected to the Room"); "You tried to use the same nickname as another user that is connected to the Room");
exit(1); std::exit(1);
break; break;
case Network::RoomMember::Error::MacCollision: case Network::RoomMember::Error::MacCollision:
LOG_ERROR(Network, "You tried to use the same MAC-Address as another user that is " LOG_ERROR(Network, "You tried to use the same MAC-Address as another user that is "
"connected to the Room"); "connected to the Room");
exit(1); std::exit(1);
break; break;
case Network::RoomMember::Error::ConsoleIdCollision: case Network::RoomMember::Error::ConsoleIdCollision:
LOG_ERROR(Network, "Your Console ID conflicted with someone else in the Room"); LOG_ERROR(Network, "Your Console ID conflicted with someone else in the Room");
exit(1); std::exit(1);
break; break;
case Network::RoomMember::Error::WrongPassword: case Network::RoomMember::Error::WrongPassword:
LOG_ERROR(Network, "Room replied with: Wrong password"); LOG_ERROR(Network, "Room replied with: Wrong password");
exit(1); std::exit(1);
break; break;
case Network::RoomMember::Error::WrongVersion: case Network::RoomMember::Error::WrongVersion:
LOG_ERROR(Network, LOG_ERROR(Network,
"You are using a different version than the room you are trying to connect to"); "You are using a different version than the room you are trying to connect to");
exit(1); std::exit(1);
break; break;
case Network::RoomMember::Error::RoomIsFull: case Network::RoomMember::Error::RoomIsFull:
LOG_ERROR(Network, "The room is full"); LOG_ERROR(Network, "The room is full");
exit(1); std::exit(1);
break; break;
case Network::RoomMember::Error::HostKicked: case Network::RoomMember::Error::HostKicked:
LOG_ERROR(Network, "You have been kicked by the host"); LOG_ERROR(Network, "You have been kicked by the host");
@ -140,6 +138,8 @@ static void OnNetworkError(const Network::RoomMember::Error& error) {
case Network::RoomMember::Error::HostBanned: case Network::RoomMember::Error::HostBanned:
LOG_ERROR(Network, "You have been banned by the host"); LOG_ERROR(Network, "You have been banned by the host");
break; break;
default:
LOG_ERROR(Network, "Unknown network error {}", error);
} }
} }

View File

@ -54,12 +54,12 @@ QtKeyboardDialog::QtKeyboardDialog(QWidget* parent, QtKeyboard* keyboard_)
case ButtonConfig::None: case ButtonConfig::None:
break; break;
} }
connect(buttons, &QDialogButtonBox::accepted, this, [=] { Submit(); }); connect(buttons, &QDialogButtonBox::accepted, this, [this] { Submit(); });
connect(buttons, &QDialogButtonBox::rejected, this, [=] { connect(buttons, &QDialogButtonBox::rejected, this, [this] {
button = QtKeyboard::cancel_id; button = QtKeyboard::cancel_id;
accept(); accept();
}); });
connect(buttons, &QDialogButtonBox::helpRequested, this, [=] { connect(buttons, &QDialogButtonBox::helpRequested, this, [this] {
button = QtKeyboard::forgot_id; button = QtKeyboard::forgot_id;
accept(); accept();
}); });

View File

@ -32,11 +32,13 @@ EmuThread::EmuThread(Frontend::GraphicsContext& core_context) : core_context(cor
EmuThread::~EmuThread() = default; EmuThread::~EmuThread() = default;
static GMainWindow* GetMainWindow() { static GMainWindow* GetMainWindow() {
for (QWidget* w : qApp->topLevelWidgets()) { const auto widgets = qApp->topLevelWidgets();
for (QWidget* w : widgets) {
if (GMainWindow* main = qobject_cast<GMainWindow*>(w)) { if (GMainWindow* main = qobject_cast<GMainWindow*>(w)) {
return main; return main;
} }
} }
return nullptr; return nullptr;
} }
@ -46,7 +48,8 @@ void EmuThread::run() {
emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0);
Core::System::GetInstance().Renderer().Rasterizer()->LoadDiskResources( Core::System& system = Core::System::GetInstance();
system.Renderer().Rasterizer()->LoadDiskResources(
stop_run, [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) { stop_run, [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) {
emit LoadProgress(stage, value, total); emit LoadProgress(stage, value, total);
}); });
@ -55,18 +58,17 @@ void EmuThread::run() {
core_context.MakeCurrent(); core_context.MakeCurrent();
if (Core::System::GetInstance().frame_limiter.IsFrameAdvancing()) { if (system.frame_limiter.IsFrameAdvancing()) {
// Usually the loading screen is hidden after the first frame is drawn. In this case // Usually the loading screen is hidden after the first frame is drawn. In this case
// we hide it immediately as we need to wait for user input to start the emulation. // we hide it immediately as we need to wait for user input to start the emulation.
emit HideLoadingScreen(); emit HideLoadingScreen();
Core::System::GetInstance().frame_limiter.WaitOnce(); system.frame_limiter.WaitOnce();
} }
// Holds whether the cpu was running during the last iteration, // Holds whether the cpu was running during the last iteration,
// so that the DebugModeLeft signal can be emitted before the // so that the DebugModeLeft signal can be emitted before the
// next execution step. // next execution step.
bool was_active = false; bool was_active = false;
Core::System& system = Core::System::GetInstance();
while (!stop_run) { while (!stop_run) {
if (running) { if (running) {
if (!was_active) if (!was_active)
@ -423,7 +425,7 @@ void GRenderWindow::CaptureScreenshot(u32 res_scale, const QString& screenshot_p
screenshot_image = QImage(QSize(layout.width, layout.height), QImage::Format_RGB32); screenshot_image = QImage(QSize(layout.width, layout.height), QImage::Format_RGB32);
VideoCore::RequestScreenshot( VideoCore::RequestScreenshot(
screenshot_image.bits(), screenshot_image.bits(),
[=] { [this, &screenshot_path] {
const std::string std_screenshot_path = screenshot_path.toStdString(); const std::string std_screenshot_path = screenshot_path.toStdString();
if (screenshot_image.mirrored(false, true).save(screenshot_path)) { if (screenshot_image.mirrored(false, true).save(screenshot_path)) {
LOG_INFO(Frontend, "Screenshot saved to \"{}\"", std_screenshot_path); LOG_INFO(Frontend, "Screenshot saved to \"{}\"", std_screenshot_path);

View File

@ -37,7 +37,7 @@ CheatDialog::CheatDialog(QWidget* parent)
connect(ui->textNotes, &QPlainTextEdit::textChanged, this, &CheatDialog::OnTextEdited); connect(ui->textNotes, &QPlainTextEdit::textChanged, this, &CheatDialog::OnTextEdited);
connect(ui->textCode, &QPlainTextEdit::textChanged, this, &CheatDialog::OnTextEdited); connect(ui->textCode, &QPlainTextEdit::textChanged, this, &CheatDialog::OnTextEdited);
connect(ui->buttonSave, &QPushButton::clicked, connect(ui->buttonSave, &QPushButton::clicked, this,
[this] { SaveCheat(ui->tableCheats->currentRow()); }); [this] { SaveCheat(ui->tableCheats->currentRow()); });
connect(ui->buttonDelete, &QPushButton::clicked, this, &CheatDialog::OnDeleteCheat); connect(ui->buttonDelete, &QPushButton::clicked, this, &CheatDialog::OnDeleteCheat);
@ -91,7 +91,7 @@ bool CheatDialog::SaveCheat(int row) {
} }
// Check if the cheat lines are valid // Check if the cheat lines are valid
auto code_lines = ui->textCode->toPlainText().split(QLatin1Char{'\n'}, QString::SkipEmptyParts); auto code_lines = ui->textCode->toPlainText().split(QLatin1Char{'\n'}, Qt::SkipEmptyParts);
for (int i = 0; i < code_lines.size(); ++i) { for (int i = 0; i < code_lines.size(); ++i) {
Cheats::GatewayCheat::CheatLine cheat_line(code_lines[i].toStdString()); Cheats::GatewayCheat::CheatLine cheat_line(code_lines[i].toStdString());
if (cheat_line.valid) if (cheat_line.valid)
@ -190,8 +190,9 @@ void CheatDialog::OnDeleteCheat() {
if (newly_created) { if (newly_created) {
newly_created = false; newly_created = false;
} else { } else {
Core::System::GetInstance().CheatEngine().RemoveCheat(ui->tableCheats->currentRow()); auto& cheat_engine = Core::System::GetInstance().CheatEngine();
Core::System::GetInstance().CheatEngine().SaveCheatFile(); cheat_engine.RemoveCheat(ui->tableCheats->currentRow());
cheat_engine.SaveCheatFile();
} }
LoadCheats(); LoadCheats();

View File

@ -518,7 +518,7 @@ void Config::ReadRendererValues() {
void Config::ReadShortcutValues() { void Config::ReadShortcutValues() {
qt_config->beginGroup(QStringLiteral("Shortcuts")); qt_config->beginGroup(QStringLiteral("Shortcuts"));
for (auto [name, group, shortcut] : default_hotkeys) { for (const auto& [name, group, shortcut] : default_hotkeys) {
auto [keyseq, context] = shortcut; auto [keyseq, context] = shortcut;
qt_config->beginGroup(group); qt_config->beginGroup(group);
qt_config->beginGroup(name); qt_config->beginGroup(name);
@ -553,7 +553,7 @@ void Config::ReadSystemValues() {
// https://developers.google.com/media/vp9/live-encoding // https://developers.google.com/media/vp9/live-encoding
const QString DEFAULT_VIDEO_ENCODER_OPTIONS = const QString DEFAULT_VIDEO_ENCODER_OPTIONS =
QStringLiteral("quality:realtime,speed:6,tile-columns:4,frame-parallel:1,threads:8,row-mt:1"); QStringLiteral("quality:realtime,speed:6,tile-columns:4,frame-parallel:1,threads:8,row-mt:1");
const QString DEFAULT_AUDIO_ENCODER_OPTIONS = QString{}; const QString DEFAULT_AUDIO_ENCODER_OPTIONS = QStringLiteral("");
void Config::ReadVideoDumpingValues() { void Config::ReadVideoDumpingValues() {
qt_config->beginGroup(QStringLiteral("VideoDumping")); qt_config->beginGroup(QStringLiteral("VideoDumping"));
@ -1013,9 +1013,9 @@ void Config::SaveRendererValues() {
200); 200);
// Cast to double because Qt's written float values are not human-readable // Cast to double because Qt's written float values are not human-readable
WriteSetting(QStringLiteral("bg_red"), (double)Settings::values.bg_red, 0.0); WriteSetting(QStringLiteral("bg_red"), static_cast<double>(Settings::values.bg_red), 0.0);
WriteSetting(QStringLiteral("bg_green"), (double)Settings::values.bg_green, 0.0); WriteSetting(QStringLiteral("bg_green"), static_cast<double>(Settings::values.bg_green), 0.0);
WriteSetting(QStringLiteral("bg_blue"), (double)Settings::values.bg_blue, 0.0); WriteSetting(QStringLiteral("bg_blue"), static_cast<double>(Settings::values.bg_blue), 0.0);
WriteSetting(QStringLiteral("texture_filter_name"), WriteSetting(QStringLiteral("texture_filter_name"),
QString::fromStdString(Settings::values.texture_filter_name), QString::fromStdString(Settings::values.texture_filter_name),

View File

@ -9,8 +9,6 @@
#include <QMessageBox> #include <QMessageBox>
#include <QWidget> #include <QWidget>
#include "citra_qt/configuration/configure_camera.h" #include "citra_qt/configuration/configure_camera.h"
#include "citra_qt/uisettings.h"
#include "core/core.h"
#include "core/frontend/camera/factory.h" #include "core/frontend/camera/factory.h"
#include "core/frontend/camera/interface.h" #include "core/frontend/camera/interface.h"
#include "core/hle/service/cam/cam.h" #include "core/hle/service/cam/cam.h"
@ -91,7 +89,7 @@ void ConfigureCamera::ConnectEvents() {
SetConfiguration(); SetConfiguration();
}); });
connect(ui->toolButton, &QToolButton::clicked, this, &ConfigureCamera::OnToolButtonClicked); connect(ui->toolButton, &QToolButton::clicked, this, &ConfigureCamera::OnToolButtonClicked);
connect(ui->preview_button, &QPushButton::clicked, this, [=] { StartPreviewing(); }); connect(ui->preview_button, &QPushButton::clicked, this, [this] { StartPreviewing(); });
connect(ui->prompt_before_load, &QCheckBox::stateChanged, this, [this](int state) { connect(ui->prompt_before_load, &QCheckBox::stateChanged, this, [this](int state) {
ui->camera_file->setDisabled(state == Qt::Checked); ui->camera_file->setDisabled(state == Qt::Checked);
ui->toolButton->setDisabled(state == Qt::Checked); ui->toolButton->setDisabled(state == Qt::Checked);
@ -99,12 +97,11 @@ void ConfigureCamera::ConnectEvents() {
ui->camera_file->setText(QString{}); ui->camera_file->setText(QString{});
} }
}); });
connect(ui->camera_file, &QLineEdit::textChanged, this, [=] { StopPreviewing(); }); connect(ui->camera_file, &QLineEdit::textChanged, this, [this] { StopPreviewing(); });
connect(ui->system_camera, connect(ui->system_camera, qOverload<int>(&QComboBox::currentIndexChanged), this,
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, [this] { StopPreviewing(); });
[=] { StopPreviewing(); }); connect(ui->camera_flip, qOverload<int>(&QComboBox::currentIndexChanged), this,
connect(ui->camera_flip, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), [this] { StopPreviewing(); });
this, [=] { StopPreviewing(); });
} }
void ConfigureCamera::UpdateCameraMode() { void ConfigureCamera::UpdateCameraMode() {

View File

@ -24,7 +24,9 @@ ConfigureDebug::ConfigureDebug(QWidget* parent)
QString path = QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::LogDir)); QString path = QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::LogDir));
QDesktopServices::openUrl(QUrl::fromLocalFile(path)); QDesktopServices::openUrl(QUrl::fromLocalFile(path));
}); });
ui->toggle_cpu_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn());
const bool is_powered_on = Core::System::GetInstance().IsPoweredOn();
ui->toggle_cpu_jit->setEnabled(!is_powered_on);
} }
ConfigureDebug::~ConfigureDebug() = default; ConfigureDebug::~ConfigureDebug() = default;

View File

@ -114,6 +114,9 @@
<layout class="QVBoxLayout" name="verticalLayout_4"> <layout class="QVBoxLayout" name="verticalLayout_4">
<item> <item>
<widget class="QCheckBox" name="toggle_cpu_jit"> <widget class="QCheckBox" name="toggle_cpu_jit">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enables the use of the ARM JIT compiler for emulating the 3DS CPUs. Don't disable unless for debugging purposes&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text"> <property name="text">
<string>Enable CPU JIT</string> <string>Enable CPU JIT</string>
</property> </property>

View File

@ -192,10 +192,10 @@ ConfigureInput::ConfigureInput(QWidget* parent)
if (!button_map[button_id]) if (!button_map[button_id])
continue; continue;
button_map[button_id]->setContextMenuPolicy(Qt::CustomContextMenu); button_map[button_id]->setContextMenuPolicy(Qt::CustomContextMenu);
connect(button_map[button_id], &QPushButton::clicked, [=]() { connect(button_map[button_id], &QPushButton::clicked, [this, button_id]() {
HandleClick( HandleClick(
button_map[button_id], button_map[button_id],
[=](const Common::ParamPackage& params) { [this, button_id](const Common::ParamPackage& params) {
buttons_param[button_id] = params; buttons_param[button_id] = params;
// If the user closes the dialog, the changes are reverted in // If the user closes the dialog, the changes are reverted in
// `GMainWindow::OnConfigure()` // `GMainWindow::OnConfigure()`
@ -204,16 +204,16 @@ ConfigureInput::ConfigureInput(QWidget* parent)
}, },
InputCommon::Polling::DeviceType::Button); InputCommon::Polling::DeviceType::Button);
}); });
connect(button_map[button_id], &QPushButton::customContextMenuRequested, connect(button_map[button_id], &QPushButton::customContextMenuRequested, this,
[=](const QPoint& menu_location) { [this, button_id](const QPoint& menu_location) {
QMenu context_menu; QMenu context_menu;
context_menu.addAction(tr("Clear"), [&] { context_menu.addAction(tr("Clear"), this, [&] {
buttons_param[button_id].Clear(); buttons_param[button_id].Clear();
button_map[button_id]->setText(tr("[not set]")); button_map[button_id]->setText(tr("[not set]"));
ApplyConfiguration(); ApplyConfiguration();
Settings::SaveProfile(ui->profile->currentIndex()); Settings::SaveProfile(ui->profile->currentIndex());
}); });
context_menu.addAction(tr("Restore Default"), [&] { context_menu.addAction(tr("Restore Default"), this, [&] {
buttons_param[button_id] = Common::ParamPackage{ buttons_param[button_id] = Common::ParamPackage{
InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])}; InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])};
button_map[button_id]->setText(ButtonToText(buttons_param[button_id])); button_map[button_id]->setText(ButtonToText(buttons_param[button_id]));
@ -230,27 +230,29 @@ ConfigureInput::ConfigureInput(QWidget* parent)
continue; continue;
analog_map_buttons[analog_id][sub_button_id]->setContextMenuPolicy( analog_map_buttons[analog_id][sub_button_id]->setContextMenuPolicy(
Qt::CustomContextMenu); Qt::CustomContextMenu);
connect(analog_map_buttons[analog_id][sub_button_id], &QPushButton::clicked, [=]() { connect(analog_map_buttons[analog_id][sub_button_id], &QPushButton::clicked, this,
HandleClick( [this, analog_id, sub_button_id]() {
analog_map_buttons[analog_id][sub_button_id], HandleClick(
[=](const Common::ParamPackage& params) { analog_map_buttons[analog_id][sub_button_id],
SetAnalogButton(params, analogs_param[analog_id], [this, analog_id, sub_button_id](const Common::ParamPackage& params) {
analog_sub_buttons[sub_button_id]); SetAnalogButton(params, analogs_param[analog_id],
ApplyConfiguration(); analog_sub_buttons[sub_button_id]);
Settings::SaveProfile(ui->profile->currentIndex()); ApplyConfiguration();
}, Settings::SaveProfile(ui->profile->currentIndex());
InputCommon::Polling::DeviceType::Button); },
}); InputCommon::Polling::DeviceType::Button);
});
connect(analog_map_buttons[analog_id][sub_button_id], connect(analog_map_buttons[analog_id][sub_button_id],
&QPushButton::customContextMenuRequested, [=](const QPoint& menu_location) { &QPushButton::customContextMenuRequested, this,
[this, analog_id, sub_button_id](const QPoint& menu_location) {
QMenu context_menu; QMenu context_menu;
context_menu.addAction(tr("Clear"), [&] { context_menu.addAction(tr("Clear"), this, [&] {
analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]); analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]);
analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]")); analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]"));
ApplyConfiguration(); ApplyConfiguration();
Settings::SaveProfile(ui->profile->currentIndex()); Settings::SaveProfile(ui->profile->currentIndex());
}); });
context_menu.addAction(tr("Restore Default"), [&] { context_menu.addAction(tr("Restore Default"), this, [&] {
Common::ParamPackage params{InputCommon::GenerateKeyboardParam( Common::ParamPackage params{InputCommon::GenerateKeyboardParam(
Config::default_analogs[analog_id][sub_button_id])}; Config::default_analogs[analog_id][sub_button_id])};
SetAnalogButton(params, analogs_param[analog_id], SetAnalogButton(params, analogs_param[analog_id],
@ -264,7 +266,7 @@ ConfigureInput::ConfigureInput(QWidget* parent)
menu_location)); menu_location));
}); });
} }
connect(analog_map_stick[analog_id], &QPushButton::clicked, [=]() { connect(analog_map_stick[analog_id], &QPushButton::clicked, this, [this, analog_id]() {
if (QMessageBox::information( if (QMessageBox::information(
this, tr("Information"), this, tr("Information"),
tr("After pressing OK, first move your joystick horizontally, " tr("After pressing OK, first move your joystick horizontally, "
@ -272,7 +274,7 @@ ConfigureInput::ConfigureInput(QWidget* parent)
QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) { QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) {
HandleClick( HandleClick(
analog_map_stick[analog_id], analog_map_stick[analog_id],
[=](const Common::ParamPackage& params) { [this, analog_id](const Common::ParamPackage& params) {
analogs_param[analog_id] = params; analogs_param[analog_id] = params;
ApplyConfiguration(); ApplyConfiguration();
Settings::SaveProfile(ui->profile->currentIndex()); Settings::SaveProfile(ui->profile->currentIndex());
@ -280,29 +282,31 @@ ConfigureInput::ConfigureInput(QWidget* parent)
InputCommon::Polling::DeviceType::Analog); InputCommon::Polling::DeviceType::Analog);
} }
}); });
connect(analog_map_deadzone_and_modifier_slider[analog_id], &QSlider::valueChanged, [=] { connect(analog_map_deadzone_and_modifier_slider[analog_id], &QSlider::valueChanged, this,
const int slider_value = analog_map_deadzone_and_modifier_slider[analog_id]->value(); [this, analog_id] {
const auto engine = analogs_param[analog_id].Get("engine", ""); const int slider_value =
if (engine == "sdl" || engine == "gcpad") { analog_map_deadzone_and_modifier_slider[analog_id]->value();
analog_map_deadzone_and_modifier_slider_label[analog_id]->setText( const auto engine = analogs_param[analog_id].Get("engine", "");
tr("Deadzone: %1%").arg(slider_value)); if (engine == "sdl" || engine == "gcpad") {
analogs_param[analog_id].Set("deadzone", slider_value / 100.0f); analog_map_deadzone_and_modifier_slider_label[analog_id]->setText(
} else { tr("Deadzone: %1%").arg(slider_value));
analog_map_deadzone_and_modifier_slider_label[analog_id]->setText( analogs_param[analog_id].Set("deadzone", slider_value / 100.0f);
tr("Modifier Scale: %1%").arg(slider_value)); } else {
analogs_param[analog_id].Set("modifier_scale", slider_value / 100.0f); analog_map_deadzone_and_modifier_slider_label[analog_id]->setText(
} tr("Modifier Scale: %1%").arg(slider_value));
ApplyConfiguration(); analogs_param[analog_id].Set("modifier_scale", slider_value / 100.0f);
Settings::SaveProfile(ui->profile->currentIndex()); }
}); ApplyConfiguration();
Settings::SaveProfile(ui->profile->currentIndex());
});
} }
// The Circle Mod button is common for both the sticks, so update the modifier settings // The Circle Mod button is common for both the sticks, so update the modifier settings
// for both the sticks. // for both the sticks.
connect(ui->buttonCircleMod, &QPushButton::clicked, [=]() { connect(ui->buttonCircleMod, &QPushButton::clicked, this, [this]() {
HandleClick( HandleClick(
ui->buttonCircleMod, ui->buttonCircleMod,
[=](const Common::ParamPackage& params) { [this](const Common::ParamPackage& params) {
for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs;
analog_id++) { analog_id++) {
SetAnalogButton(params, analogs_param[analog_id], "modifier"); SetAnalogButton(params, analogs_param[analog_id], "modifier");
@ -312,10 +316,10 @@ ConfigureInput::ConfigureInput(QWidget* parent)
}, },
InputCommon::Polling::DeviceType::Button); InputCommon::Polling::DeviceType::Button);
}); });
connect(ui->buttonCircleMod, &QPushButton::customContextMenuRequested, connect(ui->buttonCircleMod, &QPushButton::customContextMenuRequested, this,
[&](const QPoint& menu_location) { [&](const QPoint& menu_location) {
QMenu context_menu; QMenu context_menu;
context_menu.addAction(tr("Clear"), [&] { context_menu.addAction(tr("Clear"), this, [&] {
for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs;
analog_id++) { analog_id++) {
analogs_param[analog_id].Erase("modifier"); analogs_param[analog_id].Erase("modifier");
@ -325,7 +329,7 @@ ConfigureInput::ConfigureInput(QWidget* parent)
Settings::SaveProfile(ui->profile->currentIndex()); Settings::SaveProfile(ui->profile->currentIndex());
}); });
context_menu.addAction(tr("Restore Default"), [&] { context_menu.addAction(tr("Restore Default"), this, [&] {
for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs;
analog_id++) { analog_id++) {
Common::ParamPackage params{InputCommon::GenerateKeyboardParam( Common::ParamPackage params{InputCommon::GenerateKeyboardParam(
@ -341,7 +345,7 @@ ConfigureInput::ConfigureInput(QWidget* parent)
context_menu.exec(ui->buttonCircleMod->mapToGlobal(menu_location)); context_menu.exec(ui->buttonCircleMod->mapToGlobal(menu_location));
}); });
connect(ui->buttonMotionTouch, &QPushButton::clicked, [this] { connect(ui->buttonMotionTouch, &QPushButton::clicked, this, [this] {
QDialog* motion_touch_dialog = new ConfigureMotionTouch(this); QDialog* motion_touch_dialog = new ConfigureMotionTouch(this);
return motion_touch_dialog->exec(); return motion_touch_dialog->exec();
}); });
@ -356,18 +360,17 @@ ConfigureInput::ConfigureInput(QWidget* parent)
connect(ui->buttonDelete, &QPushButton::clicked, this, &ConfigureInput::DeleteProfile); connect(ui->buttonDelete, &QPushButton::clicked, this, &ConfigureInput::DeleteProfile);
connect(ui->buttonRename, &QPushButton::clicked, this, &ConfigureInput::RenameProfile); connect(ui->buttonRename, &QPushButton::clicked, this, &ConfigureInput::RenameProfile);
connect(ui->profile, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), connect(ui->profile, qOverload<int>(&QComboBox::currentIndexChanged), this, [this](int i) {
[this](int i) { ApplyConfiguration();
ApplyConfiguration(); Settings::SaveProfile(Settings::values.current_input_profile_index);
Settings::SaveProfile(Settings::values.current_input_profile_index); Settings::LoadProfile(i);
Settings::LoadProfile(i); LoadConfiguration();
LoadConfiguration(); });
});
timeout_timer->setSingleShot(true); timeout_timer->setSingleShot(true);
connect(timeout_timer.get(), &QTimer::timeout, [this]() { SetPollingResult({}, true); }); connect(timeout_timer.get(), &QTimer::timeout, this, [this]() { SetPollingResult({}, true); });
connect(poll_timer.get(), &QTimer::timeout, [this]() { connect(poll_timer.get(), &QTimer::timeout, this, [this]() {
Common::ParamPackage params; Common::ParamPackage params;
for (auto& poller : device_pollers) { for (auto& poller : device_pollers) {
params = poller->GetNextInput(); params = poller->GetNextInput();
@ -554,7 +557,7 @@ void ConfigureInput::AutoMap() {
QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel) { QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel) {
return; return;
} }
input_setter = [=](const Common::ParamPackage& params) { input_setter = [this](const Common::ParamPackage& params) {
MapFromButton(params); MapFromButton(params);
ApplyConfiguration(); ApplyConfiguration();
Settings::SaveProfile(ui->profile->currentIndex()); Settings::SaveProfile(ui->profile->currentIndex());

View File

@ -47,6 +47,9 @@ CalibrationConfigurationDialog::CalibrationConfigurationDialog(QWidget* parent,
case CalibrationConfigurationJob::Status::Completed: case CalibrationConfigurationJob::Status::Completed:
text = tr("Configuration completed!"); text = tr("Configuration completed!");
break; break;
default:
LOG_ERROR(Frontend, "Unknown calibration status {}", status);
break;
} }
QMetaObject::invokeMethod(this, "UpdateLabelText", Q_ARG(QString, text)); QMetaObject::invokeMethod(this, "UpdateLabelText", Q_ARG(QString, text));
if (status == CalibrationConfigurationJob::Status::Completed) { if (status == CalibrationConfigurationJob::Status::Completed) {
@ -102,9 +105,9 @@ ConfigureMotionTouch::ConfigureMotionTouch(QWidget* parent)
"style=\"text-decoration: underline; color:#039be5;\">Learn More</span></a>")); "style=\"text-decoration: underline; color:#039be5;\">Learn More</span></a>"));
timeout_timer->setSingleShot(true); timeout_timer->setSingleShot(true);
connect(timeout_timer.get(), &QTimer::timeout, [this]() { SetPollingResult({}, true); }); connect(timeout_timer.get(), &QTimer::timeout, this, [this]() { SetPollingResult({}, true); });
connect(poll_timer.get(), &QTimer::timeout, [this]() { connect(poll_timer.get(), &QTimer::timeout, this, [this]() {
Common::ParamPackage params; Common::ParamPackage params;
for (auto& poller : device_pollers) { for (auto& poller : device_pollers) {
params = poller->GetNextInput(); params = poller->GetNextInput();
@ -202,7 +205,7 @@ void ConfigureMotionTouch::ConnectEvents() {
[this]([[maybe_unused]] int index) { UpdateUiDisplay(); }); [this]([[maybe_unused]] int index) { UpdateUiDisplay(); });
connect(ui->touch_provider, qOverload<int>(&QComboBox::currentIndexChanged), this, connect(ui->touch_provider, qOverload<int>(&QComboBox::currentIndexChanged), this,
[this]([[maybe_unused]] int index) { UpdateUiDisplay(); }); [this]([[maybe_unused]] int index) { UpdateUiDisplay(); });
connect(ui->motion_controller_button, &QPushButton::clicked, [=]() { connect(ui->motion_controller_button, &QPushButton::clicked, this, [this]() {
if (QMessageBox::information(this, tr("Information"), if (QMessageBox::information(this, tr("Information"),
tr("After pressing OK, press a button on the controller whose " tr("After pressing OK, press a button on the controller whose "
"motion you want to track."), "motion you want to track."),
@ -210,7 +213,7 @@ void ConfigureMotionTouch::ConnectEvents() {
ui->motion_controller_button->setText(tr("[press button]")); ui->motion_controller_button->setText(tr("[press button]"));
ui->motion_controller_button->setFocus(); ui->motion_controller_button->setFocus();
input_setter = [=](const Common::ParamPackage& params) { input_setter = [this](const Common::ParamPackage& params) {
guid = params.Get("guid", "0"); guid = params.Get("guid", "0");
port = params.Get("port", 0); port = params.Get("port", 0);
}; };

View File

@ -511,7 +511,7 @@ void TouchScreenPreview::mouseMoveEvent(QMouseEvent* event) {
} }
const auto pos = MapToDeviceCoords(event->x(), event->y()); const auto pos = MapToDeviceCoords(event->x(), event->y());
if (pos) { if (pos) {
coord_label->setText(QStringLiteral("X: %1, Y: %2").arg(pos->x()).arg(pos->y())); coord_label->setText(QStringLiteral("X: %1, Y: %2").arg(pos->x(), pos->y()));
} else { } else {
coord_label->clear(); coord_label->clear();
} }
@ -572,7 +572,7 @@ bool TouchScreenPreview::eventFilter(QObject* obj, QEvent* event) {
emit DotMoved(drag_state.dot->property(PropId).toInt(), *device_coord); emit DotMoved(drag_state.dot->property(PropId).toInt(), *device_coord);
if (coord_label) { if (coord_label) {
coord_label->setText( coord_label->setText(
QStringLiteral("X: %1, Y: %2").arg(device_coord->x()).arg(device_coord->y())); QStringLiteral("X: %1, Y: %2").arg(device_coord->x(), device_coord->y()));
} }
} }
return true; return true;

View File

@ -9,7 +9,6 @@
#include <QVBoxLayout> #include <QVBoxLayout>
#include "citra_qt/debugger/graphics/graphics_breakpoints.h" #include "citra_qt/debugger/graphics/graphics_breakpoints.h"
#include "citra_qt/debugger/graphics/graphics_breakpoints_p.h" #include "citra_qt/debugger/graphics/graphics_breakpoints_p.h"
#include "common/assert.h"
BreakPointModel::BreakPointModel(std::shared_ptr<Pica::DebugContext> debug_context, QObject* parent) BreakPointModel::BreakPointModel(std::shared_ptr<Pica::DebugContext> debug_context, QObject* parent)
: QAbstractListModel(parent), context_weak(debug_context), : QAbstractListModel(parent), context_weak(debug_context),
@ -60,12 +59,15 @@ QVariant BreakPointModel::data(const QModelIndex& index, int role) const {
} }
Qt::ItemFlags BreakPointModel::flags(const QModelIndex& index) const { Qt::ItemFlags BreakPointModel::flags(const QModelIndex& index) const {
if (!index.isValid()) if (!index.isValid()) {
return 0; return {};
}
Qt::ItemFlags flags = Qt::ItemIsEnabled; Qt::ItemFlags flags = Qt::ItemIsEnabled;
if (index.column() == 0) if (index.column() == 0) {
flags |= Qt::ItemIsUserCheckable; flags |= Qt::ItemIsUserCheckable;
}
return flags; return flags;
} }

View File

@ -14,7 +14,6 @@
#include <QTreeView> #include <QTreeView>
#include <QVBoxLayout> #include <QVBoxLayout>
#include "citra_qt/debugger/graphics/graphics_cmdlists.h" #include "citra_qt/debugger/graphics/graphics_cmdlists.h"
#include "citra_qt/util/spinbox.h"
#include "citra_qt/util/util.h" #include "citra_qt/util/util.h"
#include "common/vector_math.h" #include "common/vector_math.h"
#include "core/core.h" #include "core/core.h"
@ -130,7 +129,7 @@ void GPUCommandListWidget::OnCommandDoubleClicked(const QModelIndex& index) {
COMMAND_IN_RANGE(command_id, texturing.texture1) || COMMAND_IN_RANGE(command_id, texturing.texture1) ||
COMMAND_IN_RANGE(command_id, texturing.texture2)) { COMMAND_IN_RANGE(command_id, texturing.texture2)) {
unsigned texture_index; [[maybe_unused]] u32 texture_index;
if (COMMAND_IN_RANGE(command_id, texturing.texture0)) { if (COMMAND_IN_RANGE(command_id, texturing.texture0)) {
texture_index = 0; texture_index = 0;
} else if (COMMAND_IN_RANGE(command_id, texturing.texture1)) { } else if (COMMAND_IN_RANGE(command_id, texturing.texture1)) {

View File

@ -34,12 +34,15 @@ void SurfacePicture::mousePressEvent(QMouseEvent* event) {
if (!(event->buttons() & Qt::LeftButton)) if (!(event->buttons() & Qt::LeftButton))
return; return;
if (pixmap() == nullptr) const QPixmap pixmap = this->pixmap(Qt::ReturnByValue);
if (pixmap.isNull()) {
return; return;
}
if (surface_widget) if (surface_widget) {
surface_widget->Pick(event->x() * pixmap()->width() / width(), surface_widget->Pick(event->x() * pixmap.width() / width(),
event->y() * pixmap()->height() / height()); event->y() * pixmap.height() / height());
}
} }
void SurfacePicture::mouseMoveEvent(QMouseEvent* event) { void SurfacePicture::mouseMoveEvent(QMouseEvent* event) {
@ -314,57 +317,46 @@ void GraphicsSurfaceWidget::Pick(int x, int y) {
case Format::RGBA8: { case Format::RGBA8: {
auto value = Color::DecodeRGBA8(pixel) / 255.0f; auto value = Color::DecodeRGBA8(pixel) / 255.0f;
return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4") return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4")
.arg(QString::number(value.r(), 'f', 2)) .arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2),
.arg(QString::number(value.g(), 'f', 2)) QString::number(value.b(), 'f', 2), QString::number(value.a(), 'f', 2));
.arg(QString::number(value.b(), 'f', 2))
.arg(QString::number(value.a(), 'f', 2));
} }
case Format::RGB8: { case Format::RGB8: {
auto value = Color::DecodeRGB8(pixel) / 255.0f; auto value = Color::DecodeRGB8(pixel) / 255.0f;
return QStringLiteral("Red: %1, Green: %2, Blue: %3") return QStringLiteral("Red: %1, Green: %2, Blue: %3")
.arg(QString::number(value.r(), 'f', 2)) .arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2),
.arg(QString::number(value.g(), 'f', 2)) QString::number(value.b(), 'f', 2));
.arg(QString::number(value.b(), 'f', 2));
} }
case Format::RGB5A1: { case Format::RGB5A1: {
auto value = Color::DecodeRGB5A1(pixel) / 255.0f; auto value = Color::DecodeRGB5A1(pixel) / 255.0f;
return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4") return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4")
.arg(QString::number(value.r(), 'f', 2)) .arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2),
.arg(QString::number(value.g(), 'f', 2)) QString::number(value.b(), 'f', 2), QString::number(value.a(), 'f', 2));
.arg(QString::number(value.b(), 'f', 2))
.arg(QString::number(value.a(), 'f', 2));
} }
case Format::RGB565: { case Format::RGB565: {
auto value = Color::DecodeRGB565(pixel) / 255.0f; auto value = Color::DecodeRGB565(pixel) / 255.0f;
return QStringLiteral("Red: %1, Green: %2, Blue: %3") return QStringLiteral("Red: %1, Green: %2, Blue: %3")
.arg(QString::number(value.r(), 'f', 2)) .arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2),
.arg(QString::number(value.g(), 'f', 2)) QString::number(value.b(), 'f', 2));
.arg(QString::number(value.b(), 'f', 2));
} }
case Format::RGBA4: { case Format::RGBA4: {
auto value = Color::DecodeRGBA4(pixel) / 255.0f; auto value = Color::DecodeRGBA4(pixel) / 255.0f;
return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4") return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4")
.arg(QString::number(value.r(), 'f', 2)) .arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2),
.arg(QString::number(value.g(), 'f', 2)) QString::number(value.b(), 'f', 2), QString::number(value.a(), 'f', 2));
.arg(QString::number(value.b(), 'f', 2))
.arg(QString::number(value.a(), 'f', 2));
} }
case Format::IA8: case Format::IA8:
return QStringLiteral("Index: %1, Alpha: %2").arg(pixel[0]).arg(pixel[1]); return QStringLiteral("Index: %1, Alpha: %2").arg(pixel[0], pixel[1]);
case Format::RG8: { case Format::RG8: {
auto value = Color::DecodeRG8(pixel) / 255.0f; auto value = Color::DecodeRG8(pixel) / 255.0f;
return QStringLiteral("Red: %1, Green: %2") return QStringLiteral("Red: %1, Green: %2")
.arg(QString::number(value.r(), 'f', 2)) .arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2));
.arg(QString::number(value.g(), 'f', 2));
} }
case Format::I8: case Format::I8:
return QStringLiteral("Index: %1").arg(*pixel); return QStringLiteral("Index: %1").arg(*pixel);
case Format::A8: case Format::A8:
return QStringLiteral("Alpha: %1").arg(QString::number(*pixel / 255.0f, 'f', 2)); return QStringLiteral("Alpha: %1").arg(QString::number(*pixel / 255.0f, 'f', 2));
case Format::IA4: case Format::IA4:
return QStringLiteral("Index: %1, Alpha: %2") return QStringLiteral("Index: %1, Alpha: %2").arg(*pixel & 0xF, (*pixel & 0xF0) >> 4);
.arg(*pixel & 0xF)
.arg((*pixel & 0xF0) >> 4);
case Format::I4: { case Format::I4: {
u8 i = (*pixel >> ((offset % 2) ? 4 : 0)) & 0xF; u8 i = (*pixel >> ((offset % 2) ? 4 : 0)) & 0xF;
return QStringLiteral("Index: %1").arg(i); return QStringLiteral("Index: %1").arg(i);
@ -390,8 +382,7 @@ void GraphicsSurfaceWidget::Pick(int x, int y) {
case Format::X24S8: { case Format::X24S8: {
auto values = Color::DecodeD24S8(pixel); auto values = Color::DecodeD24S8(pixel);
return QStringLiteral("Depth: %1, Stencil: %2") return QStringLiteral("Depth: %1, Stencil: %2")
.arg(QString::number(values[0] / (float)0xFFFFFF, 'f', 4)) .arg(QString::number(values[0] / (float)0xFFFFFF, 'f', 4), values[1]);
.arg(values[1]);
} }
case Format::Unknown: case Format::Unknown:
return QStringLiteral("Unknown format"); return QStringLiteral("Unknown format");
@ -401,8 +392,8 @@ void GraphicsSurfaceWidget::Pick(int x, int y) {
}; };
QString nibbles; QString nibbles;
for (unsigned i = 0; i < nibbles_per_pixel; i++) { for (u32 i = 0; i < nibbles_per_pixel; i++) {
unsigned nibble_index = i; u32 nibble_index = i;
if (nibble_mode) { if (nibble_mode) {
nibble_index += (offset % 2) ? 0 : 1; nibble_index += (offset % 2) ? 0 : 1;
} }
@ -412,7 +403,7 @@ void GraphicsSurfaceWidget::Pick(int x, int y) {
} }
surface_info_label->setText( surface_info_label->setText(
QStringLiteral("Raw: 0x%3\n(%4)").arg(nibbles).arg(GetText(surface_format, pixel))); QStringLiteral("Raw: 0x%3\n(%4)").arg(nibbles, GetText(surface_format, pixel)));
surface_info_label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); surface_info_label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
} }
@ -676,8 +667,8 @@ void GraphicsSurfaceWidget::SaveSurface() {
} }
if (selected_filter == png_filter) { if (selected_filter == png_filter) {
const QPixmap* const pixmap = surface_picture_label->pixmap(); const QPixmap pixmap = surface_picture_label->pixmap(Qt::ReturnByValue);
ASSERT_MSG(pixmap != nullptr, "No pixmap set"); ASSERT_MSG(!pixmap.isNull(), "No pixmap set");
QFile file{filename}; QFile file{filename};
if (!file.open(QIODevice::WriteOnly)) { if (!file.open(QIODevice::WriteOnly)) {
@ -685,7 +676,7 @@ void GraphicsSurfaceWidget::SaveSurface() {
return; return;
} }
if (!pixmap->save(&file, "PNG")) { if (!pixmap.save(&file, "PNG")) {
QMessageBox::warning(this, tr("Error"), QMessageBox::warning(this, tr("Error"),
tr("Failed to save surface data to file '%1'").arg(filename)); tr("Failed to save surface data to file '%1'").arg(filename));
} }

View File

@ -111,13 +111,13 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con
} }
}; };
const Instruction instr = par->info.code[index.row()]; const Instruction& instr = par->info.code[index.row()];
const OpCode opcode = instr.opcode; const OpCode opcode = instr.opcode;
const OpCode::Info opcode_info = opcode.GetInfo(); const OpCode::Info opcode_info = opcode.GetInfo();
const u32 operand_desc_id = opcode_info.type == OpCode::Type::MultiplyAdd const u32 operand_desc_id = opcode_info.type == OpCode::Type::MultiplyAdd
? instr.mad.operand_desc_id.Value() ? instr.mad.operand_desc_id.Value()
: instr.common.operand_desc_id.Value(); : instr.common.operand_desc_id.Value();
const SwizzlePattern swizzle = par->info.swizzle_info[operand_desc_id].pattern; const SwizzlePattern& swizzle = par->info.swizzle_info[operand_desc_id].pattern;
// longest known instruction name: "setemit " // longest known instruction name: "setemit "
int kOpcodeColumnWidth = 8; int kOpcodeColumnWidth = 8;
@ -407,8 +407,8 @@ GraphicsVertexShaderWidget::GraphicsVertexShaderWidget(
static_cast<void (QSignalMapper::*)()>(&QSignalMapper::map)); static_cast<void (QSignalMapper::*)()>(&QSignalMapper::map));
input_data_mapper->setMapping(input_data[i], i); input_data_mapper->setMapping(input_data[i], i);
} }
connect(input_data_mapper, static_cast<void (QSignalMapper::*)(int)>(&QSignalMapper::mapped), connect(input_data_mapper, &QSignalMapper::mappedInt, this,
this, &GraphicsVertexShaderWidget::OnInputAttributeChanged); &GraphicsVertexShaderWidget::OnInputAttributeChanged);
auto main_widget = new QWidget; auto main_widget = new QWidget;
auto main_layout = new QVBoxLayout; auto main_layout = new QVBoxLayout;
@ -514,8 +514,10 @@ void GraphicsVertexShaderWidget::Reload(bool replace_vertex_data, void* vertex_d
info.code.push_back({instr}); info.code.push_back({instr});
int num_attributes = shader_config.max_input_attribute_index + 1; int num_attributes = shader_config.max_input_attribute_index + 1;
for (auto pattern : shader_setup.swizzle_data) for (auto pattern : shader_setup.swizzle_data) {
info.swizzle_info.push_back({pattern}); const nihstro::SwizzleInfo swizzle_info = {.pattern = nihstro::SwizzlePattern{pattern}};
info.swizzle_info.push_back(swizzle_info);
}
u32 entry_point = Pica::g_state.regs.vs.main_offset; u32 entry_point = Pica::g_state.regs.vs.main_offset;
info.labels.insert({entry_point, "main"}); info.labels.insert({entry_point, "main"});

View File

@ -57,6 +57,7 @@ QString IPCRecorderWidget::GetStatusStr(const IPCDebugger::RequestRecord& record
return tr("HLE Unimplemented"); return tr("HLE Unimplemented");
default: default:
UNREACHABLE(); UNREACHABLE();
return QLatin1String{};
} }
} }

View File

@ -160,7 +160,8 @@ void MicroProfileWidget::mouseReleaseEvent(QMouseEvent* event) {
} }
void MicroProfileWidget::wheelEvent(QWheelEvent* event) { void MicroProfileWidget::wheelEvent(QWheelEvent* event) {
MicroProfileMousePosition(event->x() / x_scale, event->y() / y_scale, event->delta() / 120); MicroProfileMousePosition(event->position().x() / x_scale, event->position().y() / y_scale,
event->angleDelta().y() / 120);
event->accept(); event->accept();
} }

View File

@ -114,7 +114,7 @@ void OptionSetDialog::InitializeUI(const std::string& initial_value) {
ui->formatLabel->text().append(QStringLiteral("\n")); ui->formatLabel->text().append(QStringLiteral("\n"));
} }
ui->formatLabel->setText( ui->formatLabel->setText(
ui->formatLabel->text().append(tr("Range: %1 - %2").arg(option.min).arg(option.max))); ui->formatLabel->text().append(tr("Range: %1 - %2").arg(option.min, option.max)));
} }
// Decide and initialize layout // Decide and initialize layout

View File

@ -169,8 +169,7 @@ GameListSearchField::GameListSearchField(GameList* parent) : QWidget{parent} {
* @return true if the haystack contains all words of userinput * @return true if the haystack contains all words of userinput
*/ */
static bool ContainsAllWords(const QString& haystack, const QString& userinput) { static bool ContainsAllWords(const QString& haystack, const QString& userinput) {
const QStringList userinput_split = const QStringList userinput_split = userinput.split(QLatin1Char{' '}, Qt::SkipEmptyParts);
userinput.split(QLatin1Char{' '}, QString::SplitBehavior::SkipEmptyParts);
return std::all_of(userinput_split.begin(), userinput_split.end(), return std::all_of(userinput_split.begin(), userinput_split.end(),
[&haystack](const QString& s) { return haystack.contains(s); }); [&haystack](const QString& s) { return haystack.contains(s); });
@ -511,42 +510,42 @@ void GameList::AddGamePopup(QMenu& context_menu, const QString& path, u64 progra
navigate_to_gamedb_entry->setVisible(it != compatibility_list.end()); navigate_to_gamedb_entry->setVisible(it != compatibility_list.end());
connect(open_save_location, &QAction::triggered, [this, program_id] { connect(open_save_location, &QAction::triggered, this, [this, program_id] {
emit OpenFolderRequested(program_id, GameListOpenTarget::SAVE_DATA); emit OpenFolderRequested(program_id, GameListOpenTarget::SAVE_DATA);
}); });
connect(open_extdata_location, &QAction::triggered, [this, extdata_id] { connect(open_extdata_location, &QAction::triggered, this, [this, extdata_id] {
emit OpenFolderRequested(extdata_id, GameListOpenTarget::EXT_DATA); emit OpenFolderRequested(extdata_id, GameListOpenTarget::EXT_DATA);
}); });
connect(open_application_location, &QAction::triggered, [this, program_id] { connect(open_application_location, &QAction::triggered, this, [this, program_id] {
emit OpenFolderRequested(program_id, GameListOpenTarget::APPLICATION); emit OpenFolderRequested(program_id, GameListOpenTarget::APPLICATION);
}); });
connect(open_update_location, &QAction::triggered, [this, program_id] { connect(open_update_location, &QAction::triggered, this, [this, program_id] {
emit OpenFolderRequested(program_id, GameListOpenTarget::UPDATE_DATA); emit OpenFolderRequested(program_id, GameListOpenTarget::UPDATE_DATA);
}); });
connect(open_texture_dump_location, &QAction::triggered, [this, program_id] { connect(open_texture_dump_location, &QAction::triggered, this, [this, program_id] {
if (FileUtil::CreateFullPath(fmt::format("{}textures/{:016X}/", if (FileUtil::CreateFullPath(fmt::format("{}textures/{:016X}/",
FileUtil::GetUserPath(FileUtil::UserPath::DumpDir), FileUtil::GetUserPath(FileUtil::UserPath::DumpDir),
program_id))) { program_id))) {
emit OpenFolderRequested(program_id, GameListOpenTarget::TEXTURE_DUMP); emit OpenFolderRequested(program_id, GameListOpenTarget::TEXTURE_DUMP);
} }
}); });
connect(open_texture_load_location, &QAction::triggered, [this, program_id] { connect(open_texture_load_location, &QAction::triggered, this, [this, program_id] {
if (FileUtil::CreateFullPath(fmt::format("{}textures/{:016X}/", if (FileUtil::CreateFullPath(fmt::format("{}textures/{:016X}/",
FileUtil::GetUserPath(FileUtil::UserPath::LoadDir), FileUtil::GetUserPath(FileUtil::UserPath::LoadDir),
program_id))) { program_id))) {
emit OpenFolderRequested(program_id, GameListOpenTarget::TEXTURE_LOAD); emit OpenFolderRequested(program_id, GameListOpenTarget::TEXTURE_LOAD);
} }
}); });
connect(open_mods_location, &QAction::triggered, [this, program_id] { connect(open_mods_location, &QAction::triggered, this, [this, program_id] {
if (FileUtil::CreateFullPath(fmt::format("{}mods/{:016X}/", if (FileUtil::CreateFullPath(fmt::format("{}mods/{:016X}/",
FileUtil::GetUserPath(FileUtil::UserPath::LoadDir), FileUtil::GetUserPath(FileUtil::UserPath::LoadDir),
program_id))) { program_id))) {
emit OpenFolderRequested(program_id, GameListOpenTarget::MODS); emit OpenFolderRequested(program_id, GameListOpenTarget::MODS);
} }
}); });
connect(dump_romfs, &QAction::triggered, connect(dump_romfs, &QAction::triggered, this,
[this, path, program_id] { emit DumpRomFSRequested(path, program_id); }); [this, path, program_id] { emit DumpRomFSRequested(path, program_id); });
connect(navigate_to_gamedb_entry, &QAction::triggered, [this, program_id]() { connect(navigate_to_gamedb_entry, &QAction::triggered, this, [this, program_id]() {
emit NavigateToGamedbEntryRequested(program_id, compatibility_list); emit NavigateToGamedbEntryRequested(program_id, compatibility_list);
}); });
}; };
@ -561,11 +560,11 @@ void GameList::AddCustomDirPopup(QMenu& context_menu, QModelIndex selected) {
deep_scan->setCheckable(true); deep_scan->setCheckable(true);
deep_scan->setChecked(game_dir.deep_scan); deep_scan->setChecked(game_dir.deep_scan);
connect(deep_scan, &QAction::triggered, [this, &game_dir] { connect(deep_scan, &QAction::triggered, this, [this, &game_dir] {
game_dir.deep_scan = !game_dir.deep_scan; game_dir.deep_scan = !game_dir.deep_scan;
PopulateAsync(UISettings::values.game_dirs); PopulateAsync(UISettings::values.game_dirs);
}); });
connect(delete_dir, &QAction::triggered, [this, &game_dir, selected] { connect(delete_dir, &QAction::triggered, this, [this, &game_dir, selected] {
UISettings::values.game_dirs.removeOne(game_dir); UISettings::values.game_dirs.removeOne(game_dir);
item_model->invisibleRootItem()->removeRow(selected.row()); item_model->invisibleRootItem()->removeRow(selected.row());
}); });
@ -583,7 +582,7 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) {
move_up->setEnabled(row > 0); move_up->setEnabled(row > 0);
move_down->setEnabled(row < item_model->rowCount() - 2); move_down->setEnabled(row < item_model->rowCount() - 2);
connect(move_up, &QAction::triggered, [this, selected, row, game_dir_index] { connect(move_up, &QAction::triggered, this, [this, selected, row, game_dir_index] {
const int other_index = selected.sibling(row - 1, 0).data(GameListDir::GameDirRole).toInt(); const int other_index = selected.sibling(row - 1, 0).data(GameListDir::GameDirRole).toInt();
// swap the items in the settings // swap the items in the settings
std::swap(UISettings::values.game_dirs[game_dir_index], std::swap(UISettings::values.game_dirs[game_dir_index],
@ -598,7 +597,7 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) {
tree_view->setExpanded(selected, UISettings::values.game_dirs[game_dir_index].expanded); tree_view->setExpanded(selected, UISettings::values.game_dirs[game_dir_index].expanded);
}); });
connect(move_down, &QAction::triggered, [this, selected, row, game_dir_index] { connect(move_down, &QAction::triggered, this, [this, selected, row, game_dir_index] {
const int other_index = selected.sibling(row + 1, 0).data(GameListDir::GameDirRole).toInt(); const int other_index = selected.sibling(row + 1, 0).data(GameListDir::GameDirRole).toInt();
// swap the items in the settings // swap the items in the settings
std::swap(UISettings::values.game_dirs[game_dir_index], std::swap(UISettings::values.game_dirs[game_dir_index],
@ -613,7 +612,7 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) {
tree_view->setExpanded(selected, UISettings::values.game_dirs[game_dir_index].expanded); tree_view->setExpanded(selected, UISettings::values.game_dirs[game_dir_index].expanded);
}); });
connect(open_directory_location, &QAction::triggered, [this, game_dir_index] { connect(open_directory_location, &QAction::triggered, this, [this, game_dir_index] {
emit OpenDirectory(UISettings::values.game_dirs[game_dir_index].path); emit OpenDirectory(UISettings::values.game_dirs[game_dir_index].path);
}); });
} }
@ -640,7 +639,7 @@ void GameList::LoadCompatibilityList() {
const QJsonDocument json = QJsonDocument::fromJson(content); const QJsonDocument json = QJsonDocument::fromJson(content);
const QJsonArray arr = json.array(); const QJsonArray arr = json.array();
for (const QJsonValue value : arr) { for (const QJsonValue& value : arr) {
const QJsonObject game = value.toObject(); const QJsonObject game = value.toObject();
const QString compatibility_key = QStringLiteral("compatibility"); const QString compatibility_key = QStringLiteral("compatibility");
@ -652,7 +651,7 @@ void GameList::LoadCompatibilityList() {
const QString directory = game[QStringLiteral("directory")].toString(); const QString directory = game[QStringLiteral("directory")].toString();
const QJsonArray ids = game[QStringLiteral("releases")].toArray(); const QJsonArray ids = game[QStringLiteral("releases")].toArray();
for (const QJsonValue id_ref : ids) { for (const QJsonValue& id_ref : ids) {
const QJsonObject id_object = id_ref.toObject(); const QJsonObject id_object = id_ref.toObject();
const QString id = id_object[QStringLiteral("id")].toString(); const QString id = id_object[QStringLiteral("id")].toString();

View File

@ -152,8 +152,8 @@ static void InitializeLogging() {
} }
GMainWindow::GMainWindow() GMainWindow::GMainWindow()
: config(std::make_unique<Config>()), emu_thread(nullptr), : ui{std::make_unique<Ui::MainWindow>()}, config{std::make_unique<Config>()}, emu_thread{
ui(std::make_unique<Ui::MainWindow>()) { nullptr} {
InitializeLogging(); InitializeLogging();
Debugger::ToggleConsole(); Debugger::ToggleConsole();
Settings::LogSettings(); Settings::LogSettings();
@ -263,7 +263,7 @@ void GMainWindow::InitializeWidgets() {
loading_screen = new LoadingScreen(this); loading_screen = new LoadingScreen(this);
loading_screen->hide(); loading_screen->hide();
ui->horizontalLayout->addWidget(loading_screen); ui->horizontalLayout->addWidget(loading_screen);
connect(loading_screen, &LoadingScreen::Hidden, [&] { connect(loading_screen, &LoadingScreen::Hidden, this, [&] {
loading_screen->Clear(); loading_screen->Clear();
if (emulation_running) { if (emulation_running) {
render_window->show(); render_window->show();
@ -432,13 +432,13 @@ void GMainWindow::InitializeSaveStateMenuActions() {
ui->menu_Save_State->addAction(actions_save_state[i]); ui->menu_Save_State->addAction(actions_save_state[i]);
} }
connect(ui->action_Load_from_Newest_Slot, &QAction::triggered, [this] { connect(ui->action_Load_from_Newest_Slot, &QAction::triggered, this, [this] {
UpdateSaveStates(); UpdateSaveStates();
if (newest_slot != 0) { if (newest_slot != 0) {
actions_load_state[newest_slot - 1]->trigger(); actions_load_state[newest_slot - 1]->trigger();
} }
}); });
connect(ui->action_Save_to_Oldest_Slot, &QAction::triggered, [this] { connect(ui->action_Save_to_Oldest_Slot, &QAction::triggered, this, [this] {
UpdateSaveStates(); UpdateSaveStates();
actions_save_state[oldest_slot - 1]->trigger(); actions_save_state[oldest_slot - 1]->trigger();
}); });
@ -677,7 +677,7 @@ void GMainWindow::ConnectWidgetEvents() {
connect(game_list_placeholder, &GameListPlaceholder::AddDirectory, this, connect(game_list_placeholder, &GameListPlaceholder::AddDirectory, this,
&GMainWindow::OnGameListAddDirectory); &GMainWindow::OnGameListAddDirectory);
connect(game_list, &GameList::ShowList, this, &GMainWindow::OnGameListShowList); connect(game_list, &GameList::ShowList, this, &GMainWindow::OnGameListShowList);
connect(game_list, &GameList::PopulatingCompleted, connect(game_list, &GameList::PopulatingCompleted, this,
[this] { multiplayer_state->UpdateGameList(game_list->GetModel()); }); [this] { multiplayer_state->UpdateGameList(game_list->GetModel()); });
connect(this, &GMainWindow::EmulationStarting, render_window, connect(this, &GMainWindow::EmulationStarting, render_window,
@ -768,7 +768,7 @@ void GMainWindow::ConnectMenuEvents() {
connect(ui->action_Close_Movie, &QAction::triggered, this, &GMainWindow::OnCloseMovie); connect(ui->action_Close_Movie, &QAction::triggered, this, &GMainWindow::OnCloseMovie);
connect(ui->action_Save_Movie, &QAction::triggered, this, &GMainWindow::OnSaveMovie); connect(ui->action_Save_Movie, &QAction::triggered, this, &GMainWindow::OnSaveMovie);
connect(ui->action_Movie_Read_Only_Mode, &QAction::toggled, this, connect(ui->action_Movie_Read_Only_Mode, &QAction::toggled, this,
[this](bool checked) { Core::Movie::GetInstance().SetReadOnly(checked); }); [](bool checked) { Core::Movie::GetInstance().SetReadOnly(checked); });
connect(ui->action_Enable_Frame_Advancing, &QAction::triggered, this, [this] { connect(ui->action_Enable_Frame_Advancing, &QAction::triggered, this, [this] {
if (emulation_running) { if (emulation_running) {
Core::System::GetInstance().frame_limiter.SetFrameAdvancing( Core::System::GetInstance().frame_limiter.SetFrameAdvancing(
@ -1413,7 +1413,7 @@ void GMainWindow::OnGameListDumpRomFS(QString game_path, u64 program_id) {
program_id | 0x0004000e00000000); program_id | 0x0004000e00000000);
using FutureWatcher = QFutureWatcher<std::pair<Loader::ResultStatus, Loader::ResultStatus>>; using FutureWatcher = QFutureWatcher<std::pair<Loader::ResultStatus, Loader::ResultStatus>>;
auto* future_watcher = new FutureWatcher(this); auto* future_watcher = new FutureWatcher(this);
connect(future_watcher, &FutureWatcher::finished, connect(future_watcher, &FutureWatcher::finished, this,
[this, dialog, base_path, update_path, future_watcher] { [this, dialog, base_path, update_path, future_watcher] {
dialog->hide(); dialog->hide();
const auto& [base, update] = future_watcher->result(); const auto& [base, update] = future_watcher->result();
@ -1515,7 +1515,7 @@ void GMainWindow::InstallCIA(QStringList filepaths) {
const auto cia_progress = [&](std::size_t written, std::size_t total) { const auto cia_progress = [&](std::size_t written, std::size_t total) {
emit UpdateProgress(written, total); emit UpdateProgress(written, total);
}; };
for (const auto current_path : filepaths) { for (const auto& current_path : filepaths) {
status = Service::AM::InstallCIA(current_path.toStdString(), cia_progress); status = Service::AM::InstallCIA(current_path.toStdString(), cia_progress);
emit CIAInstallReport(status, current_path); emit CIAInstallReport(status, current_path);
} }
@ -1553,6 +1553,10 @@ void GMainWindow::OnCIAInstallReport(Service::AM::InstallStatus status, QString
"before being used with Citra. A real 3DS is required.") "before being used with Citra. A real 3DS is required.")
.arg(filename)); .arg(filename));
break; break;
case Service::AM::InstallStatus::ErrorFileNotFound:
QMessageBox::critical(this, tr("Unable to find File"),
tr("Could not find %1").arg(filename));
break;
} }
} }
@ -1730,6 +1734,8 @@ void GMainWindow::ToggleScreenLayout() {
case Settings::LayoutOption::SideScreen: case Settings::LayoutOption::SideScreen:
new_layout = Settings::LayoutOption::Default; new_layout = Settings::LayoutOption::Default;
break; break;
default:
LOG_ERROR(Frontend, "Unknown layout option {}", Settings::values.layout_option);
} }
Settings::values.layout_option = new_layout; Settings::values.layout_option = new_layout;
@ -1976,7 +1982,7 @@ void GMainWindow::OnCaptureScreenshot() {
const QString filename = game_title.remove(QRegularExpression(QStringLiteral("[\\/:?\"<>|]"))); const QString filename = game_title.remove(QRegularExpression(QStringLiteral("[\\/:?\"<>|]")));
const QString timestamp = const QString timestamp =
QDateTime::currentDateTime().toString(QStringLiteral("dd.MM.yy_hh.mm.ss.z")); QDateTime::currentDateTime().toString(QStringLiteral("dd.MM.yy_hh.mm.ss.z"));
path.append(QStringLiteral("/%1_%2.png").arg(filename).arg(timestamp)); path.append(QStringLiteral("/%1_%2.png").arg(filename, timestamp));
render_window->CaptureScreenshot(UISettings::values.screenshot_resolution_factor, path); render_window->CaptureScreenshot(UISettings::values.screenshot_resolution_factor, path);
OnStartGame(); OnStartGame();
} }
@ -2051,7 +2057,7 @@ void GMainWindow::UpdateStatusBar() {
message_label_used_for_movie = true; message_label_used_for_movie = true;
ui->action_Save_Movie->setEnabled(true); ui->action_Save_Movie->setEnabled(true);
} else if (play_mode == Core::Movie::PlayMode::Playing) { } else if (play_mode == Core::Movie::PlayMode::Playing) {
message_label->setText(tr("Playing %1 / %2").arg(current).arg(total)); message_label->setText(tr("Playing %1 / %2").arg(current, total));
message_label->setVisible(true); message_label->setVisible(true);
message_label_used_for_movie = true; message_label_used_for_movie = true;
ui->action_Save_Movie->setEnabled(false); ui->action_Save_Movie->setEnabled(false);

View File

@ -5,6 +5,7 @@
#pragma once #pragma once
#include <memory> #include <memory>
#include <unordered_map>
#include <unordered_set> #include <unordered_set>
#include <QDialog> #include <QDialog>
#include <QSortFilterProxyModel> #include <QSortFilterProxyModel>

View File

@ -7,7 +7,6 @@
#include <QIcon> #include <QIcon>
#include <QMessageBox> #include <QMessageBox>
#include <QStandardItemModel> #include <QStandardItemModel>
#include "citra_qt/game_list.h"
#include "citra_qt/multiplayer/client_room.h" #include "citra_qt/multiplayer/client_room.h"
#include "citra_qt/multiplayer/direct_connect.h" #include "citra_qt/multiplayer/direct_connect.h"
#include "citra_qt/multiplayer/host_room.h" #include "citra_qt/multiplayer/host_room.h"
@ -16,7 +15,6 @@
#include "citra_qt/multiplayer/state.h" #include "citra_qt/multiplayer/state.h"
#include "citra_qt/uisettings.h" #include "citra_qt/uisettings.h"
#include "citra_qt/util/clickable_label.h" #include "citra_qt/util/clickable_label.h"
#include "common/announce_multiplayer_room.h"
#include "common/logging/log.h" #include "common/logging/log.h"
MultiplayerState::MultiplayerState(QWidget* parent, QStandardItemModel* game_list_model, MultiplayerState::MultiplayerState(QWidget* parent, QStandardItemModel* game_list_model,
@ -231,8 +229,9 @@ bool MultiplayerState::OnCloseRoom() {
if (room->GetState() != Network::Room::State::Open) { if (room->GetState() != Network::Room::State::Open) {
return true; return true;
} }
// Save ban list // Save ban list
UISettings::values.ban_list = std::move(room->GetBanList()); UISettings::values.ban_list = room->GetBanList();
room->Destroy(); room->Destroy();
announce_multiplayer_session->Stop(); announce_multiplayer_session->Stop();

View File

@ -78,6 +78,7 @@ add_library(common STATIC
logging/backend.h logging/backend.h
logging/filter.cpp logging/filter.cpp
logging/filter.h logging/filter.h
logging/formatter.h
logging/log.h logging/log.h
logging/text_formatter.cpp logging/text_formatter.cpp
logging/text_formatter.h logging/text_formatter.h

View File

@ -31,8 +31,10 @@
#endif #endif
// 64 bit offsets for MSVC and MinGW. MinGW also needs this for using _wstat64 // 64 bit offsets for MSVC and MinGW. MinGW also needs this for using _wstat64
#ifndef __MINGW64__
#define stat _stat64 #define stat _stat64
#define fstat _fstat64 #define fstat _fstat64
#endif
#else #else
#ifdef __APPLE__ #ifdef __APPLE__

View File

@ -65,12 +65,16 @@ private:
BOOST_CLASS_EXPORT_KEY(BufferMem); BOOST_CLASS_EXPORT_KEY(BufferMem);
/// A managed reference to host-side memory. Fast enough to be used everywhere instead of u8* /**
/// Supports serialization. * A managed reference to host-side memory.
* Fast enough to be used everywhere instead of u8*
* Supports serialization.
*/
class MemoryRef { class MemoryRef {
public: public:
MemoryRef() = default; MemoryRef() = default;
MemoryRef(std::nullptr_t) {} MemoryRef(std::nullptr_t) {}
MemoryRef(std::shared_ptr<BackingMem> backing_mem_) MemoryRef(std::shared_ptr<BackingMem> backing_mem_)
: backing_mem(std::move(backing_mem_)), offset(0) { : backing_mem(std::move(backing_mem_)), offset(0) {
Init(); Init();
@ -80,30 +84,38 @@ public:
ASSERT(offset <= backing_mem->GetSize()); ASSERT(offset <= backing_mem->GetSize());
Init(); Init();
} }
explicit operator bool() const { explicit operator bool() const {
return cptr != nullptr; return cptr != nullptr;
} }
operator u8*() { operator u8*() {
return cptr; return cptr;
} }
u8* GetPtr() { u8* GetPtr() {
return cptr; return cptr;
} }
operator const u8*() const { operator const u8*() const {
return cptr; return cptr;
} }
const u8* GetPtr() const { const u8* GetPtr() const {
return cptr; return cptr;
} }
std::size_t GetSize() const { std::size_t GetSize() const {
return csize; return csize;
} }
MemoryRef& operator+=(u32 offset_by) { MemoryRef& operator+=(u32 offset_by) {
ASSERT(offset_by < csize); ASSERT(offset_by < csize);
offset += offset_by; offset += offset_by;
Init(); Init();
return *this; return *this;
} }
MemoryRef operator+(u32 offset_by) const { MemoryRef operator+(u32 offset_by) const {
ASSERT(offset_by < csize); ASSERT(offset_by < csize);
return MemoryRef(backing_mem, offset + offset_by); return MemoryRef(backing_mem, offset + offset_by);

View File

@ -23,12 +23,3 @@ typedef void* HANDLE;
#include <microprofile.h> #include <microprofile.h>
#define MP_RGB(r, g, b) ((r) << 16 | (g) << 8 | (b) << 0) #define MP_RGB(r, g, b) ((r) << 16 | (g) << 8 | (b) << 0)
// On OS X, some Mach header included by MicroProfile defines these as macros, conflicting with
// identifiers we use.
#ifdef PAGE_SIZE
#undef PAGE_SIZE
#endif
#ifdef PAGE_MASK
#undef PAGE_MASK
#endif

View File

@ -228,6 +228,7 @@ u32 ARM_Dynarmic::GetVFPSystemReg(VFPSystemRegister reg) const {
default: default:
UNREACHABLE_MSG("Unknown VFP system register: {}", reg); UNREACHABLE_MSG("Unknown VFP system register: {}", reg);
} }
return UINT_MAX; return UINT_MAX;
} }
@ -261,6 +262,8 @@ u32 ARM_Dynarmic::GetCP15Register(CP15Register reg) const {
default: default:
UNREACHABLE_MSG("Unknown CP15 register: {}", reg); UNREACHABLE_MSG("Unknown CP15 register: {}", reg);
} }
return 0;
} }
void ARM_Dynarmic::SetCP15Register(CP15Register reg, u32 value) { void ARM_Dynarmic::SetCP15Register(CP15Register reg, u32 value) {

View File

@ -849,17 +849,13 @@ static int InterpreterTranslateBlock(ARMul_State* cpu, std::size_t& bb_start, u3
// Save start addr of basicblock in CreamCache // Save start addr of basicblock in CreamCache
ARM_INST_PTR inst_base = nullptr; ARM_INST_PTR inst_base = nullptr;
TransExtData ret = TransExtData::NON_BRANCH; TransExtData ret = TransExtData::NON_BRANCH;
int size = 0; // instruction size of basic block
bb_start = trans_cache_buf_top; bb_start = trans_cache_buf_top;
u32 phys_addr = addr; u32 phys_addr = addr;
u32 pc_start = cpu->Reg[15]; u32 pc_start = cpu->Reg[15];
while (ret == TransExtData::NON_BRANCH) { while (ret == TransExtData::NON_BRANCH) {
unsigned int inst_size = InterpreterTranslateInstruction(cpu, phys_addr, inst_base); u32 inst_size = InterpreterTranslateInstruction(cpu, phys_addr, inst_base);
size++;
phys_addr += inst_size; phys_addr += inst_size;
if ((phys_addr & 0xfff) == 0) { if ((phys_addr & 0xfff) == 0) {
@ -972,7 +968,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
// GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback to a // GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback to a
// clunky switch statement. // clunky switch statement.
#if defined __GNUC__ || defined __clang__ #if defined __GNUC__ || (defined __clang__ && !defined _MSC_VER)
#define GOTO_NEXT_INST \ #define GOTO_NEXT_INST \
GDB_BP_CHECK; \ GDB_BP_CHECK; \
if (num_instrs >= cpu->NumInstrsToExecute) \ if (num_instrs >= cpu->NumInstrsToExecute) \

View File

@ -1218,7 +1218,7 @@ u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr) {
for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) { for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) {
u32 except; u32 except;
char type; [[maybe_unused]] char type;
type = (fop->flags & OP_SD) ? 's' : 'd'; type = (fop->flags & OP_SD) ? 's' : 'd';
if (op == FOP_EXT) if (op == FOP_EXT)

View File

@ -1242,7 +1242,7 @@ u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr) {
for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) { for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) {
s32 m = vfp_get_float(state, sm); s32 m = vfp_get_float(state, sm);
u32 except; u32 except;
char type; [[maybe_unused]] char type;
type = (fop->flags & OP_DD) ? 'd' : 's'; type = (fop->flags & OP_DD) ? 'd' : 's';
if (op == FOP_EXT) if (op == FOP_EXT)

View File

@ -47,7 +47,7 @@ void CheatEngine::AddCheat(const std::shared_ptr<CheatBase>& cheat) {
void CheatEngine::RemoveCheat(int index) { void CheatEngine::RemoveCheat(int index) {
std::unique_lock<std::shared_mutex> lock(cheats_list_mutex); std::unique_lock<std::shared_mutex> lock(cheats_list_mutex);
if (index < 0 || index >= cheats_list.size()) { if (index < 0 || index >= static_cast<int>(cheats_list.size())) {
LOG_ERROR(Core_Cheats, "Invalid index {}", index); LOG_ERROR(Core_Cheats, "Invalid index {}", index);
return; return;
} }
@ -56,7 +56,7 @@ void CheatEngine::RemoveCheat(int index) {
void CheatEngine::UpdateCheat(int index, const std::shared_ptr<CheatBase>& new_cheat) { void CheatEngine::UpdateCheat(int index, const std::shared_ptr<CheatBase>& new_cheat) {
std::unique_lock<std::shared_mutex> lock(cheats_list_mutex); std::unique_lock<std::shared_mutex> lock(cheats_list_mutex);
if (index < 0 || index >= cheats_list.size()) { if (index < 0 || index >= static_cast<int>(cheats_list.size())) {
LOG_ERROR(Core_Cheats, "Invalid index {}", index); LOG_ERROR(Core_Cheats, "Invalid index {}", index);
return; return;
} }

View File

@ -301,10 +301,6 @@ private:
std::vector<std::shared_ptr<Timer>> timers; std::vector<std::shared_ptr<Timer>> timers;
Timer* current_timer = nullptr; Timer* current_timer = nullptr;
// Stores a scaling for the internal clockspeed. Changing this number results in
// under/overclocking the guest cpu
double cpu_clock_scale = 1.0;
// When true, the event queue can't be modified. Used while deserializing to workaround // When true, the event queue can't be modified. Used while deserializing to workaround
// destructor side effects. // destructor side effects.
bool event_queue_locked = false; bool event_queue_locked = false;

View File

@ -849,14 +849,14 @@ static void ReadMemory() {
SendReply("E01"); SendReply("E01");
} }
if (!Memory::IsValidVirtualAddress(*Core::System::GetInstance().Kernel().GetCurrentProcess(), auto& memory = Core::System::GetInstance().Memory();
addr)) { if (!memory.IsValidVirtualAddress(*Core::System::GetInstance().Kernel().GetCurrentProcess(),
addr)) {
return SendReply("E00"); return SendReply("E00");
} }
std::vector<u8> data(len); std::vector<u8> data(len);
Core::System::GetInstance().Memory().ReadBlock( memory.ReadBlock(addr, data.data(), len);
*Core::System::GetInstance().Kernel().GetCurrentProcess(), addr, data.data(), len);
MemToGdbHex(reply, data.data(), len); MemToGdbHex(reply, data.data(), len);
reply[len * 2] = '\0'; reply[len * 2] = '\0';
@ -873,16 +873,16 @@ static void WriteMemory() {
auto len_pos = std::find(start_offset, command_buffer + command_length, ':'); auto len_pos = std::find(start_offset, command_buffer + command_length, ':');
u32 len = HexToInt(start_offset, static_cast<u32>(len_pos - start_offset)); u32 len = HexToInt(start_offset, static_cast<u32>(len_pos - start_offset));
if (!Memory::IsValidVirtualAddress(*Core::System::GetInstance().Kernel().GetCurrentProcess(), auto& memory = Core::System::GetInstance().Memory();
addr)) { if (!memory.IsValidVirtualAddress(*Core::System::GetInstance().Kernel().GetCurrentProcess(),
addr)) {
return SendReply("E00"); return SendReply("E00");
} }
std::vector<u8> data(len); std::vector<u8> data(len);
GdbHexToMem(data.data(), len_pos + 1, len); GdbHexToMem(data.data(), len_pos + 1, len);
Core::System::GetInstance().Memory().WriteBlock( memory.WriteBlock(addr, data.data(), len);
*Core::System::GetInstance().Kernel().GetCurrentProcess(), addr, data.data(), len);
Core::GetRunningCore().ClearInstructionCache(); Core::GetRunningCore().ClearInstructionCache();
SendReply("OK"); SendReply("OK");
} }

View File

@ -80,7 +80,7 @@ private:
std::shared_ptr<Callback> timeout_callback; std::shared_ptr<Callback> timeout_callback;
void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread, void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
std::shared_ptr<WaitObject> object); std::shared_ptr<WaitObject> object) override;
class DummyCallback : public WakeupCallback { class DummyCallback : public WakeupCallback {
public: public:

View File

@ -138,10 +138,10 @@ ResultCode TranslateCommandBuffer(Kernel::KernelSystem& kernel, Memory::MemorySy
u32 size = static_cast<u32>(descInfo.size); u32 size = static_cast<u32>(descInfo.size);
IPC::MappedBufferPermissions permissions = descInfo.perms; IPC::MappedBufferPermissions permissions = descInfo.perms;
VAddr page_start = Common::AlignDown(source_address, Memory::PAGE_SIZE); VAddr page_start = Common::AlignDown(source_address, Memory::CITRA_PAGE_SIZE);
u32 page_offset = source_address - page_start; u32 page_offset = source_address - page_start;
u32 num_pages = u32 num_pages = Common::AlignUp(page_offset + size, Memory::CITRA_PAGE_SIZE) >>
Common::AlignUp(page_offset + size, Memory::PAGE_SIZE) >> Memory::PAGE_BITS; Memory::CITRA_PAGE_BITS;
// Skip when the size is zero and num_pages == 0 // Skip when the size is zero and num_pages == 0
if (size == 0) { if (size == 0) {
@ -171,8 +171,8 @@ ResultCode TranslateCommandBuffer(Kernel::KernelSystem& kernel, Memory::MemorySy
found->target_address, size); found->target_address, size);
} }
VAddr prev_reserve = page_start - Memory::PAGE_SIZE; VAddr prev_reserve = page_start - Memory::CITRA_PAGE_SIZE;
VAddr next_reserve = page_start + num_pages * Memory::PAGE_SIZE; VAddr next_reserve = page_start + num_pages * Memory::CITRA_PAGE_SIZE;
auto& prev_vma = src_process->vm_manager.FindVMA(prev_reserve)->second; auto& prev_vma = src_process->vm_manager.FindVMA(prev_reserve)->second;
auto& next_vma = src_process->vm_manager.FindVMA(next_reserve)->second; auto& next_vma = src_process->vm_manager.FindVMA(next_reserve)->second;
@ -180,8 +180,9 @@ ResultCode TranslateCommandBuffer(Kernel::KernelSystem& kernel, Memory::MemorySy
next_vma.meminfo_state == MemoryState::Reserved); next_vma.meminfo_state == MemoryState::Reserved);
// Unmap the buffer and guard pages from the source process // Unmap the buffer and guard pages from the source process
ResultCode result = src_process->vm_manager.UnmapRange( ResultCode result =
page_start - Memory::PAGE_SIZE, (num_pages + 2) * Memory::PAGE_SIZE); src_process->vm_manager.UnmapRange(page_start - Memory::CITRA_PAGE_SIZE,
(num_pages + 2) * Memory::CITRA_PAGE_SIZE);
ASSERT(result == RESULT_SUCCESS); ASSERT(result == RESULT_SUCCESS);
mapped_buffer_context.erase(found); mapped_buffer_context.erase(found);
@ -196,13 +197,13 @@ ResultCode TranslateCommandBuffer(Kernel::KernelSystem& kernel, Memory::MemorySy
// Reserve a page of memory before the mapped buffer // Reserve a page of memory before the mapped buffer
std::shared_ptr<BackingMem> reserve_buffer = std::shared_ptr<BackingMem> reserve_buffer =
std::make_shared<BufferMem>(Memory::PAGE_SIZE); std::make_shared<BufferMem>(Memory::CITRA_PAGE_SIZE);
dst_process->vm_manager.MapBackingMemoryToBase( dst_process->vm_manager.MapBackingMemoryToBase(
Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE, reserve_buffer, Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE, reserve_buffer,
Memory::PAGE_SIZE, Kernel::MemoryState::Reserved); Memory::CITRA_PAGE_SIZE, Kernel::MemoryState::Reserved);
std::shared_ptr<BackingMem> buffer = std::shared_ptr<BackingMem> buffer =
std::make_shared<BufferMem>(num_pages * Memory::PAGE_SIZE); std::make_shared<BufferMem>(num_pages * Memory::CITRA_PAGE_SIZE);
memory.ReadBlock(*src_process, source_address, buffer->GetPtr() + page_offset, size); memory.ReadBlock(*src_process, source_address, buffer->GetPtr() + page_offset, size);
// Map the page(s) into the target process' address space. // Map the page(s) into the target process' address space.

View File

@ -127,7 +127,7 @@ void Process::ParseKernelCaps(const u32* kernel_caps, std::size_t len) {
// Mapped memory page // Mapped memory page
AddressMapping mapping; AddressMapping mapping;
mapping.address = descriptor << 12; mapping.address = descriptor << 12;
mapping.size = Memory::PAGE_SIZE; mapping.size = Memory::CITRA_PAGE_SIZE;
mapping.read_only = false; mapping.read_only = false;
mapping.unk_flag = false; mapping.unk_flag = false;
@ -265,7 +265,7 @@ ResultCode Process::HeapFree(VAddr target, u32 size) {
// Free heaps block by block // Free heaps block by block
CASCADE_RESULT(auto backing_blocks, vm_manager.GetBackingBlocksForRange(target, size)); CASCADE_RESULT(auto backing_blocks, vm_manager.GetBackingBlocksForRange(target, size));
for (const auto [backing_memory, block_size] : backing_blocks) { for (const auto& [backing_memory, block_size] : backing_blocks) {
memory_region->Free(kernel.memory.GetFCRAMOffset(backing_memory.GetPtr()), block_size); memory_region->Free(kernel.memory.GetFCRAMOffset(backing_memory.GetPtr()), block_size);
} }
@ -396,7 +396,7 @@ ResultCode Process::Map(VAddr target, VAddr source, u32 size, VMAPermission perm
CASCADE_RESULT(auto backing_blocks, vm_manager.GetBackingBlocksForRange(source, size)); CASCADE_RESULT(auto backing_blocks, vm_manager.GetBackingBlocksForRange(source, size));
VAddr interval_target = target; VAddr interval_target = target;
for (const auto [backing_memory, block_size] : backing_blocks) { for (const auto& [backing_memory, block_size] : backing_blocks) {
auto target_vma = auto target_vma =
vm_manager.MapBackingMemory(interval_target, backing_memory, block_size, target_state); vm_manager.MapBackingMemory(interval_target, backing_memory, block_size, target_state);
ASSERT(target_vma.Succeeded()); ASSERT(target_vma.Succeeded());

View File

@ -10,7 +10,6 @@
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/microprofile.h" #include "common/microprofile.h"
#include "common/scm_rev.h" #include "common/scm_rev.h"
#include "common/scope_exit.h"
#include "core/arm/arm_interface.h" #include "core/arm/arm_interface.h"
#include "core/core.h" #include "core/core.h"
#include "core/core_timing.h" #include "core/core_timing.h"
@ -39,7 +38,6 @@
#include "core/hle/kernel/wait_object.h" #include "core/hle/kernel/wait_object.h"
#include "core/hle/lock.h" #include "core/hle/lock.h"
#include "core/hle/result.h" #include "core/hle/result.h"
#include "core/hle/service/service.h"
namespace Kernel { namespace Kernel {
@ -219,10 +217,10 @@ ResultCode SVC::ControlMemory(u32* out_addr, u32 addr0, u32 addr1, u32 size, u32
"size=0x{:X}, permissions=0x{:08X}", "size=0x{:X}, permissions=0x{:08X}",
operation, addr0, addr1, size, permissions); operation, addr0, addr1, size, permissions);
if ((addr0 & Memory::PAGE_MASK) != 0 || (addr1 & Memory::PAGE_MASK) != 0) { if ((addr0 & Memory::CITRA_PAGE_MASK) != 0 || (addr1 & Memory::CITRA_PAGE_MASK) != 0) {
return ERR_MISALIGNED_ADDRESS; return ERR_MISALIGNED_ADDRESS;
} }
if ((size & Memory::PAGE_MASK) != 0) { if ((size & Memory::CITRA_PAGE_MASK) != 0) {
return ERR_MISALIGNED_SIZE; return ERR_MISALIGNED_SIZE;
} }
@ -374,7 +372,7 @@ ResultCode SVC::UnmapMemoryBlock(Handle handle, u32 addr) {
/// Connect to an OS service given the port name, returns the handle to the port to out /// Connect to an OS service given the port name, returns the handle to the port to out
ResultCode SVC::ConnectToPort(Handle* out_handle, VAddr port_name_address) { ResultCode SVC::ConnectToPort(Handle* out_handle, VAddr port_name_address) {
if (!Memory::IsValidVirtualAddress(*kernel.GetCurrentProcess(), port_name_address)) if (!memory.IsValidVirtualAddress(*kernel.GetCurrentProcess(), port_name_address))
return ERR_NOT_FOUND; return ERR_NOT_FOUND;
static constexpr std::size_t PortNameMaxLength = 11; static constexpr std::size_t PortNameMaxLength = 11;
@ -541,7 +539,7 @@ ResultCode SVC::WaitSynchronizationN(s32* out, VAddr handles_address, s32 handle
bool wait_all, s64 nano_seconds) { bool wait_all, s64 nano_seconds) {
Thread* thread = kernel.GetCurrentThreadManager().GetCurrentThread(); Thread* thread = kernel.GetCurrentThreadManager().GetCurrentThread();
if (!Memory::IsValidVirtualAddress(*kernel.GetCurrentProcess(), handles_address)) if (!memory.IsValidVirtualAddress(*kernel.GetCurrentProcess(), handles_address))
return ERR_INVALID_POINTER; return ERR_INVALID_POINTER;
// NOTE: on real hardware, there is no nullptr check for 'out' (tested with firmware 4.4). If // NOTE: on real hardware, there is no nullptr check for 'out' (tested with firmware 4.4). If
@ -687,7 +685,7 @@ static ResultCode ReceiveIPCRequest(Kernel::KernelSystem& kernel, Memory::Memory
/// In a single operation, sends a IPC reply and waits for a new request. /// In a single operation, sends a IPC reply and waits for a new request.
ResultCode SVC::ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_count, ResultCode SVC::ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_count,
Handle reply_target) { Handle reply_target) {
if (!Memory::IsValidVirtualAddress(*kernel.GetCurrentProcess(), handles_address)) if (!memory.IsValidVirtualAddress(*kernel.GetCurrentProcess(), handles_address))
return ERR_INVALID_POINTER; return ERR_INVALID_POINTER;
// Check if 'handle_count' is invalid // Check if 'handle_count' is invalid
@ -1288,7 +1286,7 @@ s64 SVC::GetSystemTick() {
/// Creates a memory block at the specified address with the specified permissions and size /// Creates a memory block at the specified address with the specified permissions and size
ResultCode SVC::CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 my_permission, ResultCode SVC::CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 my_permission,
u32 other_permission) { u32 other_permission) {
if (size % Memory::PAGE_SIZE != 0) if (size % Memory::CITRA_PAGE_SIZE != 0)
return ERR_MISALIGNED_SIZE; return ERR_MISALIGNED_SIZE;
std::shared_ptr<SharedMemory> shared_memory = nullptr; std::shared_ptr<SharedMemory> shared_memory = nullptr;
@ -1393,7 +1391,7 @@ ResultCode SVC::AcceptSession(Handle* out_server_session, Handle server_port_han
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
static void CopyStringPart(char* out, const char* in, int offset, int max_length) { static void CopyStringPart(char* out, const char* in, size_t offset, size_t max_length) {
size_t str_size = strlen(in); size_t str_size = strlen(in);
if (offset < str_size) { if (offset < str_size) {
strncpy(out, in + offset, max_length - 1); strncpy(out, in + offset, max_length - 1);
@ -1509,7 +1507,7 @@ ResultCode SVC::GetProcessInfo(s64* out, Handle process_handle, u32 type) {
// TODO(yuriks): Type 0 returns a slightly higher number than type 2, but I'm not sure // TODO(yuriks): Type 0 returns a slightly higher number than type 2, but I'm not sure
// what's the difference between them. // what's the difference between them.
*out = process->memory_used; *out = process->memory_used;
if (*out % Memory::PAGE_SIZE != 0) { if (*out % Memory::CITRA_PAGE_SIZE != 0) {
LOG_ERROR(Kernel_SVC, "called, memory size not page-aligned"); LOG_ERROR(Kernel_SVC, "called, memory size not page-aligned");
return ERR_MISALIGNED_SIZE; return ERR_MISALIGNED_SIZE;
} }

View File

@ -105,9 +105,9 @@ void Thread::Stop() {
ReleaseThreadMutexes(this); ReleaseThreadMutexes(this);
// Mark the TLS slot in the thread's page as free. // Mark the TLS slot in the thread's page as free.
u32 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE; u32 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::CITRA_PAGE_SIZE;
u32 tls_slot = u32 tls_slot =
((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE; ((tls_address - Memory::TLS_AREA_VADDR) % Memory::CITRA_PAGE_SIZE) / Memory::TLS_ENTRY_SIZE;
ASSERT(owner_process.lock()); ASSERT(owner_process.lock());
owner_process.lock()->tls_slots[tls_page].reset(tls_slot); owner_process.lock()->tls_slots[tls_page].reset(tls_slot);
} }
@ -337,8 +337,7 @@ ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(
} }
// TODO(yuriks): Other checks, returning 0xD9001BEA // TODO(yuriks): Other checks, returning 0xD9001BEA
if (!memory.IsValidVirtualAddress(*owner_process, entry_point)) {
if (!Memory::IsValidVirtualAddress(*owner_process, entry_point)) {
LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:08x}", name, entry_point); LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:08x}", name, entry_point);
// TODO: Verify error // TODO: Verify error
return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
@ -374,13 +373,13 @@ ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(
auto memory_region = GetMemoryRegion(MemoryRegion::BASE); auto memory_region = GetMemoryRegion(MemoryRegion::BASE);
// Allocate some memory from the end of the linear heap for this region. // Allocate some memory from the end of the linear heap for this region.
auto offset = memory_region->LinearAllocate(Memory::PAGE_SIZE); auto offset = memory_region->LinearAllocate(Memory::CITRA_PAGE_SIZE);
if (!offset) { if (!offset) {
LOG_ERROR(Kernel_SVC, LOG_ERROR(Kernel_SVC,
"Not enough space in region to allocate a new TLS page for thread"); "Not enough space in region to allocate a new TLS page for thread");
return ERR_OUT_OF_MEMORY; return ERR_OUT_OF_MEMORY;
} }
owner_process->memory_used += Memory::PAGE_SIZE; owner_process->memory_used += Memory::CITRA_PAGE_SIZE;
tls_slots.emplace_back(0); // The page is completely available at the start tls_slots.emplace_back(0); // The page is completely available at the start
available_page = tls_slots.size() - 1; available_page = tls_slots.size() - 1;
@ -390,14 +389,14 @@ ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(
// Map the page to the current process' address space. // Map the page to the current process' address space.
vm_manager.MapBackingMemory( vm_manager.MapBackingMemory(
Memory::TLS_AREA_VADDR + static_cast<VAddr>(available_page) * Memory::PAGE_SIZE, Memory::TLS_AREA_VADDR + static_cast<VAddr>(available_page) * Memory::CITRA_PAGE_SIZE,
memory.GetFCRAMRef(*offset), Memory::PAGE_SIZE, MemoryState::Locked); memory.GetFCRAMRef(*offset), Memory::CITRA_PAGE_SIZE, MemoryState::Locked);
} }
// Mark the slot as used // Mark the slot as used
tls_slots[available_page].set(available_slot); tls_slots[available_page].set(available_slot);
thread->tls_address = Memory::TLS_AREA_VADDR + thread->tls_address = Memory::TLS_AREA_VADDR +
static_cast<VAddr>(available_page) * Memory::PAGE_SIZE + static_cast<VAddr>(available_page) * Memory::CITRA_PAGE_SIZE +
static_cast<VAddr>(available_slot) * Memory::TLS_ENTRY_SIZE; static_cast<VAddr>(available_slot) * Memory::TLS_ENTRY_SIZE;
memory.ZeroBlock(*owner_process, thread->tls_address, Memory::TLS_ENTRY_SIZE); memory.ZeroBlock(*owner_process, thread->tls_address, Memory::TLS_ENTRY_SIZE);

View File

@ -260,8 +260,8 @@ VMManager::VMAIter VMManager::StripIterConstness(const VMAHandle& iter) {
} }
ResultVal<VMManager::VMAIter> VMManager::CarveVMA(VAddr base, u32 size) { ResultVal<VMManager::VMAIter> VMManager::CarveVMA(VAddr base, u32 size) {
ASSERT_MSG((size & Memory::PAGE_MASK) == 0, "non-page aligned size: {:#10X}", size); ASSERT_MSG((size & Memory::CITRA_PAGE_MASK) == 0, "non-page aligned size: {:#10X}", size);
ASSERT_MSG((base & Memory::PAGE_MASK) == 0, "non-page aligned base: {:#010X}", base); ASSERT_MSG((base & Memory::CITRA_PAGE_MASK) == 0, "non-page aligned base: {:#010X}", base);
VMAIter vma_handle = StripIterConstness(FindVMA(base)); VMAIter vma_handle = StripIterConstness(FindVMA(base));
if (vma_handle == vma_map.end()) { if (vma_handle == vma_map.end()) {
@ -296,8 +296,8 @@ ResultVal<VMManager::VMAIter> VMManager::CarveVMA(VAddr base, u32 size) {
} }
ResultVal<VMManager::VMAIter> VMManager::CarveVMARange(VAddr target, u32 size) { ResultVal<VMManager::VMAIter> VMManager::CarveVMARange(VAddr target, u32 size) {
ASSERT_MSG((size & Memory::PAGE_MASK) == 0, "non-page aligned size: {:#10X}", size); ASSERT_MSG((size & Memory::CITRA_PAGE_MASK) == 0, "non-page aligned size: {:#10X}", size);
ASSERT_MSG((target & Memory::PAGE_MASK) == 0, "non-page aligned base: {:#010X}", target); ASSERT_MSG((target & Memory::CITRA_PAGE_MASK) == 0, "non-page aligned base: {:#010X}", target);
const VAddr target_end = target + size; const VAddr target_end = target + size;
ASSERT(target_end >= target); ASSERT(target_end >= target);

View File

@ -17,12 +17,9 @@
#include "core/file_sys/errors.h" #include "core/file_sys/errors.h"
#include "core/file_sys/ncch_container.h" #include "core/file_sys/ncch_container.h"
#include "core/file_sys/title_metadata.h" #include "core/file_sys/title_metadata.h"
#include "core/hle/ipc.h"
#include "core/hle/ipc_helpers.h" #include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h" #include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/errors.h" #include "core/hle/kernel/errors.h"
#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/server_session.h" #include "core/hle/kernel/server_session.h"
#include "core/hle/kernel/session.h" #include "core/hle/kernel/session.h"
#include "core/hle/service/am/am.h" #include "core/hle/service/am/am.h"
@ -610,7 +607,6 @@ void Module::Interface::FindDLCContentInfos(Kernel::HLERequestContext& ctx) {
std::string tmd_path = GetTitleMetadataPath(media_type, title_id); std::string tmd_path = GetTitleMetadataPath(media_type, title_id);
u32 content_read = 0;
FileSys::TitleMetadata tmd; FileSys::TitleMetadata tmd;
if (tmd.Load(tmd_path) == Loader::ResultStatus::Success) { if (tmd.Load(tmd_path) == Loader::ResultStatus::Success) {
std::size_t write_offset = 0; std::size_t write_offset = 0;
@ -642,7 +638,6 @@ void Module::Interface::FindDLCContentInfos(Kernel::HLERequestContext& ctx) {
content_info_out.Write(&content_info, write_offset, sizeof(ContentInfo)); content_info_out.Write(&content_info, write_offset, sizeof(ContentInfo));
write_offset += sizeof(ContentInfo); write_offset += sizeof(ContentInfo);
content_read++;
} }
} }

View File

@ -2,7 +2,6 @@
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include "common/common_paths.h"
#include "core/core.h" #include "core/core.h"
#include "core/hle/applets/applet.h" #include "core/hle/applets/applet.h"
#include "core/hle/service/apt/applet_manager.h" #include "core/hle/service/apt/applet_manager.h"
@ -27,47 +26,66 @@ struct AppletTitleData {
static constexpr std::size_t NumApplets = 29; static constexpr std::size_t NumApplets = 29;
static constexpr std::array<AppletTitleData, NumApplets> applet_titleids = {{ static constexpr std::array<AppletTitleData, NumApplets> applet_titleids = {{
{AppletId::HomeMenu, AppletId::None, 0x4003000008202, 0x4003000008F02, 0x4003000009802, {{AppletId::HomeMenu, AppletId::None},
0x4003000008202, 0x400300000A102, 0x400300000A902, 0x400300000B102}, {0x4003000008202, 0x4003000008F02, 0x4003000009802, 0x4003000008202, 0x400300000A102,
{AppletId::AlternateMenu, AppletId::None, 0x4003000008102, 0x4003000008102, 0x4003000008102, 0x400300000A902, 0x400300000B102}},
0x4003000008102, 0x4003000008102, 0x4003000008102, 0x4003000008102}, {{AppletId::AlternateMenu, AppletId::None},
{AppletId::Camera, AppletId::None, 0x4003000008402, 0x4003000009002, 0x4003000009902, {0x4003000008102, 0x4003000008102, 0x4003000008102, 0x4003000008102, 0x4003000008102,
0x4003000008402, 0x400300000A202, 0x400300000AA02, 0x400300000B202}, 0x4003000008102, 0x4003000008102}},
{AppletId::FriendList, AppletId::None, 0x4003000008D02, 0x4003000009602, 0x4003000009F02, {{AppletId::Camera, AppletId::None},
0x4003000008D02, 0x400300000A702, 0x400300000AF02, 0x400300000B702}, {0x4003000008402, 0x4003000009002, 0x4003000009902, 0x4003000008402, 0x400300000A202,
{AppletId::GameNotes, AppletId::None, 0x4003000008702, 0x4003000009302, 0x4003000009C02, 0x400300000AA02, 0x400300000B202}},
0x4003000008702, 0x400300000A502, 0x400300000AD02, 0x400300000B502}, {{AppletId::FriendList, AppletId::None},
{AppletId::InternetBrowser, AppletId::None, 0x4003000008802, 0x4003000009402, 0x4003000009D02, {0x4003000008D02, 0x4003000009602, 0x4003000009F02, 0x4003000008D02, 0x400300000A702,
0x4003000008802, 0x400300000A602, 0x400300000AE02, 0x400300000B602}, 0x400300000AF02, 0x400300000B702}},
{AppletId::InstructionManual, AppletId::None, 0x4003000008602, 0x4003000009202, 0x4003000009B02, {{AppletId::GameNotes, AppletId::None},
0x4003000008602, 0x400300000A402, 0x400300000AC02, 0x400300000B402}, {0x4003000008702, 0x4003000009302, 0x4003000009C02, 0x4003000008702, 0x400300000A502,
{AppletId::Notifications, AppletId::None, 0x4003000008E02, 0x4003000009702, 0x400300000A002, 0x400300000AD02, 0x400300000B502}},
0x4003000008E02, 0x400300000A802, 0x400300000B002, 0x400300000B802}, {{AppletId::InternetBrowser, AppletId::None},
{AppletId::Miiverse, AppletId::None, 0x400300000BC02, 0x400300000BD02, 0x400300000BE02, {0x4003000008802, 0x4003000009402, 0x4003000009D02, 0x4003000008802, 0x400300000A602,
0x400300000BC02, 0x4003000009E02, 0x4003000009502, 0x400300000B902}, 0x400300000AE02, 0x400300000B602}},
{{AppletId::InstructionManual, AppletId::None},
{0x4003000008602, 0x4003000009202, 0x4003000009B02, 0x4003000008602, 0x400300000A402,
0x400300000AC02, 0x400300000B402}},
{{AppletId::Notifications, AppletId::None},
{0x4003000008E02, 0x4003000009702, 0x400300000A002, 0x4003000008E02, 0x400300000A802,
0x400300000B002, 0x400300000B802}},
{{AppletId::Miiverse, AppletId::None},
{0x400300000BC02, 0x400300000BD02, 0x400300000BE02, 0x400300000BC02, 0x4003000009E02,
0x4003000009502, 0x400300000B902}},
// These values obtained from an older NS dump firmware 4.5 // These values obtained from an older NS dump firmware 4.5
{AppletId::MiiversePost, AppletId::None, 0x400300000BA02, 0x400300000BA02, 0x400300000BA02, {{AppletId::MiiversePost, AppletId::None},
0x400300000BA02, 0x400300000BA02, 0x400300000BA02, 0x400300000BA02}, {0x400300000BA02, 0x400300000BA02, 0x400300000BA02, 0x400300000BA02, 0x400300000BA02,
0x400300000BA02, 0x400300000BA02}},
// {AppletId::MiiversePost, AppletId::None, 0x4003000008302, 0x4003000008B02, 0x400300000BA02, // {AppletId::MiiversePost, AppletId::None, 0x4003000008302, 0x4003000008B02, 0x400300000BA02,
// 0x4003000008302, 0x0, 0x0, 0x0}, // 0x4003000008302, 0x0, 0x0, 0x0},
{AppletId::AmiiboSettings, AppletId::None, 0x4003000009502, 0x4003000009E02, 0x400300000B902, {{AppletId::AmiiboSettings, AppletId::None},
0x4003000009502, 0x0, 0x4003000008C02, 0x400300000BF02}, {0x4003000009502, 0x4003000009E02, 0x400300000B902, 0x4003000009502, 0x0, 0x4003000008C02,
{AppletId::SoftwareKeyboard1, AppletId::SoftwareKeyboard2, 0x400300000C002, 0x400300000C802, 0x400300000BF02}},
0x400300000D002, 0x400300000C002, 0x400300000D802, 0x400300000DE02, 0x400300000E402}, {{AppletId::SoftwareKeyboard1, AppletId::SoftwareKeyboard2},
{AppletId::Ed1, AppletId::Ed2, 0x400300000C102, 0x400300000C902, 0x400300000D102, {0x400300000C002, 0x400300000C802, 0x400300000D002, 0x400300000C002, 0x400300000D802,
0x400300000C102, 0x400300000D902, 0x400300000DF02, 0x400300000E502}, 0x400300000DE02, 0x400300000E402}},
{AppletId::PnoteApp, AppletId::PnoteApp2, 0x400300000C302, 0x400300000CB02, 0x400300000D302, {{AppletId::Ed1, AppletId::Ed2},
0x400300000C302, 0x400300000DB02, 0x400300000E102, 0x400300000E702}, {0x400300000C102, 0x400300000C902, 0x400300000D102, 0x400300000C102, 0x400300000D902,
{AppletId::SnoteApp, AppletId::SnoteApp2, 0x400300000C402, 0x400300000CC02, 0x400300000D402, 0x400300000DF02, 0x400300000E502}},
0x400300000C402, 0x400300000DC02, 0x400300000E202, 0x400300000E802}, {{AppletId::PnoteApp, AppletId::PnoteApp2},
{AppletId::Error, AppletId::Error2, 0x400300000C502, 0x400300000C502, 0x400300000C502, {0x400300000C302, 0x400300000CB02, 0x400300000D302, 0x400300000C302, 0x400300000DB02,
0x400300000C502, 0x400300000CF02, 0x400300000CF02, 0x400300000CF02}, 0x400300000E102, 0x400300000E702}},
{AppletId::Mint, AppletId::Mint2, 0x400300000C602, 0x400300000CE02, 0x400300000D602, {{AppletId::SnoteApp, AppletId::SnoteApp2},
0x400300000C602, 0x400300000DD02, 0x400300000E302, 0x400300000E902}, {0x400300000C402, 0x400300000CC02, 0x400300000D402, 0x400300000C402, 0x400300000DC02,
{AppletId::Extrapad, AppletId::Extrapad2, 0x400300000CD02, 0x400300000CD02, 0x400300000CD02, 0x400300000E202, 0x400300000E802}},
0x400300000CD02, 0x400300000D502, 0x400300000D502, 0x400300000D502}, {{AppletId::Error, AppletId::Error2},
{AppletId::Memolib, AppletId::Memolib2, 0x400300000F602, 0x400300000F602, 0x400300000F602, {0x400300000C502, 0x400300000C502, 0x400300000C502, 0x400300000C502, 0x400300000CF02,
0x400300000F602, 0x400300000F602, 0x400300000F602, 0x400300000F602}, 0x400300000CF02, 0x400300000CF02}},
{{AppletId::Mint, AppletId::Mint2},
{0x400300000C602, 0x400300000CE02, 0x400300000D602, 0x400300000C602, 0x400300000DD02,
0x400300000E302, 0x400300000E902}},
{{AppletId::Extrapad, AppletId::Extrapad2},
{0x400300000CD02, 0x400300000CD02, 0x400300000CD02, 0x400300000CD02, 0x400300000D502,
0x400300000D502, 0x400300000D502}},
{{AppletId::Memolib, AppletId::Memolib2},
{0x400300000F602, 0x400300000F602, 0x400300000F602, 0x400300000F602, 0x400300000F602,
0x400300000F602, 0x400300000F602}},
// TODO(Subv): Fill in the rest of the titleids // TODO(Subv): Fill in the rest of the titleids
}}; }};

View File

@ -10,7 +10,6 @@
#include <cryptopp/osrng.h> #include <cryptopp/osrng.h>
#include <cryptopp/sha.h> #include <cryptopp/sha.h>
#include "common/archives.h" #include "common/archives.h"
#include "common/common_paths.h"
#include "common/file_util.h" #include "common/file_util.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/string_util.h" #include "common/string_util.h"
@ -107,7 +106,7 @@ static_assert(sizeof(ConsoleCountryInfo) == 4, "ConsoleCountryInfo must be exact
constexpr EULAVersion MAX_EULA_VERSION{0x7F, 0x7F}; constexpr EULAVersion MAX_EULA_VERSION{0x7F, 0x7F};
constexpr ConsoleModelInfo CONSOLE_MODEL_OLD{NINTENDO_3DS_XL, {0, 0, 0}}; constexpr ConsoleModelInfo CONSOLE_MODEL_OLD{NINTENDO_3DS_XL, {0, 0, 0}};
constexpr ConsoleModelInfo CONSOLE_MODEL_NEW{NEW_NINTENDO_3DS_XL, {0, 0, 0}}; [[maybe_unused]] constexpr ConsoleModelInfo CONSOLE_MODEL_NEW{NEW_NINTENDO_3DS_XL, {0, 0, 0}};
constexpr u8 CONSOLE_LANGUAGE = LANGUAGE_EN; constexpr u8 CONSOLE_LANGUAGE = LANGUAGE_EN;
constexpr UsernameBlock CONSOLE_USERNAME_BLOCK{u"CITRA", 0, 0}; constexpr UsernameBlock CONSOLE_USERNAME_BLOCK{u"CITRA", 0, 0};
constexpr BirthdayBlock PROFILE_BIRTHDAY{3, 25}; // March 25th, 2014 constexpr BirthdayBlock PROFILE_BIRTHDAY{3, 25}; // March 25th, 2014
@ -269,7 +268,7 @@ void Module::Interface::GetSystemModel(Kernel::HLERequestContext& ctx) {
void Module::Interface::GetModelNintendo2DS(Kernel::HLERequestContext& ctx) { void Module::Interface::GetModelNintendo2DS(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x06, 0, 0); IPC::RequestParser rp(ctx, 0x06, 0, 0);
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
u32 data; u32 data{};
// TODO(Subv): Find out the correct error codes // TODO(Subv): Find out the correct error codes
rb.Push(cfg->GetConfigInfoBlock(ConsoleModelBlockID, 4, 0x8, reinterpret_cast<u8*>(&data))); rb.Push(cfg->GetConfigInfoBlock(ConsoleModelBlockID, 4, 0x8, reinterpret_cast<u8*>(&data)));
@ -370,7 +369,7 @@ ResultVal<void*> Module::GetConfigInfoBlockPointer(u32 block_id, u32 size, u32 f
} }
ResultCode Module::GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, void* output) { ResultCode Module::GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, void* output) {
void* pointer; void* pointer = nullptr;
CASCADE_RESULT(pointer, GetConfigInfoBlockPointer(block_id, size, flag)); CASCADE_RESULT(pointer, GetConfigInfoBlockPointer(block_id, size, flag));
memcpy(output, pointer, size); memcpy(output, pointer, size);
@ -378,7 +377,7 @@ ResultCode Module::GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, void* ou
} }
ResultCode Module::SetConfigInfoBlock(u32 block_id, u32 size, u32 flag, const void* input) { ResultCode Module::SetConfigInfoBlock(u32 block_id, u32 size, u32 flag, const void* input) {
void* pointer; void* pointer = nullptr;
CASCADE_RESULT(pointer, GetConfigInfoBlockPointer(block_id, size, flag)); CASCADE_RESULT(pointer, GetConfigInfoBlockPointer(block_id, size, flag));
memcpy(pointer, input, size); memcpy(pointer, input, size);
return RESULT_SUCCESS; return RESULT_SUCCESS;
@ -701,7 +700,7 @@ void Module::SetSystemLanguage(SystemLanguage language) {
} }
SystemLanguage Module::GetSystemLanguage() { SystemLanguage Module::GetSystemLanguage() {
u8 block; u8 block{};
GetConfigInfoBlock(LanguageBlockID, sizeof(block), 8, &block); GetConfigInfoBlock(LanguageBlockID, sizeof(block), 8, &block);
return static_cast<SystemLanguage>(block); return static_cast<SystemLanguage>(block);
} }
@ -712,7 +711,7 @@ void Module::SetSoundOutputMode(SoundOutputMode mode) {
} }
SoundOutputMode Module::GetSoundOutputMode() { SoundOutputMode Module::GetSoundOutputMode() {
u8 block; u8 block{};
GetConfigInfoBlock(SoundOutputModeBlockID, sizeof(block), 8, &block); GetConfigInfoBlock(SoundOutputModeBlockID, sizeof(block), 8, &block);
return static_cast<SoundOutputMode>(block); return static_cast<SoundOutputMode>(block);
} }
@ -723,7 +722,7 @@ void Module::SetCountryCode(u8 country_code) {
} }
u8 Module::GetCountryCode() { u8 Module::GetCountryCode() {
ConsoleCountryInfo block; ConsoleCountryInfo block{};
GetConfigInfoBlock(CountryInfoBlockID, sizeof(block), 8, &block); GetConfigInfoBlock(CountryInfoBlockID, sizeof(block), 8, &block);
return block.country_code; return block.country_code;
} }
@ -734,7 +733,7 @@ void Module::SetCountryInfo(u8 country_code, u8 state_code) {
} }
u8 Module::GetStateCode() { u8 Module::GetStateCode() {
ConsoleCountryInfo block; ConsoleCountryInfo block{};
GetConfigInfoBlock(CountryInfoBlockID, sizeof(block), 8, &block); GetConfigInfoBlock(CountryInfoBlockID, sizeof(block), 8, &block);
return block.state_code; return block.state_code;
} }

View File

@ -192,7 +192,7 @@ static_assert(sizeof(CaptureState) == 0x8, "CaptureState structure size is wrong
void CSND_SND::Initialize(Kernel::HLERequestContext& ctx) { void CSND_SND::Initialize(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x01, 5, 0); IPC::RequestParser rp(ctx, 0x01, 5, 0);
const u32 size = Common::AlignUp(rp.Pop<u32>(), Memory::PAGE_SIZE); const u32 size = Common::AlignUp(rp.Pop<u32>(), Memory::CITRA_PAGE_SIZE);
master_state_offset = rp.Pop<u32>(); master_state_offset = rp.Pop<u32>();
channel_state_offset = rp.Pop<u32>(); channel_state_offset = rp.Pop<u32>();
capture_state_offset = rp.Pop<u32>(); capture_state_offset = rp.Pop<u32>();

View File

@ -95,6 +95,9 @@ void DSP_DSP::WriteProcessPipe(Kernel::HLERequestContext& ctx) {
buffer[6] = 0; buffer[6] = 0;
buffer[7] = 0; buffer[7] = 0;
break; break;
default:
LOG_ERROR(Service_DSP, "Unknown pipe {}", pipe);
break;
} }
system.DSP().PipeWrite(pipe, buffer); system.DSP().PipeWrite(pipe, buffer);

View File

@ -884,6 +884,8 @@ ResultVal<u16> FS_USER::GetSpecialContentIndexFromTMD(MediaType media_type, u64
default: default:
ASSERT(false); ASSERT(false);
} }
return ResultCode(-1);
} }
FS_USER::FS_USER(Core::System& system) FS_USER::FS_USER(Core::System& system)

View File

@ -8,9 +8,7 @@
#include "common/microprofile.h" #include "common/microprofile.h"
#include "common/swap.h" #include "common/swap.h"
#include "core/core.h" #include "core/core.h"
#include "core/hle/ipc.h"
#include "core/hle/ipc_helpers.h" #include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/shared_memory.h" #include "core/hle/kernel/shared_memory.h"
#include "core/hle/kernel/shared_page.h" #include "core/hle/kernel/shared_page.h"
#include "core/hle/result.h" #include "core/hle/result.h"
@ -83,7 +81,9 @@ u32 GSP_GPU::GetUnusedThreadId() const {
if (!used_thread_ids[id]) if (!used_thread_ids[id])
return id; return id;
} }
ASSERT_MSG(false, "All GSP threads are in use");
UNREACHABLE_MSG("All GSP threads are in use");
return 0;
} }
/// Gets a pointer to a thread command buffer in GSP shared memory /// Gets a pointer to a thread command buffer in GSP shared memory

View File

@ -1502,7 +1502,7 @@ u32 CROHelper::Fix(u32 fix_level) {
} }
} }
fix_end = Common::AlignUp(fix_end, Memory::PAGE_SIZE); fix_end = Common::AlignUp(fix_end, Memory::CITRA_PAGE_SIZE);
u32 fixed_size = fix_end - module_address; u32 fixed_size = fix_end - module_address;
SetField(FixedSize, fixed_size); SetField(FixedSize, fixed_size);
@ -1525,8 +1525,8 @@ std::tuple<VAddr, u32> CROHelper::GetExecutablePages() const {
SegmentEntry entry; SegmentEntry entry;
GetEntry(system.Memory(), i, entry); GetEntry(system.Memory(), i, entry);
if (entry.type == SegmentType::Code && entry.size != 0) { if (entry.type == SegmentType::Code && entry.size != 0) {
VAddr begin = Common::AlignDown(entry.offset, Memory::PAGE_SIZE); VAddr begin = Common::AlignDown(entry.offset, Memory::CITRA_PAGE_SIZE);
VAddr end = Common::AlignUp(entry.offset + entry.size, Memory::PAGE_SIZE); VAddr end = Common::AlignUp(entry.offset + entry.size, Memory::CITRA_PAGE_SIZE);
return std::make_tuple(begin, end - begin); return std::make_tuple(begin, end - begin);
} }
} }

View File

@ -87,19 +87,19 @@ void RO::Initialize(Kernel::HLERequestContext& ctx) {
return; return;
} }
if (crs_buffer_ptr & Memory::PAGE_MASK) { if (crs_buffer_ptr & Memory::CITRA_PAGE_MASK) {
LOG_ERROR(Service_LDR, "CRS original address is not aligned"); LOG_ERROR(Service_LDR, "CRS original address is not aligned");
rb.Push(ERROR_MISALIGNED_ADDRESS); rb.Push(ERROR_MISALIGNED_ADDRESS);
return; return;
} }
if (crs_address & Memory::PAGE_MASK) { if (crs_address & Memory::CITRA_PAGE_MASK) {
LOG_ERROR(Service_LDR, "CRS mapping address is not aligned"); LOG_ERROR(Service_LDR, "CRS mapping address is not aligned");
rb.Push(ERROR_MISALIGNED_ADDRESS); rb.Push(ERROR_MISALIGNED_ADDRESS);
return; return;
} }
if (crs_size & Memory::PAGE_MASK) { if (crs_size & Memory::CITRA_PAGE_MASK) {
LOG_ERROR(Service_LDR, "CRS size is not aligned"); LOG_ERROR(Service_LDR, "CRS size is not aligned");
rb.Push(ERROR_MISALIGNED_SIZE); rb.Push(ERROR_MISALIGNED_SIZE);
return; return;
@ -207,21 +207,21 @@ void RO::LoadCRO(Kernel::HLERequestContext& ctx, bool link_on_load_bug_fix) {
return; return;
} }
if (cro_buffer_ptr & Memory::PAGE_MASK) { if (cro_buffer_ptr & Memory::CITRA_PAGE_MASK) {
LOG_ERROR(Service_LDR, "CRO original address is not aligned"); LOG_ERROR(Service_LDR, "CRO original address is not aligned");
rb.Push(ERROR_MISALIGNED_ADDRESS); rb.Push(ERROR_MISALIGNED_ADDRESS);
rb.Push<u32>(0); rb.Push<u32>(0);
return; return;
} }
if (cro_address & Memory::PAGE_MASK) { if (cro_address & Memory::CITRA_PAGE_MASK) {
LOG_ERROR(Service_LDR, "CRO mapping address is not aligned"); LOG_ERROR(Service_LDR, "CRO mapping address is not aligned");
rb.Push(ERROR_MISALIGNED_ADDRESS); rb.Push(ERROR_MISALIGNED_ADDRESS);
rb.Push<u32>(0); rb.Push<u32>(0);
return; return;
} }
if (cro_size & Memory::PAGE_MASK) { if (cro_size & Memory::CITRA_PAGE_MASK) {
LOG_ERROR(Service_LDR, "CRO size is not aligned"); LOG_ERROR(Service_LDR, "CRO size is not aligned");
rb.Push(ERROR_MISALIGNED_SIZE); rb.Push(ERROR_MISALIGNED_SIZE);
rb.Push<u32>(0); rb.Push<u32>(0);
@ -354,7 +354,7 @@ void RO::UnloadCRO(Kernel::HLERequestContext& ctx) {
return; return;
} }
if (cro_address & Memory::PAGE_MASK) { if (cro_address & Memory::CITRA_PAGE_MASK) {
LOG_ERROR(Service_LDR, "CRO address is not aligned"); LOG_ERROR(Service_LDR, "CRO address is not aligned");
rb.Push(ERROR_MISALIGNED_ADDRESS); rb.Push(ERROR_MISALIGNED_ADDRESS);
return; return;
@ -421,7 +421,7 @@ void RO::LinkCRO(Kernel::HLERequestContext& ctx) {
return; return;
} }
if (cro_address & Memory::PAGE_MASK) { if (cro_address & Memory::CITRA_PAGE_MASK) {
LOG_ERROR(Service_LDR, "CRO address is not aligned"); LOG_ERROR(Service_LDR, "CRO address is not aligned");
rb.Push(ERROR_MISALIGNED_ADDRESS); rb.Push(ERROR_MISALIGNED_ADDRESS);
return; return;
@ -461,7 +461,7 @@ void RO::UnlinkCRO(Kernel::HLERequestContext& ctx) {
return; return;
} }
if (cro_address & Memory::PAGE_MASK) { if (cro_address & Memory::CITRA_PAGE_MASK) {
LOG_ERROR(Service_LDR, "CRO address is not aligned"); LOG_ERROR(Service_LDR, "CRO address is not aligned");
rb.Push(ERROR_MISALIGNED_ADDRESS); rb.Push(ERROR_MISALIGNED_ADDRESS);
return; return;

View File

@ -92,7 +92,8 @@ u16 NWM_UDS::GetNextAvailableNodeId() {
} }
// Any connection attempts to an already full network should have been refused. // Any connection attempts to an already full network should have been refused.
ASSERT_MSG(false, "No available connection slots in the network"); UNREACHABLE_MSG("No available connection slots in the network");
return 0;
} }
void NWM_UDS::BroadcastNodeMap() { void NWM_UDS::BroadcastNodeMap() {

View File

@ -15,9 +15,6 @@
namespace Service::NWM { namespace Service::NWM {
// 802.11 broadcast MAC address
constexpr MacAddress BroadcastMac = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
constexpr u64 DefaultNetworkUptime = 900000000; // 15 minutes in microseconds. constexpr u64 DefaultNetworkUptime = 900000000; // 15 minutes in microseconds.
// Note: These values were taken from a packet capture of an o3DS XL // Note: These values were taken from a packet capture of an o3DS XL

View File

@ -178,15 +178,6 @@ static const std::unordered_map<int, int> sockopt_map = {{
{0x1009, SO_ERROR}, {0x1009, SO_ERROR},
}}; }};
/// Converts a socket option from 3ds-specific to platform-specific
static int TranslateSockOpt(int console_opt_name) {
auto found = sockopt_map.find(console_opt_name);
if (found != sockopt_map.end()) {
return found->second;
}
return console_opt_name;
}
/// Structure to represent the 3ds' pollfd structure, which is different than most implementations /// Structure to represent the 3ds' pollfd structure, which is different than most implementations
struct CTRPollFD { struct CTRPollFD {
u32 fd; ///< Socket handle u32 fd; ///< Socket handle

View File

@ -68,9 +68,11 @@ struct Regs {
case PixelFormat::RGB5A1: case PixelFormat::RGB5A1:
case PixelFormat::RGBA4: case PixelFormat::RGBA4:
return 2; return 2;
default:
UNREACHABLE();
} }
UNREACHABLE(); return 0;
} }
INSERT_PADDING_WORDS(0x4); INSERT_PADDING_WORDS(0x4);

View File

@ -94,13 +94,13 @@ ResultStatus AppLoader_NCCH::LoadExec(std::shared_ptr<Kernel::Process>& process)
codeset->CodeSegment().offset = 0; codeset->CodeSegment().offset = 0;
codeset->CodeSegment().addr = overlay_ncch->exheader_header.codeset_info.text.address; codeset->CodeSegment().addr = overlay_ncch->exheader_header.codeset_info.text.address;
codeset->CodeSegment().size = codeset->CodeSegment().size =
overlay_ncch->exheader_header.codeset_info.text.num_max_pages * Memory::PAGE_SIZE; overlay_ncch->exheader_header.codeset_info.text.num_max_pages * Memory::CITRA_PAGE_SIZE;
codeset->RODataSegment().offset = codeset->RODataSegment().offset =
codeset->CodeSegment().offset + codeset->CodeSegment().size; codeset->CodeSegment().offset + codeset->CodeSegment().size;
codeset->RODataSegment().addr = overlay_ncch->exheader_header.codeset_info.ro.address; codeset->RODataSegment().addr = overlay_ncch->exheader_header.codeset_info.ro.address;
codeset->RODataSegment().size = codeset->RODataSegment().size =
overlay_ncch->exheader_header.codeset_info.ro.num_max_pages * Memory::PAGE_SIZE; overlay_ncch->exheader_header.codeset_info.ro.num_max_pages * Memory::CITRA_PAGE_SIZE;
// TODO(yuriks): Not sure if the bss size is added to the page-aligned .data size or just // TODO(yuriks): Not sure if the bss size is added to the page-aligned .data size or just
// to the regular size. Playing it safe for now. // to the regular size. Playing it safe for now.
@ -111,7 +111,8 @@ ResultStatus AppLoader_NCCH::LoadExec(std::shared_ptr<Kernel::Process>& process)
codeset->RODataSegment().offset + codeset->RODataSegment().size; codeset->RODataSegment().offset + codeset->RODataSegment().size;
codeset->DataSegment().addr = overlay_ncch->exheader_header.codeset_info.data.address; codeset->DataSegment().addr = overlay_ncch->exheader_header.codeset_info.data.address;
codeset->DataSegment().size = codeset->DataSegment().size =
overlay_ncch->exheader_header.codeset_info.data.num_max_pages * Memory::PAGE_SIZE + overlay_ncch->exheader_header.codeset_info.data.num_max_pages *
Memory::CITRA_PAGE_SIZE +
bss_page_size; bss_page_size;
// Apply patches now that the entire codeset (including .bss) has been allocated // Apply patches now that the entire codeset (including .bss) has been allocated

View File

@ -55,20 +55,20 @@ public:
private: private:
bool* At(VAddr addr) { bool* At(VAddr addr) {
if (addr >= VRAM_VADDR && addr < VRAM_VADDR_END) { if (addr >= VRAM_VADDR && addr < VRAM_VADDR_END) {
return &vram[(addr - VRAM_VADDR) / PAGE_SIZE]; return &vram[(addr - VRAM_VADDR) / CITRA_PAGE_SIZE];
} }
if (addr >= LINEAR_HEAP_VADDR && addr < LINEAR_HEAP_VADDR_END) { if (addr >= LINEAR_HEAP_VADDR && addr < LINEAR_HEAP_VADDR_END) {
return &linear_heap[(addr - LINEAR_HEAP_VADDR) / PAGE_SIZE]; return &linear_heap[(addr - LINEAR_HEAP_VADDR) / CITRA_PAGE_SIZE];
} }
if (addr >= NEW_LINEAR_HEAP_VADDR && addr < NEW_LINEAR_HEAP_VADDR_END) { if (addr >= NEW_LINEAR_HEAP_VADDR && addr < NEW_LINEAR_HEAP_VADDR_END) {
return &new_linear_heap[(addr - NEW_LINEAR_HEAP_VADDR) / PAGE_SIZE]; return &new_linear_heap[(addr - NEW_LINEAR_HEAP_VADDR) / CITRA_PAGE_SIZE];
} }
return nullptr; return nullptr;
} }
std::array<bool, VRAM_SIZE / PAGE_SIZE> vram{}; std::array<bool, VRAM_SIZE / CITRA_PAGE_SIZE> vram{};
std::array<bool, LINEAR_HEAP_SIZE / PAGE_SIZE> linear_heap{}; std::array<bool, LINEAR_HEAP_SIZE / CITRA_PAGE_SIZE> linear_heap{};
std::array<bool, NEW_LINEAR_HEAP_SIZE / PAGE_SIZE> new_linear_heap{}; std::array<bool, NEW_LINEAR_HEAP_SIZE / CITRA_PAGE_SIZE> new_linear_heap{};
static_assert(sizeof(bool) == 1); static_assert(sizeof(bool) == 1);
friend class boost::serialization::access; friend class boost::serialization::access;
@ -146,6 +146,145 @@ public:
} }
} }
/**
* This function should only be called for virtual addreses with attribute `PageType::Special`.
*/
MMIORegionPointer GetMMIOHandler(const PageTable& page_table, VAddr vaddr) {
for (const auto& region : page_table.special_regions) {
if (vaddr >= region.base && vaddr < (region.base + region.size)) {
return region.handler;
}
}
ASSERT_MSG(false, "Mapped IO page without a handler @ {:08X}", vaddr);
return nullptr; // Should never happen
}
template <bool UNSAFE>
void ReadBlockImpl(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer,
const std::size_t size) {
auto& page_table = *process.vm_manager.page_table;
std::size_t remaining_size = size;
std::size_t page_index = src_addr >> CITRA_PAGE_BITS;
std::size_t page_offset = src_addr & CITRA_PAGE_MASK;
while (remaining_size > 0) {
const std::size_t copy_amount = std::min(CITRA_PAGE_SIZE - page_offset, remaining_size);
const VAddr current_vaddr =
static_cast<VAddr>((page_index << CITRA_PAGE_BITS) + page_offset);
switch (page_table.attributes[page_index]) {
case PageType::Unmapped: {
LOG_ERROR(
HW_Memory,
"unmapped ReadBlock @ 0x{:08X} (start address = 0x{:08X}, size = {}) at PC "
"0x{:08X}",
current_vaddr, src_addr, size, Core::GetRunningCore().GetPC());
std::memset(dest_buffer, 0, copy_amount);
break;
}
case PageType::Memory: {
DEBUG_ASSERT(page_table.pointers[page_index]);
const u8* src_ptr = page_table.pointers[page_index] + page_offset;
std::memcpy(dest_buffer, src_ptr, copy_amount);
break;
}
case PageType::Special: {
MMIORegionPointer handler = GetMMIOHandler(page_table, current_vaddr);
DEBUG_ASSERT(handler);
handler->ReadBlock(current_vaddr, dest_buffer, copy_amount);
break;
}
case PageType::RasterizerCachedMemory: {
if constexpr (!UNSAFE) {
RasterizerFlushVirtualRegion(current_vaddr, static_cast<u32>(copy_amount),
FlushMode::Flush);
}
std::memcpy(dest_buffer, GetPointerForRasterizerCache(current_vaddr), copy_amount);
break;
}
default:
UNREACHABLE();
}
page_index++;
page_offset = 0;
dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount;
remaining_size -= copy_amount;
}
}
template <bool UNSAFE>
void WriteBlockImpl(const Kernel::Process& process, const VAddr dest_addr,
const void* src_buffer, const std::size_t size) {
auto& page_table = *process.vm_manager.page_table;
std::size_t remaining_size = size;
std::size_t page_index = dest_addr >> CITRA_PAGE_BITS;
std::size_t page_offset = dest_addr & CITRA_PAGE_MASK;
while (remaining_size > 0) {
const std::size_t copy_amount = std::min(CITRA_PAGE_SIZE - page_offset, remaining_size);
const VAddr current_vaddr =
static_cast<VAddr>((page_index << CITRA_PAGE_BITS) + page_offset);
switch (page_table.attributes[page_index]) {
case PageType::Unmapped: {
LOG_ERROR(
HW_Memory,
"unmapped WriteBlock @ 0x{:08X} (start address = 0x{:08X}, size = {}) at PC "
"0x{:08X}",
current_vaddr, dest_addr, size, Core::GetRunningCore().GetPC());
break;
}
case PageType::Memory: {
DEBUG_ASSERT(page_table.pointers[page_index]);
u8* dest_ptr = page_table.pointers[page_index] + page_offset;
std::memcpy(dest_ptr, src_buffer, copy_amount);
break;
}
case PageType::Special: {
MMIORegionPointer handler = GetMMIOHandler(page_table, current_vaddr);
DEBUG_ASSERT(handler);
handler->WriteBlock(current_vaddr, src_buffer, copy_amount);
break;
}
case PageType::RasterizerCachedMemory: {
if constexpr (!UNSAFE) {
RasterizerFlushVirtualRegion(current_vaddr, static_cast<u32>(copy_amount),
FlushMode::Invalidate);
}
std::memcpy(GetPointerForRasterizerCache(current_vaddr), src_buffer, copy_amount);
break;
}
default:
UNREACHABLE();
}
page_index++;
page_offset = 0;
src_buffer = static_cast<const u8*>(src_buffer) + copy_amount;
remaining_size -= copy_amount;
}
}
MemoryRef GetPointerForRasterizerCache(VAddr addr) const {
if (addr >= LINEAR_HEAP_VADDR && addr < LINEAR_HEAP_VADDR_END) {
return {fcram_mem, addr - LINEAR_HEAP_VADDR};
}
if (addr >= NEW_LINEAR_HEAP_VADDR && addr < NEW_LINEAR_HEAP_VADDR_END) {
return {fcram_mem, addr - NEW_LINEAR_HEAP_VADDR};
}
if (addr >= VRAM_VADDR && addr < VRAM_VADDR_END) {
return {vram_mem, addr - VRAM_VADDR};
}
UNREACHABLE();
return MemoryRef{};
}
private: private:
friend class boost::serialization::access; friend class boost::serialization::access;
template <class Archive> template <class Archive>
@ -221,10 +360,10 @@ std::shared_ptr<PageTable> MemorySystem::GetCurrentPageTable() const {
void MemorySystem::MapPages(PageTable& page_table, u32 base, u32 size, MemoryRef memory, void MemorySystem::MapPages(PageTable& page_table, u32 base, u32 size, MemoryRef memory,
PageType type) { PageType type) {
LOG_DEBUG(HW_Memory, "Mapping {} onto {:08X}-{:08X}", (void*)memory.GetPtr(), base * PAGE_SIZE, LOG_DEBUG(HW_Memory, "Mapping {} onto {:08X}-{:08X}", (void*)memory.GetPtr(),
(base + size) * PAGE_SIZE); base * CITRA_PAGE_SIZE, (base + size) * CITRA_PAGE_SIZE);
RasterizerFlushVirtualRegion(base << PAGE_BITS, size * PAGE_SIZE, RasterizerFlushVirtualRegion(base << CITRA_PAGE_BITS, size * CITRA_PAGE_SIZE,
FlushMode::FlushAndInvalidate); FlushMode::FlushAndInvalidate);
u32 end = base + size; u32 end = base + size;
@ -235,49 +374,42 @@ void MemorySystem::MapPages(PageTable& page_table, u32 base, u32 size, MemoryRef
page_table.pointers[base] = memory; page_table.pointers[base] = memory;
// If the memory to map is already rasterizer-cached, mark the page // If the memory to map is already rasterizer-cached, mark the page
if (type == PageType::Memory && impl->cache_marker.IsCached(base * PAGE_SIZE)) { if (type == PageType::Memory && impl->cache_marker.IsCached(base * CITRA_PAGE_SIZE)) {
page_table.attributes[base] = PageType::RasterizerCachedMemory; page_table.attributes[base] = PageType::RasterizerCachedMemory;
page_table.pointers[base] = nullptr; page_table.pointers[base] = nullptr;
} }
base += 1; base += 1;
if (memory != nullptr && memory.GetSize() > PAGE_SIZE) if (memory != nullptr && memory.GetSize() > CITRA_PAGE_SIZE)
memory += PAGE_SIZE; memory += CITRA_PAGE_SIZE;
} }
} }
void MemorySystem::MapMemoryRegion(PageTable& page_table, VAddr base, u32 size, MemoryRef target) { void MemorySystem::MapMemoryRegion(PageTable& page_table, VAddr base, u32 size, MemoryRef target) {
ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:08X}", size); ASSERT_MSG((size & CITRA_PAGE_MASK) == 0, "non-page aligned size: {:08X}", size);
ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:08X}", base); ASSERT_MSG((base & CITRA_PAGE_MASK) == 0, "non-page aligned base: {:08X}", base);
MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, target, PageType::Memory); MapPages(page_table, base / CITRA_PAGE_SIZE, size / CITRA_PAGE_SIZE, target, PageType::Memory);
} }
void MemorySystem::MapIoRegion(PageTable& page_table, VAddr base, u32 size, void MemorySystem::MapIoRegion(PageTable& page_table, VAddr base, u32 size,
MMIORegionPointer mmio_handler) { MMIORegionPointer mmio_handler) {
ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:08X}", size); ASSERT_MSG((size & CITRA_PAGE_MASK) == 0, "non-page aligned size: {:08X}", size);
ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:08X}", base); ASSERT_MSG((base & CITRA_PAGE_MASK) == 0, "non-page aligned base: {:08X}", base);
MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Special); MapPages(page_table, base / CITRA_PAGE_SIZE, size / CITRA_PAGE_SIZE, nullptr,
PageType::Special);
page_table.special_regions.emplace_back(SpecialRegion{base, size, mmio_handler}); page_table.special_regions.emplace_back(SpecialRegion{base, size, mmio_handler});
} }
void MemorySystem::UnmapRegion(PageTable& page_table, VAddr base, u32 size) { void MemorySystem::UnmapRegion(PageTable& page_table, VAddr base, u32 size) {
ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:08X}", size); ASSERT_MSG((size & CITRA_PAGE_MASK) == 0, "non-page aligned size: {:08X}", size);
ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:08X}", base); ASSERT_MSG((base & CITRA_PAGE_MASK) == 0, "non-page aligned base: {:08X}", base);
MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Unmapped); MapPages(page_table, base / CITRA_PAGE_SIZE, size / CITRA_PAGE_SIZE, nullptr,
PageType::Unmapped);
} }
MemoryRef MemorySystem::GetPointerForRasterizerCache(VAddr addr) const { MemoryRef MemorySystem::GetPointerForRasterizerCache(VAddr addr) const {
if (addr >= LINEAR_HEAP_VADDR && addr < LINEAR_HEAP_VADDR_END) { return impl->GetPointerForRasterizerCache(addr);
return {impl->fcram_mem, addr - LINEAR_HEAP_VADDR};
}
if (addr >= NEW_LINEAR_HEAP_VADDR && addr < NEW_LINEAR_HEAP_VADDR_END) {
return {impl->fcram_mem, addr - NEW_LINEAR_HEAP_VADDR};
}
if (addr >= VRAM_VADDR && addr < VRAM_VADDR_END) {
return {impl->vram_mem, addr - VRAM_VADDR};
}
UNREACHABLE();
} }
void MemorySystem::RegisterPageTable(std::shared_ptr<PageTable> page_table) { void MemorySystem::RegisterPageTable(std::shared_ptr<PageTable> page_table) {
@ -291,33 +423,20 @@ void MemorySystem::UnregisterPageTable(std::shared_ptr<PageTable> page_table) {
} }
} }
/**
* This function should only be called for virtual addreses with attribute `PageType::Special`.
*/
static MMIORegionPointer GetMMIOHandler(const PageTable& page_table, VAddr vaddr) {
for (const auto& region : page_table.special_regions) {
if (vaddr >= region.base && vaddr < (region.base + region.size)) {
return region.handler;
}
}
ASSERT_MSG(false, "Mapped IO page without a handler @ {:08X}", vaddr);
return nullptr; // Should never happen
}
template <typename T> template <typename T>
T ReadMMIO(MMIORegionPointer mmio_handler, VAddr addr); T ReadMMIO(MMIORegionPointer mmio_handler, VAddr addr);
template <typename T> template <typename T>
T MemorySystem::Read(const VAddr vaddr) { T MemorySystem::Read(const VAddr vaddr) {
const u8* page_pointer = impl->current_page_table->pointers[vaddr >> PAGE_BITS]; const u8* page_pointer = impl->current_page_table->pointers[vaddr >> CITRA_PAGE_BITS];
if (page_pointer) { if (page_pointer) {
// NOTE: Avoid adding any extra logic to this fast-path block // NOTE: Avoid adding any extra logic to this fast-path block
T value; T value;
std::memcpy(&value, &page_pointer[vaddr & PAGE_MASK], sizeof(T)); std::memcpy(&value, &page_pointer[vaddr & CITRA_PAGE_MASK], sizeof(T));
return value; return value;
} }
PageType type = impl->current_page_table->attributes[vaddr >> PAGE_BITS]; PageType type = impl->current_page_table->attributes[vaddr >> CITRA_PAGE_BITS];
switch (type) { switch (type) {
case PageType::Unmapped: case PageType::Unmapped:
LOG_ERROR(HW_Memory, "unmapped Read{} @ 0x{:08X} at PC 0x{:08X}", sizeof(T) * 8, vaddr, LOG_ERROR(HW_Memory, "unmapped Read{} @ 0x{:08X} at PC 0x{:08X}", sizeof(T) * 8, vaddr,
@ -334,10 +453,12 @@ T MemorySystem::Read(const VAddr vaddr) {
return value; return value;
} }
case PageType::Special: case PageType::Special:
return ReadMMIO<T>(GetMMIOHandler(*impl->current_page_table, vaddr), vaddr); return ReadMMIO<T>(impl->GetMMIOHandler(*impl->current_page_table, vaddr), vaddr);
default: default:
UNREACHABLE(); UNREACHABLE();
} }
return T{};
} }
template <typename T> template <typename T>
@ -345,14 +466,14 @@ void WriteMMIO(MMIORegionPointer mmio_handler, VAddr addr, const T data);
template <typename T> template <typename T>
void MemorySystem::Write(const VAddr vaddr, const T data) { void MemorySystem::Write(const VAddr vaddr, const T data) {
u8* page_pointer = impl->current_page_table->pointers[vaddr >> PAGE_BITS]; u8* page_pointer = impl->current_page_table->pointers[vaddr >> CITRA_PAGE_BITS];
if (page_pointer) { if (page_pointer) {
// NOTE: Avoid adding any extra logic to this fast-path block // NOTE: Avoid adding any extra logic to this fast-path block
std::memcpy(&page_pointer[vaddr & PAGE_MASK], &data, sizeof(T)); std::memcpy(&page_pointer[vaddr & CITRA_PAGE_MASK], &data, sizeof(T));
return; return;
} }
PageType type = impl->current_page_table->attributes[vaddr >> PAGE_BITS]; PageType type = impl->current_page_table->attributes[vaddr >> CITRA_PAGE_BITS];
switch (type) { switch (type) {
case PageType::Unmapped: case PageType::Unmapped:
LOG_ERROR(HW_Memory, "unmapped Write{} 0x{:08X} @ 0x{:08X} at PC 0x{:08X}", LOG_ERROR(HW_Memory, "unmapped Write{} 0x{:08X} @ 0x{:08X} at PC 0x{:08X}",
@ -367,7 +488,7 @@ void MemorySystem::Write(const VAddr vaddr, const T data) {
break; break;
} }
case PageType::Special: case PageType::Special:
WriteMMIO<T>(GetMMIOHandler(*impl->current_page_table, vaddr), vaddr, data); WriteMMIO<T>(impl->GetMMIOHandler(*impl->current_page_table, vaddr), vaddr, data);
break; break;
default: default:
UNREACHABLE(); UNREACHABLE();
@ -376,15 +497,15 @@ void MemorySystem::Write(const VAddr vaddr, const T data) {
template <typename T> template <typename T>
bool MemorySystem::WriteExclusive(const VAddr vaddr, const T data, const T expected) { bool MemorySystem::WriteExclusive(const VAddr vaddr, const T data, const T expected) {
u8* page_pointer = impl->current_page_table->pointers[vaddr >> PAGE_BITS]; u8* page_pointer = impl->current_page_table->pointers[vaddr >> CITRA_PAGE_BITS];
if (page_pointer) { if (page_pointer) {
const auto volatile_pointer = const auto volatile_pointer =
reinterpret_cast<volatile T*>(&page_pointer[vaddr & PAGE_MASK]); reinterpret_cast<volatile T*>(&page_pointer[vaddr & CITRA_PAGE_MASK]);
return Common::AtomicCompareAndSwap(volatile_pointer, data, expected); return Common::AtomicCompareAndSwap(volatile_pointer, data, expected);
} }
PageType type = impl->current_page_table->attributes[vaddr >> PAGE_BITS]; PageType type = impl->current_page_table->attributes[vaddr >> CITRA_PAGE_BITS];
switch (type) { switch (type) {
case PageType::Unmapped: case PageType::Unmapped:
LOG_ERROR(HW_Memory, "unmapped Write{} 0x{:08X} @ 0x{:08X} at PC 0x{:08X}", LOG_ERROR(HW_Memory, "unmapped Write{} 0x{:08X} @ 0x{:08X} at PC 0x{:08X}",
@ -400,7 +521,7 @@ bool MemorySystem::WriteExclusive(const VAddr vaddr, const T data, const T expec
return Common::AtomicCompareAndSwap(volatile_pointer, data, expected); return Common::AtomicCompareAndSwap(volatile_pointer, data, expected);
} }
case PageType::Special: case PageType::Special:
WriteMMIO<T>(GetMMIOHandler(*impl->current_page_table, vaddr), vaddr, data); WriteMMIO<T>(impl->GetMMIOHandler(*impl->current_page_table, vaddr), vaddr, data);
return false; return false;
default: default:
UNREACHABLE(); UNREACHABLE();
@ -408,20 +529,20 @@ bool MemorySystem::WriteExclusive(const VAddr vaddr, const T data, const T expec
return true; return true;
} }
bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) { bool MemorySystem::IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) {
auto& page_table = *process.vm_manager.page_table; auto& page_table = *process.vm_manager.page_table;
auto page_pointer = page_table.pointers[vaddr >> PAGE_BITS]; auto page_pointer = page_table.pointers[vaddr >> CITRA_PAGE_BITS];
if (page_pointer) if (page_pointer)
return true; return true;
if (page_table.attributes[vaddr >> PAGE_BITS] == PageType::RasterizerCachedMemory) if (page_table.attributes[vaddr >> CITRA_PAGE_BITS] == PageType::RasterizerCachedMemory)
return true; return true;
if (page_table.attributes[vaddr >> PAGE_BITS] != PageType::Special) if (page_table.attributes[vaddr >> CITRA_PAGE_BITS] != PageType::Special)
return false; return false;
MMIORegionPointer mmio_region = GetMMIOHandler(page_table, vaddr); MMIORegionPointer mmio_region = impl->GetMMIOHandler(page_table, vaddr);
if (mmio_region) { if (mmio_region) {
return mmio_region->IsValidAddress(vaddr); return mmio_region->IsValidAddress(vaddr);
} }
@ -430,16 +551,16 @@ bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) {
} }
bool MemorySystem::IsValidPhysicalAddress(const PAddr paddr) const { bool MemorySystem::IsValidPhysicalAddress(const PAddr paddr) const {
return GetPhysicalPointer(paddr) != nullptr; return GetPhysicalRef(paddr);
} }
u8* MemorySystem::GetPointer(const VAddr vaddr) { u8* MemorySystem::GetPointer(const VAddr vaddr) {
u8* page_pointer = impl->current_page_table->pointers[vaddr >> PAGE_BITS]; u8* page_pointer = impl->current_page_table->pointers[vaddr >> CITRA_PAGE_BITS];
if (page_pointer) { if (page_pointer) {
return page_pointer + (vaddr & PAGE_MASK); return page_pointer + (vaddr & CITRA_PAGE_MASK);
} }
if (impl->current_page_table->attributes[vaddr >> PAGE_BITS] == if (impl->current_page_table->attributes[vaddr >> CITRA_PAGE_BITS] ==
PageType::RasterizerCachedMemory) { PageType::RasterizerCachedMemory) {
return GetPointerForRasterizerCache(vaddr); return GetPointerForRasterizerCache(vaddr);
} }
@ -450,12 +571,12 @@ u8* MemorySystem::GetPointer(const VAddr vaddr) {
} }
const u8* MemorySystem::GetPointer(const VAddr vaddr) const { const u8* MemorySystem::GetPointer(const VAddr vaddr) const {
const u8* page_pointer = impl->current_page_table->pointers[vaddr >> PAGE_BITS]; const u8* page_pointer = impl->current_page_table->pointers[vaddr >> CITRA_PAGE_BITS];
if (page_pointer) { if (page_pointer) {
return page_pointer + (vaddr & PAGE_MASK); return page_pointer + (vaddr & CITRA_PAGE_MASK);
} }
if (impl->current_page_table->attributes[vaddr >> PAGE_BITS] == if (impl->current_page_table->attributes[vaddr >> CITRA_PAGE_BITS] ==
PageType::RasterizerCachedMemory) { PageType::RasterizerCachedMemory) {
return GetPointerForRasterizerCache(vaddr); return GetPointerForRasterizerCache(vaddr);
} }
@ -469,11 +590,14 @@ std::string MemorySystem::ReadCString(VAddr vaddr, std::size_t max_length) {
string.reserve(max_length); string.reserve(max_length);
for (std::size_t i = 0; i < max_length; ++i) { for (std::size_t i = 0; i < max_length; ++i) {
char c = Read8(vaddr); char c = Read8(vaddr);
if (c == '\0') if (c == '\0') {
break; break;
}
string.push_back(c); string.push_back(c);
++vaddr; ++vaddr;
} }
string.shrink_to_fit(); string.shrink_to_fit();
return string; return string;
} }
@ -482,40 +606,30 @@ u8* MemorySystem::GetPhysicalPointer(PAddr address) {
return GetPhysicalRef(address); return GetPhysicalRef(address);
} }
const u8* MemorySystem::GetPhysicalPointer(PAddr address) const {
return GetPhysicalRef(address);
}
MemoryRef MemorySystem::GetPhysicalRef(PAddr address) const { MemoryRef MemorySystem::GetPhysicalRef(PAddr address) const {
struct MemoryArea { constexpr std::array memory_areas = {
PAddr paddr_base; std::make_pair(VRAM_PADDR, VRAM_SIZE),
u32 size; std::make_pair(DSP_RAM_PADDR, DSP_RAM_SIZE),
std::make_pair(FCRAM_PADDR, FCRAM_N3DS_SIZE),
std::make_pair(N3DS_EXTRA_RAM_PADDR, N3DS_EXTRA_RAM_SIZE),
}; };
static constexpr MemoryArea memory_areas[] = { const auto area = std::find_if(memory_areas.begin(), memory_areas.end(), [&](const auto& area) {
{VRAM_PADDR, VRAM_SIZE}, // Note: the region end check is inclusive because the user can pass in an address that
{DSP_RAM_PADDR, DSP_RAM_SIZE}, // represents an open right bound
{FCRAM_PADDR, FCRAM_N3DS_SIZE}, return address >= area.first && address <= area.first + area.second;
{N3DS_EXTRA_RAM_PADDR, N3DS_EXTRA_RAM_SIZE}, });
};
const auto area = if (area == memory_areas.end()) {
std::find_if(std::begin(memory_areas), std::end(memory_areas), [&](const auto& area) { LOG_ERROR(HW_Memory, "Unknown GetPhysicalPointer @ {:#08X} at PC {:#08X}", address,
// 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,
Core::GetRunningCore().GetPC()); Core::GetRunningCore().GetPC());
return nullptr; return nullptr;
} }
u32 offset_into_region = address - area->paddr_base; u32 offset_into_region = address - area->first;
std::shared_ptr<BackingMem> target_mem = nullptr; std::shared_ptr<BackingMem> target_mem = nullptr;
switch (area->paddr_base) { switch (area->first) {
case VRAM_PADDR: case VRAM_PADDR:
target_mem = impl->vram_mem; target_mem = impl->vram_mem;
break; break;
@ -564,14 +678,14 @@ void MemorySystem::RasterizerMarkRegionCached(PAddr start, u32 size, bool cached
return; return;
} }
u32 num_pages = ((start + size - 1) >> PAGE_BITS) - (start >> PAGE_BITS) + 1; u32 num_pages = ((start + size - 1) >> CITRA_PAGE_BITS) - (start >> CITRA_PAGE_BITS) + 1;
PAddr paddr = start; PAddr paddr = start;
for (unsigned i = 0; i < num_pages; ++i, paddr += PAGE_SIZE) { for (unsigned i = 0; i < num_pages; ++i, paddr += CITRA_PAGE_SIZE) {
for (VAddr vaddr : PhysicalToVirtualAddressForRasterizer(paddr)) { for (VAddr vaddr : PhysicalToVirtualAddressForRasterizer(paddr)) {
impl->cache_marker.Mark(vaddr, cached); impl->cache_marker.Mark(vaddr, cached);
for (auto page_table : impl->page_table_list) { for (auto page_table : impl->page_table_list) {
PageType& page_type = page_table->attributes[vaddr >> PAGE_BITS]; PageType& page_type = page_table->attributes[vaddr >> CITRA_PAGE_BITS];
if (cached) { if (cached) {
// Switch page type to cached if now cached // Switch page type to cached if now cached
@ -582,7 +696,7 @@ void MemorySystem::RasterizerMarkRegionCached(PAddr start, u32 size, bool cached
break; break;
case PageType::Memory: case PageType::Memory:
page_type = PageType::RasterizerCachedMemory; page_type = PageType::RasterizerCachedMemory;
page_table->pointers[vaddr >> PAGE_BITS] = nullptr; page_table->pointers[vaddr >> CITRA_PAGE_BITS] = nullptr;
break; break;
default: default:
UNREACHABLE(); UNREACHABLE();
@ -596,8 +710,8 @@ void MemorySystem::RasterizerMarkRegionCached(PAddr start, u32 size, bool cached
break; break;
case PageType::RasterizerCachedMemory: { case PageType::RasterizerCachedMemory: {
page_type = PageType::Memory; page_type = PageType::Memory;
page_table->pointers[vaddr >> PAGE_BITS] = page_table->pointers[vaddr >> CITRA_PAGE_BITS] =
GetPointerForRasterizerCache(vaddr & ~PAGE_MASK); GetPointerForRasterizerCache(vaddr & ~CITRA_PAGE_MASK);
break; break;
} }
default: default:
@ -702,53 +816,12 @@ u64 MemorySystem::Read64(const VAddr addr) {
void MemorySystem::ReadBlock(const Kernel::Process& process, const VAddr src_addr, void MemorySystem::ReadBlock(const Kernel::Process& process, const VAddr src_addr,
void* dest_buffer, const std::size_t size) { void* dest_buffer, const std::size_t size) {
auto& page_table = *process.vm_manager.page_table; return impl->ReadBlockImpl<false>(process, src_addr, dest_buffer, size);
}
std::size_t remaining_size = size; void MemorySystem::ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size) {
std::size_t page_index = src_addr >> PAGE_BITS; const auto& process = *Core::System::GetInstance().Kernel().GetCurrentProcess();
std::size_t page_offset = src_addr & PAGE_MASK; return impl->ReadBlockImpl<false>(process, src_addr, dest_buffer, size);
while (remaining_size > 0) {
const std::size_t copy_amount = std::min(PAGE_SIZE - page_offset, remaining_size);
const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
switch (page_table.attributes[page_index]) {
case PageType::Unmapped: {
LOG_ERROR(HW_Memory,
"unmapped ReadBlock @ 0x{:08X} (start address = 0x{:08X}, size = {}) at PC "
"0x{:08X}",
current_vaddr, src_addr, size, Core::GetRunningCore().GetPC());
std::memset(dest_buffer, 0, copy_amount);
break;
}
case PageType::Memory: {
DEBUG_ASSERT(page_table.pointers[page_index]);
const u8* src_ptr = page_table.pointers[page_index] + page_offset;
std::memcpy(dest_buffer, src_ptr, copy_amount);
break;
}
case PageType::Special: {
MMIORegionPointer handler = GetMMIOHandler(page_table, current_vaddr);
DEBUG_ASSERT(handler);
handler->ReadBlock(current_vaddr, dest_buffer, copy_amount);
break;
}
case PageType::RasterizerCachedMemory: {
RasterizerFlushVirtualRegion(current_vaddr, static_cast<u32>(copy_amount),
FlushMode::Flush);
std::memcpy(dest_buffer, GetPointerForRasterizerCache(current_vaddr), copy_amount);
break;
}
default:
UNREACHABLE();
}
page_index++;
page_offset = 0;
dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount;
remaining_size -= copy_amount;
}
} }
void MemorySystem::Write8(const VAddr addr, const u8 data) { void MemorySystem::Write8(const VAddr addr, const u8 data) {
@ -785,65 +858,28 @@ bool MemorySystem::WriteExclusive64(const VAddr addr, const u64 data, const u64
void MemorySystem::WriteBlock(const Kernel::Process& process, const VAddr dest_addr, void MemorySystem::WriteBlock(const Kernel::Process& process, const VAddr dest_addr,
const void* src_buffer, const std::size_t size) { const void* src_buffer, const std::size_t size) {
auto& page_table = *process.vm_manager.page_table; return impl->WriteBlockImpl<false>(process, dest_addr, src_buffer, size);
std::size_t remaining_size = size; }
std::size_t page_index = dest_addr >> PAGE_BITS;
std::size_t page_offset = dest_addr & PAGE_MASK;
while (remaining_size > 0) { void MemorySystem::WriteBlock(const VAddr dest_addr, const void* src_buffer,
const std::size_t copy_amount = std::min(PAGE_SIZE - page_offset, remaining_size); const std::size_t size) {
const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); auto& process = *Core::System::GetInstance().Kernel().GetCurrentProcess();
return impl->WriteBlockImpl<false>(process, dest_addr, src_buffer, size);
switch (page_table.attributes[page_index]) {
case PageType::Unmapped: {
LOG_ERROR(HW_Memory,
"unmapped WriteBlock @ 0x{:08X} (start address = 0x{:08X}, size = {}) at PC "
"0x{:08X}",
current_vaddr, dest_addr, size, Core::GetRunningCore().GetPC());
break;
}
case PageType::Memory: {
DEBUG_ASSERT(page_table.pointers[page_index]);
u8* dest_ptr = page_table.pointers[page_index] + page_offset;
std::memcpy(dest_ptr, src_buffer, copy_amount);
break;
}
case PageType::Special: {
MMIORegionPointer handler = GetMMIOHandler(page_table, current_vaddr);
DEBUG_ASSERT(handler);
handler->WriteBlock(current_vaddr, src_buffer, copy_amount);
break;
}
case PageType::RasterizerCachedMemory: {
RasterizerFlushVirtualRegion(current_vaddr, static_cast<u32>(copy_amount),
FlushMode::Invalidate);
std::memcpy(GetPointerForRasterizerCache(current_vaddr), src_buffer, copy_amount);
break;
}
default:
UNREACHABLE();
}
page_index++;
page_offset = 0;
src_buffer = static_cast<const u8*>(src_buffer) + copy_amount;
remaining_size -= copy_amount;
}
} }
void MemorySystem::ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, void MemorySystem::ZeroBlock(const Kernel::Process& process, const VAddr dest_addr,
const std::size_t size) { const std::size_t size) {
auto& page_table = *process.vm_manager.page_table; auto& page_table = *process.vm_manager.page_table;
std::size_t remaining_size = size; std::size_t remaining_size = size;
std::size_t page_index = dest_addr >> PAGE_BITS; std::size_t page_index = dest_addr >> CITRA_PAGE_BITS;
std::size_t page_offset = dest_addr & PAGE_MASK; std::size_t page_offset = dest_addr & CITRA_PAGE_MASK;
static const std::array<u8, PAGE_SIZE> zeros = {}; static const std::array<u8, CITRA_PAGE_SIZE> zeros = {};
while (remaining_size > 0) { while (remaining_size > 0) {
const std::size_t copy_amount = std::min(PAGE_SIZE - page_offset, remaining_size); const std::size_t copy_amount = std::min(CITRA_PAGE_SIZE - page_offset, remaining_size);
const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); const VAddr current_vaddr =
static_cast<VAddr>((page_index << CITRA_PAGE_BITS) + page_offset);
switch (page_table.attributes[page_index]) { switch (page_table.attributes[page_index]) {
case PageType::Unmapped: { case PageType::Unmapped: {
@ -861,7 +897,7 @@ void MemorySystem::ZeroBlock(const Kernel::Process& process, const VAddr dest_ad
break; break;
} }
case PageType::Special: { case PageType::Special: {
MMIORegionPointer handler = GetMMIOHandler(page_table, current_vaddr); MMIORegionPointer handler = impl->GetMMIOHandler(page_table, current_vaddr);
DEBUG_ASSERT(handler); DEBUG_ASSERT(handler);
handler->WriteBlock(current_vaddr, zeros.data(), copy_amount); handler->WriteBlock(current_vaddr, zeros.data(), copy_amount);
break; break;
@ -892,12 +928,13 @@ void MemorySystem::CopyBlock(const Kernel::Process& dest_process,
std::size_t size) { std::size_t size) {
auto& page_table = *src_process.vm_manager.page_table; auto& page_table = *src_process.vm_manager.page_table;
std::size_t remaining_size = size; std::size_t remaining_size = size;
std::size_t page_index = src_addr >> PAGE_BITS; std::size_t page_index = src_addr >> CITRA_PAGE_BITS;
std::size_t page_offset = src_addr & PAGE_MASK; std::size_t page_offset = src_addr & CITRA_PAGE_MASK;
while (remaining_size > 0) { while (remaining_size > 0) {
const std::size_t copy_amount = std::min(PAGE_SIZE - page_offset, remaining_size); const std::size_t copy_amount = std::min(CITRA_PAGE_SIZE - page_offset, remaining_size);
const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); const VAddr current_vaddr =
static_cast<VAddr>((page_index << CITRA_PAGE_BITS) + page_offset);
switch (page_table.attributes[page_index]) { switch (page_table.attributes[page_index]) {
case PageType::Unmapped: { case PageType::Unmapped: {
@ -915,7 +952,7 @@ void MemorySystem::CopyBlock(const Kernel::Process& dest_process,
break; break;
} }
case PageType::Special: { case PageType::Special: {
MMIORegionPointer handler = GetMMIOHandler(page_table, current_vaddr); MMIORegionPointer handler = impl->GetMMIOHandler(page_table, current_vaddr);
DEBUG_ASSERT(handler); DEBUG_ASSERT(handler);
std::vector<u8> buffer(copy_amount); std::vector<u8> buffer(copy_amount);
handler->ReadBlock(current_vaddr, buffer.data(), buffer.size()); handler->ReadBlock(current_vaddr, buffer.data(), buffer.size());

View File

@ -3,12 +3,9 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#pragma once #pragma once
#include <array> #include <array>
#include <cstddef> #include <cstddef>
#include <memory>
#include <string> #include <string>
#include <vector>
#include <boost/serialization/array.hpp> #include <boost/serialization/array.hpp>
#include <boost/serialization/vector.hpp> #include <boost/serialization/vector.hpp>
#include "common/common_types.h" #include "common/common_types.h"
@ -27,17 +24,14 @@ class DspInterface;
namespace Memory { namespace Memory {
// Are defined in a system header
#undef PAGE_SIZE
#undef PAGE_MASK
/** /**
* Page size used by the ARM architecture. This is the smallest granularity with which memory can * Page size used by the ARM architecture. This is the smallest granularity with which memory can
* be mapped. * be mapped.
*/ */
const u32 PAGE_SIZE = 0x1000; constexpr u32 CITRA_PAGE_SIZE = 0x1000;
const u32 PAGE_MASK = PAGE_SIZE - 1; constexpr u32 CITRA_PAGE_MASK = CITRA_PAGE_SIZE - 1;
const int PAGE_BITS = 12; constexpr int CITRA_PAGE_BITS = 12;
const std::size_t PAGE_TABLE_NUM_ENTRIES = 1 << (32 - PAGE_BITS); constexpr std::size_t PAGE_TABLE_NUM_ENTRIES = 1 << (32 - CITRA_PAGE_BITS);
enum class PageType { enum class PageType {
/// Page is unmapped and should cause an access error. /// Page is unmapped and should cause an access error.
@ -106,11 +100,10 @@ struct PageTable {
private: private:
std::array<u8*, PAGE_TABLE_NUM_ENTRIES> raw; std::array<u8*, PAGE_TABLE_NUM_ENTRIES> raw;
std::array<MemoryRef, PAGE_TABLE_NUM_ENTRIES> refs; std::array<MemoryRef, PAGE_TABLE_NUM_ENTRIES> refs;
friend struct PageTable; friend struct PageTable;
}; };
Pointers pointers; Pointers pointers;
/** /**
@ -317,14 +310,108 @@ public:
void SetCurrentPageTable(std::shared_ptr<PageTable> page_table); void SetCurrentPageTable(std::shared_ptr<PageTable> page_table);
std::shared_ptr<PageTable> GetCurrentPageTable() const; std::shared_ptr<PageTable> GetCurrentPageTable() const;
/**
* Gets a pointer to the given address.
*
* @param vaddr Virtual address to retrieve a pointer to.
*
* @returns The pointer to the given address, if the address is valid.
* If the address is not valid, nullptr will be returned.
*/
u8* GetPointer(VAddr vaddr);
/**
* Gets a pointer to the given address.
*
* @param vaddr Virtual address to retrieve a pointer to.
*
* @returns The pointer to the given address, if the address is valid.
* If the address is not valid, nullptr will be returned.
*/
const u8* GetPointer(VAddr vaddr) const;
/**
* Reads an 8-bit unsigned value from the current process' address space
* at the given virtual address.
*
* @param addr The virtual address to read the 8-bit value from.
*
* @returns the read 8-bit unsigned value.
*/
u8 Read8(VAddr addr); u8 Read8(VAddr addr);
/**
* Reads a 16-bit unsigned value from the current process' address space
* at the given virtual address.
*
* @param addr The virtual address to read the 16-bit value from.
*
* @returns the read 16-bit unsigned value.
*/
u16 Read16(VAddr addr); u16 Read16(VAddr addr);
/**
* Reads a 32-bit unsigned value from the current process' address space
* at the given virtual address.
*
* @param addr The virtual address to read the 32-bit value from.
*
* @returns the read 32-bit unsigned value.
*/
u32 Read32(VAddr addr); u32 Read32(VAddr addr);
/**
* Reads a 64-bit unsigned value from the current process' address space
* at the given virtual address.
*
* @param addr The virtual address to read the 64-bit value from.
*
* @returns the read 64-bit value.
*/
u64 Read64(VAddr addr); u64 Read64(VAddr addr);
/**
* Writes an 8-bit unsigned integer to the given virtual address in
* the current process' address space.
*
* @param addr The virtual address to write the 8-bit unsigned integer to.
* @param data The 8-bit unsigned integer to write to the given virtual address.
*
* @post The memory at the given virtual address contains the specified data value.
*/
void Write8(VAddr addr, u8 data); void Write8(VAddr addr, u8 data);
/**
* Writes a 16-bit unsigned integer to the given virtual address in
* the current process' address space.
*
* @param addr The virtual address to write the 16-bit unsigned integer to.
* @param data The 16-bit unsigned integer to write to the given virtual address.
*
* @post The memory range [addr, sizeof(data)) contains the given data value.
*/
void Write16(VAddr addr, u16 data); void Write16(VAddr addr, u16 data);
/**
* Writes a 32-bit unsigned integer to the given virtual address in
* the current process' address space.
*
* @param addr The virtual address to write the 32-bit unsigned integer to.
* @param data The 32-bit unsigned integer to write to the given virtual address.
*
* @post The memory range [addr, sizeof(data)) contains the given data value.
*/
void Write32(VAddr addr, u32 data); void Write32(VAddr addr, u32 data);
/**
* Writes a 64-bit unsigned integer to the given virtual address in
* the current process' address space.
*
* @param addr The virtual address to write the 64-bit unsigned integer to.
* @param data The 64-bit unsigned integer to write to the given virtual address.
*
* @post The memory range [addr, sizeof(data)) contains the given data value.
*/
void Write64(VAddr addr, u64 data); void Write64(VAddr addr, u64 data);
/** /**
@ -344,29 +431,155 @@ public:
bool WriteExclusive32(const VAddr addr, const u32 data, const u32 expected); bool WriteExclusive32(const VAddr addr, const u32 data, const u32 expected);
bool WriteExclusive64(const VAddr addr, const u64 data, const u64 expected); bool WriteExclusive64(const VAddr addr, const u64 data, const u64 expected);
/**
* Reads a null-terminated string from the given virtual address.
* This function will continually read characters until either:
*
* - A null character ('\0') is reached.
* - max_length characters have been read.
*
* @note The final null-terminating character (if found) is not included
* in the returned string.
*
* @param vaddr The address to begin reading the string from.
* @param max_length The maximum length of the string to read in characters.
*
* @returns The read string.
*/
std::string ReadCString(VAddr vaddr, std::size_t max_length);
/**
* Reads a contiguous block of bytes from a specified process' address space.
*
* @param process The process to read the data from.
* @param src_addr The virtual address to begin reading from.
* @param dest_buffer The buffer to place the read bytes into.
* @param size The amount of data to read, in bytes.
*
* @note If a size of 0 is specified, then this function reads nothing and
* no attempts to access memory are made at all.
*
* @pre dest_buffer must be at least size bytes in length, otherwise a
* buffer overrun will occur.
*
* @post The range [dest_buffer, size) contains the read bytes from the
* process' address space.
*/
void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer, void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer,
std::size_t size); std::size_t size);
/**
* Reads a contiguous block of bytes from the current process' address space.
*
* @param src_addr The virtual address to begin reading from.
* @param dest_buffer The buffer to place the read bytes into.
* @param size The amount of data to read, in bytes.
*
* @note If a size of 0 is specified, then this function reads nothing and
* no attempts to access memory are made at all.
*
* @pre dest_buffer must be at least size bytes in length, otherwise a
* buffer overrun will occur.
*
* @post The range [dest_buffer, size) contains the read bytes from the
* current process' address space.
*/
void ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size);
/**
* Writes a range of bytes into a given process' address space at the specified
* virtual address.
*
* @param process The process to write data into the address space of.
* @param dest_addr The destination virtual address to begin writing the data at.
* @param src_buffer The data to write into the process' address space.
* @param size The size of the data to write, in bytes.
*
* @post The address range [dest_addr, size) in the process' address space
* contains the data that was within src_buffer.
*
* @post If an attempt is made to write into an unmapped region of memory, the writes
* will be ignored and an error will be logged.
*
* @post If a write is performed into a region of memory that is considered cached
* rasterizer memory, will cause the currently active rasterizer to be notified
* and will mark that region as invalidated to caches that the active
* graphics backend may be maintaining over the course of execution.
*/
void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer, void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
std::size_t size); std::size_t size);
/**
* Writes a range of bytes into a given process' address space at the specified
* virtual address.
*
* @param dest_addr The destination virtual address to begin writing the data at.
* @param src_buffer The data to write into the process' address space.
* @param size The size of the data to write, in bytes.
*
* @post The address range [dest_addr, size) in the process' address space
* contains the data that was within src_buffer.
*
* @post If an attempt is made to write into an unmapped region of memory, the writes
* will be ignored and an error will be logged.
*
* @post If a write is performed into a region of memory that is considered cached
* rasterizer memory, will cause the currently active rasterizer to be notified
* and will mark that region as invalidated to caches that the active
* graphics backend may be maintaining over the course of execution.
*/
void WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size);
/**
* Zeros a range of bytes within the current process' address space at the specified
* virtual address.
*
* @param process The process that will have data zeroed within its address space.
* @param dest_addr The destination virtual address to zero the data from.
* @param size The size of the range to zero out, in bytes.
*
* @post The range [dest_addr, size) within the process' address space contains the
* value 0.
*/
void ZeroBlock(const Kernel::Process& process, VAddr dest_addr, const std::size_t size); void ZeroBlock(const Kernel::Process& process, VAddr dest_addr, const std::size_t size);
/**
* Copies data within a process' address space to another location within the
* same address space.
*
* @param process The process that will have data copied within its address space.
* @param dest_addr The destination virtual address to begin copying the data into.
* @param src_addr The source virtual address to begin copying the data from.
* @param size The size of the data to copy, in bytes.
*
* @post The range [dest_addr, size) within the process' address space contains the
* same data within the range [src_addr, size).
*/
void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr,
std::size_t size); std::size_t size);
void CopyBlock(const Kernel::Process& dest_process, const Kernel::Process& src_process, void CopyBlock(const Kernel::Process& dest_process, const Kernel::Process& src_process,
VAddr dest_addr, VAddr src_addr, std::size_t size); VAddr dest_addr, VAddr src_addr, std::size_t size);
std::string ReadCString(VAddr vaddr, std::size_t max_length); /**
* Marks each page within the specified address range as cached or uncached.
*
* @param vaddr The virtual address indicating the start of the address range.
* @param size The size of the address range in bytes.
* @param cached Whether or not any pages within the address range should be
* marked as cached or uncached.
*/
void RasterizerMarkRegionCached(PAddr start, u32 size, bool cached);
/// Gets a pointer to the memory region beginning at the specified physical address. /// Gets a pointer to the memory region beginning at the specified physical address.
u8* GetPhysicalPointer(PAddr address); u8* GetPhysicalPointer(PAddr address);
/// Gets a pointer to the memory region beginning at the specified physical address. /// Returns a reference to the memory region beginning at the specified physical address
const u8* GetPhysicalPointer(PAddr address) const;
MemoryRef GetPhysicalRef(PAddr address) const; MemoryRef GetPhysicalRef(PAddr address) const;
u8* GetPointer(VAddr vaddr); /// Determines if the given VAddr is valid for the specified process.
const u8* GetPointer(VAddr vaddr) const; bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr);
/// Returns true if the address refers to a valid memory region
bool IsValidPhysicalAddress(PAddr paddr) const; bool IsValidPhysicalAddress(PAddr paddr) const;
/// Gets offset in FCRAM from a pointer inside FCRAM range /// Gets offset in FCRAM from a pointer inside FCRAM range
@ -381,11 +594,6 @@ public:
/// Gets a serializable ref to FCRAM with the given offset /// Gets a serializable ref to FCRAM with the given offset
MemoryRef GetFCRAMRef(std::size_t offset) const; MemoryRef GetFCRAMRef(std::size_t offset) const;
/**
* Mark each page touching the region as cached.
*/
void RasterizerMarkRegionCached(PAddr start, u32 size, bool cached);
/// Registers page table for rasterizer cache marking /// Registers page table for rasterizer cache marking
void RegisterPageTable(std::shared_ptr<PageTable> page_table); void RegisterPageTable(std::shared_ptr<PageTable> page_table);
@ -415,7 +623,6 @@ private:
void MapPages(PageTable& page_table, u32 base, u32 size, MemoryRef memory, PageType type); void MapPages(PageTable& page_table, u32 base, u32 size, MemoryRef memory, PageType type);
class Impl; class Impl;
std::unique_ptr<Impl> impl; std::unique_ptr<Impl> impl;
friend class boost::serialization::access; friend class boost::serialization::access;
@ -427,9 +634,6 @@ public:
class BackingMemImpl; class BackingMemImpl;
}; };
/// Determines if the given VAddr is valid for the specified process.
bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr);
} // namespace Memory } // namespace Memory
BOOST_CLASS_EXPORT_KEY(Memory::MemorySystem::BackingMemImpl<Memory::Region::FCRAM>) BOOST_CLASS_EXPORT_KEY(Memory::MemorySystem::BackingMemImpl<Memory::Region::FCRAM>)

View File

@ -22,7 +22,6 @@ namespace Settings {
Values values = {}; Values values = {};
void Apply() { void Apply() {
GDBStub::SetServerPort(values.gdbstub_port); GDBStub::SetServerPort(values.gdbstub_port);
GDBStub::ToggleServer(values.use_gdbstub); GDBStub::ToggleServer(values.use_gdbstub);

View File

@ -137,7 +137,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
} }
SECTION("translates StaticBuffer descriptors") { SECTION("translates StaticBuffer descriptors") {
auto mem = std::make_shared<BufferMem>(Memory::PAGE_SIZE); auto mem = std::make_shared<BufferMem>(Memory::CITRA_PAGE_SIZE);
MemoryRef buffer{mem}; MemoryRef buffer{mem};
std::fill(buffer.GetPtr(), buffer.GetPtr() + buffer.GetSize(), 0xAB); std::fill(buffer.GetPtr(), buffer.GetPtr() + buffer.GetSize(), 0xAB);
@ -161,7 +161,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
} }
SECTION("translates MappedBuffer descriptors") { SECTION("translates MappedBuffer descriptors") {
auto mem = std::make_shared<BufferMem>(Memory::PAGE_SIZE); auto mem = std::make_shared<BufferMem>(Memory::CITRA_PAGE_SIZE);
MemoryRef buffer{mem}; MemoryRef buffer{mem};
std::fill(buffer.GetPtr(), buffer.GetPtr() + buffer.GetSize(), 0xCD); std::fill(buffer.GetPtr(), buffer.GetPtr() + buffer.GetSize(), 0xCD);
@ -187,11 +187,11 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
} }
SECTION("translates mixed params") { SECTION("translates mixed params") {
auto mem_static = std::make_shared<BufferMem>(Memory::PAGE_SIZE); auto mem_static = std::make_shared<BufferMem>(Memory::CITRA_PAGE_SIZE);
MemoryRef buffer_static{mem_static}; MemoryRef buffer_static{mem_static};
std::fill(buffer_static.GetPtr(), buffer_static.GetPtr() + buffer_static.GetSize(), 0xCE); std::fill(buffer_static.GetPtr(), buffer_static.GetPtr() + buffer_static.GetSize(), 0xCE);
auto mem_mapped = std::make_shared<BufferMem>(Memory::PAGE_SIZE); auto mem_mapped = std::make_shared<BufferMem>(Memory::CITRA_PAGE_SIZE);
MemoryRef buffer_mapped{mem_mapped}; MemoryRef buffer_mapped{mem_mapped};
std::fill(buffer_mapped.GetPtr(), buffer_mapped.GetPtr() + buffer_mapped.GetSize(), 0xDF); std::fill(buffer_mapped.GetPtr(), buffer_mapped.GetPtr() + buffer_mapped.GetSize(), 0xDF);
@ -321,12 +321,12 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
} }
SECTION("translates StaticBuffer descriptors") { SECTION("translates StaticBuffer descriptors") {
std::vector<u8> input_buffer(Memory::PAGE_SIZE); std::vector<u8> input_buffer(Memory::CITRA_PAGE_SIZE);
std::fill(input_buffer.begin(), input_buffer.end(), 0xAB); std::fill(input_buffer.begin(), input_buffer.end(), 0xAB);
context.AddStaticBuffer(0, input_buffer); context.AddStaticBuffer(0, input_buffer);
auto output_mem = std::make_shared<BufferMem>(Memory::PAGE_SIZE); auto output_mem = std::make_shared<BufferMem>(Memory::CITRA_PAGE_SIZE);
MemoryRef output_buffer{output_mem}; MemoryRef output_buffer{output_mem};
VAddr target_address = 0x10000000; VAddr target_address = 0x10000000;
@ -355,10 +355,10 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
} }
SECTION("translates StaticBuffer descriptors") { SECTION("translates StaticBuffer descriptors") {
std::vector<u8> input_buffer(Memory::PAGE_SIZE); std::vector<u8> input_buffer(Memory::CITRA_PAGE_SIZE);
std::fill(input_buffer.begin(), input_buffer.end(), 0xAB); std::fill(input_buffer.begin(), input_buffer.end(), 0xAB);
auto output_mem = std::make_shared<BufferMem>(Memory::PAGE_SIZE); auto output_mem = std::make_shared<BufferMem>(Memory::CITRA_PAGE_SIZE);
MemoryRef output_buffer{output_mem}; MemoryRef output_buffer{output_mem};
VAddr target_address = 0x10000000; VAddr target_address = 0x10000000;

View File

@ -3,34 +3,31 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <catch2/catch_test_macros.hpp> #include <catch2/catch_test_macros.hpp>
#include "core/core.h"
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/hle/kernel/memory.h"
#include "core/hle/kernel/process.h" #include "core/hle/kernel/process.h"
#include "core/hle/kernel/shared_page.h"
#include "core/memory.h" #include "core/memory.h"
TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") { TEST_CASE("memory.IsValidVirtualAddress", "[core][memory]") {
Core::Timing timing(1, 100); Core::Timing timing(1, 100);
Memory::MemorySystem memory; Memory::MemorySystem memory;
Kernel::KernelSystem kernel( Kernel::KernelSystem kernel(
memory, timing, [] {}, 0, 1, 0); memory, timing, [] {}, 0, 1, 0);
SECTION("these regions should not be mapped on an empty process") { SECTION("these regions should not be mapped on an empty process") {
auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0)); auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0));
CHECK(Memory::IsValidVirtualAddress(*process, Memory::PROCESS_IMAGE_VADDR) == false); CHECK(memory.IsValidVirtualAddress(*process, Memory::PROCESS_IMAGE_VADDR) == false);
CHECK(Memory::IsValidVirtualAddress(*process, Memory::HEAP_VADDR) == false); CHECK(memory.IsValidVirtualAddress(*process, Memory::HEAP_VADDR) == false);
CHECK(Memory::IsValidVirtualAddress(*process, Memory::LINEAR_HEAP_VADDR) == false); CHECK(memory.IsValidVirtualAddress(*process, Memory::LINEAR_HEAP_VADDR) == false);
CHECK(Memory::IsValidVirtualAddress(*process, Memory::VRAM_VADDR) == false); CHECK(memory.IsValidVirtualAddress(*process, Memory::VRAM_VADDR) == false);
CHECK(Memory::IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == false); CHECK(memory.IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == false);
CHECK(Memory::IsValidVirtualAddress(*process, Memory::SHARED_PAGE_VADDR) == false); CHECK(memory.IsValidVirtualAddress(*process, Memory::SHARED_PAGE_VADDR) == false);
CHECK(Memory::IsValidVirtualAddress(*process, Memory::TLS_AREA_VADDR) == false); CHECK(memory.IsValidVirtualAddress(*process, Memory::TLS_AREA_VADDR) == false);
} }
SECTION("CONFIG_MEMORY_VADDR and SHARED_PAGE_VADDR should be valid after mapping them") { SECTION("CONFIG_MEMORY_VADDR and SHARED_PAGE_VADDR should be valid after mapping them") {
auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0)); auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0));
kernel.MapSharedPages(process->vm_manager); kernel.MapSharedPages(process->vm_manager);
CHECK(Memory::IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == true); CHECK(memory.IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == true);
CHECK(Memory::IsValidVirtualAddress(*process, Memory::SHARED_PAGE_VADDR) == true); CHECK(memory.IsValidVirtualAddress(*process, Memory::SHARED_PAGE_VADDR) == true);
} }
SECTION("special regions should be valid after mapping them") { SECTION("special regions should be valid after mapping them") {
@ -38,13 +35,13 @@ TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") {
SECTION("VRAM") { SECTION("VRAM") {
kernel.HandleSpecialMapping(process->vm_manager, kernel.HandleSpecialMapping(process->vm_manager,
{Memory::VRAM_VADDR, Memory::VRAM_SIZE, false, false}); {Memory::VRAM_VADDR, Memory::VRAM_SIZE, false, false});
CHECK(Memory::IsValidVirtualAddress(*process, Memory::VRAM_VADDR) == true); CHECK(memory.IsValidVirtualAddress(*process, Memory::VRAM_VADDR) == true);
} }
SECTION("IO (Not yet implemented)") { SECTION("IO (Not yet implemented)") {
kernel.HandleSpecialMapping( kernel.HandleSpecialMapping(
process->vm_manager, {Memory::IO_AREA_VADDR, Memory::IO_AREA_SIZE, false, false}); process->vm_manager, {Memory::IO_AREA_VADDR, Memory::IO_AREA_SIZE, false, false});
CHECK_FALSE(Memory::IsValidVirtualAddress(*process, Memory::IO_AREA_VADDR) == true); CHECK_FALSE(memory.IsValidVirtualAddress(*process, Memory::IO_AREA_VADDR) == true);
} }
} }
@ -52,6 +49,6 @@ TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") {
auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0)); auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0));
kernel.MapSharedPages(process->vm_manager); kernel.MapSharedPages(process->vm_manager);
process->vm_manager.UnmapRange(Memory::CONFIG_MEMORY_VADDR, Memory::CONFIG_MEMORY_SIZE); process->vm_manager.UnmapRange(Memory::CONFIG_MEMORY_VADDR, Memory::CONFIG_MEMORY_SIZE);
CHECK(Memory::IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == false); CHECK(memory.IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == false);
} }
} }

View File

@ -10,7 +10,7 @@
#include "core/memory.h" #include "core/memory.h"
TEST_CASE("Memory Basics", "[kernel][memory]") { TEST_CASE("Memory Basics", "[kernel][memory]") {
auto mem = std::make_shared<BufferMem>(Memory::PAGE_SIZE); auto mem = std::make_shared<BufferMem>(Memory::CITRA_PAGE_SIZE);
MemoryRef block{mem}; MemoryRef block{mem};
Memory::MemorySystem memory; Memory::MemorySystem memory;
SECTION("mapping memory") { SECTION("mapping memory") {

View File

@ -255,7 +255,7 @@ public:
} }
private: private:
const Regs& regs; [[maybe_unused]] const Regs& regs;
Shader::ShaderSetup& setup; Shader::ShaderSetup& setup;
Common::Vec4<float24>* buffer_begin; Common::Vec4<float24>* buffer_begin;
Common::Vec4<float24>* buffer_cur; Common::Vec4<float24>* buffer_cur;

View File

@ -28,7 +28,7 @@ public:
* @note All methods in this class are called from the GSP thread * @note All methods in this class are called from the GSP thread
*/ */
virtual void GXCommandProcessed(int total_command_count) { virtual void GXCommandProcessed(int total_command_count) {
const Service::GSP::Command& cmd = [[maybe_unused]] const Service::GSP::Command& cmd =
observed->ReadGXCommandHistory(total_command_count - 1); observed->ReadGXCommandHistory(total_command_count - 1);
LOG_TRACE(Debug_GPU, "Received command: id={:x}", (int)cmd.id.Value()); LOG_TRACE(Debug_GPU, "Received command: id={:x}", (int)cmd.id.Value());
} }

View File

@ -44,7 +44,8 @@ CachedSurface::~CachedSurface() {
} }
} }
MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 192, 64)); MICROPROFILE_DEFINE(RasterizerCache_SurfaceLoad, "RasterizerCache", "Surface Load",
MP_RGB(128, 192, 64));
void CachedSurface::LoadGLBuffer(PAddr load_start, PAddr load_end) { void CachedSurface::LoadGLBuffer(PAddr load_start, PAddr load_end) {
ASSERT(type != SurfaceType::Fill); ASSERT(type != SurfaceType::Fill);
const bool need_swap = const bool need_swap =
@ -65,7 +66,7 @@ void CachedSurface::LoadGLBuffer(PAddr load_start, PAddr load_end) {
if (load_start < Memory::VRAM_VADDR && load_end > Memory::VRAM_VADDR) if (load_start < Memory::VRAM_VADDR && load_end > Memory::VRAM_VADDR)
load_start = Memory::VRAM_VADDR; load_start = Memory::VRAM_VADDR;
MICROPROFILE_SCOPE(OpenGL_SurfaceLoad); MICROPROFILE_SCOPE(RasterizerCache_SurfaceLoad);
ASSERT(load_start >= addr && load_end <= end); ASSERT(load_start >= addr && load_end <= end);
const u32 start_offset = load_start - addr; const u32 start_offset = load_start - addr;
@ -121,7 +122,8 @@ void CachedSurface::LoadGLBuffer(PAddr load_start, PAddr load_end) {
} }
} }
MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64)); MICROPROFILE_DEFINE(RasterizerCache_SurfaceFlush, "RasterizerCache", "Surface Flush",
MP_RGB(128, 192, 64));
void CachedSurface::FlushGLBuffer(PAddr flush_start, PAddr flush_end) { void CachedSurface::FlushGLBuffer(PAddr flush_start, PAddr flush_end) {
u8* const dst_buffer = VideoCore::g_memory->GetPhysicalPointer(addr); u8* const dst_buffer = VideoCore::g_memory->GetPhysicalPointer(addr);
if (dst_buffer == nullptr) if (dst_buffer == nullptr)
@ -137,7 +139,7 @@ void CachedSurface::FlushGLBuffer(PAddr flush_start, PAddr flush_end) {
if (flush_start < Memory::VRAM_VADDR && flush_end > Memory::VRAM_VADDR) if (flush_start < Memory::VRAM_VADDR && flush_end > Memory::VRAM_VADDR)
flush_start = Memory::VRAM_VADDR; flush_start = Memory::VRAM_VADDR;
MICROPROFILE_SCOPE(OpenGL_SurfaceFlush); MICROPROFILE_SCOPE(RasterizerCache_SurfaceFlush);
ASSERT(flush_start >= addr && flush_end <= end); ASSERT(flush_start >= addr && flush_end <= end);
const u32 start_offset = flush_start - addr; const u32 start_offset = flush_start - addr;
@ -270,13 +272,14 @@ void CachedSurface::DumpTexture(GLuint target_tex, u64 tex_hash) {
} }
} }
MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 192, 64)); MICROPROFILE_DEFINE(RasterizerCache_TextureUL, "RasterizerCache", "Texture Upload",
MP_RGB(128, 192, 64));
void CachedSurface::UploadGLTexture(Common::Rectangle<u32> rect) { void CachedSurface::UploadGLTexture(Common::Rectangle<u32> rect) {
if (type == SurfaceType::Fill) { if (type == SurfaceType::Fill) {
return; return;
} }
MICROPROFILE_SCOPE(OpenGL_TextureUL); MICROPROFILE_SCOPE(RasterizerCache_TextureUL);
ASSERT(gl_buffer.size() == width * height * GetBytesPerPixel(pixel_format)); ASSERT(gl_buffer.size() == width * height * GetBytesPerPixel(pixel_format));
u64 tex_hash = 0; u64 tex_hash = 0;
@ -374,13 +377,14 @@ void CachedSurface::UploadGLTexture(Common::Rectangle<u32> rect) {
InvalidateAllWatcher(); InvalidateAllWatcher();
} }
MICROPROFILE_DEFINE(OpenGL_TextureDL, "OpenGL", "Texture Download", MP_RGB(128, 192, 64)); MICROPROFILE_DEFINE(RasterizerCache_TextureDL, "RasterizerCache", "Texture Download",
MP_RGB(128, 192, 64));
void CachedSurface::DownloadGLTexture(const Common::Rectangle<u32>& rect) { void CachedSurface::DownloadGLTexture(const Common::Rectangle<u32>& rect) {
if (type == SurfaceType::Fill) { if (type == SurfaceType::Fill) {
return; return;
} }
MICROPROFILE_SCOPE(OpenGL_TextureDL); MICROPROFILE_SCOPE(RasterizerCache_TextureDL);
if (gl_buffer.empty()) { if (gl_buffer.empty()) {
gl_buffer.resize(width * height * GetBytesPerPixel(pixel_format)); gl_buffer.resize(width * height * GetBytesPerPixel(pixel_format));

View File

@ -93,10 +93,11 @@ OGLTexture RasterizerCacheOpenGL::AllocateSurfaceTexture(const FormatTuple& tupl
return texture; return texture;
} }
MICROPROFILE_DEFINE(OpenGL_CopySurface, "OpenGL", "CopySurface", MP_RGB(128, 192, 64)); MICROPROFILE_DEFINE(RasterizerCache_CopySurface, "RasterizerCache", "CopySurface",
MP_RGB(128, 192, 64));
void RasterizerCacheOpenGL::CopySurface(const Surface& src_surface, const Surface& dst_surface, void RasterizerCacheOpenGL::CopySurface(const Surface& src_surface, const Surface& dst_surface,
SurfaceInterval copy_interval) { SurfaceInterval copy_interval) {
MICROPROFILE_SCOPE(OpenGL_CopySurface); MICROPROFILE_SCOPE(RasterizerCache_CopySurface);
SurfaceParams subrect_params = dst_surface->FromInterval(copy_interval); SurfaceParams subrect_params = dst_surface->FromInterval(copy_interval);
ASSERT(subrect_params.GetInterval() == copy_interval); ASSERT(subrect_params.GetInterval() == copy_interval);
@ -253,12 +254,13 @@ RasterizerCacheOpenGL::~RasterizerCacheOpenGL() {
#endif #endif
} }
MICROPROFILE_DEFINE(OpenGL_BlitSurface, "OpenGL", "BlitSurface", MP_RGB(128, 192, 64)); MICROPROFILE_DEFINE(RasterizerCache_BlitSurface, "RasterizerCache", "BlitSurface",
MP_RGB(128, 192, 64));
bool RasterizerCacheOpenGL::BlitSurfaces(const Surface& src_surface, bool RasterizerCacheOpenGL::BlitSurfaces(const Surface& src_surface,
const Common::Rectangle<u32>& src_rect, const Common::Rectangle<u32>& src_rect,
const Surface& dst_surface, const Surface& dst_surface,
const Common::Rectangle<u32>& dst_rect) { const Common::Rectangle<u32>& dst_rect) {
MICROPROFILE_SCOPE(OpenGL_BlitSurface); MICROPROFILE_SCOPE(RasterizerCache_BlitSurface);
if (CheckFormatsBlittable(src_surface->pixel_format, dst_surface->pixel_format)) { if (CheckFormatsBlittable(src_surface->pixel_format, dst_surface->pixel_format)) {
dst_surface->InvalidateAllWatcher(); dst_surface->InvalidateAllWatcher();
@ -917,8 +919,8 @@ void RasterizerCacheOpenGL::ClearAll(bool flush) {
for (auto& pair : RangeFromInterval(cached_pages, flush_interval)) { for (auto& pair : RangeFromInterval(cached_pages, flush_interval)) {
const auto interval = pair.first & flush_interval; const auto interval = pair.first & flush_interval;
const PAddr interval_start_addr = boost::icl::first(interval) << Memory::PAGE_BITS; const PAddr interval_start_addr = boost::icl::first(interval) << Memory::CITRA_PAGE_BITS;
const PAddr interval_end_addr = boost::icl::last_next(interval) << Memory::PAGE_BITS; const PAddr interval_end_addr = boost::icl::last_next(interval) << Memory::CITRA_PAGE_BITS;
const u32 interval_size = interval_end_addr - interval_start_addr; const u32 interval_size = interval_end_addr - interval_start_addr;
VideoCore::g_memory->RasterizerMarkRegionCached(interval_start_addr, interval_size, false); VideoCore::g_memory->RasterizerMarkRegionCached(interval_start_addr, interval_size, false);
@ -1069,8 +1071,8 @@ void RasterizerCacheOpenGL::UnregisterSurface(const Surface& surface) {
void RasterizerCacheOpenGL::UpdatePagesCachedCount(PAddr addr, u32 size, int delta) { void RasterizerCacheOpenGL::UpdatePagesCachedCount(PAddr addr, u32 size, int delta) {
const u32 num_pages = const u32 num_pages =
((addr + size - 1) >> Memory::PAGE_BITS) - (addr >> Memory::PAGE_BITS) + 1; ((addr + size - 1) >> Memory::CITRA_PAGE_BITS) - (addr >> Memory::CITRA_PAGE_BITS) + 1;
const u32 page_start = addr >> Memory::PAGE_BITS; const u32 page_start = addr >> Memory::CITRA_PAGE_BITS;
const u32 page_end = page_start + num_pages; const u32 page_end = page_start + num_pages;
// Interval maps will erase segments if count reaches 0, so if delta is negative we have to // Interval maps will erase segments if count reaches 0, so if delta is negative we have to
@ -1083,8 +1085,8 @@ void RasterizerCacheOpenGL::UpdatePagesCachedCount(PAddr addr, u32 size, int del
const auto interval = pair.first & pages_interval; const auto interval = pair.first & pages_interval;
const int count = pair.second; const int count = pair.second;
const PAddr interval_start_addr = boost::icl::first(interval) << Memory::PAGE_BITS; const PAddr interval_start_addr = boost::icl::first(interval) << Memory::CITRA_PAGE_BITS;
const PAddr interval_end_addr = boost::icl::last_next(interval) << Memory::PAGE_BITS; const PAddr interval_end_addr = boost::icl::last_next(interval) << Memory::CITRA_PAGE_BITS;
const u32 interval_size = interval_end_addr - interval_start_addr; const u32 interval_size = interval_end_addr - interval_start_addr;
if (delta > 0 && count == delta) if (delta > 0 && count == delta)

View File

@ -274,9 +274,11 @@ struct FramebufferRegs {
case DepthFormat::D24: case DepthFormat::D24:
case DepthFormat::D24S8: case DepthFormat::D24S8:
return 24; return 24;
default:
UNREACHABLE_MSG("Unknown depth format {}", format);
} }
ASSERT_MSG(false, "Unknown depth format {}", format); return 0;
} }
INSERT_PADDING_WORDS(0x10); // Gas related registers INSERT_PADDING_WORDS(0x10); // Gas related registers

View File

@ -129,6 +129,8 @@ struct LightingRegs {
"ReflectBlue, instead got %i", "ReflectBlue, instead got %i",
config); config);
} }
return false;
} }
struct LightSrc { struct LightSrc {

View File

@ -428,6 +428,8 @@ static GLenum GetCurrentPrimitiveMode() {
default: default:
UNREACHABLE(); UNREACHABLE();
} }
return GL_TRIANGLES;
} }
bool RasterizerOpenGL::AccelerateDrawBatchInternal(bool is_indexed) { bool RasterizerOpenGL::AccelerateDrawBatchInternal(bool is_indexed) {

View File

@ -89,7 +89,7 @@ void OGLTexture::CopyFrom(const OGLTexture& other, GLenum target, GLsizei levels
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, handle); glBindTexture(GL_TEXTURE_2D, handle);
for (u32 level = 0; level < levels; level++) { for (GLsizei level = 0; level < levels; level++) {
glCopyImageSubData(other.handle, target, level, 0, 0, 0, handle, target, level, 0, 0, 0, glCopyImageSubData(other.handle, target, level, 0, 0, 0, handle, target, level, 0, 0, 0,
width >> level, height >> level, 1); width >> level, height >> level, 1);
} }

View File

@ -744,7 +744,7 @@ void RendererOpenGL::ReloadShader() {
void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
const GPU::Regs::FramebufferConfig& framebuffer) { const GPU::Regs::FramebufferConfig& framebuffer) {
GPU::Regs::PixelFormat format = framebuffer.color_format; GPU::Regs::PixelFormat format = framebuffer.color_format;
GLint internal_format; GLint internal_format{};
texture.format = format; texture.format = format;
texture.width = framebuffer.width; texture.width = framebuffer.width;

View File

@ -208,7 +208,7 @@ GLuint TextureDownloaderES::ConvertDepthToColor(GLuint level, GLenum& format, GL
void TextureDownloaderES::GetTexImage(GLenum target, GLuint level, GLenum format, GLenum type, void TextureDownloaderES::GetTexImage(GLenum target, GLuint level, GLenum format, GLenum type,
GLint height, GLint width, void* pixels) { GLint height, GLint width, void* pixels) {
OpenGLState state = OpenGLState::GetCurState(); OpenGLState state = OpenGLState::GetCurState();
GLuint texture; GLuint texture{};
const GLuint old_read_buffer = state.draw.read_framebuffer; const GLuint old_read_buffer = state.draw.read_framebuffer;
switch (target) { switch (target) {
case GL_TEXTURE_2D: case GL_TEXTURE_2D:

View File

@ -46,7 +46,7 @@ public:
} }
private: private:
float24 pos; [[maybe_unused]] float24 pos;
Common::Vec4<float24> coeffs; Common::Vec4<float24> coeffs;
Common::Vec4<float24> bias; Common::Vec4<float24> bias;
}; };