This commit is contained in:
Valdis Bogdāns 2025-07-20 19:56:19 +00:00 committed by GitHub
commit 16e6231f1e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
42 changed files with 458 additions and 597 deletions

View File

@ -17,7 +17,7 @@ body:
This repository does not provide support for game patches. If you are having issues with patches please refer to [Cheats and Patches Repository](https://github.com/shadps4-emu/ps4_cheats). This repository does not provide support for game patches. If you are having issues with patches please refer to [Cheats and Patches Repository](https://github.com/shadps4-emu/ps4_cheats).
Before submitting an issue please check [Game Compatibility Repository](https://github.com/shadps4-compatibility/shadps4-game-compatibility) for the information about the status of the game. Before submitting an issue please check [Game Compatibility Repository](https://github.com/shadps4-emu/shadps4-game-compatibility) for the information about the status of the game.
Please make an effort to make sure your issue isn't already reported. Please make an effort to make sure your issue isn't already reported.

View File

@ -126,7 +126,7 @@ execute_process(
# If there's no upstream set or the command failed, check remote.pushDefault # If there's no upstream set or the command failed, check remote.pushDefault
if (GIT_REMOTE_RESULT OR GIT_REMOTE_NAME STREQUAL "") if (GIT_REMOTE_RESULT OR GIT_REMOTE_NAME STREQUAL "")
message(STATUS "check default push") message("check default push")
execute_process( execute_process(
COMMAND git config --get remote.pushDefault COMMAND git config --get remote.pushDefault
OUTPUT_VARIABLE GIT_REMOTE_NAME OUTPUT_VARIABLE GIT_REMOTE_NAME
@ -134,30 +134,30 @@ if (GIT_REMOTE_RESULT OR GIT_REMOTE_NAME STREQUAL "")
ERROR_QUIET ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_STRIP_TRAILING_WHITESPACE
) )
message(STATUS "got remote: ${GIT_REMOTE_NAME}") message("got remote: ${GIT_REMOTE_NAME}")
endif() endif()
# If running in GitHub Actions and the above fails # If running in GitHub Actions and the above fails
if (GIT_REMOTE_RESULT OR GIT_REMOTE_NAME STREQUAL "") if (GIT_REMOTE_RESULT OR GIT_REMOTE_NAME STREQUAL "")
message(STATUS "check github") message("check github")
set(GIT_REMOTE_NAME "origin") set(GIT_REMOTE_NAME "origin")
# Retrieve environment variables # Retrieve environment variables
if (DEFINED ENV{GITHUB_HEAD_REF} AND NOT "$ENV{GITHUB_HEAD_REF}" STREQUAL "") if (DEFINED ENV{GITHUB_HEAD_REF} AND NOT "$ENV{GITHUB_HEAD_REF}" STREQUAL "")
message(STATUS "github head ref: $ENV{GITHUB_HEAD_REF}") message("github head ref: $ENV{GITHUB_HEAD_REF}")
set(GITHUB_HEAD_REF "$ENV{GITHUB_HEAD_REF}") set(GITHUB_HEAD_REF "$ENV{GITHUB_HEAD_REF}")
else() else()
set(GITHUB_HEAD_REF "") set(GITHUB_HEAD_REF "")
endif() endif()
if (DEFINED ENV{GITHUB_REF} AND NOT "$ENV{GITHUB_REF}" STREQUAL "") if (DEFINED ENV{GITHUB_REF} AND NOT "$ENV{GITHUB_REF}" STREQUAL "")
message(STATUS "github ref: $ENV{GITHUB_REF}") message("github ref: $ENV{GITHUB_REF}")
string(REGEX REPLACE "^refs/[^/]*/" "" GITHUB_BRANCH "$ENV{GITHUB_REF}") string(REGEX REPLACE "^refs/[^/]*/" "" GITHUB_BRANCH "$ENV{GITHUB_REF}")
string(REGEX MATCH "refs/pull/([0-9]+)/merge" MATCHED_REF "$ENV{GITHUB_REF}") string(REGEX MATCH "refs/pull/([0-9]+)/merge" MATCHED_REF "$ENV{GITHUB_REF}")
if (MATCHED_REF) if (MATCHED_REF)
set(PR_NUMBER "${CMAKE_MATCH_1}") set(PR_NUMBER "${CMAKE_MATCH_1}")
set(GITHUB_BRANCH "") set(GITHUB_BRANCH "")
message(STATUS "PR number: ${PR_NUMBER}") message("PR number: ${PR_NUMBER}")
else() else()
set(PR_NUMBER "") set(PR_NUMBER "")
endif() endif()
@ -179,7 +179,7 @@ if (GIT_REMOTE_RESULT OR GIT_REMOTE_NAME STREQUAL "")
elseif ("${PR_NUMBER}" STREQUAL "" AND NOT "${GITHUB_REF}" STREQUAL "") elseif ("${PR_NUMBER}" STREQUAL "" AND NOT "${GITHUB_REF}" STREQUAL "")
set(GIT_BRANCH "${GITHUB_REF}") set(GIT_BRANCH "${GITHUB_REF}")
elseif("${GIT_BRANCH}" STREQUAL "") elseif("${GIT_BRANCH}" STREQUAL "")
message(STATUS "couldn't find branch") message("couldn't find branch")
set(GIT_BRANCH "detached-head") set(GIT_BRANCH "detached-head")
endif() endif()
else() else()
@ -188,13 +188,13 @@ else()
if (INDEX GREATER -1) if (INDEX GREATER -1)
string(SUBSTRING "${GIT_REMOTE_NAME}" 0 "${INDEX}" GIT_REMOTE_NAME) string(SUBSTRING "${GIT_REMOTE_NAME}" 0 "${INDEX}" GIT_REMOTE_NAME)
elseif("${GIT_REMOTE_NAME}" STREQUAL "") elseif("${GIT_REMOTE_NAME}" STREQUAL "")
message(STATUS "reset to origin") message("reset to origin")
set(GIT_REMOTE_NAME "origin") set(GIT_REMOTE_NAME "origin")
endif() endif()
endif() endif()
# Get remote link # Get remote link
message(STATUS "getting remote link") message("getting remote link")
execute_process( execute_process(
COMMAND git config --get remote.${GIT_REMOTE_NAME}.url COMMAND git config --get remote.${GIT_REMOTE_NAME}.url
OUTPUT_VARIABLE GIT_REMOTE_URL OUTPUT_VARIABLE GIT_REMOTE_URL
@ -212,12 +212,7 @@ set(APP_VERSION "${EMULATOR_VERSION_MAJOR}.${EMULATOR_VERSION_MINOR}.${EMULATOR_
set(APP_IS_RELEASE false) set(APP_IS_RELEASE false)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/common/scm_rev.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/src/common/scm_rev.cpp" @ONLY) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/common/scm_rev.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/src/common/scm_rev.cpp" @ONLY)
message("-- end git things, remote: ${GIT_REMOTE_NAME}, branch: ${GIT_BRANCH}, link: ${GIT_REMOTE_URL}") message("end git things, remote: ${GIT_REMOTE_NAME}, branch: ${GIT_BRANCH}")
if(NOT GIT_REMOTE_URL MATCHES "shadps4-emu/shadPS4" OR NOT GIT_BRANCH STREQUAL "main")
message(STATUS "not main, disabling auto update")
set(ENABLE_UPDATER OFF)
endif()
if(WIN32 AND ENABLE_QT_GUI AND NOT CMAKE_PREFIX_PATH) if(WIN32 AND ENABLE_QT_GUI AND NOT CMAKE_PREFIX_PATH)
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/DetectQtInstallation.cmake") include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/DetectQtInstallation.cmake")

View File

@ -37,7 +37,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
**shadPS4** is an early **PlayStation 4** emulator for **Windows**, **Linux** and **macOS** written in C++. **shadPS4** is an early **PlayStation 4** emulator for **Windows**, **Linux** and **macOS** written in C++.
If you encounter problems or have doubts, do not hesitate to look at the [**Quickstart**](https://github.com/shadps4-emu/shadPS4/wiki/I.-Quick-start-%5BUsers%5D).\ If you encounter problems or have doubts, do not hesitate to look at the [**Quickstart**](https://github.com/shadps4-emu/shadPS4/wiki/I.-Quick-start-%5BUsers%5D).\
To verify that a game works, you can look at [**shadPS4 Game Compatibility**](https://github.com/shadps4-compatibility/shadps4-game-compatibility).\ To verify that a game works, you can look at [**shadPS4 Game Compatibility**](https://github.com/shadps4-emu/shadps4-game-compatibility).\
To discuss shadPS4 development, suggest ideas or to ask for help, join our [**Discord server**](https://discord.gg/bFJxfftGW6).\ To discuss shadPS4 development, suggest ideas or to ask for help, join our [**Discord server**](https://discord.gg/bFJxfftGW6).\
To get the latest news, go to our [**X (Twitter)**](https://x.com/shadps4) or our [**website**](https://shadps4.net/).\ To get the latest news, go to our [**X (Twitter)**](https://x.com/shadps4) or our [**website**](https://shadps4.net/).\
For those who'd like to donate to the project, we now have a [**Kofi page**](https://ko-fi.com/shadps4)! For those who'd like to donate to the project, we now have a [**Kofi page**](https://ko-fi.com/shadps4)!

View File

@ -147,7 +147,7 @@ Accurately identifying games will help other developers that own that game recog
- If your issue is small or you aren't sure whether you have properly identified something, [join the Discord server](https://discord.gg/MyZRaBngxA) and use the #development channel - If your issue is small or you aren't sure whether you have properly identified something, [join the Discord server](https://discord.gg/MyZRaBngxA) and use the #development channel
to concisely explain the issue, as well as any findings you currently have. to concisely explain the issue, as well as any findings you currently have.
- It is recommended that you check the [game compatibility issue tracker](https://github.com/shadps4-compatibility/shadps4-game-compatibility/issues) and post very short summaries of progress changes there, - It is recommended that you check the [game compatibility issue tracker](https://github.com/shadps4-emu/shadps4-game-compatibility/issues) and post very short summaries of progress changes there,
(such as the game now booting into the menu or getting in-game) for organizational and status update purposes. (such as the game now booting into the menu or getting in-game) for organizational and status update purposes.
- ⚠ **Do not post theoretical, unproven game-specific issues in the emulator issue tracker that you cannot verify and locate in the emulator source code as being a bug.**\ - ⚠ **Do not post theoretical, unproven game-specific issues in the emulator issue tracker that you cannot verify and locate in the emulator source code as being a bug.**\

View File

@ -32,7 +32,6 @@ std::filesystem::path find_fs_path_or(const basic_value<TC>& v, const K& ky,
namespace Config { namespace Config {
// General // General
static int volumeSlider = 100;
static bool isNeo = false; static bool isNeo = false;
static bool isDevKit = false; static bool isDevKit = false;
static bool isPSNSignedIn = false; static bool isPSNSignedIn = false;
@ -109,9 +108,6 @@ static std::string trophyKey = "";
// Expected number of items in the config file // Expected number of items in the config file
static constexpr u64 total_entries = 54; static constexpr u64 total_entries = 54;
int getVolumeSlider() {
return volumeSlider;
}
bool allowHDR() { bool allowHDR() {
return isHDRAllowed; return isHDRAllowed;
} }
@ -161,10 +157,6 @@ std::filesystem::path GetSaveDataPath() {
return save_data_path; return save_data_path;
} }
void setVolumeSlider(int volumeValue) {
volumeSlider = volumeValue;
}
void setLoadGameSizeEnabled(bool enable) { void setLoadGameSizeEnabled(bool enable) {
load_game_size = enable; load_game_size = enable;
} }
@ -619,7 +611,6 @@ void load(const std::filesystem::path& path) {
if (data.contains("General")) { if (data.contains("General")) {
const toml::value& general = data.at("General"); const toml::value& general = data.at("General");
volumeSlider = toml::find_or<int>(general, "volumeSlider", volumeSlider);
isNeo = toml::find_or<bool>(general, "isPS4Pro", isNeo); isNeo = toml::find_or<bool>(general, "isPS4Pro", isNeo);
isDevKit = toml::find_or<bool>(general, "isDevKit", isDevKit); isDevKit = toml::find_or<bool>(general, "isDevKit", isDevKit);
isPSNSignedIn = toml::find_or<bool>(general, "isPSNSignedIn", isPSNSignedIn); isPSNSignedIn = toml::find_or<bool>(general, "isPSNSignedIn", isPSNSignedIn);
@ -815,7 +806,6 @@ void save(const std::filesystem::path& path) {
fmt::print("Saving new configuration file {}\n", fmt::UTF(path.u8string())); fmt::print("Saving new configuration file {}\n", fmt::UTF(path.u8string()));
} }
data["General"]["volumeSlider"] = volumeSlider;
data["General"]["isPS4Pro"] = isNeo; data["General"]["isPS4Pro"] = isNeo;
data["General"]["isDevKit"] = isDevKit; data["General"]["isDevKit"] = isDevKit;
data["General"]["isPSNSignedIn"] = isPSNSignedIn; data["General"]["isPSNSignedIn"] = isPSNSignedIn;
@ -911,7 +901,6 @@ void save(const std::filesystem::path& path) {
void setDefaultValues() { void setDefaultValues() {
// General // General
volumeSlider = 100;
isNeo = false; isNeo = false;
isDevKit = false; isDevKit = false;
isPSNSignedIn = false; isPSNSignedIn = false;

View File

@ -19,8 +19,6 @@ enum HideCursorState : int { 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);
int getVolumeSlider();
void setVolumeSlider(int volumeValue);
std::string getTrophyKey(); std::string getTrophyKey();
void setTrophyKey(std::string key); void setTrophyKey(std::string key);
bool getIsFullscreen(); bool getIsFullscreen();

View File

@ -536,24 +536,9 @@ s32 PS4_SYSV_ABI sceAudioOutSetVolume(s32 handle, s32 flag, s32* vol) {
} }
port.impl->SetVolume(port.volume); port.impl->SetVolume(port.volume);
} }
AdjustVol();
return ORBIS_OK; return ORBIS_OK;
} }
void AdjustVol() {
if (audio == nullptr) {
return;
}
for (int i = 0; i < ports_out.size(); i++) {
std::unique_lock lock{ports_out[i].mutex};
if (!ports_out[i].IsOpen()) {
continue;
}
ports_out[i].impl->SetVolume(ports_out[i].volume);
}
}
int PS4_SYSV_ABI sceAudioOutSetVolumeDown() { int PS4_SYSV_ABI sceAudioOutSetVolumeDown() {
LOG_ERROR(Lib_AudioOut, "(STUBBED) called"); LOG_ERROR(Lib_AudioOut, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;

View File

@ -182,6 +182,5 @@ int PS4_SYSV_ABI sceAudioOutSystemControlSet();
int PS4_SYSV_ABI sceAudioOutSparkControlSetEqCoef(); int PS4_SYSV_ABI sceAudioOutSparkControlSetEqCoef();
int PS4_SYSV_ABI sceAudioOutSetSystemDebugState(); int PS4_SYSV_ABI sceAudioOutSetSystemDebugState();
void AdjustVol();
void RegisterLib(Core::Loader::SymbolsResolver* sym); void RegisterLib(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::AudioOut } // namespace Libraries::AudioOut

View File

@ -4,7 +4,6 @@
#include <thread> #include <thread>
#include <SDL3/SDL_audio.h> #include <SDL3/SDL_audio.h>
#include <SDL3/SDL_hints.h> #include <SDL3/SDL_hints.h>
#include <common/config.h>
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/libraries/audio/audioout.h" #include "core/libraries/audio/audioout.h"
@ -42,7 +41,6 @@ public:
stream = nullptr; stream = nullptr;
return; return;
} }
SDL_SetAudioStreamGain(stream, Config::getVolumeSlider() / 100.0f);
} }
~SDLPortBackend() override { ~SDLPortBackend() override {
@ -79,8 +77,7 @@ public:
} }
// SDL does not have per-channel volumes, for now just take the maximum of the channels. // 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); const auto vol = *std::ranges::max_element(ch_volumes);
if (!SDL_SetAudioStreamGain(stream, static_cast<float>(vol) / SCE_AUDIO_OUT_VOLUME_0DB * if (!SDL_SetAudioStreamGain(stream, static_cast<float>(vol) / SCE_AUDIO_OUT_VOLUME_0DB)) {
Config::getVolumeSlider() / 100.0f)) {
LOG_WARNING(Lib_AudioOut, "Failed to change SDL audio stream volume: {}", LOG_WARNING(Lib_AudioOut, "Failed to change SDL audio stream volume: {}",
SDL_GetError()); SDL_GetError());
} }

View File

@ -18,9 +18,11 @@ static ImeUi g_ime_ui;
class ImeHandler { class ImeHandler {
public: public:
ImeHandler(const OrbisImeKeyboardParam* param) { ImeHandler(const OrbisImeKeyboardParam* param) {
LOG_INFO(Lib_Ime, "Creating ImeHandler for keyboard");
Init(param, false); Init(param, false);
} }
ImeHandler(const OrbisImeParam* param) { ImeHandler(const OrbisImeParam* param) {
LOG_INFO(Lib_Ime, "Creating ImeHandler for IME");
Init(param, true); Init(param, true);
} }
~ImeHandler() = default; ~ImeHandler() = default;
@ -38,8 +40,13 @@ public:
openEvent.id = (ime_mode ? OrbisImeEventId::Open : OrbisImeEventId::KeyboardOpen); openEvent.id = (ime_mode ? OrbisImeEventId::Open : OrbisImeEventId::KeyboardOpen);
if (ime_mode) { if (ime_mode) {
sceImeGetPanelSize(&m_param.ime, &openEvent.param.rect.width, LOG_INFO(Lib_Ime, "calling sceImeGetPanelSize");
Error e = sceImeGetPanelSize(&m_param.ime, &openEvent.param.rect.width,
&openEvent.param.rect.height); &openEvent.param.rect.height);
if (e != Error::OK) {
LOG_ERROR(Lib_Ime, "sceImeGetPanelSize returned 0x{:X}", static_cast<u32>(e));
}
openEvent.param.rect.x = m_param.ime.posx; openEvent.param.rect.x = m_param.ime.posx;
openEvent.param.rect.y = m_param.ime.posy; openEvent.param.rect.y = m_param.ime.posy;
} else { } else {
@ -152,8 +159,13 @@ Error PS4_SYSV_ABI sceImeClose() {
} }
g_ime_handler.release(); g_ime_handler.release();
if (g_keyboard_handler) {
return Error::INTERNAL;
}
g_ime_ui = ImeUi(); g_ime_ui = ImeUi();
g_ime_state = ImeState(); g_ime_state = ImeState();
LOG_INFO(Lib_Ime, "IME closed successfully");
return Error::OK; return Error::OK;
} }
@ -226,21 +238,21 @@ Error PS4_SYSV_ABI sceImeGetPanelSize(const OrbisImeParam* param, u32* width, u3
LOG_INFO(Lib_Ime, "sceImeGetPanelSize called"); LOG_INFO(Lib_Ime, "sceImeGetPanelSize called");
if (!param) { if (!param) {
LOG_ERROR(Lib_Ime, "sceImeGetPanelSize: param is NULL"); LOG_ERROR(Lib_Ime, "Invalid param: NULL");
return Error::INVALID_ADDRESS; return Error::INVALID_ADDRESS;
} }
if (!width) { if (!width) {
LOG_ERROR(Lib_Ime, "sceImeGetPanelSize: width pointer is NULL"); LOG_ERROR(Lib_Ime, "Invalid *width: NULL");
return Error::INVALID_ADDRESS; return Error::INVALID_ADDRESS;
} }
if (!height) { if (!height) {
LOG_ERROR(Lib_Ime, "sceImeGetPanelSize: height pointer is NULL"); LOG_ERROR(Lib_Ime, "Invalid *height: NULL");
return Error::INVALID_ADDRESS; return Error::INVALID_ADDRESS;
} }
if (static_cast<u32>(param->option) & ~0x7BFF) { // Basic check for invalid options if (static_cast<u32>(param->option) & ~0x7BFF) { // Basic check for invalid options
LOG_ERROR(Lib_Ime, "sceImeGetPanelSize: Invalid option 0x{:X}", LOG_ERROR(Lib_Ime, "Invalid option 0x{:X}", static_cast<u32>(param->option));
static_cast<u32>(param->option));
return Error::INVALID_OPTION; return Error::INVALID_OPTION;
} }
@ -248,38 +260,35 @@ Error PS4_SYSV_ABI sceImeGetPanelSize(const OrbisImeParam* param, u32* width, u3
case OrbisImeType::Default: case OrbisImeType::Default:
*width = 500; // dummy value *width = 500; // dummy value
*height = 100; // dummy value *height = 100; // dummy value
LOG_INFO(Lib_Ime, "sceImeGetPanelSize: IME type Default ({})", LOG_DEBUG(Lib_Ime, "param->type: Default ({})", static_cast<u32>(param->type));
static_cast<u32>(param->type));
break; break;
case OrbisImeType::BasicLatin: case OrbisImeType::BasicLatin:
*width = 500; // dummy value *width = 500; // dummy value
*height = 100; // dummy value *height = 100; // dummy value
LOG_INFO(Lib_Ime, "sceImeGetPanelSize: IME type BasicLatin ({})", LOG_DEBUG(Lib_Ime, "param->type: BasicLatin ({})", static_cast<u32>(param->type));
static_cast<u32>(param->type));
break; break;
case OrbisImeType::Url: case OrbisImeType::Url:
*width = 500; // dummy value *width = 500; // dummy value
*height = 100; // dummy value *height = 100; // dummy value
LOG_INFO(Lib_Ime, "sceImeGetPanelSize: IME type Url ({})", static_cast<u32>(param->type)); LOG_DEBUG(Lib_Ime, "param->type: Url ({})", static_cast<u32>(param->type));
break; break;
case OrbisImeType::Mail: case OrbisImeType::Mail:
// We set our custom sizes, commented sizes are the original ones // We set our custom sizes, commented sizes are the original ones
*width = 500; // 793 *width = 500; // 793
*height = 100; // 408 *height = 100; // 408
LOG_INFO(Lib_Ime, "sceImeGetPanelSize: IME type Mail ({})", static_cast<u32>(param->type)); LOG_DEBUG(Lib_Ime, "param->type: Mail ({})", static_cast<u32>(param->type));
break; break;
case OrbisImeType::Number: case OrbisImeType::Number:
*width = 370; *width = 370;
*height = 402; *height = 402;
LOG_INFO(Lib_Ime, "sceImeGetPanelSize: IME type Number ({})", LOG_DEBUG(Lib_Ime, "param->type: Number ({})", static_cast<u32>(param->type));
static_cast<u32>(param->type));
break; break;
default: default:
LOG_ERROR(Lib_Ime, "sceImeGetPanelSize: Invalid IME type ({})", LOG_ERROR(Lib_Ime, "Invalid param->type: ({})", static_cast<u32>(param->type));
static_cast<u32>(param->type));
return Error::INVALID_TYPE; return Error::INVALID_TYPE;
} }
LOG_INFO(Lib_Ime, "IME panel size: width={}, height={}", *width, *height);
return Error::OK; return Error::OK;
} }
@ -287,10 +296,23 @@ Error PS4_SYSV_ABI sceImeKeyboardClose(Libraries::UserService::OrbisUserServiceU
LOG_INFO(Lib_Ime, "called"); LOG_INFO(Lib_Ime, "called");
if (!g_keyboard_handler) { if (!g_keyboard_handler) {
LOG_ERROR(Lib_Ime, "No keyboard handler is open");
return Error::NOT_OPENED; return Error::NOT_OPENED;
} }
if (userId < 0 || userId > 4) { // Todo: check valid user IDs
// Maybe g_keyboard_handler should hold a user ID and I must compare it here?
LOG_ERROR(Lib_Ime, "Invalid userId: {}", userId);
return Error::INVALID_USER_ID;
}
g_keyboard_handler.release(); g_keyboard_handler.release();
if (g_ime_handler) {
LOG_ERROR(Lib_Ime, "failed to close keyboard handler, IME handler is still open");
return Error::INTERNAL;
}
LOG_INFO(Lib_Ime, "Keyboard handler closed successfully for user ID: {}", userId);
return Error::OK; return Error::OK;
} }
@ -307,24 +329,57 @@ int PS4_SYSV_ABI sceImeKeyboardGetResourceId() {
Error PS4_SYSV_ABI sceImeKeyboardOpen(Libraries::UserService::OrbisUserServiceUserId userId, Error PS4_SYSV_ABI sceImeKeyboardOpen(Libraries::UserService::OrbisUserServiceUserId userId,
const OrbisImeKeyboardParam* param) { const OrbisImeKeyboardParam* param) {
LOG_INFO(Lib_Ime, "called"); LOG_INFO(Lib_Ime, "called");
LOG_INFO(Lib_Ime, "kValidImeDialogExtOptionMask=0x{:X}", kValidImeDialogExtOptionMask);
if (!param) { if (!param) {
LOG_ERROR(Lib_Ime, "Invalid param: NULL");
return Error::INVALID_ADDRESS; return Error::INVALID_ADDRESS;
} }
if (!param->arg) {
return Error::INVALID_ARG;
}
if (!param->handler) { if (!param->handler) {
LOG_ERROR(Lib_Ime, "Invalid param->handler: NULL");
return Error::INVALID_HANDLER; return Error::INVALID_HANDLER;
} }
// seems like arg is optional, need to check if it is used in the handler
if (!param->arg && false) { // Todo: check if arg is used in the handler, temporarily disabled
LOG_ERROR(Lib_Ime, "Invalid param->arg: NULL");
return Error::INVALID_ARG;
}
if (static_cast<u32>(param->option) & ~kValidOrbisImeKeyboardOptionMask) {
LOG_ERROR(Lib_Ime,
"Invalid param->option\n"
"option: {:032b}\n"
"validMask: {:032b}",
static_cast<u32>(param->option), kValidOrbisImeKeyboardOptionMask);
return Error::INVALID_OPTION;
}
if (userId < 0 || userId > 4) { // Todo: check valid user IDs
LOG_ERROR(Lib_Ime, "Invalid userId: {}", userId);
return Error::INVALID_USER_ID;
}
for (size_t i = 0; i < sizeof(param->reserved1); ++i) {
if (param->reserved1[i] != 0) {
LOG_ERROR(Lib_Ime, "Invalid reserved1: not zeroed");
return Error::INVALID_RESERVED;
}
}
for (size_t i = 0; i < sizeof(param->reserved2); ++i) {
if (param->reserved2[i] != 0) {
LOG_ERROR(Lib_Ime, "Invalid reserved2: not zeroed");
return Error::INVALID_RESERVED;
}
}
if (false) { // Todo: check if usb keyboard is connected, always true for now
LOG_ERROR(Lib_Ime, "USB keyboard is not connected");
return Error::CONNECTION_FAILED;
}
if (g_keyboard_handler) { if (g_keyboard_handler) {
LOG_ERROR(Lib_Ime, "Keyboard handler is already open");
return Error::BUSY; return Error::BUSY;
} }
g_keyboard_handler = std::make_unique<ImeHandler>(param); g_keyboard_handler = std::make_unique<ImeHandler>(param);
if (!g_keyboard_handler) {
LOG_ERROR(Lib_Ime, "Failed to create keyboard handler");
return Error::INTERNAL; // or Error::NO_MEMORY;
}
LOG_INFO(Lib_Ime, "Keyboard handler created successfully for user ID: {}", userId);
return Error::OK; return Error::OK;
} }
@ -347,110 +402,110 @@ Error PS4_SYSV_ABI sceImeOpen(const OrbisImeParam* param, const OrbisImeParamExt
LOG_INFO(Lib_Ime, "called"); LOG_INFO(Lib_Ime, "called");
if (!param) { if (!param) {
LOG_ERROR(Lib_Ime, "sceImeOpen: param is null"); LOG_ERROR(Lib_Ime, "Invalid param: NULL");
return Error::INVALID_ADDRESS; return Error::INVALID_ADDRESS;
} else { } else {
// LOG_DEBUG values for debugging purposes // LOG_DEBUG values for debugging purposes
LOG_DEBUG(Lib_Ime, "param: user_id={}", param->user_id); LOG_DEBUG(Lib_Ime, "param->user_id: {}", param->user_id);
LOG_DEBUG(Lib_Ime, "param: type={}", static_cast<u32>(param->type)); LOG_DEBUG(Lib_Ime, "param->type: {}", static_cast<u32>(param->type));
LOG_DEBUG(Lib_Ime, "param: supported_languages={:064b}", LOG_DEBUG(Lib_Ime, "param->supported_languages: {:064b}",
static_cast<u64>(param->supported_languages)); static_cast<u64>(param->supported_languages));
LOG_DEBUG(Lib_Ime, "param: enter_label={}", static_cast<u32>(param->enter_label)); LOG_DEBUG(Lib_Ime, "param->enter_label: {}", static_cast<u32>(param->enter_label));
LOG_DEBUG(Lib_Ime, "param: input_method={}", static_cast<u32>(param->input_method)); LOG_DEBUG(Lib_Ime, "param->input_method: {}", static_cast<u32>(param->input_method));
LOG_DEBUG(Lib_Ime, "param: filter={:p}", reinterpret_cast<void*>(param->filter)); LOG_DEBUG(Lib_Ime, "param->filter: {:p}", reinterpret_cast<void*>(param->filter));
LOG_DEBUG(Lib_Ime, "param: option={:032b}", static_cast<u32>(param->option)); LOG_DEBUG(Lib_Ime, "param->option: {:032b}", static_cast<u32>(param->option));
LOG_DEBUG(Lib_Ime, "param: maxTextLength={}", param->maxTextLength); LOG_DEBUG(Lib_Ime, "param->maxTextLength: {}", param->maxTextLength);
LOG_DEBUG(Lib_Ime, "param: inputTextBuffer={:p}", LOG_DEBUG(Lib_Ime, "param->inputTextBuffer: {:p}",
static_cast<const void*>(param->inputTextBuffer)); static_cast<const void*>(param->inputTextBuffer));
LOG_DEBUG(Lib_Ime, "param: posx={}", param->posx); LOG_DEBUG(Lib_Ime, "param->posx: {}", param->posx);
LOG_DEBUG(Lib_Ime, "param: posy={}", param->posy); LOG_DEBUG(Lib_Ime, "param->posy: {}", param->posy);
LOG_DEBUG(Lib_Ime, "param: horizontal_alignment={}", LOG_DEBUG(Lib_Ime, "param->horizontal_alignment: {}",
static_cast<u32>(param->horizontal_alignment)); static_cast<u32>(param->horizontal_alignment));
LOG_DEBUG(Lib_Ime, "param: vertical_alignment={}", LOG_DEBUG(Lib_Ime, "param->vertical_alignment: {}",
static_cast<u32>(param->vertical_alignment)); static_cast<u32>(param->vertical_alignment));
LOG_DEBUG(Lib_Ime, "param: work={:p}", param->work); LOG_DEBUG(Lib_Ime, "param->work: {:p}", param->work);
LOG_DEBUG(Lib_Ime, "param: arg={:p}", param->arg); LOG_DEBUG(Lib_Ime, "param->arg: {:p}", param->arg);
LOG_DEBUG(Lib_Ime, "param: handler={:p}", reinterpret_cast<void*>(param->handler)); LOG_DEBUG(Lib_Ime, "param->handler: {:p}", reinterpret_cast<void*>(param->handler));
} }
if (!extended) { if (!extended) {
LOG_INFO(Lib_Ime, "sceImeOpen: extended is null"); LOG_INFO(Lib_Ime, "Not used extended: NULL");
} else { } else {
// LOG_DEBUG values for debugging purposes LOG_DEBUG(Lib_Ime, "extended->option: {:032b}", static_cast<u32>(extended->option));
LOG_DEBUG(Lib_Ime, "extended: option={:032b}", static_cast<u32>(extended->option)); LOG_DEBUG(Lib_Ime, "extended->color_base: {{{},{},{},{}}}", extended->color_base.r,
LOG_DEBUG(Lib_Ime, "extended: color_base={{{},{},{},{}}}", extended->color_base.r,
extended->color_base.g, extended->color_base.b, extended->color_base.a); extended->color_base.g, extended->color_base.b, extended->color_base.a);
LOG_DEBUG(Lib_Ime, "extended: color_line={{{},{},{},{}}}", extended->color_line.r, LOG_DEBUG(Lib_Ime, "extended->color_line: {{{},{},{},{}}}", extended->color_line.r,
extended->color_line.g, extended->color_line.b, extended->color_line.a); extended->color_line.g, extended->color_line.b, extended->color_line.a);
LOG_DEBUG(Lib_Ime, "extended: color_text_field={{{},{},{},{}}}", LOG_DEBUG(Lib_Ime, "extended->color_text_field: {{{},{},{},{}}}",
extended->color_text_field.r, extended->color_text_field.g, extended->color_text_field.r, extended->color_text_field.g,
extended->color_text_field.b, extended->color_text_field.a); extended->color_text_field.b, extended->color_text_field.a);
LOG_DEBUG(Lib_Ime, "extended: color_preedit={{{},{},{},{}}}", extended->color_preedit.r, LOG_DEBUG(Lib_Ime, "extended->color_preedit: {{{},{},{},{}}}", extended->color_preedit.r,
extended->color_preedit.g, extended->color_preedit.b, extended->color_preedit.a); extended->color_preedit.g, extended->color_preedit.b, extended->color_preedit.a);
LOG_DEBUG(Lib_Ime, "extended: color_button_default={{{},{},{},{}}}", LOG_DEBUG(Lib_Ime, "extended->color_button_default: {{{},{},{},{}}}",
extended->color_button_default.r, extended->color_button_default.g, extended->color_button_default.r, extended->color_button_default.g,
extended->color_button_default.b, extended->color_button_default.a); extended->color_button_default.b, extended->color_button_default.a);
LOG_DEBUG(Lib_Ime, "extended: color_button_function={{{},{},{},{}}}", LOG_DEBUG(Lib_Ime, "extended->color_button_function: {{{},{},{},{}}}",
extended->color_button_function.r, extended->color_button_function.g, extended->color_button_function.r, extended->color_button_function.g,
extended->color_button_function.b, extended->color_button_function.a); extended->color_button_function.b, extended->color_button_function.a);
LOG_DEBUG(Lib_Ime, "extended: color_button_symbol={{{},{},{},{}}}", LOG_DEBUG(Lib_Ime, "extended->color_button_symbol: {{{},{},{},{}}}",
extended->color_button_symbol.r, extended->color_button_symbol.g, extended->color_button_symbol.r, extended->color_button_symbol.g,
extended->color_button_symbol.b, extended->color_button_symbol.a); extended->color_button_symbol.b, extended->color_button_symbol.a);
LOG_DEBUG(Lib_Ime, "extended: color_text={{{},{},{},{}}}", extended->color_text.r, LOG_DEBUG(Lib_Ime, "extended->color_text: {{{},{},{},{}}}", extended->color_text.r,
extended->color_text.g, extended->color_text.b, extended->color_text.a); extended->color_text.g, extended->color_text.b, extended->color_text.a);
LOG_DEBUG(Lib_Ime, "extended: color_special={{{},{},{},{}}}", extended->color_special.r, LOG_DEBUG(Lib_Ime, "extended->color_special: {{{},{},{},{}}}", extended->color_special.r,
extended->color_special.g, extended->color_special.b, extended->color_special.a); extended->color_special.g, extended->color_special.b, extended->color_special.a);
LOG_DEBUG(Lib_Ime, "extended: priority={}", static_cast<u32>(extended->priority)); LOG_DEBUG(Lib_Ime, "extended->priority: {}", static_cast<u32>(extended->priority));
LOG_DEBUG(Lib_Ime, "extended: additional_dictionary_path={:p}", LOG_DEBUG(Lib_Ime, "extended->additional_dictionary_path: {:p}",
static_cast<const void*>(extended->additional_dictionary_path)); static_cast<const void*>(extended->additional_dictionary_path));
LOG_DEBUG(Lib_Ime, "extended: ext_keyboard_filter={:p}", LOG_DEBUG(Lib_Ime, "extended->ext_keyboard_filter: {:p}",
reinterpret_cast<void*>(extended->ext_keyboard_filter)); reinterpret_cast<void*>(extended->ext_keyboard_filter));
LOG_DEBUG(Lib_Ime, "extended: disable_device={:032b}", LOG_DEBUG(Lib_Ime, "extended->disable_device: {:032b}",
static_cast<u32>(extended->disable_device)); static_cast<u32>(extended->disable_device));
LOG_DEBUG(Lib_Ime, "extended: ext_keyboard_mode={}", extended->ext_keyboard_mode); LOG_DEBUG(Lib_Ime, "extended->ext_keyboard_mode: {}", extended->ext_keyboard_mode);
} }
if (param->user_id < 1 || param->user_id > 4) { if (param->user_id < 1 || param->user_id > 4) { // Todo: check valid user IDs
LOG_ERROR(Lib_Ime, "sceImeOpen: Invalid user_id ({})", static_cast<u32>(param->user_id)); LOG_ERROR(Lib_Ime, "Invalid user_id: {}", static_cast<u32>(param->user_id));
return Error::INVALID_USER_ID; return Error::INVALID_USER_ID;
} }
if (!magic_enum::enum_contains(param->type)) { if (!magic_enum::enum_contains(param->type)) {
LOG_ERROR(Lib_Ime, "sceImeOpen: Invalid type ({})", static_cast<u32>(param->type)); LOG_ERROR(Lib_Ime, "Invalid type: {}", static_cast<u32>(param->type));
return Error::INVALID_TYPE; return Error::INVALID_TYPE;
} }
if (static_cast<u64>(param->supported_languages) & ~kValidOrbisImeLanguageMask) { if (static_cast<u64>(param->supported_languages) & ~kValidOrbisImeLanguageMask) {
LOG_ERROR(Lib_Ime, "sceImeOpen: supported_languages has invalid bits (0x{:016X})", LOG_ERROR(Lib_Ime,
static_cast<u64>(param->supported_languages)); "Invalid supported_languages\n"
"supported_languages: {:064b}\n"
"valid_mask: {:064b}",
static_cast<u64>(param->supported_languages), kValidOrbisImeLanguageMask);
return Error::INVALID_SUPPORTED_LANGUAGES; return Error::INVALID_SUPPORTED_LANGUAGES;
} }
if (!magic_enum::enum_contains(param->enter_label)) { if (!magic_enum::enum_contains(param->enter_label)) {
LOG_ERROR(Lib_Ime, "sceImeOpen: Invalid enter_label ({})", LOG_ERROR(Lib_Ime, "Invalid enter_label: {}", static_cast<u32>(param->enter_label));
static_cast<u32>(param->enter_label));
return Error::INVALID_ENTER_LABEL; return Error::INVALID_ENTER_LABEL;
} }
if (!magic_enum::enum_contains(param->input_method)) { if (!magic_enum::enum_contains(param->input_method)) {
LOG_ERROR(Lib_Ime, "sceImeOpen: Invalid input_method ({})", LOG_ERROR(Lib_Ime, "Invalid input_method: {}", static_cast<u32>(param->input_method));
static_cast<u32>(param->input_method));
return Error::INVALID_INPUT_METHOD; return Error::INVALID_INPUT_METHOD;
} }
if (static_cast<u32>(param->option) & ~kValidImeOptionMask) { if (static_cast<u32>(param->option) & ~kValidImeOptionMask) {
LOG_ERROR(Lib_Ime, "sceImeOpen: option has invalid bits set (0x{:X}), mask=(0x{:X})", LOG_ERROR(Lib_Ime, "option has invalid bits set (0x{:X}), mask=(0x{:X})",
static_cast<u32>(param->option), kValidImeOptionMask); static_cast<u32>(param->option), kValidImeOptionMask);
return Error::INVALID_OPTION; return Error::INVALID_OPTION;
} }
if (param->maxTextLength == 0 || param->maxTextLength > ORBIS_IME_DIALOG_MAX_TEXT_LENGTH) { if (param->maxTextLength == 0 || param->maxTextLength > ORBIS_IME_DIALOG_MAX_TEXT_LENGTH) {
LOG_ERROR(Lib_Ime, "sceImeOpen: maxTextLength invalid ({})", param->maxTextLength); LOG_ERROR(Lib_Ime, "Invalid maxTextLength: {}", param->maxTextLength);
return Error::INVALID_MAX_TEXT_LENGTH; return Error::INVALID_MAX_TEXT_LENGTH;
} }
if (!param->inputTextBuffer) { if (!param->inputTextBuffer) {
LOG_ERROR(Lib_Ime, "sceImeOpen: inputTextBuffer is NULL"); LOG_ERROR(Lib_Ime, "Invalid inputTextBuffer: NULL");
return Error::INVALID_INPUT_TEXT_BUFFER; return Error::INVALID_INPUT_TEXT_BUFFER;
} }
@ -459,23 +514,21 @@ Error PS4_SYSV_ABI sceImeOpen(const OrbisImeParam* param, const OrbisImeParamExt
const float maxHeight = useHighRes ? 2160.0f : 1080.0f; const float maxHeight = useHighRes ? 2160.0f : 1080.0f;
if (param->posx < 0.0f || param->posx >= maxWidth) { if (param->posx < 0.0f || param->posx >= maxWidth) {
LOG_ERROR(Lib_Ime, "sceImeOpen: posx out of range (%.2f), max allowed %.0f", param->posx, LOG_ERROR(Lib_Ime, "Invalid posx: {}, range: 0.0 - {}", param->posx, maxWidth);
maxWidth);
return Error::INVALID_POSX; return Error::INVALID_POSX;
} }
if (param->posy < 0.0f || param->posy >= maxHeight) { if (param->posy < 0.0f || param->posy >= maxHeight) {
LOG_ERROR(Lib_Ime, "sceImeOpen: posy out of range (%.2f), max allowed %.0f", param->posy, LOG_ERROR(Lib_Ime, "Invalid posy: {}, range: 0.0 - {}", param->posy, maxHeight);
maxHeight);
return Error::INVALID_POSY; return Error::INVALID_POSY;
} }
if (!magic_enum::enum_contains(param->horizontal_alignment)) { if (!magic_enum::enum_contains(param->horizontal_alignment)) {
LOG_ERROR(Lib_Ime, "sceImeOpen: Invalid horizontal_alignment ({})", LOG_ERROR(Lib_Ime, "Invalid horizontal_alignment: {}",
static_cast<u32>(param->horizontal_alignment)); static_cast<u32>(param->horizontal_alignment));
return Error::INVALID_HORIZONTALIGNMENT; return Error::INVALID_HORIZONTALIGNMENT;
} }
if (!magic_enum::enum_contains(param->vertical_alignment)) { if (!magic_enum::enum_contains(param->vertical_alignment)) {
LOG_ERROR(Lib_Ime, "sceImeOpen: Invalid vertical_alignment ({})", LOG_ERROR(Lib_Ime, "Invalid vertical_alignment: {}",
static_cast<u32>(param->vertical_alignment)); static_cast<u32>(param->vertical_alignment));
return Error::INVALID_VERTICALALIGNMENT; return Error::INVALID_VERTICALALIGNMENT;
} }
@ -483,33 +536,51 @@ Error PS4_SYSV_ABI sceImeOpen(const OrbisImeParam* param, const OrbisImeParamExt
if (extended) { if (extended) {
u32 ext_option_value = static_cast<u32>(extended->option); u32 ext_option_value = static_cast<u32>(extended->option);
if (ext_option_value & ~kValidImeExtOptionMask) { if (ext_option_value & ~kValidImeExtOptionMask) {
LOG_ERROR(Lib_Ime, "sceImeOpen: extended->option has invalid bits set (0x{:X})", LOG_ERROR(Lib_Ime,
ext_option_value); "Invalid extended->option\n"
"option: {:032b}\n"
"valid_mask: {:032b}",
ext_option_value, kValidImeExtOptionMask);
return Error::INVALID_EXTENDED; return Error::INVALID_EXTENDED;
} }
} }
if (!param->work) { if (!param->work) {
LOG_ERROR(Lib_Ime, "sceImeOpen: work buffer is NULL"); LOG_ERROR(Lib_Ime, "Invalid work: NULL");
return Error::INVALID_WORK; return Error::INVALID_WORK;
} }
for (unsigned i = 0; i < sizeof(param->reserved); ++i) { // Todo: validate arg
if (false) {
LOG_ERROR(Lib_Ime, "Invalid arg: NULL");
return Error::INVALID_ARG;
}
// Todo: validate handler
if (false) {
LOG_ERROR(Lib_Ime, "Invalid handler: NULL");
return Error::INVALID_HANDLER;
}
for (size_t i = 0; i < sizeof(param->reserved); ++i) {
if (param->reserved[i] != 0) { if (param->reserved[i] != 0) {
LOG_ERROR(Lib_Ime, "sceImeOpen: reserved field must be zeroed"); LOG_ERROR(Lib_Ime, "Invalid reserved: not zeroed");
return Error::INVALID_RESERVED; return Error::INVALID_RESERVED;
} }
} }
// Todo: validate arg and handler
if (g_ime_handler) { if (g_ime_handler) {
LOG_ERROR(Lib_Ime, "sceImeOpen: Error BUSY"); LOG_ERROR(Lib_Ime, "IME handler is already open");
return Error::BUSY; return Error::BUSY;
} }
g_ime_handler = std::make_unique<ImeHandler>(param); g_ime_handler = std::make_unique<ImeHandler>(param);
LOG_INFO(Lib_Ime, "sceImeOpen: OK"); if (!g_ime_handler) {
LOG_ERROR(Lib_Ime, "Failed to create IME handler");
return Error::NO_MEMORY; // or Error::INTERNAL
}
LOG_INFO(Lib_Ime, "IME handler created successfully");
return Error::OK; return Error::OK;
} }

View File

@ -323,7 +323,7 @@ enum class OrbisImeEventId : u32 {
ChangeInputMethodState = 18, ChangeInputMethodState = 18,
KeyboardOpen = 256, KeyboardOpen = 256,
KeyboardKeycodeDoen = 257, KeyboardKeycodeDown = 257,
KeyboardKeycodeUp = 258, KeyboardKeycodeUp = 258,
KeyboardKeycodeRepeat = 259, KeyboardKeycodeRepeat = 259,
KeyboardConnection = 260, KeyboardConnection = 260,

View File

@ -44,7 +44,7 @@ ImeState& ImeState::operator=(ImeState&& other) noexcept {
} }
void ImeState::SendEvent(OrbisImeEvent* event) { void ImeState::SendEvent(OrbisImeEvent* event) {
std::unique_lock lock{queue_mutex}; std::unique_lock<std::mutex> lock{queue_mutex};
event_queue.push(*event); event_queue.push(*event);
} }
@ -108,7 +108,7 @@ ImeUi& ImeUi::operator=(ImeUi&& other) {
} }
void ImeUi::Draw() { void ImeUi::Draw() {
std::unique_lock lock{draw_mutex}; std::unique_lock<std::mutex> lock{draw_mutex};
if (!state) { if (!state) {
return; return;

View File

@ -22,8 +22,8 @@ void CompatibilityInfoClass::UpdateCompatibilityDatabase(QWidget* parent, bool f
if (!forced && LoadCompatibilityFile()) if (!forced && LoadCompatibilityFile())
return; return;
QUrl url("https://github.com/shadps4-compatibility/shadps4-game-compatibility/releases/latest/" QUrl url("https://github.com/shadps4-emu/shadps4-game-compatibility/releases/latest/download/"
"download/compatibility_data.json"); "compatibility_data.json");
QNetworkRequest request(url); QNetworkRequest request(url);
QNetworkReply* reply = m_network_manager->get(request); QNetworkReply* reply = m_network_manager->get(request);

View File

@ -91,8 +91,7 @@ GameListFrame::GameListFrame(std::shared_ptr<gui_settings> gui_settings,
connect(this, &QTableWidget::cellClicked, this, [=, this](int row, int column) { connect(this, &QTableWidget::cellClicked, this, [=, this](int row, int column) {
if (column == 2 && m_game_info->m_games[row].compatibility.issue_number != "") { if (column == 2 && m_game_info->m_games[row].compatibility.issue_number != "") {
auto url_issues = auto url_issues = "https://github.com/shadps4-emu/shadps4-game-compatibility/issues/";
"https://github.com/shadps4-compatibility/shadps4-game-compatibility/issues/";
QDesktopServices::openUrl( QDesktopServices::openUrl(
QUrl(url_issues + m_game_info->m_games[row].compatibility.issue_number)); QUrl(url_issues + m_game_info->m_games[row].compatibility.issue_number));
} else if (column == 10) { } else if (column == 10) {

View File

@ -581,7 +581,7 @@ public:
if (selected == viewCompatibilityReport) { if (selected == viewCompatibilityReport) {
if (m_games[itemID].compatibility.issue_number != "") { if (m_games[itemID].compatibility.issue_number != "") {
auto url_issues = auto url_issues =
"https://github.com/shadps4-compatibility/shadps4-game-compatibility/issues/"; "https://github.com/shadps4-emu/shadps4-game-compatibility/issues/";
QDesktopServices::openUrl( QDesktopServices::openUrl(
QUrl(url_issues + m_games[itemID].compatibility.issue_number)); QUrl(url_issues + m_games[itemID].compatibility.issue_number));
} }
@ -589,8 +589,8 @@ public:
if (selected == submitCompatibilityReport) { if (selected == submitCompatibilityReport) {
if (m_games[itemID].compatibility.issue_number == "") { if (m_games[itemID].compatibility.issue_number == "") {
QUrl url = QUrl("https://github.com/shadps4-compatibility/" QUrl url =
"shadps4-game-compatibility/issues/new"); QUrl("https://github.com/shadps4-emu/shadps4-game-compatibility/issues/new");
QUrlQuery query; QUrlQuery query;
query.addQueryItem("template", QString("game_compatibility.yml")); query.addQueryItem("template", QString("game_compatibility.yml"));
query.addQueryItem( query.addQueryItem(
@ -605,7 +605,7 @@ public:
QDesktopServices::openUrl(url); QDesktopServices::openUrl(url);
} else { } else {
auto url_issues = auto url_issues =
"https://github.com/shadps4-compatibility/shadps4-game-compatibility/issues/"; "https://github.com/shadps4-emu/shadps4-game-compatibility/issues/";
QDesktopServices::openUrl( QDesktopServices::openUrl(
QUrl(url_issues + m_games[itemID].compatibility.issue_number)); QUrl(url_issues + m_games[itemID].compatibility.issue_number));
} }

View File

@ -37,7 +37,6 @@ const gui_value gl_showBackgroundImage = gui_value(game_list, "showBackgroundIma
const gui_value gl_backgroundImageOpacity = gui_value(game_list, "backgroundImageOpacity", 50); const gui_value gl_backgroundImageOpacity = gui_value(game_list, "backgroundImageOpacity", 50);
const gui_value gl_playBackgroundMusic = gui_value(game_list, "playBackgroundMusic", true); const gui_value gl_playBackgroundMusic = gui_value(game_list, "playBackgroundMusic", true);
const gui_value gl_backgroundMusicVolume = gui_value(game_list, "backgroundMusicVolume", 50); const gui_value gl_backgroundMusicVolume = gui_value(game_list, "backgroundMusicVolume", 50);
const gui_value gl_VolumeSlider = gui_value(game_list, "volumeSlider", 100);
// game grid settings // game grid settings
const gui_value gg_icon_size = gui_value(game_grid, "icon_size", 69); const gui_value gg_icon_size = gui_value(game_grid, "icon_size", 69);

View File

@ -11,7 +11,6 @@
#include "common/config.h" #include "common/config.h"
#include "common/scm_rev.h" #include "common/scm_rev.h"
#include "core/libraries/audio/audioout.h"
#include "qt_gui/compatibility_info.h" #include "qt_gui/compatibility_info.h"
#ifdef ENABLE_DISCORD_RPC #ifdef ENABLE_DISCORD_RPC
#include "common/discord_rpc_handler.h" #include "common/discord_rpc_handler.h"
@ -69,7 +68,6 @@ QMap<QString, QString> chooseHomeTabMap;
int backgroundImageOpacitySlider_backup; int backgroundImageOpacitySlider_backup;
int bgm_volume_backup; int bgm_volume_backup;
int volume_slider_backup;
static std::vector<QString> m_physical_devices; static std::vector<QString> m_physical_devices;
@ -151,11 +149,9 @@ SettingsDialog::SettingsDialog(std::shared_ptr<gui_settings> gui_settings,
} else if (button == ui->buttonBox->button(QDialogButtonBox::Close)) { } else if (button == ui->buttonBox->button(QDialogButtonBox::Close)) {
ui->backgroundImageOpacitySlider->setValue(backgroundImageOpacitySlider_backup); ui->backgroundImageOpacitySlider->setValue(backgroundImageOpacitySlider_backup);
emit BackgroundOpacityChanged(backgroundImageOpacitySlider_backup); emit BackgroundOpacityChanged(backgroundImageOpacitySlider_backup);
ui->horizontalVolumeSlider->setValue(volume_slider_backup);
Config::setVolumeSlider(volume_slider_backup);
ui->BGMVolumeSlider->setValue(bgm_volume_backup); ui->BGMVolumeSlider->setValue(bgm_volume_backup);
BackgroundMusicPlayer::getInstance().setVolume(bgm_volume_backup); BackgroundMusicPlayer::getInstance().setVolume(bgm_volume_backup);
SyncRealTimeWidgetstoConfig(); ResetInstallFolders();
} }
if (Common::Log::IsActive()) { if (Common::Log::IsActive()) {
Common::Log::Filter filter; Common::Log::Filter filter;
@ -174,12 +170,6 @@ SettingsDialog::SettingsDialog(std::shared_ptr<gui_settings> gui_settings,
// GENERAL TAB // GENERAL TAB
{ {
connect(ui->horizontalVolumeSlider, &QSlider::valueChanged, this, [this](int value) {
VolumeSliderChange(value);
Config::setVolumeSlider(value);
Libraries::AudioOut::AdjustVol();
});
#ifdef ENABLE_UPDATER #ifdef ENABLE_UPDATER
#if (QT_VERSION < QT_VERSION_CHECK(6, 7, 0)) #if (QT_VERSION < QT_VERSION_CHECK(6, 7, 0))
connect(ui->updateCheckBox, &QCheckBox::stateChanged, this, [this](int state) { connect(ui->updateCheckBox, &QCheckBox::stateChanged, this, [this](int state) {
@ -408,8 +398,6 @@ void SettingsDialog::closeEvent(QCloseEvent* event) {
if (!is_saving) { if (!is_saving) {
ui->backgroundImageOpacitySlider->setValue(backgroundImageOpacitySlider_backup); ui->backgroundImageOpacitySlider->setValue(backgroundImageOpacitySlider_backup);
emit BackgroundOpacityChanged(backgroundImageOpacitySlider_backup); emit BackgroundOpacityChanged(backgroundImageOpacitySlider_backup);
ui->horizontalVolumeSlider->setValue(volume_slider_backup);
Config::setVolumeSlider(volume_slider_backup);
ui->BGMVolumeSlider->setValue(bgm_volume_backup); ui->BGMVolumeSlider->setValue(bgm_volume_backup);
BackgroundMusicPlayer::getInstance().setVolume(bgm_volume_backup); BackgroundMusicPlayer::getInstance().setVolume(bgm_volume_backup);
} }
@ -475,8 +463,6 @@ void SettingsDialog::LoadValuesFromConfig() {
ui->radioButton_Bottom->setChecked(side == "bottom"); ui->radioButton_Bottom->setChecked(side == "bottom");
ui->BGMVolumeSlider->setValue(m_gui_settings->GetValue(gui::gl_backgroundMusicVolume).toInt()); ui->BGMVolumeSlider->setValue(m_gui_settings->GetValue(gui::gl_backgroundMusicVolume).toInt());
ui->horizontalVolumeSlider->setValue(m_gui_settings->GetValue(gui::gl_VolumeSlider).toInt());
ui->volumeText->setText(QString::number(ui->horizontalVolumeSlider->sliderPosition()) + "%");
ui->discordRPCCheckbox->setChecked( ui->discordRPCCheckbox->setChecked(
toml::find_or<bool>(data, "General", "enableDiscordRPC", true)); toml::find_or<bool>(data, "General", "enableDiscordRPC", true));
QString translatedText_FullscreenMode = QString translatedText_FullscreenMode =
@ -546,7 +532,7 @@ void SettingsDialog::LoadValuesFromConfig() {
toml::find_or<bool>(data, "Input", "isMotionControlsEnabled", true)); toml::find_or<bool>(data, "Input", "isMotionControlsEnabled", true));
ui->removeFolderButton->setEnabled(!ui->gameFoldersListWidget->selectedItems().isEmpty()); ui->removeFolderButton->setEnabled(!ui->gameFoldersListWidget->selectedItems().isEmpty());
SyncRealTimeWidgetstoConfig(); ResetInstallFolders();
ui->backgroundImageOpacitySlider->setValue( ui->backgroundImageOpacitySlider->setValue(
m_gui_settings->GetValue(gui::gl_backgroundImageOpacity).toInt()); m_gui_settings->GetValue(gui::gl_backgroundImageOpacity).toInt());
ui->showBackgroundImageCheckBox->setChecked( ui->showBackgroundImageCheckBox->setChecked(
@ -555,7 +541,6 @@ void SettingsDialog::LoadValuesFromConfig() {
backgroundImageOpacitySlider_backup = backgroundImageOpacitySlider_backup =
m_gui_settings->GetValue(gui::gl_backgroundImageOpacity).toInt(); m_gui_settings->GetValue(gui::gl_backgroundImageOpacity).toInt();
bgm_volume_backup = m_gui_settings->GetValue(gui::gl_backgroundMusicVolume).toInt(); bgm_volume_backup = m_gui_settings->GetValue(gui::gl_backgroundMusicVolume).toInt();
volume_slider_backup = m_gui_settings->GetValue(gui::gl_VolumeSlider).toInt();
} }
void SettingsDialog::InitializeEmulatorLanguages() { void SettingsDialog::InitializeEmulatorLanguages() {
@ -614,10 +599,6 @@ void SettingsDialog::OnCursorStateChanged(s16 index) {
} }
} }
void SettingsDialog::VolumeSliderChange(int value) {
ui->volumeText->setText(QString::number(ui->horizontalVolumeSlider->sliderPosition()) + "%");
}
int SettingsDialog::exec() { int SettingsDialog::exec() {
return QDialog::exec(); return QDialog::exec();
} }
@ -738,6 +719,7 @@ bool SettingsDialog::eventFilter(QObject* obj, QEvent* event) {
if (qobject_cast<QWidget*>(obj)) { if (qobject_cast<QWidget*>(obj)) {
bool hovered = (event->type() == QEvent::Enter); bool hovered = (event->type() == QEvent::Enter);
QString elementName = obj->objectName(); QString elementName = obj->objectName();
if (hovered) { if (hovered) {
updateNoteTextEdit(elementName); updateNoteTextEdit(elementName);
} else { } else {
@ -777,7 +759,6 @@ void SettingsDialog::UpdateSettings() {
Config::setCursorState(ui->hideCursorComboBox->currentIndex()); Config::setCursorState(ui->hideCursorComboBox->currentIndex());
Config::setCursorHideTimeout(ui->idleTimeoutSpinBox->value()); Config::setCursorHideTimeout(ui->idleTimeoutSpinBox->value());
Config::setGpuId(ui->graphicsAdapterBox->currentIndex() - 1); Config::setGpuId(ui->graphicsAdapterBox->currentIndex() - 1);
m_gui_settings->SetValue(gui::gl_VolumeSlider, ui->horizontalVolumeSlider->value());
m_gui_settings->SetValue(gui::gl_backgroundMusicVolume, ui->BGMVolumeSlider->value()); m_gui_settings->SetValue(gui::gl_backgroundMusicVolume, ui->BGMVolumeSlider->value());
Config::setLanguage(languageIndexes[ui->consoleLanguageComboBox->currentIndex()]); Config::setLanguage(languageIndexes[ui->consoleLanguageComboBox->currentIndex()]);
Config::setEnableDiscordRPC(ui->discordRPCCheckbox->isChecked()); Config::setEnableDiscordRPC(ui->discordRPCCheckbox->isChecked());
@ -834,10 +815,9 @@ void SettingsDialog::UpdateSettings() {
#endif #endif
BackgroundMusicPlayer::getInstance().setVolume(ui->BGMVolumeSlider->value()); BackgroundMusicPlayer::getInstance().setVolume(ui->BGMVolumeSlider->value());
Config::setVolumeSlider(ui->horizontalVolumeSlider->value());
} }
void SettingsDialog::SyncRealTimeWidgetstoConfig() { void SettingsDialog::ResetInstallFolders() {
ui->gameFoldersListWidget->clear(); ui->gameFoldersListWidget->clear();
std::filesystem::path userdir = Common::FS::GetUserPath(Common::FS::PathType::UserDir); std::filesystem::path userdir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
@ -885,7 +865,6 @@ void SettingsDialog::setDefaultValues() {
m_gui_settings->SetValue(gui::gl_backgroundImageOpacity, 50); m_gui_settings->SetValue(gui::gl_backgroundImageOpacity, 50);
m_gui_settings->SetValue(gui::gl_playBackgroundMusic, false); m_gui_settings->SetValue(gui::gl_playBackgroundMusic, false);
m_gui_settings->SetValue(gui::gl_backgroundMusicVolume, 50); m_gui_settings->SetValue(gui::gl_backgroundMusicVolume, 50);
m_gui_settings->SetValue(gui::gl_VolumeSlider, 100);
m_gui_settings->SetValue(gui::gen_checkForUpdates, false); m_gui_settings->SetValue(gui::gen_checkForUpdates, false);
m_gui_settings->SetValue(gui::gen_showChangeLog, false); m_gui_settings->SetValue(gui::gen_showChangeLog, false);
if (Common::g_is_release) { if (Common::g_is_release) {

View File

@ -39,13 +39,12 @@ signals:
private: private:
void LoadValuesFromConfig(); void LoadValuesFromConfig();
void UpdateSettings(); void UpdateSettings();
void SyncRealTimeWidgetstoConfig(); void ResetInstallFolders();
void InitializeEmulatorLanguages(); void InitializeEmulatorLanguages();
void OnLanguageChanged(int index); void OnLanguageChanged(int index);
void OnCursorStateChanged(s16 index); void OnCursorStateChanged(s16 index);
void closeEvent(QCloseEvent* event) override; void closeEvent(QCloseEvent* event) override;
void setDefaultValues(); void setDefaultValues();
void VolumeSliderChange(int value);
std::unique_ptr<Ui::SettingsDialog> ui; std::unique_ptr<Ui::SettingsDialog> ui;

View File

@ -59,7 +59,7 @@
</size> </size>
</property> </property>
<property name="currentIndex"> <property name="currentIndex">
<number>0</number> <number>5</number>
</property> </property>
<widget class="QScrollArea" name="generalTab"> <widget class="QScrollArea" name="generalTab">
<property name="widgetResizable"> <property name="widgetResizable">
@ -73,8 +73,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>944</width> <width>946</width>
<height>537</height> <height>536</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="generalTabVLayout" stretch="0"> <layout class="QVBoxLayout" name="generalTabVLayout" stretch="0">
@ -86,20 +86,135 @@
<property name="spacing"> <property name="spacing">
<number>6</number> <number>6</number>
</property> </property>
<item row="2" column="0"> <item row="0" column="1">
<spacer name="verticalSpacer_3"> <layout class="QVBoxLayout" name="emulatorTabLayoutMiddle">
<property name="orientation"> <property name="leftMargin">
<enum>Qt::Orientation::Vertical</enum> <number>0</number>
</property> </property>
<property name="sizeHint" stdset="0"> <property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="emulatorSettingsGroupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Emulator</string>
</property>
<property name="flat">
<bool>false</bool>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="additionalSettingsVLayout" stretch="0">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>9</number>
</property>
<property name="topMargin">
<number>9</number>
</property>
<property name="rightMargin">
<number>9</number>
</property>
<property name="bottomMargin">
<number>9</number>
</property>
<item>
<layout class="QVBoxLayout" name="emulatorverticalLayout">
<property name="spacing">
<number>10</number>
</property>
<item>
<widget class="QCheckBox" name="showSplashCheckBox">
<property name="text">
<string>Show Splash</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="discordRPCCheckbox">
<property name="text">
<string>Enable Discord Rich Presence</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item row="0" column="0">
<layout class="QVBoxLayout" name="systemTabLayoutLeft">
<property name="spacing">
<number>6</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="SystemSettings">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sizeIncrement">
<size> <size>
<width>20</width> <width>0</width>
<height>40</height> <height>0</height>
</size> </size>
</property> </property>
</spacer> <property name="title">
<string>System</string>
</property>
<layout class="QVBoxLayout" name="emuSettingsLayout">
<property name="bottomMargin">
<number>70</number>
</property>
<item>
<widget class="QGroupBox" name="consoleLanguageGroupBox">
<property name="title">
<string>Console Language</string>
</property>
<layout class="QVBoxLayout" name="settingsLayout">
<item>
<widget class="QComboBox" name="consoleLanguageComboBox"/>
</item> </item>
<item row="2" column="2"> </layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="emulatorLanguageGroupBox">
<property name="title">
<string>Emulator Language</string>
</property>
<layout class="QVBoxLayout" name="langSettingsLayout">
<item>
<widget class="QComboBox" name="emulatorLanguageComboBox"/>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item row="1" column="1">
<spacer name="verticalSpacer_4"> <spacer name="verticalSpacer_4">
<property name="orientation"> <property name="orientation">
<enum>Qt::Orientation::Vertical</enum> <enum>Qt::Orientation::Vertical</enum>
@ -112,7 +227,33 @@
</property> </property>
</spacer> </spacer>
</item> </item>
<item row="0" column="3"> <item row="1" column="0">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="2">
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="2">
<layout class="QVBoxLayout" name="updaterTabLayoutLeft"> <layout class="QVBoxLayout" name="updaterTabLayoutLeft">
<property name="spacing"> <property name="spacing">
<number>6</number> <number>6</number>
@ -286,228 +427,6 @@
</item> </item>
</layout> </layout>
</item> </item>
<item row="0" column="0">
<layout class="QVBoxLayout" name="systemTabLayoutLeft">
<property name="spacing">
<number>6</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="SystemSettings">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sizeIncrement">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="title">
<string>System</string>
</property>
<layout class="QVBoxLayout" name="emuSettingsLayout">
<property name="bottomMargin">
<number>70</number>
</property>
<item>
<widget class="QGroupBox" name="consoleLanguageGroupBox">
<property name="title">
<string>Console Language</string>
</property>
<layout class="QVBoxLayout" name="settingsLayout">
<item>
<widget class="QComboBox" name="consoleLanguageComboBox"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="emulatorLanguageGroupBox">
<property name="title">
<string>Emulator Language</string>
</property>
<layout class="QVBoxLayout" name="langSettingsLayout">
<item>
<widget class="QComboBox" name="emulatorLanguageComboBox"/>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QGroupBox" name="volumeSliderElement">
<property name="title">
<string>Volume</string>
</property>
<layout class="QVBoxLayout" name="volumeLayout">
<item>
<widget class="QScrollArea" name="scrollArea">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string/>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents_2">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>414</width>
<height>69</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QLineEdit" name="volumeText">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>100%</string>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignCenter</set>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="horizontalVolumeSlider">
<property name="focusPolicy">
<enum>Qt::FocusPolicy::StrongFocus</enum>
</property>
<property name="maximum">
<number>500</number>
</property>
<property name="value">
<number>100</number>
</property>
<property name="sliderPosition">
<number>100</number>
</property>
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="2">
<layout class="QVBoxLayout" name="emulatorTabLayoutMiddle">
<property name="leftMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="emulatorSettingsGroupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Emulator</string>
</property>
<property name="flat">
<bool>false</bool>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="additionalSettingsVLayout" stretch="0">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>9</number>
</property>
<property name="topMargin">
<number>9</number>
</property>
<property name="rightMargin">
<number>9</number>
</property>
<property name="bottomMargin">
<number>9</number>
</property>
<item>
<layout class="QVBoxLayout" name="emulatorverticalLayout">
<property name="spacing">
<number>10</number>
</property>
<item>
<widget class="QCheckBox" name="showSplashCheckBox">
<property name="text">
<string>Show Splash</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="discordRPCCheckbox">
<property name="text">
<string>Enable Discord Rich Presence</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item row="2" column="3">
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout> </layout>
</item> </item>
</layout> </layout>
@ -525,8 +444,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>944</width> <width>946</width>
<height>537</height> <height>536</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="guiTabVLayout" stretch="0"> <layout class="QVBoxLayout" name="guiTabVLayout" stretch="0">
@ -781,7 +700,7 @@
<item> <item>
<widget class="QLabel" name="label_Volume"> <widget class="QLabel" name="label_Volume">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed"> <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
@ -974,8 +893,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>944</width> <width>946</width>
<height>537</height> <height>536</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="graphicsTabVLayout" stretch="0,0"> <layout class="QVBoxLayout" name="graphicsTabVLayout" stretch="0,0">
@ -1269,8 +1188,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>944</width> <width>946</width>
<height>537</height> <height>536</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="userTabVLayout" stretch="0,0,1"> <layout class="QVBoxLayout" name="userTabVLayout" stretch="0,0,1">
@ -1511,8 +1430,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>944</width> <width>946</width>
<height>537</height> <height>536</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="inputTabVLayout" stretch="0,0"> <layout class="QVBoxLayout" name="inputTabVLayout" stretch="0,0">
@ -1765,8 +1684,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>944</width> <width>946</width>
<height>537</height> <height>536</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="pathsTabLayout"> <layout class="QVBoxLayout" name="pathsTabLayout">
@ -1907,8 +1826,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>944</width> <width>946</width>
<height>537</height> <height>536</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="debugTabVLayout" stretch="0,0"> <layout class="QVBoxLayout" name="debugTabVLayout" stretch="0,0">

View File

@ -268,7 +268,6 @@ Id EmitBufferAtomicFMin32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id addre
const auto sign_bit_set = const auto sign_bit_set =
ctx.OpBitFieldUExtract(ctx.U32[1], u32_value, ctx.ConstU32(31u), ctx.ConstU32(1u)); ctx.OpBitFieldUExtract(ctx.U32[1], u32_value, ctx.ConstU32(31u), ctx.ConstU32(1u));
// FIXME this needs control flow because it currently executes both atomics
const auto result = ctx.OpSelect( const auto result = ctx.OpSelect(
ctx.F32[1], sign_bit_set, ctx.F32[1], sign_bit_set,
EmitBitCastF32U32(ctx, EmitBufferAtomicUMax32(ctx, inst, handle, address, u32_value)), EmitBitCastF32U32(ctx, EmitBufferAtomicUMax32(ctx, inst, handle, address, u32_value)),
@ -303,7 +302,6 @@ Id EmitBufferAtomicFMax32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id addre
const auto sign_bit_set = const auto sign_bit_set =
ctx.OpBitFieldUExtract(ctx.U32[1], u32_value, ctx.ConstU32(31u), ctx.ConstU32(1u)); ctx.OpBitFieldUExtract(ctx.U32[1], u32_value, ctx.ConstU32(31u), ctx.ConstU32(1u));
// FIXME this needs control flow because it currently executes both atomics
const auto result = ctx.OpSelect( const auto result = ctx.OpSelect(
ctx.F32[1], sign_bit_set, ctx.F32[1], sign_bit_set,
EmitBitCastF32U32(ctx, EmitBufferAtomicUMin32(ctx, inst, handle, address, u32_value)), EmitBitCastF32U32(ctx, EmitBufferAtomicUMin32(ctx, inst, handle, address, u32_value)),

View File

@ -7,32 +7,60 @@
namespace Shader::Backend::SPIRV { namespace Shader::Backend::SPIRV {
namespace { namespace {
Id ExtractU16(EmitContext& ctx, Id value) { Id ExtractU16(EmitContext& ctx, Id value) {
if (ctx.profile.support_int16) {
return ctx.OpUConvert(ctx.U16, value); return ctx.OpUConvert(ctx.U16, value);
} else {
return ctx.OpBitFieldUExtract(ctx.U32[1], value, ctx.u32_zero_value, ctx.ConstU32(16u));
}
} }
Id ExtractS16(EmitContext& ctx, Id value) { Id ExtractS16(EmitContext& ctx, Id value) {
if (ctx.profile.support_int16) {
return ctx.OpSConvert(ctx.S16, value); return ctx.OpSConvert(ctx.S16, value);
} else {
return ctx.OpBitFieldSExtract(ctx.U32[1], value, ctx.u32_zero_value, ctx.ConstU32(16u));
}
} }
Id ExtractU8(EmitContext& ctx, Id value) { Id ExtractU8(EmitContext& ctx, Id value) {
if (ctx.profile.support_int8) {
return ctx.OpUConvert(ctx.U8, value); return ctx.OpUConvert(ctx.U8, value);
} else {
return ctx.OpBitFieldUExtract(ctx.U32[1], value, ctx.u32_zero_value, ctx.ConstU32(8u));
}
} }
Id ExtractS8(EmitContext& ctx, Id value) { Id ExtractS8(EmitContext& ctx, Id value) {
if (ctx.profile.support_int8) {
return ctx.OpSConvert(ctx.S8, value); return ctx.OpSConvert(ctx.S8, value);
} else {
return ctx.OpBitFieldSExtract(ctx.U32[1], value, ctx.u32_zero_value, ctx.ConstU32(8u));
}
} }
} // Anonymous namespace } // Anonymous namespace
Id EmitConvertS16F16(EmitContext& ctx, Id value) { Id EmitConvertS16F16(EmitContext& ctx, Id value) {
if (ctx.profile.support_int16) {
return ctx.OpSConvert(ctx.U32[1], ctx.OpConvertFToS(ctx.U16, value)); return ctx.OpSConvert(ctx.U32[1], ctx.OpConvertFToS(ctx.U16, value));
} else {
return ExtractS16(ctx, ctx.OpConvertFToS(ctx.U32[1], value));
}
} }
Id EmitConvertS16F32(EmitContext& ctx, Id value) { Id EmitConvertS16F32(EmitContext& ctx, Id value) {
if (ctx.profile.support_int16) {
return ctx.OpSConvert(ctx.U32[1], ctx.OpConvertFToS(ctx.U16, value)); return ctx.OpSConvert(ctx.U32[1], ctx.OpConvertFToS(ctx.U16, value));
} else {
return ExtractS16(ctx, ctx.OpConvertFToS(ctx.U32[1], value));
}
} }
Id EmitConvertS16F64(EmitContext& ctx, Id value) { Id EmitConvertS16F64(EmitContext& ctx, Id value) {
if (ctx.profile.support_int16) {
return ctx.OpSConvert(ctx.U32[1], ctx.OpConvertFToS(ctx.U16, value)); return ctx.OpSConvert(ctx.U32[1], ctx.OpConvertFToS(ctx.U16, value));
} else {
return ExtractS16(ctx, ctx.OpConvertFToS(ctx.U32[1], value));
}
} }
Id EmitConvertS32F16(EmitContext& ctx, Id value) { Id EmitConvertS32F16(EmitContext& ctx, Id value) {
@ -60,15 +88,27 @@ Id EmitConvertS64F64(EmitContext& ctx, Id value) {
} }
Id EmitConvertU16F16(EmitContext& ctx, Id value) { Id EmitConvertU16F16(EmitContext& ctx, Id value) {
if (ctx.profile.support_int16) {
return ctx.OpUConvert(ctx.U32[1], ctx.OpConvertFToU(ctx.U16, value)); return ctx.OpUConvert(ctx.U32[1], ctx.OpConvertFToU(ctx.U16, value));
} else {
return ExtractU16(ctx, ctx.OpConvertFToU(ctx.U32[1], value));
}
} }
Id EmitConvertU16F32(EmitContext& ctx, Id value) { Id EmitConvertU16F32(EmitContext& ctx, Id value) {
if (ctx.profile.support_int16) {
return ctx.OpUConvert(ctx.U32[1], ctx.OpConvertFToU(ctx.U16, value)); return ctx.OpUConvert(ctx.U32[1], ctx.OpConvertFToU(ctx.U16, value));
} else {
return ExtractU16(ctx, ctx.OpConvertFToU(ctx.U32[1], value));
}
} }
Id EmitConvertU16F64(EmitContext& ctx, Id value) { Id EmitConvertU16F64(EmitContext& ctx, Id value) {
if (ctx.profile.support_int16) {
return ctx.OpUConvert(ctx.U32[1], ctx.OpConvertFToU(ctx.U16, value)); return ctx.OpUConvert(ctx.U32[1], ctx.OpConvertFToU(ctx.U16, value));
} else {
return ExtractU16(ctx, ctx.OpConvertFToU(ctx.U32[1], value));
}
} }
Id EmitConvertU32F16(EmitContext& ctx, Id value) { Id EmitConvertU32F16(EmitContext& ctx, Id value) {
@ -231,12 +271,4 @@ Id EmitConvertU32U8(EmitContext& ctx, Id value) {
return ctx.OpUConvert(ctx.U32[1], value); return ctx.OpUConvert(ctx.U32[1], value);
} }
Id EmitConvertS32S8(EmitContext& ctx, Id value) {
return ctx.OpSConvert(ctx.U32[1], value);
}
Id EmitConvertS32S16(EmitContext& ctx, Id value) {
return ctx.OpSConvert(ctx.U32[1], value);
}
} // namespace Shader::Backend::SPIRV } // namespace Shader::Backend::SPIRV

View File

@ -488,8 +488,6 @@ Id EmitConvertU16U32(EmitContext& ctx, Id value);
Id EmitConvertU32U16(EmitContext& ctx, Id value); Id EmitConvertU32U16(EmitContext& ctx, Id value);
Id EmitConvertU8U32(EmitContext& ctx, Id value); Id EmitConvertU8U32(EmitContext& ctx, Id value);
Id EmitConvertU32U8(EmitContext& ctx, Id value); Id EmitConvertU32U8(EmitContext& ctx, Id value);
Id EmitConvertS32S8(EmitContext& ctx, Id value);
Id EmitConvertS32S16(EmitContext& ctx, Id value);
Id EmitImageSampleRaw(EmitContext& ctx, IR::Inst* inst, u32 handle, Id address1, Id address2, Id EmitImageSampleRaw(EmitContext& ctx, IR::Inst* inst, u32 handle, Id address1, Id address2,
Id address3, Id address4); Id address3, Id address4);

View File

@ -117,9 +117,7 @@ void EmitContext::DefineArithmeticTypes() {
void_id = Name(TypeVoid(), "void_id"); void_id = Name(TypeVoid(), "void_id");
U1[1] = Name(TypeBool(), "bool_id"); U1[1] = Name(TypeBool(), "bool_id");
U8 = Name(TypeUInt(8), "u8_id"); U8 = Name(TypeUInt(8), "u8_id");
S8 = Name(TypeSInt(8), "i8_id");
U16 = Name(TypeUInt(16), "u16_id"); U16 = Name(TypeUInt(16), "u16_id");
S16 = Name(TypeSInt(16), "i16_id");
if (info.uses_fp16) { if (info.uses_fp16) {
F16[1] = Name(TypeFloat(16), "f16_id"); F16[1] = Name(TypeFloat(16), "f16_id");
U16 = Name(TypeUInt(16), "u16_id"); U16 = Name(TypeUInt(16), "u16_id");

View File

@ -281,10 +281,9 @@ public:
// Buffer Memory // Buffer Memory
// MUBUF / MTBUF // MUBUF / MTBUF
void BUFFER_LOAD(u32 num_dwords, bool is_inst_typed, bool is_buffer_typed, const GcnInst& inst, void BUFFER_LOAD(u32 num_dwords, bool is_inst_typed, bool is_buffer_typed, const GcnInst& inst);
u32 scalar_width = 32, bool is_signed = false); void BUFFER_STORE(u32 num_dwords, bool is_inst_typed, bool is_buffer_typed,
void BUFFER_STORE(u32 num_dwords, bool is_inst_typed, bool is_buffer_typed, const GcnInst& inst, const GcnInst& inst);
u32 scalar_width = 32);
template <typename T = IR::U32> template <typename T = IR::U32>
void BUFFER_ATOMIC(AtomicOp op, const GcnInst& inst); void BUFFER_ATOMIC(AtomicOp op, const GcnInst& inst);

View File

@ -28,15 +28,6 @@ void Translator::EmitVectorMemory(const GcnInst& inst) {
case Opcode::BUFFER_LOAD_FORMAT_XYZW: case Opcode::BUFFER_LOAD_FORMAT_XYZW:
return BUFFER_LOAD(4, false, true, inst); return BUFFER_LOAD(4, false, true, inst);
case Opcode::BUFFER_LOAD_UBYTE:
return BUFFER_LOAD(1, false, false, inst, 8, false);
case Opcode::BUFFER_LOAD_SBYTE:
return BUFFER_LOAD(1, false, false, inst, 8, true);
case Opcode::BUFFER_LOAD_USHORT:
return BUFFER_LOAD(1, false, false, inst, 16, false);
case Opcode::BUFFER_LOAD_SSHORT:
return BUFFER_LOAD(1, false, false, inst, 16, true);
case Opcode::BUFFER_LOAD_DWORD: case Opcode::BUFFER_LOAD_DWORD:
return BUFFER_LOAD(1, false, false, inst); return BUFFER_LOAD(1, false, false, inst);
case Opcode::BUFFER_LOAD_DWORDX2: case Opcode::BUFFER_LOAD_DWORDX2:
@ -65,11 +56,6 @@ void Translator::EmitVectorMemory(const GcnInst& inst) {
case Opcode::TBUFFER_STORE_FORMAT_XYZW: case Opcode::TBUFFER_STORE_FORMAT_XYZW:
return BUFFER_STORE(4, true, false, inst); return BUFFER_STORE(4, true, false, inst);
case Opcode::BUFFER_STORE_BYTE:
return BUFFER_STORE(1, false, false, inst, 8);
case Opcode::BUFFER_STORE_SHORT:
return BUFFER_STORE(1, false, false, inst, 16);
case Opcode::BUFFER_STORE_DWORD: case Opcode::BUFFER_STORE_DWORD:
return BUFFER_STORE(1, false, false, inst); return BUFFER_STORE(1, false, false, inst);
case Opcode::BUFFER_STORE_DWORDX2: case Opcode::BUFFER_STORE_DWORDX2:
@ -200,7 +186,7 @@ void Translator::EmitVectorMemory(const GcnInst& inst) {
} }
void Translator::BUFFER_LOAD(u32 num_dwords, bool is_inst_typed, bool is_buffer_typed, void Translator::BUFFER_LOAD(u32 num_dwords, bool is_inst_typed, bool is_buffer_typed,
const GcnInst& inst, u32 scalar_width, bool is_signed) { const GcnInst& inst) {
const auto& mubuf = inst.control.mubuf; const auto& mubuf = inst.control.mubuf;
const bool is_ring = mubuf.glc && mubuf.slc; const bool is_ring = mubuf.glc && mubuf.slc;
const IR::VectorReg vaddr{inst.src[0].code}; const IR::VectorReg vaddr{inst.src[0].code};
@ -256,26 +242,7 @@ void Translator::BUFFER_LOAD(u32 num_dwords, bool is_inst_typed, bool is_buffer_
ir.SetVectorReg(dst_reg + i, IR::F32{ir.CompositeExtract(value, i)}); ir.SetVectorReg(dst_reg + i, IR::F32{ir.CompositeExtract(value, i)});
} }
} else { } else {
IR::Value value; const IR::Value value = ir.LoadBufferU32(num_dwords, handle, address, buffer_info);
switch (scalar_width) {
case 8: {
IR::U8 byte_val = ir.LoadBufferU8(handle, address, buffer_info);
value = is_signed ? ir.SConvert(32, byte_val) : ir.UConvert(32, byte_val);
break;
}
case 16: {
IR::U16 short_val = ir.LoadBufferU16(handle, address, buffer_info);
value = is_signed ? ir.SConvert(32, short_val) : ir.UConvert(32, short_val);
break;
}
case 32:
value = ir.LoadBufferU32(num_dwords, handle, address, buffer_info);
break;
default:
UNREACHABLE();
}
if (num_dwords == 1) { if (num_dwords == 1) {
ir.SetVectorReg(dst_reg, IR::U32{value}); ir.SetVectorReg(dst_reg, IR::U32{value});
return; return;
@ -287,7 +254,7 @@ void Translator::BUFFER_LOAD(u32 num_dwords, bool is_inst_typed, bool is_buffer_
} }
void Translator::BUFFER_STORE(u32 num_dwords, bool is_inst_typed, bool is_buffer_typed, void Translator::BUFFER_STORE(u32 num_dwords, bool is_inst_typed, bool is_buffer_typed,
const GcnInst& inst, u32 scalar_width) { const GcnInst& inst) {
const auto& mubuf = inst.control.mubuf; const auto& mubuf = inst.control.mubuf;
const bool is_ring = mubuf.glc && mubuf.slc; const bool is_ring = mubuf.glc && mubuf.slc;
const IR::VectorReg vaddr{inst.src[0].code}; const IR::VectorReg vaddr{inst.src[0].code};
@ -347,23 +314,8 @@ void Translator::BUFFER_STORE(u32 num_dwords, bool is_inst_typed, bool is_buffer
} }
ir.StoreBufferFormat(handle, address, ir.CompositeConstruct(comps), buffer_info); ir.StoreBufferFormat(handle, address, ir.CompositeConstruct(comps), buffer_info);
} else { } else {
IR::Value value = num_dwords == 1 ? comps[0] : ir.CompositeConstruct(comps); const auto value = num_dwords == 1 ? comps[0] : ir.CompositeConstruct(comps);
if (scalar_width != 32) {
value = ir.UConvert(scalar_width, IR::U32{value});
}
switch (scalar_width) {
case 8:
ir.StoreBufferU8(handle, address, IR::U8{value}, buffer_info);
break;
case 16:
ir.StoreBufferU16(handle, address, IR::U16{value}, buffer_info);
break;
case 32:
ir.StoreBufferU32(num_dwords, handle, address, value, buffer_info); ir.StoreBufferU32(num_dwords, handle, address, value, buffer_info);
break;
default:
UNREACHABLE();
}
} }
} }

View File

@ -1979,24 +1979,6 @@ U8U16U32U64 IREmitter::UConvert(size_t result_bitsize, const U8U16U32U64& value)
throw NotImplementedException("Conversion from {} to {} bits", value.Type(), result_bitsize); throw NotImplementedException("Conversion from {} to {} bits", value.Type(), result_bitsize);
} }
U8U16U32U64 IR::IREmitter::SConvert(size_t result_bitsize, const U8U16U32U64& value) {
switch (result_bitsize) {
case 32:
switch (value.Type()) {
case Type::U8:
return Inst<U32>(Opcode::ConvertS32S8, value);
case Type::U16:
return Inst<U32>(Opcode::ConvertS32S16, value);
default:
break;
}
default:
break;
}
throw NotImplementedException("Signed Conversion from {} to {} bits", value.Type(),
result_bitsize);
}
F16F32F64 IREmitter::FPConvert(size_t result_bitsize, const F16F32F64& value) { F16F32F64 IREmitter::FPConvert(size_t result_bitsize, const F16F32F64& value) {
switch (result_bitsize) { switch (result_bitsize) {
case 16: case 16:

View File

@ -325,7 +325,6 @@ public:
const Value& value); const Value& value);
[[nodiscard]] U8U16U32U64 UConvert(size_t result_bitsize, const U8U16U32U64& value); [[nodiscard]] U8U16U32U64 UConvert(size_t result_bitsize, const U8U16U32U64& value);
[[nodiscard]] U8U16U32U64 SConvert(size_t result_bitsize, const U8U16U32U64& value);
[[nodiscard]] F16F32F64 FPConvert(size_t result_bitsize, const F16F32F64& value); [[nodiscard]] F16F32F64 FPConvert(size_t result_bitsize, const F16F32F64& value);
[[nodiscard]] Value ImageAtomicIAdd(const Value& handle, const Value& coords, [[nodiscard]] Value ImageAtomicIAdd(const Value& handle, const Value& coords,

View File

@ -432,8 +432,6 @@ OPCODE(ConvertU16U32, U16, U32,
OPCODE(ConvertU32U16, U32, U16, ) OPCODE(ConvertU32U16, U32, U16, )
OPCODE(ConvertU8U32, U8, U32, ) OPCODE(ConvertU8U32, U8, U32, )
OPCODE(ConvertU32U8, U32, U8, ) OPCODE(ConvertU32U8, U32, U8, )
OPCODE(ConvertS32S8, U32, U8, )
OPCODE(ConvertS32S16, U32, U16, )
// Image operations // Image operations
OPCODE(ImageSampleRaw, F32x4, Opaque, F32x4, F32x4, F32x4, F32, Opaque, ) OPCODE(ImageSampleRaw, F32x4, Opaque, F32x4, F32x4, F32x4, F32, Opaque, )

View File

@ -171,7 +171,6 @@ enum class MrtSwizzle : u8 {
static constexpr u32 MaxColorBuffers = 8; static constexpr u32 MaxColorBuffers = 8;
struct PsColorBuffer { struct PsColorBuffer {
AmdGpu::DataFormat data_format : 6;
AmdGpu::NumberFormat num_format : 4; AmdGpu::NumberFormat num_format : 4;
AmdGpu::NumberConversion num_conversion : 3; AmdGpu::NumberConversion num_conversion : 3;
AmdGpu::Liverpool::ShaderExportFormat export_format : 4; AmdGpu::Liverpool::ShaderExportFormat export_format : 4;

View File

@ -248,15 +248,6 @@ constexpr CompMapping RemapSwizzle(const DataFormat format, const CompMapping sw
result.a = swizzle.r; result.a = swizzle.r;
return result; return result;
} }
case DataFormat::Format5_6_5: {
// Remap to a more supported component order.
CompMapping result;
result.r = swizzle.b;
result.g = swizzle.g;
result.b = swizzle.r;
result.a = swizzle.a;
return result;
}
default: default:
return swizzle; return swizzle;
} }

View File

@ -961,15 +961,15 @@ bool BufferCache::SynchronizeBufferFromImage(Buffer& buffer, VAddr device_addr,
const u32 height = std::max(image.info.size.height >> m, 1u); const u32 height = std::max(image.info.size.height >> m, 1u);
const u32 depth = const u32 depth =
image.info.props.is_volume ? std::max(image.info.size.depth >> m, 1u) : 1u; image.info.props.is_volume ? std::max(image.info.size.depth >> m, 1u) : 1u;
const auto [mip_size, mip_pitch, mip_height, mip_ofs] = image.info.mips_layout[m]; const auto& [mip_size, mip_pitch, mip_height, mip_ofs] = image.info.mips_layout[m];
offset += mip_ofs; offset += mip_ofs;
if (offset + mip_size > max_offset) { if (offset + mip_size > max_offset) {
break; break;
} }
copies.push_back({ copies.push_back({
.bufferOffset = offset, .bufferOffset = offset,
.bufferRowLength = mip_pitch, .bufferRowLength = static_cast<u32>(mip_pitch),
.bufferImageHeight = mip_height, .bufferImageHeight = static_cast<u32>(mip_height),
.imageSubresource{ .imageSubresource{
.aspectMask = image.aspect_mask & ~vk::ImageAspectFlagBits::eStencil, .aspectMask = image.aspect_mask & ~vk::ImageAspectFlagBits::eStencil,
.mipLevel = m, .mipLevel = m,

View File

@ -671,7 +671,7 @@ std::span<const SurfaceFormatInfo> SurfaceFormats() {
vk::Format::eR32G32B32A32Sfloat), vk::Format::eR32G32B32A32Sfloat),
// 5_6_5 // 5_6_5
CreateSurfaceFormatInfo(AmdGpu::DataFormat::Format5_6_5, AmdGpu::NumberFormat::Unorm, CreateSurfaceFormatInfo(AmdGpu::DataFormat::Format5_6_5, AmdGpu::NumberFormat::Unorm,
vk::Format::eR5G6B5UnormPack16), vk::Format::eB5G6R5UnormPack16),
// 1_5_5_5 // 1_5_5_5
CreateSurfaceFormatInfo(AmdGpu::DataFormat::Format1_5_5_5, AmdGpu::NumberFormat::Unorm, CreateSurfaceFormatInfo(AmdGpu::DataFormat::Format1_5_5_5, AmdGpu::NumberFormat::Unorm,
vk::Format::eA1R5G5B5UnormPack16), vk::Format::eA1R5G5B5UnormPack16),

View File

@ -244,24 +244,9 @@ GraphicsPipeline::GraphicsPipeline(
const auto depth_format = const auto depth_format =
instance.GetSupportedFormat(LiverpoolToVK::DepthFormat(key.z_format, key.stencil_format), instance.GetSupportedFormat(LiverpoolToVK::DepthFormat(key.z_format, key.stencil_format),
vk::FormatFeatureFlagBits2::eDepthStencilAttachment); vk::FormatFeatureFlagBits2::eDepthStencilAttachment);
std::array<vk::Format, Shader::IR::NumRenderTargets> color_formats;
for (s32 i = 0; i < key.num_color_attachments; ++i) {
const auto& col_buf = key.color_buffers[i];
const auto format = LiverpoolToVK::SurfaceFormat(col_buf.data_format, col_buf.num_format);
const auto color_format =
instance.GetSupportedFormat(format, vk::FormatFeatureFlagBits2::eColorAttachment);
if (!instance.IsFormatSupported(color_format,
vk::FormatFeatureFlagBits2::eColorAttachment)) {
LOG_WARNING(Render_Vulkan,
"color buffer format {} does not support COLOR_ATTACHMENT_BIT",
vk::to_string(color_format));
}
color_formats[i] = color_format;
}
const vk::PipelineRenderingCreateInfo pipeline_rendering_ci = { const vk::PipelineRenderingCreateInfo pipeline_rendering_ci = {
.colorAttachmentCount = key.num_color_attachments, .colorAttachmentCount = key.num_color_attachments,
.pColorAttachmentFormats = color_formats.data(), .pColorAttachmentFormats = key.color_formats.data(),
.depthAttachmentFormat = key.z_format != Liverpool::DepthBuffer::ZFormat::Invalid .depthAttachmentFormat = key.z_format != Liverpool::DepthBuffer::ZFormat::Invalid
? depth_format ? depth_format
: vk::Format::eUndefined, : vk::Format::eUndefined,

View File

@ -36,6 +36,7 @@ struct GraphicsPipelineKey {
std::array<vk::Format, MaxVertexBufferCount> vertex_buffer_formats; std::array<vk::Format, MaxVertexBufferCount> vertex_buffer_formats;
u32 patch_control_points; u32 patch_control_points;
u32 num_color_attachments; u32 num_color_attachments;
std::array<vk::Format, Liverpool::NumColorBuffers> color_formats;
std::array<Shader::PsColorBuffer, Liverpool::NumColorBuffers> color_buffers; std::array<Shader::PsColorBuffer, Liverpool::NumColorBuffers> color_buffers;
std::array<Liverpool::BlendControl, Liverpool::NumColorBuffers> blend_controls; std::array<Liverpool::BlendControl, Liverpool::NumColorBuffers> blend_controls;
std::array<vk::ColorComponentFlags, Liverpool::NumColorBuffers> write_masks; std::array<vk::ColorComponentFlags, Liverpool::NumColorBuffers> write_masks;

View File

@ -669,12 +669,6 @@ vk::Format Instance::GetSupportedFormat(const vk::Format format,
if (IsFormatSupported(vk::Format::eD32SfloatS8Uint, flags)) { if (IsFormatSupported(vk::Format::eD32SfloatS8Uint, flags)) {
return vk::Format::eD32SfloatS8Uint; return vk::Format::eD32SfloatS8Uint;
} }
break;
case vk::Format::eR8Srgb:
if (IsFormatSupported(vk::Format::eR8Unorm, flags)) {
return vk::Format::eR8Unorm;
}
break;
default: default:
break; break;
} }

View File

@ -94,21 +94,6 @@ public:
return features.shaderFloat64; return features.shaderFloat64;
} }
/// Returns true if 64-bit ints are supported in shaders
bool IsShaderInt64Supported() const {
return features.shaderInt64;
}
/// Returns true if 16-bit ints are supported in shaders
bool IsShaderInt16Supported() const {
return features.shaderInt16;
}
/// Returns true if 8-bit ints are supported in shaders
bool IsShaderInt8Supported() const {
return vk12_features.shaderInt8;
}
/// Returns true when VK_EXT_custom_border_color is supported /// Returns true when VK_EXT_custom_border_color is supported
bool IsCustomBorderColorSupported() const { bool IsCustomBorderColorSupported() const {
return custom_border_color; return custom_border_color;

View File

@ -203,9 +203,6 @@ PipelineCache::PipelineCache(const Instance& instance_, Scheduler& scheduler_,
profile = Shader::Profile{ profile = Shader::Profile{
.supported_spirv = SpirvVersion1_6, .supported_spirv = SpirvVersion1_6,
.subgroup_size = instance.SubgroupSize(), .subgroup_size = instance.SubgroupSize(),
.support_int8 = instance.IsShaderInt8Supported(),
.support_int16 = instance.IsShaderInt16Supported(),
.support_int64 = instance.IsShaderInt64Supported(),
.support_float64 = instance.IsShaderFloat64Supported(), .support_float64 = instance.IsShaderFloat64Supported(),
.support_fp32_denorm_preserve = bool(vk12_props.shaderDenormPreserveFloat32), .support_fp32_denorm_preserve = bool(vk12_props.shaderDenormPreserveFloat32),
.support_fp32_denorm_flush = bool(vk12_props.shaderDenormFlushToZeroFloat32), .support_fp32_denorm_flush = bool(vk12_props.shaderDenormFlushToZeroFloat32),
@ -315,6 +312,7 @@ bool PipelineCache::RefreshGraphicsKey() {
// attachments. This might be not a case as HW color buffers can be bound in an arbitrary // attachments. This might be not a case as HW color buffers can be bound in an arbitrary
// order. We need to do some arrays compaction at this stage // order. We need to do some arrays compaction at this stage
key.num_color_attachments = 0; key.num_color_attachments = 0;
key.color_formats.fill(vk::Format::eUndefined);
key.color_buffers.fill({}); key.color_buffers.fill({});
key.blend_controls.fill({}); key.blend_controls.fill({});
key.write_masks.fill({}); key.write_masks.fill({});
@ -350,8 +348,16 @@ bool PipelineCache::RefreshGraphicsKey() {
col_buf.GetDataFmt() == AmdGpu::DataFormat::Format8_8 || col_buf.GetDataFmt() == AmdGpu::DataFormat::Format8_8 ||
col_buf.GetDataFmt() == AmdGpu::DataFormat::Format8_8_8_8); col_buf.GetDataFmt() == AmdGpu::DataFormat::Format8_8_8_8);
const auto format =
LiverpoolToVK::SurfaceFormat(col_buf.GetDataFmt(), col_buf.GetNumberFmt());
key.color_formats[remapped_cb] = format;
if (!instance.IsFormatSupported(format, vk::FormatFeatureFlagBits2::eColorAttachment)) {
LOG_WARNING(Render_Vulkan,
"color buffer format {} does not support COLOR_ATTACHMENT_BIT",
vk::to_string(format));
}
key.color_buffers[remapped_cb] = Shader::PsColorBuffer{ key.color_buffers[remapped_cb] = Shader::PsColorBuffer{
.data_format = col_buf.GetDataFmt(),
.num_format = col_buf.GetNumberFmt(), .num_format = col_buf.GetNumberFmt(),
.num_conversion = col_buf.GetNumberConversion(), .num_conversion = col_buf.GetNumberConversion(),
.export_format = regs.color_export_format.GetFormat(cb), .export_format = regs.color_export_format.GetFormat(cb),
@ -470,7 +476,9 @@ bool PipelineCache::RefreshGraphicsKey() {
// Attachment is masked out by either color_target_mask or shader mrt_mask. In the case // Attachment is masked out by either color_target_mask or shader mrt_mask. In the case
// of the latter we need to change format to undefined, and either way we need to // of the latter we need to change format to undefined, and either way we need to
// increment the index for the null attachment binding. // increment the index for the null attachment binding.
key.color_buffers[remapped_cb++] = {}; key.color_formats[remapped_cb] = vk::Format::eUndefined;
key.color_buffers[remapped_cb] = {};
++remapped_cb;
continue; continue;
} }

View File

@ -126,13 +126,13 @@ void BlitHelper::BlitColorToMsDepth(Image& source, Image& dest) {
.minDepth = 0.f, .minDepth = 0.f,
.maxDepth = 1.f, .maxDepth = 1.f,
}; };
cmdbuf.setViewportWithCount(viewport); cmdbuf.setViewport(0, viewport);
const vk::Rect2D scissor = { const vk::Rect2D scissor = {
.offset = {0, 0}, .offset = {0, 0},
.extent = {state.width, state.height}, .extent = {state.width, state.height},
}; };
cmdbuf.setScissorWithCount(scissor); cmdbuf.setScissor(0, scissor);
cmdbuf.draw(3, 1, 0, 0); cmdbuf.draw(3, 1, 0, 0);

View File

@ -21,7 +21,7 @@ static vk::ImageUsageFlags ImageUsageFlags(const ImageInfo& info) {
if (info.IsDepthStencil()) { if (info.IsDepthStencil()) {
usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment; usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment;
} else { } else {
if (!info.IsBlockCoded()) { if (!info.IsBlockCoded() && !info.IsPacked()) {
usage |= vk::ImageUsageFlagBits::eColorAttachment; usage |= vk::ImageUsageFlagBits::eColorAttachment;
} }
// In cases where an image is created as a render/depth target and cleared with compute, // In cases where an image is created as a render/depth target and cleared with compute,

View File

@ -176,6 +176,17 @@ bool ImageInfo::IsBlockCoded() const {
} }
} }
bool ImageInfo::IsPacked() const {
switch (pixel_format) {
case vk::Format::eB5G5R5A1UnormPack16:
[[fallthrough]];
case vk::Format::eB5G6R5UnormPack16:
return true;
default:
return false;
}
}
bool ImageInfo::IsDepthStencil() const { bool ImageInfo::IsDepthStencil() const {
switch (pixel_format) { switch (pixel_format) {
case vk::Format::eD16Unorm: case vk::Format::eD16Unorm:

View File

@ -31,6 +31,7 @@ struct ImageInfo {
} }
bool IsBlockCoded() const; bool IsBlockCoded() const;
bool IsPacked() const;
bool IsDepthStencil() const; bool IsDepthStencil() const;
bool HasStencil() const; bool HasStencil() const;

View File

@ -605,27 +605,28 @@ void TextureCache::RefreshImage(Image& image, Vulkan::Scheduler* custom_schedule
const u32 height = std::max(image.info.size.height >> m, 1u); const u32 height = std::max(image.info.size.height >> m, 1u);
const u32 depth = const u32 depth =
image.info.props.is_volume ? std::max(image.info.size.depth >> m, 1u) : 1u; image.info.props.is_volume ? std::max(image.info.size.depth >> m, 1u) : 1u;
const auto [mip_size, mip_pitch, mip_height, mip_offset] = image.info.mips_layout[m]; const auto& mip = image.info.mips_layout[m];
// Protect GPU modified resources from accidental CPU reuploads. // Protect GPU modified resources from accidental CPU reuploads.
if (is_gpu_modified && !is_gpu_dirty) { if (is_gpu_modified && !is_gpu_dirty) {
const u8* addr = std::bit_cast<u8*>(image.info.guest_address); const u8* addr = std::bit_cast<u8*>(image.info.guest_address);
const u64 hash = XXH3_64bits(addr + mip_offset, mip_size); const u64 hash = XXH3_64bits(addr + mip.offset, mip.size);
if (image.mip_hashes[m] == hash) { if (image.mip_hashes[m] == hash) {
continue; continue;
} }
image.mip_hashes[m] = hash; image.mip_hashes[m] = hash;
} }
const u32 extent_width = mip_pitch ? std::min(mip_pitch, width) : width; auto mip_pitch = static_cast<u32>(mip.pitch);
const u32 extent_height = mip_height ? std::min(mip_height, height) : height; auto mip_height = static_cast<u32>(mip.height);
const u32 height_aligned =
mip_height && image.info.IsTiled() ? std::max(mip_height, 8U) : mip_height; auto image_extent_width = mip_pitch ? std::min(mip_pitch, width) : width;
auto image_extent_height = mip_height ? std::min(mip_height, height) : height;
image_copy.push_back({ image_copy.push_back({
.bufferOffset = mip_offset, .bufferOffset = mip.offset,
.bufferRowLength = mip_pitch, .bufferRowLength = mip_pitch,
.bufferImageHeight = height_aligned, .bufferImageHeight = mip_height,
.imageSubresource{ .imageSubresource{
.aspectMask = image.aspect_mask & ~vk::ImageAspectFlagBits::eStencil, .aspectMask = image.aspect_mask & ~vk::ImageAspectFlagBits::eStencil,
.mipLevel = m, .mipLevel = m,
@ -633,7 +634,7 @@ void TextureCache::RefreshImage(Image& image, Vulkan::Scheduler* custom_schedule
.layerCount = num_layers, .layerCount = num_layers,
}, },
.imageOffset = {0, 0, 0}, .imageOffset = {0, 0, 0},
.imageExtent = {extent_width, extent_height, depth}, .imageExtent = {image_extent_width, image_extent_height, depth},
}); });
} }