From 4f426b723f2f015af022e2f9c48813448c264d7b Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Fri, 24 Jan 2025 14:30:55 +0100 Subject: [PATCH 01/29] Rebase of "Handle munmap over multiple VMAs" (#2233) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Unmap memory in chunks if spanning over multiple VMAs * clang * Merge fixups * Minor code style changes * Update function declarations --------- Co-authored-by: Marcin Mikołajczyk --- src/core/memory.cpp | 49 +++++++++++++++++++++++++++++---------------- src/core/memory.h | 4 +++- 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/src/core/memory.cpp b/src/core/memory.cpp index f90d4e6aa..a8dd72acc 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -389,32 +389,29 @@ 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; @@ -423,13 +420,25 @@ s32 MemoryManager::UnmapMemoryImpl(VAddr virtual_addr, size_t size) { vma.name = ""; MergeAdjacent(vma_map, new_it); bool readonly_file = 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 +660,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) { diff --git a/src/core/memory.h b/src/core/memory.h index 615ecc3eb..59e48b248 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -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; From a4eba8e827c062b5e6874255ff810346943d0ea2 Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Fri, 24 Jan 2025 19:22:06 +0200 Subject: [PATCH 02/29] stubbed webbrowserdialog,npparty (#2234) * stubbed webbrowserdialog,npparty * added poly's suggestions --- CMakeLists.txt | 4 + src/common/logging/filter.cpp | 2 + src/common/logging/types.h | 2 + src/core/libraries/libs.cpp | 4 + src/core/libraries/np_party/np_party.cpp | 195 ++++++++++++++++++ src/core/libraries/np_party/np_party.h | 44 ++++ .../web_browser_dialog/webbrowserdialog.cpp | 112 ++++++++++ .../web_browser_dialog/webbrowserdialog.h | 30 +++ 8 files changed, 393 insertions(+) create mode 100644 src/core/libraries/np_party/np_party.cpp create mode 100644 src/core/libraries/np_party/np_party.h create mode 100644 src/core/libraries/web_browser_dialog/webbrowserdialog.cpp create mode 100644 src/core/libraries/web_browser_dialog/webbrowserdialog.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 3db142be7..4c9dad307 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -344,6 +344,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 @@ -434,6 +436,8 @@ 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(MISC_LIBS src/core/libraries/screenshot/screenshot.cpp diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp index 168d03948..f1d3a9499 100644 --- a/src/common/logging/filter.cpp +++ b/src/common/logging/filter.cpp @@ -131,6 +131,8 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) { SUB(Lib, Videodec) \ SUB(Lib, RazorCpu) \ SUB(Lib, Mouse) \ + SUB(Lib, WebBrowserDialog) \ + SUB(Lib, NpParty) \ CLS(Frontend) \ CLS(Render) \ SUB(Render, Vulkan) \ diff --git a/src/common/logging/types.h b/src/common/logging/types.h index 4ca88e1be..d5530312c 100644 --- a/src/common/logging/types.h +++ b/src/common/logging/types.h @@ -98,6 +98,8 @@ 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 Frontend, ///< Emulator UI Render, ///< Video Core Render_Vulkan, ///< Vulkan backend diff --git a/src/core/libraries/libs.cpp b/src/core/libraries/libs.cpp index 6dc455028..e09de1cee 100644 --- a/src/core/libraries/libs.cpp +++ b/src/core/libraries/libs.cpp @@ -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,7 @@ #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 "fiber/fiber.h" #include "jpeg/jpegenc.h" @@ -107,6 +109,8 @@ 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); } } // namespace Libraries diff --git a/src/core/libraries/np_party/np_party.cpp b/src/core/libraries/np_party/np_party.cpp new file mode 100644 index 000000000..8a66ccb22 --- /dev/null +++ b/src/core/libraries/np_party/np_party.cpp @@ -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 \ No newline at end of file diff --git a/src/core/libraries/np_party/np_party.h b/src/core/libraries/np_party/np_party.h new file mode 100644 index 000000000..d5f20e4f8 --- /dev/null +++ b/src/core/libraries/np_party/np_party.h @@ -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 \ No newline at end of file diff --git a/src/core/libraries/web_browser_dialog/webbrowserdialog.cpp b/src/core/libraries/web_browser_dialog/webbrowserdialog.cpp new file mode 100644 index 000000000..ee434f96a --- /dev/null +++ b/src/core/libraries/web_browser_dialog/webbrowserdialog.cpp @@ -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 \ No newline at end of file diff --git a/src/core/libraries/web_browser_dialog/webbrowserdialog.h b/src/core/libraries/web_browser_dialog/webbrowserdialog.h new file mode 100644 index 000000000..aa118fe45 --- /dev/null +++ b/src/core/libraries/web_browser_dialog/webbrowserdialog.h @@ -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 \ No newline at end of file From b3c573f7989ffe3cc0fe15ce69f620bcaab9c61b Mon Sep 17 00:00:00 2001 From: poly <47796739+polybiusproxy@users.noreply.github.com> Date: Fri, 24 Jan 2025 19:37:34 +0100 Subject: [PATCH 03/29] libraries/fiber: print fiber ctx size on stack overflow --- src/core/libraries/fiber/fiber.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/libraries/fiber/fiber.cpp b/src/core/libraries/fiber/fiber.cpp index b77b5b5b6..345f0834d 100644 --- a/src/core/libraries/fiber/fiber.cpp +++ b/src/core/libraries/fiber/fiber.cpp @@ -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(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); } } From 56f4b8a2b860fa14421b0e6884532b441ea34a12 Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Fri, 24 Jan 2025 10:41:58 -0800 Subject: [PATCH 04/29] shader_recompiler: Implement shader export formats. (#2226) --- externals/sirit | 2 +- .../spirv/emit_spirv_bitwise_conversion.cpp | 44 +++++ .../backend/spirv/emit_spirv_instructions.h | 8 + .../frontend/translate/export.cpp | 152 ++++++++++++++---- .../frontend/translate/translate.h | 9 ++ .../frontend/translate/vector_alu.cpp | 33 ++-- src/shader_recompiler/ir/ir_emitter.cpp | 32 ++++ src/shader_recompiler/ir/ir_emitter.h | 8 + src/shader_recompiler/ir/opcodes.inc | 8 + .../ir/passes/constant_propagation_pass.cpp | 16 ++ src/shader_recompiler/runtime_info.h | 1 + src/video_core/amdgpu/liverpool.h | 4 + .../renderer_vulkan/vk_graphics_pipeline.h | 5 +- .../renderer_vulkan/vk_pipeline_cache.cpp | 21 ++- 14 files changed, 286 insertions(+), 57 deletions(-) diff --git a/externals/sirit b/externals/sirit index 26ad5a9d0..d6f3c0d99 160000 --- a/externals/sirit +++ b/externals/sirit @@ -1 +1 @@ -Subproject commit 26ad5a9d0fe13260b0d7d6c64419d01a196b2e32 +Subproject commit d6f3c0d99862ab2ff8f95e9ac221560f1f97e29a diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp index 02ac74e19..539c6cb81 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp @@ -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 diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h index 4833dc9d0..842b13207 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h @@ -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); diff --git a/src/shader_recompiler/frontend/translate/export.cpp b/src/shader_recompiler/frontend/translate/export.cpp index 38ff9ae14..84c2ee658 100644 --- a/src/shader_recompiler/frontend/translate/export.cpp +++ b/src/shader_recompiler/frontend/translate/export.cpp @@ -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(swizzle_array[comp]); + constexpr auto min_comp_type = static_cast(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(attribute) - static_cast(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(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::U32{r}) : IR::F32{r}; + const IR::F32 float_g = is_integer ? ir.BitCast(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(attribute) - static_cast(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(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(vsrc[0])); } // Export B, A if ((exp.en >> 2) & 1) { - unpack(1); + ExportCompressed(attrib, 1, ir.GetVectorReg(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(vsrc[i]); - set_attribute(i, comp); + ExportUncompressed(attrib, i, ir.GetVectorReg(vsrc[i])); } } if (IR::IsMrt(attrib)) { diff --git a/src/shader_recompiler/frontend/translate/translate.h b/src/shader_recompiler/frontend/translate/translate.h index 496455b50..287885854 100644 --- a/src/shader_recompiler/frontend/translate/translate.h +++ b/src/shader_recompiler/frontend/translate/translate.h @@ -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: diff --git a/src/shader_recompiler/frontend/translate/vector_alu.cpp b/src/shader_recompiler/frontend/translate/vector_alu.cpp index 42dbcc513..f73618dbe 100644 --- a/src/shader_recompiler/frontend/translate/vector_alu.cpp +++ b/src/shader_recompiler/frontend/translate/vector_alu.cpp @@ -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(inst.src[0])}; - const IR::F32 src1{GetSrc(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(inst.src[0]), GetSrc(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(inst.src[0]), GetSrc(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(inst.src[0]), GetSrc(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(inst.src[0]), GetSrc(inst.src[1])); + SetDst(inst.dst[0], ir.PackSint2x16(vec_u32)); } void Translator::V_CVT_PK_U8_F32(const GcnInst& inst) { diff --git a/src/shader_recompiler/ir/ir_emitter.cpp b/src/shader_recompiler/ir/ir_emitter.cpp index f0558665b..ecbe1f838 100644 --- a/src/shader_recompiler/ir/ir_emitter.cpp +++ b/src/shader_recompiler/ir/ir_emitter.cpp @@ -795,6 +795,38 @@ Value IREmitter::UnpackHalf2x16(const U32& value) { return Inst(Opcode::UnpackHalf2x16, value); } +U32 IREmitter::PackUnorm2x16(const Value& vector) { + return Inst(Opcode::PackUnorm2x16, vector); +} + +Value IREmitter::UnpackUnorm2x16(const U32& value) { + return Inst(Opcode::UnpackUnorm2x16, value); +} + +U32 IREmitter::PackSnorm2x16(const Value& vector) { + return Inst(Opcode::PackSnorm2x16, vector); +} + +Value IREmitter::UnpackSnorm2x16(const U32& value) { + return Inst(Opcode::UnpackSnorm2x16, value); +} + +U32 IREmitter::PackUint2x16(const Value& value) { + return Inst(Opcode::PackUint2x16, value); +} + +Value IREmitter::UnpackUint2x16(const U32& value) { + return Inst(Opcode::UnpackUint2x16, value); +} + +U32 IREmitter::PackSint2x16(const Value& value) { + return Inst(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()); diff --git a/src/shader_recompiler/ir/ir_emitter.h b/src/shader_recompiler/ir/ir_emitter.h index 5dd49ce7a..97b94187a 100644 --- a/src/shader_recompiler/ir/ir_emitter.h +++ b/src/shader_recompiler/ir/ir_emitter.h @@ -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); diff --git a/src/shader_recompiler/ir/opcodes.inc b/src/shader_recompiler/ir/opcodes.inc index 63a4e1e62..6750be5a6 100644 --- a/src/shader_recompiler/ir/opcodes.inc +++ b/src/shader_recompiler/ir/opcodes.inc @@ -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, ) diff --git a/src/shader_recompiler/ir/passes/constant_propagation_pass.cpp b/src/shader_recompiler/ir/passes/constant_propagation_pass.cpp index 12a1b56e9..c72b9e835 100644 --- a/src/shader_recompiler/ir/passes/constant_propagation_pass.cpp +++ b/src/shader_recompiler/ir/passes/constant_propagation_pass.cpp @@ -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: diff --git a/src/shader_recompiler/runtime_info.h b/src/shader_recompiler/runtime_info.h index 2bf5e3f0a..103c1faa8 100644 --- a/src/shader_recompiler/runtime_info.h +++ b/src/shader_recompiler/runtime_info.h @@ -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; }; diff --git a/src/video_core/amdgpu/liverpool.h b/src/video_core/amdgpu/liverpool.h index ec9c92ef1..67821b0f2 100644 --- a/src/video_core/amdgpu/liverpool.h +++ b/src/video_core/amdgpu/liverpool.h @@ -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((raw >> (buf_idx * 4)) & 0xfu); + } }; union VsOutputControl { diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h index 9a20f94c1..8c5cb1f3b 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h @@ -35,9 +35,8 @@ struct GraphicsPipelineKey { std::array stage_hashes; u32 num_color_attachments; std::array color_formats; - std::array color_num_formats; - std::array color_num_conversions; - std::array color_swizzles; + std::array + color_buffers; vk::Format depth_format; vk::Format stencil_format; diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index c6a56745d..3728a55fb 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -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; } From a51c8c17e07063065fe1780d648c3b4808f31d59 Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Fri, 24 Jan 2025 12:47:04 -0800 Subject: [PATCH 05/29] shader_recompiler: Fix image write swizzles. (#2236) --- .../ir/passes/resource_tracking_pass.cpp | 4 +-- src/video_core/amdgpu/types.h | 31 ++++++++++++++++--- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp b/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp index d94c5223a..43d125bf0 100644 --- a/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp +++ b/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp @@ -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()); diff --git a/src/video_core/amdgpu/types.h b/src/video_core/amdgpu/types.h index 63e184cc5..b442b2f1e 100644 --- a/src/video_core/amdgpu/types.h +++ b/src/video_core/amdgpu/types.h @@ -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 T ApplySingle(const std::array& 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) { From 361532418ce8a252fd873eacff0d0b83504eeffb Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Fri, 24 Jan 2025 12:47:24 -0800 Subject: [PATCH 06/29] externals: Update SPIRV-Cross for MoltenVK (#2237) --- externals/MoltenVK/SPIRV-Cross | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/externals/MoltenVK/SPIRV-Cross b/externals/MoltenVK/SPIRV-Cross index 6173e24b3..1a7b7ef6d 160000 --- a/externals/MoltenVK/SPIRV-Cross +++ b/externals/MoltenVK/SPIRV-Cross @@ -1 +1 @@ -Subproject commit 6173e24b31f09a0c3217103a130e74c4ddec14a6 +Subproject commit 1a7b7ef6de02cf6767e42b10ddad217c45e90d47 From 7072dfc99fdca87e833bf588587debef3e9b08bd Mon Sep 17 00:00:00 2001 From: hspir404 Date: Fri, 24 Jan 2025 21:56:21 +0000 Subject: [PATCH 07/29] Fix stale heap read in UnmapMemoryImpl (#2232) --- src/core/memory.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/core/memory.cpp b/src/core/memory.cpp index a8dd72acc..271092eaf 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -418,8 +418,9 @@ u64 MemoryManager::UnmapBytesFromEntry(VAddr virtual_addr, VirtualMemoryArea vma 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 + adjusted_size, From 73b7d344600a6a7aabb55d44dfe888deb8df312f Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Fri, 24 Jan 2025 19:55:27 -0800 Subject: [PATCH 08/29] hotfix: Drop scePadSetLightBar log to debug level. Some games like to spam this a lot, and we already handle it. --- src/core/libraries/pad/pad.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/libraries/pad/pad.cpp b/src/core/libraries/pad/pad.cpp index f2b81fbe0..d940d0cfa 100644 --- a/src/core/libraries/pad/pad.cpp +++ b/src/core/libraries/pad/pad.cpp @@ -473,7 +473,7 @@ 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, + LOG_DEBUG(Lib_Pad, "called handle = {} rgb = {} {} {}", handle, pParam->r, pParam->g, pParam->b); if (pParam->r < 0xD && pParam->g < 0xD && pParam->b < 0xD) { From e433f3116dd9a36a353d054e1a371e7ff257f87a Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Fri, 24 Jan 2025 19:57:04 -0800 Subject: [PATCH 09/29] hotfix 2: clang format --- src/core/libraries/pad/pad.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/libraries/pad/pad.cpp b/src/core/libraries/pad/pad.cpp index d940d0cfa..18709bcb2 100644 --- a/src/core/libraries/pad/pad.cpp +++ b/src/core/libraries/pad/pad.cpp @@ -473,8 +473,8 @@ int PS4_SYSV_ABI scePadSetForceIntercepted() { int PS4_SYSV_ABI scePadSetLightBar(s32 handle, const OrbisPadLightBarParam* pParam) { if (pParam != nullptr) { - LOG_DEBUG(Lib_Pad, "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"); From 564dbc7b94b02c70febd901f613ccb567923cb5e Mon Sep 17 00:00:00 2001 From: Ian Carpenter Date: Sat, 25 Jan 2025 04:00:52 -0500 Subject: [PATCH 10/29] system_service: Add simple event queue and push an EntitlementUpdate event to it when app content is initialized (#2238) --- .../libraries/app_content/app_content.cpp | 10 ++++++++ src/core/libraries/system/systemservice.cpp | 23 ++++++++++++++++--- src/core/libraries/system/systemservice.h | 4 ++++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/core/libraries/app_content/app_content.cpp b/src/core/libraries/app_content/app_content.cpp index 1d23e7f44..1223022c5 100644 --- a/src/core/libraries/app_content/app_content.cpp +++ b/src/core/libraries/app_content/app_content.cpp @@ -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; } diff --git a/src/core/libraries/system/systemservice.cpp b/src/core/libraries/system/systemservice.cpp index ebb9f4392..a67b9a2fc 100644 --- a/src/core/libraries/system/systemservice.cpp +++ b/src/core/libraries/system/systemservice.cpp @@ -10,6 +10,8 @@ namespace Libraries::SystemService { bool g_splash_status{true}; +std::queue 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 lock(g_event_queue_mutex); + status->event_num = static_cast(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 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 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); diff --git a/src/core/libraries/system/systemservice.h b/src/core/libraries/system/systemservice.h index cdd3c15e8..c22ccc88f 100644 --- a/src/core/libraries/system/systemservice.h +++ b/src/core/libraries/system/systemservice.h @@ -4,6 +4,8 @@ // https://github.com/OpenOrbis/OpenOrbis-PS4-Toolchain/blob/master/include/orbis/_types/sys_service.h #pragma once +#include +#include #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 From a5a1253185fc6b3231e30477ebb8dba5375ac936 Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Sat, 25 Jan 2025 04:12:18 -0800 Subject: [PATCH 11/29] liverpool: Implement PM4 MEM_SEMAPHORE. (#2235) --- src/video_core/amdgpu/liverpool.cpp | 24 ++++++++++++ src/video_core/amdgpu/pm4_cmds.h | 61 +++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) diff --git a/src/video_core/amdgpu/liverpool.cpp b/src/video_core/amdgpu/liverpool.cpp index 8355dd1e6..2f40d4136 100644 --- a/src/video_core/amdgpu/liverpool.cpp +++ b/src/video_core/amdgpu/liverpool.cpp @@ -636,6 +636,18 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span dcb, std::span(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(header); break; @@ -848,6 +860,18 @@ Liverpool::Task Liverpool::ProcessCompute(std::span acb, u32 vqid) { } break; } + case PM4ItOpcode::MemSemaphore: { + const auto* mem_semaphore = reinterpret_cast(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(header); ASSERT(wait_reg_mem->engine.Value() == PM4CmdWaitRegMem::Engine::Me); diff --git a/src/video_core/amdgpu/pm4_cmds.h b/src/video_core/amdgpu/pm4_cmds.h index 311f4d4d0..e92ba17fa 100644 --- a/src/video_core/amdgpu/pm4_cmds.h +++ b/src/video_core/amdgpu/pm4_cmds.h @@ -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 + [[nodiscard]] T Address() const { + return std::bit_cast(u64(addr_lo) << 3 | (u64(addr_hi) << 32)); + } + + [[nodiscard]] bool IsSignaling() const { + return sem_sel == Select::SignalSemaphore; + } + + [[nodiscard]] bool Signaled() const { + return *Address() > 0; + } + + void Decrement() const { + *Address() -= 1; + } + + void Signal() const { + auto* ptr = Address(); + switch (signal_type) { + case SignalType::Increment: + *ptr += 1; + break; + case SignalType::Write: + *ptr = 1; + break; + default: + UNREACHABLE_MSG("Unknown signal type {}", static_cast(signal_type.Value())); + } + } +}; + } // namespace AmdGpu From f1bc3b4f3dc492f4c067693a97e5932c8be38491 Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Sat, 25 Jan 2025 14:59:18 -0800 Subject: [PATCH 12/29] shader_recompiler: Add another constant propagation pass near the end. (#2231) --- src/shader_recompiler/recompiler.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shader_recompiler/recompiler.cpp b/src/shader_recompiler/recompiler.cpp index bb027a11e..01518ab8f 100644 --- a/src/shader_recompiler/recompiler.cpp +++ b/src/shader_recompiler/recompiler.cpp @@ -90,6 +90,7 @@ IR::Program TranslateProgram(std::span 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); From 3960283a67af70fbaf2a64a1ac97f695acf47a16 Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Sun, 26 Jan 2025 01:00:22 -0800 Subject: [PATCH 13/29] hotfix: Fix missing embedded PS shader address bits. If the emulator code is above a 40-bit address, the embedded shaders need to use address-hi to work. Embedded VS shader already supplies it, PS shader should as well. --- src/core/libraries/gnmdriver/gnmdriver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/libraries/gnmdriver/gnmdriver.cpp b/src/core/libraries/gnmdriver/gnmdriver.cpp index fdc3a1acd..06124167c 100644 --- a/src/core/libraries/gnmdriver/gnmdriver.cpp +++ b/src/core/libraries/gnmdriver/gnmdriver.cpp @@ -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], From 461148c22706ea35c8ae4985f21d695e46be01ff Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Sun, 26 Jan 2025 04:32:14 -0800 Subject: [PATCH 14/29] qt: Prevent interacting with empty grid cells. (#2243) --- src/qt_gui/game_grid_frame.cpp | 3 ++- src/qt_gui/gui_context_menus.h | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/qt_gui/game_grid_frame.cpp b/src/qt_gui/game_grid_frame.cpp index 2ebb09e5d..d719ac878 100644 --- a/src/qt_gui/game_grid_frame.cpp +++ b/src/qt_gui/game_grid_frame.cpp @@ -38,17 +38,18 @@ GameGridFrame::GameGridFrame(std::shared_ptr 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()); diff --git a/src/qt_gui/gui_context_menus.h b/src/qt_gui/gui_context_menus.h index 0e8675c0c..72affeca7 100644 --- a/src/qt_gui/gui_context_menus.h +++ b/src/qt_gui/gui_context_menus.h @@ -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; } From 46b5437fdfea7e7b3add555d62540766daa4534d Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Sun, 26 Jan 2025 08:01:15 -0800 Subject: [PATCH 15/29] emulator: Use correct game folder mount when opening update eboot directly. (#2244) --- src/emulator.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/emulator.cpp b/src/emulator.cpp index e77c2b87f..97215c06f 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -100,9 +100,21 @@ Emulator::~Emulator() { } void Emulator::Run(const std::filesystem::path& file, const std::vector 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::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"); @@ -223,7 +235,7 @@ void Emulator::Run(const std::filesystem::path& file, const std::vectorGetHLESymbols()); // 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 From 7d1631f9f43f3b781a20dd91d7ebc0980b55b8ee Mon Sep 17 00:00:00 2001 From: Ian Carpenter Date: Sun, 26 Jan 2025 18:46:59 -0500 Subject: [PATCH 16/29] memory_patcher: Remove hardcoded repositories when loading patches (#2241) --- src/common/memory_patcher.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/common/memory_patcher.cpp b/src/common/memory_patcher.cpp index 6b79edb9f..f81a0ed83 100644 --- a/src/common/memory_patcher.cpp +++ b/src/common/memory_patcher.cpp @@ -7,6 +7,7 @@ #include #include #ifdef ENABLE_QT_GUI +#include #include #include #include @@ -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."); From 6f04ea18e4f3d87e9a89f0fefcc1c8c722a87de6 Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Sun, 26 Jan 2025 19:28:58 -0800 Subject: [PATCH 17/29] externals: Update MoltenVK (#2249) Fixes broken vertex binding dynamic stride when used with tessellation. --- externals/MoltenVK/MoltenVK | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/externals/MoltenVK/MoltenVK b/externals/MoltenVK/MoltenVK index 2473ce6f0..6fa077fb8 160000 --- a/externals/MoltenVK/MoltenVK +++ b/externals/MoltenVK/MoltenVK @@ -1 +1 @@ -Subproject commit 2473ce6f0ab7d5d8a49aa91b2e37f3447a939f18 +Subproject commit 6fa077fb8ed8dac4e4cd66b6b1ebd7b4d955a754 From 191e64bfa11e45992e869e7a9df787d6fbe5038b Mon Sep 17 00:00:00 2001 From: Vladislav Mikhalin Date: Mon, 27 Jan 2025 11:17:23 +0300 Subject: [PATCH 18/29] renderer: respect zmin/zmax even if clipping is disabled (#2250) --- src/video_core/renderer_vulkan/vk_rasterizer.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 88b510eca..7a0652ed7 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -1172,6 +1172,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 +1183,14 @@ void Rasterizer::UpdateViewportScissorState(const GraphicsPipeline& pipeline) { .y = 0.f, .width = float(std::min(instance.GetMaxViewportWidth(), 16_KB)), .height = float(std::min(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, From 665261efc574562aad240466a9eed8b05b6b9a50 Mon Sep 17 00:00:00 2001 From: F1219R <109141852+F1219R@users.noreply.github.com> Date: Mon, 27 Jan 2025 16:39:27 +0100 Subject: [PATCH 19/29] Update sq translation (#2251) --- src/qt_gui/translations/sq.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/qt_gui/translations/sq.ts b/src/qt_gui/translations/sq.ts index 2f88b4390..15c18d2f6 100644 --- a/src/qt_gui/translations/sq.ts +++ b/src/qt_gui/translations/sq.ts @@ -249,7 +249,7 @@ Open shadPS4 Folder - Open shadPS4 Folder + Hap dosjen e shadPS4 Exit @@ -542,7 +542,7 @@ Fullscreen Mode - Modaliteti i Plotë + Mënyra me ekran të plotë Enable Separate Update Folder @@ -550,7 +550,7 @@ Default tab when opening settings - Skeda e parazgjedhur kur hapni cilësimet + Skeda e parazgjedhur kur hapen cilësimet Show Game Size In List @@ -594,7 +594,7 @@ Open Log Location - Hap vendndodhjen e regjistrit + Hap vendndodhjen e Ditarit Input @@ -630,11 +630,11 @@ Gui - Ndërfaqe + Ndërfaqja User - Përdorues + Përdoruesi Graphics Device @@ -822,7 +822,7 @@ GUIMusicGroupBox - Luaj muzikën e titullit:\nNëse një lojë e mbështet, aktivizohet luajtja e muzikës të veçantë kur të zgjidhësh lojën në GUI. + Luaj muzikën e titullit:\nNëse një lojë e mbështet, aktivizohet luajtja e muzikës të veçantë kur të zgjidhësh lojën në ndërfaqe. disableTrophycheckBox From 2837d848eddf2c4b2b361626c220aa415f8b241c Mon Sep 17 00:00:00 2001 From: panzone91 <150828896+panzone91@users.noreply.github.com> Date: Mon, 27 Jan 2025 21:40:58 +0100 Subject: [PATCH 20/29] linker: handle relocation for exported modules (#2247) --- src/core/linker.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/core/linker.h b/src/core/linker.h index 00da3a08c..357b39664 100644 --- a/src/core/linker.h +++ b/src/core/linker.h @@ -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()); + } } } } From d2127b38deace732f0c41b6cc1881e21f4ed268b Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Tue, 28 Jan 2025 00:12:48 -0800 Subject: [PATCH 21/29] vk_rasterizer: Keep viewport depth offset even without native depth clip control. (#2257) --- src/video_core/renderer_vulkan/vk_rasterizer.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 7a0652ed7..7c77f2519 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -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, From 8379922f8ab1209d25b4cbec14303401aa75eec9 Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Tue, 28 Jan 2025 02:31:26 -0800 Subject: [PATCH 22/29] hotfix: Reduce requested videodec memory block sizes. This really needs a more accurate implementation, but for the stub lowering the value helps games that run out of memory space if it is too large. --- src/core/libraries/videodec/videodec.cpp | 2 +- src/core/libraries/videodec/videodec2.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/libraries/videodec/videodec.cpp b/src/core/libraries/videodec/videodec.cpp index 6c9a9b8c0..79001e76f 100644 --- a/src/core/libraries/videodec/videodec.cpp +++ b/src/core/libraries/videodec/videodec.cpp @@ -9,7 +9,7 @@ namespace Libraries::Videodec { -static constexpr u64 kMinimumMemorySize = 32_MB; ///> Fake minimum memory size for querying +static constexpr u64 kMinimumMemorySize = 8_MB; ///> Fake minimum memory size for querying int PS4_SYSV_ABI sceVideodecCreateDecoder(const OrbisVideodecConfigInfo* pCfgInfoIn, const OrbisVideodecResourceInfo* pRsrcInfoIn, diff --git a/src/core/libraries/videodec/videodec2.cpp b/src/core/libraries/videodec/videodec2.cpp index 07f7a274b..be0db4ea3 100644 --- a/src/core/libraries/videodec/videodec2.cpp +++ b/src/core/libraries/videodec/videodec2.cpp @@ -10,7 +10,7 @@ namespace Libraries::Vdec2 { -static constexpr u64 kMinimumMemorySize = 32_MB; ///> Fake minimum memory size for querying +static constexpr u64 kMinimumMemorySize = 8_MB; ///> Fake minimum memory size for querying s32 PS4_SYSV_ABI sceVideodec2QueryComputeMemoryInfo(OrbisVideodec2ComputeMemoryInfo* computeMemInfo) { From 4b93b8b57460c83421d0d859e243dd05a864bdc1 Mon Sep 17 00:00:00 2001 From: Martin <67326368+Martini-141@users.noreply.github.com> Date: Tue, 28 Jan 2025 17:47:00 +0100 Subject: [PATCH 23/29] add missing translations and other corrections nb (#2253) --- src/qt_gui/translations/nb.ts | 42 +++++++++++++++++------------------ 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/qt_gui/translations/nb.ts b/src/qt_gui/translations/nb.ts index d6d4090df..0b7d2699a 100644 --- a/src/qt_gui/translations/nb.ts +++ b/src/qt_gui/translations/nb.ts @@ -98,7 +98,7 @@ Open Folder... - Åpne mappen... + Åpne mappe... Open Game Folder @@ -126,7 +126,7 @@ Copy All - Kopier alle + Kopier alt Delete... @@ -146,19 +146,19 @@ Compatibility... - Compatibility... + Kompatibilitet... Update database - Update database + Oppdater database View report - View report + Vis rapport Submit a report - Submit a report + Send inn en rapport Shortcut creation @@ -574,11 +574,11 @@ Trophy Key - Trophy Key + Trofénøkkel Trophy - Trophy + Trofé Logger @@ -658,7 +658,7 @@ Enable Shaders Dumping - Aktiver dumping av skyggelegger + Aktiver skyggeleggerdumping Enable NULL GPU @@ -666,7 +666,7 @@ Paths - Stier + Mapper Game Folders @@ -686,7 +686,7 @@ Enable Debug Dumping - Aktiver dumping av feilretting + Aktiver feilrettingsdumping Enable Vulkan Validation Layers @@ -718,7 +718,7 @@ GUI Settings - GUI-innstillinger + Grensesnitt-innstillinger Disable Trophy Pop-ups @@ -730,7 +730,7 @@ Update Compatibility Database On Startup - Oppdater kompatibilitets-database ved oppstart + Oppdater database ved oppstart Game Compatibility @@ -750,7 +750,7 @@ Audio Backend - Audio Backend + Lydsystem Save @@ -806,7 +806,7 @@ TrophyKey - Trophy Key:\nKey used to decrypt trophies. Must be obtained from your jailbroken console.\nMust contain only hex characters. + Trofénøkkel:\nNøkkel brukes til å dekryptere trofeer. Må hentes fra din konsoll (jailbroken).\nMå bare inneholde sekskantede tegn. logTypeGroupBox @@ -846,7 +846,7 @@ checkCompatibilityOnStartupCheckBox - Oppdater kompatibilitets-data ved oppstart:\nOppdaterer kompatibilitets-databasen automatisk når shadPS4 starter. + Oppdater database ved oppstart:\nOppdaterer kompatibilitets-databasen automatisk når shadPS4 starter. updateCompatibilityButton @@ -894,7 +894,7 @@ dumpShadersCheckBox - Aktiver dumping av skyggelegger:\nFor teknisk feilsøking lagrer skyggeleggerne fra spillet i en mappe mens de gjengis. + Aktiver skyggeleggerdumping:\nFor teknisk feilsøking lagrer skyggeleggerne fra spillet i en mappe mens de gjengis. nullGpuCheckBox @@ -914,7 +914,7 @@ debugDump - Aktiver dumping av feilsøking:\nLagrer import- og eksport-symbolene og filoverskriftsinformasjonen til det nåværende kjørende PS4-programmet i en katalog. + Aktiver feilrettingsdumping:\nLagrer import- og eksport-symbolene og filoverskriftsinformasjonen til det nåværende kjørende PS4-programmet i en katalog. vkValidationCheckBox @@ -1188,7 +1188,7 @@ Path - Sti + Adresse Play Time @@ -1232,7 +1232,7 @@ Game can be completed with playable performance and no major glitches - Spillet kan fullføres med spillbar ytelse og ingen store feil + Spillet kan fullføres med spillbar ytelse og uten store feil @@ -1361,4 +1361,4 @@ TB - \ No newline at end of file + From 2cdd873681dd3b03d0752bda5c84412f06f4f0b8 Mon Sep 17 00:00:00 2001 From: slick-daddy <129640104+slick-daddy@users.noreply.github.com> Date: Tue, 28 Jan 2025 19:47:12 +0300 Subject: [PATCH 24/29] Update tr_TR.ts (#2255) --- src/qt_gui/translations/tr_TR.ts | 54 ++++++++++++++++---------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/qt_gui/translations/tr_TR.ts b/src/qt_gui/translations/tr_TR.ts index 6436278de..a2368bfee 100644 --- a/src/qt_gui/translations/tr_TR.ts +++ b/src/qt_gui/translations/tr_TR.ts @@ -546,7 +546,7 @@ Enable Separate Update Folder - Enable Separate Update Folder + Ayrı Güncelleme Klasörünü Etkinleştir Default tab when opening settings @@ -554,7 +554,7 @@ Show Game Size In List - Göster oyun boyutunu listede + Oyun Boyutunu Listede Göster Show Splash @@ -574,11 +574,11 @@ Trophy Key - Trophy Key + Kupa Anahtarı Trophy - Trophy + Kupa Logger @@ -722,7 +722,7 @@ Disable Trophy Pop-ups - Disable Trophy Pop-ups + Kupa Açılır Pencerelerini Devre Dışı Bırak Play title music @@ -730,23 +730,23 @@ Update Compatibility Database On Startup - Update Compatibility Database On Startup + Başlangıçta Uyumluluk Veritabanını Güncelle Game Compatibility - Game Compatibility + Oyun Uyumluluğu Display Compatibility Data - Display Compatibility Data + Uyumluluk Verilerini Göster Update Compatibility Database - Update Compatibility Database + Uyumluluk Veritabanını Güncelle Volume - Ses seviyesi + Ses Seviyesi Audio Backend @@ -1105,11 +1105,11 @@ The game is in version: %1 - Oyun sürümde: %1 + Oyun sürümü: %1 The downloaded patch only works on version: %1 - İndirilen yamanın sadece sürümde çalışıyor: %1 + İndirilen yama sadece şu sürümde çalışıyor: %1 You may need to update your game. @@ -1168,7 +1168,7 @@ Compatibility - Compatibility + Uyumluluk Region @@ -1196,35 +1196,35 @@ Never Played - Never Played + Hiç Oynanmadı h - h + sa m - m + dk s - s + sn Compatibility is untested - Compatibility is untested + Uyumluluk test edilmemiş Game does not initialize properly / crashes the emulator - Game does not initialize properly / crashes the emulator + Oyun düzgün bir şekilde başlatılamıyor / emülatörü çökertiyor Game boots, but only displays a blank screen - Game boots, but only displays a blank screen + Oyun başlatılabiliyor ancak yalnızca boş bir ekran gösteriyor Game displays an image but does not go past the menu - Game displays an image but does not go past the menu + Oyun bir resim gösteriyor ancak menüleri geçemiyor Game has game-breaking glitches or unplayable performance @@ -1232,7 +1232,7 @@ Game can be completed with playable performance and no major glitches - Game can be completed with playable performance and no major glitches + Oyun, oynanabilir performansla tamamlanabilir ve büyük aksaklık yok @@ -1267,7 +1267,7 @@ Your version is already up to date! - Versiyonunuz zaten güncel! + Sürümünüz zaten güncel! Update Available @@ -1279,11 +1279,11 @@ Current Version - Mevcut Versiyon + Mevcut Sürüm Latest Version - Son Versiyon + Son Sürüm Do you want to update? @@ -1335,7 +1335,7 @@ Failed to create the update script file - Güncelleme betiği dosyası oluşturulamadı + Güncelleme komut dosyası oluşturulamadı @@ -1361,4 +1361,4 @@ TB - \ No newline at end of file + From a78f8afe58a995cecdb4eb1f1e6d6e58320444f6 Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Tue, 28 Jan 2025 08:48:19 -0800 Subject: [PATCH 25/29] libraries: Implement libSceZlib. (#2256) * libraries: add zlib hle skeleton/stub * libraries: Implement libSceZlib. * zlib: Make variables static. --------- Co-authored-by: Nenkai --- CMakeLists.txt | 6 + src/common/logging/filter.cpp | 1 + src/common/logging/types.h | 1 + src/core/libraries/libs.cpp | 2 + src/core/libraries/zlib/zlib.cpp | 183 +++++++++++++++++++++++++++ src/core/libraries/zlib/zlib_error.h | 18 +++ src/core/libraries/zlib/zlib_sce.h | 21 +++ 7 files changed, 232 insertions(+) create mode 100644 src/core/libraries/zlib/zlib.cpp create mode 100644 src/core/libraries/zlib/zlib_error.h create mode 100644 src/core/libraries/zlib/zlib_sce.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c9dad307..78e3c7997 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -440,6 +440,11 @@ set(NP_LIBS src/core/libraries/np_common/np_common.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 src/core/libraries/screenshot/screenshot.h src/core/libraries/move/move.cpp @@ -612,6 +617,7 @@ set(CORE src/core/aerolib/stubs.cpp ${PLAYGO_LIB} ${RANDOM_LIB} ${USBD_LIB} + ${ZLIB_LIB} ${MISC_LIBS} ${IME_LIB} ${FIBER_LIB} diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp index f1d3a9499..dd708c528 100644 --- a/src/common/logging/filter.cpp +++ b/src/common/logging/filter.cpp @@ -133,6 +133,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) { SUB(Lib, Mouse) \ SUB(Lib, WebBrowserDialog) \ SUB(Lib, NpParty) \ + SUB(Lib, Zlib) \ CLS(Frontend) \ CLS(Render) \ SUB(Render, Vulkan) \ diff --git a/src/common/logging/types.h b/src/common/logging/types.h index d5530312c..54f8cdd0b 100644 --- a/src/common/logging/types.h +++ b/src/common/logging/types.h @@ -100,6 +100,7 @@ enum class Class : u8 { 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 diff --git a/src/core/libraries/libs.cpp b/src/core/libraries/libs.cpp index e09de1cee..8cf286d13 100644 --- a/src/core/libraries/libs.cpp +++ b/src/core/libraries/libs.cpp @@ -54,6 +54,7 @@ #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" @@ -111,6 +112,7 @@ void InitHLELibs(Core::Loader::SymbolsResolver* sym) { Libraries::Mouse::RegisterlibSceMouse(sym); Libraries::WebBrowserDialog::RegisterlibSceWebBrowserDialog(sym); Libraries::NpParty::RegisterlibSceNpParty(sym); + Libraries::Zlib::RegisterlibSceZlib(sym); } } // namespace Libraries diff --git a/src/core/libraries/zlib/zlib.cpp b/src/core/libraries/zlib/zlib.cpp new file mode 100644 index 000000000..899cb5bf6 --- /dev/null +++ b/src/core/libraries/zlib/zlib.cpp @@ -0,0 +1,183 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include +#include +#include +#include + +#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 task_queue; +static std::condition_variable_any task_queue_cv; +static std::queue done_queue; +static std::condition_variable_any done_queue_cv; +static std::unordered_map 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(task.dst), &decompressed_length, + static_cast(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(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(); + done_queue = std::queue(); + 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 diff --git a/src/core/libraries/zlib/zlib_error.h b/src/core/libraries/zlib/zlib_error.h new file mode 100644 index 000000000..59574f0b2 --- /dev/null +++ b/src/core/libraries/zlib/zlib_error.h @@ -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; diff --git a/src/core/libraries/zlib/zlib_sce.h b/src/core/libraries/zlib/zlib_sce.h new file mode 100644 index 000000000..6f8cf9468 --- /dev/null +++ b/src/core/libraries/zlib/zlib_sce.h @@ -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 \ No newline at end of file From 0575853be18d8f0504482b4a5a407fb14a23d492 Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Tue, 28 Jan 2025 17:56:05 -0800 Subject: [PATCH 26/29] externals: Update MoltenVK. (#2264) Adds support for VK_EXT_depth_clip_control --- externals/MoltenVK/MoltenVK | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/externals/MoltenVK/MoltenVK b/externals/MoltenVK/MoltenVK index 6fa077fb8..aba997657 160000 --- a/externals/MoltenVK/MoltenVK +++ b/externals/MoltenVK/MoltenVK @@ -1 +1 @@ -Subproject commit 6fa077fb8ed8dac4e4cd66b6b1ebd7b4d955a754 +Subproject commit aba997657b94d6de1794ebad36ce5634341252c7 From 78a0a755c5f2ff06c340ec0dc3431fc247aaa3e4 Mon Sep 17 00:00:00 2001 From: ElBread3 <92335081+ElBread3@users.noreply.github.com> Date: Tue, 28 Jan 2025 21:14:47 -0600 Subject: [PATCH 27/29] qt_gui: Some game install features and fixes (#2261) * open update folder + delete save folder + bulk install checkbox * delete pkg on install checkbox + use game icon for finish window --- src/qt_gui/gui_context_menus.h | 45 ++++++++++++++++++++++++++++--- src/qt_gui/install_dir_select.cpp | 24 ++++++++++++++--- src/qt_gui/install_dir_select.h | 12 +++++++++ src/qt_gui/main_window.cpp | 26 +++++++++++++++--- src/qt_gui/main_window.h | 4 +++ 5 files changed, 101 insertions(+), 10 deletions(-) diff --git a/src/qt_gui/gui_context_menus.h b/src/qt_gui/gui_context_menus.h index 72affeca7..bdc2aec0c 100644 --- a/src/qt_gui/gui_context_menus.h +++ b/src/qt_gui/gui_context_menus.h @@ -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); + } } } } diff --git a/src/qt_gui/install_dir_select.cpp b/src/qt_gui/install_dir_select.cpp index e0951b123..e90a10ee6 100644 --- a/src/qt_gui/install_dir_select.cpp +++ b/src/qt_gui/install_dir_select.cpp @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include #include #include #include @@ -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); diff --git a/src/qt_gui/install_dir_select.h b/src/qt_gui/install_dir_select.h index e3e81575a..e11cbf381 100644 --- a/src/qt_gui/install_dir_select.h +++ b/src/qt_gui/install_dir_select.h @@ -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; }; diff --git a/src/qt_gui/main_window.cpp b/src/qt_gui/main_window.cpp index 3ee392613..3678b3a82 100644 --- a/src/qt_gui/main_window.cpp +++ b/src/qt_gui/main_window.cpp @@ -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::progressValueChanged, &dialog, diff --git a/src/qt_gui/main_window.h b/src/qt_gui/main_window.h index f4163defa..5ac56e44c 100644 --- a/src/qt_gui/main_window.h +++ b/src/qt_gui/main_window.h @@ -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; }; From 9bad66b24d4082240d00849a3d342d4d4a7c52d3 Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Wed, 29 Jan 2025 01:29:52 -0800 Subject: [PATCH 28/29] hotfix: Raise videodec memory back up to 16MB. Found a game that needs more, still should be low enough compared to before to fix some games. --- src/core/libraries/videodec/videodec.cpp | 2 +- src/core/libraries/videodec/videodec2.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/libraries/videodec/videodec.cpp b/src/core/libraries/videodec/videodec.cpp index 79001e76f..02ea61509 100644 --- a/src/core/libraries/videodec/videodec.cpp +++ b/src/core/libraries/videodec/videodec.cpp @@ -9,7 +9,7 @@ namespace Libraries::Videodec { -static constexpr u64 kMinimumMemorySize = 8_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, diff --git a/src/core/libraries/videodec/videodec2.cpp b/src/core/libraries/videodec/videodec2.cpp index be0db4ea3..a7e520b41 100644 --- a/src/core/libraries/videodec/videodec2.cpp +++ b/src/core/libraries/videodec/videodec2.cpp @@ -10,7 +10,7 @@ namespace Libraries::Vdec2 { -static constexpr u64 kMinimumMemorySize = 8_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) { From aa847de043e2e04512d5d01b4d9e40adc4706b0a Mon Sep 17 00:00:00 2001 From: isshininu Date: Wed, 29 Jan 2025 13:54:08 +0400 Subject: [PATCH 29/29] Update ru_RU translation (#2267) Several changes in ru_RU translation file. --- src/qt_gui/translations/ru_RU.ts | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/qt_gui/translations/ru_RU.ts b/src/qt_gui/translations/ru_RU.ts index 6423f5ba4..0fddb1e7f 100644 --- a/src/qt_gui/translations/ru_RU.ts +++ b/src/qt_gui/translations/ru_RU.ts @@ -126,11 +126,11 @@ Copy All - Копировать все + Копировать всё Delete... - Удаление... + Удалить... Delete Game @@ -158,7 +158,7 @@ Submit a report - Отправить отчет + Отправить отчёт Shortcut creation @@ -297,7 +297,7 @@ Elf Viewer - Elf + Исполняемый файл Game Install Directory @@ -542,7 +542,7 @@ Fullscreen Mode - Режим Полного Экран + Тип полноэкранного режима Enable Separate Update Folder @@ -574,11 +574,11 @@ Trophy Key - Trophy Key + Ключ трофеев Trophy - Trophy + Трофеи Logger @@ -750,7 +750,7 @@ Audio Backend - Звуковая Подсистема + Звуковая подсистема Save @@ -826,7 +826,7 @@ disableTrophycheckBox - Отключить уведомления о трофеях:\nОтключает внутриигровые уведомления о трофеях. Прогресс трофеев по прежнему можно отслеживать в меню Просмотр трофеев (правая кнопка мыши по игре в главном окне). + Отключить уведомления о трофеях:\nОтключает внутриигровые уведомления о трофеях. Прогресс трофеев по прежнему можно отслеживать в меню просмотра трофеев (правая кнопка мыши по игре в главном окне). hideCursorGroupBox @@ -1192,11 +1192,11 @@ Play Time - Времени в игре + Время в игре Never Played - Вы не играли + Нет h @@ -1361,4 +1361,4 @@ ТБ - \ No newline at end of file +