// @lint-ignore-every LICENSELINT // Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "OculusXRHMDPrivate.h" #include "ProceduralMeshComponent.h" #if OCULUS_HMD_SUPPORTED_PLATFORMS #include "OculusXRHMD_CustomPresent.h" #include "XRSwapChain.h" #include "OculusXRPassthroughLayerShapes.h" namespace OculusXRHMD { //------------------------------------------------------------------------------------------------- // FOvrpLayer //------------------------------------------------------------------------------------------------- class FDeferredDeletionQueue; class FOvrpLayer : public TSharedFromThis { public: FOvrpLayer(uint32 InOvrpLayerId, FDeferredDeletionQueue* InDeferredDeletion); ~FOvrpLayer(); protected: uint32 OvrpLayerId; private: FDeferredDeletionQueue* DeferredDeletion; // necessary for deferred deletion queue of the actual OvrpLayer }; typedef TSharedPtr FOvrpLayerPtr; //------------------------------------------------------------------------------------------------- // FLayer //------------------------------------------------------------------------------------------------- class FLayer : public TSharedFromThis { public: FLayer(uint32 InId); FLayer(const FLayer& InLayer); ~FLayer(); uint32 GetId() const { return Id; } int GetOvrpId() const { return OvrpLayerId; } void SetDesc(const IStereoLayers::FLayerDesc& InDesc); void SetDesc(const FSettings* Settings, const IStereoLayers::FLayerDesc& InDesc); const IStereoLayers::FLayerDesc& GetDesc() const { return Desc; } void SetEyeLayerDesc(const ovrpLayerDesc_EyeFov& InEyeLayerDesc); const FXRSwapChainPtr& GetSwapChain() const { return SwapChain; } const FXRSwapChainPtr& GetRightSwapChain() const { return RightSwapChain; } const FXRSwapChainPtr& GetDepthSwapChain() const { return DepthSwapChain; } const FXRSwapChainPtr& GetFoveationSwapChain() const { return FoveationSwapChain; } const FXRSwapChainPtr& GetMotionVectorSwapChain() const { return MotionVectorSwapChain; } const FXRSwapChainPtr& GetMotionVectorDepthSwapChain() const { return MotionVectorDepthSwapChain; } void MarkTextureForUpdate() { bUpdateTexture = true; } bool NeedsPokeAHole(); void HandlePokeAHoleComponent(); void BuildPokeAHoleMesh(TArray& Vertices, TArray& Triangles, TArray& UV0); bool NeedsPassthroughPokeAHole(); bool ShapeNeedsTextures(ovrpShape shape); FTextureRHIRef GetTexture() { return Desc.Texture; } TSharedPtr Clone() const; bool CanReuseResources(const FLayer* InLayer) const; bool Initialize_RenderThread(const FSettings* Settings, FCustomPresent* CustomPresent, FDeferredDeletionQueue* DeferredDeletion, FRHICommandListImmediate& RHICmdList, const FLayer* InLayer = nullptr); void UpdateTexture_RenderThread(const FSettings* Settings, FCustomPresent* CustomPresent, FRHICommandListImmediate& RHICmdList); void UpdatePassthrough_RenderThread(FCustomPresent* CustomPresent, FRHICommandListImmediate& RHICmdList, const FGameFrame* Frame); const ovrpLayerSubmit* UpdateLayer_RHIThread(const FSettings* Settings, const FGameFrame* Frame, const int LayerIndex); void IncrementSwapChainIndex_RHIThread(FCustomPresent* CustomPresent); void ReleaseResources_RHIThread(); bool IsVisible() { return (Desc.Flags & IStereoLayers::LAYER_FLAG_HIDDEN) == 0; } bool bNeedsTexSrgbCreate; void AddPassthroughMesh_RenderThread(const TArray& Vertices, const TArray& Triangles, FMatrix Transformation, uint64_t& OutMeshHandle, uint64_t& OutInstanceHandle); void UpdatePassthroughMeshTransform_RenderThread(uint64_t InstanceHandle, FMatrix Transformation); void RemovePassthroughMesh_RenderThread(uint64_t MeshHandle, uint64_t InstanceHandle); void DestroyLayer(); protected: struct FPassthroughMesh { FPassthroughMesh(uint64_t MeshHandle, uint64_t InstanceHandle) : MeshHandle(MeshHandle) , InstanceHandle(InstanceHandle) { } uint64_t MeshHandle; uint64_t InstanceHandle; }; typedef TSharedPtr, ESPMode::ThreadSafe> FUserDefinedGeometryMapPtr; void UpdatePassthroughStyle_RenderThread(const FEdgeStyleParameters& EdgeStyleParameters); struct FPassthroughPokeActor { FPassthroughPokeActor(){}; FPassthroughPokeActor(UProceduralMeshComponent* PokeAHoleComponentPtr, AActor* PokeAHoleActor) : PokeAHoleComponentPtr(PokeAHoleComponentPtr) , PokeAHoleActor(PokeAHoleActor){}; UProceduralMeshComponent* PokeAHoleComponentPtr; AActor* PokeAHoleActor; }; typedef TSharedPtr, ESPMode::ThreadSafe> FPassthroughPokeActorMapPtr; bool BuildPassthroughPokeActor(FOculusPassthroughMeshRef PassthroughMesh, FPassthroughPokeActor& OutPassthroughPokeActor); void UpdatePassthroughPokeActors_GameThread(); uint32 Id; IStereoLayers::FLayerDesc Desc; int OvrpLayerId; ovrpLayerDescUnion OvrpLayerDesc; ovrpLayerSubmitUnion OvrpLayerSubmit; FOvrpLayerPtr OvrpLayer; FXRSwapChainPtr SwapChain; FXRSwapChainPtr DepthSwapChain; FXRSwapChainPtr FoveationSwapChain; FXRSwapChainPtr RightSwapChain; FXRSwapChainPtr RightDepthSwapChain; FXRSwapChainPtr MotionVectorSwapChain; FXRSwapChainPtr MotionVectorDepthSwapChain; FTextureRHIRef InvAlphaTexture; bool bUpdateTexture; bool bInvertY; bool bHasDepth; bool bSupportDepthComposite; UProceduralMeshComponent* PokeAHoleComponentPtr; AActor* PokeAHoleActor; FUserDefinedGeometryMapPtr UserDefinedGeometryMap; FPassthroughPokeActorMapPtr PassthroughPokeActorMap; }; typedef TSharedPtr FLayerPtr; //------------------------------------------------------------------------------------------------- // FLayerPtr_CompareId //------------------------------------------------------------------------------------------------- struct FLayerPtr_CompareId { FORCEINLINE bool operator()(const FLayerPtr& A, const FLayerPtr& B) const { return A->GetId() < B->GetId(); } }; //------------------------------------------------------------------------------------------------- // FLayerPtr_ComparePriority //------------------------------------------------------------------------------------------------- struct FLayerPtr_ComparePriority { FORCEINLINE bool operator()(const FLayerPtr& A, const FLayerPtr& B) const { if (A->GetDesc().Priority < B->GetDesc().Priority) return true; if (A->GetDesc().Priority > B->GetDesc().Priority) return false; return A->GetId() < B->GetId(); } }; struct FLayerPtr_CompareTotal { FORCEINLINE int32 GetLayerTypePriority(const FLayerPtr& A) const { // Draw FReconstructedLayer, PoleAHole layers (Android only), EyeFov layer, followed by other layers const bool IsEyeFov = (A->GetId() == 0); const bool IsPokeAHole = A->NeedsPokeAHole() || A->NeedsPassthroughPokeAHole(); bool IsUnderlay = false; if (A->GetDesc().HasShape()) { const FReconstructedLayer& ReconstructedLayerProps = A->GetDesc().GetShape(); IsUnderlay = (ReconstructedLayerProps.PassthroughLayerOrder == PassthroughLayerOrder_Underlay); } else if (A->GetDesc().HasShape()) { const FUserDefinedLayer& UserDefinedLayerProps = A->GetDesc().GetShape(); IsUnderlay = (UserDefinedLayerProps.PassthroughLayerOrder == PassthroughLayerOrder_Underlay); } const int32 Priority = IsUnderlay ? -2 : IsPokeAHole ? -1 : IsEyeFov ? 0 : 1; return Priority; } FORCEINLINE bool operator()(const FLayerPtr& A, const FLayerPtr& B) const { // First order layers by type int32 PassA = GetLayerTypePriority(A); int32 PassB = GetLayerTypePriority(B); if (PassA != PassB) return PassA < PassB; // Draw non-FaceLocked layers first const IStereoLayers::FLayerDesc& DescA = A->GetDesc(); const IStereoLayers::FLayerDesc& DescB = B->GetDesc(); bool bFaceLockedA = (DescA.PositionType == IStereoLayers::ELayerType::FaceLocked); bool bFaceLockedB = (DescB.PositionType == IStereoLayers::ELayerType::FaceLocked); if (bFaceLockedA != bFaceLockedB) return !bFaceLockedA; // Draw layers by ascending priority if (DescA.Priority != DescB.Priority) return DescA.Priority < DescB.Priority; // Draw layers by ascending id return A->GetId() < B->GetId(); } }; } // namespace OculusXRHMD #endif //OCULUS_HMD_SUPPORTED_PLATFORMS