hmd2: initialize a virtual headset with --vr
Inspired by https://github.com/KytyPS5/KytyPS5/pull/607 Co-authored-by: BlackCAT <52720489+psnwd@users.noreply.github.com>
This commit is contained in:
parent
bbebb6419b
commit
1133272668
|
|
@ -55,6 +55,10 @@ bool FullscreenEnabled() {
|
|||
return g_config->fullscreen_enabled;
|
||||
}
|
||||
|
||||
bool VrEnabled() {
|
||||
return g_config->vr_enabled;
|
||||
}
|
||||
|
||||
uint32_t GetVblankFrequency() {
|
||||
return std::clamp(g_config->vblank_frequency, 30u, 360u);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ struct ConfigOptions {
|
|||
PresentMode present_mode = PresentMode::Mailbox;
|
||||
int32_t gpu_index = -1;
|
||||
bool fullscreen_enabled = false;
|
||||
bool vr_enabled = false;
|
||||
uint32_t vblank_frequency = 60;
|
||||
uint32_t console_language = DEFAULT_CONSOLE_LANGUAGE;
|
||||
bool vulkan_validation_enabled = false;
|
||||
|
|
@ -79,6 +80,7 @@ int32_t GetUserId();
|
|||
PresentMode GetPresentMode();
|
||||
int32_t GetGpuIndex();
|
||||
bool FullscreenEnabled();
|
||||
bool VrEnabled();
|
||||
uint32_t GetVblankFrequency();
|
||||
uint32_t GetConsoleLanguage();
|
||||
bool VulkanValidationEnabled();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,98 @@
|
|||
#include "common/emulatorConfig.h"
|
||||
#include "libs/errno.h"
|
||||
#include "libs/libs.h"
|
||||
#include "loader/symbolDatabase.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace Libs {
|
||||
|
||||
LIB_VERSION("Hmd2", 1, "Hmd2", 1, 1);
|
||||
|
||||
namespace Hmd2 {
|
||||
|
||||
constexpr int32_t ERROR_ALREADY_INITIALIZED = -1972240383; // 0x8a720001
|
||||
constexpr int32_t ERROR_NOT_INITIALIZED = -1972240382; // 0x8a720002
|
||||
constexpr int32_t ERROR_PARAMETER_NULL = -1972240376; // 0x8a720008
|
||||
|
||||
struct SceHmd2InitializeParam {
|
||||
void* reserved0;
|
||||
uint8_t reserved[8];
|
||||
};
|
||||
|
||||
struct SceHmd2DeviceInformation {
|
||||
uint32_t status;
|
||||
uint32_t reserve0;
|
||||
struct {
|
||||
struct {
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
} panelResolution;
|
||||
struct {
|
||||
uint16_t refreshRate90Hz;
|
||||
uint16_t refreshRate120Hz;
|
||||
} flipToDisplayLatency;
|
||||
} deviceInfo;
|
||||
uint8_t hmuMount;
|
||||
uint8_t lensSeparationDistance;
|
||||
uint8_t reserve1[2];
|
||||
float virtualImageDistance;
|
||||
};
|
||||
|
||||
static_assert(sizeof(SceHmd2InitializeParam) == 16);
|
||||
static_assert(offsetof(SceHmd2InitializeParam, reserved) == 8);
|
||||
static_assert(sizeof(SceHmd2DeviceInformation) == 28);
|
||||
static_assert(offsetof(SceHmd2DeviceInformation, deviceInfo) == 8);
|
||||
static_assert(offsetof(SceHmd2DeviceInformation, hmuMount) == 20);
|
||||
static_assert(offsetof(SceHmd2DeviceInformation, virtualImageDistance) == 24);
|
||||
|
||||
static std::atomic<bool> g_initialized = false;
|
||||
|
||||
static int32_t KYTY_SYSV_ABI Hmd2Initialize(const SceHmd2InitializeParam* param) {
|
||||
PRINT_NAME();
|
||||
if (param == nullptr) {
|
||||
return ERROR_PARAMETER_NULL;
|
||||
}
|
||||
if (g_initialized.exchange(true)) {
|
||||
return ERROR_ALREADY_INITIALIZED;
|
||||
}
|
||||
LOGF("Hmd2: initialized, virtual headset=%s\n", Config::VrEnabled() ? "enabled" : "disabled");
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int32_t KYTY_SYSV_ABI Hmd2GetDeviceInformation(SceHmd2DeviceInformation* info) {
|
||||
PRINT_NAME();
|
||||
if (!g_initialized.load()) {
|
||||
return ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
if (info == nullptr) {
|
||||
return ERROR_PARAMETER_NULL;
|
||||
}
|
||||
*info = {};
|
||||
if (Config::VrEnabled()) {
|
||||
// Virtual headset defaults: READY, MOUNT, 63 mm lens separation.
|
||||
info->hmuMount = 1;
|
||||
info->lensSeparationDistance = 63;
|
||||
// Headset characteristics: 4000x2040 panel and 2 m virtual image distance.
|
||||
info->deviceInfo.panelResolution = {4000, 2040};
|
||||
info->virtualImageDistance = 2.0f;
|
||||
// Host presentation has no emulated headset scan-out delay; latency remains zero.
|
||||
} else {
|
||||
info->status = 2; // SCE_HMD2_DEVICE_STATUS_NOT_DETECTED
|
||||
}
|
||||
LOGF("Hmd2: device status=%u panel=%ux%u mounted=%u\n", info->status,
|
||||
info->deviceInfo.panelResolution.width, info->deviceInfo.panelResolution.height,
|
||||
info->hmuMount);
|
||||
return OK;
|
||||
}
|
||||
|
||||
} // namespace Hmd2
|
||||
|
||||
LIB_DEFINE(InitHmd2_1) {
|
||||
LIB_FUNC("c812oYs7Vsc", Hmd2::Hmd2Initialize);
|
||||
LIB_FUNC("bIi4YUfSRys", Hmd2::Hmd2GetDeviceInformation);
|
||||
}
|
||||
|
||||
} // namespace Libs
|
||||
|
|
@ -82,6 +82,7 @@ LIB_DEFINE(InitDialog_1);
|
|||
LIB_DEFINE(InitFont_1);
|
||||
LIB_DEFINE(InitFontFt_1);
|
||||
LIB_DEFINE(InitAgcDriver_1);
|
||||
LIB_DEFINE(InitHmd2_1);
|
||||
LIB_DEFINE(InitLibKernel_1);
|
||||
LIB_DEFINE(InitNet_1);
|
||||
LIB_DEFINE(InitPad_1);
|
||||
|
|
@ -115,6 +116,7 @@ void InitAll(Loader::SymbolDatabase* s) {
|
|||
InitFont_1(s);
|
||||
InitFontFt_1(s);
|
||||
InitAgcDriver_1(s);
|
||||
InitHmd2_1(s);
|
||||
InitLibKernel_1(s);
|
||||
LibMouse::InitMouse_1(s);
|
||||
LibKeyboard::InitKeyboard_1(s);
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ static void PrintUsage() {
|
|||
::printf(
|
||||
" --gpu <index> Vulkan physical device index. Default: auto.\n");
|
||||
::printf(" --fullscreen Run in borderless desktop fullscreen.\n");
|
||||
::printf(" --vr Enable the virtual VR headset.\n");
|
||||
::printf(" --vblank-frequency <num> Virtual vblank frequency. Default: 60.\n");
|
||||
::printf(" --console-language <0-29> Console language. Default: 1 (English US).\n");
|
||||
::printf(" --vulkan-validation <true|false> Enable Vulkan validation.\n");
|
||||
|
|
@ -161,6 +162,11 @@ static bool ParseArgs(int argc, char* argv[], RunOptions& options, bool& show_he
|
|||
continue;
|
||||
}
|
||||
|
||||
if (arg == "--vr") {
|
||||
options.config.vr_enabled = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg == "--playgo-hack") {
|
||||
options.config.playgo_hack_enabled = true;
|
||||
continue;
|
||||
|
|
|
|||
Loading…
Reference in New Issue