Merge branch 'main' into qt-style

This commit is contained in:
tomboylover93 2024-12-27 10:22:18 -03:00 committed by GitHub
commit f17867e4e7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
135 changed files with 8742 additions and 5471 deletions

View File

@ -16,7 +16,7 @@ if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release) set(CMAKE_BUILD_TYPE Release)
endif() endif()
project(shadPS4) project(shadPS4 CXX C ASM)
# Forcing PIE makes sure that the base address is high enough so that it doesn't clash with the PS4 memory. # Forcing PIE makes sure that the base address is high enough so that it doesn't clash with the PS4 memory.
if(UNIX AND NOT APPLE) if(UNIX AND NOT APPLE)
@ -392,7 +392,8 @@ set(USBD_LIB src/core/libraries/usbd/usbd.cpp
src/core/libraries/usbd/usbd.h src/core/libraries/usbd/usbd.h
) )
set(FIBER_LIB src/core/libraries/fiber/fiber.cpp set(FIBER_LIB src/core/libraries/fiber/fiber_context.s
src/core/libraries/fiber/fiber.cpp
src/core/libraries/fiber/fiber.h src/core/libraries/fiber/fiber.h
src/core/libraries/fiber/fiber_error.h src/core/libraries/fiber/fiber_error.h
) )
@ -630,6 +631,8 @@ set(SHADER_RECOMPILER src/shader_recompiler/exception.h
src/shader_recompiler/backend/spirv/emit_spirv_instructions.h src/shader_recompiler/backend/spirv/emit_spirv_instructions.h
src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp
src/shader_recompiler/backend/spirv/emit_spirv_logical.cpp src/shader_recompiler/backend/spirv/emit_spirv_logical.cpp
src/shader_recompiler/backend/spirv/emit_spirv_quad_rect.cpp
src/shader_recompiler/backend/spirv/emit_spirv_quad_rect.h
src/shader_recompiler/backend/spirv/emit_spirv_select.cpp src/shader_recompiler/backend/spirv/emit_spirv_select.cpp
src/shader_recompiler/backend/spirv/emit_spirv_shared_memory.cpp src/shader_recompiler/backend/spirv/emit_spirv_shared_memory.cpp
src/shader_recompiler/backend/spirv/emit_spirv_special.cpp src/shader_recompiler/backend/spirv/emit_spirv_special.cpp

View File

@ -86,32 +86,32 @@ F12 | Trigger RenderDoc Capture
> [!NOTE] > [!NOTE]
> Xbox and DualShock controllers work out of the box. > Xbox and DualShock controllers work out of the box.
| Controller button | Keyboard equivelant | | Controller button | Keyboard equivelant | Mac alternative |
|-------------|-------------| |-------------|-------------|--------------|
LEFT AXIS UP | W | LEFT AXIS UP | W | |
LEFT AXIS DOWN | S | LEFT AXIS DOWN | S | |
LEFT AXIS LEFT | A | LEFT AXIS LEFT | A | |
LEFT AXIS RIGHT | D | LEFT AXIS RIGHT | D | |
RIGHT AXIS UP | I | RIGHT AXIS UP | I | |
RIGHT AXIS DOWN | K | RIGHT AXIS DOWN | K | |
RIGHT AXIS LEFT | J | RIGHT AXIS LEFT | J | |
RIGHT AXIS RIGHT | L | RIGHT AXIS RIGHT | L | |
TRIANGLE | Numpad 8 | TRIANGLE | Numpad 8 | C |
CIRCLE | Numpad 6 | CIRCLE | Numpad 6 | B |
CROSS | Numpad 2 | CROSS | Numpad 2 | N |
SQUARE | Numpad 4 | SQUARE | Numpad 4 | V |
PAD UP | UP | PAD UP | UP | |
PAD DOWN | DOWN | PAD DOWN | DOWN | |
PAD LEFT | LEFT | PAD LEFT | LEFT | |
PAD RIGHT | RIGHT | PAD RIGHT | RIGHT | |
OPTIONS | RETURN | OPTIONS | RETURN | |
BACK BUTTON / TOUCH PAD | SPACE | BACK BUTTON / TOUCH PAD | SPACE | |
L1 | Q | L1 | Q | |
R1 | U | R1 | U | |
L2 | E | L2 | E | |
R2 | O | R2 | O | |
L3 | X | L3 | X | |
R3 | M | R3 | M | |
# Main team # Main team

View File

@ -25,7 +25,7 @@ Once you are within the installer:
Beware, this requires you to create a Qt account. If you do not want to do this, please follow the MSYS2/MinGW compilation method instead. Beware, this requires you to create a Qt account. If you do not want to do this, please follow the MSYS2/MinGW compilation method instead.
1. Under the current, non beta version of Qt (at the time of writing 6.7.3), select the option `MSVC 2022 64-bit` or similar. 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. If you are on Windows on ARM / Qualcomm Snapdragon Elite X, select `MSVC 2022 ARM64` instead.
Go through the installation normally. If you know what you are doing, you may unselect individual components that eat up too much disk space. Go through the installation normally. If you know what you are doing, you may unselect individual components that eat up too much disk space.
@ -64,7 +64,7 @@ Go through the Git for Windows installation as normal
Your shadps4.exe will be in `C:\path\to\source\Build\x64-Clang-Release\` Your shadps4.exe will be in `C:\path\to\source\Build\x64-Clang-Release\`
To automatically populate the necessary files to run shadPS4.exe, run in a command prompt or terminal: To automatically populate the necessary files to run shadPS4.exe, run in a command prompt or terminal:
`C:\Qt\6.7.3\msvc2022_64\bin\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) (Change Qt path if you've installed it to non-default path)
## Option 2: MSYS2/MinGW ## Option 2: MSYS2/MinGW

View File

@ -189,7 +189,11 @@ add_library(Dear_ImGui
target_include_directories(Dear_ImGui INTERFACE dear_imgui/) target_include_directories(Dear_ImGui INTERFACE dear_imgui/)
# Tracy # Tracy
option(TRACY_ENABLE "" ON) if (CMAKE_BUILD_TYPE STREQUAL "Release")
option(TRACY_ENABLE "" OFF)
else()
option(TRACY_ENABLE "" ON)
endif()
option(TRACY_NO_CRASH_HANDLER "" ON) # Otherwise texture cache exceptions will be treaten as a crash option(TRACY_NO_CRASH_HANDLER "" ON) # Otherwise texture cache exceptions will be treaten as a crash
option(TRACY_ON_DEMAND "" ON) option(TRACY_ON_DEMAND "" ON)
option(TRACY_NO_FRAME_IMAGE "" ON) option(TRACY_NO_FRAME_IMAGE "" ON)

View File

@ -14,7 +14,11 @@
#include <tracy/Tracy.hpp> #include <tracy/Tracy.hpp>
static inline bool IsProfilerConnected() { static inline bool IsProfilerConnected() {
#if TRACY_ENABLE
return tracy::GetProfiler().IsConnected(); return tracy::GetProfiler().IsConnected();
#else
return false;
#endif
} }
#define TRACY_GPU_ENABLED 0 #define TRACY_GPU_ENABLED 0

View File

@ -1,25 +1,25 @@
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include <cstddef> #include <cstddef>
#include <type_traits> #include <type_traits>
namespace Common { namespace Common {
/// Ceiled integer division. /// Ceiled integer division.
template <typename N, typename D> template <typename N, typename D>
requires std::is_integral_v<N> && std::is_unsigned_v<D> requires std::is_integral_v<N> && std::is_unsigned_v<D>
[[nodiscard]] constexpr N DivCeil(N number, D divisor) { [[nodiscard]] constexpr N DivCeil(N number, D divisor) {
return static_cast<N>((static_cast<D>(number) + divisor - 1) / divisor); return static_cast<N>((static_cast<D>(number) + divisor - 1) / divisor);
} }
/// Ceiled integer division with logarithmic divisor in base 2 /// Ceiled integer division with logarithmic divisor in base 2
template <typename N, typename D> template <typename N, typename D>
requires std::is_integral_v<N> && std::is_unsigned_v<D> requires std::is_integral_v<N> && std::is_unsigned_v<D>
[[nodiscard]] constexpr N DivCeilLog2(N value, D alignment_log2) { [[nodiscard]] constexpr N DivCeilLog2(N value, D alignment_log2) {
return static_cast<N>((static_cast<D>(value) + (D(1) << alignment_log2) - 1) >> alignment_log2); return static_cast<N>((static_cast<D>(value) + (D(1) << alignment_log2) - 1) >> alignment_log2);
} }
} // namespace Common } // namespace Common

View File

@ -207,7 +207,7 @@ public:
return WriteSpan(string); return WriteSpan(string);
} }
static size_t WriteBytes(const std::filesystem::path path, std::span<const u8> data) { static size_t WriteBytes(const std::filesystem::path path, const auto& data) {
IOFile out(path, FileAccessMode::Write); IOFile out(path, FileAccessMode::Write);
return out.Write(data); return out.Write(data);
} }

View File

@ -1,30 +1,30 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#ifdef _WIN32 #ifdef _WIN32
#include "ntapi.h" #include "ntapi.h"
NtClose_t NtClose = nullptr; NtClose_t NtClose = nullptr;
NtSetInformationFile_t NtSetInformationFile = nullptr; NtSetInformationFile_t NtSetInformationFile = nullptr;
NtCreateThread_t NtCreateThread = nullptr; NtCreateThread_t NtCreateThread = nullptr;
NtTerminateThread_t NtTerminateThread = nullptr; NtTerminateThread_t NtTerminateThread = nullptr;
NtQueueApcThreadEx_t NtQueueApcThreadEx = nullptr; NtQueueApcThreadEx_t NtQueueApcThreadEx = nullptr;
namespace Common::NtApi { namespace Common::NtApi {
void Initialize() { void Initialize() {
HMODULE nt_handle = GetModuleHandleA("ntdll.dll"); HMODULE nt_handle = GetModuleHandleA("ntdll.dll");
// http://stackoverflow.com/a/31411628/4725495 // http://stackoverflow.com/a/31411628/4725495
NtClose = (NtClose_t)GetProcAddress(nt_handle, "NtClose"); NtClose = (NtClose_t)GetProcAddress(nt_handle, "NtClose");
NtSetInformationFile = NtSetInformationFile =
(NtSetInformationFile_t)GetProcAddress(nt_handle, "NtSetInformationFile"); (NtSetInformationFile_t)GetProcAddress(nt_handle, "NtSetInformationFile");
NtCreateThread = (NtCreateThread_t)GetProcAddress(nt_handle, "NtCreateThread"); NtCreateThread = (NtCreateThread_t)GetProcAddress(nt_handle, "NtCreateThread");
NtTerminateThread = (NtTerminateThread_t)GetProcAddress(nt_handle, "NtTerminateThread"); NtTerminateThread = (NtTerminateThread_t)GetProcAddress(nt_handle, "NtTerminateThread");
NtQueueApcThreadEx = (NtQueueApcThreadEx_t)GetProcAddress(nt_handle, "NtQueueApcThreadEx"); NtQueueApcThreadEx = (NtQueueApcThreadEx_t)GetProcAddress(nt_handle, "NtQueueApcThreadEx");
} }
} // namespace Common::NtApi } // namespace Common::NtApi
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -1,53 +1,53 @@
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "common/spin_lock.h" #include "common/spin_lock.h"
#if _MSC_VER #if _MSC_VER
#include <intrin.h> #include <intrin.h>
#if _M_AMD64 #if _M_AMD64
#define __x86_64__ 1 #define __x86_64__ 1
#endif #endif
#if _M_ARM64 #if _M_ARM64
#define __aarch64__ 1 #define __aarch64__ 1
#endif #endif
#else #else
#if __x86_64__ #if __x86_64__
#include <xmmintrin.h> #include <xmmintrin.h>
#endif #endif
#endif #endif
namespace { namespace {
void ThreadPause() { void ThreadPause() {
#if __x86_64__ #if __x86_64__
_mm_pause(); _mm_pause();
#elif __aarch64__ && _MSC_VER #elif __aarch64__ && _MSC_VER
__yield(); __yield();
#elif __aarch64__ #elif __aarch64__
asm("yield"); asm("yield");
#endif #endif
} }
} // Anonymous namespace } // Anonymous namespace
namespace Common { namespace Common {
void SpinLock::lock() { void SpinLock::lock() {
while (lck.test_and_set(std::memory_order_acquire)) { while (lck.test_and_set(std::memory_order_acquire)) {
ThreadPause(); ThreadPause();
} }
} }
void SpinLock::unlock() { void SpinLock::unlock() {
lck.clear(std::memory_order_release); lck.clear(std::memory_order_release);
} }
bool SpinLock::try_lock() { bool SpinLock::try_lock() {
if (lck.test_and_set(std::memory_order_acquire)) { if (lck.test_and_set(std::memory_order_acquire)) {
return false; return false;
} }
return true; return true;
} }
} // namespace Common } // namespace Common

View File

@ -1,33 +1,33 @@
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include <atomic> #include <atomic>
namespace Common { namespace Common {
/** /**
* SpinLock class * SpinLock class
* a lock similar to mutex that forces a thread to spin wait instead calling the * a lock similar to mutex that forces a thread to spin wait instead calling the
* supervisor. Should be used on short sequences of code. * supervisor. Should be used on short sequences of code.
*/ */
class SpinLock { class SpinLock {
public: public:
SpinLock() = default; SpinLock() = default;
SpinLock(const SpinLock&) = delete; SpinLock(const SpinLock&) = delete;
SpinLock& operator=(const SpinLock&) = delete; SpinLock& operator=(const SpinLock&) = delete;
SpinLock(SpinLock&&) = delete; SpinLock(SpinLock&&) = delete;
SpinLock& operator=(SpinLock&&) = delete; SpinLock& operator=(SpinLock&&) = delete;
void lock(); void lock();
void unlock(); void unlock();
[[nodiscard]] bool try_lock(); [[nodiscard]] bool try_lock();
private: private:
std::atomic_flag lck = ATOMIC_FLAG_INIT; std::atomic_flag lck = ATOMIC_FLAG_INIT;
}; };
} // namespace Common } // namespace Common

View File

@ -1,61 +1,61 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include <memory> #include <memory>
#include <utility> #include <utility>
namespace Common { namespace Common {
/// General purpose function wrapper similar to std::function. /// General purpose function wrapper similar to std::function.
/// Unlike std::function, the captured values don't have to be copyable. /// Unlike std::function, the captured values don't have to be copyable.
/// This class can be moved but not copied. /// This class can be moved but not copied.
template <typename ResultType, typename... Args> template <typename ResultType, typename... Args>
class UniqueFunction { class UniqueFunction {
class CallableBase { class CallableBase {
public: public:
virtual ~CallableBase() = default; virtual ~CallableBase() = default;
virtual ResultType operator()(Args&&...) = 0; virtual ResultType operator()(Args&&...) = 0;
}; };
template <typename Functor> template <typename Functor>
class Callable final : public CallableBase { class Callable final : public CallableBase {
public: public:
Callable(Functor&& functor_) : functor{std::move(functor_)} {} Callable(Functor&& functor_) : functor{std::move(functor_)} {}
~Callable() override = default; ~Callable() override = default;
ResultType operator()(Args&&... args) override { ResultType operator()(Args&&... args) override {
return functor(std::forward<Args>(args)...); return functor(std::forward<Args>(args)...);
} }
private: private:
Functor functor; Functor functor;
}; };
public: public:
UniqueFunction() = default; UniqueFunction() = default;
template <typename Functor> template <typename Functor>
UniqueFunction(Functor&& functor) UniqueFunction(Functor&& functor)
: callable{std::make_unique<Callable<Functor>>(std::move(functor))} {} : callable{std::make_unique<Callable<Functor>>(std::move(functor))} {}
UniqueFunction& operator=(UniqueFunction&& rhs) noexcept = default; UniqueFunction& operator=(UniqueFunction&& rhs) noexcept = default;
UniqueFunction(UniqueFunction&& rhs) noexcept = default; UniqueFunction(UniqueFunction&& rhs) noexcept = default;
UniqueFunction& operator=(const UniqueFunction&) = delete; UniqueFunction& operator=(const UniqueFunction&) = delete;
UniqueFunction(const UniqueFunction&) = delete; UniqueFunction(const UniqueFunction&) = delete;
ResultType operator()(Args&&... args) const { ResultType operator()(Args&&... args) const {
return (*callable)(std::forward<Args>(args)...); return (*callable)(std::forward<Args>(args)...);
} }
explicit operator bool() const noexcept { explicit operator bool() const noexcept {
return static_cast<bool>(callable); return static_cast<bool>(callable);
} }
private: private:
std::unique_ptr<CallableBase> callable; std::unique_ptr<CallableBase> callable;
}; };
} // namespace Common } // namespace Common

View File

@ -8,7 +8,7 @@
namespace Common { namespace Common {
constexpr char VERSION[] = "0.4.1 WIP"; constexpr char VERSION[] = "0.5.1 WIP";
constexpr bool isRelease = false; constexpr bool isRelease = false;
} // namespace Common } // namespace Common

View File

@ -141,12 +141,9 @@ void Crypto::decryptEFSM(std::span<CryptoPP::byte, 16> NPcommID,
std::span<CryptoPP::byte, 16> efsmIv, std::span<CryptoPP::byte> ciphertext, std::span<CryptoPP::byte, 16> efsmIv, std::span<CryptoPP::byte> ciphertext,
std::span<CryptoPP::byte> decrypted) { std::span<CryptoPP::byte> decrypted) {
std::vector<CryptoPP::byte> TrophyKey = {0x21, 0xF4, 0x1A, 0x6B, 0xAD, 0x8A, 0x1D, 0x3E,
0xCA, 0x7A, 0xD5, 0x86, 0xC1, 0x01, 0xB7, 0xA9};
std::vector<CryptoPP::byte> TrophyIV = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; std::vector<CryptoPP::byte> TrophyIV = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
// step 1: Encrypt NPcommID // step 1: Encrypt NPcommID
CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption encrypt; CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption encrypt;
encrypt.SetKeyWithIV(TrophyKey.data(), TrophyKey.size(), TrophyIV.data());
std::vector<CryptoPP::byte> trpKey(16); std::vector<CryptoPP::byte> trpKey(16);

View File

@ -11,6 +11,7 @@
#include "libraries/kernel/time.h" #include "libraries/kernel/time.h"
#include "libraries/system/msgdialog.h" #include "libraries/system/msgdialog.h"
#include "video_core/amdgpu/pm4_cmds.h" #include "video_core/amdgpu/pm4_cmds.h"
#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
using namespace DebugStateType; 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)) { if ((*dump)->regs.stage_enable.IsStageEnabled(i)) {
auto stage = (*dump)->regs.ProgramForStage(i); auto stage = (*dump)->regs.ProgramForStage(i);
if (stage->address_lo != 0) { if (stage->address_lo != 0) {
const auto& info = AmdGpu::Liverpool::SearchBinaryInfo(stage->Address<u32*>());
auto code = stage->Code(); auto code = stage->Code();
(*dump)->stages[i] = PipelineShaderProgramDump{ (*dump)->stages[i] = PipelineShaderProgramDump{
.name = Vulkan::PipelineCache::GetShaderName(Shader::StageFromIndex(i),
info.shader_hash),
.hash = info.shader_hash,
.user_data = *stage, .user_data = *stage,
.code = std::vector<u32>{code.begin(), code.end()}, .code = std::vector<u32>{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; auto& cs = (*dump)->regs.cs_program;
cs = cs_state; cs = cs_state;
const auto& info = AmdGpu::Liverpool::SearchBinaryInfo(cs.Address<u32*>());
(*dump)->cs_data = PipelineComputerProgramDump{ (*dump)->cs_data = PipelineComputerProgramDump{
.name = Vulkan::PipelineCache::GetShaderName(Shader::Stage::Compute, info.shader_hash),
.hash = info.shader_hash,
.cs_program = cs, .cs_program = cs,
.code = std::vector<u32>{cs.Code().begin(), cs.Code().end()}, .code = std::vector<u32>{cs.Code().begin(), cs.Code().end()},
}; };

View File

@ -50,11 +50,15 @@ struct QueueDump {
}; };
struct PipelineShaderProgramDump { struct PipelineShaderProgramDump {
std::string name;
u64 hash;
Vulkan::Liverpool::ShaderProgram user_data{}; Vulkan::Liverpool::ShaderProgram user_data{};
std::vector<u32> code{}; std::vector<u32> code{};
}; };
struct PipelineComputerProgramDump { struct PipelineComputerProgramDump {
std::string name;
u64 hash;
Vulkan::Liverpool::ComputeProgram cs_program{}; Vulkan::Liverpool::ComputeProgram cs_program{};
std::vector<u32> code{}; std::vector<u32> code{};
}; };

View File

@ -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(); const auto& ctx = *GetCurrentContext();
if (batch_view.open) { if (batch_view.open) {
@ -1285,6 +1285,41 @@ void CmdListViewer::Draw(bool only_batches_view) {
} }
auto& batch = std::get<BatchInfo>(event); auto& batch = std::get<BatchInfo>(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 = auto const* pm4_hdr =
reinterpret_cast<PM4Header const*>(cmdb_addr + batch.start_addr); reinterpret_cast<PM4Header const*>(cmdb_addr + batch.start_addr);

View File

@ -35,6 +35,10 @@ void ParseDepthControl(u32 value, bool begin_table = true);
void ParseEqaa(u32 value, bool begin_table = true); void ParseEqaa(u32 value, bool begin_table = true);
void ParseZInfo(u32 value, bool begin_table = true); void ParseZInfo(u32 value, bool begin_table = true);
struct CmdListFilter {
char shader_name[128]{};
};
class CmdListViewer { class CmdListViewer {
DebugStateType::FrameDump* frame_dump; DebugStateType::FrameDump* frame_dump;
@ -70,7 +74,7 @@ public:
explicit CmdListViewer(DebugStateType::FrameDump* frame_dump, const std::vector<u32>& cmd_list, explicit CmdListViewer(DebugStateType::FrameDump* frame_dump, const std::vector<u32>& cmd_list,
uintptr_t base_addr = 0, std::string name = ""); 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 } // namespace Core::Devtools::Widget

View File

@ -117,7 +117,7 @@ static bool IsDrawCall(AmdGpu::PM4ItOpcode opcode) {
inline std::optional<std::string> exec_cli(const char* cli) { inline std::optional<std::string> exec_cli(const char* cli) {
std::array<char, 64> buffer{}; std::array<char, 64> buffer{};
std::string output; std::string output;
const auto f = popen(cli, "rt"); const auto f = popen(cli, "r");
if (!f) { if (!f) {
pclose(f); pclose(f);
return {}; return {};

View File

@ -132,6 +132,15 @@ void FrameDumpViewer::Draw() {
} }
} }
EndDisabled(); EndDisabled();
SameLine();
if (BeginMenu("Filter")) {
TextUnformatted("Shader name");
SameLine();
InputText("##filter_shader", filter.shader_name, sizeof(filter.shader_name));
ImGui::EndMenu();
}
TextEx("Submit num"); TextEx("Submit num");
SameLine(); SameLine();
@ -187,7 +196,7 @@ void FrameDumpViewer::Draw() {
EndGroup(); EndGroup();
} }
if (is_showing && selected_cmd != -1) { if (is_showing && selected_cmd != -1) {
cmd_list_viewer[selected_cmd].Draw(is_collapsed); cmd_list_viewer[selected_cmd].Draw(is_collapsed, filter);
} }
End(); End();
} }

View File

@ -27,6 +27,8 @@ class FrameDumpViewer {
s32 selected_queue_num2; s32 selected_queue_num2;
s32 selected_cmd = -1; s32 selected_cmd = -1;
CmdListFilter filter;
public: public:
bool is_open = true; bool is_open = true;

View File

@ -19,6 +19,57 @@ constexpr float BAR_HEIGHT_MULT = 1.25f;
constexpr float FRAME_GRAPH_PADDING_Y = 3.0f; constexpr float FRAME_GRAPH_PADDING_Y = 3.0f;
constexpr static float FRAME_GRAPH_HEIGHT = 50.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() { void FrameGraph::Draw() {
if (!is_open) { if (!is_open) {
return; return;
@ -43,55 +94,9 @@ void FrameGraph::Draw() {
Text("Frame time: %.3f ms (%.1f FPS)", deltaTime, frameRate); Text("Frame time: %.3f ms (%.1f FPS)", deltaTime, frameRate);
Text("Flip frame: %d Gnm submit frame: %d", DebugState.flip_frame_count.load(), Text("Flip frame: %d Gnm submit frame: %d", DebugState.flip_frame_count.load(),
DebugState.gnm_frame_count.load()); DebugState.gnm_frame_count.load());
SeparatorText("Frame graph"); SeparatorText("Frame graph");
DrawFrameGraph();
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();
} }
End(); End();
} }

View File

@ -16,6 +16,8 @@ class FrameGraph {
std::array<FrameInfo, FRAME_BUFFER_SIZE> frame_list{}; std::array<FrameInfo, FRAME_BUFFER_SIZE> frame_list{};
void DrawFrameGraph();
public: public:
bool is_open = true; bool is_open = true;

View File

@ -292,6 +292,17 @@ void RegView::Draw() {
EndMenuBar(); 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 && if (!data.is_compute &&
BeginChild("STAGES", {}, BeginChild("STAGES", {},
ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_AutoResizeY)) { ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_AutoResizeY)) {

View File

@ -112,6 +112,10 @@ bool ShaderList::Selection::DrawShader(DebugStateType::ShaderDump& value) {
ReloadShader(value); ReloadShader(value);
} }
} }
SameLine();
if (Button("Copy name")) {
SetClipboardText(value.name.c_str());
}
if (value.is_patched) { if (value.is_patched) {
if (BeginCombo("Shader type", showing_bin ? "SPIRV" : "GLSL", if (BeginCombo("Shader type", showing_bin ? "SPIRV" : "GLSL",
@ -229,9 +233,16 @@ void ShaderList::Draw() {
return; return;
} }
InputTextEx("##search_shader", "Search by name", search_box, sizeof(search_box), {},
ImGuiInputTextFlags_None);
auto width = GetContentRegionAvail().x; auto width = GetContentRegionAvail().x;
int i = 0; int i = 0;
for (const auto& shader : DebugState.shader_dump_list) { for (const auto& shader : DebugState.shader_dump_list) {
if (search_box[0] != '\0' && !shader.name.contains(search_box)) {
i++;
continue;
}
char name[128]; char name[128];
if (shader.is_patched) { if (shader.is_patched) {
snprintf(name, sizeof(name), "%s (PATCH ON)", shader.name.c_str()); snprintf(name, sizeof(name), "%s (PATCH ON)", shader.name.c_str());

View File

@ -31,6 +31,8 @@ class ShaderList {
std::vector<Selection> open_shaders{}; std::vector<Selection> open_shaders{};
char search_box[128]{};
public: public:
bool open = false; bool open = false;

View File

@ -145,8 +145,10 @@ int PS4_SYSV_ABI sceAppContentDownloadDataFormat() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceAppContentDownloadDataGetAvailableSpaceKb() { int PS4_SYSV_ABI sceAppContentDownloadDataGetAvailableSpaceKb(OrbisAppContentMountPoint* mountPoint,
u64* availableSpaceKb) {
LOG_ERROR(Lib_AppContent, "(STUBBED) called"); LOG_ERROR(Lib_AppContent, "(STUBBED) called");
*availableSpaceKb = 1048576;
return ORBIS_OK; return ORBIS_OK;
} }
@ -294,9 +296,9 @@ int PS4_SYSV_ABI sceAppContentTemporaryDataFormat() {
} }
int PS4_SYSV_ABI sceAppContentTemporaryDataGetAvailableSpaceKb( int PS4_SYSV_ABI sceAppContentTemporaryDataGetAvailableSpaceKb(
const OrbisAppContentMountPoint* mountPoint, size_t* availableSpaceKb) { const OrbisAppContentMountPoint* mountPoint, u64* availableSpaceKb) {
LOG_ERROR(Lib_AppContent, "(STUBBED) called"); LOG_ERROR(Lib_AppContent, "(STUBBED) called");
*availableSpaceKb = 1073741824; *availableSpaceKb = 1048576;
return ORBIS_OK; return ORBIS_OK;
} }

View File

@ -84,7 +84,8 @@ int PS4_SYSV_ABI sceAppContentDownload0Shrink();
int PS4_SYSV_ABI sceAppContentDownload1Expand(); int PS4_SYSV_ABI sceAppContentDownload1Expand();
int PS4_SYSV_ABI sceAppContentDownload1Shrink(); int PS4_SYSV_ABI sceAppContentDownload1Shrink();
int PS4_SYSV_ABI sceAppContentDownloadDataFormat(); 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 sceAppContentGetAddcontDownloadProgress();
int PS4_SYSV_ABI sceAppContentGetAddcontInfo(u32 service_label, int PS4_SYSV_ABI sceAppContentGetAddcontInfo(u32 service_label,
const OrbisNpUnifiedEntitlementLabel* entitlementLabel, const OrbisNpUnifiedEntitlementLabel* entitlementLabel,
@ -105,7 +106,7 @@ int PS4_SYSV_ABI sceAppContentSmallSharedDataMount();
int PS4_SYSV_ABI sceAppContentSmallSharedDataUnmount(); int PS4_SYSV_ABI sceAppContentSmallSharedDataUnmount();
int PS4_SYSV_ABI sceAppContentTemporaryDataFormat(); int PS4_SYSV_ABI sceAppContentTemporaryDataFormat();
int PS4_SYSV_ABI sceAppContentTemporaryDataGetAvailableSpaceKb( 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 sceAppContentTemporaryDataMount();
int PS4_SYSV_ABI sceAppContentTemporaryDataMount2(OrbisAppContentTemporaryDataOption option, int PS4_SYSV_ABI sceAppContentTemporaryDataMount2(OrbisAppContentTemporaryDataOption option,
OrbisAppContentMountPoint* mountPoint); OrbisAppContentMountPoint* mountPoint);

View File

@ -1,281 +1,484 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "fiber.h" #include "fiber.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/libraries/fiber/fiber_error.h" #include "core/libraries/fiber/fiber_error.h"
#include "core/libraries/libs.h" #include "core/libraries/libs.h"
#include "core/tls.h" #include "core/tls.h"
#ifdef _WIN64 namespace Libraries::Fiber {
#include <windows.h>
#endif static constexpr u32 kFiberSignature0 = 0xdef1649c;
static constexpr u32 kFiberSignature1 = 0xb37592a0;
namespace Libraries::Fiber { static constexpr u32 kFiberOptSignature = 0xbb40e64d;
static constexpr u64 kFiberStackSignature = 0x7149f2ca7149f2ca;
static constexpr u64 kFiberSignature = 0x054ad954; static constexpr u64 kFiberStackSizeCheck = 0xdeadbeefdeadbeef;
thread_local SceFiber* gCurrentFiber = nullptr; static std::atomic<u32> context_size_check = false;
thread_local void* gFiberThread = nullptr;
OrbisFiberContext* GetFiberContext() {
void FiberEntry(void* param) { return Core::GetTcbBase()->tcb_fiber;
SceFiber* fiber = static_cast<SceFiber*>(param); }
u64 argRun = 0;
u64 argRet = 0; extern "C" s32 PS4_SYSV_ABI _sceFiberSetJmp(OrbisFiberContext* ctx) asm("_sceFiberSetJmp");
extern "C" s32 PS4_SYSV_ABI _sceFiberLongJmp(OrbisFiberContext* ctx) asm("_sceFiberLongJmp");
gCurrentFiber = fiber; extern "C" void PS4_SYSV_ABI _sceFiberSwitchEntry(OrbisFiberData* data,
bool set_fpu) asm("_sceFiberSwitchEntry");
if (fiber->pArgRun != nullptr) { extern "C" void PS4_SYSV_ABI _sceFiberForceQuit(u64 ret) asm("_sceFiberForceQuit");
argRun = *fiber->pArgRun;
} extern "C" void PS4_SYSV_ABI _sceFiberForceQuit(u64 ret) {
OrbisFiberContext* g_ctx = GetFiberContext();
Core::ExecuteGuest(fiber->entry, fiber->argOnInitialize, argRun); g_ctx->return_val = ret;
UNREACHABLE(); _sceFiberLongJmp(g_ctx);
} }
s32 PS4_SYSV_ABI sceFiberInitialize(SceFiber* fiber, const char* name, SceFiberEntry entry, void PS4_SYSV_ABI _sceFiberCheckStackOverflow(OrbisFiberContext* ctx) {
u64 argOnInitialize, void* addrContext, u64 sizeContext, u64* stack_base = reinterpret_cast<u64*>(ctx->current_fiber->addr_context);
const SceFiberOptParam* optParam) { if (stack_base && *stack_base != kFiberStackSignature) {
LOG_INFO(Lib_Fiber, "called: name = {}", name); UNREACHABLE_MSG("Stack overflow detected in fiber.");
}
if (!fiber || !name || !entry) { }
return ORBIS_FIBER_ERROR_NULL;
} void PS4_SYSV_ABI _sceFiberSwitchToFiber(OrbisFiber* fiber, u64 arg_on_run_to,
OrbisFiberContext* ctx) {
fiber->signature = kFiberSignature; OrbisFiberContext* fiber_ctx = fiber->context;
if (fiber_ctx) {
fiber->entry = entry; ctx->arg_on_run_to = arg_on_run_to;
fiber->argOnInitialize = argOnInitialize; _sceFiberLongJmp(fiber_ctx);
__builtin_trap();
fiber->argRun = 0; }
fiber->pArgRun = &fiber->argRun;
fiber->argReturn = 0; OrbisFiberData data{};
fiber->pArgReturn = &fiber->argReturn; if (ctx->prev_fiber) {
OrbisFiber* prev_fiber = ctx->prev_fiber;
fiber->sizeContext = sizeContext; ctx->prev_fiber = nullptr;
data.state = reinterpret_cast<u32*>(&prev_fiber->state);
fiber->state = FiberState::Init; } else {
#ifdef _WIN64 data.state = nullptr;
fiber->handle = CreateFiber(sizeContext, FiberEntry, fiber); }
#else
UNREACHABLE_MSG("Missing implementation"); data.entry = fiber->entry;
#endif data.arg_on_initialize = fiber->arg_on_initialize;
strncpy(fiber->name, name, ORBIS_FIBER_MAX_NAME_LENGTH); data.arg_on_run_to = arg_on_run_to;
data.stack_addr =
return ORBIS_OK; reinterpret_cast<void*>(reinterpret_cast<u64>(fiber->addr_context) + fiber->size_context);
} if (fiber->flags & FiberFlags::SetFpuRegs) {
data.fpucw = 0x037f;
s32 PS4_SYSV_ABI sceFiberOptParamInitialize(SceFiberOptParam* optParam) { data.mxcsr = 0x9fc0;
LOG_ERROR(Lib_Fiber, "called"); _sceFiberSwitchEntry(&data, true);
} else {
if (!optParam) { _sceFiberSwitchEntry(&data, false);
return ORBIS_FIBER_ERROR_NULL; }
}
__builtin_trap();
return ORBIS_OK; }
}
void PS4_SYSV_ABI _sceFiberSwitch(OrbisFiber* cur_fiber, OrbisFiber* fiber, u64 arg_on_run_to,
s32 PS4_SYSV_ABI sceFiberFinalize(SceFiber* fiber) { OrbisFiberContext* ctx) {
LOG_TRACE(Lib_Fiber, "called"); ctx->prev_fiber = cur_fiber;
ctx->current_fiber = fiber;
if (!fiber) {
return ORBIS_FIBER_ERROR_NULL; if (fiber->addr_context == nullptr) {
} ctx->prev_fiber = nullptr;
if ((u64)fiber % 8 != 0) {
return ORBIS_FIBER_ERROR_ALIGNMENT; OrbisFiberData data{};
} data.entry = fiber->entry;
if (fiber->signature != kFiberSignature) { data.arg_on_initialize = fiber->arg_on_initialize;
return ORBIS_FIBER_ERROR_INVALID; data.arg_on_run_to = arg_on_run_to;
} data.stack_addr = reinterpret_cast<void*>(ctx->rsp & ~15);
if (fiber->state != FiberState::Run) { data.state = reinterpret_cast<u32*>(&cur_fiber->state);
return ORBIS_FIBER_ERROR_STATE;
} if (fiber->flags & FiberFlags::SetFpuRegs) {
data.fpucw = 0x037f;
fiber->signature = 0; data.mxcsr = 0x9fc0;
fiber->state = FiberState::None; _sceFiberSwitchEntry(&data, true);
} else {
#ifdef _WIN64 _sceFiberSwitchEntry(&data, false);
DeleteFiber(fiber->handle); }
#else
UNREACHABLE_MSG("Missing implementation"); __builtin_trap();
#endif }
return ORBIS_OK;
} _sceFiberSwitchToFiber(fiber, arg_on_run_to, ctx);
__builtin_trap();
s32 PS4_SYSV_ABI sceFiberRun(SceFiber* fiber, u64 argOnRunTo, u64* argOnReturn) { }
LOG_TRACE(Lib_Fiber, "called");
void PS4_SYSV_ABI _sceFiberTerminate(OrbisFiber* fiber, u64 arg_on_return, OrbisFiberContext* ctx) {
if (!fiber) { ctx->arg_on_return = arg_on_return;
return ORBIS_FIBER_ERROR_NULL; _sceFiberLongJmp(ctx);
} __builtin_trap();
if ((u64)fiber % 8 != 0) { }
return ORBIS_FIBER_ERROR_ALIGNMENT;
} s32 PS4_SYSV_ABI sceFiberInitialize(OrbisFiber* fiber, const char* name, OrbisFiberEntry entry,
if (fiber->signature != kFiberSignature) { u64 arg_on_initialize, void* addr_context, u64 size_context,
return ORBIS_FIBER_ERROR_INVALID; const OrbisFiberOptParam* opt_param, u32 build_ver) {
} if (!fiber || !name || !entry) {
if (fiber->state == FiberState::Run) { return ORBIS_FIBER_ERROR_NULL;
return ORBIS_FIBER_ERROR_STATE; }
} if ((u64)fiber & 7 || (u64)addr_context & 15) {
return ORBIS_FIBER_ERROR_ALIGNMENT;
if (gFiberThread == nullptr) { }
#ifdef _WIN64 if (opt_param && (u64)opt_param & 7) {
gFiberThread = ConvertThreadToFiber(nullptr); return ORBIS_FIBER_ERROR_ALIGNMENT;
#else }
UNREACHABLE_MSG("Missing implementation"); if (size_context && size_context < ORBIS_FIBER_CONTEXT_MINIMUM_SIZE) {
#endif return ORBIS_FIBER_ERROR_RANGE;
} }
if (size_context & 15) {
gCurrentFiber = fiber; return ORBIS_FIBER_ERROR_INVALID;
}
if (fiber->pArgRun != nullptr) { if (!addr_context && size_context) {
*fiber->pArgRun = argOnRunTo; return ORBIS_FIBER_ERROR_INVALID;
} }
if (addr_context && !size_context) {
fiber->pArgReturn = argOnReturn; return ORBIS_FIBER_ERROR_INVALID;
fiber->state = FiberState::Run; }
#ifdef _WIN64 if (opt_param && opt_param->magic != kFiberOptSignature) {
SwitchToFiber(fiber->handle); return ORBIS_FIBER_ERROR_INVALID;
#else }
UNREACHABLE_MSG("Missing implementation");
#endif u32 flags = FiberFlags::None;
return ORBIS_OK; if (build_ver >= 0x3500000) {
} flags |= FiberFlags::SetFpuRegs;
}
s32 PS4_SYSV_ABI sceFiberSwitch(SceFiber* fiber, u64 argOnRunTo, u64* argOnRun) { if (context_size_check) {
LOG_TRACE(Lib_Fiber, "called"); flags |= FiberFlags::ContextSizeCheck;
}
if (!fiber) {
return ORBIS_FIBER_ERROR_NULL; strncpy(fiber->name, name, ORBIS_FIBER_MAX_NAME_LENGTH);
}
if ((u64)fiber % 8 != 0) { fiber->entry = entry;
return ORBIS_FIBER_ERROR_ALIGNMENT; fiber->arg_on_initialize = arg_on_initialize;
} fiber->addr_context = addr_context;
if (fiber->signature != kFiberSignature) { fiber->size_context = size_context;
return ORBIS_FIBER_ERROR_INVALID; fiber->context = nullptr;
} fiber->flags = flags;
if (gCurrentFiber == nullptr) {
return ORBIS_FIBER_ERROR_PERMISSION; /*
} A low stack area is problematic, as we can easily
if (fiber->state == FiberState::Run) { cause a stack overflow with our HLE.
return ORBIS_FIBER_ERROR_STATE; */
} if (size_context && size_context <= 4096) {
LOG_WARNING(Lib_Fiber, "Fiber initialized with small stack area.");
gCurrentFiber->state = FiberState::Suspend; }
// TODO: argOnRun fiber->magic_start = kFiberSignature0;
fiber->magic_end = kFiberSignature1;
*fiber->pArgRun = argOnRunTo;
fiber->state = FiberState::Run; if (addr_context != nullptr) {
fiber->context_start = addr_context;
gCurrentFiber = fiber; fiber->context_end =
#ifdef _WIN64 reinterpret_cast<void*>(reinterpret_cast<u64>(addr_context) + size_context);
SwitchToFiber(fiber->handle);
#else /* Apply signature to start of stack */
UNREACHABLE_MSG("Missing implementation"); *(u64*)addr_context = kFiberStackSignature;
#endif
return ORBIS_OK; if (flags & FiberFlags::ContextSizeCheck) {
} u64* stack_start = reinterpret_cast<u64*>(fiber->context_start);
u64* stack_end = reinterpret_cast<u64*>(fiber->context_end);
s32 PS4_SYSV_ABI sceFiberGetSelf(SceFiber** fiber) {
LOG_TRACE(Lib_Fiber, "called"); u64* stack_ptr = stack_start + 1;
while (stack_ptr < stack_end) {
if (!fiber || !gCurrentFiber) { *stack_ptr++ = kFiberStackSizeCheck;
return ORBIS_FIBER_ERROR_NULL; }
} }
if (gCurrentFiber->signature != kFiberSignature) { }
return ORBIS_FIBER_ERROR_PERMISSION;
} fiber->state = FiberState::Idle;
return ORBIS_OK;
*fiber = gCurrentFiber; }
return ORBIS_OK;
} s32 PS4_SYSV_ABI sceFiberOptParamInitialize(OrbisFiberOptParam* opt_param) {
if (!opt_param) {
s32 PS4_SYSV_ABI sceFiberReturnToThread(u64 argOnReturn, u64* argOnRun) { return ORBIS_FIBER_ERROR_NULL;
LOG_TRACE(Lib_Fiber, "called"); }
if ((u64)opt_param & 7) {
if (gCurrentFiber->signature != kFiberSignature) { return ORBIS_FIBER_ERROR_ALIGNMENT;
return ORBIS_FIBER_ERROR_PERMISSION; }
}
opt_param->magic = kFiberOptSignature;
if (gCurrentFiber->pArgReturn != nullptr) { return ORBIS_OK;
*gCurrentFiber->pArgReturn = argOnReturn; }
}
s32 PS4_SYSV_ABI sceFiberFinalize(OrbisFiber* fiber) {
// TODO: argOnRun if (!fiber) {
gCurrentFiber->state = FiberState::Suspend; return ORBIS_FIBER_ERROR_NULL;
gCurrentFiber = nullptr; }
#ifdef _WIN64 if ((u64)fiber & 7) {
SwitchToFiber(gFiberThread); return ORBIS_FIBER_ERROR_ALIGNMENT;
#else }
UNREACHABLE_MSG("Missing implementation"); if (fiber->magic_start != kFiberSignature0 || fiber->magic_end != kFiberSignature1) {
#endif return ORBIS_FIBER_ERROR_INVALID;
return ORBIS_OK; }
}
FiberState expected = FiberState::Idle;
s32 PS4_SYSV_ABI sceFiberGetInfo(SceFiber* fiber, SceFiberInfo* fiberInfo) { if (!fiber->state.compare_exchange_strong(expected, FiberState::Terminated)) {
LOG_INFO(Lib_Fiber, "called"); return ORBIS_FIBER_ERROR_STATE;
}
if (!fiber || !fiberInfo) {
return ORBIS_FIBER_ERROR_NULL; return ORBIS_OK;
} }
fiberInfo->entry = fiber->entry; s32 PS4_SYSV_ABI sceFiberRun(OrbisFiber* fiber, u64 arg_on_run_to, u64* arg_on_return) {
fiberInfo->argOnInitialize = fiber->argOnInitialize; if (!fiber) {
fiberInfo->addrContext = nullptr; return ORBIS_FIBER_ERROR_NULL;
fiberInfo->sizeContext = fiber->sizeContext; }
fiberInfo->sizeContextMargin = 0; if ((u64)fiber & 7) {
return ORBIS_FIBER_ERROR_ALIGNMENT;
strncpy(fiberInfo->name, fiber->name, ORBIS_FIBER_MAX_NAME_LENGTH); }
return ORBIS_OK; if (fiber->magic_start != kFiberSignature0 || fiber->magic_end != kFiberSignature1) {
} return ORBIS_FIBER_ERROR_INVALID;
}
s32 PS4_SYSV_ABI sceFiberStartContextSizeCheck(u32 flags) {
LOG_ERROR(Lib_Fiber, "called"); Core::Tcb* tcb = Core::GetTcbBase();
if (tcb->tcb_fiber) {
if (flags != 0) { return ORBIS_FIBER_ERROR_PERMISSION;
return ORBIS_FIBER_ERROR_INVALID; }
}
FiberState expected = FiberState::Idle;
return ORBIS_OK; if (!fiber->state.compare_exchange_strong(expected, FiberState::Run)) {
} return ORBIS_FIBER_ERROR_STATE;
}
s32 PS4_SYSV_ABI sceFiberStopContextSizeCheck() {
LOG_ERROR(Lib_Fiber, "called"); OrbisFiberContext ctx{};
return ORBIS_OK; ctx.current_fiber = fiber;
} ctx.prev_fiber = nullptr;
ctx.return_val = 0;
s32 PS4_SYSV_ABI sceFiberRename(SceFiber* fiber, const char* name) {
LOG_INFO(Lib_Fiber, "called, name = {}", name); tcb->tcb_fiber = &ctx;
if (!fiber || !name) { s32 jmp = _sceFiberSetJmp(&ctx);
return ORBIS_FIBER_ERROR_NULL; if (!jmp) {
} if (fiber->addr_context) {
if ((u64)fiber % 8 != 0) { _sceFiberSwitchToFiber(fiber, arg_on_run_to, &ctx);
return ORBIS_FIBER_ERROR_ALIGNMENT; __builtin_trap();
} }
strncpy(fiber->name, name, ORBIS_FIBER_MAX_NAME_LENGTH); OrbisFiberData data{};
return ORBIS_OK; data.entry = fiber->entry;
} data.arg_on_initialize = fiber->arg_on_initialize;
data.arg_on_run_to = arg_on_run_to;
void RegisterlibSceFiber(Core::Loader::SymbolsResolver* sym) { data.stack_addr = reinterpret_cast<void*>(ctx.rsp & ~15);
LIB_FUNCTION("hVYD7Ou2pCQ", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberInitialize); data.state = nullptr;
LIB_FUNCTION("asjUJJ+aa8s", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberOptParamInitialize); if (fiber->flags & FiberFlags::SetFpuRegs) {
LIB_FUNCTION("JeNX5F-NzQU", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberFinalize); data.fpucw = 0x037f;
data.mxcsr = 0x9fc0;
LIB_FUNCTION("a0LLrZWac0M", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberRun); _sceFiberSwitchEntry(&data, true);
LIB_FUNCTION("PFT2S-tJ7Uk", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberSwitch); } else {
LIB_FUNCTION("p+zLIOg27zU", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberGetSelf); _sceFiberSwitchEntry(&data, false);
LIB_FUNCTION("B0ZX2hx9DMw", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberReturnToThread); }
}
LIB_FUNCTION("uq2Y5BFz0PE", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberGetInfo);
LIB_FUNCTION("Lcqty+QNWFc", "libSceFiber", 1, "libSceFiber", 1, 1, OrbisFiber* cur_fiber = ctx.current_fiber;
sceFiberStartContextSizeCheck); ctx.current_fiber = nullptr;
LIB_FUNCTION("Kj4nXMpnM8Y", "libSceFiber", 1, "libSceFiber", 1, 1, cur_fiber->state = FiberState::Idle;
sceFiberStopContextSizeCheck);
LIB_FUNCTION("JzyT91ucGDc", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberRename); if (ctx.return_val != 0) {
} /* Fiber entry returned! This should never happen. */
UNREACHABLE_MSG("Fiber entry function returned.");
} // namespace Libraries::Fiber }
if (arg_on_return) {
*arg_on_return = ctx.arg_on_return;
}
tcb->tcb_fiber = nullptr;
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceFiberSwitch(OrbisFiber* fiber, u64 arg_on_run_to, u64* arg_on_run) {
if (!fiber) {
return ORBIS_FIBER_ERROR_NULL;
}
if ((u64)fiber & 7) {
return ORBIS_FIBER_ERROR_ALIGNMENT;
}
if (fiber->magic_start != kFiberSignature0 || fiber->magic_end != kFiberSignature1) {
return ORBIS_FIBER_ERROR_INVALID;
}
OrbisFiberContext* g_ctx = GetFiberContext();
if (!g_ctx) {
return ORBIS_FIBER_ERROR_PERMISSION;
}
FiberState expected = FiberState::Idle;
if (!fiber->state.compare_exchange_strong(expected, FiberState::Run)) {
return ORBIS_FIBER_ERROR_STATE;
}
OrbisFiber* cur_fiber = g_ctx->current_fiber;
if (cur_fiber->addr_context == nullptr) {
_sceFiberSwitch(cur_fiber, fiber, arg_on_run_to, g_ctx);
__builtin_trap();
}
OrbisFiberContext ctx{};
s32 jmp = _sceFiberSetJmp(&ctx);
if (!jmp) {
cur_fiber->context = &ctx;
_sceFiberCheckStackOverflow(g_ctx);
_sceFiberSwitch(cur_fiber, fiber, arg_on_run_to, g_ctx);
__builtin_trap();
}
g_ctx = GetFiberContext();
if (g_ctx->prev_fiber) {
g_ctx->prev_fiber->state = FiberState::Idle;
g_ctx->prev_fiber = nullptr;
}
if (arg_on_run) {
*arg_on_run = g_ctx->arg_on_run_to;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceFiberGetSelf(OrbisFiber** fiber) {
if (!fiber) {
return ORBIS_FIBER_ERROR_NULL;
}
OrbisFiberContext* g_ctx = GetFiberContext();
if (!g_ctx) {
return ORBIS_FIBER_ERROR_PERMISSION;
}
*fiber = g_ctx->current_fiber;
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceFiberReturnToThread(u64 arg_on_return, u64* arg_on_run) {
OrbisFiberContext* g_ctx = GetFiberContext();
if (!g_ctx) {
return ORBIS_FIBER_ERROR_PERMISSION;
}
OrbisFiber* cur_fiber = g_ctx->current_fiber;
if (cur_fiber->addr_context) {
OrbisFiberContext ctx{};
s32 jmp = _sceFiberSetJmp(&ctx);
if (jmp) {
g_ctx = GetFiberContext();
if (g_ctx->prev_fiber) {
g_ctx->prev_fiber->state = FiberState::Idle;
g_ctx->prev_fiber = nullptr;
}
if (arg_on_run) {
*arg_on_run = g_ctx->arg_on_run_to;
}
return ORBIS_OK;
}
cur_fiber->context = &ctx;
_sceFiberCheckStackOverflow(g_ctx);
}
_sceFiberTerminate(cur_fiber, arg_on_return, g_ctx);
__builtin_trap();
}
s32 PS4_SYSV_ABI sceFiberGetInfo(OrbisFiber* fiber, OrbisFiberInfo* fiber_info) {
if (!fiber || !fiber_info) {
return ORBIS_FIBER_ERROR_NULL;
}
if ((u64)fiber & 7 || (u64)fiber_info & 7) {
return ORBIS_FIBER_ERROR_ALIGNMENT;
}
if (fiber_info->size != sizeof(OrbisFiberInfo)) {
return ORBIS_FIBER_ERROR_INVALID;
}
if (fiber->magic_start != kFiberSignature0 || fiber->magic_end != kFiberSignature1) {
return ORBIS_FIBER_ERROR_INVALID;
}
fiber_info->entry = fiber->entry;
fiber_info->arg_on_initialize = fiber->arg_on_initialize;
fiber_info->addr_context = fiber->addr_context;
fiber_info->size_context = fiber->size_context;
strncpy(fiber_info->name, fiber->name, ORBIS_FIBER_MAX_NAME_LENGTH);
fiber_info->size_context_margin = -1;
if (fiber->flags & FiberFlags::ContextSizeCheck && fiber->addr_context != nullptr) {
u64 stack_margin = 0;
u64* stack_start = reinterpret_cast<u64*>(fiber->context_start);
u64* stack_end = reinterpret_cast<u64*>(fiber->context_end);
if (*stack_start == kFiberStackSignature) {
u64* stack_ptr = stack_start + 1;
while (stack_ptr < stack_end) {
if (*stack_ptr == kFiberStackSizeCheck) {
stack_ptr++;
}
}
stack_margin =
reinterpret_cast<u64>(stack_ptr) - reinterpret_cast<u64>(stack_start + 1);
}
fiber_info->size_context_margin = stack_margin;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceFiberStartContextSizeCheck(u32 flags) {
if (flags != 0) {
return ORBIS_FIBER_ERROR_INVALID;
}
u32 expected = 0;
if (!context_size_check.compare_exchange_strong(expected, 1u)) {
return ORBIS_FIBER_ERROR_STATE;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceFiberStopContextSizeCheck() {
u32 expected = 1;
if (!context_size_check.compare_exchange_strong(expected, 0u)) {
return ORBIS_FIBER_ERROR_STATE;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceFiberRename(OrbisFiber* fiber, const char* name) {
if (!fiber || !name) {
return ORBIS_FIBER_ERROR_NULL;
}
if ((u64)fiber & 7) {
return ORBIS_FIBER_ERROR_ALIGNMENT;
}
if (fiber->magic_start != kFiberSignature0 || fiber->magic_end != kFiberSignature1) {
return ORBIS_FIBER_ERROR_INVALID;
}
strncpy(fiber->name, name, ORBIS_FIBER_MAX_NAME_LENGTH);
return ORBIS_OK;
}
void RegisterlibSceFiber(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("hVYD7Ou2pCQ", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberInitialize);
LIB_FUNCTION("7+OJIpko9RY", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberInitialize);
LIB_FUNCTION("asjUJJ+aa8s", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberOptParamInitialize);
LIB_FUNCTION("JeNX5F-NzQU", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberFinalize);
LIB_FUNCTION("a0LLrZWac0M", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberRun);
LIB_FUNCTION("PFT2S-tJ7Uk", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberSwitch);
LIB_FUNCTION("p+zLIOg27zU", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberGetSelf);
LIB_FUNCTION("B0ZX2hx9DMw", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberReturnToThread);
LIB_FUNCTION("uq2Y5BFz0PE", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberGetInfo);
LIB_FUNCTION("Lcqty+QNWFc", "libSceFiber", 1, "libSceFiber", 1, 1,
sceFiberStartContextSizeCheck);
LIB_FUNCTION("Kj4nXMpnM8Y", "libSceFiber", 1, "libSceFiber", 1, 1,
sceFiberStopContextSizeCheck);
LIB_FUNCTION("JzyT91ucGDc", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberRename);
}
} // namespace Libraries::Fiber

View File

@ -1,78 +1,118 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include "common/assert.h" #include "common/assert.h"
#include "common/types.h" #include "common/types.h"
namespace Core::Loader { #include <atomic>
class SymbolsResolver;
} namespace Core::Loader {
namespace Libraries::Fiber { class SymbolsResolver;
}
#define ORBIS_FIBER_MAX_NAME_LENGTH (31) namespace Libraries::Fiber {
typedef void PS4_SYSV_ABI (*SceFiberEntry)(u64 argOnInitialize, u64 argOnRun); #define ORBIS_FIBER_MAX_NAME_LENGTH (31)
#define ORBIS_FIBER_CONTEXT_MINIMUM_SIZE (512)
enum FiberState : u32 {
None = 0u, typedef void PS4_SYSV_ABI (*OrbisFiberEntry)(u64 arg_on_initialize, u64 arg_on_run);
Init = 1u,
Run = 2u, enum FiberState : u32 {
Suspend = 3u, Run = 1u,
}; Idle = 2u,
Terminated = 3u,
struct SceFiber { };
u64 signature;
FiberState state; enum FiberFlags : u32 {
SceFiberEntry entry; None = 0x0,
u64 argOnInitialize; NoUlobjmgr = 0x1,
u64 argRun; ContextSizeCheck = 0x10,
u64* pArgRun; SetFpuRegs = 0x100,
u64 argReturn; };
u64* pArgReturn;
u64 sizeContext; struct OrbisFiber;
char name[ORBIS_FIBER_MAX_NAME_LENGTH];
void* handle; struct OrbisFiberContext {
}; struct {
static_assert(sizeof(SceFiber) <= 256); u64 rax, rcx, rdx, rbx, rsp, rbp, r8, r9, r10, r11, r12, r13, r14, r15;
u16 fpucw;
struct SceFiberInfo { u32 mxcsr;
u64 size; };
SceFiberEntry entry; OrbisFiber* current_fiber;
u64 argOnInitialize; OrbisFiber* prev_fiber;
void* addrContext; u64 arg_on_run_to;
u64 sizeContext; u64 arg_on_return;
char name[ORBIS_FIBER_MAX_NAME_LENGTH + 1]; u64 return_val;
u64 sizeContextMargin; };
};
static_assert(sizeof(SceFiberInfo) <= 128); struct OrbisFiberData {
OrbisFiberEntry entry;
using SceFiberOptParam = void*; u64 arg_on_initialize;
u64 arg_on_run_to;
s32 PS4_SYSV_ABI sceFiberInitialize(SceFiber* fiber, const char* name, SceFiberEntry entry, void* stack_addr;
u64 argOnInitialize, void* addrContext, u64 sizeContext, u32* state;
const SceFiberOptParam* optParam); u16 fpucw;
s8 pad[2];
s32 PS4_SYSV_ABI sceFiberOptParamInitialize(SceFiberOptParam* optParam); u32 mxcsr;
};
s32 PS4_SYSV_ABI sceFiberFinalize(SceFiber* fiber);
struct OrbisFiber {
s32 PS4_SYSV_ABI sceFiberRun(SceFiber* fiber, u64 argOnRunTo, u64* argOnReturn); u32 magic_start;
std::atomic<FiberState> state;
s32 PS4_SYSV_ABI sceFiberSwitch(SceFiber* fiber, u64 argOnRunTo, u64* argOnRun); OrbisFiberEntry entry;
u64 arg_on_initialize;
s32 PS4_SYSV_ABI sceFiberGetSelf(SceFiber** fiber); void* addr_context;
u64 size_context;
s32 PS4_SYSV_ABI sceFiberReturnToThread(u64 argOnReturn, u64* argOnRun); char name[ORBIS_FIBER_MAX_NAME_LENGTH + 1];
OrbisFiberContext* context;
s32 PS4_SYSV_ABI sceFiberGetInfo(SceFiber* fiber, SceFiberInfo* fiberInfo); u32 flags;
void* context_start;
s32 PS4_SYSV_ABI sceFiberStartContextSizeCheck(u32 flags); void* context_end;
u32 magic_end;
s32 PS4_SYSV_ABI sceFiberStopContextSizeCheck(void); };
static_assert(sizeof(OrbisFiber) <= 256);
s32 PS4_SYSV_ABI sceFiberRename(SceFiber* fiber, const char* name);
struct OrbisFiberInfo {
void RegisterlibSceFiber(Core::Loader::SymbolsResolver* sym); u64 size;
OrbisFiberEntry entry;
u64 arg_on_initialize;
void* addr_context;
u64 size_context;
char name[ORBIS_FIBER_MAX_NAME_LENGTH + 1];
u64 size_context_margin;
u8 pad[48];
};
static_assert(sizeof(OrbisFiberInfo) == 128);
struct OrbisFiberOptParam {
u32 magic;
};
static_assert(sizeof(OrbisFiberOptParam) <= 128);
s32 PS4_SYSV_ABI sceFiberInitialize(OrbisFiber* fiber, const char* name, OrbisFiberEntry entry,
u64 arg_on_initialize, void* addr_context, u64 size_context,
const OrbisFiberOptParam* opt_param, u32 build_version);
s32 PS4_SYSV_ABI sceFiberOptParamInitialize(OrbisFiberOptParam* opt_param);
s32 PS4_SYSV_ABI sceFiberFinalize(OrbisFiber* fiber);
s32 PS4_SYSV_ABI sceFiberRun(OrbisFiber* fiber, u64 arg_on_run_to, u64* arg_on_return);
s32 PS4_SYSV_ABI sceFiberSwitch(OrbisFiber* fiber, u64 arg_on_run_to, u64* arg_on_run);
s32 PS4_SYSV_ABI sceFiberGetSelf(OrbisFiber** fiber);
s32 PS4_SYSV_ABI sceFiberReturnToThread(u64 arg_on_return, u64* arg_on_run);
s32 PS4_SYSV_ABI sceFiberGetInfo(OrbisFiber* fiber, OrbisFiberInfo* fiber_info);
s32 PS4_SYSV_ABI sceFiberStartContextSizeCheck(u32 flags);
s32 PS4_SYSV_ABI sceFiberStopContextSizeCheck(void);
s32 PS4_SYSV_ABI sceFiberRename(OrbisFiber* fiber, const char* name);
void RegisterlibSceFiber(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::Fiber } // namespace Libraries::Fiber

View File

@ -0,0 +1,121 @@
# SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
.global _sceFiberSetJmp
_sceFiberSetJmp:
movq %rax, 0x0(%rdi)
movq (%rsp), %rdx
movq %rdx, 0x10(%rdi)
movq %rcx, 0x08(%rdi)
movq %rbx, 0x18(%rdi)
movq %rsp, 0x20(%rdi)
movq %rbp, 0x28(%rdi)
movq %r8, 0x30(%rdi)
movq %r9, 0x38(%rdi)
movq %r10, 0x40(%rdi)
movq %r11, 0x48(%rdi)
movq %r12, 0x50(%rdi)
movq %r13, 0x58(%rdi)
movq %r14, 0x60(%rdi)
movq %r15, 0x68(%rdi)
fnstcw 0x70(%rdi)
stmxcsr 0x72(%rdi)
xor %eax, %eax
ret
.global _sceFiberLongJmp
_sceFiberLongJmp:
# MXCSR = (MXCSR & 0x3f) ^ (ctx->mxcsr & ~0x3f)
stmxcsr -0x4(%rsp)
movl 0x72(%rdi), %eax
andl $0xffffffc0, %eax
movl -0x4(%rsp), %ecx
andl $0x3f, %ecx
xorl %eax, %ecx
movl %ecx, -0x4(%rsp)
ldmxcsr -0x4(%rsp)
movq 0x00(%rdi), %rax
movq 0x08(%rdi), %rcx
movq 0x10(%rdi), %rdx
movq 0x18(%rdi), %rbx
movq 0x20(%rdi), %rsp
movq 0x28(%rdi), %rbp
movq 0x30(%rdi), %r8
movq 0x38(%rdi), %r9
movq 0x40(%rdi), %r10
movq 0x48(%rdi), %r11
movq 0x50(%rdi), %r12
movq 0x58(%rdi), %r13
movq 0x60(%rdi), %r14
movq 0x68(%rdi), %r15
fldcw 0x70(%rdi)
# Make the jump and return 1
movq %rdx, 0x00(%rsp)
movl $0x1, %eax
ret
.global _sceFiberSwitchEntry
_sceFiberSwitchEntry:
mov %rdi, %r11
# Set stack address to provided stack
movq 0x18(%r11), %rsp
xorl %ebp, %ebp
movq 0x20(%r11), %r10 # data->state
# Set previous fiber state to Idle
test %r10, %r10
jz .clear_regs
movl $2, (%r10)
.clear_regs:
test %esi, %esi
jz .skip_fpu_regs
ldmxcsr 0x2c(%r11)
fldcw 0x28(%r11)
.skip_fpu_regs:
movq 0x08(%r11), %rdi # data->arg_on_initialize
movq 0x10(%r11), %rsi # data->arg_on_run_to
movq 0x00(%r11), %r11 # data->entry
xorl %eax, %eax
xorl %ebx, %ebx
xorl %ecx, %ecx
xorl %edx, %edx
xorq %r8, %r8
xorq %r9, %r9
xorq %r10, %r10
xorq %r12, %r12
xorq %r13, %r13
xorq %r14, %r14
xorq %r15, %r15
pxor %mm0, %mm0
pxor %mm1, %mm1
pxor %mm2, %mm2
pxor %mm3, %mm3
pxor %mm4, %mm4
pxor %mm5, %mm5
pxor %mm6, %mm6
pxor %mm7, %mm7
emms
vzeroall
# Call the fiber's entry function: entry(arg_on_initialize, arg_on_run_to)
call *%r11
# Fiber returned, not good
movl $1, %edi
call _sceFiberForceQuit
ret

View File

@ -1,183 +1,183 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include "common/types.h" #include "common/types.h"
#include "core/libraries/rtc/rtc.h" #include "core/libraries/rtc/rtc.h"
enum class OrbisImeType : u32 { enum class OrbisImeType : u32 {
Default = 0, Default = 0,
BasicLatin = 1, BasicLatin = 1,
Url = 2, Url = 2,
Mail = 3, Mail = 3,
Number = 4, Number = 4,
}; };
enum class OrbisImeHorizontalAlignment : u32 { enum class OrbisImeHorizontalAlignment : u32 {
Left = 0, Left = 0,
Center = 1, Center = 1,
Right = 2, Right = 2,
}; };
enum class OrbisImeVerticalAlignment : u32 { enum class OrbisImeVerticalAlignment : u32 {
Top = 0, Top = 0,
Center = 1, Center = 1,
Bottom = 2, Bottom = 2,
}; };
enum class OrbisImeEnterLabel : u32 { enum class OrbisImeEnterLabel : u32 {
Default = 0, Default = 0,
Send = 1, Send = 1,
Search = 2, Search = 2,
Go = 3, Go = 3,
}; };
enum class OrbisImeInputMethod : u32 { enum class OrbisImeInputMethod : u32 {
Default = 0, Default = 0,
}; };
enum class OrbisImeEventId : u32 { enum class OrbisImeEventId : u32 {
Open = 0, Open = 0,
UpdateText = 1, UpdateText = 1,
UpdateCaret = 2, UpdateCaret = 2,
PressClose = 4, PressClose = 4,
PressEnter = 5, PressEnter = 5,
Abort = 6, Abort = 6,
CandidateListStart = 7, CandidateListStart = 7,
CandidateListEnd = 8, CandidateListEnd = 8,
CandidateWord = 9, CandidateWord = 9,
CandidateIndex = 10, CandidateIndex = 10,
CandidateDone = 11, CandidateDone = 11,
CandidateCancel = 12, CandidateCancel = 12,
ChangeDevice = 14, ChangeDevice = 14,
ChangeInputMethodState = 18, ChangeInputMethodState = 18,
KeyboardOpen = 256, KeyboardOpen = 256,
KeyboardKeycodeDoen = 257, KeyboardKeycodeDoen = 257,
KeyboardKeycodeUp = 258, KeyboardKeycodeUp = 258,
KeyboardKeycodeRepeat = 259, KeyboardKeycodeRepeat = 259,
KeyboardConnection = 260, KeyboardConnection = 260,
KeyboardDisconnection = 261, KeyboardDisconnection = 261,
KeyboardAbort = 262, KeyboardAbort = 262,
}; };
enum class OrbisImeKeyboardType : u32 { enum class OrbisImeKeyboardType : u32 {
NONE = 0, NONE = 0,
DANISH = 1, DANISH = 1,
GERMAN = 2, GERMAN = 2,
GERMAN_SW = 3, GERMAN_SW = 3,
ENGLISH_US = 4, ENGLISH_US = 4,
ENGLISH_GB = 5, ENGLISH_GB = 5,
SPANISH = 6, SPANISH = 6,
SPANISH_LA = 7, SPANISH_LA = 7,
FINNISH = 8, FINNISH = 8,
FRENCH = 9, FRENCH = 9,
FRENCH_BR = 10, FRENCH_BR = 10,
FRENCH_CA = 11, FRENCH_CA = 11,
FRENCH_SW = 12, FRENCH_SW = 12,
ITALIAN = 13, ITALIAN = 13,
DUTCH = 14, DUTCH = 14,
NORWEGIAN = 15, NORWEGIAN = 15,
POLISH = 16, POLISH = 16,
PORTUGUESE_BR = 17, PORTUGUESE_BR = 17,
PORTUGUESE_PT = 18, PORTUGUESE_PT = 18,
RUSSIAN = 19, RUSSIAN = 19,
SWEDISH = 20, SWEDISH = 20,
TURKISH = 21, TURKISH = 21,
JAPANESE_ROMAN = 22, JAPANESE_ROMAN = 22,
JAPANESE_KANA = 23, JAPANESE_KANA = 23,
KOREAN = 24, KOREAN = 24,
SM_CHINESE = 25, SM_CHINESE = 25,
TR_CHINESE_ZY = 26, TR_CHINESE_ZY = 26,
TR_CHINESE_PY_HK = 27, TR_CHINESE_PY_HK = 27,
TR_CHINESE_PY_TW = 28, TR_CHINESE_PY_TW = 28,
TR_CHINESE_CG = 29, TR_CHINESE_CG = 29,
ARABIC_AR = 30, ARABIC_AR = 30,
THAI = 31, THAI = 31,
CZECH = 32, CZECH = 32,
GREEK = 33, GREEK = 33,
INDONESIAN = 34, INDONESIAN = 34,
VIETNAMESE = 35, VIETNAMESE = 35,
ROMANIAN = 36, ROMANIAN = 36,
HUNGARIAN = 37, HUNGARIAN = 37,
}; };
enum class OrbisImeDeviceType : u32 { enum class OrbisImeDeviceType : u32 {
None = 0, None = 0,
Controller = 1, Controller = 1,
ExtKeyboard = 2, ExtKeyboard = 2,
RemoteOsk = 3, RemoteOsk = 3,
}; };
struct OrbisImeRect { struct OrbisImeRect {
f32 x; f32 x;
f32 y; f32 y;
u32 width; u32 width;
u32 height; u32 height;
}; };
struct OrbisImeTextAreaProperty { struct OrbisImeTextAreaProperty {
u32 mode; // OrbisImeTextAreaMode u32 mode; // OrbisImeTextAreaMode
u32 index; u32 index;
s32 length; s32 length;
}; };
struct OrbisImeEditText { struct OrbisImeEditText {
char16_t* str; char16_t* str;
u32 caret_index; u32 caret_index;
u32 area_num; u32 area_num;
OrbisImeTextAreaProperty text_area[4]; OrbisImeTextAreaProperty text_area[4];
}; };
struct OrbisImeKeycode { struct OrbisImeKeycode {
u16 keycode; u16 keycode;
char16_t character; char16_t character;
u32 status; u32 status;
OrbisImeKeyboardType type; OrbisImeKeyboardType type;
s32 user_id; s32 user_id;
u32 resource_id; u32 resource_id;
Libraries::Rtc::OrbisRtcTick timestamp; Libraries::Rtc::OrbisRtcTick timestamp;
}; };
struct OrbisImeKeyboardResourceIdArray { struct OrbisImeKeyboardResourceIdArray {
s32 userId; s32 userId;
u32 resourceId[5]; u32 resourceId[5];
}; };
enum class OrbisImeCaretMovementDirection : u32 { enum class OrbisImeCaretMovementDirection : u32 {
Still = 0, Still = 0,
Left = 1, Left = 1,
Right = 2, Right = 2,
Up = 3, Up = 3,
Down = 4, Down = 4,
Home = 5, Home = 5,
End = 6, End = 6,
PageUp = 7, PageUp = 7,
PageDown = 8, PageDown = 8,
Top = 9, Top = 9,
Bottom = 10, Bottom = 10,
}; };
union OrbisImeEventParam { union OrbisImeEventParam {
OrbisImeRect rect; OrbisImeRect rect;
OrbisImeEditText text; OrbisImeEditText text;
OrbisImeCaretMovementDirection caret_move; OrbisImeCaretMovementDirection caret_move;
OrbisImeKeycode keycode; OrbisImeKeycode keycode;
OrbisImeKeyboardResourceIdArray resource_id_array; OrbisImeKeyboardResourceIdArray resource_id_array;
char16_t* candidate_word; char16_t* candidate_word;
s32 candidate_index; s32 candidate_index;
OrbisImeDeviceType device_type; OrbisImeDeviceType device_type;
u32 input_method_state; u32 input_method_state;
s8 reserved[64]; s8 reserved[64];
}; };
struct OrbisImeEvent { struct OrbisImeEvent {
OrbisImeEventId id; OrbisImeEventId id;
OrbisImeEventParam param; OrbisImeEventParam param;
}; };
using OrbisImeTextFilter = PS4_SYSV_ABI int (*)(char16_t* outText, u32* outTextLength, using OrbisImeTextFilter = PS4_SYSV_ABI int (*)(char16_t* outText, u32* outTextLength,
const char16_t* srcText, u32 srcTextLength); const char16_t* srcText, u32 srcTextLength);
using OrbisImeEventHandler = PS4_SYSV_ABI void (*)(void* arg, const OrbisImeEvent* e); using OrbisImeEventHandler = PS4_SYSV_ABI void (*)(void* arg, const OrbisImeEvent* e);

View File

@ -1,253 +1,253 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "ime_ui.h" #include "ime_ui.h"
#include "imgui/imgui_std.h" #include "imgui/imgui_std.h"
namespace Libraries::Ime { namespace Libraries::Ime {
using namespace ImGui; using namespace ImGui;
static constexpr ImVec2 BUTTON_SIZE{100.0f, 30.0f}; static constexpr ImVec2 BUTTON_SIZE{100.0f, 30.0f};
ImeState::ImeState(const OrbisImeParam* param) { ImeState::ImeState(const OrbisImeParam* param) {
if (!param) { if (!param) {
return; return;
} }
work_buffer = param->work; work_buffer = param->work;
text_buffer = param->inputTextBuffer; text_buffer = param->inputTextBuffer;
std::size_t text_len = std::char_traits<char16_t>::length(text_buffer); std::size_t text_len = std::char_traits<char16_t>::length(text_buffer);
if (!ConvertOrbisToUTF8(text_buffer, text_len, current_text.begin(), if (!ConvertOrbisToUTF8(text_buffer, text_len, current_text.begin(),
ORBIS_IME_MAX_TEXT_LENGTH * 4)) { ORBIS_IME_MAX_TEXT_LENGTH * 4)) {
LOG_ERROR(Lib_ImeDialog, "Failed to convert text to utf8 encoding"); LOG_ERROR(Lib_ImeDialog, "Failed to convert text to utf8 encoding");
} }
} }
ImeState::ImeState(ImeState&& other) noexcept ImeState::ImeState(ImeState&& other) noexcept
: work_buffer(other.work_buffer), text_buffer(other.text_buffer), : work_buffer(other.work_buffer), text_buffer(other.text_buffer),
current_text(std::move(other.current_text)), event_queue(std::move(other.event_queue)) { current_text(std::move(other.current_text)), event_queue(std::move(other.event_queue)) {
other.text_buffer = nullptr; other.text_buffer = nullptr;
} }
ImeState& ImeState::operator=(ImeState&& other) noexcept { ImeState& ImeState::operator=(ImeState&& other) noexcept {
if (this != &other) { if (this != &other) {
work_buffer = other.work_buffer; work_buffer = other.work_buffer;
text_buffer = other.text_buffer; text_buffer = other.text_buffer;
current_text = std::move(other.current_text); current_text = std::move(other.current_text);
event_queue = std::move(other.event_queue); event_queue = std::move(other.event_queue);
other.text_buffer = nullptr; other.text_buffer = nullptr;
} }
return *this; return *this;
} }
void ImeState::SendEvent(OrbisImeEvent* event) { void ImeState::SendEvent(OrbisImeEvent* event) {
std::unique_lock lock{queue_mutex}; std::unique_lock lock{queue_mutex};
event_queue.push(*event); event_queue.push(*event);
} }
void ImeState::SendEnterEvent() { void ImeState::SendEnterEvent() {
OrbisImeEvent enterEvent{}; OrbisImeEvent enterEvent{};
enterEvent.id = OrbisImeEventId::PressEnter; enterEvent.id = OrbisImeEventId::PressEnter;
SendEvent(&enterEvent); SendEvent(&enterEvent);
} }
void ImeState::SendCloseEvent() { void ImeState::SendCloseEvent() {
OrbisImeEvent closeEvent{}; OrbisImeEvent closeEvent{};
closeEvent.id = OrbisImeEventId::PressClose; closeEvent.id = OrbisImeEventId::PressClose;
closeEvent.param.text.str = reinterpret_cast<char16_t*>(work_buffer); closeEvent.param.text.str = reinterpret_cast<char16_t*>(work_buffer);
SendEvent(&closeEvent); SendEvent(&closeEvent);
} }
void ImeState::SetText(const char16_t* text, u32 length) {} void ImeState::SetText(const char16_t* text, u32 length) {}
void ImeState::SetCaret(u32 position) {} void ImeState::SetCaret(u32 position) {}
bool ImeState::ConvertOrbisToUTF8(const char16_t* orbis_text, std::size_t orbis_text_len, bool ImeState::ConvertOrbisToUTF8(const char16_t* orbis_text, std::size_t orbis_text_len,
char* utf8_text, std::size_t utf8_text_len) { char* utf8_text, std::size_t utf8_text_len) {
std::fill(utf8_text, utf8_text + utf8_text_len, '\0'); std::fill(utf8_text, utf8_text + utf8_text_len, '\0');
const ImWchar* orbis_text_ptr = reinterpret_cast<const ImWchar*>(orbis_text); const ImWchar* orbis_text_ptr = reinterpret_cast<const ImWchar*>(orbis_text);
ImTextStrToUtf8(utf8_text, utf8_text_len, orbis_text_ptr, orbis_text_ptr + orbis_text_len); ImTextStrToUtf8(utf8_text, utf8_text_len, orbis_text_ptr, orbis_text_ptr + orbis_text_len);
return true; return true;
} }
bool ImeState::ConvertUTF8ToOrbis(const char* utf8_text, std::size_t utf8_text_len, bool ImeState::ConvertUTF8ToOrbis(const char* utf8_text, std::size_t utf8_text_len,
char16_t* orbis_text, std::size_t orbis_text_len) { char16_t* orbis_text, std::size_t orbis_text_len) {
std::fill(orbis_text, orbis_text + orbis_text_len, u'\0'); std::fill(orbis_text, orbis_text + orbis_text_len, u'\0');
ImTextStrFromUtf8(reinterpret_cast<ImWchar*>(orbis_text), orbis_text_len, utf8_text, nullptr); ImTextStrFromUtf8(reinterpret_cast<ImWchar*>(orbis_text), orbis_text_len, utf8_text, nullptr);
return true; return true;
} }
ImeUi::ImeUi(ImeState* state, const OrbisImeParam* param) : state(state), ime_param(param) { ImeUi::ImeUi(ImeState* state, const OrbisImeParam* param) : state(state), ime_param(param) {
if (param) { if (param) {
AddLayer(this); AddLayer(this);
} }
} }
ImeUi::~ImeUi() { ImeUi::~ImeUi() {
std::scoped_lock lock(draw_mutex); std::scoped_lock lock(draw_mutex);
Free(); Free();
} }
ImeUi& ImeUi::operator=(ImeUi&& other) { ImeUi& ImeUi::operator=(ImeUi&& other) {
std::scoped_lock lock(draw_mutex, other.draw_mutex); std::scoped_lock lock(draw_mutex, other.draw_mutex);
Free(); Free();
state = other.state; state = other.state;
ime_param = other.ime_param; ime_param = other.ime_param;
first_render = other.first_render; first_render = other.first_render;
other.state = nullptr; other.state = nullptr;
other.ime_param = nullptr; other.ime_param = nullptr;
AddLayer(this); AddLayer(this);
return *this; return *this;
} }
void ImeUi::Draw() { void ImeUi::Draw() {
std::unique_lock lock{draw_mutex}; std::unique_lock lock{draw_mutex};
if (!state) { if (!state) {
return; return;
} }
const auto& ctx = *GetCurrentContext(); const auto& ctx = *GetCurrentContext();
const auto& io = ctx.IO; const auto& io = ctx.IO;
// TODO: Figure out how to properly translate the positions - // TODO: Figure out how to properly translate the positions -
// for example, if a game wants to center the IME panel, // for example, if a game wants to center the IME panel,
// we have to translate the panel position in a way that it // we have to translate the panel position in a way that it
// still becomes centered, as the game normally calculates // still becomes centered, as the game normally calculates
// the position assuming a it's running on a 1920x1080 screen, // the position assuming a it's running on a 1920x1080 screen,
// whereas we are running on a 1280x720 window size (by default). // whereas we are running on a 1280x720 window size (by default).
// //
// e.g. Panel position calculation from a game: // e.g. Panel position calculation from a game:
// param.posx = (1920 / 2) - (panelWidth / 2); // param.posx = (1920 / 2) - (panelWidth / 2);
// param.posy = (1080 / 2) - (panelHeight / 2); // param.posy = (1080 / 2) - (panelHeight / 2);
const auto size = GetIO().DisplaySize; const auto size = GetIO().DisplaySize;
f32 pos_x = (ime_param->posx / 1920.0f * (float)size.x); f32 pos_x = (ime_param->posx / 1920.0f * (float)size.x);
f32 pos_y = (ime_param->posy / 1080.0f * (float)size.y); f32 pos_y = (ime_param->posy / 1080.0f * (float)size.y);
ImVec2 window_pos = {pos_x, pos_y}; ImVec2 window_pos = {pos_x, pos_y};
ImVec2 window_size = {500.0f, 100.0f}; ImVec2 window_size = {500.0f, 100.0f};
// SetNextWindowPos(window_pos); // SetNextWindowPos(window_pos);
SetNextWindowPos(ImVec2(io.DisplaySize.x * 0.5f, io.DisplaySize.y * 0.5f), SetNextWindowPos(ImVec2(io.DisplaySize.x * 0.5f, io.DisplaySize.y * 0.5f),
ImGuiCond_FirstUseEver, ImVec2(0.5f, 0.5f)); ImGuiCond_FirstUseEver, ImVec2(0.5f, 0.5f));
SetNextWindowSize(window_size); SetNextWindowSize(window_size);
SetNextWindowCollapsed(false); SetNextWindowCollapsed(false);
if (first_render || !io.NavActive) { if (first_render || !io.NavActive) {
SetNextWindowFocus(); SetNextWindowFocus();
} }
if (Begin("IME##Ime", nullptr, if (Begin("IME##Ime", nullptr,
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize |
ImGuiWindowFlags_NoSavedSettings)) { ImGuiWindowFlags_NoSavedSettings)) {
DrawPrettyBackground(); DrawPrettyBackground();
DrawInputText(); DrawInputText();
SetCursorPosY(GetCursorPosY() + 10.0f); SetCursorPosY(GetCursorPosY() + 10.0f);
const char* button_text; const char* button_text;
button_text = "Done##ImeDone"; button_text = "Done##ImeDone";
float button_spacing = 10.0f; float button_spacing = 10.0f;
float total_button_width = BUTTON_SIZE.x * 2 + button_spacing; float total_button_width = BUTTON_SIZE.x * 2 + button_spacing;
float button_start_pos = (window_size.x - total_button_width) / 2.0f; float button_start_pos = (window_size.x - total_button_width) / 2.0f;
SetCursorPosX(button_start_pos); SetCursorPosX(button_start_pos);
if (Button(button_text, BUTTON_SIZE) || (IsKeyPressed(ImGuiKey_Enter))) { if (Button(button_text, BUTTON_SIZE) || (IsKeyPressed(ImGuiKey_Enter))) {
state->SendEnterEvent(); state->SendEnterEvent();
} }
SameLine(0.0f, button_spacing); SameLine(0.0f, button_spacing);
if (Button("Close##ImeClose", BUTTON_SIZE)) { if (Button("Close##ImeClose", BUTTON_SIZE)) {
state->SendCloseEvent(); state->SendCloseEvent();
} }
} }
End(); End();
first_render = false; first_render = false;
} }
void ImeUi::DrawInputText() { void ImeUi::DrawInputText() {
ImVec2 input_size = {GetWindowWidth() - 40.0f, 0.0f}; ImVec2 input_size = {GetWindowWidth() - 40.0f, 0.0f};
SetCursorPosX(20.0f); SetCursorPosX(20.0f);
if (first_render) { if (first_render) {
SetKeyboardFocusHere(); SetKeyboardFocusHere();
} }
if (InputTextEx("##ImeInput", nullptr, state->current_text.begin(), ime_param->maxTextLength, if (InputTextEx("##ImeInput", nullptr, state->current_text.begin(), ime_param->maxTextLength,
input_size, ImGuiInputTextFlags_CallbackAlways, InputTextCallback, this)) { input_size, ImGuiInputTextFlags_CallbackAlways, InputTextCallback, this)) {
} }
} }
int ImeUi::InputTextCallback(ImGuiInputTextCallbackData* data) { int ImeUi::InputTextCallback(ImGuiInputTextCallbackData* data) {
ImeUi* ui = static_cast<ImeUi*>(data->UserData); ImeUi* ui = static_cast<ImeUi*>(data->UserData);
ASSERT(ui); ASSERT(ui);
static std::string lastText; static std::string lastText;
std::string currentText(data->Buf, data->BufTextLen); std::string currentText(data->Buf, data->BufTextLen);
if (currentText != lastText) { if (currentText != lastText) {
OrbisImeEditText eventParam{}; OrbisImeEditText eventParam{};
eventParam.str = reinterpret_cast<char16_t*>(ui->ime_param->work); eventParam.str = reinterpret_cast<char16_t*>(ui->ime_param->work);
eventParam.caret_index = data->CursorPos; eventParam.caret_index = data->CursorPos;
eventParam.area_num = 1; eventParam.area_num = 1;
eventParam.text_area[0].mode = 1; // Edit mode eventParam.text_area[0].mode = 1; // Edit mode
eventParam.text_area[0].index = data->CursorPos; eventParam.text_area[0].index = data->CursorPos;
eventParam.text_area[0].length = data->BufTextLen; eventParam.text_area[0].length = data->BufTextLen;
if (!ui->state->ConvertUTF8ToOrbis(data->Buf, data->BufTextLen, eventParam.str, if (!ui->state->ConvertUTF8ToOrbis(data->Buf, data->BufTextLen, eventParam.str,
ui->ime_param->maxTextLength)) { ui->ime_param->maxTextLength)) {
LOG_ERROR(Lib_ImeDialog, "Failed to convert Orbis char to UTF-8"); LOG_ERROR(Lib_ImeDialog, "Failed to convert Orbis char to UTF-8");
return 0; return 0;
} }
if (!ui->state->ConvertUTF8ToOrbis(data->Buf, data->BufTextLen, if (!ui->state->ConvertUTF8ToOrbis(data->Buf, data->BufTextLen,
ui->ime_param->inputTextBuffer, ui->ime_param->inputTextBuffer,
ui->ime_param->maxTextLength)) { ui->ime_param->maxTextLength)) {
LOG_ERROR(Lib_ImeDialog, "Failed to convert Orbis char to UTF-8"); LOG_ERROR(Lib_ImeDialog, "Failed to convert Orbis char to UTF-8");
return 0; return 0;
} }
OrbisImeEvent event{}; OrbisImeEvent event{};
event.id = OrbisImeEventId::UpdateText; event.id = OrbisImeEventId::UpdateText;
event.param.text = eventParam; event.param.text = eventParam;
lastText = currentText; lastText = currentText;
ui->state->SendEvent(&event); ui->state->SendEvent(&event);
} }
static int lastCaretPos = -1; static int lastCaretPos = -1;
if (lastCaretPos == -1) { if (lastCaretPos == -1) {
lastCaretPos = data->CursorPos; lastCaretPos = data->CursorPos;
} else if (data->CursorPos != lastCaretPos) { } else if (data->CursorPos != lastCaretPos) {
OrbisImeCaretMovementDirection caretDirection = OrbisImeCaretMovementDirection::Still; OrbisImeCaretMovementDirection caretDirection = OrbisImeCaretMovementDirection::Still;
if (data->CursorPos < lastCaretPos) { if (data->CursorPos < lastCaretPos) {
caretDirection = OrbisImeCaretMovementDirection::Left; caretDirection = OrbisImeCaretMovementDirection::Left;
} else if (data->CursorPos > lastCaretPos) { } else if (data->CursorPos > lastCaretPos) {
caretDirection = OrbisImeCaretMovementDirection::Right; caretDirection = OrbisImeCaretMovementDirection::Right;
} }
OrbisImeEvent event{}; OrbisImeEvent event{};
event.id = OrbisImeEventId::UpdateCaret; event.id = OrbisImeEventId::UpdateCaret;
event.param.caret_move = caretDirection; event.param.caret_move = caretDirection;
lastCaretPos = data->CursorPos; lastCaretPos = data->CursorPos;
ui->state->SendEvent(&event); ui->state->SendEvent(&event);
} }
return 0; return 0;
} }
void ImeUi::Free() { void ImeUi::Free() {
RemoveLayer(this); RemoveLayer(this);
} }
}; // namespace Libraries::Ime }; // namespace Libraries::Ime

View File

@ -1,76 +1,76 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include <mutex> #include <mutex>
#include <imgui.h> #include <imgui.h>
#include <queue> #include <queue>
#include "imgui/imgui_layer.h" #include "imgui/imgui_layer.h"
#include "common/cstring.h" #include "common/cstring.h"
#include "common/types.h" #include "common/types.h"
#include "ime.h" #include "ime.h"
namespace Libraries::Ime { namespace Libraries::Ime {
class ImeHandler; class ImeHandler;
class ImeUi; class ImeUi;
class ImeState { class ImeState {
friend class ImeHandler; friend class ImeHandler;
friend class ImeUi; friend class ImeUi;
void* work_buffer{}; void* work_buffer{};
char16_t* text_buffer{}; char16_t* text_buffer{};
// A character can hold up to 4 bytes in UTF-8 // A character can hold up to 4 bytes in UTF-8
Common::CString<ORBIS_IME_MAX_TEXT_LENGTH * 4> current_text; Common::CString<ORBIS_IME_MAX_TEXT_LENGTH * 4> current_text;
std::queue<OrbisImeEvent> event_queue; std::queue<OrbisImeEvent> event_queue;
std::mutex queue_mutex; std::mutex queue_mutex;
public: public:
ImeState(const OrbisImeParam* param = nullptr); ImeState(const OrbisImeParam* param = nullptr);
ImeState(ImeState&& other) noexcept; ImeState(ImeState&& other) noexcept;
ImeState& operator=(ImeState&& other) noexcept; ImeState& operator=(ImeState&& other) noexcept;
void SendEvent(OrbisImeEvent* event); void SendEvent(OrbisImeEvent* event);
void SendEnterEvent(); void SendEnterEvent();
void SendCloseEvent(); void SendCloseEvent();
void SetText(const char16_t* text, u32 length); void SetText(const char16_t* text, u32 length);
void SetCaret(u32 position); void SetCaret(u32 position);
private: private:
bool ConvertOrbisToUTF8(const char16_t* orbis_text, std::size_t orbis_text_len, char* utf8_text, bool ConvertOrbisToUTF8(const char16_t* orbis_text, std::size_t orbis_text_len, char* utf8_text,
std::size_t native_text_len); std::size_t native_text_len);
bool ConvertUTF8ToOrbis(const char* native_text, std::size_t utf8_text_len, bool ConvertUTF8ToOrbis(const char* native_text, std::size_t utf8_text_len,
char16_t* orbis_text, std::size_t orbis_text_len); char16_t* orbis_text, std::size_t orbis_text_len);
}; };
class ImeUi : public ImGui::Layer { class ImeUi : public ImGui::Layer {
ImeState* state{}; ImeState* state{};
const OrbisImeParam* ime_param{}; const OrbisImeParam* ime_param{};
bool first_render = true; bool first_render = true;
std::mutex draw_mutex; std::mutex draw_mutex;
public: public:
explicit ImeUi(ImeState* state = nullptr, const OrbisImeParam* param = nullptr); explicit ImeUi(ImeState* state = nullptr, const OrbisImeParam* param = nullptr);
~ImeUi() override; ~ImeUi() override;
ImeUi(const ImeUi& other) = delete; ImeUi(const ImeUi& other) = delete;
ImeUi& operator=(ImeUi&& other); ImeUi& operator=(ImeUi&& other);
void Draw() override; void Draw() override;
private: private:
void Free(); void Free();
void DrawInputText(); void DrawInputText();
static int InputTextCallback(ImGuiInputTextCallbackData* data); static int InputTextCallback(ImGuiInputTextCallbackData* data);
}; };
}; // namespace Libraries::Ime }; // namespace Libraries::Ime

View File

@ -1,6 +1,8 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <thread>
#include "common/assert.h" #include "common/assert.h"
#include "common/debug.h" #include "common/debug.h"
#include "common/logging/log.h" #include "common/logging/log.h"

View File

@ -1,52 +1,52 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "mutex.h" #include "mutex.h"
#include "common/assert.h" #include "common/assert.h"
namespace Libraries::Kernel { namespace Libraries::Kernel {
TimedMutex::TimedMutex() { TimedMutex::TimedMutex() {
#ifdef _WIN64 #ifdef _WIN64
mtx = CreateMutex(nullptr, false, nullptr); mtx = CreateMutex(nullptr, false, nullptr);
ASSERT(mtx); ASSERT(mtx);
#endif #endif
} }
TimedMutex::~TimedMutex() { TimedMutex::~TimedMutex() {
#ifdef _WIN64 #ifdef _WIN64
CloseHandle(mtx); CloseHandle(mtx);
#endif #endif
} }
void TimedMutex::lock() { void TimedMutex::lock() {
#ifdef _WIN64 #ifdef _WIN64
for (;;) { for (;;) {
u64 res = WaitForSingleObjectEx(mtx, INFINITE, true); u64 res = WaitForSingleObjectEx(mtx, INFINITE, true);
if (res == WAIT_OBJECT_0) { if (res == WAIT_OBJECT_0) {
return; return;
} }
} }
#else #else
mtx.lock(); mtx.lock();
#endif #endif
} }
bool TimedMutex::try_lock() { bool TimedMutex::try_lock() {
#ifdef _WIN64 #ifdef _WIN64
return WaitForSingleObjectEx(mtx, 0, true) == WAIT_OBJECT_0; return WaitForSingleObjectEx(mtx, 0, true) == WAIT_OBJECT_0;
#else #else
return mtx.try_lock(); return mtx.try_lock();
#endif #endif
} }
void TimedMutex::unlock() { void TimedMutex::unlock() {
#ifdef _WIN64 #ifdef _WIN64
ReleaseMutex(mtx); ReleaseMutex(mtx);
#else #else
mtx.unlock(); mtx.unlock();
#endif #endif
} }
} // namespace Libraries::Kernel } // namespace Libraries::Kernel

View File

@ -1,80 +1,80 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include <chrono> #include <chrono>
#include "common/types.h" #include "common/types.h"
#ifdef _WIN64 #ifdef _WIN64
#include <windows.h> #include <windows.h>
#else #else
#include <mutex> #include <mutex>
#endif #endif
namespace Libraries::Kernel { namespace Libraries::Kernel {
class TimedMutex { class TimedMutex {
public: public:
TimedMutex(); TimedMutex();
~TimedMutex(); ~TimedMutex();
void lock(); void lock();
bool try_lock(); bool try_lock();
void unlock(); void unlock();
template <class Rep, class Period> template <class Rep, class Period>
bool try_lock_for(const std::chrono::duration<Rep, Period>& rel_time) { bool try_lock_for(const std::chrono::duration<Rep, Period>& rel_time) {
#ifdef _WIN64 #ifdef _WIN64
constexpr auto zero = std::chrono::duration<Rep, Period>::zero(); constexpr auto zero = std::chrono::duration<Rep, Period>::zero();
const auto now = std::chrono::steady_clock::now(); const auto now = std::chrono::steady_clock::now();
std::chrono::steady_clock::time_point abs_time = now; std::chrono::steady_clock::time_point abs_time = now;
if (rel_time > zero) { if (rel_time > zero) {
constexpr auto max = (std::chrono::steady_clock::time_point::max)(); constexpr auto max = (std::chrono::steady_clock::time_point::max)();
if (abs_time < max - rel_time) { if (abs_time < max - rel_time) {
abs_time += rel_time; abs_time += rel_time;
} else { } else {
abs_time = max; abs_time = max;
} }
} }
return try_lock_until(abs_time); return try_lock_until(abs_time);
#else #else
return mtx.try_lock_for(rel_time); return mtx.try_lock_for(rel_time);
#endif #endif
} }
template <class Clock, class Duration> template <class Clock, class Duration>
bool try_lock_until(const std::chrono::time_point<Clock, Duration>& abs_time) { bool try_lock_until(const std::chrono::time_point<Clock, Duration>& abs_time) {
#ifdef _WIN64 #ifdef _WIN64
for (;;) { for (;;) {
const auto now = Clock::now(); const auto now = Clock::now();
if (abs_time <= now) { if (abs_time <= now) {
return false; return false;
} }
const auto rel_ms = std::chrono::ceil<std::chrono::milliseconds>(abs_time - now); const auto rel_ms = std::chrono::ceil<std::chrono::milliseconds>(abs_time - now);
u64 res = WaitForSingleObjectEx(mtx, static_cast<u64>(rel_ms.count()), true); u64 res = WaitForSingleObjectEx(mtx, static_cast<u64>(rel_ms.count()), true);
if (res == WAIT_OBJECT_0) { if (res == WAIT_OBJECT_0) {
return true; return true;
} else if (res == WAIT_TIMEOUT) { } else if (res == WAIT_TIMEOUT) {
return false; return false;
} }
} }
#else #else
return mtx.try_lock_until(abs_time); return mtx.try_lock_until(abs_time);
#endif #endif
} }
private: private:
#ifdef _WIN64 #ifdef _WIN64
HANDLE mtx; HANDLE mtx;
#else #else
std::timed_mutex mtx; std::timed_mutex mtx;
#endif #endif
}; };
} // namespace Libraries::Kernel } // namespace Libraries::Kernel

View File

@ -1,167 +1,164 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include <atomic> #include <atomic>
#include <chrono> #include <chrono>
#include "common/assert.h" #include "common/assert.h"
#include "common/types.h" #include "common/types.h"
#ifdef _WIN64 #ifdef _WIN64
#include <windows.h> #include <windows.h>
#elif defined(__APPLE__) #elif defined(__APPLE__)
#include <dispatch/dispatch.h> #include <dispatch/dispatch.h>
#else #else
#include <semaphore> #include <semaphore>
#endif #endif
namespace Libraries::Kernel { namespace Libraries::Kernel {
template <s64 max> template <s64 max>
class Semaphore { class Semaphore {
public: public:
Semaphore(s32 initialCount) Semaphore(s32 initialCount)
#if !defined(_WIN64) && !defined(__APPLE__) #if !defined(_WIN64) && !defined(__APPLE__)
: sem{initialCount} : sem{initialCount}
#endif #endif
{ {
#ifdef _WIN64 #ifdef _WIN64
sem = CreateSemaphore(nullptr, initialCount, max, nullptr); sem = CreateSemaphore(nullptr, initialCount, max, nullptr);
ASSERT(sem); ASSERT(sem);
#elif defined(__APPLE__) #elif defined(__APPLE__)
sem = dispatch_semaphore_create(initialCount); sem = dispatch_semaphore_create(initialCount);
ASSERT(sem); ASSERT(sem);
#endif #endif
} }
~Semaphore() { ~Semaphore() {
#ifdef _WIN64 #ifdef _WIN64
CloseHandle(sem); CloseHandle(sem);
#elif defined(__APPLE__) #elif defined(__APPLE__)
dispatch_release(sem); dispatch_release(sem);
#endif #endif
} }
void release() { void release() {
#ifdef _WIN64 #ifdef _WIN64
ReleaseSemaphore(sem, 1, nullptr); ReleaseSemaphore(sem, 1, nullptr);
#elif defined(__APPLE__) #elif defined(__APPLE__)
dispatch_semaphore_signal(sem); dispatch_semaphore_signal(sem);
#else #else
sem.release(); sem.release();
#endif #endif
} }
void acquire() { void acquire() {
#ifdef _WIN64 #ifdef _WIN64
for (;;) { for (;;) {
u64 res = WaitForSingleObjectEx(sem, INFINITE, true); u64 res = WaitForSingleObjectEx(sem, INFINITE, true);
if (res == WAIT_OBJECT_0) { if (res == WAIT_OBJECT_0) {
return; return;
} }
} }
#elif defined(__APPLE__) #elif defined(__APPLE__)
for (;;) { for (;;) {
const auto res = dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); const auto res = dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
if (res == 0) { if (res == 0) {
return; return;
} }
} }
#else #else
sem.acquire(); sem.acquire();
#endif #endif
} }
bool try_acquire() { bool try_acquire() {
#ifdef _WIN64 #ifdef _WIN64
return WaitForSingleObjectEx(sem, 0, true) == WAIT_OBJECT_0; return WaitForSingleObjectEx(sem, 0, true) == WAIT_OBJECT_0;
#elif defined(__APPLE__) #elif defined(__APPLE__)
return dispatch_semaphore_wait(sem, DISPATCH_TIME_NOW) == 0; return dispatch_semaphore_wait(sem, DISPATCH_TIME_NOW) == 0;
#else #else
return sem.try_acquire(); return sem.try_acquire();
#endif #endif
} }
template <class Rep, class Period> template <class Rep, class Period>
bool try_acquire_for(const std::chrono::duration<Rep, Period>& rel_time) { bool try_acquire_for(const std::chrono::duration<Rep, Period>& rel_time) {
#ifdef _WIN64 #ifdef _WIN64
const auto start_time = std::chrono::high_resolution_clock::now(); const auto start_time = std::chrono::high_resolution_clock::now();
auto rel_time_ms = std::chrono::ceil<std::chrono::milliseconds>(rel_time); auto rel_time_ms = std::chrono::ceil<std::chrono::milliseconds>(rel_time);
while (rel_time_ms.count() > 0) { do {
u64 timeout_ms = static_cast<u64>(rel_time_ms.count()); u64 timeout_ms = static_cast<u64>(rel_time_ms.count());
u64 res = WaitForSingleObjectEx(sem, timeout_ms, true); u64 res = WaitForSingleObjectEx(sem, timeout_ms, true);
if (res == WAIT_OBJECT_0) { if (res == WAIT_OBJECT_0) {
return true; return true;
} else if (res == WAIT_IO_COMPLETION) { } else if (res == WAIT_IO_COMPLETION) {
auto elapsed_time = std::chrono::high_resolution_clock::now() - start_time; auto elapsed_time = std::chrono::high_resolution_clock::now() - start_time;
rel_time_ms -= std::chrono::duration_cast<std::chrono::milliseconds>(elapsed_time); rel_time_ms -= std::chrono::duration_cast<std::chrono::milliseconds>(elapsed_time);
} else { } else {
return false; return false;
} }
} } while (rel_time_ms.count() > 0);
return false; return false;
#elif defined(__APPLE__) #elif defined(__APPLE__)
const auto rel_time_ns = std::chrono::ceil<std::chrono::nanoseconds>(rel_time).count(); const auto rel_time_ns = std::chrono::ceil<std::chrono::nanoseconds>(rel_time).count();
const auto timeout = dispatch_time(DISPATCH_TIME_NOW, rel_time_ns); const auto timeout = dispatch_time(DISPATCH_TIME_NOW, rel_time_ns);
return dispatch_semaphore_wait(sem, timeout) == 0; return dispatch_semaphore_wait(sem, timeout) == 0;
#else #else
return sem.try_acquire_for(rel_time); return sem.try_acquire_for(rel_time);
#endif #endif
} }
template <class Clock, class Duration> template <class Clock, class Duration>
bool try_acquire_until(const std::chrono::time_point<Clock, Duration>& abs_time) { bool try_acquire_until(const std::chrono::time_point<Clock, Duration>& abs_time) {
#ifdef _WIN64 #ifdef _WIN64
const auto start_time = Clock::now(); const auto start_time = Clock::now();
if (start_time >= abs_time) {
return false; auto rel_time = std::chrono::ceil<std::chrono::milliseconds>(abs_time - start_time);
} do {
u64 timeout_ms = static_cast<u64>(rel_time.count());
auto rel_time = std::chrono::ceil<std::chrono::milliseconds>(abs_time - start_time); u64 res = WaitForSingleObjectEx(sem, timeout_ms, true);
while (rel_time.count() > 0) { if (res == WAIT_OBJECT_0) {
u64 timeout_ms = static_cast<u64>(rel_time.count()); return true;
u64 res = WaitForSingleObjectEx(sem, timeout_ms, true); } else if (res == WAIT_IO_COMPLETION) {
if (res == WAIT_OBJECT_0) { auto elapsed_time = Clock::now() - start_time;
return true; rel_time -= std::chrono::duration_cast<std::chrono::milliseconds>(elapsed_time);
} else if (res == WAIT_IO_COMPLETION) { } else {
auto elapsed_time = Clock::now() - start_time; return false;
rel_time -= std::chrono::duration_cast<std::chrono::milliseconds>(elapsed_time); }
} else { } while (rel_time.count() > 0);
return false;
} return false;
} #elif defined(__APPLE__)
auto abs_s = std::chrono::time_point_cast<std::chrono::seconds>(abs_time);
return false; auto abs_ns = std::chrono::time_point_cast<std::chrono::nanoseconds>(abs_time) -
#elif defined(__APPLE__) std::chrono::time_point_cast<std::chrono::nanoseconds>(abs_s);
auto abs_s = std::chrono::time_point_cast<std::chrono::seconds>(abs_time); const timespec abs_timespec = {
auto abs_ns = std::chrono::time_point_cast<std::chrono::nanoseconds>(abs_time) - .tv_sec = abs_s.time_since_epoch().count(),
std::chrono::time_point_cast<std::chrono::nanoseconds>(abs_s); .tv_nsec = abs_ns.count(),
const timespec abs_timespec = { };
.tv_sec = abs_s.time_since_epoch().count(), const auto timeout = dispatch_walltime(&abs_timespec, 0);
.tv_nsec = abs_ns.count(), return dispatch_semaphore_wait(sem, timeout) == 0;
}; #else
const auto timeout = dispatch_walltime(&abs_timespec, 0); return sem.try_acquire_until(abs_time);
return dispatch_semaphore_wait(sem, timeout) == 0; #endif
#else }
return sem.try_acquire_until(abs_time);
#endif private:
} #ifdef _WIN64
HANDLE sem;
private: #elif defined(__APPLE__)
#ifdef _WIN64 dispatch_semaphore_t sem;
HANDLE sem; #else
#elif defined(__APPLE__) std::counting_semaphore<max> sem;
dispatch_semaphore_t sem; #endif
#else };
std::counting_semaphore<max> sem;
#endif using BinarySemaphore = Semaphore<1>;
}; using CountingSemaphore = Semaphore<0x7FFFFFFF /*ORBIS_KERNEL_SEM_VALUE_MAX*/>;
using BinarySemaphore = Semaphore<1>;
using CountingSemaphore = Semaphore<0x7FFFFFFF /*ORBIS_KERNEL_SEM_VALUE_MAX*/>;
} // namespace Libraries::Kernel } // namespace Libraries::Kernel

View File

@ -22,7 +22,7 @@ void SigactionHandler(int signum, siginfo_t* inf, ucontext_t* raw_context) {
if (handler) { if (handler) {
auto ctx = Ucontext{}; auto ctx = Ucontext{};
#ifdef __APPLE__ #ifdef __APPLE__
auto& regs = raw_context->uc_mcontext->__ss; const auto& regs = raw_context->uc_mcontext->__ss;
ctx.uc_mcontext.mc_r8 = regs.__r8; ctx.uc_mcontext.mc_r8 = regs.__r8;
ctx.uc_mcontext.mc_r9 = regs.__r9; ctx.uc_mcontext.mc_r9 = regs.__r9;
ctx.uc_mcontext.mc_r10 = regs.__r10; ctx.uc_mcontext.mc_r10 = regs.__r10;
@ -42,7 +42,7 @@ void SigactionHandler(int signum, siginfo_t* inf, ucontext_t* raw_context) {
ctx.uc_mcontext.mc_fs = regs.__fs; ctx.uc_mcontext.mc_fs = regs.__fs;
ctx.uc_mcontext.mc_gs = regs.__gs; ctx.uc_mcontext.mc_gs = regs.__gs;
#else #else
auto& regs = raw_context->uc_mcontext.gregs; const auto& regs = raw_context->uc_mcontext.gregs;
ctx.uc_mcontext.mc_r8 = regs[REG_R8]; ctx.uc_mcontext.mc_r8 = regs[REG_R8];
ctx.uc_mcontext.mc_r9 = regs[REG_R9]; ctx.uc_mcontext.mc_r9 = regs[REG_R9];
ctx.uc_mcontext.mc_r10 = regs[REG_R10]; ctx.uc_mcontext.mc_r10 = regs[REG_R10];
@ -131,8 +131,12 @@ int PS4_SYSV_ABI sceKernelRaiseException(PthreadT thread, int signum) {
LOG_WARNING(Lib_Kernel, "Raising exception on thread '{}'", thread->name); LOG_WARNING(Lib_Kernel, "Raising exception on thread '{}'", thread->name);
ASSERT_MSG(signum == POSIX_SIGUSR1, "Attempting to raise non user defined signal!"); ASSERT_MSG(signum == POSIX_SIGUSR1, "Attempting to raise non user defined signal!");
#ifndef _WIN64 #ifndef _WIN64
pthread_t pthr = *reinterpret_cast<pthread_t*>(thread->native_thr.GetHandle()); const auto pthr = reinterpret_cast<pthread_t>(thread->native_thr.GetHandle());
pthread_kill(pthr, SIGUSR2); const auto ret = pthread_kill(pthr, SIGUSR2);
if (ret != 0) {
LOG_ERROR(Kernel, "Failed to send exception signal to thread '{}': {}", thread->name,
strerror(ret));
}
#else #else
USER_APC_OPTION option; USER_APC_OPTION option;
option.UserApcFlags = QueueUserApcFlagsSpecialUserApc; option.UserApcFlags = QueueUserApcFlagsSpecialUserApc;

View File

@ -53,6 +53,7 @@ Core::Tcb* TcbCtor(Pthread* thread, int initial) {
if (tcb) { if (tcb) {
tcb->tcb_thread = thread; tcb->tcb_thread = thread;
tcb->tcb_fiber = nullptr;
} }
return tcb; return tcb;
} }

View File

@ -1,199 +1,199 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "common/assert.h" #include "common/assert.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/libraries/libs.h" #include "core/libraries/libs.h"
#include "core/libraries/videodec/videodec2.h" #include "core/libraries/videodec/videodec2.h"
#include "core/libraries/videodec/videodec2_impl.h" #include "core/libraries/videodec/videodec2_impl.h"
#include "core/libraries/videodec/videodec_error.h" #include "core/libraries/videodec/videodec_error.h"
namespace Libraries::Vdec2 { namespace Libraries::Vdec2 {
static constexpr u64 kMinimumMemorySize = 32_MB; ///> Fake minimum memory size for querying static constexpr u64 kMinimumMemorySize = 32_MB; ///> Fake minimum memory size for querying
s32 PS4_SYSV_ABI s32 PS4_SYSV_ABI
sceVideodec2QueryComputeMemoryInfo(OrbisVideodec2ComputeMemoryInfo* computeMemInfo) { sceVideodec2QueryComputeMemoryInfo(OrbisVideodec2ComputeMemoryInfo* computeMemInfo) {
LOG_INFO(Lib_Vdec2, "called"); LOG_INFO(Lib_Vdec2, "called");
if (!computeMemInfo) { if (!computeMemInfo) {
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER; return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
} }
if (computeMemInfo->thisSize != sizeof(OrbisVideodec2ComputeMemoryInfo)) { if (computeMemInfo->thisSize != sizeof(OrbisVideodec2ComputeMemoryInfo)) {
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE; return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
} }
computeMemInfo->cpuGpuMemory = nullptr; computeMemInfo->cpuGpuMemory = nullptr;
computeMemInfo->cpuGpuMemorySize = kMinimumMemorySize; computeMemInfo->cpuGpuMemorySize = kMinimumMemorySize;
return ORBIS_OK; return ORBIS_OK;
} }
s32 PS4_SYSV_ABI s32 PS4_SYSV_ABI
sceVideodec2AllocateComputeQueue(const OrbisVideodec2ComputeConfigInfo* computeCfgInfo, sceVideodec2AllocateComputeQueue(const OrbisVideodec2ComputeConfigInfo* computeCfgInfo,
const OrbisVideodec2ComputeMemoryInfo* computeMemInfo, const OrbisVideodec2ComputeMemoryInfo* computeMemInfo,
OrbisVideodec2ComputeQueue* computeQueue) { OrbisVideodec2ComputeQueue* computeQueue) {
LOG_INFO(Lib_Vdec2, "called"); LOG_INFO(Lib_Vdec2, "called");
return ORBIS_OK; return ORBIS_OK;
} }
s32 PS4_SYSV_ABI sceVideodec2ReleaseComputeQueue(OrbisVideodec2ComputeQueue computeQueue) { s32 PS4_SYSV_ABI sceVideodec2ReleaseComputeQueue(OrbisVideodec2ComputeQueue computeQueue) {
LOG_INFO(Lib_Vdec2, "called"); LOG_INFO(Lib_Vdec2, "called");
return ORBIS_OK; return ORBIS_OK;
} }
s32 PS4_SYSV_ABI s32 PS4_SYSV_ABI
sceVideodec2QueryDecoderMemoryInfo(const OrbisVideodec2DecoderConfigInfo* decoderCfgInfo, sceVideodec2QueryDecoderMemoryInfo(const OrbisVideodec2DecoderConfigInfo* decoderCfgInfo,
OrbisVideodec2DecoderMemoryInfo* decoderMemInfo) { OrbisVideodec2DecoderMemoryInfo* decoderMemInfo) {
LOG_INFO(Lib_Vdec2, "called"); LOG_INFO(Lib_Vdec2, "called");
if (!decoderCfgInfo || !decoderMemInfo) { if (!decoderCfgInfo || !decoderMemInfo) {
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER; return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
} }
if (decoderCfgInfo->thisSize != sizeof(OrbisVideodec2DecoderConfigInfo) || if (decoderCfgInfo->thisSize != sizeof(OrbisVideodec2DecoderConfigInfo) ||
decoderMemInfo->thisSize != sizeof(OrbisVideodec2DecoderMemoryInfo)) { decoderMemInfo->thisSize != sizeof(OrbisVideodec2DecoderMemoryInfo)) {
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE; return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
} }
decoderMemInfo->cpuMemory = nullptr; decoderMemInfo->cpuMemory = nullptr;
decoderMemInfo->gpuMemory = nullptr; decoderMemInfo->gpuMemory = nullptr;
decoderMemInfo->cpuGpuMemory = nullptr; decoderMemInfo->cpuGpuMemory = nullptr;
decoderMemInfo->cpuGpuMemorySize = kMinimumMemorySize; decoderMemInfo->cpuGpuMemorySize = kMinimumMemorySize;
decoderMemInfo->cpuMemorySize = kMinimumMemorySize; decoderMemInfo->cpuMemorySize = kMinimumMemorySize;
decoderMemInfo->gpuMemorySize = kMinimumMemorySize; decoderMemInfo->gpuMemorySize = kMinimumMemorySize;
decoderMemInfo->maxFrameBufferSize = kMinimumMemorySize; decoderMemInfo->maxFrameBufferSize = kMinimumMemorySize;
decoderMemInfo->frameBufferAlignment = 0x100; decoderMemInfo->frameBufferAlignment = 0x100;
return ORBIS_OK; return ORBIS_OK;
} }
s32 PS4_SYSV_ABI sceVideodec2CreateDecoder(const OrbisVideodec2DecoderConfigInfo* decoderCfgInfo, s32 PS4_SYSV_ABI sceVideodec2CreateDecoder(const OrbisVideodec2DecoderConfigInfo* decoderCfgInfo,
const OrbisVideodec2DecoderMemoryInfo* decoderMemInfo, const OrbisVideodec2DecoderMemoryInfo* decoderMemInfo,
OrbisVideodec2Decoder* decoder) { OrbisVideodec2Decoder* decoder) {
LOG_INFO(Lib_Vdec2, "called"); LOG_INFO(Lib_Vdec2, "called");
if (!decoderCfgInfo || !decoderMemInfo || !decoder) { if (!decoderCfgInfo || !decoderMemInfo || !decoder) {
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER; return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
} }
if (decoderCfgInfo->thisSize != sizeof(OrbisVideodec2DecoderConfigInfo) || if (decoderCfgInfo->thisSize != sizeof(OrbisVideodec2DecoderConfigInfo) ||
decoderMemInfo->thisSize != sizeof(OrbisVideodec2DecoderMemoryInfo)) { decoderMemInfo->thisSize != sizeof(OrbisVideodec2DecoderMemoryInfo)) {
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE; return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
} }
*decoder = new VdecDecoder(*decoderCfgInfo, *decoderMemInfo); *decoder = new VdecDecoder(*decoderCfgInfo, *decoderMemInfo);
return ORBIS_OK; return ORBIS_OK;
} }
s32 PS4_SYSV_ABI sceVideodec2DeleteDecoder(OrbisVideodec2Decoder decoder) { s32 PS4_SYSV_ABI sceVideodec2DeleteDecoder(OrbisVideodec2Decoder decoder) {
LOG_INFO(Lib_Vdec2, "called"); LOG_INFO(Lib_Vdec2, "called");
if (!decoder) { if (!decoder) {
return ORBIS_VIDEODEC2_ERROR_DECODER_INSTANCE; return ORBIS_VIDEODEC2_ERROR_DECODER_INSTANCE;
} }
delete decoder; delete decoder;
return ORBIS_OK; return ORBIS_OK;
} }
s32 PS4_SYSV_ABI sceVideodec2Decode(OrbisVideodec2Decoder decoder, s32 PS4_SYSV_ABI sceVideodec2Decode(OrbisVideodec2Decoder decoder,
const OrbisVideodec2InputData* inputData, const OrbisVideodec2InputData* inputData,
OrbisVideodec2FrameBuffer* frameBuffer, OrbisVideodec2FrameBuffer* frameBuffer,
OrbisVideodec2OutputInfo* outputInfo) { OrbisVideodec2OutputInfo* outputInfo) {
LOG_TRACE(Lib_Vdec2, "called"); LOG_TRACE(Lib_Vdec2, "called");
if (!decoder) { if (!decoder) {
return ORBIS_VIDEODEC2_ERROR_DECODER_INSTANCE; return ORBIS_VIDEODEC2_ERROR_DECODER_INSTANCE;
} }
if (!inputData || !frameBuffer || !outputInfo) { if (!inputData || !frameBuffer || !outputInfo) {
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER; return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
} }
if (inputData->thisSize != sizeof(OrbisVideodec2InputData) || if (inputData->thisSize != sizeof(OrbisVideodec2InputData) ||
frameBuffer->thisSize != sizeof(OrbisVideodec2FrameBuffer)) { frameBuffer->thisSize != sizeof(OrbisVideodec2FrameBuffer)) {
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE; return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
} }
return decoder->Decode(*inputData, *frameBuffer, *outputInfo); return decoder->Decode(*inputData, *frameBuffer, *outputInfo);
} }
s32 PS4_SYSV_ABI sceVideodec2Flush(OrbisVideodec2Decoder decoder, s32 PS4_SYSV_ABI sceVideodec2Flush(OrbisVideodec2Decoder decoder,
OrbisVideodec2FrameBuffer* frameBuffer, OrbisVideodec2FrameBuffer* frameBuffer,
OrbisVideodec2OutputInfo* outputInfo) { OrbisVideodec2OutputInfo* outputInfo) {
LOG_INFO(Lib_Vdec2, "called"); LOG_INFO(Lib_Vdec2, "called");
if (!decoder) { if (!decoder) {
return ORBIS_VIDEODEC2_ERROR_DECODER_INSTANCE; return ORBIS_VIDEODEC2_ERROR_DECODER_INSTANCE;
} }
if (!frameBuffer || !outputInfo) { if (!frameBuffer || !outputInfo) {
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER; return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
} }
if (frameBuffer->thisSize != sizeof(OrbisVideodec2FrameBuffer) || if (frameBuffer->thisSize != sizeof(OrbisVideodec2FrameBuffer) ||
outputInfo->thisSize != sizeof(OrbisVideodec2OutputInfo)) { outputInfo->thisSize != sizeof(OrbisVideodec2OutputInfo)) {
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE; return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
} }
return decoder->Flush(*frameBuffer, *outputInfo); return decoder->Flush(*frameBuffer, *outputInfo);
} }
s32 PS4_SYSV_ABI sceVideodec2Reset(OrbisVideodec2Decoder decoder) { s32 PS4_SYSV_ABI sceVideodec2Reset(OrbisVideodec2Decoder decoder) {
LOG_INFO(Lib_Vdec2, "called"); LOG_INFO(Lib_Vdec2, "called");
if (!decoder) { if (!decoder) {
return ORBIS_VIDEODEC2_ERROR_DECODER_INSTANCE; return ORBIS_VIDEODEC2_ERROR_DECODER_INSTANCE;
} }
return decoder->Reset(); return decoder->Reset();
} }
s32 PS4_SYSV_ABI sceVideodec2GetPictureInfo(const OrbisVideodec2OutputInfo* outputInfo, s32 PS4_SYSV_ABI sceVideodec2GetPictureInfo(const OrbisVideodec2OutputInfo* outputInfo,
void* p1stPictureInfoOut, void* p2ndPictureInfoOut) { void* p1stPictureInfoOut, void* p2ndPictureInfoOut) {
LOG_TRACE(Lib_Vdec2, "called"); LOG_TRACE(Lib_Vdec2, "called");
if (!outputInfo) { if (!outputInfo) {
return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER; return ORBIS_VIDEODEC2_ERROR_ARGUMENT_POINTER;
} }
if (outputInfo->thisSize != sizeof(OrbisVideodec2OutputInfo)) { if (outputInfo->thisSize != sizeof(OrbisVideodec2OutputInfo)) {
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE; return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
} }
if (outputInfo->pictureCount == 0 || gPictureInfos.empty()) { if (outputInfo->pictureCount == 0 || gPictureInfos.empty()) {
return ORBIS_OK; return ORBIS_OK;
} }
if (p1stPictureInfoOut) { if (p1stPictureInfoOut) {
OrbisVideodec2AvcPictureInfo* picInfo = OrbisVideodec2AvcPictureInfo* picInfo =
static_cast<OrbisVideodec2AvcPictureInfo*>(p1stPictureInfoOut); static_cast<OrbisVideodec2AvcPictureInfo*>(p1stPictureInfoOut);
if (picInfo->thisSize != sizeof(OrbisVideodec2AvcPictureInfo)) { if (picInfo->thisSize != sizeof(OrbisVideodec2AvcPictureInfo)) {
return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE; return ORBIS_VIDEODEC2_ERROR_STRUCT_SIZE;
} }
*picInfo = gPictureInfos.back(); *picInfo = gPictureInfos.back();
} }
if (outputInfo->pictureCount > 1) { if (outputInfo->pictureCount > 1) {
UNREACHABLE(); UNREACHABLE();
} }
return ORBIS_OK; return ORBIS_OK;
} }
void RegisterlibSceVdec2(Core::Loader::SymbolsResolver* sym) { void RegisterlibSceVdec2(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("RnDibcGCPKw", "libSceVideodec2", 1, "libSceVideodec2", 1, 1, LIB_FUNCTION("RnDibcGCPKw", "libSceVideodec2", 1, "libSceVideodec2", 1, 1,
sceVideodec2QueryComputeMemoryInfo); sceVideodec2QueryComputeMemoryInfo);
LIB_FUNCTION("eD+X2SmxUt4", "libSceVideodec2", 1, "libSceVideodec2", 1, 1, LIB_FUNCTION("eD+X2SmxUt4", "libSceVideodec2", 1, "libSceVideodec2", 1, 1,
sceVideodec2AllocateComputeQueue); sceVideodec2AllocateComputeQueue);
LIB_FUNCTION("UvtA3FAiF4Y", "libSceVideodec2", 1, "libSceVideodec2", 1, 1, LIB_FUNCTION("UvtA3FAiF4Y", "libSceVideodec2", 1, "libSceVideodec2", 1, 1,
sceVideodec2ReleaseComputeQueue); sceVideodec2ReleaseComputeQueue);
LIB_FUNCTION("qqMCwlULR+E", "libSceVideodec2", 1, "libSceVideodec2", 1, 1, LIB_FUNCTION("qqMCwlULR+E", "libSceVideodec2", 1, "libSceVideodec2", 1, 1,
sceVideodec2QueryDecoderMemoryInfo); sceVideodec2QueryDecoderMemoryInfo);
LIB_FUNCTION("CNNRoRYd8XI", "libSceVideodec2", 1, "libSceVideodec2", 1, 1, LIB_FUNCTION("CNNRoRYd8XI", "libSceVideodec2", 1, "libSceVideodec2", 1, 1,
sceVideodec2CreateDecoder); sceVideodec2CreateDecoder);
LIB_FUNCTION("jwImxXRGSKA", "libSceVideodec2", 1, "libSceVideodec2", 1, 1, LIB_FUNCTION("jwImxXRGSKA", "libSceVideodec2", 1, "libSceVideodec2", 1, 1,
sceVideodec2DeleteDecoder); sceVideodec2DeleteDecoder);
LIB_FUNCTION("852F5+q6+iM", "libSceVideodec2", 1, "libSceVideodec2", 1, 1, sceVideodec2Decode); LIB_FUNCTION("852F5+q6+iM", "libSceVideodec2", 1, "libSceVideodec2", 1, 1, sceVideodec2Decode);
LIB_FUNCTION("l1hXwscLuCY", "libSceVideodec2", 1, "libSceVideodec2", 1, 1, sceVideodec2Flush); LIB_FUNCTION("l1hXwscLuCY", "libSceVideodec2", 1, "libSceVideodec2", 1, 1, sceVideodec2Flush);
LIB_FUNCTION("wJXikG6QFN8", "libSceVideodec2", 1, "libSceVideodec2", 1, 1, sceVideodec2Reset); LIB_FUNCTION("wJXikG6QFN8", "libSceVideodec2", 1, "libSceVideodec2", 1, 1, sceVideodec2Reset);
LIB_FUNCTION("NtXRa3dRzU0", "libSceVideodec2", 1, "libSceVideodec2", 1, 1, LIB_FUNCTION("NtXRa3dRzU0", "libSceVideodec2", 1, "libSceVideodec2", 1, 1,
sceVideodec2GetPictureInfo); sceVideodec2GetPictureInfo);
} }
} // namespace Libraries::Vdec2 } // namespace Libraries::Vdec2

View File

@ -1,139 +1,139 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include "common/types.h" #include "common/types.h"
#include "videodec2_avc.h" #include "videodec2_avc.h"
namespace Core::Loader { namespace Core::Loader {
class SymbolsResolver; class SymbolsResolver;
} }
namespace Libraries::Vdec2 { namespace Libraries::Vdec2 {
class VdecDecoder; class VdecDecoder;
using OrbisVideodec2Decoder = VdecDecoder*; using OrbisVideodec2Decoder = VdecDecoder*;
using OrbisVideodec2ComputeQueue = void*; using OrbisVideodec2ComputeQueue = void*;
struct OrbisVideodec2DecoderConfigInfo { struct OrbisVideodec2DecoderConfigInfo {
u64 thisSize; u64 thisSize;
u32 resourceType; u32 resourceType;
u32 codecType; u32 codecType;
u32 profile; u32 profile;
u32 maxLevel; u32 maxLevel;
s32 maxFrameWidth; s32 maxFrameWidth;
s32 maxFrameHeight; s32 maxFrameHeight;
s32 maxDpbFrameCount; s32 maxDpbFrameCount;
u32 decodePipelineDepth; u32 decodePipelineDepth;
OrbisVideodec2ComputeQueue computeQueue; OrbisVideodec2ComputeQueue computeQueue;
u64 cpuAffinityMask; u64 cpuAffinityMask;
s32 cpuThreadPriority; s32 cpuThreadPriority;
bool optimizeProgressiveVideo; bool optimizeProgressiveVideo;
bool checkMemoryType; bool checkMemoryType;
u8 reserved0; u8 reserved0;
u8 reserved1; u8 reserved1;
void* extraConfigInfo; void* extraConfigInfo;
}; };
static_assert(sizeof(OrbisVideodec2DecoderConfigInfo) == 0x48); static_assert(sizeof(OrbisVideodec2DecoderConfigInfo) == 0x48);
struct OrbisVideodec2DecoderMemoryInfo { struct OrbisVideodec2DecoderMemoryInfo {
u64 thisSize; u64 thisSize;
u64 cpuMemorySize; u64 cpuMemorySize;
void* cpuMemory; void* cpuMemory;
u64 gpuMemorySize; u64 gpuMemorySize;
void* gpuMemory; void* gpuMemory;
u64 cpuGpuMemorySize; u64 cpuGpuMemorySize;
void* cpuGpuMemory; void* cpuGpuMemory;
u64 maxFrameBufferSize; u64 maxFrameBufferSize;
u32 frameBufferAlignment; u32 frameBufferAlignment;
u32 reserved0; u32 reserved0;
}; };
static_assert(sizeof(OrbisVideodec2DecoderMemoryInfo) == 0x48); static_assert(sizeof(OrbisVideodec2DecoderMemoryInfo) == 0x48);
struct OrbisVideodec2InputData { struct OrbisVideodec2InputData {
u64 thisSize; u64 thisSize;
void* auData; void* auData;
u64 auSize; u64 auSize;
u64 ptsData; u64 ptsData;
u64 dtsData; u64 dtsData;
u64 attachedData; u64 attachedData;
}; };
static_assert(sizeof(OrbisVideodec2InputData) == 0x30); static_assert(sizeof(OrbisVideodec2InputData) == 0x30);
struct OrbisVideodec2OutputInfo { struct OrbisVideodec2OutputInfo {
u64 thisSize; u64 thisSize;
bool isValid; bool isValid;
bool isErrorFrame; bool isErrorFrame;
u8 pictureCount; u8 pictureCount;
u32 codecType; u32 codecType;
u32 frameWidth; u32 frameWidth;
u32 framePitch; u32 framePitch;
u32 frameHeight; u32 frameHeight;
void* frameBuffer; void* frameBuffer;
u64 frameBufferSize; u64 frameBufferSize;
}; };
static_assert(sizeof(OrbisVideodec2OutputInfo) == 0x30); static_assert(sizeof(OrbisVideodec2OutputInfo) == 0x30);
struct OrbisVideodec2FrameBuffer { struct OrbisVideodec2FrameBuffer {
u64 thisSize; u64 thisSize;
void* frameBuffer; void* frameBuffer;
u64 frameBufferSize; u64 frameBufferSize;
bool isAccepted; bool isAccepted;
}; };
static_assert(sizeof(OrbisVideodec2FrameBuffer) == 0x20); static_assert(sizeof(OrbisVideodec2FrameBuffer) == 0x20);
struct OrbisVideodec2ComputeMemoryInfo { struct OrbisVideodec2ComputeMemoryInfo {
u64 thisSize; u64 thisSize;
u64 cpuGpuMemorySize; u64 cpuGpuMemorySize;
void* cpuGpuMemory; void* cpuGpuMemory;
}; };
static_assert(sizeof(OrbisVideodec2ComputeMemoryInfo) == 0x18); static_assert(sizeof(OrbisVideodec2ComputeMemoryInfo) == 0x18);
struct OrbisVideodec2ComputeConfigInfo { struct OrbisVideodec2ComputeConfigInfo {
u64 thisSize; u64 thisSize;
u16 computePipeId; u16 computePipeId;
u16 computeQueueId; u16 computeQueueId;
bool checkMemoryType; bool checkMemoryType;
u8 reserved0; u8 reserved0;
u16 reserved1; u16 reserved1;
}; };
static_assert(sizeof(OrbisVideodec2ComputeConfigInfo) == 0x10); static_assert(sizeof(OrbisVideodec2ComputeConfigInfo) == 0x10);
s32 PS4_SYSV_ABI s32 PS4_SYSV_ABI
sceVideodec2QueryComputeMemoryInfo(OrbisVideodec2ComputeMemoryInfo* computeMemInfo); sceVideodec2QueryComputeMemoryInfo(OrbisVideodec2ComputeMemoryInfo* computeMemInfo);
s32 PS4_SYSV_ABI s32 PS4_SYSV_ABI
sceVideodec2AllocateComputeQueue(const OrbisVideodec2ComputeConfigInfo* computeCfgInfo, sceVideodec2AllocateComputeQueue(const OrbisVideodec2ComputeConfigInfo* computeCfgInfo,
const OrbisVideodec2ComputeMemoryInfo* computeMemInfo, const OrbisVideodec2ComputeMemoryInfo* computeMemInfo,
OrbisVideodec2ComputeQueue* computeQueue); OrbisVideodec2ComputeQueue* computeQueue);
s32 PS4_SYSV_ABI sceVideodec2ReleaseComputeQueue(OrbisVideodec2ComputeQueue computeQueue); s32 PS4_SYSV_ABI sceVideodec2ReleaseComputeQueue(OrbisVideodec2ComputeQueue computeQueue);
s32 PS4_SYSV_ABI s32 PS4_SYSV_ABI
sceVideodec2QueryDecoderMemoryInfo(const OrbisVideodec2DecoderConfigInfo* decoderCfgInfo, sceVideodec2QueryDecoderMemoryInfo(const OrbisVideodec2DecoderConfigInfo* decoderCfgInfo,
OrbisVideodec2DecoderMemoryInfo* decoderMemInfo); OrbisVideodec2DecoderMemoryInfo* decoderMemInfo);
s32 PS4_SYSV_ABI sceVideodec2CreateDecoder(const OrbisVideodec2DecoderConfigInfo* decoderCfgInfo, s32 PS4_SYSV_ABI sceVideodec2CreateDecoder(const OrbisVideodec2DecoderConfigInfo* decoderCfgInfo,
const OrbisVideodec2DecoderMemoryInfo* decoderMemInfo, const OrbisVideodec2DecoderMemoryInfo* decoderMemInfo,
OrbisVideodec2Decoder* decoder); OrbisVideodec2Decoder* decoder);
s32 PS4_SYSV_ABI sceVideodec2DeleteDecoder(OrbisVideodec2Decoder decoder); s32 PS4_SYSV_ABI sceVideodec2DeleteDecoder(OrbisVideodec2Decoder decoder);
s32 PS4_SYSV_ABI sceVideodec2Decode(OrbisVideodec2Decoder decoder, s32 PS4_SYSV_ABI sceVideodec2Decode(OrbisVideodec2Decoder decoder,
const OrbisVideodec2InputData* inputData, const OrbisVideodec2InputData* inputData,
OrbisVideodec2FrameBuffer* frameBuffer, OrbisVideodec2FrameBuffer* frameBuffer,
OrbisVideodec2OutputInfo* outputInfo); OrbisVideodec2OutputInfo* outputInfo);
s32 PS4_SYSV_ABI sceVideodec2Flush(OrbisVideodec2Decoder decoder, s32 PS4_SYSV_ABI sceVideodec2Flush(OrbisVideodec2Decoder decoder,
OrbisVideodec2FrameBuffer* frameBuffer, OrbisVideodec2FrameBuffer* frameBuffer,
OrbisVideodec2OutputInfo* outputInfo); OrbisVideodec2OutputInfo* outputInfo);
s32 PS4_SYSV_ABI sceVideodec2Reset(OrbisVideodec2Decoder decoder); s32 PS4_SYSV_ABI sceVideodec2Reset(OrbisVideodec2Decoder decoder);
s32 PS4_SYSV_ABI sceVideodec2GetPictureInfo(const OrbisVideodec2OutputInfo* outputInfo, s32 PS4_SYSV_ABI sceVideodec2GetPictureInfo(const OrbisVideodec2OutputInfo* outputInfo,
void* p1stPictureInfo, void* p2ndPictureInfo); void* p1stPictureInfo, void* p2ndPictureInfo);
void RegisterlibSceVdec2(Core::Loader::SymbolsResolver* sym); void RegisterlibSceVdec2(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::Vdec2 } // namespace Libraries::Vdec2

View File

@ -1,60 +1,60 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include "common/types.h" #include "common/types.h"
namespace Libraries::Vdec2 { namespace Libraries::Vdec2 {
struct OrbisVideodec2AvcPictureInfo { struct OrbisVideodec2AvcPictureInfo {
u64 thisSize; u64 thisSize;
bool isValid; bool isValid;
u64 ptsData; u64 ptsData;
u64 dtsData; u64 dtsData;
u64 attachedData; u64 attachedData;
u8 idrPictureflag; u8 idrPictureflag;
u8 profile_idc; u8 profile_idc;
u8 level_idc; u8 level_idc;
u32 pic_width_in_mbs_minus1; u32 pic_width_in_mbs_minus1;
u32 pic_height_in_map_units_minus1; u32 pic_height_in_map_units_minus1;
u8 frame_mbs_only_flag; u8 frame_mbs_only_flag;
u8 frame_cropping_flag; u8 frame_cropping_flag;
u32 frameCropLeftOffset; u32 frameCropLeftOffset;
u32 frameCropRightOffset; u32 frameCropRightOffset;
u32 frameCropTopOffset; u32 frameCropTopOffset;
u32 frameCropBottomOffset; u32 frameCropBottomOffset;
u8 aspect_ratio_info_present_flag; u8 aspect_ratio_info_present_flag;
u8 aspect_ratio_idc; u8 aspect_ratio_idc;
u16 sar_width; u16 sar_width;
u16 sar_height; u16 sar_height;
u8 video_signal_type_present_flag; u8 video_signal_type_present_flag;
u8 video_format; u8 video_format;
u8 video_full_range_flag; u8 video_full_range_flag;
u8 colour_description_present_flag; u8 colour_description_present_flag;
u8 colour_primaries; u8 colour_primaries;
u8 transfer_characteristics; u8 transfer_characteristics;
u8 matrix_coefficients; u8 matrix_coefficients;
u8 timing_info_present_flag; u8 timing_info_present_flag;
u32 num_units_in_tick; u32 num_units_in_tick;
u32 time_scale; u32 time_scale;
u8 fixed_frame_rate_flag; u8 fixed_frame_rate_flag;
u8 bitstream_restriction_flag; u8 bitstream_restriction_flag;
u8 max_dec_frame_buffering; u8 max_dec_frame_buffering;
u8 pic_struct_present_flag; u8 pic_struct_present_flag;
u8 pic_struct; u8 pic_struct;
u8 field_pic_flag; u8 field_pic_flag;
u8 bottom_field_flag; u8 bottom_field_flag;
}; };
} // namespace Libraries::Vdec2 } // namespace Libraries::Vdec2

View File

@ -1,229 +1,229 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "videodec2_impl.h" #include "videodec2_impl.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/libraries/videodec/videodec_error.h" #include "core/libraries/videodec/videodec_error.h"
#include "common/support/avdec.h" #include "common/support/avdec.h"
namespace Libraries::Vdec2 { namespace Libraries::Vdec2 {
std::vector<OrbisVideodec2AvcPictureInfo> gPictureInfos; std::vector<OrbisVideodec2AvcPictureInfo> gPictureInfos;
static inline void CopyNV12Data(u8* dst, const AVFrame& src) { static inline void CopyNV12Data(u8* dst, const AVFrame& src) {
std::memcpy(dst, src.data[0], src.width * src.height); std::memcpy(dst, src.data[0], src.width * src.height);
std::memcpy(dst + (src.width * src.height), src.data[1], (src.width * src.height) / 2); std::memcpy(dst + (src.width * src.height), src.data[1], (src.width * src.height) / 2);
} }
VdecDecoder::VdecDecoder(const OrbisVideodec2DecoderConfigInfo& configInfo, VdecDecoder::VdecDecoder(const OrbisVideodec2DecoderConfigInfo& configInfo,
const OrbisVideodec2DecoderMemoryInfo& memoryInfo) { const OrbisVideodec2DecoderMemoryInfo& memoryInfo) {
ASSERT(configInfo.codecType == 1); /* AVC */ ASSERT(configInfo.codecType == 1); /* AVC */
const AVCodec* codec = avcodec_find_decoder(AV_CODEC_ID_H264); const AVCodec* codec = avcodec_find_decoder(AV_CODEC_ID_H264);
ASSERT(codec); ASSERT(codec);
mCodecContext = avcodec_alloc_context3(codec); mCodecContext = avcodec_alloc_context3(codec);
ASSERT(mCodecContext); ASSERT(mCodecContext);
mCodecContext->width = configInfo.maxFrameWidth; mCodecContext->width = configInfo.maxFrameWidth;
mCodecContext->height = configInfo.maxFrameHeight; mCodecContext->height = configInfo.maxFrameHeight;
avcodec_open2(mCodecContext, codec, nullptr); avcodec_open2(mCodecContext, codec, nullptr);
} }
VdecDecoder::~VdecDecoder() { VdecDecoder::~VdecDecoder() {
avcodec_free_context(&mCodecContext); avcodec_free_context(&mCodecContext);
sws_freeContext(mSwsContext); sws_freeContext(mSwsContext);
gPictureInfos.clear(); gPictureInfos.clear();
} }
s32 VdecDecoder::Decode(const OrbisVideodec2InputData& inputData, s32 VdecDecoder::Decode(const OrbisVideodec2InputData& inputData,
OrbisVideodec2FrameBuffer& frameBuffer, OrbisVideodec2FrameBuffer& frameBuffer,
OrbisVideodec2OutputInfo& outputInfo) { OrbisVideodec2OutputInfo& outputInfo) {
frameBuffer.isAccepted = false; frameBuffer.isAccepted = false;
outputInfo.thisSize = sizeof(OrbisVideodec2OutputInfo); outputInfo.thisSize = sizeof(OrbisVideodec2OutputInfo);
outputInfo.isValid = false; outputInfo.isValid = false;
outputInfo.isErrorFrame = true; outputInfo.isErrorFrame = true;
outputInfo.pictureCount = 0; outputInfo.pictureCount = 0;
if (!inputData.auData) { if (!inputData.auData) {
return ORBIS_VIDEODEC2_ERROR_ACCESS_UNIT_POINTER; return ORBIS_VIDEODEC2_ERROR_ACCESS_UNIT_POINTER;
} }
if (inputData.auSize == 0) { if (inputData.auSize == 0) {
return ORBIS_VIDEODEC2_ERROR_ACCESS_UNIT_SIZE; return ORBIS_VIDEODEC2_ERROR_ACCESS_UNIT_SIZE;
} }
AVPacket* packet = av_packet_alloc(); AVPacket* packet = av_packet_alloc();
if (!packet) { if (!packet) {
LOG_ERROR(Lib_Vdec2, "Failed to allocate packet"); LOG_ERROR(Lib_Vdec2, "Failed to allocate packet");
return ORBIS_VIDEODEC2_ERROR_API_FAIL; return ORBIS_VIDEODEC2_ERROR_API_FAIL;
} }
packet->data = (u8*)inputData.auData; packet->data = (u8*)inputData.auData;
packet->size = inputData.auSize; packet->size = inputData.auSize;
packet->pts = inputData.ptsData; packet->pts = inputData.ptsData;
packet->dts = inputData.dtsData; packet->dts = inputData.dtsData;
int ret = avcodec_send_packet(mCodecContext, packet); int ret = avcodec_send_packet(mCodecContext, packet);
if (ret < 0) { if (ret < 0) {
LOG_ERROR(Lib_Vdec2, "Error sending packet to decoder: {}", ret); LOG_ERROR(Lib_Vdec2, "Error sending packet to decoder: {}", ret);
av_packet_free(&packet); av_packet_free(&packet);
return ORBIS_VIDEODEC2_ERROR_API_FAIL; return ORBIS_VIDEODEC2_ERROR_API_FAIL;
} }
AVFrame* frame = av_frame_alloc(); AVFrame* frame = av_frame_alloc();
if (frame == nullptr) { if (frame == nullptr) {
LOG_ERROR(Lib_Vdec2, "Failed to allocate frame"); LOG_ERROR(Lib_Vdec2, "Failed to allocate frame");
av_packet_free(&packet); av_packet_free(&packet);
return ORBIS_VIDEODEC2_ERROR_API_FAIL; return ORBIS_VIDEODEC2_ERROR_API_FAIL;
} }
while (true) { while (true) {
ret = avcodec_receive_frame(mCodecContext, frame); ret = avcodec_receive_frame(mCodecContext, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break; break;
} else if (ret < 0) { } else if (ret < 0) {
LOG_ERROR(Lib_Vdec2, "Error receiving frame from decoder: {}", ret); LOG_ERROR(Lib_Vdec2, "Error receiving frame from decoder: {}", ret);
av_packet_free(&packet); av_packet_free(&packet);
av_frame_free(&frame); av_frame_free(&frame);
return ORBIS_VIDEODEC2_ERROR_API_FAIL; return ORBIS_VIDEODEC2_ERROR_API_FAIL;
} }
if (frame->format != AV_PIX_FMT_NV12) { if (frame->format != AV_PIX_FMT_NV12) {
AVFrame* nv12_frame = ConvertNV12Frame(*frame); AVFrame* nv12_frame = ConvertNV12Frame(*frame);
ASSERT(nv12_frame); ASSERT(nv12_frame);
av_frame_free(&frame); av_frame_free(&frame);
frame = nv12_frame; frame = nv12_frame;
} }
CopyNV12Data((u8*)frameBuffer.frameBuffer, *frame); CopyNV12Data((u8*)frameBuffer.frameBuffer, *frame);
frameBuffer.isAccepted = true; frameBuffer.isAccepted = true;
outputInfo.codecType = 1; // FIXME: Hardcoded to AVC outputInfo.codecType = 1; // FIXME: Hardcoded to AVC
outputInfo.frameWidth = frame->width; outputInfo.frameWidth = frame->width;
outputInfo.frameHeight = frame->height; outputInfo.frameHeight = frame->height;
outputInfo.framePitch = frame->linesize[0]; outputInfo.framePitch = frame->linesize[0];
outputInfo.frameBufferSize = frameBuffer.frameBufferSize; outputInfo.frameBufferSize = frameBuffer.frameBufferSize;
outputInfo.frameBuffer = frameBuffer.frameBuffer; outputInfo.frameBuffer = frameBuffer.frameBuffer;
outputInfo.isValid = true; outputInfo.isValid = true;
outputInfo.isErrorFrame = false; outputInfo.isErrorFrame = false;
outputInfo.pictureCount = 1; // TODO: 2 pictures for interlaced video outputInfo.pictureCount = 1; // TODO: 2 pictures for interlaced video
if (outputInfo.isValid) { if (outputInfo.isValid) {
OrbisVideodec2AvcPictureInfo pictureInfo = {}; OrbisVideodec2AvcPictureInfo pictureInfo = {};
pictureInfo.thisSize = sizeof(OrbisVideodec2AvcPictureInfo); pictureInfo.thisSize = sizeof(OrbisVideodec2AvcPictureInfo);
pictureInfo.isValid = true; pictureInfo.isValid = true;
pictureInfo.ptsData = inputData.ptsData; pictureInfo.ptsData = inputData.ptsData;
pictureInfo.dtsData = inputData.dtsData; pictureInfo.dtsData = inputData.dtsData;
pictureInfo.attachedData = inputData.attachedData; pictureInfo.attachedData = inputData.attachedData;
pictureInfo.frameCropLeftOffset = frame->crop_left; pictureInfo.frameCropLeftOffset = frame->crop_left;
pictureInfo.frameCropRightOffset = frame->crop_right; pictureInfo.frameCropRightOffset = frame->crop_right;
pictureInfo.frameCropTopOffset = frame->crop_top; pictureInfo.frameCropTopOffset = frame->crop_top;
pictureInfo.frameCropBottomOffset = frame->crop_bottom; pictureInfo.frameCropBottomOffset = frame->crop_bottom;
gPictureInfos.push_back(pictureInfo); gPictureInfos.push_back(pictureInfo);
} }
} }
av_packet_free(&packet); av_packet_free(&packet);
av_frame_free(&frame); av_frame_free(&frame);
return ORBIS_OK; return ORBIS_OK;
} }
s32 VdecDecoder::Flush(OrbisVideodec2FrameBuffer& frameBuffer, s32 VdecDecoder::Flush(OrbisVideodec2FrameBuffer& frameBuffer,
OrbisVideodec2OutputInfo& outputInfo) { OrbisVideodec2OutputInfo& outputInfo) {
frameBuffer.isAccepted = false; frameBuffer.isAccepted = false;
outputInfo.thisSize = sizeof(OrbisVideodec2OutputInfo); outputInfo.thisSize = sizeof(OrbisVideodec2OutputInfo);
outputInfo.isValid = false; outputInfo.isValid = false;
outputInfo.isErrorFrame = true; outputInfo.isErrorFrame = true;
outputInfo.pictureCount = 0; outputInfo.pictureCount = 0;
AVFrame* frame = av_frame_alloc(); AVFrame* frame = av_frame_alloc();
if (!frame) { if (!frame) {
LOG_ERROR(Lib_Vdec2, "Failed to allocate frame"); LOG_ERROR(Lib_Vdec2, "Failed to allocate frame");
return ORBIS_VIDEODEC2_ERROR_API_FAIL; return ORBIS_VIDEODEC2_ERROR_API_FAIL;
} }
while (true) { while (true) {
int ret = avcodec_receive_frame(mCodecContext, frame); int ret = avcodec_receive_frame(mCodecContext, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break; break;
} else if (ret < 0) { } else if (ret < 0) {
LOG_ERROR(Lib_Vdec2, "Error receiving frame from decoder: {}", ret); LOG_ERROR(Lib_Vdec2, "Error receiving frame from decoder: {}", ret);
av_frame_free(&frame); av_frame_free(&frame);
return ORBIS_VIDEODEC2_ERROR_API_FAIL; return ORBIS_VIDEODEC2_ERROR_API_FAIL;
} }
if (frame->format != AV_PIX_FMT_NV12) { if (frame->format != AV_PIX_FMT_NV12) {
AVFrame* nv12_frame = ConvertNV12Frame(*frame); AVFrame* nv12_frame = ConvertNV12Frame(*frame);
ASSERT(nv12_frame); ASSERT(nv12_frame);
av_frame_free(&frame); av_frame_free(&frame);
frame = nv12_frame; frame = nv12_frame;
} }
CopyNV12Data((u8*)frameBuffer.frameBuffer, *frame); CopyNV12Data((u8*)frameBuffer.frameBuffer, *frame);
frameBuffer.isAccepted = true; frameBuffer.isAccepted = true;
outputInfo.codecType = 1; // FIXME: Hardcoded to AVC outputInfo.codecType = 1; // FIXME: Hardcoded to AVC
outputInfo.frameWidth = frame->width; outputInfo.frameWidth = frame->width;
outputInfo.frameHeight = frame->height; outputInfo.frameHeight = frame->height;
outputInfo.framePitch = frame->linesize[0]; outputInfo.framePitch = frame->linesize[0];
outputInfo.frameBufferSize = frameBuffer.frameBufferSize; outputInfo.frameBufferSize = frameBuffer.frameBufferSize;
outputInfo.frameBuffer = frameBuffer.frameBuffer; outputInfo.frameBuffer = frameBuffer.frameBuffer;
outputInfo.isValid = true; outputInfo.isValid = true;
outputInfo.isErrorFrame = false; outputInfo.isErrorFrame = false;
outputInfo.pictureCount = 1; // TODO: 2 pictures for interlaced video outputInfo.pictureCount = 1; // TODO: 2 pictures for interlaced video
// FIXME: Should we add picture info here too? // FIXME: Should we add picture info here too?
} }
av_frame_free(&frame); av_frame_free(&frame);
return ORBIS_OK; return ORBIS_OK;
} }
s32 VdecDecoder::Reset() { s32 VdecDecoder::Reset() {
avcodec_flush_buffers(mCodecContext); avcodec_flush_buffers(mCodecContext);
gPictureInfos.clear(); gPictureInfos.clear();
return ORBIS_OK; return ORBIS_OK;
} }
AVFrame* VdecDecoder::ConvertNV12Frame(AVFrame& frame) { AVFrame* VdecDecoder::ConvertNV12Frame(AVFrame& frame) {
AVFrame* nv12_frame = av_frame_alloc(); AVFrame* nv12_frame = av_frame_alloc();
nv12_frame->pts = frame.pts; nv12_frame->pts = frame.pts;
nv12_frame->pkt_dts = frame.pkt_dts < 0 ? 0 : frame.pkt_dts; nv12_frame->pkt_dts = frame.pkt_dts < 0 ? 0 : frame.pkt_dts;
nv12_frame->format = AV_PIX_FMT_NV12; nv12_frame->format = AV_PIX_FMT_NV12;
nv12_frame->width = frame.width; nv12_frame->width = frame.width;
nv12_frame->height = frame.height; nv12_frame->height = frame.height;
nv12_frame->sample_aspect_ratio = frame.sample_aspect_ratio; nv12_frame->sample_aspect_ratio = frame.sample_aspect_ratio;
nv12_frame->crop_top = frame.crop_top; nv12_frame->crop_top = frame.crop_top;
nv12_frame->crop_bottom = frame.crop_bottom; nv12_frame->crop_bottom = frame.crop_bottom;
nv12_frame->crop_left = frame.crop_left; nv12_frame->crop_left = frame.crop_left;
nv12_frame->crop_right = frame.crop_right; nv12_frame->crop_right = frame.crop_right;
av_frame_get_buffer(nv12_frame, 0); av_frame_get_buffer(nv12_frame, 0);
if (mSwsContext == nullptr) { if (mSwsContext == nullptr) {
mSwsContext = sws_getContext(frame.width, frame.height, AVPixelFormat(frame.format), mSwsContext = sws_getContext(frame.width, frame.height, AVPixelFormat(frame.format),
nv12_frame->width, nv12_frame->height, AV_PIX_FMT_NV12, nv12_frame->width, nv12_frame->height, AV_PIX_FMT_NV12,
SWS_FAST_BILINEAR, nullptr, nullptr, nullptr); SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
} }
const auto res = sws_scale(mSwsContext, frame.data, frame.linesize, 0, frame.height, const auto res = sws_scale(mSwsContext, frame.data, frame.linesize, 0, frame.height,
nv12_frame->data, nv12_frame->linesize); nv12_frame->data, nv12_frame->linesize);
if (res < 0) { if (res < 0) {
LOG_ERROR(Lib_Vdec2, "Could not convert to NV12: {}", av_err2str(res)); LOG_ERROR(Lib_Vdec2, "Could not convert to NV12: {}", av_err2str(res));
return nullptr; return nullptr;
} }
return nv12_frame; return nv12_frame;
} }
} // namespace Libraries::Vdec2 } // namespace Libraries::Vdec2

View File

@ -1,39 +1,39 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include <vector> #include <vector>
#include "videodec2.h" #include "videodec2.h"
extern "C" { extern "C" {
#include <libavcodec/avcodec.h> #include <libavcodec/avcodec.h>
#include <libavutil/imgutils.h> #include <libavutil/imgutils.h>
#include <libswscale/swscale.h> #include <libswscale/swscale.h>
} }
namespace Libraries::Vdec2 { namespace Libraries::Vdec2 {
extern std::vector<OrbisVideodec2AvcPictureInfo> gPictureInfos; extern std::vector<OrbisVideodec2AvcPictureInfo> gPictureInfos;
class VdecDecoder { class VdecDecoder {
public: public:
VdecDecoder(const OrbisVideodec2DecoderConfigInfo& configInfo, VdecDecoder(const OrbisVideodec2DecoderConfigInfo& configInfo,
const OrbisVideodec2DecoderMemoryInfo& memoryInfo); const OrbisVideodec2DecoderMemoryInfo& memoryInfo);
~VdecDecoder(); ~VdecDecoder();
s32 Decode(const OrbisVideodec2InputData& inputData, OrbisVideodec2FrameBuffer& frameBuffer, s32 Decode(const OrbisVideodec2InputData& inputData, OrbisVideodec2FrameBuffer& frameBuffer,
OrbisVideodec2OutputInfo& outputInfo); OrbisVideodec2OutputInfo& outputInfo);
s32 Flush(OrbisVideodec2FrameBuffer& frameBuffer, OrbisVideodec2OutputInfo& outputInfo); s32 Flush(OrbisVideodec2FrameBuffer& frameBuffer, OrbisVideodec2OutputInfo& outputInfo);
s32 Reset(); s32 Reset();
private: private:
AVFrame* ConvertNV12Frame(AVFrame& frame); AVFrame* ConvertNV12Frame(AVFrame& frame);
private: private:
AVCodecContext* mCodecContext = nullptr; AVCodecContext* mCodecContext = nullptr;
SwsContext* mSwsContext = nullptr; SwsContext* mSwsContext = nullptr;
}; };
} // namespace Libraries::Vdec2 } // namespace Libraries::Vdec2

View File

@ -1,151 +1,152 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "common/alignment.h" #include "common/alignment.h"
#include "core/libraries/kernel/threads/pthread.h" #include "core/libraries/kernel/threads/pthread.h"
#include "thread.h" #include "thread.h"
#ifdef _WIN64 #ifdef _WIN64
#include <windows.h> #include <windows.h>
#include "common/ntapi.h" #include "common/ntapi.h"
#else #else
#include <csignal> #include <csignal>
#include <pthread.h> #include <pthread.h>
#endif #include <unistd.h>
#endif
namespace Core {
namespace Core {
#ifdef _WIN64
#define KGDT64_R3_DATA (0x28) #ifdef _WIN64
#define KGDT64_R3_CODE (0x30) #define KGDT64_R3_DATA (0x28)
#define KGDT64_R3_CMTEB (0x50) #define KGDT64_R3_CODE (0x30)
#define RPL_MASK (0x03) #define KGDT64_R3_CMTEB (0x50)
#define RPL_MASK (0x03)
#define INITIAL_FPUCW (0x037f)
#define INITIAL_MXCSR_MASK (0xffbf) #define INITIAL_FPUCW (0x037f)
#define EFLAGS_INTERRUPT_MASK (0x200) #define INITIAL_MXCSR_MASK (0xffbf)
#define EFLAGS_INTERRUPT_MASK (0x200)
void InitializeTeb(INITIAL_TEB* teb, const ::Libraries::Kernel::PthreadAttr* attr) {
teb->StackBase = (void*)((u64)attr->stackaddr_attr + attr->stacksize_attr); void InitializeTeb(INITIAL_TEB* teb, const ::Libraries::Kernel::PthreadAttr* attr) {
teb->StackLimit = nullptr; teb->StackBase = (void*)((u64)attr->stackaddr_attr + attr->stacksize_attr);
teb->StackAllocationBase = attr->stackaddr_attr; teb->StackLimit = nullptr;
} teb->StackAllocationBase = attr->stackaddr_attr;
}
void InitializeContext(CONTEXT* ctx, ThreadFunc func, void* arg,
const ::Libraries::Kernel::PthreadAttr* attr) { void InitializeContext(CONTEXT* ctx, ThreadFunc func, void* arg,
/* Note: The stack has to be reversed */ const ::Libraries::Kernel::PthreadAttr* attr) {
ctx->Rsp = (u64)attr->stackaddr_attr + attr->stacksize_attr; /* Note: The stack has to be reversed */
ctx->Rbp = (u64)attr->stackaddr_attr + attr->stacksize_attr; ctx->Rsp = (u64)attr->stackaddr_attr + attr->stacksize_attr;
ctx->Rcx = (u64)arg; ctx->Rbp = (u64)attr->stackaddr_attr + attr->stacksize_attr;
ctx->Rip = (u64)func; ctx->Rcx = (u64)arg;
ctx->Rip = (u64)func;
ctx->SegGs = KGDT64_R3_DATA | RPL_MASK;
ctx->SegEs = KGDT64_R3_DATA | RPL_MASK; ctx->SegGs = KGDT64_R3_DATA | RPL_MASK;
ctx->SegDs = KGDT64_R3_DATA | RPL_MASK; ctx->SegEs = KGDT64_R3_DATA | RPL_MASK;
ctx->SegCs = KGDT64_R3_CODE | RPL_MASK; ctx->SegDs = KGDT64_R3_DATA | RPL_MASK;
ctx->SegSs = KGDT64_R3_DATA | RPL_MASK; ctx->SegCs = KGDT64_R3_CODE | RPL_MASK;
ctx->SegFs = KGDT64_R3_CMTEB | RPL_MASK; ctx->SegSs = KGDT64_R3_DATA | RPL_MASK;
ctx->SegFs = KGDT64_R3_CMTEB | RPL_MASK;
ctx->EFlags = 0x3000 | EFLAGS_INTERRUPT_MASK;
ctx->MxCsr = INITIAL_MXCSR; ctx->EFlags = 0x3000 | EFLAGS_INTERRUPT_MASK;
ctx->MxCsr = INITIAL_MXCSR;
ctx->FltSave.ControlWord = INITIAL_FPUCW;
ctx->FltSave.MxCsr = INITIAL_MXCSR; ctx->FltSave.ControlWord = INITIAL_FPUCW;
ctx->FltSave.MxCsr_Mask = INITIAL_MXCSR_MASK; ctx->FltSave.MxCsr = INITIAL_MXCSR;
ctx->FltSave.MxCsr_Mask = INITIAL_MXCSR_MASK;
ctx->ContextFlags =
CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT; ctx->ContextFlags =
} CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT;
#endif }
#endif
NativeThread::NativeThread() : native_handle{0} {}
NativeThread::NativeThread() : native_handle{0} {}
NativeThread::~NativeThread() {}
NativeThread::~NativeThread() {}
int NativeThread::Create(ThreadFunc func, void* arg, const ::Libraries::Kernel::PthreadAttr* attr) {
#ifndef _WIN64 int NativeThread::Create(ThreadFunc func, void* arg, const ::Libraries::Kernel::PthreadAttr* attr) {
pthread_t* pthr = reinterpret_cast<pthread_t*>(&native_handle); #ifndef _WIN64
pthread_attr_t pattr; pthread_t* pthr = reinterpret_cast<pthread_t*>(&native_handle);
pthread_attr_init(&pattr); pthread_attr_t pattr;
pthread_attr_setstack(&pattr, attr->stackaddr_attr, attr->stacksize_attr); pthread_attr_init(&pattr);
return pthread_create(pthr, &pattr, (PthreadFunc)func, arg); pthread_attr_setstack(&pattr, attr->stackaddr_attr, attr->stacksize_attr);
#else return pthread_create(pthr, &pattr, (PthreadFunc)func, arg);
CLIENT_ID clientId{}; #else
INITIAL_TEB teb{}; CLIENT_ID clientId{};
CONTEXT ctx{}; INITIAL_TEB teb{};
CONTEXT ctx{};
clientId.UniqueProcess = GetCurrentProcess();
clientId.UniqueThread = GetCurrentThread(); clientId.UniqueProcess = GetCurrentProcess();
clientId.UniqueThread = GetCurrentThread();
InitializeTeb(&teb, attr);
InitializeContext(&ctx, func, arg, attr); InitializeTeb(&teb, attr);
InitializeContext(&ctx, func, arg, attr);
return NtCreateThread(&native_handle, THREAD_ALL_ACCESS, nullptr, GetCurrentProcess(),
&clientId, &ctx, &teb, false); return NtCreateThread(&native_handle, THREAD_ALL_ACCESS, nullptr, GetCurrentProcess(),
#endif &clientId, &ctx, &teb, false);
} #endif
}
void NativeThread::Exit() {
if (!native_handle) { void NativeThread::Exit() {
return; if (!native_handle) {
} return;
}
tid = 0;
tid = 0;
#ifdef _WIN64
NtClose(native_handle); #ifdef _WIN64
native_handle = nullptr; NtClose(native_handle);
native_handle = nullptr;
/* The Windows kernel will free the stack
given at thread creation via INITIAL_TEB /* The Windows kernel will free the stack
(StackAllocationBase) upon thread termination. given at thread creation via INITIAL_TEB
(StackAllocationBase) upon thread termination.
In earlier Windows versions (NT4 to Windows Server 2003),
you could get around this via disabling FreeStackOnTermination In earlier Windows versions (NT4 to Windows Server 2003),
on the TEB. This has been removed since then. you could get around this via disabling FreeStackOnTermination
on the TEB. This has been removed since then.
To avoid this, we must forcefully set the TEB
deallocation stack pointer to NULL so ZwFreeVirtualMemory fails To avoid this, we must forcefully set the TEB
in the kernel and our stack is not freed. deallocation stack pointer to NULL so ZwFreeVirtualMemory fails
*/ in the kernel and our stack is not freed.
auto* teb = reinterpret_cast<TEB*>(NtCurrentTeb()); */
teb->DeallocationStack = nullptr; auto* teb = reinterpret_cast<TEB*>(NtCurrentTeb());
teb->DeallocationStack = nullptr;
NtTerminateThread(nullptr, 0);
#else NtTerminateThread(nullptr, 0);
// Disable and free the signal stack. #else
constexpr stack_t sig_stack = { // Disable and free the signal stack.
.ss_flags = SS_DISABLE, constexpr stack_t sig_stack = {
}; .ss_flags = SS_DISABLE,
sigaltstack(&sig_stack, nullptr); };
sigaltstack(&sig_stack, nullptr);
if (sig_stack_ptr) {
free(sig_stack_ptr); if (sig_stack_ptr) {
sig_stack_ptr = nullptr; free(sig_stack_ptr);
} sig_stack_ptr = nullptr;
}
pthread_exit(nullptr);
#endif pthread_exit(nullptr);
} #endif
}
void NativeThread::Initialize() {
#if _WIN64 void NativeThread::Initialize() {
tid = GetCurrentThreadId(); #if _WIN64
#else tid = GetCurrentThreadId();
tid = (u64)pthread_self(); #else
tid = (u64)pthread_self();
// Set up an alternate signal handler stack to avoid overflowing small thread stacks.
const size_t page_size = getpagesize(); // Set up an alternate signal handler stack to avoid overflowing small thread stacks.
const size_t sig_stack_size = Common::AlignUp(std::max<size_t>(64_KB, MINSIGSTKSZ), page_size); const size_t page_size = getpagesize();
ASSERT_MSG(posix_memalign(&sig_stack_ptr, page_size, sig_stack_size) == 0, const size_t sig_stack_size = Common::AlignUp(std::max<size_t>(64_KB, MINSIGSTKSZ), page_size);
"Failed to allocate signal stack: {}", errno); ASSERT_MSG(posix_memalign(&sig_stack_ptr, page_size, sig_stack_size) == 0,
"Failed to allocate signal stack: {}", errno);
stack_t sig_stack;
sig_stack.ss_sp = sig_stack_ptr; stack_t sig_stack;
sig_stack.ss_size = sig_stack_size; sig_stack.ss_sp = sig_stack_ptr;
sig_stack.ss_flags = 0; sig_stack.ss_size = sig_stack_size;
ASSERT_MSG(sigaltstack(&sig_stack, nullptr) == 0, "Failed to set signal stack: {}", errno); sig_stack.ss_flags = 0;
#endif ASSERT_MSG(sigaltstack(&sig_stack, nullptr) == 0, "Failed to set signal stack: {}", errno);
} #endif
}
} // namespace Core
} // namespace Core

View File

@ -1,45 +1,45 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include "common/types.h" #include "common/types.h"
namespace Libraries::Kernel { namespace Libraries::Kernel {
struct PthreadAttr; struct PthreadAttr;
} // namespace Libraries::Kernel } // namespace Libraries::Kernel
namespace Core { namespace Core {
using ThreadFunc = void (*)(void*); using ThreadFunc = void (*)(void*);
using PthreadFunc = void* (*)(void*); using PthreadFunc = void* (*)(void*);
class NativeThread { class NativeThread {
public: public:
NativeThread(); NativeThread();
~NativeThread(); ~NativeThread();
int Create(ThreadFunc func, void* arg, const ::Libraries::Kernel::PthreadAttr* attr); int Create(ThreadFunc func, void* arg, const ::Libraries::Kernel::PthreadAttr* attr);
void Exit(); void Exit();
void Initialize(); void Initialize();
uintptr_t GetHandle() { uintptr_t GetHandle() {
return reinterpret_cast<uintptr_t>(native_handle); return reinterpret_cast<uintptr_t>(native_handle);
} }
u64 GetTid() { u64 GetTid() {
return tid; return tid;
} }
private: private:
#ifdef _WIN64 #ifdef _WIN64
void* native_handle; void* native_handle;
#else #else
uintptr_t native_handle; uintptr_t native_handle;
void* sig_stack_ptr; void* sig_stack_ptr;
#endif #endif
u64 tid; u64 tid;
}; };
} // namespace Core } // namespace Core

View File

@ -9,6 +9,10 @@ namespace Xbyak {
class CodeGenerator; class CodeGenerator;
} }
namespace Libraries::Fiber {
struct OrbisFiberContext;
}
namespace Core { namespace Core {
union DtvEntry { union DtvEntry {
@ -20,6 +24,7 @@ struct Tcb {
Tcb* tcb_self; Tcb* tcb_self;
DtvEntry* tcb_dtv; DtvEntry* tcb_dtv;
void* tcb_thread; void* tcb_thread;
::Libraries::Fiber::OrbisFiberContext* tcb_fiber;
}; };
#ifdef _WIN32 #ifdef _WIN32

View File

@ -15,6 +15,7 @@
#include <QNetworkRequest> #include <QNetworkRequest>
#include <QProcess> #include <QProcess>
#include <QPushButton> #include <QPushButton>
#include <QStandardPaths>
#include <QString> #include <QString>
#include <QStringList> #include <QStringList>
#include <QTextEdit> #include <QTextEdit>
@ -212,9 +213,9 @@ void CheckUpdate::setupUI(const QString& downloadUrl, const QString& latestDate,
// Don't show changelog button if: // Don't show changelog button if:
// The current version is a pre-release and the version to be downloaded is a release. // 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 current_isWIP = currentRev.endsWith("WIP", Qt::CaseInsensitive);
bool latest_isRelease = latestRev.startsWith('v', Qt::CaseInsensitive); bool latest_isWIP = latestRev.endsWith("WIP", Qt::CaseInsensitive);
if (!current_isRelease && latest_isRelease) { if (current_isWIP && !latest_isWIP) {
} else { } else {
QTextEdit* textField = new QTextEdit(this); QTextEdit* textField = new QTextEdit(this);
textField->setReadOnly(true); textField->setReadOnly(true);
@ -348,7 +349,9 @@ void CheckUpdate::DownloadUpdate(const QString& url) {
QString userPath; QString userPath;
Common::FS::PathToQString(userPath, Common::FS::GetUserPath(Common::FS::PathType::UserDir)); Common::FS::PathToQString(userPath, Common::FS::GetUserPath(Common::FS::PathType::UserDir));
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
QString tempDownloadPath = QString(getenv("LOCALAPPDATA")) + "/Temp/temp_download_update"; QString tempDownloadPath =
QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) +
"/Temp/temp_download_update";
#else #else
QString tempDownloadPath = userPath + "/temp_download_update"; QString tempDownloadPath = userPath + "/temp_download_update";
#endif #endif
@ -397,10 +400,11 @@ void CheckUpdate::Install() {
QString processCommand; QString processCommand;
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
// On windows, overwrite tempDirPath with AppData/Local/Temp folder // On windows, overwrite tempDirPath with AppData/Roaming/shadps4/Temp folder
// due to PowerShell Expand-Archive not being able to handle correctly // due to PowerShell Expand-Archive not being able to handle correctly
// paths in square brackets (ie: ./[shadps4]) // paths in square brackets (ie: ./[shadps4])
tempDirPath = QString(getenv("LOCALAPPDATA")) + "/Temp/temp_download_update"; tempDirPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) +
"/Temp/temp_download_update";
// Windows Batch Script // Windows Batch Script
scriptFileName = tempDirPath + "/update.ps1"; scriptFileName = tempDirPath + "/update.ps1";
@ -536,6 +540,7 @@ void CheckUpdate::Install() {
QFile scriptFile(scriptFileName); QFile scriptFile(scriptFileName);
if (scriptFile.open(QIODevice::WriteOnly | QIODevice::Text)) { if (scriptFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream out(&scriptFile); QTextStream out(&scriptFile);
scriptFile.write("\xEF\xBB\xBF");
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
out << scriptContent.arg(binaryStartingUpdate).arg(tempDirPath).arg(rootPath); out << scriptContent.arg(binaryStartingUpdate).arg(tempDirPath).arg(rootPath);
#endif #endif

View File

@ -18,9 +18,10 @@ CompatibilityInfoClass::CompatibilityInfoClass()
}; };
CompatibilityInfoClass::~CompatibilityInfoClass() = default; CompatibilityInfoClass::~CompatibilityInfoClass() = default;
void CompatibilityInfoClass::UpdateCompatibilityDatabase(QWidget* parent) { void CompatibilityInfoClass::UpdateCompatibilityDatabase(QWidget* parent, bool forced) {
if (LoadCompatibilityFile()) if (!forced)
return; if (LoadCompatibilityFile())
return;
QNetworkReply* reply = FetchPage(1); QNetworkReply* reply = FetchPage(1);
if (!WaitForReply(reply)) if (!WaitForReply(reply))
@ -45,7 +46,8 @@ void CompatibilityInfoClass::UpdateCompatibilityDatabase(QWidget* parent) {
QMessageBox::critical(parent, tr("Error"), QMessageBox::critical(parent, tr("Error"),
tr("Unable to update compatibility data! Try again later.")); tr("Unable to update compatibility data! Try again later."));
// Try loading compatibility_file.json again // Try loading compatibility_file.json again
LoadCompatibilityFile(); if (!forced)
LoadCompatibilityFile();
return; return;
} }

View File

@ -84,7 +84,7 @@ public:
CompatibilityInfoClass(); CompatibilityInfoClass();
~CompatibilityInfoClass(); ~CompatibilityInfoClass();
void UpdateCompatibilityDatabase(QWidget* parent = nullptr); void UpdateCompatibilityDatabase(QWidget* parent = nullptr, bool forced = false);
bool LoadCompatibilityFile(); bool LoadCompatibilityFile();
CompatibilityEntry GetCompatibilityInfo(const std::string& serial); CompatibilityEntry GetCompatibilityInfo(const std::string& serial);
void ExtractCompatibilityInfo(QByteArray response); void ExtractCompatibilityInfo(QByteArray response);

View File

@ -3,9 +3,12 @@
#include "common/path_util.h" #include "common/path_util.h"
#include "game_grid_frame.h" #include "game_grid_frame.h"
#include "qt_gui/compatibility_info.h"
GameGridFrame::GameGridFrame(std::shared_ptr<GameInfoClass> game_info_get, QWidget* parent) GameGridFrame::GameGridFrame(std::shared_ptr<GameInfoClass> game_info_get,
: QTableWidget(parent), m_game_info(game_info_get) { std::shared_ptr<CompatibilityInfoClass> compat_info_get,
QWidget* parent)
: QTableWidget(parent), m_game_info(game_info_get), m_compat_info(compat_info_get) {
icon_size = Config::getIconSizeGrid(); icon_size = Config::getIconSizeGrid();
windowWidth = parent->width(); windowWidth = parent->width();
this->setShowGrid(false); this->setShowGrid(false);
@ -29,7 +32,7 @@ GameGridFrame::GameGridFrame(std::shared_ptr<GameInfoClass> game_info_get, QWidg
connect(this->horizontalScrollBar(), &QScrollBar::valueChanged, this, connect(this->horizontalScrollBar(), &QScrollBar::valueChanged, this,
&GameGridFrame::RefreshGridBackgroundImage); &GameGridFrame::RefreshGridBackgroundImage);
connect(this, &QTableWidget::customContextMenuRequested, this, [=, this](const QPoint& pos) { 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);
}); });
} }

View File

@ -10,6 +10,7 @@
#include "game_info.h" #include "game_info.h"
#include "game_list_utils.h" #include "game_list_utils.h"
#include "gui_context_menus.h" #include "gui_context_menus.h"
#include "qt_gui/compatibility_info.h"
class GameGridFrame : public QTableWidget { class GameGridFrame : public QTableWidget {
Q_OBJECT Q_OBJECT
@ -29,11 +30,14 @@ private:
GameListUtils m_game_list_utils; GameListUtils m_game_list_utils;
GuiContextMenus m_gui_context_menus; GuiContextMenus m_gui_context_menus;
std::shared_ptr<GameInfoClass> m_game_info; std::shared_ptr<GameInfoClass> m_game_info;
std::shared_ptr<CompatibilityInfoClass> m_compat_info;
std::shared_ptr<QVector<GameInfo>> m_games_shared; std::shared_ptr<QVector<GameInfo>> m_games_shared;
bool validCellSelected = false; bool validCellSelected = false;
public: public:
explicit GameGridFrame(std::shared_ptr<GameInfoClass> game_info_get, QWidget* parent = nullptr); explicit GameGridFrame(std::shared_ptr<GameInfoClass> game_info_get,
std::shared_ptr<CompatibilityInfoClass> compat_info_get,
QWidget* parent = nullptr);
void PopulateGameGrid(QVector<GameInfo> m_games, bool fromSearch); void PopulateGameGrid(QVector<GameInfo> m_games, bool fromSearch);
bool IsValidCellSelected(); bool IsValidCellSelected();

View File

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <QToolTip> #include <QToolTip>
#include "common/config.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/path_util.h" #include "common/path_util.h"
#include "common/string_util.h" #include "common/string_util.h"
@ -72,7 +73,7 @@ GameListFrame::GameListFrame(std::shared_ptr<GameInfoClass> game_info_get,
}); });
connect(this, &QTableWidget::customContextMenuRequested, this, [=, this](const QPoint& pos) { 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) { connect(this, &QTableWidget::cellClicked, this, [=, this](int row, int column) {
@ -80,11 +81,6 @@ GameListFrame::GameListFrame(std::shared_ptr<GameInfoClass> game_info_get,
QDesktopServices::openUrl(QUrl(m_game_info->m_games[row].compatibility.url)); 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, void GameListFrame::onCurrentCellChanged(int currentRow, int currentColumn, int previousRow,
@ -108,6 +104,8 @@ void GameListFrame::PlayBackgroundMusic(QTableWidgetItem* item) {
} }
void GameListFrame::PopulateGameList() { 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()); this->setRowCount(m_game_info->m_games.size());
ResizeIcons(icon_size); ResizeIcons(icon_size);
@ -241,7 +239,7 @@ void GameListFrame::SetCompatibilityItem(int row, int column, CompatibilityEntry
break; break;
case CompatibilityStatus::Nothing: case CompatibilityStatus::Nothing:
color = QStringLiteral("#212121"); 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; break;
case CompatibilityStatus::Boots: case CompatibilityStatus::Boots:
color = QStringLiteral("#828282"); color = QStringLiteral("#828282");

View File

@ -11,6 +11,9 @@
#include <QTreeWidgetItem> #include <QTreeWidgetItem>
#include "cheats_patches.h" #include "cheats_patches.h"
#include "common/config.h"
#include "common/version.h"
#include "compatibility_info.h"
#include "game_info.h" #include "game_info.h"
#include "trophy_viewer.h" #include "trophy_viewer.h"
@ -27,8 +30,9 @@
class GuiContextMenus : public QObject { class GuiContextMenus : public QObject {
Q_OBJECT Q_OBJECT
public: public:
void RequestGameMenu(const QPoint& pos, QVector<GameInfo> m_games, QTableWidget* widget, void RequestGameMenu(const QPoint& pos, QVector<GameInfo> m_games,
bool isList) { std::shared_ptr<CompatibilityInfoClass> m_compat_info,
QTableWidget* widget, bool isList) {
QPoint global_pos = widget->viewport()->mapToGlobal(pos); QPoint global_pos = widget->viewport()->mapToGlobal(pos);
int itemID = 0; int itemID = 0;
if (isList) { if (isList) {
@ -91,6 +95,21 @@ public:
menu.addMenu(deleteMenu); 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. // Show menu.
auto selected = menu.exec(global_pos); auto selected = menu.exec(global_pos);
if (!selected) { if (!selected) {
@ -268,11 +287,11 @@ public:
#endif #endif
QMessageBox::information( QMessageBox::information(
nullptr, tr("Shortcut creation"), nullptr, tr("Shortcut creation"),
QString(tr("Shortcut created successfully!\n %1")).arg(linkPath)); QString(tr("Shortcut created successfully!") + "\n%1").arg(linkPath));
} else { } else {
QMessageBox::critical( QMessageBox::critical(
nullptr, tr("Error"), nullptr, tr("Error"),
QString(tr("Error creating shortcut!\n %1")).arg(linkPath)); QString(tr("Error creating shortcut!") + "\n%1").arg(linkPath));
} }
} else { } else {
QMessageBox::critical(nullptr, tr("Error"), tr("Failed to convert icon.")); QMessageBox::critical(nullptr, tr("Error"), tr("Failed to convert icon."));
@ -286,11 +305,11 @@ public:
#endif #endif
QMessageBox::information( QMessageBox::information(
nullptr, tr("Shortcut creation"), nullptr, tr("Shortcut creation"),
QString(tr("Shortcut created successfully!\n %1")).arg(linkPath)); QString(tr("Shortcut created successfully!") + "\n%1").arg(linkPath));
} else { } else {
QMessageBox::critical( QMessageBox::critical(
nullptr, tr("Error"), 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) { int GetRowIndex(QTreeWidget* treeWidget, QTreeWidgetItem* item) {

View File

@ -153,7 +153,7 @@ void MainWindow::CreateDockWindows() {
m_dock_widget.reset(new QDockWidget(tr("Game List"), this)); 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.reset(new GameListFrame(m_game_info, m_compat_info, this));
m_game_list_frame->setObjectName("gamelist"); 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_game_grid_frame->setObjectName("gamegridlist");
m_elf_viewer.reset(new ElfViewer(this)); m_elf_viewer.reset(new ElfViewer(this));
m_elf_viewer->setObjectName("elflist"); m_elf_viewer->setObjectName("elflist");
@ -266,20 +266,26 @@ void MainWindow::CreateConnects() {
&MainWindow::StartGame); &MainWindow::StartGame);
connect(ui->configureAct, &QAction::triggered, this, [this]() { 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, connect(settingsDialog, &SettingsDialog::LanguageChanged, this,
&MainWindow::OnLanguageChanged); &MainWindow::OnLanguageChanged);
connect(settingsDialog, &SettingsDialog::CompatibilityChanged, this,
&MainWindow::RefreshGameTable);
settingsDialog->exec(); settingsDialog->exec();
}); });
connect(ui->settingsButton, &QPushButton::clicked, this, [this]() { 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, connect(settingsDialog, &SettingsDialog::LanguageChanged, this,
&MainWindow::OnLanguageChanged); &MainWindow::OnLanguageChanged);
connect(settingsDialog, &SettingsDialog::CompatibilityChanged, this,
&MainWindow::RefreshGameTable);
settingsDialog->exec(); settingsDialog->exec();
}); });

View File

@ -6,6 +6,8 @@
#include <QHoverEvent> #include <QHoverEvent>
#include <common/version.h> #include <common/version.h>
#include "common/config.h"
#include "qt_gui/compatibility_info.h"
#ifdef ENABLE_DISCORD_RPC #ifdef ENABLE_DISCORD_RPC
#include "common/discord_rpc_handler.h" #include "common/discord_rpc_handler.h"
#endif #endif
@ -55,7 +57,9 @@ QStringList languageNames = {"Arabic",
const QVector<int> languageIndexes = {21, 23, 14, 6, 18, 1, 12, 22, 2, 4, 25, 24, 29, 5, 0, 9, const QVector<int> 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}; 15, 16, 17, 7, 26, 8, 11, 20, 3, 13, 27, 10, 19, 30, 28};
SettingsDialog::SettingsDialog(std::span<const QString> physical_devices, QWidget* parent) SettingsDialog::SettingsDialog(std::span<const QString> physical_devices,
std::shared_ptr<CompatibilityInfoClass> m_compat_info,
QWidget* parent)
: QDialog(parent), ui(new Ui::SettingsDialog) { : QDialog(parent), ui(new Ui::SettingsDialog) {
ui->setupUi(this); ui->setupUi(this);
ui->tabWidgetSettings->setUsesScrollButtons(false); ui->tabWidgetSettings->setUsesScrollButtons(false);
@ -141,6 +145,16 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices, QWidge
ui->updaterGroupBox->setVisible(false); ui->updaterGroupBox->setVisible(false);
ui->GUIgroupBox->setMaximumSize(265, 16777215); ui->GUIgroupBox->setMaximumSize(265, 16777215);
#endif #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 // Input TAB
@ -197,6 +211,9 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices, QWidge
ui->GUIgroupBox->installEventFilter(this); ui->GUIgroupBox->installEventFilter(this);
ui->widgetComboBox->installEventFilter(this); ui->widgetComboBox->installEventFilter(this);
ui->disableTrophycheckBox->installEventFilter(this); ui->disableTrophycheckBox->installEventFilter(this);
ui->enableCompatibilityCheckBox->installEventFilter(this);
ui->checkCompatibilityOnStartupCheckBox->installEventFilter(this);
ui->updateCompatibilityButton->installEventFilter(this);
// Input // Input
ui->hideCursorGroupBox->installEventFilter(this); ui->hideCursorGroupBox->installEventFilter(this);
@ -291,6 +308,10 @@ void SettingsDialog::LoadValuesFromConfig() {
ui->vkSyncValidationCheckBox->setChecked( ui->vkSyncValidationCheckBox->setChecked(
toml::find_or<bool>(data, "Vulkan", "validation_sync", false)); toml::find_or<bool>(data, "Vulkan", "validation_sync", false));
ui->rdocCheckBox->setChecked(toml::find_or<bool>(data, "Vulkan", "rdocEnable", false)); ui->rdocCheckBox->setChecked(toml::find_or<bool>(data, "Vulkan", "rdocEnable", false));
ui->enableCompatibilityCheckBox->setChecked(
toml::find_or<bool>(data, "General", "compatibilityEnabled", false));
ui->checkCompatibilityOnStartupCheckBox->setChecked(
toml::find_or<bool>(data, "General", "checkCompatibilityOnStartup", false));
#ifdef ENABLE_UPDATER #ifdef ENABLE_UPDATER
ui->updateCheckBox->setChecked(toml::find_or<bool>(data, "General", "autoUpdate", false)); ui->updateCheckBox->setChecked(toml::find_or<bool>(data, "General", "autoUpdate", false));
@ -410,6 +431,12 @@ void SettingsDialog::updateNoteTextEdit(const QString& elementName) {
text = tr("widgetComboBox"); text = tr("widgetComboBox");
} else if (elementName == "disableTrophycheckBox") { } else if (elementName == "disableTrophycheckBox") {
text = tr("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");
} }
// Input // Input
@ -524,6 +551,8 @@ void SettingsDialog::UpdateSettings() {
Config::setRdocEnabled(ui->rdocCheckBox->isChecked()); Config::setRdocEnabled(ui->rdocCheckBox->isChecked());
Config::setAutoUpdate(ui->updateCheckBox->isChecked()); Config::setAutoUpdate(ui->updateCheckBox->isChecked());
Config::setUpdateChannel(ui->updateComboBox->currentText().toStdString()); Config::setUpdateChannel(ui->updateComboBox->currentText().toStdString());
Config::setCompatibilityEnabled(ui->enableCompatibilityCheckBox->isChecked());
Config::setCheckCompatibilityOnStartup(ui->checkCompatibilityOnStartupCheckBox->isChecked());
#ifdef ENABLE_DISCORD_RPC #ifdef ENABLE_DISCORD_RPC
auto* rpc = Common::Singleton<DiscordRPCHandler::RPC>::Instance(); auto* rpc = Common::Singleton<DiscordRPCHandler::RPC>::Instance();

View File

@ -3,6 +3,7 @@
#pragma once #pragma once
#include <memory>
#include <span> #include <span>
#include <QDialog> #include <QDialog>
#include <QGroupBox> #include <QGroupBox>
@ -10,6 +11,7 @@
#include "common/config.h" #include "common/config.h"
#include "common/path_util.h" #include "common/path_util.h"
#include "qt_gui/compatibility_info.h"
namespace Ui { namespace Ui {
class SettingsDialog; class SettingsDialog;
@ -18,7 +20,9 @@ class SettingsDialog;
class SettingsDialog : public QDialog { class SettingsDialog : public QDialog {
Q_OBJECT Q_OBJECT
public: public:
explicit SettingsDialog(std::span<const QString> physical_devices, QWidget* parent = nullptr); explicit SettingsDialog(std::span<const QString> physical_devices,
std::shared_ptr<CompatibilityInfoClass> m_compat_info,
QWidget* parent = nullptr);
~SettingsDialog(); ~SettingsDialog();
bool eventFilter(QObject* obj, QEvent* event) override; bool eventFilter(QObject* obj, QEvent* event) override;
@ -28,6 +32,7 @@ public:
signals: signals:
void LanguageChanged(const std::string& locale); void LanguageChanged(const std::string& locale);
void CompatibilityChanged();
private: private:
void LoadValuesFromConfig(); void LoadValuesFromConfig();

View File

@ -11,7 +11,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>854</width> <width>900</width>
<height>834</height> <height>834</height>
</rect> </rect>
</property> </property>
@ -42,18 +42,21 @@
</property> </property>
<layout class="QVBoxLayout" name="settingsDialogLayout"> <layout class="QVBoxLayout" name="settingsDialogLayout">
<item> <item>
<widget class="QScrollArea" name="scrollArea"> <widget class="QTabWidget" name="tabWidgetSettings">
<property name="enabled"> <property name="enabled">
<bool>true</bool> <bool>true</bool>
</property> </property>
<property name="frameShape"> <property name="sizePolicy">
<enum>QFrame::Shape::NoFrame</enum> <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property> </property>
<property name="widgetResizable"> <property name="currentIndex">
<bool>true</bool> <number>0</number>
</property> </property>
<widget class="QTabWidget" name="tabWidgetSettings"> <widget class="QScrollArea" name="generalTab">
<property name="enabled"> <property name="widgetResizable">
<bool>true</bool> <bool>true</bool>
</property> </property>
<property name="geometry"> <property name="geometry">
@ -75,127 +78,25 @@
</property> </property>
<widget class="QWidget" name="generalTab"> <widget class="QWidget" name="generalTab">
<attribute name="title"> <attribute name="title">
<string>General</string> <attribute name="title">
</attribute> <string>General</string>
<layout class="QVBoxLayout" name="generalTabVLayout" stretch="0,0"> </attribute>
<widget class="QWidget" name="generalTabContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>822</width>
<height>487</height>
</rect>
</property>
<layout class="QVBoxLayout" name="generalTabVLayout" stretch="0">
<item> <item>
<layout class="QHBoxLayout" name="generalTabHLayoutTop" stretch="1,1,1"> <layout class="QGridLayout" name="gridLayout">
<item> <property name="bottomMargin">
<layout class="QVBoxLayout" name="systemTabLayoutLeft"> <number>0</number>
<item> </property>
<widget class="QGroupBox" name="SystemSettings"> <item row="0" column="2">
<property name="title">
<string>System</string>
</property>
<layout class="QVBoxLayout" name="emuSettingsLayout">
<item>
<widget class="QGroupBox" name="consoleLanguageGroupBox">
<property name="title">
<string>Console Language</string>
</property>
<layout class="QVBoxLayout" name="settingsLayout">
<item>
<widget class="QComboBox" name="consoleLanguageComboBox"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="emulatorLanguageGroupBox">
<property name="title">
<string>Emulator Language</string>
</property>
<layout class="QVBoxLayout" name="langSettingsLayout">
<item>
<widget class="QComboBox" name="emulatorLanguageComboBox"/>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="emulatorTabLayoutMiddle">
<item>
<widget class="QGroupBox" name="emulatorSettingsGroupBox">
<property name="title">
<string>Emulator</string>
</property>
<layout class="QVBoxLayout" name="additionalSettingsVLayout">
<item>
<layout class="QVBoxLayout" name="emulatorverticalLayout">
<item>
<widget class="QCheckBox" name="fullscreenCheckBox">
<property name="text">
<string>Enable Fullscreen</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="separateUpdatesCheckBox">
<property name="text">
<string>Enable Separate Update Folder</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="showSplashCheckBox">
<property name="text">
<string>Show Splash</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="ps4proCheckBox">
<property name="text">
<string>Is PS4 Pro</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="discordRPCCheckbox">
<property name="text">
<string>Enable Discord Rich Presence</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="vLayoutUserName">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="hLayoutUserName">
<item>
<widget class="QGroupBox" name="userName">
<property name="title">
<string>Username</string>
</property>
<layout class="QVBoxLayout" name="userNameLayout">
<item>
<widget class="QLineEdit" name="userNameLineEdit"/>
</item>
</layout>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="loggerTabLayoutRight"> <layout class="QVBoxLayout" name="loggerTabLayoutRight">
<item> <item>
<widget class="QGroupBox" name="loggerGroupBox"> <widget class="QGroupBox" name="loggerGroupBox">
@ -275,12 +176,129 @@
</item> </item>
</layout> </layout>
</item> </item>
</layout> <item row="0" column="0">
</item> <layout class="QVBoxLayout" name="systemTabLayoutLeft">
<item> <item>
<layout class="QHBoxLayout" name="generalTabHLayout_2"> <widget class="QGroupBox" name="SystemSettings">
<item> <property name="title">
<string>System</string>
</property>
<layout class="QVBoxLayout" name="emuSettingsLayout">
<item>
<widget class="QGroupBox" name="consoleLanguageGroupBox">
<property name="title">
<string>Console Language</string>
</property>
<layout class="QVBoxLayout" name="settingsLayout">
<item>
<widget class="QComboBox" name="consoleLanguageComboBox"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="emulatorLanguageGroupBox">
<property name="title">
<string>Emulator Language</string>
</property>
<layout class="QVBoxLayout" name="langSettingsLayout">
<item>
<widget class="QComboBox" name="emulatorLanguageComboBox"/>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item row="0" column="1">
<layout class="QVBoxLayout" name="emulatorTabLayoutMiddle">
<item>
<widget class="QGroupBox" name="emulatorSettingsGroupBox">
<property name="title">
<string>Emulator</string>
</property>
<layout class="QVBoxLayout" name="additionalSettingsVLayout">
<item>
<layout class="QVBoxLayout" name="emulatorverticalLayout">
<property name="spacing">
<number>10</number>
</property>
<item>
<widget class="QCheckBox" name="fullscreenCheckBox">
<property name="text">
<string>Enable Fullscreen</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="separateUpdatesCheckBox">
<property name="text">
<string>Enable Separate Update Folder</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="showSplashCheckBox">
<property name="text">
<string>Show Splash</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="ps4proCheckBox">
<property name="text">
<string>Is PS4 Pro</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="discordRPCCheckbox">
<property name="text">
<string>Enable Discord Rich Presence</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="vLayoutUserName">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="hLayoutUserName">
<item>
<widget class="QGroupBox" name="userName">
<property name="title">
<string>Username</string>
</property>
<layout class="QVBoxLayout" name="userNameLayout">
<item>
<widget class="QLineEdit" name="userNameLineEdit"/>
</item>
</layout>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<layout class="QVBoxLayout" name="updaterTabLayoutLeft"> <layout class="QVBoxLayout" name="updaterTabLayoutLeft">
<property name="spacing">
<number>-1</number>
</property>
<property name="sizeConstraint"> <property name="sizeConstraint">
<enum>QLayout::SizeConstraint::SetDefaultConstraint</enum> <enum>QLayout::SizeConstraint::SetDefaultConstraint</enum>
</property> </property>
@ -296,7 +314,7 @@
<property name="bottomMargin"> <property name="bottomMargin">
<number>0</number> <number>0</number>
</property> </property>
<item alignment="Qt::AlignmentFlag::AlignTop"> <item>
<widget class="QGroupBox" name="updaterGroupBox"> <widget class="QGroupBox" name="updaterGroupBox">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding"> <sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
@ -306,7 +324,7 @@
</property> </property>
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>275</width> <width>0</width>
<height>0</height> <height>0</height>
</size> </size>
</property> </property>
@ -321,7 +339,7 @@
</property> </property>
<layout class="QVBoxLayout" name="UpdateLayout" stretch="0,0,0"> <layout class="QVBoxLayout" name="UpdateLayout" stretch="0,0,0">
<property name="spacing"> <property name="spacing">
<number>5</number> <number>10</number>
</property> </property>
<property name="topMargin"> <property name="topMargin">
<number>1</number> <number>1</number>
@ -343,7 +361,7 @@
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>0</width> <width>0</width>
<height>75</height> <height>0</height>
</size> </size>
</property> </property>
<property name="maximumSize"> <property name="maximumSize">
@ -404,8 +422,8 @@
</property> </property>
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>197</width> <width>0</width>
<height>28</height> <height>0</height>
</size> </size>
</property> </property>
<property name="maximumSize"> <property name="maximumSize">
@ -443,7 +461,7 @@
</item> </item>
</layout> </layout>
</item> </item>
<item> <item row="1" column="1">
<layout class="QVBoxLayout" name="GUITabLayoutMiddle" stretch="0"> <layout class="QVBoxLayout" name="GUITabLayoutMiddle" stretch="0">
<item alignment="Qt::AlignmentFlag::AlignTop"> <item alignment="Qt::AlignmentFlag::AlignTop">
<widget class="QGroupBox" name="GUIgroupBox"> <widget class="QGroupBox" name="GUIgroupBox">
@ -559,6 +577,19 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QCheckBox" name="playBGMCheckBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Play title music</string>
</property>
</widget>
</item>
<item> <item>
<layout class="QVBoxLayout" name="GUIMusicLayout"> <layout class="QVBoxLayout" name="GUIMusicLayout">
<property name="topMargin"> <property name="topMargin">
@ -568,20 +599,7 @@
<number>0</number> <number>0</number>
</property> </property>
<item> <item>
<widget class="QCheckBox" name="playBGMCheckBox"> <spacer name="GUIverticalSpacer_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Play title music</string>
</property>
</widget>
</item>
<item>
<spacer name="GUIverticalSpacer_2">
<property name="orientation"> <property name="orientation">
<enum>Qt::Orientation::Vertical</enum> <enum>Qt::Orientation::Vertical</enum>
</property> </property>
@ -591,7 +609,7 @@
<property name="sizeHint" stdset="0"> <property name="sizeHint" stdset="0">
<size> <size>
<width>20</width> <width>20</width>
<height>2</height> <height>13</height>
</size> </size>
</property> </property>
</spacer> </spacer>
@ -656,20 +674,76 @@
</item> </item>
</layout> </layout>
</item> </item>
<item> <item row="1" column="2">
<layout class="QVBoxLayout" name="EmptyTabLayoutRight"> <layout class="QVBoxLayout" name="CompatTabLayoutRight" stretch="0">
<item> <item alignment="Qt::AlignmentFlag::AlignTop">
<spacer name="emptyHorizontalSpacer"> <widget class="QGroupBox" name="CompatgroupBox">
<property name="orientation"> <property name="sizePolicy">
<enum>Qt::Orientation::Horizontal</enum> <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property> </property>
<property name="sizeHint" stdset="0"> <property name="minimumSize">
<size> <size>
<width>40</width> <width>0</width>
<height>20</height> <height>0</height>
</size> </size>
</property> </property>
</spacer> <property name="title">
<string>Game Compatibility</string>
</property>
<layout class="QVBoxLayout" name="CompatLayout">
<property name="spacing">
<number>10</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="bottomMargin">
<number>11</number>
</property>
<item>
<widget class="QCheckBox" name="enableCompatibilityCheckBox">
<property name="text">
<string>Display Compatibility Data</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkCompatibilityOnStartupCheckBox">
<property name="text">
<string>Update Compatibility Database On Startup</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="updateCompatibilityButton">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Update Compatibility Database</string>
</property>
</widget>
</item>
</layout>
</widget>
</item> </item>
</layout> </layout>
</item> </item>
@ -677,10 +751,23 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="inputTab"> </widget>
<attribute name="title"> <widget class="QScrollArea" name="inputTab">
<string>Input</string> <property name="widgetResizable">
</attribute> <bool>true</bool>
</property>
<attribute name="title">
<string>Input</string>
</attribute>
<widget class="QWidget" name="inputTabContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>396</width>
<height>222</height>
</rect>
</property>
<layout class="QVBoxLayout" name="inputTabVLayout" stretch="0,0"> <layout class="QVBoxLayout" name="inputTabVLayout" stretch="0,0">
<item> <item>
<layout class="QHBoxLayout" name="inputTabHLayoutTop" stretch="1,1,1"> <layout class="QHBoxLayout" name="inputTabHLayoutTop" stretch="1,1,1">
@ -789,8 +876,8 @@
</property> </property>
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>80</width> <width>0</width>
<height>30</height> <height>0</height>
</size> </size>
</property> </property>
<property name="maximumSize"> <property name="maximumSize">
@ -876,7 +963,7 @@
</property> </property>
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>237</width> <width>0</width>
<height>0</height> <height>0</height>
</size> </size>
</property> </property>
@ -955,10 +1042,23 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="grphicsTab"> </widget>
<attribute name="title"> <widget class="QScrollArea" name="graphicsTab">
<string>Graphics</string> <property name="widgetResizable">
</attribute> <bool>true</bool>
</property>
<attribute name="title">
<string>Graphics</string>
</attribute>
<widget class="QWidget" name="graphicsTabLayout">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>536</width>
<height>192</height>
</rect>
</property>
<layout class="QVBoxLayout" name="graphicsTabVLayout" stretch="0,0"> <layout class="QVBoxLayout" name="graphicsTabVLayout" stretch="0,0">
<item> <item>
<layout class="QHBoxLayout" name="graphicsTabHLayout" stretch="1,1,1"> <layout class="QHBoxLayout" name="graphicsTabHLayout" stretch="1,1,1">
@ -1193,13 +1293,26 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="pathsTab"> </widget>
<attribute name="title"> <widget class="QScrollArea" name="pathsTab">
<string>Paths</string> <property name="widgetResizable">
</attribute> <bool>true</bool>
<layout class="QVBoxLayout" name="inputTabVLayout" stretch="0"> </property>
<attribute name="title">
<string>Paths</string>
</attribute>
<widget class="QWidget" name="pathsTabContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>146</width>
<height>215</height>
</rect>
</property>
<layout class="QVBoxLayout" name="pathsTabLayout" stretch="0">
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_2"> <layout class="QHBoxLayout" name="pathsTabVLayout">
<item> <item>
<widget class="QGroupBox" name="gameFoldersGroupBox"> <widget class="QGroupBox" name="gameFoldersGroupBox">
<property name="title"> <property name="title">
@ -1242,10 +1355,23 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="debugTab"> </widget>
<attribute name="title"> <widget class="QScrollArea" name="debugTab">
<string>Debug</string> <property name="widgetResizable">
</attribute> <bool>true</bool>
</property>
<attribute name="title">
<string>Debug</string>
</attribute>
<widget class="QWidget" name="debugTabContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>288</width>
<height>163</height>
</rect>
</property>
<layout class="QVBoxLayout" name="debugTabVLayout" stretch="0,1"> <layout class="QVBoxLayout" name="debugTabVLayout" stretch="0,1">
<item> <item>
<layout class="QHBoxLayout" name="debugTabHLayout" stretch="1"> <layout class="QHBoxLayout" name="debugTabHLayout" stretch="1">

View File

@ -182,8 +182,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="196"/> <location filename="../gui_context_menus.h" line="196"/>
<source>Shortcut created successfully!\n %1</source> <source>Shortcut created successfully!</source>
<translation>تم إنشاء الاختصار بنجاح!\n %1</translation> <translation>تم إنشاء الاختصار بنجاح!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="199"/> <location filename="../gui_context_menus.h" line="199"/>
@ -192,8 +192,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="200"/> <location filename="../gui_context_menus.h" line="200"/>
<source>Error creating shortcut!\n %1</source> <source>Error creating shortcut!</source>
<translation>!\n %1 خطأ في إنشاء الاختصار</translation> <translation>خطأ في إنشاء الاختصار</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="275"/> <location filename="../gui_context_menus.h" line="275"/>
@ -672,11 +672,36 @@
<source>GUI Settings</source> <source>GUI Settings</source>
<translation>إعدادات الواجهة</translation> <translation>إعدادات الواجهة</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui" line="475"/>
<source>Disable Trophy Pop-ups</source>
<translation>Disable Trophy Pop-ups</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="375"/> <location filename="../settings_dialog.ui" line="375"/>
<source>Play title music</source> <source>Play title music</source>
<translation>تشغيل موسيقى العنوان</translation> <translation>تشغيل موسيقى العنوان</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database On Startup</source>
<translation>Update Compatibility Database On Startup</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Game Compatibility</source>
<translation>Game Compatibility</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Display Compatibility Data</source>
<translation>Display Compatibility Data</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database</source>
<translation>Update Compatibility Database</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="394"/> <location filename="../settings_dialog.ui" line="394"/>
<source>Volume</source> <source>Volume</source>
@ -1201,6 +1226,11 @@
<source>GUIgroupBox</source> <source>GUIgroupBox</source>
<translation>تشغيل موسيقى العنوان:\nإذا كانت اللعبة تدعم ذلك، قم بتمكين تشغيل موسيقى خاصة عند اختيار اللعبة في واجهة المستخدم.</translation> <translation>تشغيل موسيقى العنوان:\nإذا كانت اللعبة تدعم ذلك، قم بتمكين تشغيل موسيقى خاصة عند اختيار اللعبة في واجهة المستخدم.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp" line="267"/>
<source>disableTrophycheckBox</source>
<translation>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).</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="450"/> <location filename="../settings_dialog.cpp" line="450"/>
<source>hideCursorGroupBox</source> <source>hideCursorGroupBox</source>
@ -1216,6 +1246,21 @@
<source>backButtonBehaviorGroupBox</source> <source>backButtonBehaviorGroupBox</source>
<translation>سلوك زر العودة:\nيضبط زر العودة في وحدة التحكم ليحاكي الضغط على الموضع المحدد على لوحة اللمس في PS4.</translation> <translation>سلوك زر العودة:\nيضبط زر العودة في وحدة التحكم ليحاكي الضغط على الموضع المحدد على لوحة اللمس في PS4.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>enableCompatibilityCheckBox</source>
<translation>Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>checkCompatibilityOnStartupCheckBox</source>
<translation>Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>updateCompatibilityButton</source>
<translation>Update Compatibility Database:\nImmediately update the compatibility database.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="70"/> <location filename="../settings_dialog.cpp" line="70"/>
<source>Never</source> <source>Never</source>
@ -1329,6 +1374,11 @@
<source>Serial</source> <source>Serial</source>
<translation>سيريال</translation> <translation>سيريال</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility</source>
<translation>Compatibility</translation>
</message>
<message> <message>
<location filename="../game_list_frame.cpp" line="34"/> <location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source> <source>Region</source>
@ -1364,6 +1414,36 @@
<source>Never Played</source> <source>Never Played</source>
<translation>Never Played</translation> <translation>Never Played</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility is untested</source>
<translation>Compatibility is untested</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game does not initialize properly / crashes the emulator</source>
<translation>Game does not initialize properly / crashes the emulator</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game boots, but only displays a blank screen</source>
<translation>Game boots, but only displays a blank screen</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game displays an image but does not go past the menu</source>
<translation>Game displays an image but does not go past the menu</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game has game-breaking glitches or unplayable performance</source>
<translation>Game has game-breaking glitches or unplayable performance</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game can be completed with playable performance and no major glitches</source>
<translation>Game can be completed with playable performance and no major glitches</translation>
</message>
</context> </context>
<context> <context>
<name>CheckUpdate</name> <name>CheckUpdate</name>

View File

@ -182,8 +182,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="196"/> <location filename="../gui_context_menus.h" line="196"/>
<source>Shortcut created successfully!\n %1</source> <source>Shortcut created successfully!</source>
<translation>Shortcut created successfully!\n %1</translation> <translation>Shortcut created successfully!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="199"/> <location filename="../gui_context_menus.h" line="199"/>
@ -192,8 +192,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="200"/> <location filename="../gui_context_menus.h" line="200"/>
<source>Error creating shortcut!\n %1</source> <source>Error creating shortcut!</source>
<translation>Error creating shortcut!\n %1</translation> <translation>Error creating shortcut!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="275"/> <location filename="../gui_context_menus.h" line="275"/>
@ -672,11 +672,36 @@
<source>GUI Settings</source> <source>GUI Settings</source>
<translation>GUI-Indstillinger</translation> <translation>GUI-Indstillinger</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui" line="475"/>
<source>Disable Trophy Pop-ups</source>
<translation>Disable Trophy Pop-ups</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="375"/> <location filename="../settings_dialog.ui" line="375"/>
<source>Play title music</source> <source>Play title music</source>
<translation>Afspil titelsang</translation> <translation>Afspil titelsang</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database On Startup</source>
<translation>Update Compatibility Database On Startup</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Game Compatibility</source>
<translation>Game Compatibility</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Display Compatibility Data</source>
<translation>Display Compatibility Data</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database</source>
<translation>Update Compatibility Database</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="394"/> <location filename="../settings_dialog.ui" line="394"/>
<source>Volume</source> <source>Volume</source>
@ -1201,6 +1226,11 @@
<source>GUIgroupBox</source> <source>GUIgroupBox</source>
<translation>Titelsmusikafspilning:\nHvis spillet understøtter det, aktiver speciel musik, når spillet vælges i brugergrænsefladen.</translation> <translation>Titelsmusikafspilning:\nHvis spillet understøtter det, aktiver speciel musik, når spillet vælges i brugergrænsefladen.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp" line="267"/>
<source>disableTrophycheckBox</source>
<translation>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).</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="450"/> <location filename="../settings_dialog.cpp" line="450"/>
<source>hideCursorGroupBox</source> <source>hideCursorGroupBox</source>
@ -1216,6 +1246,21 @@
<source>backButtonBehaviorGroupBox</source> <source>backButtonBehaviorGroupBox</source>
<translation>Tilbageknap Adfærd:\nIndstiller controllerens tilbageknap til at efterligne tryk den angivne position PS4 berøringsflade.</translation> <translation>Tilbageknap Adfærd:\nIndstiller controllerens tilbageknap til at efterligne tryk den angivne position PS4 berøringsflade.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>enableCompatibilityCheckBox</source>
<translation>Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>checkCompatibilityOnStartupCheckBox</source>
<translation>Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>updateCompatibilityButton</source>
<translation>Update Compatibility Database:\nImmediately update the compatibility database.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="70"/> <location filename="../settings_dialog.cpp" line="70"/>
<source>Never</source> <source>Never</source>
@ -1329,6 +1374,11 @@
<source>Serial</source> <source>Serial</source>
<translation>Seriel</translation> <translation>Seriel</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility</source>
<translation>Compatibility</translation>
</message>
<message> <message>
<location filename="../game_list_frame.cpp" line="34"/> <location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source> <source>Region</source>
@ -1364,6 +1414,36 @@
<source>Never Played</source> <source>Never Played</source>
<translation>Never Played</translation> <translation>Never Played</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility is untested</source>
<translation>Compatibility is untested</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game does not initialize properly / crashes the emulator</source>
<translation>Game does not initialize properly / crashes the emulator</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game boots, but only displays a blank screen</source>
<translation>Game boots, but only displays a blank screen</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game displays an image but does not go past the menu</source>
<translation>Game displays an image but does not go past the menu</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game has game-breaking glitches or unplayable performance</source>
<translation>Game has game-breaking glitches or unplayable performance</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game can be completed with playable performance and no major glitches</source>
<translation>Game can be completed with playable performance and no major glitches</translation>
</message>
</context> </context>
<context> <context>
<name>CheckUpdate</name> <name>CheckUpdate</name>

View File

@ -182,8 +182,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="196"/> <location filename="../gui_context_menus.h" line="196"/>
<source>Shortcut created successfully!\n %1</source> <source>Shortcut created successfully!</source>
<translation>Verknüpfung erfolgreich erstellt!\n %1</translation> <translation>Verknüpfung erfolgreich erstellt!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="199"/> <location filename="../gui_context_menus.h" line="199"/>
@ -192,8 +192,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="200"/> <location filename="../gui_context_menus.h" line="200"/>
<source>Error creating shortcut!\n %1</source> <source>Error creating shortcut!</source>
<translation>Fehler beim Erstellen der Verknüpfung!\n %1</translation> <translation>Fehler beim Erstellen der Verknüpfung!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="275"/> <location filename="../gui_context_menus.h" line="275"/>
@ -672,11 +672,36 @@
<source>GUI Settings</source> <source>GUI Settings</source>
<translation>GUI-Einstellungen</translation> <translation>GUI-Einstellungen</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui" line="475"/>
<source>Disable Trophy Pop-ups</source>
<translation>Disable Trophy Pop-ups</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="375"/> <location filename="../settings_dialog.ui" line="375"/>
<source>Play title music</source> <source>Play title music</source>
<translation>Titelmusik abspielen</translation> <translation>Titelmusik abspielen</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database On Startup</source>
<translation>Update Compatibility Database On Startup</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Game Compatibility</source>
<translation>Game Compatibility</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Display Compatibility Data</source>
<translation>Display Compatibility Data</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database</source>
<translation>Update Compatibility Database</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="394"/> <location filename="../settings_dialog.ui" line="394"/>
<source>Volume</source> <source>Volume</source>
@ -1201,6 +1226,11 @@
<source>GUIgroupBox</source> <source>GUIgroupBox</source>
<translation>Wiedergabe der Titelmusik:\nWenn das Spiel dies unterstützt, wird beim Auswählen des Spiels in der Benutzeroberfläche spezielle Musik abgespielt.</translation> <translation>Wiedergabe der Titelmusik:\nWenn das Spiel dies unterstützt, wird beim Auswählen des Spiels in der Benutzeroberfläche spezielle Musik abgespielt.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp" line="267"/>
<source>disableTrophycheckBox</source>
<translation>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).</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="450"/> <location filename="../settings_dialog.cpp" line="450"/>
<source>hideCursorGroupBox</source> <source>hideCursorGroupBox</source>
@ -1216,6 +1246,21 @@
<source>backButtonBehaviorGroupBox</source> <source>backButtonBehaviorGroupBox</source>
<translation>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.</translation> <translation>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.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>enableCompatibilityCheckBox</source>
<translation>Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>checkCompatibilityOnStartupCheckBox</source>
<translation>Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>updateCompatibilityButton</source>
<translation>Update Compatibility Database:\nImmediately update the compatibility database.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="70"/> <location filename="../settings_dialog.cpp" line="70"/>
<source>Never</source> <source>Never</source>
@ -1329,6 +1374,11 @@
<source>Serial</source> <source>Serial</source>
<translation>Seriennummer</translation> <translation>Seriennummer</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility</source>
<translation>Compatibility</translation>
</message>
<message> <message>
<location filename="../game_list_frame.cpp" line="34"/> <location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source> <source>Region</source>
@ -1364,6 +1414,36 @@
<source>Never Played</source> <source>Never Played</source>
<translation>Never Played</translation> <translation>Never Played</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility is untested</source>
<translation>Compatibility is untested</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game does not initialize properly / crashes the emulator</source>
<translation>Game does not initialize properly / crashes the emulator</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game boots, but only displays a blank screen</source>
<translation>Game boots, but only displays a blank screen</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game displays an image but does not go past the menu</source>
<translation>Game displays an image but does not go past the menu</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game has game-breaking glitches or unplayable performance</source>
<translation>Game has game-breaking glitches or unplayable performance</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game can be completed with playable performance and no major glitches</source>
<translation>Game can be completed with playable performance and no major glitches</translation>
</message>
</context> </context>
<context> <context>
<name>CheckUpdate</name> <name>CheckUpdate</name>

View File

@ -182,8 +182,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="196"/> <location filename="../gui_context_menus.h" line="196"/>
<source>Shortcut created successfully!\n %1</source> <source>Shortcut created successfully!</source>
<translation>Shortcut created successfully!\n %1</translation> <translation>Shortcut created successfully!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="199"/> <location filename="../gui_context_menus.h" line="199"/>
@ -192,8 +192,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="200"/> <location filename="../gui_context_menus.h" line="200"/>
<source>Error creating shortcut!\n %1</source> <source>Error creating shortcut!</source>
<translation>Error creating shortcut!\n %1</translation> <translation>Error creating shortcut!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="275"/> <location filename="../gui_context_menus.h" line="275"/>
@ -672,11 +672,36 @@
<source>GUI Settings</source> <source>GUI Settings</source>
<translation>Ρυθμίσεις GUI</translation> <translation>Ρυθμίσεις GUI</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui" line="475"/>
<source>Disable Trophy Pop-ups</source>
<translation>Disable Trophy Pop-ups</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="375"/> <location filename="../settings_dialog.ui" line="375"/>
<source>Play title music</source> <source>Play title music</source>
<translation>Αναπαραγωγή μουσικής τίτλου</translation> <translation>Αναπαραγωγή μουσικής τίτλου</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database On Startup</source>
<translation>Update Compatibility Database On Startup</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Game Compatibility</source>
<translation>Game Compatibility</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Display Compatibility Data</source>
<translation>Display Compatibility Data</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database</source>
<translation>Update Compatibility Database</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="394"/> <location filename="../settings_dialog.ui" line="394"/>
<source>Volume</source> <source>Volume</source>
@ -1201,6 +1226,11 @@
<source>GUIgroupBox</source> <source>GUIgroupBox</source>
<translation>Αναπαραγωγή Μουσικής Τίτλων:\nΕάν το παιχνίδι το υποστηρίζει, ενεργοποιεί ειδική μουσική κατά την επιλογή του παιχνιδιού από τη διεπαφή χρήστη.</translation> <translation>Αναπαραγωγή Μουσικής Τίτλων:\nΕάν το παιχνίδι το υποστηρίζει, ενεργοποιεί ειδική μουσική κατά την επιλογή του παιχνιδιού από τη διεπαφή χρήστη.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp" line="267"/>
<source>disableTrophycheckBox</source>
<translation>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).</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="450"/> <location filename="../settings_dialog.cpp" line="450"/>
<source>hideCursorGroupBox</source> <source>hideCursorGroupBox</source>
@ -1216,6 +1246,21 @@
<source>backButtonBehaviorGroupBox</source> <source>backButtonBehaviorGroupBox</source>
<translation>Συμπεριφορά Κουμπιού Επιστροφής:\nΟρίζει το κουμπί επιστροφής του ελεγκτή να προσομοιώνει το πάτημα της καθορισμένης θέσης στην οθόνη αφής PS4.</translation> <translation>Συμπεριφορά Κουμπιού Επιστροφής:\nΟρίζει το κουμπί επιστροφής του ελεγκτή να προσομοιώνει το πάτημα της καθορισμένης θέσης στην οθόνη αφής PS4.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>enableCompatibilityCheckBox</source>
<translation>Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>checkCompatibilityOnStartupCheckBox</source>
<translation>Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>updateCompatibilityButton</source>
<translation>Update Compatibility Database:\nImmediately update the compatibility database.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="70"/> <location filename="../settings_dialog.cpp" line="70"/>
<source>Never</source> <source>Never</source>
@ -1329,6 +1374,11 @@
<source>Serial</source> <source>Serial</source>
<translation>Σειριακός αριθμός</translation> <translation>Σειριακός αριθμός</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility</source>
<translation>Compatibility</translation>
</message>
<message> <message>
<location filename="../game_list_frame.cpp" line="34"/> <location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source> <source>Region</source>
@ -1364,6 +1414,36 @@
<source>Never Played</source> <source>Never Played</source>
<translation>Never Played</translation> <translation>Never Played</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility is untested</source>
<translation>Compatibility is untested</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game does not initialize properly / crashes the emulator</source>
<translation>Game does not initialize properly / crashes the emulator</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game boots, but only displays a blank screen</source>
<translation>Game boots, but only displays a blank screen</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game displays an image but does not go past the menu</source>
<translation>Game displays an image but does not go past the menu</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game has game-breaking glitches or unplayable performance</source>
<translation>Game has game-breaking glitches or unplayable performance</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game can be completed with playable performance and no major glitches</source>
<translation>Game can be completed with playable performance and no major glitches</translation>
</message>
</context> </context>
<context> <context>
<name>CheckUpdate</name> <name>CheckUpdate</name>

View File

@ -182,8 +182,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="196"/> <location filename="../gui_context_menus.h" line="196"/>
<source>Shortcut created successfully!\n %1</source> <source>Shortcut created successfully!</source>
<translation>Shortcut created successfully!\n %1</translation> <translation>Shortcut created successfully!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="199"/> <location filename="../gui_context_menus.h" line="199"/>
@ -192,8 +192,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="200"/> <location filename="../gui_context_menus.h" line="200"/>
<source>Error creating shortcut!\n %1</source> <source>Error creating shortcut!</source>
<translation>Error creating shortcut!\n %1</translation> <translation>Error creating shortcut!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="275"/> <location filename="../gui_context_menus.h" line="275"/>
@ -672,11 +672,36 @@
<source>GUI Settings</source> <source>GUI Settings</source>
<translation>GUI Settings</translation> <translation>GUI Settings</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui" line="475"/>
<source>Disable Trophy Pop-ups</source>
<translation>Disable Trophy Pop-ups</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="375"/> <location filename="../settings_dialog.ui" line="375"/>
<source>Play title music</source> <source>Play title music</source>
<translation>Play title music</translation> <translation>Play title music</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database On Startup</source>
<translation>Update Compatibility Database On Startup</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Game Compatibility</source>
<translation>Game Compatibility</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Display Compatibility Data</source>
<translation>Display Compatibility Data</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database</source>
<translation>Update Compatibility Database</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="394"/> <location filename="../settings_dialog.ui" line="394"/>
<source>Volume</source> <source>Volume</source>
@ -1226,6 +1251,21 @@
<source>backButtonBehaviorGroupBox</source> <source>backButtonBehaviorGroupBox</source>
<translation>Back Button Behavior:\nSets the controller's back button to emulate tapping the specified position on the PS4 touchpad.</translation> <translation>Back Button Behavior:\nSets the controller's back button to emulate tapping the specified position on the PS4 touchpad.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>enableCompatibilityCheckBox</source>
<translation>Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>checkCompatibilityOnStartupCheckBox</source>
<translation>Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>updateCompatibilityButton</source>
<translation>Update Compatibility Database:\nImmediately update the compatibility database.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="70"/> <location filename="../settings_dialog.cpp" line="70"/>
<source>Never</source> <source>Never</source>
@ -1339,6 +1379,11 @@
<source>Serial</source> <source>Serial</source>
<translation>Serial</translation> <translation>Serial</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility</source>
<translation>Compatibility</translation>
</message>
<message> <message>
<location filename="../game_list_frame.cpp" line="34"/> <location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source> <source>Region</source>
@ -1374,6 +1419,36 @@
<source>Never Played</source> <source>Never Played</source>
<translation>Never Played</translation> <translation>Never Played</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility is untested</source>
<translation>Compatibility is untested</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game does not initialize properly / crashes the emulator</source>
<translation>Game does not initialize properly / crashes the emulator</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game boots, but only displays a blank screen</source>
<translation>Game boots, but only displays a blank screen</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game displays an image but does not go past the menu</source>
<translation>Game displays an image but does not go past the menu</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game has game-breaking glitches or unplayable performance</source>
<translation>Game has game-breaking glitches or unplayable performance</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game can be completed with playable performance and no major glitches</source>
<translation>Game can be completed with playable performance and no major glitches</translation>
</message>
</context> </context>
<context> <context>
<name>CheckUpdate</name> <name>CheckUpdate</name>

View File

@ -182,8 +182,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="196"/> <location filename="../gui_context_menus.h" line="196"/>
<source>Shortcut created successfully!\n %1</source> <source>Shortcut created successfully!</source>
<translation>¡Acceso directo creado con éxito!\n %1</translation> <translation>¡Acceso directo creado con éxito!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="199"/> <location filename="../gui_context_menus.h" line="199"/>
@ -192,8 +192,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="200"/> <location filename="../gui_context_menus.h" line="200"/>
<source>Error creating shortcut!\n %1</source> <source>Error creating shortcut!</source>
<translation>¡Error al crear el acceso directo!\n %1</translation> <translation>¡Error al crear el acceso directo!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="275"/> <location filename="../gui_context_menus.h" line="275"/>
@ -672,11 +672,36 @@
<source>GUI Settings</source> <source>GUI Settings</source>
<translation>Configuraciones de la Interfaz</translation> <translation>Configuraciones de la Interfaz</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui" line="475"/>
<source>Disable Trophy Pop-ups</source>
<translation>Disable Trophy Pop-ups</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="375"/> <location filename="../settings_dialog.ui" line="375"/>
<source>Play title music</source> <source>Play title music</source>
<translation>Reproducir la música de apertura</translation> <translation>Reproducir la música de apertura</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database On Startup</source>
<translation>Update Compatibility Database On Startup</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Game Compatibility</source>
<translation>Game Compatibility</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Display Compatibility Data</source>
<translation>Display Compatibility Data</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database</source>
<translation>Update Compatibility Database</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="394"/> <location filename="../settings_dialog.ui" line="394"/>
<source>Volume</source> <source>Volume</source>
@ -1201,6 +1226,11 @@
<source>GUIgroupBox</source> <source>GUIgroupBox</source>
<translation>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.</translation> <translation>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.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp" line="267"/>
<source>disableTrophycheckBox</source>
<translation>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).</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="450"/> <location filename="../settings_dialog.cpp" line="450"/>
<source>hideCursorGroupBox</source> <source>hideCursorGroupBox</source>
@ -1216,6 +1246,21 @@
<source>backButtonBehaviorGroupBox</source> <source>backButtonBehaviorGroupBox</source>
<translation>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.</translation> <translation>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.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>enableCompatibilityCheckBox</source>
<translation>Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>checkCompatibilityOnStartupCheckBox</source>
<translation>Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>updateCompatibilityButton</source>
<translation>Update Compatibility Database:\nImmediately update the compatibility database.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="70"/> <location filename="../settings_dialog.cpp" line="70"/>
<source>Never</source> <source>Never</source>
@ -1329,6 +1374,11 @@
<source>Serial</source> <source>Serial</source>
<translation>Numero de serie</translation> <translation>Numero de serie</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility</source>
<translation>Compatibility</translation>
</message>
<message> <message>
<location filename="../game_list_frame.cpp" line="34"/> <location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source> <source>Region</source>
@ -1364,6 +1414,36 @@
<source>Never Played</source> <source>Never Played</source>
<translation>Never Played</translation> <translation>Never Played</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility is untested</source>
<translation>Compatibility is untested</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game does not initialize properly / crashes the emulator</source>
<translation>Game does not initialize properly / crashes the emulator</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game boots, but only displays a blank screen</source>
<translation>Game boots, but only displays a blank screen</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game displays an image but does not go past the menu</source>
<translation>Game displays an image but does not go past the menu</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game has game-breaking glitches or unplayable performance</source>
<translation>Game has game-breaking glitches or unplayable performance</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game can be completed with playable performance and no major glitches</source>
<translation>Game can be completed with playable performance and no major glitches</translation>
</message>
</context> </context>
<context> <context>
<name>CheckUpdate</name> <name>CheckUpdate</name>

View File

@ -62,7 +62,7 @@
<message> <message>
<location filename="../install_dir_select.cpp" line="37"/> <location filename="../install_dir_select.cpp" line="37"/>
<source>Select which directory you want to install to.</source> <source>Select which directory you want to install to.</source>
<translation>Select which directory you want to install to.</translation> <translation>محلی را که میخواهید در آن نصب شود، انتخاب کنید.</translation>
</message> </message>
</context> </context>
<context> <context>
@ -98,7 +98,7 @@
<message> <message>
<location filename="../gui_context_menus.h" line="39"/> <location filename="../gui_context_menus.h" line="39"/>
<source>Create Shortcut</source> <source>Create Shortcut</source>
<translation>ساخت شورتکات</translation> <translation>ایجاد میانبر</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="48"/> <location filename="../gui_context_menus.h" line="48"/>
@ -113,7 +113,7 @@
<message> <message>
<location filename="../gui_context_menus.h" line="42"/> <location filename="../gui_context_menus.h" line="42"/>
<source>Trophy Viewer</source> <source>Trophy Viewer</source>
<translation>مشاهده تروفی ها</translation> <translation>مشاهده جوایز</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="49"/> <location filename="../gui_context_menus.h" line="49"/>
@ -158,32 +158,32 @@
<message> <message>
<location filename="../gui_context_menus.h" line="72"/> <location filename="../gui_context_menus.h" line="72"/>
<source>Delete...</source> <source>Delete...</source>
<translation>Delete...</translation> <translation>حذف...</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="73"/> <location filename="../gui_context_menus.h" line="73"/>
<source>Delete Game</source> <source>Delete Game</source>
<translation>Delete Game</translation> <translation>حذف بازی</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="74"/> <location filename="../gui_context_menus.h" line="74"/>
<source>Delete Update</source> <source>Delete Update</source>
<translation>Delete Update</translation> <translation>حذف بهروزرسانی</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="75"/> <location filename="../gui_context_menus.h" line="75"/>
<source>Delete DLC</source> <source>Delete DLC</source>
<translation>Delete DLC</translation> <translation>حذف محتوای اضافی (DLC)</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="173"/> <location filename="../gui_context_menus.h" line="173"/>
<source>Shortcut creation</source> <source>Shortcut creation</source>
<translation>سازنده شورتکات</translation> <translation>ایجاد میانبر</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="174"/> <location filename="../gui_context_menus.h" line="174"/>
<source>Shortcut created successfully!\n %1</source> <source>Shortcut created successfully!</source>
<translation>شورتکات با موفقیت ساخته شد! \n %1</translation> <translation>میانبر با موفقیت ساخته شد!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="177"/> <location filename="../gui_context_menus.h" line="177"/>
@ -192,8 +192,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="178"/> <location filename="../gui_context_menus.h" line="178"/>
<source>Error creating shortcut!\n %1</source> <source>Error creating shortcut!</source>
<translation>مشکلی در هنگام ساخت شورتکات بوجود آمد!\n %1</translation> <translation>مشکلی در هنگام ساخت میانبر بوجود آمد!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="253"/> <location filename="../gui_context_menus.h" line="253"/>
@ -203,27 +203,27 @@
<message> <message>
<location filename="../gui_context_menus.h" line="299"/> <location filename="../gui_context_menus.h" line="299"/>
<source>Game</source> <source>Game</source>
<translation>Game</translation> <translation>بازی</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="305"/> <location filename="../gui_context_menus.h" line="305"/>
<source>requiresEnableSeparateUpdateFolder_MSG</source> <source>requiresEnableSeparateUpdateFolder_MSG</source>
<translation>This feature requires the 'Enable Separate Update Folder' config option to work. If you want to use this feature, please enable it.</translation> <translation>این قابلیت نیازمند فعالسازی گزینه تنظیمات «ایجاد پوشه جداگانه برای بهروزرسانی» است. در صورت تمایل به استفاده از این قابلیت، لطفاً آن را فعال کنید.</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="312"/> <location filename="../gui_context_menus.h" line="312"/>
<source>This game has no update to delete!</source> <source>This game has no update to delete!</source>
<translation>This game has no update to delete!</translation> <translation>این بازی بهروزرسانیای برای حذف ندارد!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="316"/> <location filename="../gui_context_menus.h" line="316"/>
<source>Update</source> <source>Update</source>
<translation>Update</translation> <translation>بهروزرسانی</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="321"/> <location filename="../gui_context_menus.h" line="321"/>
<source>This game has no DLC to delete!</source> <source>This game has no DLC to delete!</source>
<translation>This game has no DLC to delete!</translation> <translation>این بازی محتوای اضافی (DLC) برای حذف ندارد!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="325"/> <location filename="../gui_context_menus.h" line="325"/>
@ -233,7 +233,7 @@
<message> <message>
<location filename="../gui_context_menus.h" line="332"/> <location filename="../gui_context_menus.h" line="332"/>
<source>Delete %1</source> <source>Delete %1</source>
<translation>Delete %1</translation> <translation>حذف %1</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="333"/> <location filename="../gui_context_menus.h" line="333"/>
@ -331,7 +331,7 @@
<message> <message>
<location filename="../main_window_ui.h" line="338"/> <location filename="../main_window_ui.h" line="338"/>
<source>List View</source> <source>List View</source>
<translation>لیستی</translation> <translation>نمایش لیست</translation>
</message> </message>
<message> <message>
<location filename="../main_window_ui.h" line="340"/> <location filename="../main_window_ui.h" line="340"/>
@ -341,7 +341,7 @@
<message> <message>
<location filename="../main_window_ui.h" line="341"/> <location filename="../main_window_ui.h" line="341"/>
<source>Elf Viewer</source> <source>Elf Viewer</source>
<translation>Elf Viewer</translation> <translation>مشاهده گر Elf</translation>
</message> </message>
<message> <message>
<location filename="../main_window_ui.h" line="343"/> <location filename="../main_window_ui.h" line="343"/>
@ -452,7 +452,7 @@
<message> <message>
<location filename="../trophy_viewer.cpp" line="8"/> <location filename="../trophy_viewer.cpp" line="8"/>
<source>Trophy Viewer</source> <source>Trophy Viewer</source>
<translation>تروفی ها</translation> <translation>مشاهده جوایز</translation>
</message> </message>
</context> </context>
<context> <context>
@ -495,7 +495,7 @@
<message> <message>
<location filename="../settings_dialog.ui" line="140"/> <location filename="../settings_dialog.ui" line="140"/>
<source>Enable Separate Update Folder</source> <source>Enable Separate Update Folder</source>
<translation>Enable Separate Update Folder</translation> <translation>فعالسازی پوشه جداگانه برای بهروزرسانی</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.ui" line="129"/> <location filename="../settings_dialog.ui" line="129"/>
@ -555,7 +555,7 @@
<message> <message>
<location filename="../settings_dialog.ui" line="767"/> <location filename="../settings_dialog.ui" line="767"/>
<source>Controller</source> <source>Controller</source>
<translation>کنترل کننده</translation> <translation>دسته بازی</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.ui" line="797"/> <location filename="../settings_dialog.ui" line="797"/>
@ -585,7 +585,7 @@
<message> <message>
<location filename="../settings_dialog.ui" line="405"/> <location filename="../settings_dialog.ui" line="405"/>
<source>Vblank Divider</source> <source>Vblank Divider</source>
<translation>Vblank Divider</translation> <translation>تقسیمکننده Vblank</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.ui" line="453"/> <location filename="../settings_dialog.ui" line="453"/>
@ -595,7 +595,7 @@
<message> <message>
<location filename="../settings_dialog.ui" line="462"/> <location filename="../settings_dialog.ui" line="462"/>
<source>Enable Shaders Dumping</source> <source>Enable Shaders Dumping</source>
<translation>Shaders Dumping فعال کردن</translation> <translation>فعالسازی ذخیرهسازی شیدرها</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.ui" line="469"/> <location filename="../settings_dialog.ui" line="469"/>
@ -625,7 +625,7 @@
<message> <message>
<location filename="../settings_dialog.ui" line="517"/> <location filename="../settings_dialog.ui" line="517"/>
<source>Debug</source> <source>Debug</source>
<translation>Debug</translation> <translation>دیباگ</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.ui" line="537"/> <location filename="../settings_dialog.ui" line="537"/>
@ -650,37 +650,62 @@
<message> <message>
<location filename="../settings_dialog.ui" line="274"/> <location filename="../settings_dialog.ui" line="274"/>
<source>Update</source> <source>Update</source>
<translation>بروزرسانی</translation> <translation>بهروزرسانی</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.ui" line="286"/> <location filename="../settings_dialog.ui" line="286"/>
<source>Check for Updates at Startup</source> <source>Check for Updates at Startup</source>
<translation>بررسی بروزرسانی هنگام شروع</translation> <translation>بررسی بهروزرسانیها در زمان راهاندازی</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.ui" line="313"/> <location filename="../settings_dialog.ui" line="313"/>
<source>Update Channel</source> <source>Update Channel</source>
<translation>کانال بروزرسانی</translation> <translation>کانال بهروزرسانی</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.ui" line="322"/> <location filename="../settings_dialog.ui" line="322"/>
<source>Check for Updates</source> <source>Check for Updates</source>
<translation>به روز رسانی را بررسی کنید</translation> <translation>بررسی بهروزرسانیها</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.ui" line="354"/> <location filename="../settings_dialog.ui" line="354"/>
<source>GUI Settings</source> <source>GUI Settings</source>
<translation>تنظیمات رابط کاربری</translation> <translation>تنظیمات رابط کاربری</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui" line="475"/>
<source>Disable Trophy Pop-ups</source>
<translation>غیرفعال کردن نمایش جوایز</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="375"/> <location filename="../settings_dialog.ui" line="375"/>
<source>Play title music</source> <source>Play title music</source>
<translation>پخش موسیقی عنوان</translation> <translation>پخش موسیقی عنوان</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database On Startup</source>
<translation>بهروزرسانی پایگاه داده سازگاری هنگام راهاندازی</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Game Compatibility</source>
<translation>سازگاری بازی با سیستم</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Display Compatibility Data</source>
<translation>نمایش دادههای سازگاری</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database</source>
<translation>بهروزرسانی پایگاه داده سازگاری</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="394"/> <location filename="../settings_dialog.ui" line="394"/>
<source>Volume</source> <source>Volume</source>
<translation>صدا </translation> <translation>صدا</translation>
</message> </message>
</context> </context>
<context> <context>
@ -693,7 +718,7 @@
<message> <message>
<location filename="../main_window.cpp" line="168"/> <location filename="../main_window.cpp" line="168"/>
<source> * Unsupported Vulkan Version</source> <source> * Unsupported Vulkan Version</source>
<translation>شما پشتیبانی نمیشود Vulkan ورژن*</translation> <translation>شما پشتیبانی نمیشود Vulkan ورژن *</translation>
</message> </message>
<message> <message>
<location filename="../main_window.cpp" line="326"/> <location filename="../main_window.cpp" line="326"/>
@ -841,7 +866,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="44"/> <location filename="../cheats_patches.cpp" line="44"/>
<source>Cheats / Patches for </source> <source>Cheats / Patches for </source>
<translation>Cheats / Patches for ا</translation> <translation> چیت / پچ برای </translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="50"/> <location filename="../cheats_patches.cpp" line="50"/>
@ -861,7 +886,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="83"/> <location filename="../cheats_patches.cpp" line="83"/>
<source>Version: </source> <source>Version: </source>
<translation>ورژن: </translation> <translation>نسخه: </translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="87"/> <location filename="../cheats_patches.cpp" line="87"/>
@ -886,7 +911,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="155"/> <location filename="../cheats_patches.cpp" line="155"/>
<source>Delete File</source> <source>Delete File</source>
<translation>پاک کردن فایل</translation> <translation>حذف فایل</translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="169"/> <location filename="../cheats_patches.cpp" line="169"/>
@ -1149,27 +1174,27 @@
<message> <message>
<location filename="../settings_dialog.cpp" line="291"/> <location filename="../settings_dialog.cpp" line="291"/>
<source>emulatorLanguageGroupBox</source> <source>emulatorLanguageGroupBox</source>
<translation>Emulator Language:\nSets the language of the emulator's user interface.</translation> <translation>زبان شبیهساز:\nزبان رابط کاربری شبیهساز را انتخاب میکند.</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="293"/> <location filename="../settings_dialog.cpp" line="293"/>
<source>fullscreenCheckBox</source> <source>fullscreenCheckBox</source>
<translation>Enable Full Screen:\nAutomatically puts the game window into full-screen mode.\nThis can be toggled by pressing the F11 key.</translation> <translation>فعالسازی تمام صفحه:\nپنجره بازی را بهطور خودکار به حالت تمام صفحه در میآورد.\nبرای تغییر این حالت میتوانید کلید F11 را فشار دهید.</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="293"/> <location filename="../settings_dialog.cpp" line="293"/>
<source>separateUpdatesCheckBox</source> <source>separateUpdatesCheckBox</source>
<translation>Enable Separate Update Folder:\nEnables installing game updates into a separate folder for easy management.</translation> <translation>فعالسازی پوشه جداگانه برای بهروزرسانی:\nامکان نصب بهروزرسانیهای بازی در یک پوشه جداگانه برای مدیریت راحتتر را فراهم میکند.</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="295"/> <location filename="../settings_dialog.cpp" line="295"/>
<source>showSplashCheckBox</source> <source>showSplashCheckBox</source>
<translation>Show Splash Screen:\nShows the game's splash screen (a special image) while the game is starting.</translation> <translation>نمایش صفحه شروع:\nصفحه شروع بازی (تصویری ویژه) را هنگام بارگذاری بازی نمایش میدهد.</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="297"/> <location filename="../settings_dialog.cpp" line="297"/>
<source>ps4proCheckBox</source> <source>ps4proCheckBox</source>
<translation>Is PS4 Pro:\nMakes the emulator act as a PS4 PRO, which may enable special features in games that support it.</translation> <translation>حالت PS4 Pro:\nشبیهساز را بهعنوان PS4 Pro شبیهسازی میکند که ممکن است ویژگیهای ویژهای را در بازیهای پشتیبانیشده فعال کند.</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="438"/> <location filename="../settings_dialog.cpp" line="438"/>
@ -1179,12 +1204,12 @@
<message> <message>
<location filename="../settings_dialog.cpp" line="299"/> <location filename="../settings_dialog.cpp" line="299"/>
<source>userName</source> <source>userName</source>
<translation>Username:\nSets the PS4's account username, which may be displayed by some games.</translation> <translation>نام کاربری:\ام کاربری حساب PS4 را تنظیم میکند که ممکن است توسط برخی بازیها نمایش داده شود.</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="301"/> <location filename="../settings_dialog.cpp" line="301"/>
<source>logTypeGroupBox</source> <source>logTypeGroupBox</source>
<translation>Log Type:\nSets whether to synchronize the output of the log window for performance. May have adverse effects on emulation.</translation> <translation>نوع لاگ:\nتنظیم میکند که آیا خروجی پنجره لاگ برای بهبود عملکرد همگامسازی شود یا خیر. این ممکن است تأثیر منفی بر شبیهسازی داشته باشد.</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="303"/> <location filename="../settings_dialog.cpp" line="303"/>
@ -1194,12 +1219,17 @@
<message> <message>
<location filename="../settings_dialog.cpp" line="305"/> <location filename="../settings_dialog.cpp" line="305"/>
<source>updaterGroupBox</source> <source>updaterGroupBox</source>
<translation>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.</translation> <translation>بهروزرسانی:\nانتشار: نسخه‌های رسمی که هر ماه منتشر میشوند و ممکن است بسیار قدیمی باشند، اما پایدارتر و تست شدهتر هستند.\nشبانه: نسخه‌های توسعهای که شامل جدیدترین ویژگیها و اصلاحات هستند، اما ممکن است دارای اشکال باشند و کمتر پایدار باشند.</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="306"/> <location filename="../settings_dialog.cpp" line="306"/>
<source>GUIgroupBox</source> <source>GUIgroupBox</source>
<translation>Play Title Music:\nIf a game supports it, enable playing special music when selecting the game in the GUI.</translation> <translation>پخش موسیقی عنوان:\nIدر صورتی که بازی از آن پشتیبانی کند، پخش موسیقی ویژه هنگام انتخاب بازی در رابط کاربری را فعال میکند.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="267"/>
<source>disableTrophycheckBox</source>
<translation>غیرفعال کردن نمایش جوایز:\nنمایش اعلانهای جوایز درون بازی را غیرفعال میکند. پیشرفت جوایز همچنان از طریق نمایشگر جوایز (کلیک راست روی بازی در پنجره اصلی) قابل پیگیری است..</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="450"/> <location filename="../settings_dialog.cpp" line="450"/>
@ -1216,6 +1246,21 @@
<source>backButtonBehaviorGroupBox</source> <source>backButtonBehaviorGroupBox</source>
<translation>رفتار دکمه برگشت:\nدکمه برگشت کنترلر را طوری تنظیم می کند که ضربه زدن روی موقعیت مشخص شده روی صفحه لمسی PS4 را شبیه سازی کند.</translation> <translation>رفتار دکمه برگشت:\nدکمه برگشت کنترلر را طوری تنظیم می کند که ضربه زدن روی موقعیت مشخص شده روی صفحه لمسی PS4 را شبیه سازی کند.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>enableCompatibilityCheckBox</source>
<translation>نمایش دادههای سازگاری:\nاطلاعات سازگاری بازی را به صورت جدول نمایش میدهد. برای دریافت اطلاعات بهروز، گزینه "به‌روزرسانی سازگاری هنگام راه‌اندازی" را فعال کنید.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>checkCompatibilityOnStartupCheckBox</source>
<translation>بهروزرسانی سازگاری هنگام راهاندازی:\هطور خودکار پایگاه داده سازگاری را هنگام راهاندازی ShadPS4 بهروزرسانی میکند.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>updateCompatibilityButton</source>
<translation>بهروزرسانی پایگاه داده سازگاری:\ایگاه داده سازگاری را بلافاصله بهروزرسانی میکند.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="70"/> <location filename="../settings_dialog.cpp" line="70"/>
<source>Never</source> <source>Never</source>
@ -1234,7 +1279,7 @@
<message> <message>
<location filename="../settings_dialog.cpp" line="101"/> <location filename="../settings_dialog.cpp" line="101"/>
<source>Touchpad Left</source> <source>Touchpad Left</source>
<translation>پد لمسی سمت چپ</translation> <translation>صفحه لمسی سمت چپ</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="102"/> <location filename="../settings_dialog.cpp" line="102"/>
@ -1244,7 +1289,7 @@
<message> <message>
<location filename="../settings_dialog.cpp" line="103"/> <location filename="../settings_dialog.cpp" line="103"/>
<source>Touchpad Center</source> <source>Touchpad Center</source>
<translation>مرکز تاچ پد</translation> <translation>مرکز صفحه لمسی</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="104"/> <location filename="../settings_dialog.cpp" line="104"/>
@ -1254,22 +1299,22 @@
<message> <message>
<location filename="../settings_dialog.cpp" line="312"/> <location filename="../settings_dialog.cpp" line="312"/>
<source>graphicsAdapterGroupBox</source> <source>graphicsAdapterGroupBox</source>
<translation>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.</translation> <translation>دستگاه گرافیکی:\nدر سیستمهای با چندین پردازنده گرافیکی، از فهرست کشویی، پردازنده گرافیکی که شبیهساز از آن استفاده میکند را انتخاب کنید، یا گزینه "انتخاب خودکار" را انتخاب کنید تا به طور خودکار تعیین شود.</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="314"/> <location filename="../settings_dialog.cpp" line="314"/>
<source>resolutionLayout</source> <source>resolutionLayout</source>
<translation>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.</translation> <translation>عرض/ارتفاع:\nاندازه پنجره شبیهساز را در هنگام راهاندازی تنظیم میکند، که در حین بازی قابل تغییر اندازه است.\nاین با وضوح داخل بازی متفاوت است.</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="318"/> <location filename="../settings_dialog.cpp" line="318"/>
<source>heightDivider</source> <source>heightDivider</source>
<translation>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!</translation> <translation>تقسیمکننده Vblank:\nمیزان فریم ریت که شبیهساز با آن بهروزرسانی میشود، در این عدد ضرب میشود. تغییر این مقدار ممکن است تأثیرات منفی داشته باشد، مانند افزایش سرعت بازی یا خراب شدن عملکردهای حیاتی بازی که انتظار تغییر آن را ندارند!</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="320"/> <location filename="../settings_dialog.cpp" line="320"/>
<source>dumpShadersCheckBox</source> <source>dumpShadersCheckBox</source>
<translation>Enable Shaders Dumping:\nFor the sake of technical debugging, saves the games shaders to a folder as they render.</translation> <translation>فعالسازی ذخیرهسازی شیدرها:\همنظور اشکالزدایی فنی، شیدرهای بازی را هنگام رندر شدن در یک پوشه ذخیره میکند.</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="322"/> <location filename="../settings_dialog.cpp" line="322"/>
@ -1294,7 +1339,7 @@
<message> <message>
<location filename="../settings_dialog.cpp" line="329"/> <location filename="../settings_dialog.cpp" line="329"/>
<source>debugDump</source> <source>debugDump</source>
<translation>Enable Debug Dumping:\nSaves the import and export symbols and file header information of the currently running PS4 program to a directory.</translation> <translation>فعالسازی ذخیرهسازی دیباگ:\nنمادهای import و export و اطلاعات هدر فایل برنامه در حال اجرای PS4 را در یک پوشه ذخیره میکند.</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="331"/> <location filename="../settings_dialog.cpp" line="331"/>
@ -1329,6 +1374,11 @@
<source>Serial</source> <source>Serial</source>
<translation>سریال</translation> <translation>سریال</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility</source>
<translation>سازگاری</translation>
</message>
<message> <message>
<location filename="../game_list_frame.cpp" line="34"/> <location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source> <source>Region</source>
@ -1337,7 +1387,7 @@
<message> <message>
<location filename="../game_list_frame.cpp" line="34"/> <location filename="../game_list_frame.cpp" line="34"/>
<source>Firmware</source> <source>Firmware</source>
<translation>فریمور</translation> <translation>فریمور</translation>
</message> </message>
<message> <message>
<location filename="../game_list_frame.cpp" line="35"/> <location filename="../game_list_frame.cpp" line="35"/>
@ -1362,7 +1412,37 @@
<message> <message>
<location filename="../game_list_frame.cpp" line="108"/> <location filename="../game_list_frame.cpp" line="108"/>
<source>Never Played</source> <source>Never Played</source>
<translation>Never Played</translation> <translation>هرگز بازی نشده</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility is untested</source>
<translation>سازگاری تست نشده است</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game does not initialize properly / crashes the emulator</source>
<translation>بازی به درستی راهاندازی نمیشود / شبیهساز کرش میکند</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game boots, but only displays a blank screen</source>
<translation>بازی اجرا میشود، اما فقط یک صفحه خالی نمایش داده میشود</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game displays an image but does not go past the menu</source>
<translation>بازی تصویری نمایش میدهد، اما از منو فراتر نمیرود</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game has game-breaking glitches or unplayable performance</source>
<translation>بازی دارای اشکالات بحرانی یا عملکرد غیرقابل بازی است</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game can be completed with playable performance and no major glitches</source>
<translation>بازی با عملکرد قابل قبول و بدون اشکالات عمده قابل بازی است.</translation>
</message> </message>
</context> </context>
<context> <context>
@ -1370,7 +1450,7 @@
<message> <message>
<location filename="../check_update.cpp" line="34"/> <location filename="../check_update.cpp" line="34"/>
<source>Auto Updater</source> <source>Auto Updater</source>
<translation>به روز رسانی خودکار</translation> <translation>بهروزرسانی خودکار</translation>
</message> </message>
<message> <message>
<location filename="../check_update.cpp" line="51"/> <location filename="../check_update.cpp" line="51"/>
@ -1415,7 +1495,7 @@
<message> <message>
<location filename="../check_update.cpp" line="187"/> <location filename="../check_update.cpp" line="187"/>
<source>Update Channel</source> <source>Update Channel</source>
<translation>کانال بروزرسانی</translation> <translation>کانال بهروزرسانی</translation>
</message> </message>
<message> <message>
<location filename="../check_update.cpp" line="177"/> <location filename="../check_update.cpp" line="177"/>
@ -1440,7 +1520,7 @@
<message> <message>
<location filename="../check_update.cpp" line="198"/> <location filename="../check_update.cpp" line="198"/>
<source>Check for Updates at Startup</source> <source>Check for Updates at Startup</source>
<translation>بررسی بروزرسانی هنگام شروع</translation> <translation>بررسی بهروزرسانی هنگام شروع</translation>
</message> </message>
<message> <message>
<location filename="../check_update.cpp" line="199"/> <location filename="../check_update.cpp" line="199"/>
@ -1493,4 +1573,4 @@
<translation>فایل اسکریپت به روز رسانی ایجاد نشد</translation> <translation>فایل اسکریپت به روز رسانی ایجاد نشد</translation>
</message> </message>
</context> </context>
</TS> </TS>

View File

@ -182,8 +182,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="196"/> <location filename="../gui_context_menus.h" line="196"/>
<source>Shortcut created successfully!\n %1</source> <source>Shortcut created successfully!</source>
<translation>Shortcut created successfully!\n %1</translation> <translation>Shortcut created successfully!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="199"/> <location filename="../gui_context_menus.h" line="199"/>
@ -192,8 +192,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="200"/> <location filename="../gui_context_menus.h" line="200"/>
<source>Error creating shortcut!\n %1</source> <source>Error creating shortcut!</source>
<translation>Error creating shortcut!\n %1</translation> <translation>Error creating shortcut!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="275"/> <location filename="../gui_context_menus.h" line="275"/>
@ -672,11 +672,36 @@
<source>GUI Settings</source> <source>GUI Settings</source>
<translation>GUI-Asetukset</translation> <translation>GUI-Asetukset</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui" line="475"/>
<source>Disable Trophy Pop-ups</source>
<translation>Disable Trophy Pop-ups</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="375"/> <location filename="../settings_dialog.ui" line="375"/>
<source>Play title music</source> <source>Play title music</source>
<translation>Soita otsikkomusiikkia</translation> <translation>Soita otsikkomusiikkia</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database On Startup</source>
<translation>Update Compatibility Database On Startup</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Game Compatibility</source>
<translation>Game Compatibility</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Display Compatibility Data</source>
<translation>Display Compatibility Data</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database</source>
<translation>Update Compatibility Database</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="394"/> <location filename="../settings_dialog.ui" line="394"/>
<source>Volume</source> <source>Volume</source>
@ -1201,6 +1226,11 @@
<source>GUIgroupBox</source> <source>GUIgroupBox</source>
<translation>Soita Otsikkomusiikkia:\nJos peli tukee sitä, ota käyttöön erityisen musiikin soittaminen pelin valinnan yhteydessä käyttöliittymässä.</translation> <translation>Soita Otsikkomusiikkia:\nJos peli tukee sitä, ota käyttöön erityisen musiikin soittaminen pelin valinnan yhteydessä käyttöliittymässä.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp" line="267"/>
<source>disableTrophycheckBox</source>
<translation>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).</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="450"/> <location filename="../settings_dialog.cpp" line="450"/>
<source>hideCursorGroupBox</source> <source>hideCursorGroupBox</source>
@ -1216,6 +1246,21 @@
<source>backButtonBehaviorGroupBox</source> <source>backButtonBehaviorGroupBox</source>
<translation>Takaisin-napin käyttäytyminen:\nAsettaa ohjaimen takaisin-napin jäljittelemään kosketusta PS4:n kosketuslevyn määritettyyn kohtaan.</translation> <translation>Takaisin-napin käyttäytyminen:\nAsettaa ohjaimen takaisin-napin jäljittelemään kosketusta PS4:n kosketuslevyn määritettyyn kohtaan.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>enableCompatibilityCheckBox</source>
<translation>Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>checkCompatibilityOnStartupCheckBox</source>
<translation>Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>updateCompatibilityButton</source>
<translation>Update Compatibility Database:\nImmediately update the compatibility database.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="70"/> <location filename="../settings_dialog.cpp" line="70"/>
<source>Never</source> <source>Never</source>
@ -1329,6 +1374,11 @@
<source>Serial</source> <source>Serial</source>
<translation>Sarjanumero</translation> <translation>Sarjanumero</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility</source>
<translation>Compatibility</translation>
</message>
<message> <message>
<location filename="../game_list_frame.cpp" line="34"/> <location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source> <source>Region</source>
@ -1364,6 +1414,36 @@
<source>Never Played</source> <source>Never Played</source>
<translation>Never Played</translation> <translation>Never Played</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility is untested</source>
<translation>Compatibility is untested</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game does not initialize properly / crashes the emulator</source>
<translation>Game does not initialize properly / crashes the emulator</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game boots, but only displays a blank screen</source>
<translation>Game boots, but only displays a blank screen</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game displays an image but does not go past the menu</source>
<translation>Game displays an image but does not go past the menu</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game has game-breaking glitches or unplayable performance</source>
<translation>Game has game-breaking glitches or unplayable performance</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game can be completed with playable performance and no major glitches</source>
<translation>Game can be completed with playable performance and no major glitches</translation>
</message>
</context> </context>
<context> <context>
<name>CheckUpdate</name> <name>CheckUpdate</name>

View File

@ -182,8 +182,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="196"/> <location filename="../gui_context_menus.h" line="196"/>
<source>Shortcut created successfully!\n %1</source> <source>Shortcut created successfully!</source>
<translation>Raccourci créé avec succès !\n %1</translation> <translation>Raccourci créé avec succès !</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="199"/> <location filename="../gui_context_menus.h" line="199"/>
@ -192,8 +192,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="200"/> <location filename="../gui_context_menus.h" line="200"/>
<source>Error creating shortcut!\n %1</source> <source>Error creating shortcut!</source>
<translation>Erreur lors de la création du raccourci !\n %1</translation> <translation>Erreur lors de la création du raccourci !</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="275"/> <location filename="../gui_context_menus.h" line="275"/>
@ -672,11 +672,36 @@
<source>GUI Settings</source> <source>GUI Settings</source>
<translation>Paramètres de l'interface</translation> <translation>Paramètres de l'interface</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui" line="475"/>
<source>Disable Trophy Pop-ups</source>
<translation>Disable Trophy Pop-ups</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="375"/> <location filename="../settings_dialog.ui" line="375"/>
<source>Play title music</source> <source>Play title music</source>
<translation>Lire la musique du titre</translation> <translation>Lire la musique du titre</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database On Startup</source>
<translation>Update Compatibility Database On Startup</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Game Compatibility</source>
<translation>Game Compatibility</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Display Compatibility Data</source>
<translation>Display Compatibility Data</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database</source>
<translation>Update Compatibility Database</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="394"/> <location filename="../settings_dialog.ui" line="394"/>
<source>Volume</source> <source>Volume</source>
@ -1201,6 +1226,11 @@
<source>GUIgroupBox</source> <source>GUIgroupBox</source>
<translation>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.</translation> <translation>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.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp" line="267"/>
<source>disableTrophycheckBox</source>
<translation>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).</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="450"/> <location filename="../settings_dialog.cpp" line="450"/>
<source>hideCursorGroupBox</source> <source>hideCursorGroupBox</source>
@ -1216,6 +1246,21 @@
<source>backButtonBehaviorGroupBox</source> <source>backButtonBehaviorGroupBox</source>
<translation>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.</translation> <translation>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.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>enableCompatibilityCheckBox</source>
<translation>Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>checkCompatibilityOnStartupCheckBox</source>
<translation>Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>updateCompatibilityButton</source>
<translation>Update Compatibility Database:\nImmediately update the compatibility database.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="70"/> <location filename="../settings_dialog.cpp" line="70"/>
<source>Never</source> <source>Never</source>
@ -1329,6 +1374,11 @@
<source>Serial</source> <source>Serial</source>
<translation>Série</translation> <translation>Série</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility</source>
<translation>Compatibility</translation>
</message>
<message> <message>
<location filename="../game_list_frame.cpp" line="34"/> <location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source> <source>Region</source>
@ -1364,6 +1414,36 @@
<source>Never Played</source> <source>Never Played</source>
<translation>Jamais joué</translation> <translation>Jamais joué</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility is untested</source>
<translation>Compatibility is untested</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game does not initialize properly / crashes the emulator</source>
<translation>Game does not initialize properly / crashes the emulator</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game boots, but only displays a blank screen</source>
<translation>Game boots, but only displays a blank screen</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game displays an image but does not go past the menu</source>
<translation>Game displays an image but does not go past the menu</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game has game-breaking glitches or unplayable performance</source>
<translation>Game has game-breaking glitches or unplayable performance</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game can be completed with playable performance and no major glitches</source>
<translation>Game can be completed with playable performance and no major glitches</translation>
</message>
</context> </context>
<context> <context>
<name>CheckUpdate</name> <name>CheckUpdate</name>

View File

@ -182,8 +182,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="174"/> <location filename="../gui_context_menus.h" line="174"/>
<source>Shortcut created successfully!\n %1</source> <source>Shortcut created successfully!</source>
<translation>Parancsikon sikeresen létrehozva!\n %1</translation> <translation>Parancsikon sikeresen létrehozva!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="177"/> <location filename="../gui_context_menus.h" line="177"/>
@ -192,8 +192,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="178"/> <location filename="../gui_context_menus.h" line="178"/>
<source>Error creating shortcut!\n %1</source> <source>Error creating shortcut!</source>
<translation>Hiba a parancsikon létrehozásával!\n %1</translation> <translation>Hiba a parancsikon létrehozásával!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="253"/> <location filename="../gui_context_menus.h" line="253"/>
@ -672,11 +672,36 @@
<source>GUI Settings</source> <source>GUI Settings</source>
<translation>GUI Beállítások</translation> <translation>GUI Beállítások</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui" line="475"/>
<source>Disable Trophy Pop-ups</source>
<translation>Disable Trophy Pop-ups</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="375"/> <location filename="../settings_dialog.ui" line="375"/>
<source>Play title music</source> <source>Play title music</source>
<translation>Címzene lejátszása</translation> <translation>Címzene lejátszása</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database On Startup</source>
<translation>Update Compatibility Database On Startup</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Game Compatibility</source>
<translation>Game Compatibility</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Display Compatibility Data</source>
<translation>Display Compatibility Data</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database</source>
<translation>Update Compatibility Database</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="394"/> <location filename="../settings_dialog.ui" line="394"/>
<source>Volume</source> <source>Volume</source>
@ -1201,6 +1226,11 @@
<source>GUIgroupBox</source> <source>GUIgroupBox</source>
<translation>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.</translation> <translation>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.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp" line="267"/>
<source>disableTrophycheckBox</source>
<translation>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).</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="450"/> <location filename="../settings_dialog.cpp" line="450"/>
<source>hideCursorGroupBox</source> <source>hideCursorGroupBox</source>
@ -1216,6 +1246,21 @@
<source>backButtonBehaviorGroupBox</source> <source>backButtonBehaviorGroupBox</source>
<translation>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.</translation> <translation>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.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>enableCompatibilityCheckBox</source>
<translation>Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>checkCompatibilityOnStartupCheckBox</source>
<translation>Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>updateCompatibilityButton</source>
<translation>Update Compatibility Database:\nImmediately update the compatibility database.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="70"/> <location filename="../settings_dialog.cpp" line="70"/>
<source>Never</source> <source>Never</source>
@ -1329,6 +1374,11 @@
<source>Serial</source> <source>Serial</source>
<translation>Sorozatszám</translation> <translation>Sorozatszám</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility</source>
<translation>Compatibility</translation>
</message>
<message> <message>
<location filename="../game_list_frame.cpp" line="34"/> <location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source> <source>Region</source>
@ -1364,6 +1414,36 @@
<source>Never Played</source> <source>Never Played</source>
<translation>Never Played</translation> <translation>Never Played</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility is untested</source>
<translation>Compatibility is untested</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game does not initialize properly / crashes the emulator</source>
<translation>Game does not initialize properly / crashes the emulator</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game boots, but only displays a blank screen</source>
<translation>Game boots, but only displays a blank screen</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game displays an image but does not go past the menu</source>
<translation>Game displays an image but does not go past the menu</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game has game-breaking glitches or unplayable performance</source>
<translation>Game has game-breaking glitches or unplayable performance</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game can be completed with playable performance and no major glitches</source>
<translation>Game can be completed with playable performance and no major glitches</translation>
</message>
</context> </context>
<context> <context>
<name>CheckUpdate</name> <name>CheckUpdate</name>
@ -1493,4 +1573,4 @@
<translation>A frissítési szkript fájl létrehozása nem sikerült</translation> <translation>A frissítési szkript fájl létrehozása nem sikerült</translation>
</message> </message>
</context> </context>
</TS> </TS>

View File

@ -182,8 +182,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="196"/> <location filename="../gui_context_menus.h" line="196"/>
<source>Shortcut created successfully!\n %1</source> <source>Shortcut created successfully!</source>
<translation>Shortcut created successfully!\n %1</translation> <translation>Shortcut created successfully!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="199"/> <location filename="../gui_context_menus.h" line="199"/>
@ -192,8 +192,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="200"/> <location filename="../gui_context_menus.h" line="200"/>
<source>Error creating shortcut!\n %1</source> <source>Error creating shortcut!</source>
<translation>Error creating shortcut!\n %1</translation> <translation>Error creating shortcut!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="275"/> <location filename="../gui_context_menus.h" line="275"/>
@ -672,11 +672,36 @@
<source>GUI Settings</source> <source>GUI Settings</source>
<translation>Pengaturan GUI</translation> <translation>Pengaturan GUI</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui" line="475"/>
<source>Disable Trophy Pop-ups</source>
<translation>Disable Trophy Pop-ups</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="375"/> <location filename="../settings_dialog.ui" line="375"/>
<source>Play title music</source> <source>Play title music</source>
<translation>Putar musik judul</translation> <translation>Putar musik judul</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database On Startup</source>
<translation>Update Compatibility Database On Startup</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Game Compatibility</source>
<translation>Game Compatibility</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Display Compatibility Data</source>
<translation>Display Compatibility Data</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database</source>
<translation>Update Compatibility Database</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="394"/> <location filename="../settings_dialog.ui" line="394"/>
<source>Volume</source> <source>Volume</source>
@ -1201,6 +1226,11 @@
<source>GUIgroupBox</source> <source>GUIgroupBox</source>
<translation>Putar Musik Judul Permainan:\nJika permainan mendukungnya, aktifkan pemutaran musik khusus saat memilih permainan di GUI.</translation> <translation>Putar Musik Judul Permainan:\nJika permainan mendukungnya, aktifkan pemutaran musik khusus saat memilih permainan di GUI.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp" line="267"/>
<source>disableTrophycheckBox</source>
<translation>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).</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="450"/> <location filename="../settings_dialog.cpp" line="450"/>
<source>hideCursorGroupBox</source> <source>hideCursorGroupBox</source>
@ -1216,6 +1246,21 @@
<source>backButtonBehaviorGroupBox</source> <source>backButtonBehaviorGroupBox</source>
<translation>Perilaku Tombol Kembali:\nMengatur tombol kembali pada pengontrol untuk meniru ketukan di posisi yang ditentukan di touchpad PS4.</translation> <translation>Perilaku Tombol Kembali:\nMengatur tombol kembali pada pengontrol untuk meniru ketukan di posisi yang ditentukan di touchpad PS4.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>enableCompatibilityCheckBox</source>
<translation>Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>checkCompatibilityOnStartupCheckBox</source>
<translation>Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>updateCompatibilityButton</source>
<translation>Update Compatibility Database:\nImmediately update the compatibility database.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="70"/> <location filename="../settings_dialog.cpp" line="70"/>
<source>Never</source> <source>Never</source>
@ -1329,6 +1374,11 @@
<source>Serial</source> <source>Serial</source>
<translation>Serial</translation> <translation>Serial</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility</source>
<translation>Compatibility</translation>
</message>
<message> <message>
<location filename="../game_list_frame.cpp" line="34"/> <location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source> <source>Region</source>
@ -1364,6 +1414,36 @@
<source>Never Played</source> <source>Never Played</source>
<translation>Never Played</translation> <translation>Never Played</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility is untested</source>
<translation>Compatibility is untested</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game does not initialize properly / crashes the emulator</source>
<translation>Game does not initialize properly / crashes the emulator</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game boots, but only displays a blank screen</source>
<translation>Game boots, but only displays a blank screen</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game displays an image but does not go past the menu</source>
<translation>Game displays an image but does not go past the menu</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game has game-breaking glitches or unplayable performance</source>
<translation>Game has game-breaking glitches or unplayable performance</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game can be completed with playable performance and no major glitches</source>
<translation>Game can be completed with playable performance and no major glitches</translation>
</message>
</context> </context>
<context> <context>
<name>CheckUpdate</name> <name>CheckUpdate</name>

View File

@ -182,8 +182,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="196"/> <location filename="../gui_context_menus.h" line="196"/>
<source>Shortcut created successfully!\n %1</source> <source>Shortcut created successfully!</source>
<translation>Scorciatoia creata con successo!\n %1</translation> <translation>Scorciatoia creata con successo!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="199"/> <location filename="../gui_context_menus.h" line="199"/>
@ -192,8 +192,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="200"/> <location filename="../gui_context_menus.h" line="200"/>
<source>Error creating shortcut!\n %1</source> <source>Error creating shortcut!</source>
<translation>Errore nella creazione della scorciatoia!\n %1</translation> <translation>Errore nella creazione della scorciatoia!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="275"/> <location filename="../gui_context_menus.h" line="275"/>
@ -208,7 +208,7 @@
<message> <message>
<location filename="../gui_context_menus.h" line="305"/> <location filename="../gui_context_menus.h" line="305"/>
<source>requiresEnableSeparateUpdateFolder_MSG</source> <source>requiresEnableSeparateUpdateFolder_MSG</source>
<translation>This feature requires the 'Enable Separate Update Folder' config option to work. If you want to use this feature, please enable it.</translation> <translation>Questa feature richiede che venga attivata l'opzione "Abilita Cartella Aggiornamenti Separata" per poter funzionare, per favore abilitala.</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="312"/> <location filename="../gui_context_menus.h" line="312"/>
@ -495,7 +495,7 @@
<message> <message>
<location filename="../settings_dialog.ui" line="140"/> <location filename="../settings_dialog.ui" line="140"/>
<source>Enable Separate Update Folder</source> <source>Enable Separate Update Folder</source>
<translation>Abilità Cartella Aggiornamenti Separata</translation> <translation>Abilita Cartella Aggiornamenti Separata</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.ui" line="129"/> <location filename="../settings_dialog.ui" line="129"/>
@ -672,11 +672,36 @@
<source>GUI Settings</source> <source>GUI Settings</source>
<translation>Impostazioni GUI</translation> <translation>Impostazioni GUI</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui" line="475"/>
<source>Disable Trophy Pop-ups</source>
<translation>Disabilita Notifica Trofei</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="375"/> <location filename="../settings_dialog.ui" line="375"/>
<source>Play title music</source> <source>Play title music</source>
<translation>Riproduci musica del titolo</translation> <translation>Riproduci musica del titolo</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database On Startup</source>
<translation>Aggiorna Database Compatibilità all'Avvio</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Game Compatibility</source>
<translation>Compatibilità Gioco</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Display Compatibility Data</source>
<translation>Mostra Dati Compatibilità</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database</source>
<translation>Aggiorna Database Compatibilità</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="394"/> <location filename="../settings_dialog.ui" line="394"/>
<source>Volume</source> <source>Volume</source>
@ -1201,6 +1226,11 @@
<source>GUIgroupBox</source> <source>GUIgroupBox</source>
<translation>Riproduci Musica del Titolo:\nSe un gioco lo supporta, attiva la riproduzione di musica speciale quando selezioni il gioco nell'interfaccia grafica.</translation> <translation>Riproduci Musica del Titolo:\nSe un gioco lo supporta, attiva la riproduzione di musica speciale quando selezioni il gioco nell'interfaccia grafica.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp" line="267"/>
<source>disableTrophycheckBox</source>
<translation>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).</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="450"/> <location filename="../settings_dialog.cpp" line="450"/>
<source>hideCursorGroupBox</source> <source>hideCursorGroupBox</source>
@ -1216,6 +1246,21 @@
<source>backButtonBehaviorGroupBox</source> <source>backButtonBehaviorGroupBox</source>
<translation>Comportamento del pulsante Indietro:\nImposta il pulsante Indietro del controller per emulare il tocco sulla posizione specificata sul touchpad PS4.</translation> <translation>Comportamento del pulsante Indietro:\nImposta il pulsante Indietro del controller per emulare il tocco sulla posizione specificata sul touchpad PS4.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>enableCompatibilityCheckBox</source>
<translation>Mostra Dati Compatibilità:\nMostra informazioni sulla compatibilità del gioco nella visualizzazione lista. Abilita "Aggiorna Compatiblità all'Avvio" per ottenere informazioni aggiornate.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>checkCompatibilityOnStartupCheckBox</source>
<translation>Aggiorna Compatibilità all'Avvio:\nAggiorna automaticamente il database della compatibilità quando si avvia shadps4.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>updateCompatibilityButton</source>
<translation>Aggiorna Database Compatibilità:\nAggiorna immediatamente il database di compatibilità.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="70"/> <location filename="../settings_dialog.cpp" line="70"/>
<source>Never</source> <source>Never</source>
@ -1329,6 +1374,11 @@
<source>Serial</source> <source>Serial</source>
<translation>Seriale</translation> <translation>Seriale</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility</source>
<translation>Compatibilità</translation>
</message>
<message> <message>
<location filename="../game_list_frame.cpp" line="34"/> <location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source> <source>Region</source>
@ -1362,7 +1412,37 @@
<message> <message>
<location filename="../game_list_frame.cpp" line="108"/> <location filename="../game_list_frame.cpp" line="108"/>
<source>Never Played</source> <source>Never Played</source>
<translation>Never Played</translation> <translation>Mai Giocato</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility is untested</source>
<translation>Nessuna informazione sulla compatibilità</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game does not initialize properly / crashes the emulator</source>
<translation>Il gioco non si avvia in modo corretto / forza chiusura dell'emulatore</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game boots, but only displays a blank screen</source>
<translation>Il gioco si avvia, ma mostra solo una schermata nera</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game displays an image but does not go past the menu</source>
<translation>Il gioco mostra immagini ma non va oltre il menu</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game has game-breaking glitches or unplayable performance</source>
<translation>Il gioco ha problemi gravi di emulazione oppure framerate troppo basso</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game can be completed with playable performance and no major glitches</source>
<translation>Il gioco può essere completato con buone prestazioni e senza problemi gravi</translation>
</message> </message>
</context> </context>
<context> <context>

View File

@ -182,8 +182,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="196"/> <location filename="../gui_context_menus.h" line="196"/>
<source>Shortcut created successfully!\n %1</source> <source>Shortcut created successfully!</source>
<translation>!\n %1</translation> <translation>!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="199"/> <location filename="../gui_context_menus.h" line="199"/>
@ -192,8 +192,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="200"/> <location filename="../gui_context_menus.h" line="200"/>
<source>Error creating shortcut!\n %1</source> <source>Error creating shortcut!</source>
<translation>!\n %1</translation> <translation>!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="275"/> <location filename="../gui_context_menus.h" line="275"/>
@ -672,11 +672,36 @@
<source>GUI Settings</source> <source>GUI Settings</source>
<translation>GUI設定</translation> <translation>GUI設定</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui" line="475"/>
<source>Disable Trophy Pop-ups</source>
<translation>Disable Trophy Pop-ups</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="375"/> <location filename="../settings_dialog.ui" line="375"/>
<source>Play title music</source> <source>Play title music</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database On Startup</source>
<translation>Update Compatibility Database On Startup</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Game Compatibility</source>
<translation>Game Compatibility</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Display Compatibility Data</source>
<translation>Display Compatibility Data</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database</source>
<translation>Update Compatibility Database</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="394"/> <location filename="../settings_dialog.ui" line="394"/>
<source>Volume</source> <source>Volume</source>
@ -1201,6 +1226,11 @@
<source>GUIgroupBox</source> <source>GUIgroupBox</source>
<translation>:\nゲームがそれをサポートしている場合GUIでゲームを選択したときに特別な音楽を再生することを有効にします</translation> <translation>:\nゲームがそれをサポートしている場合GUIでゲームを選択したときに特別な音楽を再生することを有効にします</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp" line="267"/>
<source>disableTrophycheckBox</source>
<translation>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).</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="450"/> <location filename="../settings_dialog.cpp" line="450"/>
<source>hideCursorGroupBox</source> <source>hideCursorGroupBox</source>
@ -1216,6 +1246,21 @@
<source>backButtonBehaviorGroupBox</source> <source>backButtonBehaviorGroupBox</source>
<translation>:\nコントローラーの戻るボタンをPS4のタッチパッドの指定された位置をタッチするように設定します</translation> <translation>:\nコントローラーの戻るボタンをPS4のタッチパッドの指定された位置をタッチするように設定します</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>enableCompatibilityCheckBox</source>
<translation>Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>checkCompatibilityOnStartupCheckBox</source>
<translation>Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>updateCompatibilityButton</source>
<translation>Update Compatibility Database:\nImmediately update the compatibility database.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="70"/> <location filename="../settings_dialog.cpp" line="70"/>
<source>Never</source> <source>Never</source>
@ -1329,6 +1374,11 @@
<source>Serial</source> <source>Serial</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility</source>
<translation>Compatibility</translation>
</message>
<message> <message>
<location filename="../game_list_frame.cpp" line="34"/> <location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source> <source>Region</source>
@ -1364,6 +1414,36 @@
<source>Never Played</source> <source>Never Played</source>
<translation>Never Played</translation> <translation>Never Played</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility is untested</source>
<translation>Compatibility is untested</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game does not initialize properly / crashes the emulator</source>
<translation>Game does not initialize properly / crashes the emulator</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game boots, but only displays a blank screen</source>
<translation>Game boots, but only displays a blank screen</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game displays an image but does not go past the menu</source>
<translation>Game displays an image but does not go past the menu</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game has game-breaking glitches or unplayable performance</source>
<translation>Game has game-breaking glitches or unplayable performance</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game can be completed with playable performance and no major glitches</source>
<translation>Game can be completed with playable performance and no major glitches</translation>
</message>
</context> </context>
<context> <context>
<name>CheckUpdate</name> <name>CheckUpdate</name>

View File

@ -182,8 +182,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="196"/> <location filename="../gui_context_menus.h" line="196"/>
<source>Shortcut created successfully!\n %1</source> <source>Shortcut created successfully!</source>
<translation>Shortcut created successfully!\n %1</translation> <translation>Shortcut created successfully!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="199"/> <location filename="../gui_context_menus.h" line="199"/>
@ -192,8 +192,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="200"/> <location filename="../gui_context_menus.h" line="200"/>
<source>Error creating shortcut!\n %1</source> <source>Error creating shortcut!</source>
<translation>Error creating shortcut!\n %1</translation> <translation>Error creating shortcut!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="275"/> <location filename="../gui_context_menus.h" line="275"/>
@ -672,11 +672,36 @@
<source>GUI Settings</source> <source>GUI Settings</source>
<translation>GUI Settings</translation> <translation>GUI Settings</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui" line="475"/>
<source>Disable Trophy Pop-ups</source>
<translation>Disable Trophy Pop-ups</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="375"/> <location filename="../settings_dialog.ui" line="375"/>
<source>Play title music</source> <source>Play title music</source>
<translation>Play title music</translation> <translation>Play title music</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database On Startup</source>
<translation>Update Compatibility Database On Startup</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Game Compatibility</source>
<translation>Game Compatibility</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Display Compatibility Data</source>
<translation>Display Compatibility Data</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database</source>
<translation>Update Compatibility Database</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="394"/> <location filename="../settings_dialog.ui" line="394"/>
<source>Volume</source> <source>Volume</source>
@ -1201,6 +1226,11 @@
<source>GUIgroupBox</source> <source>GUIgroupBox</source>
<translation>Play Title Music:\nIf a game supports it, enable playing special music when selecting the game in the GUI.</translation> <translation>Play Title Music:\nIf a game supports it, enable playing special music when selecting the game in the GUI.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp" line="267"/>
<source>disableTrophycheckBox</source>
<translation>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).</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="450"/> <location filename="../settings_dialog.cpp" line="450"/>
<source>hideCursorGroupBox</source> <source>hideCursorGroupBox</source>
@ -1216,6 +1246,21 @@
<source>backButtonBehaviorGroupBox</source> <source>backButtonBehaviorGroupBox</source>
<translation>Back Button Behavior:\nSets the controller's back button to emulate tapping the specified position on the PS4 touchpad.</translation> <translation>Back Button Behavior:\nSets the controller's back button to emulate tapping the specified position on the PS4 touchpad.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>enableCompatibilityCheckBox</source>
<translation>Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>checkCompatibilityOnStartupCheckBox</source>
<translation>Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>updateCompatibilityButton</source>
<translation>Update Compatibility Database:\nImmediately update the compatibility database.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="70"/> <location filename="../settings_dialog.cpp" line="70"/>
<source>Never</source> <source>Never</source>
@ -1329,6 +1374,11 @@
<source>Serial</source> <source>Serial</source>
<translation>Serial</translation> <translation>Serial</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility</source>
<translation>Compatibility</translation>
</message>
<message> <message>
<location filename="../game_list_frame.cpp" line="34"/> <location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source> <source>Region</source>
@ -1364,6 +1414,36 @@
<source>Never Played</source> <source>Never Played</source>
<translation>Never Played</translation> <translation>Never Played</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility is untested</source>
<translation>Compatibility is untested</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game does not initialize properly / crashes the emulator</source>
<translation>Game does not initialize properly / crashes the emulator</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game boots, but only displays a blank screen</source>
<translation>Game boots, but only displays a blank screen</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game displays an image but does not go past the menu</source>
<translation>Game displays an image but does not go past the menu</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game has game-breaking glitches or unplayable performance</source>
<translation>Game has game-breaking glitches or unplayable performance</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game can be completed with playable performance and no major glitches</source>
<translation>Game can be completed with playable performance and no major glitches</translation>
</message>
</context> </context>
<context> <context>
<name>CheckUpdate</name> <name>CheckUpdate</name>

View File

@ -182,8 +182,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="196"/> <location filename="../gui_context_menus.h" line="196"/>
<source>Shortcut created successfully!\n %1</source> <source>Shortcut created successfully!</source>
<translation>Shortcut created successfully!\n %1</translation> <translation>Shortcut created successfully!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="199"/> <location filename="../gui_context_menus.h" line="199"/>
@ -192,8 +192,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="200"/> <location filename="../gui_context_menus.h" line="200"/>
<source>Error creating shortcut!\n %1</source> <source>Error creating shortcut!</source>
<translation>Error creating shortcut!\n %1</translation> <translation>Error creating shortcut!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="275"/> <location filename="../gui_context_menus.h" line="275"/>
@ -672,11 +672,36 @@
<source>GUI Settings</source> <source>GUI Settings</source>
<translation>GUI Nustatymai</translation> <translation>GUI Nustatymai</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui" line="475"/>
<source>Disable Trophy Pop-ups</source>
<translation>Disable Trophy Pop-ups</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="375"/> <location filename="../settings_dialog.ui" line="375"/>
<source>Play title music</source> <source>Play title music</source>
<translation>Groti antraštės muziką</translation> <translation>Groti antraštės muziką</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database On Startup</source>
<translation>Update Compatibility Database On Startup</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Game Compatibility</source>
<translation>Game Compatibility</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Display Compatibility Data</source>
<translation>Display Compatibility Data</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database</source>
<translation>Update Compatibility Database</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="394"/> <location filename="../settings_dialog.ui" line="394"/>
<source>Volume</source> <source>Volume</source>
@ -1201,6 +1226,11 @@
<source>GUIgroupBox</source> <source>GUIgroupBox</source>
<translation>Groti antraščių muziką:\nJei žaidimas tai palaiko, įjungia specialios muzikos grojimą, kai pasirinkite žaidimą GUI.</translation> <translation>Groti antraščių muziką:\nJei žaidimas tai palaiko, įjungia specialios muzikos grojimą, kai pasirinkite žaidimą GUI.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp" line="267"/>
<source>disableTrophycheckBox</source>
<translation>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).</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="450"/> <location filename="../settings_dialog.cpp" line="450"/>
<source>hideCursorGroupBox</source> <source>hideCursorGroupBox</source>
@ -1216,6 +1246,21 @@
<source>backButtonBehaviorGroupBox</source> <source>backButtonBehaviorGroupBox</source>
<translation>Atgal mygtuko elgesys:\nNustato valdiklio atgal mygtuką imituoti paspaudimą nurodytoje vietoje PS4 jutiklinėje plokštėje.</translation> <translation>Atgal mygtuko elgesys:\nNustato valdiklio atgal mygtuką imituoti paspaudimą nurodytoje vietoje PS4 jutiklinėje plokštėje.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>enableCompatibilityCheckBox</source>
<translation>Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>checkCompatibilityOnStartupCheckBox</source>
<translation>Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>updateCompatibilityButton</source>
<translation>Update Compatibility Database:\nImmediately update the compatibility database.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="70"/> <location filename="../settings_dialog.cpp" line="70"/>
<source>Never</source> <source>Never</source>
@ -1329,6 +1374,11 @@
<source>Serial</source> <source>Serial</source>
<translation>Serijinis numeris</translation> <translation>Serijinis numeris</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility</source>
<translation>Compatibility</translation>
</message>
<message> <message>
<location filename="../game_list_frame.cpp" line="34"/> <location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source> <source>Region</source>
@ -1364,6 +1414,36 @@
<source>Never Played</source> <source>Never Played</source>
<translation>Never Played</translation> <translation>Never Played</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility is untested</source>
<translation>Compatibility is untested</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game does not initialize properly / crashes the emulator</source>
<translation>Game does not initialize properly / crashes the emulator</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game boots, but only displays a blank screen</source>
<translation>Game boots, but only displays a blank screen</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game displays an image but does not go past the menu</source>
<translation>Game displays an image but does not go past the menu</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game has game-breaking glitches or unplayable performance</source>
<translation>Game has game-breaking glitches or unplayable performance</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game can be completed with playable performance and no major glitches</source>
<translation>Game can be completed with playable performance and no major glitches</translation>
</message>
</context> </context>
<context> <context>
<name>CheckUpdate</name> <name>CheckUpdate</name>

View File

@ -182,8 +182,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="196"/> <location filename="../gui_context_menus.h" line="196"/>
<source>Shortcut created successfully!\n %1</source> <source>Shortcut created successfully!</source>
<translation>Snarvei opprettet!\n %1</translation> <translation>Snarvei opprettet!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="199"/> <location filename="../gui_context_menus.h" line="199"/>
@ -192,8 +192,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="200"/> <location filename="../gui_context_menus.h" line="200"/>
<source>Error creating shortcut!\n %1</source> <source>Error creating shortcut!</source>
<translation>Feil ved opprettelse av snarvei!\n %1</translation> <translation>Feil ved opprettelse av snarvei!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="275"/> <location filename="../gui_context_menus.h" line="275"/>
@ -672,11 +672,36 @@
<source>GUI Settings</source> <source>GUI Settings</source>
<translation>GUI-Innstillinger</translation> <translation>GUI-Innstillinger</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui" line="475"/>
<source>Disable Trophy Pop-ups</source>
<translation>Disable Trophy Pop-ups</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="375"/> <location filename="../settings_dialog.ui" line="375"/>
<source>Play title music</source> <source>Play title music</source>
<translation>Spill tittelmusikk</translation> <translation>Spill tittelmusikk</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database On Startup</source>
<translation>Update Compatibility Database On Startup</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Game Compatibility</source>
<translation>Game Compatibility</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Display Compatibility Data</source>
<translation>Display Compatibility Data</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database</source>
<translation>Update Compatibility Database</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="394"/> <location filename="../settings_dialog.ui" line="394"/>
<source>Volume</source> <source>Volume</source>
@ -1201,6 +1226,11 @@
<source>GUIgroupBox</source> <source>GUIgroupBox</source>
<translation>Spille tittelmusikk:\nHvis et spill støtter det, aktiveres det spesiell musikk når du velger spillet i menyen.</translation> <translation>Spille tittelmusikk:\nHvis et spill støtter det, aktiveres det spesiell musikk når du velger spillet i menyen.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp" line="267"/>
<source>disableTrophycheckBox</source>
<translation>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).</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="450"/> <location filename="../settings_dialog.cpp" line="450"/>
<source>hideCursorGroupBox</source> <source>hideCursorGroupBox</source>
@ -1216,6 +1246,21 @@
<source>backButtonBehaviorGroupBox</source> <source>backButtonBehaviorGroupBox</source>
<translation>Atferd for tilbaketasten:\nSetter tilbaketasten kontrolleren til å imitere et trykk den angitte posisjonen PS4s berøringsplate.</translation> <translation>Atferd for tilbaketasten:\nSetter tilbaketasten kontrolleren til å imitere et trykk den angitte posisjonen PS4s berøringsplate.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>enableCompatibilityCheckBox</source>
<translation>Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>checkCompatibilityOnStartupCheckBox</source>
<translation>Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>updateCompatibilityButton</source>
<translation>Update Compatibility Database:\nImmediately update the compatibility database.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="70"/> <location filename="../settings_dialog.cpp" line="70"/>
<source>Never</source> <source>Never</source>
@ -1329,6 +1374,11 @@
<source>Serial</source> <source>Serial</source>
<translation>Serienummer</translation> <translation>Serienummer</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility</source>
<translation>Compatibility</translation>
</message>
<message> <message>
<location filename="../game_list_frame.cpp" line="34"/> <location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source> <source>Region</source>
@ -1364,6 +1414,36 @@
<source>Never Played</source> <source>Never Played</source>
<translation>Never Played</translation> <translation>Never Played</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility is untested</source>
<translation>Compatibility is untested</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game does not initialize properly / crashes the emulator</source>
<translation>Game does not initialize properly / crashes the emulator</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game boots, but only displays a blank screen</source>
<translation>Game boots, but only displays a blank screen</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game displays an image but does not go past the menu</source>
<translation>Game displays an image but does not go past the menu</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game has game-breaking glitches or unplayable performance</source>
<translation>Game has game-breaking glitches or unplayable performance</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game can be completed with playable performance and no major glitches</source>
<translation>Game can be completed with playable performance and no major glitches</translation>
</message>
</context> </context>
<context> <context>
<name>CheckUpdate</name> <name>CheckUpdate</name>
@ -1493,4 +1573,4 @@
<translation>Kunne ikke opprette oppdateringsskriptfilen</translation> <translation>Kunne ikke opprette oppdateringsskriptfilen</translation>
</message> </message>
</context> </context>
</TS> </TS>

View File

@ -182,8 +182,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="196"/> <location filename="../gui_context_menus.h" line="196"/>
<source>Shortcut created successfully!\n %1</source> <source>Shortcut created successfully!</source>
<translation>Shortcut created successfully!\n %1</translation> <translation>Shortcut created successfully!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="199"/> <location filename="../gui_context_menus.h" line="199"/>
@ -192,8 +192,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="200"/> <location filename="../gui_context_menus.h" line="200"/>
<source>Error creating shortcut!\n %1</source> <source>Error creating shortcut!</source>
<translation>Error creating shortcut!\n %1</translation> <translation>Error creating shortcut!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="275"/> <location filename="../gui_context_menus.h" line="275"/>
@ -672,11 +672,36 @@
<source>GUI Settings</source> <source>GUI Settings</source>
<translation>GUI-Instellingen</translation> <translation>GUI-Instellingen</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui" line="475"/>
<source>Disable Trophy Pop-ups</source>
<translation>Disable Trophy Pop-ups</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="375"/> <location filename="../settings_dialog.ui" line="375"/>
<source>Play title music</source> <source>Play title music</source>
<translation>Titelmuziek afspelen</translation> <translation>Titelmuziek afspelen</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database On Startup</source>
<translation>Update Compatibility Database On Startup</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Game Compatibility</source>
<translation>Game Compatibility</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Display Compatibility Data</source>
<translation>Display Compatibility Data</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database</source>
<translation>Update Compatibility Database</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="394"/> <location filename="../settings_dialog.ui" line="394"/>
<source>Volume</source> <source>Volume</source>
@ -1201,6 +1226,11 @@
<source>GUIgroupBox</source> <source>GUIgroupBox</source>
<translation>Speel titelsong:\nAls een game dit ondersteunt, wordt speciale muziek afgespeeld wanneer je het spel in de GUI selecteert.</translation> <translation>Speel titelsong:\nAls een game dit ondersteunt, wordt speciale muziek afgespeeld wanneer je het spel in de GUI selecteert.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp" line="267"/>
<source>disableTrophycheckBox</source>
<translation>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).</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="450"/> <location filename="../settings_dialog.cpp" line="450"/>
<source>hideCursorGroupBox</source> <source>hideCursorGroupBox</source>
@ -1216,6 +1246,21 @@
<source>backButtonBehaviorGroupBox</source> <source>backButtonBehaviorGroupBox</source>
<translation>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.</translation> <translation>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.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>enableCompatibilityCheckBox</source>
<translation>Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>checkCompatibilityOnStartupCheckBox</source>
<translation>Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>updateCompatibilityButton</source>
<translation>Update Compatibility Database:\nImmediately update the compatibility database.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="70"/> <location filename="../settings_dialog.cpp" line="70"/>
<source>Never</source> <source>Never</source>
@ -1329,6 +1374,11 @@
<source>Serial</source> <source>Serial</source>
<translation>Serienummer</translation> <translation>Serienummer</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility</source>
<translation>Compatibility</translation>
</message>
<message> <message>
<location filename="../game_list_frame.cpp" line="34"/> <location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source> <source>Region</source>
@ -1364,6 +1414,36 @@
<source>Never Played</source> <source>Never Played</source>
<translation>Never Played</translation> <translation>Never Played</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility is untested</source>
<translation>Compatibility is untested</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game does not initialize properly / crashes the emulator</source>
<translation>Game does not initialize properly / crashes the emulator</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game boots, but only displays a blank screen</source>
<translation>Game boots, but only displays a blank screen</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game displays an image but does not go past the menu</source>
<translation>Game displays an image but does not go past the menu</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game has game-breaking glitches or unplayable performance</source>
<translation>Game has game-breaking glitches or unplayable performance</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game can be completed with playable performance and no major glitches</source>
<translation>Game can be completed with playable performance and no major glitches</translation>
</message>
</context> </context>
<context> <context>
<name>CheckUpdate</name> <name>CheckUpdate</name>

View File

@ -182,8 +182,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="196"/> <location filename="../gui_context_menus.h" line="196"/>
<source>Shortcut created successfully!\n %1</source> <source>Shortcut created successfully!</source>
<translation>Utworzenie skrótu zakończone pomyślnie!\n %1</translation> <translation>Utworzenie skrótu zakończone pomyślnie!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="199"/> <location filename="../gui_context_menus.h" line="199"/>
@ -192,8 +192,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="200"/> <location filename="../gui_context_menus.h" line="200"/>
<source>Error creating shortcut!\n %1</source> <source>Error creating shortcut!</source>
<translation>Utworzenie skrótu zakończone niepowodzeniem!\n %1</translation> <translation>Utworzenie skrótu zakończone niepowodzeniem!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="275"/> <location filename="../gui_context_menus.h" line="275"/>
@ -672,11 +672,36 @@
<source>GUI Settings</source> <source>GUI Settings</source>
<translation>Ustawienia Interfejsu</translation> <translation>Ustawienia Interfejsu</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui" line="475"/>
<source>Disable Trophy Pop-ups</source>
<translation>Disable Trophy Pop-ups</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="375"/> <location filename="../settings_dialog.ui" line="375"/>
<source>Play title music</source> <source>Play title music</source>
<translation>Odtwórz muzykę tytułową</translation> <translation>Odtwórz muzykę tytułową</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database On Startup</source>
<translation>Update Compatibility Database On Startup</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Game Compatibility</source>
<translation>Game Compatibility</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Display Compatibility Data</source>
<translation>Display Compatibility Data</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database</source>
<translation>Update Compatibility Database</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="394"/> <location filename="../settings_dialog.ui" line="394"/>
<source>Volume</source> <source>Volume</source>
@ -1201,6 +1226,11 @@
<source>GUIgroupBox</source> <source>GUIgroupBox</source>
<translation>Odtwórz muzykę tytułową:\nJeśli gra to obsługuje, aktywuje odtwarzanie specjalnej muzyki podczas wybierania gry w GUI.</translation> <translation>Odtwórz muzykę tytułową:\nJeśli gra to obsługuje, aktywuje odtwarzanie specjalnej muzyki podczas wybierania gry w GUI.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp" line="267"/>
<source>disableTrophycheckBox</source>
<translation>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).</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="450"/> <location filename="../settings_dialog.cpp" line="450"/>
<source>hideCursorGroupBox</source> <source>hideCursorGroupBox</source>
@ -1216,6 +1246,21 @@
<source>backButtonBehaviorGroupBox</source> <source>backButtonBehaviorGroupBox</source>
<translation>Zachowanie przycisku Wstecz:\nUstawia przycisk Wstecz kontrolera tak, aby emulował dotknięcie określonego miejsca na panelu dotykowym PS4.</translation> <translation>Zachowanie przycisku Wstecz:\nUstawia przycisk Wstecz kontrolera tak, aby emulował dotknięcie określonego miejsca na panelu dotykowym PS4.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>enableCompatibilityCheckBox</source>
<translation>Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>checkCompatibilityOnStartupCheckBox</source>
<translation>Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>updateCompatibilityButton</source>
<translation>Update Compatibility Database:\nImmediately update the compatibility database.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="70"/> <location filename="../settings_dialog.cpp" line="70"/>
<source>Never</source> <source>Never</source>
@ -1329,6 +1374,11 @@
<source>Serial</source> <source>Serial</source>
<translation>Numer seryjny</translation> <translation>Numer seryjny</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility</source>
<translation>Compatibility</translation>
</message>
<message> <message>
<location filename="../game_list_frame.cpp" line="34"/> <location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source> <source>Region</source>
@ -1364,6 +1414,36 @@
<source>Never Played</source> <source>Never Played</source>
<translation>Never Played</translation> <translation>Never Played</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility is untested</source>
<translation>Compatibility is untested</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game does not initialize properly / crashes the emulator</source>
<translation>Game does not initialize properly / crashes the emulator</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game boots, but only displays a blank screen</source>
<translation>Game boots, but only displays a blank screen</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game displays an image but does not go past the menu</source>
<translation>Game displays an image but does not go past the menu</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game has game-breaking glitches or unplayable performance</source>
<translation>Game has game-breaking glitches or unplayable performance</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game can be completed with playable performance and no major glitches</source>
<translation>Game can be completed with playable performance and no major glitches</translation>
</message>
</context> </context>
<context> <context>
<name>CheckUpdate</name> <name>CheckUpdate</name>

View File

@ -182,8 +182,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="196"/> <location filename="../gui_context_menus.h" line="196"/>
<source>Shortcut created successfully!\n %1</source> <source>Shortcut created successfully!</source>
<translation>Atalho criado com sucesso!\n %1</translation> <translation>Atalho criado com sucesso!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="199"/> <location filename="../gui_context_menus.h" line="199"/>
@ -192,8 +192,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="200"/> <location filename="../gui_context_menus.h" line="200"/>
<source>Error creating shortcut!\n %1</source> <source>Error creating shortcut!</source>
<translation>Erro ao criar atalho!\n %1</translation> <translation>Erro ao criar atalho!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="275"/> <location filename="../gui_context_menus.h" line="275"/>
@ -672,11 +672,36 @@
<source>GUI Settings</source> <source>GUI Settings</source>
<translation>Configurações da Interface</translation> <translation>Configurações da Interface</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui" line="475"/>
<source>Disable Trophy Pop-ups</source>
<translation>Desabilitar Pop-ups dos Troféus</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="375"/> <location filename="../settings_dialog.ui" line="375"/>
<source>Play title music</source> <source>Play title music</source>
<translation>Reproduzir música de abertura</translation> <translation>Reproduzir música de abertura</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database On Startup</source>
<translation>Atualizar Compatibilidade ao Inicializar</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Game Compatibility</source>
<translation>Compatibilidade dos Jogos</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Display Compatibility Data</source>
<translation>Exibir Dados de Compatibilidade</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database</source>
<translation>Atualizar Lista de Compatibilidade</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="394"/> <location filename="../settings_dialog.ui" line="394"/>
<source>Volume</source> <source>Volume</source>
@ -1201,6 +1226,11 @@
<source>GUIgroupBox</source> <source>GUIgroupBox</source>
<translation>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.</translation> <translation>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.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp" line="267"/>
<source>disableTrophycheckBox</source>
<translation>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).</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="450"/> <location filename="../settings_dialog.cpp" line="450"/>
<source>hideCursorGroupBox</source> <source>hideCursorGroupBox</source>
@ -1216,6 +1246,21 @@
<source>backButtonBehaviorGroupBox</source> <source>backButtonBehaviorGroupBox</source>
<translation>Comportamento do botão Voltar:\nDefine o botão Voltar do controle para emular o toque na posição especificada no touchpad do PS4.</translation> <translation>Comportamento do botão Voltar:\nDefine o botão Voltar do controle para emular o toque na posição especificada no touchpad do PS4.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>enableCompatibilityCheckBox</source>
<translation>Exibir Dados de Compatibilidade:\nExibe informações de compatibilidade dos jogos na janela principal.\nHabilitar "Atualizar Compatibilidade ao Inicializar" para obter informações atualizadas.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>checkCompatibilityOnStartupCheckBox</source>
<translation>Atualizar Compatibilidade ao inicializar:\nAtualiza automaticamente o banco de dados de compatibilidade quando o SHADPS4 é iniciado.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>updateCompatibilityButton</source>
<translation>Atualizar Lista de Compatibilidade:\nAtualizar imediatamente o banco de dados de compatibilidade.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="70"/> <location filename="../settings_dialog.cpp" line="70"/>
<source>Never</source> <source>Never</source>
@ -1329,6 +1374,11 @@
<source>Serial</source> <source>Serial</source>
<translation>Serial</translation> <translation>Serial</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility</source>
<translation>Compatibilidade</translation>
</message>
<message> <message>
<location filename="../game_list_frame.cpp" line="36"/> <location filename="../game_list_frame.cpp" line="36"/>
<source>Region</source> <source>Region</source>
@ -1364,6 +1414,36 @@
<source>Never Played</source> <source>Never Played</source>
<translation>Nunca jogado</translation> <translation>Nunca jogado</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility is untested</source>
<translation>Compatibilidade não testada</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game does not initialize properly / crashes the emulator</source>
<translation>Jogo não inicializa corretamente / trava o emulador</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game boots, but only displays a blank screen</source>
<translation>O jogo inicializa, mas exibe apenas uma tela vazia</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game displays an image but does not go past the menu</source>
<translation>Jogo exibe imagem mas não passa do menu</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game has game-breaking glitches or unplayable performance</source>
<translation>O jogo tem falhas que interrompem o jogo ou desempenho injogável</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game can be completed with playable performance and no major glitches</source>
<translation>O jogo pode ser concluído com desempenho jogável e sem grandes falhas</translation>
</message>
</context> </context>
<context> <context>
<name>CheckUpdate</name> <name>CheckUpdate</name>

View File

@ -182,8 +182,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="196"/> <location filename="../gui_context_menus.h" line="196"/>
<source>Shortcut created successfully!\n %1</source> <source>Shortcut created successfully!</source>
<translation>Shortcut created successfully!\n %1</translation> <translation>Shortcut created successfully!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="199"/> <location filename="../gui_context_menus.h" line="199"/>
@ -192,8 +192,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="200"/> <location filename="../gui_context_menus.h" line="200"/>
<source>Error creating shortcut!\n %1</source> <source>Error creating shortcut!</source>
<translation>Error creating shortcut!\n %1</translation> <translation>Error creating shortcut!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="275"/> <location filename="../gui_context_menus.h" line="275"/>
@ -672,11 +672,36 @@
<source>GUI Settings</source> <source>GUI Settings</source>
<translation>Setări GUI</translation> <translation>Setări GUI</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui" line="475"/>
<source>Disable Trophy Pop-ups</source>
<translation>Disable Trophy Pop-ups</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="375"/> <location filename="../settings_dialog.ui" line="375"/>
<source>Play title music</source> <source>Play title music</source>
<translation>Redă muzica titlului</translation> <translation>Redă muzica titlului</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database On Startup</source>
<translation>Update Compatibility Database On Startup</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Game Compatibility</source>
<translation>Game Compatibility</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Display Compatibility Data</source>
<translation>Display Compatibility Data</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database</source>
<translation>Update Compatibility Database</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="394"/> <location filename="../settings_dialog.ui" line="394"/>
<source>Volume</source> <source>Volume</source>
@ -1201,6 +1226,11 @@
<source>GUIgroupBox</source> <source>GUIgroupBox</source>
<translation>Redă muzica titlului:\nDacă un joc o suportă, activează redarea muzicii speciale când selectezi jocul în GUI.</translation> <translation>Redă muzica titlului:\nDacă un joc o suportă, activează redarea muzicii speciale când selectezi jocul în GUI.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp" line="267"/>
<source>disableTrophycheckBox</source>
<translation>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).</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="450"/> <location filename="../settings_dialog.cpp" line="450"/>
<source>hideCursorGroupBox</source> <source>hideCursorGroupBox</source>
@ -1216,6 +1246,21 @@
<source>backButtonBehaviorGroupBox</source> <source>backButtonBehaviorGroupBox</source>
<translation>Comportamentul butonului înapoi:\nSetează butonul înapoi al controlerului imite atingerea poziției specificate pe touchpad-ul PS4.</translation> <translation>Comportamentul butonului înapoi:\nSetează butonul înapoi al controlerului imite atingerea poziției specificate pe touchpad-ul PS4.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>enableCompatibilityCheckBox</source>
<translation>Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>checkCompatibilityOnStartupCheckBox</source>
<translation>Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>updateCompatibilityButton</source>
<translation>Update Compatibility Database:\nImmediately update the compatibility database.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="70"/> <location filename="../settings_dialog.cpp" line="70"/>
<source>Never</source> <source>Never</source>
@ -1329,6 +1374,11 @@
<source>Serial</source> <source>Serial</source>
<translation>Serie</translation> <translation>Serie</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility</source>
<translation>Compatibility</translation>
</message>
<message> <message>
<location filename="../game_list_frame.cpp" line="34"/> <location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source> <source>Region</source>
@ -1364,6 +1414,36 @@
<source>Never Played</source> <source>Never Played</source>
<translation>Never Played</translation> <translation>Never Played</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility is untested</source>
<translation>Compatibility is untested</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game does not initialize properly / crashes the emulator</source>
<translation>Game does not initialize properly / crashes the emulator</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game boots, but only displays a blank screen</source>
<translation>Game boots, but only displays a blank screen</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game displays an image but does not go past the menu</source>
<translation>Game displays an image but does not go past the menu</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game has game-breaking glitches or unplayable performance</source>
<translation>Game has game-breaking glitches or unplayable performance</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game can be completed with playable performance and no major glitches</source>
<translation>Game can be completed with playable performance and no major glitches</translation>
</message>
</context> </context>
<context> <context>
<name>CheckUpdate</name> <name>CheckUpdate</name>

View File

@ -182,8 +182,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="196"/> <location filename="../gui_context_menus.h" line="196"/>
<source>Shortcut created successfully!\n %1</source> <source>Shortcut created successfully!</source>
<translation>Ярлык создан успешно!\n %1</translation> <translation>Ярлык создан успешно!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="199"/> <location filename="../gui_context_menus.h" line="199"/>
@ -192,8 +192,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="200"/> <location filename="../gui_context_menus.h" line="200"/>
<source>Error creating shortcut!\n %1</source> <source>Error creating shortcut!</source>
<translation>Ошибка создания ярлыка!\n %1</translation> <translation>Ошибка создания ярлыка!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="275"/> <location filename="../gui_context_menus.h" line="275"/>
@ -672,11 +672,36 @@
<source>GUI Settings</source> <source>GUI Settings</source>
<translation>Интерфейс</translation> <translation>Интерфейс</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui" line="475"/>
<source>Disable Trophy Pop-ups</source>
<translation>Disable Trophy Pop-ups</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="375"/> <location filename="../settings_dialog.ui" line="375"/>
<source>Play title music</source> <source>Play title music</source>
<translation>Играть заглавную музыку</translation> <translation>Играть заглавную музыку</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database On Startup</source>
<translation>Update Compatibility Database On Startup</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Game Compatibility</source>
<translation>Game Compatibility</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Display Compatibility Data</source>
<translation>Display Compatibility Data</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database</source>
<translation>Update Compatibility Database</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="394"/> <location filename="../settings_dialog.ui" line="394"/>
<source>Volume</source> <source>Volume</source>
@ -1201,6 +1226,11 @@
<source>GUIgroupBox</source> <source>GUIgroupBox</source>
<translation>Играть заглавную музыку:\nВключает воспроизведение специальной музыки при выборе игры в списке, если она это поддерживает.</translation> <translation>Играть заглавную музыку:\nВключает воспроизведение специальной музыки при выборе игры в списке, если она это поддерживает.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp" line="267"/>
<source>disableTrophycheckBox</source>
<translation>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).</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="450"/> <location filename="../settings_dialog.cpp" line="450"/>
<source>hideCursorGroupBox</source> <source>hideCursorGroupBox</source>
@ -1216,6 +1246,21 @@
<source>backButtonBehaviorGroupBox</source> <source>backButtonBehaviorGroupBox</source>
<translation>Поведение кнопки «Назад»:\nНастраивает кнопку «Назад» контроллера на эмуляцию нажатия на указанную область на сенсорной панели контроллера PS4.</translation> <translation>Поведение кнопки «Назад»:\nНастраивает кнопку «Назад» контроллера на эмуляцию нажатия на указанную область на сенсорной панели контроллера PS4.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>enableCompatibilityCheckBox</source>
<translation>Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>checkCompatibilityOnStartupCheckBox</source>
<translation>Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>updateCompatibilityButton</source>
<translation>Update Compatibility Database:\nImmediately update the compatibility database.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="70"/> <location filename="../settings_dialog.cpp" line="70"/>
<source>Never</source> <source>Never</source>
@ -1329,6 +1374,11 @@
<source>Serial</source> <source>Serial</source>
<translation>Серийный номер</translation> <translation>Серийный номер</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility</source>
<translation>Compatibility</translation>
</message>
<message> <message>
<location filename="../game_list_frame.cpp" line="34"/> <location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source> <source>Region</source>
@ -1364,6 +1414,36 @@
<source>Never Played</source> <source>Never Played</source>
<translation>Never Played</translation> <translation>Never Played</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility is untested</source>
<translation>Compatibility is untested</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game does not initialize properly / crashes the emulator</source>
<translation>Game does not initialize properly / crashes the emulator</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game boots, but only displays a blank screen</source>
<translation>Game boots, but only displays a blank screen</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game displays an image but does not go past the menu</source>
<translation>Game displays an image but does not go past the menu</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game has game-breaking glitches or unplayable performance</source>
<translation>Game has game-breaking glitches or unplayable performance</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game can be completed with playable performance and no major glitches</source>
<translation>Game can be completed with playable performance and no major glitches</translation>
</message>
</context> </context>
<context> <context>
<name>CheckUpdate</name> <name>CheckUpdate</name>

View File

@ -182,8 +182,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="196"/> <location filename="../gui_context_menus.h" line="196"/>
<source>Shortcut created successfully!\n %1</source> <source>Shortcut created successfully!</source>
<translation>Shkurtorja u krijua me sukses!\n %1</translation> <translation>Shkurtorja u krijua me sukses!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="199"/> <location filename="../gui_context_menus.h" line="199"/>
@ -192,8 +192,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="200"/> <location filename="../gui_context_menus.h" line="200"/>
<source>Error creating shortcut!\n %1</source> <source>Error creating shortcut!</source>
<translation>Gabim krijimin e shkurtores!\n %1</translation> <translation>Gabim krijimin e shkurtores!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="275"/> <location filename="../gui_context_menus.h" line="275"/>
@ -672,11 +672,36 @@
<source>GUI Settings</source> <source>GUI Settings</source>
<translation>Cilësimet e GUI</translation> <translation>Cilësimet e GUI</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui" line="475"/>
<source>Disable Trophy Pop-ups</source>
<translation>Çaktivizo njoftimet për Trofetë</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="375"/> <location filename="../settings_dialog.ui" line="375"/>
<source>Play title music</source> <source>Play title music</source>
<translation>Luaj muzikën e titullit</translation> <translation>Luaj muzikën e titullit</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database On Startup</source>
<translation>Përditëso bazën e dhënave përputhshmërisë gjatë nisjes</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Game Compatibility</source>
<translation>Përputhshmëria e lojës</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Display Compatibility Data</source>
<translation>Shfaq dhënat e përputhshmërisë</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database</source>
<translation>Përditëso bazën e dhënave përputhshmërisë</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="394"/> <location filename="../settings_dialog.ui" line="394"/>
<source>Volume</source> <source>Volume</source>
@ -841,7 +866,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="44"/> <location filename="../cheats_patches.cpp" line="44"/>
<source>Cheats / Patches for </source> <source>Cheats / Patches for </source>
<translation>Cheats / Patches for </translation> <translation>Mashtrime / Arna r </translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="50"/> <location filename="../cheats_patches.cpp" line="50"/>
@ -1159,7 +1184,7 @@
<message> <message>
<location filename="../settings_dialog.cpp" line="293"/> <location filename="../settings_dialog.cpp" line="293"/>
<source>separateUpdatesCheckBox</source> <source>separateUpdatesCheckBox</source>
<translation>Aktivizo dosjen e ndarë përditësimit:\nAktivizon instalimin e përditësimeve lojërave dosje veçanta për menaxhim lehtë.</translation> <translation>Aktivizo dosjen e ndarë përditësimit:\nAktivizon instalimin e përditësimeve lojërave dosje veçanta për menaxhim lehtë.\nKjo mund krijohet manualisht duke shtuar përditësimin e shpaketuar dosjen e lojës me emrin "CUSA00000-UPDATE" ku ID-ja CUSA përputhet me ID- e lojës.</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="295"/> <location filename="../settings_dialog.cpp" line="295"/>
@ -1201,6 +1226,11 @@
<source>GUIgroupBox</source> <source>GUIgroupBox</source>
<translation>Luaj muzikën e titullit:\nNëse një lojë e mbështet, aktivizohet luajtja e muzikës veçantë kur zgjidhësh lojën GUI.</translation> <translation>Luaj muzikën e titullit:\nNëse një lojë e mbështet, aktivizohet luajtja e muzikës veçantë kur zgjidhësh lojën GUI.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp" line="267"/>
<source>disableTrophycheckBox</source>
<translation>Çaktivizo njoftimet për Trofetë:\nÇaktivizo njoftimet për trofetë gjatë lojës. Përparimi i trofeve mund ndiqet duke përdorur Shikuesin e Trofeve (kliko me djathtën mbi lojën dritaren kryesore).</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="450"/> <location filename="../settings_dialog.cpp" line="450"/>
<source>hideCursorGroupBox</source> <source>hideCursorGroupBox</source>
@ -1216,6 +1246,21 @@
<source>backButtonBehaviorGroupBox</source> <source>backButtonBehaviorGroupBox</source>
<translation>Sjellja e butonit mbrapa:\nLejon përcaktohet se cilën pjesë tastierës prekëse do imitojë një prekje butoni mprapa.</translation> <translation>Sjellja e butonit mbrapa:\nLejon përcaktohet se cilën pjesë tastierës prekëse do imitojë një prekje butoni mprapa.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>enableCompatibilityCheckBox</source>
<translation>Shfaq dhënat e përputhshmërisë:\nShfaq informacionin e përputhshmërisë lojës formë tabele. Aktivizo 'Përditëso përputhshmërinë gjatë nisjes' për marrë informacion përditësuar.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>checkCompatibilityOnStartupCheckBox</source>
<translation>Përditëso përputhshmërinë gjatë nisjes:\nPërditëson automatikisht bazën e dhënave përputhshmërisë kur shadPS4 niset.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>updateCompatibilityButton</source>
<translation>Përditëso bazën e dhënave përputhshmërisë:\nPërditëso menjëherë bazën e dhënave përputhshmërisë.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="70"/> <location filename="../settings_dialog.cpp" line="70"/>
<source>Never</source> <source>Never</source>
@ -1329,6 +1374,11 @@
<source>Serial</source> <source>Serial</source>
<translation>Seriku</translation> <translation>Seriku</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility</source>
<translation>Përputhshmëria</translation>
</message>
<message> <message>
<location filename="../game_list_frame.cpp" line="34"/> <location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source> <source>Region</source>
@ -1362,7 +1412,37 @@
<message> <message>
<location filename="../game_list_frame.cpp" line="108"/> <location filename="../game_list_frame.cpp" line="108"/>
<source>Never Played</source> <source>Never Played</source>
<translation>Never Played</translation> <translation>Nuk është luajtur kurrë</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility is untested</source>
<translation>Përputhshmëria nuk është e testuar</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game does not initialize properly / crashes the emulator</source>
<translation>Loja nuk niset siç duhet / rrëzon emulatorin</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game boots, but only displays a blank screen</source>
<translation>Loja niset, por shfaq vetëm një ekran zbrazët</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game displays an image but does not go past the menu</source>
<translation>Loja shfaq një imazh, por nuk kalon përtej menysë</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game has game-breaking glitches or unplayable performance</source>
<translation>Loja ka probleme kritike ose performancë papërshtatshme për lojë</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game can be completed with playable performance and no major glitches</source>
<translation>Loja mund përfundohet me performancë luajtshme dhe pa probleme mëdha</translation>
</message> </message>
</context> </context>
<context> <context>

View File

@ -182,8 +182,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="196"/> <location filename="../gui_context_menus.h" line="196"/>
<source>Shortcut created successfully!\n %1</source> <source>Shortcut created successfully!</source>
<translation>Kısayol başarıyla oluşturuldu!\n %1</translation> <translation>Kısayol başarıyla oluşturuldu!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="199"/> <location filename="../gui_context_menus.h" line="199"/>
@ -192,8 +192,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="200"/> <location filename="../gui_context_menus.h" line="200"/>
<source>Error creating shortcut!\n %1</source> <source>Error creating shortcut!</source>
<translation>Kısayol oluşturulurken hata oluştu!\n %1</translation> <translation>Kısayol oluşturulurken hata oluştu!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="275"/> <location filename="../gui_context_menus.h" line="275"/>
@ -672,11 +672,36 @@
<source>GUI Settings</source> <source>GUI Settings</source>
<translation>GUI Ayarları</translation> <translation>GUI Ayarları</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui" line="475"/>
<source>Disable Trophy Pop-ups</source>
<translation>Disable Trophy Pop-ups</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="375"/> <location filename="../settings_dialog.ui" line="375"/>
<source>Play title music</source> <source>Play title music</source>
<translation>Başlık müziğini çal</translation> <translation>Başlık müziğini çal</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database On Startup</source>
<translation>Update Compatibility Database On Startup</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Game Compatibility</source>
<translation>Game Compatibility</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Display Compatibility Data</source>
<translation>Display Compatibility Data</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database</source>
<translation>Update Compatibility Database</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="394"/> <location filename="../settings_dialog.ui" line="394"/>
<source>Volume</source> <source>Volume</source>
@ -1201,6 +1226,11 @@
<source>GUIgroupBox</source> <source>GUIgroupBox</source>
<translation>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.</translation> <translation>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.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp" line="267"/>
<source>disableTrophycheckBox</source>
<translation>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).</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="450"/> <location filename="../settings_dialog.cpp" line="450"/>
<source>hideCursorGroupBox</source> <source>hideCursorGroupBox</source>
@ -1216,6 +1246,21 @@
<source>backButtonBehaviorGroupBox</source> <source>backButtonBehaviorGroupBox</source>
<translation>Geri düğmesi davranışı:\nKontrol cihazındaki geri düğmesini, PS4'ün dokunmatik panelindeki belirlenen noktaya dokunmak için ayarlar.</translation> <translation>Geri düğmesi davranışı:\nKontrol cihazındaki geri düğmesini, PS4'ün dokunmatik panelindeki belirlenen noktaya dokunmak için ayarlar.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>enableCompatibilityCheckBox</source>
<translation>Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>checkCompatibilityOnStartupCheckBox</source>
<translation>Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>updateCompatibilityButton</source>
<translation>Update Compatibility Database:\nImmediately update the compatibility database.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="70"/> <location filename="../settings_dialog.cpp" line="70"/>
<source>Never</source> <source>Never</source>
@ -1329,6 +1374,11 @@
<source>Serial</source> <source>Serial</source>
<translation>Seri Numarası</translation> <translation>Seri Numarası</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility</source>
<translation>Compatibility</translation>
</message>
<message> <message>
<location filename="../game_list_frame.cpp" line="34"/> <location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source> <source>Region</source>
@ -1364,6 +1414,36 @@
<source>Never Played</source> <source>Never Played</source>
<translation>Never Played</translation> <translation>Never Played</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility is untested</source>
<translation>Compatibility is untested</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game does not initialize properly / crashes the emulator</source>
<translation>Game does not initialize properly / crashes the emulator</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game boots, but only displays a blank screen</source>
<translation>Game boots, but only displays a blank screen</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game displays an image but does not go past the menu</source>
<translation>Game displays an image but does not go past the menu</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game has game-breaking glitches or unplayable performance</source>
<translation>Game has game-breaking glitches or unplayable performance</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game can be completed with playable performance and no major glitches</source>
<translation>Game can be completed with playable performance and no major glitches</translation>
</message>
</context> </context>
<context> <context>
<name>CheckUpdate</name> <name>CheckUpdate</name>
@ -1493,4 +1573,4 @@
<translation>Güncelleme betiği dosyası oluşturulamadı</translation> <translation>Güncelleme betiği dosyası oluşturulamadı</translation>
</message> </message>
</context> </context>
</TS> </TS>

View File

@ -182,8 +182,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="196"/> <location filename="../gui_context_menus.h" line="196"/>
<source>Shortcut created successfully!\n %1</source> <source>Shortcut created successfully!</source>
<translation>Ярлик створений успішно!\n %1</translation> <translation>Ярлик створений успішно!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="199"/> <location filename="../gui_context_menus.h" line="199"/>
@ -192,8 +192,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="200"/> <location filename="../gui_context_menus.h" line="200"/>
<source>Error creating shortcut!\n %1</source> <source>Error creating shortcut!</source>
<translation>Помилка при створенні ярлика!\n %1</translation> <translation>Помилка при створенні ярлика!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="275"/> <location filename="../gui_context_menus.h" line="275"/>
@ -672,11 +672,36 @@
<source>GUI Settings</source> <source>GUI Settings</source>
<translation>Інтерфейс</translation> <translation>Інтерфейс</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui" line="475"/>
<source>Disable Trophy Pop-ups</source>
<translation>Disable Trophy Pop-ups</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="375"/> <location filename="../settings_dialog.ui" line="375"/>
<source>Play title music</source> <source>Play title music</source>
<translation>Програвати заголовну музику</translation> <translation>Програвати заголовну музику</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database On Startup</source>
<translation>Update Compatibility Database On Startup</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Game Compatibility</source>
<translation>Game Compatibility</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Display Compatibility Data</source>
<translation>Display Compatibility Data</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database</source>
<translation>Update Compatibility Database</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="394"/> <location filename="../settings_dialog.ui" line="394"/>
<source>Volume</source> <source>Volume</source>
@ -1201,6 +1226,11 @@
<source>GUIgroupBox</source> <source>GUIgroupBox</source>
<translation>Грати заголовну музику:\nВмикає відтворення спеціальної музики під час вибору гри в списку, якщо вона це підтримує.</translation> <translation>Грати заголовну музику:\nВмикає відтворення спеціальної музики під час вибору гри в списку, якщо вона це підтримує.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp" line="267"/>
<source>disableTrophycheckBox</source>
<translation>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).</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="450"/> <location filename="../settings_dialog.cpp" line="450"/>
<source>hideCursorGroupBox</source> <source>hideCursorGroupBox</source>
@ -1216,6 +1246,21 @@
<source>backButtonBehaviorGroupBox</source> <source>backButtonBehaviorGroupBox</source>
<translation>Поведінка кнопки «Назад»:\nНалаштовує кнопку «Назад» контролера на емуляцію натискання на зазначену область на сенсорній панелі контролера PS4.</translation> <translation>Поведінка кнопки «Назад»:\nНалаштовує кнопку «Назад» контролера на емуляцію натискання на зазначену область на сенсорній панелі контролера PS4.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>enableCompatibilityCheckBox</source>
<translation>Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>checkCompatibilityOnStartupCheckBox</source>
<translation>Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>updateCompatibilityButton</source>
<translation>Update Compatibility Database:\nImmediately update the compatibility database.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="70"/> <location filename="../settings_dialog.cpp" line="70"/>
<source>Never</source> <source>Never</source>
@ -1329,6 +1374,11 @@
<source>Serial</source> <source>Serial</source>
<translation>Серійний номер</translation> <translation>Серійний номер</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility</source>
<translation>Compatibility</translation>
</message>
<message> <message>
<location filename="../game_list_frame.cpp" line="34"/> <location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source> <source>Region</source>
@ -1364,6 +1414,36 @@
<source>Never Played</source> <source>Never Played</source>
<translation>Never Played</translation> <translation>Never Played</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility is untested</source>
<translation>Compatibility is untested</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game does not initialize properly / crashes the emulator</source>
<translation>Game does not initialize properly / crashes the emulator</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game boots, but only displays a blank screen</source>
<translation>Game boots, but only displays a blank screen</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game displays an image but does not go past the menu</source>
<translation>Game displays an image but does not go past the menu</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game has game-breaking glitches or unplayable performance</source>
<translation>Game has game-breaking glitches or unplayable performance</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game can be completed with playable performance and no major glitches</source>
<translation>Game can be completed with playable performance and no major glitches</translation>
</message>
</context> </context>
<context> <context>
<name>CheckUpdate</name> <name>CheckUpdate</name>

View File

@ -182,8 +182,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="196"/> <location filename="../gui_context_menus.h" line="196"/>
<source>Shortcut created successfully!\n %1</source> <source>Shortcut created successfully!</source>
<translation>Shortcut created successfully!\n %1</translation> <translation>Shortcut created successfully!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="199"/> <location filename="../gui_context_menus.h" line="199"/>
@ -192,8 +192,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="200"/> <location filename="../gui_context_menus.h" line="200"/>
<source>Error creating shortcut!\n %1</source> <source>Error creating shortcut!</source>
<translation>Error creating shortcut!\n %1</translation> <translation>Error creating shortcut!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="275"/> <location filename="../gui_context_menus.h" line="275"/>
@ -672,11 +672,36 @@
<source>GUI Settings</source> <source>GUI Settings</source>
<translation>Cài đt GUI</translation> <translation>Cài đt GUI</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui" line="475"/>
<source>Disable Trophy Pop-ups</source>
<translation>Disable Trophy Pop-ups</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="375"/> <location filename="../settings_dialog.ui" line="375"/>
<source>Play title music</source> <source>Play title music</source>
<translation>Phát nhạc tiêu đ</translation> <translation>Phát nhạc tiêu đ</translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database On Startup</source>
<translation>Update Compatibility Database On Startup</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Game Compatibility</source>
<translation>Game Compatibility</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Display Compatibility Data</source>
<translation>Display Compatibility Data</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database</source>
<translation>Update Compatibility Database</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="394"/> <location filename="../settings_dialog.ui" line="394"/>
<source>Volume</source> <source>Volume</source>
@ -1201,6 +1226,11 @@
<source>GUIgroupBox</source> <source>GUIgroupBox</source>
<translation>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.</translation> <translation>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.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp" line="267"/>
<source>disableTrophycheckBox</source>
<translation>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).</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="450"/> <location filename="../settings_dialog.cpp" line="450"/>
<source>hideCursorGroupBox</source> <source>hideCursorGroupBox</source>
@ -1216,6 +1246,21 @@
<source>backButtonBehaviorGroupBox</source> <source>backButtonBehaviorGroupBox</source>
<translation>Hành vi nút quay lại:\nĐặt nút quay lại của tay cầm đ phỏng việc chạm vào vị trí đã chỉ đnh trên touchpad của PS4.</translation> <translation>Hành vi nút quay lại:\nĐặt nút quay lại của tay cầm đ phỏng việc chạm vào vị trí đã chỉ đnh trên touchpad của PS4.</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>enableCompatibilityCheckBox</source>
<translation>Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>checkCompatibilityOnStartupCheckBox</source>
<translation>Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>updateCompatibilityButton</source>
<translation>Update Compatibility Database:\nImmediately update the compatibility database.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="70"/> <location filename="../settings_dialog.cpp" line="70"/>
<source>Never</source> <source>Never</source>
@ -1329,6 +1374,11 @@
<source>Serial</source> <source>Serial</source>
<translation>Số seri</translation> <translation>Số seri</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility</source>
<translation>Compatibility</translation>
</message>
<message> <message>
<location filename="../game_list_frame.cpp" line="34"/> <location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source> <source>Region</source>
@ -1364,6 +1414,36 @@
<source>Never Played</source> <source>Never Played</source>
<translation>Never Played</translation> <translation>Never Played</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility is untested</source>
<translation>Compatibility is untested</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game does not initialize properly / crashes the emulator</source>
<translation>Game does not initialize properly / crashes the emulator</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game boots, but only displays a blank screen</source>
<translation>Game boots, but only displays a blank screen</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game displays an image but does not go past the menu</source>
<translation>Game displays an image but does not go past the menu</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game has game-breaking glitches or unplayable performance</source>
<translation>Game has game-breaking glitches or unplayable performance</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game can be completed with playable performance and no major glitches</source>
<translation>Game can be completed with playable performance and no major glitches</translation>
</message>
</context> </context>
<context> <context>
<name>CheckUpdate</name> <name>CheckUpdate</name>

View File

@ -182,8 +182,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="196"/> <location filename="../gui_context_menus.h" line="196"/>
<source>Shortcut created successfully!\n %1</source> <source>Shortcut created successfully!</source>
<translation>!\n %1</translation> <translation>!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="199"/> <location filename="../gui_context_menus.h" line="199"/>
@ -192,8 +192,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="200"/> <location filename="../gui_context_menus.h" line="200"/>
<source>Error creating shortcut!\n %1</source> <source>Error creating shortcut!</source>
<translation>!\n %1</translation> <translation>!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="275"/> <location filename="../gui_context_menus.h" line="275"/>
@ -672,11 +672,36 @@
<source>GUI Settings</source> <source>GUI Settings</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui" line="475"/>
<source>Disable Trophy Pop-ups</source>
<translation>Disable Trophy Pop-ups</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="375"/> <location filename="../settings_dialog.ui" line="375"/>
<source>Play title music</source> <source>Play title music</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database On Startup</source>
<translation>Update Compatibility Database On Startup</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Game Compatibility</source>
<translation>Game Compatibility</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Display Compatibility Data</source>
<translation>Display Compatibility Data</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database</source>
<translation>Update Compatibility Database</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="394"/> <location filename="../settings_dialog.ui" line="394"/>
<source>Volume</source> <source>Volume</source>
@ -1201,6 +1226,11 @@
<source>GUIgroupBox</source> <source>GUIgroupBox</source>
<translation>:\n如果游戏支持</translation> <translation>:\n如果游戏支持</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp" line="267"/>
<source>disableTrophycheckBox</source>
<translation>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).</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="450"/> <location filename="../settings_dialog.cpp" line="450"/>
<source>hideCursorGroupBox</source> <source>hideCursorGroupBox</source>
@ -1216,6 +1246,21 @@
<source>backButtonBehaviorGroupBox</source> <source>backButtonBehaviorGroupBox</source>
<translation>:\n设置控制器的返回按钮以模拟在 PS4 </translation> <translation>:\n设置控制器的返回按钮以模拟在 PS4 </translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>enableCompatibilityCheckBox</source>
<translation>Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>checkCompatibilityOnStartupCheckBox</source>
<translation>Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>updateCompatibilityButton</source>
<translation>Update Compatibility Database:\nImmediately update the compatibility database.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="70"/> <location filename="../settings_dialog.cpp" line="70"/>
<source>Never</source> <source>Never</source>
@ -1329,6 +1374,11 @@
<source>Serial</source> <source>Serial</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility</source>
<translation>Compatibility</translation>
</message>
<message> <message>
<location filename="../game_list_frame.cpp" line="34"/> <location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source> <source>Region</source>
@ -1364,6 +1414,36 @@
<source>Never Played</source> <source>Never Played</source>
<translation>Never Played</translation> <translation>Never Played</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility is untested</source>
<translation>Compatibility is untested</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game does not initialize properly / crashes the emulator</source>
<translation>Game does not initialize properly / crashes the emulator</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game boots, but only displays a blank screen</source>
<translation>Game boots, but only displays a blank screen</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game displays an image but does not go past the menu</source>
<translation>Game displays an image but does not go past the menu</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game has game-breaking glitches or unplayable performance</source>
<translation>Game has game-breaking glitches or unplayable performance</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game can be completed with playable performance and no major glitches</source>
<translation>Game can be completed with playable performance and no major glitches</translation>
</message>
</context> </context>
<context> <context>
<name>CheckUpdate</name> <name>CheckUpdate</name>
@ -1493,4 +1573,4 @@
<translation></translation> <translation></translation>
</message> </message>
</context> </context>
</TS> </TS>

View File

@ -182,8 +182,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="196"/> <location filename="../gui_context_menus.h" line="196"/>
<source>Shortcut created successfully!\n %1</source> <source>Shortcut created successfully!</source>
<translation>Shortcut created successfully!\n %1</translation> <translation>Shortcut created successfully!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="199"/> <location filename="../gui_context_menus.h" line="199"/>
@ -192,8 +192,8 @@
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="200"/> <location filename="../gui_context_menus.h" line="200"/>
<source>Error creating shortcut!\n %1</source> <source>Error creating shortcut!</source>
<translation>Error creating shortcut!\n %1</translation> <translation>Error creating shortcut!</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="275"/> <location filename="../gui_context_menus.h" line="275"/>
@ -672,11 +672,36 @@
<source>GUI Settings</source> <source>GUI Settings</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui" line="475"/>
<source>Disable Trophy Pop-ups</source>
<translation>Disable Trophy Pop-ups</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="375"/> <location filename="../settings_dialog.ui" line="375"/>
<source>Play title music</source> <source>Play title music</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database On Startup</source>
<translation>Update Compatibility Database On Startup</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Game Compatibility</source>
<translation>Game Compatibility</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Display Compatibility Data</source>
<translation>Display Compatibility Data</translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database</source>
<translation>Update Compatibility Database</translation>
</message>
<message> <message>
<location filename="../settings_dialog.ui" line="394"/> <location filename="../settings_dialog.ui" line="394"/>
<source>Volume</source> <source>Volume</source>
@ -1201,6 +1226,11 @@
<source>GUIgroupBox</source> <source>GUIgroupBox</source>
<translation>:\n如果遊戲支持GUI中選擇遊戲時播放特殊音樂</translation> <translation>:\n如果遊戲支持GUI中選擇遊戲時播放特殊音樂</translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp" line="267"/>
<source>disableTrophycheckBox</source>
<translation>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).</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="450"/> <location filename="../settings_dialog.cpp" line="450"/>
<source>hideCursorGroupBox</source> <source>hideCursorGroupBox</source>
@ -1216,6 +1246,21 @@
<source>backButtonBehaviorGroupBox</source> <source>backButtonBehaviorGroupBox</source>
<translation>:\n設定控制器的返回按鈕模擬在 PS4 </translation> <translation>:\n設定控制器的返回按鈕模擬在 PS4 </translation>
</message> </message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>enableCompatibilityCheckBox</source>
<translation>Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>checkCompatibilityOnStartupCheckBox</source>
<translation>Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts.</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>updateCompatibilityButton</source>
<translation>Update Compatibility Database:\nImmediately update the compatibility database.</translation>
</message>
<message> <message>
<location filename="../settings_dialog.cpp" line="70"/> <location filename="../settings_dialog.cpp" line="70"/>
<source>Never</source> <source>Never</source>
@ -1329,6 +1374,11 @@
<source>Serial</source> <source>Serial</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility</source>
<translation>Compatibility</translation>
</message>
<message> <message>
<location filename="../game_list_frame.cpp" line="34"/> <location filename="../game_list_frame.cpp" line="34"/>
<source>Region</source> <source>Region</source>
@ -1364,6 +1414,36 @@
<source>Never Played</source> <source>Never Played</source>
<translation>Never Played</translation> <translation>Never Played</translation>
</message> </message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility is untested</source>
<translation>Compatibility is untested</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game does not initialize properly / crashes the emulator</source>
<translation>Game does not initialize properly / crashes the emulator</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game boots, but only displays a blank screen</source>
<translation>Game boots, but only displays a blank screen</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game displays an image but does not go past the menu</source>
<translation>Game displays an image but does not go past the menu</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game has game-breaking glitches or unplayable performance</source>
<translation>Game has game-breaking glitches or unplayable performance</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game can be completed with playable performance and no major glitches</source>
<translation>Game can be completed with playable performance and no major glitches</translation>
</message>
</context> </context>
<context> <context>
<name>CheckUpdate</name> <name>CheckUpdate</name>

View File

@ -1,5 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <span> #include <span>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>

View File

@ -168,22 +168,6 @@ Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords,
return texture.is_integer ? ctx.OpBitcast(ctx.F32[4], texels) : texels; return texture.is_integer ? ctx.OpBitcast(ctx.F32[4], texels) : texels;
} }
Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id lod,
const IR::Value& offset, Id ms) {
const auto& texture = ctx.images[handle & 0xFFFF];
const Id image = ctx.OpLoad(texture.image_type, texture.id);
const Id result_type = texture.data_types->Get(4);
ImageOperands operands;
operands.AddOffset(ctx, offset);
operands.Add(spv::ImageOperandsMask::Lod, lod);
operands.Add(spv::ImageOperandsMask::Sample, ms);
const Id texel =
texture.is_storage
? ctx.OpImageRead(result_type, image, coords, operands.mask, operands.operands)
: ctx.OpImageFetch(result_type, image, coords, operands.mask, operands.operands);
return texture.is_integer ? ctx.OpBitcast(ctx.F32[4], texel) : texel;
}
Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, u32 handle, Id lod, bool has_mips) { Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, u32 handle, Id lod, bool has_mips) {
const auto& texture = ctx.images[handle & 0xFFFF]; const auto& texture = ctx.images[handle & 0xFFFF];
const Id image = ctx.OpLoad(texture.image_type, texture.id); const Id image = ctx.OpLoad(texture.image_type, texture.id);
@ -236,15 +220,34 @@ Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id
return texture.is_integer ? ctx.OpBitcast(ctx.F32[4], sample) : sample; return texture.is_integer ? ctx.OpBitcast(ctx.F32[4], sample) : sample;
} }
Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id lod) { Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id lod, Id ms) {
UNREACHABLE_MSG("SPIR-V Instruction");
}
void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id lod, Id color) {
const auto& texture = ctx.images[handle & 0xFFFF]; const auto& texture = ctx.images[handle & 0xFFFF];
const Id image = ctx.OpLoad(texture.image_type, texture.id); const Id image = ctx.OpLoad(texture.image_type, texture.id);
const Id color_type = texture.data_types->Get(4); const Id color_type = texture.data_types->Get(4);
ImageOperands operands; ImageOperands operands;
operands.Add(spv::ImageOperandsMask::Sample, ms);
Id texel;
if (!texture.is_storage) {
operands.Add(spv::ImageOperandsMask::Lod, lod);
texel = ctx.OpImageFetch(color_type, image, coords, operands.mask, operands.operands);
} else {
if (ctx.profile.supports_image_load_store_lod) {
operands.Add(spv::ImageOperandsMask::Lod, lod);
} else if (Sirit::ValidId(lod)) {
LOG_WARNING(Render, "Image read with LOD not supported by driver");
}
texel = ctx.OpImageRead(color_type, image, coords, operands.mask, operands.operands);
}
return !texture.is_integer ? ctx.OpBitcast(ctx.U32[4], texel) : texel;
}
void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id lod, Id ms,
Id color) {
const auto& texture = ctx.images[handle & 0xFFFF];
const Id image = ctx.OpLoad(texture.image_type, texture.id);
const Id color_type = texture.data_types->Get(4);
ImageOperands operands;
operands.Add(spv::ImageOperandsMask::Sample, ms);
if (ctx.profile.supports_image_load_store_lod) { if (ctx.profile.supports_image_load_store_lod) {
operands.Add(spv::ImageOperandsMask::Lod, lod); operands.Add(spv::ImageOperandsMask::Lod, lod);
} else if (Sirit::ValidId(lod)) { } else if (Sirit::ValidId(lod)) {

View File

@ -395,14 +395,13 @@ Id EmitImageGather(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords,
const IR::Value& offset); const IR::Value& offset);
Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords,
const IR::Value& offset, Id dref); const IR::Value& offset, Id dref);
Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id lod,
const IR::Value& offset, Id ms);
Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, u32 handle, Id lod, bool skip_mips); Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, u32 handle, Id lod, bool skip_mips);
Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords); Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords);
Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id derivatives_dx, Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id derivatives_dx,
Id derivatives_dy, const IR::Value& offset, const IR::Value& lod_clamp); Id derivatives_dy, const IR::Value& offset, const IR::Value& lod_clamp);
Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id lod); Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id lod, Id ms);
void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id lod, Id color); void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id lod, Id ms,
Id color);
Id EmitImageAtomicIAdd32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id value); Id EmitImageAtomicIAdd32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id value);
Id EmitImageAtomicSMin32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id value); Id EmitImageAtomicSMin32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id value);

View File

@ -0,0 +1,329 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <sirit/sirit.h>
#include "shader_recompiler/backend/spirv/emit_spirv_quad_rect.h"
#include "shader_recompiler/runtime_info.h"
namespace Shader::Backend::SPIRV {
using Sirit::Id;
constexpr u32 SPIRV_VERSION_1_5 = 0x00010500;
struct QuadRectListEmitter : public Sirit::Module {
explicit QuadRectListEmitter(const FragmentRuntimeInfo& fs_info_)
: Sirit::Module{SPIRV_VERSION_1_5}, fs_info{fs_info_}, inputs{fs_info_.num_inputs},
outputs{fs_info_.num_inputs} {
void_id = TypeVoid();
bool_id = TypeBool();
float_id = TypeFloat(32);
uint_id = TypeUInt(32U);
int_id = TypeInt(32U, true);
bvec2_id = TypeVector(bool_id, 2);
vec2_id = TypeVector(float_id, 2);
vec3_id = TypeVector(float_id, 3);
vec4_id = TypeVector(float_id, 4);
float_one = Constant(float_id, 1.0f);
float_min_one = Constant(float_id, -1.0f);
int_zero = Constant(int_id, 0);
const Id float_arr{TypeArray(float_id, Constant(uint_id, 1U))};
gl_per_vertex_type = TypeStruct(vec4_id, float_id, float_arr, float_arr);
Decorate(gl_per_vertex_type, spv::Decoration::Block);
MemberDecorate(gl_per_vertex_type, 0U, spv::Decoration::BuiltIn,
static_cast<u32>(spv::BuiltIn::Position));
MemberDecorate(gl_per_vertex_type, 1U, spv::Decoration::BuiltIn,
static_cast<u32>(spv::BuiltIn::PointSize));
MemberDecorate(gl_per_vertex_type, 2U, spv::Decoration::BuiltIn,
static_cast<u32>(spv::BuiltIn::ClipDistance));
MemberDecorate(gl_per_vertex_type, 3U, spv::Decoration::BuiltIn,
static_cast<u32>(spv::BuiltIn::CullDistance));
}
/// Emits tessellation control shader for interpolating the 4th vertex of rectange primitive
void EmitRectListTCS() {
DefineEntry(spv::ExecutionModel::TessellationControl);
// Set passthrough tessellation factors
const Id output_float_id{TypePointer(spv::StorageClass::Output, float_id)};
for (int i = 0; i < 4; i++) {
const Id ptr{OpAccessChain(output_float_id, gl_tess_level_outer, Int(i))};
OpStore(ptr, float_one);
}
for (int i = 0; i < 2; i++) {
const Id ptr{OpAccessChain(output_float_id, gl_tess_level_inner, Int(i))};
OpStore(ptr, float_one);
}
const Id input_vec4{TypePointer(spv::StorageClass::Input, vec4_id)};
const Id output_vec4{TypePointer(spv::StorageClass::Output, vec4_id)};
// Emit interpolation block of the 4th vertex in rect.
// Load positions
std::array<Id, 3> pos;
for (int i = 0; i < 3; i++) {
pos[i] = OpLoad(vec4_id, OpAccessChain(input_vec4, gl_in, Int(i), int_zero));
}
std::array<Id, 3> point_coord_equal;
for (int i = 0; i < 3; i++) {
// point_coord_equal[i] = equal(gl_in[i].gl_Position.xy, gl_in[(i + 1) %
// 3].gl_Position.xy);
const Id pos_l_xy{OpVectorShuffle(vec2_id, pos[i], pos[i], 0, 1)};
const Id pos_r_xy{OpVectorShuffle(vec2_id, pos[(i + 1) % 3], pos[(i + 1) % 3], 0, 1)};
point_coord_equal[i] = OpFOrdEqual(bvec2_id, pos_l_xy, pos_r_xy);
}
std::array<Id, 3> bary_coord;
std::array<Id, 3> is_edge_vertex;
for (int i = 0; i < 3; i++) {
// bool xy_equal = point_coord_equal[i].x && point_coord_equal[(i + 2) % 3].y;
const Id xy_equal{
OpLogicalAnd(bool_id, OpCompositeExtract(bool_id, point_coord_equal[i], 0),
OpCompositeExtract(bool_id, point_coord_equal[(i + 2) % 3], 1))};
// bool yx_equal = point_coord_equal[i].y && point_coord_equal[(i + 2) % 3].x;
const Id yx_equal{
OpLogicalAnd(bool_id, OpCompositeExtract(bool_id, point_coord_equal[i], 1),
OpCompositeExtract(bool_id, point_coord_equal[(i + 2) % 3], 0))};
// bary_coord[i] = (xy_equal || yx_equal) ? -1.f : 1.f;
is_edge_vertex[i] = OpLogicalOr(bool_id, xy_equal, yx_equal);
bary_coord[i] = OpSelect(float_id, is_edge_vertex[i], float_min_one, float_one);
}
const auto interpolate = [&](Id v0, Id v1, Id v2) {
// return v0 * bary_coord.x + v1 * bary_coord.y + v2 * bary_coord.z;
const Id p0{OpVectorTimesScalar(vec4_id, v0, bary_coord[0])};
const Id p1{OpVectorTimesScalar(vec4_id, v1, bary_coord[1])};
const Id p2{OpVectorTimesScalar(vec4_id, v2, bary_coord[2])};
return OpFAdd(vec4_id, p0, OpFAdd(vec4_id, p1, p2));
};
// int vertex_index_id = is_edge_vertex[1] ? 1 : (is_edge_vertex[2] ? 2 : 0);
Id vertex_index{OpSelect(int_id, is_edge_vertex[2], Int(2), Int(0))};
vertex_index = OpSelect(int_id, is_edge_vertex[1], Int(1), vertex_index);
// int index = (vertex_index_id + gl_InvocationID) % 3;
const Id invocation_id{OpLoad(int_id, gl_invocation_id)};
const Id invocation_3{OpIEqual(bool_id, invocation_id, Int(3))};
const Id index{OpSMod(int_id, OpIAdd(int_id, vertex_index, invocation_id), Int(3))};
// gl_out[gl_InvocationID].gl_Position = gl_InvocationID == 3 ? pos3 :
// gl_in[index].gl_Position;
const Id pos3{interpolate(pos[0], pos[1], pos[2])};
const Id in_ptr{OpAccessChain(input_vec4, gl_in, index, Int(0))};
const Id position{OpSelect(vec4_id, invocation_3, pos3, OpLoad(vec4_id, in_ptr))};
OpStore(OpAccessChain(output_vec4, gl_out, invocation_id, Int(0)), position);
// Set attributes
for (int i = 0; i < inputs.size(); i++) {
// vec4 in_paramN3 = interpolate(bary_coord, in_paramN[0], in_paramN[1], in_paramN[2]);
const Id v0{OpLoad(vec4_id, OpAccessChain(input_vec4, inputs[i], Int(0)))};
const Id v1{OpLoad(vec4_id, OpAccessChain(input_vec4, inputs[i], Int(1)))};
const Id v2{OpLoad(vec4_id, OpAccessChain(input_vec4, inputs[i], Int(2)))};
const Id in_param3{interpolate(v0, v1, v2)};
// out_paramN[gl_InvocationID] = gl_InvocationID == 3 ? in_paramN3 : in_paramN[index];
const Id in_param{OpLoad(vec4_id, OpAccessChain(input_vec4, inputs[i], index))};
const Id out_param{OpSelect(vec4_id, invocation_3, in_param3, in_param)};
OpStore(OpAccessChain(output_vec4, outputs[i], invocation_id), out_param);
}
OpReturn();
OpFunctionEnd();
}
/// Emits a passthrough quad tessellation control shader that outputs 4 control points.
void EmitQuadListTCS() {
DefineEntry(spv::ExecutionModel::TessellationControl);
const Id array_type{TypeArray(int_id, Int(4))};
const Id values{ConstantComposite(array_type, Int(1), Int(2), Int(0), Int(3))};
const Id indices{AddLocalVariable(TypePointer(spv::StorageClass::Function, array_type),
spv::StorageClass::Function, values)};
// Set passthrough tessellation factors
const Id output_float{TypePointer(spv::StorageClass::Output, float_id)};
for (int i = 0; i < 4; i++) {
const Id ptr{OpAccessChain(output_float, gl_tess_level_outer, Int(i))};
OpStore(ptr, float_one);
}
for (int i = 0; i < 2; i++) {
const Id ptr{OpAccessChain(output_float, gl_tess_level_inner, Int(i))};
OpStore(ptr, float_one);
}
const Id input_vec4{TypePointer(spv::StorageClass::Input, vec4_id)};
const Id output_vec4{TypePointer(spv::StorageClass::Output, vec4_id)};
const Id func_int{TypePointer(spv::StorageClass::Function, int_id)};
const Id invocation_id{OpLoad(int_id, gl_invocation_id)};
const Id index{OpLoad(int_id, OpAccessChain(func_int, indices, invocation_id))};
// gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
const Id in_position{OpLoad(vec4_id, OpAccessChain(input_vec4, gl_in, index, Int(0)))};
OpStore(OpAccessChain(output_vec4, gl_out, invocation_id, Int(0)), in_position);
for (int i = 0; i < inputs.size(); i++) {
// out_paramN[gl_InvocationID] = in_paramN[gl_InvocationID];
const Id in_param{OpLoad(vec4_id, OpAccessChain(input_vec4, inputs[i], index))};
OpStore(OpAccessChain(output_vec4, outputs[i], invocation_id), in_param);
}
OpReturn();
OpFunctionEnd();
}
/// Emits a passthrough quad tessellation evaluation shader that outputs 4 control points.
void EmitPassthroughTES() {
DefineEntry(spv::ExecutionModel::TessellationEvaluation);
// const int index = int(gl_TessCoord.y) * 2 + int(gl_TessCoord.x);
const Id input_float{TypePointer(spv::StorageClass::Input, float_id)};
const Id tess_coord_x{OpLoad(float_id, OpAccessChain(input_float, gl_tess_coord, Int(0)))};
const Id tess_coord_y{OpLoad(float_id, OpAccessChain(input_float, gl_tess_coord, Int(1)))};
const Id index{OpIAdd(int_id, OpIMul(int_id, OpConvertFToS(int_id, tess_coord_y), Int(2)),
OpConvertFToS(int_id, tess_coord_x))};
// gl_Position = gl_in[index].gl_Position;
const Id input_vec4{TypePointer(spv::StorageClass::Input, vec4_id)};
const Id output_vec4{TypePointer(spv::StorageClass::Output, vec4_id)};
const Id position{OpLoad(vec4_id, OpAccessChain(input_vec4, gl_in, index, Int(0)))};
OpStore(OpAccessChain(output_vec4, gl_per_vertex, Int(0)), position);
// out_paramN = in_paramN[index];
for (int i = 0; i < inputs.size(); i++) {
const Id param{OpLoad(vec4_id, OpAccessChain(input_vec4, inputs[i], index))};
OpStore(outputs[i], param);
}
OpReturn();
OpFunctionEnd();
}
private:
Id Int(s32 value) {
return Constant(int_id, value);
}
Id AddInput(Id type) {
const Id input{AddGlobalVariable(TypePointer(spv::StorageClass::Input, type),
spv::StorageClass::Input)};
interfaces.push_back(input);
return input;
}
Id AddOutput(Id type) {
const Id output{AddGlobalVariable(TypePointer(spv::StorageClass::Output, type),
spv::StorageClass::Output)};
interfaces.push_back(output);
return output;
}
void DefineEntry(spv::ExecutionModel model) {
AddCapability(spv::Capability::Shader);
AddCapability(spv::Capability::Tessellation);
const Id void_function{TypeFunction(void_id)};
main = OpFunction(void_id, spv::FunctionControlMask::MaskNone, void_function);
if (model == spv::ExecutionModel::TessellationControl) {
AddExecutionMode(main, spv::ExecutionMode::OutputVertices, 4U);
} else {
AddExecutionMode(main, spv::ExecutionMode::Quads);
AddExecutionMode(main, spv::ExecutionMode::SpacingEqual);
AddExecutionMode(main, spv::ExecutionMode::VertexOrderCw);
}
DefineInputs(model);
DefineOutputs(model);
AddEntryPoint(model, main, "main", interfaces);
AddLabel(OpLabel());
}
void DefineOutputs(spv::ExecutionModel model) {
if (model == spv::ExecutionModel::TessellationControl) {
const Id gl_per_vertex_array{TypeArray(gl_per_vertex_type, Constant(uint_id, 4U))};
gl_out = AddOutput(gl_per_vertex_array);
const Id arr2_id{TypeArray(float_id, Constant(uint_id, 2U))};
gl_tess_level_inner = AddOutput(arr2_id);
Decorate(gl_tess_level_inner, spv::Decoration::BuiltIn, spv::BuiltIn::TessLevelInner);
Decorate(gl_tess_level_inner, spv::Decoration::Patch);
const Id arr4_id{TypeArray(float_id, Constant(uint_id, 4U))};
gl_tess_level_outer = AddOutput(arr4_id);
Decorate(gl_tess_level_outer, spv::Decoration::BuiltIn, spv::BuiltIn::TessLevelOuter);
Decorate(gl_tess_level_outer, spv::Decoration::Patch);
} else {
gl_per_vertex = AddOutput(gl_per_vertex_type);
}
for (int i = 0; i < fs_info.num_inputs; i++) {
outputs[i] = AddOutput(model == spv::ExecutionModel::TessellationControl
? TypeArray(vec4_id, Int(4))
: vec4_id);
Decorate(outputs[i], spv::Decoration::Location, fs_info.inputs[i].param_index);
}
}
void DefineInputs(spv::ExecutionModel model) {
if (model == spv::ExecutionModel::TessellationEvaluation) {
gl_tess_coord = AddInput(vec3_id);
Decorate(gl_tess_coord, spv::Decoration::BuiltIn, spv::BuiltIn::TessCoord);
} else {
gl_invocation_id = AddInput(int_id);
Decorate(gl_invocation_id, spv::Decoration::BuiltIn, spv::BuiltIn::InvocationId);
}
const Id gl_per_vertex_array{TypeArray(gl_per_vertex_type, Constant(uint_id, 32U))};
gl_in = AddInput(gl_per_vertex_array);
const Id float_arr{TypeArray(vec4_id, Int(32))};
for (int i = 0; i < fs_info.num_inputs; i++) {
inputs[i] = AddInput(float_arr);
Decorate(inputs[i], spv::Decoration::Location, fs_info.inputs[i].param_index);
}
}
private:
FragmentRuntimeInfo fs_info;
Id main;
Id void_id;
Id bool_id;
Id float_id;
Id uint_id;
Id int_id;
Id bvec2_id;
Id vec2_id;
Id vec3_id;
Id vec4_id;
Id float_one;
Id float_min_one;
Id int_zero;
Id gl_per_vertex_type;
Id gl_in;
union {
Id gl_out;
Id gl_per_vertex;
};
Id gl_tess_level_inner;
Id gl_tess_level_outer;
union {
Id gl_tess_coord;
Id gl_invocation_id;
};
std::vector<Id> inputs;
std::vector<Id> outputs;
std::vector<Id> interfaces;
};
std::vector<u32> EmitAuxilaryTessShader(AuxShaderType type, const FragmentRuntimeInfo& fs_info) {
QuadRectListEmitter ctx{fs_info};
switch (type) {
case AuxShaderType::RectListTCS:
ctx.EmitRectListTCS();
break;
case AuxShaderType::QuadListTCS:
ctx.EmitQuadListTCS();
break;
case AuxShaderType::PassthroughTES:
ctx.EmitPassthroughTES();
break;
}
return ctx.Assemble();
}
} // namespace Shader::Backend::SPIRV

View File

@ -0,0 +1,24 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <vector>
#include "common/types.h"
namespace Shader {
struct FragmentRuntimeInfo;
}
namespace Shader::Backend::SPIRV {
enum class AuxShaderType : u32 {
RectListTCS,
QuadListTCS,
PassthroughTES,
};
[[nodiscard]] std::vector<u32> EmitAuxilaryTessShader(AuxShaderType type,
const FragmentRuntimeInfo& fs_info);
} // namespace Shader::Backend::SPIRV

View File

@ -772,7 +772,7 @@ Id ImageType(EmitContext& ctx, const ImageResource& desc, Id sampled_type) {
const auto image = desc.GetSharp(ctx.info); const auto image = desc.GetSharp(ctx.info);
const auto format = desc.is_atomic ? GetFormat(image) : spv::ImageFormat::Unknown; const auto format = desc.is_atomic ? GetFormat(image) : spv::ImageFormat::Unknown;
const auto type = image.GetBoundType(); const auto type = image.GetBoundType();
const u32 sampled = desc.is_storage ? 2 : 1; const u32 sampled = desc.IsStorage(image) ? 2 : 1;
switch (type) { switch (type) {
case AmdGpu::ImageType::Color1D: case AmdGpu::ImageType::Color1D:
return ctx.TypeImage(sampled_type, spv::Dim::Dim1D, false, false, false, sampled, format); return ctx.TypeImage(sampled_type, spv::Dim::Dim1D, false, false, false, sampled, format);
@ -800,6 +800,7 @@ void EmitContext::DefineImagesAndSamplers() {
const auto sharp = image_desc.GetSharp(info); const auto sharp = image_desc.GetSharp(info);
const auto nfmt = sharp.GetNumberFmt(); const auto nfmt = sharp.GetNumberFmt();
const bool is_integer = AmdGpu::IsInteger(nfmt); const bool is_integer = AmdGpu::IsInteger(nfmt);
const bool is_storage = image_desc.IsStorage(sharp);
const VectorIds& data_types = GetAttributeType(*this, nfmt); const VectorIds& data_types = GetAttributeType(*this, nfmt);
const Id sampled_type = data_types[1]; const Id sampled_type = data_types[1];
const Id image_type{ImageType(*this, image_desc, sampled_type)}; const Id image_type{ImageType(*this, image_desc, sampled_type)};
@ -811,11 +812,11 @@ void EmitContext::DefineImagesAndSamplers() {
images.push_back({ images.push_back({
.data_types = &data_types, .data_types = &data_types,
.id = id, .id = id,
.sampled_type = image_desc.is_storage ? sampled_type : TypeSampledImage(image_type), .sampled_type = is_storage ? sampled_type : TypeSampledImage(image_type),
.pointer_type = pointer_type, .pointer_type = pointer_type,
.image_type = image_type, .image_type = image_type,
.is_integer = is_integer, .is_integer = is_integer,
.is_storage = image_desc.is_storage, .is_storage = is_storage,
}); });
interfaces.push_back(id); interfaces.push_back(id);
} }

View File

@ -1,7 +1,9 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "shader_recompiler/frontend/translate/translate.h" #include "shader_recompiler/frontend/translate/translate.h"
#include "shader_recompiler/ir/reg.h" #include "shader_recompiler/ir/reg.h"
#include "shader_recompiler/profile.h"
#include "shader_recompiler/runtime_info.h" #include "shader_recompiler/runtime_info.h"
namespace Shader::Gcn { namespace Shader::Gcn {
@ -203,6 +205,7 @@ void Translator::DS_WRITE(int bit_size, bool is_signed, bool is_pair, bool strid
addr, ir.Imm32((u32(inst.control.ds.offset1) << 8u) + u32(inst.control.ds.offset0))); addr, ir.Imm32((u32(inst.control.ds.offset1) << 8u) + u32(inst.control.ds.offset0)));
ir.WriteShared(bit_size, ir.GetVectorReg(data0), addr0); ir.WriteShared(bit_size, ir.GetVectorReg(data0), addr0);
} }
emit_ds_read_barrier = true;
} }
void Translator::DS_SWIZZLE_B32(const GcnInst& inst) { void Translator::DS_SWIZZLE_B32(const GcnInst& inst) {
@ -219,6 +222,11 @@ void Translator::DS_SWIZZLE_B32(const GcnInst& inst) {
void Translator::DS_READ(int bit_size, bool is_signed, bool is_pair, bool stride64, void Translator::DS_READ(int bit_size, bool is_signed, bool is_pair, bool stride64,
const GcnInst& inst) { const GcnInst& inst) {
if (emit_ds_read_barrier && profile.needs_lds_barriers) {
ir.Barrier();
emit_ds_read_barrier = false;
}
const IR::U32 addr{ir.GetVectorReg(IR::VectorReg(inst.src[0].code))}; const IR::U32 addr{ir.GetVectorReg(IR::VectorReg(inst.src[0].code))};
IR::VectorReg dst_reg{inst.dst[0].code}; IR::VectorReg dst_reg{inst.dst[0].code};
if (is_pair) { if (is_pair) {

View File

@ -306,6 +306,7 @@ private:
const RuntimeInfo& runtime_info; const RuntimeInfo& runtime_info;
const Profile& profile; const Profile& profile;
bool opcode_missing = false; bool opcode_missing = false;
bool emit_ds_read_barrier = false;
}; };
void Translate(IR::Block* block, u32 block_base, std::span<const GcnInst> inst_list, Info& info, void Translate(IR::Block* block, u32 block_base, std::span<const GcnInst> inst_list, Info& info,

View File

@ -420,13 +420,13 @@ void Translator::IMAGE_LOAD(bool has_mip, const GcnInst& inst) {
IR::TextureInstInfo info{}; IR::TextureInstInfo info{};
info.has_lod.Assign(has_mip); info.has_lod.Assign(has_mip);
const IR::Value texel = ir.ImageFetch(handle, body, {}, {}, {}, info); const IR::Value texel = ir.ImageRead(handle, body, {}, {}, info);
for (u32 i = 0; i < 4; i++) { for (u32 i = 0; i < 4; i++) {
if (((mimg.dmask >> i) & 1) == 0) { if (((mimg.dmask >> i) & 1) == 0) {
continue; continue;
} }
IR::F32 value = IR::F32{ir.CompositeExtract(texel, i)}; IR::U32 value = IR::U32{ir.CompositeExtract(texel, i)};
ir.SetVectorReg(dest_reg++, value); ir.SetVectorReg(dest_reg++, value);
} }
} }
@ -454,7 +454,7 @@ void Translator::IMAGE_STORE(bool has_mip, const GcnInst& inst) {
comps.push_back(ir.GetVectorReg<IR::F32>(data_reg++)); comps.push_back(ir.GetVectorReg<IR::F32>(data_reg++));
} }
const IR::Value value = ir.CompositeConstruct(comps[0], comps[1], comps[2], comps[3]); const IR::Value value = ir.CompositeConstruct(comps[0], comps[1], comps[2], comps[3]);
ir.ImageWrite(handle, body, {}, value, info); ir.ImageWrite(handle, body, {}, {}, value, info);
} }
void Translator::IMAGE_GET_RESINFO(const GcnInst& inst) { void Translator::IMAGE_GET_RESINFO(const GcnInst& inst) {

View File

@ -49,11 +49,11 @@ struct BufferResource {
u8 instance_attrib{}; u8 instance_attrib{};
bool is_written{}; bool is_written{};
bool IsStorage(AmdGpu::Buffer buffer) const noexcept { [[nodiscard]] bool IsStorage(const AmdGpu::Buffer& buffer) const noexcept {
return buffer.GetSize() > MaxUboSize || is_written || is_gds_buffer; return buffer.GetSize() > MaxUboSize || is_written || is_gds_buffer;
} }
constexpr AmdGpu::Buffer GetSharp(const Info& info) const noexcept; [[nodiscard]] constexpr AmdGpu::Buffer GetSharp(const Info& info) const noexcept;
}; };
using BufferResourceList = boost::container::small_vector<BufferResource, 16>; using BufferResourceList = boost::container::small_vector<BufferResource, 16>;
@ -61,18 +61,24 @@ struct TextureBufferResource {
u32 sharp_idx; u32 sharp_idx;
bool is_written{}; bool is_written{};
constexpr AmdGpu::Buffer GetSharp(const Info& info) const noexcept; [[nodiscard]] constexpr AmdGpu::Buffer GetSharp(const Info& info) const noexcept;
}; };
using TextureBufferResourceList = boost::container::small_vector<TextureBufferResource, 16>; using TextureBufferResourceList = boost::container::small_vector<TextureBufferResource, 16>;
struct ImageResource { struct ImageResource {
u32 sharp_idx; u32 sharp_idx;
bool is_storage{};
bool is_depth{}; bool is_depth{};
bool is_atomic{}; bool is_atomic{};
bool is_array{}; bool is_array{};
bool is_read{};
bool is_written{};
constexpr AmdGpu::Image GetSharp(const Info& info) const noexcept; [[nodiscard]] bool IsStorage(const AmdGpu::Image& image) const noexcept {
// Need cube as storage when used with ImageRead.
return is_written || (is_read && image.GetBoundType() == AmdGpu::ImageType::Cube);
}
[[nodiscard]] constexpr AmdGpu::Image GetSharp(const Info& info) const noexcept;
}; };
using ImageResourceList = boost::container::small_vector<ImageResource, 16>; using ImageResourceList = boost::container::small_vector<ImageResource, 16>;

View File

@ -1,74 +1,74 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include <optional> #include <optional>
#include <type_traits> #include <type_traits>
#include <boost/container/small_vector.hpp> #include <boost/container/small_vector.hpp>
#include <queue> #include <queue>
#include "shader_recompiler/ir/value.h" #include "shader_recompiler/ir/value.h"
namespace Shader::IR { namespace Shader::IR {
// Use typename Instruction so the function can be used to return either const or mutable // Use typename Instruction so the function can be used to return either const or mutable
// Insts depending on the context. // Insts depending on the context.
template <typename Instruction, typename Pred> template <typename Instruction, typename Pred>
auto BreadthFirstSearch(Instruction* inst, auto BreadthFirstSearch(Instruction* inst,
Pred&& pred) -> std::invoke_result_t<Pred, Instruction*> { Pred&& pred) -> std::invoke_result_t<Pred, Instruction*> {
// Most often case the instruction is the desired already. // Most often case the instruction is the desired already.
if (std::optional result = pred(inst)) { if (std::optional result = pred(inst)) {
return result; return result;
} }
// Breadth-first search visiting the right most arguments first // Breadth-first search visiting the right most arguments first
boost::container::small_vector<Instruction*, 2> visited; boost::container::small_vector<Instruction*, 2> visited;
std::queue<Instruction*> queue; std::queue<Instruction*> queue;
queue.push(inst); queue.push(inst);
while (!queue.empty()) { while (!queue.empty()) {
// Pop one instruction from the queue // Pop one instruction from the queue
Instruction* inst{queue.front()}; Instruction* inst{queue.front()};
queue.pop(); queue.pop();
if (std::optional result = pred(inst)) { if (std::optional result = pred(inst)) {
// This is the instruction we were looking for // This is the instruction we were looking for
return result; return result;
} }
// Visit the right most arguments first // Visit the right most arguments first
for (size_t arg = inst->NumArgs(); arg--;) { for (size_t arg = inst->NumArgs(); arg--;) {
Value arg_value{inst->Arg(arg)}; Value arg_value{inst->Arg(arg)};
if (arg_value.IsImmediate()) { if (arg_value.IsImmediate()) {
continue; continue;
} }
// Queue instruction if it hasn't been visited // Queue instruction if it hasn't been visited
Instruction* arg_inst{arg_value.InstRecursive()}; Instruction* arg_inst{arg_value.InstRecursive()};
if (std::ranges::find(visited, arg_inst) == visited.end()) { if (std::ranges::find(visited, arg_inst) == visited.end()) {
visited.push_back(arg_inst); visited.push_back(arg_inst);
queue.push(arg_inst); queue.push(arg_inst);
} }
} }
} }
// SSA tree has been traversed and the result hasn't been found // SSA tree has been traversed and the result hasn't been found
return std::nullopt; return std::nullopt;
} }
template <typename Pred> template <typename Pred>
auto BreadthFirstSearch(const Value& value, auto BreadthFirstSearch(const Value& value,
Pred&& pred) -> std::invoke_result_t<Pred, const Inst*> { Pred&& pred) -> std::invoke_result_t<Pred, const Inst*> {
if (value.IsImmediate()) { if (value.IsImmediate()) {
// Nothing to do with immediates // Nothing to do with immediates
return std::nullopt; return std::nullopt;
} }
return BreadthFirstSearch(value.InstRecursive(), pred); return BreadthFirstSearch(value.InstRecursive(), pred);
} }
template <typename Pred> template <typename Pred>
auto BreadthFirstSearch(Value value, Pred&& pred) -> std::invoke_result_t<Pred, Inst*> { auto BreadthFirstSearch(Value value, Pred&& pred) -> std::invoke_result_t<Pred, Inst*> {
if (value.IsImmediate()) { if (value.IsImmediate()) {
// Nothing to do with immediates // Nothing to do with immediates
return std::nullopt; return std::nullopt;
} }
return BreadthFirstSearch(value.InstRecursive(), pred); return BreadthFirstSearch(value.InstRecursive(), pred);
} }
} // namespace Shader::IR } // namespace Shader::IR

View File

@ -1630,11 +1630,6 @@ Value IREmitter::ImageGatherDref(const Value& handle, const Value& coords, const
return Inst(Opcode::ImageGatherDref, Flags{info}, handle, coords, offset, dref); return Inst(Opcode::ImageGatherDref, Flags{info}, handle, coords, offset, dref);
} }
Value IREmitter::ImageFetch(const Value& handle, const Value& coords, const U32& lod,
const Value& offset, const U32& multisampling, TextureInstInfo info) {
return Inst(Opcode::ImageFetch, Flags{info}, handle, coords, lod, offset, multisampling);
}
Value IREmitter::ImageQueryDimension(const Value& handle, const IR::U32& lod, Value IREmitter::ImageQueryDimension(const Value& handle, const IR::U32& lod,
const IR::U1& skip_mips) { const IR::U1& skip_mips) {
return Inst(Opcode::ImageQueryDimensions, handle, lod, skip_mips); return Inst(Opcode::ImageQueryDimensions, handle, lod, skip_mips);
@ -1657,13 +1652,13 @@ Value IREmitter::ImageGradient(const Value& handle, const Value& coords,
} }
Value IREmitter::ImageRead(const Value& handle, const Value& coords, const U32& lod, Value IREmitter::ImageRead(const Value& handle, const Value& coords, const U32& lod,
TextureInstInfo info) { const U32& multisampling, TextureInstInfo info) {
return Inst(Opcode::ImageRead, Flags{info}, handle, coords, lod); return Inst(Opcode::ImageRead, Flags{info}, handle, coords, lod, multisampling);
} }
void IREmitter::ImageWrite(const Value& handle, const Value& coords, const U32& lod, void IREmitter::ImageWrite(const Value& handle, const Value& coords, const U32& lod,
const Value& color, TextureInstInfo info) { const U32& multisampling, const Value& color, TextureInstInfo info) {
Inst(Opcode::ImageWrite, Flags{info}, handle, coords, lod, color); Inst(Opcode::ImageWrite, Flags{info}, handle, coords, lod, multisampling, color);
} }
// Debug print maps to SPIRV's NonSemantic DebugPrintf instruction // Debug print maps to SPIRV's NonSemantic DebugPrintf instruction

View File

@ -325,17 +325,14 @@ public:
TextureInstInfo info); TextureInstInfo info);
[[nodiscard]] Value ImageGatherDref(const Value& handle, const Value& coords, [[nodiscard]] Value ImageGatherDref(const Value& handle, const Value& coords,
const Value& offset, const F32& dref, TextureInstInfo info); const Value& offset, const F32& dref, TextureInstInfo info);
[[nodiscard]] Value ImageFetch(const Value& handle, const Value& coords, const U32& lod,
const Value& offset, const U32& multisampling,
TextureInstInfo info);
[[nodiscard]] Value ImageGradient(const Value& handle, const Value& coords, [[nodiscard]] Value ImageGradient(const Value& handle, const Value& coords,
const Value& derivatives_dx, const Value& derivatives_dy, const Value& derivatives_dx, const Value& derivatives_dy,
const Value& offset, const F32& lod_clamp, const Value& offset, const F32& lod_clamp,
TextureInstInfo info); TextureInstInfo info);
[[nodiscard]] Value ImageRead(const Value& handle, const Value& coords, const U32& lod, [[nodiscard]] Value ImageRead(const Value& handle, const Value& coords, const U32& lod,
TextureInstInfo info); const U32& multisampling, TextureInstInfo info);
void ImageWrite(const Value& handle, const Value& coords, const U32& lod, const Value& color, void ImageWrite(const Value& handle, const Value& coords, const U32& lod,
TextureInstInfo info); const U32& multisampling, const Value& color, TextureInstInfo info);
void EmitVertex(); void EmitVertex();
void EmitPrimitive(); void EmitPrimitive();

View File

@ -338,12 +338,11 @@ OPCODE(ImageSampleDrefImplicitLod, F32x4, Opaq
OPCODE(ImageSampleDrefExplicitLod, F32x4, Opaque, Opaque, F32, F32, Opaque, ) OPCODE(ImageSampleDrefExplicitLod, F32x4, Opaque, Opaque, F32, F32, Opaque, )
OPCODE(ImageGather, F32x4, Opaque, Opaque, Opaque, ) OPCODE(ImageGather, F32x4, Opaque, Opaque, Opaque, )
OPCODE(ImageGatherDref, F32x4, Opaque, Opaque, Opaque, F32, ) OPCODE(ImageGatherDref, F32x4, Opaque, Opaque, Opaque, F32, )
OPCODE(ImageFetch, F32x4, Opaque, Opaque, U32, Opaque, Opaque, )
OPCODE(ImageQueryDimensions, U32x4, Opaque, U32, U1, ) OPCODE(ImageQueryDimensions, U32x4, Opaque, U32, U1, )
OPCODE(ImageQueryLod, F32x4, Opaque, Opaque, ) OPCODE(ImageQueryLod, F32x4, Opaque, Opaque, )
OPCODE(ImageGradient, F32x4, Opaque, Opaque, Opaque, Opaque, Opaque, F32, ) OPCODE(ImageGradient, F32x4, Opaque, Opaque, Opaque, Opaque, Opaque, F32, )
OPCODE(ImageRead, U32x4, Opaque, Opaque, U32, ) OPCODE(ImageRead, U32x4, Opaque, Opaque, U32, U32, )
OPCODE(ImageWrite, Void, Opaque, Opaque, U32, U32x4, ) OPCODE(ImageWrite, Void, Opaque, Opaque, U32, U32, U32x4, )
// Image atomic operations // Image atomic operations
OPCODE(ImageAtomicIAdd32, U32, Opaque, Opaque, U32, ) OPCODE(ImageAtomicIAdd32, U32, Opaque, Opaque, U32, )

Some files were not shown because too many files have changed in this diff Show More