diff --git a/.gitmodules b/.gitmodules index 3d0d21c5b..1c05ba6f3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -119,3 +119,7 @@ path = externals/MoltenVK/cereal url = https://github.com/USCiLab/cereal shallow = true +[submodule "externals/cubeb"] + path = externals/cubeb + url = https://github.com/mozilla/cubeb + shallow = true diff --git a/CMakeLists.txt b/CMakeLists.txt index dac3b19ab..43e8d7cab 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -106,7 +106,7 @@ git_describe(GIT_DESC --always --long --dirty) git_branch_name(GIT_BRANCH) string(TIMESTAMP BUILD_DATE "%Y-%m-%d %H:%M:%S") -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/common/scm_rev.cpp.in" "${CMAKE_CURRENT_SOURCE_DIR}/src/common/scm_rev.cpp" @ONLY) +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/common/scm_rev.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/src/common/scm_rev.cpp" @ONLY) find_package(Boost 1.84.0 CONFIG) find_package(FFmpeg 5.1.2 MODULE) @@ -127,6 +127,7 @@ find_package(xxHash 0.8.2 MODULE) find_package(ZLIB 1.3 MODULE) find_package(Zydis 5.0.0 CONFIG) find_package(pugixml 1.14 CONFIG) +find_package(cubeb CONFIG) if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR NOT MSVC) find_package(cryptopp 8.9.0 MODULE) @@ -198,9 +199,10 @@ set(AUDIO_LIB src/core/libraries/audio/audioin.cpp src/core/libraries/audio/audioin.h src/core/libraries/audio/audioout.cpp src/core/libraries/audio/audioout.h - src/core/libraries/audio/sdl_audio.cpp - src/core/libraries/audio/sdl_audio.h + src/core/libraries/audio/audioout_backend.h src/core/libraries/audio/audioout_error.h + src/core/libraries/audio/cubeb_audio.cpp + src/core/libraries/audio/sdl_audio.cpp src/core/libraries/ngs2/ngs2.cpp src/core/libraries/ngs2/ngs2.h ) @@ -493,6 +495,7 @@ set(COMMON src/common/logging/backend.cpp src/common/polyfill_thread.h src/common/rdtsc.cpp src/common/rdtsc.h + src/common/ringbuffer.h src/common/signal_context.h src/common/signal_context.cpp src/common/singleton.h @@ -517,7 +520,7 @@ set(COMMON src/common/logging/backend.cpp src/common/number_utils.cpp src/common/memory_patcher.h src/common/memory_patcher.cpp - src/common/scm_rev.cpp + ${CMAKE_CURRENT_BINARY_DIR}/src/common/scm_rev.cpp src/common/scm_rev.h ) @@ -884,7 +887,7 @@ endif() create_target_directory_groups(shadps4) target_link_libraries(shadps4 PRIVATE magic_enum::magic_enum fmt::fmt toml11::toml11 tsl::robin_map xbyak::xbyak Tracy::TracyClient RenderDoc::API FFmpeg::ffmpeg Dear_ImGui gcn half::half ZLIB::ZLIB PNG::PNG) -target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator LibAtrac9 sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::glslang SDL3::SDL3 pugixml::pugixml stb::headers) +target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator LibAtrac9 sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::glslang SDL3::SDL3 pugixml::pugixml stb::headers cubeb::cubeb) target_compile_definitions(shadps4 PRIVATE IMGUI_USER_CONFIG="imgui/imgui_config.h") target_compile_definitions(Dear_ImGui PRIVATE IMGUI_USER_CONFIG="${PROJECT_SOURCE_DIR}/src/imgui/imgui_config.h") @@ -901,11 +904,18 @@ 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. - target_sources(shadps4 PRIVATE externals/MoltenVK/MoltenVK_icd.json) - set_source_files_properties(externals/MoltenVK/MoltenVK_icd.json - PROPERTIES MACOSX_PACKAGE_LOCATION Resources/vulkan/icd.d) - add_custom_command(TARGET shadps4 POST_BUILD - COMMAND cmake -E copy $ $/Contents/Frameworks/libMoltenVK.dylib) + 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) + + 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(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. diff --git a/LICENSES/ISC.txt b/LICENSES/ISC.txt new file mode 100644 index 000000000..b9bcfa3a4 --- /dev/null +++ b/LICENSES/ISC.txt @@ -0,0 +1,7 @@ +ISC License + + + +Permission to use, copy, modify, and /or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/README.md b/README.md index 7ef5bdf65..7ba13ad47 100644 --- a/README.md +++ b/README.md @@ -86,32 +86,32 @@ F12 | Trigger RenderDoc Capture > [!NOTE] > Xbox and DualShock controllers work out of the box. -| Controller button | Keyboard equivelant | -|-------------|-------------| -LEFT AXIS UP | W | -LEFT AXIS DOWN | S | -LEFT AXIS LEFT | A | -LEFT AXIS RIGHT | D | -RIGHT AXIS UP | I | -RIGHT AXIS DOWN | K | -RIGHT AXIS LEFT | J | -RIGHT AXIS RIGHT | L | -TRIANGLE | Numpad 8 | -CIRCLE | Numpad 6 | -CROSS | Numpad 2 | -SQUARE | Numpad 4 | -PAD UP | UP | -PAD DOWN | DOWN | -PAD LEFT | LEFT | -PAD RIGHT | RIGHT | -OPTIONS | RETURN | -BACK BUTTON / TOUCH PAD | SPACE | -L1 | Q | -R1 | U | -L2 | E | -R2 | O | -L3 | X | -R3 | M | +| Controller button | Keyboard equivelant | Mac alternative | +|-------------|-------------|--------------| +LEFT AXIS UP | W | | +LEFT AXIS DOWN | S | | +LEFT AXIS LEFT | A | | +LEFT AXIS RIGHT | D | | +RIGHT AXIS UP | I | | +RIGHT AXIS DOWN | K | | +RIGHT AXIS LEFT | J | | +RIGHT AXIS RIGHT | L | | +TRIANGLE | Numpad 8 | C | +CIRCLE | Numpad 6 | B | +CROSS | Numpad 2 | N | +SQUARE | Numpad 4 | V | +PAD UP | UP | | +PAD DOWN | DOWN | | +PAD LEFT | LEFT | | +PAD RIGHT | RIGHT | | +OPTIONS | RETURN | | +BACK BUTTON / TOUCH PAD | SPACE | | +L1 | Q | | +R1 | U | | +L2 | E | | +R2 | O | | +L3 | X | | +R3 | M | | # Main team diff --git a/documents/building-windows.md b/documents/building-windows.md index d01e7b81e..845cdd10f 100644 --- a/documents/building-windows.md +++ b/documents/building-windows.md @@ -25,7 +25,7 @@ Once you are within the installer: Beware, this requires you to create a Qt account. If you do not want to do this, please follow the MSYS2/MinGW compilation method instead. -1. Under the current, non beta version of Qt (at the time of writing 6.7.3), select the option `MSVC 2022 64-bit` or similar. +1. Under the current, non beta version of Qt (at the time of writing 6.7.3), select the option `MSVC 2022 64-bit` or similar, as well as `QT Multimedia`. If you are on Windows on ARM / Qualcomm Snapdragon Elite X, select `MSVC 2022 ARM64` instead. Go through the installation normally. If you know what you are doing, you may unselect individual components that eat up too much disk space. @@ -64,7 +64,7 @@ Go through the Git for Windows installation as normal Your shadps4.exe will be in `C:\path\to\source\Build\x64-Clang-Release\` To automatically populate the necessary files to run shadPS4.exe, run in a command prompt or terminal: -`C:\Qt\6.7.3\msvc2022_64\bin\windeployqt.exe "C:\path\to\shadps4.exe"` +`C:\Qt\6.7.3\msvc2022_64\bin\windeployqt6.exe "C:\path\to\shadps4.exe"` (Change Qt path if you've installed it to non-default path) ## Option 2: MSYS2/MinGW diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 4350948b7..8bdf089f8 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -228,6 +228,16 @@ if (NOT TARGET stb::headers) add_library(stb::headers ALIAS stb) endif() +# cubeb +if (NOT TARGET cubeb::cubeb) + option(BUILD_TESTS "" OFF) + option(BUILD_TOOLS "" OFF) + option(BUNDLE_SPEEX "" ON) + option(USE_SANITIZERS "" OFF) + add_subdirectory(cubeb) + add_library(cubeb::cubeb ALIAS cubeb) +endif() + # Apple-only dependencies if (APPLE) # date diff --git a/externals/cubeb b/externals/cubeb new file mode 160000 index 000000000..9a9d034c5 --- /dev/null +++ b/externals/cubeb @@ -0,0 +1 @@ +Subproject commit 9a9d034c51859a045a34f201334f612c51e6c19d diff --git a/src/common/config.cpp b/src/common/config.cpp index 7413f6409..d477451e1 100644 --- a/src/common/config.cpp +++ b/src/common/config.cpp @@ -67,6 +67,7 @@ static int cursorHideTimeout = 5; // 5 seconds (default) static bool separateupdatefolder = false; static bool compatibilityData = false; static bool checkCompatibilityOnStartup = false; +static std::string audioBackend = "cubeb"; // Gui std::vector settings_install_dirs = {}; @@ -239,6 +240,10 @@ bool getCheckCompatibilityOnStartup() { return checkCompatibilityOnStartup; } +std::string getAudioBackend() { + return audioBackend; +} + void setGpuId(s32 selectedGpuId) { gpuId = selectedGpuId; } @@ -371,6 +376,10 @@ void setCheckCompatibilityOnStartup(bool use) { checkCompatibilityOnStartup = use; } +void setAudioBackend(std::string backend) { + audioBackend = backend; +} + void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h) { main_window_geometry_x = x; main_window_geometry_y = y; @@ -623,6 +632,12 @@ void load(const std::filesystem::path& path) { vkCrashDiagnostic = toml::find_or(vk, "crashDiagnostic", false); } + if (data.contains("Audio")) { + const toml::value& audio = data.at("Audio"); + + audioBackend = toml::find_or(audio, "backend", "cubeb"); + } + if (data.contains("Debug")) { const toml::value& debug = data.at("Debug"); @@ -721,6 +736,7 @@ void save(const std::filesystem::path& path) { data["Vulkan"]["rdocEnable"] = rdocEnable; data["Vulkan"]["rdocMarkersEnable"] = vkMarkers; data["Vulkan"]["crashDiagnostic"] = vkCrashDiagnostic; + data["Audio"]["backend"] = audioBackend; data["Debug"]["DebugDump"] = isDebugDump; data["Debug"]["CollectShader"] = isShaderDebug; @@ -824,6 +840,7 @@ void setDefaultValues() { separateupdatefolder = false; compatibilityData = false; checkCompatibilityOnStartup = false; + audioBackend = "cubeb"; } } // namespace Config diff --git a/src/common/config.h b/src/common/config.h index 701aadb12..43ef5024b 100644 --- a/src/common/config.h +++ b/src/common/config.h @@ -24,6 +24,7 @@ bool getEnableDiscordRPC(); bool getSeparateUpdateEnabled(); bool getCompatibilityEnabled(); bool getCheckCompatibilityOnStartup(); +std::string getAudioBackend(); std::string getLogFilter(); std::string getLogType(); @@ -75,6 +76,7 @@ void setSeparateUpdateEnabled(bool use); void setGameInstallDirs(const std::vector& settings_install_dirs_config); void setCompatibilityEnabled(bool use); void setCheckCompatibilityOnStartup(bool use); +void setAudioBackend(std::string backend); void setCursorState(s16 cursorState); void setCursorHideTimeout(int newcursorHideTimeout); diff --git a/src/common/ringbuffer.h b/src/common/ringbuffer.h new file mode 100644 index 000000000..6a71c2888 --- /dev/null +++ b/src/common/ringbuffer.h @@ -0,0 +1,374 @@ +// SPDX-FileCopyrightText: Copyright 2016 Mozilla Foundation +// SPDX-License-Identifier: ISC + +#pragma once + +#include +#include +#include +#include +#include +#include "common/assert.h" + +/** + * Single producer single consumer lock-free and wait-free ring buffer. + * + * This data structure allows producing data from one thread, and consuming it + * on another thread, safely and without explicit synchronization. If used on + * two threads, this data structure uses atomics for thread safety. It is + * possible to disable the use of atomics at compile time and only use this data + * structure on one thread. + * + * The role for the producer and the consumer must be constant, i.e., the + * producer should always be on one thread and the consumer should always be on + * another thread. + * + * Some words about the inner workings of this class: + * - Capacity is fixed. Only one allocation is performed, in the constructor. + * When reading and writing, the return value of the method allows checking if + * the ring buffer is empty or full. + * - We always keep the read index at least one element ahead of the write + * index, so we can distinguish between an empty and a full ring buffer: an + * empty ring buffer is when the write index is at the same position as the + * read index. A full buffer is when the write index is exactly one position + * before the read index. + * - We synchronize updates to the read index after having read the data, and + * the write index after having written the data. This means that the each + * thread can only touch a portion of the buffer that is not touched by the + * other thread. + * - Callers are expected to provide buffers. When writing to the queue, + * elements are copied into the internal storage from the buffer passed in. + * When reading from the queue, the user is expected to provide a buffer. + * Because this is a ring buffer, data might not be contiguous in memory, + * providing an external buffer to copy into is an easy way to have linear + * data for further processing. + */ +template +class RingBuffer { +public: + /** + * Constructor for a ring buffer. + * + * This performs an allocation, but is the only allocation that will happen + * for the life time of a `RingBuffer`. + * + * @param capacity The maximum number of element this ring buffer will hold. + */ + RingBuffer(int capacity) + /* One more element to distinguish from empty and full buffer. */ + : capacity_(capacity + 1) { + ASSERT(storage_capacity() < std::numeric_limits::max() / 2 && + "buffer too large for the type of index used."); + ASSERT(capacity_ > 0); + + data_.reset(new T[storage_capacity()]); + /* If this queue is using atomics, initializing those members as the last + * action in the constructor acts as a full barrier, and allow capacity() to + * be thread-safe. */ + write_index_ = 0; + read_index_ = 0; + } + /** + * Push `count` zero or default constructed elements in the array. + * + * Only safely called on the producer thread. + * + * @param count The number of elements to enqueue. + * @return The number of element enqueued. + */ + int enqueue_default(int count) { + return enqueue(nullptr, count); + } + /** + * @brief Put an element in the queue + * + * Only safely called on the producer thread. + * + * @param element The element to put in the queue. + * + * @return 1 if the element was inserted, 0 otherwise. + */ + int enqueue(T& element) { + return enqueue(&element, 1); + } + /** + * Push `count` elements in the ring buffer. + * + * Only safely called on the producer thread. + * + * @param elements a pointer to a buffer containing at least `count` elements. + * If `elements` is nullptr, zero or default constructed elements are + * enqueued. + * @param count The number of elements to read from `elements` + * @return The number of elements successfully coped from `elements` and + * inserted into the ring buffer. + */ + int enqueue(T* elements, int count) { +#ifndef NDEBUG + assert_correct_thread(producer_id); +#endif + + int wr_idx = write_index_.load(std::memory_order_relaxed); + int rd_idx = read_index_.load(std::memory_order_acquire); + + if (full_internal(rd_idx, wr_idx)) { + return 0; + } + + int to_write = std::min(available_write_internal(rd_idx, wr_idx), count); + + /* First part, from the write index to the end of the array. */ + int first_part = std::min(storage_capacity() - wr_idx, to_write); + /* Second part, from the beginning of the array */ + int second_part = to_write - first_part; + + if (elements) { + Copy(data_.get() + wr_idx, elements, first_part); + Copy(data_.get(), elements + first_part, second_part); + } else { + ConstructDefault(data_.get() + wr_idx, first_part); + ConstructDefault(data_.get(), second_part); + } + + write_index_.store(increment_index(wr_idx, to_write), std::memory_order_release); + + return to_write; + } + /** + * Retrieve at most `count` elements from the ring buffer, and copy them to + * `elements`, if non-null. + * + * Only safely called on the consumer side. + * + * @param elements A pointer to a buffer with space for at least `count` + * elements. If `elements` is `nullptr`, `count` element will be discarded. + * @param count The maximum number of elements to dequeue. + * @return The number of elements written to `elements`. + */ + int dequeue(T* elements, int count) { +#ifndef NDEBUG + assert_correct_thread(consumer_id); +#endif + + int rd_idx = read_index_.load(std::memory_order_relaxed); + int wr_idx = write_index_.load(std::memory_order_acquire); + + if (empty_internal(rd_idx, wr_idx)) { + return 0; + } + + int to_read = std::min(available_read_internal(rd_idx, wr_idx), count); + + int first_part = std::min(storage_capacity() - rd_idx, to_read); + int second_part = to_read - first_part; + + if (elements) { + Copy(elements, data_.get() + rd_idx, first_part); + Copy(elements + first_part, data_.get(), second_part); + } + + read_index_.store(increment_index(rd_idx, to_read), std::memory_order_release); + + return to_read; + } + /** + * Get the number of available element for consuming. + * + * Only safely called on the consumer thread. + * + * @return The number of available elements for reading. + */ + int available_read() const { +#ifndef NDEBUG + assert_correct_thread(consumer_id); +#endif + return available_read_internal(read_index_.load(std::memory_order_relaxed), + write_index_.load(std::memory_order_acquire)); + } + /** + * Get the number of available elements for consuming. + * + * Only safely called on the producer thread. + * + * @return The number of empty slots in the buffer, available for writing. + */ + int available_write() const { +#ifndef NDEBUG + assert_correct_thread(producer_id); +#endif + return available_write_internal(read_index_.load(std::memory_order_acquire), + write_index_.load(std::memory_order_relaxed)); + } + /** + * Get the total capacity, for this ring buffer. + * + * Can be called safely on any thread. + * + * @return The maximum capacity of this ring buffer. + */ + int capacity() const { + return storage_capacity() - 1; + } + /** + * Reset the consumer and producer thread identifier, in case the thread are + * being changed. This has to be externally synchronized. This is no-op when + * asserts are disabled. + */ + void reset_thread_ids() { +#ifndef NDEBUG + consumer_id = producer_id = std::thread::id(); +#endif + } + +private: + /** Return true if the ring buffer is empty. + * + * @param read_index the read index to consider + * @param write_index the write index to consider + * @return true if the ring buffer is empty, false otherwise. + **/ + bool empty_internal(int read_index, int write_index) const { + return write_index == read_index; + } + /** Return true if the ring buffer is full. + * + * This happens if the write index is exactly one element behind the read + * index. + * + * @param read_index the read index to consider + * @param write_index the write index to consider + * @return true if the ring buffer is full, false otherwise. + **/ + bool full_internal(int read_index, int write_index) const { + return (write_index + 1) % storage_capacity() == read_index; + } + /** + * Return the size of the storage. It is one more than the number of elements + * that can be stored in the buffer. + * + * @return the number of elements that can be stored in the buffer. + */ + int storage_capacity() const { + return capacity_; + } + /** + * Returns the number of elements available for reading. + * + * @return the number of available elements for reading. + */ + int available_read_internal(int read_index, int write_index) const { + if (write_index >= read_index) { + return write_index - read_index; + } else { + return write_index + storage_capacity() - read_index; + } + } + /** + * Returns the number of empty elements, available for writing. + * + * @return the number of elements that can be written into the array. + */ + int available_write_internal(int read_index, int write_index) const { + /* We substract one element here to always keep at least one sample + * free in the buffer, to distinguish between full and empty array. */ + int rv = read_index - write_index - 1; + if (write_index >= read_index) { + rv += storage_capacity(); + } + return rv; + } + /** + * Increments an index, wrapping it around the storage. + * + * @param index a reference to the index to increment. + * @param increment the number by which `index` is incremented. + * @return the new index. + */ + int increment_index(int index, int increment) const { + ASSERT(increment >= 0); + return (index + increment) % storage_capacity(); + } + /** + * @brief This allows checking that enqueue (resp. dequeue) are always called + * by the right thread. + * + * @param id the id of the thread that has called the calling method first. + */ +#ifndef NDEBUG + static void assert_correct_thread(std::thread::id& id) { + if (id == std::thread::id()) { + id = std::this_thread::get_id(); + return; + } + ASSERT(id == std::this_thread::get_id()); + } +#endif + /** Similar to memcpy, but accounts for the size of an element. */ + template + void PodCopy(CopyT* destination, const CopyT* source, size_t count) { + static_assert(std::is_trivial::value, "Requires trivial type"); + ASSERT(destination && source); + memcpy(destination, source, count * sizeof(CopyT)); + } + /** Similar to a memset to zero, but accounts for the size of an element. */ + template + void PodZero(ZeroT* destination, size_t count) { + static_assert(std::is_trivial::value, "Requires trivial type"); + ASSERT(destination); + memset(destination, 0, count * sizeof(ZeroT)); + } + template + void Copy(CopyT* destination, const CopyT* source, size_t count, Trait) { + for (size_t i = 0; i < count; i++) { + destination[i] = source[i]; + } + } + template + void Copy(CopyT* destination, const CopyT* source, size_t count, std::true_type) { + PodCopy(destination, source, count); + } + /** + * This allows copying a number of elements from a `source` pointer to a + * `destination` pointer, using `memcpy` if it is safe to do so, or a loop that + * calls the constructors and destructors otherwise. + */ + template + void Copy(CopyT* destination, const T* source, size_t count) { + ASSERT(destination && source); + Copy(destination, source, count, typename std::is_trivial::type()); + } + template + void ConstructDefault(ConstructT* destination, size_t count, Trait) { + for (size_t i = 0; i < count; i++) { + destination[i] = ConstructT(); + } + } + template + void ConstructDefault(ConstructT* destination, size_t count, std::true_type) { + PodZero(destination, count); + } + /** + * This allows zeroing (using memset) or default-constructing a number of + * elements calling the constructors and destructors if necessary. + */ + template + void ConstructDefault(ConstructT* destination, size_t count) { + ASSERT(destination); + ConstructDefault(destination, count, typename std::is_arithmetic::type()); + } + /** Index at which the oldest element is at, in samples. */ + std::atomic read_index_; + /** Index at which to write new elements. `write_index` is always at + * least one element ahead of `read_index_`. */ + std::atomic write_index_; + /** Maximum number of elements that can be stored in the ring buffer. */ + const int capacity_; + /** Data storage */ + std::unique_ptr data_; +#ifndef NDEBUG + /** The id of the only thread that is allowed to read from the queue. */ + mutable std::thread::id consumer_id; + /** The id of the only thread that is allowed to write from the queue. */ + mutable std::thread::id producer_id; +#endif +}; diff --git a/src/common/version.h b/src/common/version.h index 5e6599604..c903b1db6 100644 --- a/src/common/version.h +++ b/src/common/version.h @@ -8,7 +8,7 @@ namespace Common { -constexpr char VERSION[] = "0.4.1 WIP"; +constexpr char VERSION[] = "0.5.1 WIP"; constexpr bool isRelease = false; } // namespace Common diff --git a/src/core/crypto/crypto.cpp b/src/core/crypto/crypto.cpp index aa1c96724..00f1dea46 100644 --- a/src/core/crypto/crypto.cpp +++ b/src/core/crypto/crypto.cpp @@ -141,12 +141,9 @@ void Crypto::decryptEFSM(std::span NPcommID, std::span efsmIv, std::span ciphertext, std::span decrypted) { - std::vector TrophyKey = {0x21, 0xF4, 0x1A, 0x6B, 0xAD, 0x8A, 0x1D, 0x3E, - 0xCA, 0x7A, 0xD5, 0x86, 0xC1, 0x01, 0xB7, 0xA9}; std::vector TrophyIV = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // step 1: Encrypt NPcommID CryptoPP::CBC_Mode::Encryption encrypt; - encrypt.SetKeyWithIV(TrophyKey.data(), TrophyKey.size(), TrophyIV.data()); std::vector trpKey(16); diff --git a/src/core/debug_state.cpp b/src/core/debug_state.cpp index daf614bd9..6508a9875 100644 --- a/src/core/debug_state.cpp +++ b/src/core/debug_state.cpp @@ -11,6 +11,7 @@ #include "libraries/kernel/time.h" #include "libraries/system/msgdialog.h" #include "video_core/amdgpu/pm4_cmds.h" +#include "video_core/renderer_vulkan/vk_pipeline_cache.h" using namespace DebugStateType; @@ -168,8 +169,12 @@ void DebugStateImpl::PushRegsDump(uintptr_t base_addr, uintptr_t header_addr, if ((*dump)->regs.stage_enable.IsStageEnabled(i)) { auto stage = (*dump)->regs.ProgramForStage(i); if (stage->address_lo != 0) { + const auto& info = AmdGpu::Liverpool::SearchBinaryInfo(stage->Address()); auto code = stage->Code(); (*dump)->stages[i] = PipelineShaderProgramDump{ + .name = Vulkan::PipelineCache::GetShaderName(Shader::StageFromIndex(i), + info.shader_hash), + .hash = info.shader_hash, .user_data = *stage, .code = std::vector{code.begin(), code.end()}, }; @@ -191,7 +196,10 @@ void DebugStateImpl::PushRegsDumpCompute(uintptr_t base_addr, uintptr_t header_a auto& cs = (*dump)->regs.cs_program; cs = cs_state; + const auto& info = AmdGpu::Liverpool::SearchBinaryInfo(cs.Address()); (*dump)->cs_data = PipelineComputerProgramDump{ + .name = Vulkan::PipelineCache::GetShaderName(Shader::Stage::Compute, info.shader_hash), + .hash = info.shader_hash, .cs_program = cs, .code = std::vector{cs.Code().begin(), cs.Code().end()}, }; diff --git a/src/core/debug_state.h b/src/core/debug_state.h index a0e428b6b..6a8e15baa 100644 --- a/src/core/debug_state.h +++ b/src/core/debug_state.h @@ -50,11 +50,15 @@ struct QueueDump { }; struct PipelineShaderProgramDump { + std::string name; + u64 hash; Vulkan::Liverpool::ShaderProgram user_data{}; std::vector code{}; }; struct PipelineComputerProgramDump { + std::string name; + u64 hash; Vulkan::Liverpool::ComputeProgram cs_program{}; std::vector code{}; }; diff --git a/src/core/devtools/widget/cmd_list.cpp b/src/core/devtools/widget/cmd_list.cpp index 7c550cf2e..dc3eb9cdd 100644 --- a/src/core/devtools/widget/cmd_list.cpp +++ b/src/core/devtools/widget/cmd_list.cpp @@ -1174,7 +1174,7 @@ CmdListViewer::CmdListViewer(DebugStateType::FrameDump* _frame_dump, } } -void CmdListViewer::Draw(bool only_batches_view) { +void CmdListViewer::Draw(bool only_batches_view, CmdListFilter& filter) { const auto& ctx = *GetCurrentContext(); if (batch_view.open) { @@ -1285,6 +1285,41 @@ void CmdListViewer::Draw(bool only_batches_view) { } auto& batch = std::get(event); + + // filtering + { + bool remove = false; + + if (filter.shader_name[0] != '\0') { + remove = true; + std::string_view shader_name{filter.shader_name}; + const auto& data = frame_dump->regs.find(batch.command_addr); + if (data != frame_dump->regs.end()) { + DebugStateType::RegDump& dump = data->second; + if (dump.is_compute) { + if (dump.cs_data.name.contains(shader_name)) { + remove = false; + break; + } + } else { + for (int i = 0; i < DebugStateType::RegDump::MaxShaderStages; ++i) { + if (dump.regs.stage_enable.IsStageEnabled(i)) { + auto& stage = dump.stages[i]; + if (stage.name.contains(shader_name)) { + remove = false; + break; + } + } + } + } + } + } + + if (remove) { + continue; + } + } + auto const* pm4_hdr = reinterpret_cast(cmdb_addr + batch.start_addr); diff --git a/src/core/devtools/widget/cmd_list.h b/src/core/devtools/widget/cmd_list.h index ed71d0b76..e2c61f6b9 100644 --- a/src/core/devtools/widget/cmd_list.h +++ b/src/core/devtools/widget/cmd_list.h @@ -35,6 +35,10 @@ void ParseDepthControl(u32 value, bool begin_table = true); void ParseEqaa(u32 value, bool begin_table = true); void ParseZInfo(u32 value, bool begin_table = true); +struct CmdListFilter { + char shader_name[128]{}; +}; + class CmdListViewer { DebugStateType::FrameDump* frame_dump; @@ -70,7 +74,7 @@ public: explicit CmdListViewer(DebugStateType::FrameDump* frame_dump, const std::vector& cmd_list, uintptr_t base_addr = 0, std::string name = ""); - void Draw(bool only_batches_view = false); + void Draw(bool only_batches_view, CmdListFilter& filter); }; } // namespace Core::Devtools::Widget diff --git a/src/core/devtools/widget/common.h b/src/core/devtools/widget/common.h index 75eb55301..4684f6e3b 100644 --- a/src/core/devtools/widget/common.h +++ b/src/core/devtools/widget/common.h @@ -117,7 +117,7 @@ static bool IsDrawCall(AmdGpu::PM4ItOpcode opcode) { inline std::optional exec_cli(const char* cli) { std::array buffer{}; std::string output; - const auto f = popen(cli, "rt"); + const auto f = popen(cli, "r"); if (!f) { pclose(f); return {}; diff --git a/src/core/devtools/widget/frame_dump.cpp b/src/core/devtools/widget/frame_dump.cpp index 055ce1333..646ccb6d6 100644 --- a/src/core/devtools/widget/frame_dump.cpp +++ b/src/core/devtools/widget/frame_dump.cpp @@ -132,6 +132,15 @@ void FrameDumpViewer::Draw() { } } EndDisabled(); + SameLine(); + if (BeginMenu("Filter")) { + + TextUnformatted("Shader name"); + SameLine(); + InputText("##filter_shader", filter.shader_name, sizeof(filter.shader_name)); + + ImGui::EndMenu(); + } TextEx("Submit num"); SameLine(); @@ -187,7 +196,7 @@ void FrameDumpViewer::Draw() { EndGroup(); } if (is_showing && selected_cmd != -1) { - cmd_list_viewer[selected_cmd].Draw(is_collapsed); + cmd_list_viewer[selected_cmd].Draw(is_collapsed, filter); } End(); } diff --git a/src/core/devtools/widget/frame_dump.h b/src/core/devtools/widget/frame_dump.h index cc4fe6381..94075112b 100644 --- a/src/core/devtools/widget/frame_dump.h +++ b/src/core/devtools/widget/frame_dump.h @@ -27,6 +27,8 @@ class FrameDumpViewer { s32 selected_queue_num2; s32 selected_cmd = -1; + CmdListFilter filter; + public: bool is_open = true; diff --git a/src/core/devtools/widget/frame_graph.cpp b/src/core/devtools/widget/frame_graph.cpp index 952f50c34..0e170db38 100644 --- a/src/core/devtools/widget/frame_graph.cpp +++ b/src/core/devtools/widget/frame_graph.cpp @@ -19,6 +19,57 @@ constexpr float BAR_HEIGHT_MULT = 1.25f; constexpr float FRAME_GRAPH_PADDING_Y = 3.0f; constexpr static float FRAME_GRAPH_HEIGHT = 50.0f; +void FrameGraph::DrawFrameGraph() { + // Frame graph - inspired by + // https://asawicki.info/news_1758_an_idea_for_visualization_of_frame_times + const float full_width = GetContentRegionAvail().x; + auto pos = GetCursorScreenPos(); + const ImVec2 size{full_width, FRAME_GRAPH_HEIGHT + FRAME_GRAPH_PADDING_Y * 2.0f}; + ItemSize(size); + if (!ItemAdd({pos, pos + size}, GetID("FrameGraph"))) { + return; + } + + float target_dt = 1.0f / (TARGET_FPS * (float)Config::vblankDiv()); + float cur_pos_x = pos.x + full_width; + pos.y += FRAME_GRAPH_PADDING_Y; + const float final_pos_y = pos.y + FRAME_GRAPH_HEIGHT; + + auto& draw_list = *GetWindowDrawList(); + draw_list.AddRectFilled({pos.x, pos.y - FRAME_GRAPH_PADDING_Y}, + {pos.x + full_width, final_pos_y + FRAME_GRAPH_PADDING_Y}, + IM_COL32(0x33, 0x33, 0x33, 0xFF)); + draw_list.PushClipRect({pos.x, pos.y}, {pos.x + full_width, final_pos_y}, true); + for (u32 i = 0; i < FRAME_BUFFER_SIZE; ++i) { + const auto& frame_info = frame_list[(DebugState.GetFrameNum() - i) % FRAME_BUFFER_SIZE]; + const float dt_factor = target_dt / frame_info.delta; + + const float width = std::ceil(BAR_WIDTH_MULT / dt_factor); + const float height = + std::min(std::log2(BAR_HEIGHT_MULT / dt_factor) / 3.0f, 1.0f) * FRAME_GRAPH_HEIGHT; + + ImU32 color; + if (dt_factor >= 0.95f) { // BLUE + color = IM_COL32(0x33, 0x33, 0xFF, 0xFF); + } else if (dt_factor >= 0.5f) { // GREEN <> YELLOW + float t = 1.0f - (dt_factor - 0.5f) * 2.0f; + int r = (int)(0xFF * t); + color = IM_COL32(r, 0xFF, 0, 0xFF); + } else { // YELLOW <> RED + float t = dt_factor * 2.0f; + int g = (int)(0xFF * t); + color = IM_COL32(0xFF, g, 0, 0xFF); + } + draw_list.AddRectFilled({cur_pos_x - width, final_pos_y - height}, {cur_pos_x, final_pos_y}, + color); + cur_pos_x -= width; + if (cur_pos_x < width) { + break; + } + } + draw_list.PopClipRect(); +} + void FrameGraph::Draw() { if (!is_open) { return; @@ -43,55 +94,9 @@ void FrameGraph::Draw() { Text("Frame time: %.3f ms (%.1f FPS)", deltaTime, frameRate); Text("Flip frame: %d Gnm submit frame: %d", DebugState.flip_frame_count.load(), DebugState.gnm_frame_count.load()); + SeparatorText("Frame graph"); - - const float full_width = GetContentRegionAvail().x; - // Frame graph - inspired by - // https://asawicki.info/news_1758_an_idea_for_visualization_of_frame_times - auto pos = GetCursorScreenPos(); - const ImVec2 size{full_width, FRAME_GRAPH_HEIGHT + FRAME_GRAPH_PADDING_Y * 2.0f}; - ItemSize(size); - if (!ItemAdd({pos, pos + size}, GetID("FrameGraph"))) { - return; - } - - float target_dt = 1.0f / (TARGET_FPS * (float)Config::vblankDiv()); - float cur_pos_x = pos.x + full_width; - pos.y += FRAME_GRAPH_PADDING_Y; - const float final_pos_y = pos.y + FRAME_GRAPH_HEIGHT; - - draw_list.AddRectFilled({pos.x, pos.y - FRAME_GRAPH_PADDING_Y}, - {pos.x + full_width, final_pos_y + FRAME_GRAPH_PADDING_Y}, - IM_COL32(0x33, 0x33, 0x33, 0xFF)); - draw_list.PushClipRect({pos.x, pos.y}, {pos.x + full_width, final_pos_y}, true); - for (u32 i = 0; i < FRAME_BUFFER_SIZE; ++i) { - const auto& frame_info = frame_list[(DebugState.GetFrameNum() - i) % FRAME_BUFFER_SIZE]; - const float dt_factor = target_dt / frame_info.delta; - - const float width = std::ceil(BAR_WIDTH_MULT / dt_factor); - const float height = - std::min(std::log2(BAR_HEIGHT_MULT / dt_factor) / 3.0f, 1.0f) * FRAME_GRAPH_HEIGHT; - - ImU32 color; - if (dt_factor >= 0.95f) { // BLUE - color = IM_COL32(0x33, 0x33, 0xFF, 0xFF); - } else if (dt_factor >= 0.5f) { // GREEN <> YELLOW - float t = 1.0f - (dt_factor - 0.5f) * 2.0f; - int r = (int)(0xFF * t); - color = IM_COL32(r, 0xFF, 0, 0xFF); - } else { // YELLOW <> RED - float t = dt_factor * 2.0f; - int g = (int)(0xFF * t); - color = IM_COL32(0xFF, g, 0, 0xFF); - } - draw_list.AddRectFilled({cur_pos_x - width, final_pos_y - height}, - {cur_pos_x, final_pos_y}, color); - cur_pos_x -= width; - if (cur_pos_x < width) { - break; - } - } - draw_list.PopClipRect(); + DrawFrameGraph(); } End(); } diff --git a/src/core/devtools/widget/frame_graph.h b/src/core/devtools/widget/frame_graph.h index 700b6b2a2..40a68ffa7 100644 --- a/src/core/devtools/widget/frame_graph.h +++ b/src/core/devtools/widget/frame_graph.h @@ -16,6 +16,8 @@ class FrameGraph { std::array frame_list{}; + void DrawFrameGraph(); + public: bool is_open = true; diff --git a/src/core/devtools/widget/reg_view.cpp b/src/core/devtools/widget/reg_view.cpp index 79b02a849..a1b7937df 100644 --- a/src/core/devtools/widget/reg_view.cpp +++ b/src/core/devtools/widget/reg_view.cpp @@ -292,6 +292,17 @@ void RegView::Draw() { EndMenuBar(); } + const char* shader_name = "_"; + if (data.is_compute) { + shader_name = data.cs_data.name.c_str(); + } else if (selected_shader >= 0) { + shader_name = data.stages[selected_shader].name.c_str(); + } + + TextUnformatted("Shader: "); + SameLine(); + TextUnformatted(shader_name); + if (!data.is_compute && BeginChild("STAGES", {}, ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_AutoResizeY)) { diff --git a/src/core/devtools/widget/shader_list.cpp b/src/core/devtools/widget/shader_list.cpp index 2c97db7fd..97d01896d 100644 --- a/src/core/devtools/widget/shader_list.cpp +++ b/src/core/devtools/widget/shader_list.cpp @@ -112,6 +112,10 @@ bool ShaderList::Selection::DrawShader(DebugStateType::ShaderDump& value) { ReloadShader(value); } } + SameLine(); + if (Button("Copy name")) { + SetClipboardText(value.name.c_str()); + } if (value.is_patched) { if (BeginCombo("Shader type", showing_bin ? "SPIRV" : "GLSL", @@ -229,9 +233,16 @@ void ShaderList::Draw() { return; } + InputTextEx("##search_shader", "Search by name", search_box, sizeof(search_box), {}, + ImGuiInputTextFlags_None); + auto width = GetContentRegionAvail().x; int i = 0; for (const auto& shader : DebugState.shader_dump_list) { + if (search_box[0] != '\0' && !shader.name.contains(search_box)) { + i++; + continue; + } char name[128]; if (shader.is_patched) { snprintf(name, sizeof(name), "%s (PATCH ON)", shader.name.c_str()); diff --git a/src/core/devtools/widget/shader_list.h b/src/core/devtools/widget/shader_list.h index 2534ded35..fbb8d2070 100644 --- a/src/core/devtools/widget/shader_list.h +++ b/src/core/devtools/widget/shader_list.h @@ -31,6 +31,8 @@ class ShaderList { std::vector open_shaders{}; + char search_box[128]{}; + public: bool open = false; diff --git a/src/core/libraries/ajm/ajm_batch.h b/src/core/libraries/ajm/ajm_batch.h index 65110ee73..3c586b773 100644 --- a/src/core/libraries/ajm/ajm_batch.h +++ b/src/core/libraries/ajm/ajm_batch.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include diff --git a/src/core/libraries/app_content/app_content.cpp b/src/core/libraries/app_content/app_content.cpp index ca3cdad39..1d23e7f44 100644 --- a/src/core/libraries/app_content/app_content.cpp +++ b/src/core/libraries/app_content/app_content.cpp @@ -145,8 +145,10 @@ int PS4_SYSV_ABI sceAppContentDownloadDataFormat() { return ORBIS_OK; } -int PS4_SYSV_ABI sceAppContentDownloadDataGetAvailableSpaceKb() { +int PS4_SYSV_ABI sceAppContentDownloadDataGetAvailableSpaceKb(OrbisAppContentMountPoint* mountPoint, + u64* availableSpaceKb) { LOG_ERROR(Lib_AppContent, "(STUBBED) called"); + *availableSpaceKb = 1048576; return ORBIS_OK; } @@ -294,9 +296,9 @@ int PS4_SYSV_ABI sceAppContentTemporaryDataFormat() { } int PS4_SYSV_ABI sceAppContentTemporaryDataGetAvailableSpaceKb( - const OrbisAppContentMountPoint* mountPoint, size_t* availableSpaceKb) { + const OrbisAppContentMountPoint* mountPoint, u64* availableSpaceKb) { LOG_ERROR(Lib_AppContent, "(STUBBED) called"); - *availableSpaceKb = 1073741824; + *availableSpaceKb = 1048576; return ORBIS_OK; } diff --git a/src/core/libraries/app_content/app_content.h b/src/core/libraries/app_content/app_content.h index f41f7dccf..05bd3bc49 100644 --- a/src/core/libraries/app_content/app_content.h +++ b/src/core/libraries/app_content/app_content.h @@ -84,7 +84,8 @@ int PS4_SYSV_ABI sceAppContentDownload0Shrink(); int PS4_SYSV_ABI sceAppContentDownload1Expand(); int PS4_SYSV_ABI sceAppContentDownload1Shrink(); int PS4_SYSV_ABI sceAppContentDownloadDataFormat(); -int PS4_SYSV_ABI sceAppContentDownloadDataGetAvailableSpaceKb(); +int PS4_SYSV_ABI sceAppContentDownloadDataGetAvailableSpaceKb(OrbisAppContentMountPoint* mountPoint, + u64* availableSpaceKb); int PS4_SYSV_ABI sceAppContentGetAddcontDownloadProgress(); int PS4_SYSV_ABI sceAppContentGetAddcontInfo(u32 service_label, const OrbisNpUnifiedEntitlementLabel* entitlementLabel, @@ -105,7 +106,7 @@ int PS4_SYSV_ABI sceAppContentSmallSharedDataMount(); int PS4_SYSV_ABI sceAppContentSmallSharedDataUnmount(); int PS4_SYSV_ABI sceAppContentTemporaryDataFormat(); int PS4_SYSV_ABI sceAppContentTemporaryDataGetAvailableSpaceKb( - const OrbisAppContentMountPoint* mountPoint, size_t* availableSpaceKb); + const OrbisAppContentMountPoint* mountPoint, u64* availableSpaceKb); int PS4_SYSV_ABI sceAppContentTemporaryDataMount(); int PS4_SYSV_ABI sceAppContentTemporaryDataMount2(OrbisAppContentTemporaryDataOption option, OrbisAppContentMountPoint* mountPoint); diff --git a/src/core/libraries/audio/audioout.cpp b/src/core/libraries/audio/audioout.cpp index db43ee928..89ea1d3f5 100644 --- a/src/core/libraries/audio/audioout.cpp +++ b/src/core/libraries/audio/audioout.cpp @@ -7,26 +7,15 @@ #include #include "common/assert.h" +#include "common/config.h" #include "common/logging/log.h" #include "core/libraries/audio/audioout.h" +#include "core/libraries/audio/audioout_backend.h" #include "core/libraries/audio/audioout_error.h" -#include "core/libraries/audio/sdl_audio.h" #include "core/libraries/libs.h" namespace Libraries::AudioOut { -struct PortOut { - void* impl; - u32 samples_num; - u32 freq; - OrbisAudioOutParamFormat format; - OrbisAudioOutPort type; - int channels_num; - bool is_float; - std::array volume; - u8 sample_size; - bool is_open; -}; std::shared_mutex ports_mutex; std::array ports_out{}; @@ -104,7 +93,7 @@ static bool IsFormatFloat(const OrbisAudioOutParamFormat format) { } } -static int GetFormatNumChannels(const OrbisAudioOutParamFormat format) { +static u8 GetFormatNumChannels(const OrbisAudioOutParamFormat format) { switch (format) { case OrbisAudioOutParamFormat::S16Mono: case OrbisAudioOutParamFormat::FloatMono: @@ -187,13 +176,11 @@ int PS4_SYSV_ABI sceAudioOutClose(s32 handle) { std::scoped_lock lock(ports_mutex); auto& port = ports_out.at(handle - 1); - if (!port.is_open) { + if (!port.impl) { return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT; } - audio->Close(port.impl); port.impl = nullptr; - port.is_open = false; return ORBIS_OK; } @@ -264,7 +251,7 @@ int PS4_SYSV_ABI sceAudioOutGetPortState(s32 handle, OrbisAudioOutPortState* sta std::scoped_lock lock(ports_mutex); const auto& port = ports_out.at(handle - 1); - if (!port.is_open) { + if (!port.impl) { return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT; } @@ -324,7 +311,16 @@ int PS4_SYSV_ABI sceAudioOutInit() { if (audio != nullptr) { return ORBIS_AUDIO_OUT_ERROR_ALREADY_INIT; } - audio = std::make_unique(); + const auto backend = Config::getAudioBackend(); + if (backend == "cubeb") { + audio = std::make_unique(); + } else if (backend == "sdl") { + audio = std::make_unique(); + } else { + // Cubeb as a default fallback. + LOG_ERROR(Lib_AudioOut, "Invalid audio backend '{}', defaulting to cubeb.", backend); + audio = std::make_unique(); + } return ORBIS_OK; } @@ -399,23 +395,25 @@ s32 PS4_SYSV_ABI sceAudioOutOpen(UserService::OrbisUserServiceUserId user_id, } std::scoped_lock lock{ports_mutex}; - const auto port = std::ranges::find(ports_out, false, &PortOut::is_open); + const auto port = + std::ranges::find_if(ports_out, [&](const PortOut& p) { return p.impl == nullptr; }); if (port == ports_out.end()) { LOG_ERROR(Lib_AudioOut, "Audio ports are full"); return ORBIS_AUDIO_OUT_ERROR_PORT_FULL; } - port->is_open = true; port->type = port_type; - port->samples_num = length; - port->freq = sample_rate; port->format = format; port->is_float = IsFormatFloat(format); - port->channels_num = GetFormatNumChannels(format); port->sample_size = GetFormatSampleSize(format); + port->channels_num = GetFormatNumChannels(format); + port->samples_num = length; + port->frame_size = port->sample_size * port->channels_num; + port->buffer_size = port->frame_size * port->samples_num; + port->freq = sample_rate; port->volume.fill(SCE_AUDIO_OUT_VOLUME_0DB); + port->impl = audio->Open(*port); - port->impl = audio->Open(port->is_float, port->channels_num, port->freq); return std::distance(ports_out.begin(), port) + 1; } @@ -424,7 +422,7 @@ int PS4_SYSV_ABI sceAudioOutOpenEx() { return ORBIS_OK; } -s32 PS4_SYSV_ABI sceAudioOutOutput(s32 handle, const void* ptr) { +s32 PS4_SYSV_ABI sceAudioOutOutput(s32 handle, void* ptr) { if (handle < 1 || handle > SCE_AUDIO_OUT_NUM_PORTS) { return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT; } @@ -434,12 +432,11 @@ s32 PS4_SYSV_ABI sceAudioOutOutput(s32 handle, const void* ptr) { } auto& port = ports_out.at(handle - 1); - if (!port.is_open) { + if (!port.impl) { return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT; } - const size_t data_size = port.samples_num * port.sample_size * port.channels_num; - audio->Output(port.impl, ptr, data_size); + port.impl->Output(ptr, port.buffer_size); return ORBIS_OK; } @@ -548,7 +545,7 @@ s32 PS4_SYSV_ABI sceAudioOutSetVolume(s32 handle, s32 flag, s32* vol) { std::scoped_lock lock(ports_mutex); auto& port = ports_out.at(handle - 1); - if (!port.is_open) { + if (!port.impl) { return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT; } @@ -579,7 +576,7 @@ s32 PS4_SYSV_ABI sceAudioOutSetVolume(s32 handle, s32 flag, s32* vol) { } } - audio->SetVolume(port.impl, port.volume); + port.impl->SetVolume(port.volume); return ORBIS_OK; } diff --git a/src/core/libraries/audio/audioout.h b/src/core/libraries/audio/audioout.h index c66a0e9f5..58c77db99 100644 --- a/src/core/libraries/audio/audioout.h +++ b/src/core/libraries/audio/audioout.h @@ -3,12 +3,15 @@ #pragma once -#include "common/bit_field.h" +#include +#include "common/bit_field.h" #include "core/libraries/system/userservice.h" namespace Libraries::AudioOut { +class PortBackend; + // Main up to 8 ports, BGM 1 port, voice up to 4 ports, // personal up to 4 ports, padspk up to 5 ports, aux 1 port constexpr int SCE_AUDIO_OUT_NUM_PORTS = 22; @@ -43,7 +46,7 @@ union OrbisAudioOutParamExtendedInformation { struct OrbisAudioOutOutputParam { s32 handle; - const void* ptr; + void* ptr; }; struct OrbisAudioOutPortState { @@ -56,6 +59,21 @@ struct OrbisAudioOutPortState { u64 reserved64[2]; }; +struct PortOut { + std::unique_ptr impl{}; + + OrbisAudioOutPort type; + OrbisAudioOutParamFormat format; + bool is_float; + u8 sample_size; + u8 channels_num; + u32 samples_num; + u32 frame_size; + u32 buffer_size; + u32 freq; + std::array volume; +}; + int PS4_SYSV_ABI sceAudioOutDeviceIdOpen(); int PS4_SYSV_ABI sceAudioDeviceControlGet(); int PS4_SYSV_ABI sceAudioDeviceControlSet(); @@ -94,7 +112,7 @@ s32 PS4_SYSV_ABI sceAudioOutOpen(UserService::OrbisUserServiceUserId user_id, OrbisAudioOutPort port_type, s32 index, u32 length, u32 sample_rate, OrbisAudioOutParamExtendedInformation param_type); int PS4_SYSV_ABI sceAudioOutOpenEx(); -s32 PS4_SYSV_ABI sceAudioOutOutput(s32 handle, const void* ptr); +s32 PS4_SYSV_ABI sceAudioOutOutput(s32 handle, void* ptr); s32 PS4_SYSV_ABI sceAudioOutOutputs(OrbisAudioOutOutputParam* param, u32 num); int PS4_SYSV_ABI sceAudioOutPtClose(); int PS4_SYSV_ABI sceAudioOutPtGetLastOutputTime(); diff --git a/src/core/libraries/audio/audioout_backend.h b/src/core/libraries/audio/audioout_backend.h index 238ef0201..ecc4cf7c6 100644 --- a/src/core/libraries/audio/audioout_backend.h +++ b/src/core/libraries/audio/audioout_backend.h @@ -3,17 +3,42 @@ #pragma once +typedef struct cubeb cubeb; + namespace Libraries::AudioOut { +struct PortOut; + +class PortBackend { +public: + virtual ~PortBackend() = default; + + virtual void Output(void* ptr, size_t size) = 0; + virtual void SetVolume(const std::array& ch_volumes) = 0; +}; + class AudioOutBackend { public: AudioOutBackend() = default; virtual ~AudioOutBackend() = default; - virtual void* Open(bool is_float, int num_channels, u32 sample_rate) = 0; - virtual void Close(void* impl) = 0; - virtual void Output(void* impl, const void* ptr, size_t size) = 0; - virtual void SetVolume(void* impl, std::array ch_volumes) = 0; + virtual std::unique_ptr Open(PortOut& port) = 0; +}; + +class CubebAudioOut final : public AudioOutBackend { +public: + CubebAudioOut(); + ~CubebAudioOut() override; + + std::unique_ptr Open(PortOut& port) override; + +private: + cubeb* ctx = nullptr; +}; + +class SDLAudioOut final : public AudioOutBackend { +public: + std::unique_ptr Open(PortOut& port) override; }; } // namespace Libraries::AudioOut diff --git a/src/core/libraries/audio/cubeb_audio.cpp b/src/core/libraries/audio/cubeb_audio.cpp new file mode 100644 index 000000000..e1195558a --- /dev/null +++ b/src/core/libraries/audio/cubeb_audio.cpp @@ -0,0 +1,163 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include + +#include "common/logging/log.h" +#include "common/ringbuffer.h" +#include "core/libraries/audio/audioout.h" +#include "core/libraries/audio/audioout_backend.h" + +namespace Libraries::AudioOut { + +constexpr int AUDIO_STREAM_BUFFER_THRESHOLD = 65536; // Define constant for buffer threshold + +class CubebPortBackend : public PortBackend { +public: + CubebPortBackend(cubeb* ctx, const PortOut& port) + : frame_size(port.frame_size), buffer(static_cast(port.buffer_size) * 4) { + if (!ctx) { + return; + } + const auto get_channel_layout = [&port] -> cubeb_channel_layout { + switch (port.channels_num) { + case 1: + return CUBEB_LAYOUT_MONO; + case 2: + return CUBEB_LAYOUT_STEREO; + case 8: + return CUBEB_LAYOUT_3F4_LFE; + default: + UNREACHABLE(); + } + }; + cubeb_stream_params stream_params = { + .format = port.is_float ? CUBEB_SAMPLE_FLOAT32LE : CUBEB_SAMPLE_S16LE, + .rate = port.freq, + .channels = port.channels_num, + .layout = get_channel_layout(), + .prefs = CUBEB_STREAM_PREF_NONE, + }; + u32 latency_frames = 512; + if (const auto ret = cubeb_get_min_latency(ctx, &stream_params, &latency_frames); + ret != CUBEB_OK) { + LOG_WARNING(Lib_AudioOut, + "Could not get minimum cubeb audio latency, falling back to default: {}", + ret); + } + char stream_name[64]; + snprintf(stream_name, sizeof(stream_name), "shadPS4 stream %p", this); + if (const auto ret = cubeb_stream_init(ctx, &stream, stream_name, nullptr, nullptr, nullptr, + &stream_params, latency_frames, &DataCallback, + &StateCallback, this); + ret != CUBEB_OK) { + LOG_ERROR(Lib_AudioOut, "Failed to create cubeb stream: {}", ret); + return; + } + if (const auto ret = cubeb_stream_start(stream); ret != CUBEB_OK) { + LOG_ERROR(Lib_AudioOut, "Failed to start cubeb stream: {}", ret); + cubeb_stream_destroy(stream); + stream = nullptr; + return; + } + } + + ~CubebPortBackend() override { + if (!stream) { + return; + } + if (const auto ret = cubeb_stream_stop(stream); ret != CUBEB_OK) { + LOG_WARNING(Lib_AudioOut, "Failed to stop cubeb stream: {}", ret); + } + cubeb_stream_destroy(stream); + stream = nullptr; + } + + void Output(void* ptr, size_t size) override { + if (!stream) { + return; + } + auto* data = static_cast(ptr); + + std::unique_lock lock{buffer_mutex}; + buffer_cv.wait(lock, [&] { return buffer.available_write() >= size; }); + buffer.enqueue(data, static_cast(size)); + } + + void SetVolume(const std::array& ch_volumes) override { + if (!stream) { + return; + } + // Cubeb does not have per-channel volumes, for now just take the maximum of the channels. + const auto vol = *std::ranges::max_element(ch_volumes); + if (const auto ret = + cubeb_stream_set_volume(stream, static_cast(vol) / SCE_AUDIO_OUT_VOLUME_0DB); + ret != CUBEB_OK) { + LOG_WARNING(Lib_AudioOut, "Failed to change cubeb stream volume: {}", ret); + } + } + +private: + static long DataCallback(cubeb_stream* stream, void* user_data, const void* in, void* out, + long num_frames) { + auto* stream_data = static_cast(user_data); + const auto out_data = static_cast(out); + const auto requested_size = static_cast(num_frames * stream_data->frame_size); + + std::unique_lock lock{stream_data->buffer_mutex}; + const auto dequeued_size = stream_data->buffer.dequeue(out_data, requested_size); + lock.unlock(); + stream_data->buffer_cv.notify_one(); + + if (dequeued_size < requested_size) { + // Need to fill remaining space with silence. + std::memset(out_data + dequeued_size, 0, requested_size - dequeued_size); + } + return num_frames; + } + + static void StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state) { + switch (state) { + case CUBEB_STATE_STARTED: + LOG_INFO(Lib_AudioOut, "Cubeb stream started"); + break; + case CUBEB_STATE_STOPPED: + LOG_INFO(Lib_AudioOut, "Cubeb stream stopped"); + break; + case CUBEB_STATE_DRAINED: + LOG_INFO(Lib_AudioOut, "Cubeb stream drained"); + break; + case CUBEB_STATE_ERROR: + LOG_ERROR(Lib_AudioOut, "Cubeb stream encountered an error"); + break; + } + } + + size_t frame_size; + RingBuffer buffer; + std::mutex buffer_mutex; + std::condition_variable buffer_cv; + cubeb_stream* stream{}; +}; + +CubebAudioOut::CubebAudioOut() { + if (const auto ret = cubeb_init(&ctx, "shadPS4", nullptr); ret != CUBEB_OK) { + LOG_CRITICAL(Lib_AudioOut, "Failed to create cubeb context: {}", ret); + } +} + +CubebAudioOut::~CubebAudioOut() { + if (!ctx) { + return; + } + cubeb_destroy(ctx); + ctx = nullptr; +} + +std::unique_ptr CubebAudioOut::Open(PortOut& port) { + return std::make_unique(ctx, port); +} + +} // namespace Libraries::AudioOut diff --git a/src/core/libraries/audio/sdl_audio.cpp b/src/core/libraries/audio/sdl_audio.cpp index ce385ad9c..598941ba7 100644 --- a/src/core/libraries/audio/sdl_audio.cpp +++ b/src/core/libraries/audio/sdl_audio.cpp @@ -1,44 +1,76 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include #include -#include -#include -#include "common/assert.h" -#include "core/libraries/audio/sdl_audio.h" +#include "common/logging/log.h" +#include "core/libraries/audio/audioout.h" +#include "core/libraries/audio/audioout_backend.h" namespace Libraries::AudioOut { constexpr int AUDIO_STREAM_BUFFER_THRESHOLD = 65536; // Define constant for buffer threshold -void* SDLAudioOut::Open(bool is_float, int num_channels, u32 sample_rate) { - SDL_AudioSpec fmt; - SDL_zero(fmt); - fmt.format = is_float ? SDL_AUDIO_F32 : SDL_AUDIO_S16; - fmt.channels = num_channels; - fmt.freq = sample_rate; - - auto* stream = - SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &fmt, nullptr, nullptr); - SDL_ResumeAudioStreamDevice(stream); - return stream; -} - -void SDLAudioOut::Close(void* impl) { - SDL_DestroyAudioStream(static_cast(impl)); -} - -void SDLAudioOut::Output(void* impl, const void* ptr, size_t size) { - auto* stream = static_cast(impl); - SDL_PutAudioStreamData(stream, ptr, size); - while (SDL_GetAudioStreamAvailable(stream) > AUDIO_STREAM_BUFFER_THRESHOLD) { - SDL_Delay(0); +class SDLPortBackend : public PortBackend { +public: + explicit SDLPortBackend(const PortOut& port) { + const SDL_AudioSpec fmt = { + .format = port.is_float ? SDL_AUDIO_F32 : SDL_AUDIO_S16, + .channels = port.channels_num, + .freq = static_cast(port.freq), + }; + stream = + SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &fmt, nullptr, nullptr); + if (stream == nullptr) { + LOG_ERROR(Lib_AudioOut, "Failed to create SDL audio stream: {}", SDL_GetError()); + return; + } + if (!SDL_ResumeAudioStreamDevice(stream)) { + LOG_ERROR(Lib_AudioOut, "Failed to resume SDL audio stream: {}", SDL_GetError()); + SDL_DestroyAudioStream(stream); + stream = nullptr; + return; + } } -} -void SDLAudioOut::SetVolume(void* impl, std::array ch_volumes) { - // Not yet implemented + ~SDLPortBackend() override { + if (!stream) { + return; + } + SDL_DestroyAudioStream(stream); + stream = nullptr; + } + + void Output(void* ptr, size_t size) override { + if (!stream) { + return; + } + SDL_PutAudioStreamData(stream, ptr, static_cast(size)); + while (SDL_GetAudioStreamAvailable(stream) > AUDIO_STREAM_BUFFER_THRESHOLD) { + // Yield to allow the stream to drain. + std::this_thread::yield(); + } + } + + void SetVolume(const std::array& ch_volumes) override { + if (!stream) { + return; + } + // SDL does not have per-channel volumes, for now just take the maximum of the channels. + const auto vol = *std::ranges::max_element(ch_volumes); + if (!SDL_SetAudioStreamGain(stream, static_cast(vol) / SCE_AUDIO_OUT_VOLUME_0DB)) { + LOG_WARNING(Lib_AudioOut, "Failed to change SDL audio stream volume: {}", + SDL_GetError()); + } + } + +private: + SDL_AudioStream* stream; +}; + +std::unique_ptr SDLAudioOut::Open(PortOut& port) { + return std::make_unique(port); } } // namespace Libraries::AudioOut diff --git a/src/core/libraries/audio/sdl_audio.h b/src/core/libraries/audio/sdl_audio.h deleted file mode 100644 index d55f2f6e3..000000000 --- a/src/core/libraries/audio/sdl_audio.h +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/libraries/audio/audioout_backend.h" - -namespace Libraries::AudioOut { - -class SDLAudioOut final : public AudioOutBackend { -public: - void* Open(bool is_float, int num_channels, u32 sample_rate) override; - void Close(void* impl) override; - void Output(void* impl, const void* ptr, size_t size) override; - void SetVolume(void* impl, std::array ch_volumes) override; -}; - -} // namespace Libraries::AudioOut diff --git a/src/core/libraries/gnmdriver/gnmdriver.cpp b/src/core/libraries/gnmdriver/gnmdriver.cpp index 1a6007bf8..566f8ce1f 100644 --- a/src/core/libraries/gnmdriver/gnmdriver.cpp +++ b/src/core/libraries/gnmdriver/gnmdriver.cpp @@ -29,7 +29,7 @@ namespace Libraries::GnmDriver { using namespace AmdGpu; -enum GnmEventIdents : u64 { +enum GnmEventType : u64 { Compute0RelMem = 0x00, Compute1RelMem = 0x01, Compute2RelMem = 0x02, @@ -337,6 +337,12 @@ static inline u32* ClearContextState(u32* cmdbuf) { return cmdbuf + ClearStateSequence.size(); } +static inline bool IsValidEventType(Platform::InterruptId id) { + return (static_cast(id) >= static_cast(Platform::InterruptId::Compute0RelMem) && + static_cast(id) <= static_cast(Platform::InterruptId::Compute6RelMem)) || + static_cast(id) == static_cast(Platform::InterruptId::GfxEop); +} + s32 PS4_SYSV_ABI sceGnmAddEqEvent(SceKernelEqueue eq, u64 id, void* udata) { LOG_TRACE(Lib_GnmDriver, "called"); @@ -347,8 +353,7 @@ s32 PS4_SYSV_ABI sceGnmAddEqEvent(SceKernelEqueue eq, u64 id, void* udata) { EqueueEvent kernel_event{}; kernel_event.event.ident = id; kernel_event.event.filter = SceKernelEvent::Filter::GraphicsCore; - // The library only sets EV_ADD but it is suspected the kernel driver forces EV_CLEAR - kernel_event.event.flags = SceKernelEvent::Flags::Clear; + kernel_event.event.flags = SceKernelEvent::Flags::Add; kernel_event.event.fflags = 0; kernel_event.event.data = id; kernel_event.event.udata = udata; @@ -357,11 +362,15 @@ s32 PS4_SYSV_ABI sceGnmAddEqEvent(SceKernelEqueue eq, u64 id, void* udata) { Platform::IrqC::Instance()->Register( static_cast(id), [=](Platform::InterruptId irq) { - ASSERT_MSG(irq == static_cast(id), - "An unexpected IRQ occured"); // We need to convert IRQ# to event id and do - // proper filtering in trigger function - eq->TriggerEvent(static_cast(id), SceKernelEvent::Filter::GraphicsCore, - nullptr); + ASSERT_MSG(irq == static_cast(id), "An unexpected IRQ occured"); + + // We need to convert IRQ# to event id + if (!IsValidEventType(irq)) + return; + + // Event data is expected to be an event type as per sceGnmGetEqEventType. + eq->TriggerEvent(static_cast(id), SceKernelEvent::Filter::GraphicsCore, + reinterpret_cast(id)); }, eq); return ORBIS_OK; @@ -476,7 +485,7 @@ s32 PS4_SYSV_ABI sceGnmDeleteEqEvent(SceKernelEqueue eq, u64 id) { return ORBIS_KERNEL_ERROR_EBADF; } - eq->RemoveEvent(id); + eq->RemoveEvent(id, SceKernelEvent::Filter::GraphicsCore); Platform::IrqC::Instance()->Unregister(static_cast(id), eq); return ORBIS_OK; @@ -1000,9 +1009,13 @@ int PS4_SYSV_ABI sceGnmGetDebugTimestamp() { return ORBIS_OK; } -int PS4_SYSV_ABI sceGnmGetEqEventType() { - LOG_ERROR(Lib_GnmDriver, "(STUBBED) called"); - return ORBIS_OK; +int PS4_SYSV_ABI sceGnmGetEqEventType(const SceKernelEvent* ev) { + LOG_TRACE(Lib_GnmDriver, "called"); + + auto data = sceKernelGetEventData(ev); + ASSERT(static_cast(data) == GnmEventType::GfxEop); + + return data; } int PS4_SYSV_ABI sceGnmGetEqTimeStamp() { diff --git a/src/core/libraries/gnmdriver/gnmdriver.h b/src/core/libraries/gnmdriver/gnmdriver.h index 017dbe3ad..d15483323 100644 --- a/src/core/libraries/gnmdriver/gnmdriver.h +++ b/src/core/libraries/gnmdriver/gnmdriver.h @@ -85,7 +85,7 @@ int PS4_SYSV_ABI sceGnmGetCoredumpMode(); int PS4_SYSV_ABI sceGnmGetCoredumpProtectionFaultTimestamp(); int PS4_SYSV_ABI sceGnmGetDbgGcHandle(); int PS4_SYSV_ABI sceGnmGetDebugTimestamp(); -int PS4_SYSV_ABI sceGnmGetEqEventType(); +int PS4_SYSV_ABI sceGnmGetEqEventType(const SceKernelEvent* ev); int PS4_SYSV_ABI sceGnmGetEqTimeStamp(); int PS4_SYSV_ABI sceGnmGetGpuBlockStatus(); u32 PS4_SYSV_ABI sceGnmGetGpuCoreClockFrequency(); diff --git a/src/core/libraries/kernel/equeue.cpp b/src/core/libraries/kernel/equeue.cpp index 42a8eed89..3ae77e46b 100644 --- a/src/core/libraries/kernel/equeue.cpp +++ b/src/core/libraries/kernel/equeue.cpp @@ -12,6 +12,8 @@ namespace Libraries::Kernel { +// Events are uniquely identified by id and filter. + bool EqueueInternal::AddEvent(EqueueEvent& event) { std::scoped_lock lock{m_mutex}; @@ -27,12 +29,13 @@ bool EqueueInternal::AddEvent(EqueueEvent& event) { return true; } -bool EqueueInternal::RemoveEvent(u64 id) { +bool EqueueInternal::RemoveEvent(u64 id, s16 filter) { bool has_found = false; std::scoped_lock lock{m_mutex}; - const auto& it = - std::ranges::find_if(m_events, [id](auto& ev) { return ev.event.ident == id; }); + const auto& it = std::ranges::find_if(m_events, [id, filter](auto& ev) { + return ev.event.ident == id && ev.event.filter == filter; + }); if (it != m_events.cend()) { m_events.erase(it); has_found = true; @@ -68,7 +71,7 @@ int EqueueInternal::WaitForEvents(SceKernelEvent* ev, int num, u32 micros) { if (ev->flags & SceKernelEvent::Flags::OneShot) { for (auto ev_id = 0u; ev_id < count; ++ev_id) { - RemoveEvent(ev->ident); + RemoveEvent(ev->ident, ev->filter); } } @@ -94,8 +97,11 @@ int EqueueInternal::GetTriggeredEvents(SceKernelEvent* ev, int num) { int count = 0; for (auto& event : m_events) { if (event.IsTriggered()) { + // Event should not trigger again + event.ResetTriggerState(); + if (event.event.flags & SceKernelEvent::Flags::Clear) { - event.Reset(); + event.Clear(); } ev[count++] = event.event; if (count == num) { @@ -334,7 +340,7 @@ int PS4_SYSV_ABI sceKernelDeleteUserEvent(SceKernelEqueue eq, int id) { return ORBIS_KERNEL_ERROR_EBADF; } - if (!eq->RemoveEvent(id)) { + if (!eq->RemoveEvent(id, SceKernelEvent::Filter::User)) { return ORBIS_KERNEL_ERROR_ENOENT; } return ORBIS_OK; @@ -344,6 +350,10 @@ s16 PS4_SYSV_ABI sceKernelGetEventFilter(const SceKernelEvent* ev) { return ev->filter; } +u64 PS4_SYSV_ABI sceKernelGetEventData(const SceKernelEvent* ev) { + return ev->data; +} + void RegisterEventQueue(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("D0OdFMjp46I", "libkernel", 1, "libkernel", 1, 1, sceKernelCreateEqueue); LIB_FUNCTION("jpFjmgAC5AE", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteEqueue); @@ -356,6 +366,7 @@ void RegisterEventQueue(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("LJDwdSNTnDg", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteUserEvent); LIB_FUNCTION("mJ7aghmgvfc", "libkernel", 1, "libkernel", 1, 1, sceKernelGetEventId); LIB_FUNCTION("23CPPI1tyBY", "libkernel", 1, "libkernel", 1, 1, sceKernelGetEventFilter); + LIB_FUNCTION("kwGyyjohI50", "libkernel", 1, "libkernel", 1, 1, sceKernelGetEventData); } } // namespace Libraries::Kernel diff --git a/src/core/libraries/kernel/equeue.h b/src/core/libraries/kernel/equeue.h index 5a13bdecd..f8759137c 100644 --- a/src/core/libraries/kernel/equeue.h +++ b/src/core/libraries/kernel/equeue.h @@ -66,8 +66,11 @@ struct EqueueEvent { std::chrono::steady_clock::time_point time_added; std::unique_ptr timer; - void Reset() { + void ResetTriggerState() { is_triggered = false; + } + + void Clear() { event.fflags = 0; event.data = 0; } @@ -83,7 +86,7 @@ struct EqueueEvent { } bool operator==(const EqueueEvent& ev) const { - return ev.event.ident == event.ident; + return ev.event.ident == event.ident && ev.event.filter == event.filter; } private: @@ -99,7 +102,7 @@ public: } bool AddEvent(EqueueEvent& event); - bool RemoveEvent(u64 id); + bool RemoveEvent(u64 id, s16 filter); int WaitForEvents(SceKernelEvent* ev, int num, u32 micros); bool TriggerEvent(u64 ident, s16 filter, void* trigger_data); int GetTriggeredEvents(SceKernelEvent* ev, int num); @@ -122,6 +125,8 @@ private: using SceKernelUseconds = u32; using SceKernelEqueue = EqueueInternal*; +u64 PS4_SYSV_ABI sceKernelGetEventData(const SceKernelEvent* ev); + void RegisterEventQueue(Core::Loader::SymbolsResolver* sym); } // namespace Libraries::Kernel diff --git a/src/core/libraries/kernel/threads/pthread.cpp b/src/core/libraries/kernel/threads/pthread.cpp index 610e61238..761d13346 100644 --- a/src/core/libraries/kernel/threads/pthread.cpp +++ b/src/core/libraries/kernel/threads/pthread.cpp @@ -244,8 +244,8 @@ int PS4_SYSV_ABI posix_pthread_create_name_np(PthreadT* thread, const PthreadAtt new_thread->tid = ++TidCounter; if (new_thread->attr.stackaddr_attr == 0) { - /* Enforce minimum stack size of 64 KB */ - static constexpr size_t MinimumStack = 64_KB; + /* Enforce minimum stack size of 128 KB */ + static constexpr size_t MinimumStack = 128_KB; auto& stacksize = new_thread->attr.stacksize_attr; stacksize = std::max(stacksize, MinimumStack); } diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 41db7df4b..aa116fa3d 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -101,13 +101,17 @@ PAddr MemoryManager::Allocate(PAddr search_start, PAddr search_end, size_t size, auto dmem_area = FindDmemArea(search_start); 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 (!is_suitable() && dmem_area->second.GetEnd() <= search_end) { + while (dmem_area != dmem_map.end() && !is_suitable() && + dmem_area->second.GetEnd() <= search_end) { ++dmem_area; } ASSERT_MSG(is_suitable(), "Unable to find free direct memory area: size = {:#x}", size); diff --git a/src/emulator.cpp b/src/emulator.cpp index 252a34418..10d17a2db 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -311,8 +311,9 @@ void Emulator::LoadSystemModules(const std::filesystem::path& file, std::string found_modules, [&](const auto& path) { return path.filename() == module_name; }); if (it != found_modules.end()) { LOG_INFO(Loader, "Loading {}", it->string()); - linker->LoadModule(*it); - continue; + if (linker->LoadModule(*it) != -1) { + continue; + } } if (init_func) { LOG_INFO(Loader, "Can't Load {} switching to HLE", module_name); @@ -321,7 +322,7 @@ void Emulator::LoadSystemModules(const std::filesystem::path& file, std::string LOG_INFO(Loader, "No HLE available for {} module", module_name); } } - if (std::filesystem::exists(sys_module_path / game_serial)) { + if (!game_serial.empty() && std::filesystem::exists(sys_module_path / game_serial)) { for (const auto& entry : std::filesystem::directory_iterator(sys_module_path / game_serial)) { LOG_INFO(Loader, "Loading {} from game serial file {}", entry.path().string(), diff --git a/src/qt_gui/check_update.cpp b/src/qt_gui/check_update.cpp index bb07baaf5..edd55b804 100644 --- a/src/qt_gui/check_update.cpp +++ b/src/qt_gui/check_update.cpp @@ -213,9 +213,9 @@ void CheckUpdate::setupUI(const QString& downloadUrl, const QString& latestDate, // Don't show changelog button if: // The current version is a pre-release and the version to be downloaded is a release. - bool current_isRelease = currentRev.startsWith('v', Qt::CaseInsensitive); - bool latest_isRelease = latestRev.startsWith('v', Qt::CaseInsensitive); - if (!current_isRelease && latest_isRelease) { + bool current_isWIP = currentRev.endsWith("WIP", Qt::CaseInsensitive); + bool latest_isWIP = latestRev.endsWith("WIP", Qt::CaseInsensitive); + if (current_isWIP && !latest_isWIP) { } else { QTextEdit* textField = new QTextEdit(this); textField->setReadOnly(true); diff --git a/src/qt_gui/compatibility_info.cpp b/src/qt_gui/compatibility_info.cpp index aecac60cd..69fb3e377 100644 --- a/src/qt_gui/compatibility_info.cpp +++ b/src/qt_gui/compatibility_info.cpp @@ -18,9 +18,10 @@ CompatibilityInfoClass::CompatibilityInfoClass() }; CompatibilityInfoClass::~CompatibilityInfoClass() = default; -void CompatibilityInfoClass::UpdateCompatibilityDatabase(QWidget* parent) { - if (LoadCompatibilityFile()) - return; +void CompatibilityInfoClass::UpdateCompatibilityDatabase(QWidget* parent, bool forced) { + if (!forced) + if (LoadCompatibilityFile()) + return; QNetworkReply* reply = FetchPage(1); if (!WaitForReply(reply)) @@ -45,7 +46,8 @@ void CompatibilityInfoClass::UpdateCompatibilityDatabase(QWidget* parent) { QMessageBox::critical(parent, tr("Error"), tr("Unable to update compatibility data! Try again later.")); // Try loading compatibility_file.json again - LoadCompatibilityFile(); + if (!forced) + LoadCompatibilityFile(); return; } diff --git a/src/qt_gui/compatibility_info.h b/src/qt_gui/compatibility_info.h index dcbaef847..0c47c27ff 100644 --- a/src/qt_gui/compatibility_info.h +++ b/src/qt_gui/compatibility_info.h @@ -84,7 +84,7 @@ public: CompatibilityInfoClass(); ~CompatibilityInfoClass(); - void UpdateCompatibilityDatabase(QWidget* parent = nullptr); + void UpdateCompatibilityDatabase(QWidget* parent = nullptr, bool forced = false); bool LoadCompatibilityFile(); CompatibilityEntry GetCompatibilityInfo(const std::string& serial); void ExtractCompatibilityInfo(QByteArray response); diff --git a/src/qt_gui/game_grid_frame.cpp b/src/qt_gui/game_grid_frame.cpp index b932e46c3..2ebb09e5d 100644 --- a/src/qt_gui/game_grid_frame.cpp +++ b/src/qt_gui/game_grid_frame.cpp @@ -3,9 +3,12 @@ #include "common/path_util.h" #include "game_grid_frame.h" +#include "qt_gui/compatibility_info.h" -GameGridFrame::GameGridFrame(std::shared_ptr game_info_get, QWidget* parent) - : QTableWidget(parent), m_game_info(game_info_get) { +GameGridFrame::GameGridFrame(std::shared_ptr game_info_get, + std::shared_ptr compat_info_get, + QWidget* parent) + : QTableWidget(parent), m_game_info(game_info_get), m_compat_info(compat_info_get) { icon_size = Config::getIconSizeGrid(); windowWidth = parent->width(); this->setShowGrid(false); @@ -29,7 +32,7 @@ GameGridFrame::GameGridFrame(std::shared_ptr game_info_get, QWidg connect(this->horizontalScrollBar(), &QScrollBar::valueChanged, this, &GameGridFrame::RefreshGridBackgroundImage); connect(this, &QTableWidget::customContextMenuRequested, this, [=, this](const QPoint& pos) { - m_gui_context_menus.RequestGameMenu(pos, m_game_info->m_games, this, false); + m_gui_context_menus.RequestGameMenu(pos, m_game_info->m_games, m_compat_info, this, false); }); } diff --git a/src/qt_gui/game_grid_frame.h b/src/qt_gui/game_grid_frame.h index c09767684..4825d6daf 100644 --- a/src/qt_gui/game_grid_frame.h +++ b/src/qt_gui/game_grid_frame.h @@ -10,6 +10,7 @@ #include "game_info.h" #include "game_list_utils.h" #include "gui_context_menus.h" +#include "qt_gui/compatibility_info.h" class GameGridFrame : public QTableWidget { Q_OBJECT @@ -29,11 +30,14 @@ private: GameListUtils m_game_list_utils; GuiContextMenus m_gui_context_menus; std::shared_ptr m_game_info; + std::shared_ptr m_compat_info; std::shared_ptr> m_games_shared; bool validCellSelected = false; public: - explicit GameGridFrame(std::shared_ptr game_info_get, QWidget* parent = nullptr); + explicit GameGridFrame(std::shared_ptr game_info_get, + std::shared_ptr compat_info_get, + QWidget* parent = nullptr); void PopulateGameGrid(QVector m_games, bool fromSearch); bool IsValidCellSelected(); diff --git a/src/qt_gui/game_list_frame.cpp b/src/qt_gui/game_list_frame.cpp index 53159d8e7..b1cd07216 100644 --- a/src/qt_gui/game_list_frame.cpp +++ b/src/qt_gui/game_list_frame.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include +#include "common/config.h" #include "common/logging/log.h" #include "common/path_util.h" #include "common/string_util.h" @@ -72,7 +73,7 @@ GameListFrame::GameListFrame(std::shared_ptr game_info_get, }); connect(this, &QTableWidget::customContextMenuRequested, this, [=, this](const QPoint& pos) { - m_gui_context_menus.RequestGameMenu(pos, m_game_info->m_games, this, true); + m_gui_context_menus.RequestGameMenu(pos, m_game_info->m_games, m_compat_info, this, true); }); connect(this, &QTableWidget::cellClicked, this, [=, this](int row, int column) { @@ -80,11 +81,6 @@ GameListFrame::GameListFrame(std::shared_ptr game_info_get, QDesktopServices::openUrl(QUrl(m_game_info->m_games[row].compatibility.url)); } }); - - // Do not show status column if it is not enabled - if (!Config::getCompatibilityEnabled()) { - this->setColumnHidden(2, true); - } } void GameListFrame::onCurrentCellChanged(int currentRow, int currentColumn, int previousRow, @@ -108,6 +104,8 @@ void GameListFrame::PlayBackgroundMusic(QTableWidgetItem* item) { } void GameListFrame::PopulateGameList() { + // Do not show status column if it is not enabled + this->setColumnHidden(2, !Config::getCompatibilityEnabled()); this->setRowCount(m_game_info->m_games.size()); ResizeIcons(icon_size); @@ -135,16 +133,16 @@ void GameListFrame::PopulateGameList() { QString formattedPlayTime; if (hours > 0) { - formattedPlayTime += QString("%1h ").arg(hours); + formattedPlayTime += QString("%1").arg(hours) + tr("h"); } if (minutes > 0) { - formattedPlayTime += QString("%1m ").arg(minutes); + formattedPlayTime += QString("%1").arg(minutes) + tr("m"); } formattedPlayTime = formattedPlayTime.trimmed(); m_game_info->m_games[i].play_time = playTime.toStdString(); if (formattedPlayTime.isEmpty()) { - SetTableItem(i, 8, QString("%1s").arg(seconds)); + SetTableItem(i, 8, QString("%1").arg(seconds) + tr("s")); } else { SetTableItem(i, 8, formattedPlayTime); } @@ -241,7 +239,7 @@ void GameListFrame::SetCompatibilityItem(int row, int column, CompatibilityEntry break; case CompatibilityStatus::Nothing: color = QStringLiteral("#212121"); - status_explanation = tr("Games does not initialize properly / crashes the emulator"); + status_explanation = tr("Game does not initialize properly / crashes the emulator"); break; case CompatibilityStatus::Boots: color = QStringLiteral("#828282"); diff --git a/src/qt_gui/game_list_utils.h b/src/qt_gui/game_list_utils.h index 16c0307c8..ab9233886 100644 --- a/src/qt_gui/game_list_utils.h +++ b/src/qt_gui/game_list_utils.h @@ -30,10 +30,11 @@ struct GameInfo { CompatibilityEntry compatibility = CompatibilityEntry{CompatibilityStatus::Unknown}; }; -class GameListUtils { +class GameListUtils : public QObject { + Q_OBJECT public: static QString FormatSize(qint64 size) { - static const QStringList suffixes = {"B", "KB", "MB", "GB", "TB"}; + static const QStringList suffixes = {tr("B"), tr("KB"), tr("MB"), tr("GB"), tr("TB")}; int suffixIndex = 0; double gameSize = static_cast(size); diff --git a/src/qt_gui/gui_context_menus.h b/src/qt_gui/gui_context_menus.h index 3cc12c11e..6c96ab37f 100644 --- a/src/qt_gui/gui_context_menus.h +++ b/src/qt_gui/gui_context_menus.h @@ -11,6 +11,9 @@ #include #include "cheats_patches.h" +#include "common/config.h" +#include "common/version.h" +#include "compatibility_info.h" #include "game_info.h" #include "trophy_viewer.h" @@ -27,8 +30,9 @@ class GuiContextMenus : public QObject { Q_OBJECT public: - void RequestGameMenu(const QPoint& pos, QVector m_games, QTableWidget* widget, - bool isList) { + void RequestGameMenu(const QPoint& pos, QVector m_games, + std::shared_ptr m_compat_info, + QTableWidget* widget, bool isList) { QPoint global_pos = widget->viewport()->mapToGlobal(pos); int itemID = 0; if (isList) { @@ -91,6 +95,21 @@ public: menu.addMenu(deleteMenu); + // Compatibility submenu. + QMenu* compatibilityMenu = new QMenu(tr("Compatibility..."), widget); + QAction* updateCompatibility = new QAction(tr("Update database"), widget); + QAction* viewCompatibilityReport = new QAction(tr("View report"), widget); + QAction* submitCompatibilityReport = new QAction(tr("Submit a report"), widget); + + compatibilityMenu->addAction(updateCompatibility); + compatibilityMenu->addAction(viewCompatibilityReport); + compatibilityMenu->addAction(submitCompatibilityReport); + + menu.addMenu(compatibilityMenu); + + compatibilityMenu->setEnabled(Config::getCompatibilityEnabled()); + viewCompatibilityReport->setEnabled(!m_games[itemID].compatibility.url.isEmpty()); + // Show menu. auto selected = menu.exec(global_pos); if (!selected) { @@ -268,11 +287,11 @@ public: #endif QMessageBox::information( nullptr, tr("Shortcut creation"), - QString(tr("Shortcut created successfully!\n %1")).arg(linkPath)); + QString(tr("Shortcut created successfully!") + "\n%1").arg(linkPath)); } else { QMessageBox::critical( nullptr, tr("Error"), - QString(tr("Error creating shortcut!\n %1")).arg(linkPath)); + QString(tr("Error creating shortcut!") + "\n%1").arg(linkPath)); } } else { QMessageBox::critical(nullptr, tr("Error"), tr("Failed to convert icon.")); @@ -286,11 +305,11 @@ public: #endif QMessageBox::information( nullptr, tr("Shortcut creation"), - QString(tr("Shortcut created successfully!\n %1")).arg(linkPath)); + QString(tr("Shortcut created successfully!") + "\n%1").arg(linkPath)); } else { QMessageBox::critical( nullptr, tr("Error"), - QString(tr("Error creating shortcut!\n %1")).arg(linkPath)); + QString(tr("Error creating shortcut!") + "\n%1").arg(linkPath)); } } } @@ -360,6 +379,31 @@ public: } } } + + if (selected == updateCompatibility) { + m_compat_info->UpdateCompatibilityDatabase(widget, true); + } + + if (selected == viewCompatibilityReport) { + if (!m_games[itemID].compatibility.url.isEmpty()) + QDesktopServices::openUrl(QUrl(m_games[itemID].compatibility.url)); + } + + if (selected == submitCompatibilityReport) { + QUrl url = QUrl("https://github.com/shadps4-emu/shadps4-game-compatibility/issues/new"); + QUrlQuery query; + query.addQueryItem("template", QString("game_compatibility.yml")); + query.addQueryItem( + "title", QString("%1 - %2").arg(QString::fromStdString(m_games[itemID].serial), + QString::fromStdString(m_games[itemID].name))); + query.addQueryItem("game-name", QString::fromStdString(m_games[itemID].name)); + query.addQueryItem("game-code", QString::fromStdString(m_games[itemID].serial)); + query.addQueryItem("game-version", QString::fromStdString(m_games[itemID].version)); + query.addQueryItem("emulator-version", QString(Common::VERSION)); + url.setQuery(query); + + QDesktopServices::openUrl(url); + } } int GetRowIndex(QTreeWidget* treeWidget, QTreeWidgetItem* item) { diff --git a/src/qt_gui/main_window.cpp b/src/qt_gui/main_window.cpp index adb42fc26..724e008ae 100644 --- a/src/qt_gui/main_window.cpp +++ b/src/qt_gui/main_window.cpp @@ -75,8 +75,8 @@ bool MainWindow::Init() { this->setStatusBar(statusBar.data()); // Update status bar int numGames = m_game_info->m_games.size(); - QString statusMessage = - "Games: " + QString::number(numGames) + " (" + QString::number(duration.count()) + "ms)"; + QString statusMessage = tr("Games: ") + QString::number(numGames) + " (" + + QString::number(duration.count()) + "ms)"; statusBar->showMessage(statusMessage); #ifdef ENABLE_DISCORD_RPC @@ -140,7 +140,7 @@ void MainWindow::CreateDockWindows() { m_dock_widget.reset(new QDockWidget(tr("Game List"), this)); m_game_list_frame.reset(new GameListFrame(m_game_info, m_compat_info, this)); m_game_list_frame->setObjectName("gamelist"); - m_game_grid_frame.reset(new GameGridFrame(m_game_info, this)); + m_game_grid_frame.reset(new GameGridFrame(m_game_info, m_compat_info, this)); m_game_grid_frame->setObjectName("gamegridlist"); m_elf_viewer.reset(new ElfViewer(this)); m_elf_viewer->setObjectName("elflist"); @@ -253,20 +253,26 @@ void MainWindow::CreateConnects() { &MainWindow::StartGame); connect(ui->configureAct, &QAction::triggered, this, [this]() { - auto settingsDialog = new SettingsDialog(m_physical_devices, this); + auto settingsDialog = new SettingsDialog(m_physical_devices, m_compat_info, this); connect(settingsDialog, &SettingsDialog::LanguageChanged, this, &MainWindow::OnLanguageChanged); + connect(settingsDialog, &SettingsDialog::CompatibilityChanged, this, + &MainWindow::RefreshGameTable); + settingsDialog->exec(); }); connect(ui->settingsButton, &QPushButton::clicked, this, [this]() { - auto settingsDialog = new SettingsDialog(m_physical_devices, this); + auto settingsDialog = new SettingsDialog(m_physical_devices, m_compat_info, this); connect(settingsDialog, &SettingsDialog::LanguageChanged, this, &MainWindow::OnLanguageChanged); + connect(settingsDialog, &SettingsDialog::CompatibilityChanged, this, + &MainWindow::RefreshGameTable); + settingsDialog->exec(); }); diff --git a/src/qt_gui/settings_dialog.cpp b/src/qt_gui/settings_dialog.cpp index 2f89c9fd2..a5219c3e1 100644 --- a/src/qt_gui/settings_dialog.cpp +++ b/src/qt_gui/settings_dialog.cpp @@ -6,6 +6,8 @@ #include #include +#include "common/config.h" +#include "qt_gui/compatibility_info.h" #ifdef ENABLE_DISCORD_RPC #include "common/discord_rpc_handler.h" #endif @@ -54,7 +56,9 @@ QStringList languageNames = {"Arabic", const QVector languageIndexes = {21, 23, 14, 6, 18, 1, 12, 22, 2, 4, 25, 24, 29, 5, 0, 9, 15, 16, 17, 7, 26, 8, 11, 20, 3, 13, 27, 10, 19, 30, 28}; -SettingsDialog::SettingsDialog(std::span physical_devices, QWidget* parent) +SettingsDialog::SettingsDialog(std::span physical_devices, + std::shared_ptr m_compat_info, + QWidget* parent) : QDialog(parent), ui(new Ui::SettingsDialog) { ui->setupUi(this); ui->tabWidgetSettings->setUsesScrollButtons(false); @@ -140,6 +144,16 @@ SettingsDialog::SettingsDialog(std::span physical_devices, QWidge ui->updaterGroupBox->setVisible(false); ui->GUIgroupBox->setMaximumSize(265, 16777215); #endif + connect(ui->updateCompatibilityButton, &QPushButton::clicked, this, + [this, parent, m_compat_info]() { + m_compat_info->UpdateCompatibilityDatabase(this, true); + emit CompatibilityChanged(); + }); + + connect(ui->enableCompatibilityCheckBox, &QCheckBox::stateChanged, this, [this](int state) { + Config::setCompatibilityEnabled(state); + emit CompatibilityChanged(); + }); } // Input TAB @@ -195,6 +209,10 @@ SettingsDialog::SettingsDialog(std::span physical_devices, QWidge #endif ui->GUIgroupBox->installEventFilter(this); ui->disableTrophycheckBox->installEventFilter(this); + ui->enableCompatibilityCheckBox->installEventFilter(this); + ui->checkCompatibilityOnStartupCheckBox->installEventFilter(this); + ui->updateCompatibilityButton->installEventFilter(this); + ui->audioBackendComboBox->installEventFilter(this); // Input ui->hideCursorGroupBox->installEventFilter(this); @@ -286,6 +304,12 @@ void SettingsDialog::LoadValuesFromConfig() { ui->vkSyncValidationCheckBox->setChecked( toml::find_or(data, "Vulkan", "validation_sync", false)); ui->rdocCheckBox->setChecked(toml::find_or(data, "Vulkan", "rdocEnable", false)); + ui->enableCompatibilityCheckBox->setChecked( + toml::find_or(data, "General", "compatibilityEnabled", false)); + ui->checkCompatibilityOnStartupCheckBox->setChecked( + toml::find_or(data, "General", "checkCompatibilityOnStartup", false)); + ui->audioBackendComboBox->setCurrentText( + QString::fromStdString(toml::find_or(data, "Audio", "backend", "cubeb"))); #ifdef ENABLE_UPDATER ui->updateCheckBox->setChecked(toml::find_or(data, "General", "autoUpdate", false)); @@ -403,6 +427,14 @@ void SettingsDialog::updateNoteTextEdit(const QString& elementName) { text = tr("GUIgroupBox"); } else if (elementName == "disableTrophycheckBox") { text = tr("disableTrophycheckBox"); + } else if (elementName == "enableCompatibilityCheckBox") { + text = tr("enableCompatibilityCheckBox"); + } else if (elementName == "checkCompatibilityOnStartupCheckBox") { + text = tr("checkCompatibilityOnStartupCheckBox"); + } else if (elementName == "updateCompatibilityButton") { + text = tr("updateCompatibilityButton"); + } else if (elementName == "audioBackendGroupBox") { + text = tr("audioBackendGroupBox"); } // Input @@ -515,6 +547,9 @@ void SettingsDialog::UpdateSettings() { Config::setRdocEnabled(ui->rdocCheckBox->isChecked()); Config::setAutoUpdate(ui->updateCheckBox->isChecked()); Config::setUpdateChannel(ui->updateComboBox->currentText().toStdString()); + Config::setCompatibilityEnabled(ui->enableCompatibilityCheckBox->isChecked()); + Config::setCheckCompatibilityOnStartup(ui->checkCompatibilityOnStartupCheckBox->isChecked()); + Config::setAudioBackend(ui->audioBackendComboBox->currentText().toStdString()); #ifdef ENABLE_DISCORD_RPC auto* rpc = Common::Singleton::Instance(); diff --git a/src/qt_gui/settings_dialog.h b/src/qt_gui/settings_dialog.h index 987b35d45..892e67671 100644 --- a/src/qt_gui/settings_dialog.h +++ b/src/qt_gui/settings_dialog.h @@ -3,6 +3,7 @@ #pragma once +#include #include #include #include @@ -10,6 +11,7 @@ #include "common/config.h" #include "common/path_util.h" +#include "qt_gui/compatibility_info.h" namespace Ui { class SettingsDialog; @@ -18,7 +20,9 @@ class SettingsDialog; class SettingsDialog : public QDialog { Q_OBJECT public: - explicit SettingsDialog(std::span physical_devices, QWidget* parent = nullptr); + explicit SettingsDialog(std::span physical_devices, + std::shared_ptr m_compat_info, + QWidget* parent = nullptr); ~SettingsDialog(); bool eventFilter(QObject* obj, QEvent* event) override; @@ -28,6 +32,7 @@ public: signals: void LanguageChanged(const std::string& locale); + void CompatibilityChanged(); private: void LoadValuesFromConfig(); diff --git a/src/qt_gui/settings_dialog.ui b/src/qt_gui/settings_dialog.ui index bbc170a1b..f2d6b77d2 100644 --- a/src/qt_gui/settings_dialog.ui +++ b/src/qt_gui/settings_dialog.ui @@ -11,8 +11,8 @@ 0 0 - 854 - 660 + 950 + 780 @@ -42,153 +42,42 @@ - + true - - QFrame::Shape::NoFrame + + + 0 + 0 + - - true + + 0 - - + + true - - - 0 - 0 - 815 - 581 - - - - - 0 - 0 - - - - 0 - - - - General - - + + General + + + + + 0 + 0 + 822 + 487 + + + - - - - - - - System - - - - - - Console Language - - - - - - - - - - - - Emulator Language - - - - - - - - - - - - - - - - - - - Emulator - - - - - - - - Enable Fullscreen - - - - - - - Enable Separate Update Folder - - - - - - - Show Splash - - - - - - - Enable Discord Rich Presence - - - - - - - - - 6 - - - 0 - - - - - - - Username - - - - - - - - - - - - - - - - - - + + + 0 + + @@ -268,12 +157,145 @@ - - - - - + + + + + + System + + + + + + Console Language + + + + + + + + + + + + Emulator Language + + + + + + + + + + + + + + + + + + + Emulator + + + + + + 10 + + + + + Enable Fullscreen + + + + + + + Enable Separate Update Folder + + + + + + + Show Splash + + + + + + + Enable Discord Rich Presence + + + + + + + + + 6 + + + 0 + + + + + + + Username + + + + + + + + + + + + + + + + Audio Backend + + + + + + + cubeb + + + + + sdl + + + + + + + + + + + + + + + -1 + QLayout::SizeConstraint::SetDefaultConstraint @@ -289,7 +311,7 @@ 0 - + @@ -299,7 +321,7 @@ - 275 + 0 0 @@ -314,7 +336,7 @@ - 5 + 10 1 @@ -336,7 +358,7 @@ 0 - 75 + 0 @@ -397,8 +419,8 @@ - 197 - 28 + 0 + 0 @@ -436,7 +458,7 @@ - + @@ -469,6 +491,19 @@ + + + + + 0 + 0 + + + + Play title music + + + @@ -478,20 +513,7 @@ 0 - - - - 0 - 0 - - - - Play title music - - - - - + Qt::Orientation::Vertical @@ -501,7 +523,7 @@ 20 - 2 + 13 @@ -566,20 +588,76 @@ - - - - - - Qt::Orientation::Horizontal + + + + + + + 0 + 0 + - + - 40 - 20 + 0 + 0 - + + Game Compatibility + + + + 10 + + + 1 + + + 11 + + + + + Display Compatibility Data + + + + + + + Update Compatibility Database On Startup + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + Update Compatibility Database + + + + + @@ -587,10 +665,23 @@ - - - Input - + + + + true + + + Input + + + + + 0 + 0 + 396 + 222 + + @@ -699,8 +790,8 @@ - 80 - 30 + 0 + 0 @@ -786,7 +877,7 @@ - 237 + 0 0 @@ -865,10 +956,23 @@ - - - Graphics - + + + + true + + + Graphics + + + + + 0 + 0 + 536 + 192 + + @@ -1103,58 +1207,54 @@ - - - Paths - - + + + + true + + + Paths + + + + + 0 + 0 + 146 + 215 + + + - + Game Folders - - - - 0 - 20 - 401 - 331 - - - - - - - 100 - 360 - 91 - 24 - - - - Add... - - - - - - 199 - 360 - 91 - 24 - - - - Remove - - + + + + + Remove + + + + + + + Add... + + + + + + + - + Qt::Orientation::Horizontal @@ -1173,10 +1273,23 @@ - - - Debug - + + + + true + + + Debug + + + + + 0 + 0 + 288 + 163 + + diff --git a/src/qt_gui/translations/ar.ts b/src/qt_gui/translations/ar.ts index 3f861187e..1f65db04a 100644 --- a/src/qt_gui/translations/ar.ts +++ b/src/qt_gui/translations/ar.ts @@ -175,6 +175,26 @@ Delete DLC Delete DLC + + + Compatibility... + Compatibility... + + + + Update database + Update database + + + + View report + View report + + + + Submit a report + Submit a report + Shortcut creation @@ -182,8 +202,8 @@ - Shortcut created successfully!\n %1 - تم إنشاء الاختصار بنجاح!\n %1 + Shortcut created successfully! + تم إنشاء الاختصار بنجاح! @@ -192,8 +212,8 @@ - Error creating shortcut!\n %1 - !\n %1 خطأ في إنشاء الاختصار + Error creating shortcut! + خطأ في إنشاء الاختصار @@ -552,6 +572,11 @@ Hide Cursor Idle Timeout مهلة إخفاء المؤشر عند الخمول + + + s + s + Controller @@ -672,16 +697,46 @@ GUI Settings إعدادات الواجهة + + + Disable Trophy Pop-ups + Disable Trophy Pop-ups + Play title music تشغيل موسيقى العنوان + + + Update Compatibility Database On Startup + Update Compatibility Database On Startup + + + + Game Compatibility + Game Compatibility + + + + Display Compatibility Data + Display Compatibility Data + + + + Update Compatibility Database + Update Compatibility Database + Volume الصوت + + + Audio Backend + Audio Backend + MainWindow @@ -1201,6 +1256,11 @@ GUIgroupBox تشغيل موسيقى العنوان:\nإذا كانت اللعبة تدعم ذلك، قم بتمكين تشغيل موسيقى خاصة عند اختيار اللعبة في واجهة المستخدم. + + + disableTrophycheckBox + 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). + hideCursorGroupBox @@ -1216,6 +1276,21 @@ backButtonBehaviorGroupBox سلوك زر العودة:\nيضبط زر العودة في وحدة التحكم ليحاكي الضغط على الموضع المحدد على لوحة اللمس في PS4. + + + enableCompatibilityCheckBox + Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information. + + + + checkCompatibilityOnStartupCheckBox + Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts. + + + + updateCompatibilityButton + Update Compatibility Database:\nImmediately update the compatibility database. + Never @@ -1329,6 +1404,11 @@ Serial سيريال + + + Compatibility + Compatibility + Region @@ -1364,6 +1444,51 @@ Never Played Never Played + + + h + h + + + + m + m + + + + s + s + + + + Compatibility is untested + Compatibility is untested + + + + Game does not initialize properly / crashes the emulator + Game does not initialize properly / crashes the emulator + + + + Game boots, but only displays a blank screen + Game boots, but only displays a blank screen + + + + Game displays an image but does not go past the menu + Game displays an image but does not go past the menu + + + + Game has game-breaking glitches or unplayable performance + Game has game-breaking glitches or unplayable performance + + + + Game can be completed with playable performance and no major glitches + Game can be completed with playable performance and no major glitches + CheckUpdate @@ -1493,4 +1618,32 @@ فشل في إنشاء ملف سكريبت التحديث + + GameListUtils + + + B + B + + + + KB + KB + + + + MB + MB + + + + GB + GB + + + + TB + TB + + \ No newline at end of file diff --git a/src/qt_gui/translations/da_DK.ts b/src/qt_gui/translations/da_DK.ts index 3539159e2..943e2d092 100644 --- a/src/qt_gui/translations/da_DK.ts +++ b/src/qt_gui/translations/da_DK.ts @@ -175,6 +175,26 @@ Delete DLC Delete DLC + + + Compatibility... + Compatibility... + + + + Update database + Update database + + + + View report + View report + + + + Submit a report + Submit a report + Shortcut creation @@ -182,8 +202,8 @@ - Shortcut created successfully!\n %1 - Shortcut created successfully!\n %1 + Shortcut created successfully! + Shortcut created successfully! @@ -192,8 +212,8 @@ - Error creating shortcut!\n %1 - Error creating shortcut!\n %1 + Error creating shortcut! + Error creating shortcut! @@ -552,6 +572,11 @@ Hide Cursor Idle Timeout Timeout for skjul markør ved inaktivitet + + + s + s + Controller @@ -672,16 +697,46 @@ GUI Settings GUI-Indstillinger + + + Disable Trophy Pop-ups + Disable Trophy Pop-ups + Play title music Afspil titelsang + + + Update Compatibility Database On Startup + Update Compatibility Database On Startup + + + + Game Compatibility + Game Compatibility + + + + Display Compatibility Data + Display Compatibility Data + + + + Update Compatibility Database + Update Compatibility Database + Volume Lydstyrke + + + Audio Backend + Audio Backend + MainWindow @@ -1201,6 +1256,11 @@ GUIgroupBox Titelsmusikafspilning:\nHvis spillet understøtter det, aktiver speciel musik, når spillet vælges i brugergrænsefladen. + + + disableTrophycheckBox + 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). + hideCursorGroupBox @@ -1216,6 +1276,21 @@ backButtonBehaviorGroupBox Tilbageknap Adfærd:\nIndstiller controllerens tilbageknap til at efterligne tryk på den angivne position på PS4 berøringsflade. + + + enableCompatibilityCheckBox + Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information. + + + + checkCompatibilityOnStartupCheckBox + Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts. + + + + updateCompatibilityButton + Update Compatibility Database:\nImmediately update the compatibility database. + Never @@ -1329,6 +1404,11 @@ Serial Seriel + + + Compatibility + Compatibility + Region @@ -1364,6 +1444,51 @@ Never Played Never Played + + + h + h + + + + m + m + + + + s + s + + + + Compatibility is untested + Compatibility is untested + + + + Game does not initialize properly / crashes the emulator + Game does not initialize properly / crashes the emulator + + + + Game boots, but only displays a blank screen + Game boots, but only displays a blank screen + + + + Game displays an image but does not go past the menu + Game displays an image but does not go past the menu + + + + Game has game-breaking glitches or unplayable performance + Game has game-breaking glitches or unplayable performance + + + + Game can be completed with playable performance and no major glitches + Game can be completed with playable performance and no major glitches + CheckUpdate @@ -1493,4 +1618,32 @@ Kunne ikke oprette opdateringsscriptfilen + + GameListUtils + + + B + B + + + + KB + KB + + + + MB + MB + + + + GB + GB + + + + TB + TB + + \ No newline at end of file diff --git a/src/qt_gui/translations/de.ts b/src/qt_gui/translations/de.ts index f34402ac9..cbbef8215 100644 --- a/src/qt_gui/translations/de.ts +++ b/src/qt_gui/translations/de.ts @@ -175,6 +175,26 @@ Delete DLC Delete DLC + + + Compatibility... + Compatibility... + + + + Update database + Update database + + + + View report + View report + + + + Submit a report + Submit a report + Shortcut creation @@ -182,8 +202,8 @@ - Shortcut created successfully!\n %1 - Verknüpfung erfolgreich erstellt!\n %1 + Shortcut created successfully! + Verknüpfung erfolgreich erstellt! @@ -192,8 +212,8 @@ - Error creating shortcut!\n %1 - Fehler beim Erstellen der Verknüpfung!\n %1 + Error creating shortcut! + Fehler beim Erstellen der Verknüpfung! @@ -552,6 +572,11 @@ Hide Cursor Idle Timeout Inaktivitätszeitüberschreitung zum Ausblenden des Cursors + + + s + s + Controller @@ -672,16 +697,46 @@ GUI Settings GUI-Einstellungen + + + Disable Trophy Pop-ups + Disable Trophy Pop-ups + Play title music Titelmusik abspielen + + + Update Compatibility Database On Startup + Update Compatibility Database On Startup + + + + Game Compatibility + Game Compatibility + + + + Display Compatibility Data + Display Compatibility Data + + + + Update Compatibility Database + Update Compatibility Database + Volume Lautstärke + + + Audio Backend + Audio Backend + MainWindow @@ -1201,6 +1256,11 @@ GUIgroupBox Wiedergabe der Titelmusik:\nWenn das Spiel dies unterstützt, wird beim Auswählen des Spiels in der Benutzeroberfläche spezielle Musik abgespielt. + + + disableTrophycheckBox + 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). + hideCursorGroupBox @@ -1216,6 +1276,21 @@ backButtonBehaviorGroupBox Zurück-Button Verhalten:\nStellt die Zurück-Taste des Controllers so ein, dass sie das Antippen der angegebenen Position auf dem PS4-Touchpad emuliert. + + + enableCompatibilityCheckBox + Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information. + + + + checkCompatibilityOnStartupCheckBox + Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts. + + + + updateCompatibilityButton + Update Compatibility Database:\nImmediately update the compatibility database. + Never @@ -1329,6 +1404,11 @@ Serial Seriennummer + + + Compatibility + Compatibility + Region @@ -1364,6 +1444,51 @@ Never Played Never Played + + + h + h + + + + m + m + + + + s + s + + + + Compatibility is untested + Compatibility is untested + + + + Game does not initialize properly / crashes the emulator + Game does not initialize properly / crashes the emulator + + + + Game boots, but only displays a blank screen + Game boots, but only displays a blank screen + + + + Game displays an image but does not go past the menu + Game displays an image but does not go past the menu + + + + Game has game-breaking glitches or unplayable performance + Game has game-breaking glitches or unplayable performance + + + + Game can be completed with playable performance and no major glitches + Game can be completed with playable performance and no major glitches + CheckUpdate @@ -1493,4 +1618,32 @@ Fehler beim Erstellen der Aktualisierungs-Skriptdatei + + GameListUtils + + + B + B + + + + KB + KB + + + + MB + MB + + + + GB + GB + + + + TB + TB + + \ No newline at end of file diff --git a/src/qt_gui/translations/el.ts b/src/qt_gui/translations/el.ts index 65cee641a..8737f5216 100644 --- a/src/qt_gui/translations/el.ts +++ b/src/qt_gui/translations/el.ts @@ -175,6 +175,26 @@ Delete DLC Delete DLC + + + Compatibility... + Compatibility... + + + + Update database + Update database + + + + View report + View report + + + + Submit a report + Submit a report + Shortcut creation @@ -182,8 +202,8 @@ - Shortcut created successfully!\n %1 - Shortcut created successfully!\n %1 + Shortcut created successfully! + Shortcut created successfully! @@ -192,8 +212,8 @@ - Error creating shortcut!\n %1 - Error creating shortcut!\n %1 + Error creating shortcut! + Error creating shortcut! @@ -552,6 +572,11 @@ Hide Cursor Idle Timeout Χρόνος αδράνειας απόκρυψης δείκτη + + + s + s + Controller @@ -672,16 +697,46 @@ GUI Settings Ρυθμίσεις GUI + + + Disable Trophy Pop-ups + Disable Trophy Pop-ups + Play title music Αναπαραγωγή μουσικής τίτλου + + + Update Compatibility Database On Startup + Update Compatibility Database On Startup + + + + Game Compatibility + Game Compatibility + + + + Display Compatibility Data + Display Compatibility Data + + + + Update Compatibility Database + Update Compatibility Database + Volume ένταση + + + Audio Backend + Audio Backend + MainWindow @@ -1201,6 +1256,11 @@ GUIgroupBox Αναπαραγωγή Μουσικής Τίτλων:\nΕάν το παιχνίδι το υποστηρίζει, ενεργοποιεί ειδική μουσική κατά την επιλογή του παιχνιδιού από τη διεπαφή χρήστη. + + + disableTrophycheckBox + 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). + hideCursorGroupBox @@ -1216,6 +1276,21 @@ backButtonBehaviorGroupBox Συμπεριφορά Κουμπιού Επιστροφής:\nΟρίζει το κουμπί επιστροφής του ελεγκτή να προσομοιώνει το πάτημα της καθορισμένης θέσης στην οθόνη αφής PS4. + + + enableCompatibilityCheckBox + Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information. + + + + checkCompatibilityOnStartupCheckBox + Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts. + + + + updateCompatibilityButton + Update Compatibility Database:\nImmediately update the compatibility database. + Never @@ -1329,6 +1404,11 @@ Serial Σειριακός αριθμός + + + Compatibility + Compatibility + Region @@ -1364,6 +1444,51 @@ Never Played Never Played + + + h + h + + + + m + m + + + + s + s + + + + Compatibility is untested + Compatibility is untested + + + + Game does not initialize properly / crashes the emulator + Game does not initialize properly / crashes the emulator + + + + Game boots, but only displays a blank screen + Game boots, but only displays a blank screen + + + + Game displays an image but does not go past the menu + Game displays an image but does not go past the menu + + + + Game has game-breaking glitches or unplayable performance + Game has game-breaking glitches or unplayable performance + + + + Game can be completed with playable performance and no major glitches + Game can be completed with playable performance and no major glitches + CheckUpdate @@ -1493,4 +1618,32 @@ Αποτυχία δημιουργίας του αρχείου σεναρίου ενημέρωσης + + GameListUtils + + + B + B + + + + KB + KB + + + + MB + MB + + + + GB + GB + + + + TB + TB + + \ No newline at end of file diff --git a/src/qt_gui/translations/en.ts b/src/qt_gui/translations/en.ts index ddaa4fe0d..692aa527e 100644 --- a/src/qt_gui/translations/en.ts +++ b/src/qt_gui/translations/en.ts @@ -175,6 +175,26 @@ Delete DLC Delete DLC + + + Compatibility... + Compatibility... + + + + Update database + Update database + + + + View report + View report + + + + Submit a report + Submit a report + Shortcut creation @@ -182,8 +202,8 @@ - Shortcut created successfully!\n %1 - Shortcut created successfully!\n %1 + Shortcut created successfully! + Shortcut created successfully! @@ -192,8 +212,8 @@ - Error creating shortcut!\n %1 - Error creating shortcut!\n %1 + Error creating shortcut! + Error creating shortcut! @@ -552,6 +572,11 @@ Hide Cursor Idle Timeout Hide Cursor Idle Timeout + + + s + s + Controller @@ -672,16 +697,46 @@ GUI Settings GUI Settings + + + Disable Trophy Pop-ups + Disable Trophy Pop-ups + Play title music Play title music + + + Update Compatibility Database On Startup + Update Compatibility Database On Startup + + + + Game Compatibility + Game Compatibility + + + + Display Compatibility Data + Display Compatibility Data + + + + Update Compatibility Database + Update Compatibility Database + Volume Volume + + + Audio Backend + Audio Backend + MainWindow @@ -1221,6 +1276,21 @@ backButtonBehaviorGroupBox Back Button Behavior:\nSets the controller's back button to emulate tapping the specified position on the PS4 touchpad. + + + enableCompatibilityCheckBox + Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information. + + + + checkCompatibilityOnStartupCheckBox + Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts. + + + + updateCompatibilityButton + Update Compatibility Database:\nImmediately update the compatibility database. + Never @@ -1334,6 +1404,11 @@ Serial Serial + + + Compatibility + Compatibility + Region @@ -1369,6 +1444,51 @@ Never Played Never Played + + + h + h + + + + m + m + + + + s + s + + + + Compatibility is untested + Compatibility is untested + + + + Game does not initialize properly / crashes the emulator + Game does not initialize properly / crashes the emulator + + + + Game boots, but only displays a blank screen + Game boots, but only displays a blank screen + + + + Game displays an image but does not go past the menu + Game displays an image but does not go past the menu + + + + Game has game-breaking glitches or unplayable performance + Game has game-breaking glitches or unplayable performance + + + + Game can be completed with playable performance and no major glitches + Game can be completed with playable performance and no major glitches + CheckUpdate @@ -1498,4 +1618,32 @@ Failed to create the update script file + + GameListUtils + + + B + B + + + + KB + KB + + + + MB + MB + + + + GB + GB + + + + TB + TB + + \ No newline at end of file diff --git a/src/qt_gui/translations/es_ES.ts b/src/qt_gui/translations/es_ES.ts index 3d1f291a6..70be2253d 100644 --- a/src/qt_gui/translations/es_ES.ts +++ b/src/qt_gui/translations/es_ES.ts @@ -175,6 +175,26 @@ Delete DLC Delete DLC + + + Compatibility... + Compatibility... + + + + Update database + Update database + + + + View report + View report + + + + Submit a report + Submit a report + Shortcut creation @@ -182,8 +202,8 @@ - Shortcut created successfully!\n %1 - ¡Acceso directo creado con éxito!\n %1 + Shortcut created successfully! + ¡Acceso directo creado con éxito! @@ -192,8 +212,8 @@ - Error creating shortcut!\n %1 - ¡Error al crear el acceso directo!\n %1 + Error creating shortcut! + ¡Error al crear el acceso directo! @@ -552,6 +572,11 @@ Hide Cursor Idle Timeout Tiempo de espera para ocultar cursor inactivo + + + s + s + Controller @@ -672,16 +697,46 @@ GUI Settings Configuraciones de la Interfaz + + + Disable Trophy Pop-ups + Disable Trophy Pop-ups + Play title music Reproducir la música de apertura + + + Update Compatibility Database On Startup + Update Compatibility Database On Startup + + + + Game Compatibility + Game Compatibility + + + + Display Compatibility Data + Display Compatibility Data + + + + Update Compatibility Database + Update Compatibility Database + Volume Volumen + + + Audio Backend + Audio Backend + MainWindow @@ -1201,6 +1256,11 @@ GUIgroupBox Reproducir Música del Título:\nSi un juego lo admite, habilita la reproducción de música especial al seleccionar el juego en la interfaz gráfica. + + + disableTrophycheckBox + 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). + hideCursorGroupBox @@ -1216,6 +1276,21 @@ backButtonBehaviorGroupBox Comportamiento del Botón Atrás:\nEstablece el botón atrás del controlador para emular el toque en la posición especificada en el touchpad del PS4. + + + enableCompatibilityCheckBox + Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information. + + + + checkCompatibilityOnStartupCheckBox + Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts. + + + + updateCompatibilityButton + Update Compatibility Database:\nImmediately update the compatibility database. + Never @@ -1329,6 +1404,11 @@ Serial Numero de serie + + + Compatibility + Compatibility + Region @@ -1364,6 +1444,51 @@ Never Played Never Played + + + h + h + + + + m + m + + + + s + s + + + + Compatibility is untested + Compatibility is untested + + + + Game does not initialize properly / crashes the emulator + Game does not initialize properly / crashes the emulator + + + + Game boots, but only displays a blank screen + Game boots, but only displays a blank screen + + + + Game displays an image but does not go past the menu + Game displays an image but does not go past the menu + + + + Game has game-breaking glitches or unplayable performance + Game has game-breaking glitches or unplayable performance + + + + Game can be completed with playable performance and no major glitches + Game can be completed with playable performance and no major glitches + CheckUpdate @@ -1493,4 +1618,32 @@ No se pudo crear el archivo del script de actualización + + GameListUtils + + + B + B + + + + KB + KB + + + + MB + MB + + + + GB + GB + + + + TB + TB + + \ No newline at end of file diff --git a/src/qt_gui/translations/fa_IR.ts b/src/qt_gui/translations/fa_IR.ts index 58de03346..54187cf9b 100644 --- a/src/qt_gui/translations/fa_IR.ts +++ b/src/qt_gui/translations/fa_IR.ts @@ -62,7 +62,7 @@ Select which directory you want to install to. - Select which directory you want to install to. + محلی را که می‌خواهید در آن نصب شود، انتخاب کنید. @@ -98,7 +98,7 @@ Create Shortcut - ساخت شورتکات + ایجاد میانبر @@ -113,7 +113,7 @@ Trophy Viewer - مشاهده تروفی ها + مشاهده جوایز @@ -158,32 +158,52 @@ Delete... - Delete... + حذف... Delete Game - Delete Game + حذف بازی Delete Update - Delete Update + حذف به‌روزرسانی Delete DLC - Delete DLC + حذف محتوای اضافی (DLC) + + + + Compatibility... + Compatibility... + + + + Update database + Update database + + + + View report + View report + + + + Submit a report + Submit a report Shortcut creation - سازنده شورتکات + ایجاد میانبر - Shortcut created successfully!\n %1 - شورتکات با موفقیت ساخته شد! \n %1 + Shortcut created successfully! + میانبر با موفقیت ساخته شد! @@ -192,8 +212,8 @@ - Error creating shortcut!\n %1 - مشکلی در هنگام ساخت شورتکات بوجود آمد!\n %1 + Error creating shortcut! + مشکلی در هنگام ساخت میانبر بوجود آمد! @@ -203,27 +223,27 @@ Game - Game + بازی requiresEnableSeparateUpdateFolder_MSG - This feature requires the 'Enable Separate Update Folder' config option to work. If you want to use this feature, please enable it. + این قابلیت نیازمند فعال‌سازی گزینه تنظیمات «ایجاد پوشه جداگانه برای به‌روزرسانی» است. در صورت تمایل به استفاده از این قابلیت، لطفاً آن را فعال کنید. This game has no update to delete! - This game has no update to delete! + این بازی به‌روزرسانی‌ای برای حذف ندارد! Update - Update + به‌روزرسانی This game has no DLC to delete! - This game has no DLC to delete! + این بازی محتوای اضافی (DLC) برای حذف ندارد! @@ -233,7 +253,7 @@ Delete %1 - Delete %1 + حذف %1 @@ -331,7 +351,7 @@ List View - لیستی + نمایش لیست @@ -341,7 +361,7 @@ Elf Viewer - Elf Viewer + مشاهده گر Elf @@ -452,7 +472,7 @@ Trophy Viewer - تروفی ها + مشاهده جوایز @@ -495,7 +515,7 @@ Enable Separate Update Folder - Enable Separate Update Folder + فعال‌سازی پوشه جداگانه برای به‌روزرسانی @@ -552,10 +572,15 @@ Hide Cursor Idle Timeout مخفی کردن زمان توقف مکان نما + + + s + s + Controller - کنترل کننده + دسته بازی @@ -585,7 +610,7 @@ Vblank Divider - Vblank Divider + تقسیم‌کننده Vblank @@ -595,7 +620,7 @@ Enable Shaders Dumping - Shaders Dumping فعال کردن + فعال‌سازی ذخیره‌سازی شیدرها @@ -625,7 +650,7 @@ Debug - Debug + دیباگ @@ -650,37 +675,67 @@ Update - بروزرسانی + به‌روزرسانی Check for Updates at Startup - بررسی بروزرسانی هنگام شروع + بررسی به‌روزرسانی‌ها در زمان راه‌اندازی Update Channel - کانال بروزرسانی + کانال به‌روزرسانی Check for Updates - به روز رسانی را بررسی کنید + بررسی به‌روزرسانی‌ها GUI Settings تنظیمات رابط کاربری + + + Disable Trophy Pop-ups + غیرفعال کردن نمایش جوایز + Play title music پخش موسیقی عنوان + + + Update Compatibility Database On Startup + به‌روزرسانی پایگاه داده سازگاری هنگام راه‌اندازی + + + + Game Compatibility + سازگاری بازی با سیستم + + + + Display Compatibility Data + نمایش داده‌های سازگاری + + + + Update Compatibility Database + به‌روزرسانی پایگاه داده سازگاری + Volume - صدا + صدا + + + + Audio Backend + Audio Backend @@ -693,7 +748,7 @@ * Unsupported Vulkan Version - شما پشتیبانی نمیشود Vulkan ورژن* + شما پشتیبانی نمیشود Vulkan ورژن * @@ -841,7 +896,7 @@ Cheats / Patches for - Cheats / Patches for ا + چیت / پچ برای @@ -861,7 +916,7 @@ Version: - ورژن: + نسخه: @@ -886,7 +941,7 @@ Delete File - پاک کردن فایل + حذف فایل @@ -1149,27 +1204,27 @@ emulatorLanguageGroupBox - Emulator Language:\nSets the language of the emulator's user interface. + زبان شبیه‌ساز:\nزبان رابط کاربری شبیه‌ساز را انتخاب می‌کند. fullscreenCheckBox - Enable Full Screen:\nAutomatically puts the game window into full-screen mode.\nThis can be toggled by pressing the F11 key. + فعال‌سازی تمام صفحه:\nپنجره بازی را به‌طور خودکار به حالت تمام صفحه در می‌آورد.\nبرای تغییر این حالت می‌توانید کلید F11 را فشار دهید. separateUpdatesCheckBox - Enable Separate Update Folder:\nEnables installing game updates into a separate folder for easy management. + فعال‌سازی پوشه جداگانه برای به‌روزرسانی:\nامکان نصب به‌روزرسانی‌های بازی در یک پوشه جداگانه برای مدیریت راحت‌تر را فراهم می‌کند. showSplashCheckBox - Show Splash Screen:\nShows the game's splash screen (a special image) while the game is starting. + نمایش صفحه شروع:\nصفحه شروع بازی (تصویری ویژه) را هنگام بارگذاری بازی نمایش می‌دهد. ps4proCheckBox - Is PS4 Pro:\nMakes the emulator act as a PS4 PRO, which may enable special features in games that support it. + حالت PS4 Pro:\nشبیه‌ساز را به‌عنوان PS4 Pro شبیه‌سازی می‌کند که ممکن است ویژگی‌های ویژه‌ای را در بازی‌های پشتیبانی‌شده فعال کند. @@ -1179,12 +1234,12 @@ userName - Username:\nSets the PS4's account username, which may be displayed by some games. + نام کاربری:\nنام کاربری حساب PS4 را تنظیم می‌کند که ممکن است توسط برخی بازی‌ها نمایش داده شود. logTypeGroupBox - Log Type:\nSets whether to synchronize the output of the log window for performance. May have adverse effects on emulation. + نوع لاگ:\nتنظیم می‌کند که آیا خروجی پنجره لاگ برای بهبود عملکرد همگام‌سازی شود یا خیر. این ممکن است تأثیر منفی بر شبیه‌سازی داشته باشد. @@ -1194,12 +1249,17 @@ updaterGroupBox - 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. + به‌روزرسانی:\nانتشار: نسخه‌های رسمی که هر ماه منتشر می‌شوند و ممکن است بسیار قدیمی باشند، اما پایدارتر و تست‌ شده‌تر هستند.\nشبانه: نسخه‌های توسعه‌ای که شامل جدیدترین ویژگی‌ها و اصلاحات هستند، اما ممکن است دارای اشکال باشند و کمتر پایدار باشند. GUIgroupBox - Play Title Music:\nIf a game supports it, enable playing special music when selecting the game in the GUI. + پخش موسیقی عنوان:\nIدر صورتی که بازی از آن پشتیبانی کند، پخش موسیقی ویژه هنگام انتخاب بازی در رابط کاربری را فعال می‌کند. + + + + disableTrophycheckBox + غیرفعال کردن نمایش جوایز:\nنمایش اعلان‌های جوایز درون بازی را غیرفعال می‌کند. پیشرفت جوایز همچنان از طریق نمایشگر جوایز (کلیک راست روی بازی در پنجره اصلی) قابل پیگیری است.. @@ -1216,6 +1276,21 @@ backButtonBehaviorGroupBox رفتار دکمه برگشت:\nدکمه برگشت کنترلر را طوری تنظیم می کند که ضربه زدن روی موقعیت مشخص شده روی صفحه لمسی PS4 را شبیه سازی کند. + + + enableCompatibilityCheckBox + نمایش داده‌های سازگاری:\nاطلاعات سازگاری بازی را به صورت جدول نمایش می‌دهد. برای دریافت اطلاعات به‌روز، گزینه "به‌روزرسانی سازگاری هنگام راه‌اندازی" را فعال کنید. + + + + checkCompatibilityOnStartupCheckBox + به‌روزرسانی سازگاری هنگام راه‌اندازی:\nبه‌طور خودکار پایگاه داده سازگاری را هنگام راه‌اندازی ShadPS4 به‌روزرسانی می‌کند. + + + + updateCompatibilityButton + به‌روزرسانی پایگاه داده سازگاری:\nپایگاه داده سازگاری را بلافاصله به‌روزرسانی می‌کند. + Never @@ -1234,7 +1309,7 @@ Touchpad Left - پد لمسی سمت چپ + صفحه لمسی سمت چپ @@ -1244,7 +1319,7 @@ Touchpad Center - مرکز تاچ پد + مرکز صفحه لمسی @@ -1254,22 +1329,22 @@ graphicsAdapterGroupBox - 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در سیستم‌های با چندین پردازنده گرافیکی، از فهرست کشویی، پردازنده گرافیکی که شبیه‌ساز از آن استفاده می‌کند را انتخاب کنید، یا گزینه "انتخاب خودکار" را انتخاب کنید تا به طور خودکار تعیین شود. resolutionLayout - 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این با وضوح داخل بازی متفاوت است. heightDivider - 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! + تقسیم‌کننده Vblank:\nمیزان فریم ریت که شبیه‌ساز با آن به‌روزرسانی می‌شود، در این عدد ضرب می‌شود. تغییر این مقدار ممکن است تأثیرات منفی داشته باشد، مانند افزایش سرعت بازی یا خراب شدن عملکردهای حیاتی بازی که انتظار تغییر آن را ندارند! dumpShadersCheckBox - Enable Shaders Dumping:\nFor the sake of technical debugging, saves the games shaders to a folder as they render. + فعال‌سازی ذخیره‌سازی شیدرها:\nبه‌منظور اشکال‌زدایی فنی، شیدرهای بازی را هنگام رندر شدن در یک پوشه ذخیره می‌کند. @@ -1294,7 +1369,7 @@ debugDump - Enable Debug Dumping:\nSaves the import and export symbols and file header information of the currently running PS4 program to a directory. + فعال‌سازی ذخیره‌سازی دیباگ:\nنمادهای import و export و اطلاعات هدر فایل برنامه در حال اجرای PS4 را در یک پوشه ذخیره می‌کند. @@ -1329,6 +1404,11 @@ Serial سریال + + + Compatibility + سازگاری + Region @@ -1337,7 +1417,7 @@ Firmware - فریمور + فریم‌ور @@ -1362,7 +1442,52 @@ Never Played - Never Played + هرگز بازی نشده + + + + h + h + + + + m + m + + + + s + s + + + + 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 + بازی تصویری نمایش می‌دهد، اما از منو فراتر نمی‌رود + + + + Game has game-breaking glitches or unplayable performance + بازی دارای اشکالات بحرانی یا عملکرد غیرقابل بازی است + + + + Game can be completed with playable performance and no major glitches + بازی با عملکرد قابل قبول و بدون اشکالات عمده قابل بازی است. @@ -1370,7 +1495,7 @@ Auto Updater - به روز رسانی خودکار + به‌روزرسانی خودکار @@ -1415,7 +1540,7 @@ Update Channel - کانال بروزرسانی + کانال به‌روزرسانی @@ -1440,7 +1565,7 @@ Check for Updates at Startup - بررسی بروزرسانی هنگام شروع + بررسی به‌روزرسانی هنگام شروع @@ -1493,4 +1618,32 @@ فایل اسکریپت به روز رسانی ایجاد نشد - \ No newline at end of file + + GameListUtils + + + B + B + + + + KB + KB + + + + MB + MB + + + + GB + GB + + + + TB + TB + + + diff --git a/src/qt_gui/translations/fi.ts b/src/qt_gui/translations/fi.ts index 0a7f2b250..bdc1eb703 100644 --- a/src/qt_gui/translations/fi.ts +++ b/src/qt_gui/translations/fi.ts @@ -175,6 +175,26 @@ Delete DLC Delete DLC + + + Compatibility... + Compatibility... + + + + Update database + Update database + + + + View report + View report + + + + Submit a report + Submit a report + Shortcut creation @@ -182,8 +202,8 @@ - Shortcut created successfully!\n %1 - Shortcut created successfully!\n %1 + Shortcut created successfully! + Shortcut created successfully! @@ -192,8 +212,8 @@ - Error creating shortcut!\n %1 - Error creating shortcut!\n %1 + Error creating shortcut! + Error creating shortcut! @@ -552,6 +572,11 @@ Hide Cursor Idle Timeout Inaktiivisuuden aikaraja kursorin piilottamiselle + + + s + s + Controller @@ -672,16 +697,46 @@ GUI Settings GUI-Asetukset + + + Disable Trophy Pop-ups + Disable Trophy Pop-ups + Play title music Soita otsikkomusiikkia + + + Update Compatibility Database On Startup + Update Compatibility Database On Startup + + + + Game Compatibility + Game Compatibility + + + + Display Compatibility Data + Display Compatibility Data + + + + Update Compatibility Database + Update Compatibility Database + Volume Äänenvoimakkuus + + + Audio Backend + Audio Backend + MainWindow @@ -1201,6 +1256,11 @@ GUIgroupBox Soita Otsikkomusiikkia:\nJos peli tukee sitä, ota käyttöön erityisen musiikin soittaminen pelin valinnan yhteydessä käyttöliittymässä. + + + disableTrophycheckBox + 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). + hideCursorGroupBox @@ -1216,6 +1276,21 @@ backButtonBehaviorGroupBox Takaisin-napin käyttäytyminen:\nAsettaa ohjaimen takaisin-napin jäljittelemään kosketusta PS4:n kosketuslevyn määritettyyn kohtaan. + + + enableCompatibilityCheckBox + Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information. + + + + checkCompatibilityOnStartupCheckBox + Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts. + + + + updateCompatibilityButton + Update Compatibility Database:\nImmediately update the compatibility database. + Never @@ -1329,6 +1404,11 @@ Serial Sarjanumero + + + Compatibility + Compatibility + Region @@ -1364,6 +1444,51 @@ Never Played Never Played + + + h + h + + + + m + m + + + + s + s + + + + Compatibility is untested + Compatibility is untested + + + + Game does not initialize properly / crashes the emulator + Game does not initialize properly / crashes the emulator + + + + Game boots, but only displays a blank screen + Game boots, but only displays a blank screen + + + + Game displays an image but does not go past the menu + Game displays an image but does not go past the menu + + + + Game has game-breaking glitches or unplayable performance + Game has game-breaking glitches or unplayable performance + + + + Game can be completed with playable performance and no major glitches + Game can be completed with playable performance and no major glitches + CheckUpdate @@ -1493,4 +1618,32 @@ Päivitysskripttitiedoston luominen epäonnistui + + GameListUtils + + + B + B + + + + KB + KB + + + + MB + MB + + + + GB + GB + + + + TB + TB + + \ No newline at end of file diff --git a/src/qt_gui/translations/fr.ts b/src/qt_gui/translations/fr.ts index fad90622a..19b0f9358 100644 --- a/src/qt_gui/translations/fr.ts +++ b/src/qt_gui/translations/fr.ts @@ -175,6 +175,26 @@ Delete DLC Supprimer DLC + + + Compatibility... + Compatibility... + + + + Update database + Update database + + + + View report + View report + + + + Submit a report + Submit a report + Shortcut creation @@ -182,8 +202,8 @@ - Shortcut created successfully!\n %1 - Raccourci créé avec succès !\n %1 + Shortcut created successfully! + Raccourci créé avec succès ! @@ -192,8 +212,8 @@ - Error creating shortcut!\n %1 - Erreur lors de la création du raccourci !\n %1 + Error creating shortcut! + Erreur lors de la création du raccourci ! @@ -552,6 +572,11 @@ Hide Cursor Idle Timeout Délai d'inactivité pour masquer le curseur + + + s + s + Controller @@ -672,16 +697,46 @@ GUI Settings Paramètres de l'interface + + + Disable Trophy Pop-ups + Disable Trophy Pop-ups + Play title music Lire la musique du titre + + + Update Compatibility Database On Startup + Update Compatibility Database On Startup + + + + Game Compatibility + Game Compatibility + + + + Display Compatibility Data + Display Compatibility Data + + + + Update Compatibility Database + Update Compatibility Database + Volume Volume + + + Audio Backend + Audio Backend + MainWindow @@ -1201,6 +1256,11 @@ GUIgroupBox Jouer de la musique de titre:\nSi le jeu le prend en charge, cela active la musique spéciale lorsque vous sélectionnez le jeu dans l'interface utilisateur. + + + disableTrophycheckBox + 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). + hideCursorGroupBox @@ -1216,6 +1276,21 @@ backButtonBehaviorGroupBox Comportement du bouton retour:\nDéfinit le bouton de retour de la manette pour imiter le toucher de la position spécifiée sur le pavé tactile PS4. + + + enableCompatibilityCheckBox + Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information. + + + + checkCompatibilityOnStartupCheckBox + Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts. + + + + updateCompatibilityButton + Update Compatibility Database:\nImmediately update the compatibility database. + Never @@ -1329,6 +1404,11 @@ Serial Série + + + Compatibility + Compatibility + Region @@ -1364,6 +1444,51 @@ Never Played Jamais joué + + + h + h + + + + m + m + + + + s + s + + + + Compatibility is untested + Compatibility is untested + + + + Game does not initialize properly / crashes the emulator + Game does not initialize properly / crashes the emulator + + + + Game boots, but only displays a blank screen + Game boots, but only displays a blank screen + + + + Game displays an image but does not go past the menu + Game displays an image but does not go past the menu + + + + Game has game-breaking glitches or unplayable performance + Game has game-breaking glitches or unplayable performance + + + + Game can be completed with playable performance and no major glitches + Game can be completed with playable performance and no major glitches + CheckUpdate @@ -1493,4 +1618,32 @@ Échec de la création du fichier de script de mise à jour + + GameListUtils + + + B + B + + + + KB + KB + + + + MB + MB + + + + GB + GB + + + + TB + TB + + \ No newline at end of file diff --git a/src/qt_gui/translations/hu_HU.ts b/src/qt_gui/translations/hu_HU.ts index 937e3f188..bc337f2cd 100644 --- a/src/qt_gui/translations/hu_HU.ts +++ b/src/qt_gui/translations/hu_HU.ts @@ -175,6 +175,26 @@ Delete DLC DLC-k törlése + + + Compatibility... + Compatibility... + + + + Update database + Update database + + + + View report + View report + + + + Submit a report + Submit a report + Shortcut creation @@ -182,8 +202,8 @@ - Shortcut created successfully!\n %1 - Parancsikon sikeresen létrehozva!\n %1 + Shortcut created successfully! + Parancsikon sikeresen létrehozva! @@ -192,8 +212,8 @@ - Error creating shortcut!\n %1 - Hiba a parancsikon létrehozásával!\n %1 + Error creating shortcut! + Hiba a parancsikon létrehozásával! @@ -552,6 +572,11 @@ Hide Cursor Idle Timeout Kurzor inaktivitási időtúllépés + + + s + s + Controller @@ -672,16 +697,46 @@ GUI Settings GUI Beállítások + + + Disable Trophy Pop-ups + Disable Trophy Pop-ups + Play title music Címzene lejátszása + + + Update Compatibility Database On Startup + Update Compatibility Database On Startup + + + + Game Compatibility + Game Compatibility + + + + Display Compatibility Data + Display Compatibility Data + + + + Update Compatibility Database + Update Compatibility Database + Volume Hangerő + + + Audio Backend + Audio Backend + MainWindow @@ -1201,6 +1256,11 @@ GUIgroupBox Játék címzene lejátszása:\nHa a játék támogatja, engedélyezze egy speciális zene lejátszását, amikor a játékot kiválasztja a GUI-ban. + + + disableTrophycheckBox + 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). + hideCursorGroupBox @@ -1216,6 +1276,21 @@ backButtonBehaviorGroupBox Vissza gomb viselkedés:\nBeállítja a vezérlő vissza gombját, hogy utánozza a PS4 érintőpadján megadott pozíció megérintését. + + + enableCompatibilityCheckBox + Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information. + + + + checkCompatibilityOnStartupCheckBox + Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts. + + + + updateCompatibilityButton + Update Compatibility Database:\nImmediately update the compatibility database. + Never @@ -1329,6 +1404,11 @@ Serial Sorozatszám + + + Compatibility + Compatibility + Region @@ -1364,6 +1444,51 @@ Never Played Never Played + + + h + h + + + + m + m + + + + s + s + + + + Compatibility is untested + Compatibility is untested + + + + Game does not initialize properly / crashes the emulator + Game does not initialize properly / crashes the emulator + + + + Game boots, but only displays a blank screen + Game boots, but only displays a blank screen + + + + Game displays an image but does not go past the menu + Game displays an image but does not go past the menu + + + + Game has game-breaking glitches or unplayable performance + Game has game-breaking glitches or unplayable performance + + + + Game can be completed with playable performance and no major glitches + Game can be completed with playable performance and no major glitches + CheckUpdate @@ -1493,4 +1618,32 @@ A frissítési szkript fájl létrehozása nem sikerült - + + GameListUtils + + + B + B + + + + KB + KB + + + + MB + MB + + + + GB + GB + + + + TB + TB + + + \ No newline at end of file diff --git a/src/qt_gui/translations/id.ts b/src/qt_gui/translations/id.ts index 80873daa9..7a0bf5d05 100644 --- a/src/qt_gui/translations/id.ts +++ b/src/qt_gui/translations/id.ts @@ -175,6 +175,26 @@ Delete DLC Delete DLC + + + Compatibility... + Compatibility... + + + + Update database + Update database + + + + View report + View report + + + + Submit a report + Submit a report + Shortcut creation @@ -182,8 +202,8 @@ - Shortcut created successfully!\n %1 - Shortcut created successfully!\n %1 + Shortcut created successfully! + Shortcut created successfully! @@ -192,8 +212,8 @@ - Error creating shortcut!\n %1 - Error creating shortcut!\n %1 + Error creating shortcut! + Error creating shortcut! @@ -552,6 +572,11 @@ Hide Cursor Idle Timeout Batas waktu sembunyikan kursor tidak aktif + + + s + s + Controller @@ -672,16 +697,46 @@ GUI Settings Pengaturan GUI + + + Disable Trophy Pop-ups + Disable Trophy Pop-ups + Play title music Putar musik judul + + + Update Compatibility Database On Startup + Update Compatibility Database On Startup + + + + Game Compatibility + Game Compatibility + + + + Display Compatibility Data + Display Compatibility Data + + + + Update Compatibility Database + Update Compatibility Database + Volume Volume + + + Audio Backend + Audio Backend + MainWindow @@ -1201,6 +1256,11 @@ GUIgroupBox Putar Musik Judul Permainan:\nJika permainan mendukungnya, aktifkan pemutaran musik khusus saat memilih permainan di GUI. + + + disableTrophycheckBox + 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). + hideCursorGroupBox @@ -1216,6 +1276,21 @@ backButtonBehaviorGroupBox Perilaku Tombol Kembali:\nMengatur tombol kembali pada pengontrol untuk meniru ketukan di posisi yang ditentukan di touchpad PS4. + + + enableCompatibilityCheckBox + Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information. + + + + checkCompatibilityOnStartupCheckBox + Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts. + + + + updateCompatibilityButton + Update Compatibility Database:\nImmediately update the compatibility database. + Never @@ -1329,6 +1404,11 @@ Serial Serial + + + Compatibility + Compatibility + Region @@ -1364,6 +1444,51 @@ Never Played Never Played + + + h + h + + + + m + m + + + + s + s + + + + Compatibility is untested + Compatibility is untested + + + + Game does not initialize properly / crashes the emulator + Game does not initialize properly / crashes the emulator + + + + Game boots, but only displays a blank screen + Game boots, but only displays a blank screen + + + + Game displays an image but does not go past the menu + Game displays an image but does not go past the menu + + + + Game has game-breaking glitches or unplayable performance + Game has game-breaking glitches or unplayable performance + + + + Game can be completed with playable performance and no major glitches + Game can be completed with playable performance and no major glitches + CheckUpdate @@ -1493,4 +1618,32 @@ Gagal membuat file skrip pembaruan + + GameListUtils + + + B + B + + + + KB + KB + + + + MB + MB + + + + GB + GB + + + + TB + TB + + \ No newline at end of file diff --git a/src/qt_gui/translations/it.ts b/src/qt_gui/translations/it.ts index 9094a7ed5..1391fbc55 100644 --- a/src/qt_gui/translations/it.ts +++ b/src/qt_gui/translations/it.ts @@ -175,6 +175,26 @@ Delete DLC Elimina DLC + + + Compatibility... + Compatibility... + + + + Update database + Update database + + + + View report + View report + + + + Submit a report + Submit a report + Shortcut creation @@ -182,8 +202,8 @@ - Shortcut created successfully!\n %1 - Scorciatoia creata con successo!\n %1 + Shortcut created successfully! + Scorciatoia creata con successo! @@ -192,8 +212,8 @@ - Error creating shortcut!\n %1 - Errore nella creazione della scorciatoia!\n %1 + Error creating shortcut! + Errore nella creazione della scorciatoia! @@ -208,7 +228,7 @@ requiresEnableSeparateUpdateFolder_MSG - This feature requires the 'Enable Separate Update Folder' config option to work. If you want to use this feature, please enable it. + Questa feature richiede che venga attivata l'opzione "Abilita Cartella Aggiornamenti Separata" per poter funzionare, per favore abilitala. @@ -495,7 +515,7 @@ Enable Separate Update Folder - Abilità Cartella Aggiornamenti Separata + Abilita Cartella Aggiornamenti Separata @@ -552,6 +572,11 @@ Hide Cursor Idle Timeout Timeout inattività per nascondere il cursore + + + s + s + Controller @@ -672,16 +697,46 @@ GUI Settings Impostazioni GUI + + + Disable Trophy Pop-ups + Disabilita Notifica Trofei + Play title music Riproduci musica del titolo + + + Update Compatibility Database On Startup + Aggiorna Database Compatibilità all'Avvio + + + + Game Compatibility + Compatibilità Gioco + + + + Display Compatibility Data + Mostra Dati Compatibilità + + + + Update Compatibility Database + Aggiorna Database Compatibilità + Volume Volume + + + Audio Backend + Audio Backend + MainWindow @@ -1201,6 +1256,11 @@ GUIgroupBox Riproduci Musica del Titolo:\nSe un gioco lo supporta, attiva la riproduzione di musica speciale quando selezioni il gioco nell'interfaccia grafica. + + + disableTrophycheckBox + 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). + hideCursorGroupBox @@ -1216,6 +1276,21 @@ backButtonBehaviorGroupBox Comportamento del pulsante Indietro:\nImposta il pulsante Indietro del controller per emulare il tocco sulla posizione specificata sul touchpad PS4. + + + enableCompatibilityCheckBox + Mostra Dati Compatibilità:\nMostra informazioni sulla compatibilità del gioco nella visualizzazione lista. Abilita "Aggiorna Compatiblità all'Avvio" per ottenere informazioni aggiornate. + + + + checkCompatibilityOnStartupCheckBox + Aggiorna Compatibilità all'Avvio:\nAggiorna automaticamente il database della compatibilità quando si avvia shadps4. + + + + updateCompatibilityButton + Aggiorna Database Compatibilità:\nAggiorna immediatamente il database di compatibilità. + Never @@ -1329,6 +1404,11 @@ Serial Seriale + + + Compatibility + Compatibilità + Region @@ -1362,7 +1442,52 @@ Never Played - Never Played + Mai Giocato + + + + h + h + + + + m + m + + + + s + s + + + + Compatibility is untested + Nessuna informazione sulla compatibilità + + + + Game does not initialize properly / crashes the emulator + Il gioco non si avvia in modo corretto / forza chiusura dell'emulatore + + + + Game boots, but only displays a blank screen + Il gioco si avvia, ma mostra solo una schermata nera + + + + Game displays an image but does not go past the menu + Il gioco mostra immagini ma non va oltre il menu + + + + Game has game-breaking glitches or unplayable performance + Il gioco ha problemi gravi di emulazione oppure framerate troppo basso + + + + Game can be completed with playable performance and no major glitches + Il gioco può essere completato con buone prestazioni e senza problemi gravi @@ -1493,4 +1618,32 @@ Impossibile creare il file di script di aggiornamento - + + GameListUtils + + + B + B + + + + KB + KB + + + + MB + MB + + + + GB + GB + + + + TB + TB + + + \ No newline at end of file diff --git a/src/qt_gui/translations/ja_JP.ts b/src/qt_gui/translations/ja_JP.ts index ad1f383fe..58f213e03 100644 --- a/src/qt_gui/translations/ja_JP.ts +++ b/src/qt_gui/translations/ja_JP.ts @@ -175,6 +175,26 @@ Delete DLC Delete DLC + + + Compatibility... + Compatibility... + + + + Update database + Update database + + + + View report + View report + + + + Submit a report + Submit a report + Shortcut creation @@ -182,8 +202,8 @@ - Shortcut created successfully!\n %1 - ショートカットが正常に作成されました!\n %1 + Shortcut created successfully! + ショートカットが正常に作成されました! @@ -192,8 +212,8 @@ - Error creating shortcut!\n %1 - ショートカットの作成に失敗しました!\n %1 + Error creating shortcut! + ショートカットの作成に失敗しました! @@ -552,6 +572,11 @@ Hide Cursor Idle Timeout カーソル非アクティブタイムアウト + + + s + s + Controller @@ -672,16 +697,46 @@ GUI Settings GUI設定 + + + Disable Trophy Pop-ups + Disable Trophy Pop-ups + Play title music タイトル音楽を再生する + + + Update Compatibility Database On Startup + Update Compatibility Database On Startup + + + + Game Compatibility + Game Compatibility + + + + Display Compatibility Data + Display Compatibility Data + + + + Update Compatibility Database + Update Compatibility Database + Volume 音量 + + + Audio Backend + Audio Backend + MainWindow @@ -1201,6 +1256,11 @@ GUIgroupBox タイトルミュージックを再生:\nゲームがそれをサポートしている場合、GUIでゲームを選択したときに特別な音楽を再生することを有効にします。 + + + disableTrophycheckBox + 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). + hideCursorGroupBox @@ -1216,6 +1276,21 @@ backButtonBehaviorGroupBox 戻るボタンの動作:\nコントローラーの戻るボタンを、PS4のタッチパッドの指定された位置をタッチするように設定します。 + + + enableCompatibilityCheckBox + Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information. + + + + checkCompatibilityOnStartupCheckBox + Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts. + + + + updateCompatibilityButton + Update Compatibility Database:\nImmediately update the compatibility database. + Never @@ -1329,6 +1404,11 @@ Serial シリアル + + + Compatibility + Compatibility + Region @@ -1364,6 +1444,51 @@ Never Played Never Played + + + h + h + + + + m + m + + + + s + s + + + + Compatibility is untested + Compatibility is untested + + + + Game does not initialize properly / crashes the emulator + Game does not initialize properly / crashes the emulator + + + + Game boots, but only displays a blank screen + Game boots, but only displays a blank screen + + + + Game displays an image but does not go past the menu + Game displays an image but does not go past the menu + + + + Game has game-breaking glitches or unplayable performance + Game has game-breaking glitches or unplayable performance + + + + Game can be completed with playable performance and no major glitches + Game can be completed with playable performance and no major glitches + CheckUpdate @@ -1493,4 +1618,32 @@ アップデートスクリプトファイルの作成に失敗しました + + GameListUtils + + + B + B + + + + KB + KB + + + + MB + MB + + + + GB + GB + + + + TB + TB + + \ No newline at end of file diff --git a/src/qt_gui/translations/ko_KR.ts b/src/qt_gui/translations/ko_KR.ts index a528db295..75a1b53cf 100644 --- a/src/qt_gui/translations/ko_KR.ts +++ b/src/qt_gui/translations/ko_KR.ts @@ -175,6 +175,26 @@ Delete DLC Delete DLC + + + Compatibility... + Compatibility... + + + + Update database + Update database + + + + View report + View report + + + + Submit a report + Submit a report + Shortcut creation @@ -182,8 +202,8 @@ - Shortcut created successfully!\n %1 - Shortcut created successfully!\n %1 + Shortcut created successfully! + Shortcut created successfully! @@ -192,8 +212,8 @@ - Error creating shortcut!\n %1 - Error creating shortcut!\n %1 + Error creating shortcut! + Error creating shortcut! @@ -552,6 +572,11 @@ Hide Cursor Idle Timeout Hide Cursor Idle Timeout + + + s + s + Controller @@ -672,16 +697,46 @@ GUI Settings GUI Settings + + + Disable Trophy Pop-ups + Disable Trophy Pop-ups + Play title music Play title music + + + Update Compatibility Database On Startup + Update Compatibility Database On Startup + + + + Game Compatibility + Game Compatibility + + + + Display Compatibility Data + Display Compatibility Data + + + + Update Compatibility Database + Update Compatibility Database + Volume 음량 + + + Audio Backend + Audio Backend + MainWindow @@ -1201,6 +1256,11 @@ GUIgroupBox Play Title Music:\nIf a game supports it, enable playing special music when selecting the game in the GUI. + + + disableTrophycheckBox + 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). + hideCursorGroupBox @@ -1216,6 +1276,21 @@ backButtonBehaviorGroupBox Back Button Behavior:\nSets the controller's back button to emulate tapping the specified position on the PS4 touchpad. + + + enableCompatibilityCheckBox + Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information. + + + + checkCompatibilityOnStartupCheckBox + Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts. + + + + updateCompatibilityButton + Update Compatibility Database:\nImmediately update the compatibility database. + Never @@ -1329,6 +1404,11 @@ Serial Serial + + + Compatibility + Compatibility + Region @@ -1364,6 +1444,51 @@ Never Played Never Played + + + h + h + + + + m + m + + + + s + s + + + + Compatibility is untested + Compatibility is untested + + + + Game does not initialize properly / crashes the emulator + Game does not initialize properly / crashes the emulator + + + + Game boots, but only displays a blank screen + Game boots, but only displays a blank screen + + + + Game displays an image but does not go past the menu + Game displays an image but does not go past the menu + + + + Game has game-breaking glitches or unplayable performance + Game has game-breaking glitches or unplayable performance + + + + Game can be completed with playable performance and no major glitches + Game can be completed with playable performance and no major glitches + CheckUpdate @@ -1493,4 +1618,32 @@ Failed to create the update script file + + GameListUtils + + + B + B + + + + KB + KB + + + + MB + MB + + + + GB + GB + + + + TB + TB + + \ No newline at end of file diff --git a/src/qt_gui/translations/lt_LT.ts b/src/qt_gui/translations/lt_LT.ts index 4a2820399..092521fdf 100644 --- a/src/qt_gui/translations/lt_LT.ts +++ b/src/qt_gui/translations/lt_LT.ts @@ -175,6 +175,26 @@ Delete DLC Delete DLC + + + Compatibility... + Compatibility... + + + + Update database + Update database + + + + View report + View report + + + + Submit a report + Submit a report + Shortcut creation @@ -182,8 +202,8 @@ - Shortcut created successfully!\n %1 - Shortcut created successfully!\n %1 + Shortcut created successfully! + Shortcut created successfully! @@ -192,8 +212,8 @@ - Error creating shortcut!\n %1 - Error creating shortcut!\n %1 + Error creating shortcut! + Error creating shortcut! @@ -552,6 +572,11 @@ Hide Cursor Idle Timeout Žymeklio paslėpimo neveikimo laikas + + + s + s + Controller @@ -672,16 +697,46 @@ GUI Settings GUI Nustatymai + + + Disable Trophy Pop-ups + Disable Trophy Pop-ups + Play title music Groti antraštės muziką + + + Update Compatibility Database On Startup + Update Compatibility Database On Startup + + + + Game Compatibility + Game Compatibility + + + + Display Compatibility Data + Display Compatibility Data + + + + Update Compatibility Database + Update Compatibility Database + Volume Garsumas + + + Audio Backend + Audio Backend + MainWindow @@ -1201,6 +1256,11 @@ GUIgroupBox Groti antraščių muziką:\nJei žaidimas tai palaiko, įjungia specialios muzikos grojimą, kai pasirinkite žaidimą GUI. + + + disableTrophycheckBox + 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). + hideCursorGroupBox @@ -1216,6 +1276,21 @@ backButtonBehaviorGroupBox Atgal mygtuko elgesys:\nNustato valdiklio atgal mygtuką imituoti paspaudimą nurodytoje vietoje PS4 jutiklinėje plokštėje. + + + enableCompatibilityCheckBox + Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information. + + + + checkCompatibilityOnStartupCheckBox + Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts. + + + + updateCompatibilityButton + Update Compatibility Database:\nImmediately update the compatibility database. + Never @@ -1329,6 +1404,11 @@ Serial Serijinis numeris + + + Compatibility + Compatibility + Region @@ -1364,6 +1444,51 @@ Never Played Never Played + + + h + h + + + + m + m + + + + s + s + + + + Compatibility is untested + Compatibility is untested + + + + Game does not initialize properly / crashes the emulator + Game does not initialize properly / crashes the emulator + + + + Game boots, but only displays a blank screen + Game boots, but only displays a blank screen + + + + Game displays an image but does not go past the menu + Game displays an image but does not go past the menu + + + + Game has game-breaking glitches or unplayable performance + Game has game-breaking glitches or unplayable performance + + + + Game can be completed with playable performance and no major glitches + Game can be completed with playable performance and no major glitches + CheckUpdate @@ -1493,4 +1618,32 @@ Nepavyko sukurti atnaujinimo scenarijaus failo + + GameListUtils + + + B + B + + + + KB + KB + + + + MB + MB + + + + GB + GB + + + + TB + TB + + \ No newline at end of file diff --git a/src/qt_gui/translations/nb.ts b/src/qt_gui/translations/nb.ts index 028646740..cc41573db 100644 --- a/src/qt_gui/translations/nb.ts +++ b/src/qt_gui/translations/nb.ts @@ -108,32 +108,32 @@ SFO Viewer - SFO Viser + SFO viser Trophy Viewer - Trofé Viser + Trofé viser Open Folder... - Åpne Mappen... + Åpne mappen... Open Game Folder - Åpne Spillmappen + Åpne spillmappen Open Save Data Folder - Åpne Lagrede Data-mappen + Åpne lagrede datamappen Open Log Folder - Åpne Loggmappen + Åpne loggmappen @@ -143,17 +143,17 @@ Copy Name - Kopier Navn + Kopier navn Copy Serial - Kopier Serienummer + Kopier serienummer Copy All - Kopier Alle + Kopier alle @@ -163,18 +163,38 @@ Delete Game - Slett Spill + Slett spill Delete Update - Slett Oppdatering + Slett oppdatering Delete DLC Slett DLC + + + Compatibility... + Compatibility... + + + + Update database + Update database + + + + View report + View report + + + + Submit a report + Submit a report + Shortcut creation @@ -182,8 +202,8 @@ - Shortcut created successfully!\n %1 - Snarvei opprettet!\n %1 + Shortcut created successfully! + Snarvei opprettet! @@ -192,8 +212,8 @@ - Error creating shortcut!\n %1 - Feil ved opprettelse av snarvei!\n %1 + Error creating shortcut! + Feil ved opprettelse av snarvei! @@ -251,12 +271,12 @@ Install Packages (PKG) - Installer Pakker (PKG) + Installer pakker (PKG) Boot Game - Start Spill + Start spill @@ -281,7 +301,7 @@ Recent Games - Nylige Spill + Nylige spill @@ -301,12 +321,12 @@ Show Game List - Vis Spill-listen + Vis spill-listen Game List Refresh - Oppdater Spill-listen + Oppdater spill-listen @@ -351,17 +371,17 @@ Download Cheats/Patches - Last ned Juks /Programrettelse + Last ned juks/programrettelse Dump Game List - Dump Spill-liste + Dump spill-liste PKG Viewer - PKG Viser + PKG viser @@ -381,12 +401,12 @@ Game List Icons - Spill-liste Ikoner + Spill-liste ikoner Game List Mode - Spill-liste Modus + Spill-liste modus @@ -444,7 +464,7 @@ Open Folder - Åpne Mappe + Åpne mappe @@ -452,7 +472,7 @@ Trophy Viewer - Trofé Viser + Trofé viser @@ -490,17 +510,17 @@ Enable Fullscreen - Aktiver Fullskjerm + Aktiver fullskjerm Enable Separate Update Folder - Aktiver Seperat Oppdateringsmappe + Aktiver seperat oppdateringsmappe Show Splash - Vis Velkomstbilde + Vis velkomstbilde @@ -525,12 +545,12 @@ Log Type - Log Type + Logg type Log Filter - Log Filter + Logg filter @@ -552,6 +572,11 @@ Hide Cursor Idle Timeout Skjul musepeker ved inaktivitet + + + s + s + Controller @@ -560,7 +585,7 @@ Back Button Behavior - Tilbakeknapp Atferd + Tilbakeknapp atferd @@ -585,7 +610,7 @@ Vblank Divider - Vblank Skillelinje + Vblank skillelinje @@ -595,7 +620,7 @@ Enable Shaders Dumping - Aktiver Skyggelegger Dumping + Aktiver dumping av skyggelegger @@ -630,22 +655,22 @@ Enable Debug Dumping - Aktiver Feilretting Dumping + Aktiver dumping av feilretting Enable Vulkan Validation Layers - Aktiver Vulkan Valideringslag + Aktiver Vulkan valideringslag Enable Vulkan Synchronization Validation - Aktiver Vulkan Synkroniseringslag + Aktiver Vulkan synkroniseringslag Enable RenderDoc Debugging - Aktiver RenderDoc Feilretting + Aktiver RenderDoc feilretting @@ -670,18 +695,48 @@ GUI Settings - GUI-Innstillinger + GUI-innstillinger + + + + Disable Trophy Pop-ups + Deaktiver trofé hurtigmeny Play title music Spill tittelmusikk + + + Update Compatibility Database On Startup + Oppdater kompatibilitets-database ved oppstart + + + + Game Compatibility + Spill kompatibilitet + + + + Display Compatibility Data + Vis kompatibilitets-data + + + + Update Compatibility Database + Oppdater kompatibilitets-database + Volume Volum + + + Audio Backend + Audio Backend + MainWindow @@ -703,7 +758,7 @@ Download Patches For All Games - Last ned oppdateringer for alle spill + Last ned programrettelser for alle spill @@ -753,7 +808,7 @@ PKG Extraction - PKG-ekstraksjon + PKG-utpakking @@ -763,7 +818,7 @@ PKG and Game versions match: - PKG- og spillversjoner stemmer overens: + PKG og spillversjoner stemmer overens: @@ -788,7 +843,7 @@ DLC Installation - DLC-installasjon + DLC installasjon @@ -808,7 +863,7 @@ PKG is a patch, please install the game first! - PKG er en oppdatering, vennligst installer spillet først! + PKG er en programrettelse, vennligst installer spillet først! @@ -846,7 +901,7 @@ defaultTextEdit_MSG - Juks/programrettelse er eksperimentelle.\nBruk med forsiktighet.\n\nLast ned juks individuelt ved å velge pakkebrønn og klikke på nedlastingsknappen.\nPå fanen programrettelse kan du laste ned alle programrettelser samtidig, velge hvilke du ønsker å bruke, og lagre valget ditt.\n\nSiden vi ikke utvikler Juksene/Programrettelsene,\nvær vennlig å rapportere problemer til jukse/programrettelse utvikleren.\n\nHar du laget en ny juks? Besøk:\nhttps://github.com/shadps4-emu/ps4_cheats + Juks/programrettelse er eksperimentelle.\nBruk med forsiktighet.\n\nLast ned juks individuelt ved å velge pakkebrønn og klikke på nedlastingsknappen.\nPå fanen programrettelse kan du laste ned alle programrettelser samtidig, velge hvilke du ønsker å bruke, og lagre valget ditt.\n\nSiden vi ikke utvikler Juks/Programrettelse,\nvær vennlig å rapportere problemer til juks/programrettelse utvikleren.\n\nHar du laget en ny juks? Besøk:\nhttps://github.com/shadps4-emu/ps4_cheats @@ -896,7 +951,7 @@ You can delete the cheats you don't want after downloading them. - Du kan slette juksene du ikke ønsker etter å ha lastet dem ned. + Du kan slette juks du ikke ønsker etter å ha lastet dem ned. @@ -911,7 +966,7 @@ Download Patches - Last ned programrettelse + Last ned programrettelser @@ -921,7 +976,7 @@ Cheats - Jukser + Juks @@ -976,7 +1031,7 @@ Invalid Source - Ugyldig Kilde + Ugyldig kilde @@ -986,7 +1041,7 @@ File Exists - Filen Eksisterer + Filen eksisterer @@ -1006,7 +1061,7 @@ Cheats Not Found - Fant ikke juksene + Fant ikke juks @@ -1016,12 +1071,12 @@ Cheats Downloaded Successfully - Juksene ble lastet ned + Juks ble lastet ned CheatsDownloadedSuccessfully_MSG - Du har lastet ned jukser for denne versjonen av spillet fra den valgte pakkebrønnen. Du kan prøve å laste ned fra en annen pakkebrønn, hvis det er tilgjengelig, vil det også være mulig å bruke det ved å velge filen fra listen. + Du har lastet ned juks for denne versjonen av spillet fra den valgte pakkebrønnen. Du kan prøve å laste ned fra en annen pakkebrønn, hvis det er tilgjengelig, vil det også være mulig å bruke det ved å velge filen fra listen. @@ -1041,7 +1096,7 @@ DownloadComplete_MSG - Programrettelser ble lastet ned! Alle programrettelsene tilgjengelige for alle spill har blitt lastet ned, det er ikke nødvendig å laste dem ned individuelt for hvert spill som skjer med jukser. Hvis programrettelsen ikke vises, kan det hende at den ikke finnes for den spesifikke serienummeret og versjonen av spillet. + Programrettelser ble lastet ned! Alle programrettelsene tilgjengelige for alle spill har blitt lastet ned, det er ikke nødvendig å laste dem ned individuelt for hvert spill som skjer med juks. Hvis programrettelsen ikke vises, kan det hende at den ikke finnes for den spesifikke serienummeret og versjonen av spillet. @@ -1111,7 +1166,7 @@ Can't apply cheats before the game is started - Kan ikke bruke juksene før spillet er startet. + Kan ikke bruke juks før spillet er startet. @@ -1164,7 +1219,7 @@ showSplashCheckBox - Vis Velkomstbilde:\nViser spillets velkomstbilde (et spesialbilde) når spillet starter. + Vis velkomstbilde:\nViser spillets velkomstbilde (et spesialbilde) når spillet starter. @@ -1184,12 +1239,12 @@ logTypeGroupBox - Logtype:\nAngir om loggvinduets utdata skal synkroniseres for ytelse. Kan ha negative effekter for etterligneren. + Logg type:\nAngir om loggvinduets utdata skal synkroniseres for ytelse. Kan ha negative effekter for etterligneren. logFilter - Loggfilter:\nFiltrerer loggen for å kun skrive ut spesifikk informasjon.\nEksempler: "Core:Trace" "Lib.Pad:Debug Common.Filesystem:Error" "*:Critical" Nivåer: Trace, Debug, Info, Warning, Error, Critical - i denne rekkefølgen, et spesifikt nivå demper alle tidligere nivåer i listen og logger alle nivåer etter det. + Logg filter:\nFiltrerer loggen for å kun skrive ut spesifikk informasjon.\nEksempler: "Core:Trace" "Lib.Pad:Debug Common.Filesystem:Error" "*:Critical" Nivåer: Trace, Debug, Info, Warning, Error, Critical - i denne rekkefølgen, et spesifikt nivå demper alle tidligere nivåer i listen og logger alle nivåer etter det. @@ -1201,6 +1256,11 @@ GUIgroupBox Spille tittelmusikk:\nHvis et spill støtter det, så aktiveres det spesiell musikk når du velger spillet i menyen. + + + disableTrophycheckBox + Deaktiver trofé hurtigmeny:\nDeaktiver trofévarsler i spillet. Trofé-fremgang kan fortsatt ved help av troféviseren (høyreklikk på spillet i hovedvinduet). + hideCursorGroupBox @@ -1216,6 +1276,21 @@ backButtonBehaviorGroupBox Atferd for tilbaketasten:\nSetter tilbaketasten på kontrolleren til å imitere et trykk på den angitte posisjonen på PS4s berøringsplate. + + + enableCompatibilityCheckBox + Vis kompatibilitets-data:\nViser informasjon om spillkompatibilitet i tabellvisning. Aktiver "Oppdater kompatibilitets-data ved oppstart" for oppdatert informasjon. + + + + checkCompatibilityOnStartupCheckBox + Oppdater kompatibilitets-data ved oppstart:\nOppdaterer kompatibilitets-databasen automatisk når shadPS4 starter. + + + + updateCompatibilityButton + Oppdater kompatibilitets-database:\nOppdater kompatibilitets-databasen nå. + Never @@ -1254,7 +1329,7 @@ graphicsAdapterGroupBox - Grafikkenhet:\nI systemer med flere GPU-er, velg GPU-en etterligneren skal bruke fra rullegardinlisten,\neller velg "Auto Select" for å bestemme den automatisk. + Grafikkenhet:\nI systemer med flere GPU-er, velg GPU-en etterligneren skal bruke fra rullegardinlisten,\neller velg "Auto Select" for å velge automatisk. @@ -1264,12 +1339,12 @@ heightDivider - Vblank Skillelinje:\nBildehastigheten som etterligneren oppdaterer ved, multipliseres med dette tallet. Endring av dette kan ha negative effekter, som å øke hastigheten av spillet, eller ødelegge kritisk spillfunksjonalitet som ikke forventer at dette endres! + Vblank skillelinje:\nBildehastigheten som etterligneren oppdaterer ved, multipliseres med dette tallet. Endring av dette kan ha negative effekter, som å øke hastigheten av spillet, eller ødelegge kritisk spillfunksjonalitet som ikke forventer at dette endres! dumpShadersCheckBox - Aktiver skyggelegger-dumping:\nFor teknisk feilsøking lagrer skyggeleggene fra spillet i en mappe mens de gjengis. + Aktiver dumping av skyggelegger:\nFor teknisk feilsøking lagrer skyggeleggerne fra spillet i en mappe mens de gjengis. @@ -1329,6 +1404,11 @@ Serial Serienummer + + + Compatibility + Kompatibilitet + Region @@ -1362,7 +1442,52 @@ Never Played - Never Played + Aldri spilt + + + + h + h + + + + m + m + + + + s + s + + + + Compatibility is untested + kompatibilitet er utestet + + + + Game does not initialize properly / crashes the emulator + Spillet initialiseres ikke riktig / krasjer etterligneren + + + + Game boots, but only displays a blank screen + Spillet starter, men viser bare en tom skjerm + + + + Game displays an image but does not go past the menu + Spillet viser et bilde, men går ikke forbi menyen + + + + Game has game-breaking glitches or unplayable performance + Spillet har spillbrytende feil eller uspillbar ytelse + + + + Game can be completed with playable performance and no major glitches + Spillet kan fullføres med spillbar ytelse og ingen store feil @@ -1370,7 +1495,7 @@ Auto Updater - Automatisk oppdaterering + Automatisk oppdatering @@ -1385,7 +1510,7 @@ Failed to parse update information. - Kunne ikke analysere oppdateringsinformasjonen. + Kunne ikke analysere oppdaterings-informasjonen. @@ -1465,7 +1590,7 @@ Network error occurred while trying to access the URL - Nettverksfeil oppstod mens du prøvde å få tilgang til URL + Nettverksfeil oppstod mens vi prøvde å få tilgang til URL @@ -1493,4 +1618,32 @@ Kunne ikke opprette oppdateringsskriptfilen - + + GameListUtils + + + B + B + + + + KB + KB + + + + MB + MB + + + + GB + GB + + + + TB + TB + + + \ No newline at end of file diff --git a/src/qt_gui/translations/nl.ts b/src/qt_gui/translations/nl.ts index b66cb94e4..5cd4a4224 100644 --- a/src/qt_gui/translations/nl.ts +++ b/src/qt_gui/translations/nl.ts @@ -175,6 +175,26 @@ Delete DLC Delete DLC + + + Compatibility... + Compatibility... + + + + Update database + Update database + + + + View report + View report + + + + Submit a report + Submit a report + Shortcut creation @@ -182,8 +202,8 @@ - Shortcut created successfully!\n %1 - Shortcut created successfully!\n %1 + Shortcut created successfully! + Shortcut created successfully! @@ -192,8 +212,8 @@ - Error creating shortcut!\n %1 - Error creating shortcut!\n %1 + Error creating shortcut! + Error creating shortcut! @@ -552,6 +572,11 @@ Hide Cursor Idle Timeout Inactiviteit timeout voor het verbergen van de cursor + + + s + s + Controller @@ -672,16 +697,46 @@ GUI Settings GUI-Instellingen + + + Disable Trophy Pop-ups + Disable Trophy Pop-ups + Play title music Titelmuziek afspelen + + + Update Compatibility Database On Startup + Update Compatibility Database On Startup + + + + Game Compatibility + Game Compatibility + + + + Display Compatibility Data + Display Compatibility Data + + + + Update Compatibility Database + Update Compatibility Database + Volume Volume + + + Audio Backend + Audio Backend + MainWindow @@ -1201,6 +1256,11 @@ GUIgroupBox Speel titelsong:\nAls een game dit ondersteunt, wordt speciale muziek afgespeeld wanneer je het spel in de GUI selecteert. + + + disableTrophycheckBox + 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). + hideCursorGroupBox @@ -1216,6 +1276,21 @@ backButtonBehaviorGroupBox Gedrag van de terugknop:\nStelt de terugknop van de controller in om een aanraking op de opgegeven positie op de PS4-touchpad na te bootsen. + + + enableCompatibilityCheckBox + Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information. + + + + checkCompatibilityOnStartupCheckBox + Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts. + + + + updateCompatibilityButton + Update Compatibility Database:\nImmediately update the compatibility database. + Never @@ -1329,6 +1404,11 @@ Serial Serienummer + + + Compatibility + Compatibility + Region @@ -1364,6 +1444,51 @@ Never Played Never Played + + + h + h + + + + m + m + + + + s + s + + + + Compatibility is untested + Compatibility is untested + + + + Game does not initialize properly / crashes the emulator + Game does not initialize properly / crashes the emulator + + + + Game boots, but only displays a blank screen + Game boots, but only displays a blank screen + + + + Game displays an image but does not go past the menu + Game displays an image but does not go past the menu + + + + Game has game-breaking glitches or unplayable performance + Game has game-breaking glitches or unplayable performance + + + + Game can be completed with playable performance and no major glitches + Game can be completed with playable performance and no major glitches + CheckUpdate @@ -1493,4 +1618,32 @@ Kon het update-scriptbestand niet maken + + GameListUtils + + + B + B + + + + KB + KB + + + + MB + MB + + + + GB + GB + + + + TB + TB + + \ No newline at end of file diff --git a/src/qt_gui/translations/pl_PL.ts b/src/qt_gui/translations/pl_PL.ts index 8236cf720..b85393bb0 100644 --- a/src/qt_gui/translations/pl_PL.ts +++ b/src/qt_gui/translations/pl_PL.ts @@ -175,6 +175,26 @@ Delete DLC Delete DLC + + + Compatibility... + Compatibility... + + + + Update database + Update database + + + + View report + View report + + + + Submit a report + Submit a report + Shortcut creation @@ -182,8 +202,8 @@ - Shortcut created successfully!\n %1 - Utworzenie skrótu zakończone pomyślnie!\n %1 + Shortcut created successfully! + Utworzenie skrótu zakończone pomyślnie! @@ -192,8 +212,8 @@ - Error creating shortcut!\n %1 - Utworzenie skrótu zakończone niepowodzeniem!\n %1 + Error creating shortcut! + Utworzenie skrótu zakończone niepowodzeniem! @@ -552,6 +572,11 @@ Hide Cursor Idle Timeout Czas oczekiwania na ukrycie kursora przy bezczynności + + + s + s + Controller @@ -672,16 +697,46 @@ GUI Settings Ustawienia Interfejsu + + + Disable Trophy Pop-ups + Disable Trophy Pop-ups + Play title music Odtwórz muzykę tytułową + + + Update Compatibility Database On Startup + Update Compatibility Database On Startup + + + + Game Compatibility + Game Compatibility + + + + Display Compatibility Data + Display Compatibility Data + + + + Update Compatibility Database + Update Compatibility Database + Volume Głośność + + + Audio Backend + Audio Backend + MainWindow @@ -1201,6 +1256,11 @@ GUIgroupBox Odtwórz muzykę tytułową:\nJeśli gra to obsługuje, aktywuje odtwarzanie specjalnej muzyki podczas wybierania gry w GUI. + + + disableTrophycheckBox + 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). + hideCursorGroupBox @@ -1216,6 +1276,21 @@ backButtonBehaviorGroupBox Zachowanie przycisku Wstecz:\nUstawia przycisk Wstecz kontrolera tak, aby emulował dotknięcie określonego miejsca na panelu dotykowym PS4. + + + enableCompatibilityCheckBox + Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information. + + + + checkCompatibilityOnStartupCheckBox + Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts. + + + + updateCompatibilityButton + Update Compatibility Database:\nImmediately update the compatibility database. + Never @@ -1329,6 +1404,11 @@ Serial Numer seryjny + + + Compatibility + Compatibility + Region @@ -1364,6 +1444,51 @@ Never Played Never Played + + + h + h + + + + m + m + + + + s + s + + + + Compatibility is untested + Compatibility is untested + + + + Game does not initialize properly / crashes the emulator + Game does not initialize properly / crashes the emulator + + + + Game boots, but only displays a blank screen + Game boots, but only displays a blank screen + + + + Game displays an image but does not go past the menu + Game displays an image but does not go past the menu + + + + Game has game-breaking glitches or unplayable performance + Game has game-breaking glitches or unplayable performance + + + + Game can be completed with playable performance and no major glitches + Game can be completed with playable performance and no major glitches + CheckUpdate @@ -1493,4 +1618,32 @@ Nie udało się utworzyć pliku skryptu aktualizacji + + GameListUtils + + + B + B + + + + KB + KB + + + + MB + MB + + + + GB + GB + + + + TB + TB + + \ No newline at end of file diff --git a/src/qt_gui/translations/pt_BR.ts b/src/qt_gui/translations/pt_BR.ts index 5faccf6c5..8ab8db093 100644 --- a/src/qt_gui/translations/pt_BR.ts +++ b/src/qt_gui/translations/pt_BR.ts @@ -175,6 +175,26 @@ Delete DLC Deletar DLC + + + Compatibility... + Compatibilidade... + + + + Update database + Atualizar banco de dados + + + + View report + Ver status + + + + Submit a report + Enviar status + Shortcut creation @@ -182,8 +202,8 @@ - Shortcut created successfully!\n %1 - Atalho criado com sucesso!\n %1 + Shortcut created successfully! + Atalho criado com sucesso! @@ -192,8 +212,8 @@ - Error creating shortcut!\n %1 - Erro ao criar atalho!\n %1 + Error creating shortcut! + Erro ao criar atalho! @@ -552,6 +572,11 @@ Hide Cursor Idle Timeout Tempo de Inatividade para Ocultar Cursor + + + s + s + Controller @@ -672,16 +697,46 @@ GUI Settings Configurações da Interface + + + Disable Trophy Pop-ups + Desabilitar Pop-ups dos Troféus + Play title music Reproduzir música de abertura + + + Update Compatibility Database On Startup + Atualizar Compatibilidade ao Inicializar + + + + Game Compatibility + Compatibilidade dos Jogos + + + + Display Compatibility Data + Exibir Dados de Compatibilidade + + + + Update Compatibility Database + Atualizar Lista de Compatibilidade + Volume Volume + + + Audio Backend + Backend de Áudio + MainWindow @@ -1201,6 +1256,11 @@ GUIgroupBox Reproduzir música de abertura:\nSe o jogo suportar, ativa a reprodução de uma música especial ao selecionar o jogo na interface do menu. + + + disableTrophycheckBox + Desabilitar pop-ups dos troféus:\nDesabilite notificações de troféus no jogo. O progresso do troféu ainda pode ser rastreado usando o Trophy Viewer (clique com o botão direito do mouse no jogo na janela principal). + hideCursorGroupBox @@ -1216,6 +1276,21 @@ backButtonBehaviorGroupBox Comportamento do botão Voltar:\nDefine o botão Voltar do controle para emular o toque na posição especificada no touchpad do PS4. + + + enableCompatibilityCheckBox + Exibir Dados de Compatibilidade:\nExibe informações de compatibilidade dos jogos na janela principal.\nHabilitar "Atualizar Compatibilidade ao Inicializar" para obter informações atualizadas. + + + + checkCompatibilityOnStartupCheckBox + Atualizar Compatibilidade ao inicializar:\nAtualiza automaticamente o banco de dados de compatibilidade quando o SHADPS4 é iniciado. + + + + updateCompatibilityButton + Atualizar Lista de Compatibilidade:\nAtualizar imediatamente o banco de dados de compatibilidade. + Never @@ -1329,6 +1404,11 @@ Serial Serial + + + Compatibility + Compatibilidade + Region @@ -1364,6 +1444,51 @@ Never Played Nunca jogado + + + h + h + + + + m + m + + + + s + s + + + + Compatibility is untested + Compatibilidade não testada + + + + Game does not initialize properly / crashes the emulator + Jogo não inicializa corretamente / trava o emulador + + + + Game boots, but only displays a blank screen + O jogo inicializa, mas exibe apenas uma tela vazia + + + + Game displays an image but does not go past the menu + Jogo exibe imagem mas não passa do menu + + + + Game has game-breaking glitches or unplayable performance + O jogo tem falhas que interrompem o jogo ou desempenho injogável + + + + Game can be completed with playable performance and no major glitches + O jogo pode ser concluído com desempenho jogável e sem grandes falhas + CheckUpdate @@ -1493,4 +1618,32 @@ Falha ao criar o arquivo de script de atualização + + GameListUtils + + + B + B + + + + KB + KB + + + + MB + MB + + + + GB + GB + + + + TB + TB + + \ No newline at end of file diff --git a/src/qt_gui/translations/ro_RO.ts b/src/qt_gui/translations/ro_RO.ts index 2439e69e2..00547d6ba 100644 --- a/src/qt_gui/translations/ro_RO.ts +++ b/src/qt_gui/translations/ro_RO.ts @@ -175,6 +175,26 @@ Delete DLC Delete DLC + + + Compatibility... + Compatibility... + + + + Update database + Update database + + + + View report + View report + + + + Submit a report + Submit a report + Shortcut creation @@ -182,8 +202,8 @@ - Shortcut created successfully!\n %1 - Shortcut created successfully!\n %1 + Shortcut created successfully! + Shortcut created successfully! @@ -192,8 +212,8 @@ - Error creating shortcut!\n %1 - Error creating shortcut!\n %1 + Error creating shortcut! + Error creating shortcut! @@ -552,6 +572,11 @@ Hide Cursor Idle Timeout Timeout pentru ascunderea cursorului inactiv + + + s + s + Controller @@ -672,16 +697,46 @@ GUI Settings Setări GUI + + + Disable Trophy Pop-ups + Disable Trophy Pop-ups + Play title music Redă muzica titlului + + + Update Compatibility Database On Startup + Update Compatibility Database On Startup + + + + Game Compatibility + Game Compatibility + + + + Display Compatibility Data + Display Compatibility Data + + + + Update Compatibility Database + Update Compatibility Database + Volume Volum + + + Audio Backend + Audio Backend + MainWindow @@ -1201,6 +1256,11 @@ GUIgroupBox Redă muzica titlului:\nDacă un joc o suportă, activează redarea muzicii speciale când selectezi jocul în GUI. + + + disableTrophycheckBox + 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). + hideCursorGroupBox @@ -1216,6 +1276,21 @@ backButtonBehaviorGroupBox Comportamentul butonului înapoi:\nSetează butonul înapoi al controlerului să imite atingerea poziției specificate pe touchpad-ul PS4. + + + enableCompatibilityCheckBox + Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information. + + + + checkCompatibilityOnStartupCheckBox + Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts. + + + + updateCompatibilityButton + Update Compatibility Database:\nImmediately update the compatibility database. + Never @@ -1329,6 +1404,11 @@ Serial Serie + + + Compatibility + Compatibility + Region @@ -1364,6 +1444,51 @@ Never Played Never Played + + + h + h + + + + m + m + + + + s + s + + + + Compatibility is untested + Compatibility is untested + + + + Game does not initialize properly / crashes the emulator + Game does not initialize properly / crashes the emulator + + + + Game boots, but only displays a blank screen + Game boots, but only displays a blank screen + + + + Game displays an image but does not go past the menu + Game displays an image but does not go past the menu + + + + Game has game-breaking glitches or unplayable performance + Game has game-breaking glitches or unplayable performance + + + + Game can be completed with playable performance and no major glitches + Game can be completed with playable performance and no major glitches + CheckUpdate @@ -1493,4 +1618,32 @@ Nu s-a putut crea fișierul script de actualizare + + GameListUtils + + + B + B + + + + KB + KB + + + + MB + MB + + + + GB + GB + + + + TB + TB + + \ No newline at end of file diff --git a/src/qt_gui/translations/ru_RU.ts b/src/qt_gui/translations/ru_RU.ts index ccee34517..505a05a3e 100644 --- a/src/qt_gui/translations/ru_RU.ts +++ b/src/qt_gui/translations/ru_RU.ts @@ -118,7 +118,7 @@ Open Folder... - Открыть Папку... + Открыть папку... @@ -128,12 +128,12 @@ Open Save Data Folder - Открыть Папку Сохранений + Открыть папку сохранений Open Log Folder - Открыть Папку Логов + Открыть папку логов @@ -175,6 +175,26 @@ Delete DLC Удалить DLC + + + Compatibility... + Совместимость... + + + + Update database + Обновить базу данных + + + + View report + Посмотреть отчет + + + + Submit a report + Отправить отчет + Shortcut creation @@ -182,8 +202,8 @@ - Shortcut created successfully!\n %1 - Ярлык создан успешно!\n %1 + Shortcut created successfully! + Ярлык создан успешно! @@ -192,8 +212,8 @@ - Error creating shortcut!\n %1 - Ошибка создания ярлыка!\n %1 + Error creating shortcut! + Ошибка создания ярлыка! @@ -452,7 +472,7 @@ Trophy Viewer - Трофеи + Просмотр трофеев @@ -550,7 +570,12 @@ Hide Cursor Idle Timeout - Тайм-аут скрытия курсора при бездействии + Время скрытия курсора при бездействии + + + + s + сек @@ -672,16 +697,46 @@ GUI Settings Интерфейс + + + Disable Trophy Pop-ups + Отключить уведомления о трофеях + Play title music Играть заглавную музыку + + + Update Compatibility Database On Startup + Обновлять базу совместимости при запуске + + + + Game Compatibility + Совместимость игр + + + + Display Compatibility Data + Показывать данные совместимости + + + + Update Compatibility Database + Обновить базу совместимости + Volume Громкость + + + Audio Backend + Звуковая Подсистема + MainWindow @@ -738,7 +793,7 @@ ELF files (*.bin *.elf *.oelf) - Файл ELF (*.bin *.elf *.oelf) + Файлы ELF (*.bin *.elf *.oelf) @@ -793,7 +848,7 @@ Would you like to install DLC: %1? - Вы хотите установить DLC: %1?? + Вы хотите установить DLC: %1? @@ -841,7 +896,7 @@ Cheats / Patches for - Cheats / Patches for + Читы и патчи для @@ -1164,7 +1219,7 @@ showSplashCheckBox - Показывать заставку:\nОтображает заставку игры (специальное изображение) во время запуска игры. + Показывать заставку:\nОтображает заставку игры (специальное изображение) во время запуска. @@ -1201,10 +1256,15 @@ GUIgroupBox Играть заглавную музыку:\nВключает воспроизведение специальной музыки при выборе игры в списке, если она это поддерживает. + + + disableTrophycheckBox + Отключить уведомления о трофеях:\nОтключает внутриигровые уведомления о трофеях. Прогресс трофеев по прежнему можно отслеживать в меню Просмотр трофеев (правая кнопка мыши по игре в главном окне). + hideCursorGroupBox - Скрывать курсор:\nВыберите, когда курсор исчезнет:\nНикогда: Вы всегда будете видеть мышь.\nПри бездействии: Установите время, через которое курсор исчезнет при бездействии.\nВсегда: Вы никогда не будете видеть мышь. + Скрывать курсор:\nВыберите, когда курсор будет скрыт:\nНикогда: Вы всегда будете видеть курсор.\nПри бездействии: Установите время, через которое курсор будет скрыт при бездействии.\nВсегда: Курсор всегда будет скрыт. @@ -1216,6 +1276,21 @@ backButtonBehaviorGroupBox Поведение кнопки «Назад»:\nНастраивает кнопку «Назад» контроллера на эмуляцию нажатия на указанную область на сенсорной панели контроллера PS4. + + + enableCompatibilityCheckBox + Показывать данные совместимости:\nПоказывает информацию о совместимости игр в таблице. Включите «Обновлять базу совместимости при запуске» для получения актуальной информации. + + + + checkCompatibilityOnStartupCheckBox + Обновлять базу совместимости при запуске:\nАвтоматически обновлять базу данных совместимости при запуске shadPS4. + + + + updateCompatibilityButton + Обновить базу совместимости:\nНемедленно обновить базу данных совместимости. + Never @@ -1254,7 +1329,7 @@ graphicsAdapterGroupBox - Графическое устройство:\nВ системах с несколькими GPU выберите GPU, который будет использовать эмулятор из выпадающего списка,\nили выберите "Auto Select", чтобы определить его автоматически. + Графическое устройство:\nВ системах с несколькими GPU выберите GPU, который будет использовать эмулятор.\nВыберите "Auto Select", чтобы определить его автоматически. @@ -1329,6 +1404,11 @@ Serial Серийный номер + + + Compatibility + Совместимость + Region @@ -1362,7 +1442,52 @@ Never Played - Never Played + Вы не играли + + + + h + ч + + + + m + м + + + + s + с + + + + 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 + Игра показывает картинку, но не проходит дальше меню + + + + Game has game-breaking glitches or unplayable performance + Игра имеет ломающие игру глюки или плохую производительность + + + + Game can be completed with playable performance and no major glitches + Игра может быть пройдена с хорошей производительностью и без серьезных сбоев @@ -1445,7 +1570,7 @@ Update - Обновиться + Обновить @@ -1493,4 +1618,32 @@ Не удалось создать файл скрипта обновления + + GameListUtils + + + B + Б + + + + KB + КБ + + + + MB + МБ + + + + GB + ГБ + + + + TB + ТБ + + \ No newline at end of file diff --git a/src/qt_gui/translations/sq.ts b/src/qt_gui/translations/sq.ts index 4a02298e8..0c318f4f7 100644 --- a/src/qt_gui/translations/sq.ts +++ b/src/qt_gui/translations/sq.ts @@ -175,6 +175,26 @@ Delete DLC Fshi DLC-në + + + Compatibility... + Compatibility... + + + + Update database + Update database + + + + View report + View report + + + + Submit a report + Submit a report + Shortcut creation @@ -182,8 +202,8 @@ - Shortcut created successfully!\n %1 - Shkurtorja u krijua me sukses!\n %1 + Shortcut created successfully! + Shkurtorja u krijua me sukses! @@ -192,8 +212,8 @@ - Error creating shortcut!\n %1 - Gabim në krijimin e shkurtores!\n %1 + Error creating shortcut! + Gabim në krijimin e shkurtores! @@ -552,6 +572,11 @@ Hide Cursor Idle Timeout Koha për fshehjen e kursorit joaktiv + + + s + s + Controller @@ -672,16 +697,46 @@ GUI Settings Cilësimet e GUI + + + Disable Trophy Pop-ups + Çaktivizo njoftimet për Trofetë + Play title music Luaj muzikën e titullit + + + Update Compatibility Database On Startup + Përditëso bazën e të dhënave të përputhshmërisë gjatë nisjes + + + + Game Compatibility + Përputhshmëria e lojës + + + + Display Compatibility Data + Shfaq të dhënat e përputhshmërisë + + + + Update Compatibility Database + Përditëso bazën e të dhënave të përputhshmërisë + Volume Vëllimi i zërit + + + Audio Backend + Audio Backend + MainWindow @@ -841,7 +896,7 @@ Cheats / Patches for - Cheats / Patches for + Mashtrime / Arna për @@ -1159,7 +1214,7 @@ separateUpdatesCheckBox - Aktivizo dosjen e ndarë të përditësimit:\nAktivizon instalimin e përditësimeve të lojërave në dosje të veçanta për menaxhim më të lehtë. + Aktivizo dosjen e ndarë të përditësimit:\nAktivizon instalimin e përditësimeve të lojërave në dosje të veçanta për menaxhim më të lehtë.\nKjo mund të krijohet manualisht duke shtuar përditësimin e shpaketuar në dosjen e lojës me emrin "CUSA00000-UPDATE" ku ID-ja CUSA përputhet me ID-në e lojës. @@ -1201,6 +1256,11 @@ GUIgroupBox Luaj muzikën e titullit:\nNëse një lojë e mbështet, aktivizohet luajtja e muzikës të veçantë kur të zgjidhësh lojën në GUI. + + + disableTrophycheckBox + Çaktivizo njoftimet për Trofetë:\nÇaktivizo njoftimet për trofetë gjatë lojës. Përparimi i trofeve mund të ndiqet duke përdorur Shikuesin e Trofeve (kliko me të djathtën mbi lojën në dritaren kryesore). + hideCursorGroupBox @@ -1216,6 +1276,21 @@ backButtonBehaviorGroupBox Sjellja e butonit mbrapa:\nLejon të përcaktohet se në cilën pjesë të tastierës prekëse do të imitojë një prekje butoni mprapa. + + + enableCompatibilityCheckBox + Shfaq të dhënat e përputhshmërisë:\nShfaq informacionin e përputhshmërisë së lojës në formë tabele. Aktivizo 'Përditëso përputhshmërinë gjatë nisjes' për të marrë informacion të përditësuar. + + + + checkCompatibilityOnStartupCheckBox + Përditëso përputhshmërinë gjatë nisjes:\nPërditëson automatikisht bazën e të dhënave të përputhshmërisë kur shadPS4 niset. + + + + updateCompatibilityButton + Përditëso bazën e të dhënave të përputhshmërisë:\nPërditëso menjëherë bazën e të dhënave të përputhshmërisë. + Never @@ -1329,6 +1404,11 @@ Serial Seriku + + + Compatibility + Përputhshmëria + Region @@ -1362,7 +1442,52 @@ Never Played - Never Played + Nuk është luajtur kurrë + + + + h + h + + + + m + m + + + + s + s + + + + Compatibility is untested + Përputhshmëria nuk është e testuar + + + + Game does not initialize properly / crashes the emulator + Loja nuk niset siç duhet / rrëzon emulatorin + + + + Game boots, but only displays a blank screen + Loja niset, por shfaq vetëm një ekran të zbrazët + + + + Game displays an image but does not go past the menu + Loja shfaq një imazh, por nuk kalon përtej menysë + + + + Game has game-breaking glitches or unplayable performance + Loja ka probleme kritike ose performancë të papërshtatshme për lojë + + + + Game can be completed with playable performance and no major glitches + Loja mund të përfundohet me performancë të luajtshme dhe pa probleme të mëdha @@ -1493,4 +1618,32 @@ Krijimi i skedarit skript të përditësimit dështoi + + GameListUtils + + + B + B + + + + KB + KB + + + + MB + MB + + + + GB + GB + + + + TB + TB + + diff --git a/src/qt_gui/translations/tr_TR.ts b/src/qt_gui/translations/tr_TR.ts index 4c77bc16a..2845af462 100644 --- a/src/qt_gui/translations/tr_TR.ts +++ b/src/qt_gui/translations/tr_TR.ts @@ -175,6 +175,26 @@ Delete DLC Delete DLC + + + Compatibility... + Compatibility... + + + + Update database + Update database + + + + View report + View report + + + + Submit a report + Submit a report + Shortcut creation @@ -182,8 +202,8 @@ - Shortcut created successfully!\n %1 - Kısayol başarıyla oluşturuldu!\n %1 + Shortcut created successfully! + Kısayol başarıyla oluşturuldu! @@ -192,8 +212,8 @@ - Error creating shortcut!\n %1 - Kısayol oluşturulurken hata oluştu!\n %1 + Error creating shortcut! + Kısayol oluşturulurken hata oluştu! @@ -552,6 +572,11 @@ Hide Cursor Idle Timeout İmleç İçin Hareketsizlik Zaman Aşımı + + + s + s + Controller @@ -672,16 +697,46 @@ GUI Settings GUI Ayarları + + + Disable Trophy Pop-ups + Disable Trophy Pop-ups + Play title music Başlık müziğini çal + + + Update Compatibility Database On Startup + Update Compatibility Database On Startup + + + + Game Compatibility + Game Compatibility + + + + Display Compatibility Data + Display Compatibility Data + + + + Update Compatibility Database + Update Compatibility Database + Volume Ses seviyesi + + + Audio Backend + Audio Backend + MainWindow @@ -1201,6 +1256,11 @@ GUIgroupBox Başlık Müziklerini Çal:\nEğer bir oyun bunu destekliyorsa, GUI'de oyunu seçtiğinizde özel müziklerin çalmasını etkinleştirir. + + + disableTrophycheckBox + 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). + hideCursorGroupBox @@ -1216,6 +1276,21 @@ backButtonBehaviorGroupBox Geri düğmesi davranışı:\nKontrol cihazındaki geri düğmesini, PS4'ün dokunmatik panelindeki belirlenen noktaya dokunmak için ayarlar. + + + enableCompatibilityCheckBox + Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information. + + + + checkCompatibilityOnStartupCheckBox + Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts. + + + + updateCompatibilityButton + Update Compatibility Database:\nImmediately update the compatibility database. + Never @@ -1329,6 +1404,11 @@ Serial Seri Numarası + + + Compatibility + Compatibility + Region @@ -1364,6 +1444,51 @@ Never Played Never Played + + + h + h + + + + m + m + + + + s + s + + + + Compatibility is untested + Compatibility is untested + + + + Game does not initialize properly / crashes the emulator + Game does not initialize properly / crashes the emulator + + + + Game boots, but only displays a blank screen + Game boots, but only displays a blank screen + + + + Game displays an image but does not go past the menu + Game displays an image but does not go past the menu + + + + Game has game-breaking glitches or unplayable performance + Game has game-breaking glitches or unplayable performance + + + + Game can be completed with playable performance and no major glitches + Game can be completed with playable performance and no major glitches + CheckUpdate @@ -1493,4 +1618,32 @@ Güncelleme betiği dosyası oluşturulamadı - + + GameListUtils + + + B + B + + + + KB + KB + + + + MB + MB + + + + GB + GB + + + + TB + TB + + + \ No newline at end of file diff --git a/src/qt_gui/translations/uk_UA.ts b/src/qt_gui/translations/uk_UA.ts index 805fff151..8abfca435 100644 --- a/src/qt_gui/translations/uk_UA.ts +++ b/src/qt_gui/translations/uk_UA.ts @@ -175,6 +175,26 @@ Delete DLC Видалити DLC + + + Compatibility... + Compatibility... + + + + Update database + Update database + + + + View report + View report + + + + Submit a report + Submit a report + Shortcut creation @@ -182,8 +202,8 @@ - Shortcut created successfully!\n %1 - Ярлик створений успішно!\n %1 + Shortcut created successfully! + Ярлик створений успішно! @@ -192,8 +212,8 @@ - Error creating shortcut!\n %1 - Помилка при створенні ярлика!\n %1 + Error creating shortcut! + Помилка при створенні ярлика! @@ -552,6 +572,11 @@ Hide Cursor Idle Timeout Тайм-аут приховування курсора при бездіяльності + + + s + s + Controller @@ -672,16 +697,46 @@ GUI Settings Інтерфейс + + + Disable Trophy Pop-ups + Disable Trophy Pop-ups + Play title music Програвати заголовну музику + + + Update Compatibility Database On Startup + Update Compatibility Database On Startup + + + + Game Compatibility + Game Compatibility + + + + Display Compatibility Data + Display Compatibility Data + + + + Update Compatibility Database + Update Compatibility Database + Volume Гучність + + + Audio Backend + Audio Backend + MainWindow @@ -1201,6 +1256,11 @@ GUIgroupBox Грати заголовну музику:\nВмикає відтворення спеціальної музики під час вибору гри в списку, якщо вона це підтримує. + + + disableTrophycheckBox + 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). + hideCursorGroupBox @@ -1216,6 +1276,21 @@ backButtonBehaviorGroupBox Поведінка кнопки «Назад»:\nНалаштовує кнопку «Назад» контролера на емуляцію натискання на зазначену область на сенсорній панелі контролера PS4. + + + enableCompatibilityCheckBox + Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information. + + + + checkCompatibilityOnStartupCheckBox + Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts. + + + + updateCompatibilityButton + Update Compatibility Database:\nImmediately update the compatibility database. + Never @@ -1329,6 +1404,11 @@ Serial Серійний номер + + + Compatibility + Compatibility + Region @@ -1364,6 +1444,51 @@ Never Played Never Played + + + h + h + + + + m + m + + + + s + s + + + + Compatibility is untested + Compatibility is untested + + + + Game does not initialize properly / crashes the emulator + Game does not initialize properly / crashes the emulator + + + + Game boots, but only displays a blank screen + Game boots, but only displays a blank screen + + + + Game displays an image but does not go past the menu + Game displays an image but does not go past the menu + + + + Game has game-breaking glitches or unplayable performance + Game has game-breaking glitches or unplayable performance + + + + Game can be completed with playable performance and no major glitches + Game can be completed with playable performance and no major glitches + CheckUpdate @@ -1493,4 +1618,32 @@ Не вдалося створити файл скрипта оновлення + + GameListUtils + + + B + B + + + + KB + KB + + + + MB + MB + + + + GB + GB + + + + TB + TB + + \ No newline at end of file diff --git a/src/qt_gui/translations/vi_VN.ts b/src/qt_gui/translations/vi_VN.ts index 1ac3d042d..7d0e9a2cd 100644 --- a/src/qt_gui/translations/vi_VN.ts +++ b/src/qt_gui/translations/vi_VN.ts @@ -175,6 +175,26 @@ Delete DLC Delete DLC + + + Compatibility... + Compatibility... + + + + Update database + Update database + + + + View report + View report + + + + Submit a report + Submit a report + Shortcut creation @@ -182,8 +202,8 @@ - Shortcut created successfully!\n %1 - Shortcut created successfully!\n %1 + Shortcut created successfully! + Shortcut created successfully! @@ -192,8 +212,8 @@ - Error creating shortcut!\n %1 - Error creating shortcut!\n %1 + Error creating shortcut! + Error creating shortcut! @@ -552,6 +572,11 @@ Hide Cursor Idle Timeout Thời gian chờ ẩn con trỏ + + + s + s + Controller @@ -672,16 +697,46 @@ GUI Settings Cài đặt GUI + + + Disable Trophy Pop-ups + Disable Trophy Pop-ups + Play title music Phát nhạc tiêu đề + + + Update Compatibility Database On Startup + Update Compatibility Database On Startup + + + + Game Compatibility + Game Compatibility + + + + Display Compatibility Data + Display Compatibility Data + + + + Update Compatibility Database + Update Compatibility Database + Volume Âm lượng + + + Audio Backend + Audio Backend + MainWindow @@ -1201,6 +1256,11 @@ GUIgroupBox Phát nhạc tiêu đề trò chơi:\nNếu một trò chơi hỗ trợ điều này, hãy kích hoạt phát nhạc đặc biệt khi bạn chọn trò chơi trong GUI. + + + disableTrophycheckBox + 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). + hideCursorGroupBox @@ -1216,6 +1276,21 @@ backButtonBehaviorGroupBox Hành vi nút quay lại:\nĐặt nút quay lại của tay cầm để mô phỏng việc chạm vào vị trí đã chỉ định trên touchpad của PS4. + + + enableCompatibilityCheckBox + Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information. + + + + checkCompatibilityOnStartupCheckBox + Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts. + + + + updateCompatibilityButton + Update Compatibility Database:\nImmediately update the compatibility database. + Never @@ -1329,6 +1404,11 @@ Serial Số seri + + + Compatibility + Compatibility + Region @@ -1364,6 +1444,51 @@ Never Played Never Played + + + h + h + + + + m + m + + + + s + s + + + + Compatibility is untested + Compatibility is untested + + + + Game does not initialize properly / crashes the emulator + Game does not initialize properly / crashes the emulator + + + + Game boots, but only displays a blank screen + Game boots, but only displays a blank screen + + + + Game displays an image but does not go past the menu + Game displays an image but does not go past the menu + + + + Game has game-breaking glitches or unplayable performance + Game has game-breaking glitches or unplayable performance + + + + Game can be completed with playable performance and no major glitches + Game can be completed with playable performance and no major glitches + CheckUpdate @@ -1493,4 +1618,32 @@ Không thể tạo tệp kịch bản cập nhật + + GameListUtils + + + B + B + + + + KB + KB + + + + MB + MB + + + + GB + GB + + + + TB + TB + + \ No newline at end of file diff --git a/src/qt_gui/translations/zh_CN.ts b/src/qt_gui/translations/zh_CN.ts index 19fb8edff..4ceb91315 100644 --- a/src/qt_gui/translations/zh_CN.ts +++ b/src/qt_gui/translations/zh_CN.ts @@ -175,6 +175,26 @@ Delete DLC 删除DLC + + + Compatibility... + Compatibility... + + + + Update database + Update database + + + + View report + View report + + + + Submit a report + Submit a report + Shortcut creation @@ -182,8 +202,8 @@ - Shortcut created successfully!\n %1 - 创建快捷方式成功!\n %1 + Shortcut created successfully! + 创建快捷方式成功! @@ -192,8 +212,8 @@ - Error creating shortcut!\n %1 - 创建快捷方式出错!\n %1 + Error creating shortcut! + 创建快捷方式出错! @@ -552,6 +572,11 @@ Hide Cursor Idle Timeout 光标空闲超时隐藏 + + + s + s + Controller @@ -672,16 +697,46 @@ GUI Settings 界面设置 + + + Disable Trophy Pop-ups + Disable Trophy Pop-ups + Play title music 播放标题音乐 + + + Update Compatibility Database On Startup + Update Compatibility Database On Startup + + + + Game Compatibility + Game Compatibility + + + + Display Compatibility Data + Display Compatibility Data + + + + Update Compatibility Database + Update Compatibility Database + Volume 音量 + + + Audio Backend + Audio Backend + MainWindow @@ -1201,6 +1256,11 @@ GUIgroupBox 播放标题音乐:\n如果游戏支持,在图形界面选择游戏时启用播放特殊音乐。 + + + disableTrophycheckBox + 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). + hideCursorGroupBox @@ -1216,6 +1276,21 @@ backButtonBehaviorGroupBox 返回按钮行为:\n设置控制器的返回按钮以模拟在 PS4 触控板上指定位置的点击。 + + + enableCompatibilityCheckBox + Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information. + + + + checkCompatibilityOnStartupCheckBox + Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts. + + + + updateCompatibilityButton + Update Compatibility Database:\nImmediately update the compatibility database. + Never @@ -1329,6 +1404,11 @@ Serial 序列号 + + + Compatibility + Compatibility + Region @@ -1364,6 +1444,51 @@ Never Played Never Played + + + h + h + + + + m + m + + + + s + s + + + + Compatibility is untested + Compatibility is untested + + + + Game does not initialize properly / crashes the emulator + Game does not initialize properly / crashes the emulator + + + + Game boots, but only displays a blank screen + Game boots, but only displays a blank screen + + + + Game displays an image but does not go past the menu + Game displays an image but does not go past the menu + + + + Game has game-breaking glitches or unplayable performance + Game has game-breaking glitches or unplayable performance + + + + Game can be completed with playable performance and no major glitches + Game can be completed with playable performance and no major glitches + CheckUpdate @@ -1493,4 +1618,32 @@ 无法创建更新脚本文件 - + + GameListUtils + + + B + B + + + + KB + KB + + + + MB + MB + + + + GB + GB + + + + TB + TB + + + \ No newline at end of file diff --git a/src/qt_gui/translations/zh_TW.ts b/src/qt_gui/translations/zh_TW.ts index fbd6d624d..3d27267b6 100644 --- a/src/qt_gui/translations/zh_TW.ts +++ b/src/qt_gui/translations/zh_TW.ts @@ -175,6 +175,26 @@ Delete DLC Delete DLC + + + Compatibility... + Compatibility... + + + + Update database + Update database + + + + View report + View report + + + + Submit a report + Submit a report + Shortcut creation @@ -182,8 +202,8 @@ - Shortcut created successfully!\n %1 - Shortcut created successfully!\n %1 + Shortcut created successfully! + Shortcut created successfully! @@ -192,8 +212,8 @@ - Error creating shortcut!\n %1 - Error creating shortcut!\n %1 + Error creating shortcut! + Error creating shortcut! @@ -552,6 +572,11 @@ Hide Cursor Idle Timeout 游標空閒超時隱藏 + + + s + s + Controller @@ -672,16 +697,46 @@ GUI Settings 介面設置 + + + Disable Trophy Pop-ups + Disable Trophy Pop-ups + Play title music 播放標題音樂 + + + Update Compatibility Database On Startup + Update Compatibility Database On Startup + + + + Game Compatibility + Game Compatibility + + + + Display Compatibility Data + Display Compatibility Data + + + + Update Compatibility Database + Update Compatibility Database + Volume 音量 + + + Audio Backend + Audio Backend + MainWindow @@ -1201,6 +1256,11 @@ GUIgroupBox 播放標題音樂:\n如果遊戲支持,啟用在GUI中選擇遊戲時播放特殊音樂。 + + + disableTrophycheckBox + 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). + hideCursorGroupBox @@ -1216,6 +1276,21 @@ backButtonBehaviorGroupBox 返回按鈕行為:\n設定控制器的返回按鈕模擬在 PS4 觸控板上指定位置的觸碰。 + + + enableCompatibilityCheckBox + Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information. + + + + checkCompatibilityOnStartupCheckBox + Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts. + + + + updateCompatibilityButton + Update Compatibility Database:\nImmediately update the compatibility database. + Never @@ -1329,6 +1404,11 @@ Serial 序號 + + + Compatibility + Compatibility + Region @@ -1364,6 +1444,51 @@ Never Played Never Played + + + h + h + + + + m + m + + + + s + s + + + + Compatibility is untested + Compatibility is untested + + + + Game does not initialize properly / crashes the emulator + Game does not initialize properly / crashes the emulator + + + + Game boots, but only displays a blank screen + Game boots, but only displays a blank screen + + + + Game displays an image but does not go past the menu + Game displays an image but does not go past the menu + + + + Game has game-breaking glitches or unplayable performance + Game has game-breaking glitches or unplayable performance + + + + Game can be completed with playable performance and no major glitches + Game can be completed with playable performance and no major glitches + CheckUpdate @@ -1493,4 +1618,32 @@ 無法創建更新腳本文件 + + GameListUtils + + + B + B + + + + KB + KB + + + + MB + MB + + + + GB + GB + + + + TB + TB + + \ No newline at end of file diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp index 0ce9eea7c..900d40472 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp @@ -24,6 +24,7 @@ static constexpr spv::ExecutionMode GetInputPrimitiveType(AmdGpu::PrimitiveType case AmdGpu::PrimitiveType::PointList: return spv::ExecutionMode::InputPoints; case AmdGpu::PrimitiveType::LineList: + case AmdGpu::PrimitiveType::LineStrip: return spv::ExecutionMode::InputLines; case AmdGpu::PrimitiveType::TriangleList: case AmdGpu::PrimitiveType::TriangleStrip: diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h index 2f606eb45..85bed589b 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h @@ -304,10 +304,12 @@ Id EmitBitFieldSExtract(EmitContext& ctx, IR::Inst* inst, Id base, Id offset, Id Id EmitBitFieldUExtract(EmitContext& ctx, IR::Inst* inst, Id base, Id offset, Id count); Id EmitBitReverse32(EmitContext& ctx, Id value); Id EmitBitCount32(EmitContext& ctx, Id value); +Id EmitBitCount64(EmitContext& ctx, Id value); Id EmitBitwiseNot32(EmitContext& ctx, Id value); Id EmitFindSMsb32(EmitContext& ctx, Id value); Id EmitFindUMsb32(EmitContext& ctx, Id value); Id EmitFindILsb32(EmitContext& ctx, Id value); +Id EmitFindILsb64(EmitContext& ctx, Id value); Id EmitSMin32(EmitContext& ctx, Id a, Id b); Id EmitUMin32(EmitContext& ctx, Id a, Id b); Id EmitSMax32(EmitContext& ctx, Id a, Id b); @@ -318,7 +320,8 @@ Id EmitSLessThan32(EmitContext& ctx, Id lhs, Id rhs); Id EmitSLessThan64(EmitContext& ctx, Id lhs, Id rhs); Id EmitULessThan32(EmitContext& ctx, Id lhs, Id rhs); Id EmitULessThan64(EmitContext& ctx, Id lhs, Id rhs); -Id EmitIEqual(EmitContext& ctx, Id lhs, Id rhs); +Id EmitIEqual32(EmitContext& ctx, Id lhs, Id rhs); +Id EmitIEqual64(EmitContext& ctx, Id lhs, Id rhs); Id EmitSLessThanEqual(EmitContext& ctx, Id lhs, Id rhs); Id EmitULessThanEqual(EmitContext& ctx, Id lhs, Id rhs); Id EmitSGreaterThan(EmitContext& ctx, Id lhs, Id rhs); diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp index 02af92385..def1f816e 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp @@ -201,6 +201,10 @@ Id EmitBitCount32(EmitContext& ctx, Id value) { return ctx.OpBitCount(ctx.U32[1], value); } +Id EmitBitCount64(EmitContext& ctx, Id value) { + return ctx.OpBitCount(ctx.U64, value); +} + Id EmitBitwiseNot32(EmitContext& ctx, Id value) { return ctx.OpNot(ctx.U32[1], value); } @@ -217,6 +221,10 @@ Id EmitFindILsb32(EmitContext& ctx, Id value) { return ctx.OpFindILsb(ctx.U32[1], value); } +Id EmitFindILsb64(EmitContext& ctx, Id value) { + return ctx.OpFindILsb(ctx.U64, value); +} + Id EmitSMin32(EmitContext& ctx, Id a, Id b) { return ctx.OpSMin(ctx.U32[1], a, b); } @@ -277,7 +285,11 @@ Id EmitULessThan64(EmitContext& ctx, Id lhs, Id rhs) { return ctx.OpULessThan(ctx.U1[1], lhs, rhs); } -Id EmitIEqual(EmitContext& ctx, Id lhs, Id rhs) { +Id EmitIEqual32(EmitContext& ctx, Id lhs, Id rhs) { + return ctx.OpIEqual(ctx.U1[1], lhs, rhs); +} + +Id EmitIEqual64(EmitContext& ctx, Id lhs, Id rhs) { return ctx.OpIEqual(ctx.U1[1], lhs, rhs); } diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index d8bafccd9..281c487af 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp @@ -43,6 +43,7 @@ static constexpr u32 NumVertices(AmdGpu::PrimitiveType type) { case AmdGpu::PrimitiveType::PointList: return 1u; case AmdGpu::PrimitiveType::LineList: + case AmdGpu::PrimitiveType::LineStrip: return 2u; case AmdGpu::PrimitiveType::TriangleList: case AmdGpu::PrimitiveType::TriangleStrip: diff --git a/src/shader_recompiler/frontend/format.cpp b/src/shader_recompiler/frontend/format.cpp index 4f0922e2e..9677be3e5 100644 --- a/src/shader_recompiler/frontend/format.cpp +++ b/src/shader_recompiler/frontend/format.cpp @@ -3565,8 +3565,8 @@ constexpr std::array InstructionFormatMIMG = {{ {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Float32, ScalarType::Float32}, // 64 = IMAGE_GATHER4 - {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined, - ScalarType::Undefined}, + {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32, + ScalarType::Float32}, // 65 = IMAGE_GATHER4_CL {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined, ScalarType::Undefined}, @@ -3603,10 +3603,10 @@ constexpr std::array InstructionFormatMIMG = {{ ScalarType::Undefined}, // 79 = IMAGE_GATHER4_C_LZ {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32, - ScalarType::Uint32}, + ScalarType::Float32}, // 80 = IMAGE_GATHER4_O - {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined, - ScalarType::Undefined}, + {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}, diff --git a/src/shader_recompiler/frontend/translate/scalar_alu.cpp b/src/shader_recompiler/frontend/translate/scalar_alu.cpp index f96fd0f40..3a2b01a90 100644 --- a/src/shader_recompiler/frontend/translate/scalar_alu.cpp +++ b/src/shader_recompiler/frontend/translate/scalar_alu.cpp @@ -100,8 +100,12 @@ void Translator::EmitScalarAlu(const GcnInst& inst) { return S_BREV_B32(inst); case Opcode::S_BCNT1_I32_B32: return S_BCNT1_I32_B32(inst); + case Opcode::S_BCNT1_I32_B64: + return S_BCNT1_I32_B64(inst); case Opcode::S_FF1_I32_B32: return S_FF1_I32_B32(inst); + case Opcode::S_FF1_I32_B64: + return S_FF1_I32_B64(inst); case Opcode::S_AND_SAVEEXEC_B64: return S_SAVEEXEC_B64(NegateMode::None, false, inst); case Opcode::S_ORN2_SAVEEXEC_B64: @@ -585,12 +589,25 @@ void Translator::S_BCNT1_I32_B32(const GcnInst& inst) { ir.SetScc(ir.INotEqual(result, ir.Imm32(0))); } +void Translator::S_BCNT1_I32_B64(const GcnInst& inst) { + const IR::U32 result = ir.BitCount(GetSrc64(inst.src[0])); + SetDst(inst.dst[0], result); + ir.SetScc(ir.INotEqual(result, ir.Imm32(0))); +} + void Translator::S_FF1_I32_B32(const GcnInst& inst) { const IR::U32 src0{GetSrc(inst.src[0])}; const IR::U32 result{ir.Select(ir.IEqual(src0, ir.Imm32(0U)), ir.Imm32(-1), ir.FindILsb(src0))}; SetDst(inst.dst[0], result); } +void Translator::S_FF1_I32_B64(const GcnInst& inst) { + const IR::U64 src0{GetSrc64(inst.src[0])}; + const IR::U32 result{ + ir.Select(ir.IEqual(src0, ir.Imm64(u64(0))), ir.Imm32(-1), ir.FindILsb(src0))}; + SetDst(inst.dst[0], result); +} + void Translator::S_SAVEEXEC_B64(NegateMode negate, bool is_or, const GcnInst& inst) { // This instruction normally operates on 64-bit data (EXEC, VCC, SGPRs) // However here we flatten it to 1-bit EXEC and 1-bit VCC. For the destination diff --git a/src/shader_recompiler/frontend/translate/translate.h b/src/shader_recompiler/frontend/translate/translate.h index fd4d8d86a..e8584ec2f 100644 --- a/src/shader_recompiler/frontend/translate/translate.h +++ b/src/shader_recompiler/frontend/translate/translate.h @@ -111,7 +111,9 @@ public: void S_NOT_B64(const GcnInst& inst); void S_BREV_B32(const GcnInst& inst); void S_BCNT1_I32_B32(const GcnInst& inst); + 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_GETPC_B64(u32 pc, const GcnInst& inst); void S_SAVEEXEC_B64(NegateMode negate, bool is_or, const GcnInst& inst); void S_ABS_I32(const GcnInst& inst); diff --git a/src/shader_recompiler/frontend/translate/vector_memory.cpp b/src/shader_recompiler/frontend/translate/vector_memory.cpp index 48cb79610..7c3db9551 100644 --- a/src/shader_recompiler/frontend/translate/vector_memory.cpp +++ b/src/shader_recompiler/frontend/translate/vector_memory.cpp @@ -144,8 +144,10 @@ void Translator::EmitVectorMemory(const GcnInst& inst) { return IMAGE_SAMPLE(inst); // Image gather operations + case Opcode::IMAGE_GATHER4: case Opcode::IMAGE_GATHER4_LZ: case Opcode::IMAGE_GATHER4_C: + case Opcode::IMAGE_GATHER4_O: case Opcode::IMAGE_GATHER4_C_O: case Opcode::IMAGE_GATHER4_C_LZ: case Opcode::IMAGE_GATHER4_LZ_O: diff --git a/src/shader_recompiler/ir/ir_emitter.cpp b/src/shader_recompiler/ir/ir_emitter.cpp index c241ec984..c9d97679f 100644 --- a/src/shader_recompiler/ir/ir_emitter.cpp +++ b/src/shader_recompiler/ir/ir_emitter.cpp @@ -1273,8 +1273,15 @@ U32 IREmitter::BitReverse(const U32& value) { return Inst(Opcode::BitReverse32, value); } -U32 IREmitter::BitCount(const U32& value) { - return Inst(Opcode::BitCount32, value); +U32 IREmitter::BitCount(const U32U64& value) { + switch (value.Type()) { + case Type::U32: + return Inst(Opcode::BitCount32, value); + case Type::U64: + return Inst(Opcode::BitCount64, value); + default: + ThrowInvalidType(value.Type()); + } } U32 IREmitter::BitwiseNot(const U32& value) { @@ -1289,8 +1296,15 @@ U32 IREmitter::FindUMsb(const U32& value) { return Inst(Opcode::FindUMsb32, value); } -U32 IREmitter::FindILsb(const U32& value) { - return Inst(Opcode::FindILsb32, value); +U32 IREmitter::FindILsb(const U32U64& value) { + switch (value.Type()) { + case Type::U32: + return Inst(Opcode::FindILsb32, value); + case Type::U64: + return Inst(Opcode::FindILsb64, value); + default: + ThrowInvalidType(value.Type()); + } } U32 IREmitter::SMin(const U32& a, const U32& b) { @@ -1345,7 +1359,9 @@ U1 IREmitter::IEqual(const U32U64& lhs, const U32U64& rhs) { } switch (lhs.Type()) { case Type::U32: - return Inst(Opcode::IEqual, lhs, rhs); + return Inst(Opcode::IEqual32, lhs, rhs); + case Type::U64: + return Inst(Opcode::IEqual64, lhs, rhs); default: ThrowInvalidType(lhs.Type()); } diff --git a/src/shader_recompiler/ir/ir_emitter.h b/src/shader_recompiler/ir/ir_emitter.h index 4cf44107e..4679a0133 100644 --- a/src/shader_recompiler/ir/ir_emitter.h +++ b/src/shader_recompiler/ir/ir_emitter.h @@ -229,12 +229,12 @@ public: [[nodiscard]] U32 BitFieldExtract(const U32& base, const U32& offset, const U32& count, bool is_signed = false); [[nodiscard]] U32 BitReverse(const U32& value); - [[nodiscard]] U32 BitCount(const U32& value); + [[nodiscard]] U32 BitCount(const U32U64& value); [[nodiscard]] U32 BitwiseNot(const U32& value); [[nodiscard]] U32 FindSMsb(const U32& value); [[nodiscard]] U32 FindUMsb(const U32& value); - [[nodiscard]] U32 FindILsb(const U32& value); + [[nodiscard]] U32 FindILsb(const U32U64& value); [[nodiscard]] U32 SMin(const U32& a, const U32& b); [[nodiscard]] U32 UMin(const U32& a, const U32& b); [[nodiscard]] U32 IMin(const U32& a, const U32& b, bool is_signed); diff --git a/src/shader_recompiler/ir/opcodes.inc b/src/shader_recompiler/ir/opcodes.inc index aafd43ea8..cf2c3b67e 100644 --- a/src/shader_recompiler/ir/opcodes.inc +++ b/src/shader_recompiler/ir/opcodes.inc @@ -284,11 +284,13 @@ OPCODE(BitFieldSExtract, U32, U32, OPCODE(BitFieldUExtract, U32, U32, U32, U32, ) OPCODE(BitReverse32, U32, U32, ) OPCODE(BitCount32, U32, U32, ) +OPCODE(BitCount64, U32, U64, ) OPCODE(BitwiseNot32, U32, U32, ) OPCODE(FindSMsb32, U32, U32, ) OPCODE(FindUMsb32, U32, U32, ) OPCODE(FindILsb32, U32, U32, ) +OPCODE(FindILsb64, U32, U64, ) OPCODE(SMin32, U32, U32, U32, ) OPCODE(UMin32, U32, U32, U32, ) OPCODE(SMax32, U32, U32, U32, ) @@ -299,7 +301,8 @@ OPCODE(SLessThan32, U1, U32, OPCODE(SLessThan64, U1, U64, U64, ) OPCODE(ULessThan32, U1, U32, U32, ) OPCODE(ULessThan64, U1, U64, U64, ) -OPCODE(IEqual, U1, U32, U32, ) +OPCODE(IEqual32, U1, U32, U32, ) +OPCODE(IEqual64, U1, U64, U64, ) OPCODE(SLessThanEqual, U1, U32, U32, ) OPCODE(ULessThanEqual, U1, U32, U32, ) OPCODE(SGreaterThan, U1, U32, U32, ) diff --git a/src/shader_recompiler/ir/passes/constant_propagation_pass.cpp b/src/shader_recompiler/ir/passes/constant_propagation_pass.cpp index 16b07e1a1..fcf2f7d9f 100644 --- a/src/shader_recompiler/ir/passes/constant_propagation_pass.cpp +++ b/src/shader_recompiler/ir/passes/constant_propagation_pass.cpp @@ -391,9 +391,12 @@ void ConstantPropagation(IR::Block& block, IR::Inst& inst) { case IR::Opcode::UGreaterThanEqual: FoldWhenAllImmediates(inst, [](u32 a, u32 b) { return a >= b; }); return; - case IR::Opcode::IEqual: + case IR::Opcode::IEqual32: FoldWhenAllImmediates(inst, [](u32 a, u32 b) { return a == b; }); return; + case IR::Opcode::IEqual64: + FoldWhenAllImmediates(inst, [](u64 a, u64 b) { return a == b; }); + return; case IR::Opcode::INotEqual: FoldWhenAllImmediates(inst, [](u32 a, u32 b) { return a != b; }); return; diff --git a/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp b/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp index db1a2edd2..e6d23bfe7 100644 --- a/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp +++ b/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp @@ -249,7 +249,7 @@ std::pair TryDisableAnisoLod0(const IR::Inst* inst) { // Select should be based on zero check const auto* prod0 = inst->Arg(0).InstRecursive(); - if (prod0->GetOpcode() != IR::Opcode::IEqual || + if (prod0->GetOpcode() != IR::Opcode::IEqual32 || !(prod0->Arg(1).IsImmediate() && prod0->Arg(1).U32() == 0u)) { return not_found; } diff --git a/src/video_core/amdgpu/resource.h b/src/video_core/amdgpu/resource.h index d9a8b7cac..58b286e9c 100644 --- a/src/video_core/amdgpu/resource.h +++ b/src/video_core/amdgpu/resource.h @@ -364,6 +364,16 @@ enum class Filter : u64 { AnisoLinear = 3, }; +constexpr bool IsAnisoFilter(const Filter filter) { + switch (filter) { + case Filter::AnisoPoint: + case Filter::AnisoLinear: + return true; + default: + return false; + } +} + enum class MipFilter : u64 { None = 0, Point = 1, @@ -435,6 +445,23 @@ struct Sampler { float MaxLod() const noexcept { return static_cast(max_lod.Value()) / 256.0f; } + + float MaxAniso() const { + switch (max_aniso) { + case AnisoRatio::One: + return 1.0f; + case AnisoRatio::Two: + return 2.0f; + case AnisoRatio::Four: + return 4.0f; + case AnisoRatio::Eight: + return 8.0f; + case AnisoRatio::Sixteen: + return 16.0f; + default: + UNREACHABLE(); + } + } }; } // namespace AmdGpu diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index c01d4cbe8..ffa474a1c 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -133,37 +133,23 @@ GraphicsPipeline::GraphicsPipeline( .sampleShadingEnable = false, }; - const vk::Viewport viewport = { - .x = 0.0f, - .y = 0.0f, - .width = 1.0f, - .height = 1.0f, - .minDepth = 0.0f, - .maxDepth = 1.0f, - }; - - const vk::Rect2D scissor = { - .offset = {0, 0}, - .extent = {1, 1}, - }; - const vk::PipelineViewportDepthClipControlCreateInfoEXT clip_control = { .negativeOneToOne = key.clip_space == Liverpool::ClipSpace::MinusWToW, }; const vk::PipelineViewportStateCreateInfo viewport_info = { .pNext = instance.IsDepthClipControlSupported() ? &clip_control : nullptr, - .viewportCount = 1, - .pViewports = &viewport, - .scissorCount = 1, - .pScissors = &scissor, }; boost::container::static_vector dynamic_states = { - vk::DynamicState::eViewport, vk::DynamicState::eScissor, - vk::DynamicState::eBlendConstants, vk::DynamicState::eDepthBounds, - vk::DynamicState::eDepthBias, vk::DynamicState::eStencilReference, - vk::DynamicState::eStencilCompareMask, vk::DynamicState::eStencilWriteMask, + vk::DynamicState::eViewportWithCountEXT, + vk::DynamicState::eScissorWithCountEXT, + vk::DynamicState::eBlendConstants, + vk::DynamicState::eDepthBounds, + vk::DynamicState::eDepthBias, + vk::DynamicState::eStencilReference, + vk::DynamicState::eStencilCompareMask, + vk::DynamicState::eStencilWriteMask, vk::DynamicState::eStencilOpEXT, }; diff --git a/src/video_core/renderer_vulkan/vk_instance.h b/src/video_core/renderer_vulkan/vk_instance.h index 54a9b9873..62838140c 100644 --- a/src/video_core/renderer_vulkan/vk_instance.h +++ b/src/video_core/renderer_vulkan/vk_instance.h @@ -249,6 +249,11 @@ public: return properties.limits.maxSamplerLodBias; } + /// Returns the maximum sampler anisotropy. + float MaxSamplerAnisotropy() const { + return properties.limits.maxSamplerAnisotropy; + } + /// Returns the maximum number of push descriptors. u32 MaxPushDescriptors() const { return push_descriptor_props.maxPushDescriptors; diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 74ae6b61c..c880cad70 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -497,7 +497,7 @@ vk::ShaderModule PipelineCache::CompileModule(Shader::Info& info, Shader::Runtim module = CompileSPV(spv, instance.GetDevice()); } - const auto name = fmt::format("{}_{:#018x}_{}", info.stage, info.pgm_hash, perm_idx); + const auto name = GetShaderName(info.stage, info.pgm_hash, perm_idx); Vulkan::SetObjectName(instance.GetDevice(), module, name); if (Config::collectShadersForDebug()) { DebugState.CollectShader(name, info.l_stage, module, spv, code, @@ -572,6 +572,14 @@ std::optional PipelineCache::ReplaceShader(vk::ShaderModule mo return new_module; } +std::string PipelineCache::GetShaderName(Shader::Stage stage, u64 hash, + std::optional perm) { + if (perm) { + return fmt::format("{}_{:#018x}_{}", stage, hash, *perm); + } + return fmt::format("{}_{:#018x}", stage, hash); +} + void PipelineCache::DumpShader(std::span code, u64 hash, Shader::Stage stage, size_t perm_idx, std::string_view ext) { if (!Config::dumpShaders()) { @@ -583,7 +591,7 @@ void PipelineCache::DumpShader(std::span code, u64 hash, Shader::Stag if (!std::filesystem::exists(dump_dir)) { std::filesystem::create_directories(dump_dir); } - const auto filename = fmt::format("{}_{:#018x}_{}.{}", stage, hash, perm_idx, ext); + const auto filename = fmt::format("{}.{}", GetShaderName(stage, hash, perm_idx), ext); const auto file = IOFile{dump_dir / filename, FileAccessMode::Write}; file.WriteSpan(code); } @@ -597,7 +605,7 @@ std::optional> PipelineCache::GetShaderPatch(u64 hash, Shader:: if (!std::filesystem::exists(patch_dir)) { std::filesystem::create_directories(patch_dir); } - const auto filename = fmt::format("{}_{:#018x}_{}.{}", stage, hash, perm_idx, ext); + const auto filename = fmt::format("{}.{}", GetShaderName(stage, hash, perm_idx), ext); const auto filepath = patch_dir / filename; if (!std::filesystem::exists(filepath)) { return {}; diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h index d4a51efdb..b3bccd513 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h @@ -65,6 +65,9 @@ public: std::optional ReplaceShader(vk::ShaderModule module, std::span spv_code); + static std::string GetShaderName(Shader::Stage stage, u64 hash, + std::optional perm = {}); + private: bool RefreshGraphicsKey(); bool RefreshComputeKey(); diff --git a/src/video_core/renderer_vulkan/vk_platform.cpp b/src/video_core/renderer_vulkan/vk_platform.cpp index dbdabe0d9..ab61af6a4 100644 --- a/src/video_core/renderer_vulkan/vk_platform.cpp +++ b/src/video_core/renderer_vulkan/vk_platform.cpp @@ -137,6 +137,7 @@ std::vector GetInstanceExtensions(Frontend::WindowSystemType window // Add the windowing system specific extension std::vector extensions; extensions.reserve(7); + extensions.push_back(VK_EXT_LAYER_SETTINGS_EXTENSION_NAME); switch (window_type) { case Frontend::WindowSystemType::Headless: @@ -347,6 +348,17 @@ vk::UniqueInstance CreateInstance(Frontend::WindowSystemType window_type, bool e .valueCount = 1, .pValues = &enable_force_barriers, }, +#ifdef __APPLE__ + // MoltenVK debug mode turns on additional device loss error details, so + // use the crash diagnostic setting as an indicator of whether to turn it on. + vk::LayerSettingEXT{ + .pLayerName = "MoltenVK", + .pSettingName = "MVK_CONFIG_DEBUG", + .type = vk::LayerSettingTypeEXT::eBool32, + .valueCount = 1, + .pValues = &enable_crash_diagnostic, + } +#endif }; vk::StructureChain instance_ci_chain = { diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 1e698bf6b..d458fa124 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -1019,17 +1019,44 @@ void Rasterizer::UpdateDynamicState(const GraphicsPipeline& pipeline) { } void Rasterizer::UpdateViewportScissorState() { - auto& regs = liverpool->regs; + const auto& regs = liverpool->regs; + + const auto combined_scissor_value_tl = [](s16 scr, s16 win, s16 gen, s16 win_offset) { + return std::max({scr, s16(win + win_offset), s16(gen + win_offset)}); + }; + const auto combined_scissor_value_br = [](s16 scr, s16 win, s16 gen, s16 win_offset) { + return std::min({scr, s16(win + win_offset), s16(gen + win_offset)}); + }; + const bool enable_offset = !regs.window_scissor.window_offset_disable.Value(); + + Liverpool::Scissor scsr{}; + scsr.top_left_x = combined_scissor_value_tl( + regs.screen_scissor.top_left_x, s16(regs.window_scissor.top_left_x.Value()), + s16(regs.generic_scissor.top_left_x.Value()), + enable_offset ? regs.window_offset.window_x_offset : 0); + scsr.top_left_y = combined_scissor_value_tl( + regs.screen_scissor.top_left_y, s16(regs.window_scissor.top_left_y.Value()), + s16(regs.generic_scissor.top_left_y.Value()), + enable_offset ? regs.window_offset.window_y_offset : 0); + scsr.bottom_right_x = combined_scissor_value_br( + regs.screen_scissor.bottom_right_x, regs.window_scissor.bottom_right_x, + regs.generic_scissor.bottom_right_x, + enable_offset ? regs.window_offset.window_x_offset : 0); + scsr.bottom_right_y = combined_scissor_value_br( + regs.screen_scissor.bottom_right_y, regs.window_scissor.bottom_right_y, + regs.generic_scissor.bottom_right_y, + enable_offset ? regs.window_offset.window_y_offset : 0); boost::container::static_vector viewports; boost::container::static_vector scissors; + const auto& vp_ctl = regs.viewport_control; const float reduce_z = instance.IsDepthClipControlSupported() && regs.clipper_control.clip_space == AmdGpu::Liverpool::ClipSpace::MinusWToW ? 1.0f : 0.0f; - 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]; @@ -1050,53 +1077,17 @@ void Rasterizer::UpdateViewportScissorState() { .minDepth = zoffset - zscale * reduce_z, .maxDepth = zscale + zoffset, }); - } - const bool enable_offset = !regs.window_scissor.window_offset_disable.Value(); - Liverpool::Scissor scsr{}; - const auto combined_scissor_value_tl = [](s16 scr, s16 win, s16 gen, s16 win_offset) { - return std::max({scr, s16(win + win_offset), s16(gen + win_offset)}); - }; - - scsr.top_left_x = combined_scissor_value_tl( - regs.screen_scissor.top_left_x, s16(regs.window_scissor.top_left_x.Value()), - s16(regs.generic_scissor.top_left_x.Value()), - enable_offset ? regs.window_offset.window_x_offset : 0); - - scsr.top_left_y = combined_scissor_value_tl( - regs.screen_scissor.top_left_y, s16(regs.window_scissor.top_left_y.Value()), - s16(regs.generic_scissor.top_left_y.Value()), - enable_offset ? regs.window_offset.window_y_offset : 0); - - const auto combined_scissor_value_br = [](s16 scr, s16 win, s16 gen, s16 win_offset) { - return std::min({scr, s16(win + win_offset), s16(gen + win_offset)}); - }; - - scsr.bottom_right_x = combined_scissor_value_br( - regs.screen_scissor.bottom_right_x, regs.window_scissor.bottom_right_x, - regs.generic_scissor.bottom_right_x, - enable_offset ? regs.window_offset.window_x_offset : 0); - - scsr.bottom_right_y = combined_scissor_value_br( - regs.screen_scissor.bottom_right_y, regs.window_scissor.bottom_right_y, - regs.generic_scissor.bottom_right_y, - enable_offset ? regs.window_offset.window_y_offset : 0); - - for (u32 idx = 0; idx < Liverpool::NumViewports; idx++) { - if (regs.viewports[idx].xscale == 0) { - // Scissor and viewport counts should be equal. - continue; - } auto vp_scsr = scsr; if (regs.mode_control.vport_scissor_enable) { vp_scsr.top_left_x = - std::max(vp_scsr.top_left_x, s16(regs.viewport_scissors[idx].top_left_x.Value())); + std::max(vp_scsr.top_left_x, s16(regs.viewport_scissors[i].top_left_x.Value())); vp_scsr.top_left_y = - std::max(vp_scsr.top_left_y, s16(regs.viewport_scissors[idx].top_left_y.Value())); + std::max(vp_scsr.top_left_y, s16(regs.viewport_scissors[i].top_left_y.Value())); vp_scsr.bottom_right_x = - std::min(vp_scsr.bottom_right_x, regs.viewport_scissors[idx].bottom_right_x); + std::min(vp_scsr.bottom_right_x, regs.viewport_scissors[i].bottom_right_x); vp_scsr.bottom_right_y = - std::min(vp_scsr.bottom_right_y, regs.viewport_scissors[idx].bottom_right_y); + std::min(vp_scsr.bottom_right_y, regs.viewport_scissors[i].bottom_right_y); } scissors.push_back({ .offset = {vp_scsr.top_left_x, vp_scsr.top_left_y}, @@ -1104,9 +1095,27 @@ void Rasterizer::UpdateViewportScissorState() { }); } + if (viewports.empty()) { + // Vulkan requires providing at least one viewport. + constexpr vk::Viewport empty_viewport = { + .x = 0.0f, + .y = 0.0f, + .width = 1.0f, + .height = 1.0f, + .minDepth = 0.0f, + .maxDepth = 1.0f, + }; + constexpr vk::Rect2D empty_scissor = { + .offset = {0, 0}, + .extent = {1, 1}, + }; + viewports.push_back(empty_viewport); + scissors.push_back(empty_scissor); + } + const auto cmdbuf = scheduler.CommandBuffer(); - cmdbuf.setViewport(0, viewports); - cmdbuf.setScissor(0, scissors); + cmdbuf.setViewportWithCountEXT(viewports); + cmdbuf.setScissorWithCountEXT(scissors); } void Rasterizer::ScopeMarkerBegin(const std::string_view& str) { diff --git a/src/video_core/texture_cache/sampler.cpp b/src/video_core/texture_cache/sampler.cpp index 9f4bc7a7e..5ce10ff0e 100644 --- a/src/video_core/texture_cache/sampler.cpp +++ b/src/video_core/texture_cache/sampler.cpp @@ -1,6 +1,8 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include +#include "video_core/amdgpu/resource.h" #include "video_core/renderer_vulkan/liverpool_to_vk.h" #include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/texture_cache/sampler.h" @@ -12,6 +14,11 @@ Sampler::Sampler(const Vulkan::Instance& instance, const AmdGpu::Sampler& sample LOG_WARNING(Render_Vulkan, "Texture requires gamma correction"); } using namespace Vulkan; + const bool anisotropyEnable = instance.IsAnisotropicFilteringSupported() && + (AmdGpu::IsAnisoFilter(sampler.xy_mag_filter) || + AmdGpu::IsAnisoFilter(sampler.xy_min_filter)); + const float maxAnisotropy = + std::clamp(sampler.MaxAniso(), 1.0f, instance.MaxSamplerAnisotropy()); const vk::SamplerCreateInfo sampler_ci = { .magFilter = LiverpoolToVK::Filter(sampler.xy_mag_filter), .minFilter = LiverpoolToVK::Filter(sampler.xy_min_filter), @@ -20,6 +27,8 @@ Sampler::Sampler(const Vulkan::Instance& instance, const AmdGpu::Sampler& sample .addressModeV = LiverpoolToVK::ClampMode(sampler.clamp_y), .addressModeW = LiverpoolToVK::ClampMode(sampler.clamp_z), .mipLodBias = std::min(sampler.LodBias(), instance.MaxSamplerLodBias()), + .anisotropyEnable = anisotropyEnable, + .maxAnisotropy = maxAnisotropy, .compareEnable = sampler.depth_compare_func != AmdGpu::DepthCompare::Never, .compareOp = LiverpoolToVK::DepthCompare(sampler.depth_compare_func), .minLod = sampler.MinLod(), diff --git a/src/video_core/texture_cache/tile_manager.cpp b/src/video_core/texture_cache/tile_manager.cpp index ef80f2418..de108843b 100644 --- a/src/video_core/texture_cache/tile_manager.cpp +++ b/src/video_core/texture_cache/tile_manager.cpp @@ -25,6 +25,7 @@ static vk::Format DemoteImageFormatForDetiling(vk::Format format) { switch (format) { case vk::Format::eR8Uint: case vk::Format::eR8Unorm: + case vk::Format::eR8Snorm: return vk::Format::eR8Uint; case vk::Format::eR4G4B4A4UnormPack16: case vk::Format::eB5G6R5UnormPack16: @@ -32,6 +33,7 @@ static vk::Format DemoteImageFormatForDetiling(vk::Format format) { case vk::Format::eR8G8Unorm: case vk::Format::eR16Sfloat: case vk::Format::eR16Unorm: + case vk::Format::eD16Unorm: return vk::Format::eR8G8Uint; case vk::Format::eR8G8B8A8Srgb: case vk::Format::eB8G8R8A8Srgb: @@ -40,6 +42,7 @@ static vk::Format DemoteImageFormatForDetiling(vk::Format format) { case vk::Format::eR8G8B8A8Snorm: case vk::Format::eR8G8B8A8Uint: case vk::Format::eR32Sfloat: + case vk::Format::eD32Sfloat: case vk::Format::eR32Uint: case vk::Format::eR16G16Sfloat: case vk::Format::eR16G16Unorm: