summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/core/file_sys/program_metadata.cpp27
-rw-r--r--src/core/file_sys/program_metadata.h2
-rw-r--r--src/core/file_sys/savedata_factory.cpp8
-rw-r--r--src/core/file_sys/savedata_factory.h11
-rw-r--r--src/core/hle/kernel/svc.cpp14
-rw-r--r--src/core/hle/result.h4
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp19
-rw-r--r--src/core/hle/service/filesystem/filesystem.h2
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp19
-rw-r--r--src/video_core/macro_interpreter.cpp20
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp31
-rw-r--r--src/yuzu/debugger/graphics/graphics_surface.cpp206
12 files changed, 221 insertions, 142 deletions
diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp
index d3e00437f..d863253f8 100644
--- a/src/core/file_sys/program_metadata.cpp
+++ b/src/core/file_sys/program_metadata.cpp
@@ -3,7 +3,6 @@
// Refer to the license.txt file included.
#include <cstddef>
-#include <cstring>
#include <vector>
#include "common/logging/log.h"
@@ -17,28 +16,30 @@ ProgramMetadata::ProgramMetadata() = default;
ProgramMetadata::~ProgramMetadata() = default;
Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) {
- std::size_t total_size = static_cast<std::size_t>(file->GetSize());
- if (total_size < sizeof(Header))
+ const std::size_t total_size = file->GetSize();
+ if (total_size < sizeof(Header)) {
return Loader::ResultStatus::ErrorBadNPDMHeader;
+ }
- // TODO(DarkLordZach): Use ReadObject when Header/AcidHeader becomes trivially copyable.
- std::vector<u8> npdm_header_data = file->ReadBytes(sizeof(Header));
- if (sizeof(Header) != npdm_header_data.size())
+ if (sizeof(Header) != file->ReadObject(&npdm_header)) {
return Loader::ResultStatus::ErrorBadNPDMHeader;
- std::memcpy(&npdm_header, npdm_header_data.data(), sizeof(Header));
+ }
- std::vector<u8> acid_header_data = file->ReadBytes(sizeof(AcidHeader), npdm_header.acid_offset);
- if (sizeof(AcidHeader) != acid_header_data.size())
+ if (sizeof(AcidHeader) != file->ReadObject(&acid_header, npdm_header.acid_offset)) {
return Loader::ResultStatus::ErrorBadACIDHeader;
- std::memcpy(&acid_header, acid_header_data.data(), sizeof(AcidHeader));
+ }
- if (sizeof(AciHeader) != file->ReadObject(&aci_header, npdm_header.aci_offset))
+ if (sizeof(AciHeader) != file->ReadObject(&aci_header, npdm_header.aci_offset)) {
return Loader::ResultStatus::ErrorBadACIHeader;
+ }
- if (sizeof(FileAccessControl) != file->ReadObject(&acid_file_access, acid_header.fac_offset))
+ if (sizeof(FileAccessControl) != file->ReadObject(&acid_file_access, acid_header.fac_offset)) {
return Loader::ResultStatus::ErrorBadFileAccessControl;
- if (sizeof(FileAccessHeader) != file->ReadObject(&aci_file_access, aci_header.fah_offset))
+ }
+
+ if (sizeof(FileAccessHeader) != file->ReadObject(&aci_file_access, aci_header.fah_offset)) {
return Loader::ResultStatus::ErrorBadFileAccessHeader;
+ }
aci_kernel_capabilities.resize(aci_header.kac_size / sizeof(u32));
const u64 read_size = aci_header.kac_size;
diff --git a/src/core/file_sys/program_metadata.h b/src/core/file_sys/program_metadata.h
index 0033ba347..7de5b9cf9 100644
--- a/src/core/file_sys/program_metadata.h
+++ b/src/core/file_sys/program_metadata.h
@@ -58,7 +58,6 @@ public:
void Print() const;
private:
- // TODO(DarkLordZach): BitField is not trivially copyable.
struct Header {
std::array<char, 4> magic;
std::array<u8, 8> reserved;
@@ -85,7 +84,6 @@ private:
static_assert(sizeof(Header) == 0x80, "NPDM header structure size is wrong");
- // TODO(DarkLordZach): BitField is not trivially copyable.
struct AcidHeader {
std::array<u8, 0x100> signature;
std::array<u8, 0x100> nca_modulus;
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp
index 1913dc956..7974b031d 100644
--- a/src/core/file_sys/savedata_factory.cpp
+++ b/src/core/file_sys/savedata_factory.cpp
@@ -16,8 +16,10 @@ namespace FileSys {
constexpr char SAVE_DATA_SIZE_FILENAME[] = ".yuzu_save_size";
std::string SaveDataDescriptor::DebugInfo() const {
- return fmt::format("[type={:02X}, title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}]",
- static_cast<u8>(type), title_id, user_id[1], user_id[0], save_id);
+ return fmt::format("[type={:02X}, title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}, "
+ "rank={}, index={}]",
+ static_cast<u8>(type), title_id, user_id[1], user_id[0], save_id,
+ static_cast<u8>(rank), index);
}
SaveDataFactory::SaveDataFactory(VirtualDir save_directory) : dir(std::move(save_directory)) {
@@ -28,7 +30,7 @@ SaveDataFactory::SaveDataFactory(VirtualDir save_directory) : dir(std::move(save
SaveDataFactory::~SaveDataFactory() = default;
-ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, SaveDataDescriptor meta) {
+ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataDescriptor& meta) {
if (meta.type == SaveDataType::SystemSaveData || meta.type == SaveDataType::SaveData) {
if (meta.zero_1 != 0) {
LOG_WARNING(Service_FS,
diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h
index 3a1caf292..b73654571 100644
--- a/src/core/file_sys/savedata_factory.h
+++ b/src/core/file_sys/savedata_factory.h
@@ -32,12 +32,19 @@ enum class SaveDataType : u8 {
CacheStorage = 5,
};
+enum class SaveDataRank : u8 {
+ Primary,
+ Secondary,
+};
+
struct SaveDataDescriptor {
u64_le title_id;
u128 user_id;
u64_le save_id;
SaveDataType type;
- INSERT_PADDING_BYTES(7);
+ SaveDataRank rank;
+ u16_le index;
+ INSERT_PADDING_BYTES(4);
u64_le zero_1;
u64_le zero_2;
u64_le zero_3;
@@ -57,7 +64,7 @@ public:
explicit SaveDataFactory(VirtualDir dir);
~SaveDataFactory();
- ResultVal<VirtualDir> Open(SaveDataSpaceId space, SaveDataDescriptor meta);
+ ResultVal<VirtualDir> Open(SaveDataSpaceId space, const SaveDataDescriptor& meta);
VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const;
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index ab10db3df..2fd07ab34 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -1339,6 +1339,20 @@ static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_var
"called mutex_addr={:X}, condition_variable_addr={:X}, thread_handle=0x{:08X}, timeout={}",
mutex_addr, condition_variable_addr, thread_handle, nano_seconds);
+ if (Memory::IsKernelVirtualAddress(mutex_addr)) {
+ LOG_ERROR(
+ Kernel_SVC,
+ "Given mutex address must not be within the kernel address space. address=0x{:016X}",
+ mutex_addr);
+ return ERR_INVALID_ADDRESS_STATE;
+ }
+
+ if (!Common::IsWordAligned(mutex_addr)) {
+ LOG_ERROR(Kernel_SVC, "Given mutex address must be word-aligned. address=0x{:016X}",
+ mutex_addr);
+ return ERR_INVALID_ADDRESS;
+ }
+
auto* const current_process = Core::System::GetInstance().Kernel().CurrentProcess();
const auto& handle_table = current_process->GetHandleTable();
SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index ab84f5ddc..8a3701151 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -119,10 +119,6 @@ union ResultCode {
BitField<0, 9, ErrorModule> module;
BitField<9, 13, u32> description;
- // The last bit of `level` is checked by apps and the kernel to determine if a result code is an
- // error
- BitField<31, 1, u32> is_error;
-
constexpr explicit ResultCode(u32 raw) : raw(raw) {}
constexpr ResultCode(ErrorModule module_, u32 description_)
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index c6da2df43..4c2b371c3 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -197,13 +197,16 @@ ResultCode VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_pa
ResultVal<FileSys::VirtualFile> VfsDirectoryServiceWrapper::OpenFile(const std::string& path_,
FileSys::Mode mode) const {
- std::string path(FileUtil::SanitizePath(path_));
- auto npath = path;
- while (npath.size() > 0 && (npath[0] == '/' || npath[0] == '\\'))
- npath = npath.substr(1);
+ const std::string path(FileUtil::SanitizePath(path_));
+ std::string_view npath = path;
+ while (!npath.empty() && (npath[0] == '/' || npath[0] == '\\')) {
+ npath.remove_prefix(1);
+ }
+
auto file = backing->GetFileRelative(npath);
- if (file == nullptr)
+ if (file == nullptr) {
return FileSys::ERROR_PATH_NOT_FOUND;
+ }
if (mode == FileSys::Mode::Append) {
return MakeResult<FileSys::VirtualFile>(
@@ -319,15 +322,15 @@ ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId stora
}
ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
- FileSys::SaveDataDescriptor save_struct) {
+ const FileSys::SaveDataDescriptor& descriptor) {
LOG_TRACE(Service_FS, "Opening Save Data for space_id={:01X}, save_struct={}",
- static_cast<u8>(space), save_struct.DebugInfo());
+ static_cast<u8>(space), descriptor.DebugInfo());
if (save_data_factory == nullptr) {
return FileSys::ERROR_ENTITY_NOT_FOUND;
}
- return save_data_factory->Open(space, save_struct);
+ return save_data_factory->Open(space, descriptor);
}
ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space) {
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h
index 6fd5e7b23..7cfc0d902 100644
--- a/src/core/hle/service/filesystem/filesystem.h
+++ b/src/core/hle/service/filesystem/filesystem.h
@@ -46,7 +46,7 @@ ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess();
ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
FileSys::ContentRecordType type);
ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
- FileSys::SaveDataDescriptor save_struct);
+ const FileSys::SaveDataDescriptor& descriptor);
ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space);
ResultVal<FileSys::VirtualDir> OpenSDMC();
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index 592dce31a..657baddb8 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -604,7 +604,9 @@ private:
u64_le save_id;
u64_le title_id;
u64_le save_image_size;
- INSERT_PADDING_BYTES(0x28);
+ u16_le index;
+ FileSys::SaveDataRank rank;
+ INSERT_PADDING_BYTES(0x25);
};
static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size.");
@@ -767,16 +769,17 @@ void FSP_SRV::CreateSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
}
void FSP_SRV::OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto space_id = rp.PopRaw<FileSys::SaveDataSpaceId>();
- auto unk = rp.Pop<u32>();
- LOG_INFO(Service_FS, "called with unknown={:08X}", unk);
+ LOG_INFO(Service_FS, "called.");
- auto save_struct = rp.PopRaw<FileSys::SaveDataDescriptor>();
+ struct Parameters {
+ FileSys::SaveDataSpaceId save_data_space_id;
+ FileSys::SaveDataDescriptor descriptor;
+ };
- auto dir = OpenSaveData(space_id, save_struct);
+ IPC::RequestParser rp{ctx};
+ const auto parameters = rp.PopRaw<Parameters>();
+ auto dir = OpenSaveData(parameters.save_data_space_id, parameters.descriptor);
if (dir.Failed()) {
IPC::ResponseBuilder rb{ctx, 2, 0, 0};
rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
diff --git a/src/video_core/macro_interpreter.cpp b/src/video_core/macro_interpreter.cpp
index 64f75db43..524d9ea5a 100644
--- a/src/video_core/macro_interpreter.cpp
+++ b/src/video_core/macro_interpreter.cpp
@@ -223,27 +223,21 @@ void MacroInterpreter::ProcessResult(ResultOperation operation, u32 reg, u32 res
}
u32 MacroInterpreter::FetchParameter() {
- ASSERT(next_parameter_index < parameters.size());
- return parameters[next_parameter_index++];
+ return parameters.at(next_parameter_index++);
}
u32 MacroInterpreter::GetRegister(u32 register_id) const {
- // Register 0 is supposed to always return 0.
- if (register_id == 0)
- return 0;
-
- ASSERT(register_id < registers.size());
- return registers[register_id];
+ return registers.at(register_id);
}
void MacroInterpreter::SetRegister(u32 register_id, u32 value) {
- // Register 0 is supposed to always return 0. NOP is implemented as a store to the zero
- // register.
- if (register_id == 0)
+ // Register 0 is hardwired as the zero register.
+ // Ensure no writes to it actually occur.
+ if (register_id == 0) {
return;
+ }
- ASSERT(register_id < registers.size());
- registers[register_id] = value;
+ registers.at(register_id) = value;
}
void MacroInterpreter::SetMethodAddress(u32 address) {
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 7300a4037..a1a51f226 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -69,10 +69,10 @@ public:
shader_source += '\n';
}
- std::string GenerateTemporal() {
- std::string temporal = "tmp";
- temporal += std::to_string(temporal_index++);
- return temporal;
+ std::string GenerateTemporary() {
+ std::string temporary = "tmp";
+ temporary += std::to_string(temporary_index++);
+ return temporary;
}
std::string GetResult() {
@@ -87,7 +87,7 @@ private:
}
std::string shader_source;
- u32 temporal_index = 1;
+ u32 temporary_index = 1;
};
/// Generates code to use for a swizzle operation.
@@ -426,9 +426,14 @@ private:
std::string Visit(Node node) {
if (const auto operation = std::get_if<OperationNode>(node)) {
const auto operation_index = static_cast<std::size_t>(operation->GetCode());
+ if (operation_index >= operation_decompilers.size()) {
+ UNREACHABLE_MSG("Out of bounds operation: {}", operation_index);
+ return {};
+ }
const auto decompiler = operation_decompilers[operation_index];
if (decompiler == nullptr) {
- UNREACHABLE_MSG("Operation decompiler {} not defined", operation_index);
+ UNREACHABLE_MSG("Undefined operation: {}", operation_index);
+ return {};
}
return (this->*decompiler)(*operation);
@@ -540,7 +545,7 @@ private:
} else if (std::holds_alternative<OperationNode>(*offset)) {
// Indirect access
- const std::string final_offset = code.GenerateTemporal();
+ const std::string final_offset = code.GenerateTemporary();
code.AddLine("uint " + final_offset + " = (ftou(" + Visit(offset) + ") / 4) & " +
std::to_string(MAX_CONSTBUFFER_ELEMENTS - 1) + ';');
return fmt::format("{}[{} / 4][{} % 4]", GetConstBuffer(cbuf->GetIndex()),
@@ -587,9 +592,9 @@ private:
// There's a bug in NVidia's proprietary drivers that makes precise fail on fragment shaders
const std::string precise = stage != ShaderStage::Fragment ? "precise " : "";
- const std::string temporal = code.GenerateTemporal();
- code.AddLine(precise + "float " + temporal + " = " + value + ';');
- return temporal;
+ const std::string temporary = code.GenerateTemporary();
+ code.AddLine(precise + "float " + temporary + " = " + value + ';');
+ return temporary;
}
std::string VisitOperand(Operation operation, std::size_t operand_index) {
@@ -601,9 +606,9 @@ private:
return Visit(operand);
}
- const std::string temporal = code.GenerateTemporal();
- code.AddLine("float " + temporal + " = " + Visit(operand) + ';');
- return temporal;
+ const std::string temporary = code.GenerateTemporary();
+ code.AddLine("float " + temporary + " = " + Visit(operand) + ';');
+ return temporary;
}
std::string VisitOperand(Operation operation, std::size_t operand_index, Type type) {
diff --git a/src/yuzu/debugger/graphics/graphics_surface.cpp b/src/yuzu/debugger/graphics/graphics_surface.cpp
index 11023ed63..f2d14becf 100644
--- a/src/yuzu/debugger/graphics/graphics_surface.cpp
+++ b/src/yuzu/debugger/graphics/graphics_surface.cpp
@@ -7,6 +7,7 @@
#include <QDebug>
#include <QFileDialog>
#include <QLabel>
+#include <QMessageBox>
#include <QMouseEvent>
#include <QPushButton>
#include <QScrollArea>
@@ -95,50 +96,91 @@ GraphicsSurfaceWidget::GraphicsSurfaceWidget(std::shared_ptr<Tegra::DebugContext
surface_picker_y_control = new QSpinBox;
surface_picker_y_control->setRange(0, max_dimension - 1);
- surface_format_control = new QComboBox;
-
+ // clang-format off
// Color formats sorted by Maxwell texture format index
- surface_format_control->addItem(tr("None"));
- surface_format_control->addItem(tr("Unknown"));
- surface_format_control->addItem(tr("Unknown"));
- surface_format_control->addItem(tr("Unknown"));
- surface_format_control->addItem(tr("Unknown"));
- surface_format_control->addItem(tr("Unknown"));
- surface_format_control->addItem(tr("Unknown"));
- surface_format_control->addItem(tr("Unknown"));
- surface_format_control->addItem(tr("A8R8G8B8"));
- surface_format_control->addItem(tr("Unknown"));
- surface_format_control->addItem(tr("Unknown"));
- surface_format_control->addItem(tr("Unknown"));
- surface_format_control->addItem(tr("Unknown"));
- surface_format_control->addItem(tr("Unknown"));
- surface_format_control->addItem(tr("Unknown"));
- surface_format_control->addItem(tr("Unknown"));
- surface_format_control->addItem(tr("Unknown"));
- surface_format_control->addItem(tr("Unknown"));
- surface_format_control->addItem(tr("Unknown"));
- surface_format_control->addItem(tr("Unknown"));
- surface_format_control->addItem(tr("Unknown"));
- surface_format_control->addItem(tr("Unknown"));
- surface_format_control->addItem(tr("Unknown"));
- surface_format_control->addItem(tr("Unknown"));
- surface_format_control->addItem(tr("Unknown"));
- surface_format_control->addItem(tr("Unknown"));
- surface_format_control->addItem(tr("Unknown"));
- surface_format_control->addItem(tr("Unknown"));
- surface_format_control->addItem(tr("Unknown"));
- surface_format_control->addItem(tr("Unknown"));
- surface_format_control->addItem(tr("Unknown"));
- surface_format_control->addItem(tr("Unknown"));
- surface_format_control->addItem(tr("Unknown"));
- surface_format_control->addItem(tr("Unknown"));
- surface_format_control->addItem(tr("Unknown"));
- surface_format_control->addItem(tr("Unknown"));
- surface_format_control->addItem(tr("DXT1"));
- surface_format_control->addItem(tr("DXT23"));
- surface_format_control->addItem(tr("DXT45"));
- surface_format_control->addItem(tr("DXN1"));
- surface_format_control->addItem(tr("DXN2"));
+ const QStringList surface_formats{
+ tr("None"),
+ QStringLiteral("R32_G32_B32_A32"),
+ QStringLiteral("R32_G32_B32"),
+ QStringLiteral("R16_G16_B16_A16"),
+ QStringLiteral("R32_G32"),
+ QStringLiteral("R32_B24G8"),
+ QStringLiteral("ETC2_RGB"),
+ QStringLiteral("X8B8G8R8"),
+ QStringLiteral("A8R8G8B8"),
+ QStringLiteral("A2B10G10R10"),
+ QStringLiteral("ETC2_RGB_PTA"),
+ QStringLiteral("ETC2_RGBA"),
+ QStringLiteral("R16_G16"),
+ QStringLiteral("G8R24"),
+ QStringLiteral("G24R8"),
+ QStringLiteral("R32"),
+ QStringLiteral("BC6H_SF16"),
+ QStringLiteral("BC6H_UF16"),
+ QStringLiteral("A4B4G4R4"),
+ QStringLiteral("A5B5G5R1"),
+ QStringLiteral("A1B5G5R5"),
+ QStringLiteral("B5G6R5"),
+ QStringLiteral("B6G5R5"),
+ QStringLiteral("BC7U"),
+ QStringLiteral("G8R8"),
+ QStringLiteral("EAC"),
+ QStringLiteral("EACX2"),
+ QStringLiteral("R16"),
+ QStringLiteral("Y8_VIDEO"),
+ QStringLiteral("R8"),
+ QStringLiteral("G4R4"),
+ QStringLiteral("R1"),
+ QStringLiteral("E5B9G9R9_SHAREDEXP"),
+ QStringLiteral("BF10GF11RF11"),
+ QStringLiteral("G8B8G8R8"),
+ QStringLiteral("B8G8R8G8"),
+ QStringLiteral("DXT1"),
+ QStringLiteral("DXT23"),
+ QStringLiteral("DXT45"),
+ QStringLiteral("DXN1"),
+ QStringLiteral("DXN2"),
+ QStringLiteral("Z24S8"),
+ QStringLiteral("X8Z24"),
+ QStringLiteral("S8Z24"),
+ QStringLiteral("X4V4Z24__COV4R4V"),
+ QStringLiteral("X4V4Z24__COV8R8V"),
+ QStringLiteral("V8Z24__COV4R12V"),
+ QStringLiteral("ZF32"),
+ QStringLiteral("ZF32_X24S8"),
+ QStringLiteral("X8Z24_X20V4S8__COV4R4V"),
+ QStringLiteral("X8Z24_X20V4S8__COV8R8V"),
+ QStringLiteral("ZF32_X20V4X8__COV4R4V"),
+ QStringLiteral("ZF32_X20V4X8__COV8R8V"),
+ QStringLiteral("ZF32_X20V4S8__COV4R4V"),
+ QStringLiteral("ZF32_X20V4S8__COV8R8V"),
+ QStringLiteral("X8Z24_X16V8S8__COV4R12V"),
+ QStringLiteral("ZF32_X16V8X8__COV4R12V"),
+ QStringLiteral("ZF32_X16V8S8__COV4R12V"),
+ QStringLiteral("Z16"),
+ QStringLiteral("V8Z24__COV8R24V"),
+ QStringLiteral("X8Z24_X16V8S8__COV8R24V"),
+ QStringLiteral("ZF32_X16V8X8__COV8R24V"),
+ QStringLiteral("ZF32_X16V8S8__COV8R24V"),
+ QStringLiteral("ASTC_2D_4X4"),
+ QStringLiteral("ASTC_2D_5X5"),
+ QStringLiteral("ASTC_2D_6X6"),
+ QStringLiteral("ASTC_2D_8X8"),
+ QStringLiteral("ASTC_2D_10X10"),
+ QStringLiteral("ASTC_2D_12X12"),
+ QStringLiteral("ASTC_2D_5X4"),
+ QStringLiteral("ASTC_2D_6X5"),
+ QStringLiteral("ASTC_2D_8X6"),
+ QStringLiteral("ASTC_2D_10X8"),
+ QStringLiteral("ASTC_2D_12X10"),
+ QStringLiteral("ASTC_2D_8X5"),
+ QStringLiteral("ASTC_2D_10X5"),
+ QStringLiteral("ASTC_2D_10X6"),
+ };
+ // clang-format on
+
+ surface_format_control = new QComboBox;
+ surface_format_control->addItems(surface_formats);
surface_info_label = new QLabel();
surface_info_label->setWordWrap(true);
@@ -157,22 +199,20 @@ GraphicsSurfaceWidget::GraphicsSurfaceWidget(std::shared_ptr<Tegra::DebugContext
// Connections
connect(this, &GraphicsSurfaceWidget::Update, this, &GraphicsSurfaceWidget::OnUpdate);
- connect(surface_source_list,
- static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
+ connect(surface_source_list, qOverload<int>(&QComboBox::currentIndexChanged), this,
&GraphicsSurfaceWidget::OnSurfaceSourceChanged);
connect(surface_address_control, &CSpinBox::ValueChanged, this,
&GraphicsSurfaceWidget::OnSurfaceAddressChanged);
- connect(surface_width_control, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
- this, &GraphicsSurfaceWidget::OnSurfaceWidthChanged);
- connect(surface_height_control, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
- this, &GraphicsSurfaceWidget::OnSurfaceHeightChanged);
- connect(surface_format_control,
- static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
+ connect(surface_width_control, qOverload<int>(&QSpinBox::valueChanged), this,
+ &GraphicsSurfaceWidget::OnSurfaceWidthChanged);
+ connect(surface_height_control, qOverload<int>(&QSpinBox::valueChanged), this,
+ &GraphicsSurfaceWidget::OnSurfaceHeightChanged);
+ connect(surface_format_control, qOverload<int>(&QComboBox::currentIndexChanged), this,
&GraphicsSurfaceWidget::OnSurfaceFormatChanged);
- connect(surface_picker_x_control, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
- this, &GraphicsSurfaceWidget::OnSurfacePickerXChanged);
- connect(surface_picker_y_control, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
- this, &GraphicsSurfaceWidget::OnSurfacePickerYChanged);
+ connect(surface_picker_x_control, qOverload<int>(&QSpinBox::valueChanged), this,
+ &GraphicsSurfaceWidget::OnSurfacePickerXChanged);
+ connect(surface_picker_y_control, qOverload<int>(&QSpinBox::valueChanged), this,
+ &GraphicsSurfaceWidget::OnSurfacePickerYChanged);
connect(save_surface, &QPushButton::clicked, this, &GraphicsSurfaceWidget::SaveSurface);
auto main_widget = new QWidget;
@@ -420,40 +460,56 @@ void GraphicsSurfaceWidget::OnUpdate() {
}
void GraphicsSurfaceWidget::SaveSurface() {
- QString png_filter = tr("Portable Network Graphic (*.png)");
- QString bin_filter = tr("Binary data (*.bin)");
+ const QString png_filter = tr("Portable Network Graphic (*.png)");
+ const QString bin_filter = tr("Binary data (*.bin)");
- QString selectedFilter;
- QString filename = QFileDialog::getSaveFileName(
+ QString selected_filter;
+ const QString filename = QFileDialog::getSaveFileName(
this, tr("Save Surface"),
- QString("texture-0x%1.png").arg(QString::number(surface_address, 16)),
- QString("%1;;%2").arg(png_filter, bin_filter), &selectedFilter);
+ QStringLiteral("texture-0x%1.png").arg(QString::number(surface_address, 16)),
+ QStringLiteral("%1;;%2").arg(png_filter, bin_filter), &selected_filter);
if (filename.isEmpty()) {
// If the user canceled the dialog, don't save anything.
return;
}
- if (selectedFilter == png_filter) {
- const QPixmap* pixmap = surface_picture_label->pixmap();
+ if (selected_filter == png_filter) {
+ const QPixmap* const pixmap = surface_picture_label->pixmap();
ASSERT_MSG(pixmap != nullptr, "No pixmap set");
- QFile file(filename);
- file.open(QIODevice::WriteOnly);
- if (pixmap)
- pixmap->save(&file, "PNG");
- } else if (selectedFilter == bin_filter) {
+ QFile file{filename};
+ if (!file.open(QIODevice::WriteOnly)) {
+ QMessageBox::warning(this, tr("Error"), tr("Failed to open file '%1'").arg(filename));
+ return;
+ }
+
+ if (!pixmap->save(&file, "PNG")) {
+ QMessageBox::warning(this, tr("Error"),
+ tr("Failed to save surface data to file '%1'").arg(filename));
+ }
+ } else if (selected_filter == bin_filter) {
auto& gpu = Core::System::GetInstance().GPU();
- std::optional<VAddr> address = gpu.MemoryManager().GpuToCpuAddress(surface_address);
+ const std::optional<VAddr> address = gpu.MemoryManager().GpuToCpuAddress(surface_address);
- const u8* buffer = Memory::GetPointer(*address);
+ const u8* const buffer = Memory::GetPointer(*address);
ASSERT_MSG(buffer != nullptr, "Memory not accessible");
- QFile file(filename);
- file.open(QIODevice::WriteOnly);
- int size = surface_width * surface_height * Tegra::Texture::BytesPerPixel(surface_format);
- QByteArray data(reinterpret_cast<const char*>(buffer), size);
- file.write(data);
+ QFile file{filename};
+ if (!file.open(QIODevice::WriteOnly)) {
+ QMessageBox::warning(this, tr("Error"), tr("Failed to open file '%1'").arg(filename));
+ return;
+ }
+
+ const int size =
+ surface_width * surface_height * Tegra::Texture::BytesPerPixel(surface_format);
+ const QByteArray data(reinterpret_cast<const char*>(buffer), size);
+ if (file.write(data) != data.size()) {
+ QMessageBox::warning(
+ this, tr("Error"),
+ tr("Failed to completely write surface data to file. The saved data will "
+ "likely be corrupt."));
+ }
} else {
UNREACHABLE_MSG("Unhandled filter selected");
}