Merge branch 'main' into mip-height

This commit is contained in:
georgemoralis 2025-07-18 13:14:31 +03:00 committed by GitHub
commit 354cdfffe3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
41 changed files with 920 additions and 328 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).
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.
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.
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 (GIT_REMOTE_RESULT OR GIT_REMOTE_NAME STREQUAL "")
message("check default push")
message(STATUS "check default push")
execute_process(
COMMAND git config --get remote.pushDefault
OUTPUT_VARIABLE GIT_REMOTE_NAME
@ -134,30 +134,30 @@ if (GIT_REMOTE_RESULT OR GIT_REMOTE_NAME STREQUAL "")
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE
)
message("got remote: ${GIT_REMOTE_NAME}")
message(STATUS "got remote: ${GIT_REMOTE_NAME}")
endif()
# If running in GitHub Actions and the above fails
if (GIT_REMOTE_RESULT OR GIT_REMOTE_NAME STREQUAL "")
message("check github")
message(STATUS "check github")
set(GIT_REMOTE_NAME "origin")
# Retrieve environment variables
if (DEFINED ENV{GITHUB_HEAD_REF} AND NOT "$ENV{GITHUB_HEAD_REF}" STREQUAL "")
message("github head ref: $ENV{GITHUB_HEAD_REF}")
message(STATUS "github head ref: $ENV{GITHUB_HEAD_REF}")
set(GITHUB_HEAD_REF "$ENV{GITHUB_HEAD_REF}")
else()
set(GITHUB_HEAD_REF "")
endif()
if (DEFINED ENV{GITHUB_REF} AND NOT "$ENV{GITHUB_REF}" STREQUAL "")
message("github ref: $ENV{GITHUB_REF}")
message(STATUS "github ref: $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}")
if (MATCHED_REF)
set(PR_NUMBER "${CMAKE_MATCH_1}")
set(GITHUB_BRANCH "")
message("PR number: ${PR_NUMBER}")
message(STATUS "PR number: ${PR_NUMBER}")
else()
set(PR_NUMBER "")
endif()
@ -179,7 +179,7 @@ if (GIT_REMOTE_RESULT OR GIT_REMOTE_NAME STREQUAL "")
elseif ("${PR_NUMBER}" STREQUAL "" AND NOT "${GITHUB_REF}" STREQUAL "")
set(GIT_BRANCH "${GITHUB_REF}")
elseif("${GIT_BRANCH}" STREQUAL "")
message("couldn't find branch")
message(STATUS "couldn't find branch")
set(GIT_BRANCH "detached-head")
endif()
else()
@ -188,13 +188,13 @@ else()
if (INDEX GREATER -1)
string(SUBSTRING "${GIT_REMOTE_NAME}" 0 "${INDEX}" GIT_REMOTE_NAME)
elseif("${GIT_REMOTE_NAME}" STREQUAL "")
message("reset to origin")
message(STATUS "reset to origin")
set(GIT_REMOTE_NAME "origin")
endif()
endif()
# Get remote link
message("getting remote link")
message(STATUS "getting remote link")
execute_process(
COMMAND git config --get remote.${GIT_REMOTE_NAME}.url
OUTPUT_VARIABLE GIT_REMOTE_URL
@ -212,7 +212,12 @@ set(APP_VERSION "${EMULATOR_VERSION_MAJOR}.${EMULATOR_VERSION_MINOR}.${EMULATOR_
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)
message("end git things, remote: ${GIT_REMOTE_NAME}, branch: ${GIT_BRANCH}")
message("-- end git things, remote: ${GIT_REMOTE_NAME}, branch: ${GIT_BRANCH}, link: ${GIT_REMOTE_URL}")
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)
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++.
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-emu/shadps4-game-compatibility).\
To verify that a game works, you can look at [**shadPS4 Game Compatibility**](https://github.com/shadps4-compatibility/shadps4-game-compatibility).\
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/).\
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
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-emu/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-compatibility/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.
- ⚠ **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,6 +32,7 @@ std::filesystem::path find_fs_path_or(const basic_value<TC>& v, const K& ky,
namespace Config {
// General
static int volumeSlider = 100;
static bool isNeo = false;
static bool isDevKit = false;
static bool isPSNSignedIn = false;
@ -108,6 +109,9 @@ static std::string trophyKey = "";
// Expected number of items in the config file
static constexpr u64 total_entries = 54;
int getVolumeSlider() {
return volumeSlider;
}
bool allowHDR() {
return isHDRAllowed;
}
@ -157,6 +161,10 @@ std::filesystem::path GetSaveDataPath() {
return save_data_path;
}
void setVolumeSlider(int volumeValue) {
volumeSlider = volumeValue;
}
void setLoadGameSizeEnabled(bool enable) {
load_game_size = enable;
}
@ -611,6 +619,7 @@ void load(const std::filesystem::path& path) {
if (data.contains("General")) {
const toml::value& general = data.at("General");
volumeSlider = toml::find_or<int>(general, "volumeSlider", volumeSlider);
isNeo = toml::find_or<bool>(general, "isPS4Pro", isNeo);
isDevKit = toml::find_or<bool>(general, "isDevKit", isDevKit);
isPSNSignedIn = toml::find_or<bool>(general, "isPSNSignedIn", isPSNSignedIn);
@ -806,6 +815,7 @@ void save(const std::filesystem::path& path) {
fmt::print("Saving new configuration file {}\n", fmt::UTF(path.u8string()));
}
data["General"]["volumeSlider"] = volumeSlider;
data["General"]["isPS4Pro"] = isNeo;
data["General"]["isDevKit"] = isDevKit;
data["General"]["isPSNSignedIn"] = isPSNSignedIn;
@ -901,6 +911,7 @@ void save(const std::filesystem::path& path) {
void setDefaultValues() {
// General
volumeSlider = 100;
isNeo = false;
isDevKit = false;
isPSNSignedIn = false;

View File

@ -19,6 +19,8 @@ enum HideCursorState : int { Never, Idle, Always };
void load(const std::filesystem::path& path);
void save(const std::filesystem::path& path);
int getVolumeSlider();
void setVolumeSlider(int volumeValue);
std::string getTrophyKey();
void setTrophyKey(std::string key);
bool getIsFullscreen();

View File

@ -523,9 +523,24 @@ s32 PS4_SYSV_ABI sceAudioOutSetVolume(s32 handle, s32 flag, s32* vol) {
}
port.impl->SetVolume(port.volume);
}
AdjustVol();
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() {
LOG_ERROR(Lib_AudioOut, "(STUBBED) called");
return ORBIS_OK;

View File

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

View File

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

View File

@ -65,7 +65,7 @@ public:
return Error::OK;
}
std::unique_lock lock{g_ime_state.queue_mutex};
std::unique_lock<std::mutex> lock{g_ime_state.queue_mutex};
while (!g_ime_state.event_queue.empty()) {
OrbisImeEvent event = g_ime_state.event_queue.front();
@ -144,17 +144,17 @@ int PS4_SYSV_ABI sceImeCheckUpdateTextInfo() {
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceImeClose() {
LOG_INFO(Lib_Ime, "(STUBBED) called");
Error PS4_SYSV_ABI sceImeClose() {
LOG_INFO(Lib_Ime, "called");
if (!g_ime_handler) {
return ORBIS_IME_ERROR_NOT_OPENED;
return Error::NOT_OPENED;
}
g_ime_handler.release();
g_ime_ui = ImeUi();
g_ime_state = ImeState();
return ORBIS_OK;
return Error::OK;
}
int PS4_SYSV_ABI sceImeConfigGet() {
@ -223,32 +223,68 @@ int PS4_SYSV_ABI sceImeGetPanelPositionAndForm() {
}
Error PS4_SYSV_ABI sceImeGetPanelSize(const OrbisImeParam* param, u32* width, u32* height) {
LOG_INFO(Lib_Ime, "called");
LOG_INFO(Lib_Ime, "sceImeGetPanelSize called");
if (!width || !height) {
if (!param) {
LOG_ERROR(Lib_Ime, "sceImeGetPanelSize: param is NULL");
return Error::INVALID_ADDRESS;
}
if (!width) {
LOG_ERROR(Lib_Ime, "sceImeGetPanelSize: width pointer is NULL");
return Error::INVALID_ADDRESS;
}
if (!height) {
LOG_ERROR(Lib_Ime, "sceImeGetPanelSize: height pointer is NULL");
return Error::INVALID_ADDRESS;
}
if (static_cast<u32>(param->option) & ~0x7BFF) { // Basic check for invalid options
LOG_ERROR(Lib_Ime, "sceImeGetPanelSize: Invalid option 0x{:X}",
static_cast<u32>(param->option));
return Error::INVALID_OPTION;
}
switch (param->type) {
case OrbisImeType::Default:
*width = 500; // dummy value
*height = 100; // dummy value
LOG_INFO(Lib_Ime, "sceImeGetPanelSize: IME type Default ({})",
static_cast<u32>(param->type));
break;
case OrbisImeType::BasicLatin:
*width = 500; // dummy value
*height = 100; // dummy value
LOG_INFO(Lib_Ime, "sceImeGetPanelSize: IME type BasicLatin ({})",
static_cast<u32>(param->type));
break;
case OrbisImeType::Url:
*width = 500; // dummy value
*height = 100; // dummy value
LOG_INFO(Lib_Ime, "sceImeGetPanelSize: IME type Url ({})", static_cast<u32>(param->type));
break;
case OrbisImeType::Mail:
// We set our custom sizes, commented sizes are the original ones
*width = 500; // 793
*height = 100; // 408
LOG_INFO(Lib_Ime, "sceImeGetPanelSize: IME type Mail ({})", static_cast<u32>(param->type));
break;
case OrbisImeType::Number:
*width = 370;
*height = 402;
LOG_INFO(Lib_Ime, "sceImeGetPanelSize: IME type Number ({})",
static_cast<u32>(param->type));
break;
default:
LOG_ERROR(Lib_Ime, "sceImeGetPanelSize: Invalid IME type ({})",
static_cast<u32>(param->type));
return Error::INVALID_TYPE;
}
return Error::OK;
}
Error PS4_SYSV_ABI sceImeKeyboardClose(s32 userId) {
LOG_INFO(Lib_Ime, "(STUBBED) called");
Error PS4_SYSV_ABI sceImeKeyboardClose(Libraries::UserService::OrbisUserServiceUserId userId) {
LOG_INFO(Lib_Ime, "called");
if (!g_keyboard_handler) {
return Error::NOT_OPENED;
@ -268,9 +304,12 @@ int PS4_SYSV_ABI sceImeKeyboardGetResourceId() {
return ORBIS_OK;
}
Error PS4_SYSV_ABI sceImeKeyboardOpen(s32 userId, const OrbisImeKeyboardParam* param) {
Error PS4_SYSV_ABI sceImeKeyboardOpen(Libraries::UserService::OrbisUserServiceUserId userId,
const OrbisImeKeyboardParam* param) {
LOG_INFO(Lib_Ime, "called");
LOG_INFO(Lib_Ime, "kValidImeDialogExtOptionMask=0x{:X}", kValidImeDialogExtOptionMask);
if (!param) {
return Error::INVALID_ADDRESS;
}
@ -308,13 +347,169 @@ Error PS4_SYSV_ABI sceImeOpen(const OrbisImeParam* param, const OrbisImeParamExt
LOG_INFO(Lib_Ime, "called");
if (!param) {
LOG_ERROR(Lib_Ime, "sceImeOpen: param is null");
return Error::INVALID_ADDRESS;
} else {
// LOG_DEBUG values for debugging purposes
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: supported_languages={:064b}",
static_cast<u64>(param->supported_languages));
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: filter={:p}", reinterpret_cast<void*>(param->filter));
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: inputTextBuffer={:p}",
static_cast<const void*>(param->inputTextBuffer));
LOG_DEBUG(Lib_Ime, "param: posx={}", param->posx);
LOG_DEBUG(Lib_Ime, "param: posy={}", param->posy);
LOG_DEBUG(Lib_Ime, "param: horizontal_alignment={}",
static_cast<u32>(param->horizontal_alignment));
LOG_DEBUG(Lib_Ime, "param: vertical_alignment={}",
static_cast<u32>(param->vertical_alignment));
LOG_DEBUG(Lib_Ime, "param: work={:p}", param->work);
LOG_DEBUG(Lib_Ime, "param: arg={:p}", param->arg);
LOG_DEBUG(Lib_Ime, "param: handler={:p}", reinterpret_cast<void*>(param->handler));
}
if (!extended) {
LOG_INFO(Lib_Ime, "sceImeOpen: extended is null");
} else {
// LOG_DEBUG values for debugging purposes
LOG_DEBUG(Lib_Ime, "extended: option={:032b}", static_cast<u32>(extended->option));
LOG_DEBUG(Lib_Ime, "extended: color_base={{{},{},{},{}}}", extended->color_base.r,
extended->color_base.g, extended->color_base.b, extended->color_base.a);
LOG_DEBUG(Lib_Ime, "extended: color_line={{{},{},{},{}}}", extended->color_line.r,
extended->color_line.g, extended->color_line.b, extended->color_line.a);
LOG_DEBUG(Lib_Ime, "extended: color_text_field={{{},{},{},{}}}",
extended->color_text_field.r, extended->color_text_field.g,
extended->color_text_field.b, extended->color_text_field.a);
LOG_DEBUG(Lib_Ime, "extended: color_preedit={{{},{},{},{}}}", extended->color_preedit.r,
extended->color_preedit.g, extended->color_preedit.b, extended->color_preedit.a);
LOG_DEBUG(Lib_Ime, "extended: color_button_default={{{},{},{},{}}}",
extended->color_button_default.r, extended->color_button_default.g,
extended->color_button_default.b, extended->color_button_default.a);
LOG_DEBUG(Lib_Ime, "extended: color_button_function={{{},{},{},{}}}",
extended->color_button_function.r, extended->color_button_function.g,
extended->color_button_function.b, extended->color_button_function.a);
LOG_DEBUG(Lib_Ime, "extended: color_button_symbol={{{},{},{},{}}}",
extended->color_button_symbol.r, extended->color_button_symbol.g,
extended->color_button_symbol.b, extended->color_button_symbol.a);
LOG_DEBUG(Lib_Ime, "extended: color_text={{{},{},{},{}}}", extended->color_text.r,
extended->color_text.g, extended->color_text.b, extended->color_text.a);
LOG_DEBUG(Lib_Ime, "extended: color_special={{{},{},{},{}}}", extended->color_special.r,
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: additional_dictionary_path={:p}",
static_cast<const void*>(extended->additional_dictionary_path));
LOG_DEBUG(Lib_Ime, "extended: ext_keyboard_filter={:p}",
reinterpret_cast<void*>(extended->ext_keyboard_filter));
LOG_DEBUG(Lib_Ime, "extended: disable_device={:032b}",
static_cast<u32>(extended->disable_device));
LOG_DEBUG(Lib_Ime, "extended: ext_keyboard_mode={}", extended->ext_keyboard_mode);
}
if (param->user_id < 1 || param->user_id > 4) {
LOG_ERROR(Lib_Ime, "sceImeOpen: Invalid user_id ({})", static_cast<u32>(param->user_id));
return Error::INVALID_USER_ID;
}
if (!magic_enum::enum_contains(param->type)) {
LOG_ERROR(Lib_Ime, "sceImeOpen: Invalid type ({})", static_cast<u32>(param->type));
return Error::INVALID_TYPE;
}
if (static_cast<u64>(param->supported_languages) & ~kValidOrbisImeLanguageMask) {
LOG_ERROR(Lib_Ime, "sceImeOpen: supported_languages has invalid bits (0x{:016X})",
static_cast<u64>(param->supported_languages));
return Error::INVALID_SUPPORTED_LANGUAGES;
}
if (!magic_enum::enum_contains(param->enter_label)) {
LOG_ERROR(Lib_Ime, "sceImeOpen: Invalid enter_label ({})",
static_cast<u32>(param->enter_label));
return Error::INVALID_ENTER_LABEL;
}
if (!magic_enum::enum_contains(param->input_method)) {
LOG_ERROR(Lib_Ime, "sceImeOpen: Invalid input_method ({})",
static_cast<u32>(param->input_method));
return Error::INVALID_INPUT_METHOD;
}
if (static_cast<u32>(param->option) & ~kValidImeOptionMask) {
LOG_ERROR(Lib_Ime, "sceImeOpen: option has invalid bits set (0x{:X}), mask=(0x{:X})",
static_cast<u32>(param->option), kValidImeOptionMask);
return Error::INVALID_OPTION;
}
if (param->maxTextLength == 0 || param->maxTextLength > ORBIS_IME_DIALOG_MAX_TEXT_LENGTH) {
LOG_ERROR(Lib_Ime, "sceImeOpen: maxTextLength invalid ({})", param->maxTextLength);
return Error::INVALID_MAX_TEXT_LENGTH;
}
if (!param->inputTextBuffer) {
LOG_ERROR(Lib_Ime, "sceImeOpen: inputTextBuffer is NULL");
return Error::INVALID_INPUT_TEXT_BUFFER;
}
bool useHighRes = True(param->option & OrbisImeOption::USE_OVER_2K_COORDINATES);
const float maxWidth = useHighRes ? 3840.0f : 1920.0f;
const float maxHeight = useHighRes ? 2160.0f : 1080.0f;
if (param->posx < 0.0f || param->posx >= maxWidth) {
LOG_ERROR(Lib_Ime, "sceImeOpen: posx out of range (%.2f), max allowed %.0f", param->posx,
maxWidth);
return Error::INVALID_POSX;
}
if (param->posy < 0.0f || param->posy >= maxHeight) {
LOG_ERROR(Lib_Ime, "sceImeOpen: posy out of range (%.2f), max allowed %.0f", param->posy,
maxHeight);
return Error::INVALID_POSY;
}
if (!magic_enum::enum_contains(param->horizontal_alignment)) {
LOG_ERROR(Lib_Ime, "sceImeOpen: Invalid horizontal_alignment ({})",
static_cast<u32>(param->horizontal_alignment));
return Error::INVALID_HORIZONTALIGNMENT;
}
if (!magic_enum::enum_contains(param->vertical_alignment)) {
LOG_ERROR(Lib_Ime, "sceImeOpen: Invalid vertical_alignment ({})",
static_cast<u32>(param->vertical_alignment));
return Error::INVALID_VERTICALALIGNMENT;
}
if (extended) {
u32 ext_option_value = static_cast<u32>(extended->option);
if (ext_option_value & ~kValidImeExtOptionMask) {
LOG_ERROR(Lib_Ime, "sceImeOpen: extended->option has invalid bits set (0x{:X})",
ext_option_value);
return Error::INVALID_EXTENDED;
}
}
if (!param->work) {
LOG_ERROR(Lib_Ime, "sceImeOpen: work buffer is NULL");
return Error::INVALID_WORK;
}
for (unsigned i = 0; i < sizeof(param->reserved); ++i) {
if (param->reserved[i] != 0) {
LOG_ERROR(Lib_Ime, "sceImeOpen: reserved field must be zeroed");
return Error::INVALID_RESERVED;
}
}
// Todo: validate arg and handler
if (g_ime_handler) {
LOG_ERROR(Lib_Ime, "sceImeOpen: Error BUSY");
return Error::BUSY;
}
g_ime_handler = std::make_unique<ImeHandler>(param);
LOG_INFO(Lib_Ime, "sceImeOpen: OK");
return Error::OK;
}
@ -324,7 +519,7 @@ int PS4_SYSV_ABI sceImeOpenInternal() {
}
void PS4_SYSV_ABI sceImeParamInit(OrbisImeParam* param) {
LOG_INFO(Lib_Ime, "called");
LOG_INFO(Lib_Ime, "sceImeParamInit called");
if (!param) {
return;

View File

@ -18,7 +18,7 @@ int PS4_SYSV_ABI InitializeImeModule();
int PS4_SYSV_ABI sceImeCheckFilterText();
int PS4_SYSV_ABI sceImeCheckRemoteEventParam();
int PS4_SYSV_ABI sceImeCheckUpdateTextInfo();
int PS4_SYSV_ABI sceImeClose();
Error PS4_SYSV_ABI sceImeClose();
int PS4_SYSV_ABI sceImeConfigGet();
int PS4_SYSV_ABI sceImeConfigSet();
int PS4_SYSV_ABI sceImeConfirmCandidate();
@ -33,10 +33,11 @@ int PS4_SYSV_ABI sceImeFilterText();
int PS4_SYSV_ABI sceImeForTestFunction();
int PS4_SYSV_ABI sceImeGetPanelPositionAndForm();
Error PS4_SYSV_ABI sceImeGetPanelSize(const OrbisImeParam* param, u32* width, u32* height);
Error PS4_SYSV_ABI sceImeKeyboardClose(s32 userId);
Error PS4_SYSV_ABI sceImeKeyboardClose(Libraries::UserService::OrbisUserServiceUserId userId);
int PS4_SYSV_ABI sceImeKeyboardGetInfo();
int PS4_SYSV_ABI sceImeKeyboardGetResourceId();
Error PS4_SYSV_ABI sceImeKeyboardOpen(s32 userId, const OrbisImeKeyboardParam* param);
Error PS4_SYSV_ABI sceImeKeyboardOpen(Libraries::UserService::OrbisUserServiceUserId userId,
const OrbisImeKeyboardParam* param);
int PS4_SYSV_ABI sceImeKeyboardOpenInternal();
int PS4_SYSV_ABI sceImeKeyboardSetMode();
int PS4_SYSV_ABI sceImeKeyboardUpdate();

View File

@ -3,6 +3,8 @@
#pragma once
#include <core/libraries/system/userservice.h>
#include <magic_enum/magic_enum.hpp>
#include "common/enum.h"
#include "common/types.h"
#include "core/libraries/rtc/rtc.h"
@ -10,8 +12,28 @@
constexpr u32 ORBIS_IME_MAX_TEXT_LENGTH = 2048;
constexpr u32 ORBIS_IME_DIALOG_MAX_TEXT_LENGTH = 2048;
template <typename E>
const std::underlying_type_t<E> generate_full_mask() {
static_assert(std::is_enum_v<E>, "E must be an enum type.");
static_assert(magic_enum::customize::enum_range<E>::is_flags,
"E must be marked as is_flags = true.");
using U = std::underlying_type_t<E>;
const auto values = magic_enum::enum_values<E>();
U mask = 0;
// Use index-based loop for better constexpr compatibility
for (std::size_t i = 0; i < values.size(); ++i) {
mask |= static_cast<U>(values[i]);
}
return mask;
}
enum class Error : u32 {
OK = 0x0,
// ImeDialog library
BUSY = 0x80bc0001,
NOT_OPENED = 0x80bc0002,
NO_MEMORY = 0x80bc0003,
@ -46,6 +68,8 @@ enum class Error : u32 {
INVALID_RESERVED = 0x80bc0032,
INVALID_TIMING = 0x80bc0033,
INTERNAL = 0x80bc00ff,
// Ime library
DIALOG_INVALID_TITLE = 0x80bc0101,
DIALOG_NOT_RUNNING = 0x80bc0105,
DIALOG_NOT_FINISHED = 0x80bc0106,
@ -67,9 +91,44 @@ enum class OrbisImeOption : u32 {
DISABLE_POSITION_ADJUSTMENT = 2048,
EXPANDED_PREEDIT_BUFFER = 4096,
USE_JAPANESE_EISUU_KEY_AS_CAPSLOCK = 8192,
USE_2K_COORDINATES = 16384,
USE_OVER_2K_COORDINATES = 16384,
};
DECLARE_ENUM_FLAG_OPERATORS(OrbisImeOption);
template <>
struct magic_enum::customize::enum_range<OrbisImeOption> {
static constexpr bool is_flags = true;
};
const u32 kValidImeOptionMask = generate_full_mask<OrbisImeOption>();
enum class OrbisImeExtOption : u32 {
DEFAULT = 0x00000000,
SET_PRIORITY = 0x00000002,
PRIORITY_FULL_WIDTH = 0x00000008,
PRIORITY_FIXED_PANEL = 0x00000010,
DISABLE_POINTER = 0x00000040,
ENABLE_ADDITIONAL_DICTIONARY = 0x00000080,
DISABLE_STARTUP_SE = 0x00000100,
DISABLE_LIST_FOR_EXT_KEYBOARD = 0x00000200,
HIDE_KEYPANEL_IF_EXT_KEYBOARD = 0x00000400,
INIT_EXT_KEYBOARD_MODE = 0x00000800,
ENABLE_ACCESSIBILITY = 0x00001000, // ImeDialog unly
ADDITIONAL_DICTIONARY_PRIORITY_MODE = 0x00004000, // ImeDialog only
};
DECLARE_ENUM_FLAG_OPERATORS(OrbisImeExtOption);
constexpr u32 kValidImeExtOptionMask = static_cast<u32>(
OrbisImeExtOption::SET_PRIORITY | OrbisImeExtOption::PRIORITY_FULL_WIDTH |
OrbisImeExtOption::PRIORITY_FIXED_PANEL | OrbisImeExtOption::DISABLE_POINTER |
OrbisImeExtOption::ENABLE_ADDITIONAL_DICTIONARY | OrbisImeExtOption::DISABLE_STARTUP_SE |
OrbisImeExtOption::DISABLE_LIST_FOR_EXT_KEYBOARD |
OrbisImeExtOption::HIDE_KEYPANEL_IF_EXT_KEYBOARD | OrbisImeExtOption::INIT_EXT_KEYBOARD_MODE);
template <>
struct magic_enum::customize::enum_range<OrbisImeExtOption> {
static constexpr bool is_flags = true;
};
const u32 kValidImeDialogExtOptionMask = generate_full_mask<OrbisImeExtOption>();
enum class OrbisImeLanguage : u64 {
DANISH = 0x0000000000000001,
@ -105,6 +164,112 @@ enum class OrbisImeLanguage : u64 {
};
DECLARE_ENUM_FLAG_OPERATORS(OrbisImeLanguage);
template <>
struct magic_enum::customize::enum_range<OrbisImeLanguage> {
static constexpr bool is_flags = true;
};
const u64 kValidOrbisImeLanguageMask = generate_full_mask<OrbisImeLanguage>();
enum class OrbisImeDisableDevice : u32 {
DEFAULT = 0x00000000,
CONTROLLER = 0x00000001,
EXT_KEYBOARD = 0x00000002,
REMOTE_OSK = 0x00000004,
};
DECLARE_ENUM_FLAG_OPERATORS(OrbisImeDisableDevice);
template <>
struct magic_enum::customize::enum_range<OrbisImeDisableDevice> {
static constexpr bool is_flags = true;
};
const u32 kValidOrbisImeDisableDeviceMask = generate_full_mask<OrbisImeDisableDevice>();
enum class OrbisImeInputMethodState : u32 {
PREEDIT = 0x01000000,
SELECTED = 0x02000000,
NATIVE = 0x04000000,
NATIVE2 = 0x08000000,
FULL_WIDTH = 0x10000000,
};
DECLARE_ENUM_FLAG_OPERATORS(OrbisImeInputMethodState);
template <>
struct magic_enum::customize::enum_range<OrbisImeInputMethodState> {
static constexpr bool is_flags = true;
};
const u32 kValidOrbisImeInputMethodStateMask = generate_full_mask<OrbisImeInputMethodState>();
enum class OrbisImeInitExtKeyboardMode : u32 {
ISABLE_ARABIC_INDIC_NUMERALS = 0x00000001,
ENABLE_FORMAT_CHARACTERS = 0x00000002,
INPUT_METHOD_STATE_NATIVE = 0x04000000,
INPUT_METHOD_STATE_NATIVE2 = 0x08000000,
INPUT_METHOD_STATE_FULL_WIDTH = 0x10000000,
};
DECLARE_ENUM_FLAG_OPERATORS(OrbisImeInitExtKeyboardMode);
template <>
struct magic_enum::customize::enum_range<OrbisImeInitExtKeyboardMode> {
static constexpr bool is_flags = true;
};
const u32 kValidOrbisImeInitExtKeyboardModeMask = generate_full_mask<OrbisImeInitExtKeyboardMode>();
enum class OrbisImeKeycodeState : u32 {
KEYCODE_VALID = 0x00000001,
CHARACTER_VALID = 0x00000002,
WITH_IME = 0x00000004,
FROM_OSK = 0x00000008,
FROM_OSK_SHORTCUT = 0x00000010,
FROM_IME_OPERATION = 0x00000020,
REPLACE_CHARACTER = 0x00000040,
CONTINUOUS_EVENT = 0x00000080,
MODIFIER_L_CTRL = 0x00000100,
MODIFIER_L_SHIFT = 0x00000200,
MODIFIER_L_ALT = 0x00000400,
MODIFIER_L_GUI = 0x00000800,
MODIFIER_R_CTRL = 0x00001000,
MODIFIER_R_SHIFT = 0x00002000,
MODIFIER_R_ALT = 0x00004000,
MODIFIER_R_GUI = 0x00008000,
LED_NUM_LOCK = 0x00010000,
LED_CAPS_LOCK = 0x00020000,
LED_SCROLL_LOCK = 0x00040000,
RESERVED1 = 0x00080000,
RESERVED2 = 0x00100000,
FROM_IME_INPUT = 0x00200000,
};
DECLARE_ENUM_FLAG_OPERATORS(OrbisImeKeycodeState);
template <>
struct magic_enum::customize::enum_range<OrbisImeKeycodeState> {
static constexpr bool is_flags = true;
};
const u32 kValidOrbisImeKeycodeStateMask = generate_full_mask<OrbisImeKeycodeState>();
enum class OrbisImeKeyboardOption : u32 {
Default = 0,
Repeat = 1,
RepeatEachKey = 2,
AddOsk = 4,
EffectiveWithIme = 8,
DisableResume = 16,
DisableCapslockWithoutShift = 32,
};
DECLARE_ENUM_FLAG_OPERATORS(OrbisImeKeyboardOption)
template <>
struct magic_enum::customize::enum_range<OrbisImeKeyboardOption> {
static constexpr bool is_flags = true;
};
const u32 kValidOrbisImeKeyboardOptionMask = generate_full_mask<OrbisImeKeyboardOption>();
enum class OrbisImeKeyboardMode : u32 {
Auto = 0,
Manual = 1,
Alphabet = 0,
Native = 2,
Part = 4,
Katakana = 8,
Hkana = 16,
ArabicIndicNumerals = 32,
DisableFormatCharacters = 64,
};
enum class OrbisImeType : u32 {
Default = 0,
BasicLatin = 1,
@ -260,13 +425,13 @@ struct OrbisImeKeycode {
char16_t character;
u32 status;
OrbisImeKeyboardType type;
s32 user_id; // Todo: switch to OrbisUserServiceUserId
Libraries::UserService::OrbisUserServiceUserId user_id;
u32 resource_id;
Libraries::Rtc::OrbisRtcTick timestamp;
};
struct OrbisImeKeyboardResourceIdArray {
s32 user_id; // Todo: switch to OrbisUserServiceUserId
Libraries::UserService::OrbisUserServiceUserId user_id;
u32 resource_id[5];
};
@ -322,17 +487,6 @@ using OrbisImeTextFilter = PS4_SYSV_ABI int (*)(char16_t* outText, u32* outTextL
using OrbisImeEventHandler = PS4_SYSV_ABI void (*)(void* arg, const OrbisImeEvent* e);
enum class OrbisImeKeyboardOption : u32 {
Default = 0,
Repeat = 1,
RepeatEachKey = 2,
AddOsk = 4,
EffectiveWithIme = 8,
DisableResume = 16,
DisableCapslockWithoutShift = 32,
};
DECLARE_ENUM_FLAG_OPERATORS(OrbisImeKeyboardOption)
struct OrbisImeKeyboardParam {
OrbisImeKeyboardOption option;
s8 reserved1[4];
@ -342,9 +496,9 @@ struct OrbisImeKeyboardParam {
};
struct OrbisImeParam {
s32 user_id; // Todo: switch to OrbisUserServiceUserId
Libraries::UserService::OrbisUserServiceUserId user_id;
OrbisImeType type;
u64 supported_languages; // OrbisImeLanguage flags
OrbisImeLanguage supported_languages;
OrbisImeEnterLabel enter_label;
OrbisImeInputMethod input_method;
OrbisImeTextFilter filter;
@ -369,9 +523,9 @@ struct OrbisImeCaret {
};
struct OrbisImeDialogParam {
s32 user_id;
Libraries::UserService::OrbisUserServiceUserId user_id;
OrbisImeType type;
u64 supported_languages; // OrbisImeLanguage flags
OrbisImeLanguage supported_languages;
OrbisImeEnterLabel enter_label;
OrbisImeInputMethod input_method;
OrbisImeTextFilter filter;
@ -388,7 +542,7 @@ struct OrbisImeDialogParam {
};
struct OrbisImeParamExtended {
u32 option; // OrbisImeExtOption flags
OrbisImeExtOption option;
OrbisImeColor color_base;
OrbisImeColor color_line;
OrbisImeColor color_text_field;
@ -401,7 +555,7 @@ struct OrbisImeParamExtended {
OrbisImePanelPriority priority;
char* additional_dictionary_path;
OrbisImeExtKeyboardFilter ext_keyboard_filter;
u32 disable_device;
OrbisImeDisableDevice disable_device;
u32 ext_keyboard_mode;
s8 reserved[60];
};

View File

@ -149,20 +149,47 @@ OrbisImeDialogStatus PS4_SYSV_ABI sceImeDialogGetStatus() {
}
Error PS4_SYSV_ABI sceImeDialogInit(OrbisImeDialogParam* param, OrbisImeParamExtended* extended) {
LOG_INFO(Lib_ImeDialog, ">> sceImeDialogInit: entering, param={}, extended={}",
LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: entering, param={}, extended={}",
static_cast<void*>(param), static_cast<void*>(extended));
if (g_ime_dlg_status != OrbisImeDialogStatus::None) {
LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: busy (status=%u)", (u32)g_ime_dlg_status);
return Error::BUSY;
}
if (param == nullptr) {
LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: param is null");
return Error::INVALID_ADDRESS;
} else {
LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.user_id = {}",
static_cast<u32>(param->user_id));
LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.type = {}", static_cast<u32>(param->type));
LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.supported_languages = 0x{:X}",
static_cast<u64>(param->supported_languages));
LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.enter_label = {}",
static_cast<u32>(param->enter_label));
LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.input_method = {}",
static_cast<u32>(param->input_method));
LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.filter = {}", (void*)param->filter);
LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.option = 0x{:X}",
static_cast<u32>(param->option));
LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.max_text_length = {}",
param->max_text_length);
LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.input_text_buffer = {}",
(void*)param->input_text_buffer);
LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.posx = {}", param->posx);
LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.posy = {}", param->posy);
LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.horizontal_alignment = {}",
static_cast<u32>(param->horizontal_alignment));
LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.vertical_alignment = {}",
static_cast<u32>(param->vertical_alignment));
LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.placeholder = {}",
param->placeholder ? "<non-null>" : "NULL");
LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: param.title = {}",
param->title ? "<non-null>" : "NULL");
}
if (g_ime_dlg_status != OrbisImeDialogStatus::None) {
LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: busy (status={})", (u32)g_ime_dlg_status);
return Error::BUSY;
}
if (!magic_enum::enum_contains(param->type)) {
LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: invalid param->type=%u", (u32)param->type);
LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: invalid param->type={}", (u32)param->type);
return Error::INVALID_ADDRESS;
}
@ -170,14 +197,16 @@ Error PS4_SYSV_ABI sceImeDialogInit(OrbisImeDialogParam* param, OrbisImeParamExt
// TODO: do correct param->supportedLanguages validation
if (param->posx < 0.0f ||
param->posx >= MAX_X_POSITIONS[False(param->option & OrbisImeOption::USE_2K_COORDINATES)]) {
LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: invalid posx=%f", param->posx);
param->posx >=
MAX_X_POSITIONS[False(param->option & OrbisImeOption::USE_OVER_2K_COORDINATES)]) {
LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: invalid posx={}", param->posx);
return Error::INVALID_POSX;
}
if (param->posy < 0.0f ||
param->posy >= MAX_Y_POSITIONS[False(param->option & OrbisImeOption::USE_2K_COORDINATES)]) {
LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: invalid posy=%f", param->posy);
param->posy >=
MAX_Y_POSITIONS[False(param->option & OrbisImeOption::USE_OVER_2K_COORDINATES)]) {
LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: invalid posy={}", param->posy);
return Error::INVALID_POSY;
}
@ -192,7 +221,7 @@ Error PS4_SYSV_ABI sceImeDialogInit(OrbisImeDialogParam* param, OrbisImeParamExt
}
if (!IsValidOption(param->option, param->type)) {
LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: invalid option=0x%X for type=%u",
LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: invalid option=0x{:X}for type={}",
static_cast<u32>(param->option), (u32)param->type);
return Error::INVALID_PARAM;
}
@ -204,25 +233,27 @@ Error PS4_SYSV_ABI sceImeDialogInit(OrbisImeDialogParam* param, OrbisImeParamExt
if (extended) {
if (!magic_enum::enum_contains(extended->priority)) {
LOG_INFO(Lib_ImeDialog, "Invalid extended->priority");
LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: Invalid extended->priority");
return Error::INVALID_EXTENDED;
}
// TODO: do correct extended->option validation
if ((extended->ext_keyboard_mode & 0xe3fffffc) != 0) {
LOG_INFO(Lib_ImeDialog, "Invalid extended->extKeyboardMode");
LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: Invalid extended->extKeyboardMode");
return Error::INVALID_EXTENDED;
}
if (extended->disable_device > 7) {
LOG_INFO(Lib_ImeDialog, "Invalid extended->disableDevice");
if (static_cast<u32>(extended->disable_device) & ~kValidOrbisImeDisableDeviceMask) {
LOG_ERROR(Lib_ImeDialog,
"sceImeDialogInit: disable_device has invalid bits set (0x{:X})",
static_cast<u32>(extended->disable_device));
return Error::INVALID_EXTENDED;
}
}
if (param->max_text_length == 0 || param->max_text_length > ORBIS_IME_MAX_TEXT_LENGTH) {
LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: invalid max_text_length=%u",
LOG_ERROR(Lib_ImeDialog, "sceImeDialogInit: invalid max_text_length={}",
param->max_text_length);
return Error::INVALID_MAX_TEXT_LENGTH;
}
@ -238,7 +269,7 @@ Error PS4_SYSV_ABI sceImeDialogInit(OrbisImeDialogParam* param, OrbisImeParamExt
g_ime_dlg_status = OrbisImeDialogStatus::Running;
g_ime_dlg_ui = ImeDialogUi(&g_ime_dlg_state, &g_ime_dlg_status, &g_ime_dlg_result);
LOG_INFO(Lib_ImeDialog, "<< sceImeDialogInit: successful, status now=Running");
LOG_INFO(Lib_ImeDialog, "sceImeDialogInit: successful, status now=Running");
return Error::OK;
}

View File

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

View File

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

View File

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

View File

@ -37,6 +37,7 @@ 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_playBackgroundMusic = gui_value(game_list, "playBackgroundMusic", true);
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
const gui_value gg_icon_size = gui_value(game_grid, "icon_size", 69);

View File

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

View File

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

View File

@ -59,7 +59,7 @@
</size>
</property>
<property name="currentIndex">
<number>5</number>
<number>0</number>
</property>
<widget class="QScrollArea" name="generalTab">
<property name="widgetResizable">
@ -73,8 +73,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>946</width>
<height>536</height>
<width>944</width>
<height>537</height>
</rect>
</property>
<layout class="QVBoxLayout" name="generalTabVLayout" stretch="0">
@ -86,148 +86,7 @@
<property name="spacing">
<number>6</number>
</property>
<item row="0" column="1">
<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="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="1">
<spacer name="verticalSpacer_4">
<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="0">
<item row="2" column="0">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
@ -240,8 +99,8 @@
</property>
</spacer>
</item>
<item row="1" column="2">
<spacer name="verticalSpacer_5">
<item row="2" column="2">
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
@ -253,7 +112,7 @@
</property>
</spacer>
</item>
<item row="0" column="2">
<item row="0" column="3">
<layout class="QVBoxLayout" name="updaterTabLayoutLeft">
<property name="spacing">
<number>6</number>
@ -427,6 +286,228 @@
</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>
<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>
</item>
</layout>
@ -444,8 +525,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>946</width>
<height>536</height>
<width>944</width>
<height>537</height>
</rect>
</property>
<layout class="QVBoxLayout" name="guiTabVLayout" stretch="0">
@ -700,7 +781,7 @@
<item>
<widget class="QLabel" name="label_Volume">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@ -893,8 +974,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>946</width>
<height>536</height>
<width>944</width>
<height>537</height>
</rect>
</property>
<layout class="QVBoxLayout" name="graphicsTabVLayout" stretch="0,0">
@ -1188,8 +1269,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>946</width>
<height>536</height>
<width>944</width>
<height>537</height>
</rect>
</property>
<layout class="QVBoxLayout" name="userTabVLayout" stretch="0,0,1">
@ -1430,8 +1511,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>946</width>
<height>536</height>
<width>944</width>
<height>537</height>
</rect>
</property>
<layout class="QVBoxLayout" name="inputTabVLayout" stretch="0,0">
@ -1684,8 +1765,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>946</width>
<height>536</height>
<width>944</width>
<height>537</height>
</rect>
</property>
<layout class="QVBoxLayout" name="pathsTabLayout">
@ -1826,8 +1907,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>946</width>
<height>536</height>
<width>944</width>
<height>537</height>
</rect>
</property>
<layout class="QVBoxLayout" name="debugTabVLayout" stretch="0,0">

View File

@ -268,6 +268,7 @@ Id EmitBufferAtomicFMin32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id addre
const auto sign_bit_set =
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(
ctx.F32[1], sign_bit_set,
EmitBitCastF32U32(ctx, EmitBufferAtomicUMax32(ctx, inst, handle, address, u32_value)),
@ -302,6 +303,7 @@ Id EmitBufferAtomicFMax32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id addre
const auto sign_bit_set =
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(
ctx.F32[1], sign_bit_set,
EmitBitCastF32U32(ctx, EmitBufferAtomicUMin32(ctx, inst, handle, address, u32_value)),

View File

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

View File

@ -488,6 +488,8 @@ Id EmitConvertU16U32(EmitContext& ctx, Id value);
Id EmitConvertU32U16(EmitContext& ctx, Id value);
Id EmitConvertU8U32(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 address3, Id address4);

View File

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

View File

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

View File

@ -28,6 +28,15 @@ void Translator::EmitVectorMemory(const GcnInst& inst) {
case Opcode::BUFFER_LOAD_FORMAT_XYZW:
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:
return BUFFER_LOAD(1, false, false, inst);
case Opcode::BUFFER_LOAD_DWORDX2:
@ -56,6 +65,11 @@ void Translator::EmitVectorMemory(const GcnInst& inst) {
case Opcode::TBUFFER_STORE_FORMAT_XYZW:
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:
return BUFFER_STORE(1, false, false, inst);
case Opcode::BUFFER_STORE_DWORDX2:
@ -186,7 +200,7 @@ void Translator::EmitVectorMemory(const GcnInst& inst) {
}
void Translator::BUFFER_LOAD(u32 num_dwords, bool is_inst_typed, bool is_buffer_typed,
const GcnInst& inst) {
const GcnInst& inst, u32 scalar_width, bool is_signed) {
const auto& mubuf = inst.control.mubuf;
const bool is_ring = mubuf.glc && mubuf.slc;
const IR::VectorReg vaddr{inst.src[0].code};
@ -242,7 +256,26 @@ 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)});
}
} else {
const IR::Value value = ir.LoadBufferU32(num_dwords, handle, address, buffer_info);
IR::Value value;
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) {
ir.SetVectorReg(dst_reg, IR::U32{value});
return;
@ -254,7 +287,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,
const GcnInst& inst) {
const GcnInst& inst, u32 scalar_width) {
const auto& mubuf = inst.control.mubuf;
const bool is_ring = mubuf.glc && mubuf.slc;
const IR::VectorReg vaddr{inst.src[0].code};
@ -314,8 +347,23 @@ void Translator::BUFFER_STORE(u32 num_dwords, bool is_inst_typed, bool is_buffer
}
ir.StoreBufferFormat(handle, address, ir.CompositeConstruct(comps), buffer_info);
} else {
const auto value = num_dwords == 1 ? comps[0] : ir.CompositeConstruct(comps);
ir.StoreBufferU32(num_dwords, handle, address, value, buffer_info);
IR::Value 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);
break;
default:
UNREACHABLE();
}
}
}

View File

@ -1979,6 +1979,24 @@ U8U16U32U64 IREmitter::UConvert(size_t result_bitsize, const U8U16U32U64& value)
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) {
switch (result_bitsize) {
case 16:

View File

@ -325,6 +325,7 @@ public:
const Value& 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]] Value ImageAtomicIAdd(const Value& handle, const Value& coords,

View File

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

View File

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

View File

@ -248,6 +248,15 @@ constexpr CompMapping RemapSwizzle(const DataFormat format, const CompMapping sw
result.a = swizzle.r;
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:
return swizzle;
}

View File

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

View File

@ -244,9 +244,24 @@ GraphicsPipeline::GraphicsPipeline(
const auto depth_format =
instance.GetSupportedFormat(LiverpoolToVK::DepthFormat(key.z_format, key.stencil_format),
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 = {
.colorAttachmentCount = key.num_color_attachments,
.pColorAttachmentFormats = key.color_formats.data(),
.pColorAttachmentFormats = color_formats.data(),
.depthAttachmentFormat = key.z_format != Liverpool::DepthBuffer::ZFormat::Invalid
? depth_format
: vk::Format::eUndefined,

View File

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

View File

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

View File

@ -94,6 +94,21 @@ public:
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
bool IsCustomBorderColorSupported() const {
return custom_border_color;

View File

@ -203,6 +203,9 @@ PipelineCache::PipelineCache(const Instance& instance_, Scheduler& scheduler_,
profile = Shader::Profile{
.supported_spirv = SpirvVersion1_6,
.subgroup_size = instance.SubgroupSize(),
.support_int8 = instance.IsShaderInt8Supported(),
.support_int16 = instance.IsShaderInt16Supported(),
.support_int64 = instance.IsShaderInt64Supported(),
.support_float64 = instance.IsShaderFloat64Supported(),
.support_fp32_denorm_preserve = bool(vk12_props.shaderDenormPreserveFloat32),
.support_fp32_denorm_flush = bool(vk12_props.shaderDenormFlushToZeroFloat32),
@ -312,7 +315,6 @@ bool PipelineCache::RefreshGraphicsKey() {
// 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
key.num_color_attachments = 0;
key.color_formats.fill(vk::Format::eUndefined);
key.color_buffers.fill({});
key.blend_controls.fill({});
key.write_masks.fill({});
@ -348,16 +350,8 @@ bool PipelineCache::RefreshGraphicsKey() {
col_buf.GetDataFmt() == AmdGpu::DataFormat::Format8_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{
.data_format = col_buf.GetDataFmt(),
.num_format = col_buf.GetNumberFmt(),
.num_conversion = col_buf.GetNumberConversion(),
.export_format = regs.color_export_format.GetFormat(cb),
@ -476,9 +470,7 @@ bool PipelineCache::RefreshGraphicsKey() {
// 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
// increment the index for the null attachment binding.
key.color_formats[remapped_cb] = vk::Format::eUndefined;
key.color_buffers[remapped_cb] = {};
++remapped_cb;
key.color_buffers[remapped_cb++] = {};
continue;
}

View File

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

View File

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

View File

@ -176,17 +176,6 @@ 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 {
switch (pixel_format) {
case vk::Format::eD16Unorm:

View File

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