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