mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-07-12 04:35:56 +00:00
Merge branch 'main' into http-part2
This commit is contained in:
commit
f094bbdd55
33 changed files with 737 additions and 172 deletions
|
@ -296,6 +296,8 @@ set(AJM_LIB src/core/libraries/ajm/ajm.cpp
|
|||
|
||||
set(AUDIO_LIB src/core/libraries/audio/audioin.cpp
|
||||
src/core/libraries/audio/audioin.h
|
||||
src/core/libraries/voice/voice.cpp
|
||||
src/core/libraries/voice/voice.h
|
||||
src/core/libraries/audio/audioout.cpp
|
||||
src/core/libraries/audio/audioout.h
|
||||
src/core/libraries/audio/audioout_backend.h
|
||||
|
|
|
@ -29,7 +29,7 @@ sudo dnf install clang git cmake libatomic alsa-lib-devel \
|
|||
openssl-devel libevdev-devel libudev-devel libXext-devel \
|
||||
qt6-qtbase-devel qt6-qtbase-private-devel \
|
||||
qt6-qtmultimedia-devel qt6-qtsvg-devel qt6-qttools-devel \
|
||||
vulkan-devel vulkan-validation-layers libpng-devel
|
||||
vulkan-devel vulkan-validation-layers libpng-devel libuuid-devel
|
||||
```
|
||||
|
||||
#### Arch Linux
|
||||
|
|
|
@ -69,7 +69,7 @@ static bool vkGuestMarkers = false;
|
|||
static bool rdocEnable = false;
|
||||
static bool isFpsColor = true;
|
||||
static bool isSeparateLogFilesEnabled = false;
|
||||
static s16 cursorState = HideCursorState::Idle;
|
||||
static int cursorState = HideCursorState::Idle;
|
||||
static int cursorHideTimeout = 5; // 5 seconds (default)
|
||||
static double trophyNotificationDuration = 6.0;
|
||||
static bool useUnifiedInputConfig = true;
|
||||
|
@ -78,6 +78,7 @@ static int controllerCustomColorRGB[3] = {0, 0, 255};
|
|||
static bool compatibilityData = false;
|
||||
static bool checkCompatibilityOnStartup = false;
|
||||
static std::string trophyKey;
|
||||
static bool isPSNSignedIn = false;
|
||||
|
||||
// Gui
|
||||
static bool load_game_size = true;
|
||||
|
@ -730,6 +731,14 @@ void setShowBackgroundImage(bool show) {
|
|||
showBackgroundImage = show;
|
||||
}
|
||||
|
||||
bool getPSNSignedIn() {
|
||||
return isPSNSignedIn;
|
||||
}
|
||||
|
||||
void setPSNSignedIn(bool sign) {
|
||||
isPSNSignedIn = sign;
|
||||
}
|
||||
|
||||
void load(const std::filesystem::path& path) {
|
||||
// If the configuration file does not exist, create it and return
|
||||
std::error_code error;
|
||||
|
@ -754,6 +763,7 @@ void load(const std::filesystem::path& path) {
|
|||
|
||||
isNeo = toml::find_or<bool>(general, "isPS4Pro", false);
|
||||
isDevKit = toml::find_or<bool>(general, "isDevKit", false);
|
||||
isPSNSignedIn = toml::find_or<bool>(general, "isPSNSignedIn", false);
|
||||
playBGM = toml::find_or<bool>(general, "playBGM", false);
|
||||
isTrophyPopupDisabled = toml::find_or<bool>(general, "isTrophyPopupDisabled", false);
|
||||
trophyNotificationDuration =
|
||||
|
@ -953,6 +963,7 @@ void save(const std::filesystem::path& path) {
|
|||
|
||||
data["General"]["isPS4Pro"] = isNeo;
|
||||
data["General"]["isDevKit"] = isDevKit;
|
||||
data["General"]["isPSNSignedIn"] = isPSNSignedIn;
|
||||
data["General"]["isTrophyPopupDisabled"] = isTrophyPopupDisabled;
|
||||
data["General"]["trophyNotificationDuration"] = trophyNotificationDuration;
|
||||
data["General"]["playBGM"] = playBGM;
|
||||
|
@ -1098,6 +1109,7 @@ void setDefaultValues() {
|
|||
isHDRAllowed = false;
|
||||
isNeo = false;
|
||||
isDevKit = false;
|
||||
isPSNSignedIn = false;
|
||||
isFullscreen = false;
|
||||
isTrophyPopupDisabled = false;
|
||||
playBGM = false;
|
||||
|
|
|
@ -14,7 +14,7 @@ struct GameInstallDir {
|
|||
bool enabled;
|
||||
};
|
||||
|
||||
enum HideCursorState : s16 { Never, Idle, Always };
|
||||
enum HideCursorState : int { Never, Idle, Always };
|
||||
|
||||
void load(const std::filesystem::path& path);
|
||||
void save(const std::filesystem::path& path);
|
||||
|
@ -39,6 +39,7 @@ bool getCompatibilityEnabled();
|
|||
bool getCheckCompatibilityOnStartup();
|
||||
int getBackgroundImageOpacity();
|
||||
bool getShowBackgroundImage();
|
||||
bool getPSNSignedIn();
|
||||
|
||||
std::string getLogFilter();
|
||||
std::string getLogType();
|
||||
|
@ -111,6 +112,7 @@ void setCompatibilityEnabled(bool use);
|
|||
void setCheckCompatibilityOnStartup(bool use);
|
||||
void setBackgroundImageOpacity(int opacity);
|
||||
void setShowBackgroundImage(bool show);
|
||||
void setPSNSignedIn(bool sign);
|
||||
|
||||
void setCursorState(s16 cursorState);
|
||||
void setCursorHideTimeout(int newcursorHideTimeout);
|
||||
|
|
|
@ -141,6 +141,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
|
|||
SUB(Lib, Camera) \
|
||||
SUB(Lib, CompanionHttpd) \
|
||||
SUB(Lib, CompanionUtil) \
|
||||
SUB(Lib, Voice) \
|
||||
CLS(Frontend) \
|
||||
CLS(Render) \
|
||||
SUB(Render, Vulkan) \
|
||||
|
|
|
@ -98,6 +98,7 @@ enum class Class : u8 {
|
|||
Lib_Fiber, ///< The LibSceFiber implementation.
|
||||
Lib_Vdec2, ///< The LibSceVideodec2 implementation.
|
||||
Lib_Videodec, ///< The LibSceVideodec implementation.
|
||||
Lib_Voice, ///< The LibSceVoice implementation.
|
||||
Lib_RazorCpu, ///< The LibRazorCpu implementation.
|
||||
Lib_Mouse, ///< The LibSceMouse implementation
|
||||
Lib_WebBrowserDialog, ///< The LibSceWebBrowserDialog implementation
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "common/scm_rev.h"
|
||||
|
||||
namespace Common {
|
||||
|
@ -15,5 +17,26 @@ constexpr char g_scm_remote_name[] = "@GIT_REMOTE_NAME@";
|
|||
constexpr char g_scm_remote_url[] = "@GIT_REMOTE_URL@";
|
||||
constexpr char g_scm_date[] = "@BUILD_DATE@";
|
||||
|
||||
const std::string GetRemoteNameFromLink() {
|
||||
std::string remote_url(Common::g_scm_remote_url);
|
||||
std::string remote_host;
|
||||
try {
|
||||
if (remote_url.starts_with("http")) {
|
||||
if (*remote_url.rbegin() == '/') {
|
||||
remote_url.pop_back();
|
||||
}
|
||||
remote_host = remote_url.substr(19, remote_url.rfind('/') - 19);
|
||||
} else if (remote_url.starts_with("git@")) {
|
||||
auto after_comma_pos = remote_url.find(':') + 1, slash_pos = remote_url.find('/');
|
||||
remote_host = remote_url.substr(after_comma_pos, slash_pos - after_comma_pos);
|
||||
} else {
|
||||
remote_host = "unknown";
|
||||
}
|
||||
} catch (...) {
|
||||
remote_host = "unknown";
|
||||
}
|
||||
return remote_host;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Common {
|
||||
|
||||
extern const char g_version[];
|
||||
|
@ -15,4 +17,6 @@ extern const char g_scm_remote_name[];
|
|||
extern const char g_scm_remote_url[];
|
||||
extern const char g_scm_date[];
|
||||
|
||||
const std::string GetRemoteNameFromLink();
|
||||
|
||||
} // namespace Common
|
||||
|
|
|
@ -145,6 +145,8 @@ bool EqueueInternal::TriggerEvent(u64 ident, s16 filter, void* trigger_data) {
|
|||
if (event.event.ident == ident && event.event.filter == filter) {
|
||||
if (filter == SceKernelEvent::Filter::VideoOut) {
|
||||
event.TriggerDisplay(trigger_data);
|
||||
} else if (filter == SceKernelEvent::Filter::User) {
|
||||
event.TriggerUser(trigger_data);
|
||||
} else {
|
||||
event.Trigger(trigger_data);
|
||||
}
|
||||
|
|
|
@ -98,6 +98,12 @@ struct EqueueEvent {
|
|||
event.data = reinterpret_cast<uintptr_t>(data);
|
||||
}
|
||||
|
||||
void TriggerUser(void* data) {
|
||||
is_triggered = true;
|
||||
event.fflags++;
|
||||
event.udata = data;
|
||||
}
|
||||
|
||||
void TriggerDisplay(void* data) {
|
||||
is_triggered = true;
|
||||
if (data != nullptr) {
|
||||
|
|
|
@ -264,6 +264,8 @@ int PS4_SYSV_ABI sceKernelQueryMemoryProtection(void* addr, void** start, void**
|
|||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelMprotect(const void* addr, u64 size, s32 prot) {
|
||||
LOG_INFO(Kernel_Vmm, "called addr = {}, size = {:#x}, prot = {:#x}", fmt::ptr(addr), size,
|
||||
prot);
|
||||
Core::MemoryManager* memory_manager = Core::Memory::Instance();
|
||||
Core::MemoryProt protection_flags = static_cast<Core::MemoryProt>(prot);
|
||||
return memory_manager->Protect(std::bit_cast<VAddr>(addr), size, protection_flags);
|
||||
|
@ -279,6 +281,8 @@ s32 PS4_SYSV_ABI posix_mprotect(const void* addr, u64 size, s32 prot) {
|
|||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelMtypeprotect(const void* addr, u64 size, s32 mtype, s32 prot) {
|
||||
LOG_INFO(Kernel_Vmm, "called addr = {}, size = {:#x}, prot = {:#x}", fmt::ptr(addr), size,
|
||||
prot);
|
||||
Core::MemoryManager* memory_manager = Core::Memory::Instance();
|
||||
Core::MemoryProt protection_flags = static_cast<Core::MemoryProt>(prot);
|
||||
return memory_manager->Protect(std::bit_cast<VAddr>(addr), size, protection_flags);
|
||||
|
|
|
@ -576,8 +576,19 @@ int PS4_SYSV_ABI posix_pthread_getaffinity_np(PthreadT thread, size_t cpusetsize
|
|||
if (thread == nullptr || cpusetp == nullptr) {
|
||||
return POSIX_EINVAL;
|
||||
}
|
||||
|
||||
auto* thread_state = ThrState::Instance();
|
||||
if (thread == g_curthread) {
|
||||
g_curthread->lock.lock();
|
||||
} else if (auto ret = thread_state->FindThread(thread, /*include dead*/ 0); ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
auto* attr_ptr = &thread->attr;
|
||||
return posix_pthread_attr_getaffinity_np(&attr_ptr, cpusetsize, cpusetp);
|
||||
auto ret = posix_pthread_attr_getaffinity_np(&attr_ptr, cpusetsize, cpusetp);
|
||||
|
||||
thread->lock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_setaffinity_np(PthreadT thread, size_t cpusetsize,
|
||||
|
@ -585,11 +596,23 @@ int PS4_SYSV_ABI posix_pthread_setaffinity_np(PthreadT thread, size_t cpusetsize
|
|||
if (thread == nullptr || cpusetp == nullptr) {
|
||||
return POSIX_EINVAL;
|
||||
}
|
||||
auto* attr_ptr = &thread->attr;
|
||||
if (const auto ret = posix_pthread_attr_setaffinity_np(&attr_ptr, cpusetsize, cpusetp)) {
|
||||
|
||||
auto* thread_state = ThrState::Instance();
|
||||
if (thread == g_curthread) {
|
||||
g_curthread->lock.lock();
|
||||
} else if (auto ret = thread_state->FindThread(thread, /*include dead*/ 0); ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
return thread->SetAffinity(thread->attr.cpuset);
|
||||
|
||||
auto* attr_ptr = &thread->attr;
|
||||
auto ret = posix_pthread_attr_setaffinity_np(&attr_ptr, cpusetsize, cpusetp);
|
||||
|
||||
if (ret == ORBIS_OK) {
|
||||
ret = thread->SetAffinity(thread->attr.cpuset);
|
||||
}
|
||||
|
||||
thread->lock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI scePthreadGetaffinity(PthreadT thread, u64* mask) {
|
||||
|
|
|
@ -306,6 +306,8 @@ void RegisterThreadAttr(Core::Loader::SymbolsResolver* sym) {
|
|||
posix_pthread_attr_getdetachstate);
|
||||
LIB_FUNCTION("JKyG3SWyA10", "libScePosix", 1, "libkernel", 1, 1,
|
||||
posix_pthread_attr_setguardsize);
|
||||
LIB_FUNCTION("qlk9pSLsUmM", "libScePosix", 1, "libkernel", 1, 1,
|
||||
posix_pthread_attr_getschedparam);
|
||||
|
||||
// Orbis
|
||||
LIB_FUNCTION("4+h9EzwKF4I", "libkernel", 1, "libkernel", 1, 1,
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
#include "core/libraries/videodec/videodec.h"
|
||||
#include "core/libraries/videodec/videodec2.h"
|
||||
#include "core/libraries/videoout/video_out.h"
|
||||
#include "core/libraries/voice/voice.h"
|
||||
#include "core/libraries/web_browser_dialog/webbrowserdialog.h"
|
||||
#include "core/libraries/zlib/zlib_sce.h"
|
||||
#include "fiber/fiber.h"
|
||||
|
@ -128,6 +129,7 @@ void InitHLELibs(Core::Loader::SymbolsResolver* sym) {
|
|||
Libraries::Camera::RegisterlibSceCamera(sym);
|
||||
Libraries::CompanionHttpd::RegisterlibSceCompanionHttpd(sym);
|
||||
Libraries::CompanionUtil::RegisterlibSceCompanionUtil(sym);
|
||||
Libraries::Voice::RegisterlibSceVoice(sym);
|
||||
}
|
||||
|
||||
} // namespace Libraries
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/config.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/libs.h"
|
||||
|
@ -10,6 +11,8 @@
|
|||
|
||||
namespace Libraries::NpManager {
|
||||
|
||||
#define SIGNEDIN_STATUS (Config::getPSNSignedIn() ? ORBIS_OK : ORBIS_NP_ERROR_SIGNED_OUT)
|
||||
|
||||
int PS4_SYSV_ABI Func_EF4378573542A508() {
|
||||
LOG_ERROR(Lib_NpManager, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
|
@ -921,9 +924,16 @@ int PS4_SYSV_ABI sceNpGetAccountCountry() {
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpGetAccountCountryA() {
|
||||
LOG_ERROR(Lib_NpManager, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
int PS4_SYSV_ABI sceNpGetAccountCountryA(OrbisUserServiceUserId user_id,
|
||||
OrbisNpCountryCode* country_code) {
|
||||
LOG_INFO(Lib_NpManager, "(STUBBED) called, user_id = {}", user_id);
|
||||
if (country_code == nullptr) {
|
||||
return ORBIS_NP_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
::memset(country_code, 0, sizeof(OrbisNpCountryCode));
|
||||
// TODO: get NP country code from config
|
||||
::memcpy(country_code->country_code, "us", 2);
|
||||
return SIGNEDIN_STATUS;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpGetAccountDateOfBirth() {
|
||||
|
@ -941,8 +951,8 @@ int PS4_SYSV_ABI sceNpGetAccountId(OrbisNpOnlineId* online_id, u64* account_id)
|
|||
if (online_id == nullptr || account_id == nullptr) {
|
||||
return ORBIS_NP_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
*account_id = 0;
|
||||
return ORBIS_NP_ERROR_SIGNED_OUT;
|
||||
*account_id = 0xFEEDFACE;
|
||||
return SIGNEDIN_STATUS;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpGetAccountIdA(OrbisUserServiceUserId user_id, u64* account_id) {
|
||||
|
@ -950,8 +960,8 @@ int PS4_SYSV_ABI sceNpGetAccountIdA(OrbisUserServiceUserId user_id, u64* account
|
|||
if (account_id == nullptr) {
|
||||
return ORBIS_NP_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
*account_id = 0;
|
||||
return ORBIS_NP_ERROR_SIGNED_OUT;
|
||||
*account_id = 0xFEEDFACE;
|
||||
return SIGNEDIN_STATUS;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpGetAccountLanguage() {
|
||||
|
@ -984,7 +994,9 @@ int PS4_SYSV_ABI sceNpGetNpId(OrbisUserServiceUserId user_id, OrbisNpId* np_id)
|
|||
if (np_id == nullptr) {
|
||||
return ORBIS_NP_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
return ORBIS_NP_ERROR_SIGNED_OUT;
|
||||
memset(np_id, 0, sizeof(OrbisNpId));
|
||||
strncpy(np_id->handle.data, Config::getUserName().c_str(), sizeof(np_id->handle.data));
|
||||
return SIGNEDIN_STATUS;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpGetNpReachabilityState() {
|
||||
|
@ -997,7 +1009,9 @@ int PS4_SYSV_ABI sceNpGetOnlineId(OrbisUserServiceUserId user_id, OrbisNpOnlineI
|
|||
if (online_id == nullptr) {
|
||||
return ORBIS_NP_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
return ORBIS_NP_ERROR_SIGNED_OUT;
|
||||
memset(online_id, 0, sizeof(OrbisNpOnlineId));
|
||||
strncpy(online_id->data, Config::getUserName().c_str(), sizeof(online_id->data));
|
||||
return SIGNEDIN_STATUS;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpGetParentalControlInfo() {
|
||||
|
@ -1014,8 +1028,8 @@ int PS4_SYSV_ABI sceNpGetState(OrbisUserServiceUserId user_id, OrbisNpState* sta
|
|||
if (state == nullptr) {
|
||||
return ORBIS_NP_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
*state = OrbisNpState::SignedOut;
|
||||
LOG_DEBUG(Lib_NpManager, "Signed out");
|
||||
*state = Config::getPSNSignedIn() ? OrbisNpState::SignedIn : OrbisNpState::SignedOut;
|
||||
LOG_DEBUG(Lib_NpManager, "Signed {}", Config::getPSNSignedIn() ? "in" : "out");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,12 @@ struct OrbisNpId {
|
|||
u8 reserved[8];
|
||||
};
|
||||
|
||||
struct OrbisNpCountryCode {
|
||||
char country_code[2];
|
||||
char end;
|
||||
char pad;
|
||||
};
|
||||
|
||||
int PS4_SYSV_ABI Func_EF4378573542A508();
|
||||
int PS4_SYSV_ABI _sceNpIpcCreateMemoryFromKernel();
|
||||
int PS4_SYSV_ABI _sceNpIpcCreateMemoryFromPool();
|
||||
|
@ -215,7 +221,8 @@ int PS4_SYSV_ABI sceNpCreateRequest();
|
|||
int PS4_SYSV_ABI sceNpDeleteRequest(int reqId);
|
||||
int PS4_SYSV_ABI sceNpGetAccountAge();
|
||||
int PS4_SYSV_ABI sceNpGetAccountCountry();
|
||||
int PS4_SYSV_ABI sceNpGetAccountCountryA();
|
||||
int PS4_SYSV_ABI sceNpGetAccountCountryA(OrbisUserServiceUserId user_id,
|
||||
OrbisNpCountryCode* country_code);
|
||||
int PS4_SYSV_ABI sceNpGetAccountDateOfBirth();
|
||||
int PS4_SYSV_ABI sceNpGetAccountDateOfBirthA();
|
||||
int PS4_SYSV_ABI sceNpGetAccountId(OrbisNpOnlineId* online_id, u64* account_id);
|
||||
|
|
|
@ -316,22 +316,79 @@ int PS4_SYSV_ABI scePadRead(s32 handle, OrbisPadData* pData, s32 num) {
|
|||
pData[i].angularVelocity.y = states[i].angularVelocity.y;
|
||||
pData[i].angularVelocity.z = states[i].angularVelocity.z;
|
||||
pData[i].orientation = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||
if (engine) {
|
||||
pData[i].acceleration.x = states[i].acceleration.x * 0.098;
|
||||
pData[i].acceleration.y = states[i].acceleration.y * 0.098;
|
||||
pData[i].acceleration.z = states[i].acceleration.z * 0.098;
|
||||
pData[i].angularVelocity.x = states[i].angularVelocity.x;
|
||||
pData[i].angularVelocity.y = states[i].angularVelocity.y;
|
||||
pData[i].angularVelocity.z = states[i].angularVelocity.z;
|
||||
|
||||
if (engine && handle == 1) {
|
||||
const auto gyro_poll_rate = engine->GetAccelPollRate();
|
||||
if (gyro_poll_rate != 0.0f) {
|
||||
GameController::CalculateOrientation(pData[i].acceleration,
|
||||
pData[i].angularVelocity,
|
||||
1.0f / gyro_poll_rate, pData[i].orientation);
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
float deltaTime = std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
now - controller->GetLastUpdate())
|
||||
.count() /
|
||||
1000000.0f;
|
||||
controller->SetLastUpdate(now);
|
||||
Libraries::Pad::OrbisFQuaternion lastOrientation = controller->GetLastOrientation();
|
||||
Libraries::Pad::OrbisFQuaternion outputOrientation = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||
GameController::CalculateOrientation(pData->acceleration, pData->angularVelocity,
|
||||
deltaTime, lastOrientation, outputOrientation);
|
||||
pData[i].orientation = outputOrientation;
|
||||
controller->SetLastOrientation(outputOrientation);
|
||||
}
|
||||
}
|
||||
|
||||
pData[i].touchData.touchNum =
|
||||
(states[i].touchpad[0].state ? 1 : 0) + (states[i].touchpad[1].state ? 1 : 0);
|
||||
|
||||
if (handle == 1) {
|
||||
if (controller->GetTouchCount() >= 127) {
|
||||
controller->SetTouchCount(0);
|
||||
}
|
||||
|
||||
if (controller->GetSecondaryTouchCount() >= 127) {
|
||||
controller->SetSecondaryTouchCount(0);
|
||||
}
|
||||
|
||||
if (pData->touchData.touchNum == 1 && controller->GetPreviousTouchNum() == 0) {
|
||||
controller->SetTouchCount(controller->GetTouchCount() + 1);
|
||||
controller->SetSecondaryTouchCount(controller->GetTouchCount());
|
||||
} else if (pData->touchData.touchNum == 2 && controller->GetPreviousTouchNum() == 1) {
|
||||
controller->SetSecondaryTouchCount(controller->GetSecondaryTouchCount() + 1);
|
||||
} else if (pData->touchData.touchNum == 0 && controller->GetPreviousTouchNum() > 0) {
|
||||
if (controller->GetTouchCount() < controller->GetSecondaryTouchCount()) {
|
||||
controller->SetTouchCount(controller->GetSecondaryTouchCount());
|
||||
} else {
|
||||
if (controller->WasSecondaryTouchReset()) {
|
||||
controller->SetTouchCount(controller->GetSecondaryTouchCount());
|
||||
controller->UnsetSecondaryTouchResetBool();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
controller->SetPreviousTouchNum(pData->touchData.touchNum);
|
||||
|
||||
if (pData->touchData.touchNum == 1) {
|
||||
states[i].touchpad[0].ID = controller->GetTouchCount();
|
||||
states[i].touchpad[1].ID = 0;
|
||||
} else if (pData->touchData.touchNum == 2) {
|
||||
states[i].touchpad[0].ID = controller->GetTouchCount();
|
||||
states[i].touchpad[1].ID = controller->GetSecondaryTouchCount();
|
||||
}
|
||||
} else {
|
||||
states[i].touchpad[0].ID = 1;
|
||||
states[i].touchpad[1].ID = 2;
|
||||
}
|
||||
|
||||
pData[i].touchData.touch[0].x = states[i].touchpad[0].x;
|
||||
pData[i].touchData.touch[0].y = states[i].touchpad[0].y;
|
||||
pData[i].touchData.touch[0].id = 1;
|
||||
pData[i].touchData.touch[0].id = states[i].touchpad[0].ID;
|
||||
pData[i].touchData.touch[1].x = states[i].touchpad[1].x;
|
||||
pData[i].touchData.touch[1].y = states[i].touchpad[1].y;
|
||||
pData[i].touchData.touch[1].id = 2;
|
||||
pData[i].touchData.touch[1].id = states[i].touchpad[1].ID;
|
||||
pData[i].connected = connected;
|
||||
pData[i].timestamp = states[i].time;
|
||||
pData[i].connectedCount = connected_count;
|
||||
|
@ -376,31 +433,85 @@ int PS4_SYSV_ABI scePadReadState(s32 handle, OrbisPadData* pData) {
|
|||
pData->leftStick.x = state.axes[static_cast<int>(Input::Axis::LeftX)];
|
||||
pData->leftStick.y = state.axes[static_cast<int>(Input::Axis::LeftY)];
|
||||
pData->rightStick.x = state.axes[static_cast<int>(Input::Axis::RightX)];
|
||||
pData->rightStick.x = state.axes[static_cast<int>(Input::Axis::RightX)];
|
||||
pData->rightStick.y = state.axes[static_cast<int>(Input::Axis::RightY)];
|
||||
pData->analogButtons.l2 = state.axes[static_cast<int>(Input::Axis::TriggerLeft)];
|
||||
pData->analogButtons.r2 = state.axes[static_cast<int>(Input::Axis::TriggerRight)];
|
||||
pData->acceleration.x = state.acceleration.x;
|
||||
pData->acceleration.y = state.acceleration.y;
|
||||
pData->acceleration.z = state.acceleration.z;
|
||||
pData->acceleration.x = state.acceleration.x * 0.098;
|
||||
pData->acceleration.y = state.acceleration.y * 0.098;
|
||||
pData->acceleration.z = state.acceleration.z * 0.098;
|
||||
pData->angularVelocity.x = state.angularVelocity.x;
|
||||
pData->angularVelocity.y = state.angularVelocity.y;
|
||||
pData->angularVelocity.z = state.angularVelocity.z;
|
||||
pData->orientation = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||
if (engine) {
|
||||
|
||||
// Only do this on handle 1 for now
|
||||
if (engine && handle == 1) {
|
||||
const auto gyro_poll_rate = engine->GetAccelPollRate();
|
||||
if (gyro_poll_rate != 0.0f) {
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
float deltaTime = std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
now - controller->GetLastUpdate())
|
||||
.count() /
|
||||
1000000.0f;
|
||||
controller->SetLastUpdate(now);
|
||||
Libraries::Pad::OrbisFQuaternion lastOrientation = controller->GetLastOrientation();
|
||||
Libraries::Pad::OrbisFQuaternion outputOrientation = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||
GameController::CalculateOrientation(pData->acceleration, pData->angularVelocity,
|
||||
1.0f / gyro_poll_rate, pData->orientation);
|
||||
deltaTime, lastOrientation, outputOrientation);
|
||||
pData->orientation = outputOrientation;
|
||||
controller->SetLastOrientation(outputOrientation);
|
||||
}
|
||||
}
|
||||
pData->touchData.touchNum =
|
||||
(state.touchpad[0].state ? 1 : 0) + (state.touchpad[1].state ? 1 : 0);
|
||||
|
||||
// Only do this on handle 1 for now
|
||||
if (handle == 1) {
|
||||
if (controller->GetTouchCount() >= 127) {
|
||||
controller->SetTouchCount(0);
|
||||
}
|
||||
|
||||
if (controller->GetSecondaryTouchCount() >= 127) {
|
||||
controller->SetSecondaryTouchCount(0);
|
||||
}
|
||||
|
||||
if (pData->touchData.touchNum == 1 && controller->GetPreviousTouchNum() == 0) {
|
||||
controller->SetTouchCount(controller->GetTouchCount() + 1);
|
||||
controller->SetSecondaryTouchCount(controller->GetTouchCount());
|
||||
} else if (pData->touchData.touchNum == 2 && controller->GetPreviousTouchNum() == 1) {
|
||||
controller->SetSecondaryTouchCount(controller->GetSecondaryTouchCount() + 1);
|
||||
} else if (pData->touchData.touchNum == 0 && controller->GetPreviousTouchNum() > 0) {
|
||||
if (controller->GetTouchCount() < controller->GetSecondaryTouchCount()) {
|
||||
controller->SetTouchCount(controller->GetSecondaryTouchCount());
|
||||
} else {
|
||||
if (controller->WasSecondaryTouchReset()) {
|
||||
controller->SetTouchCount(controller->GetSecondaryTouchCount());
|
||||
controller->UnsetSecondaryTouchResetBool();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
controller->SetPreviousTouchNum(pData->touchData.touchNum);
|
||||
|
||||
if (pData->touchData.touchNum == 1) {
|
||||
state.touchpad[0].ID = controller->GetTouchCount();
|
||||
state.touchpad[1].ID = 0;
|
||||
} else if (pData->touchData.touchNum == 2) {
|
||||
state.touchpad[0].ID = controller->GetTouchCount();
|
||||
state.touchpad[1].ID = controller->GetSecondaryTouchCount();
|
||||
}
|
||||
} else {
|
||||
state.touchpad[0].ID = 1;
|
||||
state.touchpad[1].ID = 2;
|
||||
}
|
||||
|
||||
pData->touchData.touch[0].x = state.touchpad[0].x;
|
||||
pData->touchData.touch[0].y = state.touchpad[0].y;
|
||||
pData->touchData.touch[0].id = 1;
|
||||
pData->touchData.touch[0].id = state.touchpad[0].ID;
|
||||
pData->touchData.touch[1].x = state.touchpad[1].x;
|
||||
pData->touchData.touch[1].y = state.touchpad[1].y;
|
||||
pData->touchData.touch[1].id = 2;
|
||||
pData->touchData.touch[1].id = state.touchpad[1].ID;
|
||||
pData->timestamp = state.time;
|
||||
pData->connected = true; // isConnected; //TODO fix me proper
|
||||
pData->connectedCount = 1; // connectedCount;
|
||||
|
|
203
src/core/libraries/voice/voice.cpp
Normal file
203
src/core/libraries/voice/voice.cpp
Normal file
|
@ -0,0 +1,203 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/libs.h"
|
||||
#include "core/libraries/voice/voice.h"
|
||||
|
||||
namespace Libraries::Voice {
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceConnectIPortToOPort() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceCreatePort() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceDeletePort() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceDisconnectIPortFromOPort() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceEnd() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceGetBitRate(u32 port_id, u32* bitrate) {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
*bitrate = 48000;
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceGetMuteFlag() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceGetPortAttr() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceGetPortInfo(u32 port_id, OrbisVoicePortInfo* info) {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
info->port_type = 0;
|
||||
info->state = 3;
|
||||
info->byte_count = 0;
|
||||
info->frame_size = 1;
|
||||
info->edge_count = 0;
|
||||
info->reserved = 0;
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceGetResourceInfo() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceGetVolume() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceInit() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceInitHQ() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoicePausePort() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoicePausePortAll() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceReadFromOPort() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceResetPort() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceResumePort() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceResumePortAll() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceSetBitRate() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceSetMuteFlag() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceSetMuteFlagAll() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceSetThreadsParams() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceSetVolume() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceStart() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceStop() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceUpdatePort() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceVADAdjustment() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceVADSetVersion() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceWriteToIPort() {
|
||||
LOG_ERROR(Lib_Voice, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
void RegisterlibSceVoice(Core::Loader::SymbolsResolver* sym) {
|
||||
LIB_FUNCTION("oV9GAdJ23Gw", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceConnectIPortToOPort);
|
||||
LIB_FUNCTION("nXpje5yNpaE", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceCreatePort);
|
||||
LIB_FUNCTION("b7kJI+nx2hg", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceDeletePort);
|
||||
LIB_FUNCTION("ajVj3QG2um4", "libSceVoice", 1, "libSceVoice", 0, 0,
|
||||
sceVoiceDisconnectIPortFromOPort);
|
||||
LIB_FUNCTION("Oo0S5PH7FIQ", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceEnd);
|
||||
LIB_FUNCTION("cJLufzou6bc", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceGetBitRate);
|
||||
LIB_FUNCTION("Pc4z1QjForU", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceGetMuteFlag);
|
||||
LIB_FUNCTION("elcxZTEfHZM", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceGetPortAttr);
|
||||
LIB_FUNCTION("CrLqDwWLoXM", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceGetPortInfo);
|
||||
LIB_FUNCTION("Z6QV6j7igvE", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceGetResourceInfo);
|
||||
LIB_FUNCTION("jjkCjneOYSs", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceGetVolume);
|
||||
LIB_FUNCTION("9TrhuGzberQ", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceInit);
|
||||
LIB_FUNCTION("IPHvnM5+g04", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceInitHQ);
|
||||
LIB_FUNCTION("x0slGBQW+wY", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoicePausePort);
|
||||
LIB_FUNCTION("Dinob0yMRl8", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoicePausePortAll);
|
||||
LIB_FUNCTION("cQ6DGsQEjV4", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceReadFromOPort);
|
||||
LIB_FUNCTION("udAxvCePkUs", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceResetPort);
|
||||
LIB_FUNCTION("gAgN+HkiEzY", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceResumePort);
|
||||
LIB_FUNCTION("jbkJFmOZ9U0", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceResumePortAll);
|
||||
LIB_FUNCTION("TexwmOHQsDg", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceSetBitRate);
|
||||
LIB_FUNCTION("gwUynkEgNFY", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceSetMuteFlag);
|
||||
LIB_FUNCTION("oUha0S-Ij9Q", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceSetMuteFlagAll);
|
||||
LIB_FUNCTION("clyKUyi3RYU", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceSetThreadsParams);
|
||||
LIB_FUNCTION("QBFoAIjJoXQ", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceSetVolume);
|
||||
LIB_FUNCTION("54phPH2LZls", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceStart);
|
||||
LIB_FUNCTION("Ao2YNSA7-Qo", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceStop);
|
||||
LIB_FUNCTION("jSZNP7xJrcw", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceUpdatePort);
|
||||
LIB_FUNCTION("hg9T73LlRiU", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceVADAdjustment);
|
||||
LIB_FUNCTION("wFeAxEeEi-8", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceVADSetVersion);
|
||||
LIB_FUNCTION("YeJl6yDlhW0", "libSceVoice", 1, "libSceVoice", 0, 0, sceVoiceWriteToIPort);
|
||||
};
|
||||
|
||||
} // namespace Libraries::Voice
|
56
src/core/libraries/voice/voice.h
Normal file
56
src/core/libraries/voice/voice.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/types.h"
|
||||
|
||||
namespace Core::Loader {
|
||||
class SymbolsResolver;
|
||||
}
|
||||
|
||||
namespace Libraries::Voice {
|
||||
|
||||
struct OrbisVoicePortInfo {
|
||||
s32 port_type;
|
||||
s32 state;
|
||||
u32* edge;
|
||||
u32 byte_count;
|
||||
u32 frame_size;
|
||||
u16 edge_count;
|
||||
u16 reserved;
|
||||
};
|
||||
|
||||
s32 PS4_SYSV_ABI sceVoiceConnectIPortToOPort();
|
||||
s32 PS4_SYSV_ABI sceVoiceCreatePort();
|
||||
s32 PS4_SYSV_ABI sceVoiceDeletePort();
|
||||
s32 PS4_SYSV_ABI sceVoiceDisconnectIPortFromOPort();
|
||||
s32 PS4_SYSV_ABI sceVoiceEnd();
|
||||
s32 PS4_SYSV_ABI sceVoiceGetBitRate(u32 port_id, u32* bitrate);
|
||||
s32 PS4_SYSV_ABI sceVoiceGetMuteFlag();
|
||||
s32 PS4_SYSV_ABI sceVoiceGetPortAttr();
|
||||
s32 PS4_SYSV_ABI sceVoiceGetPortInfo(u32 port_id, OrbisVoicePortInfo* info);
|
||||
s32 PS4_SYSV_ABI sceVoiceGetResourceInfo();
|
||||
s32 PS4_SYSV_ABI sceVoiceGetVolume();
|
||||
s32 PS4_SYSV_ABI sceVoiceInit();
|
||||
s32 PS4_SYSV_ABI sceVoiceInitHQ();
|
||||
s32 PS4_SYSV_ABI sceVoicePausePort();
|
||||
s32 PS4_SYSV_ABI sceVoicePausePortAll();
|
||||
s32 PS4_SYSV_ABI sceVoiceReadFromOPort();
|
||||
s32 PS4_SYSV_ABI sceVoiceResetPort();
|
||||
s32 PS4_SYSV_ABI sceVoiceResumePort();
|
||||
s32 PS4_SYSV_ABI sceVoiceResumePortAll();
|
||||
s32 PS4_SYSV_ABI sceVoiceSetBitRate();
|
||||
s32 PS4_SYSV_ABI sceVoiceSetMuteFlag();
|
||||
s32 PS4_SYSV_ABI sceVoiceSetMuteFlagAll();
|
||||
s32 PS4_SYSV_ABI sceVoiceSetThreadsParams();
|
||||
s32 PS4_SYSV_ABI sceVoiceSetVolume();
|
||||
s32 PS4_SYSV_ABI sceVoiceStart();
|
||||
s32 PS4_SYSV_ABI sceVoiceStop();
|
||||
s32 PS4_SYSV_ABI sceVoiceUpdatePort();
|
||||
s32 PS4_SYSV_ABI sceVoiceVADAdjustment();
|
||||
s32 PS4_SYSV_ABI sceVoiceVADSetVersion();
|
||||
s32 PS4_SYSV_ABI sceVoiceWriteToIPort();
|
||||
|
||||
void RegisterlibSceVoice(Core::Loader::SymbolsResolver* sym);
|
||||
} // namespace Libraries::Voice
|
|
@ -117,6 +117,18 @@ void Linker::Execute(const std::vector<std::string> args) {
|
|||
Common::SetCurrentThreadName("GAME_MainThread");
|
||||
LoadSharedLibraries();
|
||||
|
||||
// Simulate libSceGnmDriver initialization, which maps a chunk of direct memory.
|
||||
// Some games fail without accurately emulating this behavior.
|
||||
s64 phys_addr{};
|
||||
s32 result = Libraries::Kernel::sceKernelAllocateDirectMemory(
|
||||
0, Libraries::Kernel::sceKernelGetDirectMemorySize(), 0x10000, 0x10000, 3, &phys_addr);
|
||||
if (result == 0) {
|
||||
void* addr{reinterpret_cast<void*>(0xfe0000000)};
|
||||
result = Libraries::Kernel::sceKernelMapNamedDirectMemory(
|
||||
&addr, 0x10000, 0x13, 0, phys_addr, 0x10000, "SceGnmDriver");
|
||||
}
|
||||
ASSERT_MSG(result == 0, "Unable to emulate libSceGnmDriver initialization");
|
||||
|
||||
// Start main module.
|
||||
EntryParams params{};
|
||||
params.argc = 1;
|
||||
|
|
|
@ -68,7 +68,7 @@ void MemoryManager::SetupMemoryRegions(u64 flexible_size, bool use_extended_mem1
|
|||
}
|
||||
|
||||
u64 MemoryManager::ClampRangeSize(VAddr virtual_addr, u64 size) {
|
||||
static constexpr u64 MinSizeToClamp = 512_MB;
|
||||
static constexpr u64 MinSizeToClamp = 2_MB;
|
||||
// Dont bother with clamping if the size is small so we dont pay a map lookup on every buffer.
|
||||
if (size < MinSizeToClamp) {
|
||||
return size;
|
||||
|
@ -262,10 +262,7 @@ int MemoryManager::PoolCommit(VAddr virtual_addr, size_t size, MemoryProt prot)
|
|||
void* out_addr = impl.Map(mapped_addr, size, alignment, -1, false);
|
||||
TRACK_ALLOC(out_addr, size, "VMEM");
|
||||
|
||||
if (prot >= MemoryProt::GpuRead) {
|
||||
// PS4s only map to GPU memory when the protection includes GPU access.
|
||||
// If the address to map to is too high, PS4s throw a page fault and crash.
|
||||
ASSERT_MSG(IsValidGpuMapping(mapped_addr, size), "Invalid address for GPU mapping");
|
||||
if (IsValidGpuMapping(mapped_addr, size)) {
|
||||
rasterizer->MapMemory(mapped_addr, size);
|
||||
}
|
||||
|
||||
|
@ -345,19 +342,15 @@ s32 MemoryManager::MapMemory(void** out_addr, VAddr virtual_addr, u64 size, Memo
|
|||
MergeAdjacent(vma_map, new_vma_handle);
|
||||
}
|
||||
|
||||
if (prot >= MemoryProt::GpuRead) {
|
||||
// PS4s only map to GPU memory when the protection includes GPU access.
|
||||
// If the address to map to is too high, PS4s throw a page fault and crash.
|
||||
ASSERT_MSG(IsValidGpuMapping(mapped_addr, size), "Invalid address for GPU mapping");
|
||||
rasterizer->MapMemory(mapped_addr, size);
|
||||
}
|
||||
|
||||
if (type == VMAType::Reserved || type == VMAType::PoolReserved) {
|
||||
// For Reserved/PoolReserved mappings, we don't perform any address space allocations.
|
||||
// Just set out_addr to mapped_addr instead.
|
||||
*out_addr = std::bit_cast<void*>(mapped_addr);
|
||||
} else {
|
||||
// Type is either Direct, Flexible, or Code, these need to be mapped in our address space.
|
||||
// If this is not a reservation, then map to GPU and address space
|
||||
if (IsValidGpuMapping(mapped_addr, size)) {
|
||||
rasterizer->MapMemory(mapped_addr, size);
|
||||
}
|
||||
*out_addr = impl.Map(mapped_addr, size, alignment, phys_addr, is_exec);
|
||||
}
|
||||
|
||||
|
@ -429,7 +422,6 @@ s32 MemoryManager::PoolDecommit(VAddr virtual_addr, size_t size) {
|
|||
const bool is_exec = vma_base.is_exec;
|
||||
const auto start_in_vma = virtual_addr - vma_base_addr;
|
||||
const auto type = vma_base.type;
|
||||
const auto prot = vma_base.prot;
|
||||
|
||||
if (type != VMAType::PoolReserved && type != VMAType::Pooled) {
|
||||
LOG_ERROR(Kernel_Vmm, "Attempting to decommit non-pooled memory!");
|
||||
|
@ -437,13 +429,13 @@ s32 MemoryManager::PoolDecommit(VAddr virtual_addr, size_t size) {
|
|||
}
|
||||
|
||||
if (type == VMAType::Pooled) {
|
||||
// Track how much pooled memory is decommitted
|
||||
pool_budget += size;
|
||||
// We always map PoolCommitted memory to GPU, so unmap when decomitting.
|
||||
if (IsValidGpuMapping(virtual_addr, size)) {
|
||||
rasterizer->UnmapMemory(virtual_addr, size);
|
||||
}
|
||||
|
||||
if (prot >= MemoryProt::GpuRead) {
|
||||
// If this mapping has GPU access, unmap from GPU.
|
||||
rasterizer->UnmapMemory(virtual_addr, size);
|
||||
// Track how much pooled memory is decommitted
|
||||
pool_budget += size;
|
||||
}
|
||||
|
||||
// Mark region as free and attempt to coalesce it with neighbours.
|
||||
|
@ -486,15 +478,11 @@ u64 MemoryManager::UnmapBytesFromEntry(VAddr virtual_addr, VirtualMemoryArea vma
|
|||
if (type == VMAType::Free) {
|
||||
return adjusted_size;
|
||||
}
|
||||
|
||||
if (type == VMAType::Flexible) {
|
||||
flexible_usage -= adjusted_size;
|
||||
}
|
||||
|
||||
if (prot >= MemoryProt::GpuRead) {
|
||||
// If this mapping has GPU access, unmap from GPU.
|
||||
rasterizer->UnmapMemory(virtual_addr, size);
|
||||
}
|
||||
|
||||
// Mark region as free and attempt to coalesce it with neighbours.
|
||||
const auto new_it = CarveVMA(virtual_addr, adjusted_size);
|
||||
auto& vma = new_it->second;
|
||||
|
@ -507,6 +495,11 @@ u64 MemoryManager::UnmapBytesFromEntry(VAddr virtual_addr, VirtualMemoryArea vma
|
|||
auto& post_merge_vma = post_merge_it->second;
|
||||
bool readonly_file = post_merge_vma.prot == MemoryProt::CpuRead && type == VMAType::File;
|
||||
if (type != VMAType::Reserved && type != VMAType::PoolReserved) {
|
||||
// If this mapping has GPU access, unmap from GPU.
|
||||
if (IsValidGpuMapping(virtual_addr, size)) {
|
||||
rasterizer->UnmapMemory(virtual_addr, size);
|
||||
}
|
||||
|
||||
// Unmap the memory region.
|
||||
impl.Unmap(vma_base_addr, vma_base_size, start_in_vma, start_in_vma + adjusted_size,
|
||||
phys_base, is_exec, has_backing, readonly_file);
|
||||
|
@ -564,30 +557,6 @@ s64 MemoryManager::ProtectBytes(VAddr addr, VirtualMemoryArea vma_base, size_t s
|
|||
return adjusted_size;
|
||||
}
|
||||
|
||||
// Validate protection flags
|
||||
constexpr static MemoryProt valid_flags = MemoryProt::NoAccess | MemoryProt::CpuRead |
|
||||
MemoryProt::CpuReadWrite | MemoryProt::GpuRead |
|
||||
MemoryProt::GpuWrite | MemoryProt::GpuReadWrite;
|
||||
|
||||
MemoryProt invalid_flags = prot & ~valid_flags;
|
||||
if (u32(invalid_flags) != 0 && u32(invalid_flags) != u32(MemoryProt::NoAccess)) {
|
||||
LOG_ERROR(Kernel_Vmm, "Invalid protection flags: prot = {:#x}, invalid flags = {:#x}",
|
||||
u32(prot), u32(invalid_flags));
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
if (vma_base.prot < MemoryProt::GpuRead && prot >= MemoryProt::GpuRead) {
|
||||
// New protection will give the GPU access to this VMA, perform a rasterizer map
|
||||
ASSERT_MSG(IsValidGpuMapping(addr, size), "Invalid address for GPU mapping");
|
||||
rasterizer->MapMemory(addr, size);
|
||||
}
|
||||
|
||||
if (vma_base.prot >= MemoryProt::GpuRead && prot < MemoryProt::GpuRead) {
|
||||
// New protection will remove the GPU's access to this VMA, perform a rasterizer unmap
|
||||
ASSERT_MSG(IsValidGpuMapping(addr, size), "Invalid address for GPU unmap");
|
||||
rasterizer->UnmapMemory(addr, size);
|
||||
}
|
||||
|
||||
// Change protection
|
||||
vma_base.prot = prot;
|
||||
|
||||
|
@ -617,11 +586,25 @@ s64 MemoryManager::ProtectBytes(VAddr addr, VirtualMemoryArea vma_base, size_t s
|
|||
|
||||
s32 MemoryManager::Protect(VAddr addr, size_t size, MemoryProt prot) {
|
||||
std::scoped_lock lk{mutex};
|
||||
s64 protected_bytes = 0;
|
||||
|
||||
// Validate protection flags
|
||||
constexpr static MemoryProt valid_flags = MemoryProt::NoAccess | MemoryProt::CpuRead |
|
||||
MemoryProt::CpuReadWrite | MemoryProt::GpuRead |
|
||||
MemoryProt::GpuWrite | MemoryProt::GpuReadWrite;
|
||||
|
||||
MemoryProt invalid_flags = prot & ~valid_flags;
|
||||
if (invalid_flags != MemoryProt::NoAccess) {
|
||||
LOG_ERROR(Kernel_Vmm, "Invalid protection flags");
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
// Align addr and size to the nearest page boundary.
|
||||
auto aligned_addr = Common::AlignDown(addr, 16_KB);
|
||||
auto aligned_size = Common::AlignUp(size + addr - aligned_addr, 16_KB);
|
||||
do {
|
||||
|
||||
// Protect all VMAs between aligned_addr and aligned_addr + aligned_size.
|
||||
s64 protected_bytes = 0;
|
||||
while (protected_bytes < aligned_size) {
|
||||
auto it = FindVMA(aligned_addr + protected_bytes);
|
||||
auto& vma_base = it->second;
|
||||
ASSERT_MSG(vma_base.Contains(addr + protected_bytes, 0), "Address {:#x} is out of bounds",
|
||||
|
@ -634,7 +617,7 @@ s32 MemoryManager::Protect(VAddr addr, size_t size, MemoryProt prot) {
|
|||
return result;
|
||||
}
|
||||
protected_bytes += result;
|
||||
} while (protected_bytes < aligned_size);
|
||||
}
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <filesystem>
|
||||
#include <set>
|
||||
#include <fmt/core.h>
|
||||
|
||||
|
@ -62,8 +63,13 @@ Emulator::~Emulator() {
|
|||
Config::saveMainWindow(config_dir / "config.toml");
|
||||
}
|
||||
|
||||
void Emulator::Run(const std::filesystem::path& file, const std::vector<std::string> args) {
|
||||
void Emulator::Run(std::filesystem::path file, const std::vector<std::string> args) {
|
||||
if (std::filesystem::is_directory(file)) {
|
||||
file /= "eboot.bin";
|
||||
}
|
||||
|
||||
const auto eboot_name = file.filename().string();
|
||||
|
||||
auto game_folder = file.parent_path();
|
||||
if (const auto game_folder_name = game_folder.filename().string();
|
||||
game_folder_name.ends_with("-UPDATE") || game_folder_name.ends_with("-patch")) {
|
||||
|
@ -114,6 +120,11 @@ void Emulator::Run(const std::filesystem::path& file, const std::vector<std::str
|
|||
Common::Log::Initialize();
|
||||
}
|
||||
Common::Log::Start();
|
||||
if (!std::filesystem::exists(file)) {
|
||||
LOG_CRITICAL(Loader, "eboot.bin does not exist: {}",
|
||||
std::filesystem::absolute(file).string());
|
||||
std::quick_exit(0);
|
||||
}
|
||||
|
||||
LOG_INFO(Loader, "Starting shadps4 emulator v{} ", Common::g_version);
|
||||
LOG_INFO(Loader, "Revision {}", Common::g_scm_rev);
|
||||
|
@ -194,15 +205,7 @@ void Emulator::Run(const std::filesystem::path& file, const std::vector<std::str
|
|||
std::string game_title = fmt::format("{} - {} <{}>", id, title, app_version);
|
||||
std::string window_title = "";
|
||||
std::string remote_url(Common::g_scm_remote_url);
|
||||
std::string remote_host;
|
||||
try {
|
||||
if (*remote_url.rbegin() == '/') {
|
||||
remote_url.pop_back();
|
||||
}
|
||||
remote_host = remote_url.substr(19, remote_url.rfind('/') - 19);
|
||||
} catch (...) {
|
||||
remote_host = "unknown";
|
||||
}
|
||||
std::string remote_host = Common::GetRemoteNameFromLink();
|
||||
if (Common::g_is_release) {
|
||||
if (remote_host == "shadps4-emu" || remote_url.length() == 0) {
|
||||
window_title = fmt::format("shadPS4 v{} | {}", Common::g_version, game_title);
|
||||
|
@ -258,7 +261,11 @@ void Emulator::Run(const std::filesystem::path& file, const std::vector<std::str
|
|||
|
||||
// Load the module with the linker
|
||||
const auto eboot_path = mnt->GetHostPath("/app0/" + eboot_name);
|
||||
linker->LoadModule(eboot_path);
|
||||
if (linker->LoadModule(eboot_path) == -1) {
|
||||
LOG_CRITICAL(Loader, "Failed to load game's eboot.bin: {}",
|
||||
std::filesystem::absolute(eboot_path).string());
|
||||
std::quick_exit(0);
|
||||
}
|
||||
|
||||
// check if we have system modules to load
|
||||
LoadSystemModules(game_info.game_serial);
|
||||
|
|
|
@ -25,7 +25,7 @@ public:
|
|||
Emulator();
|
||||
~Emulator();
|
||||
|
||||
void Run(const std::filesystem::path& file, const std::vector<std::string> args = {});
|
||||
void Run(std::filesystem::path file, const std::vector<std::string> args = {});
|
||||
void UpdatePlayTime(const std::string& serial);
|
||||
|
||||
private:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
@ -165,69 +165,37 @@ void GameController::Acceleration(int id, const float acceleration[3]) {
|
|||
AddState(state);
|
||||
}
|
||||
|
||||
// Stolen from
|
||||
// https://github.com/xioTechnologies/Open-Source-AHRS-With-x-IMU/blob/master/x-IMU%20IMU%20and%20AHRS%20Algorithms/x-IMU%20IMU%20and%20AHRS%20Algorithms/AHRS/MahonyAHRS.cs
|
||||
float eInt[3] = {0.0f, 0.0f, 0.0f}; // Integral error terms
|
||||
const float Kp = 50.0f; // Proportional gain
|
||||
const float Ki = 1.0f; // Integral gain
|
||||
Libraries::Pad::OrbisFQuaternion o = {1, 0, 0, 0};
|
||||
void GameController::CalculateOrientation(Libraries::Pad::OrbisFVector3& acceleration,
|
||||
Libraries::Pad::OrbisFVector3& angularVelocity,
|
||||
float deltaTime,
|
||||
Libraries::Pad::OrbisFQuaternion& lastOrientation,
|
||||
Libraries::Pad::OrbisFQuaternion& orientation) {
|
||||
float ax = acceleration.x, ay = acceleration.y, az = acceleration.z;
|
||||
float gx = angularVelocity.x, gy = angularVelocity.y, gz = angularVelocity.z;
|
||||
Libraries::Pad::OrbisFQuaternion q = lastOrientation;
|
||||
Libraries::Pad::OrbisFQuaternion ω = {angularVelocity.x, angularVelocity.y, angularVelocity.z,
|
||||
0.0f};
|
||||
|
||||
float q1 = o.w, q2 = o.x, q3 = o.y, q4 = o.z;
|
||||
Libraries::Pad::OrbisFQuaternion qω = {q.w * ω.x + q.x * ω.w + q.y * ω.z - q.z * ω.y,
|
||||
q.w * ω.y + q.y * ω.w + q.z * ω.x - q.x * ω.z,
|
||||
q.w * ω.z + q.z * ω.w + q.x * ω.y - q.y * ω.x,
|
||||
q.w * ω.w - q.x * ω.x - q.y * ω.y - q.z * ω.z};
|
||||
|
||||
// Normalize accelerometer measurement
|
||||
float norm = std::sqrt(ax * ax + ay * ay + az * az);
|
||||
if (norm == 0.0f || deltaTime == 0.0f)
|
||||
return; // Handle NaN
|
||||
norm = 1.0f / norm;
|
||||
ax *= norm;
|
||||
ay *= norm;
|
||||
az *= norm;
|
||||
Libraries::Pad::OrbisFQuaternion qDot = {0.5f * qω.x, 0.5f * qω.y, 0.5f * qω.z, 0.5f * qω.w};
|
||||
|
||||
// Estimated direction of gravity
|
||||
float vx = 2.0f * (q2 * q4 - q1 * q3);
|
||||
float vy = 2.0f * (q1 * q2 + q3 * q4);
|
||||
float vz = q1 * q1 - q2 * q2 - q3 * q3 + q4 * q4;
|
||||
q.x += qDot.x * deltaTime;
|
||||
q.y += qDot.y * deltaTime;
|
||||
q.z += qDot.z * deltaTime;
|
||||
q.w += qDot.w * deltaTime;
|
||||
|
||||
// Error is cross product between estimated direction and measured direction of gravity
|
||||
float ex = (ay * vz - az * vy);
|
||||
float ey = (az * vx - ax * vz);
|
||||
float ez = (ax * vy - ay * vx);
|
||||
if (Ki > 0.0f) {
|
||||
eInt[0] += ex * deltaTime; // Accumulate integral error
|
||||
eInt[1] += ey * deltaTime;
|
||||
eInt[2] += ez * deltaTime;
|
||||
} else {
|
||||
eInt[0] = eInt[1] = eInt[2] = 0.0f; // Prevent integral wind-up
|
||||
}
|
||||
float norm = std::sqrt(q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w);
|
||||
q.x /= norm;
|
||||
q.y /= norm;
|
||||
q.z /= norm;
|
||||
q.w /= norm;
|
||||
|
||||
// Apply feedback terms
|
||||
gx += Kp * ex + Ki * eInt[0];
|
||||
gy += Kp * ey + Ki * eInt[1];
|
||||
gz += Kp * ez + Ki * eInt[2];
|
||||
|
||||
//// Integrate rate of change of quaternion
|
||||
q1 += (-q2 * gx - q3 * gy - q4 * gz) * (0.5f * deltaTime);
|
||||
q2 += (q1 * gx + q3 * gz - q4 * gy) * (0.5f * deltaTime);
|
||||
q3 += (q1 * gy - q2 * gz + q4 * gx) * (0.5f * deltaTime);
|
||||
q4 += (q1 * gz + q2 * gy - q3 * gx) * (0.5f * deltaTime);
|
||||
|
||||
// Normalize quaternion
|
||||
norm = std::sqrt(q1 * q1 + q2 * q2 + q3 * q3 + q4 * q4);
|
||||
norm = 1.0f / norm;
|
||||
orientation.w = q1 * norm;
|
||||
orientation.x = q2 * norm;
|
||||
orientation.y = q3 * norm;
|
||||
orientation.z = q4 * norm;
|
||||
o.w = q1 * norm;
|
||||
o.x = q2 * norm;
|
||||
o.y = q3 * norm;
|
||||
o.z = q4 * norm;
|
||||
orientation.x = q.x;
|
||||
orientation.y = q.y;
|
||||
orientation.z = q.z;
|
||||
orientation.w = q.w;
|
||||
LOG_DEBUG(Lib_Pad, "Calculated orientation: {:.2f} {:.2f} {:.2f} {:.2f}", orientation.x,
|
||||
orientation.y, orientation.z, orientation.w);
|
||||
}
|
||||
|
@ -260,6 +228,69 @@ void GameController::SetTouchpadState(int touchIndex, bool touchDown, float x, f
|
|||
}
|
||||
}
|
||||
|
||||
u8 GameController::GetTouchCount() {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
return m_touch_count;
|
||||
}
|
||||
|
||||
void GameController::SetTouchCount(u8 touchCount) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
m_touch_count = touchCount;
|
||||
}
|
||||
|
||||
u8 GameController::GetSecondaryTouchCount() {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
return m_secondary_touch_count;
|
||||
}
|
||||
|
||||
void GameController::SetSecondaryTouchCount(u8 touchCount) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
m_secondary_touch_count = touchCount;
|
||||
if (touchCount == 0) {
|
||||
m_was_secondary_reset = true;
|
||||
}
|
||||
}
|
||||
|
||||
u8 GameController::GetPreviousTouchNum() {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
return m_previous_touchnum;
|
||||
}
|
||||
|
||||
void GameController::SetPreviousTouchNum(u8 touchNum) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
m_previous_touchnum = touchNum;
|
||||
}
|
||||
|
||||
bool GameController::WasSecondaryTouchReset() {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
return m_was_secondary_reset;
|
||||
}
|
||||
|
||||
void GameController::UnsetSecondaryTouchResetBool() {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
m_was_secondary_reset = false;
|
||||
}
|
||||
|
||||
void GameController::SetLastOrientation(Libraries::Pad::OrbisFQuaternion& orientation) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
m_orientation = orientation;
|
||||
}
|
||||
|
||||
Libraries::Pad::OrbisFQuaternion GameController::GetLastOrientation() {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
return m_orientation;
|
||||
}
|
||||
|
||||
std::chrono::steady_clock::time_point GameController::GetLastUpdate() {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
return m_last_update;
|
||||
}
|
||||
|
||||
void GameController::SetLastUpdate(std::chrono::steady_clock::time_point lastUpdate) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
m_last_update = lastUpdate;
|
||||
}
|
||||
|
||||
void GameController::SetEngine(std::unique_ptr<Engine> engine) {
|
||||
std::scoped_lock _{m_mutex};
|
||||
m_engine = std::move(engine);
|
||||
|
|
|
@ -23,6 +23,7 @@ enum class Axis {
|
|||
};
|
||||
|
||||
struct TouchpadEntry {
|
||||
u8 ID = 0;
|
||||
bool state{};
|
||||
u16 x{};
|
||||
u16 y{};
|
||||
|
@ -82,9 +83,23 @@ public:
|
|||
Engine* GetEngine();
|
||||
u32 Poll();
|
||||
|
||||
u8 GetTouchCount();
|
||||
void SetTouchCount(u8 touchCount);
|
||||
u8 GetSecondaryTouchCount();
|
||||
void SetSecondaryTouchCount(u8 touchCount);
|
||||
u8 GetPreviousTouchNum();
|
||||
void SetPreviousTouchNum(u8 touchNum);
|
||||
bool WasSecondaryTouchReset();
|
||||
void UnsetSecondaryTouchResetBool();
|
||||
|
||||
void SetLastOrientation(Libraries::Pad::OrbisFQuaternion& orientation);
|
||||
Libraries::Pad::OrbisFQuaternion GetLastOrientation();
|
||||
std::chrono::steady_clock::time_point GetLastUpdate();
|
||||
void SetLastUpdate(std::chrono::steady_clock::time_point lastUpdate);
|
||||
static void CalculateOrientation(Libraries::Pad::OrbisFVector3& acceleration,
|
||||
Libraries::Pad::OrbisFVector3& angularVelocity,
|
||||
float deltaTime,
|
||||
Libraries::Pad::OrbisFQuaternion& lastOrientation,
|
||||
Libraries::Pad::OrbisFQuaternion& orientation);
|
||||
|
||||
private:
|
||||
|
@ -98,8 +113,15 @@ private:
|
|||
int m_connected_count = 0;
|
||||
u32 m_states_num = 0;
|
||||
u32 m_first_state = 0;
|
||||
u8 m_touch_count = 0;
|
||||
u8 m_secondary_touch_count = 0;
|
||||
u8 m_previous_touch_count = 0;
|
||||
u8 m_previous_touchnum = 0;
|
||||
bool m_was_secondary_reset = false;
|
||||
std::array<State, MAX_STATES> m_states;
|
||||
std::array<StateInternal, MAX_STATES> m_private;
|
||||
std::chrono::steady_clock::time_point m_last_update = {};
|
||||
Libraries::Pad::OrbisFQuaternion m_orientation = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||
|
||||
std::unique_ptr<Engine> m_engine = nullptr;
|
||||
};
|
||||
|
|
|
@ -56,15 +56,7 @@ bool MainWindow::Init() {
|
|||
setMinimumSize(720, 405);
|
||||
std::string window_title = "";
|
||||
std::string remote_url(Common::g_scm_remote_url);
|
||||
std::string remote_host;
|
||||
try {
|
||||
if (*remote_url.rbegin() == '/') {
|
||||
remote_url.pop_back();
|
||||
}
|
||||
remote_host = remote_url.substr(19, remote_url.rfind('/') - 19);
|
||||
} catch (...) {
|
||||
remote_host = "unknown";
|
||||
}
|
||||
std::string remote_host = Common::GetRemoteNameFromLink();
|
||||
if (Common::g_is_release) {
|
||||
if (remote_host == "shadps4-emu" || remote_url.length() == 0) {
|
||||
window_title = fmt::format("shadPS4 v{}", Common::g_version);
|
||||
|
@ -380,16 +372,15 @@ void MainWindow::CreateConnects() {
|
|||
connect(ui->refreshGameListAct, &QAction::triggered, this, &MainWindow::RefreshGameTable);
|
||||
connect(ui->refreshButton, &QPushButton::clicked, this, &MainWindow::RefreshGameTable);
|
||||
connect(ui->showGameListAct, &QAction::triggered, this, &MainWindow::ShowGameList);
|
||||
connect(this, &MainWindow::ExtractionFinished, this, &MainWindow::RefreshGameTable);
|
||||
connect(ui->toggleLabelsAct, &QAction::toggled, this, &MainWindow::toggleLabelsUnderIcons);
|
||||
connect(ui->fullscreenButton, &QPushButton::clicked, this, &MainWindow::toggleFullscreen);
|
||||
|
||||
connect(ui->sizeSlider, &QSlider::valueChanged, this, [this](int value) {
|
||||
if (isTableList) {
|
||||
m_game_list_frame->icon_size =
|
||||
36 + value; // 36 is the minimum icon size to use due to text disappearing.
|
||||
m_game_list_frame->ResizeIcons(36 + value);
|
||||
Config::setIconSize(36 + value);
|
||||
48 + value; // 48 is the minimum icon size to use due to text disappearing.
|
||||
m_game_list_frame->ResizeIcons(48 + value);
|
||||
Config::setIconSize(48 + value);
|
||||
Config::setSliderPosition(value);
|
||||
} else {
|
||||
m_game_grid_frame->icon_size = 69 + value;
|
||||
|
|
|
@ -29,7 +29,6 @@ class MainWindow : public QMainWindow {
|
|||
Q_OBJECT
|
||||
signals:
|
||||
void WindowResized(QResizeEvent* event);
|
||||
void ExtractionFinished();
|
||||
|
||||
public:
|
||||
explicit MainWindow(QWidget* parent = nullptr);
|
||||
|
|
|
@ -608,6 +608,16 @@ struct Liverpool {
|
|||
}
|
||||
};
|
||||
|
||||
struct BorderColorBufferBase {
|
||||
u32 base_addr_lo;
|
||||
BitField<0, 8, u32> base_addr_hi;
|
||||
|
||||
template <typename T = VAddr>
|
||||
T Address() const {
|
||||
return std::bit_cast<T>(u64(base_addr_hi) << 40 | u64(base_addr_lo) << 8);
|
||||
}
|
||||
};
|
||||
|
||||
struct IndexBufferBase {
|
||||
BitField<0, 8, u32> base_addr_hi;
|
||||
u32 base_addr_lo;
|
||||
|
@ -1299,7 +1309,9 @@ struct Liverpool {
|
|||
Scissor screen_scissor;
|
||||
INSERT_PADDING_WORDS(0xA010 - 0xA00C - 2);
|
||||
DepthBuffer depth_buffer;
|
||||
INSERT_PADDING_WORDS(0xA080 - 0xA018);
|
||||
INSERT_PADDING_WORDS(8);
|
||||
BorderColorBufferBase ta_bc_base;
|
||||
INSERT_PADDING_WORDS(0xA080 - 0xA020 - 2);
|
||||
WindowOffset window_offset;
|
||||
ViewportScissor window_scissor;
|
||||
INSERT_PADDING_WORDS(0xA08E - 0xA081 - 2);
|
||||
|
@ -1626,6 +1638,7 @@ static_assert(GFX6_3D_REG_INDEX(depth_htile_data_base) == 0xA005);
|
|||
static_assert(GFX6_3D_REG_INDEX(screen_scissor) == 0xA00C);
|
||||
static_assert(GFX6_3D_REG_INDEX(depth_buffer.z_info) == 0xA010);
|
||||
static_assert(GFX6_3D_REG_INDEX(depth_buffer.depth_slice) == 0xA017);
|
||||
static_assert(GFX6_3D_REG_INDEX(ta_bc_base) == 0xA020);
|
||||
static_assert(GFX6_3D_REG_INDEX(window_offset) == 0xA080);
|
||||
static_assert(GFX6_3D_REG_INDEX(window_scissor) == 0xA081);
|
||||
static_assert(GFX6_3D_REG_INDEX(color_target_mask) == 0xA08E);
|
||||
|
|
|
@ -716,7 +716,7 @@ void Rasterizer::BindTextures(const Shader::Info& stage, Shader::Backend::Bindin
|
|||
ssharp.max_aniso.Assign(AmdGpu::AnisoRatio::One);
|
||||
}
|
||||
}
|
||||
const auto vk_sampler = texture_cache.GetSampler(ssharp);
|
||||
const auto vk_sampler = texture_cache.GetSampler(ssharp, liverpool->regs.ta_bc_base);
|
||||
image_infos.emplace_back(vk_sampler, VK_NULL_HANDLE, vk::ImageLayout::eGeneral);
|
||||
set_writes.push_back({
|
||||
.dstSet = VK_NULL_HANDLE,
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
|
||||
namespace VideoCore {
|
||||
|
||||
Sampler::Sampler(const Vulkan::Instance& instance, const AmdGpu::Sampler& sampler) {
|
||||
Sampler::Sampler(const Vulkan::Instance& instance, const AmdGpu::Sampler& sampler,
|
||||
const AmdGpu::Liverpool::BorderColorBufferBase& border_color_base) {
|
||||
if (sampler.force_degamma) {
|
||||
LOG_WARNING(Render_Vulkan, "Texture requires gamma correction");
|
||||
}
|
||||
|
@ -20,7 +21,33 @@ Sampler::Sampler(const Vulkan::Instance& instance, const AmdGpu::Sampler& sample
|
|||
const float maxAnisotropy =
|
||||
anisotropyEnable ? std::clamp(sampler.MaxAniso(), 1.0f, instance.MaxSamplerAnisotropy())
|
||||
: 1.0f;
|
||||
auto borderColor = LiverpoolToVK::BorderColor(sampler.border_color_type);
|
||||
if (!instance.IsCustomBorderColorSupported()) {
|
||||
LOG_WARNING(Render_Vulkan, "Custom border color is not supported, falling back to black");
|
||||
borderColor = vk::BorderColor::eFloatOpaqueBlack;
|
||||
}
|
||||
|
||||
const auto customColor = [&]() -> std::optional<vk::SamplerCustomBorderColorCreateInfoEXT> {
|
||||
if (borderColor == vk::BorderColor::eFloatCustomEXT) {
|
||||
const auto borderColorIndex = sampler.border_color_ptr.Value();
|
||||
const auto borderColorBuffer = border_color_base.Address<std::array<float, 4>*>();
|
||||
const auto customBorderColorArray = borderColorBuffer[borderColorIndex];
|
||||
|
||||
const vk::SamplerCustomBorderColorCreateInfoEXT ret{
|
||||
.customBorderColor =
|
||||
vk::ClearColorValue{
|
||||
.float32 = customBorderColorArray,
|
||||
},
|
||||
.format = vk::Format::eR32G32B32A32Sfloat,
|
||||
};
|
||||
return ret;
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}();
|
||||
|
||||
const vk::SamplerCreateInfo sampler_ci = {
|
||||
.pNext = customColor ? &*customColor : nullptr,
|
||||
.magFilter = LiverpoolToVK::Filter(sampler.xy_mag_filter),
|
||||
.minFilter = LiverpoolToVK::Filter(sampler.xy_min_filter),
|
||||
.mipmapMode = LiverpoolToVK::MipFilter(sampler.mip_filter),
|
||||
|
@ -34,7 +61,7 @@ Sampler::Sampler(const Vulkan::Instance& instance, const AmdGpu::Sampler& sample
|
|||
.compareOp = LiverpoolToVK::DepthCompare(sampler.depth_compare_func),
|
||||
.minLod = sampler.MinLod(),
|
||||
.maxLod = sampler.MaxLod(),
|
||||
.borderColor = LiverpoolToVK::BorderColor(sampler.border_color_type),
|
||||
.borderColor = borderColor,
|
||||
.unnormalizedCoordinates = false, // Handled in shader due to Vulkan limitations.
|
||||
};
|
||||
auto [sampler_result, smplr] = instance.GetDevice().createSamplerUnique(sampler_ci);
|
||||
|
|
|
@ -14,7 +14,8 @@ namespace VideoCore {
|
|||
|
||||
class Sampler {
|
||||
public:
|
||||
explicit Sampler(const Vulkan::Instance& instance, const AmdGpu::Sampler& sampler);
|
||||
explicit Sampler(const Vulkan::Instance& instance, const AmdGpu::Sampler& sampler,
|
||||
const AmdGpu::Liverpool::BorderColorBufferBase& border_color_base);
|
||||
~Sampler();
|
||||
|
||||
Sampler(const Sampler&) = delete;
|
||||
|
|
|
@ -636,9 +636,11 @@ void TextureCache::RefreshImage(Image& image, Vulkan::Scheduler* custom_schedule
|
|||
image.flags &= ~ImageFlagBits::Dirty;
|
||||
}
|
||||
|
||||
vk::Sampler TextureCache::GetSampler(const AmdGpu::Sampler& sampler) {
|
||||
vk::Sampler TextureCache::GetSampler(
|
||||
const AmdGpu::Sampler& sampler,
|
||||
const AmdGpu::Liverpool::BorderColorBufferBase& border_color_base) {
|
||||
const u64 hash = XXH3_64bits(&sampler, sizeof(sampler));
|
||||
const auto [it, new_sampler] = samplers.try_emplace(hash, instance, sampler);
|
||||
const auto [it, new_sampler] = samplers.try_emplace(hash, instance, sampler, border_color_base);
|
||||
return it->second.Handle();
|
||||
}
|
||||
|
||||
|
|
|
@ -139,7 +139,9 @@ public:
|
|||
void RefreshImage(Image& image, Vulkan::Scheduler* custom_scheduler = nullptr);
|
||||
|
||||
/// Retrieves the sampler that matches the provided S# descriptor.
|
||||
[[nodiscard]] vk::Sampler GetSampler(const AmdGpu::Sampler& sampler);
|
||||
[[nodiscard]] vk::Sampler GetSampler(
|
||||
const AmdGpu::Sampler& sampler,
|
||||
const AmdGpu::Liverpool::BorderColorBufferBase& border_color_base);
|
||||
|
||||
/// Retrieves the image with the specified id.
|
||||
[[nodiscard]] Image& GetImage(ImageId id) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue