Merge branch 'main' into qt-style

This commit is contained in:
tomboylover93 2024-12-28 12:27:50 -03:00 committed by GitHub
commit a6e864f2e0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
34 changed files with 428 additions and 195 deletions

View File

@ -425,6 +425,8 @@ set(NP_LIBS src/core/libraries/np_manager/np_manager.cpp
set(MISC_LIBS src/core/libraries/screenshot/screenshot.cpp
src/core/libraries/screenshot/screenshot.h
src/core/libraries/move/move.cpp
src/core/libraries/move/move.h
)
set(DEV_TOOLS src/core/devtools/layer.cpp

View File

@ -121,6 +121,11 @@ R3 | M | |
- [**skmp**](https://github.com/skmp)
- [**wheremyfoodat**](https://github.com/wheremyfoodat)
- [**raziel1000**](https://github.com/raziel1000)
- [**viniciuslrangel**](https://github.com/viniciuslrangel)
- [**roamic**](https://github.com/vladmikhalin)
- [**poly**](https://github.com/polybiusproxy)
- [**squidbus**](https://github.com/squidbus)
- [**frodo**](https://github.com/baggins183)
Logo is done by [**Xphalnos**](https://github.com/Xphalnos)

View File

@ -97,6 +97,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
SUB(Lib, Http) \
SUB(Lib, Ssl) \
SUB(Lib, SysModule) \
SUB(Lib, Move) \
SUB(Lib, NpManager) \
SUB(Lib, NpScore) \
SUB(Lib, NpTrophy) \

View File

@ -57,8 +57,9 @@ enum class Class : u8 {
Lib_MsgDlg, ///< The LibSceMsgDialog implementation.
Lib_AudioOut, ///< The LibSceAudioOut implementation.
Lib_AudioIn, ///< The LibSceAudioIn implementation.
Lib_Move, ///< The LibSceMove implementation.
Lib_Net, ///< The LibSceNet implementation.
Lib_NetCtl, ///< The LibSecNetCtl implementation.
Lib_NetCtl, ///< The LibSceNetCtl implementation.
Lib_SaveData, ///< The LibSceSaveData implementation.
Lib_SaveDataDialog, ///< The LibSceSaveDataDialog implementation.
Lib_Ssl, ///< The LibSceSsl implementation.

View File

@ -26,7 +26,7 @@ asm(".zerofill GUEST_SYSTEM,GUEST_SYSTEM,__guest_system,0xFBFC00000");
namespace Core {
static constexpr size_t BackingSize = SCE_KERNEL_MAIN_DMEM_SIZE_PRO;
static constexpr size_t BackingSize = SCE_KERNEL_TOTAL_MEM_PRO;
#ifdef _WIN32

View File

@ -12,6 +12,7 @@
#include <atomic>
#include <limits>
#include <memory>
#include <optional>
#include <semaphore>
#include <span>
#include <vector>

View File

@ -5,7 +5,7 @@
#include <mutex>
#include <cubeb/cubeb.h>
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/ringbuffer.h"
#include "core/libraries/audio/audioout.h"
#include "core/libraries/audio/audioout_backend.h"
@ -58,6 +58,8 @@ public:
}
if (const auto ret = cubeb_stream_start(stream); ret != CUBEB_OK) {
LOG_ERROR(Lib_AudioOut, "Failed to start cubeb stream: {}", ret);
cubeb_stream_destroy(stream);
stream = nullptr;
return;
}
}
@ -74,6 +76,9 @@ public:
}
void Output(void* ptr, size_t size) override {
if (!stream) {
return;
}
auto* data = static_cast<u8*>(ptr);
std::unique_lock lock{buffer_mutex};

View File

@ -2,9 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <thread>
#include <SDL3/SDL_audio.h>
#include <SDL3/SDL_init.h>
#include "common/logging/log.h"
#include "core/libraries/audio/audioout.h"
@ -26,18 +24,28 @@ public:
SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &fmt, nullptr, nullptr);
if (stream == nullptr) {
LOG_ERROR(Lib_AudioOut, "Failed to create SDL audio stream: {}", SDL_GetError());
return;
}
if (!SDL_ResumeAudioStreamDevice(stream)) {
LOG_ERROR(Lib_AudioOut, "Failed to resume SDL audio stream: {}", SDL_GetError());
SDL_DestroyAudioStream(stream);
stream = nullptr;
return;
}
SDL_ResumeAudioStreamDevice(stream);
}
~SDLPortBackend() override {
if (stream) {
SDL_DestroyAudioStream(stream);
stream = nullptr;
if (!stream) {
return;
}
SDL_DestroyAudioStream(stream);
stream = nullptr;
}
void Output(void* ptr, size_t size) override {
if (!stream) {
return;
}
SDL_PutAudioStreamData(stream, ptr, static_cast<int>(size));
while (SDL_GetAudioStreamAvailable(stream) > AUDIO_STREAM_BUFFER_THRESHOLD) {
// Yield to allow the stream to drain.
@ -46,7 +54,15 @@ public:
}
void SetVolume(const std::array<int, 8>& ch_volumes) override {
// TODO: Not yet implemented
if (!stream) {
return;
}
// SDL does not have per-channel volumes, for now just take the maximum of the channels.
const auto vol = *std::ranges::max_element(ch_volumes);
if (!SDL_SetAudioStreamGain(stream, static_cast<float>(vol) / SCE_AUDIO_OUT_VOLUME_0DB)) {
LOG_WARNING(Lib_AudioOut, "Failed to change SDL audio stream volume: {}",
SDL_GetError());
}
}
private:

View File

@ -513,10 +513,14 @@ void PS4_SYSV_ABI sceGnmDingDong(u32 gnm_vqid, u32 next_offs_dw) {
auto vqid = gnm_vqid - 1;
auto& asc_queue = liverpool->asc_queues[{vqid}];
const auto& offs_dw = asc_next_offs_dw[vqid];
auto& offs_dw = asc_next_offs_dw[vqid];
if (next_offs_dw < offs_dw) {
ASSERT_MSG(next_offs_dw == 0, "ACB submission is split at the end of ring buffer");
if (next_offs_dw < offs_dw && next_offs_dw != 0) {
// For cases if a submission is split at the end of the ring buffer, we need to submit it in
// two parts to handle the wrap
liverpool->SubmitAsc(gnm_vqid, {reinterpret_cast<const u32*>(asc_queue.map_addr) + offs_dw,
asc_queue.ring_size_dw - offs_dw});
offs_dw = 0;
}
const auto* acb_ptr = reinterpret_cast<const u32*>(asc_queue.map_addr) + offs_dw;

View File

@ -6,9 +6,11 @@
#include "common/bit_field.h"
#include "common/types.h"
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
constexpr u64 SCE_KERNEL_TOTAL_MEM = 5248_MB;
constexpr u64 SCE_KERNEL_TOTAL_MEM_PRO = 5888_MB;
constexpr u64 SCE_FLEXIBLE_MEMORY_BASE = 64_MB;
constexpr u64 SCE_FLEXIBLE_MEMORY_SIZE = 512_MB;
namespace Core::Loader {
class SymbolsResolver;
@ -129,10 +131,6 @@ s32 PS4_SYSV_ABI sceKernelMemoryPoolDecommit(void* addr, size_t len, int flags);
int PS4_SYSV_ABI sceKernelMunmap(void* addr, size_t len);
void* Malloc(size_t size);
void Free(void* ptr);
void RegisterMemory(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::Kernel

View File

@ -18,6 +18,7 @@
#include "core/libraries/libc_internal/libc_internal.h"
#include "core/libraries/libpng/pngdec.h"
#include "core/libraries/libs.h"
#include "core/libraries/move/move.h"
#include "core/libraries/network/http.h"
#include "core/libraries/network/net.h"
#include "core/libraries/network/netctl.h"
@ -91,6 +92,7 @@ void InitHLELibs(Core::Loader::SymbolsResolver* sym) {
Libraries::Remoteplay::RegisterlibSceRemoteplay(sym);
Libraries::Videodec::RegisterlibSceVideodec(sym);
Libraries::RazorCpu::RegisterlibSceRazorCpu(sym);
Libraries::Move::RegisterlibSceMove(sym);
}
} // namespace Libraries

View File

@ -0,0 +1,44 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/libs.h"
#include "move.h"
namespace Libraries::Move {
int PS4_SYSV_ABI sceMoveOpen() {
LOG_ERROR(Lib_Move, "(STUBBED) called");
return ORBIS_FAIL;
}
int PS4_SYSV_ABI sceMoveGetDeviceInfo() {
LOG_ERROR(Lib_Move, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceMoveReadStateRecent() {
LOG_TRACE(Lib_Move, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceMoveTerm() {
LOG_ERROR(Lib_Move, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceMoveInit() {
LOG_ERROR(Lib_Move, "(STUBBED) called");
return ORBIS_OK;
}
void RegisterlibSceMove(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("HzC60MfjJxU", "libSceMove", 1, "libSceMove", 1, 1, sceMoveOpen);
LIB_FUNCTION("GWXTyxs4QbE", "libSceMove", 1, "libSceMove", 1, 1, sceMoveGetDeviceInfo);
LIB_FUNCTION("f2bcpK6kJfg", "libSceMove", 1, "libSceMove", 1, 1, sceMoveReadStateRecent);
LIB_FUNCTION("tsZi60H4ypY", "libSceMove", 1, "libSceMove", 1, 1, sceMoveTerm);
LIB_FUNCTION("j1ITE-EoJmE", "libSceMove", 1, "libSceMove", 1, 1, sceMoveInit);
};
} // namespace Libraries::Move

View File

@ -0,0 +1,21 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/types.h"
namespace Core::Loader {
class SymbolsResolver;
}
namespace Libraries::Move {
int PS4_SYSV_ABI sceMoveOpen();
int PS4_SYSV_ABI sceMoveGetDeviceInfo();
int PS4_SYSV_ABI sceMoveReadStateRecent();
int PS4_SYSV_ABI sceMoveTerm();
int PS4_SYSV_ABI sceMoveInit();
void RegisterlibSceMove(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::Move

View File

@ -498,7 +498,7 @@ int PS4_SYSV_ABI sceNpTrophyGetTrophyInfo(OrbisNpTrophyContext context, OrbisNpT
s32 PS4_SYSV_ABI sceNpTrophyGetTrophyUnlockState(OrbisNpTrophyContext context,
OrbisNpTrophyHandle handle,
OrbisNpTrophyFlagArray* flags, u32* count) {
LOG_INFO(Lib_NpTrophy, "GetTrophyUnlockState called");
LOG_INFO(Lib_NpTrophy, "called");
if (context == ORBIS_NP_TROPHY_INVALID_CONTEXT)
return ORBIS_NP_TROPHY_ERROR_INVALID_CONTEXT;
@ -519,8 +519,9 @@ s32 PS4_SYSV_ABI sceNpTrophyGetTrophyUnlockState(OrbisNpTrophyContext context,
pugi::xml_parse_result result = doc.load_file(trophy_file.native().c_str());
if (!result) {
LOG_ERROR(Lib_NpTrophy, "Failed to open trophy xml : {}", result.description());
return -1;
LOG_ERROR(Lib_NpTrophy, "Failed to open trophy XML: {}", result.description());
*count = 0;
return ORBIS_OK;
}
int num_trophies = 0;

View File

@ -5,6 +5,7 @@
#include "common/arch.h"
#include "common/assert.h"
#include "common/config.h"
#include "common/elf_info.h"
#include "common/logging/log.h"
#include "common/path_util.h"
#include "common/string_util.h"
@ -65,21 +66,41 @@ void Linker::Execute() {
Relocate(m.get());
}
// Configure used flexible memory size.
if (const auto* proc_param = GetProcParam()) {
if (proc_param->size >=
offsetof(OrbisProcParam, mem_param) + sizeof(OrbisKernelMemParam*)) {
if (const auto* mem_param = proc_param->mem_param) {
if (mem_param->size >=
offsetof(OrbisKernelMemParam, flexible_memory_size) + sizeof(u64*)) {
if (const auto* flexible_size = mem_param->flexible_memory_size) {
memory->SetupMemoryRegions(*flexible_size);
}
// Configure the direct and flexible memory regions.
u64 fmem_size = SCE_FLEXIBLE_MEMORY_SIZE;
bool use_extended_mem1 = true, use_extended_mem2 = true;
const auto* proc_param = GetProcParam();
ASSERT(proc_param);
Core::OrbisKernelMemParam mem_param{};
if (proc_param->size >= offsetof(OrbisProcParam, mem_param) + sizeof(OrbisKernelMemParam*)) {
if (proc_param->mem_param) {
mem_param = *proc_param->mem_param;
if (mem_param.size >=
offsetof(OrbisKernelMemParam, flexible_memory_size) + sizeof(u64*)) {
if (const auto* flexible_size = mem_param.flexible_memory_size) {
fmem_size = *flexible_size + SCE_FLEXIBLE_MEMORY_BASE;
}
}
}
}
if (mem_param.size < offsetof(OrbisKernelMemParam, extended_memory_1) + sizeof(u64*)) {
mem_param.extended_memory_1 = nullptr;
}
if (mem_param.size < offsetof(OrbisKernelMemParam, extended_memory_2) + sizeof(u64*)) {
mem_param.extended_memory_2 = nullptr;
}
const u64 sdk_ver = proc_param->sdk_version;
if (sdk_ver < Common::ElfInfo::FW_50) {
use_extended_mem1 = mem_param.extended_memory_1 ? *mem_param.extended_memory_1 : false;
use_extended_mem2 = mem_param.extended_memory_2 ? *mem_param.extended_memory_2 : false;
}
memory->SetupMemoryRegions(fmem_size, use_extended_mem1, use_extended_mem2);
main_thread.Run([this, module](std::stop_token) {
Common::SetCurrentThreadName("GAME_MainThread");
LoadSharedLibraries();

View File

@ -22,8 +22,9 @@ struct OrbisKernelMemParam {
u8* extended_memory_1;
u64* extended_gpu_page_table;
u8* extended_memory_2;
u64* exnteded_cpu_page_table;
u64* extended_cpu_page_table;
};
static_assert(sizeof(OrbisKernelMemParam) == 0x38);
struct OrbisProcParam {
u64 size;

View File

@ -12,12 +12,7 @@
namespace Core {
constexpr u64 SCE_DEFAULT_FLEXIBLE_MEMORY_SIZE = 448_MB;
MemoryManager::MemoryManager() {
// Set up the direct and flexible memory regions.
SetupMemoryRegions(SCE_DEFAULT_FLEXIBLE_MEMORY_SIZE);
// Insert a virtual memory area that covers the entire area we manage.
const VAddr system_managed_base = impl.SystemManagedVirtualBase();
const size_t system_managed_size = impl.SystemManagedVirtualSize();
@ -38,10 +33,17 @@ MemoryManager::MemoryManager() {
MemoryManager::~MemoryManager() = default;
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;
void MemoryManager::SetupMemoryRegions(u64 flexible_size, bool use_extended_mem1,
bool use_extended_mem2) {
const bool is_neo = Config::isNeoMode();
auto total_size = is_neo ? SCE_KERNEL_TOTAL_MEM_PRO : SCE_KERNEL_TOTAL_MEM;
if (!use_extended_mem1 && is_neo) {
total_size -= 256_MB;
}
if (!use_extended_mem2 && !is_neo) {
total_size -= 128_MB;
}
total_flexible_size = flexible_size - SCE_FLEXIBLE_MEMORY_BASE;
total_direct_size = total_size - flexible_size;
// Insert an area that covers direct memory physical block.

View File

@ -166,7 +166,7 @@ public:
bool TryWriteBacking(void* address, const void* data, u32 num_bytes);
void SetupMemoryRegions(u64 flexible_size);
void SetupMemoryRegions(u64 flexible_size, bool use_extended_mem1, bool use_extended_mem2);
PAddr PoolExpand(PAddr search_start, PAddr search_end, size_t size, u64 alignment);

View File

@ -4,11 +4,14 @@
#include "functional"
#include "iostream"
#include "string"
#include "system_error"
#include "unordered_map"
#include <fmt/core.h>
#include "common/config.h"
#include "common/memory_patcher.h"
#include "common/path_util.h"
#include "core/file_sys/fs.h"
#include "emulator.h"
#ifdef _WIN32
@ -20,6 +23,10 @@ int main(int argc, char* argv[]) {
SetConsoleOutputCP(CP_UTF8);
#endif
// Load configurations
const auto user_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
Config::load(user_dir / "config.toml");
bool has_game_argument = false;
std::string game_path;
@ -33,6 +40,7 @@ int main(int argc, char* argv[]) {
" -p, --patch <patch_file> Apply specified patch file\n"
" -f, --fullscreen <true|false> Specify window initial fullscreen "
"state. Does not overwrite the config file.\n"
" --add-game-folder <folder> Adds a new game folder to the config.\n"
" -h, --help Display this help message\n";
exit(0);
}},
@ -81,6 +89,25 @@ int main(int argc, char* argv[]) {
Config::setFullscreenMode(is_fullscreen);
}},
{"--fullscreen", [&](int& i) { arg_map["-f"](i); }},
{"--add-game-folder",
[&](int& i) {
if (++i >= argc) {
std::cerr << "Error: Missing argument for --add-game-folder\n";
exit(1);
}
std::string config_dir(argv[i]);
std::filesystem::path config_path = std::filesystem::path(config_dir);
std::error_code discard;
if (!std::filesystem::exists(config_path, discard)) {
std::cerr << "Error: File does not exist: " << config_path << "\n";
exit(1);
}
Config::addGameInstallDir(config_path);
Config::save(Common::FS::GetUserPath(Common::FS::PathType::UserDir) / "config.toml");
std::cout << "Game folder successfully saved.\n";
exit(0);
}},
};
if (argc == 1) {
@ -105,20 +132,41 @@ int main(int argc, char* argv[]) {
}
}
// If no game directory is set and no command line argument, prompt for it
if (Config::getGameInstallDirs().empty()) {
std::cout << "Warning: No game folder set, please set it by calling shadps4"
" with the --add-game-folder <folder_name> argument";
}
if (!has_game_argument) {
std::cerr << "Error: Please provide a game path or ID.\n";
exit(1);
}
// Check if the game path or ID exists
if (!std::filesystem::exists(game_path)) {
std::cerr << "Error: Game file not found\n";
return -1;
std::filesystem::path eboot_path(game_path);
// Check if the provided path is a valid file
if (!std::filesystem::exists(eboot_path)) {
// If not a file, treat it as a game ID and search in install directories
bool game_found = false;
for (const auto& install_dir : Config::getGameInstallDirs()) {
const auto candidate_path = install_dir / game_path / "eboot.bin";
if (std::filesystem::exists(candidate_path)) {
eboot_path = candidate_path;
game_found = true;
break;
}
}
if (!game_found) {
std::cerr << "Error: Game ID or file path not found: " << game_path << std::endl;
return 1;
}
}
// Run the emulator with the specified game
// Run the emulator with the resolved eboot path
Core::Emulator emulator;
emulator.Run(game_path);
emulator.Run(eboot_path);
return 0;
}

View File

@ -347,9 +347,8 @@ public:
if (selected == deleteUpdate) {
if (!std::filesystem::exists(Common::FS::PathFromQString(game_update_path))) {
QMessageBox::critical(
nullptr, tr("Error"),
QString(tr("This game has no separate update to delete!")));
QMessageBox::critical(nullptr, tr("Error"),
QString(tr("This game has no update to delete!")));
error = true;
} else {
folder_path = game_update_path;

View File

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "iostream"
#include "system_error"
#include "unordered_map"
#include "common/config.h"
@ -31,7 +32,7 @@ int main(int argc, char* argv[]) {
bool has_command_line_argument = argc > 1;
bool show_gui = false, has_game_argument = false;
std::string gamePath;
std::string game_path;
// Map of argument strings to lambda functions
std::unordered_map<std::string, std::function<void(int&)>> arg_map = {
@ -46,6 +47,7 @@ int main(int argc, char* argv[]) {
" -s, --show-gui Show the GUI\n"
" -f, --fullscreen <true|false> Specify window initial fullscreen "
"state. Does not overwrite the config file.\n"
" --add-game-folder <folder> Adds a new game folder to the config.\n"
" -h, --help Display this help message\n";
exit(0);
}},
@ -57,7 +59,7 @@ int main(int argc, char* argv[]) {
{"-g",
[&](int& i) {
if (i + 1 < argc) {
gamePath = argv[++i];
game_path = argv[++i];
has_game_argument = true;
} else {
std::cerr << "Error: Missing argument for -g/--game\n";
@ -98,6 +100,25 @@ int main(int argc, char* argv[]) {
Config::setFullscreenMode(is_fullscreen);
}},
{"--fullscreen", [&](int& i) { arg_map["-f"](i); }},
{"--add-game-folder",
[&](int& i) {
if (++i >= argc) {
std::cerr << "Error: Missing argument for --add-game-folder\n";
exit(1);
}
std::string config_dir(argv[i]);
std::filesystem::path config_path = std::filesystem::path(config_dir);
std::error_code discard;
if (!std::filesystem::is_directory(config_path, discard)) {
std::cerr << "Error: Directory does not exist: " << config_path << "\n";
exit(1);
}
Config::addGameInstallDir(config_path);
Config::save(Common::FS::GetUserPath(Common::FS::PathType::UserDir) / "config.toml");
std::cout << "Game folder successfully saved.\n";
exit(0);
}},
};
// Parse command-line arguments using the map
@ -106,6 +127,10 @@ int main(int argc, char* argv[]) {
auto it = arg_map.find(cur_arg);
if (it != arg_map.end()) {
it->second(i); // Call the associated lambda function
} else if (i == argc - 1 && !has_game_argument) {
// Assume the last argument is the game file if not specified via -g/--game
game_path = argv[i];
has_game_argument = true;
} else {
std::cerr << "Unknown argument: " << cur_arg << ", see --help for info.\n";
return 1;
@ -134,14 +159,14 @@ int main(int argc, char* argv[]) {
// Process game path or ID if provided
if (has_game_argument) {
std::filesystem::path game_file_path(gamePath);
std::filesystem::path game_file_path(game_path);
// Check if the provided path is a valid file
if (!std::filesystem::exists(game_file_path)) {
// If not a file, treat it as a game ID and search in install directories
bool game_found = false;
for (const auto& install_dir : Config::getGameInstallDirs()) {
auto potential_game_path = install_dir / gamePath / "eboot.bin";
auto potential_game_path = install_dir / game_path / "eboot.bin";
if (std::filesystem::exists(potential_game_path)) {
game_file_path = potential_game_path;
game_found = true;
@ -149,7 +174,7 @@ int main(int argc, char* argv[]) {
}
}
if (!game_found) {
std::cerr << "Error: Game ID or file path not found: " << gamePath << std::endl;
std::cerr << "Error: Game ID or file path not found: " << game_path << std::endl;
return 1;
}
}

View File

@ -115,6 +115,7 @@ void MainWindow::CreateActions() {
m_theme_act_group->addAction(ui->setThemeBlue);
m_theme_act_group->addAction(ui->setThemeViolet);
m_theme_act_group->addAction(ui->setThemeGruvbox);
m_theme_act_group->addAction(ui->setThemeTokyoNight);
m_theme_act_group->addAction(ui->setThemeSystem);
}
@ -572,6 +573,14 @@ void MainWindow::CreateConnects() {
isIconBlack = false;
}
});
connect(ui->setThemeTokyoNight, &QAction::triggered, &m_window_themes, [this]() {
m_window_themes.SetWindowTheme(Theme::TokyoNight, ui->mw_searchbar);
Config::setMainWindowTheme(static_cast<int>(Theme::TokyoNight));
if (isIconBlack) {
SetUiIcons(false);
isIconBlack = false;
}
});
connect(ui->setThemeSystem, &QAction::triggered, &m_window_themes, [this]() {
m_window_themes.SetWindowTheme(Theme::System, ui->mw_searchbar);
Config::setMainWindowTheme(static_cast<int>(Theme::System));
@ -980,6 +989,11 @@ void MainWindow::SetLastUsedTheme() {
isIconBlack = false;
SetUiIcons(false);
break;
case Theme::TokyoNight:
ui->setThemeTokyoNight->setChecked(true);
isIconBlack = false;
SetUiIcons(false);
break;
case Theme::System:
ui->setThemeSystem->setChecked(true);
bool isSystemDarkMode;

View File

@ -151,6 +151,28 @@ void WindowThemes::SetWindowTheme(Theme theme, QLineEdit* mw_searchbar) {
themePalette.setColor(QPalette::HighlightedText, Qt::black);
qApp->setPalette(themePalette);
break;
case Theme::TokyoNight:
mw_searchbar->setStyleSheet(
"QLineEdit {"
"background-color: #1a1b26; color: #9d7cd8; border: 1px solid #9d7cd8; "
"border-radius: 4px; padding: 5px; }"
"QLineEdit:focus {"
"border: 1px solid #7aa2f7; }");
themePalette.setColor(QPalette::Window, QColor(31, 35, 53));
themePalette.setColor(QPalette::WindowText, QColor(192, 202, 245));
themePalette.setColor(QPalette::Base, QColor(25, 28, 39));
themePalette.setColor(QPalette::AlternateBase, QColor(36, 40, 59));
themePalette.setColor(QPalette::ToolTipBase, QColor(192, 202, 245));
themePalette.setColor(QPalette::ToolTipText, QColor(192, 202, 245));
themePalette.setColor(QPalette::Text, QColor(192, 202, 245));
themePalette.setColor(QPalette::Button, QColor(30, 30, 41));
themePalette.setColor(QPalette::ButtonText, QColor(192, 202, 245));
themePalette.setColor(QPalette::BrightText, QColor(197, 59, 83));
themePalette.setColor(QPalette::Link, QColor(79, 214, 190));
themePalette.setColor(QPalette::Highlight, QColor(79, 214, 190));
themePalette.setColor(QPalette::HighlightedText, Qt::black);
qApp->setPalette(themePalette);
break;
case Theme::System:
mw_searchbar->setStyleSheet("QLineEdit {"
"border: 1px solid;"

View File

@ -9,7 +9,7 @@
#include <QStyleFactory>
#include <QWidget>
enum class Theme : int { Dark, Light, Green, Blue, Violet, Gruvbox, System };
enum class Theme : int { Dark, Light, Green, Blue, Violet, Gruvbox, TokyoNight, System };
class WindowThemes : public QObject {
Q_OBJECT

View File

@ -37,6 +37,7 @@ public:
QAction* setThemeBlue;
QAction* setThemeViolet;
QAction* setThemeGruvbox;
QAction* setThemeTokyoNight;
QAction* setThemeSystem;
QWidget* centralWidget;
QLineEdit* mw_searchbar;
@ -163,6 +164,9 @@ public:
setThemeGruvbox = new QAction(MainWindow);
setThemeGruvbox->setObjectName("setThemeGruvbox");
setThemeGruvbox->setCheckable(true);
setThemeTokyoNight = new QAction(MainWindow);
setThemeTokyoNight->setObjectName("setThemeTokyoNight");
setThemeTokyoNight->setCheckable(true);
setThemeSystem = new QAction(MainWindow);
setThemeSystem->setObjectName("setThemeSystem");
setThemeSystem->setCheckable(true);
@ -291,6 +295,7 @@ public:
menuThemes->addAction(setThemeBlue);
menuThemes->addAction(setThemeViolet);
menuThemes->addAction(setThemeGruvbox);
menuThemes->addAction(setThemeTokyoNight);
menuThemes->addAction(setThemeSystem);
menuGame_List_Icons->addAction(setIconSizeTinyAct);
menuGame_List_Icons->addAction(setIconSizeSmallAct);
@ -379,6 +384,7 @@ public:
setThemeBlue->setText(QCoreApplication::translate("MainWindow", "Blue", nullptr));
setThemeViolet->setText(QCoreApplication::translate("MainWindow", "Violet", nullptr));
setThemeGruvbox->setText("Gruvbox");
setThemeTokyoNight->setText("Tokyo Night");
setThemeSystem->setText(QCoreApplication::translate("MainWindow", "System", nullptr));
toolBar->setWindowTitle(QCoreApplication::translate("MainWindow", "toolBar", nullptr));
} // retranslateUi

View File

@ -200,7 +200,6 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices,
ui->fullscreenCheckBox->installEventFilter(this);
ui->separateUpdatesCheckBox->installEventFilter(this);
ui->showSplashCheckBox->installEventFilter(this);
ui->ps4proCheckBox->installEventFilter(this);
ui->discordRPCCheckbox->installEventFilter(this);
ui->userName->installEventFilter(this);
ui->logTypeGroupBox->installEventFilter(this);
@ -297,7 +296,6 @@ void SettingsDialog::LoadValuesFromConfig() {
ui->separateUpdatesCheckBox->setChecked(
toml::find_or<bool>(data, "General", "separateUpdateEnabled", false));
ui->showSplashCheckBox->setChecked(toml::find_or<bool>(data, "General", "showSplash", false));
ui->ps4proCheckBox->setChecked(toml::find_or<bool>(data, "General", "isPS4Pro", false));
ui->logTypeComboBox->setCurrentText(
QString::fromStdString(toml::find_or<std::string>(data, "General", "logType", "async")));
ui->logFilterLineEdit->setText(
@ -414,8 +412,6 @@ void SettingsDialog::updateNoteTextEdit(const QString& elementName) {
text = tr("separateUpdatesCheckBox");
} else if (elementName == "showSplashCheckBox") {
text = tr("showSplashCheckBox");
} else if (elementName == "ps4proCheckBox") {
text = tr("ps4proCheckBox");
} else if (elementName == "discordRPCCheckbox") {
text = tr("discordRPCCheckbox");
} else if (elementName == "userName") {
@ -528,11 +524,9 @@ void SettingsDialog::UpdateSettings() {
const QVector<std::string> TouchPadIndex = {"left", "center", "right", "none"};
Config::setBackButtonBehavior(TouchPadIndex[ui->backButtonBehaviorComboBox->currentIndex()]);
Config::setNeoMode(ui->ps4proCheckBox->isChecked());
Config::setFullscreenMode(ui->fullscreenCheckBox->isChecked());
Config::setisTrophyPopupDisabled(ui->disableTrophycheckBox->isChecked());
Config::setPlayBGM(ui->playBGMCheckBox->isChecked());
Config::setNeoMode(ui->ps4proCheckBox->isChecked());
Config::setLogType(ui->logTypeComboBox->currentText().toStdString());
Config::setLogFilter(ui->logFilterLineEdit->text().toStdString());
Config::setUserName(ui->userNameLineEdit->text().toStdString());
@ -609,4 +603,4 @@ void SettingsDialog::ResetInstallFolders() {
}
Config::setGameInstallDirs(settings_install_dirs_config);
}
}
}

View File

@ -246,13 +246,6 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="ps4proCheckBox">
<property name="text">
<string>Is PS4 Pro</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="discordRPCCheckbox">
<property name="text">

View File

@ -2,7 +2,7 @@
<!DOCTYPE TS>
<TS version="2.1" language="zh_CN">
<!-- SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
SPDX-License-Identifier: GPL-2.0-or-later -->
SPDX-License-Identifier: GPL-2.0-or-later -->
<context>
<name>AboutDialog</name>
<message>
@ -18,7 +18,7 @@
<message>
<location filename="../about_dialog.ui" line="78"/>
<source>shadPS4 is an experimental open-source emulator for the PlayStation 4.</source>
<translation>shadPS4 PlayStation 4</translation>
<translation>shadPS4 PlayStation 4 </translation>
</message>
<message>
<location filename="../about_dialog.ui" line="99"/>
@ -103,7 +103,7 @@
<message>
<location filename="../gui_context_menus.h" line="48"/>
<source>Cheats / Patches</source>
<translation> / </translation>
<translation>/</translation>
</message>
<message>
<location filename="../gui_context_menus.h" line="49"/>
@ -113,7 +113,7 @@
<message>
<location filename="../gui_context_menus.h" line="50"/>
<source>Trophy Viewer</source>
<translation>Trophy </translation>
<translation></translation>
</message>
<message>
<location filename="../gui_context_menus.h" line="49"/>
@ -128,7 +128,7 @@
<message>
<location filename="../gui_context_menus.h" line="51"/>
<source>Open Save Data Folder</source>
<translation></translation>
<translation></translation>
</message>
<message>
<location filename="../gui_context_menus.h" line="52"/>
@ -173,27 +173,27 @@
<message>
<location filename="../gui_context_menus.h" line="75"/>
<source>Delete DLC</source>
<translation>DLC</translation>
<translation> DLC</translation>
</message>
<message>
<location filename="../gui_context_menus.h" line="99"/>
<source>Compatibility...</source>
<translation>Compatibility...</translation>
<translation>...</translation>
</message>
<message>
<location filename="../gui_context_menus.h" line="100"/>
<source>Update database</source>
<translation>Update database</translation>
<translation></translation>
</message>
<message>
<location filename="../gui_context_menus.h" line="101"/>
<source>View report</source>
<translation>View report</translation>
<translation></translation>
</message>
<message>
<location filename="../gui_context_menus.h" line="102"/>
<source>Submit a report</source>
<translation>Submit a report</translation>
<translation></translation>
</message>
<message>
<location filename="../gui_context_menus.h" line="195"/>
@ -203,7 +203,7 @@
<message>
<location filename="../gui_context_menus.h" line="196"/>
<source>Shortcut created successfully!</source>
<translation>!</translation>
<translation></translation>
</message>
<message>
<location filename="../gui_context_menus.h" line="199"/>
@ -213,7 +213,7 @@
<message>
<location filename="../gui_context_menus.h" line="200"/>
<source>Error creating shortcut!</source>
<translation>!</translation>
<translation></translation>
</message>
<message>
<location filename="../gui_context_menus.h" line="275"/>
@ -228,7 +228,7 @@
<message>
<location filename="../gui_context_menus.h" line="305"/>
<source>requiresEnableSeparateUpdateFolder_MSG</source>
<translation>使</translation>
<translation>使</translation>
</message>
<message>
<location filename="../gui_context_menus.h" line="312"/>
@ -243,7 +243,7 @@
<message>
<location filename="../gui_context_menus.h" line="321"/>
<source>This game has no DLC to delete!</source>
<translation>DLC可以删除</translation>
<translation> DLC </translation>
</message>
<message>
<location filename="../gui_context_menus.h" line="325"/>
@ -258,7 +258,7 @@
<message>
<location filename="../gui_context_menus.h" line="333"/>
<source>Are you sure you want to delete %1's %2 directory?</source>
<translation> %1 %2 </translation>
<translation> %1 %2</translation>
</message>
</context>
<context>
@ -266,7 +266,7 @@
<message>
<location filename="../main_window_ui.h" line="310"/>
<source>Open/Add Elf Folder</source>
<translation>/Elf文件夹</translation>
<translation>/ Elf </translation>
</message>
<message>
<location filename="../main_window_ui.h" line="312"/>
@ -316,7 +316,7 @@
<message>
<location filename="../main_window_ui.h" line="327"/>
<source>Exit the application.</source>
<translation>退.</translation>
<translation>退</translation>
</message>
<message>
<location filename="../main_window_ui.h" line="330"/>
@ -341,12 +341,12 @@
<message>
<location filename="../main_window_ui.h" line="335"/>
<source>Medium</source>
<translation></translation>
<translation></translation>
</message>
<message>
<location filename="../main_window_ui.h" line="336"/>
<source>Large</source>
<translation></translation>
<translation></translation>
</message>
<message>
<location filename="../main_window_ui.h" line="338"/>
@ -376,7 +376,7 @@
<message>
<location filename="../main_window_ui.h" line="345"/>
<source>Dump Game List</source>
<translation></translation>
<translation></translation>
</message>
<message>
<location filename="../main_window_ui.h" line="346"/>
@ -472,7 +472,7 @@
<message>
<location filename="../trophy_viewer.cpp" line="8"/>
<source>Trophy Viewer</source>
<translation>Trophy </translation>
<translation></translation>
</message>
</context>
<context>
@ -485,7 +485,7 @@
<message>
<location filename="../settings_dialog.ui" line="67"/>
<source>General</source>
<translation></translation>
<translation></translation>
</message>
<message>
<location filename="../settings_dialog.ui" line="77"/>
@ -520,12 +520,12 @@
<message>
<location filename="../settings_dialog.ui" line="129"/>
<source>Show Splash</source>
<translation>Splash</translation>
<translation></translation>
</message>
<message>
<location filename="../settings_dialog.ui" line="136"/>
<source>Is PS4 Pro</source>
<translation> PS4 Pro</translation>
<translation> PS4 Pro</translation>
</message>
<message>
<location filename="../settings_dialog.ui" line="154"/>
@ -570,17 +570,17 @@
<message>
<location filename="../settings_dialog.ui" line="668"/>
<source>Hide Cursor Idle Timeout</source>
<translation></translation>
<translation></translation>
</message>
<message>
<location filename="../settings_dialog.ui" line="816"/>
<source>s</source>
<translation>s</translation>
<translation></translation>
</message>
<message>
<location filename="../settings_dialog.ui" line="767"/>
<source>Controller</source>
<translation></translation>
<translation></translation>
</message>
<message>
<location filename="../settings_dialog.ui" line="797"/>
@ -595,7 +595,7 @@
<message>
<location filename="../settings_dialog.ui" line="282"/>
<source>Graphics Device</source>
<translation></translation>
<translation></translation>
</message>
<message>
<location filename="../settings_dialog.ui" line="326"/>
@ -700,7 +700,7 @@
<message>
<location filename="../settings_dialog.ui" line="475"/>
<source>Disable Trophy Pop-ups</source>
<translation>Disable Trophy Pop-ups</translation>
<translation></translation>
</message>
<message>
<location filename="../settings_dialog.ui" line="375"/>
@ -710,22 +710,22 @@
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database On Startup</source>
<translation>Update Compatibility Database On Startup</translation>
<translation></translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Game Compatibility</source>
<translation>Game Compatibility</translation>
<translation></translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Display Compatibility Data</source>
<translation>Display Compatibility Data</translation>
<translation></translation>
</message>
<message>
<location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database</source>
<translation>Update Compatibility Database</translation>
<translation></translation>
</message>
<message>
<location filename="../settings_dialog.ui" line="394"/>
@ -735,7 +735,7 @@
<message>
<location filename="../settings_dialog.ui"/>
<source>Audio Backend</source>
<translation>Audio Backend</translation>
<translation></translation>
</message>
</context>
<context>
@ -778,12 +778,12 @@
<message>
<location filename="../main_window.cpp" line="392"/>
<source>All Patches available for all games have been downloaded.</source>
<translation></translation>
<translation></translation>
</message>
<message>
<location filename="../main_window.cpp" line="549"/>
<source>Games: </source>
<translation>: </translation>
<translation></translation>
</message>
<message>
<location filename="../main_window.cpp" line="575"/>
@ -798,7 +798,7 @@
<message>
<location filename="../main_window.cpp" line="600"/>
<source>Game Boot</source>
<translation></translation>
<translation></translation>
</message>
<message>
<location filename="../main_window.cpp" line="600"/>
@ -818,7 +818,7 @@
<message>
<location filename="../main_window.cpp" line="646"/>
<source>PKG and Game versions match: </source>
<translation>PKG : </translation>
<translation>PKG </translation>
</message>
<message>
<location filename="../main_window.cpp" line="647"/>
@ -828,17 +828,17 @@
<message>
<location filename="../main_window.cpp" line="639"/>
<source>PKG Version %1 is older than installed version: </source>
<translation>PKG %1 : </translation>
<translation>PKG %1 </translation>
</message>
<message>
<location filename="../main_window.cpp" line="660"/>
<source>Game is installed: </source>
<translation>: </translation>
<translation></translation>
</message>
<message>
<location filename="../main_window.cpp" line="660"/>
<source>Would you like to install Patch: </source>
<translation>: </translation>
<translation></translation>
</message>
<message>
<location filename="../main_window.cpp" line="673"/>
@ -848,12 +848,12 @@
<message>
<location filename="../main_window.cpp" line="674"/>
<source>Would you like to install DLC: %1?</source>
<translation> DLC: %1 </translation>
<translation> DLC%1 </translation>
</message>
<message>
<location filename="../main_window.cpp" line="688"/>
<source>DLC already installed:</source>
<translation>DLC :</translation>
<translation>DLC </translation>
</message>
<message>
<location filename="../main_window.cpp" line="701"/>
@ -896,42 +896,42 @@
<message>
<location filename="../cheats_patches.cpp" line="44"/>
<source>Cheats / Patches for </source>
<translation>Cheats / Patches for </translation>
<translation>/</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="50"/>
<source>defaultTextEdit_MSG</source>
<translation>/\n请小心使用\n\n通过选择存储库并点击下载按钮\n在使\n\n由于我们不开发作弊程序/\n请将问题报告给作弊程序的作者\n\n创建了新的作弊程序访\nhttps://github.com/shadps4-emu/ps4_cheats</translation>
<translation>/\n请小心使用\n\n通过选择存储库并点击下载按钮\n在使\n\n由于我们不开发作弊/\n请将问题报告给作弊码/\n\n创建了新的作弊码/\nhttps://github.com/shadps4-emu/ps4_cheats</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="69"/>
<source>No Image Available</source>
<translation></translation>
<translation></translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="79"/>
<source>Serial: </source>
<translation>: </translation>
<translation></translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="83"/>
<source>Version: </source>
<translation>: </translation>
<translation></translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="87"/>
<source>Size: </source>
<translation>: </translation>
<translation></translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="126"/>
<source>Select Cheat File:</source>
<translation>:</translation>
<translation></translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="133"/>
<source>Repository:</source>
<translation>:</translation>
<translation></translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="149"/>
@ -961,7 +961,7 @@
<message>
<location filename="../cheats_patches.cpp" line="213"/>
<source>Select Patch File:</source>
<translation>:</translation>
<translation></translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="241"/>
@ -1016,7 +1016,7 @@
<message>
<location filename="../cheats_patches.cpp" line="432"/>
<source>Failed to parse XML: </source>
<translation> XML : </translation>
<translation> XML </translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="434"/>
@ -1046,17 +1046,17 @@
<message>
<location filename="../cheats_patches.cpp" line="520"/>
<source>File already exists. Do you want to replace it?</source>
<translation></translation>
<translation></translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="539"/>
<source>Failed to save file:</source>
<translation>:</translation>
<translation></translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="545"/>
<source>Failed to download file:</source>
<translation>:</translation>
<translation></translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="556"/>
@ -1076,17 +1076,17 @@
<message>
<location filename="../cheats_patches.cpp" line="594"/>
<source>CheatsDownloadedSuccessfully_MSG</source>
<translation> 使</translation>
<translation>使</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="747"/>
<source>Failed to save:</source>
<translation>:</translation>
<translation></translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="754"/>
<source>Failed to download:</source>
<translation>:</translation>
<translation></translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="762"/>
@ -1096,7 +1096,7 @@
<message>
<location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source>
<translation></translation>
<translation></translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="773"/>
@ -1111,12 +1111,12 @@
<message>
<location filename="../cheats_patches.cpp" line="850"/>
<source>The game is in version: %1</source>
<translation>: %1</translation>
<translation>%1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="851"/>
<source>The downloaded patch only works on version: %1</source>
<translation>: %1</translation>
<translation>%1</translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="856"/>
@ -1131,12 +1131,12 @@
<message>
<location filename="../cheats_patches.cpp" line="801"/>
<source>Failed to open file:</source>
<translation>:</translation>
<translation></translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="819"/>
<source>XML ERROR:</source>
<translation>XML :</translation>
<translation>XML </translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="826"/>
@ -1146,12 +1146,12 @@
<message>
<location filename="../cheats_patches.cpp" line="925"/>
<source>Author: </source>
<translation>: </translation>
<translation></translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="997"/>
<source>Directory does not exist:</source>
<translation>:</translation>
<translation></translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="1006"/>
@ -1161,12 +1161,12 @@
<message>
<location filename="../cheats_patches.cpp" line="1006"/>
<source>Name:</source>
<translation>:</translation>
<translation></translation>
</message>
<message>
<location filename="../cheats_patches.cpp" line="1163"/>
<source>Can't apply cheats before the game is started</source>
<translation></translation>
<translation></translation>
</message>
</context>
<context>
@ -1199,17 +1199,17 @@
<message>
<location filename="../settings_dialog.cpp" line="289"/>
<source>consoleLanguageGroupBox</source>
<translation>:\n设置 PS4 使\n建议设置为支持的语言</translation>
<translation>\n设置 PS4 使\n建议设置为支持的语言</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="291"/>
<source>emulatorLanguageGroupBox</source>
<translation>:\n设置模拟器用户界面的语言</translation>
<translation>\n设置模拟器用户界面的语言</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="293"/>
<source>fullscreenCheckBox</source>
<translation>:\n自动将游戏窗口设置为全屏模式\n您可以按 F11 </translation>
<translation>\n以全屏模式启动游戏\n您可以按 F11 </translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="293"/>
@ -1219,77 +1219,77 @@
<message>
<location filename="../settings_dialog.cpp" line="295"/>
<source>showSplashCheckBox</source>
<translation>:\n在游戏启动时显示游戏的启动画面</translation>
<translation>\n在游戏启动时显示游戏的启动画面</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="297"/>
<source>ps4proCheckBox</source>
<translation> PS4 Pro:\n使模拟器作为 PS4 PRO </translation>
<translation> PS4 Pro:\n使模拟器作为 PS4 Pro </translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="438"/>
<source>discordRPCCheckbox</source>
<translation> Discord Rich Presence:\n在您的 Discord 仿</translation>
<translation> Discord Rich Presence\n在您的 Discord </translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="299"/>
<source>userName</source>
<translation>:\n设置 PS4 </translation>
<translation>\n设置 PS4 </translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="301"/>
<source>logTypeGroupBox</source>
<translation>:\n设置是否同步日志窗口的输出以提高性能</translation>
<translation>\n设置日志窗口输出的同步方式以提高性能</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="303"/>
<source>logFilter</source>
<translation>:\n过滤日志\n例如"Core:Trace" "Lib.Pad:Debug Common.Filesystem:Error" "*:Critical" 级别: Trace, Debug, Info, Warning, Error, Critical - </translation>
<translation>\n过滤日志\n例如"Core:Trace" "Lib.Pad:Debug Common.Filesystem:Error" "*:Critical" 级别: Trace, Debug, Info, Warning, Error, Critical - </translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="305"/>
<source>updaterGroupBox</source>
<translation>:\nRelease: 官方版本\nNightly: 开发版本</translation>
<translation>\nRelease\nNightly</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="306"/>
<source>GUIgroupBox</source>
<translation>:\n如果游戏支持</translation>
<translation>\n如果游戏支持</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="267"/>
<source>disableTrophycheckBox</source>
<translation>Disable Trophy Pop-ups:\nDisable in-game trophy notifications. Trophy progress can still be tracked using the Trophy Viewer (right-click the game in the main window).</translation>
<translation>\n禁用游戏内奖杯通知</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="450"/>
<source>hideCursorGroupBox</source>
<translation>:\n选择光标何时消失:\n从不: 您将始终看到鼠标\n空闲: 设置光标在空闲后消失的时间\n始终: 您将永远看不到鼠</translation>
<translation>\n选择光标何时消失:\n从不: 始终显示光标\闲置: 光标在闲置若干秒后消失\n始终: 始终显示光</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="452"/>
<source>idleTimeoutGroupBox</source>
<translation></translation>
<translation>\n光标自动隐藏之前的闲置时长</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="454"/>
<source>backButtonBehaviorGroupBox</source>
<translation>:\n设置控制器的返回按钮以模拟在 PS4 </translation>
<translation>\n设置手柄的返回按钮模拟在 PS4 </translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>enableCompatibilityCheckBox</source>
<translation>Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information.</translation>
<translation>\n在列表视图中显示游戏兼容性信息</translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>checkCompatibilityOnStartupCheckBox</source>
<translation>Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts.</translation>
<translation>\n当 shadPS4 </translation>
</message>
<message>
<location filename="../settings_dialog.cpp"/>
<source>updateCompatibilityButton</source>
<translation>Update Compatibility Database:\nImmediately update the compatibility database.</translation>
<translation>\n立即更新兼容性数据库</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="70"/>
@ -1299,7 +1299,7 @@
<message>
<location filename="../settings_dialog.cpp" line="71"/>
<source>Idle</source>
<translation></translation>
<translation></translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="72"/>
@ -1329,62 +1329,62 @@
<message>
<location filename="../settings_dialog.cpp" line="312"/>
<source>graphicsAdapterGroupBox</source>
<translation>:\n在具有多个 GPU 使 GPU\n或者选择</translation>
<translation>\n在具有多个 GPU 使 GPU\n或者选择</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="314"/>
<source>resolutionLayout</source>
<translation>/:\n设置启动时模拟器的窗口大小\n这与游戏中的分辨率不同</translation>
<translation>/\n设置启动游戏时的窗口大小\n这与游戏内的分辨率不同</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="318"/>
<source>heightDivider</source>
<translation>Vblank :\n模拟器更新的帧速率乘以此数字!</translation>
<translation>Vblank Divider\n模拟器刷新的帧率会乘以此数字</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="320"/>
<source>dumpShadersCheckBox</source>
<translation>:\n为了技术调试</translation>
<translation>\n用于技术调试</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="322"/>
<source>nullGpuCheckBox</source>
<translation> GPU:\n为了技术调试仿</translation>
<translation> NULL GPU\n用于技术调试</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="465"/>
<source>gameFoldersBox</source>
<translation>:\n检查已安装游戏的文件夹列表</translation>
<translation>\n检查已安装游戏的文件夹列表</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="465"/>
<source>addFolderButton</source>
<translation>:\n将文件夹添加到列表</translation>
<translation>\n将文件夹添加到列表</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="465"/>
<source>removeFolderButton</source>
<translation>:\n从列表中移除文件夹</translation>
<translation>\n从列表中移除文件夹</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="329"/>
<source>debugDump</source>
<translation>:\n将当前正在运行的 PS4 </translation>
<translation>\n将当前正在运行的 PS4 </translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="331"/>
<source>vkValidationCheckBox</source>
<translation> Vulkan :\n启用验证 Vulkan </translation>
<translation> Vulkan \n启用一个系统来验证 Vulkan \n这将降低性能并可能改变模拟的行</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="333"/>
<source>vkSyncValidationCheckBox</source>
<translation> Vulkan :\n启用验证 Vulkan </translation>
<translation> Vulkan \n启用一个系统来验证 Vulkan \n这将降低性能并可能改变模拟的行</translation>
</message>
<message>
<location filename="../settings_dialog.cpp" line="335"/>
<source>rdocCheckBox</source>
<translation> RenderDoc :\n如果启用Renderdoc </translation>
<translation> RenderDoc :\n启用后模拟器将提供Renderdoc </translation>
</message>
</context>
<context>
@ -1407,7 +1407,7 @@
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility</source>
<translation>Compatibility</translation>
<translation></translation>
</message>
<message>
<location filename="../game_list_frame.cpp" line="34"/>
@ -1442,52 +1442,52 @@
<message>
<location filename="../game_list_frame.cpp" line="108"/>
<source>Never Played</source>
<translation>Never Played</translation>
<translation></translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>h</source>
<translation>h</translation>
<translation></translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>m</source>
<translation>m</translation>
<translation></translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>s</source>
<translation>s</translation>
<translation></translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Compatibility is untested</source>
<translation>Compatibility is untested</translation>
<translation></translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game does not initialize properly / crashes the emulator</source>
<translation>Game does not initialize properly / crashes the emulator</translation>
<translation>/</translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game boots, but only displays a blank screen</source>
<translation>Game boots, but only displays a blank screen</translation>
<translation></translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game displays an image but does not go past the menu</source>
<translation>Game displays an image but does not go past the menu</translation>
<translation></translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game has game-breaking glitches or unplayable performance</source>
<translation>Game has game-breaking glitches or unplayable performance</translation>
<translation> Bug </translation>
</message>
<message>
<location filename="../game_list_frame.cpp"/>
<source>Game can be completed with playable performance and no major glitches</source>
<translation>Game can be completed with playable performance and no major glitches</translation>
<translation> Bug</translation>
</message>
</context>
<context>
@ -1525,7 +1525,7 @@
<message>
<location filename="../check_update.cpp" line="142"/>
<source>No download URL found for the specified asset.</source>
<translation> URL</translation>
<translation></translation>
</message>
<message>
<location filename="../check_update.cpp" line="148"/>
@ -1560,7 +1560,7 @@
<message>
<location filename="../check_update.cpp" line="193"/>
<source>Show Changelog</source>
<translation></translation>
<translation></translation>
</message>
<message>
<location filename="../check_update.cpp" line="198"/>
@ -1580,17 +1580,17 @@
<message>
<location filename="../check_update.cpp" line="223"/>
<source>Hide Changelog</source>
<translation></translation>
<translation></translation>
</message>
<message>
<location filename="../check_update.cpp" line="296"/>
<source>Changes</source>
<translation></translation>
<translation></translation>
</message>
<message>
<location filename="../check_update.cpp" line="310"/>
<source>Network error occurred while trying to access the URL</source>
<translation>访 URL </translation>
<translation>访</translation>
</message>
<message>
<location filename="../check_update.cpp" line="330"/>
@ -1646,4 +1646,4 @@
<translation>TB</translation>
</message>
</context>
</TS>
</TS>

View File

@ -24,9 +24,11 @@ static constexpr spv::ExecutionMode GetInputPrimitiveType(AmdGpu::PrimitiveType
case AmdGpu::PrimitiveType::PointList:
return spv::ExecutionMode::InputPoints;
case AmdGpu::PrimitiveType::LineList:
case AmdGpu::PrimitiveType::LineStrip:
return spv::ExecutionMode::InputLines;
case AmdGpu::PrimitiveType::TriangleList:
case AmdGpu::PrimitiveType::TriangleStrip:
case AmdGpu::PrimitiveType::RectList:
return spv::ExecutionMode::Triangles;
case AmdGpu::PrimitiveType::AdjTriangleList:
return spv::ExecutionMode::InputTrianglesAdjacency;

View File

@ -43,9 +43,11 @@ static constexpr u32 NumVertices(AmdGpu::PrimitiveType type) {
case AmdGpu::PrimitiveType::PointList:
return 1u;
case AmdGpu::PrimitiveType::LineList:
case AmdGpu::PrimitiveType::LineStrip:
return 2u;
case AmdGpu::PrimitiveType::TriangleList:
case AmdGpu::PrimitiveType::TriangleStrip:
case AmdGpu::PrimitiveType::RectList:
return 3u;
case AmdGpu::PrimitiveType::AdjTriangleList:
return 6u;

View File

@ -3565,8 +3565,8 @@ constexpr std::array<InstFormat, 112> InstructionFormatMIMG = {{
{InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Float32,
ScalarType::Float32},
// 64 = IMAGE_GATHER4
{InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined,
ScalarType::Undefined},
{InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32,
ScalarType::Float32},
// 65 = IMAGE_GATHER4_CL
{InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined,
ScalarType::Undefined},
@ -3603,10 +3603,10 @@ constexpr std::array<InstFormat, 112> InstructionFormatMIMG = {{
ScalarType::Undefined},
// 79 = IMAGE_GATHER4_C_LZ
{InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32,
ScalarType::Uint32},
ScalarType::Float32},
// 80 = IMAGE_GATHER4_O
{InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined,
ScalarType::Undefined},
{InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32,
ScalarType::Float32},
// 81 = IMAGE_GATHER4_CL_O
{InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined,
ScalarType::Undefined},

View File

@ -144,8 +144,10 @@ void Translator::EmitVectorMemory(const GcnInst& inst) {
return IMAGE_SAMPLE(inst);
// Image gather operations
case Opcode::IMAGE_GATHER4:
case Opcode::IMAGE_GATHER4_LZ:
case Opcode::IMAGE_GATHER4_C:
case Opcode::IMAGE_GATHER4_O:
case Opcode::IMAGE_GATHER4_C_O:
case Opcode::IMAGE_GATHER4_C_LZ:
case Opcode::IMAGE_GATHER4_LZ_O:

View File

@ -447,7 +447,7 @@ struct Sampler {
}
float MaxAniso() const {
switch (max_aniso) {
switch (max_aniso.Value()) {
case AnisoRatio::One:
return 1.0f;
case AnisoRatio::Two:

View File

@ -18,7 +18,8 @@ Sampler::Sampler(const Vulkan::Instance& instance, const AmdGpu::Sampler& sample
(AmdGpu::IsAnisoFilter(sampler.xy_mag_filter) ||
AmdGpu::IsAnisoFilter(sampler.xy_min_filter));
const float maxAnisotropy =
std::clamp(sampler.MaxAniso(), 1.0f, instance.MaxSamplerAnisotropy());
anisotropyEnable ? std::clamp(sampler.MaxAniso(), 1.0f, instance.MaxSamplerAnisotropy())
: 1.0f;
const vk::SamplerCreateInfo sampler_ci = {
.magFilter = LiverpoolToVK::Filter(sampler.xy_mag_filter),
.minFilter = LiverpoolToVK::Filter(sampler.xy_min_filter),