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
|
- name: Setup Qt
|
||||||
uses: jurplel/install-qt-action@v4
|
uses: jurplel/install-qt-action@v4
|
||||||
with:
|
with:
|
||||||
version: 6.7.3
|
version: 6.8.2
|
||||||
host: windows
|
host: windows
|
||||||
target: desktop
|
target: desktop
|
||||||
arch: win64_msvc2019_64
|
arch: win64_msvc2022_64
|
||||||
archives: qtbase qttools
|
archives: qtbase qttools
|
||||||
modules: qtmultimedia
|
modules: qtmultimedia
|
||||||
|
|
||||||
@ -228,7 +228,7 @@ jobs:
|
|||||||
- name: Setup Qt
|
- name: Setup Qt
|
||||||
uses: jurplel/install-qt-action@v4
|
uses: jurplel/install-qt-action@v4
|
||||||
with:
|
with:
|
||||||
version: 6.7.3
|
version: 6.8.2
|
||||||
host: mac
|
host: mac
|
||||||
target: desktop
|
target: desktop
|
||||||
arch: clang_64
|
arch: clang_64
|
||||||
|
@ -3,6 +3,7 @@ version = 1
|
|||||||
[[annotations]]
|
[[annotations]]
|
||||||
path = [
|
path = [
|
||||||
"REUSE.toml",
|
"REUSE.toml",
|
||||||
|
"crowdin.yml",
|
||||||
"CMakeSettings.json",
|
"CMakeSettings.json",
|
||||||
".github/FUNDING.yml",
|
".github/FUNDING.yml",
|
||||||
".github/shadps4.png",
|
".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.
|
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.
|
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.
|
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:
|
Once you are finished, you will have to configure Qt within Visual Studio:
|
||||||
|
|
||||||
1. Tools -> Options -> Qt -> Versions
|
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.
|
3. Enable the default checkmark on the new version you just created.
|
||||||
|
|
||||||
### (Prerequisite) Download [**Git for Windows**](https://git-scm.com/download/win)
|
### (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:
|
3. If you want to build shadPS4 with the Qt Gui:
|
||||||
1. Click x64-Clang-Release and select "Manage Configurations"
|
1. Click x64-Clang-Release and select "Manage Configurations"
|
||||||
2. Look for "CMake command arguments" and add to the text field
|
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)
|
(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
|
3. Press CTRL+S to save and wait a moment for CMake generation
|
||||||
4. Change the project to build to shadps4.exe
|
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\`
|
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:
|
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)
|
(Change Qt path if you've installed it to non-default path)
|
||||||
|
|
||||||
## Option 2: MSYS2/MinGW
|
## Option 2: MSYS2/MinGW
|
||||||
|
@ -2307,8 +2307,36 @@ s32 PS4_SYSV_ABI sceGnmUpdateGsShader(u32* cmdbuf, u32 size, const u32* gs_regs)
|
|||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceGnmUpdateHsShader() {
|
int PS4_SYSV_ABI sceGnmUpdateHsShader(u32* cmdbuf, u32 size, const u32* hs_regs, u32 ls_hs_config) {
|
||||||
LOG_ERROR(Lib_GnmDriver, "(STUBBED) called");
|
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;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,7 +227,7 @@ int PS4_SYSV_ABI sceGnmUnregisterAllResourcesForOwner();
|
|||||||
int PS4_SYSV_ABI sceGnmUnregisterOwnerAndResources();
|
int PS4_SYSV_ABI sceGnmUnregisterOwnerAndResources();
|
||||||
int PS4_SYSV_ABI sceGnmUnregisterResource();
|
int PS4_SYSV_ABI sceGnmUnregisterResource();
|
||||||
s32 PS4_SYSV_ABI sceGnmUpdateGsShader(u32* cmdbuf, u32 size, const u32* gs_regs);
|
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 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 sceGnmUpdatePsShader350(u32* cmdbuf, u32 size, const u32* ps_regs);
|
||||||
s32 PS4_SYSV_ABI sceGnmUpdateVsShader(u32* cmdbuf, u32 size, const u32* vs_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 {
|
} else {
|
||||||
QMessageBox::warning(this, tr("Error"),
|
QMessageBox::warning(this, tr("Error"),
|
||||||
QString(tr("Failed to download file:") +
|
QString(tr("Failed to download file:") +
|
||||||
"%1\n\n" + tr("Error:") + "%2")
|
"%1\n\n" + tr("Error") + ":%2")
|
||||||
.arg(fileUrl)
|
.arg(fileUrl)
|
||||||
.arg(fileReply->errorString()));
|
.arg(fileReply->errorString()));
|
||||||
}
|
}
|
||||||
@ -644,7 +644,7 @@ void CheatsPatches::downloadCheats(const QString& source, const QString& gameSer
|
|||||||
} else {
|
} else {
|
||||||
QMessageBox::warning(this, tr("Error"),
|
QMessageBox::warning(this, tr("Error"),
|
||||||
QString(tr("Failed to download file:") +
|
QString(tr("Failed to download file:") +
|
||||||
"%1\n\n" + tr("Error:") + "%2")
|
"%1\n\n" + tr("Error") + ":%2")
|
||||||
.arg(fileUrl)
|
.arg(fileUrl)
|
||||||
.arg(fileReply->errorString()));
|
.arg(fileReply->errorString()));
|
||||||
}
|
}
|
||||||
@ -843,7 +843,7 @@ void CheatsPatches::compatibleVersionNotice(const QString repository) {
|
|||||||
foreach (const QString& xmlFile, xmlFiles) {
|
foreach (const QString& xmlFile, xmlFiles) {
|
||||||
QFile file(dir.filePath(xmlFile));
|
QFile file(dir.filePath(xmlFile));
|
||||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
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));
|
QString(tr("Failed to open file:") + "\n%1").arg(xmlFile));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -871,7 +871,7 @@ void CheatsPatches::compatibleVersionNotice(const QString repository) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (xmlReader.hasError()) {
|
if (xmlReader.hasError()) {
|
||||||
QMessageBox::warning(this, tr("ERROR"),
|
QMessageBox::warning(this, tr("Error"),
|
||||||
QString(tr("XML ERROR:") + "\n%1").arg(xmlReader.errorString()));
|
QString(tr("XML ERROR:") + "\n%1").arg(xmlReader.errorString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -926,7 +926,7 @@ void CheatsPatches::createFilesJson(const QString& repository) {
|
|||||||
foreach (const QString& xmlFile, xmlFiles) {
|
foreach (const QString& xmlFile, xmlFiles) {
|
||||||
QFile file(dir.filePath(xmlFile));
|
QFile file(dir.filePath(xmlFile));
|
||||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
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));
|
QString(tr("Failed to open file:") + "\n%1").arg(xmlFile));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -944,7 +944,7 @@ void CheatsPatches::createFilesJson(const QString& repository) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (xmlReader.hasError()) {
|
if (xmlReader.hasError()) {
|
||||||
QMessageBox::warning(this, tr("ERROR"),
|
QMessageBox::warning(this, tr("Error"),
|
||||||
QString(tr("XML ERROR:") + "\n%1").arg(xmlReader.errorString()));
|
QString(tr("XML ERROR:") + "\n%1").arg(xmlReader.errorString()));
|
||||||
}
|
}
|
||||||
filesObject[xmlFile] = titleIdsArray;
|
filesObject[xmlFile] = titleIdsArray;
|
||||||
@ -952,7 +952,7 @@ void CheatsPatches::createFilesJson(const QString& repository) {
|
|||||||
|
|
||||||
QFile jsonFile(dir.absolutePath() + "/files.json");
|
QFile jsonFile(dir.absolutePath() + "/files.json");
|
||||||
if (!jsonFile.open(QIODevice::WriteOnly)) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1155,7 +1155,7 @@ void CheatsPatches::addPatchesToLayout(const QString& filePath) {
|
|||||||
QString fullPath = dir.filePath(folderPath);
|
QString fullPath = dir.filePath(folderPath);
|
||||||
|
|
||||||
if (!dir.exists(fullPath)) {
|
if (!dir.exists(fullPath)) {
|
||||||
QMessageBox::warning(this, tr("ERROR"),
|
QMessageBox::warning(this, tr("Error"),
|
||||||
QString(tr("Directory does not exist:") + "\n%1").arg(fullPath));
|
QString(tr("Directory does not exist:") + "\n%1").arg(fullPath));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1165,7 +1165,7 @@ void CheatsPatches::addPatchesToLayout(const QString& filePath) {
|
|||||||
|
|
||||||
QFile jsonFile(filesJsonPath);
|
QFile jsonFile(filesJsonPath);
|
||||||
if (!jsonFile.open(QIODevice::ReadOnly)) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1189,7 +1189,7 @@ void CheatsPatches::addPatchesToLayout(const QString& filePath) {
|
|||||||
|
|
||||||
if (!xmlFile.open(QIODevice::ReadOnly)) {
|
if (!xmlFile.open(QIODevice::ReadOnly)) {
|
||||||
QMessageBox::warning(
|
QMessageBox::warning(
|
||||||
this, tr("ERROR"),
|
this, tr("Error"),
|
||||||
QString(tr("Failed to open file:") + "\n%1").arg(xmlFile.fileName()));
|
QString(tr("Failed to open file:") + "\n%1").arg(xmlFile.fileName()));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -18,17 +18,8 @@ PKGViewer::PKGViewer(std::shared_ptr<GameInfoClass> game_info_get, QWidget* pare
|
|||||||
treeWidget = new QTreeWidget(this);
|
treeWidget = new QTreeWidget(this);
|
||||||
treeWidget->setColumnCount(9);
|
treeWidget->setColumnCount(9);
|
||||||
QStringList headers;
|
QStringList headers;
|
||||||
headers << "Name"
|
headers << tr("Name") << tr("Serial") << tr("Installed") << tr("Size") << tr("Category")
|
||||||
<< "Serial"
|
<< tr("Type") << tr("App Ver") << tr("FW") << tr("Region") << tr("Flags") << tr("Path");
|
||||||
<< "Installed"
|
|
||||||
<< "Size"
|
|
||||||
<< "Category"
|
|
||||||
<< "Type"
|
|
||||||
<< "App Ver"
|
|
||||||
<< "FW"
|
|
||||||
<< "Region"
|
|
||||||
<< "Flags"
|
|
||||||
<< "Path";
|
|
||||||
treeWidget->setHeaderLabels(headers);
|
treeWidget->setHeaderLabels(headers);
|
||||||
treeWidget->header()->setDefaultAlignment(Qt::AlignCenter);
|
treeWidget->header()->setDefaultAlignment(Qt::AlignCenter);
|
||||||
treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
|
treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
@ -36,7 +27,7 @@ PKGViewer::PKGViewer(std::shared_ptr<GameInfoClass> game_info_get, QWidget* pare
|
|||||||
this->setCentralWidget(treeWidget);
|
this->setCentralWidget(treeWidget);
|
||||||
QMenuBar* menuBar = new QMenuBar(this);
|
QMenuBar* menuBar = new QMenuBar(this);
|
||||||
menuBar->setContextMenuPolicy(Qt::PreventContextMenu);
|
menuBar->setContextMenuPolicy(Qt::PreventContextMenu);
|
||||||
QMenu* fileMenu = menuBar->addMenu(tr("&File"));
|
QMenu* fileMenu = menuBar->addMenu(tr("File"));
|
||||||
QAction* openFolderAct = new QAction(tr("Open Folder"), this);
|
QAction* openFolderAct = new QAction(tr("Open Folder"), this);
|
||||||
fileMenu->addAction(openFolderAct);
|
fileMenu->addAction(openFolderAct);
|
||||||
this->setMenuBar(menuBar);
|
this->setMenuBar(menuBar);
|
||||||
@ -114,15 +105,15 @@ void PKGViewer::ProcessPKGInfo() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
psf.Open(package.sfo);
|
psf.Open(package.sfo);
|
||||||
QString title_name =
|
QString title_name = QString::fromStdString(
|
||||||
QString::fromStdString(std::string{psf.GetString("TITLE").value_or("Unknown")});
|
std::string{psf.GetString("TITLE").value_or(std::string{tr("Unknown").toStdString()})});
|
||||||
QString title_id =
|
QString title_id = QString::fromStdString(std::string{
|
||||||
QString::fromStdString(std::string{psf.GetString("TITLE_ID").value_or("Unknown")});
|
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_type = GameListUtils::GetAppType(psf.GetInteger("APP_TYPE").value_or(0));
|
||||||
QString app_version =
|
QString app_version = QString::fromStdString(std::string{
|
||||||
QString::fromStdString(std::string{psf.GetString("APP_VER").value_or("Unknown")});
|
psf.GetString("APP_VER").value_or(std::string{tr("Unknown").toStdString()})});
|
||||||
QString title_category =
|
QString title_category = QString::fromStdString(std::string{
|
||||||
QString::fromStdString(std::string{psf.GetString("CATEGORY").value_or("Unknown")});
|
psf.GetString("CATEGORY").value_or(std::string{tr("Unknown").toStdString()})});
|
||||||
QString pkg_size = GameListUtils::FormatSize(package.GetPkgHeader().pkg_size);
|
QString pkg_size = GameListUtils::FormatSize(package.GetPkgHeader().pkg_size);
|
||||||
pkg_content_flag = package.GetPkgHeader().pkg_content_flags;
|
pkg_content_flag = package.GetPkgHeader().pkg_content_flags;
|
||||||
QString flagss = "";
|
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()) {
|
if (const auto fw_int_opt = psf.GetInteger("SYSTEM_VER"); fw_int_opt.has_value()) {
|
||||||
const u32 fw_int = *fw_int_opt;
|
const u32 fw_int = *fw_int_opt;
|
||||||
if (fw_int == 0) {
|
if (fw_int == 0) {
|
||||||
@ -221,6 +212,6 @@ void PKGViewer::ProcessPKGInfo() {
|
|||||||
// Update status bar.
|
// Update status bar.
|
||||||
statusBar->clearMessage();
|
statusBar->clearMessage();
|
||||||
int numPkgs = m_pkg_list.size();
|
int numPkgs = m_pkg_list.size();
|
||||||
QString statusMessage = QString::number(numPkgs) + " Package.";
|
QString statusMessage = QString::number(numPkgs) + " " + tr("Package");
|
||||||
statusBar->showMessage(statusMessage);
|
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"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||||
|
SPDX-License-Identifier: GPL-2.0-or-later -->
|
||||||
<!DOCTYPE TS>
|
<!DOCTYPE TS>
|
||||||
<TS version="2.1" language="sv_SE">
|
<TS version="2.1" language="sv_SE">
|
||||||
<!-- SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
|
||||||
SPDX-License-Identifier: GPL-2.0-or-later -->
|
|
||||||
<context>
|
<context>
|
||||||
<name>AboutDialog</name>
|
<name>AboutDialog</name>
|
||||||
<message>
|
<message>
|
||||||
@ -244,14 +244,6 @@
|
|||||||
<source>Can't apply cheats before the game is started</source>
|
<source>Can't apply cheats before the game is started</source>
|
||||||
<translation>Kan inte tillämpa fusk innan spelet är startat</translation>
|
<translation>Kan inte tillämpa fusk innan spelet är startat</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Error:</source>
|
|
||||||
<translation>Fel:</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>ERROR</source>
|
|
||||||
<translation>FEL</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Close</source>
|
<source>Close</source>
|
||||||
<translation>Stäng</translation>
|
<translation>Stäng</translation>
|
||||||
@ -386,10 +378,6 @@
|
|||||||
<source>Unable to update compatibility data! Try again later.</source>
|
<source>Unable to update compatibility data! Try again later.</source>
|
||||||
<translation>Kunde inte uppdatera kompatibilitetsdata! Försök igen senare.</translation>
|
<translation>Kunde inte uppdatera kompatibilitetsdata! Försök igen senare.</translation>
|
||||||
</message>
|
</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>
|
<message>
|
||||||
<source>Unknown</source>
|
<source>Unknown</source>
|
||||||
<translation>Okänt</translation>
|
<translation>Okänt</translation>
|
||||||
@ -673,10 +661,6 @@
|
|||||||
<source>Game can be completed with playable performance and no major glitches</source>
|
<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>
|
<translation>Spelet kan spelas klart med spelbar prestanda och utan större problem</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Click to go to issue</source>
|
|
||||||
<translation type="vanished">Klicka för att gå till problem</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Last updated</source>
|
<source>Last updated</source>
|
||||||
<translation>Senast uppdaterad</translation>
|
<translation>Senast uppdaterad</translation>
|
||||||
@ -1196,14 +1180,66 @@
|
|||||||
<source>Open Folder</source>
|
<source>Open Folder</source>
|
||||||
<translation>Öppna mapp</translation>
|
<translation>Öppna mapp</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>&File</source>
|
|
||||||
<translation>&Arkiv</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>PKG ERROR</source>
|
<source>PKG ERROR</source>
|
||||||
<translation>PKG-FEL</translation>
|
<translation>PKG-FEL</translation>
|
||||||
</message>
|
</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>
|
||||||
<context>
|
<context>
|
||||||
<name>SettingsDialog</name>
|
<name>SettingsDialog</name>
|
||||||
@ -1255,10 +1291,6 @@
|
|||||||
<source>Show Splash</source>
|
<source>Show Splash</source>
|
||||||
<translation>Visa startskärm</translation>
|
<translation>Visa startskärm</translation>
|
||||||
</message>
|
</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>
|
<message>
|
||||||
<source>Enable Discord Rich Presence</source>
|
<source>Enable Discord Rich Presence</source>
|
||||||
<translation>Aktivera Discord Rich Presence</translation>
|
<translation>Aktivera Discord Rich Presence</translation>
|
||||||
@ -1323,10 +1355,6 @@
|
|||||||
<source>Graphics</source>
|
<source>Graphics</source>
|
||||||
<translation>Grafik</translation>
|
<translation>Grafik</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Gui</source>
|
|
||||||
<translation type="vanished">Gränssnitt</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>User</source>
|
<source>User</source>
|
||||||
<translation>Användare</translation>
|
<translation>Användare</translation>
|
||||||
@ -1743,6 +1771,14 @@
|
|||||||
<source>GUIBackgroundImageGroupBox</source>
|
<source>GUIBackgroundImageGroupBox</source>
|
||||||
<translation>Bakgrundsbild:\nKontrollerar opaciteten för spelets bakgrundsbild</translation>
|
<translation>Bakgrundsbild:\nKontrollerar opaciteten för spelets bakgrundsbild</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Enable HDR</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>enableHDRCheckBox</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>TrophyViewer</name>
|
<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 EmitUndefU64(EmitContext& ctx);
|
||||||
Id EmitLoadSharedU32(EmitContext& ctx, Id offset);
|
Id EmitLoadSharedU32(EmitContext& ctx, Id offset);
|
||||||
Id EmitLoadSharedU64(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 EmitWriteSharedU32(EmitContext& ctx, Id offset, Id value);
|
||||||
void EmitWriteSharedU64(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 EmitSharedAtomicIAdd32(EmitContext& ctx, Id offset, Id value);
|
||||||
Id EmitSharedAtomicUMax32(EmitContext& ctx, Id offset, Id value);
|
Id EmitSharedAtomicUMax32(EmitContext& ctx, Id offset, Id value);
|
||||||
Id EmitSharedAtomicSMax32(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) {
|
void EmitWriteSharedU32(EmitContext& ctx, Id offset, Id value) {
|
||||||
const Id shift{ctx.ConstU32(2U)};
|
const Id shift{ctx.ConstU32(2U)};
|
||||||
const Id word_offset{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift)};
|
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
|
} // namespace Shader::Backend::SPIRV
|
||||||
|
@ -813,6 +813,8 @@ void EmitContext::DefineSharedMemory() {
|
|||||||
if (!info.uses_shared) {
|
if (!info.uses_shared) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
ASSERT(info.stage == Stage::Compute);
|
||||||
|
|
||||||
const u32 max_shared_memory_size = profile.max_shared_memory_size;
|
const u32 max_shared_memory_size = profile.max_shared_memory_size;
|
||||||
u32 shared_memory_size = runtime_info.cs_info.shared_memory_size;
|
u32 shared_memory_size = runtime_info.cs_info.shared_memory_size;
|
||||||
if (shared_memory_size == 0) {
|
if (shared_memory_size == 0) {
|
||||||
|
@ -233,7 +233,8 @@ struct Info {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AddBindings(Backend::Bindings& bnd) const {
|
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.buffer += total_buffers;
|
||||||
bnd.unified += total_buffers + images.size() + samplers.size();
|
bnd.unified += total_buffers + images.size() + samplers.size();
|
||||||
bnd.user_data += ud_mask.NumRegs();
|
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);
|
return Inst<U32>(Opcode::LoadSharedU32, offset);
|
||||||
case 64:
|
case 64:
|
||||||
return Inst(Opcode::LoadSharedU64, offset);
|
return Inst(Opcode::LoadSharedU64, offset);
|
||||||
case 128:
|
|
||||||
return Inst(Opcode::LoadSharedU128, offset);
|
|
||||||
default:
|
default:
|
||||||
UNREACHABLE_MSG("Invalid bit size {}", bit_size);
|
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:
|
case 64:
|
||||||
Inst(Opcode::WriteSharedU64, offset, value);
|
Inst(Opcode::WriteSharedU64, offset, value);
|
||||||
break;
|
break;
|
||||||
case 128:
|
|
||||||
Inst(Opcode::WriteSharedU128, offset, value);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
UNREACHABLE_MSG("Invalid bit size {}", bit_size);
|
UNREACHABLE_MSG("Invalid bit size {}", bit_size);
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,6 @@ bool Inst::MayHaveSideEffects() const noexcept {
|
|||||||
case Opcode::BufferAtomicSwap32:
|
case Opcode::BufferAtomicSwap32:
|
||||||
case Opcode::DataAppend:
|
case Opcode::DataAppend:
|
||||||
case Opcode::DataConsume:
|
case Opcode::DataConsume:
|
||||||
case Opcode::WriteSharedU128:
|
|
||||||
case Opcode::WriteSharedU64:
|
case Opcode::WriteSharedU64:
|
||||||
case Opcode::WriteSharedU32:
|
case Opcode::WriteSharedU32:
|
||||||
case Opcode::SharedAtomicIAdd32:
|
case Opcode::SharedAtomicIAdd32:
|
||||||
|
@ -32,10 +32,8 @@ OPCODE(EmitPrimitive, Void,
|
|||||||
// Shared memory operations
|
// Shared memory operations
|
||||||
OPCODE(LoadSharedU32, U32, U32, )
|
OPCODE(LoadSharedU32, U32, U32, )
|
||||||
OPCODE(LoadSharedU64, U32x2, U32, )
|
OPCODE(LoadSharedU64, U32x2, U32, )
|
||||||
OPCODE(LoadSharedU128, U32x4, U32, )
|
|
||||||
OPCODE(WriteSharedU32, Void, U32, U32, )
|
OPCODE(WriteSharedU32, Void, U32, U32, )
|
||||||
OPCODE(WriteSharedU64, Void, U32, U32x2, )
|
OPCODE(WriteSharedU64, Void, U32, U32x2, )
|
||||||
OPCODE(WriteSharedU128, Void, U32, U32x4, )
|
|
||||||
|
|
||||||
// Shared atomic operations
|
// Shared atomic operations
|
||||||
OPCODE(SharedAtomicIAdd32, U32, U32, U32, )
|
OPCODE(SharedAtomicIAdd32, U32, U32, U32, )
|
||||||
|
@ -225,10 +225,8 @@ private:
|
|||||||
switch (use.user->GetOpcode()) {
|
switch (use.user->GetOpcode()) {
|
||||||
case IR::Opcode::LoadSharedU32:
|
case IR::Opcode::LoadSharedU32:
|
||||||
case IR::Opcode::LoadSharedU64:
|
case IR::Opcode::LoadSharedU64:
|
||||||
case IR::Opcode::LoadSharedU128:
|
|
||||||
case IR::Opcode::WriteSharedU32:
|
case IR::Opcode::WriteSharedU32:
|
||||||
case IR::Opcode::WriteSharedU64:
|
case IR::Opcode::WriteSharedU64: {
|
||||||
case IR::Opcode::WriteSharedU128: {
|
|
||||||
u32 counter = inst->Flags<u32>();
|
u32 counter = inst->Flags<u32>();
|
||||||
inst->SetFlags<u32>(counter + inc);
|
inst->SetFlags<u32>(counter + inc);
|
||||||
// Stop here
|
// Stop here
|
||||||
@ -435,12 +433,9 @@ void HullShaderTransform(IR::Program& program, RuntimeInfo& runtime_info) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case IR::Opcode::WriteSharedU32:
|
case IR::Opcode::WriteSharedU32:
|
||||||
case IR::Opcode::WriteSharedU64:
|
case IR::Opcode::WriteSharedU64: {
|
||||||
case IR::Opcode::WriteSharedU128: {
|
|
||||||
IR::IREmitter ir{*block, IR::Block::InstructionList::s_iterator_to(inst)};
|
IR::IREmitter ir{*block, IR::Block::InstructionList::s_iterator_to(inst)};
|
||||||
const u32 num_dwords = opcode == IR::Opcode::WriteSharedU32
|
const u32 num_dwords = opcode == IR::Opcode::WriteSharedU32 ? 1 : 2;
|
||||||
? 1
|
|
||||||
: (opcode == IR::Opcode::WriteSharedU64 ? 2 : 4);
|
|
||||||
const IR::U32 addr{inst.Arg(0)};
|
const IR::U32 addr{inst.Arg(0)};
|
||||||
const IR::U32 data{inst.Arg(1).Resolve()};
|
const IR::U32 data{inst.Arg(1).Resolve()};
|
||||||
|
|
||||||
@ -480,15 +475,12 @@ void HullShaderTransform(IR::Program& program, RuntimeInfo& runtime_info) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case IR::Opcode::LoadSharedU32: {
|
case IR::Opcode::LoadSharedU32:
|
||||||
case IR::Opcode::LoadSharedU64:
|
case IR::Opcode::LoadSharedU64: {
|
||||||
case IR::Opcode::LoadSharedU128:
|
|
||||||
IR::IREmitter ir{*block, IR::Block::InstructionList::s_iterator_to(inst)};
|
IR::IREmitter ir{*block, IR::Block::InstructionList::s_iterator_to(inst)};
|
||||||
const IR::U32 addr{inst.Arg(0)};
|
const IR::U32 addr{inst.Arg(0)};
|
||||||
const AttributeRegion region = GetAttributeRegionKind(&inst, info, runtime_info);
|
const AttributeRegion region = GetAttributeRegionKind(&inst, info, runtime_info);
|
||||||
const u32 num_dwords = opcode == IR::Opcode::LoadSharedU32
|
const u32 num_dwords = opcode == IR::Opcode::LoadSharedU32 ? 1 : 2;
|
||||||
? 1
|
|
||||||
: (opcode == IR::Opcode::LoadSharedU64 ? 2 : 4);
|
|
||||||
ASSERT_MSG(region == AttributeRegion::InputCP ||
|
ASSERT_MSG(region == AttributeRegion::InputCP ||
|
||||||
region == AttributeRegion::OutputCP,
|
region == AttributeRegion::OutputCP,
|
||||||
"Unhandled read of patchconst attribute in hull shader");
|
"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)};
|
IR::IREmitter ir{*block, IR::Block::InstructionList::s_iterator_to(inst)};
|
||||||
const auto opcode = inst.GetOpcode();
|
const auto opcode = inst.GetOpcode();
|
||||||
switch (inst.GetOpcode()) {
|
switch (inst.GetOpcode()) {
|
||||||
case IR::Opcode::LoadSharedU32: {
|
case IR::Opcode::LoadSharedU32:
|
||||||
case IR::Opcode::LoadSharedU64:
|
case IR::Opcode::LoadSharedU64: {
|
||||||
case IR::Opcode::LoadSharedU128:
|
|
||||||
const IR::U32 addr{inst.Arg(0)};
|
const IR::U32 addr{inst.Arg(0)};
|
||||||
AttributeRegion region = GetAttributeRegionKind(&inst, info, runtime_info);
|
AttributeRegion region = GetAttributeRegionKind(&inst, info, runtime_info);
|
||||||
const u32 num_dwords = opcode == IR::Opcode::LoadSharedU32
|
const u32 num_dwords = opcode == IR::Opcode::LoadSharedU32 ? 1 : 2;
|
||||||
? 1
|
|
||||||
: (opcode == IR::Opcode::LoadSharedU64 ? 2 : 4);
|
|
||||||
const auto GetInput = [&](IR::U32 addr, u32 off_dw) -> IR::F32 {
|
const auto GetInput = [&](IR::U32 addr, u32 off_dw) -> IR::F32 {
|
||||||
if (region == AttributeRegion::OutputCP) {
|
if (region == AttributeRegion::OutputCP) {
|
||||||
return ReadTessControlPointAttribute(
|
return ReadTessControlPointAttribute(
|
||||||
@ -611,10 +600,8 @@ void TessellationPreprocess(IR::Program& program, RuntimeInfo& runtime_info) {
|
|||||||
switch (inst.GetOpcode()) {
|
switch (inst.GetOpcode()) {
|
||||||
case IR::Opcode::LoadSharedU32:
|
case IR::Opcode::LoadSharedU32:
|
||||||
case IR::Opcode::LoadSharedU64:
|
case IR::Opcode::LoadSharedU64:
|
||||||
case IR::Opcode::LoadSharedU128:
|
|
||||||
case IR::Opcode::WriteSharedU32:
|
case IR::Opcode::WriteSharedU32:
|
||||||
case IR::Opcode::WriteSharedU64:
|
case IR::Opcode::WriteSharedU64: {
|
||||||
case IR::Opcode::WriteSharedU128: {
|
|
||||||
IR::Value addr = inst.Arg(0);
|
IR::Value addr = inst.Arg(0);
|
||||||
auto read_const_buffer = IR::BreadthFirstSearch(
|
auto read_const_buffer = IR::BreadthFirstSearch(
|
||||||
addr, [](IR::Inst* maybe_tess_const) -> std::optional<IR::Inst*> {
|
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 ResourceTrackingPass(IR::Program& program);
|
||||||
void CollectShaderInfoPass(IR::Program& program);
|
void CollectShaderInfoPass(IR::Program& program);
|
||||||
void LowerBufferFormatToRaw(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,
|
void RingAccessElimination(const IR::Program& program, const RuntimeInfo& runtime_info,
|
||||||
Stage stage);
|
Stage stage);
|
||||||
void TessellationPreprocess(IR::Program& program, RuntimeInfo& runtime_info);
|
void TessellationPreprocess(IR::Program& program, RuntimeInfo& runtime_info);
|
||||||
|
@ -1,38 +1,81 @@
|
|||||||
// 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 <boost/container/small_vector.hpp>
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include "shader_recompiler/ir/ir_emitter.h"
|
||||||
#include "shader_recompiler/ir/program.h"
|
#include "shader_recompiler/ir/program.h"
|
||||||
|
|
||||||
namespace Shader::Optimization {
|
namespace Shader::Optimization {
|
||||||
|
|
||||||
void LowerSharedMemToRegisters(IR::Program& program) {
|
static bool IsSharedMemoryInst(const IR::Inst& inst) {
|
||||||
boost::container::small_vector<IR::Inst*, 8> ds_writes;
|
const auto opcode = inst.GetOpcode();
|
||||||
Info& info{program.info};
|
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::Block* const block : program.blocks) {
|
||||||
for (IR::Inst& inst : block->Instructions()) {
|
for (IR::Inst& inst : block->Instructions()) {
|
||||||
const auto opcode = inst.GetOpcode();
|
if (!IsSharedMemoryInst(inst)) {
|
||||||
if (opcode == IR::Opcode::WriteSharedU32 || opcode == IR::Opcode::WriteSharedU64) {
|
|
||||||
ds_writes.emplace_back(&inst);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (opcode == IR::Opcode::LoadSharedU32 || opcode == IR::Opcode::LoadSharedU64) {
|
const auto offset = GetSharedMemImmOffset(inst);
|
||||||
// Search for write instruction with same offset
|
const auto vgpr = get_vgpr(offset);
|
||||||
const IR::Inst* prod = inst.Arg(0).InstRecursive();
|
IR::IREmitter ir{*block, IR::Block::InstructionList::s_iterator_to(inst)};
|
||||||
const auto it = std::ranges::find_if(ds_writes, [&](const IR::Inst* write) {
|
ConvertSharedMemToVgpr(ir, inst, vgpr);
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// We should have eliminated everything. Invalidate data write instructions.
|
|
||||||
for (const auto inst : ds_writes) {
|
|
||||||
inst->Invalidate();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Shader::Optimization
|
} // namespace Shader::Optimization
|
||||||
|
@ -65,6 +65,10 @@ IR::Program TranslateProgram(std::span<const u32> code, Pools& pools, Info& info
|
|||||||
// Run optimization passes
|
// Run optimization passes
|
||||||
const auto stage = program.info.stage;
|
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::SsaRewritePass(program.post_order_blocks);
|
||||||
Shader::Optimization::IdentityRemovalPass(program.blocks);
|
Shader::Optimization::IdentityRemovalPass(program.blocks);
|
||||||
if (info.l_stage == LogicalStage::TessellationControl) {
|
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::ConstantPropagationPass(program.post_order_blocks);
|
||||||
Shader::Optimization::RingAccessElimination(program, runtime_info, stage);
|
Shader::Optimization::RingAccessElimination(program, runtime_info, stage);
|
||||||
if (stage != Stage::Compute) {
|
|
||||||
Shader::Optimization::LowerSharedMemToRegisters(program);
|
|
||||||
}
|
|
||||||
Shader::Optimization::ConstantPropagationPass(program.post_order_blocks);
|
Shader::Optimization::ConstantPropagationPass(program.post_order_blocks);
|
||||||
Shader::Optimization::FlattenExtendedUserdataPass(program);
|
Shader::Optimization::FlattenExtendedUserdataPass(program);
|
||||||
Shader::Optimization::ResourceTrackingPass(program);
|
Shader::Optimization::ResourceTrackingPass(program);
|
||||||
|
@ -143,6 +143,11 @@ struct Liverpool {
|
|||||||
const u32 num_dwords = bininfo.length / sizeof(u32);
|
const u32 num_dwords = bininfo.length / sizeof(u32);
|
||||||
return std::span{code, num_dwords};
|
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 {
|
struct HsTessFactorClamp {
|
||||||
|
@ -84,7 +84,7 @@ const Shader::RuntimeInfo& PipelineCache::BuildRuntimeInfo(Stage stage, LogicalS
|
|||||||
const auto BuildCommon = [&](const auto& program) {
|
const auto BuildCommon = [&](const auto& program) {
|
||||||
info.num_user_data = program.settings.num_user_regs;
|
info.num_user_data = program.settings.num_user_regs;
|
||||||
info.num_input_vgprs = program.settings.vgpr_comp_cnt;
|
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_denorm_mode32 = program.settings.fp_denorm_mode32;
|
||||||
info.fp_round_mode32 = program.settings.fp_round_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,
|
.descriptorType = vk::DescriptorType::eStorageBuffer,
|
||||||
.pBufferInfo = &buffer_infos.back(),
|
.pBufferInfo = &buffer_infos.back(),
|
||||||
});
|
});
|
||||||
|
++binding.buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bind the flattened user data buffer as a UBO so it's accessible to the shader
|
// Bind the flattened user data buffer as a UBO so it's accessible to the shader
|
||||||
|
Loading…
Reference in New Issue
Block a user