8#include "evan/openxr/XrDeviceBackend.hpp"
9#include "evan/openxr/XrError.hpp"
10#include "evan/openxr/XrSwapchainContext.hpp"
11#include "evan/CheckedCast.hpp"
17 this->
getLogger().info() <<
"Initializing XrDeviceBackend";
25 _openXrOptions =
xrPlatform.getOpenXrOptions();
29 _viewConfigurationType =
36 this->createSession();
46evan::XrDeviceBackend::~XrDeviceBackend()
48 this->
getLogger().info() <<
"Destroying XrDeviceBackend";
50 this->
getLogger().info() <<
"Waiting for device to be idle before cleanup";
54 this->
getLogger().info() <<
"Destroying Vulkan device";
57 if (_session != XR_NULL_HANDLE) {
58 this->getLogger().info() <<
"Destroying OpenXR session";
59 xrDestroySession(_session);
62 this->getLogger().info() <<
"Destroying Vulkan instance";
63 vkDestroyInstance(_VkInstance,
nullptr);
65 if (_XrInstance != XR_NULL_HANDLE) {
66 this->getLogger().info() <<
"Destroying OpenXR instance";
67 xrDestroyInstance(_XrInstance);
78 this->
getLogger().info() <<
"Preprocessing frame for OpenXR session";
80 if (!_sessionRunning) {
82 <<
"Cannot preprocess frame: XR session is not running";
83 return Error::NotReady;
92 <<
"Failed to wait for OpenXR frame: " <<
result;
93 return mapXrResult(
result);
98 this->
getLogger().error() <<
"Failed to begin OpenXR frame: " <<
result;
99 return mapXrResult(
result);
101 _predictedDisplayTime =
frameState.predictedDisplayTime;
109 return Error::NotReady;
119 std::vector<XrView> &views =
xrContext._views;
121 static_cast<uint32_t>(views.size()),
136 this->
getLogger().info() <<
"Processing frame for OpenXR session";
146 <<
"Failed to release OpenXR swapchain image: " <<
result;
147 return mapXrResult(
result);
155 this->
getLogger().info() <<
"Postprocessing frame for OpenXR session";
162 layer.space = _space;
165 std::array<XrCompositionLayerBaseHeader *, 1>
layers = {
178 return mapXrResult(
result);
185 this->
getLogger().info() <<
"Finding queue families for OpenXR session";
218 <<
"Enumerating swapchain formats for OpenXR session";
226std::vector<XrViewConfigurationView>
230 <<
"Enumerating view configurations for OpenXR session";
234 _viewConfigurationType, 0,
239 <<
"No view configurations found for the OpenXR system.";
250std::vector<XrViewConfigurationType>
254 <<
"Enumerating view configuration types for OpenXR system";
261 <<
"Failed to enumerate view configuration types: " <<
result;
272 <<
"Failed to enumerate view configuration types: " <<
result;
298std::vector<std::shared_ptr<utility::event::Event>>
301 this->
getLogger().info() <<
"Polling actions for OpenXR session";
303 if (!_sessionRunning) {
305 <<
"Cannot poll actions: XR session is not running";
308 if (_actionManager) {
309 return _actionManager->pollActions(*
this);
312 <<
"Action manager is not initialized, cannot poll actions";
324 this->
getLogger().info() <<
"Creating OpenXR instance for XrDeviceBackend";
331 std::vector<const char *>
layers;
335 "xrGetVulkanGraphicsRequirements2KHR",
340 <<
"Failed to get xrGetVulkanGraphicsRequirements2KHR "
348 <<
"Failed to query Vulkan graphics requirements through OpenXR.";
352 _XrInstance,
"xrCreateVulkanInstanceKHR",
356 <<
"Failed to get xrCreateVulkanInstanceKHR function pointer.";
372 if (enableValidationLayers) {
374 <<
"Enabling validation layers for OpenXR Vulkan instance";
375 extensions = this->getRequiredInstanceExtensions();
377 this->
getLogger().info() <<
"Adding required instance extensions "
378 "for OpenXR Vulkan instance";
379 layers = this->getRequiredInstanceExtensionsAndroid();
385 createInfo.pApplicationInfo = &
appInfo;
387 createInfo.ppEnabledExtensionNames =
extensions.data();
388 createInfo.enabledLayerCount =
static_cast<uint32_t>(
layers.size());
389 createInfo.ppEnabledLayerNames =
layers.data();
404 <<
"Failed to create the Vulkan instance at the runtime's maximum "
409 <<
" (VkResult: " <<
result
410 <<
"). Retrying at the minimum supported version...";
418 <<
"Failed to create Vulkan instance through OpenXR.";
421 _vulkanApiVersion =
appInfo.apiVersion;
423 <<
"Successfully created Vulkan instance through OpenXR with API "
432 <<
"Creating Vulkan logical device for OpenXR session";
435 this->
getLogger().error() <<
"Invalid Vulkan physical device provided.";
442 _XrInstance,
"xrCreateVulkanDeviceKHR",
446 <<
"Failed to get xrCreateVulkanDeviceKHR function pointer.";
450 if (!
indices.graphicsFamily.has_value()) {
452 <<
"Failed to find required queue families for the Vulkan device.";
479 && queryMultiviewSupport(_physicalDevice, _vulkanApiVersion);
482 _multiviewSupported =
true;
484 <<
"Enabling the multiview feature on the Vulkan device.";
485 }
else if (multiviewMode() == MultiviewMode::On) {
487 <<
"EVAN_MULTIVIEW=on but the device does not support the "
488 "multiview feature (or the instance is older than Vulkan "
489 "1.1). Continuing without multiview.";
495 createInfo.queueCreateInfoCount = 1;
511 <<
"Failed to create Vulkan device through OpenXR.";
515 <<
"Successfully created Vulkan device through OpenXR";
521 <<
"Picking Vulkan physical device for OpenXR session";
524 this->
getLogger().error() <<
"Invalid Vulkan instance provided.";
535 <<
"Failed to get xrGetVulkanGraphicsDevice2KHR function pointer.";
547 <<
"Failed to get Vulkan physical device through OpenXR.";
551 <<
"Successfully obtained Vulkan physical device through OpenXR";
557 <<
"Creating visualized reference space for OpenXR session";
563 spaceCreateInfo.poseInReferenceSpace = { { 0, 0, 0, 1 }, { 0, 0, 0 } };
572 <<
"Failed to create OpenXR reference space.";
577 <<
"Successfully created visualized reference space for OpenXR session";
580std::vector<VkExtensionProperties>
584 std::vector<VkExtensionProperties>
extensions;
585 std::string
layerName =
"VK_LAYER_KHRONOS_validation";
591 <<
"Failed to enumerate OpenXR instance extension properties.";
600 <<
"Failed to enumerate OpenXR instance extension properties.";
613 this->
getLogger().info() <<
"Creating OpenXR instance for XrDeviceBackend";
616 platform.getRequiredInstanceExtensions();
624 XrInstanceCreateInfo createInfo { XR_TYPE_INSTANCE_CREATE_INFO };
625 createInfo.enabledExtensionCount =
static_cast<uint32_t
>(extensions.size());
626 createInfo.enabledExtensionNames = extensions.data();
627 createInfo.enabledApiLayerCount = 0;
628 createInfo.enabledApiLayerNames =
nullptr;
629 std::strcpy(createInfo.applicationInfo.applicationName,
"evan");
630 createInfo.applicationInfo.apiVersion = XR_CURRENT_API_VERSION;
632 const IXrPlatform &xrPlatform =
635 createInfo.next = xrPlatform.getInstanceCreateInfo();
637 XrResult result = xrCreateInstance(&createInfo, &_XrInstance);
638 if (result != XR_SUCCESS) {
640 this->getLogger().error() <<
"Failed to create OpenXR instance.";
643 this->getLogger().info() <<
"Successfully created OpenXR instance";
646void evan::XrDeviceBackend::getSystem()
648 XrSystemGetInfo systemInfo { XR_TYPE_SYSTEM_GET_INFO };
649 systemInfo.formFactor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;
651 XrResult result = xrGetSystem(_XrInstance, &systemInfo, &_systemId);
652 if (result != XR_SUCCESS) {
654 this->getLogger().error() <<
"Failed to get OpenXR system.";
659void evan::XrDeviceBackend::createSession()
661 this->getLogger().info() <<
"Creating OpenXR session for XrDeviceBackend";
663 XrSessionCreateInfo sessionCreateInfo = {};
664 XrGraphicsBindingVulkan2KHR graphicsBindingVulkan = {};
665 QueueFamilyIndices indices = findQueueFamilies();
667 if (indices.graphicsFamily == std::nullopt) {
668 this->getLogger().error() <<
"Failed to create OpenXR session: no "
669 "graphics queue family found.";
673 graphicsBindingVulkan.type = XR_TYPE_GRAPHICS_BINDING_VULKAN2_KHR;
674 graphicsBindingVulkan.instance = _VkInstance;
675 graphicsBindingVulkan.physicalDevice = _physicalDevice;
676 graphicsBindingVulkan.device = _device;
677 graphicsBindingVulkan.queueFamilyIndex = indices.graphicsFamily.value();
679 sessionCreateInfo.type = XR_TYPE_SESSION_CREATE_INFO;
680 sessionCreateInfo.next = &graphicsBindingVulkan;
681 sessionCreateInfo.systemId = _systemId;
683 if (xrCreateSession(_XrInstance, &sessionCreateInfo, &_session)
685 this->getLogger().error() <<
"Failed to create OpenXR session.";
688 this->getLogger().info() <<
"Successfully created OpenXR session";
691std::vector<const char *>
692 evan::XrDeviceBackend::getRequiredInstanceExtensions()
const
694 auto availableExtensions = getInstanceExtensions();
695 std::vector<const char *> requiredExtensions;
697 for (
const auto &ext: availableExtensions) {
698 if (std::strcmp(ext.extensionName, VK_EXT_DEBUG_UTILS_EXTENSION_NAME)
700 requiredExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
701 }
else if (std::strcmp(ext.extensionName,
702 VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME)
704 requiredExtensions.push_back(
705 VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME);
708 return requiredExtensions;
711std::vector<const char *>
712 evan::XrDeviceBackend::getRequiredInstanceExtensionsAndroid()
714 std::vector<const char *> availableLayers;
716 for (
const auto &layer: this->getAvailableLayers()) {
717 if (std::strcmp(layer.layerName,
"VK_LAYER_KHRONOS_validation") == 0) {
718 availableLayers.emplace_back(
"VK_LAYER_KHRONOS_validation");
721 return availableLayers;
Represents the context for managing the swapchain in the rendering system.
ASwapchainImage is a class that represents an image in the swapchain of the Evan engine....
static XrPath stringToPath(XrInstance instance, const std::string &pathString)
Converts a string to an OpenXR path.
Represents a software version using major, minor, and patch numbers.
void createLogicalDevice() override
Creates a logical device for the OpenXR session.
std::vector< int64_t > enumerateSwapchainFormats(uint32_t swapchainFormatCount) const override
Enumerates the available swapchain formats for the Vulkan device.
uint32_t countSwapchainFormats() const override
Count the number of available swapchain formats for the Vulkan device.
std::array< XrPath, _handCount > _handActionSubactionPath
std::vector< VkExtensionProperties > getInstanceExtensions() const
void createVisualizedSpace()
Creates a visualized space for the XR session.
std::vector< std::shared_ptr< utility::event::Event > > pollActions()
Polls input actions for the OpenXR session.
Error postprocessFrame(ASwapchainContext &swapchainContext) override
Postprocesses a frame and submits it to the OpenXR compositor.
std::vector< XrViewConfigurationType > enumerateViewConfigurationTypes() const
Enumerates the primary view configuration types supported by the OpenXR system.
void createInstance(const IPlatform &platform, const std::string &appName, Version &appVersion) override
Creates an OpenXR instance with the specified application name and version.
QueueFamilyIndices findQueueFamilies() override
Finds the queue family indices for graphics and presentation operations.
Error processFrame(VkPresentInfoKHR presentInfo, ASwapchainImage &swapchainImage) override
Processes a frame by releasing the OpenXR swapchain image.
static XrViewConfigurationType selectViewConfigurationType(const std::vector< XrViewConfigurationType > &configurations)
Selects a primary view configuration type from the ones supported by the runtime.
Error preprocessFrame(ASwapchainContext &swapchainContext) override
Prepares the current frame for rendering in an OpenXR session.
std::unique_ptr< XrManageActions > _actionManager
The action manager for handling input actions in the OpenXR session.
std::vector< XrViewConfigurationView > enumerateViewConfigurations() const
Enumerates the available view configurations for the OpenXR system.
XrDeviceBackend(const IPlatform &platform)
Constructs an XrDeviceBackend instance with the specified platform.
void pickPhysicalDevice() override
Picks a physical device that is compatible with the OpenXR session.
The XrSwapchainContext class manages the swapchain context for an OpenXR application using Vulkan....
A structure to represent Vulkan queue family indices.
Small result wrapper used by helpers that must return both a status and a value (e....