Merge remote-tracking branch 'origin/main'

This commit is contained in:
kalaposfos13 2024-12-26 09:40:29 +01:00
commit 7792fd0342
134 changed files with 8659 additions and 5279 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
@ -896,7 +899,8 @@ if (ENABLE_DISCORD_RPC)
target_compile_definitions(shadps4 PRIVATE ENABLE_DISCORD_RPC) target_compile_definitions(shadps4 PRIVATE ENABLE_DISCORD_RPC)
endif() endif()
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") # Optional due to https://github.com/shadps4-emu/shadPS4/issues/1704
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND ENABLE_USERFAULTFD)
target_compile_definitions(shadps4 PRIVATE ENABLE_USERFAULTFD) target_compile_definitions(shadps4 PRIVATE ENABLE_USERFAULTFD)
endif() endif()

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.

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
if (CMAKE_BUILD_TYPE STREQUAL "Release")
option(TRACY_ENABLE "" OFF)
else()
option(TRACY_ENABLE "" ON) 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

@ -34,6 +34,7 @@ namespace Config {
static bool isNeo = false; static bool isNeo = false;
static bool isFullscreen = false; static bool isFullscreen = false;
static bool playBGM = false; static bool playBGM = false;
static bool isTrophyPopupDisabled = false;
static int BGMvolume = 50; static int BGMvolume = 50;
static bool enableDiscordRPC = false; static bool enableDiscordRPC = false;
static u32 screenWidth = 1280; static u32 screenWidth = 1280;
@ -64,6 +65,8 @@ static bool vkCrashDiagnostic = false;
static s16 cursorState = HideCursorState::Idle; static s16 cursorState = HideCursorState::Idle;
static int cursorHideTimeout = 5; // 5 seconds (default) static int cursorHideTimeout = 5; // 5 seconds (default)
static bool separateupdatefolder = false; static bool separateupdatefolder = false;
static bool compatibilityData = false;
static bool checkCompatibilityOnStartup = false;
// Gui // Gui
std::vector<std::filesystem::path> settings_install_dirs = {}; std::vector<std::filesystem::path> settings_install_dirs = {};
@ -96,6 +99,10 @@ bool isFullscreenMode() {
return isFullscreen; return isFullscreen;
} }
bool getisTrophyPopupDisabled() {
return isTrophyPopupDisabled;
}
bool getPlayBGM() { bool getPlayBGM() {
return playBGM; return playBGM;
} }
@ -224,6 +231,14 @@ bool getSeparateUpdateEnabled() {
return separateupdatefolder; return separateupdatefolder;
} }
bool getCompatibilityEnabled() {
return compatibilityData;
}
bool getCheckCompatibilityOnStartup() {
return checkCompatibilityOnStartup;
}
void setGpuId(s32 selectedGpuId) { void setGpuId(s32 selectedGpuId) {
gpuId = selectedGpuId; gpuId = selectedGpuId;
} }
@ -284,6 +299,10 @@ void setFullscreenMode(bool enable) {
isFullscreen = enable; isFullscreen = enable;
} }
void setisTrophyPopupDisabled(bool disable) {
isTrophyPopupDisabled = disable;
}
void setPlayBGM(bool enable) { void setPlayBGM(bool enable) {
playBGM = enable; playBGM = enable;
} }
@ -344,6 +363,14 @@ void setSeparateUpdateEnabled(bool use) {
separateupdatefolder = use; separateupdatefolder = use;
} }
void setCompatibilityEnabled(bool use) {
compatibilityData = use;
}
void setCheckCompatibilityOnStartup(bool use) {
checkCompatibilityOnStartup = use;
}
void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h) { void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h) {
main_window_geometry_x = x; main_window_geometry_x = x;
main_window_geometry_y = y; main_window_geometry_y = y;
@ -531,6 +558,7 @@ void load(const std::filesystem::path& path) {
isNeo = toml::find_or<bool>(general, "isPS4Pro", false); isNeo = toml::find_or<bool>(general, "isPS4Pro", false);
isFullscreen = toml::find_or<bool>(general, "Fullscreen", false); isFullscreen = toml::find_or<bool>(general, "Fullscreen", false);
playBGM = toml::find_or<bool>(general, "playBGM", false); playBGM = toml::find_or<bool>(general, "playBGM", false);
isTrophyPopupDisabled = toml::find_or<bool>(general, "isTrophyPopupDisabled", false);
BGMvolume = toml::find_or<int>(general, "BGMvolume", 50); BGMvolume = toml::find_or<int>(general, "BGMvolume", 50);
enableDiscordRPC = toml::find_or<bool>(general, "enableDiscordRPC", true); enableDiscordRPC = toml::find_or<bool>(general, "enableDiscordRPC", true);
logFilter = toml::find_or<std::string>(general, "logFilter", ""); logFilter = toml::find_or<std::string>(general, "logFilter", "");
@ -544,6 +572,9 @@ void load(const std::filesystem::path& path) {
isShowSplash = toml::find_or<bool>(general, "showSplash", true); isShowSplash = toml::find_or<bool>(general, "showSplash", true);
isAutoUpdate = toml::find_or<bool>(general, "autoUpdate", false); isAutoUpdate = toml::find_or<bool>(general, "autoUpdate", false);
separateupdatefolder = toml::find_or<bool>(general, "separateUpdateEnabled", false); separateupdatefolder = toml::find_or<bool>(general, "separateUpdateEnabled", false);
compatibilityData = toml::find_or<bool>(general, "compatibilityEnabled", false);
checkCompatibilityOnStartup =
toml::find_or<bool>(general, "checkCompatibilityOnStartup", false);
} }
if (data.contains("Input")) { if (data.contains("Input")) {
@ -646,6 +677,7 @@ void save(const std::filesystem::path& path) {
data["General"]["isPS4Pro"] = isNeo; data["General"]["isPS4Pro"] = isNeo;
data["General"]["Fullscreen"] = isFullscreen; data["General"]["Fullscreen"] = isFullscreen;
data["General"]["isTrophyPopupDisabled"] = isTrophyPopupDisabled;
data["General"]["playBGM"] = playBGM; data["General"]["playBGM"] = playBGM;
data["General"]["BGMvolume"] = BGMvolume; data["General"]["BGMvolume"] = BGMvolume;
data["General"]["enableDiscordRPC"] = enableDiscordRPC; data["General"]["enableDiscordRPC"] = enableDiscordRPC;
@ -656,6 +688,8 @@ void save(const std::filesystem::path& path) {
data["General"]["showSplash"] = isShowSplash; data["General"]["showSplash"] = isShowSplash;
data["General"]["autoUpdate"] = isAutoUpdate; data["General"]["autoUpdate"] = isAutoUpdate;
data["General"]["separateUpdateEnabled"] = separateupdatefolder; data["General"]["separateUpdateEnabled"] = separateupdatefolder;
data["General"]["compatibilityEnabled"] = compatibilityData;
data["General"]["checkCompatibilityOnStartup"] = checkCompatibilityOnStartup;
data["Input"]["cursorState"] = cursorState; data["Input"]["cursorState"] = cursorState;
data["Input"]["cursorHideTimeout"] = cursorHideTimeout; data["Input"]["cursorHideTimeout"] = cursorHideTimeout;
data["Input"]["backButtonBehavior"] = backButtonBehavior; data["Input"]["backButtonBehavior"] = backButtonBehavior;
@ -740,6 +774,7 @@ void saveMainWindow(const std::filesystem::path& path) {
void setDefaultValues() { void setDefaultValues() {
isNeo = false; isNeo = false;
isFullscreen = false; isFullscreen = false;
isTrophyPopupDisabled = false;
playBGM = false; playBGM = false;
BGMvolume = 50; BGMvolume = 50;
enableDiscordRPC = true; enableDiscordRPC = true;
@ -775,6 +810,8 @@ void setDefaultValues() {
m_language = 1; m_language = 1;
gpuId = -1; gpuId = -1;
separateupdatefolder = false; separateupdatefolder = false;
compatibilityData = false;
checkCompatibilityOnStartup = false;
} }
constexpr std::string_view GetDefaultKeyboardConfig() { constexpr std::string_view GetDefaultKeyboardConfig() {

View File

@ -19,8 +19,11 @@ bool isNeoMode();
bool isFullscreenMode(); bool isFullscreenMode();
bool getPlayBGM(); bool getPlayBGM();
int getBGMvolume(); int getBGMvolume();
bool getisTrophyPopupDisabled();
bool getEnableDiscordRPC(); bool getEnableDiscordRPC();
bool getSeparateUpdateEnabled(); bool getSeparateUpdateEnabled();
bool getCompatibilityEnabled();
bool getCheckCompatibilityOnStartup();
std::string getLogFilter(); std::string getLogFilter();
std::string getLogType(); std::string getLogType();
@ -60,6 +63,7 @@ void setGpuId(s32 selectedGpuId);
void setScreenWidth(u32 width); void setScreenWidth(u32 width);
void setScreenHeight(u32 height); void setScreenHeight(u32 height);
void setFullscreenMode(bool enable); void setFullscreenMode(bool enable);
void setisTrophyPopupDisabled(bool disable);
void setPlayBGM(bool enable); void setPlayBGM(bool enable);
void setBGMvolume(int volume); void setBGMvolume(int volume);
void setEnableDiscordRPC(bool enable); void setEnableDiscordRPC(bool enable);
@ -69,6 +73,8 @@ void setUserName(const std::string& type);
void setUpdateChannel(const std::string& type); void setUpdateChannel(const std::string& type);
void setSeparateUpdateEnabled(bool use); void setSeparateUpdateEnabled(bool use);
void setGameInstallDirs(const std::vector<std::filesystem::path>& settings_install_dirs_config); void setGameInstallDirs(const std::vector<std::filesystem::path>& settings_install_dirs_config);
void setCompatibilityEnabled(bool use);
void setCheckCompatibilityOnStartup(bool use);
void setCursorState(s16 cursorState); void setCursorState(s16 cursorState);
void setCursorHideTimeout(int newcursorHideTimeout); void setCursorHideTimeout(int newcursorHideTimeout);

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

@ -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

@ -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

@ -9,7 +9,7 @@
#include "splash.h" #include "splash.h"
bool Splash::Open(const std::filesystem::path& filepath) { bool Splash::Open(const std::filesystem::path& filepath) {
ASSERT_MSG(filepath.stem().string() != "png", "Unexpected file format passed"); ASSERT_MSG(filepath.extension().string() == ".png", "Unexpected file format passed");
Common::FS::IOFile file(filepath, Common::FS::FileAccessMode::Read); Common::FS::IOFile file(filepath, Common::FS::FileAccessMode::Read);
if (!file.IsOpen()) { if (!file.IsOpen()) {

View File

@ -171,6 +171,9 @@ void HandleTable::DeleteHandle(int d) {
File* HandleTable::GetFile(int d) { File* HandleTable::GetFile(int d) {
std::scoped_lock lock{m_mutex}; std::scoped_lock lock{m_mutex};
if (d < 0 || d >= m_files.size()) {
return nullptr;
}
return m_files.at(d); return m_files.at(d);
} }

View File

@ -2,6 +2,8 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <memory> #include <memory>
#include <mutex>
#include <shared_mutex>
#include <magic_enum/magic_enum.hpp> #include <magic_enum/magic_enum.hpp>
#include "common/assert.h" #include "common/assert.h"
@ -13,7 +15,22 @@
namespace Libraries::AudioOut { namespace Libraries::AudioOut {
static std::unique_ptr<SDLAudioOut> audio; struct PortOut {
void* impl;
u32 samples_num;
u32 freq;
OrbisAudioOutParamFormat format;
OrbisAudioOutPort type;
int channels_num;
bool is_float;
std::array<int, 8> volume;
u8 sample_size;
bool is_open;
};
std::shared_mutex ports_mutex;
std::array<PortOut, SCE_AUDIO_OUT_NUM_PORTS> ports_out{};
static std::unique_ptr<AudioOutBackend> audio;
static std::string_view GetAudioOutPort(OrbisAudioOutPort port) { static std::string_view GetAudioOutPort(OrbisAudioOutPort port) {
switch (port) { switch (port) {
@ -70,6 +87,58 @@ static std::string_view GetAudioOutParamAttr(OrbisAudioOutParamAttr attr) {
} }
} }
static bool IsFormatFloat(const OrbisAudioOutParamFormat format) {
switch (format) {
case OrbisAudioOutParamFormat::S16Mono:
case OrbisAudioOutParamFormat::S16Stereo:
case OrbisAudioOutParamFormat::S16_8CH:
case OrbisAudioOutParamFormat::S16_8CH_Std:
return false;
case OrbisAudioOutParamFormat::FloatMono:
case OrbisAudioOutParamFormat::FloatStereo:
case OrbisAudioOutParamFormat::Float_8CH:
case OrbisAudioOutParamFormat::Float_8CH_Std:
return true;
default:
UNREACHABLE_MSG("Unknown format");
}
}
static int GetFormatNumChannels(const OrbisAudioOutParamFormat format) {
switch (format) {
case OrbisAudioOutParamFormat::S16Mono:
case OrbisAudioOutParamFormat::FloatMono:
return 1;
case OrbisAudioOutParamFormat::S16Stereo:
case OrbisAudioOutParamFormat::FloatStereo:
return 2;
case OrbisAudioOutParamFormat::S16_8CH:
case OrbisAudioOutParamFormat::Float_8CH:
case OrbisAudioOutParamFormat::S16_8CH_Std:
case OrbisAudioOutParamFormat::Float_8CH_Std:
return 8;
default:
UNREACHABLE_MSG("Unknown format");
}
}
static u8 GetFormatSampleSize(const OrbisAudioOutParamFormat format) {
switch (format) {
case OrbisAudioOutParamFormat::S16Mono:
case OrbisAudioOutParamFormat::S16Stereo:
case OrbisAudioOutParamFormat::S16_8CH:
case OrbisAudioOutParamFormat::S16_8CH_Std:
return 2;
case OrbisAudioOutParamFormat::FloatMono:
case OrbisAudioOutParamFormat::FloatStereo:
case OrbisAudioOutParamFormat::Float_8CH:
case OrbisAudioOutParamFormat::Float_8CH_Std:
return 4;
default:
UNREACHABLE_MSG("Unknown format");
}
}
int PS4_SYSV_ABI sceAudioOutDeviceIdOpen() { int PS4_SYSV_ABI sceAudioOutDeviceIdOpen() {
LOG_ERROR(Lib_AudioOut, "(STUBBED) called"); LOG_ERROR(Lib_AudioOut, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
@ -110,8 +179,21 @@ int PS4_SYSV_ABI sceAudioOutChangeAppModuleState() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceAudioOutClose() { int PS4_SYSV_ABI sceAudioOutClose(s32 handle) {
LOG_ERROR(Lib_AudioOut, "(STUBBED) called"); LOG_INFO(Lib_AudioOut, "handle = {}", handle);
if (handle < 1 || handle > SCE_AUDIO_OUT_NUM_PORTS) {
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
}
std::scoped_lock lock(ports_mutex);
auto& port = ports_out.at(handle - 1);
if (!port.is_open) {
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
}
audio->Close(port.impl);
port.impl = nullptr;
port.is_open = false;
return ORBIS_OK; return ORBIS_OK;
} }
@ -180,16 +262,21 @@ int PS4_SYSV_ABI sceAudioOutGetPortState(s32 handle, OrbisAudioOutPortState* sta
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT; return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
} }
const auto [type, channels_num] = audio->GetStatus(handle); std::scoped_lock lock(ports_mutex);
const auto& port = ports_out.at(handle - 1);
if (!port.is_open) {
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
}
state->rerouteCounter = 0; state->rerouteCounter = 0;
state->volume = 127; state->volume = 127;
switch (type) { switch (port.type) {
case OrbisAudioOutPort::Main: case OrbisAudioOutPort::Main:
case OrbisAudioOutPort::Bgm: case OrbisAudioOutPort::Bgm:
case OrbisAudioOutPort::Voice: case OrbisAudioOutPort::Voice:
state->output = 1; state->output = 1;
state->channel = (channels_num > 2 ? 2 : channels_num); state->channel = port.channels_num > 2 ? 2 : port.channels_num;
break; break;
case OrbisAudioOutPort::Personal: case OrbisAudioOutPort::Personal:
case OrbisAudioOutPort::Padspk: case OrbisAudioOutPort::Padspk:
@ -276,7 +363,7 @@ s32 PS4_SYSV_ABI sceAudioOutOpen(UserService::OrbisUserServiceUserId user_id,
u32 sample_rate, u32 sample_rate,
OrbisAudioOutParamExtendedInformation param_type) { OrbisAudioOutParamExtendedInformation param_type) {
LOG_INFO(Lib_AudioOut, LOG_INFO(Lib_AudioOut,
"AudioOutOpen id = {} port_type = {} index = {} lenght= {} sample_rate = {} " "id = {} port_type = {} index = {} length = {} sample_rate = {} "
"param_type = {} attr = {}", "param_type = {} attr = {}",
user_id, GetAudioOutPort(port_type), index, length, sample_rate, user_id, GetAudioOutPort(port_type), index, length, sample_rate,
GetAudioOutParamFormat(param_type.data_format), GetAudioOutParamFormat(param_type.data_format),
@ -310,7 +397,26 @@ s32 PS4_SYSV_ABI sceAudioOutOpen(UserService::OrbisUserServiceUserId user_id,
LOG_ERROR(Lib_AudioOut, "Invalid format attribute"); LOG_ERROR(Lib_AudioOut, "Invalid format attribute");
return ORBIS_AUDIO_OUT_ERROR_INVALID_FORMAT; return ORBIS_AUDIO_OUT_ERROR_INVALID_FORMAT;
} }
return audio->Open(port_type, length, sample_rate, format);
std::scoped_lock lock{ports_mutex};
const auto port = std::ranges::find(ports_out, false, &PortOut::is_open);
if (port == ports_out.end()) {
LOG_ERROR(Lib_AudioOut, "Audio ports are full");
return ORBIS_AUDIO_OUT_ERROR_PORT_FULL;
}
port->is_open = true;
port->type = port_type;
port->samples_num = length;
port->freq = sample_rate;
port->format = format;
port->is_float = IsFormatFloat(format);
port->channels_num = GetFormatNumChannels(format);
port->sample_size = GetFormatSampleSize(format);
port->volume.fill(SCE_AUDIO_OUT_VOLUME_0DB);
port->impl = audio->Open(port->is_float, port->channels_num, port->freq);
return std::distance(ports_out.begin(), port) + 1;
} }
int PS4_SYSV_ABI sceAudioOutOpenEx() { int PS4_SYSV_ABI sceAudioOutOpenEx() {
@ -326,7 +432,15 @@ s32 PS4_SYSV_ABI sceAudioOutOutput(s32 handle, const void* ptr) {
// Nothing to output // Nothing to output
return ORBIS_OK; return ORBIS_OK;
} }
return audio->Output(handle, ptr);
auto& port = ports_out.at(handle - 1);
if (!port.is_open) {
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
}
const size_t data_size = port.samples_num * port.sample_size * port.channels_num;
audio->Output(port.impl, ptr, data_size);
return ORBIS_OK;
} }
int PS4_SYSV_ABI sceAudioOutOutputs(OrbisAudioOutOutputParam* param, u32 num) { int PS4_SYSV_ABI sceAudioOutOutputs(OrbisAudioOutOutputParam* param, u32 num) {
@ -431,7 +545,42 @@ s32 PS4_SYSV_ABI sceAudioOutSetVolume(s32 handle, s32 flag, s32* vol) {
if (handle < 1 || handle > SCE_AUDIO_OUT_NUM_PORTS) { if (handle < 1 || handle > SCE_AUDIO_OUT_NUM_PORTS) {
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT; return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
} }
return audio->SetVolume(handle, flag, vol);
std::scoped_lock lock(ports_mutex);
auto& port = ports_out.at(handle - 1);
if (!port.is_open) {
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
}
for (int i = 0; i < port.channels_num; i++, flag >>= 1u) {
auto bit = flag & 0x1u;
if (bit == 1) {
int src_index = i;
if (port.format == OrbisAudioOutParamFormat::Float_8CH_Std ||
port.format == OrbisAudioOutParamFormat::S16_8CH_Std) {
switch (i) {
case 4:
src_index = 6;
break;
case 5:
src_index = 7;
break;
case 6:
src_index = 4;
break;
case 7:
src_index = 5;
break;
default:
break;
}
}
port.volume[i] = vol[src_index];
}
}
audio->SetVolume(port.impl, port.volume);
return ORBIS_OK;
} }
int PS4_SYSV_ABI sceAudioOutSetVolumeDown() { int PS4_SYSV_ABI sceAudioOutSetVolumeDown() {

View File

@ -64,7 +64,7 @@ int PS4_SYSV_ABI sceAudioOutA3dExit();
int PS4_SYSV_ABI sceAudioOutA3dInit(); int PS4_SYSV_ABI sceAudioOutA3dInit();
int PS4_SYSV_ABI sceAudioOutAttachToApplicationByPid(); int PS4_SYSV_ABI sceAudioOutAttachToApplicationByPid();
int PS4_SYSV_ABI sceAudioOutChangeAppModuleState(); int PS4_SYSV_ABI sceAudioOutChangeAppModuleState();
int PS4_SYSV_ABI sceAudioOutClose(); int PS4_SYSV_ABI sceAudioOutClose(s32 handle);
int PS4_SYSV_ABI sceAudioOutDetachFromApplicationByPid(); int PS4_SYSV_ABI sceAudioOutDetachFromApplicationByPid();
int PS4_SYSV_ABI sceAudioOutExConfigureOutputMode(); int PS4_SYSV_ABI sceAudioOutExConfigureOutputMode();
int PS4_SYSV_ABI sceAudioOutExGetSystemInfo(); int PS4_SYSV_ABI sceAudioOutExGetSystemInfo();

View File

@ -0,0 +1,19 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
namespace Libraries::AudioOut {
class AudioOutBackend {
public:
AudioOutBackend() = default;
virtual ~AudioOutBackend() = default;
virtual void* Open(bool is_float, int num_channels, u32 sample_rate) = 0;
virtual void Close(void* impl) = 0;
virtual void Output(void* impl, const void* ptr, size_t size) = 0;
virtual void SetVolume(void* impl, std::array<int, 8> ch_volumes) = 0;
};
} // namespace Libraries::AudioOut

View File

@ -1,141 +1,44 @@
// 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>
#include <SDL3/SDL_audio.h> #include <SDL3/SDL_audio.h>
#include <SDL3/SDL_init.h> #include <SDL3/SDL_init.h>
#include <SDL3/SDL_timer.h> #include <SDL3/SDL_timer.h>
#include "common/assert.h" #include "common/assert.h"
#include "core/libraries/audio/audioout_error.h"
#include "core/libraries/audio/sdl_audio.h" #include "core/libraries/audio/sdl_audio.h"
namespace Libraries::AudioOut { namespace Libraries::AudioOut {
constexpr int AUDIO_STREAM_BUFFER_THRESHOLD = 65536; // Define constant for buffer threshold constexpr int AUDIO_STREAM_BUFFER_THRESHOLD = 65536; // Define constant for buffer threshold
s32 SDLAudioOut::Open(OrbisAudioOutPort type, u32 samples_num, u32 freq, void* SDLAudioOut::Open(bool is_float, int num_channels, u32 sample_rate) {
OrbisAudioOutParamFormat format) {
std::scoped_lock lock{m_mutex};
const auto port = std::ranges::find(ports_out, false, &PortOut::is_open);
if (port == ports_out.end()) {
LOG_ERROR(Lib_AudioOut, "Audio ports are full");
return ORBIS_AUDIO_OUT_ERROR_PORT_FULL;
}
port->is_open = true;
port->type = type;
port->samples_num = samples_num;
port->freq = freq;
port->format = format;
SDL_AudioFormat sampleFormat;
switch (format) {
case OrbisAudioOutParamFormat::S16Mono:
sampleFormat = SDL_AUDIO_S16;
port->channels_num = 1;
port->sample_size = 2;
break;
case OrbisAudioOutParamFormat::FloatMono:
sampleFormat = SDL_AUDIO_F32;
port->channels_num = 1;
port->sample_size = 4;
break;
case OrbisAudioOutParamFormat::S16Stereo:
sampleFormat = SDL_AUDIO_S16;
port->channels_num = 2;
port->sample_size = 2;
break;
case OrbisAudioOutParamFormat::FloatStereo:
sampleFormat = SDL_AUDIO_F32;
port->channels_num = 2;
port->sample_size = 4;
break;
case OrbisAudioOutParamFormat::S16_8CH:
sampleFormat = SDL_AUDIO_S16;
port->channels_num = 8;
port->sample_size = 2;
break;
case OrbisAudioOutParamFormat::Float_8CH:
sampleFormat = SDL_AUDIO_F32;
port->channels_num = 8;
port->sample_size = 4;
break;
case OrbisAudioOutParamFormat::S16_8CH_Std:
sampleFormat = SDL_AUDIO_S16;
port->channels_num = 8;
port->sample_size = 2;
break;
case OrbisAudioOutParamFormat::Float_8CH_Std:
sampleFormat = SDL_AUDIO_F32;
port->channels_num = 8;
port->sample_size = 4;
break;
default:
UNREACHABLE_MSG("Unknown format");
}
port->volume.fill(Libraries::AudioOut::SCE_AUDIO_OUT_VOLUME_0DB);
SDL_AudioSpec fmt; SDL_AudioSpec fmt;
SDL_zero(fmt); SDL_zero(fmt);
fmt.format = sampleFormat; fmt.format = is_float ? SDL_AUDIO_F32 : SDL_AUDIO_S16;
fmt.channels = port->channels_num; fmt.channels = num_channels;
fmt.freq = freq; fmt.freq = sample_rate;
port->stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &fmt, NULL, NULL);
SDL_ResumeAudioDevice(SDL_GetAudioStreamDevice(port->stream)); auto* stream =
return std::distance(ports_out.begin(), port) + 1; SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &fmt, nullptr, nullptr);
SDL_ResumeAudioStreamDevice(stream);
return stream;
} }
s32 SDLAudioOut::Output(s32 handle, const void* ptr) { void SDLAudioOut::Close(void* impl) {
auto& port = ports_out.at(handle - 1); SDL_DestroyAudioStream(static_cast<SDL_AudioStream*>(impl));
if (!port.is_open) {
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
} }
const size_t data_size = port.samples_num * port.sample_size * port.channels_num; void SDLAudioOut::Output(void* impl, const void* ptr, size_t size) {
bool result = SDL_PutAudioStreamData(port.stream, ptr, data_size); auto* stream = static_cast<SDL_AudioStream*>(impl);
while (SDL_GetAudioStreamAvailable(port.stream) > AUDIO_STREAM_BUFFER_THRESHOLD) { SDL_PutAudioStreamData(stream, ptr, size);
while (SDL_GetAudioStreamAvailable(stream) > AUDIO_STREAM_BUFFER_THRESHOLD) {
SDL_Delay(0); SDL_Delay(0);
} }
return result ? ORBIS_OK : -1;
} }
s32 SDLAudioOut::SetVolume(s32 handle, s32 bitflag, s32* volume) { void SDLAudioOut::SetVolume(void* impl, std::array<int, 8> ch_volumes) {
using Libraries::AudioOut::OrbisAudioOutParamFormat; // Not yet implemented
auto& port = ports_out.at(handle - 1);
if (!port.is_open) {
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
}
for (int i = 0; i < port.channels_num; i++, bitflag >>= 1u) {
auto bit = bitflag & 0x1u;
if (bit == 1) {
int src_index = i;
if (port.format == OrbisAudioOutParamFormat::Float_8CH_Std ||
port.format == OrbisAudioOutParamFormat::S16_8CH_Std) {
switch (i) {
case 4:
src_index = 6;
break;
case 5:
src_index = 7;
break;
case 6:
src_index = 4;
break;
case 7:
src_index = 5;
break;
default:
break;
}
}
port.volume[i] = volume[src_index];
}
}
return ORBIS_OK;
} }
} // namespace Libraries::AudioOut } // namespace Libraries::AudioOut

View File

@ -3,40 +3,16 @@
#pragma once #pragma once
#include <shared_mutex> #include "core/libraries/audio/audioout_backend.h"
#include <SDL3/SDL_audio.h>
#include "core/libraries/audio/audioout.h"
namespace Libraries::AudioOut { namespace Libraries::AudioOut {
class SDLAudioOut { class SDLAudioOut final : public AudioOutBackend {
public: public:
explicit SDLAudioOut() = default; void* Open(bool is_float, int num_channels, u32 sample_rate) override;
~SDLAudioOut() = default; void Close(void* impl) override;
void Output(void* impl, const void* ptr, size_t size) override;
s32 Open(OrbisAudioOutPort type, u32 samples_num, u32 freq, OrbisAudioOutParamFormat format); void SetVolume(void* impl, std::array<int, 8> ch_volumes) override;
s32 Output(s32 handle, const void* ptr);
s32 SetVolume(s32 handle, s32 bitflag, s32* volume);
constexpr std::pair<OrbisAudioOutPort, int> GetStatus(s32 handle) const {
const auto& port = ports_out.at(handle - 1);
return std::make_pair(port.type, port.channels_num);
}
private:
struct PortOut {
SDL_AudioStream* stream;
u32 samples_num;
u32 freq;
OrbisAudioOutParamFormat format;
OrbisAudioOutPort type;
int channels_num;
std::array<int, 8> volume;
u8 sample_size;
bool is_open;
};
std::shared_mutex m_mutex;
std::array<PortOut, Libraries::AudioOut::SCE_AUDIO_OUT_NUM_PORTS> ports_out{};
}; };
} // namespace Libraries::AudioOut } // namespace Libraries::AudioOut

View File

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

View File

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

@ -90,7 +90,7 @@ public:
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) {
@ -101,7 +101,7 @@ public:
} else { } else {
return false; return false;
} }
} } while (rel_time_ms.count() > 0);
return false; return false;
#elif defined(__APPLE__) #elif defined(__APPLE__)
@ -117,12 +117,9 @@ public:
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); auto rel_time = std::chrono::ceil<std::chrono::milliseconds>(abs_time - start_time);
while (rel_time.count() > 0) { do {
u64 timeout_ms = static_cast<u64>(rel_time.count()); u64 timeout_ms = static_cast<u64>(rel_time.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) {
@ -133,7 +130,7 @@ public:
} else { } else {
return false; return false;
} }
} } while (rel_time.count() > 0);
return false; return false;
#elif defined(__APPLE__) #elif defined(__APPLE__)

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

@ -5,6 +5,7 @@
#include <mutex> #include <mutex>
#include <imgui.h> #include <imgui.h>
#include "common/assert.h" #include "common/assert.h"
#include "common/config.h"
#include "common/singleton.h" #include "common/singleton.h"
#include "imgui/imgui_std.h" #include "imgui/imgui_std.h"
#include "trophy_ui.h" #include "trophy_ui.h"
@ -82,7 +83,10 @@ void TrophyUI::Draw() {
void AddTrophyToQueue(const std::filesystem::path& trophyIconPath, const std::string& trophyName) { void AddTrophyToQueue(const std::filesystem::path& trophyIconPath, const std::string& trophyName) {
std::lock_guard<std::mutex> lock(queueMtx); std::lock_guard<std::mutex> lock(queueMtx);
if (current_trophy_ui.has_value()) {
if (Config::getisTrophyPopupDisabled()) {
return;
} else if (current_trophy_ui.has_value()) {
TrophyInfo new_trophy; TrophyInfo new_trophy;
new_trophy.trophy_icon_path = trophyIconPath; new_trophy.trophy_icon_path = trophyIconPath;
new_trophy.trophy_name = trophyName; new_trophy.trophy_name = trophyName;

View File

@ -11,6 +11,7 @@
#else #else
#include <csignal> #include <csignal>
#include <pthread.h> #include <pthread.h>
#include <unistd.h>
#endif #endif
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

@ -4,6 +4,7 @@
#include <QFileInfo> #include <QFileInfo>
#include <QMessageBox> #include <QMessageBox>
#include <QProgressDialog> #include <QProgressDialog>
#include <QTimer>
#include "common/path_util.h" #include "common/path_util.h"
#include "compatibility_info.h" #include "compatibility_info.h"
@ -17,12 +18,14 @@ CompatibilityInfoClass::CompatibilityInfoClass()
}; };
CompatibilityInfoClass::~CompatibilityInfoClass() = default; CompatibilityInfoClass::~CompatibilityInfoClass() = default;
void CompatibilityInfoClass::UpdateCompatibilityDatabase(QWidget* parent) { void CompatibilityInfoClass::UpdateCompatibilityDatabase(QWidget* parent, bool forced) {
if (!forced)
if (LoadCompatibilityFile()) if (LoadCompatibilityFile())
return; return;
QNetworkReply* reply = FetchPage(1); QNetworkReply* reply = FetchPage(1);
WaitForReply(reply); if (!WaitForReply(reply))
return;
QProgressDialog dialog(tr("Fetching compatibility data, please wait"), tr("Cancel"), 0, 0, QProgressDialog dialog(tr("Fetching compatibility data, please wait"), tr("Cancel"), 0, 0,
parent); parent);
@ -43,6 +46,7 @@ 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
if (!forced)
LoadCompatibilityFile(); LoadCompatibilityFile();
return; return;
} }
@ -57,12 +61,17 @@ void CompatibilityInfoClass::UpdateCompatibilityDatabase(QWidget* parent) {
} }
future_watcher.setFuture(QtConcurrent::map(replies, WaitForReply)); future_watcher.setFuture(QtConcurrent::map(replies, WaitForReply));
connect(&future_watcher, &QFutureWatcher<QByteArray>::finished, [&]() { connect(&future_watcher, &QFutureWatcher<void>::finished, [&]() {
for (int i = 0; i < remaining_pages; i++) { for (int i = 0; i < remaining_pages; i++) {
if (replies[i]->bytesAvailable()) {
if (replies[i]->error() == QNetworkReply::NoError) { if (replies[i]->error() == QNetworkReply::NoError) {
ExtractCompatibilityInfo(replies[i]->readAll()); ExtractCompatibilityInfo(replies[i]->readAll());
} }
replies[i]->deleteLater(); replies[i]->deleteLater();
} else {
// This means the request timed out
return;
}
} }
QFile compatibility_file(m_compatibility_filename); QFile compatibility_file(m_compatibility_filename);
@ -83,6 +92,16 @@ void CompatibilityInfoClass::UpdateCompatibilityDatabase(QWidget* parent) {
dialog.reset(); dialog.reset();
}); });
connect(&future_watcher, &QFutureWatcher<void>::canceled, [&]() {
// Cleanup if user cancels pulling data
for (int i = 0; i < remaining_pages; i++) {
if (!replies[i]->bytesAvailable()) {
replies[i]->deleteLater();
} else if (!replies[i]->isFinished()) {
replies[i]->abort();
}
}
});
connect(&dialog, &QProgressDialog::canceled, &future_watcher, &QFutureWatcher<void>::cancel); connect(&dialog, &QProgressDialog::canceled, &future_watcher, &QFutureWatcher<void>::cancel);
dialog.setRange(0, remaining_pages); dialog.setRange(0, remaining_pages);
connect(&future_watcher, &QFutureWatcher<void>::progressValueChanged, &dialog, connect(&future_watcher, &QFutureWatcher<void>::progressValueChanged, &dialog,
@ -105,20 +124,34 @@ QNetworkReply* CompatibilityInfoClass::FetchPage(int page_num) {
return reply; return reply;
} }
void CompatibilityInfoClass::WaitForReply(QNetworkReply* reply) { bool CompatibilityInfoClass::WaitForReply(QNetworkReply* reply) {
// Returns true if reply succeeded, false if reply timed out
QTimer timer;
timer.setSingleShot(true);
QEventLoop loop; QEventLoop loop;
connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
timer.start(5000);
loop.exec(); loop.exec();
return;
if (timer.isActive()) {
timer.stop();
return true;
} else {
disconnect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
reply->abort();
return false;
}
}; };
CompatibilityEntry CompatibilityInfoClass::GetCompatibilityInfo(const std::string& serial) { CompatibilityEntry CompatibilityInfoClass::GetCompatibilityInfo(const std::string& serial) {
QString title_id = QString::fromStdString(serial); QString title_id = QString::fromStdString(serial);
if (m_compatibility_database.contains(title_id)) { if (m_compatibility_database.contains(title_id)) {
{ {
QJsonObject compatibility_obj = m_compatibility_database[title_id].toObject();
for (int os_int = 0; os_int != static_cast<int>(OSType::Last); os_int++) { for (int os_int = 0; os_int != static_cast<int>(OSType::Last); os_int++) {
QString os_string = OSTypeToString.at(static_cast<OSType>(os_int)); QString os_string = OSTypeToString.at(static_cast<OSType>(os_int));
QJsonObject compatibility_obj = m_compatibility_database[title_id].toObject();
if (compatibility_obj.contains(os_string)) { if (compatibility_obj.contains(os_string)) {
QJsonObject compatibility_entry_obj = compatibility_obj[os_string].toObject(); QJsonObject compatibility_entry_obj = compatibility_obj[os_string].toObject();
CompatibilityEntry compatibility_entry{ CompatibilityEntry compatibility_entry{
@ -133,7 +166,9 @@ CompatibilityEntry CompatibilityInfoClass::GetCompatibilityInfo(const std::strin
} }
} }
} }
return CompatibilityEntry{CompatibilityStatus::Unknown};
return CompatibilityEntry{CompatibilityStatus::Unknown, "", QDateTime::currentDateTime(), "",
0};
} }
bool CompatibilityInfoClass::LoadCompatibilityFile() { bool CompatibilityInfoClass::LoadCompatibilityFile() {

View File

@ -57,6 +57,7 @@ class CompatibilityInfoClass : public QObject {
public: public:
// Please think of a better alternative // Please think of a better alternative
inline static const std::unordered_map<QString, CompatibilityStatus> LabelToCompatStatus = { inline static const std::unordered_map<QString, CompatibilityStatus> LabelToCompatStatus = {
{QStringLiteral("status-unknown"), CompatibilityStatus::Unknown},
{QStringLiteral("status-nothing"), CompatibilityStatus::Nothing}, {QStringLiteral("status-nothing"), CompatibilityStatus::Nothing},
{QStringLiteral("status-boots"), CompatibilityStatus::Boots}, {QStringLiteral("status-boots"), CompatibilityStatus::Boots},
{QStringLiteral("status-menus"), CompatibilityStatus::Menus}, {QStringLiteral("status-menus"), CompatibilityStatus::Menus},
@ -83,11 +84,11 @@ 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);
static void WaitForReply(QNetworkReply* reply); static bool WaitForReply(QNetworkReply* reply);
QNetworkReply* FetchPage(int page_num); QNetworkReply* FetchPage(int page_num);
private: private:

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) {
@ -103,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);
@ -236,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) {
@ -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

@ -144,7 +144,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");
@ -189,7 +189,9 @@ void MainWindow::CreateDockWindows() {
void MainWindow::LoadGameLists() { void MainWindow::LoadGameLists() {
// Update compatibility database // Update compatibility database
if (Config::getCheckCompatibilityOnStartup()) {
m_compat_info->UpdateCompatibilityDatabase(this); m_compat_info->UpdateCompatibilityDatabase(this);
}
// Get game info from game folders. // Get game info from game folders.
m_game_info->GetGameInfo(this); m_game_info->GetGameInfo(this);
if (isTableList) { if (isTableList) {
@ -255,20 +257,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();
}); });
@ -564,7 +572,6 @@ void MainWindow::CreateConnects() {
} }
void MainWindow::StartGame() { void MainWindow::StartGame() {
isGameRunning = true;
BackgroundMusicPlayer::getInstance().stopMusic(); BackgroundMusicPlayer::getInstance().stopMusic();
QString gamePath = ""; QString gamePath = "";
int table_mode = Config::getTableMode(); int table_mode = Config::getTableMode();
@ -587,13 +594,12 @@ void MainWindow::StartGame() {
} }
if (gamePath != "") { if (gamePath != "") {
AddRecentFiles(gamePath); AddRecentFiles(gamePath);
Core::Emulator emulator;
const auto path = Common::FS::PathFromQString(gamePath); const auto path = Common::FS::PathFromQString(gamePath);
if (!std::filesystem::exists(path)) { if (!std::filesystem::exists(path)) {
QMessageBox::critical(nullptr, tr("Run Game"), QString(tr("Eboot.bin file not found"))); QMessageBox::critical(nullptr, tr("Run Game"), QString(tr("Eboot.bin file not found")));
return; return;
} }
emulator.Run(path); StartEmulator(path);
} }
} }
@ -690,13 +696,12 @@ void MainWindow::BootGame() {
QString(tr("Only one file can be selected!"))); QString(tr("Only one file can be selected!")));
} else { } else {
std::filesystem::path path = Common::FS::PathFromQString(fileNames[0]); std::filesystem::path path = Common::FS::PathFromQString(fileNames[0]);
Core::Emulator emulator;
if (!std::filesystem::exists(path)) { if (!std::filesystem::exists(path)) {
QMessageBox::critical(nullptr, tr("Run Game"), QMessageBox::critical(nullptr, tr("Run Game"),
QString(tr("Eboot.bin file not found"))); QString(tr("Eboot.bin file not found")));
return; return;
} }
emulator.Run(path); StartEmulator(path);
} }
} }
} }
@ -1050,12 +1055,11 @@ void MainWindow::CreateRecentGameActions() {
connect(m_recent_files_group, &QActionGroup::triggered, this, [this](QAction* action) { connect(m_recent_files_group, &QActionGroup::triggered, this, [this](QAction* action) {
auto gamePath = Common::FS::PathFromQString(action->text()); auto gamePath = Common::FS::PathFromQString(action->text());
AddRecentFiles(action->text()); // Update the list. AddRecentFiles(action->text()); // Update the list.
Core::Emulator emulator;
if (!std::filesystem::exists(gamePath)) { if (!std::filesystem::exists(gamePath)) {
QMessageBox::critical(nullptr, tr("Run Game"), QString(tr("Eboot.bin file not found"))); QMessageBox::critical(nullptr, tr("Run Game"), QString(tr("Eboot.bin file not found")));
return; return;
} }
emulator.Run(gamePath); StartEmulator(gamePath);
}); });
} }
@ -1104,3 +1108,22 @@ bool MainWindow::eventFilter(QObject* obj, QEvent* event) {
} }
return QMainWindow::eventFilter(obj, event); return QMainWindow::eventFilter(obj, event);
} }
void MainWindow::StartEmulator(std::filesystem::path path) {
if (isGameRunning) {
QMessageBox::critical(nullptr, tr("Run Game"), QString(tr("Game is already running!")));
return;
}
isGameRunning = true;
#ifdef __APPLE__
// SDL on macOS requires main thread.
Core::Emulator emulator;
emulator.Run(path);
#else
std::thread emulator_thread([=] {
Core::Emulator emulator;
emulator.Run(path);
});
emulator_thread.detach();
#endif
}

View File

@ -69,6 +69,7 @@ private:
void LoadTranslation(); void LoadTranslation();
void PlayBackgroundMusic(); void PlayBackgroundMusic();
QIcon RecolorIcon(const QIcon& icon, bool isWhite); QIcon RecolorIcon(const QIcon& icon, bool isWhite);
void StartEmulator(std::filesystem::path);
bool isIconBlack = false; bool isIconBlack = false;
bool isTableList = true; bool isTableList = true;
bool isGameRunning = false; bool isGameRunning = false;

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
@ -54,7 +56,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);
@ -140,6 +144,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
@ -194,6 +208,10 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices, QWidge
ui->updaterGroupBox->installEventFilter(this); ui->updaterGroupBox->installEventFilter(this);
#endif #endif
ui->GUIgroupBox->installEventFilter(this); ui->GUIgroupBox->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);
@ -263,6 +281,8 @@ void SettingsDialog::LoadValuesFromConfig() {
ui->dumpShadersCheckBox->setChecked(toml::find_or<bool>(data, "GPU", "dumpShaders", false)); ui->dumpShadersCheckBox->setChecked(toml::find_or<bool>(data, "GPU", "dumpShaders", false));
ui->nullGpuCheckBox->setChecked(toml::find_or<bool>(data, "GPU", "nullGpu", false)); ui->nullGpuCheckBox->setChecked(toml::find_or<bool>(data, "GPU", "nullGpu", false));
ui->playBGMCheckBox->setChecked(toml::find_or<bool>(data, "General", "playBGM", false)); ui->playBGMCheckBox->setChecked(toml::find_or<bool>(data, "General", "playBGM", false));
ui->disableTrophycheckBox->setChecked(
toml::find_or<bool>(data, "General", "isTrophyPopupDisabled", false));
ui->BGMVolumeSlider->setValue(toml::find_or<int>(data, "General", "BGMvolume", 50)); ui->BGMVolumeSlider->setValue(toml::find_or<int>(data, "General", "BGMvolume", 50));
ui->discordRPCCheckbox->setChecked( ui->discordRPCCheckbox->setChecked(
toml::find_or<bool>(data, "General", "enableDiscordRPC", true)); toml::find_or<bool>(data, "General", "enableDiscordRPC", true));
@ -282,6 +302,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));
@ -397,6 +421,14 @@ void SettingsDialog::updateNoteTextEdit(const QString& elementName) {
#endif #endif
} else if (elementName == "GUIgroupBox") { } else if (elementName == "GUIgroupBox") {
text = tr("GUIgroupBox"); text = tr("GUIgroupBox");
} else if (elementName == "disableTrophycheckBox") {
text = tr("disableTrophycheckBox");
} else if (elementName == "enableCompatibilityCheckBox") {
text = tr("enableCompatibilityCheckBox");
} else if (elementName == "checkCompatibilityOnStartupCheckBox") {
text = tr("checkCompatibilityOnStartupCheckBox");
} else if (elementName == "updateCompatibilityButton") {
text = tr("updateCompatibilityButton");
} }
// Input // Input
@ -485,6 +517,7 @@ void SettingsDialog::UpdateSettings() {
Config::setBackButtonBehavior(TouchPadIndex[ui->backButtonBehaviorComboBox->currentIndex()]); Config::setBackButtonBehavior(TouchPadIndex[ui->backButtonBehaviorComboBox->currentIndex()]);
Config::setNeoMode(ui->ps4proCheckBox->isChecked()); Config::setNeoMode(ui->ps4proCheckBox->isChecked());
Config::setFullscreenMode(ui->fullscreenCheckBox->isChecked()); Config::setFullscreenMode(ui->fullscreenCheckBox->isChecked());
Config::setisTrophyPopupDisabled(ui->disableTrophycheckBox->isChecked());
Config::setPlayBGM(ui->playBGMCheckBox->isChecked()); Config::setPlayBGM(ui->playBGMCheckBox->isChecked());
Config::setNeoMode(ui->ps4proCheckBox->isChecked()); Config::setNeoMode(ui->ps4proCheckBox->isChecked());
Config::setLogType(ui->logTypeComboBox->currentText().toStdString()); Config::setLogType(ui->logTypeComboBox->currentText().toStdString());
@ -509,6 +542,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>660</height> <height>660</height>
</rect> </rect>
</property> </property>
@ -59,9 +59,9 @@
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>-97</y>
<width>832</width> <width>815</width>
<height>431</height> <height>618</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@ -306,7 +306,7 @@
</property> </property>
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>275</width> <width>265</width>
<height>0</height> <height>0</height>
</size> </size>
</property> </property>
@ -469,6 +469,13 @@
<property name="bottomMargin"> <property name="bottomMargin">
<number>11</number> <number>11</number>
</property> </property>
<item>
<widget class="QCheckBox" name="disableTrophycheckBox">
<property name="text">
<string>Disable Trophy Pop-ups</string>
</property>
</widget>
</item>
<item> <item>
<layout class="QVBoxLayout" name="GUIMusicLayout"> <layout class="QVBoxLayout" name="GUIMusicLayout">
<property name="topMargin"> <property name="topMargin">
@ -561,35 +568,88 @@
</item> </item>
</layout> </layout>
</item> </item>
</layout>
</widget>
</item>
</layout>
</item>
<item> <item>
<widget class="QWidget" name="GUIwidgetSpacer" native="true"> <layout class="QVBoxLayout" name="CompatTabLayoutRight" stretch="0">
<item alignment="Qt::AlignmentFlag::AlignTop">
<widget class="QGroupBox" name="CompatgroupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>0</width> <width>0</width>
<height>61</height> <height>0</height>
</size> </size>
</property> </property>
</widget> <property name="title">
</item> <string>Game Compatibility</string>
</layout>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="EmptyTabLayoutRight">
<item>
<spacer name="emptyHorizontalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property> </property>
<property name="sizeHint" stdset="0"> <layout class="QVBoxLayout" name="CompatLayout">
<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>
<layout class="QVBoxLayout" name="UpdateCompatLayout">
<property name="topMargin">
<number>1</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<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> <size>
<width>40</width> <width>197</width>
<height>20</height> <height>28</height>
</size> </size>
</property> </property>
</spacer> <property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Update Compatibility Database</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item> </item>
</layout> </layout>
</item> </item>
@ -696,7 +756,7 @@
<property name="bottomMargin"> <property name="bottomMargin">
<number>5</number> <number>5</number>
</property> </property>
<item alignment="Qt::AlignmentFlag::AlignHCenter"> <item>
<widget class="QSpinBox" name="idleTimeoutSpinBox"> <widget class="QSpinBox" name="idleTimeoutSpinBox">
<property name="enabled"> <property name="enabled">
<bool>true</bool> <bool>true</bool>

View File

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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>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>رفتار دکمه برگشت:\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

@ -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

@ -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

@ -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>

View File

@ -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

@ -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>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>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>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>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>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>Seriale</translation> <translation>Seriale</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

@ -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

@ -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

@ -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

@ -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>

View File

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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>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>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>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>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>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>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>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>Seriku</translation> <translation>Seriku</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

@ -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>

View File

@ -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

@ -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

@ -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

@ -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

@ -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, )

View File

@ -115,25 +115,16 @@ bool IsImageAtomicInstruction(const IR::Inst& inst) {
} }
} }
bool IsImageStorageInstruction(const IR::Inst& inst) {
switch (inst.GetOpcode()) {
case IR::Opcode::ImageWrite:
case IR::Opcode::ImageRead:
return true;
default:
return IsImageAtomicInstruction(inst);
}
}
bool IsImageInstruction(const IR::Inst& inst) { bool IsImageInstruction(const IR::Inst& inst) {
switch (inst.GetOpcode()) { switch (inst.GetOpcode()) {
case IR::Opcode::ImageFetch: case IR::Opcode::ImageRead:
case IR::Opcode::ImageWrite:
case IR::Opcode::ImageQueryDimensions: case IR::Opcode::ImageQueryDimensions:
case IR::Opcode::ImageQueryLod: case IR::Opcode::ImageQueryLod:
case IR::Opcode::ImageSampleRaw: case IR::Opcode::ImageSampleRaw:
return true; return true;
default: default:
return IsImageStorageInstruction(inst); return IsImageAtomicInstruction(inst);
} }
} }
@ -201,7 +192,8 @@ public:
return desc.sharp_idx == existing.sharp_idx; return desc.sharp_idx == existing.sharp_idx;
})}; })};
auto& image = image_resources[index]; auto& image = image_resources[index];
image.is_storage |= desc.is_storage; image.is_read |= desc.is_read;
image.is_written |= desc.is_written;
return index; return index;
} }
@ -429,9 +421,9 @@ void PatchTextureBufferInstruction(IR::Block& block, IR::Inst& inst, Info& info,
} }
IR::Value PatchCubeCoord(IR::IREmitter& ir, const IR::Value& s, const IR::Value& t, IR::Value PatchCubeCoord(IR::IREmitter& ir, const IR::Value& s, const IR::Value& t,
const IR::Value& z, bool is_storage, bool is_array) { const IR::Value& z, bool is_written, bool is_array) {
// When cubemap is written with imageStore it is treated like 2DArray. // When cubemap is written with imageStore it is treated like 2DArray.
if (is_storage) { if (is_written) {
return ir.CompositeConstruct(s, t, z); return ir.CompositeConstruct(s, t, z);
} }
@ -684,15 +676,16 @@ void PatchImageInstruction(IR::Block& block, IR::Inst& inst, Info& info, Descrip
image = AmdGpu::Image::Null(); image = AmdGpu::Image::Null();
} }
ASSERT(image.GetType() != AmdGpu::ImageType::Invalid); ASSERT(image.GetType() != AmdGpu::ImageType::Invalid);
const bool is_storage = IsImageStorageInstruction(inst); const bool is_read = inst.GetOpcode() == IR::Opcode::ImageRead;
const bool is_written = inst.GetOpcode() == IR::Opcode::ImageWrite;
// Patch image instruction if image is FMask. // Patch image instruction if image is FMask.
if (image.IsFmask()) { if (image.IsFmask()) {
ASSERT_MSG(!is_storage, "FMask storage instructions are not supported"); ASSERT_MSG(!is_written, "FMask storage instructions are not supported");
IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
switch (inst.GetOpcode()) { switch (inst.GetOpcode()) {
case IR::Opcode::ImageFetch: case IR::Opcode::ImageRead:
case IR::Opcode::ImageSampleRaw: { case IR::Opcode::ImageSampleRaw: {
IR::F32 fmaskx = ir.BitCast<IR::F32>(ir.Imm32(0x76543210)); IR::F32 fmaskx = ir.BitCast<IR::F32>(ir.Imm32(0x76543210));
IR::F32 fmasky = ir.BitCast<IR::F32>(ir.Imm32(0xfedcba98)); IR::F32 fmasky = ir.BitCast<IR::F32>(ir.Imm32(0xfedcba98));
@ -721,10 +714,11 @@ void PatchImageInstruction(IR::Block& block, IR::Inst& inst, Info& info, Descrip
u32 image_binding = descriptors.Add(ImageResource{ u32 image_binding = descriptors.Add(ImageResource{
.sharp_idx = tsharp, .sharp_idx = tsharp,
.is_storage = is_storage,
.is_depth = bool(inst_info.is_depth), .is_depth = bool(inst_info.is_depth),
.is_atomic = IsImageAtomicInstruction(inst), .is_atomic = IsImageAtomicInstruction(inst),
.is_array = bool(inst_info.is_array), .is_array = bool(inst_info.is_array),
.is_read = is_read,
.is_written = is_written,
}); });
// Sample instructions must be resolved into a new instruction using address register data. // Sample instructions must be resolved into a new instruction using address register data.
@ -762,7 +756,7 @@ void PatchImageInstruction(IR::Block& block, IR::Inst& inst, Info& info, Descrip
case AmdGpu::ImageType::Color3D: // x, y, z, [lod] case AmdGpu::ImageType::Color3D: // x, y, z, [lod]
return {ir.CompositeConstruct(body->Arg(0), body->Arg(1), body->Arg(2)), body->Arg(3)}; return {ir.CompositeConstruct(body->Arg(0), body->Arg(1), body->Arg(2)), body->Arg(3)};
case AmdGpu::ImageType::Cube: // x, y, face, [lod] case AmdGpu::ImageType::Cube: // x, y, face, [lod]
return {PatchCubeCoord(ir, body->Arg(0), body->Arg(1), body->Arg(2), is_storage, return {PatchCubeCoord(ir, body->Arg(0), body->Arg(1), body->Arg(2), is_written,
inst_info.is_array), inst_info.is_array),
body->Arg(3)}; body->Arg(3)};
default: default:
@ -772,19 +766,20 @@ void PatchImageInstruction(IR::Block& block, IR::Inst& inst, Info& info, Descrip
inst.SetArg(1, coords); inst.SetArg(1, coords);
if (inst.GetOpcode() == IR::Opcode::ImageWrite) { if (inst.GetOpcode() == IR::Opcode::ImageWrite) {
inst.SetArg(3, SwizzleVector(ir, image, inst.Arg(3))); inst.SetArg(4, SwizzleVector(ir, image, inst.Arg(4)));
} }
if (inst_info.has_lod) { if (inst_info.has_lod) {
ASSERT(inst.GetOpcode() == IR::Opcode::ImageFetch || ASSERT(inst.GetOpcode() == IR::Opcode::ImageRead ||
inst.GetOpcode() == IR::Opcode::ImageRead ||
inst.GetOpcode() == IR::Opcode::ImageWrite); inst.GetOpcode() == IR::Opcode::ImageWrite);
ASSERT(image.GetType() != AmdGpu::ImageType::Color2DMsaa && ASSERT(image.GetType() != AmdGpu::ImageType::Color2DMsaa &&
image.GetType() != AmdGpu::ImageType::Color2DMsaaArray); image.GetType() != AmdGpu::ImageType::Color2DMsaaArray);
inst.SetArg(2, arg); inst.SetArg(2, arg);
} else if (image.GetType() == AmdGpu::ImageType::Color2DMsaa || } else if ((image.GetType() == AmdGpu::ImageType::Color2DMsaa ||
image.GetType() == AmdGpu::ImageType::Color2DMsaaArray) { image.GetType() == AmdGpu::ImageType::Color2DMsaaArray) &&
inst.SetArg(4, arg); (inst.GetOpcode() == IR::Opcode::ImageRead ||
inst.GetOpcode() == IR::Opcode::ImageWrite)) {
inst.SetArg(3, arg);
} }
} }

View File

@ -227,7 +227,7 @@ struct RuntimeInfo {
ComputeRuntimeInfo cs_info; ComputeRuntimeInfo cs_info;
}; };
RuntimeInfo(Stage stage_) { void Initialize(Stage stage_) {
memset(this, 0, sizeof(*this)); memset(this, 0, sizeof(*this));
stage = stage_; stage = stage_;
} }

View File

@ -39,10 +39,12 @@ struct TextureBufferSpecialization {
struct ImageSpecialization { struct ImageSpecialization {
AmdGpu::ImageType type = AmdGpu::ImageType::Color2D; AmdGpu::ImageType type = AmdGpu::ImageType::Color2D;
bool is_integer = false; bool is_integer = false;
bool is_storage = false;
u32 dst_select = 0; u32 dst_select = 0;
bool operator==(const ImageSpecialization& other) const { bool operator==(const ImageSpecialization& other) const {
return type == other.type && is_integer == other.is_integer && return type == other.type && is_integer == other.is_integer &&
is_storage == other.is_storage &&
(dst_select != 0 ? dst_select == other.dst_select : true); (dst_select != 0 ? dst_select == other.dst_select : true);
} }
}; };
@ -114,7 +116,8 @@ struct StageSpecialization {
[](auto& spec, const auto& desc, AmdGpu::Image sharp) { [](auto& spec, const auto& desc, AmdGpu::Image sharp) {
spec.type = sharp.GetBoundType(); spec.type = sharp.GetBoundType();
spec.is_integer = AmdGpu::IsInteger(sharp.GetNumberFmt()); spec.is_integer = AmdGpu::IsInteger(sharp.GetNumberFmt());
if (desc.is_storage) { spec.is_storage = desc.IsStorage(sharp);
if (spec.is_storage) {
spec.dst_select = sharp.DstSelect(); spec.dst_select = sharp.DstSelect();
} }
}); });

View File

@ -428,6 +428,14 @@ struct Liverpool {
BitField<0, 22, u32> tile_max; BitField<0, 22, u32> tile_max;
} depth_slice; } depth_slice;
bool DepthValid() const {
return Address() != 0 && z_info.format != ZFormat::Invalid;
}
bool StencilValid() const {
return Address() != 0 && stencil_info.format != StencilFormat::Invalid;
}
u32 Pitch() const { u32 Pitch() const {
return (depth_size.pitch_tile_max + 1) << 3; return (depth_size.pitch_tile_max + 1) << 3;
} }
@ -1275,6 +1283,26 @@ struct Liverpool {
return nullptr; return nullptr;
} }
u32 NumSamples() const {
// It seems that the number of samples > 1 set in the AA config doesn't mean we're
// always rendering with MSAA, so we need to derive MS ratio from the CB and DB
// settings.
u32 num_samples = 1u;
if (color_control.mode != ColorControl::OperationMode::Disable) {
for (auto cb = 0u; cb < NumColorBuffers; ++cb) {
const auto& col_buf = color_buffers[cb];
if (!col_buf) {
continue;
}
num_samples = std::max(num_samples, col_buf.NumSamples());
}
}
if (depth_buffer.DepthValid() || depth_buffer.StencilValid()) {
num_samples = std::max(num_samples, depth_buffer.NumSamples());
}
return num_samples;
}
void SetDefaults(); void SetDefaults();
}; };

View File

@ -126,6 +126,7 @@ enum class TilingMode : u32 {
Display_MacroTiled = 0xAu, Display_MacroTiled = 0xAu,
Texture_MicroTiled = 0xDu, Texture_MicroTiled = 0xDu,
Texture_MacroTiled = 0xEu, Texture_MacroTiled = 0xEu,
Texture_Volume = 0x13u,
}; };
constexpr std::string_view NameOf(TilingMode type) { constexpr std::string_view NameOf(TilingMode type) {
@ -140,6 +141,8 @@ constexpr std::string_view NameOf(TilingMode type) {
return "Texture_MicroTiled"; return "Texture_MicroTiled";
case TilingMode::Texture_MacroTiled: case TilingMode::Texture_MacroTiled:
return "Texture_MacroTiled"; return "Texture_MacroTiled";
case TilingMode::Texture_Volume:
return "Texture_Volume";
default: default:
return "Unknown"; return "Unknown";
} }
@ -294,9 +297,6 @@ struct Image {
return tiling_index == 5 ? TilingMode::Texture_MicroTiled return tiling_index == 5 ? TilingMode::Texture_MicroTiled
: TilingMode::Depth_MacroTiled; : TilingMode::Depth_MacroTiled;
} }
if (tiling_index == 0x13) {
return TilingMode::Texture_MicroTiled;
}
return static_cast<TilingMode>(tiling_index); return static_cast<TilingMode>(tiling_index);
} }

View File

@ -235,25 +235,26 @@ bool BufferCache::BindVertexBuffers(
} }
u32 BufferCache::BindIndexBuffer(bool& is_indexed, u32 index_offset) { u32 BufferCache::BindIndexBuffer(bool& is_indexed, u32 index_offset) {
// Emulate QuadList primitive type with CPU made index buffer. // Emulate QuadList and Polygon primitive types with CPU made index buffer.
const auto& regs = liverpool->regs; const auto& regs = liverpool->regs;
if (regs.primitive_type == AmdGpu::PrimitiveType::QuadList && !is_indexed) { if (!is_indexed) {
is_indexed = true; if (regs.primitive_type != AmdGpu::PrimitiveType::Polygon) {
return regs.num_indices;
}
// Emit indices. // Emit indices.
const u32 index_size = 3 * regs.num_indices; const u32 index_size = 3 * regs.num_indices;
const auto [data, offset] = stream_buffer.Map(index_size); const auto [data, offset] = stream_buffer.Map(index_size);
Vulkan::LiverpoolToVK::EmitQuadToTriangleListIndices(data, regs.num_indices); Vulkan::LiverpoolToVK::EmitPolygonToTriangleListIndices(data, regs.num_indices);
stream_buffer.Commit(); stream_buffer.Commit();
// Bind index buffer. // Bind index buffer.
is_indexed = true;
const auto cmdbuf = scheduler.CommandBuffer(); const auto cmdbuf = scheduler.CommandBuffer();
cmdbuf.bindIndexBuffer(stream_buffer.Handle(), offset, vk::IndexType::eUint16); cmdbuf.bindIndexBuffer(stream_buffer.Handle(), offset, vk::IndexType::eUint16);
return index_size / sizeof(u16); return index_size / sizeof(u16);
} }
if (!is_indexed) {
return regs.num_indices;
}
// Figure out index type and size. // Figure out index type and size.
const bool is_index16 = const bool is_index16 =
@ -263,30 +264,8 @@ u32 BufferCache::BindIndexBuffer(bool& is_indexed, u32 index_offset) {
VAddr index_address = regs.index_base_address.Address<VAddr>(); VAddr index_address = regs.index_base_address.Address<VAddr>();
index_address += index_offset * index_size; index_address += index_offset * index_size;
if (regs.primitive_type == AmdGpu::PrimitiveType::QuadList) { if (regs.primitive_type == AmdGpu::PrimitiveType::Polygon) {
// Convert indices. UNREACHABLE();
const u32 new_index_size = regs.num_indices * index_size * 6 / 4;
const auto [data, offset] = stream_buffer.Map(new_index_size);
const auto index_ptr = reinterpret_cast<u8*>(index_address);
switch (index_type) {
case vk::IndexType::eUint16:
Vulkan::LiverpoolToVK::ConvertQuadToTriangleListIndices<u16>(data, index_ptr,
regs.num_indices);
break;
case vk::IndexType::eUint32:
Vulkan::LiverpoolToVK::ConvertQuadToTriangleListIndices<u32>(data, index_ptr,
regs.num_indices);
break;
default:
UNREACHABLE_MSG("Unsupported QuadList index type {}", vk::to_string(index_type));
break;
}
stream_buffer.Commit();
// Bind index buffer.
const auto cmdbuf = scheduler.CommandBuffer();
cmdbuf.bindIndexBuffer(stream_buffer.Handle(), offset, index_type);
return new_index_size / index_size;
} }
// Bind index buffer. // Bind index buffer.

View File

@ -7,6 +7,8 @@ set(SHADER_FILES
detile_m32x1.comp detile_m32x1.comp
detile_m32x2.comp detile_m32x2.comp
detile_m32x4.comp detile_m32x4.comp
detile_macro32x1.comp
detile_macro32x2.comp
fs_tri.vert fs_tri.vert
post_process.frag post_process.frag
) )

View File

@ -15,6 +15,7 @@ layout(std430, binding = 1) buffer output_buf {
layout(push_constant) uniform image_info { layout(push_constant) uniform image_info {
uint num_levels; uint num_levels;
uint pitch; uint pitch;
uint height;
uint sizes[14]; uint sizes[14];
} info; } info;

View File

@ -15,6 +15,7 @@ layout(std430, binding = 1) buffer output_buf {
layout(push_constant) uniform image_info { layout(push_constant) uniform image_info {
uint num_levels; uint num_levels;
uint pitch; uint pitch;
uint height;
uint sizes[14]; uint sizes[14];
} info; } info;

View File

@ -15,6 +15,7 @@ layout(std430, binding = 1) buffer output_buf {
layout(push_constant) uniform image_info { layout(push_constant) uniform image_info {
uint num_levels; uint num_levels;
uint pitch; uint pitch;
uint height;
uint sizes[14]; uint sizes[14];
} info; } info;

View File

@ -18,6 +18,7 @@ layout(std430, binding = 1) buffer output_buf {
layout(push_constant) uniform image_info { layout(push_constant) uniform image_info {
uint num_levels; uint num_levels;
uint pitch; uint pitch;
uint height;
uint sizes[14]; uint sizes[14];
} info; } info;

View File

@ -17,6 +17,7 @@ layout(std430, binding = 1) buffer output_buf {
layout(push_constant) uniform image_info { layout(push_constant) uniform image_info {
uint num_levels; uint num_levels;
uint pitch; uint pitch;
uint height;
uint sizes[14]; uint sizes[14];
} info; } info;

View File

@ -0,0 +1,90 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#version 450
layout (local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
layout(std430, binding = 0) buffer input_buf {
uint in_data[];
};
layout(std430, binding = 1) buffer output_buf {
uint out_data[];
};
layout(push_constant) uniform image_info {
uint num_levels;
uint pitch;
uint height;
uint c0;
uint c1;
} info;
// Each LUT is 64 bytes, so should fit into K$ given tiled slices locality
const uint lut_32bpp[][64] = {
{
0x00, 0x01, 0x04, 0x05, 0x40, 0x41, 0x44, 0x45,
0x02, 0x03, 0x06, 0x07, 0x42, 0x43, 0x46, 0x47,
0x10, 0x11, 0x14, 0x15, 0x50, 0x51, 0x54, 0x55,
0x12, 0x13, 0x16, 0x17, 0x52, 0x53, 0x56, 0x57,
0x80, 0x81, 0x84, 0x85, 0xc0, 0xc1, 0xc4, 0xc5,
0x82, 0x83, 0x86, 0x87, 0xc2, 0xc3, 0xc6, 0xc7,
0x90, 0x91, 0x94, 0x95, 0xd0, 0xd1, 0xd4, 0xd5,
0x92, 0x93, 0x96, 0x97, 0xd2, 0xd3, 0xd6, 0xd7,
},
{
0x08, 0x09, 0x0c, 0x0d, 0x48, 0x49, 0x4c, 0x4d,
0x0a, 0x0b, 0x0e, 0x0f, 0x4a, 0x4b, 0x4e, 0x4f,
0x18, 0x19, 0x1c, 0x1d, 0x58, 0x59, 0x5c, 0x5d,
0x1a, 0x1b, 0x1e, 0x1f, 0x5a, 0x5b, 0x5e, 0x5f,
0x88, 0x89, 0x8c, 0x8d, 0xc8, 0xc9, 0xcc, 0xcd,
0x8a, 0x8b, 0x8e, 0x8f, 0xca, 0xcb, 0xce, 0xcf,
0x98, 0x99, 0x9c, 0x9d, 0xd8, 0xd9, 0xdc, 0xdd,
0x9a, 0x9b, 0x9e, 0x9f, 0xda, 0xdb, 0xde, 0xdf,
},
{
0x20, 0x21, 0x24, 0x25, 0x60, 0x61, 0x64, 0x65,
0x22, 0x23, 0x26, 0x27, 0x62, 0x63, 0x66, 0x67,
0x30, 0x31, 0x34, 0x35, 0x70, 0x71, 0x74, 0x75,
0x32, 0x33, 0x36, 0x37, 0x72, 0x73, 0x76, 0x77,
0xa0, 0xa1, 0xa4, 0xa5, 0xe0, 0xe1, 0xe4, 0xe5,
0xa2, 0xa3, 0xa6, 0xa7, 0xe2, 0xe3, 0xe6, 0xe7,
0xb0, 0xb1, 0xb4, 0xb5, 0xf0, 0xf1, 0xf4, 0xf5,
0xb2, 0xb3, 0xb6, 0xb7, 0xf2, 0xf3, 0xf6, 0xf7,
},
{
0x28, 0x29, 0x2c, 0x2d, 0x68, 0x69, 0x6c, 0x6d,
0x2a, 0x2b, 0x2e, 0x2f, 0x6a, 0x6b, 0x6e, 0x6f,
0x38, 0x39, 0x3c, 0x3d, 0x78, 0x79, 0x7c, 0x7d,
0x3a, 0x3b, 0x3e, 0x3f, 0x7a, 0x7b, 0x7e, 0x7f,
0xa8, 0xa9, 0xac, 0xad, 0xe8, 0xe9, 0xec, 0xed,
0xaa, 0xab, 0xae, 0xaf, 0xea, 0xeb, 0xee, 0xef,
0xb8, 0xb9, 0xbc, 0xbd, 0xf8, 0xf9, 0xfc, 0xfd,
0xba, 0xbb, 0xbe, 0xbf, 0xfa, 0xfb, 0xfe, 0xff,
}
};
#define MICRO_TILE_DIM (8)
#define MICRO_TILE_SZ (1024)
#define TEXELS_PER_ELEMENT (1)
#define BPP (32)
void main() {
uint x = gl_GlobalInvocationID.x % info.pitch;
uint y = (gl_GlobalInvocationID.x / info.pitch) % info.height;
uint z = gl_GlobalInvocationID.x / (info.pitch * info.height);
uint col = bitfieldExtract(x, 0, 3);
uint row = bitfieldExtract(y, 0, 3);
uint lut = bitfieldExtract(z, 0, 2);
uint idx = lut_32bpp[lut][col + row * MICRO_TILE_DIM];
uint slice_offs = (z >> 2u) * info.c1 * MICRO_TILE_SZ;
uint tile_row = y / MICRO_TILE_DIM;
uint tile_column = x / MICRO_TILE_DIM;
uint tile_offs = ((tile_row * info.c0) + tile_column) * MICRO_TILE_SZ;
uint offs = slice_offs + tile_offs + (idx * BPP / 8);
uint p0 = in_data[offs >> 2u];
out_data[gl_GlobalInvocationID.x] = p0;
}

View File

@ -0,0 +1,91 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#version 450
layout (local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
layout(std430, binding = 0) buffer input_buf {
uint in_data[];
};
layout(std430, binding = 1) buffer output_buf {
uint out_data[];
};
layout(push_constant) uniform image_info {
uint num_levels;
uint pitch;
uint height;
uint c0;
uint c1;
} info;
const uint lut_64bpp[][64] = {
{
0x00, 0x01, 0x08, 0x09, 0x40, 0x41, 0x48, 0x49,
0x02, 0x03, 0x0a, 0x0b, 0x42, 0x43, 0x4a, 0x4b,
0x10, 0x11, 0x18, 0x19, 0x50, 0x51, 0x58, 0x59,
0x12, 0x13, 0x1a, 0x1b, 0x52, 0x53, 0x5a, 0x5b,
0x80, 0x81, 0x88, 0x89, 0xc0, 0xc1, 0xc8, 0xc9,
0x82, 0x83, 0x8a, 0x8b, 0xc2, 0xc3, 0xca, 0xcb,
0x90, 0x91, 0x98, 0x99, 0xd0, 0xd1, 0xd8, 0xd9,
0x92, 0x93, 0x9a, 0x9b, 0xd2, 0xd3, 0xda, 0xdb,
},
{
0x04, 0x05, 0x0c, 0x0d, 0x44, 0x45, 0x4c, 0x4d,
0x06, 0x07, 0x0e, 0x0f, 0x46, 0x47, 0x4e, 0x4f,
0x14, 0x15, 0x1c, 0x1d, 0x54, 0x55, 0x5c, 0x5d,
0x16, 0x17, 0x1e, 0x1f, 0x56, 0x57, 0x5e, 0x5f,
0x84, 0x85, 0x8c, 0x8d, 0xc4, 0xc5, 0xcc, 0xcd,
0x86, 0x87, 0x8e, 0x8f, 0xc6, 0xc7, 0xce, 0xcf,
0x94, 0x95, 0x9c, 0x9d, 0xd4, 0xd5, 0xdc, 0xdd,
0x96, 0x97, 0x9e, 0x9f, 0xd6, 0xd7, 0xde, 0xdf,
},
{
0x20, 0x21, 0x28, 0x29, 0x60, 0x61, 0x68, 0x69,
0x22, 0x23, 0x2a, 0x2b, 0x62, 0x63, 0x6a, 0x6b,
0x30, 0x31, 0x38, 0x39, 0x70, 0x71, 0x78, 0x79,
0x32, 0x33, 0x3a, 0x3b, 0x72, 0x73, 0x7a, 0x7b,
0xa0, 0xa1, 0xa8, 0xa9, 0xe0, 0xe1, 0xe8, 0xe9,
0xa2, 0xa3, 0xaa, 0xab, 0xe2, 0xe3, 0xea, 0xeb,
0xb0, 0xb1, 0xb8, 0xb9, 0xf0, 0xf1, 0xf8, 0xf9,
0xb2, 0xb3, 0xba, 0xbb, 0xf2, 0xf3, 0xfa, 0xfb,
},
{
0x24, 0x25, 0x2c, 0x2d, 0x64, 0x65, 0x6c, 0x6d,
0x26, 0x27, 0x2e, 0x2f, 0x66, 0x67, 0x6e, 0x6f,
0x34, 0x35, 0x3c, 0x3d, 0x74, 0x75, 0x7c, 0x7d,
0x36, 0x37, 0x3e, 0x3f, 0x76, 0x77, 0x7e, 0x7f,
0xa4, 0xa5, 0xac, 0xad, 0xe4, 0xe5, 0xec, 0xed,
0xa6, 0xa7, 0xae, 0xaf, 0xe6, 0xe7, 0xee, 0xef,
0xb4, 0xb5, 0xbc, 0xbd, 0xf4, 0xf5, 0xfc, 0xfd,
0xb6, 0xb7, 0xbe, 0xbf, 0xf6, 0xf7, 0xfe, 0xff,
},
};
#define MICRO_TILE_DIM (8)
#define MICRO_TILE_SZ (2048)
#define TEXELS_PER_ELEMENT (1)
#define BPP (64)
void main() {
uint x = gl_GlobalInvocationID.x % info.pitch;
uint y = (gl_GlobalInvocationID.x / info.pitch) % info.height;
uint z = gl_GlobalInvocationID.x / (info.pitch * info.height);
uint col = bitfieldExtract(x, 0, 3);
uint row = bitfieldExtract(y, 0, 3);
uint lut = bitfieldExtract(z, 0, 2);
uint idx = lut_64bpp[lut][col + row * MICRO_TILE_DIM];
uint slice_offs = (z >> 2u) * info.c1 * MICRO_TILE_SZ;
uint tile_row = y / MICRO_TILE_DIM;
uint tile_column = x / MICRO_TILE_DIM;
uint tile_offs = ((tile_row * info.c0) + tile_column) * MICRO_TILE_SZ;
uint offs = slice_offs + tile_offs + (idx * BPP / 8);
uint p0 = in_data[(offs >> 2) + 0];
uint p1 = in_data[(offs >> 2) + 1];
out_data[2 * gl_GlobalInvocationID.x + 0] = p0;
out_data[2 * gl_GlobalInvocationID.x + 1] = p1;
}

View File

@ -12,8 +12,14 @@ layout(push_constant) uniform settings {
float gamma; float gamma;
} pp; } pp;
const float cutoff = 0.0031308, a = 1.055, b = 0.055, d = 12.92;
vec3 gamma(vec3 rgb)
{
return mix(a * pow(rgb, vec3(1.0 / (2.4 + 1.0 - pp.gamma))) - b, d * rgb / pp.gamma, lessThan(rgb, vec3(cutoff)));
}
void main() void main()
{ {
vec4 color_linear = texture(texSampler, uv); vec4 color_linear = texture(texSampler, uv);
color = pow(color_linear, vec4(1.0/(2.2 + 1.0 - pp.gamma))); color = vec4(gamma(color_linear.rgb), color_linear.a);
} }

View File

@ -116,11 +116,12 @@ vk::PrimitiveTopology PrimitiveType(AmdGpu::PrimitiveType type) {
return vk::PrimitiveTopology::eTriangleStripWithAdjacency; return vk::PrimitiveTopology::eTriangleStripWithAdjacency;
case AmdGpu::PrimitiveType::PatchPrimitive: case AmdGpu::PrimitiveType::PatchPrimitive:
return vk::PrimitiveTopology::ePatchList; return vk::PrimitiveTopology::ePatchList;
case AmdGpu::PrimitiveType::QuadList: case AmdGpu::PrimitiveType::Polygon:
// Needs to generate index buffer on the fly. // Needs to generate index buffer on the fly.
return vk::PrimitiveTopology::eTriangleList; return vk::PrimitiveTopology::eTriangleList;
case AmdGpu::PrimitiveType::QuadList:
case AmdGpu::PrimitiveType::RectList: case AmdGpu::PrimitiveType::RectList:
return vk::PrimitiveTopology::eTriangleStrip; return vk::PrimitiveTopology::ePatchList;
default: default:
UNREACHABLE(); UNREACHABLE();
return vk::PrimitiveTopology::eTriangleList; return vk::PrimitiveTopology::eTriangleList;

View File

@ -70,31 +70,12 @@ vk::ClearValue ColorBufferClearValue(const AmdGpu::Liverpool::ColorBuffer& color
vk::SampleCountFlagBits NumSamples(u32 num_samples, vk::SampleCountFlags supported_flags); vk::SampleCountFlagBits NumSamples(u32 num_samples, vk::SampleCountFlags supported_flags);
static constexpr u16 NumVerticesPerQuad = 4; inline void EmitPolygonToTriangleListIndices(u8* out_ptr, u32 num_vertices) {
inline void EmitQuadToTriangleListIndices(u8* out_ptr, u32 num_vertices) {
u16* out_data = reinterpret_cast<u16*>(out_ptr); u16* out_data = reinterpret_cast<u16*>(out_ptr);
for (u16 i = 0; i < num_vertices; i += NumVerticesPerQuad) { for (u16 i = 1; i < num_vertices - 1; i++) {
*out_data++ = 0;
*out_data++ = i; *out_data++ = i;
*out_data++ = i + 1; *out_data++ = i + 1;
*out_data++ = i + 2;
*out_data++ = i;
*out_data++ = i + 2;
*out_data++ = i + 3;
}
}
template <typename T>
void ConvertQuadToTriangleListIndices(u8* out_ptr, const u8* in_ptr, u32 num_vertices) {
T* out_data = reinterpret_cast<T*>(out_ptr);
const T* in_data = reinterpret_cast<const T*>(in_ptr);
for (u16 i = 0; i < num_vertices; i += NumVerticesPerQuad) {
*out_data++ = in_data[i];
*out_data++ = in_data[i + 1];
*out_data++ = in_data[i + 2];
*out_data++ = in_data[i];
*out_data++ = in_data[i + 2];
*out_data++ = in_data[i + 3];
} }
} }

View File

@ -58,7 +58,8 @@ ComputePipeline::ComputePipeline(const Instance& instance_, Scheduler& scheduler
for (const auto& image : info->images) { for (const auto& image : info->images) {
bindings.push_back({ bindings.push_back({
.binding = binding++, .binding = binding++,
.descriptorType = image.is_storage ? vk::DescriptorType::eStorageImage .descriptorType = image.IsStorage(image.GetSharp(*info))
? vk::DescriptorType::eStorageImage
: vk::DescriptorType::eSampledImage, : vk::DescriptorType::eSampledImage,
.descriptorCount = 1, .descriptorCount = 1,
.stageFlags = vk::ShaderStageFlagBits::eCompute, .stageFlags = vk::ShaderStageFlagBits::eCompute,

View File

@ -7,23 +7,28 @@
#include <boost/container/static_vector.hpp> #include <boost/container/static_vector.hpp>
#include "common/assert.h" #include "common/assert.h"
#include "common/io_file.h"
#include "common/scope_exit.h" #include "common/scope_exit.h"
#include "shader_recompiler/backend/spirv/emit_spirv_quad_rect.h"
#include "shader_recompiler/frontend/fetch_shader.h"
#include "shader_recompiler/runtime_info.h" #include "shader_recompiler/runtime_info.h"
#include "video_core/amdgpu/resource.h" #include "video_core/amdgpu/resource.h"
#include "video_core/buffer_cache/buffer_cache.h" #include "video_core/buffer_cache/buffer_cache.h"
#include "video_core/renderer_vulkan/vk_graphics_pipeline.h" #include "video_core/renderer_vulkan/vk_graphics_pipeline.h"
#include "shader_recompiler/frontend/fetch_shader.h"
#include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_shader_util.h"
#include "video_core/texture_cache/texture_cache.h" #include "video_core/texture_cache/texture_cache.h"
namespace Vulkan { namespace Vulkan {
GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& scheduler_, using Shader::Backend::SPIRV::AuxShaderType;
DescriptorHeap& desc_heap_, const GraphicsPipelineKey& key_,
vk::PipelineCache pipeline_cache, GraphicsPipeline::GraphicsPipeline(
const Instance& instance_, Scheduler& scheduler_, DescriptorHeap& desc_heap_,
const GraphicsPipelineKey& key_, vk::PipelineCache pipeline_cache,
std::span<const Shader::Info*, MaxShaderStages> infos, std::span<const Shader::Info*, MaxShaderStages> infos,
std::span<const Shader::RuntimeInfo, MaxShaderStages> runtime_infos,
std::optional<const Shader::Gcn::FetchShaderData> fetch_shader_, std::optional<const Shader::Gcn::FetchShaderData> fetch_shader_,
std::span<const vk::ShaderModule> modules) std::span<const vk::ShaderModule> modules)
: Pipeline{instance_, scheduler_, desc_heap_, pipeline_cache}, key{key_}, : Pipeline{instance_, scheduler_, desc_heap_, pipeline_cache}, key{key_},
@ -88,11 +93,6 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
.pVertexAttributeDescriptions = vertex_attributes.data(), .pVertexAttributeDescriptions = vertex_attributes.data(),
}; };
if (key.prim_type == AmdGpu::PrimitiveType::RectList && !IsEmbeddedVs()) {
LOG_WARNING(Render_Vulkan,
"Rectangle List primitive type is only supported for embedded VS");
}
auto prim_restart = key.enable_primitive_restart != 0; auto prim_restart = key.enable_primitive_restart != 0;
if (prim_restart && IsPrimitiveListTopology() && !instance.IsListRestartSupported()) { if (prim_restart && IsPrimitiveListTopology() && !instance.IsListRestartSupported()) {
LOG_WARNING(Render_Vulkan, LOG_WARNING(Render_Vulkan,
@ -106,9 +106,11 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
ASSERT_MSG(!prim_restart || key.primitive_restart_index == 0xFFFF || ASSERT_MSG(!prim_restart || key.primitive_restart_index == 0xFFFF ||
key.primitive_restart_index == 0xFFFFFFFF, key.primitive_restart_index == 0xFFFFFFFF,
"Primitive restart index other than -1 is not supported yet"); "Primitive restart index other than -1 is not supported yet");
const bool is_rect_list = key.prim_type == AmdGpu::PrimitiveType::RectList;
const bool is_quad_list = key.prim_type == AmdGpu::PrimitiveType::QuadList;
const auto& fs_info = runtime_infos[u32(Shader::LogicalStage::Fragment)].fs_info;
const vk::PipelineTessellationStateCreateInfo tessellation_state = { const vk::PipelineTessellationStateCreateInfo tessellation_state = {
.patchControlPoints = key.patch_control_points, .patchControlPoints = is_rect_list ? 3U : (is_quad_list ? 4U : key.patch_control_points),
}; };
const vk::PipelineRasterizationStateCreateInfo raster_state = { const vk::PipelineRasterizationStateCreateInfo raster_state = {
@ -121,7 +123,7 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
.frontFace = key.front_face == Liverpool::FrontFace::Clockwise .frontFace = key.front_face == Liverpool::FrontFace::Clockwise
? vk::FrontFace::eClockwise ? vk::FrontFace::eClockwise
: vk::FrontFace::eCounterClockwise, : vk::FrontFace::eCounterClockwise,
.depthBiasEnable = bool(key.depth_bias_enable), .depthBiasEnable = key.depth_bias_enable,
.lineWidth = 1.0f, .lineWidth = 1.0f,
}; };
@ -131,37 +133,24 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
.sampleShadingEnable = false, .sampleShadingEnable = false,
}; };
const vk::Viewport viewport = {
.x = 0.0f,
.y = 0.0f,
.width = 1.0f,
.height = 1.0f,
.minDepth = 0.0f,
.maxDepth = 1.0f,
};
const vk::Rect2D scissor = {
.offset = {0, 0},
.extent = {1, 1},
};
const vk::PipelineViewportDepthClipControlCreateInfoEXT clip_control = { const vk::PipelineViewportDepthClipControlCreateInfoEXT clip_control = {
.negativeOneToOne = key.clip_space == Liverpool::ClipSpace::MinusWToW, .negativeOneToOne = key.clip_space == Liverpool::ClipSpace::MinusWToW,
}; };
const vk::PipelineViewportStateCreateInfo viewport_info = { const vk::PipelineViewportStateCreateInfo viewport_info = {
.pNext = instance.IsDepthClipControlSupported() ? &clip_control : nullptr, .pNext = instance.IsDepthClipControlSupported() ? &clip_control : nullptr,
.viewportCount = 1,
.pViewports = &viewport,
.scissorCount = 1,
.pScissors = &scissor,
}; };
boost::container::static_vector<vk::DynamicState, 14> dynamic_states = { boost::container::static_vector<vk::DynamicState, 14> dynamic_states = {
vk::DynamicState::eViewport, vk::DynamicState::eScissor, vk::DynamicState::eViewportWithCountEXT,
vk::DynamicState::eBlendConstants, vk::DynamicState::eDepthBounds, vk::DynamicState::eScissorWithCountEXT,
vk::DynamicState::eDepthBias, vk::DynamicState::eStencilReference, vk::DynamicState::eBlendConstants,
vk::DynamicState::eStencilCompareMask, vk::DynamicState::eStencilWriteMask, vk::DynamicState::eDepthBounds,
vk::DynamicState::eDepthBias,
vk::DynamicState::eStencilReference,
vk::DynamicState::eStencilCompareMask,
vk::DynamicState::eStencilWriteMask,
vk::DynamicState::eStencilOpEXT,
}; };
if (instance.IsColorWriteEnableSupported()) { if (instance.IsColorWriteEnableSupported()) {
@ -180,31 +169,11 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
}; };
const vk::PipelineDepthStencilStateCreateInfo depth_info = { const vk::PipelineDepthStencilStateCreateInfo depth_info = {
.depthTestEnable = key.depth_stencil.depth_enable, .depthTestEnable = key.depth_test_enable,
.depthWriteEnable = key.depth_stencil.depth_write_enable, .depthWriteEnable = key.depth_write_enable,
.depthCompareOp = LiverpoolToVK::CompareOp(key.depth_stencil.depth_func), .depthCompareOp = key.depth_compare_op,
.depthBoundsTestEnable = key.depth_stencil.depth_bounds_enable, .depthBoundsTestEnable = key.depth_bounds_test_enable,
.stencilTestEnable = key.depth_stencil.stencil_enable, .stencilTestEnable = key.stencil_test_enable,
.front{
.failOp = LiverpoolToVK::StencilOp(key.stencil.stencil_fail_front),
.passOp = LiverpoolToVK::StencilOp(key.stencil.stencil_zpass_front),
.depthFailOp = LiverpoolToVK::StencilOp(key.stencil.stencil_zfail_front),
.compareOp = LiverpoolToVK::CompareOp(key.depth_stencil.stencil_ref_func),
},
.back{
.failOp = LiverpoolToVK::StencilOp(key.depth_stencil.backface_enable
? key.stencil.stencil_fail_back.Value()
: key.stencil.stencil_fail_front.Value()),
.passOp = LiverpoolToVK::StencilOp(key.depth_stencil.backface_enable
? key.stencil.stencil_zpass_back.Value()
: key.stencil.stencil_zpass_front.Value()),
.depthFailOp = LiverpoolToVK::StencilOp(key.depth_stencil.backface_enable
? key.stencil.stencil_zfail_back.Value()
: key.stencil.stencil_zfail_front.Value()),
.compareOp = LiverpoolToVK::CompareOp(key.depth_stencil.backface_enable
? key.depth_stencil.stencil_bf_func.Value()
: key.depth_stencil.stencil_ref_func.Value()),
},
}; };
boost::container::static_vector<vk::PipelineShaderStageCreateInfo, MaxShaderStages> boost::container::static_vector<vk::PipelineShaderStageCreateInfo, MaxShaderStages>
@ -232,6 +201,14 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
.module = modules[stage], .module = modules[stage],
.pName = "main", .pName = "main",
}); });
} else if (is_rect_list || is_quad_list) {
const auto type = is_quad_list ? AuxShaderType::QuadListTCS : AuxShaderType::RectListTCS;
auto tcs = Shader::Backend::SPIRV::EmitAuxilaryTessShader(type, fs_info);
shader_stages.emplace_back(vk::PipelineShaderStageCreateInfo{
.stage = vk::ShaderStageFlagBits::eTessellationControl,
.module = CompileSPV(tcs, instance.GetDevice()),
.pName = "main",
});
} }
stage = u32(Shader::LogicalStage::TessellationEval); stage = u32(Shader::LogicalStage::TessellationEval);
if (infos[stage]) { if (infos[stage]) {
@ -240,6 +217,14 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
.module = modules[stage], .module = modules[stage],
.pName = "main", .pName = "main",
}); });
} else if (is_rect_list || is_quad_list) {
auto tes =
Shader::Backend::SPIRV::EmitAuxilaryTessShader(AuxShaderType::PassthroughTES, fs_info);
shader_stages.emplace_back(vk::PipelineShaderStageCreateInfo{
.stage = vk::ShaderStageFlagBits::eTessellationEvaluation,
.module = CompileSPV(tes, instance.GetDevice()),
.pName = "main",
});
} }
stage = u32(Shader::LogicalStage::Fragment); stage = u32(Shader::LogicalStage::Fragment);
if (infos[stage]) { if (infos[stage]) {
@ -322,8 +307,7 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
.pStages = shader_stages.data(), .pStages = shader_stages.data(),
.pVertexInputState = !instance.IsVertexInputDynamicState() ? &vertex_input_info : nullptr, .pVertexInputState = !instance.IsVertexInputDynamicState() ? &vertex_input_info : nullptr,
.pInputAssemblyState = &input_assembly, .pInputAssemblyState = &input_assembly,
.pTessellationState = .pTessellationState = &tessellation_state,
stages[u32(Shader::LogicalStage::TessellationControl)] ? &tessellation_state : nullptr,
.pViewportState = &viewport_info, .pViewportState = &viewport_info,
.pRasterizationState = &raster_state, .pRasterizationState = &raster_state,
.pMultisampleState = &multisampling, .pMultisampleState = &multisampling,
@ -380,7 +364,8 @@ void GraphicsPipeline::BuildDescSetLayout() {
for (const auto& image : stage->images) { for (const auto& image : stage->images) {
bindings.push_back({ bindings.push_back({
.binding = binding++, .binding = binding++,
.descriptorType = image.is_storage ? vk::DescriptorType::eStorageImage .descriptorType = image.IsStorage(image.GetSharp(*stage))
? vk::DescriptorType::eStorageImage
: vk::DescriptorType::eSampledImage, : vk::DescriptorType::eSampledImage,
.descriptorCount = 1, .descriptorCount = 1,
.stageFlags = gp_stage_flags, .stageFlags = gp_stage_flags,

View File

@ -18,7 +18,7 @@ class TextureCache;
namespace Vulkan { namespace Vulkan {
static constexpr u32 MaxShaderStages = 5; static constexpr u32 MaxShaderStages = static_cast<u32>(Shader::LogicalStage::NumLogicalStages);
static constexpr u32 MaxVertexBufferCount = 32; static constexpr u32 MaxVertexBufferCount = 32;
class Instance; class Instance;
@ -36,11 +36,19 @@ struct GraphicsPipelineKey {
vk::Format depth_format; vk::Format depth_format;
vk::Format stencil_format; vk::Format stencil_format;
Liverpool::DepthControl depth_stencil; struct {
u32 depth_bias_enable; bool depth_test_enable : 1;
bool depth_write_enable : 1;
bool depth_bounds_test_enable : 1;
bool depth_bias_enable : 1;
bool stencil_test_enable : 1;
// Must be named to be zero-initialized.
u8 _unused : 3;
};
vk::CompareOp depth_compare_op;
u32 num_samples; u32 num_samples;
u32 mrt_mask; u32 mrt_mask;
Liverpool::StencilControl stencil;
AmdGpu::PrimitiveType prim_type; AmdGpu::PrimitiveType prim_type;
u32 enable_primitive_restart; u32 enable_primitive_restart;
u32 primitive_restart_index; u32 primitive_restart_index;
@ -64,6 +72,7 @@ public:
GraphicsPipeline(const Instance& instance, Scheduler& scheduler, DescriptorHeap& desc_heap, GraphicsPipeline(const Instance& instance, Scheduler& scheduler, DescriptorHeap& desc_heap,
const GraphicsPipelineKey& key, vk::PipelineCache pipeline_cache, const GraphicsPipelineKey& key, vk::PipelineCache pipeline_cache,
std::span<const Shader::Info*, MaxShaderStages> stages, std::span<const Shader::Info*, MaxShaderStages> stages,
std::span<const Shader::RuntimeInfo, MaxShaderStages> runtime_infos,
std::optional<const Shader::Gcn::FetchShaderData> fetch_shader, std::optional<const Shader::Gcn::FetchShaderData> fetch_shader,
std::span<const vk::ShaderModule> modules); std::span<const vk::ShaderModule> modules);
~GraphicsPipeline(); ~GraphicsPipeline();
@ -72,11 +81,6 @@ public:
return fetch_shader; return fetch_shader;
} }
bool IsEmbeddedVs() const noexcept {
static constexpr size_t EmbeddedVsHash = 0x9b2da5cf47f8c29f;
return key.stage_hashes[u32(Shader::LogicalStage::Vertex)] == EmbeddedVsHash;
}
auto GetWriteMasks() const { auto GetWriteMasks() const {
return key.write_masks; return key.write_masks;
} }
@ -85,10 +89,6 @@ public:
return key.mrt_mask; return key.mrt_mask;
} }
bool IsDepthEnabled() const {
return key.depth_stencil.depth_enable.Value();
}
[[nodiscard]] bool IsPrimitiveListTopology() const { [[nodiscard]] bool IsPrimitiveListTopology() const {
return key.prim_type == AmdGpu::PrimitiveType::PointList || return key.prim_type == AmdGpu::PrimitiveType::PointList ||
key.prim_type == AmdGpu::PrimitiveType::LineList || key.prim_type == AmdGpu::PrimitiveType::LineList ||

View File

@ -80,8 +80,8 @@ void GatherVertexOutputs(Shader::VertexRuntimeInfo& info,
: (ctl.IsCullDistEnabled(7) ? VsOutput::CullDist7 : VsOutput::None)); : (ctl.IsCullDistEnabled(7) ? VsOutput::CullDist7 : VsOutput::None));
} }
Shader::RuntimeInfo PipelineCache::BuildRuntimeInfo(Stage stage, LogicalStage l_stage) { const Shader::RuntimeInfo& PipelineCache::BuildRuntimeInfo(Stage stage, LogicalStage l_stage) {
auto info = Shader::RuntimeInfo{stage}; auto& info = runtime_infos[u32(l_stage)];
const auto& regs = liverpool->regs; const auto& regs = liverpool->regs;
const auto BuildCommon = [&](const auto& program) { const auto BuildCommon = [&](const auto& program) {
info.num_user_data = program.settings.num_user_regs; info.num_user_data = program.settings.num_user_regs;
@ -90,6 +90,7 @@ Shader::RuntimeInfo PipelineCache::BuildRuntimeInfo(Stage stage, LogicalStage l_
info.fp_denorm_mode32 = program.settings.fp_denorm_mode32; info.fp_denorm_mode32 = program.settings.fp_denorm_mode32;
info.fp_round_mode32 = program.settings.fp_round_mode32; info.fp_round_mode32 = program.settings.fp_round_mode32;
}; };
info.Initialize(stage);
switch (stage) { switch (stage) {
case Stage::Local: { case Stage::Local: {
BuildCommon(regs.ls_program); BuildCommon(regs.ls_program);
@ -204,7 +205,8 @@ PipelineCache::PipelineCache(const Instance& instance_, Scheduler& scheduler_,
.supports_image_load_store_lod = instance_.IsImageLoadStoreLodSupported(), .supports_image_load_store_lod = instance_.IsImageLoadStoreLodSupported(),
.needs_manual_interpolation = instance.IsFragmentShaderBarycentricSupported() && .needs_manual_interpolation = instance.IsFragmentShaderBarycentricSupported() &&
instance.GetDriverID() == vk::DriverId::eNvidiaProprietary, instance.GetDriverID() == vk::DriverId::eNvidiaProprietary,
.needs_lds_barriers = instance.GetDriverID() == vk::DriverId::eNvidiaProprietary, .needs_lds_barriers = instance.GetDriverID() == vk::DriverId::eNvidiaProprietary ||
instance.GetDriverID() == vk::DriverId::eMoltenvk,
}; };
auto [cache_result, cache] = instance.GetDevice().createPipelineCacheUnique({}); auto [cache_result, cache] = instance.GetDevice().createPipelineCacheUnique({});
ASSERT_MSG(cache_result == vk::Result::eSuccess, "Failed to create pipeline cache: {}", ASSERT_MSG(cache_result == vk::Result::eSuccess, "Failed to create pipeline cache: {}",
@ -220,9 +222,9 @@ const GraphicsPipeline* PipelineCache::GetGraphicsPipeline() {
} }
const auto [it, is_new] = graphics_pipelines.try_emplace(graphics_key); const auto [it, is_new] = graphics_pipelines.try_emplace(graphics_key);
if (is_new) { if (is_new) {
it.value() = it.value() = std::make_unique<GraphicsPipeline>(instance, scheduler, desc_heap,
std::make_unique<GraphicsPipeline>(instance, scheduler, desc_heap, graphics_key, graphics_key, *pipeline_cache, infos,
*pipeline_cache, infos, fetch_shader, modules); runtime_infos, fetch_shader, modules);
if (Config::collectShadersForDebug()) { if (Config::collectShadersForDebug()) {
for (auto stage = 0; stage < MaxShaderStages; ++stage) { for (auto stage = 0; stage < MaxShaderStages; ++stage) {
if (infos[stage]) { if (infos[stage]) {
@ -257,33 +259,31 @@ bool PipelineCache::RefreshGraphicsKey() {
auto& regs = liverpool->regs; auto& regs = liverpool->regs;
auto& key = graphics_key; auto& key = graphics_key;
key.depth_stencil = regs.depth_control; key.depth_test_enable = regs.depth_control.depth_enable;
key.depth_stencil.depth_write_enable.Assign(regs.depth_control.depth_write_enable.Value() && key.depth_write_enable =
!regs.depth_render_control.depth_clear_enable); regs.depth_control.depth_write_enable && !regs.depth_render_control.depth_clear_enable;
key.depth_bounds_test_enable = regs.depth_control.depth_bounds_enable;
key.depth_bias_enable = regs.polygon_control.NeedsBias(); key.depth_bias_enable = regs.polygon_control.NeedsBias();
key.depth_compare_op = LiverpoolToVK::CompareOp(regs.depth_control.depth_func);
key.stencil_test_enable = regs.depth_control.stencil_enable;
const auto& db = regs.depth_buffer; const auto depth_format = instance.GetSupportedFormat(
const auto ds_format = instance.GetSupportedFormat( LiverpoolToVK::DepthFormat(regs.depth_buffer.z_info.format,
LiverpoolToVK::DepthFormat(db.z_info.format, db.stencil_info.format), regs.depth_buffer.stencil_info.format),
vk::FormatFeatureFlagBits2::eDepthStencilAttachment); vk::FormatFeatureFlagBits2::eDepthStencilAttachment);
if (db.z_info.format != AmdGpu::Liverpool::DepthBuffer::ZFormat::Invalid) { if (regs.depth_buffer.DepthValid()) {
key.depth_format = ds_format; key.depth_format = depth_format;
} else { } else {
key.depth_format = vk::Format::eUndefined; key.depth_format = vk::Format::eUndefined;
key.depth_test_enable = false;
} }
if (regs.depth_control.depth_enable) { if (regs.depth_buffer.StencilValid()) {
key.depth_stencil.depth_enable.Assign(key.depth_format != vk::Format::eUndefined); key.stencil_format = depth_format;
}
key.stencil = regs.stencil_control;
if (db.stencil_info.format != AmdGpu::Liverpool::DepthBuffer::StencilFormat::Invalid) {
key.stencil_format = key.depth_format;
} else { } else {
key.stencil_format = vk::Format::eUndefined; key.stencil_format = vk::Format::eUndefined;
key.stencil_test_enable = false;
} }
if (key.depth_stencil.stencil_enable) {
key.depth_stencil.stencil_enable.Assign(key.stencil_format != vk::Format::eUndefined);
}
key.prim_type = regs.primitive_type; key.prim_type = regs.primitive_type;
key.enable_primitive_restart = regs.enable_primitive_restart & 1; key.enable_primitive_restart = regs.enable_primitive_restart & 1;
key.primitive_restart_index = regs.primitive_restart_index; key.primitive_restart_index = regs.primitive_restart_index;
@ -291,7 +291,7 @@ bool PipelineCache::RefreshGraphicsKey() {
key.cull_mode = regs.polygon_control.CullingMode(); key.cull_mode = regs.polygon_control.CullingMode();
key.clip_space = regs.clipper_control.clip_space; key.clip_space = regs.clipper_control.clip_space;
key.front_face = regs.polygon_control.front_face; key.front_face = regs.polygon_control.front_face;
key.num_samples = regs.aa_config.NumSamples(); key.num_samples = regs.NumSamples();
const bool skip_cb_binding = const bool skip_cb_binding =
regs.color_control.mode == AmdGpu::Liverpool::ColorControl::OperationMode::Disable; regs.color_control.mode == AmdGpu::Liverpool::ColorControl::OperationMode::Disable;
@ -437,8 +437,6 @@ bool PipelineCache::RefreshGraphicsKey() {
} }
} }
u32 num_samples = 1u;
// Second pass to fill remain CB pipeline key data // Second pass to fill remain CB pipeline key data
for (auto cb = 0u, remapped_cb = 0u; cb < Liverpool::NumColorBuffers; ++cb) { for (auto cb = 0u, remapped_cb = 0u; cb < Liverpool::NumColorBuffers; ++cb) {
auto const& col_buf = regs.color_buffers[cb]; auto const& col_buf = regs.color_buffers[cb];
@ -463,15 +461,8 @@ bool PipelineCache::RefreshGraphicsKey() {
key.write_masks[remapped_cb] = vk::ColorComponentFlags{regs.color_target_mask.GetMask(cb)}; key.write_masks[remapped_cb] = vk::ColorComponentFlags{regs.color_target_mask.GetMask(cb)};
key.cb_shader_mask.SetMask(remapped_cb, regs.color_shader_mask.GetMask(cb)); key.cb_shader_mask.SetMask(remapped_cb, regs.color_shader_mask.GetMask(cb));
++remapped_cb; ++remapped_cb;
num_samples = std::max(num_samples, 1u << col_buf.attrib.num_samples_log2);
} }
// It seems that the number of samples > 1 set in the AA config doesn't mean we're always
// rendering with MSAA, so we need to derive MS ratio from the CB settings.
num_samples = std::max(num_samples, regs.depth_buffer.NumSamples());
key.num_samples = num_samples;
return true; return true;
} // namespace Vulkan } // namespace Vulkan

View File

@ -76,7 +76,7 @@ private:
vk::ShaderModule CompileModule(Shader::Info& info, Shader::RuntimeInfo& runtime_info, vk::ShaderModule CompileModule(Shader::Info& info, Shader::RuntimeInfo& runtime_info,
std::span<const u32> code, size_t perm_idx, std::span<const u32> code, size_t perm_idx,
Shader::Backend::Bindings& binding); Shader::Backend::Bindings& binding);
Shader::RuntimeInfo BuildRuntimeInfo(Shader::Stage stage, Shader::LogicalStage l_stage); const Shader::RuntimeInfo& BuildRuntimeInfo(Shader::Stage stage, Shader::LogicalStage l_stage);
private: private:
const Instance& instance; const Instance& instance;
@ -90,6 +90,7 @@ private:
tsl::robin_map<size_t, std::unique_ptr<Program>> program_cache; tsl::robin_map<size_t, std::unique_ptr<Program>> program_cache;
tsl::robin_map<ComputePipelineKey, std::unique_ptr<ComputePipeline>> compute_pipelines; tsl::robin_map<ComputePipelineKey, std::unique_ptr<ComputePipeline>> compute_pipelines;
tsl::robin_map<GraphicsPipelineKey, std::unique_ptr<GraphicsPipeline>> graphics_pipelines; tsl::robin_map<GraphicsPipelineKey, std::unique_ptr<GraphicsPipeline>> graphics_pipelines;
std::array<Shader::RuntimeInfo, MaxShaderStages> runtime_infos{};
std::array<const Shader::Info*, MaxShaderStages> infos{}; std::array<const Shader::Info*, MaxShaderStages> infos{};
std::array<vk::ShaderModule, MaxShaderStages> modules{}; std::array<vk::ShaderModule, MaxShaderStages> modules{};
std::optional<Shader::Gcn::FetchShaderData> fetch_shader{}; std::optional<Shader::Gcn::FetchShaderData> fetch_shader{};

View File

@ -154,7 +154,7 @@ void Presenter::CreatePostProcessPipeline() {
const auto& fs_module = const auto& fs_module =
Vulkan::Compile(pp_shaders[1], vk::ShaderStageFlagBits::eFragment, instance.GetDevice()); Vulkan::Compile(pp_shaders[1], vk::ShaderStageFlagBits::eFragment, instance.GetDevice());
ASSERT(fs_module); ASSERT(fs_module);
Vulkan::SetObjectName(instance.GetDevice(), vs_module, "post_process.frag"); Vulkan::SetObjectName(instance.GetDevice(), fs_module, "post_process.frag");
const std::array shaders_ci{ const std::array shaders_ci{
vk::PipelineShaderStageCreateInfo{ vk::PipelineShaderStageCreateInfo{
@ -634,9 +634,11 @@ void Presenter::Present(Frame* frame) {
swapchain.Recreate(window.GetWidth(), window.GetHeight()); swapchain.Recreate(window.GetWidth(), window.GetHeight());
} }
ImGui::Core::NewFrame(); if (!swapchain.AcquireNextImage()) {
swapchain.Recreate(window.GetWidth(), window.GetHeight());
}
swapchain.AcquireNextImage(); ImGui::Core::NewFrame();
const vk::Image swapchain_image = swapchain.Image(); const vk::Image swapchain_image = swapchain.Image();
@ -731,7 +733,9 @@ void Presenter::Present(Frame* frame) {
// Present to swapchain. // Present to swapchain.
std::scoped_lock submit_lock{Scheduler::submit_mutex}; std::scoped_lock submit_lock{Scheduler::submit_mutex};
swapchain.Present(); if (!swapchain.Present()) {
swapchain.Recreate(window.GetWidth(), window.GetHeight());
}
// Free the frame for reuse // Free the frame for reuse
std::scoped_lock fl{free_mutex}; std::scoped_lock fl{free_mutex};

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