diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 3bb94f2f4b0a..b2b246851060 100644 --- a/Common/VR/PPSSPPVR.cpp +++ b/Common/VR/PPSSPPVR.cpp @@ -162,6 +162,7 @@ void InitVROnAndroid(void* vm, void* activity, const char* system, int version, } else if ((strcmp(vendor, "META") == 0) || (strcmp(vendor, "OCULUS") == 0)) { VR_SetPlatformFLag(VR_PLATFORM_CONTROLLER_QUEST, true); VR_SetPlatformFLag(VR_PLATFORM_EXTENSION_FOVEATION, true); + VR_SetPlatformFLag(VR_PLATFORM_EXTENSION_PASSTHROUGH, true); VR_SetPlatformFLag(VR_PLATFORM_EXTENSION_PERFORMANCE, true); } VR_SetPlatformFLag(VR_PLATFORM_RENDERER_VULKAN, (GPUBackend)g_Config.iGPUBackend == GPUBackend::VULKAN); @@ -792,6 +793,7 @@ bool StartVRRender() { // Set customizations __DisplaySetFramerate(g_Config.bForce72Hz ? 72 : 60); VR_SetConfigFloat(VR_CONFIG_CANVAS_DISTANCE, g_Config.fCanvasDistance); + VR_SetConfig(VR_CONFIG_PASSTHROUGH, g_Config.bPassthrough); vrMirroring[VR_MIRRORING_UPDATED] = false; return true; } @@ -828,6 +830,10 @@ bool IsMultiviewSupported() { return false; } +bool IsPassthroughSupported() { + return VR_GetPlatformFlag(VR_PLATFORM_EXTENSION_PASSTHROUGH); +} + bool IsFlatVRGame() { return vrFlatGame; } diff --git a/Common/VR/PPSSPPVR.h b/Common/VR/PPSSPPVR.h index 59264d67fea3..b2fd9ec31feb 100644 --- a/Common/VR/PPSSPPVR.h +++ b/Common/VR/PPSSPPVR.h @@ -51,6 +51,7 @@ void PostVRFrameRender(); int GetVRFBOIndex(); int GetVRPassesCount(); bool IsMultiviewSupported(); +bool IsPassthroughSupported(); bool IsFlatVRGame(); bool IsFlatVRScene(); bool IsGameVRScene(); diff --git a/Common/VR/VRBase.cpp b/Common/VR/VRBase.cpp index 715ea6644ea7..6a22203586e7 100644 --- a/Common/VR/VRBase.cpp +++ b/Common/VR/VRBase.cpp @@ -61,6 +61,9 @@ void VR_Init( void* system, const char* name, int version ) { if (VR_GetPlatformFlag(VR_PLATFORM_EXTENSION_INSTANCE)) { extensions.push_back(XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME); } + if (VR_GetPlatformFlag(VR_PLATFORM_EXTENSION_PASSTHROUGH)) { + extensions.push_back(XR_FB_PASSTHROUGH_EXTENSION_NAME); + } if (VR_GetPlatformFlag(VR_PLATFORM_EXTENSION_PERFORMANCE)) { extensions.push_back(XR_EXT_PERFORMANCE_SETTINGS_EXTENSION_NAME); extensions.push_back(XR_KHR_ANDROID_THREAD_SETTINGS_EXTENSION_NAME); diff --git a/Common/VR/VRBase.h b/Common/VR/VRBase.h index 2d3405f8a7b1..8642640db00f 100644 --- a/Common/VR/VRBase.h +++ b/Common/VR/VRBase.h @@ -42,12 +42,16 @@ static void OXR_CheckErrors(XrInstance instance, XrResult result, const char* fu #define OXR(func) func; #endif -enum { ovrMaxLayerCount = 2 }; +#define DECL_PFN(pfn) PFN_##pfn pfn = nullptr +#define INIT_PFN(pfn) OXR(xrGetInstanceProcAddr(engine->appState.Instance, #pfn, (PFN_xrVoidFunction*)(&pfn))) + +enum { ovrMaxLayerCount = 3 }; enum { ovrMaxNumEyes = 2 }; typedef union { XrCompositionLayerProjection Projection; XrCompositionLayerCylinderKHR Cylinder; + XrCompositionLayerPassthroughFB Passthrough; } ovrCompositorLayer_Union; typedef struct { @@ -122,6 +126,7 @@ enum VRPlatformFlag { VR_PLATFORM_CONTROLLER_QUEST, VR_PLATFORM_EXTENSION_FOVEATION, VR_PLATFORM_EXTENSION_INSTANCE, + VR_PLATFORM_EXTENSION_PASSTHROUGH, VR_PLATFORM_EXTENSION_PERFORMANCE, VR_PLATFORM_RENDERER_VULKAN, VR_PLATFORM_TRACKING_FLOOR, diff --git a/Common/VR/VRRenderer.cpp b/Common/VR/VRRenderer.cpp index 5a9a20892665..6c22312311af 100644 --- a/Common/VR/VRRenderer.cpp +++ b/Common/VR/VRRenderer.cpp @@ -20,6 +20,17 @@ float vrConfigFloat[VR_CONFIG_FLOAT_MAX] = {}; XrVector3f hmdorientation; +XrPassthroughFB passthrough = XR_NULL_HANDLE; +XrPassthroughLayerFB passthroughLayer = XR_NULL_HANDLE; +DECL_PFN(xrCreatePassthroughFB); +DECL_PFN(xrDestroyPassthroughFB); +DECL_PFN(xrPassthroughStartFB); +DECL_PFN(xrPassthroughPauseFB); +DECL_PFN(xrCreatePassthroughLayerFB); +DECL_PFN(xrDestroyPassthroughLayerFB); +DECL_PFN(xrPassthroughLayerPauseFB); +DECL_PFN(xrPassthroughLayerResumeFB); + void VR_UpdateStageBounds(ovrApp* pappState) { XrExtent2Df stageBounds = {}; @@ -179,6 +190,17 @@ void VR_InitRenderer( engine_t* engine, bool multiview ) { VR_DestroyRenderer(engine); } + if (VR_GetPlatformFlag(VRPlatformFlag::VR_PLATFORM_EXTENSION_PASSTHROUGH)) { + INIT_PFN(xrCreatePassthroughFB); + INIT_PFN(xrDestroyPassthroughFB); + INIT_PFN(xrPassthroughStartFB); + INIT_PFN(xrPassthroughPauseFB); + INIT_PFN(xrCreatePassthroughLayerFB); + INIT_PFN(xrDestroyPassthroughLayerFB); + INIT_PFN(xrPassthroughLayerPauseFB); + INIT_PFN(xrPassthroughLayerResumeFB); + } + int eyeW, eyeH; VR_GetResolution(engine, &eyeW, &eyeH); VR_SetConfig(VR_CONFIG_VIEWPORT_WIDTH, eyeW); @@ -221,10 +243,32 @@ void VR_InitRenderer( engine_t* engine, bool multiview ) { ovrRenderer_SetFoveation(&engine->appState.Instance, &engine->appState.Session, &engine->appState.Renderer, XR_FOVEATION_LEVEL_HIGH_TOP_FB, 0, XR_FOVEATION_DYNAMIC_LEVEL_ENABLED_FB); } #endif + + if (VR_GetPlatformFlag(VRPlatformFlag::VR_PLATFORM_EXTENSION_PASSTHROUGH)) { + XrPassthroughCreateInfoFB ptci = {XR_TYPE_PASSTHROUGH_CREATE_INFO_FB}; + XrResult result; + OXR(result = xrCreatePassthroughFB(engine->appState.Session, &ptci, &passthrough)); + + if (XR_SUCCEEDED(result)) { + XrPassthroughLayerCreateInfoFB plci = {XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_FB}; + plci.passthrough = passthrough; + plci.purpose = XR_PASSTHROUGH_LAYER_PURPOSE_RECONSTRUCTION_FB; + OXR(xrCreatePassthroughLayerFB(engine->appState.Session, &plci, &passthroughLayer)); + } + + OXR(xrPassthroughStartFB(passthrough)); + OXR(xrPassthroughLayerResumeFB(passthroughLayer)); + } initialized = true; } void VR_DestroyRenderer( engine_t* engine ) { + if (VR_GetPlatformFlag(VRPlatformFlag::VR_PLATFORM_EXTENSION_PASSTHROUGH)) { + OXR(xrPassthroughLayerPauseFB(passthroughLayer)); + OXR(xrPassthroughPauseFB(passthrough)); + OXR(xrDestroyPassthroughFB(passthrough)); + passthrough = XR_NULL_HANDLE; + } ovrRenderer_Destroy(&engine->appState.Renderer); free(projections); initialized = false; @@ -328,6 +372,16 @@ void VR_EndFrame( engine_t* engine ) { void VR_FinishFrame( engine_t* engine ) { + if (VR_GetPlatformFlag(VRPlatformFlag::VR_PLATFORM_EXTENSION_PASSTHROUGH) && VR_GetConfig(VR_CONFIG_PASSTHROUGH)) { + if (passthroughLayer != XR_NULL_HANDLE) { + XrCompositionLayerPassthroughFB passthrough_layer = {XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB}; + passthrough_layer.layerHandle = passthroughLayer; + passthrough_layer.flags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT; + passthrough_layer.space = XR_NULL_HANDLE; + engine->appState.Layers[engine->appState.LayerCount++].Passthrough = passthrough_layer; + } + } + int vrMode = vrConfig[VR_CONFIG_MODE]; XrCompositionLayerProjectionView projection_layer_elements[2] = {}; if ((vrMode == VR_MODE_MONO_6DOF) || (vrMode == VR_MODE_STEREO_6DOF)) { diff --git a/Common/VR/VRRenderer.h b/Common/VR/VRRenderer.h index 8ed786965606..c583740b6e84 100644 --- a/Common/VR/VRRenderer.h +++ b/Common/VR/VRRenderer.h @@ -4,8 +4,8 @@ #include "VRMath.h" enum VRConfig { - //switching between 2D and 3D - VR_CONFIG_MODE, + //switching between mode + VR_CONFIG_MODE, VR_CONFIG_PASSTHROUGH, //mouse cursor VR_CONFIG_MOUSE_SIZE, VR_CONFIG_MOUSE_X, VR_CONFIG_MOUSE_Y, //viewport setup diff --git a/Core/Config.cpp b/Core/Config.cpp index 7ce91c706450..5753b803b7c6 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -839,6 +839,7 @@ static const ConfigSetting vrSettings[] = { ConfigSetting("VREnableMotions", &g_Config.bEnableMotions, true, CfgFlag::PER_GAME), ConfigSetting("VRForce72Hz", &g_Config.bForce72Hz, true, CfgFlag::PER_GAME), ConfigSetting("VRManualForceVR", &g_Config.bManualForceVR, false, CfgFlag::PER_GAME), + ConfigSetting("VRPassthrough", &g_Config.bPassthrough, false, CfgFlag::PER_GAME), ConfigSetting("VRRescaleHUD", &g_Config.bRescaleHUD, true, CfgFlag::PER_GAME), ConfigSetting("VRCameraDistance", &g_Config.fCameraDistance, 0.0f, CfgFlag::PER_GAME), ConfigSetting("VRCameraHeight", &g_Config.fCameraHeight, 0.0f, CfgFlag::PER_GAME), diff --git a/Core/Config.h b/Core/Config.h index 0b23b59c8e20..ae0c95b3d05b 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -453,6 +453,7 @@ struct Config { bool bEnableMotions; bool bForce72Hz; bool bManualForceVR; + bool bPassthrough; bool bRescaleHUD; float fCameraDistance; float fCameraHeight; diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 817e8ee7d10c..dd7b0bc23f37 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1152,6 +1152,9 @@ void GameSettingsScreen::CreateVRSettings(UI::ViewGroup *vrSettings) { vr6DoF->SetEnabledPtr(&g_Config.bEnableVR); vrSettings->Add(new CheckBox(&g_Config.bEnableStereo, vr->T("Stereoscopic vision (Experimental)"))); vrSettings->Add(new CheckBox(&g_Config.bForce72Hz, vr->T("Force 72Hz update"))); + if (IsPassthroughSupported()) { + vrSettings->Add(new CheckBox(&g_Config.bPassthrough, vr->T("Enable passthrough"))); + } vrSettings->Add(new ItemHeader(vr->T("VR camera"))); vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fCanvasDistance, 1.0f, 15.0f, 12.0f, vr->T("Distance to 2D menus and scenes"), 1.0f, screenManager(), "")); diff --git a/android/VRManifest.xml b/android/VRManifest.xml index 4dfda7647a58..dc1a3aa1eb7f 100644 --- a/android/VRManifest.xml +++ b/android/VRManifest.xml @@ -3,6 +3,7 @@ +