mirror of
https://github.com/mitch030504/Wiicompiled_VR_Frame.git
synced 2026-10-06 13:00:26 +02:00
The panel was drawn into the eye images, so below a 1.00x OpenXR resolution its 1440x1080 canvas was minified into a small eye region and the text became hard to read. It is now submitted as a quad layer of its own over the scene's projection or menu quad, which the compositor samples directly at any render scale. Each backend (D3D12, Windows Vulkan, Quest) makes the panel's swapchain pair (plus two shared buffers on the Quest) the first time the panel opens. While it is open, the frame hands Aurora one more stereo target after the eyes, which the bridge fills with the panel texture or a transparent image. The panel image follows the eyes' displayed/retained pairing, so a cancelled frame never shows an unwritten panel. The quad hangs where the pointer's hits are tested. Aurora leaves the panel out of the eyes in layer mode, and a backend that cannot make the layer falls back to drawing it into the eyes. On the Quest, debug.wiicompiled.panel_layer 0 selects the old path at run time. Measured there at a race start (render_scale 0.8), the layer costs nothing while the panel is closed; while it is open, app GPU time is 10.5 ms against 9.7 ms drawn into the eyes, with unchanged frame rates. The replay tests cover lazy creation, cancelled frames, closed and unplaced panels, and render-first pacing on D3D12 and Windows Vulkan. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
113 lines
5.2 KiB
C++
113 lines
5.2 KiB
C++
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
#pragma once
|
|
|
|
#if defined(MKW_ENABLE_OPENXR) && defined(_WIN32)
|
|
|
|
#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);
|
|
|
|
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)
|