diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 86ca81c38..55549ab4c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -205,12 +205,12 @@ jobs: run: | mkdir upload mv ${{github.workspace}}/build/shadps4 upload - cp ${{github.workspace}}/build/externals/MoltenVK/libMoltenVK.dylib upload - tar cf shadps4-macos-sdl.tar.gz -C upload . + mv ${{github.workspace}}/build/MoltenVK_icd.json upload + mv ${{github.workspace}}/build/libMoltenVK.dylib upload - uses: actions/upload-artifact@v4 with: name: shadps4-macos-sdl-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }} - path: shadps4-macos-sdl.tar.gz + path: upload/ macos-qt: runs-on: macos-15 diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ea8688df..96cce0b10 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -200,7 +200,14 @@ execute_process( OUTPUT_STRIP_TRAILING_WHITESPACE ) -set(APP_VERSION "0.7.1 WIP") +# Set Version +set(EMULATOR_VERSION_MAJOR "0") +set(EMULATOR_VERSION_MINOR "8") +set(EMULATOR_VERSION_PATCH "1") + +set_source_files_properties(src/shadps4.rc PROPERTIES COMPILE_DEFINITIONS "EMULATOR_VERSION_MAJOR=${EMULATOR_VERSION_MAJOR};EMULATOR_VERSION_MINOR=${EMULATOR_VERSION_MINOR};EMULATOR_VERSION_PATCH=${EMULATOR_VERSION_PATCH}") + +set(APP_VERSION "${EMULATOR_VERSION_MAJOR}.${EMULATOR_VERSION_MINOR}.${EMULATOR_VERSION_PATCH} WIP") set(APP_IS_RELEASE false) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/common/scm_rev.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/src/common/scm_rev.cpp" @ONLY) @@ -563,6 +570,8 @@ set(NP_LIBS src/core/libraries/np_common/np_common.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 + src/core/libraries/np_auth/np_auth.cpp + src/core/libraries/np_auth/np_auth.h ) set(ZLIB_LIB src/core/libraries/zlib/zlib.cpp @@ -1074,34 +1083,43 @@ if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND ENABLE_USERFAULTFD) endif() if (APPLE) - if (ENABLE_QT_GUI) - # Include MoltenVK in the app bundle, along with an ICD file so it can be found by the system Vulkan loader if used for loading layers. - set(MVK_ICD ${CMAKE_CURRENT_SOURCE_DIR}/externals/MoltenVK/MoltenVK_icd.json) - target_sources(shadps4 PRIVATE ${MVK_ICD}) - set_source_files_properties(${MVK_ICD} PROPERTIES MACOSX_PACKAGE_LOCATION Resources/vulkan/icd.d) + # Include MoltenVK, along with an ICD file so it can be found by the system Vulkan loader if used for loading layers. + if (ENABLE_QT_GUI) + set(MVK_BUNDLE_PATH "Resources/vulkan/icd.d") + set_property(TARGET shadps4 APPEND PROPERTY BUILD_RPATH "@executable_path/../${MVK_BUNDLE_PATH}") + set(MVK_DST ${CMAKE_CURRENT_BINARY_DIR}/shadps4.app/Contents/${MVK_BUNDLE_PATH}) + else() + set_property(TARGET shadps4 APPEND PROPERTY BUILD_RPATH "@executable_path") + set(MVK_DST ${CMAKE_CURRENT_BINARY_DIR}) + endif() - set(MVK_DYLIB_SRC ${CMAKE_CURRENT_BINARY_DIR}/externals/MoltenVK/libMoltenVK.dylib) - set(MVK_DYLIB_DST ${CMAKE_CURRENT_BINARY_DIR}/shadps4.app/Contents/Frameworks/libMoltenVK.dylib) - add_custom_command( - OUTPUT ${MVK_DYLIB_DST} - DEPENDS ${MVK_DYLIB_SRC} - COMMAND cmake -E copy ${MVK_DYLIB_SRC} ${MVK_DYLIB_DST}) - add_custom_target(CopyMoltenVK DEPENDS ${MVK_DYLIB_DST}) - add_dependencies(CopyMoltenVK MoltenVK) - add_dependencies(shadps4 CopyMoltenVK) - set_property(TARGET shadps4 APPEND PROPERTY BUILD_RPATH "@executable_path/../Frameworks") - else() - # For non-bundled SDL build, just do a normal library link. - target_link_libraries(shadps4 PRIVATE MoltenVK) - endif() + set(MVK_DYLIB_SRC ${CMAKE_CURRENT_BINARY_DIR}/externals/MoltenVK/libMoltenVK.dylib) + set(MVK_DYLIB_DST ${MVK_DST}/libMoltenVK.dylib) + set(MVK_ICD_SRC ${CMAKE_CURRENT_SOURCE_DIR}/externals/MoltenVK/MoltenVK/MoltenVK/icd/MoltenVK_icd.json) + set(MVK_ICD_DST ${MVK_DST}/MoltenVK_icd.json) - if (ARCHITECTURE STREQUAL "x86_64") - # Reserve system-managed memory space. - target_link_options(shadps4 PRIVATE -Wl,-no_pie,-no_fixup_chains,-no_huge,-pagezero_size,0x4000,-segaddr,TCB_SPACE,0x4000,-segaddr,SYSTEM_MANAGED,0x400000,-segaddr,SYSTEM_RESERVED,0x7FFFFC000,-image_base,0x20000000000) - endif() + add_custom_command( + OUTPUT ${MVK_DST} + COMMAND ${CMAKE_COMMAND} -E make_directory ${MVK_DST}) + add_custom_command( + OUTPUT ${MVK_ICD_DST} + DEPENDS ${MVK_ICD_SRC} ${MVK_DST} + COMMAND ${CMAKE_COMMAND} -E copy ${MVK_ICD_SRC} ${MVK_ICD_DST}) + add_custom_command( + OUTPUT ${MVK_DYLIB_DST} + DEPENDS ${MVK_DYLIB_SRC} ${MVK_DST} + COMMAND ${CMAKE_COMMAND} -E copy ${MVK_DYLIB_SRC} ${MVK_DYLIB_DST}) + add_custom_target(CopyMoltenVK DEPENDS ${MVK_ICD_DST} ${MVK_DYLIB_DST}) + add_dependencies(CopyMoltenVK MoltenVK) + add_dependencies(shadps4 CopyMoltenVK) - # Replacement for std::chrono::time_zone - target_link_libraries(shadps4 PRIVATE date::date-tz) + if (ARCHITECTURE STREQUAL "x86_64") + # Reserve system-managed memory space. + target_link_options(shadps4 PRIVATE -Wl,-no_pie,-no_fixup_chains,-no_huge,-pagezero_size,0x4000,-segaddr,TCB_SPACE,0x4000,-segaddr,SYSTEM_MANAGED,0x400000,-segaddr,SYSTEM_RESERVED,0x7FFFFC000,-image_base,0x20000000000) + endif() + + # Replacement for std::chrono::time_zone + target_link_libraries(shadps4 PRIVATE date::date-tz) endif() if (NOT ENABLE_QT_GUI) diff --git a/README.md b/README.md index 0e2248970..985bba586 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ SPDX-License-Identifier: GPL-2.0-or-later

- + @@ -146,16 +146,13 @@ The following firmware modules are supported and must be placed in shadPS4's `us # Main team - [**georgemoralis**](https://github.com/georgemoralis) -- [**raphaelthegreat**](https://github.com/raphaelthegreat) - [**psucien**](https://github.com/psucien) -- [**skmp**](https://github.com/skmp) -- [**wheremyfoodat**](https://github.com/wheremyfoodat) -- [**raziel1000**](https://github.com/raziel1000) - [**viniciuslrangel**](https://github.com/viniciuslrangel) - [**roamic**](https://github.com/vladmikhalin) -- [**poly**](https://github.com/polybiusproxy) - [**squidbus**](https://github.com/squidbus) - [**frodo**](https://github.com/baggins183) +- [**Stephen Miller**](https://github.com/StevenMiller123) +- [**kalaposfos13**](https://github.com/kalaposfos13) Logo is done by [**Xphalnos**](https://github.com/Xphalnos) @@ -166,11 +163,11 @@ Open a PR and we'll check it :) # Translations -If you want to translate shadPS4 to your language we use [**crowdin**](https://crowdin.com/project/shadps4-emulator). +If you want to translate shadPS4 to your language we use [**Crowdin**](https://crowdin.com/project/shadps4-emulator). # Contributors - + diff --git a/dist/net.shadps4.shadPS4.metainfo.xml b/dist/net.shadps4.shadPS4.metainfo.xml index 99f9e070d..9f7b4f9c5 100644 --- a/dist/net.shadps4.shadPS4.metainfo.xml +++ b/dist/net.shadps4.shadPS4.metainfo.xml @@ -37,6 +37,9 @@ Game + + https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.8.0 + https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.7.0 diff --git a/documents/Quickstart/Quickstart.md b/documents/Quickstart/Quickstart.md index 55825ac7d..62df95e71 100644 --- a/documents/Quickstart/Quickstart.md +++ b/documents/Quickstart/Quickstart.md @@ -29,8 +29,8 @@ SPDX-License-Identifier: GPL-2.0-or-later ### GPU - A graphics card with at least 1GB of VRAM -- Keep your graphics drivers up to date -- Vulkan 1.3 support (required) +- Up-to-date graphics drivers +- Vulkan 1.3 with the `VK_KHR_swapchain` and `VK_KHR_push_descriptor` extensions ### RAM diff --git a/externals/MoltenVK/MoltenVK b/externals/MoltenVK/MoltenVK index 83510e0f3..87a8e8b13 160000 --- a/externals/MoltenVK/MoltenVK +++ b/externals/MoltenVK/MoltenVK @@ -1 +1 @@ -Subproject commit 83510e0f3835c3c43651dda087305abc42572e17 +Subproject commit 87a8e8b13d4ad8835367fea1ebad1896d0460946 diff --git a/externals/MoltenVK/MoltenVK_icd.json b/externals/MoltenVK/MoltenVK_icd.json deleted file mode 100644 index 2c3319263..000000000 --- a/externals/MoltenVK/MoltenVK_icd.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "file_format_version": "1.0.0", - "ICD": { - "library_path": "../../../Frameworks/libMoltenVK.dylib", - "api_version": "1.2.0", - "is_portability_driver": true - } -} diff --git a/externals/MoltenVK/SPIRV-Cross b/externals/MoltenVK/SPIRV-Cross index 68300dc07..791877574 160000 --- a/externals/MoltenVK/SPIRV-Cross +++ b/externals/MoltenVK/SPIRV-Cross @@ -1 +1 @@ -Subproject commit 68300dc07ac3dc592dbbdb87e02d5180f984ad12 +Subproject commit 7918775748c5e2f5c40d9918ce68825035b5a1e1 diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp index bed7802ed..867d62916 100644 --- a/src/common/logging/filter.cpp +++ b/src/common/logging/filter.cpp @@ -101,6 +101,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) { SUB(Lib, Ssl2) \ SUB(Lib, SysModule) \ SUB(Lib, Move) \ + SUB(Lib, NpAuth) \ SUB(Lib, NpCommon) \ SUB(Lib, NpManager) \ SUB(Lib, NpScore) \ diff --git a/src/common/logging/types.h b/src/common/logging/types.h index c07efbc0d..e5714a81a 100644 --- a/src/common/logging/types.h +++ b/src/common/logging/types.h @@ -69,6 +69,7 @@ enum class Class : u8 { Lib_Http2, ///< The LibSceHttp2 implementation. Lib_SysModule, ///< The LibSceSysModule implementation Lib_NpCommon, ///< The LibSceNpCommon implementation + Lib_NpAuth, ///< The LibSceNpAuth implementation Lib_NpManager, ///< The LibSceNpManager implementation Lib_NpScore, ///< The LibSceNpScore implementation Lib_NpTrophy, ///< The LibSceNpTrophy implementation diff --git a/src/common/path_util.cpp b/src/common/path_util.cpp index 702d0fabc..1a6ff9ec8 100644 --- a/src/common/path_util.cpp +++ b/src/common/path_util.cpp @@ -60,7 +60,7 @@ static CFURLRef UntranslocateBundlePath(const CFURLRef bundle_path) { return nullptr; } -static std::filesystem::path GetBundleParentDirectory() { +static std::optional GetBundleParentDirectory() { if (CFBundleRef bundle_ref = CFBundleGetMainBundle()) { if (CFURLRef bundle_url_ref = CFBundleCopyBundleURL(bundle_ref)) { SCOPE_EXIT { @@ -83,14 +83,16 @@ static std::filesystem::path GetBundleParentDirectory() { } } } - return std::filesystem::current_path(); + return std::nullopt; } #endif static auto UserPaths = [] { -#ifdef __APPLE__ +#if defined(__APPLE__) && defined(ENABLE_QT_GUI) // Set the current path to the directory containing the app bundle. - std::filesystem::current_path(GetBundleParentDirectory()); + if (const auto bundle_dir = GetBundleParentDirectory()) { + std::filesystem::current_path(*bundle_dir); + } #endif // Try the portable user directory first. diff --git a/src/core/libraries/gnmdriver/gnmdriver.cpp b/src/core/libraries/gnmdriver/gnmdriver.cpp index e8560b2b8..25ac4921c 100644 --- a/src/core/libraries/gnmdriver/gnmdriver.cpp +++ b/src/core/libraries/gnmdriver/gnmdriver.cpp @@ -2804,7 +2804,7 @@ void RegisterlibSceGnmDriver(Core::Loader::SymbolsResolver* sym) { liverpool = std::make_unique(); presenter = std::make_unique(*g_window, liverpool.get()); - const int result = sceKernelGetCompiledSdkVersion(&sdk_version); + const s32 result = sceKernelGetCompiledSdkVersion(&sdk_version); if (result != ORBIS_OK) { sdk_version = 0; } diff --git a/src/core/libraries/ime/ime_dialog.cpp b/src/core/libraries/ime/ime_dialog.cpp index 9151aa64e..bee185787 100644 --- a/src/core/libraries/ime/ime_dialog.cpp +++ b/src/core/libraries/ime/ime_dialog.cpp @@ -83,9 +83,35 @@ int PS4_SYSV_ABI sceImeDialogGetPanelPositionAndForm() { return ORBIS_OK; } -int PS4_SYSV_ABI sceImeDialogGetPanelSize() { - LOG_ERROR(Lib_ImeDialog, "(STUBBED) called"); - return ORBIS_OK; +Error PS4_SYSV_ABI sceImeDialogGetPanelSize(const OrbisImeDialogParam* param, u32* width, + u32* height) { + LOG_INFO(Lib_ImeDialog, "called"); + + if (!width || !height) { + return Error::INVALID_ADDRESS; + } + switch (param->type) { + case OrbisImeType::Default: + case OrbisImeType::BasicLatin: + case OrbisImeType::Url: + case OrbisImeType::Mail: + *width = 500; // original: 793 + if (True(param->option & OrbisImeDialogOption::Multiline)) { + *height = 300; // original: 576 + } else { + *height = 150; // original: 476 + } + break; + case OrbisImeType::Number: + *width = 370; + *height = 470; + break; + default: + LOG_ERROR(Lib_ImeDialog, "Unknown OrbisImeType: {}", (u32)param->type); + return Error::INVALID_PARAM; + } + + return Error::OK; } int PS4_SYSV_ABI sceImeDialogGetPanelSizeExtended() { diff --git a/src/core/libraries/ime/ime_dialog.h b/src/core/libraries/ime/ime_dialog.h index c8b228498..33abc7ecd 100644 --- a/src/core/libraries/ime/ime_dialog.h +++ b/src/core/libraries/ime/ime_dialog.h @@ -155,7 +155,8 @@ Error PS4_SYSV_ABI sceImeDialogForceClose(); Error PS4_SYSV_ABI sceImeDialogForTestFunction(); int PS4_SYSV_ABI sceImeDialogGetCurrentStarState(); int PS4_SYSV_ABI sceImeDialogGetPanelPositionAndForm(); -int PS4_SYSV_ABI sceImeDialogGetPanelSize(); +Error PS4_SYSV_ABI sceImeDialogGetPanelSize(const OrbisImeDialogParam* param, u32* width, + u32* height); int PS4_SYSV_ABI sceImeDialogGetPanelSizeExtended(); Error PS4_SYSV_ABI sceImeDialogGetResult(OrbisImeDialogResult* result); OrbisImeDialogStatus PS4_SYSV_ABI sceImeDialogGetStatus(); diff --git a/src/core/libraries/kernel/memory.cpp b/src/core/libraries/kernel/memory.cpp index 7b3ac5646..8a0c91479 100644 --- a/src/core/libraries/kernel/memory.cpp +++ b/src/core/libraries/kernel/memory.cpp @@ -19,7 +19,7 @@ namespace Libraries::Kernel { u64 PS4_SYSV_ABI sceKernelGetDirectMemorySize() { - LOG_WARNING(Kernel_Vmm, "called"); + LOG_TRACE(Kernel_Vmm, "called"); const auto* memory = Core::Memory::Instance(); return memory->GetTotalDirectSize(); } @@ -106,12 +106,6 @@ s32 PS4_SYSV_ABI sceKernelAvailableDirectMemorySize(u64 searchStart, u64 searchE if (physAddrOut == nullptr || sizeOut == nullptr) { return ORBIS_KERNEL_ERROR_EINVAL; } - if (searchEnd > sceKernelGetDirectMemorySize()) { - return ORBIS_KERNEL_ERROR_EINVAL; - } - if (searchEnd <= searchStart) { - return ORBIS_KERNEL_ERROR_ENOMEM; - } auto* memory = Core::Memory::Instance(); diff --git a/src/core/libraries/libs.cpp b/src/core/libraries/libs.cpp index d0f82556e..3f5baf640 100644 --- a/src/core/libraries/libs.cpp +++ b/src/core/libraries/libs.cpp @@ -27,6 +27,7 @@ #include "core/libraries/network/netctl.h" #include "core/libraries/network/ssl.h" #include "core/libraries/network/ssl2.h" +#include "core/libraries/np_auth/np_auth.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" @@ -88,6 +89,7 @@ void InitHLELibs(Core::Loader::SymbolsResolver* sym) { Libraries::NpScore::RegisterlibSceNpScore(sym); Libraries::NpTrophy::RegisterlibSceNpTrophy(sym); Libraries::NpWebApi::RegisterlibSceNpWebApi(sym); + Libraries::NpAuth::RegisterlibSceNpAuth(sym); Libraries::ScreenShot::RegisterlibSceScreenShot(sym); Libraries::AppContent::RegisterlibSceAppContent(sym); Libraries::PngDec::RegisterlibScePngDec(sym); diff --git a/src/core/libraries/np_auth/np_auth.cpp b/src/core/libraries/np_auth/np_auth.cpp new file mode 100644 index 000000000..9ec986f3c --- /dev/null +++ b/src/core/libraries/np_auth/np_auth.cpp @@ -0,0 +1,99 @@ +// 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_auth/np_auth.h" + +namespace Libraries::NpAuth { + +s32 PS4_SYSV_ABI sceNpAuthGetAuthorizationCode() { + LOG_ERROR(Lib_NpAuth, "(STUBBED) called"); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceNpAuthGetIdToken() { + LOG_ERROR(Lib_NpAuth, "(STUBBED) called"); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceNpAuthAbortRequest() { + LOG_ERROR(Lib_NpAuth, "(STUBBED) called"); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceNpAuthCreateAsyncRequest() { + LOG_ERROR(Lib_NpAuth, "(STUBBED) called"); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceNpAuthCreateRequest() { + LOG_WARNING(Lib_NpAuth, "(DUMMY) called"); + return 1; +} + +s32 PS4_SYSV_ABI sceNpAuthDeleteRequest(s32 id) { + LOG_WARNING(Lib_NpAuth, "(DUMMY) called"); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceNpAuthGetAuthorizationCodeA() { + LOG_ERROR(Lib_NpAuth, "(STUBBED) called"); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceNpAuthGetAuthorizationCodeV3() { + LOG_ERROR(Lib_NpAuth, "(STUBBED) called"); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceNpAuthGetIdTokenA() { + LOG_ERROR(Lib_NpAuth, "(STUBBED) called"); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceNpAuthGetIdTokenV3() { + LOG_ERROR(Lib_NpAuth, "(STUBBED) called"); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceNpAuthPollAsync() { + LOG_ERROR(Lib_NpAuth, "(STUBBED) called"); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceNpAuthSetTimeout() { + LOG_ERROR(Lib_NpAuth, "(STUBBED) called"); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceNpAuthWaitAsync() { + LOG_ERROR(Lib_NpAuth, "(STUBBED) called"); + return ORBIS_OK; +} + +void RegisterlibSceNpAuth(Core::Loader::SymbolsResolver* sym) { + LIB_FUNCTION("KxGkOrQJTqY", "libSceNpAuthCompat", 1, "libSceNpAuth", 1, 1, + sceNpAuthGetAuthorizationCode); + LIB_FUNCTION("uaB-LoJqHis", "libSceNpAuthCompat", 1, "libSceNpAuth", 1, 1, sceNpAuthGetIdToken); + LIB_FUNCTION("cE7wIsqXdZ8", "libSceNpAuth", 1, "libSceNpAuth", 1, 1, sceNpAuthAbortRequest); + LIB_FUNCTION("N+mr7GjTvr8", "libSceNpAuth", 1, "libSceNpAuth", 1, 1, + sceNpAuthCreateAsyncRequest); + LIB_FUNCTION("6bwFkosYRQg", "libSceNpAuth", 1, "libSceNpAuth", 1, 1, sceNpAuthCreateRequest); + LIB_FUNCTION("H8wG9Bk-nPc", "libSceNpAuth", 1, "libSceNpAuth", 1, 1, sceNpAuthDeleteRequest); + LIB_FUNCTION("KxGkOrQJTqY", "libSceNpAuth", 1, "libSceNpAuth", 1, 1, + sceNpAuthGetAuthorizationCode); + LIB_FUNCTION("qAUXQ9GdWp8", "libSceNpAuth", 1, "libSceNpAuth", 1, 1, + sceNpAuthGetAuthorizationCodeA); + LIB_FUNCTION("KI4dHLlTNl0", "libSceNpAuth", 1, "libSceNpAuth", 1, 1, + sceNpAuthGetAuthorizationCodeV3); + LIB_FUNCTION("uaB-LoJqHis", "libSceNpAuth", 1, "libSceNpAuth", 1, 1, sceNpAuthGetIdToken); + LIB_FUNCTION("CocbHVIKPE8", "libSceNpAuth", 1, "libSceNpAuth", 1, 1, sceNpAuthGetIdTokenA); + LIB_FUNCTION("RdsFVsgSpZY", "libSceNpAuth", 1, "libSceNpAuth", 1, 1, sceNpAuthGetIdTokenV3); + LIB_FUNCTION("gjSyfzSsDcE", "libSceNpAuth", 1, "libSceNpAuth", 1, 1, sceNpAuthPollAsync); + LIB_FUNCTION("PM3IZCw-7m0", "libSceNpAuth", 1, "libSceNpAuth", 1, 1, sceNpAuthSetTimeout); + LIB_FUNCTION("SK-S7daqJSE", "libSceNpAuth", 1, "libSceNpAuth", 1, 1, sceNpAuthWaitAsync); +}; + +} // namespace Libraries::NpAuth \ No newline at end of file diff --git a/src/core/libraries/np_auth/np_auth.h b/src/core/libraries/np_auth/np_auth.h new file mode 100644 index 000000000..a6a66b452 --- /dev/null +++ b/src/core/libraries/np_auth/np_auth.h @@ -0,0 +1,29 @@ +// 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::NpAuth { + +s32 PS4_SYSV_ABI sceNpAuthGetAuthorizationCode(); +s32 PS4_SYSV_ABI sceNpAuthGetIdToken(); +s32 PS4_SYSV_ABI sceNpAuthAbortRequest(); +s32 PS4_SYSV_ABI sceNpAuthCreateAsyncRequest(); +s32 PS4_SYSV_ABI sceNpAuthCreateRequest(); +s32 PS4_SYSV_ABI sceNpAuthDeleteRequest(s32 id); +s32 PS4_SYSV_ABI sceNpAuthGetAuthorizationCodeA(); +s32 PS4_SYSV_ABI sceNpAuthGetAuthorizationCodeV3(); +s32 PS4_SYSV_ABI sceNpAuthGetIdTokenA(); +s32 PS4_SYSV_ABI sceNpAuthGetIdTokenV3(); +s32 PS4_SYSV_ABI sceNpAuthPollAsync(); +s32 PS4_SYSV_ABI sceNpAuthSetTimeout(); +s32 PS4_SYSV_ABI sceNpAuthWaitAsync(); + +void RegisterlibSceNpAuth(Core::Loader::SymbolsResolver* sym); +} // namespace Libraries::NpAuth \ No newline at end of file diff --git a/src/core/libraries/system/sysmodule.cpp b/src/core/libraries/system/sysmodule.cpp index 6c73764f2..d9e78e4ab 100644 --- a/src/core/libraries/system/sysmodule.cpp +++ b/src/core/libraries/system/sysmodule.cpp @@ -19,11 +19,40 @@ int PS4_SYSV_ABI sceSysmoduleGetModuleHandleInternal() { return ORBIS_OK; } -s32 PS4_SYSV_ABI sceSysmoduleGetModuleInfoForUnwind(VAddr addr, s32 flags, void* info) { - LOG_ERROR(Lib_SysModule, "(STUBBED) called"); - Kernel::OrbisModuleInfoForUnwind module_info; - module_info.st_size = 0x130; - s32 res = Kernel::sceKernelGetModuleInfoForUnwind(addr, flags, &module_info); +s32 PS4_SYSV_ABI sceSysmoduleGetModuleInfoForUnwind(VAddr addr, s32 flags, + Kernel::OrbisModuleInfoForUnwind* info) { + LOG_TRACE(Lib_SysModule, "sceSysmoduleGetModuleInfoForUnwind(addr=0x{:X}, flags=0x{:X})", addr, + flags); + + s32 res = Kernel::sceKernelGetModuleInfoForUnwind(addr, flags, info); + if (res != 0) { + return res; + } + + static constexpr std::array modules_to_hide = { + "libc.prx", + "libc.sprx", + "libSceAudioLatencyEstimation.prx", + "libSceFace.prx", + "libSceFaceTracker.prx", + "libSceFios2.prx", + "libSceFios2.sprx", + "libSceFontGsm.prx", + "libSceHand.prx", + "libSceHandTracker.prx", + "libSceHeadTracker.prx", + "libSceJobManager.prx", + "libSceNpCppWebApi.prx", + "libSceNpToolkit.prx", + "libSceNpToolkit2.prx", + "libSceS3DConversion.prx", + "libSceSmart.prx", + }; + + const std::string_view module_name = info->name.data(); + if (std::ranges::find(modules_to_hide, module_name) != modules_to_hide.end()) { + std::ranges::fill(info->name, '\0'); + } return res; } @@ -56,7 +85,6 @@ int PS4_SYSV_ABI sceSysmoduleIsLoadedInternal(OrbisSysModuleInternal id) { } int PS4_SYSV_ABI sceSysmoduleLoadModule(OrbisSysModule id) { - auto color_name = magic_enum::enum_name(id); LOG_ERROR(Lib_SysModule, "(DUMMY) called module = {}", magic_enum::enum_name(id)); return ORBIS_OK; } diff --git a/src/core/libraries/system/sysmodule.h b/src/core/libraries/system/sysmodule.h index dfbdca162..9a5fe9513 100644 --- a/src/core/libraries/system/sysmodule.h +++ b/src/core/libraries/system/sysmodule.h @@ -4,6 +4,7 @@ #pragma once #include "common/types.h" +#include "core/libraries/kernel/process.h" namespace Core::Loader { class SymbolsResolver; @@ -152,7 +153,8 @@ enum class OrbisSysModuleInternal : u32 { }; int PS4_SYSV_ABI sceSysmoduleGetModuleHandleInternal(); -s32 PS4_SYSV_ABI sceSysmoduleGetModuleInfoForUnwind(VAddr addr, s32 flags, void* info); +s32 PS4_SYSV_ABI sceSysmoduleGetModuleInfoForUnwind(VAddr addr, s32 flags, + Kernel::OrbisModuleInfoForUnwind* info); int PS4_SYSV_ABI sceSysmoduleIsCalledFromSysModule(); int PS4_SYSV_ABI sceSysmoduleIsCameraPreloaded(); int PS4_SYSV_ABI sceSysmoduleIsLoaded(OrbisSysModule id); diff --git a/src/core/linker.cpp b/src/core/linker.cpp index 4ccb9d943..0f86376af 100644 --- a/src/core/linker.cpp +++ b/src/core/linker.cpp @@ -108,8 +108,8 @@ void Linker::Execute(const std::vector args) { static constexpr s64 InternalMemorySize = 0x1000000; void* addr_out{reinterpret_cast(KernelAllocBase)}; - const s32 ret = Libraries::Kernel::sceKernelMapNamedFlexibleMemory( - &addr_out, InternalMemorySize, 3, 0, "SceKernelInternalMemory"); + s32 ret = Libraries::Kernel::sceKernelMapNamedFlexibleMemory(&addr_out, InternalMemorySize, 3, + 0, "SceKernelInternalMemory"); ASSERT_MSG(ret == 0, "Unable to perform sceKernelInternalMemory mapping"); main_thread.Run([this, module, args](std::stop_token) { diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 8b108a654..494ffa70c 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -139,35 +139,33 @@ PAddr MemoryManager::Allocate(PAddr search_start, PAddr search_end, size_t size, alignment = alignment > 0 ? alignment : 16_KB; auto dmem_area = FindDmemArea(search_start); + auto mapping_start = search_start > dmem_area->second.base + ? Common::AlignUp(search_start, alignment) + : Common::AlignUp(dmem_area->second.base, alignment); + auto mapping_end = mapping_start + size; - const auto is_suitable = [&] { - if (dmem_area == dmem_map.end()) { - return false; - } - const auto aligned_base = Common::AlignUp(dmem_area->second.base, alignment); - const auto alignment_size = aligned_base - dmem_area->second.base; - const auto remaining_size = - dmem_area->second.size >= alignment_size ? dmem_area->second.size - alignment_size : 0; - return dmem_area->second.is_free && remaining_size >= size; - }; - while (dmem_area != dmem_map.end() && !is_suitable() && - dmem_area->second.GetEnd() <= search_end) { - ++dmem_area; + // Find the first free, large enough dmem area in the range. + while ((!dmem_area->second.is_free || dmem_area->second.GetEnd() < mapping_end) && + dmem_area != dmem_map.end()) { + // The current dmem_area isn't suitable, move to the next one. + dmem_area++; + + // Update local variables based on the new dmem_area + mapping_start = Common::AlignUp(dmem_area->second.base, alignment); + mapping_end = mapping_start + size; } - if (!is_suitable()) { + + if (dmem_area == dmem_map.end()) { + // There are no suitable mappings in this range LOG_ERROR(Kernel_Vmm, "Unable to find free direct memory area: size = {:#x}", size); return -1; } - // Align free position - PAddr free_addr = dmem_area->second.base; - free_addr = Common::AlignUp(free_addr, alignment); - // Add the allocated region to the list and commit its pages. - auto& area = CarveDmemArea(free_addr, size)->second; + auto& area = CarveDmemArea(mapping_start, size)->second; area.memory_type = memory_type; area.is_free = false; - return free_addr; + return mapping_start; } void MemoryManager::Free(PAddr phys_addr, size_t size) { @@ -632,17 +630,34 @@ int MemoryManager::DirectQueryAvailable(PAddr search_start, PAddr search_end, si auto dmem_area = FindDmemArea(search_start); PAddr paddr{}; size_t max_size{}; - while (dmem_area != dmem_map.end() && dmem_area->second.GetEnd() <= search_end) { + + while (dmem_area != dmem_map.end()) { if (!dmem_area->second.is_free) { dmem_area++; continue; } - const auto aligned_base = alignment > 0 ? Common::AlignUp(dmem_area->second.base, alignment) - : dmem_area->second.base; + auto aligned_base = alignment > 0 ? Common::AlignUp(dmem_area->second.base, alignment) + : dmem_area->second.base; const auto alignment_size = aligned_base - dmem_area->second.base; - const auto remaining_size = + auto remaining_size = dmem_area->second.size >= alignment_size ? dmem_area->second.size - alignment_size : 0; + + if (dmem_area->second.base < search_start) { + // We need to trim remaining_size to ignore addresses before search_start + remaining_size = remaining_size > (search_start - dmem_area->second.base) + ? remaining_size - (search_start - dmem_area->second.base) + : 0; + aligned_base = alignment > 0 ? Common::AlignUp(search_start, alignment) : search_start; + } + + if (dmem_area->second.GetEnd() > search_end) { + // We need to trim remaining_size to ignore addresses beyond search_end + remaining_size = remaining_size > (dmem_area->second.GetEnd() - search_end) + ? remaining_size - (dmem_area->second.GetEnd() - search_end) + : 0; + } + if (remaining_size > max_size) { paddr = aligned_base; max_size = remaining_size; diff --git a/src/qt_gui/kbm_gui.cpp b/src/qt_gui/kbm_gui.cpp index 8777dda95..15e9008ab 100644 --- a/src/qt_gui/kbm_gui.cpp +++ b/src/qt_gui/kbm_gui.cpp @@ -127,58 +127,9 @@ tr("Do you want to overwrite existing mappings with the mappings from the Common } void KBMSettings::ButtonConnects() { - connect(ui->CrossButton, &QPushButton::clicked, this, - [this]() { StartTimer(ui->CrossButton); }); - connect(ui->CircleButton, &QPushButton::clicked, this, - [this]() { StartTimer(ui->CircleButton); }); - connect(ui->TriangleButton, &QPushButton::clicked, this, - [this]() { StartTimer(ui->TriangleButton); }); - connect(ui->SquareButton, &QPushButton::clicked, this, - [this]() { StartTimer(ui->SquareButton); }); - - connect(ui->L1Button, &QPushButton::clicked, this, [this]() { StartTimer(ui->L1Button); }); - connect(ui->L2Button, &QPushButton::clicked, this, [this]() { StartTimer(ui->L2Button); }); - connect(ui->L3Button, &QPushButton::clicked, this, [this]() { StartTimer(ui->L3Button); }); - connect(ui->R1Button, &QPushButton::clicked, this, [this]() { StartTimer(ui->R1Button); }); - connect(ui->R2Button, &QPushButton::clicked, this, [this]() { StartTimer(ui->R2Button); }); - connect(ui->R3Button, &QPushButton::clicked, this, [this]() { StartTimer(ui->R3Button); }); - - connect(ui->TouchpadButton, &QPushButton::clicked, this, - [this]() { StartTimer(ui->TouchpadButton); }); - connect(ui->OptionsButton, &QPushButton::clicked, this, - [this]() { StartTimer(ui->OptionsButton); }); - - connect(ui->DpadUpButton, &QPushButton::clicked, this, - [this]() { StartTimer(ui->DpadUpButton); }); - connect(ui->DpadDownButton, &QPushButton::clicked, this, - [this]() { StartTimer(ui->DpadDownButton); }); - connect(ui->DpadLeftButton, &QPushButton::clicked, this, - [this]() { StartTimer(ui->DpadLeftButton); }); - connect(ui->DpadRightButton, &QPushButton::clicked, this, - [this]() { StartTimer(ui->DpadRightButton); }); - - connect(ui->LStickUpButton, &QPushButton::clicked, this, - [this]() { StartTimer(ui->LStickUpButton); }); - connect(ui->LStickDownButton, &QPushButton::clicked, this, - [this]() { StartTimer(ui->LStickDownButton); }); - connect(ui->LStickLeftButton, &QPushButton::clicked, this, - [this]() { StartTimer(ui->LStickLeftButton); }); - connect(ui->LStickRightButton, &QPushButton::clicked, this, - [this]() { StartTimer(ui->LStickRightButton); }); - - connect(ui->RStickUpButton, &QPushButton::clicked, this, - [this]() { StartTimer(ui->RStickUpButton); }); - connect(ui->RStickDownButton, &QPushButton::clicked, this, - [this]() { StartTimer(ui->RStickDownButton); }); - connect(ui->RStickLeftButton, &QPushButton::clicked, this, - [this]() { StartTimer(ui->RStickLeftButton); }); - connect(ui->RStickRightButton, &QPushButton::clicked, this, - [this]() { StartTimer(ui->RStickRightButton); }); - - connect(ui->LHalfButton, &QPushButton::clicked, this, - [this]() { StartTimer(ui->LHalfButton); }); - connect(ui->RHalfButton, &QPushButton::clicked, this, - [this]() { StartTimer(ui->RHalfButton); }); + for (auto& button : ButtonsList) { + connect(button, &QPushButton::clicked, this, [this, &button]() { StartTimer(button); }); + } } void KBMSettings::DisableMappingButtons() { @@ -657,21 +608,28 @@ void KBMSettings::CheckMapping(QPushButton*& button) { MappingTimer -= 1; button->setText(tr("Press a key") + " [" + QString::number(MappingTimer) + "]"); + if (pressedKeys.size() > 0) { + QStringList keyStrings; + + for (const QString& buttonAction : pressedKeys) { + keyStrings << buttonAction; + } + + QString combo = keyStrings.join(","); + SetMapping(combo); + MappingCompleted = true; + EnableMapping = false; + + MappingButton->setText(combo); + pressedKeys.clear(); + timer->stop(); + } if (MappingCompleted) { EnableMapping = false; EnableMappingButtons(); timer->stop(); - if (mapping == "lshift" || mapping == "lalt" || mapping == "lctrl" || mapping == "lmeta" || - mapping == "lwin") { - modifier = ""; - } - - if (modifier != "") { - button->setText(modifier + ", " + mapping); - } else { - button->setText(mapping); - } + button->setText(mapping); } if (MappingTimer <= 0) { @@ -696,322 +654,346 @@ bool KBMSettings::eventFilter(QObject* obj, QEvent* event) { } if (EnableMapping) { - if (Qt::ShiftModifier & QApplication::keyboardModifiers()) { - modifier = "lshift"; - } else if (Qt::AltModifier & QApplication::keyboardModifiers()) { - modifier = "lalt"; - } else if (Qt::ControlModifier & QApplication::keyboardModifiers()) { - modifier = "lctrl"; - } else if (Qt::MetaModifier & QApplication::keyboardModifiers()) { -#ifdef _WIN32 - modifier = "lwin"; -#else - modifier = "lmeta"; -#endif - } - if (event->type() == QEvent::KeyPress) { QKeyEvent* keyEvent = static_cast(event); + if (keyEvent->isAutoRepeat()) + return true; + + if (pressedKeys.size() >= 3) { + return true; + } + switch (keyEvent->key()) { case Qt::Key_Space: - SetMapping("space"); + pressedKeys.insert("space"); break; case Qt::Key_Comma: if (Qt::KeypadModifier & QApplication::keyboardModifiers()) { - SetMapping("kpcomma"); + pressedKeys.insert("kpcomma"); } else { - SetMapping("comma"); + pressedKeys.insert("comma"); } break; case Qt::Key_Period: if (Qt::KeypadModifier & QApplication::keyboardModifiers()) { - SetMapping("kpperiod"); + pressedKeys.insert("kpperiod"); } else { - SetMapping("period"); + pressedKeys.insert("period"); } break; case Qt::Key_Slash: if (Qt::KeypadModifier & QApplication::keyboardModifiers()) - SetMapping("kpdivide"); + pressedKeys.insert("kpdivide"); break; case Qt::Key_Asterisk: if (Qt::KeypadModifier & QApplication::keyboardModifiers()) - SetMapping("kpmultiply"); + pressedKeys.insert("kpmultiply"); break; case Qt::Key_Question: - SetMapping("question"); + pressedKeys.insert("question"); break; case Qt::Key_Semicolon: - SetMapping("semicolon"); + pressedKeys.insert("semicolon"); break; case Qt::Key_Minus: if (Qt::KeypadModifier & QApplication::keyboardModifiers()) { - SetMapping("kpminus"); + pressedKeys.insert("kpminus"); } else { - SetMapping("minus"); + pressedKeys.insert("minus"); } break; case Qt::Key_Plus: if (Qt::KeypadModifier & QApplication::keyboardModifiers()) { - SetMapping("kpplus"); + pressedKeys.insert("kpplus"); } else { - SetMapping("plus"); + pressedKeys.insert("plus"); } break; case Qt::Key_ParenLeft: - SetMapping("lparenthesis"); + pressedKeys.insert("lparenthesis"); break; case Qt::Key_ParenRight: - SetMapping("rparenthesis"); + pressedKeys.insert("rparenthesis"); break; case Qt::Key_BracketLeft: - SetMapping("lbracket"); + pressedKeys.insert("lbracket"); break; case Qt::Key_BracketRight: - SetMapping("rbracket"); + pressedKeys.insert("rbracket"); break; case Qt::Key_BraceLeft: - SetMapping("lbrace"); + pressedKeys.insert("lbrace"); break; case Qt::Key_BraceRight: - SetMapping("rbrace"); + pressedKeys.insert("rbrace"); break; case Qt::Key_Backslash: - SetMapping("backslash"); + pressedKeys.insert("backslash"); break; case Qt::Key_Tab: - SetMapping("tab"); + pressedKeys.insert("tab"); break; case Qt::Key_Backspace: - SetMapping("backspace"); + pressedKeys.insert("backspace"); break; case Qt::Key_Return: - SetMapping("enter"); + pressedKeys.insert("enter"); break; case Qt::Key_Enter: - SetMapping("kpenter"); + pressedKeys.insert("kpenter"); + break; + case Qt::Key_Home: + pressedKeys.insert("home"); + break; + case Qt::Key_End: + pressedKeys.insert("end"); + break; + case Qt::Key_PageDown: + pressedKeys.insert("pgdown"); + break; + case Qt::Key_PageUp: + pressedKeys.insert("pgup"); + break; + case Qt::Key_CapsLock: + pressedKeys.insert("capslock"); break; case Qt::Key_Escape: - SetMapping("unmapped"); + pressedKeys.insert("unmapped"); break; case Qt::Key_Shift: - SetMapping("lshift"); + if (keyEvent->nativeScanCode() == rshift) { + pressedKeys.insert("rshift"); + } else { + pressedKeys.insert("lshift"); + } break; case Qt::Key_Alt: - SetMapping("lalt"); + if (keyEvent->nativeScanCode() == ralt) { + pressedKeys.insert("ralt"); + } else { + pressedKeys.insert("lalt"); + } break; case Qt::Key_Control: - SetMapping("lctrl"); + if (keyEvent->nativeScanCode() == rctrl) { + pressedKeys.insert("rctrl"); + } else { + pressedKeys.insert("lctrl"); + } break; case Qt::Key_Meta: activateWindow(); #ifdef _WIN32 - SetMapping("lwin"); + pressedKeys.insert("lwin"); #else - SetMapping("lmeta"); + pressedKeys.insert("lmeta"); #endif case Qt::Key_1: if (Qt::KeypadModifier & QApplication::keyboardModifiers()) { - SetMapping("kp1"); + pressedKeys.insert("kp1"); } else { - SetMapping("1"); + pressedKeys.insert("1"); } break; case Qt::Key_2: if (Qt::KeypadModifier & QApplication::keyboardModifiers()) { - SetMapping("kp2"); + pressedKeys.insert("kp2"); } else { - SetMapping("2"); + pressedKeys.insert("2"); } break; case Qt::Key_3: if (Qt::KeypadModifier & QApplication::keyboardModifiers()) { - SetMapping("kp3"); + pressedKeys.insert("kp3"); } else { - SetMapping("3"); + pressedKeys.insert("3"); } break; case Qt::Key_4: if (Qt::KeypadModifier & QApplication::keyboardModifiers()) { - SetMapping("kp4"); + pressedKeys.insert("kp4"); } else { - SetMapping("4"); + pressedKeys.insert("4"); } break; case Qt::Key_5: if (Qt::KeypadModifier & QApplication::keyboardModifiers()) { - SetMapping("kp5"); + pressedKeys.insert("kp5"); } else { - SetMapping("5"); + pressedKeys.insert("5"); } break; case Qt::Key_6: if (Qt::KeypadModifier & QApplication::keyboardModifiers()) { - SetMapping("kp6"); + pressedKeys.insert("kp6"); } else { - SetMapping("6"); + pressedKeys.insert("6"); } break; case Qt::Key_7: if (Qt::KeypadModifier & QApplication::keyboardModifiers()) { - SetMapping("kp7"); + pressedKeys.insert("kp7"); } else { - SetMapping("7"); + pressedKeys.insert("7"); } break; case Qt::Key_8: if (Qt::KeypadModifier & QApplication::keyboardModifiers()) { - SetMapping("kp8"); + pressedKeys.insert("kp8"); } else { - SetMapping("8"); + pressedKeys.insert("8"); } break; case Qt::Key_9: if (Qt::KeypadModifier & QApplication::keyboardModifiers()) { - SetMapping("kp9"); + pressedKeys.insert("kp9"); } else { - SetMapping("9"); + pressedKeys.insert("9"); } break; case Qt::Key_0: if (Qt::KeypadModifier & QApplication::keyboardModifiers()) { - SetMapping("kp0"); + pressedKeys.insert("kp0"); } else { - SetMapping("0"); + pressedKeys.insert("0"); } break; case Qt::Key_Up: activateWindow(); - SetMapping("up"); + pressedKeys.insert("up"); break; case Qt::Key_Down: - SetMapping("down"); + pressedKeys.insert("down"); break; case Qt::Key_Left: - SetMapping("left"); + pressedKeys.insert("left"); break; case Qt::Key_Right: - SetMapping("right"); + pressedKeys.insert("right"); break; case Qt::Key_A: - SetMapping("a"); + pressedKeys.insert("a"); break; case Qt::Key_B: - SetMapping("b"); + pressedKeys.insert("b"); break; case Qt::Key_C: - SetMapping("c"); + pressedKeys.insert("c"); break; case Qt::Key_D: - SetMapping("d"); + pressedKeys.insert("d"); break; case Qt::Key_E: - SetMapping("e"); + pressedKeys.insert("e"); break; case Qt::Key_F: - SetMapping("f"); + pressedKeys.insert("f"); break; case Qt::Key_G: - SetMapping("g"); + pressedKeys.insert("g"); break; case Qt::Key_H: - SetMapping("h"); + pressedKeys.insert("h"); break; case Qt::Key_I: - SetMapping("i"); + pressedKeys.insert("i"); break; case Qt::Key_J: - SetMapping("j"); + pressedKeys.insert("j"); break; case Qt::Key_K: - SetMapping("k"); + pressedKeys.insert("k"); break; case Qt::Key_L: - SetMapping("l"); + pressedKeys.insert("l"); break; case Qt::Key_M: - SetMapping("m"); + pressedKeys.insert("m"); break; case Qt::Key_N: - SetMapping("n"); + pressedKeys.insert("n"); break; case Qt::Key_O: - SetMapping("o"); + pressedKeys.insert("o"); break; case Qt::Key_P: - SetMapping("p"); + pressedKeys.insert("p"); break; case Qt::Key_Q: - SetMapping("q"); + pressedKeys.insert("q"); break; case Qt::Key_R: - SetMapping("r"); + pressedKeys.insert("r"); break; case Qt::Key_S: - SetMapping("s"); + pressedKeys.insert("s"); break; case Qt::Key_T: - SetMapping("t"); + pressedKeys.insert("t"); break; case Qt::Key_U: - SetMapping("u"); + pressedKeys.insert("u"); break; case Qt::Key_V: - SetMapping("v"); + pressedKeys.insert("v"); break; case Qt::Key_W: - SetMapping("w"); + pressedKeys.insert("w"); break; case Qt::Key_X: - SetMapping("x"); + pressedKeys.insert("x"); break; case Qt::Key_Y: - SetMapping("Y"); + pressedKeys.insert("Y"); break; case Qt::Key_Z: - SetMapping("z"); + pressedKeys.insert("z"); break; default: break; } return true; } + } - if (event->type() == QEvent::MouseButtonPress) { - QMouseEvent* mouseEvent = static_cast(event); + if (event->type() == QEvent::MouseButtonPress) { + QMouseEvent* mouseEvent = static_cast(event); + if (pressedKeys.size() < 3) { switch (mouseEvent->button()) { case Qt::LeftButton: - SetMapping("leftbutton"); + pressedKeys.insert("leftbutton"); break; case Qt::RightButton: - SetMapping("rightbutton"); + pressedKeys.insert("rightbutton"); break; case Qt::MiddleButton: - SetMapping("middlebutton"); + pressedKeys.insert("middlebutton"); break; default: break; } return true; } + } - const QList AxisList = { - ui->LStickUpButton, ui->LStickDownButton, ui->LStickLeftButton, ui->LStickRightButton, - ui->RStickUpButton, ui->LStickDownButton, ui->LStickLeftButton, ui->RStickRightButton}; + const QList AxisList = { + ui->LStickUpButton, ui->LStickDownButton, ui->LStickLeftButton, ui->LStickRightButton, + ui->RStickUpButton, ui->LStickDownButton, ui->LStickLeftButton, ui->RStickRightButton}; - if (event->type() == QEvent::Wheel) { - QWheelEvent* wheelEvent = static_cast(event); + if (event->type() == QEvent::Wheel) { + QWheelEvent* wheelEvent = static_cast(event); + if (pressedKeys.size() < 3) { if (wheelEvent->angleDelta().y() > 5) { if (std::find(AxisList.begin(), AxisList.end(), MappingButton) == AxisList.end()) { - SetMapping("mousewheelup"); + pressedKeys.insert("mousewheelup"); } else { QMessageBox::information(this, tr("Cannot set mapping"), tr("Mousewheel cannot be mapped to stick outputs")); } } else if (wheelEvent->angleDelta().y() < -5) { if (std::find(AxisList.begin(), AxisList.end(), MappingButton) == AxisList.end()) { - SetMapping("mousewheeldown"); + pressedKeys.insert("mousewheeldown"); } else { QMessageBox::information(this, tr("Cannot set mapping"), tr("Mousewheel cannot be mapped to stick outputs")); @@ -1021,9 +1003,9 @@ bool KBMSettings::eventFilter(QObject* obj, QEvent* event) { if (std::find(AxisList.begin(), AxisList.end(), MappingButton) == AxisList.end()) { // QT changes scrolling to horizontal for all widgets with the alt modifier if (Qt::AltModifier & QApplication::keyboardModifiers()) { - SetMapping("mousewheelup"); + pressedKeys.insert("mousewheelup"); } else { - SetMapping("mousewheelright"); + pressedKeys.insert("mousewheelright"); } } else { QMessageBox::information(this, tr("Cannot set mapping"), @@ -1032,18 +1014,18 @@ bool KBMSettings::eventFilter(QObject* obj, QEvent* event) { } else if (wheelEvent->angleDelta().x() < -5) { if (std::find(AxisList.begin(), AxisList.end(), MappingButton) == AxisList.end()) { if (Qt::AltModifier & QApplication::keyboardModifiers()) { - SetMapping("mousewheeldown"); + pressedKeys.insert("mousewheeldown"); } else { - SetMapping("mousewheelleft"); + pressedKeys.insert("mousewheelleft"); } } else { QMessageBox::information(this, tr("Cannot set mapping"), tr("Mousewheel cannot be mapped to stick outputs")); } } - return true; } } + return QDialog::eventFilter(obj, event); } diff --git a/src/qt_gui/kbm_gui.h b/src/qt_gui/kbm_gui.h index 06e58eef6..bfeed2b01 100644 --- a/src/qt_gui/kbm_gui.h +++ b/src/qt_gui/kbm_gui.h @@ -25,6 +25,22 @@ private: std::unique_ptr ui; std::shared_ptr m_game_info; +#ifdef _WIN32 + const int lctrl = 29; + const int rctrl = 57373; + const int lalt = 56; + const int ralt = 57400; + const int lshift = 42; + const int rshift = 54; +#else + const int lctrl = 37; + const int rctrl = 105; + const int lalt = 64; + const int ralt = 108; + const int lshift = 50; + const int rshift = 62; +#endif + bool eventFilter(QObject* obj, QEvent* event) override; void ButtonConnects(); void SetUIValuestoMappings(std::string config_id); @@ -33,6 +49,7 @@ private: void EnableMappingButtons(); void SetMapping(QString input); + QSet pressedKeys; bool EnableMapping = false; bool MappingCompleted = false; bool HelpWindowOpen = false; diff --git a/src/qt_gui/main_window_ui.h b/src/qt_gui/main_window_ui.h index 2c4d4480b..4d3481c07 100644 --- a/src/qt_gui/main_window_ui.h +++ b/src/qt_gui/main_window_ui.h @@ -106,8 +106,6 @@ public: toggleLabelsAct = new QAction(MainWindow); toggleLabelsAct->setObjectName("toggleLabelsAct"); - toggleLabelsAct->setText( - QCoreApplication::translate("MainWindow", "Show Labels Under Icons")); toggleLabelsAct->setCheckable(true); toggleLabelsAct->setChecked(Config::getShowLabelsUnderIcons()); @@ -413,6 +411,8 @@ public: setThemeTokyoNight->setText("Tokyo Night"); setThemeOled->setText("OLED"); toolBar->setWindowTitle(QCoreApplication::translate("MainWindow", "toolBar", nullptr)); + toggleLabelsAct->setText( + QCoreApplication::translate("MainWindow", "Show Labels Under Icons")); } // retranslateUi }; diff --git a/src/qt_gui/translations/ar_SA.ts b/src/qt_gui/translations/ar_SA.ts index f71ec7d3a..e434b3259 100644 --- a/src/qt_gui/translations/ar_SA.ts +++ b/src/qt_gui/translations/ar_SA.ts @@ -7,34 +7,34 @@ AboutDialog About shadPS4 - حول shadPS4 + حول محاكي الظل PS4 shadPS4 is an experimental open-source emulator for the PlayStation 4. - shadPS4 هو محاكي تجريبي مفتوح المصدر لجهاز PlayStation 4. + محاكي الظل هو محاكي تجريبي مفتوح المصدر مخصص لـ PS4 This software should not be used to play games you have not legally obtained. - يجب عدم استخدام هذا البرنامج لتشغيل الألعاب التي لم تحصل عليها بشكل قانوني. + لا تستخدم هذا البرنامج لتشغيل الألعاب بطريقة غير قانونية. CheatsPatches Cheats / Patches for - الغِشّ / التصحيحات + شفرات / إصلاحات لـ Cheats/Patches are experimental.\nUse with caution.\n\nDownload cheats individually by selecting the repository and clicking the download button.\nIn the Patches tab, you can download all patches at once, choose which ones you want to use, and save your selection.\n\nSince we do not develop the Cheats/Patches,\nplease report issues to the cheat author.\n\nCreated a new cheat? Visit:\n - الغش والتصحيحات هي ميزات تجريبية.\nاستخدمها بحذر.\n\nقم بتنزيل الغش بشكل فردي عن طريق اختيار المستودع والنقر على زر التنزيل.\nفي علامة تبويب التصحيحات، يمكنك تنزيل جميع التصحيحات دفعة واحدة، واختيار ما تريد استخدامه، وحفظ اختياراتك.\n\nنظرًا لأننا لا نقوم بتطوير الغش/التصحيحات،\nيرجى الإبلاغ عن أي مشاكل إلى مؤلف الغش.\n\nهل قمت بإنشاء غش جديد؟ قم بزيارة:\n + الشفرات والإصلاحات هي ميزات تجريبية.\nاستخدمها بحذر.\n\nقم بتنزيل الشفرات بشكل فردي عن طريق اختيار المستودع والضغط على تنزيل.\nفي علامة تبويب الإصلاحات، يمكنك تنزيل جميع الإصلاحات دفعة واحدة، واختيار ما تريد استخدامه، وحفظ اختياراتك.\n\nنظرًا لأننا لا نقوم بتطوير الشفرات والإصلاحات ،\nيرجى الإبلاغ عن أي مشاكل إلى مؤلف الشفرات.\n\nهل قمت بإنشاء شفرة جديد؟ قم بزيارة:\n No Image Available - لا تتوفر صورة + الصورة غير موجودة Serial: - الرقم التسلسلي: + الرَّقَم التسلسلي: Version: @@ -46,7 +46,7 @@ Select Cheat File: - اختر ملف الغش: + حدد مِلَفّ الشفرات: Repository: @@ -54,7 +54,7 @@ Download Cheats - تنزيل الغش + تحميل الشفرات Delete File @@ -66,19 +66,19 @@ You can delete the cheats you don't want after downloading them. - يمكنك حذف الغش الذي لا تريده بعد تنزيله. + يمكنك حذف الشفرات التي لا 'تريدها بعد تنزيلها. Do you want to delete the selected file?\n%1 - هل تريد حذف الملف المحدد؟\n%1 + هل ترغب في حذف الملف المحدد؟\n%1 Select Patch File: - اختر ملف التصحيح: + اختر مِلَف التصحيح: Download Patches - تنزيل التصحيحات + تحميل ملفات التصحيح Save @@ -86,7 +86,7 @@ Cheats - الغش + الشفرات Patches @@ -98,15 +98,15 @@ No patch selected. - لم يتم اختيار أي تصحيح. + لم يتم تحديد أي مِلَف تصحيح. Unable to open files.json for reading. - تعذر فتح files.json للقراءة. + تعذّر فتح مِلَف files.json للقراءة. No patch file found for the current serial. - لم يتم العثور على ملف تصحيح للرقم التسلسلي الحالي. + لم يتم العثور على مِلَف تصحيح للسيريال الحالي. Unable to open the file for reading. @@ -126,11 +126,11 @@ Options saved successfully. - تم حفظ الخيارات بنجاح. + تم حفظ الإعدادات. Invalid Source - مصدر غير صالح + المصدر غير صالح The selected source is invalid. @@ -138,11 +138,11 @@ File Exists - الملف موجود + المِلَف موجود مسبقًا File already exists. Do you want to replace it? - الملف موجود بالفعل. هل تريد استبداله؟ + المِلَف موجود مسبقًا. هل ترغب في استبداله؟ Failed to save file: @@ -154,19 +154,19 @@ Cheats Not Found - لم يتم العثور على الغش + لم يتم العثور على أي شفرات No Cheats found for this game in this version of the selected repository,try another repository or a different version of the game. - لم يتم العثور على غش لهذه اللعبة في هذا الإصدار من المستودع المحدد. حاول استخدام مستودع آخر أو إصدار آخر من اللعبة. + لم يتم العثور على شفرات لهذه اللعبة في هذا الإصدار من المستودع المحدد. جرّب مستودعًا آخر أو إصدارًا مختلفًا من اللعبة. Cheats Downloaded Successfully - تم تنزيل الغش بنجاح + تم تحميل الشفرات بنجاح You have successfully downloaded the cheats for this version of the game from the selected repository. You can try downloading from another repository, if it is available it will also be possible to use it by selecting the file from the list. - لقد نجحت في تنزيل الغش لهذا الإصدار من اللعبة من المستودع المحدد. يمكنك محاولة التنزيل من مستودع آخر. إذا كان متاحًا، يمكنك اختياره عن طريق تحديد الملف من القائمة. + تم تحميل الشفرات بنجاح لهذه النسخة من اللعبة من المستودع الذي اخترته. إذا أردت، يمكنك تجربة مستودع آخر، وإذا كان متاحًا، يمكنك استخدام الشفرات عن طريق اختيار الملف من القائمة. Failed to save: @@ -182,7 +182,7 @@ Patches Downloaded Successfully! All Patches available for all games have been downloaded, there is no need to download them individually for each game as happens in Cheats. If the patch does not appear, it may be that it does not exist for the specific serial and version of the game. - تم تنزيل التصحيحات بنجاح! تم تنزيل جميع التصحيحات لجميع الألعاب، ولا داعي لتنزيلها بشكل فردي لكل لعبة كما هو الحال مع الغش. إذا لم يظهر التحديث، قد يكون السبب أنه غير متوفر للإصدار وسيريال اللعبة المحدد. + تم تنزيل التصحيحات بنجاح! تم تنزيل جميع التصحيحات المتوفرة لجميع الألعاب، ولا حاجة إلى تنزيلها بشكل فردي لكل لعبة كما هو الحال مع الشفرات. إذا لم يظهر التصحيح، فقد لا يكون متوفرًا للسيريال أو الإصدار المحدد من اللعبة. Failed to parse JSON data from HTML. @@ -190,15 +190,15 @@ Failed to retrieve HTML page. - .HTML فشل في استرجاع صفحة + فشل في جلب صفحة HTML. The game is in version: %1 - اللعبة في الإصدار: %1 + إصدار اللعبة الحالي: %1 The downloaded patch only works on version: %1 - الباتش الذي تم تنزيله يعمل فقط على الإصدار: %1 + التصحيح الذي تم تنزيله يعمل فقط مع الإصدار:%1 You may need to update your game. @@ -206,7 +206,7 @@ Incompatibility Notice - إشعار عدم التوافق + إشعار بعدم التوافق Failed to open file: @@ -238,7 +238,7 @@ Can't apply cheats before the game is started - لا يمكن تطبيق الغش قبل بدء اللعبة. + لا 'يمكن تطبيق الشفرات قبل بَدْء اللعبة Close @@ -249,7 +249,7 @@ CheckUpdate Auto Updater - محدث تلقائي + التحديثات التلقائية Error @@ -261,7 +261,7 @@ The Auto Updater allows up to 60 update checks per hour.\nYou have reached this limit. Please try again later. - يتيح التحديث التلقائي ما يصل إلى 60 عملية تحقق من التحديث في الساعة.\nلقد وصلت إلى هذا الحد. الرجاء المحاولة مرة أخرى لاحقًا. + تسمح التحديثات التلقائية بـ 60 عملية تحقق من التحديث في الساعة.\nلقد وصلت إلى الحد المسموح به. الرجاء المحاولة لاحقًا. Failed to parse update information. @@ -329,7 +329,7 @@ Network error occurred while trying to access the URL - حدث خطأ في الشبكة أثناء محاولة الوصول إلى عنوان URL + حدث خطأ في الشبكة عند محاولة الوصول إلى الموقع Download Complete @@ -388,11 +388,11 @@ Boots - أحذية + إقلاع Menus - قوائم + القائمة Ingame @@ -407,7 +407,7 @@ ControlSettings Configure Controls - تعديل عناصر التحكم + إعدادات التحكم D-Pad @@ -431,11 +431,11 @@ Left Stick Deadzone (def:2 max:127) - مدى تسجيل الإدخال للعصا اليسرى (التلقائي:2 حد أقصى:127) + النقطة العمياء للعصا اليسرى (الافتراضي: 2، الحد الأقصى: 127) Left Deadzone - إعدادات مدى تسجيل الإدخال لعصا التحكم اليسرى + النقطة العمياء لليسار Left Stick @@ -507,11 +507,11 @@ Right Stick Deadzone (def:2, max:127) - مدى تسجيل الإدخال للعصا اليمنى (التلقائي:2 حد أقصى:127) + النقطة العمياء للعصا اليمنى (الافتراضي: 2، الحد الأقصى: 127) Right Deadzone - إعدادات مدى تسجيل الإدخال لعصا التحكم اليمنى + النقطة العمياء اليمنى Right Stick @@ -617,7 +617,7 @@ ElfViewer Open Folder - فتح المجلد + افتح مجلد @@ -647,7 +647,7 @@ Browse - تصفح + استعراض Error @@ -718,15 +718,15 @@ Compatibility is untested - التوافق غير مختبر + لم يتم اختبار التوافق Game does not initialize properly / crashes the emulator - اللعبة لا تهيئ بشكل صحيح / تعطل المحاكي + اللعبة لا تبدأ بشكل صحيح / تتسبب في انهيار المحاكي Game boots, but only displays a blank screen - اللعبة تبدأ بالعمل، ولكن فقط تعرض شاشة فارغة + اللعبة تبدأ بالإقلاع، لكنها تعرض شاشة فارغة فقط Game displays an image but does not go past the menu @@ -734,15 +734,15 @@ Game has game-breaking glitches or unplayable performance - اللعبة بها قلتشات أو أداء غير قابل للتشغيل + اللعبة بها أخطاء جسيمة أو أداء يجعلها غير قابلة للعب Game can be completed with playable performance and no major glitches - يمكن الانتهاء من اللعبة مع الأداء القابل للتشغيل و لا توجد قلتشات كبيرة + يمكن إنهاء اللعبة بأداء جيد وبدون أعطال رئيسية Click to see details on github - انقر لرؤية التفاصيل على GitHub + اضغط لعرض التفاصيل على GitHub Last updated @@ -780,15 +780,15 @@ Cheats / Patches - الغش / التصحيحات + الشفرات / التصحيحات SFO Viewer - عارض SFO + عارض معلومات اللعبة (SFO) Trophy Viewer - عارض الجوائز + عارض الكؤوس Open Folder... @@ -820,11 +820,11 @@ Copy Version - إصدار النسخة + نسخ الإصدار Copy Size - حجم النسخة + نسخ حجم Copy All @@ -864,7 +864,7 @@ Submit a report - إرسال بلاغ + إرسال تقرير Shortcut creation @@ -888,7 +888,7 @@ This game has no update to delete! - لا تحتوي اللعبة على تحديث لحذفه! + لا يوجد تحديث لهذه اللعبة لحذفه! Update @@ -896,7 +896,7 @@ This game has no DLC to delete! - لا تحتوي اللعبة على DLC لحذفه! + لا توجد محتويات إضافية (DLC) لهذه اللعبة لحذفها! DLC @@ -916,11 +916,11 @@ Delete Save Data - حذف التخزينه + حذف بيانات الحفظ This game has no update folder to open! - لا تحتوي اللعبة على تحديث لفتحه! + لا يوجد مجلد تحديث لهذه اللعبة لفتحه! No log file found for this game! @@ -932,15 +932,15 @@ This game has no save data to delete! - هذه اللعبة لا تحتوي على أي تخزينات لحذفها! + لا توجد بيانات حفظ لهذه اللعبة لحذفها! This game has no saved trophies to delete! - هذه اللعبة ليس لديها كؤوس محفوظة للحذف! + لا توجد كؤوس محفوظة لهذه اللعبة لحذفها! Save Data - حفظ البيانات + بيانات الحفظ Trophy @@ -955,7 +955,7 @@ HelpDialog Quickstart - التشغيل السريع + البدء السريع FAQ @@ -963,22 +963,22 @@ Syntax - الصّيغة + البنية Special Bindings - إدخالات خاصة + الارتباطات الخاصة Keybindings - أزرار التحكم + تعيين الأزرار KBMSettings Configure Controls - تعديل عناصر التحكم + إعدادات جهاز التحكم D-Pad @@ -1026,7 +1026,7 @@ Use per-game configs - استخدام إعدادات كل لُعْبَة + استخدام إعدادات خاصة لكل لعبه L1 @@ -1038,7 +1038,7 @@ Text Editor - محرر النص + محرّر النصوص Help @@ -1058,15 +1058,15 @@ Touchpad Click - النقر على لوحة اللمس + زر لوحة اللمس Mouse to Joystick - الفأرة إلى عصا التحكم + تحويل الماوس إلى عصا التحكم *press F7 ingame to activate - * اضغط على F7 للتفعيل + * اضغط F7 داخل اللعبة للتفعيل R3 @@ -1078,15 +1078,15 @@ Mouse Movement Parameters - معطيات حركة الفأرة + إعدادات حركة الماوس note: click Help Button/Special Keybindings for more information - ملاحظة: انقر فوق زر المساعدة/روابط المفاتيح الخاصة للحصول على مزيد من المعلومات + ملاحظة: لمزيد من المعلومات عن التعيينات الخاصة، اضغط على زر المساعدة Face Buttons - أزرار الوجه + الأزرار الأمامية Triangle @@ -1106,11 +1106,11 @@ Right Analog Halfmode - تقليل سرعة عصا التحكم اليمنى للنصف + وضع النصف للعصا اليمنى (نصف الحساسية أو نصف الحركة) hold to move right stick at half-speed - الضغط باستمرار لتحريك العصا اليمنى بنصف السرعة + اضغط مع الاستمرار لتحريك العصا اليمنى بسرعة منخفضة Right Stick @@ -1118,15 +1118,15 @@ Speed Offset (def 0.125): - إزاحة السرعة (تلقائي 0.125): + تعويض السرعة (الافتراضي 0.125): Copy from Common Config - نسخ من الإعدادات الشائعة + نسخ من الإعدادات العامة Deadzone Offset (def 0.50): - إزاحة المدى الغير فعال (الأصل ٠.٥٠). + تعويض منطقة الخمول (الافتراضي 0.50): Speed Multiplier (def 1.0): @@ -1134,39 +1134,39 @@ Common Config Selected - الإعدادات الشائعة محدده + تم اختيار الإعدادات العامة This button copies mappings from the Common Config to the currently selected profile, and cannot be used when the currently selected profile is the Common Config. - هذا الزر يقوم بنسخ تعيينات الأزرار من إعدادات المستخدم العامة لإعدادات المستخدم المحددة حالياً، ولا يمكن استعماله عندما تكون الإعدادات المستخدمة هي الإعدادات العامة. + يقوم هذا الزر بنسخ التعيينات من الإعدادات العامة إلى الملف الشخصي المحدد حاليًا، ولا يمكن استخدامه إذا كانت الإعدادات العامة هي الملف المحدد. Copy values from Common Config - نسخ من الإعدادات الشائعة + نسخ القيم من الإعدادات العامة Do you want to overwrite existing mappings with the mappings from the Common Config? - هل تريد استبدال التعيينات الحالية بالتعيينات العامة؟ + هل تريد استبدال التعيينات الحالية بالتعيينات من الإعدادات العامة؟ Unable to Save - غير قادر على الحفظ + تعذّر الحفظ Cannot bind any unique input more than once - لا يمكن ربط أي إدخال فريد أكثر من مرة + لا يمكن تعيين نفس الزر لأكثر من وظيفة Press a key - اضغط على مفتاح + اضغط زرًا Cannot set mapping - لا يمكن تعيين الأزرار + تعذّر تعيين الزر Mousewheel cannot be mapped to stick outputs - عجلة الفأرة لا يمكن تعيينها لعصا التحكم + لا يمكن تعيين عجلة الفأرة لمخرجات العصا Save @@ -1189,7 +1189,7 @@ MainWindow Open/Add Elf Folder - Elf فتح/إضافة مجلد + فتح / إضافة مجلد Elf Boot Game @@ -1225,11 +1225,11 @@ Exit the application. - الخروج من التطبيق. + إغلاق التطبيق Show Game List - إظهار قائمة الألعاب + عرض قائمة الألعاب Game List Refresh @@ -1281,7 +1281,7 @@ No games found. Please add your games to your library first. - لم يتم العثور على ألعاب. الرجاء إضافة ألعابك إلى مكتبتك أولاً. + لم يتم العثور على ألعاب. يرجى إضافة ألعابك إلى المكتبة أولاً. Search... @@ -1345,7 +1345,7 @@ Game List - ققائمة الألعاب + قائمة الألعاب * Unsupported Vulkan Version @@ -1353,7 +1353,7 @@ Download Cheats For All Installed Games - تنزيل الغش لجميع الألعاب المثبتة + تحميل الشفرات لجميع الألعاب المثبتة Download Patches For All Games @@ -1365,7 +1365,7 @@ You have downloaded cheats for all the games you have installed. - لقد قمت بتنزيل الغش لجميع الألعاب التي قمت بتثبيتها. + تم تحميل الشفرات لجميع الألعاب المثبتة. Patches Downloaded Successfully! @@ -1409,11 +1409,11 @@ Play - أبدأ اللعب + تشغيل Pause - توقف مؤقت + إيقاف مؤقت Stop @@ -1425,11 +1425,11 @@ Full Screen - وضع ملء الشاشة + الشاشة الكاملة Controllers - أذرعة التحكم + وحدات التحكم Keyboard @@ -1445,7 +1445,7 @@ Show Labels Under Icons - إظهار العلامات أسفل الأيقونات + إظهار التسميات تحت الأيقونات @@ -1464,7 +1464,7 @@ Console Language - لغة وحدة التحكم + لغة النظام Emulator Language @@ -1476,11 +1476,11 @@ Default tab when opening settings - علامة التبويب الافتراضية عند فتح الإعدادات + التبويب الافتراضي عند فتح الإعدادات Show Game Size In List - عرض حجم اللعبة في القائمة + إظهار حجم اللعبة في القائمة Show Splash @@ -1496,7 +1496,7 @@ Trophy Key - زر الميداليات + مفتاح الكأس Trophy @@ -1504,11 +1504,11 @@ Open the custom trophy images/sounds folder - افتح مجلد تخصيص اصوات/صور الميداليات + فتح مجلد الصور/الأصوات المخصصة للكؤوس Logger - المسجل + سجل الأحداث Log Type @@ -1520,23 +1520,23 @@ Open Log Location - افتح موقع السجل + فتح موقع السجل Input - إدخال + إعدادات المدخلات Cursor - مؤشر + مؤشر الماوس Hide Cursor - إخفاء المؤشر + إخفاء مؤشر الماوس Hide Cursor Idle Timeout - مهلة إخفاء المؤشر عند الخمول + إخفاء المؤشر بعد فترة الخمول s @@ -1552,7 +1552,7 @@ Graphics - الرسومات + الرسوميات GUI @@ -1564,7 +1564,7 @@ Graphics Device - جهاز الرسومات + جهاز الرسوميات Vblank Divider @@ -1572,15 +1572,15 @@ Advanced - متقدم + الإعدادات المتقدمة Enable Shaders Dumping - تمكين تفريغ الشيدرات + تمكين تصدير الشيدرات Enable NULL GPU - تمكين وحدة معالجة الرسومات الفارغة + تمكين GPU فارغ Enable HDR @@ -1604,23 +1604,23 @@ Debug - تصحيح الأخطاء + التصحيح Enable Debug Dumping - تمكين تفريغ التصحيح + تمكين تصدير بيانات التصحيح Enable Vulkan Validation Layers - Vulkan تمكين طبقات التحقق من + تمكين طبقات التحقق لـ Vulkan Enable Vulkan Synchronization Validation - Vulkan تمكين التحقق من تزامن + تمكين التحقق من تزامن Vulkan Enable RenderDoc Debugging - RenderDoc تمكين تصحيح أخطاء + تمكين التصحيح باستخدام RenderDoc Enable Crash Diagnostics @@ -1628,19 +1628,19 @@ Collect Shaders - اجمع برامج التظليل + جمع الشيدرات Copy GPU Buffers - انسخ التخزين المؤقت لوحدة معالجة الرُسوم + نسخ مخازن الرسوميات Host Debug Markers - استضافة علامات التصحيح + علامات التصحيح على المضيف Guest Debug Markers - ضيف علامات التصحيح + علامات التصحيح على الضيف Update @@ -1648,11 +1648,11 @@ Check for Updates at Startup - تحقق من التحديثات عند بدء التشغيل + التحقق من التحديثات عند بدء التشغيل Always Show Changelog - اظهر سجل التغيرات دائماً + عرض سجل التغييرات دائمًا Update Channel @@ -1672,7 +1672,7 @@ Disable Trophy Notification - إغلاق إشعارات الميداليات + تعطيل إشعار التروفي Background Image @@ -1684,7 +1684,7 @@ Opacity - درجة السواد + الشفافية Play title music @@ -1692,7 +1692,7 @@ Update Compatibility Database On Startup - تحديث قاعدة بيانات التوافق عند التشغيل + تحديث بيانات التوافق تلقائيًا عند التشغيل Game Compatibility @@ -1700,7 +1700,7 @@ Display Compatibility Data - إظهار معلومات التوافق + عرض بيانات التوافق Update Compatibility Database @@ -1728,7 +1728,7 @@ Point your mouse at an option to display its description. - وجّه الماوس نحو خيار لعرض وصفه. + ✅ مرّر مؤشر الماوس على أي خِيار لعرض وصفه. Console Language:\nSets the language that the PS4 game uses.\nIt's recommended to set this to a language the game supports, which will vary by region. @@ -1736,11 +1736,11 @@ Emulator Language:\nSets the language of the emulator's user interface. - لغة المحاكي:\nتحدد لغة واجهة المستخدم الخاصة بالمحاكي. + لغة المحاكي:\nتحدد اللغة المستخدمة في واجهة المحاكي. Show Splash Screen:\nShows the game's splash screen (a special image) while the game is starting. - إظهار شاشة البداية:\nيعرض شاشة البداية الخاصة باللعبة (صورة خاصة) أثناء بدء التشغيل. + عرض شاشة البداية:\nيعرض شاشة البداية الخاصة باللعبة (صورة مميزة) أثناء بدء التشغيل. Enable Discord Rich Presence:\nDisplays the emulator icon and relevant information on your Discord profile. @@ -1748,59 +1748,60 @@ Username:\nSets the PS4's account username, which may be displayed by some games. - اسم المستخدم:\nيضبط اسم حساب PS4، الذي قد يتم عرضه في بعض الألعاب. + اسم المستخدم:\nيحدد اسم حساب'PS4، وقد يظهر في بعض الألعاب. Trophy Key:\nKey used to decrypt trophies. Must be obtained from your jailbroken console.\nMust contain only hex characters. - مفتاح الميداليات:\nمفتاح يستخدم لفتح تشفير الميداليات. يجب أن يكون من جهاز مكسور الحماية.\nيجي أن يحتوي على أحرف نظام العد السداسي. + مفتاح الكؤوس:\nيُستخدم لفك تشفير الجوائز داخل الألعاب. يُستخرج من جهاز معدل.\nيجب أن يُكتب باستخدام رموز ست عشرية فقط. Log Type:\nSets whether to synchronize the output of the log window for performance. May have adverse effects on emulation. - نوع السجل:\nيضبط ما إذا كان سيتم مزامنة مخرجات نافذة السجل للأداء. قد يؤثر سلبًا على المحاكاة. + نوع السجل:\nييحدد ما إذا كان سيتم مزامنة مخرجات نافذة السجل لتحسين الأداء. قد يؤدي ذلك إلى تأثيرات سلبية على المحاكاة. Log Filter:\nFilters the log to only print specific information.\nExamples: "Core:Trace" "Lib.Pad:Debug Common.Filesystem:Error" "*:Critical"\nLevels: Trace, Debug, Info, Warning, Error, Critical - in this order, a specific level silences all levels preceding it in the list and logs every level after it. - فلتر السجل:\nيقوم بتصفية السجل لطباعة معلومات محددة فقط.\nأمثلة: "Core:Trace" "Lib.Pad:Debug Common.Filesystem:Error" "*:Critical" المستويات: Trace, Debug, Info, Warning, Error, Critical - بالترتيب، مستوى محدد يخفي جميع المستويات التي تسبقه ويعرض جميع المستويات بعده. + تصفية السجل:\nيمكنك تحديد نوع المعلومات التي سيتم عرضها في السجل فقط.\nأمثلة: "Core:Trace" "Lib.Pad:Debug Common.Filesystem:Error" "*:Critical" االمستويات حسب الترتيب:: Trace, Debug, Info, Warning, Error, Critical - عند اختيار مستوى معين، يتم تجاهل كل ما قبله، وتسجيل كل ما بعده. Update:\nRelease: Official versions released every month that may be very outdated, but are more reliable and tested.\nNightly: Development versions that have all the latest features and fixes, but may contain bugs and are less stable. - تحديث: Release: إصدارات رسمية تصدر شهريًا، قد تكون قديمة بعض الشيء، لكنها أكثر استقرارًا واختبارًا. Nightly: إصدارات تطوير تحتوي على أحدث الميزات والإصلاحات، لكنها قد تحتوي على أخطاء وأقل استقرارًا. + تحديث: Release: نُسخ شهرية مستقرة وخضعت للاختبار، لكنها قد تكون قديمة. +Nightly: نُسخ تحتوي على أحدث الميزات، لكنها أقل استقرارًا وقد تحتوي على أخطاء. Background Image:\nControl the opacity of the game background image. - صورة الخلفية:\nيتحكم في درجة سواد صورة خلفية اللعبة. + صورة الخلفية:\nتحكم في شفافية صورة خلفية اللعبة. Play Title Music:\nIf a game supports it, enable playing special music when selecting the game in the GUI. - تشغيل موسيقى العنوان:\nإذا كانت اللعبة تدعم ذلك، قم بتمكين تشغيل موسيقى خاصة عند اختيار اللعبة في واجهة المستخدم. + تشغيل موسيقى العنوان:\nفي حال كانت اللعبة تدعم ذلك، يتم تشغيل موسيقى خاصة عند تحديدها في الواجهة. Disable Trophy Pop-ups:\nDisable in-game trophy notifications. Trophy progress can still be tracked using the Trophy Viewer (right-click the game in the main window). - إغلاق نوافذ الميداليات المنبثقة:\n إغلاق إشعارات الميداليات داخل اللعبة. تقدم الميداليات يمكن تتبعه باستخدام عارض الميداليات (قم بالضغط على زر الفأرة الأيمن داخل النافذة الرئيسية). + تعطيل إشعارات التروفي:\nيمنع ظهور إشعارات الجوائز أثناء اللعب، بينما يظل بإمكانك متابعة التقدم من خلال "عارض التروفي" (انقر بزر الفأرة الأيمن على اللعبة في النافذة الرئيسية). Hide Cursor:\nChoose when the cursor will disappear:\nNever: You will always see the mouse.\nidle: Set a time for it to disappear after being idle.\nAlways: you will never see the mouse. - إخفاء المؤشر:\nاختر متى سيختفي المؤشر:\nأبداً: سترى الفأرة دائماً.\nعاطل: حدد وقتاً لاختفائه بعد أن يكون غير مستخدم.\nدائماً: لن ترى الفأرة أبداً. + إخفاء المؤشر:\nاختر متى يتم إخفاء مؤشر الماوس:\nأبدًا: يظهر دائمًا.\nعند الخمول: يختفي بعد فترة من عدم الحركة.\nدائمًا: لا يظهر إطلاقًا. Hide Idle Cursor Timeout:\nThe duration (seconds) after which the cursor that has been idle hides itself. - حدد وقتاً لاختفاء الفأرة بعد أن تكون غير مستخدم. + مدة إخفاء المؤشر عند الخمول:\nالوقت (بالثواني) الذي ينتظره المؤشر قبل أن يختفي تلقائيًا عند عدم استخدامه. Back Button Behavior:\nSets the controller's back button to emulate tapping the specified position on the PS4 touchpad. - سلوك زر العودة:\nيضبط زر العودة في وحدة التحكم ليحاكي الضغط على الموضع المحدد على لوحة اللمس في PS4. + سلوك زر الرجوع:\nيحدد وظيفة زر' الرجوع في وحدة التحكم لمحاكاة اللمس في موقع معيّن على لوحة اللمس الخاصة بـ PS4. Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information. - عرض بيانات التوافق:\nيقوم بإظهار معلومات توافق اللعبة في طريقة عرض الطاولة. تشغيل"تحديث التوافق عند التشغيل" للحصول على معلومات محدثة. + عرض بيانات التوافق:\nيعرض معلومات توافق الألعاب في عرض جدولي. فعّل ""تحديث التوافق عند بدء التشغيل"" للحصول على أحدث المعلومات. Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts. - تحديث التوافق عند التشغيل:\nتحديث قاعدة بيانات التوافق تلقائياً عند تشغيل shadps4. + تحديث التوافق عند بدء التشغيل:\nيتم تحديث قاعدة بيانات التوافق تلقائيًا عند بدء تشغيل shadPS4. Update Compatibility Database:\nImmediately update the compatibility database. - تحديث قاعدة بيانات التوافق:\nقم بتحديث قاعدة بيانات التوافق حالاً. + تحديث قاعدة بيانات التوافق:\nتحديث فوري لقاعدة بيانات التوافق. Never @@ -1816,15 +1817,15 @@ Touchpad Left - لوحة اللمس اليسرى + الجانب الأيسر من لوحة اللمس Touchpad Right - لوحة اللمس اليمنى + الجانب الأيمن من لوحة اللمس Touchpad Center - وسط لوحة اللمس + مركز لوحة اللمس None @@ -1832,11 +1833,11 @@ Graphics Device:\nOn multiple GPU systems, select the GPU the emulator will use from the drop down list,\nor select "Auto Select" to automatically determine it. - جهاز الرسومات:\nعلى الأنظمة متعددة وحدات معالجة الرسومات، اختر وحدة معالجة الرسومات التي سيستخدمها المحاكي من قائمة منسدلة،\nأو اختر "Auto Select" لتحديدها تلقائيًا. + جهاز الرسوميات:\nفي الأنظمة التي تحتوي على أكثر من معالج رسومي، اختر وحدة المعالجة الرسومية GPU التي سيستخدمها المحاكي من القائمة المنسدلة،\nأو اختر ""تحديد تلقائي"" ليتم اختيارها تلقائيًا. Width/Height:\nSets the size of the emulator window at launch, which can be resized during gameplay.\nThis is different from the in-game resolution. - العرض / الارتفاع:\nيضبط حجم نافذة المحاكي عند التشغيل، والذي يمكن تغيير حجمه أثناء اللعب.\nهذا يختلف عن دقة اللعبة نفسها. + العرض/الارتفاع:\nتحدد حجم نافذة المحاكي عند التشغيل، ويمكن تغيير حجمها أثناء اللعب.\nيختلف هذا عن دقة اللعبة داخل اللعبة. Vblank Divider:\nThe frame rate at which the emulator refreshes at is multiplied by this number. Changing this may have adverse effects, such as increasing the game speed, or breaking critical game functionality that does not expect this to change! @@ -1844,11 +1845,11 @@ Enable Shaders Dumping:\nFor the sake of technical debugging, saves the games shaders to a folder as they render. - تمكين تفريغ الـ Shaders:\nلأغراض تصحيح الأخطاء التقنية، يحفظ الـ Shaders الخاصة باللعبة في مجلد أثناء التشغيل. + تمكين تفريغ الشيدرات:\nلأغراض تصحيح الأخطاء التقنية، يقوم بحفظ شيدرات اللعبة في مجلد أثناء عرضها. Enable Null GPU:\nFor the sake of technical debugging, disables game rendering as if there were no graphics card. - تمكين GPU الافتراضية:\nلأغراض تصحيح الأخطاء التقنية، يقوم بتعطيل عرض اللعبة كما لو لم يكن هناك بطاقة رسومات. + تمكين GPU فارغ:\nلأغراض تصحيح الأخطاء التقنية، يتم تعطيل عرض اللعبة كما لو لم يكن هناك كرت شاشة. Enable HDR:\nEnables HDR in games that support it.\nYour monitor must have support for the BT2020 PQ color space and the RGB10A2 swapchain format. @@ -1856,7 +1857,7 @@ Game Folders:\nThe list of folders to check for installed games. - مجلدات اللعبة:\nقائمة بالمجلدات للتحقق من الألعاب المثبتة. + مجلدات اللعبة:\nقائمة المجلدات التي يتم فحصها للبحث عن الألعاب المثبتة. Add:\nAdd a folder to the list. @@ -1868,7 +1869,7 @@ Enable Debug Dumping:\nSaves the import and export symbols and file header information of the currently running PS4 program to a directory. - تمكين تفريغ التصحيح:\nيحفظ رموز الاستيراد والتصدير ومعلومات رأس الملف للبرنامج الحالي لجهاز PS4 إلى دليل. + تمكين تفريغ التصحيح:\nيقوم بحفظ الرموز المستوردة والمصدرة، بالإضافة إلى معلومات رأس الملف للبرنامج الجاري تشغيله على PS4 في مجلد. Enable Vulkan Validation Layers:\nEnables a system that validates the state of the Vulkan renderer and logs information about its internal state.\nThis will reduce performance and likely change the behavior of emulation. @@ -1980,11 +1981,11 @@ W: - W: + العرض: H: - H: + الارتفاع: Separate Log Files @@ -2055,7 +2056,7 @@ TrophyViewer Trophy Viewer - عارض الجوائز + عارض التروفي Select Game: diff --git a/src/qt_gui/translations/it_IT.ts b/src/qt_gui/translations/it_IT.ts index 908013004..8c9e53611 100644 --- a/src/qt_gui/translations/it_IT.ts +++ b/src/qt_gui/translations/it_IT.ts @@ -138,7 +138,7 @@ File Exists - Il file è presente + Il file esiste già File already exists. Do you want to replace it? diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp index 036df24d8..936f82cd6 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp @@ -335,8 +335,7 @@ void DefineEntryPoint(const Info& info, EmitContext& ctx, Id main) { ctx.AddExecutionMode(main, spv::ExecutionMode::OriginUpperLeft); } if (info.has_discard) { - ctx.AddExtension("SPV_EXT_demote_to_helper_invocation"); - ctx.AddCapability(spv::Capability::DemoteToHelperInvocationEXT); + ctx.AddCapability(spv::Capability::DemoteToHelperInvocation); } if (info.stores.GetAny(IR::Attribute::Depth)) { ctx.AddExecutionMode(main, spv::ExecutionMode::DepthReplacing); diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp index 4faa99fe8..c6ec65606 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp @@ -21,6 +21,15 @@ Id SharedAtomicU32(EmitContext& ctx, Id offset, Id value, return (ctx.*atomic_func)(ctx.U32[1], pointer, scope, semantics, value); } +Id SharedAtomicU32_IncDec(EmitContext& ctx, Id offset, + Id (Sirit::Module::*atomic_func)(Id, Id, Id, Id)) { + const Id shift_id{ctx.ConstU32(2U)}; + const Id index{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift_id)}; + const Id pointer{ctx.OpAccessChain(ctx.shared_u32, ctx.shared_memory_u32, index)}; + const auto [scope, semantics]{AtomicArgs(ctx)}; + return (ctx.*atomic_func)(ctx.U32[1], pointer, scope, semantics); +} + Id BufferAtomicU32BoundsCheck(EmitContext& ctx, Id index, Id buffer_size, auto emit_func) { if (Sirit::ValidId(buffer_size)) { // Bounds checking enabled, wrap in a conditional branch to make sure that @@ -99,6 +108,18 @@ Id EmitSharedAtomicXor32(EmitContext& ctx, Id offset, Id value) { return SharedAtomicU32(ctx, offset, value, &Sirit::Module::OpAtomicXor); } +Id EmitSharedAtomicISub32(EmitContext& ctx, Id offset, Id value) { + return SharedAtomicU32(ctx, offset, value, &Sirit::Module::OpAtomicISub); +} + +Id EmitSharedAtomicIIncrement32(EmitContext& ctx, Id offset) { + return SharedAtomicU32_IncDec(ctx, offset, &Sirit::Module::OpAtomicIIncrement); +} + +Id EmitSharedAtomicIDecrement32(EmitContext& ctx, Id offset) { + return SharedAtomicU32_IncDec(ctx, offset, &Sirit::Module::OpAtomicIDecrement); +} + Id EmitBufferAtomicIAdd32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id address, Id value) { return BufferAtomicU32(ctx, inst, handle, address, value, &Sirit::Module::OpAtomicIAdd); } diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h index fb37799f5..9b7528be8 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h @@ -130,6 +130,10 @@ Id EmitSharedAtomicSMin32(EmitContext& ctx, Id offset, Id value); Id EmitSharedAtomicAnd32(EmitContext& ctx, Id offset, Id value); Id EmitSharedAtomicOr32(EmitContext& ctx, Id offset, Id value); Id EmitSharedAtomicXor32(EmitContext& ctx, Id offset, Id value); +Id EmitSharedAtomicIIncrement32(EmitContext& ctx, Id offset); +Id EmitSharedAtomicIDecrement32(EmitContext& ctx, Id offset); +Id EmitSharedAtomicISub32(EmitContext& ctx, Id offset, Id value); + Id EmitCompositeConstructU32x2(EmitContext& ctx, IR::Inst* inst, Id e1, Id e2); Id EmitCompositeConstructU32x3(EmitContext& ctx, IR::Inst* inst, Id e1, Id e2, Id e3); Id EmitCompositeConstructU32x4(EmitContext& ctx, IR::Inst* inst, Id e1, Id e2, Id e3, Id e4); @@ -338,8 +342,8 @@ Id EmitIAdd64(EmitContext& ctx, Id a, Id b); Id EmitIAddCary32(EmitContext& ctx, Id a, Id b); Id EmitISub32(EmitContext& ctx, Id a, Id b); Id EmitISub64(EmitContext& ctx, Id a, Id b); -Id EmitSMulExt(EmitContext& ctx, Id a, Id b); -Id EmitUMulExt(EmitContext& ctx, Id a, Id b); +Id EmitSMulHi(EmitContext& ctx, Id a, Id b); +Id EmitUMulHi(EmitContext& ctx, Id a, Id b); Id EmitIMul32(EmitContext& ctx, Id a, Id b); Id EmitIMul64(EmitContext& ctx, Id a, Id b); Id EmitSDiv32(EmitContext& ctx, Id a, Id b); diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp index 36726b6df..10bfbb2ab 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp @@ -72,12 +72,17 @@ Id EmitISub64(EmitContext& ctx, Id a, Id b) { return ctx.OpISub(ctx.U64, a, b); } -Id EmitSMulExt(EmitContext& ctx, Id a, Id b) { - return ctx.OpSMulExtended(ctx.full_result_i32x2, a, b); +Id EmitSMulHi(EmitContext& ctx, Id a, Id b) { + const auto signed_a{ctx.OpBitcast(ctx.S32[1], a)}; + const auto signed_b{ctx.OpBitcast(ctx.S32[1], b)}; + const auto mul_ext{ctx.OpSMulExtended(ctx.full_result_i32x2, signed_a, signed_b)}; + const auto signed_hi{ctx.OpCompositeExtract(ctx.S32[1], mul_ext, 1)}; + return ctx.OpBitcast(ctx.U32[1], signed_hi); } -Id EmitUMulExt(EmitContext& ctx, Id a, Id b) { - return ctx.OpUMulExtended(ctx.full_result_u32x2, a, b); +Id EmitUMulHi(EmitContext& ctx, Id a, Id b) { + const auto mul_ext{ctx.OpUMulExtended(ctx.full_result_u32x2, a, b)}; + return ctx.OpCompositeExtract(ctx.U32[1], mul_ext, 1); } Id EmitIMul32(EmitContext& ctx, Id a, Id b) { diff --git a/src/shader_recompiler/frontend/control_flow_graph.cpp b/src/shader_recompiler/frontend/control_flow_graph.cpp index cf1882b8c..b53db9e94 100644 --- a/src/shader_recompiler/frontend/control_flow_graph.cpp +++ b/src/shader_recompiler/frontend/control_flow_graph.cpp @@ -4,6 +4,7 @@ #include #include #include "common/assert.h" +#include "common/logging/log.h" #include "shader_recompiler/frontend/control_flow_graph.h" namespace Shader::Gcn { @@ -67,6 +68,39 @@ static bool IgnoresExecMask(const GcnInst& inst) { return false; } +static std::optional ResolveSetPcTarget(std::span list, u32 setpc_index, + std::span pc_map) { + if (setpc_index < 3) { + return std::nullopt; + } + + const auto& getpc = list[setpc_index - 3]; + const auto& arith = list[setpc_index - 2]; + const auto& setpc = list[setpc_index]; + + if (getpc.opcode != Opcode::S_GETPC_B64 || + !(arith.opcode == Opcode::S_ADD_U32 || arith.opcode == Opcode::S_SUB_U32) || + setpc.opcode != Opcode::S_SETPC_B64) + return std::nullopt; + + if (getpc.dst[0].code != setpc.src[0].code || arith.dst[0].code != setpc.src[0].code) + return std::nullopt; + + if (arith.src_count < 2 || arith.src[1].field != OperandField::LiteralConst) + return std::nullopt; + + const u32 imm = arith.src[1].code; + + const s32 signed_offset = + (arith.opcode == Opcode::S_ADD_U32) ? static_cast(imm) : -static_cast(imm); + + const u32 base_pc = pc_map[setpc_index - 3] + getpc.length; + + const u32 result_pc = static_cast(static_cast(base_pc) + signed_offset); + LOG_DEBUG(Render_Recompiler, "SetPC target: {} + {} = {}", base_pc, signed_offset, result_pc); + return result_pc & ~0x3u; +} + static constexpr size_t LabelReserveSize = 32; CFG::CFG(Common::ObjectPool& block_pool_, std::span inst_list_) @@ -89,9 +123,20 @@ void CFG::EmitLabels() { index_to_pc[i] = pc; const GcnInst inst = inst_list[i]; if (inst.IsUnconditionalBranch()) { - const u32 target = inst.BranchTarget(pc); + u32 target = inst.BranchTarget(pc); + if (inst.opcode == Opcode::S_SETPC_B64) { + if (auto t = ResolveSetPcTarget(inst_list, i, index_to_pc)) { + target = *t; + } else { + ASSERT_MSG( + false, + "S_SETPC_B64 without a resolvable offset at PC {:#x} (Index {}): Involved " + "instructions not recognized or invalid pattern", + pc, i); + } + } AddLabel(target); - // Emit this label so that the block ends with s_branch instruction + // Emit this label so that the block ends with the branching instruction AddLabel(pc + inst.length); } else if (inst.IsConditionalBranch()) { const u32 true_label = inst.BranchTarget(pc); @@ -102,6 +147,7 @@ void CFG::EmitLabels() { const u32 next_label = pc + inst.length; AddLabel(next_label); } + pc += inst.length; } index_to_pc[inst_list.size()] = pc; @@ -280,7 +326,18 @@ void CFG::LinkBlocks() { // Find the branch targets from the instruction and link the blocks. // Note: Block end address is one instruction after end_inst. const u32 branch_pc = block.end - end_inst.length; - const u32 target_pc = end_inst.BranchTarget(branch_pc); + u32 target_pc = 0; + if (end_inst.opcode == Opcode::S_SETPC_B64) { + auto tgt = ResolveSetPcTarget(inst_list, block.end_index, index_to_pc); + ASSERT_MSG(tgt, + "S_SETPC_B64 without a resolvable offset at PC {:#x} (Index {}): Involved " + "instructions not recognized or invalid pattern", + branch_pc, block.end_index); + target_pc = *tgt; + } else { + target_pc = end_inst.BranchTarget(branch_pc); + } + if (end_inst.IsUnconditionalBranch()) { auto* target_block = get_block(target_pc); ++target_block->num_predecessors; diff --git a/src/shader_recompiler/frontend/format.cpp b/src/shader_recompiler/frontend/format.cpp index f89f0a582..52c8c733e 100644 --- a/src/shader_recompiler/frontend/format.cpp +++ b/src/shader_recompiler/frontend/format.cpp @@ -3569,19 +3569,19 @@ constexpr std::array InstructionFormatMIMG = {{ {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32, ScalarType::Float32}, // 65 = IMAGE_GATHER4_CL - {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined, - ScalarType::Undefined}, + {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32, + ScalarType::Float32}, {}, {}, // 68 = IMAGE_GATHER4_L - {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined, - ScalarType::Undefined}, + {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32, + ScalarType::Float32}, // 69 = IMAGE_GATHER4_B - {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined, - ScalarType::Undefined}, + {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32, + ScalarType::Float32}, // 70 = IMAGE_GATHER4_B_CL - {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined, - ScalarType::Undefined}, + {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32, + ScalarType::Float32}, // 71 = IMAGE_GATHER4_LZ {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32, ScalarType::Float32}, @@ -3589,19 +3589,19 @@ constexpr std::array InstructionFormatMIMG = {{ {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32, ScalarType::Float32}, // 73 = IMAGE_GATHER4_C_CL - {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined, - ScalarType::Undefined}, + {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32, + ScalarType::Float32}, {}, {}, // 76 = IMAGE_GATHER4_C_L - {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined, - ScalarType::Undefined}, + {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32, + ScalarType::Float32}, // 77 = IMAGE_GATHER4_C_B - {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined, - ScalarType::Undefined}, + {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32, + ScalarType::Float32}, // 78 = IMAGE_GATHER4_C_B_CL - {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined, - ScalarType::Undefined}, + {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32, + ScalarType::Float32}, // 79 = IMAGE_GATHER4_C_LZ {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32, ScalarType::Float32}, @@ -3609,19 +3609,19 @@ constexpr std::array InstructionFormatMIMG = {{ {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32, ScalarType::Float32}, // 81 = IMAGE_GATHER4_CL_O - {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined, - ScalarType::Undefined}, + {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32, + ScalarType::Float32}, {}, {}, // 84 = IMAGE_GATHER4_L_O - {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined, - ScalarType::Undefined}, + {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32, + ScalarType::Float32}, // 85 = IMAGE_GATHER4_B_O - {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined, - ScalarType::Undefined}, + {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32, + ScalarType::Float32}, // 86 = IMAGE_GATHER4_B_CL_O - {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined, - ScalarType::Undefined}, + {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32, + ScalarType::Float32}, // 87 = IMAGE_GATHER4_LZ_O {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32, ScalarType::Float32}, @@ -3629,19 +3629,19 @@ constexpr std::array InstructionFormatMIMG = {{ {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32, ScalarType::Float32}, // 89 = IMAGE_GATHER4_C_CL_O - {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined, - ScalarType::Undefined}, + {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32, + ScalarType::Float32}, {}, {}, // 92 = IMAGE_GATHER4_C_L_O - {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined, - ScalarType::Undefined}, + {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32, + ScalarType::Float32}, // 93 = IMAGE_GATHER4_C_B_O - {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined, - ScalarType::Undefined}, + {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32, + ScalarType::Float32}, // 94 = IMAGE_GATHER4_C_B_CL_O - {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined, - ScalarType::Undefined}, + {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32, + ScalarType::Float32}, // 95 = IMAGE_GATHER4_C_LZ_O {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32, ScalarType::Float32}, diff --git a/src/shader_recompiler/frontend/instruction.cpp b/src/shader_recompiler/frontend/instruction.cpp index a0c132053..246c2b85a 100644 --- a/src/shader_recompiler/frontend/instruction.cpp +++ b/src/shader_recompiler/frontend/instruction.cpp @@ -18,7 +18,7 @@ bool GcnInst::IsTerminateInstruction() const { } bool GcnInst::IsUnconditionalBranch() const { - return opcode == Opcode::S_BRANCH; + return opcode == Opcode::S_BRANCH || opcode == Opcode::S_SETPC_B64; } bool GcnInst::IsFork() const { diff --git a/src/shader_recompiler/frontend/translate/data_share.cpp b/src/shader_recompiler/frontend/translate/data_share.cpp index 22f5b8644..c29497ada 100644 --- a/src/shader_recompiler/frontend/translate/data_share.cpp +++ b/src/shader_recompiler/frontend/translate/data_share.cpp @@ -13,6 +13,12 @@ void Translator::EmitDataShare(const GcnInst& inst) { // DS case Opcode::DS_ADD_U32: return DS_ADD_U32(inst, false); + case Opcode::DS_SUB_U32: + return DS_SUB_U32(inst, false); + case Opcode::DS_INC_U32: + return DS_INC_U32(inst, false); + case Opcode::DS_DEC_U32: + return DS_DEC_U32(inst, false); case Opcode::DS_MIN_I32: return DS_MIN_U32(inst, true, false); case Opcode::DS_MAX_I32: @@ -35,6 +41,8 @@ void Translator::EmitDataShare(const GcnInst& inst) { return DS_WRITE(32, false, true, true, inst); case Opcode::DS_ADD_RTN_U32: return DS_ADD_U32(inst, true); + case Opcode::DS_SUB_RTN_U32: + return DS_SUB_U32(inst, true); case Opcode::DS_MIN_RTN_U32: return DS_MIN_U32(inst, false, true); case Opcode::DS_MAX_RTN_U32: @@ -67,6 +75,8 @@ void Translator::EmitDataShare(const GcnInst& inst) { return DS_READ(64, false, false, false, inst); case Opcode::DS_READ2_B64: return DS_READ(64, false, true, false, inst); + case Opcode::DS_READ2ST64_B64: + return DS_READ(64, false, true, true, inst); default: LogMissingOpcode(inst); } @@ -226,6 +236,40 @@ void Translator::DS_SWIZZLE_B32(const GcnInst& inst) { SetDst(inst.dst[0], ir.QuadShuffle(src, index)); } +void Translator::DS_INC_U32(const GcnInst& inst, bool rtn) { + const IR::U32 addr{GetSrc(inst.src[0])}; + const IR::U32 offset = + ir.Imm32((u32(inst.control.ds.offset1) << 8u) + u32(inst.control.ds.offset0)); + const IR::U32 addr_offset = ir.IAdd(addr, offset); + const IR::Value original_val = ir.SharedAtomicIIncrement(addr_offset); + if (rtn) { + SetDst(inst.dst[0], IR::U32{original_val}); + } +} + +void Translator::DS_DEC_U32(const GcnInst& inst, bool rtn) { + const IR::U32 addr{GetSrc(inst.src[0])}; + const IR::U32 offset = + ir.Imm32((u32(inst.control.ds.offset1) << 8u) + u32(inst.control.ds.offset0)); + const IR::U32 addr_offset = ir.IAdd(addr, offset); + const IR::Value original_val = ir.SharedAtomicIDecrement(addr_offset); + if (rtn) { + SetDst(inst.dst[0], IR::U32{original_val}); + } +} + +void Translator::DS_SUB_U32(const GcnInst& inst, bool rtn) { + const IR::U32 addr{GetSrc(inst.src[0])}; + const IR::U32 data{GetSrc(inst.src[1])}; + const IR::U32 offset = + ir.Imm32((u32(inst.control.ds.offset1) << 8u) + u32(inst.control.ds.offset0)); + const IR::U32 addr_offset = ir.IAdd(addr, offset); + const IR::Value original_val = ir.SharedAtomicISub(addr_offset, data); + if (rtn) { + SetDst(inst.dst[0], IR::U32{original_val}); + } +} + void Translator::DS_READ(int bit_size, bool is_signed, bool is_pair, bool stride64, const GcnInst& inst) { const IR::U32 addr{ir.GetVectorReg(IR::VectorReg(inst.src[0].code))}; diff --git a/src/shader_recompiler/frontend/translate/scalar_alu.cpp b/src/shader_recompiler/frontend/translate/scalar_alu.cpp index 39f972848..3a8e894ae 100644 --- a/src/shader_recompiler/frontend/translate/scalar_alu.cpp +++ b/src/shader_recompiler/frontend/translate/scalar_alu.cpp @@ -30,6 +30,8 @@ void Translator::EmitScalarAlu(const GcnInst& inst) { return S_SUB_I32(inst); case Opcode::S_ADDC_U32: return S_ADDC_U32(inst); + case Opcode::S_SUBB_U32: + return S_SUBB_U32(inst); case Opcode::S_MIN_I32: return S_MIN_U32(true, inst); case Opcode::S_MIN_U32: @@ -110,6 +112,8 @@ void Translator::EmitScalarAlu(const GcnInst& inst) { return S_FF1_I32_B32(inst); case Opcode::S_FF1_I32_B64: return S_FF1_I32_B64(inst); + case Opcode::S_FLBIT_I32_B32: + return S_FLBIT_I32_B32(inst); case Opcode::S_BITSET0_B32: return S_BITSET_B32(inst, 0); case Opcode::S_BITSET1_B32: @@ -236,6 +240,17 @@ void Translator::S_SUB_U32(const GcnInst& inst) { ir.SetScc(ir.IGreaterThan(src1, src0, false)); } +void Translator::S_SUBB_U32(const GcnInst& inst) { + const IR::U32 src0{GetSrc(inst.src[0])}; + const IR::U32 src1{GetSrc(inst.src[1])}; + const IR::U32 borrow{ir.Select(ir.GetScc(), ir.Imm32(1U), ir.Imm32(0U))}; + const IR::U32 result{ir.ISub(ir.ISub(src0, src1), borrow)}; + SetDst(inst.dst[0], result); + + const IR::U32 sum_with_borrow{ir.IAdd(src1, borrow)}; + ir.SetScc(ir.ILessThan(src0, sum_with_borrow, false)); +} + void Translator::S_ADD_I32(const GcnInst& inst) { const IR::U32 src0{GetSrc(inst.src[0])}; const IR::U32 src1{GetSrc(inst.src[1])}; @@ -660,6 +675,17 @@ void Translator::S_FF1_I32_B64(const GcnInst& inst) { SetDst(inst.dst[0], result); } +void Translator::S_FLBIT_I32_B32(const GcnInst& inst) { + const IR::U32 src0{GetSrc(inst.src[0])}; + // Gcn wants the MSB position counting from the left, but SPIR-V counts from the rightmost (LSB) + // position + const IR::U32 msb_pos = ir.FindUMsb(src0); + const IR::U32 pos_from_left = ir.ISub(ir.Imm32(31), msb_pos); + // Select 0xFFFFFFFF if src0 was 0 + const IR::U1 cond = ir.INotEqual(src0, ir.Imm32(0)); + SetDst(inst.dst[0], IR::U32{ir.Select(cond, pos_from_left, ir.Imm32(~0U))}); +} + void Translator::S_BITSET_B32(const GcnInst& inst, u32 bit_value) { const IR::U32 old_value{GetSrc(inst.dst[0])}; const IR::U32 offset{ir.BitFieldExtract(GetSrc(inst.src[0]), ir.Imm32(0U), ir.Imm32(5U))}; diff --git a/src/shader_recompiler/frontend/translate/scalar_flow.cpp b/src/shader_recompiler/frontend/translate/scalar_flow.cpp index 0e02b77a2..cd1cf51f0 100644 --- a/src/shader_recompiler/frontend/translate/scalar_flow.cpp +++ b/src/shader_recompiler/frontend/translate/scalar_flow.cpp @@ -18,6 +18,7 @@ void Translator::EmitFlowControl(u32 pc, const GcnInst& inst) { return; case Opcode::S_GETPC_B64: return S_GETPC_B64(pc, inst); + case Opcode::S_SETPC_B64: case Opcode::S_WAITCNT: case Opcode::S_NOP: case Opcode::S_ENDPGM: diff --git a/src/shader_recompiler/frontend/translate/translate.h b/src/shader_recompiler/frontend/translate/translate.h index 6803cda25..68d5e8dc8 100644 --- a/src/shader_recompiler/frontend/translate/translate.h +++ b/src/shader_recompiler/frontend/translate/translate.h @@ -80,6 +80,7 @@ public: // SOP2 void S_ADD_U32(const GcnInst& inst); void S_SUB_U32(const GcnInst& inst); + void S_SUBB_U32(const GcnInst& inst); void S_ADD_I32(const GcnInst& inst); void S_SUB_I32(const GcnInst& inst); void S_ADDC_U32(const GcnInst& inst); @@ -119,6 +120,7 @@ public: void S_BCNT1_I32_B64(const GcnInst& inst); void S_FF1_I32_B32(const GcnInst& inst); void S_FF1_I32_B64(const GcnInst& inst); + void S_FLBIT_I32_B32(const GcnInst& inst); void S_BITSET_B32(const GcnInst& inst, u32 bit_value); void S_GETPC_B64(u32 pc, const GcnInst& inst); void S_SAVEEXEC_B64(NegateMode negate, bool is_or, const GcnInst& inst); @@ -273,6 +275,9 @@ public: void DS_READ(int bit_size, bool is_signed, bool is_pair, bool stride64, const GcnInst& inst); void DS_APPEND(const GcnInst& inst); void DS_CONSUME(const GcnInst& inst); + void DS_SUB_U32(const GcnInst& inst, bool rtn); + void DS_INC_U32(const GcnInst& inst, bool rtn); + void DS_DEC_U32(const GcnInst& inst, bool rtn); // Buffer Memory // MUBUF / MTBUF diff --git a/src/shader_recompiler/frontend/translate/vector_alu.cpp b/src/shader_recompiler/frontend/translate/vector_alu.cpp index da25f5434..787cf6ad3 100644 --- a/src/shader_recompiler/frontend/translate/vector_alu.cpp +++ b/src/shader_recompiler/frontend/translate/vector_alu.cpp @@ -394,6 +394,8 @@ void Translator::EmitVectorAlu(const GcnInst& inst) { return V_MUL_HI_U32(false, inst); case Opcode::V_MUL_LO_I32: return V_MUL_LO_U32(inst); + case Opcode::V_MUL_HI_I32: + return V_MUL_HI_U32(true, inst); case Opcode::V_MAD_U64_U32: return V_MAD_U64_U32(inst); case Opcode::V_NOP: @@ -1279,7 +1281,7 @@ void Translator::V_MUL_LO_U32(const GcnInst& inst) { void Translator::V_MUL_HI_U32(bool is_signed, const GcnInst& inst) { const IR::U32 src0{GetSrc(inst.src[0])}; const IR::U32 src1{GetSrc(inst.src[1])}; - const IR::U32 hi{ir.CompositeExtract(ir.IMulExt(src0, src1, is_signed), 1)}; + const IR::U32 hi{ir.IMulHi(src0, src1, is_signed)}; SetDst(inst.dst[0], hi); } diff --git a/src/shader_recompiler/ir/ir_emitter.cpp b/src/shader_recompiler/ir/ir_emitter.cpp index a171d32a2..e8836bb4c 100644 --- a/src/shader_recompiler/ir/ir_emitter.cpp +++ b/src/shader_recompiler/ir/ir_emitter.cpp @@ -357,6 +357,18 @@ U32 IREmitter::SharedAtomicXor(const U32& address, const U32& data) { return Inst(Opcode::SharedAtomicXor32, address, data); } +U32 IREmitter::SharedAtomicIIncrement(const U32& address) { + return Inst(Opcode::SharedAtomicIIncrement32, address); +} + +U32 IREmitter::SharedAtomicIDecrement(const U32& address) { + return Inst(Opcode::SharedAtomicIDecrement32, address); +} + +U32 IREmitter::SharedAtomicISub(const U32& address, const U32& data) { + return Inst(Opcode::SharedAtomicISub32, address, data); +} + U32 IREmitter::ReadConst(const Value& base, const U32& offset) { return Inst(Opcode::ReadConst, base, offset); } @@ -1388,8 +1400,8 @@ U32U64 IREmitter::ISub(const U32U64& a, const U32U64& b) { } } -IR::Value IREmitter::IMulExt(const U32& a, const U32& b, bool is_signed) { - return Inst(is_signed ? Opcode::SMulExt : Opcode::UMulExt, a, b); +U32 IREmitter::IMulHi(const U32& a, const U32& b, bool is_signed) { + return Inst(is_signed ? Opcode::SMulHi : Opcode::UMulHi, a, b); } U32U64 IREmitter::IMul(const U32U64& a, const U32U64& b) { diff --git a/src/shader_recompiler/ir/ir_emitter.h b/src/shader_recompiler/ir/ir_emitter.h index 48cc02725..186d83a07 100644 --- a/src/shader_recompiler/ir/ir_emitter.h +++ b/src/shader_recompiler/ir/ir_emitter.h @@ -106,6 +106,10 @@ public: [[nodiscard]] U32 SharedAtomicOr(const U32& address, const U32& data); [[nodiscard]] U32 SharedAtomicXor(const U32& address, const U32& data); + [[nodiscard]] U32 SharedAtomicIIncrement(const U32& address); + [[nodiscard]] U32 SharedAtomicIDecrement(const U32& address); + [[nodiscard]] U32 SharedAtomicISub(const U32& address, const U32& data); + [[nodiscard]] U32 ReadConst(const Value& base, const U32& offset); [[nodiscard]] U32 ReadConstBuffer(const Value& handle, const U32& index); @@ -240,7 +244,7 @@ public: [[nodiscard]] U32U64 IAdd(const U32U64& a, const U32U64& b); [[nodiscard]] Value IAddCary(const U32& a, const U32& b); [[nodiscard]] U32U64 ISub(const U32U64& a, const U32U64& b); - [[nodiscard]] Value IMulExt(const U32& a, const U32& b, bool is_signed = false); + [[nodiscard]] U32 IMulHi(const U32& a, const U32& b, bool is_signed = false); [[nodiscard]] U32U64 IMul(const U32U64& a, const U32U64& b); [[nodiscard]] U32 IDiv(const U32& a, const U32& b, bool is_signed = false); [[nodiscard]] U32 IMod(const U32& a, const U32& b, bool is_signed = false); diff --git a/src/shader_recompiler/ir/opcodes.inc b/src/shader_recompiler/ir/opcodes.inc index 93d759b74..4932ff9a0 100644 --- a/src/shader_recompiler/ir/opcodes.inc +++ b/src/shader_recompiler/ir/opcodes.inc @@ -44,6 +44,9 @@ OPCODE(SharedAtomicUMax32, U32, U32, OPCODE(SharedAtomicAnd32, U32, U32, U32, ) OPCODE(SharedAtomicOr32, U32, U32, U32, ) OPCODE(SharedAtomicXor32, U32, U32, U32, ) +OPCODE(SharedAtomicISub32, U32, U32, U32, ) +OPCODE(SharedAtomicIIncrement32, U32, U32, ) +OPCODE(SharedAtomicIDecrement32, U32, U32, ) // Context getters/setters OPCODE(GetUserData, U32, ScalarReg, ) @@ -317,8 +320,8 @@ OPCODE(ISub32, U32, U32, OPCODE(ISub64, U64, U64, U64, ) OPCODE(IMul32, U32, U32, U32, ) OPCODE(IMul64, U64, U64, U64, ) -OPCODE(SMulExt, U32x2, U32, U32, ) -OPCODE(UMulExt, U32x2, U32, U32, ) +OPCODE(SMulHi, U32, U32, U32, ) +OPCODE(UMulHi, U32, U32, U32, ) OPCODE(SDiv32, U32, U32, U32, ) OPCODE(UDiv32, U32, U32, U32, ) OPCODE(SMod32, U32, U32, U32, ) diff --git a/src/shadps4.rc b/src/shadps4.rc index 8c984f260..9edccfbfd 100644 --- a/src/shadps4.rc +++ b/src/shadps4.rc @@ -1 +1,43 @@ -IDI_ICON1 ICON "images/shadps4.ico" \ No newline at end of file +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "winresrc.h" + +#define xstr(s) str(s) +#define str(s) #s + +// NEUTRAL LANG +LANGUAGE LANG_NEUTRAL, 0x8 + +// ICON +IDI_ICON1 ICON "images/shadps4.ico" + +// VERSION +VS_VERSION_INFO VERSIONINFO + FILEVERSION EMULATOR_VERSION_MAJOR, EMULATOR_VERSION_MINOR, EMULATOR_VERSION_PATCH, 0 + PRODUCTVERSION EMULATOR_VERSION_MAJOR, EMULATOR_VERSION_MINOR, EMULATOR_VERSION_PATCH, 0 + FILEFLAGSMASK 0x3fL + FILEFLAGS 0x0L + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "\0" + VALUE "FileDescription", "shadPS4 - PlayStation 4 Emulator\0" + VALUE "FileVersion", xstr(EMULATOR_VERSION_MAJOR) "." xstr(EMULATOR_VERSION_MINOR) "." xstr(EMULATOR_VERSION_PATCH) ".0\0" + VALUE "InternalName", "shadPS4\0" + VALUE "LegalCopyright", "Copyright 2025 shadPS4 Team\0" + VALUE "OriginalFilename", "shadPS4.exe\0" + VALUE "ProductName", "shadPS4\0" + VALUE "ProductVersion", xstr(EMULATOR_VERSION_MAJOR) "." xstr(EMULATOR_VERSION_MINOR) "." xstr(EMULATOR_VERSION_PATCH) ".0\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/src/video_core/renderer_vulkan/host_passes/pp_pass.cpp b/src/video_core/renderer_vulkan/host_passes/pp_pass.cpp index c854e124f..0c40ffd7a 100644 --- a/src/video_core/renderer_vulkan/host_passes/pp_pass.cpp +++ b/src/video_core/renderer_vulkan/host_passes/pp_pass.cpp @@ -78,7 +78,7 @@ void PostProcessingPass::Create(vk::Device device) { const std::array pp_color_formats{ vk::Format::eB8G8R8A8Unorm, // swapchain.GetSurfaceFormat().format, }; - const vk::PipelineRenderingCreateInfoKHR pipeline_rendering_ci{ + const vk::PipelineRenderingCreateInfo pipeline_rendering_ci{ .colorAttachmentCount = pp_color_formats.size(), .pColorAttachmentFormats = pp_color_formats.data(), }; diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 354e22331..7c020a012 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -122,21 +122,21 @@ GraphicsPipeline::GraphicsPipeline( }; boost::container::static_vector dynamic_states = { - vk::DynamicState::eViewportWithCountEXT, vk::DynamicState::eScissorWithCountEXT, - vk::DynamicState::eBlendConstants, vk::DynamicState::eDepthTestEnableEXT, - vk::DynamicState::eDepthWriteEnableEXT, vk::DynamicState::eDepthCompareOpEXT, - vk::DynamicState::eDepthBiasEnableEXT, vk::DynamicState::eDepthBias, - vk::DynamicState::eStencilTestEnableEXT, vk::DynamicState::eStencilReference, - vk::DynamicState::eStencilCompareMask, vk::DynamicState::eStencilWriteMask, - vk::DynamicState::eStencilOpEXT, vk::DynamicState::eCullModeEXT, - vk::DynamicState::eFrontFaceEXT, + vk::DynamicState::eViewportWithCount, vk::DynamicState::eScissorWithCount, + vk::DynamicState::eBlendConstants, vk::DynamicState::eDepthTestEnable, + vk::DynamicState::eDepthWriteEnable, vk::DynamicState::eDepthCompareOp, + vk::DynamicState::eDepthBiasEnable, vk::DynamicState::eDepthBias, + vk::DynamicState::eStencilTestEnable, vk::DynamicState::eStencilReference, + vk::DynamicState::eStencilCompareMask, vk::DynamicState::eStencilWriteMask, + vk::DynamicState::eStencilOp, vk::DynamicState::eCullMode, + vk::DynamicState::eFrontFace, }; if (instance.IsPrimitiveRestartDisableSupported()) { - dynamic_states.push_back(vk::DynamicState::ePrimitiveRestartEnableEXT); + dynamic_states.push_back(vk::DynamicState::ePrimitiveRestartEnable); } if (instance.IsDepthBoundsSupported()) { - dynamic_states.push_back(vk::DynamicState::eDepthBoundsTestEnableEXT); + dynamic_states.push_back(vk::DynamicState::eDepthBoundsTestEnable); dynamic_states.push_back(vk::DynamicState::eDepthBounds); } if (instance.IsDynamicColorWriteMaskSupported()) { @@ -145,7 +145,7 @@ GraphicsPipeline::GraphicsPipeline( if (instance.IsVertexInputDynamicState()) { dynamic_states.push_back(vk::DynamicState::eVertexInputEXT); } else if (!vertex_bindings.empty()) { - dynamic_states.push_back(vk::DynamicState::eVertexInputBindingStrideEXT); + dynamic_states.push_back(vk::DynamicState::eVertexInputBindingStride); } const vk::PipelineDynamicStateCreateInfo dynamic_info = { @@ -212,7 +212,7 @@ GraphicsPipeline::GraphicsPipeline( }); } - const vk::PipelineRenderingCreateInfoKHR pipeline_rendering_ci = { + const vk::PipelineRenderingCreateInfo pipeline_rendering_ci = { .colorAttachmentCount = key.num_color_attachments, .pColorAttachmentFormats = key.color_formats.data(), .depthAttachmentFormat = key.depth_format, diff --git a/src/video_core/renderer_vulkan/vk_instance.cpp b/src/video_core/renderer_vulkan/vk_instance.cpp index d45889054..d33a1607b 100644 --- a/src/video_core/renderer_vulkan/vk_instance.cpp +++ b/src/video_core/renderer_vulkan/vk_instance.cpp @@ -203,12 +203,14 @@ std::string Instance::GetDriverVersionName() { } bool Instance::CreateDevice() { - const vk::StructureChain feature_chain = physical_device.getFeatures2< - vk::PhysicalDeviceFeatures2, vk::PhysicalDeviceVulkan11Features, - vk::PhysicalDeviceVulkan12Features, vk::PhysicalDeviceRobustness2FeaturesEXT, - vk::PhysicalDeviceExtendedDynamicState3FeaturesEXT, - vk::PhysicalDevicePrimitiveTopologyListRestartFeaturesEXT, - vk::PhysicalDevicePortabilitySubsetFeaturesKHR>(); + const vk::StructureChain feature_chain = + physical_device + .getFeatures2(); features = feature_chain.get().features; const vk::StructureChain properties_chain = physical_device.getProperties2< @@ -240,20 +242,12 @@ bool Instance::CreateDevice() { return false; }; - // These extensions are promoted by Vulkan 1.3, but for greater compatibility we use Vulkan 1.2 - // with extensions. - add_extension(VK_KHR_FORMAT_FEATURE_FLAGS_2_EXTENSION_NAME); - add_extension(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME); - add_extension(VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME); - add_extension(VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME); - add_extension(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME); - add_extension(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME); - add_extension(VK_EXT_TOOLING_INFO_EXTENSION_NAME); - const bool maintenance4 = add_extension(VK_KHR_MAINTENANCE_4_EXTENSION_NAME); + // Required + ASSERT(add_extension(VK_KHR_SWAPCHAIN_EXTENSION_NAME)); + ASSERT(add_extension(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME)); - add_extension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); - add_extension(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME); - add_extension(VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME); + // Optional + depth_range_unrestricted = add_extension(VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME); dynamic_state_3 = add_extension(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); if (dynamic_state_3) { dynamic_state_3_features = @@ -320,6 +314,7 @@ bool Instance::CreateDevice() { feature_chain.get(); const auto vk11_features = feature_chain.get(); const auto vk12_features = feature_chain.get(); + const auto vk13_features = feature_chain.get(); vk::StructureChain device_chain = { vk::DeviceCreateInfo{ .queueCreateInfoCount = 1u, @@ -368,26 +363,14 @@ bool Instance::CreateDevice() { .hostQueryReset = vk12_features.hostQueryReset, .timelineSemaphore = vk12_features.timelineSemaphore, }, - // Vulkan 1.3 promoted extensions - vk::PhysicalDeviceDynamicRenderingFeaturesKHR{ - .dynamicRendering = true, + vk::PhysicalDeviceVulkan13Features{ + .robustImageAccess = vk13_features.robustImageAccess, + .shaderDemoteToHelperInvocation = vk13_features.shaderDemoteToHelperInvocation, + .synchronization2 = vk13_features.synchronization2, + .dynamicRendering = vk13_features.dynamicRendering, + .maintenance4 = vk13_features.maintenance4, }, - vk::PhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT{ - .shaderDemoteToHelperInvocation = true, - }, - vk::PhysicalDeviceSynchronization2Features{ - .synchronization2 = true, - }, - vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT{ - .extendedDynamicState = true, - }, - vk::PhysicalDeviceExtendedDynamicState2FeaturesEXT{ - .extendedDynamicState2 = true, - }, - vk::PhysicalDeviceMaintenance4FeaturesKHR{ - .maintenance4 = true, - }, - // Other extensions + // Extensions vk::PhysicalDeviceCustomBorderColorFeaturesEXT{ .customBorderColors = true, .customBorderColorWithoutFormat = true, @@ -422,9 +405,6 @@ bool Instance::CreateDevice() { #endif }; - if (!maintenance4) { - device_chain.unlink(); - } if (!custom_border_color) { device_chain.unlink(); } @@ -541,12 +521,14 @@ void Instance::CollectDeviceParameters() { LOG_INFO(Render_Vulkan, "GPU_Vulkan_Extensions: {}", extensions); } -void Instance::CollectToolingInfo() { - if (GetDriverID() == vk::DriverId::eAmdProprietary) { - // Currently causes issues with Reshade on AMD proprietary, disabled until fix released. +void Instance::CollectToolingInfo() const { + if (driver_id == vk::DriverId::eAmdProprietary || + driver_id == vk::DriverId::eIntelProprietaryWindows) { + // AMD: Causes issues with Reshade. + // Intel: Causes crash on start. return; } - const auto [tools_result, tools] = physical_device.getToolPropertiesEXT(); + const auto [tools_result, tools] = physical_device.getToolProperties(); if (tools_result != vk::Result::eSuccess) { LOG_ERROR(Render_Vulkan, "Could not get Vulkan tool properties: {}", vk::to_string(tools_result)); diff --git a/src/video_core/renderer_vulkan/vk_instance.h b/src/video_core/renderer_vulkan/vk_instance.h index 6de419041..b3f3e60b6 100644 --- a/src/video_core/renderer_vulkan/vk_instance.h +++ b/src/video_core/renderer_vulkan/vk_instance.h @@ -104,6 +104,11 @@ public: return depth_clip_control; } + /// Returns true when VK_EXT_depth_range_unrestricted is supported + bool IsDepthRangeUnrestrictedSupported() const { + return depth_range_unrestricted; + } + /// Returns true when the extendedDynamicState3ColorWriteMask feature of /// VK_EXT_extended_dynamic_state3 is supported. bool IsDynamicColorWriteMaskSupported() const { @@ -306,7 +311,7 @@ private: /// Collects telemetry information from the device. void CollectDeviceParameters(); - void CollectToolingInfo(); + void CollectToolingInfo() const; /// Gets the supported feature flags for a format. [[nodiscard]] vk::FormatFeatureFlags2 GetFormatFeatureFlags(vk::Format format) const; @@ -340,6 +345,7 @@ private: bool custom_border_color{}; bool fragment_shader_barycentric{}; bool depth_clip_control{}; + bool depth_range_unrestricted{}; bool dynamic_state_3{}; bool vertex_input_dynamic_state{}; bool robustness2{}; diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index bad2a549c..efb1966ba 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -26,6 +26,8 @@ using Shader::LogicalStage; using Shader::Stage; using Shader::VsOutput; +constexpr static auto SpirvVersion1_6 = 0x00010600U; + constexpr static std::array DescriptorHeapSizes = { vk::DescriptorPoolSize{vk::DescriptorType::eUniformBuffer, 8192}, vk::DescriptorPoolSize{vk::DescriptorType::eStorageBuffer, 1024}, @@ -192,7 +194,7 @@ PipelineCache::PipelineCache(const Instance& instance_, Scheduler& scheduler_, desc_heap{instance, scheduler.GetMasterSemaphore(), DescriptorHeapSizes} { const auto& vk12_props = instance.GetVk12Properties(); profile = Shader::Profile{ - .supported_spirv = instance.ApiVersion() >= VK_API_VERSION_1_3 ? 0x00010600U : 0x00010500U, + .supported_spirv = SpirvVersion1_6, .subgroup_size = instance.SubgroupSize(), .support_fp32_denorm_preserve = bool(vk12_props.shaderDenormPreserveFloat32), .support_fp32_denorm_flush = bool(vk12_props.shaderDenormFlushToZeroFloat32), diff --git a/src/video_core/renderer_vulkan/vk_platform.cpp b/src/video_core/renderer_vulkan/vk_platform.cpp index e656369b2..c49e62f4e 100644 --- a/src/video_core/renderer_vulkan/vk_platform.cpp +++ b/src/video_core/renderer_vulkan/vk_platform.cpp @@ -22,6 +22,10 @@ #include "sdl_window.h" #include "video_core/renderer_vulkan/vk_platform.h" +#ifdef __APPLE__ +#include +#endif + namespace Vulkan { static const char* const VALIDATION_LAYER_NAME = "VK_LAYER_KHRONOS_validation"; @@ -223,8 +227,19 @@ vk::UniqueInstance CreateInstance(Frontend::WindowSystemType window_type, bool e LOG_INFO(Render_Vulkan, "Creating vulkan instance"); #ifdef __APPLE__ +#ifndef ENABLE_QT_GUI + // Initialize the environment with the path to the MoltenVK ICD, so that the loader will + // find it. + static const auto icd_path = [] { + char path[PATH_MAX]; + u32 length = PATH_MAX; + _NSGetExecutablePath(path, &length); + return std::filesystem::path(path).parent_path() / "MoltenVK_icd.json"; + }(); + setenv("VK_DRIVER_FILES", icd_path.c_str(), true); +#endif // If the Vulkan loader exists in /usr/local/lib, give it priority. The Vulkan SDK - // installs it here by default but it is not in the default library search path. + // installs it here by default, but it is not in the default library search path. // The loader has a clause to check for it, but at a lower priority than the bundled // libMoltenVK.dylib, so we need to handle it ourselves to give it priority. static const std::string usr_local_path = "/usr/local/lib/libvulkan.dylib"; diff --git a/src/video_core/renderer_vulkan/vk_platform.h b/src/video_core/renderer_vulkan/vk_platform.h index 6a6ebeb15..b8f5f9f11 100644 --- a/src/video_core/renderer_vulkan/vk_platform.h +++ b/src/video_core/renderer_vulkan/vk_platform.h @@ -18,7 +18,7 @@ class WindowSDL; namespace Vulkan { -constexpr u32 TargetVulkanApiVersion = VK_API_VERSION_1_2; +constexpr u32 TargetVulkanApiVersion = VK_API_VERSION_1_3; vk::SurfaceKHR CreateSurface(vk::Instance instance, const Frontend::WindowSDL& emu_window); diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 13779977d..b04b4a07e 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -999,16 +999,13 @@ void Rasterizer::UpdateViewportScissorState() const { boost::container::static_vector viewports; boost::container::static_vector scissors; - const auto& vp_ctl = regs.viewport_control; - const float reduce_z = - regs.clipper_control.clip_space == AmdGpu::Liverpool::ClipSpace::MinusWToW ? 1.0f : 0.0f; - if (regs.polygon_control.enable_window_offset && (regs.window_offset.window_x_offset != 0 || regs.window_offset.window_y_offset != 0)) { LOG_ERROR(Render_Vulkan, "PA_SU_SC_MODE_CNTL.VTX_WINDOW_OFFSET_ENABLE support is not yet implemented."); } + const auto& vp_ctl = regs.viewport_control; for (u32 i = 0; i < Liverpool::NumViewports; i++) { const auto& vp = regs.viewports[i]; const auto& vp_d = regs.viewport_depths[i]; @@ -1018,33 +1015,55 @@ void Rasterizer::UpdateViewportScissorState() const { const auto zoffset = vp_ctl.zoffset_enable ? vp.zoffset : 0.f; const auto zscale = vp_ctl.zscale_enable ? vp.zscale : 1.f; + + vk::Viewport viewport{}; + + // https://gitlab.freedesktop.org/mesa/mesa/-/blob/209a0ed/src/amd/vulkan/radv_pipeline_graphics.c#L688-689 + // https://gitlab.freedesktop.org/mesa/mesa/-/blob/209a0ed/src/amd/vulkan/radv_cmd_buffer.c#L3103-3109 + // When the clip space is ranged [-1...1], the zoffset is centered. + // By reversing the above viewport calculations, we get the following: + if (regs.clipper_control.clip_space == AmdGpu::Liverpool::ClipSpace::MinusWToW) { + viewport.minDepth = zoffset - zscale; + viewport.maxDepth = zoffset + zscale; + } else { + viewport.minDepth = zoffset; + viewport.maxDepth = zoffset + zscale; + } + + if (!regs.depth_render_override.disable_viewport_clamp) { + // Apply depth clamp. + viewport.minDepth = std::max(viewport.minDepth, vp_d.zmin); + viewport.maxDepth = std::min(viewport.maxDepth, vp_d.zmax); + } + + if (!instance.IsDepthRangeUnrestrictedSupported()) { + // Unrestricted depth range not supported by device. Restrict to valid range. + viewport.minDepth = std::max(viewport.minDepth, 0.f); + viewport.maxDepth = std::min(viewport.maxDepth, 1.f); + } + if (regs.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 // window range [0..16383, 0..16383] and setting the viewport to its size. - viewports.push_back({ - .x = 0.f, - .y = 0.f, - .width = float(std::min(instance.GetMaxViewportWidth(), 16_KB)), - .height = float(std::min(instance.GetMaxViewportHeight(), 16_KB)), - .minDepth = zoffset - zscale * reduce_z, - .maxDepth = zscale + zoffset, - }); + viewport.x = 0.f; + viewport.y = 0.f; + viewport.width = float(std::min(instance.GetMaxViewportWidth(), 16_KB)); + viewport.height = float(std::min(instance.GetMaxViewportHeight(), 16_KB)); } 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; - viewports.push_back({ - .x = xoffset - xscale, - .y = yoffset - yscale, - .width = xscale * 2.0f, - .height = yscale * 2.0f, - .minDepth = zoffset - zscale * reduce_z, - .maxDepth = zscale + zoffset, - }); + + viewport.x = xoffset - xscale; + viewport.y = yoffset - yscale; + viewport.width = xscale * 2.0f; + viewport.height = yscale * 2.0f; } + viewports.push_back(viewport); + auto vp_scsr = scsr; if (regs.mode_control.vport_scissor_enable) { vp_scsr.top_left_x = diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index a48d93dee..8d4188a22 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp @@ -170,29 +170,29 @@ void Scheduler::SubmitExecution(SubmitInfo& info) { void DynamicState::Commit(const Instance& instance, const vk::CommandBuffer& cmdbuf) { if (dirty_state.viewports) { dirty_state.viewports = false; - cmdbuf.setViewportWithCountEXT(viewports); + cmdbuf.setViewportWithCount(viewports); } if (dirty_state.scissors) { dirty_state.scissors = false; - cmdbuf.setScissorWithCountEXT(scissors); + cmdbuf.setScissorWithCount(scissors); } if (dirty_state.depth_test_enabled) { dirty_state.depth_test_enabled = false; - cmdbuf.setDepthTestEnableEXT(depth_test_enabled); + cmdbuf.setDepthTestEnable(depth_test_enabled); } if (dirty_state.depth_write_enabled) { dirty_state.depth_write_enabled = false; // Note that this must be set in a command buffer even if depth test is disabled. - cmdbuf.setDepthWriteEnableEXT(depth_write_enabled); + cmdbuf.setDepthWriteEnable(depth_write_enabled); } if (depth_test_enabled && dirty_state.depth_compare_op) { dirty_state.depth_compare_op = false; - cmdbuf.setDepthCompareOpEXT(depth_compare_op); + cmdbuf.setDepthCompareOp(depth_compare_op); } if (dirty_state.depth_bounds_test_enabled) { dirty_state.depth_bounds_test_enabled = false; if (instance.IsDepthBoundsSupported()) { - cmdbuf.setDepthBoundsTestEnableEXT(depth_bounds_test_enabled); + cmdbuf.setDepthBoundsTestEnable(depth_bounds_test_enabled); } } if (depth_bounds_test_enabled && dirty_state.depth_bounds) { @@ -203,7 +203,7 @@ void DynamicState::Commit(const Instance& instance, const vk::CommandBuffer& cmd } if (dirty_state.depth_bias_enabled) { dirty_state.depth_bias_enabled = false; - cmdbuf.setDepthBiasEnableEXT(depth_bias_enabled); + cmdbuf.setDepthBiasEnable(depth_bias_enabled); } if (depth_bias_enabled && dirty_state.depth_bias) { dirty_state.depth_bias = false; @@ -211,28 +211,28 @@ void DynamicState::Commit(const Instance& instance, const vk::CommandBuffer& cmd } if (dirty_state.stencil_test_enabled) { dirty_state.stencil_test_enabled = false; - cmdbuf.setStencilTestEnableEXT(stencil_test_enabled); + cmdbuf.setStencilTestEnable(stencil_test_enabled); } if (stencil_test_enabled) { if (dirty_state.stencil_front_ops && dirty_state.stencil_back_ops && stencil_front_ops == stencil_back_ops) { dirty_state.stencil_front_ops = false; dirty_state.stencil_back_ops = false; - cmdbuf.setStencilOpEXT(vk::StencilFaceFlagBits::eFrontAndBack, - stencil_front_ops.fail_op, stencil_front_ops.pass_op, - stencil_front_ops.depth_fail_op, stencil_front_ops.compare_op); + cmdbuf.setStencilOp(vk::StencilFaceFlagBits::eFrontAndBack, stencil_front_ops.fail_op, + stencil_front_ops.pass_op, stencil_front_ops.depth_fail_op, + stencil_front_ops.compare_op); } else { if (dirty_state.stencil_front_ops) { dirty_state.stencil_front_ops = false; - cmdbuf.setStencilOpEXT(vk::StencilFaceFlagBits::eFront, stencil_front_ops.fail_op, - stencil_front_ops.pass_op, stencil_front_ops.depth_fail_op, - stencil_front_ops.compare_op); + cmdbuf.setStencilOp(vk::StencilFaceFlagBits::eFront, stencil_front_ops.fail_op, + stencil_front_ops.pass_op, stencil_front_ops.depth_fail_op, + stencil_front_ops.compare_op); } if (dirty_state.stencil_back_ops) { dirty_state.stencil_back_ops = false; - cmdbuf.setStencilOpEXT(vk::StencilFaceFlagBits::eBack, stencil_back_ops.fail_op, - stencil_back_ops.pass_op, stencil_back_ops.depth_fail_op, - stencil_back_ops.compare_op); + cmdbuf.setStencilOp(vk::StencilFaceFlagBits::eBack, stencil_back_ops.fail_op, + stencil_back_ops.pass_op, stencil_back_ops.depth_fail_op, + stencil_back_ops.compare_op); } } if (dirty_state.stencil_front_reference && dirty_state.stencil_back_reference && @@ -291,16 +291,16 @@ void DynamicState::Commit(const Instance& instance, const vk::CommandBuffer& cmd if (dirty_state.primitive_restart_enable) { dirty_state.primitive_restart_enable = false; if (instance.IsPrimitiveRestartDisableSupported()) { - cmdbuf.setPrimitiveRestartEnableEXT(primitive_restart_enable); + cmdbuf.setPrimitiveRestartEnable(primitive_restart_enable); } } if (dirty_state.cull_mode) { dirty_state.cull_mode = false; - cmdbuf.setCullModeEXT(cull_mode); + cmdbuf.setCullMode(cull_mode); } if (dirty_state.front_face) { dirty_state.front_face = false; - cmdbuf.setFrontFaceEXT(front_face); + cmdbuf.setFrontFace(front_face); } if (dirty_state.blend_constants) { dirty_state.blend_constants = false; diff --git a/src/video_core/texture_cache/texture_cache.cpp b/src/video_core/texture_cache/texture_cache.cpp index d41ee57cc..047bb3dfe 100644 --- a/src/video_core/texture_cache/texture_cache.cpp +++ b/src/video_core/texture_cache/texture_cache.cpp @@ -319,15 +319,14 @@ ImageId TextureCache::FindImage(BaseDesc& desc, FindFlags flags) { continue; } if (False(flags & FindFlags::RelaxFmt) && - !IsVulkanFormatCompatible(info.pixel_format, cache_image.info.pixel_format)) { + (!IsVulkanFormatCompatible(info.pixel_format, cache_image.info.pixel_format) || + (cache_image.info.type != info.type && info.size != Extent3D{1, 1, 1}))) { continue; } if (True(flags & FindFlags::ExactFmt) && info.pixel_format != cache_image.info.pixel_format) { continue; } - ASSERT((cache_image.info.type == info.type || info.size == Extent3D{1, 1, 1} || - True(flags & FindFlags::RelaxFmt))); image_id = cache_id; }