Compare commits

..

1 Commits

Author SHA1 Message Date
Fernando Sahmkow 43df0c983a Name the Main and GPU thread to make debugging easier. 2019-04-07 07:53:46 -04:00
36 changed files with 692 additions and 134 deletions
+1
View File
@@ -26,6 +26,7 @@ using Vector = Dynarmic::A64::Vector;
class ARM_Dynarmic_Callbacks : public Dynarmic::A64::UserCallbacks {
public:
explicit ARM_Dynarmic_Callbacks(ARM_Dynarmic& parent) : parent(parent) {}
~ARM_Dynarmic_Callbacks() = default;
u8 MemoryRead8(u64 vaddr) override {
return Memory::Read8(vaddr);
+2 -2
View File
@@ -29,7 +29,7 @@ class ARM_Dynarmic final : public ARM_Interface {
public:
ARM_Dynarmic(Timing::CoreTiming& core_timing, ExclusiveMonitor& exclusive_monitor,
std::size_t core_index);
~ARM_Dynarmic() override;
~ARM_Dynarmic();
void MapBackingMemory(VAddr address, std::size_t size, u8* memory,
Kernel::VMAPermission perms) override;
@@ -76,7 +76,7 @@ private:
class DynarmicExclusiveMonitor final : public ExclusiveMonitor {
public:
explicit DynarmicExclusiveMonitor(std::size_t core_count);
~DynarmicExclusiveMonitor() override;
~DynarmicExclusiveMonitor();
void SetExclusive(std::size_t core_index, VAddr addr) override;
void ClearExclusive() override;
+1 -1
View File
@@ -18,7 +18,7 @@ namespace Core {
class ARM_Unicorn final : public ARM_Interface {
public:
explicit ARM_Unicorn(Timing::CoreTiming& core_timing);
~ARM_Unicorn() override;
~ARM_Unicorn();
void MapBackingMemory(VAddr address, std::size_t size, u8* memory,
Kernel::VMAPermission perms) override;
+1 -3
View File
@@ -23,7 +23,6 @@
*/
#include <cstring>
#include <string_view>
#include "common/alignment.h"
#include "common/assert.h"
#include "core/file_sys/fsmitm_romfsbuild.h"
@@ -98,8 +97,7 @@ struct RomFSBuildFileContext {
VirtualFile source;
};
static u32 romfs_calc_path_hash(u32 parent, std::string_view path, u32 start,
std::size_t path_len) {
static u32 romfs_calc_path_hash(u32 parent, std::string path, u32 start, std::size_t path_len) {
u32 hash = parent ^ 123456789;
for (u32 i = 0; i < path_len; i++) {
hash = (hash >> 5) | (hash << 27);
+8
View File
@@ -10,6 +10,14 @@
namespace FileSys {
bool operator>=(TitleType lhs, TitleType rhs) {
return static_cast<std::size_t>(lhs) >= static_cast<std::size_t>(rhs);
}
bool operator<=(TitleType lhs, TitleType rhs) {
return static_cast<std::size_t>(lhs) <= static_cast<std::size_t>(rhs);
}
CNMT::CNMT(VirtualFile file) {
if (file->ReadObject(&header) != sizeof(CNMTHeader))
return;
+3
View File
@@ -29,6 +29,9 @@ enum class TitleType : u8 {
DeltaTitle = 0x83,
};
bool operator>=(TitleType lhs, TitleType rhs);
bool operator<=(TitleType lhs, TitleType rhs);
enum class ContentRecordType : u8 {
Meta = 0,
Program = 1,
+13 -14
View File
@@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include <cstddef>
#include <cstring>
#include <vector>
#include "common/logging/log.h"
@@ -16,30 +17,28 @@ ProgramMetadata::ProgramMetadata() = default;
ProgramMetadata::~ProgramMetadata() = default;
Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) {
const std::size_t total_size = file->GetSize();
if (total_size < sizeof(Header)) {
std::size_t total_size = static_cast<std::size_t>(file->GetSize());
if (total_size < sizeof(Header))
return Loader::ResultStatus::ErrorBadNPDMHeader;
}
if (sizeof(Header) != file->ReadObject(&npdm_header)) {
// 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())
return Loader::ResultStatus::ErrorBadNPDMHeader;
}
std::memcpy(&npdm_header, npdm_header_data.data(), sizeof(Header));
if (sizeof(AcidHeader) != file->ReadObject(&acid_header, npdm_header.acid_offset)) {
std::vector<u8> acid_header_data = file->ReadBytes(sizeof(AcidHeader), npdm_header.acid_offset);
if (sizeof(AcidHeader) != acid_header_data.size())
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;
+2
View File
@@ -58,6 +58,7 @@ public:
void Print() const;
private:
// TODO(DarkLordZach): BitField is not trivially copyable.
struct Header {
std::array<char, 4> magic;
std::array<u8, 8> reserved;
@@ -84,6 +85,7 @@ 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;
+3 -5
View File
@@ -16,10 +16,8 @@ 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}, "
"rank={}, index={}]",
static_cast<u8>(type), title_id, user_id[1], user_id[0], save_id,
static_cast<u8>(rank), index);
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);
}
SaveDataFactory::SaveDataFactory(VirtualDir save_directory) : dir(std::move(save_directory)) {
@@ -30,7 +28,7 @@ SaveDataFactory::SaveDataFactory(VirtualDir save_directory) : dir(std::move(save
SaveDataFactory::~SaveDataFactory() = default;
ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataDescriptor& meta) {
ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, SaveDataDescriptor meta) {
if (meta.type == SaveDataType::SystemSaveData || meta.type == SaveDataType::SaveData) {
if (meta.zero_1 != 0) {
LOG_WARNING(Service_FS,
+2 -9
View File
@@ -32,19 +32,12 @@ 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;
SaveDataRank rank;
u16_le index;
INSERT_PADDING_BYTES(4);
INSERT_PADDING_BYTES(7);
u64_le zero_1;
u64_le zero_2;
u64_le zero_3;
@@ -64,7 +57,7 @@ public:
explicit SaveDataFactory(VirtualDir dir);
~SaveDataFactory();
ResultVal<VirtualDir> Open(SaveDataSpaceId space, const SaveDataDescriptor& meta);
ResultVal<VirtualDir> Open(SaveDataSpaceId space, SaveDataDescriptor meta);
VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const;
-14
View File
@@ -1339,20 +1339,6 @@ 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);
+4
View File
@@ -119,6 +119,10 @@ 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_)
+4
View File
@@ -2,6 +2,9 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/service/audio/audin_u.h"
namespace Service::Audio {
@@ -30,6 +33,7 @@ public:
RegisterHandlers(functions);
}
~IAudioIn() = default;
};
AudInU::AudInU() : ServiceFramework("audin:u") {
+4
View File
@@ -2,6 +2,9 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/service/audio/audrec_u.h"
namespace Service::Audio {
@@ -27,6 +30,7 @@ public:
RegisterHandlers(functions);
}
~IFinalOutputRecorder() = default;
};
AudRecU::AudRecU() : ServiceFramework("audrec:u") {
@@ -322,15 +322,15 @@ ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId stora
}
ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
const FileSys::SaveDataDescriptor& descriptor) {
FileSys::SaveDataDescriptor save_struct) {
LOG_TRACE(Service_FS, "Opening Save Data for space_id={:01X}, save_struct={}",
static_cast<u8>(space), descriptor.DebugInfo());
static_cast<u8>(space), save_struct.DebugInfo());
if (save_data_factory == nullptr) {
return FileSys::ERROR_ENTITY_NOT_FOUND;
}
return save_data_factory->Open(space, descriptor);
return save_data_factory->Open(space, save_struct);
}
ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space) {
+1 -1
View File
@@ -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,
const FileSys::SaveDataDescriptor& descriptor);
FileSys::SaveDataDescriptor save_struct);
ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space);
ResultVal<FileSys::VirtualDir> OpenSDMC();
+9 -12
View File
@@ -604,9 +604,7 @@ private:
u64_le save_id;
u64_le title_id;
u64_le save_image_size;
u16_le index;
FileSys::SaveDataRank rank;
INSERT_PADDING_BYTES(0x25);
INSERT_PADDING_BYTES(0x28);
};
static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size.");
@@ -769,17 +767,16 @@ void FSP_SRV::CreateSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
}
void FSP_SRV::OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
LOG_INFO(Service_FS, "called.");
struct Parameters {
FileSys::SaveDataSpaceId save_data_space_id;
FileSys::SaveDataDescriptor descriptor;
};
IPC::RequestParser rp{ctx};
const auto parameters = rp.PopRaw<Parameters>();
auto dir = OpenSaveData(parameters.save_data_space_id, parameters.descriptor);
auto space_id = rp.PopRaw<FileSys::SaveDataSpaceId>();
auto unk = rp.Pop<u32>();
LOG_INFO(Service_FS, "called with unknown={:08X}", unk);
auto save_struct = rp.PopRaw<FileSys::SaveDataDescriptor>();
auto dir = OpenSaveData(space_id, save_struct);
if (dir.Failed()) {
IPC::ResponseBuilder rb{ctx, 2, 0, 0};
rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
@@ -18,7 +18,7 @@ class nvmap;
class nvdisp_disp0 final : public nvdevice {
public:
explicit nvdisp_disp0(std::shared_ptr<nvmap> nvmap_dev);
~nvdisp_disp0() override;
~nvdisp_disp0();
u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
+1 -1
View File
@@ -17,7 +17,7 @@ namespace Service::Nvidia {
class NVDRV final : public ServiceFramework<NVDRV> {
public:
NVDRV(std::shared_ptr<Module> nvdrv, const char* name);
~NVDRV() override;
~NVDRV();
private:
void Open(Kernel::HLERequestContext& ctx);
+1 -1
View File
@@ -11,7 +11,7 @@ namespace Service::Nvidia {
class NVMEMP final : public ServiceFramework<NVMEMP> {
public:
NVMEMP();
~NVMEMP() override;
~NVMEMP();
private:
void Cmd0(Kernel::HLERequestContext& ctx);
+1 -1
View File
@@ -90,7 +90,7 @@ private:
Kernel::HLERequestContext& ctx);
ServiceFrameworkBase(const char* service_name, u32 max_sessions, InvokerFn* handler_invoker);
~ServiceFrameworkBase() override;
~ServiceFrameworkBase();
void RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n);
void ReportUnimplementedFunction(Kernel::HLERequestContext& ctx, const FunctionInfoBase* info);
+1 -1
View File
@@ -11,7 +11,7 @@ namespace Service::Set {
class SET_CAL final : public ServiceFramework<SET_CAL> {
public:
explicit SET_CAL();
~SET_CAL() override;
~SET_CAL();
};
} // namespace Service::Set
+1
View File
@@ -64,6 +64,7 @@ public:
};
RegisterHandlers(functions);
}
~ISslContext() = default;
private:
void SetOption(Kernel::HLERequestContext& ctx) {
+4
View File
@@ -498,6 +498,7 @@ public:
};
RegisterHandlers(functions);
}
~IHOSBinderDriver() = default;
private:
enum class TransactionId {
@@ -691,6 +692,7 @@ public:
};
RegisterHandlers(functions);
}
~ISystemDisplayService() = default;
private:
void SetLayerZ(Kernel::HLERequestContext& ctx) {
@@ -816,6 +818,7 @@ public:
};
RegisterHandlers(functions);
}
~IManagerDisplayService() = default;
private:
void CloseDisplay(Kernel::HLERequestContext& ctx) {
@@ -881,6 +884,7 @@ private:
class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> {
public:
explicit IApplicationDisplayService(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger);
~IApplicationDisplayService() = default;
private:
enum class ConvertedScaleMode : u64 {
+1 -1
View File
@@ -22,7 +22,7 @@ class AppLoader_NCA;
class AppLoader_XCI final : public AppLoader {
public:
explicit AppLoader_XCI(FileSys::VirtualFile file);
~AppLoader_XCI() override;
~AppLoader_XCI();
/**
* Returns the type of the file
+3 -1
View File
@@ -4,6 +4,7 @@
#include "common/assert.h"
#include "common/microprofile.h"
#include "common/thread.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/core_timing_util.h"
@@ -22,6 +23,7 @@ static void RunThread(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_p
// Wait for first GPU command before acquiring the window context
state.WaitForCommands();
Common::SetCurrentThreadName("yuzu GPU");
// If emulation was stopped during disk shader loading, abort before trying to acquire context
if (!state.is_running) {
@@ -59,7 +61,7 @@ ThreadManager::ThreadManager(Core::System& system, VideoCore::RendererBase& rend
Tegra::DmaPusher& dma_pusher)
: system{system}, thread{RunThread, std::ref(renderer), std::ref(dma_pusher), std::ref(state)} {
synchronization_event = system.CoreTiming().RegisterEvent(
"GPUThreadSynch", [this](u64 fence, s64) { state.WaitForSynchronization(fence); });
"GPUThreadSynch", [this](u64 fence, int) { state.WaitForSynchronization(fence); });
}
ThreadManager::~ThreadManager() {
+13 -7
View File
@@ -223,21 +223,27 @@ void MacroInterpreter::ProcessResult(ResultOperation operation, u32 reg, u32 res
}
u32 MacroInterpreter::FetchParameter() {
return parameters.at(next_parameter_index++);
ASSERT(next_parameter_index < parameters.size());
return parameters[next_parameter_index++];
}
u32 MacroInterpreter::GetRegister(u32 register_id) const {
return registers.at(register_id);
// Register 0 is supposed to always return 0.
if (register_id == 0)
return 0;
ASSERT(register_id < registers.size());
return registers[register_id];
}
void MacroInterpreter::SetRegister(u32 register_id, u32 value) {
// Register 0 is hardwired as the zero register.
// Ensure no writes to it actually occur.
if (register_id == 0) {
// Register 0 is supposed to always return 0. NOP is implemented as a store to the zero
// register.
if (register_id == 0)
return;
}
registers.at(register_id) = value;
ASSERT(register_id < registers.size());
registers[register_id] = value;
}
void MacroInterpreter::SetMethodAddress(u32 address) {
+18 -33
View File
@@ -77,17 +77,16 @@ GPUVAddr MemoryManager::UnmapBuffer(GPUVAddr gpu_addr, u64 size) {
return gpu_addr;
}
GPUVAddr MemoryManager::FindFreeRegion(GPUVAddr region_start, u64 size) const {
GPUVAddr MemoryManager::FindFreeRegion(GPUVAddr region_start, u64 size) {
// Find the first Free VMA.
const VMAHandle vma_handle{
std::find_if(vma_map.begin(), vma_map.end(), [region_start, size](const auto& vma) {
if (vma.second.type != VirtualMemoryArea::Type::Unmapped) {
return false;
}
const VMAHandle vma_handle{std::find_if(vma_map.begin(), vma_map.end(), [&](const auto& vma) {
if (vma.second.type != VirtualMemoryArea::Type::Unmapped) {
return false;
}
const VAddr vma_end{vma.second.base + vma.second.size};
return vma_end > region_start && vma_end >= region_start + size;
})};
const VAddr vma_end{vma.second.base + vma.second.size};
return vma_end > region_start && vma_end >= region_start + size;
})};
if (vma_handle == vma_map.end()) {
return {};
@@ -100,12 +99,12 @@ bool MemoryManager::IsAddressValid(GPUVAddr addr) const {
return (addr >> page_bits) < page_table.pointers.size();
}
std::optional<VAddr> MemoryManager::GpuToCpuAddress(GPUVAddr addr) const {
std::optional<VAddr> MemoryManager::GpuToCpuAddress(GPUVAddr addr) {
if (!IsAddressValid(addr)) {
return {};
}
const VAddr cpu_addr{page_table.backing_addr[addr >> page_bits]};
VAddr cpu_addr{page_table.backing_addr[addr >> page_bits]};
if (cpu_addr) {
return cpu_addr + (addr & page_mask);
}
@@ -114,7 +113,7 @@ std::optional<VAddr> MemoryManager::GpuToCpuAddress(GPUVAddr addr) const {
}
template <typename T>
T MemoryManager::Read(GPUVAddr addr) const {
T MemoryManager::Read(GPUVAddr addr) {
if (!IsAddressValid(addr)) {
return {};
}
@@ -166,10 +165,10 @@ void MemoryManager::Write(GPUVAddr addr, T data) {
}
}
template u8 MemoryManager::Read<u8>(GPUVAddr addr) const;
template u16 MemoryManager::Read<u16>(GPUVAddr addr) const;
template u32 MemoryManager::Read<u32>(GPUVAddr addr) const;
template u64 MemoryManager::Read<u64>(GPUVAddr addr) const;
template u8 MemoryManager::Read<u8>(GPUVAddr addr);
template u16 MemoryManager::Read<u16>(GPUVAddr addr);
template u32 MemoryManager::Read<u32>(GPUVAddr addr);
template u64 MemoryManager::Read<u64>(GPUVAddr addr);
template void MemoryManager::Write<u8>(GPUVAddr addr, u8 data);
template void MemoryManager::Write<u16>(GPUVAddr addr, u16 data);
template void MemoryManager::Write<u32>(GPUVAddr addr, u32 data);
@@ -180,8 +179,8 @@ u8* MemoryManager::GetPointer(GPUVAddr addr) {
return {};
}
u8* const page_pointer{page_table.pointers[addr >> page_bits]};
if (page_pointer != nullptr) {
u8* page_pointer{page_table.pointers[addr >> page_bits]};
if (page_pointer) {
return page_pointer + (addr & page_mask);
}
@@ -189,21 +188,7 @@ u8* MemoryManager::GetPointer(GPUVAddr addr) {
return {};
}
const u8* MemoryManager::GetPointer(GPUVAddr addr) const {
if (!IsAddressValid(addr)) {
return {};
}
const u8* const page_pointer{page_table.pointers[addr >> page_bits]};
if (page_pointer != nullptr) {
return page_pointer + (addr & page_mask);
}
LOG_ERROR(HW_GPU, "Unknown GetPointer @ 0x{:016X}", addr);
return {};
}
void MemoryManager::ReadBlock(GPUVAddr src_addr, void* dest_buffer, std::size_t size) const {
void MemoryManager::ReadBlock(GPUVAddr src_addr, void* dest_buffer, std::size_t size) {
std::memcpy(dest_buffer, GetPointer(src_addr), size);
}
void MemoryManager::WriteBlock(GPUVAddr dest_addr, const void* src_buffer, std::size_t size) {
+4 -5
View File
@@ -50,18 +50,17 @@ public:
GPUVAddr MapBufferEx(VAddr cpu_addr, u64 size);
GPUVAddr MapBufferEx(VAddr cpu_addr, GPUVAddr addr, u64 size);
GPUVAddr UnmapBuffer(GPUVAddr addr, u64 size);
std::optional<VAddr> GpuToCpuAddress(GPUVAddr addr) const;
std::optional<VAddr> GpuToCpuAddress(GPUVAddr addr);
template <typename T>
T Read(GPUVAddr addr) const;
T Read(GPUVAddr addr);
template <typename T>
void Write(GPUVAddr addr, T data);
u8* GetPointer(GPUVAddr addr);
const u8* GetPointer(GPUVAddr addr) const;
void ReadBlock(GPUVAddr src_addr, void* dest_buffer, std::size_t size) const;
void ReadBlock(GPUVAddr src_addr, void* dest_buffer, std::size_t size);
void WriteBlock(GPUVAddr dest_addr, const void* src_buffer, std::size_t size);
void CopyBlock(GPUVAddr dest_addr, GPUVAddr src_addr, std::size_t size);
@@ -128,7 +127,7 @@ private:
void UpdatePageTableForVMA(const VirtualMemoryArea& vma);
/// Finds a free (unmapped region) of the specified size starting at the specified address.
GPUVAddr FindFreeRegion(GPUVAddr region_start, u64 size) const;
GPUVAddr FindFreeRegion(GPUVAddr region_start, u64 size);
private:
static constexpr u64 page_bits{16};
@@ -69,10 +69,10 @@ public:
shader_source += '\n';
}
std::string GenerateTemporary() {
std::string temporary = "tmp";
temporary += std::to_string(temporary_index++);
return temporary;
std::string GenerateTemporal() {
std::string temporal = "tmp";
temporal += std::to_string(temporal_index++);
return temporal;
}
std::string GetResult() {
@@ -87,7 +87,7 @@ private:
}
std::string shader_source;
u32 temporary_index = 1;
u32 temporal_index = 1;
};
/// Generates code to use for a swizzle operation.
@@ -426,14 +426,9 @@ 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("Undefined operation: {}", operation_index);
return {};
UNREACHABLE_MSG("Operation decompiler {} not defined", operation_index);
}
return (this->*decompiler)(*operation);
@@ -545,7 +540,7 @@ private:
} else if (std::holds_alternative<OperationNode>(*offset)) {
// Indirect access
const std::string final_offset = code.GenerateTemporary();
const std::string final_offset = code.GenerateTemporal();
code.AddLine("uint " + final_offset + " = (ftou(" + Visit(offset) + ") / 4) & " +
std::to_string(MAX_CONSTBUFFER_ELEMENTS - 1) + ';');
return fmt::format("{}[{} / 4][{} % 4]", GetConstBuffer(cbuf->GetIndex()),
@@ -592,9 +587,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 temporary = code.GenerateTemporary();
code.AddLine(precise + "float " + temporary + " = " + value + ';');
return temporary;
const std::string temporal = code.GenerateTemporal();
code.AddLine(precise + "float " + temporal + " = " + value + ';');
return temporal;
}
std::string VisitOperand(Operation operation, std::size_t operand_index) {
@@ -606,9 +601,9 @@ private:
return Visit(operand);
}
const std::string temporary = code.GenerateTemporary();
code.AddLine("float " + temporary + " = " + Visit(operand) + ';');
return temporary;
const std::string temporal = code.GenerateTemporal();
code.AddLine("float " + temporal + " = " + Visit(operand) + ';');
return temporal;
}
std::string VisitOperand(Operation operation, std::size_t operand_index, Type type) {
+2
View File
@@ -54,6 +54,8 @@ add_executable(yuzu
debugger/graphics/graphics_breakpoints.cpp
debugger/graphics/graphics_breakpoints.h
debugger/graphics/graphics_breakpoints_p.h
debugger/graphics/graphics_surface.cpp
debugger/graphics/graphics_surface.h
debugger/console.cpp
debugger/console.h
debugger/profiler.cpp
+3
View File
@@ -6,6 +6,7 @@
#include <fmt/format.h>
#include "common/microprofile.h"
#include "common/scm_rev.h"
#include "common/thread.h"
#include "core/core.h"
#include "core/frontend/framebuffer_layout.h"
#include "core/settings.h"
@@ -24,6 +25,8 @@ void EmuThread::run() {
MicroProfileOnThreadCreate("EmuThread");
Common::SetCurrentThreadName("yuzu Main");
emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0);
Core::System::GetInstance().Renderer().Rasterizer().LoadDiskResources(
@@ -0,0 +1,460 @@
// Copyright 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <QBoxLayout>
#include <QComboBox>
#include <QDebug>
#include <QFileDialog>
#include <QLabel>
#include <QMouseEvent>
#include <QPushButton>
#include <QScrollArea>
#include <QSpinBox>
#include "common/vector_math.h"
#include "core/core.h"
#include "core/memory.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/gpu.h"
#include "video_core/textures/decoders.h"
#include "video_core/textures/texture.h"
#include "yuzu/debugger/graphics/graphics_surface.h"
#include "yuzu/util/spinbox.h"
static Tegra::Texture::TextureFormat ConvertToTextureFormat(
Tegra::RenderTargetFormat render_target_format) {
switch (render_target_format) {
case Tegra::RenderTargetFormat::RGBA8_UNORM:
return Tegra::Texture::TextureFormat::A8R8G8B8;
case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
return Tegra::Texture::TextureFormat::A2B10G10R10;
default:
UNIMPLEMENTED_MSG("Unimplemented RT format");
return Tegra::Texture::TextureFormat::A8R8G8B8;
}
}
SurfacePicture::SurfacePicture(QWidget* parent, GraphicsSurfaceWidget* surface_widget_)
: QLabel(parent), surface_widget(surface_widget_) {}
SurfacePicture::~SurfacePicture() = default;
void SurfacePicture::mousePressEvent(QMouseEvent* event) {
// Only do something while the left mouse button is held down
if (!(event->buttons() & Qt::LeftButton))
return;
if (pixmap() == nullptr)
return;
if (surface_widget)
surface_widget->Pick(event->x() * pixmap()->width() / width(),
event->y() * pixmap()->height() / height());
}
void SurfacePicture::mouseMoveEvent(QMouseEvent* event) {
// We also want to handle the event if the user moves the mouse while holding down the LMB
mousePressEvent(event);
}
GraphicsSurfaceWidget::GraphicsSurfaceWidget(std::shared_ptr<Tegra::DebugContext> debug_context,
QWidget* parent)
: BreakPointObserverDock(debug_context, tr("Maxwell Surface Viewer"), parent),
surface_source(Source::RenderTarget0) {
setObjectName("MaxwellSurface");
surface_source_list = new QComboBox;
surface_source_list->addItem(tr("Render Target 0"));
surface_source_list->addItem(tr("Render Target 1"));
surface_source_list->addItem(tr("Render Target 2"));
surface_source_list->addItem(tr("Render Target 3"));
surface_source_list->addItem(tr("Render Target 4"));
surface_source_list->addItem(tr("Render Target 5"));
surface_source_list->addItem(tr("Render Target 6"));
surface_source_list->addItem(tr("Render Target 7"));
surface_source_list->addItem(tr("Z Buffer"));
surface_source_list->addItem(tr("Custom"));
surface_source_list->setCurrentIndex(static_cast<int>(surface_source));
surface_address_control = new CSpinBox;
surface_address_control->SetBase(16);
surface_address_control->SetRange(0, 0x7FFFFFFFFFFFFFFF);
surface_address_control->SetPrefix("0x");
unsigned max_dimension = 16384; // TODO: Find actual maximum
surface_width_control = new QSpinBox;
surface_width_control->setRange(0, max_dimension);
surface_height_control = new QSpinBox;
surface_height_control->setRange(0, max_dimension);
surface_picker_x_control = new QSpinBox;
surface_picker_x_control->setRange(0, max_dimension - 1);
surface_picker_y_control = new QSpinBox;
surface_picker_y_control->setRange(0, max_dimension - 1);
surface_format_control = new QComboBox;
// 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"));
surface_info_label = new QLabel();
surface_info_label->setWordWrap(true);
surface_picture_label = new SurfacePicture(0, this);
surface_picture_label->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
surface_picture_label->setAlignment(Qt::AlignLeft | Qt::AlignTop);
surface_picture_label->setScaledContents(false);
auto scroll_area = new QScrollArea();
scroll_area->setBackgroundRole(QPalette::Dark);
scroll_area->setWidgetResizable(false);
scroll_area->setWidget(surface_picture_label);
save_surface = new QPushButton(QIcon::fromTheme("document-save"), tr("Save"));
// Connections
connect(this, &GraphicsSurfaceWidget::Update, this, &GraphicsSurfaceWidget::OnUpdate);
connect(surface_source_list,
static_cast<void (QComboBox::*)(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,
&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(save_surface, &QPushButton::clicked, this, &GraphicsSurfaceWidget::SaveSurface);
auto main_widget = new QWidget;
auto main_layout = new QVBoxLayout;
{
auto sub_layout = new QHBoxLayout;
sub_layout->addWidget(new QLabel(tr("Source:")));
sub_layout->addWidget(surface_source_list);
main_layout->addLayout(sub_layout);
}
{
auto sub_layout = new QHBoxLayout;
sub_layout->addWidget(new QLabel(tr("GPU Address:")));
sub_layout->addWidget(surface_address_control);
main_layout->addLayout(sub_layout);
}
{
auto sub_layout = new QHBoxLayout;
sub_layout->addWidget(new QLabel(tr("Width:")));
sub_layout->addWidget(surface_width_control);
main_layout->addLayout(sub_layout);
}
{
auto sub_layout = new QHBoxLayout;
sub_layout->addWidget(new QLabel(tr("Height:")));
sub_layout->addWidget(surface_height_control);
main_layout->addLayout(sub_layout);
}
{
auto sub_layout = new QHBoxLayout;
sub_layout->addWidget(new QLabel(tr("Format:")));
sub_layout->addWidget(surface_format_control);
main_layout->addLayout(sub_layout);
}
main_layout->addWidget(scroll_area);
auto info_layout = new QHBoxLayout;
{
auto xy_layout = new QVBoxLayout;
{
{
auto sub_layout = new QHBoxLayout;
sub_layout->addWidget(new QLabel(tr("X:")));
sub_layout->addWidget(surface_picker_x_control);
xy_layout->addLayout(sub_layout);
}
{
auto sub_layout = new QHBoxLayout;
sub_layout->addWidget(new QLabel(tr("Y:")));
sub_layout->addWidget(surface_picker_y_control);
xy_layout->addLayout(sub_layout);
}
}
info_layout->addLayout(xy_layout);
surface_info_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
info_layout->addWidget(surface_info_label);
}
main_layout->addLayout(info_layout);
main_layout->addWidget(save_surface);
main_widget->setLayout(main_layout);
setWidget(main_widget);
// Load current data - TODO: Make sure this works when emulation is not running
if (debug_context && debug_context->at_breakpoint) {
emit Update();
widget()->setEnabled(debug_context->at_breakpoint);
} else {
widget()->setEnabled(false);
}
}
void GraphicsSurfaceWidget::OnBreakPointHit(Tegra::DebugContext::Event event, void* data) {
emit Update();
widget()->setEnabled(true);
}
void GraphicsSurfaceWidget::OnResumed() {
widget()->setEnabled(false);
}
void GraphicsSurfaceWidget::OnSurfaceSourceChanged(int new_value) {
surface_source = static_cast<Source>(new_value);
emit Update();
}
void GraphicsSurfaceWidget::OnSurfaceAddressChanged(qint64 new_value) {
if (surface_address != new_value) {
surface_address = static_cast<GPUVAddr>(new_value);
surface_source_list->setCurrentIndex(static_cast<int>(Source::Custom));
emit Update();
}
}
void GraphicsSurfaceWidget::OnSurfaceWidthChanged(int new_value) {
if (surface_width != static_cast<unsigned>(new_value)) {
surface_width = static_cast<unsigned>(new_value);
surface_source_list->setCurrentIndex(static_cast<int>(Source::Custom));
emit Update();
}
}
void GraphicsSurfaceWidget::OnSurfaceHeightChanged(int new_value) {
if (surface_height != static_cast<unsigned>(new_value)) {
surface_height = static_cast<unsigned>(new_value);
surface_source_list->setCurrentIndex(static_cast<int>(Source::Custom));
emit Update();
}
}
void GraphicsSurfaceWidget::OnSurfaceFormatChanged(int new_value) {
if (surface_format != static_cast<Tegra::Texture::TextureFormat>(new_value)) {
surface_format = static_cast<Tegra::Texture::TextureFormat>(new_value);
surface_source_list->setCurrentIndex(static_cast<int>(Source::Custom));
emit Update();
}
}
void GraphicsSurfaceWidget::OnSurfacePickerXChanged(int new_value) {
if (surface_picker_x != new_value) {
surface_picker_x = new_value;
Pick(surface_picker_x, surface_picker_y);
}
}
void GraphicsSurfaceWidget::OnSurfacePickerYChanged(int new_value) {
if (surface_picker_y != new_value) {
surface_picker_y = new_value;
Pick(surface_picker_x, surface_picker_y);
}
}
void GraphicsSurfaceWidget::Pick(int x, int y) {
surface_picker_x_control->setValue(x);
surface_picker_y_control->setValue(y);
if (x < 0 || x >= static_cast<int>(surface_width) || y < 0 ||
y >= static_cast<int>(surface_height)) {
surface_info_label->setText(tr("Pixel out of bounds"));
surface_info_label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
return;
}
surface_info_label->setText(QString("Raw: <Unimplemented>\n(%1)").arg("<Unimplemented>"));
surface_info_label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
}
void GraphicsSurfaceWidget::OnUpdate() {
auto& gpu = Core::System::GetInstance().GPU();
QPixmap pixmap;
switch (surface_source) {
case Source::RenderTarget0:
case Source::RenderTarget1:
case Source::RenderTarget2:
case Source::RenderTarget3:
case Source::RenderTarget4:
case Source::RenderTarget5:
case Source::RenderTarget6:
case Source::RenderTarget7: {
// TODO: Store a reference to the registers in the debug context instead of accessing them
// directly...
const auto& registers = gpu.Maxwell3D().regs;
const auto& rt = registers.rt[static_cast<std::size_t>(surface_source) -
static_cast<std::size_t>(Source::RenderTarget0)];
surface_address = rt.Address();
surface_width = rt.width;
surface_height = rt.height;
if (rt.format != Tegra::RenderTargetFormat::NONE) {
surface_format = ConvertToTextureFormat(rt.format);
}
break;
}
case Source::Custom: {
// Keep user-specified values
break;
}
default:
qDebug() << "Unknown surface source " << static_cast<int>(surface_source);
break;
}
surface_address_control->SetValue(surface_address);
surface_width_control->setValue(surface_width);
surface_height_control->setValue(surface_height);
surface_format_control->setCurrentIndex(static_cast<int>(surface_format));
if (surface_address == 0) {
surface_picture_label->hide();
surface_info_label->setText(tr("(invalid surface address)"));
surface_info_label->setAlignment(Qt::AlignCenter);
surface_picker_x_control->setEnabled(false);
surface_picker_y_control->setEnabled(false);
save_surface->setEnabled(false);
return;
}
// TODO: Implement a good way to visualize alpha components!
QImage decoded_image(surface_width, surface_height, QImage::Format_ARGB32);
// TODO(bunnei): Will not work with BCn formats that swizzle 4x4 tiles.
// Needs to be fixed if we plan to use this feature more, otherwise we may remove it.
auto unswizzled_data = Tegra::Texture::UnswizzleTexture(
gpu.MemoryManager().GetPointer(surface_address), 1, 1,
Tegra::Texture::BytesPerPixel(surface_format), surface_width, surface_height, 1U);
auto texture_data = Tegra::Texture::DecodeTexture(unswizzled_data, surface_format,
surface_width, surface_height);
surface_picture_label->show();
for (unsigned int y = 0; y < surface_height; ++y) {
for (unsigned int x = 0; x < surface_width; ++x) {
Common::Vec4<u8> color;
color[0] = texture_data[x + y * surface_width + 0];
color[1] = texture_data[x + y * surface_width + 1];
color[2] = texture_data[x + y * surface_width + 2];
color[3] = texture_data[x + y * surface_width + 3];
decoded_image.setPixel(x, y, qRgba(color.r(), color.g(), color.b(), color.a()));
}
}
pixmap = QPixmap::fromImage(decoded_image);
surface_picture_label->setPixmap(pixmap);
surface_picture_label->resize(pixmap.size());
// Update the info with pixel data
surface_picker_x_control->setEnabled(true);
surface_picker_y_control->setEnabled(true);
Pick(surface_picker_x, surface_picker_y);
// Enable saving the converted pixmap to file
save_surface->setEnabled(true);
}
void GraphicsSurfaceWidget::SaveSurface() {
QString png_filter = tr("Portable Network Graphic (*.png)");
QString bin_filter = tr("Binary data (*.bin)");
QString selectedFilter;
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);
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();
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) {
auto& gpu = Core::System::GetInstance().GPU();
std::optional<VAddr> address = gpu.MemoryManager().GpuToCpuAddress(surface_address);
const u8* 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);
} else {
UNREACHABLE_MSG("Unhandled filter selected");
}
}
@@ -0,0 +1,96 @@
// Copyright 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <QLabel>
#include <QPushButton>
#include "video_core/memory_manager.h"
#include "video_core/textures/texture.h"
#include "yuzu/debugger/graphics/graphics_breakpoint_observer.h"
class QComboBox;
class QSpinBox;
class CSpinBox;
class GraphicsSurfaceWidget;
class SurfacePicture : public QLabel {
Q_OBJECT
public:
explicit SurfacePicture(QWidget* parent = nullptr,
GraphicsSurfaceWidget* surface_widget = nullptr);
~SurfacePicture() override;
protected slots:
void mouseMoveEvent(QMouseEvent* event) override;
void mousePressEvent(QMouseEvent* event) override;
private:
GraphicsSurfaceWidget* surface_widget;
};
class GraphicsSurfaceWidget : public BreakPointObserverDock {
Q_OBJECT
using Event = Tegra::DebugContext::Event;
enum class Source {
RenderTarget0 = 0,
RenderTarget1 = 1,
RenderTarget2 = 2,
RenderTarget3 = 3,
RenderTarget4 = 4,
RenderTarget5 = 5,
RenderTarget6 = 6,
RenderTarget7 = 7,
ZBuffer = 8,
Custom = 9,
};
public:
explicit GraphicsSurfaceWidget(std::shared_ptr<Tegra::DebugContext> debug_context,
QWidget* parent = nullptr);
void Pick(int x, int y);
public slots:
void OnSurfaceSourceChanged(int new_value);
void OnSurfaceAddressChanged(qint64 new_value);
void OnSurfaceWidthChanged(int new_value);
void OnSurfaceHeightChanged(int new_value);
void OnSurfaceFormatChanged(int new_value);
void OnSurfacePickerXChanged(int new_value);
void OnSurfacePickerYChanged(int new_value);
void OnUpdate();
signals:
void Update();
private:
void OnBreakPointHit(Tegra::DebugContext::Event event, void* data) override;
void OnResumed() override;
void SaveSurface();
QComboBox* surface_source_list;
CSpinBox* surface_address_control;
QSpinBox* surface_width_control;
QSpinBox* surface_height_control;
QComboBox* surface_format_control;
SurfacePicture* surface_picture_label;
QSpinBox* surface_picker_x_control;
QSpinBox* surface_picker_y_control;
QLabel* surface_info_label;
QPushButton* save_surface;
Source surface_source;
GPUVAddr surface_address;
unsigned surface_width;
unsigned surface_height;
Tegra::Texture::TextureFormat surface_format;
int surface_picker_x = 0;
int surface_picker_y = 0;
};
+6
View File
@@ -90,6 +90,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
#include "yuzu/configuration/configure_dialog.h"
#include "yuzu/debugger/console.h"
#include "yuzu/debugger/graphics/graphics_breakpoints.h"
#include "yuzu/debugger/graphics/graphics_surface.h"
#include "yuzu/debugger/profiler.h"
#include "yuzu/debugger/wait_tree.h"
#include "yuzu/discord.h"
@@ -477,6 +478,11 @@ void GMainWindow::InitializeDebugWidgets() {
graphicsBreakpointsWidget->hide();
debug_menu->addAction(graphicsBreakpointsWidget->toggleViewAction());
graphicsSurfaceWidget = new GraphicsSurfaceWidget(debug_context, this);
addDockWidget(Qt::RightDockWidgetArea, graphicsSurfaceWidget);
graphicsSurfaceWidget->hide();
debug_menu->addAction(graphicsSurfaceWidget->toggleViewAction());
waitTreeWidget = new WaitTreeWidget(this);
addDockWidget(Qt::LeftDockWidgetArea, waitTreeWidget);
waitTreeWidget->hide();
+2
View File
@@ -23,6 +23,7 @@ class EmuThread;
class GameList;
class GImageInfo;
class GraphicsBreakPointsWidget;
class GraphicsSurfaceWidget;
class GRenderWindow;
class LoadingScreen;
class MicroProfileDialog;
@@ -237,6 +238,7 @@ private:
ProfilerWidget* profilerWidget;
MicroProfileDialog* microProfileDialog;
GraphicsBreakPointsWidget* graphicsBreakpointsWidget;
GraphicsSurfaceWidget* graphicsSurfaceWidget;
WaitTreeWidget* waitTreeWidget;
QAction* actions_recent_files[max_recent_files_item];