Merge branch 'upstreamMain'

This commit is contained in:
kalaposfos13 2024-10-20 09:41:28 +02:00
commit abbff1fa66
59 changed files with 1127 additions and 389 deletions

View File

@ -30,6 +30,7 @@ if(UNIX AND NOT APPLE)
endif() endif()
option(ENABLE_QT_GUI "Enable the Qt GUI. If not selected then the emulator uses a minimal SDL-based UI instead" OFF) option(ENABLE_QT_GUI "Enable the Qt GUI. If not selected then the emulator uses a minimal SDL-based UI instead" OFF)
option(ENABLE_DISCORD_RPC "Enable the Discord RPC integration" ON)
# First, determine whether to use CMAKE_OSX_ARCHITECTURES or CMAKE_SYSTEM_PROCESSOR. # First, determine whether to use CMAKE_OSX_ARCHITECTURES or CMAKE_SYSTEM_PROCESSOR.
if (APPLE AND CMAKE_OSX_ARCHITECTURES) if (APPLE AND CMAKE_OSX_ARCHITECTURES)
@ -405,8 +406,6 @@ set(COMMON src/common/logging/backend.cpp
src/common/debug.h src/common/debug.h
src/common/decoder.cpp src/common/decoder.cpp
src/common/decoder.h src/common/decoder.h
src/common/discord_rpc_handler.cpp
src/common/discord_rpc_handler.h
src/common/elf_info.h src/common/elf_info.h
src/common/endian.h src/common/endian.h
src/common/enum.h src/common/enum.h
@ -447,6 +446,10 @@ set(COMMON src/common/logging/backend.cpp
src/common/scm_rev.h src/common/scm_rev.h
) )
if (ENABLE_DISCORD_RPC)
list(APPEND COMMON src/common/discord_rpc_handler.cpp src/common/discord_rpc_handler.h)
endif()
set(CORE src/core/aerolib/stubs.cpp set(CORE src/core/aerolib/stubs.cpp
src/core/aerolib/stubs.h src/core/aerolib/stubs.h
src/core/aerolib/aerolib.cpp src/core/aerolib/aerolib.cpp
@ -895,7 +898,9 @@ if (UNIX AND NOT APPLE)
endif() endif()
# Discord RPC # Discord RPC
target_link_libraries(shadps4 PRIVATE discord-rpc) if (ENABLE_DISCORD_RPC)
target_link_libraries(shadps4 PRIVATE discord-rpc)
endif()
# Install rules # Install rules
install(TARGETS shadps4 BUNDLE DESTINATION .) install(TARGETS shadps4 BUNDLE DESTINATION .)

View File

@ -188,9 +188,11 @@ if (NOT TARGET pugixml::pugixml)
endif() endif()
# Discord RPC # Discord RPC
set(BUILD_EXAMPLES OFF) if (ENABLE_DISCORD_RPC)
add_subdirectory(discord-rpc/) set(BUILD_EXAMPLES OFF)
target_include_directories(discord-rpc INTERFACE discord-rpc/include) add_subdirectory(discord-rpc/)
target_include_directories(discord-rpc INTERFACE discord-rpc/include)
endif()
# GCN Headers # GCN Headers
add_subdirectory(gcn) add_subdirectory(gcn)

View File

@ -45,6 +45,10 @@ public:
explicit AddressSpace(); explicit AddressSpace();
~AddressSpace(); ~AddressSpace();
[[nodiscard]] u8* BackingBase() const noexcept {
return backing_base;
}
[[nodiscard]] VAddr SystemManagedVirtualBase() noexcept { [[nodiscard]] VAddr SystemManagedVirtualBase() noexcept {
return reinterpret_cast<VAddr>(system_managed_base); return reinterpret_cast<VAddr>(system_managed_base);
} }

View File

@ -31,7 +31,8 @@ void MntPoints::UnmountAll() {
std::filesystem::path MntPoints::GetHostPath(std::string_view path, bool* is_read_only) { std::filesystem::path MntPoints::GetHostPath(std::string_view path, bool* is_read_only) {
// Evil games like Turok2 pass double slashes e.g /app0//game.kpf // Evil games like Turok2 pass double slashes e.g /app0//game.kpf
std::string corrected_path(path); std::string corrected_path(path);
while (size_t pos = corrected_path.find("//") != std::string::npos) { size_t pos = corrected_path.find("//");
while (pos != std::string::npos) {
corrected_path.replace(pos, 2, "/"); corrected_path.replace(pos, 2, "/");
pos = corrected_path.find("//", pos + 1); pos = corrected_path.find("//", pos + 1);
} }

View File

@ -54,6 +54,17 @@ void MemoryManager::SetupMemoryRegions(u64 flexible_size) {
total_flexible_size, total_direct_size); total_flexible_size, total_direct_size);
} }
bool MemoryManager::TryWriteBacking(void* address, const void* data, u32 num_bytes) {
const VAddr virtual_addr = std::bit_cast<VAddr>(address);
const auto& vma = FindVMA(virtual_addr)->second;
if (vma.type != VMAType::Direct) {
return false;
}
u8* backing = impl.BackingBase() + vma.phys_base + (virtual_addr - vma.base);
memcpy(backing, data, num_bytes);
return true;
}
PAddr MemoryManager::PoolExpand(PAddr search_start, PAddr search_end, size_t size, u64 alignment) { PAddr MemoryManager::PoolExpand(PAddr search_start, PAddr search_end, size_t size, u64 alignment) {
std::scoped_lock lk{mutex}; std::scoped_lock lk{mutex};

View File

@ -149,6 +149,8 @@ public:
return impl.SystemReservedVirtualBase(); return impl.SystemReservedVirtualBase();
} }
bool TryWriteBacking(void* address, const void* data, u32 num_bytes);
void SetupMemoryRegions(u64 flexible_size); void SetupMemoryRegions(u64 flexible_size);
PAddr PoolExpand(PAddr search_start, PAddr search_end, size_t size, u64 alignment); PAddr PoolExpand(PAddr search_start, PAddr search_end, size_t size, u64 alignment);

View File

@ -12,7 +12,9 @@
#include "common/memory_patcher.h" #include "common/memory_patcher.h"
#endif #endif
#include "common/assert.h" #include "common/assert.h"
#ifdef ENABLE_DISCORD_RPC
#include "common/discord_rpc_handler.h" #include "common/discord_rpc_handler.h"
#endif
#include "common/elf_info.h" #include "common/elf_info.h"
#include "common/ntapi.h" #include "common/ntapi.h"
#include "common/path_util.h" #include "common/path_util.h"
@ -244,6 +246,7 @@ void Emulator::Run(const std::filesystem::path& file) {
} }
} }
#ifdef ENABLE_DISCORD_RPC
// Discord RPC // Discord RPC
if (Config::getEnableDiscordRPC()) { if (Config::getEnableDiscordRPC()) {
auto* rpc = Common::Singleton<DiscordRPCHandler::RPC>::Instance(); auto* rpc = Common::Singleton<DiscordRPCHandler::RPC>::Instance();
@ -252,11 +255,13 @@ void Emulator::Run(const std::filesystem::path& file) {
} }
rpc->setStatusPlaying(game_info.title, id); rpc->setStatusPlaying(game_info.title, id);
} }
#endif
// start execution // start execution
std::jthread mainthread = std::jthread mainthread =
std::jthread([this](std::stop_token stop_token) { linker->Execute(); }); std::jthread([this](std::stop_token stop_token) { linker->Execute(); });
window->initTimers();
while (window->isOpen()) { while (window->isOpen()) {
window->waitEvent(); window->waitEvent();
} }

View File

@ -1,10 +1,13 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <SDL3/SDL.h> #include "controller.h"
#include "common/assert.h"
#include "core/libraries/kernel/time_management.h" #include "core/libraries/kernel/time_management.h"
#include "core/libraries/pad/pad.h" #include "core/libraries/pad/pad.h"
#include "input/controller.h"
#include <SDL3/SDL.h>
namespace Input { namespace Input {
@ -157,4 +160,23 @@ void GameController::TryOpenSDLController() {
} }
} }
u32 GameController::Poll() {
if (m_connected) {
auto time = Libraries::Kernel::sceKernelGetProcessTime();
if (m_states_num == 0) {
auto diff = (time - m_last_state.time) / 1000;
if (diff >= 100) {
AddState(GetLastState());
}
} else {
auto index = (m_first_state - 1 + m_states_num) % MAX_STATES;
auto diff = (time - m_states[index].time) / 1000;
if (m_private[index].obtained && diff >= 100) {
AddState(GetLastState());
}
}
}
return 100;
}
} // namespace Input } // namespace Input

View File

@ -56,6 +56,7 @@ public:
bool SetVibration(u8 smallMotor, u8 largeMotor); bool SetVibration(u8 smallMotor, u8 largeMotor);
void SetTouchpadState(int touchIndex, bool touchDown, float x, float y); void SetTouchpadState(int touchIndex, bool touchDown, float x, float y);
void TryOpenSDLController(); void TryOpenSDLController();
u32 Poll();
private: private:
struct StateInternal { struct StateInternal {

View File

@ -32,8 +32,6 @@
#include "common/path_util.h" #include "common/path_util.h"
#include "core/module.h" #include "core/module.h"
using namespace Common::FS;
CheatsPatches::CheatsPatches(const QString& gameName, const QString& gameSerial, CheatsPatches::CheatsPatches(const QString& gameName, const QString& gameSerial,
const QString& gameVersion, const QString& gameSize, const QString& gameVersion, const QString& gameSize,
const QPixmap& gameImage, QWidget* parent) const QPixmap& gameImage, QWidget* parent)
@ -776,6 +774,7 @@ void CheatsPatches::downloadPatches(const QString repository, const bool showMes
// Create the files.json file with the identification of which file to open // Create the files.json file with the identification of which file to open
createFilesJson(repository); createFilesJson(repository);
populateFileListPatches(); populateFileListPatches();
compatibleVersionNotice(repository);
} else { } else {
if (showMessageBox) { if (showMessageBox) {
QMessageBox::warning(this, tr("Error"), QMessageBox::warning(this, tr("Error"),
@ -787,6 +786,84 @@ void CheatsPatches::downloadPatches(const QString repository, const bool showMes
}); });
} }
void CheatsPatches::compatibleVersionNotice(const QString repository) {
QDir patchesDir(Common::FS::GetUserPath(Common::FS::PathType::PatchesDir));
QDir dir = patchesDir.filePath(repository);
QStringList xmlFiles = dir.entryList(QStringList() << "*.xml", QDir::Files);
QSet<QString> appVersionsSet;
foreach (const QString& xmlFile, xmlFiles) {
QFile file(dir.filePath(xmlFile));
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QMessageBox::warning(this, tr("ERROR"),
QString(tr("Failed to open file:") + "\n%1").arg(xmlFile));
continue;
}
QXmlStreamReader xmlReader(&file);
bool foundMatchingID = false;
while (!xmlReader.atEnd() && !xmlReader.hasError()) {
QXmlStreamReader::TokenType token = xmlReader.readNext();
if (token == QXmlStreamReader::StartElement) {
if (xmlReader.name() == QStringLiteral("ID")) {
QString id = xmlReader.readElementText();
if (id == m_gameSerial) {
foundMatchingID = true;
}
} else if (xmlReader.name() == QStringLiteral("Metadata")) {
if (foundMatchingID) {
QString appVer = xmlReader.attributes().value("AppVer").toString();
if (!appVer.isEmpty()) {
appVersionsSet.insert(appVer);
}
}
}
}
}
if (xmlReader.hasError()) {
QMessageBox::warning(this, tr("ERROR"),
QString(tr("XML ERROR:") + "\n%1").arg(xmlReader.errorString()));
}
if (foundMatchingID) {
QStringList incompatibleVersions;
bool hasMatchingVersion = false;
foreach (const QString& appVer, appVersionsSet) {
if (appVer != m_gameVersion) {
incompatibleVersions.append(appVer);
} else {
hasMatchingVersion = true;
}
}
if (!incompatibleVersions.isEmpty() ||
(hasMatchingVersion && incompatibleVersions.isEmpty())) {
QString message;
if (!incompatibleVersions.isEmpty()) {
QString versionsList = incompatibleVersions.join(", ");
message += QString(tr("The game is in version: %1")).arg(m_gameVersion) + "\n" +
QString(tr("The downloaded patch only works on version: %1"))
.arg(versionsList);
if (hasMatchingVersion) {
message += QString(", %1").arg(m_gameVersion);
}
message += QString("\n" + tr("You may need to update your game."));
}
if (!message.isEmpty()) {
QMessageBox::information(this, tr("Incompatibility Notice"), message);
}
}
}
}
}
void CheatsPatches::createFilesJson(const QString& repository) { void CheatsPatches::createFilesJson(const QString& repository) {
QDir dir(Common::FS::GetUserPath(Common::FS::PathType::PatchesDir)); QDir dir(Common::FS::GetUserPath(Common::FS::PathType::PatchesDir));
@ -1126,8 +1203,8 @@ void CheatsPatches::addPatchesToLayout(const QString& filePath) {
} }
} }
// Remove the item from the list view if no patches were added (the game has patches, but not // Remove the item from the list view if no patches were added
// for the current version) // (the game has patches, but not for the current version)
if (!patchAdded) { if (!patchAdded) {
QStringListModel* model = qobject_cast<QStringListModel*>(patchesListView->model()); QStringListModel* model = qobject_cast<QStringListModel*>(patchesListView->model());
if (model) { if (model) {
@ -1154,12 +1231,6 @@ void CheatsPatches::updateNoteTextEdit(const QString& patchName) {
QString type = lineObject["Type"].toString(); QString type = lineObject["Type"].toString();
QString address = lineObject["Address"].toString(); QString address = lineObject["Address"].toString();
QString patchValue = lineObject["Value"].toString(); QString patchValue = lineObject["Value"].toString();
// add the values to be modified in instructionsTextEdit
// text.append(QString("\nType: %1\nAddress: %2\n\nValue: %3")
// .arg(type)
// .arg(address)
// .arg(patchValue));
} }
text.replace("\\n", "\n"); text.replace("\\n", "\n");
instructionsTextEdit->setText(text); instructionsTextEdit->setText(text);

View File

@ -32,11 +32,11 @@ public:
const QString& gameSize, const QPixmap& gameImage, QWidget* parent = nullptr); const QString& gameSize, const QPixmap& gameImage, QWidget* parent = nullptr);
~CheatsPatches(); ~CheatsPatches();
// Public Methods
void downloadCheats(const QString& source, const QString& m_gameSerial, void downloadCheats(const QString& source, const QString& m_gameSerial,
const QString& m_gameVersion, bool showMessageBox); const QString& m_gameVersion, bool showMessageBox);
void downloadPatches(const QString repository, const bool showMessageBox); void downloadPatches(const QString repository, const bool showMessageBox);
void createFilesJson(const QString& repository); void createFilesJson(const QString& repository);
void compatibleVersionNotice(const QString repository);
signals: signals:
void downloadFinished(); void downloadFinished();

View File

@ -1026,7 +1026,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="763"/> <location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source> <source>DownloadComplete_MSG</source>
<translation>تم تنزيل التصحيحات بنجاح! تم تنزيل جميع التصحيحات لجميع الألعاب، ولا داعي لتنزيلها بشكل فردي لكل لعبة كما هو الحال مع الغش. إذا لم يظهر التحديث، قد يكون السبب أنه غير متوفر للإصدار وسيريال اللعبة المحدد. قد تحتاج إلى تحديث اللعبة.</translation> <translation>تم تنزيل التصحيحات بنجاح! تم تنزيل جميع التصحيحات لجميع الألعاب، ولا داعي لتنزيلها بشكل فردي لكل لعبة كما هو الحال مع الغش. إذا لم يظهر التحديث، قد يكون السبب أنه غير متوفر للإصدار وسيريال اللعبة المحدد.</translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="773"/> <location filename="../cheats_patches.cpp" line="773"/>
@ -1038,6 +1038,26 @@
<source>Failed to retrieve HTML page.</source> <source>Failed to retrieve HTML page.</source>
<translation>.HTML فشل في استرجاع صفحة</translation> <translation>.HTML فشل في استرجاع صفحة</translation>
</message> </message>
<message>
<location filename="../cheats_patches.cpp" line="850"/>
<source>The game is in version: %1</source>
<translation>اللعبة في الإصدار: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="851"/>
<source>The downloaded patch only works on version: %1</source>
<translation>الباتش الذي تم تنزيله يعمل فقط على الإصدار: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="856"/>
<source>You may need to update your game.</source>
<translation>قد تحتاج إلى تحديث لعبتك.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="860"/>
<source>Incompatibility Notice</source>
<translation>إشعار عدم التوافق</translation>
</message>
<message> <message>
<location filename="../cheats_patches.cpp" line="801"/> <location filename="../cheats_patches.cpp" line="801"/>
<source>Failed to open file:</source> <source>Failed to open file:</source>

View File

@ -1026,7 +1026,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="763"/> <location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source> <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. 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> <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.</translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="773"/> <location filename="../cheats_patches.cpp" line="773"/>
@ -1038,6 +1038,26 @@
<source>Failed to retrieve HTML page.</source> <source>Failed to retrieve HTML page.</source>
<translation>Kunne ikke hente HTML-side.</translation> <translation>Kunne ikke hente HTML-side.</translation>
</message> </message>
<message>
<location filename="../cheats_patches.cpp" line="850"/>
<source>The game is in version: %1</source>
<translation>Spillet er i version: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="851"/>
<source>The downloaded patch only works on version: %1</source>
<translation>Den downloadede patch fungerer kun version: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="856"/>
<source>You may need to update your game.</source>
<translation>Du skal muligvis opdatere dit spil.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="860"/>
<source>Incompatibility Notice</source>
<translation>Uforenelighedsmeddelelse</translation>
</message>
<message> <message>
<location filename="../cheats_patches.cpp" line="801"/> <location filename="../cheats_patches.cpp" line="801"/>
<source>Failed to open file:</source> <source>Failed to open file:</source>

View File

@ -1026,7 +1026,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="763"/> <location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source> <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. 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> <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.</translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="773"/> <location filename="../cheats_patches.cpp" line="773"/>
@ -1038,6 +1038,26 @@
<source>Failed to retrieve HTML page.</source> <source>Failed to retrieve HTML page.</source>
<translation>Fehler beim Abrufen der HTML-Seite.</translation> <translation>Fehler beim Abrufen der HTML-Seite.</translation>
</message> </message>
<message>
<location filename="../cheats_patches.cpp" line="850"/>
<source>The game is in version: %1</source>
<translation>Das Spiel ist in der Version: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="851"/>
<source>The downloaded patch only works on version: %1</source>
<translation>Der heruntergeladene Patch funktioniert nur in der Version: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="856"/>
<source>You may need to update your game.</source>
<translation>Sie müssen möglicherweise Ihr Spiel aktualisieren.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="860"/>
<source>Incompatibility Notice</source>
<translation>Inkompatibilitätsbenachrichtigung</translation>
</message>
<message> <message>
<location filename="../cheats_patches.cpp" line="801"/> <location filename="../cheats_patches.cpp" line="801"/>
<source>Failed to open file:</source> <source>Failed to open file:</source>

View File

@ -1026,7 +1026,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="763"/> <location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source> <source>DownloadComplete_MSG</source>
<translation>Τα Patches κατεβάστηκαν επιτυχώς! Όλα τα Patches για όλα τα παιχνίδια έχουν κατέβει, δεν είναι απαραίτητο να τα κατεβάσετε ένα-ένα για κάθε παιχνίδι, όπως με τα Cheats. Εάν η ενημέρωση δεν εμφανίζεται, μπορεί να μην υπάρχει για τον συγκεκριμένο σειριακό αριθμό και έκδοση του παιχνιδιού. Μπορεί να χρειαστεί να ενημερώσετε το παιχνίδι.</translation> <translation>Τα Patches κατεβάστηκαν επιτυχώς! Όλα τα Patches για όλα τα παιχνίδια έχουν κατέβει, δεν είναι απαραίτητο να τα κατεβάσετε ένα-ένα για κάθε παιχνίδι, όπως με τα Cheats. Εάν η ενημέρωση δεν εμφανίζεται, μπορεί να μην υπάρχει για τον συγκεκριμένο σειριακό αριθμό και έκδοση του παιχνιδιού.</translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="773"/> <location filename="../cheats_patches.cpp" line="773"/>
@ -1038,6 +1038,26 @@
<source>Failed to retrieve HTML page.</source> <source>Failed to retrieve HTML page.</source>
<translation>Αποτυχία ανάκτησης σελίδας HTML.</translation> <translation>Αποτυχία ανάκτησης σελίδας HTML.</translation>
</message> </message>
<message>
<location filename="../cheats_patches.cpp" line="850"/>
<source>The game is in version: %1</source>
<translation>Το παιχνίδι είναι στην έκδοση: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="851"/>
<source>The downloaded patch only works on version: %1</source>
<translation>Η ληφθείσα ενημέρωση λειτουργεί μόνο στην έκδοση: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="856"/>
<source>You may need to update your game.</source>
<translation>Μπορεί να χρειαστεί να ενημερώσετε το παιχνίδι σας.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="860"/>
<source>Incompatibility Notice</source>
<translation>Ειδοποίηση ασυμβατότητας</translation>
</message>
<message> <message>
<location filename="../cheats_patches.cpp" line="801"/> <location filename="../cheats_patches.cpp" line="801"/>
<source>Failed to open file:</source> <source>Failed to open file:</source>

View File

@ -1026,7 +1026,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="763"/> <location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source> <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. 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> <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.</translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="773"/> <location filename="../cheats_patches.cpp" line="773"/>
@ -1038,6 +1038,26 @@
<source>Failed to retrieve HTML page.</source> <source>Failed to retrieve HTML page.</source>
<translation>Failed to retrieve HTML page.</translation> <translation>Failed to retrieve HTML page.</translation>
</message> </message>
<message>
<location filename="../cheats_patches.cpp" line="850"/>
<source>The game is in version: %1</source>
<translation>The game is in version: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="851"/>
<source>The downloaded patch only works on version: %1</source>
<translation>The downloaded patch only works on version: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="856"/>
<source>You may need to update your game.</source>
<translation>You may need to update your game.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="860"/>
<source>Incompatibility Notice</source>
<translation>Incompatibility Notice</translation>
</message>
<message> <message>
<location filename="../cheats_patches.cpp" line="801"/> <location filename="../cheats_patches.cpp" line="801"/>
<source>Failed to open file:</source> <source>Failed to open file:</source>

View File

@ -1026,7 +1026,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="763"/> <location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source> <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. 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> <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.</translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="773"/> <location filename="../cheats_patches.cpp" line="773"/>
@ -1038,6 +1038,26 @@
<source>Failed to retrieve HTML page.</source> <source>Failed to retrieve HTML page.</source>
<translation>Error al recuperar la página HTML.</translation> <translation>Error al recuperar la página HTML.</translation>
</message> </message>
<message>
<location filename="../cheats_patches.cpp" line="850"/>
<source>The game is in version: %1</source>
<translation>El juego está en la versión: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="851"/>
<source>The downloaded patch only works on version: %1</source>
<translation>El parche descargado solo funciona en la versión: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="856"/>
<source>You may need to update your game.</source>
<translation>Puede que necesites actualizar tu juego.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="860"/>
<source>Incompatibility Notice</source>
<translation>Aviso de incompatibilidad</translation>
</message>
<message> <message>
<location filename="../cheats_patches.cpp" line="801"/> <location filename="../cheats_patches.cpp" line="801"/>
<source>Failed to open file:</source> <source>Failed to open file:</source>

View File

@ -1021,12 +1021,12 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="762"/> <location filename="../cheats_patches.cpp" line="762"/>
<source>Download Complete</source> <source>Download Complete</source>
<translation>پچ ها با موفقیت بارگیری شدند! تمام وصله های موجود برای همه بازی ها دانلود شده اند، نیازی به دانلود جداگانه آنها برای هر بازی نیست، همانطور که در Cheats اتفاق می افتد. اگر پچ ظاهر نشد، ممکن است برای سریال و نسخه خاصی از بازی وجود نداشته باشد. ممکن است نیاز به آپدیت بازی باشد.</translation> <translation>دانلود کامل شد</translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="763"/> <location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source> <source>DownloadComplete_MSG</source>
<translation>دانلود با موفقیت به اتمام رسید</translation> <translation>پچ ها با موفقیت بارگیری شدند! تمام وصله های موجود برای همه بازی ها دانلود شده اند، نیازی به دانلود جداگانه آنها برای هر بازی نیست، همانطور که در Cheats اتفاق می افتد. اگر پچ ظاهر نشد، ممکن است برای سریال و نسخه خاصی از بازی وجود نداشته باشد.</translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="773"/> <location filename="../cheats_patches.cpp" line="773"/>
@ -1038,6 +1038,26 @@
<source>Failed to retrieve HTML page.</source> <source>Failed to retrieve HTML page.</source>
<translation>HTML خطا دربازیابی صفحه</translation> <translation>HTML خطا دربازیابی صفحه</translation>
</message> </message>
<message>
<location filename="../cheats_patches.cpp" line="850"/>
<source>The game is in version: %1</source>
<translation>بازی در نسخه: %1 است</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="851"/>
<source>The downloaded patch only works on version: %1</source>
<translation>وصله دانلود شده فقط در نسخه: %1 کار می کند</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="856"/>
<source>You may need to update your game.</source>
<translation>شاید لازم باشد بازی خود را به روز کنید.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="860"/>
<source>Incompatibility Notice</source>
<translation>اطلاعیه عدم سازگاری</translation>
</message>
<message> <message>
<location filename="../cheats_patches.cpp" line="801"/> <location filename="../cheats_patches.cpp" line="801"/>
<source>Failed to open file:</source> <source>Failed to open file:</source>

View File

@ -1026,7 +1026,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="763"/> <location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source> <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. 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> <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.</translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="773"/> <location filename="../cheats_patches.cpp" line="773"/>
@ -1038,6 +1038,26 @@
<source>Failed to retrieve HTML page.</source> <source>Failed to retrieve HTML page.</source>
<translation>HTML-sivun hakeminen epäonnistui.</translation> <translation>HTML-sivun hakeminen epäonnistui.</translation>
</message> </message>
<message>
<location filename="../cheats_patches.cpp" line="850"/>
<source>The game is in version: %1</source>
<translation>Peli on versiossa: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="851"/>
<source>The downloaded patch only works on version: %1</source>
<translation> ladattu päivitys toimii vain versiossa: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="856"/>
<source>You may need to update your game.</source>
<translation>Sinun on ehkä päivitettävä peliäsi.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="860"/>
<source>Incompatibility Notice</source>
<translation>Yhteensopivuusilmoitus</translation>
</message>
<message> <message>
<location filename="../cheats_patches.cpp" line="801"/> <location filename="../cheats_patches.cpp" line="801"/>
<source>Failed to open file:</source> <source>Failed to open file:</source>

View File

@ -1026,7 +1026,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="763"/> <location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source> <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. 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> <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.</translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="773"/> <location filename="../cheats_patches.cpp" line="773"/>
@ -1038,6 +1038,26 @@
<source>Failed to retrieve HTML page.</source> <source>Failed to retrieve HTML page.</source>
<translation>Échec de la récupération de la page HTML.</translation> <translation>Échec de la récupération de la page HTML.</translation>
</message> </message>
<message>
<location filename="../cheats_patches.cpp" line="850"/>
<source>The game is in version: %1</source>
<translation>Le jeu est en version: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="851"/>
<source>The downloaded patch only works on version: %1</source>
<translation>Le patch téléchargé ne fonctionne que sur la version: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="856"/>
<source>You may need to update your game.</source>
<translation>Vous devrez peut-être mettre à jour votre jeu.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="860"/>
<source>Incompatibility Notice</source>
<translation>Avis d'incompatibilité</translation>
</message>
<message> <message>
<location filename="../cheats_patches.cpp" line="801"/> <location filename="../cheats_patches.cpp" line="801"/>
<source>Failed to open file:</source> <source>Failed to open file:</source>

View File

@ -1026,7 +1026,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="763"/> <location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source> <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. 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> <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.</translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="773"/> <location filename="../cheats_patches.cpp" line="773"/>
@ -1038,6 +1038,26 @@
<source>Failed to retrieve HTML page.</source> <source>Failed to retrieve HTML page.</source>
<translation>Nem sikerült HTML oldal lekérése.</translation> <translation>Nem sikerült HTML oldal lekérése.</translation>
</message> </message>
<message>
<location filename="../cheats_patches.cpp" line="850"/>
<source>The game is in version: %1</source>
<translation>A játék verziója: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="851"/>
<source>The downloaded patch only works on version: %1</source>
<translation>A letöltött javítás csak a(z) %1 verzión működik</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="856"/>
<source>You may need to update your game.</source>
<translation>Lehet, hogy frissítened kell a játékodat.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="860"/>
<source>Incompatibility Notice</source>
<translation>Inkompatibilitási értesítés</translation>
</message>
<message> <message>
<location filename="../cheats_patches.cpp" line="801"/> <location filename="../cheats_patches.cpp" line="801"/>
<source>Failed to open file:</source> <source>Failed to open file:</source>

View File

@ -1026,7 +1026,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="763"/> <location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source> <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. Jika patch tidak muncul, mungkin patch tersebut tidak ada untuk nomor seri dan versi game yang spesifik. Mungkin perlu memperbarui game.</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.</translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="773"/> <location filename="../cheats_patches.cpp" line="773"/>
@ -1038,6 +1038,26 @@
<source>Failed to retrieve HTML page.</source> <source>Failed to retrieve HTML page.</source>
<translation>Gagal mengambil halaman HTML.</translation> <translation>Gagal mengambil halaman HTML.</translation>
</message> </message>
<message>
<location filename="../cheats_patches.cpp" line="850"/>
<source>The game is in version: %1</source>
<translation>Permainan berada di versi: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="851"/>
<source>The downloaded patch only works on version: %1</source>
<translation>Patch yang diunduh hanya berfungsi pada versi: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="856"/>
<source>You may need to update your game.</source>
<translation>Anda mungkin perlu memperbarui permainan Anda.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="860"/>
<source>Incompatibility Notice</source>
<translation>Pemberitahuan Ketidakcocokan</translation>
</message>
<message> <message>
<location filename="../cheats_patches.cpp" line="801"/> <location filename="../cheats_patches.cpp" line="801"/>
<source>Failed to open file:</source> <source>Failed to open file:</source>

View File

@ -1026,7 +1026,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="763"/> <location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source> <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. 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> <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.</translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="773"/> <location filename="../cheats_patches.cpp" line="773"/>
@ -1038,6 +1038,26 @@
<source>Failed to retrieve HTML page.</source> <source>Failed to retrieve HTML page.</source>
<translation>Impossibile recuperare la pagina HTML.</translation> <translation>Impossibile recuperare la pagina HTML.</translation>
</message> </message>
<message>
<location filename="../cheats_patches.cpp" line="850"/>
<source>The game is in version: %1</source>
<translation>Il gioco è nella versione: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="851"/>
<source>The downloaded patch only works on version: %1</source>
<translation>La patch scaricata funziona solo sulla versione: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="856"/>
<source>You may need to update your game.</source>
<translation>Potresti aver bisogno di aggiornare il tuo gioco.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="860"/>
<source>Incompatibility Notice</source>
<translation>Avviso di incompatibilità</translation>
</message>
<message> <message>
<location filename="../cheats_patches.cpp" line="801"/> <location filename="../cheats_patches.cpp" line="801"/>
<source>Failed to open file:</source> <source>Failed to open file:</source>

View File

@ -1026,7 +1026,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="763"/> <location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source> <source>DownloadComplete_MSG</source>
<translation> </translation> <translation> </translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="773"/> <location filename="../cheats_patches.cpp" line="773"/>
@ -1038,6 +1038,26 @@
<source>Failed to retrieve HTML page.</source> <source>Failed to retrieve HTML page.</source>
<translation>HTMLページの取得に失敗しました</translation> <translation>HTMLページの取得に失敗しました</translation>
</message> </message>
<message>
<location filename="../cheats_patches.cpp" line="850"/>
<source>The game is in version: %1</source>
<translation>: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="851"/>
<source>The downloaded patch only works on version: %1</source>
<translation>: %1 </translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="856"/>
<source>You may need to update your game.</source>
<translation></translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="860"/>
<source>Incompatibility Notice</source>
<translation></translation>
</message>
<message> <message>
<location filename="../cheats_patches.cpp" line="801"/> <location filename="../cheats_patches.cpp" line="801"/>
<source>Failed to open file:</source> <source>Failed to open file:</source>

View File

@ -1026,7 +1026,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="763"/> <location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source> <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. 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> <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.</translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="773"/> <location filename="../cheats_patches.cpp" line="773"/>
@ -1038,6 +1038,26 @@
<source>Failed to retrieve HTML page.</source> <source>Failed to retrieve HTML page.</source>
<translation>Failed to retrieve HTML page.</translation> <translation>Failed to retrieve HTML page.</translation>
</message> </message>
<message>
<location filename="../cheats_patches.cpp" line="850"/>
<source>The game is in version: %1</source>
<translation>The game is in version: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="851"/>
<source>The downloaded patch only works on version: %1</source>
<translation>The downloaded patch only works on version: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="856"/>
<source>You may need to update your game.</source>
<translation>You may need to update your game.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="860"/>
<source>Incompatibility Notice</source>
<translation>Incompatibility Notice</translation>
</message>
<message> <message>
<location filename="../cheats_patches.cpp" line="801"/> <location filename="../cheats_patches.cpp" line="801"/>
<source>Failed to open file:</source> <source>Failed to open file:</source>

View File

@ -1026,7 +1026,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="763"/> <location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source> <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. Jei pleistras nepasirodo, gali būti, kad jo nėra tam tikram žaidimo serijos numeriui ir versijai. Gali prireikti atnaujinti žaidimą.</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.</translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="773"/> <location filename="../cheats_patches.cpp" line="773"/>
@ -1038,6 +1038,26 @@
<source>Failed to retrieve HTML page.</source> <source>Failed to retrieve HTML page.</source>
<translation>Nepavyko gauti HTML puslapio.</translation> <translation>Nepavyko gauti HTML puslapio.</translation>
</message> </message>
<message>
<location filename="../cheats_patches.cpp" line="850"/>
<source>The game is in version: %1</source>
<translation>Žaidimas yra versijoje: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="851"/>
<source>The downloaded patch only works on version: %1</source>
<translation>Parsisiųstas pataisas veikia tik versijoje: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="856"/>
<source>You may need to update your game.</source>
<translation>Gali tekti atnaujinti savo žaidimą.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="860"/>
<source>Incompatibility Notice</source>
<translation>Suderinamumo pranešimas</translation>
</message>
<message> <message>
<location filename="../cheats_patches.cpp" line="801"/> <location filename="../cheats_patches.cpp" line="801"/>
<source>Failed to open file:</source> <source>Failed to open file:</source>

View File

@ -1026,7 +1026,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="763"/> <location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source> <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. 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> <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.</translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="773"/> <location filename="../cheats_patches.cpp" line="773"/>
@ -1038,6 +1038,26 @@
<source>Failed to retrieve HTML page.</source> <source>Failed to retrieve HTML page.</source>
<translation>Kunne ikke hente HTML-side.</translation> <translation>Kunne ikke hente HTML-side.</translation>
</message> </message>
<message>
<location filename="../cheats_patches.cpp" line="850"/>
<source>The game is in version: %1</source>
<translation>Spillet er i versjon: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="851"/>
<source>The downloaded patch only works on version: %1</source>
<translation>Den nedlastede patchen fungerer bare versjon: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="856"/>
<source>You may need to update your game.</source>
<translation>Du kanskje oppdatere spillet ditt.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="860"/>
<source>Incompatibility Notice</source>
<translation>Inkompatibilitetsvarsel</translation>
</message>
<message> <message>
<location filename="../cheats_patches.cpp" line="801"/> <location filename="../cheats_patches.cpp" line="801"/>
<source>Failed to open file:</source> <source>Failed to open file:</source>

View File

@ -1026,7 +1026,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="763"/> <location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source> <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. 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> <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.</translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="773"/> <location filename="../cheats_patches.cpp" line="773"/>
@ -1038,6 +1038,26 @@
<source>Failed to retrieve HTML page.</source> <source>Failed to retrieve HTML page.</source>
<translation>Kan HTML-pagina niet ophalen.</translation> <translation>Kan HTML-pagina niet ophalen.</translation>
</message> </message>
<message>
<location filename="../cheats_patches.cpp" line="850"/>
<source>The game is in version: %1</source>
<translation>Het spel is in versie: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="851"/>
<source>The downloaded patch only works on version: %1</source>
<translation>De gedownloade patch werkt alleen op versie: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="856"/>
<source>You may need to update your game.</source>
<translation>Misschien moet je je spel bijwerken.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="860"/>
<source>Incompatibility Notice</source>
<translation>Incompatibiliteitsmelding</translation>
</message>
<message> <message>
<location filename="../cheats_patches.cpp" line="801"/> <location filename="../cheats_patches.cpp" line="801"/>
<source>Failed to open file:</source> <source>Failed to open file:</source>

View File

@ -1026,7 +1026,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="763"/> <location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source> <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. 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> <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.</translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="773"/> <location filename="../cheats_patches.cpp" line="773"/>
@ -1038,6 +1038,26 @@
<source>Failed to retrieve HTML page.</source> <source>Failed to retrieve HTML page.</source>
<translation>Nie udało się pobrać strony HTML.</translation> <translation>Nie udało się pobrać strony HTML.</translation>
</message> </message>
<message>
<location filename="../cheats_patches.cpp" line="850"/>
<source>The game is in version: %1</source>
<translation>Gra jest w wersji: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="851"/>
<source>The downloaded patch only works on version: %1</source>
<translation>Pobrana łatka działa tylko w wersji: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="856"/>
<source>You may need to update your game.</source>
<translation>Możesz potrzebować zaktualizować swoją grę.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="860"/>
<source>Incompatibility Notice</source>
<translation>Powiadomienie o niezgodności</translation>
</message>
<message> <message>
<location filename="../cheats_patches.cpp" line="801"/> <location filename="../cheats_patches.cpp" line="801"/>
<source>Failed to open file:</source> <source>Failed to open file:</source>

View File

@ -1026,7 +1026,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="763"/> <location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source> <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. 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> <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.</translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="773"/> <location filename="../cheats_patches.cpp" line="773"/>
@ -1038,6 +1038,26 @@
<source>Failed to retrieve HTML page.</source> <source>Failed to retrieve HTML page.</source>
<translation>Falha ao recuperar a página HTML.</translation> <translation>Falha ao recuperar a página HTML.</translation>
</message> </message>
<message>
<location filename="../cheats_patches.cpp" line="850"/>
<source>The game is in version: %1</source>
<translation>O jogo está na versão: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="851"/>
<source>The downloaded patch only works on version: %1</source>
<translation>O patch baixado funciona na versão: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="856"/>
<source>You may need to update your game.</source>
<translation>Talvez você precise atualizar seu jogo.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="860"/>
<source>Incompatibility Notice</source>
<translation>Aviso de incompatibilidade</translation>
</message>
<message> <message>
<location filename="../cheats_patches.cpp" line="801"/> <location filename="../cheats_patches.cpp" line="801"/>
<source>Failed to open file:</source> <source>Failed to open file:</source>

View File

@ -1026,7 +1026,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="763"/> <location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source> <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. Dacă patch-ul nu apare, este posibil nu existe pentru seria și versiunea specifică a jocului. Poate fi necesar actualizați jocul.</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.</translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="773"/> <location filename="../cheats_patches.cpp" line="773"/>
@ -1038,6 +1038,26 @@
<source>Failed to retrieve HTML page.</source> <source>Failed to retrieve HTML page.</source>
<translation>Nu s-a reușit obținerea paginii HTML.</translation> <translation>Nu s-a reușit obținerea paginii HTML.</translation>
</message> </message>
<message>
<location filename="../cheats_patches.cpp" line="850"/>
<source>The game is in version: %1</source>
<translation>Jocul este în versiunea: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="851"/>
<source>The downloaded patch only works on version: %1</source>
<translation>Patch-ul descărcat funcționează doar pe versiunea: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="856"/>
<source>You may need to update your game.</source>
<translation>Este posibil trebuiască actualizezi jocul tău.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="860"/>
<source>Incompatibility Notice</source>
<translation>Avertizare de incompatibilitate</translation>
</message>
<message> <message>
<location filename="../cheats_patches.cpp" line="801"/> <location filename="../cheats_patches.cpp" line="801"/>
<source>Failed to open file:</source> <source>Failed to open file:</source>

View File

@ -1026,7 +1026,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="763"/> <location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source> <source>DownloadComplete_MSG</source>
<translation>Патчи успешно скачаны! Все доступные патчи для всех игр были скачаны, нет необходимости скачивать их по отдельности для каждой игры, как это происходит с читами. Если патч не появляется, возможно, его не существует для конкретного серийного номера и версии игры. Возможно, потребуется обновить игру.</translation> <translation>Патчи успешно скачаны! Все доступные патчи для всех игр были скачаны, нет необходимости скачивать их по отдельности для каждой игры, как это происходит с читами. Если патч не появляется, возможно, его не существует для конкретного серийного номера и версии игры.</translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="773"/> <location filename="../cheats_patches.cpp" line="773"/>
@ -1038,6 +1038,26 @@
<source>Failed to retrieve HTML page.</source> <source>Failed to retrieve HTML page.</source>
<translation>Не удалось получить HTML-страницу.</translation> <translation>Не удалось получить HTML-страницу.</translation>
</message> </message>
<message>
<location filename="../cheats_patches.cpp" line="850"/>
<source>The game is in version: %1</source>
<translation>Игра в версии: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="851"/>
<source>The downloaded patch only works on version: %1</source>
<translation>Скачанный патч работает только на версии: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="856"/>
<source>You may need to update your game.</source>
<translation>Вам может понадобиться обновить игру.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="860"/>
<source>Incompatibility Notice</source>
<translation>Уведомление о несовместимости</translation>
</message>
<message> <message>
<location filename="../cheats_patches.cpp" line="801"/> <location filename="../cheats_patches.cpp" line="801"/>
<source>Failed to open file:</source> <source>Failed to open file:</source>

View File

@ -1026,7 +1026,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="763"/> <location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source> <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'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ësosh lojën.</translation> <translation>Arnat u shkarkuan me sukses! gjitha arnat e ofruara për gjitha lojërat janë shkarkuar, nuk ka nevojë t'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.</translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="773"/> <location filename="../cheats_patches.cpp" line="773"/>
@ -1038,6 +1038,26 @@
<source>Failed to retrieve HTML page.</source> <source>Failed to retrieve HTML page.</source>
<translation>Gjetja e faqes HTML dështoi.</translation> <translation>Gjetja e faqes HTML dështoi.</translation>
</message> </message>
<message>
<location filename="../cheats_patches.cpp" line="850"/>
<source>The game is in version: %1</source>
<translation>Loja është versionin: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="851"/>
<source>The downloaded patch only works on version: %1</source>
<translation>Patch-i i shkarkuar funksionon vetëm versionin: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="856"/>
<source>You may need to update your game.</source>
<translation>Ju mund duhet përditësoni lojën tuaj.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="860"/>
<source>Incompatibility Notice</source>
<translation>Njoftim për papajtueshmëri</translation>
</message>
<message> <message>
<location filename="../cheats_patches.cpp" line="801"/> <location filename="../cheats_patches.cpp" line="801"/>
<source>Failed to open file:</source> <source>Failed to open file:</source>

View File

@ -1026,7 +1026,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="763"/> <location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source> <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. Yamanın görünmemesi durumunda, belirli seri numarası ve oyun sürümü için mevcut olmayabilir. Oyunu güncellemeniz gerekebilir.</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.</translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="773"/> <location filename="../cheats_patches.cpp" line="773"/>
@ -1038,6 +1038,26 @@
<source>Failed to retrieve HTML page.</source> <source>Failed to retrieve HTML page.</source>
<translation>HTML sayfası alınamadı.</translation> <translation>HTML sayfası alınamadı.</translation>
</message> </message>
<message>
<location filename="../cheats_patches.cpp" line="850"/>
<source>The game is in version: %1</source>
<translation>Oyun sürümde: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="851"/>
<source>The downloaded patch only works on version: %1</source>
<translation>İndirilen yamanın sadece sürümde çalışıyor: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="856"/>
<source>You may need to update your game.</source>
<translation>Oyunuzu güncellemeniz gerekebilir.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="860"/>
<source>Incompatibility Notice</source>
<translation>Uyumsuzluk Bildirimi</translation>
</message>
<message> <message>
<location filename="../cheats_patches.cpp" line="801"/> <location filename="../cheats_patches.cpp" line="801"/>
<source>Failed to open file:</source> <source>Failed to open file:</source>

View File

@ -1026,7 +1026,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="763"/> <location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source> <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. 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> <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.</translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="773"/> <location filename="../cheats_patches.cpp" line="773"/>
@ -1038,6 +1038,26 @@
<source>Failed to retrieve HTML page.</source> <source>Failed to retrieve HTML page.</source>
<translation>Không thể lấy trang HTML.</translation> <translation>Không thể lấy trang HTML.</translation>
</message> </message>
<message>
<location filename="../cheats_patches.cpp" line="850"/>
<source>The game is in version: %1</source>
<translation>Trò chơi đang phiên bản: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="851"/>
<source>The downloaded patch only works on version: %1</source>
<translation>Patch đã tải về chỉ hoạt đng trên phiên bản: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="856"/>
<source>You may need to update your game.</source>
<translation>Bạn thể cần cập nhật trò chơi của mình.</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="860"/>
<source>Incompatibility Notice</source>
<translation>Thông báo không tương thích</translation>
</message>
<message> <message>
<location filename="../cheats_patches.cpp" line="801"/> <location filename="../cheats_patches.cpp" line="801"/>
<source>Failed to open file:</source> <source>Failed to open file:</source>

View File

@ -1026,7 +1026,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="763"/> <location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source> <source>DownloadComplete_MSG</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="773"/> <location filename="../cheats_patches.cpp" line="773"/>
@ -1038,6 +1038,26 @@
<source>Failed to retrieve HTML page.</source> <source>Failed to retrieve HTML page.</source>
<translation> HTML </translation> <translation> HTML </translation>
</message> </message>
<message>
<location filename="../cheats_patches.cpp" line="850"/>
<source>The game is in version: %1</source>
<translation>: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="851"/>
<source>The downloaded patch only works on version: %1</source>
<translation>: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="856"/>
<source>You may need to update your game.</source>
<translation></translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="860"/>
<source>Incompatibility Notice</source>
<translation></translation>
</message>
<message> <message>
<location filename="../cheats_patches.cpp" line="801"/> <location filename="../cheats_patches.cpp" line="801"/>
<source>Failed to open file:</source> <source>Failed to open file:</source>

View File

@ -1026,7 +1026,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="763"/> <location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source> <source>DownloadComplete_MSG</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="773"/> <location filename="../cheats_patches.cpp" line="773"/>
@ -1038,6 +1038,26 @@
<source>Failed to retrieve HTML page.</source> <source>Failed to retrieve HTML page.</source>
<translation> HTML </translation> <translation> HTML </translation>
</message> </message>
<message>
<location filename="../cheats_patches.cpp" line="850"/>
<source>The game is in version: %1</source>
<translation>: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="851"/>
<source>The downloaded patch only works on version: %1</source>
<translation>: %1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="856"/>
<source>You may need to update your game.</source>
<translation></translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="860"/>
<source>Incompatibility Notice</source>
<translation></translation>
</message>
<message> <message>
<location filename="../cheats_patches.cpp" line="801"/> <location filename="../cheats_patches.cpp" line="801"/>
<source>Failed to open file:</source> <source>Failed to open file:</source>

View File

@ -571,6 +571,11 @@ void WindowSDL::updateMouse() {
} }
} }
static Uint32 SDLCALL PollController(void* userdata, SDL_TimerID timer_id, Uint32 interval) {
auto* controller = reinterpret_cast<Input::GameController*>(userdata);
return controller->Poll();
}
WindowSDL::WindowSDL(s32 width_, s32 height_, Input::GameController* controller_, WindowSDL::WindowSDL(s32 width_, s32 height_, Input::GameController* controller_,
std::string_view window_title) std::string_view window_title)
: width{width_}, height{height_}, controller{controller_} { : width{width_}, height{height_}, controller{controller_} {
@ -684,6 +689,14 @@ void WindowSDL::waitEvent() {
break; break;
} }
} }
<<<<<<< HEAD
=======
void WindowSDL::initTimers() {
SDL_AddTimer(100, &PollController, controller);
}
>>>>>>> upstreamMain
void WindowSDL::onResize() { void WindowSDL::onResize() {
SDL_GetWindowSizeInPixels(window, &width, &height); SDL_GetWindowSizeInPixels(window, &width, &height);
ImGui::Core::OnResize(); ImGui::Core::OnResize();

View File

@ -93,6 +93,8 @@ public:
void waitEvent(); void waitEvent();
void updateMouse(); void updateMouse();
void initTimers();
private: private:
void onResize(); void onResize();
void onKeyboardMouseEvent(const SDL_Event* event); void onKeyboardMouseEvent(const SDL_Event* event);

View File

@ -29,6 +29,14 @@ CopyShaderData ParseCopyShader(std::span<const u32> code) {
sources[inst.dst[0].code] = inst.control.sopk.simm; sources[inst.dst[0].code] = inst.control.sopk.simm;
break; break;
} }
case Gcn::Opcode::S_MOV_B32: {
sources[inst.dst[0].code] = inst.src[0].code;
break;
}
case Gcn::Opcode::S_ADDK_I32: {
sources[inst.dst[0].code] += inst.control.sopk.simm;
break;
}
case Gcn::Opcode::EXP: { case Gcn::Opcode::EXP: {
const auto& exp = inst.control.exp; const auto& exp = inst.control.exp;
const IR::Attribute semantic = static_cast<IR::Attribute>(exp.target); const IR::Attribute semantic = static_cast<IR::Attribute>(exp.target);

View File

@ -92,8 +92,12 @@ void Translator::EmitScalarAlu(const GcnInst& inst) {
break; break;
case Opcode::S_BREV_B32: case Opcode::S_BREV_B32:
return S_BREV_B32(inst); return S_BREV_B32(inst);
case Opcode::S_BCNT1_I32_B64:
return S_BCNT1_I32_B64(inst);
case Opcode::S_AND_SAVEEXEC_B64: case Opcode::S_AND_SAVEEXEC_B64:
return S_AND_SAVEEXEC_B64(inst); return S_SAVEEXEC_B64(NegateMode::None, false, inst);
case Opcode::S_ORN2_SAVEEXEC_B64:
return S_SAVEEXEC_B64(NegateMode::Src1, true, inst);
default: default:
LogMissingOpcode(inst); LogMissingOpcode(inst);
} }
@ -540,11 +544,17 @@ void Translator::S_BREV_B32(const GcnInst& inst) {
SetDst(inst.dst[0], ir.BitReverse(GetSrc(inst.src[0]))); SetDst(inst.dst[0], ir.BitReverse(GetSrc(inst.src[0])));
} }
void Translator::S_AND_SAVEEXEC_B64(const GcnInst& inst) { void Translator::S_BCNT1_I32_B64(const GcnInst& inst) {
const IR::U32 result = ir.BitCount(GetSrc(inst.src[0]));
SetDst(inst.dst[0], result);
ir.SetScc(ir.INotEqual(result, ir.Imm32(0)));
}
void Translator::S_SAVEEXEC_B64(NegateMode negate, bool is_or, const GcnInst& inst) {
// This instruction normally operates on 64-bit data (EXEC, VCC, SGPRs) // This instruction normally operates on 64-bit data (EXEC, VCC, SGPRs)
// However here we flatten it to 1-bit EXEC and 1-bit VCC. For the destination // However here we flatten it to 1-bit EXEC and 1-bit VCC. For the destination
// SGPR we have a special IR opcode for SPGRs that act as thread masks. // SGPR we have a special IR opcode for SPGRs that act as thread masks.
const IR::U1 exec{ir.GetExec()}; IR::U1 exec{ir.GetExec()};
const IR::U1 src = [&] { const IR::U1 src = [&] {
switch (inst.src[0].field) { switch (inst.src[0].field) {
case OperandField::VccLo: case OperandField::VccLo:
@ -568,7 +578,13 @@ void Translator::S_AND_SAVEEXEC_B64(const GcnInst& inst) {
} }
// Update EXEC. // Update EXEC.
const IR::U1 result = ir.LogicalAnd(exec, src); if (negate == NegateMode::Src1) {
exec = ir.LogicalNot(exec);
}
IR::U1 result = is_or ? ir.LogicalOr(exec, src) : ir.LogicalAnd(exec, src);
if (negate == NegateMode::Result) {
result = ir.LogicalNot(result);
}
ir.SetExec(result); ir.SetExec(result);
ir.SetScc(result); ir.SetScc(result);
} }

View File

@ -108,8 +108,9 @@ public:
void S_MOV_B64(const GcnInst& inst); void S_MOV_B64(const GcnInst& inst);
void S_NOT_B64(const GcnInst& inst); void S_NOT_B64(const GcnInst& inst);
void S_BREV_B32(const GcnInst& inst); void S_BREV_B32(const GcnInst& inst);
void S_BCNT1_I32_B64(const GcnInst& inst);
void S_GETPC_B64(u32 pc, const GcnInst& inst); void S_GETPC_B64(u32 pc, const GcnInst& inst);
void S_AND_SAVEEXEC_B64(const GcnInst& inst); void S_SAVEEXEC_B64(NegateMode negate, bool is_or, const GcnInst& inst);
// SOPC // SOPC
void S_CMP(ConditionOp cond, bool is_signed, const GcnInst& inst); void S_CMP(ConditionOp cond, bool is_signed, const GcnInst& inst);
@ -225,6 +226,7 @@ public:
void V_MED3_I32(const GcnInst& inst); void V_MED3_I32(const GcnInst& inst);
void V_SAD(const GcnInst& inst); void V_SAD(const GcnInst& inst);
void V_SAD_U32(const GcnInst& inst); void V_SAD_U32(const GcnInst& inst);
void V_CVT_PK_U16_U32(const GcnInst& inst);
void V_CVT_PK_U8_F32(const GcnInst& inst); void V_CVT_PK_U8_F32(const GcnInst& inst);
void V_LSHL_B64(const GcnInst& inst); void V_LSHL_B64(const GcnInst& inst);
void V_MUL_F64(const GcnInst& inst); void V_MUL_F64(const GcnInst& inst);

View File

@ -157,6 +157,8 @@ void Translator::EmitVectorAlu(const GcnInst& inst) {
return V_RCP_F64(inst); return V_RCP_F64(inst);
case Opcode::V_RCP_IFLAG_F32: case Opcode::V_RCP_IFLAG_F32:
return V_RCP_F32(inst); return V_RCP_F32(inst);
case Opcode::V_RCP_CLAMP_F32:
return V_RCP_F32(inst);
case Opcode::V_RSQ_CLAMP_F32: case Opcode::V_RSQ_CLAMP_F32:
return V_RSQ_F32(inst); return V_RSQ_F32(inst);
case Opcode::V_RSQ_LEGACY_F32: case Opcode::V_RSQ_LEGACY_F32:
@ -268,6 +270,8 @@ void Translator::EmitVectorAlu(const GcnInst& inst) {
return V_CMP_U32(ConditionOp::GT, true, true, inst); return V_CMP_U32(ConditionOp::GT, true, true, inst);
case Opcode::V_CMPX_LG_I32: case Opcode::V_CMPX_LG_I32:
return V_CMP_U32(ConditionOp::LG, true, true, inst); return V_CMP_U32(ConditionOp::LG, true, true, inst);
case Opcode::V_CMPX_GE_I32:
return V_CMP_U32(ConditionOp::GE, true, true, inst);
// V_CMP_{OP8}_U32 // V_CMP_{OP8}_U32
case Opcode::V_CMP_F_U32: case Opcode::V_CMP_F_U32:
@ -355,6 +359,8 @@ void Translator::EmitVectorAlu(const GcnInst& inst) {
return V_MED3_I32(inst); return V_MED3_I32(inst);
case Opcode::V_SAD_U32: case Opcode::V_SAD_U32:
return V_SAD_U32(inst); return V_SAD_U32(inst);
case Opcode::V_CVT_PK_U16_U32:
return V_CVT_PK_U16_U32(inst);
case Opcode::V_CVT_PK_U8_F32: case Opcode::V_CVT_PK_U8_F32:
return V_CVT_PK_U8_F32(inst); return V_CVT_PK_U8_F32(inst);
case Opcode::V_LSHL_B64: case Opcode::V_LSHL_B64:
@ -1108,6 +1114,14 @@ void Translator::V_SAD_U32(const GcnInst& inst) {
SetDst(inst.dst[0], ir.IAdd(result, src2)); SetDst(inst.dst[0], ir.IAdd(result, src2));
} }
void Translator::V_CVT_PK_U16_U32(const GcnInst& inst) {
const IR::U32 src0{GetSrc(inst.src[0])};
const IR::U32 src1{GetSrc(inst.src[1])};
const IR::U32 lo = ir.IMin(src0, ir.Imm32(0xFFFF), false);
const IR::U32 hi = ir.IMin(src1, ir.Imm32(0xFFFF), false);
SetDst(inst.dst[0], ir.BitFieldInsert(lo, hi, ir.Imm32(16), ir.Imm32(16)));
}
void Translator::V_CVT_PK_U8_F32(const GcnInst& inst) { void Translator::V_CVT_PK_U8_F32(const GcnInst& inst) {
const IR::F32 src0{GetSrc<IR::F32>(inst.src[0])}; const IR::F32 src0{GetSrc<IR::F32>(inst.src[0])};
const IR::U32 src1{GetSrc(inst.src[1])}; const IR::U32 src1{GetSrc(inst.src[1])};

View File

@ -6,6 +6,7 @@
#include <type_traits> #include <type_traits>
#include "common/func_traits.h" #include "common/func_traits.h"
#include "shader_recompiler/ir/basic_block.h" #include "shader_recompiler/ir/basic_block.h"
#include "shader_recompiler/ir/ir_emitter.h"
namespace Shader::Optimization { namespace Shader::Optimization {
@ -215,36 +216,17 @@ void FoldAdd(IR::Block& block, IR::Inst& inst) {
} }
} }
template <u32 idx> void FoldCmpClass(IR::Block& block, IR::Inst& inst) {
bool IsArgImm(const IR::Inst& inst, u32 imm) {
const IR::Value& arg = inst.Arg(idx);
return arg.IsImmediate() && arg.U32() == imm;
};
void FoldBooleanConvert(IR::Inst& inst) {
// Eliminate pattern
// %4 = <some bool>
// %5 = SelectU32 %4, #1, #0 (uses: 2)
// %8 = INotEqual %5, #0 (uses: 1)
if (!IsArgImm<1>(inst, 0)) {
return;
}
IR::Inst* prod = inst.Arg(0).TryInstRecursive();
if (!prod || prod->GetOpcode() != IR::Opcode::SelectU32) {
return;
}
if (IsArgImm<1>(*prod, 1) && IsArgImm<2>(*prod, 0)) {
inst.ReplaceUsesWith(prod->Arg(0));
}
}
void FoldCmpClass(IR::Inst& inst) {
ASSERT_MSG(inst.Arg(1).IsImmediate(), "Unable to resolve compare operation"); ASSERT_MSG(inst.Arg(1).IsImmediate(), "Unable to resolve compare operation");
const auto class_mask = static_cast<IR::FloatClassFunc>(inst.Arg(1).U32()); const auto class_mask = static_cast<IR::FloatClassFunc>(inst.Arg(1).U32());
if ((class_mask & IR::FloatClassFunc::NaN) == IR::FloatClassFunc::NaN) { if ((class_mask & IR::FloatClassFunc::NaN) == IR::FloatClassFunc::NaN) {
inst.ReplaceOpcode(IR::Opcode::FPIsNan32); inst.ReplaceOpcode(IR::Opcode::FPIsNan32);
} else if ((class_mask & IR::FloatClassFunc::Infinity) == IR::FloatClassFunc::Infinity) { } else if ((class_mask & IR::FloatClassFunc::Infinity) == IR::FloatClassFunc::Infinity) {
inst.ReplaceOpcode(IR::Opcode::FPIsInf32); inst.ReplaceOpcode(IR::Opcode::FPIsInf32);
} else if ((class_mask & IR::FloatClassFunc::Finite) == IR::FloatClassFunc::Finite) {
IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
const IR::F32 value = IR::F32{inst.Arg(0)};
inst.ReplaceUsesWith(ir.LogicalNot(ir.LogicalOr(ir.FPIsInf(value), ir.FPIsInf(value))));
} else { } else {
UNREACHABLE(); UNREACHABLE();
} }
@ -276,7 +258,7 @@ void ConstantPropagation(IR::Block& block, IR::Inst& inst) {
FoldWhenAllImmediates(inst, [](u32 a, u32 b) { return a * b; }); FoldWhenAllImmediates(inst, [](u32 a, u32 b) { return a * b; });
return; return;
case IR::Opcode::FPCmpClass32: case IR::Opcode::FPCmpClass32:
FoldCmpClass(inst); FoldCmpClass(block, inst);
return; return;
case IR::Opcode::ShiftLeftLogical32: case IR::Opcode::ShiftLeftLogical32:
FoldWhenAllImmediates(inst, [](u32 a, u32 b) { return static_cast<u32>(a << b); }); FoldWhenAllImmediates(inst, [](u32 a, u32 b) { return static_cast<u32>(a << b); });

View File

@ -605,7 +605,7 @@ void PatchImageSampleInstruction(IR::Block& block, IR::Inst& inst, Info& info,
: IR::F32{}; : IR::F32{};
const IR::F32 lod_clamp = inst_info.has_lod_clamp ? get_addr_reg(addr_reg++) : IR::F32{}; const IR::F32 lod_clamp = inst_info.has_lod_clamp ? get_addr_reg(addr_reg++) : IR::F32{};
const auto new_inst = [&] -> IR::Value { auto new_inst = [&] -> IR::Value {
if (inst_info.is_gather) { if (inst_info.is_gather) {
if (inst_info.is_depth) { if (inst_info.is_depth) {
return ir.ImageGatherDref(handle, coords, offset, dref, inst_info); return ir.ImageGatherDref(handle, coords, offset, dref, inst_info);

View File

@ -24,6 +24,8 @@ enum class FloatClassFunc : u32 {
NaN = SignalingNan | QuietNan, NaN = SignalingNan | QuietNan,
Infinity = PositiveInfinity | NegativeInfinity, Infinity = PositiveInfinity | NegativeInfinity,
Finite = NegativeNormal | NegativeDenorm | NegativeZero | PositiveNormal | PositiveDenorm |
PositiveZero,
}; };
DECLARE_ENUM_FLAG_OPERATORS(FloatClassFunc) DECLARE_ENUM_FLAG_OPERATORS(FloatClassFunc)

View File

@ -8,6 +8,7 @@
#include "common/thread.h" #include "common/thread.h"
#include "core/debug_state.h" #include "core/debug_state.h"
#include "core/libraries/videoout/driver.h" #include "core/libraries/videoout/driver.h"
#include "core/memory.h"
#include "video_core/amdgpu/liverpool.h" #include "video_core/amdgpu/liverpool.h"
#include "video_core/amdgpu/pm4_cmds.h" #include "video_core/amdgpu/pm4_cmds.h"
#include "video_core/renderdoc.h" #include "video_core/renderdoc.h"
@ -504,7 +505,12 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
} }
case PM4ItOpcode::EventWriteEos: { case PM4ItOpcode::EventWriteEos: {
const auto* event_eos = reinterpret_cast<const PM4CmdEventWriteEos*>(header); const auto* event_eos = reinterpret_cast<const PM4CmdEventWriteEos*>(header);
event_eos->SignalFence(); event_eos->SignalFence([](void* address, u64 data, u32 num_bytes) {
auto* memory = Core::Memory::Instance();
if (!memory->TryWriteBacking(address, &data, num_bytes)) {
memcpy(address, &data, num_bytes);
}
});
if (event_eos->command == PM4CmdEventWriteEos::Command::GdsStore) { if (event_eos->command == PM4CmdEventWriteEos::Command::GdsStore) {
ASSERT(event_eos->size == 1); ASSERT(event_eos->size == 1);
if (rasterizer) { if (rasterizer) {
@ -517,13 +523,42 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
} }
case PM4ItOpcode::EventWriteEop: { case PM4ItOpcode::EventWriteEop: {
const auto* event_eop = reinterpret_cast<const PM4CmdEventWriteEop*>(header); const auto* event_eop = reinterpret_cast<const PM4CmdEventWriteEop*>(header);
event_eop->SignalFence(); event_eop->SignalFence([](void* address, u64 data, u32 num_bytes) {
auto* memory = Core::Memory::Instance();
if (!memory->TryWriteBacking(address, &data, num_bytes)) {
memcpy(address, &data, num_bytes);
}
});
break; break;
} }
case PM4ItOpcode::DmaData: { case PM4ItOpcode::DmaData: {
const auto* dma_data = reinterpret_cast<const PM4DmaData*>(header); const auto* dma_data = reinterpret_cast<const PM4DmaData*>(header);
if (dma_data->dst_addr_lo == 0x3022C) {
break;
}
if (dma_data->src_sel == DmaDataSrc::Data && dma_data->dst_sel == DmaDataDst::Gds) { if (dma_data->src_sel == DmaDataSrc::Data && dma_data->dst_sel == DmaDataDst::Gds) {
rasterizer->InlineDataToGds(dma_data->dst_addr_lo, dma_data->data); rasterizer->InlineData(dma_data->dst_addr_lo, &dma_data->data, sizeof(u32),
true);
} else if (dma_data->src_sel == DmaDataSrc::Memory &&
dma_data->dst_sel == DmaDataDst::Gds) {
rasterizer->InlineData(dma_data->dst_addr_lo,
dma_data->SrcAddress<const void*>(),
dma_data->NumBytes(), true);
} else if (dma_data->src_sel == DmaDataSrc::Data &&
dma_data->dst_sel == DmaDataDst::Memory) {
rasterizer->InlineData(dma_data->DstAddress<VAddr>(), &dma_data->data,
sizeof(u32), false);
} else if (dma_data->src_sel == DmaDataSrc::Gds &&
dma_data->dst_sel == DmaDataDst::Memory) {
LOG_WARNING(Render_Vulkan, "GDS memory read");
} else if (dma_data->src_sel == DmaDataSrc::Memory &&
dma_data->dst_sel == DmaDataDst::Memory) {
rasterizer->InlineData(dma_data->DstAddress<VAddr>(),
dma_data->SrcAddress<const void*>(),
dma_data->NumBytes(), false);
} else {
UNREACHABLE_MSG("WriteData src_sel = {}, dst_sel = {}",
u32(dma_data->src_sel.Value()), u32(dma_data->dst_sel.Value()));
} }
break; break;
} }
@ -631,6 +666,35 @@ Liverpool::Task Liverpool::ProcessCompute(std::span<const u32> acb, int vqid) {
}; };
break; break;
} }
case PM4ItOpcode::DmaData: {
const auto* dma_data = reinterpret_cast<const PM4DmaData*>(header);
if (dma_data->dst_addr_lo == 0x3022C) {
break;
}
if (dma_data->src_sel == DmaDataSrc::Data && dma_data->dst_sel == DmaDataDst::Gds) {
rasterizer->InlineData(dma_data->dst_addr_lo, &dma_data->data, sizeof(u32), true);
} else if (dma_data->src_sel == DmaDataSrc::Memory &&
dma_data->dst_sel == DmaDataDst::Gds) {
rasterizer->InlineData(dma_data->dst_addr_lo, dma_data->SrcAddress<const void*>(),
dma_data->NumBytes(), true);
} else if (dma_data->src_sel == DmaDataSrc::Data &&
dma_data->dst_sel == DmaDataDst::Memory) {
rasterizer->InlineData(dma_data->DstAddress<VAddr>(), &dma_data->data, sizeof(u32),
false);
} else if (dma_data->src_sel == DmaDataSrc::Gds &&
dma_data->dst_sel == DmaDataDst::Memory) {
LOG_WARNING(Render_Vulkan, "GDS memory read");
} else if (dma_data->src_sel == DmaDataSrc::Memory &&
dma_data->dst_sel == DmaDataDst::Memory) {
rasterizer->InlineData(dma_data->DstAddress<VAddr>(),
dma_data->SrcAddress<const void*>(), dma_data->NumBytes(),
false);
} else {
UNREACHABLE_MSG("WriteData src_sel = {}, dst_sel = {}",
u32(dma_data->src_sel.Value()), u32(dma_data->dst_sel.Value()));
}
break;
}
case PM4ItOpcode::AcquireMem: { case PM4ItOpcode::AcquireMem: {
break; break;
} }

View File

@ -313,25 +313,26 @@ struct PM4CmdEventWriteEop {
return data_lo | u64(data_hi) << 32; return data_lo | u64(data_hi) << 32;
} }
void SignalFence() const { void SignalFence(auto&& write_mem) const {
u32* address = Address<u32>();
switch (data_sel.Value()) { switch (data_sel.Value()) {
case DataSelect::None: { case DataSelect::None: {
break; break;
} }
case DataSelect::Data32Low: { case DataSelect::Data32Low: {
*Address<u32>() = DataDWord(); write_mem(address, DataDWord(), sizeof(u32));
break; break;
} }
case DataSelect::Data64: { case DataSelect::Data64: {
*Address<u64>() = DataQWord(); write_mem(address, DataQWord(), sizeof(u64));
break; break;
} }
case DataSelect::GpuClock64: { case DataSelect::GpuClock64: {
*Address<u64>() = GetGpuClock64(); write_mem(address, GetGpuClock64(), sizeof(u64));
break; break;
} }
case DataSelect::PerfCounter: { case DataSelect::PerfCounter: {
*Address<u64>() = Common::FencedRDTSC(); write_mem(address, Common::FencedRDTSC(), sizeof(u64));
break; break;
} }
default: { default: {
@ -401,6 +402,20 @@ struct PM4DmaData {
u32 dst_addr_lo; u32 dst_addr_lo;
u32 dst_addr_hi; u32 dst_addr_hi;
u32 command; u32 command;
template <typename T>
T SrcAddress() const {
return std::bit_cast<T>(src_addr_lo | u64(src_addr_hi) << 32);
}
template <typename T>
T DstAddress() const {
return std::bit_cast<T>(dst_addr_lo | u64(dst_addr_hi) << 32);
}
u32 NumBytes() const noexcept {
return command & 0x1fffff;
}
}; };
struct PM4CmdWaitRegMem { struct PM4CmdWaitRegMem {
@ -432,7 +447,7 @@ struct PM4CmdWaitRegMem {
template <typename T = u32*> template <typename T = u32*>
T Address() const { T Address() const {
return reinterpret_cast<T>((uintptr_t(poll_addr_hi) << 32) | poll_addr_lo); return std::bit_cast<T>((uintptr_t(poll_addr_hi) << 32) | poll_addr_lo);
} }
bool Test() const { bool Test() const {
@ -534,11 +549,11 @@ struct PM4CmdEventWriteEos {
return this->data; return this->data;
} }
void SignalFence() const { void SignalFence(auto&& write_mem) const {
const auto cmd = command.Value(); const auto cmd = command.Value();
switch (cmd) { switch (cmd) {
case Command::SignalFence: { case Command::SignalFence: {
*Address() = DataDWord(); write_mem(Address(), DataDWord(), sizeof(u32));
break; break;
} }
case Command::GdsStore: { case Command::GdsStore: {

View File

@ -142,6 +142,7 @@ public:
VAddr cpu_addr = 0; VAddr cpu_addr = 0;
bool is_picked{}; bool is_picked{};
bool is_coherent{}; bool is_coherent{};
bool is_deleted{};
int stream_score = 0; int stream_score = 0;
size_t size_bytes = 0; size_t size_bytes = 0;
std::span<u8> mapped_data; std::span<u8> mapped_data;

View File

@ -20,7 +20,7 @@ static constexpr size_t StagingBufferSize = 1_GB;
static constexpr size_t UboStreamBufferSize = 64_MB; static constexpr size_t UboStreamBufferSize = 64_MB;
BufferCache::BufferCache(const Vulkan::Instance& instance_, Vulkan::Scheduler& scheduler_, BufferCache::BufferCache(const Vulkan::Instance& instance_, Vulkan::Scheduler& scheduler_,
const AmdGpu::Liverpool* liverpool_, TextureCache& texture_cache_, AmdGpu::Liverpool* liverpool_, TextureCache& texture_cache_,
PageManager& tracker_) PageManager& tracker_)
: instance{instance_}, scheduler{scheduler_}, liverpool{liverpool_}, : instance{instance_}, scheduler{scheduler_}, liverpool{liverpool_},
texture_cache{texture_cache_}, tracker{tracker_}, texture_cache{texture_cache_}, tracker{tracker_},
@ -70,11 +70,10 @@ void BufferCache::InvalidateMemory(VAddr device_addr, u64 size) {
void BufferCache::DownloadBufferMemory(Buffer& buffer, VAddr device_addr, u64 size) { void BufferCache::DownloadBufferMemory(Buffer& buffer, VAddr device_addr, u64 size) {
boost::container::small_vector<vk::BufferCopy, 1> copies; boost::container::small_vector<vk::BufferCopy, 1> copies;
u64 total_size_bytes = 0; u64 total_size_bytes = 0;
u64 largest_copy = 0;
memory_tracker.ForEachDownloadRange<true>( memory_tracker.ForEachDownloadRange<true>(
device_addr, size, [&](u64 device_addr_out, u64 range_size) { device_addr, size, [&](u64 device_addr_out, u64 range_size) {
const VAddr buffer_addr = buffer.CpuAddr(); const VAddr buffer_addr = buffer.CpuAddr();
const auto add_download = [&](VAddr start, VAddr end, u64) { const auto add_download = [&](VAddr start, VAddr end) {
const u64 new_offset = start - buffer_addr; const u64 new_offset = start - buffer_addr;
const u64 new_size = end - start; const u64 new_size = end - start;
copies.push_back(vk::BufferCopy{ copies.push_back(vk::BufferCopy{
@ -82,12 +81,10 @@ void BufferCache::DownloadBufferMemory(Buffer& buffer, VAddr device_addr, u64 si
.dstOffset = total_size_bytes, .dstOffset = total_size_bytes,
.size = new_size, .size = new_size,
}); });
// Align up to avoid cache conflicts total_size_bytes += new_size;
constexpr u64 align = 64ULL;
constexpr u64 mask = ~(align - 1ULL);
total_size_bytes += (new_size + align - 1) & mask;
largest_copy = std::max(largest_copy, new_size);
}; };
gpu_modified_ranges.ForEachInRange(device_addr_out, range_size, add_download);
gpu_modified_ranges.Subtract(device_addr_out, range_size);
}); });
if (total_size_bytes == 0) { if (total_size_bytes == 0) {
return; return;
@ -181,6 +178,9 @@ bool BufferCache::BindVertexBuffers(const Shader::Info& vs_info) {
.divisor = 1, .divisor = 1,
}); });
} }
if (ranges.empty()) {
return false;
}
std::ranges::sort(ranges, [](const BufferRange& lhv, const BufferRange& rhv) { std::ranges::sort(ranges, [](const BufferRange& lhv, const BufferRange& rhv) {
return lhv.base_address < rhv.base_address; return lhv.base_address < rhv.base_address;
@ -269,48 +269,62 @@ u32 BufferCache::BindIndexBuffer(bool& is_indexed, u32 index_offset) {
return regs.num_indices; return regs.num_indices;
} }
void BufferCache::InlineDataToGds(u32 gds_offset, u32 value) { void BufferCache::InlineData(VAddr address, const void* value, u32 num_bytes, bool is_gds) {
ASSERT_MSG(gds_offset % 4 == 0, "GDS offset must be dword aligned"); ASSERT_MSG(address % 4 == 0, "GDS offset must be dword aligned");
if (!is_gds && !IsRegionRegistered(address, num_bytes)) {
memcpy(std::bit_cast<void*>(address), value, num_bytes);
return;
}
scheduler.EndRendering(); scheduler.EndRendering();
const auto cmdbuf = scheduler.CommandBuffer(); const auto cmdbuf = scheduler.CommandBuffer();
const Buffer* buffer = [&] {
if (is_gds) {
return &gds_buffer;
}
const BufferId buffer_id = FindBuffer(address, num_bytes);
return &slot_buffers[buffer_id];
}();
const vk::BufferMemoryBarrier2 buf_barrier = { const vk::BufferMemoryBarrier2 buf_barrier = {
.srcStageMask = vk::PipelineStageFlagBits2::eTransfer, .srcStageMask = vk::PipelineStageFlagBits2::eTransfer,
.srcAccessMask = vk::AccessFlagBits2::eTransferWrite, .srcAccessMask = vk::AccessFlagBits2::eTransferWrite,
.dstStageMask = vk::PipelineStageFlagBits2::eAllCommands, .dstStageMask = vk::PipelineStageFlagBits2::eAllCommands,
.dstAccessMask = vk::AccessFlagBits2::eMemoryRead, .dstAccessMask = vk::AccessFlagBits2::eMemoryRead,
.buffer = gds_buffer.Handle(), .buffer = buffer->Handle(),
.offset = gds_offset, .offset = buffer->Offset(address),
.size = sizeof(u32), .size = num_bytes,
}; };
cmdbuf.pipelineBarrier2(vk::DependencyInfo{ cmdbuf.pipelineBarrier2(vk::DependencyInfo{
.dependencyFlags = vk::DependencyFlagBits::eByRegion, .dependencyFlags = vk::DependencyFlagBits::eByRegion,
.bufferMemoryBarrierCount = 1, .bufferMemoryBarrierCount = 1,
.pBufferMemoryBarriers = &buf_barrier, .pBufferMemoryBarriers = &buf_barrier,
}); });
cmdbuf.updateBuffer(gds_buffer.Handle(), gds_offset, sizeof(u32), &value); cmdbuf.updateBuffer(buffer->Handle(), buf_barrier.offset, num_bytes, value);
} }
std::pair<Buffer*, u32> BufferCache::ObtainBuffer(VAddr device_addr, u32 size, bool is_written, std::pair<Buffer*, u32> BufferCache::ObtainBuffer(VAddr device_addr, u32 size, bool is_written,
bool is_texel_buffer) { bool is_texel_buffer, BufferId buffer_id) {
// For small uniform buffers that have not been modified by gpu
// use device local stream buffer to reduce renderpass breaks.
static constexpr u64 StreamThreshold = CACHING_PAGESIZE; static constexpr u64 StreamThreshold = CACHING_PAGESIZE;
const bool is_gpu_dirty = memory_tracker.IsRegionGpuModified(device_addr, size); const bool is_gpu_dirty = memory_tracker.IsRegionGpuModified(device_addr, size);
if (!is_written && 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()); const u64 offset = stream_buffer.Copy(device_addr, size, instance.UniformMinAlignment());
return {&stream_buffer, offset}; return {&stream_buffer, offset};
} }
const BufferId buffer_id = FindBuffer(device_addr, size); if (!buffer_id || slot_buffers[buffer_id].is_deleted) {
buffer_id = FindBuffer(device_addr, size);
}
Buffer& buffer = slot_buffers[buffer_id]; Buffer& buffer = slot_buffers[buffer_id];
SynchronizeBuffer(buffer, device_addr, size, is_texel_buffer); SynchronizeBuffer(buffer, device_addr, size, is_texel_buffer);
if (is_written) { if (is_written) {
memory_tracker.MarkRegionAsGpuModified(device_addr, size); memory_tracker.MarkRegionAsGpuModified(device_addr, size);
gpu_modified_ranges.Add(device_addr, size);
} }
return {&buffer, buffer.Offset(device_addr)}; return {&buffer, buffer.Offset(device_addr)};
} }
std::pair<Buffer*, u32> BufferCache::ObtainTempBuffer(VAddr gpu_addr, u32 size) { std::pair<Buffer*, u32> BufferCache::ObtainViewBuffer(VAddr gpu_addr, u32 size) {
const u64 page = gpu_addr >> CACHING_PAGEBITS; const u64 page = gpu_addr >> CACHING_PAGEBITS;
const BufferId buffer_id = page_table[page]; const BufferId buffer_id = page_table[page];
if (buffer_id) { if (buffer_id) {
@ -474,7 +488,7 @@ void BufferCache::JoinOverlap(BufferId new_buffer_id, BufferId overlap_id,
cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer,
vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eAllCommands,
vk::DependencyFlagBits::eByRegion, WRITE_BARRIER, {}, {}); vk::DependencyFlagBits::eByRegion, WRITE_BARRIER, {}, {});
DeleteBuffer(overlap_id, true); DeleteBuffer(overlap_id);
} }
BufferId BufferCache::CreateBuffer(VAddr device_addr, u32 wanted_size) { BufferId BufferCache::CreateBuffer(VAddr device_addr, u32 wanted_size) {
@ -529,7 +543,7 @@ void BufferCache::SynchronizeBuffer(Buffer& buffer, VAddr device_addr, u32 size,
u64 total_size_bytes = 0; u64 total_size_bytes = 0;
u64 largest_copy = 0; u64 largest_copy = 0;
VAddr buffer_start = buffer.CpuAddr(); VAddr buffer_start = buffer.CpuAddr();
const auto add_copy = [&](VAddr device_addr_out, u64 range_size) { memory_tracker.ForEachUploadRange(device_addr, size, [&](u64 device_addr_out, u64 range_size) {
copies.push_back(vk::BufferCopy{ copies.push_back(vk::BufferCopy{
.srcOffset = total_size_bytes, .srcOffset = total_size_bytes,
.dstOffset = device_addr_out - buffer_start, .dstOffset = device_addr_out - buffer_start,
@ -537,11 +551,6 @@ void BufferCache::SynchronizeBuffer(Buffer& buffer, VAddr device_addr, u32 size,
}); });
total_size_bytes += range_size; total_size_bytes += range_size;
largest_copy = std::max(largest_copy, range_size); largest_copy = std::max(largest_copy, range_size);
};
memory_tracker.ForEachUploadRange(device_addr, size, [&](u64 device_addr_out, u64 range_size) {
add_copy(device_addr_out, range_size);
// Prevent uploading to gpu modified regions.
// gpu_modified_ranges.ForEachNotInRange(device_addr_out, range_size, add_copy);
}); });
SCOPE_EXIT { SCOPE_EXIT {
if (is_texel_buffer) { if (is_texel_buffer) {
@ -654,14 +663,11 @@ bool BufferCache::SynchronizeBufferFromImage(Buffer& buffer, VAddr device_addr,
return true; return true;
} }
void BufferCache::DeleteBuffer(BufferId buffer_id, bool do_not_mark) { void BufferCache::DeleteBuffer(BufferId buffer_id) {
// Mark the whole buffer as CPU written to stop tracking CPU writes Buffer& buffer = slot_buffers[buffer_id];
if (!do_not_mark) {
Buffer& buffer = slot_buffers[buffer_id];
memory_tracker.MarkRegionAsCpuModified(buffer.CpuAddr(), buffer.SizeBytes());
}
Unregister(buffer_id); Unregister(buffer_id);
scheduler.DeferOperation([this, buffer_id] { slot_buffers.erase(buffer_id); }); scheduler.DeferOperation([this, buffer_id] { slot_buffers.erase(buffer_id); });
buffer.is_deleted = true;
} }
} // namespace VideoCore } // namespace VideoCore

View File

@ -12,6 +12,7 @@
#include "common/types.h" #include "common/types.h"
#include "video_core/buffer_cache/buffer.h" #include "video_core/buffer_cache/buffer.h"
#include "video_core/buffer_cache/memory_tracker_base.h" #include "video_core/buffer_cache/memory_tracker_base.h"
#include "video_core/buffer_cache/range_set.h"
#include "video_core/multi_level_page_table.h" #include "video_core/multi_level_page_table.h"
namespace AmdGpu { namespace AmdGpu {
@ -53,7 +54,7 @@ public:
public: public:
explicit BufferCache(const Vulkan::Instance& instance, Vulkan::Scheduler& scheduler, explicit BufferCache(const Vulkan::Instance& instance, Vulkan::Scheduler& scheduler,
const AmdGpu::Liverpool* liverpool, TextureCache& texture_cache, AmdGpu::Liverpool* liverpool, TextureCache& texture_cache,
PageManager& tracker); PageManager& tracker);
~BufferCache(); ~BufferCache();
@ -80,15 +81,16 @@ public:
/// Bind host index buffer for the current draw. /// Bind host index buffer for the current draw.
u32 BindIndexBuffer(bool& is_indexed, u32 index_offset); u32 BindIndexBuffer(bool& is_indexed, u32 index_offset);
/// Writes a value to GDS buffer. /// Writes a value to GPU buffer.
void InlineDataToGds(u32 gds_offset, u32 value); void InlineData(VAddr address, const void* value, u32 num_bytes, bool is_gds);
/// Obtains a buffer for the specified region. /// Obtains a buffer for the specified region.
[[nodiscard]] std::pair<Buffer*, u32> ObtainBuffer(VAddr gpu_addr, u32 size, bool is_written, [[nodiscard]] std::pair<Buffer*, u32> ObtainBuffer(VAddr gpu_addr, u32 size, bool is_written,
bool is_texel_buffer = false); bool is_texel_buffer = false,
BufferId buffer_id = {});
/// Obtains a temporary buffer for usage in texture cache. /// Attempts to obtain a buffer without modifying the cache contents.
[[nodiscard]] std::pair<Buffer*, u32> ObtainTempBuffer(VAddr gpu_addr, u32 size); [[nodiscard]] std::pair<Buffer*, u32> ObtainViewBuffer(VAddr gpu_addr, u32 size);
/// Return true when a region is registered on the cache /// Return true when a region is registered on the cache
[[nodiscard]] bool IsRegionRegistered(VAddr addr, size_t size); [[nodiscard]] bool IsRegionRegistered(VAddr addr, size_t size);
@ -99,6 +101,8 @@ public:
/// Return true when a CPU region is modified from the GPU /// Return true when a CPU region is modified from the GPU
[[nodiscard]] bool IsRegionGpuModified(VAddr addr, size_t size); [[nodiscard]] bool IsRegionGpuModified(VAddr addr, size_t size);
[[nodiscard]] BufferId FindBuffer(VAddr device_addr, u32 size);
private: private:
template <typename Func> template <typename Func>
void ForEachBufferInRange(VAddr device_addr, u64 size, Func&& func) { void ForEachBufferInRange(VAddr device_addr, u64 size, Func&& func) {
@ -119,8 +123,6 @@ private:
void DownloadBufferMemory(Buffer& buffer, VAddr device_addr, u64 size); void DownloadBufferMemory(Buffer& buffer, VAddr device_addr, u64 size);
[[nodiscard]] BufferId FindBuffer(VAddr device_addr, u32 size);
[[nodiscard]] OverlapResult ResolveOverlaps(VAddr device_addr, u32 wanted_size); [[nodiscard]] OverlapResult ResolveOverlaps(VAddr device_addr, u32 wanted_size);
void JoinOverlap(BufferId new_buffer_id, BufferId overlap_id, bool accumulate_stream_score); void JoinOverlap(BufferId new_buffer_id, BufferId overlap_id, bool accumulate_stream_score);
@ -138,11 +140,11 @@ private:
bool SynchronizeBufferFromImage(Buffer& buffer, VAddr device_addr, u32 size); bool SynchronizeBufferFromImage(Buffer& buffer, VAddr device_addr, u32 size);
void DeleteBuffer(BufferId buffer_id, bool do_not_mark = false); void DeleteBuffer(BufferId buffer_id);
const Vulkan::Instance& instance; const Vulkan::Instance& instance;
Vulkan::Scheduler& scheduler; Vulkan::Scheduler& scheduler;
const AmdGpu::Liverpool* liverpool; AmdGpu::Liverpool* liverpool;
TextureCache& texture_cache; TextureCache& texture_cache;
PageManager& tracker; PageManager& tracker;
StreamBuffer staging_buffer; StreamBuffer staging_buffer;
@ -150,6 +152,7 @@ private:
Buffer gds_buffer; Buffer gds_buffer;
std::mutex mutex; std::mutex mutex;
Common::SlotVector<Buffer> slot_buffers; Common::SlotVector<Buffer> slot_buffers;
RangeSet gpu_modified_ranges;
vk::BufferView null_buffer_view; vk::BufferView null_buffer_view;
MemoryTracker memory_tracker; MemoryTracker memory_tracker;
PageTable page_table; PageTable page_table;

View File

@ -3,7 +3,6 @@
#include <boost/container/small_vector.hpp> #include <boost/container/small_vector.hpp>
#include "common/alignment.h"
#include "video_core/buffer_cache/buffer_cache.h" #include "video_core/buffer_cache/buffer_cache.h"
#include "video_core/renderer_vulkan/vk_compute_pipeline.h" #include "video_core/renderer_vulkan/vk_compute_pipeline.h"
#include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_instance.h"
@ -113,140 +112,45 @@ ComputePipeline::~ComputePipeline() = default;
bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache, bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache,
VideoCore::TextureCache& texture_cache) const { VideoCore::TextureCache& texture_cache) const {
// Bind resource buffers and textures. // Bind resource buffers and textures.
boost::container::static_vector<vk::BufferView, 8> buffer_views;
boost::container::static_vector<vk::DescriptorBufferInfo, 32> buffer_infos;
boost::container::small_vector<vk::WriteDescriptorSet, 16> set_writes; boost::container::small_vector<vk::WriteDescriptorSet, 16> set_writes;
boost::container::small_vector<vk::BufferMemoryBarrier2, 16> buffer_barriers; BufferBarriers buffer_barriers;
Shader::PushData push_data{}; Shader::PushData push_data{};
Shader::Backend::Bindings binding{}; Shader::Backend::Bindings binding{};
info->PushUd(binding, push_data);
buffer_infos.clear();
buffer_views.clear();
image_infos.clear(); image_infos.clear();
info->PushUd(binding, push_data); // Most of the time when a metadata is updated with a shader it gets cleared. It means
for (const auto& desc : info->buffers) { // we can skip the whole dispatch and update the tracked state instead. Also, it is not
bool is_storage = true; // intended to be consumed and in such rare cases (e.g. HTile introspection, CRAA) we
if (desc.is_gds_buffer) { // will need its full emulation anyways. For cases of metadata read a warning will be logged.
auto* vk_buffer = buffer_cache.GetGdsBuffer(); for (const auto& desc : info->texture_buffers) {
buffer_infos.emplace_back(vk_buffer->Handle(), 0, vk_buffer->SizeBytes()); const VAddr address = desc.GetSharp(*info).base_address;
} else { if (desc.is_written) {
const auto vsharp = desc.GetSharp(*info); if (texture_cache.TouchMeta(address, true)) {
is_storage = desc.IsStorage(vsharp); LOG_TRACE(Render_Vulkan, "Metadata update skipped");
const VAddr address = vsharp.base_address; return false;
// Most of the time when a metadata is updated with a shader it gets cleared. It means }
// we can skip the whole dispatch and update the tracked state instead. Also, it is not } else {
// intended to be consumed and in such rare cases (e.g. HTile introspection, CRAA) we if (texture_cache.IsMeta(address)) {
// will need its full emulation anyways. For cases of metadata read a warning will be LOG_WARNING(Render_Vulkan, "Unexpected metadata read by a CS shader (buffer)");
// logged.
if (desc.is_written) {
if (texture_cache.TouchMeta(address, true)) {
LOG_TRACE(Render_Vulkan, "Metadata update skipped");
return false;
}
} else {
if (texture_cache.IsMeta(address)) {
LOG_WARNING(Render_Vulkan, "Unexpected metadata read by a CS shader (buffer)");
}
} }
const u32 size = vsharp.GetSize();
const u32 alignment =
is_storage ? instance.StorageMinAlignment() : instance.UniformMinAlignment();
const auto [vk_buffer, offset] =
buffer_cache.ObtainBuffer(address, size, desc.is_written);
const u32 offset_aligned = Common::AlignDown(offset, alignment);
const u32 adjust = offset - offset_aligned;
ASSERT(adjust % 4 == 0);
push_data.AddOffset(binding.buffer, adjust);
buffer_infos.emplace_back(vk_buffer->Handle(), offset_aligned, size + adjust);
} }
set_writes.push_back({
.dstSet = VK_NULL_HANDLE,
.dstBinding = binding.unified++,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = is_storage ? vk::DescriptorType::eStorageBuffer
: vk::DescriptorType::eUniformBuffer,
.pBufferInfo = &buffer_infos.back(),
});
++binding.buffer;
} }
const auto null_buffer_view = BindBuffers(buffer_cache, texture_cache, *info, binding, push_data, set_writes,
instance.IsNullDescriptorSupported() ? VK_NULL_HANDLE : buffer_cache.NullBufferView(); buffer_barriers);
for (const auto& desc : info->texture_buffers) {
const auto vsharp = desc.GetSharp(*info);
vk::BufferView& buffer_view = buffer_views.emplace_back(null_buffer_view);
const u32 size = vsharp.GetSize();
if (vsharp.GetDataFmt() != AmdGpu::DataFormat::FormatInvalid && size != 0) {
const VAddr address = vsharp.base_address;
if (desc.is_written) {
if (texture_cache.TouchMeta(address, true)) {
LOG_TRACE(Render_Vulkan, "Metadata update skipped");
return false;
}
} else {
if (texture_cache.IsMeta(address)) {
LOG_WARNING(Render_Vulkan, "Unexpected metadata read by a CS shader (buffer)");
}
}
const u32 alignment = instance.TexelBufferMinAlignment();
const auto [vk_buffer, offset] =
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");
const u32 offset_aligned = Common::AlignDown(offset, alignment);
const u32 adjust = offset - offset_aligned;
ASSERT(adjust % fmt_stride == 0);
push_data.AddOffset(binding.buffer, adjust / fmt_stride);
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.InvalidateMemoryFromGPU(address, size);
}
}
set_writes.push_back({
.dstSet = VK_NULL_HANDLE,
.dstBinding = binding.unified++,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = desc.is_written ? vk::DescriptorType::eStorageTexelBuffer
: vk::DescriptorType::eUniformTexelBuffer,
.pTexelBufferView = &buffer_view,
});
++binding.buffer;
}
BindTextures(texture_cache, *info, binding, set_writes); BindTextures(texture_cache, *info, binding, set_writes);
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({
.dstSet = VK_NULL_HANDLE,
.dstBinding = binding.unified++,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = vk::DescriptorType::eSampler,
.pImageInfo = &image_infos.back(),
});
}
if (set_writes.empty()) { if (set_writes.empty()) {
return false; return false;
} }
const auto cmdbuf = scheduler.CommandBuffer(); const auto cmdbuf = scheduler.CommandBuffer();
if (!buffer_barriers.empty()) { if (!buffer_barriers.empty()) {
const auto dependencies = vk::DependencyInfo{ const auto dependencies = vk::DependencyInfo{
.dependencyFlags = vk::DependencyFlagBits::eByRegion, .dependencyFlags = vk::DependencyFlagBits::eByRegion,
@ -257,21 +161,22 @@ bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache,
cmdbuf.pipelineBarrier2(dependencies); cmdbuf.pipelineBarrier2(dependencies);
} }
cmdbuf.pushConstants(*pipeline_layout, vk::ShaderStageFlagBits::eCompute, 0u, sizeof(push_data),
&push_data);
// Bind descriptor set.
if (uses_push_descriptors) { if (uses_push_descriptors) {
cmdbuf.pushDescriptorSetKHR(vk::PipelineBindPoint::eCompute, *pipeline_layout, 0, cmdbuf.pushDescriptorSetKHR(vk::PipelineBindPoint::eCompute, *pipeline_layout, 0,
set_writes); set_writes);
} else { return true;
const auto desc_set = desc_heap.Commit(*desc_layout);
for (auto& set_write : set_writes) {
set_write.dstSet = desc_set;
}
instance.GetDevice().updateDescriptorSets(set_writes, {});
cmdbuf.bindDescriptorSets(vk::PipelineBindPoint::eCompute, *pipeline_layout, 0, desc_set,
{});
} }
const auto desc_set = desc_heap.Commit(*desc_layout);
for (auto& set_write : set_writes) {
set_write.dstSet = desc_set;
}
instance.GetDevice().updateDescriptorSets(set_writes, {});
cmdbuf.bindDescriptorSets(vk::PipelineBindPoint::eCompute, *pipeline_layout, 0, desc_set, {});
cmdbuf.pushConstants(*pipeline_layout, vk::ShaderStageFlagBits::eCompute, 0u, sizeof(push_data),
&push_data);
return true; return true;
} }

View File

@ -5,8 +5,8 @@
#include <boost/container/small_vector.hpp> #include <boost/container/small_vector.hpp>
#include <boost/container/static_vector.hpp> #include <boost/container/static_vector.hpp>
#include "common/alignment.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/scope_exit.h"
#include "video_core/amdgpu/resource.h" #include "video_core/amdgpu/resource.h"
#include "video_core/buffer_cache/buffer_cache.h" #include "video_core/buffer_cache/buffer_cache.h"
#include "video_core/renderer_vulkan/vk_graphics_pipeline.h" #include "video_core/renderer_vulkan/vk_graphics_pipeline.h"
@ -384,13 +384,13 @@ void GraphicsPipeline::BindResources(const Liverpool::Regs& regs,
VideoCore::BufferCache& buffer_cache, VideoCore::BufferCache& buffer_cache,
VideoCore::TextureCache& texture_cache) const { VideoCore::TextureCache& texture_cache) const {
// Bind resource buffers and textures. // Bind resource buffers and textures.
boost::container::static_vector<vk::BufferView, 8> buffer_views;
boost::container::static_vector<vk::DescriptorBufferInfo, 32> buffer_infos;
boost::container::small_vector<vk::WriteDescriptorSet, 16> set_writes; boost::container::small_vector<vk::WriteDescriptorSet, 16> set_writes;
boost::container::small_vector<vk::BufferMemoryBarrier2, 16> buffer_barriers; BufferBarriers buffer_barriers;
Shader::PushData push_data{}; Shader::PushData push_data{};
Shader::Backend::Bindings binding{}; Shader::Backend::Bindings binding{};
buffer_infos.clear();
buffer_views.clear();
image_infos.clear(); image_infos.clear();
for (const auto* stage : stages) { for (const auto* stage : stages) {
@ -402,111 +402,22 @@ void GraphicsPipeline::BindResources(const Liverpool::Regs& regs,
push_data.step1 = regs.vgt_instance_step_rate_1; push_data.step1 = regs.vgt_instance_step_rate_1;
} }
stage->PushUd(binding, push_data); stage->PushUd(binding, push_data);
for (const auto& buffer : stage->buffers) {
const auto vsharp = buffer.GetSharp(*stage);
const bool is_storage = buffer.IsStorage(vsharp);
if (vsharp && vsharp.GetSize() > 0) {
const VAddr address = vsharp.base_address;
if (texture_cache.IsMeta(address)) {
LOG_WARNING(Render_Vulkan, "Unexpected metadata read by a PS shader (buffer)");
}
const u32 size = vsharp.GetSize();
const u32 alignment =
is_storage ? instance.StorageMinAlignment() : instance.UniformMinAlignment();
const auto [vk_buffer, offset] =
buffer_cache.ObtainBuffer(address, size, buffer.is_written);
const u32 offset_aligned = Common::AlignDown(offset, alignment);
const u32 adjust = offset - offset_aligned;
ASSERT(adjust % 4 == 0);
push_data.AddOffset(binding.buffer, adjust);
buffer_infos.emplace_back(vk_buffer->Handle(), offset_aligned, size + adjust);
} else if (instance.IsNullDescriptorSupported()) {
buffer_infos.emplace_back(VK_NULL_HANDLE, 0, VK_WHOLE_SIZE);
} else {
auto& null_buffer = buffer_cache.GetBuffer(VideoCore::NULL_BUFFER_ID);
buffer_infos.emplace_back(null_buffer.Handle(), 0, VK_WHOLE_SIZE);
}
set_writes.push_back({
.dstSet = VK_NULL_HANDLE,
.dstBinding = binding.unified++,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = is_storage ? vk::DescriptorType::eStorageBuffer
: vk::DescriptorType::eUniformBuffer,
.pBufferInfo = &buffer_infos.back(),
});
++binding.buffer;
}
const auto null_buffer_view = BindBuffers(buffer_cache, texture_cache, *stage, binding, push_data, set_writes,
instance.IsNullDescriptorSupported() ? VK_NULL_HANDLE : buffer_cache.NullBufferView(); buffer_barriers);
for (const auto& desc : stage->texture_buffers) {
const auto vsharp = desc.GetSharp(*stage);
vk::BufferView& buffer_view = buffer_views.emplace_back(null_buffer_view);
const u32 size = vsharp.GetSize();
if (vsharp.GetDataFmt() != AmdGpu::DataFormat::FormatInvalid && size != 0) {
const VAddr address = vsharp.base_address;
const u32 alignment = instance.TexelBufferMinAlignment();
const auto [vk_buffer, offset] =
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");
const u32 offset_aligned = Common::AlignDown(offset, alignment);
const u32 adjust = offset - offset_aligned;
ASSERT(adjust % fmt_stride == 0);
push_data.AddOffset(binding.buffer, adjust / fmt_stride);
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.InvalidateMemoryFromGPU(address, size);
}
}
set_writes.push_back({
.dstSet = VK_NULL_HANDLE,
.dstBinding = binding.unified++,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = desc.is_written ? vk::DescriptorType::eStorageTexelBuffer
: vk::DescriptorType::eUniformTexelBuffer,
.pTexelBufferView = &buffer_view,
});
++binding.buffer;
}
BindTextures(texture_cache, *stage, binding, set_writes); BindTextures(texture_cache, *stage, binding, set_writes);
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 = stage->images[sampler.associated_image].GetSharp(*stage);
if (tsharp.base_level == 0 && tsharp.last_level == 0) {
ssharp.max_aniso.Assign(AmdGpu::AnisoRatio::One);
}
}
const auto vk_sampler = texture_cache.GetSampler(ssharp);
image_infos.emplace_back(vk_sampler, VK_NULL_HANDLE, vk::ImageLayout::eGeneral);
set_writes.push_back({
.dstSet = VK_NULL_HANDLE,
.dstBinding = binding.unified++,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = vk::DescriptorType::eSampler,
.pImageInfo = &image_infos.back(),
});
}
} }
const auto cmdbuf = scheduler.CommandBuffer(); const auto cmdbuf = scheduler.CommandBuffer();
SCOPE_EXIT {
cmdbuf.pushConstants(*pipeline_layout, gp_stage_flags, 0U, sizeof(push_data), &push_data);
cmdbuf.bindPipeline(vk::PipelineBindPoint::eGraphics, Handle());
};
if (set_writes.empty()) {
return;
}
if (!buffer_barriers.empty()) { if (!buffer_barriers.empty()) {
const auto dependencies = vk::DependencyInfo{ const auto dependencies = vk::DependencyInfo{
@ -518,22 +429,18 @@ void GraphicsPipeline::BindResources(const Liverpool::Regs& regs,
cmdbuf.pipelineBarrier2(dependencies); cmdbuf.pipelineBarrier2(dependencies);
} }
if (!set_writes.empty()) { // Bind descriptor set.
if (uses_push_descriptors) { if (uses_push_descriptors) {
cmdbuf.pushDescriptorSetKHR(vk::PipelineBindPoint::eGraphics, *pipeline_layout, 0, cmdbuf.pushDescriptorSetKHR(vk::PipelineBindPoint::eGraphics, *pipeline_layout, 0,
set_writes); set_writes);
} else { return;
const auto desc_set = desc_heap.Commit(*desc_layout);
for (auto& set_write : set_writes) {
set_write.dstSet = desc_set;
}
instance.GetDevice().updateDescriptorSets(set_writes, {});
cmdbuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, *pipeline_layout, 0,
desc_set, {});
}
} }
cmdbuf.pushConstants(*pipeline_layout, gp_stage_flags, 0U, sizeof(push_data), &push_data); const auto desc_set = desc_heap.Commit(*desc_layout);
cmdbuf.bindPipeline(vk::PipelineBindPoint::eGraphics, Handle()); for (auto& set_write : set_writes) {
set_write.dstSet = desc_set;
}
instance.GetDevice().updateDescriptorSets(set_writes, {});
cmdbuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, *pipeline_layout, 0, desc_set, {});
} }
} // namespace Vulkan } // namespace Vulkan

View File

@ -4,6 +4,7 @@
#include <boost/container/static_vector.hpp> #include <boost/container/static_vector.hpp>
#include "shader_recompiler/info.h" #include "shader_recompiler/info.h"
#include "video_core/buffer_cache/buffer_cache.h"
#include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_pipeline_common.h" #include "video_core/renderer_vulkan/vk_pipeline_common.h"
#include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_scheduler.h"
@ -12,6 +13,8 @@
namespace Vulkan { namespace Vulkan {
boost::container::static_vector<vk::DescriptorImageInfo, 32> Pipeline::image_infos; boost::container::static_vector<vk::DescriptorImageInfo, 32> Pipeline::image_infos;
boost::container::static_vector<vk::BufferView, 8> Pipeline::buffer_views;
boost::container::static_vector<vk::DescriptorBufferInfo, 32> Pipeline::buffer_infos;
Pipeline::Pipeline(const Instance& instance_, Scheduler& scheduler_, DescriptorHeap& desc_heap_, Pipeline::Pipeline(const Instance& instance_, Scheduler& scheduler_, DescriptorHeap& desc_heap_,
vk::PipelineCache pipeline_cache) vk::PipelineCache pipeline_cache)
@ -19,12 +22,133 @@ Pipeline::Pipeline(const Instance& instance_, Scheduler& scheduler_, DescriptorH
Pipeline::~Pipeline() = default; Pipeline::~Pipeline() = default;
void Pipeline::BindBuffers(VideoCore::BufferCache& buffer_cache,
VideoCore::TextureCache& texture_cache, const Shader::Info& stage,
Shader::Backend::Bindings& binding, Shader::PushData& push_data,
DescriptorWrites& set_writes, BufferBarriers& buffer_barriers) const {
using BufferBindingInfo = std::pair<VideoCore::BufferId, AmdGpu::Buffer>;
static boost::container::static_vector<BufferBindingInfo, 32> buffer_bindings;
buffer_bindings.clear();
for (const auto& desc : stage.buffers) {
const auto vsharp = desc.GetSharp(stage);
if (!desc.is_gds_buffer && vsharp.base_address != 0 && vsharp.GetSize() > 0) {
const auto buffer_id = buffer_cache.FindBuffer(vsharp.base_address, vsharp.GetSize());
buffer_bindings.emplace_back(buffer_id, vsharp);
} else {
buffer_bindings.emplace_back(VideoCore::BufferId{}, vsharp);
}
}
using TexBufferBindingInfo = std::pair<VideoCore::BufferId, AmdGpu::Buffer>;
static boost::container::static_vector<TexBufferBindingInfo, 32> texbuffer_bindings;
texbuffer_bindings.clear();
for (const auto& desc : stage.texture_buffers) {
const auto vsharp = desc.GetSharp(stage);
if (vsharp.base_address != 0 && vsharp.GetSize() > 0 &&
vsharp.GetDataFmt() != AmdGpu::DataFormat::FormatInvalid) {
const auto buffer_id = buffer_cache.FindBuffer(vsharp.base_address, vsharp.GetSize());
texbuffer_bindings.emplace_back(buffer_id, vsharp);
} else {
texbuffer_bindings.emplace_back(VideoCore::BufferId{}, vsharp);
}
}
// Second pass to re-bind buffers that were updated after binding
for (u32 i = 0; i < buffer_bindings.size(); i++) {
const auto& [buffer_id, vsharp] = buffer_bindings[i];
const auto& desc = stage.buffers[i];
const bool is_storage = desc.IsStorage(vsharp);
if (!buffer_id) {
if (desc.is_gds_buffer) {
const auto* gds_buf = buffer_cache.GetGdsBuffer();
buffer_infos.emplace_back(gds_buf->Handle(), 0, gds_buf->SizeBytes());
} else if (instance.IsNullDescriptorSupported()) {
buffer_infos.emplace_back(VK_NULL_HANDLE, 0, VK_WHOLE_SIZE);
} else {
auto& null_buffer = buffer_cache.GetBuffer(VideoCore::NULL_BUFFER_ID);
buffer_infos.emplace_back(null_buffer.Handle(), 0, VK_WHOLE_SIZE);
}
} else {
const auto [vk_buffer, offset] = buffer_cache.ObtainBuffer(
vsharp.base_address, vsharp.GetSize(), desc.is_written, false, buffer_id);
const u32 alignment =
is_storage ? instance.StorageMinAlignment() : instance.UniformMinAlignment();
const u32 offset_aligned = Common::AlignDown(offset, alignment);
const u32 adjust = offset - offset_aligned;
ASSERT(adjust % 4 == 0);
push_data.AddOffset(binding.buffer, adjust);
buffer_infos.emplace_back(vk_buffer->Handle(), offset_aligned,
vsharp.GetSize() + adjust);
}
set_writes.push_back({
.dstSet = VK_NULL_HANDLE,
.dstBinding = binding.unified++,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = is_storage ? vk::DescriptorType::eStorageBuffer
: vk::DescriptorType::eUniformBuffer,
.pBufferInfo = &buffer_infos.back(),
});
++binding.buffer;
}
const auto null_buffer_view =
instance.IsNullDescriptorSupported() ? VK_NULL_HANDLE : buffer_cache.NullBufferView();
for (u32 i = 0; i < texbuffer_bindings.size(); i++) {
const auto& [buffer_id, vsharp] = texbuffer_bindings[i];
const auto& desc = stage.texture_buffers[i];
vk::BufferView& buffer_view = buffer_views.emplace_back(null_buffer_view);
if (buffer_id) {
const u32 alignment = instance.TexelBufferMinAlignment();
const auto [vk_buffer, offset] = buffer_cache.ObtainBuffer(
vsharp.base_address, vsharp.GetSize(), desc.is_written, true, buffer_id);
const u32 fmt_stride = AmdGpu::NumBits(vsharp.GetDataFmt()) >> 3;
ASSERT_MSG(fmt_stride == vsharp.GetStride(),
"Texel buffer stride must match format stride");
const u32 offset_aligned = Common::AlignDown(offset, alignment);
const u32 adjust = offset - offset_aligned;
ASSERT(adjust % fmt_stride == 0);
push_data.AddOffset(binding.buffer, adjust / fmt_stride);
buffer_view =
vk_buffer->View(offset_aligned, vsharp.GetSize() + 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.InvalidateMemoryFromGPU(vsharp.base_address, vsharp.GetSize());
}
}
set_writes.push_back({
.dstSet = VK_NULL_HANDLE,
.dstBinding = binding.unified++,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = desc.is_written ? vk::DescriptorType::eStorageTexelBuffer
: vk::DescriptorType::eUniformTexelBuffer,
.pTexelBufferView = &buffer_view,
});
++binding.buffer;
}
}
void Pipeline::BindTextures(VideoCore::TextureCache& texture_cache, const Shader::Info& stage, void Pipeline::BindTextures(VideoCore::TextureCache& texture_cache, const Shader::Info& stage,
Shader::Backend::Bindings& binding, Shader::Backend::Bindings& binding,
DescriptorWrites& set_writes) const { DescriptorWrites& set_writes) const {
using ImageBindingInfo = std::tuple<VideoCore::ImageId, AmdGpu::Image, Shader::ImageResource>; using ImageBindingInfo = std::tuple<VideoCore::ImageId, AmdGpu::Image, Shader::ImageResource>;
boost::container::static_vector<ImageBindingInfo, 32> image_bindings; static boost::container::static_vector<ImageBindingInfo, 32> image_bindings;
image_bindings.clear();
for (const auto& image_desc : stage.images) { for (const auto& image_desc : stage.images) {
const auto tsharp = image_desc.GetSharp(stage); const auto tsharp = image_desc.GetSharp(stage);
@ -76,6 +200,26 @@ void Pipeline::BindTextures(VideoCore::TextureCache& texture_cache, const Shader
.pImageInfo = &image_infos.back(), .pImageInfo = &image_infos.back(),
}); });
} }
for (const auto& sampler : stage.samplers) {
auto ssharp = sampler.GetSharp(stage);
if (sampler.disable_aniso) {
const auto& tsharp = stage.images[sampler.associated_image].GetSharp(stage);
if (tsharp.base_level == 0 && tsharp.last_level == 0) {
ssharp.max_aniso.Assign(AmdGpu::AnisoRatio::One);
}
}
const auto vk_sampler = texture_cache.GetSampler(ssharp);
image_infos.emplace_back(vk_sampler, VK_NULL_HANDLE, vk::ImageLayout::eGeneral);
set_writes.push_back({
.dstSet = VK_NULL_HANDLE,
.dstBinding = binding.unified++,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = vk::DescriptorType::eSampler,
.pImageInfo = &image_infos.back(),
});
}
} }
} // namespace Vulkan } // namespace Vulkan

View File

@ -33,6 +33,13 @@ public:
} }
using DescriptorWrites = boost::container::small_vector<vk::WriteDescriptorSet, 16>; using DescriptorWrites = boost::container::small_vector<vk::WriteDescriptorSet, 16>;
using BufferBarriers = boost::container::small_vector<vk::BufferMemoryBarrier2, 16>;
void BindBuffers(VideoCore::BufferCache& buffer_cache, VideoCore::TextureCache& texture_cache,
const Shader::Info& stage, Shader::Backend::Bindings& binding,
Shader::PushData& push_data, DescriptorWrites& set_writes,
BufferBarriers& buffer_barriers) const;
void BindTextures(VideoCore::TextureCache& texture_cache, const Shader::Info& stage, void BindTextures(VideoCore::TextureCache& texture_cache, const Shader::Info& stage,
Shader::Backend::Bindings& binding, DescriptorWrites& set_writes) const; Shader::Backend::Bindings& binding, DescriptorWrites& set_writes) const;
@ -44,6 +51,8 @@ protected:
vk::UniquePipelineLayout pipeline_layout; vk::UniquePipelineLayout pipeline_layout;
vk::UniqueDescriptorSetLayout desc_layout; vk::UniqueDescriptorSetLayout desc_layout;
static boost::container::static_vector<vk::DescriptorImageInfo, 32> image_infos; static boost::container::static_vector<vk::DescriptorImageInfo, 32> image_infos;
static boost::container::static_vector<vk::BufferView, 8> buffer_views;
static boost::container::static_vector<vk::DescriptorBufferInfo, 32> buffer_infos;
}; };
} // namespace Vulkan } // namespace Vulkan

View File

@ -98,10 +98,9 @@ void Rasterizer::DrawIndirect(bool is_indexed, VAddr address, u32 offset, u32 si
const auto& vs_info = pipeline->GetStage(Shader::Stage::Vertex); const auto& vs_info = pipeline->GetStage(Shader::Stage::Vertex);
buffer_cache.BindVertexBuffers(vs_info); buffer_cache.BindVertexBuffers(vs_info);
const u32 num_indices = buffer_cache.BindIndexBuffer(is_indexed, 0); buffer_cache.BindIndexBuffer(is_indexed, 0);
const auto [buffer, base] = buffer_cache.ObtainBuffer(address, size, true); const auto [buffer, base] = buffer_cache.ObtainBuffer(address + offset, size, false);
const auto total_offset = base + offset;
BeginRendering(*pipeline); BeginRendering(*pipeline);
UpdateDynamicState(*pipeline); UpdateDynamicState(*pipeline);
@ -110,9 +109,9 @@ void Rasterizer::DrawIndirect(bool is_indexed, VAddr address, u32 offset, u32 si
// instance offsets will be automatically applied by Vulkan from indirect args buffer. // instance offsets will be automatically applied by Vulkan from indirect args buffer.
if (is_indexed) { if (is_indexed) {
cmdbuf.drawIndexedIndirect(buffer->Handle(), total_offset, 1, 0); cmdbuf.drawIndexedIndirect(buffer->Handle(), base, 1, 0);
} else { } else {
cmdbuf.drawIndirect(buffer->Handle(), total_offset, 1, 0); cmdbuf.drawIndirect(buffer->Handle(), base, 1, 0);
} }
} }
@ -161,9 +160,8 @@ void Rasterizer::DispatchIndirect(VAddr address, u32 offset, u32 size) {
scheduler.EndRendering(); scheduler.EndRendering();
cmdbuf.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline->Handle()); cmdbuf.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline->Handle());
const auto [buffer, base] = buffer_cache.ObtainBuffer(address, size, true); const auto [buffer, base] = buffer_cache.ObtainBuffer(address + offset, size, false);
const auto total_offset = base + offset; cmdbuf.dispatchIndirect(buffer->Handle(), base);
cmdbuf.dispatchIndirect(buffer->Handle(), total_offset);
} }
u64 Rasterizer::Flush() { u64 Rasterizer::Flush() {
@ -260,8 +258,8 @@ void Rasterizer::BeginRendering(const GraphicsPipeline& pipeline) {
scheduler.BeginRendering(state); scheduler.BeginRendering(state);
} }
void Rasterizer::InlineDataToGds(u32 gds_offset, u32 value) { void Rasterizer::InlineData(VAddr address, const void* value, u32 num_bytes, bool is_gds) {
buffer_cache.InlineDataToGds(gds_offset, value); buffer_cache.InlineData(address, value, num_bytes, is_gds);
} }
u32 Rasterizer::ReadDataFromGds(u32 gds_offset) { u32 Rasterizer::ReadDataFromGds(u32 gds_offset) {

View File

@ -42,7 +42,7 @@ public:
void ScopedMarkerInsert(const std::string_view& str); void ScopedMarkerInsert(const std::string_view& str);
void ScopedMarkerInsertColor(const std::string_view& str, const u32 color); void ScopedMarkerInsertColor(const std::string_view& str, const u32 color);
void InlineDataToGds(u32 gds_offset, u32 value); void InlineData(VAddr address, const void* value, u32 num_bytes, bool is_gds);
u32 ReadDataFromGds(u32 gsd_offset); u32 ReadDataFromGds(u32 gsd_offset);
void InvalidateMemory(VAddr addr, u64 size); void InvalidateMemory(VAddr addr, u64 size);
void MapMemory(VAddr addr, u64 size); void MapMemory(VAddr addr, u64 size);

View File

@ -8,6 +8,9 @@
namespace VideoCore { namespace VideoCore {
Sampler::Sampler(const Vulkan::Instance& instance, const AmdGpu::Sampler& sampler) { Sampler::Sampler(const Vulkan::Instance& instance, const AmdGpu::Sampler& sampler) {
if (sampler.force_degamma) {
LOG_WARNING(Render_Vulkan, "Texture requires gamma correction");
}
using namespace Vulkan; using namespace Vulkan;
const vk::SamplerCreateInfo sampler_ci = { const vk::SamplerCreateInfo sampler_ci = {
.magFilter = LiverpoolToVK::Filter(sampler.xy_mag_filter), .magFilter = LiverpoolToVK::Filter(sampler.xy_mag_filter),

View File

@ -427,7 +427,7 @@ void TextureCache::RefreshImage(Image& image, Vulkan::Scheduler* custom_schedule
const VAddr image_addr = image.info.guest_address; const VAddr image_addr = image.info.guest_address;
const size_t image_size = image.info.guest_size_bytes; const size_t image_size = image.info.guest_size_bytes;
const auto [vk_buffer, buf_offset] = buffer_cache.ObtainTempBuffer(image_addr, image_size); const auto [vk_buffer, buf_offset] = buffer_cache.ObtainViewBuffer(image_addr, image_size);
// The obtained buffer may be written by a shader so we need to emit a barrier to prevent RAW // The obtained buffer may be written by a shader so we need to emit a barrier to prevent RAW
// hazard // hazard
if (auto barrier = vk_buffer->GetBarrier(vk::AccessFlagBits2::eTransferRead, if (auto barrier = vk_buffer->GetBarrier(vk::AccessFlagBits2::eTransferRead,