mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-08-04 16:32:39 +00:00
Merge branch 'main' into ime
This commit is contained in:
commit
8e6ebc56e2
2
.github/linux-appimage-qt.sh
vendored
2
.github/linux-appimage-qt.sh
vendored
@ -9,6 +9,8 @@ fi
|
|||||||
|
|
||||||
export Qt6_DIR="/usr/lib/qt6"
|
export Qt6_DIR="/usr/lib/qt6"
|
||||||
export PATH="$Qt6_DIR/bin:$PATH"
|
export PATH="$Qt6_DIR/bin:$PATH"
|
||||||
|
export EXTRA_QT_PLUGINS="waylandcompositor"
|
||||||
|
export EXTRA_PLATFORM_PLUGINS="libqwayland-egl.so;libqwayland-generic.so"
|
||||||
|
|
||||||
# Prepare Tools for building the AppImage
|
# Prepare Tools for building the AppImage
|
||||||
wget -q https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
|
wget -q https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
|
||||||
|
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@ -287,7 +287,7 @@ jobs:
|
|||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libfuse2 clang build-essential libasound2-dev libpulse-dev libopenal-dev
|
run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libdecor-0-dev libxkbcommon-dev libglfw3-dev libgles2-mesa-dev libfuse2 clang build-essential libasound2-dev libpulse-dev libopenal-dev
|
||||||
|
|
||||||
- name: Cache CMake Configuration
|
- name: Cache CMake Configuration
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
@ -343,7 +343,7 @@ jobs:
|
|||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libfuse2 clang build-essential qt6-base-dev qt6-tools-dev qt6-multimedia-dev libasound2-dev libpulse-dev libopenal-dev
|
run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libdecor-0-dev libxkbcommon-dev libglfw3-dev libgles2-mesa-dev libfuse2 clang build-essential qt6-base-dev qt6-tools-dev qt6-multimedia-dev libasound2-dev libpulse-dev libopenal-dev
|
||||||
|
|
||||||
- name: Cache CMake Configuration
|
- name: Cache CMake Configuration
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -95,3 +95,6 @@
|
|||||||
path = externals/pugixml
|
path = externals/pugixml
|
||||||
url = https://github.com/zeux/pugixml.git
|
url = https://github.com/zeux/pugixml.git
|
||||||
shallow = true
|
shallow = true
|
||||||
|
[submodule "externals/discord-rpc"]
|
||||||
|
path = externals/discord-rpc
|
||||||
|
url = https://github.com/shadps4-emu/ext-discord-rpc
|
||||||
|
@ -326,6 +326,10 @@ set(USBD_LIB src/core/libraries/usbd/usbd.cpp
|
|||||||
src/core/libraries/usbd/usbd.h
|
src/core/libraries/usbd/usbd.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set(FIBER_LIB src/core/libraries/fiber/fiber.cpp
|
||||||
|
src/core/libraries/fiber/fiber.h
|
||||||
|
)
|
||||||
|
|
||||||
set(NP_LIBS src/core/libraries/np_manager/np_manager.cpp
|
set(NP_LIBS src/core/libraries/np_manager/np_manager.cpp
|
||||||
src/core/libraries/np_manager/np_manager.h
|
src/core/libraries/np_manager/np_manager.h
|
||||||
src/core/libraries/np_score/np_score.cpp
|
src/core/libraries/np_score/np_score.cpp
|
||||||
@ -376,6 +380,8 @@ set(COMMON src/common/logging/backend.cpp
|
|||||||
src/common/debug.h
|
src/common/debug.h
|
||||||
src/common/decoder.cpp
|
src/common/decoder.cpp
|
||||||
src/common/decoder.h
|
src/common/decoder.h
|
||||||
|
src/common/discord_rpc_handler.cpp
|
||||||
|
src/common/discord_rpc_handler.h
|
||||||
src/common/elf_info.h
|
src/common/elf_info.h
|
||||||
src/common/endian.h
|
src/common/endian.h
|
||||||
src/common/enum.h
|
src/common/enum.h
|
||||||
@ -464,6 +470,7 @@ set(CORE src/core/aerolib/stubs.cpp
|
|||||||
${USBD_LIB}
|
${USBD_LIB}
|
||||||
${MISC_LIBS}
|
${MISC_LIBS}
|
||||||
${DIALOGS_LIB}
|
${DIALOGS_LIB}
|
||||||
|
${FIBER_LIB}
|
||||||
${DEV_TOOLS}
|
${DEV_TOOLS}
|
||||||
src/core/debug_state.cpp
|
src/core/debug_state.cpp
|
||||||
src/core/debug_state.h
|
src/core/debug_state.h
|
||||||
@ -693,6 +700,8 @@ set(QT_GUI src/qt_gui/about_dialog.cpp
|
|||||||
src/qt_gui/game_grid_frame.h
|
src/qt_gui/game_grid_frame.h
|
||||||
src/qt_gui/game_install_dialog.cpp
|
src/qt_gui/game_install_dialog.cpp
|
||||||
src/qt_gui/game_install_dialog.h
|
src/qt_gui/game_install_dialog.h
|
||||||
|
src/qt_gui/install_dir_select.cpp
|
||||||
|
src/qt_gui/install_dir_select.h
|
||||||
src/qt_gui/pkg_viewer.cpp
|
src/qt_gui/pkg_viewer.cpp
|
||||||
src/qt_gui/pkg_viewer.h
|
src/qt_gui/pkg_viewer.h
|
||||||
src/qt_gui/trophy_viewer.cpp
|
src/qt_gui/trophy_viewer.cpp
|
||||||
@ -860,3 +869,6 @@ if (UNIX AND NOT APPLE)
|
|||||||
target_link_libraries(shadps4 PRIVATE ${OPENSSL_LIBRARIES})
|
target_link_libraries(shadps4 PRIVATE ${OPENSSL_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Discord RPC
|
||||||
|
target_link_libraries(shadps4 PRIVATE discord-rpc)
|
||||||
|
@ -102,7 +102,7 @@ PAD DOWN | DOWN |
|
|||||||
PAD LEFT | LEFT |
|
PAD LEFT | LEFT |
|
||||||
PAD RIGHT | RIGHT |
|
PAD RIGHT | RIGHT |
|
||||||
OPTIONS | RETURN |
|
OPTIONS | RETURN |
|
||||||
TOUCH PAD | SPACE |
|
BACK BUTTON / TOUCH PAD | SPACE |
|
||||||
L1 | Q |
|
L1 | Q |
|
||||||
R1 | U |
|
R1 | U |
|
||||||
L2 | E |
|
L2 | E |
|
||||||
|
17
externals/CMakeLists.txt
vendored
17
externals/CMakeLists.txt
vendored
@ -3,7 +3,10 @@
|
|||||||
|
|
||||||
set(BUILD_SHARED_LIBS OFF)
|
set(BUILD_SHARED_LIBS OFF)
|
||||||
set(BUILD_TESTING OFF)
|
set(BUILD_TESTING OFF)
|
||||||
set_property(DIRECTORY PROPERTY EXCLUDE_FROM_ALL ON)
|
set_directory_properties(PROPERTIES
|
||||||
|
EXCLUDE_FROM_ALL ON
|
||||||
|
SYSTEM ON
|
||||||
|
)
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
# Silence "deprecation" warnings
|
# Silence "deprecation" warnings
|
||||||
@ -13,11 +16,8 @@ endif()
|
|||||||
# Boost
|
# Boost
|
||||||
if (NOT TARGET Boost::headers)
|
if (NOT TARGET Boost::headers)
|
||||||
set(BOOST_ROOT "${CMAKE_SOURCE_DIR}/externals/ext-boost" CACHE STRING "")
|
set(BOOST_ROOT "${CMAKE_SOURCE_DIR}/externals/ext-boost" CACHE STRING "")
|
||||||
set(Boost_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/externals/ext-boost" CACHE STRING "")
|
|
||||||
set(Boost_NO_SYSTEM_PATHS ON CACHE BOOL "")
|
set(Boost_NO_SYSTEM_PATHS ON CACHE BOOL "")
|
||||||
add_library(boost INTERFACE)
|
add_subdirectory(ext-boost)
|
||||||
target_include_directories(boost SYSTEM INTERFACE ${Boost_INCLUDE_DIR})
|
|
||||||
add_library(Boost::headers ALIAS boost)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# fmtlib
|
# fmtlib
|
||||||
@ -77,7 +77,7 @@ endif()
|
|||||||
# RenderDoc
|
# RenderDoc
|
||||||
if (NOT TARGET RenderDoc::API)
|
if (NOT TARGET RenderDoc::API)
|
||||||
add_library(renderdoc INTERFACE)
|
add_library(renderdoc INTERFACE)
|
||||||
target_include_directories(renderdoc SYSTEM INTERFACE ./renderdoc)
|
target_include_directories(renderdoc INTERFACE ./renderdoc)
|
||||||
add_library(RenderDoc::API ALIAS renderdoc)
|
add_library(RenderDoc::API ALIAS renderdoc)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -184,5 +184,10 @@ if (NOT TARGET pugixml::pugixml)
|
|||||||
add_subdirectory(pugixml)
|
add_subdirectory(pugixml)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Discord RPC
|
||||||
|
set(BUILD_EXAMPLES OFF)
|
||||||
|
add_subdirectory(discord-rpc/)
|
||||||
|
target_include_directories(discord-rpc INTERFACE discord-rpc/include)
|
||||||
|
|
||||||
# GCN Headers
|
# GCN Headers
|
||||||
add_subdirectory(gcn)
|
add_subdirectory(gcn)
|
2
externals/date
vendored
2
externals/date
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 51ce7e131079c061533d741be5fe7cca57f2faac
|
Subproject commit dd8affc6de5755e07638bf0a14382d29549d6ee9
|
1
externals/discord-rpc
vendored
Submodule
1
externals/discord-rpc
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 4ec218155d73bcb8022f8f7ca72305d801f84beb
|
2
externals/ext-boost
vendored
2
externals/ext-boost
vendored
@ -1 +1 @@
|
|||||||
Subproject commit a04136add1e469f46d8ae8d3e8307779240a5c53
|
Subproject commit f2474e1b584fb7a3ed6f85ba875e6eacd742ec8a
|
2
externals/sdl3
vendored
2
externals/sdl3
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 0548050fc5a4edf1f47c3633c2cd06d8762b5532
|
Subproject commit 54e622c2e6af456bfef382fae44c17682d5ac88a
|
2
externals/sirit
vendored
2
externals/sirit
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 37090c74cc6e680f2bc334cac8fd182f7634a1f6
|
Subproject commit 6cecb95d679c82c413d1f989e0b7ad9af130600d
|
@ -103,7 +103,7 @@ s32 SDLAudio::AudioOutOutput(s32 handle, const void* ptr) {
|
|||||||
|
|
||||||
const size_t data_size = port.samples_num * port.sample_size * port.channels_num;
|
const size_t data_size = port.samples_num * port.sample_size * port.channels_num;
|
||||||
|
|
||||||
SDL_bool result = SDL_PutAudioStreamData(port.stream, ptr, data_size);
|
bool result = SDL_PutAudioStreamData(port.stream, ptr, data_size);
|
||||||
|
|
||||||
lock.unlock(); // Unlock only after necessary operations
|
lock.unlock(); // Unlock only after necessary operations
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ static bool isNeo = false;
|
|||||||
static bool isFullscreen = false;
|
static bool isFullscreen = false;
|
||||||
static bool playBGM = false;
|
static bool playBGM = false;
|
||||||
static int BGMvolume = 50;
|
static int BGMvolume = 50;
|
||||||
|
static bool enableDiscordRPC = false;
|
||||||
static u32 screenWidth = 1280;
|
static u32 screenWidth = 1280;
|
||||||
static u32 screenHeight = 720;
|
static u32 screenHeight = 720;
|
||||||
static s32 gpuId = -1; // Vulkan physical device index. Set to negative for auto select
|
static s32 gpuId = -1; // Vulkan physical device index. Set to negative for auto select
|
||||||
@ -41,6 +42,7 @@ static std::string logFilter;
|
|||||||
static std::string logType = "async";
|
static std::string logType = "async";
|
||||||
static std::string userName = "shadPS4";
|
static std::string userName = "shadPS4";
|
||||||
static std::string updateChannel;
|
static std::string updateChannel;
|
||||||
|
static std::string backButtonBehavior = "left";
|
||||||
static bool useSpecialPad = false;
|
static bool useSpecialPad = false;
|
||||||
static int specialPadClass = 1;
|
static int specialPadClass = 1;
|
||||||
static bool isDebugDump = false;
|
static bool isDebugDump = false;
|
||||||
@ -56,9 +58,11 @@ static bool vkValidationGpu = false;
|
|||||||
static bool rdocEnable = false;
|
static bool rdocEnable = false;
|
||||||
static bool vkMarkers = false;
|
static bool vkMarkers = false;
|
||||||
static bool vkCrashDiagnostic = false;
|
static bool vkCrashDiagnostic = false;
|
||||||
|
static s16 cursorState = HideCursorState::Idle;
|
||||||
|
static int cursorHideTimeout = 5; // 5 seconds (default)
|
||||||
|
|
||||||
// Gui
|
// Gui
|
||||||
std::filesystem::path settings_install_dir = {};
|
std::vector<std::filesystem::path> settings_install_dirs = {};
|
||||||
std::filesystem::path settings_addon_install_dir = {};
|
std::filesystem::path settings_addon_install_dir = {};
|
||||||
u32 main_window_geometry_x = 400;
|
u32 main_window_geometry_x = 400;
|
||||||
u32 main_window_geometry_y = 400;
|
u32 main_window_geometry_y = 400;
|
||||||
@ -95,6 +99,18 @@ int getBGMvolume() {
|
|||||||
return BGMvolume;
|
return BGMvolume;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool getEnableDiscordRPC() {
|
||||||
|
return enableDiscordRPC;
|
||||||
|
}
|
||||||
|
|
||||||
|
s16 getCursorState() {
|
||||||
|
return cursorState;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getCursorHideTimeout() {
|
||||||
|
return cursorHideTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
u32 getScreenWidth() {
|
u32 getScreenWidth() {
|
||||||
return screenWidth;
|
return screenWidth;
|
||||||
}
|
}
|
||||||
@ -123,6 +139,10 @@ std::string getUpdateChannel() {
|
|||||||
return updateChannel;
|
return updateChannel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string getBackButtonBehavior() {
|
||||||
|
return backButtonBehavior;
|
||||||
|
}
|
||||||
|
|
||||||
bool getUseSpecialPad() {
|
bool getUseSpecialPad() {
|
||||||
return useSpecialPad;
|
return useSpecialPad;
|
||||||
}
|
}
|
||||||
@ -251,6 +271,18 @@ void setBGMvolume(int volume) {
|
|||||||
BGMvolume = volume;
|
BGMvolume = volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setEnableDiscordRPC(bool enable) {
|
||||||
|
enableDiscordRPC = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCursorState(s16 newCursorState) {
|
||||||
|
cursorState = newCursorState;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCursorHideTimeout(int newcursorHideTimeout) {
|
||||||
|
cursorHideTimeout = newcursorHideTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
void setLanguage(u32 language) {
|
void setLanguage(u32 language) {
|
||||||
m_language = language;
|
m_language = language;
|
||||||
}
|
}
|
||||||
@ -275,6 +307,10 @@ void setUpdateChannel(const std::string& type) {
|
|||||||
updateChannel = type;
|
updateChannel = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setBackButtonBehavior(const std::string& type) {
|
||||||
|
backButtonBehavior = type;
|
||||||
|
}
|
||||||
|
|
||||||
void setUseSpecialPad(bool use) {
|
void setUseSpecialPad(bool use) {
|
||||||
useSpecialPad = use;
|
useSpecialPad = use;
|
||||||
}
|
}
|
||||||
@ -289,8 +325,9 @@ void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h) {
|
|||||||
main_window_geometry_w = w;
|
main_window_geometry_w = w;
|
||||||
main_window_geometry_h = h;
|
main_window_geometry_h = h;
|
||||||
}
|
}
|
||||||
void setGameInstallDir(const std::filesystem::path& dir) {
|
void setGameInstallDirs(const std::vector<std::filesystem::path>& dir) {
|
||||||
settings_install_dir = dir;
|
settings_install_dirs.resize(dir.size());
|
||||||
|
settings_install_dirs = dir;
|
||||||
}
|
}
|
||||||
void setAddonInstallDir(const std::filesystem::path& dir) {
|
void setAddonInstallDir(const std::filesystem::path& dir) {
|
||||||
settings_addon_install_dir = dir;
|
settings_addon_install_dir = dir;
|
||||||
@ -348,8 +385,8 @@ u32 getMainWindowGeometryW() {
|
|||||||
u32 getMainWindowGeometryH() {
|
u32 getMainWindowGeometryH() {
|
||||||
return main_window_geometry_h;
|
return main_window_geometry_h;
|
||||||
}
|
}
|
||||||
std::filesystem::path getGameInstallDir() {
|
std::vector<std::filesystem::path> getGameInstallDirs() {
|
||||||
return settings_install_dir;
|
return settings_install_dirs;
|
||||||
}
|
}
|
||||||
std::filesystem::path getAddonInstallDir() {
|
std::filesystem::path getAddonInstallDir() {
|
||||||
if (settings_addon_install_dir.empty()) {
|
if (settings_addon_install_dir.empty()) {
|
||||||
@ -425,6 +462,7 @@ void load(const std::filesystem::path& path) {
|
|||||||
isFullscreen = toml::find_or<bool>(general, "Fullscreen", false);
|
isFullscreen = toml::find_or<bool>(general, "Fullscreen", false);
|
||||||
playBGM = toml::find_or<bool>(general, "playBGM", false);
|
playBGM = toml::find_or<bool>(general, "playBGM", false);
|
||||||
BGMvolume = toml::find_or<int>(general, "BGMvolume", 50);
|
BGMvolume = toml::find_or<int>(general, "BGMvolume", 50);
|
||||||
|
enableDiscordRPC = toml::find_or<bool>(general, "enableDiscordRPC", true);
|
||||||
logFilter = toml::find_or<std::string>(general, "logFilter", "");
|
logFilter = toml::find_or<std::string>(general, "logFilter", "");
|
||||||
logType = toml::find_or<std::string>(general, "logType", "sync");
|
logType = toml::find_or<std::string>(general, "logType", "sync");
|
||||||
userName = toml::find_or<std::string>(general, "userName", "shadPS4");
|
userName = toml::find_or<std::string>(general, "userName", "shadPS4");
|
||||||
@ -440,6 +478,9 @@ void load(const std::filesystem::path& path) {
|
|||||||
if (data.contains("Input")) {
|
if (data.contains("Input")) {
|
||||||
const toml::value& input = data.at("Input");
|
const toml::value& input = data.at("Input");
|
||||||
|
|
||||||
|
cursorState = toml::find_or<int>(input, "cursorState", HideCursorState::Idle);
|
||||||
|
cursorHideTimeout = toml::find_or<int>(input, "cursorHideTimeout", 5);
|
||||||
|
backButtonBehavior = toml::find_or<std::string>(input, "backButtonBehavior", "left");
|
||||||
useSpecialPad = toml::find_or<bool>(input, "useSpecialPad", false);
|
useSpecialPad = toml::find_or<bool>(input, "useSpecialPad", false);
|
||||||
specialPadClass = toml::find_or<int>(input, "specialPadClass", 1);
|
specialPadClass = toml::find_or<int>(input, "specialPadClass", 1);
|
||||||
}
|
}
|
||||||
@ -483,7 +524,24 @@ void load(const std::filesystem::path& path) {
|
|||||||
mw_themes = toml::find_or<int>(gui, "theme", 0);
|
mw_themes = toml::find_or<int>(gui, "theme", 0);
|
||||||
m_window_size_W = toml::find_or<int>(gui, "mw_width", 0);
|
m_window_size_W = toml::find_or<int>(gui, "mw_width", 0);
|
||||||
m_window_size_H = toml::find_or<int>(gui, "mw_height", 0);
|
m_window_size_H = toml::find_or<int>(gui, "mw_height", 0);
|
||||||
settings_install_dir = toml::find_fs_path_or(gui, "installDir", {});
|
|
||||||
|
auto old_game_install_dir = toml::find_fs_path_or(gui, "installDir", {});
|
||||||
|
if (!old_game_install_dir.empty()) {
|
||||||
|
settings_install_dirs.push_back(old_game_install_dir);
|
||||||
|
data.as_table().erase("installDir");
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto install_dir_array =
|
||||||
|
toml::find_or<std::vector<std::string>>(gui, "installDirs", {});
|
||||||
|
for (const auto& dir : install_dir_array) {
|
||||||
|
bool not_already_included =
|
||||||
|
std::find(settings_install_dirs.begin(), settings_install_dirs.end(), dir) ==
|
||||||
|
settings_install_dirs.end();
|
||||||
|
if (not_already_included) {
|
||||||
|
settings_install_dirs.emplace_back(std::filesystem::path{dir});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
settings_addon_install_dir = toml::find_fs_path_or(gui, "addonInstallDir", {});
|
settings_addon_install_dir = toml::find_fs_path_or(gui, "addonInstallDir", {});
|
||||||
main_window_geometry_x = toml::find_or<int>(gui, "geometry_x", 0);
|
main_window_geometry_x = toml::find_or<int>(gui, "geometry_x", 0);
|
||||||
main_window_geometry_y = toml::find_or<int>(gui, "geometry_y", 0);
|
main_window_geometry_y = toml::find_or<int>(gui, "geometry_y", 0);
|
||||||
@ -527,12 +585,16 @@ void save(const std::filesystem::path& path) {
|
|||||||
data["General"]["Fullscreen"] = isFullscreen;
|
data["General"]["Fullscreen"] = isFullscreen;
|
||||||
data["General"]["playBGM"] = playBGM;
|
data["General"]["playBGM"] = playBGM;
|
||||||
data["General"]["BGMvolume"] = BGMvolume;
|
data["General"]["BGMvolume"] = BGMvolume;
|
||||||
|
data["General"]["enableDiscordRPC"] = enableDiscordRPC;
|
||||||
data["General"]["logFilter"] = logFilter;
|
data["General"]["logFilter"] = logFilter;
|
||||||
data["General"]["logType"] = logType;
|
data["General"]["logType"] = logType;
|
||||||
data["General"]["userName"] = userName;
|
data["General"]["userName"] = userName;
|
||||||
data["General"]["updateChannel"] = updateChannel;
|
data["General"]["updateChannel"] = updateChannel;
|
||||||
data["General"]["showSplash"] = isShowSplash;
|
data["General"]["showSplash"] = isShowSplash;
|
||||||
data["General"]["autoUpdate"] = isAutoUpdate;
|
data["General"]["autoUpdate"] = isAutoUpdate;
|
||||||
|
data["Input"]["cursorState"] = cursorState;
|
||||||
|
data["Input"]["cursorHideTimeout"] = cursorHideTimeout;
|
||||||
|
data["Input"]["backButtonBehavior"] = backButtonBehavior;
|
||||||
data["Input"]["useSpecialPad"] = useSpecialPad;
|
data["Input"]["useSpecialPad"] = useSpecialPad;
|
||||||
data["Input"]["specialPadClass"] = specialPadClass;
|
data["Input"]["specialPadClass"] = specialPadClass;
|
||||||
data["GPU"]["screenWidth"] = screenWidth;
|
data["GPU"]["screenWidth"] = screenWidth;
|
||||||
@ -557,7 +619,13 @@ void save(const std::filesystem::path& path) {
|
|||||||
data["GUI"]["gameTableMode"] = m_table_mode;
|
data["GUI"]["gameTableMode"] = m_table_mode;
|
||||||
data["GUI"]["mw_width"] = m_window_size_W;
|
data["GUI"]["mw_width"] = m_window_size_W;
|
||||||
data["GUI"]["mw_height"] = m_window_size_H;
|
data["GUI"]["mw_height"] = m_window_size_H;
|
||||||
data["GUI"]["installDir"] = std::string{fmt::UTF(settings_install_dir.u8string()).data};
|
|
||||||
|
std::vector<std::string> install_dirs;
|
||||||
|
for (const auto& dirString : settings_install_dirs) {
|
||||||
|
install_dirs.emplace_back(std::string{fmt::UTF(dirString.u8string()).data});
|
||||||
|
}
|
||||||
|
data["GUI"]["installDirs"] = install_dirs;
|
||||||
|
|
||||||
data["GUI"]["addonInstallDir"] =
|
data["GUI"]["addonInstallDir"] =
|
||||||
std::string{fmt::UTF(settings_addon_install_dir.u8string()).data};
|
std::string{fmt::UTF(settings_addon_install_dir.u8string()).data};
|
||||||
data["GUI"]["geometry_x"] = main_window_geometry_x;
|
data["GUI"]["geometry_x"] = main_window_geometry_x;
|
||||||
@ -581,6 +649,7 @@ void setDefaultValues() {
|
|||||||
isFullscreen = false;
|
isFullscreen = false;
|
||||||
playBGM = false;
|
playBGM = false;
|
||||||
BGMvolume = 50;
|
BGMvolume = 50;
|
||||||
|
enableDiscordRPC = true;
|
||||||
screenWidth = 1280;
|
screenWidth = 1280;
|
||||||
screenHeight = 720;
|
screenHeight = 720;
|
||||||
logFilter = "";
|
logFilter = "";
|
||||||
@ -591,6 +660,9 @@ void setDefaultValues() {
|
|||||||
} else {
|
} else {
|
||||||
updateChannel = "Nightly";
|
updateChannel = "Nightly";
|
||||||
}
|
}
|
||||||
|
cursorState = HideCursorState::Idle;
|
||||||
|
cursorHideTimeout = 5;
|
||||||
|
backButtonBehavior = "left";
|
||||||
useSpecialPad = false;
|
useSpecialPad = false;
|
||||||
specialPadClass = 1;
|
specialPadClass = 1;
|
||||||
isDebugDump = false;
|
isDebugDump = false;
|
||||||
|
@ -8,6 +8,9 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
namespace Config {
|
namespace Config {
|
||||||
|
|
||||||
|
enum HideCursorState : s16 { Never, Idle, Always };
|
||||||
|
|
||||||
void load(const std::filesystem::path& path);
|
void load(const std::filesystem::path& path);
|
||||||
void save(const std::filesystem::path& path);
|
void save(const std::filesystem::path& path);
|
||||||
|
|
||||||
@ -15,12 +18,16 @@ bool isNeoMode();
|
|||||||
bool isFullscreenMode();
|
bool isFullscreenMode();
|
||||||
bool getPlayBGM();
|
bool getPlayBGM();
|
||||||
int getBGMvolume();
|
int getBGMvolume();
|
||||||
|
bool getEnableDiscordRPC();
|
||||||
|
|
||||||
std::string getLogFilter();
|
std::string getLogFilter();
|
||||||
std::string getLogType();
|
std::string getLogType();
|
||||||
std::string getUserName();
|
std::string getUserName();
|
||||||
std::string getUpdateChannel();
|
std::string getUpdateChannel();
|
||||||
|
|
||||||
|
s16 getCursorState();
|
||||||
|
int getCursorHideTimeout();
|
||||||
|
std::string getBackButtonBehavior();
|
||||||
bool getUseSpecialPad();
|
bool getUseSpecialPad();
|
||||||
int getSpecialPadClass();
|
int getSpecialPadClass();
|
||||||
|
|
||||||
@ -50,11 +57,15 @@ void setScreenHeight(u32 height);
|
|||||||
void setFullscreenMode(bool enable);
|
void setFullscreenMode(bool enable);
|
||||||
void setPlayBGM(bool enable);
|
void setPlayBGM(bool enable);
|
||||||
void setBGMvolume(int volume);
|
void setBGMvolume(int volume);
|
||||||
|
void setEnableDiscordRPC(bool enable);
|
||||||
void setLanguage(u32 language);
|
void setLanguage(u32 language);
|
||||||
void setNeoMode(bool enable);
|
void setNeoMode(bool enable);
|
||||||
void setUserName(const std::string& type);
|
void setUserName(const std::string& type);
|
||||||
void setUpdateChannel(const std::string& type);
|
void setUpdateChannel(const std::string& type);
|
||||||
|
|
||||||
|
void setCursorState(s16 cursorState);
|
||||||
|
void setCursorHideTimeout(int newcursorHideTimeout);
|
||||||
|
void setBackButtonBehavior(const std::string& type);
|
||||||
void setUseSpecialPad(bool use);
|
void setUseSpecialPad(bool use);
|
||||||
void setSpecialPadClass(int type);
|
void setSpecialPadClass(int type);
|
||||||
|
|
||||||
@ -73,7 +84,7 @@ bool vkCrashDiagnosticEnabled();
|
|||||||
|
|
||||||
// Gui
|
// Gui
|
||||||
void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h);
|
void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h);
|
||||||
void setGameInstallDir(const std::filesystem::path& dir);
|
void setGameInstallDirs(const std::vector<std::filesystem::path>& dir);
|
||||||
void setAddonInstallDir(const std::filesystem::path& dir);
|
void setAddonInstallDir(const std::filesystem::path& dir);
|
||||||
void setMainWindowTheme(u32 theme);
|
void setMainWindowTheme(u32 theme);
|
||||||
void setIconSize(u32 size);
|
void setIconSize(u32 size);
|
||||||
@ -92,7 +103,7 @@ u32 getMainWindowGeometryX();
|
|||||||
u32 getMainWindowGeometryY();
|
u32 getMainWindowGeometryY();
|
||||||
u32 getMainWindowGeometryW();
|
u32 getMainWindowGeometryW();
|
||||||
u32 getMainWindowGeometryH();
|
u32 getMainWindowGeometryH();
|
||||||
std::filesystem::path getGameInstallDir();
|
std::vector<std::filesystem::path> getGameInstallDirs();
|
||||||
std::filesystem::path getAddonInstallDir();
|
std::filesystem::path getAddonInstallDir();
|
||||||
u32 getMainWindowTheme();
|
u32 getMainWindowTheme();
|
||||||
u32 getIconSize();
|
u32 getIconSize();
|
||||||
|
@ -1,43 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
#include <ctime>
|
|
||||||
#include "common/discord.h"
|
|
||||||
|
|
||||||
namespace Discord {
|
|
||||||
|
|
||||||
void RPC::init() {
|
|
||||||
DiscordEventHandlers handlers{};
|
|
||||||
Discord_Initialize("1139939140494971051", &handlers, 1, nullptr);
|
|
||||||
|
|
||||||
startTimestamp = time(nullptr);
|
|
||||||
enabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RPC::update(Discord::RPCStatus status, const std::string& game) {
|
|
||||||
DiscordRichPresence rpc{};
|
|
||||||
|
|
||||||
if (status == Discord::RPCStatus::Playing) {
|
|
||||||
rpc.details = "Playing a game";
|
|
||||||
rpc.state = game.c_str();
|
|
||||||
} else {
|
|
||||||
rpc.details = "Idle";
|
|
||||||
}
|
|
||||||
|
|
||||||
rpc.largeImageKey = "shadps4";
|
|
||||||
rpc.largeImageText = "ShadPS4 is a PS4 emulator";
|
|
||||||
rpc.startTimestamp = startTimestamp;
|
|
||||||
|
|
||||||
Discord_UpdatePresence(&rpc);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RPC::stop() {
|
|
||||||
if (enabled) {
|
|
||||||
enabled = false;
|
|
||||||
Discord_ClearPresence();
|
|
||||||
Discord_Shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Discord
|
|
57
src/common/discord_rpc_handler.cpp
Normal file
57
src/common/discord_rpc_handler.cpp
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <ctime>
|
||||||
|
#include "src/common/discord_rpc_handler.h"
|
||||||
|
|
||||||
|
namespace DiscordRPCHandler {
|
||||||
|
|
||||||
|
void RPC::init() {
|
||||||
|
DiscordEventHandlers handlers{};
|
||||||
|
|
||||||
|
Discord_Initialize("1139939140494971051", &handlers, 1, nullptr);
|
||||||
|
startTimestamp = time(nullptr);
|
||||||
|
rpcEnabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RPC::setStatusIdling() {
|
||||||
|
DiscordRichPresence rpc{};
|
||||||
|
rpc.largeImageKey = "https://github.com/shadps4-emu/shadPS4/raw/main/.github/shadps4.png";
|
||||||
|
rpc.largeImageText = "shadPS4 is a PS4 emulator";
|
||||||
|
rpc.startTimestamp = startTimestamp;
|
||||||
|
rpc.details = "Idle";
|
||||||
|
|
||||||
|
status = RPCStatus::Idling;
|
||||||
|
Discord_UpdatePresence(&rpc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RPC::setStatusPlaying(const std::string& game_name, const std::string& game_id) {
|
||||||
|
DiscordRichPresence rpc{};
|
||||||
|
|
||||||
|
rpc.details = "Playing";
|
||||||
|
rpc.state = game_name.c_str();
|
||||||
|
std::string largeImageUrl =
|
||||||
|
"https://store.playstation.com/store/api/chihiro/00_09_000/titlecontainer/US/en/999/" +
|
||||||
|
game_id + "_00/image";
|
||||||
|
rpc.largeImageKey = largeImageUrl.c_str();
|
||||||
|
rpc.largeImageText = game_name.c_str();
|
||||||
|
rpc.startTimestamp = startTimestamp;
|
||||||
|
|
||||||
|
status = RPCStatus::Playing;
|
||||||
|
Discord_UpdatePresence(&rpc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RPC::shutdown() {
|
||||||
|
if (rpcEnabled) {
|
||||||
|
rpcEnabled = false;
|
||||||
|
Discord_ClearPresence();
|
||||||
|
Discord_Shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RPC::getRPCEnabled() {
|
||||||
|
return rpcEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace DiscordRPCHandler
|
@ -7,7 +7,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <discord_rpc.h>
|
#include <discord_rpc.h>
|
||||||
|
|
||||||
namespace Discord {
|
namespace DiscordRPCHandler {
|
||||||
|
|
||||||
enum class RPCStatus {
|
enum class RPCStatus {
|
||||||
Idling,
|
Idling,
|
||||||
@ -16,12 +16,15 @@ enum class RPCStatus {
|
|||||||
|
|
||||||
class RPC {
|
class RPC {
|
||||||
std::uint64_t startTimestamp;
|
std::uint64_t startTimestamp;
|
||||||
bool enabled = false;
|
bool rpcEnabled = false;
|
||||||
|
RPCStatus status;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void init();
|
void init();
|
||||||
void update(RPCStatus status, const std::string& title);
|
void setStatusIdling();
|
||||||
void stop();
|
void setStatusPlaying(const std::string& game_name, const std::string& game_id);
|
||||||
|
void shutdown();
|
||||||
|
bool getRPCEnabled();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Discord
|
} // namespace DiscordRPCHandler
|
@ -114,6 +114,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
|
|||||||
SUB(Lib, AvPlayer) \
|
SUB(Lib, AvPlayer) \
|
||||||
SUB(Lib, Ngs2) \
|
SUB(Lib, Ngs2) \
|
||||||
SUB(Lib, Audio3d) \
|
SUB(Lib, Audio3d) \
|
||||||
|
SUB(Lib, Fiber) \
|
||||||
CLS(Frontend) \
|
CLS(Frontend) \
|
||||||
CLS(Render) \
|
CLS(Render) \
|
||||||
SUB(Render, Vulkan) \
|
SUB(Render, Vulkan) \
|
||||||
|
@ -81,6 +81,7 @@ enum class Class : u8 {
|
|||||||
Lib_AvPlayer, ///< The LibSceAvPlayer implementation.
|
Lib_AvPlayer, ///< The LibSceAvPlayer implementation.
|
||||||
Lib_Ngs2, ///< The LibSceNgs2 implementation.
|
Lib_Ngs2, ///< The LibSceNgs2 implementation.
|
||||||
Lib_Audio3d, ///< The LibSceAudio3d implementation.
|
Lib_Audio3d, ///< The LibSceAudio3d implementation.
|
||||||
|
Lib_Fiber, ///< The LibSceFiber implementation.
|
||||||
Frontend, ///< Emulator UI
|
Frontend, ///< Emulator UI
|
||||||
Render, ///< Video Core
|
Render, ///< Video Core
|
||||||
Render_Vulkan, ///< Vulkan backend
|
Render_Vulkan, ///< Vulkan backend
|
||||||
|
@ -95,6 +95,18 @@ static auto UserPaths = [] {
|
|||||||
user_dir =
|
user_dir =
|
||||||
std::filesystem::path(getenv("HOME")) / "Library" / "Application Support" / "shadPS4";
|
std::filesystem::path(getenv("HOME")) / "Library" / "Application Support" / "shadPS4";
|
||||||
}
|
}
|
||||||
|
#elif defined(__linux__)
|
||||||
|
auto user_dir = std::filesystem::current_path() / PORTABLE_DIR;
|
||||||
|
// Check if the "user" directory exists in the current path:
|
||||||
|
if (!std::filesystem::exists(user_dir)) {
|
||||||
|
// If it doesn't exist, use XDG_DATA_HOME if it is set, and provide a standard default
|
||||||
|
const char* xdg_data_home = getenv("XDG_DATA_HOME");
|
||||||
|
if (xdg_data_home != nullptr && strlen(xdg_data_home) > 0) {
|
||||||
|
user_dir = std::filesystem::path(xdg_data_home) / "shadPS4";
|
||||||
|
} else {
|
||||||
|
user_dir = std::filesystem::path(getenv("HOME")) / ".local" / "share" / "shadPS4";
|
||||||
|
}
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
const auto user_dir = std::filesystem::current_path() / PORTABLE_DIR;
|
const auto user_dir = std::filesystem::current_path() / PORTABLE_DIR;
|
||||||
#endif
|
#endif
|
||||||
|
@ -25,7 +25,7 @@ asm(".zerofill GUEST_SYSTEM,GUEST_SYSTEM,__guest_system,0xFBFC00000");
|
|||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
static constexpr size_t BackingSize = SCE_KERNEL_MAIN_DMEM_SIZE;
|
static constexpr size_t BackingSize = SCE_KERNEL_MAIN_DMEM_SIZE_PRO;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
@ -227,6 +227,12 @@ void PSF::AddBinary(std::string key, std::vector<u8> value, bool update) {
|
|||||||
map_binaries.emplace(entry_list.size() - 1, std::move(value));
|
map_binaries.emplace(entry_list.size() - 1, std::move(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PSF::AddBinary(std::string key, uint64_t value, bool update) {
|
||||||
|
std::vector<u8> data(8);
|
||||||
|
std::memcpy(data.data(), &value, 8);
|
||||||
|
return AddBinary(std::move(key), std::move(data), update);
|
||||||
|
}
|
||||||
|
|
||||||
void PSF::AddString(std::string key, std::string value, bool update) {
|
void PSF::AddString(std::string key, std::string value, bool update) {
|
||||||
auto [it, index] = FindEntry(key);
|
auto [it, index] = FindEntry(key);
|
||||||
bool exist = it != entry_list.end();
|
bool exist = it != entry_list.end();
|
||||||
|
@ -67,6 +67,7 @@ public:
|
|||||||
std::optional<s32> GetInteger(std::string_view key) const;
|
std::optional<s32> GetInteger(std::string_view key) const;
|
||||||
|
|
||||||
void AddBinary(std::string key, std::vector<u8> value, bool update = false);
|
void AddBinary(std::string key, std::vector<u8> value, bool update = false);
|
||||||
|
void AddBinary(std::string key, uint64_t value, bool update = false); // rsv4 format
|
||||||
void AddString(std::string key, std::string value, bool update = false);
|
void AddString(std::string key, std::string value, bool update = false);
|
||||||
void AddInteger(std::string key, s32 value, bool update = false);
|
void AddInteger(std::string key, s32 value, bool update = false);
|
||||||
|
|
||||||
|
@ -499,3 +499,11 @@ constexpr int ORBIS_AVPLAYER_ERROR_INFO_OTHER_ENCRY = 0x806A00BF;
|
|||||||
constexpr int ORBIS_APP_CONTENT_ERROR_PARAMETER = 0x80D90002;
|
constexpr int ORBIS_APP_CONTENT_ERROR_PARAMETER = 0x80D90002;
|
||||||
constexpr int ORBIS_APP_CONTENT_ERROR_DRM_NO_ENTITLEMENT = 0x80D90007;
|
constexpr int ORBIS_APP_CONTENT_ERROR_DRM_NO_ENTITLEMENT = 0x80D90007;
|
||||||
constexpr int ORBIS_APP_CONTENT_ERROR_NOT_FOUND = 0x80D90005;
|
constexpr int ORBIS_APP_CONTENT_ERROR_NOT_FOUND = 0x80D90005;
|
||||||
|
|
||||||
|
// Fiber library
|
||||||
|
constexpr int ORBIS_FIBER_ERROR_NULL = 0x80590001;
|
||||||
|
constexpr int ORBIS_FIBER_ERROR_ALIGNMENT = 0x80590002;
|
||||||
|
constexpr int ORBIS_FIBER_ERROR_RANGE = 0x80590003;
|
||||||
|
constexpr int ORBIS_FIBER_ERROR_INVALID = 0x80590004;
|
||||||
|
constexpr int ORBIS_FIBER_ERROR_PERMISSION = 0x80590005;
|
||||||
|
constexpr int ORBIS_FIBER_ERROR_STATE = 0x80590006;
|
284
src/core/libraries/fiber/fiber.cpp
Normal file
284
src/core/libraries/fiber/fiber.cpp
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "fiber.h"
|
||||||
|
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "common/singleton.h"
|
||||||
|
#include "core/libraries/error_codes.h"
|
||||||
|
#include "core/libraries/libs.h"
|
||||||
|
#include "core/linker.h"
|
||||||
|
|
||||||
|
#ifdef _WIN64
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Libraries::Fiber {
|
||||||
|
|
||||||
|
constexpr static u64 kFiberSignature = 0x054ad954;
|
||||||
|
|
||||||
|
thread_local SceFiber* gCurrentFiber = nullptr;
|
||||||
|
thread_local void* gFiberThread = nullptr;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto* linker = Common::Singleton<Core::Linker>::Instance();
|
||||||
|
linker->ExecuteGuest(fiber->entry, fiber->argOnInitialize, argRun);
|
||||||
|
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (!fiber || !name || !entry) {
|
||||||
|
return ORBIS_FIBER_ERROR_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fiber->signature = kFiberSignature;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberOptParamInitialize(SceFiberOptParam* optParam) {
|
||||||
|
LOG_ERROR(Lib_Fiber, "called");
|
||||||
|
|
||||||
|
if (!optParam) {
|
||||||
|
return ORBIS_FIBER_ERROR_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberFinalize(SceFiber* fiber) {
|
||||||
|
LOG_TRACE(Lib_Fiber, "called");
|
||||||
|
|
||||||
|
if (!fiber) {
|
||||||
|
return ORBIS_FIBER_ERROR_NULL;
|
||||||
|
}
|
||||||
|
if ((u64)fiber % 8 != 0) {
|
||||||
|
return ORBIS_FIBER_ERROR_ALIGNMENT;
|
||||||
|
}
|
||||||
|
if (fiber->signature != kFiberSignature) {
|
||||||
|
return ORBIS_FIBER_ERROR_INVALID;
|
||||||
|
}
|
||||||
|
if (fiber->state != FiberState::Run) {
|
||||||
|
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");
|
||||||
|
|
||||||
|
if (!fiber) {
|
||||||
|
return ORBIS_FIBER_ERROR_NULL;
|
||||||
|
}
|
||||||
|
if ((u64)fiber % 8 != 0) {
|
||||||
|
return ORBIS_FIBER_ERROR_ALIGNMENT;
|
||||||
|
}
|
||||||
|
if (fiber->signature != kFiberSignature) {
|
||||||
|
return ORBIS_FIBER_ERROR_INVALID;
|
||||||
|
}
|
||||||
|
if (fiber->state == FiberState::Run) {
|
||||||
|
return ORBIS_FIBER_ERROR_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gFiberThread == nullptr) {
|
||||||
|
#ifdef _WIN64
|
||||||
|
gFiberThread = ConvertThreadToFiber(nullptr);
|
||||||
|
#else
|
||||||
|
UNREACHABLE_MSG("Missing implementation");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
gCurrentFiber = fiber;
|
||||||
|
|
||||||
|
if (fiber->pArgRun != nullptr) {
|
||||||
|
*fiber->pArgRun = argOnRunTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
fiber->pArgReturn = argOnReturn;
|
||||||
|
fiber->state = FiberState::Run;
|
||||||
|
#ifdef _WIN64
|
||||||
|
SwitchToFiber(fiber->handle);
|
||||||
|
#else
|
||||||
|
UNREACHABLE_MSG("Missing implementation");
|
||||||
|
#endif
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberSwitch(SceFiber* fiber, u64 argOnRunTo, u64* argOnRun) {
|
||||||
|
LOG_TRACE(Lib_Fiber, "called");
|
||||||
|
|
||||||
|
if (!fiber) {
|
||||||
|
return ORBIS_FIBER_ERROR_NULL;
|
||||||
|
}
|
||||||
|
if ((u64)fiber % 8 != 0) {
|
||||||
|
return ORBIS_FIBER_ERROR_ALIGNMENT;
|
||||||
|
}
|
||||||
|
if (fiber->signature != kFiberSignature) {
|
||||||
|
return ORBIS_FIBER_ERROR_INVALID;
|
||||||
|
}
|
||||||
|
if (gCurrentFiber == nullptr) {
|
||||||
|
return ORBIS_FIBER_ERROR_PERMISSION;
|
||||||
|
}
|
||||||
|
if (fiber->state == FiberState::Run) {
|
||||||
|
return ORBIS_FIBER_ERROR_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gCurrentFiber->state = FiberState::Suspend;
|
||||||
|
|
||||||
|
// TODO: argOnRun
|
||||||
|
|
||||||
|
*fiber->pArgRun = argOnRunTo;
|
||||||
|
fiber->state = FiberState::Run;
|
||||||
|
|
||||||
|
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) {
|
||||||
|
return ORBIS_FIBER_ERROR_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fiberInfo->entry = fiber->entry;
|
||||||
|
fiberInfo->argOnInitialize = fiber->argOnInitialize;
|
||||||
|
fiberInfo->addrContext = nullptr;
|
||||||
|
fiberInfo->sizeContext = fiber->sizeContext;
|
||||||
|
fiberInfo->sizeContextMargin = 0;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberStopContextSizeCheck() {
|
||||||
|
LOG_ERROR(Lib_Fiber, "called");
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberRename(SceFiber* fiber, const char* name) {
|
||||||
|
LOG_INFO(Lib_Fiber, "called, name = {}", name);
|
||||||
|
|
||||||
|
if (!fiber || !name) {
|
||||||
|
return ORBIS_FIBER_ERROR_NULL;
|
||||||
|
}
|
||||||
|
if ((u64)fiber % 8 != 0) {
|
||||||
|
return ORBIS_FIBER_ERROR_ALIGNMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(fiber->name, name, ORBIS_FIBER_MAX_NAME_LENGTH);
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegisterlibSceFiber(Core::Loader::SymbolsResolver* sym) {
|
||||||
|
LIB_FUNCTION("hVYD7Ou2pCQ", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberInitialize);
|
||||||
|
LIB_FUNCTION("asjUJJ+aa8s", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberOptParamInitialize);
|
||||||
|
LIB_FUNCTION("JeNX5F-NzQU", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberFinalize);
|
||||||
|
|
||||||
|
LIB_FUNCTION("a0LLrZWac0M", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberRun);
|
||||||
|
LIB_FUNCTION("PFT2S-tJ7Uk", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberSwitch);
|
||||||
|
LIB_FUNCTION("p+zLIOg27zU", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberGetSelf);
|
||||||
|
LIB_FUNCTION("B0ZX2hx9DMw", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberReturnToThread);
|
||||||
|
|
||||||
|
LIB_FUNCTION("uq2Y5BFz0PE", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberGetInfo);
|
||||||
|
LIB_FUNCTION("Lcqty+QNWFc", "libSceFiber", 1, "libSceFiber", 1, 1,
|
||||||
|
sceFiberStartContextSizeCheck);
|
||||||
|
LIB_FUNCTION("Kj4nXMpnM8Y", "libSceFiber", 1, "libSceFiber", 1, 1,
|
||||||
|
sceFiberStopContextSizeCheck);
|
||||||
|
LIB_FUNCTION("JzyT91ucGDc", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberRename);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Libraries::Fiber
|
83
src/core/libraries/fiber/fiber.h
Normal file
83
src/core/libraries/fiber/fiber.h
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/assert.h"
|
||||||
|
#include "common/types.h"
|
||||||
|
|
||||||
|
namespace Core::Loader {
|
||||||
|
class SymbolsResolver;
|
||||||
|
}
|
||||||
|
namespace Libraries::Fiber {
|
||||||
|
|
||||||
|
#define ORBIS_FIBER_MAX_NAME_LENGTH (31)
|
||||||
|
|
||||||
|
typedef void PS4_SYSV_ABI (*SceFiberEntry)(u64 argOnInitialize, u64 argOnRun);
|
||||||
|
|
||||||
|
enum FiberState : u32 {
|
||||||
|
None = 0u,
|
||||||
|
Init = 1u,
|
||||||
|
Run = 2u,
|
||||||
|
Suspend = 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;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(SceFiber) <= 256);
|
||||||
|
|
||||||
|
struct SceFiberInfo {
|
||||||
|
u64 size;
|
||||||
|
SceFiberEntry entry;
|
||||||
|
u64 argOnInitialize;
|
||||||
|
void* addrContext;
|
||||||
|
u64 sizeContext;
|
||||||
|
char name[ORBIS_FIBER_MAX_NAME_LENGTH + 1];
|
||||||
|
u64 sizeContextMargin;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(SceFiberInfo) <= 128);
|
||||||
|
|
||||||
|
typedef void* SceFiberOptParam;
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberInitialize(SceFiber* fiber, const char* name, SceFiberEntry entry,
|
||||||
|
u64 argOnInitialize, void* addrContext, u64 sizeContext,
|
||||||
|
const SceFiberOptParam* optParam);
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberOptParamInitialize(SceFiberOptParam* optParam);
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberFinalize(SceFiber* fiber);
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberRun(SceFiber* fiber, u64 argOnRunTo, u64* argOnReturn);
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberSwitch(SceFiber* fiber, u64 argOnRunTo, u64* argOnRun);
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberGetSelf(SceFiber** fiber);
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberReturnToThread(u64 argOnReturn, u64* argOnRun);
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberGetInfo(SceFiber* fiber, SceFiberInfo* fiberInfo);
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberStartContextSizeCheck(u32 flags);
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberStopContextSizeCheck(void);
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceFiberRename(SceFiber* fiber, const char* name);
|
||||||
|
|
||||||
|
void RegisterlibSceFiber(Core::Loader::SymbolsResolver* sym);
|
||||||
|
} // namespace Libraries::Fiber
|
@ -1076,10 +1076,28 @@ s32 PS4_SYSV_ABI sceGnmInsertPopMarker(u32* cmdbuf, u32 size) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceGnmInsertPushColorMarker() {
|
s32 PS4_SYSV_ABI sceGnmInsertPushColorMarker(u32* cmdbuf, u32 size, const char* marker, u32 color) {
|
||||||
LOG_ERROR(Lib_GnmDriver, "(STUBBED) called");
|
LOG_TRACE(Lib_GnmDriver, "called");
|
||||||
|
|
||||||
|
if (cmdbuf && marker) {
|
||||||
|
const auto len = std::strlen(marker);
|
||||||
|
const u32 packet_size = ((len + 0xc) >> 2) + ((len + 0x10) >> 3) * 2;
|
||||||
|
if (packet_size + 2 == size) {
|
||||||
|
auto* nop = reinterpret_cast<PM4CmdNop*>(cmdbuf);
|
||||||
|
nop->header =
|
||||||
|
PM4Type3Header{PM4ItOpcode::Nop, packet_size, PM4ShaderType::ShaderGraphics};
|
||||||
|
nop->data_block[0] = PM4CmdNop::PayloadType::DebugColorMarkerPush;
|
||||||
|
const auto marker_len = len + 1;
|
||||||
|
std::memcpy(&nop->data_block[1], marker, marker_len);
|
||||||
|
*reinterpret_cast<u32*>(reinterpret_cast<u8*>(&nop->data_block[1]) + marker_len + 8) =
|
||||||
|
color;
|
||||||
|
std::memset(reinterpret_cast<u8*>(&nop->data_block[1]) + marker_len + 8 + sizeof(u32),
|
||||||
|
0, packet_size * 4 - marker_len - 8 - sizeof(u32));
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI sceGnmInsertPushMarker(u32* cmdbuf, u32 size, const char* marker) {
|
s32 PS4_SYSV_ABI sceGnmInsertPushMarker(u32* cmdbuf, u32 size, const char* marker) {
|
||||||
LOG_TRACE(Lib_GnmDriver, "called");
|
LOG_TRACE(Lib_GnmDriver, "called");
|
||||||
|
@ -105,7 +105,7 @@ int PS4_SYSV_ABI sceGnmGpuPaDebugEnter();
|
|||||||
int PS4_SYSV_ABI sceGnmGpuPaDebugLeave();
|
int PS4_SYSV_ABI sceGnmGpuPaDebugLeave();
|
||||||
int PS4_SYSV_ABI sceGnmInsertDingDongMarker();
|
int PS4_SYSV_ABI sceGnmInsertDingDongMarker();
|
||||||
s32 PS4_SYSV_ABI sceGnmInsertPopMarker(u32* cmdbuf, u32 size);
|
s32 PS4_SYSV_ABI sceGnmInsertPopMarker(u32* cmdbuf, u32 size);
|
||||||
int PS4_SYSV_ABI sceGnmInsertPushColorMarker();
|
s32 PS4_SYSV_ABI sceGnmInsertPushColorMarker(u32* cmdbuf, u32 size, const char* marker, u32 color);
|
||||||
s32 PS4_SYSV_ABI sceGnmInsertPushMarker(u32* cmdbuf, u32 size, const char* marker);
|
s32 PS4_SYSV_ABI sceGnmInsertPushMarker(u32* cmdbuf, u32 size, const char* marker);
|
||||||
int PS4_SYSV_ABI sceGnmInsertSetColorMarker();
|
int PS4_SYSV_ABI sceGnmInsertSetColorMarker();
|
||||||
int PS4_SYSV_ABI sceGnmInsertSetMarker();
|
int PS4_SYSV_ABI sceGnmInsertSetMarker();
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
|
|
||||||
constexpr u64 SCE_KERNEL_MAIN_DMEM_SIZE = 5056_MB; // ~ 5GB
|
constexpr u64 SCE_KERNEL_MAIN_DMEM_SIZE = 5056_MB; // ~ 5GB
|
||||||
|
// TODO: Confirm this value on hardware.
|
||||||
|
constexpr u64 SCE_KERNEL_MAIN_DMEM_SIZE_PRO = 5568_MB; // ~ 5.5GB
|
||||||
|
|
||||||
namespace Libraries::Kernel {
|
namespace Libraries::Kernel {
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "core/libraries/dialogs/error_dialog.h"
|
#include "core/libraries/dialogs/error_dialog.h"
|
||||||
#include "core/libraries/dialogs/ime_dialog.h"
|
#include "core/libraries/dialogs/ime_dialog.h"
|
||||||
#include "core/libraries/disc_map/disc_map.h"
|
#include "core/libraries/disc_map/disc_map.h"
|
||||||
|
#include "core/libraries/fiber/fiber.h"
|
||||||
#include "core/libraries/gnmdriver/gnmdriver.h"
|
#include "core/libraries/gnmdriver/gnmdriver.h"
|
||||||
#include "core/libraries/kernel/libkernel.h"
|
#include "core/libraries/kernel/libkernel.h"
|
||||||
#include "core/libraries/libc_internal/libc_internal.h"
|
#include "core/libraries/libc_internal/libc_internal.h"
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
namespace Libraries::Net {
|
namespace Libraries::Net {
|
||||||
|
|
||||||
|
static thread_local int32_t net_errno = 0;
|
||||||
|
|
||||||
int PS4_SYSV_ABI in6addr_any() {
|
int PS4_SYSV_ABI in6addr_any() {
|
||||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
@ -563,9 +565,9 @@ int PS4_SYSV_ABI sceNetEpollWait() {
|
|||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceNetErrnoLoc() {
|
int* PS4_SYSV_ABI sceNetErrnoLoc() {
|
||||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return &net_errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceNetEtherNtostr() {
|
int PS4_SYSV_ABI sceNetEtherNtostr() {
|
||||||
|
@ -136,7 +136,7 @@ int PS4_SYSV_ABI sceNetEpollControl();
|
|||||||
int PS4_SYSV_ABI sceNetEpollCreate();
|
int PS4_SYSV_ABI sceNetEpollCreate();
|
||||||
int PS4_SYSV_ABI sceNetEpollDestroy();
|
int PS4_SYSV_ABI sceNetEpollDestroy();
|
||||||
int PS4_SYSV_ABI sceNetEpollWait();
|
int PS4_SYSV_ABI sceNetEpollWait();
|
||||||
int PS4_SYSV_ABI sceNetErrnoLoc();
|
int* PS4_SYSV_ABI sceNetErrnoLoc();
|
||||||
int PS4_SYSV_ABI sceNetEtherNtostr();
|
int PS4_SYSV_ABI sceNetEtherNtostr();
|
||||||
int PS4_SYSV_ABI sceNetEtherStrton();
|
int PS4_SYSV_ABI sceNetEtherStrton();
|
||||||
int PS4_SYSV_ABI sceNetEventCallbackCreate();
|
int PS4_SYSV_ABI sceNetEventCallbackCreate();
|
||||||
|
@ -902,12 +902,13 @@ int PS4_SYSV_ABI sceNpCreateAsyncRequest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceNpCreateRequest() {
|
int PS4_SYSV_ABI sceNpCreateRequest() {
|
||||||
LOG_ERROR(Lib_NpManager, "(STUBBED) called");
|
LOG_ERROR(Lib_NpManager, "(DUMMY) called");
|
||||||
return ORBIS_OK;
|
static int id = 0;
|
||||||
|
return ++id;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceNpDeleteRequest() {
|
int PS4_SYSV_ABI sceNpDeleteRequest(int reqId) {
|
||||||
LOG_ERROR(Lib_NpManager, "(STUBBED) called");
|
LOG_ERROR(Lib_NpManager, "(DUMMY) called reqId = {}", reqId);
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,7 +218,7 @@ int PS4_SYSV_ABI sceNpCheckNpReachability();
|
|||||||
int PS4_SYSV_ABI sceNpCheckPlus();
|
int PS4_SYSV_ABI sceNpCheckPlus();
|
||||||
int PS4_SYSV_ABI sceNpCreateAsyncRequest();
|
int PS4_SYSV_ABI sceNpCreateAsyncRequest();
|
||||||
int PS4_SYSV_ABI sceNpCreateRequest();
|
int PS4_SYSV_ABI sceNpCreateRequest();
|
||||||
int PS4_SYSV_ABI sceNpDeleteRequest();
|
int PS4_SYSV_ABI sceNpDeleteRequest(int reqId);
|
||||||
int PS4_SYSV_ABI sceNpGetAccountAge();
|
int PS4_SYSV_ABI sceNpGetAccountAge();
|
||||||
int PS4_SYSV_ABI sceNpGetAccountCountry();
|
int PS4_SYSV_ABI sceNpGetAccountCountry();
|
||||||
int PS4_SYSV_ABI sceNpGetAccountCountryA();
|
int PS4_SYSV_ABI sceNpGetAccountCountryA();
|
||||||
|
@ -12,9 +12,9 @@
|
|||||||
#include "core/file_sys/fs.h"
|
#include "core/file_sys/fs.h"
|
||||||
#include "save_instance.h"
|
#include "save_instance.h"
|
||||||
|
|
||||||
constexpr u32 OrbisSaveDataBlocksMax = 32768; // 1 GiB
|
constexpr auto OrbisSaveDataBlocksMin2 = 96; // 3MiB
|
||||||
|
constexpr auto OrbisSaveDataBlocksMax = 32768; // 1 GiB
|
||||||
constexpr std::string_view sce_sys = "sce_sys"; // system folder inside save
|
constexpr std::string_view sce_sys = "sce_sys"; // system folder inside save
|
||||||
constexpr std::string_view max_block_file_name = "max_block.txt";
|
|
||||||
|
|
||||||
static Core::FileSys::MntPoints* g_mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
static Core::FileSys::MntPoints* g_mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
||||||
|
|
||||||
@ -58,18 +58,13 @@ std::filesystem::path SaveInstance::MakeDirSavePath(OrbisUserServiceUserId user_
|
|||||||
game_serial / dir_name;
|
game_serial / dir_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SaveInstance::GetMaxBlocks(const std::filesystem::path& save_path) {
|
uint64_t SaveInstance::GetMaxBlockFromSFO(const PSF& psf) {
|
||||||
Common::FS::IOFile max_blocks_file{save_path / sce_sys / max_block_file_name,
|
const auto vec = psf.GetBinary(std::string{SaveParams::SAVEDATA_BLOCKS});
|
||||||
Common::FS::FileAccessMode::Read};
|
if (!vec.has_value()) {
|
||||||
int max_blocks = 0;
|
return OrbisSaveDataBlocksMax;
|
||||||
if (max_blocks_file.IsOpen()) {
|
|
||||||
max_blocks = std::atoi(max_blocks_file.ReadString(16).c_str());
|
|
||||||
}
|
}
|
||||||
if (max_blocks <= 0) {
|
auto value = vec.value();
|
||||||
max_blocks = OrbisSaveDataBlocksMax;
|
return *(uint64_t*)value.data();
|
||||||
}
|
|
||||||
|
|
||||||
return max_blocks;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::filesystem::path SaveInstance::GetParamSFOPath(const std::filesystem::path& dir_path) {
|
std::filesystem::path SaveInstance::GetParamSFOPath(const std::filesystem::path& dir_path) {
|
||||||
@ -92,13 +87,15 @@ void SaveInstance::SetupDefaultParamSFO(PSF& param_sfo, std::string dir_name,
|
|||||||
P(String, SaveParams::SAVEDATA_DIRECTORY, std::move(dir_name));
|
P(String, SaveParams::SAVEDATA_DIRECTORY, std::move(dir_name));
|
||||||
P(Integer, SaveParams::SAVEDATA_LIST_PARAM, 0);
|
P(Integer, SaveParams::SAVEDATA_LIST_PARAM, 0);
|
||||||
P(String, SaveParams::TITLE_ID, std::move(game_serial));
|
P(String, SaveParams::TITLE_ID, std::move(game_serial));
|
||||||
|
P(Binary, SaveParams::SAVEDATA_BLOCKS, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
|
||||||
#undef P
|
#undef P
|
||||||
}
|
}
|
||||||
|
|
||||||
SaveInstance::SaveInstance(int slot_num, OrbisUserServiceUserId user_id, std::string _game_serial,
|
SaveInstance::SaveInstance(int slot_num, OrbisUserServiceUserId user_id, std::string _game_serial,
|
||||||
std::string_view _dir_name, int max_blocks)
|
std::string_view _dir_name, int max_blocks)
|
||||||
: slot_num(slot_num), user_id(user_id), game_serial(std::move(_game_serial)),
|
: slot_num(slot_num), user_id(user_id), game_serial(std::move(_game_serial)),
|
||||||
dir_name(_dir_name), max_blocks(max_blocks) {
|
dir_name(_dir_name),
|
||||||
|
max_blocks(std::clamp(max_blocks, OrbisSaveDataBlocksMin2, OrbisSaveDataBlocksMax)) {
|
||||||
ASSERT(slot_num >= 0 && slot_num < 16);
|
ASSERT(slot_num >= 0 && slot_num < 16);
|
||||||
|
|
||||||
save_path = MakeDirSavePath(user_id, game_serial, dir_name);
|
save_path = MakeDirSavePath(user_id, game_serial, dir_name);
|
||||||
@ -187,7 +184,7 @@ void SaveInstance::SetupAndMount(bool read_only, bool copy_icon, bool ignore_cor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
max_blocks = GetMaxBlocks(save_path);
|
max_blocks = static_cast<int>(GetMaxBlockFromSFO(param_sfo));
|
||||||
|
|
||||||
g_mnt->Mount(save_path, mount_point, read_only);
|
g_mnt->Mount(save_path, mount_point, read_only);
|
||||||
mounted = true;
|
mounted = true;
|
||||||
@ -217,16 +214,13 @@ void SaveInstance::CreateFiles() {
|
|||||||
fs::create_directories(sce_sys_dir);
|
fs::create_directories(sce_sys_dir);
|
||||||
|
|
||||||
SetupDefaultParamSFO(param_sfo, dir_name, game_serial);
|
SetupDefaultParamSFO(param_sfo, dir_name, game_serial);
|
||||||
|
param_sfo.AddBinary(std::string{SaveParams::SAVEDATA_BLOCKS}, max_blocks, true);
|
||||||
|
|
||||||
const bool ok = param_sfo.Encode(param_sfo_path);
|
const bool ok = param_sfo.Encode(param_sfo_path);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
throw std::filesystem::filesystem_error("Failed to write param.sfo", param_sfo_path,
|
throw std::filesystem::filesystem_error("Failed to write param.sfo", param_sfo_path,
|
||||||
std::make_error_code(std::errc::permission_denied));
|
std::make_error_code(std::errc::permission_denied));
|
||||||
}
|
}
|
||||||
|
|
||||||
Common::FS::IOFile max_block{sce_sys_dir / max_block_file_name,
|
|
||||||
Common::FS::FileAccessMode::Write};
|
|
||||||
max_block.WriteString(std::to_string(max_blocks == 0 ? OrbisSaveDataBlocksMax : max_blocks));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Libraries::SaveData
|
} // namespace Libraries::SaveData
|
@ -62,7 +62,7 @@ public:
|
|||||||
std::string_view game_serial,
|
std::string_view game_serial,
|
||||||
std::string_view dir_name);
|
std::string_view dir_name);
|
||||||
|
|
||||||
static int GetMaxBlocks(const std::filesystem::path& save_path);
|
static uint64_t GetMaxBlockFromSFO(const PSF& psf);
|
||||||
|
|
||||||
// Get param.sfo path from a dir_path generated by MakeDirSavePath
|
// Get param.sfo path from a dir_path generated by MakeDirSavePath
|
||||||
static std::filesystem::path GetParamSFOPath(const std::filesystem::path& dir_path);
|
static std::filesystem::path GetParamSFOPath(const std::filesystem::path& dir_path);
|
||||||
|
@ -445,7 +445,7 @@ static Error saveDataMount(const OrbisSaveDataMount2* mount_info,
|
|||||||
fs::create_directories(root_save);
|
fs::create_directories(root_save);
|
||||||
const auto available = fs::space(root_save).available;
|
const auto available = fs::space(root_save).available;
|
||||||
|
|
||||||
auto requested_size = mount_info->blocks * OrbisSaveDataBlockSize;
|
auto requested_size = save_instance.GetMaxBlocks() * OrbisSaveDataBlockSize;
|
||||||
if (requested_size > available) {
|
if (requested_size > available) {
|
||||||
mount_result->required_blocks = (requested_size - available) / OrbisSaveDataBlockSize;
|
mount_result->required_blocks = (requested_size - available) / OrbisSaveDataBlockSize;
|
||||||
return Error::NO_SPACE_FS;
|
return Error::NO_SPACE_FS;
|
||||||
@ -830,10 +830,11 @@ Error PS4_SYSV_ABI sceSaveDataDirNameSearch(const OrbisSaveDataDirNameSearchCond
|
|||||||
LOG_ERROR(Lib_SaveData, "Failed to read SFO: {}", fmt::UTF(sfo_path.u8string()));
|
LOG_ERROR(Lib_SaveData, "Failed to read SFO: {}", fmt::UTF(sfo_path.u8string()));
|
||||||
ASSERT_MSG(false, "Failed to read SFO");
|
ASSERT_MSG(false, "Failed to read SFO");
|
||||||
}
|
}
|
||||||
map_dir_sfo.emplace(dir_name, std::move(sfo));
|
|
||||||
|
|
||||||
size_t size = Common::FS::GetDirectorySize(dir_path);
|
size_t size = Common::FS::GetDirectorySize(dir_path);
|
||||||
size_t total = SaveInstance::GetMaxBlocks(dir_path);
|
size_t total = SaveInstance::GetMaxBlockFromSFO(sfo);
|
||||||
|
|
||||||
|
map_dir_sfo.emplace(dir_name, std::move(sfo));
|
||||||
map_free_size.emplace(dir_name, total - size / OrbisSaveDataBlockSize);
|
map_free_size.emplace(dir_name, total - size / OrbisSaveDataBlockSize);
|
||||||
map_max_blocks.emplace(dir_name, total);
|
map_max_blocks.emplace(dir_name, total);
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "common/alignment.h"
|
#include "common/alignment.h"
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
#include "common/config.h"
|
||||||
#include "common/debug.h"
|
#include "common/debug.h"
|
||||||
#include "core/libraries/error_codes.h"
|
#include "core/libraries/error_codes.h"
|
||||||
#include "core/libraries/kernel/memory_management.h"
|
#include "core/libraries/kernel/memory_management.h"
|
||||||
@ -39,8 +40,10 @@ MemoryManager::MemoryManager() {
|
|||||||
MemoryManager::~MemoryManager() = default;
|
MemoryManager::~MemoryManager() = default;
|
||||||
|
|
||||||
void MemoryManager::SetupMemoryRegions(u64 flexible_size) {
|
void MemoryManager::SetupMemoryRegions(u64 flexible_size) {
|
||||||
|
const auto total_size =
|
||||||
|
Config::isNeoMode() ? SCE_KERNEL_MAIN_DMEM_SIZE_PRO : SCE_KERNEL_MAIN_DMEM_SIZE;
|
||||||
total_flexible_size = flexible_size;
|
total_flexible_size = flexible_size;
|
||||||
total_direct_size = SCE_KERNEL_MAIN_DMEM_SIZE - flexible_size;
|
total_direct_size = total_size - flexible_size;
|
||||||
|
|
||||||
// Insert an area that covers direct memory physical block.
|
// Insert an area that covers direct memory physical block.
|
||||||
// Note that this should never be called after direct memory allocations have been made.
|
// Note that this should never be called after direct memory allocations have been made.
|
||||||
|
108
src/emulator.cpp
108
src/emulator.cpp
@ -8,9 +8,11 @@
|
|||||||
#include "common/logging/backend.h"
|
#include "common/logging/backend.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#ifdef ENABLE_QT_GUI
|
#ifdef ENABLE_QT_GUI
|
||||||
|
#include <QtCore>
|
||||||
#include "common/memory_patcher.h"
|
#include "common/memory_patcher.h"
|
||||||
#endif
|
#endif
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
#include "common/discord_rpc_handler.h"
|
||||||
#include "common/elf_info.h"
|
#include "common/elf_info.h"
|
||||||
#include "common/ntapi.h"
|
#include "common/ntapi.h"
|
||||||
#include "common/path_util.h"
|
#include "common/path_util.h"
|
||||||
@ -24,6 +26,7 @@
|
|||||||
#include "core/file_format/trp.h"
|
#include "core/file_format/trp.h"
|
||||||
#include "core/file_sys/fs.h"
|
#include "core/file_sys/fs.h"
|
||||||
#include "core/libraries/disc_map/disc_map.h"
|
#include "core/libraries/disc_map/disc_map.h"
|
||||||
|
#include "core/libraries/fiber/fiber.h"
|
||||||
#include "core/libraries/kernel/thread_management.h"
|
#include "core/libraries/kernel/thread_management.h"
|
||||||
#include "core/libraries/libc_internal/libc_internal.h"
|
#include "core/libraries/libc_internal/libc_internal.h"
|
||||||
#include "core/libraries/libs.h"
|
#include "core/libraries/libs.h"
|
||||||
@ -58,6 +61,7 @@ Emulator::Emulator() {
|
|||||||
LOG_INFO(Loader, "Branch {}", Common::g_scm_branch);
|
LOG_INFO(Loader, "Branch {}", Common::g_scm_branch);
|
||||||
LOG_INFO(Loader, "Description {}", Common::g_scm_desc);
|
LOG_INFO(Loader, "Description {}", Common::g_scm_desc);
|
||||||
|
|
||||||
|
LOG_INFO(Config, "General Logtype: {}", Config::getLogType());
|
||||||
LOG_INFO(Config, "General isNeo: {}", Config::isNeoMode());
|
LOG_INFO(Config, "General isNeo: {}", Config::isNeoMode());
|
||||||
LOG_INFO(Config, "GPU isNullGpu: {}", Config::nullGpu());
|
LOG_INFO(Config, "GPU isNullGpu: {}", Config::nullGpu());
|
||||||
LOG_INFO(Config, "GPU shouldDumpShaders: {}", Config::dumpShaders());
|
LOG_INFO(Config, "GPU shouldDumpShaders: {}", Config::dumpShaders());
|
||||||
@ -77,6 +81,17 @@ Emulator::Emulator() {
|
|||||||
|
|
||||||
// Load renderdoc module.
|
// Load renderdoc module.
|
||||||
VideoCore::LoadRenderDoc();
|
VideoCore::LoadRenderDoc();
|
||||||
|
|
||||||
|
// Start the timer (Play Time)
|
||||||
|
#ifdef ENABLE_QT_GUI
|
||||||
|
start_time = std::chrono::steady_clock::now();
|
||||||
|
const auto user_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
|
||||||
|
QString filePath = QString::fromStdString((user_dir / "play_time.txt").string());
|
||||||
|
QFile file(filePath);
|
||||||
|
if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) {
|
||||||
|
LOG_INFO(Loader, "Error opening or creating play_time.txt");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
Emulator::~Emulator() {
|
Emulator::~Emulator() {
|
||||||
@ -120,6 +135,14 @@ void Emulator::Run(const std::filesystem::path& file) {
|
|||||||
}
|
}
|
||||||
#ifdef ENABLE_QT_GUI
|
#ifdef ENABLE_QT_GUI
|
||||||
MemoryPatcher::g_game_serial = id;
|
MemoryPatcher::g_game_serial = id;
|
||||||
|
|
||||||
|
// Timer for 'Play Time'
|
||||||
|
QTimer* timer = new QTimer();
|
||||||
|
QObject::connect(timer, &QTimer::timeout, [this, id]() {
|
||||||
|
UpdatePlayTime(id);
|
||||||
|
start_time = std::chrono::steady_clock::now();
|
||||||
|
});
|
||||||
|
timer->start(60000); // 60000 ms = 1 minute
|
||||||
#endif
|
#endif
|
||||||
title = param_sfo->GetString("TITLE").value_or("Unknown title");
|
title = param_sfo->GetString("TITLE").value_or("Unknown title");
|
||||||
LOG_INFO(Loader, "Game id: {} Title: {}", id, title);
|
LOG_INFO(Loader, "Game id: {} Title: {}", id, title);
|
||||||
@ -209,6 +232,15 @@ void Emulator::Run(const std::filesystem::path& file) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Discord RPC
|
||||||
|
if (Config::getEnableDiscordRPC()) {
|
||||||
|
auto* rpc = Common::Singleton<DiscordRPCHandler::RPC>::Instance();
|
||||||
|
if (rpc->getRPCEnabled() == false) {
|
||||||
|
rpc->init();
|
||||||
|
}
|
||||||
|
rpc->setStatusPlaying(game_info.title, id);
|
||||||
|
}
|
||||||
|
|
||||||
// start execution
|
// start execution
|
||||||
std::jthread mainthread =
|
std::jthread mainthread =
|
||||||
std::jthread([this](std::stop_token stop_token) { linker->Execute(); });
|
std::jthread([this](std::stop_token stop_token) { linker->Execute(); });
|
||||||
@ -217,13 +249,17 @@ void Emulator::Run(const std::filesystem::path& file) {
|
|||||||
window->waitEvent();
|
window->waitEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_QT_GUI
|
||||||
|
UpdatePlayTime(id);
|
||||||
|
#endif
|
||||||
|
|
||||||
std::exit(0);
|
std::exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Emulator::LoadSystemModules(const std::filesystem::path& file) {
|
void Emulator::LoadSystemModules(const std::filesystem::path& file) {
|
||||||
constexpr std::array<SysModules, 13> ModulesToLoad{
|
constexpr std::array<SysModules, 13> ModulesToLoad{
|
||||||
{{"libSceNgs2.sprx", &Libraries::Ngs2::RegisterlibSceNgs2},
|
{{"libSceNgs2.sprx", &Libraries::Ngs2::RegisterlibSceNgs2},
|
||||||
{"libSceFiber.sprx", nullptr},
|
{"libSceFiber.sprx", &Libraries::Fiber::RegisterlibSceFiber},
|
||||||
{"libSceUlt.sprx", nullptr},
|
{"libSceUlt.sprx", nullptr},
|
||||||
{"libSceJson.sprx", nullptr},
|
{"libSceJson.sprx", nullptr},
|
||||||
{"libSceJson2.sprx", nullptr},
|
{"libSceJson2.sprx", nullptr},
|
||||||
@ -258,4 +294,74 @@ void Emulator::LoadSystemModules(const std::filesystem::path& file) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_QT_GUI
|
||||||
|
void Emulator::UpdatePlayTime(const std::string& serial) {
|
||||||
|
const auto user_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
|
||||||
|
QString filePath = QString::fromStdString((user_dir / "play_time.txt").string());
|
||||||
|
|
||||||
|
QFile file(filePath);
|
||||||
|
if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) {
|
||||||
|
LOG_INFO(Loader, "Error opening play_time.txt");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto end_time = std::chrono::steady_clock::now();
|
||||||
|
auto duration = std::chrono::duration_cast<std::chrono::seconds>(end_time - start_time);
|
||||||
|
int totalSeconds = duration.count();
|
||||||
|
|
||||||
|
QTextStream in(&file);
|
||||||
|
QStringList lines;
|
||||||
|
QString content;
|
||||||
|
while (!in.atEnd()) {
|
||||||
|
content += in.readLine() + "\n";
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
QStringList existingLines = content.split('\n', Qt::SkipEmptyParts);
|
||||||
|
int accumulatedSeconds = 0;
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
for (const QString& line : existingLines) {
|
||||||
|
QStringList parts = line.split(' ');
|
||||||
|
if (parts.size() == 2 && parts[0] == QString::fromStdString(serial)) {
|
||||||
|
QStringList timeParts = parts[1].split(':');
|
||||||
|
if (timeParts.size() == 3) {
|
||||||
|
int hours = timeParts[0].toInt();
|
||||||
|
int minutes = timeParts[1].toInt();
|
||||||
|
int seconds = timeParts[2].toInt();
|
||||||
|
accumulatedSeconds = hours * 3600 + minutes * 60 + seconds;
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
accumulatedSeconds += totalSeconds;
|
||||||
|
int hours = accumulatedSeconds / 3600;
|
||||||
|
int minutes = (accumulatedSeconds % 3600) / 60;
|
||||||
|
int seconds = accumulatedSeconds % 60;
|
||||||
|
QString playTimeSaved = QString::number(hours) + ":" +
|
||||||
|
QString::number(minutes).rightJustified(2, '0') + ":" +
|
||||||
|
QString::number(seconds).rightJustified(2, '0');
|
||||||
|
|
||||||
|
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||||
|
QTextStream out(&file);
|
||||||
|
bool lineUpdated = false;
|
||||||
|
|
||||||
|
for (const QString& line : existingLines) {
|
||||||
|
if (line.startsWith(QString::fromStdString(serial))) {
|
||||||
|
out << QString::fromStdString(serial) + " " + playTimeSaved + "\n";
|
||||||
|
lineUpdated = true;
|
||||||
|
} else {
|
||||||
|
out << line << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lineUpdated) {
|
||||||
|
out << QString::fromStdString(serial) + " " + playTimeSaved + "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOG_INFO(Loader, "Playing time for {}: {}", serial, playTimeSaved.toStdString());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
@ -26,6 +26,7 @@ public:
|
|||||||
~Emulator();
|
~Emulator();
|
||||||
|
|
||||||
void Run(const std::filesystem::path& file);
|
void Run(const std::filesystem::path& file);
|
||||||
|
void UpdatePlayTime(const std::string& serial);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void LoadSystemModules(const std::filesystem::path& file);
|
void LoadSystemModules(const std::filesystem::path& file);
|
||||||
@ -34,6 +35,7 @@ private:
|
|||||||
Input::GameController* controller;
|
Input::GameController* controller;
|
||||||
Core::Linker* linker;
|
Core::Linker* linker;
|
||||||
std::unique_ptr<Frontend::WindowSDL> window;
|
std::unique_ptr<Frontend::WindowSDL> window;
|
||||||
|
std::chrono::steady_clock::time_point start_time;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
// Based on imgui_impl_sdl3.cpp from Dear ImGui repository
|
// Based on imgui_impl_sdl3.cpp from Dear ImGui repository
|
||||||
|
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
|
#include "common/config.h"
|
||||||
#include "imgui_impl_sdl3.h"
|
#include "imgui_impl_sdl3.h"
|
||||||
|
|
||||||
// SDL
|
// SDL
|
||||||
@ -36,6 +37,8 @@ struct SdlData {
|
|||||||
SDL_Cursor* mouse_cursors[ImGuiMouseCursor_COUNT]{};
|
SDL_Cursor* mouse_cursors[ImGuiMouseCursor_COUNT]{};
|
||||||
SDL_Cursor* mouse_last_cursor{};
|
SDL_Cursor* mouse_last_cursor{};
|
||||||
int mouse_pending_leave_frame{};
|
int mouse_pending_leave_frame{};
|
||||||
|
ImVec2 prev_mouse_pos{0, 0};
|
||||||
|
Uint64 lastCursorMoveTime{};
|
||||||
|
|
||||||
// Gamepad handling
|
// Gamepad handling
|
||||||
ImVector<SDL_Gamepad*> gamepads{};
|
ImVector<SDL_Gamepad*> gamepads{};
|
||||||
@ -371,6 +374,13 @@ bool ProcessEvent(const SDL_Event* event) {
|
|||||||
? ImGuiMouseSource_TouchScreen
|
? ImGuiMouseSource_TouchScreen
|
||||||
: ImGuiMouseSource_Mouse);
|
: ImGuiMouseSource_Mouse);
|
||||||
io.AddMousePosEvent(mouse_pos.x, mouse_pos.y);
|
io.AddMousePosEvent(mouse_pos.x, mouse_pos.y);
|
||||||
|
if (mouse_pos.x != bd->prev_mouse_pos.x || mouse_pos.y != bd->prev_mouse_pos.y) {
|
||||||
|
bd->prev_mouse_pos.x = mouse_pos.x;
|
||||||
|
bd->prev_mouse_pos.y = mouse_pos.y;
|
||||||
|
if (Config::getCursorState() == Config::HideCursorState::Idle) {
|
||||||
|
bd->lastCursorMoveTime = bd->time;
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case SDL_EVENT_MOUSE_WHEEL: {
|
case SDL_EVENT_MOUSE_WHEEL: {
|
||||||
@ -447,6 +457,7 @@ bool ProcessEvent(const SDL_Event* event) {
|
|||||||
return false;
|
return false;
|
||||||
bd->mouse_window_id = event->window.windowID;
|
bd->mouse_window_id = event->window.windowID;
|
||||||
bd->mouse_pending_leave_frame = 0;
|
bd->mouse_pending_leave_frame = 0;
|
||||||
|
bd->lastCursorMoveTime = bd->time;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// - In some cases, when detaching a window from main viewport SDL may send
|
// - In some cases, when detaching a window from main viewport SDL may send
|
||||||
@ -459,6 +470,7 @@ bool ProcessEvent(const SDL_Event* event) {
|
|||||||
if (GetViewportForWindowId(event->window.windowID) == NULL)
|
if (GetViewportForWindowId(event->window.windowID) == NULL)
|
||||||
return false;
|
return false;
|
||||||
bd->mouse_pending_leave_frame = ImGui::GetFrameCount() + 1;
|
bd->mouse_pending_leave_frame = ImGui::GetFrameCount() + 1;
|
||||||
|
bd->lastCursorMoveTime = bd->time;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case SDL_EVENT_WINDOW_FOCUS_GAINED:
|
case SDL_EVENT_WINDOW_FOCUS_GAINED:
|
||||||
@ -581,7 +593,7 @@ static void UpdateMouseData() {
|
|||||||
// (below)
|
// (below)
|
||||||
// SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries
|
// SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries
|
||||||
// shouldn't e.g. trigger other operations outside
|
// shouldn't e.g. trigger other operations outside
|
||||||
SDL_CaptureMouse((bd->mouse_buttons_down != 0) ? SDL_TRUE : SDL_FALSE);
|
SDL_CaptureMouse((bd->mouse_buttons_down != 0) ? true : false);
|
||||||
SDL_Window* focused_window = SDL_GetKeyboardFocus();
|
SDL_Window* focused_window = SDL_GetKeyboardFocus();
|
||||||
const bool is_app_focused = (bd->window == focused_window);
|
const bool is_app_focused = (bd->window == focused_window);
|
||||||
|
|
||||||
@ -600,7 +612,18 @@ static void UpdateMouseData() {
|
|||||||
int window_x, window_y;
|
int window_x, window_y;
|
||||||
SDL_GetGlobalMouseState(&mouse_x_global, &mouse_y_global);
|
SDL_GetGlobalMouseState(&mouse_x_global, &mouse_y_global);
|
||||||
SDL_GetWindowPosition(focused_window, &window_x, &window_y);
|
SDL_GetWindowPosition(focused_window, &window_x, &window_y);
|
||||||
io.AddMousePosEvent(mouse_x_global - (float)window_x, mouse_y_global - (float)window_y);
|
mouse_x_global -= (float)window_x;
|
||||||
|
mouse_y_global -= (float)window_y;
|
||||||
|
io.AddMousePosEvent(mouse_x_global, mouse_y_global);
|
||||||
|
// SDL_EVENT_MOUSE_MOTION isn't triggered before the first frame is rendered
|
||||||
|
// force update the prev_cursor coords
|
||||||
|
if (mouse_x_global != bd->prev_mouse_pos.x || mouse_y_global != bd->prev_mouse_pos.y &&
|
||||||
|
bd->prev_mouse_pos.y == 0 &&
|
||||||
|
bd->prev_mouse_pos.x == 0) {
|
||||||
|
bd->prev_mouse_pos.x = mouse_x_global;
|
||||||
|
bd->prev_mouse_pos.y = mouse_y_global;
|
||||||
|
bd->lastCursorMoveTime = bd->time;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -611,10 +634,25 @@ static void UpdateMouseCursor() {
|
|||||||
return;
|
return;
|
||||||
SdlData* bd = GetBackendData();
|
SdlData* bd = GetBackendData();
|
||||||
|
|
||||||
|
s16 cursorState = Config::getCursorState();
|
||||||
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
|
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
|
||||||
if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None) {
|
if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None ||
|
||||||
|
cursorState == Config::HideCursorState::Always) {
|
||||||
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
|
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
|
||||||
SDL_HideCursor();
|
SDL_HideCursor();
|
||||||
|
|
||||||
|
} else if (cursorState == Config::HideCursorState::Idle &&
|
||||||
|
bd->time - bd->lastCursorMoveTime >=
|
||||||
|
Config::getCursorHideTimeout() * SDL_GetPerformanceFrequency()) {
|
||||||
|
|
||||||
|
bool wasCursorVisible = SDL_CursorVisible();
|
||||||
|
SDL_HideCursor();
|
||||||
|
|
||||||
|
if (wasCursorVisible) {
|
||||||
|
SDL_WarpMouseInWindow(SDL_GetKeyboardFocus(), bd->prev_mouse_pos.x,
|
||||||
|
bd->prev_mouse_pos.y); // Force refresh the cursor state
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Show OS mouse cursor
|
// Show OS mouse cursor
|
||||||
SDL_Cursor* expected_cursor = bd->mouse_cursors[imgui_cursor]
|
SDL_Cursor* expected_cursor = bd->mouse_cursors[imgui_cursor]
|
||||||
|
@ -374,11 +374,17 @@ void CheckUpdate::Install() {
|
|||||||
QString userPath;
|
QString userPath;
|
||||||
Common::FS::PathToQString(userPath, Common::FS::GetUserPath(Common::FS::PathType::UserDir));
|
Common::FS::PathToQString(userPath, Common::FS::GetUserPath(Common::FS::PathType::UserDir));
|
||||||
|
|
||||||
QString startingUpdate = tr("Starting Update...");
|
|
||||||
QString tempDirPath = userPath + "/temp_download_update";
|
|
||||||
QString rootPath;
|
QString rootPath;
|
||||||
Common::FS::PathToQString(rootPath, std::filesystem::current_path());
|
Common::FS::PathToQString(rootPath, std::filesystem::current_path());
|
||||||
|
|
||||||
|
QString tempDirPath = userPath + "/temp_download_update";
|
||||||
|
QString startingUpdate = tr("Starting Update...");
|
||||||
|
|
||||||
|
QString binaryStartingUpdate;
|
||||||
|
for (QChar c : startingUpdate) {
|
||||||
|
binaryStartingUpdate.append(QString::number(c.unicode(), 2).rightJustified(16, '0'));
|
||||||
|
}
|
||||||
|
|
||||||
QString scriptContent;
|
QString scriptContent;
|
||||||
QString scriptFileName;
|
QString scriptFileName;
|
||||||
QStringList arguments;
|
QStringList arguments;
|
||||||
@ -389,7 +395,13 @@ void CheckUpdate::Install() {
|
|||||||
scriptFileName = tempDirPath + "/update.ps1";
|
scriptFileName = tempDirPath + "/update.ps1";
|
||||||
scriptContent = QStringLiteral(
|
scriptContent = QStringLiteral(
|
||||||
"Set-ExecutionPolicy Bypass -Scope Process -Force\n"
|
"Set-ExecutionPolicy Bypass -Scope Process -Force\n"
|
||||||
"Write-Output '%1'\n"
|
"$binaryStartingUpdate = '%1'\n"
|
||||||
|
"$chars = @()\n"
|
||||||
|
"for ($i = 0; $i -lt $binaryStartingUpdate.Length; $i += 16) {\n"
|
||||||
|
" $chars += [char]([convert]::ToInt32($binaryStartingUpdate.Substring($i, 16), 2))\n"
|
||||||
|
"}\n"
|
||||||
|
"$startingUpdate = -join $chars\n"
|
||||||
|
"Write-Output $startingUpdate\n"
|
||||||
"Expand-Archive -Path '%2\\temp_download_update.zip' -DestinationPath '%2' -Force\n"
|
"Expand-Archive -Path '%2\\temp_download_update.zip' -DestinationPath '%2' -Force\n"
|
||||||
"Start-Sleep -Seconds 3\n"
|
"Start-Sleep -Seconds 3\n"
|
||||||
"Copy-Item -Recurse -Force '%2\\*' '%3\\'\n"
|
"Copy-Item -Recurse -Force '%2\\*' '%3\\'\n"
|
||||||
@ -454,6 +466,10 @@ void CheckUpdate::Install() {
|
|||||||
" sleep 2\n"
|
" sleep 2\n"
|
||||||
" extract_file\n"
|
" extract_file\n"
|
||||||
" sleep 2\n"
|
" sleep 2\n"
|
||||||
|
" if pgrep -f \"Shadps4-qt.AppImage\" > /dev/null; then\n"
|
||||||
|
" pkill -f \"Shadps4-qt.AppImage\"\n"
|
||||||
|
" sleep 2\n"
|
||||||
|
" fi\n"
|
||||||
" cp -r \"%2/\"* \"%3/\"\n"
|
" cp -r \"%2/\"* \"%3/\"\n"
|
||||||
" sleep 2\n"
|
" sleep 2\n"
|
||||||
" rm \"%3/update.sh\"\n"
|
" rm \"%3/update.sh\"\n"
|
||||||
@ -508,7 +524,12 @@ void CheckUpdate::Install() {
|
|||||||
QFile scriptFile(scriptFileName);
|
QFile scriptFile(scriptFileName);
|
||||||
if (scriptFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
if (scriptFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||||
QTextStream out(&scriptFile);
|
QTextStream out(&scriptFile);
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
out << scriptContent.arg(binaryStartingUpdate).arg(tempDirPath).arg(rootPath);
|
||||||
|
#endif
|
||||||
|
#if defined(Q_OS_LINUX) || defined(Q_OS_MAC)
|
||||||
out << scriptContent.arg(startingUpdate).arg(tempDirPath).arg(rootPath);
|
out << scriptContent.arg(startingUpdate).arg(tempDirPath).arg(rootPath);
|
||||||
|
#endif
|
||||||
scriptFile.close();
|
scriptFile.close();
|
||||||
|
|
||||||
// Make the script executable on Unix-like systems
|
// Make the script executable on Unix-like systems
|
||||||
|
@ -10,9 +10,10 @@ GameInfoClass::GameInfoClass() = default;
|
|||||||
GameInfoClass::~GameInfoClass() = default;
|
GameInfoClass::~GameInfoClass() = default;
|
||||||
|
|
||||||
void GameInfoClass::GetGameInfo(QWidget* parent) {
|
void GameInfoClass::GetGameInfo(QWidget* parent) {
|
||||||
QString installDir;
|
|
||||||
Common::FS::PathToQString(installDir, Config::getGameInstallDir());
|
|
||||||
QStringList filePaths;
|
QStringList filePaths;
|
||||||
|
for (const auto& installLoc : Config::getGameInstallDirs()) {
|
||||||
|
QString installDir;
|
||||||
|
Common::FS::PathToQString(installDir, installLoc);
|
||||||
QDir parentFolder(installDir);
|
QDir parentFolder(installDir);
|
||||||
QFileInfoList fileList = parentFolder.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
|
QFileInfoList fileList = parentFolder.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||||
for (const auto& fileInfo : fileList) {
|
for (const auto& fileInfo : fileList) {
|
||||||
@ -20,6 +21,7 @@ void GameInfoClass::GetGameInfo(QWidget* parent) {
|
|||||||
filePaths.append(fileInfo.absoluteFilePath());
|
filePaths.append(fileInfo.absoluteFilePath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
m_games = QtConcurrent::mapped(filePaths, [&](const QString& path) {
|
m_games = QtConcurrent::mapped(filePaths, [&](const QString& path) {
|
||||||
return readGameInfo(Common::FS::PathFromQString(path));
|
return readGameInfo(Common::FS::PathFromQString(path));
|
||||||
}).results();
|
}).results();
|
||||||
|
@ -60,6 +60,9 @@ public:
|
|||||||
if (auto app_ver = psf.GetString("APP_VER"); app_ver.has_value()) {
|
if (auto app_ver = psf.GetString("APP_VER"); app_ver.has_value()) {
|
||||||
game.version = *app_ver;
|
game.version = *app_ver;
|
||||||
}
|
}
|
||||||
|
if (const auto play_time = psf.GetString("PLAY_TIME"); play_time.has_value()) {
|
||||||
|
game.play_time = *play_time;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return game;
|
return game;
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,9 @@ QWidget* GameInstallDialog::SetupGamesDirectory() {
|
|||||||
// Input.
|
// Input.
|
||||||
m_gamesDirectory = new QLineEdit();
|
m_gamesDirectory = new QLineEdit();
|
||||||
QString install_dir;
|
QString install_dir;
|
||||||
Common::FS::PathToQString(install_dir, Config::getGameInstallDir());
|
std::filesystem::path install_path =
|
||||||
|
Config::getGameInstallDirs().empty() ? "" : Config::getGameInstallDirs().front();
|
||||||
|
Common::FS::PathToQString(install_dir, install_path);
|
||||||
m_gamesDirectory->setText(install_dir);
|
m_gamesDirectory->setText(install_dir);
|
||||||
m_gamesDirectory->setMinimumWidth(400);
|
m_gamesDirectory->setMinimumWidth(400);
|
||||||
|
|
||||||
@ -125,7 +127,9 @@ void GameInstallDialog::Save() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Config::setGameInstallDir(Common::FS::PathFromQString(gamesDirectory));
|
std::vector<std::filesystem::path> install_dirs;
|
||||||
|
install_dirs.emplace_back(Common::FS::PathFromQString(gamesDirectory));
|
||||||
|
Config::setGameInstallDirs(install_dirs);
|
||||||
Config::setAddonInstallDir(Common::FS::PathFromQString(addonsDirectory));
|
Config::setAddonInstallDir(Common::FS::PathFromQString(addonsDirectory));
|
||||||
const auto config_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
|
const auto config_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
|
||||||
Config::save(config_dir / "config.toml");
|
Config::save(config_dir / "config.toml");
|
||||||
|
@ -24,16 +24,17 @@ GameListFrame::GameListFrame(std::shared_ptr<GameInfoClass> game_info_get, QWidg
|
|||||||
this->horizontalHeader()->setSortIndicatorShown(true);
|
this->horizontalHeader()->setSortIndicatorShown(true);
|
||||||
this->horizontalHeader()->setStretchLastSection(true);
|
this->horizontalHeader()->setStretchLastSection(true);
|
||||||
this->setContextMenuPolicy(Qt::CustomContextMenu);
|
this->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
this->setColumnCount(8);
|
this->setColumnCount(9);
|
||||||
this->setColumnWidth(1, 300); // Name
|
this->setColumnWidth(1, 300); // Name
|
||||||
this->setColumnWidth(2, 120); // Serial
|
this->setColumnWidth(2, 120); // Serial
|
||||||
this->setColumnWidth(3, 90); // Region
|
this->setColumnWidth(3, 90); // Region
|
||||||
this->setColumnWidth(4, 90); // Firmware
|
this->setColumnWidth(4, 90); // Firmware
|
||||||
this->setColumnWidth(5, 90); // Size
|
this->setColumnWidth(5, 90); // Size
|
||||||
this->setColumnWidth(6, 90); // Version
|
this->setColumnWidth(6, 90); // Version
|
||||||
|
this->setColumnWidth(7, 100); // Play Time
|
||||||
QStringList headers;
|
QStringList headers;
|
||||||
headers << tr("Icon") << tr("Name") << tr("Serial") << tr("Region") << tr("Firmware")
|
headers << tr("Icon") << tr("Name") << tr("Serial") << tr("Region") << tr("Firmware")
|
||||||
<< tr("Size") << tr("Version") << tr("Path");
|
<< tr("Size") << tr("Version") << tr("Play Time") << tr("Path");
|
||||||
this->setHorizontalHeaderLabels(headers);
|
this->setHorizontalHeaderLabels(headers);
|
||||||
this->horizontalHeader()->setSortIndicatorShown(true);
|
this->horizontalHeader()->setSortIndicatorShown(true);
|
||||||
this->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
|
this->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
|
||||||
@ -100,9 +101,37 @@ void GameListFrame::PopulateGameList() {
|
|||||||
SetTableItem(i, 4, QString::fromStdString(m_game_info->m_games[i].fw));
|
SetTableItem(i, 4, QString::fromStdString(m_game_info->m_games[i].fw));
|
||||||
SetTableItem(i, 5, QString::fromStdString(m_game_info->m_games[i].size));
|
SetTableItem(i, 5, QString::fromStdString(m_game_info->m_games[i].size));
|
||||||
SetTableItem(i, 6, QString::fromStdString(m_game_info->m_games[i].version));
|
SetTableItem(i, 6, QString::fromStdString(m_game_info->m_games[i].version));
|
||||||
|
|
||||||
|
QString playTime = GetPlayTime(m_game_info->m_games[i].serial);
|
||||||
|
if (playTime.isEmpty()) {
|
||||||
|
m_game_info->m_games[i].play_time = "0:00:00";
|
||||||
|
SetTableItem(i, 7, "0");
|
||||||
|
} else {
|
||||||
|
QStringList timeParts = playTime.split(':');
|
||||||
|
int hours = timeParts[0].toInt();
|
||||||
|
int minutes = timeParts[1].toInt();
|
||||||
|
int seconds = timeParts[2].toInt();
|
||||||
|
|
||||||
|
QString formattedPlayTime;
|
||||||
|
if (hours > 0) {
|
||||||
|
formattedPlayTime += QString("%1h ").arg(hours);
|
||||||
|
}
|
||||||
|
if (minutes > 0) {
|
||||||
|
formattedPlayTime += QString("%1m ").arg(minutes);
|
||||||
|
}
|
||||||
|
|
||||||
|
formattedPlayTime = formattedPlayTime.trimmed();
|
||||||
|
m_game_info->m_games[i].play_time = playTime.toStdString();
|
||||||
|
if (formattedPlayTime.isEmpty()) {
|
||||||
|
SetTableItem(i, 7, "0");
|
||||||
|
} else {
|
||||||
|
SetTableItem(i, 7, formattedPlayTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QString path;
|
QString path;
|
||||||
Common::FS::PathToQString(path, m_game_info->m_games[i].path);
|
Common::FS::PathToQString(path, m_game_info->m_games[i].path);
|
||||||
SetTableItem(i, 7, path);
|
SetTableItem(i, 8, path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,7 +200,7 @@ void GameListFrame::ResizeIcons(int iconSize) {
|
|||||||
this->setItem(index, 0, iconItem);
|
this->setItem(index, 0, iconItem);
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
this->horizontalHeader()->setSectionResizeMode(7, QHeaderView::ResizeToContents);
|
this->horizontalHeader()->setSectionResizeMode(8, QHeaderView::ResizeToContents);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameListFrame::SetTableItem(int row, int column, QString itemStr) {
|
void GameListFrame::SetTableItem(int row, int column, QString itemStr) {
|
||||||
@ -224,3 +253,33 @@ void GameListFrame::SetRegionFlag(int row, int column, QString itemStr) {
|
|||||||
this->setItem(row, column, item);
|
this->setItem(row, column, item);
|
||||||
this->setCellWidget(row, column, widget);
|
this->setCellWidget(row, column, widget);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString GameListFrame::GetPlayTime(const std::string& serial) {
|
||||||
|
QString playTime;
|
||||||
|
const auto user_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
|
||||||
|
QString filePath = QString::fromStdString((user_dir / "play_time.txt").string());
|
||||||
|
|
||||||
|
QFile file(filePath);
|
||||||
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
|
return playTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!file.atEnd()) {
|
||||||
|
QByteArray line = file.readLine();
|
||||||
|
QString lineStr = QString::fromUtf8(line).trimmed();
|
||||||
|
|
||||||
|
QStringList parts = lineStr.split(' ');
|
||||||
|
if (parts.size() >= 2) {
|
||||||
|
QString fileSerial = parts[0];
|
||||||
|
QString time = parts[1];
|
||||||
|
|
||||||
|
if (fileSerial == QString::fromStdString(serial)) {
|
||||||
|
playTime = time;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
return playTime;
|
||||||
|
}
|
||||||
|
@ -29,6 +29,7 @@ public Q_SLOTS:
|
|||||||
private:
|
private:
|
||||||
void SetTableItem(int row, int column, QString itemStr);
|
void SetTableItem(int row, int column, QString itemStr);
|
||||||
void SetRegionFlag(int row, int column, QString itemStr);
|
void SetRegionFlag(int row, int column, QString itemStr);
|
||||||
|
QString GetPlayTime(const std::string& serial);
|
||||||
QList<QAction*> m_columnActs;
|
QList<QAction*> m_columnActs;
|
||||||
GameInfoClass* game_inf_get = nullptr;
|
GameInfoClass* game_inf_get = nullptr;
|
||||||
bool ListSortedAsc = true;
|
bool ListSortedAsc = true;
|
||||||
@ -68,6 +69,8 @@ public:
|
|||||||
case 6:
|
case 6:
|
||||||
return a.version < b.version;
|
return a.version < b.version;
|
||||||
case 7:
|
case 7:
|
||||||
|
return a.play_time < b.play_time;
|
||||||
|
case 8:
|
||||||
return a.path < b.path;
|
return a.path < b.path;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
@ -89,6 +92,8 @@ public:
|
|||||||
case 6:
|
case 6:
|
||||||
return a.version > b.version;
|
return a.version > b.version;
|
||||||
case 7:
|
case 7:
|
||||||
|
return a.play_time > b.play_time;
|
||||||
|
case 8:
|
||||||
return a.path > b.path;
|
return a.path > b.path;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
@ -19,6 +19,8 @@ struct GameInfo {
|
|||||||
std::string version = "Unknown";
|
std::string version = "Unknown";
|
||||||
std::string region = "Unknown";
|
std::string region = "Unknown";
|
||||||
std::string fw = "Unknown";
|
std::string fw = "Unknown";
|
||||||
|
|
||||||
|
std::string play_time = "Unknown";
|
||||||
};
|
};
|
||||||
|
|
||||||
class GameListUtils {
|
class GameListUtils {
|
||||||
|
76
src/qt_gui/install_dir_select.cpp
Normal file
76
src/qt_gui/install_dir_select.cpp
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <QDialogButtonBox>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QGroupBox>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QListWidget>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
#include "install_dir_select.h"
|
||||||
|
|
||||||
|
InstallDirSelect::InstallDirSelect() : selected_dir() {
|
||||||
|
selected_dir = Config::getGameInstallDirs().empty() ? "" : Config::getGameInstallDirs().front();
|
||||||
|
|
||||||
|
if (!Config::getGameInstallDirs().empty() && Config::getGameInstallDirs().size() == 1) {
|
||||||
|
reject();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto layout = new QVBoxLayout(this);
|
||||||
|
|
||||||
|
layout->addWidget(SetupInstallDirList());
|
||||||
|
layout->addStretch();
|
||||||
|
layout->addWidget(SetupDialogActions());
|
||||||
|
|
||||||
|
setWindowTitle(tr("shadPS4 - Choose directory"));
|
||||||
|
setWindowIcon(QIcon(":images/shadps4.ico"));
|
||||||
|
}
|
||||||
|
|
||||||
|
InstallDirSelect::~InstallDirSelect() {}
|
||||||
|
|
||||||
|
QWidget* InstallDirSelect::SetupInstallDirList() {
|
||||||
|
auto group = new QGroupBox(tr("Select which directory you want to install to."));
|
||||||
|
auto vlayout = new QVBoxLayout();
|
||||||
|
|
||||||
|
auto m_path_list = new QListWidget();
|
||||||
|
QList<QString> qt_list;
|
||||||
|
for (const auto& str : Config::getGameInstallDirs()) {
|
||||||
|
QString installDirPath;
|
||||||
|
Common::FS::PathToQString(installDirPath, str);
|
||||||
|
qt_list.append(installDirPath);
|
||||||
|
}
|
||||||
|
m_path_list->insertItems(0, qt_list);
|
||||||
|
m_path_list->setSpacing(1);
|
||||||
|
|
||||||
|
connect(m_path_list, &QListWidget::itemClicked, this, &InstallDirSelect::setSelectedDirectory);
|
||||||
|
connect(m_path_list, &QListWidget::itemActivated, this,
|
||||||
|
&InstallDirSelect::setSelectedDirectory);
|
||||||
|
|
||||||
|
vlayout->addWidget(m_path_list);
|
||||||
|
|
||||||
|
group->setLayout(vlayout);
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InstallDirSelect::setSelectedDirectory(QListWidgetItem* item) {
|
||||||
|
if (item) {
|
||||||
|
const auto highlighted_path = Common::FS::PathFromQString(item->text());
|
||||||
|
if (!highlighted_path.empty()) {
|
||||||
|
selected_dir = highlighted_path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget* InstallDirSelect::SetupDialogActions() {
|
||||||
|
auto actions = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||||
|
|
||||||
|
connect(actions, &QDialogButtonBox::accepted, this, &InstallDirSelect::accept);
|
||||||
|
connect(actions, &QDialogButtonBox::rejected, this, &InstallDirSelect::reject);
|
||||||
|
|
||||||
|
return actions;
|
||||||
|
}
|
31
src/qt_gui/install_dir_select.h
Normal file
31
src/qt_gui/install_dir_select.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QListWidget>
|
||||||
|
|
||||||
|
#include "common/config.h"
|
||||||
|
#include "common/path_util.h"
|
||||||
|
|
||||||
|
class QLineEdit;
|
||||||
|
|
||||||
|
class InstallDirSelect final : public QDialog {
|
||||||
|
public:
|
||||||
|
InstallDirSelect();
|
||||||
|
~InstallDirSelect();
|
||||||
|
|
||||||
|
std::filesystem::path getSelectedDirectory() {
|
||||||
|
return selected_dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void BrowseGamesDirectory();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QWidget* SetupInstallDirList();
|
||||||
|
QWidget* SetupDialogActions();
|
||||||
|
void setSelectedDirectory(QListWidgetItem* item);
|
||||||
|
std::filesystem::path selected_dir;
|
||||||
|
};
|
@ -30,7 +30,7 @@ int main(int argc, char* argv[]) {
|
|||||||
bool has_command_line_argument = argc > 1;
|
bool has_command_line_argument = argc > 1;
|
||||||
|
|
||||||
// Check if the game install directory is set
|
// Check if the game install directory is set
|
||||||
if (Config::getGameInstallDir().empty() && !has_command_line_argument) {
|
if (Config::getGameInstallDirs().empty() && !has_command_line_argument) {
|
||||||
GameInstallDialog dlg;
|
GameInstallDialog dlg;
|
||||||
dlg.exec();
|
dlg.exec();
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "core/file_format/pkg.h"
|
#include "core/file_format/pkg.h"
|
||||||
#include "core/loader.h"
|
#include "core/loader.h"
|
||||||
#include "game_install_dialog.h"
|
#include "game_install_dialog.h"
|
||||||
|
#include "install_dir_select.h"
|
||||||
#include "main_window.h"
|
#include "main_window.h"
|
||||||
#include "settings_dialog.h"
|
#include "settings_dialog.h"
|
||||||
#include "video_core/renderer_vulkan/vk_instance.h"
|
#include "video_core/renderer_vulkan/vk_instance.h"
|
||||||
@ -58,6 +59,7 @@ bool MainWindow::Init() {
|
|||||||
this->show();
|
this->show();
|
||||||
// load game list
|
// load game list
|
||||||
LoadGameLists();
|
LoadGameLists();
|
||||||
|
// Check for update
|
||||||
CheckUpdateMain(true);
|
CheckUpdateMain(true);
|
||||||
|
|
||||||
auto end = std::chrono::steady_clock::now();
|
auto end = std::chrono::steady_clock::now();
|
||||||
@ -69,6 +71,14 @@ bool MainWindow::Init() {
|
|||||||
QString statusMessage =
|
QString statusMessage =
|
||||||
"Games: " + QString::number(numGames) + " (" + QString::number(duration.count()) + "ms)";
|
"Games: " + QString::number(numGames) + " (" + QString::number(duration.count()) + "ms)";
|
||||||
statusBar->showMessage(statusMessage);
|
statusBar->showMessage(statusMessage);
|
||||||
|
|
||||||
|
// Initialize Discord RPC
|
||||||
|
if (Config::getEnableDiscordRPC()) {
|
||||||
|
auto* rpc = Common::Singleton<DiscordRPCHandler::RPC>::Instance();
|
||||||
|
rpc->init();
|
||||||
|
rpc->setStatusIdling();
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -663,7 +673,10 @@ void MainWindow::InstallDragDropPkg(std::filesystem::path file, int pkgNum, int
|
|||||||
QMessageBox::critical(this, tr("PKG ERROR"), QString::fromStdString(failreason));
|
QMessageBox::critical(this, tr("PKG ERROR"), QString::fromStdString(failreason));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto extract_path = Config::getGameInstallDir() / pkg.GetTitleID();
|
InstallDirSelect ids;
|
||||||
|
ids.exec();
|
||||||
|
auto game_install_dir = ids.getSelectedDirectory();
|
||||||
|
auto extract_path = game_install_dir / pkg.GetTitleID();
|
||||||
QString pkgType = QString::fromStdString(pkg.GetPkgFlags());
|
QString pkgType = QString::fromStdString(pkg.GetPkgFlags());
|
||||||
QString gameDirPath;
|
QString gameDirPath;
|
||||||
Common::FS::PathToQString(gameDirPath, extract_path);
|
Common::FS::PathToQString(gameDirPath, extract_path);
|
||||||
@ -812,7 +825,7 @@ void MainWindow::InstallDragDropPkg(std::filesystem::path file, int pkgNum, int
|
|||||||
connect(&futureWatcher, &QFutureWatcher<void>::finished, this, [=, this]() {
|
connect(&futureWatcher, &QFutureWatcher<void>::finished, this, [=, this]() {
|
||||||
if (pkgNum == nPkg) {
|
if (pkgNum == nPkg) {
|
||||||
QString path;
|
QString path;
|
||||||
Common::FS::PathToQString(path, Config::getGameInstallDir());
|
Common::FS::PathToQString(path, game_install_dir);
|
||||||
QMessageBox extractMsgBox(this);
|
QMessageBox extractMsgBox(this);
|
||||||
extractMsgBox.setWindowTitle(tr("Extraction Finished"));
|
extractMsgBox.setWindowTitle(tr("Extraction Finished"));
|
||||||
extractMsgBox.setText(
|
extractMsgBox.setText(
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "background_music_player.h"
|
#include "background_music_player.h"
|
||||||
#include "common/config.h"
|
#include "common/config.h"
|
||||||
|
#include "common/discord_rpc_handler.h"
|
||||||
#include "common/path_util.h"
|
#include "common/path_util.h"
|
||||||
#include "core/file_format/psf.h"
|
#include "core/file_format/psf.h"
|
||||||
#include "core/file_sys/fs.h"
|
#include "core/file_sys/fs.h"
|
||||||
|
@ -67,6 +67,15 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices, QWidge
|
|||||||
completer->setCaseSensitivity(Qt::CaseInsensitive);
|
completer->setCaseSensitivity(Qt::CaseInsensitive);
|
||||||
ui->consoleLanguageComboBox->setCompleter(completer);
|
ui->consoleLanguageComboBox->setCompleter(completer);
|
||||||
|
|
||||||
|
ui->hideCursorComboBox->addItem(tr("Never"));
|
||||||
|
ui->hideCursorComboBox->addItem(tr("Idle"));
|
||||||
|
ui->hideCursorComboBox->addItem(tr("Always"));
|
||||||
|
|
||||||
|
ui->backButtonBehaviorComboBox->addItem(tr("Touchpad Left"), "left");
|
||||||
|
ui->backButtonBehaviorComboBox->addItem(tr("Touchpad Center"), "center");
|
||||||
|
ui->backButtonBehaviorComboBox->addItem(tr("Touchpad Right"), "right");
|
||||||
|
ui->backButtonBehaviorComboBox->addItem(tr("None"), "none");
|
||||||
|
|
||||||
InitializeEmulatorLanguages();
|
InitializeEmulatorLanguages();
|
||||||
LoadValuesFromConfig();
|
LoadValuesFromConfig();
|
||||||
|
|
||||||
@ -151,6 +160,37 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices, QWidge
|
|||||||
Config::setBGMvolume(val);
|
Config::setBGMvolume(val);
|
||||||
BackgroundMusicPlayer::getInstance().setVolume(val);
|
BackgroundMusicPlayer::getInstance().setVolume(val);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
connect(ui->discordRPCCheckbox, &QCheckBox::stateChanged, this, [](int val) {
|
||||||
|
Config::setEnableDiscordRPC(val);
|
||||||
|
auto* rpc = Common::Singleton<DiscordRPCHandler::RPC>::Instance();
|
||||||
|
if (val == Qt::Checked) {
|
||||||
|
rpc->init();
|
||||||
|
rpc->setStatusIdling();
|
||||||
|
} else {
|
||||||
|
rpc->shutdown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Input TAB
|
||||||
|
{
|
||||||
|
connect(ui->hideCursorComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||||
|
[this](s16 index) {
|
||||||
|
Config::setCursorState(index);
|
||||||
|
OnCursorStateChanged(index);
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(ui->idleTimeoutSpinBox, &QSpinBox::valueChanged, this,
|
||||||
|
[](int index) { Config::setCursorHideTimeout(index); });
|
||||||
|
|
||||||
|
connect(ui->backButtonBehaviorComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||||
|
this, [this](int index) {
|
||||||
|
if (index >= 0 && index < ui->backButtonBehaviorComboBox->count()) {
|
||||||
|
QString data = ui->backButtonBehaviorComboBox->itemData(index).toString();
|
||||||
|
Config::setBackButtonBehavior(data.toStdString());
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// GPU TAB
|
// GPU TAB
|
||||||
@ -176,6 +216,51 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices, QWidge
|
|||||||
[](int val) { Config::setNullGpu(val); });
|
[](int val) { Config::setNullGpu(val); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PATH TAB
|
||||||
|
{
|
||||||
|
ui->removeFolderButton->setEnabled(false);
|
||||||
|
|
||||||
|
connect(ui->addFolderButton, &QPushButton::clicked, this, [this]() {
|
||||||
|
const auto config_dir = Config::getGameInstallDirs();
|
||||||
|
QString file_path_string =
|
||||||
|
QFileDialog::getExistingDirectory(this, tr("Directory to install games"));
|
||||||
|
auto file_path = Common::FS::PathFromQString(file_path_string);
|
||||||
|
bool not_already_included =
|
||||||
|
std::find(config_dir.begin(), config_dir.end(), file_path) == config_dir.end();
|
||||||
|
if (!file_path.empty() && not_already_included) {
|
||||||
|
std::vector<std::filesystem::path> install_dirs = config_dir;
|
||||||
|
install_dirs.push_back(file_path);
|
||||||
|
Config::setGameInstallDirs(install_dirs);
|
||||||
|
QListWidgetItem* item = new QListWidgetItem(file_path_string);
|
||||||
|
ui->gameFoldersListWidget->addItem(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(ui->gameFoldersListWidget, &QListWidget::itemSelectionChanged, this, [this]() {
|
||||||
|
ui->removeFolderButton->setEnabled(
|
||||||
|
!ui->gameFoldersListWidget->selectedItems().isEmpty());
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(ui->removeFolderButton, &QPushButton::clicked, this, [this]() {
|
||||||
|
QListWidgetItem* selected_item = ui->gameFoldersListWidget->currentItem();
|
||||||
|
QString item_path_string = selected_item ? selected_item->text() : QString();
|
||||||
|
if (!item_path_string.isEmpty()) {
|
||||||
|
auto file_path = Common::FS::PathFromQString(item_path_string);
|
||||||
|
std::vector<std::filesystem::path> install_dirs = Config::getGameInstallDirs();
|
||||||
|
|
||||||
|
auto iterator = std::remove_if(
|
||||||
|
install_dirs.begin(), install_dirs.end(),
|
||||||
|
[&file_path](const std::filesystem::path& dir) { return file_path == dir; });
|
||||||
|
|
||||||
|
if (iterator != install_dirs.end()) {
|
||||||
|
install_dirs.erase(iterator, install_dirs.end());
|
||||||
|
delete selected_item;
|
||||||
|
}
|
||||||
|
Config::setGameInstallDirs(install_dirs);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// DEBUG TAB
|
// DEBUG TAB
|
||||||
{
|
{
|
||||||
connect(ui->debugDump, &QCheckBox::stateChanged, this,
|
connect(ui->debugDump, &QCheckBox::stateChanged, this,
|
||||||
@ -205,6 +290,12 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices, QWidge
|
|||||||
ui->updaterGroupBox->installEventFilter(this);
|
ui->updaterGroupBox->installEventFilter(this);
|
||||||
ui->GUIgroupBox->installEventFilter(this);
|
ui->GUIgroupBox->installEventFilter(this);
|
||||||
|
|
||||||
|
// Input
|
||||||
|
ui->cursorGroupBox->installEventFilter(this);
|
||||||
|
ui->hideCursorGroupBox->installEventFilter(this);
|
||||||
|
ui->idleTimeoutGroupBox->installEventFilter(this);
|
||||||
|
ui->backButtonBehaviorGroupBox->installEventFilter(this);
|
||||||
|
|
||||||
// Graphics
|
// Graphics
|
||||||
ui->graphicsAdapterGroupBox->installEventFilter(this);
|
ui->graphicsAdapterGroupBox->installEventFilter(this);
|
||||||
ui->widthGroupBox->installEventFilter(this);
|
ui->widthGroupBox->installEventFilter(this);
|
||||||
@ -213,6 +304,12 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices, QWidge
|
|||||||
ui->dumpShadersCheckBox->installEventFilter(this);
|
ui->dumpShadersCheckBox->installEventFilter(this);
|
||||||
ui->nullGpuCheckBox->installEventFilter(this);
|
ui->nullGpuCheckBox->installEventFilter(this);
|
||||||
|
|
||||||
|
// Paths
|
||||||
|
ui->gameFoldersGroupBox->installEventFilter(this);
|
||||||
|
ui->gameFoldersListWidget->installEventFilter(this);
|
||||||
|
ui->addFolderButton->installEventFilter(this);
|
||||||
|
ui->removeFolderButton->installEventFilter(this);
|
||||||
|
|
||||||
// Debug
|
// Debug
|
||||||
ui->debugDump->installEventFilter(this);
|
ui->debugDump->installEventFilter(this);
|
||||||
ui->vkValidationCheckBox->installEventFilter(this);
|
ui->vkValidationCheckBox->installEventFilter(this);
|
||||||
@ -228,6 +325,9 @@ void SettingsDialog::LoadValuesFromConfig() {
|
|||||||
std::find(languageIndexes.begin(), languageIndexes.end(), Config::GetLanguage())) %
|
std::find(languageIndexes.begin(), languageIndexes.end(), Config::GetLanguage())) %
|
||||||
languageIndexes.size());
|
languageIndexes.size());
|
||||||
ui->emulatorLanguageComboBox->setCurrentIndex(languages[Config::getEmulatorLanguage()]);
|
ui->emulatorLanguageComboBox->setCurrentIndex(languages[Config::getEmulatorLanguage()]);
|
||||||
|
ui->hideCursorComboBox->setCurrentIndex(Config::getCursorState());
|
||||||
|
OnCursorStateChanged(Config::getCursorState());
|
||||||
|
ui->idleTimeoutSpinBox->setValue(Config::getCursorHideTimeout());
|
||||||
ui->graphicsAdapterBox->setCurrentIndex(Config::getGpuId() + 1);
|
ui->graphicsAdapterBox->setCurrentIndex(Config::getGpuId() + 1);
|
||||||
ui->widthSpinBox->setValue(Config::getScreenWidth());
|
ui->widthSpinBox->setValue(Config::getScreenWidth());
|
||||||
ui->heightSpinBox->setValue(Config::getScreenHeight());
|
ui->heightSpinBox->setValue(Config::getScreenHeight());
|
||||||
@ -236,6 +336,7 @@ void SettingsDialog::LoadValuesFromConfig() {
|
|||||||
ui->nullGpuCheckBox->setChecked(Config::nullGpu());
|
ui->nullGpuCheckBox->setChecked(Config::nullGpu());
|
||||||
ui->playBGMCheckBox->setChecked(Config::getPlayBGM());
|
ui->playBGMCheckBox->setChecked(Config::getPlayBGM());
|
||||||
ui->BGMVolumeSlider->setValue((Config::getBGMvolume()));
|
ui->BGMVolumeSlider->setValue((Config::getBGMvolume()));
|
||||||
|
ui->discordRPCCheckbox->setChecked(Config::getEnableDiscordRPC());
|
||||||
ui->fullscreenCheckBox->setChecked(Config::isFullscreenMode());
|
ui->fullscreenCheckBox->setChecked(Config::isFullscreenMode());
|
||||||
ui->showSplashCheckBox->setChecked(Config::showSplash());
|
ui->showSplashCheckBox->setChecked(Config::showSplash());
|
||||||
ui->ps4proCheckBox->setChecked(Config::isNeoMode());
|
ui->ps4proCheckBox->setChecked(Config::isNeoMode());
|
||||||
@ -258,6 +359,17 @@ void SettingsDialog::LoadValuesFromConfig() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ui->updateComboBox->setCurrentText(QString::fromStdString(updateChannel));
|
ui->updateComboBox->setCurrentText(QString::fromStdString(updateChannel));
|
||||||
|
|
||||||
|
for (const auto& dir : Config::getGameInstallDirs()) {
|
||||||
|
QString path_string;
|
||||||
|
Common::FS::PathToQString(path_string, dir);
|
||||||
|
QListWidgetItem* item = new QListWidgetItem(path_string);
|
||||||
|
ui->gameFoldersListWidget->addItem(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString backButtonBehavior = QString::fromStdString(Config::getBackButtonBehavior());
|
||||||
|
int index = ui->backButtonBehaviorComboBox->findData(backButtonBehavior);
|
||||||
|
ui->backButtonBehaviorComboBox->setCurrentIndex(index != -1 ? index : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SettingsDialog::InitializeEmulatorLanguages() {
|
void SettingsDialog::InitializeEmulatorLanguages() {
|
||||||
@ -289,6 +401,18 @@ void SettingsDialog::OnLanguageChanged(int index) {
|
|||||||
emit LanguageChanged(ui->emulatorLanguageComboBox->itemData(index).toString().toStdString());
|
emit LanguageChanged(ui->emulatorLanguageComboBox->itemData(index).toString().toStdString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SettingsDialog::OnCursorStateChanged(s16 index) {
|
||||||
|
if (index == -1)
|
||||||
|
return;
|
||||||
|
if (index == Config::HideCursorState::Idle) {
|
||||||
|
ui->idleTimeoutGroupBox->show();
|
||||||
|
} else {
|
||||||
|
if (!ui->idleTimeoutGroupBox->isHidden()) {
|
||||||
|
ui->idleTimeoutGroupBox->hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int SettingsDialog::exec() {
|
int SettingsDialog::exec() {
|
||||||
return QDialog::exec();
|
return QDialog::exec();
|
||||||
}
|
}
|
||||||
@ -321,6 +445,17 @@ void SettingsDialog::updateNoteTextEdit(const QString& elementName) {
|
|||||||
text = tr("GUIgroupBox");
|
text = tr("GUIgroupBox");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Input
|
||||||
|
if (elementName == "cursorGroupBox") {
|
||||||
|
text = tr("cursorGroupBox");
|
||||||
|
} else if (elementName == "hideCursorGroupBox") {
|
||||||
|
text = tr("hideCursorGroupBox");
|
||||||
|
} else if (elementName == "idleTimeoutGroupBox") {
|
||||||
|
text = tr("idleTimeoutGroupBox");
|
||||||
|
} else if (elementName == "backButtonBehaviorGroupBox") {
|
||||||
|
text = tr("backButtonBehaviorGroupBox");
|
||||||
|
}
|
||||||
|
|
||||||
// Graphics
|
// Graphics
|
||||||
if (elementName == "graphicsAdapterGroupBox") {
|
if (elementName == "graphicsAdapterGroupBox") {
|
||||||
text = tr("graphicsAdapterGroupBox");
|
text = tr("graphicsAdapterGroupBox");
|
||||||
@ -334,8 +469,15 @@ void SettingsDialog::updateNoteTextEdit(const QString& elementName) {
|
|||||||
text = tr("dumpShadersCheckBox");
|
text = tr("dumpShadersCheckBox");
|
||||||
} else if (elementName == "nullGpuCheckBox") {
|
} else if (elementName == "nullGpuCheckBox") {
|
||||||
text = tr("nullGpuCheckBox");
|
text = tr("nullGpuCheckBox");
|
||||||
} else if (elementName == "dumpPM4CheckBox") {
|
}
|
||||||
text = tr("dumpPM4CheckBox");
|
|
||||||
|
// Path
|
||||||
|
if (elementName == "gameFoldersGroupBox" || elementName == "gameFoldersListWidget") {
|
||||||
|
text = tr("gameFoldersBox");
|
||||||
|
} else if (elementName == "addFolderButton") {
|
||||||
|
text = tr("addFolderButton");
|
||||||
|
} else if (elementName == "removeFolderButton") {
|
||||||
|
text = tr("removeFolderButton");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debug
|
// Debug
|
||||||
@ -352,7 +494,7 @@ void SettingsDialog::updateNoteTextEdit(const QString& elementName) {
|
|||||||
ui->descriptionText->setText(text.replace("\\n", "\n"));
|
ui->descriptionText->setText(text.replace("\\n", "\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SettingsDialog::override(QObject* obj, QEvent* event) {
|
bool SettingsDialog::eventFilter(QObject* obj, QEvent* event) {
|
||||||
if (event->type() == QEvent::Enter || event->type() == QEvent::Leave) {
|
if (event->type() == QEvent::Enter || event->type() == QEvent::Leave) {
|
||||||
if (qobject_cast<QWidget*>(obj)) {
|
if (qobject_cast<QWidget*>(obj)) {
|
||||||
bool hovered = (event->type() == QEvent::Enter);
|
bool hovered = (event->type() == QEvent::Enter);
|
||||||
|
@ -21,7 +21,7 @@ public:
|
|||||||
explicit SettingsDialog(std::span<const QString> physical_devices, QWidget* parent = nullptr);
|
explicit SettingsDialog(std::span<const QString> physical_devices, QWidget* parent = nullptr);
|
||||||
~SettingsDialog();
|
~SettingsDialog();
|
||||||
|
|
||||||
bool override(QObject* obj, QEvent* event);
|
bool eventFilter(QObject* obj, QEvent* event) override;
|
||||||
void updateNoteTextEdit(const QString& groupName);
|
void updateNoteTextEdit(const QString& groupName);
|
||||||
|
|
||||||
int exec() override;
|
int exec() override;
|
||||||
@ -33,6 +33,7 @@ private:
|
|||||||
void LoadValuesFromConfig();
|
void LoadValuesFromConfig();
|
||||||
void InitializeEmulatorLanguages();
|
void InitializeEmulatorLanguages();
|
||||||
void OnLanguageChanged(int index);
|
void OnLanguageChanged(int index);
|
||||||
|
void OnCursorStateChanged(s16 index);
|
||||||
|
|
||||||
std::unique_ptr<Ui::SettingsDialog> ui;
|
std::unique_ptr<Ui::SettingsDialog> ui;
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>854</width>
|
<width>854</width>
|
||||||
<height>570</height>
|
<height>605</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
@ -34,9 +34,18 @@
|
|||||||
<iconset>
|
<iconset>
|
||||||
<normaloff>:/images/shadps4.ico</normaloff>:/images/shadps4.ico</iconset>
|
<normaloff>:/images/shadps4.ico</normaloff>:/images/shadps4.ico</iconset>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="sizeGripEnabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="modal">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
<layout class="QVBoxLayout" name="settingsDialogLayout">
|
<layout class="QVBoxLayout" name="settingsDialogLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QScrollArea" name="scrollArea">
|
<widget class="QScrollArea" name="scrollArea">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
<property name="frameShape">
|
<property name="frameShape">
|
||||||
<enum>QFrame::Shape::NoFrame</enum>
|
<enum>QFrame::Shape::NoFrame</enum>
|
||||||
</property>
|
</property>
|
||||||
@ -51,8 +60,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>836</width>
|
<width>832</width>
|
||||||
<height>446</height>
|
<height>431</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
@ -139,6 +148,13 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="discordRPCCheckbox">
|
||||||
|
<property name="text">
|
||||||
|
<string>Enable Discord Rich Presence</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@ -258,6 +274,9 @@
|
|||||||
<layout class="QHBoxLayout" name="generalTabHLayout_2">
|
<layout class="QHBoxLayout" name="generalTabHLayout_2">
|
||||||
<item>
|
<item>
|
||||||
<layout class="QVBoxLayout" name="updaterTabLayoutLeft">
|
<layout class="QVBoxLayout" name="updaterTabLayoutLeft">
|
||||||
|
<property name="sizeConstraint">
|
||||||
|
<enum>QLayout::SizeConstraint::SetDefaultConstraint</enum>
|
||||||
|
</property>
|
||||||
<property name="leftMargin">
|
<property name="leftMargin">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
@ -270,56 +289,88 @@
|
|||||||
<property name="bottomMargin">
|
<property name="bottomMargin">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<item alignment="Qt::AlignmentFlag::AlignTop">
|
||||||
<widget class="QGroupBox" name="updaterGroupBox">
|
<widget class="QGroupBox" name="updaterGroupBox">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
<verstretch>0</verstretch>
|
<verstretch>0</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>265</width>
|
<width>275</width>
|
||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>16777215</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Update</string>
|
<string>Update</string>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QCheckBox" name="updateCheckBox">
|
<layout class="QVBoxLayout" name="UpdateLayout" stretch="0,0,0">
|
||||||
<property name="geometry">
|
<property name="spacing">
|
||||||
<rect>
|
<number>5</number>
|
||||||
<x>10</x>
|
|
||||||
<y>130</y>
|
|
||||||
<width>261</width>
|
|
||||||
<height>22</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="topMargin">
|
||||||
<string>Check for Updates at Startup</string>
|
<number>1</number>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
<property name="rightMargin">
|
||||||
|
<number>11</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>11</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
<widget class="QGroupBox" name="updaterComboBox">
|
<widget class="QGroupBox" name="updaterComboBox">
|
||||||
<property name="geometry">
|
<property name="sizePolicy">
|
||||||
<rect>
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
<x>12</x>
|
<horstretch>0</horstretch>
|
||||||
<y>30</y>
|
<verstretch>0</verstretch>
|
||||||
<width>241</width>
|
</sizepolicy>
|
||||||
<height>65</height>
|
</property>
|
||||||
</rect>
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>75</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>16777215</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Update Channel</string>
|
<string>Update Channel</string>
|
||||||
</property>
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="UpdateChannelLayout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>7</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>11</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>11</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>11</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>11</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
<widget class="QComboBox" name="updateComboBox">
|
<widget class="QComboBox" name="updateComboBox">
|
||||||
<property name="geometry">
|
<property name="sizePolicy">
|
||||||
<rect>
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
<x>12</x>
|
<horstretch>0</horstretch>
|
||||||
<y>30</y>
|
<verstretch>0</verstretch>
|
||||||
<width>217</width>
|
</sizepolicy>
|
||||||
<height>28</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@ -332,47 +383,93 @@
|
|||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
</widget>
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
<widget class="QPushButton" name="checkUpdateButton">
|
<widget class="QPushButton" name="checkUpdateButton">
|
||||||
<property name="geometry">
|
<property name="sizePolicy">
|
||||||
<rect>
|
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||||
<x>25</x>
|
<horstretch>0</horstretch>
|
||||||
<y>100</y>
|
<verstretch>0</verstretch>
|
||||||
<width>215</width>
|
</sizepolicy>
|
||||||
<height>24</height>
|
</property>
|
||||||
</rect>
|
<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>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Check for Updates</string>
|
<string>Check for Updates</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="updateCheckBox">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>11</pointsize>
|
||||||
|
<bold>false</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Check for Updates at Startup</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QVBoxLayout" name="GUITabLayoutMiddle" stretch="1">
|
<layout class="QVBoxLayout" name="GUITabLayoutMiddle" stretch="0">
|
||||||
<item>
|
<item alignment="Qt::AlignmentFlag::AlignTop">
|
||||||
<widget class="QGroupBox" name="GUIgroupBox">
|
<widget class="QGroupBox" name="GUIgroupBox">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
<verstretch>0</verstretch>
|
<verstretch>0</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>GUI Settings</string>
|
<string>GUI Settings</string>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="verticalLayoutWidget_3">
|
<layout class="QVBoxLayout" name="GUILayout">
|
||||||
<property name="geometry">
|
<property name="topMargin">
|
||||||
<rect>
|
<number>1</number>
|
||||||
<x>10</x>
|
</property>
|
||||||
<y>30</y>
|
<property name="bottomMargin">
|
||||||
<width>241</width>
|
<number>11</number>
|
||||||
<height>71</height>
|
</property>
|
||||||
</rect>
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="GUIMusicLayout">
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="playBGMCheckBox">
|
<widget class="QCheckBox" name="playBGMCheckBox">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
@ -387,11 +484,35 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<spacer name="GUIverticalSpacer_2">
|
||||||
<item>
|
<property name="orientation">
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
<enum>Qt::Orientation::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::Policy::Fixed</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>2</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label">
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>16777215</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Volume</string>
|
<string>Volume</string>
|
||||||
</property>
|
</property>
|
||||||
@ -433,28 +554,314 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
<item>
|
||||||
|
<widget class="QWidget" name="GUIwidgetSpacer" native="true">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>61</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</widget>
|
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer name="horizontalSpacer">
|
<layout class="QVBoxLayout" name="EmptyTabLayoutRight">
|
||||||
|
<item>
|
||||||
|
<spacer name="emptyHorizontalSpacer">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Orientation::Horizontal</enum>
|
<enum>Qt::Orientation::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeType">
|
|
||||||
<enum>QSizePolicy::Policy::Expanding</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="inputTab">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Input</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QVBoxLayout" name="inputTabVLayout" stretch="0,0">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="inputTabHLayoutTop" stretch="1,1,1">
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="cursorTabLayoutLeft">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>7</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item alignment="Qt::AlignmentFlag::AlignTop">
|
||||||
|
<widget class="QGroupBox" name="cursorGroupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Cursor</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="inputCursorLayout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>11</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>11</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="hideCursorGroupBox">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string>Hide Cursor</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="hideCursorLayout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>7</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>11</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="hideCursorComboBox"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="idleTimeoutGroupBox">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>0</width>
|
<width>0</width>
|
||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string>Hide Cursor Idle Timeout</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop</set>
|
||||||
|
</property>
|
||||||
|
<property name="flat">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="IdleTimeoutLayout" stretch="0,0">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>70</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>5</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>5</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>5</number>
|
||||||
|
</property>
|
||||||
|
<item alignment="Qt::AlignmentFlag::AlignHCenter">
|
||||||
|
<widget class="QSpinBox" name="idleTimeoutSpinBox">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>80</width>
|
||||||
|
<height>30</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>16777215</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="layoutDirection">
|
||||||
|
<enum>Qt::LayoutDirection::LeftToRight</enum>
|
||||||
|
</property>
|
||||||
|
<property name="wrapping">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignmentFlag::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="buttonSymbols">
|
||||||
|
<enum>QAbstractSpinBox::ButtonSymbols::UpDownArrows</enum>
|
||||||
|
</property>
|
||||||
|
<property name="suffix">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>3600</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>5</number>
|
||||||
|
</property>
|
||||||
|
<property name="displayIntegerBase">
|
||||||
|
<number>10</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="idleTimeoutDurationLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>s</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="ControllerTabLayoutMiddle">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="ControllerGroupBox">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string>Controller</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="ControllerLayout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>11</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>11</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="backButtonBehaviorGroupBox">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>237</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string>Back Button Behavior</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="BackButtonLayout">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>11</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="backButtonBehaviorComboBox"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QWidget" name="controllerWidgetSpacer" native="true">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>0</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>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="inputTabHLayoutBottom">
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<spacer name="emptyVerticalSpacerBottom">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Orientation::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::Policy::MinimumExpanding</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
@ -699,6 +1106,76 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QWidget" name="pathsTab">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Paths</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QVBoxLayout" name="inputTabVLayout" stretch="0">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="gameFoldersGroupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Game Folders</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QListWidget" name="gameFoldersListWidget">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>20</y>
|
||||||
|
<width>401</width>
|
||||||
|
<height>331</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPushButton" name="addFolderButton">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>100</x>
|
||||||
|
<y>360</y>
|
||||||
|
<width>80</width>
|
||||||
|
<height>24</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Add...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPushButton" name="removeFolderButton">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>210</x>
|
||||||
|
<y>360</y>
|
||||||
|
<width>80</width>
|
||||||
|
<height>24</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Remove</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Orientation::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::Policy::Preferred</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
<widget class="QWidget" name="debugTab">
|
<widget class="QWidget" name="debugTab">
|
||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
<string>Debug</string>
|
<string>Debug</string>
|
||||||
|
@ -474,11 +474,6 @@
|
|||||||
<source>Enable NULL GPU</source>
|
<source>Enable NULL GPU</source>
|
||||||
<translation>تمكين وحدة معالجة الرسومات الفارغة</translation>
|
<translation>تمكين وحدة معالجة الرسومات الفارغة</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.ui" line="476"/>
|
|
||||||
<source>Enable PM4 Dumping</source>
|
|
||||||
<translation>PM4 تمكين تفريغ</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.ui" line="517"/>
|
<location filename="../settings_dialog.ui" line="517"/>
|
||||||
<source>Debug</source>
|
<source>Debug</source>
|
||||||
@ -1053,11 +1048,6 @@
|
|||||||
<source>nullGpuCheckBox</source>
|
<source>nullGpuCheckBox</source>
|
||||||
<translation>تمكين GPU الافتراضية:\nلأغراض تصحيح الأخطاء التقنية، يقوم بتعطيل عرض اللعبة كما لو لم يكن هناك بطاقة رسومات.</translation>
|
<translation>تمكين GPU الافتراضية:\nلأغراض تصحيح الأخطاء التقنية، يقوم بتعطيل عرض اللعبة كما لو لم يكن هناك بطاقة رسومات.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.cpp" line="323"/>
|
|
||||||
<source>dumpPM4CheckBox</source>
|
|
||||||
<translation>تمكين تفريغ PM4:\nلأغراض تصحيح الأخطاء التقنية، يحفظ بيانات تعليمات GPU الأولية في مجلد أثناء معالجتها.</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="329"/>
|
<location filename="../settings_dialog.cpp" line="329"/>
|
||||||
<source>debugDump</source>
|
<source>debugDump</source>
|
||||||
@ -1121,6 +1111,11 @@
|
|||||||
<source>Path</source>
|
<source>Path</source>
|
||||||
<translation>مسار</translation>
|
<translation>مسار</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../game_list_frame.cpp" line="38"/>
|
||||||
|
<source>Play Time</source>
|
||||||
|
<translation>وقت اللعب</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>CheckUpdate</name>
|
<name>CheckUpdate</name>
|
||||||
|
@ -474,11 +474,6 @@
|
|||||||
<source>Enable NULL GPU</source>
|
<source>Enable NULL GPU</source>
|
||||||
<translation>Enable NULL GPU</translation>
|
<translation>Enable NULL GPU</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.ui" line="476"/>
|
|
||||||
<source>Enable PM4 Dumping</source>
|
|
||||||
<translation>Enable PM4 Dumping</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.ui" line="517"/>
|
<location filename="../settings_dialog.ui" line="517"/>
|
||||||
<source>Debug</source>
|
<source>Debug</source>
|
||||||
@ -1053,11 +1048,6 @@
|
|||||||
<source>nullGpuCheckBox</source>
|
<source>nullGpuCheckBox</source>
|
||||||
<translation>Aktiver virtuel GPU:\nTil teknisk fejlfinding deaktiverer det spilvisning, som om der ikke var et grafikkort.</translation>
|
<translation>Aktiver virtuel GPU:\nTil teknisk fejlfinding deaktiverer det spilvisning, som om der ikke var et grafikkort.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.cpp" line="323"/>
|
|
||||||
<source>dumpPM4CheckBox</source>
|
|
||||||
<translation>Aktiver dumping af PM4:\nTil teknisk fejlfinding gemmer det rå GPU-kommandoer i en mappe under behandling.</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="329"/>
|
<location filename="../settings_dialog.cpp" line="329"/>
|
||||||
<source>debugDump</source>
|
<source>debugDump</source>
|
||||||
@ -1121,6 +1111,11 @@
|
|||||||
<source>Path</source>
|
<source>Path</source>
|
||||||
<translation>Sti</translation>
|
<translation>Sti</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../game_list_frame.cpp" line="38"/>
|
||||||
|
<source>Play Time</source>
|
||||||
|
<translation>Spilletid</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>CheckUpdate</name>
|
<name>CheckUpdate</name>
|
||||||
|
@ -474,11 +474,6 @@
|
|||||||
<source>Enable NULL GPU</source>
|
<source>Enable NULL GPU</source>
|
||||||
<translation>NULL GPU aktivieren</translation>
|
<translation>NULL GPU aktivieren</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.ui" line="476"/>
|
|
||||||
<source>Enable PM4 Dumping</source>
|
|
||||||
<translation>PM4-Dumping aktivieren</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.ui" line="517"/>
|
<location filename="../settings_dialog.ui" line="517"/>
|
||||||
<source>Debug</source>
|
<source>Debug</source>
|
||||||
@ -1053,11 +1048,6 @@
|
|||||||
<source>nullGpuCheckBox</source>
|
<source>nullGpuCheckBox</source>
|
||||||
<translation>Virtuelle GPU aktivieren:\nFür das technische Debugging deaktiviert es die Spielanzeige, als ob keine Grafikkarte vorhanden wäre.</translation>
|
<translation>Virtuelle GPU aktivieren:\nFür das technische Debugging deaktiviert es die Spielanzeige, als ob keine Grafikkarte vorhanden wäre.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.cpp" line="323"/>
|
|
||||||
<source>dumpPM4CheckBox</source>
|
|
||||||
<translation>PM4-Dumping aktivieren:\nZum technischen Debuggen speichert es rohe GPU-Befehlsdaten in einem Ordner während der Verarbeitung.</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="329"/>
|
<location filename="../settings_dialog.cpp" line="329"/>
|
||||||
<source>debugDump</source>
|
<source>debugDump</source>
|
||||||
@ -1121,6 +1111,11 @@
|
|||||||
<source>Path</source>
|
<source>Path</source>
|
||||||
<translation>Pfad</translation>
|
<translation>Pfad</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../game_list_frame.cpp" line="38"/>
|
||||||
|
<source>Play Time</source>
|
||||||
|
<translation>Spielzeit</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>CheckUpdate</name>
|
<name>CheckUpdate</name>
|
||||||
|
@ -474,11 +474,6 @@
|
|||||||
<source>Enable NULL GPU</source>
|
<source>Enable NULL GPU</source>
|
||||||
<translation>Enable NULL GPU</translation>
|
<translation>Enable NULL GPU</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.ui" line="476"/>
|
|
||||||
<source>Enable PM4 Dumping</source>
|
|
||||||
<translation>Enable PM4 Dumping</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.ui" line="517"/>
|
<location filename="../settings_dialog.ui" line="517"/>
|
||||||
<source>Debug</source>
|
<source>Debug</source>
|
||||||
@ -1053,11 +1048,6 @@
|
|||||||
<source>nullGpuCheckBox</source>
|
<source>nullGpuCheckBox</source>
|
||||||
<translation>Ενεργοποίηση Εικονικής GPU:\nΓια τεχνικό εντοπισμό σφαλμάτων, απενεργοποιεί την εμφάνιση του παιχνιδιού σαν να μην υπάρχει κάρτα γραφικών.</translation>
|
<translation>Ενεργοποίηση Εικονικής GPU:\nΓια τεχνικό εντοπισμό σφαλμάτων, απενεργοποιεί την εμφάνιση του παιχνιδιού σαν να μην υπάρχει κάρτα γραφικών.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.cpp" line="323"/>
|
|
||||||
<source>dumpPM4CheckBox</source>
|
|
||||||
<translation>Ενεργοποίηση Καταγραφής PM4:\nΓια τεχνικό εντοπισμό σφαλμάτων, αποθηκεύει τις ακατέργαστες εντολές της GPU σε φάκελο κατά την επεξεργασία.</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="329"/>
|
<location filename="../settings_dialog.cpp" line="329"/>
|
||||||
<source>debugDump</source>
|
<source>debugDump</source>
|
||||||
@ -1121,6 +1111,11 @@
|
|||||||
<source>Path</source>
|
<source>Path</source>
|
||||||
<translation>Διαδρομή</translation>
|
<translation>Διαδρομή</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../game_list_frame.cpp" line="38"/>
|
||||||
|
<source>Play Time</source>
|
||||||
|
<translation>Χρόνος παιχνιδιού</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>CheckUpdate</name>
|
<name>CheckUpdate</name>
|
||||||
|
@ -434,6 +434,41 @@
|
|||||||
<source>Log Filter</source>
|
<source>Log Filter</source>
|
||||||
<translation>Log Filter</translation>
|
<translation>Log Filter</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../settings_dialog.ui" line="595"/>
|
||||||
|
<source>Input</source>
|
||||||
|
<translation>Input</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../settings_dialog.ui" line="611"/>
|
||||||
|
<source>Cursor</source>
|
||||||
|
<translation>Cursor</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../settings_dialog.ui" line="635"/>
|
||||||
|
<source>Hide Cursor</source>
|
||||||
|
<translation>Hide Cursor</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../settings_dialog.ui" line="668"/>
|
||||||
|
<source>Hide Cursor Idle Timeout</source>
|
||||||
|
<translation>Hide Cursor Idle Timeout</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../settings_dialog.ui" line="595"/>
|
||||||
|
<source>Input</source>
|
||||||
|
<translation>Input</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../settings_dialog.ui" line="767"/>
|
||||||
|
<source>Controller</source>
|
||||||
|
<translation>Controller</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../settings_dialog.ui" line="797"/>
|
||||||
|
<source>Back Button Behavior</source>
|
||||||
|
<translation>Back Button Behavior</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.ui" line="272"/>
|
<location filename="../settings_dialog.ui" line="272"/>
|
||||||
<source>Graphics</source>
|
<source>Graphics</source>
|
||||||
@ -474,11 +509,6 @@
|
|||||||
<source>Enable NULL GPU</source>
|
<source>Enable NULL GPU</source>
|
||||||
<translation>Enable NULL GPU</translation>
|
<translation>Enable NULL GPU</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.ui" line="476"/>
|
|
||||||
<source>Enable PM4 Dumping</source>
|
|
||||||
<translation>Enable PM4 Dumping</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.ui" line="517"/>
|
<location filename="../settings_dialog.ui" line="517"/>
|
||||||
<source>Debug</source>
|
<source>Debug</source>
|
||||||
@ -1028,6 +1058,66 @@
|
|||||||
<source>GUIgroupBox</source>
|
<source>GUIgroupBox</source>
|
||||||
<translation>Play Title Music:\nIf a game supports it, enable playing special music when selecting the game in the GUI.</translation>
|
<translation>Play Title Music:\nIf a game supports it, enable playing special music when selecting the game in the GUI.</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../settings_dialog.cpp" line="392"/>
|
||||||
|
<source>cursorGroupBox</source>
|
||||||
|
<translation>Cursor:\nChange settings related to the cursor.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../settings_dialog.cpp" line="394"/>
|
||||||
|
<source>hideCursorGroupBox</source>
|
||||||
|
<translation>Hide Cursor:\nSet cursor hiding behavior.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../settings_dialog.cpp" line="396"/>
|
||||||
|
<source>idleTimeoutGroupBox</source>
|
||||||
|
<translation>Hide Idle Cursor Timeout:\nThe duration (seconds) after which the cursor that has been idle hides itself.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../settings_dialog.cpp" line="70"/>
|
||||||
|
<source>Never</source>
|
||||||
|
<translation>Never</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../settings_dialog.cpp" line="71"/>
|
||||||
|
<source>Idle</source>
|
||||||
|
<translation>Idle</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../settings_dialog.cpp" line="72"/>
|
||||||
|
<source>Always</source>
|
||||||
|
<translation>Always</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../settings_dialog.cpp" line="330"/>
|
||||||
|
<source>backButtonBehaviorGroupBox</source>
|
||||||
|
<translation>Back Button Behavior:\nAllows setting which part of the touchpad the back button will emulate a touch on.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../settings_dialog.cpp" line="330"/>
|
||||||
|
<source>backButtonBehaviorGroupBox</source>
|
||||||
|
<translation>Back Button Behavior:\nAllows setting which part of the touchpad the back button will emulate a touch on.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../settings_dialog.cpp" line="101"/>
|
||||||
|
<source>Touchpad Left</source>
|
||||||
|
<translation>Touchpad Left</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../settings_dialog.cpp" line="102"/>
|
||||||
|
<source>Touchpad Right</source>
|
||||||
|
<translation>Touchpad Right</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../settings_dialog.cpp" line="103"/>
|
||||||
|
<source>Touchpad Center</source>
|
||||||
|
<translation>Touchpad Center</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../settings_dialog.cpp" line="104"/>
|
||||||
|
<source>None</source>
|
||||||
|
<translation>None</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="312"/>
|
<location filename="../settings_dialog.cpp" line="312"/>
|
||||||
<source>graphicsAdapterGroupBox</source>
|
<source>graphicsAdapterGroupBox</source>
|
||||||
@ -1054,9 +1144,19 @@
|
|||||||
<translation>Enable Null GPU:\nFor the sake of technical debugging, disables game rendering as if there were no graphics card.</translation>
|
<translation>Enable Null GPU:\nFor the sake of technical debugging, disables game rendering as if there were no graphics card.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="323"/>
|
<location filename="../settings_dialog.cpp" line="465"/>
|
||||||
<source>dumpPM4CheckBox</source>
|
<source>gameFoldersBox</source>
|
||||||
<translation>Enable PM4 Dumping:\nFor the sake of technical debugging, saves raw GPU instruction data to a folder as the emulator processes it.</translation>
|
<translation>Game Folders: The list of folders to check for installed games.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../settings_dialog.cpp" line="465"/>
|
||||||
|
<source>addFolderButton</source>
|
||||||
|
<translation>Add: Add a folder to the list.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../settings_dialog.cpp" line="465"/>
|
||||||
|
<source>removeFolderButton</source>
|
||||||
|
<translation>Remove: Remove a folder from the list.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="329"/>
|
<location filename="../settings_dialog.cpp" line="329"/>
|
||||||
@ -1121,6 +1221,11 @@
|
|||||||
<source>Path</source>
|
<source>Path</source>
|
||||||
<translation>Path</translation>
|
<translation>Path</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../game_list_frame.cpp" line="38"/>
|
||||||
|
<source>Play Time</source>
|
||||||
|
<translation>Play Time</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>CheckUpdate</name>
|
<name>CheckUpdate</name>
|
||||||
|
@ -474,11 +474,6 @@
|
|||||||
<source>Enable NULL GPU</source>
|
<source>Enable NULL GPU</source>
|
||||||
<translation>Habilitar GPU NULL</translation>
|
<translation>Habilitar GPU NULL</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.ui" line="476"/>
|
|
||||||
<source>Enable PM4 Dumping</source>
|
|
||||||
<translation>Habilitar volcado de PM4</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.ui" line="517"/>
|
<location filename="../settings_dialog.ui" line="517"/>
|
||||||
<source>Debug</source>
|
<source>Debug</source>
|
||||||
@ -1053,11 +1048,6 @@
|
|||||||
<source>nullGpuCheckBox</source>
|
<source>nullGpuCheckBox</source>
|
||||||
<translation>Habilitar GPU Nula:\nPor el bien de la depuración técnica, desactiva el renderizado del juego como si no hubiera tarjeta gráfica.</translation>
|
<translation>Habilitar GPU Nula:\nPor el bien de la depuración técnica, desactiva el renderizado del juego como si no hubiera tarjeta gráfica.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.cpp" line="323"/>
|
|
||||||
<source>dumpPM4CheckBox</source>
|
|
||||||
<translation>Habilitar la Volcadura de PM4:\nPor el bien de la depuración técnica, guarda los datos de instrucciones crudas de GPU en una carpeta a medida que el emulador los procesa.</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="329"/>
|
<location filename="../settings_dialog.cpp" line="329"/>
|
||||||
<source>debugDump</source>
|
<source>debugDump</source>
|
||||||
@ -1121,6 +1111,11 @@
|
|||||||
<source>Path</source>
|
<source>Path</source>
|
||||||
<translation>Ruta</translation>
|
<translation>Ruta</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../game_list_frame.cpp" line="38"/>
|
||||||
|
<source>Play Time</source>
|
||||||
|
<translation>Tiempo de Juego</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>CheckUpdate</name>
|
<name>CheckUpdate</name>
|
||||||
|
@ -474,11 +474,6 @@
|
|||||||
<source>Enable NULL GPU</source>
|
<source>Enable NULL GPU</source>
|
||||||
<translation>NULL GPU فعال کردن</translation>
|
<translation>NULL GPU فعال کردن</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.ui" line="476"/>
|
|
||||||
<source>Enable PM4 Dumping</source>
|
|
||||||
<translation>PM4 Dumping فعال کردن</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.ui" line="517"/>
|
<location filename="../settings_dialog.ui" line="517"/>
|
||||||
<source>Debug</source>
|
<source>Debug</source>
|
||||||
@ -1053,11 +1048,6 @@
|
|||||||
<source>nullGpuCheckBox</source>
|
<source>nullGpuCheckBox</source>
|
||||||
<translation>Enable Null GPU:\nFor the sake of technical debugging, disables game rendering as if there were no graphics card.</translation>
|
<translation>Enable Null GPU:\nFor the sake of technical debugging, disables game rendering as if there were no graphics card.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.cpp" line="323"/>
|
|
||||||
<source>dumpPM4CheckBox</source>
|
|
||||||
<translation>Enable PM4 Dumping:\nFor the sake of technical debugging, saves raw GPU instruction data to a folder as the emulator processes it.</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="329"/>
|
<location filename="../settings_dialog.cpp" line="329"/>
|
||||||
<source>debugDump</source>
|
<source>debugDump</source>
|
||||||
@ -1121,6 +1111,11 @@
|
|||||||
<source>Path</source>
|
<source>Path</source>
|
||||||
<translation>مسیر</translation>
|
<translation>مسیر</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../game_list_frame.cpp" line="38"/>
|
||||||
|
<source>Play Time</source>
|
||||||
|
<translation>زمان بازی</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>CheckUpdate</name>
|
<name>CheckUpdate</name>
|
||||||
|
@ -474,11 +474,6 @@
|
|||||||
<source>Enable NULL GPU</source>
|
<source>Enable NULL GPU</source>
|
||||||
<translation>Enable NULL GPU</translation>
|
<translation>Enable NULL GPU</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.ui" line="476"/>
|
|
||||||
<source>Enable PM4 Dumping</source>
|
|
||||||
<translation>Enable PM4 Dumping</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.ui" line="517"/>
|
<location filename="../settings_dialog.ui" line="517"/>
|
||||||
<source>Debug</source>
|
<source>Debug</source>
|
||||||
@ -1053,11 +1048,6 @@
|
|||||||
<source>nullGpuCheckBox</source>
|
<source>nullGpuCheckBox</source>
|
||||||
<translation>Ota Null GPU käyttöön:\nTeknistä vianetsintää varten pelin renderöinti estetään niin, että ikään kuin grafiikkakorttia ei olisi.</translation>
|
<translation>Ota Null GPU käyttöön:\nTeknistä vianetsintää varten pelin renderöinti estetään niin, että ikään kuin grafiikkakorttia ei olisi.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.cpp" line="323"/>
|
|
||||||
<source>dumpPM4CheckBox</source>
|
|
||||||
<translation>Ota PM4 dumpaus käyttöön:\nTeknistä vianetsintää varten raakoja GPU-ohjeita tallennetaan kansioon emulaattorin käsitellessä sitä.</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="329"/>
|
<location filename="../settings_dialog.cpp" line="329"/>
|
||||||
<source>debugDump</source>
|
<source>debugDump</source>
|
||||||
@ -1121,6 +1111,11 @@
|
|||||||
<source>Path</source>
|
<source>Path</source>
|
||||||
<translation>Polku</translation>
|
<translation>Polku</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../game_list_frame.cpp" line="38"/>
|
||||||
|
<source>Play Time</source>
|
||||||
|
<translation>Peliaika</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>CheckUpdate</name>
|
<name>CheckUpdate</name>
|
||||||
|
@ -474,11 +474,6 @@
|
|||||||
<source>Enable NULL GPU</source>
|
<source>Enable NULL GPU</source>
|
||||||
<translation>NULL GPU</translation>
|
<translation>NULL GPU</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.ui" line="476"/>
|
|
||||||
<source>Enable PM4 Dumping</source>
|
|
||||||
<translation>Dumper le PM4</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.ui" line="517"/>
|
<location filename="../settings_dialog.ui" line="517"/>
|
||||||
<source>Debug</source>
|
<source>Debug</source>
|
||||||
@ -1053,11 +1048,6 @@
|
|||||||
<source>nullGpuCheckBox</source>
|
<source>nullGpuCheckBox</source>
|
||||||
<translation>Activer le GPU nul :\nPour le débogage technique, désactive le rendu du jeu comme s'il n'y avait pas de carte graphique.</translation>
|
<translation>Activer le GPU nul :\nPour le débogage technique, désactive le rendu du jeu comme s'il n'y avait pas de carte graphique.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.cpp" line="323"/>
|
|
||||||
<source>dumpPM4CheckBox</source>
|
|
||||||
<translation>Activer l'exportation PM4 :\nPour le débogage technique, enregistre les données brutes des instructions GPU dans un dossier pendant que l'émulateur les traite.</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="329"/>
|
<location filename="../settings_dialog.cpp" line="329"/>
|
||||||
<source>debugDump</source>
|
<source>debugDump</source>
|
||||||
@ -1121,6 +1111,11 @@
|
|||||||
<source>Path</source>
|
<source>Path</source>
|
||||||
<translation>Répertoire</translation>
|
<translation>Répertoire</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../game_list_frame.cpp" line="38"/>
|
||||||
|
<source>Play Time</source>
|
||||||
|
<translation>Temps de jeu</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>CheckUpdate</name>
|
<name>CheckUpdate</name>
|
||||||
|
@ -474,11 +474,6 @@
|
|||||||
<source>Enable NULL GPU</source>
|
<source>Enable NULL GPU</source>
|
||||||
<translation>NULL GPU Engedélyezése</translation>
|
<translation>NULL GPU Engedélyezése</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.ui" line="476"/>
|
|
||||||
<source>Enable PM4 Dumping</source>
|
|
||||||
<translation>PM4 Dumpolás Engedélyezése</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.ui" line="517"/>
|
<location filename="../settings_dialog.ui" line="517"/>
|
||||||
<source>Debug</source>
|
<source>Debug</source>
|
||||||
@ -1053,11 +1048,6 @@
|
|||||||
<source>nullGpuCheckBox</source>
|
<source>nullGpuCheckBox</source>
|
||||||
<translation>Null GPU engedélyezése:\nMűszaki hibaelhárítás céljából letiltja a játék renderelését, mintha nem lenne grafikus kártya.</translation>
|
<translation>Null GPU engedélyezése:\nMűszaki hibaelhárítás céljából letiltja a játék renderelését, mintha nem lenne grafikus kártya.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.cpp" line="323"/>
|
|
||||||
<source>dumpPM4CheckBox</source>
|
|
||||||
<translation>PM4 dumpolás engedélyezése:\nMűszaki hibaelhárítás céljából a nyers GPU utasítási adatokat elmenti egy mappába, ahogy az emulátor feldolgozza őket.</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="329"/>
|
<location filename="../settings_dialog.cpp" line="329"/>
|
||||||
<source>debugDump</source>
|
<source>debugDump</source>
|
||||||
@ -1121,6 +1111,11 @@
|
|||||||
<source>Path</source>
|
<source>Path</source>
|
||||||
<translation>Útvonal</translation>
|
<translation>Útvonal</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../game_list_frame.cpp" line="38"/>
|
||||||
|
<source>Play Time</source>
|
||||||
|
<translation>Játékidő</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>CheckUpdate</name>
|
<name>CheckUpdate</name>
|
||||||
|
@ -474,11 +474,6 @@
|
|||||||
<source>Enable NULL GPU</source>
|
<source>Enable NULL GPU</source>
|
||||||
<translation>Enable NULL GPU</translation>
|
<translation>Enable NULL GPU</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.ui" line="476"/>
|
|
||||||
<source>Enable PM4 Dumping</source>
|
|
||||||
<translation>Enable PM4 Dumping</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.ui" line="517"/>
|
<location filename="../settings_dialog.ui" line="517"/>
|
||||||
<source>Debug</source>
|
<source>Debug</source>
|
||||||
@ -1053,11 +1048,6 @@
|
|||||||
<source>nullGpuCheckBox</source>
|
<source>nullGpuCheckBox</source>
|
||||||
<translation>Aktifkan GPU Null:\nUntuk tujuan debugging teknis, menonaktifkan rendering permainan seolah-olah tidak ada kartu grafis.</translation>
|
<translation>Aktifkan GPU Null:\nUntuk tujuan debugging teknis, menonaktifkan rendering permainan seolah-olah tidak ada kartu grafis.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.cpp" line="323"/>
|
|
||||||
<source>dumpPM4CheckBox</source>
|
|
||||||
<translation>Aktifkan Pembuangan PM4:\nUntuk tujuan debugging teknis, menyimpan data instruksi GPU mentah ke folder saat emulator memprosesnya.</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="329"/>
|
<location filename="../settings_dialog.cpp" line="329"/>
|
||||||
<source>debugDump</source>
|
<source>debugDump</source>
|
||||||
@ -1121,6 +1111,11 @@
|
|||||||
<source>Path</source>
|
<source>Path</source>
|
||||||
<translation>Jalur</translation>
|
<translation>Jalur</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../game_list_frame.cpp" line="38"/>
|
||||||
|
<source>Play Time</source>
|
||||||
|
<translation>Waktu Bermain</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>CheckUpdate</name>
|
<name>CheckUpdate</name>
|
||||||
|
@ -474,11 +474,6 @@
|
|||||||
<source>Enable NULL GPU</source>
|
<source>Enable NULL GPU</source>
|
||||||
<translation>Abilita NULL GPU</translation>
|
<translation>Abilita NULL GPU</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.ui" line="476"/>
|
|
||||||
<source>Enable PM4 Dumping</source>
|
|
||||||
<translation>Abilita Dump PM4</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.ui" line="517"/>
|
<location filename="../settings_dialog.ui" line="517"/>
|
||||||
<source>Debug</source>
|
<source>Debug</source>
|
||||||
@ -1053,11 +1048,6 @@
|
|||||||
<source>nullGpuCheckBox</source>
|
<source>nullGpuCheckBox</source>
|
||||||
<translation>Abilita GPU Null:\nPer scopi di debug tecnico, disabilita il rendering del gioco come se non ci fosse alcuna scheda grafica.</translation>
|
<translation>Abilita GPU Null:\nPer scopi di debug tecnico, disabilita il rendering del gioco come se non ci fosse alcuna scheda grafica.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.cpp" line="323"/>
|
|
||||||
<source>dumpPM4CheckBox</source>
|
|
||||||
<translation>Abilita Pompaggio PM4:\nPer scopi di debug tecnico, salva i dati delle istruzioni GPU grezze in una cartella mentre l'emulatore li elabora.</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="329"/>
|
<location filename="../settings_dialog.cpp" line="329"/>
|
||||||
<source>debugDump</source>
|
<source>debugDump</source>
|
||||||
@ -1121,6 +1111,11 @@
|
|||||||
<source>Path</source>
|
<source>Path</source>
|
||||||
<translation>Percorso</translation>
|
<translation>Percorso</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../game_list_frame.cpp" line="38"/>
|
||||||
|
<source>Play Time</source>
|
||||||
|
<translation>Tempo di Gioco</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>CheckUpdate</name>
|
<name>CheckUpdate</name>
|
||||||
|
@ -474,11 +474,6 @@
|
|||||||
<source>Enable NULL GPU</source>
|
<source>Enable NULL GPU</source>
|
||||||
<translation>NULL GPUを有効にする</translation>
|
<translation>NULL GPUを有効にする</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.ui" line="476"/>
|
|
||||||
<source>Enable PM4 Dumping</source>
|
|
||||||
<translation>PM4ダンプを有効にする</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.ui" line="517"/>
|
<location filename="../settings_dialog.ui" line="517"/>
|
||||||
<source>Debug</source>
|
<source>Debug</source>
|
||||||
@ -1053,11 +1048,6 @@
|
|||||||
<source>nullGpuCheckBox</source>
|
<source>nullGpuCheckBox</source>
|
||||||
<translation>Null GPUを有効にする:\n技術的なデバッグの目的で、グラフィックスカードがないかのようにゲームのレンダリングを無効にします。</translation>
|
<translation>Null GPUを有効にする:\n技術的なデバッグの目的で、グラフィックスカードがないかのようにゲームのレンダリングを無効にします。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.cpp" line="323"/>
|
|
||||||
<source>dumpPM4CheckBox</source>
|
|
||||||
<translation>PM4ダンプを有効にする:\n技術的なデバッグの目的で、エミュレーターが処理している間に生のGPU命令データをフォルダーに保存します。</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="329"/>
|
<location filename="../settings_dialog.cpp" line="329"/>
|
||||||
<source>debugDump</source>
|
<source>debugDump</source>
|
||||||
@ -1121,6 +1111,11 @@
|
|||||||
<source>Path</source>
|
<source>Path</source>
|
||||||
<translation>パス</translation>
|
<translation>パス</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../game_list_frame.cpp" line="38"/>
|
||||||
|
<source>Play Time</source>
|
||||||
|
<translation>プレイ時間</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>CheckUpdate</name>
|
<name>CheckUpdate</name>
|
||||||
|
@ -474,11 +474,6 @@
|
|||||||
<source>Enable NULL GPU</source>
|
<source>Enable NULL GPU</source>
|
||||||
<translation>Enable NULL GPU</translation>
|
<translation>Enable NULL GPU</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.ui" line="476"/>
|
|
||||||
<source>Enable PM4 Dumping</source>
|
|
||||||
<translation>Enable PM4 Dumping</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.ui" line="517"/>
|
<location filename="../settings_dialog.ui" line="517"/>
|
||||||
<source>Debug</source>
|
<source>Debug</source>
|
||||||
@ -1053,11 +1048,6 @@
|
|||||||
<source>nullGpuCheckBox</source>
|
<source>nullGpuCheckBox</source>
|
||||||
<translation>Enable Null GPU:\nFor the sake of technical debugging, disables game rendering as if there were no graphics card.</translation>
|
<translation>Enable Null GPU:\nFor the sake of technical debugging, disables game rendering as if there were no graphics card.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.cpp" line="323"/>
|
|
||||||
<source>dumpPM4CheckBox</source>
|
|
||||||
<translation>Enable PM4 Dumping:\nFor the sake of technical debugging, saves raw GPU instruction data to a folder as the emulator processes it.</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="329"/>
|
<location filename="../settings_dialog.cpp" line="329"/>
|
||||||
<source>debugDump</source>
|
<source>debugDump</source>
|
||||||
@ -1121,6 +1111,11 @@
|
|||||||
<source>Path</source>
|
<source>Path</source>
|
||||||
<translation>Path</translation>
|
<translation>Path</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../game_list_frame.cpp" line="38"/>
|
||||||
|
<source>Play Time</source>
|
||||||
|
<translation>Play Time</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>CheckUpdate</name>
|
<name>CheckUpdate</name>
|
||||||
|
@ -474,11 +474,6 @@
|
|||||||
<source>Enable NULL GPU</source>
|
<source>Enable NULL GPU</source>
|
||||||
<translation>Enable NULL GPU</translation>
|
<translation>Enable NULL GPU</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.ui" line="476"/>
|
|
||||||
<source>Enable PM4 Dumping</source>
|
|
||||||
<translation>Enable PM4 Dumping</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.ui" line="517"/>
|
<location filename="../settings_dialog.ui" line="517"/>
|
||||||
<source>Debug</source>
|
<source>Debug</source>
|
||||||
@ -1053,11 +1048,6 @@
|
|||||||
<source>nullGpuCheckBox</source>
|
<source>nullGpuCheckBox</source>
|
||||||
<translation>Įjungti tuščią GPU:\nTechninio derinimo tikslais išjungia žaidimo renderiavimą, tarsi nebūtų grafikos plokštės.</translation>
|
<translation>Įjungti tuščią GPU:\nTechninio derinimo tikslais išjungia žaidimo renderiavimą, tarsi nebūtų grafikos plokštės.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.cpp" line="323"/>
|
|
||||||
<source>dumpPM4CheckBox</source>
|
|
||||||
<translation>Įjungti PM4 išmetimą:\nTechninio derinimo tikslais saugo žalius GPU nurodymų duomenis į aplanką, kai emuliatorius juos apdoroja.</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="329"/>
|
<location filename="../settings_dialog.cpp" line="329"/>
|
||||||
<source>debugDump</source>
|
<source>debugDump</source>
|
||||||
@ -1121,6 +1111,11 @@
|
|||||||
<source>Path</source>
|
<source>Path</source>
|
||||||
<translation>Kelias</translation>
|
<translation>Kelias</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../game_list_frame.cpp" line="38"/>
|
||||||
|
<source>Play Time</source>
|
||||||
|
<translation>Žaidimo laikas</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>CheckUpdate</name>
|
<name>CheckUpdate</name>
|
||||||
|
@ -474,11 +474,6 @@
|
|||||||
<source>Enable NULL GPU</source>
|
<source>Enable NULL GPU</source>
|
||||||
<translation>Enable NULL GPU</translation>
|
<translation>Enable NULL GPU</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.ui" line="476"/>
|
|
||||||
<source>Enable PM4 Dumping</source>
|
|
||||||
<translation>Enable PM4 Dumping</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.ui" line="517"/>
|
<location filename="../settings_dialog.ui" line="517"/>
|
||||||
<source>Debug</source>
|
<source>Debug</source>
|
||||||
@ -1053,11 +1048,6 @@
|
|||||||
<source>nullGpuCheckBox</source>
|
<source>nullGpuCheckBox</source>
|
||||||
<translation>Aktiver Null GPU:\nFor teknisk feilsøking deaktiverer spillrendering som om det ikke var noe grafikkort.</translation>
|
<translation>Aktiver Null GPU:\nFor teknisk feilsøking deaktiverer spillrendering som om det ikke var noe grafikkort.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.cpp" line="323"/>
|
|
||||||
<source>dumpPM4CheckBox</source>
|
|
||||||
<translation>Aktiver PM4 dumping:\nFor teknisk feilsøking lagrer rå GPU-instruksjonsdata i en mappe mens emulatoren behandler dem.</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="329"/>
|
<location filename="../settings_dialog.cpp" line="329"/>
|
||||||
<source>debugDump</source>
|
<source>debugDump</source>
|
||||||
@ -1121,6 +1111,11 @@
|
|||||||
<source>Path</source>
|
<source>Path</source>
|
||||||
<translation>Sti</translation>
|
<translation>Sti</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../game_list_frame.cpp" line="38"/>
|
||||||
|
<source>Play Time</source>
|
||||||
|
<translation>Spilletid</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>CheckUpdate</name>
|
<name>CheckUpdate</name>
|
||||||
|
@ -474,11 +474,6 @@
|
|||||||
<source>Enable NULL GPU</source>
|
<source>Enable NULL GPU</source>
|
||||||
<translation>Enable NULL GPU</translation>
|
<translation>Enable NULL GPU</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.ui" line="476"/>
|
|
||||||
<source>Enable PM4 Dumping</source>
|
|
||||||
<translation>Enable PM4 Dumping</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.ui" line="517"/>
|
<location filename="../settings_dialog.ui" line="517"/>
|
||||||
<source>Debug</source>
|
<source>Debug</source>
|
||||||
@ -1053,11 +1048,6 @@
|
|||||||
<source>nullGpuCheckBox</source>
|
<source>nullGpuCheckBox</source>
|
||||||
<translation>Null GPU inschakelen:\nVoor technische foutopsporing schakelt de game-rendering uit alsof er geen grafische kaart is.</translation>
|
<translation>Null GPU inschakelen:\nVoor technische foutopsporing schakelt de game-rendering uit alsof er geen grafische kaart is.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.cpp" line="323"/>
|
|
||||||
<source>dumpPM4CheckBox</source>
|
|
||||||
<translation>PM4 dumpen inschakelen:\nVoor technische foutopsporing slaat het ruwe GPU-instructiegegevens op in een map terwijl de emulator ze verwerkt.</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="329"/>
|
<location filename="../settings_dialog.cpp" line="329"/>
|
||||||
<source>debugDump</source>
|
<source>debugDump</source>
|
||||||
@ -1121,6 +1111,11 @@
|
|||||||
<source>Path</source>
|
<source>Path</source>
|
||||||
<translation>Pad</translation>
|
<translation>Pad</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../game_list_frame.cpp" line="38"/>
|
||||||
|
<source>Play Time</source>
|
||||||
|
<translation>Speeltijd</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>CheckUpdate</name>
|
<name>CheckUpdate</name>
|
||||||
|
@ -474,11 +474,6 @@
|
|||||||
<source>Enable NULL GPU</source>
|
<source>Enable NULL GPU</source>
|
||||||
<translation>Wyłącz kartę graficzną</translation>
|
<translation>Wyłącz kartę graficzną</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.ui" line="476"/>
|
|
||||||
<source>Enable PM4 Dumping</source>
|
|
||||||
<translation>Włącz zgrywanie PM4</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.ui" line="517"/>
|
<location filename="../settings_dialog.ui" line="517"/>
|
||||||
<source>Debug</source>
|
<source>Debug</source>
|
||||||
@ -1053,11 +1048,6 @@
|
|||||||
<source>nullGpuCheckBox</source>
|
<source>nullGpuCheckBox</source>
|
||||||
<translation>Włącz Null GPU:\nDla technicznego debugowania dezaktywuje renderowanie gry tak, jakby nie było karty graficznej.</translation>
|
<translation>Włącz Null GPU:\nDla technicznego debugowania dezaktywuje renderowanie gry tak, jakby nie było karty graficznej.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.cpp" line="323"/>
|
|
||||||
<source>dumpPM4CheckBox</source>
|
|
||||||
<translation>Włącz zrzucanie PM4:\nDla technicznego debugowania zapisuje surowe dane instrukcji GPU w folderze, gdy emulator je przetwarza.</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="329"/>
|
<location filename="../settings_dialog.cpp" line="329"/>
|
||||||
<source>debugDump</source>
|
<source>debugDump</source>
|
||||||
@ -1121,6 +1111,11 @@
|
|||||||
<source>Path</source>
|
<source>Path</source>
|
||||||
<translation>Ścieżka</translation>
|
<translation>Ścieżka</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../game_list_frame.cpp" line="38"/>
|
||||||
|
<source>Play Time</source>
|
||||||
|
<translation>Czas gry</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>CheckUpdate</name>
|
<name>CheckUpdate</name>
|
||||||
|
@ -474,11 +474,6 @@
|
|||||||
<source>Enable NULL GPU</source>
|
<source>Enable NULL GPU</source>
|
||||||
<translation>Ativar GPU NULA</translation>
|
<translation>Ativar GPU NULA</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.ui" line="476"/>
|
|
||||||
<source>Enable PM4 Dumping</source>
|
|
||||||
<translation>Ativar Dumping de PM4</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.ui" line="517"/>
|
<location filename="../settings_dialog.ui" line="517"/>
|
||||||
<source>Debug</source>
|
<source>Debug</source>
|
||||||
@ -1053,11 +1048,6 @@
|
|||||||
<source>nullGpuCheckBox</source>
|
<source>nullGpuCheckBox</source>
|
||||||
<translation>Ativar GPU NULA:\nDesativa a renderização do jogo para fins de depuração técnica, como se não houvesse nenhuma placa gráfica.</translation>
|
<translation>Ativar GPU NULA:\nDesativa a renderização do jogo para fins de depuração técnica, como se não houvesse nenhuma placa gráfica.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.cpp" line="323"/>
|
|
||||||
<source>dumpPM4CheckBox</source>
|
|
||||||
<translation>Ativar Dumping de PM4:\nArmazena os dados de instrução bruta da GPU em uma pasta enquanto o emulador os processa, para fins de depuração técnica. Recomendado deixar desativado.</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="329"/>
|
<location filename="../settings_dialog.cpp" line="329"/>
|
||||||
<source>debugDump</source>
|
<source>debugDump</source>
|
||||||
@ -1121,6 +1111,11 @@
|
|||||||
<source>Path</source>
|
<source>Path</source>
|
||||||
<translation>Diretório</translation>
|
<translation>Diretório</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../game_list_frame.cpp" line="38"/>
|
||||||
|
<source>Play Time</source>
|
||||||
|
<translation>Horas Jogadas</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>CheckUpdate</name>
|
<name>CheckUpdate</name>
|
||||||
|
@ -474,11 +474,6 @@
|
|||||||
<source>Enable NULL GPU</source>
|
<source>Enable NULL GPU</source>
|
||||||
<translation>Enable NULL GPU</translation>
|
<translation>Enable NULL GPU</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.ui" line="476"/>
|
|
||||||
<source>Enable PM4 Dumping</source>
|
|
||||||
<translation>Enable PM4 Dumping</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.ui" line="517"/>
|
<location filename="../settings_dialog.ui" line="517"/>
|
||||||
<source>Debug</source>
|
<source>Debug</source>
|
||||||
@ -1053,11 +1048,6 @@
|
|||||||
<source>nullGpuCheckBox</source>
|
<source>nullGpuCheckBox</source>
|
||||||
<translation>Activează GPU Null:\nÎn scopuri de depanare tehnică, dezactivează redarea jocului ca și cum nu ar exista o placă grafică.</translation>
|
<translation>Activează GPU Null:\nÎn scopuri de depanare tehnică, dezactivează redarea jocului ca și cum nu ar exista o placă grafică.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.cpp" line="323"/>
|
|
||||||
<source>dumpPM4CheckBox</source>
|
|
||||||
<translation>Activează salvarea PM4:\nÎn scopuri de depanare tehnică, salvează datele brute ale instrucțiunilor GPU într-un folder pe măsură ce emulatorul le procesează.</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="329"/>
|
<location filename="../settings_dialog.cpp" line="329"/>
|
||||||
<source>debugDump</source>
|
<source>debugDump</source>
|
||||||
@ -1121,6 +1111,11 @@
|
|||||||
<source>Path</source>
|
<source>Path</source>
|
||||||
<translation>Drum</translation>
|
<translation>Drum</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../game_list_frame.cpp" line="38"/>
|
||||||
|
<source>Play Time</source>
|
||||||
|
<translation>Timp de Joacă</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>CheckUpdate</name>
|
<name>CheckUpdate</name>
|
||||||
|
@ -474,11 +474,6 @@
|
|||||||
<source>Enable NULL GPU</source>
|
<source>Enable NULL GPU</source>
|
||||||
<translation>Включить NULL GPU</translation>
|
<translation>Включить NULL GPU</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.ui" line="476"/>
|
|
||||||
<source>Enable PM4 Dumping</source>
|
|
||||||
<translation>Включить дамп PM4</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.ui" line="517"/>
|
<location filename="../settings_dialog.ui" line="517"/>
|
||||||
<source>Debug</source>
|
<source>Debug</source>
|
||||||
@ -1053,11 +1048,6 @@
|
|||||||
<source>nullGpuCheckBox</source>
|
<source>nullGpuCheckBox</source>
|
||||||
<translation>Включить NULL GPU:\nДля технической отладки отключает рендеринг игры так, как будто графической карты нет.</translation>
|
<translation>Включить NULL GPU:\nДля технической отладки отключает рендеринг игры так, как будто графической карты нет.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.cpp" line="323"/>
|
|
||||||
<source>dumpPM4CheckBox</source>
|
|
||||||
<translation>Включить дамп PM4:\nДля технической отладки сохраняет необработанные данные инструкций GPU в папку, пока эмулятор их обрабатывает.</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="329"/>
|
<location filename="../settings_dialog.cpp" line="329"/>
|
||||||
<source>debugDump</source>
|
<source>debugDump</source>
|
||||||
@ -1121,6 +1111,11 @@
|
|||||||
<source>Path</source>
|
<source>Path</source>
|
||||||
<translation>Путь</translation>
|
<translation>Путь</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../game_list_frame.cpp" line="38"/>
|
||||||
|
<source>Play Time</source>
|
||||||
|
<translation>Время Игры</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>CheckUpdate</name>
|
<name>CheckUpdate</name>
|
||||||
|
@ -417,7 +417,7 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.ui" line="155"/>
|
<location filename="../settings_dialog.ui" line="155"/>
|
||||||
<source>Username</source>
|
<source>Username</source>
|
||||||
<translation>Nofka</translation>
|
<translation>Përdoruesi</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.ui" line="178"/>
|
<location filename="../settings_dialog.ui" line="178"/>
|
||||||
@ -474,11 +474,6 @@
|
|||||||
<source>Enable NULL GPU</source>
|
<source>Enable NULL GPU</source>
|
||||||
<translation>Aktivizo GPU-në NULL</translation>
|
<translation>Aktivizo GPU-në NULL</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.ui" line="476"/>
|
|
||||||
<source>Enable PM4 Dumping</source>
|
|
||||||
<translation>Aktivizo Zbrazjen PM4</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.ui" line="517"/>
|
<location filename="../settings_dialog.ui" line="517"/>
|
||||||
<source>Debug</source>
|
<source>Debug</source>
|
||||||
@ -517,7 +512,7 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.ui" line="313"/>
|
<location filename="../settings_dialog.ui" line="313"/>
|
||||||
<source>Update Channel</source>
|
<source>Update Channel</source>
|
||||||
<translation>Kanali i Përditësimit</translation>
|
<translation>Kanali i përditësimit</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.ui" line="322"/>
|
<location filename="../settings_dialog.ui" line="322"/>
|
||||||
@ -527,7 +522,7 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.ui" line="354"/>
|
<location filename="../settings_dialog.ui" line="354"/>
|
||||||
<source>GUI Settings</source>
|
<source>GUI Settings</source>
|
||||||
<translation>Parametrat e GUI</translation>
|
<translation>Cilësimet e GUI</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.ui" line="375"/>
|
<location filename="../settings_dialog.ui" line="375"/>
|
||||||
@ -537,7 +532,7 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.ui" line="394"/>
|
<location filename="../settings_dialog.ui" line="394"/>
|
||||||
<source>Volume</source>
|
<source>Volume</source>
|
||||||
<translation>Volumi</translation>
|
<translation>Vëllimi i zërit</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
@ -976,12 +971,12 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="72"/>
|
<location filename="../settings_dialog.cpp" line="72"/>
|
||||||
<source>Point your mouse at an option to display its description.</source>
|
<source>Point your mouse at an option to display its description.</source>
|
||||||
<translation>Hidhni mouse-in mbi një opsion për të shfaqur përshkrimin e tij.</translation>
|
<translation>Vendos miun mbi një rregullim për të shfaqur përshkrimin e tij.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="289"/>
|
<location filename="../settings_dialog.cpp" line="289"/>
|
||||||
<source>consoleLanguageGroupBox</source>
|
<source>consoleLanguageGroupBox</source>
|
||||||
<translation>Gjuha e konsolës:\nPërcakton gjuhën që përdor loja PS4.\nRrekomandohet të vendosni këtë në një gjuhë që loja mbështet, e cila do të ndryshojë sipas rajonit.</translation>
|
<translation>Gjuha e konsolës:\nPërcakton gjuhën që përdor loja PS4.\nKëshillohet të caktosh një gjuhë që loja mbështet, e cila do të ndryshojë sipas rajonit.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="291"/>
|
<location filename="../settings_dialog.cpp" line="291"/>
|
||||||
@ -991,17 +986,17 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="293"/>
|
<location filename="../settings_dialog.cpp" line="293"/>
|
||||||
<source>fullscreenCheckBox</source>
|
<source>fullscreenCheckBox</source>
|
||||||
<translation>Aktivizo ekranin e plotë:\nAutomatikisht vendos dritaren e lojës në modalitetin e ekranit të plotë.\nKjo mund të aktivizohet duke shtypur çelësin F11.</translation>
|
<translation>Aktivizo ekranin e plotë:\nVendos automatikisht dritaren e lojës në mënyrën e ekranit të plotë.\nKjo mund të aktivizohet duke shtypur tastin F11.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="295"/>
|
<location filename="../settings_dialog.cpp" line="295"/>
|
||||||
<source>showSplashCheckBox</source>
|
<source>showSplashCheckBox</source>
|
||||||
<translation>Shfaq ekranin e ngarkesës:\nShfaq ekranin e ngarkesës së lojës (një imazh special) gjatë fillimit të lojës.</translation>
|
<translation>Shfaq ekranin e ngarkesës:\nShfaq ekranin e ngarkesës së lojës (një pamje e veçantë) gjatë fillimit të lojës.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="297"/>
|
<location filename="../settings_dialog.cpp" line="297"/>
|
||||||
<source>ps4proCheckBox</source>
|
<source>ps4proCheckBox</source>
|
||||||
<translation>Është PS4 Pro:\nBën që emulatori të veprojë si një PS4 PRO, i cili mund të aktivizojë karakteristika speciale në lojrat që e mbështesin atë.</translation>
|
<translation>Është PS4 Pro:\nBën që emulatori të veprojë si një PS4 PRO, gjë që mund të aktivizojë veçori të veçanta në lojrat që e mbështesin.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="299"/>
|
<location filename="../settings_dialog.cpp" line="299"/>
|
||||||
@ -1011,27 +1006,27 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="301"/>
|
<location filename="../settings_dialog.cpp" line="301"/>
|
||||||
<source>logTypeGroupBox</source>
|
<source>logTypeGroupBox</source>
|
||||||
<translation>Tipi i logut:\nPërcakton nëse të sinkronizoni daljen e dritares së logut për performancën. Mund të ketë efekte të këqija në emulim.</translation>
|
<translation>Lloji i ditarit:\nPërcakton nëse të sinkronizohet dalja e dritares së ditarit për performancë. Mund të ketë efekte të këqija në emulim.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="303"/>
|
<location filename="../settings_dialog.cpp" line="303"/>
|
||||||
<source>logFilter</source>
|
<source>logFilter</source>
|
||||||
<translation>Filtri i logut: Filtron logun për të printuar vetëm informacione specifike. Shembuj: "Core:Trace" "Lib.Pad:Debug Common.Filesystem:Error" "*:Critical" Nivelet: Trace, Debug, Info, Warning, Error, Critical - në këtë rend, një nivel specifik hesht të gjitha nivelet përpara në listë dhe regjistron çdo nivel pas saj.</translation>
|
<translation>Filtri i ditarit: Filtron ditarin për të shfaqur vetëm informacione specifike. Shembuj: "Core:Trace" "Lib.Pad:Debug Common.Filesystem:Error" "*:Critical" Nivelet: Trace, Debug, Info, Warning, Error, Critical - në këtë rend, një nivel specifik hesht të gjitha nivelet përpara në listë dhe regjistron çdo nivel pas atij.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="305"/>
|
<location filename="../settings_dialog.cpp" line="305"/>
|
||||||
<source>updaterGroupBox</source>
|
<source>updaterGroupBox</source>
|
||||||
<translation>Aktualizimi:\nRelease: Versionet zyrtare të lëshuara çdo muaj që mund të jenë shumë të vjetra, por janë më të besueshme dhe të testuara.\nNightly: Versionet e zhvillimit që kanë të gjitha veçoritë dhe rregullimet më të fundit, por mund të përmbajnë gabime dhe janë më pak të qëndrueshme.</translation>
|
<translation>Aktualizimi:\nRelease: Versionet zyrtare të lëshuara çdo muaj që mund të jenë shumë të vjetra, por janë më të besueshme dhe të provuara.\nNightly: Versionet e zhvillimit që kanë të gjitha veçoritë dhe rregullimet më të fundit, por mund të përmbajnë gabime dhe janë më pak të qëndrueshme.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="306"/>
|
<location filename="../settings_dialog.cpp" line="306"/>
|
||||||
<source>GUIgroupBox</source>
|
<source>GUIgroupBox</source>
|
||||||
<translation>Lojë muzikë titulli:\nNëse një lojë e mbështet, aktivizoja luajtjen e muzikës speciale kur të zgjidhni lojën në GUI.</translation>
|
<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>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="312"/>
|
<location filename="../settings_dialog.cpp" line="312"/>
|
||||||
<source>graphicsAdapterGroupBox</source>
|
<source>graphicsAdapterGroupBox</source>
|
||||||
<translation>Dispositivi grafik:\nNë sistemet me GPU të shumëfishta, zgjidhni GPU-në që do të përdorë emulatori nga lista e rënies,\nor zgjidhni "Auto Select" për ta përcaktuar automatikisht.</translation>
|
<translation>Pajisja grafike:\nNë sistemet me GPU të shumëfishta, zgjidh GPU-në që do të përdorë emulatori nga lista rënëse,\nose zgjidh "Auto Select" për ta përcaktuar automatikisht.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="314"/>
|
<location filename="../settings_dialog.cpp" line="314"/>
|
||||||
@ -1041,42 +1036,37 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="318"/>
|
<location filename="../settings_dialog.cpp" line="318"/>
|
||||||
<source>heightDivider</source>
|
<source>heightDivider</source>
|
||||||
<translation>Pjesëtari Vblank:\nShpejtësia e kuadrit me të cilën refreshohet emulatori është shumëzuar me këtë numër. Ndryshimi i këtij mund të ketë efekte të këqija, si rritja e shpejtësisë së lojës ose shkatërrimi i funksionalitetit kritik të lojës që nuk e pret këtë të ndryshojë!</translation>
|
<translation>Ndarësi Vblank:\nFrekuenca pamore me të cilën rifreskohet emulatori shumëzohet me këtë numër. Ndryshimi i këtij mund të ketë efekte të këqija, si rritja e shpejtësisë së lojës ose prishja e punimit thelbësor të lojës që nuk e pret këtë ndryshim!</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="320"/>
|
<location filename="../settings_dialog.cpp" line="320"/>
|
||||||
<source>dumpShadersCheckBox</source>
|
<source>dumpShadersCheckBox</source>
|
||||||
<translation>Aktivizo dump-in e shaders:\nPër qëllime të debugimit teknik, ruan shaders e lojës në një folder ndërsa ato renditen.</translation>
|
<translation>Aktivizo zbrazjen e shaders-ave:\nPër qëllime të korrigjimit teknik, ruan shaders-at e lojës në një dosje ndërsa ato pasqyrohen.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="322"/>
|
<location filename="../settings_dialog.cpp" line="322"/>
|
||||||
<source>nullGpuCheckBox</source>
|
<source>nullGpuCheckBox</source>
|
||||||
<translation>Aktivizo GPU Null:\nPër qëllime të debugimit teknik, deaktivizon renditjen e lojës sikur nuk do të kishte një kartë grafike.</translation>
|
<translation>Aktivizo GPU-në Null:\nPër qëllime të korrigjimit teknik, çaktivizon pasqyrimin e lojës sikur nuk ka një kartë grafike.</translation>
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.cpp" line="323"/>
|
|
||||||
<source>dumpPM4CheckBox</source>
|
|
||||||
<translation>Aktivizo dump-in e PM4:\nPër qëllime të debugimit teknik, ruan të dhënat e instruksioneve të GPU-së në një folder ndërsa emulatori i përpunon ato.</translation>
|
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="329"/>
|
<location filename="../settings_dialog.cpp" line="329"/>
|
||||||
<source>debugDump</source>
|
<source>debugDump</source>
|
||||||
<translation>Aktivizo dump-in e debugimit:\nRuani simbolet e importit dhe eksportit dhe informacionin e titullit të skedarit për aplikacionin aktual PS4 që po punon në një katalog.</translation>
|
<translation>Aktivizo zbrazjen për korrigjim:\nRuan simbolet e importit dhe eksportit dhe informacionin e kreut të skedarit për aplikacionin PS4 që po ekzekutohet në një dosje.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="331"/>
|
<location filename="../settings_dialog.cpp" line="331"/>
|
||||||
<source>vkValidationCheckBox</source>
|
<source>vkValidationCheckBox</source>
|
||||||
<translation>Aktivizo stratet e validimit Vulkan:\nAktivizon një sistem që validon gjendjen e renderizuesit Vulkan dhe regjistron informacionin në lidhje me gjendjen e tij të brendshme. Kjo do të ulet performancën dhe ndoshta do të ndryshojë sjelljen e emulimit.</translation>
|
<translation>Aktivizo shtresat e vlefshmërisë Vulkan:\nAktivizon një sistem që vërteton gjendjen e pasqyruesit Vulkan dhe regjistron informacionin në lidhje me gjendjen e tij të brendshme. Kjo do të ul performancën dhe ndoshta do të ndryshojë sjelljen e emulimit.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="333"/>
|
<location filename="../settings_dialog.cpp" line="333"/>
|
||||||
<source>vkSyncValidationCheckBox</source>
|
<source>vkSyncValidationCheckBox</source>
|
||||||
<translation>Aktivizo validimin e sinkronizimit Vulkan:\nAktivizon një sistem që validon kohën e detyrave të renderizimit Vulkan. Kjo do të ulet performancën dhe ndoshta do të ndryshojë sjelljen e emulimit.</translation>
|
<translation>Aktivizo vërtetimin e sinkronizimit Vulkan:\nAktivizon një sistem që vërteton kohën e detyrave të pasqyrimit Vulkan. Kjo do të ul performancën dhe ndoshta do të ndryshojë sjelljen e emulimit.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="335"/>
|
<location filename="../settings_dialog.cpp" line="335"/>
|
||||||
<source>rdocCheckBox</source>
|
<source>rdocCheckBox</source>
|
||||||
<translation>Aktivizo debugimin RenderDoc:\nNëse aktivizohet, emulatori do të ofrojë pajtueshmëri me Renderdoc për të lejuar kapjen dhe analizën e kornizës aktuale të renderizuar.</translation>
|
<translation>Aktivizo korrigjimin RenderDoc:\nNëse aktivizohet, emulatori do të ofrojë pajtueshmëri me Renderdoc për të lejuar kapjen dhe analizën e pamjes të pasqyruar në moment.</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
@ -1121,6 +1111,11 @@
|
|||||||
<source>Path</source>
|
<source>Path</source>
|
||||||
<translation>Shtegu</translation>
|
<translation>Shtegu</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../game_list_frame.cpp" line="38"/>
|
||||||
|
<source>Play Time</source>
|
||||||
|
<translation>Kohë Lojë</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>CheckUpdate</name>
|
<name>CheckUpdate</name>
|
||||||
@ -1172,7 +1167,7 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../check_update.cpp" line="187"/>
|
<location filename="../check_update.cpp" line="187"/>
|
||||||
<source>Update Channel</source>
|
<source>Update Channel</source>
|
||||||
<translation>Kanali i Përditësimit</translation>
|
<translation>Kanali i përditësimit</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../check_update.cpp" line="177"/>
|
<location filename="../check_update.cpp" line="177"/>
|
||||||
|
@ -474,11 +474,6 @@
|
|||||||
<source>Enable NULL GPU</source>
|
<source>Enable NULL GPU</source>
|
||||||
<translation>NULL GPU'yu Etkinleştir</translation>
|
<translation>NULL GPU'yu Etkinleştir</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.ui" line="476"/>
|
|
||||||
<source>Enable PM4 Dumping</source>
|
|
||||||
<translation>PM4 Kaydını Etkinleştir</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.ui" line="517"/>
|
<location filename="../settings_dialog.ui" line="517"/>
|
||||||
<source>Debug</source>
|
<source>Debug</source>
|
||||||
@ -1053,11 +1048,6 @@
|
|||||||
<source>nullGpuCheckBox</source>
|
<source>nullGpuCheckBox</source>
|
||||||
<translation>Null GPU'yu Etkinleştir:\nTeknik hata ayıklama amacıyla, oyunun render edilmesini grafik kartı yokmuş gibi devre dışı bırakır.</translation>
|
<translation>Null GPU'yu Etkinleştir:\nTeknik hata ayıklama amacıyla, oyunun render edilmesini grafik kartı yokmuş gibi devre dışı bırakır.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.cpp" line="323"/>
|
|
||||||
<source>dumpPM4CheckBox</source>
|
|
||||||
<translation>PM4 Dışa Aktarmayı Etkinleştir:\nTeknik hata ayıklama amacıyla, emülatör bunları işlerken GPU komut verilerini bir klasöre kaydeder.</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="329"/>
|
<location filename="../settings_dialog.cpp" line="329"/>
|
||||||
<source>debugDump</source>
|
<source>debugDump</source>
|
||||||
@ -1121,6 +1111,11 @@
|
|||||||
<source>Path</source>
|
<source>Path</source>
|
||||||
<translation>Yol</translation>
|
<translation>Yol</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../game_list_frame.cpp" line="38"/>
|
||||||
|
<source>Play Time</source>
|
||||||
|
<translation>Oynama Süresi</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>CheckUpdate</name>
|
<name>CheckUpdate</name>
|
||||||
|
@ -474,11 +474,6 @@
|
|||||||
<source>Enable NULL GPU</source>
|
<source>Enable NULL GPU</source>
|
||||||
<translation>Enable NULL GPU</translation>
|
<translation>Enable NULL GPU</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.ui" line="476"/>
|
|
||||||
<source>Enable PM4 Dumping</source>
|
|
||||||
<translation>Enable PM4 Dumping</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.ui" line="517"/>
|
<location filename="../settings_dialog.ui" line="517"/>
|
||||||
<source>Debug</source>
|
<source>Debug</source>
|
||||||
@ -1053,11 +1048,6 @@
|
|||||||
<source>nullGpuCheckBox</source>
|
<source>nullGpuCheckBox</source>
|
||||||
<translation>Bật GPU Null:\nĐể mục đích gỡ lỗi kỹ thuật, vô hiệu hóa việc kết xuất trò chơi như thể không có card đồ họa.</translation>
|
<translation>Bật GPU Null:\nĐể mục đích gỡ lỗi kỹ thuật, vô hiệu hóa việc kết xuất trò chơi như thể không có card đồ họa.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.cpp" line="323"/>
|
|
||||||
<source>dumpPM4CheckBox</source>
|
|
||||||
<translation>Bật xuất PM4:\nĐể mục đích gỡ lỗi kỹ thuật, lưu dữ liệu lệnh GPU vào một thư mục khi trình giả lập xử lý chúng.</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="329"/>
|
<location filename="../settings_dialog.cpp" line="329"/>
|
||||||
<source>debugDump</source>
|
<source>debugDump</source>
|
||||||
@ -1121,6 +1111,11 @@
|
|||||||
<source>Path</source>
|
<source>Path</source>
|
||||||
<translation>Đường dẫn</translation>
|
<translation>Đường dẫn</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../game_list_frame.cpp" line="38"/>
|
||||||
|
<source>Play Time</source>
|
||||||
|
<translation>Thời gian chơi</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>CheckUpdate</name>
|
<name>CheckUpdate</name>
|
||||||
|
@ -474,11 +474,6 @@
|
|||||||
<source>Enable NULL GPU</source>
|
<source>Enable NULL GPU</source>
|
||||||
<translation>启用 NULL GPU</translation>
|
<translation>启用 NULL GPU</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.ui" line="476"/>
|
|
||||||
<source>Enable PM4 Dumping</source>
|
|
||||||
<translation>启用 PM4 转储</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.ui" line="517"/>
|
<location filename="../settings_dialog.ui" line="517"/>
|
||||||
<source>Debug</source>
|
<source>Debug</source>
|
||||||
@ -1053,11 +1048,6 @@
|
|||||||
<source>nullGpuCheckBox</source>
|
<source>nullGpuCheckBox</source>
|
||||||
<translation>启用空 GPU:\n为了技术调试,将游戏渲染禁用,仿佛没有图形卡。</translation>
|
<translation>启用空 GPU:\n为了技术调试,将游戏渲染禁用,仿佛没有图形卡。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.cpp" line="323"/>
|
|
||||||
<source>dumpPM4CheckBox</source>
|
|
||||||
<translation>启用 PM4 转储:\n为了技术调试,在模拟器处理时将原始 GPU 指令数据保存到文件夹中。</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="329"/>
|
<location filename="../settings_dialog.cpp" line="329"/>
|
||||||
<source>debugDump</source>
|
<source>debugDump</source>
|
||||||
@ -1121,6 +1111,11 @@
|
|||||||
<source>Path</source>
|
<source>Path</source>
|
||||||
<translation>路径</translation>
|
<translation>路径</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../game_list_frame.cpp" line="38"/>
|
||||||
|
<source>Play Time</source>
|
||||||
|
<translation>游戏时间</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>CheckUpdate</name>
|
<name>CheckUpdate</name>
|
||||||
|
@ -474,11 +474,6 @@
|
|||||||
<source>Enable NULL GPU</source>
|
<source>Enable NULL GPU</source>
|
||||||
<translation>Enable NULL GPU</translation>
|
<translation>Enable NULL GPU</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.ui" line="476"/>
|
|
||||||
<source>Enable PM4 Dumping</source>
|
|
||||||
<translation>Enable PM4 Dumping</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.ui" line="517"/>
|
<location filename="../settings_dialog.ui" line="517"/>
|
||||||
<source>Debug</source>
|
<source>Debug</source>
|
||||||
@ -1053,11 +1048,6 @@
|
|||||||
<source>nullGpuCheckBox</source>
|
<source>nullGpuCheckBox</source>
|
||||||
<translation>啟用空GPU:\n為了技術調試,禁用遊戲渲染,彷彿沒有顯示卡。</translation>
|
<translation>啟用空GPU:\n為了技術調試,禁用遊戲渲染,彷彿沒有顯示卡。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../settings_dialog.cpp" line="323"/>
|
|
||||||
<source>dumpPM4CheckBox</source>
|
|
||||||
<translation>啟用PM4轉儲:\n為了技術調試,將原始GPU指令數據在模擬器處理時保存到文件夾中。</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<location filename="../settings_dialog.cpp" line="329"/>
|
<location filename="../settings_dialog.cpp" line="329"/>
|
||||||
<source>debugDump</source>
|
<source>debugDump</source>
|
||||||
@ -1121,6 +1111,11 @@
|
|||||||
<source>Path</source>
|
<source>Path</source>
|
||||||
<translation>路徑</translation>
|
<translation>路徑</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../game_list_frame.cpp" line="38"/>
|
||||||
|
<source>Play Time</source>
|
||||||
|
<translation>遊玩時間</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>CheckUpdate</name>
|
<name>CheckUpdate</name>
|
||||||
|
@ -145,6 +145,7 @@ void WindowSDL::onKeyPress(const SDL_Event* event) {
|
|||||||
Input::Axis axis = Input::Axis::AxisMax;
|
Input::Axis axis = Input::Axis::AxisMax;
|
||||||
int axisvalue = 0;
|
int axisvalue = 0;
|
||||||
int ax = 0;
|
int ax = 0;
|
||||||
|
std::string backButtonBehavior = Config::getBackButtonBehavior();
|
||||||
switch (event->key.key) {
|
switch (event->key.key) {
|
||||||
case SDLK_UP:
|
case SDLK_UP:
|
||||||
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_UP;
|
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_UP;
|
||||||
@ -278,7 +279,15 @@ void WindowSDL::onKeyPress(const SDL_Event* event) {
|
|||||||
ax = Input::GetAxis(0, 0x80, axisvalue);
|
ax = Input::GetAxis(0, 0x80, axisvalue);
|
||||||
break;
|
break;
|
||||||
case SDLK_SPACE:
|
case SDLK_SPACE:
|
||||||
|
if (backButtonBehavior != "none") {
|
||||||
|
float x = backButtonBehavior == "left" ? 0.25f
|
||||||
|
: (backButtonBehavior == "right" ? 0.75f : 0.5f);
|
||||||
|
// trigger a touchpad event so that the touchpad emulation for back button works
|
||||||
|
controller->SetTouchpadState(0, true, x, 0.5f);
|
||||||
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD;
|
button = OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD;
|
||||||
|
} else {
|
||||||
|
button = 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case SDLK_F11:
|
case SDLK_F11:
|
||||||
if (event->type == SDL_EVENT_KEY_DOWN) {
|
if (event->type == SDL_EVENT_KEY_DOWN) {
|
||||||
@ -304,9 +313,6 @@ void WindowSDL::onKeyPress(const SDL_Event* event) {
|
|||||||
if (axis != Input::Axis::AxisMax) {
|
if (axis != Input::Axis::AxisMax) {
|
||||||
controller->Axis(0, axis, ax);
|
controller->Axis(0, axis, ax);
|
||||||
}
|
}
|
||||||
if (SDL_GetCursor() != NULL) {
|
|
||||||
SDL_HideCursor();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowSDL::onGamepadEvent(const SDL_Event* event) {
|
void WindowSDL::onGamepadEvent(const SDL_Event* event) {
|
||||||
@ -330,10 +336,20 @@ void WindowSDL::onGamepadEvent(const SDL_Event* event) {
|
|||||||
case SDL_EVENT_GAMEPAD_BUTTON_UP:
|
case SDL_EVENT_GAMEPAD_BUTTON_UP:
|
||||||
button = sdlGamepadToOrbisButton(event->gbutton.button);
|
button = sdlGamepadToOrbisButton(event->gbutton.button);
|
||||||
if (button != 0) {
|
if (button != 0) {
|
||||||
|
if (event->gbutton.button == SDL_GAMEPAD_BUTTON_BACK) {
|
||||||
|
std::string backButtonBehavior = Config::getBackButtonBehavior();
|
||||||
|
if (backButtonBehavior != "none") {
|
||||||
|
float x = backButtonBehavior == "left"
|
||||||
|
? 0.25f
|
||||||
|
: (backButtonBehavior == "right" ? 0.75f : 0.5f);
|
||||||
|
// trigger a touchpad event so that the touchpad emulation for back button works
|
||||||
|
controller->SetTouchpadState(0, true, x, 0.5f);
|
||||||
|
controller->CheckButton(0, button,
|
||||||
|
event->type == SDL_EVENT_GAMEPAD_BUTTON_DOWN);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
controller->CheckButton(0, button, event->type == SDL_EVENT_GAMEPAD_BUTTON_DOWN);
|
controller->CheckButton(0, button, event->type == SDL_EVENT_GAMEPAD_BUTTON_DOWN);
|
||||||
}
|
}
|
||||||
if (SDL_GetCursor() != NULL) {
|
|
||||||
SDL_HideCursor();
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SDL_EVENT_GAMEPAD_AXIS_MOTION:
|
case SDL_EVENT_GAMEPAD_AXIS_MOTION:
|
||||||
|
@ -27,8 +27,10 @@ static constexpr spv::ExecutionMode GetInputPrimitiveType(AmdGpu::PrimitiveType
|
|||||||
case AmdGpu::PrimitiveType::TriangleList:
|
case AmdGpu::PrimitiveType::TriangleList:
|
||||||
case AmdGpu::PrimitiveType::TriangleStrip:
|
case AmdGpu::PrimitiveType::TriangleStrip:
|
||||||
return spv::ExecutionMode::Triangles;
|
return spv::ExecutionMode::Triangles;
|
||||||
|
case AmdGpu::PrimitiveType::AdjTriangleList:
|
||||||
|
return spv::ExecutionMode::InputTrianglesAdjacency;
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE_MSG("Unknown input primitive type {}", u32(type));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,7 +43,7 @@ static constexpr spv::ExecutionMode GetOutputPrimitiveType(AmdGpu::GsOutputPrimi
|
|||||||
case AmdGpu::GsOutputPrimitiveType::TriangleStrip:
|
case AmdGpu::GsOutputPrimitiveType::TriangleStrip:
|
||||||
return spv::ExecutionMode::OutputTriangleStrip;
|
return spv::ExecutionMode::OutputTriangleStrip;
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE_MSG("Unknown output primitive type {}", u32(type));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,6 +70,8 @@ ArgType Arg(EmitContext& ctx, const IR::Value& arg) {
|
|||||||
return arg.ScalarReg();
|
return arg.ScalarReg();
|
||||||
} else if constexpr (std::is_same_v<ArgType, IR::VectorReg>) {
|
} else if constexpr (std::is_same_v<ArgType, IR::VectorReg>) {
|
||||||
return arg.VectorReg();
|
return arg.VectorReg();
|
||||||
|
} else if constexpr (std::is_same_v<ArgType, const char*>) {
|
||||||
|
return arg.StringLiteral();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,10 +206,7 @@ Id DefineMain(EmitContext& ctx, const IR::Program& program) {
|
|||||||
return main;
|
return main;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DefineEntryPoint(const IR::Program& program, EmitContext& ctx, Id main) {
|
void SetupCapabilities(const Info& info, EmitContext& ctx) {
|
||||||
const auto& info = program.info;
|
|
||||||
const std::span interfaces(ctx.interfaces.data(), ctx.interfaces.size());
|
|
||||||
spv::ExecutionModel execution_model{};
|
|
||||||
ctx.AddCapability(spv::Capability::Image1D);
|
ctx.AddCapability(spv::Capability::Image1D);
|
||||||
ctx.AddCapability(spv::Capability::Sampled1D);
|
ctx.AddCapability(spv::Capability::Sampled1D);
|
||||||
ctx.AddCapability(spv::Capability::ImageQuery);
|
ctx.AddCapability(spv::Capability::ImageQuery);
|
||||||
@ -243,6 +244,19 @@ void DefineEntryPoint(const IR::Program& program, EmitContext& ctx, Id main) {
|
|||||||
if (info.uses_group_ballot) {
|
if (info.uses_group_ballot) {
|
||||||
ctx.AddCapability(spv::Capability::GroupNonUniformBallot);
|
ctx.AddCapability(spv::Capability::GroupNonUniformBallot);
|
||||||
}
|
}
|
||||||
|
if (info.stage == Stage::Export || info.stage == Stage::Vertex) {
|
||||||
|
ctx.AddExtension("SPV_KHR_shader_draw_parameters");
|
||||||
|
ctx.AddCapability(spv::Capability::DrawParameters);
|
||||||
|
}
|
||||||
|
if (info.stage == Stage::Geometry) {
|
||||||
|
ctx.AddCapability(spv::Capability::Geometry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DefineEntryPoint(const IR::Program& program, EmitContext& ctx, Id main) {
|
||||||
|
const auto& info = program.info;
|
||||||
|
const std::span interfaces(ctx.interfaces.data(), ctx.interfaces.size());
|
||||||
|
spv::ExecutionModel execution_model{};
|
||||||
switch (program.info.stage) {
|
switch (program.info.stage) {
|
||||||
case Stage::Compute: {
|
case Stage::Compute: {
|
||||||
const std::array<u32, 3> workgroup_size{ctx.runtime_info.cs_info.workgroup_size};
|
const std::array<u32, 3> workgroup_size{ctx.runtime_info.cs_info.workgroup_size};
|
||||||
@ -286,6 +300,24 @@ void DefineEntryPoint(const IR::Program& program, EmitContext& ctx, Id main) {
|
|||||||
ctx.AddEntryPoint(execution_model, main, "main", interfaces);
|
ctx.AddEntryPoint(execution_model, main, "main", interfaces);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetupFloatMode(EmitContext& ctx, const Profile& profile, const RuntimeInfo& runtime_info,
|
||||||
|
Id main_func) {
|
||||||
|
ctx.AddExtension("SPV_KHR_float_controls");
|
||||||
|
const auto fp_denorm_mode = runtime_info.fp_denorm_mode32;
|
||||||
|
if (fp_denorm_mode == AmdGpu::FpDenormMode::InOutFlush) {
|
||||||
|
if (profile.support_fp32_denorm_flush) {
|
||||||
|
ctx.AddCapability(spv::Capability::DenormFlushToZero);
|
||||||
|
ctx.AddExecutionMode(main_func, spv::ExecutionMode::DenormFlushToZero, 32U);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG_WARNING(Render_Vulkan, "Unknown FP denorm mode {}", u32(fp_denorm_mode));
|
||||||
|
}
|
||||||
|
const auto fp_round_mode = runtime_info.fp_round_mode32;
|
||||||
|
if (fp_round_mode != AmdGpu::FpRoundMode::NearestEven) {
|
||||||
|
LOG_WARNING(Render_Vulkan, "Unknown FP rounding mode {}", u32(fp_round_mode));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void PatchPhiNodes(const IR::Program& program, EmitContext& ctx) {
|
void PatchPhiNodes(const IR::Program& program, EmitContext& ctx) {
|
||||||
auto inst{program.blocks.front()->begin()};
|
auto inst{program.blocks.front()->begin()};
|
||||||
size_t block_index{0};
|
size_t block_index{0};
|
||||||
@ -310,18 +342,8 @@ std::vector<u32> EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_in
|
|||||||
EmitContext ctx{profile, runtime_info, program.info, binding};
|
EmitContext ctx{profile, runtime_info, program.info, binding};
|
||||||
const Id main{DefineMain(ctx, program)};
|
const Id main{DefineMain(ctx, program)};
|
||||||
DefineEntryPoint(program, ctx, main);
|
DefineEntryPoint(program, ctx, main);
|
||||||
switch (program.info.stage) {
|
SetupCapabilities(program.info, ctx);
|
||||||
case Stage::Export:
|
SetupFloatMode(ctx, profile, runtime_info, main);
|
||||||
case Stage::Vertex:
|
|
||||||
ctx.AddExtension("SPV_KHR_shader_draw_parameters");
|
|
||||||
ctx.AddCapability(spv::Capability::DrawParameters);
|
|
||||||
break;
|
|
||||||
case Stage::Geometry:
|
|
||||||
ctx.AddCapability(spv::Capability::Geometry);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
PatchPhiNodes(program, ctx);
|
PatchPhiNodes(program, ctx);
|
||||||
binding.user_data += program.info.ud_mask.NumRegs();
|
binding.user_data += program.info.ud_mask.NumRegs();
|
||||||
return ctx.Assemble();
|
return ctx.Assemble();
|
||||||
|
@ -59,19 +59,22 @@ struct ImageOperands {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddDerivatives(EmitContext& ctx, Id derivatives) {
|
void AddDerivatives(EmitContext& ctx, Id derivatives_dx, Id derivatives_dy) {
|
||||||
if (!Sirit::ValidId(derivatives)) {
|
if (!Sirit::ValidId(derivatives_dx) || !Sirit::ValidId(derivatives_dy)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const Id dx{ctx.OpVectorShuffle(ctx.F32[2], derivatives, derivatives, 0, 1)};
|
Add(spv::ImageOperandsMask::Grad, derivatives_dx, derivatives_dy);
|
||||||
const Id dy{ctx.OpVectorShuffle(ctx.F32[2], derivatives, derivatives, 2, 3)};
|
|
||||||
Add(spv::ImageOperandsMask::Grad, dx, dy);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
spv::ImageOperandsMask mask{};
|
spv::ImageOperandsMask mask{};
|
||||||
boost::container::static_vector<Id, 4> operands;
|
boost::container::static_vector<Id, 4> operands;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Id EmitImageSampleRaw(EmitContext& ctx, IR::Inst* inst, u32 handle, Id address1, Id address2,
|
||||||
|
Id address3, Id address4) {
|
||||||
|
UNREACHABLE_MSG("Unreachable instruction");
|
||||||
|
}
|
||||||
|
|
||||||
Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id bias,
|
Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id bias,
|
||||||
const IR::Value& offset) {
|
const IR::Value& offset) {
|
||||||
const auto& texture = ctx.images[handle & 0xFFFF];
|
const auto& texture = ctx.images[handle & 0xFFFF];
|
||||||
@ -114,7 +117,9 @@ Id EmitImageSampleDrefImplicitLod(EmitContext& ctx, IR::Inst* inst, u32 handle,
|
|||||||
operands.AddOffset(ctx, offset);
|
operands.AddOffset(ctx, offset);
|
||||||
const Id sample = ctx.OpImageSampleDrefImplicitLod(result_type, sampled_image, coords, dref,
|
const Id sample = ctx.OpImageSampleDrefImplicitLod(result_type, sampled_image, coords, dref,
|
||||||
operands.mask, operands.operands);
|
operands.mask, operands.operands);
|
||||||
return texture.is_integer ? ctx.OpBitcast(ctx.F32[1], sample) : sample;
|
const Id sample_typed = texture.is_integer ? ctx.OpBitcast(ctx.F32[1], sample) : sample;
|
||||||
|
return ctx.OpCompositeConstruct(ctx.F32[4], sample_typed, ctx.f32_zero_value,
|
||||||
|
ctx.f32_zero_value, ctx.f32_zero_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitImageSampleDrefExplicitLod(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id dref,
|
Id EmitImageSampleDrefExplicitLod(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id dref,
|
||||||
@ -129,7 +134,9 @@ Id EmitImageSampleDrefExplicitLod(EmitContext& ctx, IR::Inst* inst, u32 handle,
|
|||||||
operands.Add(spv::ImageOperandsMask::Lod, lod);
|
operands.Add(spv::ImageOperandsMask::Lod, lod);
|
||||||
const Id sample = ctx.OpImageSampleDrefExplicitLod(result_type, sampled_image, coords, dref,
|
const Id sample = ctx.OpImageSampleDrefExplicitLod(result_type, sampled_image, coords, dref,
|
||||||
operands.mask, operands.operands);
|
operands.mask, operands.operands);
|
||||||
return texture.is_integer ? ctx.OpBitcast(ctx.F32[1], sample) : sample;
|
const Id sample_typed = texture.is_integer ? ctx.OpBitcast(ctx.F32[1], sample) : sample;
|
||||||
|
return ctx.OpCompositeConstruct(ctx.F32[4], sample_typed, ctx.f32_zero_value,
|
||||||
|
ctx.f32_zero_value, ctx.f32_zero_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitImageGather(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords,
|
Id EmitImageGather(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords,
|
||||||
@ -212,15 +219,15 @@ Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords) {
|
|||||||
return ctx.OpImageQueryLod(ctx.F32[2], sampled_image, coords);
|
return ctx.OpImageQueryLod(ctx.F32[2], sampled_image, coords);
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id derivatives,
|
Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id derivatives_dx,
|
||||||
const IR::Value& offset, Id lod_clamp) {
|
Id derivatives_dy, const IR::Value& offset, const IR::Value& lod_clamp) {
|
||||||
const auto& texture = ctx.images[handle & 0xFFFF];
|
const auto& texture = ctx.images[handle & 0xFFFF];
|
||||||
const Id image = ctx.OpLoad(texture.image_type, texture.id);
|
const Id image = ctx.OpLoad(texture.image_type, texture.id);
|
||||||
const Id result_type = texture.data_types->Get(4);
|
const Id result_type = texture.data_types->Get(4);
|
||||||
const Id sampler = ctx.OpLoad(ctx.sampler_type, ctx.samplers[handle >> 16]);
|
const Id sampler = ctx.OpLoad(ctx.sampler_type, ctx.samplers[handle >> 16]);
|
||||||
const Id sampled_image = ctx.OpSampledImage(texture.sampled_type, image, sampler);
|
const Id sampled_image = ctx.OpSampledImage(texture.sampled_type, image, sampler);
|
||||||
ImageOperands operands;
|
ImageOperands operands;
|
||||||
operands.AddDerivatives(ctx, derivatives);
|
operands.AddDerivatives(ctx, derivatives_dx, derivatives_dy);
|
||||||
operands.AddOffset(ctx, offset);
|
operands.AddOffset(ctx, offset);
|
||||||
const Id sample = ctx.OpImageSampleExplicitLod(result_type, sampled_image, coords,
|
const Id sample = ctx.OpImageSampleExplicitLod(result_type, sampled_image, coords,
|
||||||
operands.mask, operands.operands);
|
operands.mask, operands.operands);
|
||||||
|
@ -48,6 +48,7 @@ void EmitPrologue(EmitContext& ctx);
|
|||||||
void EmitEpilogue(EmitContext& ctx);
|
void EmitEpilogue(EmitContext& ctx);
|
||||||
void EmitDiscard(EmitContext& ctx);
|
void EmitDiscard(EmitContext& ctx);
|
||||||
void EmitDiscardCond(EmitContext& ctx, Id condition);
|
void EmitDiscardCond(EmitContext& ctx, Id condition);
|
||||||
|
void EmitDebugPrint(EmitContext& ctx, IR::Inst* inst, Id arg0, Id arg1, Id arg2, Id arg3, Id arg4);
|
||||||
void EmitBarrier(EmitContext& ctx);
|
void EmitBarrier(EmitContext& ctx);
|
||||||
void EmitWorkgroupMemoryBarrier(EmitContext& ctx);
|
void EmitWorkgroupMemoryBarrier(EmitContext& ctx);
|
||||||
void EmitDeviceMemoryBarrier(EmitContext& ctx);
|
void EmitDeviceMemoryBarrier(EmitContext& ctx);
|
||||||
@ -367,6 +368,8 @@ Id EmitConvertF64U64(EmitContext& ctx, Id value);
|
|||||||
Id EmitConvertU16U32(EmitContext& ctx, Id value);
|
Id EmitConvertU16U32(EmitContext& ctx, Id value);
|
||||||
Id EmitConvertU32U16(EmitContext& ctx, Id value);
|
Id EmitConvertU32U16(EmitContext& ctx, Id value);
|
||||||
|
|
||||||
|
Id EmitImageSampleRaw(EmitContext& ctx, IR::Inst* inst, u32 handle, Id address1, Id address2,
|
||||||
|
Id address3, Id address4);
|
||||||
Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id bias,
|
Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id bias,
|
||||||
const IR::Value& offset);
|
const IR::Value& offset);
|
||||||
Id EmitImageSampleExplicitLod(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id lod,
|
Id EmitImageSampleExplicitLod(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id lod,
|
||||||
@ -383,8 +386,8 @@ Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, const
|
|||||||
Id lod, Id ms);
|
Id lod, Id ms);
|
||||||
Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, u32 handle, Id lod, bool skip_mips);
|
Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, u32 handle, Id lod, bool skip_mips);
|
||||||
Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords);
|
Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords);
|
||||||
Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id derivatives,
|
Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id derivatives_dx,
|
||||||
const IR::Value& offset, Id lod_clamp);
|
Id derivatives_dy, const IR::Value& offset, const IR::Value& lod_clamp);
|
||||||
Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords);
|
Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords);
|
||||||
void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id color);
|
void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id color);
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
|
#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
|
||||||
#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
|
#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
|
||||||
|
#include "shader_recompiler/ir/debug_print.h"
|
||||||
|
|
||||||
namespace Shader::Backend::SPIRV {
|
namespace Shader::Backend::SPIRV {
|
||||||
|
|
||||||
@ -57,4 +58,11 @@ void EmitEndPrimitive(EmitContext& ctx, const IR::Value& stream) {
|
|||||||
throw NotImplementedException("Geometry streams");
|
throw NotImplementedException("Geometry streams");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmitDebugPrint(EmitContext& ctx, IR::Inst* inst, Id fmt, Id arg0, Id arg1, Id arg2, Id arg3) {
|
||||||
|
IR::DebugPrintFlags flags = inst->Flags<IR::DebugPrintFlags>();
|
||||||
|
std::array<Id, IR::DEBUGPRINT_NUM_FORMAT_ARGS> fmt_args = {arg0, arg1, arg2, arg3};
|
||||||
|
auto fmt_args_span = std::span<Id>(fmt_args.begin(), fmt_args.begin() + flags.num_args);
|
||||||
|
ctx.OpDebugPrintf(fmt, fmt_args_span);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Shader::Backend::SPIRV
|
} // namespace Shader::Backend::SPIRV
|
||||||
|
@ -34,14 +34,17 @@ std::string_view StageName(Stage stage) {
|
|||||||
throw InvalidArgument("Invalid stage {}", u32(stage));
|
throw InvalidArgument("Invalid stage {}", u32(stage));
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr u32 NumVertices(AmdGpu::GsOutputPrimitiveType type) {
|
static constexpr u32 NumVertices(AmdGpu::PrimitiveType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case AmdGpu::GsOutputPrimitiveType::PointList:
|
case AmdGpu::PrimitiveType::PointList:
|
||||||
return 1u;
|
return 1u;
|
||||||
case AmdGpu::GsOutputPrimitiveType::LineStrip:
|
case AmdGpu::PrimitiveType::LineList:
|
||||||
return 2u;
|
return 2u;
|
||||||
case AmdGpu::GsOutputPrimitiveType::TriangleStrip:
|
case AmdGpu::PrimitiveType::TriangleList:
|
||||||
|
case AmdGpu::PrimitiveType::TriangleStrip:
|
||||||
return 3u;
|
return 3u;
|
||||||
|
case AmdGpu::PrimitiveType::AdjTriangleList:
|
||||||
|
return 6u;
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
@ -88,6 +91,8 @@ Id EmitContext::Def(const IR::Value& value) {
|
|||||||
return ConstF32(value.F32());
|
return ConstF32(value.F32());
|
||||||
case IR::Type::F64:
|
case IR::Type::F64:
|
||||||
return Constant(F64[1], value.F64());
|
return Constant(F64[1], value.F64());
|
||||||
|
case IR::Type::StringLiteral:
|
||||||
|
return String(value.StringLiteral());
|
||||||
default:
|
default:
|
||||||
throw NotImplementedException("Immediate type {}", value.Type());
|
throw NotImplementedException("Immediate type {}", value.Type());
|
||||||
}
|
}
|
||||||
@ -279,7 +284,8 @@ void EmitContext::DefineInputs() {
|
|||||||
frag_coord = DefineVariable(F32[4], spv::BuiltIn::FragCoord, spv::StorageClass::Input);
|
frag_coord = DefineVariable(F32[4], spv::BuiltIn::FragCoord, spv::StorageClass::Input);
|
||||||
frag_depth = DefineVariable(F32[1], spv::BuiltIn::FragDepth, spv::StorageClass::Output);
|
frag_depth = DefineVariable(F32[1], spv::BuiltIn::FragDepth, spv::StorageClass::Output);
|
||||||
front_facing = DefineVariable(U1[1], spv::BuiltIn::FrontFacing, spv::StorageClass::Input);
|
front_facing = DefineVariable(U1[1], spv::BuiltIn::FrontFacing, spv::StorageClass::Input);
|
||||||
for (const auto& input : runtime_info.fs_info.inputs) {
|
for (s32 i = 0; i < runtime_info.fs_info.num_inputs; i++) {
|
||||||
|
const auto& input = runtime_info.fs_info.inputs[i];
|
||||||
const u32 semantic = input.param_index;
|
const u32 semantic = input.param_index;
|
||||||
ASSERT(semantic < IR::NumParams);
|
ASSERT(semantic < IR::NumParams);
|
||||||
if (input.is_default && !input.is_flat) {
|
if (input.is_default && !input.is_flat) {
|
||||||
@ -321,16 +327,14 @@ void EmitContext::DefineInputs() {
|
|||||||
MemberDecorate(gl_per_vertex, 2, spv::Decoration::BuiltIn,
|
MemberDecorate(gl_per_vertex, 2, spv::Decoration::BuiltIn,
|
||||||
static_cast<std::uint32_t>(spv::BuiltIn::ClipDistance));
|
static_cast<std::uint32_t>(spv::BuiltIn::ClipDistance));
|
||||||
Decorate(gl_per_vertex, spv::Decoration::Block);
|
Decorate(gl_per_vertex, spv::Decoration::Block);
|
||||||
const auto vertices_in =
|
const auto num_verts_in = NumVertices(runtime_info.gs_info.in_primitive);
|
||||||
TypeArray(gl_per_vertex, ConstU32(NumVertices(runtime_info.gs_info.out_primitive[0])));
|
const auto vertices_in = TypeArray(gl_per_vertex, ConstU32(num_verts_in));
|
||||||
gl_in = Name(DefineVar(vertices_in, spv::StorageClass::Input), "gl_in");
|
gl_in = Name(DefineVar(vertices_in, spv::StorageClass::Input), "gl_in");
|
||||||
interfaces.push_back(gl_in);
|
interfaces.push_back(gl_in);
|
||||||
|
|
||||||
const auto num_params = runtime_info.gs_info.in_vertex_data_size / 4 - 1u;
|
const auto num_params = runtime_info.gs_info.in_vertex_data_size / 4 - 1u;
|
||||||
for (int param_id = 0; param_id < num_params; ++param_id) {
|
for (int param_id = 0; param_id < num_params; ++param_id) {
|
||||||
const IR::Attribute param{IR::Attribute::Param0 + param_id};
|
const Id type{TypeArray(F32[4], ConstU32(num_verts_in))};
|
||||||
const Id type{
|
|
||||||
TypeArray(F32[4], ConstU32(NumVertices(runtime_info.gs_info.out_primitive[0])))};
|
|
||||||
const Id id{DefineInput(type, param_id)};
|
const Id id{DefineInput(type, param_id)};
|
||||||
Name(id, fmt::format("in_attr{}", param_id));
|
Name(id, fmt::format("in_attr{}", param_id));
|
||||||
input_params[param_id] = {id, input_f32, F32[1], 4};
|
input_params[param_id] = {id, input_f32, F32[1], 4};
|
||||||
@ -390,8 +394,7 @@ void EmitContext::DefineOutputs() {
|
|||||||
case Stage::Geometry: {
|
case Stage::Geometry: {
|
||||||
output_position = DefineVariable(F32[4], spv::BuiltIn::Position, spv::StorageClass::Output);
|
output_position = DefineVariable(F32[4], spv::BuiltIn::Position, spv::StorageClass::Output);
|
||||||
|
|
||||||
for (u32 attr_id = 0; attr_id < runtime_info.gs_info.copy_data.num_attrs; attr_id++) {
|
for (u32 attr_id = 0; attr_id < info.gs_copy_data.num_attrs; attr_id++) {
|
||||||
const IR::Attribute param{IR::Attribute::Param0 + attr_id};
|
|
||||||
const Id id{DefineOutput(F32[4], attr_id)};
|
const Id id{DefineOutput(F32[4], attr_id)};
|
||||||
Name(id, fmt::format("out_attr{}", attr_id));
|
Name(id, fmt::format("out_attr{}", attr_id));
|
||||||
output_params[attr_id] = {id, output_f32, F32[1], 4u};
|
output_params[attr_id] = {id, output_f32, F32[1], 4u};
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
namespace Shader {
|
namespace Shader {
|
||||||
|
|
||||||
CopyShaderData ParseCopyShader(const std::span<const u32>& code) {
|
CopyShaderData ParseCopyShader(std::span<const u32> code) {
|
||||||
Gcn::GcnCodeSlice code_slice{code.data(), code.data() + code.size()};
|
Gcn::GcnCodeSlice code_slice{code.data(), code.data() + code.size()};
|
||||||
Gcn::GcnDecodeContext decoder;
|
Gcn::GcnDecodeContext decoder;
|
||||||
|
|
||||||
@ -15,18 +15,18 @@ CopyShaderData ParseCopyShader(const std::span<const u32>& code) {
|
|||||||
ASSERT_MSG(code[0] == token_mov_vcchi, "First instruction is not s_mov_b32 vcc_hi, #imm");
|
ASSERT_MSG(code[0] == token_mov_vcchi, "First instruction is not s_mov_b32 vcc_hi, #imm");
|
||||||
|
|
||||||
std::array<s32, 32> offsets{};
|
std::array<s32, 32> offsets{};
|
||||||
std::fill(offsets.begin(), offsets.end(), -1);
|
offsets.fill(-1);
|
||||||
|
|
||||||
|
std::array<s32, 256> sources{};
|
||||||
|
sources.fill(-1);
|
||||||
|
|
||||||
CopyShaderData data{};
|
CopyShaderData data{};
|
||||||
Gcn::OperandField sgpr{};
|
|
||||||
auto last_attr{IR::Attribute::Position0};
|
auto last_attr{IR::Attribute::Position0};
|
||||||
s32 soffset{0};
|
|
||||||
while (!code_slice.atEnd()) {
|
while (!code_slice.atEnd()) {
|
||||||
auto inst = decoder.decodeInstruction(code_slice);
|
auto inst = decoder.decodeInstruction(code_slice);
|
||||||
switch (inst.opcode) {
|
switch (inst.opcode) {
|
||||||
case Gcn::Opcode::S_MOVK_I32: {
|
case Gcn::Opcode::S_MOVK_I32: {
|
||||||
sgpr = inst.dst[0].field;
|
sources[inst.dst[0].code] = inst.control.sopk.simm;
|
||||||
soffset = inst.control.sopk.simm;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Gcn::Opcode::EXP: {
|
case Gcn::Opcode::EXP: {
|
||||||
@ -46,8 +46,9 @@ CopyShaderData ParseCopyShader(const std::span<const u32>& code) {
|
|||||||
case Gcn::Opcode::BUFFER_LOAD_DWORD: {
|
case Gcn::Opcode::BUFFER_LOAD_DWORD: {
|
||||||
offsets[inst.src[1].code] = inst.control.mubuf.offset;
|
offsets[inst.src[1].code] = inst.control.mubuf.offset;
|
||||||
if (inst.src[3].field != Gcn::OperandField::ConstZero) {
|
if (inst.src[3].field != Gcn::OperandField::ConstZero) {
|
||||||
ASSERT(inst.src[3].field == sgpr);
|
const u32 index = inst.src[3].code;
|
||||||
offsets[inst.src[1].code] += soffset;
|
ASSERT(sources[index] != -1);
|
||||||
|
offsets[inst.src[1].code] += sources[index];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -59,6 +60,7 @@ CopyShaderData ParseCopyShader(const std::span<const u32>& code) {
|
|||||||
if (last_attr != IR::Attribute::Position0) {
|
if (last_attr != IR::Attribute::Position0) {
|
||||||
data.num_attrs = static_cast<u32>(last_attr) - static_cast<u32>(IR::Attribute::Param0) + 1;
|
data.num_attrs = static_cast<u32>(last_attr) - static_cast<u32>(IR::Attribute::Param0) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,6 @@ struct CopyShaderData {
|
|||||||
u32 num_attrs{0};
|
u32 num_attrs{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
CopyShaderData ParseCopyShader(const std::span<const u32>& code);
|
CopyShaderData ParseCopyShader(std::span<const u32> code);
|
||||||
|
|
||||||
} // namespace Shader
|
} // namespace Shader
|
||||||
|
@ -3642,8 +3642,8 @@ constexpr std::array<InstFormat, 112> InstructionFormatMIMG = {{
|
|||||||
{InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined,
|
{InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined,
|
||||||
ScalarType::Undefined},
|
ScalarType::Undefined},
|
||||||
// 95 = IMAGE_GATHER4_C_LZ_O
|
// 95 = IMAGE_GATHER4_C_LZ_O
|
||||||
{InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined,
|
{InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32,
|
||||||
ScalarType::Undefined},
|
ScalarType::Float32},
|
||||||
// 96 = IMAGE_GET_LOD
|
// 96 = IMAGE_GET_LOD
|
||||||
{InstClass::VectorMemImgUt, InstCategory::VectorMemory, 4, 1, ScalarType::Float32,
|
{InstClass::VectorMemImgUt, InstCategory::VectorMemory, 4, 1, ScalarType::Float32,
|
||||||
ScalarType::Float32},
|
ScalarType::Float32},
|
||||||
|
@ -155,6 +155,8 @@ public:
|
|||||||
void V_SUB_I32(const GcnInst& inst);
|
void V_SUB_I32(const GcnInst& inst);
|
||||||
void V_SUBREV_I32(const GcnInst& inst);
|
void V_SUBREV_I32(const GcnInst& inst);
|
||||||
void V_ADDC_U32(const GcnInst& inst);
|
void V_ADDC_U32(const GcnInst& inst);
|
||||||
|
void V_SUBB_U32(const GcnInst& inst);
|
||||||
|
void V_SUBBREV_U32(const GcnInst& inst);
|
||||||
void V_LDEXP_F32(const GcnInst& inst);
|
void V_LDEXP_F32(const GcnInst& inst);
|
||||||
void V_CVT_PKNORM_U16_F32(const GcnInst& inst);
|
void V_CVT_PKNORM_U16_F32(const GcnInst& inst);
|
||||||
void V_CVT_PKRTZ_F16_F32(const GcnInst& inst);
|
void V_CVT_PKRTZ_F16_F32(const GcnInst& inst);
|
||||||
@ -273,7 +275,9 @@ private:
|
|||||||
void SetDst(const InstOperand& operand, const IR::U32F32& value);
|
void SetDst(const InstOperand& operand, const IR::U32F32& value);
|
||||||
void SetDst64(const InstOperand& operand, const IR::U64F64& value_raw);
|
void SetDst64(const InstOperand& operand, const IR::U64F64& value_raw);
|
||||||
|
|
||||||
// Vector ALU Helprers
|
// Vector ALU Helpers
|
||||||
|
IR::U32 GetCarryIn(const GcnInst& inst);
|
||||||
|
void SetCarryOut(const GcnInst& inst, const IR::U1& carry);
|
||||||
IR::U32 VMovRelSHelper(u32 src_vgprno, const IR::U32 m0);
|
IR::U32 VMovRelSHelper(u32 src_vgprno, const IR::U32 m0);
|
||||||
void VMovRelDHelper(u32 dst_vgprno, const IR::U32 src_val, const IR::U32 m0);
|
void VMovRelDHelper(u32 dst_vgprno, const IR::U32 src_val, const IR::U32 m0);
|
||||||
|
|
||||||
|
@ -87,6 +87,10 @@ void Translator::EmitVectorAlu(const GcnInst& inst) {
|
|||||||
return V_SUBREV_I32(inst);
|
return V_SUBREV_I32(inst);
|
||||||
case Opcode::V_ADDC_U32:
|
case Opcode::V_ADDC_U32:
|
||||||
return V_ADDC_U32(inst);
|
return V_ADDC_U32(inst);
|
||||||
|
case Opcode::V_SUBB_U32:
|
||||||
|
return V_SUBB_U32(inst);
|
||||||
|
case Opcode::V_SUBBREV_U32:
|
||||||
|
return V_SUBBREV_U32(inst);
|
||||||
case Opcode::V_LDEXP_F32:
|
case Opcode::V_LDEXP_F32:
|
||||||
return V_LDEXP_F32(inst);
|
return V_LDEXP_F32(inst);
|
||||||
case Opcode::V_CVT_PKNORM_U16_F32:
|
case Opcode::V_CVT_PKNORM_U16_F32:
|
||||||
@ -546,51 +550,71 @@ void Translator::V_MBCNT_U32_B32(bool is_low, const GcnInst& inst) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Translator::V_ADD_I32(const GcnInst& inst) {
|
void Translator::V_ADD_I32(const GcnInst& inst) {
|
||||||
|
// Signed or unsigned components
|
||||||
const IR::U32 src0{GetSrc(inst.src[0])};
|
const IR::U32 src0{GetSrc(inst.src[0])};
|
||||||
const IR::U32 src1{ir.GetVectorReg(IR::VectorReg(inst.src[1].code))};
|
const IR::U32 src1{ir.GetVectorReg(IR::VectorReg(inst.src[1].code))};
|
||||||
SetDst(inst.dst[0], ir.IAdd(src0, src1));
|
const IR::U32 result{ir.IAdd(src0, src1)};
|
||||||
// TODO: Carry
|
SetDst(inst.dst[0], result);
|
||||||
|
|
||||||
|
// TODO: Carry-out with signed or unsigned components
|
||||||
}
|
}
|
||||||
|
|
||||||
void Translator::V_SUB_I32(const GcnInst& inst) {
|
void Translator::V_SUB_I32(const GcnInst& inst) {
|
||||||
|
// Unsigned components
|
||||||
const IR::U32 src0{GetSrc(inst.src[0])};
|
const IR::U32 src0{GetSrc(inst.src[0])};
|
||||||
const IR::U32 src1{GetSrc(inst.src[1])};
|
const IR::U32 src1{GetSrc(inst.src[1])};
|
||||||
SetDst(inst.dst[0], ir.ISub(src0, src1));
|
const IR::U32 result{ir.ISub(src0, src1)};
|
||||||
|
SetDst(inst.dst[0], result);
|
||||||
|
|
||||||
|
const IR::U1 did_underflow{ir.IGreaterThan(src1, src0, false)};
|
||||||
|
SetCarryOut(inst, did_underflow);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Translator::V_SUBREV_I32(const GcnInst& inst) {
|
void Translator::V_SUBREV_I32(const GcnInst& inst) {
|
||||||
|
// Unsigned components
|
||||||
const IR::U32 src0{GetSrc(inst.src[0])};
|
const IR::U32 src0{GetSrc(inst.src[0])};
|
||||||
const IR::U32 src1{GetSrc(inst.src[1])};
|
const IR::U32 src1{GetSrc(inst.src[1])};
|
||||||
SetDst(inst.dst[0], ir.ISub(src1, src0));
|
const IR::U32 result{ir.ISub(src1, src0)};
|
||||||
// TODO: Carry-out
|
SetDst(inst.dst[0], result);
|
||||||
|
|
||||||
|
const IR::U1 did_underflow{ir.IGreaterThan(src0, src1, false)};
|
||||||
|
SetCarryOut(inst, did_underflow);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Translator::V_ADDC_U32(const GcnInst& inst) {
|
void Translator::V_ADDC_U32(const GcnInst& inst) {
|
||||||
const auto src0 = GetSrc<IR::U32>(inst.src[0]);
|
// Unsigned components
|
||||||
const auto src1 = GetSrc<IR::U32>(inst.src[1]);
|
const IR::U32 src0{GetSrc(inst.src[0])};
|
||||||
|
const IR::U32 src1{GetSrc(inst.src[1])};
|
||||||
IR::U1 carry;
|
const IR::U32 carry{GetCarryIn(inst)};
|
||||||
if (inst.src_count == 3) { // VOP3
|
const IR::U32 result{ir.IAdd(ir.IAdd(src0, src1), carry)};
|
||||||
if (inst.src[2].field == OperandField::VccLo) {
|
|
||||||
carry = ir.GetVcc();
|
|
||||||
} else if (inst.src[2].field == OperandField::ScalarGPR) {
|
|
||||||
carry = ir.GetThreadBitScalarReg(IR::ScalarReg(inst.src[2].code));
|
|
||||||
} else {
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
} else { // VOP2
|
|
||||||
carry = ir.GetVcc();
|
|
||||||
}
|
|
||||||
|
|
||||||
const IR::U32 scarry = IR::U32{ir.Select(carry, ir.Imm32(1), ir.Imm32(0))};
|
|
||||||
const IR::U32 result = ir.IAdd(ir.IAdd(src0, src1), scarry);
|
|
||||||
|
|
||||||
SetDst(inst.dst[0], result);
|
SetDst(inst.dst[0], result);
|
||||||
|
|
||||||
const IR::U1 less_src0 = ir.ILessThan(result, src0, false);
|
const IR::U1 less_src0{ir.ILessThan(result, src0, false)};
|
||||||
const IR::U1 less_src1 = ir.ILessThan(result, src1, false);
|
const IR::U1 less_src1{ir.ILessThan(result, src1, false)};
|
||||||
const IR::U1 did_overflow = ir.LogicalOr(less_src0, less_src1);
|
const IR::U1 did_overflow{ir.LogicalOr(less_src0, less_src1)};
|
||||||
ir.SetVcc(did_overflow);
|
SetCarryOut(inst, did_overflow);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Translator::V_SUBB_U32(const GcnInst& inst) {
|
||||||
|
// Signed or unsigned components
|
||||||
|
const IR::U32 src0{GetSrc(inst.src[0])};
|
||||||
|
const IR::U32 src1{GetSrc(inst.src[1])};
|
||||||
|
const IR::U32 carry{GetCarryIn(inst)};
|
||||||
|
const IR::U32 result{ir.ISub(ir.ISub(src0, src1), carry)};
|
||||||
|
SetDst(inst.dst[0], result);
|
||||||
|
|
||||||
|
// TODO: Carry-out with signed or unsigned components
|
||||||
|
}
|
||||||
|
|
||||||
|
void Translator::V_SUBBREV_U32(const GcnInst& inst) {
|
||||||
|
// Signed or unsigned components
|
||||||
|
const IR::U32 src0{GetSrc(inst.src[0])};
|
||||||
|
const IR::U32 src1{GetSrc(inst.src[1])};
|
||||||
|
const IR::U32 carry{GetCarryIn(inst)};
|
||||||
|
const IR::U32 result{ir.ISub(ir.ISub(src1, src0), carry)};
|
||||||
|
SetDst(inst.dst[0], result);
|
||||||
|
|
||||||
|
// TODO: Carry-out with signed or unsigned components
|
||||||
}
|
}
|
||||||
|
|
||||||
void Translator::V_LDEXP_F32(const GcnInst& inst) {
|
void Translator::V_LDEXP_F32(const GcnInst& inst) {
|
||||||
@ -1152,6 +1176,37 @@ void Translator::V_MAD_U64_U32(const GcnInst& inst) {
|
|||||||
ir.SetVcc(did_overflow);
|
ir.SetVcc(did_overflow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IR::U32 Translator::GetCarryIn(const GcnInst& inst) {
|
||||||
|
IR::U1 carry;
|
||||||
|
if (inst.src_count == 3) { // VOP3
|
||||||
|
if (inst.src[2].field == OperandField::VccLo) {
|
||||||
|
carry = ir.GetVcc();
|
||||||
|
} else if (inst.src[2].field == OperandField::ScalarGPR) {
|
||||||
|
carry = ir.GetThreadBitScalarReg(IR::ScalarReg(inst.src[2].code));
|
||||||
|
} else {
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
} else { // VOP2
|
||||||
|
carry = ir.GetVcc();
|
||||||
|
}
|
||||||
|
|
||||||
|
return IR::U32{ir.Select(carry, ir.Imm32(1), ir.Imm32(0))};
|
||||||
|
}
|
||||||
|
|
||||||
|
void Translator::SetCarryOut(const GcnInst& inst, const IR::U1& carry) {
|
||||||
|
if (inst.dst_count == 2) { // VOP3
|
||||||
|
if (inst.dst[1].field == OperandField::VccLo) {
|
||||||
|
ir.SetVcc(carry);
|
||||||
|
} else if (inst.dst[1].field == OperandField::ScalarGPR) {
|
||||||
|
ir.SetThreadBitScalarReg(IR::ScalarReg(inst.dst[1].code), carry);
|
||||||
|
} else {
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
} else { // VOP2
|
||||||
|
ir.SetVcc(carry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: add range analysis pass to hopefully put an upper bound on m0, and only select one of
|
// TODO: add range analysis pass to hopefully put an upper bound on m0, and only select one of
|
||||||
// [src_vgprno, src_vgprno + max_m0]. Same for dst regs we may write back to
|
// [src_vgprno, src_vgprno + max_m0]. Same for dst regs we may write back to
|
||||||
|
|
||||||
|
@ -147,6 +147,7 @@ void Translator::EmitVectorMemory(const GcnInst& inst) {
|
|||||||
case Opcode::IMAGE_GATHER4_C_O:
|
case Opcode::IMAGE_GATHER4_C_O:
|
||||||
case Opcode::IMAGE_GATHER4_C_LZ:
|
case Opcode::IMAGE_GATHER4_C_LZ:
|
||||||
case Opcode::IMAGE_GATHER4_LZ_O:
|
case Opcode::IMAGE_GATHER4_LZ_O:
|
||||||
|
case Opcode::IMAGE_GATHER4_C_LZ_O:
|
||||||
return IMAGE_GATHER(inst);
|
return IMAGE_GATHER(inst);
|
||||||
|
|
||||||
// Image misc operations
|
// Image misc operations
|
||||||
@ -410,7 +411,7 @@ void Translator::IMAGE_LOAD(bool has_mip, const GcnInst& inst) {
|
|||||||
ir.GetVectorReg(addr_reg + 2), ir.GetVectorReg(addr_reg + 3));
|
ir.GetVectorReg(addr_reg + 2), ir.GetVectorReg(addr_reg + 3));
|
||||||
|
|
||||||
IR::TextureInstInfo info{};
|
IR::TextureInstInfo info{};
|
||||||
info.explicit_lod.Assign(has_mip);
|
info.has_lod.Assign(has_mip);
|
||||||
const IR::Value texel = ir.ImageFetch(handle, body, {}, {}, {}, info);
|
const IR::Value texel = ir.ImageFetch(handle, body, {}, {}, {}, info);
|
||||||
|
|
||||||
for (u32 i = 0; i < 4; i++) {
|
for (u32 i = 0; i < 4; i++) {
|
||||||
@ -512,6 +513,76 @@ void Translator::IMAGE_ATOMIC(AtomicOp op, const GcnInst& inst) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IR::Value EmitImageSample(IR::IREmitter& ir, const GcnInst& inst, const IR::ScalarReg tsharp_reg,
|
||||||
|
const IR::ScalarReg sampler_reg, const IR::VectorReg addr_reg,
|
||||||
|
bool gather) {
|
||||||
|
const auto& mimg = inst.control.mimg;
|
||||||
|
const auto flags = MimgModifierFlags(mimg.mod);
|
||||||
|
|
||||||
|
IR::TextureInstInfo info{};
|
||||||
|
info.is_depth.Assign(flags.test(MimgModifier::Pcf));
|
||||||
|
info.has_bias.Assign(flags.test(MimgModifier::LodBias));
|
||||||
|
info.has_lod_clamp.Assign(flags.test(MimgModifier::LodClamp));
|
||||||
|
info.force_level0.Assign(flags.test(MimgModifier::Level0));
|
||||||
|
info.has_offset.Assign(flags.test(MimgModifier::Offset));
|
||||||
|
info.has_lod.Assign(flags.any(MimgModifier::Lod));
|
||||||
|
info.is_array.Assign(mimg.da);
|
||||||
|
|
||||||
|
if (gather) {
|
||||||
|
info.gather_comp.Assign(std::bit_width(mimg.dmask) - 1);
|
||||||
|
info.is_gather.Assign(true);
|
||||||
|
} else {
|
||||||
|
info.has_derivatives.Assign(flags.test(MimgModifier::Derivative));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load first dword of T# and S#. We will use them as the handle that will guide resource
|
||||||
|
// tracking pass where to read the sharps. This will later also get patched to the SPIRV texture
|
||||||
|
// binding index.
|
||||||
|
const IR::Value handle =
|
||||||
|
ir.CompositeConstruct(ir.GetScalarReg(tsharp_reg), ir.GetScalarReg(sampler_reg));
|
||||||
|
|
||||||
|
// Determine how many address registers need to be passed.
|
||||||
|
// The image type is unknown, so add all 4 possible base registers and resolve later.
|
||||||
|
int num_addr_regs = 4;
|
||||||
|
if (info.has_offset) {
|
||||||
|
++num_addr_regs;
|
||||||
|
}
|
||||||
|
if (info.has_bias) {
|
||||||
|
++num_addr_regs;
|
||||||
|
}
|
||||||
|
if (info.is_depth) {
|
||||||
|
++num_addr_regs;
|
||||||
|
}
|
||||||
|
if (info.has_derivatives) {
|
||||||
|
// The image type is unknown, so add all 6 possible derivative registers and resolve later.
|
||||||
|
num_addr_regs += 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch all the address registers to pass in the IR instruction. There can be up to 13
|
||||||
|
// registers.
|
||||||
|
const auto get_addr_reg = [&](int index) -> IR::F32 {
|
||||||
|
if (index >= num_addr_regs) {
|
||||||
|
return ir.Imm32(0.f);
|
||||||
|
}
|
||||||
|
return ir.GetVectorReg<IR::F32>(addr_reg + index);
|
||||||
|
};
|
||||||
|
const IR::Value address1 =
|
||||||
|
ir.CompositeConstruct(get_addr_reg(0), get_addr_reg(1), get_addr_reg(2), get_addr_reg(3));
|
||||||
|
const IR::Value address2 =
|
||||||
|
ir.CompositeConstruct(get_addr_reg(4), get_addr_reg(5), get_addr_reg(6), get_addr_reg(7));
|
||||||
|
const IR::Value address3 =
|
||||||
|
ir.CompositeConstruct(get_addr_reg(8), get_addr_reg(9), get_addr_reg(10), get_addr_reg(11));
|
||||||
|
const IR::Value address4 = get_addr_reg(12);
|
||||||
|
|
||||||
|
// Issue the placeholder IR instruction.
|
||||||
|
IR::Value texel = ir.ImageSampleRaw(handle, address1, address2, address3, address4, info);
|
||||||
|
if (info.is_depth && !gather) {
|
||||||
|
// For non-gather depth sampling, only return a single value.
|
||||||
|
texel = ir.CompositeExtract(texel, 0);
|
||||||
|
}
|
||||||
|
return texel;
|
||||||
|
}
|
||||||
|
|
||||||
void Translator::IMAGE_SAMPLE(const GcnInst& inst) {
|
void Translator::IMAGE_SAMPLE(const GcnInst& inst) {
|
||||||
const auto& mimg = inst.control.mimg;
|
const auto& mimg = inst.control.mimg;
|
||||||
IR::VectorReg addr_reg{inst.src[0].code};
|
IR::VectorReg addr_reg{inst.src[0].code};
|
||||||
@ -520,72 +591,7 @@ void Translator::IMAGE_SAMPLE(const GcnInst& inst) {
|
|||||||
const IR::ScalarReg sampler_reg{inst.src[3].code * 4};
|
const IR::ScalarReg sampler_reg{inst.src[3].code * 4};
|
||||||
const auto flags = MimgModifierFlags(mimg.mod);
|
const auto flags = MimgModifierFlags(mimg.mod);
|
||||||
|
|
||||||
// Load first dword of T# and S#. We will use them as the handle that will guide resource
|
const IR::Value texel = EmitImageSample(ir, inst, tsharp_reg, sampler_reg, addr_reg, false);
|
||||||
// tracking pass where to read the sharps. This will later also get patched to the SPIRV texture
|
|
||||||
// binding index.
|
|
||||||
const IR::Value handle =
|
|
||||||
ir.CompositeConstruct(ir.GetScalarReg(tsharp_reg), ir.GetScalarReg(sampler_reg));
|
|
||||||
|
|
||||||
// Load first address components as denoted in 8.2.4 VGPR Usage Sea Islands Series Instruction
|
|
||||||
// Set Architecture
|
|
||||||
const IR::U32 offset =
|
|
||||||
flags.test(MimgModifier::Offset) ? ir.GetVectorReg<IR::U32>(addr_reg++) : IR::U32{};
|
|
||||||
const IR::F32 bias =
|
|
||||||
flags.test(MimgModifier::LodBias) ? ir.GetVectorReg<IR::F32>(addr_reg++) : IR::F32{};
|
|
||||||
const IR::F32 dref =
|
|
||||||
flags.test(MimgModifier::Pcf) ? ir.GetVectorReg<IR::F32>(addr_reg++) : IR::F32{};
|
|
||||||
const IR::Value derivatives = [&] -> IR::Value {
|
|
||||||
if (!flags.test(MimgModifier::Derivative)) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
addr_reg = addr_reg + 4;
|
|
||||||
return ir.CompositeConstruct(
|
|
||||||
ir.GetVectorReg<IR::F32>(addr_reg - 4), ir.GetVectorReg<IR::F32>(addr_reg - 3),
|
|
||||||
ir.GetVectorReg<IR::F32>(addr_reg - 2), ir.GetVectorReg<IR::F32>(addr_reg - 1));
|
|
||||||
}();
|
|
||||||
|
|
||||||
// Now we can load body components as noted in Table 8.9 Image Opcodes with Sampler
|
|
||||||
// Since these are at most 4 dwords, we load them into a single uvec4 and place them
|
|
||||||
// in coords field of the instruction. Then the resource tracking pass will patch the
|
|
||||||
// IR instruction to fill in lod_clamp field.
|
|
||||||
const IR::Value body = ir.CompositeConstruct(
|
|
||||||
ir.GetVectorReg<IR::F32>(addr_reg), ir.GetVectorReg<IR::F32>(addr_reg + 1),
|
|
||||||
ir.GetVectorReg<IR::F32>(addr_reg + 2), ir.GetVectorReg<IR::F32>(addr_reg + 3));
|
|
||||||
|
|
||||||
// Derivatives are tricky because their number depends on the texture type which is located in
|
|
||||||
// T#. We don't have access to T# though until resource tracking pass. For now assume if
|
|
||||||
// derivatives are present, that a 2D image is bound.
|
|
||||||
const bool has_derivatives = flags.test(MimgModifier::Derivative);
|
|
||||||
const bool explicit_lod = flags.any(MimgModifier::Level0, MimgModifier::Lod);
|
|
||||||
|
|
||||||
IR::TextureInstInfo info{};
|
|
||||||
info.is_depth.Assign(flags.test(MimgModifier::Pcf));
|
|
||||||
info.has_bias.Assign(flags.test(MimgModifier::LodBias));
|
|
||||||
info.has_lod_clamp.Assign(flags.test(MimgModifier::LodClamp));
|
|
||||||
info.force_level0.Assign(flags.test(MimgModifier::Level0));
|
|
||||||
info.has_offset.Assign(flags.test(MimgModifier::Offset));
|
|
||||||
info.explicit_lod.Assign(explicit_lod);
|
|
||||||
info.has_derivatives.Assign(has_derivatives);
|
|
||||||
info.is_array.Assign(mimg.da);
|
|
||||||
|
|
||||||
// Issue IR instruction, leaving unknown fields blank to patch later.
|
|
||||||
const IR::Value texel = [&]() -> IR::Value {
|
|
||||||
if (has_derivatives) {
|
|
||||||
return ir.ImageGradient(handle, body, derivatives, offset, {}, info);
|
|
||||||
}
|
|
||||||
if (!flags.test(MimgModifier::Pcf)) {
|
|
||||||
if (explicit_lod) {
|
|
||||||
return ir.ImageSampleExplicitLod(handle, body, offset, info);
|
|
||||||
} else {
|
|
||||||
return ir.ImageSampleImplicitLod(handle, body, bias, offset, info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (explicit_lod) {
|
|
||||||
return ir.ImageSampleDrefExplicitLod(handle, body, dref, offset, info);
|
|
||||||
}
|
|
||||||
return ir.ImageSampleDrefImplicitLod(handle, body, dref, bias, offset, info);
|
|
||||||
}();
|
|
||||||
|
|
||||||
for (u32 i = 0; i < 4; i++) {
|
for (u32 i = 0; i < 4; i++) {
|
||||||
if (((mimg.dmask >> i) & 1) == 0) {
|
if (((mimg.dmask >> i) & 1) == 0) {
|
||||||
continue;
|
continue;
|
||||||
@ -608,60 +614,13 @@ void Translator::IMAGE_GATHER(const GcnInst& inst) {
|
|||||||
const IR::ScalarReg sampler_reg{inst.src[3].code * 4};
|
const IR::ScalarReg sampler_reg{inst.src[3].code * 4};
|
||||||
const auto flags = MimgModifierFlags(mimg.mod);
|
const auto flags = MimgModifierFlags(mimg.mod);
|
||||||
|
|
||||||
// Load first dword of T# and S#. We will use them as the handle that will guide resource
|
|
||||||
// tracking pass where to read the sharps. This will later also get patched to the SPIRV texture
|
|
||||||
// binding index.
|
|
||||||
const IR::Value handle =
|
|
||||||
ir.CompositeConstruct(ir.GetScalarReg(tsharp_reg), ir.GetScalarReg(sampler_reg));
|
|
||||||
|
|
||||||
// Load first address components as denoted in 8.2.4 VGPR Usage Sea Islands Series Instruction
|
|
||||||
// Set Architecture
|
|
||||||
const IR::Value offset =
|
|
||||||
flags.test(MimgModifier::Offset) ? ir.GetVectorReg(addr_reg++) : IR::Value{};
|
|
||||||
const IR::F32 bias =
|
|
||||||
flags.test(MimgModifier::LodBias) ? ir.GetVectorReg<IR::F32>(addr_reg++) : IR::F32{};
|
|
||||||
const IR::F32 dref =
|
|
||||||
flags.test(MimgModifier::Pcf) ? ir.GetVectorReg<IR::F32>(addr_reg++) : IR::F32{};
|
|
||||||
|
|
||||||
// Derivatives are tricky because their number depends on the texture type which is located in
|
|
||||||
// T#. We don't have access to T# though until resource tracking pass. For now assume no
|
|
||||||
// derivatives are present, otherwise we don't know where coordinates are placed in the address
|
|
||||||
// stream.
|
|
||||||
ASSERT_MSG(!flags.test(MimgModifier::Derivative), "Derivative image instruction");
|
|
||||||
|
|
||||||
// Now we can load body components as noted in Table 8.9 Image Opcodes with Sampler
|
|
||||||
// Since these are at most 4 dwords, we load them into a single uvec4 and place them
|
|
||||||
// in coords field of the instruction. Then the resource tracking pass will patch the
|
|
||||||
// IR instruction to fill in lod_clamp field.
|
|
||||||
const IR::Value body = ir.CompositeConstruct(
|
|
||||||
ir.GetVectorReg<IR::F32>(addr_reg), ir.GetVectorReg<IR::F32>(addr_reg + 1),
|
|
||||||
ir.GetVectorReg<IR::F32>(addr_reg + 2), ir.GetVectorReg<IR::F32>(addr_reg + 3));
|
|
||||||
|
|
||||||
const bool explicit_lod = flags.any(MimgModifier::Level0, MimgModifier::Lod);
|
|
||||||
|
|
||||||
IR::TextureInstInfo info{};
|
|
||||||
info.is_depth.Assign(flags.test(MimgModifier::Pcf));
|
|
||||||
info.has_bias.Assign(flags.test(MimgModifier::LodBias));
|
|
||||||
info.has_lod_clamp.Assign(flags.test(MimgModifier::LodClamp));
|
|
||||||
info.force_level0.Assign(flags.test(MimgModifier::Level0));
|
|
||||||
info.has_offset.Assign(flags.test(MimgModifier::Offset));
|
|
||||||
// info.explicit_lod.Assign(explicit_lod);
|
|
||||||
info.gather_comp.Assign(std::bit_width(mimg.dmask) - 1);
|
|
||||||
info.is_array.Assign(mimg.da);
|
|
||||||
|
|
||||||
// Issue IR instruction, leaving unknown fields blank to patch later.
|
|
||||||
const IR::Value texel = [&]() -> IR::Value {
|
|
||||||
const IR::F32 lod = flags.test(MimgModifier::Level0) ? ir.Imm32(0.f) : IR::F32{};
|
|
||||||
if (!flags.test(MimgModifier::Pcf)) {
|
|
||||||
return ir.ImageGather(handle, body, offset, info);
|
|
||||||
}
|
|
||||||
ASSERT(mimg.dmask & 1); // should be always 1st (R) component
|
|
||||||
return ir.ImageGatherDref(handle, body, offset, dref, info);
|
|
||||||
}();
|
|
||||||
|
|
||||||
// For gather4 instructions dmask selects which component to read and must have
|
// For gather4 instructions dmask selects which component to read and must have
|
||||||
// only one bit set to 1
|
// only one bit set to 1
|
||||||
ASSERT_MSG(std::popcount(mimg.dmask) == 1, "Unexpected bits in gather dmask");
|
ASSERT_MSG(std::popcount(mimg.dmask) == 1, "Unexpected bits in gather dmask");
|
||||||
|
// should be always 1st (R) component for depth
|
||||||
|
ASSERT(!flags.test(MimgModifier::Pcf) || mimg.dmask & 1);
|
||||||
|
|
||||||
|
const IR::Value texel = EmitImageSample(ir, inst, tsharp_reg, sampler_reg, addr_reg, true);
|
||||||
for (u32 i = 0; i < 4; i++) {
|
for (u32 i = 0; i < 4; i++) {
|
||||||
const IR::F32 value = IR::F32{ir.CompositeExtract(texel, i)};
|
const IR::F32 value = IR::F32{ir.CompositeExtract(texel, i)};
|
||||||
ir.SetVectorReg(dest_reg++, value);
|
ir.SetVectorReg(dest_reg++, value);
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
#include "shader_recompiler/backend/bindings.h"
|
#include "shader_recompiler/backend/bindings.h"
|
||||||
|
#include "shader_recompiler/frontend/copy_shader.h"
|
||||||
#include "shader_recompiler/ir/attribute.h"
|
#include "shader_recompiler/ir/attribute.h"
|
||||||
#include "shader_recompiler/ir/reg.h"
|
#include "shader_recompiler/ir/reg.h"
|
||||||
#include "shader_recompiler/ir/type.h"
|
#include "shader_recompiler/ir/type.h"
|
||||||
@ -169,6 +170,8 @@ struct Info {
|
|||||||
};
|
};
|
||||||
UserDataMask ud_mask{};
|
UserDataMask ud_mask{};
|
||||||
|
|
||||||
|
CopyShaderData gs_copy_data;
|
||||||
|
|
||||||
s8 vertex_offset_sgpr = -1;
|
s8 vertex_offset_sgpr = -1;
|
||||||
s8 instance_offset_sgpr = -1;
|
s8 instance_offset_sgpr = -1;
|
||||||
|
|
||||||
|
21
src/shader_recompiler/ir/debug_print.h
Normal file
21
src/shader_recompiler/ir/debug_print.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "common/bit_field.h"
|
||||||
|
#include "shader_recompiler/ir/opcodes.h"
|
||||||
|
#include "src/common/types.h"
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Shader::IR {
|
||||||
|
|
||||||
|
constexpr size_t DEBUGPRINT_NUM_FORMAT_ARGS = NumArgsOf(IR::Opcode::DebugPrint) - 1;
|
||||||
|
|
||||||
|
union DebugPrintFlags {
|
||||||
|
u32 raw;
|
||||||
|
// For now, only flag is the number of variadic format args actually used
|
||||||
|
// So bitfield not really needed
|
||||||
|
BitField<0, 32, u32> num_args;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Shader::IR
|
@ -1,10 +1,15 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <bit>
|
#include <bit>
|
||||||
#include <source_location>
|
#include <source_location>
|
||||||
|
#include <boost/container/small_vector.hpp>
|
||||||
|
#include "common/assert.h"
|
||||||
#include "shader_recompiler/exception.h"
|
#include "shader_recompiler/exception.h"
|
||||||
|
#include "shader_recompiler/ir/debug_print.h"
|
||||||
#include "shader_recompiler/ir/ir_emitter.h"
|
#include "shader_recompiler/ir/ir_emitter.h"
|
||||||
|
#include "shader_recompiler/ir/opcodes.h"
|
||||||
#include "shader_recompiler/ir/value.h"
|
#include "shader_recompiler/ir/value.h"
|
||||||
|
|
||||||
namespace Shader::IR {
|
namespace Shader::IR {
|
||||||
@ -1487,27 +1492,34 @@ Value IREmitter::ImageAtomicExchange(const Value& handle, const Value& coords, c
|
|||||||
return Inst(Opcode::ImageAtomicExchange32, Flags{info}, handle, coords, value);
|
return Inst(Opcode::ImageAtomicExchange32, Flags{info}, handle, coords, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::ImageSampleImplicitLod(const Value& handle, const Value& body, const F32& bias,
|
Value IREmitter::ImageSampleRaw(const Value& handle, const Value& address1, const Value& address2,
|
||||||
const U32& offset, TextureInstInfo info) {
|
const Value& address3, const Value& address4,
|
||||||
return Inst(Opcode::ImageSampleImplicitLod, Flags{info}, handle, body, bias, offset);
|
TextureInstInfo info) {
|
||||||
|
return Inst(Opcode::ImageSampleRaw, Flags{info}, handle, address1, address2, address3,
|
||||||
|
address4);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::ImageSampleExplicitLod(const Value& handle, const Value& body, const U32& offset,
|
Value IREmitter::ImageSampleImplicitLod(const Value& handle, const Value& coords, const F32& bias,
|
||||||
TextureInstInfo info) {
|
const Value& offset, TextureInstInfo info) {
|
||||||
return Inst(Opcode::ImageSampleExplicitLod, Flags{info}, handle, body, IR::F32{}, offset);
|
return Inst(Opcode::ImageSampleImplicitLod, Flags{info}, handle, coords, bias, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
F32 IREmitter::ImageSampleDrefImplicitLod(const Value& handle, const Value& body, const F32& dref,
|
Value IREmitter::ImageSampleExplicitLod(const Value& handle, const Value& coords, const F32& lod,
|
||||||
const F32& bias, const U32& offset,
|
const Value& offset, TextureInstInfo info) {
|
||||||
|
return Inst(Opcode::ImageSampleExplicitLod, Flags{info}, handle, coords, lod, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
Value IREmitter::ImageSampleDrefImplicitLod(const Value& handle, const Value& coords,
|
||||||
|
const F32& dref, const F32& bias, const Value& offset,
|
||||||
TextureInstInfo info) {
|
TextureInstInfo info) {
|
||||||
return Inst<F32>(Opcode::ImageSampleDrefImplicitLod, Flags{info}, handle, body, dref, bias,
|
return Inst(Opcode::ImageSampleDrefImplicitLod, Flags{info}, handle, coords, dref, bias,
|
||||||
offset);
|
offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
F32 IREmitter::ImageSampleDrefExplicitLod(const Value& handle, const Value& body, const F32& dref,
|
Value IREmitter::ImageSampleDrefExplicitLod(const Value& handle, const Value& coords,
|
||||||
const U32& offset, TextureInstInfo info) {
|
const F32& dref, const F32& lod, const Value& offset,
|
||||||
return Inst<F32>(Opcode::ImageSampleDrefExplicitLod, Flags{info}, handle, body, dref, IR::F32{},
|
TextureInstInfo info) {
|
||||||
offset);
|
return Inst(Opcode::ImageSampleDrefExplicitLod, Flags{info}, handle, coords, dref, lod, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::ImageGather(const Value& handle, const Value& coords, const Value& offset,
|
Value IREmitter::ImageGather(const Value& handle, const Value& coords, const Value& offset,
|
||||||
@ -1539,9 +1551,11 @@ Value IREmitter::ImageQueryLod(const Value& handle, const Value& coords, Texture
|
|||||||
return Inst(Opcode::ImageQueryLod, Flags{info}, handle, coords);
|
return Inst(Opcode::ImageQueryLod, Flags{info}, handle, coords);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::ImageGradient(const Value& handle, const Value& coords, const Value& derivatives,
|
Value IREmitter::ImageGradient(const Value& handle, const Value& coords,
|
||||||
|
const Value& derivatives_dx, const Value& derivatives_dy,
|
||||||
const Value& offset, const F32& lod_clamp, TextureInstInfo info) {
|
const Value& offset, const F32& lod_clamp, TextureInstInfo info) {
|
||||||
return Inst(Opcode::ImageGradient, Flags{info}, handle, coords, derivatives, offset, lod_clamp);
|
return Inst(Opcode::ImageGradient, Flags{info}, handle, coords, derivatives_dx, derivatives_dy,
|
||||||
|
offset, lod_clamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::ImageRead(const Value& handle, const Value& coords, TextureInstInfo info) {
|
Value IREmitter::ImageRead(const Value& handle, const Value& coords, TextureInstInfo info) {
|
||||||
@ -1553,6 +1567,38 @@ void IREmitter::ImageWrite(const Value& handle, const Value& coords, const Value
|
|||||||
Inst(Opcode::ImageWrite, Flags{info}, handle, coords, color);
|
Inst(Opcode::ImageWrite, Flags{info}, handle, coords, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Debug print maps to SPIRV's NonSemantic DebugPrintf instruction
|
||||||
|
// Renderdoc will hook in its own implementation of the SPIRV instruction
|
||||||
|
// Renderdoc accepts format specifiers, e.g. %u, listed here:
|
||||||
|
// https://github.com/KhronosGroup/Vulkan-ValidationLayers/blob/main/docs/debug_printf.md
|
||||||
|
//
|
||||||
|
// fmt must be a string literal (pointer is shallow copied into a Value)
|
||||||
|
// Example usage:
|
||||||
|
// ir.DebugPrint("invocation xyz: (%u, %u, %u)",
|
||||||
|
// {ir.GetVectorReg(IR::VectorReg::V0),
|
||||||
|
// ir.GetVectorReg(IR::VectorReg::V1),
|
||||||
|
// ir.GetVectorReg(IR::VectorReg::V2)});
|
||||||
|
void IREmitter::DebugPrint(const char* fmt, boost::container::small_vector<Value, 5> format_args) {
|
||||||
|
std::array<Value, DEBUGPRINT_NUM_FORMAT_ARGS> args;
|
||||||
|
|
||||||
|
ASSERT_MSG(format_args.size() < DEBUGPRINT_NUM_FORMAT_ARGS,
|
||||||
|
"DebugPrint only supports up to {} format args", DEBUGPRINT_NUM_FORMAT_ARGS);
|
||||||
|
|
||||||
|
for (int i = 0; i < format_args.size(); i++) {
|
||||||
|
args[i] = format_args[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = format_args.size(); i < DEBUGPRINT_NUM_FORMAT_ARGS; i++) {
|
||||||
|
args[i] = Inst(Opcode::Void);
|
||||||
|
}
|
||||||
|
|
||||||
|
IR::Value fmt_val{fmt};
|
||||||
|
|
||||||
|
DebugPrintFlags flags;
|
||||||
|
flags.num_args.Assign(format_args.size());
|
||||||
|
Inst(Opcode::DebugPrint, Flags{flags}, fmt_val, args[0], args[1], args[2], args[3]);
|
||||||
|
}
|
||||||
|
|
||||||
void IREmitter::EmitVertex() {
|
void IREmitter::EmitVertex() {
|
||||||
Inst(Opcode::EmitVertex);
|
Inst(Opcode::EmitVertex);
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include "shader_recompiler/info.h"
|
||||||
#include "shader_recompiler/ir/attribute.h"
|
#include "shader_recompiler/ir/attribute.h"
|
||||||
#include "shader_recompiler/ir/basic_block.h"
|
#include "shader_recompiler/ir/basic_block.h"
|
||||||
#include "shader_recompiler/ir/condition.h"
|
#include "shader_recompiler/ir/condition.h"
|
||||||
@ -43,6 +44,7 @@ public:
|
|||||||
void Epilogue();
|
void Epilogue();
|
||||||
void Discard();
|
void Discard();
|
||||||
void Discard(const U1& cond);
|
void Discard(const U1& cond);
|
||||||
|
void DebugPrint(const char* fmt, boost::container::small_vector<Value, 5> args);
|
||||||
|
|
||||||
void Barrier();
|
void Barrier();
|
||||||
void WorkgroupMemoryBarrier();
|
void WorkgroupMemoryBarrier();
|
||||||
@ -275,21 +277,26 @@ public:
|
|||||||
[[nodiscard]] Value ImageAtomicExchange(const Value& handle, const Value& coords,
|
[[nodiscard]] Value ImageAtomicExchange(const Value& handle, const Value& coords,
|
||||||
const Value& value, TextureInstInfo info);
|
const Value& value, TextureInstInfo info);
|
||||||
|
|
||||||
|
[[nodiscard]] Value ImageSampleRaw(const Value& handle, const Value& address1,
|
||||||
|
const Value& address2, const Value& address3,
|
||||||
|
const Value& address4, TextureInstInfo info);
|
||||||
|
|
||||||
[[nodiscard]] Value ImageSampleImplicitLod(const Value& handle, const Value& body,
|
[[nodiscard]] Value ImageSampleImplicitLod(const Value& handle, const Value& body,
|
||||||
const F32& bias, const U32& offset,
|
const F32& bias, const Value& offset,
|
||||||
TextureInstInfo info);
|
TextureInstInfo info);
|
||||||
|
|
||||||
[[nodiscard]] Value ImageSampleExplicitLod(const Value& handle, const Value& body,
|
[[nodiscard]] Value ImageSampleExplicitLod(const Value& handle, const Value& body,
|
||||||
const U32& offset, TextureInstInfo info);
|
const F32& lod, const Value& offset,
|
||||||
|
|
||||||
[[nodiscard]] F32 ImageSampleDrefImplicitLod(const Value& handle, const Value& body,
|
|
||||||
const F32& dref, const F32& bias,
|
|
||||||
const U32& offset, TextureInstInfo info);
|
|
||||||
|
|
||||||
[[nodiscard]] F32 ImageSampleDrefExplicitLod(const Value& handle, const Value& body,
|
|
||||||
const F32& dref, const U32& offset,
|
|
||||||
TextureInstInfo info);
|
TextureInstInfo info);
|
||||||
|
|
||||||
|
[[nodiscard]] Value ImageSampleDrefImplicitLod(const Value& handle, const Value& body,
|
||||||
|
const F32& dref, const F32& bias,
|
||||||
|
const Value& offset, TextureInstInfo info);
|
||||||
|
|
||||||
|
[[nodiscard]] Value ImageSampleDrefExplicitLod(const Value& handle, const Value& body,
|
||||||
|
const F32& dref, const F32& lod,
|
||||||
|
const Value& offset, TextureInstInfo info);
|
||||||
|
|
||||||
[[nodiscard]] Value ImageQueryDimension(const Value& handle, const U32& lod,
|
[[nodiscard]] Value ImageQueryDimension(const Value& handle, const U32& lod,
|
||||||
const U1& skip_mips);
|
const U1& skip_mips);
|
||||||
[[nodiscard]] Value ImageQueryDimension(const Value& handle, const U32& lod,
|
[[nodiscard]] Value ImageQueryDimension(const Value& handle, const U32& lod,
|
||||||
@ -304,8 +311,9 @@ public:
|
|||||||
[[nodiscard]] Value ImageFetch(const Value& handle, const Value& coords, const Value& offset,
|
[[nodiscard]] Value ImageFetch(const Value& handle, const Value& coords, const Value& offset,
|
||||||
const U32& lod, const U32& multisampling, TextureInstInfo info);
|
const U32& lod, const U32& multisampling, TextureInstInfo info);
|
||||||
[[nodiscard]] Value ImageGradient(const Value& handle, const Value& coords,
|
[[nodiscard]] Value ImageGradient(const Value& handle, const Value& coords,
|
||||||
const Value& derivatives, const Value& offset,
|
const Value& derivatives_dx, const Value& derivatives_dy,
|
||||||
const F32& lod_clamp, TextureInstInfo info);
|
const Value& offset, const F32& lod_clamp,
|
||||||
|
TextureInstInfo info);
|
||||||
[[nodiscard]] Value ImageRead(const Value& handle, const Value& coords, TextureInstInfo info);
|
[[nodiscard]] Value ImageRead(const Value& handle, const Value& coords, TextureInstInfo info);
|
||||||
void ImageWrite(const Value& handle, const Value& coords, const Value& color,
|
void ImageWrite(const Value& handle, const Value& coords, const Value& color,
|
||||||
TextureInstInfo info);
|
TextureInstInfo info);
|
||||||
|
@ -89,6 +89,7 @@ bool Inst::MayHaveSideEffects() const noexcept {
|
|||||||
case Opcode::ImageAtomicOr32:
|
case Opcode::ImageAtomicOr32:
|
||||||
case Opcode::ImageAtomicXor32:
|
case Opcode::ImageAtomicXor32:
|
||||||
case Opcode::ImageAtomicExchange32:
|
case Opcode::ImageAtomicExchange32:
|
||||||
|
case Opcode::DebugPrint:
|
||||||
case Opcode::EmitVertex:
|
case Opcode::EmitVertex:
|
||||||
case Opcode::EmitPrimitive:
|
case Opcode::EmitPrimitive:
|
||||||
return true;
|
return true;
|
||||||
|
@ -21,7 +21,7 @@ namespace Detail {
|
|||||||
struct OpcodeMeta {
|
struct OpcodeMeta {
|
||||||
std::string_view name;
|
std::string_view name;
|
||||||
Type type;
|
Type type;
|
||||||
std::array<Type, 5> arg_types;
|
std::array<Type, 6> arg_types;
|
||||||
};
|
};
|
||||||
|
|
||||||
// using enum Type;
|
// using enum Type;
|
||||||
@ -51,6 +51,7 @@ constexpr Type F32x4{Type::F32x4};
|
|||||||
constexpr Type F64x2{Type::F64x2};
|
constexpr Type F64x2{Type::F64x2};
|
||||||
constexpr Type F64x3{Type::F64x3};
|
constexpr Type F64x3{Type::F64x3};
|
||||||
constexpr Type F64x4{Type::F64x4};
|
constexpr Type F64x4{Type::F64x4};
|
||||||
|
constexpr Type StringLiteral{Type::StringLiteral};
|
||||||
|
|
||||||
constexpr OpcodeMeta META_TABLE[]{
|
constexpr OpcodeMeta META_TABLE[]{
|
||||||
#define OPCODE(name_token, type_token, ...) \
|
#define OPCODE(name_token, type_token, ...) \
|
||||||
@ -81,7 +82,7 @@ constexpr u8 NUM_ARGS[]{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get the number of arguments an opcode accepts
|
/// Get the number of arguments an opcode accepts
|
||||||
[[nodiscard]] inline size_t NumArgsOf(Opcode op) noexcept {
|
[[nodiscard]] constexpr inline size_t NumArgsOf(Opcode op) noexcept {
|
||||||
return static_cast<size_t>(Detail::NUM_ARGS[static_cast<size_t>(op)]);
|
return static_cast<size_t>(Detail::NUM_ARGS[static_cast<size_t>(op)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user