mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-08-05 08:52:36 +00:00
Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
7792fd0342
@ -16,7 +16,7 @@ if (NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Release)
|
||||
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.
|
||||
if(UNIX AND NOT APPLE)
|
||||
@ -392,7 +392,8 @@ set(USBD_LIB src/core/libraries/usbd/usbd.cpp
|
||||
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_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_integer.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_shared_memory.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)
|
||||
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)
|
||||
endif()
|
||||
|
||||
|
@ -25,7 +25,7 @@ Once you are within the installer:
|
||||
|
||||
Beware, this requires you to create a Qt account. If you do not want to do this, please follow the MSYS2/MinGW compilation method instead.
|
||||
|
||||
1. Under the current, non beta version of Qt (at the time of writing 6.7.3), select the option `MSVC 2022 64-bit` or similar.
|
||||
1. Under the current, non beta version of Qt (at the time of writing 6.7.3), select the option `MSVC 2022 64-bit` or similar, as well as `QT Multimedia`.
|
||||
If you are on Windows on ARM / Qualcomm Snapdragon Elite X, select `MSVC 2022 ARM64` instead.
|
||||
|
||||
Go through the installation normally. If you know what you are doing, you may unselect individual components that eat up too much disk space.
|
||||
|
6
externals/CMakeLists.txt
vendored
6
externals/CMakeLists.txt
vendored
@ -189,7 +189,11 @@ add_library(Dear_ImGui
|
||||
target_include_directories(Dear_ImGui INTERFACE dear_imgui/)
|
||||
|
||||
# Tracy
|
||||
option(TRACY_ENABLE "" ON)
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
option(TRACY_ENABLE "" OFF)
|
||||
else()
|
||||
option(TRACY_ENABLE "" ON)
|
||||
endif()
|
||||
option(TRACY_NO_CRASH_HANDLER "" ON) # Otherwise texture cache exceptions will be treaten as a crash
|
||||
option(TRACY_ON_DEMAND "" ON)
|
||||
option(TRACY_NO_FRAME_IMAGE "" ON)
|
||||
|
@ -34,6 +34,7 @@ namespace Config {
|
||||
static bool isNeo = false;
|
||||
static bool isFullscreen = false;
|
||||
static bool playBGM = false;
|
||||
static bool isTrophyPopupDisabled = false;
|
||||
static int BGMvolume = 50;
|
||||
static bool enableDiscordRPC = false;
|
||||
static u32 screenWidth = 1280;
|
||||
@ -64,6 +65,8 @@ static bool vkCrashDiagnostic = false;
|
||||
static s16 cursorState = HideCursorState::Idle;
|
||||
static int cursorHideTimeout = 5; // 5 seconds (default)
|
||||
static bool separateupdatefolder = false;
|
||||
static bool compatibilityData = false;
|
||||
static bool checkCompatibilityOnStartup = false;
|
||||
|
||||
// Gui
|
||||
std::vector<std::filesystem::path> settings_install_dirs = {};
|
||||
@ -96,6 +99,10 @@ bool isFullscreenMode() {
|
||||
return isFullscreen;
|
||||
}
|
||||
|
||||
bool getisTrophyPopupDisabled() {
|
||||
return isTrophyPopupDisabled;
|
||||
}
|
||||
|
||||
bool getPlayBGM() {
|
||||
return playBGM;
|
||||
}
|
||||
@ -224,6 +231,14 @@ bool getSeparateUpdateEnabled() {
|
||||
return separateupdatefolder;
|
||||
}
|
||||
|
||||
bool getCompatibilityEnabled() {
|
||||
return compatibilityData;
|
||||
}
|
||||
|
||||
bool getCheckCompatibilityOnStartup() {
|
||||
return checkCompatibilityOnStartup;
|
||||
}
|
||||
|
||||
void setGpuId(s32 selectedGpuId) {
|
||||
gpuId = selectedGpuId;
|
||||
}
|
||||
@ -284,6 +299,10 @@ void setFullscreenMode(bool enable) {
|
||||
isFullscreen = enable;
|
||||
}
|
||||
|
||||
void setisTrophyPopupDisabled(bool disable) {
|
||||
isTrophyPopupDisabled = disable;
|
||||
}
|
||||
|
||||
void setPlayBGM(bool enable) {
|
||||
playBGM = enable;
|
||||
}
|
||||
@ -344,6 +363,14 @@ void setSeparateUpdateEnabled(bool 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) {
|
||||
main_window_geometry_x = x;
|
||||
main_window_geometry_y = y;
|
||||
@ -531,6 +558,7 @@ void load(const std::filesystem::path& path) {
|
||||
isNeo = toml::find_or<bool>(general, "isPS4Pro", false);
|
||||
isFullscreen = toml::find_or<bool>(general, "Fullscreen", 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);
|
||||
enableDiscordRPC = toml::find_or<bool>(general, "enableDiscordRPC", true);
|
||||
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);
|
||||
isAutoUpdate = toml::find_or<bool>(general, "autoUpdate", 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")) {
|
||||
@ -646,6 +677,7 @@ void save(const std::filesystem::path& path) {
|
||||
|
||||
data["General"]["isPS4Pro"] = isNeo;
|
||||
data["General"]["Fullscreen"] = isFullscreen;
|
||||
data["General"]["isTrophyPopupDisabled"] = isTrophyPopupDisabled;
|
||||
data["General"]["playBGM"] = playBGM;
|
||||
data["General"]["BGMvolume"] = BGMvolume;
|
||||
data["General"]["enableDiscordRPC"] = enableDiscordRPC;
|
||||
@ -656,6 +688,8 @@ void save(const std::filesystem::path& path) {
|
||||
data["General"]["showSplash"] = isShowSplash;
|
||||
data["General"]["autoUpdate"] = isAutoUpdate;
|
||||
data["General"]["separateUpdateEnabled"] = separateupdatefolder;
|
||||
data["General"]["compatibilityEnabled"] = compatibilityData;
|
||||
data["General"]["checkCompatibilityOnStartup"] = checkCompatibilityOnStartup;
|
||||
data["Input"]["cursorState"] = cursorState;
|
||||
data["Input"]["cursorHideTimeout"] = cursorHideTimeout;
|
||||
data["Input"]["backButtonBehavior"] = backButtonBehavior;
|
||||
@ -740,6 +774,7 @@ void saveMainWindow(const std::filesystem::path& path) {
|
||||
void setDefaultValues() {
|
||||
isNeo = false;
|
||||
isFullscreen = false;
|
||||
isTrophyPopupDisabled = false;
|
||||
playBGM = false;
|
||||
BGMvolume = 50;
|
||||
enableDiscordRPC = true;
|
||||
@ -775,6 +810,8 @@ void setDefaultValues() {
|
||||
m_language = 1;
|
||||
gpuId = -1;
|
||||
separateupdatefolder = false;
|
||||
compatibilityData = false;
|
||||
checkCompatibilityOnStartup = false;
|
||||
}
|
||||
|
||||
constexpr std::string_view GetDefaultKeyboardConfig() {
|
||||
|
@ -19,8 +19,11 @@ bool isNeoMode();
|
||||
bool isFullscreenMode();
|
||||
bool getPlayBGM();
|
||||
int getBGMvolume();
|
||||
bool getisTrophyPopupDisabled();
|
||||
bool getEnableDiscordRPC();
|
||||
bool getSeparateUpdateEnabled();
|
||||
bool getCompatibilityEnabled();
|
||||
bool getCheckCompatibilityOnStartup();
|
||||
|
||||
std::string getLogFilter();
|
||||
std::string getLogType();
|
||||
@ -60,6 +63,7 @@ void setGpuId(s32 selectedGpuId);
|
||||
void setScreenWidth(u32 width);
|
||||
void setScreenHeight(u32 height);
|
||||
void setFullscreenMode(bool enable);
|
||||
void setisTrophyPopupDisabled(bool disable);
|
||||
void setPlayBGM(bool enable);
|
||||
void setBGMvolume(int volume);
|
||||
void setEnableDiscordRPC(bool enable);
|
||||
@ -69,6 +73,8 @@ void setUserName(const std::string& type);
|
||||
void setUpdateChannel(const std::string& type);
|
||||
void setSeparateUpdateEnabled(bool use);
|
||||
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 setCursorHideTimeout(int newcursorHideTimeout);
|
||||
|
@ -14,7 +14,11 @@
|
||||
#include <tracy/Tracy.hpp>
|
||||
|
||||
static inline bool IsProfilerConnected() {
|
||||
#if TRACY_ENABLE
|
||||
return tracy::GetProfiler().IsConnected();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#define TRACY_GPU_ENABLED 0
|
||||
|
@ -207,7 +207,7 @@ public:
|
||||
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);
|
||||
return out.Write(data);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
namespace Common {
|
||||
|
||||
constexpr char VERSION[] = "0.4.1 WIP";
|
||||
constexpr char VERSION[] = "0.5.1 WIP";
|
||||
constexpr bool isRelease = false;
|
||||
|
||||
} // namespace Common
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include "splash.h"
|
||||
|
||||
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);
|
||||
if (!file.IsOpen()) {
|
||||
|
@ -171,6 +171,9 @@ void HandleTable::DeleteHandle(int d) {
|
||||
|
||||
File* HandleTable::GetFile(int d) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
if (d < 0 || d >= m_files.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
return m_files.at(d);
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <shared_mutex>
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
|
||||
#include "common/assert.h"
|
||||
@ -13,7 +15,22 @@
|
||||
|
||||
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) {
|
||||
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() {
|
||||
LOG_ERROR(Lib_AudioOut, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
@ -110,8 +179,21 @@ int PS4_SYSV_ABI sceAudioOutChangeAppModuleState() {
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudioOutClose() {
|
||||
LOG_ERROR(Lib_AudioOut, "(STUBBED) called");
|
||||
int PS4_SYSV_ABI sceAudioOutClose(s32 handle) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -180,16 +262,21 @@ int PS4_SYSV_ABI sceAudioOutGetPortState(s32 handle, OrbisAudioOutPortState* sta
|
||||
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->volume = 127;
|
||||
|
||||
switch (type) {
|
||||
switch (port.type) {
|
||||
case OrbisAudioOutPort::Main:
|
||||
case OrbisAudioOutPort::Bgm:
|
||||
case OrbisAudioOutPort::Voice:
|
||||
state->output = 1;
|
||||
state->channel = (channels_num > 2 ? 2 : channels_num);
|
||||
state->channel = port.channels_num > 2 ? 2 : port.channels_num;
|
||||
break;
|
||||
case OrbisAudioOutPort::Personal:
|
||||
case OrbisAudioOutPort::Padspk:
|
||||
@ -276,7 +363,7 @@ s32 PS4_SYSV_ABI sceAudioOutOpen(UserService::OrbisUserServiceUserId user_id,
|
||||
u32 sample_rate,
|
||||
OrbisAudioOutParamExtendedInformation param_type) {
|
||||
LOG_INFO(Lib_AudioOut,
|
||||
"AudioOutOpen id = {} port_type = {} index = {} lenght= {} sample_rate = {} "
|
||||
"id = {} port_type = {} index = {} length = {} sample_rate = {} "
|
||||
"param_type = {} attr = {}",
|
||||
user_id, GetAudioOutPort(port_type), index, length, sample_rate,
|
||||
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");
|
||||
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() {
|
||||
@ -326,7 +432,15 @@ s32 PS4_SYSV_ABI sceAudioOutOutput(s32 handle, const void* ptr) {
|
||||
// Nothing to output
|
||||
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) {
|
||||
@ -431,7 +545,42 @@ s32 PS4_SYSV_ABI sceAudioOutSetVolume(s32 handle, s32 flag, s32* vol) {
|
||||
if (handle < 1 || handle > SCE_AUDIO_OUT_NUM_PORTS) {
|
||||
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() {
|
||||
|
@ -64,7 +64,7 @@ int PS4_SYSV_ABI sceAudioOutA3dExit();
|
||||
int PS4_SYSV_ABI sceAudioOutA3dInit();
|
||||
int PS4_SYSV_ABI sceAudioOutAttachToApplicationByPid();
|
||||
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 sceAudioOutExConfigureOutputMode();
|
||||
int PS4_SYSV_ABI sceAudioOutExGetSystemInfo();
|
||||
|
19
src/core/libraries/audio/audioout_backend.h
Normal file
19
src/core/libraries/audio/audioout_backend.h
Normal 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
|
@ -1,141 +1,44 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <mutex>
|
||||
#include <SDL3/SDL_audio.h>
|
||||
#include <SDL3/SDL_init.h>
|
||||
#include <SDL3/SDL_timer.h>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "core/libraries/audio/audioout_error.h"
|
||||
#include "core/libraries/audio/sdl_audio.h"
|
||||
|
||||
namespace Libraries::AudioOut {
|
||||
|
||||
constexpr int AUDIO_STREAM_BUFFER_THRESHOLD = 65536; // Define constant for buffer threshold
|
||||
|
||||
s32 SDLAudioOut::Open(OrbisAudioOutPort type, u32 samples_num, u32 freq,
|
||||
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);
|
||||
|
||||
void* SDLAudioOut::Open(bool is_float, int num_channels, u32 sample_rate) {
|
||||
SDL_AudioSpec fmt;
|
||||
SDL_zero(fmt);
|
||||
fmt.format = sampleFormat;
|
||||
fmt.channels = port->channels_num;
|
||||
fmt.freq = freq;
|
||||
port->stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &fmt, NULL, NULL);
|
||||
SDL_ResumeAudioDevice(SDL_GetAudioStreamDevice(port->stream));
|
||||
return std::distance(ports_out.begin(), port) + 1;
|
||||
fmt.format = is_float ? SDL_AUDIO_F32 : SDL_AUDIO_S16;
|
||||
fmt.channels = num_channels;
|
||||
fmt.freq = sample_rate;
|
||||
|
||||
auto* stream =
|
||||
SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &fmt, nullptr, nullptr);
|
||||
SDL_ResumeAudioStreamDevice(stream);
|
||||
return stream;
|
||||
}
|
||||
|
||||
s32 SDLAudioOut::Output(s32 handle, const void* ptr) {
|
||||
auto& port = ports_out.at(handle - 1);
|
||||
if (!port.is_open) {
|
||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
||||
}
|
||||
void SDLAudioOut::Close(void* impl) {
|
||||
SDL_DestroyAudioStream(static_cast<SDL_AudioStream*>(impl));
|
||||
}
|
||||
|
||||
const size_t data_size = port.samples_num * port.sample_size * port.channels_num;
|
||||
bool result = SDL_PutAudioStreamData(port.stream, ptr, data_size);
|
||||
while (SDL_GetAudioStreamAvailable(port.stream) > AUDIO_STREAM_BUFFER_THRESHOLD) {
|
||||
void SDLAudioOut::Output(void* impl, const void* ptr, size_t size) {
|
||||
auto* stream = static_cast<SDL_AudioStream*>(impl);
|
||||
SDL_PutAudioStreamData(stream, ptr, size);
|
||||
while (SDL_GetAudioStreamAvailable(stream) > AUDIO_STREAM_BUFFER_THRESHOLD) {
|
||||
SDL_Delay(0);
|
||||
}
|
||||
return result ? ORBIS_OK : -1;
|
||||
}
|
||||
|
||||
s32 SDLAudioOut::SetVolume(s32 handle, s32 bitflag, s32* volume) {
|
||||
using Libraries::AudioOut::OrbisAudioOutParamFormat;
|
||||
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;
|
||||
void SDLAudioOut::SetVolume(void* impl, std::array<int, 8> ch_volumes) {
|
||||
// Not yet implemented
|
||||
}
|
||||
|
||||
} // namespace Libraries::AudioOut
|
||||
|
@ -3,40 +3,16 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <shared_mutex>
|
||||
#include <SDL3/SDL_audio.h>
|
||||
#include "core/libraries/audio/audioout.h"
|
||||
#include "core/libraries/audio/audioout_backend.h"
|
||||
|
||||
namespace Libraries::AudioOut {
|
||||
|
||||
class SDLAudioOut {
|
||||
class SDLAudioOut final : public AudioOutBackend {
|
||||
public:
|
||||
explicit SDLAudioOut() = default;
|
||||
~SDLAudioOut() = default;
|
||||
|
||||
s32 Open(OrbisAudioOutPort type, u32 samples_num, u32 freq, OrbisAudioOutParamFormat format);
|
||||
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{};
|
||||
void* Open(bool is_float, int num_channels, u32 sample_rate) override;
|
||||
void Close(void* impl) override;
|
||||
void Output(void* impl, const void* ptr, size_t size) override;
|
||||
void SetVolume(void* impl, std::array<int, 8> ch_volumes) override;
|
||||
};
|
||||
|
||||
} // namespace Libraries::AudioOut
|
||||
|
@ -8,253 +8,455 @@
|
||||
#include "core/libraries/libs.h"
|
||||
#include "core/tls.h"
|
||||
|
||||
#ifdef _WIN64
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
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;
|
||||
thread_local void* gFiberThread = nullptr;
|
||||
static std::atomic<u32> context_size_check = false;
|
||||
|
||||
void FiberEntry(void* param) {
|
||||
SceFiber* fiber = static_cast<SceFiber*>(param);
|
||||
u64 argRun = 0;
|
||||
u64 argRet = 0;
|
||||
|
||||
gCurrentFiber = fiber;
|
||||
|
||||
if (fiber->pArgRun != nullptr) {
|
||||
argRun = *fiber->pArgRun;
|
||||
}
|
||||
|
||||
Core::ExecuteGuest(fiber->entry, fiber->argOnInitialize, argRun);
|
||||
UNREACHABLE();
|
||||
OrbisFiberContext* GetFiberContext() {
|
||||
return Core::GetTcbBase()->tcb_fiber;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberInitialize(SceFiber* fiber, const char* name, SceFiberEntry entry,
|
||||
u64 argOnInitialize, void* addrContext, u64 sizeContext,
|
||||
const SceFiberOptParam* optParam) {
|
||||
LOG_INFO(Lib_Fiber, "called: name = {}", name);
|
||||
extern "C" s32 PS4_SYSV_ABI _sceFiberSetJmp(OrbisFiberContext* ctx) asm("_sceFiberSetJmp");
|
||||
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);
|
||||
}
|
||||
|
||||
void PS4_SYSV_ABI _sceFiberCheckStackOverflow(OrbisFiberContext* ctx) {
|
||||
u64* stack_base = reinterpret_cast<u64*>(ctx->current_fiber->addr_context);
|
||||
if (stack_base && *stack_base != kFiberStackSignature) {
|
||||
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) {
|
||||
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);
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
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;
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberOptParamInitialize(SceFiberOptParam* optParam) {
|
||||
LOG_ERROR(Lib_Fiber, "called");
|
||||
|
||||
if (!optParam) {
|
||||
return ORBIS_FIBER_ERROR_NULL;
|
||||
/*
|
||||
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;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberFinalize(SceFiber* fiber) {
|
||||
LOG_TRACE(Lib_Fiber, "called");
|
||||
s32 PS4_SYSV_ABI sceFiberOptParamInitialize(OrbisFiberOptParam* opt_param) {
|
||||
if (!opt_param) {
|
||||
return ORBIS_FIBER_ERROR_NULL;
|
||||
}
|
||||
if ((u64)opt_param & 7) {
|
||||
return ORBIS_FIBER_ERROR_ALIGNMENT;
|
||||
}
|
||||
|
||||
opt_param->magic = kFiberOptSignature;
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberFinalize(OrbisFiber* fiber) {
|
||||
if (!fiber) {
|
||||
return ORBIS_FIBER_ERROR_NULL;
|
||||
}
|
||||
if ((u64)fiber % 8 != 0) {
|
||||
if ((u64)fiber & 7) {
|
||||
return ORBIS_FIBER_ERROR_ALIGNMENT;
|
||||
}
|
||||
if (fiber->signature != kFiberSignature) {
|
||||
if (fiber->magic_start != kFiberSignature0 || fiber->magic_end != kFiberSignature1) {
|
||||
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;
|
||||
}
|
||||
|
||||
fiber->signature = 0;
|
||||
fiber->state = FiberState::None;
|
||||
|
||||
#ifdef _WIN64
|
||||
DeleteFiber(fiber->handle);
|
||||
#else
|
||||
UNREACHABLE_MSG("Missing implementation");
|
||||
#endif
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberRun(SceFiber* fiber, u64 argOnRunTo, u64* argOnReturn) {
|
||||
LOG_TRACE(Lib_Fiber, "called");
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberRun(OrbisFiber* fiber, u64 arg_on_run_to, u64* arg_on_return) {
|
||||
if (!fiber) {
|
||||
return ORBIS_FIBER_ERROR_NULL;
|
||||
}
|
||||
if ((u64)fiber % 8 != 0) {
|
||||
if ((u64)fiber & 7) {
|
||||
return ORBIS_FIBER_ERROR_ALIGNMENT;
|
||||
}
|
||||
if (fiber->signature != kFiberSignature) {
|
||||
if (fiber->magic_start != kFiberSignature0 || fiber->magic_end != kFiberSignature1) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (gFiberThread == nullptr) {
|
||||
#ifdef _WIN64
|
||||
gFiberThread = ConvertThreadToFiber(nullptr);
|
||||
#else
|
||||
UNREACHABLE_MSG("Missing implementation");
|
||||
#endif
|
||||
OrbisFiberContext ctx{};
|
||||
ctx.current_fiber = fiber;
|
||||
ctx.prev_fiber = nullptr;
|
||||
ctx.return_val = 0;
|
||||
|
||||
tcb->tcb_fiber = &ctx;
|
||||
|
||||
s32 jmp = _sceFiberSetJmp(&ctx);
|
||||
if (!jmp) {
|
||||
if (fiber->addr_context) {
|
||||
_sceFiberSwitchToFiber(fiber, arg_on_run_to, &ctx);
|
||||
__builtin_trap();
|
||||
}
|
||||
|
||||
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 = nullptr;
|
||||
if (fiber->flags & FiberFlags::SetFpuRegs) {
|
||||
data.fpucw = 0x037f;
|
||||
data.mxcsr = 0x9fc0;
|
||||
_sceFiberSwitchEntry(&data, true);
|
||||
} else {
|
||||
_sceFiberSwitchEntry(&data, false);
|
||||
}
|
||||
}
|
||||
|
||||
gCurrentFiber = fiber;
|
||||
OrbisFiber* cur_fiber = ctx.current_fiber;
|
||||
ctx.current_fiber = nullptr;
|
||||
cur_fiber->state = FiberState::Idle;
|
||||
|
||||
if (fiber->pArgRun != nullptr) {
|
||||
*fiber->pArgRun = argOnRunTo;
|
||||
if (ctx.return_val != 0) {
|
||||
/* Fiber entry returned! This should never happen. */
|
||||
UNREACHABLE_MSG("Fiber entry function returned.");
|
||||
}
|
||||
|
||||
fiber->pArgReturn = argOnReturn;
|
||||
fiber->state = FiberState::Run;
|
||||
#ifdef _WIN64
|
||||
SwitchToFiber(fiber->handle);
|
||||
#else
|
||||
UNREACHABLE_MSG("Missing implementation");
|
||||
#endif
|
||||
if (arg_on_return) {
|
||||
*arg_on_return = ctx.arg_on_return;
|
||||
}
|
||||
|
||||
tcb->tcb_fiber = nullptr;
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberSwitch(SceFiber* fiber, u64 argOnRunTo, u64* argOnRun) {
|
||||
LOG_TRACE(Lib_Fiber, "called");
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberSwitch(OrbisFiber* fiber, u64 arg_on_run_to, u64* arg_on_run) {
|
||||
if (!fiber) {
|
||||
return ORBIS_FIBER_ERROR_NULL;
|
||||
}
|
||||
if ((u64)fiber % 8 != 0) {
|
||||
if ((u64)fiber & 7) {
|
||||
return ORBIS_FIBER_ERROR_ALIGNMENT;
|
||||
}
|
||||
if (fiber->signature != kFiberSignature) {
|
||||
if (fiber->magic_start != kFiberSignature0 || fiber->magic_end != kFiberSignature1) {
|
||||
return ORBIS_FIBER_ERROR_INVALID;
|
||||
}
|
||||
if (gCurrentFiber == nullptr) {
|
||||
|
||||
OrbisFiberContext* g_ctx = GetFiberContext();
|
||||
if (!g_ctx) {
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
fiber->state = FiberState::Run;
|
||||
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;
|
||||
}
|
||||
|
||||
gCurrentFiber = fiber;
|
||||
#ifdef _WIN64
|
||||
SwitchToFiber(fiber->handle);
|
||||
#else
|
||||
UNREACHABLE_MSG("Missing implementation");
|
||||
#endif
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberGetSelf(SceFiber** fiber) {
|
||||
LOG_TRACE(Lib_Fiber, "called");
|
||||
|
||||
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) {
|
||||
s32 PS4_SYSV_ABI sceFiberGetSelf(OrbisFiber** fiber) {
|
||||
if (!fiber) {
|
||||
return ORBIS_FIBER_ERROR_NULL;
|
||||
}
|
||||
|
||||
fiberInfo->entry = fiber->entry;
|
||||
fiberInfo->argOnInitialize = fiber->argOnInitialize;
|
||||
fiberInfo->addrContext = nullptr;
|
||||
fiberInfo->sizeContext = fiber->sizeContext;
|
||||
fiberInfo->sizeContextMargin = 0;
|
||||
OrbisFiberContext* g_ctx = GetFiberContext();
|
||||
if (!g_ctx) {
|
||||
return ORBIS_FIBER_ERROR_PERMISSION;
|
||||
}
|
||||
|
||||
*fiber = g_ctx->current_fiber;
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberReturnToThread(u64 arg_on_return, u64* arg_on_run) {
|
||||
OrbisFiberContext* g_ctx = GetFiberContext();
|
||||
if (!g_ctx) {
|
||||
return ORBIS_FIBER_ERROR_PERMISSION;
|
||||
}
|
||||
|
||||
OrbisFiber* cur_fiber = g_ctx->current_fiber;
|
||||
if (cur_fiber->addr_context) {
|
||||
OrbisFiberContext ctx{};
|
||||
s32 jmp = _sceFiberSetJmp(&ctx);
|
||||
if (jmp) {
|
||||
g_ctx = GetFiberContext();
|
||||
if (g_ctx->prev_fiber) {
|
||||
g_ctx->prev_fiber->state = FiberState::Idle;
|
||||
g_ctx->prev_fiber = nullptr;
|
||||
}
|
||||
if (arg_on_run) {
|
||||
*arg_on_run = g_ctx->arg_on_run_to;
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
cur_fiber->context = &ctx;
|
||||
_sceFiberCheckStackOverflow(g_ctx);
|
||||
}
|
||||
|
||||
_sceFiberTerminate(cur_fiber, arg_on_return, g_ctx);
|
||||
__builtin_trap();
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberGetInfo(OrbisFiber* fiber, OrbisFiberInfo* fiber_info) {
|
||||
if (!fiber || !fiber_info) {
|
||||
return ORBIS_FIBER_ERROR_NULL;
|
||||
}
|
||||
if ((u64)fiber & 7 || (u64)fiber_info & 7) {
|
||||
return ORBIS_FIBER_ERROR_ALIGNMENT;
|
||||
}
|
||||
if (fiber_info->size != sizeof(OrbisFiberInfo)) {
|
||||
return ORBIS_FIBER_ERROR_INVALID;
|
||||
}
|
||||
if (fiber->magic_start != kFiberSignature0 || fiber->magic_end != kFiberSignature1) {
|
||||
return ORBIS_FIBER_ERROR_INVALID;
|
||||
}
|
||||
|
||||
fiber_info->entry = fiber->entry;
|
||||
fiber_info->arg_on_initialize = fiber->arg_on_initialize;
|
||||
fiber_info->addr_context = fiber->addr_context;
|
||||
fiber_info->size_context = fiber->size_context;
|
||||
strncpy(fiber_info->name, fiber->name, ORBIS_FIBER_MAX_NAME_LENGTH);
|
||||
|
||||
fiber_info->size_context_margin = -1;
|
||||
if (fiber->flags & FiberFlags::ContextSizeCheck && fiber->addr_context != nullptr) {
|
||||
u64 stack_margin = 0;
|
||||
u64* stack_start = reinterpret_cast<u64*>(fiber->context_start);
|
||||
u64* stack_end = reinterpret_cast<u64*>(fiber->context_end);
|
||||
|
||||
if (*stack_start == kFiberStackSignature) {
|
||||
u64* stack_ptr = stack_start + 1;
|
||||
while (stack_ptr < stack_end) {
|
||||
if (*stack_ptr == kFiberStackSizeCheck) {
|
||||
stack_ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
stack_margin =
|
||||
reinterpret_cast<u64>(stack_ptr) - reinterpret_cast<u64>(stack_start + 1);
|
||||
}
|
||||
|
||||
fiber_info->size_context_margin = stack_margin;
|
||||
}
|
||||
|
||||
strncpy(fiberInfo->name, fiber->name, ORBIS_FIBER_MAX_NAME_LENGTH);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberStartContextSizeCheck(u32 flags) {
|
||||
LOG_ERROR(Lib_Fiber, "called");
|
||||
|
||||
if (flags != 0) {
|
||||
return ORBIS_FIBER_ERROR_INVALID;
|
||||
}
|
||||
|
||||
u32 expected = 0;
|
||||
if (!context_size_check.compare_exchange_strong(expected, 1u)) {
|
||||
return ORBIS_FIBER_ERROR_STATE;
|
||||
}
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberStopContextSizeCheck() {
|
||||
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;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberRename(SceFiber* fiber, const char* name) {
|
||||
LOG_INFO(Lib_Fiber, "called, name = {}", name);
|
||||
|
||||
s32 PS4_SYSV_ABI sceFiberRename(OrbisFiber* fiber, const char* name) {
|
||||
if (!fiber || !name) {
|
||||
return ORBIS_FIBER_ERROR_NULL;
|
||||
}
|
||||
if ((u64)fiber % 8 != 0) {
|
||||
if ((u64)fiber & 7) {
|
||||
return ORBIS_FIBER_ERROR_ALIGNMENT;
|
||||
}
|
||||
if (fiber->magic_start != kFiberSignature0 || fiber->magic_end != kFiberSignature1) {
|
||||
return ORBIS_FIBER_ERROR_INVALID;
|
||||
}
|
||||
|
||||
strncpy(fiber->name, name, ORBIS_FIBER_MAX_NAME_LENGTH);
|
||||
return ORBIS_OK;
|
||||
@ -262,6 +464,7 @@ s32 PS4_SYSV_ABI sceFiberRename(SceFiber* fiber, const char* name) {
|
||||
|
||||
void RegisterlibSceFiber(Core::Loader::SymbolsResolver* sym) {
|
||||
LIB_FUNCTION("hVYD7Ou2pCQ", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberInitialize);
|
||||
LIB_FUNCTION("7+OJIpko9RY", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberInitialize);
|
||||
LIB_FUNCTION("asjUJJ+aa8s", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberOptParamInitialize);
|
||||
LIB_FUNCTION("JeNX5F-NzQU", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberFinalize);
|
||||
|
||||
|
@ -6,73 +6,113 @@
|
||||
#include "common/assert.h"
|
||||
#include "common/types.h"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace Core::Loader {
|
||||
class SymbolsResolver;
|
||||
}
|
||||
namespace Libraries::Fiber {
|
||||
|
||||
#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 {
|
||||
None = 0u,
|
||||
Init = 1u,
|
||||
Run = 2u,
|
||||
Suspend = 3u,
|
||||
Run = 1u,
|
||||
Idle = 2u,
|
||||
Terminated = 3u,
|
||||
};
|
||||
|
||||
struct SceFiber {
|
||||
u64 signature;
|
||||
FiberState state;
|
||||
SceFiberEntry entry;
|
||||
u64 argOnInitialize;
|
||||
u64 argRun;
|
||||
u64* pArgRun;
|
||||
u64 argReturn;
|
||||
u64* pArgReturn;
|
||||
u64 sizeContext;
|
||||
char name[ORBIS_FIBER_MAX_NAME_LENGTH];
|
||||
void* handle;
|
||||
enum FiberFlags : u32 {
|
||||
None = 0x0,
|
||||
NoUlobjmgr = 0x1,
|
||||
ContextSizeCheck = 0x10,
|
||||
SetFpuRegs = 0x100,
|
||||
};
|
||||
static_assert(sizeof(SceFiber) <= 256);
|
||||
|
||||
struct SceFiberInfo {
|
||||
u64 size;
|
||||
SceFiberEntry entry;
|
||||
u64 argOnInitialize;
|
||||
void* addrContext;
|
||||
u64 sizeContext;
|
||||
struct OrbisFiber;
|
||||
|
||||
struct OrbisFiberContext {
|
||||
struct {
|
||||
u64 rax, rcx, rdx, rbx, rsp, rbp, r8, r9, r10, r11, r12, r13, r14, r15;
|
||||
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];
|
||||
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,
|
||||
u64 argOnInitialize, void* addrContext, u64 sizeContext,
|
||||
const SceFiberOptParam* optParam);
|
||||
struct OrbisFiberOptParam {
|
||||
u32 magic;
|
||||
};
|
||||
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 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);
|
||||
} // namespace Libraries::Fiber
|
121
src/core/libraries/fiber/fiber_context.s
Normal file
121
src/core/libraries/fiber/fiber_context.s
Normal 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
|
@ -1,6 +1,8 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/logging/log.h"
|
||||
|
@ -90,7 +90,7 @@ public:
|
||||
const auto start_time = std::chrono::high_resolution_clock::now();
|
||||
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 res = WaitForSingleObjectEx(sem, timeout_ms, true);
|
||||
if (res == WAIT_OBJECT_0) {
|
||||
@ -101,7 +101,7 @@ public:
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} while (rel_time_ms.count() > 0);
|
||||
|
||||
return false;
|
||||
#elif defined(__APPLE__)
|
||||
@ -117,12 +117,9 @@ public:
|
||||
bool try_acquire_until(const std::chrono::time_point<Clock, Duration>& abs_time) {
|
||||
#ifdef _WIN64
|
||||
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);
|
||||
while (rel_time.count() > 0) {
|
||||
do {
|
||||
u64 timeout_ms = static_cast<u64>(rel_time.count());
|
||||
u64 res = WaitForSingleObjectEx(sem, timeout_ms, true);
|
||||
if (res == WAIT_OBJECT_0) {
|
||||
@ -133,7 +130,7 @@ public:
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} while (rel_time.count() > 0);
|
||||
|
||||
return false;
|
||||
#elif defined(__APPLE__)
|
||||
|
@ -22,7 +22,7 @@ void SigactionHandler(int signum, siginfo_t* inf, ucontext_t* raw_context) {
|
||||
if (handler) {
|
||||
auto ctx = Ucontext{};
|
||||
#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_r9 = regs.__r9;
|
||||
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_gs = regs.__gs;
|
||||
#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_r9 = regs[REG_R9];
|
||||
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);
|
||||
ASSERT_MSG(signum == POSIX_SIGUSR1, "Attempting to raise non user defined signal!");
|
||||
#ifndef _WIN64
|
||||
pthread_t pthr = *reinterpret_cast<pthread_t*>(thread->native_thr.GetHandle());
|
||||
pthread_kill(pthr, SIGUSR2);
|
||||
const auto pthr = reinterpret_cast<pthread_t>(thread->native_thr.GetHandle());
|
||||
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
|
||||
USER_APC_OPTION option;
|
||||
option.UserApcFlags = QueueUserApcFlagsSpecialUserApc;
|
||||
|
@ -53,6 +53,7 @@ Core::Tcb* TcbCtor(Pthread* thread, int initial) {
|
||||
|
||||
if (tcb) {
|
||||
tcb->tcb_thread = thread;
|
||||
tcb->tcb_fiber = nullptr;
|
||||
}
|
||||
return tcb;
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <mutex>
|
||||
#include <imgui.h>
|
||||
#include "common/assert.h"
|
||||
#include "common/config.h"
|
||||
#include "common/singleton.h"
|
||||
#include "imgui/imgui_std.h"
|
||||
#include "trophy_ui.h"
|
||||
@ -82,7 +83,10 @@ void TrophyUI::Draw() {
|
||||
|
||||
void AddTrophyToQueue(const std::filesystem::path& trophyIconPath, const std::string& trophyName) {
|
||||
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;
|
||||
new_trophy.trophy_icon_path = trophyIconPath;
|
||||
new_trophy.trophy_name = trophyName;
|
||||
|
@ -11,6 +11,7 @@
|
||||
#else
|
||||
#include <csignal>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
namespace Core {
|
||||
|
@ -9,6 +9,10 @@ namespace Xbyak {
|
||||
class CodeGenerator;
|
||||
}
|
||||
|
||||
namespace Libraries::Fiber {
|
||||
struct OrbisFiberContext;
|
||||
}
|
||||
|
||||
namespace Core {
|
||||
|
||||
union DtvEntry {
|
||||
@ -20,6 +24,7 @@ struct Tcb {
|
||||
Tcb* tcb_self;
|
||||
DtvEntry* tcb_dtv;
|
||||
void* tcb_thread;
|
||||
::Libraries::Fiber::OrbisFiberContext* tcb_fiber;
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <QNetworkRequest>
|
||||
#include <QProcess>
|
||||
#include <QPushButton>
|
||||
#include <QStandardPaths>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QTextEdit>
|
||||
@ -212,9 +213,9 @@ void CheckUpdate::setupUI(const QString& downloadUrl, const QString& latestDate,
|
||||
|
||||
// Don't show changelog button if:
|
||||
// The current version is a pre-release and the version to be downloaded is a release.
|
||||
bool current_isRelease = currentRev.startsWith('v', Qt::CaseInsensitive);
|
||||
bool latest_isRelease = latestRev.startsWith('v', Qt::CaseInsensitive);
|
||||
if (!current_isRelease && latest_isRelease) {
|
||||
bool current_isWIP = currentRev.endsWith("WIP", Qt::CaseInsensitive);
|
||||
bool latest_isWIP = latestRev.endsWith("WIP", Qt::CaseInsensitive);
|
||||
if (current_isWIP && !latest_isWIP) {
|
||||
} else {
|
||||
QTextEdit* textField = new QTextEdit(this);
|
||||
textField->setReadOnly(true);
|
||||
@ -348,7 +349,9 @@ void CheckUpdate::DownloadUpdate(const QString& url) {
|
||||
QString userPath;
|
||||
Common::FS::PathToQString(userPath, Common::FS::GetUserPath(Common::FS::PathType::UserDir));
|
||||
#ifdef Q_OS_WIN
|
||||
QString tempDownloadPath = QString(getenv("LOCALAPPDATA")) + "/Temp/temp_download_update";
|
||||
QString tempDownloadPath =
|
||||
QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) +
|
||||
"/Temp/temp_download_update";
|
||||
#else
|
||||
QString tempDownloadPath = userPath + "/temp_download_update";
|
||||
#endif
|
||||
@ -397,10 +400,11 @@ void CheckUpdate::Install() {
|
||||
QString processCommand;
|
||||
|
||||
#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
|
||||
// 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
|
||||
scriptFileName = tempDirPath + "/update.ps1";
|
||||
@ -536,6 +540,7 @@ void CheckUpdate::Install() {
|
||||
QFile scriptFile(scriptFileName);
|
||||
if (scriptFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
QTextStream out(&scriptFile);
|
||||
scriptFile.write("\xEF\xBB\xBF");
|
||||
#ifdef Q_OS_WIN
|
||||
out << scriptContent.arg(binaryStartingUpdate).arg(tempDirPath).arg(rootPath);
|
||||
#endif
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <QFileInfo>
|
||||
#include <QMessageBox>
|
||||
#include <QProgressDialog>
|
||||
#include <QTimer>
|
||||
|
||||
#include "common/path_util.h"
|
||||
#include "compatibility_info.h"
|
||||
@ -17,12 +18,14 @@ CompatibilityInfoClass::CompatibilityInfoClass()
|
||||
};
|
||||
CompatibilityInfoClass::~CompatibilityInfoClass() = default;
|
||||
|
||||
void CompatibilityInfoClass::UpdateCompatibilityDatabase(QWidget* parent) {
|
||||
if (LoadCompatibilityFile())
|
||||
return;
|
||||
void CompatibilityInfoClass::UpdateCompatibilityDatabase(QWidget* parent, bool forced) {
|
||||
if (!forced)
|
||||
if (LoadCompatibilityFile())
|
||||
return;
|
||||
|
||||
QNetworkReply* reply = FetchPage(1);
|
||||
WaitForReply(reply);
|
||||
if (!WaitForReply(reply))
|
||||
return;
|
||||
|
||||
QProgressDialog dialog(tr("Fetching compatibility data, please wait"), tr("Cancel"), 0, 0,
|
||||
parent);
|
||||
@ -43,7 +46,8 @@ void CompatibilityInfoClass::UpdateCompatibilityDatabase(QWidget* parent) {
|
||||
QMessageBox::critical(parent, tr("Error"),
|
||||
tr("Unable to update compatibility data! Try again later."));
|
||||
// Try loading compatibility_file.json again
|
||||
LoadCompatibilityFile();
|
||||
if (!forced)
|
||||
LoadCompatibilityFile();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -57,12 +61,17 @@ void CompatibilityInfoClass::UpdateCompatibilityDatabase(QWidget* parent) {
|
||||
}
|
||||
|
||||
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++) {
|
||||
if (replies[i]->error() == QNetworkReply::NoError) {
|
||||
ExtractCompatibilityInfo(replies[i]->readAll());
|
||||
if (replies[i]->bytesAvailable()) {
|
||||
if (replies[i]->error() == QNetworkReply::NoError) {
|
||||
ExtractCompatibilityInfo(replies[i]->readAll());
|
||||
}
|
||||
replies[i]->deleteLater();
|
||||
} else {
|
||||
// This means the request timed out
|
||||
return;
|
||||
}
|
||||
replies[i]->deleteLater();
|
||||
}
|
||||
|
||||
QFile compatibility_file(m_compatibility_filename);
|
||||
@ -83,6 +92,16 @@ void CompatibilityInfoClass::UpdateCompatibilityDatabase(QWidget* parent) {
|
||||
|
||||
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);
|
||||
dialog.setRange(0, remaining_pages);
|
||||
connect(&future_watcher, &QFutureWatcher<void>::progressValueChanged, &dialog,
|
||||
@ -105,20 +124,34 @@ QNetworkReply* CompatibilityInfoClass::FetchPage(int page_num) {
|
||||
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;
|
||||
connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
||||
connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
|
||||
timer.start(5000);
|
||||
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) {
|
||||
QString title_id = QString::fromStdString(serial);
|
||||
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++) {
|
||||
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)) {
|
||||
QJsonObject compatibility_entry_obj = compatibility_obj[os_string].toObject();
|
||||
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() {
|
||||
|
@ -57,6 +57,7 @@ class CompatibilityInfoClass : public QObject {
|
||||
public:
|
||||
// Please think of a better alternative
|
||||
inline static const std::unordered_map<QString, CompatibilityStatus> LabelToCompatStatus = {
|
||||
{QStringLiteral("status-unknown"), CompatibilityStatus::Unknown},
|
||||
{QStringLiteral("status-nothing"), CompatibilityStatus::Nothing},
|
||||
{QStringLiteral("status-boots"), CompatibilityStatus::Boots},
|
||||
{QStringLiteral("status-menus"), CompatibilityStatus::Menus},
|
||||
@ -83,11 +84,11 @@ public:
|
||||
|
||||
CompatibilityInfoClass();
|
||||
~CompatibilityInfoClass();
|
||||
void UpdateCompatibilityDatabase(QWidget* parent = nullptr);
|
||||
void UpdateCompatibilityDatabase(QWidget* parent = nullptr, bool forced = false);
|
||||
bool LoadCompatibilityFile();
|
||||
CompatibilityEntry GetCompatibilityInfo(const std::string& serial);
|
||||
void ExtractCompatibilityInfo(QByteArray response);
|
||||
static void WaitForReply(QNetworkReply* reply);
|
||||
static bool WaitForReply(QNetworkReply* reply);
|
||||
QNetworkReply* FetchPage(int page_num);
|
||||
|
||||
private:
|
||||
|
@ -3,9 +3,12 @@
|
||||
|
||||
#include "common/path_util.h"
|
||||
#include "game_grid_frame.h"
|
||||
#include "qt_gui/compatibility_info.h"
|
||||
|
||||
GameGridFrame::GameGridFrame(std::shared_ptr<GameInfoClass> game_info_get, QWidget* parent)
|
||||
: QTableWidget(parent), m_game_info(game_info_get) {
|
||||
GameGridFrame::GameGridFrame(std::shared_ptr<GameInfoClass> 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();
|
||||
windowWidth = parent->width();
|
||||
this->setShowGrid(false);
|
||||
@ -29,7 +32,7 @@ GameGridFrame::GameGridFrame(std::shared_ptr<GameInfoClass> game_info_get, QWidg
|
||||
connect(this->horizontalScrollBar(), &QScrollBar::valueChanged, this,
|
||||
&GameGridFrame::RefreshGridBackgroundImage);
|
||||
connect(this, &QTableWidget::customContextMenuRequested, this, [=, this](const QPoint& pos) {
|
||||
m_gui_context_menus.RequestGameMenu(pos, m_game_info->m_games, this, false);
|
||||
m_gui_context_menus.RequestGameMenu(pos, m_game_info->m_games, m_compat_info, this, false);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "game_info.h"
|
||||
#include "game_list_utils.h"
|
||||
#include "gui_context_menus.h"
|
||||
#include "qt_gui/compatibility_info.h"
|
||||
|
||||
class GameGridFrame : public QTableWidget {
|
||||
Q_OBJECT
|
||||
@ -29,11 +30,14 @@ private:
|
||||
GameListUtils m_game_list_utils;
|
||||
GuiContextMenus m_gui_context_menus;
|
||||
std::shared_ptr<GameInfoClass> m_game_info;
|
||||
std::shared_ptr<CompatibilityInfoClass> m_compat_info;
|
||||
std::shared_ptr<QVector<GameInfo>> m_games_shared;
|
||||
bool validCellSelected = false;
|
||||
|
||||
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);
|
||||
bool IsValidCellSelected();
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <QToolTip>
|
||||
#include "common/config.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/path_util.h"
|
||||
#include "common/string_util.h"
|
||||
@ -72,7 +73,7 @@ GameListFrame::GameListFrame(std::shared_ptr<GameInfoClass> game_info_get,
|
||||
});
|
||||
|
||||
connect(this, &QTableWidget::customContextMenuRequested, this, [=, this](const QPoint& pos) {
|
||||
m_gui_context_menus.RequestGameMenu(pos, m_game_info->m_games, this, true);
|
||||
m_gui_context_menus.RequestGameMenu(pos, m_game_info->m_games, m_compat_info, this, true);
|
||||
});
|
||||
|
||||
connect(this, &QTableWidget::cellClicked, this, [=, this](int row, int column) {
|
||||
@ -103,6 +104,8 @@ void GameListFrame::PlayBackgroundMusic(QTableWidgetItem* item) {
|
||||
}
|
||||
|
||||
void GameListFrame::PopulateGameList() {
|
||||
// Do not show status column if it is not enabled
|
||||
this->setColumnHidden(2, !Config::getCompatibilityEnabled());
|
||||
this->setRowCount(m_game_info->m_games.size());
|
||||
ResizeIcons(icon_size);
|
||||
|
||||
@ -236,7 +239,7 @@ void GameListFrame::SetCompatibilityItem(int row, int column, CompatibilityEntry
|
||||
break;
|
||||
case CompatibilityStatus::Nothing:
|
||||
color = QStringLiteral("#212121");
|
||||
status_explanation = tr("Games does not initialize properly / crashes the emulator");
|
||||
status_explanation = tr("Game does not initialize properly / crashes the emulator");
|
||||
break;
|
||||
case CompatibilityStatus::Boots:
|
||||
color = QStringLiteral("#828282");
|
||||
|
@ -11,6 +11,9 @@
|
||||
#include <QTreeWidgetItem>
|
||||
|
||||
#include "cheats_patches.h"
|
||||
#include "common/config.h"
|
||||
#include "common/version.h"
|
||||
#include "compatibility_info.h"
|
||||
#include "game_info.h"
|
||||
#include "trophy_viewer.h"
|
||||
|
||||
@ -27,8 +30,9 @@
|
||||
class GuiContextMenus : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
void RequestGameMenu(const QPoint& pos, QVector<GameInfo> m_games, QTableWidget* widget,
|
||||
bool isList) {
|
||||
void RequestGameMenu(const QPoint& pos, QVector<GameInfo> m_games,
|
||||
std::shared_ptr<CompatibilityInfoClass> m_compat_info,
|
||||
QTableWidget* widget, bool isList) {
|
||||
QPoint global_pos = widget->viewport()->mapToGlobal(pos);
|
||||
int itemID = 0;
|
||||
if (isList) {
|
||||
@ -91,6 +95,21 @@ public:
|
||||
|
||||
menu.addMenu(deleteMenu);
|
||||
|
||||
// Compatibility submenu.
|
||||
QMenu* compatibilityMenu = new QMenu(tr("Compatibility..."), widget);
|
||||
QAction* updateCompatibility = new QAction(tr("Update database"), widget);
|
||||
QAction* viewCompatibilityReport = new QAction(tr("View report"), widget);
|
||||
QAction* submitCompatibilityReport = new QAction(tr("Submit a report"), widget);
|
||||
|
||||
compatibilityMenu->addAction(updateCompatibility);
|
||||
compatibilityMenu->addAction(viewCompatibilityReport);
|
||||
compatibilityMenu->addAction(submitCompatibilityReport);
|
||||
|
||||
menu.addMenu(compatibilityMenu);
|
||||
|
||||
compatibilityMenu->setEnabled(Config::getCompatibilityEnabled());
|
||||
viewCompatibilityReport->setEnabled(!m_games[itemID].compatibility.url.isEmpty());
|
||||
|
||||
// Show menu.
|
||||
auto selected = menu.exec(global_pos);
|
||||
if (!selected) {
|
||||
@ -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) {
|
||||
|
@ -144,7 +144,7 @@ void MainWindow::CreateDockWindows() {
|
||||
m_dock_widget.reset(new QDockWidget(tr("Game List"), this));
|
||||
m_game_list_frame.reset(new GameListFrame(m_game_info, m_compat_info, this));
|
||||
m_game_list_frame->setObjectName("gamelist");
|
||||
m_game_grid_frame.reset(new GameGridFrame(m_game_info, this));
|
||||
m_game_grid_frame.reset(new GameGridFrame(m_game_info, m_compat_info, this));
|
||||
m_game_grid_frame->setObjectName("gamegridlist");
|
||||
m_elf_viewer.reset(new ElfViewer(this));
|
||||
m_elf_viewer->setObjectName("elflist");
|
||||
@ -189,7 +189,9 @@ void MainWindow::CreateDockWindows() {
|
||||
|
||||
void MainWindow::LoadGameLists() {
|
||||
// Update compatibility database
|
||||
m_compat_info->UpdateCompatibilityDatabase(this);
|
||||
if (Config::getCheckCompatibilityOnStartup()) {
|
||||
m_compat_info->UpdateCompatibilityDatabase(this);
|
||||
}
|
||||
// Get game info from game folders.
|
||||
m_game_info->GetGameInfo(this);
|
||||
if (isTableList) {
|
||||
@ -255,20 +257,26 @@ void MainWindow::CreateConnects() {
|
||||
&MainWindow::StartGame);
|
||||
|
||||
connect(ui->configureAct, &QAction::triggered, this, [this]() {
|
||||
auto settingsDialog = new SettingsDialog(m_physical_devices, this);
|
||||
auto settingsDialog = new SettingsDialog(m_physical_devices, m_compat_info, this);
|
||||
|
||||
connect(settingsDialog, &SettingsDialog::LanguageChanged, this,
|
||||
&MainWindow::OnLanguageChanged);
|
||||
|
||||
connect(settingsDialog, &SettingsDialog::CompatibilityChanged, this,
|
||||
&MainWindow::RefreshGameTable);
|
||||
|
||||
settingsDialog->exec();
|
||||
});
|
||||
|
||||
connect(ui->settingsButton, &QPushButton::clicked, this, [this]() {
|
||||
auto settingsDialog = new SettingsDialog(m_physical_devices, this);
|
||||
auto settingsDialog = new SettingsDialog(m_physical_devices, m_compat_info, this);
|
||||
|
||||
connect(settingsDialog, &SettingsDialog::LanguageChanged, this,
|
||||
&MainWindow::OnLanguageChanged);
|
||||
|
||||
connect(settingsDialog, &SettingsDialog::CompatibilityChanged, this,
|
||||
&MainWindow::RefreshGameTable);
|
||||
|
||||
settingsDialog->exec();
|
||||
});
|
||||
|
||||
@ -564,7 +572,6 @@ void MainWindow::CreateConnects() {
|
||||
}
|
||||
|
||||
void MainWindow::StartGame() {
|
||||
isGameRunning = true;
|
||||
BackgroundMusicPlayer::getInstance().stopMusic();
|
||||
QString gamePath = "";
|
||||
int table_mode = Config::getTableMode();
|
||||
@ -587,13 +594,12 @@ void MainWindow::StartGame() {
|
||||
}
|
||||
if (gamePath != "") {
|
||||
AddRecentFiles(gamePath);
|
||||
Core::Emulator emulator;
|
||||
const auto path = Common::FS::PathFromQString(gamePath);
|
||||
if (!std::filesystem::exists(path)) {
|
||||
QMessageBox::critical(nullptr, tr("Run Game"), QString(tr("Eboot.bin file not found")));
|
||||
return;
|
||||
}
|
||||
emulator.Run(path);
|
||||
StartEmulator(path);
|
||||
}
|
||||
}
|
||||
|
||||
@ -690,13 +696,12 @@ void MainWindow::BootGame() {
|
||||
QString(tr("Only one file can be selected!")));
|
||||
} else {
|
||||
std::filesystem::path path = Common::FS::PathFromQString(fileNames[0]);
|
||||
Core::Emulator emulator;
|
||||
if (!std::filesystem::exists(path)) {
|
||||
QMessageBox::critical(nullptr, tr("Run Game"),
|
||||
QString(tr("Eboot.bin file not found")));
|
||||
return;
|
||||
}
|
||||
emulator.Run(path);
|
||||
StartEmulator(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1050,12 +1055,11 @@ void MainWindow::CreateRecentGameActions() {
|
||||
connect(m_recent_files_group, &QActionGroup::triggered, this, [this](QAction* action) {
|
||||
auto gamePath = Common::FS::PathFromQString(action->text());
|
||||
AddRecentFiles(action->text()); // Update the list.
|
||||
Core::Emulator emulator;
|
||||
if (!std::filesystem::exists(gamePath)) {
|
||||
QMessageBox::critical(nullptr, tr("Run Game"), QString(tr("Eboot.bin file not found")));
|
||||
return;
|
||||
}
|
||||
emulator.Run(gamePath);
|
||||
StartEmulator(gamePath);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1104,3 +1108,22 @@ bool MainWindow::eventFilter(QObject* obj, QEvent* 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
|
||||
}
|
||||
|
@ -69,6 +69,7 @@ private:
|
||||
void LoadTranslation();
|
||||
void PlayBackgroundMusic();
|
||||
QIcon RecolorIcon(const QIcon& icon, bool isWhite);
|
||||
void StartEmulator(std::filesystem::path);
|
||||
bool isIconBlack = false;
|
||||
bool isTableList = true;
|
||||
bool isGameRunning = false;
|
||||
|
@ -6,6 +6,8 @@
|
||||
#include <QHoverEvent>
|
||||
|
||||
#include <common/version.h>
|
||||
#include "common/config.h"
|
||||
#include "qt_gui/compatibility_info.h"
|
||||
#ifdef ENABLE_DISCORD_RPC
|
||||
#include "common/discord_rpc_handler.h"
|
||||
#endif
|
||||
@ -54,7 +56,9 @@ QStringList languageNames = {"Arabic",
|
||||
const QVector<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};
|
||||
|
||||
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) {
|
||||
ui->setupUi(this);
|
||||
ui->tabWidgetSettings->setUsesScrollButtons(false);
|
||||
@ -140,6 +144,16 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices, QWidge
|
||||
ui->updaterGroupBox->setVisible(false);
|
||||
ui->GUIgroupBox->setMaximumSize(265, 16777215);
|
||||
#endif
|
||||
connect(ui->updateCompatibilityButton, &QPushButton::clicked, this,
|
||||
[this, parent, m_compat_info]() {
|
||||
m_compat_info->UpdateCompatibilityDatabase(this, true);
|
||||
emit CompatibilityChanged();
|
||||
});
|
||||
|
||||
connect(ui->enableCompatibilityCheckBox, &QCheckBox::stateChanged, this, [this](int state) {
|
||||
Config::setCompatibilityEnabled(state);
|
||||
emit CompatibilityChanged();
|
||||
});
|
||||
}
|
||||
|
||||
// Input TAB
|
||||
@ -194,6 +208,10 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices, QWidge
|
||||
ui->updaterGroupBox->installEventFilter(this);
|
||||
#endif
|
||||
ui->GUIgroupBox->installEventFilter(this);
|
||||
ui->disableTrophycheckBox->installEventFilter(this);
|
||||
ui->enableCompatibilityCheckBox->installEventFilter(this);
|
||||
ui->checkCompatibilityOnStartupCheckBox->installEventFilter(this);
|
||||
ui->updateCompatibilityButton->installEventFilter(this);
|
||||
|
||||
// Input
|
||||
ui->hideCursorGroupBox->installEventFilter(this);
|
||||
@ -263,6 +281,8 @@ void SettingsDialog::LoadValuesFromConfig() {
|
||||
ui->dumpShadersCheckBox->setChecked(toml::find_or<bool>(data, "GPU", "dumpShaders", false));
|
||||
ui->nullGpuCheckBox->setChecked(toml::find_or<bool>(data, "GPU", "nullGpu", 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->discordRPCCheckbox->setChecked(
|
||||
toml::find_or<bool>(data, "General", "enableDiscordRPC", true));
|
||||
@ -282,6 +302,10 @@ void SettingsDialog::LoadValuesFromConfig() {
|
||||
ui->vkSyncValidationCheckBox->setChecked(
|
||||
toml::find_or<bool>(data, "Vulkan", "validation_sync", 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
|
||||
ui->updateCheckBox->setChecked(toml::find_or<bool>(data, "General", "autoUpdate", false));
|
||||
@ -397,6 +421,14 @@ void SettingsDialog::updateNoteTextEdit(const QString& elementName) {
|
||||
#endif
|
||||
} else if (elementName == "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
|
||||
@ -485,6 +517,7 @@ void SettingsDialog::UpdateSettings() {
|
||||
Config::setBackButtonBehavior(TouchPadIndex[ui->backButtonBehaviorComboBox->currentIndex()]);
|
||||
Config::setNeoMode(ui->ps4proCheckBox->isChecked());
|
||||
Config::setFullscreenMode(ui->fullscreenCheckBox->isChecked());
|
||||
Config::setisTrophyPopupDisabled(ui->disableTrophycheckBox->isChecked());
|
||||
Config::setPlayBGM(ui->playBGMCheckBox->isChecked());
|
||||
Config::setNeoMode(ui->ps4proCheckBox->isChecked());
|
||||
Config::setLogType(ui->logTypeComboBox->currentText().toStdString());
|
||||
@ -509,6 +542,8 @@ void SettingsDialog::UpdateSettings() {
|
||||
Config::setRdocEnabled(ui->rdocCheckBox->isChecked());
|
||||
Config::setAutoUpdate(ui->updateCheckBox->isChecked());
|
||||
Config::setUpdateChannel(ui->updateComboBox->currentText().toStdString());
|
||||
Config::setCompatibilityEnabled(ui->enableCompatibilityCheckBox->isChecked());
|
||||
Config::setCheckCompatibilityOnStartup(ui->checkCompatibilityOnStartupCheckBox->isChecked());
|
||||
|
||||
#ifdef ENABLE_DISCORD_RPC
|
||||
auto* rpc = Common::Singleton<DiscordRPCHandler::RPC>::Instance();
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <span>
|
||||
#include <QDialog>
|
||||
#include <QGroupBox>
|
||||
@ -10,6 +11,7 @@
|
||||
|
||||
#include "common/config.h"
|
||||
#include "common/path_util.h"
|
||||
#include "qt_gui/compatibility_info.h"
|
||||
|
||||
namespace Ui {
|
||||
class SettingsDialog;
|
||||
@ -18,7 +20,9 @@ class SettingsDialog;
|
||||
class SettingsDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SettingsDialog(std::span<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();
|
||||
|
||||
bool eventFilter(QObject* obj, QEvent* event) override;
|
||||
@ -28,6 +32,7 @@ public:
|
||||
|
||||
signals:
|
||||
void LanguageChanged(const std::string& locale);
|
||||
void CompatibilityChanged();
|
||||
|
||||
private:
|
||||
void LoadValuesFromConfig();
|
||||
|
@ -11,7 +11,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>854</width>
|
||||
<width>900</width>
|
||||
<height>660</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -59,9 +59,9 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>832</width>
|
||||
<height>431</height>
|
||||
<y>-97</y>
|
||||
<width>815</width>
|
||||
<height>618</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
@ -306,7 +306,7 @@
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>275</width>
|
||||
<width>265</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
@ -469,6 +469,13 @@
|
||||
<property name="bottomMargin">
|
||||
<number>11</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="disableTrophycheckBox">
|
||||
<property name="text">
|
||||
<string>Disable Trophy Pop-ups</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="GUIMusicLayout">
|
||||
<property name="topMargin">
|
||||
@ -561,41 +568,94 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="GUIwidgetSpacer" native="true">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>61</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="EmptyTabLayoutRight">
|
||||
<item>
|
||||
<spacer name="emptyHorizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
<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="sizeHint" stdset="0">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
<property name="title">
|
||||
<string>Game Compatibility</string>
|
||||
</property>
|
||||
<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>
|
||||
<width>197</width>
|
||||
<height>28</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Update Compatibility Database</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="inputTab">
|
||||
<attribute name="title">
|
||||
@ -696,7 +756,7 @@
|
||||
<property name="bottomMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item alignment="Qt::AlignmentFlag::AlignHCenter">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="idleTimeoutSpinBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
|
@ -672,11 +672,36 @@
|
||||
<source>GUI Settings</source>
|
||||
<translation>إعدادات الواجهة</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="475"/>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="375"/>
|
||||
<source>Play title music</source>
|
||||
<translation>تشغيل موسيقى العنوان</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="394"/>
|
||||
<source>Volume</source>
|
||||
@ -1201,6 +1226,11 @@
|
||||
<source>GUIgroupBox</source>
|
||||
<translation>تشغيل موسيقى العنوان:\nإذا كانت اللعبة تدعم ذلك، قم بتمكين تشغيل موسيقى خاصة عند اختيار اللعبة في واجهة المستخدم.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="450"/>
|
||||
<source>hideCursorGroupBox</source>
|
||||
@ -1216,6 +1246,21 @@
|
||||
<source>backButtonBehaviorGroupBox</source>
|
||||
<translation>سلوك زر العودة:\nيضبط زر العودة في وحدة التحكم ليحاكي الضغط على الموضع المحدد على لوحة اللمس في PS4.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="70"/>
|
||||
<source>Never</source>
|
||||
@ -1329,6 +1374,11 @@
|
||||
<source>Serial</source>
|
||||
<translation>سيريال</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp"/>
|
||||
<source>Compatibility</source>
|
||||
<translation>Compatibility</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp" line="34"/>
|
||||
<source>Region</source>
|
||||
@ -1364,6 +1414,36 @@
|
||||
<source>Never Played</source>
|
||||
<translation>Never Played</translation>
|
||||
</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>
|
||||
<name>CheckUpdate</name>
|
||||
|
@ -672,11 +672,36 @@
|
||||
<source>GUI Settings</source>
|
||||
<translation>GUI-Indstillinger</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="475"/>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="375"/>
|
||||
<source>Play title music</source>
|
||||
<translation>Afspil titelsang</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="394"/>
|
||||
<source>Volume</source>
|
||||
@ -1201,6 +1226,11 @@
|
||||
<source>GUIgroupBox</source>
|
||||
<translation>Titelsmusikafspilning:\nHvis spillet understøtter det, aktiver speciel musik, når spillet vælges i brugergrænsefladen.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="450"/>
|
||||
<source>hideCursorGroupBox</source>
|
||||
@ -1216,6 +1246,21 @@
|
||||
<source>backButtonBehaviorGroupBox</source>
|
||||
<translation>Tilbageknap Adfærd:\nIndstiller controllerens tilbageknap til at efterligne tryk på den angivne position på PS4 berøringsflade.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="70"/>
|
||||
<source>Never</source>
|
||||
@ -1329,6 +1374,11 @@
|
||||
<source>Serial</source>
|
||||
<translation>Seriel</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp"/>
|
||||
<source>Compatibility</source>
|
||||
<translation>Compatibility</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp" line="34"/>
|
||||
<source>Region</source>
|
||||
@ -1364,6 +1414,36 @@
|
||||
<source>Never Played</source>
|
||||
<translation>Never Played</translation>
|
||||
</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>
|
||||
<name>CheckUpdate</name>
|
||||
|
@ -672,11 +672,36 @@
|
||||
<source>GUI Settings</source>
|
||||
<translation>GUI-Einstellungen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="475"/>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="375"/>
|
||||
<source>Play title music</source>
|
||||
<translation>Titelmusik abspielen</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="394"/>
|
||||
<source>Volume</source>
|
||||
@ -1201,6 +1226,11 @@
|
||||
<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>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="450"/>
|
||||
<source>hideCursorGroupBox</source>
|
||||
@ -1216,6 +1246,21 @@
|
||||
<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>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="70"/>
|
||||
<source>Never</source>
|
||||
@ -1329,6 +1374,11 @@
|
||||
<source>Serial</source>
|
||||
<translation>Seriennummer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp"/>
|
||||
<source>Compatibility</source>
|
||||
<translation>Compatibility</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp" line="34"/>
|
||||
<source>Region</source>
|
||||
@ -1364,6 +1414,36 @@
|
||||
<source>Never Played</source>
|
||||
<translation>Never Played</translation>
|
||||
</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>
|
||||
<name>CheckUpdate</name>
|
||||
|
@ -672,11 +672,36 @@
|
||||
<source>GUI Settings</source>
|
||||
<translation>Ρυθμίσεις GUI</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="475"/>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="375"/>
|
||||
<source>Play title music</source>
|
||||
<translation>Αναπαραγωγή μουσικής τίτλου</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="394"/>
|
||||
<source>Volume</source>
|
||||
@ -1201,6 +1226,11 @@
|
||||
<source>GUIgroupBox</source>
|
||||
<translation>Αναπαραγωγή Μουσικής Τίτλων:\nΕάν το παιχνίδι το υποστηρίζει, ενεργοποιεί ειδική μουσική κατά την επιλογή του παιχνιδιού από τη διεπαφή χρήστη.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="450"/>
|
||||
<source>hideCursorGroupBox</source>
|
||||
@ -1216,6 +1246,21 @@
|
||||
<source>backButtonBehaviorGroupBox</source>
|
||||
<translation>Συμπεριφορά Κουμπιού Επιστροφής:\nΟρίζει το κουμπί επιστροφής του ελεγκτή να προσομοιώνει το πάτημα της καθορισμένης θέσης στην οθόνη αφής PS4.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="70"/>
|
||||
<source>Never</source>
|
||||
@ -1329,6 +1374,11 @@
|
||||
<source>Serial</source>
|
||||
<translation>Σειριακός αριθμός</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp"/>
|
||||
<source>Compatibility</source>
|
||||
<translation>Compatibility</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp" line="34"/>
|
||||
<source>Region</source>
|
||||
@ -1364,6 +1414,36 @@
|
||||
<source>Never Played</source>
|
||||
<translation>Never Played</translation>
|
||||
</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>
|
||||
<name>CheckUpdate</name>
|
||||
|
@ -672,11 +672,36 @@
|
||||
<source>GUI Settings</source>
|
||||
<translation>GUI Settings</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="475"/>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="375"/>
|
||||
<source>Play title music</source>
|
||||
<translation>Play title music</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="394"/>
|
||||
<source>Volume</source>
|
||||
@ -1201,6 +1226,11 @@
|
||||
<source>GUIgroupBox</source>
|
||||
<translation>Play Title Music:\nIf a game supports it, enable playing special music when selecting the game in the GUI.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="450"/>
|
||||
<source>hideCursorGroupBox</source>
|
||||
@ -1216,6 +1246,21 @@
|
||||
<source>backButtonBehaviorGroupBox</source>
|
||||
<translation>Back Button Behavior:\nSets the controller's back button to emulate tapping the specified position on the PS4 touchpad.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="70"/>
|
||||
<source>Never</source>
|
||||
@ -1329,6 +1374,11 @@
|
||||
<source>Serial</source>
|
||||
<translation>Serial</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp"/>
|
||||
<source>Compatibility</source>
|
||||
<translation>Compatibility</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp" line="34"/>
|
||||
<source>Region</source>
|
||||
@ -1364,6 +1414,36 @@
|
||||
<source>Never Played</source>
|
||||
<translation>Never Played</translation>
|
||||
</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>
|
||||
<name>CheckUpdate</name>
|
||||
|
@ -672,11 +672,36 @@
|
||||
<source>GUI Settings</source>
|
||||
<translation>Configuraciones de la Interfaz</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="475"/>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="375"/>
|
||||
<source>Play title music</source>
|
||||
<translation>Reproducir la música de apertura</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="394"/>
|
||||
<source>Volume</source>
|
||||
@ -1201,6 +1226,11 @@
|
||||
<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>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="450"/>
|
||||
<source>hideCursorGroupBox</source>
|
||||
@ -1216,6 +1246,21 @@
|
||||
<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>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="70"/>
|
||||
<source>Never</source>
|
||||
@ -1329,6 +1374,11 @@
|
||||
<source>Serial</source>
|
||||
<translation>Numero de serie</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp"/>
|
||||
<source>Compatibility</source>
|
||||
<translation>Compatibility</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp" line="34"/>
|
||||
<source>Region</source>
|
||||
@ -1364,6 +1414,36 @@
|
||||
<source>Never Played</source>
|
||||
<translation>Never Played</translation>
|
||||
</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>
|
||||
<name>CheckUpdate</name>
|
||||
|
@ -672,11 +672,36 @@
|
||||
<source>GUI Settings</source>
|
||||
<translation>تنظیمات رابط کاربری</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="475"/>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="375"/>
|
||||
<source>Play title music</source>
|
||||
<translation>پخش موسیقی عنوان</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="394"/>
|
||||
<source>Volume</source>
|
||||
@ -1201,6 +1226,11 @@
|
||||
<source>GUIgroupBox</source>
|
||||
<translation>Play Title Music:\nIf a game supports it, enable playing special music when selecting the game in the GUI.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="450"/>
|
||||
<source>hideCursorGroupBox</source>
|
||||
@ -1216,6 +1246,21 @@
|
||||
<source>backButtonBehaviorGroupBox</source>
|
||||
<translation>رفتار دکمه برگشت:\nدکمه برگشت کنترلر را طوری تنظیم می کند که ضربه زدن روی موقعیت مشخص شده روی صفحه لمسی PS4 را شبیه سازی کند.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="70"/>
|
||||
<source>Never</source>
|
||||
@ -1329,6 +1374,11 @@
|
||||
<source>Serial</source>
|
||||
<translation>سریال</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp"/>
|
||||
<source>Compatibility</source>
|
||||
<translation>Compatibility</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp" line="34"/>
|
||||
<source>Region</source>
|
||||
@ -1364,6 +1414,36 @@
|
||||
<source>Never Played</source>
|
||||
<translation>Never Played</translation>
|
||||
</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>
|
||||
<name>CheckUpdate</name>
|
||||
|
@ -672,11 +672,36 @@
|
||||
<source>GUI Settings</source>
|
||||
<translation>GUI-Asetukset</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="475"/>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="375"/>
|
||||
<source>Play title music</source>
|
||||
<translation>Soita otsikkomusiikkia</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="394"/>
|
||||
<source>Volume</source>
|
||||
@ -1201,6 +1226,11 @@
|
||||
<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>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="450"/>
|
||||
<source>hideCursorGroupBox</source>
|
||||
@ -1216,6 +1246,21 @@
|
||||
<source>backButtonBehaviorGroupBox</source>
|
||||
<translation>Takaisin-napin käyttäytyminen:\nAsettaa ohjaimen takaisin-napin jäljittelemään kosketusta PS4:n kosketuslevyn määritettyyn kohtaan.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="70"/>
|
||||
<source>Never</source>
|
||||
@ -1329,6 +1374,11 @@
|
||||
<source>Serial</source>
|
||||
<translation>Sarjanumero</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp"/>
|
||||
<source>Compatibility</source>
|
||||
<translation>Compatibility</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp" line="34"/>
|
||||
<source>Region</source>
|
||||
@ -1364,6 +1414,36 @@
|
||||
<source>Never Played</source>
|
||||
<translation>Never Played</translation>
|
||||
</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>
|
||||
<name>CheckUpdate</name>
|
||||
|
@ -672,11 +672,36 @@
|
||||
<source>GUI Settings</source>
|
||||
<translation>Paramètres de l'interface</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="475"/>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="375"/>
|
||||
<source>Play title music</source>
|
||||
<translation>Lire la musique du titre</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="394"/>
|
||||
<source>Volume</source>
|
||||
@ -1201,6 +1226,11 @@
|
||||
<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>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="450"/>
|
||||
<source>hideCursorGroupBox</source>
|
||||
@ -1216,6 +1246,21 @@
|
||||
<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>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="70"/>
|
||||
<source>Never</source>
|
||||
@ -1329,6 +1374,11 @@
|
||||
<source>Serial</source>
|
||||
<translation>Série</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp"/>
|
||||
<source>Compatibility</source>
|
||||
<translation>Compatibility</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp" line="34"/>
|
||||
<source>Region</source>
|
||||
@ -1364,6 +1414,36 @@
|
||||
<source>Never Played</source>
|
||||
<translation>Jamais joué</translation>
|
||||
</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>
|
||||
<name>CheckUpdate</name>
|
||||
|
@ -672,11 +672,36 @@
|
||||
<source>GUI Settings</source>
|
||||
<translation>GUI Beállítások</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="475"/>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="375"/>
|
||||
<source>Play title music</source>
|
||||
<translation>Címzene lejátszása</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="394"/>
|
||||
<source>Volume</source>
|
||||
@ -1201,6 +1226,11 @@
|
||||
<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>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="450"/>
|
||||
<source>hideCursorGroupBox</source>
|
||||
@ -1216,6 +1246,21 @@
|
||||
<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>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="70"/>
|
||||
<source>Never</source>
|
||||
@ -1329,6 +1374,11 @@
|
||||
<source>Serial</source>
|
||||
<translation>Sorozatszám</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp"/>
|
||||
<source>Compatibility</source>
|
||||
<translation>Compatibility</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp" line="34"/>
|
||||
<source>Region</source>
|
||||
@ -1364,6 +1414,36 @@
|
||||
<source>Never Played</source>
|
||||
<translation>Never Played</translation>
|
||||
</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>
|
||||
<name>CheckUpdate</name>
|
||||
|
@ -672,11 +672,36 @@
|
||||
<source>GUI Settings</source>
|
||||
<translation>Pengaturan GUI</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="475"/>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="375"/>
|
||||
<source>Play title music</source>
|
||||
<translation>Putar musik judul</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="394"/>
|
||||
<source>Volume</source>
|
||||
@ -1201,6 +1226,11 @@
|
||||
<source>GUIgroupBox</source>
|
||||
<translation>Putar Musik Judul Permainan:\nJika permainan mendukungnya, aktifkan pemutaran musik khusus saat memilih permainan di GUI.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="450"/>
|
||||
<source>hideCursorGroupBox</source>
|
||||
@ -1216,6 +1246,21 @@
|
||||
<source>backButtonBehaviorGroupBox</source>
|
||||
<translation>Perilaku Tombol Kembali:\nMengatur tombol kembali pada pengontrol untuk meniru ketukan di posisi yang ditentukan di touchpad PS4.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="70"/>
|
||||
<source>Never</source>
|
||||
@ -1329,6 +1374,11 @@
|
||||
<source>Serial</source>
|
||||
<translation>Serial</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp"/>
|
||||
<source>Compatibility</source>
|
||||
<translation>Compatibility</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp" line="34"/>
|
||||
<source>Region</source>
|
||||
@ -1364,6 +1414,36 @@
|
||||
<source>Never Played</source>
|
||||
<translation>Never Played</translation>
|
||||
</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>
|
||||
<name>CheckUpdate</name>
|
||||
|
@ -672,11 +672,36 @@
|
||||
<source>GUI Settings</source>
|
||||
<translation>Impostazioni GUI</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="475"/>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="375"/>
|
||||
<source>Play title music</source>
|
||||
<translation>Riproduci musica del titolo</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="394"/>
|
||||
<source>Volume</source>
|
||||
@ -1201,6 +1226,11 @@
|
||||
<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>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="450"/>
|
||||
<source>hideCursorGroupBox</source>
|
||||
@ -1216,6 +1246,21 @@
|
||||
<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>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="70"/>
|
||||
<source>Never</source>
|
||||
@ -1329,6 +1374,11 @@
|
||||
<source>Serial</source>
|
||||
<translation>Seriale</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp"/>
|
||||
<source>Compatibility</source>
|
||||
<translation>Compatibility</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp" line="34"/>
|
||||
<source>Region</source>
|
||||
@ -1364,6 +1414,36 @@
|
||||
<source>Never Played</source>
|
||||
<translation>Never Played</translation>
|
||||
</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>
|
||||
<name>CheckUpdate</name>
|
||||
|
@ -672,11 +672,36 @@
|
||||
<source>GUI Settings</source>
|
||||
<translation>GUI設定</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="475"/>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="375"/>
|
||||
<source>Play title music</source>
|
||||
<translation>タイトル音楽を再生する</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="394"/>
|
||||
<source>Volume</source>
|
||||
@ -1201,6 +1226,11 @@
|
||||
<source>GUIgroupBox</source>
|
||||
<translation>タイトルミュージックを再生:\nゲームがそれをサポートしている場合、GUIでゲームを選択したときに特別な音楽を再生することを有効にします。</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="450"/>
|
||||
<source>hideCursorGroupBox</source>
|
||||
@ -1216,6 +1246,21 @@
|
||||
<source>backButtonBehaviorGroupBox</source>
|
||||
<translation>戻るボタンの動作:\nコントローラーの戻るボタンを、PS4のタッチパッドの指定された位置をタッチするように設定します。</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="70"/>
|
||||
<source>Never</source>
|
||||
@ -1329,6 +1374,11 @@
|
||||
<source>Serial</source>
|
||||
<translation>シリアル</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp"/>
|
||||
<source>Compatibility</source>
|
||||
<translation>Compatibility</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp" line="34"/>
|
||||
<source>Region</source>
|
||||
@ -1364,6 +1414,36 @@
|
||||
<source>Never Played</source>
|
||||
<translation>Never Played</translation>
|
||||
</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>
|
||||
<name>CheckUpdate</name>
|
||||
|
@ -672,11 +672,36 @@
|
||||
<source>GUI Settings</source>
|
||||
<translation>GUI Settings</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="475"/>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="375"/>
|
||||
<source>Play title music</source>
|
||||
<translation>Play title music</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="394"/>
|
||||
<source>Volume</source>
|
||||
@ -1201,6 +1226,11 @@
|
||||
<source>GUIgroupBox</source>
|
||||
<translation>Play Title Music:\nIf a game supports it, enable playing special music when selecting the game in the GUI.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="450"/>
|
||||
<source>hideCursorGroupBox</source>
|
||||
@ -1216,6 +1246,21 @@
|
||||
<source>backButtonBehaviorGroupBox</source>
|
||||
<translation>Back Button Behavior:\nSets the controller's back button to emulate tapping the specified position on the PS4 touchpad.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="70"/>
|
||||
<source>Never</source>
|
||||
@ -1329,6 +1374,11 @@
|
||||
<source>Serial</source>
|
||||
<translation>Serial</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp"/>
|
||||
<source>Compatibility</source>
|
||||
<translation>Compatibility</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp" line="34"/>
|
||||
<source>Region</source>
|
||||
@ -1364,6 +1414,36 @@
|
||||
<source>Never Played</source>
|
||||
<translation>Never Played</translation>
|
||||
</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>
|
||||
<name>CheckUpdate</name>
|
||||
|
@ -672,11 +672,36 @@
|
||||
<source>GUI Settings</source>
|
||||
<translation>GUI Nustatymai</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="475"/>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="375"/>
|
||||
<source>Play title music</source>
|
||||
<translation>Groti antraštės muziką</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="394"/>
|
||||
<source>Volume</source>
|
||||
@ -1201,6 +1226,11 @@
|
||||
<source>GUIgroupBox</source>
|
||||
<translation>Groti antraščių muziką:\nJei žaidimas tai palaiko, įjungia specialios muzikos grojimą, kai pasirinkite žaidimą GUI.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="450"/>
|
||||
<source>hideCursorGroupBox</source>
|
||||
@ -1216,6 +1246,21 @@
|
||||
<source>backButtonBehaviorGroupBox</source>
|
||||
<translation>Atgal mygtuko elgesys:\nNustato valdiklio atgal mygtuką imituoti paspaudimą nurodytoje vietoje PS4 jutiklinėje plokštėje.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="70"/>
|
||||
<source>Never</source>
|
||||
@ -1329,6 +1374,11 @@
|
||||
<source>Serial</source>
|
||||
<translation>Serijinis numeris</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp"/>
|
||||
<source>Compatibility</source>
|
||||
<translation>Compatibility</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp" line="34"/>
|
||||
<source>Region</source>
|
||||
@ -1364,6 +1414,36 @@
|
||||
<source>Never Played</source>
|
||||
<translation>Never Played</translation>
|
||||
</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>
|
||||
<name>CheckUpdate</name>
|
||||
|
@ -672,11 +672,36 @@
|
||||
<source>GUI Settings</source>
|
||||
<translation>GUI-Innstillinger</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="475"/>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="375"/>
|
||||
<source>Play title music</source>
|
||||
<translation>Spill tittelmusikk</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="394"/>
|
||||
<source>Volume</source>
|
||||
@ -1201,6 +1226,11 @@
|
||||
<source>GUIgroupBox</source>
|
||||
<translation>Spille tittelmusikk:\nHvis et spill støtter det, så aktiveres det spesiell musikk når du velger spillet i menyen.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="450"/>
|
||||
<source>hideCursorGroupBox</source>
|
||||
@ -1216,6 +1246,21 @@
|
||||
<source>backButtonBehaviorGroupBox</source>
|
||||
<translation>Atferd for tilbaketasten:\nSetter tilbaketasten på kontrolleren til å imitere et trykk på den angitte posisjonen på PS4s berøringsplate.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="70"/>
|
||||
<source>Never</source>
|
||||
@ -1329,6 +1374,11 @@
|
||||
<source>Serial</source>
|
||||
<translation>Serienummer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp"/>
|
||||
<source>Compatibility</source>
|
||||
<translation>Compatibility</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp" line="34"/>
|
||||
<source>Region</source>
|
||||
@ -1364,6 +1414,36 @@
|
||||
<source>Never Played</source>
|
||||
<translation>Never Played</translation>
|
||||
</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>
|
||||
<name>CheckUpdate</name>
|
||||
|
@ -672,11 +672,36 @@
|
||||
<source>GUI Settings</source>
|
||||
<translation>GUI-Instellingen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="475"/>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="375"/>
|
||||
<source>Play title music</source>
|
||||
<translation>Titelmuziek afspelen</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="394"/>
|
||||
<source>Volume</source>
|
||||
@ -1201,6 +1226,11 @@
|
||||
<source>GUIgroupBox</source>
|
||||
<translation>Speel titelsong:\nAls een game dit ondersteunt, wordt speciale muziek afgespeeld wanneer je het spel in de GUI selecteert.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="450"/>
|
||||
<source>hideCursorGroupBox</source>
|
||||
@ -1216,6 +1246,21 @@
|
||||
<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>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="70"/>
|
||||
<source>Never</source>
|
||||
@ -1329,6 +1374,11 @@
|
||||
<source>Serial</source>
|
||||
<translation>Serienummer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp"/>
|
||||
<source>Compatibility</source>
|
||||
<translation>Compatibility</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp" line="34"/>
|
||||
<source>Region</source>
|
||||
@ -1364,6 +1414,36 @@
|
||||
<source>Never Played</source>
|
||||
<translation>Never Played</translation>
|
||||
</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>
|
||||
<name>CheckUpdate</name>
|
||||
|
@ -672,11 +672,36 @@
|
||||
<source>GUI Settings</source>
|
||||
<translation>Ustawienia Interfejsu</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="475"/>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="375"/>
|
||||
<source>Play title music</source>
|
||||
<translation>Odtwórz muzykę tytułową</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="394"/>
|
||||
<source>Volume</source>
|
||||
@ -1201,6 +1226,11 @@
|
||||
<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>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="450"/>
|
||||
<source>hideCursorGroupBox</source>
|
||||
@ -1216,6 +1246,21 @@
|
||||
<source>backButtonBehaviorGroupBox</source>
|
||||
<translation>Zachowanie przycisku Wstecz:\nUstawia przycisk Wstecz kontrolera tak, aby emulował dotknięcie określonego miejsca na panelu dotykowym PS4.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="70"/>
|
||||
<source>Never</source>
|
||||
@ -1329,6 +1374,11 @@
|
||||
<source>Serial</source>
|
||||
<translation>Numer seryjny</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp"/>
|
||||
<source>Compatibility</source>
|
||||
<translation>Compatibility</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp" line="34"/>
|
||||
<source>Region</source>
|
||||
@ -1364,6 +1414,36 @@
|
||||
<source>Never Played</source>
|
||||
<translation>Never Played</translation>
|
||||
</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>
|
||||
<name>CheckUpdate</name>
|
||||
|
@ -672,11 +672,36 @@
|
||||
<source>GUI Settings</source>
|
||||
<translation>Configurações da Interface</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="375"/>
|
||||
<source>Play title music</source>
|
||||
<translation>Reproduzir música de abertura</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="394"/>
|
||||
<source>Volume</source>
|
||||
@ -1201,6 +1226,11 @@
|
||||
<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>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="450"/>
|
||||
<source>hideCursorGroupBox</source>
|
||||
@ -1216,6 +1246,21 @@
|
||||
<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>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="70"/>
|
||||
<source>Never</source>
|
||||
@ -1329,6 +1374,11 @@
|
||||
<source>Serial</source>
|
||||
<translation>Serial</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp"/>
|
||||
<source>Compatibility</source>
|
||||
<translation>Compatibilidade</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp" line="36"/>
|
||||
<source>Region</source>
|
||||
@ -1364,6 +1414,36 @@
|
||||
<source>Never Played</source>
|
||||
<translation>Nunca jogado</translation>
|
||||
</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>
|
||||
<name>CheckUpdate</name>
|
||||
|
@ -672,11 +672,36 @@
|
||||
<source>GUI Settings</source>
|
||||
<translation>Setări GUI</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="475"/>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="375"/>
|
||||
<source>Play title music</source>
|
||||
<translation>Redă muzica titlului</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="394"/>
|
||||
<source>Volume</source>
|
||||
@ -1201,6 +1226,11 @@
|
||||
<source>GUIgroupBox</source>
|
||||
<translation>Redă muzica titlului:\nDacă un joc o suportă, activează redarea muzicii speciale când selectezi jocul în GUI.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="450"/>
|
||||
<source>hideCursorGroupBox</source>
|
||||
@ -1216,6 +1246,21 @@
|
||||
<source>backButtonBehaviorGroupBox</source>
|
||||
<translation>Comportamentul butonului înapoi:\nSetează butonul înapoi al controlerului să imite atingerea poziției specificate pe touchpad-ul PS4.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="70"/>
|
||||
<source>Never</source>
|
||||
@ -1329,6 +1374,11 @@
|
||||
<source>Serial</source>
|
||||
<translation>Serie</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp"/>
|
||||
<source>Compatibility</source>
|
||||
<translation>Compatibility</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp" line="34"/>
|
||||
<source>Region</source>
|
||||
@ -1364,6 +1414,36 @@
|
||||
<source>Never Played</source>
|
||||
<translation>Never Played</translation>
|
||||
</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>
|
||||
<name>CheckUpdate</name>
|
||||
|
@ -672,11 +672,36 @@
|
||||
<source>GUI Settings</source>
|
||||
<translation>Интерфейс</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="475"/>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="375"/>
|
||||
<source>Play title music</source>
|
||||
<translation>Играть заглавную музыку</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="394"/>
|
||||
<source>Volume</source>
|
||||
@ -1201,6 +1226,11 @@
|
||||
<source>GUIgroupBox</source>
|
||||
<translation>Играть заглавную музыку:\nВключает воспроизведение специальной музыки при выборе игры в списке, если она это поддерживает.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="450"/>
|
||||
<source>hideCursorGroupBox</source>
|
||||
@ -1216,6 +1246,21 @@
|
||||
<source>backButtonBehaviorGroupBox</source>
|
||||
<translation>Поведение кнопки «Назад»:\nНастраивает кнопку «Назад» контроллера на эмуляцию нажатия на указанную область на сенсорной панели контроллера PS4.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="70"/>
|
||||
<source>Never</source>
|
||||
@ -1329,6 +1374,11 @@
|
||||
<source>Serial</source>
|
||||
<translation>Серийный номер</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp"/>
|
||||
<source>Compatibility</source>
|
||||
<translation>Compatibility</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp" line="34"/>
|
||||
<source>Region</source>
|
||||
@ -1364,6 +1414,36 @@
|
||||
<source>Never Played</source>
|
||||
<translation>Never Played</translation>
|
||||
</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>
|
||||
<name>CheckUpdate</name>
|
||||
|
@ -672,11 +672,36 @@
|
||||
<source>GUI Settings</source>
|
||||
<translation>Cilësimet e GUI</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="475"/>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="375"/>
|
||||
<source>Play title music</source>
|
||||
<translation>Luaj muzikën e titullit</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="394"/>
|
||||
<source>Volume</source>
|
||||
@ -1201,6 +1226,11 @@
|
||||
<source>GUIgroupBox</source>
|
||||
<translation>Luaj muzikën e titullit:\nNëse një lojë e mbështet, aktivizohet luajtja e muzikës të veçantë kur të zgjidhësh lojën në GUI.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="450"/>
|
||||
<source>hideCursorGroupBox</source>
|
||||
@ -1216,6 +1246,21 @@
|
||||
<source>backButtonBehaviorGroupBox</source>
|
||||
<translation>Sjellja e butonit mbrapa:\nLejon të përcaktohet se në cilën pjesë të tastierës prekëse do të imitojë një prekje butoni mprapa.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="70"/>
|
||||
<source>Never</source>
|
||||
@ -1329,6 +1374,11 @@
|
||||
<source>Serial</source>
|
||||
<translation>Seriku</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp"/>
|
||||
<source>Compatibility</source>
|
||||
<translation>Compatibility</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp" line="34"/>
|
||||
<source>Region</source>
|
||||
@ -1364,6 +1414,36 @@
|
||||
<source>Never Played</source>
|
||||
<translation>Never Played</translation>
|
||||
</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>
|
||||
<name>CheckUpdate</name>
|
||||
|
@ -672,11 +672,36 @@
|
||||
<source>GUI Settings</source>
|
||||
<translation>GUI Ayarları</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="475"/>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="375"/>
|
||||
<source>Play title music</source>
|
||||
<translation>Başlık müziğini çal</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="394"/>
|
||||
<source>Volume</source>
|
||||
@ -1201,6 +1226,11 @@
|
||||
<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>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="450"/>
|
||||
<source>hideCursorGroupBox</source>
|
||||
@ -1216,6 +1246,21 @@
|
||||
<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>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="70"/>
|
||||
<source>Never</source>
|
||||
@ -1329,6 +1374,11 @@
|
||||
<source>Serial</source>
|
||||
<translation>Seri Numarası</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp"/>
|
||||
<source>Compatibility</source>
|
||||
<translation>Compatibility</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp" line="34"/>
|
||||
<source>Region</source>
|
||||
@ -1364,6 +1414,36 @@
|
||||
<source>Never Played</source>
|
||||
<translation>Never Played</translation>
|
||||
</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>
|
||||
<name>CheckUpdate</name>
|
||||
|
@ -672,11 +672,36 @@
|
||||
<source>GUI Settings</source>
|
||||
<translation>Інтерфейс</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="475"/>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="375"/>
|
||||
<source>Play title music</source>
|
||||
<translation>Програвати заголовну музику</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="394"/>
|
||||
<source>Volume</source>
|
||||
@ -1201,6 +1226,11 @@
|
||||
<source>GUIgroupBox</source>
|
||||
<translation>Грати заголовну музику:\nВмикає відтворення спеціальної музики під час вибору гри в списку, якщо вона це підтримує.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="450"/>
|
||||
<source>hideCursorGroupBox</source>
|
||||
@ -1216,6 +1246,21 @@
|
||||
<source>backButtonBehaviorGroupBox</source>
|
||||
<translation>Поведінка кнопки «Назад»:\nНалаштовує кнопку «Назад» контролера на емуляцію натискання на зазначену область на сенсорній панелі контролера PS4.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="70"/>
|
||||
<source>Never</source>
|
||||
@ -1329,6 +1374,11 @@
|
||||
<source>Serial</source>
|
||||
<translation>Серійний номер</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp"/>
|
||||
<source>Compatibility</source>
|
||||
<translation>Compatibility</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp" line="34"/>
|
||||
<source>Region</source>
|
||||
@ -1364,6 +1414,36 @@
|
||||
<source>Never Played</source>
|
||||
<translation>Never Played</translation>
|
||||
</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>
|
||||
<name>CheckUpdate</name>
|
||||
|
@ -672,11 +672,36 @@
|
||||
<source>GUI Settings</source>
|
||||
<translation>Cài đặt GUI</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="475"/>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="375"/>
|
||||
<source>Play title music</source>
|
||||
<translation>Phát nhạc tiêu đề</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="394"/>
|
||||
<source>Volume</source>
|
||||
@ -1201,6 +1226,11 @@
|
||||
<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>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="450"/>
|
||||
<source>hideCursorGroupBox</source>
|
||||
@ -1216,6 +1246,21 @@
|
||||
<source>backButtonBehaviorGroupBox</source>
|
||||
<translation>Hành vi nút quay lại:\nĐặt nút quay lại của tay cầm để mô phỏng việc chạm vào vị trí đã chỉ định trên touchpad của PS4.</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="70"/>
|
||||
<source>Never</source>
|
||||
@ -1329,6 +1374,11 @@
|
||||
<source>Serial</source>
|
||||
<translation>Số seri</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp"/>
|
||||
<source>Compatibility</source>
|
||||
<translation>Compatibility</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp" line="34"/>
|
||||
<source>Region</source>
|
||||
@ -1364,6 +1414,36 @@
|
||||
<source>Never Played</source>
|
||||
<translation>Never Played</translation>
|
||||
</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>
|
||||
<name>CheckUpdate</name>
|
||||
|
@ -672,11 +672,36 @@
|
||||
<source>GUI Settings</source>
|
||||
<translation>界面设置</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="475"/>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="375"/>
|
||||
<source>Play title music</source>
|
||||
<translation>播放标题音乐</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="394"/>
|
||||
<source>Volume</source>
|
||||
@ -1201,6 +1226,11 @@
|
||||
<source>GUIgroupBox</source>
|
||||
<translation>播放标题音乐:\n如果游戏支持,在图形界面选择游戏时启用播放特殊音乐。</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="450"/>
|
||||
<source>hideCursorGroupBox</source>
|
||||
@ -1216,6 +1246,21 @@
|
||||
<source>backButtonBehaviorGroupBox</source>
|
||||
<translation>返回按钮行为:\n设置控制器的返回按钮以模拟在 PS4 触控板上指定位置的点击。</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="70"/>
|
||||
<source>Never</source>
|
||||
@ -1329,6 +1374,11 @@
|
||||
<source>Serial</source>
|
||||
<translation>序列号</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp"/>
|
||||
<source>Compatibility</source>
|
||||
<translation>Compatibility</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp" line="34"/>
|
||||
<source>Region</source>
|
||||
@ -1364,6 +1414,36 @@
|
||||
<source>Never Played</source>
|
||||
<translation>Never Played</translation>
|
||||
</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>
|
||||
<name>CheckUpdate</name>
|
||||
|
@ -672,11 +672,36 @@
|
||||
<source>GUI Settings</source>
|
||||
<translation>介面設置</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="475"/>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settings_dialog.ui" line="375"/>
|
||||
<source>Play title music</source>
|
||||
<translation>播放標題音樂</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.ui" line="394"/>
|
||||
<source>Volume</source>
|
||||
@ -1201,6 +1226,11 @@
|
||||
<source>GUIgroupBox</source>
|
||||
<translation>播放標題音樂:\n如果遊戲支持,啟用在GUI中選擇遊戲時播放特殊音樂。</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="450"/>
|
||||
<source>hideCursorGroupBox</source>
|
||||
@ -1216,6 +1246,21 @@
|
||||
<source>backButtonBehaviorGroupBox</source>
|
||||
<translation>返回按鈕行為:\n設定控制器的返回按鈕模擬在 PS4 觸控板上指定位置的觸碰。</translation>
|
||||
</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>
|
||||
<location filename="../settings_dialog.cpp" line="70"/>
|
||||
<source>Never</source>
|
||||
@ -1329,6 +1374,11 @@
|
||||
<source>Serial</source>
|
||||
<translation>序號</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp"/>
|
||||
<source>Compatibility</source>
|
||||
<translation>Compatibility</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../game_list_frame.cpp" line="34"/>
|
||||
<source>Region</source>
|
||||
@ -1364,6 +1414,36 @@
|
||||
<source>Never Played</source>
|
||||
<translation>Never Played</translation>
|
||||
</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>
|
||||
<name>CheckUpdate</name>
|
||||
|
@ -1,5 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <span>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
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) {
|
||||
const auto& texture = ctx.images[handle & 0xFFFF];
|
||||
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;
|
||||
}
|
||||
|
||||
Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id lod) {
|
||||
UNREACHABLE_MSG("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id lod, Id color) {
|
||||
Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id lod, Id ms) {
|
||||
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);
|
||||
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) {
|
||||
operands.Add(spv::ImageOperandsMask::Lod, lod);
|
||||
} else if (Sirit::ValidId(lod)) {
|
||||
|
@ -395,14 +395,13 @@ Id EmitImageGather(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords,
|
||||
const IR::Value& offset);
|
||||
Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords,
|
||||
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 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 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);
|
||||
void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id lod, Id color);
|
||||
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 ms,
|
||||
Id color);
|
||||
|
||||
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);
|
||||
|
329
src/shader_recompiler/backend/spirv/emit_spirv_quad_rect.cpp
Normal file
329
src/shader_recompiler/backend/spirv/emit_spirv_quad_rect.cpp
Normal 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
|
24
src/shader_recompiler/backend/spirv/emit_spirv_quad_rect.h
Normal file
24
src/shader_recompiler/backend/spirv/emit_spirv_quad_rect.h
Normal 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
|
@ -772,7 +772,7 @@ Id ImageType(EmitContext& ctx, const ImageResource& desc, Id sampled_type) {
|
||||
const auto image = desc.GetSharp(ctx.info);
|
||||
const auto format = desc.is_atomic ? GetFormat(image) : spv::ImageFormat::Unknown;
|
||||
const auto type = image.GetBoundType();
|
||||
const u32 sampled = desc.is_storage ? 2 : 1;
|
||||
const u32 sampled = desc.IsStorage(image) ? 2 : 1;
|
||||
switch (type) {
|
||||
case AmdGpu::ImageType::Color1D:
|
||||
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 nfmt = sharp.GetNumberFmt();
|
||||
const bool is_integer = AmdGpu::IsInteger(nfmt);
|
||||
const bool is_storage = image_desc.IsStorage(sharp);
|
||||
const VectorIds& data_types = GetAttributeType(*this, nfmt);
|
||||
const Id sampled_type = data_types[1];
|
||||
const Id image_type{ImageType(*this, image_desc, sampled_type)};
|
||||
@ -811,11 +812,11 @@ void EmitContext::DefineImagesAndSamplers() {
|
||||
images.push_back({
|
||||
.data_types = &data_types,
|
||||
.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,
|
||||
.image_type = image_type,
|
||||
.is_integer = is_integer,
|
||||
.is_storage = image_desc.is_storage,
|
||||
.is_storage = is_storage,
|
||||
});
|
||||
interfaces.push_back(id);
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "shader_recompiler/frontend/translate/translate.h"
|
||||
#include "shader_recompiler/ir/reg.h"
|
||||
#include "shader_recompiler/profile.h"
|
||||
#include "shader_recompiler/runtime_info.h"
|
||||
|
||||
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)));
|
||||
ir.WriteShared(bit_size, ir.GetVectorReg(data0), addr0);
|
||||
}
|
||||
emit_ds_read_barrier = true;
|
||||
}
|
||||
|
||||
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,
|
||||
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))};
|
||||
IR::VectorReg dst_reg{inst.dst[0].code};
|
||||
if (is_pair) {
|
||||
|
@ -306,6 +306,7 @@ private:
|
||||
const RuntimeInfo& runtime_info;
|
||||
const Profile& profile;
|
||||
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,
|
||||
|
@ -420,13 +420,13 @@ void Translator::IMAGE_LOAD(bool has_mip, const GcnInst& inst) {
|
||||
|
||||
IR::TextureInstInfo info{};
|
||||
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++) {
|
||||
if (((mimg.dmask >> i) & 1) == 0) {
|
||||
continue;
|
||||
}
|
||||
IR::F32 value = IR::F32{ir.CompositeExtract(texel, i)};
|
||||
IR::U32 value = IR::U32{ir.CompositeExtract(texel, i)};
|
||||
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++));
|
||||
}
|
||||
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) {
|
||||
|
@ -49,11 +49,11 @@ struct BufferResource {
|
||||
u8 instance_attrib{};
|
||||
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;
|
||||
}
|
||||
|
||||
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>;
|
||||
|
||||
@ -61,18 +61,24 @@ struct TextureBufferResource {
|
||||
u32 sharp_idx;
|
||||
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>;
|
||||
|
||||
struct ImageResource {
|
||||
u32 sharp_idx;
|
||||
bool is_storage{};
|
||||
bool is_depth{};
|
||||
bool is_atomic{};
|
||||
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>;
|
||||
|
||||
|
@ -1630,11 +1630,6 @@ Value IREmitter::ImageGatherDref(const Value& handle, const Value& coords, const
|
||||
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,
|
||||
const IR::U1& 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,
|
||||
TextureInstInfo info) {
|
||||
return Inst(Opcode::ImageRead, Flags{info}, handle, coords, lod);
|
||||
const U32& multisampling, TextureInstInfo info) {
|
||||
return Inst(Opcode::ImageRead, Flags{info}, handle, coords, lod, multisampling);
|
||||
}
|
||||
|
||||
void IREmitter::ImageWrite(const Value& handle, const Value& coords, const U32& lod,
|
||||
const Value& color, TextureInstInfo info) {
|
||||
Inst(Opcode::ImageWrite, Flags{info}, handle, coords, lod, color);
|
||||
const U32& multisampling, const Value& color, TextureInstInfo info) {
|
||||
Inst(Opcode::ImageWrite, Flags{info}, handle, coords, lod, multisampling, color);
|
||||
}
|
||||
|
||||
// Debug print maps to SPIRV's NonSemantic DebugPrintf instruction
|
||||
|
@ -325,17 +325,14 @@ public:
|
||||
TextureInstInfo info);
|
||||
[[nodiscard]] Value ImageGatherDref(const Value& handle, const Value& coords,
|
||||
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,
|
||||
const Value& derivatives_dx, const Value& derivatives_dy,
|
||||
const Value& offset, const F32& lod_clamp,
|
||||
TextureInstInfo info);
|
||||
[[nodiscard]] Value ImageRead(const Value& handle, const Value& coords, const U32& lod,
|
||||
TextureInstInfo info);
|
||||
void ImageWrite(const Value& handle, const Value& coords, const U32& lod, const Value& color,
|
||||
TextureInstInfo info);
|
||||
const U32& multisampling, TextureInstInfo info);
|
||||
void ImageWrite(const Value& handle, const Value& coords, const U32& lod,
|
||||
const U32& multisampling, const Value& color, TextureInstInfo info);
|
||||
|
||||
void EmitVertex();
|
||||
void EmitPrimitive();
|
||||
|
@ -338,12 +338,11 @@ OPCODE(ImageSampleDrefImplicitLod, F32x4, Opaq
|
||||
OPCODE(ImageSampleDrefExplicitLod, F32x4, Opaque, Opaque, F32, F32, Opaque, )
|
||||
OPCODE(ImageGather, F32x4, Opaque, Opaque, Opaque, )
|
||||
OPCODE(ImageGatherDref, F32x4, Opaque, Opaque, Opaque, F32, )
|
||||
OPCODE(ImageFetch, F32x4, Opaque, Opaque, U32, Opaque, Opaque, )
|
||||
OPCODE(ImageQueryDimensions, U32x4, Opaque, U32, U1, )
|
||||
OPCODE(ImageQueryLod, F32x4, Opaque, Opaque, )
|
||||
OPCODE(ImageGradient, F32x4, Opaque, Opaque, Opaque, Opaque, Opaque, F32, )
|
||||
OPCODE(ImageRead, U32x4, Opaque, Opaque, U32, )
|
||||
OPCODE(ImageWrite, Void, Opaque, Opaque, U32, U32x4, )
|
||||
OPCODE(ImageRead, U32x4, Opaque, Opaque, U32, U32, )
|
||||
OPCODE(ImageWrite, Void, Opaque, Opaque, U32, U32, U32x4, )
|
||||
|
||||
// Image atomic operations
|
||||
OPCODE(ImageAtomicIAdd32, U32, Opaque, Opaque, U32, )
|
||||
|
@ -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) {
|
||||
switch (inst.GetOpcode()) {
|
||||
case IR::Opcode::ImageFetch:
|
||||
case IR::Opcode::ImageRead:
|
||||
case IR::Opcode::ImageWrite:
|
||||
case IR::Opcode::ImageQueryDimensions:
|
||||
case IR::Opcode::ImageQueryLod:
|
||||
case IR::Opcode::ImageSampleRaw:
|
||||
return true;
|
||||
default:
|
||||
return IsImageStorageInstruction(inst);
|
||||
return IsImageAtomicInstruction(inst);
|
||||
}
|
||||
}
|
||||
|
||||
@ -201,7 +192,8 @@ public:
|
||||
return desc.sharp_idx == existing.sharp_idx;
|
||||
})};
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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,
|
||||
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.
|
||||
if (is_storage) {
|
||||
if (is_written) {
|
||||
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();
|
||||
}
|
||||
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.
|
||||
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)};
|
||||
switch (inst.GetOpcode()) {
|
||||
case IR::Opcode::ImageFetch:
|
||||
case IR::Opcode::ImageRead:
|
||||
case IR::Opcode::ImageSampleRaw: {
|
||||
IR::F32 fmaskx = ir.BitCast<IR::F32>(ir.Imm32(0x76543210));
|
||||
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{
|
||||
.sharp_idx = tsharp,
|
||||
.is_storage = is_storage,
|
||||
.is_depth = bool(inst_info.is_depth),
|
||||
.is_atomic = IsImageAtomicInstruction(inst),
|
||||
.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.
|
||||
@ -762,7 +756,7 @@ void PatchImageInstruction(IR::Block& block, IR::Inst& inst, Info& info, Descrip
|
||||
case AmdGpu::ImageType::Color3D: // x, y, z, [lod]
|
||||
return {ir.CompositeConstruct(body->Arg(0), body->Arg(1), body->Arg(2)), body->Arg(3)};
|
||||
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),
|
||||
body->Arg(3)};
|
||||
default:
|
||||
@ -772,19 +766,20 @@ void PatchImageInstruction(IR::Block& block, IR::Inst& inst, Info& info, Descrip
|
||||
inst.SetArg(1, coords);
|
||||
|
||||
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) {
|
||||
ASSERT(inst.GetOpcode() == IR::Opcode::ImageFetch ||
|
||||
inst.GetOpcode() == IR::Opcode::ImageRead ||
|
||||
ASSERT(inst.GetOpcode() == IR::Opcode::ImageRead ||
|
||||
inst.GetOpcode() == IR::Opcode::ImageWrite);
|
||||
ASSERT(image.GetType() != AmdGpu::ImageType::Color2DMsaa &&
|
||||
image.GetType() != AmdGpu::ImageType::Color2DMsaaArray);
|
||||
inst.SetArg(2, arg);
|
||||
} else if (image.GetType() == AmdGpu::ImageType::Color2DMsaa ||
|
||||
image.GetType() == AmdGpu::ImageType::Color2DMsaaArray) {
|
||||
inst.SetArg(4, arg);
|
||||
} else if ((image.GetType() == AmdGpu::ImageType::Color2DMsaa ||
|
||||
image.GetType() == AmdGpu::ImageType::Color2DMsaaArray) &&
|
||||
(inst.GetOpcode() == IR::Opcode::ImageRead ||
|
||||
inst.GetOpcode() == IR::Opcode::ImageWrite)) {
|
||||
inst.SetArg(3, arg);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -227,7 +227,7 @@ struct RuntimeInfo {
|
||||
ComputeRuntimeInfo cs_info;
|
||||
};
|
||||
|
||||
RuntimeInfo(Stage stage_) {
|
||||
void Initialize(Stage stage_) {
|
||||
memset(this, 0, sizeof(*this));
|
||||
stage = stage_;
|
||||
}
|
||||
|
@ -39,10 +39,12 @@ struct TextureBufferSpecialization {
|
||||
struct ImageSpecialization {
|
||||
AmdGpu::ImageType type = AmdGpu::ImageType::Color2D;
|
||||
bool is_integer = false;
|
||||
bool is_storage = false;
|
||||
u32 dst_select = 0;
|
||||
|
||||
bool operator==(const ImageSpecialization& other) const {
|
||||
return type == other.type && is_integer == other.is_integer &&
|
||||
is_storage == other.is_storage &&
|
||||
(dst_select != 0 ? dst_select == other.dst_select : true);
|
||||
}
|
||||
};
|
||||
@ -114,7 +116,8 @@ struct StageSpecialization {
|
||||
[](auto& spec, const auto& desc, AmdGpu::Image sharp) {
|
||||
spec.type = sharp.GetBoundType();
|
||||
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();
|
||||
}
|
||||
});
|
||||
|
@ -428,6 +428,14 @@ struct Liverpool {
|
||||
BitField<0, 22, u32> tile_max;
|
||||
} 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 {
|
||||
return (depth_size.pitch_tile_max + 1) << 3;
|
||||
}
|
||||
@ -1275,6 +1283,26 @@ struct Liverpool {
|
||||
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();
|
||||
};
|
||||
|
||||
|
@ -126,6 +126,7 @@ enum class TilingMode : u32 {
|
||||
Display_MacroTiled = 0xAu,
|
||||
Texture_MicroTiled = 0xDu,
|
||||
Texture_MacroTiled = 0xEu,
|
||||
Texture_Volume = 0x13u,
|
||||
};
|
||||
|
||||
constexpr std::string_view NameOf(TilingMode type) {
|
||||
@ -140,6 +141,8 @@ constexpr std::string_view NameOf(TilingMode type) {
|
||||
return "Texture_MicroTiled";
|
||||
case TilingMode::Texture_MacroTiled:
|
||||
return "Texture_MacroTiled";
|
||||
case TilingMode::Texture_Volume:
|
||||
return "Texture_Volume";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
@ -294,9 +297,6 @@ struct Image {
|
||||
return tiling_index == 5 ? TilingMode::Texture_MicroTiled
|
||||
: TilingMode::Depth_MacroTiled;
|
||||
}
|
||||
if (tiling_index == 0x13) {
|
||||
return TilingMode::Texture_MicroTiled;
|
||||
}
|
||||
return static_cast<TilingMode>(tiling_index);
|
||||
}
|
||||
|
||||
|
@ -235,25 +235,26 @@ bool BufferCache::BindVertexBuffers(
|
||||
}
|
||||
|
||||
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;
|
||||
if (regs.primitive_type == AmdGpu::PrimitiveType::QuadList && !is_indexed) {
|
||||
is_indexed = true;
|
||||
if (!is_indexed) {
|
||||
if (regs.primitive_type != AmdGpu::PrimitiveType::Polygon) {
|
||||
return regs.num_indices;
|
||||
}
|
||||
|
||||
// Emit indices.
|
||||
const u32 index_size = 3 * regs.num_indices;
|
||||
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();
|
||||
|
||||
// Bind index buffer.
|
||||
is_indexed = true;
|
||||
|
||||
const auto cmdbuf = scheduler.CommandBuffer();
|
||||
cmdbuf.bindIndexBuffer(stream_buffer.Handle(), offset, vk::IndexType::eUint16);
|
||||
return index_size / sizeof(u16);
|
||||
}
|
||||
if (!is_indexed) {
|
||||
return regs.num_indices;
|
||||
}
|
||||
|
||||
// Figure out index type and size.
|
||||
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>();
|
||||
index_address += index_offset * index_size;
|
||||
|
||||
if (regs.primitive_type == AmdGpu::PrimitiveType::QuadList) {
|
||||
// Convert indices.
|
||||
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;
|
||||
if (regs.primitive_type == AmdGpu::PrimitiveType::Polygon) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
// Bind index buffer.
|
||||
|
@ -7,6 +7,8 @@ set(SHADER_FILES
|
||||
detile_m32x1.comp
|
||||
detile_m32x2.comp
|
||||
detile_m32x4.comp
|
||||
detile_macro32x1.comp
|
||||
detile_macro32x2.comp
|
||||
fs_tri.vert
|
||||
post_process.frag
|
||||
)
|
||||
|
@ -15,6 +15,7 @@ layout(std430, binding = 1) buffer output_buf {
|
||||
layout(push_constant) uniform image_info {
|
||||
uint num_levels;
|
||||
uint pitch;
|
||||
uint height;
|
||||
uint sizes[14];
|
||||
} info;
|
||||
|
||||
|
@ -15,6 +15,7 @@ layout(std430, binding = 1) buffer output_buf {
|
||||
layout(push_constant) uniform image_info {
|
||||
uint num_levels;
|
||||
uint pitch;
|
||||
uint height;
|
||||
uint sizes[14];
|
||||
} info;
|
||||
|
||||
|
@ -15,6 +15,7 @@ layout(std430, binding = 1) buffer output_buf {
|
||||
layout(push_constant) uniform image_info {
|
||||
uint num_levels;
|
||||
uint pitch;
|
||||
uint height;
|
||||
uint sizes[14];
|
||||
} info;
|
||||
|
||||
|
@ -18,6 +18,7 @@ layout(std430, binding = 1) buffer output_buf {
|
||||
layout(push_constant) uniform image_info {
|
||||
uint num_levels;
|
||||
uint pitch;
|
||||
uint height;
|
||||
uint sizes[14];
|
||||
} info;
|
||||
|
||||
|
@ -17,6 +17,7 @@ layout(std430, binding = 1) buffer output_buf {
|
||||
layout(push_constant) uniform image_info {
|
||||
uint num_levels;
|
||||
uint pitch;
|
||||
uint height;
|
||||
uint sizes[14];
|
||||
} info;
|
||||
|
||||
|
90
src/video_core/host_shaders/detile_macro32x1.comp
Normal file
90
src/video_core/host_shaders/detile_macro32x1.comp
Normal 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;
|
||||
}
|
91
src/video_core/host_shaders/detile_macro32x2.comp
Normal file
91
src/video_core/host_shaders/detile_macro32x2.comp
Normal 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;
|
||||
}
|
@ -12,8 +12,14 @@ layout(push_constant) uniform settings {
|
||||
float gamma;
|
||||
} 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()
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
@ -116,11 +116,12 @@ vk::PrimitiveTopology PrimitiveType(AmdGpu::PrimitiveType type) {
|
||||
return vk::PrimitiveTopology::eTriangleStripWithAdjacency;
|
||||
case AmdGpu::PrimitiveType::PatchPrimitive:
|
||||
return vk::PrimitiveTopology::ePatchList;
|
||||
case AmdGpu::PrimitiveType::QuadList:
|
||||
case AmdGpu::PrimitiveType::Polygon:
|
||||
// Needs to generate index buffer on the fly.
|
||||
return vk::PrimitiveTopology::eTriangleList;
|
||||
case AmdGpu::PrimitiveType::QuadList:
|
||||
case AmdGpu::PrimitiveType::RectList:
|
||||
return vk::PrimitiveTopology::eTriangleStrip;
|
||||
return vk::PrimitiveTopology::ePatchList;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return vk::PrimitiveTopology::eTriangleList;
|
||||
|
@ -70,31 +70,12 @@ vk::ClearValue ColorBufferClearValue(const AmdGpu::Liverpool::ColorBuffer& color
|
||||
|
||||
vk::SampleCountFlagBits NumSamples(u32 num_samples, vk::SampleCountFlags supported_flags);
|
||||
|
||||
static constexpr u16 NumVerticesPerQuad = 4;
|
||||
|
||||
inline void EmitQuadToTriangleListIndices(u8* out_ptr, u32 num_vertices) {
|
||||
inline void EmitPolygonToTriangleListIndices(u8* out_ptr, u32 num_vertices) {
|
||||
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 + 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];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,8 +58,9 @@ ComputePipeline::ComputePipeline(const Instance& instance_, Scheduler& scheduler
|
||||
for (const auto& image : info->images) {
|
||||
bindings.push_back({
|
||||
.binding = binding++,
|
||||
.descriptorType = image.is_storage ? vk::DescriptorType::eStorageImage
|
||||
: vk::DescriptorType::eSampledImage,
|
||||
.descriptorType = image.IsStorage(image.GetSharp(*info))
|
||||
? vk::DescriptorType::eStorageImage
|
||||
: vk::DescriptorType::eSampledImage,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = vk::ShaderStageFlagBits::eCompute,
|
||||
});
|
||||
|
@ -7,25 +7,30 @@
|
||||
#include <boost/container/static_vector.hpp>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/io_file.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 "video_core/amdgpu/resource.h"
|
||||
#include "video_core/buffer_cache/buffer_cache.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_scheduler.h"
|
||||
#include "video_core/renderer_vulkan/vk_shader_util.h"
|
||||
#include "video_core/texture_cache/texture_cache.h"
|
||||
|
||||
namespace Vulkan {
|
||||
|
||||
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::optional<const Shader::Gcn::FetchShaderData> fetch_shader_,
|
||||
std::span<const vk::ShaderModule> modules)
|
||||
using Shader::Backend::SPIRV::AuxShaderType;
|
||||
|
||||
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::RuntimeInfo, MaxShaderStages> runtime_infos,
|
||||
std::optional<const Shader::Gcn::FetchShaderData> fetch_shader_,
|
||||
std::span<const vk::ShaderModule> modules)
|
||||
: Pipeline{instance_, scheduler_, desc_heap_, pipeline_cache}, key{key_},
|
||||
fetch_shader{std::move(fetch_shader_)} {
|
||||
const vk::Device device = instance.GetDevice();
|
||||
@ -88,11 +93,6 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
|
||||
.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;
|
||||
if (prim_restart && IsPrimitiveListTopology() && !instance.IsListRestartSupported()) {
|
||||
LOG_WARNING(Render_Vulkan,
|
||||
@ -106,9 +106,11 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
|
||||
ASSERT_MSG(!prim_restart || key.primitive_restart_index == 0xFFFF ||
|
||||
key.primitive_restart_index == 0xFFFFFFFF,
|
||||
"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 = {
|
||||
.patchControlPoints = key.patch_control_points,
|
||||
.patchControlPoints = is_rect_list ? 3U : (is_quad_list ? 4U : key.patch_control_points),
|
||||
};
|
||||
|
||||
const vk::PipelineRasterizationStateCreateInfo raster_state = {
|
||||
@ -121,7 +123,7 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
|
||||
.frontFace = key.front_face == Liverpool::FrontFace::Clockwise
|
||||
? vk::FrontFace::eClockwise
|
||||
: vk::FrontFace::eCounterClockwise,
|
||||
.depthBiasEnable = bool(key.depth_bias_enable),
|
||||
.depthBiasEnable = key.depth_bias_enable,
|
||||
.lineWidth = 1.0f,
|
||||
};
|
||||
|
||||
@ -131,37 +133,24 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
|
||||
.sampleShadingEnable = false,
|
||||
};
|
||||
|
||||
const vk::Viewport viewport = {
|
||||
.x = 0.0f,
|
||||
.y = 0.0f,
|
||||
.width = 1.0f,
|
||||
.height = 1.0f,
|
||||
.minDepth = 0.0f,
|
||||
.maxDepth = 1.0f,
|
||||
};
|
||||
|
||||
const vk::Rect2D scissor = {
|
||||
.offset = {0, 0},
|
||||
.extent = {1, 1},
|
||||
};
|
||||
|
||||
const vk::PipelineViewportDepthClipControlCreateInfoEXT clip_control = {
|
||||
.negativeOneToOne = key.clip_space == Liverpool::ClipSpace::MinusWToW,
|
||||
};
|
||||
|
||||
const vk::PipelineViewportStateCreateInfo viewport_info = {
|
||||
.pNext = instance.IsDepthClipControlSupported() ? &clip_control : nullptr,
|
||||
.viewportCount = 1,
|
||||
.pViewports = &viewport,
|
||||
.scissorCount = 1,
|
||||
.pScissors = &scissor,
|
||||
};
|
||||
|
||||
boost::container::static_vector<vk::DynamicState, 14> dynamic_states = {
|
||||
vk::DynamicState::eViewport, vk::DynamicState::eScissor,
|
||||
vk::DynamicState::eBlendConstants, vk::DynamicState::eDepthBounds,
|
||||
vk::DynamicState::eDepthBias, vk::DynamicState::eStencilReference,
|
||||
vk::DynamicState::eStencilCompareMask, vk::DynamicState::eStencilWriteMask,
|
||||
vk::DynamicState::eViewportWithCountEXT,
|
||||
vk::DynamicState::eScissorWithCountEXT,
|
||||
vk::DynamicState::eBlendConstants,
|
||||
vk::DynamicState::eDepthBounds,
|
||||
vk::DynamicState::eDepthBias,
|
||||
vk::DynamicState::eStencilReference,
|
||||
vk::DynamicState::eStencilCompareMask,
|
||||
vk::DynamicState::eStencilWriteMask,
|
||||
vk::DynamicState::eStencilOpEXT,
|
||||
};
|
||||
|
||||
if (instance.IsColorWriteEnableSupported()) {
|
||||
@ -180,31 +169,11 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
|
||||
};
|
||||
|
||||
const vk::PipelineDepthStencilStateCreateInfo depth_info = {
|
||||
.depthTestEnable = key.depth_stencil.depth_enable,
|
||||
.depthWriteEnable = key.depth_stencil.depth_write_enable,
|
||||
.depthCompareOp = LiverpoolToVK::CompareOp(key.depth_stencil.depth_func),
|
||||
.depthBoundsTestEnable = key.depth_stencil.depth_bounds_enable,
|
||||
.stencilTestEnable = key.depth_stencil.stencil_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()),
|
||||
},
|
||||
.depthTestEnable = key.depth_test_enable,
|
||||
.depthWriteEnable = key.depth_write_enable,
|
||||
.depthCompareOp = key.depth_compare_op,
|
||||
.depthBoundsTestEnable = key.depth_bounds_test_enable,
|
||||
.stencilTestEnable = key.stencil_test_enable,
|
||||
};
|
||||
|
||||
boost::container::static_vector<vk::PipelineShaderStageCreateInfo, MaxShaderStages>
|
||||
@ -232,6 +201,14 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
|
||||
.module = modules[stage],
|
||||
.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);
|
||||
if (infos[stage]) {
|
||||
@ -240,6 +217,14 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
|
||||
.module = modules[stage],
|
||||
.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);
|
||||
if (infos[stage]) {
|
||||
@ -322,8 +307,7 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
|
||||
.pStages = shader_stages.data(),
|
||||
.pVertexInputState = !instance.IsVertexInputDynamicState() ? &vertex_input_info : nullptr,
|
||||
.pInputAssemblyState = &input_assembly,
|
||||
.pTessellationState =
|
||||
stages[u32(Shader::LogicalStage::TessellationControl)] ? &tessellation_state : nullptr,
|
||||
.pTessellationState = &tessellation_state,
|
||||
.pViewportState = &viewport_info,
|
||||
.pRasterizationState = &raster_state,
|
||||
.pMultisampleState = &multisampling,
|
||||
@ -380,8 +364,9 @@ void GraphicsPipeline::BuildDescSetLayout() {
|
||||
for (const auto& image : stage->images) {
|
||||
bindings.push_back({
|
||||
.binding = binding++,
|
||||
.descriptorType = image.is_storage ? vk::DescriptorType::eStorageImage
|
||||
: vk::DescriptorType::eSampledImage,
|
||||
.descriptorType = image.IsStorage(image.GetSharp(*stage))
|
||||
? vk::DescriptorType::eStorageImage
|
||||
: vk::DescriptorType::eSampledImage,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = gp_stage_flags,
|
||||
});
|
||||
|
@ -18,7 +18,7 @@ class TextureCache;
|
||||
|
||||
namespace Vulkan {
|
||||
|
||||
static constexpr u32 MaxShaderStages = 5;
|
||||
static constexpr u32 MaxShaderStages = static_cast<u32>(Shader::LogicalStage::NumLogicalStages);
|
||||
static constexpr u32 MaxVertexBufferCount = 32;
|
||||
|
||||
class Instance;
|
||||
@ -36,11 +36,19 @@ struct GraphicsPipelineKey {
|
||||
vk::Format depth_format;
|
||||
vk::Format stencil_format;
|
||||
|
||||
Liverpool::DepthControl depth_stencil;
|
||||
u32 depth_bias_enable;
|
||||
struct {
|
||||
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 mrt_mask;
|
||||
Liverpool::StencilControl stencil;
|
||||
AmdGpu::PrimitiveType prim_type;
|
||||
u32 enable_primitive_restart;
|
||||
u32 primitive_restart_index;
|
||||
@ -64,6 +72,7 @@ public:
|
||||
GraphicsPipeline(const Instance& instance, Scheduler& scheduler, DescriptorHeap& desc_heap,
|
||||
const GraphicsPipelineKey& key, vk::PipelineCache pipeline_cache,
|
||||
std::span<const Shader::Info*, MaxShaderStages> stages,
|
||||
std::span<const Shader::RuntimeInfo, MaxShaderStages> runtime_infos,
|
||||
std::optional<const Shader::Gcn::FetchShaderData> fetch_shader,
|
||||
std::span<const vk::ShaderModule> modules);
|
||||
~GraphicsPipeline();
|
||||
@ -72,11 +81,6 @@ public:
|
||||
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 {
|
||||
return key.write_masks;
|
||||
}
|
||||
@ -85,10 +89,6 @@ public:
|
||||
return key.mrt_mask;
|
||||
}
|
||||
|
||||
bool IsDepthEnabled() const {
|
||||
return key.depth_stencil.depth_enable.Value();
|
||||
}
|
||||
|
||||
[[nodiscard]] bool IsPrimitiveListTopology() const {
|
||||
return key.prim_type == AmdGpu::PrimitiveType::PointList ||
|
||||
key.prim_type == AmdGpu::PrimitiveType::LineList ||
|
||||
|
@ -80,8 +80,8 @@ void GatherVertexOutputs(Shader::VertexRuntimeInfo& info,
|
||||
: (ctl.IsCullDistEnabled(7) ? VsOutput::CullDist7 : VsOutput::None));
|
||||
}
|
||||
|
||||
Shader::RuntimeInfo PipelineCache::BuildRuntimeInfo(Stage stage, LogicalStage l_stage) {
|
||||
auto info = Shader::RuntimeInfo{stage};
|
||||
const Shader::RuntimeInfo& PipelineCache::BuildRuntimeInfo(Stage stage, LogicalStage l_stage) {
|
||||
auto& info = runtime_infos[u32(l_stage)];
|
||||
const auto& regs = liverpool->regs;
|
||||
const auto BuildCommon = [&](const auto& program) {
|
||||
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_round_mode32 = program.settings.fp_round_mode32;
|
||||
};
|
||||
info.Initialize(stage);
|
||||
switch (stage) {
|
||||
case Stage::Local: {
|
||||
BuildCommon(regs.ls_program);
|
||||
@ -204,7 +205,8 @@ PipelineCache::PipelineCache(const Instance& instance_, Scheduler& scheduler_,
|
||||
.supports_image_load_store_lod = instance_.IsImageLoadStoreLodSupported(),
|
||||
.needs_manual_interpolation = instance.IsFragmentShaderBarycentricSupported() &&
|
||||
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({});
|
||||
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);
|
||||
if (is_new) {
|
||||
it.value() =
|
||||
std::make_unique<GraphicsPipeline>(instance, scheduler, desc_heap, graphics_key,
|
||||
*pipeline_cache, infos, fetch_shader, modules);
|
||||
it.value() = std::make_unique<GraphicsPipeline>(instance, scheduler, desc_heap,
|
||||
graphics_key, *pipeline_cache, infos,
|
||||
runtime_infos, fetch_shader, modules);
|
||||
if (Config::collectShadersForDebug()) {
|
||||
for (auto stage = 0; stage < MaxShaderStages; ++stage) {
|
||||
if (infos[stage]) {
|
||||
@ -257,33 +259,31 @@ bool PipelineCache::RefreshGraphicsKey() {
|
||||
auto& regs = liverpool->regs;
|
||||
auto& key = graphics_key;
|
||||
|
||||
key.depth_stencil = regs.depth_control;
|
||||
key.depth_stencil.depth_write_enable.Assign(regs.depth_control.depth_write_enable.Value() &&
|
||||
!regs.depth_render_control.depth_clear_enable);
|
||||
key.depth_test_enable = regs.depth_control.depth_enable;
|
||||
key.depth_write_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_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 ds_format = instance.GetSupportedFormat(
|
||||
LiverpoolToVK::DepthFormat(db.z_info.format, db.stencil_info.format),
|
||||
const auto depth_format = instance.GetSupportedFormat(
|
||||
LiverpoolToVK::DepthFormat(regs.depth_buffer.z_info.format,
|
||||
regs.depth_buffer.stencil_info.format),
|
||||
vk::FormatFeatureFlagBits2::eDepthStencilAttachment);
|
||||
if (db.z_info.format != AmdGpu::Liverpool::DepthBuffer::ZFormat::Invalid) {
|
||||
key.depth_format = ds_format;
|
||||
if (regs.depth_buffer.DepthValid()) {
|
||||
key.depth_format = depth_format;
|
||||
} else {
|
||||
key.depth_format = vk::Format::eUndefined;
|
||||
key.depth_test_enable = false;
|
||||
}
|
||||
if (regs.depth_control.depth_enable) {
|
||||
key.depth_stencil.depth_enable.Assign(key.depth_format != vk::Format::eUndefined);
|
||||
}
|
||||
key.stencil = regs.stencil_control;
|
||||
|
||||
if (db.stencil_info.format != AmdGpu::Liverpool::DepthBuffer::StencilFormat::Invalid) {
|
||||
key.stencil_format = key.depth_format;
|
||||
if (regs.depth_buffer.StencilValid()) {
|
||||
key.stencil_format = depth_format;
|
||||
} else {
|
||||
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.enable_primitive_restart = regs.enable_primitive_restart & 1;
|
||||
key.primitive_restart_index = regs.primitive_restart_index;
|
||||
@ -291,7 +291,7 @@ bool PipelineCache::RefreshGraphicsKey() {
|
||||
key.cull_mode = regs.polygon_control.CullingMode();
|
||||
key.clip_space = regs.clipper_control.clip_space;
|
||||
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 =
|
||||
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
|
||||
for (auto cb = 0u, remapped_cb = 0u; cb < Liverpool::NumColorBuffers; ++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.cb_shader_mask.SetMask(remapped_cb, regs.color_shader_mask.GetMask(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;
|
||||
} // namespace Vulkan
|
||||
|
||||
|
@ -76,7 +76,7 @@ private:
|
||||
vk::ShaderModule CompileModule(Shader::Info& info, Shader::RuntimeInfo& runtime_info,
|
||||
std::span<const u32> code, size_t perm_idx,
|
||||
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:
|
||||
const Instance& instance;
|
||||
@ -90,6 +90,7 @@ private:
|
||||
tsl::robin_map<size_t, std::unique_ptr<Program>> program_cache;
|
||||
tsl::robin_map<ComputePipelineKey, std::unique_ptr<ComputePipeline>> compute_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<vk::ShaderModule, MaxShaderStages> modules{};
|
||||
std::optional<Shader::Gcn::FetchShaderData> fetch_shader{};
|
||||
|
@ -154,7 +154,7 @@ void Presenter::CreatePostProcessPipeline() {
|
||||
const auto& fs_module =
|
||||
Vulkan::Compile(pp_shaders[1], vk::ShaderStageFlagBits::eFragment, instance.GetDevice());
|
||||
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{
|
||||
vk::PipelineShaderStageCreateInfo{
|
||||
@ -634,9 +634,11 @@ void Presenter::Present(Frame* frame) {
|
||||
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();
|
||||
|
||||
@ -731,7 +733,9 @@ void Presenter::Present(Frame* frame) {
|
||||
|
||||
// Present to swapchain.
|
||||
std::scoped_lock submit_lock{Scheduler::submit_mutex};
|
||||
swapchain.Present();
|
||||
if (!swapchain.Present()) {
|
||||
swapchain.Recreate(window.GetWidth(), window.GetHeight());
|
||||
}
|
||||
|
||||
// Free the frame for reuse
|
||||
std::scoped_lock fl{free_mutex};
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user