Merge branch 'shadps4-emu:main' into audio3d

This commit is contained in:
Lizardy 2024-09-05 14:57:05 -04:00 committed by GitHub
commit 94e911c508
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
66 changed files with 4156 additions and 1185 deletions

View file

@ -558,6 +558,7 @@ set(VIDEO_CORE src/video_core/amdgpu/liverpool.cpp
src/video_core/texture_cache/tile_manager.cpp
src/video_core/texture_cache/tile_manager.h
src/video_core/texture_cache/types.h
src/video_core/texture_cache/host_compatibility.h
src/video_core/page_manager.cpp
src/video_core/page_manager.h
src/video_core/multi_level_page_table.h

View file

@ -15,6 +15,7 @@
#include <fcntl.h>
#include <sys/mman.h>
#endif
#include "libraries/error_codes.h"
#ifdef __APPLE__
// Reserve space for the system address space using a zerofill section.
@ -231,27 +232,36 @@ struct AddressSpace::Impl {
void Protect(VAddr virtual_addr, size_t size, bool read, bool write, bool execute) {
DWORD new_flags{};
if (read && write) {
if (read && write && execute) {
new_flags = PAGE_EXECUTE_READWRITE;
} else if (read && write) {
new_flags = PAGE_READWRITE;
} else if (read && !write) {
new_flags = PAGE_READONLY;
} else if (!read && !write) {
} else if (execute && !read && not write) {
new_flags = PAGE_EXECUTE;
} else if (!read && !write && !execute) {
new_flags = PAGE_NOACCESS;
} else {
UNIMPLEMENTED_MSG("Protection flag combination read={} write={}", read, write);
LOG_CRITICAL(Common_Memory,
"Unsupported protection flag combination for address {:#x}, size {}",
virtual_addr, size);
return;
}
const VAddr virtual_end = virtual_addr + size;
auto [it, end] = placeholders.equal_range({virtual_addr, virtual_end});
while (it != end) {
const size_t offset = std::max(it->lower(), virtual_addr);
const size_t protect_length = std::min(it->upper(), virtual_end) - offset;
DWORD old_flags{};
if (!VirtualProtect(virtual_base + offset, protect_length, new_flags, &old_flags)) {
LOG_CRITICAL(Common_Memory, "Failed to change virtual memory protect rules");
}
++it;
DWORD old_flags{};
bool success =
VirtualProtect(reinterpret_cast<void*>(virtual_addr), size, new_flags, &old_flags);
if (!success) {
LOG_ERROR(Common_Memory,
"Failed to change virtual memory protection for address {:#x}, size {}",
virtual_addr, size);
}
// Use assert to ensure success in debug builds
DEBUG_ASSERT(success && "Failed to change virtual memory protection");
}
HANDLE process{};
@ -493,7 +503,10 @@ void AddressSpace::Unmap(VAddr virtual_addr, size_t size, VAddr start_in_vma, VA
}
void AddressSpace::Protect(VAddr virtual_addr, size_t size, MemoryPermission perms) {
return impl->Protect(virtual_addr, size, true, true, true);
const bool read = True(perms & MemoryPermission::Read);
const bool write = True(perms & MemoryPermission::Write);
const bool execute = True(perms & MemoryPermission::Execute);
return impl->Protect(virtual_addr, size, read, write, execute);
}
} // namespace Core

View file

@ -145,7 +145,7 @@ int PS4_SYSV_ABI sceKernelPollEventFlag(OrbisKernelEventFlag ef, u64 bitPattern,
}
int PS4_SYSV_ABI sceKernelWaitEventFlag(OrbisKernelEventFlag ef, u64 bitPattern, u32 waitMode,
u64* pResultPat, OrbisKernelUseconds* pTimeout) {
LOG_INFO(Kernel_Event, "called bitPattern = {:#x} waitMode = {:#x}", bitPattern, waitMode);
LOG_DEBUG(Kernel_Event, "called bitPattern = {:#x} waitMode = {:#x}", bitPattern, waitMode);
if (ef == nullptr) {
return ORBIS_KERNEL_ERROR_ESRCH;
}

View file

@ -454,6 +454,8 @@ void LibKernel_Register(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("F6e0kwo4cnk", "libkernel", 1, "libkernel", 1, 1, sceKernelTriggerUserEvent);
LIB_FUNCTION("LJDwdSNTnDg", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteUserEvent);
LIB_FUNCTION("mJ7aghmgvfc", "libkernel", 1, "libkernel", 1, 1, sceKernelGetEventId);
LIB_FUNCTION("9bfdLIyuwCY", "libkernel", 1, "libkernel", 1, 1, sceKernelMTypeProtect);
LIB_FUNCTION("vSMAm3cxYTY", "libkernel", 1, "libkernel", 1, 1, sceKernelMProtect);
LIB_FUNCTION("23CPPI1tyBY", "libkernel", 1, "libkernel", 1, 1, sceKernelGetEventFilter);
// misc

View file

@ -7,6 +7,7 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/singleton.h"
#include "core/address_space.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/kernel/memory_management.h"
#include "core/linker.h"
@ -218,6 +219,19 @@ int PS4_SYSV_ABI sceKernelQueryMemoryProtection(void* addr, void** start, void**
return memory->QueryProtection(std::bit_cast<VAddr>(addr), start, end, prot);
}
int PS4_SYSV_ABI sceKernelMProtect(const void* addr, size_t size, int prot) {
Core::MemoryManager* memory_manager = Core::Memory::Instance();
Core::MemoryProt protection_flags = static_cast<Core::MemoryProt>(prot);
return memory_manager->Protect(std::bit_cast<VAddr>(addr), size, protection_flags);
}
int PS4_SYSV_ABI sceKernelMTypeProtect(const void* addr, size_t size, int mtype, int prot) {
Core::MemoryManager* memory_manager = Core::Memory::Instance();
Core::MemoryProt protection_flags = static_cast<Core::MemoryProt>(prot);
return memory_manager->MTypeProtect(std::bit_cast<VAddr>(addr), size,
static_cast<Core::VMAType>(mtype), protection_flags);
}
int PS4_SYSV_ABI sceKernelDirectMemoryQuery(u64 offset, int flags, OrbisQueryInfo* query_info,
size_t infoSize) {
LOG_WARNING(Kernel_Vmm, "called offset = {:#x}, flags = {:#x}", offset, flags);
@ -282,6 +296,12 @@ s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, int numEn
entries[i].operation, entries[i].length, result);
break;
}
case MemoryOpTypes::ORBIS_KERNEL_MAP_OP_PROTECT: {
result = sceKernelMProtect(entries[i].start, entries[i].length, entries[i].protection);
LOG_INFO(Kernel_Vmm, "entry = {}, operation = {}, len = {:#x}, result = {}", i,
entries[i].operation, entries[i].length, result);
break;
}
case MemoryOpTypes::ORBIS_KERNEL_MAP_OP_MAP_FLEXIBLE: {
result = sceKernelMapNamedFlexibleMemory(&entries[i].start, entries[i].length,
entries[i].protection, flags, "");
@ -292,11 +312,10 @@ s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, int numEn
break;
}
case MemoryOpTypes::ORBIS_KERNEL_MAP_OP_TYPE_PROTECT: {
// By now, ignore protection and log it instead
LOG_WARNING(Kernel_Vmm,
"entry = {}, operation = {}, len = {:#x}, type = {} "
"is UNSUPPORTED and skipped",
i, entries[i].operation, entries[i].length, (u8)entries[i].type);
result = sceKernelMTypeProtect(entries[i].start, entries[i].length, entries[i].type,
entries[i].protection);
LOG_INFO(Kernel_Vmm, "entry = {}, operation = {}, len = {:#x}, result = {}", i,
entries[i].operation, entries[i].length, result);
break;
}
default: {

View file

@ -95,6 +95,10 @@ s32 PS4_SYSV_ABI sceKernelMapFlexibleMemory(void** addr_in_out, std::size_t len,
int flags);
int PS4_SYSV_ABI sceKernelQueryMemoryProtection(void* addr, void** start, void** end, u32* prot);
int PS4_SYSV_ABI sceKernelMProtect(const void* addr, size_t size, int prot);
int PS4_SYSV_ABI sceKernelMTypeProtect(const void* addr, size_t size, int mtype, int prot);
int PS4_SYSV_ABI sceKernelDirectMemoryQuery(u64 offset, int flags, OrbisQueryInfo* query_info,
size_t infoSize);
s32 PS4_SYSV_ABI sceKernelAvailableFlexibleMemorySize(size_t* sizeOut);

View file

@ -414,11 +414,6 @@ ScePthreadMutex* createMutex(ScePthreadMutex* addr) {
if (addr == nullptr || *addr != nullptr) {
return addr;
}
static std::mutex mutex;
std::scoped_lock lk{mutex};
if (*addr != nullptr) {
return addr;
}
const VAddr vaddr = reinterpret_cast<VAddr>(addr);
std::string name = fmt::format("mutex{:#x}", vaddr);
scePthreadMutexInit(addr, nullptr, name.c_str());
@ -584,8 +579,7 @@ int PS4_SYSV_ABI scePthreadMutexLock(ScePthreadMutex* mutex) {
}
int PS4_SYSV_ABI scePthreadMutexUnlock(ScePthreadMutex* mutex) {
mutex = createMutex(mutex);
if (mutex == nullptr) {
if (mutex == nullptr || *mutex == nullptr) {
return SCE_KERNEL_ERROR_EINVAL;
}

View file

@ -10,8 +10,12 @@ class SymbolsResolver;
}
// Define our own htonll and ntohll because its not available in some systems/platforms
#ifndef HTONLL
#define HTONLL(x) (((uint64_t)htonl((x) & 0xFFFFFFFFUL)) << 32) | htonl((uint32_t)((x) >> 32))
#endif
#ifndef NTOHLL
#define NTOHLL(x) (((uint64_t)ntohl((x) & 0xFFFFFFFFUL)) << 32) | ntohl((uint32_t)((x) >> 32))
#endif
namespace Libraries::Net {

View file

@ -250,7 +250,7 @@ int PS4_SYSV_ABI scePadOpen(s32 userId, s32 type, s32 index, const OrbisPadOpenP
if (type != ORBIS_PAD_PORT_TYPE_SPECIAL)
return ORBIS_PAD_ERROR_DEVICE_NOT_CONNECTED;
} else {
if (type != ORBIS_PAD_PORT_TYPE_STANDARD)
if (type != ORBIS_PAD_PORT_TYPE_STANDARD && type != ORBIS_PAD_PORT_TYPE_REMOTE_CONTROL)
return ORBIS_PAD_ERROR_DEVICE_NOT_CONNECTED;
}
return 1; // dummy
@ -263,7 +263,7 @@ int PS4_SYSV_ABI scePadOpenExt(s32 userId, s32 type, s32 index,
if (type != ORBIS_PAD_PORT_TYPE_SPECIAL)
return ORBIS_PAD_ERROR_DEVICE_NOT_CONNECTED;
} else {
if (type != ORBIS_PAD_PORT_TYPE_STANDARD)
if (type != ORBIS_PAD_PORT_TYPE_STANDARD && type != ORBIS_PAD_PORT_TYPE_REMOTE_CONTROL)
return ORBIS_PAD_ERROR_DEVICE_NOT_CONNECTED;
}
return 1; // dummy

View file

@ -16,6 +16,7 @@ constexpr int ORBIS_PAD_MAX_DEVICE_UNIQUE_DATA_SIZE = 12;
constexpr int ORBIS_PAD_PORT_TYPE_STANDARD = 0;
constexpr int ORBIS_PAD_PORT_TYPE_SPECIAL = 2;
constexpr int ORBIS_PAD_PORT_TYPE_REMOTE_CONTROL = 16;
enum OrbisPadDeviceClass {
ORBIS_PAD_DEVICE_CLASS_INVALID = -1,

View file

@ -7,6 +7,7 @@
#include "core/libraries/error_codes.h"
#include "core/libraries/kernel/memory_management.h"
#include "core/memory.h"
#include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_rasterizer.h"
namespace Core {
@ -292,6 +293,118 @@ int MemoryManager::QueryProtection(VAddr addr, void** start, void** end, u32* pr
return ORBIS_OK;
}
int MemoryManager::Protect(VAddr addr, size_t size, MemoryProt prot) {
std::scoped_lock lk{mutex};
// Find the virtual memory area that contains the specified address range.
auto it = FindVMA(addr);
if (it == vma_map.end() || !it->second.Contains(addr, size)) {
LOG_ERROR(Core, "Address range not mapped");
return ORBIS_KERNEL_ERROR_EINVAL;
}
VirtualMemoryArea& vma = it->second;
if (vma.type == VMAType::Free) {
LOG_ERROR(Core, "Cannot change protection on free memory region");
return ORBIS_KERNEL_ERROR_EINVAL;
}
// Validate protection flags
constexpr static MemoryProt valid_flags = MemoryProt::NoAccess | MemoryProt::CpuRead |
MemoryProt::CpuReadWrite | MemoryProt::GpuRead |
MemoryProt::GpuWrite | MemoryProt::GpuReadWrite;
MemoryProt invalid_flags = prot & ~valid_flags;
if (u32(invalid_flags) != 0 && u32(invalid_flags) != u32(MemoryProt::NoAccess)) {
LOG_ERROR(Core, "Invalid protection flags: prot = {:#x}, invalid flags = {:#x}", u32(prot),
u32(invalid_flags));
return ORBIS_KERNEL_ERROR_EINVAL;
}
// Change protection
vma.prot = prot;
// Set permissions
Core::MemoryPermission perms{};
if (True(prot & MemoryProt::CpuRead)) {
perms |= Core::MemoryPermission::Read;
}
if (True(prot & MemoryProt::CpuReadWrite)) {
perms |= Core::MemoryPermission::ReadWrite;
}
if (True(prot & MemoryProt::GpuRead)) {
perms |= Core::MemoryPermission::Read;
}
if (True(prot & MemoryProt::GpuWrite)) {
perms |= Core::MemoryPermission::Write;
}
if (True(prot & MemoryProt::GpuReadWrite)) {
perms |= Core::MemoryPermission::ReadWrite;
}
impl.Protect(addr, size, perms);
return ORBIS_OK;
}
int MemoryManager::MTypeProtect(VAddr addr, size_t size, VMAType mtype, MemoryProt prot) {
std::scoped_lock lk{mutex};
// Find the virtual memory area that contains the specified address range.
auto it = FindVMA(addr);
if (it == vma_map.end() || !it->second.Contains(addr, size)) {
LOG_ERROR(Core, "Address range not mapped");
return ORBIS_KERNEL_ERROR_EINVAL;
}
VirtualMemoryArea& vma = it->second;
if (vma.type == VMAType::Free) {
LOG_ERROR(Core, "Cannot change protection on free memory region");
return ORBIS_KERNEL_ERROR_EINVAL;
}
// Validate protection flags
constexpr static MemoryProt valid_flags = MemoryProt::NoAccess | MemoryProt::CpuRead |
MemoryProt::CpuReadWrite | MemoryProt::GpuRead |
MemoryProt::GpuWrite | MemoryProt::GpuReadWrite;
MemoryProt invalid_flags = prot & ~valid_flags;
if (u32(invalid_flags) != 0 && u32(invalid_flags) != u32(MemoryProt::NoAccess)) {
LOG_ERROR(Core, "Invalid protection flags: prot = {:#x}, invalid flags = {:#x}", u32(prot),
u32(invalid_flags));
return ORBIS_KERNEL_ERROR_EINVAL;
}
// Change type and protection
vma.type = mtype;
vma.prot = prot;
// Set permissions
Core::MemoryPermission perms{};
if (True(prot & MemoryProt::CpuRead)) {
perms |= Core::MemoryPermission::Read;
}
if (True(prot & MemoryProt::CpuReadWrite)) {
perms |= Core::MemoryPermission::ReadWrite;
}
if (True(prot & MemoryProt::GpuRead)) {
perms |= Core::MemoryPermission::Read;
}
if (True(prot & MemoryProt::GpuWrite)) {
perms |= Core::MemoryPermission::Write;
}
if (True(prot & MemoryProt::GpuReadWrite)) {
perms |= Core::MemoryPermission::ReadWrite;
}
impl.Protect(addr, size, perms);
return ORBIS_OK;
}
int MemoryManager::VirtualQuery(VAddr addr, int flags,
::Libraries::Kernel::OrbisVirtualQueryInfo* info) {
std::scoped_lock lk{mutex};

View file

@ -30,6 +30,7 @@ enum class MemoryProt : u32 {
GpuWrite = 32,
GpuReadWrite = 38,
};
DECLARE_ENUM_FLAG_OPERATORS(MemoryProt)
enum class MemoryMapFlags : u32 {
NoFlags = 0,
@ -163,6 +164,10 @@ public:
int QueryProtection(VAddr addr, void** start, void** end, u32* prot);
int Protect(VAddr addr, size_t size, MemoryProt prot);
int MTypeProtect(VAddr addr, size_t size, VMAType mtype, MemoryProt prot);
int VirtualQuery(VAddr addr, int flags, ::Libraries::Kernel::OrbisVirtualQueryInfo* info);
int DirectMemoryQuery(PAddr addr, bool find_next,

View file

@ -31,14 +31,8 @@ GameListFrame::GameListFrame(std::shared_ptr<GameInfoClass> game_info_get, QWidg
this->setColumnWidth(5, 90); // Size
this->setColumnWidth(6, 90); // Version
QStringList headers;
headers << "Icon"
<< "Name"
<< "Serial"
<< "Region"
<< "Firmware"
<< "Size"
<< "Version"
<< "Path";
headers << tr("Icon") << tr("Name") << tr("Serial") << tr("Region") << tr("Firmware")
<< tr("Size") << tr("Version") << tr("Path");
this->setHorizontalHeaderLabels(headers);
this->horizontalHeader()->setSortIndicatorShown(true);
this->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents);

View file

@ -34,12 +34,12 @@ bool MainWindow::Init() {
CreateActions();
CreateRecentGameActions();
ConfigureGuiFromSettings();
LoadTranslation();
CreateDockWindows();
CreateConnects();
SetLastUsedTheme();
SetLastIconSizeBullet();
GetPhysicalDevices();
LoadTranslation();
// show ui
setMinimumSize(350, minimumSizeHint().height());
setWindowTitle(QString::fromStdString("shadPS4 v" + std::string(Common::VERSION)));
@ -103,7 +103,7 @@ void MainWindow::CreateDockWindows() {
QWidget* phCentralWidget = new QWidget(this);
setCentralWidget(phCentralWidget);
m_dock_widget.reset(new QDockWidget("Game List", this));
m_dock_widget.reset(new QDockWidget(tr("Game List"), this));
m_game_list_frame.reset(new GameListFrame(m_game_info, this));
m_game_list_frame->setObjectName("gamelist");
m_game_grid_frame.reset(new GameGridFrame(m_game_info, this));

View file

@ -80,9 +80,13 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices, QWidge
}
});
connect(ui->tabWidgetSettings, &QTabWidget::currentChanged, this, [this]() {
ui->buttonBox->button(QDialogButtonBox::StandardButton::Close)->setFocus();
});
ui->buttonBox->button(QDialogButtonBox::Save)->setText(tr("Save"));
ui->buttonBox->button(QDialogButtonBox::Apply)->setText(tr("Apply"));
ui->buttonBox->button(QDialogButtonBox::RestoreDefaults)->setText(tr("Restore Defaults"));
ui->buttonBox->button(QDialogButtonBox::Close)->setText(tr("Close"));
connect(ui->tabWidgetSettings, &QTabWidget::currentChanged, this,
[this]() { ui->buttonBox->button(QDialogButtonBox::Close)->setFocus(); });
// GENERAL TAB
{

View file

@ -502,6 +502,11 @@
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../main_window.cpp" line="106"/>
<source>Game List</source>
<translation>ققائمة الألعاب</translation>
</message>
<message>
<location filename="../main_window.cpp" line="168"/>
<source> * Unsupported Vulkan Version</source>
@ -864,7 +869,7 @@
<message>
<location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source>
<translation>تم تنزيل التصحيحات بنجاح! تم تنزيل جميع التصحيحات لجميع الألعاب، ولا داعي لتنزيلها بشكل فردي لكل لعبة كما هو الحال مع الغش.</translation>
<translation>تم تنزيل التصحيحات بنجاح! تم تنزيل جميع التصحيحات لجميع الألعاب، ولا داعي لتنزيلها بشكل فردي لكل لعبة كما هو الحال مع الغش. إذا لم يظهر التحديث، قد يكون السبب أنه غير متوفر للإصدار وسيريال اللعبة المحدد. قد تحتاج إلى تحديث اللعبة.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="773"/>
@ -911,5 +916,76 @@
<source>Name:</source>
<translation>:الاسم</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="1163"/>
<source>Can't apply cheats before the game is started</source>
<translation>لا يمكن تطبيق الغش قبل بدء اللعبة.</translation>
</message>
</context>
<context>
<name>SettingsDialog</name>
<message>
<location filename="../settings_dialog.cpp" line="83"/>
<source>Save</source>
<translation>حفظ</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="84"/>
<source>Apply</source>
<translation>تطبيق</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="85"/>
<source>Restore Defaults</source>
<translation>استعادة الإعدادات الافتراضية</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="86"/>
<source>Close</source>
<translation>إغلاق</translation>
</message>
</context>
<context>
<name>GameListFrame</name>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Icon</source>
<translation>أيقونة</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Name</source>
<translation>اسم</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Serial</source>
<translation>سيريال</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source>
<translation>منطقة</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Firmware</source>
<translation>البرمجيات الثابتة</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Size</source>
<translation>حجم</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Version</source>
<translation>إصدار</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Path</source>
<translation>مسار</translation>
</message>
</context>
</TS>

View file

@ -500,6 +500,11 @@
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../main_window.cpp" line="106"/>
<source>Game List</source>
<translation>Spiloversigt</translation>
</message>
<message>
<location filename="../main_window.cpp" line="168"/>
<source> * Unsupported Vulkan Version</source>
@ -851,7 +856,7 @@
<message>
<location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source>
<translation>Patcher hentet med succes! Alle patches til alle spil er blevet hentet, der er ikke behov for at hente dem individuelt for hvert spil, som det sker med snyd.</translation>
<translation>Patcher hentet med succes! Alle patches til alle spil er blevet hentet, der er ikke behov for at hente dem individuelt for hvert spil, som det sker med snyd. Hvis opdateringen ikke vises, kan det være, at den ikke findes for den specifikke serie og version af spillet. Det kan være nødvendigt at opdatere spillet.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="773"/>
@ -898,5 +903,76 @@
<source>Name:</source>
<translation>Navn:</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="1163"/>
<source>Can't apply cheats before the game is started</source>
<translation>Kan ikke anvende snyd før spillet er startet.</translation>
</message>
</context>
<context>
<name>SettingsDialog</name>
<message>
<location filename="../settings_dialog.cpp" line="83"/>
<source>Save</source>
<translation>Gem</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="84"/>
<source>Apply</source>
<translation>Anvend</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="85"/>
<source>Restore Defaults</source>
<translation>Gendan standardindstillinger</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="86"/>
<source>Close</source>
<translation>Luk</translation>
</message>
</context>
<context>
<name>GameListFrame</name>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Icon</source>
<translation>Ikon</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Name</source>
<translation>Navn</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Serial</source>
<translation>Seriel</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source>
<translation>Region</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Firmware</source>
<translation>Firmware</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Size</source>
<translation>Størrelse</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Version</source>
<translation>Version</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Path</source>
<translation>Sti</translation>
</message>
</context>
</TS>

View file

@ -500,6 +500,11 @@
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../main_window.cpp" line="106"/>
<source>Game List</source>
<translation>Spieleliste</translation>
</message>
<message>
<location filename="../main_window.cpp" line="168"/>
<source> * Unsupported Vulkan Version</source>
@ -851,7 +856,7 @@
<message>
<location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source>
<translation>Patches erfolgreich heruntergeladen! Alle Patches für alle Spiele wurden heruntergeladen, es ist nicht notwendig, sie einzeln für jedes Spiel herunterzuladen, wie es bei Cheats der Fall ist.</translation>
<translation>Patches erfolgreich heruntergeladen! Alle Patches für alle Spiele wurden heruntergeladen, es ist nicht notwendig, sie einzeln für jedes Spiel herunterzuladen, wie es bei Cheats der Fall ist. Wenn der Patch nicht angezeigt wird, könnte es sein, dass er für die spezifische Seriennummer und Version des Spiels nicht existiert. Möglicherweise müssen Sie das Spiel aktualisieren.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="773"/>
@ -898,5 +903,76 @@
<source>Name:</source>
<translation>Name:</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="1163"/>
<source>Can't apply cheats before the game is started</source>
<translation>Kann keine Cheats anwenden, bevor das Spiel gestartet ist.</translation>
</message>
</context>
<context>
<name>SettingsDialog</name>
<message>
<location filename="../settings_dialog.cpp" line="83"/>
<source>Save</source>
<translation>Speichern</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="84"/>
<source>Apply</source>
<translation>Übernehmen</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="85"/>
<source>Restore Defaults</source>
<translation>Werkseinstellungen wiederherstellen</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="86"/>
<source>Close</source>
<translation>Schließen</translation>
</message>
</context>
<context>
<name>GameListFrame</name>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Icon</source>
<translation>Symbol</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Name</source>
<translation>Name</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Serial</source>
<translation>Seriennummer</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source>
<translation>Region</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Firmware</source>
<translation>Firmware</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Size</source>
<translation>Größe</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Version</source>
<translation>Version</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Path</source>
<translation>Pfad</translation>
</message>
</context>
</TS>

View file

@ -500,6 +500,11 @@
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../main_window.cpp" line="106"/>
<source>Game List</source>
<translation>Λίστα παιχνιδιών</translation>
</message>
<message>
<location filename="../main_window.cpp" line="168"/>
<source> * Unsupported Vulkan Version</source>
@ -851,7 +856,7 @@
<message>
<location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source>
<translation>Τα Patches κατεβάστηκαν επιτυχώς! Όλα τα Patches για όλα τα παιχνίδια έχουν κατέβει, δεν είναι απαραίτητο να τα κατεβάσετε ένα-ένα για κάθε παιχνίδι, όπως με τα Cheats.</translation>
<translation>Τα Patches κατεβάστηκαν επιτυχώς! Όλα τα Patches για όλα τα παιχνίδια έχουν κατέβει, δεν είναι απαραίτητο να τα κατεβάσετε ένα-ένα για κάθε παιχνίδι, όπως με τα Cheats. Εάν η ενημέρωση δεν εμφανίζεται, μπορεί να μην υπάρχει για τον συγκεκριμένο σειριακό αριθμό και έκδοση του παιχνιδιού. Μπορεί να χρειαστεί να ενημερώσετε το παιχνίδι.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="773"/>
@ -898,5 +903,76 @@
<source>Name:</source>
<translation>Όνομα:</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="1163"/>
<source>Can't apply cheats before the game is started</source>
<translation>Δεν μπορείτε να εφαρμόσετε cheats πριν ξεκινήσει το παιχνίδι.</translation>
</message>
</context>
<context>
<name>SettingsDialog</name>
<message>
<location filename="../settings_dialog.cpp" line="83"/>
<source>Save</source>
<translation>Αποθήκευση</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="84"/>
<source>Apply</source>
<translation>Εφαρμογή</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="85"/>
<source>Restore Defaults</source>
<translation>Επαναφορά Προεπιλογών</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="86"/>
<source>Close</source>
<translation>Κλείσιμο</translation>
</message>
</context>
<context>
<name>GameListFrame</name>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Icon</source>
<translation>Εικονίδιο</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Name</source>
<translation>Όνομα</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Serial</source>
<translation>Σειριακός αριθμός</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source>
<translation>Περιοχή</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Firmware</source>
<translation>Λογισμικό</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Size</source>
<translation>Μέγεθος</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Version</source>
<translation>Έκδοση</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Path</source>
<translation>Διαδρομή</translation>
</message>
</context>
</TS>

View file

@ -500,6 +500,11 @@
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../main_window.cpp" line="106"/>
<source>Game List</source>
<translation>Game List</translation>
</message>
<message>
<location filename="../main_window.cpp" line="168"/>
<source> * Unsupported Vulkan Version</source>
@ -851,7 +856,7 @@
<message>
<location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source>
<translation>Patches Downloaded Successfully! All Patches available for all games have been downloaded, there is no need to download them individually for each game as happens in Cheats.</translation>
<translation>Patches Downloaded Successfully! All Patches available for all games have been downloaded, there is no need to download them individually for each game as happens in Cheats. If the patch does not appear, it may be that it does not exist for the specific serial and version of the game. It may be necessary to update the game.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="773"/>
@ -898,5 +903,76 @@
<source>Name:</source>
<translation>Name:</translation>
</message>
</context>
<message>
<location filename="../cheats_patches.cpp" line="1163"/>
<source>Can't apply cheats before the game is started</source>
<translation>Can't apply cheats before the game is started.</translation>
</message>
</context>
<context>
<name>SettingsDialog</name>
<message>
<location filename="../settings_dialog.cpp" line="83"/>
<source>Save</source>
<translation>Save</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="84"/>
<source>Apply</source>
<translation>Apply</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="85"/>
<source>Restore Defaults</source>
<translation>Restore Defaults</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="86"/>
<source>Close</source>
<translation>Close</translation>
</message>
</context>
<context>
<name>GameListFrame</name>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Icon</source>
<translation>Icon</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Name</source>
<translation>Name</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Serial</source>
<translation>Serial</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source>
<translation>Region</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Firmware</source>
<translation>Firmware</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Size</source>
<translation>Size</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Version</source>
<translation>Version</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Path</source>
<translation>Path</translation>
</message>
</context>
</TS>

View file

@ -500,6 +500,11 @@
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../main_window.cpp" line="106"/>
<source>Game List</source>
<translation>Lista de juegos</translation>
</message>
<message>
<location filename="../main_window.cpp" line="168"/>
<source> * Unsupported Vulkan Version</source>
@ -851,7 +856,7 @@
<message>
<location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source>
<translation>¡Parches descargados exitosamente! Todos los parches disponibles para todos los juegos han sido descargados, no es necesario descargarlos individualmente para cada juego como ocurre con los trucos.</translation>
<translation>¡Parches descargados exitosamente! Todos los parches disponibles para todos los juegos han sido descargados, no es necesario descargarlos individualmente para cada juego como ocurre con los trucos. Si el parche no aparece, puede ser que no exista para el número de serie y versión específicos del juego. Puede ser necesario actualizar el juego.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="773"/>
@ -898,5 +903,76 @@
<source>Name:</source>
<translation>Nombre:</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="1163"/>
<source>Can't apply cheats before the game is started</source>
<translation>No se pueden aplicar trucos antes de que se inicie el juego.</translation>
</message>
</context>
<context>
<name>SettingsDialog</name>
<message>
<location filename="../settings_dialog.cpp" line="83"/>
<source>Save</source>
<translation>Guardar</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="84"/>
<source>Apply</source>
<translation>Aplicar</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="85"/>
<source>Restore Defaults</source>
<translation>Restaurar Valores Predeterminados</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="86"/>
<source>Close</source>
<translation>Cerrar</translation>
</message>
</context>
<context>
<name>GameListFrame</name>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Icon</source>
<translation>Ícono</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Name</source>
<translation>Nombre</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Serial</source>
<translation>Serie</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source>
<translation>Región</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Firmware</source>
<translation>Firmware</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Size</source>
<translation>Tamaño</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Version</source>
<translation>Versión</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Path</source>
<translation>Ruta</translation>
</message>
</context>
</TS>

File diff suppressed because it is too large Load diff

View file

@ -500,6 +500,11 @@
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../main_window.cpp" line="106"/>
<source>Game List</source>
<translation>Pelilista</translation>
</message>
<message>
<location filename="../main_window.cpp" line="168"/>
<source> * Unsupported Vulkan Version</source>
@ -851,7 +856,7 @@
<message>
<location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source>
<translation>Korjaukset ladattu onnistuneesti! Kaikki saatavilla olevat korjaukset kaikille peleille on ladattu, eikä niitä tarvitse ladata yksittäin jokaiselle pelille kuten huijauksissa.</translation>
<translation>Korjaukset ladattu onnistuneesti! Kaikki saatavilla olevat korjaukset kaikille peleille on ladattu, eikä niitä tarvitse ladata yksittäin jokaiselle pelille kuten huijauksissa. Jos päivitystä ei näy, se saattaa olla, että sitä ei ole saatavilla tietylle sarjanumerolle ja peliversiolle. Saattaa olla tarpeen päivittää peli.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="773"/>
@ -898,5 +903,76 @@
<source>Name:</source>
<translation>Nimi:</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="1163"/>
<source>Can't apply cheats before the game is started</source>
<translation>Ei voi käyttää huijauksia ennen kuin peli on aloitettu.</translation>
</message>
</context>
<context>
<name>SettingsDialog</name>
<message>
<location filename="../settings_dialog.cpp" line="83"/>
<source>Save</source>
<translation>Tallenna</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="84"/>
<source>Apply</source>
<translation>Ota käyttöön</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="85"/>
<source>Restore Defaults</source>
<translation>Palauta oletukset</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="86"/>
<source>Close</source>
<translation>Sulje</translation>
</message>
</context>
<context>
<name>GameListFrame</name>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Icon</source>
<translation>Ikoni</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Name</source>
<translation>Nimi</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Serial</source>
<translation>Sarjanumero</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source>
<translation>Alue</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Firmware</source>
<translation>Ohjelmisto</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Size</source>
<translation>Koko</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Version</source>
<translation>Versio</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Path</source>
<translation>Polku</translation>
</message>
</context>
</TS>

View file

@ -500,6 +500,11 @@
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../main_window.cpp" line="106"/>
<source>Game List</source>
<translation>Liste de jeux</translation>
</message>
<message>
<location filename="../main_window.cpp" line="168"/>
<source> * Unsupported Vulkan Version</source>
@ -851,7 +856,7 @@
<message>
<location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source>
<translation>Patchs téléchargés avec succès ! Tous les patches disponibles pour tous les jeux ont é téléchargés, il n'est pas nécessaire de les télécharger individuellement pour chaque jeu comme c'est le cas pour les Cheats.</translation>
<translation>Patchs téléchargés avec succès ! Tous les patches disponibles pour tous les jeux ont é téléchargés, il n'est pas nécessaire de les télécharger individuellement pour chaque jeu comme c'est le cas pour les Cheats. Si le correctif n'apparaît pas, il se peut qu'il n'existe pas pour le numéro de série et la version spécifiques du jeu. Il peut être nécessaire de mettre à jour le jeu.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="773"/>
@ -898,5 +903,76 @@
<source>Name:</source>
<translation>Nom :</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="1163"/>
<source>Can't apply cheats before the game is started</source>
<translation>Impossible d'appliquer les triches avant que le jeu ne commence.</translation>
</message>
</context>
</TS>
<context>
<name>SettingsDialog</name>
<message>
<location filename="../settings_dialog.cpp" line="83"/>
<source>Save</source>
<translation>Enregistrer</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="84"/>
<source>Apply</source>
<translation>Appliquer</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="85"/>
<source>Restore Defaults</source>
<translation>Restaurer les paramètres par défaut</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="86"/>
<source>Close</source>
<translation>Fermer</translation>
</message>
</context>
<context>
<name>GameListFrame</name>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Icon</source>
<translation>Icône</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Name</source>
<translation>Nom</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Serial</source>
<translation>Série</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source>
<translation>Région</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Firmware</source>
<translation>Firmware</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Size</source>
<translation>Taille</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Version</source>
<translation>Version</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Path</source>
<translation>Chemin</translation>
</message>
</context>
</TS>

View file

@ -500,6 +500,11 @@
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../main_window.cpp" line="106"/>
<source>Game List</source>
<translation>Játéklista</translation>
</message>
<message>
<location filename="../main_window.cpp" line="168"/>
<source> * Unsupported Vulkan Version</source>
@ -851,7 +856,7 @@
<message>
<location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source>
<translation>Frissítések sikeresen letöltve! Minden elérhető frissítés letöltésre került, nem szükséges egyesével letölteni őket minden játékhoz, mint a csalások esetében.</translation>
<translation>Frissítések sikeresen letöltve! Minden elérhető frissítés letöltésre került, nem szükséges egyesével letölteni őket minden játékhoz, mint a csalások esetében. Ha a javítás nem jelenik meg, lehet, hogy nem létezik a játék adott sorozatszámához és verziójához. Lehet, hogy frissítenie kell a játékot.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="773"/>
@ -898,5 +903,76 @@
<source>Name:</source>
<translation>Név:</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="1163"/>
<source>Can't apply cheats before the game is started</source>
<translation>Nem lehet csalásokat alkalmazni, mielőtt a játék elindul.</translation>
</message>
</context>
<context>
<name>SettingsDialog</name>
<message>
<location filename="../settings_dialog.cpp" line="83"/>
<source>Save</source>
<translation>Mentés</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="84"/>
<source>Apply</source>
<translation>Alkalmaz</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="85"/>
<source>Restore Defaults</source>
<translation>Alapértelmezett értékek visszaállítása</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="86"/>
<source>Close</source>
<translation>Bezárás</translation>
</message>
</context>
<context>
<name>GameListFrame</name>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Icon</source>
<translation>Ikon</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Name</source>
<translation>Név</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Serial</source>
<translation>Sorozatszám</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source>
<translation>Régió</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Firmware</source>
<translation>Firmware</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Size</source>
<translation>Méret</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Version</source>
<translation>Verzió</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Path</source>
<translation>Útvonal</translation>
</message>
</context>
</TS>

View file

@ -500,6 +500,11 @@
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../main_window.cpp" line="106"/>
<source>Game List</source>
<translation>Daftar game</translation>
</message>
<message>
<location filename="../main_window.cpp" line="168"/>
<source> * Unsupported Vulkan Version</source>
@ -851,7 +856,7 @@
<message>
<location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source>
<translation>Patch Berhasil Diunduh! Semua Patch yang tersedia untuk semua game telah diunduh, tidak perlu mengunduhnya satu per satu seperti yang terjadi pada Cheat.</translation>
<translation>Patch Berhasil Diunduh! Semua Patch yang tersedia untuk semua game telah diunduh, tidak perlu mengunduhnya satu per satu seperti yang terjadi pada Cheat. Jika patch tidak muncul, mungkin patch tersebut tidak ada untuk nomor seri dan versi game yang spesifik. Mungkin perlu memperbarui game.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="773"/>
@ -898,5 +903,76 @@
<source>Name:</source>
<translation>Nama:</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="1163"/>
<source>Can't apply cheats before the game is started</source>
<translation>Tidak bisa menerapkan cheat sebelum permainan dimulai.</translation>
</message>
</context>
<context>
<name>SettingsDialog</name>
<message>
<location filename="../settings_dialog.cpp" line="83"/>
<source>Save</source>
<translation>Simpan</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="84"/>
<source>Apply</source>
<translation>Terapkan</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="85"/>
<source>Restore Defaults</source>
<translation>Kembalikan Pengaturan Default</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="86"/>
<source>Close</source>
<translation>Tutup</translation>
</message>
</context>
<context>
<name>GameListFrame</name>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Icon</source>
<translation>Ikon</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Name</source>
<translation>Nama</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Serial</source>
<translation>Serial</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source>
<translation>Wilayah</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Firmware</source>
<translation>Firmware</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Size</source>
<translation>Ukuran</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Version</source>
<translation>Versi</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Path</source>
<translation>Jalur</translation>
</message>
</context>
</TS>

View file

@ -500,6 +500,11 @@
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../main_window.cpp" line="106"/>
<source>Game List</source>
<translation>Elenco giochi</translation>
</message>
<message>
<location filename="../main_window.cpp" line="168"/>
<source> * Unsupported Vulkan Version</source>
@ -851,7 +856,7 @@
<message>
<location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source>
<translation>Patch scaricata con successo! Vengono scaricate tutte le patch disponibili per tutti i giochi, non è necessario scaricarle singolarmente per ogni gioco come nel caso dei trucchi.</translation>
<translation>Patch scaricata con successo! Vengono scaricate tutte le patch disponibili per tutti i giochi, non è necessario scaricarle singolarmente per ogni gioco come nel caso dei trucchi. Se la patch non appare, potrebbe essere che non esista per il numero di serie e la versione specifica del gioco. Potrebbe essere necessario aggiornare il gioco.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="773"/>
@ -898,5 +903,76 @@
<source>Name:</source>
<translation>Nome:</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="1163"/>
<source>Can't apply cheats before the game is started</source>
<translation>Non è possibile applicare i trucchi prima dell'inizio del gioco.</translation>
</message>
</context>
<context>
<name>SettingsDialog</name>
<message>
<location filename="../settings_dialog.cpp" line="83"/>
<source>Save</source>
<translation>Salva</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="84"/>
<source>Apply</source>
<translation>Applica</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="85"/>
<source>Restore Defaults</source>
<translation>Ripristina Impostazioni Predefinite</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="86"/>
<source>Close</source>
<translation>Chiudi</translation>
</message>
</context>
<context>
<name>GameListFrame</name>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Icon</source>
<translation>Icona</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Name</source>
<translation>Nome</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Serial</source>
<translation>Seriale</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source>
<translation>Regione</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Firmware</source>
<translation>Firmware</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Size</source>
<translation>Dimensione</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Version</source>
<translation>Versione</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Path</source>
<translation>Percorso</translation>
</message>
</context>
</TS>

View file

@ -500,6 +500,11 @@
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../main_window.cpp" line="106"/>
<source>Game List</source>
<translation></translation>
</message>
<message>
<location filename="../main_window.cpp" line="168"/>
<source> * Unsupported Vulkan Version</source>
@ -851,7 +856,7 @@
<message>
<location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source>
<translation> </translation>
<translation> </translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="773"/>
@ -898,5 +903,76 @@
<source>Name:</source>
<translation>:</translation>
</message>
</context>
<message>
<location filename="../cheats_patches.cpp" line="1163"/>
<source>Can't apply cheats before the game is started</source>
<translation></translation>
</message>
</context>
<context>
<name>SettingsDialog</name>
<message>
<location filename="../settings_dialog.cpp" line="83"/>
<source>Save</source>
<translation></translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="84"/>
<source>Apply</source>
<translation></translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="85"/>
<source>Restore Defaults</source>
<translation></translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="86"/>
<source>Close</source>
<translation></translation>
</message>
</context>
<context>
<name>GameListFrame</name>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Icon</source>
<translation></translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Name</source>
<translation></translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Serial</source>
<translation></translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source>
<translation></translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Firmware</source>
<translation></translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Size</source>
<translation></translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Version</source>
<translation></translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Path</source>
<translation></translation>
</message>
</context>
</TS>

View file

@ -500,6 +500,11 @@
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../main_window.cpp" line="106"/>
<source>Game List</source>
<translation>Game List</translation>
</message>
<message>
<location filename="../main_window.cpp" line="168"/>
<source> * Unsupported Vulkan Version</source>
@ -851,7 +856,7 @@
<message>
<location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source>
<translation>Patches Downloaded Successfully! All Patches available for all games have been downloaded, there is no need to download them individually for each game as happens in Cheats.</translation>
<translation>Patches Downloaded Successfully! All Patches available for all games have been downloaded, there is no need to download them individually for each game as happens in Cheats. If the patch does not appear, it may be that it does not exist for the specific serial and version of the game. It may be necessary to update the game.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="773"/>
@ -898,5 +903,76 @@
<source>Name:</source>
<translation>Name:</translation>
</message>
</context>
<message>
<location filename="../cheats_patches.cpp" line="1163"/>
<source>Can't apply cheats before the game is started</source>
<translation>Can't apply cheats before the game is started.</translation>
</message>
</context>
<context>
<name>SettingsDialog</name>
<message>
<location filename="../settings_dialog.cpp" line="83"/>
<source>Save</source>
<translation>Save</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="84"/>
<source>Apply</source>
<translation>Apply</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="85"/>
<source>Restore Defaults</source>
<translation>Restore Defaults</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="86"/>
<source>Close</source>
<translation>Close</translation>
</message>
</context>
<context>
<name>GameListFrame</name>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Icon</source>
<translation>Icon</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Name</source>
<translation>Name</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Serial</source>
<translation>Serial</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source>
<translation>Region</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Firmware</source>
<translation>Firmware</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Size</source>
<translation>Size</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Version</source>
<translation>Version</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Path</source>
<translation>Path</translation>
</message>
</context>
</TS>

View file

@ -500,6 +500,11 @@
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../main_window.cpp" line="106"/>
<source>Game List</source>
<translation>Žaidimų sąrašas</translation>
</message>
<message>
<location filename="../main_window.cpp" line="168"/>
<source> * Unsupported Vulkan Version</source>
@ -851,7 +856,7 @@
<message>
<location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source>
<translation>Pataisos sėkmingai atsisiųstos! Visos pataisos visiems žaidimams buvo atsisiųstos, nebėra reikalo jas atsisiųsti atskirai kiekvienam žaidimui, kaip tai vyksta su sukčiavimais.</translation>
<translation>Pataisos sėkmingai atsisiųstos! Visos pataisos visiems žaidimams buvo atsisiųstos, nebėra reikalo jas atsisiųsti atskirai kiekvienam žaidimui, kaip tai vyksta su sukčiavimais. Jei pleistras nepasirodo, gali būti, kad jo nėra tam tikram žaidimo serijos numeriui ir versijai. Gali prireikti atnaujinti žaidimą.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="773"/>
@ -898,5 +903,76 @@
<source>Name:</source>
<translation>Pavadinimas:</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="1163"/>
<source>Can't apply cheats before the game is started</source>
<translation>Negalima taikyti sukčiavimų prieš pradedant žaidimą.</translation>
</message>
</context>
<context>
<name>SettingsDialog</name>
<message>
<location filename="../settings_dialog.cpp" line="83"/>
<source>Save</source>
<translation>Įrašyti</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="84"/>
<source>Apply</source>
<translation>Taikyti</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="85"/>
<source>Restore Defaults</source>
<translation>Atkurti numatytuosius nustatymus</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="86"/>
<source>Close</source>
<translation>Uždaryti</translation>
</message>
</context>
<context>
<name>GameListFrame</name>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Icon</source>
<translation>Ikona</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Name</source>
<translation>Vardas</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Serial</source>
<translation>Serijinis numeris</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source>
<translation>Regionas</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Firmware</source>
<translation>Firmvare</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Size</source>
<translation>Dydis</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Version</source>
<translation>Versija</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Path</source>
<translation>Kelias</translation>
</message>
</context>
</TS>

View file

@ -500,6 +500,11 @@
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../main_window.cpp" line="106"/>
<source>Game List</source>
<translation>Spilliste</translation>
</message>
<message>
<location filename="../main_window.cpp" line="168"/>
<source> * Unsupported Vulkan Version</source>
@ -851,7 +856,7 @@
<message>
<location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source>
<translation>Oppdateringer lastet ned vellykket! Alle oppdateringer tilgjengelige for alle spill har blitt lastet ned, det er ikke nødvendig å laste dem ned individuelt for hvert spill som skjer med jukser.</translation>
<translation>Oppdateringer lastet ned vellykket! Alle oppdateringer tilgjengelige for alle spill har blitt lastet ned, det er ikke nødvendig å laste dem ned individuelt for hvert spill som skjer med jukser. Hvis oppdateringen ikke vises, kan det hende at den ikke finnes for den spesifikke serienummeret og versjonen av spillet. Det kan være nødvendig å oppdatere spillet.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="773"/>
@ -898,5 +903,76 @@
<source>Name:</source>
<translation>Navn:</translation>
</message>
</context>
<message>
<location filename="../cheats_patches.cpp" line="1163"/>
<source>Can't apply cheats before the game is started</source>
<translation>Kan ikke bruke juksetriks før spillet er startet.</translation>
</message>
</context>
<context>
<name>SettingsDialog</name>
<message>
<location filename="../settings_dialog.cpp" line="83"/>
<source>Save</source>
<translation>Lag</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="84"/>
<source>Apply</source>
<translation>Bruk</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="85"/>
<source>Restore Defaults</source>
<translation>Gjenopprett standardinnstillinger</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="86"/>
<source>Close</source>
<translation>Lukk</translation>
</message>
</context>
<context>
<name>GameListFrame</name>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Icon</source>
<translation>Ikon</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Name</source>
<translation>Navn</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Serial</source>
<translation>Serienummer</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source>
<translation>Region</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Firmware</source>
<translation>Firmware</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Size</source>
<translation>Størrelse</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Version</source>
<translation>Versjon</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Path</source>
<translation>Sti</translation>
</message>
</context>
</TS>

View file

@ -500,6 +500,11 @@
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../main_window.cpp" line="106"/>
<source>Game List</source>
<translation>Lijst met spellen</translation>
</message>
<message>
<location filename="../main_window.cpp" line="168"/>
<source> * Unsupported Vulkan Version</source>
@ -851,7 +856,7 @@
<message>
<location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source>
<translation>Patches succesvol gedownload! Alle beschikbare patches voor alle spellen zijn gedownload. Het is niet nodig om ze afzonderlijk te downloaden voor elk spel dat cheats heeft.</translation>
<translation>Patches succesvol gedownload! Alle beschikbare patches voor alle spellen zijn gedownload. Het is niet nodig om ze afzonderlijk te downloaden voor elk spel dat cheats heeft. Als de patch niet verschijnt, kan het zijn dat deze niet bestaat voor het specifieke serienummer en de versie van het spel. Het kan nodig zijn om het spel bij te werken.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="773"/>
@ -898,5 +903,76 @@
<source>Name:</source>
<translation>Naam:</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="1163"/>
<source>Can't apply cheats before the game is started</source>
<translation>Je kunt geen cheats toepassen voordat het spel is gestart.</translation>
</message>
</context>
<context>
<name>SettingsDialog</name>
<message>
<location filename="../settings_dialog.cpp" line="83"/>
<source>Save</source>
<translation>Opslaan</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="84"/>
<source>Apply</source>
<translation>Toepassen</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="85"/>
<source>Restore Defaults</source>
<translation>Standaardinstellingen herstellen</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="86"/>
<source>Close</source>
<translation>Sluiten</translation>
</message>
</context>
<context>
<name>GameListFrame</name>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Icon</source>
<translation>Pictogram</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Name</source>
<translation>Naam</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Serial</source>
<translation>Serienummer</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source>
<translation>Regio</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Firmware</source>
<translation>Firmware</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Size</source>
<translation>Grootte</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Version</source>
<translation>Versie</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Path</source>
<translation>Pad</translation>
</message>
</context>
</TS>

View file

@ -251,7 +251,7 @@
<message>
<location filename="../main_window_ui.h" line="343"/>
<source>Game Install Directory</source>
<translation>Katalog zainstalowanych gry</translation>
<translation>Katalog zainstalowanych gier</translation>
</message>
<message>
<location filename="../main_window_ui.h" line="343"/>
@ -500,6 +500,11 @@
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../main_window.cpp" line="106"/>
<source>Game List</source>
<translation>Lista gier</translation>
</message>
<message>
<location filename="../main_window.cpp" line="168"/>
<source> * Unsupported Vulkan Version</source>
@ -851,7 +856,7 @@
<message>
<location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source>
<translation>Poprawki zostały pomyślnie pobrane! Wszystkie dostępne poprawki dla wszystkich gier zostały pobrane. Nie ma potrzeby pobierania ich osobno dla każdej gry, która ma kody.</translation>
<translation>Poprawki zostały pomyślnie pobrane! Wszystkie dostępne poprawki dla wszystkich gier zostały pobrane. Nie ma potrzeby pobierania ich osobno dla każdej gry, która ma kody. Jeśli poprawka się nie pojawia, możliwe, że nie istnieje dla konkretnego numeru seryjnego i wersji gry. Może być konieczne zaktualizowanie gry.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="773"/>
@ -898,5 +903,76 @@
<source>Failed to parse JSON:</source>
<translation>Nie udało się przeanlizować JSON:</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="1163"/>
<source>Can't apply cheats before the game is started</source>
<translation>Nie można zastosować kodów przed uruchomieniem gry.</translation>
</message>
</context>
<context>
<name>SettingsDialog</name>
<message>
<location filename="../settings_dialog.cpp" line="83"/>
<source>Save</source>
<translation>Zapisz</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="84"/>
<source>Apply</source>
<translation>Zastosuj</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="85"/>
<source>Restore Defaults</source>
<translation>Przywróć ustawienia domyślne</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="86"/>
<source>Close</source>
<translation>Zamknij</translation>
</message>
</context>
<context>
<name>GameListFrame</name>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Icon</source>
<translation>Ikona</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Name</source>
<translation>Nazwa</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Serial</source>
<translation>Numer seryjny</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source>
<translation>Region</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Firmware</source>
<translation>Oprogramowanie</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Size</source>
<translation>Rozmiar</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Version</source>
<translation>Wersja</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Path</source>
<translation>Ścieżka</translation>
</message>
</context>
</TS>

View file

@ -500,6 +500,11 @@
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../main_window.cpp" line="106"/>
<source>Game List</source>
<translation>Lista de Jogos</translation>
</message>
<message>
<location filename="../main_window.cpp" line="168"/>
<source> * Unsupported Vulkan Version</source>
@ -851,7 +856,7 @@
<message>
<location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source>
<translation>Patches Baixados com Sucesso! Todos os patches disponíveis para todos os jogos foram baixados, não é necessário baixá-los individualmente para cada jogo como acontece com os Cheats.</translation>
<translation>Patches Baixados com Sucesso! Todos os patches disponíveis para todos os jogos foram baixados, não é necessário baixá-los individualmente para cada jogo como acontece com os Cheats. Se o patch não aparecer, pode ser que ele não exista para o número de série e a versão específicos do jogo. Pode ser necessário atualizar o jogo.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="773"/>
@ -897,6 +902,77 @@
<location filename="../cheats_patches.cpp" line="1006"/>
<source>Name:</source>
<translation>Nome:</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="1163"/>
<source>Can't apply cheats before the game is started</source>
<translation>Não é possível aplicar cheats antes que o jogo comece.</translation>
</message>
</context>
<context>
<name>SettingsDialog</name>
<message>
<location filename="../settings_dialog.cpp" line="83"/>
<source>Save</source>
<translation>Salvar</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="84"/>
<source>Apply</source>
<translation>Aplicar</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="85"/>
<source>Restore Defaults</source>
<translation>Restaurar Padrões</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="86"/>
<source>Close</source>
<translation>Fechar</translation>
</message>
</context>
<context>
<name>GameListFrame</name>
<message>
<location filename="../game_list_frame.cpp" line="33"/>
<source>Icon</source>
<translation>Icone</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Name</source>
<translation>Nome</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Serial</source>
<translation>Serial</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="36"/>
<source>Region</source>
<translation>Região</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Firmware</source>
<translation>Firmware</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Size</source>
<translation>Tamanho</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Version</source>
<translation>Versão</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Path</source>
<translation>Diretório</translation>
</message>
</context>
</TS>

View file

@ -499,6 +499,11 @@
</message>
</context>
<context>
<message>
<location filename="../main_window.cpp" line="106"/>
<source>Game List</source>
<translation>Lista jocurilor</translation>
</message>
<name>MainWindow</name>
<message>
<location filename="../main_window.cpp" line="168"/>
@ -851,7 +856,7 @@
<message>
<location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source>
<translation>Patches descărcate cu succes! Toate Patches disponibile pentru toate jocurile au fost descărcate; nu este nevoie le descarci individual pentru fiecare joc, așa cum se întâmplă cu Cheats.</translation>
<translation>Patches descărcate cu succes! Toate Patches disponibile pentru toate jocurile au fost descărcate; nu este nevoie le descarci individual pentru fiecare joc, așa cum se întâmplă cu Cheats. Dacă patch-ul nu apare, este posibil nu existe pentru seria și versiunea specifică a jocului. Poate fi necesar actualizați jocul.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="773"/>
@ -898,5 +903,76 @@
<source>Name:</source>
<translation>Nume:</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="1163"/>
<source>Can't apply cheats before the game is started</source>
<translation>Nu poți aplica cheats înainte ca jocul înceapă.</translation>
</message>
</context>
<context>
<name>SettingsDialog</name>
<message>
<location filename="../settings_dialog.cpp" line="83"/>
<source>Save</source>
<translation>Salvează</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="84"/>
<source>Apply</source>
<translation>Aplică</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="85"/>
<source>Restore Defaults</source>
<translation>Restabilește Impozitivele</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="86"/>
<source>Close</source>
<translation>Închide</translation>
</message>
</context>
<context>
<name>GameListFrame</name>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Icon</source>
<translation>Icon</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Name</source>
<translation>Nume</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Serial</source>
<translation>Serie</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source>
<translation>Regiune</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Firmware</source>
<translation>Firmware</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Size</source>
<translation>Dimensiune</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Version</source>
<translation>Versiune</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Path</source>
<translation>Drum</translation>
</message>
</context>
</TS>

View file

@ -500,6 +500,11 @@
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../main_window.cpp" line="106"/>
<source>Game List</source>
<translation>Список игр</translation>
</message>
<message>
<location filename="../main_window.cpp" line="168"/>
<source> * Unsupported Vulkan Version</source>
@ -851,7 +856,7 @@
<message>
<location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source>
<translation>Патчи успешно скачаны! Все доступные патчи для всех игр были скачаны, нет необходимости скачивать их по отдельности для каждой игры, как это происходит с читами.</translation>
<translation>Патчи успешно скачаны! Все доступные патчи для всех игр были скачаны, нет необходимости скачивать их по отдельности для каждой игры, как это происходит с читами. Если патч не появляется, возможно, его не существует для конкретного серийного номера и версии игры. Возможно, потребуется обновить игру.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="773"/>
@ -898,5 +903,76 @@
<source>Name:</source>
<translation>Имя:</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="1163"/>
<source>Can't apply cheats before the game is started</source>
<translation>Невозможно применить читы до начала игрыs</translation>
</message>
</context>
<context>
<name>SettingsDialog</name>
<message>
<location filename="../settings_dialog.cpp" line="83"/>
<source>Save</source>
<translation>Сохранить</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="84"/>
<source>Apply</source>
<translation>Применить</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="85"/>
<source>Restore Defaults</source>
<translation>Восстановить умолчания</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="86"/>
<source>Close</source>
<translation>Закрыть</translation>
</message>
</context>
<context>
<name>GameListFrame</name>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Icon</source>
<translation>Иконка</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Name</source>
<translation>Название</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Serial</source>
<translation>Серийный номер</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source>
<translation>Регион</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Firmware</source>
<translation>Прошивка</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Size</source>
<translation>Размер</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Version</source>
<translation>Версия</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Path</source>
<translation>Путь</translation>
</message>
</context>
</TS>

View file

@ -500,6 +500,11 @@
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../main_window.cpp" line="106"/>
<source>Game List</source>
<translation>Lista e lojërave</translation>
</message>
<message>
<location filename="../main_window.cpp" line="168"/>
<source> * Unsupported Vulkan Version</source>
@ -851,7 +856,7 @@
<message>
<location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source>
<translation>Arnat u shkarkuan me sukses! gjitha arnat e ofruara për gjitha lojërat janë shkarkuar, nuk ka nevojë t&apos;i shkarkosh ato individualisht për secilën lojë siç ndodh me Mashtrimet.</translation>
<translation>Arnat u shkarkuan me sukses! gjitha arnat e ofruara për gjitha lojërat janë shkarkuar, nuk ka nevojë t&apos;i shkarkosh ato individualisht për secilën lojë siç ndodh me Mashtrimet. Nëse patch-i nuk shfaqet, mund mos ekzistojë për numrin e serisë dhe versionin specifik lojës. Mund jetë e nevojshme përditësoni lojën.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="773"/>
@ -898,5 +903,76 @@
<source>Name:</source>
<translation>Emri:</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="1163"/>
<source>Can't apply cheats before the game is started</source>
<translation>Nuk mund aplikoni mashtrime para se fillojë loja.</translation>
</message>
</context>
<context>
<name>SettingsDialog</name>
<message>
<location filename="../settings_dialog.cpp" line="83"/>
<source>Save</source>
<translation>Ruaj</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="84"/>
<source>Apply</source>
<translation>Përdor</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="85"/>
<source>Restore Defaults</source>
<translation>Rikthe parazgjedhjet</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="86"/>
<source>Close</source>
<translation>Mbyll</translation>
</message>
</context>
<context>
<name>GameListFrame</name>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Icon</source>
<translation>Ikonë</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Name</source>
<translation>Emri</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Serial</source>
<translation>Seri</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source>
<translation>Rajoni</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Firmware</source>
<translation>Firmware</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Size</source>
<translation>Madësia</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Version</source>
<translation>Versioni</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Path</source>
<translation>Rrugë</translation>
</message>
</context>
</TS>

View file

@ -500,6 +500,11 @@
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../main_window.cpp" line="106"/>
<source>Game List</source>
<translation>Oyun Listesi</translation>
</message>
<message>
<location filename="../main_window.cpp" line="168"/>
<source> * Unsupported Vulkan Version</source>
@ -851,7 +856,7 @@
<message>
<location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source>
<translation>Yamalar başarıyla indirildi! Tüm oyunlar için mevcut tüm yamalar indirildi, her oyun için ayrı ayrı indirme yapmanız gerekmez, hilelerle olduğu gibi.</translation>
<translation>Yamalar başarıyla indirildi! Tüm oyunlar için mevcut tüm yamalar indirildi, her oyun için ayrı ayrı indirme yapmanız gerekmez, hilelerle olduğu gibi. Yamanın görünmemesi durumunda, belirli seri numarası ve oyun sürümü için mevcut olmayabilir. Oyunu güncellemeniz gerekebilir.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="773"/>
@ -969,5 +974,76 @@
<source>Apply Changes</source>
<translation>Değişiklikleri Uygula</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="1163"/>
<source>Can't apply cheats before the game is started</source>
<translation>Hileleri oyuna başlamadan önce uygulayamazsınız.</translation>
</message>
</context>
<context>
<name>SettingsDialog</name>
<message>
<location filename="../settings_dialog.cpp" line="83"/>
<source>Save</source>
<translation>Kaydet</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="84"/>
<source>Apply</source>
<translation>Uygula</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="85"/>
<source>Restore Defaults</source>
<translation>Varsayılanları Geri Yükle</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="86"/>
<source>Close</source>
<translation>Kapat</translation>
</message>
</context>
<context>
<name>GameListFrame</name>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Icon</source>
<translation>Simge</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Name</source>
<translation>Ad</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Serial</source>
<translation>Seri Numarası</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source>
<translation>Bölge</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Firmware</source>
<translation>Yazılım</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Size</source>
<translation>Boyut</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Version</source>
<translation>Sürüm</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Path</source>
<translation>Yol</translation>
</message>
</context>
</TS>

View file

@ -500,6 +500,11 @@
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../main_window.cpp" line="106"/>
<source>Game List</source>
<translation>Danh sách trò chơi</translation>
</message>
<message>
<location filename="../main_window.cpp" line="168"/>
<source> * Unsupported Vulkan Version</source>
@ -851,7 +856,7 @@
<message>
<location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source>
<translation>Bản đã tải xuống thành công! Tất cả các bản sẵn cho tất cả các trò chơi đã đưc tải xuống, không cần tải xuống riêng lẻ cho mỗi trò chơi như trong Cheat.</translation>
<translation>Bản đã tải xuống thành công! Tất cả các bản sẵn cho tất cả các trò chơi đã đưc tải xuống, không cần tải xuống riêng lẻ cho mỗi trò chơi như trong Cheat. Nếu bản không xuất hiện, thể không tồn tại cho số seri phiên bản cụ thể của trò chơi. thể bạn cần phải cập nhật trò chơi.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="773"/>
@ -898,5 +903,76 @@
<source>Name:</source>
<translation>Tên:</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="1163"/>
<source>Can't apply cheats before the game is started</source>
<translation>Không thể áp dụng cheat trước khi trò chơi bắt đu.</translation>
</message>
</context>
<context>
<name>SettingsDialog</name>
<message>
<location filename="../settings_dialog.cpp" line="83"/>
<source>Save</source>
<translation>Lưu</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="84"/>
<source>Apply</source>
<translation>Áp dụng</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="85"/>
<source>Restore Defaults</source>
<translation>Khôi phục cài đt mặc đnh</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="86"/>
<source>Close</source>
<translation>Đóng</translation>
</message>
</context>
<context>
<name>GameListFrame</name>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Icon</source>
<translation>Biểu tượng</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Name</source>
<translation>Tên</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Serial</source>
<translation>Số seri</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source>
<translation>Khu vực</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Firmware</source>
<translation>Phần mềm</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Size</source>
<translation>Kích thước</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Version</source>
<translation>Phiên bản</translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Path</source>
<translation>Đưng dẫn</translation>
</message>
</context>
</TS>

View file

@ -500,6 +500,11 @@
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../main_window.cpp" line="106"/>
<source>Game List</source>
<translation></translation>
</message>
<message>
<location filename="../main_window.cpp" line="168"/>
<source> * Unsupported Vulkan Version</source>
@ -851,7 +856,7 @@
<message>
<location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source>
<translation></translation>
<translation></translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="773"/>
@ -898,5 +903,76 @@
<source>Name:</source>
<translation>:</translation>
</message>
</context>
<message>
<location filename="../cheats_patches.cpp" line="1163"/>
<source>Can't apply cheats before the game is started</source>
<translation></translation>
</message>
</context>
<context>
<name>SettingsDialog</name>
<message>
<location filename="../settings_dialog.cpp" line="83"/>
<source>Save</source>
<translation></translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="84"/>
<source>Apply</source>
<translation></translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="85"/>
<source>Restore Defaults</source>
<translation></translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="86"/>
<source>Close</source>
<translation></translation>
</message>
</context>
<context>
<name>GameListFrame</name>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Icon</source>
<translation></translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Name</source>
<translation></translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Serial</source>
<translation></translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source>
<translation></translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Firmware</source>
<translation></translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Size</source>
<translation></translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Version</source>
<translation></translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Path</source>
<translation></translation>
</message>
</context>
</TS>

View file

@ -500,6 +500,11 @@
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../main_window.cpp" line="106"/>
<source>Game List</source>
<translation></translation>
</message>
<message>
<location filename="../main_window.cpp" line="168"/>
<source> * Unsupported Vulkan Version</source>
@ -851,7 +856,7 @@
<message>
<location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source>
<translation></translation>
<translation></translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="773"/>
@ -898,5 +903,76 @@
<source>Name:</source>
<translation>:</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="1163"/>
<source>Can't apply cheats before the game is started</source>
<translation></translation>
</message>
</context>
<context>
<name>SettingsDialog</name>
<message>
<location filename="../settings_dialog.cpp" line="83"/>
<source>Save</source>
<translation></translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="84"/>
<source>Apply</source>
<translation></translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="85"/>
<source>Restore Defaults</source>
<translation></translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="86"/>
<source>Close</source>
<translation></translation>
</message>
</context>
<context>
<name>GameListFrame</name>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Icon</source>
<translation></translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Name</source>
<translation></translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Serial</source>
<translation></translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source>
<translation></translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
<source>Firmware</source>
<translation></translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Size</source>
<translation></translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Version</source>
<translation></translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="35"/>
<source>Path</source>
<translation></translation>
</message>
</context>
</TS>

View file

@ -5,6 +5,8 @@
#include "common/assert.h"
#include "shader_recompiler/frontend/decode.h"
#include "magic_enum.hpp"
namespace Shader::Gcn {
namespace bit {
@ -253,7 +255,9 @@ void GcnDecodeContext::updateInstructionMeta(InstEncoding encoding) {
ASSERT_MSG(instFormat.src_type != ScalarType::Undefined &&
instFormat.dst_type != ScalarType::Undefined,
"TODO: Instruction format table not complete, please fix it manually.");
"Instruction format table incomplete for opcode {} ({}, encoding = {})",
magic_enum::enum_name(m_instruction.opcode), u32(m_instruction.opcode),
magic_enum::enum_name(encoding));
m_instruction.inst_class = instFormat.inst_class;
m_instruction.category = instFormat.inst_category;

View file

@ -1786,8 +1786,7 @@ constexpr std::array<InstFormat, 455> InstructionFormatVOP3 = {{
constexpr std::array<InstFormat, 71> InstructionFormatVOP1 = {{
// 0 = V_NOP
{InstClass::VectorMisc, InstCategory::VectorALU, 0, 1, ScalarType::Undefined,
ScalarType::Undefined},
{InstClass::VectorMisc, InstCategory::VectorALU, 0, 1, ScalarType::Any, ScalarType::Any},
// 1 = V_MOV_B32
{InstClass::VectorRegMov, InstCategory::VectorALU, 1, 1, ScalarType::Uint32,
ScalarType::Uint32},
@ -3603,8 +3602,8 @@ constexpr std::array<InstFormat, 112> InstructionFormatMIMG = {{
{InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined,
ScalarType::Undefined},
// 79 = IMAGE_GATHER4_C_LZ
{InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined,
ScalarType::Undefined},
{InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32,
ScalarType::Uint32},
// 80 = IMAGE_GATHER4_O
{InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined,
ScalarType::Undefined},
@ -3656,8 +3655,8 @@ constexpr std::array<InstFormat, 112> InstructionFormatMIMG = {{
{},
{},
// 104 = IMAGE_SAMPLE_CD
{InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined,
ScalarType::Undefined},
{InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Float32,
ScalarType::Float32},
// 105 = IMAGE_SAMPLE_CD_CL
{InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined,
ScalarType::Undefined},

View file

@ -171,9 +171,9 @@ void Translator::V_READFIRSTLANE_B32(const GcnInst& inst) {
const IR::U32 value{GetSrc(inst.src[0])};
if (info.stage != Stage::Compute) {
ir.SetScalarReg(dst, value);
SetDst(inst.dst[0], value);
} else {
ir.SetScalarReg(dst, ir.ReadFirstLane(value));
SetDst(inst.dst[0], ir.ReadFirstLane(value));
}
}

View file

@ -91,10 +91,10 @@ void UniqueBuffer::Create(const vk::BufferCreateInfo& buffer_ci, MemoryUsage usa
buffer = vk::Buffer{unsafe_buffer};
}
Buffer::Buffer(const Vulkan::Instance& instance_, MemoryUsage usage_, VAddr cpu_addr_,
vk::BufferUsageFlags flags, u64 size_bytes_)
: cpu_addr{cpu_addr_}, size_bytes{size_bytes_}, instance{&instance_}, usage{usage_},
buffer{instance->GetDevice(), instance->GetAllocator()} {
Buffer::Buffer(const Vulkan::Instance& instance_, Vulkan::Scheduler& scheduler_, MemoryUsage usage_,
VAddr cpu_addr_, vk::BufferUsageFlags flags, u64 size_bytes_)
: cpu_addr{cpu_addr_}, size_bytes{size_bytes_}, instance{&instance_}, scheduler{&scheduler_},
usage{usage_}, buffer{instance->GetDevice(), instance->GetAllocator()} {
// Create buffer object.
const vk::BufferCreateInfo buffer_ci = {
.size = size_bytes,
@ -117,13 +117,6 @@ Buffer::Buffer(const Vulkan::Instance& instance_, MemoryUsage usage_, VAddr cpu_
vk::BufferView Buffer::View(u32 offset, u32 size, bool is_written, AmdGpu::DataFormat dfmt,
AmdGpu::NumberFormat nfmt) {
const auto it{std::ranges::find_if(views, [=](const BufferView& view) {
return offset == view.offset && size == view.size && is_written == view.is_written &&
dfmt == view.dfmt && nfmt == view.nfmt;
})};
if (it != views.end()) {
return *it->handle;
}
const vk::BufferUsageFlags2CreateInfoKHR usage_flags = {
.usage = is_written ? vk::BufferUsageFlagBits2KHR::eStorageTexelBuffer
: vk::BufferUsageFlagBits2KHR::eUniformTexelBuffer,
@ -135,23 +128,18 @@ vk::BufferView Buffer::View(u32 offset, u32 size, bool is_written, AmdGpu::DataF
.offset = offset,
.range = size,
};
views.push_back({
.offset = offset,
.size = size,
.is_written = is_written,
.dfmt = dfmt,
.nfmt = nfmt,
.handle = instance->GetDevice().createBufferViewUnique(view_ci),
});
return *views.back().handle;
const auto view = instance->GetDevice().createBufferView(view_ci);
scheduler->DeferOperation(
[view, device = instance->GetDevice()] { device.destroyBufferView(view); });
return view;
}
constexpr u64 WATCHES_INITIAL_RESERVE = 0x4000;
constexpr u64 WATCHES_RESERVE_CHUNK = 0x1000;
StreamBuffer::StreamBuffer(const Vulkan::Instance& instance, Vulkan::Scheduler& scheduler_,
StreamBuffer::StreamBuffer(const Vulkan::Instance& instance, Vulkan::Scheduler& scheduler,
MemoryUsage usage, u64 size_bytes)
: Buffer{instance, usage, 0, AllFlags, size_bytes}, scheduler{scheduler_} {
: Buffer{instance, scheduler, usage, 0, AllFlags, size_bytes} {
ReserveWatches(current_watches, WATCHES_INITIAL_RESERVE);
ReserveWatches(previous_watches, WATCHES_INITIAL_RESERVE);
const auto device = instance.GetDevice();
@ -206,7 +194,7 @@ void StreamBuffer::Commit() {
auto& watch = current_watches[current_watch_cursor++];
watch.upper_bound = offset;
watch.tick = scheduler.CurrentTick();
watch.tick = scheduler->CurrentTick();
}
void StreamBuffer::ReserveWatches(std::vector<Watch>& watches, std::size_t grow_size) {
@ -220,7 +208,7 @@ void StreamBuffer::WaitPendingOperations(u64 requested_upper_bound) {
while (requested_upper_bound > wait_bound && wait_cursor < *invalidation_mark) {
auto& watch = previous_watches[wait_cursor];
wait_bound = watch.upper_bound;
scheduler.Wait(watch.tick);
scheduler->Wait(watch.tick);
++wait_cursor;
}
}

View file

@ -73,8 +73,9 @@ struct UniqueBuffer {
class Buffer {
public:
explicit Buffer(const Vulkan::Instance& instance, MemoryUsage usage, VAddr cpu_addr_,
vk::BufferUsageFlags flags, u64 size_bytes_);
explicit Buffer(const Vulkan::Instance& instance, Vulkan::Scheduler& scheduler,
MemoryUsage usage, VAddr cpu_addr_, vk::BufferUsageFlags flags,
u64 size_bytes_);
Buffer& operator=(const Buffer&) = delete;
Buffer(const Buffer&) = delete;
@ -118,6 +119,25 @@ public:
return buffer;
}
std::optional<vk::BufferMemoryBarrier2> GetBarrier(vk::AccessFlagBits2 dst_acess_mask,
vk::PipelineStageFlagBits2 dst_stage) {
if (dst_acess_mask == access_mask && stage == dst_stage) {
return {};
}
auto barrier = vk::BufferMemoryBarrier2{
.srcStageMask = stage,
.srcAccessMask = access_mask,
.dstStageMask = dst_stage,
.dstAccessMask = dst_acess_mask,
.buffer = buffer.buffer,
.size = size_bytes,
};
access_mask = dst_acess_mask;
stage = dst_stage;
return barrier;
}
public:
VAddr cpu_addr = 0;
bool is_picked{};
@ -125,18 +145,12 @@ public:
int stream_score = 0;
size_t size_bytes = 0;
std::span<u8> mapped_data;
const Vulkan::Instance* instance{};
const Vulkan::Instance* instance;
Vulkan::Scheduler* scheduler;
MemoryUsage usage;
UniqueBuffer buffer;
struct BufferView {
u32 offset;
u32 size;
bool is_written;
AmdGpu::DataFormat dfmt;
AmdGpu::NumberFormat nfmt;
vk::UniqueBufferView handle;
};
std::vector<BufferView> views;
vk::AccessFlagBits2 access_mask{vk::AccessFlagBits2::eNone};
vk::PipelineStageFlagBits2 stage{vk::PipelineStageFlagBits2::eNone};
};
class StreamBuffer : public Buffer {
@ -175,7 +189,6 @@ private:
void WaitPendingOperations(u64 requested_upper_bound);
private:
Vulkan::Scheduler& scheduler;
u64 offset{};
u64 mapped_size{};
std::vector<Watch> current_watches;

View file

@ -10,20 +10,24 @@
#include "video_core/renderer_vulkan/liverpool_to_vk.h"
#include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/texture_cache/texture_cache.h"
namespace VideoCore {
static constexpr size_t NumVertexBuffers = 32;
static constexpr size_t StagingBufferSize = 512_MB;
static constexpr size_t UboStreamBufferSize = 64_MB;
BufferCache::BufferCache(const Vulkan::Instance& instance_, Vulkan::Scheduler& scheduler_,
const AmdGpu::Liverpool* liverpool_, PageManager& tracker_)
: instance{instance_}, scheduler{scheduler_}, liverpool{liverpool_}, tracker{tracker_},
const AmdGpu::Liverpool* liverpool_, TextureCache& texture_cache_,
PageManager& tracker_)
: instance{instance_}, scheduler{scheduler_}, liverpool{liverpool_},
texture_cache{texture_cache_}, tracker{tracker_},
staging_buffer{instance, scheduler, MemoryUsage::Upload, StagingBufferSize},
stream_buffer{instance, scheduler, MemoryUsage::Stream, UboStreamBufferSize},
memory_tracker{&tracker} {
// Ensure the first slot is used for the null buffer
void(slot_buffers.insert(instance, MemoryUsage::DeviceLocal, 0, ReadFlags, 1));
void(slot_buffers.insert(instance, scheduler, MemoryUsage::DeviceLocal, 0, ReadFlags, 1));
}
BufferCache::~BufferCache() = default;
@ -100,9 +104,9 @@ bool BufferCache::BindVertexBuffers(const Shader::Info& vs_info) {
return false;
}
std::array<vk::Buffer, NUM_VERTEX_BUFFERS> host_buffers;
std::array<vk::DeviceSize, NUM_VERTEX_BUFFERS> host_offsets;
boost::container::static_vector<AmdGpu::Buffer, NUM_VERTEX_BUFFERS> guest_buffers;
std::array<vk::Buffer, NumVertexBuffers> host_buffers;
std::array<vk::DeviceSize, NumVertexBuffers> host_offsets;
boost::container::static_vector<AmdGpu::Buffer, NumVertexBuffers> guest_buffers;
struct BufferRange {
VAddr base_address;
@ -117,7 +121,7 @@ bool BufferCache::BindVertexBuffers(const Shader::Info& vs_info) {
// Calculate buffers memory overlaps
bool has_step_rate = false;
boost::container::static_vector<BufferRange, NUM_VERTEX_BUFFERS> ranges{};
boost::container::static_vector<BufferRange, NumVertexBuffers> ranges{};
for (const auto& input : vs_info.vs_inputs) {
if (input.instance_step_rate == Shader::Info::VsInput::InstanceIdType::OverStepRate0 ||
input.instance_step_rate == Shader::Info::VsInput::InstanceIdType::OverStepRate1) {
@ -152,7 +156,7 @@ bool BufferCache::BindVertexBuffers(const Shader::Info& vs_info) {
return lhv.base_address < rhv.base_address;
});
boost::container::static_vector<BufferRange, NUM_VERTEX_BUFFERS> ranges_merged{ranges[0]};
boost::container::static_vector<BufferRange, NumVertexBuffers> ranges_merged{ranges[0]};
for (auto range : ranges) {
auto& prev_range = ranges_merged.back();
if (prev_range.end_address < range.base_address) {
@ -232,7 +236,7 @@ std::pair<Buffer*, u32> BufferCache::ObtainBuffer(VAddr device_addr, u32 size, b
bool is_texel_buffer) {
static constexpr u64 StreamThreshold = CACHING_PAGESIZE;
const bool is_gpu_dirty = memory_tracker.IsRegionGpuModified(device_addr, size);
if (!is_written && !is_texel_buffer && size <= StreamThreshold && !is_gpu_dirty) {
if (!is_written && size <= StreamThreshold && !is_gpu_dirty) {
// For small uniform buffers that have not been modified by gpu
// use device local stream buffer to reduce renderpass breaks.
const u64 offset = stream_buffer.Copy(device_addr, size, instance.UniformMinAlignment());
@ -241,18 +245,18 @@ std::pair<Buffer*, u32> BufferCache::ObtainBuffer(VAddr device_addr, u32 size, b
const BufferId buffer_id = FindBuffer(device_addr, size);
Buffer& buffer = slot_buffers[buffer_id];
SynchronizeBuffer(buffer, device_addr, size);
SynchronizeBuffer(buffer, device_addr, size, is_texel_buffer);
if (is_written) {
memory_tracker.MarkRegionAsGpuModified(device_addr, size);
}
return {&buffer, buffer.Offset(device_addr)};
}
std::pair<const Buffer*, u32> BufferCache::ObtainTempBuffer(VAddr gpu_addr, u32 size) {
std::pair<Buffer*, u32> BufferCache::ObtainTempBuffer(VAddr gpu_addr, u32 size) {
const u64 page = gpu_addr >> CACHING_PAGEBITS;
const BufferId buffer_id = page_table[page];
if (buffer_id) {
const Buffer& buffer = slot_buffers[buffer_id];
Buffer& buffer = slot_buffers[buffer_id];
if (buffer.IsInBounds(gpu_addr, size)) {
return {&buffer, buffer.Offset(gpu_addr)};
}
@ -420,8 +424,8 @@ BufferId BufferCache::CreateBuffer(VAddr device_addr, u32 wanted_size) {
wanted_size = static_cast<u32>(device_addr_end - device_addr);
const OverlapResult overlap = ResolveOverlaps(device_addr, wanted_size);
const u32 size = static_cast<u32>(overlap.end - overlap.begin);
const BufferId new_buffer_id =
slot_buffers.insert(instance, MemoryUsage::DeviceLocal, overlap.begin, AllFlags, size);
const BufferId new_buffer_id = slot_buffers.insert(
instance, scheduler, MemoryUsage::DeviceLocal, overlap.begin, AllFlags, size);
auto& new_buffer = slot_buffers[new_buffer_id];
const size_t size_bytes = new_buffer.SizeBytes();
const auto cmdbuf = scheduler.CommandBuffer();
@ -459,7 +463,8 @@ void BufferCache::ChangeRegister(BufferId buffer_id) {
}
}
bool BufferCache::SynchronizeBuffer(Buffer& buffer, VAddr device_addr, u32 size) {
void BufferCache::SynchronizeBuffer(Buffer& buffer, VAddr device_addr, u32 size,
bool is_texel_buffer) {
std::scoped_lock lk{mutex};
boost::container::small_vector<vk::BufferCopy, 4> copies;
u64 total_size_bytes = 0;
@ -479,8 +484,13 @@ bool BufferCache::SynchronizeBuffer(Buffer& buffer, VAddr device_addr, u32 size)
// Prevent uploading to gpu modified regions.
// gpu_modified_ranges.ForEachNotInRange(device_addr_out, range_size, add_copy);
});
SCOPE_EXIT {
if (is_texel_buffer) {
SynchronizeBufferFromImage(buffer, device_addr, size);
}
};
if (total_size_bytes == 0) {
return true;
return;
}
vk::Buffer src_buffer = staging_buffer.Handle();
if (total_size_bytes < StagingBufferSize) {
@ -496,7 +506,11 @@ bool BufferCache::SynchronizeBuffer(Buffer& buffer, VAddr device_addr, u32 size)
} else {
// For large one time transfers use a temporary host buffer.
// RenderDoc can lag quite a bit if the stream buffer is too large.
Buffer temp_buffer{instance, MemoryUsage::Upload, 0, vk::BufferUsageFlagBits::eTransferSrc,
Buffer temp_buffer{instance,
scheduler,
MemoryUsage::Upload,
0,
vk::BufferUsageFlagBits::eTransferSrc,
total_size_bytes};
src_buffer = temp_buffer.Handle();
u8* const staging = temp_buffer.mapped_data.data();
@ -524,7 +538,68 @@ bool BufferCache::SynchronizeBuffer(Buffer& buffer, VAddr device_addr, u32 size)
cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer,
vk::PipelineStageFlagBits::eAllCommands,
vk::DependencyFlagBits::eByRegion, WRITE_BARRIER, {}, {});
return false;
}
bool BufferCache::SynchronizeBufferFromImage(Buffer& buffer, VAddr device_addr, u32 size) {
boost::container::small_vector<ImageId, 8> image_ids;
const u32 inv_size = std::min(size, MaxInvalidateDist);
texture_cache.ForEachImageInRegion(device_addr, inv_size, [&](ImageId image_id, Image& image) {
// Only consider GPU modified images, i.e render targets or storage images.
// Also avoid any CPU modified images as the image data is likely to be stale.
if (True(image.flags & ImageFlagBits::CpuModified) ||
False(image.flags & ImageFlagBits::GpuModified)) {
return;
}
// Image must fully overlap with the provided buffer range.
if (image.cpu_addr < device_addr || image.cpu_addr_end > device_addr + size) {
return;
}
image_ids.push_back(image_id);
});
if (image_ids.empty()) {
return false;
}
// Sort images by modification tick. If there are overlaps we want to
// copy from least to most recently modified.
std::ranges::sort(image_ids, [&](ImageId lhs_id, ImageId rhs_id) {
const Image& lhs = texture_cache.GetImage(lhs_id);
const Image& rhs = texture_cache.GetImage(rhs_id);
return lhs.tick_accessed_last < rhs.tick_accessed_last;
});
boost::container::small_vector<vk::BufferImageCopy, 8> copies;
for (const ImageId image_id : image_ids) {
copies.clear();
Image& image = texture_cache.GetImage(image_id);
u32 offset = buffer.Offset(image.cpu_addr);
const u32 num_layers = image.info.resources.layers;
for (u32 m = 0; m < image.info.resources.levels; m++) {
const u32 width = std::max(image.info.size.width >> m, 1u);
const u32 height = std::max(image.info.size.height >> m, 1u);
const u32 depth =
image.info.props.is_volume ? std::max(image.info.size.depth >> m, 1u) : 1u;
const auto& [mip_size, mip_pitch, mip_height, mip_ofs] = image.info.mips_layout[m];
copies.push_back({
.bufferOffset = offset,
.bufferRowLength = static_cast<u32>(mip_pitch),
.bufferImageHeight = static_cast<u32>(mip_height),
.imageSubresource{
.aspectMask = image.aspect_mask & ~vk::ImageAspectFlagBits::eStencil,
.mipLevel = m,
.baseArrayLayer = 0,
.layerCount = num_layers,
},
.imageOffset = {0, 0, 0},
.imageExtent = {width, height, depth},
});
offset += mip_ofs * num_layers;
}
scheduler.EndRendering();
image.Transit(vk::ImageLayout::eTransferSrcOptimal, vk::AccessFlagBits::eTransferRead);
const auto cmdbuf = scheduler.CommandBuffer();
cmdbuf.copyImageToBuffer(image.image, vk::ImageLayout::eTransferSrcOptimal, buffer.buffer,
copies);
}
return true;
}
void BufferCache::DeleteBuffer(BufferId buffer_id, bool do_not_mark) {

View file

@ -28,7 +28,7 @@ using BufferId = Common::SlotId;
static constexpr BufferId NULL_BUFFER_ID{0};
static constexpr u32 NUM_VERTEX_BUFFERS = 32;
class TextureCache;
class BufferCache {
public:
@ -53,7 +53,8 @@ public:
public:
explicit BufferCache(const Vulkan::Instance& instance, Vulkan::Scheduler& scheduler,
const AmdGpu::Liverpool* liverpool, PageManager& tracker);
const AmdGpu::Liverpool* liverpool, TextureCache& texture_cache,
PageManager& tracker);
~BufferCache();
/// Invalidates any buffer in the logical page range.
@ -70,7 +71,7 @@ public:
bool is_texel_buffer = false);
/// Obtains a temporary buffer for usage in texture cache.
[[nodiscard]] std::pair<const Buffer*, u32> ObtainTempBuffer(VAddr gpu_addr, u32 size);
[[nodiscard]] std::pair<Buffer*, u32> ObtainTempBuffer(VAddr gpu_addr, u32 size);
/// Return true when a region is registered on the cache
[[nodiscard]] bool IsRegionRegistered(VAddr addr, size_t size);
@ -116,13 +117,16 @@ private:
template <bool insert>
void ChangeRegister(BufferId buffer_id);
bool SynchronizeBuffer(Buffer& buffer, VAddr device_addr, u32 size);
void SynchronizeBuffer(Buffer& buffer, VAddr device_addr, u32 size, bool is_texel_buffer);
bool SynchronizeBufferFromImage(Buffer& buffer, VAddr device_addr, u32 size);
void DeleteBuffer(BufferId buffer_id, bool do_not_mark = false);
const Vulkan::Instance& instance;
Vulkan::Scheduler& scheduler;
const AmdGpu::Liverpool* liverpool;
TextureCache& texture_cache;
PageManager& tracker;
StreamBuffer staging_buffer;
StreamBuffer stream_buffer;

View file

@ -13,6 +13,7 @@
#define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1
#define VULKAN_HPP_NO_CONSTRUCTORS
#define VULKAN_HPP_NO_STRUCT_SETTERS
#define VULKAN_HPP_HAS_SPACESHIP_OPERATOR
#include <vulkan/vulkan.hpp>
#define VMA_STATIC_VULKAN_FUNCTIONS 0

View file

@ -104,6 +104,7 @@ bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache,
boost::container::static_vector<vk::DescriptorBufferInfo, 16> buffer_infos;
boost::container::static_vector<vk::DescriptorImageInfo, 16> image_infos;
boost::container::small_vector<vk::WriteDescriptorSet, 16> set_writes;
boost::container::small_vector<vk::BufferMemoryBarrier2, 16> buffer_barriers;
Shader::PushData push_data{};
u32 binding{};
@ -153,9 +154,9 @@ bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache,
for (const auto& desc : info->texture_buffers) {
const auto vsharp = desc.GetSharp(*info);
vk::BufferView& buffer_view = buffer_views.emplace_back(VK_NULL_HANDLE);
if (vsharp.GetDataFmt() != AmdGpu::DataFormat::FormatInvalid) {
const u32 size = vsharp.GetSize();
if (vsharp.GetDataFmt() != AmdGpu::DataFormat::FormatInvalid && size != 0) {
const VAddr address = vsharp.base_address;
const u32 size = vsharp.GetSize();
if (desc.is_written) {
if (texture_cache.TouchMeta(address, true)) {
LOG_TRACE(Render_Vulkan, "Metadata update skipped");
@ -166,9 +167,6 @@ bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache,
LOG_WARNING(Render_Vulkan, "Unexpected metadata read by a CS shader (buffer)");
}
}
if (desc.is_written) {
texture_cache.InvalidateMemory(address, size);
}
const u32 alignment = instance.TexelBufferMinAlignment();
const auto [vk_buffer, offset] =
buffer_cache.ObtainBuffer(address, size, desc.is_written, true);
@ -183,6 +181,15 @@ bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache,
}
buffer_view = vk_buffer->View(offset_aligned, size + adjust, desc.is_written,
vsharp.GetDataFmt(), vsharp.GetNumberFmt());
if (auto barrier =
vk_buffer->GetBarrier(desc.is_written ? vk::AccessFlagBits2::eShaderWrite
: vk::AccessFlagBits2::eShaderRead,
vk::PipelineStageFlagBits2::eComputeShader)) {
buffer_barriers.emplace_back(*barrier);
}
if (desc.is_written) {
texture_cache.InvalidateMemory(address, size);
}
}
set_writes.push_back({
.dstSet = VK_NULL_HANDLE,
@ -198,7 +205,7 @@ bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache,
for (const auto& image_desc : info->images) {
const auto tsharp = image_desc.GetSharp(*info);
if (tsharp.GetDataFmt() != AmdGpu::DataFormat::FormatInvalid) {
VideoCore::ImageInfo image_info{tsharp};
VideoCore::ImageInfo image_info{tsharp, image_desc.is_depth};
VideoCore::ImageViewInfo view_info{tsharp, image_desc.is_storage};
const auto& image_view = texture_cache.FindTexture(image_info, view_info);
const auto& image = texture_cache.GetImage(image_view.image_id);
@ -222,6 +229,9 @@ bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache,
}
for (const auto& sampler : info->samplers) {
const auto ssharp = sampler.GetSharp(*info);
if (ssharp.force_degamma) {
LOG_WARNING(Render_Vulkan, "Texture requires gamma correction");
}
const auto vk_sampler = texture_cache.GetSampler(ssharp);
image_infos.emplace_back(vk_sampler, VK_NULL_HANDLE, vk::ImageLayout::eGeneral);
set_writes.push_back({
@ -239,6 +249,17 @@ bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache,
}
const auto cmdbuf = scheduler.CommandBuffer();
if (!buffer_barriers.empty()) {
const auto dependencies = vk::DependencyInfo{
.dependencyFlags = vk::DependencyFlagBits::eByRegion,
.bufferMemoryBarrierCount = u32(buffer_barriers.size()),
.pBufferMemoryBarriers = buffer_barriers.data(),
};
scheduler.EndRendering();
cmdbuf.pipelineBarrier2(dependencies);
}
cmdbuf.pushConstants(*pipeline_layout, vk::ShaderStageFlagBits::eCompute, 0u, sizeof(push_data),
&push_data);
cmdbuf.pushDescriptorSetKHR(vk::PipelineBindPoint::eCompute, *pipeline_layout, 0, set_writes);

View file

@ -359,6 +359,7 @@ void GraphicsPipeline::BindResources(const Liverpool::Regs& regs,
boost::container::static_vector<vk::DescriptorBufferInfo, 32> buffer_infos;
boost::container::static_vector<vk::DescriptorImageInfo, 32> image_infos;
boost::container::small_vector<vk::WriteDescriptorSet, 16> set_writes;
boost::container::small_vector<vk::BufferMemoryBarrier2, 16> buffer_barriers;
Shader::PushData push_data{};
u32 binding{};
@ -404,15 +405,15 @@ void GraphicsPipeline::BindResources(const Liverpool::Regs& regs,
});
}
for (const auto& tex_buffer : stage->texture_buffers) {
const auto vsharp = tex_buffer.GetSharp(*stage);
for (const auto& desc : stage->texture_buffers) {
const auto vsharp = desc.GetSharp(*stage);
vk::BufferView& buffer_view = buffer_views.emplace_back(VK_NULL_HANDLE);
if (vsharp.GetDataFmt() != AmdGpu::DataFormat::FormatInvalid) {
const u32 size = vsharp.GetSize();
if (vsharp.GetDataFmt() != AmdGpu::DataFormat::FormatInvalid && size != 0) {
const VAddr address = vsharp.base_address;
const u32 size = vsharp.GetSize();
const u32 alignment = instance.TexelBufferMinAlignment();
const auto [vk_buffer, offset] =
buffer_cache.ObtainBuffer(address, size, tex_buffer.is_written, true);
buffer_cache.ObtainBuffer(address, size, desc.is_written, true);
const u32 fmt_stride = AmdGpu::NumBits(vsharp.GetDataFmt()) >> 3;
ASSERT_MSG(fmt_stride == vsharp.GetStride(),
"Texel buffer stride must match format stride");
@ -422,16 +423,25 @@ void GraphicsPipeline::BindResources(const Liverpool::Regs& regs,
ASSERT(adjust % fmt_stride == 0);
push_data.AddOffset(binding, adjust / fmt_stride);
}
buffer_view = vk_buffer->View(offset_aligned, size + adjust, tex_buffer.is_written,
buffer_view = vk_buffer->View(offset_aligned, size + adjust, desc.is_written,
vsharp.GetDataFmt(), vsharp.GetNumberFmt());
const auto dst_access = desc.is_written ? vk::AccessFlagBits2::eShaderWrite
: vk::AccessFlagBits2::eShaderRead;
if (auto barrier = vk_buffer->GetBarrier(
dst_access, vk::PipelineStageFlagBits2::eVertexShader)) {
buffer_barriers.emplace_back(*barrier);
}
if (desc.is_written) {
texture_cache.InvalidateMemory(address, size);
}
}
set_writes.push_back({
.dstSet = VK_NULL_HANDLE,
.dstBinding = binding++,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = tex_buffer.is_written ? vk::DescriptorType::eStorageTexelBuffer
: vk::DescriptorType::eUniformTexelBuffer,
.descriptorType = desc.is_written ? vk::DescriptorType::eStorageTexelBuffer
: vk::DescriptorType::eUniformTexelBuffer,
.pTexelBufferView = &buffer_view,
});
}
@ -441,7 +451,7 @@ void GraphicsPipeline::BindResources(const Liverpool::Regs& regs,
const auto tsharp = image_desc.GetSharp(*stage);
if (tsharp) {
tsharps.emplace_back(tsharp);
VideoCore::ImageInfo image_info{tsharp};
VideoCore::ImageInfo image_info{tsharp, image_desc.is_depth};
VideoCore::ImageViewInfo view_info{tsharp, image_desc.is_storage};
const auto& image_view = texture_cache.FindTexture(image_info, view_info);
const auto& image = texture_cache.GetImage(image_view.image_id);
@ -465,6 +475,9 @@ void GraphicsPipeline::BindResources(const Liverpool::Regs& regs,
}
for (const auto& sampler : stage->samplers) {
auto ssharp = sampler.GetSharp(*stage);
if (ssharp.force_degamma) {
LOG_WARNING(Render_Vulkan, "Texture requires gamma correction");
}
if (sampler.disable_aniso) {
const auto& tsharp = tsharps[sampler.associated_image];
if (tsharp.base_level == 0 && tsharp.last_level == 0) {
@ -485,6 +498,17 @@ void GraphicsPipeline::BindResources(const Liverpool::Regs& regs,
}
const auto cmdbuf = scheduler.CommandBuffer();
if (!buffer_barriers.empty()) {
const auto dependencies = vk::DependencyInfo{
.dependencyFlags = vk::DependencyFlagBits::eByRegion,
.bufferMemoryBarrierCount = u32(buffer_barriers.size()),
.pBufferMemoryBarriers = buffer_barriers.data(),
};
scheduler.EndRendering();
cmdbuf.pipelineBarrier2(dependencies);
}
if (!set_writes.empty()) {
cmdbuf.pushDescriptorSetKHR(vk::PipelineBindPoint::eGraphics, *pipeline_layout, 0,
set_writes);

View file

@ -228,6 +228,7 @@ bool Instance::CreateDevice() {
const bool maintenance5 = add_extension(VK_KHR_MAINTENANCE_5_EXTENSION_NAME);
add_extension(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
add_extension(VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME);
add_extension(VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME);
#ifdef __APPLE__
// Required by Vulkan spec if supported.
@ -296,6 +297,7 @@ bool Instance::CreateDevice() {
.shaderFloat16 = vk12_features.shaderFloat16,
.scalarBlockLayout = vk12_features.scalarBlockLayout,
.uniformBufferStandardLayout = vk12_features.uniformBufferStandardLayout,
.separateDepthStencilLayouts = vk12_features.separateDepthStencilLayouts,
.hostQueryReset = vk12_features.hostQueryReset,
.timelineSemaphore = vk12_features.timelineSemaphore,
},

View file

@ -290,6 +290,11 @@ bool PipelineCache::RefreshGraphicsKey() {
}
const auto stage = Shader::StageFromIndex(i);
const auto params = Liverpool::GetParams(*pgm);
if (stage != Shader::Stage::Vertex && stage != Shader::Stage::Fragment) {
return false;
}
std::tie(infos[i], modules[i], key.stage_hashes[i]) = GetProgram(stage, params, binding);
}
return true;

View file

@ -42,6 +42,8 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL DebugUtilsCallback(
switch (static_cast<u32>(callback_data->messageIdNumber)) {
case 0x609a13b: // Vertex attribute at location not consumed by shader
case 0xc81ad50e:
case 0xb7c39078:
case 0x32868fde: // vkCreateBufferView(): pCreateInfo->range does not equal VK_WHOLE_SIZE
case 0x92d66fc1: // `pMultisampleState is NULL` for depth only passes (confirmed VL error)
return VK_FALSE;
default:

View file

@ -17,7 +17,7 @@ namespace Vulkan {
Rasterizer::Rasterizer(const Instance& instance_, Scheduler& scheduler_,
AmdGpu::Liverpool* liverpool_)
: instance{instance_}, scheduler{scheduler_}, page_manager{this},
buffer_cache{instance, scheduler, liverpool_, page_manager},
buffer_cache{instance, scheduler, liverpool_, texture_cache, page_manager},
texture_cache{instance, scheduler, buffer_cache, page_manager}, liverpool{liverpool_},
memory{Core::Memory::Instance()}, pipeline_cache{instance, scheduler, liverpool} {
if (!Config::nullGpu()) {
@ -179,6 +179,10 @@ void Rasterizer::BeginRendering() {
const auto& regs = liverpool->regs;
RenderState state;
if (regs.color_control.degamma_enable) {
LOG_WARNING(Render_Vulkan, "Color buffers require gamma correction");
}
for (auto col_buf_id = 0u; col_buf_id < Liverpool::NumColorBuffers; ++col_buf_id) {
const auto& col_buf = regs.color_buffers[col_buf_id];
if (!col_buf) {

View file

@ -0,0 +1,392 @@
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright © 2023 Skyline Team and Contributors (https://github.com/skyline-emu/)
// Copyright © 2015-2023 The Khronos Group Inc.
// Copyright © 2015-2023 Valve Corporation
// Copyright © 2015-2023 LunarG, Inc.
#pragma once
#include <unordered_map>
#include "video_core/renderer_vulkan/vk_common.h"
namespace VideoCore {
/**
* @brief All classes of format compatibility according to the Vulkan specification
* @url
* https://github.com/KhronosGroup/Vulkan-ValidationLayers/blob/d37c676f75f545a3e5a98d7dfb89864391a1db1e/layers/generated/vk_format_utils.h#L47-L131
* @note This is copied directly from Vulkan Validation Layers and doesn't follow the Skyline naming
* conventions
*/
enum class FORMAT_COMPATIBILITY_CLASS {
NONE = 0,
_10BIT_2PLANE_420,
_10BIT_2PLANE_422,
_10BIT_2PLANE_444,
_10BIT_3PLANE_420,
_10BIT_3PLANE_422,
_10BIT_3PLANE_444,
_12BIT_2PLANE_420,
_12BIT_2PLANE_422,
_12BIT_2PLANE_444,
_12BIT_3PLANE_420,
_12BIT_3PLANE_422,
_12BIT_3PLANE_444,
_128BIT,
_16BIT,
_16BIT_2PLANE_420,
_16BIT_2PLANE_422,
_16BIT_2PLANE_444,
_16BIT_3PLANE_420,
_16BIT_3PLANE_422,
_16BIT_3PLANE_444,
_192BIT,
_24BIT,
_256BIT,
_32BIT,
_32BIT_B8G8R8G8,
_32BIT_G8B8G8R8,
_48BIT,
_64BIT,
_64BIT_B10G10R10G10,
_64BIT_B12G12R12G12,
_64BIT_B16G16R16G16,
_64BIT_G10B10G10R10,
_64BIT_G12B12G12R12,
_64BIT_G16B16G16R16,
_64BIT_R10G10B10A10,
_64BIT_R12G12B12A12,
_8BIT,
_8BIT_2PLANE_420,
_8BIT_2PLANE_422,
_8BIT_2PLANE_444,
_8BIT_3PLANE_420,
_8BIT_3PLANE_422,
_8BIT_3PLANE_444,
_96BIT,
ASTC_10X10,
ASTC_10X5,
ASTC_10X6,
ASTC_10X8,
ASTC_12X10,
ASTC_12X12,
ASTC_4X4,
ASTC_5X4,
ASTC_5X5,
ASTC_6X5,
ASTC_6X6,
ASTC_8X5,
ASTC_8X6,
ASTC_8X8,
BC1_RGB,
BC1_RGBA,
BC2,
BC3,
BC4,
BC5,
BC6H,
BC7,
D16,
D16S8,
D24,
D24S8,
D32,
D32S8,
EAC_R,
EAC_RG,
ETC2_EAC_RGBA,
ETC2_RGB,
ETC2_RGBA,
PVRTC1_2BPP,
PVRTC1_4BPP,
PVRTC2_2BPP,
PVRTC2_4BPP,
S8
};
/**
* @brief The format compatibility class according to the Vulkan specification
* @url
* https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#formats-compatibility-classes
* @url
* https://github.com/KhronosGroup/Vulkan-ValidationLayers/blob/d37c676f75f545a3e5a98d7dfb89864391a1db1e/layers/generated/vk_format_utils.cpp#L70-L812
* @note This is copied directly from Vulkan Validation Layers and doesn't follow the Skyline naming
* conventions
*/
static const std::unordered_map<VkFormat, FORMAT_COMPATIBILITY_CLASS> vkFormatClassTable{
{VK_FORMAT_A1R5G5B5_UNORM_PACK16, FORMAT_COMPATIBILITY_CLASS::_16BIT},
{VK_FORMAT_A2B10G10R10_SINT_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_A2B10G10R10_SNORM_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_A2B10G10R10_SSCALED_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_A2B10G10R10_UINT_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_A2B10G10R10_UNORM_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_A2B10G10R10_USCALED_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_A2R10G10B10_SINT_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_A2R10G10B10_SNORM_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_A2R10G10B10_SSCALED_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_A2R10G10B10_UINT_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_A2R10G10B10_UNORM_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_A2R10G10B10_USCALED_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT, FORMAT_COMPATIBILITY_CLASS::_16BIT},
{VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT, FORMAT_COMPATIBILITY_CLASS::_16BIT},
{VK_FORMAT_A8B8G8R8_SINT_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_A8B8G8R8_SNORM_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_A8B8G8R8_SRGB_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_A8B8G8R8_SSCALED_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_A8B8G8R8_UINT_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_A8B8G8R8_UNORM_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_A8B8G8R8_USCALED_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT, FORMAT_COMPATIBILITY_CLASS::ASTC_10X10},
{VK_FORMAT_ASTC_10x10_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_10X10},
{VK_FORMAT_ASTC_10x10_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_10X10},
{VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT, FORMAT_COMPATIBILITY_CLASS::ASTC_10X5},
{VK_FORMAT_ASTC_10x5_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_10X5},
{VK_FORMAT_ASTC_10x5_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_10X5},
{VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT, FORMAT_COMPATIBILITY_CLASS::ASTC_10X6},
{VK_FORMAT_ASTC_10x6_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_10X6},
{VK_FORMAT_ASTC_10x6_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_10X6},
{VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT, FORMAT_COMPATIBILITY_CLASS::ASTC_10X8},
{VK_FORMAT_ASTC_10x8_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_10X8},
{VK_FORMAT_ASTC_10x8_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_10X8},
{VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT, FORMAT_COMPATIBILITY_CLASS::ASTC_12X10},
{VK_FORMAT_ASTC_12x10_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_12X10},
{VK_FORMAT_ASTC_12x10_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_12X10},
{VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT, FORMAT_COMPATIBILITY_CLASS::ASTC_12X12},
{VK_FORMAT_ASTC_12x12_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_12X12},
{VK_FORMAT_ASTC_12x12_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_12X12},
{VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT, FORMAT_COMPATIBILITY_CLASS::ASTC_4X4},
{VK_FORMAT_ASTC_4x4_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_4X4},
{VK_FORMAT_ASTC_4x4_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_4X4},
{VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT, FORMAT_COMPATIBILITY_CLASS::ASTC_5X4},
{VK_FORMAT_ASTC_5x4_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_5X4},
{VK_FORMAT_ASTC_5x4_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_5X4},
{VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT, FORMAT_COMPATIBILITY_CLASS::ASTC_5X5},
{VK_FORMAT_ASTC_5x5_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_5X5},
{VK_FORMAT_ASTC_5x5_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_5X5},
{VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT, FORMAT_COMPATIBILITY_CLASS::ASTC_6X5},
{VK_FORMAT_ASTC_6x5_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_6X5},
{VK_FORMAT_ASTC_6x5_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_6X5},
{VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT, FORMAT_COMPATIBILITY_CLASS::ASTC_6X6},
{VK_FORMAT_ASTC_6x6_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_6X6},
{VK_FORMAT_ASTC_6x6_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_6X6},
{VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT, FORMAT_COMPATIBILITY_CLASS::ASTC_8X5},
{VK_FORMAT_ASTC_8x5_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_8X5},
{VK_FORMAT_ASTC_8x5_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_8X5},
{VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT, FORMAT_COMPATIBILITY_CLASS::ASTC_8X6},
{VK_FORMAT_ASTC_8x6_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_8X6},
{VK_FORMAT_ASTC_8x6_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_8X6},
{VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT, FORMAT_COMPATIBILITY_CLASS::ASTC_8X8},
{VK_FORMAT_ASTC_8x8_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_8X8},
{VK_FORMAT_ASTC_8x8_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_8X8},
{VK_FORMAT_B10G11R11_UFLOAT_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16,
FORMAT_COMPATIBILITY_CLASS::_64BIT_B10G10R10G10},
{VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16,
FORMAT_COMPATIBILITY_CLASS::_64BIT_B12G12R12G12},
{VK_FORMAT_B16G16R16G16_422_UNORM, FORMAT_COMPATIBILITY_CLASS::_64BIT_B16G16R16G16},
{VK_FORMAT_B4G4R4A4_UNORM_PACK16, FORMAT_COMPATIBILITY_CLASS::_16BIT},
{VK_FORMAT_B5G5R5A1_UNORM_PACK16, FORMAT_COMPATIBILITY_CLASS::_16BIT},
{VK_FORMAT_B5G6R5_UNORM_PACK16, FORMAT_COMPATIBILITY_CLASS::_16BIT},
{VK_FORMAT_B8G8R8A8_SINT, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_B8G8R8A8_SNORM, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_B8G8R8A8_SRGB, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_B8G8R8A8_SSCALED, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_B8G8R8A8_UINT, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_B8G8R8A8_UNORM, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_B8G8R8A8_USCALED, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_B8G8R8G8_422_UNORM, FORMAT_COMPATIBILITY_CLASS::_32BIT_B8G8R8G8},
{VK_FORMAT_B8G8R8_SINT, FORMAT_COMPATIBILITY_CLASS::_24BIT},
{VK_FORMAT_B8G8R8_SNORM, FORMAT_COMPATIBILITY_CLASS::_24BIT},
{VK_FORMAT_B8G8R8_SRGB, FORMAT_COMPATIBILITY_CLASS::_24BIT},
{VK_FORMAT_B8G8R8_SSCALED, FORMAT_COMPATIBILITY_CLASS::_24BIT},
{VK_FORMAT_B8G8R8_UINT, FORMAT_COMPATIBILITY_CLASS::_24BIT},
{VK_FORMAT_B8G8R8_UNORM, FORMAT_COMPATIBILITY_CLASS::_24BIT},
{VK_FORMAT_B8G8R8_USCALED, FORMAT_COMPATIBILITY_CLASS::_24BIT},
{VK_FORMAT_BC1_RGBA_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::BC1_RGBA},
{VK_FORMAT_BC1_RGBA_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::BC1_RGBA},
{VK_FORMAT_BC1_RGB_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::BC1_RGB},
{VK_FORMAT_BC1_RGB_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::BC1_RGB},
{VK_FORMAT_BC2_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::BC2},
{VK_FORMAT_BC2_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::BC2},
{VK_FORMAT_BC3_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::BC3},
{VK_FORMAT_BC3_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::BC3},
{VK_FORMAT_BC4_SNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::BC4},
{VK_FORMAT_BC4_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::BC4},
{VK_FORMAT_BC5_SNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::BC5},
{VK_FORMAT_BC5_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::BC5},
{VK_FORMAT_BC6H_SFLOAT_BLOCK, FORMAT_COMPATIBILITY_CLASS::BC6H},
{VK_FORMAT_BC6H_UFLOAT_BLOCK, FORMAT_COMPATIBILITY_CLASS::BC6H},
{VK_FORMAT_BC7_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::BC7},
{VK_FORMAT_BC7_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::BC7},
{VK_FORMAT_D16_UNORM, FORMAT_COMPATIBILITY_CLASS::D16},
{VK_FORMAT_D16_UNORM_S8_UINT, FORMAT_COMPATIBILITY_CLASS::D16S8},
{VK_FORMAT_D24_UNORM_S8_UINT, FORMAT_COMPATIBILITY_CLASS::D24S8},
{VK_FORMAT_D32_SFLOAT, FORMAT_COMPATIBILITY_CLASS::D32},
{VK_FORMAT_D32_SFLOAT_S8_UINT, FORMAT_COMPATIBILITY_CLASS::D32S8},
{VK_FORMAT_E5B9G9R9_UFLOAT_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_EAC_R11G11_SNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::EAC_RG},
{VK_FORMAT_EAC_R11G11_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::EAC_RG},
{VK_FORMAT_EAC_R11_SNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::EAC_R},
{VK_FORMAT_EAC_R11_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::EAC_R},
{VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::ETC2_RGBA},
{VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::ETC2_RGBA},
{VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::ETC2_EAC_RGBA},
{VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::ETC2_EAC_RGBA},
{VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::ETC2_RGB},
{VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::ETC2_RGB},
{VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16,
FORMAT_COMPATIBILITY_CLASS::_64BIT_G10B10G10R10},
{VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16,
FORMAT_COMPATIBILITY_CLASS::_10BIT_2PLANE_420},
{VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16,
FORMAT_COMPATIBILITY_CLASS::_10BIT_2PLANE_422},
{VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16_EXT,
FORMAT_COMPATIBILITY_CLASS::_10BIT_2PLANE_444},
{VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16,
FORMAT_COMPATIBILITY_CLASS::_10BIT_3PLANE_420},
{VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16,
FORMAT_COMPATIBILITY_CLASS::_10BIT_3PLANE_422},
{VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16,
FORMAT_COMPATIBILITY_CLASS::_10BIT_3PLANE_444},
{VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16,
FORMAT_COMPATIBILITY_CLASS::_64BIT_G12B12G12R12},
{VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16,
FORMAT_COMPATIBILITY_CLASS::_12BIT_2PLANE_420},
{VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16,
FORMAT_COMPATIBILITY_CLASS::_12BIT_2PLANE_422},
{VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16_EXT,
FORMAT_COMPATIBILITY_CLASS::_12BIT_2PLANE_444},
{VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16,
FORMAT_COMPATIBILITY_CLASS::_12BIT_3PLANE_420},
{VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16,
FORMAT_COMPATIBILITY_CLASS::_12BIT_3PLANE_422},
{VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16,
FORMAT_COMPATIBILITY_CLASS::_12BIT_3PLANE_444},
{VK_FORMAT_G16B16G16R16_422_UNORM, FORMAT_COMPATIBILITY_CLASS::_64BIT_G16B16G16R16},
{VK_FORMAT_G16_B16R16_2PLANE_420_UNORM, FORMAT_COMPATIBILITY_CLASS::_16BIT_2PLANE_420},
{VK_FORMAT_G16_B16R16_2PLANE_422_UNORM, FORMAT_COMPATIBILITY_CLASS::_16BIT_2PLANE_422},
{VK_FORMAT_G16_B16R16_2PLANE_444_UNORM_EXT, FORMAT_COMPATIBILITY_CLASS::_16BIT_2PLANE_444},
{VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM, FORMAT_COMPATIBILITY_CLASS::_16BIT_3PLANE_420},
{VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM, FORMAT_COMPATIBILITY_CLASS::_16BIT_3PLANE_422},
{VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM, FORMAT_COMPATIBILITY_CLASS::_16BIT_3PLANE_444},
{VK_FORMAT_G8B8G8R8_422_UNORM, FORMAT_COMPATIBILITY_CLASS::_32BIT_G8B8G8R8},
{VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, FORMAT_COMPATIBILITY_CLASS::_8BIT_2PLANE_420},
{VK_FORMAT_G8_B8R8_2PLANE_422_UNORM, FORMAT_COMPATIBILITY_CLASS::_8BIT_2PLANE_422},
{VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT, FORMAT_COMPATIBILITY_CLASS::_8BIT_2PLANE_444},
{VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM, FORMAT_COMPATIBILITY_CLASS::_8BIT_3PLANE_420},
{VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM, FORMAT_COMPATIBILITY_CLASS::_8BIT_3PLANE_422},
{VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM, FORMAT_COMPATIBILITY_CLASS::_8BIT_3PLANE_444},
{VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG, FORMAT_COMPATIBILITY_CLASS::PVRTC1_2BPP},
{VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG, FORMAT_COMPATIBILITY_CLASS::PVRTC1_2BPP},
{VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG, FORMAT_COMPATIBILITY_CLASS::PVRTC1_4BPP},
{VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG, FORMAT_COMPATIBILITY_CLASS::PVRTC1_4BPP},
{VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG, FORMAT_COMPATIBILITY_CLASS::PVRTC2_2BPP},
{VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG, FORMAT_COMPATIBILITY_CLASS::PVRTC2_2BPP},
{VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG, FORMAT_COMPATIBILITY_CLASS::PVRTC2_4BPP},
{VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG, FORMAT_COMPATIBILITY_CLASS::PVRTC2_4BPP},
{VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16, FORMAT_COMPATIBILITY_CLASS::_64BIT_R10G10B10A10},
{VK_FORMAT_R10X6G10X6_UNORM_2PACK16, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_R10X6_UNORM_PACK16, FORMAT_COMPATIBILITY_CLASS::_16BIT},
{VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16, FORMAT_COMPATIBILITY_CLASS::_64BIT_R12G12B12A12},
{VK_FORMAT_R12X4G12X4_UNORM_2PACK16, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_R12X4_UNORM_PACK16, FORMAT_COMPATIBILITY_CLASS::_16BIT},
{VK_FORMAT_R16G16B16A16_SFLOAT, FORMAT_COMPATIBILITY_CLASS::_64BIT},
{VK_FORMAT_R16G16B16A16_SINT, FORMAT_COMPATIBILITY_CLASS::_64BIT},
{VK_FORMAT_R16G16B16A16_SNORM, FORMAT_COMPATIBILITY_CLASS::_64BIT},
{VK_FORMAT_R16G16B16A16_SSCALED, FORMAT_COMPATIBILITY_CLASS::_64BIT},
{VK_FORMAT_R16G16B16A16_UINT, FORMAT_COMPATIBILITY_CLASS::_64BIT},
{VK_FORMAT_R16G16B16A16_UNORM, FORMAT_COMPATIBILITY_CLASS::_64BIT},
{VK_FORMAT_R16G16B16A16_USCALED, FORMAT_COMPATIBILITY_CLASS::_64BIT},
{VK_FORMAT_R16G16B16_SFLOAT, FORMAT_COMPATIBILITY_CLASS::_48BIT},
{VK_FORMAT_R16G16B16_SINT, FORMAT_COMPATIBILITY_CLASS::_48BIT},
{VK_FORMAT_R16G16B16_SNORM, FORMAT_COMPATIBILITY_CLASS::_48BIT},
{VK_FORMAT_R16G16B16_SSCALED, FORMAT_COMPATIBILITY_CLASS::_48BIT},
{VK_FORMAT_R16G16B16_UINT, FORMAT_COMPATIBILITY_CLASS::_48BIT},
{VK_FORMAT_R16G16B16_UNORM, FORMAT_COMPATIBILITY_CLASS::_48BIT},
{VK_FORMAT_R16G16B16_USCALED, FORMAT_COMPATIBILITY_CLASS::_48BIT},
{VK_FORMAT_R16G16_SFLOAT, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_R16G16_SINT, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_R16G16_SNORM, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_R16G16_SSCALED, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_R16G16_UINT, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_R16G16_UNORM, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_R16G16_USCALED, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_R16_SFLOAT, FORMAT_COMPATIBILITY_CLASS::_16BIT},
{VK_FORMAT_R16_SINT, FORMAT_COMPATIBILITY_CLASS::_16BIT},
{VK_FORMAT_R16_SNORM, FORMAT_COMPATIBILITY_CLASS::_16BIT},
{VK_FORMAT_R16_SSCALED, FORMAT_COMPATIBILITY_CLASS::_16BIT},
{VK_FORMAT_R16_UINT, FORMAT_COMPATIBILITY_CLASS::_16BIT},
{VK_FORMAT_R16_UNORM, FORMAT_COMPATIBILITY_CLASS::_16BIT},
{VK_FORMAT_R16_USCALED, FORMAT_COMPATIBILITY_CLASS::_16BIT},
{VK_FORMAT_R32G32B32A32_SFLOAT, FORMAT_COMPATIBILITY_CLASS::_128BIT},
{VK_FORMAT_R32G32B32A32_SINT, FORMAT_COMPATIBILITY_CLASS::_128BIT},
{VK_FORMAT_R32G32B32A32_UINT, FORMAT_COMPATIBILITY_CLASS::_128BIT},
{VK_FORMAT_R32G32B32_SFLOAT, FORMAT_COMPATIBILITY_CLASS::_96BIT},
{VK_FORMAT_R32G32B32_SINT, FORMAT_COMPATIBILITY_CLASS::_96BIT},
{VK_FORMAT_R32G32B32_UINT, FORMAT_COMPATIBILITY_CLASS::_96BIT},
{VK_FORMAT_R32G32_SFLOAT, FORMAT_COMPATIBILITY_CLASS::_64BIT},
{VK_FORMAT_R32G32_SINT, FORMAT_COMPATIBILITY_CLASS::_64BIT},
{VK_FORMAT_R32G32_UINT, FORMAT_COMPATIBILITY_CLASS::_64BIT},
{VK_FORMAT_R32_SFLOAT, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_R32_SINT, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_R32_UINT, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_R4G4B4A4_UNORM_PACK16, FORMAT_COMPATIBILITY_CLASS::_16BIT},
{VK_FORMAT_R4G4_UNORM_PACK8, FORMAT_COMPATIBILITY_CLASS::_8BIT},
{VK_FORMAT_R5G5B5A1_UNORM_PACK16, FORMAT_COMPATIBILITY_CLASS::_16BIT},
{VK_FORMAT_R5G6B5_UNORM_PACK16, FORMAT_COMPATIBILITY_CLASS::_16BIT},
{VK_FORMAT_R64G64B64A64_SFLOAT, FORMAT_COMPATIBILITY_CLASS::_256BIT},
{VK_FORMAT_R64G64B64A64_SINT, FORMAT_COMPATIBILITY_CLASS::_256BIT},
{VK_FORMAT_R64G64B64A64_UINT, FORMAT_COMPATIBILITY_CLASS::_256BIT},
{VK_FORMAT_R64G64B64_SFLOAT, FORMAT_COMPATIBILITY_CLASS::_192BIT},
{VK_FORMAT_R64G64B64_SINT, FORMAT_COMPATIBILITY_CLASS::_192BIT},
{VK_FORMAT_R64G64B64_UINT, FORMAT_COMPATIBILITY_CLASS::_192BIT},
{VK_FORMAT_R64G64_SFLOAT, FORMAT_COMPATIBILITY_CLASS::_128BIT},
{VK_FORMAT_R64G64_SINT, FORMAT_COMPATIBILITY_CLASS::_128BIT},
{VK_FORMAT_R64G64_UINT, FORMAT_COMPATIBILITY_CLASS::_128BIT},
{VK_FORMAT_R64_SFLOAT, FORMAT_COMPATIBILITY_CLASS::_64BIT},
{VK_FORMAT_R64_SINT, FORMAT_COMPATIBILITY_CLASS::_64BIT},
{VK_FORMAT_R64_UINT, FORMAT_COMPATIBILITY_CLASS::_64BIT},
{VK_FORMAT_R8G8B8A8_SINT, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_R8G8B8A8_SNORM, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_R8G8B8A8_SRGB, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_R8G8B8A8_SSCALED, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_R8G8B8A8_UINT, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_R8G8B8A8_UNORM, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_R8G8B8A8_USCALED, FORMAT_COMPATIBILITY_CLASS::_32BIT},
{VK_FORMAT_R8G8B8_SINT, FORMAT_COMPATIBILITY_CLASS::_24BIT},
{VK_FORMAT_R8G8B8_SNORM, FORMAT_COMPATIBILITY_CLASS::_24BIT},
{VK_FORMAT_R8G8B8_SRGB, FORMAT_COMPATIBILITY_CLASS::_24BIT},
{VK_FORMAT_R8G8B8_SSCALED, FORMAT_COMPATIBILITY_CLASS::_24BIT},
{VK_FORMAT_R8G8B8_UINT, FORMAT_COMPATIBILITY_CLASS::_24BIT},
{VK_FORMAT_R8G8B8_UNORM, FORMAT_COMPATIBILITY_CLASS::_24BIT},
{VK_FORMAT_R8G8B8_USCALED, FORMAT_COMPATIBILITY_CLASS::_24BIT},
{VK_FORMAT_R8G8_SINT, FORMAT_COMPATIBILITY_CLASS::_16BIT},
{VK_FORMAT_R8G8_SNORM, FORMAT_COMPATIBILITY_CLASS::_16BIT},
{VK_FORMAT_R8G8_SRGB, FORMAT_COMPATIBILITY_CLASS::_16BIT},
{VK_FORMAT_R8G8_SSCALED, FORMAT_COMPATIBILITY_CLASS::_16BIT},
{VK_FORMAT_R8G8_UINT, FORMAT_COMPATIBILITY_CLASS::_16BIT},
{VK_FORMAT_R8G8_UNORM, FORMAT_COMPATIBILITY_CLASS::_16BIT},
{VK_FORMAT_R8G8_USCALED, FORMAT_COMPATIBILITY_CLASS::_16BIT},
{VK_FORMAT_R8_SINT, FORMAT_COMPATIBILITY_CLASS::_8BIT},
{VK_FORMAT_R8_SNORM, FORMAT_COMPATIBILITY_CLASS::_8BIT},
{VK_FORMAT_R8_SRGB, FORMAT_COMPATIBILITY_CLASS::_8BIT},
{VK_FORMAT_R8_SSCALED, FORMAT_COMPATIBILITY_CLASS::_8BIT},
{VK_FORMAT_R8_UINT, FORMAT_COMPATIBILITY_CLASS::_8BIT},
{VK_FORMAT_R8_UNORM, FORMAT_COMPATIBILITY_CLASS::_8BIT},
{VK_FORMAT_R8_USCALED, FORMAT_COMPATIBILITY_CLASS::_8BIT},
{VK_FORMAT_S8_UINT, FORMAT_COMPATIBILITY_CLASS::S8},
{VK_FORMAT_X8_D24_UNORM_PACK32, FORMAT_COMPATIBILITY_CLASS::D24},
{VK_FORMAT_UNDEFINED, FORMAT_COMPATIBILITY_CLASS::NONE},
};
/**
* @return If the two formats are compatible according to Vulkan's format compatibility rules
* @url
* https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#formats-compatibility
*/
static bool IsVulkanFormatCompatible(vk::Format lhs, vk::Format rhs) {
if (lhs == rhs) {
return true;
}
return vkFormatClassTable.at(VkFormat(lhs)) == vkFormatClassTable.at(VkFormat(rhs));
}
} // namespace VideoCore

View file

@ -166,8 +166,9 @@ Image::Image(const Vulkan::Instance& instance_, Vulkan::Scheduler& scheduler_,
image.Create(image_ci);
Vulkan::SetObjectName(instance->GetDevice(), (vk::Image)image, "Image {:#x}:{:#x}",
info.guest_address, info.guest_size_bytes);
Vulkan::SetObjectName(instance->GetDevice(), (vk::Image)image, "Image {}x{}x{} {:#x}:{:#x}",
info.size.width, info.size.height, info.size.depth, info.guest_address,
info.guest_size_bytes);
}
void Image::Transit(vk::ImageLayout dst_layout, vk::Flags<vk::AccessFlagBits> dst_mask,
@ -242,6 +243,74 @@ void Image::Upload(vk::Buffer buffer, u64 offset) {
vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eTransferRead);
}
void Image::CopyImage(const Image& image) {
scheduler->EndRendering();
Transit(vk::ImageLayout::eTransferDstOptimal, vk::AccessFlagBits::eTransferWrite);
auto cmdbuf = scheduler->CommandBuffer();
boost::container::small_vector<vk::ImageCopy, 14> image_copy{};
for (u32 m = 0; m < image.info.resources.levels; ++m) {
const auto mip_w = std::max(info.size.width >> m, 1u);
const auto mip_h = std::max(info.size.height >> m, 1u);
const auto mip_d = std::max(info.size.depth >> m, 1u);
image_copy.emplace_back(vk::ImageCopy{
.srcSubresource{
.aspectMask = image.aspect_mask,
.mipLevel = m,
.baseArrayLayer = 0,
.layerCount = image.info.resources.layers,
},
.dstSubresource{
.aspectMask = image.aspect_mask,
.mipLevel = m,
.baseArrayLayer = 0,
.layerCount = image.info.resources.layers,
},
.extent = {mip_w, mip_h, mip_d},
});
}
cmdbuf.copyImage(image.image, image.layout, this->image, this->layout, image_copy);
Transit(vk::ImageLayout::eGeneral,
vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eTransferRead);
}
void Image::CopyMip(const Image& image, u32 mip) {
scheduler->EndRendering();
Transit(vk::ImageLayout::eTransferDstOptimal, vk::AccessFlagBits::eTransferWrite);
auto cmdbuf = scheduler->CommandBuffer();
const auto mip_w = std::max(info.size.width >> mip, 1u);
const auto mip_h = std::max(info.size.height >> mip, 1u);
const auto mip_d = std::max(info.size.depth >> mip, 1u);
ASSERT(mip_w == image.info.size.width);
ASSERT(mip_h == image.info.size.height);
const vk::ImageCopy image_copy{
.srcSubresource{
.aspectMask = image.aspect_mask,
.mipLevel = 0,
.baseArrayLayer = 0,
.layerCount = image.info.resources.layers,
},
.dstSubresource{
.aspectMask = image.aspect_mask,
.mipLevel = mip,
.baseArrayLayer = 0,
.layerCount = info.resources.layers,
},
.extent = {mip_w, mip_h, mip_d},
};
cmdbuf.copyImage(image.image, image.layout, this->image, this->layout, image_copy);
Transit(vk::ImageLayout::eGeneral,
vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eTransferRead);
}
Image::~Image() = default;
} // namespace VideoCore

View file

@ -32,6 +32,7 @@ enum ImageFlagBits : u32 {
Registered = 1 << 6, ///< True when the image is registered
Picked = 1 << 7, ///< Temporary flag to mark the image as picked
MetaRegistered = 1 << 8, ///< True when metadata for this surface is known and registered
Deleted = 1 << 9, ///< Indicates that images was marked for deletion once frame is done
};
DECLARE_ENUM_FLAG_OPERATORS(ImageFlagBits)
@ -95,6 +96,9 @@ struct Image {
vk::CommandBuffer cmdbuf = {});
void Upload(vk::Buffer buffer, u64 offset);
void CopyImage(const Image& image);
void CopyMip(const Image& image, u32 mip);
const Vulkan::Instance* instance;
Vulkan::Scheduler* scheduler;
ImageInfo info;
@ -112,6 +116,7 @@ struct Image {
vk::Flags<vk::AccessFlagBits> access_mask = vk::AccessFlagBits::eNone;
vk::ImageLayout layout = vk::ImageLayout::eUndefined;
boost::container::small_vector<u64, 14> mip_hashes;
u64 tick_accessed_last{0};
};
} // namespace VideoCore

View file

@ -174,6 +174,7 @@ ImageInfo::ImageInfo(const AmdGpu::Liverpool::ColorBuffer& buffer,
const auto color_slice_sz = buffer.GetColorSliceSize();
guest_size_bytes = color_slice_sz * buffer.NumSlices();
mips_layout.emplace_back(color_slice_sz, pitch, 0);
tiling_idx = static_cast<u32>(buffer.attrib.tile_mode_index.Value());
}
ImageInfo::ImageInfo(const AmdGpu::Liverpool::DepthBuffer& buffer, u32 num_slices,
@ -186,7 +187,7 @@ ImageInfo::ImageInfo(const AmdGpu::Liverpool::DepthBuffer& buffer, u32 num_slice
size.width = hint.Valid() ? hint.width : buffer.Pitch();
size.height = hint.Valid() ? hint.height : buffer.Height();
size.depth = 1;
pitch = size.width;
pitch = buffer.Pitch();
resources.layers = num_slices;
meta_info.htile_addr = buffer.z_info.tile_surface_en ? htile_address : 0;
usage.depth_target = true;
@ -199,9 +200,19 @@ ImageInfo::ImageInfo(const AmdGpu::Liverpool::DepthBuffer& buffer, u32 num_slice
mips_layout.emplace_back(depth_slice_sz, pitch, 0);
}
ImageInfo::ImageInfo(const AmdGpu::Image& image) noexcept {
ImageInfo::ImageInfo(const AmdGpu::Image& image, bool force_depth /*= false*/) noexcept {
tiling_mode = image.GetTilingMode();
pixel_format = LiverpoolToVK::SurfaceFormat(image.GetDataFmt(), image.GetNumberFmt());
// Override format if image is forced to be a depth target
if (force_depth || tiling_mode == AmdGpu::TilingMode::Depth_MacroTiled) {
if (pixel_format == vk::Format::eR32Sfloat) {
pixel_format = vk::Format::eD32SfloatS8Uint;
} else if (pixel_format == vk::Format::eR16Unorm) {
pixel_format = vk::Format::eD16UnormS8Uint;
} else {
UNREACHABLE();
}
}
type = ConvertImageType(image.GetType());
props.is_tiled = image.IsTiled();
props.is_cube = image.GetType() == AmdGpu::ImageType::Cube;
@ -287,4 +298,74 @@ void ImageInfo::UpdateSize() {
guest_size_bytes *= resources.layers;
}
bool ImageInfo::IsMipOf(const ImageInfo& info) const {
if (!IsCompatible(info)) {
return false;
}
// Currently we expect only on level to be copied.
if (resources.levels != 1) {
return false;
}
const int mip = info.resources.levels - resources.levels;
if (mip < 1) {
return false;
}
const auto mip_w = std::max(info.size.width >> mip, 1u);
const auto mip_h = std::max(info.size.height >> mip, 1u);
if ((size.width != mip_w) || (size.height != mip_h)) {
return false;
}
const auto mip_d = std::max(info.size.depth >> mip, 1u);
if (info.type == vk::ImageType::e3D && type == vk::ImageType::e2D) {
// In case of 2D array to 3D copy, make sure we have proper number of layers.
if (resources.layers != mip_d) {
return false;
}
} else {
if (type != info.type) {
return false;
}
}
// Check if the mip has correct size.
if (info.mips_layout.size() <= mip || info.mips_layout[mip].size != guest_size_bytes) {
return false;
}
return true;
}
bool ImageInfo::IsSliceOf(const ImageInfo& info) const {
if (!IsCompatible(info)) {
return false;
}
// Array slices should be of the same type.
if (type != info.type) {
return false;
}
// 2D dimensions of both images should be the same.
if ((size.width != info.size.width) || (size.height != info.size.height)) {
return false;
}
// Check for size alignment.
const bool slice_size = info.guest_size_bytes / info.resources.layers;
if (guest_size_bytes % slice_size != 0) {
return false;
}
// Ensure that address is aligned too.
if (((info.guest_address - guest_address) % guest_size_bytes) != 0) {
return false;
}
return true;
}
} // namespace VideoCore

View file

@ -3,7 +3,6 @@
#pragma once
#include "common/enum.h"
#include "common/types.h"
#include "core/libraries/videoout/buffer.h"
#include "video_core/amdgpu/liverpool.h"
@ -20,7 +19,7 @@ struct ImageInfo {
const AmdGpu::Liverpool::CbDbExtent& hint = {}) noexcept;
ImageInfo(const AmdGpu::Liverpool::DepthBuffer& buffer, u32 num_slices, VAddr htile_address,
const AmdGpu::Liverpool::CbDbExtent& hint = {}) noexcept;
ImageInfo(const AmdGpu::Image& image) noexcept;
ImageInfo(const AmdGpu::Image& image, bool force_depth = false) noexcept;
bool IsTiled() const {
return tiling_mode != AmdGpu::TilingMode::Display_Linear;
@ -29,6 +28,15 @@ struct ImageInfo {
bool IsPacked() const;
bool IsDepthStencil() const;
bool IsMipOf(const ImageInfo& info) const;
bool IsSliceOf(const ImageInfo& info) const;
/// Verifies if images are compatible for subresource merging.
bool IsCompatible(const ImageInfo& info) const {
return (pixel_format == info.pixel_format && tiling_idx == info.tiling_idx &&
num_samples == info.num_samples && num_bits == info.num_bits);
}
void UpdateSize();
struct {

View file

@ -123,7 +123,8 @@ ImageView::ImageView(const Vulkan::Instance& instance, const ImageViewInfo& info
// When sampling D32 texture from shader, the T# specifies R32 Float format so adjust it.
vk::Format format = info.format;
vk::ImageAspectFlags aspect = image.aspect_mask;
if (image.aspect_mask & vk::ImageAspectFlagBits::eDepth && format == vk::Format::eR32Sfloat) {
if (image.aspect_mask & vk::ImageAspectFlagBits::eDepth &&
(format == vk::Format::eR32Sfloat || format == vk::Format::eD32Sfloat)) {
format = image.info.pixel_format;
aspect = vk::ImageAspectFlagBits::eDepth;
}

View file

@ -1,18 +1,21 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <optional>
#include <xxhash.h>
#include "common/assert.h"
#include "video_core/buffer_cache/buffer_cache.h"
#include "video_core/page_manager.h"
#include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/texture_cache/host_compatibility.h"
#include "video_core/texture_cache/texture_cache.h"
#include "video_core/texture_cache/tile_manager.h"
namespace VideoCore {
static constexpr u64 PageShift = 12;
static constexpr u64 NumFramesBeforeRemoval = 32;
TextureCache::TextureCache(const Vulkan::Instance& instance_, Vulkan::Scheduler& scheduler_,
BufferCache& buffer_cache_, PageManager& tracker_)
@ -35,15 +38,16 @@ TextureCache::TextureCache(const Vulkan::Instance& instance_, Vulkan::Scheduler&
TextureCache::~TextureCache() = default;
void TextureCache::InvalidateMemory(VAddr address, size_t size) {
std::unique_lock lock{mutex};
std::scoped_lock lock{mutex};
ForEachImageInRegion(address, size, [&](ImageId image_id, Image& image) {
if (!image.Overlaps(address, size)) {
return;
const size_t image_dist =
image.cpu_addr > address ? image.cpu_addr - address : address - image.cpu_addr;
if (image_dist < MaxInvalidateDist) {
// Ensure image is reuploaded when accessed again.
image.flags |= ImageFlagBits::CpuModified;
}
// Ensure image is reuploaded when accessed again.
image.flags |= ImageFlagBits::CpuModified;
// Untrack image, so the range is unprotected and the guest can write freely.
UntrackImage(image, image_id);
UntrackImage(image_id);
});
}
@ -53,46 +57,170 @@ void TextureCache::UnmapMemory(VAddr cpu_addr, size_t size) {
boost::container::small_vector<ImageId, 16> deleted_images;
ForEachImageInRegion(cpu_addr, size, [&](ImageId id, Image&) { deleted_images.push_back(id); });
for (const ImageId id : deleted_images) {
Image& image = slot_images[id];
if (True(image.flags & ImageFlagBits::Tracked)) {
UntrackImage(image, id);
}
// TODO: Download image data back to host.
UnregisterImage(id);
DeleteImage(id);
FreeImage(id);
}
}
ImageId TextureCache::FindImage(const ImageInfo& info) {
ImageId TextureCache::ResolveDepthOverlap(const ImageInfo& requested_info, ImageId cache_image_id) {
const auto& cache_info = slot_images[cache_image_id].info;
const bool was_bound_as_texture =
!cache_info.usage.depth_target && (cache_info.usage.texture || cache_info.usage.storage);
if (requested_info.usage.depth_target && was_bound_as_texture) {
auto new_image_id = slot_images.insert(instance, scheduler, requested_info);
RegisterImage(new_image_id);
// auto& new_image = slot_images[new_image_id];
// TODO: need to run a helper for depth copy here
FreeImage(cache_image_id);
return new_image_id;
}
const bool should_bind_as_texture =
!requested_info.usage.depth_target &&
(requested_info.usage.texture || requested_info.usage.storage);
if (cache_info.usage.depth_target && should_bind_as_texture) {
return cache_image_id;
}
return {};
}
ImageId TextureCache::ResolveOverlap(const ImageInfo& image_info, ImageId cache_image_id,
ImageId merged_image_id) {
auto& tex_cache_image = slot_images[cache_image_id];
if (image_info.guest_address == tex_cache_image.info.guest_address) { // Equal address
if (image_info.size != tex_cache_image.info.size) {
// Very likely this kind of overlap is caused by allocation from a pool. We can assume
// it is safe to delete the image if it wasn't accessed in some amount of frames.
if (scheduler.CurrentTick() - tex_cache_image.tick_accessed_last >
NumFramesBeforeRemoval) {
FreeImage(cache_image_id);
}
return merged_image_id;
}
if (auto depth_image_id = ResolveDepthOverlap(image_info, cache_image_id)) {
return depth_image_id;
}
if (image_info.pixel_format != tex_cache_image.info.pixel_format ||
image_info.size != tex_cache_image.info.size ||
image_info.guest_size_bytes <= tex_cache_image.info.guest_size_bytes) {
return merged_image_id ? merged_image_id : cache_image_id;
}
ImageId new_image_id{};
if (image_info.type == tex_cache_image.info.type) {
new_image_id = ExpandImage(image_info, cache_image_id);
} else {
UNREACHABLE();
}
return new_image_id;
}
// Right overlap, the image requested is a possible subresource of the image from cache.
if (image_info.guest_address > tex_cache_image.info.guest_address) {
// Should be handled by view. No additional actions needed.
} else {
// Left overlap, the image from cache is a possible subresource of the image requested
if (!merged_image_id) {
// We need to have a larger, already allocated image to copy this one into
return {};
}
if (tex_cache_image.info.IsMipOf(image_info)) {
tex_cache_image.Transit(vk::ImageLayout::eTransferSrcOptimal,
vk::AccessFlagBits::eTransferRead);
const auto num_mips_to_copy = tex_cache_image.info.resources.levels;
ASSERT(num_mips_to_copy == 1);
auto& merged_image = slot_images[merged_image_id];
merged_image.CopyMip(tex_cache_image, image_info.resources.levels - 1);
FreeImage(cache_image_id);
}
}
return merged_image_id;
}
ImageId TextureCache::ExpandImage(const ImageInfo& info, ImageId image_id) {
const auto new_image_id = slot_images.insert(instance, scheduler, info);
RegisterImage(new_image_id);
auto& src_image = slot_images[image_id];
auto& new_image = slot_images[new_image_id];
src_image.Transit(vk::ImageLayout::eTransferSrcOptimal, vk::AccessFlagBits::eTransferRead);
new_image.CopyImage(src_image);
FreeImage(image_id);
TrackImage(new_image_id);
new_image.flags &= ~ImageFlagBits::CpuModified;
return new_image_id;
}
ImageId TextureCache::FindImage(const ImageInfo& info, FindFlags flags) {
if (info.guest_address == 0) [[unlikely]] {
return NULL_IMAGE_VIEW_ID;
}
std::unique_lock lock{mutex};
boost::container::small_vector<ImageId, 2> image_ids;
ForEachImageInRegion(
info.guest_address, info.guest_size_bytes, [&](ImageId image_id, Image& image) {
// Address and width must match.
if (image.cpu_addr != info.guest_address || image.info.size.width != info.size.width) {
return;
}
if (info.IsDepthStencil() != image.info.IsDepthStencil() &&
info.pixel_format != vk::Format::eR32Sfloat) {
return;
}
image_ids.push_back(image_id);
});
// ASSERT_MSG(image_ids.size() <= 1, "Overlapping images not allowed!");
std::scoped_lock lock{mutex};
boost::container::small_vector<ImageId, 8> image_ids;
ForEachImageInRegion(info.guest_address, info.guest_size_bytes,
[&](ImageId image_id, Image& image) { image_ids.push_back(image_id); });
ImageId image_id{};
if (image_ids.empty()) {
// Check for a perfect match first
for (const auto& cache_id : image_ids) {
auto& cache_image = slot_images[cache_id];
if (cache_image.info.guest_address != info.guest_address) {
continue;
}
if (False(flags & FindFlags::RelaxSize) &&
cache_image.info.guest_size_bytes != info.guest_size_bytes) {
continue;
}
if (False(flags & FindFlags::RelaxDim) && cache_image.info.size != info.size) {
continue;
}
if (False(flags & FindFlags::RelaxFmt) &&
!IsVulkanFormatCompatible(info.pixel_format, cache_image.info.pixel_format)) {
continue;
}
ASSERT(cache_image.info.type == info.type);
image_id = cache_id;
}
// Try to resolve overlaps (if any)
if (!image_id) {
for (const auto& cache_id : image_ids) {
const auto& merged_info = image_id ? slot_images[image_id].info : info;
image_id = ResolveOverlap(merged_info, cache_id, image_id);
}
}
if (True(flags & FindFlags::NoCreate) && !image_id) {
return {};
}
// Create and register a new image
if (!image_id) {
image_id = slot_images.insert(instance, scheduler, info);
RegisterImage(image_id);
} else {
image_id = image_ids[image_ids.size() > 1 ? 1 : 0];
}
Image& image = slot_images[image_id];
image.tick_accessed_last = scheduler.CurrentTick();
return image_id;
}
@ -119,8 +247,11 @@ ImageView& TextureCache::RegisterImageView(ImageId image_id, const ImageViewInfo
ImageView& TextureCache::FindTexture(const ImageInfo& info, const ImageViewInfo& view_info) {
const ImageId image_id = FindImage(info);
UpdateImage(image_id);
Image& image = slot_images[image_id];
if (view_info.is_storage) {
image.flags |= ImageFlagBits::GpuModified;
}
UpdateImage(image_id);
auto& usage = image.info.usage;
if (view_info.is_storage) {
@ -135,31 +266,7 @@ ImageView& TextureCache::FindTexture(const ImageInfo& info, const ImageViewInfo&
usage.texture = true;
}
// These changes are temporary and should be removed once texture cache will handle subresources
// merging
auto view_info_tmp = view_info;
if (view_info_tmp.range.base.level > image.info.resources.levels - 1 ||
view_info_tmp.range.base.layer > image.info.resources.layers - 1 ||
view_info_tmp.range.extent.levels > image.info.resources.levels ||
view_info_tmp.range.extent.layers > image.info.resources.layers) {
LOG_DEBUG(Render_Vulkan,
"Subresource range ({}~{},{}~{}) exceeds base image extents ({},{})",
view_info_tmp.range.base.level, view_info_tmp.range.extent.levels,
view_info_tmp.range.base.layer, view_info_tmp.range.extent.layers,
image.info.resources.levels, image.info.resources.layers);
view_info_tmp.range.base.level =
std::min(view_info_tmp.range.base.level, image.info.resources.levels - 1);
view_info_tmp.range.base.layer =
std::min(view_info_tmp.range.base.layer, image.info.resources.layers - 1);
view_info_tmp.range.extent.levels =
std::min(view_info_tmp.range.extent.levels, image.info.resources.levels);
view_info_tmp.range.extent.layers =
std::min(view_info_tmp.range.extent.layers, image.info.resources.layers);
}
return RegisterImageView(image_id, view_info_tmp);
return RegisterImageView(image_id, view_info);
}
ImageView& TextureCache::FindRenderTarget(const ImageInfo& image_info,
@ -204,10 +311,18 @@ ImageView& TextureCache::FindDepthTarget(const ImageInfo& image_info,
Image& image = slot_images[image_id];
image.flags |= ImageFlagBits::GpuModified;
image.flags &= ~ImageFlagBits::CpuModified;
image.aspect_mask = vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil;
image.aspect_mask = vk::ImageAspectFlagBits::eDepth;
const auto new_layout = view_info.is_storage ? vk::ImageLayout::eDepthStencilAttachmentOptimal
: vk::ImageLayout::eDepthStencilReadOnlyOptimal;
const bool has_stencil = image_info.usage.stencil;
if (has_stencil) {
image.aspect_mask |= vk::ImageAspectFlagBits::eStencil;
}
const auto new_layout = view_info.is_storage
? has_stencil ? vk::ImageLayout::eDepthStencilAttachmentOptimal
: vk::ImageLayout::eDepthAttachmentOptimal
: has_stencil ? vk::ImageLayout::eDepthStencilReadOnlyOptimal
: vk::ImageLayout::eDepthReadOnlyOptimal;
image.Transit(new_layout, vk::AccessFlagBits::eDepthStencilAttachmentWrite |
vk::AccessFlagBits::eDepthStencilAttachmentRead);
@ -224,11 +339,16 @@ ImageView& TextureCache::FindDepthTarget(const ImageInfo& image_info,
// Update tracked image usage
image.info.usage.depth_target = true;
image.info.usage.stencil = has_stencil;
return RegisterImageView(image_id, view_info);
}
void TextureCache::RefreshImage(Image& image, Vulkan::Scheduler* custom_scheduler /*= nullptr*/) {
if (False(image.flags & ImageFlagBits::CpuModified)) {
return;
}
// Mark image as validated.
image.flags &= ~ImageFlagBits::CpuModified;
@ -260,7 +380,7 @@ void TextureCache::RefreshImage(Image& image, Vulkan::Scheduler* custom_schedule
.bufferRowLength = static_cast<u32>(mip_pitch),
.bufferImageHeight = static_cast<u32>(mip_height),
.imageSubresource{
.aspectMask = vk::ImageAspectFlagBits::eColor,
.aspectMask = image.aspect_mask & ~vk::ImageAspectFlagBits::eStencil,
.mipLevel = m,
.baseArrayLayer = 0,
.layerCount = num_layers,
@ -282,16 +402,20 @@ void TextureCache::RefreshImage(Image& image, Vulkan::Scheduler* custom_schedule
const VAddr image_addr = image.info.guest_address;
const size_t image_size = image.info.guest_size_bytes;
vk::Buffer buffer{};
u32 offset{};
if (auto upload_buffer = tile_manager.TryDetile(image); upload_buffer) {
buffer = *upload_buffer;
} else {
const auto [vk_buffer, buf_offset] = buffer_cache.ObtainTempBuffer(image_addr, image_size);
buffer = vk_buffer->Handle();
offset = buf_offset;
const auto [vk_buffer, buf_offset] = buffer_cache.ObtainTempBuffer(image_addr, image_size);
// The obtained buffer may be written by a shader so we need to emit a barrier to prevent RAW
// hazard
if (auto barrier = vk_buffer->GetBarrier(vk::AccessFlagBits2::eTransferRead,
vk::PipelineStageFlagBits2::eTransfer)) {
const auto dependencies = vk::DependencyInfo{
.dependencyFlags = vk::DependencyFlagBits::eByRegion,
.bufferMemoryBarrierCount = 1,
.pBufferMemoryBarriers = &barrier.value(),
};
cmdbuf.pipelineBarrier2(dependencies);
}
const auto [buffer, offset] = tile_manager.TryDetile(vk_buffer->Handle(), buf_offset, image);
for (auto& copy : image_copy) {
copy.bufferOffset += offset;
}
@ -335,7 +459,8 @@ void TextureCache::UnregisterImage(ImageId image_id) {
});
}
void TextureCache::TrackImage(Image& image, ImageId image_id) {
void TextureCache::TrackImage(ImageId image_id) {
auto& image = slot_images[image_id];
if (True(image.flags & ImageFlagBits::Tracked)) {
return;
}
@ -343,7 +468,8 @@ void TextureCache::TrackImage(Image& image, ImageId image_id) {
tracker.UpdatePagesCachedCount(image.cpu_addr, image.info.guest_size_bytes, 1);
}
void TextureCache::UntrackImage(Image& image, ImageId image_id) {
void TextureCache::UntrackImage(ImageId image_id) {
auto& image = slot_images[image_id];
if (False(image.flags & ImageFlagBits::Tracked)) {
return;
}
@ -356,6 +482,8 @@ void TextureCache::DeleteImage(ImageId image_id) {
ASSERT_MSG(False(image.flags & ImageFlagBits::Tracked), "Image was not untracked");
ASSERT_MSG(False(image.flags & ImageFlagBits::Registered), "Image was not unregistered");
image.flags |= ImageFlagBits::Deleted;
// Remove any registered meta areas.
const auto& meta_info = image.info.meta_info;
if (meta_info.cmask_addr) {

View file

@ -23,6 +23,16 @@ namespace VideoCore {
class BufferCache;
class PageManager;
enum class FindFlags {
NoCreate = 1 << 0, ///< Do not create an image if searching for one fails.
RelaxDim = 1 << 1, ///< Do not check the dimentions of image, only address.
RelaxSize = 1 << 2, ///< Do not check that the size matches exactly.
RelaxFmt = 1 << 3, ///< Do not check that format is compatible.
};
DECLARE_ENUM_FLAG_OPERATORS(FindFlags)
static constexpr u32 MaxInvalidateDist = 12_MB;
class TextureCache {
struct Traits {
using Entry = boost::container::small_vector<ImageId, 16>;
@ -44,7 +54,7 @@ public:
void UnmapMemory(VAddr cpu_addr, size_t size);
/// Retrieves the image handle of the image with the provided attributes.
[[nodiscard]] ImageId FindImage(const ImageInfo& info);
[[nodiscard]] ImageId FindImage(const ImageInfo& info, FindFlags flags = {});
/// Retrieves an image view with the properties of the specified image descriptor.
[[nodiscard]] ImageView& FindTexture(const ImageInfo& image_info,
@ -61,13 +71,19 @@ public:
/// Updates image contents if it was modified by CPU.
void UpdateImage(ImageId image_id, Vulkan::Scheduler* custom_scheduler = nullptr) {
Image& image = slot_images[image_id];
if (False(image.flags & ImageFlagBits::CpuModified)) {
return;
}
TrackImage(image_id);
RefreshImage(image, custom_scheduler);
TrackImage(image, image_id);
}
[[nodiscard]] ImageId ResolveOverlap(const ImageInfo& info, ImageId cache_img_id,
ImageId merged_image_id);
/// Resolves depth overlap and either re-creates the image or returns existing one
[[nodiscard]] ImageId ResolveDepthOverlap(const ImageInfo& requested_info,
ImageId cache_img_id);
[[nodiscard]] ImageId ExpandImage(const ImageInfo& info, ImageId image_id);
/// Reuploads image contents.
void RefreshImage(Image& image, Vulkan::Scheduler* custom_scheduler = nullptr);
@ -100,31 +116,12 @@ public:
return false;
}
private:
ImageView& RegisterImageView(ImageId image_id, const ImageViewInfo& view_info);
/// Iterate over all page indices in a range
template <typename Func>
static void ForEachPage(PAddr addr, size_t size, Func&& func) {
static constexpr bool RETURNS_BOOL = std::is_same_v<std::invoke_result<Func, u64>, bool>;
const u64 page_end = (addr + size - 1) >> Traits::PageBits;
for (u64 page = addr >> Traits::PageBits; page <= page_end; ++page) {
if constexpr (RETURNS_BOOL) {
if (func(page)) {
break;
}
} else {
func(page);
}
}
}
template <typename Func>
void ForEachImageInRegion(VAddr cpu_addr, size_t size, Func&& func) {
using FuncReturn = typename std::invoke_result<Func, ImageId, Image&>::type;
static constexpr bool BOOL_BREAK = std::is_same_v<FuncReturn, bool>;
boost::container::small_vector<ImageId, 32> images;
ForEachPage(cpu_addr, size, [this, &images, func](u64 page) {
ForEachPage(cpu_addr, size, [this, &images, cpu_addr, size, func](u64 page) {
const auto it = page_table.find(page);
if (it == nullptr) {
if constexpr (BOOL_BREAK) {
@ -138,6 +135,9 @@ private:
if (image.flags & ImageFlagBits::Picked) {
continue;
}
if (!image.Overlaps(cpu_addr, size)) {
continue;
}
image.flags |= ImageFlagBits::Picked;
images.push_back(image_id);
if constexpr (BOOL_BREAK) {
@ -157,6 +157,26 @@ private:
}
}
private:
/// Iterate over all page indices in a range
template <typename Func>
static void ForEachPage(PAddr addr, size_t size, Func&& func) {
static constexpr bool RETURNS_BOOL = std::is_same_v<std::invoke_result<Func, u64>, bool>;
const u64 page_end = (addr + size - 1) >> Traits::PageBits;
for (u64 page = addr >> Traits::PageBits; page <= page_end; ++page) {
if constexpr (RETURNS_BOOL) {
if (func(page)) {
break;
}
} else {
func(page);
}
}
}
/// Registers an image view for provided image
ImageView& RegisterImageView(ImageId image_id, const ImageViewInfo& view_info);
/// Create an image from the given parameters
[[nodiscard]] ImageId InsertImage(const ImageInfo& info, VAddr cpu_addr);
@ -167,14 +187,20 @@ private:
void UnregisterImage(ImageId image);
/// Track CPU reads and writes for image
void TrackImage(Image& image, ImageId image_id);
void TrackImage(ImageId image_id);
/// Stop tracking CPU reads and writes for image
void UntrackImage(Image& image, ImageId image_id);
void UntrackImage(ImageId image_id);
/// Removes the image and any views/surface metas that reference it.
void DeleteImage(ImageId image_id);
void FreeImage(ImageId image_id) {
UntrackImage(image_id);
UnregisterImage(image_id);
DeleteImage(image_id);
}
private:
const Vulkan::Instance& instance;
Vulkan::Scheduler& scheduler;

View file

@ -254,11 +254,8 @@ struct DetilerParams {
u32 sizes[14];
};
static constexpr size_t StreamBufferSize = 1_GB;
TileManager::TileManager(const Vulkan::Instance& instance, Vulkan::Scheduler& scheduler)
: instance{instance}, scheduler{scheduler},
stream_buffer{instance, scheduler, MemoryUsage::Upload, StreamBufferSize} {
: instance{instance}, scheduler{scheduler} {
static const std::array detiler_shaders{
HostShaders::DETILE_M8X1_COMP, HostShaders::DETILE_M8X2_COMP,
HostShaders::DETILE_M32X1_COMP, HostShaders::DETILE_M32X2_COMP,
@ -380,35 +377,23 @@ void TileManager::FreeBuffer(ScratchBuffer buffer) {
vmaDestroyBuffer(instance.GetAllocator(), buffer.first, buffer.second);
}
std::optional<vk::Buffer> TileManager::TryDetile(Image& image) {
std::pair<vk::Buffer, u32> TileManager::TryDetile(vk::Buffer in_buffer, u32 in_offset,
Image& image) {
if (!image.info.props.is_tiled) {
return std::nullopt;
return {in_buffer, in_offset};
}
const auto* detiler = GetDetiler(image);
if (!detiler) {
if (image.info.tiling_mode != AmdGpu::TilingMode::Texture_MacroTiled) {
if (image.info.tiling_mode != AmdGpu::TilingMode::Texture_MacroTiled &&
image.info.tiling_mode != AmdGpu::TilingMode::Display_MacroTiled) {
LOG_ERROR(Render_Vulkan, "Unsupported tiled image: {} ({})",
vk::to_string(image.info.pixel_format), NameOf(image.info.tiling_mode));
}
return std::nullopt;
return {in_buffer, in_offset};
}
// Prepare input buffer
const u32 image_size = image.info.guest_size_bytes;
const auto [in_buffer, in_offset] = [&] -> std::pair<vk::Buffer, u32> {
// Use stream buffer for smaller textures.
if (image_size <= stream_buffer.GetFreeSize()) {
u32 offset = stream_buffer.Copy(image.info.guest_address, image_size);
return {stream_buffer.Handle(), offset};
}
// Request temporary host buffer for larger sizes.
auto in_buffer = AllocBuffer(image_size);
const auto addr = reinterpret_cast<const void*>(image.info.guest_address);
Upload(in_buffer, addr, image_size);
scheduler.DeferOperation([=, this]() { FreeBuffer(in_buffer); });
return {in_buffer.first, 0};
}();
// Prepare output buffer
auto out_buffer = AllocBuffer(image_size, true);
@ -479,7 +464,7 @@ std::optional<vk::Buffer> TileManager::TryDetile(Image& image) {
vk::PipelineStageFlagBits::eTransfer, vk::DependencyFlagBits::eByRegion,
{}, post_barrier, {});
return {out_buffer.first};
return {out_buffer.first, 0};
}
} // namespace VideoCore

View file

@ -39,7 +39,7 @@ public:
TileManager(const Vulkan::Instance& instance, Vulkan::Scheduler& scheduler);
~TileManager();
std::optional<vk::Buffer> TryDetile(Image& image);
std::pair<vk::Buffer, u32> TryDetile(vk::Buffer in_buffer, u32 in_offset, Image& image);
ScratchBuffer AllocBuffer(u32 size, bool is_storage = false);
void Upload(ScratchBuffer buffer, const void* data, size_t size);
@ -51,7 +51,6 @@ private:
private:
const Vulkan::Instance& instance;
Vulkan::Scheduler& scheduler;
StreamBuffer stream_buffer;
std::array<DetilerContext, DetilerType::Max> detilers;
};

View file

@ -36,6 +36,8 @@ struct Extent3D {
u32 width;
u32 height;
u32 depth;
auto operator<=>(const Extent3D&) const = default;
};
struct SubresourceLayers {