From 4642e0a66f336b373618561640c6712474cc06f3 Mon Sep 17 00:00:00 2001 From: Lubos Date: Sat, 17 Jun 2023 16:33:21 +0200 Subject: [PATCH] OpenXR - Add passthrough option (Quest only) --- Common/VR/PPSSPPVR.cpp | 6 +++++ Common/VR/PPSSPPVR.h | 1 + Common/VR/VRBase.cpp | 3 +++ Common/VR/VRBase.h | 7 +++++- Common/VR/VRRenderer.cpp | 54 ++++++++++++++++++++++++++++++++++++++++ Common/VR/VRRenderer.h | 4 +-- 6 files changed, 72 insertions(+), 3 deletions(-) diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp index 3bb94f2f4b..b2b2468510 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 59264d67fe..b2fd9ec31f 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 715ea6644e..6a22203586 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 2d3405f8a7..8642640db0 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 5a9a208926..6c22312311 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 8ed7869656..c583740b6e 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