// SPDX-License-Identifier: GPL-3.0-or-later #pragma once #if defined(MKW_ENABLE_OPENXR) && defined(__ANDROID__) #include "vr/openxr_backend.h" #include "vr/openxr_runtime.h" #include #include #include namespace mkw::vr { struct OpenXRVulkanGraphicsRequirements { // XR_MAKE_VERSION-encoded bounds reported by xrGetVulkanGraphicsRequirements2KHR. XrVersion min_api_version = 0; XrVersion max_api_version = 0; // Which binding extension was negotiated: XR_KHR_vulkan_enable2 when the // runtime offers it, otherwise the original XR_KHR_vulkan_enable. bool uses_enable2 = false; }; // Two-device Dawn/OpenXR Vulkan backend for Android (Meta Quest). // // Method surface and threading rules are identical to OpenXRD3D12Backend so the // pacing thread in openxr_integration.cpp is shared. The difference is behind // BindAurora: instead of binding Dawn's device to the session, this backend // creates its own VkInstance/VkDevice through the OpenXR runtime, owns a small // ring of AHardwareBuffers per eye, and hands them to Aurora's Vulkan stereo // bridge (aurora/vulkan_interop.h). When Aurora reports a completed copy, the // backend copies the buffer into the acquired XrSwapchain image on the // session's queue, so the compositor sees ordinary same-queue rendering. // // QueryGraphicsRequirements() runs after OpenXRRuntime::Initialize() and before // aurora_initialize(); BindAurora() runs afterwards, while Aurora's frame worker // is idle. Everything from BeginFrame() through FinishFrame() belongs to one XR // pacing thread; the Aurora callback only records a small copy on this // backend's private queue and publishes a token. class OpenXRVulkanBackend final { public: explicit OpenXRVulkanBackend(OpenXRLogCallback logger = {}); ~OpenXRVulkanBackend(); OpenXRVulkanBackend(const OpenXRVulkanBackend&) = delete; OpenXRVulkanBackend& operator=(const OpenXRVulkanBackend&) = delete; OpenXRVulkanBackend(OpenXRVulkanBackend&&) = delete; OpenXRVulkanBackend& operator=(OpenXRVulkanBackend&&) = delete; bool QueryGraphicsRequirements(OpenXRRuntime& runtime); bool BindAurora(OpenXRRuntime& runtime); OpenXRBeginStatus BeginFrame(const OpenXRPresentation& presentation, OpenXRBackendFrame& frame); OpenXRSubmissionStatus WaitForSubmission(const OpenXRBackendFrame& frame, uint32_t timeout_ms = UINT32_MAX); bool TryCancelPendingFrame(OpenXRBackendFrame& frame); bool RepeatFrame(const OpenXRBackendFrame& frame); bool FinishFrame(OpenXRBackendFrame& frame, bool submit_layer); // Drains this backend's own queue before tearing down. Returns false only // when the private device could not be waited on, in which case the caller // retains the backend and runtime for the process lifetime. bool Shutdown(); bool IsBound() const; const OpenXRVulkanGraphicsRequirements& GraphicsRequirements() const; int64_t SwapchainFormat() const; const std::string& LastError() const; private: class Impl; std::unique_ptr m_impl; }; } // namespace mkw::vr #endif // defined(MKW_ENABLE_OPENXR) && defined(__ANDROID__)