mirror of
https://github.com/mitch030504/Wiicompiled_VR_Frame.git
synced 2026-10-06 08:00:25 +02:00
Added Vulkan PC OpenXR Support
This commit is contained in:
1 parent
fbc9ce7217
commit
e7b670b2cc
23 files changed
+2174
-22
No files matched your search
@@ -286,6 +286,15 @@ if(MKW_PROJECT_COMPILE_DEFINITIONS)
|
||||
add_compile_definitions(${MKW_PROJECT_COMPILE_DEFINITIONS})
|
||||
endif()
|
||||
|
||||
if(MKW_PLATFORM_WINDOWS AND MKW_ENABLE_OPENXR)
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(vulkan_headers
|
||||
URL "https://github.com/KhronosGroup/Vulkan-Headers/archive/015e25c3c91b70eb1a754d36fb14c4ba6ad9b0b9.tar.gz"
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP TRUE)
|
||||
FetchContent_MakeAvailable(vulkan_headers)
|
||||
include_directories("${vulkan_headers_SOURCE_DIR}/include")
|
||||
endif()
|
||||
|
||||
set(MKW_OPENXR_TARGET "")
|
||||
if(MKW_ENABLE_OPENXR)
|
||||
if(NOT MKW_PLATFORM_WINDOWS AND NOT MKW_PLATFORM_LINUX AND NOT MKW_PLATFORM_ANDROID)
|
||||
@@ -340,6 +349,7 @@ endif()
|
||||
# a registration file is silently never compiled and never errors. The stale-glob
|
||||
# failure mode is worth far more than the milliseconds.
|
||||
file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS "src/*.cpp")
|
||||
set_source_files_properties(src/vr/openxr_vulkan_win32.cpp PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
|
||||
if(MKW_PLATFORM_MACOS)
|
||||
list(REMOVE_ITEM SOURCES "${CMAKE_CURRENT_LIST_DIR}/src/guest_flat_memory.cpp")
|
||||
# HostContext's Apple Silicon backend is implemented in a small assembly
|
||||
@@ -453,6 +463,16 @@ if(MKW_ENABLE_OPENXR AND MKW_PLATFORM_WINDOWS)
|
||||
target_compile_features(mkw_openxr_replay_tests PRIVATE cxx_std_17)
|
||||
set_target_properties(mkw_openxr_replay_tests PROPERTIES UNITY_BUILD OFF)
|
||||
add_test(NAME mkw_openxr_replay_tests COMMAND mkw_openxr_replay_tests)
|
||||
add_executable(mkw_openxr_vulkan_replay_tests
|
||||
tests/openxr_d3d12_replay_tests.cpp src/vr/openxr_vulkan_win32.cpp src/vr/openxr_diagnostics.cpp)
|
||||
target_include_directories(mkw_openxr_vulkan_replay_tests PRIVATE
|
||||
"${CMAKE_CURRENT_LIST_DIR}/include"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/../aurora-main/include"
|
||||
"$<TARGET_PROPERTY:${MKW_OPENXR_TARGET},INTERFACE_INCLUDE_DIRECTORIES>")
|
||||
target_compile_definitions(mkw_openxr_vulkan_replay_tests PRIVATE MKW_ENABLE_OPENXR=1 TEST_WINDOWS_VULKAN=1)
|
||||
target_compile_features(mkw_openxr_vulkan_replay_tests PRIVATE cxx_std_17)
|
||||
set_target_properties(mkw_openxr_vulkan_replay_tests PROPERTIES UNITY_BUILD OFF)
|
||||
add_test(NAME mkw_openxr_vulkan_replay_tests COMMAND mkw_openxr_vulkan_replay_tests)
|
||||
endif()
|
||||
|
||||
add_executable(mkw_nand_save_tests "${CMAKE_CURRENT_LIST_DIR}/tests/nand_save_tests.cpp")
|
||||
|
||||
@@ -106,6 +106,23 @@ public:
|
||||
OpenXRRuntime(OpenXRRuntime&&) = delete;
|
||||
OpenXRRuntime& operator=(OpenXRRuntime&&) = delete;
|
||||
|
||||
// Same-device Vulkan runtimes may touch Dawn's queue in frame/swapchain
|
||||
// calls. Share Dawn's device guard; never hold it across xrWaitFrame.
|
||||
struct GraphicsQueueGuard {
|
||||
GraphicsQueueGuard(void* value, void (*release)(void*)) : token(value), unlock(release) {}
|
||||
GraphicsQueueGuard(const GraphicsQueueGuard&) = delete;
|
||||
GraphicsQueueGuard& operator=(const GraphicsQueueGuard&) = delete;
|
||||
void* token;
|
||||
void (*unlock)(void*);
|
||||
~GraphicsQueueGuard() { if (token && unlock) unlock(token); }
|
||||
};
|
||||
void SetGraphicsQueueGuard(void* (*lock)(), void (*unlock)(void*)) {
|
||||
m_queue_lock = lock; m_queue_unlock = unlock;
|
||||
}
|
||||
GraphicsQueueGuard LockGraphicsQueue() const {
|
||||
return {m_queue_lock ? m_queue_lock() : nullptr, m_queue_unlock};
|
||||
}
|
||||
|
||||
// Creates the instance, resolves the HMD system, and enumerates the stereo
|
||||
// view configuration. Returns false without terminating the application;
|
||||
// the caller should continue in non-VR mode.
|
||||
@@ -214,6 +231,8 @@ public:
|
||||
const OpenXRError& LastError() const { return m_last_error; }
|
||||
|
||||
private:
|
||||
void* (*m_queue_lock)() = nullptr;
|
||||
void (*m_queue_unlock)(void*) = nullptr;
|
||||
enum class FramePhase {
|
||||
Idle,
|
||||
Waited,
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
// 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;
|
||||
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)
|
||||
@@ -0,0 +1,64 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#pragma once
|
||||
#include "vr/openxr_d3d12.h"
|
||||
#include "vr/openxr_vulkan_win32.h"
|
||||
#include <variant>
|
||||
namespace mkw::vr {
|
||||
// Runtime API selection; both backends expose the same pacing/ownership contract.
|
||||
class OpenXRWindowsBackend {
|
||||
std::variant<std::unique_ptr<OpenXRD3D12Backend>, std::unique_ptr<OpenXRWindowsVulkanBackend>> backend_;
|
||||
public:
|
||||
OpenXRWindowsBackend(OpenXRLogCallback logger, bool vulkan) {
|
||||
if (vulkan) backend_ = std::make_unique<OpenXRWindowsVulkanBackend>(logger);
|
||||
else backend_ = std::make_unique<OpenXRD3D12Backend>(logger);
|
||||
}
|
||||
const OpenXRD3D12GraphicsRequirements& GraphicsRequirements() {
|
||||
return std::get<0>(backend_)->GraphicsRequirements();
|
||||
}
|
||||
bool QueryGraphicsRequirements(OpenXRRuntime& runtime) {
|
||||
return std::visit([&](auto& backend) -> bool { return backend->QueryGraphicsRequirements(runtime); }, backend_);
|
||||
}
|
||||
bool BindAurora(OpenXRRuntime& runtime) {
|
||||
return std::visit([&](auto& backend) -> bool { return backend->BindAurora(runtime); }, backend_);
|
||||
}
|
||||
OpenXRBeginStatus BeginFrame(const OpenXRPresentation& presentation, OpenXRBackendFrame& frame) {
|
||||
return std::visit([&](auto& backend) -> OpenXRBeginStatus { return backend->BeginFrame(presentation, frame); }, backend_);
|
||||
}
|
||||
OpenXRSubmissionStatus WaitForSubmission(const OpenXRBackendFrame& frame, uint32_t timeout) {
|
||||
return std::visit([&](auto& backend) -> OpenXRSubmissionStatus { return backend->WaitForSubmission(frame, timeout); }, backend_);
|
||||
}
|
||||
bool TryCancelPendingFrame(OpenXRBackendFrame& frame) {
|
||||
return std::visit([&](auto& backend) -> bool { return backend->TryCancelPendingFrame(frame); }, backend_);
|
||||
}
|
||||
bool RepeatFrame(const OpenXRBackendFrame& frame) {
|
||||
return std::visit([&](auto& backend) -> bool { return backend->RepeatFrame(frame); }, backend_);
|
||||
}
|
||||
bool FinishFrame(OpenXRBackendFrame& frame, bool submit) {
|
||||
return std::visit([&](auto& backend) -> bool { return backend->FinishFrame(frame, submit); }, backend_);
|
||||
}
|
||||
OpenXRBeginStatus PreparePacket(const OpenXRPresentation& presentation, OpenXRBackendFrame& frame) {
|
||||
return std::visit([&](auto& backend) -> OpenXRBeginStatus { return backend->PreparePacket(presentation, frame); }, backend_);
|
||||
}
|
||||
bool TryCancelPendingPacket(OpenXRBackendFrame& frame) {
|
||||
return std::visit([&](auto& backend) -> bool { return backend->TryCancelPendingPacket(frame); }, backend_);
|
||||
}
|
||||
OpenXRBeginStatus BeginFrameForPacket(const OpenXRBackendFrame& packet, OpenXRBackendFrame& frame) {
|
||||
return std::visit([&](auto& backend) -> OpenXRBeginStatus { return backend->BeginFrameForPacket(packet, frame); }, backend_);
|
||||
}
|
||||
OpenXRSubmissionStatus CopyRenderedEyes(const OpenXRBackendFrame& frame) {
|
||||
return std::visit([&](auto& backend) -> OpenXRSubmissionStatus { return backend->CopyRenderedEyes(frame); }, backend_);
|
||||
}
|
||||
OpenXRBeginStatus KeepAliveCycle() {
|
||||
return std::visit([&](auto& backend) -> OpenXRBeginStatus { return backend->KeepAliveCycle(); }, backend_);
|
||||
}
|
||||
bool Shutdown() {
|
||||
return std::visit([&](auto& backend) -> bool { return backend->Shutdown(); }, backend_);
|
||||
}
|
||||
int64_t SwapchainFormat() {
|
||||
return std::visit([&](auto& backend) -> int64_t { return backend->SwapchainFormat(); }, backend_);
|
||||
}
|
||||
const std::string& LastError() {
|
||||
return std::visit([&](auto& backend) -> const std::string& { return backend->LastError(); }, backend_);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
#include "vr/openxr_input.h"
|
||||
#include "vr/openxr_runtime.h"
|
||||
#if defined(_WIN32)
|
||||
#include "vr/openxr_d3d12.h"
|
||||
#include "vr/openxr_windows.h"
|
||||
#define MKW_OPENXR_GRAPHICS_BACKEND 1
|
||||
#elif defined(__ANDROID__)
|
||||
#include "vr/openxr_android.h"
|
||||
@@ -78,8 +78,8 @@ void ConfigurePolicy(bool enabled) noexcept {
|
||||
#if MKW_OPENXR_GRAPHICS_BACKEND
|
||||
|
||||
#if defined(_WIN32)
|
||||
using GraphicsBackend = OpenXRD3D12Backend;
|
||||
inline constexpr const char* kGraphicsBackendName = "D3D12";
|
||||
using GraphicsBackend = OpenXRWindowsBackend;
|
||||
|
||||
#else
|
||||
using GraphicsBackend = OpenXRVulkanBackend;
|
||||
inline constexpr const char* kGraphicsBackendName = "Vulkan";
|
||||
@@ -360,7 +360,11 @@ public:
|
||||
}
|
||||
#endif
|
||||
runtime_ = std::make_unique<OpenXRRuntime>(logger_);
|
||||
#if defined(_WIN32)
|
||||
backend_ = std::make_unique<GraphicsBackend>(logger_, kRequiredAuroraBackend == BACKEND_VULKAN);
|
||||
#else
|
||||
backend_ = std::make_unique<GraphicsBackend>(logger_);
|
||||
#endif
|
||||
|
||||
OpenXRConfig config{};
|
||||
config.application_name = aurora_config.appName != nullptr ? aurora_config.appName
|
||||
@@ -368,7 +372,7 @@ public:
|
||||
config.engine_name = "Aurora";
|
||||
config.resolution_scale = RuntimeConfigFile::VrRenderScale();
|
||||
#if defined(_WIN32)
|
||||
config.required_extensions = {"XR_KHR_D3D12_enable"};
|
||||
config.required_extensions = {kRequiredAuroraBackend == BACKEND_VULKAN ? "XR_KHR_vulkan_enable2" : "XR_KHR_D3D12_enable"};
|
||||
config.optional_extensions = {"XR_KHR_win32_convert_performance_counter_time",
|
||||
"XR_FB_display_refresh_rate", "XR_EXT_performance_settings"};
|
||||
#else
|
||||
@@ -567,7 +571,8 @@ private:
|
||||
};
|
||||
|
||||
#if defined(_WIN32)
|
||||
static constexpr AuroraBackend kRequiredAuroraBackend = BACKEND_D3D12;
|
||||
AuroraBackend kRequiredAuroraBackend = BACKEND_D3D12;
|
||||
const char* kGraphicsBackendName = "D3D12";
|
||||
#else
|
||||
static constexpr AuroraBackend kRequiredAuroraBackend = BACKEND_VULKAN;
|
||||
#endif
|
||||
@@ -576,6 +581,10 @@ private:
|
||||
static constexpr uint32_t kMaxConsecutiveSkips = 300;
|
||||
|
||||
bool BackendMatchesConfiguredGraphicsApi(const AuroraConfig& aurora_config) {
|
||||
#if defined(_WIN32)
|
||||
kRequiredAuroraBackend = aurora_config.desiredBackend == BACKEND_VULKAN ? BACKEND_VULKAN : BACKEND_D3D12;
|
||||
kGraphicsBackendName = kRequiredAuroraBackend == BACKEND_VULKAN ? "Vulkan" : "D3D12";
|
||||
#endif
|
||||
if (aurora_config.desiredBackend == BACKEND_AUTO ||
|
||||
aurora_config.desiredBackend == kRequiredAuroraBackend) {
|
||||
return true;
|
||||
@@ -589,6 +598,7 @@ private:
|
||||
aurora_config.desiredBackend = kRequiredAuroraBackend;
|
||||
aurora_config.xrInterop = true;
|
||||
#if defined(_WIN32)
|
||||
if (kRequiredAuroraBackend != BACKEND_D3D12) return;
|
||||
const auto& requirements = backend_->GraphicsRequirements();
|
||||
aurora_config.hasD3D12AdapterLuid = true;
|
||||
aurora_config.d3d12AdapterLuidLow = requirements.adapter_luid_low;
|
||||
|
||||
@@ -724,6 +724,7 @@ bool OpenXRRuntime::BeginFrame(const OpenXRFrame& frame) {
|
||||
|
||||
XrFrameBeginInfo begin_info{XR_TYPE_FRAME_BEGIN_INFO};
|
||||
const XrResult result = diagnostics::Measure(diagnostics::Stage::BeginCall, [&] {
|
||||
const auto queue_guard = LockGraphicsQueue();
|
||||
return xrBeginFrame(m_session, &begin_info);
|
||||
});
|
||||
if (XR_FAILED(result)) {
|
||||
@@ -816,7 +817,10 @@ bool OpenXRRuntime::EndFrame(
|
||||
end_info.layerCount = layer_count;
|
||||
end_info.layers = layers;
|
||||
const diagnostics::Stopwatch end_timer;
|
||||
const XrResult result = xrEndFrame(m_session, &end_info);
|
||||
const XrResult result = [&] {
|
||||
const auto queue_guard = LockGraphicsQueue();
|
||||
return xrEndFrame(m_session, &end_info);
|
||||
}();
|
||||
diagnostics::OnEndFrame(end_timer);
|
||||
m_frame_phase = FramePhase::Idle;
|
||||
m_active_frame_serial = 0;
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,6 +1,23 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Exercise the real backend against a deterministic compositor and Aurora sink.
|
||||
// No headset, graphics driver, OpenXR loader, or translated game is required.
|
||||
#if defined(TEST_WINDOWS_VULKAN)
|
||||
#define XR_USE_GRAPHICS_API_VULKAN
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <openxr/openxr_platform.h>
|
||||
#include <aurora/vulkan_win32_interop.h>
|
||||
#include "vr/openxr_vulkan_win32.h"
|
||||
#define OpenXRD3D12Backend OpenXRWindowsVulkanBackend
|
||||
#define OpenXRD3D12BeginStatus OpenXRWindowsVulkanBeginStatus
|
||||
#define OpenXRD3D12SubmissionStatus OpenXRWindowsVulkanSubmissionStatus
|
||||
#define OpenXRD3D12Frame OpenXRWindowsVulkanFrame
|
||||
#define OpenXRD3D12Presentation OpenXRWindowsVulkanPresentation
|
||||
#define OpenXRD3D12FrameMode OpenXRWindowsVulkanFrameMode
|
||||
#define aurora_d3d12_enable_stereo_bridge aurora_vulkan_win32_enable
|
||||
#define aurora_d3d12_set_stereo_targets aurora_vulkan_win32_set_targets
|
||||
#define aurora_d3d12_cancel_stereo_targets aurora_vulkan_win32_cancel
|
||||
#define aurora_d3d12_disable_stereo_bridge aurora_vulkan_win32_disable
|
||||
#else
|
||||
#define CINTERFACE
|
||||
#define XR_USE_GRAPHICS_API_D3D12
|
||||
#ifndef NOMINMAX
|
||||
@@ -10,8 +27,10 @@
|
||||
#include <openxr/openxr_platform.h>
|
||||
#include <aurora/d3d12_interop.h>
|
||||
#include "vr/openxr_d3d12.h"
|
||||
#endif
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
@@ -65,6 +84,26 @@ void Complete(bool success = true) {
|
||||
encoded = false;
|
||||
}
|
||||
|
||||
#if defined(TEST_WINDOWS_VULKAN)
|
||||
AuroraDawnVulkanHooks hooks{};
|
||||
bool queue_locked = false;
|
||||
XrResult XRAPI_CALL Requirements(XrInstance, XrSystemId, XrGraphicsRequirementsVulkanKHR* out) {
|
||||
out->minApiVersionSupported = XR_MAKE_VERSION(1, 1, 0);
|
||||
out->maxApiVersionSupported = XR_MAKE_VERSION(1, 3, 0);
|
||||
return XR_SUCCESS;
|
||||
}
|
||||
XrResult XRAPI_CALL Physical(XrInstance, const XrVulkanGraphicsDeviceGetInfoKHR*, VkPhysicalDevice* out) {
|
||||
*out = reinterpret_cast<VkPhysicalDevice>(2); return XR_SUCCESS;
|
||||
}
|
||||
XrResult XRAPI_CALL CreateInstance(XrInstance, const XrVulkanInstanceCreateInfoKHR* info, VkInstance* out, VkResult* result) {
|
||||
Require(info->vulkanCreateInfo->pApplicationInfo->apiVersion >= VK_API_VERSION_1_1);
|
||||
*out = reinterpret_cast<VkInstance>(1); *result = VK_SUCCESS; return XR_SUCCESS;
|
||||
}
|
||||
XrResult XRAPI_CALL CreateDevice(XrInstance, const XrVulkanDeviceCreateInfoKHR* info, VkDevice* out, VkResult* result) {
|
||||
Require(info->vulkanPhysicalDevice == reinterpret_cast<VkPhysicalDevice>(2));
|
||||
*out = reinterpret_cast<VkDevice>(3); *result = VK_SUCCESS; return XR_SUCCESS;
|
||||
}
|
||||
#else
|
||||
HRESULT STDMETHODCALLTYPE FeatureSupport(ID3D12Device*, D3D12_FEATURE,
|
||||
void* data, UINT) {
|
||||
static_cast<D3D12_FEATURE_DATA_FEATURE_LEVELS*>(data)->MaxSupportedFeatureLevel =
|
||||
@@ -77,10 +116,28 @@ XrResult XRAPI_CALL Requirements(XrInstance, XrSystemId,
|
||||
requirements->minFeatureLevel = D3D_FEATURE_LEVEL_11_0;
|
||||
return XR_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// A COM vtable in its C representation supplies the single device operation
|
||||
// used by BindAurora. The production backend is compiled normally as C++.
|
||||
#if defined(TEST_WINDOWS_VULKAN)
|
||||
bool aurora_vulkan_win32_configure(const AuroraDawnVulkanHooks* value) {
|
||||
hooks = value ? *value : AuroraDawnVulkanHooks{}; return true;
|
||||
}
|
||||
bool aurora_vulkan_win32_get_handles(AuroraDawnVulkanHandles* handles, int64_t* format) {
|
||||
VkApplicationInfo app{VK_STRUCTURE_TYPE_APPLICATION_INFO};
|
||||
app.apiVersion = VK_API_VERSION_1_0;
|
||||
VkInstanceCreateInfo instance{VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO}; instance.pApplicationInfo = &app;
|
||||
Require(hooks.createInstance(hooks.userdata, nullptr, &instance, nullptr, &handles->instance) == VK_SUCCESS);
|
||||
Require(hooks.getPhysicalDevice(hooks.userdata, handles->instance, &handles->physicalDevice) == VK_SUCCESS);
|
||||
VkDeviceCreateInfo device{VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO};
|
||||
Require(hooks.createDevice(hooks.userdata, nullptr, handles->physicalDevice, &device, nullptr, &handles->device) == VK_SUCCESS);
|
||||
*format = VK_FORMAT_R8G8B8A8_UNORM; return true;
|
||||
}
|
||||
void* aurora_vulkan_win32_lock_queue() { Require(!queue_locked); queue_locked = true; return &queue_locked; }
|
||||
void aurora_vulkan_win32_unlock_queue(void*) { Require(queue_locked); queue_locked = false; }
|
||||
#else
|
||||
bool aurora_d3d12_get_native_handles(AuroraD3D12NativeHandles* handles) {
|
||||
static ID3D12DeviceVtbl vtable{};
|
||||
vtable.CheckFeatureSupport = FeatureSupport;
|
||||
@@ -88,6 +145,7 @@ bool aurora_d3d12_get_native_handles(AuroraD3D12NativeHandles* handles) {
|
||||
*handles = {&device, &device, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 0};
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
bool aurora_d3d12_enable_stereo_bridge(AuroraD3D12StereoSubmittedCallback cb, void* data) {
|
||||
callback = cb;
|
||||
callback_data = data;
|
||||
@@ -119,13 +177,21 @@ XrResult XRAPI_CALL xrCreateSwapchain(XrSession, const XrSwapchainCreateInfo*, X
|
||||
XrResult XRAPI_CALL xrEnumerateSwapchainImages(XrSwapchain handle, uint32_t capacity,
|
||||
uint32_t* count, XrSwapchainImageBaseHeader* images) {
|
||||
*count = 1; // Single-image swapchains also require a separate retained pair.
|
||||
#if defined(TEST_WINDOWS_VULKAN)
|
||||
if (capacity) reinterpret_cast<XrSwapchainImageVulkanKHR*>(images)->image =
|
||||
reinterpret_cast<VkImage>(&reinterpret_cast<Swapchain*>(handle)->image);
|
||||
#else
|
||||
if (capacity) reinterpret_cast<XrSwapchainImageD3D12KHR*>(images)->texture =
|
||||
reinterpret_cast<ID3D12Resource*>(&reinterpret_cast<Swapchain*>(handle)->image);
|
||||
#endif
|
||||
return XR_SUCCESS;
|
||||
}
|
||||
XrResult XRAPI_CALL xrAcquireSwapchainImage(XrSwapchain handle,
|
||||
const XrSwapchainImageAcquireInfo*, uint32_t* index) {
|
||||
auto& chain = *reinterpret_cast<Swapchain*>(handle);
|
||||
#if defined(TEST_WINDOWS_VULKAN)
|
||||
Require(queue_locked);
|
||||
#endif
|
||||
Require(!chain.acquired);
|
||||
chain.acquired = true;
|
||||
chain.waited = false;
|
||||
@@ -141,6 +207,9 @@ XrResult XRAPI_CALL xrWaitSwapchainImage(XrSwapchain handle, const XrSwapchainIm
|
||||
XrResult XRAPI_CALL xrReleaseSwapchainImage(XrSwapchain handle,
|
||||
const XrSwapchainImageReleaseInfo*) {
|
||||
auto& chain = *reinterpret_cast<Swapchain*>(handle);
|
||||
#if defined(TEST_WINDOWS_VULKAN)
|
||||
Require(queue_locked); // The runtime may touch Dawn's VkQueue here.
|
||||
#endif
|
||||
Require(chain.acquired && chain.waited);
|
||||
chain.acquired = false;
|
||||
chain.released = true;
|
||||
@@ -158,14 +227,24 @@ XrResult XRAPI_CALL xrDestroySwapchain(XrSwapchain handle) {
|
||||
namespace mkw::vr {
|
||||
OpenXRRuntime::OpenXRRuntime(OpenXRLogCallback) {
|
||||
m_instance = reinterpret_cast<XrInstance>(this);
|
||||
#if defined(TEST_WINDOWS_VULKAN)
|
||||
m_swapchain_formats = {VK_FORMAT_R8G8B8A8_SRGB};
|
||||
#else
|
||||
m_swapchain_formats = {DXGI_FORMAT_R8G8B8A8_UNORM_SRGB};
|
||||
#endif
|
||||
for (auto& view : m_view_configuration) {
|
||||
view.render_width = 100;
|
||||
view.render_height = 80;
|
||||
}
|
||||
}
|
||||
OpenXRRuntime::~OpenXRRuntime() = default;
|
||||
bool OpenXRRuntime::GetInstanceProcAddress(const char*, PFN_xrVoidFunction* out) {
|
||||
bool OpenXRRuntime::GetInstanceProcAddress(const char* name, PFN_xrVoidFunction* out) {
|
||||
#if defined(TEST_WINDOWS_VULKAN)
|
||||
if (std::strcmp(name, "xrCreateVulkanInstanceKHR") == 0) *out = reinterpret_cast<PFN_xrVoidFunction>(::CreateInstance);
|
||||
else if (std::strcmp(name, "xrCreateVulkanDeviceKHR") == 0) *out = reinterpret_cast<PFN_xrVoidFunction>(CreateDevice);
|
||||
else if (std::strcmp(name, "xrGetVulkanGraphicsDevice2KHR") == 0) *out = reinterpret_cast<PFN_xrVoidFunction>(Physical);
|
||||
else
|
||||
#endif
|
||||
*out = reinterpret_cast<PFN_xrVoidFunction>(Requirements);
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user