Config for building for Quest
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<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
|
||||
{ ovrpNode_HandLeft, ovrpSystemHeadset_Meta_Quest_3, ovrpSystemHeadset_Meta_Quest_3, FOculusAssetDirectory::AssetListing[LeftTouchQuest3] },
|
||||
{ ovrpNode_HandRight, ovrpSystemHeadset_Meta_Quest_3, ovrpSystemHeadset_Meta_Quest_3, 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
|
||||
{ ovrpNode_HandLeft, ovrpSystemHeadset_Meta_Link_Quest_3, ovrpSystemHeadset_Meta_Link_Quest_3, FOculusAssetDirectory::AssetListing[LeftTouchQuest3] },
|
||||
{ ovrpNode_HandRight, ovrpSystemHeadset_Meta_Link_Quest_3, ovrpSystemHeadset_Meta_Link_Quest_3, 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,985 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "OculusXRFunctionLibrary.h"
|
||||
#include "OculusXRHMDPrivate.h"
|
||||
#include "OculusXRHMD.h"
|
||||
#include "Logging/MessageLog.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "OculusFunctionLibrary"
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// UOculusXRFunctionLibrary
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
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
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = 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
|
||||
#endif // #if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
{
|
||||
DeviceRotation = FRotator::ZeroRotator;
|
||||
DevicePosition = FVector::ZeroVector;
|
||||
NeckPosition = FVector::ZeroVector;
|
||||
}
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::SetBaseRotationAndBaseOffsetInMeters(FRotator Rotation, FVector BaseOffsetInMeters, EOrientPositionSelector::Type Options)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
if ((Options == EOrientPositionSelector::Orientation) || (Options == EOrientPositionSelector::OrientationAndPosition))
|
||||
{
|
||||
OculusXRHMD->SetBaseRotation(Rotation);
|
||||
}
|
||||
if ((Options == EOrientPositionSelector::Position) || (Options == EOrientPositionSelector::OrientationAndPosition))
|
||||
{
|
||||
OculusXRHMD->SetBaseOffsetInMeters(BaseOffsetInMeters);
|
||||
}
|
||||
}
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::GetBaseRotationAndBaseOffsetInMeters(FRotator& OutRotation, FVector& OutBaseOffsetInMeters)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
OutRotation = OculusXRHMD->GetBaseRotation();
|
||||
OutBaseOffsetInMeters = OculusXRHMD->GetBaseOffsetInMeters();
|
||||
}
|
||||
else
|
||||
{
|
||||
OutRotation = FRotator::ZeroRotator;
|
||||
OutBaseOffsetInMeters = FVector::ZeroVector;
|
||||
}
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::GetRawSensorData(FVector& AngularAcceleration, FVector& LinearAcceleration, FVector& AngularVelocity, FVector& LinearVelocity, float& TimeInSeconds, EOculusXRTrackedDeviceType DeviceType)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = 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;
|
||||
}
|
||||
}
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
}
|
||||
|
||||
bool UOculusXRFunctionLibrary::IsDeviceTracked(EOculusXRTrackedDeviceType DeviceType)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = 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;
|
||||
}
|
||||
}
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
return false;
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::GetSuggestedCpuAndGpuPerformanceLevels(EOculusXRProcessorPerformanceLevel& CpuPerfLevel, EOculusXRProcessorPerformanceLevel& GpuPerfLevel)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr && OculusXRHMD->IsHMDActive())
|
||||
{
|
||||
OculusXRHMD->GetSuggestedCpuAndGpuPerformanceLevels(CpuPerfLevel, GpuPerfLevel);
|
||||
}
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::SetSuggestedCpuAndGpuPerformanceLevels(EOculusXRProcessorPerformanceLevel CpuPerfLevel, EOculusXRProcessorPerformanceLevel GpuPerfLevel)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr && OculusXRHMD->IsHMDActive())
|
||||
{
|
||||
OculusXRHMD->SetSuggestedCpuAndGpuPerformanceLevels(CpuPerfLevel, GpuPerfLevel);
|
||||
}
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::SetCPUAndGPULevels(int CPULevel, int GPULevel)
|
||||
{
|
||||
// Deprecated. Please use Get/SetSuggestedCpuAndGpuPerformanceLevels instead.
|
||||
}
|
||||
|
||||
bool UOculusXRFunctionLibrary::GetUserProfile(FOculusXRHmdUserProfile& Profile)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = 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;
|
||||
}
|
||||
}
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
return false;
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::SetBaseRotationAndPositionOffset(FRotator BaseRot, FVector PosOffset, EOrientPositionSelector::Type Options)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
if (Options == EOrientPositionSelector::Orientation || Options == EOrientPositionSelector::OrientationAndPosition)
|
||||
{
|
||||
OculusXRHMD->SetBaseRotation(BaseRot);
|
||||
}
|
||||
}
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::GetBaseRotationAndPositionOffset(FRotator& OutRot, FVector& OutPosOffset)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
OutRot = OculusXRHMD->GetBaseRotation();
|
||||
OutPosOffset = FVector::ZeroVector;
|
||||
}
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::AddLoadingSplashScreen(class UTexture2D* Texture, FVector TranslationInMeters, FRotator Rotation, FVector2D SizeInMeters, FRotator DeltaRotation, bool bClearBeforeAdd)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = 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);
|
||||
}
|
||||
}
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::ClearLoadingSplashScreens()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
OculusXRHMD::FSplash* Splash = OculusXRHMD->GetSplash();
|
||||
if (Splash)
|
||||
{
|
||||
Splash->ClearSplashes();
|
||||
}
|
||||
}
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
}
|
||||
|
||||
bool UOculusXRFunctionLibrary::HasInputFocus()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
const OculusXRHMD::FOculusXRHMD* const OculusXRHMD = GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr && OculusXRHMD->IsHMDActive())
|
||||
{
|
||||
ovrpBool HasFocus;
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetAppHasInputFocus(&HasFocus)))
|
||||
{
|
||||
return HasFocus != ovrpBool_False;
|
||||
}
|
||||
}
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UOculusXRFunctionLibrary::HasSystemOverlayPresent()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
const OculusXRHMD::FOculusXRHMD* const OculusXRHMD = GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr && OculusXRHMD->IsHMDActive())
|
||||
{
|
||||
ovrpBool HasFocus;
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetAppHasInputFocus(&HasFocus)))
|
||||
{
|
||||
return HasFocus == ovrpBool_False;
|
||||
}
|
||||
}
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
return false;
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::GetGPUUtilization(bool& IsGPUAvailable, float& GPUUtilization)
|
||||
{
|
||||
GPUUtilization = 0.0f;
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
const OculusXRHMD::FOculusXRHMD* const OculusXRHMD = 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
}
|
||||
|
||||
float UOculusXRFunctionLibrary::GetGPUFrameTime()
|
||||
{
|
||||
float FrameTime = 0;
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
const OculusXRHMD::FOculusXRHMD* const OculusXRHMD = 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
EOculusXRFoveatedRenderingMethod UOculusXRFunctionLibrary::GetFoveatedRenderingMethod()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
ovrpBool enabled;
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetFoveationEyeTracked(&enabled)))
|
||||
{
|
||||
return enabled == ovrpBool_True ? EOculusXRFoveatedRenderingMethod::EyeTrackedFoveatedRendering : EOculusXRFoveatedRenderingMethod::FixedFoveatedRendering;
|
||||
}
|
||||
}
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
return EOculusXRFoveatedRenderingMethod::FixedFoveatedRendering;
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::SetFoveatedRenderingMethod(EOculusXRFoveatedRenderingMethod Method)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
OculusXRHMD->SetFoveatedRenderingMethod(Method);
|
||||
}
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::SetFoveatedRenderingLevel(EOculusXRFoveatedRenderingLevel level, bool isDynamic)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
OculusXRHMD->SetFoveatedRenderingLevel(level, isDynamic);
|
||||
}
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
}
|
||||
|
||||
EOculusXRFoveatedRenderingLevel UOculusXRFunctionLibrary::GetFoveatedRenderingLevel()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
ovrpTiledMultiResLevel Lvl;
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetTiledMultiResLevel(&Lvl)))
|
||||
{
|
||||
return (EOculusXRFoveatedRenderingLevel)Lvl;
|
||||
}
|
||||
}
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
return EOculusXRFoveatedRenderingLevel::Off;
|
||||
}
|
||||
|
||||
bool UOculusXRFunctionLibrary::GetEyeTrackedFoveatedRenderingSupported()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
// Always return false on other engine releases, since they don't have FDM offset support
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
ovrpBool Supported;
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetFoveationEyeTrackedSupported(&Supported)))
|
||||
{
|
||||
return Supported == ovrpBool_True;
|
||||
}
|
||||
}
|
||||
#endif // WITH_OCULUS_BRANCH
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
return false;
|
||||
}
|
||||
|
||||
FString UOculusXRFunctionLibrary::GetDeviceName()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
const char* NameString;
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetSystemProductName2(&NameString)) && NameString)
|
||||
{
|
||||
return FString(NameString);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return FString();
|
||||
}
|
||||
|
||||
EOculusXRDeviceType UOculusXRFunctionLibrary::GetDeviceType()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = 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_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;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return EOculusXRDeviceType::OculusUnknown;
|
||||
}
|
||||
|
||||
EOculusXRControllerType UOculusXRFunctionLibrary::GetControllerType(EControllerHand deviceHand)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
auto getOVRPHand = [](EControllerHand hand) {
|
||||
switch (hand)
|
||||
{
|
||||
case EControllerHand::Left:
|
||||
return ovrpHand::ovrpHand_Left;
|
||||
case EControllerHand::Right:
|
||||
return ovrpHand::ovrpHand_Right;
|
||||
default:
|
||||
return ovrpHand::ovrpHand_None;
|
||||
}
|
||||
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:
|
||||
return EOculusXRControllerType::None;
|
||||
}
|
||||
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;
|
||||
#endif
|
||||
return EOculusXRControllerType::Unknown;
|
||||
}
|
||||
|
||||
TArray<float> UOculusXRFunctionLibrary::GetAvailableDisplayFrequencies()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = 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;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return TArray<float>();
|
||||
}
|
||||
|
||||
float UOculusXRFunctionLibrary::GetCurrentDisplayFrequency()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
float Frequency;
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetSystemDisplayFrequency2(&Frequency)))
|
||||
{
|
||||
return Frequency;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::SetDisplayFrequency(float RequestedFrequency)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
FOculusXRHMDModule::GetPluginWrapper().SetSystemDisplayFrequency(RequestedFrequency);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::EnablePositionTracking(bool bPositionTracking)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
FOculusXRHMDModule::GetPluginWrapper().SetTrackingPositionEnabled2(bPositionTracking);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::EnableOrientationTracking(bool bOrientationTracking)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
FOculusXRHMDModule::GetPluginWrapper().SetTrackingOrientationEnabled2(bOrientationTracking);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::SetColorScaleAndOffset(FLinearColor ColorScale, FLinearColor ColorOffset, bool bApplyToAllLayers)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
OculusXRHMD->SetColorScaleAndOffset(ColorScale, ColorOffset, bApplyToAllLayers);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
class IStereoLayers* UOculusXRFunctionLibrary::GetStereoLayers()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
return OculusXRHMD;
|
||||
}
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/** Helper that converts EOculusXRBoundaryType to ovrpBoundaryType */
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
static ovrpBoundaryType ToOvrpBoundaryType(EOculusXRBoundaryType Source)
|
||||
{
|
||||
switch (Source)
|
||||
{
|
||||
case EOculusXRBoundaryType::Boundary_PlayArea:
|
||||
return ovrpBoundary_PlayArea;
|
||||
|
||||
case EOculusXRBoundaryType::Boundary_Outer:
|
||||
default:
|
||||
return ovrpBoundary_Outer;
|
||||
}
|
||||
}
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
|
||||
bool UOculusXRFunctionLibrary::IsGuardianConfigured()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
ovrpBool boundaryConfigured;
|
||||
return OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetBoundaryConfigured2(&boundaryConfigured)) && boundaryConfigured;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UOculusXRFunctionLibrary::IsGuardianDisplayed()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
ovrpBool boundaryVisible;
|
||||
return OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetBoundaryVisible2(&boundaryVisible)) && boundaryVisible;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
TArray<FVector> UOculusXRFunctionLibrary::GetGuardianPoints(EOculusXRBoundaryType BoundaryType, bool UsePawnSpace /* = false */)
|
||||
{
|
||||
TArray<FVector> BoundaryPointList;
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return BoundaryPointList;
|
||||
}
|
||||
|
||||
FVector UOculusXRFunctionLibrary::GetGuardianDimensions(EOculusXRBoundaryType BoundaryType)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = 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);
|
||||
}
|
||||
#endif
|
||||
return FVector::ZeroVector;
|
||||
}
|
||||
|
||||
FTransform UOculusXRFunctionLibrary::GetPlayAreaTransform()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return FTransform();
|
||||
}
|
||||
|
||||
FOculusXRGuardianTestResult UOculusXRFunctionLibrary::GetPointGuardianIntersection(const FVector Point, EOculusXRBoundaryType BoundaryType)
|
||||
{
|
||||
FOculusXRGuardianTestResult InteractionInfo;
|
||||
memset(&InteractionInfo, 0, sizeof(FOculusXRGuardianTestResult));
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = 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;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return InteractionInfo;
|
||||
}
|
||||
|
||||
FOculusXRGuardianTestResult UOculusXRFunctionLibrary::GetNodeGuardianIntersection(EOculusXRTrackedDeviceType DeviceType, EOculusXRBoundaryType BoundaryType)
|
||||
{
|
||||
FOculusXRGuardianTestResult InteractionInfo;
|
||||
memset(&InteractionInfo, 0, sizeof(FOculusXRGuardianTestResult));
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = 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);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return InteractionInfo;
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::SetGuardianVisibility(bool GuardianVisible)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
FOculusXRHMDModule::GetPluginWrapper().SetBoundaryVisible2(GuardianVisible);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool UOculusXRFunctionLibrary::GetSystemHmd3DofModeEnabled()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
ovrpBool enabled;
|
||||
return OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetSystemHmd3DofModeEnabled(&enabled)) && enabled;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
EOculusXRColorSpace UOculusXRFunctionLibrary::GetHmdColorDesc()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
ovrpColorSpace HmdColorSpace;
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetHmdColorDesc(&HmdColorSpace)))
|
||||
{
|
||||
return (EOculusXRColorSpace)HmdColorSpace;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return EOculusXRColorSpace::Unknown;
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::SetClientColorDesc(EOculusXRColorSpace ColorSpace)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
ovrpColorSpace ClientColorSpace = (ovrpColorSpace)ColorSpace;
|
||||
#if PLATFORM_ANDROID
|
||||
if (ClientColorSpace == ovrpColorSpace_Unknown)
|
||||
{
|
||||
ClientColorSpace = ovrpColorSpace_Quest;
|
||||
}
|
||||
#endif
|
||||
FOculusXRHMDModule::GetPluginWrapper().SetClientColorDesc(ClientColorSpace);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::SetLocalDimmingOn(bool LocalDimmingOn)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
UE_LOG(LogHMD, Log, TEXT("SetLocalDimmingOn %d"), LocalDimmingOn);
|
||||
FOculusXRHMDModule::GetPluginWrapper().SetLocalDimming(LocalDimmingOn);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool UOculusXRFunctionLibrary::IsPassthroughSupported()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
ovrpInsightPassthroughCapabilityFlags capabilities;
|
||||
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetPassthroughCapabilityFlags(&capabilities)))
|
||||
{
|
||||
return (capabilities & ovrpInsightPassthroughCapabilityFlags::ovrpInsightPassthroughCapabilityFlags_Passthrough)
|
||||
== ovrpInsightPassthroughCapabilityFlags::ovrpInsightPassthroughCapabilityFlags_Passthrough;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UOculusXRFunctionLibrary::IsColorPassthroughSupported()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
ovrpInsightPassthroughCapabilityFlags capabilities;
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetPassthroughCapabilityFlags(&capabilities)))
|
||||
{
|
||||
return (capabilities & ovrpInsightPassthroughCapabilityFlags::ovrpInsightPassthroughCapabilityFlags_Color)
|
||||
== ovrpInsightPassthroughCapabilityFlags::ovrpInsightPassthroughCapabilityFlags_Color;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::StartEnvironmentDepth()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
int CreateFlags = 0;
|
||||
OculusXRHMD->StartEnvironmentDepth(CreateFlags);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::StopEnvironmentDepth()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
OculusXRHMD->StopEnvironmentDepth();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool UOculusXRFunctionLibrary::IsEnvironmentDepthStarted()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
return OculusXRHMD->IsEnvironmentDepthStarted();
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::SetEnvironmentDepthHandRemoval(bool RemoveHands)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
OculusXRHMD->SetEnvironmentDepthHandRemoval(RemoveHands);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::SetXROcclusionsMode(UObject* WorldContextObject, EOculusXROcclusionsMode Mode)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD();
|
||||
if (OculusXRHMD != nullptr)
|
||||
{
|
||||
OculusXRHMD->EnableHardOcclusions(Mode == EOculusXROcclusionsMode::HardOcclusions);
|
||||
}
|
||||
#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 // defined(WITH_OCULUS_BRANCH)
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
}
|
||||
|
||||
void UOculusXRFunctionLibrary::SetEyeBufferSharpenType(EOculusXREyeBufferSharpenType EyeBufferSharpenType)
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
OculusXRHMD::FOculusXRHMD* OculusXRHMD = 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;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool UOculusXRFunctionLibrary::IsPassthroughRecommended()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
const OculusXRHMD::FOculusXRHMD* OculusHMD = GetOculusXRHMD();
|
||||
if (OculusHMD != nullptr)
|
||||
{
|
||||
ovrpPassthroughPreferences Preferences;
|
||||
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetPassthroughPreferences(&Preferences)))
|
||||
{
|
||||
return (Preferences.Flags & ovrpPassthroughPreferenceFlags::ovrpPassthroughPreferenceFlags_DefaultToActive)
|
||||
== ovrpPassthroughPreferenceFlags::ovrpPassthroughPreferenceFlags_DefaultToActive;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
4876
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD.cpp
Normal file
4876
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD.cpp
Normal file
File diff suppressed because it is too large
Load Diff
637
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD.h
Normal file
637
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD.h
Normal file
@@ -0,0 +1,637 @@
|
||||
// @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 "Misc/EngineVersionComparison.h"
|
||||
#include "OculusXRHMD_FoveatedRendering.h"
|
||||
|
||||
namespace OculusXRHMD
|
||||
{
|
||||
|
||||
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:
|
||||
OCULUSXRHMD_API static const FName OculusSystemName;
|
||||
// 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;
|
||||
virtual void DrawHiddenAreaMesh(class FRHICommandList& RHICmdList, int32 ViewIndex) const override;
|
||||
virtual void DrawVisibleAreaMesh(class FRHICommandList& RHICmdList, int32 ViewIndex) const override;
|
||||
//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;
|
||||
|
||||
// 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(FTexture2DRHIRef EyeTexture) const override;
|
||||
virtual void CopyTexture_RenderThread(FRHICommandListImmediate& RHICmdList, FRHITexture2D* SrcTexture, FIntRect SrcRect, FRHITexture2D* DstTexture, FIntRect DstRect, bool bClearBlack, bool bNoAlpha) const override;
|
||||
virtual bool PopulateAnalyticsAttributes(TArray<struct FAnalyticsEventAttribute>& EventAttributes) override;
|
||||
|
||||
// FXRRenderTargetManager interface
|
||||
virtual bool ShouldUseSeparateRenderTarget() const override;
|
||||
virtual void CalculateRenderTargetSize(const FViewport& Viewport, uint32& InOutSizeX, uint32& InOutSizeY) override;
|
||||
virtual bool NeedReAllocateViewportRenderTarget(const class FViewport& Viewport) override;
|
||||
virtual bool NeedReAllocateDepthTexture(const TRefCountPtr<IPooledRenderTarget>& DepthTarget) override;
|
||||
virtual bool NeedReAllocateShadingRateTexture(const TRefCountPtr<IPooledRenderTarget>& FoveationTarget) override;
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
virtual bool NeedReAllocateMotionVectorTexture(const TRefCountPtr<IPooledRenderTarget>& MotionVectorTarget, const TRefCountPtr<IPooledRenderTarget>& MotionVectorDepthTarget) override;
|
||||
#endif // WITH_OCULUS_BRANCH
|
||||
virtual bool AllocateRenderTargetTexture(uint32 Index, uint32 SizeX, uint32 SizeY, uint8 Format, uint32 NumMips, ETextureCreateFlags InTexFlags, ETextureCreateFlags InTargetableTextureFlags, FTexture2DRHIRef& OutTargetableTexture, FTexture2DRHIRef& OutShaderResourceTexture, uint32 NumSamples = 1) override;
|
||||
virtual bool AllocateDepthTexture(uint32 Index, uint32 SizeX, uint32 SizeY, uint8 Format, uint32 NumMips, ETextureCreateFlags InTexFlags, ETextureCreateFlags TargetableTextureFlags, FTexture2DRHIRef& OutTargetableTexture, FTexture2DRHIRef& OutShaderResourceTexture, uint32 NumSamples = 1) override;
|
||||
virtual bool AllocateShadingRateTexture(uint32 Index, uint32 RenderSizeX, uint32 RenderSizeY, uint8 Format, uint32 NumMips, ETextureCreateFlags InTexFlags, ETextureCreateFlags InTargetableTextureFlags, FTexture2DRHIRef& OutTexture, FIntPoint& OutTextureSize) override;
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
virtual bool AllocateMotionVectorTexture(uint32 Index, uint8 Format, uint32 NumMips, ETextureCreateFlags InTexFlags, ETextureCreateFlags InTargetableTextureFlags, FTexture2DRHIRef& OutTexture, FIntPoint& OutTextureSize, FTexture2DRHIRef& OutDepthTexture, FIntPoint& OutDepthTextureSize) override;
|
||||
virtual bool FindEnvironmentDepthTexture_RenderThread(FTextureRHIRef& OutTexture, FVector2f& OutDepthFactors, FMatrix44f OutScreenToDepthMatrices[2], FMatrix44f OutDepthViewProjMatrices[2]) override;
|
||||
#endif // 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
|
||||
|
||||
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 ResetControlRotation() const;
|
||||
void UpdateFoveationOffsets_RenderThread();
|
||||
bool ComputeEnvironmentDepthParameters_RenderThread(FVector2f& DepthFactors, FMatrix44f ScreenToDepth[ovrpEye_Count], FMatrix44f DepthViewProj[ovrpEye_Count], int& SwapchainIndex);
|
||||
#if UE_VERSION_OLDER_THAN(5, 3, 0)
|
||||
void RenderHardOcclusions_RenderThread(FRHICommandListImmediate& RHICmdList, const FSceneView& InView);
|
||||
#else
|
||||
void RenderHardOcclusions_RenderThread(FRHICommandList& RHICmdList, const FSceneView& InView);
|
||||
#endif
|
||||
|
||||
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();
|
||||
|
||||
void EnableHardOcclusions(bool bEnable);
|
||||
|
||||
OCULUSXRHMD_API void UpdateRTPoses();
|
||||
|
||||
FTransform GetLastTrackingToWorld() const { return LastTrackingToWorld; }
|
||||
OCULUSXRHMD_API void AddEventPollingDelegate(const FOculusXRHMDEventPollingDelegate& NewDelegate);
|
||||
|
||||
protected:
|
||||
FConsoleCommands ConsoleCommands;
|
||||
void UpdateOnRenderThreadCommandHandler(const TArray<FString>& Args, UWorld* World, FOutputDevice& Ar);
|
||||
void PixelDensityMinCommandHandler(const TArray<FString>& Args, UWorld* World, FOutputDevice& Ar);
|
||||
void PixelDensityMaxCommandHandler(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 CheckMultiPlayer();
|
||||
void DoSessionShutdown();
|
||||
|
||||
protected:
|
||||
void UpdateHMDWornState();
|
||||
EHMDWornState::Type HMDWornState = EHMDWornState::Unknown;
|
||||
|
||||
void UpdateHMDEvents();
|
||||
|
||||
void EnableInsightPassthrough_RenderThread(bool bEnablePassthrough);
|
||||
|
||||
void DrawHmdViewMesh(
|
||||
FRHICommandList& RHICmdList,
|
||||
float X,
|
||||
float Y,
|
||||
float SizeX,
|
||||
float SizeY,
|
||||
float U,
|
||||
float V,
|
||||
float SizeU,
|
||||
float SizeV,
|
||||
FIntPoint TargetSize,
|
||||
FIntPoint TextureSize,
|
||||
int32 StereoView,
|
||||
const TShaderRef<class FShader>& VertexShader);
|
||||
|
||||
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> 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;
|
||||
#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;
|
||||
|
||||
#if !UE_BUILD_SHIPPING
|
||||
FDelegateHandle DrawDebugDelegateHandle;
|
||||
#endif
|
||||
|
||||
enum class FInsightInitStatus
|
||||
{
|
||||
NotInitialized,
|
||||
Initialized,
|
||||
Failed,
|
||||
};
|
||||
|
||||
FInsightInitStatus InsightInitStatus;
|
||||
|
||||
bool bShutdownRequestQueued;
|
||||
bool bEyeTrackedFoveatedRenderingSupported;
|
||||
|
||||
TArray<FOculusXRHMDEventPollingDelegate> EventPollingDelegates;
|
||||
|
||||
// MultiPlayer
|
||||
bool bMultiPlayer;
|
||||
bool bShouldWait_GameThread;
|
||||
bool bIsRendering_RenderThread;
|
||||
};
|
||||
|
||||
typedef TSharedPtr<FOculusXRHMD, ESPMode::ThreadSafe> FOculusXRHMDPtr;
|
||||
|
||||
} // namespace OculusXRHMD
|
||||
|
||||
#endif //OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
509
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDModule.cpp
Normal file
509
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDModule.cpp
Normal file
@@ -0,0 +1,509 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "OculusXRHMDModule.h"
|
||||
#include "OculusXRHMD.h"
|
||||
#include "OculusXRHMDPrivateRHI.h"
|
||||
#include "OculusXRHMDRuntimeSettings.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;
|
||||
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
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// 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);
|
||||
}
|
||||
|
||||
void FOculusXRHMDModule::ShutdownModule()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
if (PluginWrapper.IsInitialized())
|
||||
{
|
||||
OculusXRTelemetry::FTelemetryBackend::OnEditorShutdown();
|
||||
PluginWrapper.Shutdown2();
|
||||
OculusPluginWrapper::DestroyOculusPluginWrapper(&PluginWrapper);
|
||||
}
|
||||
|
||||
if (OVRPluginHandle)
|
||||
{
|
||||
FPlatformProcess::FreeDllHandle(OVRPluginHandle);
|
||||
OVRPluginHandle = nullptr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if PLATFORM_ANDROID
|
||||
extern bool AndroidThunkCpp_IsOculusMobileApplication();
|
||||
#endif
|
||||
|
||||
FString FOculusXRHMDModule::GetModuleKeyName() const
|
||||
{
|
||||
return FString(TEXT("OculusXRHMD"));
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
if (OVRP_FAILURE(PluginWrapper.PreInitialize5(Activity, PreinitApiType, ovrpPreinitializeFlags::ovrpPreinitializeFlag_None)))
|
||||
{
|
||||
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")) && GetMutableDefault<UOculusXRHMDRuntimeSettings>()->MetaXRJsonPath.FilePath.Len())
|
||||
{
|
||||
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");
|
||||
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
case ovrpSystemHeadset_Meta_Quest_Pro:
|
||||
return FString("Meta Quest Pro");
|
||||
|
||||
case ovrpSystemHeadset_Meta_Quest_3:
|
||||
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
|
||||
}
|
||||
|
||||
void FOculusXRHMDModule::ToggleOpenXRRuntime()
|
||||
{
|
||||
#if PLATFORM_WINDOWS
|
||||
FMetaXRSimulator::ToggleOpenXRRuntime();
|
||||
#endif
|
||||
}
|
||||
|
||||
void FOculusXRHMDModule::LaunchEnvironment(FString EnvironmentName)
|
||||
{
|
||||
#if PLATFORM_WINDOWS
|
||||
FMetaXRSES::LaunchEnvironment(EnvironmentName);
|
||||
#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)
|
||||
121
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDModule.h
Normal file
121
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDModule.h
Normal file
@@ -0,0 +1,121 @@
|
||||
// @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"
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// FOculusXRHMDModule
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
class FOculusXRHMDModule : public IOculusXRHMDModule
|
||||
{
|
||||
public:
|
||||
FOculusXRHMDModule();
|
||||
|
||||
static inline FOculusXRHMDModule& Get()
|
||||
{
|
||||
return FModuleManager::LoadModuleChecked<FOculusXRHMDModule>("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;
|
||||
|
||||
// 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();
|
||||
|
||||
// FMetaXRSES
|
||||
OCULUSXRHMD_API static void LaunchEnvironment(FString EnvironmentName);
|
||||
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;
|
||||
|
||||
friend class ::OculusXRHMD::FOculusXRHMD;
|
||||
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
};
|
||||
@@ -0,0 +1,95 @@
|
||||
// @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 (GIsThreadedRendering && !GIsRenderingThreadSuspended.Load(EMemoryOrder::Relaxed))
|
||||
{
|
||||
return IsInParallelRenderingThread();
|
||||
}
|
||||
else
|
||||
{
|
||||
return InGameThread();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Change in case of parallel RHI threads
|
||||
bool InRHIThread()
|
||||
{
|
||||
if (GIsThreadedRendering && !GIsRenderingThreadSuspended.Load(EMemoryOrder::Relaxed))
|
||||
{
|
||||
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
|
||||
311
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDPrivate.h
Normal file
311
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDPrivate.h
Normal file
@@ -0,0 +1,311 @@
|
||||
// @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 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,299 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "OculusXRHMDRuntimeSettings.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// UOculusXRHMDRuntimeSettings
|
||||
|
||||
#include "OculusXRHMD_Settings.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;
|
||||
PixelDensityMin = DefaultSettings.PixelDensityMin;
|
||||
PixelDensityMax = DefaultSettings.PixelDensityMax;
|
||||
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;
|
||||
ProcessorFavor = DefaultSettings.ProcessorFavor;
|
||||
bTileTurnOffEnabled = DefaultSettings.Flags.bTileTurnOffEnabled;
|
||||
|
||||
|
||||
FaceTrackingDataSource.Empty(static_cast<int8>(EFaceTrackingDataSourceConfig::MAX));
|
||||
FaceTrackingDataSource.Append(DefaultSettings.FaceTrackingDataSource);
|
||||
|
||||
// Default this to false, FSettings doesn't have a separate composite depth flag for mobile
|
||||
bCompositeDepthMobile = false;
|
||||
|
||||
#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;
|
||||
PixelDensityMin = 0.8f;
|
||||
PixelDensityMax = 1.2f;
|
||||
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;
|
||||
bAnchorSupportEnabled = false;
|
||||
bAnchorSharingEnabled = false;
|
||||
bSceneSupportEnabled = false;
|
||||
ProcessorFavor = EProcessorFavor::FavorEqually;
|
||||
bTileTurnOffEnabled = false;
|
||||
#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];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // WITH_EDITOR
|
||||
|
||||
void UOculusXRHMDRuntimeSettings::PostInitProperties()
|
||||
{
|
||||
Super::PostInitProperties();
|
||||
RenameProperties();
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
void UOculusXRHMDRuntimeSettings::LoadFromIni()
|
||||
{
|
||||
const TCHAR* OculusSettings = TEXT("Oculus.Settings");
|
||||
bool v;
|
||||
float f;
|
||||
FVector vec;
|
||||
|
||||
if (GConfig->GetFloat(OculusSettings, TEXT("PixelDensityMax"), f, GEngineIni))
|
||||
{
|
||||
check(!FMath::IsNaN(f));
|
||||
PixelDensityMax = f;
|
||||
}
|
||||
if (GConfig->GetFloat(OculusSettings, TEXT("PixelDensityMin"), f, GEngineIni))
|
||||
{
|
||||
check(!FMath::IsNaN(f));
|
||||
PixelDensityMin = 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 TCHAR* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
// @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))
|
||||
, PixelDensityMinCommand(TEXT("vr.oculus.PixelDensity.min"),
|
||||
*NSLOCTEXT("OculusRift", "CCommandText_PixelDensityMin", "Oculus Rift specific extension.\nMinimum pixel density when adaptive pixel density is enabled").ToString(),
|
||||
FConsoleCommandWithWorldArgsAndOutputDeviceDelegate::CreateRaw(InHMDPtr, &FOculusXRHMD::PixelDensityMinCommandHandler))
|
||||
, PixelDensityMaxCommand(TEXT("vr.oculus.PixelDensity.max"),
|
||||
*NSLOCTEXT("OculusRift", "CCommandText_PixelDensityMax", "Oculus Rift specific extension.\nMaximum pixel density when adaptive pixel density is enabled").ToString(),
|
||||
FConsoleCommandWithWorldArgsAndOutputDeviceDelegate::CreateRaw(InHMDPtr, &FOculusXRHMD::PixelDensityMaxCommandHandler))
|
||||
, 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,45 @@
|
||||
// @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 PixelDensityMinCommand;
|
||||
FAutoConsoleCommand PixelDensityMaxCommand;
|
||||
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,657 @@
|
||||
// @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/AndroidEGL.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) const
|
||||
{
|
||||
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;
|
||||
|
||||
const auto FeatureLevel = OculusXRHMD->GetSettings_RenderThread()->CurrentFeatureLevel;
|
||||
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);
|
||||
|
||||
// On Vulkan the positive and negative Y faces of the cubemap need to be flipped
|
||||
if (RenderAPI == ovrpRenderAPI_Vulkan)
|
||||
{
|
||||
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);
|
||||
|
||||
TShaderMapRef<FOculusCubemapPS> PixelShader(ShaderMap);
|
||||
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();
|
||||
PixelShader->SetParameters(BatchedParameters, SamplerState, SrcTextureRHI, FaceIndex);
|
||||
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.SubmitCommandsHint();
|
||||
}
|
||||
|
||||
} // namespace OculusXRHMD
|
||||
|
||||
#endif //OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
@@ -0,0 +1,117 @@
|
||||
// @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();
|
||||
|
||||
FTexture2DRHIRef 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) const;
|
||||
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;
|
||||
FTexture2DRHIRef 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, 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,171 @@
|
||||
// @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"
|
||||
|
||||
#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
|
||||
if (GRHISupportsRHIThread && GIsThreadedRendering && GUseRHIThread_InternalUseOnly)
|
||||
{
|
||||
SetRHIThreadEnabled(false, false);
|
||||
}
|
||||
#endif
|
||||
|
||||
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,71 @@
|
||||
// @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"
|
||||
|
||||
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)
|
||||
{
|
||||
DeferredDeletionArray.RemoveAtSwap(Index, 1, false);
|
||||
}
|
||||
}
|
||||
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);
|
||||
});
|
||||
DeferredDeletionArray.RemoveAtSwap(Index, 1, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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,90 @@
|
||||
// @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->PixelDensityMin;
|
||||
float MaxResolutionFraction = Settings->PixelDensityMax;
|
||||
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
|
||||
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,43 @@
|
||||
// @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;
|
||||
|
||||
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,53 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "OculusXRHMD_FoveatedRendering.h"
|
||||
|
||||
#if !UE_VERSION_OLDER_THAN(5, 3, 0)
|
||||
#include "RenderGraphBuilder.h"
|
||||
#include "HeadMountedDisplayTypes.h" // For the LogHMD log category
|
||||
|
||||
FOculusXRFoveatedRenderingImageGenerator::FOculusXRFoveatedRenderingImageGenerator(const FXRSwapChainPtr& Swapchain)
|
||||
: FoveationSwapchain(Swapchain)
|
||||
{
|
||||
GVRSImageManager.RegisterExternalImageGenerator(this);
|
||||
}
|
||||
|
||||
FOculusXRFoveatedRenderingImageGenerator::~FOculusXRFoveatedRenderingImageGenerator()
|
||||
{
|
||||
GVRSImageManager.UnregisterExternalImageGenerator(this);
|
||||
}
|
||||
|
||||
FRDGTextureRef FOculusXRFoveatedRenderingImageGenerator::GetImage(FRDGBuilder& GraphBuilder, const FViewInfo& ViewInfo, FVariableRateShadingImageManager::EVRSImageType ImageType)
|
||||
{
|
||||
if (!FoveationSwapchain.IsValid())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FTexture2DRHIRef 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;
|
||||
}
|
||||
|
||||
void FOculusXRFoveatedRenderingImageGenerator::PrepareImages(FRDGBuilder& GraphBuilder, const FSceneViewFamily& ViewFamily, const FMinimalSceneTextures& SceneTextures)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool FOculusXRFoveatedRenderingImageGenerator::IsEnabledForView(const FSceneView& View) const
|
||||
{
|
||||
return View.StereoPass != EStereoscopicPass::eSSP_FULL;
|
||||
}
|
||||
|
||||
FRDGTextureRef FOculusXRFoveatedRenderingImageGenerator::GetDebugImage(FRDGBuilder& GraphBuilder, const FViewInfo& ViewInfo, FVariableRateShadingImageManager::EVRSImageType ImageType)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
#endif // !UE_VERSION_OLDER_THAN(5, 3, 0)
|
||||
@@ -0,0 +1,31 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Misc/EngineVersionComparison.h"
|
||||
|
||||
#if !UE_VERSION_OLDER_THAN(5, 3, 0)
|
||||
#include "VariableRateShadingImageManager.h"
|
||||
#include "XRSwapchain.h"
|
||||
|
||||
class FOculusXRFoveatedRenderingImageGenerator : public IVariableRateShadingImageGenerator
|
||||
{
|
||||
public:
|
||||
FOculusXRFoveatedRenderingImageGenerator(const FXRSwapChainPtr& Swapchain);
|
||||
virtual ~FOculusXRFoveatedRenderingImageGenerator() override;
|
||||
|
||||
// IVariableRateShadingImageGenerator interface
|
||||
virtual FRDGTextureRef GetImage(FRDGBuilder& GraphBuilder, const FViewInfo& ViewInfo, FVariableRateShadingImageManager::EVRSImageType ImageType) override;
|
||||
virtual void PrepareImages(FRDGBuilder& GraphBuilder, const FSceneViewFamily& ViewFamily, const FMinimalSceneTextures& SceneTextures) override;
|
||||
virtual bool IsEnabledForView(const FSceneView& View) const override;
|
||||
virtual FRDGTextureRef GetDebugImage(FRDGBuilder& GraphBuilder, const FViewInfo& ViewInfo, FVariableRateShadingImageManager::EVRSImageType ImageType) override;
|
||||
virtual FVariableRateShadingImageManager::EVRSSourceType GetType() const override
|
||||
{
|
||||
return FVariableRateShadingImageManager::EVRSSourceType::FixedFoveation;
|
||||
}
|
||||
|
||||
private:
|
||||
const FXRSwapChainPtr& FoveationSwapchain;
|
||||
};
|
||||
#endif // !UE_VERSION_OLDER_THAN(5, 3, 0)
|
||||
@@ -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
|
||||
1484
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Layer.cpp
Normal file
1484
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Layer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
233
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Layer.h
Normal file
233
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Layer.h
Normal file
@@ -0,0 +1,233 @@
|
||||
// @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);
|
||||
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;
|
||||
|
||||
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,135 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "OculusXRHMD_Settings.h"
|
||||
#include "Engine/Engine.h"
|
||||
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
|
||||
namespace OculusXRHMD
|
||||
{
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// FSettings
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
FSettings::FSettings()
|
||||
: BaseOffset(0, 0, 0)
|
||||
, BaseOrientation(FQuat::Identity)
|
||||
, PixelDensity(1.0f)
|
||||
, PixelDensityMin(0.8f)
|
||||
, PixelDensityMax(1.2f)
|
||||
, 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)
|
||||
{
|
||||
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.bBodyTrackingEnabled = false;
|
||||
Flags.bEyeTrackingEnabled = false;
|
||||
Flags.bFaceTrackingEnabled = false;
|
||||
EyeRenderViewport[0] = EyeRenderViewport[1] = FIntRect(0, 0, 0, 0);
|
||||
|
||||
RenderTargetSize = FIntPoint(0, 0);
|
||||
|
||||
#ifdef WITH_OCULUS_BRANCH
|
||||
Flags.bTileTurnOffEnabled = false;
|
||||
#else
|
||||
Flags.bTileTurnOffEnabled = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
TSharedPtr<FSettings, ESPMode::ThreadSafe> FSettings::Clone() const
|
||||
{
|
||||
TSharedPtr<FSettings, ESPMode::ThreadSafe> NewSettings = MakeShareable(new FSettings(*this));
|
||||
return NewSettings;
|
||||
}
|
||||
|
||||
void FSettings::SetPixelDensity(float NewPixelDensity)
|
||||
{
|
||||
if (Flags.bPixelDensityAdaptive)
|
||||
{
|
||||
PixelDensity = FMath::Clamp(NewPixelDensity, PixelDensityMin, PixelDensityMax);
|
||||
}
|
||||
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, PixelDensityMin, PixelDensityMax);
|
||||
}
|
||||
else
|
||||
{
|
||||
PixelDensity = FMath::Clamp(NewClampedPixelDensity, ClampPixelDensityMin, ClampPixelDensityMax);
|
||||
}
|
||||
}
|
||||
|
||||
void FSettings::SetPixelDensityMin(float NewPixelDensityMin)
|
||||
{
|
||||
PixelDensityMin = FMath::Clamp(NewPixelDensityMin, ClampPixelDensityMin, ClampPixelDensityMax);
|
||||
PixelDensityMax = FMath::Max(PixelDensityMin, PixelDensityMax);
|
||||
SetPixelDensity(PixelDensity);
|
||||
}
|
||||
|
||||
void FSettings::SetPixelDensityMax(float NewPixelDensityMax)
|
||||
{
|
||||
PixelDensityMax = FMath::Clamp(NewPixelDensityMax, ClampPixelDensityMin, ClampPixelDensityMax);
|
||||
PixelDensityMin = FMath::Min(PixelDensityMin, PixelDensityMax);
|
||||
SetPixelDensity(PixelDensity);
|
||||
}
|
||||
|
||||
} // namespace OculusXRHMD
|
||||
|
||||
#endif //OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
174
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Settings.h
Normal file
174
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Settings.h
Normal file
@@ -0,0 +1,174 @@
|
||||
// @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 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;
|
||||
};
|
||||
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;
|
||||
float PixelDensityMin;
|
||||
float PixelDensityMax;
|
||||
|
||||
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;
|
||||
|
||||
public:
|
||||
FSettings();
|
||||
virtual ~FSettings() {}
|
||||
|
||||
bool IsStereoEnabled() const { return Flags.bStereoEnabled && Flags.bHMDEnabled; }
|
||||
|
||||
void SetPixelDensity(float NewPixelDensity);
|
||||
void SetPixelDensitySmooth(float NewPixelDensity);
|
||||
void SetPixelDensityMin(float NewPixelDensityMin);
|
||||
void SetPixelDensityMax(float NewPixelDensityMax);
|
||||
|
||||
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, FRHITexture2D* BackBuffer, FTexture2DRHIRef 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,
|
||||
FTexture2DRHIRef(BackBuffer),
|
||||
ForegroundResource->GetRenderTargetTexture(),
|
||||
BackgroundResource->GetRenderTargetTexture());
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (SpectatorMode == EMRSpectatorScreenMode::DirectComposition)
|
||||
{
|
||||
auto BackgroundResource = BackgroundRenderTexture->GetRenderTargetResource();
|
||||
if (BackgroundResource)
|
||||
{
|
||||
RenderSpectatorModeDirectComposition(
|
||||
RHICmdList,
|
||||
FTexture2DRHIRef(BackBuffer),
|
||||
BackgroundRenderTexture->GetRenderTargetResource()->GetRenderTargetTexture());
|
||||
return;
|
||||
}
|
||||
}
|
||||
FDefaultSpectatorScreenController::RenderSpectatorScreen_RenderThread(RHICmdList, BackBuffer, RenderTexture, WindowSize);
|
||||
}
|
||||
}
|
||||
|
||||
void FSpectatorScreenController::RenderSpectatorModeUndistorted(FRHICommandListImmediate& RHICmdList, FTexture2DRHIRef TargetTexture, FTexture2DRHIRef EyeTexture, FTexture2DRHIRef 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, FTexture2DRHIRef TargetTexture, FTexture2DRHIRef EyeTexture, FTexture2DRHIRef OtherTexture, FVector2D WindowSize)
|
||||
{
|
||||
CheckInRenderThread();
|
||||
FCustomPresent* CustomPresent = OculusXRHMD->GetCustomPresent_Internal();
|
||||
FTexture2DRHIRef 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, FTexture2DRHIRef TargetTexture, FTexture2DRHIRef EyeTexture, FTexture2DRHIRef 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, FTexture2DRHIRef TargetTexture, const FTexture2DRHIRef 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, FTexture2DRHIRef TargetTexture, const FTexture2DRHIRef FrontTexture, const FTexture2DRHIRef 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, FRHITexture2D* BackBuffer, FTexture2DRHIRef RenderTarget, FVector2D WindowSize) override;
|
||||
virtual void RenderSpectatorModeUndistorted(FRHICommandListImmediate& RHICmdList, FTexture2DRHIRef TargetTexture, FTexture2DRHIRef EyeTexture, FTexture2DRHIRef OtherTexture, FVector2D WindowSize) override;
|
||||
virtual void RenderSpectatorModeDistorted(FRHICommandListImmediate& RHICmdList, FTexture2DRHIRef TargetTexture, FTexture2DRHIRef EyeTexture, FTexture2DRHIRef OtherTexture, FVector2D WindowSize) override;
|
||||
virtual void RenderSpectatorModeSingleEye(FRHICommandListImmediate& RHICmdList, FTexture2DRHIRef TargetTexture, FTexture2DRHIRef EyeTexture, FTexture2DRHIRef OtherTexture, FVector2D WindowSize) override;
|
||||
|
||||
private:
|
||||
FOculusXRHMD* OculusXRHMD;
|
||||
EMRSpectatorScreenMode SpectatorMode;
|
||||
UTextureRenderTarget2D* ForegroundRenderTexture;
|
||||
UTextureRenderTarget2D* BackgroundRenderTexture;
|
||||
|
||||
void RenderSpectatorModeDirectComposition(FRHICommandListImmediate& RHICmdList, FTexture2DRHIRef TargetTexture, const FTexture2DRHIRef SrcTexture) const;
|
||||
void RenderSpectatorModeExternalComposition(FRHICommandListImmediate& RHICmdList, FTexture2DRHIRef TargetTexture, const FTexture2DRHIRef FrontTexture, const FTexture2DRHIRef BackTexture) const;
|
||||
};
|
||||
|
||||
} // namespace OculusXRHMD
|
||||
|
||||
#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
666
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Splash.cpp
Normal file
666
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Splash.cpp
Normal file
@@ -0,0 +1,666 @@
|
||||
// @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 "StereoLayerFunctionLibrary.h"
|
||||
#include "TextureResource.h"
|
||||
|
||||
#if PLATFORM_ANDROID
|
||||
#include "Android/AndroidJNI.h"
|
||||
#include "Android/AndroidEGL.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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->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,152 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#include "OculusXRPassthroughLayerShapes.h"
|
||||
|
||||
#include "OculusXRHMDPrivate.h"
|
||||
#include "Curves/CurveLinearColor.h"
|
||||
#include "OculusXRPluginWrapper.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);
|
||||
}
|
||||
|
||||
NewColorMapData.SetNum(TotalEntries * sizeof(ovrpColorf));
|
||||
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 += sizeof(ovrpColorf);
|
||||
}
|
||||
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,461 @@
|
||||
// @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(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(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(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(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(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(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(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(CreateSpaceUser),
|
||||
OCULUS_BIND_ENTRY_POINT(DestroySpaceUser),
|
||||
|
||||
|
||||
// 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),
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// 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),
|
||||
|
||||
// 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,414 @@
|
||||
// @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(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(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(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(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(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(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(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(CreateSpaceUser);
|
||||
OCULUS_DECLARE_ENTRY_POINT(DestroySpaceUser);
|
||||
|
||||
|
||||
// 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);
|
||||
|
||||
|
||||
|
||||
|
||||
// Local Groups
|
||||
|
||||
// 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);
|
||||
|
||||
// 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
|
||||
106
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRQPL.cpp
Normal file
106
Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRQPL.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
// 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
|
||||
};
|
||||
@@ -0,0 +1,66 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "OculusXRSimulator.h"
|
||||
#if PLATFORM_WINDOWS
|
||||
#include "OculusXRHMDRuntimeSettings.h"
|
||||
#include "OculusXRTelemetryEvents.h"
|
||||
#include "Misc/MessageDialog.h"
|
||||
|
||||
#include "Windows/WindowsPlatformMisc.h"
|
||||
|
||||
const FString OpenXrRuntimeEnvKey = "XR_RUNTIME_JSON";
|
||||
const FString PreviousOpenXrRuntimeEnvKey = "XR_RUNTIME_JSON_PREV";
|
||||
|
||||
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))
|
||||
{
|
||||
FString Message("Meta XR Simulator Not Found.\nPlease set its path in Project Settings/Meta XR Plugin/PC.");
|
||||
FMessageDialog::Open(EAppMsgType::Ok, FText::FromString(Message));
|
||||
UE_LOG(LogMetaXRSim, Error, TEXT("%s"), *Message);
|
||||
const auto& NotEnd = Event.SetResult(OculusXRTelemetry::EAction::Fail).AddAnnotation("reason", "not found");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
FString FMetaXRSimulator::GetSimulatorJsonPath()
|
||||
{
|
||||
return GetMutableDefault<UOculusXRHMDRuntimeSettings>()->MetaXRJsonPath.FilePath;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,21 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
DEFINE_LOG_CATEGORY_STATIC(LogMetaXRSim, Log, All);
|
||||
|
||||
/** */
|
||||
class FMetaXRSimulator
|
||||
{
|
||||
public:
|
||||
static bool IsSimulatorActivated();
|
||||
static void ToggleOpenXRRuntime();
|
||||
|
||||
private:
|
||||
static FString GetSimulatorJsonPath();
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,108 @@
|
||||
// @lint-ignore-every LICENSELINT
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "OculusXRSyntheticEnvironmentServer.h"
|
||||
#if PLATFORM_WINDOWS
|
||||
#include "OculusXRHMDRuntimeSettings.h"
|
||||
#include "OculusXRTelemetryEvents.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(FString EnvironmentName)
|
||||
{
|
||||
if (GetMetaXRSimPackagePath().IsEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
StopServer();
|
||||
|
||||
OculusXRTelemetry::TScopedMarker<OculusXRTelemetry::Events::FSimulator> Event;
|
||||
FString SESPath = GetSynthEnvServerPath();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
FString FMetaXRSES::GetMetaXRSimPackagePath()
|
||||
{
|
||||
FString JsonPath = GetMutableDefault<UOculusXRHMDRuntimeSettings>()->MetaXRJsonPath.FilePath;
|
||||
if (JsonPath.IsEmpty() || !IFileManager::Get().FileExists(*JsonPath))
|
||||
{
|
||||
FString Message("Meta XR Simulator Not Found.\nPlease set its path in Project Settings/Meta XR Plugin/PC.");
|
||||
FMessageDialog::Open(EAppMsgType::Ok, FText::FromString(Message));
|
||||
UE_LOG(LogMetaXRSES, Error, TEXT("%s"), *Message);
|
||||
}
|
||||
return FPaths::GetPath(JsonPath);
|
||||
}
|
||||
|
||||
FString FMetaXRSES::GetSynthEnvServerPath()
|
||||
{
|
||||
return GetMetaXRSimPackagePath() + "/.synth_env_server/synth_env_server.exe";
|
||||
}
|
||||
|
||||
FString FMetaXRSES::GetLocalSharingServerPath()
|
||||
{
|
||||
return GetMetaXRSimPackagePath() + "/.local_sharing_server/local_sharing_server.exe";
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,31 @@
|
||||
// @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(FString EnvironmentName);
|
||||
static void StopServer();
|
||||
|
||||
private:
|
||||
static void LaunchLocalSharingServer();
|
||||
static bool LaunchProcess(FString BinaryPath, FString Arguments, FString LogContext, FProcHandle& OutProcHandle);
|
||||
static void StopProcess(FProcHandle& ProcHandle, FString LogContext);
|
||||
|
||||
static FString GetMetaXRSimPackagePath();
|
||||
static FString GetSynthEnvServerPath();
|
||||
static FString GetLocalSharingServerPath();
|
||||
|
||||
static FProcHandle EnvProcHandle;
|
||||
static FProcHandle LSSProcHandle;
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,49 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#include "OculusXRTelemetry.h"
|
||||
#include "OculusXRHMDModule.h"
|
||||
#include "OculusXRTelemetryPrivacySettings.h"
|
||||
#include "Async/Async.h"
|
||||
|
||||
namespace OculusXRTelemetry
|
||||
{
|
||||
bool IsActive()
|
||||
{
|
||||
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||||
if constexpr (FTelemetryBackend::IsNullBackend())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (FOculusXRHMDModule::Get().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()
|
||||
{
|
||||
bool HasConsent = true;
|
||||
#ifdef WITH_EDITOR
|
||||
if (const auto EditorPrivacySettings = GetDefault<UOculusXRTelemetryPrivacySettings>())
|
||||
{
|
||||
HasConsent = EditorPrivacySettings->bIsEnabled;
|
||||
}
|
||||
#endif
|
||||
if (FOculusXRHMDModule::Get().IsOVRPluginAvailable() && FOculusXRHMDModule::GetPluginWrapper().IsInitialized())
|
||||
{
|
||||
FOculusXRHMDModule::GetPluginWrapper().QplSetConsent(HasConsent);
|
||||
}
|
||||
}
|
||||
} // namespace OculusXRTelemetry
|
||||
@@ -0,0 +1,12 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "OculusXRTelemetry.h"
|
||||
|
||||
namespace OculusXRTelemetry::Events
|
||||
{
|
||||
using FEditorConsent = TMarker<191965622>;
|
||||
using FSimulator = TMarker<191963436>;
|
||||
constexpr const char* ConsentOriginKey = "Origin";
|
||||
} // namespace OculusXRTelemetry::Events
|
||||
@@ -0,0 +1,82 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
#include "OculusXRTelemetryPrivacySettings.h"
|
||||
|
||||
#include "OculusXRHMDModule.h"
|
||||
#include "OculusXRTelemetry.h"
|
||||
#include "OculusXRTelemetryEvents.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "OculusXRTelemetryPrivacySettings"
|
||||
|
||||
UOculusXRTelemetryPrivacySettings::UOculusXRTelemetryPrivacySettings(const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
}
|
||||
|
||||
void UOculusXRTelemetryPrivacySettings::GetToggleCategoryAndPropertyNames(FName& OutCategory, FName& OutProperty) const
|
||||
{
|
||||
OutCategory = FName("Options");
|
||||
OutProperty = FName("bIsEnabled");
|
||||
};
|
||||
|
||||
FText UOculusXRTelemetryPrivacySettings::GetFalseStateLabel() const
|
||||
{
|
||||
return LOCTEXT("FalseStateLabel", "Don't Send");
|
||||
};
|
||||
|
||||
FText UOculusXRTelemetryPrivacySettings::GetFalseStateTooltip() const
|
||||
{
|
||||
return LOCTEXT("FalseStateTooltip", "Don't send MetaXR plugin usage data to Meta.");
|
||||
};
|
||||
|
||||
FText UOculusXRTelemetryPrivacySettings::GetFalseStateDescription() const
|
||||
{
|
||||
return LOCTEXT("FalseStateDescription", "By opting out you don't allow Meta to collect usage data on its SDKs, such as package name, class names and plugin configuration in your projects using Meta SDKs on this machine. This data helps improve the Meta SDKs and is collected in accordance with Meta's Privacy Policy.");
|
||||
};
|
||||
|
||||
FText UOculusXRTelemetryPrivacySettings::GetTrueStateLabel() const
|
||||
{
|
||||
return LOCTEXT("TrueStateLabel", "Send Usage Data");
|
||||
};
|
||||
|
||||
FText UOculusXRTelemetryPrivacySettings::GetTrueStateTooltip() const
|
||||
{
|
||||
return LOCTEXT("TrueStateTooltip", "Send MetaXR plugin usage data to Meta.");
|
||||
};
|
||||
|
||||
FText UOculusXRTelemetryPrivacySettings::GetTrueStateDescription() const
|
||||
{
|
||||
return LOCTEXT("TrueStateDescription", "By opting in you allow Meta to collect usage data on its SDKs, such as package name, class names and plugin configuration in your projects using Meta SDKs on this machine. This data helps improve the Meta SDKs and is collected in accordance with Meta's Privacy Policy.");
|
||||
};
|
||||
|
||||
FString UOculusXRTelemetryPrivacySettings::GetAdditionalInfoUrl() const
|
||||
{
|
||||
return FString(TEXT("https://www.meta.com/legal/quest/privacy-policy/"));
|
||||
};
|
||||
|
||||
FText UOculusXRTelemetryPrivacySettings::GetAdditionalInfoUrlLabel() const
|
||||
{
|
||||
return LOCTEXT("HyperlinkLabel", "Meta Platforms Technologies Privacy Policy");
|
||||
};
|
||||
|
||||
#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())
|
||||
{
|
||||
PropagateTelemetryConsent();
|
||||
Events::FEditorConsent().Start() //
|
||||
.AddAnnotation(Events::ConsentOriginKey, "Settings") //
|
||||
.End(bIsEnabled ? EAction::Success : EAction::Fail);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
@@ -0,0 +1,39 @@
|
||||
// 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, config, Category = Options)
|
||||
bool bIsEnabled = false;
|
||||
|
||||
UPROPERTY(config)
|
||||
bool bHasNotified = 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
|
||||
};
|
||||
Reference in New Issue
Block a user