Files
mitch030504--Wiicompiled_VR…/runtime/include/vr/openxr_vulkan_win32.h
T
Claude 28a25108c6 Run the same-device Vulkan OpenXR backend on desktop Linux
Lepton's Vulkan driver has no external memory or sync fd extensions,
so the Steam Frame gets a native SteamOS build instead. Its backend is
the PC's: OpenXR creates Dawn's own Vulkan instance and device, and the
eyes are copied into the swapchain on Dawn's queue, with nothing shared
between devices.

- openxr_vulkan_win32 and Aurora's vulkan_win32_interop now compile on
  desktop Linux. Dawn links statically there, so the bridge calls the
  patched package's hooks directly, and exists only when the package's
  aurora-dawn.json declares the Vulkan hook ABI (AuroraDawnProvider
  turns AuroraVulkanAbi into AURORA_DAWN_VULKAN_HOOKS); a stock Dawn
  keeps the stubs and VR falls back to the desktop.
- openxr_integration.cpp gains a Linux branch: XR_KHR_vulkan_enable2,
  the timespec clock, refresh rate, performance level, the Frame
  controllers and eye gaze; fragment density maps are requested on
  Linux as on the Quest (fdm.cpp and gpu.cpp, AURORA_FDM=0/1 overrides).
- Controller motion uses XR_KHR_convert_timespec_time on any Linux.
- CMake: Vulkan headers are fetched for Linux OpenXR builds, the
  headset option is MKW_HEADSET on Android and Linux, and Linux aarch64
  builds take MKW_LINUX_CPU (cortex-x4 for the Steam Frame, else native).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019HBRGKTE1GnN2ah8gcZKr3
2026-10-04 09:48:48 +00:00

118 lines
5.6 KiB
C++

// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
// Despite the name, also the desktop Linux backend (SteamOS on the Steam Frame): nothing in it is
// Windows-specific. The Quest has its own two-device backend (openxr_vulkan.h).
#if defined(MKW_ENABLE_OPENXR) && (defined(_WIN32) || (defined(__linux__) && !defined(__ANDROID__)))
#include "vr/openxr_backend.h"
#include "vr/openxr_runtime.h"
#include <array>
#include <cstdint>
#include <memory>
#include <string>
namespace mkw::vr {
// Shared frame vocabulary for the Windows pacing and replay paths.
using OpenXRWindowsVulkanFrameMode = OpenXRFrameMode;
using OpenXRWindowsVulkanBeginStatus = OpenXRBeginStatus;
using OpenXRWindowsVulkanSubmissionStatus = OpenXRSubmissionStatus;
using OpenXRWindowsVulkanPresentation = OpenXRPresentation;
using OpenXRWindowsVulkanFrame = OpenXRBackendFrame;
struct OpenXRWindowsVulkanGraphicsRequirements {
XrVersion min_api_version = 0;
XrVersion max_api_version = 0;
};
// Same-device Dawn/OpenXR Vulkan backend.
//
// Startup is deliberately split in two. QueryGraphicsRequirements() runs
// after OpenXRRuntime::Initialize() but before aurora_initialize(), allowing
// OpenXR to create Dawn's Vulkan instance/device and select the physical GPU.
// BindAurora() runs afterwards and checks the device before creating a session.
//
// All methods from BeginFrame() through FinishFrame(), plus PollEvents on the
// associated OpenXRRuntime, belong to one XR pacing thread. Aurora's frame
// worker never calls OpenXR: its post-submit callback only publishes a token
// that WaitForSubmission() consumes. This is the synchronization boundary
// required by the asynchronous sealed-frame renderer.
class OpenXRWindowsVulkanBackend final {
public:
explicit OpenXRWindowsVulkanBackend(OpenXRLogCallback logger = {});
~OpenXRWindowsVulkanBackend();
OpenXRWindowsVulkanBackend(const OpenXRWindowsVulkanBackend&) = delete;
OpenXRWindowsVulkanBackend& operator=(const OpenXRWindowsVulkanBackend&) = delete;
OpenXRWindowsVulkanBackend(OpenXRWindowsVulkanBackend&&) = delete;
OpenXRWindowsVulkanBackend& operator=(OpenXRWindowsVulkanBackend&&) = delete;
bool QueryGraphicsRequirements(OpenXRRuntime& runtime);
bool BindAurora(OpenXRRuntime& runtime);
// As OpenXRD3D12Backend::SetRenderScale.
void SetRenderScale(float scale);
OpenXRWindowsVulkanBeginStatus BeginFrame(const OpenXRWindowsVulkanPresentation& presentation,
OpenXRWindowsVulkanFrame& frame);
// timeout_ms == UINT32_MAX waits until Aurora publishes this token or
// Shutdown() interrupts the wait. A timeout does not release XR images;
// the caller may keep pacing with RepeatFrame while Aurora still owns them.
OpenXRWindowsVulkanSubmissionStatus WaitForSubmission(const OpenXRWindowsVulkanFrame& frame,
uint32_t timeout_ms = UINT32_MAX);
// Withdraws this token only if Aurora has not encoded it. On success no GPU
// command can reference the acquired images, and FinishFrame(frame, false)
// is required to release them and close the compositor frame.
bool TryCancelPendingFrame(OpenXRWindowsVulkanFrame& frame);
// Ends the current compositor cycle with the last completed layer and starts
// another, without releasing or changing Aurora's pending images/render token.
// The original render poses remain attached to the pending and retained images.
bool RepeatFrame(const OpenXRWindowsVulkanFrame& frame);
// Releases acquired images and calls xrEndFrame. submit_layer must only be
// true after WaitForSubmission returned Success. Immersive frames submit
// XrCompositionLayerProjection; virtual-screen frames submit an
// XrCompositionLayerQuad using the single mono target, placed as the
// presentation's quad_anchored/quad_pose describe. If no new usable layer is
// available, resubmits the retained layer using the current display time.
bool FinishFrame(OpenXRWindowsVulkanFrame& frame, bool submit_layer);
// Render-first path when interpolation is off. Aurora renders into acquired
// non-retained XR images while no compositor frame is open. BeginFrameForPacket
// accepts only a completed packet; CopyRenderedEyes verifies the already queued
// bridge copy. FinishFrame releases the images and submits their original poses.
OpenXRBeginStatus PreparePacket(const OpenXRPresentation& presentation, OpenXRBackendFrame& packet);
bool TryCancelPendingPacket(OpenXRBackendFrame& packet);
OpenXRBeginStatus BeginFrameForPacket(const OpenXRBackendFrame& packet, OpenXRBackendFrame& frame);
OpenXRSubmissionStatus CopyRenderedEyes(const OpenXRBackendFrame& frame);
OpenXRBeginStatus KeepAliveCycle();
// Call on the XR owner thread after Aurora's worker is idle and before
// aurora_shutdown(). Safe to repeat. False means a submitted Vulkan command
// could not be fenced; the caller must retain this backend and its runtime
// for the process lifetime instead of destroying possibly live resources.
bool Shutdown();
bool IsBound() const;
// False once the settings panel's own layer could not be set up; the panel
// is then drawn into the eyes again.
bool PanelLayerAvailable() const;
const OpenXRWindowsVulkanGraphicsRequirements& GraphicsRequirements() const;
int64_t SwapchainFormat() const;
const std::string& LastError() const;
private:
class Impl;
std::unique_ptr<Impl> m_impl;
};
} // namespace mkw::vr
#endif // defined(MKW_ENABLE_OPENXR) && (defined(_WIN32) || (defined(__linux__) && !defined(__ANDROID__)))