Prechádzať zdrojové kódy

Fixed OpenXRVk compilation and using Vulkan Function Loader from Atom (#9)

Removed duplicated function glad loader code and using Atom_RHI_Vulkan.Glad.Static instead.

Fixed compilation issues after glad vulkan header was updated to use multi-context in Vulkan gem (https://github.com/o3de/o3de/pull/10118)

Built with latest O3DE using AtomSampleViewer project (openxr branch). RHI VR Sample works with Quest 2 via link cable.

Fixes https://github.com/o3de/o3de-extras/issues/7 

Signed-off-by: moraaar <[email protected]>
moraaar 3 rokov pred
rodič
commit
0caaf9add2

+ 1 - 1
Gems/OpenXRVk/Code/CMakeLists.txt

@@ -56,9 +56,9 @@ ly_add_target(
             AZ::AzCore
             AZ::AzFramework
             3rdParty::OpenXR
-            3rdParty::glad_vulkan
             AZ::AtomCore
             Gem::Atom_RHI_Vulkan.Reflect
+            Gem::Atom_RHI_Vulkan.Glad.Static
             Gem::XR.Static
 )
 

+ 4 - 0
Gems/OpenXRVk/Code/Include/OpenXRVk/OpenXRVkDevice.h

@@ -41,6 +41,9 @@ namespace OpenXRVk
         //! Get the native device
         VkDevice GetNativeDevice() const;
 
+        //! Get glad vulkan context.
+        const GladVulkanContext& GetContext() const;
+
         //! Reserve space for appropriate number of views 
         void InitXrViews(uint32_t numViews);
 
@@ -68,5 +71,6 @@ namespace OpenXRVk
         AZStd::vector<XrCompositionLayerProjectionView> m_projectionLayerViews;
         AZStd::vector<XrView> m_views;
         uint32_t m_viewCountOutput = 0;
+        GladVulkanContext m_context;
     };
 }

+ 0 - 38
Gems/OpenXRVk/Code/Include/OpenXRVk/OpenXRVkFunctionLoader.h

@@ -1,38 +0,0 @@
-/*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
-
-#pragma once
-
-#include <AzCore/Memory/SystemAllocator.h>
-#include <AzCore/std/smart_ptr/unique_ptr.h>
-#include <AzCore/Module/DynamicModuleHandle.h>
-
-namespace OpenXRVk
-{
-    class FunctionLoader
-    {
-    public:
-        AZ_CLASS_ALLOCATOR(FunctionLoader, AZ::SystemAllocator, 0);
-
-        static AZStd::unique_ptr<FunctionLoader> Create();
-
-        //! Load vulkan specific dlls.
-        bool Init();
-
-        //! Unload the dlls.
-        void Shutdown();
-
-        virtual ~FunctionLoader();
-    protected:
-
-        virtual bool InitInternal() = 0;
-        virtual void ShutdownInternal() = 0;
-
-        AZStd::unique_ptr<AZ::DynamicModuleHandle> m_moduleHandle;
-    };
-}

+ 0 - 32
Gems/OpenXRVk/Code/Include/OpenXRVk/OpenXRVkGladFuncLoader.h

@@ -1,32 +0,0 @@
-/*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
-
-#pragma once
-#include <OpenXRVk/OpenXRVkFunctionLoader.h>
-#include <AzCore/Memory/SystemAllocator.h>
-
-namespace OpenXRVk
-{
-    class GladFunctionLoader:
-        public FunctionLoader
-    {
-    public:
-        AZ_CLASS_ALLOCATOR(GladFunctionLoader, AZ::SystemAllocator, 0);
-
-        GladFunctionLoader() = default;
-        virtual ~GladFunctionLoader() = default;
-
-    private:
-        //////////////////////////////////////////////////////////////////////////
-        // FunctionLoader overrrides
-        //! Load the the function pointers from the vulkan dll.
-        bool InitInternal() override;
-        //! Unload appropriate data.
-        void ShutdownInternal() override;
-    };
-}

+ 9 - 2
Gems/OpenXRVk/Code/Include/OpenXRVk/OpenXRVkInstance.h

@@ -10,8 +10,8 @@
 
 #include <AzCore/std/containers/vector.h>
 #include <Atom/RHI/ValidationLayer.h>
+#include <Atom/RHI.Loader/FunctionLoader.h>
 #include <OpenXRVk_Platform.h>
-#include <OpenXRVk/OpenXRVkFunctionLoader.h>
 #include <OpenXRVk/OpenXRVkPhysicalDevice.h>
 #include <XR/XRInstance.h>
 
@@ -57,6 +57,12 @@ namespace OpenXRVk
         //! Get native VkInstance.
         VkInstance GetNativeInstance() const;
 
+        //! Get glad vulkan context.
+        GladVulkanContext& GetContext();
+
+        //! Get function loader.
+        AZ::Vulkan::FunctionLoader& GetFunctionLoader();
+
         //! Get XR environment blend mode.
         XrEnvironmentBlendMode GetEnvironmentBlendMode() const;
 
@@ -79,7 +85,8 @@ namespace OpenXRVk
         XrSystemId m_xrSystemId = XR_NULL_SYSTEM_ID;
         XR::RawStringList m_requiredLayers;
         XR::RawStringList m_requiredExtensions;
-        AZStd::unique_ptr<FunctionLoader> m_functionLoader;
+        GladVulkanContext m_context;
+        AZStd::unique_ptr<AZ::Vulkan::FunctionLoader> m_functionLoader;
         AZStd::vector<VkPhysicalDevice> m_supportedXRDevices;
         AZ::u32 m_physicalDeviceActiveIndex = 0;
     };

+ 1 - 1
Gems/OpenXRVk/Code/Include/OpenXRVk/Platform/Android/OpenXRVk_Android.h

@@ -12,7 +12,7 @@
 #include <AzCore/std/algorithm.h>
 #include <limits.h>
 
-#include <glad/vulkan.h>
+#include <vulkan/vulkan.h>
 
 #include <jni.h>
 

+ 1 - 4
Gems/OpenXRVk/Code/Include/OpenXRVk/Platform/Linux/OpenXRVk_Linux.h

@@ -12,10 +12,7 @@
 #include <AzCore/std/algorithm.h>
 #include <limits.h>
 
-#if defined(PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB)
-    #include <xcb/xcb.h> // needed for glad vulkan
-#endif
-#include <glad/vulkan.h>
+#include <vulkan/vulkan.h>
 
  // Tell OpenXR what platform code we'll be using
 #if defined(PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB)

+ 1 - 1
Gems/OpenXRVk/Code/Include/OpenXRVk/Platform/Windows/OpenXRVk_Windows.h

@@ -14,7 +14,7 @@
 
 #include <Unknwn.h>
 
-#include <glad/vulkan.h>
+#include <vulkan/vulkan.h>
 
  // Tell OpenXR what platform code we'll be using
 #define XR_USE_PLATFORM_WIN32

+ 27 - 5
Gems/OpenXRVk/Code/Source/OpenXRVkDevice.cpp

@@ -28,7 +28,7 @@ namespace OpenXRVk
         Instance* xrVkInstance = static_cast<Instance*>(GetDescriptor().m_instance.get());
         XrVulkanDeviceCreateInfoKHR xrDeviceCreateInfo{ XR_TYPE_VULKAN_DEVICE_CREATE_INFO_KHR };
         xrDeviceCreateInfo.systemId = xrVkInstance->GetXRSystemId();
-        xrDeviceCreateInfo.pfnGetInstanceProcAddr = vkGetInstanceProcAddr;
+        xrDeviceCreateInfo.pfnGetInstanceProcAddr = xrVkInstance->GetContext().GetInstanceProcAddr;
         xrDeviceCreateInfo.vulkanCreateInfo = xrDeviceDescriptor->m_inputData.m_deviceCreateInfo;
         xrDeviceCreateInfo.vulkanPhysicalDevice = xrVkInstance->GetActivePhysicalDevice();
         xrDeviceCreateInfo.vulkanAllocator = nullptr;
@@ -44,7 +44,7 @@ namespace OpenXRVk
 
         AZStd::vector<char> deviceExtensionNames(deviceExtensionNamesSize);
         result = pfnGetVulkanDeviceExtensionsKHR(
-	        xrVkInstance->GetXRInstance(), xrDeviceCreateInfo.systemId, deviceExtensionNamesSize, &deviceExtensionNamesSize, &deviceExtensionNames[0]);
+            xrVkInstance->GetXRInstance(), xrDeviceCreateInfo.systemId, deviceExtensionNamesSize, &deviceExtensionNamesSize, &deviceExtensionNames[0]);
         ASSERT_IF_UNSUCCESSFUL(result);
 
         AZStd::vector<const char*> extensions = ParseExtensionString(&deviceExtensionNames[0]);
@@ -57,7 +57,7 @@ namespace OpenXRVk
         memcpy(&features, xrDeviceCreateInfo.vulkanCreateInfo->pEnabledFeatures, sizeof(features));
 
         VkPhysicalDeviceFeatures availableFeatures{};
-        vkGetPhysicalDeviceFeatures(xrVkInstance->GetActivePhysicalDevice(), &availableFeatures);
+        xrVkInstance->GetContext().GetPhysicalDeviceFeatures(xrVkInstance->GetActivePhysicalDevice(), &availableFeatures);
         if (availableFeatures.shaderStorageImageMultisample == VK_TRUE)
         {
             // Setting this quiets down a validation error triggered by the Oculus runtime
@@ -75,9 +75,26 @@ namespace OpenXRVk
         VkResult vulkanResult = pfnCreateDevice(xrDeviceCreateInfo.vulkanPhysicalDevice, &deviceInfo, xrDeviceCreateInfo.vulkanAllocator, &m_xrVkDevice);
         if (vulkanResult != VK_SUCCESS)
         {
+            ShutdownInternal();
+            AZ_Error("OpenXRVk", false, "Failed to create the device.");
             return AZ::RHI::ResultCode::Fail;
         }
-		
+
+        // Now that we have created the device, load the function pointers for it.
+        // NOTE: Passing the xr physical device to LoadProcAddresses causes a crash in glad vulkan
+        //       inside 'glad_vk_find_core_vulkan' function when calling 'context->GetPhysicalDeviceProperties'.
+        //       It's OK to pass VK_NULL_HANDLE at the moment, which means glad vulkan will use only device and instance
+        //       to check for vulkan extensions.
+        if (!xrVkInstance->GetFunctionLoader().LoadProcAddresses(
+            &m_context, xrVkInstance->GetNativeInstance(), VK_NULL_HANDLE/*xrVkInstance->GetActivePhysicalDevice()*/, m_xrVkDevice))
+        {
+            // Something went wrong loading function pointers, use the glad context from the instance to shut down the device.
+            m_context = xrVkInstance->GetContext();
+            ShutdownInternal();
+            AZ_Error("OpenXRVk", false, "Failed to initialize function loader for the device.");
+            return AZ::RHI::ResultCode::Fail;
+        }
+
         //Populate the output data of the descriptor
         xrDeviceDescriptor->m_outputData.m_xrVkDevice = m_xrVkDevice;
 
@@ -221,6 +238,11 @@ namespace OpenXRVk
         return m_xrVkDevice;
     }
 
+    const GladVulkanContext& Device::GetContext() const
+    {
+        return m_context;
+    }
+
     AZ::RPI::FovData Device::GetViewFov(AZ::u32 viewIndex) const
     {
         AZ::RPI::FovData viewFov;
@@ -264,7 +286,7 @@ namespace OpenXRVk
         m_xrLayers.clear();
         if (m_xrVkDevice != VK_NULL_HANDLE)
         {
-            vkDestroyDevice(m_xrVkDevice, nullptr);
+            m_context.DestroyDevice(m_xrVkDevice, nullptr);
             m_xrVkDevice = VK_NULL_HANDLE;
         }
     }

+ 0 - 59
Gems/OpenXRVk/Code/Source/OpenXRVkFunctionLoader.cpp

@@ -1,59 +0,0 @@
-/*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
-
-#include <AzCore/std/containers/vector.h>
-#include <OpenXRVk/OpenXRVkFunctionLoader.h>
-#include <OpenXRVk_Platform.h>
-#include <OpenXRVk_Traits_Platform.h>
-
-namespace OpenXRVk
-{
-    FunctionLoader::~FunctionLoader()
-    {
-        AZ_Assert(!m_moduleHandle, "Shutdown was not called before destroying this FunctionLoader");
-    }
-
-    bool FunctionLoader::Init()
-    {
-        const AZStd::vector<const char*> libs = {
-            VULKAN_DLL,
-            VULKAN_1_DLL
-        };
-
-        for (const char* libName : libs)
-        {
-            m_moduleHandle = AZ::DynamicModuleHandle::Create(libName);
-            if (m_moduleHandle->Load(false))
-            {
-                break;
-            }
-            else
-            {
-                m_moduleHandle = nullptr;
-            }
-        }
-
-        if (!m_moduleHandle)
-        {
-            AZ_Warning("Vulkan", false, "Could not find Vulkan library.");
-            return false;
-        }
-            
-        return InitInternal();
-    }
-
-    void FunctionLoader::Shutdown()
-    {
-        ShutdownInternal();
-        if (m_moduleHandle)
-        {
-            m_moduleHandle->Unload();
-        }
-        m_moduleHandle = nullptr;
-    }
-}

+ 0 - 44
Gems/OpenXRVk/Code/Source/OpenXRVkGladFuncLoader.cpp

@@ -1,44 +0,0 @@
-/*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
-
-#include <AzCore/PlatformIncl.h>
-#define GLAD_VULKAN_IMPLEMENTATION
-#include <OpenXRVk_Platform.h>
-
-#include <OpenXRVk/OpenXRVkGladFuncLoader.h>
-#include <AzCore/Module/DynamicModuleHandle.h>
-
-namespace
-{
-    GLADapiproc LoadFunctionFromLibrary(void* userPtr, const char *name)
-    {
-        AZ::DynamicModuleHandle* moduleHandle = reinterpret_cast<AZ::DynamicModuleHandle*>(userPtr);
-        AZ_Assert(moduleHandle, "Invalid module handle");
-        return moduleHandle->GetFunction<GLADapiproc>(name);
-    }
-}
-
-namespace OpenXRVk
-{
-    AZStd::unique_ptr<FunctionLoader> FunctionLoader::Create()
-    {
-        return AZStd::make_unique<GladFunctionLoader>();
-    }
-
-    bool GladFunctionLoader::InitInternal()
-    {
-        // Since we don't have the vulkan instance or device yet, we just load the function pointers from the loader
-        // using dlsym or something similar.
-        return gladLoadVulkanUserPtr(VK_NULL_HANDLE, &LoadFunctionFromLibrary, m_moduleHandle.get()) != 0;
-    }
-
-    void GladFunctionLoader::ShutdownInternal()
-    {
-        gladLoaderUnloadVulkan();
-    }
-}

+ 38 - 11
Gems/OpenXRVk/Code/Source/OpenXRVkInstance.cpp

@@ -277,17 +277,19 @@ namespace OpenXRVk
 
     AZ::RHI::ResultCode Instance::InitNativeInstance(AZ::RHI::XRInstanceDescriptor* instanceDescriptor)
     {
-        m_functionLoader = FunctionLoader::Create();
-        if (!m_functionLoader->Init())
+        m_functionLoader = AZ::Vulkan::FunctionLoader::Create();
+        if (!m_functionLoader->Init() ||
+            !m_functionLoader->LoadProcAddresses(&m_context, VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE))
         {
-            AZ_Warning("Vulkan", false, "OpenXRVk Could not initialized function loader.");
+            m_functionLoader.reset();
+            AZ_Error("OpenXRVk", false, "Could not initialize function loader.");
             return AZ::RHI::ResultCode::Fail;
         }
 
         AZ::Vulkan::XRInstanceDescriptor* xrInstanceDescriptor = static_cast<AZ::Vulkan::XRInstanceDescriptor*>(instanceDescriptor);
         XrVulkanInstanceCreateInfoKHR createInfo{ XR_TYPE_VULKAN_INSTANCE_CREATE_INFO_KHR };
         createInfo.systemId = m_xrSystemId;
-        createInfo.pfnGetInstanceProcAddr = vkGetInstanceProcAddr;
+        createInfo.pfnGetInstanceProcAddr = m_context.GetInstanceProcAddr;
         createInfo.vulkanCreateInfo = xrInstanceDescriptor->m_inputData.m_createInfo;
         createInfo.vulkanAllocator = nullptr;
 
@@ -302,7 +304,7 @@ namespace OpenXRVk
         AZStd::vector<char> extensionNames(extensionNamesSize);
         result = pfnGetVulkanInstanceExtensionsKHR(m_xrInstance, m_xrSystemId, extensionNamesSize, &extensionNamesSize, &extensionNames[0]);
         ASSERT_IF_UNSUCCESSFUL(result);
-		
+
         AZStd::vector<const char*> extensions = ParseExtensionString(&extensionNames[0]);
         for (uint32_t i = 0; i < createInfo.vulkanCreateInfo->enabledExtensionCount; ++i)
         {
@@ -318,19 +320,34 @@ namespace OpenXRVk
         VkResult vkResult = pfnCreateInstance(&instInfo, nullptr, &m_xrVkInstance);
         if (vkResult != VK_SUCCESS)
         {
+            ShutdownInternal();
+            AZ_Error("OpenXRVk", false, "Failed to create the instance.");
             return AZ::RHI::ResultCode::Fail;
         }
-		
+
+        // Now that we have created the instance, load the function pointers for it.
+        if (!m_functionLoader->LoadProcAddresses(&m_context, m_xrVkInstance, VK_NULL_HANDLE, VK_NULL_HANDLE))
+        {
+            ShutdownInternal();
+            AZ_Warning("OpenXRVk", false, "Failed to initialize function loader for the instance.");
+            return AZ::RHI::ResultCode::Fail;
+        }
+
         //Populate the instance descriptor with the correct VkInstance
         xrInstanceDescriptor->m_outputData.m_xrVkInstance = m_xrVkInstance;
 
         //Get the list of Physical devices
         m_supportedXRDevices = PhysicalDevice::EnumerateDeviceList(m_xrSystemId, m_xrInstance, m_xrVkInstance);
-        if (m_supportedXRDevices.size() > 1)
+        if (m_supportedXRDevices.empty())
         {
-            //Just use the first device at the moment.
-            m_physicalDeviceActiveIndex = 0;
+            ShutdownInternal();
+            AZ_Error("OpenXRVk", false, "No physical devices found.");
+            return AZ::RHI::ResultCode::Fail;
         }
+
+        //Just use the first device at the moment.
+        m_physicalDeviceActiveIndex = 0;
+
         return AZ::RHI::ResultCode::Success;
     }
 
@@ -340,8 +357,8 @@ namespace OpenXRVk
         {
             m_supportedXRDevices.clear();
 
-            vkDestroyInstance(m_xrVkInstance, nullptr);
-            m_functionLoader = VK_NULL_HANDLE;
+            m_context.DestroyInstance(m_xrVkInstance, nullptr);
+            m_xrVkInstance = VK_NULL_HANDLE;
         }
 
         if (m_functionLoader)
@@ -388,6 +405,16 @@ namespace OpenXRVk
         return m_xrVkInstance;
     }
 
+    GladVulkanContext& Instance::GetContext()
+    {
+        return m_context;
+    }
+
+    AZ::Vulkan::FunctionLoader& Instance::GetFunctionLoader()
+    {
+        return *m_functionLoader;
+    }
+
     XrEnvironmentBlendMode Instance::GetEnvironmentBlendMode() const
     {
         return m_environmentBlendMode;

+ 0 - 3
Gems/OpenXRVk/Code/Source/Platform/Android/OpenXRVk_Traits_Android.h

@@ -6,6 +6,3 @@
  *
  */
 #pragma once
-
-#define VULKAN_DLL "libvulkan.so"
-#define VULKAN_1_DLL "libvulkan.so.1"

+ 0 - 3
Gems/OpenXRVk/Code/Source/Platform/Linux/OpenXRVk_Traits_Linux.h

@@ -6,6 +6,3 @@
  *
  */
 #pragma once
-
-#define VULKAN_DLL "libvulkan.so"
-#define VULKAN_1_DLL "libvulkan.so.1"

+ 0 - 3
Gems/OpenXRVk/Code/Source/Platform/Windows/OpenXRVk_Traits_Windows.h

@@ -6,6 +6,3 @@
  *
  */
 #pragma once
-
-#define VULKAN_DLL "vulkan.dll"
-#define VULKAN_1_DLL "vulkan-1.dll"

+ 0 - 11
Gems/OpenXRVk/Code/openxrvk_private_common_files.cmake

@@ -16,8 +16,6 @@ set(FILES
     Include/OpenXRVk/OpenXRVkSwapChain.h
     Include/OpenXRVk/OpenXRVkSystemComponent.h
     Include/OpenXRVk/OpenXRVkUtils.h
-    Include/OpenXRVk/OpenXRVkFunctionLoader.h
-    Include/OpenXRVk/OpenXRVkGladFuncLoader.h
     Source/OpenXRVkDevice.cpp
     Source/OpenXRVkInput.cpp
     Source/OpenXRVkInstance.cpp
@@ -27,13 +25,4 @@ set(FILES
     Source/OpenXRVkSwapChain.cpp
     Source/OpenXRVkSystemComponent.cpp
     Source/OpenXRVkUtils.cpp
-    Source/OpenXRVkFunctionLoader.cpp
-    Source/OpenXRVkGladFuncLoader.cpp
 )
-
-set(SKIP_UNITY_BUILD_INCLUSION_FILES
-    # The following file defines GLAD_VULKAN_IMPLEMENTATION before including vulkan.h changing
-    # the behavior inside vulkan.h. Other files also includes vulkan.h so this file cannot
-    # be added to unity, other files could end up including vulkan.h and making this one fail.
-    Source/OpenXRVkGladFuncLoader.cpp
-)