Files
Brandyn / Techy fcc1b09210 init
2026-04-04 15:40:51 -05:00

340 lines
13 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "OpenXRHMD_RenderBridge.h"
#include "OpenXRHMD.h"
#include "OpenXRHMD_Swapchain.h"
#include "OpenXRCore.h"
bool FOpenXRRenderBridge::Present(IRHICommandContext& RHICmdContext, int32& InOutSyncInterval)
{
bool bNeedsNativePresent = true;
if (OpenXRHMD)
{
HMDOnFinishRendering_RHIThread(RHICmdContext);
bNeedsNativePresent = !OpenXRHMD->IsStandaloneStereoOnlyDevice();
}
InOutSyncInterval = 0; // VSync off
return bNeedsNativePresent;
}
void FOpenXRRenderBridge::HMDOnFinishRendering_RHIThread(IRHICommandContext& RHICmdContext)
{
if (OpenXRHMD)
{
OpenXRHMD->OnFinishRendering_RHIThread(RHICmdContext);
}
}
#ifdef XR_USE_GRAPHICS_API_D3D11
class FD3D11RenderBridge : public FOpenXRRenderBridge
{
public:
FD3D11RenderBridge(XrInstance InInstance)
: FOpenXRRenderBridge(InInstance)
, Binding()
{
XR_ENSURE(xrGetInstanceProcAddr(InInstance, "xrGetD3D11GraphicsRequirementsKHR", (PFN_xrVoidFunction*)&GetD3D11GraphicsRequirementsKHR));
}
virtual uint64 GetGraphicsAdapterLuid(XrSystemId InSystem) override
{
XrGraphicsRequirementsD3D11KHR Requirements;
Requirements.type = XR_TYPE_GRAPHICS_REQUIREMENTS_D3D11_KHR;
Requirements.next = nullptr;
if (XR_ENSURE(GetD3D11GraphicsRequirementsKHR(Instance, InSystem, &Requirements)))
{
return reinterpret_cast<uint64&>(Requirements.adapterLuid);
}
return 0;
}
virtual void* GetGraphicsBinding(XrSystemId InSystem) override
{
DXGI_ADAPTER_DESC AdapterDesc;
GetID3D11DynamicRHI()->RHIGetAdapter()->GetDesc(&AdapterDesc);
if (reinterpret_cast<uint64&>(AdapterDesc.AdapterLuid) != GetGraphicsAdapterLuid(InSystem))
{
return nullptr;
}
Binding.type = XR_TYPE_GRAPHICS_BINDING_D3D11_KHR;
Binding.next = nullptr;
Binding.device = GetID3D11DynamicRHI()->RHIGetDevice();
return &Binding;
}
virtual FXRSwapChainPtr CreateSwapchain(XrSession InSession, uint8 Format, uint8& OutActualFormat, uint32 SizeX, uint32 SizeY, uint32 ArraySize, uint32 NumMips, uint32 NumSamples, ETextureCreateFlags CreateFlags, const FClearValueBinding& ClearValueBinding, ETextureCreateFlags AuxiliaryCreateFlags) override final
{
return CreateSwapchain_D3D11(InSession, Format, OutActualFormat, SizeX, SizeY, ArraySize, NumMips, NumSamples, CreateFlags, ClearValueBinding, AuxiliaryCreateFlags);
}
private:
PFN_xrGetD3D11GraphicsRequirementsKHR GetD3D11GraphicsRequirementsKHR;
XrGraphicsBindingD3D11KHR Binding;
};
FOpenXRRenderBridge* CreateRenderBridge_D3D11(XrInstance InInstance) { return new FD3D11RenderBridge(InInstance); }
#endif
#ifdef XR_USE_GRAPHICS_API_D3D12
class FD3D12RenderBridge : public FOpenXRRenderBridge
{
public:
FD3D12RenderBridge(XrInstance InInstance)
: FOpenXRRenderBridge(InInstance)
, Binding()
{
XR_ENSURE(xrGetInstanceProcAddr(InInstance, "xrGetD3D12GraphicsRequirementsKHR", (PFN_xrVoidFunction*)&GetD3D12GraphicsRequirementsKHR));
}
virtual uint64 GetGraphicsAdapterLuid(XrSystemId InSystem) override
{
XrGraphicsRequirementsD3D12KHR Requirements;
Requirements.type = XR_TYPE_GRAPHICS_REQUIREMENTS_D3D12_KHR;
Requirements.next = nullptr;
if (XR_ENSURE(GetD3D12GraphicsRequirementsKHR(Instance, InSystem, &Requirements)))
{
return reinterpret_cast<uint64&>(Requirements.adapterLuid);
}
return 0;
}
virtual void* GetGraphicsBinding(XrSystemId InSystem) override
{
LUID AdapterLuid = GetID3D12DynamicRHI()->RHIGetDevice(0)->GetAdapterLuid();
if (reinterpret_cast<uint64&>(AdapterLuid) != GetGraphicsAdapterLuid(InSystem))
{
return nullptr;
}
Binding.type = XR_TYPE_GRAPHICS_BINDING_D3D12_KHR;
Binding.next = nullptr;
Binding.device = GetID3D12DynamicRHI()->RHIGetDevice(0);
Binding.queue = GetID3D12DynamicRHI()->RHIGetCommandQueue();
return &Binding;
}
virtual FXRSwapChainPtr CreateSwapchain(XrSession InSession, uint8 Format, uint8& OutActualFormat, uint32 SizeX, uint32 SizeY, uint32 ArraySize, uint32 NumMips, uint32 NumSamples, ETextureCreateFlags CreateFlags, const FClearValueBinding& ClearValueBinding, ETextureCreateFlags AuxiliaryCreateFlags) override final
{
return CreateSwapchain_D3D12(InSession, Format, OutActualFormat, SizeX, SizeY, ArraySize, NumMips, NumSamples, CreateFlags, ClearValueBinding, AuxiliaryCreateFlags);
}
virtual void RunOnRHISubmissionThread(TFunction<void()>&& CodeToRun) override
{
ensure(IsInRenderingThread() || IsInRHIThread());
GetID3D12DynamicRHI()->RHIRunOnQueue(ED3D12RHIRunOnQueueType::Graphics, [CodeToRun](ID3D12CommandQueue* Queue) { CodeToRun(); }, false);
}
private:
PFN_xrGetD3D12GraphicsRequirementsKHR GetD3D12GraphicsRequirementsKHR;
XrGraphicsBindingD3D12KHR Binding;
};
FOpenXRRenderBridge* CreateRenderBridge_D3D12(XrInstance InInstance) { return new FD3D12RenderBridge(InInstance); }
#endif
#ifdef XR_USE_GRAPHICS_API_OPENGL
class FOpenGLRenderBridge : public FOpenXRRenderBridge
{
public:
FOpenGLRenderBridge(XrInstance InInstance)
: FOpenXRRenderBridge(InInstance)
, Binding()
{
XR_ENSURE(xrGetInstanceProcAddr(InInstance, "xrGetOpenGLGraphicsRequirementsKHR", (PFN_xrVoidFunction*)&GetOpenGLGraphicsRequirementsKHR));
}
virtual void* GetGraphicsBinding(XrSystemId InSystem) override
{
XrGraphicsRequirementsOpenGLKHR Requirements;
Requirements.type = XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR;
Requirements.next = nullptr;
Requirements.minApiVersionSupported = 0;
Requirements.maxApiVersionSupported = 0;
XR_ENSURE(GetOpenGLGraphicsRequirementsKHR(Instance, InSystem, &Requirements));
IOpenGLDynamicRHI* RHI = GetIOpenGLDynamicRHI();
XrVersion RHIVersion = XR_MAKE_VERSION(RHI->RHIGetGLMajorVersion(), RHI->RHIGetGLMinorVersion(), 0);
if (RHIVersion < Requirements.minApiVersionSupported) //-V547
{
UE_LOG(LogHMD, Error, TEXT("The OpenGL API version does not meet the minimum version required by the OpenXR runtime"));
return nullptr;
}
if (RHIVersion > Requirements.maxApiVersionSupported) //-V547
{
UE_LOG(LogHMD, Warning, TEXT("The OpenGL API version has not been tested with the OpenXR runtime"));
}
#if PLATFORM_WINDOWS
Binding.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR;
Binding.next = nullptr;
Binding.hDC = wglGetCurrentDC();
Binding.hGLRC = wglGetCurrentContext();
return &Binding;
#else
return nullptr;
#endif
}
virtual FXRSwapChainPtr CreateSwapchain(XrSession InSession, uint8 Format, uint8& OutActualFormat, uint32 SizeX, uint32 SizeY, uint32 ArraySize, uint32 NumMips, uint32 NumSamples, ETextureCreateFlags CreateFlags, const FClearValueBinding& ClearValueBinding, ETextureCreateFlags AuxiliaryCreateFlags) override final
{
return CreateSwapchain_OpenGL(InSession, Format, OutActualFormat, SizeX, SizeY, ArraySize, NumMips, NumSamples, CreateFlags, ClearValueBinding, AuxiliaryCreateFlags);
}
private:
PFN_xrGetOpenGLGraphicsRequirementsKHR GetOpenGLGraphicsRequirementsKHR;
#if PLATFORM_WINDOWS
XrGraphicsBindingOpenGLWin32KHR Binding;
#endif
};
FOpenXRRenderBridge* CreateRenderBridge_OpenGL(XrInstance InInstance) { return new FOpenGLRenderBridge(InInstance); }
#endif
#ifdef XR_USE_GRAPHICS_API_OPENGL_ES
class FOpenGLESRenderBridge : public FOpenXRRenderBridge
{
public:
FOpenGLESRenderBridge(XrInstance InInstance)
: FOpenXRRenderBridge(InInstance)
, Binding()
{
XR_ENSURE(xrGetInstanceProcAddr(InInstance, "xrGetOpenGLESGraphicsRequirementsKHR", (PFN_xrVoidFunction*)&GetOpenGLESGraphicsRequirementsKHR));
}
virtual void* GetGraphicsBinding(XrSystemId InSystem) override
{
XrGraphicsRequirementsOpenGLESKHR Requirements;
Requirements.type = XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR;
Requirements.next = nullptr;
Requirements.minApiVersionSupported = 0;
Requirements.maxApiVersionSupported = 0;
XR_ENSURE(GetOpenGLESGraphicsRequirementsKHR(Instance, InSystem, &Requirements));
#if PLATFORM_ANDROID
IOpenGLDynamicRHI* RHI = GetIOpenGLDynamicRHI();
XrVersion RHIVersion = XR_MAKE_VERSION(RHI->RHIGetGLMajorVersion(), RHI->RHIGetGLMinorVersion(), 0);
if (RHIVersion < Requirements.minApiVersionSupported) //-V547
{
UE_LOG(LogHMD, Error, TEXT("The OpenGLES API version does not meet the minimum version required by the OpenXR runtime"));
return nullptr;
}
if (RHIVersion > Requirements.maxApiVersionSupported) //-V547
{
UE_LOG(LogHMD, Warning, TEXT("The OpenGLES API version has not been tested with the OpenXR runtime"));
}
Binding.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR;
Binding.next = nullptr;
Binding.display = RHI->RHIGetEGLDisplay();
Binding.config = RHI->RHIGetEGLConfig();
Binding.context = RHI->RHIGetEGLContext();
return &Binding;
#endif
return nullptr;
}
virtual FXRSwapChainPtr CreateSwapchain(XrSession InSession, uint8 Format, uint8& OutActualFormat, uint32 SizeX, uint32 SizeY, uint32 ArraySize, uint32 NumMips, uint32 NumSamples, ETextureCreateFlags CreateFlags, const FClearValueBinding& ClearValueBinding, ETextureCreateFlags AuxiliaryCreateFlags) override final
{
return CreateSwapchain_OpenGLES(InSession, Format, OutActualFormat, SizeX, SizeY, ArraySize, NumMips, NumSamples, CreateFlags, ClearValueBinding, AuxiliaryCreateFlags);
}
private:
PFN_xrGetOpenGLESGraphicsRequirementsKHR GetOpenGLESGraphicsRequirementsKHR;
#if PLATFORM_ANDROID
XrGraphicsBindingOpenGLESAndroidKHR Binding;
#endif
};
FOpenXRRenderBridge* CreateRenderBridge_OpenGLES(XrInstance InInstance) { return new FOpenGLESRenderBridge(InInstance); }
#endif
#ifdef XR_USE_GRAPHICS_API_VULKAN
class FVulkanRenderBridge : public FOpenXRRenderBridge
{
public:
FVulkanRenderBridge(XrInstance InInstance)
: FOpenXRRenderBridge(InInstance)
, Binding()
{
XR_ENSURE(xrGetInstanceProcAddr(InInstance, "xrGetVulkanGraphicsRequirementsKHR", (PFN_xrVoidFunction*)&GetVulkanGraphicsRequirementsKHR));
XR_ENSURE(xrGetInstanceProcAddr(InInstance, "xrGetVulkanGraphicsDeviceKHR", (PFN_xrVoidFunction*)&GetVulkanGraphicsDeviceKHR));
}
virtual void* GetGraphicsBinding(XrSystemId InSystem) override
{
XrGraphicsRequirementsVulkanKHR Requirements;
Requirements.type = XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR;
Requirements.next = nullptr;
Requirements.minApiVersionSupported = 0;
Requirements.maxApiVersionSupported = 0;
XR_ENSURE(GetVulkanGraphicsRequirementsKHR(Instance, InSystem, &Requirements));
IVulkanDynamicRHI* VulkanRHI = GetIVulkanDynamicRHI();
const uint32 VulkanVersion = VulkanRHI->RHIGetVulkanVersion();
// The extension uses the OpenXR version format instead of the Vulkan one
XrVersion RHIVersion = XR_MAKE_VERSION(
VK_VERSION_MAJOR(VulkanVersion),
VK_VERSION_MINOR(VulkanVersion),
VK_VERSION_PATCH(VulkanVersion)
);
if (RHIVersion < Requirements.minApiVersionSupported) //-V547
{
UE_LOG(LogHMD, Fatal, TEXT("The Vulkan API version does not meet the minimum version required by the OpenXR runtime"));
}
if (RHIVersion > Requirements.maxApiVersionSupported) //-V547
{
UE_LOG(LogHMD, Warning, TEXT("The Vulkan API version has not been tested with the OpenXR runtime"));
}
VkPhysicalDevice Gpu = nullptr;
XR_ENSURE(GetVulkanGraphicsDeviceKHR(Instance, InSystem, VulkanRHI->RHIGetVkInstance(), &Gpu));
if (Gpu != VulkanRHI->RHIGetVkPhysicalDevice())
{
return nullptr;
}
Binding.type = XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR;
Binding.next = nullptr;
Binding.instance = VulkanRHI->RHIGetVkInstance();
Binding.physicalDevice = VulkanRHI->RHIGetVkPhysicalDevice();
Binding.device = VulkanRHI->RHIGetVkDevice();
Binding.queueFamilyIndex = VulkanRHI->RHIGetGraphicsQueueFamilyIndex();
Binding.queueIndex = 0;
return &Binding;
}
virtual uint64 GetGraphicsAdapterLuid(XrSystemId InSystem) override
{
VkPhysicalDevice Gpu = nullptr;
XR_ENSURE(GetVulkanGraphicsDeviceKHR(Instance, InSystem, GetIVulkanDynamicRHI()->RHIGetVkInstance(), &Gpu));
return GetIVulkanDynamicRHI()->RHIGetGraphicsAdapterLUID(Gpu);
}
virtual FXRSwapChainPtr CreateSwapchain(XrSession InSession, uint8 Format, uint8& OutActualFormat, uint32 SizeX, uint32 SizeY, uint32 ArraySize, uint32 NumMips, uint32 NumSamples, ETextureCreateFlags CreateFlags, const FClearValueBinding& ClearValueBinding, ETextureCreateFlags AuxiliaryCreateFlags) override final
{
return CreateSwapchain_Vulkan(InSession, Format, OutActualFormat, SizeX, SizeY, ArraySize, NumMips, NumSamples, CreateFlags, ClearValueBinding, AuxiliaryCreateFlags);
}
virtual void RunOnRHISubmissionThread(TFunction<void()>&& CodeToRun) override
{
ensure(IsInRenderingThread() || IsInRHIThread());
GetIVulkanDynamicRHI()->RHIRunOnQueue(EVulkanRHIRunOnQueueType::Graphics, [CodeToRun](VkQueue Queue) { CodeToRun(); }, false);
}
private:
PFN_xrGetVulkanGraphicsRequirementsKHR GetVulkanGraphicsRequirementsKHR;
PFN_xrGetVulkanGraphicsDeviceKHR GetVulkanGraphicsDeviceKHR;
XrGraphicsBindingVulkanKHR Binding;
};
FOpenXRRenderBridge* CreateRenderBridge_Vulkan(XrInstance InInstance) { return new FVulkanRenderBridge(InInstance); }
#endif