Merge remote-tracking branch 'origin/main' into fork-detection

This commit is contained in:
kalaposfos13 2025-01-29 10:56:18 +01:00
commit 1ab011b833
56 changed files with 1315 additions and 194 deletions

View File

@ -362,6 +362,8 @@ set(SYSTEM_LIBS src/core/libraries/system/commondialog.cpp
src/core/libraries/razor_cpu/razor_cpu.h
src/core/libraries/mouse/mouse.cpp
src/core/libraries/mouse/mouse.h
src/core/libraries/web_browser_dialog/webbrowserdialog.cpp
src/core/libraries/web_browser_dialog/webbrowserdialog.h
)
set(VIDEOOUT_LIB src/core/libraries/videoout/buffer.h
@ -452,6 +454,13 @@ set(NP_LIBS src/core/libraries/np_common/np_common.cpp
src/core/libraries/np_trophy/np_trophy_error.h
src/core/libraries/np_web_api/np_web_api.cpp
src/core/libraries/np_web_api/np_web_api.h
src/core/libraries/np_party/np_party.cpp
src/core/libraries/np_party/np_party.h
)
set(ZLIB_LIB src/core/libraries/zlib/zlib.cpp
src/core/libraries/zlib/zlib_sce.h
src/core/libraries/zlib/zlib_error.h
)
set(MISC_LIBS src/core/libraries/screenshot/screenshot.cpp
@ -626,6 +635,7 @@ set(CORE src/core/aerolib/stubs.cpp
${PLAYGO_LIB}
${RANDOM_LIB}
${USBD_LIB}
${ZLIB_LIB}
${MISC_LIBS}
${IME_LIB}
${FIBER_LIB}

@ -1 +1 @@
Subproject commit 2473ce6f0ab7d5d8a49aa91b2e37f3447a939f18
Subproject commit aba997657b94d6de1794ebad36ce5634341252c7

@ -1 +1 @@
Subproject commit 6173e24b31f09a0c3217103a130e74c4ddec14a6
Subproject commit 1a7b7ef6de02cf6767e42b10ddad217c45e90d47

2
externals/sirit vendored

@ -1 +1 @@
Subproject commit 26ad5a9d0fe13260b0d7d6c64419d01a196b2e32
Subproject commit d6f3c0d99862ab2ff8f95e9ac221560f1f97e29a

View File

@ -131,6 +131,9 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
SUB(Lib, Videodec) \
SUB(Lib, RazorCpu) \
SUB(Lib, Mouse) \
SUB(Lib, WebBrowserDialog) \
SUB(Lib, NpParty) \
SUB(Lib, Zlib) \
CLS(Frontend) \
CLS(Render) \
SUB(Render, Vulkan) \

View File

@ -98,6 +98,9 @@ enum class Class : u8 {
Lib_Videodec, ///< The LibSceVideodec implementation.
Lib_RazorCpu, ///< The LibRazorCpu implementation.
Lib_Mouse, ///< The LibSceMouse implementation
Lib_WebBrowserDialog, ///< The LibSceWebBrowserDialog implementation
Lib_NpParty, ///< The LibSceNpParty implementation
Lib_Zlib, ///< The LibSceZlib implementation.
Frontend, ///< Emulator UI
Render, ///< Video Core
Render_Vulkan, ///< Vulkan backend

View File

@ -7,6 +7,7 @@
#include <string>
#include <pugixml.hpp>
#ifdef ENABLE_QT_GUI
#include <QDir>
#include <QFile>
#include <QJsonArray>
#include <QJsonDocument>
@ -189,14 +190,16 @@ void OnGameLoaded() {
// We use the QT headers for the xml and json parsing, this define is only true on QT builds
QString patchDir;
Common::FS::PathToQString(patchDir, Common::FS::GetUserPath(Common::FS::PathType::PatchesDir));
QString repositories[] = {"GoldHEN", "shadPS4"};
QDir dir(patchDir);
QStringList folders = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
for (const QString& repository : repositories) {
QString filesJsonPath = patchDir + "/" + repository + "/files.json";
for (const QString& folder : folders) {
QString filesJsonPath = patchDir + "/" + folder + "/files.json";
QFile jsonFile(filesJsonPath);
if (!jsonFile.open(QIODevice::ReadOnly)) {
LOG_ERROR(Loader, "Unable to open files.json for reading.");
LOG_ERROR(Loader, "Unable to open files.json for reading in repository {}",
folder.toStdString());
continue;
}
@ -220,11 +223,12 @@ void OnGameLoaded() {
}
if (selectedFileName.isEmpty()) {
LOG_ERROR(Loader, "No patch file found for the current serial.");
LOG_ERROR(Loader, "No patch file found for the current serial in repository {}",
folder.toStdString());
continue;
}
QString filePath = patchDir + "/" + repository + "/" + selectedFileName;
QString filePath = patchDir + "/" + folder + "/" + selectedFileName;
QFile file(filePath);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
LOG_ERROR(Loader, "Unable to open the file for reading.");

View File

@ -12,6 +12,7 @@
#include "core/file_sys/fs.h"
#include "core/libraries/app_content/app_content_error.h"
#include "core/libraries/libs.h"
#include "core/libraries/system/systemservice.h"
namespace Libraries::AppContent {
@ -262,6 +263,15 @@ int PS4_SYSV_ABI sceAppContentInitialize(const OrbisAppContentInitParam* initPar
entitlement_label.copy(info.entitlement_label, sizeof(info.entitlement_label));
}
}
if (addcont_count > 0) {
SystemService::OrbisSystemServiceEvent event{};
event.event_type = SystemService::OrbisSystemServiceEventType::EntitlementUpdate;
event.service_entitlement_update.user_id = 0;
event.service_entitlement_update.np_service_label = 0;
SystemService::PushSystemServiceEvent(event);
}
return ORBIS_OK;
}

View File

@ -37,8 +37,9 @@ extern "C" void PS4_SYSV_ABI _sceFiberForceQuit(u64 ret) {
void PS4_SYSV_ABI _sceFiberCheckStackOverflow(OrbisFiberContext* ctx) {
u64* stack_base = reinterpret_cast<u64*>(ctx->current_fiber->addr_context);
u64 stack_size = ctx->current_fiber->size_context;
if (stack_base && *stack_base != kFiberStackSignature) {
UNREACHABLE_MSG("Stack overflow detected in fiber.");
UNREACHABLE_MSG("Stack overflow detected in fiber with size = 0x{:x}", stack_size);
}
}

View File

@ -1366,7 +1366,7 @@ s32 PS4_SYSV_ABI sceGnmSetEmbeddedPsShader(u32* cmdbuf, u32 size, u32 shader_id,
// pointer to a stack memory, so the check will likely fail. To workaround it we will
// repeat set shader functionality here as it is trivial.
cmdbuf = PM4CmdSetData::SetShReg(cmdbuf, 8u, ps_regs[0],
0u); // SPI_SHADER_PGM_LO_PS/SPI_SHADER_PGM_HI_PS
ps_regs[1]); // SPI_SHADER_PGM_LO_PS/SPI_SHADER_PGM_HI_PS
cmdbuf = PM4CmdSetData::SetShReg(cmdbuf, 10u, ps_regs[2],
ps_regs[3]); // SPI_SHADER_PGM_RSRC1_PS/SPI_SHADER_PGM_RSRC2_PS
cmdbuf = PM4CmdSetData::SetContextReg(cmdbuf, 0x1c4u, ps_regs[4],

View File

@ -28,6 +28,7 @@
#include "core/libraries/network/ssl2.h"
#include "core/libraries/np_common/np_common.h"
#include "core/libraries/np_manager/np_manager.h"
#include "core/libraries/np_party/np_party.h"
#include "core/libraries/np_score/np_score.h"
#include "core/libraries/np_trophy/np_trophy.h"
#include "core/libraries/np_web_api/np_web_api.h"
@ -52,6 +53,8 @@
#include "core/libraries/videodec/videodec.h"
#include "core/libraries/videodec/videodec2.h"
#include "core/libraries/videoout/video_out.h"
#include "core/libraries/web_browser_dialog/webbrowserdialog.h"
#include "core/libraries/zlib/zlib_sce.h"
#include "fiber/fiber.h"
#include "jpeg/jpegenc.h"
@ -107,6 +110,9 @@ void InitHLELibs(Core::Loader::SymbolsResolver* sym) {
Libraries::Fiber::RegisterlibSceFiber(sym);
Libraries::JpegEnc::RegisterlibSceJpegEnc(sym);
Libraries::Mouse::RegisterlibSceMouse(sym);
Libraries::WebBrowserDialog::RegisterlibSceWebBrowserDialog(sym);
Libraries::NpParty::RegisterlibSceNpParty(sym);
Libraries::Zlib::RegisterlibSceZlib(sym);
}
} // namespace Libraries

View File

@ -0,0 +1,195 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/libs.h"
#include "core/libraries/np_party/np_party.h"
namespace Libraries::NpParty {
s32 PS4_SYSV_ABI sceNpPartyCheckCallback() {
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpPartyCreate() {
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpPartyCreateA() {
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpPartyGetId() {
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpPartyGetMemberInfo() {
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpPartyGetMemberInfoA() {
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpPartyGetMembers() {
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpPartyGetMembersA() {
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpPartyGetMemberSessionInfo() {
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpPartyGetMemberVoiceInfo() {
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpPartyGetState() {
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpPartyGetStateAsUser() {
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpPartyGetStateAsUserA() {
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpPartyGetVoiceChatPriority() {
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpPartyInitialize() {
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpPartyJoin() {
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpPartyLeave() {
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpPartyRegisterHandler() {
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpPartyRegisterHandlerA() {
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpPartyRegisterPrivateHandler() {
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpPartySendBinaryMessage() {
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpPartySetVoiceChatPriority() {
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpPartyShowInvitationList() {
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpPartyShowInvitationListA() {
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpPartyTerminate() {
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpPartyUnregisterPrivateHandler() {
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
return ORBIS_OK;
}
void RegisterlibSceNpParty(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("3e4k2mzLkmc", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyCheckCallback);
LIB_FUNCTION("nOZRy-slBoA", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyCreate);
LIB_FUNCTION("XQSUbbnpPBA", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyCreateA);
LIB_FUNCTION("DRA3ay-1DFQ", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyGetId);
LIB_FUNCTION("F1P+-wpxQow", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyGetMemberInfo);
LIB_FUNCTION("v2RYVGrJDkM", "libSceNpParty", 1, "libSceNpParty", 1, 1,
sceNpPartyGetMemberInfoA);
LIB_FUNCTION("T2UOKf00ZN0", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyGetMembers);
LIB_FUNCTION("TaNw7W25QJw", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyGetMembersA);
LIB_FUNCTION("4gOMfNYzllw", "libSceNpParty", 1, "libSceNpParty", 1, 1,
sceNpPartyGetMemberSessionInfo);
LIB_FUNCTION("EKi1jx59SP4", "libSceNpParty", 1, "libSceNpParty", 1, 1,
sceNpPartyGetMemberVoiceInfo);
LIB_FUNCTION("aEzKdJzATZ0", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyGetState);
LIB_FUNCTION("o7grRhiGHYI", "libSceNpParty", 1, "libSceNpParty", 1, 1,
sceNpPartyGetStateAsUser);
LIB_FUNCTION("EjyAI+QNgFw", "libSceNpParty", 1, "libSceNpParty", 1, 1,
sceNpPartyGetStateAsUserA);
LIB_FUNCTION("-lc6XZnQXvM", "libSceNpParty", 1, "libSceNpParty", 1, 1,
sceNpPartyGetVoiceChatPriority);
LIB_FUNCTION("lhYCTQmBkds", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyInitialize);
LIB_FUNCTION("RXNCDw2GDEg", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyJoin);
LIB_FUNCTION("J8jAi-tfJHc", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyLeave);
LIB_FUNCTION("kA88gbv71ao", "libSceNpParty", 1, "libSceNpParty", 1, 1,
sceNpPartyRegisterHandler);
LIB_FUNCTION("+v4fVHMwFWc", "libSceNpParty", 1, "libSceNpParty", 1, 1,
sceNpPartyRegisterHandlerA);
LIB_FUNCTION("zo4G5WWYpKg", "libSceNpParty", 1, "libSceNpParty", 1, 1,
sceNpPartyRegisterPrivateHandler);
LIB_FUNCTION("U6VdUe-PNAY", "libSceNpParty", 1, "libSceNpParty", 1, 1,
sceNpPartySendBinaryMessage);
LIB_FUNCTION("nazKyHygHhY", "libSceNpParty", 1, "libSceNpParty", 1, 1,
sceNpPartySetVoiceChatPriority);
LIB_FUNCTION("-MFiL7hEnPE", "libSceNpParty", 1, "libSceNpParty", 1, 1,
sceNpPartyShowInvitationList);
LIB_FUNCTION("yARHEYLajs0", "libSceNpParty", 1, "libSceNpParty", 1, 1,
sceNpPartyShowInvitationListA);
LIB_FUNCTION("oLYkibiHqRA", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyTerminate);
LIB_FUNCTION("zQ7gIvt11Pc", "libSceNpParty", 1, "libSceNpParty", 1, 1,
sceNpPartyUnregisterPrivateHandler);
LIB_FUNCTION("nOZRy-slBoA", "libSceNpPartyCompat", 1, "libSceNpParty", 1, 1, sceNpPartyCreate);
LIB_FUNCTION("F1P+-wpxQow", "libSceNpPartyCompat", 1, "libSceNpParty", 1, 1,
sceNpPartyGetMemberInfo);
LIB_FUNCTION("T2UOKf00ZN0", "libSceNpPartyCompat", 1, "libSceNpParty", 1, 1,
sceNpPartyGetMembers);
LIB_FUNCTION("o7grRhiGHYI", "libSceNpPartyCompat", 1, "libSceNpParty", 1, 1,
sceNpPartyGetStateAsUser);
LIB_FUNCTION("kA88gbv71ao", "libSceNpPartyCompat", 1, "libSceNpParty", 1, 1,
sceNpPartyRegisterHandler);
LIB_FUNCTION("-MFiL7hEnPE", "libSceNpPartyCompat", 1, "libSceNpParty", 1, 1,
sceNpPartyShowInvitationList);
};
} // namespace Libraries::NpParty

View File

@ -0,0 +1,44 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/types.h"
namespace Core::Loader {
class SymbolsResolver;
}
namespace Libraries::NpParty {
s32 PS4_SYSV_ABI sceNpPartyCheckCallback();
s32 PS4_SYSV_ABI sceNpPartyCreate();
s32 PS4_SYSV_ABI sceNpPartyCreateA();
s32 PS4_SYSV_ABI sceNpPartyGetId();
s32 PS4_SYSV_ABI sceNpPartyGetMemberInfo();
s32 PS4_SYSV_ABI sceNpPartyGetMemberInfoA();
s32 PS4_SYSV_ABI sceNpPartyGetMembers();
s32 PS4_SYSV_ABI sceNpPartyGetMembersA();
s32 PS4_SYSV_ABI sceNpPartyGetMemberSessionInfo();
s32 PS4_SYSV_ABI sceNpPartyGetMemberVoiceInfo();
s32 PS4_SYSV_ABI sceNpPartyGetState();
s32 PS4_SYSV_ABI sceNpPartyGetStateAsUser();
s32 PS4_SYSV_ABI sceNpPartyGetStateAsUserA();
s32 PS4_SYSV_ABI sceNpPartyGetVoiceChatPriority();
s32 PS4_SYSV_ABI sceNpPartyInitialize();
s32 PS4_SYSV_ABI sceNpPartyJoin();
s32 PS4_SYSV_ABI sceNpPartyLeave();
s32 PS4_SYSV_ABI sceNpPartyRegisterHandler();
s32 PS4_SYSV_ABI sceNpPartyRegisterHandlerA();
s32 PS4_SYSV_ABI sceNpPartyRegisterPrivateHandler();
s32 PS4_SYSV_ABI sceNpPartySendBinaryMessage();
s32 PS4_SYSV_ABI sceNpPartySetVoiceChatPriority();
s32 PS4_SYSV_ABI sceNpPartyShowInvitationList();
s32 PS4_SYSV_ABI sceNpPartyShowInvitationListA();
s32 PS4_SYSV_ABI sceNpPartyTerminate();
s32 PS4_SYSV_ABI sceNpPartyUnregisterPrivateHandler();
s32 PS4_SYSV_ABI module_start();
s32 PS4_SYSV_ABI module_stop();
void RegisterlibSceNpParty(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::NpParty

View File

@ -473,8 +473,8 @@ int PS4_SYSV_ABI scePadSetForceIntercepted() {
int PS4_SYSV_ABI scePadSetLightBar(s32 handle, const OrbisPadLightBarParam* pParam) {
if (pParam != nullptr) {
LOG_INFO(Lib_Pad, "scePadSetLightBar called handle = {} rgb = {} {} {}", handle, pParam->r,
pParam->g, pParam->b);
LOG_DEBUG(Lib_Pad, "called handle = {} rgb = {} {} {}", handle, pParam->r, pParam->g,
pParam->b);
if (pParam->r < 0xD && pParam->g < 0xD && pParam->b < 0xD) {
LOG_INFO(Lib_Pad, "Invalid lightbar setting");

View File

@ -10,6 +10,8 @@
namespace Libraries::SystemService {
bool g_splash_status{true};
std::queue<OrbisSystemServiceEvent> g_event_queue;
std::mutex g_event_queue_mutex;
bool IsSplashVisible() {
return Config::showSplash() && g_splash_status;
@ -1772,7 +1774,9 @@ s32 PS4_SYSV_ABI sceSystemServiceGetStatus(OrbisSystemServiceStatus* status) {
LOG_ERROR(Lib_SystemService, "OrbisSystemServiceStatus is null");
return ORBIS_SYSTEM_SERVICE_ERROR_PARAMETER;
}
status->event_num = 0;
std::lock_guard<std::mutex> lock(g_event_queue_mutex);
status->event_num = static_cast<s32>(g_event_queue.size());
status->is_system_ui_overlaid = false;
status->is_in_background_execution = false;
status->is_cpu_mode7_cpu_normal = true;
@ -1940,11 +1944,19 @@ int PS4_SYSV_ABI sceSystemServiceRaiseExceptionLocalProcess() {
}
s32 PS4_SYSV_ABI sceSystemServiceReceiveEvent(OrbisSystemServiceEvent* event) {
LOG_ERROR(Lib_SystemService, "(STUBBED) called");
LOG_TRACE(Lib_SystemService, "called");
if (event == nullptr) {
return ORBIS_SYSTEM_SERVICE_ERROR_PARAMETER;
}
return ORBIS_SYSTEM_SERVICE_ERROR_NO_EVENT;
std::lock_guard<std::mutex> lock(g_event_queue_mutex);
if (g_event_queue.empty()) {
return ORBIS_SYSTEM_SERVICE_ERROR_NO_EVENT;
}
*event = g_event_queue.front();
g_event_queue.pop();
return ORBIS_OK;
}
int PS4_SYSV_ABI sceSystemServiceReenableMusicPlayer() {
@ -2412,6 +2424,11 @@ int PS4_SYSV_ABI Func_CB5E885E225F69F0() {
return ORBIS_OK;
}
void PushSystemServiceEvent(const OrbisSystemServiceEvent& event) {
std::lock_guard<std::mutex> lock(g_event_queue_mutex);
g_event_queue.push(event);
}
void RegisterlibSceSystemService(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("alZfRdr2RP8", "libSceAppMessaging", 1, "libSceSystemService", 1, 1,
sceAppMessagingClearEventFlag);

View File

@ -4,6 +4,8 @@
// https://github.com/OpenOrbis/OpenOrbis-PS4-Toolchain/blob/master/include/orbis/_types/sys_service.h
#pragma once
#include <mutex>
#include <queue>
#include "common/types.h"
namespace Core::Loader {
@ -603,5 +605,7 @@ int PS4_SYSV_ABI sceSystemServiceReenableVoiceRecognition();
int PS4_SYSV_ABI Func_6B1CDB955F0EBD65();
int PS4_SYSV_ABI Func_CB5E885E225F69F0();
void PushSystemServiceEvent(const OrbisSystemServiceEvent& event);
void RegisterlibSceSystemService(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::SystemService

View File

@ -9,7 +9,7 @@
namespace Libraries::Videodec {
static constexpr u64 kMinimumMemorySize = 32_MB; ///> Fake minimum memory size for querying
static constexpr u64 kMinimumMemorySize = 16_MB; ///> Fake minimum memory size for querying
int PS4_SYSV_ABI sceVideodecCreateDecoder(const OrbisVideodecConfigInfo* pCfgInfoIn,
const OrbisVideodecResourceInfo* pRsrcInfoIn,

View File

@ -10,7 +10,7 @@
namespace Libraries::Vdec2 {
static constexpr u64 kMinimumMemorySize = 32_MB; ///> Fake minimum memory size for querying
static constexpr u64 kMinimumMemorySize = 16_MB; ///> Fake minimum memory size for querying
s32 PS4_SYSV_ABI
sceVideodec2QueryComputeMemoryInfo(OrbisVideodec2ComputeMemoryInfo* computeMemInfo) {

View File

@ -0,0 +1,112 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/libs.h"
#include "core/libraries/web_browser_dialog/webbrowserdialog.h"
namespace Libraries::WebBrowserDialog {
s32 PS4_SYSV_ABI sceWebBrowserDialogClose() {
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceWebBrowserDialogGetEvent() {
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceWebBrowserDialogGetResult() {
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceWebBrowserDialogGetStatus() {
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceWebBrowserDialogInitialize() {
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceWebBrowserDialogNavigate() {
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceWebBrowserDialogOpen() {
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceWebBrowserDialogOpenForPredeterminedContent() {
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceWebBrowserDialogResetCookie() {
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceWebBrowserDialogSetCookie() {
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceWebBrowserDialogSetZoom() {
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceWebBrowserDialogTerminate() {
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceWebBrowserDialogUpdateStatus() {
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_F2BE042771625F8C() {
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
return ORBIS_OK;
}
void RegisterlibSceWebBrowserDialog(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("PSK+Eik919Q", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
sceWebBrowserDialogClose);
LIB_FUNCTION("Wit4LjeoeX4", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
sceWebBrowserDialogGetEvent);
LIB_FUNCTION("vCaW0fgVQmc", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
sceWebBrowserDialogGetResult);
LIB_FUNCTION("CFTG6a8TjOU", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
sceWebBrowserDialogGetStatus);
LIB_FUNCTION("jqb7HntFQFc", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
sceWebBrowserDialogInitialize);
LIB_FUNCTION("uYELOMVnmNQ", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
sceWebBrowserDialogNavigate);
LIB_FUNCTION("FraP7debcdg", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
sceWebBrowserDialogOpen);
LIB_FUNCTION("O7dIZQrwVFY", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
sceWebBrowserDialogOpenForPredeterminedContent);
LIB_FUNCTION("Cya+jvTtPqg", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
sceWebBrowserDialogResetCookie);
LIB_FUNCTION("TZnDVkP91Rg", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
sceWebBrowserDialogSetCookie);
LIB_FUNCTION("RLhKBOoNyXY", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
sceWebBrowserDialogSetZoom);
LIB_FUNCTION("ocHtyBwHfys", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
sceWebBrowserDialogTerminate);
LIB_FUNCTION("h1dR-t5ISgg", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
sceWebBrowserDialogUpdateStatus);
LIB_FUNCTION("8r4EJ3FiX4w", "libSceWebBrowserDialogLimited", 1, "libSceWebBrowserDialog", 1, 1,
Func_F2BE042771625F8C);
};
} // namespace Libraries::WebBrowserDialog

View File

@ -0,0 +1,30 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/types.h"
namespace Core::Loader {
class SymbolsResolver;
}
namespace Libraries::WebBrowserDialog {
s32 PS4_SYSV_ABI sceWebBrowserDialogClose();
s32 PS4_SYSV_ABI sceWebBrowserDialogGetEvent();
s32 PS4_SYSV_ABI sceWebBrowserDialogGetResult();
s32 PS4_SYSV_ABI sceWebBrowserDialogGetStatus();
s32 PS4_SYSV_ABI sceWebBrowserDialogInitialize();
s32 PS4_SYSV_ABI sceWebBrowserDialogNavigate();
s32 PS4_SYSV_ABI sceWebBrowserDialogOpen();
s32 PS4_SYSV_ABI sceWebBrowserDialogOpenForPredeterminedContent();
s32 PS4_SYSV_ABI sceWebBrowserDialogResetCookie();
s32 PS4_SYSV_ABI sceWebBrowserDialogSetCookie();
s32 PS4_SYSV_ABI sceWebBrowserDialogSetZoom();
s32 PS4_SYSV_ABI sceWebBrowserDialogTerminate();
s32 PS4_SYSV_ABI sceWebBrowserDialogUpdateStatus();
s32 PS4_SYSV_ABI Func_F2BE042771625F8C();
void RegisterlibSceWebBrowserDialog(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::WebBrowserDialog

View File

@ -0,0 +1,183 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <condition_variable>
#include <mutex>
#include <stop_token>
#include <unordered_map>
#include <queue>
#include <zlib.h>
#include "common/logging/log.h"
#include "common/thread.h"
#include "core/libraries/kernel/threads.h"
#include "core/libraries/libs.h"
#include "core/libraries/zlib/zlib_error.h"
#include "core/libraries/zlib/zlib_sce.h"
namespace Libraries::Zlib {
struct InflateTask {
u64 request_id;
const void* src;
u32 src_length;
void* dst;
u32 dst_length;
};
struct InflateResult {
u32 length;
s32 status;
};
static Kernel::Thread task_thread;
static std::mutex mutex;
static std::queue<InflateTask> task_queue;
static std::condition_variable_any task_queue_cv;
static std::queue<u64> done_queue;
static std::condition_variable_any done_queue_cv;
static std::unordered_map<u64, InflateResult> results;
static u64 next_request_id;
void ZlibTaskThread(const std::stop_token& stop) {
Common::SetCurrentThreadName("shadPS4:ZlibTaskThread");
while (!stop.stop_requested()) {
InflateTask task;
{
// Lock and pop from the task queue, unless stop has been requested.
std::unique_lock lock(mutex);
if (!task_queue_cv.wait(lock, stop, [&] { return !task_queue.empty(); })) {
break;
}
task = task_queue.back();
task_queue.pop();
}
uLongf decompressed_length = task.dst_length;
const auto ret = uncompress(static_cast<Bytef*>(task.dst), &decompressed_length,
static_cast<const Bytef*>(task.src), task.src_length);
{
// Lock, insert the new result, and push the finished request ID to the done queue.
std::unique_lock lock(mutex);
results[task.request_id] = InflateResult{
.length = static_cast<u32>(decompressed_length),
.status = ret == Z_BUF_ERROR ? ORBIS_ZLIB_ERROR_NOSPACE
: ret == Z_OK ? ORBIS_OK
: ORBIS_ZLIB_ERROR_FATAL,
};
done_queue.push(task.request_id);
}
done_queue_cv.notify_one();
}
}
s32 PS4_SYSV_ABI sceZlibInitialize(const void* buffer, u32 length) {
LOG_INFO(Lib_Zlib, "called");
if (task_thread.Joinable()) {
return ORBIS_ZLIB_ERROR_ALREADY_INITIALIZED;
}
// Initialize with empty task data
task_queue = std::queue<InflateTask>();
done_queue = std::queue<u64>();
results.clear();
next_request_id = 1;
task_thread.Run([](const std::stop_token& stop) { ZlibTaskThread(stop); });
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceZlibInflate(const void* src, u32 src_len, void* dst, u32 dst_len,
u64* request_id) {
LOG_DEBUG(Lib_Zlib, "(STUBBED) called");
if (!task_thread.Joinable()) {
return ORBIS_ZLIB_ERROR_NOT_INITIALIZED;
}
if (!src || !src_len || !dst || !dst_len || !request_id || dst_len > 64_KB ||
dst_len % 2_KB != 0) {
return ORBIS_ZLIB_ERROR_INVALID;
}
{
std::unique_lock lock(mutex);
*request_id = next_request_id++;
task_queue.emplace(InflateTask{
.request_id = *request_id,
.src = src,
.src_length = src_len,
.dst = dst,
.dst_length = dst_len,
});
task_queue_cv.notify_one();
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceZlibWaitForDone(u64* request_id, const u32* timeout) {
LOG_DEBUG(Lib_Zlib, "(STUBBED) called");
if (!task_thread.Joinable()) {
return ORBIS_ZLIB_ERROR_NOT_INITIALIZED;
}
if (!request_id) {
return ORBIS_ZLIB_ERROR_INVALID;
}
{
// Pop from the done queue, unless the timeout is reached.
std::unique_lock lock(mutex);
const auto pred = [] { return !done_queue.empty(); };
if (timeout) {
if (!done_queue_cv.wait_for(lock, std::chrono::milliseconds(*timeout), pred)) {
return ORBIS_ZLIB_ERROR_TIMEDOUT;
}
} else {
done_queue_cv.wait(lock, pred);
}
*request_id = done_queue.back();
done_queue.pop();
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceZlibGetResult(const u64 request_id, u32* dst_length, s32* status) {
LOG_DEBUG(Lib_Zlib, "(STUBBED) called");
if (!task_thread.Joinable()) {
return ORBIS_ZLIB_ERROR_NOT_INITIALIZED;
}
if (!dst_length || !status) {
return ORBIS_ZLIB_ERROR_INVALID;
}
{
std::unique_lock lock(mutex);
if (!results.contains(request_id)) {
return ORBIS_ZLIB_ERROR_NOT_FOUND;
}
const auto result = results[request_id];
*dst_length = result.length;
*status = result.status;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceZlibFinalize() {
LOG_INFO(Lib_Zlib, "called");
if (!task_thread.Joinable()) {
return ORBIS_ZLIB_ERROR_NOT_INITIALIZED;
}
task_thread.Stop();
return ORBIS_OK;
}
void RegisterlibSceZlib(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("m1YErdIXCp4", "libSceZlib", 1, "libSceZlib", 1, 1, sceZlibInitialize);
LIB_FUNCTION("6na+Sa-B83w", "libSceZlib", 1, "libSceZlib", 1, 1, sceZlibFinalize);
LIB_FUNCTION("TLar1HULv1Q", "libSceZlib", 1, "libSceZlib", 1, 1, sceZlibInflate);
LIB_FUNCTION("uB8VlDD4e0s", "libSceZlib", 1, "libSceZlib", 1, 1, sceZlibWaitForDone);
LIB_FUNCTION("2eDcGHC0YaM", "libSceZlib", 1, "libSceZlib", 1, 1, sceZlibGetResult);
};
} // namespace Libraries::Zlib

View File

@ -0,0 +1,18 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/libraries/error_codes.h"
// Zlib library
constexpr int ORBIS_ZLIB_ERROR_NOT_FOUND = 0x81120002;
constexpr int ORBIS_ZLIB_ERROR_BUSY = 0x8112000B;
constexpr int ORBIS_ZLIB_ERROR_FAULT = 0x8112000E;
constexpr int ORBIS_ZLIB_ERROR_INVALID = 0x81120016;
constexpr int ORBIS_ZLIB_ERROR_NOSPACE = 0x8112001C;
constexpr int ORBIS_ZLIB_ERROR_NOT_SUPPORTED = 0x81120025;
constexpr int ORBIS_ZLIB_ERROR_TIMEDOUT = 0x81120027;
constexpr int ORBIS_ZLIB_ERROR_NOT_INITIALIZED = 0x81120032;
constexpr int ORBIS_ZLIB_ERROR_ALREADY_INITIALIZED = 0x81120033;
constexpr int ORBIS_ZLIB_ERROR_FATAL = 0x811200FF;

View File

@ -0,0 +1,21 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/types.h"
namespace Core::Loader {
class SymbolsResolver;
}
namespace Libraries::Zlib {
s32 PS4_SYSV_ABI sceZlibInitialize(const void* buffer, u32 length);
s32 PS4_SYSV_ABI sceZlibInflate(const void* src, u32 src_len, void* dst, u32 dst_len,
u64* request_id);
s32 PS4_SYSV_ABI sceZlibWaitForDone(u64* request_id, const u32* timeout);
s32 PS4_SYSV_ABI sceZlibGetResult(u64 request_id, u32* dst_length, s32* status);
s32 PS4_SYSV_ABI sceZlibFinalize();
void RegisterlibSceZlib(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::Zlib

View File

@ -109,10 +109,13 @@ public:
void RelocateAnyImports(Module* m) {
Relocate(m);
for (auto& module : m_modules) {
const auto imports = module->GetImportModules();
if (std::ranges::contains(imports, m->name, &ModuleInfo::name)) {
Relocate(module.get());
const auto exports = m->GetExportModules();
for (auto& export_mod : exports) {
for (auto& module : m_modules) {
const auto imports = module->GetImportModules();
if (std::ranges::contains(imports, export_mod.name, &ModuleInfo::name)) {
Relocate(module.get());
}
}
}
}

View File

@ -389,47 +389,57 @@ s32 MemoryManager::UnmapMemory(VAddr virtual_addr, size_t size) {
return UnmapMemoryImpl(virtual_addr, size);
}
s32 MemoryManager::UnmapMemoryImpl(VAddr virtual_addr, size_t size) {
const auto it = FindVMA(virtual_addr);
const auto& vma_base = it->second;
ASSERT_MSG(vma_base.Contains(virtual_addr, size),
"Existing mapping does not contain requested unmap range");
const auto type = vma_base.type;
if (type == VMAType::Free) {
return ORBIS_OK;
}
u64 MemoryManager::UnmapBytesFromEntry(VAddr virtual_addr, VirtualMemoryArea vma_base, u64 size) {
const auto vma_base_addr = vma_base.base;
const auto vma_base_size = vma_base.size;
const auto type = vma_base.type;
const auto phys_base = vma_base.phys_base;
const bool is_exec = vma_base.is_exec;
const auto start_in_vma = virtual_addr - vma_base_addr;
const auto adjusted_size =
vma_base_size - start_in_vma < size ? vma_base_size - start_in_vma : size;
const bool has_backing = type == VMAType::Direct || type == VMAType::File;
if (type == VMAType::Free) {
return adjusted_size;
}
if (type == VMAType::Direct || type == VMAType::Pooled) {
rasterizer->UnmapMemory(virtual_addr, size);
rasterizer->UnmapMemory(virtual_addr, adjusted_size);
}
if (type == VMAType::Flexible) {
flexible_usage -= size;
flexible_usage -= adjusted_size;
}
// Mark region as free and attempt to coalesce it with neighbours.
const auto new_it = CarveVMA(virtual_addr, size);
const auto new_it = CarveVMA(virtual_addr, adjusted_size);
auto& vma = new_it->second;
vma.type = VMAType::Free;
vma.prot = MemoryProt::NoAccess;
vma.phys_base = 0;
vma.disallow_merge = false;
vma.name = "";
MergeAdjacent(vma_map, new_it);
bool readonly_file = vma.prot == MemoryProt::CpuRead && type == VMAType::File;
const auto post_merge_it = MergeAdjacent(vma_map, new_it);
auto& post_merge_vma = post_merge_it->second;
bool readonly_file = post_merge_vma.prot == MemoryProt::CpuRead && type == VMAType::File;
if (type != VMAType::Reserved && type != VMAType::PoolReserved) {
// Unmap the memory region.
impl.Unmap(vma_base_addr, vma_base_size, start_in_vma, start_in_vma + size, phys_base,
is_exec, has_backing, readonly_file);
impl.Unmap(vma_base_addr, vma_base_size, start_in_vma, start_in_vma + adjusted_size,
phys_base, is_exec, has_backing, readonly_file);
TRACK_FREE(virtual_addr, "VMEM");
}
return adjusted_size;
}
s32 MemoryManager::UnmapMemoryImpl(VAddr virtual_addr, u64 size) {
u64 unmapped_bytes = 0;
do {
auto it = FindVMA(virtual_addr + unmapped_bytes);
auto& vma_base = it->second;
auto unmapped =
UnmapBytesFromEntry(virtual_addr + unmapped_bytes, vma_base, size - unmapped_bytes);
ASSERT_MSG(unmapped > 0, "Failed to unmap memory, progress is impossible");
unmapped_bytes += unmapped;
} while (unmapped_bytes < size);
return ORBIS_OK;
}
@ -651,6 +661,12 @@ MemoryManager::VMAHandle MemoryManager::CarveVMA(VAddr virtual_addr, size_t size
const VAddr start_in_vma = virtual_addr - vma.base;
const VAddr end_in_vma = start_in_vma + size;
if (start_in_vma == 0 && size == vma.size) {
// if requsting the whole VMA, return it
return vma_handle;
}
ASSERT_MSG(end_in_vma <= vma.size, "Mapping cannot fit inside free region");
if (end_in_vma != vma.size) {

View File

@ -252,7 +252,9 @@ private:
DMemHandle Split(DMemHandle dmem_handle, size_t offset_in_area);
s32 UnmapMemoryImpl(VAddr virtual_addr, size_t size);
u64 UnmapBytesFromEntry(VAddr virtual_addr, VirtualMemoryArea vma_base, u64 size);
s32 UnmapMemoryImpl(VAddr virtual_addr, u64 size);
private:
AddressSpace impl;

View File

@ -101,9 +101,21 @@ Emulator::~Emulator() {
}
void Emulator::Run(const std::filesystem::path& file, const std::vector<std::string> args) {
const auto eboot_name = file.filename().string();
auto game_folder = file.parent_path();
if (const auto game_folder_name = game_folder.filename().string();
game_folder_name.ends_with("-UPDATE")) {
// If an executable was launched from a separate update directory,
// use the base game directory as the game folder.
const auto base_name = game_folder_name.substr(0, game_folder_name.size() - 7);
const auto base_path = game_folder.parent_path() / base_name;
if (std::filesystem::is_directory(base_path)) {
game_folder = base_path;
}
}
// Applications expect to be run from /app0 so mount the file's parent path as app0.
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
const auto game_folder = file.parent_path();
mnt->Mount(game_folder, "/app0");
// Certain games may use /hostapp as well such as CUSA001100
mnt->Mount(game_folder, "/hostapp");
@ -224,7 +236,7 @@ void Emulator::Run(const std::filesystem::path& file, const std::vector<std::str
Libraries::InitHLELibs(&linker->GetHLESymbols());
// Load the module with the linker
const auto eboot_path = mnt->GetHostPath("/app0/" + file.filename().string());
const auto eboot_path = mnt->GetHostPath("/app0/" + eboot_name);
linker->LoadModule(eboot_path);
// check if we have system modules to load

View File

@ -38,17 +38,18 @@ GameGridFrame::GameGridFrame(std::shared_ptr<GameInfoClass> game_info_get,
void GameGridFrame::onCurrentCellChanged(int currentRow, int currentColumn, int previousRow,
int previousColumn) {
cellClicked = true;
crtRow = currentRow;
crtColumn = currentColumn;
columnCnt = this->columnCount();
auto itemID = (crtRow * columnCnt) + currentColumn;
if (itemID > m_game_info->m_games.count() - 1) {
cellClicked = false;
validCellSelected = false;
BackgroundMusicPlayer::getInstance().stopMusic();
return;
}
cellClicked = true;
validCellSelected = true;
SetGridBackgroundImage(crtRow, crtColumn);
auto snd0Path = QString::fromStdString(m_game_info->m_games[itemID].snd0_path.string());

View File

@ -41,8 +41,8 @@ public:
itemID = widget->currentRow() * widget->columnCount() + widget->currentColumn();
}
// Do not show the menu if an item is selected
if (itemID == -1) {
// Do not show the menu if no item is selected
if (itemID < 0 || itemID >= m_games.size()) {
return;
}
@ -52,10 +52,12 @@ public:
// "Open Folder..." submenu
QMenu* openFolderMenu = new QMenu(tr("Open Folder..."), widget);
QAction* openGameFolder = new QAction(tr("Open Game Folder"), widget);
QAction* openUpdateFolder = new QAction(tr("Open Update Folder"), widget);
QAction* openSaveDataFolder = new QAction(tr("Open Save Data Folder"), widget);
QAction* openLogFolder = new QAction(tr("Open Log Folder"), widget);
openFolderMenu->addAction(openGameFolder);
openFolderMenu->addAction(openUpdateFolder);
openFolderMenu->addAction(openSaveDataFolder);
openFolderMenu->addAction(openLogFolder);
@ -87,10 +89,12 @@ public:
QMenu* deleteMenu = new QMenu(tr("Delete..."), widget);
QAction* deleteGame = new QAction(tr("Delete Game"), widget);
QAction* deleteUpdate = new QAction(tr("Delete Update"), widget);
QAction* deleteSaveData = new QAction(tr("Delete Save Data"), widget);
QAction* deleteDLC = new QAction(tr("Delete DLC"), widget);
deleteMenu->addAction(deleteGame);
deleteMenu->addAction(deleteUpdate);
deleteMenu->addAction(deleteSaveData);
deleteMenu->addAction(deleteDLC);
menu.addMenu(deleteMenu);
@ -122,6 +126,18 @@ public:
QDesktopServices::openUrl(QUrl::fromLocalFile(folderPath));
}
if (selected == openUpdateFolder) {
QString open_update_path;
Common::FS::PathToQString(open_update_path, m_games[itemID].path);
open_update_path += "-UPDATE";
if (!std::filesystem::exists(Common::FS::PathFromQString(open_update_path))) {
QMessageBox::critical(nullptr, tr("Error"),
QString(tr("This game has no update folder to open!")));
} else {
QDesktopServices::openUrl(QUrl::fromLocalFile(open_update_path));
}
}
if (selected == openSaveDataFolder) {
QString userPath;
Common::FS::PathToQString(userPath,
@ -143,7 +159,7 @@ public:
PSF psf;
std::filesystem::path game_folder_path = m_games[itemID].path;
std::filesystem::path game_update_path = game_folder_path;
game_update_path += "UPDATE";
game_update_path += "-UPDATE";
if (std::filesystem::exists(game_update_path)) {
game_folder_path = game_update_path;
}
@ -238,6 +254,11 @@ public:
QString trophyPath, gameTrpPath;
Common::FS::PathToQString(trophyPath, m_games[itemID].serial);
Common::FS::PathToQString(gameTrpPath, m_games[itemID].path);
auto game_update_path = Common::FS::PathFromQString(gameTrpPath);
game_update_path += "-UPDATE";
if (std::filesystem::exists(game_update_path)) {
Common::FS::PathToQString(gameTrpPath, game_update_path);
}
TrophyViewer* trophyViewer = new TrophyViewer(trophyPath, gameTrpPath);
trophyViewer->show();
connect(widget->parent(), &QWidget::destroyed, trophyViewer,
@ -335,14 +356,18 @@ public:
clipboard->setText(combinedText);
}
if (selected == deleteGame || selected == deleteUpdate || selected == deleteDLC) {
if (selected == deleteGame || selected == deleteUpdate || selected == deleteDLC ||
selected == deleteSaveData) {
bool error = false;
QString folder_path, game_update_path, dlc_path;
QString folder_path, game_update_path, dlc_path, save_data_path;
Common::FS::PathToQString(folder_path, m_games[itemID].path);
game_update_path = folder_path + "-UPDATE";
Common::FS::PathToQString(
dlc_path, Config::getAddonInstallDir() /
Common::FS::PathFromQString(folder_path).parent_path().filename());
Common::FS::PathToQString(save_data_path,
Common::FS::GetUserPath(Common::FS::PathType::UserDir) /
"savedata/1" / m_games[itemID].serial);
QString message_type = tr("Game");
if (selected == deleteUpdate) {
@ -363,6 +388,15 @@ public:
folder_path = dlc_path;
message_type = tr("DLC");
}
} else if (selected == deleteSaveData) {
if (!std::filesystem::exists(Common::FS::PathFromQString(save_data_path))) {
QMessageBox::critical(nullptr, tr("Error"),
QString(tr("This game has no save data to delete!")));
error = true;
} else {
folder_path = save_data_path;
message_type = tr("Save Data");
}
}
if (!error) {
QString gameName = QString::fromStdString(m_games[itemID].name);
@ -374,7 +408,10 @@ public:
QMessageBox::Yes | QMessageBox::No);
if (reply == QMessageBox::Yes) {
dir.removeRecursively();
widget->removeRow(itemID);
if (selected == deleteGame) {
widget->removeRow(itemID);
m_games.removeAt(itemID);
}
}
}
}

View File

@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <QCheckBox>
#include <QDialogButtonBox>
#include <QDir>
#include <QFileDialog>
@ -15,10 +16,11 @@
#include "install_dir_select.h"
InstallDirSelect::InstallDirSelect() : selected_dir() {
selected_dir = Config::getGameInstallDirs().empty() ? "" : Config::getGameInstallDirs().front();
auto install_dirs = Config::getGameInstallDirs();
selected_dir = install_dirs.empty() ? "" : install_dirs.front();
if (!Config::getGameInstallDirs().empty() && Config::getGameInstallDirs().size() == 1) {
reject();
if (!install_dirs.empty() && install_dirs.size() == 1) {
accept();
}
auto layout = new QVBoxLayout(this);
@ -53,6 +55,14 @@ QWidget* InstallDirSelect::SetupInstallDirList() {
vlayout->addWidget(m_path_list);
auto checkbox = new QCheckBox(tr("Install All Queued to Selected Folder"));
connect(checkbox, &QCheckBox::toggled, this, &InstallDirSelect::setUseForAllQueued);
vlayout->addWidget(checkbox);
auto checkbox2 = new QCheckBox(tr("Delete PKG File on Install"));
connect(checkbox2, &QCheckBox::toggled, this, &InstallDirSelect::setDeleteFileOnInstall);
vlayout->addWidget(checkbox2);
group->setLayout(vlayout);
return group;
}
@ -66,6 +76,14 @@ void InstallDirSelect::setSelectedDirectory(QListWidgetItem* item) {
}
}
void InstallDirSelect::setUseForAllQueued(bool enabled) {
use_for_all_queued = enabled;
}
void InstallDirSelect::setDeleteFileOnInstall(bool enabled) {
delete_file_on_install = enabled;
}
QWidget* InstallDirSelect::SetupDialogActions() {
auto actions = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);

View File

@ -22,9 +22,21 @@ public:
return selected_dir;
}
bool useForAllQueued() {
return use_for_all_queued;
}
bool deleteFileOnInstall() {
return delete_file_on_install;
}
private:
QWidget* SetupInstallDirList();
QWidget* SetupDialogActions();
void setSelectedDirectory(QListWidgetItem* item);
void setDeleteFileOnInstall(bool enabled);
void setUseForAllQueued(bool enabled);
std::filesystem::path selected_dir;
bool delete_file_on_install = false;
bool use_for_all_queued = false;
};

View File

@ -725,9 +725,20 @@ void MainWindow::InstallDragDropPkg(std::filesystem::path file, int pkgNum, int
return;
}
auto category = psf.GetString("CATEGORY");
InstallDirSelect ids;
ids.exec();
auto game_install_dir = ids.getSelectedDirectory();
if (!use_for_all_queued || pkgNum == 1) {
InstallDirSelect ids;
const auto selected = ids.exec();
if (selected == QDialog::Rejected) {
return;
}
last_install_dir = ids.getSelectedDirectory();
delete_file_on_install = ids.deleteFileOnInstall();
use_for_all_queued = ids.useForAllQueued();
}
std::filesystem::path game_install_dir = last_install_dir;
auto game_folder_path = game_install_dir / pkg.GetTitleID();
QString pkgType = QString::fromStdString(pkg.GetPkgFlags());
bool use_game_update = pkgType.contains("PATCH") && Config::getSeparateUpdateEnabled();
@ -879,8 +890,14 @@ void MainWindow::InstallDragDropPkg(std::filesystem::path file, int pkgNum, int
if (pkgNum == nPkg) {
QString path;
Common::FS::PathToQString(path, game_install_dir);
QIcon windowIcon(
Common::FS::PathToUTF8String(game_folder_path / "sce_sys/icon0.png")
.c_str());
QMessageBox extractMsgBox(this);
extractMsgBox.setWindowTitle(tr("Extraction Finished"));
if (!windowIcon.isNull()) {
extractMsgBox.setWindowIcon(windowIcon);
}
extractMsgBox.setText(
QString(tr("Game successfully installed at %1")).arg(path));
extractMsgBox.addButton(QMessageBox::Ok);
@ -894,6 +911,9 @@ void MainWindow::InstallDragDropPkg(std::filesystem::path file, int pkgNum, int
});
extractMsgBox.exec();
}
if (delete_file_on_install) {
std::filesystem::remove(file);
}
});
connect(&dialog, &QProgressDialog::canceled, [&]() { futureWatcher.cancel(); });
connect(&futureWatcher, &QFutureWatcher<void>::progressValueChanged, &dialog,

View File

@ -123,4 +123,8 @@ protected:
}
void resizeEvent(QResizeEvent* event) override;
std::filesystem::path last_install_dir = "";
bool delete_file_on_install = false;
bool use_for_all_queued = false;
};

View File

@ -98,7 +98,7 @@
</message>
<message>
<source>Open Folder...</source>
<translation>Åpne mappen...</translation>
<translation>Åpne mappe...</translation>
</message>
<message>
<source>Open Game Folder</source>
@ -126,7 +126,7 @@
</message>
<message>
<source>Copy All</source>
<translation>Kopier alle</translation>
<translation>Kopier alt</translation>
</message>
<message>
<source>Delete...</source>
@ -146,19 +146,19 @@
</message>
<message>
<source>Compatibility...</source>
<translation>Compatibility...</translation>
<translation>Kompatibilitet...</translation>
</message>
<message>
<source>Update database</source>
<translation>Update database</translation>
<translation>Oppdater database</translation>
</message>
<message>
<source>View report</source>
<translation>View report</translation>
<translation>Vis rapport</translation>
</message>
<message>
<source>Submit a report</source>
<translation>Submit a report</translation>
<translation>Send inn en rapport</translation>
</message>
<message>
<source>Shortcut creation</source>
@ -574,11 +574,11 @@
</message>
<message>
<source>Trophy Key</source>
<translation>Trophy Key</translation>
<translation>Trofénøkkel</translation>
</message>
<message>
<source>Trophy</source>
<translation>Trophy</translation>
<translation>Tro</translation>
</message>
<message>
<source>Logger</source>
@ -658,7 +658,7 @@
</message>
<message>
<source>Enable Shaders Dumping</source>
<translation>Aktiver dumping av skyggelegger</translation>
<translation>Aktiver skyggeleggerdumping</translation>
</message>
<message>
<source>Enable NULL GPU</source>
@ -666,7 +666,7 @@
</message>
<message>
<source>Paths</source>
<translation>Stier</translation>
<translation>Mapper</translation>
</message>
<message>
<source>Game Folders</source>
@ -686,7 +686,7 @@
</message>
<message>
<source>Enable Debug Dumping</source>
<translation>Aktiver dumping av feilretting</translation>
<translation>Aktiver feilrettingsdumping</translation>
</message>
<message>
<source>Enable Vulkan Validation Layers</source>
@ -718,7 +718,7 @@
</message>
<message>
<source>GUI Settings</source>
<translation>GUI-innstillinger</translation>
<translation>Grensesnitt-innstillinger</translation>
</message>
<message>
<source>Disable Trophy Pop-ups</source>
@ -730,7 +730,7 @@
</message>
<message>
<source>Update Compatibility Database On Startup</source>
<translation>Oppdater kompatibilitets-database ved oppstart</translation>
<translation>Oppdater database ved oppstart</translation>
</message>
<message>
<source>Game Compatibility</source>
@ -750,7 +750,7 @@
</message>
<message>
<source>Audio Backend</source>
<translation>Audio Backend</translation>
<translation>Lydsystem</translation>
</message>
<message>
<source>Save</source>
@ -806,7 +806,7 @@
</message>
<message>
<source>TrophyKey</source>
<translation>Trophy Key:\nKey used to decrypt trophies. Must be obtained from your jailbroken console.\nMust contain only hex characters.</translation>
<translation>Trofénøkkel:\nNøkkel brukes til å dekryptere trofeer. hentes fra din konsoll (jailbroken).\nMå bare inneholde sekskantede tegn.</translation>
</message>
<message>
<source>logTypeGroupBox</source>
@ -846,7 +846,7 @@
</message>
<message>
<source>checkCompatibilityOnStartupCheckBox</source>
<translation>Oppdater kompatibilitets-data ved oppstart:\nOppdaterer kompatibilitets-databasen automatisk når shadPS4 starter.</translation>
<translation>Oppdater database ved oppstart:\nOppdaterer kompatibilitets-databasen automatisk når shadPS4 starter.</translation>
</message>
<message>
<source>updateCompatibilityButton</source>
@ -894,7 +894,7 @@
</message>
<message>
<source>dumpShadersCheckBox</source>
<translation>Aktiver dumping av skyggelegger:\nFor teknisk feilsøking lagrer skyggeleggerne fra spillet i en mappe mens de gjengis.</translation>
<translation>Aktiver skyggeleggerdumping:\nFor teknisk feilsøking lagrer skyggeleggerne fra spillet i en mappe mens de gjengis.</translation>
</message>
<message>
<source>nullGpuCheckBox</source>
@ -914,7 +914,7 @@
</message>
<message>
<source>debugDump</source>
<translation>Aktiver dumping av feilsøking:\nLagrer import- og eksport-symbolene og filoverskriftsinformasjonen til det nåværende kjørende PS4-programmet i en katalog.</translation>
<translation>Aktiver feilrettingsdumping:\nLagrer import- og eksport-symbolene og filoverskriftsinformasjonen til det nåværende kjørende PS4-programmet i en katalog.</translation>
</message>
<message>
<source>vkValidationCheckBox</source>
@ -1188,7 +1188,7 @@
</message>
<message>
<source>Path</source>
<translation>Sti</translation>
<translation>Adresse</translation>
</message>
<message>
<source>Play Time</source>
@ -1232,7 +1232,7 @@
</message>
<message>
<source>Game can be completed with playable performance and no major glitches</source>
<translation>Spillet kan fullføres med spillbar ytelse og ingen store feil</translation>
<translation>Spillet kan fullføres med spillbar ytelse og uten store feil</translation>
</message>
</context>
<context>
@ -1361,4 +1361,4 @@
<translation>TB</translation>
</message>
</context>
</TS>
</TS>

View File

@ -126,11 +126,11 @@
</message>
<message>
<source>Copy All</source>
<translation>Копировать все</translation>
<translation>Копировать всё</translation>
</message>
<message>
<source>Delete...</source>
<translation>Удаление...</translation>
<translation>Удалить...</translation>
</message>
<message>
<source>Delete Game</source>
@ -158,7 +158,7 @@
</message>
<message>
<source>Submit a report</source>
<translation>Отправить отчет</translation>
<translation>Отправить отчёт</translation>
</message>
<message>
<source>Shortcut creation</source>
@ -297,7 +297,7 @@
</message>
<message>
<source>Elf Viewer</source>
<translation>Elf</translation>
<translation>Исполняемый файл</translation>
</message>
<message>
<source>Game Install Directory</source>
@ -542,7 +542,7 @@
</message>
<message>
<source>Fullscreen Mode</source>
<translation>Режим Полного Экран</translation>
<translation>Тип полноэкранного режима</translation>
</message>
<message>
<source>Enable Separate Update Folder</source>
@ -574,11 +574,11 @@
</message>
<message>
<source>Trophy Key</source>
<translation>Trophy Key</translation>
<translation>Ключ трофеев</translation>
</message>
<message>
<source>Trophy</source>
<translation>Trophy</translation>
<translation>Трофеи</translation>
</message>
<message>
<source>Logger</source>
@ -750,7 +750,7 @@
</message>
<message>
<source>Audio Backend</source>
<translation>Звуковая Подсистема</translation>
<translation>Звуковая подсистема</translation>
</message>
<message>
<source>Save</source>
@ -826,7 +826,7 @@
</message>
<message>
<source>disableTrophycheckBox</source>
<translation>Отключить уведомления о трофеях:\nОтключает внутриигровые уведомления о трофеях. Прогресс трофеев по прежнему можно отслеживать в меню Просмотр трофеев (правая кнопка мыши по игре в главном окне).</translation>
<translation>Отключить уведомления о трофеях:\nОтключает внутриигровые уведомления о трофеях. Прогресс трофеев по прежнему можно отслеживать в меню просмотра трофеев (правая кнопка мыши по игре в главном окне).</translation>
</message>
<message>
<source>hideCursorGroupBox</source>
@ -1192,11 +1192,11 @@
</message>
<message>
<source>Play Time</source>
<translation>Времени в игре</translation>
<translation>Время в игре</translation>
</message>
<message>
<source>Never Played</source>
<translation>Вы не играли</translation>
<translation>Нет</translation>
</message>
<message>
<source>h</source>
@ -1361,4 +1361,4 @@
<translation>ТБ</translation>
</message>
</context>
</TS>
</TS>

View File

@ -249,7 +249,7 @@
</message>
<message>
<source>Open shadPS4 Folder</source>
<translation>Open shadPS4 Folder</translation>
<translation>Hap dosjen e shadPS4</translation>
</message>
<message>
<source>Exit</source>
@ -542,7 +542,7 @@
</message>
<message>
<source>Fullscreen Mode</source>
<translation>Modaliteti i Plotë</translation>
<translation>Mënyra me ekran plotë</translation>
</message>
<message>
<source>Enable Separate Update Folder</source>
@ -550,7 +550,7 @@
</message>
<message>
<source>Default tab when opening settings</source>
<translation>Skeda e parazgjedhur kur hapni cilësimet</translation>
<translation>Skeda e parazgjedhur kur hapen cilësimet</translation>
</message>
<message>
<source>Show Game Size In List</source>
@ -594,7 +594,7 @@
</message>
<message>
<source>Open Log Location</source>
<translation>Hap vendndodhjen e regjistrit</translation>
<translation>Hap vendndodhjen e Ditarit</translation>
</message>
<message>
<source>Input</source>
@ -630,11 +630,11 @@
</message>
<message>
<source>Gui</source>
<translation>Ndërfaqe</translation>
<translation>Ndërfaqja</translation>
</message>
<message>
<source>User</source>
<translation>Përdorues</translation>
<translation>Përdoruesi</translation>
</message>
<message>
<source>Graphics Device</source>
@ -822,7 +822,7 @@
</message>
<message>
<source>GUIMusicGroupBox</source>
<translation>Luaj muzikën e titullit:\nNëse një lojë e mbështet, aktivizohet luajtja e muzikës veçantë kur zgjidhësh lojën GUI.</translation>
<translation>Luaj muzikën e titullit:\nNëse një lojë e mbështet, aktivizohet luajtja e muzikës veçantë kur zgjidhësh lojën ndërfaqe.</translation>
</message>
<message>
<source>disableTrophycheckBox</source>

View File

@ -546,7 +546,7 @@
</message>
<message>
<source>Enable Separate Update Folder</source>
<translation>Enable Separate Update Folder</translation>
<translation>Ayrı Güncelleme Klasörünü Etkinleştir</translation>
</message>
<message>
<source>Default tab when opening settings</source>
@ -554,7 +554,7 @@
</message>
<message>
<source>Show Game Size In List</source>
<translation>Göster oyun boyutunu listede</translation>
<translation>Oyun Boyutunu Listede Göster</translation>
</message>
<message>
<source>Show Splash</source>
@ -574,11 +574,11 @@
</message>
<message>
<source>Trophy Key</source>
<translation>Trophy Key</translation>
<translation>Kupa Anahtarı</translation>
</message>
<message>
<source>Trophy</source>
<translation>Trophy</translation>
<translation>Kupa</translation>
</message>
<message>
<source>Logger</source>
@ -722,7 +722,7 @@
</message>
<message>
<source>Disable Trophy Pop-ups</source>
<translation>Disable Trophy Pop-ups</translation>
<translation>Kupa ılır Pencerelerini Devre Dışı Bırak</translation>
</message>
<message>
<source>Play title music</source>
@ -730,23 +730,23 @@
</message>
<message>
<source>Update Compatibility Database On Startup</source>
<translation>Update Compatibility Database On Startup</translation>
<translation>Başlangıçta Uyumluluk Veritabanını Güncelle</translation>
</message>
<message>
<source>Game Compatibility</source>
<translation>Game Compatibility</translation>
<translation>Oyun Uyumluluğu</translation>
</message>
<message>
<source>Display Compatibility Data</source>
<translation>Display Compatibility Data</translation>
<translation>Uyumluluk Verilerini Göster</translation>
</message>
<message>
<source>Update Compatibility Database</source>
<translation>Update Compatibility Database</translation>
<translation>Uyumluluk Veritabanını Güncelle</translation>
</message>
<message>
<source>Volume</source>
<translation>Ses seviyesi</translation>
<translation>Ses Seviyesi</translation>
</message>
<message>
<source>Audio Backend</source>
@ -1105,11 +1105,11 @@
</message>
<message>
<source>The game is in version: %1</source>
<translation>Oyun sürümde: %1</translation>
<translation>Oyun sürümü: %1</translation>
</message>
<message>
<source>The downloaded patch only works on version: %1</source>
<translation>İndirilen yamanın sadece sürümde çalışıyor: %1</translation>
<translation>İndirilen yama sadece şu sürümde çalışıyor: %1</translation>
</message>
<message>
<source>You may need to update your game.</source>
@ -1168,7 +1168,7 @@
</message>
<message>
<source>Compatibility</source>
<translation>Compatibility</translation>
<translation>Uyumluluk</translation>
</message>
<message>
<source>Region</source>
@ -1196,35 +1196,35 @@
</message>
<message>
<source>Never Played</source>
<translation>Never Played</translation>
<translation>Hiç Oynanmadı</translation>
</message>
<message>
<source>h</source>
<translation>h</translation>
<translation>sa</translation>
</message>
<message>
<source>m</source>
<translation>m</translation>
<translation>dk</translation>
</message>
<message>
<source>s</source>
<translation>s</translation>
<translation>sn</translation>
</message>
<message>
<source>Compatibility is untested</source>
<translation>Compatibility is untested</translation>
<translation>Uyumluluk test edilmemiş</translation>
</message>
<message>
<source>Game does not initialize properly / crashes the emulator</source>
<translation>Game does not initialize properly / crashes the emulator</translation>
<translation>Oyun düzgün bir şekilde başlatılamıyor / emülatörü çökertiyor</translation>
</message>
<message>
<source>Game boots, but only displays a blank screen</source>
<translation>Game boots, but only displays a blank screen</translation>
<translation>Oyun başlatılabiliyor ancak yalnızca boş bir ekran gösteriyor</translation>
</message>
<message>
<source>Game displays an image but does not go past the menu</source>
<translation>Game displays an image but does not go past the menu</translation>
<translation>Oyun bir resim gösteriyor ancak menüleri geçemiyor</translation>
</message>
<message>
<source>Game has game-breaking glitches or unplayable performance</source>
@ -1232,7 +1232,7 @@
</message>
<message>
<source>Game can be completed with playable performance and no major glitches</source>
<translation>Game can be completed with playable performance and no major glitches</translation>
<translation>Oyun, oynanabilir performansla tamamlanabilir ve büyük aksaklık yok</translation>
</message>
</context>
<context>
@ -1267,7 +1267,7 @@
</message>
<message>
<source>Your version is already up to date!</source>
<translation>Versiyonunuz zaten güncel!</translation>
<translation>Sürümünüz zaten güncel!</translation>
</message>
<message>
<source>Update Available</source>
@ -1279,11 +1279,11 @@
</message>
<message>
<source>Current Version</source>
<translation>Mevcut Versiyon</translation>
<translation>Mevcut Sürüm</translation>
</message>
<message>
<source>Latest Version</source>
<translation>Son Versiyon</translation>
<translation>Son Sürüm</translation>
</message>
<message>
<source>Do you want to update?</source>
@ -1335,7 +1335,7 @@
</message>
<message>
<source>Failed to create the update script file</source>
<translation>Güncelleme betiği dosyası oluşturulamadı</translation>
<translation>Güncelleme komut dosyası oluşturulamadı</translation>
</message>
</context>
<context>
@ -1361,4 +1361,4 @@
<translation>TB</translation>
</message>
</context>
</TS>
</TS>

View File

@ -58,4 +58,48 @@ Id EmitUnpackHalf2x16(EmitContext& ctx, Id value) {
return ctx.OpUnpackHalf2x16(ctx.F32[2], value);
}
Id EmitPackUnorm2x16(EmitContext& ctx, Id value) {
return ctx.OpPackUnorm2x16(ctx.U32[1], value);
}
Id EmitUnpackUnorm2x16(EmitContext& ctx, Id value) {
return ctx.OpUnpackUnorm2x16(ctx.F32[2], value);
}
Id EmitPackSnorm2x16(EmitContext& ctx, Id value) {
return ctx.OpPackSnorm2x16(ctx.U32[1], value);
}
Id EmitUnpackSnorm2x16(EmitContext& ctx, Id value) {
return ctx.OpUnpackSnorm2x16(ctx.F32[2], value);
}
Id EmitPackUint2x16(EmitContext& ctx, Id value) {
// No SPIR-V instruction for this, do it manually.
const auto x{ctx.OpCompositeExtract(ctx.U32[1], value, 0)};
const auto y{ctx.OpCompositeExtract(ctx.U32[1], value, 1)};
return ctx.OpBitFieldInsert(ctx.U32[1], x, y, ctx.ConstU32(16U), ctx.ConstU32(16U));
}
Id EmitUnpackUint2x16(EmitContext& ctx, Id value) {
// No SPIR-V instruction for this, do it manually.
const auto x{ctx.OpBitFieldUExtract(ctx.U32[1], value, ctx.ConstU32(0U), ctx.ConstU32(16U))};
const auto y{ctx.OpBitFieldUExtract(ctx.U32[1], value, ctx.ConstU32(16U), ctx.ConstU32(16U))};
return ctx.OpCompositeConstruct(ctx.U32[2], x, y);
}
Id EmitPackSint2x16(EmitContext& ctx, Id value) {
// No SPIR-V instruction for this, do it manually.
const auto x{ctx.OpCompositeExtract(ctx.U32[1], value, 0)};
const auto y{ctx.OpCompositeExtract(ctx.U32[1], value, 1)};
return ctx.OpBitFieldInsert(ctx.U32[1], x, y, ctx.ConstU32(16U), ctx.ConstU32(16U));
}
Id EmitUnpackSint2x16(EmitContext& ctx, Id value) {
// No SPIR-V instruction for this, do it manually.
const auto x{ctx.OpBitFieldSExtract(ctx.U32[1], value, ctx.ConstU32(0U), ctx.ConstU32(16U))};
const auto y{ctx.OpBitFieldSExtract(ctx.U32[1], value, ctx.ConstU32(16U), ctx.ConstU32(16U))};
return ctx.OpCompositeConstruct(ctx.U32[2], x, y);
}
} // namespace Shader::Backend::SPIRV

View File

@ -197,6 +197,14 @@ Id EmitPackFloat2x16(EmitContext& ctx, Id value);
Id EmitUnpackFloat2x16(EmitContext& ctx, Id value);
Id EmitPackHalf2x16(EmitContext& ctx, Id value);
Id EmitUnpackHalf2x16(EmitContext& ctx, Id value);
Id EmitPackUnorm2x16(EmitContext& ctx, Id value);
Id EmitUnpackUnorm2x16(EmitContext& ctx, Id value);
Id EmitPackSnorm2x16(EmitContext& ctx, Id value);
Id EmitUnpackSnorm2x16(EmitContext& ctx, Id value);
Id EmitPackUint2x16(EmitContext& ctx, Id value);
Id EmitUnpackUint2x16(EmitContext& ctx, Id value);
Id EmitPackSint2x16(EmitContext& ctx, Id value);
Id EmitUnpackSint2x16(EmitContext& ctx, Id value);
Id EmitFPAbs16(EmitContext& ctx, Id value);
Id EmitFPAbs32(EmitContext& ctx, Id value);
Id EmitFPAbs64(EmitContext& ctx, Id value);

View File

@ -7,6 +7,125 @@
namespace Shader::Gcn {
u32 SwizzleMrtComponent(const FragmentRuntimeInfo::PsColorBuffer& color_buffer, u32 comp) {
const auto [r, g, b, a] = color_buffer.swizzle;
const std::array swizzle_array = {r, g, b, a};
const auto swizzled_comp_type = static_cast<u32>(swizzle_array[comp]);
constexpr auto min_comp_type = static_cast<u32>(AmdGpu::CompSwizzle::Red);
return swizzled_comp_type >= min_comp_type ? swizzled_comp_type - min_comp_type : comp;
}
void Translator::ExportMrtValue(IR::Attribute attribute, u32 comp, const IR::F32& value,
const FragmentRuntimeInfo::PsColorBuffer& color_buffer) {
const auto converted = ApplyWriteNumberConversion(ir, value, color_buffer.num_conversion);
ir.SetAttribute(attribute, converted, comp);
}
void Translator::ExportMrtCompressed(IR::Attribute attribute, u32 idx, const IR::U32& value) {
const u32 color_buffer_idx =
static_cast<u32>(attribute) - static_cast<u32>(IR::Attribute::RenderTarget0);
const auto color_buffer = runtime_info.fs_info.color_buffers[color_buffer_idx];
IR::Value unpacked_value;
bool is_integer = false;
switch (color_buffer.export_format) {
case AmdGpu::Liverpool::ShaderExportFormat::Zero:
// No export
return;
case AmdGpu::Liverpool::ShaderExportFormat::ABGR_FP16:
unpacked_value = ir.UnpackHalf2x16(value);
break;
case AmdGpu::Liverpool::ShaderExportFormat::ABGR_UNORM16:
unpacked_value = ir.UnpackUnorm2x16(value);
break;
case AmdGpu::Liverpool::ShaderExportFormat::ABGR_SNORM16:
unpacked_value = ir.UnpackSnorm2x16(value);
break;
case AmdGpu::Liverpool::ShaderExportFormat::ABGR_UINT16:
unpacked_value = ir.UnpackUint2x16(value);
is_integer = true;
break;
case AmdGpu::Liverpool::ShaderExportFormat::ABGR_SINT16:
unpacked_value = ir.UnpackSint2x16(value);
is_integer = true;
break;
default:
UNREACHABLE_MSG("Unimplemented compressed MRT export format {}",
static_cast<u32>(color_buffer.export_format));
break;
}
const auto r = ir.CompositeExtract(unpacked_value, 0);
const auto g = ir.CompositeExtract(unpacked_value, 1);
const IR::F32 float_r = is_integer ? ir.BitCast<IR::F32>(IR::U32{r}) : IR::F32{r};
const IR::F32 float_g = is_integer ? ir.BitCast<IR::F32>(IR::U32{g}) : IR::F32{g};
const auto swizzled_r = SwizzleMrtComponent(color_buffer, idx * 2);
const auto swizzled_g = SwizzleMrtComponent(color_buffer, idx * 2 + 1);
ExportMrtValue(attribute, swizzled_r, float_r, color_buffer);
ExportMrtValue(attribute, swizzled_g, float_g, color_buffer);
}
void Translator::ExportMrtUncompressed(IR::Attribute attribute, u32 comp, const IR::F32& value) {
const u32 color_buffer_idx =
static_cast<u32>(attribute) - static_cast<u32>(IR::Attribute::RenderTarget0);
const auto color_buffer = runtime_info.fs_info.color_buffers[color_buffer_idx];
const auto swizzled_comp = SwizzleMrtComponent(color_buffer, comp);
switch (color_buffer.export_format) {
case AmdGpu::Liverpool::ShaderExportFormat::Zero:
// No export
return;
case AmdGpu::Liverpool::ShaderExportFormat::R_32:
// Red only
if (swizzled_comp != 0) {
return;
}
break;
case AmdGpu::Liverpool::ShaderExportFormat::GR_32:
// Red and Green only
if (swizzled_comp != 0 && swizzled_comp != 1) {
return;
}
break;
case AmdGpu::Liverpool::ShaderExportFormat::AR_32:
// Red and Alpha only
if (swizzled_comp != 0 && swizzled_comp != 3) {
return;
}
break;
case AmdGpu::Liverpool::ShaderExportFormat::ABGR_32:
// All components
break;
default:
UNREACHABLE_MSG("Unimplemented uncompressed MRT export format {}",
static_cast<u32>(color_buffer.export_format));
break;
}
ExportMrtValue(attribute, swizzled_comp, value, color_buffer);
}
void Translator::ExportCompressed(IR::Attribute attribute, u32 idx, const IR::U32& value) {
if (IsMrt(attribute)) {
ExportMrtCompressed(attribute, idx, value);
return;
}
const IR::Value unpacked_value = ir.UnpackHalf2x16(value);
const IR::F32 r = IR::F32{ir.CompositeExtract(unpacked_value, 0)};
const IR::F32 g = IR::F32{ir.CompositeExtract(unpacked_value, 1)};
ir.SetAttribute(attribute, r, idx * 2);
ir.SetAttribute(attribute, g, idx * 2 + 1);
}
void Translator::ExportUncompressed(IR::Attribute attribute, u32 comp, const IR::F32& value) {
if (IsMrt(attribute)) {
ExportMrtUncompressed(attribute, comp, value);
return;
}
ir.SetAttribute(attribute, value, comp);
}
void Translator::EmitExport(const GcnInst& inst) {
if (ir.block->has_multiple_predecessors && info.stage == Stage::Fragment) {
ir.Discard(ir.LogicalNot(ir.GetExec()));
@ -26,41 +145,15 @@ void Translator::EmitExport(const GcnInst& inst) {
IR::VectorReg(inst.src[3].code),
};
const auto set_attribute = [&](u32 comp, IR::F32 value) {
if (!IR::IsMrt(attrib)) {
ir.SetAttribute(attrib, value, comp);
return;
}
const u32 index = u32(attrib) - u32(IR::Attribute::RenderTarget0);
const auto col_buf = runtime_info.fs_info.color_buffers[index];
const auto converted = IR::ApplyWriteNumberConversion(ir, value, col_buf.num_conversion);
const auto [r, g, b, a] = col_buf.swizzle;
const std::array swizzle_array = {r, g, b, a};
const auto swizzled_comp = swizzle_array[comp];
if (u32(swizzled_comp) < u32(AmdGpu::CompSwizzle::Red)) {
ir.SetAttribute(attrib, converted, comp);
return;
}
ir.SetAttribute(attrib, converted, u32(swizzled_comp) - u32(AmdGpu::CompSwizzle::Red));
};
const auto unpack = [&](u32 idx) {
const IR::Value value = ir.UnpackHalf2x16(ir.GetVectorReg(vsrc[idx]));
const IR::F32 r = IR::F32{ir.CompositeExtract(value, 0)};
const IR::F32 g = IR::F32{ir.CompositeExtract(value, 1)};
set_attribute(idx * 2, r);
set_attribute(idx * 2 + 1, g);
};
// Components are float16 packed into a VGPR
if (exp.compr) {
// Export R, G
if (exp.en & 1) {
unpack(0);
ExportCompressed(attrib, 0, ir.GetVectorReg<IR::U32>(vsrc[0]));
}
// Export B, A
if ((exp.en >> 2) & 1) {
unpack(1);
ExportCompressed(attrib, 1, ir.GetVectorReg<IR::U32>(vsrc[1]));
}
} else {
// Components are float32 into separate VGPRS
@ -69,8 +162,7 @@ void Translator::EmitExport(const GcnInst& inst) {
if ((mask & 1) == 0) {
continue;
}
const IR::F32 comp = ir.GetVectorReg<IR::F32>(vsrc[i]);
set_attribute(i, comp);
ExportUncompressed(attrib, i, ir.GetVectorReg<IR::F32>(vsrc[i]));
}
}
if (IR::IsMrt(attrib)) {

View File

@ -170,6 +170,7 @@ public:
void V_SUBBREV_U32(const GcnInst& inst);
void V_LDEXP_F32(const GcnInst& inst);
void V_CVT_PKNORM_U16_F32(const GcnInst& inst);
void V_CVT_PKNORM_I16_F32(const GcnInst& inst);
void V_CVT_PKRTZ_F16_F32(const GcnInst& inst);
// VOP1
@ -244,6 +245,7 @@ public:
void V_SAD(const GcnInst& inst);
void V_SAD_U32(const GcnInst& inst);
void V_CVT_PK_U16_U32(const GcnInst& inst);
void V_CVT_PK_I16_I32(const GcnInst& inst);
void V_CVT_PK_U8_F32(const GcnInst& inst);
void V_LSHL_B64(const GcnInst& inst);
void V_MUL_F64(const GcnInst& inst);
@ -306,6 +308,13 @@ private:
IR::F32 SelectCubeResult(const IR::F32& x, const IR::F32& y, const IR::F32& z,
const IR::F32& x_res, const IR::F32& y_res, const IR::F32& z_res);
void ExportMrtValue(IR::Attribute attribute, u32 comp, const IR::F32& value,
const FragmentRuntimeInfo::PsColorBuffer& color_buffer);
void ExportMrtCompressed(IR::Attribute attribute, u32 idx, const IR::U32& value);
void ExportMrtUncompressed(IR::Attribute attribute, u32 comp, const IR::F32& value);
void ExportCompressed(IR::Attribute attribute, u32 idx, const IR::U32& value);
void ExportUncompressed(IR::Attribute attribute, u32 comp, const IR::F32& value);
void LogMissingOpcode(const GcnInst& inst);
private:

View File

@ -96,6 +96,8 @@ void Translator::EmitVectorAlu(const GcnInst& inst) {
return V_LDEXP_F32(inst);
case Opcode::V_CVT_PKNORM_U16_F32:
return V_CVT_PKNORM_U16_F32(inst);
case Opcode::V_CVT_PKNORM_I16_F32:
return V_CVT_PKNORM_I16_F32(inst);
case Opcode::V_CVT_PKRTZ_F16_F32:
return V_CVT_PKRTZ_F16_F32(inst);
@ -376,6 +378,8 @@ void Translator::EmitVectorAlu(const GcnInst& 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_I16_I32:
return V_CVT_PK_I16_I32(inst);
case Opcode::V_CVT_PK_U8_F32:
return V_CVT_PK_U8_F32(inst);
case Opcode::V_LSHL_B64:
@ -645,12 +649,15 @@ void Translator::V_LDEXP_F32(const GcnInst& inst) {
}
void Translator::V_CVT_PKNORM_U16_F32(const GcnInst& inst) {
const IR::F32 src0{GetSrc<IR::F32>(inst.src[0])};
const IR::F32 src1{GetSrc<IR::F32>(inst.src[1])};
const IR::U32 dst0 = ir.ConvertFToU(32, ir.FPMul(src0, ir.Imm32(65535.f)));
const IR::U32 dst1 = ir.ConvertFToU(32, ir.FPMul(src1, ir.Imm32(65535.f)));
const IR::VectorReg dst_reg{inst.dst[0].code};
ir.SetVectorReg(dst_reg, ir.BitFieldInsert(dst0, dst1, ir.Imm32(16), ir.Imm32(16)));
const IR::Value vec_f32 =
ir.CompositeConstruct(GetSrc<IR::F32>(inst.src[0]), GetSrc<IR::F32>(inst.src[1]));
SetDst(inst.dst[0], ir.PackUnorm2x16(vec_f32));
}
void Translator::V_CVT_PKNORM_I16_F32(const GcnInst& inst) {
const IR::Value vec_f32 =
ir.CompositeConstruct(GetSrc<IR::F32>(inst.src[0]), GetSrc<IR::F32>(inst.src[1]));
SetDst(inst.dst[0], ir.PackSnorm2x16(vec_f32));
}
void Translator::V_CVT_PKRTZ_F16_F32(const GcnInst& inst) {
@ -1237,11 +1244,15 @@ void Translator::V_SAD_U32(const GcnInst& inst) {
}
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)));
const IR::Value vec_u32 =
ir.CompositeConstruct(GetSrc<IR::U32>(inst.src[0]), GetSrc<IR::U32>(inst.src[1]));
SetDst(inst.dst[0], ir.PackUint2x16(vec_u32));
}
void Translator::V_CVT_PK_I16_I32(const GcnInst& inst) {
const IR::Value vec_u32 =
ir.CompositeConstruct(GetSrc<IR::U32>(inst.src[0]), GetSrc<IR::U32>(inst.src[1]));
SetDst(inst.dst[0], ir.PackSint2x16(vec_u32));
}
void Translator::V_CVT_PK_U8_F32(const GcnInst& inst) {

View File

@ -795,6 +795,38 @@ Value IREmitter::UnpackHalf2x16(const U32& value) {
return Inst(Opcode::UnpackHalf2x16, value);
}
U32 IREmitter::PackUnorm2x16(const Value& vector) {
return Inst<U32>(Opcode::PackUnorm2x16, vector);
}
Value IREmitter::UnpackUnorm2x16(const U32& value) {
return Inst(Opcode::UnpackUnorm2x16, value);
}
U32 IREmitter::PackSnorm2x16(const Value& vector) {
return Inst<U32>(Opcode::PackSnorm2x16, vector);
}
Value IREmitter::UnpackSnorm2x16(const U32& value) {
return Inst(Opcode::UnpackSnorm2x16, value);
}
U32 IREmitter::PackUint2x16(const Value& value) {
return Inst<U32>(Opcode::PackUint2x16, value);
}
Value IREmitter::UnpackUint2x16(const U32& value) {
return Inst(Opcode::UnpackUint2x16, value);
}
U32 IREmitter::PackSint2x16(const Value& value) {
return Inst<U32>(Opcode::PackSint2x16, value);
}
Value IREmitter::UnpackSint2x16(const U32& value) {
return Inst(Opcode::UnpackSint2x16, value);
}
F32F64 IREmitter::FPMul(const F32F64& a, const F32F64& b) {
if (a.Type() != b.Type()) {
UNREACHABLE_MSG("Mismatching types {} and {}", a.Type(), b.Type());

View File

@ -175,6 +175,14 @@ public:
[[nodiscard]] U32 PackHalf2x16(const Value& vector);
[[nodiscard]] Value UnpackHalf2x16(const U32& value);
[[nodiscard]] U32 PackUnorm2x16(const Value& vector);
[[nodiscard]] Value UnpackUnorm2x16(const U32& value);
[[nodiscard]] U32 PackSnorm2x16(const Value& vector);
[[nodiscard]] Value UnpackSnorm2x16(const U32& value);
[[nodiscard]] U32 PackUint2x16(const Value& value);
[[nodiscard]] Value UnpackUint2x16(const U32& value);
[[nodiscard]] U32 PackSint2x16(const Value& value);
[[nodiscard]] Value UnpackSint2x16(const U32& value);
[[nodiscard]] F32F64 FPAdd(const F32F64& a, const F32F64& b);
[[nodiscard]] F32F64 FPSub(const F32F64& a, const F32F64& b);

View File

@ -187,6 +187,14 @@ OPCODE(PackFloat2x16, U32, F16x
OPCODE(UnpackFloat2x16, F16x2, U32, )
OPCODE(PackHalf2x16, U32, F32x2, )
OPCODE(UnpackHalf2x16, F32x2, U32, )
OPCODE(PackUnorm2x16, U32, F32x2, )
OPCODE(UnpackUnorm2x16, F32x2, U32, )
OPCODE(PackSnorm2x16, U32, F32x2, )
OPCODE(UnpackSnorm2x16, F32x2, U32, )
OPCODE(PackUint2x16, U32, U32x2, )
OPCODE(UnpackUint2x16, U32x2, U32, )
OPCODE(PackSint2x16, U32, U32x2, )
OPCODE(UnpackSint2x16, U32x2, U32, )
// Floating-point operations
OPCODE(FPAbs32, F32, F32, )

View File

@ -348,6 +348,22 @@ void ConstantPropagation(IR::Block& block, IR::Inst& inst) {
return FoldInverseFunc(inst, IR::Opcode::UnpackFloat2x16);
case IR::Opcode::UnpackFloat2x16:
return FoldInverseFunc(inst, IR::Opcode::PackFloat2x16);
case IR::Opcode::PackUnorm2x16:
return FoldInverseFunc(inst, IR::Opcode::UnpackUnorm2x16);
case IR::Opcode::UnpackUnorm2x16:
return FoldInverseFunc(inst, IR::Opcode::PackUnorm2x16);
case IR::Opcode::PackSnorm2x16:
return FoldInverseFunc(inst, IR::Opcode::UnpackSnorm2x16);
case IR::Opcode::UnpackSnorm2x16:
return FoldInverseFunc(inst, IR::Opcode::PackSnorm2x16);
case IR::Opcode::PackUint2x16:
return FoldInverseFunc(inst, IR::Opcode::UnpackUint2x16);
case IR::Opcode::UnpackUint2x16:
return FoldInverseFunc(inst, IR::Opcode::PackUint2x16);
case IR::Opcode::PackSint2x16:
return FoldInverseFunc(inst, IR::Opcode::UnpackSint2x16);
case IR::Opcode::UnpackSint2x16:
return FoldInverseFunc(inst, IR::Opcode::PackSint2x16);
case IR::Opcode::SelectU1:
case IR::Opcode::SelectU8:
case IR::Opcode::SelectU16:

View File

@ -569,7 +569,7 @@ void PatchTextureBufferArgs(IR::Block& block, IR::Inst& inst, Info& info) {
inst.SetArg(1, CalculateBufferAddress(ir, inst, info, buffer, 1U));
if (inst.GetOpcode() == IR::Opcode::StoreBufferFormatF32) {
const auto swizzled = ApplySwizzle(ir, inst.Arg(2), buffer.DstSelect());
const auto swizzled = ApplySwizzle(ir, inst.Arg(2), buffer.DstSelect().Inverse());
const auto converted =
ApplyWriteNumberConversionVec4(ir, swizzled, buffer.GetNumberConversion());
inst.SetArg(2, converted);
@ -829,7 +829,7 @@ void PatchImageArgs(IR::Block& block, IR::Inst& inst, Info& info) {
auto texel = inst.Arg(4);
if (is_storage) {
// Storage image requires shader swizzle.
texel = ApplySwizzle(ir, texel, image.DstSelect());
texel = ApplySwizzle(ir, texel, image.DstSelect().Inverse());
}
const auto converted =
ApplyWriteNumberConversionVec4(ir, texel, image.GetNumberConversion());

View File

@ -90,6 +90,7 @@ IR::Program TranslateProgram(std::span<const u32> code, Pools& pools, Info& info
Shader::Optimization::ResourceTrackingPass(program);
Shader::Optimization::IdentityRemovalPass(program.blocks);
Shader::Optimization::DeadCodeEliminationPass(program);
Shader::Optimization::ConstantPropagationPass(program.post_order_blocks);
Shader::Optimization::CollectShaderInfoPass(program);
Shader::Optimization::SharedMemoryBarrierPass(program, profile);

View File

@ -184,6 +184,7 @@ struct FragmentRuntimeInfo {
AmdGpu::NumberFormat num_format;
AmdGpu::NumberConversion num_conversion;
AmdGpu::CompMapping swizzle;
AmdGpu::Liverpool::ShaderExportFormat export_format;
auto operator<=>(const PsColorBuffer&) const noexcept = default;
};

View File

@ -636,6 +636,18 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
}
break;
}
case PM4ItOpcode::MemSemaphore: {
const auto* mem_semaphore = reinterpret_cast<const PM4CmdMemSemaphore*>(header);
if (mem_semaphore->IsSignaling()) {
mem_semaphore->Signal();
} else {
while (!mem_semaphore->Signaled()) {
YIELD_GFX();
}
mem_semaphore->Decrement();
}
break;
}
case PM4ItOpcode::AcquireMem: {
// const auto* acquire_mem = reinterpret_cast<PM4CmdAcquireMem*>(header);
break;
@ -848,6 +860,18 @@ Liverpool::Task Liverpool::ProcessCompute(std::span<const u32> acb, u32 vqid) {
}
break;
}
case PM4ItOpcode::MemSemaphore: {
const auto* mem_semaphore = reinterpret_cast<const PM4CmdMemSemaphore*>(header);
if (mem_semaphore->IsSignaling()) {
mem_semaphore->Signal();
} else {
while (!mem_semaphore->Signaled()) {
YIELD_ASC(vqid);
}
mem_semaphore->Decrement();
}
break;
}
case PM4ItOpcode::WaitRegMem: {
const auto* wait_reg_mem = reinterpret_cast<const PM4CmdWaitRegMem*>(header);
ASSERT(wait_reg_mem->engine.Value() == PM4CmdWaitRegMem::Engine::Me);

View File

@ -266,6 +266,10 @@ struct Liverpool {
BitField<20, 4, ShaderExportFormat> col5;
BitField<24, 4, ShaderExportFormat> col6;
BitField<28, 4, ShaderExportFormat> col7;
[[nodiscard]] ShaderExportFormat GetFormat(const u32 buf_idx) const {
return static_cast<ShaderExportFormat>((raw >> (buf_idx * 4)) & 0xfu);
}
};
union VsOutputControl {

View File

@ -884,4 +884,65 @@ struct PM4CmdDrawIndexIndirectMulti {
u32 draw_initiator; ///< Draw Initiator Register
};
struct PM4CmdMemSemaphore {
enum class ClientCode : u32 {
CommandProcessor = 0u,
CommandBuffer = 1u,
DataBuffer = 2u,
};
enum class Select : u32 {
SignalSemaphore = 6u,
WaitSemaphore = 7u,
};
enum class SignalType : u32 {
Increment = 0u,
Write = 1u,
};
PM4Type3Header header; ///< header
union {
u32 dw1;
BitField<3, 29, u32> addr_lo; ///< Semaphore address bits [31:3]
};
union {
u32 dw2;
BitField<0, 8, u32> addr_hi; ///< Semaphore address bits [39:32]
BitField<16, 1, u32> use_mailbox; ///< Enables waiting until mailbox is written to
BitField<20, 1, SignalType> signal_type; ///< Indicates the type of signal sent
BitField<24, 2, ClientCode> client_code;
BitField<29, 3, Select> sem_sel; ///< Indicates whether to do a signal or wait operation
};
template <typename T>
[[nodiscard]] T Address() const {
return std::bit_cast<T>(u64(addr_lo) << 3 | (u64(addr_hi) << 32));
}
[[nodiscard]] bool IsSignaling() const {
return sem_sel == Select::SignalSemaphore;
}
[[nodiscard]] bool Signaled() const {
return *Address<u64*>() > 0;
}
void Decrement() const {
*Address<u64*>() -= 1;
}
void Signal() const {
auto* ptr = Address<u64*>();
switch (signal_type) {
case SignalType::Increment:
*ptr += 1;
break;
case SignalType::Write:
*ptr = 1;
break;
default:
UNREACHABLE_MSG("Unknown signal type {}", static_cast<u32>(signal_type.Value()));
}
}
};
} // namespace AmdGpu

View File

@ -200,10 +200,10 @@ enum class NumberConversion : u32 {
};
struct CompMapping {
CompSwizzle r : 3;
CompSwizzle g : 3;
CompSwizzle b : 3;
CompSwizzle a : 3;
CompSwizzle r;
CompSwizzle g;
CompSwizzle b;
CompSwizzle a;
auto operator<=>(const CompMapping& other) const = default;
@ -217,6 +217,15 @@ struct CompMapping {
};
}
[[nodiscard]] CompMapping Inverse() const {
CompMapping result{};
InverseSingle(result.r, CompSwizzle::Red);
InverseSingle(result.g, CompSwizzle::Green);
InverseSingle(result.b, CompSwizzle::Blue);
InverseSingle(result.a, CompSwizzle::Alpha);
return result;
}
private:
template <typename T>
T ApplySingle(const std::array<T, 4>& data, const CompSwizzle swizzle) const {
@ -237,6 +246,20 @@ private:
UNREACHABLE();
}
}
void InverseSingle(CompSwizzle& dst, const CompSwizzle target) const {
if (r == target) {
dst = CompSwizzle::Red;
} else if (g == target) {
dst = CompSwizzle::Green;
} else if (b == target) {
dst = CompSwizzle::Blue;
} else if (a == target) {
dst = CompSwizzle::Alpha;
} else {
dst = CompSwizzle::Zero;
}
}
};
inline DataFormat RemapDataFormat(const DataFormat format) {

View File

@ -35,9 +35,8 @@ struct GraphicsPipelineKey {
std::array<size_t, MaxShaderStages> stage_hashes;
u32 num_color_attachments;
std::array<vk::Format, Liverpool::NumColorBuffers> color_formats;
std::array<AmdGpu::NumberFormat, Liverpool::NumColorBuffers> color_num_formats;
std::array<AmdGpu::NumberConversion, Liverpool::NumColorBuffers> color_num_conversions;
std::array<AmdGpu::CompMapping, Liverpool::NumColorBuffers> color_swizzles;
std::array<Shader::FragmentRuntimeInfo::PsColorBuffer, Liverpool::NumColorBuffers>
color_buffers;
vk::Format depth_format;
vk::Format stencil_format;

View File

@ -167,11 +167,7 @@ const Shader::RuntimeInfo& PipelineCache::BuildRuntimeInfo(Stage stage, LogicalS
};
}
for (u32 i = 0; i < Shader::MaxColorBuffers; i++) {
info.fs_info.color_buffers[i] = {
.num_format = graphics_key.color_num_formats[i],
.num_conversion = graphics_key.color_num_conversions[i],
.swizzle = graphics_key.color_swizzles[i],
};
info.fs_info.color_buffers[i] = graphics_key.color_buffers[i];
}
break;
}
@ -309,11 +305,9 @@ bool PipelineCache::RefreshGraphicsKey() {
// order. We need to do some arrays compaction at this stage
key.num_color_attachments = 0;
key.color_formats.fill(vk::Format::eUndefined);
key.color_num_formats.fill(AmdGpu::NumberFormat::Unorm);
key.color_num_conversions.fill(AmdGpu::NumberConversion::None);
key.color_buffers.fill({});
key.blend_controls.fill({});
key.write_masks.fill({});
key.color_swizzles.fill({});
key.vertex_buffer_formats.fill(vk::Format::eUndefined);
key.patch_control_points = 0;
@ -338,9 +332,12 @@ bool PipelineCache::RefreshGraphicsKey() {
key.color_formats[remapped_cb] =
LiverpoolToVK::SurfaceFormat(col_buf.GetDataFmt(), col_buf.GetNumberFmt());
key.color_num_formats[remapped_cb] = col_buf.GetNumberFmt();
key.color_num_conversions[remapped_cb] = col_buf.GetNumberConversion();
key.color_swizzles[remapped_cb] = col_buf.Swizzle();
key.color_buffers[remapped_cb] = {
.num_format = col_buf.GetNumberFmt(),
.num_conversion = col_buf.GetNumberConversion(),
.swizzle = col_buf.Swizzle(),
.export_format = regs.color_export_format.GetFormat(cb),
};
}
fetch_shader = std::nullopt;
@ -456,7 +453,7 @@ bool PipelineCache::RefreshGraphicsKey() {
// of the latter we need to change format to undefined, and either way we need to
// increment the index for the null attachment binding.
key.color_formats[remapped_cb] = vk::Format::eUndefined;
key.color_swizzles[remapped_cb] = {};
key.color_buffers[remapped_cb] = {};
++remapped_cb;
continue;
}

View File

@ -1155,10 +1155,7 @@ void Rasterizer::UpdateViewportScissorState(const GraphicsPipeline& pipeline) {
const auto& vp_ctl = regs.viewport_control;
const float reduce_z =
instance.IsDepthClipControlSupported() &&
regs.clipper_control.clip_space == AmdGpu::Liverpool::ClipSpace::MinusWToW
? 1.0f
: 0.0f;
regs.clipper_control.clip_space == AmdGpu::Liverpool::ClipSpace::MinusWToW ? 1.0f : 0.0f;
if (regs.polygon_control.enable_window_offset) {
LOG_ERROR(Render_Vulkan,
@ -1172,6 +1169,8 @@ void Rasterizer::UpdateViewportScissorState(const GraphicsPipeline& pipeline) {
continue;
}
const auto zoffset = vp_ctl.zoffset_enable ? vp.zoffset : 0.f;
const auto zscale = vp_ctl.zscale_enable ? vp.zscale : 1.f;
if (pipeline.IsClipDisabled()) {
// In case if clipping is disabled we patch the shader to convert vertex position
// from screen space coordinates to NDC by defining a render space as full hardware
@ -1181,16 +1180,14 @@ void Rasterizer::UpdateViewportScissorState(const GraphicsPipeline& pipeline) {
.y = 0.f,
.width = float(std::min<u32>(instance.GetMaxViewportWidth(), 16_KB)),
.height = float(std::min<u32>(instance.GetMaxViewportHeight(), 16_KB)),
.minDepth = 0.0,
.maxDepth = 1.0,
.minDepth = zoffset - zscale * reduce_z,
.maxDepth = zscale + zoffset,
});
} else {
const auto xoffset = vp_ctl.xoffset_enable ? vp.xoffset : 0.f;
const auto xscale = vp_ctl.xscale_enable ? vp.xscale : 1.f;
const auto yoffset = vp_ctl.yoffset_enable ? vp.yoffset : 0.f;
const auto yscale = vp_ctl.yscale_enable ? vp.yscale : 1.f;
const auto zoffset = vp_ctl.zoffset_enable ? vp.zoffset : 0.f;
const auto zscale = vp_ctl.zscale_enable ? vp.zscale : 1.f;
viewports.push_back({
.x = xoffset - xscale,
.y = yoffset - yscale,