Skip to content

Commit

Permalink
D3D11: enabled OpenXR support
Browse files Browse the repository at this point in the history
  • Loading branch information
TheMostDiligent committed Dec 8, 2024
1 parent ed41511 commit b3703f9
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 32 deletions.
4 changes: 4 additions & 0 deletions Graphics/GraphicsEngineD3D11/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ PRIVATE
PUBLIC
Diligent-GraphicsEngineD3D11Interface
)
if(DILIGENT_USE_OPENXR)
target_link_libraries(Diligent-GraphicsEngineD3D11-static PRIVATE OpenXR::headers)
target_compile_definitions(Diligent-GraphicsEngineD3D11-static PRIVATE DILIGENT_USE_OPENXR=1)
endif()

target_link_libraries(Diligent-GraphicsEngineD3D11-shared
PRIVATE
Expand Down
66 changes: 61 additions & 5 deletions Graphics/GraphicsEngineD3D11/src/EngineFactoryD3D11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@
#include "EngineFactoryD3DBase.hpp"
#include "DearchiverD3D11Impl.hpp"

#if DILIGENT_USE_OPENXR
# define XR_USE_GRAPHICS_API_D3D11
# include <openxr/openxr_platform.h>
#endif

namespace Diligent
{

Expand All @@ -64,6 +69,41 @@ bool CheckAdapterD3D11Compatibility(IDXGIAdapter1* pDXGIAdapter, D3D_FEATURE_LEV
return SUCCEEDED(hr);
}

#if DILIGENT_USE_OPENXR
void GetOpenXRAdapterRequirements(const OpenXRAttribs& XR, LUID& AdapterLUID, D3D_FEATURE_LEVEL& d3dFeatureLevel) noexcept(false)
{
if (XR.Instance == 0)
return;

if (XR.GetInstanceProcAddr == nullptr)
LOG_ERROR_AND_THROW("xrGetInstanceProcAddr must not be null");

XrInstance xrInstance = XR_NULL_HANDLE;
static_assert(sizeof(xrInstance) == sizeof(XR.Instance), "XrInstance size mismatch");
memcpy(&xrInstance, &XR.Instance, sizeof(xrInstance));

XrSystemId xrSystemId = XR_NULL_SYSTEM_ID;
static_assert(sizeof(xrSystemId) == sizeof(XR.SystemId), "XrSystemId size mismatch");
memcpy(&xrSystemId, &XR.SystemId, sizeof(XrSystemId));

PFN_xrGetInstanceProcAddr xrGetInstanceProcAddr = reinterpret_cast<PFN_xrGetInstanceProcAddr>(XR.GetInstanceProcAddr);
PFN_xrGetD3D11GraphicsRequirementsKHR xrGetD3D11GraphicsRequirementsKHR = nullptr;
if (XR_FAILED(xrGetInstanceProcAddr(xrInstance, "xrGetD3D11GraphicsRequirementsKHR", reinterpret_cast<PFN_xrVoidFunction*>(&xrGetD3D11GraphicsRequirementsKHR))))
{
LOG_ERROR_AND_THROW("Failed to get xrGetD3D11GraphicsRequirementsKHR. Make sure that XR_KHR_D3D11_enable extension is enabled.");
}

XrGraphicsRequirementsD3D11KHR xrGraphicsRequirementsD3D11KHR{XR_TYPE_GRAPHICS_REQUIREMENTS_D3D11_KHR};
if (XR_FAILED(xrGetD3D11GraphicsRequirementsKHR(xrInstance, xrSystemId, &xrGraphicsRequirementsD3D11KHR)))
{
LOG_ERROR_AND_THROW("Failed to get D3D11 graphics requirements");
}

AdapterLUID = xrGraphicsRequirementsD3D11KHR.adapterLuid;
d3dFeatureLevel = (std::max)(d3dFeatureLevel, xrGraphicsRequirementsD3D11KHR.minFeatureLevel);
}
#endif

/// Engine factory for D3D11 implementation
class EngineFactoryD3D11Impl : public EngineFactoryD3DBase<IEngineFactoryD3D11, RENDER_DEVICE_TYPE_D3D11>
{
Expand Down Expand Up @@ -208,15 +248,31 @@ void EngineFactoryD3D11Impl::CreateDeviceAndContextsD3D11(const EngineD3D11Creat
}
#endif

LUID AdapterLUID{};
D3D_FEATURE_LEVEL d3dFeatureLevel = GetD3DFeatureLevel((std::max)(EngineCI.GraphicsAPIVersion, Version{10, 0}));
Uint32 AdapterId = EngineCI.AdapterId;
#if DILIGENT_USE_OPENXR
if (EngineCI.pXRAttribs != nullptr && EngineCI.pXRAttribs->Instance != 0)
{
GetOpenXRAdapterRequirements(*EngineCI.pXRAttribs, AdapterLUID, d3dFeatureLevel);
if (AdapterId != DEFAULT_ADAPTER_ID)
{
LOG_WARNING_MESSAGE("AdapterId is ignored when OpenXR is used as the suitable adapter is selected by OpenXR runtime");
}
// There should be only one adapter
AdapterId = 0;
}
#endif

CComPtr<IDXGIAdapter1> SpecificAdapter;
if (EngineCI.AdapterId != DEFAULT_ADAPTER_ID)
if (AdapterId != DEFAULT_ADAPTER_ID)
{
auto Adapters = FindCompatibleAdapters(EngineCI.GraphicsAPIVersion);
if (EngineCI.AdapterId < Adapters.size())
SpecificAdapter = Adapters[EngineCI.AdapterId];
auto Adapters = FindCompatibleAdapters(d3dFeatureLevel, AdapterLUID);
if (AdapterId < Adapters.size())
SpecificAdapter = Adapters[AdapterId];
else
{
LOG_ERROR_AND_THROW(EngineCI.AdapterId, " is not a valid hardware adapter id. Total number of compatible adapters available on this system: ", Adapters.size());
LOG_ERROR_AND_THROW(AdapterId, " is not a valid hardware adapter id. Total number of compatible adapters available on this system: ", Adapters.size());
}
}

Expand Down
20 changes: 17 additions & 3 deletions Graphics/GraphicsEngineD3DBase/include/EngineFactoryD3DBase.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,15 @@ namespace Diligent
bool CheckAdapterD3D11Compatibility(IDXGIAdapter1* pDXGIAdapter, D3D_FEATURE_LEVEL FeatureLevel);
bool CheckAdapterD3D12Compatibility(IDXGIAdapter1* pDXGIAdapter, D3D_FEATURE_LEVEL FeatureLevel);

inline bool operator==(const LUID& Lhs, const LUID& Rhs)
{
return Lhs.HighPart == Rhs.HighPart && Lhs.LowPart == Rhs.LowPart;
}
inline bool operator!=(const LUID& Lhs, const LUID& Rhs)
{
return !(Lhs == Rhs);
}

template <typename BaseInterface, RENDER_DEVICE_TYPE DevType>
class EngineFactoryD3DBase : public EngineFactoryBase<BaseInterface>
{
Expand Down Expand Up @@ -142,7 +151,7 @@ class EngineFactoryD3DBase : public EngineFactoryBase<BaseInterface>
}


std::vector<CComPtr<IDXGIAdapter1>> FindCompatibleAdapters(Version MinVersion) const
std::vector<CComPtr<IDXGIAdapter1>> FindCompatibleAdapters(D3D_FEATURE_LEVEL d3dFeatureLevel, LUID AdapterLUID = {}) const
{
std::vector<CComPtr<IDXGIAdapter1>> DXGIAdapters;

Expand All @@ -154,12 +163,13 @@ class EngineFactoryD3DBase : public EngineFactoryBase<BaseInterface>
}

CComPtr<IDXGIAdapter1> pDXIAdapter;

const auto d3dFeatureLevel = GetD3DFeatureLevel(MinVersion);
for (UINT adapter = 0; pFactory->EnumAdapters1(adapter, &pDXIAdapter) != DXGI_ERROR_NOT_FOUND; ++adapter, pDXIAdapter.Release())
{
DXGI_ADAPTER_DESC1 AdapterDesc;
pDXIAdapter->GetDesc1(&AdapterDesc);
if (AdapterLUID != LUID{} && AdapterDesc.AdapterLuid != AdapterLUID)
continue;

bool IsCompatibleAdapter = CheckAdapterCompatibility<DevType>(pDXIAdapter, d3dFeatureLevel);
if (IsCompatibleAdapter)
{
Expand All @@ -170,6 +180,10 @@ class EngineFactoryD3DBase : public EngineFactoryBase<BaseInterface>
return DXGIAdapters;
}

std::vector<CComPtr<IDXGIAdapter1>> FindCompatibleAdapters(Version MinVersion) const
{
return FindCompatibleAdapters(GetD3DFeatureLevel(MinVersion));
}

virtual GraphicsAdapterInfo GetGraphicsAdapterInfo(void* pd3Device,
IDXGIAdapter1* pDXIAdapter) const
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,37 +176,39 @@ static uint32_t GetRequiredOpenXRVulkanVersion(uint32_t VulkanV
PFN_xrGetInstanceProcAddr xrGetInstanceProcAddr) noexcept(false)
{
PFN_xrGetVulkanGraphicsRequirements2KHR xrGetVulkanGraphicsRequirements2KHR = nullptr;
if (XR_SUCCEEDED(xrGetInstanceProcAddr(xrInstance, "xrGetVulkanGraphicsRequirements2KHR", reinterpret_cast<PFN_xrVoidFunction*>(&xrGetVulkanGraphicsRequirements2KHR))))
if (XR_FAILED(xrGetInstanceProcAddr(xrInstance, "xrGetVulkanGraphicsRequirements2KHR", reinterpret_cast<PFN_xrVoidFunction*>(&xrGetVulkanGraphicsRequirements2KHR))))
{
VERIFY_EXPR(xrGetVulkanGraphicsRequirements2KHR != nullptr);
LOG_ERROR_AND_THROW("Failed to get xrGetVulkanGraphicsRequirements2KHR function. Make sure that XR_KHR_vulkan_enable2 extension is enabled.");
}

XrGraphicsRequirementsVulkan2KHR xrVulkan2Req{XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN2_KHR};
if (XR_SUCCEEDED(xrGetVulkanGraphicsRequirements2KHR(xrInstance, xrSystemId, &xrVulkan2Req)))
{
auto XrVersionToVkVersion = [](XrVersion XrVersion) {
return VK_MAKE_API_VERSION(0, XR_VERSION_MAJOR(XrVersion), XR_VERSION_MINOR(XrVersion), 0);
};
VERIFY_EXPR(xrGetVulkanGraphicsRequirements2KHR != nullptr);

uint32_t MinVkVersion = XrVersionToVkVersion(xrVulkan2Req.minApiVersionSupported);
if (VulkanVersion < MinVkVersion)
{
LOG_ERROR_AND_THROW("OpenXR requires Vulkan version ", VK_API_VERSION_MAJOR(MinVkVersion), '.', VK_API_VERSION_MINOR(MinVkVersion),
", but this device only supports Vulkan ", VK_API_VERSION_MAJOR(VulkanVersion), '.', VK_API_VERSION_MINOR(VulkanVersion));
}
uint32_t MaxVkVersion = VK_MAKE_API_VERSION(0, XR_VERSION_MAJOR(xrVulkan2Req.maxApiVersionSupported), XR_VERSION_MINOR(xrVulkan2Req.maxApiVersionSupported), 0);
if (MaxVkVersion < VulkanVersion)
{
LOG_INFO_MESSAGE("This device supports Vulkan ", VK_API_VERSION_MAJOR(VulkanVersion), '.', VK_API_VERSION_MINOR(VulkanVersion),
", but OpenXR was only tested with Vulkan up to ", VK_API_VERSION_MAJOR(MaxVkVersion), '.', VK_API_VERSION_MINOR(MaxVkVersion),
". Proceeding with Vulkan ", VK_API_VERSION_MAJOR(MaxVkVersion), '.', VK_API_VERSION_MINOR(MaxVkVersion), '.');
VulkanVersion = MaxVkVersion;
}
XrGraphicsRequirementsVulkan2KHR xrVulkan2Req{XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN2_KHR};
if (XR_SUCCEEDED(xrGetVulkanGraphicsRequirements2KHR(xrInstance, xrSystemId, &xrVulkan2Req)))
{
auto XrVersionToVkVersion = [](XrVersion XrVersion) {
return VK_MAKE_API_VERSION(0, XR_VERSION_MAJOR(XrVersion), XR_VERSION_MINOR(XrVersion), 0);
};

uint32_t MinVkVersion = XrVersionToVkVersion(xrVulkan2Req.minApiVersionSupported);
if (VulkanVersion < MinVkVersion)
{
LOG_ERROR_AND_THROW("OpenXR requires Vulkan version ", VK_API_VERSION_MAJOR(MinVkVersion), '.', VK_API_VERSION_MINOR(MinVkVersion),
", but this device only supports Vulkan ", VK_API_VERSION_MAJOR(VulkanVersion), '.', VK_API_VERSION_MINOR(VulkanVersion));
}
else
uint32_t MaxVkVersion = VK_MAKE_API_VERSION(0, XR_VERSION_MAJOR(xrVulkan2Req.maxApiVersionSupported), XR_VERSION_MINOR(xrVulkan2Req.maxApiVersionSupported), 0);
if (MaxVkVersion < VulkanVersion)
{
LOG_WARNING_MESSAGE("Failed to get Vulkan requirements from OpenXR. Proceeding without checking Vulkan instance version requirements.");
LOG_INFO_MESSAGE("This device supports Vulkan ", VK_API_VERSION_MAJOR(VulkanVersion), '.', VK_API_VERSION_MINOR(VulkanVersion),
", but OpenXR was only tested with Vulkan up to ", VK_API_VERSION_MAJOR(MaxVkVersion), '.', VK_API_VERSION_MINOR(MaxVkVersion),
". Proceeding with Vulkan ", VK_API_VERSION_MAJOR(MaxVkVersion), '.', VK_API_VERSION_MINOR(MaxVkVersion), '.');
VulkanVersion = MaxVkVersion;
}
}
else
{
LOG_WARNING_MESSAGE("Failed to get Vulkan requirements from OpenXR. Proceeding without checking Vulkan instance version requirements.");
}

return VulkanVersion;
}
Expand Down

0 comments on commit b3703f9

Please sign in to comment.