diff --git a/Graphics/GraphicsEngineD3D11/CMakeLists.txt b/Graphics/GraphicsEngineD3D11/CMakeLists.txt index adef784da..59208af50 100644 --- a/Graphics/GraphicsEngineD3D11/CMakeLists.txt +++ b/Graphics/GraphicsEngineD3D11/CMakeLists.txt @@ -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 diff --git a/Graphics/GraphicsEngineD3D11/src/EngineFactoryD3D11.cpp b/Graphics/GraphicsEngineD3D11/src/EngineFactoryD3D11.cpp index b08248c10..87730c1a2 100644 --- a/Graphics/GraphicsEngineD3D11/src/EngineFactoryD3D11.cpp +++ b/Graphics/GraphicsEngineD3D11/src/EngineFactoryD3D11.cpp @@ -44,6 +44,11 @@ #include "EngineFactoryD3DBase.hpp" #include "DearchiverD3D11Impl.hpp" +#if DILIGENT_USE_OPENXR +# define XR_USE_GRAPHICS_API_D3D11 +# include +#endif + namespace Diligent { @@ -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(XR.GetInstanceProcAddr); + PFN_xrGetD3D11GraphicsRequirementsKHR xrGetD3D11GraphicsRequirementsKHR = nullptr; + if (XR_FAILED(xrGetInstanceProcAddr(xrInstance, "xrGetD3D11GraphicsRequirementsKHR", reinterpret_cast(&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 { @@ -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 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()); } } diff --git a/Graphics/GraphicsEngineD3DBase/include/EngineFactoryD3DBase.hpp b/Graphics/GraphicsEngineD3DBase/include/EngineFactoryD3DBase.hpp index 4f9574cf3..a4cc3bf28 100644 --- a/Graphics/GraphicsEngineD3DBase/include/EngineFactoryD3DBase.hpp +++ b/Graphics/GraphicsEngineD3DBase/include/EngineFactoryD3DBase.hpp @@ -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 class EngineFactoryD3DBase : public EngineFactoryBase { @@ -142,7 +151,7 @@ class EngineFactoryD3DBase : public EngineFactoryBase } - std::vector> FindCompatibleAdapters(Version MinVersion) const + std::vector> FindCompatibleAdapters(D3D_FEATURE_LEVEL d3dFeatureLevel, LUID AdapterLUID = {}) const { std::vector> DXGIAdapters; @@ -154,12 +163,13 @@ class EngineFactoryD3DBase : public EngineFactoryBase } CComPtr 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(pDXIAdapter, d3dFeatureLevel); if (IsCompatibleAdapter) { @@ -170,6 +180,10 @@ class EngineFactoryD3DBase : public EngineFactoryBase return DXGIAdapters; } + std::vector> FindCompatibleAdapters(Version MinVersion) const + { + return FindCompatibleAdapters(GetD3DFeatureLevel(MinVersion)); + } virtual GraphicsAdapterInfo GetGraphicsAdapterInfo(void* pd3Device, IDXGIAdapter1* pDXIAdapter) const diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanInstance.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanInstance.cpp index 09da17e98..98ccb57e9 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanInstance.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanInstance.cpp @@ -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(&xrGetVulkanGraphicsRequirements2KHR)))) + if (XR_FAILED(xrGetInstanceProcAddr(xrInstance, "xrGetVulkanGraphicsRequirements2KHR", reinterpret_cast(&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; }