mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-07-22 10:04:39 +00:00
Merge branch 'main' into Feature/initial-ps4-ime-keyboard
This commit is contained in:
commit
b4e3bf13de
2
.github/ISSUE_TEMPLATE/game-bug-report.yaml
vendored
2
.github/ISSUE_TEMPLATE/game-bug-report.yaml
vendored
@ -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.
|
||||
|
||||
|
@ -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")
|
||||
|
@ -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)!
|
||||
|
@ -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.**\
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "core/libraries/audio/audioout.h"
|
||||
#include "core/libraries/audio/audioout_backend.h"
|
||||
#include "core/libraries/audio/audioout_error.h"
|
||||
#include "core/libraries/kernel/time.h"
|
||||
#include "core/libraries/libs.h"
|
||||
|
||||
namespace Libraries::AudioOut {
|
||||
@ -168,8 +169,19 @@ int PS4_SYSV_ABI sceAudioOutGetInfoOpenNum() {
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudioOutGetLastOutputTime() {
|
||||
LOG_ERROR(Lib_AudioOut, "(STUBBED) called");
|
||||
int PS4_SYSV_ABI sceAudioOutGetLastOutputTime(s32 handle, u64* output_time) {
|
||||
LOG_DEBUG(Lib_AudioOut, "called, handle: {}, output time: {}", handle, fmt::ptr(output_time));
|
||||
if (!output_time) {
|
||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_POINTER;
|
||||
}
|
||||
if (handle >= ports_out.size()) {
|
||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
||||
}
|
||||
auto& port = ports_out.at(handle - 1);
|
||||
if (!port.IsOpen()) {
|
||||
return ORBIS_AUDIO_OUT_ERROR_NOT_OPENED;
|
||||
}
|
||||
*output_time = port.last_output_time;
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
@ -396,6 +408,7 @@ s32 PS4_SYSV_ABI sceAudioOutOutput(s32 handle, void* ptr) {
|
||||
if (ptr != nullptr && port.IsOpen()) {
|
||||
std::memcpy(port.output_buffer, ptr, port.BufferSize());
|
||||
port.output_ready = true;
|
||||
port.last_output_time = Kernel::sceKernelGetProcessTime();
|
||||
}
|
||||
}
|
||||
port.output_cv.notify_one();
|
||||
@ -523,9 +536,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;
|
||||
|
@ -96,6 +96,7 @@ struct PortOut {
|
||||
AudioFormatInfo format_info;
|
||||
u32 sample_rate;
|
||||
u32 buffer_frames;
|
||||
u64 last_output_time;
|
||||
std::array<s32, 8> volume;
|
||||
|
||||
[[nodiscard]] bool IsOpen() const {
|
||||
@ -127,7 +128,7 @@ int PS4_SYSV_ABI sceAudioOutGetFocusEnablePid();
|
||||
int PS4_SYSV_ABI sceAudioOutGetHandleStatusInfo();
|
||||
int PS4_SYSV_ABI sceAudioOutGetInfo();
|
||||
int PS4_SYSV_ABI sceAudioOutGetInfoOpenNum();
|
||||
int PS4_SYSV_ABI sceAudioOutGetLastOutputTime();
|
||||
int PS4_SYSV_ABI sceAudioOutGetLastOutputTime(s32 handle, u64* output_time);
|
||||
int PS4_SYSV_ABI sceAudioOutGetPortState(s32 handle, OrbisAudioOutPortState* state);
|
||||
int PS4_SYSV_ABI sceAudioOutGetSimulatedBusUsableStatusByBusType();
|
||||
int PS4_SYSV_ABI sceAudioOutGetSimulatedHandleStatusInfo();
|
||||
@ -181,5 +182,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
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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];
|
||||
};
|
||||
|
@ -197,13 +197,15 @@ 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)]) {
|
||||
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)]) {
|
||||
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;
|
||||
}
|
||||
@ -242,7 +244,7 @@ Error PS4_SYSV_ABI sceImeDialogInit(OrbisImeDialogParam* param, OrbisImeParamExt
|
||||
return Error::INVALID_EXTENDED;
|
||||
}
|
||||
|
||||
if (static_cast<u32>(extended->disable_device) & 0x7) {
|
||||
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));
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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">
|
||||
|
@ -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)),
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
@ -14,7 +14,7 @@ CopyShaderData ParseCopyShader(std::span<const u32> code) {
|
||||
constexpr u32 token_mov_vcchi = 0xBEEB03FF;
|
||||
ASSERT_MSG(code[0] == token_mov_vcchi, "First instruction is not s_mov_b32 vcc_hi, #imm");
|
||||
|
||||
std::array<s32, 32> offsets{};
|
||||
std::array<s32, 64> offsets{};
|
||||
offsets.fill(-1);
|
||||
|
||||
std::array<s32, 256> sources{};
|
||||
@ -52,6 +52,8 @@ CopyShaderData ParseCopyShader(std::span<const u32> code) {
|
||||
break;
|
||||
}
|
||||
case Gcn::Opcode::BUFFER_LOAD_DWORD: {
|
||||
ASSERT_MSG(inst.src[1].code < offsets.size(),
|
||||
"offsets array for geometry shaders is too short");
|
||||
offsets[inst.src[1].code] = inst.control.mubuf.offset;
|
||||
if (inst.src[3].field != Gcn::OperandField::ConstZero) {
|
||||
const u32 index = inst.src[3].code;
|
||||
@ -65,7 +67,7 @@ CopyShaderData ParseCopyShader(std::span<const u32> code) {
|
||||
}
|
||||
}
|
||||
|
||||
if (last_attr != IR::Attribute::Position0) {
|
||||
if (!IsPosition(last_attr)) {
|
||||
data.num_attrs = static_cast<u32>(last_attr) - static_cast<u32>(IR::Attribute::Param0) + 1;
|
||||
const auto it = data.attr_map.begin();
|
||||
const u32 comp_stride = std::next(it)->first - it->first;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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,
|
||||
|
@ -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, )
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -699,7 +699,7 @@ struct PM4CmdWaitRegMem {
|
||||
struct PM4CmdWriteData {
|
||||
PM4Type3Header header;
|
||||
union {
|
||||
BitField<8, 11, u32> dst_sel;
|
||||
BitField<8, 4, u32> dst_sel;
|
||||
BitField<16, 1, u32> wr_one_addr;
|
||||
BitField<20, 1, u32> wr_confirm;
|
||||
BitField<30, 1, u32> engine_sel;
|
||||
|
@ -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 depth =
|
||||
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;
|
||||
if (offset + mip_size > max_offset) {
|
||||
break;
|
||||
}
|
||||
copies.push_back({
|
||||
.bufferOffset = offset,
|
||||
.bufferRowLength = static_cast<u32>(mip_pitch),
|
||||
.bufferImageHeight = static_cast<u32>(mip_height),
|
||||
.bufferRowLength = mip_pitch,
|
||||
.bufferImageHeight = mip_height,
|
||||
.imageSubresource{
|
||||
.aspectMask = image.aspect_mask & ~vk::ImageAspectFlagBits::eStencil,
|
||||
.mipLevel = m,
|
||||
|
@ -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),
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -1211,11 +1211,13 @@ void Rasterizer::UpdateDepthStencilState() const {
|
||||
} : front_ops;
|
||||
dynamic_state.SetStencilOps(front_ops, back_ops);
|
||||
|
||||
const bool stencil_clear = regs.depth_render_control.stencil_clear_enable;
|
||||
const auto front = regs.stencil_ref_front;
|
||||
const auto back =
|
||||
regs.depth_control.backface_enable ? regs.stencil_ref_back : regs.stencil_ref_front;
|
||||
dynamic_state.SetStencilReferences(front.stencil_test_val, back.stencil_test_val);
|
||||
dynamic_state.SetStencilWriteMasks(front.stencil_write_mask, back.stencil_write_mask);
|
||||
dynamic_state.SetStencilWriteMasks(!stencil_clear ? front.stencil_write_mask.Value() : 0U,
|
||||
!stencil_clear ? back.stencil_write_mask.Value() : 0U);
|
||||
dynamic_state.SetStencilCompareMasks(front.stencil_mask, back.stencil_mask);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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:
|
||||
|
@ -31,7 +31,6 @@ struct ImageInfo {
|
||||
}
|
||||
|
||||
bool IsBlockCoded() const;
|
||||
bool IsPacked() const;
|
||||
bool IsDepthStencil() const;
|
||||
bool HasStencil() const;
|
||||
|
||||
|
@ -605,28 +605,27 @@ void TextureCache::RefreshImage(Image& image, Vulkan::Scheduler* custom_schedule
|
||||
const u32 height = std::max(image.info.size.height >> m, 1u);
|
||||
const u32 depth =
|
||||
image.info.props.is_volume ? std::max(image.info.size.depth >> m, 1u) : 1u;
|
||||
const auto& mip = image.info.mips_layout[m];
|
||||
const auto [mip_size, mip_pitch, mip_height, mip_offset] = image.info.mips_layout[m];
|
||||
|
||||
// Protect GPU modified resources from accidental CPU reuploads.
|
||||
if (is_gpu_modified && !is_gpu_dirty) {
|
||||
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) {
|
||||
continue;
|
||||
}
|
||||
image.mip_hashes[m] = hash;
|
||||
}
|
||||
|
||||
auto mip_pitch = static_cast<u32>(mip.pitch);
|
||||
auto mip_height = static_cast<u32>(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;
|
||||
const u32 extent_width = mip_pitch ? std::min(mip_pitch, width) : width;
|
||||
const u32 extent_height = mip_height ? std::min(mip_height, height) : height;
|
||||
const u32 height_aligned =
|
||||
mip_height && image.info.IsTiled() ? std::max(mip_height, 8U) : mip_height;
|
||||
|
||||
image_copy.push_back({
|
||||
.bufferOffset = mip.offset,
|
||||
.bufferOffset = mip_offset,
|
||||
.bufferRowLength = mip_pitch,
|
||||
.bufferImageHeight = mip_height,
|
||||
.bufferImageHeight = height_aligned,
|
||||
.imageSubresource{
|
||||
.aspectMask = image.aspect_mask & ~vk::ImageAspectFlagBits::eStencil,
|
||||
.mipLevel = m,
|
||||
@ -634,7 +633,7 @@ void TextureCache::RefreshImage(Image& image, Vulkan::Scheduler* custom_schedule
|
||||
.layerCount = num_layers,
|
||||
},
|
||||
.imageOffset = {0, 0, 0},
|
||||
.imageExtent = {image_extent_width, image_extent_height, depth},
|
||||
.imageExtent = {extent_width, extent_height, depth},
|
||||
});
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user