Skip to content

Commit 546548d

Browse files
Vulkan: enabled OpenXR support through XR_KHR_vulkan_enable2
1 parent 8d2e896 commit 546548d

File tree

10 files changed

+312
-40
lines changed

10 files changed

+312
-40
lines changed

.github/workflows/build-windows.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ jobs:
2828
toolset: ["Win32", "x64"]
2929
build_type: ["Debug", "Release"]
3030
cmake_generator: ["Visual Studio 17 2022"]
31-
cmake_args: ["-DDILIGENT_BUILD_TESTS=ON -DDILIGENT_NO_WEBGPU=OFF"]
31+
cmake_args: ["-DDILIGENT_BUILD_TESTS=ON -DDILIGENT_NO_WEBGPU=OFF -DDILIGENT_USE_OPENXR=ON "]
3232
platform: ["Win32"]
3333

3434
include:

Graphics/GraphicsEngine/interface/GraphicsTypes.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3408,6 +3408,21 @@ struct ImmediateContextCreateInfo
34083408
typedef struct ImmediateContextCreateInfo ImmediateContextCreateInfo;
34093409

34103410

3411+
/// OpenXR attributes
3412+
struct OpenXRAttribs
3413+
{
3414+
/// A pointer to the xrGetInstanceProcAddr function.
3415+
void* GetInstanceProcAddr DEFAULT_INITIALIZER(nullptr);
3416+
3417+
/// OpenXR instance handle (XrInstance).
3418+
Uint64 Instance DEFAULT_INITIALIZER(0);
3419+
3420+
/// OpenXR system id (XrSystemId).
3421+
Uint64 SystemId DEFAULT_INITIALIZER(0);
3422+
};
3423+
typedef struct OpenXRAttribs OpenXRAttribs;
3424+
3425+
34113426
/// Engine creation information
34123427
struct EngineCreateInfo
34133428
{
@@ -3504,6 +3519,10 @@ struct EngineCreateInfo
35043519
// The structure must be 8-byte aligned
35053520
Uint32 Padding DEFAULT_INITIALIZER(0);
35063521

3522+
/// An optional pointer to the OpenXR attributes, must be set if OpenXR is used.
3523+
/// See Diligent::OpenXRAttribs.
3524+
const OpenXRAttribs *pXRAttribs DEFAULT_INITIALIZER(nullptr);
3525+
35073526
#if DILIGENT_CPP_INTERFACE
35083527
EngineCreateInfo() noexcept
35093528
{

Graphics/GraphicsEngineVulkan/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,9 @@ else()
265265
find_library(Vulkan_LIBRARY NAMES vulkan)
266266
list(APPEND PRIVATE_DEPENDENCIES ${Vulkan_LIBRARY})
267267
endif()
268+
if(DILIGENT_USE_OPENXR)
269+
list(APPEND PRIVATE_DEPENDENCIES OpenXR::headers)
270+
endif()
268271

269272
set(PUBLIC_DEPENDENCIES
270273
Diligent-GraphicsEngineVkInterface
@@ -311,6 +314,10 @@ if (${DILIGENT_NO_GLSLANG})
311314
message("GLSLang is not being built. Vulkan backend will only be able to consume SPIRV byte code.")
312315
endif()
313316

317+
if(DILIGENT_USE_OPENXR)
318+
list(APPEND PRIVATE_COMPILE_DEFINITIONS DILIGENT_USE_OPENXR=1)
319+
endif()
320+
314321
target_compile_definitions(Diligent-GraphicsEngineVk-static
315322
PRIVATE
316323
${PRIVATE_COMPILE_DEFINITIONS}

Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanInstance.hpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019-2022 Diligent Graphics LLC
2+
* Copyright 2019-2024 Diligent Graphics LLC
33
* Copyright 2015-2019 Egor Yusov
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -62,6 +62,13 @@ class VulkanInstance : public std::enable_shared_from_this<VulkanInstance>
6262
VkAllocationCallbacks* pVkAllocator = nullptr;
6363
uint32_t IgnoreDebugMessageCount = 0;
6464
const char* const* ppIgnoreDebugMessageNames = nullptr;
65+
66+
struct OpenXRInfo
67+
{
68+
uint64_t Instance = 0;
69+
uint64_t SystemId = 0;
70+
void* GetInstanceProcAddr = nullptr;
71+
} XR;
6572
};
6673
static std::shared_ptr<VulkanInstance> Create(const CreateInfo& CI);
6774

@@ -82,7 +89,8 @@ class VulkanInstance : public std::enable_shared_from_this<VulkanInstance>
8289
bool IsExtensionAvailable(const char* ExtensionName)const;
8390
bool IsExtensionEnabled (const char* ExtensionName)const;
8491

85-
VkPhysicalDevice SelectPhysicalDevice(uint32_t AdapterId)const;
92+
VkPhysicalDevice SelectPhysicalDevice(uint32_t AdapterId)const noexcept(false);
93+
VkPhysicalDevice SelectPhysicalDeviceForOpenXR(const CreateInfo::OpenXRInfo& XRInfo)const noexcept(false);
8694

8795
VkAllocationCallbacks* GetVkAllocator() const {return m_pVkAllocator;}
8896
VkInstance GetVkInstance() const {return m_VkInstance; }

Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanLogicalDevice.hpp

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019-2022 Diligent Graphics LLC
2+
* Copyright 2019-2024 Diligent Graphics LLC
33
* Copyright 2015-2019 Egor Yusov
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -92,10 +92,15 @@ class VulkanLogicalDevice : public std::enable_shared_from_this<VulkanLogicalDev
9292
public:
9393
using ExtensionFeatures = VulkanPhysicalDevice::ExtensionFeatures;
9494

95-
static std::shared_ptr<VulkanLogicalDevice> Create(const VulkanPhysicalDevice& PhysicalDevice,
96-
const VkDeviceCreateInfo& DeviceCI,
97-
const ExtensionFeatures& EnabledExtFeatures,
98-
const VkAllocationCallbacks* vkAllocator);
95+
struct CreateInfo
96+
{
97+
const VulkanPhysicalDevice& PhysicalDevice;
98+
const VkDevice vkDevice;
99+
const VkPhysicalDeviceFeatures& EnabledFeatures;
100+
const ExtensionFeatures& EnabledExtFeatures;
101+
const VkAllocationCallbacks* const vkAllocator;
102+
};
103+
static std::shared_ptr<VulkanLogicalDevice> Create(const CreateInfo& CI);
99104

100105
// clang-format off
101106
VulkanLogicalDevice (const VulkanLogicalDevice&) = delete;
@@ -243,10 +248,7 @@ class VulkanLogicalDevice : public std::enable_shared_from_this<VulkanLogicalDev
243248
const ExtensionFeatures& GetEnabledExtFeatures() const { return m_EnabledExtFeatures; }
244249

245250
private:
246-
VulkanLogicalDevice(const VulkanPhysicalDevice& PhysicalDevice,
247-
const VkDeviceCreateInfo& DeviceCI,
248-
const ExtensionFeatures& EnabledExtFeatures,
249-
const VkAllocationCallbacks* vkAllocator);
251+
VulkanLogicalDevice(const CreateInfo& CI);
250252

251253
template <typename VkObjectType,
252254
VulkanHandleTypeId VkTypeId,

Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp

Lines changed: 90 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@
4646
# include "FileSystem.hpp"
4747
#endif
4848

49+
#if DILIGENT_USE_OPENXR
50+
# define XR_USE_GRAPHICS_API_VULKAN
51+
# include <openxr/openxr_platform.h>
52+
#endif
53+
4954
namespace Diligent
5055
{
5156
namespace
@@ -620,6 +625,43 @@ void EngineFactoryVkImpl::EnumerateAdapters(Version MinVersion,
620625
}
621626
}
622627

628+
#if DILIGENT_USE_OPENXR
629+
VkResult CreateVulkanDeviceForOpenXR(const OpenXRAttribs& XRAttribs,
630+
VkPhysicalDevice PhysicalDevice,
631+
const VkDeviceCreateInfo* pCreateInfo,
632+
const VkAllocationCallbacks* pAllocator,
633+
VkDevice* pDevice) noexcept(false)
634+
{
635+
XrInstance xrInstance = XR_NULL_HANDLE;
636+
static_assert(sizeof(XrInstance) == sizeof(XRAttribs.Instance), "XrInstance size mismatch");
637+
memcpy(&xrInstance, &XRAttribs.Instance, sizeof(XrInstance));
638+
639+
PFN_xrGetInstanceProcAddr xrGetInstanceProcAddr = reinterpret_cast<PFN_xrGetInstanceProcAddr>(XRAttribs.GetInstanceProcAddr);
640+
PFN_xrCreateVulkanDeviceKHR xrCreateVulkanDeviceKHR = nullptr;
641+
if (XR_FAILED(xrGetInstanceProcAddr(xrInstance, "xrCreateVulkanDeviceKHR", reinterpret_cast<PFN_xrVoidFunction*>(&xrCreateVulkanDeviceKHR))))
642+
{
643+
LOG_ERROR_AND_THROW("Failed to get xrCreateVulkanDeviceKHR function");
644+
}
645+
VERIFY_EXPR(xrCreateVulkanDeviceKHR != nullptr);
646+
647+
XrVulkanDeviceCreateInfoKHR VulkanDeviceCI{XR_TYPE_VULKAN_DEVICE_CREATE_INFO_KHR};
648+
static_assert(sizeof(VulkanDeviceCI.systemId) == sizeof(XRAttribs.SystemId), "systemId size mismatch");
649+
memcpy(&VulkanDeviceCI.systemId, &XRAttribs.SystemId, sizeof(VulkanDeviceCI.systemId));
650+
VulkanDeviceCI.createFlags = 0;
651+
VulkanDeviceCI.pfnGetInstanceProcAddr = vkGetInstanceProcAddr;
652+
VulkanDeviceCI.vulkanPhysicalDevice = PhysicalDevice;
653+
VulkanDeviceCI.vulkanCreateInfo = pCreateInfo;
654+
VulkanDeviceCI.vulkanAllocator = pAllocator;
655+
656+
VkResult vkRes = VK_ERROR_UNKNOWN;
657+
if (XR_FAILED(xrCreateVulkanDeviceKHR(xrInstance, &VulkanDeviceCI, pDevice, &vkRes)))
658+
{
659+
LOG_ERROR_AND_THROW("Failed to create Vulkan device for OpenXR");
660+
}
661+
return vkRes;
662+
}
663+
#endif
664+
623665
void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& EngineCI,
624666
IRenderDevice** ppDevice,
625667
IDeviceContext** ppContexts)
@@ -664,10 +706,34 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& En
664706
InstanceCI.IgnoreDebugMessageCount = EngineCI.IgnoreDebugMessageCount;
665707
InstanceCI.ppIgnoreDebugMessageNames = EngineCI.ppIgnoreDebugMessageNames;
666708

709+
#if DILIGENT_USE_OPENXR
710+
if (EngineCI.pXRAttribs != nullptr && EngineCI.pXRAttribs->Instance != 0)
711+
{
712+
InstanceCI.XR.Instance = EngineCI.pXRAttribs->Instance;
713+
InstanceCI.XR.SystemId = EngineCI.pXRAttribs->SystemId;
714+
InstanceCI.XR.GetInstanceProcAddr = EngineCI.pXRAttribs->GetInstanceProcAddr;
715+
}
716+
#endif
717+
667718
auto Instance = VulkanUtilities::VulkanInstance::Create(InstanceCI);
668719

669-
auto vkDevice = Instance->SelectPhysicalDevice(EngineCI.AdapterId);
670-
auto PhysicalDevice = VulkanUtilities::VulkanPhysicalDevice::Create({*Instance, vkDevice, /*LogExtensions = */ true});
720+
VkPhysicalDevice vkPhysDevice = VK_NULL_HANDLE;
721+
#if DILIGENT_USE_OPENXR
722+
if (InstanceCI.XR.Instance != 0)
723+
{
724+
if (EngineCI.AdapterId != DEFAULT_ADAPTER_ID)
725+
{
726+
LOG_WARNING_MESSAGE("AdapterId is ignored when OpenXR is used as the physical device is selected by OpenXR runtime");
727+
}
728+
vkPhysDevice = Instance->SelectPhysicalDeviceForOpenXR(InstanceCI.XR);
729+
}
730+
else
731+
#endif
732+
{
733+
vkPhysDevice = Instance->SelectPhysicalDevice(EngineCI.AdapterId);
734+
}
735+
736+
auto PhysicalDevice = VulkanUtilities::VulkanPhysicalDevice::Create({*Instance, vkPhysDevice, /*LogExtensions = */ true});
671737

672738
std::vector<const char*> DeviceExtensions;
673739
if (Instance->IsExtensionEnabled(VK_KHR_SURFACE_EXTENSION_NAME))
@@ -1199,8 +1265,28 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& En
11991265
vkDeviceCreateInfo.ppEnabledExtensionNames = DeviceExtensions.empty() ? nullptr : DeviceExtensions.data();
12001266
vkDeviceCreateInfo.enabledExtensionCount = static_cast<uint32_t>(DeviceExtensions.size());
12011267

1202-
auto vkAllocator = Instance->GetVkAllocator();
1203-
auto LogicalDevice = VulkanUtilities::VulkanLogicalDevice::Create(*PhysicalDevice, vkDeviceCreateInfo, EnabledExtFeats, vkAllocator);
1268+
VkAllocationCallbacks* vkAllocator = Instance->GetVkAllocator();
1269+
VkDevice vkDevice = VK_NULL_HANDLE;
1270+
VkResult vkRes = VK_ERROR_UNKNOWN;
1271+
#if DILIGENT_USE_OPENXR
1272+
if (InstanceCI.XR.Instance != 0)
1273+
{
1274+
vkRes = CreateVulkanDeviceForOpenXR(*EngineCI.pXRAttribs, PhysicalDevice->GetVkDeviceHandle(), &vkDeviceCreateInfo, vkAllocator, &vkDevice);
1275+
}
1276+
else
1277+
#endif
1278+
{
1279+
vkRes = vkCreateDevice(PhysicalDevice->GetVkDeviceHandle(), &vkDeviceCreateInfo, vkAllocator, &vkDevice);
1280+
}
1281+
CHECK_VK_ERROR_AND_THROW(vkRes, "Failed to create logical device");
1282+
1283+
auto LogicalDevice = VulkanUtilities::VulkanLogicalDevice::Create({
1284+
*PhysicalDevice,
1285+
vkDevice,
1286+
*vkDeviceCreateInfo.pEnabledFeatures,
1287+
EnabledExtFeats,
1288+
vkAllocator,
1289+
});
12041290

12051291
auto& RawMemAllocator = GetRawAllocator();
12061292

0 commit comments

Comments
 (0)