mirror of
https://github.com/mitch030504/Wiicompiled_VR_Frame.git
synced 2026-10-06 10:00:27 +02:00
runtime: integrate OpenXR presentation for Mario Kart Wii
This commit is contained in:
1 parent
d8788de919
commit
2156617cd5
17 files changed
+3052
-42
No files matched your search
@@ -49,6 +49,8 @@ struct RuntimeUserConfig {
|
||||
std::optional<float> vrRenderScale;
|
||||
std::optional<float> vrWorldUnitsPerMeter;
|
||||
std::optional<float> vrHudDistanceMeters;
|
||||
std::optional<bool> vrStopAtDisplayCopy;
|
||||
std::optional<bool> vrSkipCopyClears;
|
||||
std::optional<float> audioVolume;
|
||||
std::optional<float> audioMusicVolume;
|
||||
std::optional<float> audioSoundEffectsVolume;
|
||||
@@ -284,7 +286,14 @@ inline void EnsureConfigFile() {
|
||||
"required = false\n"
|
||||
"render_scale = 1.0\n"
|
||||
"world_units_per_meter = 500.0\n"
|
||||
"hud_distance_meters = 2.0\n\n"
|
||||
"hud_distance_meters = 2.0\n"
|
||||
"# EFB replay controls for the per-eye views, changeable live\n"
|
||||
"# from the F10 menu. stop_at_display_copy ends each eye at the\n"
|
||||
"# frame's final GXCopyDisp; skip_copy_clears drops the EFB\n"
|
||||
"# reset a GX copy performs afterwards. Both keep that reset\n"
|
||||
"# from erasing the eye, and both are safe to turn off.\n"
|
||||
"stop_at_display_copy = true\n"
|
||||
"skip_copy_clears = true\n\n"
|
||||
"[audio]\n"
|
||||
"volume = 1.0\n"
|
||||
"music_volume = 1.0\n"
|
||||
@@ -431,6 +440,8 @@ inline RuntimeUserConfig ParseConfigDocument(const toml::value& document) {
|
||||
value && *value >= 0.25f && *value <= 10.0f) {
|
||||
config.vrHudDistanceMeters = *value;
|
||||
}
|
||||
config.vrStopAtDisplayCopy = FindConfigValue<bool>(document, "vr", "stop_at_display_copy");
|
||||
config.vrSkipCopyClears = FindConfigValue<bool>(document, "vr", "skip_copy_clears");
|
||||
|
||||
auto readVolume = [&](std::string_view key) -> std::optional<float> {
|
||||
auto value = FindConfigFloat(document, "audio", key);
|
||||
@@ -650,6 +661,16 @@ inline bool SetVrEnabled(bool value) {
|
||||
return WriteSetting("vr", "enabled", value ? "true" : "false");
|
||||
}
|
||||
|
||||
inline bool SetVrStopAtDisplayCopy(bool value) {
|
||||
Mutable().vrStopAtDisplayCopy = value;
|
||||
return WriteSetting("vr", "stop_at_display_copy", value ? "true" : "false");
|
||||
}
|
||||
|
||||
inline bool SetVrSkipCopyClears(bool value) {
|
||||
Mutable().vrSkipCopyClears = value;
|
||||
return WriteSetting("vr", "skip_copy_clears", value ? "true" : "false");
|
||||
}
|
||||
|
||||
inline bool SetControllerButton(size_t index, std::string value) {
|
||||
if (index >= kControllerButtonKeys.size()) {
|
||||
return false;
|
||||
@@ -821,6 +842,14 @@ inline float VrHudDistanceMeters(float fallback = 2.0f) {
|
||||
return std::clamp(Get().vrHudDistanceMeters.value_or(fallback), 0.25f, 10.0f);
|
||||
}
|
||||
|
||||
inline bool VrStopAtDisplayCopy(bool fallback = true) {
|
||||
return Get().vrStopAtDisplayCopy.value_or(fallback);
|
||||
}
|
||||
|
||||
inline bool VrSkipCopyClears(bool fallback = true) {
|
||||
return Get().vrSkipCopyClears.value_or(fallback);
|
||||
}
|
||||
|
||||
inline std::string GraphicsApi(std::string fallback = "auto") {
|
||||
return Get().graphicsApi.value_or(std::move(fallback));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
struct CpuContext;
|
||||
|
||||
namespace mkw::vr {
|
||||
|
||||
// Announces the capabilities supplied by the translated entry observers. It
|
||||
// is harmless to call repeatedly and does not enable presentation by itself.
|
||||
void MkwVRInstrumentationInitialize() noexcept;
|
||||
|
||||
} // namespace mkw::vr
|
||||
|
||||
// Called only from translator-generated PAL RMCP01 function entries. It is a
|
||||
// read-only observer, not a native replacement: the original translated body
|
||||
// still runs, and the const context contract is part of translator correctness.
|
||||
extern "C" void MkwVRObserveTranslatedFunctionEntry(uint32_t address,
|
||||
const CpuContext* context) noexcept;
|
||||
@@ -105,6 +105,13 @@ struct MkwVRPolicySnapshot {
|
||||
MkwVRCameraObservation camera{};
|
||||
uint32_t available_bindings = MkwVRBindingNone;
|
||||
bool session_active = false;
|
||||
// Changes whenever the stable presentation-safety state changes. Ordinary
|
||||
// per-frame scene/camera publication does not advance it.
|
||||
uint64_t safety_generation = 1;
|
||||
// Opaque safety-state tag for the content being sealed. This also includes
|
||||
// the current presentation mode, so a transient scene/camera mismatch
|
||||
// cannot accept an immersive packet from an adjacent asynchronous frame.
|
||||
uint64_t content_tag = 0;
|
||||
};
|
||||
|
||||
// All policy functions are thread-safe. Publishing functions are intended for
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(MKW_ENABLE_OPENXR) && defined(_WIN32)
|
||||
|
||||
#include "vr/openxr_runtime.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace mkw::vr {
|
||||
|
||||
enum class OpenXRD3D12FrameMode {
|
||||
ImmersiveProjection,
|
||||
VirtualScreen,
|
||||
};
|
||||
|
||||
enum class OpenXRD3D12BeginStatus {
|
||||
Ready,
|
||||
SessionNotRunning,
|
||||
ExitRequested,
|
||||
Error,
|
||||
};
|
||||
|
||||
enum class OpenXRD3D12SubmissionStatus {
|
||||
Success,
|
||||
Failed,
|
||||
Timeout,
|
||||
ShuttingDown,
|
||||
};
|
||||
|
||||
struct OpenXRD3D12GraphicsRequirements {
|
||||
uint32_t adapter_luid_low = 0;
|
||||
int32_t adapter_luid_high = 0;
|
||||
uint32_t minimum_feature_level = 0;
|
||||
};
|
||||
|
||||
struct OpenXRD3D12Presentation {
|
||||
OpenXRD3D12FrameMode mode = OpenXRD3D12FrameMode::ImmersiveProjection;
|
||||
|
||||
// Used only by VirtualScreen. The quad is head-locked in XR_VIEW_SPACE
|
||||
// and centered straight ahead at -Z.
|
||||
float quad_distance_meters = 2.0f;
|
||||
float quad_width_meters = 2.4f;
|
||||
};
|
||||
|
||||
struct OpenXRD3D12Frame {
|
||||
OpenXRFrame xr_frame;
|
||||
OpenXRD3D12Presentation presentation;
|
||||
std::array<uint32_t, kOpenXREyeCount> render_width{};
|
||||
std::array<uint32_t, kOpenXREyeCount> render_height{};
|
||||
bool expects_gpu_submission = false;
|
||||
};
|
||||
|
||||
// Same-device Dawn/OpenXR D3D12 backend.
|
||||
//
|
||||
// Startup is deliberately split in two. QueryGraphicsRequirements() runs
|
||||
// after OpenXRRuntime::Initialize() but before aurora_initialize(), allowing
|
||||
// its LUID to be placed in AuroraConfig. BindAurora() runs afterwards and
|
||||
// rejects any device/queue that does not match the queried runtime adapter.
|
||||
//
|
||||
// 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 OpenXRD3D12Backend final {
|
||||
public:
|
||||
explicit OpenXRD3D12Backend(OpenXRLogCallback logger = {});
|
||||
~OpenXRD3D12Backend();
|
||||
|
||||
OpenXRD3D12Backend(const OpenXRD3D12Backend&) = delete;
|
||||
OpenXRD3D12Backend& operator=(const OpenXRD3D12Backend&) = delete;
|
||||
OpenXRD3D12Backend(OpenXRD3D12Backend&&) = delete;
|
||||
OpenXRD3D12Backend& operator=(OpenXRD3D12Backend&&) = delete;
|
||||
|
||||
bool QueryGraphicsRequirements(OpenXRRuntime& runtime);
|
||||
bool BindAurora(OpenXRRuntime& runtime);
|
||||
|
||||
OpenXRD3D12BeginStatus BeginFrame(const OpenXRD3D12Presentation& presentation,
|
||||
OpenXRD3D12Frame& 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 must first drain/cancel Aurora, then FinishFrame(false).
|
||||
OpenXRD3D12SubmissionStatus WaitForSubmission(const OpenXRD3D12Frame& 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(OpenXRD3D12Frame& 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 a head-locked
|
||||
// XrCompositionLayerQuad using the single mono target.
|
||||
bool FinishFrame(OpenXRD3D12Frame& frame, bool submit_layer);
|
||||
|
||||
// Call on the XR owner thread after Aurora's worker is idle and before
|
||||
// aurora_shutdown(). Safe to repeat. False means a submitted D3D12 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;
|
||||
const OpenXRD3D12GraphicsRequirements& 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)
|
||||
@@ -0,0 +1,39 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <aurora/aurora.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace mkw::vr {
|
||||
|
||||
enum class OpenXRStartupResult {
|
||||
Disabled,
|
||||
Prepared,
|
||||
Unavailable,
|
||||
};
|
||||
|
||||
// Performs the OpenXR instance/system and graphics-requirements work that must
|
||||
// happen before Aurora selects an adapter. On success this may force the
|
||||
// backend and populate AuroraConfig's XR interop fields.
|
||||
OpenXRStartupResult OpenXRPrepareAurora(AuroraConfig& config);
|
||||
|
||||
// Completes the graphics binding and starts the asynchronous XR pacing thread.
|
||||
// Call after aurora_initialize(), while Aurora's frame worker is idle.
|
||||
bool OpenXRStartAfterAurora(AuroraBackend active_backend);
|
||||
|
||||
// Stops publishing stereo work, drains the pacing thread, and destroys the XR
|
||||
// session before aurora_shutdown(). Safe to call after partial initialization.
|
||||
void OpenXRShutdownBeforeAurora() noexcept;
|
||||
|
||||
// Services an XR-owned teardown request at the producer's safe frame boundary:
|
||||
// after aurora_begin_frame() has granted the worker's prepare phase and before
|
||||
// aurora_end_frame_tagged() seals the current frame. No-op unless the pacing
|
||||
// thread has fallen back to desktop rendering.
|
||||
void OpenXRServiceProducerFrameBoundary() noexcept;
|
||||
|
||||
bool OpenXRIsRunning() noexcept;
|
||||
std::string OpenXRLastError();
|
||||
|
||||
} // namespace mkw::vr
|
||||
@@ -142,6 +142,11 @@ public:
|
||||
OpenXREventStatus PollEvents();
|
||||
bool RequestExitSession();
|
||||
|
||||
// Graphics backends call OpenXR entry points directly for swapchain work.
|
||||
// Feed their results back here so positive loss-pending and negative
|
||||
// session/instance-loss results update the central lifecycle state.
|
||||
void ObserveResult(XrResult result) noexcept;
|
||||
|
||||
// Explicit frame protocol. A successful WaitFrame must be followed by
|
||||
// BeginFrame and EndFrame using the same token. LocateViews is optional when
|
||||
// should_render is false; it is otherwise normally called after BeginFrame.
|
||||
@@ -171,7 +176,9 @@ public:
|
||||
return m_session_state == XR_SESSION_STATE_VISIBLE ||
|
||||
m_session_state == XR_SESSION_STATE_FOCUSED;
|
||||
}
|
||||
bool ShouldExit() const { return m_exit_requested || m_instance_loss_pending; }
|
||||
bool ShouldExit() const {
|
||||
return m_exit_requested || m_session_loss_pending || m_instance_loss_pending;
|
||||
}
|
||||
|
||||
XrInstance Instance() const { return m_instance; }
|
||||
XrSystemId SystemId() const { return m_system_id; }
|
||||
@@ -179,6 +186,7 @@ public:
|
||||
XrSpace AppSpace() const { return m_app_space; }
|
||||
XrSpace ViewSpace() const { return m_view_space; }
|
||||
XrSessionState SessionState() const { return m_session_state; }
|
||||
uint64_t SessionRunSerial() const { return m_session_run_serial; }
|
||||
XrReferenceSpaceType AppSpaceType() const { return m_app_space_type; }
|
||||
XrEnvironmentBlendMode EnvironmentBlendMode() const { return m_blend_mode; }
|
||||
|
||||
@@ -194,6 +202,10 @@ public:
|
||||
const OpenXRReferenceSpaceChange& LastReferenceSpaceChange() const {
|
||||
return m_reference_space_change;
|
||||
}
|
||||
// Consumes every queued application-space change whose effective time is
|
||||
// no later than display_time. Multiple future recenter events are retained
|
||||
// independently rather than overwriting one another.
|
||||
bool ConsumeAppSpaceChangesThrough(XrTime display_time);
|
||||
const OpenXRError& LastError() const { return m_last_error; }
|
||||
|
||||
private:
|
||||
@@ -212,6 +224,7 @@ private:
|
||||
bool EnumerateSwapchainFormats();
|
||||
bool HandleSessionStateChanged(const XrEventDataSessionStateChanged& event);
|
||||
bool IsFrameTokenCurrent(const OpenXRFrame& frame, FramePhase expected) const;
|
||||
void ResetFrameState();
|
||||
void DestroyReferenceSpaces();
|
||||
void ResetSessionState();
|
||||
void ResetInstanceState();
|
||||
@@ -237,10 +250,12 @@ private:
|
||||
XrEnvironmentBlendMode m_blend_mode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE;
|
||||
bool m_session_running = false;
|
||||
bool m_exit_requested = false;
|
||||
bool m_session_loss_pending = false;
|
||||
bool m_instance_loss_pending = false;
|
||||
bool m_shutting_down_session = false;
|
||||
|
||||
FramePhase m_frame_phase = FramePhase::Idle;
|
||||
uint64_t m_session_run_serial = 0;
|
||||
uint64_t m_next_frame_serial = 1;
|
||||
uint64_t m_active_frame_serial = 0;
|
||||
XrTime m_active_frame_display_time = 0;
|
||||
@@ -255,6 +270,7 @@ private:
|
||||
std::vector<XrEnvironmentBlendMode> m_supported_blend_modes;
|
||||
std::vector<int64_t> m_swapchain_formats;
|
||||
OpenXRReferenceSpaceChange m_reference_space_change;
|
||||
std::vector<OpenXRReferenceSpaceChange> m_pending_app_space_changes;
|
||||
};
|
||||
|
||||
} // namespace mkw::vr
|
||||
@@ -0,0 +1,186 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(MKW_ENABLE_OPENXR)
|
||||
|
||||
#include "vr/openxr_runtime.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
namespace mkw::vr {
|
||||
|
||||
// Keep Vulkan implementation types out of the runtime/Aurora boundary. Vulkan
|
||||
// dispatchable and non-dispatchable handles both fit in 64 bits on every target
|
||||
// supported by this project. The backend converts these values to the Vulkan
|
||||
// header's actual handle types only in its implementation file.
|
||||
using OpenXRVulkanHandle = uint64_t;
|
||||
|
||||
inline constexpr uint32_t kOpenXRVulkanNativeContextVersion = 1;
|
||||
|
||||
enum OpenXRVulkanNativeContextFlagBits : uint32_t {
|
||||
// The handles are the exact objects used by Aurora's Dawn device. A second
|
||||
// Vulkan device is not a valid substitute: it cannot present Dawn's work to
|
||||
// an OpenXR swapchain without an explicit external-memory bridge.
|
||||
OpenXRVulkanNativeContextDawnOwnedBit = 1u << 0,
|
||||
|
||||
// The provider has queried the queue from device/queue_family_index/
|
||||
// queue_index and verified that it equals queue. Dawn's package API does not
|
||||
// currently expose enough information for this backend to do that itself.
|
||||
OpenXRVulkanNativeContextQueueVerifiedBit = 1u << 1,
|
||||
};
|
||||
|
||||
using OpenXRVulkanQueueLockCallback = bool (*)(void* userdata);
|
||||
using OpenXRVulkanQueueUnlockCallback = void (*)(void* userdata);
|
||||
|
||||
// ABI-stable context a Dawn-native shim must provide. All handles are borrowed
|
||||
// and must outlive OpenXRVulkanBackend. The paired callbacks externally
|
||||
// synchronize Vulkan queue access with Dawn; they are mandatory because a
|
||||
// Vulkan queue is not internally synchronized and XR may use the graphics queue
|
||||
// during image hand-off.
|
||||
struct OpenXRVulkanNativeContext {
|
||||
uint32_t version = kOpenXRVulkanNativeContextVersion;
|
||||
uint32_t struct_size = sizeof(OpenXRVulkanNativeContext);
|
||||
uint32_t flags = 0;
|
||||
|
||||
OpenXRVulkanHandle instance = 0;
|
||||
OpenXRVulkanHandle physical_device = 0;
|
||||
OpenXRVulkanHandle device = 0;
|
||||
OpenXRVulkanHandle queue = 0;
|
||||
uint32_t queue_family_index = 0;
|
||||
uint32_t queue_index = 0;
|
||||
|
||||
// A VK_MAKE_API_VERSION encoded value for the Vulkan instance/device.
|
||||
uint32_t api_version = 0;
|
||||
|
||||
OpenXRVulkanQueueLockCallback lock_queue = nullptr;
|
||||
OpenXRVulkanQueueUnlockCallback unlock_queue = nullptr;
|
||||
void* queue_userdata = nullptr;
|
||||
};
|
||||
|
||||
enum class OpenXRVulkanCapability {
|
||||
Available,
|
||||
VulkanHeadersUnavailable,
|
||||
DawnNativeHandlesUnavailable,
|
||||
InvalidNativeContext,
|
||||
MissingEnable2Extension,
|
||||
RuntimeRejectedGraphicsDevice,
|
||||
RuntimeApiVersionMismatch,
|
||||
};
|
||||
|
||||
struct OpenXRVulkanCapabilityInfo {
|
||||
OpenXRVulkanCapability capability = OpenXRVulkanCapability::Available;
|
||||
std::string reason;
|
||||
|
||||
explicit operator bool() const {
|
||||
return capability == OpenXRVulkanCapability::Available;
|
||||
}
|
||||
};
|
||||
|
||||
struct OpenXRVulkanBackendConfig {
|
||||
// Rendering directly into an XR image needs COLOR_ATTACHMENT. Aurora's
|
||||
// intended zero-copy bridge renders to an imported/application-owned image
|
||||
// and performs a GPU copy, which additionally requires TRANSFER_DST.
|
||||
bool require_transfer_destination = true;
|
||||
XrDuration image_wait_timeout = XR_INFINITE_DURATION;
|
||||
XrCompositionLayerFlags projection_layer_flags = 0;
|
||||
};
|
||||
|
||||
struct OpenXRVulkanEyeImage {
|
||||
uint32_t eye = 0;
|
||||
uint32_t image_index = 0;
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
int64_t format = 0;
|
||||
OpenXRVulkanHandle image = 0;
|
||||
};
|
||||
|
||||
// Owns the Vulkan-bound session and its per-eye OpenXR swapchains. It does not
|
||||
// record Vulkan commands: Aurora's backend bridge is responsible for rendering
|
||||
// or copying into the borrowed VkImage on the supplied Dawn queue, submitting
|
||||
// that GPU work, then calling ReleaseEyeImage(). No CPU/readback fallback exists.
|
||||
//
|
||||
// All methods must be called on the XR owner thread. Shutdown() must run before
|
||||
// the native Vulkan device is destroyed.
|
||||
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;
|
||||
|
||||
// Reports whether this build's Aurora/Dawn provider has the native Vulkan
|
||||
// handle shim required by the backend. The pinned prebuilt Dawn package does
|
||||
// not expose VkPhysicalDevice, VkDevice, VkQueue, or the queue-family index,
|
||||
// so this intentionally reports DawnNativeHandlesUnavailable until such a
|
||||
// shim is compiled in.
|
||||
static OpenXRVulkanCapabilityInfo DawnInteropCapability();
|
||||
|
||||
// runtime must already be initialized with XR_KHR_vulkan_enable2 in its
|
||||
// required extension list and must not yet own a session.
|
||||
bool Initialize(OpenXRRuntime& runtime,
|
||||
const OpenXRVulkanNativeContext& native_context,
|
||||
const OpenXRVulkanBackendConfig& config = {});
|
||||
void Shutdown();
|
||||
|
||||
bool AcquireEyeImage(uint32_t eye, OpenXRVulkanEyeImage& image);
|
||||
bool ReleaseEyeImage(uint32_t eye);
|
||||
|
||||
// Ends a begun OpenXR frame with a stereo projection layer. The pose/FOV
|
||||
// come from the same OpenXRFrame token used for rendering. When
|
||||
// should_render is false or views are invalid, the frame is ended without a
|
||||
// layer as required by the OpenXR frame protocol.
|
||||
bool SubmitProjection(const OpenXRFrame& frame);
|
||||
|
||||
bool IsInitialized() const { return m_runtime != nullptr; }
|
||||
int64_t SwapchainFormat() const { return m_swapchain_format; }
|
||||
const std::array<OpenXRViewConfiguration, kOpenXREyeCount>&
|
||||
ViewConfiguration() const;
|
||||
const OpenXRError& LastError() const { return m_last_error; }
|
||||
|
||||
private:
|
||||
struct EyeSwapchain {
|
||||
XrSwapchain handle = XR_NULL_HANDLE;
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
std::vector<OpenXRVulkanHandle> images;
|
||||
uint32_t acquired_index = 0;
|
||||
bool acquired = false;
|
||||
bool waited = false;
|
||||
};
|
||||
|
||||
bool ValidateNativeContext(const OpenXRVulkanNativeContext& native_context);
|
||||
bool ValidateRuntimeDevice();
|
||||
bool CreateSwapchains();
|
||||
bool CreateEyeSwapchain(uint32_t eye);
|
||||
bool SelectSwapchainFormat();
|
||||
void DestroySwapchains();
|
||||
|
||||
bool LockQueue();
|
||||
void UnlockQueue();
|
||||
bool Check(XrResult result, std::string_view operation);
|
||||
bool Fail(XrResult result, std::string_view operation, std::string_view detail);
|
||||
void Log(OpenXRLogLevel level, std::string_view message) const noexcept;
|
||||
std::string ResultString(XrResult result) const;
|
||||
|
||||
OpenXRRuntime* m_runtime = nullptr;
|
||||
OpenXRLogCallback m_logger;
|
||||
OpenXRError m_last_error;
|
||||
OpenXRVulkanNativeContext m_native_context{};
|
||||
OpenXRVulkanBackendConfig m_config{};
|
||||
std::array<EyeSwapchain, kOpenXREyeCount> m_eye_swapchains{};
|
||||
int64_t m_swapchain_format = 0;
|
||||
bool m_owns_session = false;
|
||||
};
|
||||
|
||||
} // namespace mkw::vr
|
||||
|
||||
#endif // defined(MKW_ENABLE_OPENXR)
|
||||
Reference in new issue
Block a user