Android build settings + metaxr
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
#include "Common.ush"
|
||||
|
||||
void MainVertexShader(
|
||||
float4 InPosition : ATTRIBUTE0,
|
||||
float2 InUV : ATTRIBUTE1,
|
||||
out float2 OutUV : TEXCOORD0,
|
||||
out float4 OutPosition : SV_POSITION
|
||||
)
|
||||
{
|
||||
OutPosition = InPosition;
|
||||
OutUV = InUV;
|
||||
}
|
||||
|
||||
Texture2D<uint> TextureParameter;
|
||||
|
||||
#define Zoom 2
|
||||
#define Pan float2(0.5, 0)
|
||||
#define Aspect 1
|
||||
#define Iterations int(128*PSVariables.IterationsMultiplier)
|
||||
#define JuliaSeed float2(0.39, 0.2)
|
||||
#define ColorScale float3(4, 5, 6)
|
||||
|
||||
float ComputeValue(float2 v, float2 offset)
|
||||
{
|
||||
float vxsquare = 0;
|
||||
float vysquare = 0;
|
||||
|
||||
int iteration = 0;
|
||||
int lastIteration = Iterations;
|
||||
|
||||
do
|
||||
{
|
||||
vxsquare = v.x * v.x;
|
||||
vysquare = v.y * v.y;
|
||||
|
||||
v = float2(vxsquare - vysquare, v.x * v.y * 2) + offset;
|
||||
|
||||
iteration++;
|
||||
|
||||
if ((lastIteration == Iterations) && (vxsquare + vysquare) > 4.0)
|
||||
{
|
||||
lastIteration = iteration + 1;
|
||||
}
|
||||
} while (iteration < lastIteration);
|
||||
|
||||
return (float(iteration) - (log(log(sqrt(vxsquare + vysquare))) / log(2.0))) / float(Iterations);
|
||||
}
|
||||
|
||||
float4 Mandelbrot_Func(float2 texCoord : TEXCOORD0) : COLOR0
|
||||
{
|
||||
float2 v = (texCoord - 0.5) * Zoom * float2(1, Aspect) - Pan;
|
||||
|
||||
float val = ComputeValue(v, v);
|
||||
|
||||
return float4(sin(val * ColorScale.x), sin(val * ColorScale.y), sin(val * ColorScale.z), 1);
|
||||
}
|
||||
|
||||
void MainPixelShader(
|
||||
in float2 uv : TEXCOORD0,
|
||||
out float4 OutColor : SV_Target0
|
||||
)
|
||||
{
|
||||
OutColor = Mandelbrot_Func(uv);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,294 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "OculusXRAssetManager.h"
|
||||
#include "OculusXRHMDPrivate.h"
|
||||
#include "OculusXRHMDModule.h"
|
||||
#include "Engine/StaticMesh.h"
|
||||
#include "Components/StaticMeshComponent.h"
|
||||
#include "UObject/SoftObjectPath.h"
|
||||
#include "Engine/SkeletalMesh.h"
|
||||
#include "Components/SkeletalMeshComponent.h"
|
||||
#include "OculusXRAssetDirectory.h"
|
||||
#include "UObject/GCObject.h"
|
||||
|
||||
/* FOculusAssetDirectory
|
||||
*****************************************************************************/
|
||||
|
||||
enum EOculusAsset
|
||||
{
|
||||
LeftTouchRiftS,
|
||||
RightTouchRiftS,
|
||||
LeftTouchQuest2,
|
||||
RightTouchQuest2,
|
||||
LeftTouchQuestPro,
|
||||
RightTouchQuestPro,
|
||||
LeftTouchQuest3,
|
||||
RightTouchQuest3,
|
||||
OculusAssetTotal
|
||||
};
|
||||
|
||||
FSoftObjectPath FOculusAssetDirectory::AssetListing[OculusAssetTotal] = {
|
||||
FString(TEXT("/OculusXR/Meshes/LeftTouchForQuestRiftSController.LeftTouchForQuestRiftSController")),
|
||||
FString(TEXT("/OculusXR/Meshes/RightTouchForQuestRiftSController.RightTouchForQuestRiftSController")),
|
||||
FString(TEXT("/OculusXR/Meshes/LeftTouchForQuest2.LeftTouchForQuest2")),
|
||||
FString(TEXT("/OculusXR/Meshes/RightTouchForQuest2.RightTouchForQuest2")),
|
||||
FString(TEXT("/OculusXR/Meshes/LeftMetaQuestTouchPro.LeftMetaQuestTouchPro")),
|
||||
FString(TEXT("/OculusXR/Meshes/RightMetaQuestTouchPro.RightMetaQuestTouchPro")),
|
||||
FString(TEXT("/OculusXR/Meshes/LeftMetaQuestTouchPlus.LeftMetaQuestTouchPlus")),
|
||||
FString(TEXT("/OculusXR/Meshes/RightMetaQuestTouchPlus.RightMetaQuestTouchPlus")),
|
||||
};
|
||||
|
||||
#if WITH_EDITORONLY_DATA
|
||||
class FOculusAssetRepo : public FGCObject, public TArray<TObjectPtr<UObject>>
|
||||
{
|
||||
public:
|
||||
// made an on-demand singleton rather than a static global, to avoid issues with FGCObject initialization
|
||||
static FOculusAssetRepo& Get()
|
||||
{
|
||||
static FOculusAssetRepo AssetRepository;
|
||||
return AssetRepository;
|
||||
}
|
||||
|
||||
UObject* LoadAndAdd(const FSoftObjectPath& AssetPath)
|
||||
{
|
||||
UObject* AssetObj = AssetPath.TryLoad();
|
||||
if (AssetObj != nullptr)
|
||||
{
|
||||
AddUnique(AssetObj);
|
||||
}
|
||||
return AssetObj;
|
||||
}
|
||||
|
||||
public:
|
||||
//~ FGCObject interface
|
||||
virtual void AddReferencedObjects(FReferenceCollector& Collector) override
|
||||
{
|
||||
Collector.AddReferencedObjects(*this);
|
||||
}
|
||||
virtual FString GetReferencerName() const override
|
||||
{
|
||||
return TEXT("FOculusAssetRepo");
|
||||
}
|
||||
};
|
||||
|
||||
void FOculusAssetDirectory::LoadForCook()
|
||||
{
|
||||
FOculusAssetRepo& AssetRepro = FOculusAssetRepo::Get();
|
||||
for (int32 AssetIndex = 0; AssetIndex < UE_ARRAY_COUNT(FOculusAssetDirectory::AssetListing); ++AssetIndex)
|
||||
{
|
||||
AssetRepro.LoadAndAdd(FOculusAssetDirectory::AssetListing[AssetIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
void FOculusAssetDirectory::ReleaseAll()
|
||||
{
|
||||
FOculusAssetRepo::Get().Empty();
|
||||
}
|
||||
#endif // WITH_EDITORONLY_DATA
|
||||
|
||||
/* OculusAssetManager_Impl
|
||||
*****************************************************************************/
|
||||
|
||||
namespace OculusAssetManager_Impl
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
struct FRenderableDevice
|
||||
{
|
||||
ovrpNode OVRNode;
|
||||
ovrpSystemHeadset MinDeviceRange;
|
||||
ovrpSystemHeadset MaxDeviceRange;
|
||||
FSoftObjectPath MeshAssetRef;
|
||||
};
|
||||
|
||||
static FRenderableDevice RenderableDevices[] = {
|
||||
#if PLATFORM_ANDROID
|
||||
// Quest 1 & 2
|
||||
{ ovrpNode_HandLeft, ovrpSystemHeadset_Oculus_Quest, ovrpSystemHeadset_Oculus_Quest_2, FOculusAssetDirectory::AssetListing[LeftTouchQuest2] },
|
||||
{ ovrpNode_HandRight, ovrpSystemHeadset_Oculus_Quest, ovrpSystemHeadset_Oculus_Quest_2, FOculusAssetDirectory::AssetListing[RightTouchQuest2] },
|
||||
|
||||
// Quest Pro
|
||||
{ ovrpNode_HandLeft, ovrpSystemHeadset_Meta_Quest_Pro, ovrpSystemHeadset_Meta_Quest_Pro, FOculusAssetDirectory::AssetListing[LeftTouchQuestPro] },
|
||||
{ ovrpNode_HandRight, ovrpSystemHeadset_Meta_Quest_Pro, ovrpSystemHeadset_Meta_Quest_Pro, FOculusAssetDirectory::AssetListing[RightTouchQuestPro] },
|
||||
|
||||
// Quest 3 & 3s
|
||||
{ ovrpNode_HandLeft, ovrpSystemHeadset_Meta_Quest_3, ovrpSystemHeadset_Meta_Quest_3S, FOculusAssetDirectory::AssetListing[LeftTouchQuest3] },
|
||||
{ ovrpNode_HandRight, ovrpSystemHeadset_Meta_Quest_3, ovrpSystemHeadset_Meta_Quest_3S, FOculusAssetDirectory::AssetListing[RightTouchQuest3] },
|
||||
#else
|
||||
// PC - Rift S
|
||||
{ ovrpNode_HandLeft, ovrpSystemHeadset_Rift_S, ovrpSystemHeadset_Rift_S, FOculusAssetDirectory::AssetListing[LeftTouchRiftS] },
|
||||
{ ovrpNode_HandRight, ovrpSystemHeadset_Rift_S, ovrpSystemHeadset_Rift_S, FOculusAssetDirectory::AssetListing[RightTouchRiftS] },
|
||||
|
||||
// PC - Quest 1 & 2
|
||||
{ ovrpNode_HandLeft, ovrpSystemHeadset_Oculus_Link_Quest, ovrpSystemHeadset_Oculus_Link_Quest_2, FOculusAssetDirectory::AssetListing[LeftTouchQuest2] },
|
||||
{ ovrpNode_HandRight, ovrpSystemHeadset_Oculus_Link_Quest, ovrpSystemHeadset_Oculus_Link_Quest_2, FOculusAssetDirectory::AssetListing[RightTouchQuest2] },
|
||||
|
||||
// PC - Quest Pro
|
||||
{ ovrpNode_HandLeft, ovrpSystemHeadset_Meta_Link_Quest_Pro, ovrpSystemHeadset_Meta_Link_Quest_Pro, FOculusAssetDirectory::AssetListing[LeftTouchQuestPro] },
|
||||
{ ovrpNode_HandRight, ovrpSystemHeadset_Meta_Link_Quest_Pro, ovrpSystemHeadset_Meta_Link_Quest_Pro, FOculusAssetDirectory::AssetListing[RightTouchQuestPro] },
|
||||
|
||||
// Quest 3 & 3s
|
||||
{ ovrpNode_HandLeft, ovrpSystemHeadset_Meta_Link_Quest_3, ovrpSystemHeadset_Meta_Link_Quest_3S, FOculusAssetDirectory::AssetListing[LeftTouchQuest3] },
|
||||
{ ovrpNode_HandRight, ovrpSystemHeadset_Meta_Link_Quest_3, ovrpSystemHeadset_Meta_Link_Quest_3S, FOculusAssetDirectory::AssetListing[RightTouchQuest3] },
|
||||
#endif
|
||||
};
|
||||
|
||||
static uint32 RenderableDeviceCount = sizeof(RenderableDevices) / sizeof(RenderableDevices[0]);
|
||||
#endif // #if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
|
||||
static UObject* FindDeviceMesh(const int32 DeviceID);
|
||||
}; // namespace OculusAssetManager_Impl
|
||||
|
||||
static UObject* OculusAssetManager_Impl::FindDeviceMesh(const int32 DeviceID)
|
||||
{
|
||||
UObject* DeviceMesh = nullptr;
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
const ovrpNode DeviceOVRNode = OculusXRHMD::ToOvrpNode(DeviceID);
|
||||
|
||||
bool bUseSystemHeadsetType = false;
|
||||
ovrpSystemHeadset HeadsetType;
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetSystemHeadsetType2(&HeadsetType)))
|
||||
{
|
||||
bUseSystemHeadsetType = true;
|
||||
}
|
||||
|
||||
if (DeviceOVRNode != ovrpNode_None)
|
||||
{
|
||||
for (uint32 DeviceIndex = 0; DeviceIndex < RenderableDeviceCount; ++DeviceIndex)
|
||||
{
|
||||
const FRenderableDevice& RenderableDevice = RenderableDevices[DeviceIndex];
|
||||
if (RenderableDevice.OVRNode == DeviceOVRNode)
|
||||
{
|
||||
// If we have information about the current headset, load the model based of the headset information, otherwise load defaults.
|
||||
if (bUseSystemHeadsetType)
|
||||
{
|
||||
if (HeadsetType >= RenderableDevice.MinDeviceRange && HeadsetType <= RenderableDevice.MaxDeviceRange)
|
||||
{
|
||||
DeviceMesh = RenderableDevice.MeshAssetRef.TryLoad();
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DeviceMesh = RenderableDevice.MeshAssetRef.TryLoad();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return DeviceMesh;
|
||||
}
|
||||
|
||||
/* FOculusAssetManager
|
||||
*****************************************************************************/
|
||||
|
||||
FOculusAssetManager::FOculusAssetManager()
|
||||
{
|
||||
IModularFeatures::Get().RegisterModularFeature(IXRSystemAssets::GetModularFeatureName(), this);
|
||||
|
||||
ResourceHolder = NewObject<UOculusXRResourceHolder>();
|
||||
ResourceHolder->AddToRoot();
|
||||
}
|
||||
|
||||
FOculusAssetManager::~FOculusAssetManager()
|
||||
{
|
||||
if (ResourceHolder)
|
||||
{
|
||||
ResourceHolder->ConditionalBeginDestroy();
|
||||
ResourceHolder = nullptr;
|
||||
}
|
||||
|
||||
IModularFeatures::Get().UnregisterModularFeature(IXRSystemAssets::GetModularFeatureName(), this);
|
||||
}
|
||||
|
||||
bool FOculusAssetManager::EnumerateRenderableDevices(TArray<int32>& DeviceListOut)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
using namespace OculusAssetManager_Impl;
|
||||
DeviceListOut.Empty(RenderableDeviceCount);
|
||||
|
||||
for (uint32 DeviceIndex = 0; DeviceIndex < RenderableDeviceCount; ++DeviceIndex)
|
||||
{
|
||||
const FRenderableDevice& RenderableDevice = RenderableDevices[DeviceIndex];
|
||||
|
||||
const int32 ExternalDeviceId = OculusXRHMD::ToExternalDeviceId(RenderableDevice.OVRNode);
|
||||
DeviceListOut.Add(ExternalDeviceId);
|
||||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
int32 FOculusAssetManager::GetDeviceId(EControllerHand ControllerHand)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
ovrpNode ControllerOVRNode = ovrpNode_None;
|
||||
|
||||
switch (ControllerHand)
|
||||
{
|
||||
case EControllerHand::AnyHand:
|
||||
// @TODO: maybe check if the right is tracking, if not choose left (if tracking)?
|
||||
case EControllerHand::Right:
|
||||
ControllerOVRNode = ovrpNode_HandRight;
|
||||
break;
|
||||
case EControllerHand::Left:
|
||||
ControllerOVRNode = ovrpNode_HandLeft;
|
||||
break;
|
||||
|
||||
case EControllerHand::ExternalCamera:
|
||||
ControllerOVRNode = ovrpNode_TrackerZero;
|
||||
break;
|
||||
// case EControllerHand::Special_1:
|
||||
// ControllerOVRNode = ovrpNode_TrackerOne;
|
||||
// break;
|
||||
// case EControllerHand::Special_2:
|
||||
// ControllerOVRNode = ovrpNode_TrackerTwo;
|
||||
// break;
|
||||
// case EControllerHand::Special_3:
|
||||
// ControllerOVRNode = ovrpNode_TrackerThree;
|
||||
// break;
|
||||
|
||||
// case EControllerHand::Special_4:
|
||||
// ControllerOVRNode = ovrpNode_DeviceObjectZero;
|
||||
// break;
|
||||
|
||||
default:
|
||||
// ControllerOVRNode = ovrpNode_None => returns -1
|
||||
break;
|
||||
}
|
||||
return OculusXRHMD::ToExternalDeviceId(ControllerOVRNode);
|
||||
#else
|
||||
return INDEX_NONE;
|
||||
#endif
|
||||
}
|
||||
|
||||
UPrimitiveComponent* FOculusAssetManager::CreateRenderComponent(const int32 DeviceId, AActor* Owner, EObjectFlags Flags, const bool /*bForceSynchronous*/, const FXRComponentLoadComplete& OnLoadComplete)
|
||||
{
|
||||
UPrimitiveComponent* NewRenderComponent = nullptr;
|
||||
if (UObject* DeviceMesh = OculusAssetManager_Impl::FindDeviceMesh(DeviceId))
|
||||
{
|
||||
if (UStaticMesh* AsStaticMesh = Cast<UStaticMesh>(DeviceMesh))
|
||||
{
|
||||
const FName ComponentName = MakeUniqueObjectName(Owner, UStaticMeshComponent::StaticClass(), *FString::Printf(TEXT("%s_Device%d"), TEXT("Oculus"), DeviceId));
|
||||
UStaticMeshComponent* MeshComponent = NewObject<UStaticMeshComponent>(Owner, ComponentName, Flags);
|
||||
|
||||
MeshComponent->SetStaticMesh(AsStaticMesh);
|
||||
NewRenderComponent = MeshComponent;
|
||||
}
|
||||
else if (USkeletalMesh* AsSkeletalMesh = Cast<USkeletalMesh>(DeviceMesh))
|
||||
{
|
||||
const FName ComponentName = MakeUniqueObjectName(Owner, USkeletalMeshComponent::StaticClass(), *FString::Printf(TEXT("%s_Device%d"), TEXT("Oculus"), DeviceId));
|
||||
USkeletalMeshComponent* SkelMeshComponent = NewObject<USkeletalMeshComponent>(Owner, ComponentName, Flags);
|
||||
|
||||
SkelMeshComponent->SetSkeletalMesh(AsSkeletalMesh);
|
||||
NewRenderComponent = SkelMeshComponent;
|
||||
}
|
||||
NewRenderComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision);
|
||||
}
|
||||
|
||||
OnLoadComplete.ExecuteIfBound(NewRenderComponent);
|
||||
return NewRenderComponent;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "IXRSystemAssets.h"
|
||||
#include "OculusXRResourceHolder.h"
|
||||
#include "UObject/SoftObjectPtr.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class FOculusAssetManager : public IXRSystemAssets
|
||||
{
|
||||
public:
|
||||
FOculusAssetManager();
|
||||
virtual ~FOculusAssetManager();
|
||||
|
||||
public:
|
||||
UOculusXRResourceHolder* GetResourceHolder() { return ResourceHolder; }
|
||||
|
||||
//~ IXRSystemAssets interface
|
||||
|
||||
virtual bool EnumerateRenderableDevices(TArray<int32>& DeviceListOut) override;
|
||||
virtual int32 GetDeviceId(EControllerHand ControllerHand) override;
|
||||
virtual UPrimitiveComponent* CreateRenderComponent(const int32 DeviceId, AActor* Owner, EObjectFlags Flags, const bool bForceSynchronous, const FXRComponentLoadComplete& OnLoadComplete) override;
|
||||
|
||||
protected:
|
||||
UOculusXRResourceHolder* ResourceHolder;
|
||||
};
|
||||
@@ -0,0 +1,8 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "OculusXRDelegates.h"
|
||||
|
||||
FOculusEventDelegates::FOculusDisplayRefreshRateChangedEvent FOculusEventDelegates::OculusDisplayRefreshRateChanged;
|
||||
|
||||
FOculusEventDelegates::FOculusEyeTrackingStateChangedEvent FOculusEventDelegates::OculusEyeTrackingStateChanged;
|
||||
@@ -0,0 +1,19 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreTypes.h"
|
||||
#include "Delegates/Delegate.h"
|
||||
|
||||
class FOculusEventDelegates
|
||||
{
|
||||
public:
|
||||
/** When the display refresh rate is changed */
|
||||
DECLARE_MULTICAST_DELEGATE_TwoParams(FOculusDisplayRefreshRateChangedEvent, float /*fromRefreshRate*/, float /*toRefreshRate*/);
|
||||
static FOculusDisplayRefreshRateChangedEvent OculusDisplayRefreshRateChanged;
|
||||
|
||||
/** When the eye tracking status changes */
|
||||
DECLARE_MULTICAST_DELEGATE_OneParam(FOculusEyeTrackingStateChangedEvent, bool /*bIsEyeTrackingOn*/);
|
||||
static FOculusEyeTrackingStateChangedEvent OculusEyeTrackingStateChanged;
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright 1998-2020 Epic Games, Inc. All Rights Reserved.
|
||||
#include "OculusXREventComponent.h"
|
||||
#include "OculusXRHMD.h"
|
||||
#include "OculusXRDelegates.h"
|
||||
|
||||
void UOculusXREventComponent::OnRegister()
|
||||
{
|
||||
Super::OnRegister();
|
||||
|
||||
FOculusEventDelegates::OculusDisplayRefreshRateChanged.AddUObject(this, &UOculusXREventComponent::OculusDisplayRefreshRateChanged_Handler);
|
||||
FOculusEventDelegates::OculusEyeTrackingStateChanged.AddUObject(this, &UOculusXREventComponent::OculusEyeTrackingStateChanged_Handler);
|
||||
}
|
||||
|
||||
void UOculusXREventComponent::OnUnregister()
|
||||
{
|
||||
Super::OnUnregister();
|
||||
|
||||
FOculusEventDelegates::OculusDisplayRefreshRateChanged.RemoveAll(this);
|
||||
FOculusEventDelegates::OculusEyeTrackingStateChanged.RemoveAll(this);
|
||||
}
|
||||
@@ -0,0 +1,768 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "OculusXRFunctionLibrary.h"
|
||||
#include "OculusXRFunctionLibraryOpenXR.h"
|
||||
#include "OculusXRFunctionLibraryOVR.h"
|
||||
#include "OculusXRHMDPrivate.h"
|
||||
#include "OculusXRHMD.h"
|
||||
#include "OpenXR/OculusXROpenXRUtilities.h"
|
||||
#include "Logging/MessageLog.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "OculusFunctionLibrary"
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// UOculusXRFunctionLibrary
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> UOculusXRFunctionLibrary::FunctionLibraryImpl = nullptr;
|
||||
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> UOculusXRFunctionLibrary::GetOculusXRFunctionImpl()
|
||||
{
|
||||
if (FunctionLibraryImpl == nullptr)
|
||||
{
|
||||
if (OculusXR::IsOpenXRSystem())
|
||||
{
|
||||
FunctionLibraryImpl = MakeShared<OculusXRHMD::FOculusXRFunctionLibraryOpenXR>();
|
||||
}
|
||||
else
|
||||
{
|
||||
FunctionLibraryImpl = MakeShared<OculusXRHMD::FOculusXRFunctionLibraryOVR>();
|
||||
}
|
||||
}
|
||||
return FunctionLibraryImpl;
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::ShutdownXRFunctionLibrary()
|
||||
{
|
||||
FunctionLibraryImpl = nullptr;
|
||||
}
|
||||
|
||||
UOculusXRFunctionLibrary::UOculusXRFunctionLibrary(const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
}
|
||||
|
||||
OculusXRHMD::FOculusXRHMD* UOculusXRFunctionLibrary::GetOculusXRHMD()
|
||||
{
|
||||
return OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::GetPose(FRotator& DeviceRotation, FVector& DevicePosition, FVector& NeckPosition, bool bUseOrienationForPlayerCamera, bool bUsePositionForPlayerCamera, const FVector PositionScale)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Impl->GetPose(DeviceRotation, DevicePosition, NeckPosition);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
DeviceRotation = FRotator::ZeroRotator;
|
||||
DevicePosition = FVector::ZeroVector;
|
||||
NeckPosition = FVector::ZeroVector;
|
||||
}
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::SetBaseRotationAndBaseOffsetInMeters(FRotator Rotation, FVector BaseOffsetInMeters, EOrientPositionSelector::Type Options)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Impl->SetBaseRotationAndBaseOffsetInMeters(Rotation, BaseOffsetInMeters, Options);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::GetBaseRotationAndBaseOffsetInMeters(FRotator& OutRotation, FVector& OutBaseOffsetInMeters)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Impl->GetBaseRotationAndBaseOffsetInMeters(OutRotation, OutBaseOffsetInMeters);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::GetRawSensorData(FVector& AngularAcceleration, FVector& LinearAcceleration, FVector& AngularVelocity, FVector& LinearVelocity, float& TimeInSeconds, EOculusXRTrackedDeviceType DeviceType)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Impl->GetRawSensorData(AngularAcceleration, LinearAcceleration, AngularVelocity, LinearVelocity, TimeInSeconds, DeviceType);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool UOculusXRFunctionLibrary::IsDeviceTracked(EOculusXRTrackedDeviceType DeviceType)
|
||||
{
|
||||
bool bIsDeviceTracked = false;
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
bIsDeviceTracked = Impl->IsDeviceTracked(DeviceType);
|
||||
}
|
||||
#endif
|
||||
return bIsDeviceTracked;
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::GetSuggestedCpuAndGpuPerformanceLevels(EOculusXRProcessorPerformanceLevel& CpuPerfLevel, EOculusXRProcessorPerformanceLevel& GpuPerfLevel)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Impl->GetSuggestedCpuAndGpuPerformanceLevels(CpuPerfLevel, GpuPerfLevel);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::SetSuggestedCpuAndGpuPerformanceLevels(EOculusXRProcessorPerformanceLevel CpuPerfLevel, EOculusXRProcessorPerformanceLevel GpuPerfLevel)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Impl->SetSuggestedCpuAndGpuPerformanceLevels(CpuPerfLevel, GpuPerfLevel);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::SetCPUAndGPULevels(int CPULevel, int GPULevel)
|
||||
{
|
||||
// Deprecated. Please use Get/SetSuggestedCpuAndGpuPerformanceLevels instead.
|
||||
}
|
||||
|
||||
bool UOculusXRFunctionLibrary::GetUserProfile(FOculusXRHmdUserProfile& Profile)
|
||||
{
|
||||
bool bGetUserProfile = false;
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
bGetUserProfile = Impl->GetUserProfile(Profile);
|
||||
}
|
||||
#endif
|
||||
return bGetUserProfile;
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::SetBaseRotationAndPositionOffset(FRotator BaseRot, FVector PosOffset, EOrientPositionSelector::Type Options)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Impl->SetBaseRotationAndPositionOffset(BaseRot, PosOffset, Options);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::GetBaseRotationAndPositionOffset(FRotator& OutRot, FVector& OutPosOffset)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Impl->GetBaseRotationAndPositionOffset(OutRot, OutPosOffset);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::AddLoadingSplashScreen(class UTexture2D* Texture, FVector TranslationInMeters, FRotator Rotation, FVector2D SizeInMeters, FRotator DeltaRotation, bool bClearBeforeAdd)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Impl->AddLoadingSplashScreen(Texture, TranslationInMeters, Rotation, SizeInMeters, DeltaRotation, bClearBeforeAdd);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::ClearLoadingSplashScreens()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Impl->ClearLoadingSplashScreens();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool UOculusXRFunctionLibrary::HasInputFocus()
|
||||
{
|
||||
bool bHasInputFocus = false;
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
bHasInputFocus = Impl->HasInputFocus();
|
||||
}
|
||||
#endif
|
||||
return bHasInputFocus;
|
||||
}
|
||||
|
||||
bool UOculusXRFunctionLibrary::HasSystemOverlayPresent()
|
||||
{
|
||||
bool bHasSystemOverlayPresent = false;
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
bHasSystemOverlayPresent = Impl->HasSystemOverlayPresent();
|
||||
}
|
||||
#endif
|
||||
return bHasSystemOverlayPresent;
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::GetGPUUtilization(bool& IsGPUAvailable, float& GPUUtilization)
|
||||
{
|
||||
GPUUtilization = 0.0f;
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Impl->GetGPUUtilization(IsGPUAvailable, GPUUtilization);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
float UOculusXRFunctionLibrary::GetGPUFrameTime()
|
||||
{
|
||||
float FrameTime = 0;
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
FrameTime = Impl->GetGPUFrameTime();
|
||||
}
|
||||
#endif
|
||||
return FrameTime;
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::GetPerformanceMetrics(FOculusXRPerformanceMetrics& PerformanceMetrics)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Impl->GetPerformanceMetrics(PerformanceMetrics);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
EOculusXRFoveatedRenderingMethod UOculusXRFunctionLibrary::GetFoveatedRenderingMethod()
|
||||
{
|
||||
EOculusXRFoveatedRenderingMethod FoveatedRenderingMethod = EOculusXRFoveatedRenderingMethod::FixedFoveatedRendering;
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
FoveatedRenderingMethod = Impl->GetFoveatedRenderingMethod();
|
||||
}
|
||||
#endif
|
||||
return FoveatedRenderingMethod;
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::SetFoveatedRenderingMethod(EOculusXRFoveatedRenderingMethod Method)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Impl->SetFoveatedRenderingMethod(Method);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::SetFoveatedRenderingLevel(EOculusXRFoveatedRenderingLevel level, bool isDynamic)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Impl->SetFoveatedRenderingLevel(level, isDynamic);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
EOculusXRFoveatedRenderingLevel UOculusXRFunctionLibrary::GetFoveatedRenderingLevel()
|
||||
{
|
||||
EOculusXRFoveatedRenderingLevel FoveatedRenderingLevel = EOculusXRFoveatedRenderingLevel::Off;
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
FoveatedRenderingLevel = Impl->GetFoveatedRenderingLevel();
|
||||
}
|
||||
#endif
|
||||
return FoveatedRenderingLevel;
|
||||
}
|
||||
|
||||
bool UOculusXRFunctionLibrary::GetEyeTrackedFoveatedRenderingSupported()
|
||||
{
|
||||
bool bEyeTrackedFoveatedRenderingSupported = false;
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
bEyeTrackedFoveatedRenderingSupported = Impl->GetEyeTrackedFoveatedRenderingSupported();
|
||||
}
|
||||
#endif
|
||||
return bEyeTrackedFoveatedRenderingSupported;
|
||||
}
|
||||
|
||||
FString UOculusXRFunctionLibrary::GetDeviceName()
|
||||
{
|
||||
FString DeviceName;
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
DeviceName = Impl->GetDeviceName();
|
||||
}
|
||||
#endif
|
||||
return DeviceName;
|
||||
}
|
||||
|
||||
EOculusXRDeviceType UOculusXRFunctionLibrary::GetDeviceType()
|
||||
{
|
||||
EOculusXRDeviceType DeviceType = EOculusXRDeviceType::OculusUnknown;
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
DeviceType = Impl->GetDeviceType();
|
||||
}
|
||||
#endif
|
||||
return DeviceType;
|
||||
}
|
||||
|
||||
EOculusXRControllerType UOculusXRFunctionLibrary::GetControllerType(EControllerHand deviceHand)
|
||||
{
|
||||
EOculusXRControllerType ControllerType = EOculusXRControllerType::Unknown;
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
ControllerType = Impl->GetControllerType(deviceHand);
|
||||
}
|
||||
#endif
|
||||
return ControllerType;
|
||||
}
|
||||
|
||||
TArray<float> UOculusXRFunctionLibrary::GetAvailableDisplayFrequencies()
|
||||
{
|
||||
TArray<float> FreqArray;
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
FreqArray = Impl->GetAvailableDisplayFrequencies();
|
||||
}
|
||||
#endif
|
||||
return FreqArray;
|
||||
}
|
||||
|
||||
float UOculusXRFunctionLibrary::GetCurrentDisplayFrequency()
|
||||
{
|
||||
float Frequency = 0.0f;
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Frequency = Impl->GetCurrentDisplayFrequency();
|
||||
}
|
||||
#endif
|
||||
return Frequency;
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::SetDisplayFrequency(float RequestedFrequency)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Impl->SetDisplayFrequency(RequestedFrequency);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::EnablePositionTracking(bool bPositionTracking)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Impl->EnablePositionTracking(bPositionTracking);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::EnableOrientationTracking(bool bOrientationTracking)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Impl->EnableOrientationTracking(bOrientationTracking);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::SetColorScaleAndOffset(FLinearColor ColorScale, FLinearColor ColorOffset, bool bApplyToAllLayers)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Impl->SetColorScaleAndOffset(ColorScale, ColorOffset, bApplyToAllLayers);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
class IStereoLayers* UOculusXRFunctionLibrary::GetStereoLayers()
|
||||
{
|
||||
IStereoLayers* Layers = nullptr;
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Layers = Impl->GetStereoLayers();
|
||||
}
|
||||
#endif
|
||||
return Layers;
|
||||
}
|
||||
|
||||
bool UOculusXRFunctionLibrary::IsGuardianConfigured()
|
||||
{
|
||||
bool bIsGuardianConfigured = false;
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
bIsGuardianConfigured = Impl->IsGuardianConfigured();
|
||||
}
|
||||
#endif
|
||||
return bIsGuardianConfigured;
|
||||
}
|
||||
|
||||
bool UOculusXRFunctionLibrary::IsGuardianDisplayed()
|
||||
{
|
||||
bool bIsGuardianDisplayed = false;
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
bIsGuardianDisplayed = Impl->IsGuardianDisplayed();
|
||||
}
|
||||
#endif
|
||||
return bIsGuardianDisplayed;
|
||||
}
|
||||
|
||||
TArray<FVector> UOculusXRFunctionLibrary::GetGuardianPoints(EOculusXRBoundaryType BoundaryType, bool UsePawnSpace /* = false */)
|
||||
{
|
||||
TArray<FVector> BoundaryPointList;
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
BoundaryPointList = Impl->GetGuardianPoints(BoundaryType, UsePawnSpace);
|
||||
}
|
||||
#endif
|
||||
return BoundaryPointList;
|
||||
}
|
||||
|
||||
FVector UOculusXRFunctionLibrary::GetGuardianDimensions(EOculusXRBoundaryType BoundaryType)
|
||||
{
|
||||
FVector Dimensions = FVector::ZeroVector;
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Dimensions = Impl->GetGuardianDimensions(BoundaryType);
|
||||
}
|
||||
#endif
|
||||
return Dimensions;
|
||||
}
|
||||
|
||||
FTransform UOculusXRFunctionLibrary::GetPlayAreaTransform()
|
||||
{
|
||||
FTransform Transform;
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Transform = Impl->GetPlayAreaTransform();
|
||||
}
|
||||
#endif
|
||||
return Transform;
|
||||
}
|
||||
|
||||
FOculusXRGuardianTestResult UOculusXRFunctionLibrary::GetPointGuardianIntersection(const FVector Point, EOculusXRBoundaryType BoundaryType)
|
||||
{
|
||||
FOculusXRGuardianTestResult InteractionInfo;
|
||||
memset(&InteractionInfo, 0, sizeof(FOculusXRGuardianTestResult));
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
InteractionInfo = Impl->GetPointGuardianIntersection(Point, BoundaryType);
|
||||
}
|
||||
#endif
|
||||
return InteractionInfo;
|
||||
}
|
||||
|
||||
FOculusXRGuardianTestResult UOculusXRFunctionLibrary::GetNodeGuardianIntersection(EOculusXRTrackedDeviceType DeviceType, EOculusXRBoundaryType BoundaryType)
|
||||
{
|
||||
FOculusXRGuardianTestResult InteractionInfo;
|
||||
memset(&InteractionInfo, 0, sizeof(FOculusXRGuardianTestResult));
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
InteractionInfo = Impl->GetNodeGuardianIntersection(DeviceType, BoundaryType);
|
||||
}
|
||||
#endif
|
||||
return InteractionInfo;
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::SetGuardianVisibility(bool GuardianVisible)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Impl->SetGuardianVisibility(GuardianVisible);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool UOculusXRFunctionLibrary::GetSystemHmd3DofModeEnabled()
|
||||
{
|
||||
bool bGetSystemHmd3DofModeEnabled = false;
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
bGetSystemHmd3DofModeEnabled = Impl->GetSystemHmd3DofModeEnabled();
|
||||
}
|
||||
#endif
|
||||
return bGetSystemHmd3DofModeEnabled;
|
||||
}
|
||||
|
||||
EOculusXRColorSpace UOculusXRFunctionLibrary::GetHmdColorDesc()
|
||||
{
|
||||
EOculusXRColorSpace HmdColorSpace = EOculusXRColorSpace::Unknown;
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
HmdColorSpace = Impl->GetHmdColorDesc();
|
||||
}
|
||||
#endif
|
||||
return HmdColorSpace;
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::SetClientColorDesc(EOculusXRColorSpace ColorSpace)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Impl->SetClientColorDesc(ColorSpace);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::SetLocalDimmingOn(bool LocalDimmingOn)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Impl->SetLocalDimmingOn(LocalDimmingOn);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool UOculusXRFunctionLibrary::IsPassthroughSupported()
|
||||
{
|
||||
bool bIsPassthroughSupported = false;
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
bIsPassthroughSupported = Impl->IsPassthroughSupported();
|
||||
}
|
||||
#endif
|
||||
return bIsPassthroughSupported;
|
||||
}
|
||||
|
||||
bool UOculusXRFunctionLibrary::IsColorPassthroughSupported()
|
||||
{
|
||||
bool bIsColorPassthroughSupported = false;
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
bIsColorPassthroughSupported = Impl->IsColorPassthroughSupported();
|
||||
}
|
||||
#endif
|
||||
return bIsColorPassthroughSupported;
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::StartEnvironmentDepth()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Impl->StartEnvironmentDepth();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::StopEnvironmentDepth()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Impl->StopEnvironmentDepth();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool UOculusXRFunctionLibrary::IsEnvironmentDepthStarted()
|
||||
{
|
||||
bool bIsEnvironmentDepthStarted = false;
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
bIsEnvironmentDepthStarted = Impl->IsEnvironmentDepthStarted();
|
||||
}
|
||||
#endif
|
||||
return bIsEnvironmentDepthStarted;
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::SetEnvironmentDepthHandRemoval(bool RemoveHands)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Impl->SetEnvironmentDepthHandRemoval(RemoveHands);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::SetXROcclusionsMode(UObject* WorldContextObject, EOculusXROcclusionsMode Mode)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Impl->SetXROcclusionsMode(WorldContextObject, Mode);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::SetEyeBufferSharpenType(EOculusXREyeBufferSharpenType EyeBufferSharpenType)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Impl->SetEyeBufferSharpenType(EyeBufferSharpenType);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool UOculusXRFunctionLibrary::IsPassthroughRecommended()
|
||||
{
|
||||
bool bIsPassthroughRecommended = false;
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
bIsPassthroughRecommended = Impl->IsPassthroughRecommended();
|
||||
}
|
||||
#endif
|
||||
return bIsPassthroughRecommended;
|
||||
}
|
||||
void UOculusXRFunctionLibrary::GetOpenXRInstanceProcAddrFunc(void** func)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Impl->GetOpenXRInstanceProcAddrFunc(func);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::GetNativeOpenXRHandles(uint64_t* OutXrInstance, uint64_t* OutXrSession)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Impl->GetNativeOpenXRHandles(OutXrInstance, OutXrSession);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::GetAppSpace(uint64_t* OutAppSpace)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Impl->GetAppSpace(OutAppSpace);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::GetNextPredictedDisplayTime(uint64_t* NextPredictedDisplayTime)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Impl->GetNextPredictedDisplayTime(NextPredictedDisplayTime);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::RegisterOpenXrEventHandler(void (*OpenXrEventHandler)(void* data, void* context), void* Context)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Impl->RegisterOpenXrEventHandler(OpenXrEventHandler, Context);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::UnregisterOpenXrEventHandler(void (*OpenXrEventHandler)(void* data, void* context))
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
TSharedPtr<OculusXRHMD::IOculusXRFunctionLibrary> Impl = GetOculusXRFunctionImpl();
|
||||
if (Impl != nullptr)
|
||||
{
|
||||
Impl->UnregisterOpenXrEventHandler(OpenXrEventHandler);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
@@ -0,0 +1,903 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#include "OculusXRFunctionLibraryOVR.h"
|
||||
|
||||
#include "OculusXRHMD.h"
|
||||
#include "OpenXR/OculusXROpenXRUtilities.h"
|
||||
|
||||
namespace OculusXRHMD
|
||||
{
|
||||
void FOculusXRFunctionLibraryOVR::GetPose(FRotator& DeviceRotation, FVector& DevicePosition, FVector& NeckPosition)
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD && OculusXRHMD->IsHeadTrackingAllowed())
|
||||
{
|
||||
FQuat HeadOrientation = FQuat::Identity;
|
||||
FVector HeadPosition = FVector::ZeroVector;
|
||||
OculusXRHMD->GetCurrentPose(OculusXRHMD->HMDDeviceId, HeadOrientation, HeadPosition);
|
||||
DeviceRotation = HeadOrientation.Rotator();
|
||||
DevicePosition = HeadPosition;
|
||||
NeckPosition = OculusXRHMD->GetNeckPosition(HeadOrientation, HeadPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
DeviceRotation = FRotator::ZeroRotator;
|
||||
DevicePosition = FVector::ZeroVector;
|
||||
NeckPosition = FVector::ZeroVector;
|
||||
}
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOVR::SetBaseRotationAndBaseOffsetInMeters(FRotator Rotation, FVector BaseOffsetInMeters, EOrientPositionSelector::Type Options)
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
if ((Options == EOrientPositionSelector::Orientation) || (Options == EOrientPositionSelector::OrientationAndPosition))
|
||||
{
|
||||
OculusXRHMD->SetBaseRotation(Rotation);
|
||||
}
|
||||
if ((Options == EOrientPositionSelector::Position) || (Options == EOrientPositionSelector::OrientationAndPosition))
|
||||
{
|
||||
OculusXRHMD->SetBaseOffsetInMeters(BaseOffsetInMeters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOVR::GetBaseRotationAndBaseOffsetInMeters(FRotator& OutRotation, FVector& OutBaseOffsetInMeters)
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
OutRotation = OculusXRHMD->GetBaseRotation();
|
||||
OutBaseOffsetInMeters = OculusXRHMD->GetBaseOffsetInMeters();
|
||||
}
|
||||
else
|
||||
{
|
||||
OutRotation = FRotator::ZeroRotator;
|
||||
OutBaseOffsetInMeters = FVector::ZeroVector;
|
||||
}
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOVR::GetRawSensorData(FVector& AngularAcceleration, FVector& LinearAcceleration, FVector& AngularVelocity, FVector& LinearVelocity, float& TimeInSeconds, EOculusXRTrackedDeviceType DeviceType)
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr && OculusXRHMD->IsHMDActive())
|
||||
{
|
||||
ovrpPoseStatef state;
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetNodePoseState3(ovrpStep_Render, OVRP_CURRENT_FRAMEINDEX, OculusXRHMD::ToOvrpNode(DeviceType), &state)))
|
||||
{
|
||||
AngularAcceleration = OculusXRHMD::ToFVector(state.AngularAcceleration);
|
||||
LinearAcceleration = OculusXRHMD::ToFVector(state.Acceleration);
|
||||
AngularVelocity = OculusXRHMD::ToFVector(state.AngularVelocity);
|
||||
LinearVelocity = OculusXRHMD::ToFVector(state.Velocity);
|
||||
TimeInSeconds = state.Time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool FOculusXRFunctionLibraryOVR::IsDeviceTracked(EOculusXRTrackedDeviceType DeviceType)
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr && OculusXRHMD->IsHMDActive())
|
||||
{
|
||||
ovrpBool Present;
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetNodePresent2(OculusXRHMD::ToOvrpNode(DeviceType), &Present)))
|
||||
{
|
||||
return Present != ovrpBool_False;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOVR::GetSuggestedCpuAndGpuPerformanceLevels(EOculusXRProcessorPerformanceLevel& CpuPerfLevel, EOculusXRProcessorPerformanceLevel& GpuPerfLevel)
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr && OculusXRHMD->IsHMDActive())
|
||||
{
|
||||
OculusXRHMD->GetSuggestedCpuAndGpuPerformanceLevels(CpuPerfLevel, GpuPerfLevel);
|
||||
}
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOVR::SetSuggestedCpuAndGpuPerformanceLevels(EOculusXRProcessorPerformanceLevel CpuPerfLevel, EOculusXRProcessorPerformanceLevel GpuPerfLevel)
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr && OculusXRHMD->IsHMDActive())
|
||||
{
|
||||
OculusXRHMD->SetSuggestedCpuAndGpuPerformanceLevels(CpuPerfLevel, GpuPerfLevel);
|
||||
}
|
||||
}
|
||||
|
||||
bool FOculusXRFunctionLibraryOVR::GetUserProfile(FOculusXRHmdUserProfile& Profile)
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD::UserProfile Data;
|
||||
if (OculusXRHMD->GetUserProfile(Data))
|
||||
{
|
||||
Profile.Name = "";
|
||||
Profile.Gender = "Unknown";
|
||||
Profile.PlayerHeight = 0.0f;
|
||||
Profile.EyeHeight = Data.EyeHeight;
|
||||
Profile.IPD = Data.IPD;
|
||||
Profile.NeckToEyeDistance = FVector2D(Data.EyeDepth, 0.0f);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOVR::SetBaseRotationAndPositionOffset(FRotator BaseRot, FVector PosOffset, EOrientPositionSelector::Type Options)
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
if (Options == EOrientPositionSelector::Orientation || Options == EOrientPositionSelector::OrientationAndPosition)
|
||||
{
|
||||
OculusXRHMD->SetBaseRotation(BaseRot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOVR::GetBaseRotationAndPositionOffset(FRotator& OutRot, FVector& OutPosOffset)
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
OutRot = OculusXRHMD->GetBaseRotation();
|
||||
OutPosOffset = FVector::ZeroVector;
|
||||
}
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOVR::AddLoadingSplashScreen(class UTexture2D* Texture, FVector TranslationInMeters, FRotator Rotation, FVector2D SizeInMeters, FRotator DeltaRotation, bool bClearBeforeAdd)
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
OculusXRHMD::FSplash* Splash = OculusXRHMD->GetSplash();
|
||||
if (Splash)
|
||||
{
|
||||
if (bClearBeforeAdd)
|
||||
{
|
||||
Splash->ClearSplashes();
|
||||
}
|
||||
|
||||
FOculusXRSplashDesc Desc;
|
||||
Desc.LoadingTexture = Texture;
|
||||
Desc.QuadSizeInMeters = SizeInMeters;
|
||||
Desc.TransformInMeters = FTransform(Rotation, TranslationInMeters);
|
||||
Desc.DeltaRotation = FQuat(DeltaRotation);
|
||||
Splash->AddSplash(Desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOVR::ClearLoadingSplashScreens()
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
OculusXRHMD::FSplash* Splash = OculusXRHMD->GetSplash();
|
||||
if (Splash)
|
||||
{
|
||||
Splash->ClearSplashes();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool FOculusXRFunctionLibraryOVR::HasInputFocus()
|
||||
{
|
||||
const OculusXRHMD::FOculusXRHMD* const OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr && OculusXRHMD->IsHMDActive())
|
||||
{
|
||||
ovrpBool HasFocus;
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetAppHasInputFocus(&HasFocus)))
|
||||
{
|
||||
return HasFocus != ovrpBool_False;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FOculusXRFunctionLibraryOVR::HasSystemOverlayPresent()
|
||||
{
|
||||
const OculusXRHMD::FOculusXRHMD* const OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr && OculusXRHMD->IsHMDActive())
|
||||
{
|
||||
ovrpBool HasFocus;
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetAppHasInputFocus(&HasFocus)))
|
||||
{
|
||||
return HasFocus == ovrpBool_False;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOVR::GetGPUUtilization(bool& IsGPUAvailable, float& GPUUtilization)
|
||||
{
|
||||
GPUUtilization = 0.0f;
|
||||
const OculusXRHMD::FOculusXRHMD* const OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
ovrpBool bIsSupported = ovrpBool_False;
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().IsPerfMetricsSupported(ovrpPerfMetrics_System_GpuUtilPercentage_Float, &bIsSupported)) && bIsSupported == ovrpBool_True)
|
||||
{
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetPerfMetricsFloat(ovrpPerfMetrics_System_GpuUtilPercentage_Float, &GPUUtilization)))
|
||||
{
|
||||
IsGPUAvailable = true;
|
||||
GPUUtilization *= 100;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float FOculusXRFunctionLibraryOVR::GetGPUFrameTime()
|
||||
{
|
||||
float FrameTime = 0;
|
||||
const OculusXRHMD::FOculusXRHMD* const OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
ovrpBool bIsSupported = ovrpBool_False;
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().IsPerfMetricsSupported(ovrpPerfMetrics_App_GpuTime_Float, &bIsSupported)) && bIsSupported == ovrpBool_True)
|
||||
{
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetPerfMetricsFloat(ovrpPerfMetrics_App_GpuTime_Float, &FrameTime)))
|
||||
{
|
||||
return FrameTime * 1000;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOVR::GetPerformanceMetrics(FOculusXRPerformanceMetrics& PerformanceMetrics)
|
||||
{
|
||||
const OculusXRHMD::FOculusXRHMD* const OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
PerformanceMetrics = OculusXRHMD->GetPerformanceMetrics();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
EOculusXRFoveatedRenderingMethod FOculusXRFunctionLibraryOVR::GetFoveatedRenderingMethod()
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
ovrpBool enabled;
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetFoveationEyeTracked(&enabled)))
|
||||
{
|
||||
return enabled == ovrpBool_True ? EOculusXRFoveatedRenderingMethod::EyeTrackedFoveatedRendering : EOculusXRFoveatedRenderingMethod::FixedFoveatedRendering;
|
||||
}
|
||||
}
|
||||
return EOculusXRFoveatedRenderingMethod::FixedFoveatedRendering;
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOVR::SetFoveatedRenderingMethod(EOculusXRFoveatedRenderingMethod Method)
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
OculusXRHMD->SetFoveatedRenderingMethod(Method);
|
||||
}
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOVR::SetFoveatedRenderingLevel(EOculusXRFoveatedRenderingLevel level, bool isDynamic)
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
OculusXRHMD->SetFoveatedRenderingLevel(level, isDynamic);
|
||||
}
|
||||
}
|
||||
|
||||
EOculusXRFoveatedRenderingLevel FOculusXRFunctionLibraryOVR::GetFoveatedRenderingLevel()
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
ovrpTiledMultiResLevel Lvl;
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetTiledMultiResLevel(&Lvl)))
|
||||
{
|
||||
return (EOculusXRFoveatedRenderingLevel)Lvl;
|
||||
}
|
||||
}
|
||||
return EOculusXRFoveatedRenderingLevel::Off;
|
||||
}
|
||||
|
||||
bool FOculusXRFunctionLibraryOVR::GetEyeTrackedFoveatedRenderingSupported()
|
||||
{
|
||||
// Always return false on other engine releases, since they don't have FDM offset support
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
ovrpBool Supported;
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetFoveationEyeTrackedSupported(&Supported)))
|
||||
{
|
||||
return Supported == ovrpBool_True;
|
||||
}
|
||||
}
|
||||
#endif // WITH_OCULUS_BRANCH
|
||||
return false;
|
||||
}
|
||||
|
||||
FString FOculusXRFunctionLibraryOVR::GetDeviceName()
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
const char* NameString;
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetSystemProductName2(&NameString)) && NameString)
|
||||
{
|
||||
return FString(NameString);
|
||||
}
|
||||
}
|
||||
return FString();
|
||||
}
|
||||
|
||||
EOculusXRDeviceType FOculusXRFunctionLibraryOVR::GetDeviceType()
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
if (OculusXRHMD->GetSettings())
|
||||
{
|
||||
switch (OculusXRHMD->GetSettings()->SystemHeadset)
|
||||
{
|
||||
case ovrpSystemHeadset_Oculus_Quest:
|
||||
return EOculusXRDeviceType::OculusQuest_Deprecated;
|
||||
case ovrpSystemHeadset_Oculus_Quest_2:
|
||||
return EOculusXRDeviceType::OculusQuest2;
|
||||
case ovrpSystemHeadset_Meta_Quest_Pro:
|
||||
return EOculusXRDeviceType::MetaQuestPro;
|
||||
case ovrpSystemHeadset_Meta_Quest_3:
|
||||
return EOculusXRDeviceType::MetaQuest3;
|
||||
case ovrpSystemHeadset_Meta_Quest_3S:
|
||||
return EOculusXRDeviceType::MetaQuest3S;
|
||||
case ovrpSystemHeadset_Rift_CV1:
|
||||
return EOculusXRDeviceType::Rift;
|
||||
case ovrpSystemHeadset_Rift_S:
|
||||
return EOculusXRDeviceType::Rift_S;
|
||||
case ovrpSystemHeadset_Oculus_Link_Quest:
|
||||
return EOculusXRDeviceType::Quest_Link_Deprecated;
|
||||
case ovrpSystemHeadset_Oculus_Link_Quest_2:
|
||||
return EOculusXRDeviceType::Quest2_Link;
|
||||
case ovrpSystemHeadset_Meta_Link_Quest_Pro:
|
||||
return EOculusXRDeviceType::MetaQuestProLink;
|
||||
case ovrpSystemHeadset_Meta_Link_Quest_3:
|
||||
return EOculusXRDeviceType::MetaQuest3Link;
|
||||
case ovrpSystemHeadset_Meta_Link_Quest_3S:
|
||||
return EOculusXRDeviceType::MetaQuest3SLink;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return EOculusXRDeviceType::OculusUnknown;
|
||||
}
|
||||
|
||||
EOculusXRControllerType FOculusXRFunctionLibraryOVR::GetControllerType(EControllerHand deviceHand)
|
||||
{
|
||||
auto getOVRPHand = [](EControllerHand hand) {
|
||||
switch (hand)
|
||||
{
|
||||
case EControllerHand::Left:
|
||||
return ovrpHand::ovrpHand_Left;
|
||||
case EControllerHand::Right:
|
||||
return ovrpHand::ovrpHand_Right;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ovrpHand::ovrpHand_None;
|
||||
};
|
||||
|
||||
auto getEControllerType = [](ovrpInteractionProfile profile) {
|
||||
switch (profile)
|
||||
{
|
||||
case ovrpInteractionProfile::ovrpInteractionProfile_Touch:
|
||||
return EOculusXRControllerType::MetaQuestTouch;
|
||||
case ovrpInteractionProfile::ovrpInteractionProfile_TouchPro:
|
||||
return EOculusXRControllerType::MetaQuestTouchPro;
|
||||
case ovrpInteractionProfile::ovrpInteractionProfile_TouchPlus:
|
||||
return EOculusXRControllerType::MetaQuestTouchPlus;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return EOculusXRControllerType::None;
|
||||
};
|
||||
|
||||
ovrpInteractionProfile interactionProfile = ovrpInteractionProfile::ovrpInteractionProfile_None;
|
||||
ovrpHand hand = getOVRPHand(deviceHand);
|
||||
if (hand == ovrpHand::ovrpHand_None)
|
||||
return EOculusXRControllerType::Unknown;
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetCurrentInteractionProfile(hand, &interactionProfile)))
|
||||
{
|
||||
return getEControllerType(interactionProfile);
|
||||
}
|
||||
return EOculusXRControllerType::Unknown;
|
||||
}
|
||||
|
||||
TArray<float> FOculusXRFunctionLibraryOVR::GetAvailableDisplayFrequencies()
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
int NumberOfFrequencies;
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetSystemDisplayAvailableFrequencies(nullptr, &NumberOfFrequencies)))
|
||||
{
|
||||
TArray<float> freqArray;
|
||||
freqArray.SetNum(NumberOfFrequencies);
|
||||
FOculusXRHMDModule::GetPluginWrapper().GetSystemDisplayAvailableFrequencies(freqArray.GetData(), &NumberOfFrequencies);
|
||||
return freqArray;
|
||||
}
|
||||
}
|
||||
return TArray<float>();
|
||||
}
|
||||
|
||||
float FOculusXRFunctionLibraryOVR::GetCurrentDisplayFrequency()
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
float Frequency;
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetSystemDisplayFrequency2(&Frequency)))
|
||||
{
|
||||
return Frequency;
|
||||
}
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOVR::SetDisplayFrequency(float RequestedFrequency)
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
FOculusXRHMDModule::GetPluginWrapper().SetSystemDisplayFrequency(RequestedFrequency);
|
||||
}
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOVR::EnablePositionTracking(bool bPositionTracking)
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
FOculusXRHMDModule::GetPluginWrapper().SetTrackingPositionEnabled2(bPositionTracking);
|
||||
}
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOVR::EnableOrientationTracking(bool bOrientationTracking)
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
FOculusXRHMDModule::GetPluginWrapper().SetTrackingOrientationEnabled2(bOrientationTracking);
|
||||
}
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOVR::SetColorScaleAndOffset(FLinearColor ColorScale, FLinearColor ColorOffset, bool bApplyToAllLayers)
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
OculusXRHMD->SetColorScaleAndOffset(ColorScale, ColorOffset, bApplyToAllLayers);
|
||||
}
|
||||
}
|
||||
|
||||
class IStereoLayers* FOculusXRFunctionLibraryOVR::GetStereoLayers()
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
return OculusXRHMD;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static ovrpBoundaryType ToOvrpBoundaryType(EOculusXRBoundaryType Source)
|
||||
{
|
||||
switch (Source)
|
||||
{
|
||||
case EOculusXRBoundaryType::Boundary_PlayArea:
|
||||
return ovrpBoundary_PlayArea;
|
||||
|
||||
case EOculusXRBoundaryType::Boundary_Outer:
|
||||
default:
|
||||
return ovrpBoundary_Outer;
|
||||
}
|
||||
}
|
||||
|
||||
bool FOculusXRFunctionLibraryOVR::IsGuardianConfigured()
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
ovrpBool boundaryConfigured;
|
||||
return OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetBoundaryConfigured2(&boundaryConfigured)) && boundaryConfigured;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FOculusXRFunctionLibraryOVR::IsGuardianDisplayed()
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
ovrpBool boundaryVisible;
|
||||
return OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetBoundaryVisible2(&boundaryVisible)) && boundaryVisible;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
TArray<FVector> FOculusXRFunctionLibraryOVR::GetGuardianPoints(EOculusXRBoundaryType BoundaryType, bool UsePawnSpace /* = false */)
|
||||
{
|
||||
TArray<FVector> BoundaryPointList;
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
ovrpBool bBoundaryConfigured = false;
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetBoundaryConfigured2(&bBoundaryConfigured)) && bBoundaryConfigured)
|
||||
{
|
||||
ovrpBoundaryType obt = ToOvrpBoundaryType(BoundaryType);
|
||||
int NumPoints = 0;
|
||||
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetBoundaryGeometry3(obt, nullptr, &NumPoints)))
|
||||
{
|
||||
// allocate points
|
||||
const int BufferSize = NumPoints;
|
||||
ovrpVector3f* BoundaryPoints = new ovrpVector3f[BufferSize];
|
||||
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetBoundaryGeometry3(obt, BoundaryPoints, &NumPoints)))
|
||||
{
|
||||
NumPoints = FMath::Min(BufferSize, NumPoints);
|
||||
check(NumPoints <= BufferSize); // For static analyzer
|
||||
BoundaryPointList.Reserve(NumPoints);
|
||||
|
||||
for (int i = 0; i < NumPoints; i++)
|
||||
{
|
||||
FVector point;
|
||||
if (UsePawnSpace)
|
||||
{
|
||||
point = OculusXRHMD->ConvertVector_M2U(BoundaryPoints[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
point = OculusXRHMD->ScaleAndMovePointWithPlayer(BoundaryPoints[i]);
|
||||
}
|
||||
BoundaryPointList.Add(point);
|
||||
}
|
||||
}
|
||||
|
||||
delete[] BoundaryPoints;
|
||||
}
|
||||
}
|
||||
}
|
||||
return BoundaryPointList;
|
||||
}
|
||||
|
||||
FVector FOculusXRFunctionLibraryOVR::GetGuardianDimensions(EOculusXRBoundaryType BoundaryType)
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
ovrpBoundaryType obt = ToOvrpBoundaryType(BoundaryType);
|
||||
ovrpVector3f Dimensions;
|
||||
|
||||
if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().GetBoundaryDimensions2(obt, &Dimensions)))
|
||||
return FVector::ZeroVector;
|
||||
|
||||
Dimensions.z *= -1.0;
|
||||
return OculusXRHMD->ConvertVector_M2U(Dimensions);
|
||||
}
|
||||
return FVector::ZeroVector;
|
||||
}
|
||||
|
||||
FTransform FOculusXRFunctionLibraryOVR::GetPlayAreaTransform()
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
ovrpBool bBoundaryConfigured = false;
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetBoundaryConfigured2(&bBoundaryConfigured)) && bBoundaryConfigured)
|
||||
{
|
||||
int NumPoints = 4;
|
||||
ovrpVector3f BoundaryPoints[4];
|
||||
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetBoundaryGeometry3(ovrpBoundary_PlayArea, BoundaryPoints, &NumPoints)))
|
||||
{
|
||||
FVector ConvertedPoints[4];
|
||||
|
||||
for (int i = 0; i < NumPoints; i++)
|
||||
{
|
||||
ConvertedPoints[i] = OculusXRHMD->ScaleAndMovePointWithPlayer(BoundaryPoints[i]);
|
||||
}
|
||||
|
||||
float metersScale = OculusXRHMD->GetWorldToMetersScale();
|
||||
|
||||
FVector Edge = ConvertedPoints[1] - ConvertedPoints[0];
|
||||
float Angle = FMath::Acos((Edge).GetSafeNormal() | FVector::RightVector);
|
||||
FQuat Rotation(FVector::UpVector, Edge.X < 0 ? Angle : -Angle);
|
||||
|
||||
FVector Position = (ConvertedPoints[0] + ConvertedPoints[1] + ConvertedPoints[2] + ConvertedPoints[3]) / 4;
|
||||
FVector Scale(FVector::Distance(ConvertedPoints[3], ConvertedPoints[0]) / metersScale, FVector::Distance(ConvertedPoints[1], ConvertedPoints[0]) / metersScale, 1.0);
|
||||
|
||||
return FTransform(Rotation, Position, Scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
return FTransform();
|
||||
}
|
||||
|
||||
FOculusXRGuardianTestResult FOculusXRFunctionLibraryOVR::GetPointGuardianIntersection(const FVector Point, EOculusXRBoundaryType BoundaryType)
|
||||
{
|
||||
FOculusXRGuardianTestResult InteractionInfo;
|
||||
memset(&InteractionInfo, 0, sizeof(FOculusXRGuardianTestResult));
|
||||
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
ovrpVector3f OvrpPoint = OculusXRHMD->WorldLocationToOculusPoint(Point);
|
||||
ovrpBoundaryType OvrpBoundaryType = ToOvrpBoundaryType(BoundaryType);
|
||||
ovrpBoundaryTestResult InteractionResult;
|
||||
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().TestBoundaryPoint2(OvrpPoint, OvrpBoundaryType, &InteractionResult)))
|
||||
{
|
||||
InteractionInfo.IsTriggering = (InteractionResult.IsTriggering != 0);
|
||||
InteractionInfo.ClosestDistance = OculusXRHMD->ConvertFloat_M2U(InteractionResult.ClosestDistance);
|
||||
InteractionInfo.ClosestPoint = OculusXRHMD->ScaleAndMovePointWithPlayer(InteractionResult.ClosestPoint);
|
||||
InteractionInfo.ClosestPointNormal = OculusXRHMD->ConvertVector_M2U(InteractionResult.ClosestPointNormal);
|
||||
InteractionInfo.DeviceType = EOculusXRTrackedDeviceType::None;
|
||||
}
|
||||
}
|
||||
|
||||
return InteractionInfo;
|
||||
}
|
||||
|
||||
FOculusXRGuardianTestResult FOculusXRFunctionLibraryOVR::GetNodeGuardianIntersection(EOculusXRTrackedDeviceType DeviceType, EOculusXRBoundaryType BoundaryType)
|
||||
{
|
||||
FOculusXRGuardianTestResult InteractionInfo;
|
||||
memset(&InteractionInfo, 0, sizeof(FOculusXRGuardianTestResult));
|
||||
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
ovrpNode OvrpNode = OculusXRHMD::ToOvrpNode(DeviceType);
|
||||
ovrpBoundaryType OvrpBoundaryType = ToOvrpBoundaryType(BoundaryType);
|
||||
ovrpBoundaryTestResult TestResult;
|
||||
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().TestBoundaryNode2(OvrpNode, ovrpBoundary_PlayArea, &TestResult)) && TestResult.IsTriggering)
|
||||
{
|
||||
InteractionInfo.IsTriggering = true;
|
||||
InteractionInfo.DeviceType = OculusXRHMD::ToEOculusXRTrackedDeviceType(OvrpNode);
|
||||
InteractionInfo.ClosestDistance = OculusXRHMD->ConvertFloat_M2U(TestResult.ClosestDistance);
|
||||
InteractionInfo.ClosestPoint = OculusXRHMD->ScaleAndMovePointWithPlayer(TestResult.ClosestPoint);
|
||||
InteractionInfo.ClosestPointNormal = OculusXRHMD->ConvertVector_M2U(TestResult.ClosestPointNormal);
|
||||
}
|
||||
}
|
||||
|
||||
return InteractionInfo;
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOVR::SetGuardianVisibility(bool GuardianVisible)
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
FOculusXRHMDModule::GetPluginWrapper().SetBoundaryVisible2(GuardianVisible);
|
||||
}
|
||||
}
|
||||
|
||||
bool FOculusXRFunctionLibraryOVR::GetSystemHmd3DofModeEnabled()
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
ovrpBool enabled;
|
||||
return OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetSystemHmd3DofModeEnabled(&enabled)) && enabled;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
EOculusXRColorSpace FOculusXRFunctionLibraryOVR::GetHmdColorDesc()
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
ovrpColorSpace HmdColorSpace;
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetHmdColorDesc(&HmdColorSpace)))
|
||||
{
|
||||
return (EOculusXRColorSpace)HmdColorSpace;
|
||||
}
|
||||
}
|
||||
return EOculusXRColorSpace::Unknown;
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOVR::SetClientColorDesc(EOculusXRColorSpace ColorSpace)
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
ovrpColorSpace ClientColorSpace = (ovrpColorSpace)ColorSpace;
|
||||
#if PLATFORM_ANDROID
|
||||
if (ClientColorSpace == ovrpColorSpace_Unknown)
|
||||
{
|
||||
ClientColorSpace = ovrpColorSpace_Quest;
|
||||
}
|
||||
#endif
|
||||
FOculusXRHMDModule::GetPluginWrapper().SetClientColorDesc(ClientColorSpace);
|
||||
}
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOVR::SetLocalDimmingOn(bool LocalDimmingOn)
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
UE_LOG(LogHMD, Log, TEXT("SetLocalDimmingOn %d"), LocalDimmingOn);
|
||||
FOculusXRHMDModule::GetPluginWrapper().SetLocalDimming(LocalDimmingOn);
|
||||
}
|
||||
}
|
||||
|
||||
bool FOculusXRFunctionLibraryOVR::IsPassthroughSupported()
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
ovrpInsightPassthroughCapabilityFlags capabilities;
|
||||
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetPassthroughCapabilityFlags(&capabilities)))
|
||||
{
|
||||
return (capabilities & ovrpInsightPassthroughCapabilityFlags::ovrpInsightPassthroughCapabilityFlags_Passthrough)
|
||||
== ovrpInsightPassthroughCapabilityFlags::ovrpInsightPassthroughCapabilityFlags_Passthrough;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FOculusXRFunctionLibraryOVR::IsColorPassthroughSupported()
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
ovrpInsightPassthroughCapabilityFlags capabilities;
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetPassthroughCapabilityFlags(&capabilities)))
|
||||
{
|
||||
return (capabilities & ovrpInsightPassthroughCapabilityFlags::ovrpInsightPassthroughCapabilityFlags_Color)
|
||||
== ovrpInsightPassthroughCapabilityFlags::ovrpInsightPassthroughCapabilityFlags_Color;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOVR::StartEnvironmentDepth()
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
int CreateFlags = 0;
|
||||
OculusXRHMD->StartEnvironmentDepth(CreateFlags);
|
||||
}
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOVR::StopEnvironmentDepth()
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
OculusXRHMD->StopEnvironmentDepth();
|
||||
}
|
||||
}
|
||||
|
||||
bool FOculusXRFunctionLibraryOVR::IsEnvironmentDepthStarted()
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
return OculusXRHMD->IsEnvironmentDepthStarted();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOVR::SetEnvironmentDepthHandRemoval(bool RemoveHands)
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
OculusXRHMD->SetEnvironmentDepthHandRemoval(RemoveHands);
|
||||
}
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOVR::SetXROcclusionsMode(UObject* WorldContextObject, EOculusXROcclusionsMode Mode)
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
OculusXRHMD->EnableHardOcclusions(Mode == EOculusXROcclusionsMode::HardOcclusions_Deprecated);
|
||||
OculusXRHMD->EnableSoftOcclusions(Mode == EOculusXROcclusionsMode::SoftOcclusions);
|
||||
}
|
||||
#if defined(WITH_OCULUS_BRANCH)
|
||||
WorldContextObject->GetWorld()->Scene->SetEnableXRPassthroughSoftOcclusions(Mode == EOculusXROcclusionsMode::SoftOcclusions);
|
||||
#else
|
||||
ensureMsgf(Mode != EOculusXROcclusionsMode::SoftOcclusions, TEXT("Soft occlusions are only supported with the Oculus branch of the Unreal Engine"));
|
||||
#endif
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOVR::SetEyeBufferSharpenType(EOculusXREyeBufferSharpenType EyeBufferSharpenType)
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
switch (EyeBufferSharpenType)
|
||||
{
|
||||
case EOculusXREyeBufferSharpenType::SLST_Normal:
|
||||
FOculusXRHMDModule::GetPluginWrapper().SetEyeBufferSharpenType(ovrpLayerSubmitFlag_EfficientSharpen);
|
||||
break;
|
||||
case EOculusXREyeBufferSharpenType::SLST_Quality:
|
||||
FOculusXRHMDModule::GetPluginWrapper().SetEyeBufferSharpenType(ovrpLayerSubmitFlag_QualitySharpen);
|
||||
break;
|
||||
case EOculusXREyeBufferSharpenType::SLST_Auto:
|
||||
FOculusXRHMDModule::GetPluginWrapper().SetEyeBufferSharpenType(ovrpLayerSubmitFlag_AutoLayerFilter);
|
||||
break;
|
||||
default:
|
||||
FOculusXRHMDModule::GetPluginWrapper().SetEyeBufferSharpenType(ovrpLayerSubmitFlags(0));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool FOculusXRFunctionLibraryOVR::IsPassthroughRecommended()
|
||||
{
|
||||
const OculusXRHMD::FOculusXRHMD* OculusHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD();
|
||||
if (OculusHMD != nullptr)
|
||||
{
|
||||
ovrpPassthroughPreferences Preferences;
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetPassthroughPreferences(&Preferences)))
|
||||
{
|
||||
return (Preferences.Flags & ovrpPassthroughPreferenceFlags::ovrpPassthroughPreferenceFlags_DefaultToActive)
|
||||
== ovrpPassthroughPreferenceFlags::ovrpPassthroughPreferenceFlags_DefaultToActive;
|
||||
};
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOVR::GetOpenXRInstanceProcAddrFunc(void** func)
|
||||
{
|
||||
FOculusXRHMDModule::GetPluginWrapper().GetOpenXRInstanceProcAddrFunc(func);
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOVR::GetNativeOpenXRHandles(uint64_t* OutXrInstance, uint64_t* OutXrSession)
|
||||
{
|
||||
FOculusXRHMDModule::GetPluginWrapper().GetNativeOpenXRHandles((ovrpUInt64*)OutXrInstance, (ovrpUInt64*)OutXrSession);
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOVR::GetAppSpace(uint64_t* OutAppSpace)
|
||||
{
|
||||
FOculusXRHMDModule::GetPluginWrapper().GetAppSpace((ovrpUInt64*)OutAppSpace);
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOVR::GetNextPredictedDisplayTime(uint64_t* NextPredictedDisplayTime)
|
||||
{
|
||||
double Time = 0;
|
||||
FOculusXRHMDModule::GetPluginWrapper().GetPredictedDisplayTime(OVRP_CURRENT_FRAMEINDEX, &Time);
|
||||
*NextPredictedDisplayTime = OculusXR::ToXrTime(Time);
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOVR::RegisterOpenXrEventHandler(void (*OpenXrEventHandler)(void* data, void* context), void* Context)
|
||||
{
|
||||
FOculusXRHMDModule::GetPluginWrapper().RegisterOpenXREventHandler(OpenXrEventHandler, Context);
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOVR::UnregisterOpenXrEventHandler(void (*OpenXrEventHandler)(void* data, void* context))
|
||||
{
|
||||
FOculusXRHMDModule::GetPluginWrapper().UnregisterOpenXREventHandler(OpenXrEventHandler);
|
||||
}
|
||||
|
||||
} // namespace OculusXRHMD
|
||||
@@ -0,0 +1,74 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "OculusXRFunctionLibrary.h"
|
||||
|
||||
namespace OculusXRHMD
|
||||
{
|
||||
class FOculusXRFunctionLibraryOVR : public IOculusXRFunctionLibrary
|
||||
{
|
||||
public:
|
||||
virtual void GetPose(FRotator& DeviceRotation, FVector& DevicePosition, FVector& NeckPosition) override;
|
||||
virtual void SetBaseRotationAndBaseOffsetInMeters(FRotator Rotation, FVector BaseOffsetInMeters, EOrientPositionSelector::Type Options) override;
|
||||
virtual void GetBaseRotationAndBaseOffsetInMeters(FRotator& OutRotation, FVector& OutBaseOffsetInMeters) override;
|
||||
virtual void GetRawSensorData(FVector& AngularAcceleration, FVector& LinearAcceleration, FVector& AngularVelocity, FVector& LinearVelocity, float& TimeInSeconds, EOculusXRTrackedDeviceType DeviceType) override;
|
||||
virtual bool IsDeviceTracked(EOculusXRTrackedDeviceType DeviceType) override;
|
||||
virtual void GetSuggestedCpuAndGpuPerformanceLevels(EOculusXRProcessorPerformanceLevel& CpuPerfLevel, EOculusXRProcessorPerformanceLevel& GpuPerfLevel) override;
|
||||
virtual void SetSuggestedCpuAndGpuPerformanceLevels(EOculusXRProcessorPerformanceLevel CpuPerfLevel, EOculusXRProcessorPerformanceLevel GpuPerfLevel) override;
|
||||
virtual bool GetUserProfile(FOculusXRHmdUserProfile& Profile) override;
|
||||
virtual void SetBaseRotationAndPositionOffset(FRotator BaseRot, FVector PosOffset, EOrientPositionSelector::Type Options) override;
|
||||
virtual void GetBaseRotationAndPositionOffset(FRotator& OutRot, FVector& OutPosOffset) override;
|
||||
virtual void AddLoadingSplashScreen(class UTexture2D* Texture, FVector TranslationInMeters, FRotator Rotation, FVector2D SizeInMeters, FRotator DeltaRotation, bool bClearBeforeAdd) override;
|
||||
virtual void ClearLoadingSplashScreens() override;
|
||||
virtual bool HasInputFocus() override;
|
||||
virtual bool HasSystemOverlayPresent() override;
|
||||
virtual void GetGPUUtilization(bool& IsGPUAvailable, float& GPUUtilization) override;
|
||||
virtual float GetGPUFrameTime() override;
|
||||
virtual void GetPerformanceMetrics(FOculusXRPerformanceMetrics& PerformanceMetrics) override;
|
||||
|
||||
|
||||
virtual EOculusXRFoveatedRenderingMethod GetFoveatedRenderingMethod() override;
|
||||
virtual void SetFoveatedRenderingMethod(EOculusXRFoveatedRenderingMethod Method) override;
|
||||
virtual void SetFoveatedRenderingLevel(EOculusXRFoveatedRenderingLevel level, bool isDynamic) override;
|
||||
virtual EOculusXRFoveatedRenderingLevel GetFoveatedRenderingLevel() override;
|
||||
virtual bool GetEyeTrackedFoveatedRenderingSupported() override;
|
||||
virtual FString GetDeviceName() override;
|
||||
virtual EOculusXRDeviceType GetDeviceType() override;
|
||||
virtual EOculusXRControllerType GetControllerType(EControllerHand deviceHand) override;
|
||||
virtual TArray<float> GetAvailableDisplayFrequencies() override;
|
||||
virtual float GetCurrentDisplayFrequency() override;
|
||||
virtual void SetDisplayFrequency(float RequestedFrequency) override;
|
||||
virtual void EnablePositionTracking(bool bPositionTracking) override;
|
||||
virtual void EnableOrientationTracking(bool bOrientationTracking) override;
|
||||
virtual void SetColorScaleAndOffset(FLinearColor ColorScale, FLinearColor ColorOffset, bool bApplyToAllLayers) override;
|
||||
virtual class IStereoLayers* GetStereoLayers() override;
|
||||
virtual bool IsGuardianConfigured() override;
|
||||
virtual bool IsGuardianDisplayed() override;
|
||||
virtual TArray<FVector> GetGuardianPoints(EOculusXRBoundaryType BoundaryType, bool UsePawnSpace /* = false */) override;
|
||||
virtual FVector GetGuardianDimensions(EOculusXRBoundaryType BoundaryType) override;
|
||||
virtual FTransform GetPlayAreaTransform() override;
|
||||
virtual FOculusXRGuardianTestResult GetPointGuardianIntersection(const FVector Point, EOculusXRBoundaryType BoundaryType) override;
|
||||
virtual FOculusXRGuardianTestResult GetNodeGuardianIntersection(EOculusXRTrackedDeviceType DeviceType, EOculusXRBoundaryType BoundaryType) override;
|
||||
virtual void SetGuardianVisibility(bool GuardianVisible) override;
|
||||
virtual bool GetSystemHmd3DofModeEnabled() override;
|
||||
virtual EOculusXRColorSpace GetHmdColorDesc() override;
|
||||
virtual void SetClientColorDesc(EOculusXRColorSpace ColorSpace) override;
|
||||
virtual void SetLocalDimmingOn(bool LocalDimmingOn) override;
|
||||
virtual bool IsPassthroughSupported() override;
|
||||
virtual bool IsColorPassthroughSupported() override;
|
||||
virtual void StartEnvironmentDepth() override;
|
||||
virtual void StopEnvironmentDepth() override;
|
||||
virtual bool IsEnvironmentDepthStarted() override;
|
||||
virtual void SetEnvironmentDepthHandRemoval(bool RemoveHands) override;
|
||||
virtual void SetXROcclusionsMode(UObject* WorldContextObject, EOculusXROcclusionsMode Mode) override;
|
||||
virtual void SetEyeBufferSharpenType(EOculusXREyeBufferSharpenType EyeBufferSharpenType) override;
|
||||
virtual bool IsPassthroughRecommended() override;
|
||||
virtual void GetOpenXRInstanceProcAddrFunc(void** Func) override;
|
||||
virtual void GetNativeOpenXRHandles(uint64_t* OutXrInstance, uint64_t* OutXrSession) override;
|
||||
virtual void GetAppSpace(uint64_t* OutAppSpace) override;
|
||||
virtual void GetNextPredictedDisplayTime(uint64_t* NextPredictedDisplayTime) override;
|
||||
virtual void RegisterOpenXrEventHandler(void (*OpenXrEventHandler)(void* data, void* context), void* Context) override;
|
||||
virtual void UnregisterOpenXrEventHandler(void (*OpenXrEventHandler)(void* data, void* context)) override;
|
||||
};
|
||||
} // namespace OculusXRHMD
|
||||
@@ -0,0 +1,632 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#include "OculusXRFunctionLibraryOpenXR.h"
|
||||
|
||||
#include "OpenXR\OculusXRXRFunctions.h"
|
||||
#include "OculusXRHMD.h"
|
||||
#include "IOpenXRHMD.h"
|
||||
#include "OpenXR\OculusXROpenXRUtilities.h"
|
||||
#include "IOpenXRHMD.h"
|
||||
#include "IOpenXRHMDModule.h"
|
||||
#include "OpenXRBlueprintFunctionLibrary.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
struct HeadModelParms
|
||||
{
|
||||
float HeadModelDepth;
|
||||
float HeadModelHeight;
|
||||
};
|
||||
|
||||
// CompositorOpenXR Constants
|
||||
const HeadModelParms DefaultHeadModel = {
|
||||
0.0805f,
|
||||
0.0750f,
|
||||
};
|
||||
|
||||
FVector2D GetUserNeckEyeDistance()
|
||||
{
|
||||
return FVector2D(DefaultHeadModel.HeadModelDepth, DefaultHeadModel.HeadModelHeight);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
#define NOT_IMPLEMENTED() \
|
||||
UE_LOG(LogHMD, Log, TEXT("%s Not Implemented In OpenXR"), StringCast<TCHAR>(__FUNCTION__).Get());
|
||||
|
||||
namespace OculusXRHMD
|
||||
{
|
||||
void FOculusXRFunctionLibraryOpenXR::GetPose(FRotator& DeviceRotation, FVector& DevicePosition, FVector& NeckPosition)
|
||||
{
|
||||
FQuat HeadOrientation = FQuat::Identity;
|
||||
FVector HeadPosition = FVector::ZeroVector;
|
||||
|
||||
GEngine->XRSystem->GetCurrentPose(IXRTrackingSystem::HMDDeviceId, HeadOrientation, HeadPosition);
|
||||
|
||||
FVector LocalNeckPosition = HeadOrientation.Inverse().RotateVector(HeadPosition);
|
||||
const FVector2D NeckEyeDistance = GetUserNeckEyeDistance();
|
||||
|
||||
const float WorldToMetersScale = GEngine->XRSystem->GetWorldToMetersScale();
|
||||
LocalNeckPosition.X -= NeckEyeDistance.X * WorldToMetersScale;
|
||||
LocalNeckPosition.Z -= NeckEyeDistance.Y * WorldToMetersScale;
|
||||
|
||||
DeviceRotation = HeadOrientation.Rotator();
|
||||
DevicePosition = HeadPosition;
|
||||
NeckPosition = LocalNeckPosition;
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOpenXR::SetBaseRotationAndBaseOffsetInMeters(FRotator Rotation, FVector BaseOffsetInMeters, EOrientPositionSelector::Type Options)
|
||||
{
|
||||
if (GEngine->XRSystem.IsValid())
|
||||
{
|
||||
if ((Options == EOrientPositionSelector::Orientation) || (Options == EOrientPositionSelector::OrientationAndPosition))
|
||||
{
|
||||
GEngine->XRSystem->SetBaseRotation(Rotation);
|
||||
}
|
||||
if ((Options == EOrientPositionSelector::Position) || (Options == EOrientPositionSelector::OrientationAndPosition))
|
||||
{
|
||||
GEngine->XRSystem->SetBasePosition(BaseOffsetInMeters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOpenXR::GetBaseRotationAndBaseOffsetInMeters(FRotator& OutRotation, FVector& OutBaseOffsetInMeters)
|
||||
{
|
||||
if (GEngine->XRSystem.IsValid())
|
||||
{
|
||||
OutRotation = GEngine->XRSystem->GetBaseRotation();
|
||||
OutBaseOffsetInMeters = GEngine->XRSystem->GetBasePosition();
|
||||
}
|
||||
else
|
||||
{
|
||||
OutRotation = FRotator::ZeroRotator;
|
||||
OutBaseOffsetInMeters = FVector::ZeroVector;
|
||||
}
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOpenXR::GetRawSensorData(FVector& AngularAcceleration, FVector& LinearAcceleration, FVector& AngularVelocity, FVector& LinearVelocity, float& TimeInSeconds, EOculusXRTrackedDeviceType DeviceType)
|
||||
{
|
||||
NOT_IMPLEMENTED();
|
||||
}
|
||||
|
||||
static IMotionController* GetMotionController()
|
||||
{
|
||||
TArray<IMotionController*> MotionControllers;
|
||||
MotionControllers = IModularFeatures::Get().GetModularFeatureImplementations<IMotionController>(IMotionController::GetModularFeatureName());
|
||||
for (auto MotionController : MotionControllers)
|
||||
{
|
||||
FName MotionControllerName("OpenXR");
|
||||
if (MotionController != nullptr && MotionController->GetMotionControllerDeviceTypeName() == MotionControllerName)
|
||||
{
|
||||
return MotionController;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool IsControllerTracked(FName MotionSource)
|
||||
{
|
||||
IMotionController* MotionController = GetMotionController();
|
||||
if (MotionController != nullptr)
|
||||
{
|
||||
const int32_t ControllerIndex = 0;
|
||||
return MotionController->GetControllerTrackingStatus(ControllerIndex, MotionSource) == ETrackingStatus::Tracked;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FOculusXRFunctionLibraryOpenXR::IsDeviceTracked(EOculusXRTrackedDeviceType DeviceType)
|
||||
{
|
||||
bool bIsDeviceTracked = false;
|
||||
if (GEngine->XRSystem.IsValid())
|
||||
{
|
||||
switch (DeviceType)
|
||||
{
|
||||
case EOculusXRTrackedDeviceType::None:
|
||||
break;
|
||||
case EOculusXRTrackedDeviceType::HMD:
|
||||
if (GEngine->XRSystem.IsValid())
|
||||
{
|
||||
bIsDeviceTracked = GEngine->XRSystem->IsTracking(IXRTrackingSystem::HMDDeviceId);
|
||||
}
|
||||
break;
|
||||
case EOculusXRTrackedDeviceType::LTouch:
|
||||
{
|
||||
bIsDeviceTracked = IsControllerTracked(FName("LeftAim"));
|
||||
}
|
||||
break;
|
||||
case EOculusXRTrackedDeviceType::RTouch:
|
||||
{
|
||||
bIsDeviceTracked = IsControllerTracked(FName("RightAim"));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return bIsDeviceTracked;
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOpenXR::GetSuggestedCpuAndGpuPerformanceLevels(EOculusXRProcessorPerformanceLevel& CpuPerfLevel, EOculusXRProcessorPerformanceLevel& GpuPerfLevel)
|
||||
{
|
||||
OculusXR::FPerformanceExtensionPlugin& PerfPlugin = FOculusXRHMDModule::Get().GetExtensionPluginManager().GetPerformanceExtensionPlugin();
|
||||
PerfPlugin.GetSuggestedCpuAndGpuPerformanceLevels(CpuPerfLevel, GpuPerfLevel);
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOpenXR::SetSuggestedCpuAndGpuPerformanceLevels(EOculusXRProcessorPerformanceLevel CpuPerfLevel, EOculusXRProcessorPerformanceLevel GpuPerfLevel)
|
||||
{
|
||||
OculusXR::FPerformanceExtensionPlugin& PerfPlugin = FOculusXRHMDModule::Get().GetExtensionPluginManager().GetPerformanceExtensionPlugin();
|
||||
PerfPlugin.SetSuggestedCpuAndGpuPerformanceLevels(CpuPerfLevel, GpuPerfLevel);
|
||||
}
|
||||
|
||||
bool FOculusXRFunctionLibraryOpenXR::GetUserProfile(FOculusXRHmdUserProfile& Profile)
|
||||
{
|
||||
IXRTrackingSystem* TrackingSystem = OculusXR::GetOpenXRTrackingSystem();
|
||||
if (TrackingSystem != nullptr)
|
||||
{
|
||||
const IHeadMountedDisplay* Hmd = TrackingSystem->GetHMDDevice();
|
||||
if (Hmd != nullptr)
|
||||
{
|
||||
const float IPD = Hmd->GetInterpupillaryDistance();
|
||||
Profile.Name = "";
|
||||
Profile.Gender = "Unknown";
|
||||
Profile.PlayerHeight = 0.0f;
|
||||
Profile.EyeHeight = DefaultHeadModel.HeadModelHeight;
|
||||
Profile.IPD = IPD;
|
||||
Profile.NeckToEyeDistance = FVector2D(DefaultHeadModel.HeadModelDepth, 0.0f);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOpenXR::SetBaseRotationAndPositionOffset(FRotator BaseRot, FVector PosOffset, EOrientPositionSelector::Type Options)
|
||||
{
|
||||
NOT_IMPLEMENTED();
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOpenXR::GetBaseRotationAndPositionOffset(FRotator& OutRot, FVector& OutPosOffset)
|
||||
{
|
||||
NOT_IMPLEMENTED();
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOpenXR::AddLoadingSplashScreen(class UTexture2D* Texture, FVector TranslationInMeters, FRotator Rotation, FVector2D SizeInMeters, FRotator DeltaRotation, bool bClearBeforeAdd)
|
||||
{
|
||||
NOT_IMPLEMENTED();
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOpenXR::ClearLoadingSplashScreens()
|
||||
{
|
||||
NOT_IMPLEMENTED();
|
||||
}
|
||||
|
||||
bool FOculusXRFunctionLibraryOpenXR::HasInputFocus()
|
||||
{
|
||||
IXRTrackingSystem* TrackingSystem = OculusXR::GetOpenXRTrackingSystem();
|
||||
if (TrackingSystem != nullptr)
|
||||
{
|
||||
IOpenXRHMD* OpenXRHMD = TrackingSystem->GetIOpenXRHMD();
|
||||
if (OpenXRHMD != nullptr)
|
||||
{
|
||||
return OpenXRHMD->IsFocused();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FOculusXRFunctionLibraryOpenXR::HasSystemOverlayPresent()
|
||||
{
|
||||
IXRTrackingSystem* TrackingSystem = OculusXR::GetOpenXRTrackingSystem();
|
||||
if (TrackingSystem != nullptr)
|
||||
{
|
||||
IOpenXRHMD* OpenXRHMD = TrackingSystem->GetIOpenXRHMD();
|
||||
if (OpenXRHMD != nullptr)
|
||||
{
|
||||
return !OpenXRHMD->IsFocused();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOpenXR::GetGPUUtilization(bool& IsGPUAvailable, float& GPUUtilization)
|
||||
{
|
||||
OculusXR::FPerformanceExtensionPlugin& PerfPlugin = FOculusXRHMDModule::Get().GetExtensionPluginManager().GetPerformanceExtensionPlugin();
|
||||
const FOculusXRPerformanceMetrics& PerformanceMetrics = PerfPlugin.GetPerformanceMetrics();
|
||||
if (PerfPlugin.IsPerformanceMetricsSupported(OculusXR::GPUUtilizationFloat))
|
||||
{
|
||||
GPUUtilization = PerformanceMetrics.GpuUtil;
|
||||
IsGPUAvailable = true;
|
||||
}
|
||||
IsGPUAvailable = false;
|
||||
}
|
||||
|
||||
float FOculusXRFunctionLibraryOpenXR::GetGPUFrameTime()
|
||||
{
|
||||
OculusXR::FPerformanceExtensionPlugin& PerfPlugin = FOculusXRHMDModule::Get().GetExtensionPluginManager().GetPerformanceExtensionPlugin();
|
||||
const FOculusXRPerformanceMetrics& PerformanceMetrics = PerfPlugin.GetPerformanceMetrics();
|
||||
return PerformanceMetrics.AppGpuTime;
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOpenXR::GetPerformanceMetrics(FOculusXRPerformanceMetrics& PerformanceMetrics)
|
||||
{
|
||||
OculusXR::FPerformanceExtensionPlugin& PerfPlugin = FOculusXRHMDModule::Get().GetExtensionPluginManager().GetPerformanceExtensionPlugin();
|
||||
PerformanceMetrics = PerfPlugin.GetPerformanceMetrics();
|
||||
}
|
||||
|
||||
|
||||
EOculusXRFoveatedRenderingMethod FOculusXRFunctionLibraryOpenXR::GetFoveatedRenderingMethod()
|
||||
{
|
||||
NOT_IMPLEMENTED();
|
||||
return EOculusXRFoveatedRenderingMethod::FixedFoveatedRendering;
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOpenXR::SetFoveatedRenderingMethod(EOculusXRFoveatedRenderingMethod Method)
|
||||
{
|
||||
NOT_IMPLEMENTED();
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOpenXR::SetFoveatedRenderingLevel(EOculusXRFoveatedRenderingLevel level, bool isDynamic)
|
||||
{
|
||||
if (IConsoleVariable* FoveationLevelCVar = IConsoleManager::Get().FindConsoleVariable(TEXT("xr.OpenXRFBFoveationLevel")))
|
||||
{
|
||||
FoveationLevelCVar->Set(static_cast<int>(level));
|
||||
}
|
||||
if (IConsoleVariable* FoveationDynamicCVar = IConsoleManager::Get().FindConsoleVariable(TEXT("xr.OpenXRFBFoveationDynamic")))
|
||||
{
|
||||
FoveationDynamicCVar->Set(isDynamic);
|
||||
}
|
||||
}
|
||||
|
||||
EOculusXRFoveatedRenderingLevel FOculusXRFunctionLibraryOpenXR::GetFoveatedRenderingLevel()
|
||||
{
|
||||
const auto FoveationLevelCVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("xr.OpenXRFBFoveationLevel"));
|
||||
|
||||
return FoveationLevelCVar ? static_cast<EOculusXRFoveatedRenderingLevel>(FoveationLevelCVar->GetValueOnAnyThread()) : EOculusXRFoveatedRenderingLevel::Off;
|
||||
}
|
||||
|
||||
bool FOculusXRFunctionLibraryOpenXR::GetEyeTrackedFoveatedRenderingSupported()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FString FOculusXRFunctionLibraryOpenXR::GetDeviceName()
|
||||
{
|
||||
// deprecated
|
||||
return FString();
|
||||
}
|
||||
|
||||
EOculusXRDeviceType FOculusXRFunctionLibraryOpenXR::GetDeviceType()
|
||||
{
|
||||
#if defined(WITH_OCULUS_BRANCH)
|
||||
OculusXR::FSystemInfoExtensionPlugin& SystemPlugin = FOculusXRHMDModule::Get().GetExtensionPluginManager().GetSystemInfoExtensionPlugin();
|
||||
return SystemPlugin.GetDeviceType();
|
||||
#else // defined(WITH_OCULUS_BRANCH)
|
||||
NOT_IMPLEMENTED();
|
||||
return EOculusXRDeviceType::OculusUnknown;
|
||||
#endif // defined(WITH_OCULUS_BRANCH)
|
||||
}
|
||||
|
||||
EOculusXRControllerType FOculusXRFunctionLibraryOpenXR::GetControllerType(EControllerHand deviceHand)
|
||||
{
|
||||
#if defined(WITH_OCULUS_BRANCH)
|
||||
OculusXR::FSystemInfoExtensionPlugin& SystemPlugin = FOculusXRHMDModule::Get().GetExtensionPluginManager().GetSystemInfoExtensionPlugin();
|
||||
return SystemPlugin.GetControllerType(deviceHand);
|
||||
#else // defined(WITH_OCULUS_BRANCH)
|
||||
NOT_IMPLEMENTED();
|
||||
return EOculusXRControllerType::None;
|
||||
#endif // defined(WITH_OCULUS_BRANCH)
|
||||
}
|
||||
|
||||
TArray<float> FOculusXRFunctionLibraryOpenXR::GetAvailableDisplayFrequencies()
|
||||
{
|
||||
#if defined(WITH_OCULUS_BRANCH)
|
||||
OculusXR::FSystemInfoExtensionPlugin& SystemPlugin = FOculusXRHMDModule::Get().GetExtensionPluginManager().GetSystemInfoExtensionPlugin();
|
||||
return SystemPlugin.GetSystemDisplayAvailableFrequencies();
|
||||
#else // defined(WITH_OCULUS_BRANCH)
|
||||
NOT_IMPLEMENTED();
|
||||
return TArray<float>();
|
||||
#endif // defined(WITH_OCULUS_BRANCH)
|
||||
}
|
||||
|
||||
float FOculusXRFunctionLibraryOpenXR::GetCurrentDisplayFrequency()
|
||||
{
|
||||
#if defined(WITH_OCULUS_BRANCH)
|
||||
OculusXR::FSystemInfoExtensionPlugin& SystemPlugin = FOculusXRHMDModule::Get().GetExtensionPluginManager().GetSystemInfoExtensionPlugin();
|
||||
return SystemPlugin.GetSystemDisplayFrequency();
|
||||
#else // defined(WITH_OCULUS_BRANCH)
|
||||
NOT_IMPLEMENTED();
|
||||
return 0.0f;
|
||||
#endif // defined(WITH_OCULUS_BRANCH)
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOpenXR::SetDisplayFrequency(float RequestedFrequency)
|
||||
{
|
||||
#if defined(WITH_OCULUS_BRANCH)
|
||||
OculusXR::FSystemInfoExtensionPlugin& SystemPlugin = FOculusXRHMDModule::Get().GetExtensionPluginManager().GetSystemInfoExtensionPlugin();
|
||||
SystemPlugin.SetSystemDisplayFrequency(RequestedFrequency);
|
||||
#else // defined(WITH_OCULUS_BRANCH)
|
||||
NOT_IMPLEMENTED();
|
||||
#endif // defined(WITH_OCULUS_BRANCH)
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOpenXR::EnablePositionTracking(bool bPositionTracking)
|
||||
{
|
||||
NOT_IMPLEMENTED();
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOpenXR::EnableOrientationTracking(bool bOrientationTracking)
|
||||
{
|
||||
NOT_IMPLEMENTED();
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOpenXR::SetColorScaleAndOffset(FLinearColor ColorScale, FLinearColor ColorOffset, bool bApplyToAllLayers)
|
||||
{
|
||||
OculusXR::FLayerExtensionPlugin& Plugin = FOculusXRHMDModule::Get().GetExtensionPluginManager().GetLayerExtensionPlugin();
|
||||
Plugin.SetColorScaleAndOffset(ColorScale, ColorOffset, bApplyToAllLayers);
|
||||
}
|
||||
|
||||
class IStereoLayers* FOculusXRFunctionLibraryOpenXR::GetStereoLayers()
|
||||
{
|
||||
NOT_IMPLEMENTED();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool FOculusXRFunctionLibraryOpenXR::IsGuardianConfigured()
|
||||
{
|
||||
OculusXR::FGuardianExtensionPlugin& Plugin = FOculusXRHMDModule::Get().GetExtensionPluginManager().GetGuardianExtensionPlugin();
|
||||
return Plugin.IsGuardianConfigured();
|
||||
}
|
||||
|
||||
bool FOculusXRFunctionLibraryOpenXR::IsGuardianDisplayed()
|
||||
{
|
||||
// deprecated
|
||||
return false;
|
||||
}
|
||||
|
||||
TArray<FVector> FOculusXRFunctionLibraryOpenXR::GetGuardianPoints(EOculusXRBoundaryType BoundaryType, bool UsePawnSpace /* = false */)
|
||||
{
|
||||
if (BoundaryType != EOculusXRBoundaryType::Boundary_PlayArea)
|
||||
{
|
||||
UE_LOG(LogHMD, Log, TEXT("GetGuardianPoints: Only Boundary_PlayArea is applicable in OpenXR"));
|
||||
return TArray<FVector>();
|
||||
}
|
||||
|
||||
TArray<FVector> BoundaryPoints;
|
||||
IXRTrackingSystem* TrackingSystem = OculusXR::GetOpenXRTrackingSystem();
|
||||
|
||||
if (TrackingSystem != nullptr)
|
||||
{
|
||||
OculusXR::FGuardianExtensionPlugin& Plugin = FOculusXRHMDModule::Get().GetExtensionPluginManager().GetGuardianExtensionPlugin();
|
||||
Plugin.GetGuardianPoints(BoundaryPoints);
|
||||
}
|
||||
|
||||
return BoundaryPoints;
|
||||
}
|
||||
|
||||
FVector FOculusXRFunctionLibraryOpenXR::GetGuardianDimensions(EOculusXRBoundaryType BoundaryType)
|
||||
{
|
||||
OculusXR::FGuardianExtensionPlugin& Plugin = FOculusXRHMDModule::Get().GetExtensionPluginManager().GetGuardianExtensionPlugin();
|
||||
return Plugin.GetGuardianDimensions();
|
||||
}
|
||||
|
||||
FTransform FOculusXRFunctionLibraryOpenXR::GetPlayAreaTransform()
|
||||
{
|
||||
IXRTrackingSystem* TrackingSystem = OculusXR::GetOpenXRTrackingSystem();
|
||||
if (TrackingSystem != nullptr)
|
||||
{
|
||||
TArray<FVector> BoundaryPoints;
|
||||
OculusXR::FGuardianExtensionPlugin& Plugin = FOculusXRHMDModule::Get().GetExtensionPluginManager().GetGuardianExtensionPlugin();
|
||||
if (Plugin.GetGuardianPoints(BoundaryPoints))
|
||||
{
|
||||
check(BoundaryPoints.Num() == 4);
|
||||
const float WorldToMetersScale = TrackingSystem->GetWorldToMetersScale();
|
||||
|
||||
const FVector Edge = BoundaryPoints[1] - BoundaryPoints[0];
|
||||
const float Angle = FMath::Acos((Edge).GetSafeNormal() | FVector::RightVector);
|
||||
const FQuat Rotation(FVector::UpVector, Edge.X < 0 ? Angle : -Angle);
|
||||
|
||||
const FVector Position = (BoundaryPoints[0] + BoundaryPoints[1] + BoundaryPoints[2] + BoundaryPoints[3]) / 4;
|
||||
const FVector Scale(FVector::Distance(BoundaryPoints[3], BoundaryPoints[0]) / WorldToMetersScale, FVector::Distance(BoundaryPoints[1], BoundaryPoints[0]) / WorldToMetersScale, 1.0);
|
||||
|
||||
return FTransform(Rotation, Position, Scale);
|
||||
}
|
||||
}
|
||||
return FTransform();
|
||||
}
|
||||
|
||||
FOculusXRGuardianTestResult FOculusXRFunctionLibraryOpenXR::GetPointGuardianIntersection(const FVector Point, EOculusXRBoundaryType BoundaryType)
|
||||
{
|
||||
// deprecated
|
||||
FOculusXRGuardianTestResult InteractionInfo;
|
||||
memset(&InteractionInfo, 0, sizeof(FOculusXRGuardianTestResult));
|
||||
return InteractionInfo;
|
||||
}
|
||||
|
||||
FOculusXRGuardianTestResult FOculusXRFunctionLibraryOpenXR::GetNodeGuardianIntersection(EOculusXRTrackedDeviceType DeviceType, EOculusXRBoundaryType BoundaryType)
|
||||
{
|
||||
// deprecated
|
||||
FOculusXRGuardianTestResult InteractionInfo;
|
||||
memset(&InteractionInfo, 0, sizeof(FOculusXRGuardianTestResult));
|
||||
return InteractionInfo;
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOpenXR::SetGuardianVisibility(bool GuardianVisible)
|
||||
{
|
||||
// deprecated
|
||||
}
|
||||
|
||||
bool FOculusXRFunctionLibraryOpenXR::GetSystemHmd3DofModeEnabled()
|
||||
{
|
||||
NOT_IMPLEMENTED();
|
||||
return false;
|
||||
}
|
||||
|
||||
EOculusXRColorSpace FOculusXRFunctionLibraryOpenXR::GetHmdColorDesc()
|
||||
{
|
||||
#if defined(WITH_OCULUS_BRANCH)
|
||||
OculusXR::FSystemInfoExtensionPlugin& SystemPlugin = FOculusXRHMDModule::Get().GetExtensionPluginManager().GetSystemInfoExtensionPlugin();
|
||||
return SystemPlugin.GetColorSpace();
|
||||
#else // defined(WITH_OCULUS_BRANCH)
|
||||
NOT_IMPLEMENTED();
|
||||
return EOculusXRColorSpace::Unknown;
|
||||
#endif // defined(WITH_OCULUS_BRANCH)
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOpenXR::SetClientColorDesc(EOculusXRColorSpace ColorSpace)
|
||||
{
|
||||
#if defined(WITH_OCULUS_BRANCH)
|
||||
OculusXR::FSystemInfoExtensionPlugin& SystemPlugin = FOculusXRHMDModule::Get().GetExtensionPluginManager().GetSystemInfoExtensionPlugin();
|
||||
SystemPlugin.SetColorSpace(ColorSpace);
|
||||
#else // defined(WITH_OCULUS_BRANCH)
|
||||
NOT_IMPLEMENTED();
|
||||
#endif // defined(WITH_OCULUS_BRANCH)
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOpenXR::SetLocalDimmingOn(bool LocalDimmingOn)
|
||||
{
|
||||
OculusXR::FLayerExtensionPlugin& Plugin = FOculusXRHMDModule::Get().GetExtensionPluginManager().GetLayerExtensionPlugin();
|
||||
return Plugin.SetEnableLocalDimming(LocalDimmingOn);
|
||||
}
|
||||
|
||||
bool FOculusXRFunctionLibraryOpenXR::IsPassthroughSupported()
|
||||
{
|
||||
#if defined(WITH_OCULUS_BRANCH)
|
||||
OculusXR::FSystemInfoExtensionPlugin& SystemPlugin = FOculusXRHMDModule::Get().GetExtensionPluginManager().GetSystemInfoExtensionPlugin();
|
||||
return SystemPlugin.IsPassthroughSupported();
|
||||
#else // defined(WITH_OCULUS_BRANCH)
|
||||
NOT_IMPLEMENTED();
|
||||
return false;
|
||||
#endif // defined(WITH_OCULUS_BRANCH)
|
||||
}
|
||||
|
||||
bool FOculusXRFunctionLibraryOpenXR::IsColorPassthroughSupported()
|
||||
{
|
||||
#if defined(WITH_OCULUS_BRANCH)
|
||||
OculusXR::FSystemInfoExtensionPlugin& SystemPlugin = FOculusXRHMDModule::Get().GetExtensionPluginManager().GetSystemInfoExtensionPlugin();
|
||||
return SystemPlugin.IsColorPassthroughSupported();
|
||||
#else // defined(WITH_OCULUS_BRANCH)
|
||||
NOT_IMPLEMENTED();
|
||||
return false;
|
||||
#endif // defined(WITH_OCULUS_BRANCH)
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOpenXR::StartEnvironmentDepth()
|
||||
{
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
auto& EnvDepthPlugin = FOculusXRHMDModule::Get().GetExtensionPluginManager().GetEnvironmentDepthExtensionPlugin();
|
||||
EnvDepthPlugin.StartEnvironmentDepth();
|
||||
#endif
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOpenXR::StopEnvironmentDepth()
|
||||
{
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
auto& EnvDepthPlugin = FOculusXRHMDModule::Get().GetExtensionPluginManager().GetEnvironmentDepthExtensionPlugin();
|
||||
EnvDepthPlugin.StopEnvironmentDepth();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool FOculusXRFunctionLibraryOpenXR::IsEnvironmentDepthStarted()
|
||||
{
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
const auto& EnvDepthPlugin = FOculusXRHMDModule::Get().GetExtensionPluginManager().GetEnvironmentDepthExtensionPlugin();
|
||||
return !EnvDepthPlugin.IsEnvironmentDepthStarted();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOpenXR::SetEnvironmentDepthHandRemoval(bool RemoveHands)
|
||||
{
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
auto& EnvDepthPlugin = FOculusXRHMDModule::Get().GetExtensionPluginManager().GetEnvironmentDepthExtensionPlugin();
|
||||
EnvDepthPlugin.SetEnvironmentDepthHandRemoval_RenderThread(RemoveHands);
|
||||
#endif
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOpenXR::SetXROcclusionsMode(UObject* WorldContextObject, EOculusXROcclusionsMode Mode)
|
||||
{
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
auto& EnvDepthPlugin = FOculusXRHMDModule::Get().GetExtensionPluginManager().GetEnvironmentDepthExtensionPlugin();
|
||||
EnvDepthPlugin.SetXROcclusionsMode(WorldContextObject, Mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOpenXR::SetEyeBufferSharpenType(EOculusXREyeBufferSharpenType EyeBufferSharpenType)
|
||||
{
|
||||
OculusXR::FLayerExtensionPlugin& Plugin = FOculusXRHMDModule::Get().GetExtensionPluginManager().GetLayerExtensionPlugin();
|
||||
Plugin.SetEyeBufferSharpenType(EyeBufferSharpenType);
|
||||
}
|
||||
|
||||
bool FOculusXRFunctionLibraryOpenXR::IsPassthroughRecommended()
|
||||
{
|
||||
#if defined(WITH_OCULUS_BRANCH)
|
||||
OculusXR::FSystemInfoExtensionPlugin& SystemPlugin = FOculusXRHMDModule::Get().GetExtensionPluginManager().GetSystemInfoExtensionPlugin();
|
||||
return SystemPlugin.IsPassthroughRecommended();
|
||||
#else // defined(WITH_OCULUS_BRANCH)
|
||||
NOT_IMPLEMENTED();
|
||||
return false;
|
||||
#endif // defined(WITH_OCULUS_BRANCH)
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOpenXR::GetOpenXRInstanceProcAddrFunc(void** func)
|
||||
{
|
||||
*func = (void*)OpenXRDynamicAPI::xrGetInstanceProcAddr;
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOpenXR::GetNativeOpenXRHandles(uint64_t* OutXrInstance, uint64_t* OutXrSession)
|
||||
{
|
||||
IXRTrackingSystem* TrackingSystem = OculusXR::GetOpenXRTrackingSystem();
|
||||
if (TrackingSystem)
|
||||
{
|
||||
IOpenXRHMD* OpenXRHMD = TrackingSystem->GetIOpenXRHMD();
|
||||
if (OpenXRHMD)
|
||||
{
|
||||
if (OutXrInstance)
|
||||
{
|
||||
*OutXrInstance = (uint64_t)OpenXRHMD->GetInstance();
|
||||
}
|
||||
if (OutXrSession)
|
||||
{
|
||||
*OutXrSession = (uint64_t)OpenXRHMD->GetSession();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOpenXR::GetAppSpace(uint64_t* OutAppSpace)
|
||||
{
|
||||
IXRTrackingSystem* TrackingSystem = OculusXR::GetOpenXRTrackingSystem();
|
||||
if (TrackingSystem)
|
||||
{
|
||||
IOpenXRHMD* OpenXRHMD = TrackingSystem->GetIOpenXRHMD();
|
||||
if (OpenXRHMD)
|
||||
{
|
||||
*OutAppSpace = (uint64_t)OpenXRHMD->GetTrackingSpace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOpenXR::GetNextPredictedDisplayTime(uint64_t* NextPredictedDisplayTime)
|
||||
{
|
||||
IXRTrackingSystem* TrackingSystem = OculusXR::GetOpenXRTrackingSystem();
|
||||
if (TrackingSystem)
|
||||
{
|
||||
IOpenXRHMD* OpenXRHMD = TrackingSystem->GetIOpenXRHMD();
|
||||
if (OpenXRHMD)
|
||||
{
|
||||
*NextPredictedDisplayTime = OpenXRHMD->GetDisplayTime();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOpenXR::RegisterOpenXrEventHandler(void (*OpenXrEventHandler)(void* data, void* context), void* Context)
|
||||
{
|
||||
ensureMsgf(false, TEXT("RegisterOpenXrEventHandler is only available with OvrPlugin"));
|
||||
}
|
||||
|
||||
void FOculusXRFunctionLibraryOpenXR::UnregisterOpenXrEventHandler(void (*OpenXrEventHandler)(void* data, void* context))
|
||||
{
|
||||
ensureMsgf(false, TEXT("UnregisterOpenXrEventHandler is only available with OvrPlugin"));
|
||||
}
|
||||
|
||||
} // namespace OculusXRHMD
|
||||
@@ -0,0 +1,73 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
#include "OculusXRFunctionLibrary.h"
|
||||
|
||||
namespace OculusXRHMD
|
||||
{
|
||||
class FOculusXRFunctionLibraryOpenXR : public IOculusXRFunctionLibrary
|
||||
{
|
||||
public:
|
||||
virtual void GetPose(FRotator& DeviceRotation, FVector& DevicePosition, FVector& NeckPosition) override;
|
||||
virtual void SetBaseRotationAndBaseOffsetInMeters(FRotator Rotation, FVector BaseOffsetInMeters, EOrientPositionSelector::Type Options) override;
|
||||
virtual void GetBaseRotationAndBaseOffsetInMeters(FRotator& OutRotation, FVector& OutBaseOffsetInMeters) override;
|
||||
virtual void GetRawSensorData(FVector& AngularAcceleration, FVector& LinearAcceleration, FVector& AngularVelocity, FVector& LinearVelocity, float& TimeInSeconds, EOculusXRTrackedDeviceType DeviceType) override;
|
||||
virtual bool IsDeviceTracked(EOculusXRTrackedDeviceType DeviceType) override;
|
||||
virtual void GetSuggestedCpuAndGpuPerformanceLevels(EOculusXRProcessorPerformanceLevel& CpuPerfLevel, EOculusXRProcessorPerformanceLevel& GpuPerfLevel) override;
|
||||
virtual void SetSuggestedCpuAndGpuPerformanceLevels(EOculusXRProcessorPerformanceLevel CpuPerfLevel, EOculusXRProcessorPerformanceLevel GpuPerfLevel) override;
|
||||
virtual bool GetUserProfile(FOculusXRHmdUserProfile& Profile) override;
|
||||
virtual void SetBaseRotationAndPositionOffset(FRotator BaseRot, FVector PosOffset, EOrientPositionSelector::Type Options) override;
|
||||
virtual void GetBaseRotationAndPositionOffset(FRotator& OutRot, FVector& OutPosOffset) override;
|
||||
virtual void AddLoadingSplashScreen(class UTexture2D* Texture, FVector TranslationInMeters, FRotator Rotation, FVector2D SizeInMeters, FRotator DeltaRotation, bool bClearBeforeAdd) override;
|
||||
virtual void ClearLoadingSplashScreens() override;
|
||||
virtual bool HasInputFocus() override;
|
||||
virtual bool HasSystemOverlayPresent() override;
|
||||
virtual void GetGPUUtilization(bool& IsGPUAvailable, float& GPUUtilization) override;
|
||||
virtual float GetGPUFrameTime() override;
|
||||
virtual void GetPerformanceMetrics(FOculusXRPerformanceMetrics& PerformanceMetrics) override;
|
||||
|
||||
|
||||
virtual EOculusXRFoveatedRenderingMethod GetFoveatedRenderingMethod() override;
|
||||
virtual void SetFoveatedRenderingMethod(EOculusXRFoveatedRenderingMethod Method) override;
|
||||
virtual void SetFoveatedRenderingLevel(EOculusXRFoveatedRenderingLevel level, bool isDynamic) override;
|
||||
virtual EOculusXRFoveatedRenderingLevel GetFoveatedRenderingLevel() override;
|
||||
virtual bool GetEyeTrackedFoveatedRenderingSupported() override;
|
||||
virtual FString GetDeviceName() override;
|
||||
virtual EOculusXRDeviceType GetDeviceType() override;
|
||||
virtual EOculusXRControllerType GetControllerType(EControllerHand deviceHand) override;
|
||||
virtual TArray<float> GetAvailableDisplayFrequencies() override;
|
||||
virtual float GetCurrentDisplayFrequency() override;
|
||||
virtual void SetDisplayFrequency(float RequestedFrequency) override;
|
||||
virtual void EnablePositionTracking(bool bPositionTracking) override;
|
||||
virtual void EnableOrientationTracking(bool bOrientationTracking) override;
|
||||
virtual void SetColorScaleAndOffset(FLinearColor ColorScale, FLinearColor ColorOffset, bool bApplyToAllLayers) override;
|
||||
virtual class IStereoLayers* GetStereoLayers() override;
|
||||
virtual bool IsGuardianConfigured() override;
|
||||
virtual bool IsGuardianDisplayed() override;
|
||||
virtual TArray<FVector> GetGuardianPoints(EOculusXRBoundaryType BoundaryType, bool UsePawnSpace /* = false */) override;
|
||||
virtual FVector GetGuardianDimensions(EOculusXRBoundaryType BoundaryType) override;
|
||||
virtual FTransform GetPlayAreaTransform() override;
|
||||
virtual FOculusXRGuardianTestResult GetPointGuardianIntersection(const FVector Point, EOculusXRBoundaryType BoundaryType) override;
|
||||
virtual FOculusXRGuardianTestResult GetNodeGuardianIntersection(EOculusXRTrackedDeviceType DeviceType, EOculusXRBoundaryType BoundaryType) override;
|
||||
virtual void SetGuardianVisibility(bool GuardianVisible) override;
|
||||
virtual bool GetSystemHmd3DofModeEnabled() override;
|
||||
virtual EOculusXRColorSpace GetHmdColorDesc() override;
|
||||
virtual void SetClientColorDesc(EOculusXRColorSpace ColorSpace) override;
|
||||
virtual void SetLocalDimmingOn(bool LocalDimmingOn) override;
|
||||
virtual bool IsPassthroughSupported() override;
|
||||
virtual bool IsColorPassthroughSupported() override;
|
||||
virtual void StartEnvironmentDepth() override;
|
||||
virtual void StopEnvironmentDepth() override;
|
||||
virtual bool IsEnvironmentDepthStarted() override;
|
||||
virtual void SetEnvironmentDepthHandRemoval(bool RemoveHands) override;
|
||||
virtual void SetXROcclusionsMode(UObject* WorldContextObject, EOculusXROcclusionsMode Mode) override;
|
||||
virtual void SetEyeBufferSharpenType(EOculusXREyeBufferSharpenType EyeBufferSharpenType) override;
|
||||
virtual bool IsPassthroughRecommended() override;
|
||||
virtual void GetOpenXRInstanceProcAddrFunc(void** func) override;
|
||||
virtual void GetNativeOpenXRHandles(uint64_t* OutXrInstance, uint64_t* OutXrSession) override;
|
||||
virtual void GetAppSpace(uint64_t* OutAppSpace) override;
|
||||
virtual void GetNextPredictedDisplayTime(uint64_t* NextPredictedDisplayTime) override;
|
||||
virtual void RegisterOpenXrEventHandler(void (*OpenXrEventHandler)(void* data, void* context), void* Context);
|
||||
virtual void UnregisterOpenXrEventHandler(void (*OpenXrEventHandler)(void* data, void* context));
|
||||
};
|
||||
} // namespace OculusXRHMD
|
||||
5182
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD.cpp
Normal file
5182
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD.cpp
Normal file
File diff suppressed because it is too large
Load Diff
734
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD.h
Normal file
734
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD.h
Normal file
@@ -0,0 +1,734 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
#include "OculusXRHMDModule.h"
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
#include "OculusXRHMD_Settings.h"
|
||||
#include "OculusXRHMD_GameFrame.h"
|
||||
#include "OculusXRHMD_CustomPresent.h"
|
||||
#include "OculusXRHMD_Layer.h"
|
||||
#include "OculusXRHMD_Splash.h"
|
||||
#include "OculusXRHMD_StressTester.h"
|
||||
#include "OculusXRHMD_ConsoleCommands.h"
|
||||
#include "OculusXRHMD_SpectatorScreenController.h"
|
||||
#include "OculusXRHMD_DynamicResolutionState.h"
|
||||
#include "OculusXRHMD_DeferredDeletionQueue.h"
|
||||
|
||||
#include "OculusXRAssetManager.h"
|
||||
|
||||
#include "HeadMountedDisplayBase.h"
|
||||
#include "HeadMountedDisplay.h"
|
||||
#include "XRRenderTargetManager.h"
|
||||
#include "XRRenderBridge.h"
|
||||
#include "IStereoLayers.h"
|
||||
#include "Stats/Stats.h"
|
||||
#include "SceneViewExtension.h"
|
||||
#include "Engine/Engine.h"
|
||||
#include "Engine/StaticMeshActor.h"
|
||||
#include "XRThreadUtils.h"
|
||||
#include "ProceduralMeshComponent.h"
|
||||
#include "Shader.h"
|
||||
#include "GlobalShader.h"
|
||||
#include "Misc/EngineVersionComparison.h"
|
||||
#include "OculusXRHMD_FoveatedRendering.h"
|
||||
|
||||
namespace OculusXRHMD
|
||||
{
|
||||
class FHardOcclusionsPS : public FGlobalShader
|
||||
{
|
||||
DECLARE_SHADER_TYPE(FHardOcclusionsPS, Global);
|
||||
|
||||
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment);
|
||||
|
||||
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters);
|
||||
|
||||
/** Default constructor. */
|
||||
FHardOcclusionsPS();
|
||||
|
||||
/** Initialization constructor. */
|
||||
FHardOcclusionsPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer);
|
||||
|
||||
void SetParameters(
|
||||
FRHIBatchedShaderParameters& BatchedParameters,
|
||||
FRHISamplerState* Sampler,
|
||||
FRHITexture* Texture,
|
||||
const FVector2f& Factors,
|
||||
const FMatrix44f ScreenToDepth[ovrpEye_Count],
|
||||
const int ViewId);
|
||||
|
||||
private:
|
||||
LAYOUT_FIELD(FShaderResourceParameter, EnvironmentDepthTexture);
|
||||
LAYOUT_FIELD(FShaderResourceParameter, EnvironmentDepthSampler);
|
||||
LAYOUT_FIELD(FShaderParameter, DepthFactors);
|
||||
LAYOUT_FIELD(FShaderParameter, ScreenToDepthMatrices);
|
||||
LAYOUT_FIELD(FShaderParameter, DepthViewId);
|
||||
};
|
||||
|
||||
/**
|
||||
* A pixel shader for rendering occlusions, this is the min/max preprocessing step.
|
||||
*/
|
||||
template <bool bEnableMultiView>
|
||||
class FScreenPSEnvironmentDepthMinMax : public FGlobalShader
|
||||
{
|
||||
DECLARE_SHADER_TYPE(FScreenPSEnvironmentDepthMinMax, Global);
|
||||
|
||||
public:
|
||||
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
||||
{
|
||||
return !bEnableMultiView || Parameters.Platform == SP_VULKAN_ES3_1_ANDROID || Parameters.Platform == SP_VULKAN_SM5;
|
||||
}
|
||||
|
||||
static void ModifyCompilationEnvironment(const FPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
|
||||
{
|
||||
OutEnvironment.SetDefine(TEXT("ENABLE_MULTI_VIEW"), bEnableMultiView ? 1 : 0);
|
||||
}
|
||||
|
||||
FScreenPSEnvironmentDepthMinMax(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
|
||||
: FGlobalShader(Initializer)
|
||||
{
|
||||
InTexture.Bind(Initializer.ParameterMap, TEXT("InTexture"), SPF_Mandatory);
|
||||
InTextureSampler.Bind(Initializer.ParameterMap, TEXT("InTextureSampler"));
|
||||
if (!bEnableMultiView)
|
||||
{
|
||||
InArraySliceParameter.Bind(Initializer.ParameterMap, TEXT("ArraySlice"));
|
||||
}
|
||||
}
|
||||
|
||||
FScreenPSEnvironmentDepthMinMax() {}
|
||||
|
||||
void SetParameters(FRHIBatchedShaderParameters& BatchedParameters, FRHISamplerState* SamplerStateRHI, FRHITexture* TextureRHI, int ArraySlice)
|
||||
{
|
||||
SetTextureParameter(BatchedParameters, InTexture, InTextureSampler, SamplerStateRHI, TextureRHI);
|
||||
if (!bEnableMultiView)
|
||||
{
|
||||
SetShaderValue(BatchedParameters, InArraySliceParameter, ArraySlice);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
LAYOUT_FIELD(FShaderResourceParameter, InTexture);
|
||||
LAYOUT_FIELD(FShaderResourceParameter, InTextureSampler);
|
||||
LAYOUT_FIELD(FShaderParameter, InArraySliceParameter);
|
||||
};
|
||||
|
||||
DECLARE_DELEGATE_TwoParams(FOculusXRHMDEventPollingDelegate, ovrpEventDataBuffer*, bool&);
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// FPerformanceStats
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
struct FPerformanceStats
|
||||
{
|
||||
uint64 Frames;
|
||||
double Seconds;
|
||||
|
||||
FPerformanceStats(uint32 InFrames = 0, double InSeconds = 0.0)
|
||||
: Frames(InFrames)
|
||||
, Seconds(InSeconds)
|
||||
{
|
||||
}
|
||||
|
||||
FPerformanceStats operator-(const FPerformanceStats& PerformanceStats) const
|
||||
{
|
||||
return FPerformanceStats(
|
||||
Frames - PerformanceStats.Frames,
|
||||
Seconds - PerformanceStats.Seconds);
|
||||
}
|
||||
};
|
||||
|
||||
enum FRecenterTypes
|
||||
{
|
||||
RecenterOrientation = 0x1,
|
||||
RecenterPosition = 0x2,
|
||||
RecenterOrientationAndPosition = 0x3
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// FOculusXRHMD - Oculus Rift Head Mounted Display
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
class FOculusXRHMD : public FHeadMountedDisplayBase, public FXRRenderTargetManager, public IStereoLayers, public FHMDSceneViewExtension, public FOculusAssetManager
|
||||
{
|
||||
friend class UOculusXRFunctionLibrary;
|
||||
friend FOculusXRHMDModule;
|
||||
friend class FSplash;
|
||||
friend class FConsoleCommands;
|
||||
|
||||
public:
|
||||
// IXRSystemIdentifier
|
||||
virtual FName GetSystemName() const override;
|
||||
virtual int32 GetXRSystemFlags() const override;
|
||||
|
||||
// IXRTrackingSystem
|
||||
virtual FString GetVersionString() const override;
|
||||
virtual bool DoesSupportPositionalTracking() const override;
|
||||
virtual bool HasValidTrackingPosition() override;
|
||||
virtual bool EnumerateTrackedDevices(TArray<int32>& OutDevices, EXRTrackedDeviceType Type = EXRTrackedDeviceType::Any) override;
|
||||
virtual bool GetCurrentPose(int32 InDeviceId, FQuat& OutOrientation, FVector& OutPosition) override;
|
||||
virtual bool GetRelativeEyePose(int32 InDeviceId, int32 ViewIndex, FQuat& OutOrientation, FVector& OutPosition) override;
|
||||
virtual bool GetTrackingSensorProperties(int32 InDeviceId, FQuat& OutOrientation, FVector& OutPosition, FXRSensorProperties& OutSensorProperties) override;
|
||||
virtual void SetTrackingOrigin(EHMDTrackingOrigin::Type NewOrigin) override;
|
||||
virtual EHMDTrackingOrigin::Type GetTrackingOrigin() const override;
|
||||
virtual bool GetFloorToEyeTrackingTransform(FTransform& OutFloorToEye) const override;
|
||||
// virtual FVector GetAudioListenerOffset(int32 InDeviceId = HMDDeviceId) const override;
|
||||
virtual void ResetOrientationAndPosition(float Yaw = 0.f) override;
|
||||
virtual void ResetOrientation(float Yaw = 0.f) override;
|
||||
virtual void ResetPosition() override;
|
||||
virtual void SetBaseRotation(const FRotator& BaseRot) override;
|
||||
virtual FRotator GetBaseRotation() const override;
|
||||
virtual void SetBaseOrientation(const FQuat& BaseOrient) override;
|
||||
virtual FQuat GetBaseOrientation() const override;
|
||||
// virtual TSharedPtr<class IXRCamera, ESPMode::ThreadSafe> GetXRCamera(int32 DeviceId = HMDDeviceId) override;
|
||||
virtual class IHeadMountedDisplay* GetHMDDevice() override { return this; }
|
||||
virtual class TSharedPtr<class IStereoRendering, ESPMode::ThreadSafe> GetStereoRenderingDevice() override
|
||||
{
|
||||
return SharedThis(this);
|
||||
}
|
||||
// virtual class IXRInput* GetXRInput() override;
|
||||
virtual bool
|
||||
IsHeadTrackingEnforced() const override;
|
||||
virtual void SetHeadTrackingEnforced(bool bEnabled) override;
|
||||
virtual bool IsHeadTrackingAllowed() const override;
|
||||
virtual void OnBeginPlay(FWorldContext& InWorldContext) override;
|
||||
virtual void OnEndPlay(FWorldContext& InWorldContext) override;
|
||||
virtual bool OnStartGameFrame(FWorldContext& WorldContext) override;
|
||||
virtual bool OnEndGameFrame(FWorldContext& WorldContext) override;
|
||||
virtual void OnBeginRendering_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneViewFamily& ViewFamily) override;
|
||||
virtual void OnBeginRendering_GameThread() override;
|
||||
virtual class IXRLoadingScreen* CreateLoadingScreen() override { return GetSplash(); }
|
||||
virtual FVector2D GetPlayAreaBounds(EHMDTrackingOrigin::Type Origin) const override;
|
||||
|
||||
// IHeadMountedDisplay
|
||||
virtual bool IsHMDConnected() override { return true; }
|
||||
virtual bool IsHMDEnabled() const override;
|
||||
virtual EHMDWornState::Type GetHMDWornState() override;
|
||||
virtual void EnableHMD(bool bEnable = true) override;
|
||||
virtual bool GetHMDMonitorInfo(MonitorInfo&) override;
|
||||
virtual void GetFieldOfView(float& InOutHFOVInDegrees, float& InOutVFOVInDegrees) const override;
|
||||
virtual void SetInterpupillaryDistance(float NewInterpupillaryDistance) override;
|
||||
virtual float GetInterpupillaryDistance() const override;
|
||||
// virtual void SetClippingPlanes(float NCP, float FCP) override;
|
||||
// virtual FVector GetAudioListenerOffset() const override;
|
||||
virtual bool GetHMDDistortionEnabled(EShadingPath ShadingPath) const override;
|
||||
// virtual void BeginRendering_RenderThread(const FTransform& NewRelativeTransform, FRHICommandListImmediate& RHICmdList, FSceneViewFamily& ViewFamily) override;
|
||||
// virtual bool IsSpectatorScreenActive() const override;
|
||||
// virtual class ISpectatorScreenController* GetSpectatorScreenController() override;
|
||||
// virtual class ISpectatorScreenController const* GetSpectatorScreenController() const override;
|
||||
// virtual float GetDistortionScalingFactor() const override;
|
||||
// virtual float GetLensCenterOffset() const override;
|
||||
// virtual void GetDistortionWarpValues(FVector4& K) const override;
|
||||
virtual bool IsChromaAbCorrectionEnabled() const override;
|
||||
// virtual bool GetChromaAbCorrectionValues(FVector4& K) const override;
|
||||
virtual bool HasHiddenAreaMesh() const override;
|
||||
virtual bool HasVisibleAreaMesh() const override;
|
||||
|
||||
#if UE_VERSION_OLDER_THAN(5, 5, 0)
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
virtual void DrawHiddenAreaMesh(class FRHICommandList& RHICmdList, int32 ViewIndex, int32 InstanceCount = 1) const override;
|
||||
virtual void DrawVisibleAreaMesh(class FRHICommandList& RHICmdList, int32 ViewIndex, int32 InstanceCount = 1) const override;
|
||||
#else
|
||||
virtual void DrawHiddenAreaMesh(class FRHICommandList& RHICmdList, int32 ViewIndex) const override;
|
||||
virtual void DrawVisibleAreaMesh(class FRHICommandList& RHICmdList, int32 ViewIndex) const override;
|
||||
#endif // WITH_OCULUS_BRANCH
|
||||
#else
|
||||
virtual void DrawHiddenAreaMesh(class FRHICommandList& RHICmdList, int32 ViewIndex) const override final;
|
||||
virtual void DrawVisibleAreaMesh(class FRHICommandList& RHICmdList, int32 ViewIndex) const override final;
|
||||
virtual void DrawHiddenAreaMesh(class FRHICommandList& RHICmdList, int32 ViewIndex, int32 InstanceCount) const override final;
|
||||
virtual void DrawVisibleAreaMesh(class FRHICommandList& RHICmdList, int32 ViewIndex, int32 InstanceCount) const override final;
|
||||
#endif
|
||||
|
||||
// virtual void DrawDistortionMesh_RenderThread(struct FHeadMountedDisplayPassContext& Context, const FIntPoint& TextureSize) override;
|
||||
// virtual void UpdateScreenSettings(const FViewport* InViewport) override;
|
||||
// virtual void UpdatePostProcessSettings(FPostProcessSettings*) override;
|
||||
// virtual FTexture* GetDistortionTextureLeft() const override;
|
||||
// virtual FTexture* GetDistortionTextureRight() const override;
|
||||
// virtual FVector2D GetTextureOffsetLeft() const override;
|
||||
// virtual FVector2D GetTextureOffsetRight() const override;
|
||||
// virtual FVector2D GetTextureScaleLeft() const override;
|
||||
// virtual FVector2D GetTextureScaleRight() const override;
|
||||
// virtual const float* GetRedDistortionParameters() const override;
|
||||
// virtual const float* GetGreenDistortionParameters() const override;
|
||||
// virtual const float* GetBlueDistortionParameters() const override;
|
||||
// virtual bool NeedsUpscalePostProcessPass() override;
|
||||
// virtual void RecordAnalytics() override;
|
||||
// virtual bool DoesAppUseVRFocus() const override;
|
||||
// virtual bool DoesAppHaveVRFocus() const override;
|
||||
virtual float GetPixelDenity() const override;
|
||||
virtual void SetPixelDensity(const float NewPixelDensity) override;
|
||||
virtual FIntPoint GetIdealRenderTargetSize() const override;
|
||||
virtual void GetMotionControllerData(UObject* WorldContext, const EControllerHand Hand, FXRMotionControllerData& MotionControllerData) override;
|
||||
#if !UE_VERSION_OLDER_THAN(5, 5, 0)
|
||||
virtual void GetMotionControllerState(UObject* WorldContext, const EXRSpaceType XRSpaceType, const EControllerHand Hand, const EXRControllerPoseType XRControllerPoseType, FXRMotionControllerState& MotionControllerState) override;
|
||||
#endif
|
||||
// IStereoRendering interface
|
||||
virtual bool IsStereoEnabled() const override;
|
||||
virtual bool IsStereoEnabledOnNextFrame() const override;
|
||||
virtual bool EnableStereo(bool stereo = true) override;
|
||||
virtual void AdjustViewRect(int32 ViewIndex, int32& X, int32& Y, uint32& SizeX, uint32& SizeY) const override;
|
||||
virtual void SetFinalViewRect(FRHICommandListImmediate& RHICmdList, const int32 ViewIndex, const FIntRect& FinalViewRect) override;
|
||||
// virtual FVector2D GetTextSafeRegionBounds() const override;
|
||||
virtual void CalculateStereoViewOffset(const int32 ViewIndex, FRotator& ViewRotation, const float WorldToMeters, FVector& ViewLocation) override;
|
||||
virtual FMatrix GetStereoProjectionMatrix(const int32 ViewIndex) const override;
|
||||
virtual void InitCanvasFromView(class FSceneView* InView, class UCanvas* Canvas) override;
|
||||
// virtual void GetEyeRenderParams_RenderThread(const struct FRenderingCompositePassContext& Context, FVector2D& EyeToSrcUVScaleValue, FVector2D& EyeToSrcUVOffsetValue) const override;
|
||||
virtual void RenderTexture_RenderThread(class FRHICommandListImmediate& RHICmdList, class FRHITexture* BackBuffer, class FRHITexture* SrcTexture, FVector2D WindowSize) const override;
|
||||
// virtual void SetClippingPlanes(float NCP, float FCP) override;
|
||||
virtual IStereoRenderTargetManager* GetRenderTargetManager() override { return this; }
|
||||
virtual IStereoLayers* GetStereoLayers() override { return this; }
|
||||
// virtual void UseImplicitHmdPosition(bool bInImplicitHmdPosition) override;
|
||||
// virtual bool GetUseImplicitHmdPosition() override;
|
||||
virtual bool IsStandaloneStereoOnlyDevice() const override { return bIsStandaloneStereoOnlyDevice; }
|
||||
bool SupportsSpaceWarp() const;
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
virtual void CalculateScissorRect(const int32 ViewIndex, const FIntRect& ViewRect, FIntRect& OutRect) override;
|
||||
#endif // WITH_OCULUS_BRANCH
|
||||
|
||||
// FHeadMountedDisplayBase interface
|
||||
virtual FVector2D GetEyeCenterPoint_RenderThread(int32 ViewIndex) const override;
|
||||
virtual FIntRect GetFullFlatEyeRect_RenderThread(FTextureRHIRef EyeTexture) const override;
|
||||
virtual void CopyTexture_RenderThread(FRHICommandListImmediate& RHICmdList, FRHITexture* SrcTexture, FIntRect SrcRect, FRHITexture* DstTexture, FIntRect DstRect, bool bClearBlack, bool bNoAlpha) const override;
|
||||
virtual bool PopulateAnalyticsAttributes(TArray<struct FAnalyticsEventAttribute>& EventAttributes) override;
|
||||
|
||||
// FXRRenderTargetManager interface
|
||||
virtual bool ShouldUseSeparateRenderTarget() const override;
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
virtual void CalculateRenderTargetSize(uint32& InOutSizeX, uint32& InOutSizeY) override;
|
||||
#else // WITH_OCULUS_BRANCH
|
||||
virtual void CalculateRenderTargetSize(const FViewport& Viewport, uint32& InOutSizeX, uint32& InOutSizeY) override;
|
||||
#endif // WITH_OCULUS_BRANCH
|
||||
virtual bool NeedReAllocateViewportRenderTarget(const class FViewport& Viewport) override;
|
||||
virtual bool NeedReAllocateDepthTexture(const TRefCountPtr<IPooledRenderTarget>& DepthTarget) override;
|
||||
virtual bool NeedReAllocateShadingRateTexture(const TRefCountPtr<IPooledRenderTarget>& FoveationTarget) override;
|
||||
virtual bool AllocateRenderTargetTexture(uint32 Index, uint32 SizeX, uint32 SizeY, uint8 Format, uint32 NumMips, ETextureCreateFlags InTexFlags, ETextureCreateFlags InTargetableTextureFlags, FTextureRHIRef& OutTargetableTexture, FTextureRHIRef& OutShaderResourceTexture, uint32 NumSamples = 1) override;
|
||||
virtual bool AllocateDepthTexture(uint32 Index, uint32 SizeX, uint32 SizeY, uint8 Format, uint32 NumMips, ETextureCreateFlags InTexFlags, ETextureCreateFlags TargetableTextureFlags, FTextureRHIRef& OutTargetableTexture, FTextureRHIRef& OutShaderResourceTexture, uint32 NumSamples = 1) override;
|
||||
virtual bool AllocateShadingRateTexture(uint32 Index, uint32 RenderSizeX, uint32 RenderSizeY, uint8 Format, uint32 NumMips, ETextureCreateFlags InTexFlags, ETextureCreateFlags InTargetableTextureFlags, FTextureRHIRef& OutTexture, FIntPoint& OutTextureSize) override;
|
||||
#if defined(WITH_OCULUS_BRANCH)
|
||||
virtual bool GetRecommendedVelocityTextureSize(FIntPoint& OutTextureSize) override;
|
||||
virtual bool AllocateVelocityTexture(uint32 Index, const FIntPoint& Size, uint8 Format, uint32 NumMips, ETextureCreateFlags TexFlags, FTextureRHIRef& OutTexture, uint32 NumSamples = 1) override;
|
||||
virtual bool AllocateVelocityDepthTexture(uint32 Index, const FIntPoint& Size, uint8 Format, uint32 NumMips, ETextureCreateFlags TexFlags, FTextureRHIRef& OutTexture, uint32 NumSamples = 1) override;
|
||||
virtual bool FindEnvironmentDepthTexture_RenderThread(FTextureRHIRef& OutTexture, FTextureRHIRef& OutMinMaxTexture, FVector2f& OutDepthFactors, FMatrix44f OutScreenToDepthMatrices[2], FMatrix44f OutDepthViewProjMatrices[2]) override;
|
||||
#endif // defined(WITH_OCULUS_BRANCH)
|
||||
virtual EPixelFormat GetActualColorSwapchainFormat() const override;
|
||||
|
||||
virtual void UpdateViewportWidget(bool bUseSeparateRenderTarget, const class FViewport& Viewport, class SViewport* ViewportWidget) override;
|
||||
virtual FXRRenderBridge* GetActiveRenderBridge_GameThread(bool bUseSeparateRenderTarget);
|
||||
void AllocateEyeBuffer();
|
||||
|
||||
// IStereoLayers interface
|
||||
virtual uint32 CreateLayer(const IStereoLayers::FLayerDesc& InLayerDesc) override;
|
||||
virtual void DestroyLayer(uint32 LayerId) override;
|
||||
virtual void SetLayerDesc(uint32 LayerId, const IStereoLayers::FLayerDesc& InLayerDesc) override;
|
||||
virtual bool GetLayerDesc(uint32 LayerId, IStereoLayers::FLayerDesc& OutLayerDesc) override;
|
||||
virtual void MarkTextureForUpdate(uint32 LayerId) override;
|
||||
virtual IStereoLayers::FLayerDesc GetDebugCanvasLayerDesc(FTextureRHIRef Texture) override;
|
||||
virtual void GetAllocatedTexture(uint32 LayerId, FTextureRHIRef& Texture, FTextureRHIRef& LeftTexture) override;
|
||||
virtual bool ShouldCopyDebugLayersToSpectatorScreen() const override { return true; }
|
||||
virtual void PushLayerState(bool) override
|
||||
{ /* Todo */
|
||||
}
|
||||
virtual void PopLayerState() override
|
||||
{ /* Todo */
|
||||
}
|
||||
|
||||
// ISceneViewExtension
|
||||
virtual void SetupViewFamily(FSceneViewFamily& InViewFamily) override;
|
||||
virtual void SetupView(FSceneViewFamily& InViewFamily, FSceneView& InView) override;
|
||||
virtual void BeginRenderViewFamily(FSceneViewFamily& InViewFamily) override;
|
||||
virtual void PreRenderViewFamily_RenderThread(FRDGBuilder& GraphBuilder, FSceneViewFamily& InViewFamily) override;
|
||||
virtual void PreRenderView_RenderThread(FRDGBuilder& GraphBuilder, FSceneView& InView) override;
|
||||
virtual void PostRenderViewFamily_RenderThread(FRDGBuilder& GraphBuilder, FSceneViewFamily& InViewFamily) override;
|
||||
#if UE_VERSION_OLDER_THAN(5, 3, 0)
|
||||
virtual void PostRenderBasePassMobile_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneView& InView) override;
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
virtual void PostSceneColorRenderingMobile_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneView& InView) override;
|
||||
#endif
|
||||
#else
|
||||
virtual void PostRenderBasePassMobile_RenderThread(FRHICommandList& RHICmdList, FSceneView& InView) override;
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
virtual void PostSceneColorRenderingMobile_RenderThread(FRHICommandList& RHICmdList, FSceneView& InView) override;
|
||||
#endif
|
||||
#endif
|
||||
virtual void PostRenderBasePassDeferred_RenderThread(FRDGBuilder& GraphBuilder, FSceneView& InView, const FRenderTargetBindingSlots& RenderTargets, TRDGUniformBufferRef<FSceneTextureUniformParameters> SceneTextures) override;
|
||||
virtual int32 GetPriority() const override;
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
virtual bool LateLatchingEnabled() const override;
|
||||
virtual void PreLateLatchingViewFamily_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneViewFamily& InViewFamily) override;
|
||||
#endif
|
||||
|
||||
// MultiPlayer
|
||||
void SwitchPrimaryPIE(int PrimaryPIEIndex);
|
||||
const FOculusXRPerformanceMetrics GetPerformanceMetrics() const;
|
||||
|
||||
public:
|
||||
FOculusXRHMD(const FAutoRegister&);
|
||||
~FOculusXRHMD();
|
||||
|
||||
protected:
|
||||
bool Startup();
|
||||
void PreShutdown();
|
||||
void Shutdown();
|
||||
bool InitializeSession();
|
||||
void ShutdownSession();
|
||||
bool InitDevice();
|
||||
void ReleaseDevice();
|
||||
void ApplicationPauseDelegate();
|
||||
void ApplicationResumeDelegate();
|
||||
bool CheckEyeTrackingPermission(EOculusXRFoveatedRenderingMethod FoveatedRenderingMethod);
|
||||
void SetupOcclusionMeshes();
|
||||
void UpdateStereoRenderingParams();
|
||||
void UpdateHmdRenderInfo();
|
||||
void InitializeEyeLayer_RenderThread(FRHICommandListImmediate& RHICmdList);
|
||||
void ApplySystemOverridesOnStereo(bool force = false);
|
||||
bool OnOculusStateChange(bool bIsEnabledNow);
|
||||
bool ShouldDisableHiddenAndVisibileAreaMeshForSpectatorScreen_RenderThread() const;
|
||||
void Recenter(FRecenterTypes RecenterType, float Yaw);
|
||||
FIntRect GetAsymmetricViewRect(const int32 ViewIndex, const FIntRect& ViewRect);
|
||||
#if !UE_BUILD_SHIPPING
|
||||
void DrawDebug(UCanvas* InCanvas, APlayerController* InPlayerController);
|
||||
#endif
|
||||
|
||||
class FSceneViewport* FindSceneViewport();
|
||||
FOculusXRSplashDesc GetUESplashScreenDesc();
|
||||
void EyeTrackedFoveatedRenderingFallback();
|
||||
|
||||
public:
|
||||
OCULUSXRHMD_API static FOculusXRHMD* GetOculusXRHMD();
|
||||
|
||||
bool IsHMDActive() const;
|
||||
|
||||
FSplash* GetSplash() const { return Splash.Get(); }
|
||||
FCustomPresent* GetCustomPresent_Internal() const { return CustomPresent; }
|
||||
|
||||
float GetWorldToMetersScale() const;
|
||||
|
||||
ESpectatorScreenMode GetSpectatorScreenMode_RenderThread() const;
|
||||
|
||||
FVector GetNeckPosition(const FQuat& HeadOrientation, const FVector& HeadPosition);
|
||||
|
||||
/**
|
||||
* Sets base position offset (in meters). The base position offset is the distance from the physical (0, 0, 0) position
|
||||
* to current HMD position (bringing the (0, 0, 0) point to the current HMD position)
|
||||
* Note, this vector is set by ResetPosition call; use this method with care.
|
||||
* The axis of the vector are the same as in Unreal: X - forward, Y - right, Z - up.
|
||||
*
|
||||
* @param BaseOffset (in) the vector to be set as base offset, in meters.
|
||||
*/
|
||||
void SetBaseOffsetInMeters(const FVector& BaseOffset);
|
||||
|
||||
/**
|
||||
* Returns the currently used base position offset, previously set by the
|
||||
* ResetPosition or SetBasePositionOffset calls. It represents a vector that translates the HMD's position
|
||||
* into (0,0,0) point, in meters.
|
||||
* The axis of the vector are the same as in Unreal: X - forward, Y - right, Z - up.
|
||||
*
|
||||
* @return Base position offset, in meters.
|
||||
*/
|
||||
FVector GetBaseOffsetInMeters() const;
|
||||
|
||||
OCULUSXRHMD_API bool ConvertPose(const ovrpPosef& InPose, FPose& OutPose) const;
|
||||
OCULUSXRHMD_API bool ConvertPose(const FPose& InPose, ovrpPosef& OutPose) const;
|
||||
OCULUSXRHMD_API bool ConvertPose_RenderThread(const ovrpPosef& InPose, FPose& OutPose) const;
|
||||
OCULUSXRHMD_API static bool ConvertPose_Internal(const ovrpPosef& InPose, FPose& OutPose, const FSettings* Settings, float WorldToMetersScale = 100.0f);
|
||||
OCULUSXRHMD_API static bool ConvertPose_Internal(const FPose& InPose, ovrpPosef& OutPose, const FSettings* Settings, float WorldToMetersScale = 100.0f);
|
||||
|
||||
/** Turns ovrVector3f in Unreal World space to a scaled FVector and applies translation and rotation corresponding to player movement */
|
||||
FVector ScaleAndMovePointWithPlayer(ovrpVector3f& OculusXRHMDPoint);
|
||||
|
||||
/** The inverse of ScaleAndMovePointWithPlayer */
|
||||
ovrpVector3f WorldLocationToOculusPoint(const FVector& InUnrealPosition);
|
||||
|
||||
/** Convert dimension of a float (e.g., a distance) from meters to Unreal Units */
|
||||
float ConvertFloat_M2U(float OculusFloat) const;
|
||||
FVector ConvertVector_M2U(ovrpVector3f OculusPoint) const;
|
||||
|
||||
struct UserProfile
|
||||
{
|
||||
float IPD;
|
||||
float EyeDepth;
|
||||
float EyeHeight;
|
||||
};
|
||||
|
||||
bool GetUserProfile(UserProfile& OutProfile);
|
||||
float GetVsyncToNextVsync() const;
|
||||
FPerformanceStats GetPerformanceStats() const;
|
||||
bool DoEnableStereo(bool bStereo);
|
||||
void SendTelemetryData();
|
||||
void ResetControlRotation() const;
|
||||
void UpdateFoveationOffsets_RenderThread();
|
||||
bool ComputeEnvironmentDepthParameters_RenderThread(FVector2f& DepthFactors, FMatrix44f ScreenToDepth[ovrpEye_Count], FMatrix44f DepthViewProj[ovrpEye_Count], int& SwapchainIndex);
|
||||
|
||||
FSettingsPtr CreateNewSettings() const;
|
||||
FGameFramePtr CreateNewGameFrame() const;
|
||||
|
||||
FGameFrame* GetFrame()
|
||||
{
|
||||
CheckInGameThread();
|
||||
return Frame.Get();
|
||||
}
|
||||
const FGameFrame* GetFrame() const
|
||||
{
|
||||
CheckInGameThread();
|
||||
return Frame.Get();
|
||||
}
|
||||
FGameFrame* GetFrame_RenderThread()
|
||||
{
|
||||
CheckInRenderThread();
|
||||
return Frame_RenderThread.Get();
|
||||
}
|
||||
const FGameFrame* GetFrame_RenderThread() const
|
||||
{
|
||||
CheckInRenderThread();
|
||||
return Frame_RenderThread.Get();
|
||||
}
|
||||
FGameFrame* GetFrame_RHIThread()
|
||||
{
|
||||
CheckInRHIThread();
|
||||
return Frame_RHIThread.Get();
|
||||
}
|
||||
const FGameFrame* GetFrame_RHIThread() const
|
||||
{
|
||||
CheckInRHIThread();
|
||||
return Frame_RHIThread.Get();
|
||||
}
|
||||
FGameFrame* GetNextFrameToRender()
|
||||
{
|
||||
CheckInGameThread();
|
||||
return NextFrameToRender.Get();
|
||||
}
|
||||
const FGameFrame* GetNextFrameToRender() const
|
||||
{
|
||||
CheckInGameThread();
|
||||
return NextFrameToRender.Get();
|
||||
}
|
||||
|
||||
FSettings* GetSettings()
|
||||
{
|
||||
CheckInGameThread();
|
||||
return Settings.Get();
|
||||
}
|
||||
const FSettings* GetSettings() const
|
||||
{
|
||||
CheckInGameThread();
|
||||
return Settings.Get();
|
||||
}
|
||||
FSettings* GetSettings_RenderThread()
|
||||
{
|
||||
CheckInRenderThread();
|
||||
return Settings_RenderThread.Get();
|
||||
}
|
||||
const FSettings* GetSettings_RenderThread() const
|
||||
{
|
||||
CheckInRenderThread();
|
||||
return Settings_RenderThread.Get();
|
||||
}
|
||||
FSettings* GetSettings_RHIThread()
|
||||
{
|
||||
CheckInRHIThread();
|
||||
return Settings_RHIThread.Get();
|
||||
}
|
||||
const FSettings* GetSettings_RHIThread() const
|
||||
{
|
||||
CheckInRHIThread();
|
||||
return Settings_RHIThread.Get();
|
||||
}
|
||||
|
||||
const int GetNextFrameNumber() const { return NextFrameNumber; }
|
||||
|
||||
const FRotator GetSplashRotation() const { return SplashRotation; }
|
||||
void SetSplashRotationToForward();
|
||||
|
||||
OCULUSXRHMD_API void StartGameFrame_GameThread(); // Called from OnStartGameFrame or from FOculusXRInput::SendControllerEvents (first actual call of the frame)
|
||||
void FinishGameFrame_GameThread(); // Called from OnEndGameFrame
|
||||
void StartRenderFrame_GameThread(); // Called from BeginRenderViewFamily
|
||||
void FinishRenderFrame_RenderThread(FRDGBuilder& GraphBuilder); // Called from PostRenderViewFamily_RenderThread
|
||||
void StartRHIFrame_RenderThread(); // Called from PreRenderViewFamily_RenderThread
|
||||
void FinishRHIFrame_RHIThread(); // Called from FinishRendering_RHIThread
|
||||
|
||||
void GetSuggestedCpuAndGpuPerformanceLevels(EOculusXRProcessorPerformanceLevel& CpuPerfLevel, EOculusXRProcessorPerformanceLevel& GpuPerfLevel);
|
||||
void SetSuggestedCpuAndGpuPerformanceLevels(EOculusXRProcessorPerformanceLevel CpuPerfLevel, EOculusXRProcessorPerformanceLevel GpuPerfLevel);
|
||||
void SetFoveatedRenderingMethod(EOculusXRFoveatedRenderingMethod InFoveationMethod);
|
||||
void SetFoveatedRenderingLevel(EOculusXRFoveatedRenderingLevel InFoveationLevel, bool isDynamic);
|
||||
void SetColorScaleAndOffset(FLinearColor ColorScale, FLinearColor ColorOffset, bool bApplyToAllLayers);
|
||||
void SetEnvironmentDepthHandRemoval(bool RemoveHands);
|
||||
void StartEnvironmentDepth(int CreateFlags);
|
||||
void StopEnvironmentDepth();
|
||||
bool IsEnvironmentDepthStarted();
|
||||
|
||||
UE_DEPRECATED(5.5, "Hard occlusions is deprecated, use Soft occlusions instead.")
|
||||
void EnableHardOcclusions(bool bEnable);
|
||||
void EnableSoftOcclusions(bool bEnable);
|
||||
|
||||
OCULUSXRHMD_API void UpdateRTPoses();
|
||||
|
||||
FTransform GetLastTrackingToWorld() const { return LastTrackingToWorld; }
|
||||
OCULUSXRHMD_API void AddEventPollingDelegate(const FOculusXRHMDEventPollingDelegate& NewDelegate);
|
||||
|
||||
OCULUSXRHMD_API uint32 GetLayerIdFromOvrpId(int OvrpId) const;
|
||||
|
||||
protected:
|
||||
FConsoleCommands ConsoleCommands;
|
||||
void UpdateOnRenderThreadCommandHandler(const TArray<FString>& Args, UWorld* World, FOutputDevice& Ar);
|
||||
void HQBufferCommandHandler(const TArray<FString>& Args, UWorld*, FOutputDevice& Ar);
|
||||
void HQDistortionCommandHandler(const TArray<FString>& Args, UWorld*, FOutputDevice& Ar);
|
||||
void ShowGlobalMenuCommandHandler(const TArray<FString>& Args, UWorld* World, FOutputDevice& Ar);
|
||||
void ShowQuitMenuCommandHandler(const TArray<FString>& Args, UWorld* World, FOutputDevice& Ar);
|
||||
#if !UE_BUILD_SHIPPING
|
||||
void StatsCommandHandler(const TArray<FString>& Args, UWorld* World, FOutputDevice& Ar);
|
||||
void ShowSettingsCommandHandler(const TArray<FString>& Args, UWorld* World, FOutputDevice& Ar);
|
||||
void IPDCommandHandler(const TArray<FString>& Args, UWorld* World, FOutputDevice& Ar);
|
||||
#endif
|
||||
|
||||
void LoadFromSettings();
|
||||
void LogEnabledFeatures() const;
|
||||
void DoSessionShutdown();
|
||||
|
||||
protected:
|
||||
void UpdateHMDWornState();
|
||||
EHMDWornState::Type HMDWornState = EHMDWornState::Unknown;
|
||||
|
||||
void UpdateHMDEvents();
|
||||
|
||||
void EnableInsightPassthrough_RenderThread(bool bEnablePassthrough);
|
||||
|
||||
void PrepareAndRenderHardOcclusions_RenderThread(FRHICommandList& RHICmdList, FSceneView& InView);
|
||||
|
||||
// MultiPlayer
|
||||
void InitMultiPlayerPoses(const FPose& CurPose);
|
||||
void ResetMultiPlayerPoses();
|
||||
void ReCalcMultiPlayerPoses(FPose& CurHMDHeadPose);
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint64 bApplySystemOverridesOnStereo : 1;
|
||||
|
||||
uint64 bNeedEnableStereo : 1;
|
||||
uint64 bNeedDisableStereo : 1;
|
||||
};
|
||||
uint64 Raw;
|
||||
} Flags;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
// set to true when origin was set while OvrSession == null; the origin will be set ASA OvrSession != null
|
||||
uint64 NeedSetTrackingOrigin : 1;
|
||||
// enforces exit; used mostly for testing
|
||||
uint64 EnforceExit : 1;
|
||||
// set if a game is paused by the plug-in
|
||||
uint64 AppIsPaused : 1;
|
||||
// set to indicate that DisplayLost was detected by game thread.
|
||||
uint64 DisplayLostDetected : 1;
|
||||
// set to true once new session is created; being handled and reset as soon as session->IsVisible.
|
||||
uint64 NeedSetFocusToGameViewport : 1;
|
||||
};
|
||||
uint64 Raw;
|
||||
} OCFlags;
|
||||
|
||||
TRefCountPtr<FCustomPresent> CustomPresent;
|
||||
FSplashPtr Splash;
|
||||
IRendererModule* RendererModule;
|
||||
|
||||
FDeferredDeletionQueue DeferredDeletion;
|
||||
|
||||
EHMDTrackingOrigin::Type TrackingOrigin;
|
||||
// Stores difference between ViewRotation and EyeOrientation from previous frame
|
||||
FQuat LastPlayerOrientation;
|
||||
// Stores GetFrame()->PlayerLocation (i.e., ViewLocation) from the previous frame
|
||||
FVector LastPlayerLocation;
|
||||
FRotator DeltaControlRotation; // used from ApplyHmdRotation
|
||||
TWeakPtr<SWidget> CachedViewportWidget;
|
||||
TWeakPtr<SWindow> CachedWindow;
|
||||
FIntPoint CachedWindowSize;
|
||||
float CachedWorldToMetersScale;
|
||||
bool bIsStandaloneStereoOnlyDevice;
|
||||
// Stores TrackingToWorld from previous frame
|
||||
FTransform LastTrackingToWorld;
|
||||
std::atomic<bool> bHardOcclusionsEnabled;
|
||||
std::atomic<bool> bSoftOcclusionsEnabled;
|
||||
std::atomic<bool> bEnvironmentDepthHandRemovalEnabled;
|
||||
|
||||
// These three properties indicate the current state of foveated rendering, which may differ from what's in Settings
|
||||
// due to cases such as falling back to FFR when eye tracked foveated rendering isn't enabled. Will allow us to resume
|
||||
// ETFR from situations such as when ET gets paused.
|
||||
std::atomic<EOculusXRFoveatedRenderingMethod> FoveatedRenderingMethod;
|
||||
std::atomic<EOculusXRFoveatedRenderingLevel> FoveatedRenderingLevel;
|
||||
std::atomic<bool> bDynamicFoveatedRendering;
|
||||
|
||||
// Game thread
|
||||
FSettingsPtr Settings;
|
||||
uint32 NextFrameNumber;
|
||||
uint32 WaitFrameNumber;
|
||||
FGameFramePtr Frame; // Valid from OnStartGameFrame to OnEndGameFrame
|
||||
FGameFramePtr NextFrameToRender; // Valid from OnStartGameFrame to BeginRenderViewFamily
|
||||
FGameFramePtr LastFrameToRender; // Valid from OnStartGameFrame to BeginRenderViewFamily
|
||||
uint32 NextLayerId;
|
||||
TMap<uint32, FLayerPtr> LayerMap;
|
||||
bool bNeedReAllocateViewportRenderTarget;
|
||||
|
||||
// Render thread
|
||||
FSettingsPtr Settings_RenderThread;
|
||||
FGameFramePtr Frame_RenderThread; // Valid from BeginRenderViewFamily to PostRenderViewFamily_RenderThread
|
||||
TArray<FLayerPtr> Layers_RenderThread;
|
||||
FLayerPtr EyeLayer_RenderThread; // Valid to be accessed from game thread, since updated only when game thread is waiting
|
||||
bool bNeedReAllocateDepthTexture_RenderThread;
|
||||
bool bNeedReAllocateFoveationTexture_RenderThread;
|
||||
bool bNeedReAllocateMotionVectorTexture_RenderThread;
|
||||
bool bNeedReAllocateMotionVectorDepthTexture_RenderThread;
|
||||
#if !UE_VERSION_OLDER_THAN(5, 3, 0)
|
||||
TSharedPtr<FOculusXRFoveatedRenderingImageGenerator, ESPMode::ThreadSafe> FoveationImageGenerator;
|
||||
#endif // !UE_VERSION_OLDER_THAN(5, 3, 0)
|
||||
|
||||
// RHI thread
|
||||
FSettingsPtr Settings_RHIThread;
|
||||
FGameFramePtr Frame_RHIThread; // Valid from PreRenderViewFamily_RenderThread to FinishRendering_RHIThread
|
||||
TArray<FLayerPtr> Layers_RHIThread;
|
||||
|
||||
FHMDViewMesh HiddenAreaMeshes[2];
|
||||
FHMDViewMesh VisibleAreaMeshes[2];
|
||||
|
||||
FPerformanceStats PerformanceStats;
|
||||
|
||||
FRotator SplashRotation; // rotation applied to all splash screens (dependent on HMD orientation as the splash is shown)
|
||||
|
||||
TArray<FTextureRHIRef> EnvironmentDepthSwapchain;
|
||||
FTextureRHIRef EnvironmentDepthMinMaxTexture;
|
||||
int PrevEnvironmentDepthMinMaxSwapchainIndex = -1;
|
||||
|
||||
#if !UE_BUILD_SHIPPING
|
||||
FDelegateHandle DrawDebugDelegateHandle;
|
||||
#endif
|
||||
|
||||
enum class FInsightInitStatus
|
||||
{
|
||||
NotInitialized,
|
||||
Initialized,
|
||||
Failed,
|
||||
};
|
||||
|
||||
FInsightInitStatus InsightInitStatus;
|
||||
|
||||
bool bShutdownRequestQueued;
|
||||
bool bEyeTrackedFoveatedRenderingSupported;
|
||||
|
||||
FOculusXRPerformanceMetrics PerformanceMetrics;
|
||||
|
||||
TArray<FOculusXRHMDEventPollingDelegate> EventPollingDelegates;
|
||||
|
||||
// MultiPlayer
|
||||
int CurPlayerIndex;
|
||||
FPose LastFrameHMDHeadPose;
|
||||
TArray<FPose> MultiPlayerPoses;
|
||||
bool bShouldWait_GameThread;
|
||||
bool bIsRendering_RenderThread;
|
||||
};
|
||||
|
||||
typedef TSharedPtr<FOculusXRHMD, ESPMode::ThreadSafe> FOculusXRHMDPtr;
|
||||
|
||||
} // namespace OculusXRHMD
|
||||
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
567
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDModule.cpp
Normal file
567
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDModule.cpp
Normal file
@@ -0,0 +1,567 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "OculusXRHMDModule.h"
|
||||
#include "OculusXRFunctionLibrary.h"
|
||||
#include "OculusXRHMD.h"
|
||||
#include "OculusXRHMDPrivateRHI.h"
|
||||
#include "OculusXRHMDRuntimeSettings.h"
|
||||
#include "OculusXRStereoLayersFlagsSupplier.h"
|
||||
#include "Containers/StringConv.h"
|
||||
#include "Misc/EngineVersion.h"
|
||||
#include "Misc/Paths.h"
|
||||
#if PLATFORM_ANDROID
|
||||
#include "Android/AndroidApplication.h"
|
||||
#include "Android/AndroidPlatformMisc.h"
|
||||
#endif
|
||||
#include "Interfaces/IPluginManager.h"
|
||||
#include "ShaderCore.h"
|
||||
#include "OculusXRTelemetry.h"
|
||||
#if PLATFORM_WINDOWS
|
||||
#include "OculusXRSimulator.h"
|
||||
#include "OculusXRSyntheticEnvironmentServer.h"
|
||||
#endif
|
||||
|
||||
#if !PLATFORM_ANDROID
|
||||
#if !UE_BUILD_SHIPPING
|
||||
namespace
|
||||
{
|
||||
void __cdecl OvrpLogCallback2(ovrpLogLevel InLevel, const char* Message, int Length)
|
||||
{
|
||||
ELogVerbosity::Type OutLevel;
|
||||
switch (InLevel)
|
||||
{
|
||||
case ovrpLogLevel_Debug:
|
||||
OutLevel = ELogVerbosity::Log;
|
||||
break;
|
||||
case ovrpLogLevel_Info:
|
||||
OutLevel = ELogVerbosity::Display;
|
||||
break;
|
||||
case ovrpLogLevel_Error:
|
||||
OutLevel = ELogVerbosity::Error;
|
||||
break;
|
||||
case ovrpLogLevel_Warning:
|
||||
OutLevel = ELogVerbosity::Warning;
|
||||
break;
|
||||
default:
|
||||
OutLevel = ELogVerbosity::NoLogging;
|
||||
}
|
||||
const FString MessageStr(Length, Message);
|
||||
GLog->CategorizedLogf(TEXT("LogOVRPlugin"), OutLevel, TEXT("%s"), *MessageStr);
|
||||
}
|
||||
} // namespace
|
||||
#endif // !UE_BUILD_SHIPPING
|
||||
#endif // !PLATFORM_ANDROID
|
||||
|
||||
const FName IOculusXRHMDModule::NAME_OculusXRHMD(TEXT("OculusXRHMD"));
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// FOculusXRHMDModule
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
OculusPluginWrapper FOculusXRHMDModule::PluginWrapper{};
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusPluginWrapper& FOculusXRHMDModule::GetPluginWrapper()
|
||||
{
|
||||
return PluginWrapper;
|
||||
}
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
|
||||
FOculusXRHMDModule::FOculusXRHMDModule()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
bPreInit = false;
|
||||
bPreInitCalled = false;
|
||||
OVRPluginHandle = nullptr;
|
||||
GraphicsAdapterLuid = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void FOculusXRHMDModule::StartupModule()
|
||||
{
|
||||
IHeadMountedDisplayModule::StartupModule();
|
||||
FString PluginShaderDir = FPaths::Combine(IPluginManager::Get().FindPlugin(TEXT("OculusXR"))->GetBaseDir(), TEXT("Shaders"));
|
||||
AddShaderSourceDirectoryMapping(TEXT("/Plugin/OculusXR"), PluginShaderDir);
|
||||
|
||||
#if !UE_VERSION_OLDER_THAN(5, 4, 0)
|
||||
auto StereoLayersFlagsSupplier = FOculusXRStereoLayersFlagsSupplier::Get();
|
||||
if (StereoLayersFlagsSupplier.IsValid())
|
||||
{
|
||||
IModularFeatures::Get().RegisterModularFeature(IStereoLayersFlagsSupplier::GetModularFeatureName(), StereoLayersFlagsSupplier.Get());
|
||||
TArray<IStereoLayersFlagsSupplier*> FlagsSuppliers = IModularFeatures::Get().GetModularFeatureImplementations<IStereoLayersFlagsSupplier>(IStereoLayersFlagsSupplier::GetModularFeatureName());
|
||||
if (FlagsSuppliers.Num() > 1)
|
||||
{
|
||||
UE_LOG(LogHMD, Log, TEXT("OculusXR Stereo Layer Filters CANNOT be used with layer filters!"));
|
||||
IModularFeatures::Get().UnregisterModularFeature(IStereoLayersFlagsSupplier::GetModularFeatureName(), StereoLayersFlagsSupplier.Get());
|
||||
}
|
||||
}
|
||||
PreInit();
|
||||
#endif // !UE_VERSION_OLDER_THAN(5, 4, 0)
|
||||
|
||||
ExtensionPluginManager.StartupOpenXRPlugins();
|
||||
}
|
||||
|
||||
void FOculusXRHMDModule::ShutdownModule()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
#if !UE_VERSION_OLDER_THAN(5, 4, 0)
|
||||
auto StereoLayersFlagsSupplier = FOculusXRStereoLayersFlagsSupplier::Get();
|
||||
if (StereoLayersFlagsSupplier.IsValid())
|
||||
{
|
||||
IModularFeatures::Get().UnregisterModularFeature(IStereoLayersFlagsSupplier::GetModularFeatureName(), StereoLayersFlagsSupplier.Get());
|
||||
}
|
||||
#endif // !UE_VERSION_OLDER_THAN(5, 4, 0)
|
||||
UOculusXRFunctionLibrary::ShutdownXRFunctionLibrary();
|
||||
|
||||
if (PluginWrapper.IsInitialized())
|
||||
{
|
||||
OculusXRTelemetry::FTelemetryBackend::OnEditorShutdown();
|
||||
PluginWrapper.Shutdown2();
|
||||
OculusPluginWrapper::DestroyOculusPluginWrapper(&PluginWrapper);
|
||||
}
|
||||
|
||||
if (OVRPluginHandle)
|
||||
{
|
||||
FPlatformProcess::FreeDllHandle(OVRPluginHandle);
|
||||
OVRPluginHandle = nullptr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
OculusXR::FExtensionPluginManager& FOculusXRHMDModule::GetExtensionPluginManager()
|
||||
{
|
||||
return ExtensionPluginManager;
|
||||
}
|
||||
|
||||
#if PLATFORM_ANDROID
|
||||
extern bool AndroidThunkCpp_IsOculusMobileApplication();
|
||||
#endif
|
||||
|
||||
FString FOculusXRHMDModule::GetModuleKeyName() const
|
||||
{
|
||||
return NAME_OculusXRHMD.ToString();
|
||||
}
|
||||
|
||||
void FOculusXRHMDModule::GetModuleAliases(TArray<FString>& AliasesOut) const
|
||||
{
|
||||
// Pre-OculusXR rename (5.0.3 v44)
|
||||
AliasesOut.Add(TEXT("OculusHMD"));
|
||||
}
|
||||
|
||||
bool FOculusXRHMDModule::PreInit()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
if (!bPreInitCalled)
|
||||
{
|
||||
bPreInit = false;
|
||||
|
||||
#if PLATFORM_ANDROID
|
||||
bPreInitCalled = true;
|
||||
if (!AndroidThunkCpp_IsOculusMobileApplication())
|
||||
{
|
||||
UE_LOG(LogHMD, Log, TEXT("App is not packaged for Oculus Mobile"));
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Init module if app can render
|
||||
if (FApp::CanEverRender())
|
||||
{
|
||||
// Load OVRPlugin
|
||||
OVRPluginHandle = GetOVRPluginHandle();
|
||||
|
||||
if (!OVRPluginHandle)
|
||||
{
|
||||
UE_LOG(LogHMD, Log, TEXT("Failed loading OVRPlugin %s"), TEXT(OVRP_VERSION_STR));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!OculusPluginWrapper::InitializeOculusPluginWrapper(&PluginWrapper))
|
||||
{
|
||||
UE_LOG(LogHMD, Log, TEXT("Failed InitializeOculusPluginWrapper"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Initialize OVRPlugin
|
||||
ovrpRenderAPIType PreinitApiType = ovrpRenderAPI_None;
|
||||
#if PLATFORM_ANDROID
|
||||
void* Activity = (void*)FAndroidApplication::GetGameActivityThis();
|
||||
PreinitApiType = ovrpRenderAPI_Vulkan;
|
||||
#else
|
||||
void* Activity = nullptr;
|
||||
#endif
|
||||
|
||||
#if !PLATFORM_ANDROID
|
||||
#if !UE_BUILD_SHIPPING
|
||||
PluginWrapper.SetLogCallback2(OvrpLogCallback2);
|
||||
#endif // !UE_BUILD_SHIPPING
|
||||
#endif // !PLATFORM_ANDROID
|
||||
|
||||
// Determine Preinit flag based on platform
|
||||
ovrpPreinitializeFlags PreinitFlag = ovrpPreinitializeFlags::ovrpPreinitializeFlag_None;
|
||||
#if WITH_EDITOR && PLATFORM_WINDOWS
|
||||
PreinitFlag = ovrpPreinitializeFlags::ovrpPreinitializeFlag_DisableLogSystemError;
|
||||
#endif
|
||||
if (OVRP_FAILURE(PluginWrapper.PreInitialize5(Activity, PreinitApiType, PreinitFlag)))
|
||||
{
|
||||
UE_LOG(LogHMD, Log, TEXT("Failed initializing OVRPlugin %s"), TEXT(OVRP_VERSION_STR));
|
||||
#if WITH_EDITOR && PLATFORM_WINDOWS
|
||||
// In the editor, we want to allow the headset to connect after the editor has booted.
|
||||
// To do this, we must have PreInit() return true, to prevent the HMD module from being unloaded.
|
||||
return GIsEditor;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
bPreInitCalled = true;
|
||||
const LUID* DisplayAdapterId;
|
||||
if (OVRP_SUCCESS(PluginWrapper.GetDisplayAdapterId2((const void**)&DisplayAdapterId)) && DisplayAdapterId)
|
||||
{
|
||||
SetGraphicsAdapterLuid(*(const uint64*)DisplayAdapterId);
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogHMD, Log, TEXT("Could not determine HMD display adapter"));
|
||||
}
|
||||
|
||||
const WCHAR* AudioInDeviceId;
|
||||
if (OVRP_SUCCESS(PluginWrapper.GetAudioInDeviceId2((const void**)&AudioInDeviceId)) && AudioInDeviceId)
|
||||
{
|
||||
GConfig->SetString(TEXT("Oculus.Settings"), TEXT("AudioInputDevice"), AudioInDeviceId, GEngineIni);
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogHMD, Log, TEXT("Could not determine HMD audio input device"));
|
||||
}
|
||||
|
||||
const WCHAR* AudioOutDeviceId;
|
||||
if (OVRP_SUCCESS(PluginWrapper.GetAudioOutDeviceId2((const void**)&AudioOutDeviceId)) && AudioOutDeviceId)
|
||||
{
|
||||
GConfig->SetString(TEXT("Oculus.Settings"), TEXT("AudioOutputDevice"), AudioOutDeviceId, GEngineIni);
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogHMD, Log, TEXT("Could not determine HMD audio output device"));
|
||||
}
|
||||
#endif
|
||||
|
||||
float ModulePriority;
|
||||
if (!GConfig->GetFloat(TEXT("HMDPluginPriority"), *GetModuleKeyName(), ModulePriority, GEngineIni))
|
||||
{
|
||||
// if user doesn't set priority set it for them to allow this hmd to be used if enabled
|
||||
ModulePriority = 45.0f;
|
||||
GConfig->SetFloat(TEXT("HMDPluginPriority"), *GetModuleKeyName(), ModulePriority, GEngineIni);
|
||||
}
|
||||
|
||||
UE_LOG(LogHMD, Log, TEXT("FOculusXRHMDModule PreInit successfully"));
|
||||
|
||||
bPreInit = true;
|
||||
}
|
||||
}
|
||||
|
||||
return bPreInit;
|
||||
#else
|
||||
return false;
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
}
|
||||
|
||||
bool FOculusXRHMDModule::IsHMDConnected()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
UOculusXRHMDRuntimeSettings* HMDSettings = GetMutableDefault<UOculusXRHMDRuntimeSettings>();
|
||||
if (FApp::CanEverRender() && HMDSettings->XrApi != EOculusXRXrApi::NativeOpenXR)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64 FOculusXRHMDModule::GetGraphicsAdapterLuid()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS_D3D11 || OCULUS_HMD_SUPPORTED_PLATFORMS_D3D12
|
||||
if (!GraphicsAdapterLuid)
|
||||
{
|
||||
int GraphicsAdapter;
|
||||
|
||||
if (GConfig->GetInt(TEXT("Oculus.Settings"), TEXT("GraphicsAdapter"), GraphicsAdapter, GEngineIni) && GraphicsAdapter >= 0)
|
||||
{
|
||||
TRefCountPtr<IDXGIFactory> DXGIFactory;
|
||||
TRefCountPtr<IDXGIAdapter> DXGIAdapter;
|
||||
DXGI_ADAPTER_DESC DXGIAdapterDesc;
|
||||
|
||||
if (SUCCEEDED(CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)DXGIFactory.GetInitReference())) && SUCCEEDED(DXGIFactory->EnumAdapters(GraphicsAdapter, DXGIAdapter.GetInitReference())) && SUCCEEDED(DXGIAdapter->GetDesc(&DXGIAdapterDesc)))
|
||||
{
|
||||
FMemory::Memcpy(&GraphicsAdapterLuid, &DXGIAdapterDesc.AdapterLuid, sizeof(GraphicsAdapterLuid));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
return GraphicsAdapterLuid;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
FString FOculusXRHMDModule::GetAudioInputDevice()
|
||||
{
|
||||
FString AudioInputDevice;
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
GConfig->GetString(TEXT("Oculus.Settings"), TEXT("AudioInputDevice"), AudioInputDevice, GEngineIni);
|
||||
#endif
|
||||
return AudioInputDevice;
|
||||
}
|
||||
|
||||
FString FOculusXRHMDModule::GetAudioOutputDevice()
|
||||
{
|
||||
FString AudioOutputDevice;
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
#if PLATFORM_WINDOWS
|
||||
if (bPreInit)
|
||||
{
|
||||
if (FApp::CanEverRender())
|
||||
{
|
||||
const WCHAR* audioOutDeviceId;
|
||||
if (OVRP_SUCCESS(PluginWrapper.GetAudioOutDeviceId2((const void**)&audioOutDeviceId)) && audioOutDeviceId)
|
||||
{
|
||||
AudioOutputDevice = audioOutDeviceId;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
GConfig->GetString(TEXT("Oculus.Settings"), TEXT("AudioOutputDevice"), AudioOutputDevice, GEngineIni);
|
||||
#endif
|
||||
#endif
|
||||
return AudioOutputDevice;
|
||||
}
|
||||
|
||||
TSharedPtr<class IXRTrackingSystem, ESPMode::ThreadSafe> FOculusXRHMDModule::CreateTrackingSystem()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
if (bPreInit || (GIsEditor && PLATFORM_WINDOWS))
|
||||
{
|
||||
// If -HMDSimulator is used as the command option to launch UE, use simulator runtime instead of the physical HMD runtime (like PC-Link).
|
||||
if (FParse::Param(FCommandLine::Get(), TEXT("HMDSimulator")) && IsSimulatorInstalled())
|
||||
{
|
||||
if (!IsSimulatorActivated())
|
||||
{
|
||||
ToggleOpenXRRuntime();
|
||||
}
|
||||
}
|
||||
|
||||
OculusXRHMD::FOculusXRHMDPtr OculusXRHMD = FSceneViewExtensions::NewExtension<OculusXRHMD::FOculusXRHMD>();
|
||||
|
||||
if (OculusXRHMD->Startup())
|
||||
{
|
||||
HeadMountedDisplay = OculusXRHMD;
|
||||
return OculusXRHMD;
|
||||
}
|
||||
}
|
||||
HeadMountedDisplay = nullptr;
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TSharedPtr<IHeadMountedDisplayVulkanExtensions, ESPMode::ThreadSafe> FOculusXRHMDModule::GetVulkanExtensions()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
if (bPreInit)
|
||||
{
|
||||
if (!VulkanExtensions.IsValid())
|
||||
{
|
||||
VulkanExtensions = MakeShareable(new OculusXRHMD::FVulkanExtensions);
|
||||
}
|
||||
}
|
||||
#if WITH_EDITOR && PLATFORM_WINDOWS
|
||||
else if (GIsEditor)
|
||||
{
|
||||
// OpenXR has no ability to query for possible vulkan extensions without connecting a HMD.
|
||||
// This is a problem, because we need to create our VkInstance and VkDevice to render in 2D and there's no HMD.
|
||||
// For now, as a workaround, we hardcode the extensions that Oculus's OpenXR implementation needs.
|
||||
// Eventually, one of three things has to happen for a proper fix:
|
||||
//
|
||||
// 1. OculusXRHMD (or, better, OVRPlugin) maintains a separate VkInstance that has the right extensions,
|
||||
// and uses the vk_external extensions to transfer data between them when needed.
|
||||
// 2. OpenXR changes to allow querying instance and device extensions without an active HMD.
|
||||
// It may still require a physical device handle to list device extensions.
|
||||
// 3. Oculus's Link implementation for OpenXR changes to allow an XrSystemId to be created before a headset
|
||||
// is connected (possibly as an opt-in OpenXR extension for backwards compatibility).
|
||||
//
|
||||
// (2) or (3) are preferable, but if OpenXR is held constant we will have to do (1).
|
||||
if (!VulkanExtensions.IsValid())
|
||||
{
|
||||
VulkanExtensions = MakeShareable(new OculusXRHMD::FEditorVulkanExtensions);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return VulkanExtensions;
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FString FOculusXRHMDModule::GetDeviceSystemName()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
ovrpSystemHeadset SystemHeadset;
|
||||
if (PluginWrapper.IsInitialized() && OVRP_SUCCESS(PluginWrapper.GetSystemHeadsetType2(&SystemHeadset)))
|
||||
{
|
||||
switch (SystemHeadset)
|
||||
{
|
||||
case ovrpSystemHeadset_Oculus_Quest:
|
||||
return FString("Oculus Quest");
|
||||
|
||||
case ovrpSystemHeadset_Oculus_Quest_2:
|
||||
default:
|
||||
return FString("Oculus Quest2");
|
||||
|
||||
case ovrpSystemHeadset_Meta_Quest_Pro:
|
||||
return FString("Meta Quest Pro");
|
||||
|
||||
case ovrpSystemHeadset_Meta_Quest_3:
|
||||
return FString("Meta Quest 3");
|
||||
|
||||
case ovrpSystemHeadset_Meta_Quest_3S:
|
||||
// The marketplace engine does not have the Quest 3S device profile yet, so just represent the system as Quest 3 to use the closest device profile
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
return FString("Meta Quest 3S");
|
||||
#else // WITH_OCULUS_BRANCH
|
||||
return FString("Meta Quest 3");
|
||||
#endif // WITH_OCULUS_BRANCH
|
||||
}
|
||||
}
|
||||
return FString();
|
||||
#else
|
||||
return FString();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool FOculusXRHMDModule::IsStandaloneStereoOnlyDevice()
|
||||
{
|
||||
#if PLATFORM_ANDROID
|
||||
return FAndroidMisc::GetDeviceMake() == FString("Oculus");
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool FOculusXRHMDModule::IsSimulatorActivated()
|
||||
{
|
||||
#if PLATFORM_WINDOWS
|
||||
return FMetaXRSimulator::IsSimulatorActivated();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool FOculusXRHMDModule::IsSimulatorInstalled()
|
||||
{
|
||||
#if PLATFORM_WINDOWS
|
||||
return FMetaXRSimulator::IsSimulatorInstalled();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void FOculusXRHMDModule::ToggleOpenXRRuntime()
|
||||
{
|
||||
#if PLATFORM_WINDOWS
|
||||
FMetaXRSimulator::ToggleOpenXRRuntime();
|
||||
#endif
|
||||
}
|
||||
|
||||
void FOculusXRHMDModule::LaunchEnvironment(int32 EnvironmentIndex)
|
||||
{
|
||||
#if PLATFORM_WINDOWS
|
||||
FMetaXRSES::LaunchEnvironment(EnvironmentIndex);
|
||||
#endif
|
||||
}
|
||||
|
||||
void FOculusXRHMDModule::StopServer()
|
||||
{
|
||||
#if PLATFORM_WINDOWS
|
||||
FMetaXRSES::StopServer();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
void* FOculusXRHMDModule::GetOVRPluginHandle()
|
||||
{
|
||||
void* OVRPluginHandle = nullptr;
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
FString XrApi;
|
||||
if (!FModuleManager::Get().IsModuleLoaded("OpenXRHMD") || !GConfig->GetString(TEXT("/Script/OculusXRHMD.OculusXRHMDRuntimeSettings"), TEXT("XrApi"), XrApi, GEngineIni) || XrApi.Equals(FString("OVRPluginOpenXR")))
|
||||
{
|
||||
FString BinariesPath = FPaths::Combine(IPluginManager::Get().FindPlugin(TEXT("OculusXR"))->GetBaseDir(), TEXT("/Source/ThirdParty/OVRPlugin/OVRPlugin/Lib/Win64"));
|
||||
FPlatformProcess::PushDllDirectory(*BinariesPath);
|
||||
OVRPluginHandle = FPlatformProcess::GetDllHandle(*(BinariesPath / "OpenXR/OVRPlugin.dll"));
|
||||
FPlatformProcess::PopDllDirectory(*BinariesPath);
|
||||
}
|
||||
#elif PLATFORM_ANDROID
|
||||
OVRPluginHandle = FPlatformProcess::GetDllHandle(TEXT("libOVRPlugin.so"));
|
||||
#endif // PLATFORM_ANDROID
|
||||
|
||||
return OVRPluginHandle;
|
||||
}
|
||||
|
||||
bool FOculusXRHMDModule::PoseToOrientationAndPosition(const FQuat& InOrientation, const FVector& InPosition, FQuat& OutOrientation, FVector& OutPosition) const
|
||||
{
|
||||
OculusXRHMD::CheckInGameThread();
|
||||
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = static_cast<OculusXRHMD::FOculusXRHMD*>(HeadMountedDisplay.Pin().Get());
|
||||
|
||||
if (OculusXRHMD)
|
||||
{
|
||||
ovrpPosef InPose;
|
||||
InPose.Orientation = OculusXRHMD::ToOvrpQuatf(InOrientation);
|
||||
InPose.Position = OculusXRHMD::ToOvrpVector3f(InPosition);
|
||||
OculusXRHMD::FPose OutPose;
|
||||
|
||||
if (OculusXRHMD->ConvertPose(InPose, OutPose))
|
||||
{
|
||||
OutOrientation = OutPose.Orientation;
|
||||
OutPosition = OutPose.Position;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void FOculusXRHMDModule::SetGraphicsAdapterLuid(uint64 InLuid)
|
||||
{
|
||||
GraphicsAdapterLuid = InLuid;
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS_D3D11 || OCULUS_HMD_SUPPORTED_PLATFORMS_D3D12
|
||||
TRefCountPtr<IDXGIFactory> DXGIFactory;
|
||||
|
||||
if (SUCCEEDED(CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)DXGIFactory.GetInitReference())))
|
||||
{
|
||||
for (int32 adapterIndex = 0;; adapterIndex++)
|
||||
{
|
||||
TRefCountPtr<IDXGIAdapter> DXGIAdapter;
|
||||
DXGI_ADAPTER_DESC DXGIAdapterDesc;
|
||||
|
||||
if (FAILED(DXGIFactory->EnumAdapters(adapterIndex, DXGIAdapter.GetInitReference())) || FAILED(DXGIAdapter->GetDesc(&DXGIAdapterDesc)))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (!FMemory::Memcmp(&GraphicsAdapterLuid, &DXGIAdapterDesc.AdapterLuid, sizeof(GraphicsAdapterLuid)))
|
||||
{
|
||||
// Remember this adapterIndex so we use the right adapter, even when we startup without HMD connected
|
||||
GConfig->SetInt(TEXT("Oculus.Settings"), TEXT("GraphicsAdapter"), adapterIndex, GEngineIni);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS_D3D11 || OCULUS_HMD_SUPPORTED_PLATFORMS_D3D12
|
||||
}
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
|
||||
IMPLEMENT_MODULE(FOculusXRHMDModule, OculusXRHMD)
|
||||
126
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDModule.h
Normal file
126
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDModule.h
Normal file
@@ -0,0 +1,126 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
#include "OculusXRHMDPrivate.h"
|
||||
#include "IHeadMountedDisplay.h"
|
||||
#include "OculusXRFunctionLibrary.h"
|
||||
#include "OculusXRHMD_VulkanExtensions.h"
|
||||
#include "OculusXRPluginWrapper.h"
|
||||
#include "OpenXR/OculusXRExtensionPluginManager.h"
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// FOculusXRHMDModule
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
class FOculusXRHMDModule : public IOculusXRHMDModule
|
||||
{
|
||||
public:
|
||||
FOculusXRHMDModule();
|
||||
|
||||
static inline FOculusXRHMDModule& Get()
|
||||
{
|
||||
return FModuleManager::LoadModuleChecked<FOculusXRHMDModule>(NAME_OculusXRHMD);
|
||||
}
|
||||
|
||||
// IModuleInterface
|
||||
virtual void StartupModule() override;
|
||||
virtual void ShutdownModule() override;
|
||||
|
||||
// IHeadMountedDisplayModule
|
||||
virtual FString GetModuleKeyName() const override;
|
||||
virtual void GetModuleAliases(TArray<FString>& AliasesOut) const override;
|
||||
virtual bool PreInit() override;
|
||||
virtual bool IsHMDConnected() override;
|
||||
virtual uint64 GetGraphicsAdapterLuid() override;
|
||||
virtual FString GetAudioInputDevice() override;
|
||||
virtual FString GetAudioOutputDevice() override;
|
||||
virtual FString GetDeviceSystemName() override;
|
||||
|
||||
virtual TSharedPtr<class IXRTrackingSystem, ESPMode::ThreadSafe> CreateTrackingSystem() override;
|
||||
virtual TSharedPtr<IHeadMountedDisplayVulkanExtensions, ESPMode::ThreadSafe> GetVulkanExtensions() override;
|
||||
virtual bool IsStandaloneStereoOnlyDevice() override;
|
||||
|
||||
virtual OculusXR::FExtensionPluginManager& GetExtensionPluginManager();
|
||||
|
||||
// IOculusXRHMDModule
|
||||
virtual void GetPose(FRotator& DeviceRotation, FVector& DevicePosition, FVector& NeckPosition, bool bUseOrienationForPlayerCamera = false, bool bUsePositionForPlayerCamera = false, const FVector PositionScale = FVector::ZeroVector) override
|
||||
{
|
||||
UOculusXRFunctionLibrary::GetPose(DeviceRotation, DevicePosition, NeckPosition, bUseOrienationForPlayerCamera, bUsePositionForPlayerCamera, PositionScale);
|
||||
}
|
||||
|
||||
virtual void GetRawSensorData(FVector& AngularAcceleration, FVector& LinearAcceleration, FVector& AngularVelocity, FVector& LinearVelocity, float& TimeInSeconds) override
|
||||
{
|
||||
UOculusXRFunctionLibrary::GetRawSensorData(AngularAcceleration, LinearAcceleration, AngularVelocity, LinearVelocity, TimeInSeconds, EOculusXRTrackedDeviceType::HMD);
|
||||
}
|
||||
|
||||
virtual bool GetUserProfile(struct FOculusXRHmdUserProfile& Profile) override
|
||||
{
|
||||
return UOculusXRFunctionLibrary::GetUserProfile(Profile);
|
||||
}
|
||||
|
||||
virtual void SetBaseRotationAndBaseOffsetInMeters(FRotator Rotation, FVector BaseOffsetInMeters, EOrientPositionSelector::Type Options) override
|
||||
{
|
||||
UOculusXRFunctionLibrary::SetBaseRotationAndBaseOffsetInMeters(Rotation, BaseOffsetInMeters, Options);
|
||||
}
|
||||
|
||||
virtual void GetBaseRotationAndBaseOffsetInMeters(FRotator& OutRotation, FVector& OutBaseOffsetInMeters) override
|
||||
{
|
||||
UOculusXRFunctionLibrary::GetBaseRotationAndBaseOffsetInMeters(OutRotation, OutBaseOffsetInMeters);
|
||||
}
|
||||
|
||||
virtual void SetBaseRotationAndPositionOffset(FRotator BaseRot, FVector PosOffset, EOrientPositionSelector::Type Options) override
|
||||
{
|
||||
UOculusXRFunctionLibrary::SetBaseRotationAndPositionOffset(BaseRot, PosOffset, Options);
|
||||
}
|
||||
|
||||
virtual void GetBaseRotationAndPositionOffset(FRotator& OutRot, FVector& OutPosOffset) override
|
||||
{
|
||||
UOculusXRFunctionLibrary::GetBaseRotationAndPositionOffset(OutRot, OutPosOffset);
|
||||
}
|
||||
|
||||
virtual class IStereoLayers* GetStereoLayers() override
|
||||
{
|
||||
return UOculusXRFunctionLibrary::GetStereoLayers();
|
||||
}
|
||||
|
||||
bool IsOVRPluginAvailable() const
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
return OVRPluginHandle != nullptr;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// FMetaXRSimulator
|
||||
OCULUSXRHMD_API static bool IsSimulatorActivated();
|
||||
OCULUSXRHMD_API static void ToggleOpenXRRuntime();
|
||||
OCULUSXRHMD_API static bool IsSimulatorInstalled();
|
||||
|
||||
// FMetaXRSES
|
||||
OCULUSXRHMD_API static void LaunchEnvironment(int32 EnvironmentIndex);
|
||||
OCULUSXRHMD_API static void StopServer();
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OCULUSXRHMD_API static void* GetOVRPluginHandle();
|
||||
OCULUSXRHMD_API static OculusPluginWrapper& GetPluginWrapper();
|
||||
virtual bool PoseToOrientationAndPosition(const FQuat& InOrientation, const FVector& InPosition, FQuat& OutOrientation, FVector& OutPosition) const override;
|
||||
|
||||
protected:
|
||||
void SetGraphicsAdapterLuid(uint64 InLuid);
|
||||
|
||||
static OculusPluginWrapper PluginWrapper;
|
||||
|
||||
bool bPreInit;
|
||||
bool bPreInitCalled;
|
||||
void* OVRPluginHandle;
|
||||
uint64 GraphicsAdapterLuid;
|
||||
TWeakPtr<IHeadMountedDisplay, ESPMode::ThreadSafe> HeadMountedDisplay;
|
||||
TSharedPtr<IHeadMountedDisplayVulkanExtensions, ESPMode::ThreadSafe> VulkanExtensions;
|
||||
OculusXR::FExtensionPluginManager ExtensionPluginManager;
|
||||
|
||||
friend class ::OculusXRHMD::FOculusXRHMD;
|
||||
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
};
|
||||
103
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDPrivate.cpp
Normal file
103
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDPrivate.cpp
Normal file
@@ -0,0 +1,103 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "OculusXRHMDPrivate.h"
|
||||
#include "RHICommandList.h"
|
||||
#include "RenderingThread.h"
|
||||
|
||||
namespace OculusXRHMD
|
||||
{
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// Utility functions
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
// TODO: Change in case of parallel game threads
|
||||
bool InGameThread()
|
||||
{
|
||||
if (GIsGameThreadIdInitialized)
|
||||
{
|
||||
return FPlatformTLS::GetCurrentThreadId() == GGameThreadId;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool InRenderThread()
|
||||
{
|
||||
#if UE_VERSION_OLDER_THAN(5, 5, 0)
|
||||
if (GIsThreadedRendering && !GIsRenderingThreadSuspended.Load(EMemoryOrder::Relaxed))
|
||||
#else
|
||||
if (GIsThreadedRendering)
|
||||
#endif
|
||||
{
|
||||
return IsInParallelRenderingThread();
|
||||
}
|
||||
else
|
||||
{
|
||||
return InGameThread();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Change in case of parallel RHI threads
|
||||
bool InRHIThread()
|
||||
{
|
||||
#if UE_VERSION_OLDER_THAN(5, 5, 0)
|
||||
if (GIsThreadedRendering && !GIsRenderingThreadSuspended.Load(EMemoryOrder::Relaxed))
|
||||
#else
|
||||
if (GIsThreadedRendering)
|
||||
#endif
|
||||
{
|
||||
if (IsRHIThreadRunning())
|
||||
{
|
||||
if (IsInRHIThread())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsInParallelRenderingThread())
|
||||
{
|
||||
return GetImmediateCommandList_ForRenderCommand().Bypass();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return IsInParallelRenderingThread();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return InGameThread();
|
||||
}
|
||||
}
|
||||
|
||||
bool ConvertPose_Internal(const FPose& InPose, FPose& OutPose, const FQuat BaseOrientation, const FVector BaseOffset, float WorldToMetersScale)
|
||||
{
|
||||
// apply base orientation correction
|
||||
OutPose.Orientation = BaseOrientation.Inverse() * InPose.Orientation;
|
||||
OutPose.Orientation.Normalize();
|
||||
|
||||
// correct position according to BaseOrientation and BaseOffset.
|
||||
OutPose.Position = (InPose.Position - BaseOffset) * WorldToMetersScale;
|
||||
OutPose.Position = BaseOrientation.Inverse().RotateVector(OutPose.Position);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConvertPose_Internal(const ovrpPosef& InPose, FPose& OutPose, const FQuat BaseOrientation, const FVector BaseOffset, float WorldToMetersScale)
|
||||
{
|
||||
return ConvertPose_Internal(FPose(ToFQuat(InPose.Orientation), ToFVector(InPose.Position)), OutPose, BaseOrientation, BaseOffset, WorldToMetersScale);
|
||||
}
|
||||
|
||||
bool ConvertPose_Internal(const FPose& InPose, ovrpPosef& OutPose, const FQuat BaseOrientation, const FVector BaseOffset, float WorldToMetersScale)
|
||||
{
|
||||
OutPose.Orientation = ToOvrpQuatf(BaseOrientation * InPose.Orientation);
|
||||
OutPose.Position = ToOvrpVector3f(BaseOrientation.RotateVector(InPose.Position) / WorldToMetersScale + BaseOffset);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace OculusXRHMD
|
||||
317
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDPrivate.h
Normal file
317
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDPrivate.h
Normal file
@@ -0,0 +1,317 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
#include "GameFramework/WorldSettings.h"
|
||||
#include "IOculusXRHMDModule.h"
|
||||
#include "OculusXRFunctionLibrary.h"
|
||||
#include "OculusXRPassthroughLayerShapes.h"
|
||||
#include "StereoRendering.h"
|
||||
#include "HAL/RunnableThread.h"
|
||||
#include "RHI.h"
|
||||
#include <functional>
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
#define OCULUS_HMD_SUPPORTED_PLATFORMS_D3D11 PLATFORM_WINDOWS
|
||||
#define OCULUS_HMD_SUPPORTED_PLATFORMS_D3D12 PLATFORM_WINDOWS
|
||||
#define OCULUS_HMD_SUPPORTED_PLATFORMS_VULKAN (PLATFORM_WINDOWS || PLATFORM_ANDROID)
|
||||
#else
|
||||
#define OCULUS_HMD_SUPPORTED_PLATFORMS_D3D11 0
|
||||
#define OCULUS_HMD_SUPPORTED_PLATFORMS_D3D12 0
|
||||
#define OCULUS_HMD_SUPPORTED_PLATFORMS_VULKAN 0
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// OVRPlugin
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
#include "OculusXRPluginWrapper.h"
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// Utility functions
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
namespace OculusXRHMD
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
struct FPose
|
||||
{
|
||||
FQuat Orientation;
|
||||
FVector Position;
|
||||
|
||||
FPose()
|
||||
: Orientation(EForceInit::ForceInit)
|
||||
, Position(EForceInit::ForceInit)
|
||||
{
|
||||
}
|
||||
|
||||
FPose(const FQuat& InOrientation, const FVector& InPosition)
|
||||
: Orientation(InOrientation), Position(InPosition) {}
|
||||
|
||||
FPose Inverse() const
|
||||
{
|
||||
FQuat InvOrientation = Orientation.Inverse();
|
||||
FVector InvPosition = InvOrientation.RotateVector(-Position);
|
||||
return FPose(InvOrientation, InvPosition);
|
||||
}
|
||||
|
||||
FPose operator*(const FPose& other) const
|
||||
{
|
||||
return FPose(Orientation * other.Orientation, Orientation.RotateVector(other.Position) + Position);
|
||||
}
|
||||
};
|
||||
|
||||
/** Converts ovrpQuatf to FQuat */
|
||||
FORCEINLINE FQuat ToFQuat(const ovrpQuatf& InQuat)
|
||||
{
|
||||
return FQuat(-InQuat.z, InQuat.x, InQuat.y, -InQuat.w);
|
||||
}
|
||||
|
||||
/** Converts FQuat to ovrpQuatf */
|
||||
FORCEINLINE ovrpQuatf ToOvrpQuatf(const FQuat& InQuat)
|
||||
{
|
||||
return ovrpQuatf{ static_cast<float>(InQuat.Y), static_cast<float>(InQuat.Z), static_cast<float>(-InQuat.X), static_cast<float>(-InQuat.W) };
|
||||
}
|
||||
|
||||
/** Converts vector from Oculus to Unreal */
|
||||
FORCEINLINE FVector ToFVector(const ovrpVector3f& InVec)
|
||||
{
|
||||
return FVector(-InVec.z, InVec.x, InVec.y);
|
||||
}
|
||||
|
||||
/** Converts vector from Unreal to Oculus. */
|
||||
FORCEINLINE ovrpVector3f ToOvrpVector3f(const FVector& InVec)
|
||||
{
|
||||
return ovrpVector3f{ static_cast<float>(InVec.Y), static_cast<float>(InVec.Z), static_cast<float>(-InVec.X) };
|
||||
}
|
||||
|
||||
FORCEINLINE FMatrix ToFMatrix(const ovrpMatrix4f& vtm)
|
||||
{
|
||||
// Rows and columns are swapped between ovrpMatrix4f and FMatrix
|
||||
return FMatrix(
|
||||
FPlane(vtm.M[0][0], vtm.M[1][0], vtm.M[2][0], vtm.M[3][0]),
|
||||
FPlane(vtm.M[0][1], vtm.M[1][1], vtm.M[2][1], vtm.M[3][1]),
|
||||
FPlane(vtm.M[0][2], vtm.M[1][2], vtm.M[2][2], vtm.M[3][2]),
|
||||
FPlane(vtm.M[0][3], vtm.M[1][3], vtm.M[2][3], vtm.M[3][3]));
|
||||
}
|
||||
|
||||
FORCEINLINE ovrpVector4f LinearColorToOvrpVector4f(const FLinearColor& InColor)
|
||||
{
|
||||
return ovrpVector4f{ InColor.R, InColor.G, InColor.B, InColor.A };
|
||||
}
|
||||
|
||||
FORCEINLINE ovrpRecti ToOvrpRecti(const FIntRect& rect)
|
||||
{
|
||||
return ovrpRecti{ { rect.Min.X, rect.Min.Y }, { rect.Size().X, rect.Size().Y } };
|
||||
}
|
||||
|
||||
FORCEINLINE FLinearColor ToFLinearColor(const ovrpColorf& color)
|
||||
{
|
||||
return FLinearColor(color.r, color.g, color.b, color.a);
|
||||
}
|
||||
|
||||
FORCEINLINE ovrpColorf ToOvrpColorf(const FLinearColor LinearColor)
|
||||
{
|
||||
return ovrpColorf{ LinearColor.R, LinearColor.G, LinearColor.B, LinearColor.A };
|
||||
}
|
||||
|
||||
FORCEINLINE ovrpMatrix4f ToOvrpMatrix(FMatrix Matrix)
|
||||
{
|
||||
ovrpMatrix4f Result;
|
||||
|
||||
Result.M[0][0] = Matrix.M[0][0];
|
||||
Result.M[0][1] = Matrix.M[0][1];
|
||||
Result.M[0][2] = Matrix.M[0][2];
|
||||
Result.M[0][3] = Matrix.M[0][3];
|
||||
|
||||
Result.M[1][0] = Matrix.M[1][0];
|
||||
Result.M[1][1] = Matrix.M[1][1];
|
||||
Result.M[1][2] = Matrix.M[1][2];
|
||||
Result.M[1][3] = Matrix.M[1][3];
|
||||
|
||||
Result.M[2][0] = Matrix.M[2][0];
|
||||
Result.M[2][1] = Matrix.M[2][1];
|
||||
Result.M[2][2] = Matrix.M[2][2];
|
||||
Result.M[2][3] = Matrix.M[2][3];
|
||||
|
||||
Result.M[3][0] = Matrix.M[3][0];
|
||||
Result.M[3][1] = Matrix.M[3][1];
|
||||
Result.M[3][2] = Matrix.M[3][2];
|
||||
Result.M[3][3] = Matrix.M[3][3];
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
||||
/** Helper that converts ovrTrackedDeviceType to EOculusXRTrackedDeviceType */
|
||||
FORCEINLINE EOculusXRTrackedDeviceType ToEOculusXRTrackedDeviceType(ovrpNode Source)
|
||||
{
|
||||
EOculusXRTrackedDeviceType Destination = EOculusXRTrackedDeviceType::All; // Best attempt at initialization
|
||||
|
||||
switch (Source)
|
||||
{
|
||||
case ovrpNode_None:
|
||||
Destination = EOculusXRTrackedDeviceType::None;
|
||||
break;
|
||||
case ovrpNode_Head:
|
||||
Destination = EOculusXRTrackedDeviceType::HMD;
|
||||
break;
|
||||
case ovrpNode_HandLeft:
|
||||
Destination = EOculusXRTrackedDeviceType::LTouch;
|
||||
break;
|
||||
case ovrpNode_HandRight:
|
||||
Destination = EOculusXRTrackedDeviceType::RTouch;
|
||||
break;
|
||||
case ovrpNode_DeviceObjectZero:
|
||||
Destination = EOculusXRTrackedDeviceType::DeviceObjectZero;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return Destination;
|
||||
}
|
||||
|
||||
/** Helper that converts EOculusXRTrackedDeviceType to ovrTrackedDeviceType */
|
||||
FORCEINLINE ovrpNode ToOvrpNode(EOculusXRTrackedDeviceType Source)
|
||||
{
|
||||
ovrpNode Destination = ovrpNode_None; // Best attempt at initialization
|
||||
|
||||
switch (Source)
|
||||
{
|
||||
case EOculusXRTrackedDeviceType::None:
|
||||
Destination = ovrpNode_None;
|
||||
break;
|
||||
case EOculusXRTrackedDeviceType::HMD:
|
||||
Destination = ovrpNode_Head;
|
||||
break;
|
||||
case EOculusXRTrackedDeviceType::LTouch:
|
||||
Destination = ovrpNode_HandLeft;
|
||||
break;
|
||||
case EOculusXRTrackedDeviceType::RTouch:
|
||||
Destination = ovrpNode_HandRight;
|
||||
break;
|
||||
case EOculusXRTrackedDeviceType::DeviceObjectZero:
|
||||
Destination = ovrpNode_DeviceObjectZero;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return Destination;
|
||||
}
|
||||
|
||||
FORCEINLINE int32 ToExternalDeviceId(const ovrpNode Source)
|
||||
{
|
||||
int32 ExternalDeviceId = INDEX_NONE;
|
||||
switch (Source)
|
||||
{
|
||||
case ovrpNode_Head:
|
||||
// required to be zero (see IXRTrackingSystem::HMDDeviceId)
|
||||
ExternalDeviceId = 0;
|
||||
break;
|
||||
case ovrpNode_None:
|
||||
case ovrpNode_Count:
|
||||
case ovrpNode_EnumSize:
|
||||
// ExternalDeviceId = INDEX_NONE;
|
||||
break;
|
||||
default:
|
||||
// add one, in case the enum value is zero (conflicting with the HMD)
|
||||
ExternalDeviceId = 1 + (int32)Source;
|
||||
break;
|
||||
}
|
||||
return ExternalDeviceId;
|
||||
}
|
||||
|
||||
FORCEINLINE ovrpNode ToOvrpNode(const int32 ExternalDeviceId)
|
||||
{
|
||||
ovrpNode Destination = ovrpNode_None;
|
||||
switch (ExternalDeviceId)
|
||||
{
|
||||
case 0:
|
||||
// zero implies HMD (see ToExternalDeviceId/IXRTrackingSystem::HMDDeviceId)
|
||||
Destination = ovrpNode_Head;
|
||||
break;
|
||||
case -1:
|
||||
// Destination = ovrpNode_None;
|
||||
break;
|
||||
default:
|
||||
// we added one to avoid collision with the HMD's ID (see ToExternalDeviceId)
|
||||
Destination = ovrpNode(ExternalDeviceId - 1);
|
||||
break;
|
||||
}
|
||||
return Destination;
|
||||
}
|
||||
|
||||
bool ConvertPose_Internal(const FPose& InPose, FPose& OutPose, const FQuat BaseOrientation, const FVector BaseOffset, float WorldToMetersScale);
|
||||
|
||||
bool ConvertPose_Internal(const ovrpPosef& InPose, FPose& OutPose, const FQuat BaseOrientation, const FVector BaseOffset, float WorldToMetersScale);
|
||||
|
||||
bool ConvertPose_Internal(const FPose& InPose, ovrpPosef& OutPose, const FQuat BaseOrientation, const FVector BaseOffset, float WorldToMetersScale);
|
||||
|
||||
FORCEINLINE ovrpInsightPassthroughColorMapType ToOVRPColorMapType(EOculusXRColorMapType InColorMapType)
|
||||
{
|
||||
switch (InColorMapType)
|
||||
{
|
||||
case ColorMapType_GrayscaleToColor:
|
||||
return ovrpInsightPassthroughColorMapType_MonoToRgba;
|
||||
case ColorMapType_Grayscale:
|
||||
return ovrpInsightPassthroughColorMapType_MonoToMono;
|
||||
case ColorMapType_ColorAdjustment:
|
||||
return ovrpInsightPassthroughColorMapType_BrightnessContrastSaturation;
|
||||
case ColorMapType_ColorLut:
|
||||
return ovrpInsightPassthroughColorMapType_ColorLut;
|
||||
case ColorMapType_ColorLut_Interpolated:
|
||||
return ovrpInsightPassthroughColorMapType_InterpolatedColorLut;
|
||||
default:
|
||||
return ovrpInsightPassthroughColorMapType_None;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
|
||||
/** Check currently executing from Game thread */
|
||||
OCULUSXRHMD_API bool InGameThread();
|
||||
|
||||
FORCEINLINE void CheckInGameThread()
|
||||
{
|
||||
#if DO_CHECK
|
||||
check(InGameThread());
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Check currently executing from Render thread */
|
||||
OCULUSXRHMD_API bool InRenderThread();
|
||||
|
||||
FORCEINLINE void CheckInRenderThread()
|
||||
{
|
||||
#if DO_CHECK
|
||||
check(InRenderThread());
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Check currently executing from RHI thread */
|
||||
OCULUSXRHMD_API bool InRHIThread();
|
||||
|
||||
FORCEINLINE void CheckInRHIThread()
|
||||
{
|
||||
#if DO_CHECK
|
||||
check(InRHIThread());
|
||||
#endif
|
||||
}
|
||||
|
||||
FORCEINLINE bool GetUnitScaleFactorFromSettings(UWorld* World, float& outWorldToMeters)
|
||||
{
|
||||
if (IsValid(World))
|
||||
{
|
||||
const auto* WorldSettings = World->GetWorldSettings();
|
||||
if (IsValid(WorldSettings))
|
||||
{
|
||||
outWorldToMeters = WorldSettings->WorldToMeters;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace OculusXRHMD
|
||||
@@ -0,0 +1,64 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// D3D11
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS_D3D11
|
||||
#include "ID3D11DynamicRHI.h"
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS_D3D11
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// D3D12
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS_D3D12
|
||||
#define GetD3D11CubeFace GetD3D12CubeFace
|
||||
#define VerifyD3D11Result VerifyD3D12Result
|
||||
#define GetD3D11TextureFromRHITexture GetD3D12TextureFromRHITexture
|
||||
#define FRingAllocation FRingAllocation_D3D12
|
||||
#define GetRenderTargetFormat GetRenderTargetFormat_D3D12
|
||||
#define ED3D11ShaderOffsetBuffer ED3D12ShaderOffsetBuffer
|
||||
#define FindShaderResourceDXGIFormat FindShaderResourceDXGIFormat_D3D12
|
||||
#define FindUnorderedAccessDXGIFormat FindUnorderedAccessDXGIFormat_D3D12
|
||||
#define FindDepthStencilDXGIFormat FindDepthStencilDXGIFormat_D3D12
|
||||
#define HasStencilBits HasStencilBits_D3D12
|
||||
#define FVector4VertexDeclaration FVector4VertexDeclaration_D3D12
|
||||
#define GLOBAL_CONSTANT_BUFFER_INDEX GLOBAL_CONSTANT_BUFFER_INDEX_D3D12
|
||||
#define MAX_CONSTANT_BUFFER_SLOTS MAX_CONSTANT_BUFFER_SLOTS_D3D12
|
||||
#define FD3DGPUProfiler FD3D12GPUProfiler
|
||||
#define FRangeAllocator FRangeAllocator_D3D12
|
||||
|
||||
#include "ID3D12DynamicRHI.h"
|
||||
|
||||
#undef GetD3D11CubeFace
|
||||
#undef VerifyD3D11Result
|
||||
#undef GetD3D11TextureFromRHITexture
|
||||
#undef FRingAllocation
|
||||
#undef GetRenderTargetFormat
|
||||
#undef ED3D11ShaderOffsetBuffer
|
||||
#undef FindShaderResourceDXGIFormat
|
||||
#undef FindUnorderedAccessDXGIFormat
|
||||
#undef FindDepthStencilDXGIFormat
|
||||
#undef HasStencilBits
|
||||
#undef FVector4VertexDeclaration
|
||||
#undef GLOBAL_CONSTANT_BUFFER_INDEX
|
||||
#undef MAX_CONSTANT_BUFFER_SLOTS
|
||||
#undef FD3DGPUProfiler
|
||||
#undef FRangeAllocator
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS_D3D12
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// Vulkan
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS_VULKAN
|
||||
#include "IVulkanDynamicRHI.h"
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS_VULKAN
|
||||
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
@@ -0,0 +1,378 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "OculusXRHMDRuntimeSettings.h"
|
||||
#include "Algo/ForEach.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// UOculusXRHMDRuntimeSettings
|
||||
|
||||
#include "OculusXRHMD_Settings.h"
|
||||
|
||||
#include "DeviceProfiles/DeviceProfile.h"
|
||||
#include "DeviceProfiles/DeviceProfileManager.h"
|
||||
|
||||
UOculusXRHMDRuntimeSettings::UOculusXRHMDRuntimeSettings(const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
, bAutoEnabled(false)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
// FSettings is the sole source of truth for Oculus default settings
|
||||
OculusXRHMD::FSettings DefaultSettings;
|
||||
SystemSplashBackground = DefaultSettings.SystemSplashBackground;
|
||||
bSupportsDash = DefaultSettings.Flags.bSupportsDash;
|
||||
bCompositesDepth = DefaultSettings.Flags.bCompositeDepth;
|
||||
bHQDistortion = DefaultSettings.Flags.bHQDistortion;
|
||||
SuggestedCpuPerfLevel = DefaultSettings.SuggestedCpuPerfLevel;
|
||||
SuggestedGpuPerfLevel = DefaultSettings.SuggestedGpuPerfLevel;
|
||||
FoveatedRenderingMethod = DefaultSettings.FoveatedRenderingMethod;
|
||||
FoveatedRenderingLevel = DefaultSettings.FoveatedRenderingLevel;
|
||||
bDynamicFoveatedRendering = DefaultSettings.bDynamicFoveatedRendering;
|
||||
bSupportEyeTrackedFoveatedRendering = DefaultSettings.bSupportEyeTrackedFoveatedRendering;
|
||||
|
||||
bFocusAware = DefaultSettings.Flags.bFocusAware;
|
||||
bDynamicResolution = DefaultSettings.Flags.bPixelDensityAdaptive;
|
||||
XrApi = DefaultSettings.XrApi;
|
||||
ColorSpace = DefaultSettings.ColorSpace;
|
||||
ControllerPoseAlignment = DefaultSettings.ControllerPoseAlignment;
|
||||
bRequiresSystemKeyboard = DefaultSettings.Flags.bRequiresSystemKeyboard;
|
||||
HandTrackingSupport = DefaultSettings.HandTrackingSupport;
|
||||
HandTrackingFrequency = DefaultSettings.HandTrackingFrequency;
|
||||
HandTrackingVersion = DefaultSettings.HandTrackingVersion;
|
||||
bInsightPassthroughEnabled = DefaultSettings.Flags.bInsightPassthroughEnabled;
|
||||
bBodyTrackingEnabled = DefaultSettings.Flags.bBodyTrackingEnabled;
|
||||
bEyeTrackingEnabled = DefaultSettings.Flags.bEyeTrackingEnabled;
|
||||
bFaceTrackingEnabled = DefaultSettings.Flags.bFaceTrackingEnabled;
|
||||
bSupportExperimentalFeatures = DefaultSettings.bSupportExperimentalFeatures;
|
||||
bAnchorSupportEnabled = DefaultSettings.Flags.bAnchorSupportEnabled;
|
||||
bAnchorSharingEnabled = DefaultSettings.Flags.bAnchorSharingEnabled;
|
||||
bSceneSupportEnabled = DefaultSettings.Flags.bSceneSupportEnabled;
|
||||
bIterativeCookOnTheFly = DefaultSettings.Flags.bIterativeCookOnTheFly;
|
||||
bSetActivePIEToPrimary = DefaultSettings.Flags.bSetActivePIEToPrimary;
|
||||
bSetCVarPIEToPrimary = DefaultSettings.Flags.bSetCVarPIEToPrimary;
|
||||
bUpdateHeadPoseForInactivePlayer = DefaultSettings.Flags.bUpdateHeadPoseForInactivePlayer;
|
||||
MPPoseRestoreType = DefaultSettings.MPPoseRestoreType;
|
||||
bBoundaryVisibilitySupportEnabled = DefaultSettings.Flags.bBoundaryVisibilitySupportEnabled;
|
||||
bDefaultBoundaryVisibilitySuppressed = DefaultSettings.Flags.bDefaultBoundaryVisibilitySuppressed;
|
||||
bColocationSessionsEnabled = DefaultSettings.Flags.bColocationSessionsEnabled;
|
||||
ProcessorFavor = DefaultSettings.ProcessorFavor;
|
||||
bTileTurnOffEnabled = DefaultSettings.Flags.bTileTurnOffEnabled;
|
||||
|
||||
BodyTrackingFidelity = DefaultSettings.BodyTrackingFidelity;
|
||||
BodyTrackingJointSet = DefaultSettings.BodyTrackingJointSet;
|
||||
|
||||
FaceTrackingDataSource.Empty(static_cast<int8>(EFaceTrackingDataSourceConfig::MAX));
|
||||
FaceTrackingDataSource.Append(DefaultSettings.FaceTrackingDataSource);
|
||||
bFaceTrackingVisemesEnabled = DefaultSettings.bFaceTrackingVisemesEnabled;
|
||||
|
||||
// Default this to false, FSettings doesn't have a separate composite depth flag for mobile
|
||||
bCompositeDepthMobile = false;
|
||||
|
||||
bThumbstickDpadEmulationEnabled = true;
|
||||
|
||||
bSupportSBC = DefaultSettings.Flags.bSupportSBC;
|
||||
SBCPath = DefaultSettings.SBCPath;
|
||||
#else
|
||||
// Some set of reasonable defaults, since blueprints are still available on non-Oculus platforms.
|
||||
SystemSplashBackground = ESystemSplashBackgroundType::Black;
|
||||
bSupportsDash = false;
|
||||
bCompositesDepth = false;
|
||||
bHQDistortion = false;
|
||||
SuggestedCpuPerfLevel = EOculusXRProcessorPerformanceLevel::SustainedLow;
|
||||
SuggestedGpuPerfLevel = EOculusXRProcessorPerformanceLevel::SustainedHigh;
|
||||
FoveatedRenderingMethod = EOculusXRFoveatedRenderingMethod::FixedFoveatedRendering;
|
||||
FoveatedRenderingLevel = EOculusXRFoveatedRenderingLevel::Off;
|
||||
bDynamicFoveatedRendering = false;
|
||||
bSupportEyeTrackedFoveatedRendering = false;
|
||||
bDynamicResolution = false;
|
||||
bCompositeDepthMobile = false;
|
||||
bFocusAware = true;
|
||||
XrApi = EOculusXRXrApi::OVRPluginOpenXR;
|
||||
bLateLatching = false;
|
||||
ColorSpace = EOculusXRColorSpace::P3;
|
||||
ControllerPoseAlignment = EOculusXRControllerPoseAlignment::Default;
|
||||
bRequiresSystemKeyboard = false;
|
||||
HandTrackingSupport = EOculusXRHandTrackingSupport::ControllersOnly;
|
||||
HandTrackingFrequency = EOculusXRHandTrackingFrequency::Low;
|
||||
HandTrackingVersion = EOculusXRHandTrackingVersion::Default;
|
||||
bInsightPassthroughEnabled = false;
|
||||
bSupportExperimentalFeatures = false;
|
||||
bBodyTrackingEnabled = false;
|
||||
bEyeTrackingEnabled = false;
|
||||
bFaceTrackingEnabled = false;
|
||||
bSupportSBC = false;
|
||||
bFaceTrackingVisemesEnabled = false;
|
||||
bAnchorSupportEnabled = false;
|
||||
bAnchorSharingEnabled = false;
|
||||
bSceneSupportEnabled = false;
|
||||
bIterativeCookOnTheFly = false;
|
||||
bSetActivePIEToPrimary = false;
|
||||
bSetCVarPIEToPrimary = false;
|
||||
bUpdateHeadPoseForInactivePlayer = false;
|
||||
MPPoseRestoreType = EOculusXRMPPoseRestoreType::Disabled;
|
||||
bBoundaryVisibilitySupportEnabled = false;
|
||||
bDefaultBoundaryVisibilitySuppressed = false;
|
||||
bColocationSessionsEnabled = false;
|
||||
ProcessorFavor = EProcessorFavor::FavorEqually;
|
||||
bTileTurnOffEnabled = false;
|
||||
bThumbstickDpadEmulationEnabled = true;
|
||||
#endif
|
||||
|
||||
LoadFromIni();
|
||||
}
|
||||
|
||||
#if WITH_EDITOR
|
||||
bool UOculusXRHMDRuntimeSettings::CanEditChange(const FProperty* InProperty) const
|
||||
{
|
||||
bool bIsEditable = Super::CanEditChange(InProperty);
|
||||
|
||||
if (bIsEditable && InProperty)
|
||||
{
|
||||
const FName PropertyName = InProperty->GetFName();
|
||||
|
||||
if (PropertyName == GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, XrApi) && !FModuleManager::Get().IsModuleLoaded("OpenXRHMD"))
|
||||
{
|
||||
bIsEditable = false;
|
||||
}
|
||||
|
||||
// Disable settings for marketplace release that are only compatible with the Oculus engine fork
|
||||
#ifndef WITH_OCULUS_BRANCH
|
||||
if (PropertyName == GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, FoveatedRenderingMethod) || PropertyName == GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, bSupportEyeTrackedFoveatedRendering) || PropertyName == GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, bDynamicResolution))
|
||||
|
||||
{
|
||||
bIsEditable = false;
|
||||
}
|
||||
#endif // WITH_OCULUS_BRANCH
|
||||
}
|
||||
|
||||
return bIsEditable;
|
||||
}
|
||||
|
||||
void UOculusXRHMDRuntimeSettings::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent)
|
||||
{
|
||||
Super::PostEditChangeProperty(PropertyChangedEvent);
|
||||
|
||||
if (PropertyChangedEvent.Property != nullptr)
|
||||
{
|
||||
// Automatically switch to Fixed Foveated Rendering when removing Eye Tracked Foveated rendering support
|
||||
if (PropertyChangedEvent.Property->GetFName() == GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, bSupportEyeTrackedFoveatedRendering) && !bSupportEyeTrackedFoveatedRendering)
|
||||
{
|
||||
FoveatedRenderingMethod = EOculusXRFoveatedRenderingMethod::FixedFoveatedRendering;
|
||||
UpdateSinglePropertyInConfigFile(GetClass()->FindPropertyByName(GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, FoveatedRenderingMethod)), GetDefaultConfigFilename());
|
||||
}
|
||||
// Automatically enable support for eye tracked foveated rendering when selecting the Eye Tracked Foveated Rendering method
|
||||
if (PropertyChangedEvent.Property->GetFName() == GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, FoveatedRenderingMethod) && FoveatedRenderingMethod == EOculusXRFoveatedRenderingMethod::EyeTrackedFoveatedRendering)
|
||||
{
|
||||
bSupportEyeTrackedFoveatedRendering = true;
|
||||
UpdateSinglePropertyInConfigFile(GetClass()->FindPropertyByName(GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, bSupportEyeTrackedFoveatedRendering)), GetDefaultConfigFilename());
|
||||
}
|
||||
|
||||
if (PropertyChangedEvent.Property->GetFName() == GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, SupportedDevices))
|
||||
{
|
||||
if (PropertyChangedEvent.ChangeType == EPropertyChangeType::ArrayAdd)
|
||||
{
|
||||
// Get a list of all available devices
|
||||
TArray<EOculusXRSupportedDevices> deviceList;
|
||||
#define OCULUS_DEVICE_LOOP(device) deviceList.Add(device);
|
||||
FOREACH_ENUM_EOCULUSXRSUPPORTEDDEVICES(OCULUS_DEVICE_LOOP);
|
||||
#undef OCULUS_DEVICE_LOOP
|
||||
// Add last device that isn't already in the list
|
||||
for (int i = deviceList.Num() - 1; i >= 0; --i)
|
||||
{
|
||||
if (!SupportedDevices.Contains(deviceList[i]))
|
||||
{
|
||||
SupportedDevices.Last() = deviceList[i];
|
||||
break;
|
||||
}
|
||||
// Just add another copy of the first device if nothing was available
|
||||
SupportedDevices.Last() = deviceList[deviceList.Num() - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Force CTXPT when Passthough is enabled
|
||||
if (PropertyChangedEvent.Property->GetFName() == GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, bInsightPassthroughEnabled) && bInsightPassthroughEnabled)
|
||||
{
|
||||
SystemSplashBackground = ESystemSplashBackgroundType::Contextual;
|
||||
UpdateSinglePropertyInConfigFile(GetClass()->FindPropertyByName(GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, SystemSplashBackground)), GetDefaultConfigFilename());
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // WITH_EDITOR
|
||||
|
||||
void UOculusXRHMDRuntimeSettings::PostInitProperties()
|
||||
{
|
||||
Super::PostInitProperties();
|
||||
RenameProperties();
|
||||
MigratePixelDensityRange();
|
||||
|
||||
const TCHAR* OculusSettings = TEXT("/Script/OculusXRHMD.OculusXRHMDRuntimeSettings");
|
||||
if (!FModuleManager::Get().IsModuleLoaded("OpenXRHMD"))
|
||||
{
|
||||
XrApi = EOculusXRXrApi::OVRPluginOpenXR;
|
||||
UpdateSinglePropertyInConfigFile(GetClass()->FindPropertyByName(GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, XrApi)), GetDefaultConfigFilename());
|
||||
}
|
||||
|
||||
// Force CTXPT for MR apps
|
||||
if (bInsightPassthroughEnabled && SystemSplashBackground != ESystemSplashBackgroundType::Contextual)
|
||||
{
|
||||
SystemSplashBackground = ESystemSplashBackgroundType::Contextual;
|
||||
UpdateSinglePropertyInConfigFile(GetClass()->FindPropertyByName(GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, SystemSplashBackground)), GetDefaultConfigFilename());
|
||||
}
|
||||
|
||||
UpdateSinglePropertyInConfigFile(GetClass()->FindPropertyByName(GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, SBCPath)), GetDefaultConfigFilename());
|
||||
}
|
||||
|
||||
void UOculusXRHMDRuntimeSettings::LoadFromIni()
|
||||
{
|
||||
const TCHAR* OculusSettings = TEXT("Oculus.Settings");
|
||||
bool v;
|
||||
float f;
|
||||
|
||||
if (GConfig->GetFloat(OculusSettings, TEXT("PixelDensityMax"), f, GEngineIni))
|
||||
{
|
||||
UE_LOG(LogTemp, Error, TEXT("DONOT manually add setting to Oculus.Settings. PixelDensityMax is ignored."));
|
||||
PixelDensityMax = 0.f;
|
||||
}
|
||||
if (GConfig->GetFloat(OculusSettings, TEXT("PixelDensityMin"), f, GEngineIni))
|
||||
{
|
||||
UE_LOG(LogTemp, Error, TEXT("DONOT manually add setting to Oculus.Settings. PixelDensityMin is ignored."));
|
||||
PixelDensityMin = 0.f;
|
||||
}
|
||||
if (GConfig->GetBool(OculusSettings, TEXT("bHQDistortion"), v, GEngineIni))
|
||||
{
|
||||
bHQDistortion = v;
|
||||
}
|
||||
if (GConfig->GetBool(OculusSettings, TEXT("bCompositeDepth"), v, GEngineIni))
|
||||
{
|
||||
bCompositesDepth = v;
|
||||
}
|
||||
}
|
||||
|
||||
/** This essentially acts like redirects for plugin settings saved in the engine config.
|
||||
Anything added here should check for the current setting in the config so that if the dev changes the setting manually, we don't overwrite it with the old setting.
|
||||
Note: Do not use UpdateSinglePropertyInConfigFile() here, since that uses a temp config to save the single property,
|
||||
it'll get overwritten when GConfig->RemoveKey() marks the main config as dirty and it gets saved again **/
|
||||
void UOculusXRHMDRuntimeSettings::RenameProperties()
|
||||
{
|
||||
const TCHAR* OculusSettings = TEXT("/Script/OculusXRHMD.OculusXRHMDRuntimeSettings");
|
||||
bool v = false;
|
||||
FString str;
|
||||
|
||||
// FFRLevel was renamed to FoveatedRenderingLevel
|
||||
if (!GConfig->GetString(OculusSettings, GET_MEMBER_NAME_STRING_CHECKED(UOculusXRHMDRuntimeSettings, FoveatedRenderingLevel), str, GetDefaultConfigFilename()) && GConfig->GetString(OculusSettings, TEXT("FFRLevel"), str, GetDefaultConfigFilename()))
|
||||
{
|
||||
if (str.Equals(TEXT("FFR_Off")))
|
||||
{
|
||||
FoveatedRenderingLevel = EOculusXRFoveatedRenderingLevel::Off;
|
||||
}
|
||||
else if (str.Equals(TEXT("FFR_Low")))
|
||||
{
|
||||
FoveatedRenderingLevel = EOculusXRFoveatedRenderingLevel::Low;
|
||||
}
|
||||
else if (str.Equals(TEXT("FFR_Medium")))
|
||||
{
|
||||
FoveatedRenderingLevel = EOculusXRFoveatedRenderingLevel::Medium;
|
||||
}
|
||||
else if (str.Equals(TEXT("FFR_High")))
|
||||
{
|
||||
FoveatedRenderingLevel = EOculusXRFoveatedRenderingLevel::High;
|
||||
}
|
||||
else if (str.Equals(TEXT("FFR_HighTop")))
|
||||
{
|
||||
FoveatedRenderingLevel = EOculusXRFoveatedRenderingLevel::HighTop;
|
||||
}
|
||||
// Use GetNameStringByValue() here because GetValueAsString() includes the type name as well
|
||||
GConfig->SetString(OculusSettings, GET_MEMBER_NAME_STRING_CHECKED(UOculusXRHMDRuntimeSettings, FoveatedRenderingLevel), *StaticEnum<EOculusXRFoveatedRenderingLevel>()->GetNameStringByValue((int64)FoveatedRenderingLevel), GetDefaultConfigFilename());
|
||||
GConfig->RemoveKey(OculusSettings, TEXT("FFRLevel"), GetDefaultConfigFilename());
|
||||
}
|
||||
|
||||
// FFRDynamic was renamed to bDynamicFoveatedRendering
|
||||
if (!GConfig->GetString(OculusSettings, GET_MEMBER_NAME_STRING_CHECKED(UOculusXRHMDRuntimeSettings, bDynamicFoveatedRendering), str, GetDefaultConfigFilename()) && GConfig->GetBool(OculusSettings, TEXT("FFRDynamic"), v, GetDefaultConfigFilename()))
|
||||
{
|
||||
bDynamicFoveatedRendering = v;
|
||||
GConfig->SetBool(OculusSettings, GET_MEMBER_NAME_STRING_CHECKED(UOculusXRHMDRuntimeSettings, bDynamicFoveatedRendering), bDynamicFoveatedRendering, GetDefaultConfigFilename());
|
||||
GConfig->RemoveKey(OculusSettings, TEXT("FFRDynamic"), GetDefaultConfigFilename());
|
||||
}
|
||||
|
||||
const FString Quest = TEXT("Quest");
|
||||
|
||||
#ifndef WITH_OCULUS_BRANCH
|
||||
const TCHAR* AndroidSettings = TEXT("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings");
|
||||
TArray<FString> PackageList;
|
||||
const TCHAR* PackageForMobileKey = TEXT("+PackageForOculusMobile");
|
||||
if (GConfig->GetArray(AndroidSettings, PackageForMobileKey, PackageList, GetDefaultConfigFilename()))
|
||||
{
|
||||
const FString Quest2 = TEXT("Quest2");
|
||||
if (PackageList.Contains(Quest))
|
||||
{
|
||||
PackageList.Remove(Quest);
|
||||
if (!PackageList.Contains(Quest2))
|
||||
{
|
||||
PackageList.Add(Quest2);
|
||||
}
|
||||
GConfig->SetArray(AndroidSettings, PackageForMobileKey, PackageList, GetDefaultConfigFilename());
|
||||
}
|
||||
}
|
||||
#endif // WITH_OCULUS_BRANCH
|
||||
|
||||
TArray<FString> DeviceList;
|
||||
const FString SupportedDevicesKey = FString("+").Append(GET_MEMBER_NAME_STRING_CHECKED(UOculusXRHMDRuntimeSettings, SupportedDevices));
|
||||
if (GConfig->GetArray(OculusSettings, *SupportedDevicesKey, DeviceList, GetDefaultConfigFilename()))
|
||||
{
|
||||
const EOculusXRSupportedDevices LastSupportedDevice = EOculusXRSupportedDevices::Quest2;
|
||||
const FString LastSupportedDeviceString = StaticEnum<EOculusXRSupportedDevices>()->GetNameStringByValue((int64)LastSupportedDevice);
|
||||
if (DeviceList.Contains(Quest))
|
||||
{
|
||||
DeviceList.Remove(Quest);
|
||||
if (!DeviceList.Contains(LastSupportedDeviceString))
|
||||
{
|
||||
DeviceList.Add(LastSupportedDeviceString);
|
||||
}
|
||||
GConfig->SetArray(OculusSettings, *SupportedDevicesKey, DeviceList, GetDefaultConfigFilename());
|
||||
|
||||
// Reflect the config changes in the Project Settings UI
|
||||
SupportedDevices.Remove((EOculusXRSupportedDevices)0); // Enums that don't exist just have a value of 0
|
||||
if (!SupportedDevices.Contains(LastSupportedDevice))
|
||||
{
|
||||
SupportedDevices.Add(LastSupportedDevice);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UOculusXRHMDRuntimeSettings::MigratePixelDensityRange()
|
||||
{
|
||||
#if WITH_EDITOR
|
||||
if (!FMath::IsNearlyZero(PixelDensityMin))
|
||||
{
|
||||
Algo::ForEach(UDeviceProfileManager::Get().Profiles, [&](UDeviceProfile* Profile) {
|
||||
float ProfilePixelDensityMin = 0.f;
|
||||
if (Profile->GetConsolidatedCVarValue(VAR_PixelDensityMin, ProfilePixelDensityMin))
|
||||
{
|
||||
Profile->ModifyCVarValue(VAR_PixelDensityMin, FString::SanitizeFloat(PixelDensityMin), true);
|
||||
UDeviceProfileManager::Get().SaveProfiles(true);
|
||||
}
|
||||
});
|
||||
|
||||
PixelDensityMin = 0.f;
|
||||
TryUpdateDefaultConfigFile();
|
||||
UE_LOG(LogTemp, Log, TEXT("PixelDensityMin %f is migrated to per device range."), PixelDensityMin);
|
||||
}
|
||||
if (!FMath::IsNearlyZero(PixelDensityMax))
|
||||
{
|
||||
Algo::ForEach(UDeviceProfileManager::Get().Profiles, [&](UDeviceProfile* Profile) {
|
||||
float ProfilePixelDensityMax = 0.f;
|
||||
if (Profile->GetConsolidatedCVarValue(VAR_PixelDensityMax, ProfilePixelDensityMax))
|
||||
{
|
||||
Profile->ModifyCVarValue(VAR_PixelDensityMax, FString::SanitizeFloat(PixelDensityMax), true);
|
||||
UDeviceProfileManager::Get().SaveProfiles(true);
|
||||
}
|
||||
});
|
||||
|
||||
PixelDensityMax = 0.f;
|
||||
TryUpdateDefaultConfigFile();
|
||||
UE_LOG(LogTemp, Log, TEXT("PixelDensityMax %f is migrated to per device range."), PixelDensityMax);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
#include "OculusXRHMD_ConsoleCommands.h"
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
#include "OculusXRHMD.h"
|
||||
#include "OculusXRSceneCaptureCubemap.h"
|
||||
|
||||
namespace OculusXRHMD
|
||||
{
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// FConsoleCommands
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
/// @cond DOXYGEN_WARNINGS
|
||||
|
||||
FConsoleCommands::FConsoleCommands(class FOculusXRHMD* InHMDPtr)
|
||||
: UpdateOnRenderThreadCommand(TEXT("vr.oculus.bUpdateOnRenderThread"),
|
||||
*NSLOCTEXT("OculusRift", "CCommandText_UpdateRT", "Oculus Rift specific extension.\nEnables or disables updating on the render thread.").ToString(),
|
||||
FConsoleCommandWithWorldArgsAndOutputDeviceDelegate::CreateRaw(InHMDPtr, &FOculusXRHMD::UpdateOnRenderThreadCommandHandler))
|
||||
, HQBufferCommand(TEXT("vr.oculus.bHQBuffer"),
|
||||
*NSLOCTEXT("OculusRift", "CCommandText_HQBuffer", "Oculus Rift specific extension.\nEnable or disable using floating point texture format for the eye layer.").ToString(),
|
||||
FConsoleCommandWithWorldArgsAndOutputDeviceDelegate::CreateRaw(InHMDPtr, &FOculusXRHMD::HQBufferCommandHandler))
|
||||
, HQDistortionCommand(TEXT("vr.oculus.bHQDistortion"),
|
||||
*NSLOCTEXT("OculusRift", "CCommandText_HQDistortion", "Oculus Rift specific extension.\nEnable or disable using multiple mipmap levels for the eye layer.").ToString(),
|
||||
FConsoleCommandWithWorldArgsAndOutputDeviceDelegate::CreateRaw(InHMDPtr, &FOculusXRHMD::HQDistortionCommandHandler))
|
||||
, ShowGlobalMenuCommand(TEXT("vr.oculus.ShowGlobalMenu"),
|
||||
*NSLOCTEXT("OculusRift", "CCommandText_GlobalMenu", "Oculus Rift specific extension.\nOpens the global menu.").ToString(),
|
||||
FConsoleCommandWithWorldArgsAndOutputDeviceDelegate::CreateRaw(InHMDPtr, &FOculusXRHMD::ShowGlobalMenuCommandHandler))
|
||||
, ShowQuitMenuCommand(TEXT("vr.oculus.ShowQuitMenu"),
|
||||
*NSLOCTEXT("OculusRift", "CCommandText_QuitMenu", "Oculus Rift specific extension.\nOpens the quit menu.").ToString(),
|
||||
FConsoleCommandWithWorldArgsAndOutputDeviceDelegate::CreateRaw(InHMDPtr, &FOculusXRHMD::ShowQuitMenuCommandHandler))
|
||||
|
||||
#if !UE_BUILD_SHIPPING
|
||||
, StatsCommand(TEXT("vr.oculus.Debug.bShowStats"),
|
||||
*NSLOCTEXT("OculusRift", "CCommandText_Stats", "Oculus Rift specific extension.\nEnable or disable rendering of stats.").ToString(),
|
||||
FConsoleCommandWithWorldArgsAndOutputDeviceDelegate::CreateRaw(InHMDPtr, &FOculusXRHMD::StatsCommandHandler))
|
||||
, CubemapCommand(TEXT("vr.oculus.Debug.CaptureCubemap"),
|
||||
*NSLOCTEXT("OculusRift", "CCommandText_Cubemap", "Oculus Rift specific extension.\nCaptures a cubemap for Oculus Home.\nOptional arguments (default is zero for all numeric arguments):\n xoff=<float> -- X axis offset from the origin\n yoff=<float> -- Y axis offset\n zoff=<float> -- Z axis offset\n yaw=<float> -- the direction to look into (roll and pitch is fixed to zero)\n mobile -- Generate a Mobile format cubemap\n (height of the captured cubemap will be 1024 instead of 2048 pixels)\n").ToString(),
|
||||
FConsoleCommandWithWorldArgsAndOutputDeviceDelegate::CreateStatic(&UOculusXRSceneCaptureCubemap::CaptureCubemapCommandHandler))
|
||||
, ShowSettingsCommand(TEXT("vr.oculus.Debug.Show"),
|
||||
*NSLOCTEXT("OculusRift", "CCommandText_Show", "Oculus Rift specific extension.\nShows the current value of various stereo rendering params.").ToString(),
|
||||
FConsoleCommandWithWorldArgsAndOutputDeviceDelegate::CreateRaw(InHMDPtr, &FOculusXRHMD::ShowSettingsCommandHandler))
|
||||
, IPDCommand(TEXT("vr.oculus.Debug.IPD"),
|
||||
*NSLOCTEXT("OculusRift", "CCommandText_IPD", "Oculus Rift specific extension.\nShows or changes the current interpupillary distance in meters.").ToString(),
|
||||
FConsoleCommandWithWorldArgsAndOutputDeviceDelegate::CreateRaw(InHMDPtr, &FOculusXRHMD::IPDCommandHandler))
|
||||
#endif // !UE_BUILD_SHIPPING
|
||||
{
|
||||
}
|
||||
|
||||
bool FConsoleCommands::Exec(UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar)
|
||||
{
|
||||
const TCHAR* OrigCmd = Cmd;
|
||||
FString AliasedCommand;
|
||||
|
||||
if (FParse::Command(&Cmd, TEXT("OVRGLOBALMENU")))
|
||||
{
|
||||
AliasedCommand = TEXT("vr.oculus.ShowGlobalMenu");
|
||||
}
|
||||
else if (FParse::Command(&Cmd, TEXT("OVRQUITMENU")))
|
||||
{
|
||||
AliasedCommand = TEXT("vr.oculus.ShowQuitMenu");
|
||||
}
|
||||
#if !UE_BUILD_SHIPPING
|
||||
else if (FParse::Command(&Cmd, TEXT("vr.oculus.Debug.EnforceHeadTracking")))
|
||||
{
|
||||
AliasedCommand = TEXT("vr.HeadTracking.bEnforced");
|
||||
}
|
||||
#endif // !UE_BUILD_SHIPPING
|
||||
|
||||
if (!AliasedCommand.IsEmpty())
|
||||
{
|
||||
Ar.Logf(ELogVerbosity::Warning, TEXT("%s is deprecated. Use %s instead"), OrigCmd, *AliasedCommand);
|
||||
return IConsoleManager::Get().ProcessUserConsoleInput(*AliasedCommand, Ar, InWorld);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// @endcond
|
||||
|
||||
} // namespace OculusXRHMD
|
||||
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
@@ -0,0 +1,43 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
#include "OculusXRHMDPrivate.h"
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
#include "HAL/IConsoleManager.h"
|
||||
|
||||
namespace OculusXRHMD
|
||||
{
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// FConsoleCommands
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
class FConsoleCommands : private FSelfRegisteringExec
|
||||
{
|
||||
public:
|
||||
FConsoleCommands(class FOculusXRHMD* InHMDPtr);
|
||||
|
||||
// FSelfRegisteringExec interface
|
||||
virtual bool Exec(UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar) override;
|
||||
|
||||
private:
|
||||
FAutoConsoleCommand UpdateOnRenderThreadCommand;
|
||||
FAutoConsoleCommand HQBufferCommand;
|
||||
FAutoConsoleCommand HQDistortionCommand;
|
||||
FAutoConsoleCommand ShowGlobalMenuCommand;
|
||||
FAutoConsoleCommand ShowQuitMenuCommand;
|
||||
|
||||
#if !UE_BUILD_SHIPPING
|
||||
// Debug console commands
|
||||
FAutoConsoleCommand StatsCommand;
|
||||
FAutoConsoleCommand CubemapCommand;
|
||||
FAutoConsoleCommand ShowSettingsCommand;
|
||||
FAutoConsoleCommand IPDCommand;
|
||||
#endif // !UE_BUILD_SHIPPING
|
||||
};
|
||||
|
||||
} // namespace OculusXRHMD
|
||||
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
@@ -0,0 +1,707 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "OculusXRHMD_CustomPresent.h"
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
#include "OculusXRHMD.h"
|
||||
#include "ScreenRendering.h"
|
||||
#include "PipelineStateCache.h"
|
||||
#include "ClearQuad.h"
|
||||
#include "OculusShaders.h"
|
||||
#include "CommonRenderResources.h"
|
||||
#include "RHIStaticStates.h"
|
||||
|
||||
#if PLATFORM_ANDROID
|
||||
#include "Android/AndroidJNI.h"
|
||||
#include "Android/AndroidApplication.h"
|
||||
#include "Android/AndroidPlatformMisc.h"
|
||||
#endif
|
||||
|
||||
#define VULKAN_CUBEMAP_POSITIVE_Y 2
|
||||
#define VULKAN_CUBEMAP_NEGATIVE_Y 3
|
||||
|
||||
namespace OculusXRHMD
|
||||
{
|
||||
/**
|
||||
* A pixel shader for rendering a textured screen element with mip maps and array slice.
|
||||
*/
|
||||
class FScreenPSMipLevelArray : public FGlobalShader
|
||||
{
|
||||
DECLARE_SHADER_TYPE(FScreenPSMipLevelArray, Global);
|
||||
|
||||
public:
|
||||
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters) { return true; }
|
||||
|
||||
FScreenPSMipLevelArray(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
|
||||
: FGlobalShader(Initializer)
|
||||
{
|
||||
InTexture.Bind(Initializer.ParameterMap, TEXT("InTexture"), SPF_Mandatory);
|
||||
InTextureSampler.Bind(Initializer.ParameterMap, TEXT("InTextureSampler"));
|
||||
InMipLevelParameter.Bind(Initializer.ParameterMap, TEXT("MipLevel"));
|
||||
InArraySliceParameter.Bind(Initializer.ParameterMap, TEXT("ArraySlice"));
|
||||
}
|
||||
FScreenPSMipLevelArray() {}
|
||||
|
||||
void SetParameters(FRHIBatchedShaderParameters& BatchedParameters, const FTexture* Texture, int ArraySlice, int MipLevel)
|
||||
{
|
||||
SetTextureParameter(BatchedParameters, InTexture, InTextureSampler, Texture);
|
||||
SetShaderValue(BatchedParameters, InMipLevelParameter, MipLevel);
|
||||
SetShaderValue(BatchedParameters, InArraySliceParameter, ArraySlice);
|
||||
}
|
||||
|
||||
void SetParameters(FRHIBatchedShaderParameters& BatchedParameters, FRHISamplerState* SamplerStateRHI, FRHITexture* TextureRHI, int ArraySlice, int MipLevel)
|
||||
{
|
||||
SetTextureParameter(BatchedParameters, InTexture, InTextureSampler, SamplerStateRHI, TextureRHI);
|
||||
SetShaderValue(BatchedParameters, InMipLevelParameter, MipLevel);
|
||||
SetShaderValue(BatchedParameters, InArraySliceParameter, ArraySlice);
|
||||
}
|
||||
|
||||
private:
|
||||
LAYOUT_FIELD(FShaderResourceParameter, InTexture);
|
||||
LAYOUT_FIELD(FShaderResourceParameter, InTextureSampler);
|
||||
LAYOUT_FIELD(FShaderParameter, InMipLevelParameter);
|
||||
LAYOUT_FIELD(FShaderParameter, InArraySliceParameter);
|
||||
};
|
||||
IMPLEMENT_SHADER_TYPE(, FScreenPSMipLevelArray, TEXT("/Plugin/OculusXR/Private/ScreenPixelShaderArraySlice.usf"), TEXT("MainMipLevel"), SF_Pixel);
|
||||
|
||||
/**
|
||||
* A pixel shader for rendering a textured screen element with mip maps and array slice.
|
||||
*/
|
||||
class FScreenPSsRGBSourceMipLevelArray : public FGlobalShader
|
||||
{
|
||||
DECLARE_SHADER_TYPE(FScreenPSsRGBSourceMipLevelArray, Global);
|
||||
|
||||
public:
|
||||
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters) { return true; }
|
||||
|
||||
FScreenPSsRGBSourceMipLevelArray(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
|
||||
: FGlobalShader(Initializer)
|
||||
{
|
||||
InTexture.Bind(Initializer.ParameterMap, TEXT("InTexture"), SPF_Mandatory);
|
||||
InTextureSampler.Bind(Initializer.ParameterMap, TEXT("InTextureSampler"));
|
||||
InMipLevelParameter.Bind(Initializer.ParameterMap, TEXT("MipLevel"));
|
||||
InArraySliceParameter.Bind(Initializer.ParameterMap, TEXT("ArraySlice"));
|
||||
}
|
||||
FScreenPSsRGBSourceMipLevelArray() {}
|
||||
|
||||
void SetParameters(FRHIBatchedShaderParameters& BatchedParameters, const FTexture* Texture, int ArraySlice, int MipLevel)
|
||||
{
|
||||
SetTextureParameter(BatchedParameters, InTexture, InTextureSampler, Texture);
|
||||
SetShaderValue(BatchedParameters, InMipLevelParameter, MipLevel);
|
||||
SetShaderValue(BatchedParameters, InArraySliceParameter, ArraySlice);
|
||||
}
|
||||
|
||||
void SetParameters(FRHIBatchedShaderParameters& BatchedParameters, FRHISamplerState* SamplerStateRHI, FRHITexture* TextureRHI, int ArraySlice, int MipLevel)
|
||||
{
|
||||
SetTextureParameter(BatchedParameters, InTexture, InTextureSampler, SamplerStateRHI, TextureRHI);
|
||||
SetShaderValue(BatchedParameters, InMipLevelParameter, MipLevel);
|
||||
SetShaderValue(BatchedParameters, InArraySliceParameter, ArraySlice);
|
||||
}
|
||||
|
||||
private:
|
||||
LAYOUT_FIELD(FShaderResourceParameter, InTexture);
|
||||
LAYOUT_FIELD(FShaderResourceParameter, InTextureSampler);
|
||||
LAYOUT_FIELD(FShaderParameter, InMipLevelParameter);
|
||||
LAYOUT_FIELD(FShaderParameter, InArraySliceParameter);
|
||||
};
|
||||
IMPLEMENT_SHADER_TYPE(, FScreenPSsRGBSourceMipLevelArray, TEXT("/Plugin/OculusXR/Private/ScreenPixelShaderArraySlice.usf"), TEXT("MainsRGBSourceMipLevel"), SF_Pixel);
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// FCustomPresent
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
FCustomPresent::FCustomPresent(class FOculusXRHMD* InOculusXRHMD, ovrpRenderAPIType InRenderAPI, EPixelFormat InDefaultPixelFormat, bool bInSupportsSRGB)
|
||||
: OculusXRHMD(InOculusXRHMD)
|
||||
, RenderAPI(InRenderAPI)
|
||||
, DefaultPixelFormat(InDefaultPixelFormat)
|
||||
, bSupportsSRGB(bInSupportsSRGB)
|
||||
, bSupportsSubsampled(false)
|
||||
, bIsStandaloneStereoDevice(false)
|
||||
{
|
||||
CheckInGameThread();
|
||||
|
||||
DefaultOvrpTextureFormat = GetOvrpTextureFormat(GetDefaultPixelFormat());
|
||||
DefaultDepthOvrpTextureFormat = ovrpTextureFormat_None;
|
||||
|
||||
#if PLATFORM_ANDROID
|
||||
bIsStandaloneStereoDevice = FAndroidMisc::GetDeviceMake() == FString("Oculus");
|
||||
#endif
|
||||
|
||||
// grab a pointer to the renderer module for displaying our mirror window
|
||||
static const FName RendererModuleName("Renderer");
|
||||
RendererModule = FModuleManager::GetModulePtr<IRendererModule>(RendererModuleName);
|
||||
}
|
||||
|
||||
void FCustomPresent::ReleaseResources_RHIThread()
|
||||
{
|
||||
CheckInRHIThread();
|
||||
|
||||
if (MirrorTextureRHI.IsValid())
|
||||
{
|
||||
FOculusXRHMDModule::GetPluginWrapper().DestroyMirrorTexture2();
|
||||
MirrorTextureRHI = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void FCustomPresent::Shutdown()
|
||||
{
|
||||
CheckInGameThread();
|
||||
|
||||
// OculusXRHMD is going away, but this object can live on until viewport is destroyed
|
||||
ExecuteOnRenderThread([this]() {
|
||||
ExecuteOnRHIThread([this]() {
|
||||
OculusXRHMD = nullptr;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
bool FCustomPresent::NeedsNativePresent()
|
||||
{
|
||||
return !bIsStandaloneStereoDevice;
|
||||
}
|
||||
|
||||
bool FCustomPresent::Present(int32& SyncInterval)
|
||||
{
|
||||
CheckInRHIThread();
|
||||
|
||||
if (OculusXRHMD)
|
||||
{
|
||||
FGameFrame* Frame_RHIThread = OculusXRHMD->GetFrame_RHIThread();
|
||||
if (Frame_RHIThread)
|
||||
{
|
||||
FinishRendering_RHIThread();
|
||||
}
|
||||
}
|
||||
|
||||
SyncInterval = 0; // VSync off
|
||||
|
||||
return NeedsNativePresent();
|
||||
}
|
||||
|
||||
void FCustomPresent::UpdateMirrorTexture_RenderThread()
|
||||
{
|
||||
SCOPE_CYCLE_COUNTER(STAT_BeginRendering);
|
||||
|
||||
CheckInRenderThread();
|
||||
|
||||
const ESpectatorScreenMode MirrorWindowMode = OculusXRHMD->GetSpectatorScreenMode_RenderThread();
|
||||
const FIntPoint MirrorWindowSize = OculusXRHMD->GetFrame_RenderThread()->WindowSize;
|
||||
|
||||
if (FOculusXRHMDModule::GetPluginWrapper().GetInitialized())
|
||||
{
|
||||
// Need to destroy mirror texture?
|
||||
if (MirrorTextureRHI.IsValid())
|
||||
{
|
||||
const auto MirrorTextureSize = FIntPoint(MirrorTextureRHI->GetDesc().Extent.X, MirrorTextureRHI->GetDesc().Extent.Y);
|
||||
if (MirrorWindowMode != ESpectatorScreenMode::Distorted || MirrorWindowSize != MirrorTextureSize)
|
||||
{
|
||||
ExecuteOnRHIThread([]() {
|
||||
FOculusXRHMDModule::GetPluginWrapper().DestroyMirrorTexture2();
|
||||
});
|
||||
|
||||
MirrorTextureRHI = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Need to create mirror texture?
|
||||
if (!MirrorTextureRHI.IsValid() && MirrorWindowMode == ESpectatorScreenMode::Distorted && MirrorWindowSize.X != 0 && MirrorWindowSize.Y != 0)
|
||||
{
|
||||
const int Width = MirrorWindowSize.X;
|
||||
const int Height = MirrorWindowSize.Y;
|
||||
ovrpTextureHandle TextureHandle;
|
||||
|
||||
ExecuteOnRHIThread([&]() {
|
||||
FOculusXRHMDModule::GetPluginWrapper().SetupMirrorTexture2(GetOvrpDevice(), Height, Width, GetDefaultOvrpTextureFormat(), &TextureHandle);
|
||||
});
|
||||
|
||||
UE_LOG(LogHMD, Log, TEXT("Allocated a new mirror texture (size %d x %d)"), Width, Height);
|
||||
|
||||
ETextureCreateFlags TexCreateFlags = TexCreate_ShaderResource | TexCreate_RenderTargetable;
|
||||
|
||||
MirrorTextureRHI = CreateTexture_RenderThread(Width, Height, GetDefaultPixelFormat(), FClearValueBinding::None, 1, 1, 1, RRT_Texture2D, TextureHandle, TexCreateFlags)->GetTexture2D();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FCustomPresent::FinishRendering_RHIThread()
|
||||
{
|
||||
SCOPE_CYCLE_COUNTER(STAT_FinishRendering);
|
||||
CheckInRHIThread();
|
||||
|
||||
#if STATS
|
||||
if (OculusXRHMD->GetFrame_RHIThread()->ShowFlags.Rendering)
|
||||
{
|
||||
ovrpAppLatencyTimings AppLatencyTimings;
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetAppLatencyTimings2(&AppLatencyTimings)))
|
||||
{
|
||||
SET_FLOAT_STAT(STAT_LatencyRender, AppLatencyTimings.LatencyRender * 1000.0f);
|
||||
SET_FLOAT_STAT(STAT_LatencyTimewarp, AppLatencyTimings.LatencyTimewarp * 1000.0f);
|
||||
SET_FLOAT_STAT(STAT_LatencyPostPresent, AppLatencyTimings.LatencyPostPresent * 1000.0f);
|
||||
SET_FLOAT_STAT(STAT_ErrorRender, AppLatencyTimings.ErrorRender * 1000.0f);
|
||||
SET_FLOAT_STAT(STAT_ErrorTimewarp, AppLatencyTimings.ErrorTimewarp * 1000.0f);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
OculusXRHMD->FinishRHIFrame_RHIThread();
|
||||
|
||||
#if PLATFORM_ANDROID
|
||||
float GPUFrameTime = 0.0f;
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetGPUFrameTime(&GPUFrameTime)))
|
||||
{
|
||||
SubmitGPUFrameTime(GPUFrameTime);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
EPixelFormat FCustomPresent::GetPixelFormat(EPixelFormat Format) const
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
// case PF_B8G8R8A8:
|
||||
case PF_FloatRGBA:
|
||||
case PF_FloatR11G11B10:
|
||||
// case PF_R8G8B8A8:
|
||||
case PF_G16:
|
||||
case PF_R16F:
|
||||
case PF_R32_FLOAT:
|
||||
case PF_ShadowDepth:
|
||||
case PF_D24:
|
||||
return Format;
|
||||
}
|
||||
|
||||
return GetDefaultPixelFormat();
|
||||
}
|
||||
|
||||
EPixelFormat FCustomPresent::GetPixelFormat(ovrpTextureFormat Format) const
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
// case ovrpTextureFormat_R8G8B8A8_sRGB:
|
||||
// case ovrpTextureFormat_R8G8B8A8:
|
||||
// return PF_R8G8B8A8;
|
||||
case ovrpTextureFormat_R16G16B16A16_FP:
|
||||
return PF_FloatRGBA;
|
||||
case ovrpTextureFormat_R11G11B10_FP:
|
||||
return PF_FloatR11G11B10;
|
||||
// case ovrpTextureFormat_B8G8R8A8_sRGB:
|
||||
// case ovrpTextureFormat_B8G8R8A8:
|
||||
// return PF_B8G8R8A8;
|
||||
case ovrpTextureFormat_R16:
|
||||
return PF_G16; // G stands for grey here, not green, and is actually R16 in RHI
|
||||
case ovrpTextureFormat_R16_FP:
|
||||
return PF_R16F;
|
||||
case ovrpTextureFormat_R32_FP:
|
||||
return PF_R32_FLOAT;
|
||||
case ovrpTextureFormat_D16:
|
||||
return PF_ShadowDepth; // ShadowDepth maps to D16 in Vulkan
|
||||
case ovrpTextureFormat_D24_S8:
|
||||
return PF_D24;
|
||||
}
|
||||
|
||||
return GetDefaultPixelFormat();
|
||||
}
|
||||
|
||||
ovrpTextureFormat FCustomPresent::GetOvrpTextureFormat(EPixelFormat Format, bool usesRGB) const
|
||||
{
|
||||
switch (GetPixelFormat(Format))
|
||||
{
|
||||
case PF_B8G8R8A8:
|
||||
return bSupportsSRGB && usesRGB ? ovrpTextureFormat_B8G8R8A8_sRGB : ovrpTextureFormat_B8G8R8A8;
|
||||
case PF_FloatRGBA:
|
||||
return ovrpTextureFormat_R16G16B16A16_FP;
|
||||
case PF_FloatR11G11B10:
|
||||
return ovrpTextureFormat_R11G11B10_FP;
|
||||
case PF_R8G8B8A8:
|
||||
return bSupportsSRGB && usesRGB ? ovrpTextureFormat_R8G8B8A8_sRGB : ovrpTextureFormat_R8G8B8A8;
|
||||
case PF_G16:
|
||||
return ovrpTextureFormat_R16;
|
||||
case PF_R16F:
|
||||
return ovrpTextureFormat_R16_FP;
|
||||
case PF_R32_FLOAT:
|
||||
return ovrpTextureFormat_R32_FP;
|
||||
case PF_ShadowDepth:
|
||||
return ovrpTextureFormat_D16;
|
||||
case PF_D24:
|
||||
return ovrpTextureFormat_D24_S8;
|
||||
}
|
||||
|
||||
return ovrpTextureFormat_None;
|
||||
}
|
||||
|
||||
bool FCustomPresent::IsSRGB(ovrpTextureFormat InFormat)
|
||||
{
|
||||
switch (InFormat)
|
||||
{
|
||||
case ovrpTextureFormat_B8G8R8A8_sRGB:
|
||||
case ovrpTextureFormat_R8G8B8A8_sRGB:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int FCustomPresent::GetSystemRecommendedMSAALevel() const
|
||||
{
|
||||
int SystemRecommendedMSAALevel = 1;
|
||||
FOculusXRHMDModule::GetPluginWrapper().GetSystemRecommendedMSAALevel2(&SystemRecommendedMSAALevel);
|
||||
return SystemRecommendedMSAALevel;
|
||||
}
|
||||
|
||||
FXRSwapChainPtr FCustomPresent::CreateSwapChain_RenderThread(uint32 InSizeX, uint32 InSizeY, EPixelFormat InFormat, FClearValueBinding InBinding, uint32 InNumMips, uint32 InNumSamples, uint32 InNumSamplesTileMem, ERHIResourceType InResourceType, const TArray<ovrpTextureHandle>& InTextures, ETextureCreateFlags InTexCreateFlags, const TCHAR* DebugName)
|
||||
{
|
||||
TArray<FTextureRHIRef> RHITextureSwapChain = CreateSwapChainTextures_RenderThread(InSizeX, InSizeY, InFormat, InBinding, InNumMips, InNumSamples, InNumSamplesTileMem, InResourceType, InTextures, InTexCreateFlags, DebugName);
|
||||
|
||||
FTextureRHIRef RHITexture = GDynamicRHI->RHICreateAliasedTexture(RHITextureSwapChain[0]);
|
||||
|
||||
return CreateXRSwapChain(MoveTemp(RHITextureSwapChain), RHITexture);
|
||||
}
|
||||
|
||||
TArray<FTextureRHIRef> FCustomPresent::CreateSwapChainTextures_RenderThread(uint32 InSizeX, uint32 InSizeY, EPixelFormat InFormat, FClearValueBinding InBinding, uint32 InNumMips, uint32 InNumSamples, uint32 InNumSamplesTileMem, ERHIResourceType InResourceType, const TArray<ovrpTextureHandle>& InTextures, ETextureCreateFlags InTexCreateFlags, const TCHAR* DebugName)
|
||||
{
|
||||
CheckInRenderThread();
|
||||
|
||||
TArray<FTextureRHIRef> RHITextureSwapChain;
|
||||
{
|
||||
for (int32 TextureIndex = 0; TextureIndex < InTextures.Num(); ++TextureIndex)
|
||||
{
|
||||
FTextureRHIRef TexRef = CreateTexture_RenderThread(InSizeX, InSizeY, InFormat, InBinding, InNumMips, InNumSamples, InNumSamplesTileMem, InResourceType, InTextures[TextureIndex], InTexCreateFlags);
|
||||
|
||||
FString TexName = FString::Printf(TEXT("%s (%d/%d)"), DebugName, TextureIndex, InTextures.Num());
|
||||
TexRef->SetName(*TexName);
|
||||
RHIBindDebugLabelName(TexRef, *TexName);
|
||||
|
||||
RHITextureSwapChain.Add(TexRef);
|
||||
}
|
||||
}
|
||||
|
||||
return RHITextureSwapChain;
|
||||
}
|
||||
|
||||
void FCustomPresent::CopyTexture_RenderThread(FRHICommandListImmediate& RHICmdList, FRHITexture* DstTexture, FRHITexture* SrcTexture, FIntRect DstRect, FIntRect SrcRect, bool bAlphaPremultiply, bool bNoAlphaWrite, bool bInvertY, bool sRGBSource, bool bInvertAlpha)
|
||||
{
|
||||
FCustomPresent::CopyTexture_RenderThread(RHICmdList, RendererModule, DstTexture, SrcTexture, OculusXRHMD->GetSettings_RenderThread()->CurrentFeatureLevel, RenderAPI == ovrpRenderAPI_Vulkan,
|
||||
DstRect, SrcRect, bAlphaPremultiply, bNoAlphaWrite, bInvertY, sRGBSource, bInvertAlpha);
|
||||
}
|
||||
|
||||
void FCustomPresent::CopyTexture_RenderThread(FRHICommandListImmediate& RHICmdList, IRendererModule* RendererModule, FRHITexture* DstTexture, FRHITexture* SrcTexture, FStaticFeatureLevel FeatureLevel, bool bUsingVulkan,
|
||||
FIntRect DstRect, FIntRect SrcRect, bool bAlphaPremultiply, bool bNoAlphaWrite, bool bInvertY, bool sRGBSource, bool bInvertAlpha)
|
||||
{
|
||||
CheckInRenderThread();
|
||||
|
||||
FIntPoint DstSize;
|
||||
FIntPoint SrcSize;
|
||||
|
||||
if (DstTexture->GetDesc().IsTexture2D() && SrcTexture->GetDesc().IsTexture2D())
|
||||
{
|
||||
DstSize = FIntPoint(DstTexture->GetSizeX(), DstTexture->GetSizeY());
|
||||
SrcSize = FIntPoint(SrcTexture->GetSizeX(), SrcTexture->GetSizeY());
|
||||
}
|
||||
else if (DstTexture->GetDesc().IsTextureCube() && SrcTexture->GetDesc().IsTextureCube())
|
||||
{
|
||||
DstSize = FIntPoint(DstTexture->GetSize(), DstTexture->GetSize());
|
||||
SrcSize = FIntPoint(SrcTexture->GetSize(), SrcTexture->GetSize());
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (DstRect.IsEmpty())
|
||||
{
|
||||
DstRect = FIntRect(FIntPoint::ZeroValue, DstSize);
|
||||
}
|
||||
|
||||
if (SrcRect.IsEmpty())
|
||||
{
|
||||
SrcRect = FIntRect(FIntPoint::ZeroValue, SrcSize);
|
||||
}
|
||||
|
||||
const uint32 ViewportWidth = DstRect.Width();
|
||||
const uint32 ViewportHeight = DstRect.Height();
|
||||
const FIntPoint TargetSize(ViewportWidth, ViewportHeight);
|
||||
float U = SrcRect.Min.X / (float)SrcSize.X;
|
||||
float V = SrcRect.Min.Y / (float)SrcSize.Y;
|
||||
float USize = SrcRect.Width() / (float)SrcSize.X;
|
||||
float VSize = SrcRect.Height() / (float)SrcSize.Y;
|
||||
|
||||
#if PLATFORM_ANDROID // on android, top-left isn't 0/0 but 1/0.
|
||||
if (bInvertY)
|
||||
{
|
||||
V = 1.0f - V;
|
||||
VSize = -VSize;
|
||||
}
|
||||
#endif
|
||||
|
||||
FRHITexture* SrcTextureRHI = SrcTexture;
|
||||
RHICmdList.Transition(FRHITransitionInfo(SrcTextureRHI, ERHIAccess::Unknown, ERHIAccess::SRVGraphics));
|
||||
FGraphicsPipelineStateInitializer GraphicsPSOInit;
|
||||
|
||||
if (bInvertAlpha)
|
||||
{
|
||||
// write RGBA, RGB = src.rgb * 1 + dst.rgb * 0, A = src.a * 0 + dst.a * (1 - src.a)
|
||||
GraphicsPSOInit.BlendState = TStaticBlendState<CW_RGBA, BO_Add, BF_One, BF_Zero, BO_Add, BF_Zero, BF_InverseSourceAlpha>::GetRHI();
|
||||
}
|
||||
else if (bAlphaPremultiply)
|
||||
{
|
||||
if (bNoAlphaWrite)
|
||||
{
|
||||
// for quads, write RGB, RGB = src.rgb * 1 + dst.rgb * 0
|
||||
GraphicsPSOInit.BlendState = TStaticBlendState<CW_RGB, BO_Add, BF_One, BF_Zero, BO_Add, BF_One, BF_Zero>::GetRHI();
|
||||
}
|
||||
else
|
||||
{
|
||||
// for quads, write RGBA, RGB = src.rgb * src.a + dst.rgb * 0, A = src.a + dst.a * 0
|
||||
GraphicsPSOInit.BlendState = TStaticBlendState<CW_RGBA, BO_Add, BF_SourceAlpha, BF_Zero, BO_Add, BF_One, BF_Zero>::GetRHI();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bNoAlphaWrite)
|
||||
{
|
||||
GraphicsPSOInit.BlendState = TStaticBlendState<CW_RGB>::GetRHI();
|
||||
}
|
||||
else
|
||||
{
|
||||
// for mirror window, write RGBA, RGB = src.rgb * src.a + dst.rgb * (1 - src.a), A = src.a * 1 + dst.a * (1 - src a)
|
||||
GraphicsPSOInit.BlendState = TStaticBlendState<CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_One, BF_InverseSourceAlpha>::GetRHI();
|
||||
}
|
||||
}
|
||||
|
||||
GraphicsPSOInit.RasterizerState = TStaticRasterizerState<>::GetRHI();
|
||||
GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
|
||||
GraphicsPSOInit.PrimitiveType = PT_TriangleList;
|
||||
|
||||
auto ShaderMap = GetGlobalShaderMap(FeatureLevel);
|
||||
TShaderMapRef<FScreenVS> VertexShader(ShaderMap);
|
||||
GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
|
||||
GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
|
||||
|
||||
if (DstTexture->GetDesc().IsTexture2D())
|
||||
{
|
||||
sRGBSource &= EnumHasAnyFlags(SrcTexture->GetFlags(), TexCreate_SRGB);
|
||||
|
||||
// Need to copy over mip maps on Android since they are not generated like they are on PC
|
||||
#if PLATFORM_ANDROID
|
||||
uint32 NumMips = SrcTexture->GetNumMips();
|
||||
#else
|
||||
uint32 NumMips = 1;
|
||||
#endif
|
||||
|
||||
const bool bUseTexArrayShader = SrcTexture->GetDesc().IsTextureArray() && DstTexture->GetDesc().IsTextureArray();
|
||||
const int32 SliceCount = bUseTexArrayShader ? FMath::Min(SrcTexture->GetDesc().ArraySize, DstTexture->GetDesc().ArraySize) : 1;
|
||||
|
||||
for (uint32 MipIndex = 0; MipIndex < NumMips; MipIndex++)
|
||||
{
|
||||
FRHIRenderPassInfo RPInfo(DstTexture, ERenderTargetActions::Load_Store);
|
||||
RPInfo.ColorRenderTargets[0].MipIndex = MipIndex;
|
||||
|
||||
for (int32 SliceIndex = 0; SliceIndex < SliceCount; ++SliceIndex)
|
||||
{
|
||||
RPInfo.ColorRenderTargets[0].ArraySlice = SliceIndex;
|
||||
|
||||
RHICmdList.BeginRenderPass(RPInfo, TEXT("CopyTexture"));
|
||||
{
|
||||
const uint32 MipViewportWidth = ViewportWidth >> MipIndex;
|
||||
const uint32 MipViewportHeight = ViewportHeight >> MipIndex;
|
||||
const FIntPoint MipTargetSize(MipViewportWidth, MipViewportHeight);
|
||||
|
||||
if (bNoAlphaWrite || bInvertAlpha)
|
||||
{
|
||||
RHICmdList.SetViewport(DstRect.Min.X, DstRect.Min.Y, 0.0f, DstRect.Max.X, DstRect.Max.Y, 1.0f);
|
||||
DrawClearQuad(RHICmdList, bAlphaPremultiply ? FLinearColor::Black : FLinearColor::White);
|
||||
}
|
||||
|
||||
RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
|
||||
FRHISamplerState* SamplerState = DstRect.Size() == SrcRect.Size() ? TStaticSamplerState<SF_Point>::GetRHI() : TStaticSamplerState<SF_Bilinear>::GetRHI();
|
||||
|
||||
if (!sRGBSource)
|
||||
{
|
||||
if (bUseTexArrayShader)
|
||||
{
|
||||
TShaderMapRef<FScreenPSMipLevelArray> PixelShader(ShaderMap);
|
||||
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
|
||||
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit, 0);
|
||||
FRHIBatchedShaderParameters& BatchedParameters = RHICmdList.GetScratchShaderParameters();
|
||||
PixelShader->SetParameters(BatchedParameters, SamplerState, SrcTextureRHI, SliceIndex, MipIndex);
|
||||
RHICmdList.SetBatchedShaderParameters(RHICmdList.GetBoundPixelShader(), BatchedParameters);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
TShaderMapRef<FScreenPSMipLevel> PixelShader(ShaderMap);
|
||||
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
|
||||
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit, 0);
|
||||
#if UE_VERSION_OLDER_THAN(5, 3, 0)
|
||||
PixelShader->SetParameters(RHICmdList, SamplerState, SrcTextureRHI, MipIndex);
|
||||
#else
|
||||
FRHIBatchedShaderParameters& BatchedParameters = RHICmdList.GetScratchShaderParameters();
|
||||
PixelShader->SetParameters(BatchedParameters, SamplerState, SrcTextureRHI, MipIndex);
|
||||
RHICmdList.SetBatchedShaderParameters(RHICmdList.GetBoundPixelShader(), BatchedParameters);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bUseTexArrayShader)
|
||||
{
|
||||
TShaderMapRef<FScreenPSsRGBSourceMipLevelArray> PixelShader(ShaderMap);
|
||||
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
|
||||
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit, 0);
|
||||
FRHIBatchedShaderParameters& BatchedParameters = RHICmdList.GetScratchShaderParameters();
|
||||
PixelShader->SetParameters(BatchedParameters, SamplerState, SrcTextureRHI, SliceIndex, MipIndex);
|
||||
RHICmdList.SetBatchedShaderParameters(RHICmdList.GetBoundPixelShader(), BatchedParameters);
|
||||
}
|
||||
else
|
||||
{
|
||||
TShaderMapRef<FScreenPSsRGBSourceMipLevel> PixelShader(ShaderMap);
|
||||
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
|
||||
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit, 0);
|
||||
#if UE_VERSION_OLDER_THAN(5, 3, 0)
|
||||
PixelShader->SetParameters(RHICmdList, SamplerState, SrcTextureRHI, MipIndex);
|
||||
#else
|
||||
FRHIBatchedShaderParameters& BatchedParameters = RHICmdList.GetScratchShaderParameters();
|
||||
PixelShader->SetParameters(BatchedParameters, SamplerState, SrcTextureRHI, MipIndex);
|
||||
RHICmdList.SetBatchedShaderParameters(RHICmdList.GetBoundPixelShader(), BatchedParameters);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
RHICmdList.SetViewport(DstRect.Min.X, DstRect.Min.Y, 0.0f, DstRect.Min.X + MipViewportWidth, DstRect.Min.Y + MipViewportHeight, 1.0f);
|
||||
|
||||
RendererModule->DrawRectangle(
|
||||
RHICmdList,
|
||||
0, 0, MipViewportWidth, MipViewportHeight,
|
||||
U, V, USize, VSize,
|
||||
MipTargetSize,
|
||||
FIntPoint(1, 1),
|
||||
VertexShader,
|
||||
EDRF_Default);
|
||||
}
|
||||
RHICmdList.EndRenderPass();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int FaceIndex = 0; FaceIndex < 6; FaceIndex++)
|
||||
{
|
||||
FRHIRenderPassInfo RPInfo(DstTexture, ERenderTargetActions::Load_Store);
|
||||
|
||||
#if defined(WITH_OCULUS_BRANCH)
|
||||
static const FMatrix44f FaceToSampleMatrix[6] = {
|
||||
FMatrix44f(
|
||||
FVector3f(0, 0, 1),
|
||||
FVector3f(0, 1, 0),
|
||||
FVector3f(1, 0, 0),
|
||||
FVector3f(0, 0, 0)),
|
||||
FMatrix44f(
|
||||
FVector3f(0, 0, -1),
|
||||
FVector3f(0, 1, 0),
|
||||
FVector3f(-1, 0, 0),
|
||||
FVector3f(0, 0, 0)),
|
||||
FMatrix44f(
|
||||
FVector3f(1, 0, 0),
|
||||
FVector3f(0, 0, 1),
|
||||
FVector3f(0, 1, 0),
|
||||
FVector3f(0, 0, 0)),
|
||||
FMatrix44f(
|
||||
FVector3f(1, 0, 0),
|
||||
FVector3f(0, 0, -1),
|
||||
FVector3f(0, -1, 0),
|
||||
FVector3f(0, 0, 0)),
|
||||
FMatrix44f(
|
||||
FVector3f(1, 0, 0),
|
||||
FVector3f(0, 1, 0),
|
||||
FVector3f(0, 0, -1),
|
||||
FVector3f(0, 0, 0)),
|
||||
FMatrix44f(
|
||||
FVector3f(-1, 0, 0),
|
||||
FVector3f(0, 1, 0),
|
||||
FVector3f(0, 0, 1),
|
||||
FVector3f(0, 0, 0)),
|
||||
};
|
||||
#endif
|
||||
|
||||
// On Vulkan the positive and negative Y faces of the cubemap need to be flipped
|
||||
if (bUsingVulkan)
|
||||
{
|
||||
int NewFaceIndex = 0;
|
||||
|
||||
if (FaceIndex == VULKAN_CUBEMAP_POSITIVE_Y)
|
||||
NewFaceIndex = VULKAN_CUBEMAP_NEGATIVE_Y;
|
||||
else if (FaceIndex == VULKAN_CUBEMAP_NEGATIVE_Y)
|
||||
NewFaceIndex = VULKAN_CUBEMAP_POSITIVE_Y;
|
||||
else
|
||||
NewFaceIndex = FaceIndex;
|
||||
|
||||
RPInfo.ColorRenderTargets[0].ArraySlice = NewFaceIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
RPInfo.ColorRenderTargets[0].ArraySlice = FaceIndex;
|
||||
}
|
||||
|
||||
RHICmdList.BeginRenderPass(RPInfo, TEXT("CopyTextureFace"));
|
||||
{
|
||||
if (bNoAlphaWrite)
|
||||
{
|
||||
DrawClearQuad(RHICmdList, bAlphaPremultiply ? FLinearColor::Black : FLinearColor::White);
|
||||
}
|
||||
|
||||
RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
|
||||
|
||||
#if defined(WITH_OCULUS_BRANCH)
|
||||
TShaderMapRef<FOculusOpenXRCubemapPS> PixelShader(ShaderMap);
|
||||
#else
|
||||
TShaderMapRef<FOculusCubemapPS> PixelShader(ShaderMap);
|
||||
#endif
|
||||
|
||||
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
|
||||
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit, 0);
|
||||
FRHISamplerState* SamplerState = DstRect.Size() == SrcRect.Size() ? TStaticSamplerState<SF_Point>::GetRHI() : TStaticSamplerState<SF_Bilinear>::GetRHI();
|
||||
#if UE_VERSION_OLDER_THAN(5, 3, 0)
|
||||
PixelShader->SetParameters(RHICmdList, SamplerState, SrcTextureRHI, FaceIndex);
|
||||
#else
|
||||
FRHIBatchedShaderParameters& BatchedParameters = RHICmdList.GetScratchShaderParameters();
|
||||
|
||||
#if defined(WITH_OCULUS_BRANCH)
|
||||
check(FaceIndex < UE_ARRAY_COUNT(FaceToSampleMatrix));
|
||||
PixelShader->SetParameters(BatchedParameters, SamplerState, SrcTextureRHI, FaceToSampleMatrix[FaceIndex]);
|
||||
#else
|
||||
PixelShader->SetParameters(BatchedParameters, SamplerState, SrcTextureRHI, FaceIndex);
|
||||
#endif
|
||||
RHICmdList.SetBatchedShaderParameters(RHICmdList.GetBoundPixelShader(), BatchedParameters);
|
||||
#endif
|
||||
|
||||
RHICmdList.SetViewport(DstRect.Min.X, DstRect.Min.Y, 0.0f, DstRect.Max.X, DstRect.Max.Y, 1.0f);
|
||||
|
||||
RendererModule->DrawRectangle(
|
||||
RHICmdList,
|
||||
0, 0, ViewportWidth, ViewportHeight,
|
||||
#if PLATFORM_ANDROID
|
||||
U, V, USize, VSize,
|
||||
#else
|
||||
U, 1.0 - V, USize, -VSize,
|
||||
#endif
|
||||
TargetSize,
|
||||
FIntPoint(1, 1),
|
||||
VertexShader,
|
||||
EDRF_Default);
|
||||
}
|
||||
RHICmdList.EndRenderPass();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FCustomPresent::SubmitGPUCommands_RenderThread(FRHICommandListImmediate& RHICmdList)
|
||||
{
|
||||
CheckInRenderThread();
|
||||
|
||||
RHICmdList.ImmediateFlush(EImmediateFlushType::DispatchToRHIThread);
|
||||
}
|
||||
|
||||
} // namespace OculusXRHMD
|
||||
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
@@ -0,0 +1,120 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
#include "OculusXRHMDPrivate.h"
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
#include "OculusXRHMD_Settings.h"
|
||||
#include "OculusXRHMD_GameFrame.h"
|
||||
#include "XRSwapChain.h"
|
||||
#include "RHI.h"
|
||||
#include "RendererInterface.h"
|
||||
#include "IStereoLayers.h"
|
||||
#include "XRRenderBridge.h"
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#include "Windows/WindowsHWrapper.h"
|
||||
#endif
|
||||
|
||||
DECLARE_STATS_GROUP(TEXT("OculusXRHMD"), STATGROUP_OculusXRHMD, STATCAT_Advanced);
|
||||
DECLARE_CYCLE_STAT(TEXT("BeginRendering"), STAT_BeginRendering, STATGROUP_OculusXRHMD);
|
||||
DECLARE_CYCLE_STAT(TEXT("FinishRendering"), STAT_FinishRendering, STATGROUP_OculusXRHMD);
|
||||
DECLARE_FLOAT_COUNTER_STAT(TEXT("LatencyRender"), STAT_LatencyRender, STATGROUP_OculusXRHMD);
|
||||
DECLARE_FLOAT_COUNTER_STAT(TEXT("LatencyTimewarp"), STAT_LatencyTimewarp, STATGROUP_OculusXRHMD);
|
||||
DECLARE_FLOAT_COUNTER_STAT(TEXT("LatencyPostPresent"), STAT_LatencyPostPresent, STATGROUP_OculusXRHMD);
|
||||
DECLARE_FLOAT_COUNTER_STAT(TEXT("ErrorRender"), STAT_ErrorRender, STATGROUP_OculusXRHMD);
|
||||
DECLARE_FLOAT_COUNTER_STAT(TEXT("ErrorTimewarp"), STAT_ErrorTimewarp, STATGROUP_OculusXRHMD);
|
||||
|
||||
namespace OculusXRHMD
|
||||
{
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// FCustomPresent
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
class FCustomPresent : public FXRRenderBridge
|
||||
{
|
||||
public:
|
||||
FCustomPresent(class FOculusXRHMD* InOculusXRHMD, ovrpRenderAPIType InRenderAPI, EPixelFormat InDefaultPixelFormat, bool InSupportsSRGB);
|
||||
|
||||
// FXRRenderBridge/FRHICustomPresent
|
||||
virtual bool NeedsNativePresent() override;
|
||||
virtual bool Present(int32& SyncInterval) override;
|
||||
virtual void FinishRendering_RHIThread();
|
||||
|
||||
ovrpRenderAPIType GetRenderAPI() const { return RenderAPI; }
|
||||
virtual bool IsUsingCorrectDisplayAdapter() const { return true; }
|
||||
|
||||
void UpdateMirrorTexture_RenderThread();
|
||||
void ReleaseResources_RHIThread();
|
||||
void Shutdown();
|
||||
|
||||
FTextureRHIRef GetMirrorTexture() { return MirrorTextureRHI; }
|
||||
|
||||
virtual void* GetOvrpInstance() const { return nullptr; }
|
||||
virtual void* GetOvrpPhysicalDevice() const { return nullptr; }
|
||||
virtual void* GetOvrpDevice() const { return nullptr; }
|
||||
virtual void* GetOvrpCommandQueue() const { return nullptr; }
|
||||
EPixelFormat GetPixelFormat(EPixelFormat InFormat) const;
|
||||
EPixelFormat GetPixelFormat(ovrpTextureFormat InFormat) const;
|
||||
EPixelFormat GetDefaultPixelFormat() const { return DefaultPixelFormat; }
|
||||
ovrpTextureFormat GetOvrpTextureFormat(EPixelFormat InFormat, bool usesRGB = true) const;
|
||||
ovrpTextureFormat GetDefaultOvrpTextureFormat() const { return DefaultOvrpTextureFormat; }
|
||||
ovrpTextureFormat GetDefaultDepthOvrpTextureFormat() const { return DefaultDepthOvrpTextureFormat; }
|
||||
static bool IsSRGB(ovrpTextureFormat InFormat);
|
||||
virtual int GetSystemRecommendedMSAALevel() const;
|
||||
virtual int GetLayerFlags() const { return 0; }
|
||||
|
||||
virtual FTextureRHIRef CreateTexture_RenderThread(uint32 InSizeX, uint32 InSizeY, EPixelFormat InFormat, FClearValueBinding InBinding, uint32 InNumMips, uint32 InNumSamples, uint32 InNumSamplesTileMem, ERHIResourceType InResourceType, ovrpTextureHandle InTexture, ETextureCreateFlags TexCreateFlags) = 0;
|
||||
FXRSwapChainPtr CreateSwapChain_RenderThread(uint32 InSizeX, uint32 InSizeY, EPixelFormat InFormat, FClearValueBinding InBinding, uint32 InNumMips, uint32 InNumSamples, uint32 InNumSamplesTileMem, ERHIResourceType InResourceType, const TArray<ovrpTextureHandle>& InTextures, ETextureCreateFlags InTexCreateFlags, const TCHAR* DebugName);
|
||||
TArray<FTextureRHIRef> CreateSwapChainTextures_RenderThread(uint32 InSizeX, uint32 InSizeY, EPixelFormat InFormat, FClearValueBinding InBinding, uint32 InNumMips, uint32 InNumSamples, uint32 InNumSamplesTileMem, ERHIResourceType InResourceType, const TArray<ovrpTextureHandle>& InTextures, ETextureCreateFlags InTexCreateFlags, const TCHAR* DebugName);
|
||||
|
||||
void CopyTexture_RenderThread(FRHICommandListImmediate& RHICmdList, FRHITexture* DstTexture, FRHITexture* SrcTexture, FIntRect DstRect = FIntRect(), FIntRect SrcRect = FIntRect(), bool bAlphaPremultiply = false, bool bNoAlphaWrite = false, bool bInvertY = true, bool sRGBSource = false, bool bInvertAlpha = false);
|
||||
OCULUSXRHMD_API static void CopyTexture_RenderThread(FRHICommandListImmediate& RHICmdList, IRendererModule* RendererModule, FRHITexture* DstTexture, FRHITexture* SrcTexture, FStaticFeatureLevel FeatureLevel, bool bUsingVulkan, FIntRect DstRect = FIntRect(), FIntRect SrcRect = FIntRect(), bool bAlphaPremultiply = false, bool bNoAlphaWrite = false, bool bInvertY = true, bool sRGBSource = false, bool bInvertAlpha = false);
|
||||
|
||||
void SubmitGPUCommands_RenderThread(FRHICommandListImmediate& RHICmdList);
|
||||
virtual void SubmitGPUFrameTime(float GPUFrameTime) {}
|
||||
// This is a hack to turn force FSR off when we allocate our FDM to avoid a crash on Quest 3
|
||||
// TODO: Remove this for UE 5.3 after there's an engine-side fix
|
||||
virtual void UseFragmentDensityMapOverShadingRate_RHIThread() {};
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
virtual void UpdateFoveationOffsets_RHIThread(bool bUseOffsets, FIntPoint Offsets[2]) {};
|
||||
#endif // WITH_OCULUS_BRANCH
|
||||
|
||||
bool SupportsSRGB()
|
||||
{
|
||||
return bSupportsSRGB;
|
||||
}
|
||||
bool SupportsSubsampled() { return bSupportsSubsampled; }
|
||||
|
||||
protected:
|
||||
FOculusXRHMD* OculusXRHMD;
|
||||
ovrpRenderAPIType RenderAPI;
|
||||
EPixelFormat DefaultPixelFormat;
|
||||
bool bSupportsSRGB;
|
||||
bool bSupportsSubsampled;
|
||||
ovrpTextureFormat DefaultOvrpTextureFormat;
|
||||
ovrpTextureFormat DefaultDepthOvrpTextureFormat;
|
||||
IRendererModule* RendererModule;
|
||||
FTextureRHIRef MirrorTextureRHI;
|
||||
bool bIsStandaloneStereoDevice;
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// APIs
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS_D3D11
|
||||
FCustomPresent* CreateCustomPresent_D3D11(FOculusXRHMD* InOculusXRHMD);
|
||||
#endif
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS_D3D12
|
||||
FCustomPresent* CreateCustomPresent_D3D12(FOculusXRHMD* InOculusXRHMD);
|
||||
#endif
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS_VULKAN
|
||||
FCustomPresent* CreateCustomPresent_Vulkan(FOculusXRHMD* InOculusXRHMD);
|
||||
#endif
|
||||
|
||||
} // namespace OculusXRHMD
|
||||
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
@@ -0,0 +1,118 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "OculusXRHMD_CustomPresent.h"
|
||||
#include "OculusXRHMDPrivateRHI.h"
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS_D3D11
|
||||
#include "OculusXRHMD.h"
|
||||
|
||||
#ifndef WINDOWS_PLATFORM_TYPES_GUARD
|
||||
#include "Windows/AllowWindowsPlatformTypes.h"
|
||||
#endif
|
||||
|
||||
namespace OculusXRHMD
|
||||
{
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// FD3D11CustomPresent
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
class FD3D11CustomPresent : public FCustomPresent
|
||||
{
|
||||
public:
|
||||
FD3D11CustomPresent(FOculusXRHMD* InOculusXRHMD);
|
||||
|
||||
// Implementation of FCustomPresent, called by Plugin itself
|
||||
virtual bool IsUsingCorrectDisplayAdapter() const override;
|
||||
virtual void* GetOvrpDevice() const override;
|
||||
virtual FTextureRHIRef CreateTexture_RenderThread(uint32 InSizeX, uint32 InSizeY, EPixelFormat InFormat, FClearValueBinding InBinding, uint32 InNumMips, uint32 InNumSamples, uint32 InNumSamplesTileMem, ERHIResourceType InResourceType, ovrpTextureHandle InTexture, ETextureCreateFlags InTexCreateFlags) override;
|
||||
};
|
||||
|
||||
FD3D11CustomPresent::FD3D11CustomPresent(FOculusXRHMD* InOculusXRHMD)
|
||||
: FCustomPresent(InOculusXRHMD, ovrpRenderAPI_D3D11, PF_B8G8R8A8, true)
|
||||
{
|
||||
switch (GPixelFormats[PF_DepthStencil].PlatformFormat)
|
||||
{
|
||||
case DXGI_FORMAT_R24G8_TYPELESS:
|
||||
DefaultDepthOvrpTextureFormat = ovrpTextureFormat_D24_S8;
|
||||
break;
|
||||
case DXGI_FORMAT_R32G8X24_TYPELESS:
|
||||
DefaultDepthOvrpTextureFormat = ovrpTextureFormat_D32_FP_S8;
|
||||
break;
|
||||
default:
|
||||
UE_LOG(LogHMD, Error, TEXT("Unrecognized depth buffer format"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool FD3D11CustomPresent::IsUsingCorrectDisplayAdapter() const
|
||||
{
|
||||
const void* luid;
|
||||
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetDisplayAdapterId2(&luid)) && luid)
|
||||
{
|
||||
TRefCountPtr<ID3D11Device> D3D11Device;
|
||||
|
||||
ExecuteOnRenderThread([&D3D11Device]() {
|
||||
D3D11Device = (ID3D11Device*)RHIGetNativeDevice();
|
||||
});
|
||||
|
||||
if (D3D11Device)
|
||||
{
|
||||
TRefCountPtr<IDXGIDevice> DXGIDevice;
|
||||
TRefCountPtr<IDXGIAdapter> DXGIAdapter;
|
||||
DXGI_ADAPTER_DESC DXGIAdapterDesc;
|
||||
|
||||
if (SUCCEEDED(D3D11Device->QueryInterface(__uuidof(IDXGIDevice), (void**)DXGIDevice.GetInitReference())) && SUCCEEDED(DXGIDevice->GetAdapter(DXGIAdapter.GetInitReference())) && SUCCEEDED(DXGIAdapter->GetDesc(&DXGIAdapterDesc)))
|
||||
{
|
||||
return !FMemory::Memcmp(luid, &DXGIAdapterDesc.AdapterLuid, sizeof(LUID));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Not enough information. Assume that we are using the correct adapter.
|
||||
return true;
|
||||
}
|
||||
|
||||
void* FD3D11CustomPresent::GetOvrpDevice() const
|
||||
{
|
||||
return GetID3D11DynamicRHI()->RHIGetDevice();
|
||||
}
|
||||
|
||||
FTextureRHIRef FD3D11CustomPresent::CreateTexture_RenderThread(uint32 InSizeX, uint32 InSizeY, EPixelFormat InFormat, FClearValueBinding InBinding, uint32 InNumMips, uint32 InNumSamples, uint32 InNumSamplesTileMem, ERHIResourceType InResourceType, ovrpTextureHandle InTexture, ETextureCreateFlags InTexCreateFlags)
|
||||
{
|
||||
CheckInRenderThread();
|
||||
|
||||
switch (InResourceType)
|
||||
{
|
||||
case RRT_Texture2D:
|
||||
return GetID3D11DynamicRHI()->RHICreateTexture2DFromResource(InFormat, InTexCreateFlags, InBinding, (ID3D11Texture2D*)InTexture).GetReference();
|
||||
|
||||
case RRT_Texture2DArray:
|
||||
return GetID3D11DynamicRHI()->RHICreateTexture2DArrayFromResource(InFormat, InTexCreateFlags, InBinding, (ID3D11Texture2D*)InTexture).GetReference();
|
||||
|
||||
case RRT_TextureCube:
|
||||
return GetID3D11DynamicRHI()->RHICreateTextureCubeFromResource(InFormat, InTexCreateFlags | TexCreate_TargetArraySlicesIndependently, InBinding, (ID3D11Texture2D*)InTexture).GetReference();
|
||||
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// APIs
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
FCustomPresent* CreateCustomPresent_D3D11(FOculusXRHMD* InOculusXRHMD)
|
||||
{
|
||||
return new FD3D11CustomPresent(InOculusXRHMD);
|
||||
}
|
||||
|
||||
} // namespace OculusXRHMD
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#undef WINDOWS_PLATFORM_TYPES_GUARD
|
||||
#endif
|
||||
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS_D3D11
|
||||
@@ -0,0 +1,114 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "OculusXRHMD_CustomPresent.h"
|
||||
#include "OculusXRHMDPrivateRHI.h"
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS_D3D12
|
||||
#include "OculusXRHMD.h"
|
||||
|
||||
#ifndef WINDOWS_PLATFORM_TYPES_GUARD
|
||||
#include "Windows/AllowWindowsPlatformTypes.h"
|
||||
#endif
|
||||
|
||||
namespace OculusXRHMD
|
||||
{
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// FCustomPresentD3D12
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
class FD3D12CustomPresent : public FCustomPresent
|
||||
{
|
||||
public:
|
||||
FD3D12CustomPresent(FOculusXRHMD* InOculusXRHMD);
|
||||
|
||||
// Implementation of FCustomPresent, called by Plugin itself
|
||||
virtual bool IsUsingCorrectDisplayAdapter() const override;
|
||||
virtual void* GetOvrpDevice() const override;
|
||||
virtual FTextureRHIRef CreateTexture_RenderThread(uint32 InSizeX, uint32 InSizeY, EPixelFormat InFormat, FClearValueBinding InBinding, uint32 InNumMips, uint32 InNumSamples, uint32 InNumSamplesTileMem, ERHIResourceType InResourceType, ovrpTextureHandle InTexture, ETextureCreateFlags InTexCreateFlags) override;
|
||||
};
|
||||
|
||||
FD3D12CustomPresent::FD3D12CustomPresent(FOculusXRHMD* InOculusXRHMD)
|
||||
: FCustomPresent(InOculusXRHMD, ovrpRenderAPI_D3D12, PF_B8G8R8A8, true)
|
||||
{
|
||||
switch (GPixelFormats[PF_DepthStencil].PlatformFormat)
|
||||
{
|
||||
case DXGI_FORMAT_R24G8_TYPELESS:
|
||||
DefaultDepthOvrpTextureFormat = ovrpTextureFormat_D24_S8;
|
||||
break;
|
||||
case DXGI_FORMAT_R32G8X24_TYPELESS:
|
||||
DefaultDepthOvrpTextureFormat = ovrpTextureFormat_D32_FP_S8;
|
||||
break;
|
||||
default:
|
||||
UE_LOG(LogHMD, Error, TEXT("Unrecognized depth buffer format"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool FD3D12CustomPresent::IsUsingCorrectDisplayAdapter() const
|
||||
{
|
||||
const void* luid;
|
||||
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetDisplayAdapterId2(&luid)) && luid)
|
||||
{
|
||||
TRefCountPtr<ID3D12Device> D3DDevice;
|
||||
|
||||
ExecuteOnRenderThread([&D3DDevice]() {
|
||||
D3DDevice = (ID3D12Device*)RHIGetNativeDevice();
|
||||
});
|
||||
|
||||
if (D3DDevice)
|
||||
{
|
||||
LUID AdapterLuid = D3DDevice->GetAdapterLuid();
|
||||
return !FMemory::Memcmp(luid, &AdapterLuid, sizeof(LUID));
|
||||
}
|
||||
}
|
||||
|
||||
// Not enough information. Assume that we are using the correct adapter.
|
||||
return true;
|
||||
}
|
||||
|
||||
void* FD3D12CustomPresent::GetOvrpDevice() const
|
||||
{
|
||||
return GetID3D12DynamicRHI()->RHIGetCommandQueue();
|
||||
}
|
||||
|
||||
FTextureRHIRef FD3D12CustomPresent::CreateTexture_RenderThread(uint32 InSizeX, uint32 InSizeY, EPixelFormat InFormat, FClearValueBinding InBinding, uint32 InNumMips, uint32 InNumSamples, uint32 InNumSamplesTileMem, ERHIResourceType InResourceType, ovrpTextureHandle InTexture, ETextureCreateFlags InTexCreateFlags)
|
||||
{
|
||||
CheckInRenderThread();
|
||||
|
||||
ID3D12DynamicRHI* DynamicRHI = GetID3D12DynamicRHI();
|
||||
|
||||
switch (InResourceType)
|
||||
{
|
||||
case RRT_Texture2D:
|
||||
return DynamicRHI->RHICreateTexture2DFromResource(InFormat, InTexCreateFlags, InBinding, (ID3D12Resource*)InTexture).GetReference();
|
||||
|
||||
case RRT_Texture2DArray:
|
||||
return DynamicRHI->RHICreateTexture2DArrayFromResource(InFormat, InTexCreateFlags, InBinding, (ID3D12Resource*)InTexture).GetReference();
|
||||
|
||||
case RRT_TextureCube:
|
||||
return DynamicRHI->RHICreateTextureCubeFromResource(InFormat, InTexCreateFlags | TexCreate_TargetArraySlicesIndependently, InBinding, (ID3D12Resource*)InTexture).GetReference();
|
||||
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// APIs
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
FCustomPresent* CreateCustomPresent_D3D12(FOculusXRHMD* InOculusXRHMD)
|
||||
{
|
||||
return new FD3D12CustomPresent(InOculusXRHMD);
|
||||
}
|
||||
|
||||
} // namespace OculusXRHMD
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#undef WINDOWS_PLATFORM_TYPES_GUARD
|
||||
#endif
|
||||
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS_D3D12
|
||||
@@ -0,0 +1,178 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "OculusXRHMD_CustomPresent.h"
|
||||
#include "OculusXRHMDPrivateRHI.h"
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS_VULKAN
|
||||
#include "OculusXRHMD.h"
|
||||
#include "IVulkanDynamicRHI.h"
|
||||
#include "Async/Async.h"
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#ifndef WINDOWS_PLATFORM_TYPES_GUARD
|
||||
#include "Windows/AllowWindowsPlatformTypes.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace OculusXRHMD
|
||||
{
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// FCustomPresentVulkan
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
class FVulkanCustomPresent : public FCustomPresent
|
||||
{
|
||||
public:
|
||||
FVulkanCustomPresent(FOculusXRHMD* InOculusXRHMD);
|
||||
|
||||
// Implementation of FCustomPresent, called by Plugin itself
|
||||
virtual bool IsUsingCorrectDisplayAdapter() const override;
|
||||
virtual void* GetOvrpInstance() const override;
|
||||
virtual void* GetOvrpPhysicalDevice() const override;
|
||||
virtual void* GetOvrpDevice() const override;
|
||||
virtual void* GetOvrpCommandQueue() const override;
|
||||
virtual FTextureRHIRef CreateTexture_RenderThread(uint32 InSizeX, uint32 InSizeY, EPixelFormat InFormat, FClearValueBinding InBinding, uint32 InNumMips, uint32 InNumSamples, uint32 InNumSamplesTileMem, ERHIResourceType InResourceType, ovrpTextureHandle InTexture, ETextureCreateFlags InTexCreateFlags) override;
|
||||
// This is a hack to turn force FSR off when we allocate our FDM to avoid a crash on Quest 3
|
||||
// TODO: Remove this for UE 5.3 after there's an engine-side fix
|
||||
virtual void UseFragmentDensityMapOverShadingRate_RHIThread() override;
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
virtual void UpdateFoveationOffsets_RHIThread(bool bUseTileOffsets, FIntPoint TileOffsets[2]) override;
|
||||
#endif // WITH_OCULUS_BRANCH
|
||||
};
|
||||
|
||||
FVulkanCustomPresent::FVulkanCustomPresent(FOculusXRHMD* InOculusXRHMD)
|
||||
: FCustomPresent(InOculusXRHMD, ovrpRenderAPI_Vulkan, PF_R8G8B8A8, true)
|
||||
{
|
||||
#if PLATFORM_ANDROID
|
||||
AsyncTask(ENamedThreads::GameThread, []() {
|
||||
#if UE_VERSION_OLDER_THAN(5, 5, 0)
|
||||
if (GRHISupportsRHIThread && GIsThreadedRendering && GUseRHIThread_InternalUseOnly)
|
||||
{
|
||||
SetRHIThreadEnabled(false, false);
|
||||
}
|
||||
#else
|
||||
GPendingRHIThreadMode = ERHIThreadMode::None;
|
||||
#endif // UE_VERSION_OLDER_THAN
|
||||
});
|
||||
#endif // PLATFORM_ANDROID
|
||||
|
||||
switch (GPixelFormats[PF_DepthStencil].PlatformFormat)
|
||||
{
|
||||
case VK_FORMAT_D24_UNORM_S8_UINT:
|
||||
DefaultDepthOvrpTextureFormat = ovrpTextureFormat_D24_S8;
|
||||
break;
|
||||
case VK_FORMAT_D32_SFLOAT_S8_UINT:
|
||||
DefaultDepthOvrpTextureFormat = ovrpTextureFormat_D32_FP_S8;
|
||||
break;
|
||||
default:
|
||||
UE_LOG(LogHMD, Error, TEXT("Unrecognized depth buffer format"));
|
||||
break;
|
||||
}
|
||||
bSupportsSubsampled = GetIVulkanDynamicRHI()->RHISupportsEXTFragmentDensityMap2();
|
||||
}
|
||||
|
||||
bool FVulkanCustomPresent::IsUsingCorrectDisplayAdapter() const
|
||||
{
|
||||
#if PLATFORM_WINDOWS
|
||||
const void* AdapterId = nullptr;
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetDisplayAdapterId2(&AdapterId)) && AdapterId)
|
||||
{
|
||||
return GetIVulkanDynamicRHI()->RHIDoesAdapterMatchDevice(AdapterId);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Not enough information. Assume that we are using the correct adapter.
|
||||
return true;
|
||||
}
|
||||
|
||||
void* FVulkanCustomPresent::GetOvrpInstance() const
|
||||
{
|
||||
return GetIVulkanDynamicRHI()->RHIGetVkInstance();
|
||||
}
|
||||
|
||||
void* FVulkanCustomPresent::GetOvrpPhysicalDevice() const
|
||||
{
|
||||
return GetIVulkanDynamicRHI()->RHIGetVkPhysicalDevice();
|
||||
}
|
||||
|
||||
void* FVulkanCustomPresent::GetOvrpDevice() const
|
||||
{
|
||||
return GetIVulkanDynamicRHI()->RHIGetVkDevice();
|
||||
}
|
||||
|
||||
void* FVulkanCustomPresent::GetOvrpCommandQueue() const
|
||||
{
|
||||
return GetIVulkanDynamicRHI()->RHIGetGraphicsVkQueue();
|
||||
}
|
||||
|
||||
FTextureRHIRef FVulkanCustomPresent::CreateTexture_RenderThread(uint32 InSizeX, uint32 InSizeY, EPixelFormat InFormat, FClearValueBinding InBinding, uint32 InNumMips, uint32 InNumSamples, uint32 InNumSamplesTileMem, ERHIResourceType InResourceType, ovrpTextureHandle InTexture, ETextureCreateFlags InTexCreateFlags)
|
||||
{
|
||||
CheckInRenderThread();
|
||||
|
||||
IVulkanDynamicRHI* VulkanRHI = GetIVulkanDynamicRHI();
|
||||
const VkImageSubresourceRange SubresourceRangeAll = { VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS };
|
||||
|
||||
if (EnumHasAnyFlags(InTexCreateFlags, TexCreate_RenderTargetable))
|
||||
{
|
||||
VulkanRHI->RHISetImageLayout((VkImage)InTexture, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, SubresourceRangeAll);
|
||||
}
|
||||
else if (EnumHasAnyFlags(InTexCreateFlags, TexCreate_Foveation))
|
||||
{
|
||||
VulkanRHI->RHISetImageLayout((VkImage)InTexture, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT, SubresourceRangeAll);
|
||||
}
|
||||
|
||||
switch (InResourceType)
|
||||
{
|
||||
case RRT_Texture2D:
|
||||
return VulkanRHI->RHICreateTexture2DFromResource(InFormat, InSizeX, InSizeY, InNumMips, InNumSamples, (VkImage)InTexture, InTexCreateFlags, InBinding).GetReference();
|
||||
|
||||
case RRT_Texture2DArray:
|
||||
return VulkanRHI->RHICreateTexture2DArrayFromResource(InFormat, InSizeX, InSizeY, 2, InNumMips, InNumSamples, (VkImage)InTexture, InTexCreateFlags, InBinding).GetReference();
|
||||
|
||||
case RRT_TextureCube:
|
||||
return VulkanRHI->RHICreateTextureCubeFromResource(InFormat, InSizeX, false, 1, InNumMips, (VkImage)InTexture, InTexCreateFlags, InBinding).GetReference();
|
||||
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// This is a hack to turn force FSR off when we allocate our FDM to avoid a crash on Quest 3
|
||||
// TODO: Remove this for UE 5.3 after there's an engine-side fix
|
||||
void FVulkanCustomPresent::UseFragmentDensityMapOverShadingRate_RHIThread()
|
||||
{
|
||||
CheckInRHIThread();
|
||||
SCOPED_NAMED_EVENT(UseFragmentDensityMapOverShadingRate_RHIThread, FColor::Red);
|
||||
|
||||
GRHIVariableRateShadingImageDataType = VRSImage_Fractional;
|
||||
GRHIVariableRateShadingImageFormat = PF_R8G8;
|
||||
}
|
||||
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
void FVulkanCustomPresent::UpdateFoveationOffsets_RHIThread(bool bUseOffsets, FIntPoint Offsets[2])
|
||||
{
|
||||
CheckInRHIThread();
|
||||
|
||||
SCOPED_NAMED_EVENT(UpdateFoveationOffsets_RHIThread, FColor::Red);
|
||||
GetIVulkanDynamicRHI()->RHISetQcomFragmentDensityMapOffsets(bUseOffsets, Offsets);
|
||||
}
|
||||
#endif // WITH_OCULUS_BRANCH
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// APIs
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
FCustomPresent* CreateCustomPresent_Vulkan(FOculusXRHMD* InOculusXRHMD)
|
||||
{
|
||||
return new FVulkanCustomPresent(InOculusXRHMD);
|
||||
}
|
||||
|
||||
} // namespace OculusXRHMD
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#undef WINDOWS_PLATFORM_TYPES_GUARD
|
||||
#endif
|
||||
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS_VULKAN
|
||||
@@ -0,0 +1,80 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "OculusXRHMD_DeferredDeletionQueue.h"
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
#include "OculusXRHMDPrivate.h"
|
||||
#include "XRThreadUtils.h"
|
||||
#include "OculusXRHMDModule.h"
|
||||
#include "Misc/EngineVersionComparison.h"
|
||||
|
||||
namespace OculusXRHMD
|
||||
{
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// FDeferredDeletionQueue
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
uint32 GOculusXRHMDLayerDeletionFrameNumber = 0;
|
||||
const uint32 NUM_FRAMES_TO_WAIT_FOR_LAYER_DELETE = 3;
|
||||
const uint32 NUM_FRAMES_TO_WAIT_FOR_OVRP_LAYER_DELETE = 7;
|
||||
|
||||
void FDeferredDeletionQueue::AddLayerToDeferredDeletionQueue(const FLayerPtr& ptr)
|
||||
{
|
||||
DeferredDeletionEntry Entry;
|
||||
Entry.Layer = ptr;
|
||||
Entry.FrameEnqueued = GOculusXRHMDLayerDeletionFrameNumber;
|
||||
Entry.EntryType = DeferredDeletionEntry::DeferredDeletionEntryType::Layer;
|
||||
DeferredDeletionArray.Add(Entry);
|
||||
}
|
||||
|
||||
void FDeferredDeletionQueue::AddOVRPLayerToDeferredDeletionQueue(const uint32 layerID)
|
||||
{
|
||||
DeferredDeletionEntry Entry;
|
||||
Entry.OvrpLayerId = layerID;
|
||||
Entry.FrameEnqueued = GOculusXRHMDLayerDeletionFrameNumber;
|
||||
Entry.EntryType = DeferredDeletionEntry::DeferredDeletionEntryType::OvrpLayer;
|
||||
DeferredDeletionArray.Add(Entry);
|
||||
}
|
||||
|
||||
void FDeferredDeletionQueue::HandleLayerDeferredDeletionQueue_RenderThread(bool bDeleteImmediately)
|
||||
{
|
||||
// Traverse list backwards so the swap switches to elements already tested
|
||||
for (int32 Index = DeferredDeletionArray.Num() - 1; Index >= 0; --Index)
|
||||
{
|
||||
DeferredDeletionEntry* Entry = &DeferredDeletionArray[Index];
|
||||
if (Entry->EntryType == DeferredDeletionEntry::DeferredDeletionEntryType::Layer)
|
||||
{
|
||||
if (bDeleteImmediately || GOculusXRHMDLayerDeletionFrameNumber > Entry->FrameEnqueued + NUM_FRAMES_TO_WAIT_FOR_LAYER_DELETE)
|
||||
{
|
||||
#if UE_VERSION_OLDER_THAN(5, 5, 0)
|
||||
DeferredDeletionArray.RemoveAtSwap(Index, 1, false);
|
||||
#else
|
||||
DeferredDeletionArray.RemoveAtSwap(Index, 1, EAllowShrinking::No);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else if (Entry->EntryType == DeferredDeletionEntry::DeferredDeletionEntryType::OvrpLayer)
|
||||
{
|
||||
if (bDeleteImmediately || GOculusXRHMDLayerDeletionFrameNumber > Entry->FrameEnqueued + NUM_FRAMES_TO_WAIT_FOR_OVRP_LAYER_DELETE)
|
||||
{
|
||||
ExecuteOnRHIThread_DoNotWait([OvrpLayerId = Entry->OvrpLayerId]() {
|
||||
UE_LOG(LogHMD, Warning, TEXT("Destroying layer %d"), OvrpLayerId);
|
||||
FOculusXRHMDModule::GetPluginWrapper().DestroyLayer(OvrpLayerId);
|
||||
});
|
||||
#if UE_VERSION_OLDER_THAN(5, 5, 0)
|
||||
DeferredDeletionArray.RemoveAtSwap(Index, 1, false);
|
||||
#else
|
||||
DeferredDeletionArray.RemoveAtSwap(Index, 1, EAllowShrinking::No);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if the function is to be called multiple times, move this increment somewhere unique!
|
||||
++GOculusXRHMDLayerDeletionFrameNumber;
|
||||
}
|
||||
|
||||
} // namespace OculusXRHMD
|
||||
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
@@ -0,0 +1,45 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
#include "OculusXRHMDPrivate.h"
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
#include "OculusXRHMD_Layer.h"
|
||||
|
||||
namespace OculusXRHMD
|
||||
{
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// FDeferredDeletionQueue
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
class FDeferredDeletionQueue
|
||||
{
|
||||
public:
|
||||
void AddLayerToDeferredDeletionQueue(const FLayerPtr& ptr);
|
||||
void AddOVRPLayerToDeferredDeletionQueue(const uint32 layerID);
|
||||
void HandleLayerDeferredDeletionQueue_RenderThread(bool bDeleteImmediately = false);
|
||||
|
||||
private:
|
||||
struct DeferredDeletionEntry
|
||||
{
|
||||
enum class DeferredDeletionEntryType
|
||||
{
|
||||
Layer,
|
||||
OvrpLayer
|
||||
};
|
||||
|
||||
FLayerPtr Layer;
|
||||
uint32 OvrpLayerId;
|
||||
|
||||
uint32 FrameEnqueued;
|
||||
DeferredDeletionEntryType EntryType;
|
||||
};
|
||||
|
||||
TArray<DeferredDeletionEntry> DeferredDeletionArray;
|
||||
};
|
||||
|
||||
} // namespace OculusXRHMD
|
||||
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
@@ -0,0 +1,97 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "OculusXRHMD_DynamicResolutionState.h"
|
||||
#include "LegacyScreenPercentageDriver.h"
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
#include "SceneView.h"
|
||||
|
||||
namespace OculusXRHMD
|
||||
{
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// FDynamicResolutionState implementation
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
FDynamicResolutionState::FDynamicResolutionState(const OculusXRHMD::FSettingsPtr InSettings)
|
||||
: Settings(InSettings)
|
||||
, ResolutionFraction(-1.0f)
|
||||
, ResolutionFractionUpperBound(-1.0f)
|
||||
{
|
||||
check(Settings.IsValid());
|
||||
}
|
||||
|
||||
void FDynamicResolutionState::ResetHistory() {
|
||||
// Empty - Oculus drives resolution fraction externally
|
||||
};
|
||||
|
||||
bool FDynamicResolutionState::IsSupported() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void FDynamicResolutionState::SetupMainViewFamily(class FSceneViewFamily& ViewFamily)
|
||||
{
|
||||
check(IsInGameThread());
|
||||
check(ViewFamily.EngineShowFlags.ScreenPercentage == true);
|
||||
|
||||
if (IsEnabled())
|
||||
{
|
||||
// Compute desired resolution fraction range
|
||||
float MinResolutionFraction = Settings->GetPixelDensityMin();
|
||||
float MaxResolutionFraction = Settings->GetPixelDensityMax();
|
||||
|
||||
// Clamp resolution fraction to what the renderer can do.
|
||||
MinResolutionFraction = FMath::Max(MinResolutionFraction, ISceneViewFamilyScreenPercentage::kMinResolutionFraction);
|
||||
MaxResolutionFraction = FMath::Min(MaxResolutionFraction, ISceneViewFamilyScreenPercentage::kMaxResolutionFraction);
|
||||
|
||||
ResolutionFraction = FMath::Clamp(Settings->PixelDensity, MinResolutionFraction, MaxResolutionFraction);
|
||||
ResolutionFractionUpperBound = MaxResolutionFraction;
|
||||
|
||||
ViewFamily.SetScreenPercentageInterface(new FLegacyScreenPercentageDriver(ViewFamily, ResolutionFraction, ResolutionFractionUpperBound));
|
||||
}
|
||||
}
|
||||
#if !UE_VERSION_OLDER_THAN(5, 4, 0)
|
||||
void FDynamicResolutionState::SetTemporalUpscaler(const UE::Renderer::Private::ITemporalUpscaler* InTemporalUpscaler)
|
||||
{
|
||||
// Not supported
|
||||
return;
|
||||
}
|
||||
#endif // !UE_VERSION_OLDER_THAN(5, 4, 0)
|
||||
|
||||
DynamicRenderScaling::TMap<float> FDynamicResolutionState::GetResolutionFractionsApproximation() const
|
||||
{
|
||||
DynamicRenderScaling::TMap<float> ResolutionFractions;
|
||||
ResolutionFractions.SetAll(1.0f);
|
||||
ResolutionFractions[GDynamicPrimaryResolutionFraction] = ResolutionFraction;
|
||||
return ResolutionFractions;
|
||||
}
|
||||
|
||||
DynamicRenderScaling::TMap<float> FDynamicResolutionState::GetResolutionFractionsUpperBound() const
|
||||
{
|
||||
DynamicRenderScaling::TMap<float> ResolutionFractions;
|
||||
ResolutionFractions.SetAll(1.0f);
|
||||
ResolutionFractions[GDynamicPrimaryResolutionFraction] = ResolutionFractionUpperBound;
|
||||
return ResolutionFractionUpperBound;
|
||||
}
|
||||
|
||||
void FDynamicResolutionState::SetEnabled(bool bEnable)
|
||||
{
|
||||
check(IsInGameThread());
|
||||
Settings->Flags.bPixelDensityAdaptive = bEnable;
|
||||
}
|
||||
|
||||
bool FDynamicResolutionState::IsEnabled() const
|
||||
{
|
||||
check(IsInGameThread());
|
||||
return Settings->Flags.bPixelDensityAdaptive;
|
||||
}
|
||||
|
||||
void FDynamicResolutionState::ProcessEvent(EDynamicResolutionStateEvent Event) {
|
||||
// Empty - Oculus drives resolution fraction externally
|
||||
};
|
||||
|
||||
} // namespace OculusXRHMD
|
||||
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
@@ -0,0 +1,46 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
#include "OculusXRHMDPrivate.h"
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
#include "OculusXRHMD_Settings.h"
|
||||
#include "DynamicResolutionState.h"
|
||||
|
||||
namespace OculusXRHMD
|
||||
{
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// FDynamicResolutionState
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
class FDynamicResolutionState : public IDynamicResolutionState
|
||||
{
|
||||
public:
|
||||
FDynamicResolutionState(const OculusXRHMD::FSettingsPtr InSettings);
|
||||
|
||||
// ISceneViewFamilyScreenPercentage
|
||||
virtual void ResetHistory() override;
|
||||
virtual bool IsSupported() const override;
|
||||
virtual void SetupMainViewFamily(class FSceneViewFamily& ViewFamily) override;
|
||||
#if !UE_VERSION_OLDER_THAN(5, 4, 0)
|
||||
virtual void SetTemporalUpscaler(const UE::Renderer::Private::ITemporalUpscaler* InTemporalUpscaler) override;
|
||||
#endif // !UE_VERSION_OLDER_THAN(5, 4, 0)
|
||||
|
||||
protected:
|
||||
virtual DynamicRenderScaling::TMap<float> GetResolutionFractionsApproximation() const override;
|
||||
virtual DynamicRenderScaling::TMap<float> GetResolutionFractionsUpperBound() const override;
|
||||
virtual void SetEnabled(bool bEnable) override;
|
||||
virtual bool IsEnabled() const override;
|
||||
virtual void ProcessEvent(EDynamicResolutionStateEvent Event) override;
|
||||
|
||||
private:
|
||||
const OculusXRHMD::FSettingsPtr Settings;
|
||||
float ResolutionFraction;
|
||||
float ResolutionFractionUpperBound;
|
||||
};
|
||||
|
||||
} // namespace OculusXRHMD
|
||||
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
@@ -0,0 +1,74 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "OculusXRHMD_FoveatedRendering.h"
|
||||
|
||||
#include "HeadMountedDisplayTypes.h" // For the LogHMD log category
|
||||
#include "RenderGraphBuilder.h"
|
||||
#include "SceneView.h"
|
||||
#include "StereoRendering.h"
|
||||
|
||||
FOculusXRFoveatedRenderingImageGenerator::FOculusXRFoveatedRenderingImageGenerator(const FXRSwapChainPtr& Swapchain)
|
||||
: FoveationSwapchain(Swapchain)
|
||||
{
|
||||
GVRSImageManager.RegisterExternalImageGenerator(this);
|
||||
}
|
||||
|
||||
FOculusXRFoveatedRenderingImageGenerator::~FOculusXRFoveatedRenderingImageGenerator()
|
||||
{
|
||||
GVRSImageManager.UnregisterExternalImageGenerator(this);
|
||||
}
|
||||
|
||||
#if !UE_VERSION_OLDER_THAN(5, 4, 0)
|
||||
FRDGTextureRef FOculusXRFoveatedRenderingImageGenerator::GetImage(
|
||||
FRDGBuilder& GraphBuilder,
|
||||
const FViewInfo& ViewInfo,
|
||||
FVariableRateShadingImageManager::EVRSImageType ImageType, bool bGetSoftwareImage)
|
||||
#else
|
||||
FRDGTextureRef FOculusXRFoveatedRenderingImageGenerator::GetImage(
|
||||
FRDGBuilder& GraphBuilder,
|
||||
const FViewInfo& ViewInfo,
|
||||
FVariableRateShadingImageManager::EVRSImageType ImageType)
|
||||
#endif
|
||||
{
|
||||
if (!FoveationSwapchain.IsValid())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FTextureRHIRef SwapchainTexture = FoveationSwapchain->GetTexture2DArray() ? FoveationSwapchain->GetTexture2DArray() : FoveationSwapchain->GetTexture2D();
|
||||
FIntPoint TexSize = SwapchainTexture->GetSizeXY();
|
||||
// Only set texture and return true if we have a valid texture of compatible size
|
||||
if (SwapchainTexture->IsValid() && TexSize.X > 0 && TexSize.Y > 0)
|
||||
{
|
||||
TRefCountPtr<IPooledRenderTarget> PooledRenderTarget = CreateRenderTarget(SwapchainTexture, *SwapchainTexture->GetName().ToString());
|
||||
return GraphBuilder.RegisterExternalTexture(PooledRenderTarget, *SwapchainTexture->GetName().ToString(), ERDGTextureFlags::SkipTracking);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if !UE_VERSION_OLDER_THAN(5, 4, 0)
|
||||
bool FOculusXRFoveatedRenderingImageGenerator::IsSupportedByView(const FSceneView& View) const
|
||||
#else
|
||||
bool FOculusXRFoveatedRenderingImageGenerator::IsEnabledForView(const FSceneView& View) const
|
||||
#endif
|
||||
{
|
||||
return View.StereoPass != EStereoscopicPass::eSSP_FULL;
|
||||
}
|
||||
|
||||
#if !UE_VERSION_OLDER_THAN(5, 4, 0)
|
||||
FRDGTextureRef FOculusXRFoveatedRenderingImageGenerator::GetDebugImage(
|
||||
FRDGBuilder& GraphBuilder,
|
||||
const FViewInfo& ViewInfo,
|
||||
FVariableRateShadingImageManager::EVRSImageType ImageType,
|
||||
bool bGetSoftwareImage)
|
||||
|
||||
#else
|
||||
FRDGTextureRef FOculusXRFoveatedRenderingImageGenerator::GetDebugImage(
|
||||
FRDGBuilder& GraphBuilder,
|
||||
const FViewInfo& ViewInfo,
|
||||
FVariableRateShadingImageManager::EVRSImageType ImageType)
|
||||
#endif
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Misc/EngineVersionComparison.h"
|
||||
|
||||
#include "VariableRateShadingImageManager.h"
|
||||
#include "XRSwapchain.h"
|
||||
|
||||
class FOculusXRFoveatedRenderingImageGenerator : public IVariableRateShadingImageGenerator
|
||||
{
|
||||
public:
|
||||
FOculusXRFoveatedRenderingImageGenerator(const FXRSwapChainPtr& Swapchain);
|
||||
virtual ~FOculusXRFoveatedRenderingImageGenerator() override;
|
||||
|
||||
// IVariableRateShadingImageGenerator interface
|
||||
#if !UE_VERSION_OLDER_THAN(5, 4, 0)
|
||||
virtual FRDGTextureRef GetImage(
|
||||
FRDGBuilder& GraphBuilder,
|
||||
const FViewInfo& ViewInfo,
|
||||
FVariableRateShadingImageManager::EVRSImageType ImageType,
|
||||
bool bGetSoftwareImage = false) override;
|
||||
#else
|
||||
virtual FRDGTextureRef GetImage(
|
||||
FRDGBuilder& GraphBuilder,
|
||||
const FViewInfo& ViewInfo,
|
||||
FVariableRateShadingImageManager::EVRSImageType ImageType) override;
|
||||
#endif
|
||||
|
||||
#if !UE_VERSION_OLDER_THAN(5, 4, 0)
|
||||
virtual void PrepareImages(
|
||||
FRDGBuilder& GraphBuilder,
|
||||
const FSceneViewFamily& ViewFamily,
|
||||
const FMinimalSceneTextures& SceneTextures,
|
||||
bool bPrepareHardwareImages,
|
||||
bool bPrepareSoftwareImages) override
|
||||
{
|
||||
return;
|
||||
}
|
||||
#else
|
||||
virtual void PrepareImages(
|
||||
FRDGBuilder& GraphBuilder,
|
||||
const FSceneViewFamily& ViewFamily,
|
||||
const FMinimalSceneTextures& SceneTextures) override
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !UE_VERSION_OLDER_THAN(5, 4, 0)
|
||||
virtual bool IsEnabled() const override
|
||||
{
|
||||
return true;
|
||||
};
|
||||
#endif
|
||||
|
||||
#if !UE_VERSION_OLDER_THAN(5, 4, 0)
|
||||
virtual bool IsSupportedByView(const FSceneView& View) const override;
|
||||
#else
|
||||
virtual bool IsEnabledForView(const FSceneView& View) const override;
|
||||
#endif
|
||||
|
||||
#if !UE_VERSION_OLDER_THAN(5, 4, 0)
|
||||
virtual FRDGTextureRef GetDebugImage(
|
||||
FRDGBuilder& GraphBuilder,
|
||||
const FViewInfo& ViewInfo,
|
||||
FVariableRateShadingImageManager::EVRSImageType ImageType,
|
||||
bool bGetSoftwareImage = false) override;
|
||||
#else
|
||||
virtual FRDGTextureRef GetDebugImage(
|
||||
FRDGBuilder& GraphBuilder,
|
||||
const FViewInfo& ViewInfo,
|
||||
FVariableRateShadingImageManager::EVRSImageType ImageType) override;
|
||||
#endif
|
||||
|
||||
virtual FVariableRateShadingImageManager::EVRSSourceType GetType() const override
|
||||
{
|
||||
return FVariableRateShadingImageManager::EVRSSourceType::FixedFoveation;
|
||||
}
|
||||
|
||||
private:
|
||||
const FXRSwapChainPtr& FoveationSwapchain;
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "OculusXRHMD_GameFrame.h"
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
#include "GameFramework/WorldSettings.h"
|
||||
#include "Engine/Engine.h"
|
||||
#include "Engine/World.h"
|
||||
|
||||
namespace OculusXRHMD
|
||||
{
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// FGameFrame
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
FGameFrame::FGameFrame()
|
||||
: FrameNumber(0), WorldToMetersScale(100.f), ShowFlags(ESFIM_All0), PlayerOrientation(FQuat::Identity), PlayerLocation(FVector::ZeroVector), FoveatedRenderingMethod(EOculusXRFoveatedRenderingMethod::FixedFoveatedRendering), FoveatedRenderingLevel(EOculusXRFoveatedRenderingLevel::Off), bDynamicFoveatedRendering(false)
|
||||
{
|
||||
Flags.Raw = 0;
|
||||
Fov[0] = Fov[1] = SymmetricFov[0] = SymmetricFov[1] = ovrpFovf{ 0, 0, 0, 0 };
|
||||
}
|
||||
|
||||
TSharedPtr<FGameFrame, ESPMode::ThreadSafe> FGameFrame::Clone() const
|
||||
{
|
||||
TSharedPtr<FGameFrame, ESPMode::ThreadSafe> NewFrame = MakeShareable(new FGameFrame(*this));
|
||||
return NewFrame;
|
||||
}
|
||||
|
||||
} // namespace OculusXRHMD
|
||||
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
@@ -0,0 +1,65 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
#include "OculusXRHMDPrivate.h"
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
#include "OculusXRHMD_Settings.h"
|
||||
#include "ShowFlags.h"
|
||||
|
||||
namespace OculusXRHMD
|
||||
{
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// FGameFrame
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
class FGameFrame : public TSharedFromThis<FGameFrame, ESPMode::ThreadSafe>
|
||||
{
|
||||
public:
|
||||
uint32 FrameNumber; // current frame number. (StartGameFrame_GameThread)
|
||||
float WorldToMetersScale; // World units (UU) to Meters scale. (OnStartGameFrame)
|
||||
FIntPoint WindowSize; // actual window size (StartGameFrame_GameThread)
|
||||
FEngineShowFlags ShowFlags; // (PreRenderViewFamily_RenderThread)
|
||||
|
||||
FQuat HeadOrientation; // (CalculateStereoViewOffset)
|
||||
FQuat PlayerOrientation; // (CalculateStereoViewOffset)
|
||||
FVector PlayerLocation; // (CalculateStereoViewOffset)
|
||||
float NearClippingPlane; // (GetStereoProjectionMatrix)
|
||||
|
||||
FTransform TrackingToWorld; // (OnEndGameFrame)
|
||||
FTransform LastTrackingToWorld; // (OnEndGameFrame)
|
||||
|
||||
EOculusXRFoveatedRenderingMethod FoveatedRenderingMethod; // OnStartGameFrame
|
||||
EOculusXRFoveatedRenderingLevel FoveatedRenderingLevel; // OnStartGameFrame
|
||||
bool bDynamicFoveatedRendering; // OnStartGameFrame
|
||||
|
||||
ovrpFovf Fov[ovrpEye_Count]; // UpdateStereoRenderingParams
|
||||
ovrpFovf SymmetricFov[ovrpEye_Count]; // UpdateStereoRenderingParams, symmetric FOV if frame is using symmetricFOV.
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** True, if splash is shown */
|
||||
uint64 bSplashIsShown : 1;
|
||||
/** True, if spectator screen is active */
|
||||
uint64 bSpectatorScreenActive : 1;
|
||||
/** True if the frame's positions have been updated on the render thread */
|
||||
uint64 bRTLateUpdateDone : 1;
|
||||
};
|
||||
uint64 Raw;
|
||||
} Flags;
|
||||
|
||||
public:
|
||||
FGameFrame();
|
||||
|
||||
TSharedPtr<FGameFrame, ESPMode::ThreadSafe> Clone() const;
|
||||
};
|
||||
|
||||
typedef TSharedPtr<FGameFrame, ESPMode::ThreadSafe> FGameFramePtr;
|
||||
|
||||
} // namespace OculusXRHMD
|
||||
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
1539
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Layer.cpp
Normal file
1539
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Layer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
234
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Layer.h
Normal file
234
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Layer.h
Normal file
@@ -0,0 +1,234 @@
|
||||
// @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<FOvrpLayer, ESPMode::ThreadSafe>
|
||||
{
|
||||
public:
|
||||
FOvrpLayer(uint32 InOvrpLayerId, FDeferredDeletionQueue* InDeferredDeletion);
|
||||
~FOvrpLayer();
|
||||
|
||||
protected:
|
||||
uint32 OvrpLayerId;
|
||||
|
||||
private:
|
||||
FDeferredDeletionQueue* DeferredDeletion; // necessary for deferred deletion queue of the actual OvrpLayer
|
||||
};
|
||||
|
||||
typedef TSharedPtr<FOvrpLayer, ESPMode::ThreadSafe> FOvrpLayerPtr;
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// FLayer
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
class FLayer : public TSharedFromThis<FLayer, ESPMode::ThreadSafe>
|
||||
{
|
||||
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, bool bInSubmitSpaceWarp);
|
||||
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<FVector>& Vertices, TArray<int32>& Triangles, TArray<FVector2D>& UV0);
|
||||
bool NeedsPassthroughPokeAHole();
|
||||
|
||||
bool ShapeNeedsTextures(ovrpShape shape);
|
||||
|
||||
FTextureRHIRef GetTexture() { return Desc.Texture; }
|
||||
|
||||
TSharedPtr<FLayer, ESPMode::ThreadSafe> 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<FVector>& Vertices, const TArray<int32>& 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<TMap<FString, FPassthroughMesh>, 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<TMap<FString, FPassthroughPokeActor>, 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;
|
||||
bool bSubmitSpaceWarp;
|
||||
|
||||
UProceduralMeshComponent* PokeAHoleComponentPtr;
|
||||
AActor* PokeAHoleActor;
|
||||
|
||||
FUserDefinedGeometryMapPtr UserDefinedGeometryMap;
|
||||
FPassthroughPokeActorMapPtr PassthroughPokeActorMap;
|
||||
};
|
||||
|
||||
typedef TSharedPtr<FLayer, ESPMode::ThreadSafe> 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<FReconstructedLayer>())
|
||||
{
|
||||
const FReconstructedLayer& ReconstructedLayerProps = A->GetDesc().GetShape<FReconstructedLayer>();
|
||||
IsUnderlay = (ReconstructedLayerProps.PassthroughLayerOrder == PassthroughLayerOrder_Underlay);
|
||||
}
|
||||
else if (A->GetDesc().HasShape<FUserDefinedLayer>())
|
||||
{
|
||||
const FUserDefinedLayer& UserDefinedLayerProps = A->GetDesc().GetShape<FUserDefinedLayer>();
|
||||
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
|
||||
@@ -0,0 +1,151 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "OculusXRHMD_Settings.h"
|
||||
#include "Engine/Engine.h"
|
||||
#include "OculusXRHMDTypes.h"
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
|
||||
namespace OculusXRHMD
|
||||
{
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// FSettings
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
FSettings::FSettings()
|
||||
: BaseOffset(0, 0, 0)
|
||||
, BaseOrientation(FQuat::Identity)
|
||||
, PixelDensity(1.0f)
|
||||
, SystemHeadset(ovrpSystemHeadset_None)
|
||||
, SuggestedCpuPerfLevel(EOculusXRProcessorPerformanceLevel::SustainedLow)
|
||||
, SuggestedGpuPerfLevel(EOculusXRProcessorPerformanceLevel::SustainedHigh)
|
||||
, FoveatedRenderingMethod(EOculusXRFoveatedRenderingMethod::FixedFoveatedRendering)
|
||||
, FoveatedRenderingLevel(EOculusXRFoveatedRenderingLevel::Off)
|
||||
, bDynamicFoveatedRendering(true)
|
||||
, bSupportEyeTrackedFoveatedRendering(false)
|
||||
, SystemSplashBackground(ESystemSplashBackgroundType::Black)
|
||||
, XrApi(EOculusXRXrApi::OVRPluginOpenXR)
|
||||
, ColorSpace(EOculusXRColorSpace::P3)
|
||||
, ControllerPoseAlignment(EOculusXRControllerPoseAlignment::Default)
|
||||
, HandTrackingSupport(EOculusXRHandTrackingSupport::ControllersOnly)
|
||||
, HandTrackingFrequency(EOculusXRHandTrackingFrequency::LOW)
|
||||
, HandTrackingVersion(EOculusXRHandTrackingVersion::Default)
|
||||
, ColorScale(ovrpVector4f{ 1, 1, 1, 1 })
|
||||
, ColorOffset(ovrpVector4f{ 0, 0, 0, 0 })
|
||||
, bApplyColorScaleAndOffsetToAllLayers(false)
|
||||
, CurrentFeatureLevel(GMaxRHIFeatureLevel)
|
||||
, bLateLatching(false)
|
||||
, bSupportExperimentalFeatures(false)
|
||||
, ProcessorFavor(EProcessorFavor::FavorEqually)
|
||||
, BodyTrackingFidelity(EOculusXRHMDBodyTrackingFidelity::Low)
|
||||
, BodyTrackingJointSet(EOculusXRHMDBodyJointSet::UpperBody)
|
||||
, FaceTrackingDataSource()
|
||||
, bFaceTrackingVisemesEnabled(false)
|
||||
, MPPoseRestoreType(EOculusXRMPPoseRestoreType::Disabled)
|
||||
{
|
||||
Flags.Raw = 0;
|
||||
Flags.bHMDEnabled = true;
|
||||
Flags.bUpdateOnRT = true;
|
||||
Flags.bHQBuffer = false;
|
||||
Flags.bCompositeDepth = true;
|
||||
#if PLATFORM_ANDROID
|
||||
Flags.bsRGBEyeBuffer = true;
|
||||
// oculus mobile is always-on stereo, no need for enableStereo codepaths
|
||||
Flags.bStereoEnabled = true;
|
||||
#else
|
||||
Flags.bsRGBEyeBuffer = false;
|
||||
Flags.bStereoEnabled = false;
|
||||
#endif
|
||||
CurrentFeatureLevel = GEngine ? GEngine->GetDefaultWorldFeatureLevel() : GMaxRHIFeatureLevel;
|
||||
CurrentShaderPlatform = GShaderPlatformForFeatureLevel[CurrentFeatureLevel];
|
||||
|
||||
Flags.bSupportsDash = true;
|
||||
Flags.bFocusAware = true;
|
||||
Flags.bRequiresSystemKeyboard = false;
|
||||
Flags.bInsightPassthroughEnabled = false;
|
||||
Flags.bAnchorSupportEnabled = false;
|
||||
Flags.bAnchorSharingEnabled = false;
|
||||
Flags.bSceneSupportEnabled = false;
|
||||
Flags.bBoundaryVisibilitySupportEnabled = false;
|
||||
Flags.bDefaultBoundaryVisibilitySuppressed = false;
|
||||
Flags.bColocationSessionsEnabled = false;
|
||||
Flags.bBodyTrackingEnabled = false;
|
||||
Flags.bEyeTrackingEnabled = false;
|
||||
Flags.bFaceTrackingEnabled = false;
|
||||
EyeRenderViewport[0] = EyeRenderViewport[1] = FIntRect(0, 0, 0, 0);
|
||||
|
||||
RenderTargetSize = FIntPoint(0, 0);
|
||||
|
||||
Flags.bIterativeCookOnTheFly = false;
|
||||
Flags.bSupportSBC = false;
|
||||
// Note: SBCPath should be consistent as other project saved path, e.g. /sdcard/Android/data/[packagename]/files/UnrealGame/[ProjectName]/[ProjectName]/Saved/Profiling/CSV/
|
||||
FString ProjectName = !FApp::IsProjectNameEmpty() ? FApp::GetProjectName() : FPlatformProcess::ExecutableName();
|
||||
SBCPath = FString("files/UnrealGame/") + ProjectName + FString("/") + ProjectName + FString("/Saved/VulkanCache");
|
||||
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
Flags.bTileTurnOffEnabled = false;
|
||||
|
||||
Flags.bSetActivePIEToPrimary = true;
|
||||
Flags.bSetCVarPIEToPrimary = true;
|
||||
Flags.bUpdateHeadPoseForInactivePlayer = false;
|
||||
#else
|
||||
Flags.bTileTurnOffEnabled = true;
|
||||
|
||||
// Vanilla UE doesn't support MultiPlayerTesting well, disable it for now.
|
||||
Flags.bSetActivePIEToPrimary = false;
|
||||
Flags.bSetCVarPIEToPrimary = false;
|
||||
Flags.bUpdateHeadPoseForInactivePlayer = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
TSharedPtr<FSettings, ESPMode::ThreadSafe> FSettings::Clone() const
|
||||
{
|
||||
TSharedPtr<FSettings, ESPMode::ThreadSafe> NewSettings = MakeShareable(new FSettings(*this));
|
||||
return NewSettings;
|
||||
}
|
||||
|
||||
float FSettings::GetPixelDensityMin() const
|
||||
{
|
||||
static const IConsoleVariable* CVarPixelDensityMin = IConsoleManager::Get().FindConsoleVariable(VAR_PixelDensityMin);
|
||||
return CVarPixelDensityMin ? CVarPixelDensityMin->GetFloat() : 0.8f;
|
||||
}
|
||||
float FSettings::GetPixelDensityMax() const
|
||||
{
|
||||
static const IConsoleVariable* CVarPixelDensityMax = IConsoleManager::Get().FindConsoleVariable(VAR_PixelDensityMax);
|
||||
return CVarPixelDensityMax ? CVarPixelDensityMax->GetFloat() : 1.2f;
|
||||
}
|
||||
void FSettings::SetPixelDensity(float NewPixelDensity)
|
||||
{
|
||||
if (Flags.bPixelDensityAdaptive)
|
||||
{
|
||||
PixelDensity = FMath::Clamp(NewPixelDensity, GetPixelDensityMin(), GetPixelDensityMax());
|
||||
}
|
||||
else
|
||||
{
|
||||
PixelDensity = FMath::Clamp(NewPixelDensity, ClampPixelDensityMin, ClampPixelDensityMax);
|
||||
}
|
||||
}
|
||||
|
||||
void FSettings::SetPixelDensitySmooth(float NewPixelDensity)
|
||||
{
|
||||
// Pixel Density changes need to be smooth both for artifacts with FFR/TTO (FFR/tile-turnoff is one frame late so shouldn't change too fast)
|
||||
// but also so that if the developer uses the CVar and not the runtime (which is already smooth) there is no jump artifacts.
|
||||
constexpr float MaxPerFrameIncrease = 0.010;
|
||||
constexpr float MaxPerFrameDecrease = 0.045;
|
||||
|
||||
float NewClampedPixelDensity = FMath::Clamp(NewPixelDensity, PixelDensity - MaxPerFrameDecrease, PixelDensity + MaxPerFrameIncrease);
|
||||
if (Flags.bPixelDensityAdaptive)
|
||||
{
|
||||
PixelDensity = FMath::Clamp(NewClampedPixelDensity, GetPixelDensityMin(), GetPixelDensityMax());
|
||||
}
|
||||
else
|
||||
{
|
||||
PixelDensity = FMath::Clamp(NewClampedPixelDensity, ClampPixelDensityMin, ClampPixelDensityMax);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace OculusXRHMD
|
||||
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
201
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Settings.h
Normal file
201
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Settings.h
Normal file
@@ -0,0 +1,201 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
#include "OculusXRHMDPrivate.h"
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
|
||||
namespace OculusXRHMD
|
||||
{
|
||||
|
||||
static const float ClampPixelDensityMin = 0.5f;
|
||||
static const float ClampPixelDensityMax = 2.0f;
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// FSettings
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
class FSettings : public TSharedFromThis<FSettings, ESPMode::ThreadSafe>
|
||||
{
|
||||
public:
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** Whether stereo is currently on or off. */
|
||||
uint64 bStereoEnabled : 1;
|
||||
|
||||
/** Whether or not switching to stereo is allowed */
|
||||
uint64 bHMDEnabled : 1;
|
||||
|
||||
/** Turns on/off updating view's orientation/position on a RenderThread. When it is on,
|
||||
latency should be significantly lower.
|
||||
See 'HMD UPDATEONRT ON|OFF' console command.
|
||||
*/
|
||||
uint64 bUpdateOnRT : 1;
|
||||
|
||||
/** Enforces headtracking to work even in non-stereo mode (for debugging or screenshots).
|
||||
See 'MOTION ENFORCE' console command. */
|
||||
uint64 bHeadTrackingEnforced : 1;
|
||||
|
||||
/** Allocate an high quality OVR_FORMAT_R11G11B10_FLOAT buffer for Rift */
|
||||
uint64 bHQBuffer : 1;
|
||||
|
||||
/** Rendering should be (could be) paused */
|
||||
uint64 bPauseRendering : 1;
|
||||
|
||||
/** HQ Distortion */
|
||||
uint64 bHQDistortion : 1;
|
||||
|
||||
/** Send the depth buffer to the compositor */
|
||||
uint64 bCompositeDepth : 1;
|
||||
|
||||
/** Supports Dash in-game compositing */
|
||||
uint64 bSupportsDash : 1;
|
||||
#if !UE_BUILD_SHIPPING
|
||||
/** Show status / statistics on screen. See 'hmd stats' cmd */
|
||||
uint64 bShowStats : 1;
|
||||
#endif
|
||||
/** Dynamically update pixel density to maintain framerate */
|
||||
uint64 bPixelDensityAdaptive : 1;
|
||||
|
||||
/** All future eye buffers will need to be created with TexSRGB_Create flag due to the current feature level (ES31) */
|
||||
uint64 bsRGBEyeBuffer : 1;
|
||||
|
||||
/** Supports Focus Aware state on Quest */
|
||||
uint64 bFocusAware : 1;
|
||||
|
||||
/** Requires the Oculus system keyboard */
|
||||
uint64 bRequiresSystemKeyboard : 1;
|
||||
|
||||
/** Whether passthrough functionality can be used with the app */
|
||||
uint64 bInsightPassthroughEnabled : 1;
|
||||
|
||||
/** Whether Anchors can be used with the app */
|
||||
uint64 bAnchorSupportEnabled : 1;
|
||||
|
||||
/** Whether Anchor Sharing can be used with the app */
|
||||
uint64 bAnchorSharingEnabled : 1;
|
||||
|
||||
/** Whether Scene can be used with the app */
|
||||
uint64 bSceneSupportEnabled : 1;
|
||||
|
||||
/** Whether the guardian boundary visibility toggles can be used with the app */
|
||||
uint64 bBoundaryVisibilitySupportEnabled : 1;
|
||||
|
||||
/** Whether the guardian boundary visibility should be suppressed by default, this can only be true if passthrough is enabled */
|
||||
uint64 bDefaultBoundaryVisibilitySuppressed : 1;
|
||||
|
||||
/** Whether Colocation Sessions can be used with the app */
|
||||
uint64 bColocationSessionsEnabled : 1;
|
||||
|
||||
/** Whether body tracking functionality can be used with the app */
|
||||
uint64 bBodyTrackingEnabled : 1;
|
||||
|
||||
/** Whether eye tracking functionality can be used with the app */
|
||||
uint64 bEyeTrackingEnabled : 1;
|
||||
|
||||
/** Whether face tracking functionality can be used with the app */
|
||||
uint64 bFaceTrackingEnabled : 1;
|
||||
|
||||
/** Whether tile turn off can be used with the app */
|
||||
uint64 bTileTurnOffEnabled : 1;
|
||||
|
||||
/** Whether iterative cook-on-the-fly is enabled */
|
||||
uint64 bIterativeCookOnTheFly : 1;
|
||||
|
||||
/** When running multiple player windows in a single process with VRPreview, this option determins whether to set the current active PIE to the primary one on the fly.*/
|
||||
uint64 bSetActivePIEToPrimary : 1;
|
||||
|
||||
/** When running multiple player windows in a single process with VRPreview, this option determins whether to set the PIE specified by CVar vr.PrimaryPIEIndex to the primary one on the fly.*/
|
||||
uint64 bSetCVarPIEToPrimary : 1;
|
||||
|
||||
/* In case of multiple players testing, when the current player is inactive, disabling this setting will make sure the current player does NOT update headpose until it is active again.*/
|
||||
uint64 bUpdateHeadPoseForInactivePlayer : 1;
|
||||
|
||||
/* Enable Shader Binary Cache (SBC) and setup its path */
|
||||
uint64 bSupportSBC : 1;
|
||||
};
|
||||
uint64 Raw;
|
||||
} Flags;
|
||||
|
||||
/** HMD base values, specify forward orientation and zero pos offset */
|
||||
FVector BaseOffset; // base position, in meters, relatively to the sensor //@todo hmd: clients need to stop using oculus space
|
||||
FQuat BaseOrientation; // base orientation
|
||||
|
||||
/** Viewports for each eye, in render target texture coordinates */
|
||||
FIntRect EyeRenderViewport[ovrpEye_Count];
|
||||
/** Viewports for each eye, without DynamicResolution scaling applied */
|
||||
FIntRect EyeUnscaledRenderViewport[ovrpEye_Count];
|
||||
|
||||
ovrpMatrix4f EyeProjectionMatrices[ovrpEye_Count]; // 0 - left, 1 - right same as Views
|
||||
ovrpMatrix4f MonoProjectionMatrix;
|
||||
|
||||
FIntPoint RenderTargetSize;
|
||||
float PixelDensity;
|
||||
|
||||
ovrpSystemHeadset SystemHeadset;
|
||||
|
||||
float VsyncToNextVsync;
|
||||
|
||||
EOculusXRProcessorPerformanceLevel SuggestedCpuPerfLevel;
|
||||
EOculusXRProcessorPerformanceLevel SuggestedGpuPerfLevel;
|
||||
|
||||
EOculusXRFoveatedRenderingMethod FoveatedRenderingMethod;
|
||||
EOculusXRFoveatedRenderingLevel FoveatedRenderingLevel;
|
||||
bool bDynamicFoveatedRendering;
|
||||
bool bSupportEyeTrackedFoveatedRendering;
|
||||
|
||||
ESystemSplashBackgroundType SystemSplashBackground;
|
||||
|
||||
EOculusXRXrApi XrApi;
|
||||
EOculusXRColorSpace ColorSpace;
|
||||
EOculusXRControllerPoseAlignment ControllerPoseAlignment;
|
||||
|
||||
EOculusXRHandTrackingSupport HandTrackingSupport;
|
||||
EOculusXRHandTrackingFrequency HandTrackingFrequency;
|
||||
EOculusXRHandTrackingVersion HandTrackingVersion;
|
||||
|
||||
ovrpVector4f ColorScale, ColorOffset;
|
||||
bool bApplyColorScaleAndOffsetToAllLayers;
|
||||
|
||||
FStaticFeatureLevel CurrentFeatureLevel;
|
||||
EShaderPlatform CurrentShaderPlatform;
|
||||
|
||||
bool bLateLatching;
|
||||
bool bSupportExperimentalFeatures;
|
||||
|
||||
EProcessorFavor ProcessorFavor;
|
||||
|
||||
EOculusXRHMDBodyTrackingFidelity BodyTrackingFidelity;
|
||||
EOculusXRHMDBodyJointSet BodyTrackingJointSet;
|
||||
|
||||
TSet<EFaceTrackingDataSourceConfig> FaceTrackingDataSource;
|
||||
bool bFaceTrackingVisemesEnabled;
|
||||
|
||||
bool bIterativeCookOnTheFly;
|
||||
|
||||
EOculusXRMPPoseRestoreType MPPoseRestoreType;
|
||||
|
||||
FString SBCPath;
|
||||
|
||||
public:
|
||||
FSettings();
|
||||
virtual ~FSettings() {}
|
||||
|
||||
bool IsStereoEnabled() const { return Flags.bStereoEnabled && Flags.bHMDEnabled; }
|
||||
|
||||
float GetPixelDensityMin() const;
|
||||
float GetPixelDensityMax() const;
|
||||
void SetPixelDensity(float NewPixelDensity);
|
||||
void SetPixelDensitySmooth(float NewPixelDensity);
|
||||
|
||||
TSharedPtr<FSettings, ESPMode::ThreadSafe> Clone() const;
|
||||
};
|
||||
|
||||
typedef TSharedPtr<FSettings, ESPMode::ThreadSafe> FSettingsPtr;
|
||||
|
||||
} // namespace OculusXRHMD
|
||||
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
@@ -0,0 +1,121 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "OculusXRHMD_SpectatorScreenController.h"
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
#include "OculusXRHMD.h"
|
||||
#include "TextureResource.h"
|
||||
#include "Engine/TextureRenderTarget2D.h"
|
||||
|
||||
namespace OculusXRHMD
|
||||
{
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// FSpectatorScreenController
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
FSpectatorScreenController::FSpectatorScreenController(FOculusXRHMD* InOculusXRHMD)
|
||||
: FDefaultSpectatorScreenController(InOculusXRHMD)
|
||||
, OculusXRHMD(InOculusXRHMD)
|
||||
, SpectatorMode(EMRSpectatorScreenMode::Default)
|
||||
, ForegroundRenderTexture(nullptr)
|
||||
, BackgroundRenderTexture(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
void FSpectatorScreenController::RenderSpectatorScreen_RenderThread(FRHICommandListImmediate& RHICmdList, FRHITexture* BackBuffer, FTextureRHIRef RenderTexture, FVector2D WindowSize)
|
||||
{
|
||||
CheckInRenderThread();
|
||||
if (OculusXRHMD->GetCustomPresent_Internal())
|
||||
{
|
||||
if (SpectatorMode == EMRSpectatorScreenMode::ExternalComposition)
|
||||
{
|
||||
auto ForegroundResource = ForegroundRenderTexture->GetRenderTargetResource();
|
||||
auto BackgroundResource = BackgroundRenderTexture->GetRenderTargetResource();
|
||||
if (ForegroundResource && BackgroundResource)
|
||||
{
|
||||
RenderSpectatorModeExternalComposition(
|
||||
RHICmdList,
|
||||
FTextureRHIRef(BackBuffer),
|
||||
ForegroundResource->GetRenderTargetTexture(),
|
||||
BackgroundResource->GetRenderTargetTexture());
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (SpectatorMode == EMRSpectatorScreenMode::DirectComposition)
|
||||
{
|
||||
auto BackgroundResource = BackgroundRenderTexture->GetRenderTargetResource();
|
||||
if (BackgroundResource)
|
||||
{
|
||||
RenderSpectatorModeDirectComposition(
|
||||
RHICmdList,
|
||||
FTextureRHIRef(BackBuffer),
|
||||
BackgroundRenderTexture->GetRenderTargetResource()->GetRenderTargetTexture());
|
||||
return;
|
||||
}
|
||||
}
|
||||
FDefaultSpectatorScreenController::RenderSpectatorScreen_RenderThread(RHICmdList, BackBuffer, RenderTexture, WindowSize);
|
||||
}
|
||||
}
|
||||
|
||||
void FSpectatorScreenController::RenderSpectatorModeUndistorted(FRHICommandListImmediate& RHICmdList, FTextureRHIRef TargetTexture, FTextureRHIRef EyeTexture, FTextureRHIRef OtherTexture, FVector2D WindowSize)
|
||||
{
|
||||
CheckInRenderThread();
|
||||
FSettings* Settings = OculusXRHMD->GetSettings_RenderThread();
|
||||
FIntRect DestRect(0, 0, TargetTexture->GetSizeX() / 2, TargetTexture->GetSizeY());
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
OculusXRHMD->CopyTexture_RenderThread(RHICmdList, EyeTexture, Settings->EyeRenderViewport[i], TargetTexture, DestRect, false, true);
|
||||
DestRect.Min.X += TargetTexture->GetSizeX() / 2;
|
||||
DestRect.Max.X += TargetTexture->GetSizeX() / 2;
|
||||
}
|
||||
}
|
||||
|
||||
void FSpectatorScreenController::RenderSpectatorModeDistorted(FRHICommandListImmediate& RHICmdList, FTextureRHIRef TargetTexture, FTextureRHIRef EyeTexture, FTextureRHIRef OtherTexture, FVector2D WindowSize)
|
||||
{
|
||||
CheckInRenderThread();
|
||||
FCustomPresent* CustomPresent = OculusXRHMD->GetCustomPresent_Internal();
|
||||
FTextureRHIRef MirrorTexture = CustomPresent->GetMirrorTexture();
|
||||
if (MirrorTexture)
|
||||
{
|
||||
FIntRect SrcRect(0, 0, MirrorTexture->GetSizeX(), MirrorTexture->GetSizeY());
|
||||
FIntRect DestRect(0, 0, TargetTexture->GetSizeX(), TargetTexture->GetSizeY());
|
||||
OculusXRHMD->CopyTexture_RenderThread(RHICmdList, MirrorTexture, SrcRect, TargetTexture, DestRect, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
void FSpectatorScreenController::RenderSpectatorModeSingleEye(FRHICommandListImmediate& RHICmdList, FTextureRHIRef TargetTexture, FTextureRHIRef EyeTexture, FTextureRHIRef OtherTexture, FVector2D WindowSize)
|
||||
{
|
||||
CheckInRenderThread();
|
||||
FSettings* Settings = OculusXRHMD->GetSettings_RenderThread();
|
||||
const FIntRect SrcRect = Settings->EyeRenderViewport[0];
|
||||
const FIntRect DstRect(0, 0, TargetTexture->GetSizeX(), TargetTexture->GetSizeY());
|
||||
|
||||
OculusXRHMD->CopyTexture_RenderThread(RHICmdList, EyeTexture, SrcRect, TargetTexture, DstRect, false, true);
|
||||
}
|
||||
|
||||
void FSpectatorScreenController::RenderSpectatorModeDirectComposition(FRHICommandListImmediate& RHICmdList, FTextureRHIRef TargetTexture, const FTextureRHIRef SrcTexture) const
|
||||
{
|
||||
CheckInRenderThread();
|
||||
const FIntRect SrcRect(0, 0, SrcTexture->GetSizeX(), SrcTexture->GetSizeY());
|
||||
const FIntRect DstRect(0, 0, TargetTexture->GetSizeX(), TargetTexture->GetSizeY());
|
||||
|
||||
OculusXRHMD->CopyTexture_RenderThread(RHICmdList, SrcTexture, SrcRect, TargetTexture, DstRect, false, true);
|
||||
}
|
||||
|
||||
void FSpectatorScreenController::RenderSpectatorModeExternalComposition(FRHICommandListImmediate& RHICmdList, FTextureRHIRef TargetTexture, const FTextureRHIRef FrontTexture, const FTextureRHIRef BackTexture) const
|
||||
{
|
||||
CheckInRenderThread();
|
||||
const FIntRect FrontSrcRect(0, 0, FrontTexture->GetSizeX(), FrontTexture->GetSizeY());
|
||||
const FIntRect FrontDstRect(0, 0, TargetTexture->GetSizeX() / 2, TargetTexture->GetSizeY());
|
||||
const FIntRect BackSrcRect(0, 0, BackTexture->GetSizeX(), BackTexture->GetSizeY());
|
||||
const FIntRect BackDstRect(TargetTexture->GetSizeX() / 2, 0, TargetTexture->GetSizeX(), TargetTexture->GetSizeY());
|
||||
|
||||
OculusXRHMD->CopyTexture_RenderThread(RHICmdList, FrontTexture, FrontSrcRect, TargetTexture, FrontDstRect, false, true);
|
||||
OculusXRHMD->CopyTexture_RenderThread(RHICmdList, BackTexture, BackSrcRect, TargetTexture, BackDstRect, false, true);
|
||||
}
|
||||
|
||||
} // namespace OculusXRHMD
|
||||
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
@@ -0,0 +1,53 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
#include "OculusXRHMDPrivate.h"
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
#include "DefaultSpectatorScreenController.h"
|
||||
|
||||
class UTextureRenderTarget2D;
|
||||
|
||||
namespace OculusXRHMD
|
||||
{
|
||||
|
||||
// Oculus specific spectator screen modes that override the regular VR spectator screens
|
||||
enum class EMRSpectatorScreenMode : uint8
|
||||
{
|
||||
Default,
|
||||
ExternalComposition,
|
||||
DirectComposition
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// FSpectatorScreenController
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
class FSpectatorScreenController : public FDefaultSpectatorScreenController
|
||||
{
|
||||
public:
|
||||
FSpectatorScreenController(class FOculusXRHMD* InOculusXRHMD);
|
||||
|
||||
void SetMRSpectatorScreenMode(EMRSpectatorScreenMode Mode) { SpectatorMode = Mode; }
|
||||
void SetMRForeground(UTextureRenderTarget2D* Texture) { ForegroundRenderTexture = Texture; }
|
||||
void SetMRBackground(UTextureRenderTarget2D* Texture) { BackgroundRenderTexture = Texture; }
|
||||
|
||||
virtual void RenderSpectatorScreen_RenderThread(FRHICommandListImmediate& RHICmdList, FRHITexture* BackBuffer, FTextureRHIRef RenderTarget, FVector2D WindowSize) override;
|
||||
virtual void RenderSpectatorModeUndistorted(FRHICommandListImmediate& RHICmdList, FTextureRHIRef TargetTexture, FTextureRHIRef EyeTexture, FTextureRHIRef OtherTexture, FVector2D WindowSize) override;
|
||||
virtual void RenderSpectatorModeDistorted(FRHICommandListImmediate& RHICmdList, FTextureRHIRef TargetTexture, FTextureRHIRef EyeTexture, FTextureRHIRef OtherTexture, FVector2D WindowSize) override;
|
||||
virtual void RenderSpectatorModeSingleEye(FRHICommandListImmediate& RHICmdList, FTextureRHIRef TargetTexture, FTextureRHIRef EyeTexture, FTextureRHIRef OtherTexture, FVector2D WindowSize) override;
|
||||
|
||||
private:
|
||||
FOculusXRHMD* OculusXRHMD;
|
||||
EMRSpectatorScreenMode SpectatorMode;
|
||||
UTextureRenderTarget2D* ForegroundRenderTexture;
|
||||
UTextureRenderTarget2D* BackgroundRenderTexture;
|
||||
|
||||
void RenderSpectatorModeDirectComposition(FRHICommandListImmediate& RHICmdList, FTextureRHIRef TargetTexture, const FTextureRHIRef SrcTexture) const;
|
||||
void RenderSpectatorModeExternalComposition(FRHICommandListImmediate& RHICmdList, FTextureRHIRef TargetTexture, const FTextureRHIRef FrontTexture, const FTextureRHIRef BackTexture) const;
|
||||
};
|
||||
|
||||
} // namespace OculusXRHMD
|
||||
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
667
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Splash.cpp
Normal file
667
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Splash.cpp
Normal file
@@ -0,0 +1,667 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "OculusXRHMD_Splash.h"
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
#include "OculusXRHMD.h"
|
||||
#include "RenderingThread.h"
|
||||
#include "Misc/ScopeLock.h"
|
||||
#include "OculusXRHMDRuntimeSettings.h"
|
||||
#include "TextureResource.h"
|
||||
|
||||
#if PLATFORM_ANDROID
|
||||
#include "Android/AndroidJNI.h"
|
||||
#include "Android/AndroidApplication.h"
|
||||
#include "OculusXRHMDTypes.h"
|
||||
#endif
|
||||
|
||||
namespace OculusXRHMD
|
||||
{
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// FSplash
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
FSplash::FSplash(FOculusXRHMD* InOculusXRHMD)
|
||||
: OculusXRHMD(InOculusXRHMD), CustomPresent(InOculusXRHMD->GetCustomPresent_Internal()), FramesOutstanding(0), NextLayerId(1), bInitialized(false), bIsShown(false), bNeedSplashUpdate(false), bShouldShowSplash(false), SystemDisplayInterval(1 / 90.0f)
|
||||
{
|
||||
// Create empty quad layer for UE layer
|
||||
{
|
||||
IStereoLayers::FLayerDesc LayerDesc;
|
||||
LayerDesc.QuadSize = FVector2D(0.01f, 0.01f);
|
||||
LayerDesc.Priority = 0;
|
||||
LayerDesc.PositionType = IStereoLayers::TrackerLocked;
|
||||
LayerDesc.Texture = nullptr;
|
||||
UELayer = MakeShareable(new FLayer(NextLayerId++));
|
||||
UELayer->SetDesc(LayerDesc);
|
||||
}
|
||||
}
|
||||
|
||||
FSplash::~FSplash()
|
||||
{
|
||||
// Make sure RenTicker is freed in Shutdown
|
||||
check(!Ticker.IsValid())
|
||||
}
|
||||
|
||||
void FSplash::Tick_RenderThread(float DeltaTime)
|
||||
{
|
||||
CheckInRenderThread();
|
||||
|
||||
if (FramesOutstanding > 0)
|
||||
{
|
||||
UE_LOG(LogHMD, VeryVerbose, TEXT("Splash skipping frame; too many frames outstanding"));
|
||||
return;
|
||||
}
|
||||
|
||||
const double TimeInSeconds = FPlatformTime::Seconds();
|
||||
const double DeltaTimeInSeconds = TimeInSeconds - LastTimeInSeconds;
|
||||
|
||||
if (DeltaTimeInSeconds > 2.f * SystemDisplayInterval && Layers_RenderThread_DeltaRotation.Num() > 0)
|
||||
{
|
||||
FScopeLock ScopeLock(&RenderThreadLock);
|
||||
for (TTuple<FLayerPtr, FQuat>& Info : Layers_RenderThread_DeltaRotation)
|
||||
{
|
||||
FLayerPtr Layer = Info.Key;
|
||||
const FQuat& DeltaRotation = Info.Value;
|
||||
check(Layer.IsValid());
|
||||
check(!DeltaRotation.Equals(FQuat::Identity)); // Only layers with non-zero delta rotation should be in the DeltaRotation array.
|
||||
|
||||
IStereoLayers::FLayerDesc LayerDesc = Layer->GetDesc();
|
||||
LayerDesc.Transform.SetRotation(LayerDesc.Transform.GetRotation() * DeltaRotation);
|
||||
LayerDesc.Transform.NormalizeRotation();
|
||||
Layer->SetDesc(LayerDesc);
|
||||
}
|
||||
LastTimeInSeconds = TimeInSeconds;
|
||||
}
|
||||
|
||||
RenderFrame_RenderThread(FRHICommandListExecutor::GetImmediateCommandList());
|
||||
}
|
||||
|
||||
void FSplash::LoadSettings()
|
||||
{
|
||||
UOculusXRHMDRuntimeSettings* HMDSettings = GetMutableDefault<UOculusXRHMDRuntimeSettings>();
|
||||
check(HMDSettings);
|
||||
ClearSplashes();
|
||||
for (const FOculusXRSplashDesc& SplashDesc : HMDSettings->SplashDescs)
|
||||
{
|
||||
AddSplash(SplashDesc);
|
||||
}
|
||||
|
||||
if (HMDSettings->bAutoEnabled)
|
||||
{
|
||||
if (!PreLoadLevelDelegate.IsValid())
|
||||
{
|
||||
PreLoadLevelDelegate = FCoreUObjectDelegates::PreLoadMap.AddSP(this, &FSplash::OnPreLoadMap);
|
||||
}
|
||||
if (!PostLoadLevelDelegate.IsValid())
|
||||
{
|
||||
PostLoadLevelDelegate = FCoreUObjectDelegates::PostLoadMapWithWorld.AddSP(this, &FSplash::OnPostLoadMap);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PreLoadLevelDelegate.IsValid())
|
||||
{
|
||||
FCoreUObjectDelegates::PreLoadMap.Remove(PreLoadLevelDelegate);
|
||||
PreLoadLevelDelegate.Reset();
|
||||
}
|
||||
if (PostLoadLevelDelegate.IsValid())
|
||||
{
|
||||
FCoreUObjectDelegates::PostLoadMapWithWorld.Remove(PostLoadLevelDelegate);
|
||||
PostLoadLevelDelegate.Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FSplash::OnPreLoadMap(const FString&)
|
||||
{
|
||||
DoShow();
|
||||
}
|
||||
|
||||
void FSplash::OnPostLoadMap(UWorld* LoadedWorld)
|
||||
{
|
||||
// Don't auto-hide splash if show loading screen is called explicitly
|
||||
if (!bShouldShowSplash)
|
||||
{
|
||||
UE_LOG(LogHMD, Log, TEXT("FSplash::OnPostLoadMap Hide Auto Splash"));
|
||||
HideLoadingScreen();
|
||||
}
|
||||
}
|
||||
|
||||
#if WITH_EDITOR
|
||||
void FSplash::OnPieBegin(bool bIsSimulating)
|
||||
{
|
||||
LoadSettings();
|
||||
}
|
||||
#endif
|
||||
|
||||
void FSplash::Startup()
|
||||
{
|
||||
CheckInGameThread();
|
||||
|
||||
if (!bInitialized)
|
||||
{
|
||||
Settings = OculusXRHMD->CreateNewSettings();
|
||||
Frame = OculusXRHMD->CreateNewGameFrame();
|
||||
// keep units in meters rather than UU (because UU make not much sense).
|
||||
Frame->WorldToMetersScale = 1.0f;
|
||||
|
||||
float SystemDisplayFrequency;
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetSystemDisplayFrequency2(&SystemDisplayFrequency)))
|
||||
{
|
||||
SystemDisplayInterval = 1.0f / SystemDisplayFrequency;
|
||||
}
|
||||
|
||||
LoadSettings();
|
||||
|
||||
OculusXRHMD->InitDevice();
|
||||
|
||||
#if WITH_EDITOR
|
||||
PieBeginDelegateHandle = FEditorDelegates::BeginPIE.AddRaw(this, &FSplash::OnPieBegin);
|
||||
#else
|
||||
UOculusXRHMDRuntimeSettings* HMDSettings = GetMutableDefault<UOculusXRHMDRuntimeSettings>();
|
||||
check(HMDSettings);
|
||||
if (HMDSettings->bAutoEnabled)
|
||||
{
|
||||
UE_LOG(LogHMD, Log, TEXT("FSplash::Startup Show Splash on Startup"));
|
||||
DoShow();
|
||||
}
|
||||
#endif
|
||||
|
||||
OculusXRHMD->Settings_RenderThread = OculusXRHMD->Settings->Clone();
|
||||
|
||||
bInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
void FSplash::StopTicker()
|
||||
{
|
||||
CheckInGameThread();
|
||||
|
||||
if (!bIsShown)
|
||||
{
|
||||
ExecuteOnRenderThread([this]() {
|
||||
if (Ticker.IsValid())
|
||||
{
|
||||
Ticker->Unregister();
|
||||
Ticker = nullptr;
|
||||
}
|
||||
});
|
||||
UnloadTextures();
|
||||
}
|
||||
}
|
||||
|
||||
void FSplash::StartTicker()
|
||||
{
|
||||
CheckInGameThread();
|
||||
|
||||
if (!Ticker.IsValid())
|
||||
{
|
||||
Ticker = MakeShareable(new FTicker(this));
|
||||
|
||||
ExecuteOnRenderThread([this]() {
|
||||
LastTimeInSeconds = FPlatformTime::Seconds();
|
||||
Ticker->Register();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void FSplash::RenderFrame_RenderThread(FRHICommandListImmediate& RHICmdList)
|
||||
{
|
||||
CheckInRenderThread();
|
||||
|
||||
FScopeLock ScopeLock(&RenderThreadLock);
|
||||
|
||||
// RenderFrame
|
||||
FSettingsPtr XSettings = Settings->Clone();
|
||||
FGameFramePtr XFrame = Frame->Clone();
|
||||
XFrame->FrameNumber = OculusXRHMD->NextFrameNumber;
|
||||
XFrame->ShowFlags.Rendering = true;
|
||||
TArray<FLayerPtr> XLayers = Layers_RenderThread_Input;
|
||||
|
||||
ensure(XLayers.Num() != 0);
|
||||
|
||||
ovrpResult Result;
|
||||
if (FOculusXRHMDModule::GetPluginWrapper().GetInitialized() && OculusXRHMD->WaitFrameNumber != XFrame->FrameNumber)
|
||||
{
|
||||
UE_LOG(LogHMD, Verbose, TEXT("Splash FOculusXRHMDModule::GetPluginWrapper().WaitToBeginFrame %u"), XFrame->FrameNumber);
|
||||
if (OVRP_FAILURE(Result = FOculusXRHMDModule::GetPluginWrapper().WaitToBeginFrame(XFrame->FrameNumber)))
|
||||
{
|
||||
UE_LOG(LogHMD, Error, TEXT("Splash FOculusXRHMDModule::GetPluginWrapper().WaitToBeginFrame %u failed (%d)"), XFrame->FrameNumber, Result);
|
||||
XFrame->ShowFlags.Rendering = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
OculusXRHMD->WaitFrameNumber = XFrame->FrameNumber;
|
||||
OculusXRHMD->NextFrameNumber = XFrame->FrameNumber + 1;
|
||||
FPlatformAtomics::InterlockedIncrement(&FramesOutstanding);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
XFrame->ShowFlags.Rendering = false;
|
||||
}
|
||||
|
||||
if (XFrame->ShowFlags.Rendering)
|
||||
{
|
||||
if (OVRP_FAILURE(Result = FOculusXRHMDModule::GetPluginWrapper().Update3(ovrpStep_Render, XFrame->FrameNumber, 0.0)))
|
||||
{
|
||||
UE_LOG(LogHMD, Error, TEXT("Splash FOculusXRHMDModule::GetPluginWrapper().Update3 %u failed (%d)"), XFrame->FrameNumber, Result);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
int32 LayerIndex = 0;
|
||||
int32 LayerIndex_RenderThread = 0;
|
||||
|
||||
while (LayerIndex < XLayers.Num() && LayerIndex_RenderThread < Layers_RenderThread.Num())
|
||||
{
|
||||
uint32 LayerIdA = XLayers[LayerIndex]->GetId();
|
||||
uint32 LayerIdB = Layers_RenderThread[LayerIndex_RenderThread]->GetId();
|
||||
|
||||
if (LayerIdA < LayerIdB)
|
||||
{
|
||||
XLayers[LayerIndex++]->Initialize_RenderThread(XSettings.Get(), CustomPresent, &OculusXRHMD->DeferredDeletion, RHICmdList);
|
||||
}
|
||||
else if (LayerIdA > LayerIdB)
|
||||
{
|
||||
OculusXRHMD->DeferredDeletion.AddLayerToDeferredDeletionQueue(Layers_RenderThread[LayerIndex_RenderThread++]);
|
||||
}
|
||||
else
|
||||
{
|
||||
XLayers[LayerIndex++]->Initialize_RenderThread(XSettings.Get(), CustomPresent, &OculusXRHMD->DeferredDeletion, RHICmdList, Layers_RenderThread[LayerIndex_RenderThread++].Get());
|
||||
}
|
||||
}
|
||||
|
||||
while (LayerIndex < XLayers.Num())
|
||||
{
|
||||
XLayers[LayerIndex++]->Initialize_RenderThread(XSettings.Get(), CustomPresent, &OculusXRHMD->DeferredDeletion, RHICmdList);
|
||||
}
|
||||
|
||||
while (LayerIndex_RenderThread < Layers_RenderThread.Num())
|
||||
{
|
||||
OculusXRHMD->DeferredDeletion.AddLayerToDeferredDeletionQueue(Layers_RenderThread[LayerIndex_RenderThread++]);
|
||||
}
|
||||
}
|
||||
|
||||
Layers_RenderThread = XLayers;
|
||||
|
||||
for (int32 LayerIndex = 0; LayerIndex < Layers_RenderThread.Num(); LayerIndex++)
|
||||
{
|
||||
Layers_RenderThread[LayerIndex]->UpdateTexture_RenderThread(XSettings.Get(), CustomPresent, RHICmdList);
|
||||
}
|
||||
|
||||
// This submit is required since splash happens before the game is rendering, so layers won't be submitted with game render commands
|
||||
CustomPresent->SubmitGPUCommands_RenderThread(RHICmdList);
|
||||
|
||||
// RHIFrame
|
||||
for (int32 LayerIndex = 0; LayerIndex < XLayers.Num(); LayerIndex++)
|
||||
{
|
||||
XLayers[LayerIndex] = XLayers[LayerIndex]->Clone();
|
||||
}
|
||||
|
||||
ExecuteOnRHIThread_DoNotWait([this, XSettings, XFrame, XLayers]() {
|
||||
ovrpResult ResultT;
|
||||
|
||||
if (XFrame->ShowFlags.Rendering)
|
||||
{
|
||||
UE_LOG(LogHMD, Verbose, TEXT("Splash FOculusXRHMDModule::GetPluginWrapper().BeginFrame4 %u"), XFrame->FrameNumber);
|
||||
if (OVRP_FAILURE(ResultT = FOculusXRHMDModule::GetPluginWrapper().BeginFrame4(XFrame->FrameNumber, CustomPresent->GetOvrpCommandQueue())))
|
||||
{
|
||||
UE_LOG(LogHMD, Error, TEXT("Splash FOculusXRHMDModule::GetPluginWrapper().BeginFrame4 %u failed (%d)"), XFrame->FrameNumber, ResultT);
|
||||
XFrame->ShowFlags.Rendering = false;
|
||||
}
|
||||
}
|
||||
|
||||
FPlatformAtomics::InterlockedDecrement(&FramesOutstanding);
|
||||
|
||||
Layers_RHIThread = XLayers;
|
||||
Layers_RHIThread.Sort(FLayerPtr_ComparePriority());
|
||||
|
||||
if (XFrame->ShowFlags.Rendering)
|
||||
{
|
||||
TArray<const ovrpLayerSubmit*> LayerSubmitPtr;
|
||||
LayerSubmitPtr.SetNum(Layers_RHIThread.Num());
|
||||
|
||||
for (int32 LayerIndex = 0; LayerIndex < Layers_RHIThread.Num(); LayerIndex++)
|
||||
{
|
||||
LayerSubmitPtr[LayerIndex] = Layers_RHIThread[LayerIndex]->UpdateLayer_RHIThread(XSettings.Get(), XFrame.Get(), LayerIndex);
|
||||
}
|
||||
|
||||
UE_LOG(LogHMD, Verbose, TEXT("Splash FOculusXRHMDModule::GetPluginWrapper().EndFrame4 %u"), XFrame->FrameNumber);
|
||||
if (OVRP_FAILURE(ResultT = FOculusXRHMDModule::GetPluginWrapper().EndFrame4(XFrame->FrameNumber, LayerSubmitPtr.GetData(), LayerSubmitPtr.Num(), CustomPresent->GetOvrpCommandQueue())))
|
||||
{
|
||||
UE_LOG(LogHMD, Error, TEXT("Splash FOculusXRHMDModule::GetPluginWrapper().EndFrame4 %u failed (%d)"), XFrame->FrameNumber, ResultT);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int32 LayerIndex = 0; LayerIndex < Layers_RHIThread.Num(); LayerIndex++)
|
||||
{
|
||||
Layers_RHIThread[LayerIndex]->IncrementSwapChainIndex_RHIThread(CustomPresent);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Splash screen render loop sometimes doesn't trigger RHICmdList flush
|
||||
CustomPresent->SubmitGPUCommands_RenderThread(FRHICommandListExecutor::GetImmediateCommandList());
|
||||
}
|
||||
|
||||
void FSplash::ReleaseResources_RHIThread()
|
||||
{
|
||||
for (int32 LayerIndex = 0; LayerIndex < Layers_RenderThread.Num(); LayerIndex++)
|
||||
{
|
||||
Layers_RenderThread[LayerIndex]->ReleaseResources_RHIThread();
|
||||
}
|
||||
|
||||
for (int32 LayerIndex = 0; LayerIndex < Layers_RHIThread.Num(); LayerIndex++)
|
||||
{
|
||||
Layers_RHIThread[LayerIndex]->ReleaseResources_RHIThread();
|
||||
}
|
||||
|
||||
Layers_RenderThread.Reset();
|
||||
Layers_RHIThread.Reset();
|
||||
}
|
||||
|
||||
void FSplash::PreShutdown()
|
||||
{
|
||||
CheckInGameThread();
|
||||
}
|
||||
|
||||
void FSplash::Shutdown()
|
||||
{
|
||||
CheckInGameThread();
|
||||
|
||||
#if WITH_EDITOR
|
||||
if (PieBeginDelegateHandle.IsValid())
|
||||
{
|
||||
FEditorDelegates::BeginPIE.Remove(PieBeginDelegateHandle);
|
||||
PieBeginDelegateHandle.Reset();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (PreLoadLevelDelegate.IsValid())
|
||||
{
|
||||
FCoreUObjectDelegates::PreLoadMap.Remove(PreLoadLevelDelegate);
|
||||
PreLoadLevelDelegate.Reset();
|
||||
}
|
||||
if (PostLoadLevelDelegate.IsValid())
|
||||
{
|
||||
FCoreUObjectDelegates::PostLoadMapWithWorld.Remove(PostLoadLevelDelegate);
|
||||
PostLoadLevelDelegate.Reset();
|
||||
}
|
||||
|
||||
if (bInitialized)
|
||||
{
|
||||
ExecuteOnRenderThread([this]() {
|
||||
if (Ticker)
|
||||
{
|
||||
Ticker->Unregister();
|
||||
Ticker = nullptr;
|
||||
}
|
||||
|
||||
ExecuteOnRHIThread([this]() {
|
||||
SplashLayers.Reset();
|
||||
Layers_RenderThread.Reset();
|
||||
Layers_RenderThread_Input.Reset();
|
||||
Layers_RHIThread.Reset();
|
||||
});
|
||||
});
|
||||
|
||||
bInitialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
int FSplash::AddSplash(const FOculusXRSplashDesc& Desc)
|
||||
{
|
||||
CheckInGameThread();
|
||||
|
||||
FScopeLock ScopeLock(&RenderThreadLock);
|
||||
return SplashLayers.Add(FSplashLayer(Desc));
|
||||
}
|
||||
|
||||
void FSplash::AddSplash(const FSplashDesc& Splash)
|
||||
{
|
||||
FOculusXRSplashDesc OculusDesc;
|
||||
OculusDesc.TransformInMeters = Splash.Transform;
|
||||
OculusDesc.QuadSizeInMeters = Splash.QuadSize;
|
||||
OculusDesc.DeltaRotation = Splash.DeltaRotation;
|
||||
OculusDesc.bNoAlphaChannel = Splash.bIgnoreAlpha;
|
||||
OculusDesc.bIsDynamic = Splash.bIsDynamic || Splash.bIsExternal;
|
||||
OculusDesc.TextureOffset = Splash.UVRect.Min;
|
||||
OculusDesc.TextureScale = Splash.UVRect.Max;
|
||||
OculusDesc.LoadedTexture = Splash.Texture;
|
||||
|
||||
AddSplash(OculusDesc);
|
||||
}
|
||||
|
||||
void FSplash::ClearSplashes()
|
||||
{
|
||||
CheckInGameThread();
|
||||
|
||||
FScopeLock ScopeLock(&RenderThreadLock);
|
||||
SplashLayers.Reset();
|
||||
}
|
||||
|
||||
bool FSplash::GetSplash(unsigned InSplashLayerIndex, FOculusXRSplashDesc& OutDesc)
|
||||
{
|
||||
CheckInGameThread();
|
||||
|
||||
FScopeLock ScopeLock(&RenderThreadLock);
|
||||
if (InSplashLayerIndex < unsigned(SplashLayers.Num()))
|
||||
{
|
||||
OutDesc = SplashLayers[int32(InSplashLayerIndex)].Desc;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
IStereoLayers::FLayerDesc FSplash::StereoLayerDescFromOculusSplashDesc(FOculusXRSplashDesc OculusDesc)
|
||||
{
|
||||
IStereoLayers::FLayerDesc LayerDesc;
|
||||
if (OculusDesc.LoadedTexture->GetTextureCube() != nullptr)
|
||||
{
|
||||
LayerDesc.SetShape<FCubemapLayer>();
|
||||
}
|
||||
// else LayerDesc.Shape defaults to FQuadLayer
|
||||
|
||||
LayerDesc.Transform = OculusDesc.TransformInMeters * FTransform(OculusXRHMD->GetSplashRotation().Quaternion());
|
||||
LayerDesc.QuadSize = OculusDesc.QuadSizeInMeters;
|
||||
LayerDesc.UVRect = FBox2D(OculusDesc.TextureOffset, OculusDesc.TextureOffset + OculusDesc.TextureScale);
|
||||
LayerDesc.Priority = INT32_MAX - (int32)(OculusDesc.TransformInMeters.GetTranslation().X * 1000.f);
|
||||
LayerDesc.PositionType = IStereoLayers::TrackerLocked;
|
||||
LayerDesc.Texture = OculusDesc.LoadedTexture;
|
||||
LayerDesc.Flags = IStereoLayers::LAYER_FLAG_QUAD_PRESERVE_TEX_RATIO | (OculusDesc.bNoAlphaChannel ? IStereoLayers::LAYER_FLAG_TEX_NO_ALPHA_CHANNEL : 0) | (OculusDesc.bIsDynamic ? IStereoLayers::LAYER_FLAG_TEX_CONTINUOUS_UPDATE : 0);
|
||||
|
||||
return LayerDesc;
|
||||
}
|
||||
|
||||
void FSplash::DoShow()
|
||||
{
|
||||
CheckInGameThread();
|
||||
|
||||
OculusXRHMD->SetSplashRotationToForward();
|
||||
|
||||
// Create new textures
|
||||
UnloadTextures();
|
||||
|
||||
// Make sure all UTextures are loaded and contain Resource->TextureRHI
|
||||
bool bWaitForRT = false;
|
||||
|
||||
for (int32 SplashLayerIndex = 0; SplashLayerIndex < SplashLayers.Num(); ++SplashLayerIndex)
|
||||
{
|
||||
FSplashLayer& SplashLayer = SplashLayers[SplashLayerIndex];
|
||||
|
||||
if (SplashLayer.Desc.TexturePath.IsValid())
|
||||
{
|
||||
// load temporary texture (if TexturePath was specified)
|
||||
LoadTexture(SplashLayer);
|
||||
}
|
||||
if (SplashLayer.Desc.LoadingTexture && SplashLayer.Desc.LoadingTexture->IsValidLowLevel())
|
||||
{
|
||||
SplashLayer.Desc.LoadingTexture->UpdateResource();
|
||||
bWaitForRT = true;
|
||||
}
|
||||
}
|
||||
|
||||
FlushRenderingCommands();
|
||||
|
||||
for (int32 SplashLayerIndex = 0; SplashLayerIndex < SplashLayers.Num(); ++SplashLayerIndex)
|
||||
{
|
||||
FSplashLayer& SplashLayer = SplashLayers[SplashLayerIndex];
|
||||
|
||||
//@DBG BEGIN
|
||||
if (SplashLayer.Desc.LoadingTexture && SplashLayer.Desc.LoadingTexture->IsValidLowLevel())
|
||||
{
|
||||
if (SplashLayer.Desc.LoadingTexture->GetResource() && SplashLayer.Desc.LoadingTexture->GetResource()->TextureRHI)
|
||||
{
|
||||
SplashLayer.Desc.LoadedTexture = SplashLayer.Desc.LoadingTexture->GetResource()->TextureRHI;
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogHMD, Warning, TEXT("Splash, %s - no Resource"), *SplashLayer.Desc.LoadingTexture->GetDesc());
|
||||
}
|
||||
}
|
||||
//@DBG END
|
||||
|
||||
if (SplashLayer.Desc.LoadedTexture)
|
||||
{
|
||||
SplashLayer.Layer = MakeShareable(new FLayer(NextLayerId++));
|
||||
SplashLayer.Layer->SetDesc(StereoLayerDescFromOculusSplashDesc(SplashLayer.Desc));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// add oculus-generated layers through the OculusVR settings area
|
||||
FScopeLock ScopeLock(&RenderThreadLock);
|
||||
Layers_RenderThread_DeltaRotation.Reset();
|
||||
Layers_RenderThread_Input.Reset();
|
||||
for (int32 SplashLayerIndex = 0; SplashLayerIndex < SplashLayers.Num(); SplashLayerIndex++)
|
||||
{
|
||||
const FSplashLayer& SplashLayer = SplashLayers[SplashLayerIndex];
|
||||
|
||||
if (SplashLayer.Layer.IsValid())
|
||||
{
|
||||
FLayerPtr ClonedLayer = SplashLayer.Layer->Clone();
|
||||
Layers_RenderThread_Input.Add(ClonedLayer);
|
||||
|
||||
// Register layers that need to be rotated every n ticks
|
||||
if (!SplashLayer.Desc.DeltaRotation.Equals(FQuat::Identity))
|
||||
{
|
||||
Layers_RenderThread_DeltaRotation.Emplace(ClonedLayer, SplashLayer.Desc.DeltaRotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add UE VR splash screen
|
||||
FOculusXRSplashDesc UESplashDesc = OculusXRHMD->GetUESplashScreenDesc();
|
||||
if (UESplashDesc.LoadedTexture != nullptr)
|
||||
{
|
||||
UELayer.Reset();
|
||||
UELayer = MakeShareable(new FLayer(NextLayerId++));
|
||||
UELayer->SetDesc(StereoLayerDescFromOculusSplashDesc(UESplashDesc));
|
||||
Layers_RenderThread_Input.Add(UELayer->Clone());
|
||||
}
|
||||
|
||||
Layers_RenderThread_Input.Sort(FLayerPtr_CompareId());
|
||||
}
|
||||
|
||||
if (Layers_RenderThread_Input.Num() > 0)
|
||||
{
|
||||
// If no textures are loaded, this will push black frame
|
||||
StartTicker();
|
||||
bIsShown = true;
|
||||
UE_LOG(LogHMD, Log, TEXT("FSplash::DoShow"));
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogHMD, Log, TEXT("No splash layers in FSplash::DoShow"));
|
||||
}
|
||||
}
|
||||
|
||||
void FSplash::DoHide()
|
||||
{
|
||||
CheckInGameThread();
|
||||
|
||||
UE_LOG(LogHMD, Log, TEXT("FSplash::DoHide"));
|
||||
bIsShown = false;
|
||||
|
||||
StopTicker();
|
||||
}
|
||||
|
||||
void FSplash::UpdateLoadingScreen_GameThread()
|
||||
{
|
||||
if (bNeedSplashUpdate)
|
||||
{
|
||||
if (bShouldShowSplash)
|
||||
{
|
||||
DoShow();
|
||||
}
|
||||
else
|
||||
{
|
||||
DoHide();
|
||||
}
|
||||
|
||||
bNeedSplashUpdate = false;
|
||||
}
|
||||
}
|
||||
|
||||
void FSplash::ShowLoadingScreen()
|
||||
{
|
||||
bShouldShowSplash = true;
|
||||
|
||||
// DoShow will be called from UpdateSplashScreen_Gamethread().
|
||||
// This can can happen if the splashes are already being shown, as it will reset the relative positions and delta rotations of the layers.
|
||||
bNeedSplashUpdate = true;
|
||||
}
|
||||
|
||||
void FSplash::HideLoadingScreen()
|
||||
{
|
||||
bShouldShowSplash = false;
|
||||
bNeedSplashUpdate = bIsShown; // no need to call DoHide when the splash is already hidden
|
||||
}
|
||||
|
||||
void FSplash::UnloadTextures()
|
||||
{
|
||||
CheckInGameThread();
|
||||
|
||||
// unload temporary loaded textures
|
||||
FScopeLock ScopeLock(&RenderThreadLock);
|
||||
for (int32 SplashLayerIndex = 0; SplashLayerIndex < SplashLayers.Num(); ++SplashLayerIndex)
|
||||
{
|
||||
if (SplashLayers[SplashLayerIndex].Desc.TexturePath.IsValid())
|
||||
{
|
||||
UnloadTexture(SplashLayers[SplashLayerIndex]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FSplash::LoadTexture(FSplashLayer& InSplashLayer)
|
||||
{
|
||||
CheckInGameThread();
|
||||
|
||||
UnloadTexture(InSplashLayer);
|
||||
|
||||
UE_LOG(LogLoadingSplash, Log, TEXT("Loading texture for splash %s..."), *InSplashLayer.Desc.TexturePath.GetAssetName());
|
||||
InSplashLayer.Desc.LoadingTexture = Cast<UTexture>(InSplashLayer.Desc.TexturePath.TryLoad());
|
||||
if (InSplashLayer.Desc.LoadingTexture != nullptr)
|
||||
{
|
||||
UE_LOG(LogLoadingSplash, Log, TEXT("...Success. "));
|
||||
}
|
||||
InSplashLayer.Desc.LoadedTexture = nullptr;
|
||||
InSplashLayer.Layer.Reset();
|
||||
}
|
||||
|
||||
void FSplash::UnloadTexture(FSplashLayer& InSplashLayer)
|
||||
{
|
||||
CheckInGameThread();
|
||||
|
||||
InSplashLayer.Desc.LoadingTexture = nullptr;
|
||||
InSplashLayer.Desc.LoadedTexture = nullptr;
|
||||
InSplashLayer.Layer.Reset();
|
||||
}
|
||||
|
||||
} // namespace OculusXRHMD
|
||||
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
146
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Splash.h
Normal file
146
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Splash.h
Normal file
@@ -0,0 +1,146 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
#include "OculusXRHMDPrivate.h"
|
||||
#include "IXRLoadingScreen.h"
|
||||
|
||||
#if WITH_EDITOR
|
||||
#include "Editor.h"
|
||||
#endif
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
#include "OculusXRHMD_GameFrame.h"
|
||||
#include "OculusXRHMD_Layer.h"
|
||||
#include "TickableObjectRenderThread.h"
|
||||
#include "OculusXRHMDTypes.h"
|
||||
|
||||
namespace OculusXRHMD
|
||||
{
|
||||
|
||||
class FOculusXRHMD;
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// FSplashLayer
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
struct FSplashLayer
|
||||
{
|
||||
FOculusXRSplashDesc Desc;
|
||||
FLayerPtr Layer;
|
||||
|
||||
public:
|
||||
FSplashLayer(const FOculusXRSplashDesc& InDesc)
|
||||
: Desc(InDesc) {}
|
||||
FSplashLayer(const FSplashLayer& InSplashLayer)
|
||||
: Desc(InSplashLayer.Desc), Layer(InSplashLayer.Layer) {}
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// FSplash
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
class FSplash : public IXRLoadingScreen, public TSharedFromThis<FSplash>
|
||||
{
|
||||
protected:
|
||||
class FTicker : public FTickableObjectRenderThread, public TSharedFromThis<FTicker>
|
||||
{
|
||||
public:
|
||||
FTicker(FSplash* InSplash)
|
||||
: FTickableObjectRenderThread(false, true), pSplash(InSplash) {}
|
||||
|
||||
virtual void Tick(float DeltaTime) override { pSplash->Tick_RenderThread(DeltaTime); }
|
||||
virtual TStatId GetStatId() const override { RETURN_QUICK_DECLARE_CYCLE_STAT(FSplash, STATGROUP_Tickables); }
|
||||
virtual bool IsTickable() const override { return true; }
|
||||
|
||||
protected:
|
||||
FSplash* pSplash;
|
||||
};
|
||||
|
||||
public:
|
||||
FSplash(FOculusXRHMD* InPlugin);
|
||||
virtual ~FSplash();
|
||||
|
||||
void Tick_RenderThread(float DeltaTime);
|
||||
|
||||
void Startup();
|
||||
void LoadSettings();
|
||||
void ReleaseResources_RHIThread();
|
||||
void PreShutdown();
|
||||
void Shutdown();
|
||||
|
||||
void OnPreLoadMap(const FString&);
|
||||
void OnPostLoadMap(UWorld* LoadedWorld);
|
||||
#if WITH_EDITOR
|
||||
void OnPieBegin(bool bIsSimulating);
|
||||
#endif
|
||||
|
||||
// Called from FOculusXRHMD
|
||||
void UpdateLoadingScreen_GameThread();
|
||||
|
||||
// Internal extended API
|
||||
int AddSplash(const FOculusXRSplashDesc&);
|
||||
bool GetSplash(unsigned index, FOculusXRSplashDesc& OutDesc);
|
||||
void StopTicker();
|
||||
void StartTicker();
|
||||
|
||||
// The standard IXRLoadingScreen interface
|
||||
virtual void ShowLoadingScreen() override;
|
||||
virtual void HideLoadingScreen() override;
|
||||
virtual void ClearSplashes() override;
|
||||
virtual void AddSplash(const FSplashDesc& Splash) override;
|
||||
virtual bool IsShown() const override { return bIsShown; }
|
||||
#if !UE_VERSION_OLDER_THAN(5, 3, 0)
|
||||
virtual bool IsPlayingLoadingMovie() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
void DoShow();
|
||||
void DoHide();
|
||||
void UnloadTextures();
|
||||
void LoadTexture(FSplashLayer& InSplashLayer);
|
||||
void UnloadTexture(FSplashLayer& InSplashLayer);
|
||||
|
||||
void RenderFrame_RenderThread(FRHICommandListImmediate& RHICmdList);
|
||||
IStereoLayers::FLayerDesc StereoLayerDescFromOculusSplashDesc(FOculusXRSplashDesc OculusDesc);
|
||||
|
||||
protected:
|
||||
FOculusXRHMD* OculusXRHMD;
|
||||
FCustomPresent* CustomPresent;
|
||||
TSharedPtr<FTicker> Ticker;
|
||||
int32 FramesOutstanding;
|
||||
FCriticalSection RenderThreadLock;
|
||||
FSettingsPtr Settings;
|
||||
FGameFramePtr Frame;
|
||||
TArray<FSplashLayer> SplashLayers;
|
||||
uint32 NextLayerId;
|
||||
FLayerPtr BlackLayer;
|
||||
FLayerPtr UELayer;
|
||||
TArray<TTuple<FLayerPtr, FQuat>> Layers_RenderThread_DeltaRotation;
|
||||
TArray<FLayerPtr> Layers_RenderThread_Input;
|
||||
TArray<FLayerPtr> Layers_RenderThread;
|
||||
TArray<FLayerPtr> Layers_RHIThread;
|
||||
|
||||
// All these flags are only modified from the Game thread
|
||||
bool bInitialized;
|
||||
bool bIsShown;
|
||||
bool bNeedSplashUpdate;
|
||||
bool bShouldShowSplash;
|
||||
|
||||
float SystemDisplayInterval;
|
||||
double LastTimeInSeconds;
|
||||
FDelegateHandle PreLoadLevelDelegate;
|
||||
FDelegateHandle PostLoadLevelDelegate;
|
||||
#if WITH_EDITOR
|
||||
FDelegateHandle PieBeginDelegateHandle;
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef TSharedPtr<FSplash> FSplashPtr;
|
||||
|
||||
} // namespace OculusXRHMD
|
||||
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
@@ -0,0 +1,309 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "OculusXRHMD_StressTester.h"
|
||||
|
||||
#if OCULUS_STRESS_TESTS_ENABLED
|
||||
#include "OculusXRHMD.h"
|
||||
#include "GlobalShader.h"
|
||||
#include "UniformBuffer.h"
|
||||
#include "RHICommandList.h"
|
||||
#include "ShaderParameterUtils.h"
|
||||
#include "RHIStaticStates.h"
|
||||
#include "PipelineStateCache.h"
|
||||
#include "OculusShaders.h"
|
||||
#include "SceneUtils.h" // for SCOPED_DRAW_EVENT()
|
||||
|
||||
DECLARE_STATS_GROUP(TEXT("Oculus"), STATGROUP_Oculus, STATCAT_Advanced);
|
||||
DECLARE_CYCLE_STAT(TEXT("GPUStressRendering"), STAT_GPUStressRendering, STATGROUP_Oculus);
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// Uniform buffers
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
// This buffer should contain variables that never, or rarely change
|
||||
BEGIN_GLOBAL_SHADER_PARAMETER_STRUCT(FOculusPixelShaderConstantParameters, )
|
||||
// SHADER_PARAMETER(FVector4, Name)
|
||||
END_GLOBAL_SHADER_PARAMETER_STRUCT()
|
||||
|
||||
IMPLEMENT_GLOBAL_SHADER_PARAMETER_STRUCT(FOculusPixelShaderConstantParameters, "PSConstants");
|
||||
|
||||
typedef TUniformBufferRef<FOculusPixelShaderConstantParameters> FOculusPixelShaderConstantParametersRef;
|
||||
|
||||
// This buffer is for variables that change very often (each frame for example)
|
||||
BEGIN_GLOBAL_SHADER_PARAMETER_STRUCT(FOculusPixelShaderVariableParameters, )
|
||||
SHADER_PARAMETER(int, IterationsMultiplier)
|
||||
END_GLOBAL_SHADER_PARAMETER_STRUCT()
|
||||
|
||||
IMPLEMENT_GLOBAL_SHADER_PARAMETER_STRUCT(FOculusPixelShaderVariableParameters, "PSVariables");
|
||||
|
||||
typedef TUniformBufferRef<FOculusPixelShaderVariableParameters> FOculusPixelShaderVariableParametersRef;
|
||||
|
||||
namespace OculusXRHMD
|
||||
{
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// FTextureVertexDeclaration
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
struct FTextureVertex
|
||||
{
|
||||
FVector4 Position;
|
||||
FVector2f UV;
|
||||
};
|
||||
|
||||
class FTextureVertexDeclaration : public FRenderResource
|
||||
{
|
||||
public:
|
||||
FVertexDeclarationRHIRef VertexDeclarationRHI;
|
||||
|
||||
#if UE_VERSION_OLDER_THAN(5, 3, 0)
|
||||
virtual void InitRHI() override
|
||||
#else
|
||||
virtual void InitRHI(FRHICommandListBase& RHICmdList) override
|
||||
#endif
|
||||
{
|
||||
FVertexDeclarationElementList Elements;
|
||||
uint32 Stride = sizeof(FTextureVertex);
|
||||
Elements.Add(FVertexElement(0, STRUCT_OFFSET(FTextureVertex, Position), VET_Float4, 0, Stride));
|
||||
Elements.Add(FVertexElement(0, STRUCT_OFFSET(FTextureVertex, UV), VET_Float2, 1, Stride));
|
||||
VertexDeclarationRHI = PipelineStateCache::GetOrCreateVertexDeclaration(Elements);
|
||||
}
|
||||
|
||||
virtual void ReleaseRHI() override
|
||||
{
|
||||
VertexDeclarationRHI.SafeRelease();
|
||||
}
|
||||
};
|
||||
|
||||
static TGlobalResource<FTextureVertexDeclaration> GOculusTextureVertexDeclaration;
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// FStressTester
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
TSharedPtr<FStressTester, ESPMode::ThreadSafe> FStressTester::SharedInstance;
|
||||
|
||||
TSharedRef<class FStressTester, ESPMode::ThreadSafe> FStressTester::Get()
|
||||
{
|
||||
CheckInGameThread();
|
||||
if (!SharedInstance.IsValid())
|
||||
{
|
||||
SharedInstance = TSharedPtr<class FStressTester, ESPMode::ThreadSafe>(new FStressTester());
|
||||
check(SharedInstance.IsValid());
|
||||
}
|
||||
return SharedInstance.ToSharedRef();
|
||||
}
|
||||
|
||||
FStressTester::FStressTester()
|
||||
: Mode(STM_None)
|
||||
, CPUSpinOffInSeconds(0.011 / 3.) // one third of the frame (default value)
|
||||
, PDsTimeLimitInSeconds(10.) // 10 secs
|
||||
, CPUsTimeLimitInSeconds(10.) // 10 secs
|
||||
, GPUsTimeLimitInSeconds(10.) // 10 secs
|
||||
, GPUIterationsMultiplier(0.)
|
||||
, CPUStartTimeInSeconds(0.)
|
||||
, GPUStartTimeInSeconds(0.)
|
||||
, PDStartTimeInSeconds(0.)
|
||||
{
|
||||
}
|
||||
|
||||
// multiple masks could be set, see EStressTestMode
|
||||
void FStressTester::SetStressMode(uint32 InStressMask)
|
||||
{
|
||||
check((InStressMask & (~STM__All)) == 0);
|
||||
Mode = InStressMask;
|
||||
|
||||
for (uint32 m = 1; m < STM__All; m <<= 1)
|
||||
{
|
||||
if (InStressMask & m)
|
||||
{
|
||||
switch (m)
|
||||
{
|
||||
case STM_EyeBufferRealloc:
|
||||
UE_LOG(LogHMD, Log, TEXT("PD of EyeBuffer stress test is started"));
|
||||
break;
|
||||
case STM_CPUSpin:
|
||||
UE_LOG(LogHMD, Log, TEXT("CPU stress test is started"));
|
||||
break;
|
||||
case STM_GPU:
|
||||
UE_LOG(LogHMD, Log, TEXT("GPU stress test is started"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FStressTester::DoTickCPU_GameThread(FOculusXRHMD* pPlugin)
|
||||
{
|
||||
CheckInGameThread();
|
||||
|
||||
if (Mode & STM_EyeBufferRealloc)
|
||||
{
|
||||
// Change PixelDensity every frame within MinPixelDensity..MaxPixelDensity range
|
||||
if (PDStartTimeInSeconds == 0.)
|
||||
{
|
||||
PDStartTimeInSeconds = FPlatformTime::Seconds();
|
||||
}
|
||||
else
|
||||
{
|
||||
const double Now = FPlatformTime::Seconds();
|
||||
if (Now - PDStartTimeInSeconds >= PDsTimeLimitInSeconds)
|
||||
{
|
||||
PDStartTimeInSeconds = 0.;
|
||||
Mode &= ~STM_EyeBufferRealloc;
|
||||
UE_LOG(LogHMD, Log, TEXT("PD of EyeBuffer stress test is finished"));
|
||||
}
|
||||
}
|
||||
|
||||
const int divisor = int((MaxPixelDensity - MinPixelDensity) * 10.f);
|
||||
float NewPD = float(uint64(FPlatformTime::Seconds() * 1000) % divisor) / 10.f + MinPixelDensity;
|
||||
|
||||
pPlugin->SetPixelDensity(NewPD);
|
||||
}
|
||||
|
||||
if (Mode & STM_CPUSpin)
|
||||
{
|
||||
// Simulate heavy CPU load within specified time limits
|
||||
|
||||
if (CPUStartTimeInSeconds == 0.)
|
||||
{
|
||||
CPUStartTimeInSeconds = FPlatformTime::Seconds();
|
||||
}
|
||||
else
|
||||
{
|
||||
const double Now = FPlatformTime::Seconds();
|
||||
if (Now - CPUStartTimeInSeconds >= CPUsTimeLimitInSeconds)
|
||||
{
|
||||
CPUStartTimeInSeconds = 0.;
|
||||
Mode &= ~STM_CPUSpin;
|
||||
UE_LOG(LogHMD, Log, TEXT("CPU stress test is finished"));
|
||||
}
|
||||
}
|
||||
|
||||
const double StartSeconds = FPlatformTime::Seconds();
|
||||
int i, num = 1, primes = 0;
|
||||
|
||||
bool bFinish = false;
|
||||
while (!bFinish)
|
||||
{
|
||||
i = 2;
|
||||
while (i <= num)
|
||||
{
|
||||
if (num % i == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
const double NowSeconds = FPlatformTime::Seconds();
|
||||
if (NowSeconds - StartSeconds >= CPUSpinOffInSeconds)
|
||||
{
|
||||
bFinish = true;
|
||||
}
|
||||
}
|
||||
if (i == num)
|
||||
{
|
||||
++primes;
|
||||
}
|
||||
|
||||
++num;
|
||||
}
|
||||
}
|
||||
|
||||
if (Mode & STM_GPU)
|
||||
{
|
||||
// Simulate heavy CPU load within specified time limits
|
||||
|
||||
if (GPUStartTimeInSeconds == 0.)
|
||||
{
|
||||
GPUStartTimeInSeconds = FPlatformTime::Seconds();
|
||||
}
|
||||
else
|
||||
{
|
||||
const double Now = FPlatformTime::Seconds();
|
||||
if (Now - GPUStartTimeInSeconds >= GPUsTimeLimitInSeconds)
|
||||
{
|
||||
GPUStartTimeInSeconds = 0.;
|
||||
Mode &= ~STM_GPU;
|
||||
UE_LOG(LogHMD, Log, TEXT("GPU stress test is finished"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// Console commands for managing the stress tester:
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
static void StressGPUCmdHandler(const TArray<FString>& Args, UWorld* World, FOutputDevice& Ar)
|
||||
{
|
||||
auto StressTester = FStressTester::Get();
|
||||
StressTester->SetStressMode(FStressTester::STM_GPU | StressTester->GetStressMode());
|
||||
if (Args.Num() > 0)
|
||||
{
|
||||
const int GpuMult = FCString::Atoi(*Args[0]);
|
||||
StressTester->SetGPULoadMultiplier(GpuMult);
|
||||
}
|
||||
if (Args.Num() > 1)
|
||||
{
|
||||
const float GpuTimeLimit = FCString::Atof(*Args[1]);
|
||||
StressTester->SetGPUsTimeLimitInSeconds(GpuTimeLimit);
|
||||
}
|
||||
}
|
||||
|
||||
static FAutoConsoleCommand CStressGPUCmd(
|
||||
TEXT("vr.oculus.Stress.GPU"),
|
||||
*NSLOCTEXT("OculusRift", "CCommandText_StressGPU", "Initiates a GPU stress test.\n Usage: vr.oculus.Stress.GPU [LoadMultiplier [TimeLimit]]").ToString(),
|
||||
FConsoleCommandWithWorldArgsAndOutputDeviceDelegate::CreateStatic(StressGPUCmdHandler));
|
||||
|
||||
static void StressCPUCmdHandler(const TArray<FString>& Args, UWorld* World, FOutputDevice& Ar)
|
||||
{
|
||||
auto StressTester = FStressTester::Get();
|
||||
StressTester->SetStressMode(FStressTester::STM_CPUSpin | StressTester->GetStressMode());
|
||||
if (Args.Num() > 0)
|
||||
{
|
||||
const float CpuLimit = FCString::Atof(*Args[0]);
|
||||
StressTester->SetCPUSpinOffPerFrameInSeconds(CpuLimit);
|
||||
}
|
||||
if (Args.Num() > 1)
|
||||
{
|
||||
const float CpuTimeLimit = FCString::Atof(*Args[1]);
|
||||
StressTester->SetCPUsTimeLimitInSeconds(CpuTimeLimit);
|
||||
}
|
||||
}
|
||||
|
||||
static FAutoConsoleCommand CStressCPUCmd(
|
||||
TEXT("vr.oculus.Stress.CPU"),
|
||||
*NSLOCTEXT("OculusRift", "CCommandText_StressCPU", "Initiates a CPU stress test.\n Usage: vr.oculus.Stress.CPU [PerFrameTime [TotalTimeLimit]]").ToString(),
|
||||
FConsoleCommandWithWorldArgsAndOutputDeviceDelegate::CreateStatic(StressCPUCmdHandler));
|
||||
|
||||
static void StressPDCmdHandler(const TArray<FString>& Args, UWorld* World, FOutputDevice& Ar)
|
||||
{
|
||||
auto StressTester = FStressTester::Get();
|
||||
StressTester->SetStressMode(FStressTester::STM_EyeBufferRealloc | StressTester->GetStressMode());
|
||||
if (Args.Num() > 0)
|
||||
{
|
||||
const float TimeLimit = FCString::Atof(*Args[0]);
|
||||
StressTester->SetPDsTimeLimitInSeconds(TimeLimit);
|
||||
}
|
||||
}
|
||||
|
||||
static FAutoConsoleCommand CStressPDCmd(
|
||||
TEXT("vr.oculus.Stress.PD"),
|
||||
*NSLOCTEXT("OculusRift", "CCommandText_StressPD", "Initiates a pixel density stress test wher pixel density is changed every frame for TotalTimeLimit seconds.\n Usage: vr.oculus.Stress.PD [TotalTimeLimit]").ToString(),
|
||||
FConsoleCommandWithWorldArgsAndOutputDeviceDelegate::CreateStatic(StressPDCmdHandler));
|
||||
|
||||
static void StressResetCmdHandler(const TArray<FString>& Args, UWorld* World, FOutputDevice& Ar)
|
||||
{
|
||||
auto StressTester = FStressTester::Get();
|
||||
StressTester->SetStressMode(0);
|
||||
}
|
||||
|
||||
static FAutoConsoleCommand CStressResetCmd(
|
||||
TEXT("vr.oculus.Stress.Reset"),
|
||||
*NSLOCTEXT("OculusRift", "CCommandText_StressReset", "Resets the stress tester and stops all currently running stress tests.\n Usage: vr.oculus.Stress.Reset").ToString(),
|
||||
FConsoleCommandWithWorldArgsAndOutputDeviceDelegate::CreateStatic(StressResetCmdHandler));
|
||||
|
||||
} // namespace OculusXRHMD
|
||||
|
||||
#endif // #if OCULUS_STRESS_TESTS_ENABLED
|
||||
@@ -0,0 +1,91 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
#include "OculusXRHMDPrivate.h"
|
||||
|
||||
#define OCULUS_STRESS_TESTS_ENABLED (OCULUS_HMD_SUPPORTED_PLATFORMS && !UE_BUILD_SHIPPING && !PLATFORM_ANDROID)
|
||||
|
||||
#if OCULUS_STRESS_TESTS_ENABLED
|
||||
|
||||
namespace OculusXRHMD
|
||||
{
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// FStressTester
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
class FStressTester
|
||||
{
|
||||
|
||||
public:
|
||||
const float MinPixelDensity = 0.4f;
|
||||
const float MaxPixelDensity = 2.0f;
|
||||
|
||||
enum EStressTestMode
|
||||
{
|
||||
STM_None,
|
||||
STM_EyeBufferRealloc = 0x01,
|
||||
STM_CPUSpin = 0x02,
|
||||
STM_GPU = 0x04,
|
||||
|
||||
STM__All = ((STM_GPU << 1) - 1)
|
||||
};
|
||||
|
||||
// multiple masks could be set, see EStressTestMode
|
||||
void SetStressMode(uint32 InStressMask);
|
||||
uint32 GetStressMode() const { return Mode; }
|
||||
|
||||
// sets limits for CPUSpin mode, per frame
|
||||
void SetCPUSpinOffPerFrameInSeconds(double InCPUSpinOffInSeconds) { CPUSpinOffInSeconds = InCPUSpinOffInSeconds; }
|
||||
|
||||
// set GPU load multiplier
|
||||
// if IterationsMultiplier is 0 then the multiplier will be randomly changed in 1..20 range.
|
||||
// the bigger the multiplier the longer it takes GPU to draw the quad.
|
||||
void SetGPULoadMultiplier(int IterationsMultiplier) { GPUIterationsMultiplier = IterationsMultiplier; }
|
||||
|
||||
// sets time limit for STM_EyeBufferRealloc mode; 0 - unlimited
|
||||
void SetPDsTimeLimitInSeconds(double InSeconds) { PDsTimeLimitInSeconds = InSeconds; }
|
||||
|
||||
// sets time limit for STM_CPUSpin mode; 0 - unlimited
|
||||
void SetCPUsTimeLimitInSeconds(double InSeconds) { CPUsTimeLimitInSeconds = InSeconds; }
|
||||
|
||||
// sets time limit for STM_GPU mode; 0 - unlimited
|
||||
void SetGPUsTimeLimitInSeconds(double InSeconds) { GPUsTimeLimitInSeconds = InSeconds; }
|
||||
|
||||
static TSharedRef<class FStressTester, ESPMode::ThreadSafe> Get();
|
||||
|
||||
static void TickCPU_GameThread(class FOculusXRHMD* pPlugin)
|
||||
{
|
||||
CheckInGameThread();
|
||||
|
||||
if (SharedInstance.IsValid())
|
||||
{
|
||||
SharedInstance->DoTickCPU_GameThread(pPlugin);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
void DoTickCPU_GameThread(class FOculusXRHMD* pPlugin);
|
||||
|
||||
FStressTester();
|
||||
|
||||
uint32 Mode; // bit mask, see EStressTestMode
|
||||
double CPUSpinOffInSeconds; // limit of additional CPU load per frame, STM_CPUSpin
|
||||
double PDsTimeLimitInSeconds; // time limit for STM_EyeBufferRealloc mode; 0 - unlimited
|
||||
double CPUsTimeLimitInSeconds; // time limit for STM_CPUSpin mode; 0 - unlimited
|
||||
double GPUsTimeLimitInSeconds; // time limit for STM_GPU mode; 0 - unlimited
|
||||
|
||||
// the higher multiplier the longer it takes GPU to draw
|
||||
int GPUIterationsMultiplier; // if 0 - then it is dynamically changed.
|
||||
|
||||
double CPUStartTimeInSeconds;
|
||||
double GPUStartTimeInSeconds;
|
||||
double PDStartTimeInSeconds;
|
||||
|
||||
static TSharedPtr<class FStressTester, ESPMode::ThreadSafe> SharedInstance;
|
||||
};
|
||||
|
||||
} // namespace OculusXRHMD
|
||||
|
||||
#endif // #if OCULUS_STRESS_TESTS_ENABLED
|
||||
@@ -0,0 +1,120 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "OculusXRHMD_VulkanExtensions.h"
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
#include "OculusXRHMDPrivateRHI.h"
|
||||
#include "OculusXRHMDModule.h"
|
||||
|
||||
namespace OculusXRHMD
|
||||
{
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// FVulkanExtensions
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
bool FVulkanExtensions::GetVulkanInstanceExtensionsRequired(TArray<const ANSICHAR*>& Out)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS_VULKAN
|
||||
// TArray<VkExtensionProperties> Properties = GetIVulkanDynamicRHI()->RHIGetAllInstanceExtensions();
|
||||
|
||||
TArray<const char*> Extensions;
|
||||
{
|
||||
int32 ExtensionCount = 0;
|
||||
FOculusXRHMDModule::GetPluginWrapper().GetInstanceExtensionsVk(nullptr, &ExtensionCount);
|
||||
Extensions.SetNum(ExtensionCount);
|
||||
FOculusXRHMDModule::GetPluginWrapper().GetInstanceExtensionsVk(Extensions.GetData(), &ExtensionCount);
|
||||
}
|
||||
|
||||
// int32 ExtensionsFound = 0;
|
||||
for (int32 ExtensionIndex = 0; ExtensionIndex < Extensions.Num(); ExtensionIndex++)
|
||||
{
|
||||
// for (int32 PropertyIndex = 0; PropertyIndex < Properties.Num(); PropertyIndex++)
|
||||
{
|
||||
// const char* PropertyExtensionName = Properties[PropertyIndex].extensionName;
|
||||
|
||||
// if (!FCStringAnsi::Strcmp(PropertyExtensionName, Extensions[ExtensionIndex]))
|
||||
{
|
||||
Out.Add(Extensions[ExtensionIndex]);
|
||||
// ExtensionsFound++;
|
||||
// break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
// return ExtensionsFound == Extensions.Num();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FVulkanExtensions::GetVulkanDeviceExtensionsRequired(struct VkPhysicalDevice_T* pPhysicalDevice, TArray<const ANSICHAR*>& Out)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS_VULKAN
|
||||
// TArray<VkExtensionProperties> Properties = GetIVulkanDynamicRHI()->RHIGetAllDeviceExtensions((VkPhysicalDevice)pPhysicalDevice);
|
||||
|
||||
TArray<const char*> Extensions;
|
||||
{
|
||||
int32 ExtensionCount = 0;
|
||||
FOculusXRHMDModule::GetPluginWrapper().GetDeviceExtensionsVk(nullptr, &ExtensionCount);
|
||||
Extensions.SetNum(ExtensionCount);
|
||||
FOculusXRHMDModule::GetPluginWrapper().GetDeviceExtensionsVk(Extensions.GetData(), &ExtensionCount);
|
||||
}
|
||||
|
||||
// int32 ExtensionsFound = 0;
|
||||
for (int32 ExtensionIndex = 0; ExtensionIndex < Extensions.Num(); ExtensionIndex++)
|
||||
{
|
||||
// for (int32 PropertyIndex = 0; PropertyIndex < Properties.Num(); PropertyIndex++)
|
||||
{
|
||||
// const char* PropertyExtensionName = Properties[PropertyIndex].extensionName;
|
||||
|
||||
// if (!FCStringAnsi::Strcmp(PropertyExtensionName, Extensions[ExtensionIndex]))
|
||||
{
|
||||
Out.Add(Extensions[ExtensionIndex]);
|
||||
// ExtensionsFound++;
|
||||
// break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
// return ExtensionsFound == Extensions.Num();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
#if WITH_EDITOR
|
||||
bool FEditorVulkanExtensions::GetVulkanInstanceExtensionsRequired(TArray<const ANSICHAR*>& Out)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS_VULKAN && PLATFORM_WINDOWS
|
||||
Out.Append({ "VK_KHR_surface",
|
||||
"VK_KHR_external_memory_capabilities",
|
||||
"VK_KHR_win32_surface",
|
||||
"VK_KHR_external_fence_capabilities",
|
||||
"VK_KHR_external_semaphore_capabilities",
|
||||
"VK_KHR_get_physical_device_properties2" });
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FEditorVulkanExtensions::GetVulkanDeviceExtensionsRequired(struct VkPhysicalDevice_T* pPhysicalDevice, TArray<const ANSICHAR*>& Out)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS_VULKAN && PLATFORM_WINDOWS
|
||||
Out.Append({ "VK_KHR_swapchain",
|
||||
"VK_KHR_external_memory",
|
||||
"VK_KHR_external_memory_win32",
|
||||
"VK_KHR_external_fence",
|
||||
"VK_KHR_external_fence_win32",
|
||||
"VK_KHR_external_semaphore",
|
||||
"VK_KHR_external_semaphore_win32",
|
||||
"VK_KHR_get_memory_requirements2",
|
||||
"VK_KHR_dedicated_allocation" });
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace OculusXRHMD
|
||||
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
@@ -0,0 +1,43 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
#include "OculusXRHMDPrivate.h"
|
||||
#include "IHeadMountedDisplayVulkanExtensions.h"
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
|
||||
namespace OculusXRHMD
|
||||
{
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// FVulkanExtensions
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
class FVulkanExtensions : public IHeadMountedDisplayVulkanExtensions, public TSharedFromThis<FVulkanExtensions, ESPMode::ThreadSafe>
|
||||
{
|
||||
public:
|
||||
FVulkanExtensions() {}
|
||||
virtual ~FVulkanExtensions() {}
|
||||
|
||||
// IHeadMountedDisplayVulkanExtensions
|
||||
virtual bool GetVulkanInstanceExtensionsRequired(TArray<const ANSICHAR*>& Out) override;
|
||||
virtual bool GetVulkanDeviceExtensionsRequired(struct VkPhysicalDevice_T* pPhysicalDevice, TArray<const ANSICHAR*>& Out) override;
|
||||
};
|
||||
|
||||
#if WITH_EDITOR
|
||||
class FEditorVulkanExtensions : public IHeadMountedDisplayVulkanExtensions, public TSharedFromThis<FEditorVulkanExtensions, ESPMode::ThreadSafe>
|
||||
{
|
||||
public:
|
||||
FEditorVulkanExtensions() {}
|
||||
virtual ~FEditorVulkanExtensions() {}
|
||||
|
||||
// IHeadMountedDisplayVulkanExtensions
|
||||
virtual bool GetVulkanInstanceExtensionsRequired(TArray<const ANSICHAR*>& Out) override;
|
||||
virtual bool GetVulkanDeviceExtensionsRequired(struct VkPhysicalDevice_T* pPhysicalDevice, TArray<const ANSICHAR*>& Out) override;
|
||||
};
|
||||
#endif
|
||||
|
||||
} // namespace OculusXRHMD
|
||||
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
@@ -0,0 +1,379 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#include "OculusXRMultiPlayerTestingSubsystem.h"
|
||||
|
||||
#include "IHeadMountedDisplay.h"
|
||||
#include "IXRTrackingSystem.h"
|
||||
#include "Widgets/SViewport.h"
|
||||
#include "Slate/SceneViewport.h"
|
||||
|
||||
#include "OculusXRHMDModule.h"
|
||||
#include "OculusXRHMDRuntimeSettings.h"
|
||||
#include "OculusXRHMD.h"
|
||||
|
||||
#if WITH_EDITOR
|
||||
#include "Editor/UnrealEd/Classes/Editor/EditorEngine.h"
|
||||
#include "Settings/LevelEditorPlaySettings.h"
|
||||
#endif
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#include "Windows/WindowsPlatformProcess.h"
|
||||
#include <TlHelp32.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Initialize the subsystem. USubsystem override
|
||||
*/
|
||||
void UOculusXRMultiPlayerTestingSubsystem::Initialize(FSubsystemCollectionBase& Collection)
|
||||
{
|
||||
Super::Initialize(Collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* De-initializes the subsystem. USubsystem override
|
||||
*/
|
||||
void UOculusXRMultiPlayerTestingSubsystem::Deinitialize()
|
||||
{
|
||||
Super::Deinitialize();
|
||||
}
|
||||
|
||||
ETickableTickType UOculusXRMultiPlayerTestingSubsystem::GetTickableTickType() const
|
||||
{
|
||||
return IsMultiPlayerTestingSupported() ? ETickableTickType::Always : ETickableTickType::Never;
|
||||
}
|
||||
|
||||
bool UOculusXRMultiPlayerTestingSubsystem::IsAllowedToTick() const
|
||||
{
|
||||
return IsMultiPlayerTestingSupported();
|
||||
}
|
||||
|
||||
void UOculusXRMultiPlayerTestingSubsystem::Tick(float)
|
||||
{
|
||||
#if PLATFORM_WINDOWS && WITH_EDITOR
|
||||
bool bSingleProcessMode = true;
|
||||
if (!IsMultiPlayerTestingEnabled(bSingleProcessMode))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (GEngine)
|
||||
{
|
||||
const ULevelEditorPlaySettings* PlayInSettings = GetDefault<ULevelEditorPlaySettings>();
|
||||
bool RunUnderOneProcess = true;
|
||||
PlayInSettings->GetRunUnderOneProcess(RunUnderOneProcess);
|
||||
if (GetMutableDefault<UOculusXRHMDRuntimeSettings>()->bSetActivePIEToPrimary && RunUnderOneProcess)
|
||||
{
|
||||
SwitchPrimaryPIE_SingleProcess();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool UOculusXRMultiPlayerTestingSubsystem::IsMultiPlayerTestingSupported() const
|
||||
{
|
||||
#if PLATFORM_WINDOWS && WITH_EDITOR
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
bool UOculusXRMultiPlayerTestingSubsystem::IsMultiPlayerTestingEnabled(bool& bSingleProcessMode)
|
||||
{
|
||||
bSingleProcessMode = false;
|
||||
NumClients = 1;
|
||||
// ULevelEditorPlaySettings of 2nd+ player of MultipleProcess mode does NOT have correct GetRunUnderOneProcess() data.
|
||||
// Let's use InInstanceNum to figure out how many clients are enabled already.
|
||||
int InInstanceNum = 0;
|
||||
FParse::Value(FCommandLine::Get(), TEXT("InInstanceNum="), InInstanceNum);
|
||||
if (InInstanceNum)
|
||||
{
|
||||
bSingleProcessMode = false;
|
||||
NumClients = InInstanceNum + 1;
|
||||
}
|
||||
#if WITH_EDITOR
|
||||
else
|
||||
{
|
||||
// SingleProcess mode OR 1st player of MultipleProcess mode are kicked off from editor
|
||||
const ULevelEditorPlaySettings* PlayInSettings = GetDefault<ULevelEditorPlaySettings>();
|
||||
if (PlayInSettings)
|
||||
{
|
||||
PlayInSettings->GetPlayNumberOfClients(NumClients);
|
||||
PlayInSettings->GetRunUnderOneProcess(bSingleProcessMode);
|
||||
}
|
||||
}
|
||||
#endif // WITH_EDITOR
|
||||
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
return (NumClients > 1
|
||||
&& GEngine
|
||||
&& GEngine->XRSystem.IsValid()
|
||||
&& GEngine->XRSystem->GetStereoRenderingDevice().IsValid()
|
||||
&& GEngine->XRSystem->GetStereoRenderingDevice()->IsStereoEnabled());
|
||||
#else
|
||||
return (NumClients > 1 && OculusXRHMD::FOculusXRHMD::GetOculusXRHMD() && OculusXRHMD::FOculusXRHMD::GetOculusXRHMD()->IsStereoEnabled());
|
||||
#endif
|
||||
}
|
||||
|
||||
static void SwitchPrimaryPIE(const TArray<FString>& Args, UWorld*, FOutputDevice& Ar)
|
||||
{
|
||||
if (!GEngine || !GEngine->XRSystem.IsValid())
|
||||
{
|
||||
Ar.Logf(TEXT("XRSystem must be valid to switch PrimaryPIE!"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GetMutableDefault<UOculusXRHMDRuntimeSettings>()->bSetCVarPIEToPrimary)
|
||||
{
|
||||
Ar.Logf(TEXT("Please enable \"Set CVar PIE To Primary\" in MetaXRPlugin settings!"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (Args.Num())
|
||||
{
|
||||
if (UOculusXRMultiPlayerTestingSubsystem* MPTSSubsystem = GEngine ? GEngine->GetEngineSubsystem<UOculusXRMultiPlayerTestingSubsystem>() : nullptr)
|
||||
{
|
||||
MPTSSubsystem->SwitchPrimaryPIE(nullptr, FCString::Atoi(*Args[0]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Ar.Logf(TEXT("Invalid PrimaryPIEIndex!"));
|
||||
}
|
||||
}
|
||||
|
||||
const int DefaultNextProcIndex = -1;
|
||||
static FAutoConsoleCommand CSwitchHMDCmd(
|
||||
TEXT("vr.PrimaryPIEIndex"),
|
||||
TEXT("Set primary PIE index on the fly. Setting it to -1 is to set the index to next PIE window. If RunUnderOneProcess is enabled, this index can be set to any PIE index."),
|
||||
FConsoleCommandWithWorldArgsAndOutputDeviceDelegate::CreateStatic(SwitchPrimaryPIE));
|
||||
|
||||
void UOculusXRMultiPlayerTestingSubsystem::SwitchPrimaryPIE(UGameViewportClient* InViewport, TOptional<int> PrimaryPIEIndex)
|
||||
{
|
||||
bool bSingleProcessMode = true;
|
||||
if (!IsMultiPlayerTestingEnabled(bSingleProcessMode))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bSingleProcessMode)
|
||||
{
|
||||
check(PrimaryPIEIndex.IsSet());
|
||||
SwitchPrimaryPIE_MultiProcess(PrimaryPIEIndex.GetValue());
|
||||
}
|
||||
#if WITH_EDITOR
|
||||
else
|
||||
{
|
||||
SwitchPrimaryPIE_SingleProcess(InViewport, PrimaryPIEIndex);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UOculusXRMultiPlayerTestingSubsystem::GetUnrealEditorProcs(TArray<int32>& ProcIds)
|
||||
{
|
||||
FString ProcNameWithExtension = "UnrealEditor.exe";
|
||||
HANDLE SnapShot = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
if (SnapShot != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
PROCESSENTRY32 Entry;
|
||||
Entry.dwSize = sizeof(PROCESSENTRY32);
|
||||
|
||||
const int ProjectNameMaxLength = 512;
|
||||
if (::Process32First(SnapShot, &Entry))
|
||||
{
|
||||
do
|
||||
{
|
||||
// find unreal editor processes
|
||||
if (FCString::Stricmp(*ProcNameWithExtension, Entry.szExeFile) == 0)
|
||||
{
|
||||
int32 ProcID = Entry.th32ProcessID;
|
||||
HWND HWnd = FWindowsPlatformMisc::GetTopLevelWindowHandle(ProcID);
|
||||
if (HWnd)
|
||||
{
|
||||
const TCHAR* ProjectName = FApp::GetProjectName();
|
||||
WCHAR Buffer[ProjectNameMaxLength];
|
||||
GetWindowText(HWnd, Buffer, ProjectNameMaxLength);
|
||||
size_t ProjectNameLen = _tcslen(ProjectName);
|
||||
if (_tcsnccmp(ProjectName, Buffer, ProjectNameLen) == 0)
|
||||
{
|
||||
ProcIds.Add(ProcID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while (::Process32Next(SnapShot, &Entry));
|
||||
}
|
||||
::CloseHandle(SnapShot);
|
||||
}
|
||||
ProcIds.Sort(TLess<int32>());
|
||||
}
|
||||
|
||||
// Activate PIE window across processes.
|
||||
void UOculusXRMultiPlayerTestingSubsystem::SwitchPrimaryPIE_MultiProcess(int PrimaryPIEIndex)
|
||||
{
|
||||
uint32 CurProcId = FPlatformProcess::GetCurrentProcessId();
|
||||
uint32 DestProcId = -1;
|
||||
TArray<int32> ProcIds;
|
||||
GetUnrealEditorProcs(ProcIds);
|
||||
// For now, PrimaryPIEIndex must be -1 which means we always switch to next player.
|
||||
// The reason is users don't know each process' index and cannot easily set it via vr.PrimaryPIEIndex even if we sort processIDs first.
|
||||
if (PrimaryPIEIndex == DefaultNextProcIndex)
|
||||
{ // find next process's Id
|
||||
int32 CurProcIdx = ProcIds.Find(CurProcId);
|
||||
check(CurProcIdx != INDEX_NONE);
|
||||
int32 NextProcIdx = (CurProcIdx + 1) % ProcIds.Num();
|
||||
DestProcId = ProcIds[NextProcIdx];
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogHMD, Warning, TEXT("vr.PrimaryPIEIndex must be -1 if RunUnderOneProcess is not set."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (DestProcId == -1)
|
||||
{
|
||||
UE_LOG(LogHMD, Warning, TEXT("Cannot find vr.PrimaryPIEIndex: %d"), PrimaryPIEIndex);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogHMD, Log, TEXT("SwitchPrimaryPIE from ProcID: %d to: %d"), CurProcId, DestProcId);
|
||||
HWND MainWindowHandle = FWindowsPlatformMisc::GetTopLevelWindowHandle(DestProcId);
|
||||
::SwitchToThisWindow(MainWindowHandle, true);
|
||||
}
|
||||
}
|
||||
|
||||
#if WITH_EDITOR
|
||||
void UOculusXRMultiPlayerTestingSubsystem::SwitchPrimaryPIE_SingleProcess(UGameViewportClient* InViewport, TOptional<int> PrimaryPIEIndex)
|
||||
{
|
||||
if (InViewport && PrimaryPIEIndex.IsSet())
|
||||
{
|
||||
UE_LOG(LogHMD, Warning, TEXT("InViewport and PrimaryPIEIndex should not be set at the same time."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GEditor)
|
||||
{
|
||||
UE_LOG(LogHMD, Warning, TEXT("SwitchPrimaryPIE_SingleProcess is only supported in editor."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (PrimaryPIEIndex == DefaultNextProcIndex)
|
||||
{ // Activate the world next to the current primary one
|
||||
for (const FWorldContext& WorldContext : GEditor->GetWorldContexts())
|
||||
{
|
||||
if (WorldContext.bIsPrimaryPIEInstance)
|
||||
{
|
||||
PrimaryPIEIndex = (WorldContext.PIEInstance + 1) % NumClients;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FWorldContext* OldPrimaryWorld = nullptr;
|
||||
FWorldContext* NewPrimaryWorld = nullptr;
|
||||
for (const FWorldContext& WorldContext : GEditor->GetWorldContexts())
|
||||
{
|
||||
if (WorldContext.bIsPrimaryPIEInstance)
|
||||
{
|
||||
OldPrimaryWorld = GEditor->GetWorldContextFromWorld(WorldContext.World());
|
||||
}
|
||||
else if (WorldContext.GameViewport == InViewport || (PrimaryPIEIndex.IsSet() && WorldContext.PIEInstance == PrimaryPIEIndex.GetValue()))
|
||||
{
|
||||
NewPrimaryWorld = GEditor->GetWorldContextFromWorld(WorldContext.World());
|
||||
}
|
||||
}
|
||||
|
||||
if (OldPrimaryWorld && NewPrimaryWorld)
|
||||
{
|
||||
SwitchPrimaryPIE(OldPrimaryWorld, NewPrimaryWorld);
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogHMD, Warning, TEXT("Failed to switch primary PIE."));
|
||||
}
|
||||
}
|
||||
|
||||
void UOculusXRMultiPlayerTestingSubsystem::SwitchPrimaryPIE_SingleProcess()
|
||||
{
|
||||
NumClients = 0;
|
||||
const ULevelEditorPlaySettings* PlayInSettings = GetDefault<ULevelEditorPlaySettings>();
|
||||
if (PlayInSettings)
|
||||
{
|
||||
PlayInSettings->GetPlayNumberOfClients(NumClients);
|
||||
}
|
||||
|
||||
if (!(GEditor && GEditor->GetPlayInEditorSessionInfo().IsSet() && GEditor->GetPlayInEditorSessionInfo()->NumClientInstancesCreated == NumClients))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FWorldContext* OldPrimaryWorld = nullptr;
|
||||
FWorldContext* NewPrimaryWorld = nullptr;
|
||||
for (const FWorldContext& WorldContext : GEditor->GetWorldContexts())
|
||||
{
|
||||
if (!WorldContext.GameViewport || !WorldContext.GameViewport->GetGameViewport())
|
||||
{
|
||||
UE_LOG(LogHMD, Warning, TEXT("No GameViewport or SceneViewPort for the current world %d."), WorldContext.PIEInstance);
|
||||
continue;
|
||||
}
|
||||
const FSceneViewport* SceneViewPort = WorldContext.GameViewport->GetGameViewport();
|
||||
if (WorldContext.bIsPrimaryPIEInstance && !SceneViewPort->HasFocus())
|
||||
{
|
||||
OldPrimaryWorld = GEditor->GetWorldContextFromWorld(WorldContext.World());
|
||||
}
|
||||
else if (!WorldContext.bIsPrimaryPIEInstance && SceneViewPort->HasFocus())
|
||||
{
|
||||
NewPrimaryWorld = GEditor->GetWorldContextFromWorld(WorldContext.World());
|
||||
}
|
||||
}
|
||||
|
||||
if (OldPrimaryWorld && NewPrimaryWorld)
|
||||
{
|
||||
UE_LOG(LogHMD, Log, TEXT("SwitchPrimaryPIE from %d to %d."), OldPrimaryWorld->PIEInstance, NewPrimaryWorld->PIEInstance);
|
||||
SwitchPrimaryPIE(OldPrimaryWorld, NewPrimaryWorld);
|
||||
}
|
||||
}
|
||||
|
||||
void UOculusXRMultiPlayerTestingSubsystem::SwitchPrimaryPIE(FWorldContext* OldPrimaryWorld, FWorldContext* NewPrimaryWorld)
|
||||
{
|
||||
auto TogglePrimaryWorld = [](FWorldContext* PrimaryWorld, bool bEnable) {
|
||||
check(PrimaryWorld != nullptr);
|
||||
|
||||
FSceneViewport* SceneViewPort = PrimaryWorld->GameViewport->GetGameViewport();
|
||||
|
||||
PrimaryWorld->bIsPrimaryPIEInstance = bEnable;
|
||||
SceneViewPort->GetViewportWidget().Pin()->EnableStereoRendering(bEnable);
|
||||
SceneViewPort->GetViewportWidget().Pin()->SetRenderDirectlyToWindow(bEnable);
|
||||
SceneViewPort->SetPlayInEditorGetsMouseControl(bEnable);
|
||||
SceneViewPort->SetViewportSize(SceneViewPort->GetSizeXY().X, SceneViewPort->GetSizeXY().Y);
|
||||
if (bEnable)
|
||||
{
|
||||
SceneViewPort->FindWindow()->GetNativeWindow()->SetWindowFocus();
|
||||
}
|
||||
else
|
||||
{
|
||||
SceneViewPort->FindWindow()->SetViewportSizeDrivenByWindow(true);
|
||||
}
|
||||
};
|
||||
|
||||
if (NewPrimaryWorld->GameViewport && NewPrimaryWorld->GameViewport->GetGameViewport() && OldPrimaryWorld->GameViewport && OldPrimaryWorld->GameViewport->GetGameViewport())
|
||||
{
|
||||
TogglePrimaryWorld(NewPrimaryWorld, true);
|
||||
TogglePrimaryWorld(OldPrimaryWorld, false);
|
||||
|
||||
// ATM, in Vanilla/Stock UE, no MultiPlayer support in OpenXR plugin.
|
||||
// TODO: Remove below branch checking and refactor FOculusXRHMD to be the same with FOpenXRHMD once IOpenXRExtensionPlugin::ReCalcPose(...) is upstreamed.
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
OculusXR::FMultiPlayerStateExtensionPlugin& MPPlugin = FOculusXRHMDModule::Get().GetExtensionPluginManager().GetMultiPlayerStateExtensionPlugin();
|
||||
MPPlugin.SwitchPrimaryPIE(NewPrimaryWorld->PIEInstance);
|
||||
#endif // WITH_OCULUS_BRANCH
|
||||
|
||||
if (OculusXRHMD::FOculusXRHMD::GetOculusXRHMD())
|
||||
{
|
||||
OculusXRHMD::FOculusXRHMD::GetOculusXRHMD()->SwitchPrimaryPIE(NewPrimaryWorld->PIEInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // WITH_EDITOR
|
||||
#endif // PLATFORM_WINDOWS
|
||||
@@ -0,0 +1,158 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#include "OculusXRPassthroughLayerShapes.h"
|
||||
|
||||
#include "OculusXRHMDPrivate.h"
|
||||
#include "Curves/CurveLinearColor.h"
|
||||
#include "OculusXRPluginWrapper.h"
|
||||
#include "OpenXR/OculusXROpenXRUtilities.h"
|
||||
|
||||
const FName FReconstructedLayer::ShapeName = FName("ReconstructedLayer");
|
||||
const FName FUserDefinedLayer::ShapeName = FName("UserDefinedLayer");
|
||||
|
||||
FColorLutDesc::FColorLutDesc()
|
||||
: Weight(0)
|
||||
, ColorLuts{}
|
||||
{
|
||||
}
|
||||
|
||||
FColorLutDesc::FColorLutDesc(const TArray<uint64>& InColorLuts, float InWeight)
|
||||
: Weight(InWeight)
|
||||
, ColorLuts(InColorLuts)
|
||||
{
|
||||
}
|
||||
|
||||
FEdgeStyleParameters::FEdgeStyleParameters()
|
||||
: bEnableEdgeColor(false)
|
||||
, bEnableColorMap(false)
|
||||
, bUseColorLuts(false)
|
||||
, TextureOpacityFactor(1.0f)
|
||||
, EdgeColor{}
|
||||
, ColorMapType{}
|
||||
, ColorMapData{}
|
||||
, ColorLutDesc{} {
|
||||
|
||||
};
|
||||
|
||||
FEdgeStyleParameters::FEdgeStyleParameters(
|
||||
bool bEnableEdgeColor,
|
||||
bool bEnableColorMap,
|
||||
float TextureOpacityFactor,
|
||||
float Brightness,
|
||||
float Contrast,
|
||||
float Posterize,
|
||||
float Saturation,
|
||||
FLinearColor EdgeColor,
|
||||
FLinearColor ColorScale,
|
||||
FLinearColor ColorOffset,
|
||||
EOculusXRColorMapType InColorMapType,
|
||||
const TArray<FLinearColor>& InColorMapGradient,
|
||||
const FColorLutDesc& InLutDesc)
|
||||
: bEnableEdgeColor(bEnableEdgeColor)
|
||||
, bEnableColorMap(bEnableColorMap)
|
||||
, TextureOpacityFactor(TextureOpacityFactor)
|
||||
, Brightness(Brightness)
|
||||
, Contrast(Contrast)
|
||||
, Posterize(Posterize)
|
||||
, Saturation(Saturation)
|
||||
, EdgeColor(EdgeColor)
|
||||
, ColorScale(ColorScale)
|
||||
, ColorOffset(ColorOffset)
|
||||
, ColorMapType(InColorMapType)
|
||||
, ColorLutDesc(InLutDesc)
|
||||
{
|
||||
bUseColorLuts = (InColorMapType == ColorMapType_ColorLut && InLutDesc.ColorLuts.Num() == 1)
|
||||
|| (InColorMapType == ColorMapType_ColorLut_Interpolated && InLutDesc.ColorLuts.Num() == 2);
|
||||
if ((InColorMapType == ColorMapType_ColorLut || InColorMapType == ColorMapType_ColorLut_Interpolated)
|
||||
&& !bUseColorLuts)
|
||||
{
|
||||
ColorMapType = ColorMapType_None;
|
||||
}
|
||||
ColorMapData = GenerateColorMapData(InColorMapType, InColorMapGradient);
|
||||
};
|
||||
|
||||
TArray<uint8> FEdgeStyleParameters::GenerateColorMapData(EOculusXRColorMapType InColorMapType, const TArray<FLinearColor>& InColorMapGradient)
|
||||
{
|
||||
switch (InColorMapType)
|
||||
{
|
||||
case ColorMapType_GrayscaleToColor:
|
||||
{
|
||||
TArray<uint8> NewColorMapData = GenerateMonoBrightnessContrastPosterizeMap();
|
||||
return GenerateMonoToRGBA(InColorMapGradient, NewColorMapData);
|
||||
}
|
||||
case ColorMapType_Grayscale:
|
||||
return GenerateMonoBrightnessContrastPosterizeMap();
|
||||
case ColorMapType_ColorAdjustment:
|
||||
return GenerateBrightnessContrastSaturationColorMap();
|
||||
default:
|
||||
return TArray<uint8>();
|
||||
}
|
||||
}
|
||||
|
||||
TArray<uint8> FEdgeStyleParameters::GenerateMonoToRGBA(const TArray<FLinearColor>& InColorMapGradient, const TArray<uint8>& InColorMapData)
|
||||
{
|
||||
TArray<uint8> NewColorMapData;
|
||||
FInterpCurveLinearColor InterpCurve;
|
||||
const uint32 TotalEntries = 256;
|
||||
|
||||
for (int32 Index = 0; Index < InColorMapGradient.Num(); ++Index)
|
||||
{
|
||||
InterpCurve.AddPoint(Index, (InColorMapGradient[Index] * ColorScale) + ColorOffset);
|
||||
}
|
||||
|
||||
// XrColor4f and ovrpColorf need to be same size, as either will be sent to the OVR plugin or OpenXR implementation
|
||||
static_assert(sizeof(XrColor4f) == sizeof(ovrpColorf));
|
||||
|
||||
const int32 ColorSize = sizeof(ovrpColorf);
|
||||
NewColorMapData.SetNum(TotalEntries * ColorSize);
|
||||
|
||||
uint8* Dest = NewColorMapData.GetData();
|
||||
for (int32 Index = 0; Index < TotalEntries; ++Index)
|
||||
{
|
||||
const ovrpColorf Color = OculusXRHMD::ToOvrpColorf(InterpCurve.Eval(InColorMapData[Index]));
|
||||
FMemory::Memcpy(Dest, &Color, sizeof(Color));
|
||||
Dest += ColorSize;
|
||||
}
|
||||
return NewColorMapData;
|
||||
}
|
||||
|
||||
TArray<uint8> FEdgeStyleParameters::GenerateMonoBrightnessContrastPosterizeMap()
|
||||
{
|
||||
TArray<uint8> NewColorMapData;
|
||||
const int32 TotalEntries = 256;
|
||||
NewColorMapData.SetNum(TotalEntries * sizeof(uint8));
|
||||
for (int32 Index = 0; Index < TotalEntries; ++Index)
|
||||
{
|
||||
float Alpha = ((float)Index / TotalEntries);
|
||||
float ContrastFactor = Contrast + 1.0;
|
||||
Alpha = (Alpha - 0.5) * ContrastFactor + 0.5 + Brightness;
|
||||
|
||||
if (Posterize > 0.0f)
|
||||
{
|
||||
const float PosterizationBase = 50.0f;
|
||||
float FinalPosterize = (FMath::Pow(PosterizationBase, Posterize) - 1.0) / (PosterizationBase - 1.0);
|
||||
Alpha = FMath::RoundToFloat(Alpha / FinalPosterize) * FinalPosterize;
|
||||
}
|
||||
|
||||
NewColorMapData[Index] = (uint8)(FMath::Min(FMath::Max(Alpha, 0.0f), 1.0f) * 255.0f);
|
||||
}
|
||||
return NewColorMapData;
|
||||
}
|
||||
|
||||
TArray<uint8> FEdgeStyleParameters::GenerateBrightnessContrastSaturationColorMap()
|
||||
{
|
||||
TArray<uint8> NewColorMapData;
|
||||
NewColorMapData.SetNum(3 * sizeof(float));
|
||||
float newB = Brightness * 100.0f;
|
||||
float newC = Contrast + 1.0f;
|
||||
float newS = Saturation + 1.0f;
|
||||
|
||||
uint8* Dest = NewColorMapData.GetData();
|
||||
FMemory::Memcpy(Dest, &newB, sizeof(float));
|
||||
Dest += sizeof(float);
|
||||
FMemory::Memcpy(Dest, &newC, sizeof(float));
|
||||
Dest += sizeof(float);
|
||||
FMemory::Memcpy(Dest, &newS, sizeof(float));
|
||||
|
||||
return NewColorMapData;
|
||||
}
|
||||
@@ -0,0 +1,503 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "OculusXRPluginWrapper.h"
|
||||
#include "OculusXRHMDModule.h"
|
||||
|
||||
#if PLATFORM_ANDROID
|
||||
#include <dlfcn.h>
|
||||
#define MIN_SDK_VERSION 29
|
||||
#endif
|
||||
|
||||
DEFINE_LOG_CATEGORY(LogOculusPluginWrapper);
|
||||
|
||||
static void* LoadEntryPoint(void* handle, const char* EntryPointName);
|
||||
|
||||
bool OculusPluginWrapper::InitializeOculusPluginWrapper(OculusPluginWrapper* wrapper)
|
||||
{
|
||||
if (wrapper->IsInitialized())
|
||||
{
|
||||
UE_LOG(LogOculusPluginWrapper, Warning, TEXT("wrapper already initialized"));
|
||||
return true;
|
||||
}
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
void* LibraryHandle = nullptr;
|
||||
|
||||
#if PLATFORM_ANDROID
|
||||
const bool VersionValid = FAndroidMisc::GetAndroidBuildVersion() >= MIN_SDK_VERSION;
|
||||
#else
|
||||
const bool VersionValid = true;
|
||||
#endif
|
||||
|
||||
if (VersionValid)
|
||||
{
|
||||
LibraryHandle = FOculusXRHMDModule::GetOVRPluginHandle();
|
||||
if (LibraryHandle == nullptr)
|
||||
{
|
||||
UE_LOG(LogOculusPluginWrapper, Warning, TEXT("GetOVRPluginHandle() returned NULL"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
|
||||
struct OculusEntryPoint
|
||||
{
|
||||
const char* EntryPointName;
|
||||
void** EntryPointPtr;
|
||||
};
|
||||
|
||||
#define OCULUS_BIND_ENTRY_POINT(Func) \
|
||||
{ \
|
||||
"ovrp_" #Func, (void**)&wrapper->Func \
|
||||
}
|
||||
|
||||
OculusEntryPoint entryPointArray[] = {
|
||||
// OVR_Plugin.h
|
||||
|
||||
OCULUS_BIND_ENTRY_POINT(PreInitialize5),
|
||||
OCULUS_BIND_ENTRY_POINT(GetInitialized),
|
||||
OCULUS_BIND_ENTRY_POINT(Initialize7),
|
||||
OCULUS_BIND_ENTRY_POINT(Shutdown2),
|
||||
OCULUS_BIND_ENTRY_POINT(SetLogCallback2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetVersion2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetNativeSDKVersion2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetNativeSDKPointer2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetNativeOpenXRHandles),
|
||||
OCULUS_BIND_ENTRY_POINT(GetDisplayAdapterId2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetAudioOutId2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetAudioOutDeviceId2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetAudioInId2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetAudioInDeviceId2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetInstanceExtensionsVk),
|
||||
OCULUS_BIND_ENTRY_POINT(GetDeviceExtensionsVk),
|
||||
OCULUS_BIND_ENTRY_POINT(SetupDistortionWindow3),
|
||||
OCULUS_BIND_ENTRY_POINT(DestroyDistortionWindow2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetDominantHand),
|
||||
OCULUS_BIND_ENTRY_POINT(SetRemoteHandedness),
|
||||
OCULUS_BIND_ENTRY_POINT(SetColorScaleAndOffset),
|
||||
OCULUS_BIND_ENTRY_POINT(SetupLayer),
|
||||
OCULUS_BIND_ENTRY_POINT(SetupLayerDepth),
|
||||
OCULUS_BIND_ENTRY_POINT(SetEyeFovPremultipliedAlphaMode),
|
||||
OCULUS_BIND_ENTRY_POINT(GetEyeFovLayerId),
|
||||
OCULUS_BIND_ENTRY_POINT(GetLayerTextureStageCount),
|
||||
OCULUS_BIND_ENTRY_POINT(GetLayerTexture2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetLayerTextureFoveation),
|
||||
OCULUS_BIND_ENTRY_POINT(GetLayerOcclusionMesh),
|
||||
OCULUS_BIND_ENTRY_POINT(GetLayerAndroidSurfaceObject),
|
||||
OCULUS_BIND_ENTRY_POINT(GetLayerTextureSpaceWarp),
|
||||
OCULUS_BIND_ENTRY_POINT(CalculateEyeLayerDesc3),
|
||||
OCULUS_BIND_ENTRY_POINT(DestroyLayer),
|
||||
OCULUS_BIND_ENTRY_POINT(CalculateLayerDesc),
|
||||
OCULUS_BIND_ENTRY_POINT(CalculateEyeLayerDesc2),
|
||||
OCULUS_BIND_ENTRY_POINT(CalculateEyePreviewRect),
|
||||
OCULUS_BIND_ENTRY_POINT(SetupMirrorTexture2),
|
||||
OCULUS_BIND_ENTRY_POINT(DestroyMirrorTexture2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetAdaptiveGpuPerformanceScale2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetAppCpuStartToGpuEndTime2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetEyePixelsPerTanAngleAtCenter2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetHmdToEyeOffset2),
|
||||
OCULUS_BIND_ENTRY_POINT(Update3),
|
||||
OCULUS_BIND_ENTRY_POINT(WaitToBeginFrame),
|
||||
OCULUS_BIND_ENTRY_POINT(BeginFrame4),
|
||||
OCULUS_BIND_ENTRY_POINT(UpdateFoveation),
|
||||
OCULUS_BIND_ENTRY_POINT(EndFrame4),
|
||||
OCULUS_BIND_ENTRY_POINT(GetTrackingOrientationSupported2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetTrackingOrientationEnabled2),
|
||||
OCULUS_BIND_ENTRY_POINT(SetTrackingOrientationEnabled2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetTrackingPositionSupported2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetTrackingPositionEnabled2),
|
||||
OCULUS_BIND_ENTRY_POINT(SetTrackingPositionEnabled2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetTrackingPoseEnabledForInvisibleSession),
|
||||
OCULUS_BIND_ENTRY_POINT(SetTrackingPoseEnabledForInvisibleSession),
|
||||
OCULUS_BIND_ENTRY_POINT(GetTrackingIPDEnabled2),
|
||||
OCULUS_BIND_ENTRY_POINT(SetTrackingIPDEnabled2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetTrackingCalibratedOrigin2),
|
||||
OCULUS_BIND_ENTRY_POINT(SetTrackingCalibratedOrigin2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetTrackingOriginType2),
|
||||
OCULUS_BIND_ENTRY_POINT(SetTrackingOriginType2),
|
||||
OCULUS_BIND_ENTRY_POINT(RecenterTrackingOrigin2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetNodePresent2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetNodeOrientationTracked2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetNodeOrientationValid),
|
||||
OCULUS_BIND_ENTRY_POINT(GetNodePositionTracked2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetNodePositionValid),
|
||||
OCULUS_BIND_ENTRY_POINT(SetNodePositionTracked2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetNodePoseState3),
|
||||
OCULUS_BIND_ENTRY_POINT(GetNodePoseStateRaw),
|
||||
OCULUS_BIND_ENTRY_POINT(GetNodeFrustum2),
|
||||
OCULUS_BIND_ENTRY_POINT(SetHeadPoseModifier),
|
||||
OCULUS_BIND_ENTRY_POINT(GetHeadPoseModifier),
|
||||
OCULUS_BIND_ENTRY_POINT(GetControllerState4),
|
||||
OCULUS_BIND_ENTRY_POINT(GetControllerState5),
|
||||
OCULUS_BIND_ENTRY_POINT(GetControllerState6),
|
||||
OCULUS_BIND_ENTRY_POINT(GetActiveController2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetConnectedControllers2),
|
||||
OCULUS_BIND_ENTRY_POINT(SetControllerVibration2),
|
||||
OCULUS_BIND_ENTRY_POINT(SetControllerLocalizedVibration),
|
||||
OCULUS_BIND_ENTRY_POINT(SetControllerHapticsAmplitudeEnvelope),
|
||||
OCULUS_BIND_ENTRY_POINT(SetControllerHapticsPcm),
|
||||
OCULUS_BIND_ENTRY_POINT(GetControllerHapticsDesc2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetControllerHapticsState2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetControllerSampleRateHz),
|
||||
OCULUS_BIND_ENTRY_POINT(SetControllerHaptics2),
|
||||
OCULUS_BIND_ENTRY_POINT(SetSuggestedCpuPerformanceLevel),
|
||||
OCULUS_BIND_ENTRY_POINT(GetSuggestedCpuPerformanceLevel),
|
||||
OCULUS_BIND_ENTRY_POINT(SetSuggestedGpuPerformanceLevel),
|
||||
OCULUS_BIND_ENTRY_POINT(GetSuggestedGpuPerformanceLevel),
|
||||
OCULUS_BIND_ENTRY_POINT(GetAppCPUPriority2),
|
||||
OCULUS_BIND_ENTRY_POINT(SetAppCPUPriority2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetSystemPowerSavingMode2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetSystemDisplayFrequency2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetSystemDisplayAvailableFrequencies),
|
||||
OCULUS_BIND_ENTRY_POINT(SetSystemDisplayFrequency),
|
||||
OCULUS_BIND_ENTRY_POINT(GetSystemVSyncCount2),
|
||||
OCULUS_BIND_ENTRY_POINT(SetSystemVSyncCount2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetSystemProductName2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetSystemRegion2),
|
||||
OCULUS_BIND_ENTRY_POINT(ShowSystemUI2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetAppHasVrFocus2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetAppHasInputFocus),
|
||||
OCULUS_BIND_ENTRY_POINT(GetAppHasSystemOverlayPresent),
|
||||
OCULUS_BIND_ENTRY_POINT(GetAppShouldQuit2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetAppShouldRecenter2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetAppShouldRecreateDistortionWindow2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetAppSpace),
|
||||
OCULUS_BIND_ENTRY_POINT(GetAppLatencyTimings2),
|
||||
OCULUS_BIND_ENTRY_POINT(SetAppEngineInfo2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetUserPresent2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetUserIPD2),
|
||||
OCULUS_BIND_ENTRY_POINT(SetUserIPD2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetUserEyeHeight2),
|
||||
OCULUS_BIND_ENTRY_POINT(SetUserEyeHeight2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetUserNeckEyeDistance2),
|
||||
OCULUS_BIND_ENTRY_POINT(SetUserNeckEyeDistance2),
|
||||
OCULUS_BIND_ENTRY_POINT(SetupDisplayObjects2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetSystemMultiViewSupported2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetEyeTextureArraySupported2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetBoundaryConfigured2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetDepthCompositingSupported),
|
||||
OCULUS_BIND_ENTRY_POINT(TestBoundaryNode2),
|
||||
OCULUS_BIND_ENTRY_POINT(TestBoundaryPoint2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetBoundaryGeometry3),
|
||||
OCULUS_BIND_ENTRY_POINT(GetBoundaryDimensions2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetBoundaryVisible2),
|
||||
OCULUS_BIND_ENTRY_POINT(SetBoundaryVisible2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetSystemHeadsetType2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetAppPerfStats2),
|
||||
OCULUS_BIND_ENTRY_POINT(ResetAppPerfStats2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetAppFramerate2),
|
||||
OCULUS_BIND_ENTRY_POINT(IsPerfMetricsSupported),
|
||||
OCULUS_BIND_ENTRY_POINT(GetPerfMetricsFloat),
|
||||
OCULUS_BIND_ENTRY_POINT(GetPerfMetricsInt),
|
||||
OCULUS_BIND_ENTRY_POINT(SetHandNodePoseStateLatency),
|
||||
OCULUS_BIND_ENTRY_POINT(GetHandNodePoseStateLatency),
|
||||
OCULUS_BIND_ENTRY_POINT(GetSystemRecommendedMSAALevel2),
|
||||
OCULUS_BIND_ENTRY_POINT(SetInhibitSystemUX2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetTiledMultiResSupported),
|
||||
OCULUS_BIND_ENTRY_POINT(GetTiledMultiResLevel),
|
||||
OCULUS_BIND_ENTRY_POINT(SetTiledMultiResLevel),
|
||||
OCULUS_BIND_ENTRY_POINT(GetTiledMultiResDynamic),
|
||||
OCULUS_BIND_ENTRY_POINT(SetTiledMultiResDynamic),
|
||||
OCULUS_BIND_ENTRY_POINT(GetFoveationEyeTrackedSupported),
|
||||
OCULUS_BIND_ENTRY_POINT(GetFoveationEyeTracked),
|
||||
OCULUS_BIND_ENTRY_POINT(SetFoveationEyeTracked),
|
||||
OCULUS_BIND_ENTRY_POINT(GetFoveationEyeTrackedCenter),
|
||||
OCULUS_BIND_ENTRY_POINT(GetGPUUtilSupported),
|
||||
OCULUS_BIND_ENTRY_POINT(GetGPUUtilLevel),
|
||||
OCULUS_BIND_ENTRY_POINT(SetThreadPerformance),
|
||||
OCULUS_BIND_ENTRY_POINT(AutoThreadScheduling),
|
||||
OCULUS_BIND_ENTRY_POINT(GetGPUFrameTime),
|
||||
OCULUS_BIND_ENTRY_POINT(GetViewportStencil),
|
||||
OCULUS_BIND_ENTRY_POINT(SetDeveloperTelemetryConsent),
|
||||
OCULUS_BIND_ENTRY_POINT(SendEvent),
|
||||
OCULUS_BIND_ENTRY_POINT(SendEvent2),
|
||||
OCULUS_BIND_ENTRY_POINT(AddCustomMetadata),
|
||||
OCULUS_BIND_ENTRY_POINT(SetDeveloperMode),
|
||||
OCULUS_BIND_ENTRY_POINT(GetCurrentTrackingTransformPose),
|
||||
OCULUS_BIND_ENTRY_POINT(GetTrackingTransformRawPose),
|
||||
OCULUS_BIND_ENTRY_POINT(GetTrackingTransformRelativePose),
|
||||
OCULUS_BIND_ENTRY_POINT(GetTimeInSeconds),
|
||||
// OCULUS_BIND_ENTRY_POINT(GetPTWNear),
|
||||
OCULUS_BIND_ENTRY_POINT(GetASWVelocityScale),
|
||||
OCULUS_BIND_ENTRY_POINT(GetASWDepthScale),
|
||||
OCULUS_BIND_ENTRY_POINT(GetASWAdaptiveMode),
|
||||
OCULUS_BIND_ENTRY_POINT(SetASWAdaptiveMode),
|
||||
OCULUS_BIND_ENTRY_POINT(IsRequestingASWData),
|
||||
OCULUS_BIND_ENTRY_POINT(GetPredictedDisplayTime),
|
||||
OCULUS_BIND_ENTRY_POINT(GetHandTrackingEnabled),
|
||||
OCULUS_BIND_ENTRY_POINT(GetHandState),
|
||||
OCULUS_BIND_ENTRY_POINT(GetHandState2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetSkeleton2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetSkeleton3),
|
||||
OCULUS_BIND_ENTRY_POINT(GetMesh),
|
||||
OCULUS_BIND_ENTRY_POINT(GetLocalTrackingSpaceRecenterCount),
|
||||
OCULUS_BIND_ENTRY_POINT(GetSystemHmd3DofModeEnabled),
|
||||
OCULUS_BIND_ENTRY_POINT(SetClientColorDesc),
|
||||
OCULUS_BIND_ENTRY_POINT(GetHmdColorDesc),
|
||||
OCULUS_BIND_ENTRY_POINT(PollEvent),
|
||||
OCULUS_BIND_ENTRY_POINT(RegisterOpenXREventHandler),
|
||||
OCULUS_BIND_ENTRY_POINT(UnregisterOpenXREventHandler),
|
||||
OCULUS_BIND_ENTRY_POINT(GetNativeXrApiType),
|
||||
OCULUS_BIND_ENTRY_POINT(GetLocalDimmingSupported),
|
||||
OCULUS_BIND_ENTRY_POINT(SetLocalDimming),
|
||||
OCULUS_BIND_ENTRY_POINT(GetCurrentInteractionProfile),
|
||||
OCULUS_BIND_ENTRY_POINT(GetLayerRecommendedResolution),
|
||||
OCULUS_BIND_ENTRY_POINT(IsLayerShapeSupported),
|
||||
OCULUS_BIND_ENTRY_POINT(SetEyeBufferSharpenType),
|
||||
OCULUS_BIND_ENTRY_POINT(GetOpenXRInstanceProcAddrFunc),
|
||||
|
||||
OCULUS_BIND_ENTRY_POINT(SaveUnifiedConsent),
|
||||
OCULUS_BIND_ENTRY_POINT(SaveUnifiedConsentWithOlderVersion),
|
||||
OCULUS_BIND_ENTRY_POINT(GetUnifiedConsent),
|
||||
OCULUS_BIND_ENTRY_POINT(GetConsentTitle),
|
||||
OCULUS_BIND_ENTRY_POINT(GetConsentMarkdownText),
|
||||
OCULUS_BIND_ENTRY_POINT(GetConsentNotificationMarkdownText),
|
||||
OCULUS_BIND_ENTRY_POINT(ShouldShowTelemetryConsentWindow),
|
||||
OCULUS_BIND_ENTRY_POINT(ShouldShowTelemetryNotification),
|
||||
OCULUS_BIND_ENTRY_POINT(SetNotificationShown),
|
||||
OCULUS_BIND_ENTRY_POINT(GetConsentSettingsChangeText),
|
||||
OCULUS_BIND_ENTRY_POINT(IsConsentSettingsChangeEnabled),
|
||||
|
||||
OCULUS_BIND_ENTRY_POINT(InitializeEnvironmentDepth),
|
||||
OCULUS_BIND_ENTRY_POINT(DestroyEnvironmentDepth),
|
||||
OCULUS_BIND_ENTRY_POINT(GetEnvironmentDepthTextureDesc),
|
||||
OCULUS_BIND_ENTRY_POINT(GetEnvironmentDepthTextureStageCount),
|
||||
OCULUS_BIND_ENTRY_POINT(GetEnvironmentDepthTexture),
|
||||
OCULUS_BIND_ENTRY_POINT(SetEnvironmentDepthHandRemoval),
|
||||
OCULUS_BIND_ENTRY_POINT(StartEnvironmentDepth),
|
||||
OCULUS_BIND_ENTRY_POINT(StopEnvironmentDepth),
|
||||
OCULUS_BIND_ENTRY_POINT(GetEnvironmentDepthFrameDesc),
|
||||
|
||||
|
||||
#ifndef OVRPLUGIN_JNI_LIB_EXCLUDED
|
||||
OCULUS_BIND_ENTRY_POINT(GetSystemVolume2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetSystemHeadphonesPresent2),
|
||||
#endif
|
||||
|
||||
// Anchors
|
||||
OCULUS_BIND_ENTRY_POINT(LocateSpace),
|
||||
OCULUS_BIND_ENTRY_POINT(LocateSpace2),
|
||||
OCULUS_BIND_ENTRY_POINT(CreateSpatialAnchor),
|
||||
OCULUS_BIND_ENTRY_POINT(DestroySpace),
|
||||
OCULUS_BIND_ENTRY_POINT(SetSpaceComponentStatus),
|
||||
OCULUS_BIND_ENTRY_POINT(GetSpaceComponentStatus),
|
||||
OCULUS_BIND_ENTRY_POINT(EnumerateSpaceSupportedComponents),
|
||||
OCULUS_BIND_ENTRY_POINT(QuerySpaces),
|
||||
OCULUS_BIND_ENTRY_POINT(QuerySpaces2),
|
||||
OCULUS_BIND_ENTRY_POINT(RetrieveSpaceQueryResults),
|
||||
OCULUS_BIND_ENTRY_POINT(SaveSpace),
|
||||
OCULUS_BIND_ENTRY_POINT(EraseSpace),
|
||||
OCULUS_BIND_ENTRY_POINT(GetSpaceUuid),
|
||||
OCULUS_BIND_ENTRY_POINT(SaveSpaceList),
|
||||
OCULUS_BIND_ENTRY_POINT(ShareSpaces),
|
||||
OCULUS_BIND_ENTRY_POINT(ShareSpaces2),
|
||||
OCULUS_BIND_ENTRY_POINT(CreateSpaceUser),
|
||||
OCULUS_BIND_ENTRY_POINT(DestroySpaceUser),
|
||||
|
||||
// Anchors 2.0 (APD)
|
||||
OCULUS_BIND_ENTRY_POINT(DiscoverSpaces),
|
||||
OCULUS_BIND_ENTRY_POINT(RetrieveSpaceDiscoveryResults),
|
||||
OCULUS_BIND_ENTRY_POINT(SaveSpaces),
|
||||
OCULUS_BIND_ENTRY_POINT(EraseSpaces),
|
||||
|
||||
// Scene
|
||||
OCULUS_BIND_ENTRY_POINT(GetSpaceContainer),
|
||||
OCULUS_BIND_ENTRY_POINT(GetSpaceBoundingBox2D),
|
||||
OCULUS_BIND_ENTRY_POINT(GetSpaceBoundingBox3D),
|
||||
OCULUS_BIND_ENTRY_POINT(GetSpaceSemanticLabels),
|
||||
OCULUS_BIND_ENTRY_POINT(GetSpaceRoomLayout),
|
||||
OCULUS_BIND_ENTRY_POINT(GetSpaceBoundary2D),
|
||||
OCULUS_BIND_ENTRY_POINT(RequestSceneCapture),
|
||||
OCULUS_BIND_ENTRY_POINT(GetSpaceTriangleMesh),
|
||||
|
||||
|
||||
// Boundary Visibility
|
||||
OCULUS_BIND_ENTRY_POINT(RequestBoundaryVisibility),
|
||||
OCULUS_BIND_ENTRY_POINT(GetBoundaryVisibility),
|
||||
|
||||
// Colocation Session
|
||||
OCULUS_BIND_ENTRY_POINT(StartColocationDiscovery),
|
||||
OCULUS_BIND_ENTRY_POINT(StopColocationDiscovery),
|
||||
OCULUS_BIND_ENTRY_POINT(StartColocationAdvertisement),
|
||||
OCULUS_BIND_ENTRY_POINT(StopColocationAdvertisement),
|
||||
|
||||
// MovementSDK
|
||||
OCULUS_BIND_ENTRY_POINT(GetBodyTrackingEnabled),
|
||||
OCULUS_BIND_ENTRY_POINT(GetBodyTrackingSupported),
|
||||
OCULUS_BIND_ENTRY_POINT(StopBodyTracking),
|
||||
OCULUS_BIND_ENTRY_POINT(GetBodyState4),
|
||||
OCULUS_BIND_ENTRY_POINT(GetFullBodyTrackingEnabled),
|
||||
OCULUS_BIND_ENTRY_POINT(StartBodyTracking2),
|
||||
OCULUS_BIND_ENTRY_POINT(RequestBodyTrackingFidelity),
|
||||
OCULUS_BIND_ENTRY_POINT(ResetBodyTrackingCalibration),
|
||||
OCULUS_BIND_ENTRY_POINT(SuggestBodyTrackingCalibrationOverride),
|
||||
|
||||
OCULUS_BIND_ENTRY_POINT(GetFaceTracking2Enabled),
|
||||
OCULUS_BIND_ENTRY_POINT(GetFaceTracking2Supported),
|
||||
OCULUS_BIND_ENTRY_POINT(GetFaceState2),
|
||||
OCULUS_BIND_ENTRY_POINT(StartFaceTracking2),
|
||||
OCULUS_BIND_ENTRY_POINT(StopFaceTracking2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetEyeTrackingEnabled),
|
||||
OCULUS_BIND_ENTRY_POINT(GetEyeTrackingSupported),
|
||||
OCULUS_BIND_ENTRY_POINT(GetEyeGazesState),
|
||||
OCULUS_BIND_ENTRY_POINT(StartEyeTracking),
|
||||
OCULUS_BIND_ENTRY_POINT(StopEyeTracking),
|
||||
OCULUS_BIND_ENTRY_POINT(GetFaceTrackingVisemesSupported),
|
||||
OCULUS_BIND_ENTRY_POINT(GetFaceTrackingVisemesEnabled),
|
||||
OCULUS_BIND_ENTRY_POINT(GetFaceVisemesState),
|
||||
OCULUS_BIND_ENTRY_POINT(SetFaceTrackingVisemesEnabled),
|
||||
|
||||
// QPL
|
||||
OCULUS_BIND_ENTRY_POINT(QplMarkerStart),
|
||||
OCULUS_BIND_ENTRY_POINT(QplMarkerEnd),
|
||||
OCULUS_BIND_ENTRY_POINT(QplMarkerPoint),
|
||||
OCULUS_BIND_ENTRY_POINT(QplMarkerPointCached),
|
||||
OCULUS_BIND_ENTRY_POINT(QplMarkerAnnotation),
|
||||
OCULUS_BIND_ENTRY_POINT(QplCreateMarkerHandle),
|
||||
OCULUS_BIND_ENTRY_POINT(QplDestroyMarkerHandle),
|
||||
OCULUS_BIND_ENTRY_POINT(OnEditorShutdown),
|
||||
OCULUS_BIND_ENTRY_POINT(QplSetConsent),
|
||||
|
||||
// OVR_Plugin_Insight.h
|
||||
OCULUS_BIND_ENTRY_POINT(InitializeInsightPassthrough),
|
||||
OCULUS_BIND_ENTRY_POINT(ShutdownInsightPassthrough),
|
||||
OCULUS_BIND_ENTRY_POINT(GetInsightPassthroughInitialized),
|
||||
OCULUS_BIND_ENTRY_POINT(GetInsightPassthroughInitializationState),
|
||||
OCULUS_BIND_ENTRY_POINT(CreateInsightTriangleMesh),
|
||||
OCULUS_BIND_ENTRY_POINT(DestroyInsightTriangleMesh),
|
||||
OCULUS_BIND_ENTRY_POINT(AddInsightPassthroughSurfaceGeometry),
|
||||
OCULUS_BIND_ENTRY_POINT(DestroyInsightPassthroughGeometryInstance),
|
||||
OCULUS_BIND_ENTRY_POINT(UpdateInsightPassthroughGeometryTransform),
|
||||
OCULUS_BIND_ENTRY_POINT(SetInsightPassthroughStyle),
|
||||
OCULUS_BIND_ENTRY_POINT(SetInsightPassthroughStyle2),
|
||||
OCULUS_BIND_ENTRY_POINT(GetPassthroughCapabilityFlags),
|
||||
OCULUS_BIND_ENTRY_POINT(CreatePassthroughColorLut),
|
||||
OCULUS_BIND_ENTRY_POINT(DestroyPassthroughColorLut),
|
||||
OCULUS_BIND_ENTRY_POINT(UpdatePassthroughColorLut),
|
||||
OCULUS_BIND_ENTRY_POINT(GetPassthroughCapabilities),
|
||||
OCULUS_BIND_ENTRY_POINT(GetPassthroughPreferences),
|
||||
|
||||
// OVR_Plugin_MixedReality.h
|
||||
|
||||
OCULUS_BIND_ENTRY_POINT(InitializeMixedReality),
|
||||
OCULUS_BIND_ENTRY_POINT(ShutdownMixedReality),
|
||||
OCULUS_BIND_ENTRY_POINT(GetMixedRealityInitialized),
|
||||
OCULUS_BIND_ENTRY_POINT(UpdateExternalCamera),
|
||||
OCULUS_BIND_ENTRY_POINT(GetExternalCameraCount),
|
||||
OCULUS_BIND_ENTRY_POINT(GetExternalCameraName),
|
||||
OCULUS_BIND_ENTRY_POINT(GetExternalCameraIntrinsics),
|
||||
OCULUS_BIND_ENTRY_POINT(GetExternalCameraExtrinsics),
|
||||
|
||||
// OVR_Plugin_Media.h
|
||||
|
||||
OCULUS_BIND_ENTRY_POINT(Media_Initialize),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_Shutdown),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_GetInitialized),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_Update),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_GetMrcActivationMode),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_SetMrcActivationMode),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_IsMrcEnabled),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_IsMrcActivated),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_UseMrcDebugCamera),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_SetMrcInputVideoBufferType),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_GetMrcInputVideoBufferType),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_SetMrcFrameSize),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_GetMrcFrameSize),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_SetMrcAudioSampleRate),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_GetMrcAudioSampleRate),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_SetMrcFrameImageFlipped),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_GetMrcFrameImageFlipped),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_SetMrcFrameInverseAlpha),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_GetMrcFrameInverseAlpha),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_SetAvailableQueueIndexVulkan),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_EncodeMrcFrame),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_EncodeMrcFrameWithDualTextures),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_SyncMrcFrame),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_EncodeMrcFrameWithPoseTime),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_EncodeMrcFrameDualTexturesWithPoseTime),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_SetHeadsetControllerPose),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_EnumerateCameraAnchorHandles),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_GetCurrentCameraAnchorHandle),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_GetCameraAnchorName),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_GetCameraAnchorHandle),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_GetCameraAnchorType),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_CreateCustomCameraAnchor),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_DestroyCustomCameraAnchor),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_GetCustomCameraAnchorPose),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_SetCustomCameraAnchorPose),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_GetCameraMinMaxDistance),
|
||||
OCULUS_BIND_ENTRY_POINT(Media_SetCameraMinMaxDistance),
|
||||
|
||||
OCULUS_BIND_ENTRY_POINT(SetControllerDrivenHandPoses),
|
||||
OCULUS_BIND_ENTRY_POINT(SetControllerDrivenHandPosesAreNatural),
|
||||
};
|
||||
|
||||
#undef OCULUS_BIND_ENTRY_POINT
|
||||
|
||||
bool result = true;
|
||||
for (int i = 0; i < UE_ARRAY_COUNT(entryPointArray); ++i)
|
||||
{
|
||||
*(entryPointArray[i].EntryPointPtr) = LoadEntryPoint(LibraryHandle, entryPointArray[i].EntryPointName);
|
||||
|
||||
if (*entryPointArray[i].EntryPointPtr == nullptr)
|
||||
{
|
||||
UE_LOG(LogOculusPluginWrapper, Error, TEXT("OculusPlugin EntryPoint could not be loaded: %s"), ANSI_TO_TCHAR(entryPointArray[i].EntryPointName));
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
wrapper->Initialized = true;
|
||||
|
||||
if (result)
|
||||
{
|
||||
UE_LOG(LogOculusPluginWrapper, Log, TEXT("OculusPlugin initialized successfully"));
|
||||
}
|
||||
else
|
||||
{
|
||||
DestroyOculusPluginWrapper(wrapper);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void OculusPluginWrapper::DestroyOculusPluginWrapper(OculusPluginWrapper* wrapper)
|
||||
{
|
||||
if (!wrapper->Initialized)
|
||||
return;
|
||||
|
||||
wrapper->Reset();
|
||||
|
||||
UE_LOG(LogOculusPluginWrapper, Log, TEXT("OculusPlugin destroyed successfully"));
|
||||
}
|
||||
|
||||
static void* LoadEntryPoint(void* Handle, const char* EntryPointName)
|
||||
{
|
||||
if (Handle == nullptr)
|
||||
return nullptr;
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
void* ptr = GetProcAddress((HMODULE)Handle, EntryPointName);
|
||||
if (ptr == nullptr)
|
||||
{
|
||||
UE_LOG(LogOculusPluginWrapper, Error, TEXT("Unable to load entry point: %s"), ANSI_TO_TCHAR(EntryPointName));
|
||||
}
|
||||
return ptr;
|
||||
#elif PLATFORM_ANDROID
|
||||
void* ptr = dlsym(Handle, EntryPointName);
|
||||
if (ptr == nullptr)
|
||||
{
|
||||
UE_LOG(LogOculusPluginWrapper, Error, TEXT("Unable to load entry point: %s, error %s"), ANSI_TO_TCHAR(EntryPointName), ANSI_TO_TCHAR(dlerror()));
|
||||
}
|
||||
return ptr;
|
||||
#else
|
||||
UE_LOG(LogOculusPluginWrapper, Error, TEXT("LoadEntryPoint: Unsupported platform"));
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,452 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include <memory.h>
|
||||
|
||||
#if PLATFORM_SUPPORTS_PRAGMA_PACK
|
||||
#pragma pack(push, 8)
|
||||
#endif
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#include "Windows/AllowWindowsPlatformTypes.h"
|
||||
#endif
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4201) // nonstandard extension used: nameless struct/union
|
||||
// #pragma warning(disable:4668) // 'symbol' is not defined as a preprocessor macro, replacing with '0' for 'directives'
|
||||
#define OVRP_EXPORT typedef
|
||||
#include "OVR_Plugin.h"
|
||||
#include "OVR_Plugin_Insight.h"
|
||||
#include "OVR_Plugin_MixedReality.h"
|
||||
#include "OVR_Plugin_Media.h"
|
||||
#undef OVRP_EXPORT
|
||||
#pragma warning(pop)
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#include "Windows/HideWindowsPlatformTypes.h"
|
||||
#endif
|
||||
|
||||
#if PLATFORM_SUPPORTS_PRAGMA_PACK
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#include "Windows/WindowsHWrapper.h"
|
||||
#endif
|
||||
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogOculusPluginWrapper, Log, All);
|
||||
|
||||
#define OCULUS_DECLARE_ENTRY_POINT(Func) ovrp_##Func* Func
|
||||
|
||||
struct OculusPluginWrapper
|
||||
{
|
||||
OculusPluginWrapper()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
memset(this, 0, sizeof(OculusPluginWrapper));
|
||||
ovrpHeaderVersion.MajorVersion = OVRP_MAJOR_VERSION;
|
||||
ovrpHeaderVersion.MinorVersion = OVRP_MINOR_VERSION;
|
||||
ovrpHeaderVersion.PatchVersion = OVRP_PATCH_VERSION;
|
||||
}
|
||||
|
||||
bool IsInitialized() const
|
||||
{
|
||||
return Initialized;
|
||||
}
|
||||
|
||||
// OVR_Plugin.h
|
||||
|
||||
OCULUS_DECLARE_ENTRY_POINT(PreInitialize5);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetInitialized);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Initialize7);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Shutdown2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetLogCallback2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetVersion2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetNativeSDKVersion2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetNativeSDKPointer2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetNativeOpenXRHandles);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetDisplayAdapterId2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetAudioOutId2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetAudioOutDeviceId2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetAudioInId2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetAudioInDeviceId2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetInstanceExtensionsVk);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetDeviceExtensionsVk);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetupDistortionWindow3);
|
||||
OCULUS_DECLARE_ENTRY_POINT(DestroyDistortionWindow2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetDominantHand);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetRemoteHandedness);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetColorScaleAndOffset);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetupLayer);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetupLayerDepth);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetEyeFovPremultipliedAlphaMode);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetEyeFovLayerId);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetLayerTextureStageCount);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetLayerTexture2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetLayerTextureFoveation);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetLayerTextureSpaceWarp);
|
||||
OCULUS_DECLARE_ENTRY_POINT(CalculateEyeLayerDesc3);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetLayerAndroidSurfaceObject);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetLayerOcclusionMesh);
|
||||
OCULUS_DECLARE_ENTRY_POINT(DestroyLayer);
|
||||
OCULUS_DECLARE_ENTRY_POINT(CalculateLayerDesc);
|
||||
OCULUS_DECLARE_ENTRY_POINT(CalculateEyeLayerDesc2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(CalculateEyePreviewRect);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetupMirrorTexture2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(DestroyMirrorTexture2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetAdaptiveGpuPerformanceScale2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetAppCpuStartToGpuEndTime2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetEyePixelsPerTanAngleAtCenter2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetHmdToEyeOffset2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Update3);
|
||||
OCULUS_DECLARE_ENTRY_POINT(WaitToBeginFrame);
|
||||
OCULUS_DECLARE_ENTRY_POINT(BeginFrame4);
|
||||
OCULUS_DECLARE_ENTRY_POINT(UpdateFoveation);
|
||||
OCULUS_DECLARE_ENTRY_POINT(EndFrame4);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetTrackingOrientationSupported2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetTrackingOrientationEnabled2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetTrackingOrientationEnabled2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetTrackingPositionSupported2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetTrackingPositionEnabled2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetTrackingPositionEnabled2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetTrackingPoseEnabledForInvisibleSession);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetTrackingPoseEnabledForInvisibleSession);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetTrackingIPDEnabled2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetTrackingIPDEnabled2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetTrackingCalibratedOrigin2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetTrackingCalibratedOrigin2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetTrackingOriginType2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetTrackingOriginType2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(RecenterTrackingOrigin2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetNodePresent2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetNodeOrientationTracked2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetNodeOrientationValid);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetNodePositionTracked2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetNodePositionValid);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetNodePositionTracked2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetNodePoseState3);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetNodePoseStateRaw);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetNodeFrustum2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetHeadPoseModifier);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetHeadPoseModifier);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetControllerState4);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetControllerState5);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetControllerState6);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetActiveController2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetConnectedControllers2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetControllerVibration2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetControllerLocalizedVibration);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetControllerHapticsAmplitudeEnvelope);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetControllerHapticsPcm);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetControllerHapticsDesc2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetControllerHapticsState2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetControllerSampleRateHz);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetControllerHaptics2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetSuggestedCpuPerformanceLevel);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetSuggestedCpuPerformanceLevel);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetSuggestedGpuPerformanceLevel);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetSuggestedGpuPerformanceLevel);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetAppCPUPriority2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetAppCPUPriority2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetSystemPowerSavingMode2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetSystemDisplayFrequency2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetSystemDisplayAvailableFrequencies);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetSystemDisplayFrequency);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetSystemVSyncCount2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetSystemVSyncCount2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetSystemProductName2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetSystemRegion2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(ShowSystemUI2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetAppHasVrFocus2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetAppHasInputFocus);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetAppHasSystemOverlayPresent);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetAppShouldQuit2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetAppShouldRecenter2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetAppShouldRecreateDistortionWindow2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetAppSpace);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetAppLatencyTimings2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetAppEngineInfo2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetUserPresent2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetUserIPD2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetUserIPD2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetUserEyeHeight2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetUserEyeHeight2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetUserNeckEyeDistance2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetUserNeckEyeDistance2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetupDisplayObjects2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetSystemMultiViewSupported2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetEyeTextureArraySupported2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetBoundaryConfigured2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetDepthCompositingSupported);
|
||||
OCULUS_DECLARE_ENTRY_POINT(TestBoundaryNode2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(TestBoundaryPoint2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetBoundaryGeometry3);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetBoundaryDimensions2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetBoundaryVisible2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetBoundaryVisible2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetSystemHeadsetType2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetAppPerfStats2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(ResetAppPerfStats2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetAppFramerate2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(IsPerfMetricsSupported);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetPerfMetricsFloat);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetPerfMetricsInt);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetHandNodePoseStateLatency);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetHandNodePoseStateLatency);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetSystemRecommendedMSAALevel2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetInhibitSystemUX2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetTiledMultiResSupported);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetTiledMultiResLevel);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetTiledMultiResLevel);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetTiledMultiResDynamic);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetTiledMultiResDynamic);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetFoveationEyeTrackedSupported);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetFoveationEyeTracked);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetFoveationEyeTracked);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetFoveationEyeTrackedCenter);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetGPUUtilSupported);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetGPUUtilLevel);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetThreadPerformance);
|
||||
OCULUS_DECLARE_ENTRY_POINT(AutoThreadScheduling);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetGPUFrameTime);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetViewportStencil);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetDeveloperTelemetryConsent);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SendEvent);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SendEvent2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(AddCustomMetadata);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetDeveloperMode);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetCurrentTrackingTransformPose);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetTrackingTransformRawPose);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetTrackingTransformRelativePose);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetTimeInSeconds);
|
||||
// OCULUS_DECLARE_ENTRY_POINT(GetPTWNear);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetASWVelocityScale);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetASWDepthScale);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetASWAdaptiveMode);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetASWAdaptiveMode);
|
||||
OCULUS_DECLARE_ENTRY_POINT(IsRequestingASWData);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetPredictedDisplayTime);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetHandTrackingEnabled);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetHandState);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetHandState2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetSkeleton2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetSkeleton3);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetMesh);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetLocalTrackingSpaceRecenterCount);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetSystemHmd3DofModeEnabled);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetClientColorDesc);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetHmdColorDesc);
|
||||
OCULUS_DECLARE_ENTRY_POINT(PollEvent);
|
||||
OCULUS_DECLARE_ENTRY_POINT(RegisterOpenXREventHandler);
|
||||
OCULUS_DECLARE_ENTRY_POINT(UnregisterOpenXREventHandler);
|
||||
|
||||
OCULUS_DECLARE_ENTRY_POINT(SaveUnifiedConsent);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SaveUnifiedConsentWithOlderVersion);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetUnifiedConsent);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetConsentTitle);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetConsentMarkdownText);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetConsentNotificationMarkdownText);
|
||||
OCULUS_DECLARE_ENTRY_POINT(ShouldShowTelemetryConsentWindow);
|
||||
OCULUS_DECLARE_ENTRY_POINT(ShouldShowTelemetryNotification);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetNotificationShown);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetConsentSettingsChangeText);
|
||||
OCULUS_DECLARE_ENTRY_POINT(IsConsentSettingsChangeEnabled);
|
||||
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetNativeXrApiType);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetLocalDimmingSupported);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetLocalDimming);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetCurrentInteractionProfile);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetLayerRecommendedResolution);
|
||||
OCULUS_DECLARE_ENTRY_POINT(IsLayerShapeSupported);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetEyeBufferSharpenType);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetOpenXRInstanceProcAddrFunc);
|
||||
|
||||
OCULUS_DECLARE_ENTRY_POINT(InitializeEnvironmentDepth);
|
||||
OCULUS_DECLARE_ENTRY_POINT(DestroyEnvironmentDepth);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetEnvironmentDepthTextureDesc);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetEnvironmentDepthTextureStageCount);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetEnvironmentDepthTexture);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetEnvironmentDepthHandRemoval);
|
||||
OCULUS_DECLARE_ENTRY_POINT(StartEnvironmentDepth);
|
||||
OCULUS_DECLARE_ENTRY_POINT(StopEnvironmentDepth);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetEnvironmentDepthFrameDesc);
|
||||
|
||||
|
||||
#ifndef OVRPLUGIN_JNI_LIB_EXCLUDED
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetSystemVolume2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetSystemHeadphonesPresent2);
|
||||
#endif
|
||||
|
||||
// Anchors
|
||||
OCULUS_DECLARE_ENTRY_POINT(LocateSpace);
|
||||
OCULUS_DECLARE_ENTRY_POINT(LocateSpace2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(CreateSpatialAnchor);
|
||||
OCULUS_DECLARE_ENTRY_POINT(DestroySpace);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetSpaceComponentStatus);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetSpaceComponentStatus);
|
||||
OCULUS_DECLARE_ENTRY_POINT(EnumerateSpaceSupportedComponents);
|
||||
OCULUS_DECLARE_ENTRY_POINT(QuerySpaces);
|
||||
OCULUS_DECLARE_ENTRY_POINT(QuerySpaces2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(RetrieveSpaceQueryResults);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SaveSpace);
|
||||
OCULUS_DECLARE_ENTRY_POINT(EraseSpace);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetSpaceUuid);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SaveSpaceList);
|
||||
OCULUS_DECLARE_ENTRY_POINT(ShareSpaces);
|
||||
OCULUS_DECLARE_ENTRY_POINT(ShareSpaces2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(CreateSpaceUser);
|
||||
OCULUS_DECLARE_ENTRY_POINT(DestroySpaceUser);
|
||||
|
||||
// Anchors 2.0 (APD)
|
||||
OCULUS_DECLARE_ENTRY_POINT(DiscoverSpaces);
|
||||
OCULUS_DECLARE_ENTRY_POINT(RetrieveSpaceDiscoveryResults);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SaveSpaces);
|
||||
OCULUS_DECLARE_ENTRY_POINT(EraseSpaces);
|
||||
|
||||
// Scene
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetSpaceContainer);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetSpaceBoundingBox2D);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetSpaceBoundingBox3D);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetSpaceSemanticLabels);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetSpaceRoomLayout);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetSpaceBoundary2D);
|
||||
OCULUS_DECLARE_ENTRY_POINT(RequestSceneCapture);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetSpaceTriangleMesh);
|
||||
|
||||
|
||||
// Boundary Visibility
|
||||
OCULUS_DECLARE_ENTRY_POINT(RequestBoundaryVisibility);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetBoundaryVisibility);
|
||||
|
||||
// Colocation Session
|
||||
OCULUS_DECLARE_ENTRY_POINT(StartColocationDiscovery);
|
||||
OCULUS_DECLARE_ENTRY_POINT(StopColocationDiscovery);
|
||||
OCULUS_DECLARE_ENTRY_POINT(StartColocationAdvertisement);
|
||||
OCULUS_DECLARE_ENTRY_POINT(StopColocationAdvertisement);
|
||||
|
||||
// MovementSDK
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetBodyTrackingEnabled);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetBodyTrackingSupported);
|
||||
OCULUS_DECLARE_ENTRY_POINT(StopBodyTracking);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetBodyState4);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetFullBodyTrackingEnabled);
|
||||
OCULUS_DECLARE_ENTRY_POINT(StartBodyTracking2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(RequestBodyTrackingFidelity);
|
||||
OCULUS_DECLARE_ENTRY_POINT(ResetBodyTrackingCalibration);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SuggestBodyTrackingCalibrationOverride);
|
||||
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetFaceTracking2Enabled);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetFaceTracking2Supported);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetFaceState2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(StartFaceTracking2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(StopFaceTracking2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetEyeTrackingEnabled);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetEyeTrackingSupported);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetEyeGazesState);
|
||||
OCULUS_DECLARE_ENTRY_POINT(StartEyeTracking);
|
||||
OCULUS_DECLARE_ENTRY_POINT(StopEyeTracking);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetFaceTrackingVisemesSupported);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetFaceTrackingVisemesEnabled);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetFaceVisemesState);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetFaceTrackingVisemesEnabled);
|
||||
|
||||
// QPL
|
||||
OCULUS_DECLARE_ENTRY_POINT(QplMarkerStart);
|
||||
OCULUS_DECLARE_ENTRY_POINT(QplMarkerEnd);
|
||||
OCULUS_DECLARE_ENTRY_POINT(QplMarkerPoint);
|
||||
OCULUS_DECLARE_ENTRY_POINT(QplMarkerPointCached);
|
||||
OCULUS_DECLARE_ENTRY_POINT(QplMarkerAnnotation);
|
||||
OCULUS_DECLARE_ENTRY_POINT(QplCreateMarkerHandle);
|
||||
OCULUS_DECLARE_ENTRY_POINT(QplDestroyMarkerHandle);
|
||||
OCULUS_DECLARE_ENTRY_POINT(OnEditorShutdown);
|
||||
OCULUS_DECLARE_ENTRY_POINT(QplSetConsent);
|
||||
|
||||
// OVR_Plugin_Insight.h
|
||||
OCULUS_DECLARE_ENTRY_POINT(InitializeInsightPassthrough);
|
||||
OCULUS_DECLARE_ENTRY_POINT(ShutdownInsightPassthrough);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetInsightPassthroughInitialized);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetInsightPassthroughInitializationState);
|
||||
OCULUS_DECLARE_ENTRY_POINT(CreateInsightTriangleMesh);
|
||||
OCULUS_DECLARE_ENTRY_POINT(DestroyInsightTriangleMesh);
|
||||
OCULUS_DECLARE_ENTRY_POINT(AddInsightPassthroughSurfaceGeometry);
|
||||
OCULUS_DECLARE_ENTRY_POINT(DestroyInsightPassthroughGeometryInstance);
|
||||
OCULUS_DECLARE_ENTRY_POINT(UpdateInsightPassthroughGeometryTransform);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetInsightPassthroughStyle);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetInsightPassthroughStyle2);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetPassthroughCapabilityFlags);
|
||||
OCULUS_DECLARE_ENTRY_POINT(CreatePassthroughColorLut);
|
||||
OCULUS_DECLARE_ENTRY_POINT(DestroyPassthroughColorLut);
|
||||
OCULUS_DECLARE_ENTRY_POINT(UpdatePassthroughColorLut);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetPassthroughCapabilities);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetPassthroughPreferences);
|
||||
|
||||
// OVR_Plugin_MixedReality.h
|
||||
|
||||
OCULUS_DECLARE_ENTRY_POINT(InitializeMixedReality);
|
||||
OCULUS_DECLARE_ENTRY_POINT(ShutdownMixedReality);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetMixedRealityInitialized);
|
||||
OCULUS_DECLARE_ENTRY_POINT(UpdateExternalCamera);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetExternalCameraCount);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetExternalCameraName);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetExternalCameraIntrinsics);
|
||||
OCULUS_DECLARE_ENTRY_POINT(GetExternalCameraExtrinsics);
|
||||
|
||||
// OVR_Plugin_Media.h
|
||||
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_Initialize);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_Shutdown);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_GetInitialized);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_Update);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_GetMrcActivationMode);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_SetMrcActivationMode);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_IsMrcEnabled);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_IsMrcActivated);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_UseMrcDebugCamera);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_SetMrcInputVideoBufferType);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_GetMrcInputVideoBufferType);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_SetMrcFrameSize);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_GetMrcFrameSize);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_SetMrcAudioSampleRate);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_GetMrcAudioSampleRate);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_SetMrcFrameImageFlipped);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_GetMrcFrameImageFlipped);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_SetMrcFrameInverseAlpha);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_GetMrcFrameInverseAlpha);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_SetAvailableQueueIndexVulkan);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_EncodeMrcFrame);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_EncodeMrcFrameWithDualTextures);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_SyncMrcFrame);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_EncodeMrcFrameWithPoseTime);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_EncodeMrcFrameDualTexturesWithPoseTime);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_SetHeadsetControllerPose);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_EnumerateCameraAnchorHandles);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_GetCurrentCameraAnchorHandle);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_GetCameraAnchorName);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_GetCameraAnchorHandle);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_GetCameraAnchorType);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_CreateCustomCameraAnchor);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_DestroyCustomCameraAnchor);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_GetCustomCameraAnchorPose);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_SetCustomCameraAnchorPose);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_GetCameraMinMaxDistance);
|
||||
OCULUS_DECLARE_ENTRY_POINT(Media_SetCameraMinMaxDistance);
|
||||
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetControllerDrivenHandPoses);
|
||||
OCULUS_DECLARE_ENTRY_POINT(SetControllerDrivenHandPosesAreNatural);
|
||||
|
||||
static bool InitializeOculusPluginWrapper(OculusPluginWrapper* wrapper);
|
||||
static void DestroyOculusPluginWrapper(OculusPluginWrapper* wrapper);
|
||||
|
||||
private:
|
||||
ovrpVersion ovrpHeaderVersion;
|
||||
bool Initialized;
|
||||
};
|
||||
|
||||
#undef OCULUS_DECLARE_ENTRY_POINT
|
||||
130
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRQPL.cpp
Normal file
130
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRQPL.cpp
Normal file
@@ -0,0 +1,130 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#include "OculusXRQPL.h"
|
||||
#include "OculusXRHMDModule.h"
|
||||
#include "OculusXRPluginWrapper.h"
|
||||
|
||||
namespace OculusXRTelemetry
|
||||
{
|
||||
namespace QPL
|
||||
{
|
||||
bool MarkerStart(const int MarkerId, const FTelemetryInstanceKey InstanceKey, const FTelemetryTimestamp Timestamp)
|
||||
{
|
||||
const ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().QplMarkerStart(
|
||||
MarkerId,
|
||||
InstanceKey.GetValue(),
|
||||
Timestamp.GetTimestamp());
|
||||
|
||||
return OVRP_SUCCESS(Result);
|
||||
}
|
||||
bool MarkerEnd(const int MarkerId, const EAction Action, const FTelemetryInstanceKey InstanceKey, const FTelemetryTimestamp Timestamp)
|
||||
{
|
||||
const ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().QplMarkerEnd(
|
||||
MarkerId,
|
||||
static_cast<short>(Action),
|
||||
InstanceKey.GetValue(),
|
||||
Timestamp.GetTimestamp());
|
||||
|
||||
return OVRP_SUCCESS(Result);
|
||||
}
|
||||
|
||||
bool MarkerPoint(const int MarkerId, const char* Name, const FTelemetryInstanceKey InstanceKey, const FTelemetryTimestamp Timestamp)
|
||||
{
|
||||
const ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().QplMarkerPoint(
|
||||
MarkerId,
|
||||
Name,
|
||||
InstanceKey.GetValue(),
|
||||
Timestamp.GetTimestamp());
|
||||
|
||||
return OVRP_SUCCESS(Result);
|
||||
}
|
||||
|
||||
bool MarkerPointCached(const int MarkerId, const int NameHandle, const FTelemetryInstanceKey InstanceKey, const FTelemetryTimestamp Timestamp)
|
||||
{
|
||||
const ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().QplMarkerPointCached(
|
||||
MarkerId,
|
||||
NameHandle,
|
||||
InstanceKey.GetValue(),
|
||||
Timestamp.GetTimestamp());
|
||||
|
||||
return OVRP_SUCCESS(Result);
|
||||
}
|
||||
|
||||
bool MarkerAnnotation(const int MarkerId, const char* AnnotationKey, const char* AnnotationValue, const FTelemetryInstanceKey InstanceKey)
|
||||
{
|
||||
if (nullptr == AnnotationValue)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().QplMarkerAnnotation(
|
||||
MarkerId,
|
||||
AnnotationKey,
|
||||
AnnotationValue,
|
||||
InstanceKey.GetValue());
|
||||
|
||||
return OVRP_SUCCESS(Result);
|
||||
}
|
||||
|
||||
bool CreateMarkerHandle(const char* Name, int* NameHandle)
|
||||
{
|
||||
if (nullptr == NameHandle)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().QplCreateMarkerHandle(
|
||||
Name,
|
||||
NameHandle);
|
||||
|
||||
return OVRP_SUCCESS(Result);
|
||||
}
|
||||
|
||||
bool DestroyMarkerHandle(const int NameHandle)
|
||||
{
|
||||
const ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().QplDestroyMarkerHandle(
|
||||
NameHandle);
|
||||
|
||||
return OVRP_SUCCESS(Result);
|
||||
}
|
||||
|
||||
bool OnEditorShutdown()
|
||||
{
|
||||
const ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().OnEditorShutdown();
|
||||
|
||||
return OVRP_SUCCESS(Result);
|
||||
}
|
||||
|
||||
} // namespace QPL
|
||||
bool FQPLBackend::MarkerStart(const int MarkerId, const FTelemetryInstanceKey InstanceKey, const FTelemetryTimestamp Timestamp)
|
||||
{
|
||||
return QPL::MarkerStart(MarkerId, InstanceKey, Timestamp);
|
||||
}
|
||||
bool FQPLBackend::MarkerEnd(const int MarkerId, const EAction Action, const FTelemetryInstanceKey InstanceKey, const FTelemetryTimestamp Timestamp)
|
||||
{
|
||||
return QPL::MarkerEnd(MarkerId, Action, InstanceKey, Timestamp);
|
||||
};
|
||||
bool FQPLBackend::MarkerPoint(const int MarkerId, const char* Name, const FTelemetryInstanceKey InstanceKey, const FTelemetryTimestamp Timestamp)
|
||||
{
|
||||
return QPL::MarkerPoint(MarkerId, Name, InstanceKey, Timestamp);
|
||||
};
|
||||
bool FQPLBackend::MarkerPointCached(const int MarkerId, const int NameHandle, const FTelemetryInstanceKey InstanceKey, const FTelemetryTimestamp Timestamp)
|
||||
{
|
||||
return QPL::MarkerPointCached(MarkerId, NameHandle, InstanceKey, Timestamp);
|
||||
};
|
||||
bool FQPLBackend::MarkerAnnotation(const int MarkerId, const char* AnnotationKey, const char* AnnotationValue, const FTelemetryInstanceKey InstanceKey)
|
||||
{
|
||||
return QPL::MarkerAnnotation(MarkerId, AnnotationKey, AnnotationValue, InstanceKey);
|
||||
};
|
||||
bool FQPLBackend::CreateMarkerHandle(const char* Name, int* NameHandle)
|
||||
{
|
||||
return QPL::CreateMarkerHandle(Name, NameHandle);
|
||||
};
|
||||
bool FQPLBackend::DestroyMarkerHandle(const int NameHandle)
|
||||
{
|
||||
return QPL::DestroyMarkerHandle(NameHandle);
|
||||
};
|
||||
bool FQPLBackend::OnEditorShutdown()
|
||||
{
|
||||
return QPL::OnEditorShutdown();
|
||||
};
|
||||
} // namespace OculusXRTelemetry
|
||||
@@ -0,0 +1,27 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "OculusXRResourceHolder.h"
|
||||
#include "HeadMountedDisplayTypes.h" // for LogHMD
|
||||
#include "UObject/ConstructorHelpers.h"
|
||||
#include "Materials/Material.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// UOculusResourceManager
|
||||
|
||||
UOculusXRResourceHolder::UOculusXRResourceHolder(const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
static ConstructorHelpers::FObjectFinder<UMaterial> StaticPokeAHoleMaterial(TEXT("/OculusXR/Materials/PokeAHoleMaterial"));
|
||||
|
||||
PokeAHoleMaterial = StaticPokeAHoleMaterial.Object;
|
||||
|
||||
if (!PokeAHoleMaterial)
|
||||
{
|
||||
UE_LOG(LogHMD, Error, TEXT("Unable to load PokeAHoleMaterial"));
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogHMD, Log, TEXT("PokeAHoleMaterial loaded successfully"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "UObject/Object.h"
|
||||
#include "Materials/MaterialInterface.h"
|
||||
#include "OculusXRResourceHolder.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class UOculusXRResourceHolder : public UObject
|
||||
{
|
||||
GENERATED_UCLASS_BODY()
|
||||
|
||||
public:
|
||||
UPROPERTY()
|
||||
UMaterial* PokeAHoleMaterial;
|
||||
};
|
||||
@@ -0,0 +1,193 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "OculusXRSceneCaptureCubemap.h"
|
||||
#include "OculusXRHMDPrivate.h"
|
||||
#include "IImageWrapper.h"
|
||||
#include "IImageWrapperModule.h"
|
||||
#include "Kismet/GameplayStatics.h"
|
||||
#include "GameFramework/PlayerController.h"
|
||||
#include "Components/SceneCaptureComponent2D.h"
|
||||
#include "Engine/World.h"
|
||||
#include "Engine/StaticMeshActor.h"
|
||||
#include "Engine/TextureRenderTarget2D.h"
|
||||
#include "TextureResource.h"
|
||||
#include "HAL/FileManager.h"
|
||||
#include "Misc/FileHelper.h"
|
||||
#include "XRThreadUtils.h"
|
||||
#include "RenderingThread.h"
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// UOculusXRSceneCaptureCubemap
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
UOculusXRSceneCaptureCubemap::UOculusXRSceneCaptureCubemap()
|
||||
: Stage(None)
|
||||
, CaptureBoxSideRes(2048)
|
||||
, CaptureFormat(EPixelFormat::PF_A16B16G16R16)
|
||||
, OverriddenLocation(FVector::ZeroVector)
|
||||
, OverriddenOrientation(FQuat::Identity)
|
||||
, CaptureOffset(FVector::ZeroVector)
|
||||
{
|
||||
}
|
||||
|
||||
void UOculusXRSceneCaptureCubemap::StartCapture(UWorld* World, uint32 InCaptureBoxSideRes, EPixelFormat InFormat)
|
||||
{
|
||||
CaptureBoxSideRes = InCaptureBoxSideRes;
|
||||
CaptureFormat = InFormat;
|
||||
|
||||
FVector Location = OverriddenLocation;
|
||||
FQuat Orientation = OverriddenOrientation;
|
||||
|
||||
APlayerController* CapturePlayerController = UGameplayStatics::GetPlayerController(GWorld, 0);
|
||||
if (CapturePlayerController)
|
||||
{
|
||||
FRotator Rotation;
|
||||
CapturePlayerController->GetPlayerViewPoint(Location, Rotation);
|
||||
Rotation.Pitch = Rotation.Roll = 0;
|
||||
Orientation = FQuat(Rotation);
|
||||
|
||||
Location += CaptureOffset;
|
||||
}
|
||||
|
||||
if (!OverriddenOrientation.IsIdentity())
|
||||
{
|
||||
Orientation = OverriddenOrientation;
|
||||
}
|
||||
if (!OverriddenLocation.IsZero())
|
||||
{
|
||||
Location = OverriddenLocation;
|
||||
}
|
||||
|
||||
const FVector ZAxis(0, 0, 1);
|
||||
const FVector YAxis(0, 1, 0);
|
||||
const FQuat FaceOrientations[] = { { ZAxis, PI / 2 }, { ZAxis, -PI / 2 }, // right, left
|
||||
{ YAxis, -PI / 2 }, { YAxis, PI / 2 }, // top, bottom
|
||||
{ ZAxis, 0 }, { ZAxis, -PI } }; // front, back
|
||||
|
||||
for (int i = 0; i < 6; ++i)
|
||||
{
|
||||
USceneCaptureComponent2D* CaptureComponent = NewObject<USceneCaptureComponent2D>();
|
||||
CaptureComponent->SetVisibility(true);
|
||||
CaptureComponent->SetHiddenInGame(false);
|
||||
|
||||
CaptureComponent->FOVAngle = 90.f;
|
||||
CaptureComponent->bCaptureEveryFrame = true;
|
||||
CaptureComponent->CaptureSource = ESceneCaptureSource::SCS_FinalColorLDR;
|
||||
|
||||
const FName TargetName = MakeUniqueObjectName(this, UTextureRenderTarget2D::StaticClass(), TEXT("SceneCaptureTextureTarget"));
|
||||
CaptureComponent->TextureTarget = NewObject<UTextureRenderTarget2D>(this, TargetName);
|
||||
CaptureComponent->TextureTarget->InitCustomFormat(CaptureBoxSideRes, CaptureBoxSideRes, CaptureFormat, false);
|
||||
|
||||
CaptureComponents.Add(CaptureComponent);
|
||||
|
||||
CaptureComponent->RegisterComponentWithWorld(GWorld);
|
||||
|
||||
CaptureComponent->SetWorldLocationAndRotation(Location, Orientation * FaceOrientations[i]);
|
||||
CaptureComponent->UpdateContent();
|
||||
}
|
||||
Stage = SettingPos;
|
||||
|
||||
FActorSpawnParameters SpawnInfo;
|
||||
SpawnInfo.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
|
||||
SpawnInfo.bNoFail = true;
|
||||
SpawnInfo.ObjectFlags = RF_Transient;
|
||||
|
||||
AStaticMeshActor* InGameActor;
|
||||
InGameActor = World->SpawnActor<AStaticMeshActor>(SpawnInfo);
|
||||
|
||||
OutputDir = FPaths::ProjectSavedDir() + TEXT("/Cubemaps");
|
||||
IFileManager::Get().MakeDirectory(*OutputDir);
|
||||
}
|
||||
|
||||
void UOculusXRSceneCaptureCubemap::Tick(float DeltaTime)
|
||||
{
|
||||
ExecuteOnRenderThread([]() {
|
||||
TickRenderingTickables();
|
||||
});
|
||||
|
||||
if (Stage == SettingPos)
|
||||
{
|
||||
Stage = Capturing;
|
||||
return;
|
||||
}
|
||||
|
||||
// Read Whole Capture Buffer
|
||||
IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));
|
||||
TSharedPtr<IImageWrapper> ImageWrapper = ImageWrapperModule.CreateImageWrapper(EImageFormat::PNG);
|
||||
|
||||
TArray<FColor> OneFaceSurface, WholeCubemapData;
|
||||
OneFaceSurface.AddUninitialized(CaptureBoxSideRes * CaptureBoxSideRes);
|
||||
WholeCubemapData.AddUninitialized(CaptureBoxSideRes * 6 * CaptureBoxSideRes);
|
||||
// Read pixels
|
||||
for (int cubeFaceIdx = 0; cubeFaceIdx < 6; ++cubeFaceIdx)
|
||||
{
|
||||
auto RenderTarget = CaptureComponents[cubeFaceIdx]->TextureTarget->GameThread_GetRenderTargetResource();
|
||||
RenderTarget->ReadPixelsPtr(OneFaceSurface.GetData(), FReadSurfaceDataFlags());
|
||||
|
||||
// enforce alpha to be 1
|
||||
for (FColor& Color : OneFaceSurface)
|
||||
{
|
||||
Color.A = 255;
|
||||
}
|
||||
|
||||
// copy subimage into whole cubemap array
|
||||
const uint32 Stride = CaptureBoxSideRes * 6;
|
||||
const uint32 XOff = cubeFaceIdx * CaptureBoxSideRes;
|
||||
const uint32 StripSizeInBytes = CaptureBoxSideRes * sizeof(FColor);
|
||||
for (uint32 y = 0; y < CaptureBoxSideRes; ++y)
|
||||
{
|
||||
FMemory::Memcpy(WholeCubemapData.GetData() + XOff + y * Stride, OneFaceSurface.GetData() + y * CaptureBoxSideRes, StripSizeInBytes);
|
||||
}
|
||||
}
|
||||
|
||||
ImageWrapper->SetRaw(WholeCubemapData.GetData(), WholeCubemapData.GetAllocatedSize(), CaptureBoxSideRes * 6, CaptureBoxSideRes, ERGBFormat::BGRA, 8);
|
||||
const TArray64<uint8>& PNGData = ImageWrapper->GetCompressed(100);
|
||||
|
||||
const FString Filename = OutputDir + FString::Printf(TEXT("/Cubemap-%d-%s.png"), CaptureBoxSideRes, *FDateTime::Now().ToString(TEXT("%m.%d-%H.%M.%S")));
|
||||
|
||||
FFileHelper::SaveArrayToFile(PNGData, *Filename);
|
||||
|
||||
check(Stage == Capturing);
|
||||
Stage = Finished;
|
||||
for (int i = 0; i < CaptureComponents.Num(); ++i)
|
||||
{
|
||||
CaptureComponents[i]->UnregisterComponent();
|
||||
}
|
||||
CaptureComponents.SetNum(0);
|
||||
RemoveFromRoot(); // We're done here, so remove ourselves from the root set. @TODO: Fix this later
|
||||
}
|
||||
|
||||
#if !UE_BUILD_SHIPPING
|
||||
void UOculusXRSceneCaptureCubemap::CaptureCubemapCommandHandler(const TArray<FString>& Args, UWorld* World, FOutputDevice& Ar)
|
||||
{
|
||||
bool bCreateOculusMobileCubemap = false;
|
||||
FVector CaptureOffset(FVector::ZeroVector);
|
||||
float Yaw = 0.f;
|
||||
for (const FString& Arg : Args)
|
||||
{
|
||||
FParse::Value(*Arg, TEXT("XOFF="), CaptureOffset.X);
|
||||
FParse::Value(*Arg, TEXT("YOFF="), CaptureOffset.Y);
|
||||
FParse::Value(*Arg, TEXT("ZOFF="), CaptureOffset.Z);
|
||||
FParse::Value(*Arg, TEXT("YAW="), Yaw);
|
||||
|
||||
if (Arg.Equals(TEXT("MOBILE"), ESearchCase::IgnoreCase))
|
||||
{
|
||||
bCreateOculusMobileCubemap = true;
|
||||
}
|
||||
}
|
||||
|
||||
UOculusXRSceneCaptureCubemap* CubemapCapturer = NewObject<UOculusXRSceneCaptureCubemap>();
|
||||
CubemapCapturer->AddToRoot(); // TODO: Don't add the object to the GC root
|
||||
CubemapCapturer->SetOffset((FVector)CaptureOffset);
|
||||
if (Yaw != 0.f)
|
||||
{
|
||||
FRotator Rotation(FRotator::ZeroRotator);
|
||||
Rotation.Yaw = Yaw;
|
||||
const FQuat Orient(Rotation);
|
||||
CubemapCapturer->SetInitialOrientation(Orient);
|
||||
}
|
||||
const uint32 CaptureHeight = 2048;
|
||||
CubemapCapturer->StartCapture(World, bCreateOculusMobileCubemap ? CaptureHeight / 2 : CaptureHeight);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,79 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
#include "OculusXRHMDPrivate.h"
|
||||
#include "UObject/ObjectMacros.h"
|
||||
#include "Tickable.h"
|
||||
#include "OculusXRSceneCaptureCubemap.generated.h"
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// UOculusXRSceneCaptureCubemap
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
class USceneCaptureComponent2D;
|
||||
|
||||
UCLASS()
|
||||
class UOculusXRSceneCaptureCubemap : public UObject, public FTickableGameObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
UOculusXRSceneCaptureCubemap();
|
||||
|
||||
virtual void Tick(float DeltaTime) override;
|
||||
|
||||
virtual bool IsTickable() const override
|
||||
{
|
||||
return CaptureComponents.Num() != 0 && Stage != None;
|
||||
}
|
||||
|
||||
virtual bool IsTickableWhenPaused() const override
|
||||
{
|
||||
return IsTickable();
|
||||
}
|
||||
|
||||
virtual TStatId GetStatId() const
|
||||
{
|
||||
RETURN_QUICK_DECLARE_CYCLE_STAT(USceneCapturer, STATGROUP_Tickables);
|
||||
}
|
||||
|
||||
// init capture params and start
|
||||
void StartCapture(UWorld* World, uint32 InCaptureBoxSideRes, EPixelFormat InFormat = EPixelFormat::PF_A16B16G16R16);
|
||||
|
||||
// sets offset for the capture, in UU, relatively to current player 0 location
|
||||
void SetOffset(FVector InOffset) { CaptureOffset = InOffset; }
|
||||
|
||||
// overrides player's 0 orientation for the capture.
|
||||
void SetInitialOrientation(const FQuat& InOrientation) { OverriddenOrientation = InOrientation; }
|
||||
|
||||
// overrides player's 0 location for the capture.
|
||||
void SetInitialLocation(FVector InLocation) { OverriddenLocation = InLocation; }
|
||||
|
||||
bool IsFinished() const { return Stage == Finished; }
|
||||
bool IsCapturing() const { return Stage == Capturing || Stage == SettingPos; }
|
||||
|
||||
#if !UE_BUILD_SHIPPING
|
||||
static void CaptureCubemapCommandHandler(const TArray<FString>& Args, UWorld* World, FOutputDevice& Ar);
|
||||
#endif // UE_BUILD_SHIPPING
|
||||
|
||||
private:
|
||||
enum EStage
|
||||
{
|
||||
None,
|
||||
SettingPos,
|
||||
Capturing,
|
||||
Finished
|
||||
} Stage;
|
||||
|
||||
UPROPERTY()
|
||||
TArray<USceneCaptureComponent2D*> CaptureComponents;
|
||||
|
||||
uint32 CaptureBoxSideRes;
|
||||
EPixelFormat CaptureFormat;
|
||||
|
||||
FString OutputDir;
|
||||
|
||||
FVector OverriddenLocation; // overridden location of the capture, world coordinates, UU
|
||||
FQuat OverriddenOrientation; // overridden orientation of the capture. Full orientation is used (not only yaw, like with player's rotation).
|
||||
FVector CaptureOffset; // offset relative to current player's 0 location
|
||||
};
|
||||
515
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRSimulator.cpp
Normal file
515
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRSimulator.cpp
Normal file
@@ -0,0 +1,515 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "OculusXRSimulator.h"
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#include "HttpModule.h"
|
||||
#include "Interfaces/IHttpResponse.h"
|
||||
#include "Interfaces/IHttpRequest.h"
|
||||
#include "Misc/FileHelper.h"
|
||||
#include "Misc/Paths.h"
|
||||
#include "HAL/PlatformFilemanager.h"
|
||||
#include "GenericPlatform/GenericPlatformFile.h"
|
||||
#include "libzip/zip.h"
|
||||
|
||||
#include "HAL/FileManager.h"
|
||||
#include "OculusXRHMDRuntimeSettings.h"
|
||||
#include "OculusXRTelemetryEvents.h"
|
||||
#include "Misc/MessageDialog.h"
|
||||
#include "OpenXR/OculusXROpenXRUtilities.h"
|
||||
#include "Internationalization/Regex.h"
|
||||
|
||||
#include "Windows/WindowsPlatformMisc.h"
|
||||
#include "Interfaces/IPluginManager.h"
|
||||
|
||||
#include "Framework/Notifications/NotificationManager.h"
|
||||
#include "Widgets/Notifications/SNotificationList.h"
|
||||
|
||||
#if WITH_EDITOR
|
||||
#include "UnrealEdMisc.h"
|
||||
#endif // WITH_EDITOR
|
||||
|
||||
const FString OpenXrRuntimeEnvKey = "XR_RUNTIME_JSON";
|
||||
const FString PreviousOpenXrRuntimeEnvKey = "XR_RUNTIME_JSON_PREV";
|
||||
|
||||
namespace
|
||||
{
|
||||
class FZipArchiveReader
|
||||
{
|
||||
public:
|
||||
FZipArchiveReader(IFileHandle* InFileHandle);
|
||||
~FZipArchiveReader();
|
||||
|
||||
bool IsValid() const;
|
||||
TArray<FString> GetFileNames() const;
|
||||
bool TryReadFile(FStringView FileName, TArray<uint8>& OutData) const;
|
||||
|
||||
private:
|
||||
TMap<FString, zip_int64_t> EmbeddedFileToIndex;
|
||||
IFileHandle* FileHandle = nullptr;
|
||||
zip_source_t* ZipFileSource = nullptr;
|
||||
zip_t* ZipFile = nullptr;
|
||||
uint64 FilePos = 0;
|
||||
uint64 FileSize = 0;
|
||||
|
||||
void Destruct();
|
||||
zip_int64_t ZipSourceFunctionReader(void* OutData, zip_uint64_t DataLen, zip_source_cmd_t Command);
|
||||
|
||||
static zip_int64_t ZipSourceFunctionReaderStatic(void* InUserData, void* OutData, zip_uint64_t DataLen,
|
||||
zip_source_cmd_t Command);
|
||||
};
|
||||
|
||||
FZipArchiveReader::FZipArchiveReader(IFileHandle* InFileHandle)
|
||||
: FileHandle(InFileHandle)
|
||||
{
|
||||
if (!FileHandle)
|
||||
{
|
||||
Destruct();
|
||||
return;
|
||||
}
|
||||
|
||||
if (FileHandle->Tell() != 0)
|
||||
{
|
||||
FileHandle->Seek(0);
|
||||
}
|
||||
FilePos = 0;
|
||||
FileSize = FileHandle->Size();
|
||||
zip_error_t ZipError;
|
||||
zip_error_init(&ZipError);
|
||||
ZipFileSource = zip_source_function_create(ZipSourceFunctionReaderStatic, this, &ZipError);
|
||||
if (!ZipFileSource)
|
||||
{
|
||||
zip_error_fini(&ZipError);
|
||||
Destruct();
|
||||
return;
|
||||
}
|
||||
|
||||
zip_error_init(&ZipError);
|
||||
ZipFile = zip_open_from_source(ZipFileSource, ZIP_RDONLY, &ZipError);
|
||||
if (!ZipFile)
|
||||
{
|
||||
zip_error_fini(&ZipError);
|
||||
Destruct();
|
||||
return;
|
||||
}
|
||||
|
||||
zip_int64_t NumberOfFiles = zip_get_num_entries(ZipFile, 0);
|
||||
if (NumberOfFiles < 0 || MAX_int32 < NumberOfFiles)
|
||||
{
|
||||
Destruct();
|
||||
return;
|
||||
}
|
||||
EmbeddedFileToIndex.Reserve(NumberOfFiles);
|
||||
|
||||
// produce the manifest file first in case the operation gets canceled while unzipping
|
||||
for (zip_int64_t i = 0; i < NumberOfFiles; i++)
|
||||
{
|
||||
zip_stat_t ZipFileStat;
|
||||
if (zip_stat_index(ZipFile, i, 0, &ZipFileStat) != 0)
|
||||
{
|
||||
Destruct();
|
||||
return;
|
||||
}
|
||||
zip_uint64_t ValidStat = ZipFileStat.valid;
|
||||
if (!(ValidStat & ZIP_STAT_NAME))
|
||||
{
|
||||
Destruct();
|
||||
return;
|
||||
}
|
||||
EmbeddedFileToIndex.Add(FString(ANSI_TO_TCHAR(ZipFileStat.name)), i);
|
||||
}
|
||||
}
|
||||
|
||||
FZipArchiveReader::~FZipArchiveReader()
|
||||
{
|
||||
Destruct();
|
||||
}
|
||||
|
||||
void FZipArchiveReader::Destruct()
|
||||
{
|
||||
EmbeddedFileToIndex.Empty();
|
||||
if (ZipFile)
|
||||
{
|
||||
zip_close(ZipFile);
|
||||
ZipFile = nullptr;
|
||||
}
|
||||
if (ZipFileSource)
|
||||
{
|
||||
zip_source_close(ZipFileSource);
|
||||
ZipFileSource = nullptr;
|
||||
}
|
||||
delete FileHandle;
|
||||
FileHandle = nullptr;
|
||||
}
|
||||
|
||||
bool FZipArchiveReader::IsValid() const
|
||||
{
|
||||
return ZipFile != nullptr;
|
||||
}
|
||||
|
||||
TArray<FString> FZipArchiveReader::GetFileNames() const
|
||||
{
|
||||
TArray<FString> Result;
|
||||
EmbeddedFileToIndex.GenerateKeyArray(Result);
|
||||
return Result;
|
||||
}
|
||||
|
||||
bool FZipArchiveReader::TryReadFile(FStringView FileName, TArray<uint8>& OutData) const
|
||||
{
|
||||
OutData.Reset();
|
||||
|
||||
const zip_int64_t* Index = EmbeddedFileToIndex.FindByHash(GetTypeHash(FileName), FileName);
|
||||
if (!Index)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
zip_stat_t ZipFileStat;
|
||||
if (zip_stat_index(ZipFile, *Index, 0, &ZipFileStat) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(ZipFileStat.valid & ZIP_STAT_SIZE))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ZipFileStat.size == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (ZipFileStat.size > MAX_int32)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
OutData.SetNumUninitialized(ZipFileStat.size, EAllowShrinking::No);
|
||||
|
||||
zip_file* EmbeddedFile = zip_fopen_index(ZipFile, *Index, 0 /* flags */);
|
||||
if (!EmbeddedFile)
|
||||
{
|
||||
OutData.Reset();
|
||||
return false;
|
||||
}
|
||||
bool bReadSuccess = zip_fread(EmbeddedFile, OutData.GetData(), ZipFileStat.size) == ZipFileStat.size;
|
||||
zip_fclose(EmbeddedFile);
|
||||
if (!bReadSuccess)
|
||||
{
|
||||
OutData.Reset();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
zip_int64_t FZipArchiveReader::ZipSourceFunctionReaderStatic(
|
||||
void* InUserData, void* OutData, zip_uint64_t DataLen, zip_source_cmd_t Command)
|
||||
{
|
||||
return reinterpret_cast<FZipArchiveReader*>(InUserData)->ZipSourceFunctionReader(OutData, DataLen, Command);
|
||||
}
|
||||
|
||||
zip_int64_t FZipArchiveReader::ZipSourceFunctionReader(
|
||||
void* OutData, zip_uint64_t DataLen, zip_source_cmd_t Command)
|
||||
{
|
||||
switch (Command)
|
||||
{
|
||||
case ZIP_SOURCE_OPEN:
|
||||
return 0;
|
||||
case ZIP_SOURCE_READ:
|
||||
if (FilePos == FileSize)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
DataLen = FMath::Min(static_cast<zip_uint64_t>(FileSize - FilePos), DataLen);
|
||||
if (!FileHandle->Read(reinterpret_cast<uint8*>(OutData), DataLen))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
FilePos += DataLen;
|
||||
return DataLen;
|
||||
case ZIP_SOURCE_CLOSE:
|
||||
return 0;
|
||||
case ZIP_SOURCE_STAT:
|
||||
{
|
||||
zip_stat_t* OutStat = reinterpret_cast<zip_stat_t*>(OutData);
|
||||
zip_stat_init(OutStat);
|
||||
OutStat->size = FileSize;
|
||||
OutStat->comp_size = FileSize;
|
||||
OutStat->comp_method = ZIP_CM_STORE;
|
||||
OutStat->encryption_method = ZIP_EM_NONE;
|
||||
OutStat->valid = ZIP_STAT_SIZE | ZIP_STAT_COMP_SIZE | ZIP_STAT_COMP_METHOD | ZIP_STAT_ENCRYPTION_METHOD;
|
||||
return sizeof(*OutStat);
|
||||
}
|
||||
case ZIP_SOURCE_ERROR:
|
||||
{
|
||||
zip_uint32_t* OutLibZipError = reinterpret_cast<zip_uint32_t*>(OutData);
|
||||
zip_uint32_t* OutSystemError = OutLibZipError + 1;
|
||||
*OutLibZipError = ZIP_ER_INTERNAL;
|
||||
*OutSystemError = 0;
|
||||
return 2 * sizeof(*OutLibZipError);
|
||||
}
|
||||
case ZIP_SOURCE_FREE:
|
||||
return 0;
|
||||
case ZIP_SOURCE_SEEK:
|
||||
{
|
||||
zip_int64_t NewOffset = zip_source_seek_compute_offset(FilePos, FileSize, OutData, DataLen, nullptr);
|
||||
if (NewOffset < 0 || FileSize < static_cast<uint64>(NewOffset))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!FileHandle->Seek(NewOffset))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
FilePos = NewOffset;
|
||||
return 0;
|
||||
}
|
||||
case ZIP_SOURCE_TELL:
|
||||
return static_cast<zip_int64_t>(FilePos);
|
||||
case ZIP_SOURCE_SUPPORTS:
|
||||
return zip_source_make_command_bitmap(ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_STAT,
|
||||
ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, ZIP_SOURCE_SEEK, ZIP_SOURCE_TELL, ZIP_SOURCE_SUPPORTS, -1);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool Unzip(const FString& Path, const FString& TargetPath, const TSharedPtr<SNotificationItem>& Notification)
|
||||
{
|
||||
IPlatformFile& FileManager = FPlatformFileManager::Get().GetPlatformFile();
|
||||
|
||||
IFileHandle* ArchiveFileHandle = FileManager.OpenRead(*Path);
|
||||
const FZipArchiveReader ZipArchiveReader(ArchiveFileHandle);
|
||||
if (!ZipArchiveReader.IsValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const TArray<FString> ArchiveFiles = ZipArchiveReader.GetFileNames();
|
||||
uint64 Size = ArchiveFiles.Num();
|
||||
uint64 Index = 0;
|
||||
for (const FString& FileName : ArchiveFiles)
|
||||
{
|
||||
Index++;
|
||||
if (Notification.IsValid())
|
||||
{
|
||||
Notification->SetText(FText::FromString(FString::Format(TEXT("Unzipping {0} / {1}"), { Index, Size })));
|
||||
}
|
||||
|
||||
if (FileName.EndsWith("/") || FileName.EndsWith("\\"))
|
||||
continue;
|
||||
if (TArray<uint8> FileBuffer; ZipArchiveReader.TryReadFile(FileName, FileBuffer))
|
||||
{
|
||||
if (!FFileHelper::SaveArrayToFile(FileBuffer, *(TargetPath / FileName)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} // namespace
|
||||
bool FMetaXRSimulator::IsSimulatorActivated()
|
||||
{
|
||||
FString MetaXRSimPath = GetSimulatorJsonPath();
|
||||
FString CurRuntimePath = FWindowsPlatformMisc::GetEnvironmentVariable(*OpenXrRuntimeEnvKey);
|
||||
return (!MetaXRSimPath.IsEmpty() && MetaXRSimPath == CurRuntimePath);
|
||||
}
|
||||
|
||||
void FMetaXRSimulator::ToggleOpenXRRuntime()
|
||||
{
|
||||
OculusXRTelemetry::TScopedMarker<OculusXRTelemetry::Events::FSimulator> Event;
|
||||
FString MetaXRSimPath = GetSimulatorJsonPath();
|
||||
if (!IFileManager::Get().FileExists(*MetaXRSimPath))
|
||||
{
|
||||
InstallSimulator(ToggleOpenXRRuntime);
|
||||
UE_LOG(LogMetaXRSim, Log, TEXT("Meta XR Simulator Not Installed.\nInstalling Meta XR Simulator."));
|
||||
return;
|
||||
}
|
||||
|
||||
#if WITH_EDITOR
|
||||
if (OculusXR::IsOpenXRSystem())
|
||||
{
|
||||
FString ActivationText = IsSimulatorActivated() ? "deactivate" : "activate";
|
||||
FString Message = FString::Format(TEXT("A restart is required in order to {0} XR simulator. The restart must be performed from this dialog, opening and closing the editor manually will not work. Restart now?"), { ActivationText });
|
||||
if (FMessageDialog::Open(EAppMsgType::OkCancel, FText::FromString(Message)) == EAppReturnType::Cancel)
|
||||
{
|
||||
UE_LOG(LogMetaXRSim, Log, TEXT("Meta XR Simulator %s action canceled."), *ActivationText);
|
||||
const auto& NotEnd = Event.SetResult(OculusXRTelemetry::EAction::Fail).AddAnnotation("reason", "restart canceled");
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif // WITH_EDITOR
|
||||
|
||||
if (IsSimulatorActivated())
|
||||
{
|
||||
// Deactivate MetaXR Simulator
|
||||
FString PrevOpenXrRuntimeEnvKey = FWindowsPlatformMisc::GetEnvironmentVariable(*PreviousOpenXrRuntimeEnvKey);
|
||||
|
||||
FWindowsPlatformMisc::SetEnvironmentVar(*PreviousOpenXrRuntimeEnvKey,
|
||||
TEXT(""));
|
||||
FWindowsPlatformMisc::SetEnvironmentVar(*OpenXrRuntimeEnvKey, *PrevOpenXrRuntimeEnvKey);
|
||||
|
||||
UE_LOG(LogMetaXRSim, Log, TEXT("Meta XR Simulator is deactivated. (%s : %s)"), *OpenXrRuntimeEnvKey, *PrevOpenXrRuntimeEnvKey);
|
||||
const auto& NotEnd = Event.AddAnnotation("action", "deactivated");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Activate MetaXR Simulator
|
||||
FString CurOpenXrRuntimeEnvKey = FWindowsPlatformMisc::GetEnvironmentVariable(*OpenXrRuntimeEnvKey);
|
||||
|
||||
FWindowsPlatformMisc::SetEnvironmentVar(*PreviousOpenXrRuntimeEnvKey,
|
||||
*CurOpenXrRuntimeEnvKey);
|
||||
FWindowsPlatformMisc::SetEnvironmentVar(*OpenXrRuntimeEnvKey, *MetaXRSimPath);
|
||||
|
||||
UE_LOG(LogMetaXRSim, Log, TEXT("Meta XR Simulator is activated. (%s : %s)"), *OpenXrRuntimeEnvKey, *MetaXRSimPath);
|
||||
const auto& NotEnd = Event.AddAnnotation("action", "activated");
|
||||
}
|
||||
|
||||
#if WITH_EDITOR
|
||||
if (OculusXR::IsOpenXRSystem())
|
||||
{
|
||||
FUnrealEdMisc::Get().RestartEditor(false);
|
||||
}
|
||||
#endif // WITH_EDITOR
|
||||
}
|
||||
|
||||
FString FMetaXRSimulator::GetSimulatorJsonPath()
|
||||
{
|
||||
return FPaths::Combine(GetPackagePath(), TEXT("meta_openxr_simulator.json"));
|
||||
}
|
||||
|
||||
bool FMetaXRSimulator::IsSimulatorInstalled()
|
||||
{
|
||||
return FPaths::FileExists(GetSimulatorJsonPath());
|
||||
}
|
||||
|
||||
void FMetaXRSimulator::TryActivateOnStartup()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS && WITH_EDITOR
|
||||
// If -HMDSimulator is used as the command option to launch UE, use simulator runtime instead of the physical HMD runtime (like PC-Link).
|
||||
if (FParse::Param(FCommandLine::Get(), TEXT("HMDSimulator")))
|
||||
{
|
||||
if (IsSimulatorActivated())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ToggleOpenXRRuntime();
|
||||
}
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS && WITH_EDITOR
|
||||
}
|
||||
|
||||
FString FMetaXRSimulator::GetPackagePath()
|
||||
{
|
||||
return FPaths::Combine(FPlatformMisc::GetEnvironmentVariable(TEXT("LOCALAPPDATA")), TEXT("MetaXR"), TEXT("MetaXRSimulator"), GetVersion());
|
||||
}
|
||||
|
||||
void FMetaXRSimulator::InstallSimulator(const TFunction<void()>& OnSuccess)
|
||||
{
|
||||
FNotificationInfo Progress(FText::FromString("Installing Meta XR Simulator..."));
|
||||
Progress.bFireAndForget = false;
|
||||
Progress.FadeInDuration = 0.5f;
|
||||
Progress.FadeOutDuration = 0.5f;
|
||||
Progress.ExpireDuration = 5.0f;
|
||||
Progress.bUseThrobber = true;
|
||||
Progress.bUseSuccessFailIcons = true;
|
||||
|
||||
TSharedPtr<SNotificationItem> NotificationItem = FSlateNotificationManager::Get().AddNotification(Progress);
|
||||
if (NotificationItem.IsValid())
|
||||
{
|
||||
NotificationItem->SetCompletionState(SNotificationItem::CS_Pending);
|
||||
}
|
||||
|
||||
auto DestinationFolder = GetPackagePath();
|
||||
auto DownloadPath = FPaths::Combine(FPaths::EngineSavedDir(), TEXT("Downloads"), TEXT("MetaXRSimulator"), GetVersion(), TEXT("MetaXRSimulator.zip"));
|
||||
|
||||
if (FPaths::FileExists(DownloadPath))
|
||||
{
|
||||
UnzipSimulator(DownloadPath, DestinationFolder, NotificationItem, OnSuccess);
|
||||
return;
|
||||
}
|
||||
|
||||
TSharedPtr<IHttpRequest, ESPMode::ThreadSafe> Request = FHttpModule::Get().CreateRequest();
|
||||
|
||||
Request->OnProcessRequestComplete().BindLambda([DownloadPath, DestinationFolder, NotificationItem, OnSuccess](FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful) {
|
||||
Request->OnRequestProgress64().Unbind();
|
||||
if (Response.IsValid() && EHttpResponseCodes::IsOk(Response->GetResponseCode()))
|
||||
{
|
||||
// Save the downloaded zip file
|
||||
FFileHelper::SaveArrayToFile(Response->GetContent(), *DownloadPath);
|
||||
if (NotificationItem.IsValid())
|
||||
{
|
||||
NotificationItem->SetText(FText::FromString("Unzipping ... "));
|
||||
}
|
||||
|
||||
UnzipSimulator(DownloadPath, DestinationFolder, NotificationItem, OnSuccess);
|
||||
return;
|
||||
}
|
||||
|
||||
UE_LOG(LogMetaXRSim, Error, TEXT("Failed to install Meta XR Simulator."));
|
||||
if (NotificationItem.IsValid())
|
||||
{
|
||||
NotificationItem->SetText(FText::FromString("Installation failed!"));
|
||||
NotificationItem->SetCompletionState(SNotificationItem::CS_Fail);
|
||||
NotificationItem->ExpireAndFadeout();
|
||||
}
|
||||
});
|
||||
|
||||
Request->OnRequestProgress64().BindLambda([NotificationItem](const FHttpRequestPtr& Request, uint64 /* BytesSent */, uint64 BytesReceived) {
|
||||
uint64 ContentLength = Request->GetResponse()->GetContentLength();
|
||||
if (NotificationItem.IsValid())
|
||||
{
|
||||
NotificationItem->SetText(FText::FromString(FString::Format(TEXT("Downloading {0} / {1}"), { BytesReceived, ContentLength })));
|
||||
}
|
||||
});
|
||||
|
||||
Request->SetURL("https://www.facebook.com/horizon_devcenter_download?app_id=28549923061320041&sdk_version=" + GetVersion());
|
||||
Request->SetVerb(TEXT("GET"));
|
||||
Request->ProcessRequest();
|
||||
}
|
||||
|
||||
FString FMetaXRSimulator::GetVersion()
|
||||
{
|
||||
TSharedPtr<IPlugin> Plugin = IPluginManager::Get().FindPlugin(TEXT("OculusXR"));
|
||||
if (Plugin.IsValid())
|
||||
{
|
||||
FString VersionName = Plugin->GetDescriptor().VersionName;
|
||||
TArray<FString> ParsedParts;
|
||||
VersionName.ParseIntoArray(ParsedParts, TEXT("."), true);
|
||||
return FString::FromInt(FCString::Atoi(*ParsedParts[1]) - 32);
|
||||
}
|
||||
return "0";
|
||||
}
|
||||
|
||||
void FMetaXRSimulator::UnzipSimulator(const FString& Path, const FString& TargetPath, const TSharedPtr<SNotificationItem>& Notification,
|
||||
const TFunction<void()>& OnSuccess)
|
||||
{
|
||||
bool bSuccess = Unzip(Path, TargetPath, Notification);
|
||||
|
||||
if (!bSuccess || !IsSimulatorInstalled())
|
||||
{
|
||||
UE_LOG(LogMetaXRSim, Error, TEXT("Failed to unzip the file."));
|
||||
if (Notification.IsValid())
|
||||
{
|
||||
Notification->SetText(FText::FromString("Installation failed!"));
|
||||
Notification->SetCompletionState(SNotificationItem::CS_Fail);
|
||||
Notification->ExpireAndFadeout();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (Notification.IsValid())
|
||||
{
|
||||
Notification->SetText(FText::FromString("Installation succeeded!"));
|
||||
Notification->SetCompletionState(SNotificationItem::CS_Success);
|
||||
Notification->ExpireAndFadeout();
|
||||
}
|
||||
|
||||
if (OnSuccess)
|
||||
{
|
||||
OnSuccess();
|
||||
}
|
||||
}
|
||||
#endif // PLATFORM_WINDOWS
|
||||
@@ -0,0 +1,30 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
|
||||
#include "Widgets/Notifications/SNotificationList.h"
|
||||
|
||||
DEFINE_LOG_CATEGORY_STATIC(LogMetaXRSim, Log, All);
|
||||
|
||||
/** */
|
||||
class FMetaXRSimulator
|
||||
{
|
||||
public:
|
||||
static bool IsSimulatorActivated();
|
||||
static void ToggleOpenXRRuntime();
|
||||
static void TryActivateOnStartup();
|
||||
static FString GetPackagePath();
|
||||
static bool IsSimulatorInstalled();
|
||||
|
||||
private:
|
||||
static FString GetSimulatorJsonPath();
|
||||
static void InstallSimulator(const TFunction<void()>& OnSuccess);
|
||||
static FString GetVersion();
|
||||
static void UnzipSimulator(const FString& Path, const FString& TargetPath, const TSharedPtr<SNotificationItem>& Notification, const TFunction<void()>& OnSuccess);
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,85 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "OculusXRStereoLayersFlagsSupplier.h"
|
||||
#include "IStereoLayers.h"
|
||||
#include "OVR_Plugin_Types.h"
|
||||
|
||||
TSharedPtr<FOculusXRStereoLayersFlagsSupplier> FOculusXRStereoLayersFlagsSupplier::Instance = NULL;
|
||||
|
||||
TSharedPtr<FOculusXRStereoLayersFlagsSupplier> FOculusXRStereoLayersFlagsSupplier::Get()
|
||||
{
|
||||
if (!Instance.IsValid())
|
||||
{
|
||||
Instance = MakeShared<FOculusXRStereoLayersFlagsSupplier>();
|
||||
}
|
||||
|
||||
return Instance;
|
||||
}
|
||||
|
||||
FOculusXRStereoLayersFlagsSupplier::FOculusXRStereoLayersFlagsSupplier()
|
||||
{
|
||||
#if !UE_VERSION_OLDER_THAN(5, 4, 0)
|
||||
uint32 Value = IStereoLayers::ELayerFlags::LAYER_FLAG_MAX_VALUE << 1;
|
||||
UnrealFlagValOvrpFlagValMap.Add(Value, ovrpLayerFlag_BicubicFiltering);
|
||||
SupportedFilters.Add(FName("Bicubic Filtering"));
|
||||
|
||||
Value = Value << 1;
|
||||
UnrealFlagValOvrpFlagValMap.Add(Value, ovrpLayerSubmitFlag_AutoLayerFilter);
|
||||
SupportedFilters.Add(FName("Auto Filtering"));
|
||||
|
||||
Value = Value << 1;
|
||||
UnrealFlagValOvrpFlagValMap.Add(Value, ovrpLayerSubmitFlag_EfficientSuperSample);
|
||||
SupportedFilters.Add(FName("Normal SuperSampling"));
|
||||
|
||||
Value = Value << 1;
|
||||
UnrealFlagValOvrpFlagValMap.Add(Value, ovrpLayerSubmitFlag_ExpensiveSuperSample);
|
||||
SupportedFilters.Add(FName("Quality SuperSampling"));
|
||||
|
||||
Value = Value << 1;
|
||||
UnrealFlagValOvrpFlagValMap.Add(Value, ovrpLayerSubmitFlag_EfficientSharpen);
|
||||
SupportedFilters.Add(FName("Normal Sharpening"));
|
||||
|
||||
Value = Value << 1;
|
||||
UnrealFlagValOvrpFlagValMap.Add(Value, ovrpLayerSubmitFlag_QualitySharpen);
|
||||
SupportedFilters.Add(FName("Quality Sharpening"));
|
||||
#endif // !UE_VERSION_OLDER_THAN(5, 4, 0)
|
||||
}
|
||||
|
||||
int FOculusXRStereoLayersFlagsSupplier::GetOvrpFlag(uint32 DescFlags, bool bMQSR)
|
||||
{
|
||||
int LayerSubmitFlags = 0;
|
||||
#if !UE_VERSION_OLDER_THAN(5, 4, 0)
|
||||
for (auto& FlagPair : UnrealFlagValOvrpFlagValMap)
|
||||
{
|
||||
if (bMQSR && FlagPair.Value == ovrpLayerFlag_BicubicFiltering)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (!bMQSR && FlagPair.Value != ovrpLayerFlag_BicubicFiltering)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (DescFlags & FlagPair.Key)
|
||||
{
|
||||
LayerSubmitFlags |= FlagPair.Value;
|
||||
}
|
||||
}
|
||||
|
||||
if (bMQSR)
|
||||
{ // validate if autofilter conflicts with supersampling and sharpening
|
||||
bool bAutoFiltering = LayerSubmitFlags & ovrpLayerSubmitFlag_AutoLayerFilter;
|
||||
bool bSuperSamplingType = ((LayerSubmitFlags & ovrpLayerSubmitFlag_EfficientSuperSample) || (LayerSubmitFlags & ovrpLayerSubmitFlag_ExpensiveSuperSample));
|
||||
bool bSSharpenType = ((LayerSubmitFlags & ovrpLayerSubmitFlag_EfficientSharpen) || (LayerSubmitFlags & ovrpLayerSubmitFlag_QualitySharpen));
|
||||
|
||||
if (!bAutoFiltering && bSuperSamplingType && bSSharpenType)
|
||||
{
|
||||
UE_LOG(LogTemp, Error, TEXT("XR sharpening and supersampling cannot be enabled simultaneously.\n Either enable autofiltering or disable one of the options."));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif // !UE_VERSION_OLDER_THAN(5, 4, 0)
|
||||
|
||||
return LayerSubmitFlags;
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "OculusXRSyntheticEnvironmentServer.h"
|
||||
|
||||
#include "OculusXRSimulator.h"
|
||||
#if PLATFORM_WINDOWS
|
||||
#include "HAL/FileManager.h"
|
||||
#include "Internationalization/Regex.h"
|
||||
#include "OculusXRHMDRuntimeSettings.h"
|
||||
#include "OculusXRTelemetryEvents.h"
|
||||
#include "Misc/FileHelper.h"
|
||||
#include "Misc/MessageDialog.h"
|
||||
#include "Windows/WindowsPlatformMisc.h"
|
||||
|
||||
const FString SynthEnvServer = "Synthetic Environment Server";
|
||||
const FString LocalSharingServer = "Local Sharing Server";
|
||||
|
||||
FProcHandle FMetaXRSES::EnvProcHandle;
|
||||
FProcHandle FMetaXRSES::LSSProcHandle;
|
||||
|
||||
void FMetaXRSES::StopServer()
|
||||
{
|
||||
StopProcess(EnvProcHandle, SynthEnvServer);
|
||||
StopProcess(LSSProcHandle, LocalSharingServer);
|
||||
}
|
||||
|
||||
void FMetaXRSES::LaunchEnvironment(int32 EnvironmentIndex)
|
||||
{
|
||||
const FString EnvironmentName = SynthEnvRooms[EnvironmentIndex].SynthName;
|
||||
const FString SESPath = SynthEnvRooms[EnvironmentIndex].Executable;
|
||||
|
||||
if (FMetaXRSimulator::GetPackagePath().IsEmpty() || SESPath.IsEmpty() || EnvironmentName.IsEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
StopServer();
|
||||
|
||||
OculusXRTelemetry::TScopedMarker<OculusXRTelemetry::Events::FSimulator> Event;
|
||||
const bool bLaunched = LaunchProcess(SESPath, EnvironmentName, LocalSharingServer, EnvProcHandle);
|
||||
const auto& _ = Event.SetResult(bLaunched ? OculusXRTelemetry::EAction::Success : OculusXRTelemetry::EAction::Fail).AddAnnotation("launch", StringCast<ANSICHAR>(*EnvironmentName).Get());
|
||||
|
||||
LaunchLocalSharingServer();
|
||||
}
|
||||
|
||||
void FMetaXRSES::LaunchLocalSharingServer()
|
||||
{
|
||||
OculusXRTelemetry::TScopedMarker<OculusXRTelemetry::Events::FSimulator> Event;
|
||||
FString LSSPath = GetLocalSharingServerPath();
|
||||
const bool bLaunched = LaunchProcess(LSSPath, "", LocalSharingServer, LSSProcHandle);
|
||||
const auto& _ = Event.SetResult(bLaunched ? OculusXRTelemetry::EAction::Success : OculusXRTelemetry::EAction::Fail).AddAnnotation("launch", "localsharingserver");
|
||||
}
|
||||
|
||||
bool FMetaXRSES::LaunchProcess(FString BinaryPath, FString Arguments, FString LogContext, FProcHandle& OutProcHandle)
|
||||
{
|
||||
if (!IFileManager::Get().FileExists(*BinaryPath))
|
||||
{
|
||||
UE_LOG(LogMetaXRSES, Error, TEXT("Failed to find %s."), *BinaryPath);
|
||||
return false;
|
||||
}
|
||||
UE_LOG(LogMetaXRSES, Log, TEXT("Launching %s."), *BinaryPath);
|
||||
|
||||
uint32 OutProcessId = 0;
|
||||
OutProcHandle = FPlatformProcess::CreateProc(*BinaryPath, *Arguments, false, false, false, &OutProcessId, 0, NULL, NULL);
|
||||
if (!OutProcHandle.IsValid())
|
||||
{
|
||||
UE_LOG(LogMetaXRSES, Error, TEXT("Failed to launch %s."), *BinaryPath);
|
||||
FPlatformProcess::CloseProc(OutProcHandle);
|
||||
return false;
|
||||
}
|
||||
|
||||
UE_LOG(LogMetaXRSES, Log, TEXT("Launched %s."), *BinaryPath);
|
||||
return true;
|
||||
}
|
||||
|
||||
void FMetaXRSES::StopProcess(FProcHandle& ProcHandle, FString LogContext)
|
||||
{
|
||||
if (ProcHandle.IsValid())
|
||||
{
|
||||
if (FPlatformProcess::IsProcRunning(ProcHandle))
|
||||
{
|
||||
UE_LOG(LogMetaXRSES, Log, TEXT("Stopping %s."), *LogContext);
|
||||
FPlatformProcess::TerminateProc(ProcHandle);
|
||||
}
|
||||
FPlatformProcess::CloseProc(ProcHandle);
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogMetaXRSES, Warning, TEXT("Failed to stop process %s because it is not active anymore."), *LogContext);
|
||||
}
|
||||
}
|
||||
|
||||
TArray<FMetaXRSES::ServerInfo> FMetaXRSES::SynthEnvRooms = {};
|
||||
bool FMetaXRSES::SynthEnvParsed = false;
|
||||
|
||||
TArray<FMetaXRSES::ServerInfo> GatherServers(const FString& path)
|
||||
{
|
||||
TArray<FMetaXRSES::ServerInfo> servers{};
|
||||
TArray<FString> batFiles{};
|
||||
const FString ext("bat");
|
||||
IFileManager::Get().FindFiles(batFiles, *path, *ext);
|
||||
const static FRegexPattern pattern(TEXT("start (\\S+) (\\S+)"));
|
||||
|
||||
for (const FString& stem : batFiles)
|
||||
{
|
||||
const FString file = path + "/" + stem;
|
||||
FString result;
|
||||
if (!FFileHelper::LoadFileToString(result, *file))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
FRegexMatcher matcher(pattern, result);
|
||||
|
||||
if (!matcher.FindNext())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
UE_LOG(LogMetaXRSES, Warning, TEXT("In %s, found %s && %s"), *file, *matcher.GetCaptureGroup(1), *matcher.GetCaptureGroup(2));
|
||||
FString left;
|
||||
stem.Split(TEXT("."), &left, NULL);
|
||||
auto absPath = path + "/" + matcher.GetCaptureGroup(1);
|
||||
servers.Push({ left, matcher.GetCaptureGroup(2), IFileManager::Get().ConvertToAbsolutePathForExternalAppForRead(absPath.GetCharArray().GetData()) });
|
||||
}
|
||||
return servers;
|
||||
}
|
||||
|
||||
TArray<FMetaXRSES::ServerInfo>& FMetaXRSES::GetSynthEnvRooms()
|
||||
{
|
||||
if (SynthEnvParsed)
|
||||
{
|
||||
return SynthEnvRooms;
|
||||
}
|
||||
|
||||
SynthEnvRooms = {};
|
||||
|
||||
FString dirPath = FMetaXRSimulator::GetPackagePath();
|
||||
if (dirPath.IsEmpty())
|
||||
{
|
||||
return SynthEnvRooms;
|
||||
}
|
||||
|
||||
TArray<FString> dirNames;
|
||||
IFileManager::Get().IterateDirectory(dirPath.GetCharArray().GetData(), [&dirNames](const TCHAR* name, bool) -> bool {
|
||||
dirNames.Add(name);
|
||||
return true;
|
||||
});
|
||||
|
||||
for (auto dir : dirNames)
|
||||
{
|
||||
// find all of the servers in the subdirectories
|
||||
SynthEnvRooms.Append(GatherServers(dir));
|
||||
}
|
||||
SynthEnvParsed = true;
|
||||
return SynthEnvRooms;
|
||||
}
|
||||
|
||||
FString FMetaXRSES::GetLocalSharingServerPath()
|
||||
{
|
||||
FString Path = FMetaXRSimulator::GetPackagePath() + "/local_sharing_server~/local_sharing_server.exe";
|
||||
|
||||
if (!IFileManager::Get().FileExists(*Path))
|
||||
{
|
||||
UE_LOG(LogMetaXRSES, Warning, TEXT("Failed to find %s, trying the previous version"), *Path);
|
||||
Path = FMetaXRSimulator::GetPackagePath() + "/.local_sharing_server/local_sharing_server.exe";
|
||||
|
||||
if (!IFileManager::Get().FileExists(*Path))
|
||||
{
|
||||
UE_LOG(LogMetaXRSES, Error, TEXT("Failed to find LocalSharingServer, giving up"));
|
||||
Path = "";
|
||||
}
|
||||
}
|
||||
|
||||
return Path;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,41 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#if PLATFORM_WINDOWS
|
||||
DEFINE_LOG_CATEGORY_STATIC(LogMetaXRSES, Log, All);
|
||||
|
||||
struct FProcHandle;
|
||||
|
||||
/** */
|
||||
class FMetaXRSES
|
||||
{
|
||||
public:
|
||||
static void LaunchEnvironment(int32 EnvironmentIndex);
|
||||
static void StopServer();
|
||||
|
||||
struct ServerInfo
|
||||
{
|
||||
FString GuiName;
|
||||
FString SynthName;
|
||||
FString Executable;
|
||||
};
|
||||
|
||||
OCULUSXRHMD_API static TArray<ServerInfo>& GetSynthEnvRooms();
|
||||
|
||||
private:
|
||||
static void LaunchLocalSharingServer();
|
||||
static bool LaunchProcess(FString BinaryPath, FString Arguments, FString LogContext, FProcHandle& OutProcHandle);
|
||||
static void StopProcess(FProcHandle& ProcHandle, FString LogContext);
|
||||
|
||||
static FString GetLocalSharingServerPath();
|
||||
|
||||
static FProcHandle EnvProcHandle;
|
||||
static FProcHandle LSSProcHandle;
|
||||
|
||||
static TArray<ServerInfo> SynthEnvRooms;
|
||||
static bool SynthEnvParsed;
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,93 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#include "OculusXRTelemetry.h"
|
||||
#include "OculusXRHMDModule.h"
|
||||
#include "OculusXRTelemetryPrivacySettings.h"
|
||||
#include "Async/Async.h"
|
||||
#include "GeneralProjectSettings.h"
|
||||
|
||||
namespace OculusXRTelemetry
|
||||
{
|
||||
namespace
|
||||
{
|
||||
const char* TelemetrySource = "UE5Integration";
|
||||
}
|
||||
|
||||
bool IsActive()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
if constexpr (FTelemetryBackend::IsNullBackend())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// IsActive() can be called during shutdown, after the FOculusXRHMDModule has been unloaded.
|
||||
// This means we can't use the checked FOculusXRHMDModule::Get(), we instead need to use a fallible
|
||||
// GetModule(..) and check that the module exists.
|
||||
FOculusXRHMDModule* HMDModule = static_cast<FOculusXRHMDModule*>(FModuleManager::Get().GetModule(IOculusXRHMDModule::NAME_OculusXRHMD));
|
||||
if (HMDModule && HMDModule->IsOVRPluginAvailable() && FOculusXRHMDModule::GetPluginWrapper().IsInitialized())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
return false;
|
||||
}
|
||||
|
||||
void IfActiveThen(TUniqueFunction<void()> Function)
|
||||
{
|
||||
AsyncTask(ENamedThreads::GameThread, [F = MoveTemp(Function)]() {
|
||||
if (IsActive())
|
||||
{
|
||||
F();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void PropagateTelemetryConsent()
|
||||
{
|
||||
#ifdef WITH_EDITOR
|
||||
if (FOculusXRHMDModule::Get().IsOVRPluginAvailable() && FOculusXRHMDModule::GetPluginWrapper().IsInitialized())
|
||||
{
|
||||
const bool bHasConsent = FOculusXRHMDModule::GetPluginWrapper().GetUnifiedConsent(UNREAL_TOOL_ID) == ovrpBool_True;
|
||||
FOculusXRHMDModule::GetPluginWrapper().QplSetConsent(bHasConsent);
|
||||
FOculusXRHMDModule::GetPluginWrapper().SetDeveloperTelemetryConsent(bHasConsent);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
FString GetProjectId()
|
||||
{
|
||||
const UGeneralProjectSettings& ProjectSettings = *GetDefault<UGeneralProjectSettings>();
|
||||
return ProjectSettings.ProjectID.ToString();
|
||||
}
|
||||
|
||||
bool IsConsentGiven()
|
||||
{
|
||||
#ifdef WITH_EDITOR
|
||||
if (const UOculusXRTelemetryPrivacySettings* EditorPrivacySettings = GetDefault<UOculusXRTelemetryPrivacySettings>())
|
||||
{
|
||||
return EditorPrivacySettings->bIsEnabled;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
void SendEvent(const TCHAR* EventName, float Param)
|
||||
{
|
||||
const FString StrVal = FString::Printf(TEXT("%f"), Param);
|
||||
SendEvent(EventName, *StrVal);
|
||||
}
|
||||
|
||||
void SendEvent(const TCHAR* EventName, bool bParam)
|
||||
{
|
||||
SendEvent(EventName, bParam ? TEXT("true") : TEXT("false"));
|
||||
}
|
||||
|
||||
void SendEvent(const TCHAR* EventName, const TCHAR* Param)
|
||||
{
|
||||
if (IsActive())
|
||||
{
|
||||
FOculusXRHMDModule::GetPluginWrapper().SendEvent2(TCHAR_TO_ANSI(EventName), TCHAR_TO_ANSI(Param), TelemetrySource);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace OculusXRTelemetry
|
||||
@@ -0,0 +1,14 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "OculusXRTelemetry.h"
|
||||
|
||||
namespace OculusXRTelemetry::Events
|
||||
{
|
||||
using FEditorConsent = TMarker<191965622>;
|
||||
using FSimulator = TMarker<191963436>;
|
||||
using FEnableHardOcclusions = TMarker<191958638>;
|
||||
using FEnableSoftOcclusions = TMarker<191958877>;
|
||||
constexpr const char* ConsentOriginKey = "Origin";
|
||||
} // namespace OculusXRTelemetry::Events
|
||||
@@ -0,0 +1,124 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#include "OculusXRTelemetryPrivacySettings.h"
|
||||
|
||||
#include "OculusXRHMDModule.h"
|
||||
#include "OculusXRTelemetry.h"
|
||||
|
||||
#include <regex>
|
||||
|
||||
#define LOCTEXT_NAMESPACE "OculusXRTelemetryPrivacySettings"
|
||||
|
||||
constexpr int CONSENT_NOTIFICATION_MAX_LENGTH = 1024;
|
||||
TMap<FString, FString> GetLinks(const std::string& markdown, std::string& textWithoutLink)
|
||||
{
|
||||
TMap<FString, FString> links;
|
||||
const std::regex linkRegex(R"(\[(.*?)\]\((.*?)\))");
|
||||
|
||||
std::smatch matches;
|
||||
std::string::const_iterator searchStart(markdown.cbegin());
|
||||
while (std::regex_search(searchStart, markdown.cend(), matches, linkRegex))
|
||||
{
|
||||
links.Add(matches[1].str().c_str(), matches[2].str().c_str());
|
||||
searchStart = matches.suffix().first;
|
||||
}
|
||||
|
||||
const std::string linkReplacement = "";
|
||||
textWithoutLink = std::regex_replace(markdown, linkRegex, linkReplacement);
|
||||
return links;
|
||||
}
|
||||
|
||||
UOculusXRTelemetryPrivacySettings::UOculusXRTelemetryPrivacySettings(const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
if (!FOculusXRHMDModule::Get().IsOVRPluginAvailable() || !FOculusXRHMDModule::GetPluginWrapper().IsInitialized())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bIsEnabled = FOculusXRHMDModule::GetPluginWrapper().GetUnifiedConsent(OculusXRTelemetry::UNREAL_TOOL_ID) == ovrpBool_True;
|
||||
|
||||
char SettingsText[CONSENT_NOTIFICATION_MAX_LENGTH];
|
||||
if (FOculusXRHMDModule::GetPluginWrapper().GetConsentSettingsChangeText(SettingsText) == ovrpFailure)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::string settingsDesc = "";
|
||||
Links = GetLinks(SettingsText, settingsDesc);
|
||||
Description = FText::FromString(settingsDesc.c_str());
|
||||
}
|
||||
|
||||
void UOculusXRTelemetryPrivacySettings::GetToggleCategoryAndPropertyNames(FName& OutCategory, FName& OutProperty) const
|
||||
{
|
||||
OutCategory = FName("Options");
|
||||
OutProperty = FName("bIsEnabled");
|
||||
}
|
||||
|
||||
FText UOculusXRTelemetryPrivacySettings::GetFalseStateLabel() const
|
||||
{
|
||||
return LOCTEXT("FalseStateLabel", "Only share essential data");
|
||||
}
|
||||
|
||||
FText UOculusXRTelemetryPrivacySettings::GetFalseStateTooltip() const
|
||||
{
|
||||
return LOCTEXT("FalseStateTooltip", "Only share essential data");
|
||||
}
|
||||
|
||||
FText UOculusXRTelemetryPrivacySettings::GetFalseStateDescription() const
|
||||
{
|
||||
return Description;
|
||||
}
|
||||
|
||||
FText UOculusXRTelemetryPrivacySettings::GetTrueStateLabel() const
|
||||
{
|
||||
return LOCTEXT("TrueStateLabel", "Share additional data");
|
||||
}
|
||||
|
||||
FText UOculusXRTelemetryPrivacySettings::GetTrueStateTooltip() const
|
||||
{
|
||||
return LOCTEXT("TrueStateTooltip", "Share additional data");
|
||||
}
|
||||
|
||||
FText UOculusXRTelemetryPrivacySettings::GetTrueStateDescription() const
|
||||
{
|
||||
return Description;
|
||||
}
|
||||
|
||||
FString UOculusXRTelemetryPrivacySettings::GetAdditionalInfoUrl() const
|
||||
{
|
||||
if (Links.Num() > 0)
|
||||
{
|
||||
return Links.begin().Value();
|
||||
}
|
||||
return FString();
|
||||
}
|
||||
|
||||
FText UOculusXRTelemetryPrivacySettings::GetAdditionalInfoUrlLabel() const
|
||||
{
|
||||
if (Links.Num() > 0)
|
||||
{
|
||||
return FText::FromString(Links.begin().Key());
|
||||
}
|
||||
return FText();
|
||||
}
|
||||
|
||||
#if WITH_EDITOR
|
||||
void UOculusXRTelemetryPrivacySettings::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent)
|
||||
{
|
||||
Super::PostEditChangeProperty(PropertyChangedEvent);
|
||||
|
||||
const FName PropertyName = (PropertyChangedEvent.Property != nullptr) ? PropertyChangedEvent.Property->GetFName() : NAME_None;
|
||||
if (PropertyName == GET_MEMBER_NAME_CHECKED(UOculusXRTelemetryPrivacySettings, bIsEnabled))
|
||||
{
|
||||
using namespace OculusXRTelemetry;
|
||||
if (FOculusXRHMDModule::Get().IsOVRPluginAvailable() && FOculusXRHMDModule::GetPluginWrapper().IsInitialized())
|
||||
{
|
||||
FOculusXRHMDModule::GetPluginWrapper().SaveUnifiedConsent(UNREAL_TOOL_ID, bIsEnabled ? ovrpBool_True : ovrpBool_False);
|
||||
PropagateTelemetryConsent();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "UObject/Object.h"
|
||||
#include "Engine/ImportantToggleSettingInterface.h"
|
||||
#include "OculusXRTelemetryPrivacySettings.generated.h"
|
||||
|
||||
UCLASS(MinimalAPI, hidecategories = Object, config = EditorSettings)
|
||||
class UOculusXRTelemetryPrivacySettings : public UObject, public IImportantToggleSettingInterface
|
||||
{
|
||||
GENERATED_UCLASS_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, Category = Options)
|
||||
bool bIsEnabled = false;
|
||||
|
||||
public:
|
||||
// BEGIN IImportantToggleSettingInterface
|
||||
virtual void GetToggleCategoryAndPropertyNames(FName& OutCategory, FName& OutProperty) const override;
|
||||
virtual FText GetFalseStateLabel() const override;
|
||||
virtual FText GetFalseStateTooltip() const override;
|
||||
virtual FText GetFalseStateDescription() const override;
|
||||
virtual FText GetTrueStateLabel() const override;
|
||||
virtual FText GetTrueStateTooltip() const override;
|
||||
virtual FText GetTrueStateDescription() const override;
|
||||
virtual FString GetAdditionalInfoUrl() const override;
|
||||
virtual FText GetAdditionalInfoUrlLabel() const override;
|
||||
// END IImportantToggleSettingInterface
|
||||
|
||||
#if WITH_EDITOR
|
||||
//~ Begin UObject Interface
|
||||
virtual void PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) override;
|
||||
//~ End UObject Interface
|
||||
#endif // WITH_EDITOR
|
||||
|
||||
private:
|
||||
FText Description;
|
||||
TMap<FString, FString> Links;
|
||||
};
|
||||
@@ -0,0 +1,90 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#include "OculusXRCoreExtensionPlugin.h"
|
||||
|
||||
#include "DefaultSpectatorScreenController.h"
|
||||
#include "OculusXRFunctionLibrary.h"
|
||||
#include "OculusXRHMDRuntimeSettings.h"
|
||||
#include "OculusXRXRFunctions.h"
|
||||
#include "OculusXROpenXRUtilities.h"
|
||||
#include "OpenXRCore.h"
|
||||
#include "OpenXRHMDSettings.h"
|
||||
|
||||
#if PLATFORM_ANDROID
|
||||
// #include <openxr_oculus.h>
|
||||
#include <dlfcn.h>
|
||||
#endif // PLATFORM_ANDROID
|
||||
|
||||
DEFINE_LOG_CATEGORY(LogOculusOpenXRPlugin);
|
||||
|
||||
namespace OculusXR
|
||||
{
|
||||
|
||||
bool FCoreExtensionPlugin::IsStandaloneStereoOnlyDevice()
|
||||
{
|
||||
#if PLATFORM_ANDROID
|
||||
const bool bIsStandaloneStereoDevice = FAndroidMisc::GetDeviceMake() == FString("Oculus");
|
||||
#else
|
||||
const bool bIsStandaloneStereoDevice = false;
|
||||
#endif
|
||||
return bIsStandaloneStereoDevice;
|
||||
}
|
||||
|
||||
bool FCoreExtensionPlugin::GetOptionalExtensions(TArray<const ANSICHAR*>& OutExtensions)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FCoreExtensionPlugin::GetSpectatorScreenController(FHeadMountedDisplayBase* InHMDBase, TUniquePtr<FDefaultSpectatorScreenController>& OutSpectatorScreenController)
|
||||
{
|
||||
#if PLATFORM_ANDROID
|
||||
OutSpectatorScreenController = nullptr;
|
||||
return true;
|
||||
#else // PLATFORM_ANDROID
|
||||
OutSpectatorScreenController = MakeUnique<FDefaultSpectatorScreenController>(InHMDBase);
|
||||
return false;
|
||||
#endif // PLATFORM_ANDROID
|
||||
}
|
||||
|
||||
const void* FCoreExtensionPlugin::OnCreateSession(XrInstance InInstance, XrSystemId InSystem, const void* InNext)
|
||||
{
|
||||
check(IsInGameThread());
|
||||
|
||||
InitOpenXRFunctions(InInstance);
|
||||
|
||||
if (UOpenXRHMDSettings* OpenXRHMDSettings = GetMutableDefault<UOpenXRHMDSettings>())
|
||||
{
|
||||
OpenXRHMDSettings->bIsFBFoveationEnabled = true;
|
||||
}
|
||||
|
||||
if (IConsoleVariable* VariableRateShadingCVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.VRS.Enable")))
|
||||
{
|
||||
VariableRateShadingCVar->Set(1);
|
||||
}
|
||||
|
||||
if (const UOculusXRHMDRuntimeSettings* OculusXRHMDSettings = GetDefault<UOculusXRHMDRuntimeSettings>())
|
||||
{
|
||||
if (IConsoleVariable* FoveationLevelCVar = IConsoleManager::Get().FindConsoleVariable(TEXT("xr.OpenXRFBFoveationLevel")))
|
||||
{
|
||||
FoveationLevelCVar->Set(static_cast<int>(OculusXRHMDSettings->FoveatedRenderingLevel));
|
||||
}
|
||||
if (IConsoleVariable* FoveationDynamicCVar = IConsoleManager::Get().FindConsoleVariable(TEXT("xr.OpenXRFBFoveationDynamic")))
|
||||
{
|
||||
FoveationDynamicCVar->Set(OculusXRHMDSettings->bDynamicFoveatedRendering);
|
||||
}
|
||||
}
|
||||
|
||||
#if PLATFORM_ANDROID
|
||||
#if UE_VERSION_OLDER_THAN(5, 5, 0)
|
||||
if (GRHISupportsRHIThread && GIsThreadedRendering && GUseRHIThread_InternalUseOnly)
|
||||
{
|
||||
SetRHIThreadEnabled(false, false);
|
||||
}
|
||||
#else
|
||||
GPendingRHIThreadMode = ERHIThreadMode::None;
|
||||
#endif // UE_VERSION_OLDER_THAN
|
||||
#endif // PLATFORM_ANDROID
|
||||
return InNext;
|
||||
}
|
||||
|
||||
} // namespace OculusXR
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
#include "CoreMinimal.h"
|
||||
#include "Misc/EngineVersionComparison.h"
|
||||
#include "OpenXR/IOculusXRExtensionPlugin.h"
|
||||
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogOculusOpenXRPlugin, Log, All);
|
||||
|
||||
namespace OculusXR
|
||||
{
|
||||
|
||||
class FCoreExtensionPlugin : public IOculusXRExtensionPlugin
|
||||
{
|
||||
public:
|
||||
// IOpenXRExtensionPlugin
|
||||
virtual bool IsStandaloneStereoOnlyDevice() override;
|
||||
virtual bool GetOptionalExtensions(TArray<const ANSICHAR*>& OutExtensions) override;
|
||||
virtual bool GetSpectatorScreenController(FHeadMountedDisplayBase* InHMDBase, TUniquePtr<FDefaultSpectatorScreenController>& OutSpectatorScreenController) override;
|
||||
virtual const void* OnCreateSession(XrInstance InInstance, XrSystemId InSystem, const void* InNext) override;
|
||||
};
|
||||
|
||||
} // namespace OculusXR
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,136 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
|
||||
#include "khronos/openxr/openxr.h"
|
||||
#include "IOpenXRExtensionPlugin.h"
|
||||
#include "OculusXRHMDTypes.h"
|
||||
#include "Shader.h"
|
||||
#include "Misc/EngineVersionComparison.h"
|
||||
|
||||
namespace OculusXR
|
||||
{
|
||||
/// Texture handle which can be cast to GLuint, VkImage, ID3D11Texture2D*, or ID3D12Resource*
|
||||
using TextureHandle = unsigned long long;
|
||||
|
||||
constexpr uint32 EYE_COUNT = 2;
|
||||
|
||||
void RenderHardOcclusions_RenderThread(IRendererModule* RendererModule, const FVector2f& DepthFactors,
|
||||
const FMatrix44f ScreenToDepthMatrices[EYE_COUNT], FRHITexture* DepthTexture, FRHICommandList& RHICmdList, const FSceneView& InView);
|
||||
void RenderEnvironmentDepthMinMaxTexture_RenderThread(IRendererModule* RendererModule, FTextureRHIRef EnvironmentDepthMinMaxTexture,
|
||||
FTextureRHIRef EnvironmentDepthSwapchain, FRHICommandListImmediate& RHICmdList);
|
||||
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
|
||||
extern PFN_xrCreateEnvironmentDepthProviderMETA xrCreateEnvironmentDepthProviderMETA;
|
||||
extern PFN_xrDestroyEnvironmentDepthProviderMETA xrDestroyEnvironmentDepthProviderMETA;
|
||||
extern PFN_xrStartEnvironmentDepthProviderMETA xrStartEnvironmentDepthProviderMETA;
|
||||
extern PFN_xrStopEnvironmentDepthProviderMETA xrStopEnvironmentDepthProviderMETA;
|
||||
extern PFN_xrCreateEnvironmentDepthSwapchainMETA xrCreateEnvironmentDepthSwapchainMETA;
|
||||
extern PFN_xrDestroyEnvironmentDepthSwapchainMETA xrDestroyEnvironmentDepthSwapchainMETA;
|
||||
extern PFN_xrEnumerateEnvironmentDepthSwapchainImagesMETA xrEnumerateEnvironmentDepthSwapchainImagesMETA;
|
||||
extern PFN_xrGetEnvironmentDepthSwapchainStateMETA xrGetEnvironmentDepthSwapchainStateMETA;
|
||||
extern PFN_xrAcquireEnvironmentDepthImageMETA xrAcquireEnvironmentDepthImageMETA;
|
||||
extern PFN_xrSetEnvironmentDepthHandRemovalMETA xrSetEnvironmentDepthHandRemovalMETA;
|
||||
|
||||
class FEnvironmentDepthExtensionPlugin : public IOpenXRExtensionPlugin
|
||||
{
|
||||
public:
|
||||
void RegisterOpenXRExtensionPlugin()
|
||||
{
|
||||
#if defined(WITH_OCULUS_BRANCH)
|
||||
RegisterOpenXRExtensionModularFeature();
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual void PostCreateSession(XrSession InSession) override;
|
||||
virtual void BindExtensionPluginDelegates(class IOpenXRExtensionPluginDelegates& OpenXRHMD) override;
|
||||
virtual bool GetRequiredExtensions(TArray<const ANSICHAR*>& OutExtensions) override;
|
||||
virtual const void* OnCreateInstance(class IOpenXRHMDModule* InModule, const void* InNext) override;
|
||||
virtual const void* OnCreateSession(XrInstance InInstance, XrSystemId InSystem, const void* InNext) override;
|
||||
virtual void OnBeginRendering_GameThread(XrSession InSession) override;
|
||||
virtual void OnBeginRenderingLate_RenderThread(XrSession InSession, FRHICommandListImmediate& RHICmdList) override;
|
||||
virtual void PostBeginFrame_RHIThread(XrTime PredictedDisplayTime) override;
|
||||
virtual void PostRenderBasePassMobile_RenderThread(FRHICommandList& RHICmdList, FSceneView& InView) override;
|
||||
virtual void PostRenderBasePassDeferred_RenderThread(FRDGBuilder& GraphBuilder, FSceneView& InView,
|
||||
const FRenderTargetBindingSlots& RenderTargets, TRDGUniformBufferRef<FSceneTextureUniformParameters> SceneTextures) override;
|
||||
virtual bool OnStartGameFrame(FWorldContext& WorldContext) override;
|
||||
virtual bool OnEndGameFrame(FWorldContext& WorldContext) override;
|
||||
virtual void OnDestroySession(XrSession InSession) override;
|
||||
virtual const void* OnLocateViews(XrSession InSession, XrTime InDisplayTime, XrViewConfigurationType ViewConfigurationType, const void* InNext) override;
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
virtual bool FindEnvironmentDepthTexture_RenderThread(FTextureRHIRef& OutTexture, FTextureRHIRef& OutMinMaxTexture,
|
||||
FVector2f& OutDepthFactors, FMatrix44f OutScreenToDepthMatrices[2], FMatrix44f OutDepthViewProjMatrices[2]) override;
|
||||
#endif // WITH_OCULUS_BRANCH
|
||||
bool StartEnvironmentDepth();
|
||||
bool StopEnvironmentDepth();
|
||||
void SetXROcclusionsMode(UObject* WorldContextObject, EOculusXROcclusionsMode Mode);
|
||||
bool IsEnvironmentDepthStarted() const;
|
||||
|
||||
bool InitializeEnvironmentDepth_RenderThread();
|
||||
bool DestroyEnvironmentDepth_RenderThread();
|
||||
bool GetEnvironmentDepthTextureStageCount_RenderThread(int& OutStageCount);
|
||||
bool GetEnvironmentDepthTexture_RenderThread(int Stage, TextureHandle& OutHandle);
|
||||
bool SetEnvironmentDepthHandRemoval_RenderThread(bool Enabled);
|
||||
bool StartEnvironmentDepth_RenderThread();
|
||||
bool StopEnvironmentDepth_RenderThread();
|
||||
bool AcquireEnvironmentDepthTexture_RHIThread(XrTime predictedDisplayTime);
|
||||
bool GetEnvironmentDepthFrameDesc_RenderThread(TOptional<XrEnvironmentDepthImageMETA>& OutEnvironmentDepthFrameDesc);
|
||||
|
||||
private:
|
||||
XrSession Session = XR_NULL_HANDLE;
|
||||
XrSpace StageSpace = XR_NULL_HANDLE;
|
||||
|
||||
XrEnvironmentDepthProviderMETA EnvironmentDepthProviderMeta = XR_NULL_HANDLE;
|
||||
XrEnvironmentDepthSwapchainMETA EnvironmentDepthSwapchainMeta = XR_NULL_HANDLE;
|
||||
XrEnvironmentDepthSwapchainStateMETA EnvironmentDepthSwapchainStateMeta{ XR_TYPE_ENVIRONMENT_DEPTH_SWAPCHAIN_STATE_META };
|
||||
|
||||
std::mutex EnvironmentDepthTextureMutex;
|
||||
|
||||
bool bExtEnvironmentDepthAvailable = false;
|
||||
bool bHandsRemovalSupported = false;
|
||||
bool bEnvironmentDepthRunning = false;
|
||||
|
||||
std::function<FTextureRHIRef(uint32 InSizeX, uint32 InSizeY, EPixelFormat InFormat, const FClearValueBinding& InBinding, uint32 InNumMips,
|
||||
uint32 InNumSamples, uint32 InNumSamplesTileMem, ERHIResourceType InResourceType, TextureHandle InTexture,
|
||||
ETextureCreateFlags InTexCreateFlags)>
|
||||
CreateTexture_RenderThread_Fn;
|
||||
|
||||
TArray<FTextureRHIRef> EnvironmentDepthSwapchain;
|
||||
FTextureRHIRef EnvironmentDepthMinMaxTexture;
|
||||
int PrevEnvironmentDepthMinMaxSwapchainIndex = -1;
|
||||
|
||||
TArray<TextureHandle> EnvironmentDepthTextures;
|
||||
TOptional<XrEnvironmentDepthImageMETA> EnvironmentDepthFrameDesc;
|
||||
|
||||
std::atomic<bool> bHardOcclusionsEnabled = false;
|
||||
std::atomic<bool> bSoftOcclusionsEnabled = false;
|
||||
std::atomic<bool> bEnvironmentDepthHandRemovalEnabled = false;
|
||||
|
||||
FString RHIString;
|
||||
IRendererModule* RendererModule = nullptr;
|
||||
float WorldToMeters;
|
||||
float WorldToMeters_RenderThread;
|
||||
FTransform TrackingToWorld;
|
||||
FTransform TrackingToWorld_RenderThread;
|
||||
FQuat HeadOrientation;
|
||||
FQuat HeadOrientation_RenderThread;
|
||||
FQuat BaseOrientation;
|
||||
FQuat BaseOrientation_RenderThread;
|
||||
|
||||
TArray<XrView> EyeViews;
|
||||
TArray<XrView> EyeViews_RenderThread;
|
||||
|
||||
XrStructureType GetEnvironmentDepthSwapchainImageType() const;
|
||||
bool ComputeEnvironmentDepthParameters_RenderThread(FVector2f& DepthFactors, FMatrix44f ScreenToDepth[EYE_COUNT],
|
||||
FMatrix44f DepthViewProj[EYE_COUNT], int& SwapchainIndex);
|
||||
TArray<FTextureRHIRef> CreateSwapChainTextures_RenderThread(uint32 InSizeX, uint32 InSizeY, EPixelFormat InFormat,
|
||||
const FClearValueBinding& InBinding, uint32 InNumMips, uint32 InNumSamples, uint32 InNumSamplesTileMem, ERHIResourceType InResourceType,
|
||||
const TArray<TextureHandle>& InTextures, ETextureCreateFlags InTexCreateFlags, const TCHAR* DebugName) const;
|
||||
void PrepareAndRenderHardOcclusions_RenderThread(FRHICommandList& RHICmdList, FSceneView& InView);
|
||||
};
|
||||
#endif
|
||||
} // namespace OculusXR
|
||||
@@ -0,0 +1,76 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#include "OculusXRExtensionPluginManager.h"
|
||||
|
||||
namespace OculusXR
|
||||
{
|
||||
FExtensionPluginManager::FExtensionPluginManager()
|
||||
: CoreExtensionPlugin()
|
||||
, PerformanceExtensionPlugin()
|
||||
, XRSimulatorExtensionPlugin()
|
||||
, GuardianExtensionPlugin()
|
||||
, LayerExtensionPlugin()
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
, EnvironmentDepthExtensionPlugin()
|
||||
#endif
|
||||
#if defined(WITH_OCULUS_BRANCH)
|
||||
, SpaceWarpExtensionPlugin()
|
||||
#endif // defined(WITH_OCULUS_BRANCH)
|
||||
, SystemInfoExtensionPlugin()
|
||||
{
|
||||
}
|
||||
|
||||
FExtensionPluginManager::~FExtensionPluginManager()
|
||||
{
|
||||
}
|
||||
|
||||
void FExtensionPluginManager::StartupOpenXRPlugins()
|
||||
{
|
||||
CoreExtensionPlugin.RegisterOpenXRExtensionPlugin();
|
||||
PerformanceExtensionPlugin.RegisterOpenXRExtensionPlugin();
|
||||
XRSimulatorExtensionPlugin.RegisterOpenXRExtensionPlugin();
|
||||
SystemInfoExtensionPlugin.RegisterOpenXRExtensionPlugin();
|
||||
GuardianExtensionPlugin.RegisterOpenXRExtensionPlugin();
|
||||
LayerExtensionPlugin.RegisterOpenXRExtensionPlugin();
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
EnvironmentDepthExtensionPlugin.RegisterOpenXRExtensionPlugin();
|
||||
#endif
|
||||
#if defined(WITH_OCULUS_BRANCH)
|
||||
SpaceWarpExtensionPlugin.RegisterOpenXRExtensionPlugin();
|
||||
#endif // defined(WITH_OCULUS_BRANCH)
|
||||
MultiPlayerStateExtensionPlugin.RegisterOpenXRExtensionPlugin();
|
||||
}
|
||||
|
||||
FPerformanceExtensionPlugin& FExtensionPluginManager::GetPerformanceExtensionPlugin()
|
||||
{
|
||||
return PerformanceExtensionPlugin;
|
||||
}
|
||||
|
||||
FSystemInfoExtensionPlugin& FExtensionPluginManager::GetSystemInfoExtensionPlugin()
|
||||
{
|
||||
return SystemInfoExtensionPlugin;
|
||||
}
|
||||
|
||||
FGuardianExtensionPlugin& FExtensionPluginManager::GetGuardianExtensionPlugin()
|
||||
{
|
||||
return GuardianExtensionPlugin;
|
||||
}
|
||||
|
||||
FLayerExtensionPlugin& FExtensionPluginManager::GetLayerExtensionPlugin()
|
||||
{
|
||||
return LayerExtensionPlugin;
|
||||
}
|
||||
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
FEnvironmentDepthExtensionPlugin& FExtensionPluginManager::GetEnvironmentDepthExtensionPlugin()
|
||||
{
|
||||
return EnvironmentDepthExtensionPlugin;
|
||||
}
|
||||
#endif // WITH_OCULUS_BRANCH
|
||||
|
||||
FMultiPlayerStateExtensionPlugin& FExtensionPluginManager::GetMultiPlayerStateExtensionPlugin()
|
||||
{
|
||||
return MultiPlayerStateExtensionPlugin;
|
||||
}
|
||||
|
||||
} // namespace OculusXR
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
#include "CoreMinimal.h"
|
||||
#include "OculusXREnvironmentDepthExtensionPlugin.h"
|
||||
#include "OculusXRCoreExtensionPlugin.h"
|
||||
#include "OculusXRGuardianExtensionPlugin.h"
|
||||
#include "OculusXRLayerExtensionPlugin.h"
|
||||
#include "OculusXRPerformanceExtensionPlugin.h"
|
||||
#include "OculusXRSimulatorExtensionPlugin.h"
|
||||
#include "OculusXRSpaceWarp.h"
|
||||
#include "OculusXRSystemInfoExtensionPlugin.h"
|
||||
#include "OculusXRMultiPlayerStateExtensionPlugin.h"
|
||||
|
||||
namespace OculusXR
|
||||
{
|
||||
|
||||
class FExtensionPluginManager
|
||||
{
|
||||
public:
|
||||
FExtensionPluginManager();
|
||||
virtual ~FExtensionPluginManager();
|
||||
|
||||
void StartupOpenXRPlugins();
|
||||
|
||||
FPerformanceExtensionPlugin& GetPerformanceExtensionPlugin();
|
||||
FSystemInfoExtensionPlugin& GetSystemInfoExtensionPlugin();
|
||||
FGuardianExtensionPlugin& GetGuardianExtensionPlugin();
|
||||
FLayerExtensionPlugin& GetLayerExtensionPlugin();
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
FEnvironmentDepthExtensionPlugin& GetEnvironmentDepthExtensionPlugin();
|
||||
#endif
|
||||
FMultiPlayerStateExtensionPlugin& GetMultiPlayerStateExtensionPlugin();
|
||||
|
||||
private:
|
||||
FCoreExtensionPlugin CoreExtensionPlugin;
|
||||
FPerformanceExtensionPlugin PerformanceExtensionPlugin;
|
||||
FXRSimulatorExtensionPlugin XRSimulatorExtensionPlugin;
|
||||
FGuardianExtensionPlugin GuardianExtensionPlugin;
|
||||
FLayerExtensionPlugin LayerExtensionPlugin;
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
FEnvironmentDepthExtensionPlugin EnvironmentDepthExtensionPlugin;
|
||||
#endif
|
||||
#if defined(WITH_OCULUS_BRANCH)
|
||||
FSpaceWarpExtensionPlugin SpaceWarpExtensionPlugin;
|
||||
#endif // defined(WITH_OCULUS_BRANCH)
|
||||
FMultiPlayerStateExtensionPlugin MultiPlayerStateExtensionPlugin;
|
||||
|
||||
FSystemInfoExtensionPlugin SystemInfoExtensionPlugin;
|
||||
};
|
||||
|
||||
} // namespace OculusXR
|
||||
@@ -0,0 +1,78 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#include "OculusXRGuardianExtensionPlugin.h"
|
||||
#include "Engine/GameEngine.h"
|
||||
#include "IXRTrackingSystem.h"
|
||||
#include "OculusXROpenXRUtilities.h"
|
||||
#include "OpenXRCore.h"
|
||||
|
||||
DEFINE_LOG_CATEGORY(LogOculusXRGuardian);
|
||||
|
||||
namespace OculusXR
|
||||
{
|
||||
void FGuardianExtensionPlugin::PostCreateSession(XrSession InSession)
|
||||
{
|
||||
Session = InSession;
|
||||
}
|
||||
|
||||
bool FGuardianExtensionPlugin::IsGuardianConfigured()
|
||||
{
|
||||
XrExtent2Df Extent;
|
||||
const XrResult Result = xrGetReferenceSpaceBoundsRect(Session, XR_REFERENCE_SPACE_TYPE_STAGE, &Extent);
|
||||
return (XR_SUCCEEDED(Result) && (Result != XR_SPACE_BOUNDS_UNAVAILABLE));
|
||||
}
|
||||
|
||||
bool FGuardianExtensionPlugin::GetGuardianPoints(TArray<FVector>& BoundaryPoints)
|
||||
{
|
||||
XrExtent2Df Extent;
|
||||
XrResult Result = xrGetReferenceSpaceBoundsRect(Session, XR_REFERENCE_SPACE_TYPE_STAGE, &Extent);
|
||||
if (!XR_SUCCEEDED(Result) || Result == XR_SPACE_BOUNDS_UNAVAILABLE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
IXRTrackingSystem* TrackingSystem = GetOpenXRTrackingSystem();
|
||||
if (TrackingSystem == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FTransform OriginTransform;
|
||||
if (!TrackingSystem->GetTrackingOriginTransform(EHMDTrackingOrigin::Stage, OriginTransform))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const float WorldToMetersScale = TrackingSystem->GetWorldToMetersScale();
|
||||
|
||||
const XrVector3f XrPoints[] = {
|
||||
{ -Extent.width * 0.5f, 0.0f, -Extent.height * 0.5 },
|
||||
{ -Extent.width * 0.5f, 0.0f, Extent.height * 0.5f },
|
||||
{ Extent.width * 0.5f, 0.0f, Extent.height * 0.5f },
|
||||
{ Extent.width * 0.5f, 0.0f, -Extent.height * 0.5f }
|
||||
};
|
||||
|
||||
BoundaryPoints.Reset(UE_ARRAY_COUNT(XrPoints));
|
||||
for (int Index = 0; Index < UE_ARRAY_COUNT(XrPoints); ++Index)
|
||||
{
|
||||
BoundaryPoints.Emplace(OriginTransform.TransformPosition(ToFVector(XrPoints[Index], WorldToMetersScale)));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FVector FGuardianExtensionPlugin::GetGuardianDimensions()
|
||||
{
|
||||
XrExtent2Df Extent;
|
||||
FVector Dimensions;
|
||||
XrResult Result = xrGetReferenceSpaceBoundsRect(Session, XR_REFERENCE_SPACE_TYPE_STAGE, &Extent);
|
||||
if (XR_SUCCEEDED(Result) && Result == XR_SPACE_BOUNDS_UNAVAILABLE)
|
||||
{
|
||||
// Set height to 10.0f which matches expected OVRPlugin Version
|
||||
const float BoundsHeight = 10.0f;
|
||||
Dimensions = FVector(Extent.width, BoundsHeight, Extent.height);
|
||||
}
|
||||
return Dimensions;
|
||||
}
|
||||
|
||||
} // namespace OculusXR
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
#include "OculusXRHMDTypes.h"
|
||||
#include "OpenXR/IOculusXRExtensionPlugin.h"
|
||||
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogOculusXRGuardian, Log, All);
|
||||
|
||||
namespace OculusXR
|
||||
{
|
||||
class FGuardianExtensionPlugin : public IOculusXRExtensionPlugin
|
||||
{
|
||||
public:
|
||||
// IOpenXRExtensionPlugin
|
||||
virtual void PostCreateSession(XrSession InSession) override;
|
||||
|
||||
bool IsGuardianConfigured();
|
||||
bool GetGuardianPoints(TArray<FVector>& BoundaryPoints);
|
||||
FVector GetGuardianDimensions();
|
||||
|
||||
private:
|
||||
XrSession Session;
|
||||
};
|
||||
} // namespace OculusXR
|
||||
@@ -0,0 +1,344 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#include "OculusXRLayerExtensionPlugin.h"
|
||||
#include "Async/Async.h"
|
||||
#include "DynamicResolutionState.h"
|
||||
#include "IHeadMountedDisplay.h"
|
||||
#include "IOpenXRHMD.h"
|
||||
#include "IOpenXRHMDModule.h"
|
||||
#include "OculusXRHMD_DynamicResolutionState.h"
|
||||
#include "OculusXRHMDRuntimeSettings.h"
|
||||
#include "OculusXROpenXRUtilities.h"
|
||||
#include "OculusXRXRFunctions.h"
|
||||
#include "OpenXRCore.h"
|
||||
#include "XRThreadUtils.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
XrCompositionLayerSettingsFlagsFB ToSharpenLayerFlag(EOculusXREyeBufferSharpenType EyeBufferSharpenType)
|
||||
{
|
||||
XrCompositionLayerSettingsFlagsFB Flag = 0;
|
||||
switch (EyeBufferSharpenType)
|
||||
{
|
||||
case EOculusXREyeBufferSharpenType::SLST_None:
|
||||
Flag = 0;
|
||||
break;
|
||||
case EOculusXREyeBufferSharpenType::SLST_Normal:
|
||||
Flag = XR_COMPOSITION_LAYER_SETTINGS_NORMAL_SHARPENING_BIT_FB;
|
||||
break;
|
||||
case EOculusXREyeBufferSharpenType::SLST_Quality:
|
||||
Flag = XR_COMPOSITION_LAYER_SETTINGS_QUALITY_SHARPENING_BIT_FB;
|
||||
break;
|
||||
case EOculusXREyeBufferSharpenType::SLST_Auto:
|
||||
Flag = XR_COMPOSITION_LAYER_SETTINGS_AUTO_LAYER_FILTER_BIT_META;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return Flag;
|
||||
}
|
||||
|
||||
XrColor4f ToXrColor4f(FLinearColor Color)
|
||||
{
|
||||
return XrColor4f{ Color.R, Color.G, Color.B, Color.A };
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace OculusXR
|
||||
{
|
||||
FLayerExtensionPlugin::FLayerExtensionPlugin()
|
||||
: Session(XR_NULL_HANDLE)
|
||||
, bExtLocalDimmingAvailable(false)
|
||||
, bExtCompositionLayerSettingsAvailable(false)
|
||||
, bRecommendedResolutionExtensionAvailable(false)
|
||||
, LocalDimmingMode_RHIThread(XR_LOCAL_DIMMING_MODE_ON_META)
|
||||
, LocalDimmingExt_RHIThread{}
|
||||
, EyeSharpenLayerFlags_RHIThread(0)
|
||||
, ColorScaleInfo_RHIThread{}
|
||||
, _HeadersStorage{}
|
||||
, bPixelDensityAdaptive(false)
|
||||
, RecommendedImageHeight_GameThread(0)
|
||||
, Settings_GameThread{}
|
||||
, MaxPixelDensity_RenderThread(0)
|
||||
{
|
||||
}
|
||||
|
||||
bool FLayerExtensionPlugin::GetOptionalExtensions(TArray<const ANSICHAR*>& OutExtensions)
|
||||
{
|
||||
OutExtensions.Add(XR_META_LOCAL_DIMMING_EXTENSION_NAME);
|
||||
OutExtensions.Add(XR_FB_COMPOSITION_LAYER_SETTINGS_EXTENSION_NAME);
|
||||
OutExtensions.Add(XR_META_RECOMMENDED_LAYER_RESOLUTION_EXTENSION_NAME);
|
||||
return true;
|
||||
}
|
||||
|
||||
const void* FLayerExtensionPlugin::OnCreateInstance(class IOpenXRHMDModule* InModule, const void* InNext)
|
||||
{
|
||||
if (InModule != nullptr)
|
||||
{
|
||||
bExtLocalDimmingAvailable = InModule->IsExtensionEnabled(XR_META_LOCAL_DIMMING_EXTENSION_NAME);
|
||||
bExtCompositionLayerSettingsAvailable = InModule->IsExtensionEnabled(XR_FB_COMPOSITION_LAYER_SETTINGS_EXTENSION_NAME);
|
||||
bRecommendedResolutionExtensionAvailable = InModule->IsExtensionEnabled(XR_META_RECOMMENDED_LAYER_RESOLUTION_EXTENSION_NAME);
|
||||
}
|
||||
return IOculusXRExtensionPlugin::OnCreateInstance(InModule, InNext);
|
||||
}
|
||||
|
||||
void FLayerExtensionPlugin::PostCreateSession(XrSession InSession)
|
||||
{
|
||||
Session = InSession;
|
||||
const UOculusXRHMDRuntimeSettings* HMDSettings = GetDefault<UOculusXRHMDRuntimeSettings>();
|
||||
if (HMDSettings != nullptr)
|
||||
{
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
// currently only enabled in fork
|
||||
bPixelDensityAdaptive = HMDSettings->bDynamicResolution && bRecommendedResolutionExtensionAvailable;
|
||||
#endif
|
||||
|
||||
if (IConsoleVariable* MobileDynamicResCVar = IConsoleManager::Get().FindConsoleVariable(TEXT("xr.MobileLDRDynamicResolution")))
|
||||
{
|
||||
MobileDynamicResCVar->Set(bPixelDensityAdaptive);
|
||||
}
|
||||
|
||||
if (bPixelDensityAdaptive)
|
||||
{
|
||||
Settings_GameThread = MakeShareable(new OculusXRHMD::FSettings());
|
||||
Settings_GameThread->Flags.bPixelDensityAdaptive = bPixelDensityAdaptive;
|
||||
|
||||
if (IConsoleVariable* DynamicResOperationCVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.DynamicRes.OperationMode")))
|
||||
{
|
||||
// Operation mode for dynamic resolution
|
||||
// Enable regardless of the game user settings
|
||||
DynamicResOperationCVar->Set(2);
|
||||
}
|
||||
|
||||
GEngine->ChangeDynamicResolutionStateAtNextFrame(MakeShareable(new OculusXRHMD::FDynamicResolutionState(Settings_GameThread)));
|
||||
|
||||
const float MaxPixelDensity = Settings_GameThread->GetPixelDensityMax();
|
||||
|
||||
ENQUEUE_RENDER_COMMAND(OculusXR_SetEnableLocalDimming)
|
||||
([this, MaxPixelDensity](FRHICommandListImmediate& RHICmdList) {
|
||||
MaxPixelDensity_RenderThread = MaxPixelDensity;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FLayerExtensionPlugin::OnBeginRendering_GameThread(XrSession InSession)
|
||||
{
|
||||
check(IsInGameThread());
|
||||
|
||||
if (bPixelDensityAdaptive)
|
||||
{
|
||||
IXRTrackingSystem* TrackingSystem = OculusXR::GetOpenXRTrackingSystem();
|
||||
if (TrackingSystem != nullptr)
|
||||
{
|
||||
IOpenXRHMD* OpenXRHMD = TrackingSystem->GetIOpenXRHMD();
|
||||
check(OpenXRHMD != nullptr);
|
||||
|
||||
const XrTime PredictedDisplayTime = OpenXRHMD->GetDisplayTime();
|
||||
|
||||
ENQUEUE_RENDER_COMMAND(OculusXR_UpdatePredictedTime)
|
||||
([this, PredictedDisplayTime](FRHICommandListImmediate& RHICmdList) {
|
||||
RHICmdList.EnqueueLambda([this, PredictedDisplayTime](FRHICommandListImmediate& RHICmdList) {
|
||||
PredictedDisplayTime_RHIThread = PredictedDisplayTime;
|
||||
});
|
||||
});
|
||||
|
||||
IHeadMountedDisplay* Hmd = TrackingSystem->GetHMDDevice();
|
||||
IHeadMountedDisplay::MonitorInfo MonitorInfo = {};
|
||||
check(Hmd != nullptr);
|
||||
|
||||
if (Hmd->GetHMDMonitorInfo(MonitorInfo))
|
||||
{
|
||||
float PixelDensity = RecommendedImageHeight_GameThread == 0 ? Hmd->GetPixelDenity() : static_cast<float>(RecommendedImageHeight_GameThread) / MonitorInfo.ResolutionY;
|
||||
|
||||
static const auto CVarOculusDynamicPixelDensity = IConsoleManager::Get().FindTConsoleVariableDataFloat(TEXT("r.Oculus.DynamicResolution.PixelDensity"));
|
||||
const float PixelDensityCVarOverride = CVarOculusDynamicPixelDensity != nullptr ? CVarOculusDynamicPixelDensity->GetValueOnAnyThread() : 0.0f;
|
||||
if (PixelDensityCVarOverride > 0.0f)
|
||||
{
|
||||
PixelDensity = PixelDensityCVarOverride;
|
||||
}
|
||||
|
||||
check(Settings_GameThread != nullptr)
|
||||
Settings_GameThread->SetPixelDensitySmooth(PixelDensity);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Settings_GameThread != nullptr)
|
||||
{
|
||||
#if !UE_VERSION_OLDER_THAN(5, 5, 0)
|
||||
static const auto PixelDensityCVar = IConsoleManager::Get().FindConsoleVariable(TEXT("xr.SecondaryScreenPercentage.HMDRenderTarget"));
|
||||
#else
|
||||
static const auto PixelDensityCVar = IConsoleManager::Get().FindConsoleVariable(TEXT("vr.PixelDensity"));
|
||||
#endif
|
||||
|
||||
Settings_GameThread->SetPixelDensity(PixelDensityCVar ? PixelDensityCVar->GetFloat() : 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
float FLayerExtensionPlugin::GetMaxPixelDensity()
|
||||
{
|
||||
check(IsInGameThread() || IsInRenderingThread());
|
||||
|
||||
float PixelDensity = 0.0f;
|
||||
if (bPixelDensityAdaptive)
|
||||
{
|
||||
// Engine allows this call to happen on game or rendering thread.
|
||||
PixelDensity = IsInRenderingThread() ? MaxPixelDensity_RenderThread : Settings_GameThread->GetPixelDensityMax();
|
||||
}
|
||||
return PixelDensity;
|
||||
}
|
||||
#endif
|
||||
|
||||
const void* FLayerExtensionPlugin::OnEndFrame(XrSession InSession, XrTime DisplayTime, const void* InNext)
|
||||
{
|
||||
check(IsInRenderingThread() || IsInRHIThread());
|
||||
const void* Next = InNext;
|
||||
if (bExtLocalDimmingAvailable)
|
||||
{
|
||||
LocalDimmingExt_RHIThread.type = XR_TYPE_LOCAL_DIMMING_FRAME_END_INFO_META;
|
||||
LocalDimmingExt_RHIThread.localDimmingMode = LocalDimmingMode_RHIThread;
|
||||
LocalDimmingExt_RHIThread.next = Next;
|
||||
Next = &LocalDimmingExt_RHIThread;
|
||||
}
|
||||
return Next;
|
||||
}
|
||||
|
||||
const void* FLayerExtensionPlugin::OnEndProjectionLayer(XrSession InSession, int32 InLayerIndex, const void* InNext, XrCompositionLayerFlags& OutFlags)
|
||||
{
|
||||
check(IsInRenderingThread() || IsInRHIThread());
|
||||
const void* Next = InNext;
|
||||
if (bExtCompositionLayerSettingsAvailable)
|
||||
{
|
||||
XrCompositionLayerSettingsExt.type = XR_TYPE_COMPOSITION_LAYER_SETTINGS_FB;
|
||||
XrCompositionLayerSettingsExt.next = Next;
|
||||
XrCompositionLayerSettingsExt.layerFlags = EyeSharpenLayerFlags_RHIThread;
|
||||
Next = &XrCompositionLayerSettingsExt;
|
||||
}
|
||||
return Next;
|
||||
}
|
||||
|
||||
void FLayerExtensionPlugin::SetEnableLocalDimming(bool Enable)
|
||||
{
|
||||
ENQUEUE_RENDER_COMMAND(OculusXR_SetEnableLocalDimming)
|
||||
([this, Enable](FRHICommandListImmediate& RHICmdList) {
|
||||
RHICmdList.EnqueueLambda([this, Enable](FRHICommandListImmediate& RHICmdList) {
|
||||
LocalDimmingMode_RHIThread = Enable ? XR_LOCAL_DIMMING_MODE_ON_META : XR_LOCAL_DIMMING_MODE_OFF_META;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void FLayerExtensionPlugin::SetEyeBufferSharpenType(EOculusXREyeBufferSharpenType EyeBufferSharpenType)
|
||||
{
|
||||
ENQUEUE_RENDER_COMMAND(OculusXR_SetEyeBufferSharpenType)
|
||||
([this, EyeBufferSharpenType](FRHICommandListImmediate& RHICmdList) {
|
||||
RHICmdList.EnqueueLambda([this, EyeBufferSharpenType](FRHICommandListImmediate& RHICmdList) {
|
||||
EyeSharpenLayerFlags_RHIThread = ToSharpenLayerFlag(EyeBufferSharpenType);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void FLayerExtensionPlugin::SetColorScaleAndOffset(FLinearColor ColorScale, FLinearColor ColorOffset, bool bApplyToAllLayers)
|
||||
{
|
||||
IXRTrackingSystem* TrackingSystem = OculusXR::GetOpenXRTrackingSystem();
|
||||
if (TrackingSystem != nullptr)
|
||||
{
|
||||
IHeadMountedDisplay* Hmd = TrackingSystem->GetHMDDevice();
|
||||
Hmd->SetColorScaleAndBias(ColorScale, ColorOffset);
|
||||
}
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
ENQUEUE_RENDER_COMMAND(OculusXR_SetColorScaleAndOffset)
|
||||
([this, ColorScale, ColorOffset, bApplyToAllLayers](FRHICommandListImmediate& RHICmdList) {
|
||||
RHICmdList.EnqueueLambda([this, ColorScale, ColorOffset, bApplyToAllLayers](FRHICommandListImmediate& RHICmdList) {
|
||||
ColorScaleInfo_RHIThread.ColorScale = ColorScale;
|
||||
ColorScaleInfo_RHIThread.ColorOffset = ColorOffset;
|
||||
ColorScaleInfo_RHIThread.bApplyColorScaleAndOffsetToAllLayers = bApplyToAllLayers;
|
||||
});
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
static bool ShouldApplyColorScale(const XrCompositionLayerBaseHeader* Header)
|
||||
{
|
||||
switch (Header->type)
|
||||
{
|
||||
case XR_TYPE_COMPOSITION_LAYER_QUAD:
|
||||
case XR_TYPE_COMPOSITION_LAYER_EQUIRECT_KHR:
|
||||
case XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR:
|
||||
case XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR:
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void FLayerExtensionPlugin::UpdatePixelDensity(const XrCompositionLayerBaseHeader* LayerHeader)
|
||||
{
|
||||
check(LayerHeader != nullptr);
|
||||
|
||||
if (LayerHeader->type == XR_TYPE_COMPOSITION_LAYER_PROJECTION && bPixelDensityAdaptive && bRecommendedResolutionExtensionAvailable)
|
||||
{
|
||||
IXRTrackingSystem* TrackingSystem = OculusXR::GetOpenXRTrackingSystem();
|
||||
if (TrackingSystem != nullptr)
|
||||
{
|
||||
XrRecommendedLayerResolutionMETA ResolutionRecommendation = {};
|
||||
ResolutionRecommendation.type = XR_TYPE_RECOMMENDED_LAYER_RESOLUTION_META;
|
||||
ResolutionRecommendation.next = nullptr;
|
||||
ResolutionRecommendation.isValid = false;
|
||||
|
||||
XrRecommendedLayerResolutionGetInfoMETA ResolutionRecommendationGetInfo = {};
|
||||
ResolutionRecommendationGetInfo.type = XR_TYPE_RECOMMENDED_LAYER_RESOLUTION_GET_INFO_META;
|
||||
ResolutionRecommendationGetInfo.next = nullptr;
|
||||
ResolutionRecommendationGetInfo.layer = LayerHeader;
|
||||
ResolutionRecommendationGetInfo.predictedDisplayTime = PredictedDisplayTime_RHIThread;
|
||||
|
||||
ENSURE_XRCMD(xrGetRecommendedLayerResolutionMETA.GetValue()(Session, &ResolutionRecommendationGetInfo, &ResolutionRecommendation));
|
||||
|
||||
if (ResolutionRecommendation.isValid == XR_TRUE)
|
||||
{
|
||||
AsyncTask(ENamedThreads::GameThread, [this, ResolutionRecommendation] {
|
||||
RecommendedImageHeight_GameThread = ResolutionRecommendation.recommendedImageDimensions.height;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FLayerExtensionPlugin::UpdateCompositionLayers(XrSession InSession, TArray<XrCompositionLayerBaseHeader*>& Headers)
|
||||
{
|
||||
check(IsInRenderingThread() || IsInRHIThread());
|
||||
|
||||
if (ColorScaleInfo_RHIThread.bApplyColorScaleAndOffsetToAllLayers)
|
||||
{
|
||||
ColorScale_RHIThread.Reset(Headers.Num());
|
||||
}
|
||||
|
||||
for (const XrCompositionLayerBaseHeader* Header : Headers)
|
||||
{
|
||||
if (Header->type == XR_TYPE_COMPOSITION_LAYER_PROJECTION)
|
||||
{
|
||||
UpdatePixelDensity(Header);
|
||||
}
|
||||
|
||||
if (ColorScaleInfo_RHIThread.bApplyColorScaleAndOffsetToAllLayers && ShouldApplyColorScale(Header))
|
||||
{
|
||||
ColorScale_RHIThread.AddUninitialized();
|
||||
XrCompositionLayerColorScaleBiasKHR& ColorScaleBias = ColorScale_RHIThread.Last();
|
||||
ColorScaleBias = { XR_TYPE_COMPOSITION_LAYER_COLOR_SCALE_BIAS_KHR };
|
||||
ColorScaleBias.next = const_cast<void*>(Header->next);
|
||||
ColorScaleBias.colorScale = ToXrColor4f(ColorScaleInfo_RHIThread.ColorScale);
|
||||
ColorScaleBias.colorBias = ToXrColor4f(ColorScaleInfo_RHIThread.ColorOffset);
|
||||
const_cast<XrCompositionLayerBaseHeader*>(Header)->next = &ColorScaleBias;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace OculusXR
|
||||
@@ -0,0 +1,71 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
#include "khronos/openxr/openxr.h"
|
||||
#include "CoreMinimal.h"
|
||||
#include "OculusXRHMDTypes.h"
|
||||
#include "OculusXRHMD_Settings.h"
|
||||
#include "OpenXR/IOculusXRExtensionPlugin.h"
|
||||
|
||||
namespace OculusXR
|
||||
{
|
||||
|
||||
class FLayerExtensionPlugin : public IOculusXRExtensionPlugin
|
||||
{
|
||||
public:
|
||||
FLayerExtensionPlugin();
|
||||
// IOpenXRExtensionPlugin
|
||||
virtual bool GetOptionalExtensions(TArray<const ANSICHAR*>& OutExtensions) override;
|
||||
const void* OnCreateInstance(class IOpenXRHMDModule* InModule, const void* InNext);
|
||||
virtual const void* OnEndFrame(XrSession InSession, XrTime DisplayTime, const void* InNext) override;
|
||||
virtual const void* OnEndProjectionLayer(XrSession InSession, int32 InLayerIndex, const void* InNext, XrCompositionLayerFlags& OutFlags);
|
||||
virtual void PostCreateSession(XrSession InSession) override;
|
||||
virtual void OnBeginRendering_GameThread(XrSession InSession) override;
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
virtual float GetMaxPixelDensity() override;
|
||||
#endif
|
||||
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
// epic branch has member as const, not usable in this case
|
||||
virtual void UpdateCompositionLayers(XrSession InSession, TArray<XrCompositionLayerBaseHeader*>& Headers) override;
|
||||
#endif
|
||||
void SetEnableLocalDimming(bool Enable);
|
||||
void SetEyeBufferSharpenType(EOculusXREyeBufferSharpenType EyeBufferSharpenType);
|
||||
void SetColorScaleAndOffset(FLinearColor ColorScale, FLinearColor ColorOffset, bool bApplyToAllLayers);
|
||||
|
||||
private:
|
||||
void UpdatePixelDensity(const XrCompositionLayerBaseHeader* LayerHeader);
|
||||
|
||||
XrSession Session;
|
||||
bool bExtLocalDimmingAvailable;
|
||||
bool bExtCompositionLayerSettingsAvailable;
|
||||
bool bRecommendedResolutionExtensionAvailable;
|
||||
|
||||
XrLocalDimmingModeMETA LocalDimmingMode_RHIThread;
|
||||
XrLocalDimmingFrameEndInfoMETA LocalDimmingExt_RHIThread;
|
||||
XrCompositionLayerSettingsFlagsFB EyeSharpenLayerFlags_RHIThread;
|
||||
XrCompositionLayerSettingsFB XrCompositionLayerSettingsExt;
|
||||
|
||||
struct FColorScaleInfo
|
||||
{
|
||||
FColorScaleInfo()
|
||||
: ColorScale{ 1.0f, 1.0f, 1.0f, 1.0f }
|
||||
, ColorOffset{ 0.0f, 0.0f, 0.0f, 0.0f }
|
||||
, bApplyColorScaleAndOffsetToAllLayers(false){};
|
||||
FLinearColor ColorScale;
|
||||
FLinearColor ColorOffset;
|
||||
bool bApplyColorScaleAndOffsetToAllLayers;
|
||||
};
|
||||
|
||||
FColorScaleInfo ColorScaleInfo_RHIThread;
|
||||
TArray<XrCompositionLayerColorScaleBiasKHR> ColorScale_RHIThread;
|
||||
|
||||
TArray<XrCompositionLayerBaseHeader> _HeadersStorage;
|
||||
bool bPixelDensityAdaptive;
|
||||
uint32_t RecommendedImageHeight_GameThread;
|
||||
OculusXRHMD::FSettingsPtr Settings_GameThread;
|
||||
XrTime PredictedDisplayTime_RHIThread;
|
||||
float MaxPixelDensity_RenderThread;
|
||||
};
|
||||
|
||||
} // namespace OculusXR
|
||||
@@ -0,0 +1,120 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#include "OculusXRMultiPlayerStateExtensionPlugin.h"
|
||||
#include "OculusXRHMDRuntimeSettings.h"
|
||||
|
||||
DEFINE_LOG_CATEGORY(LogOculusMultiPlayerStateExtensionPlugin);
|
||||
|
||||
namespace OculusXR
|
||||
{
|
||||
|
||||
FMultiPlayerStateExtensionPlugin::FMultiPlayerStateExtensionPlugin()
|
||||
{
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
ResetPose();
|
||||
#endif // WITH_OCULUS_BRANCH
|
||||
}
|
||||
|
||||
FMultiPlayerStateExtensionPlugin::~FMultiPlayerStateExtensionPlugin()
|
||||
{
|
||||
}
|
||||
|
||||
void FMultiPlayerStateExtensionPlugin::SwitchPrimaryPIE(int PrimaryPIEIndex)
|
||||
{
|
||||
CurPlayerIndex = PrimaryPIEIndex;
|
||||
}
|
||||
|
||||
void FMultiPlayerStateExtensionPlugin::InitMultiPlayerPoses(const FTransform& CurPose)
|
||||
{
|
||||
#if WITH_EDITOR && PLATFORM_WINDOWS
|
||||
if (!GIsEditor || MultiPlayerPoses.Num())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!FApp::HasVRFocus())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ULevelEditorPlaySettings* PlayInSettings = GetMutableDefault<ULevelEditorPlaySettings>();
|
||||
check(PlayInSettings);
|
||||
int PlayNumberOfClients;
|
||||
PlayInSettings->GetPlayNumberOfClients(PlayNumberOfClients);
|
||||
if (PlayNumberOfClients <= 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EPlayNetMode OutPlayNetMode;
|
||||
PlayInSettings->GetPlayNetMode(OutPlayNetMode);
|
||||
if (OutPlayNetMode != EPlayNetMode::PIE_Standalone)
|
||||
{
|
||||
// In case of non-standalone mode, server is the first player, client idx should start from 1
|
||||
PlayNumberOfClients++;
|
||||
}
|
||||
|
||||
LastFrameHMDHeadPose = CurPose;
|
||||
MultiPlayerPoses.Empty();
|
||||
MultiPlayerPoses.InsertDefaulted(0, PlayNumberOfClients);
|
||||
for (auto& PlayerPose : MultiPlayerPoses)
|
||||
{
|
||||
PlayerPose = CurPose;
|
||||
}
|
||||
UE_LOG(LogHMD, Log, TEXT("MultiPlayer poses are initialized."));
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
void FMultiPlayerStateExtensionPlugin::ResetPose()
|
||||
{
|
||||
#if WITH_EDITOR && PLATFORM_WINDOWS
|
||||
CurPlayerIndex = 0;
|
||||
LastFrameHMDHeadPose = FTransform::Identity;
|
||||
MultiPlayerPoses.Empty();
|
||||
#endif
|
||||
}
|
||||
|
||||
void FMultiPlayerStateExtensionPlugin::ReCalcPose(FTransform& CurHMDHeadPose)
|
||||
{
|
||||
#if WITH_EDITOR && PLATFORM_WINDOWS
|
||||
if (!GIsEditor || GetMutableDefault<UOculusXRHMDRuntimeSettings>()->MPPoseRestoreType == EOculusXRMPPoseRestoreType::Disabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!MultiPlayerPoses.Num())
|
||||
{
|
||||
InitMultiPlayerPoses(CurHMDHeadPose);
|
||||
}
|
||||
|
||||
if (MultiPlayerPoses.Num() <= 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (CurPlayerIndex >= MultiPlayerPoses.Num())
|
||||
{
|
||||
UE_LOG(LogHMD, Error, TEXT("CurPlayerIndex %i is larger than MultiPlayerPoses.Num() !"), CurPlayerIndex, MultiPlayerPoses.Num());
|
||||
}
|
||||
|
||||
FTransform& PlayerPose = MultiPlayerPoses[CurPlayerIndex];
|
||||
if (GetMutableDefault<UOculusXRHMDRuntimeSettings>()->MPPoseRestoreType == EOculusXRMPPoseRestoreType::PositionOnly)
|
||||
{
|
||||
FVector DeltaPosition = CurHMDHeadPose.GetTranslation() - LastFrameHMDHeadPose.GetTranslation();
|
||||
PlayerPose.SetTranslation(PlayerPose.GetTranslation() + DeltaPosition);
|
||||
LastFrameHMDHeadPose.SetTranslation(CurHMDHeadPose.GetTranslation());
|
||||
CurHMDHeadPose.SetTranslation(PlayerPose.GetTranslation());
|
||||
}
|
||||
else
|
||||
{
|
||||
FTransform DeltaPose = LastFrameHMDHeadPose.Inverse() * CurHMDHeadPose;
|
||||
PlayerPose = PlayerPose * DeltaPose;
|
||||
LastFrameHMDHeadPose = CurHMDHeadPose;
|
||||
CurHMDHeadPose = PlayerPose;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif // WITH_OCULUS_BRANCH
|
||||
|
||||
} // namespace OculusXR
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "OpenXR/IOculusXRExtensionPlugin.h"
|
||||
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogOculusMultiPlayerStateExtensionPlugin, Log, All);
|
||||
|
||||
namespace OculusXR
|
||||
{
|
||||
class FMultiPlayerStateExtensionPlugin : public IOculusXRExtensionPlugin
|
||||
{
|
||||
public:
|
||||
FMultiPlayerStateExtensionPlugin();
|
||||
~FMultiPlayerStateExtensionPlugin();
|
||||
|
||||
void SwitchPrimaryPIE(int PrimaryPIEIndex);
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
virtual void ResetPose() override;
|
||||
virtual void ReCalcPose(FTransform& CurHMDHeadPose) override;
|
||||
#endif // WITH_OCULUS_BRANCH
|
||||
private:
|
||||
void InitMultiPlayerPoses(const FTransform& CurPose);
|
||||
|
||||
int CurPlayerIndex;
|
||||
FTransform LastFrameHMDHeadPose;
|
||||
TArray<FTransform> MultiPlayerPoses;
|
||||
};
|
||||
|
||||
} // namespace OculusXR
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#include "OculusXROpenXRUtilities.h"
|
||||
#include "RHICommandList.h"
|
||||
#include "RenderingThread.h"
|
||||
|
||||
namespace OculusXR
|
||||
{
|
||||
XrResult CheckXrResult(XrResult Result, const char* Cmd)
|
||||
{
|
||||
if (!XR_SUCCEEDED(Result))
|
||||
{
|
||||
UE_LOG(LogHMD, Error, TEXT("%hs failed (%d)"), Cmd, Result);
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
IXRTrackingSystem* GetOpenXRTrackingSystem()
|
||||
{
|
||||
static FName SystemName(TEXT("OpenXR"));
|
||||
if (GEngine && GEngine->XRSystem.IsValid() && (GEngine->XRSystem->GetSystemName() == SystemName))
|
||||
{
|
||||
return GEngine->XRSystem.Get();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace OculusXR
|
||||
@@ -0,0 +1,109 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "khronos/openxr/openxr.h"
|
||||
#include "RHI.h"
|
||||
#include "HeadMountedDisplayTypes.h"
|
||||
#include "OpenXRCore.h"
|
||||
#include "IXRTrackingSystem.h"
|
||||
#include "Engine/Engine.h"
|
||||
|
||||
#define ENSURE_XRCMD(cmd) \
|
||||
XR_ENSURE(cmd)
|
||||
|
||||
namespace OculusXR
|
||||
{
|
||||
|
||||
#if defined(WITH_OCULUS_BRANCH)
|
||||
template <typename T>
|
||||
static void XRGetInstanceProcAddr(XrInstance InInstance, const char* Name, T* Function)
|
||||
{
|
||||
if (XR_FAILED(OpenXRDynamicAPI::xrGetInstanceProcAddr(InInstance, Name, reinterpret_cast<PFN_xrVoidFunction*>(Function))))
|
||||
{
|
||||
UE_LOG(LogHMD, Fatal, TEXT("Failed to bind OpenXR entry %s."), ANSI_TO_TCHAR(Name));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void XRGetInstanceProcAddr(XrInstance InInstance, const char* Name, TOptional<T>* Function)
|
||||
{
|
||||
if (XR_FAILED(OpenXRDynamicAPI::xrGetInstanceProcAddr(InInstance, Name, reinterpret_cast<PFN_xrVoidFunction*>(Function))))
|
||||
{
|
||||
UE_LOG(LogHMD, Warning, TEXT("Unable to bind optional OpenXR entry %s."), ANSI_TO_TCHAR(Name));
|
||||
}
|
||||
}
|
||||
|
||||
static void XRAppendToChain(XrBaseOutStructure* ToAppend, XrBaseOutStructure* Chain)
|
||||
{
|
||||
while (Chain->next != XR_NULL_HANDLE)
|
||||
{
|
||||
if (Chain->next == ToAppend)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Chain = Chain->next;
|
||||
}
|
||||
Chain->next = ToAppend;
|
||||
}
|
||||
#else
|
||||
// Don't call xrGetInstanceProcAddr on marketplace build. This prevents the linker
|
||||
// from adding a dependency on OpenXr. On the marketplace build OpenXR loading is
|
||||
// currently disabled
|
||||
template <typename T>
|
||||
static void XRGetInstanceProcAddr(XrInstance InInstance, const char* Name, T* Function)
|
||||
{
|
||||
(void)InInstance;
|
||||
(void)Name;
|
||||
(void)Function;
|
||||
UE_LOG(LogHMD, Warning, TEXT("Failed to bind OpenXR entry %s."), ANSI_TO_TCHAR(Name));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void XRGetInstanceProcAddr(XrInstance InInstance, const char* Name, TOptional<T>* Function)
|
||||
{
|
||||
(void)InInstance;
|
||||
(void)Name;
|
||||
(void)Function;
|
||||
UE_LOG(LogHMD, Warning, TEXT("Unable to bind optional OpenXR entry %s."), ANSI_TO_TCHAR(Name));
|
||||
}
|
||||
|
||||
static void XRAppendToChain(XrBaseOutStructure* ToAppend, XrBaseOutStructure* Chain)
|
||||
{
|
||||
(void)ToAppend;
|
||||
(void)Chain;
|
||||
UE_LOG(LogHMD, Warning, TEXT("Unable to append structure to structure chain. Appending Type: %d -- Base chain Type: %d"), ToAppend->type, Chain->type);
|
||||
}
|
||||
#endif
|
||||
|
||||
XrResult CheckXrResult(XrResult res, const char* cmd);
|
||||
|
||||
static inline double FromXrDuration(const XrDuration duration)
|
||||
{
|
||||
return (duration * 1e-9);
|
||||
}
|
||||
|
||||
static inline XrDuration ToXrDuration(const double duration)
|
||||
{
|
||||
return (duration * 1e9);
|
||||
}
|
||||
|
||||
static inline double FromXrTime(const XrTime time)
|
||||
{
|
||||
return (time * 1e-9);
|
||||
}
|
||||
|
||||
static inline XrTime ToXrTime(const double time)
|
||||
{
|
||||
return (time * 1e9);
|
||||
}
|
||||
|
||||
static bool IsOpenXRSystem()
|
||||
{
|
||||
const FName SystemName(TEXT("OpenXR"));
|
||||
return GEngine->XRSystem.IsValid() && (GEngine->XRSystem->GetSystemName() == SystemName);
|
||||
}
|
||||
|
||||
IXRTrackingSystem* GetOpenXRTrackingSystem();
|
||||
|
||||
} // namespace OculusXR
|
||||
@@ -0,0 +1,244 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#include "OculusXRPerformanceExtensionPlugin.h"
|
||||
#include "OculusXRXRFunctions.h"
|
||||
#include "OculusXROpenXRUtilities.h"
|
||||
#include "OculusXRHMDRuntimeSettings.h"
|
||||
#include "OpenXRCore.h"
|
||||
|
||||
DEFINE_LOG_CATEGORY(LogOculusPerformanceExtensionPlugin);
|
||||
|
||||
namespace OculusXR
|
||||
{
|
||||
|
||||
namespace // anonymous
|
||||
{
|
||||
XrPerfSettingsLevelEXT ToXrPerfSettingsLevel(EOculusXRProcessorPerformanceLevel PerformanceLevel)
|
||||
{
|
||||
switch (PerformanceLevel)
|
||||
{
|
||||
case EOculusXRProcessorPerformanceLevel::PowerSavings:
|
||||
return XR_PERF_SETTINGS_LEVEL_POWER_SAVINGS_EXT;
|
||||
case EOculusXRProcessorPerformanceLevel::SustainedLow:
|
||||
return XR_PERF_SETTINGS_LEVEL_SUSTAINED_LOW_EXT;
|
||||
case EOculusXRProcessorPerformanceLevel::SustainedHigh:
|
||||
return XR_PERF_SETTINGS_LEVEL_SUSTAINED_HIGH_EXT;
|
||||
case EOculusXRProcessorPerformanceLevel::Boost:
|
||||
return XR_PERF_SETTINGS_LEVEL_BOOST_EXT;
|
||||
default:
|
||||
check(false);
|
||||
}
|
||||
return XR_PERF_SETTINGS_LEVEL_POWER_SAVINGS_EXT;
|
||||
}
|
||||
|
||||
static constexpr int MaxCPUCores = CPUCoreLast - CPUCoreStart;
|
||||
|
||||
} // namespace
|
||||
|
||||
FPerformanceExtensionPlugin::FPerformanceExtensionPlugin()
|
||||
: Instance(XR_NULL_HANDLE)
|
||||
, bPerfSettingsInitialized(false)
|
||||
, bPerfLevelsChanged(false)
|
||||
, CpuPerfLevel(EOculusXRProcessorPerformanceLevel::PowerSavings)
|
||||
, GpuPerfLevel(EOculusXRProcessorPerformanceLevel::PowerSavings)
|
||||
, MetricsUpdateMask(0)
|
||||
, PathPerformanceMetricsMap{}
|
||||
, PerformanceMetrics{}
|
||||
, PerformanceMetricsMask(0)
|
||||
{
|
||||
PerformanceMetrics.CpuCoreUtil.Init(0, MaxCPUCores);
|
||||
}
|
||||
|
||||
bool FPerformanceExtensionPlugin::GetRequiredExtensions(TArray<const ANSICHAR*>& OutExtensions)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FPerformanceExtensionPlugin::GetOptionalExtensions(TArray<const ANSICHAR*>& OutExtensions)
|
||||
{
|
||||
OutExtensions.Add(XR_EXT_PERFORMANCE_SETTINGS_EXTENSION_NAME);
|
||||
OutExtensions.Add(XR_META_PERFORMANCE_METRICS_EXTENSION_NAME);
|
||||
return true;
|
||||
}
|
||||
|
||||
void FPerformanceExtensionPlugin::PostCreateSession(XrSession InSession)
|
||||
{
|
||||
const UOculusXRHMDRuntimeSettings* HMDSettings = GetDefault<UOculusXRHMDRuntimeSettings>();
|
||||
LoadFromSettings();
|
||||
InitializePerformanceMetrics(InSession);
|
||||
}
|
||||
|
||||
void* FPerformanceExtensionPlugin::OnWaitFrame(XrSession InSession, void* InNext)
|
||||
{
|
||||
UpdatePerformanceLevels(InSession);
|
||||
UpdatePerformanceMetrics(InSession);
|
||||
return InNext;
|
||||
}
|
||||
|
||||
void FPerformanceExtensionPlugin::PostCreateInstance(XrInstance InInstance)
|
||||
{
|
||||
Instance = InInstance;
|
||||
}
|
||||
|
||||
void FPerformanceExtensionPlugin::UpdatePerformanceLevels(XrSession InSession)
|
||||
{
|
||||
if (bPerfLevelsChanged && xrPerfSettingsSetPerformanceLevelEXT.IsSet() && xrPerfSettingsSetPerformanceLevelEXT.GetValue() != nullptr)
|
||||
{
|
||||
UE_LOG(LogOculusPerformanceExtensionPlugin, Log, TEXT("Oculus OpenXR SetPerformanceLevel CPU=%d, GPU=%d"), CpuPerfLevel, GpuPerfLevel);
|
||||
ENSURE_XRCMD(xrPerfSettingsSetPerformanceLevelEXT.GetValue()(InSession, XR_PERF_SETTINGS_DOMAIN_CPU_EXT, ToXrPerfSettingsLevel(CpuPerfLevel)));
|
||||
ENSURE_XRCMD(xrPerfSettingsSetPerformanceLevelEXT.GetValue()(InSession, XR_PERF_SETTINGS_DOMAIN_GPU_EXT, ToXrPerfSettingsLevel(GpuPerfLevel)));
|
||||
bPerfLevelsChanged = false;
|
||||
}
|
||||
}
|
||||
|
||||
void FPerformanceExtensionPlugin::GetSuggestedCpuAndGpuPerformanceLevels(EOculusXRProcessorPerformanceLevel& CpuLevel, EOculusXRProcessorPerformanceLevel& GpuLevel)
|
||||
{
|
||||
if (!bPerfSettingsInitialized)
|
||||
{
|
||||
LoadFromSettings();
|
||||
}
|
||||
CpuLevel = CpuPerfLevel;
|
||||
GpuLevel = GpuPerfLevel;
|
||||
}
|
||||
|
||||
void FPerformanceExtensionPlugin::SetSuggestedCpuAndGpuPerformanceLevels(EOculusXRProcessorPerformanceLevel CpuLevel, EOculusXRProcessorPerformanceLevel GpuLevel)
|
||||
{
|
||||
if (CpuPerfLevel != CpuLevel || GpuPerfLevel != GpuLevel)
|
||||
{
|
||||
CpuPerfLevel = CpuLevel;
|
||||
GpuPerfLevel = GpuLevel;
|
||||
bPerfLevelsChanged = true;
|
||||
}
|
||||
bPerfSettingsInitialized = true;
|
||||
}
|
||||
|
||||
void FPerformanceExtensionPlugin::LoadFromSettings()
|
||||
{
|
||||
const UOculusXRHMDRuntimeSettings* HMDSettings = GetDefault<UOculusXRHMDRuntimeSettings>();
|
||||
SetSuggestedCpuAndGpuPerformanceLevels(HMDSettings->SuggestedCpuPerfLevel, HMDSettings->SuggestedGpuPerfLevel);
|
||||
}
|
||||
|
||||
void FPerformanceExtensionPlugin::InitializePerformanceMetrics(XrSession InSession)
|
||||
{
|
||||
if (xrEnumeratePerformanceMetricsCounterPathsMETA.GetValue() == 0 || xrSetPerformanceMetricsStateMETA.GetValue() == 0 || xrQueryPerformanceMetricsCounterMETA.GetValue() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TArray<XrPath> PerfMetricsCounterPaths;
|
||||
uint32 NumPerfMetricsCounterPaths = 0;
|
||||
XrPerformanceMetricsStateMETA MetricsState = { XR_TYPE_PERFORMANCE_METRICS_STATE_META };
|
||||
MetricsState.enabled = XR_TRUE;
|
||||
ENSURE_XRCMD(xrSetPerformanceMetricsStateMETA.GetValue()(InSession, &MetricsState));
|
||||
ENSURE_XRCMD(xrEnumeratePerformanceMetricsCounterPathsMETA.GetValue()(Instance, 0, &NumPerfMetricsCounterPaths, nullptr));
|
||||
PerfMetricsCounterPaths.SetNum(NumPerfMetricsCounterPaths);
|
||||
ENSURE_XRCMD(xrEnumeratePerformanceMetricsCounterPathsMETA.GetValue()(Instance, NumPerfMetricsCounterPaths, &NumPerfMetricsCounterPaths, PerfMetricsCounterPaths.GetData()));
|
||||
|
||||
TSet<XrPath> PerfMetricsCounterPathHash;
|
||||
|
||||
for (auto& Path : PerfMetricsCounterPaths)
|
||||
{
|
||||
PerfMetricsCounterPathHash.Emplace(Path);
|
||||
}
|
||||
|
||||
auto AddMetrics = [&](FString Name, EPerformanceMetricsType Metric) {
|
||||
const FOpenXRPath MetricsPath(Name);
|
||||
if (PerfMetricsCounterPathHash.Contains(MetricsPath))
|
||||
{
|
||||
PathPerformanceMetricsMap.Add(MetricsPath, Metric);
|
||||
PerformanceMetricsMask |= static_cast<uint64>(1) << Metric;
|
||||
UE_LOG(LogOculusPerformanceExtensionPlugin, Log, TEXT("Supported Performance Metrics: %s"), *Name);
|
||||
}
|
||||
};
|
||||
|
||||
AddMetrics(TEXT("/perfmetrics_meta/app/cpu_frametime"), AppCPUTimeFloat);
|
||||
AddMetrics(TEXT("/perfmetrics_meta/app/gpu_frametime"), AppGPUTimeFloat);
|
||||
AddMetrics(TEXT("/perfmetrics_meta/compositor/cpu_frametime"), CompositorCPUTimeFloat);
|
||||
AddMetrics(TEXT("/perfmetrics_meta/compositor/gpu_frametime"), CompositorGPUTimeFloat);
|
||||
AddMetrics(TEXT("/perfmetrics_meta/compositor/dropped_frame_count"), CompositorDroppedFramesInt);
|
||||
AddMetrics(TEXT("/perfmetrics_meta/compositor/spacewarp_mode"), CompositorSpaceWarpModeInt);
|
||||
AddMetrics(TEXT("/perfmetrics_meta/device/gpu_utilization"), GPUUtilizationFloat);
|
||||
AddMetrics(TEXT("/perfmetrics_meta/device/cpu_utilization_average"), GPUUtilizationAverageFloat);
|
||||
AddMetrics(TEXT("/perfmetrics_meta/device/cpu_utilization_worst"), GPUUtilizationWorstFloat);
|
||||
|
||||
for (uint32 CPUId = 0; CPUId < MaxCPUCores; ++CPUId)
|
||||
{
|
||||
const FString PerCpuCounterPathString = FString::Printf(TEXT("/perfmetrics_meta/device/cpu%d_utilization"), CPUId);
|
||||
AddMetrics(PerCpuCounterPathString,
|
||||
static_cast<EPerformanceMetricsType>(CPUCore0UtilizationFloat + CPUId));
|
||||
}
|
||||
}
|
||||
|
||||
bool FPerformanceExtensionPlugin::IsPerformanceMetricsSupported(EPerformanceMetricsType Metric) const
|
||||
{
|
||||
const uint64_t Val = static_cast<uint64>(1) << Metric;
|
||||
return ((PerformanceMetricsMask & Val) != 0);
|
||||
}
|
||||
|
||||
void FPerformanceExtensionPlugin::UpdatePerformanceMetrics(XrSession InSession)
|
||||
{
|
||||
if ((xrQueryPerformanceMetricsCounterMETA.GetValue() == 0) || (PerformanceMetricsMask == 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& Pair : PathPerformanceMetricsMap)
|
||||
{
|
||||
const XrPath Path = Pair.Key;
|
||||
const EPerformanceMetricsType Metric = Pair.Value;
|
||||
XrPerformanceMetricsCounterMETA Counter = { XR_TYPE_PERFORMANCE_METRICS_COUNTER_META };
|
||||
ENSURE_XRCMD(xrQueryPerformanceMetricsCounterMETA.GetValue()(InSession, Path, &Counter));
|
||||
|
||||
switch (Metric)
|
||||
{
|
||||
case AppCPUTimeFloat:
|
||||
PerformanceMetrics.AppCpuTime = Counter.floatValue;
|
||||
break;
|
||||
case AppGPUTimeFloat:
|
||||
PerformanceMetrics.AppGpuTime = Counter.floatValue;
|
||||
break;
|
||||
case CompositorCPUTimeFloat:
|
||||
PerformanceMetrics.ComCpuTime = Counter.floatValue;
|
||||
break;
|
||||
case CompositorGPUTimeFloat:
|
||||
PerformanceMetrics.ComGpuTime = Counter.floatValue;
|
||||
break;
|
||||
case CompositorDroppedFramesInt:
|
||||
PerformanceMetrics.DroppedFrames = Counter.uintValue;
|
||||
break;
|
||||
case CompositorSpaceWarpModeInt:
|
||||
PerformanceMetrics.ComSpaceWarpMode = Counter.uintValue;
|
||||
break;
|
||||
case GPUUtilizationFloat:
|
||||
PerformanceMetrics.GpuUtil = Counter.floatValue;
|
||||
break;
|
||||
case GPUUtilizationAverageFloat:
|
||||
PerformanceMetrics.CpuUtilAvg = Counter.floatValue;
|
||||
break;
|
||||
case GPUUtilizationWorstFloat:
|
||||
PerformanceMetrics.CpuUtilWorst = Counter.floatValue;
|
||||
break;
|
||||
default:
|
||||
{
|
||||
if (Metric >= CPUCore0UtilizationFloat && Metric < CPUCore0UtilizationFloat + MaxCPUCores)
|
||||
{
|
||||
const int32 CpuCoreIdx = Metric - CPUCore0UtilizationFloat;
|
||||
check(CpuCoreIdx < PerformanceMetrics.CpuCoreUtil.Num());
|
||||
PerformanceMetrics.CpuCoreUtil[CpuCoreIdx] = Counter.floatValue / 100.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogOculusPerformanceExtensionPlugin, Log, TEXT("Unsupported Metric: %d"), static_cast<uint32>(Metric));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const FOculusXRPerformanceMetrics& FPerformanceExtensionPlugin::GetPerformanceMetrics() const
|
||||
{
|
||||
return PerformanceMetrics;
|
||||
}
|
||||
|
||||
} // namespace OculusXR
|
||||
@@ -0,0 +1,70 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
#include "CoreMinimal.h"
|
||||
#include "OculusXRHMDTypes.h"
|
||||
#include "OpenXR/IOculusXRExtensionPlugin.h"
|
||||
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogOculusPerformanceExtensionPlugin, Log, All);
|
||||
|
||||
namespace OculusXR
|
||||
{
|
||||
enum EPerformanceMetricsType
|
||||
{
|
||||
AppCPUTimeFloat,
|
||||
AppGPUTimeFloat,
|
||||
CompositorCPUTimeFloat,
|
||||
CompositorGPUTimeFloat,
|
||||
CompositorDroppedFramesInt,
|
||||
CompositorSpaceWarpModeInt,
|
||||
GPUUtilizationFloat,
|
||||
GPUUtilizationAverageFloat,
|
||||
GPUUtilizationWorstFloat,
|
||||
CPUCoreStart,
|
||||
CPUCore0UtilizationFloat,
|
||||
CPUCore1UtilizationFloat,
|
||||
CPUCore2UtilizationFloat,
|
||||
CPUCore3UtilizationFloat,
|
||||
CPUCore4UtilizationFloat,
|
||||
CPUCore5UtilizationFloat,
|
||||
CPUCore6UtilizationFloat,
|
||||
CPUCore7UtilizationFloat,
|
||||
CPUCoreLast = CPUCore7UtilizationFloat,
|
||||
};
|
||||
|
||||
class FPerformanceExtensionPlugin : public IOculusXRExtensionPlugin
|
||||
{
|
||||
private:
|
||||
XrInstance Instance;
|
||||
bool bPerfSettingsInitialized;
|
||||
bool bPerfLevelsChanged;
|
||||
EOculusXRProcessorPerformanceLevel CpuPerfLevel;
|
||||
EOculusXRProcessorPerformanceLevel GpuPerfLevel;
|
||||
uint64_t MetricsUpdateMask;
|
||||
|
||||
TMap<XrPath, EPerformanceMetricsType> PathPerformanceMetricsMap;
|
||||
FOculusXRPerformanceMetrics PerformanceMetrics;
|
||||
uint64 PerformanceMetricsMask;
|
||||
|
||||
public:
|
||||
FPerformanceExtensionPlugin();
|
||||
|
||||
// IOpenXRExtensionPlugin
|
||||
virtual bool GetRequiredExtensions(TArray<const ANSICHAR*>& OutExtensions) override;
|
||||
virtual bool GetOptionalExtensions(TArray<const ANSICHAR*>& OutExtensions) override;
|
||||
virtual void PostCreateSession(XrSession InSession) override;
|
||||
virtual void PostCreateInstance(XrInstance InInstance) override;
|
||||
virtual void* OnWaitFrame(XrSession InSession, void* InNext) override;
|
||||
|
||||
void UpdatePerformanceLevels(XrSession InSession);
|
||||
void GetSuggestedCpuAndGpuPerformanceLevels(EOculusXRProcessorPerformanceLevel& CpuPerfLevel, EOculusXRProcessorPerformanceLevel& GpuPerfLevel);
|
||||
void SetSuggestedCpuAndGpuPerformanceLevels(EOculusXRProcessorPerformanceLevel CpuPerfLevel, EOculusXRProcessorPerformanceLevel GpuPerfLevel);
|
||||
void LoadFromSettings();
|
||||
|
||||
void InitializePerformanceMetrics(XrSession InSession);
|
||||
bool IsPerformanceMetricsSupported(EPerformanceMetricsType Metric) const;
|
||||
void UpdatePerformanceMetrics(XrSession InSession);
|
||||
const FOculusXRPerformanceMetrics& GetPerformanceMetrics() const;
|
||||
};
|
||||
|
||||
} // namespace OculusXR
|
||||
@@ -0,0 +1,19 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#include "OculusXRSimulatorExtensionPlugin.h"
|
||||
|
||||
#include "OculusXRSimulator.h"
|
||||
|
||||
DEFINE_LOG_CATEGORY(LogOculusXRSimulatorPlugin);
|
||||
|
||||
namespace OculusXR
|
||||
{
|
||||
bool FXRSimulatorExtensionPlugin::GetCustomLoader(PFN_xrGetInstanceProcAddr* OutGetProcAddr)
|
||||
{
|
||||
#if PLATFORM_WINDOWS
|
||||
FMetaXRSimulator::TryActivateOnStartup();
|
||||
#endif // PLATFORM_WINDOWS
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace OculusXR
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
#include "OpenXR/IOculusXRExtensionPlugin.h"
|
||||
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogOculusXRSimulatorPlugin, Log, All);
|
||||
|
||||
namespace OculusXR
|
||||
{
|
||||
|
||||
class FXRSimulatorExtensionPlugin : public IOculusXRExtensionPlugin
|
||||
{
|
||||
public:
|
||||
// IOpenXRExtensionPlugin
|
||||
virtual bool GetCustomLoader(PFN_xrGetInstanceProcAddr* OutGetProcAddr) override;
|
||||
};
|
||||
|
||||
} // namespace OculusXR
|
||||
@@ -0,0 +1,386 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#include "OculusXRSpaceWarp.h"
|
||||
#include "IOpenXRHMD.h"
|
||||
#include "IOpenXRHMDModule.h"
|
||||
#include "IXRTrackingSystem.h"
|
||||
#include "OculusXROpenXRUtilities.h"
|
||||
#include "OpenXRCore.h"
|
||||
#include "OpenXRHMD_Swapchain.h"
|
||||
#include "StereoRenderUtils.h"
|
||||
|
||||
#if defined(WITH_OCULUS_BRANCH)
|
||||
|
||||
DEFINE_LOG_CATEGORY(LogOculusSpaceWarpExtensionPlugin);
|
||||
|
||||
static const int64 VELOCITY_SWAPCHAIN_WAIT_TIMEOUT = 100000000ll; // 100ms in nanoseconds.
|
||||
|
||||
namespace OculusXR
|
||||
{
|
||||
FSpaceWarpExtensionPlugin::FSpaceWarpExtensionPlugin()
|
||||
{
|
||||
}
|
||||
|
||||
bool FSpaceWarpExtensionPlugin::GetRequiredExtensions(TArray<const ANSICHAR*>& OutExtensions)
|
||||
{
|
||||
UE_LOG(LogOculusSpaceWarpExtensionPlugin, Warning, TEXT("FSpaceWarpExtensionPlugin::GetRequiredExtensions"));
|
||||
|
||||
static const auto CVarSupportMobileSpaceWarp = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("vr.SupportMobileSpaceWarp"));
|
||||
if (CVarSupportMobileSpaceWarp && (CVarSupportMobileSpaceWarp->GetValueOnAnyThread() != 0))
|
||||
{
|
||||
OutExtensions.Add(XR_FB_SPACE_WARP_EXTENSION_NAME);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void* FSpaceWarpExtensionPlugin::OnEnumerateViewConfigurationViews(XrInstance InInstance, XrSystemId InSystem, XrViewConfigurationType InViewConfigurationType, uint32_t InViewIndex, void* InNext)
|
||||
{
|
||||
SelectedViewConfigurationType = InViewConfigurationType;
|
||||
return InNext;
|
||||
}
|
||||
|
||||
const void* FSpaceWarpExtensionPlugin::OnCreateInstance(IOpenXRHMDModule* InModule, const void* InNext)
|
||||
{
|
||||
static const auto CVarSupportMobileSpaceWarp = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("vr.SupportMobileSpaceWarp"));
|
||||
if (InModule && CVarSupportMobileSpaceWarp && (CVarSupportMobileSpaceWarp->GetValueOnAnyThread() != 0))
|
||||
{
|
||||
bSpaceWarpExtensionEnabled = InModule->IsExtensionEnabled(XR_FB_SPACE_WARP_EXTENSION_NAME);
|
||||
}
|
||||
|
||||
return InNext;
|
||||
}
|
||||
|
||||
void FSpaceWarpExtensionPlugin::PostCreateInstance(XrInstance InInstance)
|
||||
{
|
||||
if (!bSpaceWarpExtensionEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
XrInstanceProperties InstanceProperties = { XR_TYPE_INSTANCE_PROPERTIES, nullptr };
|
||||
XR_ENSURE(xrGetInstanceProperties(InInstance, &InstanceProperties));
|
||||
InstanceProperties.runtimeName[XR_MAX_RUNTIME_NAME_SIZE - 1] = 0; // Ensure the name is null terminated.
|
||||
}
|
||||
|
||||
void FSpaceWarpExtensionPlugin::PostCreateSession(XrSession InSession)
|
||||
{
|
||||
if (!bSpaceWarpExtensionEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
XrSystemProperties SystemProperties;
|
||||
SystemProperties = XrSystemProperties{ XR_TYPE_SYSTEM_PROPERTIES, &SpaceWarpSystemProperties };
|
||||
XR_ENSURE(xrGetSystemProperties(IOpenXRHMDModule::Get().GetInstance(), IOpenXRHMDModule::Get().GetSystemId(), &SystemProperties));
|
||||
|
||||
SpaceWarpViewExtension = FSceneViewExtensions::NewExtension<FSpaceWarpViewExtension>(this);
|
||||
|
||||
UE::StereoRenderUtils::FStereoShaderAspects Aspects(GMaxRHIShaderPlatform);
|
||||
bIsMobileMultiViewEnabled = Aspects.IsMobileMultiViewEnabled();
|
||||
}
|
||||
|
||||
void FSpaceWarpExtensionPlugin::OnBeginRendering_RenderThread(XrSession InSession)
|
||||
{
|
||||
check(IsInRenderingThread());
|
||||
|
||||
if (!PipelinedVelocityState_RenderThread.bEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SCOPED_NAMED_EVENT(FSpaceWarpExtensionPlugin_OnBeginRendering_RenderThread, FColor::Red);
|
||||
|
||||
const FXRSwapChainPtr& VelocitySwapchain = PipelinedVelocityState_RenderThread.VelocitySwapchain;
|
||||
const FXRSwapChainPtr& VelocityDepthSwapchain = PipelinedVelocityState_RenderThread.VelocityDepthSwapchain;
|
||||
if (VelocitySwapchain)
|
||||
{
|
||||
VelocitySwapchain->IncrementSwapChainIndex_RHIThread();
|
||||
if (VelocityDepthSwapchain)
|
||||
{
|
||||
VelocityDepthSwapchain->IncrementSwapChainIndex_RHIThread();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const void* FSpaceWarpExtensionPlugin::OnBeginProjectionView(XrSession InSession, int32 InLayerIndex, int32 InViewIndex, const void* InNext)
|
||||
{
|
||||
check(IsInRenderingThread());
|
||||
|
||||
IXRTrackingSystem* XRTrackingSystem = GetOpenXRTrackingSystem();
|
||||
if (!XRTrackingSystem || !PipelinedVelocityState_RenderThread.bEnabled)
|
||||
{
|
||||
return InNext;
|
||||
}
|
||||
|
||||
SCOPED_NAMED_EVENT(FSpaceWarpExtensionPlugin_OnBeginProjectionView, FColor::Red);
|
||||
|
||||
TSharedPtr<XrCompositionLayerSpaceWarpInfoFB> SpaceWarpLayerInfo = MakeShared<XrCompositionLayerSpaceWarpInfoFB>();
|
||||
|
||||
FTransform TrackingToWorld = XRTrackingSystem->GetTrackingToWorldTransform();
|
||||
FTransform TrackingSpaceDeltaPose = TrackingToWorld * LastTrackingToWorld.Inverse();
|
||||
LastTrackingToWorld = TrackingToWorld;
|
||||
FTransform BaseTransform = FTransform(XRTrackingSystem->GetBaseOrientation(), XRTrackingSystem->GetBasePosition());
|
||||
TrackingSpaceDeltaPose = BaseTransform.Inverse() * TrackingSpaceDeltaPose * BaseTransform;
|
||||
|
||||
SpaceWarpLayerInfo->type = XR_TYPE_COMPOSITION_LAYER_SPACE_WARP_INFO_FB;
|
||||
SpaceWarpLayerInfo->next = InNext;
|
||||
SpaceWarpLayerInfo->layerFlags = 0;
|
||||
SpaceWarpLayerInfo->appSpaceDeltaPose = ToXrPose(TrackingSpaceDeltaPose);
|
||||
SpaceWarpLayerInfo->farZ = GNearClippingPlane / 100.f;
|
||||
SpaceWarpLayerInfo->nearZ = INFINITY;
|
||||
SpaceWarpLayerInfo->minDepth = 0.0f;
|
||||
SpaceWarpLayerInfo->maxDepth = 1.0f;
|
||||
|
||||
FIntPoint TextureSize;
|
||||
if (GetRecommendedVelocityTextureSize_RenderThread(TextureSize) && PipelinedVelocityState_RenderThread.VelocitySwapchain.IsValid())
|
||||
{
|
||||
FIntPoint TextureOffset(0, 0);
|
||||
FIntRect ImageRect(TextureOffset, TextureOffset + TextureSize);
|
||||
|
||||
TSharedPtr<XrSwapchainSubImage> VelocityImage = MakeShared<XrSwapchainSubImage>();
|
||||
VelocityImage->swapchain = static_cast<FOpenXRSwapchain*>(PipelinedVelocityState_RenderThread.VelocitySwapchain.Get())->GetHandle();
|
||||
VelocityImage->imageArrayIndex = (bIsMobileMultiViewEnabled && InViewIndex < 2) ? InViewIndex : 0;
|
||||
VelocityImage->imageRect = ToXrRect(ImageRect);
|
||||
SpaceWarpLayerInfo->motionVectorSubImage = *VelocityImage;
|
||||
|
||||
TSharedPtr<XrSwapchainSubImage> VelocityDepthImage = nullptr;
|
||||
if (PipelinedVelocityState_RenderThread.VelocityDepthSwapchain.IsValid())
|
||||
{
|
||||
VelocityDepthImage = MakeShared<XrSwapchainSubImage>();
|
||||
VelocityDepthImage->swapchain = static_cast<FOpenXRSwapchain*>(PipelinedVelocityState_RenderThread.VelocityDepthSwapchain.Get())->GetHandle();
|
||||
VelocityDepthImage->imageArrayIndex = (bIsMobileMultiViewEnabled && InViewIndex < 2) ? InViewIndex : 0;
|
||||
VelocityDepthImage->imageRect = ToXrRect(ImageRect);
|
||||
SpaceWarpLayerInfo->depthSubImage = *VelocityDepthImage;
|
||||
}
|
||||
|
||||
// The SpaceWarpInfo that we return from here gets used when the layer is submitted on xrEndFrame on the RHI Thread,
|
||||
// so we need to keep the XrSwapchainSubImage objects on the RHI Thread until PostEndFrame_RHIThread()
|
||||
GetImmediateCommandList_ForRenderCommand().EnqueueLambda([this, SpaceWarpLayerInfo, VelocityImage, VelocityDepthImage, InViewIndex](FRHICommandList& RHICmdList) {
|
||||
if (SpaceWarpLayerInfo_RHIThread.IsValidIndex(InViewIndex))
|
||||
{
|
||||
SpaceWarpLayerInfo_RHIThread[InViewIndex] = SpaceWarpLayerInfo;
|
||||
}
|
||||
|
||||
if (VelocityImages_RHIThread.IsValidIndex(InViewIndex) && VelocityImage.IsValid())
|
||||
{
|
||||
VelocityImages_RHIThread[InViewIndex] = VelocityImage;
|
||||
}
|
||||
|
||||
if (VelocityDepthImages_RHIThread.IsValidIndex(InViewIndex) && VelocityDepthImage.IsValid())
|
||||
{
|
||||
VelocityDepthImages_RHIThread[InViewIndex] = VelocityDepthImage;
|
||||
}
|
||||
});
|
||||
|
||||
return SpaceWarpLayerInfo.Get();
|
||||
}
|
||||
return InNext;
|
||||
}
|
||||
|
||||
void FSpaceWarpExtensionPlugin::PostBeginFrame_RHIThread(XrTime PredictedDisplayTime)
|
||||
{
|
||||
check(IsRunningRHIInSeparateThread() ? IsInRHIThread() : IsInRenderingThread());
|
||||
|
||||
if (!PipelinedVelocityState_RHIThread.bEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SCOPED_NAMED_EVENT(FSpaceWarpExtensionPlugin_PostBeginFrame_RHIThread, FColor::Red);
|
||||
|
||||
// We need a new swapchain image unless we've already acquired one for rendering
|
||||
if (PipelinedVelocityState_RHIThread.VelocitySwapchain.IsValid())
|
||||
{
|
||||
PipelinedVelocityState_RHIThread.VelocitySwapchain->WaitCurrentImage_RHIThread(VELOCITY_SWAPCHAIN_WAIT_TIMEOUT);
|
||||
if (PipelinedVelocityState_RHIThread.VelocityDepthSwapchain.IsValid())
|
||||
{
|
||||
PipelinedVelocityState_RHIThread.VelocityDepthSwapchain->WaitCurrentImage_RHIThread(VELOCITY_SWAPCHAIN_WAIT_TIMEOUT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const void* FSpaceWarpExtensionPlugin::OnEndFrame(XrSession InSession, XrTime DisplayTime, const void* InNext)
|
||||
{
|
||||
check(IsRunningRHIInSeparateThread() ? IsInRHIThread() : IsInRenderingThread());
|
||||
|
||||
if (!PipelinedVelocityState_RHIThread.bEnabled)
|
||||
{
|
||||
return InNext;
|
||||
}
|
||||
|
||||
SCOPED_NAMED_EVENT(FSpaceWarpExtensionPlugin_OnEndFrame, FColor::Red);
|
||||
|
||||
if (PipelinedVelocityState_RHIThread.VelocitySwapchain.IsValid())
|
||||
{
|
||||
PipelinedVelocityState_RHIThread.VelocitySwapchain->ReleaseCurrentImage_RHIThread(nullptr);
|
||||
if (PipelinedVelocityState_RHIThread.VelocityDepthSwapchain.IsValid())
|
||||
{
|
||||
PipelinedVelocityState_RHIThread.VelocityDepthSwapchain->ReleaseCurrentImage_RHIThread(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
return InNext;
|
||||
}
|
||||
|
||||
void FSpaceWarpExtensionPlugin::PostEndFrame_RHIThread()
|
||||
{
|
||||
SpaceWarpLayerInfo_RHIThread.Reset();
|
||||
VelocityImages_RHIThread.Reset();
|
||||
VelocityDepthImages_RHIThread.Reset();
|
||||
}
|
||||
|
||||
void FSpaceWarpExtensionPlugin::AllocateRenderTargetTextures_RenderThread()
|
||||
{
|
||||
check(IsInRenderingThread());
|
||||
|
||||
if (!bSpaceWarpExtensionEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SCOPED_NAMED_EVENT(FSpaceWarpExtensionPlugin_AllocateRenderTargetTextures_RenderThread, FColor::Red);
|
||||
|
||||
FIntPoint VelocitySize;
|
||||
if (GetRecommendedVelocityTextureSize_RenderThread(VelocitySize))
|
||||
{
|
||||
IOpenXRHMD* OpenXRHMD = nullptr;
|
||||
if (GEngine && GEngine->XRSystem.IsValid())
|
||||
{
|
||||
OpenXRHMD = GEngine->XRSystem.Get()->GetIOpenXRHMD();
|
||||
if (OpenXRHMD)
|
||||
{
|
||||
uint8 UnusedActualFormat = 0;
|
||||
const FOpenXRSwapchainProperties VelocitySwapchainProperties = {
|
||||
TEXT("VelocitySwapchain"),
|
||||
PF_FloatRGBA,
|
||||
static_cast<uint32>(VelocitySize.X),
|
||||
static_cast<uint32>(VelocitySize.Y),
|
||||
static_cast<uint32>(bIsMobileMultiViewEnabled ? 2 : 1),
|
||||
1,
|
||||
1,
|
||||
// BEGIN META SECTION - Add XR Cubemap Support
|
||||
(bIsMobileMultiViewEnabled) ? ETextureDimension::Texture2DArray : ETextureDimension::Texture2D,
|
||||
// END META SECTION - Add XR Cubemap Support
|
||||
TexCreate_RenderTargetable | TexCreate_ResolveTargetable | TexCreate_ShaderResource | TexCreate_InputAttachmentRead | TexCreate_Dynamic,
|
||||
FClearValueBinding::Transparent,
|
||||
TexCreate_None
|
||||
};
|
||||
|
||||
OpenXRHMD->AllocateSwapchainTextures_RenderThread(
|
||||
VelocitySwapchainProperties,
|
||||
PipelinedVelocityState_RenderThread.VelocitySwapchain,
|
||||
UnusedActualFormat);
|
||||
|
||||
const FOpenXRSwapchainProperties VelocityDepthSwapchainProperties = {
|
||||
TEXT("VelocityDepthSwapchain"),
|
||||
PF_DepthStencil,
|
||||
static_cast<uint32>(VelocitySize.X),
|
||||
static_cast<uint32>(VelocitySize.Y),
|
||||
static_cast<uint32>(bIsMobileMultiViewEnabled ? 2 : 1),
|
||||
1,
|
||||
1,
|
||||
// BEGIN META SECTION - Add XR Cubemap Support
|
||||
(bIsMobileMultiViewEnabled) ? ETextureDimension::Texture2DArray : ETextureDimension::Texture2D,
|
||||
// END META SECTION - Add XR Cubemap Support
|
||||
TexCreate_DepthStencilTargetable | TexCreate_ShaderResource | TexCreate_InputAttachmentRead | TexCreate_Dynamic,
|
||||
FClearValueBinding::DepthZero,
|
||||
TexCreate_None
|
||||
};
|
||||
OpenXRHMD->AllocateSwapchainTextures_RenderThread(
|
||||
VelocityDepthSwapchainProperties,
|
||||
PipelinedVelocityState_RenderThread.VelocityDepthSwapchain,
|
||||
UnusedActualFormat);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool FSpaceWarpExtensionPlugin::GetRecommendedVelocityTextureSize_RenderThread(FIntPoint& OutTextureSize)
|
||||
{
|
||||
check(IsInRenderingThread());
|
||||
|
||||
if (!bSpaceWarpExtensionEnabled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
OutTextureSize = FIntPoint(SpaceWarpSystemProperties.recommendedMotionVectorImageRectWidth, SpaceWarpSystemProperties.recommendedMotionVectorImageRectHeight);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FXRSwapChainPtr FSpaceWarpExtensionPlugin::GetVelocitySwapchain_RenderThread()
|
||||
{
|
||||
check(IsInRenderingThread());
|
||||
|
||||
if (!PipelinedVelocityState_RenderThread.bEnabled)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return PipelinedVelocityState_RenderThread.VelocitySwapchain;
|
||||
}
|
||||
|
||||
FXRSwapChainPtr FSpaceWarpExtensionPlugin::GetVelocityDepthSwapchain_RenderThread()
|
||||
{
|
||||
check(IsInRenderingThread());
|
||||
|
||||
if (!PipelinedVelocityState_RenderThread.bEnabled)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return PipelinedVelocityState_RenderThread.VelocityDepthSwapchain;
|
||||
}
|
||||
|
||||
bool FSpaceWarpExtensionPlugin::IsSpaceWarpEnabled() const
|
||||
{
|
||||
if (bSpaceWarpExtensionEnabled)
|
||||
{
|
||||
static const auto CVarOculusEnableSpaceWarp = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.Mobile.Oculus.SpaceWarp.Enable"));
|
||||
return CVarOculusEnableSpaceWarp && (CVarOculusEnableSpaceWarp->GetValueOnAnyThread() != 0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
FSpaceWarpExtensionPlugin::FSpaceWarpViewExtension::FSpaceWarpViewExtension(const FAutoRegister& AutoRegister, FSpaceWarpExtensionPlugin* InPlugin)
|
||||
: FHMDSceneViewExtension(AutoRegister)
|
||||
, SpaceWarpExtensionPlugin(InPlugin)
|
||||
{
|
||||
check(SpaceWarpExtensionPlugin);
|
||||
}
|
||||
|
||||
void FSpaceWarpExtensionPlugin::FSpaceWarpViewExtension::SetupViewFamily(FSceneViewFamily& InViewFamily)
|
||||
{
|
||||
check(IsInGameThread())
|
||||
InViewFamily.bRenderStereoVelocity = SpaceWarpExtensionPlugin->IsSpaceWarpEnabled();
|
||||
}
|
||||
|
||||
void FSpaceWarpExtensionPlugin::FSpaceWarpViewExtension::SetupView(FSceneViewFamily& InViewFamily, FSceneView& InView)
|
||||
{
|
||||
}
|
||||
|
||||
void FSpaceWarpExtensionPlugin::FSpaceWarpViewExtension::BeginRenderViewFamily(FSceneViewFamily& InViewFamily)
|
||||
{
|
||||
bool bEnabled = SpaceWarpExtensionPlugin->IsSpaceWarpEnabled();
|
||||
|
||||
ENQUEUE_RENDER_COMMAND(FSpaceWarpViewExtension_BeginRenderViewFamily)
|
||||
([this, bEnabled](FRHICommandList& RHICmdList) {
|
||||
SpaceWarpExtensionPlugin->PipelinedVelocityState_RenderThread.bEnabled = bEnabled;
|
||||
|
||||
FPipelinedVelocityState VelocityState = SpaceWarpExtensionPlugin->PipelinedVelocityState_RenderThread;
|
||||
RHICmdList.EnqueueLambda([this, VelocityState, bEnabled](FRHICommandList& RHICmdList) {
|
||||
SpaceWarpExtensionPlugin->PipelinedVelocityState_RHIThread = VelocityState;
|
||||
|
||||
uint32_t ViewConfigCount = 0;
|
||||
XR_ENSURE(xrEnumerateViewConfigurationViews(IOpenXRHMDModule::Get().GetInstance(), IOpenXRHMDModule::Get().GetSystemId(), SpaceWarpExtensionPlugin->SelectedViewConfigurationType, 0, &ViewConfigCount, nullptr));
|
||||
SpaceWarpExtensionPlugin->SpaceWarpLayerInfo_RHIThread.SetNum(ViewConfigCount);
|
||||
SpaceWarpExtensionPlugin->VelocityImages_RHIThread.SetNum(ViewConfigCount);
|
||||
SpaceWarpExtensionPlugin->VelocityDepthImages_RHIThread.SetNum(ViewConfigCount);
|
||||
});
|
||||
});
|
||||
}
|
||||
} // namespace OculusXR
|
||||
|
||||
#endif // defined(WITH_OCULUS_BRANCH)
|
||||
@@ -0,0 +1,84 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
#include "CoreMinimal.h"
|
||||
#include "SceneViewExtension.h"
|
||||
#include "XRSwapChain.h"
|
||||
#include "OpenXR/IOculusXRExtensionPlugin.h"
|
||||
|
||||
#if defined(WITH_OCULUS_BRANCH)
|
||||
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogOculusSpaceWarpExtensionPlugin, Log, All);
|
||||
|
||||
struct FOpenXRSwapchainProperties;
|
||||
|
||||
namespace OculusXR
|
||||
{
|
||||
class FSpaceWarpExtensionPlugin : public IOculusXRExtensionPlugin
|
||||
{
|
||||
public:
|
||||
FSpaceWarpExtensionPlugin();
|
||||
|
||||
// IOpenXRExtensionPlugin
|
||||
virtual bool GetRequiredExtensions(TArray<const ANSICHAR*>& OutExtensions) override;
|
||||
virtual void* OnEnumerateViewConfigurationViews(XrInstance InInstance, XrSystemId InSystem, XrViewConfigurationType InViewConfigurationType, uint32_t InViewIndex, void* InNext) override;
|
||||
virtual const void* OnCreateInstance(IOpenXRHMDModule* InModule, const void* InNext) override;
|
||||
virtual void PostCreateInstance(XrInstance InInstance) override;
|
||||
virtual void PostCreateSession(XrSession InSession) override;
|
||||
virtual void OnBeginRendering_RenderThread(XrSession InSession) override;
|
||||
virtual const void* OnBeginProjectionView(XrSession InSession, int32 InLayerIndex, int32 InViewIndex, const void* InNext) override;
|
||||
virtual void PostBeginFrame_RHIThread(XrTime PredictedDisplayTime) override;
|
||||
virtual const void* OnEndFrame(XrSession InSession, XrTime DisplayTime, const void* InNext) override;
|
||||
virtual void PostEndFrame_RHIThread() override;
|
||||
virtual void AllocateRenderTargetTextures_RenderThread() override;
|
||||
virtual bool GetRecommendedVelocityTextureSize_RenderThread(FIntPoint& OutTextureSize) override;
|
||||
virtual FXRSwapChainPtr GetVelocitySwapchain_RenderThread() override;
|
||||
virtual FXRSwapChainPtr GetVelocityDepthSwapchain_RenderThread() override;
|
||||
|
||||
bool IsSpaceWarpEnabled() const;
|
||||
|
||||
private:
|
||||
class FSpaceWarpViewExtension : public FHMDSceneViewExtension
|
||||
{
|
||||
public:
|
||||
FSpaceWarpViewExtension(const FAutoRegister& AutoRegister, FSpaceWarpExtensionPlugin* InPlugin);
|
||||
|
||||
// ISceneViewExtension
|
||||
virtual void SetupViewFamily(FSceneViewFamily& InViewFamily) override;
|
||||
virtual void SetupView(FSceneViewFamily& InViewFamily, FSceneView& InView) override;
|
||||
virtual void BeginRenderViewFamily(FSceneViewFamily& InViewFamily) override;
|
||||
|
||||
private:
|
||||
friend FSpaceWarpExtensionPlugin;
|
||||
|
||||
FSpaceWarpExtensionPlugin* SpaceWarpExtensionPlugin = nullptr;
|
||||
};
|
||||
|
||||
struct FPipelinedVelocityState
|
||||
{
|
||||
FXRSwapChainPtr VelocitySwapchain;
|
||||
FXRSwapChainPtr VelocityDepthSwapchain;
|
||||
|
||||
bool bEnabled = false;
|
||||
};
|
||||
|
||||
TArray<TSharedPtr<XrSwapchainSubImage>> VelocityImages_RHIThread;
|
||||
TArray<TSharedPtr<XrSwapchainSubImage>> VelocityDepthImages_RHIThread;
|
||||
TArray<TSharedPtr<XrCompositionLayerSpaceWarpInfoFB>> SpaceWarpLayerInfo_RHIThread;
|
||||
|
||||
std::atomic<bool> bSpaceWarpExtensionEnabled = false;
|
||||
bool bIsMobileMultiViewEnabled = false;
|
||||
|
||||
TSharedPtr<FSpaceWarpViewExtension> SpaceWarpViewExtension = nullptr;
|
||||
FPipelinedVelocityState PipelinedVelocityState_RenderThread = {};
|
||||
FPipelinedVelocityState PipelinedVelocityState_RHIThread = {};
|
||||
|
||||
XrViewConfigurationType SelectedViewConfigurationType = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO;
|
||||
XrSystemSpaceWarpPropertiesFB SpaceWarpSystemProperties = { XR_TYPE_SYSTEM_SPACE_WARP_PROPERTIES_FB };
|
||||
|
||||
FTransform LastTrackingToWorld = FTransform::Identity;
|
||||
};
|
||||
|
||||
} // namespace OculusXR
|
||||
|
||||
#endif // defined(WITH_OCULUS_BRANCH)
|
||||
@@ -0,0 +1,619 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#include "OculusXRSystemInfoExtensionPlugin.h"
|
||||
#include "IOpenXRHMDModule.h"
|
||||
#include "OculusXRAssetDirectory.h"
|
||||
#include "OculusXRXRFunctions.h"
|
||||
#include "OculusXROpenXRUtilities.h"
|
||||
#include "OculusXRHMDRuntimeSettings.h"
|
||||
|
||||
DEFINE_LOG_CATEGORY(LogOculusSystemInfoExtensionPlugin);
|
||||
|
||||
namespace OculusXR
|
||||
{
|
||||
enum EOculusAsset
|
||||
{
|
||||
LeftTouchRiftS,
|
||||
RightTouchRiftS,
|
||||
LeftTouchQuest2,
|
||||
RightTouchQuest2,
|
||||
LeftTouchQuestPro,
|
||||
RightTouchQuestPro,
|
||||
LeftTouchQuest3,
|
||||
RightTouchQuest3,
|
||||
OculusAssetTotal
|
||||
};
|
||||
|
||||
struct FRenderableDevice
|
||||
{
|
||||
FString Device;
|
||||
EOculusXRDeviceType MinDeviceRange;
|
||||
EOculusXRDeviceType MaxDeviceRange;
|
||||
FSoftObjectPath MeshAssetRef;
|
||||
};
|
||||
|
||||
static FRenderableDevice RenderableDevices[] = {
|
||||
#if PLATFORM_ANDROID
|
||||
// Quest 1 & 2
|
||||
{ "/user/hand/left", EOculusXRDeviceType::OculusQuest_Deprecated, EOculusXRDeviceType::OculusQuest2, FOculusAssetDirectory::AssetListing[LeftTouchQuest2] },
|
||||
{ "/user/hand/right", EOculusXRDeviceType::OculusQuest_Deprecated, EOculusXRDeviceType::OculusQuest2, FOculusAssetDirectory::AssetListing[RightTouchQuest2] },
|
||||
|
||||
// Quest Pro
|
||||
{ "/user/hand/left", EOculusXRDeviceType::MetaQuestPro, EOculusXRDeviceType::MetaQuestPro, FOculusAssetDirectory::AssetListing[LeftTouchQuestPro] },
|
||||
{ "/user/hand/right", EOculusXRDeviceType::MetaQuestPro, EOculusXRDeviceType::MetaQuestPro, FOculusAssetDirectory::AssetListing[RightTouchQuestPro] },
|
||||
|
||||
// Quest 3 & 3s
|
||||
{ "/user/hand/left", EOculusXRDeviceType::MetaQuest3, EOculusXRDeviceType::MetaQuest3S, FOculusAssetDirectory::AssetListing[LeftTouchQuest3] },
|
||||
{ "/user/hand/right", EOculusXRDeviceType::MetaQuest3, EOculusXRDeviceType::MetaQuest3S, FOculusAssetDirectory::AssetListing[RightTouchQuest3] },
|
||||
#else
|
||||
// PC - Rift S
|
||||
{ "/user/hand/left", EOculusXRDeviceType::Rift_S, EOculusXRDeviceType::Rift_S, FOculusAssetDirectory::AssetListing[LeftTouchRiftS] },
|
||||
{ "/user/hand/right", EOculusXRDeviceType::Rift_S, EOculusXRDeviceType::Rift_S, FOculusAssetDirectory::AssetListing[RightTouchRiftS] },
|
||||
|
||||
// PC - Quest 1 & 2
|
||||
{ "/user/hand/left", EOculusXRDeviceType::Quest_Link_Deprecated, EOculusXRDeviceType::Quest2_Link, FOculusAssetDirectory::AssetListing[LeftTouchQuest2] },
|
||||
{ "/user/hand/right", EOculusXRDeviceType::Quest_Link_Deprecated, EOculusXRDeviceType::Quest2_Link, FOculusAssetDirectory::AssetListing[RightTouchQuest2] },
|
||||
|
||||
// PC - Quest Pro
|
||||
{ "/user/hand/left", EOculusXRDeviceType::MetaQuestProLink, EOculusXRDeviceType::MetaQuestProLink, FOculusAssetDirectory::AssetListing[LeftTouchQuestPro] },
|
||||
{ "/user/hand/right", EOculusXRDeviceType::MetaQuestProLink, EOculusXRDeviceType::MetaQuestProLink, FOculusAssetDirectory::AssetListing[RightTouchQuestPro] },
|
||||
|
||||
// Quest 3 & 3s
|
||||
{ "/user/hand/left", EOculusXRDeviceType::MetaQuest3Link, EOculusXRDeviceType::MetaQuest3SLink, FOculusAssetDirectory::AssetListing[LeftTouchQuest3] },
|
||||
{ "/user/hand/right", EOculusXRDeviceType::MetaQuest3Link, EOculusXRDeviceType::MetaQuest3SLink, FOculusAssetDirectory::AssetListing[RightTouchQuest3] },
|
||||
#endif
|
||||
};
|
||||
static uint32 RenderableDeviceCount = sizeof(RenderableDevices) / sizeof(RenderableDevices[0]);
|
||||
|
||||
FSoftObjectPath FindDeviceMesh(FString DevicePath, EOculusXRDeviceType SystemDeviceType)
|
||||
{
|
||||
if (DevicePath == "")
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (uint32 DeviceIndex = 0; DeviceIndex < RenderableDeviceCount; ++DeviceIndex)
|
||||
{
|
||||
const FRenderableDevice& RenderableDevice = RenderableDevices[DeviceIndex];
|
||||
if (RenderableDevice.Device == DevicePath)
|
||||
{
|
||||
// If we have information about the current headset, load the model based of the headset information, otherwise load defaults.
|
||||
if (SystemDeviceType != EOculusXRDeviceType::OculusUnknown)
|
||||
{
|
||||
if (SystemDeviceType >= RenderableDevice.MinDeviceRange && SystemDeviceType <= RenderableDevice.MaxDeviceRange)
|
||||
{
|
||||
return RenderableDevice.MeshAssetRef;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return RenderableDevice.MeshAssetRef;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
namespace // anonymous
|
||||
{
|
||||
void AppendToChain(XrBaseOutStructure* ToAppend, XrBaseOutStructure* Chain)
|
||||
{
|
||||
while (Chain->next != XR_NULL_HANDLE)
|
||||
{
|
||||
if (Chain->next == ToAppend)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Chain = Chain->next;
|
||||
}
|
||||
Chain->next = ToAppend;
|
||||
}
|
||||
|
||||
bool IsEqualUuid(const XrUuidEXT& a, const XrUuidEXT& b)
|
||||
{
|
||||
return FMemory::Memcmp(&a, &b, sizeof(XrUuidEXT)) == 0;
|
||||
}
|
||||
|
||||
XrColorSpaceFB ToXrColorSpace(EOculusXRColorSpace ColorSpace)
|
||||
{
|
||||
XrColorSpaceFB XrColorSpace = XR_COLOR_SPACE_UNMANAGED_FB;
|
||||
switch (ColorSpace)
|
||||
{
|
||||
case EOculusXRColorSpace::Unmanaged:
|
||||
XrColorSpace = XR_COLOR_SPACE_UNMANAGED_FB;
|
||||
break;
|
||||
case EOculusXRColorSpace::Rec_2020:
|
||||
XrColorSpace = XR_COLOR_SPACE_REC2020_FB;
|
||||
break;
|
||||
case EOculusXRColorSpace::Rec_709:
|
||||
XrColorSpace = XR_COLOR_SPACE_REC709_FB;
|
||||
break;
|
||||
case EOculusXRColorSpace::Rift_CV1:
|
||||
XrColorSpace = XR_COLOR_SPACE_RIFT_CV1_FB;
|
||||
break;
|
||||
case EOculusXRColorSpace::Rift_S:
|
||||
XrColorSpace = XR_COLOR_SPACE_RIFT_S_FB;
|
||||
break;
|
||||
case EOculusXRColorSpace::Quest:
|
||||
XrColorSpace = XR_COLOR_SPACE_QUEST_FB;
|
||||
break;
|
||||
case EOculusXRColorSpace::P3:
|
||||
XrColorSpace = XR_COLOR_SPACE_P3_FB;
|
||||
break;
|
||||
case EOculusXRColorSpace::Adobe_RGB:
|
||||
XrColorSpace = XR_COLOR_SPACE_ADOBE_RGB_FB;
|
||||
break;
|
||||
}
|
||||
return XrColorSpace;
|
||||
}
|
||||
|
||||
EOculusXRColorSpace ToOculusXRColorSpace(XrColorSpaceFB InXrColorSpace)
|
||||
{
|
||||
EOculusXRColorSpace ColorSpace = EOculusXRColorSpace::Unknown;
|
||||
|
||||
switch (InXrColorSpace)
|
||||
{
|
||||
case XR_COLOR_SPACE_UNMANAGED_FB:
|
||||
ColorSpace = EOculusXRColorSpace::Unmanaged;
|
||||
break;
|
||||
case XR_COLOR_SPACE_REC2020_FB:
|
||||
ColorSpace = EOculusXRColorSpace::Rec_2020;
|
||||
break;
|
||||
case XR_COLOR_SPACE_REC709_FB:
|
||||
ColorSpace = EOculusXRColorSpace::Rec_709;
|
||||
break;
|
||||
case XR_COLOR_SPACE_RIFT_CV1_FB:
|
||||
ColorSpace = EOculusXRColorSpace::Rift_CV1;
|
||||
break;
|
||||
case XR_COLOR_SPACE_RIFT_S_FB:
|
||||
ColorSpace = EOculusXRColorSpace::Rift_S;
|
||||
break;
|
||||
case XR_COLOR_SPACE_QUEST_FB:
|
||||
ColorSpace = EOculusXRColorSpace::Quest;
|
||||
break;
|
||||
case XR_COLOR_SPACE_P3_FB:
|
||||
ColorSpace = EOculusXRColorSpace::P3;
|
||||
break;
|
||||
case XR_COLOR_SPACE_ADOBE_RGB_FB:
|
||||
ColorSpace = EOculusXRColorSpace::Adobe_RGB;
|
||||
break;
|
||||
default:
|
||||
ColorSpace = EOculusXRColorSpace::Unknown;
|
||||
}
|
||||
return ColorSpace;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
FSystemInfoExtensionPlugin::FSystemInfoExtensionPlugin()
|
||||
: Instance(XR_NULL_HANDLE)
|
||||
, Session(XR_NULL_HANDLE)
|
||||
, SystemId(XR_NULL_SYSTEM_ID)
|
||||
, bExtHeadsetIdAvailable(false)
|
||||
, SystemHeadsetId{}
|
||||
, bSystemHeadsetIdValid(false)
|
||||
, SystemProductName{}
|
||||
, bExtDisplayRefreshAvailible(false)
|
||||
, bExtColorspaceAvailable(false)
|
||||
, bExtPassthroughAvailable(false)
|
||||
, bExtPassthroughPreferencesAvailable(false)
|
||||
{
|
||||
}
|
||||
|
||||
bool FSystemInfoExtensionPlugin::GetRequiredExtensions(TArray<const ANSICHAR*>& OutExtensions)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FSystemInfoExtensionPlugin::GetOptionalExtensions(TArray<const ANSICHAR*>& OutExtensions)
|
||||
{
|
||||
OutExtensions.Add(XR_META_HEADSET_ID_EXTENSION_NAME);
|
||||
OutExtensions.Add(XR_FB_DISPLAY_REFRESH_RATE_EXTENSION_NAME);
|
||||
OutExtensions.Add(XR_FB_COLOR_SPACE_EXTENSION_NAME);
|
||||
OutExtensions.Add(XR_META_PASSTHROUGH_PREFERENCES_EXTENSION_NAME);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FSystemInfoExtensionPlugin::PostCreateInstance(XrInstance InInstance)
|
||||
{
|
||||
Instance = InInstance;
|
||||
}
|
||||
|
||||
const void* FSystemInfoExtensionPlugin::OnCreateInstance(class IOpenXRHMDModule* InModule, const void* InNext)
|
||||
{
|
||||
if (InModule != nullptr)
|
||||
{
|
||||
bExtHeadsetIdAvailable = InModule->IsExtensionEnabled(XR_META_HEADSET_ID_EXTENSION_NAME);
|
||||
bExtDisplayRefreshAvailible = InModule->IsExtensionEnabled(XR_FB_DISPLAY_REFRESH_RATE_EXTENSION_NAME);
|
||||
bExtColorspaceAvailable = InModule->IsExtensionEnabled(XR_FB_COLOR_SPACE_EXTENSION_NAME);
|
||||
bExtPassthroughAvailable = InModule->IsExtensionEnabled(XR_FB_PASSTHROUGH_EXTENSION_NAME);
|
||||
bExtPassthroughPreferencesAvailable = InModule->IsExtensionEnabled(XR_META_PASSTHROUGH_PREFERENCES_EXTENSION_NAME);
|
||||
}
|
||||
return IOculusXRExtensionPlugin::OnCreateInstance(InModule, InNext);
|
||||
}
|
||||
|
||||
void FSystemInfoExtensionPlugin::PostCreateSession(XrSession InSession)
|
||||
{
|
||||
Session = InSession;
|
||||
XrSystemGetInfo SystemGetInfo = { XR_TYPE_SYSTEM_GET_INFO };
|
||||
SystemGetInfo.formFactor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;
|
||||
|
||||
ENSURE_XRCMD(xrGetSystem(Instance, &SystemGetInfo, &SystemId));
|
||||
|
||||
XrSystemHeadsetIdPropertiesMETA SystemHeadsetIdProperties = { XR_TYPE_SYSTEM_HEADSET_ID_PROPERTIES_META };
|
||||
|
||||
XrSystemProperties SystemProperties = { XR_TYPE_SYSTEM_PROPERTIES };
|
||||
|
||||
if (bExtHeadsetIdAvailable)
|
||||
{
|
||||
AppendToChain(
|
||||
reinterpret_cast<XrBaseOutStructure*>(&SystemHeadsetIdProperties),
|
||||
reinterpret_cast<XrBaseOutStructure*>(&SystemProperties));
|
||||
}
|
||||
|
||||
ENSURE_XRCMD(xrGetSystemProperties(Instance, SystemId, &SystemProperties));
|
||||
|
||||
if (bExtHeadsetIdAvailable)
|
||||
{
|
||||
SystemHeadsetId = SystemHeadsetIdProperties.id;
|
||||
bSystemHeadsetIdValid = true;
|
||||
}
|
||||
|
||||
SystemProductName = SystemProperties.systemName;
|
||||
SystemDeviceType = GetSystemHeadsetType();
|
||||
|
||||
const UOculusXRHMDRuntimeSettings* HMDSettings = GetDefault<UOculusXRHMDRuntimeSettings>();
|
||||
SetColorSpace(HMDSettings->ColorSpace);
|
||||
|
||||
ControllerPaths.TouchControllerPath = FOpenXRPath("/interaction_profiles/oculus/touch_controller");
|
||||
ControllerPaths.TouchControllerProPath = FOpenXRPath("/interaction_profiles/facebook/touch_controller_pro");
|
||||
ControllerPaths.TouchControllerPlusPath = FOpenXRPath("/interaction_profiles/meta/touch_controller_plus");
|
||||
ControllerPaths.LeftHandPath = FOpenXRPath("/user/hand/left");
|
||||
ControllerPaths.RightHandPath = FOpenXRPath("/user/hand/right");
|
||||
}
|
||||
|
||||
bool FSystemInfoExtensionPlugin::GetControllerModel(XrInstance InInstance, XrPath InInteractionProfile, XrPath InDevicePath, FSoftObjectPath& OutPath)
|
||||
{
|
||||
if (InDevicePath == XR_NULL_PATH)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const FString DevicePath = FOpenXRPath(InDevicePath).ToString();
|
||||
OutPath = FindDeviceMesh(DevicePath, SystemDeviceType);
|
||||
return OutPath.IsValid();
|
||||
}
|
||||
|
||||
void FSystemInfoExtensionPlugin::GetControllerModelsForCooking(TArray<FSoftObjectPath>& OutPaths)
|
||||
{
|
||||
OutPaths.Append(FOculusAssetDirectory::AssetListing, OculusAssetTotal);
|
||||
}
|
||||
|
||||
EOculusXRDeviceType FSystemInfoExtensionPlugin::GetDeviceType()
|
||||
{
|
||||
return SystemDeviceType;
|
||||
}
|
||||
|
||||
EOculusXRDeviceType FSystemInfoExtensionPlugin::GetSystemHeadsetType()
|
||||
{
|
||||
// Magic legacy conversion paths from ovrplugin
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
|
||||
constexpr XrUuidEXT XR_HEADSET_ID_QUEST = {
|
||||
{ 0x4c, 0xa2, 0xf7, 0x94, 0xaf, 0x6a, 0x46, 0x9d, 0xbb, 0xe5, 0x1f, 0x7f, 0xce, 0xef, 0x7b, 0xad }
|
||||
};
|
||||
constexpr XrUuidEXT XR_HEADSET_ID_QUEST2 = {
|
||||
{ 0x30, 0x64, 0xf2, 0x39, 0x15, 0xed, 0x47, 0x22, 0xa6, 0x59, 0x5e, 0xa1, 0xec, 0xd8, 0x99, 0xc2 }
|
||||
};
|
||||
// Quest Pro
|
||||
constexpr XrUuidEXT XR_HEADSET_ID_QUEST_PRO = {
|
||||
{ 0xb5, 0x84, 0x43, 0xc9, 0xdf, 0x86, 0x40, 0xcd, 0x89, 0x18, 0x2a, 0x27, 0x8e, 0x18, 0xab, 0x71 }
|
||||
};
|
||||
// Quest 3
|
||||
constexpr XrUuidEXT XR_HEADSET_ID_QUEST_3 = {
|
||||
{ 0x08, 0x27, 0x46, 0xba, 0xa0, 0x71, 0x4c, 0xf7, 0x8f, 0x87, 0xba, 0xde, 0x5c, 0xce, 0x43, 0xce }
|
||||
};
|
||||
// Quest 3S
|
||||
constexpr XrUuidEXT XR_HEADSET_ID_QUEST_3S = {
|
||||
{ 0x95, 0x10, 0x49, 0x2b, 0x0d, 0x42, 0x48, 0x72, 0xbc, 0xf4, 0xfb, 0x1a, 0x8d, 0xef, 0x6f, 0x0e }
|
||||
};
|
||||
#else
|
||||
// PC Headsets
|
||||
constexpr XrUuidEXT XR_HEADSET_ID_RIFT_CV1 = {
|
||||
{ 0xbe, 0x4f, 0x8d, 0x7c, 0x8e, 0x33, 0x4d, 0xa2, 0xbf, 0x54, 0xda, 0xd9, 0xea, 0x57, 0x54, 0x9f }
|
||||
};
|
||||
constexpr XrUuidEXT XR_HEADSET_ID_RIFT_S = {
|
||||
{ 0x0d, 0x42, 0xaa, 0xc6, 0x7f, 0x1c, 0x46, 0x27, 0x9c, 0xc5, 0x2c, 0xba, 0x8b, 0x0b, 0xaf, 0xfc }
|
||||
};
|
||||
constexpr XrUuidEXT XR_HEADSET_ID_QUEST_LINK = {
|
||||
{ 0x2f, 0x03, 0x26, 0xc0, 0x09, 0xeb, 0x4d, 0xa9, 0x9a, 0x88, 0x4c, 0xc2, 0x93, 0x53, 0x0a, 0xb2 }
|
||||
};
|
||||
constexpr XrUuidEXT XR_HEADSET_ID_QUEST2_LINK = {
|
||||
{ 0x52, 0x50, 0x78, 0xa5, 0x5a, 0xab, 0x4d, 0xc9, 0xb8, 0x02, 0x1e, 0xbd, 0x6c, 0x7c, 0xff, 0xf4 }
|
||||
};
|
||||
// Quest Pro
|
||||
constexpr XrUuidEXT XR_HEADSET_ID_QUEST_PRO_LINK = {
|
||||
{ 0x99, 0x09, 0x86, 0xc7, 0x9b, 0xad, 0x47, 0x5f, 0x89, 0x83, 0xc1, 0xc7, 0xbd, 0x49, 0xad, 0x51 }
|
||||
};
|
||||
// Quest 3
|
||||
constexpr XrUuidEXT XR_HEADSET_ID_QUEST_3_LINK = {
|
||||
{ 0x64, 0x09, 0xe3, 0xb3, 0x50, 0x89, 0x4e, 0xd6, 0x86, 0x8e, 0xaa, 0xed, 0x82, 0xda, 0x36, 0x76 }
|
||||
};
|
||||
// Quest 3S
|
||||
constexpr XrUuidEXT XR_HEADSET_ID_QUEST_3S_LINK = {
|
||||
{ 0x8c, 0x2e, 0xc4, 0x47, 0xac, 0x73, 0x41, 0x9f, 0x90, 0x96, 0x36, 0xa7, 0x72, 0x33, 0x78, 0x62 }
|
||||
};
|
||||
#endif // defined(__ANDROID__)
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
if (bSystemHeadsetIdValid)
|
||||
{
|
||||
UE_LOG(LogOculusSystemInfoExtensionPlugin, Log, TEXT("UID %x %x %x %x - %x %x %x %x - %x %x %x %x - %x %x %x %x"),
|
||||
SystemHeadsetId.data[0],
|
||||
SystemHeadsetId.data[1],
|
||||
SystemHeadsetId.data[2],
|
||||
SystemHeadsetId.data[3],
|
||||
|
||||
SystemHeadsetId.data[4],
|
||||
SystemHeadsetId.data[5],
|
||||
SystemHeadsetId.data[6],
|
||||
SystemHeadsetId.data[7],
|
||||
|
||||
SystemHeadsetId.data[8],
|
||||
SystemHeadsetId.data[9],
|
||||
SystemHeadsetId.data[10],
|
||||
SystemHeadsetId.data[11],
|
||||
|
||||
SystemHeadsetId.data[12],
|
||||
SystemHeadsetId.data[13],
|
||||
SystemHeadsetId.data[14],
|
||||
SystemHeadsetId.data[15]);
|
||||
|
||||
if (IsEqualUuid(SystemHeadsetId, XR_HEADSET_ID_QUEST))
|
||||
{
|
||||
return EOculusXRDeviceType::OculusQuest_Deprecated;
|
||||
}
|
||||
else if (IsEqualUuid(SystemHeadsetId, XR_HEADSET_ID_QUEST2))
|
||||
{
|
||||
return EOculusXRDeviceType::OculusQuest2;
|
||||
}
|
||||
else if (IsEqualUuid(SystemHeadsetId, XR_HEADSET_ID_QUEST_PRO))
|
||||
{
|
||||
return EOculusXRDeviceType::MetaQuestPro;
|
||||
}
|
||||
else if (IsEqualUuid(SystemHeadsetId, XR_HEADSET_ID_QUEST_3))
|
||||
{
|
||||
return EOculusXRDeviceType::MetaQuest3;
|
||||
}
|
||||
else if (IsEqualUuid(SystemHeadsetId, XR_HEADSET_ID_QUEST_3S))
|
||||
{
|
||||
return EOculusXRDeviceType::MetaQuest3S;
|
||||
}
|
||||
else
|
||||
{
|
||||
return EOculusXRDeviceType::OculusQuest2; // return Quest 2 as the default headset type
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SystemProductName == TEXT("Oculus Quest"))
|
||||
{
|
||||
return EOculusXRDeviceType::OculusQuest_Deprecated;
|
||||
}
|
||||
else if (SystemProductName == TEXT("Oculus Quest2"))
|
||||
{
|
||||
return EOculusXRDeviceType::OculusQuest2;
|
||||
}
|
||||
else if (SystemProductName == TEXT("Meta Quest Pro") || SystemProductName == TEXT("Oculus Headset1"))
|
||||
{
|
||||
return EOculusXRDeviceType::MetaQuestPro;
|
||||
}
|
||||
else if (SystemProductName == TEXT("Meta Quest 3") || SystemProductName == TEXT("Oculus Headset2"))
|
||||
{
|
||||
return EOculusXRDeviceType::MetaQuest3;
|
||||
}
|
||||
else if (SystemProductName == TEXT("Meta Quest 3S") || SystemProductName == TEXT("Oculus Headset3"))
|
||||
{
|
||||
return EOculusXRDeviceType::MetaQuest3S;
|
||||
}
|
||||
else
|
||||
{
|
||||
return EOculusXRDeviceType::OculusQuest2; // return Quest 2 as the default headset type
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (bSystemHeadsetIdValid)
|
||||
{
|
||||
if (IsEqualUuid(SystemHeadsetId, XR_HEADSET_ID_RIFT_CV1))
|
||||
{
|
||||
return EOculusXRDeviceType::Rift;
|
||||
}
|
||||
else if (IsEqualUuid(SystemHeadsetId, XR_HEADSET_ID_RIFT_S))
|
||||
{
|
||||
return EOculusXRDeviceType::Rift_S;
|
||||
}
|
||||
else if (IsEqualUuid(SystemHeadsetId, XR_HEADSET_ID_QUEST_LINK))
|
||||
{
|
||||
return EOculusXRDeviceType::Quest_Link_Deprecated;
|
||||
}
|
||||
else if (IsEqualUuid(SystemHeadsetId, XR_HEADSET_ID_QUEST2_LINK))
|
||||
{
|
||||
return EOculusXRDeviceType::Quest2_Link;
|
||||
}
|
||||
else if (IsEqualUuid(SystemHeadsetId, XR_HEADSET_ID_QUEST_PRO_LINK))
|
||||
{
|
||||
return EOculusXRDeviceType::MetaQuestProLink;
|
||||
}
|
||||
else if (IsEqualUuid(SystemHeadsetId, XR_HEADSET_ID_QUEST_3_LINK))
|
||||
{
|
||||
return EOculusXRDeviceType::MetaQuest3Link;
|
||||
}
|
||||
else if (IsEqualUuid(SystemHeadsetId, XR_HEADSET_ID_QUEST_3S_LINK))
|
||||
{
|
||||
return EOculusXRDeviceType::MetaQuest3SLink;
|
||||
}
|
||||
else
|
||||
{
|
||||
return EOculusXRDeviceType::Quest2_Link; // return Quest 2 (over Link) as the default headset type
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SystemProductName == TEXT("Oculus Rift S"))
|
||||
{
|
||||
return EOculusXRDeviceType::Rift_S;
|
||||
}
|
||||
else if (SystemProductName == TEXT("Oculus Rift CV1"))
|
||||
{
|
||||
return EOculusXRDeviceType::Rift;
|
||||
}
|
||||
else
|
||||
{
|
||||
return EOculusXRDeviceType::Quest2_Link; // return Quest 2 (over Link) as the default headset type
|
||||
}
|
||||
}
|
||||
#endif // defined(__ANDROID__)
|
||||
}
|
||||
|
||||
TArray<float> FSystemInfoExtensionPlugin::GetSystemDisplayAvailableFrequencies()
|
||||
{
|
||||
TArray<float> DisplayFrequencies;
|
||||
|
||||
if (bExtDisplayRefreshAvailible)
|
||||
{
|
||||
check(xrEnumerateDisplayRefreshRatesFB.GetValue() != nullptr);
|
||||
|
||||
uint32 TotalRates = 0;
|
||||
ENSURE_XRCMD(xrEnumerateDisplayRefreshRatesFB.GetValue()(Session, 0, &TotalRates, nullptr));
|
||||
|
||||
DisplayFrequencies.Init(0, TotalRates);
|
||||
|
||||
ENSURE_XRCMD(xrEnumerateDisplayRefreshRatesFB.GetValue()(Session, TotalRates, &TotalRates, DisplayFrequencies.GetData()));
|
||||
}
|
||||
|
||||
return DisplayFrequencies;
|
||||
}
|
||||
|
||||
float FSystemInfoExtensionPlugin::GetSystemDisplayFrequency()
|
||||
{
|
||||
float Frequency = 0.0f;
|
||||
|
||||
if (bExtDisplayRefreshAvailible)
|
||||
{
|
||||
check(xrGetDisplayRefreshRateFB.GetValue() != nullptr);
|
||||
ENSURE_XRCMD(xrGetDisplayRefreshRateFB.GetValue()(Session, &Frequency));
|
||||
}
|
||||
return Frequency;
|
||||
}
|
||||
|
||||
void FSystemInfoExtensionPlugin::SetSystemDisplayFrequency(float DisplayFrequency)
|
||||
{
|
||||
if (bExtDisplayRefreshAvailible)
|
||||
{
|
||||
check(xrRequestDisplayRefreshRateFB.GetValue() != nullptr);
|
||||
ENSURE_XRCMD(xrRequestDisplayRefreshRateFB.GetValue()(Session, DisplayFrequency));
|
||||
}
|
||||
}
|
||||
|
||||
void FSystemInfoExtensionPlugin::SetColorSpace(EOculusXRColorSpace ColorSpace)
|
||||
{
|
||||
if (bExtColorspaceAvailable)
|
||||
{
|
||||
XrColorSpaceFB XrColorSpace = ToXrColorSpace(ColorSpace);
|
||||
check(xrSetColorSpaceFB.GetValue() != nullptr);
|
||||
ENSURE_XRCMD(xrSetColorSpaceFB.GetValue()(Session, XrColorSpace));
|
||||
}
|
||||
}
|
||||
|
||||
EOculusXRColorSpace FSystemInfoExtensionPlugin::GetColorSpace()
|
||||
{
|
||||
EOculusXRColorSpace ColorSpace = EOculusXRColorSpace::Unknown;
|
||||
if (bExtColorspaceAvailable)
|
||||
{
|
||||
XrSystemColorSpacePropertiesFB ColorSpaceProperties = { XR_TYPE_SYSTEM_COLOR_SPACE_PROPERTIES_FB };
|
||||
XrSystemProperties SystemProperties = { XR_TYPE_SYSTEM_PROPERTIES, &ColorSpaceProperties };
|
||||
|
||||
ENSURE_XRCMD(xrGetSystemProperties(Instance, SystemId, &SystemProperties));
|
||||
ColorSpace = ToOculusXRColorSpace(ColorSpaceProperties.colorSpace);
|
||||
}
|
||||
return ColorSpace;
|
||||
}
|
||||
|
||||
bool FSystemInfoExtensionPlugin::IsPassthroughSupported()
|
||||
{
|
||||
if (bExtPassthroughAvailable)
|
||||
{
|
||||
XrSystemPassthroughProperties2FB PassthroughProperties = { XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES2_FB };
|
||||
XrSystemProperties SystemProperties = { XR_TYPE_SYSTEM_PROPERTIES, &PassthroughProperties };
|
||||
|
||||
XR_ENSURE(xrGetSystemProperties(Instance, SystemId, &SystemProperties));
|
||||
|
||||
return (PassthroughProperties.capabilities & XR_PASSTHROUGH_CAPABILITY_BIT_FB) == XR_PASSTHROUGH_CAPABILITY_BIT_FB;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FSystemInfoExtensionPlugin::IsColorPassthroughSupported()
|
||||
{
|
||||
if (bExtPassthroughAvailable)
|
||||
{
|
||||
XrSystemPassthroughProperties2FB PassthroughProperties = { XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES2_FB };
|
||||
XrSystemProperties SystemProperties = { XR_TYPE_SYSTEM_PROPERTIES, &PassthroughProperties };
|
||||
|
||||
XR_ENSURE(xrGetSystemProperties(Instance, SystemId, &SystemProperties));
|
||||
|
||||
return (PassthroughProperties.capabilities & XR_PASSTHROUGH_CAPABILITY_COLOR_BIT_FB) == XR_PASSTHROUGH_CAPABILITY_COLOR_BIT_FB;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FSystemInfoExtensionPlugin::IsPassthroughRecommended()
|
||||
{
|
||||
if (bExtPassthroughPreferencesAvailable && OculusXR::xrGetPassthroughPreferencesMETA.IsSet())
|
||||
{
|
||||
XrPassthroughPreferencesMETA PassthroughPreferences = { XR_TYPE_PASSTHROUGH_PREFERENCES_META };
|
||||
|
||||
ENSURE_XRCMD(OculusXR::xrGetPassthroughPreferencesMETA.GetValue()(Session, &PassthroughPreferences));
|
||||
|
||||
return (PassthroughPreferences.flags & XR_PASSTHROUGH_PREFERENCE_DEFAULT_TO_ACTIVE_BIT_META) == XR_PASSTHROUGH_PREFERENCE_DEFAULT_TO_ACTIVE_BIT_META;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
EOculusXRControllerType FSystemInfoExtensionPlugin::GetControllerType(EControllerHand DeviceHand)
|
||||
{
|
||||
EOculusXRControllerType ControllerType = EOculusXRControllerType::Unknown;
|
||||
IXRTrackingSystem* TrackingSystem = GetOpenXRTrackingSystem();
|
||||
|
||||
if (TrackingSystem != nullptr)
|
||||
{
|
||||
if (DeviceHand != EControllerHand::Left || DeviceHand != EControllerHand::Right)
|
||||
{
|
||||
XrInteractionProfileState Profile;
|
||||
Profile.type = XR_TYPE_INTERACTION_PROFILE_STATE;
|
||||
Profile.next = nullptr;
|
||||
const XrPath TopLevelUserPath = DeviceHand != EControllerHand::Left ? ControllerPaths.LeftHandPath : ControllerPaths.RightHandPath;
|
||||
XR_ENSURE(xrGetCurrentInteractionProfile(Session, TopLevelUserPath, &Profile));
|
||||
|
||||
const XrPath InteractionProfile = Profile.interactionProfile;
|
||||
if (InteractionProfile == ControllerPaths.TouchControllerPath)
|
||||
{
|
||||
ControllerType = EOculusXRControllerType::MetaQuestTouch;
|
||||
}
|
||||
else if (InteractionProfile == ControllerPaths.TouchControllerProPath)
|
||||
{
|
||||
ControllerType = EOculusXRControllerType::MetaQuestTouchPro;
|
||||
}
|
||||
else if (InteractionProfile == ControllerPaths.TouchControllerPlusPath)
|
||||
{
|
||||
ControllerType = EOculusXRControllerType::MetaQuestTouchPlus;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ControllerType;
|
||||
}
|
||||
|
||||
} // namespace OculusXR
|
||||
@@ -0,0 +1,75 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
#include "CoreMinimal.h"
|
||||
#include "OculusXRHMDTypes.h"
|
||||
#include "OpenXR/IOculusXRExtensionPlugin.h"
|
||||
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogOculusSystemInfoExtensionPlugin, Log, All);
|
||||
|
||||
namespace OculusXR
|
||||
{
|
||||
class FSystemInfoExtensionPlugin : public IOculusXRExtensionPlugin
|
||||
{
|
||||
public:
|
||||
FSystemInfoExtensionPlugin();
|
||||
|
||||
// IOpenXRExtensionPlugin
|
||||
virtual bool GetRequiredExtensions(TArray<const ANSICHAR*>& OutExtensions) override;
|
||||
virtual bool GetOptionalExtensions(TArray<const ANSICHAR*>& OutExtensions) override;
|
||||
virtual const void* OnCreateInstance(class IOpenXRHMDModule* InModule, const void* InNext);
|
||||
virtual void PostCreateInstance(XrInstance InInstance) override;
|
||||
virtual void PostCreateSession(XrSession InSession) override;
|
||||
virtual bool GetControllerModel(XrInstance InInstance, XrPath InInteractionProfile, XrPath InDevicePath, FSoftObjectPath& OutPath) override;
|
||||
virtual void GetControllerModelsForCooking(TArray<FSoftObjectPath>& OutPaths) override;
|
||||
|
||||
FString GetSystemProductName();
|
||||
EOculusXRDeviceType GetDeviceType();
|
||||
|
||||
TArray<float> GetSystemDisplayAvailableFrequencies();
|
||||
float GetSystemDisplayFrequency();
|
||||
void SetSystemDisplayFrequency(float DisplayFrequency);
|
||||
void SetColorSpace(EOculusXRColorSpace ColorSpace);
|
||||
EOculusXRColorSpace GetColorSpace();
|
||||
EOculusXRControllerType GetControllerType(EControllerHand DeviceHand);
|
||||
|
||||
bool IsPassthroughSupported();
|
||||
bool IsColorPassthroughSupported();
|
||||
bool IsPassthroughRecommended();
|
||||
|
||||
private:
|
||||
EOculusXRDeviceType GetSystemHeadsetType();
|
||||
|
||||
XrInstance Instance;
|
||||
XrSession Session;
|
||||
XrSystemId SystemId;
|
||||
bool bExtHeadsetIdAvailable;
|
||||
XrUuidEXT SystemHeadsetId;
|
||||
bool bSystemHeadsetIdValid;
|
||||
FString SystemProductName;
|
||||
EOculusXRDeviceType SystemDeviceType;
|
||||
bool bExtDisplayRefreshAvailible;
|
||||
bool bExtColorspaceAvailable;
|
||||
bool bExtPassthroughAvailable;
|
||||
bool bExtPassthroughPreferencesAvailable;
|
||||
|
||||
struct FControllerPaths
|
||||
{
|
||||
FControllerPaths()
|
||||
: TouchControllerPath(XR_NULL_PATH)
|
||||
, TouchControllerProPath(XR_NULL_PATH)
|
||||
, TouchControllerPlusPath(XR_NULL_PATH)
|
||||
, LeftHandPath(XR_NULL_PATH)
|
||||
, RightHandPath(XR_NULL_PATH){};
|
||||
|
||||
XrPath TouchControllerPath;
|
||||
XrPath TouchControllerProPath;
|
||||
XrPath TouchControllerPlusPath;
|
||||
XrPath LeftHandPath;
|
||||
XrPath RightHandPath;
|
||||
};
|
||||
|
||||
FControllerPaths ControllerPaths;
|
||||
};
|
||||
|
||||
} // namespace OculusXR
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#include "OculusXRXRFunctions.h"
|
||||
#include "OpenXRCore.h"
|
||||
#include "OculusXROpenXRUtilities.h"
|
||||
|
||||
namespace OculusXR
|
||||
{
|
||||
TOptional<PFN_xrPerfSettingsSetPerformanceLevelEXT> xrPerfSettingsSetPerformanceLevelEXT = nullptr;
|
||||
TOptional<PFN_xrQueryPerformanceMetricsCounterMETA> xrQueryPerformanceMetricsCounterMETA = nullptr;
|
||||
TOptional<PFN_xrEnumeratePerformanceMetricsCounterPathsMETA> xrEnumeratePerformanceMetricsCounterPathsMETA = nullptr;
|
||||
TOptional<PFN_xrSetPerformanceMetricsStateMETA> xrSetPerformanceMetricsStateMETA = nullptr;
|
||||
TOptional<PFN_xrGetDisplayRefreshRateFB> xrGetDisplayRefreshRateFB = nullptr;
|
||||
TOptional<PFN_xrRequestDisplayRefreshRateFB> xrRequestDisplayRefreshRateFB = nullptr;
|
||||
TOptional<PFN_xrEnumerateDisplayRefreshRatesFB> xrEnumerateDisplayRefreshRatesFB = nullptr;
|
||||
TOptional<PFN_xrSetColorSpaceFB> xrSetColorSpaceFB = nullptr;
|
||||
TOptional<PFN_xrGetPassthroughPreferencesMETA> xrGetPassthroughPreferencesMETA = nullptr;
|
||||
TOptional<PFN_xrGetRecommendedLayerResolutionMETA> xrGetRecommendedLayerResolutionMETA = nullptr;
|
||||
|
||||
void InitOpenXRFunctions(XrInstance InInstance)
|
||||
{
|
||||
OculusXR::XRGetInstanceProcAddr(InInstance, "xrPerfSettingsSetPerformanceLevelEXT", &xrPerfSettingsSetPerformanceLevelEXT);
|
||||
OculusXR::XRGetInstanceProcAddr(InInstance, "xrQueryPerformanceMetricsCounterMETA", &xrQueryPerformanceMetricsCounterMETA);
|
||||
OculusXR::XRGetInstanceProcAddr(InInstance, "xrEnumeratePerformanceMetricsCounterPathsMETA", &xrEnumeratePerformanceMetricsCounterPathsMETA);
|
||||
OculusXR::XRGetInstanceProcAddr(InInstance, "xrSetPerformanceMetricsStateMETA", &xrSetPerformanceMetricsStateMETA);
|
||||
OculusXR::XRGetInstanceProcAddr(InInstance, "xrGetDisplayRefreshRateFB", &xrGetDisplayRefreshRateFB);
|
||||
OculusXR::XRGetInstanceProcAddr(InInstance, "xrRequestDisplayRefreshRateFB", &xrRequestDisplayRefreshRateFB);
|
||||
OculusXR::XRGetInstanceProcAddr(InInstance, "xrEnumerateDisplayRefreshRatesFB", &xrEnumerateDisplayRefreshRatesFB);
|
||||
OculusXR::XRGetInstanceProcAddr(InInstance, "xrSetColorSpaceFB", &xrSetColorSpaceFB);
|
||||
OculusXR::XRGetInstanceProcAddr(InInstance, "xrGetPassthroughPreferencesMETA", &xrGetPassthroughPreferencesMETA);
|
||||
OculusXR::XRGetInstanceProcAddr(InInstance, "xrGetRecommendedLayerResolutionMETA", &xrGetRecommendedLayerResolutionMETA);
|
||||
}
|
||||
|
||||
} // namespace OculusXR
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "khronos/openxr/openxr.h"
|
||||
#include "Misc/Optional.h"
|
||||
|
||||
namespace OculusXR
|
||||
{
|
||||
extern TOptional<PFN_xrPerfSettingsSetPerformanceLevelEXT> xrPerfSettingsSetPerformanceLevelEXT;
|
||||
extern TOptional<PFN_xrQueryPerformanceMetricsCounterMETA> xrQueryPerformanceMetricsCounterMETA;
|
||||
extern TOptional<PFN_xrEnumeratePerformanceMetricsCounterPathsMETA> xrEnumeratePerformanceMetricsCounterPathsMETA;
|
||||
extern TOptional<PFN_xrSetPerformanceMetricsStateMETA> xrSetPerformanceMetricsStateMETA;
|
||||
extern TOptional<PFN_xrGetDisplayRefreshRateFB> xrGetDisplayRefreshRateFB;
|
||||
extern TOptional<PFN_xrRequestDisplayRefreshRateFB> xrRequestDisplayRefreshRateFB;
|
||||
extern TOptional<PFN_xrEnumerateDisplayRefreshRatesFB> xrEnumerateDisplayRefreshRatesFB;
|
||||
extern TOptional<PFN_xrSetColorSpaceFB> xrSetColorSpaceFB;
|
||||
extern TOptional<PFN_xrGetPassthroughPreferencesMETA> xrGetPassthroughPreferencesMETA;
|
||||
extern TOptional<PFN_xrGetRecommendedLayerResolutionMETA> xrGetRecommendedLayerResolutionMETA;
|
||||
|
||||
void InitOpenXRFunctions(XrInstance InInstance);
|
||||
} // namespace OculusXR
|
||||
Reference in New Issue
Block a user