Files
workinf_Blender_Wasm/blender-5.2.0/intern/ghost/intern/GHOST_XrGraphicsBindingVulkan.hh
2026-08-12 04:47:48 -04:00

171 lines
6.6 KiB
C++

/* SPDX-FileCopyrightText: 2025 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup GHOST
*/
#pragma once
#include <list>
#include <vulkan/vulkan.h>
#ifdef _WIN32
# include <vulkan/vulkan_win32.h>
#endif
#define VMA_VULKAN_VERSION 1002000 // Vulkan 1.2
#if !defined(_WIN32) or defined(_M_ARM64)
/* Silence compilation warning on non-windows x64 systems. */
# define VMA_EXTERNAL_MEMORY_WIN32 0
#endif
#include "vk_mem_alloc.h"
#include "GHOST_ContextVK.hh"
#include "GHOST_IXrGraphicsBinding.hh"
#include "GHOST_Types.hh"
/**
* \brief Graphics binding between OpenXR and Vulkan
*
* OpenXR and Blender can have different requirements for a Vulkan device to be used.
* Some platforms require extensions that Blender didn't enable and other want to use
* a specific device.
*
* Depending on the enabled extensions and device selection process one of the next three
* behaviors can be done.
*
* \note See #152482 for the initial design.
*
* **Reusing Blender Vulkan Instance**
*
* Blender tries to reuse the already created vulkan instance of GHOST_ContextVK. This is only
* possible when:
*
* - XR_KHR_vulkan_enable is supported by the Xr platform
* - xrGetVulkanGraphicsDeviceKHR returns the same device
* - extensions returned by xrGetVulkanInstanceExtensionsKHR are all enabled by GHOST_ContextVK
* - extensions returned by xrGetVulkanDeviceExtensionsKHR are all enabled by GHOST_ContextVK
*
* This is typically the fastest way as almost everything can be done using Blenders' rendergraph.
*
* **Create a OpenXR Vulkan Instance**
*
* When we cannot reuse the existing instance an Xr specific Vulkan instance is being created. The
* data is transferred using external memory. Additional synchronization is needed as part of the
* pipeline cannot be done by Blender.
*
* - XR_KHR_vulkan_enable2 is supported by the Xr platform
* - Created physical device is the same as GHOST_ContextVK
*
* **Use CPU transfer**
*
* This is a fallback when devices don't match. In that case the results are transferred from the
* device that Blender is using to draw the UI to RAM and then transferred to the GPU that OpenXR
* is using.
*/
class GHOST_XrGraphicsBindingVulkan : public GHOST_IXrGraphicsBinding {
public:
GHOST_XrGraphicsBindingVulkan(GHOST_Context &ghost_ctx);
~GHOST_XrGraphicsBindingVulkan() override;
bool loadExtensionFunctions(XrInstance instance) override;
/**
* Check the version requirements to use OpenXR with the Vulkan backend.
*/
bool checkVersionRequirements(GHOST_Context &ghost_ctx,
XrInstance instance,
XrSystemId system_id,
std::string *r_requirement_info) const override;
void initFromGhostContext(GHOST_Context &ghost_ctx,
XrInstance instance,
XrSystemId system_id) override;
std::optional<int64_t> chooseSwapchainFormat(const std::vector<int64_t> &runtime_formats,
GHOST_TXrSwapchainFormat &r_format,
bool &r_is_srgb_format) const override;
std::vector<XrSwapchainImageBaseHeader *> createSwapchainImages(uint32_t image_count) override;
void submitToSwapchainBegin() override;
void submitToSwapchainImage(XrSwapchainImageBaseHeader &swapchain_image,
const GHOST_XrDrawViewInfo &draw_info) override;
void submitToSwapchainEnd() override;
bool needsUpsideDownDrawing(GHOST_Context &ghost_ctx) const override;
private:
struct {
/* XR_KHR_vulkan_enable */
PFN_xrGetVulkanInstanceExtensionsKHR xrGetVulkanInstanceExtensionsKHR = nullptr;
PFN_xrGetVulkanDeviceExtensionsKHR xrGetVulkanDeviceExtensionsKHR = nullptr;
PFN_xrGetVulkanGraphicsDeviceKHR xrGetVulkanGraphicsDeviceKHR = nullptr;
PFN_xrGetVulkanGraphicsRequirementsKHR xrGetVulkanGraphicsRequirementsKHR = nullptr;
/* XR_KHR_vulkan_enable2 */
PFN_xrGetVulkanGraphicsRequirements2KHR xrGetVulkanGraphicsRequirements2KHR = nullptr;
PFN_xrGetVulkanGraphicsDevice2KHR xrGetVulkanGraphicsDevice2KHR = nullptr;
PFN_xrCreateVulkanInstanceKHR xrCreateVulkanInstanceKHR = nullptr;
PFN_xrCreateVulkanDeviceKHR xrCreateVulkanDeviceKHR = nullptr;
} functions_;
struct {
/** Is XK_KHR_vulkan_enable extension available */
bool vulkan_enable = false;
/** Is XK_KHR_vulkan_enable2 extension available */
bool vulkan_enable2 = false;
} extensions_;
GHOST_ContextVK &ghost_ctx_;
VkInstance vk_instance_ = VK_NULL_HANDLE;
VkPhysicalDevice vk_physical_device_ = VK_NULL_HANDLE;
uint32_t graphics_queue_family_ = 0;
VkQueue vk_queue_ = VK_NULL_HANDLE;
VkDevice vk_device_ = VK_NULL_HANDLE;
VmaAllocator vma_allocator_ = VK_NULL_HANDLE;
VmaAllocation vk_buffer_allocation_ = VK_NULL_HANDLE;
VkBuffer vk_buffer_ = VK_NULL_HANDLE;
VmaAllocationInfo vk_buffer_allocation_info_ = {};
GHOST_TVulkanXRModes data_transfer_mode_ = GHOST_kVulkanXRModeCPU;
std::list<std::vector<XrSwapchainImageVulkan2KHR>> image_cache_;
VkCommandPool vk_command_pool_ = VK_NULL_HANDLE;
struct ImportedMemory {
char view_idx;
VkImage vk_image_blender;
VkImage vk_image_xr;
VkDeviceMemory vk_device_memory_xr;
};
std::vector<ImportedMemory> imported_memory_;
GHOST_TVulkanXRModes choseDataTransferMode();
void submitToSwapchainImageCpu(XrSwapchainImageVulkan2KHR &swapchain_image,
const GHOST_XrDrawViewInfo &draw_info);
void submitToSwapchainImageGpu(XrSwapchainImageVulkan2KHR &swapchain_image,
const GHOST_XrDrawViewInfo &draw_info);
void submitToSwapchainImageRenderGraph(XrSwapchainImageVulkan2KHR &swapchain_image,
const GHOST_XrDrawViewInfo &draw_info);
/**
* Single VkCommandBuffer that is used for all views/swap-chains.
*
* This can be improved by having a single command buffer per swap-chain image.
*/
VkCommandBuffer vk_command_buffer_ = VK_NULL_HANDLE;
/**
* \brief try to reuse GHOST context vulkan instance.
*
* \returns true when blenders' Vulkan instance will be reused, false when not.
*/
bool tryReuseVulkanInstance(GHOST_ContextVK &ghost_ctx, XrInstance instance, XrSystemId system);
bool areRequiredInstanceExtensionsEnabled(XrInstance instance, XrSystemId system_id) const;
bool areRequiredDeviceExtensionsEnabled(XrInstance instance, XrSystemId system_id) const;
bool isSamePhysicalDeviceSelected(XrInstance instance,
XrSystemId system_id,
const GHOST_VulkanHandles &context_handles) const;
};