mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-08-04 16:32:39 +00:00
Merge branch 'shadps4-emu:main' into unity-flip-fix
This commit is contained in:
commit
9218d2e381
6
.github/workflows/build.yml
vendored
6
.github/workflows/build.yml
vendored
@ -111,10 +111,10 @@ jobs:
|
||||
- name: Setup Qt
|
||||
uses: jurplel/install-qt-action@v4
|
||||
with:
|
||||
version: 6.7.3
|
||||
version: 6.8.2
|
||||
host: windows
|
||||
target: desktop
|
||||
arch: win64_msvc2019_64
|
||||
arch: win64_msvc2022_64
|
||||
archives: qtbase qttools
|
||||
modules: qtmultimedia
|
||||
|
||||
@ -228,7 +228,7 @@ jobs:
|
||||
- name: Setup Qt
|
||||
uses: jurplel/install-qt-action@v4
|
||||
with:
|
||||
version: 6.7.3
|
||||
version: 6.8.2
|
||||
host: mac
|
||||
target: desktop
|
||||
arch: clang_64
|
||||
|
@ -3,6 +3,7 @@ version = 1
|
||||
[[annotations]]
|
||||
path = [
|
||||
"REUSE.toml",
|
||||
"crowdin.yml",
|
||||
"CMakeSettings.json",
|
||||
".github/FUNDING.yml",
|
||||
".github/shadps4.png",
|
||||
|
3
crowdin.yml
Normal file
3
crowdin.yml
Normal file
@ -0,0 +1,3 @@
|
||||
files:
|
||||
- source: /src/qt_gui/translations/en_US.ts
|
||||
translation: /%original_path%/%locale_with_underscore%.ts
|
@ -25,7 +25,7 @@ Once you are within the installer:
|
||||
|
||||
Beware, this requires you to create a Qt account. If you do not want to do this, please follow the MSYS2/MinGW compilation method instead.
|
||||
|
||||
1. Under the current, non beta version of Qt (at the time of writing 6.7.3), select the option `MSVC 2022 64-bit` or similar, as well as `QT Multimedia`.
|
||||
1. Under the current, non beta version of Qt (at the time of writing 6.8.2), select the option `MSVC 2022 64-bit` or similar, as well as `QT Multimedia`.
|
||||
If you are on Windows on ARM / Qualcomm Snapdragon Elite X, select `MSVC 2022 ARM64` instead.
|
||||
|
||||
Go through the installation normally. If you know what you are doing, you may unselect individual components that eat up too much disk space.
|
||||
@ -35,7 +35,7 @@ Beware, this requires you to create a Qt account. If you do not want to do this,
|
||||
Once you are finished, you will have to configure Qt within Visual Studio:
|
||||
|
||||
1. Tools -> Options -> Qt -> Versions
|
||||
2. Add a new Qt version and navigate it to the correct folder. Should look like so: `C:\Qt\6.7.3\msvc2022_64`
|
||||
2. Add a new Qt version and navigate it to the correct folder. Should look like so: `C:\Qt\6.8.2\msvc2022_64`
|
||||
3. Enable the default checkmark on the new version you just created.
|
||||
|
||||
### (Prerequisite) Download [**Git for Windows**](https://git-scm.com/download/win)
|
||||
@ -55,7 +55,7 @@ Go through the Git for Windows installation as normal
|
||||
3. If you want to build shadPS4 with the Qt Gui:
|
||||
1. Click x64-Clang-Release and select "Manage Configurations"
|
||||
2. Look for "CMake command arguments" and add to the text field
|
||||
`-DENABLE_QT_GUI=ON -DCMAKE_PREFIX_PATH=C:\Qt\6.7.3\msvc2022_64`
|
||||
`-DENABLE_QT_GUI=ON -DCMAKE_PREFIX_PATH=C:\Qt\6.8.2\msvc2022_64`
|
||||
(Change Qt path if you've installed it to non-default path)
|
||||
3. Press CTRL+S to save and wait a moment for CMake generation
|
||||
4. Change the project to build to shadps4.exe
|
||||
@ -64,7 +64,7 @@ Go through the Git for Windows installation as normal
|
||||
Your shadps4.exe will be in `C:\path\to\source\Build\x64-Clang-Release\`
|
||||
|
||||
To automatically populate the necessary files to run shadPS4.exe, run in a command prompt or terminal:
|
||||
`C:\Qt\6.7.3\msvc2022_64\bin\windeployqt6.exe "C:\path\to\shadps4.exe"`
|
||||
`C:\Qt\6.8.2\msvc2022_64\bin\windeployqt6.exe "C:\path\to\shadps4.exe"`
|
||||
(Change Qt path if you've installed it to non-default path)
|
||||
|
||||
## Option 2: MSYS2/MinGW
|
||||
|
@ -2307,8 +2307,36 @@ s32 PS4_SYSV_ABI sceGnmUpdateGsShader(u32* cmdbuf, u32 size, const u32* gs_regs)
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceGnmUpdateHsShader() {
|
||||
LOG_ERROR(Lib_GnmDriver, "(STUBBED) called");
|
||||
int PS4_SYSV_ABI sceGnmUpdateHsShader(u32* cmdbuf, u32 size, const u32* hs_regs, u32 ls_hs_config) {
|
||||
LOG_TRACE(Lib_GnmDriver, "called");
|
||||
|
||||
if (!cmdbuf || size <= 0x1c) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!hs_regs) {
|
||||
LOG_ERROR(Lib_GnmDriver, "Null pointer passed as argument");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hs_regs[1] != 0) {
|
||||
LOG_ERROR(Lib_GnmDriver, "Invalid shader address");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cmdbuf = PM4CmdSetData::SetShReg(cmdbuf, 0x108u, hs_regs[0],
|
||||
0u); // SPI_SHADER_PGM_LO_HS/SPI_SHADER_PGM_HI_HS
|
||||
cmdbuf = PM4CmdSetData::SetShReg(cmdbuf, 0x10au, hs_regs[2],
|
||||
hs_regs[3]); // SPI_SHADER_PGM_RSRC1_HS/SPI_SHADER_PGM_RSRC1_LS
|
||||
cmdbuf = WritePacket<PM4ItOpcode::Nop>(
|
||||
cmdbuf, PM4ShaderType::ShaderGraphics, 0xc01e0286u, hs_regs[5],
|
||||
hs_regs[6]); // VGT_HOS_MAX_TESS_LEVEL/VGT_HOS_MIN_TESS_LEVEL update
|
||||
cmdbuf = WritePacket<PM4ItOpcode::Nop>(cmdbuf, PM4ShaderType::ShaderGraphics, 0xc01e02dbu,
|
||||
hs_regs[4]); // VGT_TF_PARAM update
|
||||
cmdbuf = WritePacket<PM4ItOpcode::Nop>(cmdbuf, PM4ShaderType::ShaderGraphics, 0xc01e02d6u,
|
||||
ls_hs_config); // VGT_LS_HS_CONFIG update
|
||||
|
||||
WriteTrailingNop<11>(cmdbuf);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
@ -227,7 +227,7 @@ int PS4_SYSV_ABI sceGnmUnregisterAllResourcesForOwner();
|
||||
int PS4_SYSV_ABI sceGnmUnregisterOwnerAndResources();
|
||||
int PS4_SYSV_ABI sceGnmUnregisterResource();
|
||||
s32 PS4_SYSV_ABI sceGnmUpdateGsShader(u32* cmdbuf, u32 size, const u32* gs_regs);
|
||||
int PS4_SYSV_ABI sceGnmUpdateHsShader();
|
||||
int PS4_SYSV_ABI sceGnmUpdateHsShader(u32* cmdbuf, u32 size, const u32* ps_regs, u32 ls_hs_config);
|
||||
s32 PS4_SYSV_ABI sceGnmUpdatePsShader(u32* cmdbuf, u32 size, const u32* ps_regs);
|
||||
s32 PS4_SYSV_ABI sceGnmUpdatePsShader350(u32* cmdbuf, u32 size, const u32* ps_regs);
|
||||
s32 PS4_SYSV_ABI sceGnmUpdateVsShader(u32* cmdbuf, u32 size, const u32* vs_regs,
|
||||
|
@ -568,7 +568,7 @@ void CheatsPatches::downloadCheats(const QString& source, const QString& gameSer
|
||||
} else {
|
||||
QMessageBox::warning(this, tr("Error"),
|
||||
QString(tr("Failed to download file:") +
|
||||
"%1\n\n" + tr("Error:") + "%2")
|
||||
"%1\n\n" + tr("Error") + ":%2")
|
||||
.arg(fileUrl)
|
||||
.arg(fileReply->errorString()));
|
||||
}
|
||||
@ -644,7 +644,7 @@ void CheatsPatches::downloadCheats(const QString& source, const QString& gameSer
|
||||
} else {
|
||||
QMessageBox::warning(this, tr("Error"),
|
||||
QString(tr("Failed to download file:") +
|
||||
"%1\n\n" + tr("Error:") + "%2")
|
||||
"%1\n\n" + tr("Error") + ":%2")
|
||||
.arg(fileUrl)
|
||||
.arg(fileReply->errorString()));
|
||||
}
|
||||
@ -843,7 +843,7 @@ void CheatsPatches::compatibleVersionNotice(const QString repository) {
|
||||
foreach (const QString& xmlFile, xmlFiles) {
|
||||
QFile file(dir.filePath(xmlFile));
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
QMessageBox::warning(this, tr("ERROR"),
|
||||
QMessageBox::warning(this, tr("Error"),
|
||||
QString(tr("Failed to open file:") + "\n%1").arg(xmlFile));
|
||||
continue;
|
||||
}
|
||||
@ -871,7 +871,7 @@ void CheatsPatches::compatibleVersionNotice(const QString repository) {
|
||||
}
|
||||
|
||||
if (xmlReader.hasError()) {
|
||||
QMessageBox::warning(this, tr("ERROR"),
|
||||
QMessageBox::warning(this, tr("Error"),
|
||||
QString(tr("XML ERROR:") + "\n%1").arg(xmlReader.errorString()));
|
||||
}
|
||||
|
||||
@ -926,7 +926,7 @@ void CheatsPatches::createFilesJson(const QString& repository) {
|
||||
foreach (const QString& xmlFile, xmlFiles) {
|
||||
QFile file(dir.filePath(xmlFile));
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
QMessageBox::warning(this, tr("ERROR"),
|
||||
QMessageBox::warning(this, tr("Error"),
|
||||
QString(tr("Failed to open file:") + "\n%1").arg(xmlFile));
|
||||
continue;
|
||||
}
|
||||
@ -944,7 +944,7 @@ void CheatsPatches::createFilesJson(const QString& repository) {
|
||||
}
|
||||
|
||||
if (xmlReader.hasError()) {
|
||||
QMessageBox::warning(this, tr("ERROR"),
|
||||
QMessageBox::warning(this, tr("Error"),
|
||||
QString(tr("XML ERROR:") + "\n%1").arg(xmlReader.errorString()));
|
||||
}
|
||||
filesObject[xmlFile] = titleIdsArray;
|
||||
@ -952,7 +952,7 @@ void CheatsPatches::createFilesJson(const QString& repository) {
|
||||
|
||||
QFile jsonFile(dir.absolutePath() + "/files.json");
|
||||
if (!jsonFile.open(QIODevice::WriteOnly)) {
|
||||
QMessageBox::warning(this, tr("ERROR"), tr("Failed to open files.json for writing"));
|
||||
QMessageBox::warning(this, tr("Error"), tr("Failed to open files.json for writing"));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1155,7 +1155,7 @@ void CheatsPatches::addPatchesToLayout(const QString& filePath) {
|
||||
QString fullPath = dir.filePath(folderPath);
|
||||
|
||||
if (!dir.exists(fullPath)) {
|
||||
QMessageBox::warning(this, tr("ERROR"),
|
||||
QMessageBox::warning(this, tr("Error"),
|
||||
QString(tr("Directory does not exist:") + "\n%1").arg(fullPath));
|
||||
return;
|
||||
}
|
||||
@ -1165,7 +1165,7 @@ void CheatsPatches::addPatchesToLayout(const QString& filePath) {
|
||||
|
||||
QFile jsonFile(filesJsonPath);
|
||||
if (!jsonFile.open(QIODevice::ReadOnly)) {
|
||||
QMessageBox::warning(this, tr("ERROR"), tr("Failed to open files.json for reading."));
|
||||
QMessageBox::warning(this, tr("Error"), tr("Failed to open files.json for reading."));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1189,7 +1189,7 @@ void CheatsPatches::addPatchesToLayout(const QString& filePath) {
|
||||
|
||||
if (!xmlFile.open(QIODevice::ReadOnly)) {
|
||||
QMessageBox::warning(
|
||||
this, tr("ERROR"),
|
||||
this, tr("Error"),
|
||||
QString(tr("Failed to open file:") + "\n%1").arg(xmlFile.fileName()));
|
||||
continue;
|
||||
}
|
||||
|
@ -18,17 +18,8 @@ PKGViewer::PKGViewer(std::shared_ptr<GameInfoClass> game_info_get, QWidget* pare
|
||||
treeWidget = new QTreeWidget(this);
|
||||
treeWidget->setColumnCount(9);
|
||||
QStringList headers;
|
||||
headers << "Name"
|
||||
<< "Serial"
|
||||
<< "Installed"
|
||||
<< "Size"
|
||||
<< "Category"
|
||||
<< "Type"
|
||||
<< "App Ver"
|
||||
<< "FW"
|
||||
<< "Region"
|
||||
<< "Flags"
|
||||
<< "Path";
|
||||
headers << tr("Name") << tr("Serial") << tr("Installed") << tr("Size") << tr("Category")
|
||||
<< tr("Type") << tr("App Ver") << tr("FW") << tr("Region") << tr("Flags") << tr("Path");
|
||||
treeWidget->setHeaderLabels(headers);
|
||||
treeWidget->header()->setDefaultAlignment(Qt::AlignCenter);
|
||||
treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
@ -36,7 +27,7 @@ PKGViewer::PKGViewer(std::shared_ptr<GameInfoClass> game_info_get, QWidget* pare
|
||||
this->setCentralWidget(treeWidget);
|
||||
QMenuBar* menuBar = new QMenuBar(this);
|
||||
menuBar->setContextMenuPolicy(Qt::PreventContextMenu);
|
||||
QMenu* fileMenu = menuBar->addMenu(tr("&File"));
|
||||
QMenu* fileMenu = menuBar->addMenu(tr("File"));
|
||||
QAction* openFolderAct = new QAction(tr("Open Folder"), this);
|
||||
fileMenu->addAction(openFolderAct);
|
||||
this->setMenuBar(menuBar);
|
||||
@ -114,15 +105,15 @@ void PKGViewer::ProcessPKGInfo() {
|
||||
return;
|
||||
}
|
||||
psf.Open(package.sfo);
|
||||
QString title_name =
|
||||
QString::fromStdString(std::string{psf.GetString("TITLE").value_or("Unknown")});
|
||||
QString title_id =
|
||||
QString::fromStdString(std::string{psf.GetString("TITLE_ID").value_or("Unknown")});
|
||||
QString title_name = QString::fromStdString(
|
||||
std::string{psf.GetString("TITLE").value_or(std::string{tr("Unknown").toStdString()})});
|
||||
QString title_id = QString::fromStdString(std::string{
|
||||
psf.GetString("TITLE_ID").value_or(std::string{tr("Unknown").toStdString()})});
|
||||
QString app_type = GameListUtils::GetAppType(psf.GetInteger("APP_TYPE").value_or(0));
|
||||
QString app_version =
|
||||
QString::fromStdString(std::string{psf.GetString("APP_VER").value_or("Unknown")});
|
||||
QString title_category =
|
||||
QString::fromStdString(std::string{psf.GetString("CATEGORY").value_or("Unknown")});
|
||||
QString app_version = QString::fromStdString(std::string{
|
||||
psf.GetString("APP_VER").value_or(std::string{tr("Unknown").toStdString()})});
|
||||
QString title_category = QString::fromStdString(std::string{
|
||||
psf.GetString("CATEGORY").value_or(std::string{tr("Unknown").toStdString()})});
|
||||
QString pkg_size = GameListUtils::FormatSize(package.GetPkgHeader().pkg_size);
|
||||
pkg_content_flag = package.GetPkgHeader().pkg_content_flags;
|
||||
QString flagss = "";
|
||||
@ -134,7 +125,7 @@ void PKGViewer::ProcessPKGInfo() {
|
||||
}
|
||||
}
|
||||
|
||||
QString fw_ = "Unknown";
|
||||
QString fw_ = tr("Unknown");
|
||||
if (const auto fw_int_opt = psf.GetInteger("SYSTEM_VER"); fw_int_opt.has_value()) {
|
||||
const u32 fw_int = *fw_int_opt;
|
||||
if (fw_int == 0) {
|
||||
@ -221,6 +212,6 @@ void PKGViewer::ProcessPKGInfo() {
|
||||
// Update status bar.
|
||||
statusBar->clearMessage();
|
||||
int numPkgs = m_pkg_list.size();
|
||||
QString statusMessage = QString::number(numPkgs) + " Package.";
|
||||
QString statusMessage = QString::number(numPkgs) + " " + tr("Package");
|
||||
statusBar->showMessage(statusMessage);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
1790
src/qt_gui/translations/ar_SA.ts
Normal file
1790
src/qt_gui/translations/ar_SA.ts
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1790
src/qt_gui/translations/de_DE.ts
Normal file
1790
src/qt_gui/translations/de_DE.ts
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1790
src/qt_gui/translations/el_GR.ts
Normal file
1790
src/qt_gui/translations/el_GR.ts
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1790
src/qt_gui/translations/en_US.ts
Normal file
1790
src/qt_gui/translations/en_US.ts
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1790
src/qt_gui/translations/fi_FI.ts
Normal file
1790
src/qt_gui/translations/fi_FI.ts
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1790
src/qt_gui/translations/fr_FR.ts
Normal file
1790
src/qt_gui/translations/fr_FR.ts
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1790
src/qt_gui/translations/id_ID.ts
Normal file
1790
src/qt_gui/translations/id_ID.ts
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1790
src/qt_gui/translations/it_IT.ts
Normal file
1790
src/qt_gui/translations/it_IT.ts
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1790
src/qt_gui/translations/nl_NL.ts
Normal file
1790
src/qt_gui/translations/nl_NL.ts
Normal file
File diff suppressed because it is too large
Load Diff
1790
src/qt_gui/translations/no_NO.ts
Normal file
1790
src/qt_gui/translations/no_NO.ts
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1790
src/qt_gui/translations/sq_AL.ts
Normal file
1790
src/qt_gui/translations/sq_AL.ts
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="sv_SE">
|
||||
<!-- SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||
SPDX-License-Identifier: GPL-2.0-or-later -->
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="sv_SE">
|
||||
<context>
|
||||
<name>AboutDialog</name>
|
||||
<message>
|
||||
@ -244,14 +244,6 @@
|
||||
<source>Can't apply cheats before the game is started</source>
|
||||
<translation>Kan inte tillämpa fusk innan spelet är startat</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Error:</source>
|
||||
<translation>Fel:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>ERROR</source>
|
||||
<translation>FEL</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Close</source>
|
||||
<translation>Stäng</translation>
|
||||
@ -386,10 +378,6 @@
|
||||
<source>Unable to update compatibility data! Try again later.</source>
|
||||
<translation>Kunde inte uppdatera kompatibilitetsdata! Försök igen senare.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Unable to open compatibility.json for writing.</source>
|
||||
<translation type="vanished">Kunde inte öppna compatibility.json för skrivning.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Unknown</source>
|
||||
<translation>Okänt</translation>
|
||||
@ -673,10 +661,6 @@
|
||||
<source>Game can be completed with playable performance and no major glitches</source>
|
||||
<translation>Spelet kan spelas klart med spelbar prestanda och utan större problem</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Click to go to issue</source>
|
||||
<translation type="vanished">Klicka för att gå till problem</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Last updated</source>
|
||||
<translation>Senast uppdaterad</translation>
|
||||
@ -1196,14 +1180,66 @@
|
||||
<source>Open Folder</source>
|
||||
<translation>Öppna mapp</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>&File</source>
|
||||
<translation>&Arkiv</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>PKG ERROR</source>
|
||||
<translation>PKG-FEL</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Name</source>
|
||||
<translation type="unfinished">Namn</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Serial</source>
|
||||
<translation type="unfinished">Serienummer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Installed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Size</source>
|
||||
<translation type="unfinished">Storlek</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Category</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Type</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>App Ver</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>FW</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Region</source>
|
||||
<translation type="unfinished">Region</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Flags</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Path</source>
|
||||
<translation type="unfinished">Sökväg</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>File</source>
|
||||
<translation type="unfinished">Arkiv</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Unknown</source>
|
||||
<translation type="unfinished">Okänt</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Package</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SettingsDialog</name>
|
||||
@ -1255,10 +1291,6 @@
|
||||
<source>Show Splash</source>
|
||||
<translation>Visa startskärm</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>ps4proCheckBox</source>
|
||||
<translation type="vanished">Är PS4 Pro:\nGör att emulatorn agerar som en PS4 PRO, vilket kan aktivera speciella funktioner i spel som har stöd för det</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Discord Rich Presence</source>
|
||||
<translation>Aktivera Discord Rich Presence</translation>
|
||||
@ -1323,10 +1355,6 @@
|
||||
<source>Graphics</source>
|
||||
<translation>Grafik</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Gui</source>
|
||||
<translation type="vanished">Gränssnitt</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>User</source>
|
||||
<translation>Användare</translation>
|
||||
@ -1743,6 +1771,14 @@
|
||||
<source>GUIBackgroundImageGroupBox</source>
|
||||
<translation>Bakgrundsbild:\nKontrollerar opaciteten för spelets bakgrundsbild</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable HDR</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>enableHDRCheckBox</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TrophyViewer</name>
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -120,10 +120,8 @@ Id EmitUndefU32(EmitContext& ctx);
|
||||
Id EmitUndefU64(EmitContext& ctx);
|
||||
Id EmitLoadSharedU32(EmitContext& ctx, Id offset);
|
||||
Id EmitLoadSharedU64(EmitContext& ctx, Id offset);
|
||||
Id EmitLoadSharedU128(EmitContext& ctx, Id offset);
|
||||
void EmitWriteSharedU32(EmitContext& ctx, Id offset, Id value);
|
||||
void EmitWriteSharedU64(EmitContext& ctx, Id offset, Id value);
|
||||
void EmitWriteSharedU128(EmitContext& ctx, Id offset, Id value);
|
||||
Id EmitSharedAtomicIAdd32(EmitContext& ctx, Id offset, Id value);
|
||||
Id EmitSharedAtomicUMax32(EmitContext& ctx, Id offset, Id value);
|
||||
Id EmitSharedAtomicSMax32(EmitContext& ctx, Id offset, Id value);
|
||||
|
@ -38,24 +38,6 @@ Id EmitLoadSharedU64(EmitContext& ctx, Id offset) {
|
||||
}
|
||||
}
|
||||
|
||||
Id EmitLoadSharedU128(EmitContext& ctx, Id offset) {
|
||||
const Id shift_id{ctx.ConstU32(2U)};
|
||||
const Id base_index{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift_id)};
|
||||
std::array<Id, 4> values{};
|
||||
for (u32 i = 0; i < 4; ++i) {
|
||||
const Id index{i == 0 ? base_index : ctx.OpIAdd(ctx.U32[1], base_index, ctx.ConstU32(i))};
|
||||
if (ctx.info.has_emulated_shared_memory) {
|
||||
const Id pointer{ctx.OpAccessChain(ctx.shared_u32, ctx.shared_memory_u32,
|
||||
ctx.u32_zero_value, index)};
|
||||
values[i] = ctx.OpLoad(ctx.U32[1], pointer);
|
||||
} else {
|
||||
const Id pointer{ctx.OpAccessChain(ctx.shared_u32, ctx.shared_memory_u32, index)};
|
||||
values[i] = ctx.OpLoad(ctx.U32[1], pointer);
|
||||
}
|
||||
}
|
||||
return ctx.OpCompositeConstruct(ctx.U32[4], values);
|
||||
}
|
||||
|
||||
void EmitWriteSharedU32(EmitContext& ctx, Id offset, Id value) {
|
||||
const Id shift{ctx.ConstU32(2U)};
|
||||
const Id word_offset{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift)};
|
||||
@ -88,20 +70,4 @@ void EmitWriteSharedU64(EmitContext& ctx, Id offset, Id value) {
|
||||
}
|
||||
}
|
||||
|
||||
void EmitWriteSharedU128(EmitContext& ctx, Id offset, Id value) {
|
||||
const Id shift{ctx.ConstU32(2U)};
|
||||
const Id base_index{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift)};
|
||||
for (u32 i = 0; i < 4; ++i) {
|
||||
const Id index{i == 0 ? base_index : ctx.OpIAdd(ctx.U32[1], base_index, ctx.ConstU32(i))};
|
||||
if (ctx.info.has_emulated_shared_memory) {
|
||||
const Id pointer{ctx.OpAccessChain(ctx.shared_u32, ctx.shared_memory_u32,
|
||||
ctx.u32_zero_value, index)};
|
||||
ctx.OpStore(pointer, ctx.OpCompositeExtract(ctx.U32[1], value, i));
|
||||
} else {
|
||||
const Id pointer{ctx.OpAccessChain(ctx.shared_u32, ctx.shared_memory_u32, index)};
|
||||
ctx.OpStore(pointer, ctx.OpCompositeExtract(ctx.U32[1], value, i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Shader::Backend::SPIRV
|
||||
|
@ -813,6 +813,8 @@ void EmitContext::DefineSharedMemory() {
|
||||
if (!info.uses_shared) {
|
||||
return;
|
||||
}
|
||||
ASSERT(info.stage == Stage::Compute);
|
||||
|
||||
const u32 max_shared_memory_size = profile.max_shared_memory_size;
|
||||
u32 shared_memory_size = runtime_info.cs_info.shared_memory_size;
|
||||
if (shared_memory_size == 0) {
|
||||
|
@ -233,7 +233,8 @@ struct Info {
|
||||
}
|
||||
|
||||
void AddBindings(Backend::Bindings& bnd) const {
|
||||
const auto total_buffers = buffers.size() + (has_readconst ? 1 : 0);
|
||||
const auto total_buffers =
|
||||
buffers.size() + (has_readconst ? 1 : 0) + (has_emulated_shared_memory ? 1 : 0);
|
||||
bnd.buffer += total_buffers;
|
||||
bnd.unified += total_buffers + images.size() + samplers.size();
|
||||
bnd.user_data += ud_mask.NumRegs();
|
||||
|
@ -308,8 +308,6 @@ Value IREmitter::LoadShared(int bit_size, bool is_signed, const U32& offset) {
|
||||
return Inst<U32>(Opcode::LoadSharedU32, offset);
|
||||
case 64:
|
||||
return Inst(Opcode::LoadSharedU64, offset);
|
||||
case 128:
|
||||
return Inst(Opcode::LoadSharedU128, offset);
|
||||
default:
|
||||
UNREACHABLE_MSG("Invalid bit size {}", bit_size);
|
||||
}
|
||||
@ -323,9 +321,6 @@ void IREmitter::WriteShared(int bit_size, const Value& value, const U32& offset)
|
||||
case 64:
|
||||
Inst(Opcode::WriteSharedU64, offset, value);
|
||||
break;
|
||||
case 128:
|
||||
Inst(Opcode::WriteSharedU128, offset, value);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE_MSG("Invalid bit size {}", bit_size);
|
||||
}
|
||||
|
@ -78,7 +78,6 @@ bool Inst::MayHaveSideEffects() const noexcept {
|
||||
case Opcode::BufferAtomicSwap32:
|
||||
case Opcode::DataAppend:
|
||||
case Opcode::DataConsume:
|
||||
case Opcode::WriteSharedU128:
|
||||
case Opcode::WriteSharedU64:
|
||||
case Opcode::WriteSharedU32:
|
||||
case Opcode::SharedAtomicIAdd32:
|
||||
|
@ -32,10 +32,8 @@ OPCODE(EmitPrimitive, Void,
|
||||
// Shared memory operations
|
||||
OPCODE(LoadSharedU32, U32, U32, )
|
||||
OPCODE(LoadSharedU64, U32x2, U32, )
|
||||
OPCODE(LoadSharedU128, U32x4, U32, )
|
||||
OPCODE(WriteSharedU32, Void, U32, U32, )
|
||||
OPCODE(WriteSharedU64, Void, U32, U32x2, )
|
||||
OPCODE(WriteSharedU128, Void, U32, U32x4, )
|
||||
|
||||
// Shared atomic operations
|
||||
OPCODE(SharedAtomicIAdd32, U32, U32, U32, )
|
||||
|
@ -225,10 +225,8 @@ private:
|
||||
switch (use.user->GetOpcode()) {
|
||||
case IR::Opcode::LoadSharedU32:
|
||||
case IR::Opcode::LoadSharedU64:
|
||||
case IR::Opcode::LoadSharedU128:
|
||||
case IR::Opcode::WriteSharedU32:
|
||||
case IR::Opcode::WriteSharedU64:
|
||||
case IR::Opcode::WriteSharedU128: {
|
||||
case IR::Opcode::WriteSharedU64: {
|
||||
u32 counter = inst->Flags<u32>();
|
||||
inst->SetFlags<u32>(counter + inc);
|
||||
// Stop here
|
||||
@ -435,12 +433,9 @@ void HullShaderTransform(IR::Program& program, RuntimeInfo& runtime_info) {
|
||||
}
|
||||
|
||||
case IR::Opcode::WriteSharedU32:
|
||||
case IR::Opcode::WriteSharedU64:
|
||||
case IR::Opcode::WriteSharedU128: {
|
||||
case IR::Opcode::WriteSharedU64: {
|
||||
IR::IREmitter ir{*block, IR::Block::InstructionList::s_iterator_to(inst)};
|
||||
const u32 num_dwords = opcode == IR::Opcode::WriteSharedU32
|
||||
? 1
|
||||
: (opcode == IR::Opcode::WriteSharedU64 ? 2 : 4);
|
||||
const u32 num_dwords = opcode == IR::Opcode::WriteSharedU32 ? 1 : 2;
|
||||
const IR::U32 addr{inst.Arg(0)};
|
||||
const IR::U32 data{inst.Arg(1).Resolve()};
|
||||
|
||||
@ -480,15 +475,12 @@ void HullShaderTransform(IR::Program& program, RuntimeInfo& runtime_info) {
|
||||
break;
|
||||
}
|
||||
|
||||
case IR::Opcode::LoadSharedU32: {
|
||||
case IR::Opcode::LoadSharedU64:
|
||||
case IR::Opcode::LoadSharedU128:
|
||||
case IR::Opcode::LoadSharedU32:
|
||||
case IR::Opcode::LoadSharedU64: {
|
||||
IR::IREmitter ir{*block, IR::Block::InstructionList::s_iterator_to(inst)};
|
||||
const IR::U32 addr{inst.Arg(0)};
|
||||
const AttributeRegion region = GetAttributeRegionKind(&inst, info, runtime_info);
|
||||
const u32 num_dwords = opcode == IR::Opcode::LoadSharedU32
|
||||
? 1
|
||||
: (opcode == IR::Opcode::LoadSharedU64 ? 2 : 4);
|
||||
const u32 num_dwords = opcode == IR::Opcode::LoadSharedU32 ? 1 : 2;
|
||||
ASSERT_MSG(region == AttributeRegion::InputCP ||
|
||||
region == AttributeRegion::OutputCP,
|
||||
"Unhandled read of patchconst attribute in hull shader");
|
||||
@ -562,14 +554,11 @@ void DomainShaderTransform(IR::Program& program, RuntimeInfo& runtime_info) {
|
||||
IR::IREmitter ir{*block, IR::Block::InstructionList::s_iterator_to(inst)};
|
||||
const auto opcode = inst.GetOpcode();
|
||||
switch (inst.GetOpcode()) {
|
||||
case IR::Opcode::LoadSharedU32: {
|
||||
case IR::Opcode::LoadSharedU64:
|
||||
case IR::Opcode::LoadSharedU128:
|
||||
case IR::Opcode::LoadSharedU32:
|
||||
case IR::Opcode::LoadSharedU64: {
|
||||
const IR::U32 addr{inst.Arg(0)};
|
||||
AttributeRegion region = GetAttributeRegionKind(&inst, info, runtime_info);
|
||||
const u32 num_dwords = opcode == IR::Opcode::LoadSharedU32
|
||||
? 1
|
||||
: (opcode == IR::Opcode::LoadSharedU64 ? 2 : 4);
|
||||
const u32 num_dwords = opcode == IR::Opcode::LoadSharedU32 ? 1 : 2;
|
||||
const auto GetInput = [&](IR::U32 addr, u32 off_dw) -> IR::F32 {
|
||||
if (region == AttributeRegion::OutputCP) {
|
||||
return ReadTessControlPointAttribute(
|
||||
@ -611,10 +600,8 @@ void TessellationPreprocess(IR::Program& program, RuntimeInfo& runtime_info) {
|
||||
switch (inst.GetOpcode()) {
|
||||
case IR::Opcode::LoadSharedU32:
|
||||
case IR::Opcode::LoadSharedU64:
|
||||
case IR::Opcode::LoadSharedU128:
|
||||
case IR::Opcode::WriteSharedU32:
|
||||
case IR::Opcode::WriteSharedU64:
|
||||
case IR::Opcode::WriteSharedU128: {
|
||||
case IR::Opcode::WriteSharedU64: {
|
||||
IR::Value addr = inst.Arg(0);
|
||||
auto read_const_buffer = IR::BreadthFirstSearch(
|
||||
addr, [](IR::Inst* maybe_tess_const) -> std::optional<IR::Inst*> {
|
||||
|
@ -20,7 +20,7 @@ void FlattenExtendedUserdataPass(IR::Program& program);
|
||||
void ResourceTrackingPass(IR::Program& program);
|
||||
void CollectShaderInfoPass(IR::Program& program);
|
||||
void LowerBufferFormatToRaw(IR::Program& program);
|
||||
void LowerSharedMemToRegisters(IR::Program& program);
|
||||
void LowerSharedMemToRegisters(IR::Program& program, const RuntimeInfo& runtime_info);
|
||||
void RingAccessElimination(const IR::Program& program, const RuntimeInfo& runtime_info,
|
||||
Stage stage);
|
||||
void TessellationPreprocess(IR::Program& program, RuntimeInfo& runtime_info);
|
||||
|
@ -1,38 +1,81 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <boost/container/small_vector.hpp>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "shader_recompiler/ir/ir_emitter.h"
|
||||
#include "shader_recompiler/ir/program.h"
|
||||
|
||||
namespace Shader::Optimization {
|
||||
|
||||
void LowerSharedMemToRegisters(IR::Program& program) {
|
||||
boost::container::small_vector<IR::Inst*, 8> ds_writes;
|
||||
Info& info{program.info};
|
||||
static bool IsSharedMemoryInst(const IR::Inst& inst) {
|
||||
const auto opcode = inst.GetOpcode();
|
||||
return opcode == IR::Opcode::LoadSharedU32 || opcode == IR::Opcode::LoadSharedU64 ||
|
||||
opcode == IR::Opcode::WriteSharedU32 || opcode == IR::Opcode::WriteSharedU64;
|
||||
}
|
||||
|
||||
static u32 GetSharedMemImmOffset(const IR::Inst& inst) {
|
||||
const auto* address = inst.Arg(0).InstRecursive();
|
||||
ASSERT(address->GetOpcode() == IR::Opcode::IAdd32);
|
||||
const auto ir_offset = address->Arg(1);
|
||||
ASSERT_MSG(ir_offset.IsImmediate());
|
||||
const auto offset = ir_offset.U32();
|
||||
// Typical usage is the compiler spilling registers into shared memory, with 256 bytes between
|
||||
// each register to account for 4 bytes per register times 64 threads per group. Ensure that
|
||||
// this assumption holds, as if it does not this approach may need to be revised.
|
||||
ASSERT_MSG(offset % 256 == 0, "Unexpected shared memory offset alignment: {}", offset);
|
||||
return offset;
|
||||
}
|
||||
|
||||
static void ConvertSharedMemToVgpr(IR::IREmitter& ir, IR::Inst& inst, const IR::VectorReg vgpr) {
|
||||
switch (inst.GetOpcode()) {
|
||||
case IR::Opcode::LoadSharedU32:
|
||||
inst.ReplaceUsesWithAndRemove(ir.GetVectorReg(vgpr));
|
||||
break;
|
||||
case IR::Opcode::LoadSharedU64:
|
||||
inst.ReplaceUsesWithAndRemove(
|
||||
ir.CompositeConstruct(ir.GetVectorReg(vgpr), ir.GetVectorReg(vgpr + 1)));
|
||||
break;
|
||||
case IR::Opcode::WriteSharedU32:
|
||||
ir.SetVectorReg(vgpr, IR::U32{inst.Arg(1)});
|
||||
inst.Invalidate();
|
||||
break;
|
||||
case IR::Opcode::WriteSharedU64: {
|
||||
const auto value = inst.Arg(1);
|
||||
ir.SetVectorReg(vgpr, IR::U32{ir.CompositeExtract(value, 0)});
|
||||
ir.SetVectorReg(vgpr, IR::U32{ir.CompositeExtract(value, 1)});
|
||||
inst.Invalidate();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE_MSG("Unknown shared memory opcode: {}", inst.GetOpcode());
|
||||
}
|
||||
}
|
||||
|
||||
void LowerSharedMemToRegisters(IR::Program& program, const RuntimeInfo& runtime_info) {
|
||||
u32 next_vgpr_num = runtime_info.num_allocated_vgprs;
|
||||
std::unordered_map<u32, IR::VectorReg> vgpr_map;
|
||||
const auto get_vgpr = [&next_vgpr_num, &vgpr_map](const u32 offset) {
|
||||
const auto [it, is_new] = vgpr_map.try_emplace(offset);
|
||||
if (is_new) {
|
||||
ASSERT_MSG(next_vgpr_num < 256, "Out of VGPRs");
|
||||
const auto new_vgpr = static_cast<IR::VectorReg>(next_vgpr_num++);
|
||||
it->second = new_vgpr;
|
||||
}
|
||||
return it->second;
|
||||
};
|
||||
|
||||
for (IR::Block* const block : program.blocks) {
|
||||
for (IR::Inst& inst : block->Instructions()) {
|
||||
const auto opcode = inst.GetOpcode();
|
||||
if (opcode == IR::Opcode::WriteSharedU32 || opcode == IR::Opcode::WriteSharedU64) {
|
||||
ds_writes.emplace_back(&inst);
|
||||
if (!IsSharedMemoryInst(inst)) {
|
||||
continue;
|
||||
}
|
||||
if (opcode == IR::Opcode::LoadSharedU32 || opcode == IR::Opcode::LoadSharedU64) {
|
||||
// Search for write instruction with same offset
|
||||
const IR::Inst* prod = inst.Arg(0).InstRecursive();
|
||||
const auto it = std::ranges::find_if(ds_writes, [&](const IR::Inst* write) {
|
||||
const IR::Inst* write_prod = write->Arg(0).InstRecursive();
|
||||
return write_prod->Arg(1).U32() == prod->Arg(1).U32();
|
||||
});
|
||||
ASSERT(it != ds_writes.end());
|
||||
// Replace data read with value written.
|
||||
inst.ReplaceUsesWithAndRemove((*it)->Arg(1));
|
||||
const auto offset = GetSharedMemImmOffset(inst);
|
||||
const auto vgpr = get_vgpr(offset);
|
||||
IR::IREmitter ir{*block, IR::Block::InstructionList::s_iterator_to(inst)};
|
||||
ConvertSharedMemToVgpr(ir, inst, vgpr);
|
||||
}
|
||||
}
|
||||
}
|
||||
// We should have eliminated everything. Invalidate data write instructions.
|
||||
for (const auto inst : ds_writes) {
|
||||
inst->Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Shader::Optimization
|
||||
|
@ -65,6 +65,10 @@ IR::Program TranslateProgram(std::span<const u32> code, Pools& pools, Info& info
|
||||
// Run optimization passes
|
||||
const auto stage = program.info.stage;
|
||||
|
||||
if (stage == Stage::Fragment) {
|
||||
// Before SSA pass, as it will rewrite to VGPR load/store.
|
||||
Shader::Optimization::LowerSharedMemToRegisters(program, runtime_info);
|
||||
}
|
||||
Shader::Optimization::SsaRewritePass(program.post_order_blocks);
|
||||
Shader::Optimization::IdentityRemovalPass(program.blocks);
|
||||
if (info.l_stage == LogicalStage::TessellationControl) {
|
||||
@ -82,9 +86,6 @@ IR::Program TranslateProgram(std::span<const u32> code, Pools& pools, Info& info
|
||||
}
|
||||
Shader::Optimization::ConstantPropagationPass(program.post_order_blocks);
|
||||
Shader::Optimization::RingAccessElimination(program, runtime_info, stage);
|
||||
if (stage != Stage::Compute) {
|
||||
Shader::Optimization::LowerSharedMemToRegisters(program);
|
||||
}
|
||||
Shader::Optimization::ConstantPropagationPass(program.post_order_blocks);
|
||||
Shader::Optimization::FlattenExtendedUserdataPass(program);
|
||||
Shader::Optimization::ResourceTrackingPass(program);
|
||||
|
@ -143,6 +143,11 @@ struct Liverpool {
|
||||
const u32 num_dwords = bininfo.length / sizeof(u32);
|
||||
return std::span{code, num_dwords};
|
||||
}
|
||||
|
||||
[[nodiscard]] u32 NumVgprs() const {
|
||||
// Each increment allocates 4 registers, where 0 = 4 registers.
|
||||
return (settings.num_vgprs + 1) * 4;
|
||||
}
|
||||
};
|
||||
|
||||
struct HsTessFactorClamp {
|
||||
|
@ -84,7 +84,7 @@ const Shader::RuntimeInfo& PipelineCache::BuildRuntimeInfo(Stage stage, LogicalS
|
||||
const auto BuildCommon = [&](const auto& program) {
|
||||
info.num_user_data = program.settings.num_user_regs;
|
||||
info.num_input_vgprs = program.settings.vgpr_comp_cnt;
|
||||
info.num_allocated_vgprs = program.settings.num_vgprs * 4;
|
||||
info.num_allocated_vgprs = program.NumVgprs();
|
||||
info.fp_denorm_mode32 = program.settings.fp_denorm_mode32;
|
||||
info.fp_round_mode32 = program.settings.fp_round_mode32;
|
||||
};
|
||||
|
@ -535,6 +535,7 @@ void Rasterizer::BindBuffers(const Shader::Info& stage, Shader::Backend::Binding
|
||||
.descriptorType = vk::DescriptorType::eStorageBuffer,
|
||||
.pBufferInfo = &buffer_infos.back(),
|
||||
});
|
||||
++binding.buffer;
|
||||
}
|
||||
|
||||
// Bind the flattened user data buffer as a UBO so it's accessible to the shader
|
||||
|
Loading…
Reference in New Issue
Block a user