mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-12-16 12:09:07 +00:00
Merge branch 'shadps4-emu:main' into rdr2-test
This commit is contained in:
commit
d7883108a3
@ -1310,6 +1310,7 @@ hotkey_pause = f9
|
||||
hotkey_reload_inputs = f8
|
||||
hotkey_toggle_mouse_to_joystick = f7
|
||||
hotkey_toggle_mouse_to_gyro = f6
|
||||
hotkey_toggle_mouse_to_touchpad = delete
|
||||
hotkey_quit = lctrl, lshift, end
|
||||
)";
|
||||
}
|
||||
|
||||
@ -6,8 +6,8 @@
|
||||
#include "common/elf_info.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/libraries/fiber/fiber_error.h"
|
||||
#include "core/libraries/kernel/threads/pthread.h"
|
||||
#include "core/libraries/libs.h"
|
||||
#include "core/tls.h"
|
||||
|
||||
namespace Libraries::Fiber {
|
||||
|
||||
@ -20,7 +20,7 @@ static constexpr u64 kFiberStackSizeCheck = 0xdeadbeefdeadbeef;
|
||||
static std::atomic<u32> context_size_check = false;
|
||||
|
||||
OrbisFiberContext* GetFiberContext() {
|
||||
return Libraries::Kernel::g_curthread->tcb->tcb_fiber;
|
||||
return Core::GetTcbBase()->tcb_fiber;
|
||||
}
|
||||
|
||||
extern "C" s32 PS4_SYSV_ABI _sceFiberSetJmp(OrbisFiberContext* ctx) asm("_sceFiberSetJmp");
|
||||
@ -269,7 +269,7 @@ s32 PS4_SYSV_ABI sceFiberRunImpl(OrbisFiber* fiber, void* addr_context, u64 size
|
||||
return ORBIS_FIBER_ERROR_INVALID;
|
||||
}
|
||||
|
||||
Core::Tcb* tcb = Libraries::Kernel::g_curthread->tcb;
|
||||
Core::Tcb* tcb = Core::GetTcbBase();
|
||||
if (tcb->tcb_fiber) {
|
||||
return ORBIS_FIBER_ERROR_PERMISSION;
|
||||
}
|
||||
|
||||
@ -42,6 +42,16 @@ s32 PS4_SYSV_ABI sceKernelGetCompiledSdkVersion(s32* ver) {
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelGetCpumode() {
|
||||
LOG_DEBUG(Lib_Kernel, "called");
|
||||
auto& attrs = Common::ElfInfo::Instance().GetPSFAttributes();
|
||||
u32 is_cpu6 = attrs.six_cpu_mode.Value();
|
||||
u32 is_cpu7 = attrs.seven_cpu_mode.Value();
|
||||
if (is_cpu6 == 1 && is_cpu7 == 1) {
|
||||
return 2;
|
||||
}
|
||||
if (is_cpu7 == 1) {
|
||||
return 5;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -663,6 +663,10 @@ void RegisterThread(Core::Loader::SymbolsResolver* sym) {
|
||||
LIB_FUNCTION("Z4QosVuAsA0", "libkernel", 1, "libkernel", posix_pthread_once);
|
||||
LIB_FUNCTION("EotR8a3ASf4", "libkernel", 1, "libkernel", posix_pthread_self);
|
||||
LIB_FUNCTION("OxhIB8LB-PQ", "libkernel", 1, "libkernel", posix_pthread_create);
|
||||
LIB_FUNCTION("lZzFeSxPl08", "libkernel", 1, "libkernel", posix_pthread_setcancelstate);
|
||||
LIB_FUNCTION("CBNtXOoef-E", "libkernel", 1, "libkernel", posix_sched_get_priority_max);
|
||||
LIB_FUNCTION("m0iS6jNsXds", "libkernel", 1, "libkernel", posix_sched_get_priority_min);
|
||||
LIB_FUNCTION("Xs9hdiD7sAA", "libkernel", 1, "libkernel", posix_pthread_setschedparam);
|
||||
LIB_FUNCTION("+U1R4WtXvoc", "libkernel", 1, "libkernel", posix_pthread_detach);
|
||||
LIB_FUNCTION("7Xl257M4VNI", "libkernel", 1, "libkernel", posix_pthread_equal);
|
||||
LIB_FUNCTION("h9CcP3J0oVM", "libkernel", 1, "libkernel", posix_pthread_join);
|
||||
|
||||
@ -712,8 +712,61 @@ int PS4_SYSV_ABI sceHttpUriCopy() {
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceHttpUriEscape() {
|
||||
LOG_ERROR(Lib_Http, "(STUBBED) called");
|
||||
int PS4_SYSV_ABI sceHttpUriEscape(char* out, u64* require, u64 prepare, const char* in) {
|
||||
LOG_TRACE(Lib_Http, "called");
|
||||
|
||||
if (!in) {
|
||||
LOG_ERROR(Lib_Http, "Invalid input string");
|
||||
return ORBIS_HTTP_ERROR_INVALID_VALUE;
|
||||
}
|
||||
|
||||
auto IsUnreserved = [](unsigned char c) -> bool {
|
||||
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
|
||||
c == '-' || c == '_' || c == '.' || c == '~';
|
||||
};
|
||||
|
||||
u64 needed = 0;
|
||||
const char* src = in;
|
||||
while (*src) {
|
||||
unsigned char c = static_cast<unsigned char>(*src);
|
||||
if (IsUnreserved(c)) {
|
||||
needed++;
|
||||
} else {
|
||||
needed += 3; // %XX format
|
||||
}
|
||||
src++;
|
||||
}
|
||||
needed++; // null terminator
|
||||
|
||||
if (require) {
|
||||
*require = needed;
|
||||
}
|
||||
|
||||
if (!out) {
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
if (prepare < needed) {
|
||||
LOG_ERROR(Lib_Http, "Buffer too small: need {} but only {} available", needed, prepare);
|
||||
return ORBIS_HTTP_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
static const char hex_chars[] = "0123456789ABCDEF";
|
||||
src = in;
|
||||
char* dst = out;
|
||||
while (*src) {
|
||||
unsigned char c = static_cast<unsigned char>(*src);
|
||||
if (IsUnreserved(c)) {
|
||||
*dst++ = *src;
|
||||
} else {
|
||||
*dst++ = '%';
|
||||
*dst++ = hex_chars[(c >> 4) & 0x0F];
|
||||
*dst++ = hex_chars[c & 0x0F];
|
||||
}
|
||||
src++;
|
||||
}
|
||||
*dst = '\0';
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
@ -1072,12 +1125,163 @@ int PS4_SYSV_ABI sceHttpUriParse(OrbisHttpUriElement* out, const char* srcUri, v
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceHttpUriSweepPath(char* dst, const char* src, u64 srcSize) {
|
||||
LOG_ERROR(Lib_Http, "(STUBBED) called");
|
||||
LOG_TRACE(Lib_Http, "called");
|
||||
|
||||
if (!dst || !src) {
|
||||
LOG_ERROR(Lib_Http, "Invalid parameters");
|
||||
return ORBIS_HTTP_ERROR_INVALID_VALUE;
|
||||
}
|
||||
|
||||
if (srcSize == 0) {
|
||||
dst[0] = '\0';
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
u64 len = 0;
|
||||
while (len < srcSize && src[len] != '\0') {
|
||||
len++;
|
||||
}
|
||||
|
||||
for (u64 i = 0; i < len; i++) {
|
||||
dst[i] = src[i];
|
||||
}
|
||||
dst[len] = '\0';
|
||||
|
||||
char* read = dst;
|
||||
char* write = dst;
|
||||
|
||||
while (*read) {
|
||||
if (read[0] == '.' && read[1] == '.' && read[2] == '/') {
|
||||
read += 3;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (read[0] == '.' && read[1] == '/') {
|
||||
read += 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (read[0] == '/' && read[1] == '.' && read[2] == '/') {
|
||||
read += 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (read[0] == '/' && read[1] == '.' && read[2] == '\0') {
|
||||
if (write == dst) {
|
||||
*write++ = '/';
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
bool is_dotdot_mid = (read[0] == '/' && read[1] == '.' && read[2] == '.' && read[3] == '/');
|
||||
bool is_dotdot_end =
|
||||
(read[0] == '/' && read[1] == '.' && read[2] == '.' && read[3] == '\0');
|
||||
|
||||
if (is_dotdot_mid || is_dotdot_end) {
|
||||
if (write > dst) {
|
||||
if (*(write - 1) == '/') {
|
||||
write--;
|
||||
}
|
||||
while (write > dst && *(write - 1) != '/') {
|
||||
write--;
|
||||
}
|
||||
|
||||
if (is_dotdot_mid && write > dst) {
|
||||
write--;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_dotdot_mid) {
|
||||
read += 3;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((read[0] == '.' && read[1] == '\0') ||
|
||||
(read[0] == '.' && read[1] == '.' && read[2] == '\0')) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (read[0] == '/') {
|
||||
*write++ = *read++;
|
||||
}
|
||||
while (*read && *read != '/') {
|
||||
*write++ = *read++;
|
||||
}
|
||||
}
|
||||
|
||||
*write = '\0';
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceHttpUriUnescape(char* out, u64* require, u64 prepare, const char* in) {
|
||||
LOG_ERROR(Lib_Http, "(STUBBED) called");
|
||||
LOG_TRACE(Lib_Http, "called");
|
||||
|
||||
if (!in) {
|
||||
LOG_ERROR(Lib_Http, "Invalid input string");
|
||||
return ORBIS_HTTP_ERROR_INVALID_VALUE;
|
||||
}
|
||||
|
||||
// Locale-independent hex digit check
|
||||
auto IsHex = [](char c) -> bool {
|
||||
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
|
||||
};
|
||||
|
||||
// Convert hex char to int value
|
||||
auto HexToInt = [](char c) -> int {
|
||||
if (c >= '0' && c <= '9')
|
||||
return c - '0';
|
||||
if (c >= 'A' && c <= 'F')
|
||||
return c - 'A' + 10;
|
||||
if (c >= 'a' && c <= 'f')
|
||||
return c - 'a' + 10;
|
||||
return 0;
|
||||
};
|
||||
|
||||
// Check for valid percent-encoded sequence (%XX)
|
||||
auto IsValidPercentSequence = [&](const char* s) -> bool {
|
||||
return s[0] == '%' && s[1] != '\0' && s[2] != '\0' && IsHex(s[1]) && IsHex(s[2]);
|
||||
};
|
||||
|
||||
u64 needed = 0;
|
||||
const char* src = in;
|
||||
while (*src) {
|
||||
if (IsValidPercentSequence(src)) {
|
||||
src += 3;
|
||||
} else {
|
||||
src++;
|
||||
}
|
||||
needed++;
|
||||
}
|
||||
needed++; // null terminator
|
||||
|
||||
if (require) {
|
||||
*require = needed;
|
||||
}
|
||||
|
||||
if (!out) {
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
if (prepare < needed) {
|
||||
LOG_ERROR(Lib_Http, "Buffer too small: need {} but only {} available", needed, prepare);
|
||||
return ORBIS_HTTP_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
src = in;
|
||||
char* dst = out;
|
||||
while (*src) {
|
||||
if (IsValidPercentSequence(src)) {
|
||||
*dst++ = static_cast<char>((HexToInt(src[1]) << 4) | HexToInt(src[2]));
|
||||
src += 3;
|
||||
} else {
|
||||
*dst++ = *src++;
|
||||
}
|
||||
}
|
||||
*dst = '\0';
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
||||
@ -148,7 +148,7 @@ int PS4_SYSV_ABI sceHttpUnsetEpoll();
|
||||
int PS4_SYSV_ABI sceHttpUriBuild(char* out, u64* require, u64 prepare,
|
||||
const OrbisHttpUriElement* srcElement, u32 option);
|
||||
int PS4_SYSV_ABI sceHttpUriCopy();
|
||||
int PS4_SYSV_ABI sceHttpUriEscape();
|
||||
int PS4_SYSV_ABI sceHttpUriEscape(char* out, u64* require, u64 prepare, const char* in);
|
||||
int PS4_SYSV_ABI sceHttpUriMerge(char* mergedUrl, char* url, char* relativeUri, u64* require,
|
||||
u64 prepare, u32 option);
|
||||
int PS4_SYSV_ABI sceHttpUriParse(OrbisHttpUriElement* out, const char* srcUri, void* pool,
|
||||
|
||||
@ -4,46 +4,87 @@
|
||||
#include "common/logging/log.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/libs.h"
|
||||
#include "core/libraries/system/commondialog.h"
|
||||
|
||||
namespace Libraries::Np::NpCommerce {
|
||||
|
||||
using CommonDialog::Error;
|
||||
using CommonDialog::Result;
|
||||
using CommonDialog::Status;
|
||||
|
||||
static Status g_dialog_status = Status::NONE;
|
||||
static Result g_dialog_result = Result::OK;
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpCommerceDialogClose() {
|
||||
LOG_ERROR(Lib_NpCommerce, "(STUBBED) called");
|
||||
LOG_INFO(Lib_NpCommerce, "called");
|
||||
if (g_dialog_status == Status::NONE) {
|
||||
return static_cast<s32>(Error::NOT_INITIALIZED);
|
||||
}
|
||||
if (g_dialog_status != Status::FINISHED) {
|
||||
return static_cast<s32>(Error::NOT_FINISHED);
|
||||
}
|
||||
g_dialog_status = Status::INITIALIZED;
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpCommerceDialogGetResult(s32* result) {
|
||||
LOG_ERROR(Lib_NpCommerce, "(STUBBED) called");
|
||||
LOG_INFO(Lib_NpCommerce, "called");
|
||||
if (result == nullptr) {
|
||||
return static_cast<s32>(Error::ARG_NULL);
|
||||
}
|
||||
if (g_dialog_status != Status::FINISHED) {
|
||||
return static_cast<s32>(Error::NOT_FINISHED);
|
||||
}
|
||||
*result = static_cast<s32>(g_dialog_result);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s8 PS4_SYSV_ABI sceNpCommerceDialogGetStatus() {
|
||||
LOG_ERROR(Lib_NpCommerce, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
LOG_DEBUG(Lib_NpCommerce, "called, status = {}", static_cast<u32>(g_dialog_status));
|
||||
return static_cast<s8>(g_dialog_status);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpCommerceDialogInitialize() {
|
||||
LOG_ERROR(Lib_NpCommerce, "(STUBBED) called");
|
||||
LOG_INFO(Lib_NpCommerce, "called");
|
||||
if (g_dialog_status != Status::NONE) {
|
||||
return static_cast<s32>(Error::ALREADY_INITIALIZED);
|
||||
}
|
||||
g_dialog_status = Status::INITIALIZED;
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpCommerceDialogInitializeInternal() {
|
||||
LOG_ERROR(Lib_NpCommerce, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
LOG_INFO(Lib_NpCommerce, "called");
|
||||
return sceNpCommerceDialogInitialize();
|
||||
}
|
||||
|
||||
s16 PS4_SYSV_ABI sceNpCommerceDialogOpen(s64 check) {
|
||||
LOG_ERROR(Lib_NpCommerce, "(STUBBED) called");
|
||||
LOG_INFO(Lib_NpCommerce, "called, check = {}", check);
|
||||
if (g_dialog_status != Status::INITIALIZED) {
|
||||
LOG_WARNING(Lib_NpCommerce, "Dialog not initialized");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
g_dialog_status = Status::FINISHED;
|
||||
g_dialog_result = Result::USER_CANCELED;
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpCommerceDialogTerminate() {
|
||||
LOG_ERROR(Lib_NpCommerce, "(STUBBED) called");
|
||||
LOG_INFO(Lib_NpCommerce, "called");
|
||||
if (g_dialog_status == Status::NONE) {
|
||||
return static_cast<s32>(Error::NOT_INITIALIZED);
|
||||
}
|
||||
if (g_dialog_status == Status::RUNNING) {
|
||||
return static_cast<s32>(Error::NOT_FINISHED);
|
||||
}
|
||||
g_dialog_status = Status::NONE;
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpCommerceDialogUpdateStatus() {
|
||||
LOG_ERROR(Lib_NpCommerce, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
LOG_DEBUG(Lib_NpCommerce, "called, status = {}", static_cast<u32>(g_dialog_status));
|
||||
return static_cast<s32>(g_dialog_status);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpCommerceHidePsStoreIcon() {
|
||||
|
||||
@ -368,7 +368,7 @@ bool Linker::Resolve(const std::string& name, Loader::SymbolType sym_type, Modul
|
||||
void* Linker::TlsGetAddr(u64 module_index, u64 offset) {
|
||||
std::scoped_lock lk{mutex};
|
||||
|
||||
DtvEntry* dtv_table = Libraries::Kernel::g_curthread->tcb->tcb_dtv;
|
||||
DtvEntry* dtv_table = GetTcbBase()->tcb_dtv;
|
||||
if (dtv_table[0].counter != dtv_generation_counter) {
|
||||
// Generation counter changed, a dynamic module was either loaded or unloaded.
|
||||
const u32 old_num_dtvs = dtv_table[1].counter;
|
||||
@ -381,7 +381,7 @@ void* Linker::TlsGetAddr(u64 module_index, u64 offset) {
|
||||
delete[] dtv_table;
|
||||
|
||||
// Update TCB pointer.
|
||||
Libraries::Kernel::g_curthread->tcb->tcb_dtv = new_dtv_table;
|
||||
GetTcbBase()->tcb_dtv = new_dtv_table;
|
||||
dtv_table = new_dtv_table;
|
||||
}
|
||||
|
||||
|
||||
@ -46,6 +46,10 @@ void SetTcbBase(void* image_address) {
|
||||
ASSERT(result != 0);
|
||||
}
|
||||
|
||||
Tcb* GetTcbBase() {
|
||||
return reinterpret_cast<Tcb*>(TlsGetValue(GetTcbKey()));
|
||||
}
|
||||
|
||||
#elif defined(__APPLE__) && defined(ARCH_X86_64)
|
||||
|
||||
// Apple x86_64
|
||||
@ -145,6 +149,12 @@ void SetTcbBase(void* image_address) {
|
||||
"Failed to store thread LDT page pointer: {}", errno);
|
||||
}
|
||||
|
||||
Tcb* GetTcbBase() {
|
||||
Tcb* tcb;
|
||||
asm volatile("mov %%fs:0x0, %0" : "=r"(tcb));
|
||||
return tcb;
|
||||
}
|
||||
|
||||
#elif defined(ARCH_X86_64)
|
||||
|
||||
// Other POSIX x86_64
|
||||
@ -154,6 +164,10 @@ void SetTcbBase(void* image_address) {
|
||||
ASSERT_MSG(ret == 0, "Failed to set GS base: errno {}", errno);
|
||||
}
|
||||
|
||||
Tcb* GetTcbBase() {
|
||||
return Libraries::Kernel::g_curthread->tcb;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// POSIX non-x86_64
|
||||
@ -176,6 +190,10 @@ void SetTcbBase(void* image_address) {
|
||||
ASSERT(pthread_setspecific(GetTcbKey(), image_address) == 0);
|
||||
}
|
||||
|
||||
Tcb* GetTcbBase() {
|
||||
return static_cast<Tcb*>(pthread_getspecific(GetTcbKey()));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
thread_local std::once_flag init_tls_flag;
|
||||
|
||||
@ -39,6 +39,9 @@ u32 GetTcbKey();
|
||||
/// Sets the data pointer to the TCB block.
|
||||
void SetTcbBase(void* image_address);
|
||||
|
||||
/// Retrieves Tcb structure for the calling thread.
|
||||
Tcb* GetTcbBase();
|
||||
|
||||
/// Makes sure TLS is initialized for the thread before entering guest.
|
||||
void EnsureThreadInitialized();
|
||||
|
||||
|
||||
@ -106,6 +106,7 @@ auto output_array = std::array{
|
||||
ControllerOutput(HOTKEY_RELOAD_INPUTS),
|
||||
ControllerOutput(HOTKEY_TOGGLE_MOUSE_TO_JOYSTICK),
|
||||
ControllerOutput(HOTKEY_TOGGLE_MOUSE_TO_GYRO),
|
||||
ControllerOutput(HOTKEY_TOGGLE_MOUSE_TO_TOUCHPAD),
|
||||
ControllerOutput(HOTKEY_RENDERDOC),
|
||||
|
||||
ControllerOutput(SDL_GAMEPAD_BUTTON_INVALID, SDL_GAMEPAD_AXIS_INVALID),
|
||||
@ -579,6 +580,9 @@ void ControllerOutput::FinalizeUpdate() {
|
||||
case HOTKEY_TOGGLE_MOUSE_TO_GYRO:
|
||||
PushSDLEvent(SDL_EVENT_MOUSE_TO_GYRO);
|
||||
break;
|
||||
case HOTKEY_TOGGLE_MOUSE_TO_TOUCHPAD:
|
||||
PushSDLEvent(SDL_EVENT_MOUSE_TO_TOUCHPAD);
|
||||
break;
|
||||
case HOTKEY_RENDERDOC:
|
||||
PushSDLEvent(SDL_EVENT_RDOC_CAPTURE);
|
||||
break;
|
||||
@ -773,6 +777,9 @@ void ActivateOutputsFromInputs() {
|
||||
it.ResetUpdate();
|
||||
}
|
||||
|
||||
// Check for input blockers
|
||||
ApplyMouseInputBlockers();
|
||||
|
||||
// Iterate over all inputs, and update their respecive outputs accordingly
|
||||
for (auto& it : connections) {
|
||||
it.output->AddUpdate(it.ProcessBinding());
|
||||
|
||||
@ -34,9 +34,10 @@
|
||||
#define SDL_EVENT_RELOAD_INPUTS SDL_EVENT_USER + 5
|
||||
#define SDL_EVENT_MOUSE_TO_JOYSTICK SDL_EVENT_USER + 6
|
||||
#define SDL_EVENT_MOUSE_TO_GYRO SDL_EVENT_USER + 7
|
||||
#define SDL_EVENT_RDOC_CAPTURE SDL_EVENT_USER + 8
|
||||
#define SDL_EVENT_QUIT_DIALOG SDL_EVENT_USER + 9
|
||||
#define SDL_EVENT_MOUSE_WHEEL_OFF SDL_EVENT_USER + 10
|
||||
#define SDL_EVENT_MOUSE_TO_TOUCHPAD SDL_EVENT_USER + 8
|
||||
#define SDL_EVENT_RDOC_CAPTURE SDL_EVENT_USER + 9
|
||||
#define SDL_EVENT_QUIT_DIALOG SDL_EVENT_USER + 10
|
||||
#define SDL_EVENT_MOUSE_WHEEL_OFF SDL_EVENT_USER + 11
|
||||
|
||||
#define LEFTJOYSTICK_HALFMODE 0x00010000
|
||||
#define RIGHTJOYSTICK_HALFMODE 0x00020000
|
||||
@ -52,7 +53,8 @@
|
||||
#define HOTKEY_RELOAD_INPUTS 0xf0000005
|
||||
#define HOTKEY_TOGGLE_MOUSE_TO_JOYSTICK 0xf0000006
|
||||
#define HOTKEY_TOGGLE_MOUSE_TO_GYRO 0xf0000007
|
||||
#define HOTKEY_RENDERDOC 0xf0000008
|
||||
#define HOTKEY_TOGGLE_MOUSE_TO_TOUCHPAD 0xf0000008
|
||||
#define HOTKEY_RENDERDOC 0xf0000009
|
||||
|
||||
#define SDL_UNMAPPED UINT32_MAX - 1
|
||||
|
||||
@ -141,6 +143,7 @@ const std::map<std::string, u32> string_to_cbutton_map = {
|
||||
{"hotkey_reload_inputs", HOTKEY_RELOAD_INPUTS},
|
||||
{"hotkey_toggle_mouse_to_joystick", HOTKEY_TOGGLE_MOUSE_TO_JOYSTICK},
|
||||
{"hotkey_toggle_mouse_to_gyro", HOTKEY_TOGGLE_MOUSE_TO_GYRO},
|
||||
{"hotkey_toggle_mouse_to_touchpad", HOTKEY_TOGGLE_MOUSE_TO_TOUCHPAD},
|
||||
{"hotkey_renderdoc_capture", HOTKEY_RENDERDOC},
|
||||
};
|
||||
|
||||
|
||||
@ -6,12 +6,19 @@
|
||||
#include "common/assert.h"
|
||||
#include "common/types.h"
|
||||
#include "input/controller.h"
|
||||
#include "input/input_handler.h"
|
||||
#include "input_mouse.h"
|
||||
|
||||
#include <common/singleton.h>
|
||||
#include <emulator.h>
|
||||
#include "SDL3/SDL.h"
|
||||
|
||||
extern Frontend::WindowSDL* g_window;
|
||||
|
||||
namespace Input {
|
||||
|
||||
extern std::list<std::pair<InputEvent, bool>> pressed_keys;
|
||||
|
||||
int mouse_joystick_binding = 0;
|
||||
float mouse_deadzone_offset = 0.5, mouse_speed = 1, mouse_speed_offset = 0.1250;
|
||||
bool mouse_gyro_roll_mode = false;
|
||||
@ -80,7 +87,6 @@ void EmulateJoystick(GameController* controller, u32 interval) {
|
||||
|
||||
constexpr float constant_down_accel[3] = {0.0f, 10.0f, 0.0f};
|
||||
void EmulateGyro(GameController* controller, u32 interval) {
|
||||
// LOG_INFO(Input, "todo gyro");
|
||||
float d_x = 0, d_y = 0;
|
||||
SDL_GetRelativeMouseState(&d_x, &d_y);
|
||||
controller->Acceleration(1, constant_down_accel);
|
||||
@ -92,6 +98,31 @@ void EmulateGyro(GameController* controller, u32 interval) {
|
||||
controller->Gyro(1, gyro_from_mouse);
|
||||
}
|
||||
|
||||
void EmulateTouchpad(GameController* controller, u32 interval) {
|
||||
float x, y;
|
||||
SDL_MouseButtonFlags mouse_buttons = SDL_GetMouseState(&x, &y);
|
||||
controller->SetTouchpadState(0, (mouse_buttons & SDL_BUTTON_LMASK) != 0,
|
||||
std::clamp(x / g_window->GetWidth(), 0.0f, 1.0f),
|
||||
std::clamp(y / g_window->GetHeight(), 0.0f, 1.0f));
|
||||
controller->CheckButton(0, Libraries::Pad::OrbisPadButtonDataOffset::TouchPad,
|
||||
(mouse_buttons & SDL_BUTTON_RMASK) != 0);
|
||||
}
|
||||
|
||||
void ApplyMouseInputBlockers() {
|
||||
switch (mouse_mode) {
|
||||
case MouseMode::Touchpad:
|
||||
for (auto& k : pressed_keys) {
|
||||
if (k.first.input.sdl_id == SDL_BUTTON_LEFT ||
|
||||
k.first.input.sdl_id == SDL_BUTTON_RIGHT) {
|
||||
k.second = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Uint32 MousePolling(void* param, Uint32 id, Uint32 interval) {
|
||||
auto* controller = (GameController*)param;
|
||||
switch (mouse_mode) {
|
||||
@ -101,6 +132,9 @@ Uint32 MousePolling(void* param, Uint32 id, Uint32 interval) {
|
||||
case MouseMode::Gyro:
|
||||
EmulateGyro(controller, interval);
|
||||
break;
|
||||
case MouseMode::Touchpad:
|
||||
EmulateTouchpad(controller, interval);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
@ -12,6 +12,7 @@ enum MouseMode {
|
||||
Off = 0,
|
||||
Joystick,
|
||||
Gyro,
|
||||
Touchpad,
|
||||
};
|
||||
|
||||
bool ToggleMouseModeTo(MouseMode m);
|
||||
@ -22,6 +23,8 @@ void SetMouseGyroRollMode(bool mode);
|
||||
void EmulateJoystick(GameController* controller, u32 interval);
|
||||
void EmulateGyro(GameController* controller, u32 interval);
|
||||
|
||||
void ApplyMouseInputBlockers();
|
||||
|
||||
// Polls the mouse for changes
|
||||
Uint32 MousePolling(void* param, Uint32 id, Uint32 interval);
|
||||
|
||||
|
||||
@ -457,6 +457,11 @@ void WindowSDL::WaitEvent() {
|
||||
SDL_SetWindowRelativeMouseMode(this->GetSDLWindow(),
|
||||
Input::ToggleMouseModeTo(Input::MouseMode::Gyro));
|
||||
break;
|
||||
case SDL_EVENT_MOUSE_TO_TOUCHPAD:
|
||||
SDL_SetWindowRelativeMouseMode(this->GetSDLWindow(),
|
||||
Input::ToggleMouseModeTo(Input::MouseMode::Touchpad));
|
||||
SDL_SetWindowRelativeMouseMode(this->GetSDLWindow(), false);
|
||||
break;
|
||||
case SDL_EVENT_RDOC_CAPTURE:
|
||||
VideoCore::TriggerCapture();
|
||||
break;
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/thread.h"
|
||||
#include "imgui/renderer/texture_manager.h"
|
||||
#include "video_core/renderer_vulkan/vk_instance.h"
|
||||
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
||||
@ -17,6 +18,8 @@ Scheduler::Scheduler(const Instance& instance)
|
||||
profiler_scope = reinterpret_cast<tracy::VkCtxScope*>(std::malloc(sizeof(tracy::VkCtxScope)));
|
||||
#endif
|
||||
AllocateWorkerCommandBuffers();
|
||||
priority_pending_ops_thread =
|
||||
std::jthread(std::bind_front(&Scheduler::PriorityPendingOpsThread, this));
|
||||
}
|
||||
|
||||
Scheduler::~Scheduler() {
|
||||
@ -167,6 +170,32 @@ void Scheduler::SubmitExecution(SubmitInfo& info) {
|
||||
PopPendingOperations();
|
||||
}
|
||||
|
||||
void Scheduler::PriorityPendingOpsThread(std::stop_token stoken) {
|
||||
Common::SetCurrentThreadName("shadPS4:GpuSchedPriorityPendingOpsRunner");
|
||||
|
||||
while (!stoken.stop_requested()) {
|
||||
PendingOp op;
|
||||
{
|
||||
std::unique_lock lk(priority_pending_ops_mutex);
|
||||
priority_pending_ops_cv.wait(lk, stoken,
|
||||
[this] { return !priority_pending_ops.empty(); });
|
||||
if (stoken.stop_requested()) {
|
||||
break;
|
||||
}
|
||||
|
||||
op = std::move(priority_pending_ops.front());
|
||||
priority_pending_ops.pop();
|
||||
}
|
||||
|
||||
master_semaphore.Wait(op.gpu_tick);
|
||||
if (stoken.stop_requested()) {
|
||||
break;
|
||||
}
|
||||
|
||||
op.callback();
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicState::Commit(const Instance& instance, const vk::CommandBuffer& cmdbuf) {
|
||||
if (dirty_state.viewports) {
|
||||
dirty_state.viewports = false;
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <queue>
|
||||
|
||||
#include "common/unique_function.h"
|
||||
@ -401,10 +402,21 @@ public:
|
||||
}
|
||||
|
||||
/// Defers an operation until the gpu has reached the current cpu tick.
|
||||
/// Will be run when submitting or calling PopPendingOperations.
|
||||
void DeferOperation(Common::UniqueFunction<void>&& func) {
|
||||
pending_ops.emplace(std::move(func), CurrentTick());
|
||||
}
|
||||
|
||||
/// Defers an operation until the gpu has reached the current cpu tick.
|
||||
/// Runs as soon as possible in another thread.
|
||||
void DeferPriorityOperation(Common::UniqueFunction<void>&& func) {
|
||||
{
|
||||
std::unique_lock lk(priority_pending_ops_mutex);
|
||||
priority_pending_ops.emplace(std::move(func), CurrentTick());
|
||||
}
|
||||
priority_pending_ops_cv.notify_one();
|
||||
}
|
||||
|
||||
static std::mutex submit_mutex;
|
||||
|
||||
private:
|
||||
@ -412,6 +424,8 @@ private:
|
||||
|
||||
void SubmitExecution(SubmitInfo& info);
|
||||
|
||||
void PriorityPendingOpsThread(std::stop_token stoken);
|
||||
|
||||
private:
|
||||
const Instance& instance;
|
||||
MasterSemaphore master_semaphore;
|
||||
@ -424,6 +438,10 @@ private:
|
||||
u64 gpu_tick;
|
||||
};
|
||||
std::queue<PendingOp> pending_ops;
|
||||
std::queue<PendingOp> priority_pending_ops;
|
||||
std::mutex priority_pending_ops_mutex;
|
||||
std::condition_variable_any priority_pending_ops_cv;
|
||||
std::jthread priority_pending_ops_thread;
|
||||
RenderState render_state;
|
||||
bool is_rendering = false;
|
||||
tracy::VkCtxScope* profiler_scope{};
|
||||
|
||||
@ -52,9 +52,6 @@ TextureCache::TextureCache(const Vulkan::Instance& instance_, Vulkan::Scheduler&
|
||||
std::max<u64>(std::min(device_local_memory - min_vacancy_critical, min_spacing_critical),
|
||||
DEFAULT_CRITICAL_GC_MEMORY));
|
||||
trigger_gc_memory = static_cast<u64>((device_local_memory - mem_threshold) / 2);
|
||||
|
||||
downloaded_images_thread =
|
||||
std::jthread([&](const std::stop_token& token) { DownloadedImagesThread(token); });
|
||||
}
|
||||
|
||||
TextureCache::~TextureCache() = default;
|
||||
@ -125,33 +122,11 @@ void TextureCache::DownloadImageMemory(ImageId image_id) {
|
||||
cmdbuf.copyImageToBuffer(image.GetImage(), vk::ImageLayout::eTransferSrcOptimal,
|
||||
download_buffer.Handle(), image_download);
|
||||
|
||||
{
|
||||
std::unique_lock lock(downloaded_images_mutex);
|
||||
downloaded_images_queue.emplace(scheduler.CurrentTick(), image.info.guest_address, download,
|
||||
download_size);
|
||||
downloaded_images_cv.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
void TextureCache::DownloadedImagesThread(const std::stop_token& token) {
|
||||
auto* memory = Core::Memory::Instance();
|
||||
while (!token.stop_requested()) {
|
||||
DownloadedImage image;
|
||||
{
|
||||
std::unique_lock lock{downloaded_images_mutex};
|
||||
downloaded_images_cv.wait(lock, token,
|
||||
[this] { return !downloaded_images_queue.empty(); });
|
||||
if (token.stop_requested()) {
|
||||
break;
|
||||
}
|
||||
image = downloaded_images_queue.front();
|
||||
downloaded_images_queue.pop();
|
||||
}
|
||||
|
||||
scheduler.GetMasterSemaphore()->Wait(image.tick);
|
||||
memory->TryWriteBacking(std::bit_cast<u8*>(image.device_addr), image.download,
|
||||
image.download_size);
|
||||
}
|
||||
scheduler.DeferPriorityOperation(
|
||||
[this, device_addr = image.info.guest_address, download, download_size] {
|
||||
Core::Memory::Instance()->TryWriteBacking(std::bit_cast<u8*>(device_addr), download,
|
||||
download_size);
|
||||
});
|
||||
}
|
||||
|
||||
void TextureCache::MarkAsMaybeDirty(ImageId image_id, Image& image) {
|
||||
|
||||
@ -314,16 +314,6 @@ private:
|
||||
Common::LeastRecentlyUsedCache<ImageId, u64> lru_cache;
|
||||
PageTable page_table;
|
||||
std::mutex mutex;
|
||||
struct DownloadedImage {
|
||||
u64 tick;
|
||||
VAddr device_addr;
|
||||
void* download;
|
||||
size_t download_size;
|
||||
};
|
||||
std::queue<DownloadedImage> downloaded_images_queue;
|
||||
std::mutex downloaded_images_mutex;
|
||||
std::condition_variable_any downloaded_images_cv;
|
||||
std::jthread downloaded_images_thread;
|
||||
struct MetaDataInfo {
|
||||
enum class Type {
|
||||
CMask,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user