上传YomovSDK

This commit is contained in:
Sora丶kong
2026-03-03 03:15:46 +08:00
parent 9096da7e6c
commit eb97f31065
6477 changed files with 1932208 additions and 3 deletions

View File

@@ -0,0 +1,127 @@
#include "../mock.h"
#define CHECK_EXT() \
if (nullptr == s_ext) \
return XR_ERROR_FUNCTION_UNSUPPORTED;
struct ConformanceAutomation
{
std::map<XrPath, MockInputState> states;
std::map<std::pair<XrPath, XrPath>, bool> activeStates;
MockInputState& GetState(XrPath path, XrActionType actionType)
{
auto it = states.find(path);
if (it != states.end())
return it->second;
MockInputState& state = states[path];
state.type = actionType;
return state;
}
};
static ConformanceAutomation* s_ext = nullptr;
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrSetInputDeviceActiveEXT(XrSession session, XrPath interactionProfile, XrPath topLevelPath, XrBool32 isActive)
{
LOG_FUNC();
CHECK_RUNTIME();
CHECK_EXT();
s_ext->activeStates[std::pair<XrPath, XrPath>(interactionProfile, topLevelPath)] = isActive;
return XR_SUCCESS;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrSetInputDeviceStateBoolEXT(XrSession session, XrPath topLevelPath, XrPath inputSourcePath, XrBool32 state)
{
LOG_FUNC();
CHECK_EXT();
s_ext->GetState(inputSourcePath, XR_ACTION_TYPE_BOOLEAN_INPUT).Set(state);
return XR_SUCCESS;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrSetInputDeviceStateFloatEXT(XrSession session, XrPath topLevelPath, XrPath inputSourcePath, float state)
{
LOG_FUNC();
CHECK_EXT();
CHECK_SESSION(session);
s_ext->GetState(inputSourcePath, XR_ACTION_TYPE_FLOAT_INPUT).Set(state);
return XR_SUCCESS;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrSetInputDeviceStateVector2fEXT(XrSession session, XrPath topLevelPath, XrPath inputSourcePath, XrVector2f state)
{
LOG_FUNC();
CHECK_EXT();
s_ext->GetState(inputSourcePath, XR_ACTION_TYPE_VECTOR2F_INPUT).Set(state);
return XR_SUCCESS;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrSetInputDeviceLocationEXT(XrSession session, XrPath topLevelPath, XrPath inputSourcePath, XrSpace space, XrPosef pose)
{
LOG_FUNC();
CHECK_EXT();
s_ext->GetState(inputSourcePath, XR_ACTION_TYPE_POSE_INPUT).Set(space, pose);
return XR_SUCCESS;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrSetInputDeviceVelocityUNITY(XrSession session, XrPath topLevelPath, XrPath inputSourcePath, bool linearValid, XrVector3f linear, bool angularValid, XrVector3f angular)
{
LOG_FUNC();
CHECK_EXT();
s_ext->GetState(inputSourcePath, XR_ACTION_TYPE_POSE_INPUT).SetVelocity(linearValid, linear, angularValid, angular);
return XR_SUCCESS;
}
void ConformanceAutomation_Create()
{
// Make sure there is no orphaned extension
ConformanceAutomation_Destroy();
s_ext = new ConformanceAutomation();
}
void ConformanceAutomation_Destroy()
{
delete s_ext;
s_ext = nullptr;
}
XrResult ConformanceAutomation_GetInstanceProcAddr(const char* name, PFN_xrVoidFunction* function)
{
CHECK_EXT();
GET_PROC_ADDRESS(xrSetInputDeviceActiveEXT)
GET_PROC_ADDRESS(xrSetInputDeviceStateBoolEXT)
GET_PROC_ADDRESS(xrSetInputDeviceStateFloatEXT)
GET_PROC_ADDRESS(xrSetInputDeviceStateVector2fEXT)
GET_PROC_ADDRESS(xrSetInputDeviceLocationEXT)
GET_PROC_ADDRESS(xrSetInputDeviceVelocityUNITY)
return XR_ERROR_FUNCTION_UNSUPPORTED;
}
XrResult ConformanceAutomation_GetInputState(MockInputState* state)
{
CHECK_EXT();
auto it = s_ext->states.find(state->path);
if (it == s_ext->states.end())
return XR_ERROR_HANDLE_INVALID;
state->CopyValue(it->second);
return XR_SUCCESS;
}
bool ConformanceAutomation_IsActive(XrPath interactionProfilePath, XrPath userPath, bool defaultValue)
{
if (nullptr == s_ext)
return false;
auto active = s_ext->activeStates.find(std::pair<XrPath, XrPath>(interactionProfilePath, userPath));
if (active == s_ext->activeStates.end())
active = s_ext->activeStates.find(std::pair<XrPath, XrPath>(XR_NULL_PATH, userPath));
return (active != s_ext->activeStates.end()) ? active->second : defaultValue;
}
#undef CHECK_EXT

View File

@@ -0,0 +1,187 @@
#include "../mock.h"
#if defined(XR_USE_GRAPHICS_API_D3D11)
struct MockD3D11
{
ID3D11Device* device = nullptr;
};
static MockD3D11 s_MockD3D11 = {};
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrGetD3D11GraphicsRequirementsKHR(
XrInstance instance,
XrSystemId systemId,
XrGraphicsRequirementsD3D11KHR* graphicsRequirements)
{
IDXGIAdapter* pAdapter;
std::vector<IDXGIAdapter*> vAdapters;
IDXGIFactory* pFactory = NULL;
// Create a DXGIFactory object.
if (FAILED(CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&pFactory)))
return XR_ERROR_RUNTIME_FAILURE;
XrResult xrresult = XR_ERROR_RUNTIME_FAILURE;
graphicsRequirements->adapterLuid = {};
for (UINT i = 0; pFactory->EnumAdapters(i, &pAdapter) != DXGI_ERROR_NOT_FOUND; ++i)
{
DXGI_ADAPTER_DESC desc = {};
pAdapter->GetDesc(&desc);
graphicsRequirements->adapterLuid = desc.AdapterLuid;
xrresult = XR_SUCCESS;
break;
}
if (pFactory)
pFactory->Release();
return xrresult;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR MockD3D11_xrEnumerateSwapchainFormats(XrSession session, uint32_t formatCapacityInput, uint32_t* formatCountOutput, int64_t* formats)
{
if (nullptr == formatCountOutput)
return XR_ERROR_VALIDATION_FAILURE;
*formatCountOutput = 6;
if (formatCapacityInput == 0)
return XR_SUCCESS;
if (nullptr == formats)
return XR_ERROR_VALIDATION_FAILURE;
if (formatCapacityInput < 6)
return XR_ERROR_SIZE_INSUFFICIENT;
formats[0] = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
formats[1] = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
formats[2] = DXGI_FORMAT_R8G8B8A8_UNORM;
formats[3] = DXGI_FORMAT_B8G8R8A8_UNORM;
formats[4] = DXGI_FORMAT_D16_UNORM;
formats[5] = DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
return XR_SUCCESS;
}
static XrResult MockD3D11_xrCreateSwapchain(XrSession session, const XrSwapchainCreateInfo* createInfo, XrSwapchain* swapchain)
{
if (nullptr == s_MockD3D11.device)
return XR_ERROR_RUNTIME_FAILURE;
ID3D11Texture2D* texture;
D3D11_TEXTURE2D_DESC desc = {};
desc.Width = createInfo->width;
desc.Height = createInfo->height;
desc.MipLevels = createInfo->mipCount;
desc.ArraySize = createInfo->arraySize;
desc.SampleDesc.Count = createInfo->sampleCount;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
if (createInfo->usageFlags & XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)
{
if (createInfo->format == DXGI_FORMAT_D16_UNORM)
desc.Format = DXGI_FORMAT_R16_TYPELESS;
else
desc.Format = DXGI_FORMAT_R32G8X24_TYPELESS;
desc.BindFlags |= D3D11_BIND_DEPTH_STENCIL;
}
else
{
desc.BindFlags |= D3D11_BIND_RENDER_TARGET;
desc.Format = DXGI_FORMAT_R8G8B8A8_TYPELESS;
desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
}
if (FAILED(s_MockD3D11.device->CreateTexture2D(&desc, NULL, &texture)))
return XR_ERROR_RUNTIME_FAILURE;
*swapchain = (XrSwapchain)texture;
return XR_SUCCESS;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR MockD3D11_xrCreateSwapchainHook(XrSession session, const XrSwapchainCreateInfo* createInfo, XrSwapchain* swapchain)
{
LOG_FUNC();
MOCK_HOOK_NAMED("xrCreateSwapchain", MockD3D11_xrCreateSwapchain(session, createInfo, swapchain));
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR MockD3D11_xrDestroySwapChain(XrSwapchain swapchain)
{
ID3D11Texture2D* texture = (ID3D11Texture2D*)swapchain;
texture->Release();
return XR_SUCCESS;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR MockD3D11_xrEnumerateSwapchainImages(XrSwapchain swapchain, uint32_t imageCapacityInput, uint32_t* imageCountOutput, XrSwapchainImageBaseHeader* images)
{
LOG_FUNC();
*imageCountOutput = 1;
if (images == nullptr)
return XR_SUCCESS;
if (imageCapacityInput < *imageCountOutput)
return XR_ERROR_VALIDATION_FAILURE;
XrSwapchainImageD3D11KHR* d3d11images = (XrSwapchainImageD3D11KHR*)images;
d3d11images[0].texture = (ID3D11Texture2D*)swapchain;
return XR_SUCCESS;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR MockD3D11_xrAcquireSwapchainImage(XrSwapchain swapchain, const XrSwapchainImageAcquireInfo* acquireInfo, uint32_t* index)
{
LOG_FUNC();
*index = 0;
return XR_SUCCESS;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR MockD3D11_xrReleaseSwapchainImage(XrSwapchain swapchain, const XrSwapchainImageReleaseInfo* releaseInfo)
{
LOG_FUNC();
return XR_SUCCESS;
}
/// <summary>
/// Hook xrCreateSession to get the necessary D3D11 handles
/// </summary>
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrCreateSession(XrInstance instance, const XrSessionCreateInfo* createInfo, XrSession* session);
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR MockD3D11_xrCreateSession(XrInstance instance, const XrSessionCreateInfo* createInfo, XrSession* session)
{
s_MockD3D11 = {};
if (createInfo->next != nullptr)
{
XrGraphicsBindingD3D11KHR* bindings = (XrGraphicsBindingD3D11KHR*)createInfo->next;
if (bindings->type == XR_TYPE_GRAPHICS_BINDING_D3D11_KHR)
{
s_MockD3D11.device = bindings->device;
}
}
return xrCreateSession(instance, createInfo, session);
}
XrResult MockD3D11_GetInstanceProcAddr(const char* name, PFN_xrVoidFunction* function)
{
LOG_FUNC();
GET_PROC_ADDRESS_REMAP(xrCreateSession, MockD3D11_xrCreateSession)
GET_PROC_ADDRESS_REMAP(xrEnumerateSwapchainFormats, MockD3D11_xrEnumerateSwapchainFormats)
GET_PROC_ADDRESS_REMAP(xrCreateSwapchain, MockD3D11_xrCreateSwapchainHook)
GET_PROC_ADDRESS_REMAP(xrDestroySwapChain, MockD3D11_xrDestroySwapChain)
GET_PROC_ADDRESS_REMAP(xrEnumerateSwapchainImages, MockD3D11_xrEnumerateSwapchainImages)
GET_PROC_ADDRESS_REMAP(xrAcquireSwapchainImage, MockD3D11_xrAcquireSwapchainImage)
GET_PROC_ADDRESS_REMAP(xrReleaseSwapchainImage, MockD3D11_xrReleaseSwapchainImage)
GET_PROC_ADDRESS(xrGetD3D11GraphicsRequirementsKHR)
return XR_ERROR_FUNCTION_UNSUPPORTED;
}
#endif

View File

@@ -0,0 +1,207 @@
#include "../mock.h"
#if defined(XR_USE_GRAPHICS_API_D3D12)
struct MockD3D12
{
ID3D12Device* device = nullptr;
};
static MockD3D12 s_MockD3D12 = {};
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrGetD3D12GraphicsRequirementsKHR(
XrInstance instance,
XrSystemId systemId,
XrGraphicsRequirementsD3D12KHR* graphicsRequirements)
{
IDXGIAdapter* pAdapter;
std::vector<IDXGIAdapter*> vAdapters;
IDXGIFactory* pFactory = NULL;
// Create a DXGIFactory object.
if (FAILED(CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&pFactory)))
return XR_ERROR_RUNTIME_FAILURE;
XrResult xrresult = XR_ERROR_RUNTIME_FAILURE;
graphicsRequirements->adapterLuid = {};
for (UINT i = 0; pFactory->EnumAdapters(i, &pAdapter) != DXGI_ERROR_NOT_FOUND; ++i)
{
DXGI_ADAPTER_DESC desc = {};
pAdapter->GetDesc(&desc);
graphicsRequirements->adapterLuid = desc.AdapterLuid;
xrresult = XR_SUCCESS;
break;
}
if (pFactory)
pFactory->Release();
return xrresult;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR MockD3D12_xrEnumerateSwapchainFormats(XrSession session, uint32_t formatCapacityInput, uint32_t* formatCountOutput, int64_t* formats)
{
if (nullptr == formatCountOutput)
return XR_ERROR_VALIDATION_FAILURE;
*formatCountOutput = 6;
if (formatCapacityInput == 0)
return XR_SUCCESS;
if (nullptr == formats)
return XR_ERROR_VALIDATION_FAILURE;
if (formatCapacityInput < 6)
return XR_ERROR_SIZE_INSUFFICIENT;
formats[0] = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
formats[1] = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
formats[2] = DXGI_FORMAT_R8G8B8A8_UNORM;
formats[3] = DXGI_FORMAT_B8G8R8A8_UNORM;
formats[4] = DXGI_FORMAT_D16_UNORM;
formats[5] = DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
return XR_SUCCESS;
}
static XrResult MockD3D12_xrCreateSwapchain(XrSession session, const XrSwapchainCreateInfo* createInfo, XrSwapchain* swapchain)
{
if (nullptr == s_MockD3D12.device)
{
MOCK_TRACE_DEBUG("Mock device is null");
return XR_ERROR_RUNTIME_FAILURE;
}
D3D12_HEAP_PROPERTIES heapProps{};
heapProps.Type = D3D12_HEAP_TYPE_DEFAULT;
heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
D3D12_RESOURCE_DESC desc{};
desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
desc.Width = createInfo->width;
desc.Height = createInfo->height;
desc.MipLevels = createInfo->mipCount;
desc.DepthOrArraySize = createInfo->arraySize;
desc.SampleDesc.Count = createInfo->sampleCount;
desc.SampleDesc.Quality = 0;
desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
if (createInfo->usageFlags & XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)
{
if (createInfo->format == DXGI_FORMAT_D16_UNORM)
desc.Format = DXGI_FORMAT_R16_TYPELESS;
else
desc.Format = DXGI_FORMAT_R32G8X24_TYPELESS;
desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
}
else
{
desc.Format = DXGI_FORMAT_R8G8B8A8_TYPELESS;
}
ID3D12Resource* texture;
const HRESULT result = s_MockD3D12.device->CreateCommittedResource(
&heapProps,
D3D12_HEAP_FLAG_NONE,
&desc,
D3D12_RESOURCE_STATE_RENDER_TARGET,
nullptr,
IID_PPV_ARGS(&texture));
if (FAILED(result))
{
MOCK_TRACE_DEBUG("ID3D12Device::CreateCommittedResource failed, HRESULT: 0x%08x", result);
return XR_ERROR_RUNTIME_FAILURE;
}
else
{
MOCK_TRACE_DEBUG("ID3D12Device::CreateCommittedResource success");
}
*swapchain = (XrSwapchain)texture;
return XR_SUCCESS;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR MockD3D12_xrCreateSwapchainHook(XrSession session, const XrSwapchainCreateInfo* createInfo, XrSwapchain* swapchain)
{
LOG_FUNC();
MOCK_HOOK_NAMED("xrCreateSwapchain", MockD3D12_xrCreateSwapchain(session, createInfo, swapchain));
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR MockD3D12_xrDestroySwapChain(XrSwapchain swapchain)
{
ID3D12Resource* texture = (ID3D12Resource*)swapchain;
texture->Release();
return XR_SUCCESS;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR MockD3D12_xrEnumerateSwapchainImages(XrSwapchain swapchain, uint32_t imageCapacityInput, uint32_t* imageCountOutput, XrSwapchainImageBaseHeader* images)
{
LOG_FUNC();
*imageCountOutput = 1;
if (images == nullptr)
return XR_SUCCESS;
if (imageCapacityInput < *imageCountOutput)
return XR_ERROR_VALIDATION_FAILURE;
XrSwapchainImageD3D12KHR* d3d12images = (XrSwapchainImageD3D12KHR*)images;
d3d12images[0].texture = (ID3D12Resource*)swapchain;
return XR_SUCCESS;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR MockD3D12_xrAcquireSwapchainImage(XrSwapchain swapchain, const XrSwapchainImageAcquireInfo* acquireInfo, uint32_t* index)
{
LOG_FUNC();
*index = 0;
return XR_SUCCESS;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR MockD3D12_xrReleaseSwapchainImage(XrSwapchain swapchain, const XrSwapchainImageReleaseInfo* releaseInfo)
{
LOG_FUNC();
return XR_SUCCESS;
}
/// <summary>
/// Hook xrCreateSession to get the necessary D3D12 handles
/// </summary>
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrCreateSession(XrInstance instance, const XrSessionCreateInfo* createInfo, XrSession* session);
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR MockD3D12_xrCreateSession(XrInstance instance, const XrSessionCreateInfo* createInfo, XrSession* session)
{
s_MockD3D12 = {};
if (createInfo->next != nullptr)
{
XrGraphicsBindingD3D12KHR* bindings = (XrGraphicsBindingD3D12KHR*)createInfo->next;
if (bindings->type == XR_TYPE_GRAPHICS_BINDING_D3D12_KHR)
{
s_MockD3D12.device = bindings->device;
}
}
return xrCreateSession(instance, createInfo, session);
}
XrResult MockD3D12_GetInstanceProcAddr(const char* name, PFN_xrVoidFunction* function)
{
LOG_FUNC();
GET_PROC_ADDRESS_REMAP(xrCreateSession, MockD3D12_xrCreateSession)
GET_PROC_ADDRESS_REMAP(xrEnumerateSwapchainFormats, MockD3D12_xrEnumerateSwapchainFormats)
GET_PROC_ADDRESS_REMAP(xrCreateSwapchain, MockD3D12_xrCreateSwapchainHook)
GET_PROC_ADDRESS_REMAP(xrDestroySwapChain, MockD3D12_xrDestroySwapChain)
GET_PROC_ADDRESS_REMAP(xrEnumerateSwapchainImages, MockD3D12_xrEnumerateSwapchainImages)
GET_PROC_ADDRESS_REMAP(xrAcquireSwapchainImage, MockD3D12_xrAcquireSwapchainImage)
GET_PROC_ADDRESS_REMAP(xrReleaseSwapchainImage, MockD3D12_xrReleaseSwapchainImage)
GET_PROC_ADDRESS(xrGetD3D12GraphicsRequirementsKHR)
return XR_ERROR_FUNCTION_UNSUPPORTED;
}
#endif

View File

@@ -0,0 +1,82 @@
#include "mock_khr_android_thread_settings.h"
#ifdef XR_USE_PLATFORM_ANDROID
#define CHECK_EXT_INIT() \
if (nullptr == MockAndroidThreadSettings::Instance()) \
return XR_ERROR_FUNCTION_UNSUPPORTED;
std::unique_ptr<MockAndroidThreadSettings> MockAndroidThreadSettings::s_Instance;
MockAndroidThreadSettings* MockAndroidThreadSettings::Instance()
{
return s_Instance.get();
}
void MockAndroidThreadSettings::Init(MockRuntime& runtime)
{
s_Instance.reset(new MockAndroidThreadSettings(runtime));
}
void MockAndroidThreadSettings::Deinit()
{
s_Instance.reset();
}
MockAndroidThreadSettings::MockAndroidThreadSettings(MockRuntime& runtime)
: m_Runtime{runtime}
{
}
XrResult MockAndroidThreadSettings::SetAndroidApplicationThread(XrAndroidThreadTypeKHR threadType, uint32_t threadId)
{
m_AssignedThreadTypes[threadId] = threadType;
return XR_SUCCESS;
}
bool MockAndroidThreadSettings::IsAndroidThreadTypeRegistered(XrAndroidThreadTypeKHR threadType) const
{
for (auto i = m_AssignedThreadTypes.cbegin(); i != m_AssignedThreadTypes.cend(); ++i)
{
if (i->second == threadType)
{
return true;
}
}
return false;
}
uint32_t MockAndroidThreadSettings::GetRegisteredAndroidThreadsCount() const
{
return m_AssignedThreadTypes.size();
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR
xrSetAndroidApplicationThreadKHR(
XrSession session,
XrAndroidThreadTypeKHR threadType,
uint32_t threadId)
{
LOG_FUNC();
CHECK_SESSION(session);
CHECK_EXT_INIT();
MOCK_HOOK_BEFORE();
const XrResult result =
MockAndroidThreadSettings::Instance()->SetAndroidApplicationThread(
threadType,
threadId);
MOCK_HOOK_AFTER(result);
return result;
}
XrResult MockAndroidThreadSettings_GetInstanceProcAddr(const char* name, PFN_xrVoidFunction* function)
{
GET_PROC_ADDRESS(xrSetAndroidApplicationThreadKHR)
return XR_ERROR_FEATURE_UNSUPPORTED;
}
#undef CHECK_EXT_INIT
#endif // XR_USE_PLATFORM_ANDROID

View File

@@ -0,0 +1,29 @@
#pragma once
#include "../mock.h"
#include <map>
#include <memory>
#ifdef XR_USE_PLATFORM_ANDROID
class MockAndroidThreadSettings
{
public:
static MockAndroidThreadSettings* Instance();
static void Init(MockRuntime& runtime);
static void Deinit();
MockAndroidThreadSettings(MockRuntime& runtime);
XrResult SetAndroidApplicationThread(XrAndroidThreadTypeKHR threadType, uint32_t threadId);
bool IsAndroidThreadTypeRegistered(XrAndroidThreadTypeKHR threadType) const;
uint32_t GetRegisteredAndroidThreadsCount() const;
private:
static std::unique_ptr<MockAndroidThreadSettings> s_Instance;
MockRuntime& m_Runtime;
std::map<uint32_t, XrAndroidThreadTypeKHR> m_AssignedThreadTypes{};
};
XrResult MockAndroidThreadSettings_GetInstanceProcAddr(const char* name, PFN_xrVoidFunction* function);
#endif

View File

@@ -0,0 +1,304 @@
#include "mock_meta_performance_metrics.h"
#include "../mock.h"
#include <sstream>
#define CHECK_EXT() \
if (nullptr == MockMetaPerformanceMetrics::Instance()) \
return XR_ERROR_FUNCTION_UNSUPPORTED;
// storage for static
std::unique_ptr<MockMetaPerformanceMetrics> MockMetaPerformanceMetrics::s_ext;
enum class MockMetaPerformanceMetrics::InternalPaths : int
{
Invalid = 0,
AppCPUFrametime,
AppGPUFrametime,
AppMotionToPhotonLatency,
CompositorCPUFrametime,
CompositorGPUFrametime,
CompositorDroppedFrameCount,
CompositorSpacewarpMode,
DeviceCPUUtilizationAvg,
DeviceCPUUtilizationWorst,
DeviceGPUUtilization,
};
namespace
{
constexpr char kAppCPUFrametimeStr[] = "/perfmetrics_meta/app/cpu_frametime";
constexpr char kAppGPUFrametimeStr[] = "/perfmetrics_meta/app/gpu_frametime";
constexpr char kAppMotionToPhotonLatencyStr[] = "/perfmetrics_meta/app/motion_to_photon_latency";
constexpr char kCompositorCPUFrametimeStr[] = "/perfmetrics_meta/compositor/cpu_frametime";
constexpr char kCompositorGPUFrametimeStr[] = "/perfmetrics_meta/compositor/gpu_frametime";
constexpr char kCompositorDroppedFrameCountStr[] = "/perfmetrics_meta/compositor/dropped_frame_count";
constexpr char kCompositorSpacewarpModeStr[] = "/perfmetrics_meta/compositor/spacewarp_mode";
constexpr char kDeviceCPUUtilizationAvgStr[] = "/perfmetrics_meta/device/cpu_utilization_average";
constexpr char kDeviceCPUUtilizationWorstStr[] = "/perfmetrics_meta/device/cpu_utilization_worst";
constexpr char kDeviceGPUUtilizationStr[] = "/perfmetrics_meta/device/gpu_utilization";
} // namespace
MockMetaPerformanceMetrics::InternalPaths MockMetaPerformanceMetrics::InternalPathFromString(
const std::string& s)
{
if (s == kAppCPUFrametimeStr)
return InternalPaths::AppCPUFrametime;
if (s == kAppGPUFrametimeStr)
return InternalPaths::AppGPUFrametime;
if (s == kAppMotionToPhotonLatencyStr)
return InternalPaths::AppMotionToPhotonLatency;
if (s == kCompositorCPUFrametimeStr)
return InternalPaths::CompositorCPUFrametime;
if (s == kCompositorGPUFrametimeStr)
return InternalPaths::CompositorGPUFrametime;
if (s == kCompositorDroppedFrameCountStr)
return InternalPaths::CompositorDroppedFrameCount;
if (s == kCompositorSpacewarpModeStr)
return InternalPaths::CompositorSpacewarpMode;
if (s == kDeviceCPUUtilizationAvgStr)
return InternalPaths::DeviceCPUUtilizationAvg;
if (s == kDeviceCPUUtilizationWorstStr)
return InternalPaths::DeviceCPUUtilizationWorst;
if (s == kDeviceGPUUtilizationStr)
return InternalPaths::DeviceGPUUtilization;
return InternalPaths::Invalid;
}
MockMetaPerformanceMetrics::MockMetaPerformanceMetrics(MockRuntime& runtime, const int numMockCPUs)
: m_NumMockCPUs{numMockCPUs}
, m_Runtime{runtime}
{
static constexpr const char* k_ListPaths[] = {
kAppCPUFrametimeStr,
kAppGPUFrametimeStr,
kAppMotionToPhotonLatencyStr,
kCompositorCPUFrametimeStr,
kCompositorGPUFrametimeStr,
kCompositorDroppedFrameCountStr,
kCompositorSpacewarpModeStr,
kDeviceCPUUtilizationAvgStr,
kDeviceCPUUtilizationWorstStr,
kDeviceGPUUtilizationStr,
};
for (const char* const pathString : k_ListPaths)
{
const XrPath path = runtime.StringToPath(pathString);
m_Paths[path] = InternalPathFromString(pathString);
}
for (int i = 0; i < m_NumMockCPUs; i++)
{
std::stringstream ss{"/perfmetrics_meta/device/cpu"};
ss << i << "_utilization";
std::string pathString = ss.str();
const XrPath path = runtime.StringToPath(pathString.c_str());
m_Paths[path] = InternalPathFromString(pathString);
}
}
void MockMetaPerformanceMetrics::Init(MockRuntime& runtime, const int numMockCPUs)
{
s_ext.reset(new MockMetaPerformanceMetrics(runtime, numMockCPUs));
}
void MockMetaPerformanceMetrics::Deinit()
{
s_ext.reset();
}
MockMetaPerformanceMetrics* MockMetaPerformanceMetrics::Instance()
{
return s_ext.get();
}
XrResult MockMetaPerformanceMetrics::EnumeratePaths(
XrInstance instance,
uint32_t counterPathCapacityInput,
uint32_t* counterPathCountOutput,
XrPath* counterPaths)
{
*counterPathCountOutput = static_cast<uint32_t>(m_Paths.size());
if (counterPathCapacityInput >= *counterPathCountOutput)
{
int i = 0;
for (const auto kv : m_Paths)
{
counterPaths[i] = kv.first;
i++;
}
}
return XR_SUCCESS;
}
XrResult MockMetaPerformanceMetrics::SetState(XrSession session, const XrPerformanceMetricsStateMETA* state)
{
if (!state || state->type != XR_TYPE_PERFORMANCE_METRICS_STATE_META)
{
return XR_ERROR_VALIDATION_FAILURE;
}
m_Enabled = state->enabled == XR_TRUE;
return XR_SUCCESS;
}
XrResult MockMetaPerformanceMetrics::GetState(XrSession session, XrPerformanceMetricsStateMETA* state)
{
if (!state || state->type != XR_TYPE_PERFORMANCE_METRICS_STATE_META)
{
return XR_ERROR_VALIDATION_FAILURE;
}
state->enabled = m_Enabled ? XR_TRUE : XR_FALSE;
return XR_SUCCESS;
}
XrResult MockMetaPerformanceMetrics::QueryCounter(
XrSession session,
XrPath counterPath,
XrPerformanceMetricsCounterMETA* counter)
{
if (!m_Enabled || !counter || counter->type != XR_TYPE_PERFORMANCE_METRICS_COUNTER_META)
{
// disabled state return value confirmed by Xiang Wei @ Meta.
return XR_ERROR_VALIDATION_FAILURE;
}
std::list<MockResult>& values = m_SeededResults[m_Paths[counterPath]];
if (values.empty())
{
if (!m_NoResultsSeededWarningShown)
{
m_NoResultsSeededWarningShown = true;
MOCK_TRACE_DEBUG("No results were seeded for the requested stat. If you aren't testing stats, ignore this warning.");
}
*counter = m_DefaultResult.value;
return m_DefaultResult.rv;
}
// FIFO, fill in the counter struct and return the seeded return value.
*counter = values.front().value;
XrResult rv = values.front().rv;
values.pop_front();
return rv;
}
void MockMetaPerformanceMetrics::SeedCounterOnce(const std::string& counterPathString, MockResult result)
{
const XrPath path = m_Runtime.StringToPath(counterPathString.c_str());
if (path == XR_NULL_PATH)
{
// providing an invalid path during testing shouldn't happen, kill and warn our dev
// if you want to test whether a path exists, use the runtime functions themselves.
MOCK_TRACE_ERROR("Could not find path %s", counterPathString.c_str());
return;
}
if (result.value.type != XR_TYPE_PERFORMANCE_METRICS_COUNTER_META)
{
MOCK_TRACE_ERROR(
"Invalid or no type supplied for XrPerformanceMetricsCounterMETA. Type MUST be"
" XR_TYPE_PERFORMANCE_METRICS_COUNTER_META.");
return;
}
if (result.value.next != nullptr)
{
MOCK_TRACE_ERROR(
"This structure does not currently support chaining (`next` should be `nullptr`).");
return;
}
std::list<MockResult>& values = m_SeededResults[m_Paths[path]];
values.push_back(result);
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR
xrEnumeratePerformanceMetricsCounterPathsMETA(
XrInstance instance,
uint32_t counterPathCapacityInput,
uint32_t* counterPathCountOutput,
XrPath* counterPaths)
{
LOG_FUNC();
CHECK_RUNTIME();
CHECK_INSTANCE(instance);
CHECK_EXT();
MOCK_HOOK_BEFORE();
const XrResult result =
MockMetaPerformanceMetrics::Instance()->EnumeratePaths(
instance,
counterPathCapacityInput,
counterPathCountOutput,
counterPaths);
MOCK_HOOK_AFTER(result);
return result;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR
xrSetPerformanceMetricsStateMETA(
XrSession session,
const XrPerformanceMetricsStateMETA* state)
{
LOG_FUNC();
CHECK_SESSION(session);
CHECK_EXT();
MOCK_HOOK_BEFORE();
const XrResult result = MockMetaPerformanceMetrics::Instance()->SetState(session, state);
MOCK_HOOK_AFTER(result);
return result;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR
xrGetPerformanceMetricsStateMETA(
XrSession session,
XrPerformanceMetricsStateMETA* state)
{
LOG_FUNC();
CHECK_SESSION(session);
CHECK_EXT();
MOCK_HOOK_BEFORE();
const XrResult result = MockMetaPerformanceMetrics::Instance()->GetState(session, state);
MOCK_HOOK_AFTER(result);
return result;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR
xrQueryPerformanceMetricsCounterMETA(
XrSession session,
XrPath counterPath,
XrPerformanceMetricsCounterMETA* counter)
{
LOG_FUNC();
CHECK_SESSION(session);
CHECK_EXT();
MOCK_HOOK_BEFORE();
const XrResult result =
MockMetaPerformanceMetrics::Instance()->QueryCounter(
session,
counterPath,
counter);
MOCK_HOOK_AFTER(result);
return result;
}
XrResult MockMetaPerformanceMetrics_GetInstanceProcAddr(const char* name, PFN_xrVoidFunction* function)
{
GET_PROC_ADDRESS(xrEnumeratePerformanceMetricsCounterPathsMETA)
GET_PROC_ADDRESS(xrSetPerformanceMetricsStateMETA)
GET_PROC_ADDRESS(xrGetPerformanceMetricsStateMETA)
GET_PROC_ADDRESS(xrQueryPerformanceMetricsCounterMETA)
return XR_ERROR_FUNCTION_UNSUPPORTED;
}
#undef CHECK_EXT

View File

@@ -0,0 +1,73 @@
// Mock extension for XR_META_performance_metrics extension
// https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#XR_META_performance_metrics
#pragma once
#include "openxr/openxr.h"
#include <list>
#include <map>
#include <memory>
#include <string>
#include <unordered_map>
class MockRuntime;
class MockMetaPerformanceMetrics
{
public:
enum class InternalPaths : int;
struct MockResult
{
XrResult rv;
XrPerformanceMetricsCounterMETA value;
};
static void Init(MockRuntime& runtime, const int numMockCPUs);
static void Deinit();
static MockMetaPerformanceMetrics* Instance();
static InternalPaths InternalPathFromString(const std::string& s);
XrResult EnumeratePaths(
XrInstance instance,
uint32_t counterPathCapacityInput,
uint32_t* counterPathCountOutput,
XrPath* counterPaths);
XrResult SetState(XrSession session, const XrPerformanceMetricsStateMETA* state);
XrResult GetState(XrSession session, XrPerformanceMetricsStateMETA* state);
XrResult QueryCounter(
XrSession session,
XrPath counterPath,
XrPerformanceMetricsCounterMETA* counter);
void SeedCounterOnce(const std::string& counterPath, MockResult result);
private:
MockMetaPerformanceMetrics(MockRuntime& runtime, const int numMockCPUs);
static std::unique_ptr<MockMetaPerformanceMetrics> s_ext;
MockRuntime& m_Runtime;
const int m_NumMockCPUs;
// we use an ordered set just to keep things consistent for enumeration
std::map<XrPath, InternalPaths> m_Paths;
bool m_Enabled;
bool m_NoResultsSeededWarningShown;
std::map<InternalPaths, std::list<MockResult>> m_SeededResults;
MockResult m_DefaultResult{
XR_SUCCESS,
{
XR_TYPE_PERFORMANCE_METRICS_COUNTER_META,
nullptr,
XR_PERFORMANCE_METRICS_COUNTER_ANY_VALUE_VALID_BIT_META,
XR_PERFORMANCE_METRICS_COUNTER_UNIT_GENERIC_META,
0,
0.f,
}};
};
XrResult MockMetaPerformanceMetrics_GetInstanceProcAddr(const char* name, PFN_xrVoidFunction* function);

View File

@@ -0,0 +1,21 @@
#include "../mock.h"
XrResult MockRuntime::MSFTFirstPersonObserver_Init()
{
MockViewConfiguration firstPersonConfig = {};
firstPersonConfig.primary = false;
firstPersonConfig.enabled = false;
firstPersonConfig.active = false;
firstPersonConfig.stateFlags = XR_VIEW_STATE_ORIENTATION_TRACKED_BIT |
XR_VIEW_STATE_ORIENTATION_VALID_BIT |
XR_VIEW_STATE_POSITION_TRACKED_BIT |
XR_VIEW_STATE_POSITION_VALID_BIT;
firstPersonConfig.views = {
{viewConfigurations[XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO].views[0].configuration,
{{0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 2.0f, 0.0f}},
{-0.995535672f, 0.995566666f, 0.954059243f, -0.954661012f}}};
viewConfigurations[XR_VIEW_CONFIGURATION_TYPE_SECONDARY_MONO_FIRST_PERSON_OBSERVER_MSFT] = firstPersonConfig;
return XR_SUCCESS;
}

View File

@@ -0,0 +1,114 @@
#include "../mock.h"
XrResult MockRuntime::MSFTSecondaryViewConfiguration_BeginSession(const XrSessionBeginInfo* beginInfo)
{
// Check for secondary view configuration
const XrSecondaryViewConfigurationSessionBeginInfoMSFT* secondaryViewConfiguration =
FindNextPointerType<XrSecondaryViewConfigurationSessionBeginInfoMSFT>(beginInfo, XR_TYPE_SECONDARY_VIEW_CONFIGURATION_SESSION_BEGIN_INFO_MSFT);
if (nullptr == secondaryViewConfiguration)
return XR_SUCCESS;
if (secondaryViewConfiguration->viewConfigurationCount == 0)
return XR_ERROR_VALIDATION_FAILURE;
if (secondaryViewConfiguration->enabledViewConfigurationTypes == nullptr)
return XR_ERROR_VALIDATION_FAILURE;
secondaryViewConfigurationStates.reserve(secondaryViewConfiguration->viewConfigurationCount);
for (uint32_t i = 0; i < secondaryViewConfiguration->viewConfigurationCount; i++)
{
MockViewConfiguration* viewConfiguration = GetMockViewConfiguration(secondaryViewConfiguration->enabledViewConfigurationTypes[i]);
if (nullptr == viewConfiguration)
return XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED;
if (viewConfiguration->primary || viewConfiguration->enabled)
return XR_ERROR_VALIDATION_FAILURE;
viewConfiguration->enabled = true;
XrSecondaryViewConfigurationStateMSFT viewState = {XR_TYPE_SECONDARY_VIEW_CONFIGURATION_STATE_MSFT};
viewState.viewConfigurationType = secondaryViewConfiguration->enabledViewConfigurationTypes[i];
viewState.active = viewConfiguration->active;
secondaryViewConfigurationStates.push_back(viewState);
}
return XR_SUCCESS;
}
XrResult MockRuntime::MSFTSecondaryViewConfiguration_WaitFrame(const XrFrameWaitInfo* frameWaitInfo, XrFrameState* frameState)
{
// Check for secondary view configuration
XrSecondaryViewConfigurationFrameStateMSFT* secondaryFrameState =
FindNextPointerType<XrSecondaryViewConfigurationFrameStateMSFT>(frameState, XR_TYPE_SECONDARY_VIEW_CONFIGURATION_FRAME_STATE_MSFT);
if (secondaryFrameState == nullptr)
return XR_SUCCESS;
if (secondaryFrameState->viewConfigurationCount == 0 || secondaryFrameState->viewConfigurationStates == nullptr)
return XR_ERROR_VALIDATION_FAILURE;
if (secondaryFrameState->viewConfigurationCount != (uint32_t)secondaryViewConfigurationStates.size())
return XR_ERROR_VALIDATION_FAILURE;
for (auto& viewConfiguration : secondaryViewConfigurationStates)
{
if (viewConfiguration.viewConfigurationType != 0)
{
viewConfiguration.active = GetMockViewConfiguration(viewConfiguration.viewConfigurationType)->active;
}
}
memcpy(secondaryFrameState->viewConfigurationStates, secondaryViewConfigurationStates.data(), secondaryViewConfigurationStates.size() * sizeof(XrSecondaryViewConfigurationStateMSFT));
return XR_SUCCESS;
}
XrResult MockRuntime::MSFTSecondaryViewConfiguration_EndFrame(const XrFrameEndInfo* frameEndInfo)
{
const XrSecondaryViewConfigurationFrameEndInfoMSFT* secondaryFrameEndInfo =
FindNextPointerType<XrSecondaryViewConfigurationFrameEndInfoMSFT>(frameEndInfo, XR_TYPE_SECONDARY_VIEW_CONFIGURATION_FRAME_END_INFO_MSFT);
if (secondaryFrameEndInfo == nullptr)
return XR_SUCCESS;
if (secondaryFrameEndInfo->viewConfigurationCount == 0 || secondaryFrameEndInfo->viewConfigurationLayersInfo == nullptr)
return XR_ERROR_VALIDATION_FAILURE;
for (uint32_t i = 0; i < secondaryFrameEndInfo->viewConfigurationCount; i++)
{
auto& info = secondaryFrameEndInfo->viewConfigurationLayersInfo[0];
MockViewConfiguration* viewConfiguration = GetMockViewConfiguration(info.viewConfigurationType);
if (viewConfiguration->primary)
return XR_ERROR_LAYER_INVALID;
if (!viewConfiguration->enabled)
return XR_ERROR_SECONDARY_VIEW_CONFIGURATION_TYPE_NOT_ENABLED_MSFT;
if (!viewConfiguration->active)
continue;
secondaryLayersRendered += info.layerCount;
}
return XR_SUCCESS;
}
XrResult MockRuntime::ActivateSecondaryView(XrViewConfigurationType viewConfigurationType, bool active)
{
if (viewConfigurationType == 0)
{
// emulating a bug we saw with microsoft runtime
secondaryViewConfigurationStates.clear();
secondaryViewConfigurationStates.push_back({XR_TYPE_SECONDARY_VIEW_CONFIGURATION_STATE_MSFT});
}
MockViewConfiguration* viewConfiguration = GetMockViewConfiguration(viewConfigurationType);
if (nullptr == viewConfiguration || (IsSessionRunning() && !viewConfiguration->enabled))
return XR_ERROR_SECONDARY_VIEW_CONFIGURATION_TYPE_NOT_ENABLED_MSFT;
if (viewConfiguration->primary)
return XR_ERROR_VALIDATION_FAILURE;
viewConfiguration->active = active;
return XR_SUCCESS;
}

View File

@@ -0,0 +1,21 @@
#include "../mock.h"
XrResult MockRuntime::MSFTThirdPersonObserver_Init()
{
MockViewConfiguration thirdPersonConfig = {};
thirdPersonConfig.primary = false;
thirdPersonConfig.enabled = false;
thirdPersonConfig.active = false;
thirdPersonConfig.stateFlags = XR_VIEW_STATE_ORIENTATION_TRACKED_BIT |
XR_VIEW_STATE_ORIENTATION_VALID_BIT |
XR_VIEW_STATE_POSITION_TRACKED_BIT |
XR_VIEW_STATE_POSITION_VALID_BIT;
thirdPersonConfig.views = {
{viewConfigurations[XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO].views[0].configuration,
{{0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 2.0f, 0.0f}},
{-0.995535672f, 0.995566666f, 0.954059243f, -0.954661012f}}};
viewConfigurations[XR_VIEW_CONFIGURATION_TYPE_SECONDARY_MONO_THIRD_PERSON_OBSERVER_MSFT] = thirdPersonConfig;
return XR_SUCCESS;
}

View File

@@ -0,0 +1,97 @@
#include "mock_performance_settings.h"
#define CHECK_PERF_SETTINGS_EXT() \
if (nullptr == MockPerformanceSettings::Instance()) \
return XR_ERROR_FUNCTION_UNSUPPORTED;
std::unique_ptr<MockPerformanceSettings> MockPerformanceSettings::s_ext;
void MockPerformanceSettings::Init(MockRuntime& runtime)
{
s_ext.reset(new MockPerformanceSettings(runtime));
}
void MockPerformanceSettings::Deinit()
{
s_ext.reset();
}
MockPerformanceSettings* MockPerformanceSettings::Instance()
{
return s_ext.get();
}
MockPerformanceSettings::MockPerformanceSettings(MockRuntime& runtime)
: m_Runtime(runtime)
{
}
XrResult MockPerformanceSettings::SetPerformanceLevel(XrSession session, XrPerfSettingsDomainEXT domain, XrPerfSettingsLevelEXT level)
{
if (domain != XR_PERF_SETTINGS_DOMAIN_CPU_EXT &&
domain != XR_PERF_SETTINGS_DOMAIN_GPU_EXT)
{
return XR_ERROR_VALIDATION_FAILURE;
}
if (level != XR_PERF_SETTINGS_LEVEL_POWER_SAVINGS_EXT &&
level != XR_PERF_SETTINGS_LEVEL_SUSTAINED_LOW_EXT &&
level != XR_PERF_SETTINGS_LEVEL_SUSTAINED_HIGH_EXT &&
level != XR_PERF_SETTINGS_LEVEL_BOOST_EXT)
{
return XR_ERROR_VALIDATION_FAILURE;
}
m_PerformanceLevelHints[domain] = level;
return XR_SUCCESS;
}
XrPerfSettingsLevelEXT MockPerformanceSettings::GetPerformanceLevelHint(XrPerfSettingsDomainEXT domain)
{
if (m_PerformanceLevelHints.find(domain) != m_PerformanceLevelHints.end())
{
return m_PerformanceLevelHints[domain];
}
return XR_PERF_SETTINGS_LEVEL_SUSTAINED_HIGH_EXT; // Default value per spec
}
XrPerfSettingsNotificationLevelEXT MockPerformanceSettings::GetPerformanceSettingsNotificationLevel(XrPerfSettingsDomainEXT domain, XrPerfSettingsSubDomainEXT subdomain)
{
auto pair = std::make_pair(domain, subdomain);
return m_notificationLevel[pair];
}
void MockPerformanceSettings::SetPerformanceSettingsNotificationLevel(XrPerfSettingsDomainEXT domain, XrPerfSettingsSubDomainEXT subdomain, XrPerfSettingsNotificationLevelEXT nextLevel)
{
auto pair = std::make_pair(domain, subdomain);
m_notificationLevel[pair] = nextLevel;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR
xrPerfSettingsSetPerformanceLevelEXT(
XrSession session,
XrPerfSettingsDomainEXT domain,
XrPerfSettingsLevelEXT level)
{
LOG_FUNC();
CHECK_SESSION(session);
CHECK_PERF_SETTINGS_EXT();
MOCK_HOOK_BEFORE();
const XrResult result =
MockPerformanceSettings::Instance()->SetPerformanceLevel(session, domain, level);
MOCK_HOOK_AFTER(result);
return result;
}
XrResult MockPerformanceSettings_GetInstanceProcAddr(const char* name, PFN_xrVoidFunction* function)
{
GET_PROC_ADDRESS(xrPerfSettingsSetPerformanceLevelEXT);
return XR_ERROR_FUNCTION_UNSUPPORTED;
}
#undef CHECK_PERF_SETTINGS_EXT

View File

@@ -0,0 +1,37 @@
#pragma once
#include <map>
#include <memory>
#include "../mock.h"
#include "IUnityInterface.h"
#include "openxr/openxr.h"
#include "openxr/openxr_platform_defines.h"
class MockRuntime;
class MockPerformanceSettings
{
public:
static void Init(MockRuntime& runtime);
static void Deinit();
static MockPerformanceSettings* Instance();
XrResult SetPerformanceLevel(XrSession session, XrPerfSettingsDomainEXT domain, XrPerfSettingsLevelEXT level);
XrPerfSettingsLevelEXT GetPerformanceLevelHint(XrPerfSettingsDomainEXT domain);
XrPerfSettingsNotificationLevelEXT GetPerformanceSettingsNotificationLevel(XrPerfSettingsDomainEXT domain, XrPerfSettingsSubDomainEXT subdomain);
void SetPerformanceSettingsNotificationLevel(XrPerfSettingsDomainEXT domain, XrPerfSettingsSubDomainEXT subdomain, XrPerfSettingsNotificationLevelEXT nextLevel);
private:
static std::unique_ptr<MockPerformanceSettings> s_ext;
MockRuntime& m_Runtime;
std::map<XrPerfSettingsDomainEXT, XrPerfSettingsLevelEXT> m_PerformanceLevelHints;
std::map<std::pair<XrPerfSettingsDomainEXT, XrPerfSettingsSubDomainEXT>, XrPerfSettingsNotificationLevelEXT> m_notificationLevel;
MockPerformanceSettings(MockRuntime& runtime);
};
XrResult MockPerformanceSettings_GetInstanceProcAddr(const char* name, PFN_xrVoidFunction* function);

View File

@@ -0,0 +1,317 @@
#include "../mock.h"
#if defined(XR_USE_GRAPHICS_API_VULKAN)
struct MockVulkan
{
VkInstance instance = VK_NULL_HANDLE;
VkPhysicalDevice phsyicalDevice = VK_NULL_HANDLE;
VkDevice device = VK_NULL_HANDLE;
VkQueue queue = VK_NULL_HANDLE;
VkPhysicalDeviceMemoryProperties memoryProperties = {};
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = nullptr;
PFN_vkAllocateMemory vkAllocateMemory = nullptr;
PFN_vkCreateImage vkCreateImage = nullptr;
PFN_vkCreateDevice vkCreateDevice = nullptr;
PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices = nullptr;
PFN_vkBindImageMemory vkBindImageMemory = nullptr;
PFN_vkDestroyImage vkDestroyImage = nullptr;
PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements = nullptr;
PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties = nullptr;
};
static MockVulkan s_MockVulkan = {};
static bool GetVulkanMemoryTypeIndex(uint32_t typeBits, VkMemoryPropertyFlags properties, uint32_t* index)
{
for (uint32_t i = 0; i < s_MockVulkan.memoryProperties.memoryTypeCount; i++, typeBits >>= 1)
{
// Only consider memory types included in the typeBits mask
if ((typeBits & 1) == 0)
continue;
// If all requested properties are a match then return this memory type
if ((s_MockVulkan.memoryProperties.memoryTypes[i].propertyFlags & properties) == properties)
{
*index = i;
return true;
}
}
return false;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrGetVulkanInstanceExtensionsKHR(XrInstance instance, XrSystemId systemId, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, char* buffer)
{
if (nullptr == bufferCountOutput)
return XR_ERROR_VALIDATION_FAILURE;
*bufferCountOutput = 0;
if (bufferCapacityInput > 0 && buffer == nullptr)
return XR_ERROR_VALIDATION_FAILURE;
return XR_SUCCESS;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrGetVulkanDeviceExtensionsKHR(XrInstance instance, XrSystemId systemId, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, char* buffer)
{
if (nullptr == bufferCountOutput)
return XR_ERROR_VALIDATION_FAILURE;
*bufferCountOutput = 0;
if (bufferCapacityInput > 0 && buffer == nullptr)
return XR_ERROR_VALIDATION_FAILURE;
return XR_SUCCESS;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrGetVulkanGraphicsDeviceKHR(XrInstance instance, XrSystemId systemId, VkInstance vkInstance, VkPhysicalDevice* vkPhysicalDevice)
{
*vkPhysicalDevice = s_MockVulkan.phsyicalDevice;
return XR_SUCCESS;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrCreateVulkanInstanceKHR(
XrInstance instance,
const XrVulkanInstanceCreateInfoKHR* createInfo,
VkInstance* vulkanInstance,
VkResult* vulkanResult)
{
s_MockVulkan = {};
s_MockVulkan.vkGetInstanceProcAddr = createInfo->pfnGetInstanceProcAddr;
if (s_MockVulkan.vkGetInstanceProcAddr == nullptr)
return XR_ERROR_RUNTIME_FAILURE;
PFN_vkCreateInstance vkCreateInstance = (PFN_vkCreateInstance)s_MockVulkan.vkGetInstanceProcAddr(nullptr, "vkCreateInstance");
if (nullptr == vkCreateInstance)
return XR_ERROR_RUNTIME_FAILURE;
if (VK_SUCCESS != vkCreateInstance(createInfo->vulkanCreateInfo, createInfo->vulkanAllocator, vulkanInstance))
return XR_ERROR_RUNTIME_FAILURE;
#define VK_GET_PROC_ADDR(func) s_MockVulkan.func = (PFN_##func)s_MockVulkan.vkGetInstanceProcAddr(*vulkanInstance, #func);
VK_GET_PROC_ADDR(vkCreateImage)
VK_GET_PROC_ADDR(vkCreateDevice)
VK_GET_PROC_ADDR(vkDestroyImage)
VK_GET_PROC_ADDR(vkGetPhysicalDeviceMemoryProperties)
VK_GET_PROC_ADDR(vkGetImageMemoryRequirements)
VK_GET_PROC_ADDR(vkAllocateMemory)
VK_GET_PROC_ADDR(vkBindImageMemory)
VK_GET_PROC_ADDR(vkEnumeratePhysicalDevices)
#undef VK_GET_PROC_ADDR
return XR_SUCCESS;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrCreateVulkanDeviceKHR(XrInstance instance, const XrVulkanDeviceCreateInfoKHR* createInfo, VkDevice* device, VkResult* result)
{
*result = s_MockVulkan.vkCreateDevice(createInfo->vulkanPhysicalDevice, createInfo->vulkanCreateInfo, createInfo->vulkanAllocator, device);
return XR_SUCCESS;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrGetVulkanGraphicsRequirements2KHR(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsVulkanKHR* graphicsRequirements)
{
graphicsRequirements->minApiVersionSupported = VK_MAKE_VERSION(0, 0, 0);
graphicsRequirements->maxApiVersionSupported = VK_MAKE_VERSION(255, 255, 255);
return XR_SUCCESS;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrGetVulkanGraphicsDevice2KHR(
XrInstance instance,
const XrVulkanGraphicsDeviceGetInfoKHR* getInfo,
VkPhysicalDevice* vulkanPhysicalDevice)
{
if (nullptr == s_MockVulkan.vkEnumeratePhysicalDevices)
{
*vulkanPhysicalDevice = nullptr;
return XR_SUCCESS;
}
uint32_t physicalDeviceCount = 0;
s_MockVulkan.vkEnumeratePhysicalDevices(getInfo->vulkanInstance, &physicalDeviceCount, nullptr);
if (physicalDeviceCount == 0)
return XR_ERROR_RUNTIME_FAILURE;
std::vector<VkPhysicalDevice> physicalDevices;
physicalDevices.resize(physicalDeviceCount);
s_MockVulkan.vkEnumeratePhysicalDevices(getInfo->vulkanInstance, &physicalDeviceCount, physicalDevices.data());
if (physicalDeviceCount != (uint32_t)physicalDevices.size())
return XR_ERROR_RUNTIME_FAILURE;
*vulkanPhysicalDevice = physicalDevices[0];
return XR_SUCCESS;
}
/// <summary>
/// Hook xrCreateSession to get the necessary vulkan handles
/// </summary>
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrCreateSession(XrInstance instance, const XrSessionCreateInfo* createInfo, XrSession* session);
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR MockVulkan_xrCreateSession(XrInstance instance, const XrSessionCreateInfo* createInfo, XrSession* session)
{
if (createInfo->next != nullptr)
{
XrGraphicsBindingVulkanKHR* bindings = (XrGraphicsBindingVulkanKHR*)createInfo->next;
if (bindings->type == XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR)
{
s_MockVulkan.device = bindings->device;
s_MockVulkan.instance = bindings->instance;
s_MockVulkan.phsyicalDevice = bindings->physicalDevice;
if (s_MockVulkan.vkGetPhysicalDeviceMemoryProperties == nullptr)
return XR_ERROR_RUNTIME_FAILURE;
s_MockVulkan.vkGetPhysicalDeviceMemoryProperties(s_MockVulkan.phsyicalDevice, &s_MockVulkan.memoryProperties);
}
}
return xrCreateSession(instance, createInfo, session);
}
static VkImage CreateSwapchainImage(const XrSwapchainCreateInfo* createInfo)
{
VkImageCreateInfo imageCreateInfo = {};
imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
imageCreateInfo.format = (VkFormat)createInfo->format;
imageCreateInfo.mipLevels = createInfo->mipCount;
imageCreateInfo.arrayLayers = createInfo->arraySize;
imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageCreateInfo.extent.width = createInfo->width;
imageCreateInfo.extent.height = createInfo->height;
imageCreateInfo.extent.depth = 1;
imageCreateInfo.usage = 0;
if (createInfo->usageFlags & XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT)
imageCreateInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
if (createInfo->usageFlags & XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)
imageCreateInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
VkImage vkimage;
s_MockVulkan.vkCreateImage(s_MockVulkan.device, &imageCreateInfo, nullptr, &vkimage);
// Allocate memory to back the destination image
VkMemoryRequirements memRequirements;
s_MockVulkan.vkGetImageMemoryRequirements(s_MockVulkan.device, vkimage, &memRequirements);
VkDeviceMemory imageMemory;
VkMemoryAllocateInfo memAllocInfo = {};
memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
memAllocInfo.allocationSize = memRequirements.size;
if (!GetVulkanMemoryTypeIndex(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memAllocInfo.memoryTypeIndex))
return VK_NULL_HANDLE;
s_MockVulkan.vkAllocateMemory(s_MockVulkan.device, &memAllocInfo, nullptr, &imageMemory);
s_MockVulkan.vkBindImageMemory(s_MockVulkan.device, vkimage, imageMemory, 0);
return vkimage;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR MockVulkan_xrCreateSwapchain(XrSession session, const XrSwapchainCreateInfo* createInfo, XrSwapchain* swapchain)
{
LOG_FUNC();
*swapchain = (XrSwapchain)CreateSwapchainImage(createInfo);
return XR_SUCCESS;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR MockVulkan_xrCreateSwapchainHook(XrSession session, const XrSwapchainCreateInfo* createInfo, XrSwapchain* swapchain)
{
LOG_FUNC();
MOCK_HOOK_NAMED("xrCreateSwapchain", MockVulkan_xrCreateSwapchain(session, createInfo, swapchain));
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR MockVulkan_xrDestroySwapChain(XrSwapchain swapchain)
{
s_MockVulkan.vkDestroyImage(s_MockVulkan.device, (VkImage)swapchain, nullptr);
return XR_SUCCESS;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR MockVulkan_xrAcquireSwapchainImage(XrSwapchain swapchain, const XrSwapchainImageAcquireInfo* acquireInfo, uint32_t* index)
{
LOG_FUNC();
*index = 0;
return XR_SUCCESS;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR MockVulkan_xrReleaseSwapchainImage(XrSwapchain swapchain, const XrSwapchainImageReleaseInfo* releaseInfo)
{
LOG_FUNC();
return XR_SUCCESS;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR MockVulkan_xrEnumerateSwapchainFormats(XrSession session, uint32_t formatCapacityInput, uint32_t* formatCountOutput, int64_t* formats)
{
if (nullptr == formatCountOutput)
return XR_ERROR_VALIDATION_FAILURE;
*formatCountOutput = 3;
if (formatCapacityInput == 0)
return XR_SUCCESS;
if (nullptr == formats)
return XR_ERROR_VALIDATION_FAILURE;
if (formatCapacityInput < 3)
return XR_ERROR_SIZE_INSUFFICIENT;
formats[0] = VK_FORMAT_R8G8B8A8_SRGB;
formats[1] = VK_FORMAT_D16_UNORM;
formats[2] = VK_FORMAT_D24_UNORM_S8_UINT;
return XR_SUCCESS;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR MockVulkan_xrEnumerateSwapchainImages(XrSwapchain swapchain, uint32_t imageCapacityInput, uint32_t* imageCountOutput, XrSwapchainImageBaseHeader* images)
{
LOG_FUNC();
*imageCountOutput = 1;
if (images == nullptr)
return XR_SUCCESS;
if (imageCapacityInput < *imageCountOutput)
return XR_ERROR_VALIDATION_FAILURE;
XrSwapchainImageVulkanKHR* vkimages = (XrSwapchainImageVulkanKHR*)images;
vkimages[0].image = (VkImage)swapchain;
return XR_SUCCESS;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrEndFrame(XrSession session, const XrFrameEndInfo* frameEndInfo);
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR MockVulkan_xrEndFrame(XrSession session, const XrFrameEndInfo* frameEndInfo)
{
return xrEndFrame(session, frameEndInfo);
}
XrResult MockVulkan_GetInstanceProcAddr(const char* name, PFN_xrVoidFunction* function)
{
LOG_FUNC();
GET_PROC_ADDRESS_REMAP(xrCreateSession, MockVulkan_xrCreateSession)
GET_PROC_ADDRESS_REMAP(xrCreateSwapchain, MockVulkan_xrCreateSwapchainHook)
GET_PROC_ADDRESS_REMAP(xrDestroySwapChain, MockVulkan_xrDestroySwapChain)
GET_PROC_ADDRESS_REMAP(xrEnumerateSwapchainFormats, MockVulkan_xrEnumerateSwapchainFormats)
GET_PROC_ADDRESS_REMAP(xrEnumerateSwapchainImages, MockVulkan_xrEnumerateSwapchainImages)
GET_PROC_ADDRESS_REMAP(xrAcquireSwapchainImage, MockVulkan_xrAcquireSwapchainImage)
GET_PROC_ADDRESS_REMAP(xrReleaseSwapchainImage, MockVulkan_xrReleaseSwapchainImage)
GET_PROC_ADDRESS_REMAP(xrEndFrame, MockVulkan_xrEndFrame)
GET_PROC_ADDRESS(xrCreateVulkanInstanceKHR)
GET_PROC_ADDRESS(xrGetVulkanGraphicsRequirements2KHR)
GET_PROC_ADDRESS(xrGetVulkanGraphicsDevice2KHR)
GET_PROC_ADDRESS(xrCreateVulkanDeviceKHR)
return XR_ERROR_FUNCTION_UNSUPPORTED;
}
#endif // XR_USE_GRAPHICS_API_VULKAN

View File

@@ -0,0 +1,205 @@
#pragma once
#ifdef _WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif // !WIN32_LEAN_AND_MEAN
#include <d3d11.h>
#include <d3d12.h>
#include <windows.h>
#endif
#ifdef XR_USE_PLATFORM_ANDROID
#include <jni.h>
#include <sstream>
#include <string.h>
#include <string>
#include <sys/system_properties.h>
namespace std
{
template <typename T>
std::string to_string(T value)
{
std::ostringstream os;
os << value;
return os.str();
}
} // namespace std
#endif
#ifdef XR_USE_GRAPHICS_API_OPENGL_ES
#include <EGL/egl.h>
#endif
#include <vulkan/vulkan.h>
struct IUnityXRTrace;
extern IUnityXRTrace* s_Trace;
#define DEBUG_TRACE 1
#define MOCK_TRACE(TYPE, STRING, ...) \
if (s_Trace != nullptr) \
s_Trace->Trace(TYPE, "[Mock] " STRING "\n", ##__VA_ARGS__)
#define MOCK_TRACE_LOG(STRING, ...) MOCK_TRACE(kXRLogTypeLog, STRING, ##__VA_ARGS__)
#define MOCK_TRACE_ERROR(STRING, ...) MOCK_TRACE(kXRLogTypeError, STRING, ##__VA_ARGS__)
#if DEBUG_TRACE
#define MOCK_TRACE_DEBUG(STRING, ...) MOCK_TRACE(kXRLogTypeDebug, STRING, ##__VA_ARGS__)
#else
#define MOCK_TRACE_DEBUG(STRING, ...)
#endif
#define XR_NO_PROTOTYPES
#include "openxr/openxr.h"
#include "openxr/openxr_platform.h"
#include <openxr/openxr_reflection.h>
#include <openxr/xr_msft_third_person_observer_private.h>
#include "XR/IUnityXRTrace.h"
#include <chrono>
#include <map>
#include <queue>
#include <string>
#include <unordered_map>
#include "openxr/openxr_reflection.h"
#include "enums_to_string.h"
#include "openxr_utils.h"
class MockRuntime;
extern MockRuntime* s_runtime;
#define GET_PROC_ADDRESS(funcName) \
if (strcmp(#funcName, name) == 0) \
{ \
*function = (PFN_xrVoidFunction)&funcName; \
return XR_SUCCESS; \
}
#define GET_PROC_ADDRESS_REMAP(funcName, funcProc) \
if (strcmp(#funcName, name) == 0) \
{ \
*function = (PFN_xrVoidFunction)&funcProc; \
return XR_SUCCESS; \
}
#define CHECK_RUNTIME() \
if (s_runtime == nullptr) \
return XR_ERROR_HANDLE_INVALID;
#define CHECK_INSTANCE(instance) \
if (s_runtime == nullptr || s_runtime->GetInstance() != instance) \
return XR_ERROR_HANDLE_INVALID;
#define CHECK_SESSION(session) \
if (s_runtime == nullptr || s_runtime->GetSession() != session) \
return XR_ERROR_HANDLE_INVALID;
#define CHECK_SUCCESS(body) \
{ \
XrResult result = (body); \
if (result != XR_SUCCESS) \
return result; \
}
#define DEBUG_LOG_EVERY_FUNC_CALL 0
#if DEBUG_LOG_EVERY_FUNC_CALL
#define LOG_FUNC() MOCK_TRACE(kXRLogTypeDebug, "%s: %s", __FILE__, __FUNCTION__)
#else
#define LOG_FUNC()
#endif
XrResult GetProcAddrMockAPI(XrInstance instance, const char* name, PFN_xrVoidFunction* function);
XrResult MockRuntime_BeforeFunction(const char* name);
void MockRuntime_AfterFunction(const char* name, XrResult result);
#define MOCK_HOOK_AFTER_NAMED(name, result) MockRuntime_AfterFunction(name, result);
#define MOCK_HOOK_AFTER(result) MOCK_HOOK_AFTER_NAMED(__FUNCTION__, result);
#define MOCK_HOOK_BEFORE_NAMED(name) \
XrResult hookResult = MockRuntime_BeforeFunction(name); \
if (hookResult != XR_SUCCESS) \
{ \
MOCK_HOOK_AFTER_NAMED(name, hookResult); \
return hookResult; \
}
#define MOCK_HOOK_BEFORE() MOCK_HOOK_BEFORE_NAMED(__FUNCTION__)
#define MOCK_HOOK_NAMED(name, x) \
MOCK_HOOK_BEFORE_NAMED(name) \
hookResult = (x); \
MOCK_HOOK_AFTER_NAMED(name, hookResult); \
return hookResult;
#define MOCK_HOOK(x) MOCK_HOOK_NAMED(__FUNCTION__, (x))
#include "mock_events.h"
#include "mock_extensions.h"
#include "mock_input_state.h"
#include "mock_runtime.h"
struct UnityVector3
{
float x;
float y;
float z;
UnityVector3()
{
x = y = z = 0.0f;
}
UnityVector3(const XrVector3f& v)
: x(v.x)
, y(v.y)
, z(-v.z)
{
}
operator XrVector3f() const
{
return XrVector3f{x, y, -z};
}
};
struct UnityVector4
{
float x;
float y;
float z;
float w;
UnityVector4()
{
x = y = z = 0.0f;
}
UnityVector4(const XrFovf& f)
: x(f.angleLeft)
, y(f.angleRight)
, z(f.angleUp)
, w(f.angleDown)
{
}
UnityVector4(const XrQuaternionf& q)
: x(-q.x)
, y(-q.y)
, z(q.z)
, w(q.w)
{
}
operator XrFovf() const
{
return XrFovf{x, y, z, w};
}
operator XrQuaternionf() const
{
return XrQuaternionf{-x, -y, z, w};
}
};

View File

@@ -0,0 +1,391 @@
#include "mock.h"
#ifndef TRAMPOLINE
#define TRAMPOLINE 0
#endif
static PFN_xrGetInstanceProcAddr s_GetInstanceProcAddr = nullptr;
static PFN_xrCreateInstance s_xrCreateInstance = nullptr;
static PFN_xrDestroyInstance s_xrDestroyInstance = nullptr;
static XrInstance s_Instance = XR_NULL_HANDLE;
typedef XrResult(XRAPI_PTR* PFN_BeforeFunctionCallback)(const char* name);
typedef void(XRAPI_PTR* PFN_AfterFunctionCallback)(const char* name, XrResult result);
static PFN_BeforeFunctionCallback s_BeforeFunctionCallback = nullptr;
static PFN_AfterFunctionCallback s_AfterFunctionCallback = nullptr;
static bool s_KeepFunctionCallbacks = false;
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API MockRuntime_RegisterFunctionCallbacks(PFN_BeforeFunctionCallback before, PFN_AfterFunctionCallback after)
{
s_BeforeFunctionCallback = before;
s_AfterFunctionCallback = after;
#if TRAMPOLINE
if (s_Instance == nullptr || s_GetInstanceProcAddr == nullptr)
return;
void (*fptr)(PFN_BeforeFunctionCallback before, PFN_AfterFunctionCallback after) = nullptr;
s_GetInstanceProcAddr(s_Instance, __func__, (PFN_xrVoidFunction*)&fptr);
return fptr(before, after);
#endif
}
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API MockRuntime_SetKeepFunctionCallbacks(bool value)
{
s_KeepFunctionCallbacks = value;
}
XrResult MockRuntime_BeforeFunction(const char* name)
{
if (s_BeforeFunctionCallback == nullptr)
return XR_SUCCESS;
return s_BeforeFunctionCallback(name);
}
void MockRuntime_AfterFunction(const char* name, XrResult result)
{
if (s_AfterFunctionCallback == nullptr)
return;
s_AfterFunctionCallback(name, result);
}
// Special handling of before / after function callbacks for xrCreateInstance and xrDestroyInstance
extern "C" PFN_xrGetInstanceProcAddr UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API MockRuntime_HookCreateInstance(PFN_xrGetInstanceProcAddr procAddr)
{
s_GetInstanceProcAddr = procAddr;
return (PFN_xrGetInstanceProcAddr)[](XrInstance instance, const char* name, PFN_xrVoidFunction* function)->XrResult
{
XrResult ret = s_GetInstanceProcAddr(instance, name, function);
if (strcmp(name, "xrCreateInstance") == 0)
{
s_xrCreateInstance = (PFN_xrCreateInstance)*function;
*function = (PFN_xrVoidFunction)(PFN_xrCreateInstance)[](const XrInstanceCreateInfo* createInfo, XrInstance* instance)->XrResult
{
XrResult ret = XR_SUCCESS;
if (s_BeforeFunctionCallback != nullptr)
ret = s_BeforeFunctionCallback("xrCreateInstance");
if (XR_FAILED(ret))
return ret;
ret = s_xrCreateInstance(createInfo, instance);
s_Instance = *instance;
if (s_AfterFunctionCallback != nullptr)
s_AfterFunctionCallback("xrCreateInstance", ret);
MockRuntime_RegisterFunctionCallbacks(s_BeforeFunctionCallback, s_AfterFunctionCallback);
return ret;
};
return ret;
}
else if (strcmp(name, "xrDestroyInstance") == 0)
{
s_xrDestroyInstance = (PFN_xrDestroyInstance)*function;
*function = (PFN_xrVoidFunction)(PFN_xrDestroyInstance)[](XrInstance instance)->XrResult
{
PFN_BeforeFunctionCallback before = s_BeforeFunctionCallback;
PFN_AfterFunctionCallback after = s_AfterFunctionCallback;
if (!s_KeepFunctionCallbacks)
{
MockRuntime_RegisterFunctionCallbacks(nullptr, nullptr);
}
XrResult ret = XR_SUCCESS;
if (before != nullptr)
ret = before("xrDestroyInstance");
if (XR_FAILED(ret))
return ret;
ret = s_xrDestroyInstance(instance);
s_Instance = XR_NULL_HANDLE;
if (after != nullptr)
after("xrDestroyInstance", ret);
return ret;
};
return ret;
}
return ret;
};
}
#if TRAMPOLINE
#define MOCK_API_TRAMPOLINE(API_RETURN, DEFAULT_VAL, API_NAME, API_ARGS, API_ARG_NAMES) \
extern "C" API_RETURN UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API API_NAME API_ARGS \
{ \
if (s_Instance == XR_NULL_HANDLE || s_GetInstanceProcAddr == nullptr) \
return DEFAULT_VAL; \
API_RETURN(*fptr) \
API_ARGS = nullptr; \
s_GetInstanceProcAddr(s_Instance, __func__, (PFN_xrVoidFunction*)&fptr); \
return fptr API_ARG_NAMES; \
}
#else
#define MOCK_API_TRAMPOLINE(API_RETURN, DEFAULT_VAL, API_NAME, API_ARGS, API_ARG_NAMES) \
extern "C" API_RETURN UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API API_NAME API_ARGS
#endif
void NO_RETURN()
{
}
MOCK_API_TRAMPOLINE(void, NO_RETURN(), MockRuntime_SetView,
(XrViewConfigurationType viewConfigurationType, int viewIndex, UnityVector3 position, UnityVector4 orientation, UnityVector4 fov),
(viewConfigurationType, viewIndex, position, orientation, fov))
#if !TRAMPOLINE
{
if (nullptr == s_runtime)
return;
s_runtime->SetViewPose(viewConfigurationType, viewIndex, {orientation, position}, fov);
}
#endif
MOCK_API_TRAMPOLINE(void, NO_RETURN(), MockRuntime_SetViewState,
(XrViewConfigurationType viewConfigurationType, XrViewStateFlags stateFlags),
(viewConfigurationType, stateFlags))
#if !TRAMPOLINE
{
if (nullptr == s_runtime)
return;
s_runtime->SetViewStateFlags(viewConfigurationType, stateFlags);
}
#endif
MOCK_API_TRAMPOLINE(void, NO_RETURN(), MockRuntime_SetReferenceSpace,
(XrReferenceSpaceType referenceSpace, UnityVector3 position, UnityVector4 orientation, XrSpaceLocationFlags locationFlags),
(referenceSpace, position, orientation, locationFlags))
#if !TRAMPOLINE
{
if (nullptr == s_runtime)
return;
s_runtime->SetSpace(referenceSpace, {orientation, position}, locationFlags);
}
#endif
MOCK_API_TRAMPOLINE(void, NO_RETURN(), MockRuntime_SetActionSpace,
(XrAction action, UnityVector3 position, UnityVector4 orientation, XrSpaceLocationFlags locationFlags),
(action, position, orientation, locationFlags))
#if !TRAMPOLINE
{
if (nullptr == s_runtime)
return;
s_runtime->SetSpace(action, {orientation, position}, locationFlags);
}
#endif
MOCK_API_TRAMPOLINE(XrSessionState, XR_SESSION_STATE_UNKNOWN, MockRuntime_GetSessionState,
(),
())
#if !TRAMPOLINE
{
if (nullptr == s_runtime)
return XR_SESSION_STATE_UNKNOWN;
return s_runtime->GetSessionState();
}
#endif
MOCK_API_TRAMPOLINE(void, NO_RETURN(), MockRuntime_RequestExitSession,
(),
())
#if !TRAMPOLINE
{
if (nullptr == s_runtime)
return;
s_runtime->RequestExitSession();
}
#endif
MOCK_API_TRAMPOLINE(void, NO_RETURN(), MockRuntime_CauseInstanceLoss,
(),
())
#if !TRAMPOLINE
{
if (nullptr == s_runtime)
return;
s_runtime->CauseInstanceLoss();
}
#endif
MOCK_API_TRAMPOLINE(void, NO_RETURN(), MockRuntime_CauseUserPresenceChange,
(bool hasUserPresent),
(hasUserPresent))
#if !TRAMPOLINE
{
if (nullptr == s_runtime)
return;
s_runtime->CauseUserPresenceChange(hasUserPresent);
}
#endif
MOCK_API_TRAMPOLINE(void, NO_RETURN(), MockRuntime_SetReferenceSpaceBounds,
(XrReferenceSpaceType referenceSpaceType, XrExtent2Df bounds),
(referenceSpaceType, bounds))
#if !TRAMPOLINE
{
if (nullptr == s_runtime)
return;
s_runtime->SetExtentsForReferenceSpace(referenceSpaceType, bounds);
}
#endif
MOCK_API_TRAMPOLINE(void, NO_RETURN(), MockRuntime_GetEndFrameStats,
(int* primaryLayerCount, int* secondaryLayerCount),
(primaryLayerCount, secondaryLayerCount))
#if !TRAMPOLINE
{
*primaryLayerCount = 0;
*secondaryLayerCount = 0;
if (nullptr == s_runtime)
return;
s_runtime->GetEndFrameStats(primaryLayerCount, secondaryLayerCount);
}
#endif
MOCK_API_TRAMPOLINE(void, NO_RETURN(), MockRuntime_ActivateSecondaryView,
(XrViewConfigurationType viewConfigurationType, bool activate),
(viewConfigurationType, activate))
#if !TRAMPOLINE
{
if (nullptr == s_runtime)
return;
s_runtime->ActivateSecondaryView(viewConfigurationType, activate);
}
#endif
MOCK_API_TRAMPOLINE(void, NO_RETURN(), MockRuntime_RegisterScriptEventCallback,
(PFN_ScriptEventCallback callback),
(callback))
#if !TRAMPOLINE
{
if (nullptr == s_runtime)
return;
s_runtime->RegisterScriptEventCallback(callback);
}
#endif
MOCK_API_TRAMPOLINE(bool, false, MockRuntime_TransitionToState,
(XrSessionState requestedState, bool forceTransition),
(requestedState, forceTransition))
#if !TRAMPOLINE
{
if (nullptr == s_runtime)
return false;
if (!forceTransition && !s_runtime->IsStateTransitionValid(requestedState))
{
MOCK_TRACE_ERROR("Failed to request state. Was transition valid: %s with force %s",
s_runtime->IsStateTransitionValid(requestedState) ? "TRUE" : "FALSE",
forceTransition ? "TRUE" : "FALSE");
return false;
}
s_runtime->ChangeSessionState(requestedState);
return true;
}
#endif
MOCK_API_TRAMPOLINE(void, NO_RETURN(), MockRuntime_MetaPerformanceMetrics_SeedCounterOnce_Float,
(const char* xrPathString, float value, uint32_t unit),
(xrPathString, value, unit))
#if !TRAMPOLINE
{
MockMetaPerformanceMetrics::Instance()->SeedCounterOnce(
xrPathString,
{XR_SUCCESS,
{XR_TYPE_PERFORMANCE_METRICS_COUNTER_META,
nullptr,
XR_PERFORMANCE_METRICS_COUNTER_FLOAT_VALUE_VALID_BIT_META,
static_cast<XrPerformanceMetricsCounterUnitMETA>(unit),
0,
value}});
}
#endif
MOCK_API_TRAMPOLINE(void, NO_RETURN(), MockRuntime_PerformanceSettings_CauseNotification,
(XrPerfSettingsDomainEXT domain, XrPerfSettingsSubDomainEXT subdomain, XrPerfSettingsNotificationLevelEXT level),
(domain, subdomain, level))
#if !TRAMPOLINE
{
if (s_runtime == nullptr)
return;
s_runtime->CausePerformanceSettingsNotification(domain, subdomain, level);
}
#endif
MOCK_API_TRAMPOLINE(XrPerfSettingsLevelEXT, XR_PERF_SETTINGS_LEVEL_SUSTAINED_HIGH_EXT, MockRuntime_PerformanceSettings_GetPerformanceLevelHint,
(XrPerfSettingsDomainEXT domain),
(domain))
#if !TRAMPOLINE
{
if (MockPerformanceSettings::Instance() == nullptr)
return XR_PERF_SETTINGS_LEVEL_SUSTAINED_HIGH_EXT;
return MockPerformanceSettings::Instance()->GetPerformanceLevelHint(domain);
}
#endif
#ifdef XR_USE_PLATFORM_ANDROID
MOCK_API_TRAMPOLINE(bool, false, MockRuntime_IsAndroidThreadTypeRegistered,
(uint32_t threadTypeValue),
(threadTypeValue))
#if !TRAMPOLINE
{
LOG_FUNC();
auto threadType = static_cast<XrAndroidThreadTypeKHR>(threadTypeValue);
return MockAndroidThreadSettings::Instance()->IsAndroidThreadTypeRegistered(threadType);
}
#endif // !TRAMPOLINE
MOCK_API_TRAMPOLINE(uint32_t, 0, MockRuntime_GetRegisteredAndroidThreadsCount,
(),
())
#if !TRAMPOLINE
{
LOG_FUNC();
MOCK_TRACE_DEBUG("Session is valid");
return MockAndroidThreadSettings::Instance()->GetRegisteredAndroidThreadsCount();
}
#endif // !TRAMPOLINE
#endif // XR_USE_PLATFORM_ANDROID
#if !TRAMPOLINE
XrResult GetProcAddrMockAPI(XrInstance instance, const char* name, PFN_xrVoidFunction* function)
{
GET_PROC_ADDRESS(MockRuntime_SetView)
GET_PROC_ADDRESS(MockRuntime_SetViewState)
GET_PROC_ADDRESS(MockRuntime_SetReferenceSpace)
GET_PROC_ADDRESS(MockRuntime_SetActionSpace)
GET_PROC_ADDRESS(MockRuntime_GetSessionState)
GET_PROC_ADDRESS(MockRuntime_RequestExitSession)
GET_PROC_ADDRESS(MockRuntime_CauseInstanceLoss)
GET_PROC_ADDRESS(MockRuntime_CauseUserPresenceChange)
GET_PROC_ADDRESS(MockRuntime_SetReferenceSpaceBounds)
GET_PROC_ADDRESS(MockRuntime_GetEndFrameStats)
GET_PROC_ADDRESS(MockRuntime_ActivateSecondaryView)
GET_PROC_ADDRESS(MockRuntime_RegisterScriptEventCallback)
GET_PROC_ADDRESS(MockRuntime_RegisterFunctionCallbacks)
GET_PROC_ADDRESS(MockRuntime_TransitionToState)
GET_PROC_ADDRESS(MockRuntime_MetaPerformanceMetrics_SeedCounterOnce_Float)
GET_PROC_ADDRESS(MockRuntime_PerformanceSettings_CauseNotification)
GET_PROC_ADDRESS(MockRuntime_PerformanceSettings_GetPerformanceLevelHint)
#ifdef XR_USE_PLATFORM_ANDROID
GET_PROC_ADDRESS(MockRuntime_IsAndroidThreadTypeRegistered)
GET_PROC_ADDRESS(MockRuntime_GetRegisteredAndroidThreadsCount)
#endif // XR_USE_PLATFORM_ANDROID
return XR_ERROR_FUNCTION_UNSUPPORTED;
}
#endif

View File

@@ -0,0 +1,24 @@
// Defines Mock Runtime specific events at the end of the structure type list
const XrStructureType XR_TYPE_EVENT_SCRIPT_EVENT_MOCK = (XrStructureType)(XR_STRUCTURE_TYPE_MAX_ENUM - 1);
// Register a callback that gets called for script events sent by mock
//
typedef enum
{
XR_MOCK_SCRIPT_EVENT_UNKNOWN,
XR_MOCK_SCRIPT_EVENT_END_FRAME,
XR_MOCK_SCRIPT_EVENT_HAPTIC_IMPULSE,
XR_MOCK_SCRIPT_EVENT_HAPTIC_STOP
} XrMockScriptEvent;
typedef struct XrEventScriptEventMOCK
{
XrStructureType type;
const void* XR_MAY_ALIAS next;
XrMockScriptEvent event;
uint64_t param;
} XrEventScriptEventMOCK;
typedef void (*PFN_ScriptEventCallback)(XrMockScriptEvent event, uint64_t param);

View File

@@ -0,0 +1,33 @@
#pragma once
#include "Extensions/mock_khr_android_thread_settings.h"
#include "Extensions/mock_meta_performance_metrics.h"
#include "Extensions/mock_performance_settings.h"
// XR_EXT_conformance_automation
struct ConformanceAutomation;
class MockInputState;
void ConformanceAutomation_Create();
void ConformanceAutomation_Destroy();
XrResult ConformanceAutomation_GetInstanceProcAddr(const char* name, PFN_xrVoidFunction* function);
XrResult ConformanceAutomation_GetInputState(MockInputState* state);
bool ConformanceAutomation_IsActive(XrPath interactionProfile, XrPath userPath, bool defaultValue = true);
// XR_KHR_VULKAN_ENABLE2
#if defined(XR_USE_GRAPHICS_API_VULKAN)
XrResult MockVulkan_GetInstanceProcAddr(const char* name, PFN_xrVoidFunction* function);
#endif
// XR_KHR_D3D11_ENABLE
#if defined(XR_USE_GRAPHICS_API_D3D11)
XrResult MockD3D11_GetInstanceProcAddr(const char* name, PFN_xrVoidFunction* function);
#endif
// XR_KHR_D3D12_ENABLE
#if defined(XR_USE_GRAPHICS_API_D3D12)
XrResult MockD3D12_GetInstanceProcAddr(const char* name, PFN_xrVoidFunction* function);
#endif

View File

@@ -0,0 +1,227 @@
#include "mock.h"
void MockInputState::Reset()
{
switch (type)
{
case XR_ACTION_TYPE_BOOLEAN_INPUT:
value.boolValue = false;
break;
case XR_ACTION_TYPE_FLOAT_INPUT:
value.floatValue = false;
break;
case XR_ACTION_TYPE_VECTOR2F_INPUT:
value.vectorValue = {0, 0};
break;
case XR_ACTION_TYPE_POSE_INPUT:
value.locationValue.pose = {{0, 0, 0, 1}, {0, 0, 0}};
value.locationValue.space = XR_NULL_HANDLE;
value.locationValue.linearVelocityValid = false;
value.locationValue.linearVelocity = {0, 0, 0};
value.locationValue.angularVelocityValid = false;
value.locationValue.angularVelocity = {0, 0, 0};
break;
default:
break;
}
}
void MockInputState::Set(float v)
{
switch (type)
{
case XR_ACTION_TYPE_FLOAT_INPUT:
value.floatValue = v;
break;
case XR_ACTION_TYPE_BOOLEAN_INPUT:
value.boolValue = v != 0.0f;
break;
default:
value.floatValue = 0.0f;
break;
}
}
void MockInputState::Set(XrBool32 v)
{
switch (type)
{
case XR_ACTION_TYPE_BOOLEAN_INPUT:
value.boolValue = v;
break;
case XR_ACTION_TYPE_FLOAT_INPUT:
value.floatValue = v ? 1.0f : 0.0f;
break;
default:
value.boolValue = false;
break;
}
}
void MockInputState::Set(XrVector2f v)
{
if (type != XR_ACTION_TYPE_VECTOR2F_INPUT)
{
Reset();
return;
}
value.vectorValue = v;
}
void MockInputState::Set(XrSpace space, XrPosef pose)
{
if (type != XR_ACTION_TYPE_POSE_INPUT)
{
Reset();
return;
}
value.locationValue.space = space;
value.locationValue.pose = pose;
}
void MockInputState::SetVelocity(bool linearValid, XrVector3f linear, bool angularValid, XrVector3f angular)
{
value.locationValue.linearVelocityValid = linearValid;
value.locationValue.linearVelocity = linearValid ? linear : XrVector3f{0, 0, 0};
value.locationValue.angularVelocityValid = angularValid;
value.locationValue.angularVelocity = angularValid ? angular : XrVector3f{0, 0, 0};
}
float MockInputState::GetFloat() const
{
switch (type)
{
case XR_ACTION_TYPE_BOOLEAN_INPUT:
return (float)value.boolValue;
case XR_ACTION_TYPE_FLOAT_INPUT:
return value.floatValue;
default:
break;
}
return 0.0f;
}
XrBool32 MockInputState::GetBoolean() const
{
switch (type)
{
case XR_ACTION_TYPE_BOOLEAN_INPUT:
return value.boolValue;
case XR_ACTION_TYPE_FLOAT_INPUT:
return value.floatValue != 0.0f;
default:
break;
}
return false;
}
XrVector2f MockInputState::GetVector2() const
{
if (type == XR_ACTION_TYPE_VECTOR2F_INPUT)
return value.vectorValue;
return XrVector2f();
}
XrSpace MockInputState::GetLocationSpace() const
{
if (type == XR_ACTION_TYPE_POSE_INPUT)
return value.locationValue.space;
return XR_NULL_HANDLE;
}
XrPosef MockInputState::GetLocationPose() const
{
if (type == XR_ACTION_TYPE_POSE_INPUT)
return value.locationValue.pose;
return XrPosef();
}
bool MockInputState::HasLinearVelocity() const
{
return type == XR_ACTION_TYPE_POSE_INPUT && value.locationValue.linearVelocityValid;
}
XrVector3f MockInputState::GetLinearVelocity() const
{
if (HasLinearVelocity())
return value.locationValue.linearVelocity;
return XrVector3f{};
}
bool MockInputState::HasAngularVelocity() const
{
return type == XR_ACTION_TYPE_POSE_INPUT && value.locationValue.angularVelocityValid;
}
XrVector3f MockInputState::GetAngularVelocity() const
{
if (type == XR_ACTION_TYPE_POSE_INPUT)
return value.locationValue.angularVelocity;
return XrVector3f{};
}
bool MockInputState::IsCompatibleType(XrActionType actionType) const
{
switch (type)
{
case XR_ACTION_TYPE_BOOLEAN_INPUT:
case XR_ACTION_TYPE_FLOAT_INPUT:
return actionType == XR_ACTION_TYPE_FLOAT_INPUT || actionType == XR_ACTION_TYPE_BOOLEAN_INPUT;
default:
break;
}
return IsType(actionType);
}
void MockInputState::CopyValue(const MockInputState& state)
{
switch (type)
{
case XR_ACTION_TYPE_BOOLEAN_INPUT:
value.boolValue = state.GetBoolean();
break;
case XR_ACTION_TYPE_FLOAT_INPUT:
value.floatValue = state.GetFloat();
break;
case XR_ACTION_TYPE_VECTOR2F_INPUT:
value.vectorValue = state.GetVector2();
break;
case XR_ACTION_TYPE_POSE_INPUT:
value.locationValue.space = state.GetLocationSpace();
value.locationValue.pose = state.GetLocationPose();
value.locationValue.angularVelocityValid = state.HasAngularVelocity();
value.locationValue.angularVelocity = state.GetAngularVelocity();
value.locationValue.linearVelocityValid = state.HasLinearVelocity();
value.locationValue.linearVelocity = state.GetLinearVelocity();
break;
default:
break;
}
}

View File

@@ -0,0 +1,56 @@
#pragma once
class MockInputState
{
public:
XrPath interactionProfile;
XrPath path;
XrActionType type;
const char* localizedName;
bool IsType(XrActionType actionType) const
{
return type == actionType;
}
bool IsCompatibleType(XrActionType actionType) const;
void Reset();
void Set(float value);
void Set(XrBool32 value);
void Set(XrVector2f value);
void Set(XrSpace space, XrPosef pose);
void SetVelocity(bool linearValid, XrVector3f linear, bool angularValid, XrVector3f angular);
void CopyValue(const MockInputState& state);
float GetFloat() const;
XrBool32 GetBoolean() const;
XrVector2f GetVector2() const;
XrSpace GetLocationSpace() const;
XrPosef GetLocationPose() const;
bool HasAngularVelocity() const;
bool HasLinearVelocity() const;
XrVector3f GetAngularVelocity() const;
XrVector3f GetLinearVelocity() const;
private:
union
{
XrBool32 boolValue;
float floatValue;
XrVector2f vectorValue;
struct
{
XrSpace space;
XrPosef pose;
XrVector3f linearVelocity;
XrVector3f angularVelocity;
bool linearVelocityValid;
bool angularVelocityValid;
} locationValue;
} value;
};

View File

@@ -0,0 +1,902 @@
#include "mock.h"
#include <openxr/loader_interfaces.h>
IUnityXRTrace* s_Trace = nullptr;
MockRuntime* s_runtime = nullptr;
uint64_t s_nextInstanceId = 11; // Start at 11 because 10 is a special test case
#define XR_UNITY_mock_test_SPEC_VERSION 123
#define XR_UNITY_MOCK_TEST_EXTENSION_NAME "XR_UNITY_mock_test"
#define XR_UNITY_null_gfx_SPEC_VERSION 1
#define XR_UNITY_NULL_GFX_EXTENSION_NAME "XR_UNITY_null_gfx"
#define XR_UNITY_android_present_SPEC_VERSION 1
#define XR_UNITY_ANDROID_PRESENT_EXTENSION_NAME "XR_UNITY_android_present"
#define ENUM_TO_STR(name, val) \
case val: \
strncpy(buffer, #name, XR_MAX_RESULT_STRING_SIZE - 1); \
break;
// clang-format off
static XrExtensionProperties s_Extensions[] = {
{
XR_TYPE_EXTENSION_PROPERTIES,
nullptr,
XR_UNITY_MOCK_TEST_EXTENSION_NAME,
XR_UNITY_mock_test_SPEC_VERSION
},
{
XR_TYPE_EXTENSION_PROPERTIES,
nullptr,
XR_UNITY_NULL_GFX_EXTENSION_NAME,
XR_UNITY_null_gfx_SPEC_VERSION
},
{
XR_TYPE_EXTENSION_PROPERTIES,
nullptr,
XR_UNITY_ANDROID_PRESENT_EXTENSION_NAME,
XR_UNITY_android_present_SPEC_VERSION
},
{
XR_TYPE_EXTENSION_PROPERTIES,
nullptr,
XR_KHR_VISIBILITY_MASK_EXTENSION_NAME,
XR_KHR_visibility_mask_SPEC_VERSION
},
{
XR_TYPE_EXTENSION_PROPERTIES,
nullptr,
XR_EXT_CONFORMANCE_AUTOMATION_EXTENSION_NAME,
XR_EXT_conformance_automation_SPEC_VERSION
},
{
XR_TYPE_EXTENSION_PROPERTIES,
nullptr,
XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME,
XR_KHR_composition_layer_depth_SPEC_VERSION
},
{
XR_TYPE_EXTENSION_PROPERTIES,
nullptr,
XR_VARJO_QUAD_VIEWS_EXTENSION_NAME,
XR_VARJO_quad_views_SPEC_VERSION
},
{
XR_TYPE_EXTENSION_PROPERTIES,
nullptr,
XR_MSFT_SECONDARY_VIEW_CONFIGURATION_EXTENSION_NAME,
XR_MSFT_secondary_view_configuration_SPEC_VERSION
},
{
XR_TYPE_EXTENSION_PROPERTIES,
nullptr,
XR_EXT_EYE_GAZE_INTERACTION_EXTENSION_NAME,
XR_EXT_eye_gaze_interaction_SPEC_VERSION
},
{
XR_TYPE_EXTENSION_PROPERTIES,
nullptr,
XR_MSFT_HAND_INTERACTION_EXTENSION_NAME,
XR_MSFT_hand_interaction_SPEC_VERSION
},
{
XR_TYPE_EXTENSION_PROPERTIES,
nullptr,
XR_EXT_HAND_INTERACTION_EXTENSION_NAME,
XR_EXT_hand_interaction_SPEC_VERSION
},
{
XR_TYPE_EXTENSION_PROPERTIES,
nullptr,
XR_FB_TOUCH_CONTROLLER_PRO_EXTENSION_NAME,
XR_FB_touch_controller_pro_SPEC_VERSION
},
{
XR_TYPE_EXTENSION_PROPERTIES,
nullptr,
XR_MSFT_FIRST_PERSON_OBSERVER_EXTENSION_NAME,
XR_MSFT_first_person_observer_SPEC_VERSION
},
{
XR_TYPE_EXTENSION_PROPERTIES,
nullptr,
XR_MSFT_THIRD_PERSON_OBSERVER_PRIVATE_EXTENSION_NAME,
XR_MSFT_third_person_observer_private_SPEC_VERSION
},
{
XR_TYPE_EXTENSION_PROPERTIES,
nullptr,
XR_META_PERFORMANCE_METRICS_EXTENSION_NAME,
XR_META_performance_metrics_SPEC_VERSION
},
{
XR_TYPE_EXTENSION_PROPERTIES,
nullptr,
XR_META_TOUCH_CONTROLLER_PLUS_EXTENSION_NAME,
XR_META_touch_controller_plus_SPEC_VERSION
},
{
XR_TYPE_EXTENSION_PROPERTIES,
nullptr,
XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME,
XR_EXT_hp_mixed_reality_controller_SPEC_VERSION
},
{
XR_TYPE_EXTENSION_PROPERTIES,
nullptr,
XR_EXT_USER_PRESENCE_EXTENSION_NAME,
XR_EXT_user_presence_SPEC_VERSION
},
{
XR_TYPE_EXTENSION_PROPERTIES,
nullptr,
XR_EXT_PERFORMANCE_SETTINGS_EXTENSION_NAME,
XR_EXT_performance_settings_SPEC_VERSION
}
#if defined(XR_USE_PLATFORM_ANDROID)
,{
XR_TYPE_EXTENSION_PROPERTIES,
nullptr,
XR_KHR_ANDROID_THREAD_SETTINGS_EXTENSION_NAME,
XR_KHR_android_thread_settings_SPEC_VERSION
}
#endif
#if defined(XR_USE_GRAPHICS_API_VULKAN)
,{
XR_TYPE_EXTENSION_PROPERTIES,
nullptr,
XR_KHR_VULKAN_ENABLE2_EXTENSION_NAME,
XR_KHR_vulkan_enable2_SPEC_VERSION
}
#endif
#if defined(XR_USE_GRAPHICS_API_D3D11)
,{
XR_TYPE_EXTENSION_PROPERTIES,
nullptr,
XR_KHR_D3D11_ENABLE_EXTENSION_NAME,
XR_KHR_D3D11_enable_SPEC_VERSION
}
#endif
#if defined(XR_USE_GRAPHICS_API_D3D12)
,{
XR_TYPE_EXTENSION_PROPERTIES,
nullptr,
XR_KHR_D3D12_ENABLE_EXTENSION_NAME,
XR_KHR_D3D12_enable_SPEC_VERSION
}
#endif
};
// clang-format on
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrEnumerateApiLayerProperties(uint32_t propertyCapacityInput, uint32_t* propertyCountOutput, XrApiLayerProperties* properties)
{
LOG_FUNC();
*propertyCountOutput = 0;
return XR_SUCCESS;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrEnumerateInstanceExtensionProperties(const char* layerName, uint32_t propertyCapacityInput, uint32_t* propertyCountOutput, XrExtensionProperties* properties)
{
LOG_FUNC();
*propertyCountOutput = sizeof(s_Extensions) / sizeof(XrExtensionProperties);
if (propertyCapacityInput == 0)
return XR_SUCCESS;
if (propertyCapacityInput < *propertyCountOutput)
return XR_ERROR_VALIDATION_FAILURE;
uint32_t count = 0;
while (count < *propertyCountOutput)
{
properties[count] = s_Extensions[count];
++count;
}
return XR_SUCCESS;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrCreateInstance(const XrInstanceCreateInfo* createInfo, XrInstance* instance)
{
LOG_FUNC();
// Destroy any existing runtime if there is one
if (s_runtime != nullptr)
{
delete s_runtime;
s_runtime = nullptr;
}
*instance = 0;
MockRuntimeCreateFlags flags = 0;
for (uint32_t i = 0; i < createInfo->enabledExtensionCount; ++i)
{
const char* extension = createInfo->enabledExtensionNames[i];
if (strncmp(XR_UNITY_MOCK_TEST_EXTENSION_NAME, extension, sizeof(XR_UNITY_MOCK_TEST_EXTENSION_NAME)) == 0)
{
*instance = (XrInstance)10;
continue;
}
if ((flags & MR_CREATE_ALL_GFX_EXT) == 0)
{
#if defined(XR_USE_GRAPHICS_API_VULKAN)
if (strncmp(XR_KHR_VULKAN_ENABLE2_EXTENSION_NAME, extension, sizeof(XR_KHR_VULKAN_ENABLE2_EXTENSION_NAME)) == 0)
{
flags |= MR_CREATE_VULKAN_GFX_EXT;
continue;
}
#endif
#if defined(XR_USE_GRAPHICS_API_D3D11)
if (strncmp(XR_KHR_D3D11_ENABLE_EXTENSION_NAME, extension, sizeof(XR_KHR_D3D11_ENABLE_EXTENSION_NAME)) == 0)
{
flags |= MR_CREATE_D3D11_GFX_EXT;
continue;
}
#endif
#if defined(XR_USE_GRAPHICS_API_D3D12)
if (strncmp(XR_KHR_D3D12_ENABLE_EXTENSION_NAME, extension, sizeof(XR_KHR_D3D12_ENABLE_EXTENSION_NAME)) == 0)
{
flags |= MR_CREATE_D3D12_GFX_EXT;
continue;
}
#endif
if (strncmp(XR_UNITY_NULL_GFX_EXTENSION_NAME, extension, sizeof(XR_UNITY_NULL_GFX_EXTENSION_NAME)) == 0)
{
flags |= MR_CREATE_NULL_GFX_EXT;
continue;
}
}
// Conformance Automation
if (strncmp(XR_EXT_CONFORMANCE_AUTOMATION_EXTENSION_NAME, extension, sizeof(XR_EXT_CONFORMANCE_AUTOMATION_EXTENSION_NAME)) == 0)
{
flags |= MR_CREATE_CONFORMANCE_AUTOMATION_EXT;
continue;
}
if (strncmp(XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME, extension, sizeof(XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME)) == 0)
{
flags |= MR_CREATE_COMPOSITION_LAYER_DEPTH_EXT;
continue;
}
if (strncmp(XR_VARJO_QUAD_VIEWS_EXTENSION_NAME, extension, sizeof(XR_VARJO_QUAD_VIEWS_EXTENSION_NAME)) == 0)
{
flags |= MR_CREATE_VARJO_QUAD_VIEWS_EXT;
continue;
}
if (strncmp(XR_MSFT_SECONDARY_VIEW_CONFIGURATION_EXTENSION_NAME, extension, sizeof(XR_MSFT_SECONDARY_VIEW_CONFIGURATION_EXTENSION_NAME)) == 0)
{
flags |= MR_CREATE_MSFT_SECONDARY_VIEW_CONFIGURATION_EXT;
continue;
}
if (strncmp(XR_MSFT_FIRST_PERSON_OBSERVER_EXTENSION_NAME, extension, sizeof(XR_MSFT_FIRST_PERSON_OBSERVER_EXTENSION_NAME)) == 0)
{
flags |= MR_CREATE_MSFT_FIRST_PERSON_OBSERVER_EXT;
continue;
}
if (strncmp(XR_MSFT_THIRD_PERSON_OBSERVER_PRIVATE_EXTENSION_NAME, extension, sizeof(XR_MSFT_THIRD_PERSON_OBSERVER_PRIVATE_EXTENSION_NAME)) == 0)
{
flags |= MR_CREATE_MSFT_THIRD_PERSON_OBSERVER_EXT;
continue;
}
if (strncmp(XR_EXT_EYE_GAZE_INTERACTION_EXTENSION_NAME, extension, sizeof(XR_EXT_EYE_GAZE_INTERACTION_EXTENSION_NAME)) == 0)
{
flags |= MR_CREATE_EYE_GAZE_INTERACTION_EXT;
continue;
}
if (strncmp(XR_MSFT_HAND_INTERACTION_EXTENSION_NAME, extension, sizeof(XR_MSFT_HAND_INTERACTION_EXTENSION_NAME)) == 0)
{
flags |= MR_CREATE_MSFT_HAND_INTERACTION_EXT;
continue;
}
if (strncmp(XR_EXT_HAND_INTERACTION_EXTENSION_NAME, extension, sizeof(XR_EXT_HAND_INTERACTION_EXTENSION_NAME)) == 0)
{
flags |= MR_CREATE_HAND_INTERACTION_EXT;
continue;
}
if (strncmp(XR_FB_TOUCH_CONTROLLER_PRO_EXTENSION_NAME, extension, sizeof(XR_FB_TOUCH_CONTROLLER_PRO_EXTENSION_NAME)) == 0)
{
flags |= MR_CREATE_FB_TOUCH_CONTROLLER_PRO;
continue;
}
if (strncmp(XR_EXT_USER_PRESENCE_EXTENSION_NAME, extension, sizeof(XR_EXT_USER_PRESENCE_EXTENSION_NAME)) == 0)
{
flags |= MR_CREATE_USER_PRESENCE_EXT;
continue;
}
if (strncmp(XR_META_PERFORMANCE_METRICS_EXTENSION_NAME, extension, sizeof(XR_META_PERFORMANCE_METRICS_EXTENSION_NAME)) == 0)
{
flags |= MR_CREATE_META_PERFORMANCE_METRICS_EXT;
}
if (strncmp(XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME, extension, sizeof(XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME)) == 0)
{
flags |= MR_CREATE_HP_REVERB_G2_CONTROLLER;
}
if (strncmp(XR_EXT_PERFORMANCE_SETTINGS_EXTENSION_NAME, extension, sizeof(XR_EXT_PERFORMANCE_SETTINGS_EXTENSION_NAME)) == 0)
{
flags |= MR_CREATE_PERFORMANCE_SETTINGS_EXT;
}
if (strncmp(XR_META_TOUCH_CONTROLLER_PLUS_EXTENSION_NAME, extension, sizeof(XR_META_TOUCH_CONTROLLER_PLUS_EXTENSION_NAME)) == 0)
{
flags |= MR_CREATE_META_TOUCH_CONTROLLER_PLUS;
continue;
}
#ifdef XR_USE_PLATFORM_ANDROID
if (strncmp(XR_KHR_ANDROID_THREAD_SETTINGS_EXTENSION_NAME, extension, sizeof(XR_KHR_ANDROID_THREAD_SETTINGS_EXTENSION_NAME)) == 0)
{
flags |= MR_CREATE_KHR_ANDROID_THREAD_SETTINGS_EXT;
}
#endif
}
if ((flags & MR_CREATE_ALL_GFX_EXT) == 0)
flags |= MR_CREATE_NULL_GFX_EXT;
// Assign an instance id if one was not given
if (*instance == 0)
*instance = (XrInstance)(s_nextInstanceId++);
s_runtime = new MockRuntime(*instance, flags);
MOCK_HOOK(XR_SUCCESS);
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrDestroyInstance(XrInstance instance)
{
LOG_FUNC();
CHECK_INSTANCE(instance);
MOCK_HOOK_BEFORE();
delete s_runtime;
s_runtime = nullptr;
MOCK_HOOK_AFTER(XR_SUCCESS);
return XR_SUCCESS;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrGetInstanceProperties(XrInstance instance, XrInstanceProperties* instanceProperties)
{
LOG_FUNC();
CHECK_INSTANCE(instance);
instanceProperties->runtimeVersion = XR_MAKE_VERSION(0, 0, 2);
strncpy(instanceProperties->runtimeName, "Unity Mock Runtime", XR_MAX_RUNTIME_NAME_SIZE);
return XR_SUCCESS;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrPollEvent(XrInstance instance, XrEventDataBuffer* eventData)
{
LOG_FUNC();
CHECK_INSTANCE(instance);
MOCK_HOOK(s_runtime->GetNextEvent(eventData));
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrResultToString(XrInstance instance, XrResult value, char buffer[XR_MAX_RESULT_STRING_SIZE])
{
LOG_FUNC();
CHECK_INSTANCE(instance);
switch (value)
{
XR_LIST_ENUM_XrResult(ENUM_TO_STR) default : strncpy(buffer, ((value < 0 ? "XR_UNKNOWN_FAILURE_" : "XR_UNKNOWN_SUCCESS_") + std::to_string(value)).c_str(), XR_MAX_RESULT_STRING_SIZE - 1);
break;
}
return XR_SUCCESS;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrStructureTypeToString(XrInstance instance, XrStructureType value, char buffer[XR_MAX_STRUCTURE_NAME_SIZE])
{
LOG_FUNC();
CHECK_INSTANCE(instance);
switch (value)
{
XR_LIST_ENUM_XrStructureType(ENUM_TO_STR) default : strncpy(buffer, ("XR_UNKNOWN_STRUCTURE_TYPE_" + std::to_string(value)).c_str(), XR_MAX_RESULT_STRING_SIZE - 1);
break;
}
return XR_SUCCESS;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrGetSystem(XrInstance instance, const XrSystemGetInfo* getInfo, XrSystemId* systemId)
{
LOG_FUNC();
CHECK_INSTANCE(instance);
*systemId = (XrSystemId)2;
MOCK_HOOK(XR_SUCCESS);
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrGetSystemProperties(XrInstance instance, XrSystemId systemId, XrSystemProperties* properties)
{
LOG_FUNC();
CHECK_INSTANCE(instance);
MOCK_HOOK(s_runtime->GetSystemProperties(systemId, properties));
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrEnumerateEnvironmentBlendModes(XrInstance instance, XrSystemId systemId, XrViewConfigurationType viewConfigurationType, uint32_t environmentBlendModeCapacityInput, uint32_t* environmentBlendModeCountOutput, XrEnvironmentBlendMode* environmentBlendModes)
{
LOG_FUNC();
CHECK_INSTANCE(instance);
MOCK_HOOK(s_runtime->EnumerateEnvironmentBlendModes(systemId, viewConfigurationType, environmentBlendModeCapacityInput, environmentBlendModeCountOutput, environmentBlendModes));
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrCreateSession(XrInstance instance, const XrSessionCreateInfo* createInfo, XrSession* session)
{
LOG_FUNC();
CHECK_INSTANCE(instance);
MOCK_HOOK_BEFORE();
XrResult result = s_runtime->CreateSession(createInfo);
if (result == XR_SUCCESS)
*session = s_runtime->GetSession();
MOCK_HOOK_AFTER(result);
return result;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrDestroySession(XrSession session)
{
LOG_FUNC();
CHECK_SESSION(session);
MOCK_HOOK(s_runtime->DestroySession());
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrEnumerateReferenceSpaces(XrSession session, uint32_t spaceCapacityInput, uint32_t* spaceCountOutput, XrReferenceSpaceType* spaces)
{
LOG_FUNC();
CHECK_SESSION(session);
if (!spaceCountOutput)
return XR_ERROR_VALIDATION_FAILURE;
if (s_runtime->IsLocalFloorSpaceEnabled())
{
*spaceCountOutput = 5;
}
else
{
*spaceCountOutput = 4;
}
if (spaceCapacityInput == 0)
return XR_SUCCESS;
if (spaceCapacityInput < *spaceCountOutput || !spaces)
return XR_ERROR_VALIDATION_FAILURE;
spaces[0] = XR_REFERENCE_SPACE_TYPE_VIEW;
spaces[1] = XR_REFERENCE_SPACE_TYPE_LOCAL;
spaces[2] = XR_REFERENCE_SPACE_TYPE_STAGE;
spaces[3] = XR_REFERENCE_SPACE_TYPE_UNBOUNDED_MSFT;
if (s_runtime->IsLocalFloorSpaceEnabled())
{
spaces[4] = XR_REFERENCE_SPACE_TYPE_LOCAL_FLOOR_EXT;
}
return XR_SUCCESS;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrCreateReferenceSpace(XrSession session, const XrReferenceSpaceCreateInfo* createInfo, XrSpace* space)
{
LOG_FUNC();
CHECK_SESSION(session);
MOCK_HOOK(s_runtime->CreateReferenceSpace(createInfo, space));
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrGetReferenceSpaceBoundsRect(XrSession session, XrReferenceSpaceType referenceSpaceType, XrExtent2Df* bounds)
{
LOG_FUNC();
CHECK_SESSION(session);
MOCK_HOOK(s_runtime->GetReferenceSpaceBoundsRect(referenceSpaceType, bounds));
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrCreateActionSpace(XrSession session, const XrActionSpaceCreateInfo* createInfo, XrSpace* space)
{
LOG_FUNC();
CHECK_SESSION(session);
MOCK_HOOK(s_runtime->CreateActionSpace(createInfo, space));
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrLocateSpace(XrSpace space, XrSpace baseSpace, XrTime time, XrSpaceLocation* location)
{
LOG_FUNC();
CHECK_RUNTIME();
MOCK_HOOK(s_runtime->LocateSpace(space, baseSpace, time, location));
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrDestroySpace(XrSpace space)
{
LOG_FUNC();
MOCK_HOOK(XR_SUCCESS);
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrEnumerateViewConfigurations(XrInstance instance, XrSystemId systemId, uint32_t viewConfigurationTypeCapacityInput, uint32_t* viewConfigurationTypeCountOutput, XrViewConfigurationType* viewConfigurationTypes)
{
LOG_FUNC();
CHECK_INSTANCE(instance);
MOCK_HOOK(s_runtime->EnumerateViewConfigurations(systemId, viewConfigurationTypeCapacityInput, viewConfigurationTypeCountOutput, viewConfigurationTypes));
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrGetViewConfigurationProperties(XrInstance instance, XrSystemId systemId, XrViewConfigurationType viewConfigurationType, XrViewConfigurationProperties* configurationProperties)
{
LOG_FUNC();
MOCK_HOOK(XR_SUCCESS);
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrEnumerateViewConfigurationViews(XrInstance instance, XrSystemId systemId, XrViewConfigurationType viewConfigurationType, uint32_t viewCapacityInput, uint32_t* viewCountOutput, XrViewConfigurationView* views)
{
LOG_FUNC();
CHECK_INSTANCE(instance);
MOCK_HOOK(s_runtime->EnumerateViewConfigurationViews(systemId, viewConfigurationType, viewCapacityInput, viewCountOutput, views));
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrEnumerateSwapchainFormats(XrSession session, uint32_t formatCapacityInput, uint32_t* formatCountOutput, int64_t* formats)
{
LOG_FUNC();
*formatCountOutput = 1;
if (formatCapacityInput == 0)
return XR_SUCCESS;
if (formatCapacityInput < *formatCountOutput)
return XR_ERROR_VALIDATION_FAILURE;
formats[0] = 0;
return XR_SUCCESS;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrCreateSwapchain(XrSession session, const XrSwapchainCreateInfo* createInfo, XrSwapchain* swapchain)
{
LOG_FUNC();
static uint64_t uniqueSwapchainHandle = 0;
*swapchain = (XrSwapchain)++uniqueSwapchainHandle;
MOCK_HOOK(XR_SUCCESS);
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrDestroySwapchain(XrSwapchain swapchain)
{
LOG_FUNC();
MOCK_HOOK(XR_SUCCESS);
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrEnumerateSwapchainImages(XrSwapchain swapchain, uint32_t imageCapacityInput, uint32_t* imageCountOutput, XrSwapchainImageBaseHeader* images)
{
LOG_FUNC();
*imageCountOutput = 1;
if (imageCapacityInput == 0)
return XR_SUCCESS;
if (imageCapacityInput < *imageCountOutput)
return XR_ERROR_VALIDATION_FAILURE;
return XR_SUCCESS;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrAcquireSwapchainImage(XrSwapchain swapchain, const XrSwapchainImageAcquireInfo* acquireInfo, uint32_t* index)
{
LOG_FUNC();
*index = 0;
MOCK_HOOK(XR_SUCCESS);
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrWaitSwapchainImage(XrSwapchain swapchain, const XrSwapchainImageWaitInfo* waitInfo)
{
LOG_FUNC();
MOCK_HOOK(XR_SUCCESS);
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrReleaseSwapchainImage(XrSwapchain swapchain, const XrSwapchainImageReleaseInfo* releaseInfo)
{
LOG_FUNC();
MOCK_HOOK(XR_SUCCESS);
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrBeginSession(XrSession session, const XrSessionBeginInfo* beginInfo)
{
LOG_FUNC();
CHECK_SESSION(session);
MOCK_HOOK(s_runtime->BeginSession(beginInfo));
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrEndSession(XrSession session)
{
LOG_FUNC();
CHECK_SESSION(session);
//CHECK_EXPECTED_RESULT(XR_SUCCESS, XR_ERROR_SESSION_NOT_STOPPING);
MOCK_HOOK(s_runtime->EndSession());
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrRequestExitSession(XrSession session)
{
LOG_FUNC();
CHECK_SESSION(session);
MOCK_HOOK(s_runtime->RequestExitSession());
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrWaitFrame(XrSession session, const XrFrameWaitInfo* frameWaitInfo, XrFrameState* frameState)
{
LOG_FUNC();
CHECK_SESSION(session);
MOCK_HOOK(s_runtime->WaitFrame(frameWaitInfo, frameState));
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrBeginFrame(XrSession session, const XrFrameBeginInfo* frameBeginInfo)
{
LOG_FUNC();
MOCK_HOOK(XR_SUCCESS);
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrEndFrame(XrSession session, const XrFrameEndInfo* frameEndInfo)
{
LOG_FUNC();
CHECK_SESSION(session);
MOCK_HOOK(s_runtime->EndFrame(frameEndInfo));
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrLocateViews(XrSession session, const XrViewLocateInfo* viewLocateInfo, XrViewState* viewState, uint32_t viewCapacityInput, uint32_t* viewCountOutput, XrView* views)
{
LOG_FUNC();
CHECK_SESSION(session);
MOCK_HOOK(s_runtime->LocateViews(viewLocateInfo, viewState, viewCapacityInput, viewCountOutput, views));
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrStringToPath(XrInstance instance, const char* pathString, XrPath* path)
{
LOG_FUNC();
CHECK_INSTANCE(instance);
MOCK_HOOK(s_runtime->StringToPath(pathString, path));
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrPathToString(XrInstance instance, XrPath path, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, char* buffer)
{
LOG_FUNC();
CHECK_INSTANCE(instance);
MOCK_HOOK(s_runtime->PathToString(path, bufferCapacityInput, bufferCountOutput, buffer));
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrCreateActionSet(XrInstance instance, const XrActionSetCreateInfo* createInfo, XrActionSet* actionSet)
{
LOG_FUNC();
CHECK_INSTANCE(instance);
MOCK_HOOK(s_runtime->CreateActionSet(createInfo, actionSet));
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrDestroyActionSet(XrActionSet actionSet)
{
LOG_FUNC();
CHECK_RUNTIME();
MOCK_HOOK(s_runtime->DestroyActionSet(actionSet));
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrCreateAction(XrActionSet actionSet, const XrActionCreateInfo* createInfo, XrAction* action)
{
LOG_FUNC();
CHECK_RUNTIME();
MOCK_HOOK(s_runtime->CreateAction(actionSet, createInfo, action));
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrDestroyAction(XrAction action)
{
LOG_FUNC();
CHECK_RUNTIME();
MOCK_HOOK(s_runtime->DestroyAction(action));
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrSuggestInteractionProfileBindings(XrInstance instance, const XrInteractionProfileSuggestedBinding* suggestedBindings)
{
LOG_FUNC();
CHECK_INSTANCE(instance);
MOCK_HOOK(s_runtime->SuggestInteractionProfileBindings(suggestedBindings));
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrAttachSessionActionSets(XrSession session, const XrSessionActionSetsAttachInfo* attachInfo)
{
LOG_FUNC();
CHECK_SESSION(session);
MOCK_HOOK(s_runtime->AttachSessionActionSets(attachInfo));
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrGetCurrentInteractionProfile(XrSession session, XrPath topLevelUserPath, XrInteractionProfileState* interactionProfile)
{
LOG_FUNC();
CHECK_SESSION(session);
MOCK_HOOK(s_runtime->GetCurrentInteractionProfile(topLevelUserPath, interactionProfile));
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrGetActionStateBoolean(XrSession session, const XrActionStateGetInfo* getInfo, XrActionStateBoolean* state)
{
LOG_FUNC();
CHECK_SESSION(session);
MOCK_HOOK(s_runtime->GetActionStateBoolean(getInfo, state));
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrGetActionStateFloat(XrSession session, const XrActionStateGetInfo* getInfo, XrActionStateFloat* state)
{
LOG_FUNC();
CHECK_SESSION(session);
MOCK_HOOK(s_runtime->GetActionStateFloat(getInfo, state));
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrGetActionStateVector2f(XrSession session, const XrActionStateGetInfo* getInfo, XrActionStateVector2f* state)
{
LOG_FUNC();
CHECK_SESSION(session);
MOCK_HOOK(s_runtime->GetActionStateVector2f(getInfo, state));
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrGetActionStatePose(XrSession session, const XrActionStateGetInfo* getInfo, XrActionStatePose* state)
{
LOG_FUNC();
CHECK_SESSION(session);
MOCK_HOOK(s_runtime->GetActionStatePose(getInfo, state));
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrSyncActions(XrSession session, const XrActionsSyncInfo* syncInfo)
{
LOG_FUNC();
CHECK_SESSION(session);
MOCK_HOOK(s_runtime->SyncActions(syncInfo));
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrEnumerateBoundSourcesForAction(XrSession session, const XrBoundSourcesForActionEnumerateInfo* enumerateInfo, uint32_t sourceCapacityInput, uint32_t* sourceCountOutput, XrPath* sources)
{
LOG_FUNC();
CHECK_SESSION(session)
MOCK_HOOK(s_runtime->EnumerateBoundSourcesForAction(enumerateInfo, sourceCapacityInput, sourceCountOutput, sources));
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrGetInputSourceLocalizedName(XrSession session, const XrInputSourceLocalizedNameGetInfo* getInfo, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, char* buffer)
{
LOG_FUNC();
CHECK_SESSION(session);
MOCK_HOOK(s_runtime->GetInputSourceLocalizedName(getInfo, bufferCapacityInput, bufferCountOutput, buffer));
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrApplyHapticFeedback(XrSession session, const XrHapticActionInfo* hapticActionInfo, const XrHapticBaseHeader* hapticFeedback)
{
LOG_FUNC();
CHECK_SESSION(session);
MOCK_HOOK(s_runtime->ApplyHapticFeedback(hapticActionInfo, hapticFeedback));
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrStopHapticFeedback(XrSession session, const XrHapticActionInfo* hapticActionInfo)
{
LOG_FUNC();
CHECK_SESSION(session);
MOCK_HOOK(s_runtime->StopHapticFeedback(hapticActionInfo));
}
extern uint32_t s_VisibilityMaskVerticesSizes[2][3];
extern uint32_t s_VisibilityMaskIndicesSizes[2][3];
extern XrVector2f s_VisibilityMaskVertices[2][3][99];
extern uint32_t s_VisibilityMaskIndices[2][3][200];
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrGetVisibilityMaskKHR(XrSession session, XrViewConfigurationType viewConfigurationType, uint32_t viewIndex, XrVisibilityMaskTypeKHR visibilityMaskType, XrVisibilityMaskKHR* visibilityMask)
{
const uint32_t visiblityMaskTypeLookup = visibilityMaskType - 1;
visibilityMask->vertexCountOutput = s_VisibilityMaskVerticesSizes[viewIndex][visiblityMaskTypeLookup];
visibilityMask->indexCountOutput = s_VisibilityMaskIndicesSizes[viewIndex][visiblityMaskTypeLookup];
if (visibilityMask->vertexCapacityInput == 0 || visibilityMask->indexCapacityInput == 0)
return XR_SUCCESS;
if (visibilityMask->vertexCapacityInput < visibilityMask->vertexCountOutput ||
visibilityMask->indexCapacityInput < visibilityMask->indexCountOutput)
return XR_ERROR_VALIDATION_FAILURE;
memcpy(visibilityMask->vertices, &s_VisibilityMaskVertices[viewIndex][visiblityMaskTypeLookup], sizeof(XrVector2f) * visibilityMask->vertexCountOutput);
memcpy(visibilityMask->indices, &s_VisibilityMaskIndices[viewIndex][visiblityMaskTypeLookup], sizeof(uint32_t) * visibilityMask->indexCountOutput);
return XR_SUCCESS;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrGetInstanceProcAddr(XrInstance instance, const char* name, PFN_xrVoidFunction* function)
{
LOG_FUNC();
if (s_runtime != nullptr && XR_SUCCESS == s_runtime->GetInstanceProcAddr(name, function))
return XR_SUCCESS;
GET_PROC_ADDRESS(xrEnumerateApiLayerProperties)
GET_PROC_ADDRESS(xrEnumerateInstanceExtensionProperties)
GET_PROC_ADDRESS(xrCreateInstance)
GET_PROC_ADDRESS(xrDestroyInstance)
GET_PROC_ADDRESS(xrGetInstanceProperties)
GET_PROC_ADDRESS(xrPollEvent)
GET_PROC_ADDRESS(xrResultToString)
GET_PROC_ADDRESS(xrStructureTypeToString)
GET_PROC_ADDRESS(xrGetSystem)
GET_PROC_ADDRESS(xrGetSystemProperties)
GET_PROC_ADDRESS(xrEnumerateEnvironmentBlendModes)
GET_PROC_ADDRESS(xrCreateSession)
GET_PROC_ADDRESS(xrDestroySession)
GET_PROC_ADDRESS(xrEnumerateReferenceSpaces)
GET_PROC_ADDRESS(xrCreateReferenceSpace)
GET_PROC_ADDRESS(xrGetReferenceSpaceBoundsRect)
GET_PROC_ADDRESS(xrCreateActionSpace)
GET_PROC_ADDRESS(xrLocateSpace)
GET_PROC_ADDRESS(xrDestroySpace)
GET_PROC_ADDRESS(xrEnumerateViewConfigurations)
GET_PROC_ADDRESS(xrGetViewConfigurationProperties)
GET_PROC_ADDRESS(xrEnumerateViewConfigurationViews)
GET_PROC_ADDRESS(xrEnumerateSwapchainFormats)
GET_PROC_ADDRESS(xrCreateSwapchain)
GET_PROC_ADDRESS(xrDestroySwapchain)
GET_PROC_ADDRESS(xrEnumerateSwapchainImages)
GET_PROC_ADDRESS(xrAcquireSwapchainImage)
GET_PROC_ADDRESS(xrWaitSwapchainImage)
GET_PROC_ADDRESS(xrReleaseSwapchainImage)
GET_PROC_ADDRESS(xrBeginSession)
GET_PROC_ADDRESS(xrEndSession)
GET_PROC_ADDRESS(xrRequestExitSession)
GET_PROC_ADDRESS(xrWaitFrame)
GET_PROC_ADDRESS(xrBeginFrame)
GET_PROC_ADDRESS(xrEndFrame)
GET_PROC_ADDRESS(xrLocateViews)
GET_PROC_ADDRESS(xrStringToPath)
GET_PROC_ADDRESS(xrPathToString)
GET_PROC_ADDRESS(xrCreateActionSet)
GET_PROC_ADDRESS(xrDestroyActionSet)
GET_PROC_ADDRESS(xrCreateAction)
GET_PROC_ADDRESS(xrDestroyAction)
GET_PROC_ADDRESS(xrSuggestInteractionProfileBindings)
GET_PROC_ADDRESS(xrAttachSessionActionSets)
GET_PROC_ADDRESS(xrGetCurrentInteractionProfile)
GET_PROC_ADDRESS(xrGetActionStateBoolean)
GET_PROC_ADDRESS(xrGetActionStateFloat)
GET_PROC_ADDRESS(xrGetActionStateVector2f)
GET_PROC_ADDRESS(xrGetActionStatePose)
GET_PROC_ADDRESS(xrSyncActions)
GET_PROC_ADDRESS(xrEnumerateBoundSourcesForAction)
GET_PROC_ADDRESS(xrGetInputSourceLocalizedName)
GET_PROC_ADDRESS(xrApplyHapticFeedback)
GET_PROC_ADDRESS(xrStopHapticFeedback)
GET_PROC_ADDRESS(xrGetVisibilityMaskKHR)
if (XR_SUCCEEDED(GetProcAddrMockAPI(instance, name, function)))
return XR_SUCCESS;
return XR_ERROR_FUNCTION_UNSUPPORTED;
}
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API SetXRTrace(IUnityXRTrace* trace)
{
s_Trace = trace;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrNegotiateLoaderRuntimeInterface(const XrNegotiateLoaderInfo* loaderInfo, XrNegotiateRuntimeRequest* runtimeRequest)
{
runtimeRequest->getInstanceProcAddr = xrGetInstanceProcAddr;
runtimeRequest->runtimeApiVersion = XR_CURRENT_API_VERSION;
runtimeRequest->runtimeInterfaceVersion = 1;
return XR_SUCCESS;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,396 @@
#pragma once
typedef XrFlags64 MockRuntimeCreateFlags;
static const MockRuntimeCreateFlags MR_CREATE_DRIVER_EXT = 0x00000001;
static const MockRuntimeCreateFlags MR_CREATE_NULL_GFX_EXT = 0x00000002;
static const MockRuntimeCreateFlags MR_CREATE_CONFORMANCE_AUTOMATION_EXT = 0x00000004;
static const MockRuntimeCreateFlags MR_CREATE_COMPOSITION_LAYER_DEPTH_EXT = 0x00000008;
static const MockRuntimeCreateFlags MR_CREATE_VULKAN_GFX_EXT = 0x00000010;
static const MockRuntimeCreateFlags MR_CREATE_D3D11_GFX_EXT = 0x00000020;
static const MockRuntimeCreateFlags MR_CREATE_VARJO_QUAD_VIEWS_EXT = 0x00000040;
static const MockRuntimeCreateFlags MR_CREATE_MSFT_SECONDARY_VIEW_CONFIGURATION_EXT = 0x00000080;
static const MockRuntimeCreateFlags MR_CREATE_MSFT_FIRST_PERSON_OBSERVER_EXT = 0x00000100;
static const MockRuntimeCreateFlags MR_CREATE_EYE_GAZE_INTERACTION_EXT = 0x00000200;
static const MockRuntimeCreateFlags MR_CREATE_MSFT_HAND_INTERACTION_EXT = 0x00000400;
static const MockRuntimeCreateFlags MR_CREATE_MSFT_THIRD_PERSON_OBSERVER_EXT = 0x00000800;
static const MockRuntimeCreateFlags MR_CREATE_FB_TOUCH_CONTROLLER_PRO = 0x00001000;
static const MockRuntimeCreateFlags MR_CREATE_META_PERFORMANCE_METRICS_EXT = 0x00002000;
static const MockRuntimeCreateFlags MR_CREATE_HP_REVERB_G2_CONTROLLER = 0x00004000;
static const MockRuntimeCreateFlags MR_CREATE_HAND_INTERACTION_EXT = 0x00008000;
static const MockRuntimeCreateFlags MR_CREATE_D3D12_GFX_EXT = 0x00020000;
static const MockRuntimeCreateFlags MR_CREATE_PERFORMANCE_SETTINGS_EXT = 0x00040000;
static const MockRuntimeCreateFlags MR_CREATE_USER_PRESENCE_EXT = 0x00080000;
static const MockRuntimeCreateFlags MR_CREATE_KHR_ANDROID_THREAD_SETTINGS_EXT = 0x00100000;
static const MockRuntimeCreateFlags MR_CREATE_META_TOUCH_CONTROLLER_PLUS = 0x00200000;
static const MockRuntimeCreateFlags MR_CREATE_ALL_GFX_EXT = MR_CREATE_VULKAN_GFX_EXT | MR_CREATE_NULL_GFX_EXT | MR_CREATE_D3D11_GFX_EXT | MR_CREATE_D3D12_GFX_EXT;
class MockRuntime
{
public:
MockRuntime(XrInstance instance, MockRuntimeCreateFlags flags);
~MockRuntime();
XrInstance GetInstance() const
{
return instance;
}
XrSession GetSession() const
{
return session;
}
XrSessionState GetSessionState() const
{
return currentState;
}
bool HasValidSession() const
{
return session != XR_NULL_HANDLE;
}
bool HasValidInstance() const
{
return instance != XR_NULL_HANDLE;
}
bool IsSessionState(XrSessionState state) const
{
return currentState == state;
}
bool IsConformanceAutomationEnabled() const
{
return (createFlags & MR_CREATE_CONFORMANCE_AUTOMATION_EXT) != 0;
}
bool IsLocalFloorSpaceEnabled() const
{
return true;
}
XrResult GetNextEvent(XrEventDataBuffer* eventData);
XrResult CreateSession(const XrSessionCreateInfo* createInfo);
XrResult BeginSession(const XrSessionBeginInfo* beginInfo);
XrResult EndSession();
XrResult DestroySession();
void SetMockSession(XrInstance instance, XrSession* session);
void SetSupportingDriverExtension(XrInstance instance, bool usingExtension);
bool IsStateTransitionValid(XrSessionState newState) const;
bool ChangeSessionStateFrom(XrSessionState fromState, XrSessionState toState);
void ChangeSessionState(XrSessionState state);
bool IsSessionRunning() const
{
return isRunning;
}
XrResult RequestExitSession();
bool HasExitBeenRequested() const
{
return exitSessionRequested;
}
void SetExtentsForReferenceSpace(XrReferenceSpaceType referenceSpace, XrExtent2Df extents);
XrResult GetReferenceSpaceBoundsRect(XrReferenceSpaceType referenceSpace, XrExtent2Df* extents);
XrResult CauseInstanceLoss();
XrResult CauseUserPresenceChange(bool hasUserPresent);
bool IsInstanceLost(XrInstance instance) const
{
return instanceIsLost;
};
void SetNullGfx(bool nullGfx);
bool IsNullGfx() const
{
return (createFlags & MR_CREATE_NULL_GFX_EXT) != 0;
}
bool IsVulkanGfx() const
{
return (createFlags & MR_CREATE_VULKAN_GFX_EXT) != 0;
}
bool IsD3D11Gfx() const
{
return (createFlags & MR_CREATE_D3D11_GFX_EXT) != 0;
}
bool IsD3D12Gfx() const
{
return (createFlags & MR_CREATE_D3D12_GFX_EXT) != 0;
}
XrResult WaitFrame(const XrFrameWaitInfo* frameWaitInfo, XrFrameState* frameState);
XrResult LocateSpace(XrSpace space, XrSpace baseSpace, XrTime time, XrSpaceLocation* location);
void SetSpace(XrReferenceSpaceType referenceSpaceType, XrPosef pose, XrSpaceLocationFlags spaceLocationFlags);
void SetSpace(XrAction action, XrPosef pose, XrSpaceLocationFlags spaceLocationFlags);
void SetViewPose(XrViewConfigurationType viewConfigurationType, int viewIndex, XrPosef pose, XrFovf fov);
void SetViewStateFlags(XrViewConfigurationType viewConfigurationType, XrViewStateFlags viewStateFlags);
XrResult GetEndFrameStats(int* primaryLayerCount, int* secondaryLayerCount);
XrResult EndFrame(const XrFrameEndInfo* frameEndInfo);
XrResult CreateActionSet(const XrActionSetCreateInfo* createInfo, XrActionSet* actionSet);
XrResult DestroyActionSet(XrActionSet actionSet);
XrResult CreateAction(XrActionSet actionSet, const XrActionCreateInfo* createInfo, XrAction* action);
XrResult DestroyAction(XrAction action);
XrResult SyncActions(const XrActionsSyncInfo* syncInfo);
XrResult GetActionStateFloat(const XrActionStateGetInfo* getInfo, XrActionStateFloat* state);
XrResult GetActionStateBoolean(const XrActionStateGetInfo* getInfo, XrActionStateBoolean* state);
XrResult GetActionStateVector2f(const XrActionStateGetInfo* getInfo, XrActionStateVector2f* state);
XrResult GetActionStatePose(const XrActionStateGetInfo* getInfo, XrActionStatePose* state);
XrResult CreateReferenceSpace(const XrReferenceSpaceCreateInfo* createInfo, XrSpace* space);
XrResult CreateActionSpace(const XrActionSpaceCreateInfo* createInfo, XrSpace* space);
void VisibilityMaskChangedKHR(XrViewConfigurationType viewConfigurationType, uint32_t viewIndex);
XrResult StringToPath(const char* pathString, XrPath* path);
XrPath StringToPath(const char* pathString);
std::string PathToString(XrPath) const;
XrResult PathToString(XrPath path, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, char* buffer) const;
// Return the user path portion of the given path handle
XrPath GetUserPath(XrPath path) const
{
return path & 0x00000000FFFFFFFFull;
}
// Return the component path portion of the given path handle
XrPath GetComponentPath(XrPath path) const
{
return path & 0xFFFFFFFF00000000ull;
}
// Make a new path using the given user path and component path
XrPath MakePath(XrPath userPath, XrPath componentPath) const;
// Append the given path
XrPath AppendPath(XrPath path, const char* append);
// Returns true if the given path is a valid path handle
bool IsValidHandle(XrPath path) const;
XrResult GetCurrentInteractionProfile(XrPath topLevelUserPath, XrInteractionProfileState* interactionProfile);
XrResult AttachSessionActionSets(const XrSessionActionSetsAttachInfo* attachInfo);
XrResult SuggestInteractionProfileBindings(const XrInteractionProfileSuggestedBinding* suggestedBindings);
XrResult GetInputSourceLocalizedName(const XrInputSourceLocalizedNameGetInfo* getInfo, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, char* buffer);
XrResult LocateViews(const XrViewLocateInfo* viewLocateInfo, XrViewState* viewState, uint32_t viewCapacityInput, uint32_t* viewCountOutput, XrView* views);
XrResult EnumerateBoundSourcesForAction(const XrBoundSourcesForActionEnumerateInfo* enumerateInfo, uint32_t sourceCapacityInput, uint32_t* sourceCountOutput, XrPath* sources);
XrResult EnumerateViewConfigurations(XrSystemId systemId, uint32_t viewConfigurationTypeCapacityInput, uint32_t* viewConfigurationTypeCountOutput, XrViewConfigurationType* viewConfigurationTypes);
XrResult EnumerateViewConfigurationViews(XrSystemId systemId, XrViewConfigurationType viewConfigurationType, uint32_t viewCapacityInput, uint32_t* viewCountOutput, XrViewConfigurationView* views);
XrResult EnumerateEnvironmentBlendModes(XrSystemId systemId, XrViewConfigurationType viewConfigurationType, uint32_t environmentBlendModeCapacityInput, uint32_t* environmentBlendModeCountOutput, XrEnvironmentBlendMode* environmentBlendModes);
XrResult ApplyHapticFeedback(const XrHapticActionInfo* hapticActionInfo, const XrHapticBaseHeader* hapticFeedback);
XrResult StopHapticFeedback(const XrHapticActionInfo* hapticActionInfo);
XrResult GetInstanceProcAddr(const char* name, PFN_xrVoidFunction* function);
XrResult ActivateSecondaryView(XrViewConfigurationType viewConfiguration, bool activate);
XrResult RegisterScriptEventCallback(PFN_ScriptEventCallback callback);
XrResult GetSystemProperties(XrSystemId systemId, XrSystemProperties* properties);
XrResult CausePerformanceSettingsNotification(XrPerfSettingsDomainEXT domain, XrPerfSettingsSubDomainEXT subdomain, XrPerfSettingsNotificationLevelEXT nextLevel);
private:
struct MockView
{
XrViewConfigurationView configuration;
XrPosef pose;
XrFovf fov;
};
struct MockViewConfiguration
{
XrViewStateFlags stateFlags;
std::vector<MockView> views;
bool primary;
bool enabled;
bool active;
};
struct MockAction
{
XrAction action;
XrPath path;
std::string name;
std::string localizedName;
XrActionType type;
std::vector<MockInputState*> bindings;
std::vector<XrPath> userPaths;
bool isDestroyed;
};
struct MockActionSet
{
XrActionSet actionSet;
bool attached;
std::string name;
std::string localizedName;
std::vector<MockAction> actions;
bool isDestroyed;
};
struct MockInteractionInputSource
{
XrPath path;
XrActionType actionType;
const char* localizedName;
};
struct MockInteractionProfile
{
XrPath path;
const char* localizedName;
std::vector<XrPath> userPaths;
};
struct MockUserPath
{
std::string path;
std::string localizedName;
const MockInteractionProfile* profile;
};
struct MockSpace
{
XrPosef pose;
bool isDestroyed;
XrAction action;
XrPath subActionPath;
XrSpaceLocationFlags locationFlags;
XrReferenceSpaceType referenceSpaceType;
};
struct MockReferenceSpace
{
bool validExtent;
XrExtent2Df extent;
};
uint64_t GetNextHandle()
{
return ++nextHandle;
}
template <class T>
T GetNextHandle()
{
return (T)GetNextHandle();
}
bool IsValidUserPath(XrPath path) const
{
return path != XR_NULL_PATH && GetUserPath(path) == path;
}
MockActionSet* GetMockActionSet(XrActionSet actionSet);
MockActionSet* GetMockActionSet(XrAction action);
MockAction* GetMockAction(XrAction action);
const MockInteractionProfile* GetMockInteractionProfile(XrPath interactionProfile) const;
bool IsActionAttached(XrAction action);
MockInputState* GetMockInputState(const MockInteractionProfile& mockProfile, XrPath path, XrActionType actionType = XR_ACTION_TYPE_MAX_ENUM);
MockSpace* GetMockSpace(XrSpace space);
MockViewConfiguration* GetMockViewConfiguration(XrViewConfigurationType viewConfigType);
MockView* GetMockView(XrViewConfigurationType viewConfigType, size_t viewIndex);
MockUserPath* GetMockUserPath(XrPath path);
MockReferenceSpace* GetMockReferenceSpace(XrReferenceSpaceType referenceSpaceType);
XrResult ValidateName(const char* name) const;
XrResult ValidatePath(const char* path) const;
XrTime GetPredictedTime();
void InitializeInteractionProfiles();
bool SetActiveInteractionProfile(MockUserPath* mockUserPath, const MockInteractionProfile* mockProfile);
MockInputState* AddMockInputState(XrPath interactionPath, XrPath path, XrActionType actionType, const char* localizedName);
//// XR_MSFT_secondary_view_configuration
XrResult MSFTSecondaryViewConfiguration_BeginSession(const XrSessionBeginInfo* beginInfo);
XrResult MSFTSecondaryViewConfiguration_WaitFrame(const XrFrameWaitInfo* frameWaitInfo, XrFrameState* frameState);
XrResult MSFTSecondaryViewConfiguration_EndFrame(const XrFrameEndInfo* frameEndInfo);
template <typename T>
void QueueEvent(const T& event)
{
QueueEvent((const XrEventDataBuffer&)event);
}
void QueueEvent(const XrEventDataBuffer& buffer);
XrEventDataBuffer GetNextEvent();
std::vector<XrSecondaryViewConfigurationStateMSFT> secondaryViewConfigurationStates;
//// XR_MSFT_first_person_observer
XrResult MSFTFirstPersonObserver_Init();
//// XR_MSFT_first_person_observer
XrResult MSFTThirdPersonObserver_Init();
std::vector<MockInteractionProfile> interactionProfiles;
MockRuntimeCreateFlags createFlags;
std::queue<XrEventDataBuffer> eventQueue;
XrInstance instance;
XrSession session;
XrSessionState currentState;
XrEnvironmentBlendMode blendMode{XR_ENVIRONMENT_BLEND_MODE_OPAQUE};
bool isRunning;
bool exitSessionRequested;
bool actionSetsAttached;
XrTime lastWaitFrame;
XrTime invalidTimeThreshold;
std::map<XrViewConfigurationType, MockViewConfiguration> viewConfigurations;
XrViewConfigurationType primaryViewConfiguration;
std::vector<std::string> componentPathStrings;
std::vector<MockUserPath> userPaths;
std::chrono::time_point<std::chrono::high_resolution_clock> startTime;
bool instanceIsLost;
bool nullGfx;
int primaryLayersRendered;
int secondaryLayersRendered;
uint64_t nextHandle;
std::vector<MockActionSet> actionSets;
std::vector<MockInputState> inputStates;
std::vector<MockSpace> spaces;
std::map<XrReferenceSpaceType, MockReferenceSpace> referenceSpaces;
PFN_ScriptEventCallback scriptEventCallback;
};
extern MockRuntime* s_runtime;

View File

@@ -0,0 +1,570 @@
#include "mock.h"
struct MockInputSourcePath
{
const char* path;
XrActionType type;
const char* localizedName;
};
struct MockInteractionProfileDef
{
const char* localizedName;
const char* name;
MockRuntimeCreateFlags requiredFlags;
std::vector<const char*> userPaths;
std::vector<MockInputSourcePath> inputSources;
};
static std::vector<MockInteractionProfileDef> s_InteractionProfiles = {
// Mock Controller
{
"Mock Controller",
"/interaction_profiles/unity/mock_controller",
0,
{"/user/hand/left",
"/user/hand/right"},
{
{"/user/hand/left/input/trigger/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Button"},
{"/user/hand/left/input/trigger/value", XR_ACTION_TYPE_FLOAT_INPUT, "Trigger"},
{"/user/hand/left/input/thumbstick/value", XR_ACTION_TYPE_VECTOR2F_INPUT, "Thumbstick"},
{"/user/hand/left/input/grip/pose", XR_ACTION_TYPE_POSE_INPUT, "Grip"},
{"/user/hand/left/output/haptic", XR_ACTION_TYPE_VIBRATION_OUTPUT, "Haptic"},
{"/user/hand/right/input/trigger/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Button"},
{"/user/hand/right/input/trigger/value", XR_ACTION_TYPE_FLOAT_INPUT, "Trigger"},
{"/user/hand/right/input/thumbstick/value", XR_ACTION_TYPE_VECTOR2F_INPUT, "Thumbstick"},
{"/user/hand/right/input/grip/pose", XR_ACTION_TYPE_POSE_INPUT, "Grip"},
{"/user/hand/right/output/haptic", XR_ACTION_TYPE_VIBRATION_OUTPUT, "Haptic"},
}},
// KHR Simple controller
{
"KHR Simple Controller",
"/interaction_profiles/khr/simple_controller",
0,
{"/user/hand/left",
"/user/hand/right"},
{{"/user/hand/left/input/select/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Select"},
{"/user/hand/left/input/menu/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Menu"},
{"/user/hand/left/input/grip/pose", XR_ACTION_TYPE_POSE_INPUT, "Grip"},
{"/user/hand/left/input/aim/pose", XR_ACTION_TYPE_POSE_INPUT, "Aim"},
{"/user/hand/left/output/haptic", XR_ACTION_TYPE_VIBRATION_OUTPUT, "Haptic"},
{"/user/hand/right/input/select/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Select"},
{"/user/hand/right/input/menu/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Menu"},
{"/user/hand/right/input/grip/pose", XR_ACTION_TYPE_POSE_INPUT, "Grip"},
{"/user/hand/right/input/aim/pose", XR_ACTION_TYPE_POSE_INPUT, "Aim"},
{"/user/hand/right/output/haptic", XR_ACTION_TYPE_VIBRATION_OUTPUT, "Haptic"}}},
// Microsoft Mixed Reality Motion Controller Profile
{
"Mixed Reality Controller",
"/interaction_profiles/microsoft/motion_controller",
0,
{"/user/hand/left",
"/user/hand/right"},
{{"/user/hand/left/input/menu/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Menu"},
{"/user/hand/left/input/squeeze/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Squeeze"},
{"/user/hand/left/input/trigger/value", XR_ACTION_TYPE_FLOAT_INPUT, "Trigger"},
{"/user/hand/left/input/thumbstick/x", XR_ACTION_TYPE_FLOAT_INPUT, "Thumbstick X"},
{"/user/hand/left/input/thumbstick/y", XR_ACTION_TYPE_FLOAT_INPUT, "Thumbstick Y"},
{"/user/hand/left/input/thumbstick/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Thumbstick Click"},
{"/user/hand/left/input/thumbstick", XR_ACTION_TYPE_VECTOR2F_INPUT, "Thumbstick"},
{"/user/hand/left/input/trackpad/x", XR_ACTION_TYPE_FLOAT_INPUT, "Trackpad X"},
{"/user/hand/left/input/trackpad/y", XR_ACTION_TYPE_FLOAT_INPUT, "Trackpad Y"},
{"/user/hand/left/input/trackpad", XR_ACTION_TYPE_VECTOR2F_INPUT, "Trackpad"},
{"/user/hand/left/input/trackpad/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Trackpad Click"},
{"/user/hand/left/input/trackpad/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "Trackpad Touch"},
{"/user/hand/left/input/grip/pose", XR_ACTION_TYPE_POSE_INPUT, "Grip"},
{"/user/hand/left/input/aim/pose", XR_ACTION_TYPE_POSE_INPUT, "Aim"},
{"/user/hand/left/output/haptic", XR_ACTION_TYPE_VIBRATION_OUTPUT, "Haptic"},
{"/user/hand/right/input/menu/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Menu"},
{"/user/hand/right/input/squeeze/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Squeeze"},
{"/user/hand/right/input/trigger/value", XR_ACTION_TYPE_FLOAT_INPUT, "Trigger"},
{"/user/hand/right/input/thumbstick/x", XR_ACTION_TYPE_FLOAT_INPUT, "Thumbstick X"},
{"/user/hand/right/input/thumbstick/y", XR_ACTION_TYPE_FLOAT_INPUT, "Thumbstick Y"},
{"/user/hand/right/input/thumbstick/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Thumbstick Click"},
{"/user/hand/right/input/thumbstick", XR_ACTION_TYPE_VECTOR2F_INPUT, "Thumbstick"},
{"/user/hand/right/input/trackpad/x", XR_ACTION_TYPE_FLOAT_INPUT, "Trackpad X"},
{"/user/hand/right/input/trackpad/y", XR_ACTION_TYPE_FLOAT_INPUT, "Trackpad Y"},
{"/user/hand/right/input/trackpad", XR_ACTION_TYPE_VECTOR2F_INPUT, "Trackpad"},
{"/user/hand/right/input/trackpad/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Trackpad Click"},
{"/user/hand/right/input/trackpad/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "Trackpad Touch"},
{"/user/hand/right/input/grip/pose", XR_ACTION_TYPE_POSE_INPUT, "Grip"},
{"/user/hand/right/input/aim/pose", XR_ACTION_TYPE_POSE_INPUT, "Aim"},
{"/user/hand/right/output/haptic", XR_ACTION_TYPE_VIBRATION_OUTPUT, "Haptic"}}},
// Google Daydream Controller Profile
{
"Daydream Controller",
"/interaction_profiles/google/daydream_controller",
0,
{"/user/hand/left",
"/user/hand/right"},
{{"/user/hand/left/input/select/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Select"},
{"/user/hand/left/input/trackpad/x", XR_ACTION_TYPE_FLOAT_INPUT, "Trackpad X"},
{"/user/hand/left/input/trackpad/y", XR_ACTION_TYPE_FLOAT_INPUT, "Trackpad Y"},
{"/user/hand/left/input/trackpad/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Trackpad Click"},
{"/user/hand/left/input/trackpad/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "Trackpad Touch"},
{"/user/hand/left/input/trackpad", XR_ACTION_TYPE_VECTOR2F_INPUT, "Trackpad"},
{"/user/hand/left/input/grip/pose", XR_ACTION_TYPE_POSE_INPUT, "Grip"},
{"/user/hand/left/input/aim/pose", XR_ACTION_TYPE_POSE_INPUT, "Pose"},
{"/user/hand/right/input/select/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Select"},
{"/user/hand/right/input/trackpad/x", XR_ACTION_TYPE_FLOAT_INPUT, "Trackpad X"},
{"/user/hand/right/input/trackpad/y", XR_ACTION_TYPE_FLOAT_INPUT, "Trackpad Y"},
{"/user/hand/right/input/trackpad/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Trackpad Click"},
{"/user/hand/right/input/trackpad/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "Trackpad Touch"},
{"/user/hand/right/input/trackpad", XR_ACTION_TYPE_VECTOR2F_INPUT, "Trackpad"},
{"/user/hand/right/input/grip/pose", XR_ACTION_TYPE_POSE_INPUT, "Grip"},
{"/user/hand/right/input/aim/pose", XR_ACTION_TYPE_POSE_INPUT, "Aim"}}},
// HTC Vive Controller Profile
{
"HTC Vive Controller",
"/interaction_profiles/htc/vive_controller",
0,
{"/user/hand/left",
"/user/hand/right"},
{{"/user/hand/left/input/menu/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Menu"},
{"/user/hand/left/input/system/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "System"},
{"/user/hand/left/input/squeeze/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Squeeze"},
{"/user/hand/left/input/trigger/value", XR_ACTION_TYPE_FLOAT_INPUT, "Trigger"},
{"/user/hand/left/input/trigger/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Trigger Click"},
{"/user/hand/left/input/trackpad/x", XR_ACTION_TYPE_FLOAT_INPUT, "Trackpad X"},
{"/user/hand/left/input/trackpad/y", XR_ACTION_TYPE_FLOAT_INPUT, "Trackpad Y"},
{"/user/hand/left/input/trackpad/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Trackpad Click"},
{"/user/hand/left/input/trackpad/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "Trackpad Touch"},
{"/user/hand/left/input/trackpad", XR_ACTION_TYPE_VECTOR2F_INPUT, "Trackpad"},
{"/user/hand/left/input/grip/pose", XR_ACTION_TYPE_POSE_INPUT, "Grip"},
{"/user/hand/left/input/aim/pose", XR_ACTION_TYPE_POSE_INPUT, "Aim"},
{"/user/hand/left/output/haptic", XR_ACTION_TYPE_VIBRATION_OUTPUT, "Haptic"},
{"/user/hand/right/input/system/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "System"},
{"/user/hand/right/input/menu/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Menu"},
{"/user/hand/right/input/squeeze/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Squeeze"},
{"/user/hand/right/input/trigger/value", XR_ACTION_TYPE_FLOAT_INPUT, "Trigger"},
{"/user/hand/right/input/trigger/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Trigger Click"},
{"/user/hand/right/input/trackpad/x", XR_ACTION_TYPE_FLOAT_INPUT, "Trackpad X"},
{"/user/hand/right/input/trackpad/y", XR_ACTION_TYPE_FLOAT_INPUT, "Trackpad Y"},
{"/user/hand/right/input/trackpad/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Trackpad Click"},
{"/user/hand/right/input/trackpad/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "Trackpad Touch"},
{"/user/hand/right/input/trackpad", XR_ACTION_TYPE_VECTOR2F_INPUT, "Trackpad"},
{"/user/hand/right/input/grip/pose", XR_ACTION_TYPE_POSE_INPUT, "Grip"},
{"/user/hand/right/input/aim/pose", XR_ACTION_TYPE_POSE_INPUT, "Aim"},
{"/user/hand/right/output/haptic", XR_ACTION_TYPE_VIBRATION_OUTPUT, "Haptic"}}},
// HTC Vive Pro Profile
{
"HTC Vive Pro Controller",
"/interaction_profiles/htc/vive_pro",
0,
{"/user/head"},
{
{"/user/head/input/volume_up/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Volume Up"},
{"/user/head/input/volume_down/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Volume Down"},
{"/user/head/input/mute_mic/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Mute Mic"},
}},
// Microsoft Xbox Controller Profile
{
"XBox Controller",
"/interaction_profiles/microsoft/xbox_controller",
0,
{"/user/gamepad"},
{{"/user/gamepad/input/menu/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Menu"},
{"/user/gamepad/input/view/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "View"},
{"/user/gamepad/input/a/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "A"},
{"/user/gamepad/input/b/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "B"},
{"/user/gamepad/input/x/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "X"},
{"/user/gamepad/input/y/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Y"},
{"/user/gamepad/input/dpad_down/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "D-pad Down"},
{"/user/gamepad/input/dpad_right/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "D-pad Right"},
{"/user/gamepad/input/dpad_up/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "D-pad Up"},
{"/user/gamepad/input/dpad_left/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "D-pad Left"},
{"/user/gamepad/input/shoulder_left/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Left Shoulder"},
{"/user/gamepad/input/shoulder_right/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Right Shoulder"},
{"/user/gamepad/input/thumbstick_left/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Left Thumbstick Click"},
{"/user/gamepad/input/thumbstick_right/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Right Thumbstick Click"},
{"/user/gamepad/input/trigger_left/value", XR_ACTION_TYPE_FLOAT_INPUT, "Left Trigger"},
{"/user/gamepad/input/trigger_right/value", XR_ACTION_TYPE_FLOAT_INPUT, "Right Trigger"},
{"/user/gamepad/input/thumbstick_left/x", XR_ACTION_TYPE_FLOAT_INPUT, "Left Thumbstick X"},
{"/user/gamepad/input/thumbstick_left/y", XR_ACTION_TYPE_FLOAT_INPUT, "Left Thumbstick Y"},
{"/user/gamepad/input/thumbstick_left", XR_ACTION_TYPE_VECTOR2F_INPUT, "Left Thumbstick"},
{"/user/gamepad/input/thumbstick_right/x", XR_ACTION_TYPE_FLOAT_INPUT, "Right Thumbstick X"},
{"/user/gamepad/input/thumbstick_right/y", XR_ACTION_TYPE_FLOAT_INPUT, "Right Thumbstick Y"},
{"/user/gamepad/input/thumbstick_right", XR_ACTION_TYPE_VECTOR2F_INPUT, "Right Thumbstick"},
{"/user/gamepad/output/haptic_left", XR_ACTION_TYPE_VIBRATION_OUTPUT, "Left Hatic"},
{"/user/gamepad/output/haptic_right", XR_ACTION_TYPE_VIBRATION_OUTPUT, "Right Haptic"},
{"/user/gamepad/output/haptic_left_trigger", XR_ACTION_TYPE_VIBRATION_OUTPUT, "Left Trigger Haptic"},
{"/user/gamepad/output/haptic_right_trigger", XR_ACTION_TYPE_VIBRATION_OUTPUT, "Right Trigger Haptic"}}},
// Oculus Go Controller Profile
{
"Oculus Go Controller",
"/interaction_profiles/oculus/go_controller",
0,
{"/user/hand/left",
"/user/hand/right"},
{
{"/user/hand/left/input/trigger/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Trigger"},
{"/user/hand/left/input/back/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Back"},
{"/user/hand/left/input/trackpad/x", XR_ACTION_TYPE_FLOAT_INPUT, "Trackpad X"},
{"/user/hand/left/input/trackpad/y", XR_ACTION_TYPE_FLOAT_INPUT, "Trackpad Y"},
{"/user/hand/left/input/trackpad", XR_ACTION_TYPE_VECTOR2F_INPUT, "Trackpad"},
{"/user/hand/left/input/trackpad/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Trackpad Click"},
{"/user/hand/left/input/trackpad/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "Trackpad Touch"},
{"/user/hand/left/input/grip/pose", XR_ACTION_TYPE_POSE_INPUT, "Grip"},
{"/user/hand/left/input/aim/pose", XR_ACTION_TYPE_POSE_INPUT, "Aim"},
{"/user/hand/right/input/trigger/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Trigger"},
{"/user/hand/right/input/back/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Back"},
{"/user/hand/right/input/trackpad/x", XR_ACTION_TYPE_FLOAT_INPUT, "Trackpad X"},
{"/user/hand/right/input/trackpad/y", XR_ACTION_TYPE_FLOAT_INPUT, "Trackpad Y"},
{"/user/hand/right/input/trackpad", XR_ACTION_TYPE_VECTOR2F_INPUT, "Trackpad"},
{"/user/hand/right/input/trackpad/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Trackpad Click"},
{"/user/hand/right/input/trackpad/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "Trackpad Touch"},
{"/user/hand/right/input/grip/pose", XR_ACTION_TYPE_POSE_INPUT, "Grip"},
{"/user/hand/right/input/aim/pose", XR_ACTION_TYPE_POSE_INPUT, "Pose"},
}},
// Oculus Touch Controller Profile
{
"Oculus Touch Controller",
"/interaction_profiles/oculus/touch_controller",
0,
{"/user/hand/left",
"/user/hand/right"},
{
{"/user/hand/left/input/x/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "X"},
{"/user/hand/left/input/x/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "X Touch"},
{"/user/hand/left/input/y/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Y"},
{"/user/hand/left/input/y/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "Y Touch"},
{"/user/hand/left/input/menu/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Menu"},
{"/user/hand/left/input/squeeze/value", XR_ACTION_TYPE_FLOAT_INPUT, "Grip"},
{"/user/hand/left/input/trigger/value", XR_ACTION_TYPE_FLOAT_INPUT, "Trigger"},
{"/user/hand/left/input/trigger/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "Touch"},
{"/user/hand/left/input/thumbstick/x", XR_ACTION_TYPE_FLOAT_INPUT, "Thumbstick X"},
{"/user/hand/left/input/thumbstick/y", XR_ACTION_TYPE_FLOAT_INPUT, "Thumbstick Y"},
{"/user/hand/left/input/thumbstick/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Thumbstick Click"},
{"/user/hand/left/input/thumbstick/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "Thumbstick Touch"},
{"/user/hand/left/input/thumbstick", XR_ACTION_TYPE_VECTOR2F_INPUT, "Thumbstick"},
// Rift S and Quest controllers lack thumbrests
{"/user/hand/left/input/thumbrest/touch", XR_ACTION_TYPE_BOOLEAN_INPUT},
{"/user/hand/left/input/grip/pose", XR_ACTION_TYPE_POSE_INPUT, "Grip"},
{"/user/hand/left/input/aim/pose", XR_ACTION_TYPE_POSE_INPUT, "Aim"},
{"/user/hand/left/output/haptic", XR_ACTION_TYPE_VIBRATION_OUTPUT, "Haptic"},
{"/user/hand/right/input/a/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "A"},
{"/user/hand/right/input/a/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "A Touch"},
{"/user/hand/right/input/b/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "B"},
{"/user/hand/right/input/b/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "B Touch"},
// The system ("Oculus") button is reserved for system applications
{"/user/hand/right/input/system/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "System"},
{"/user/hand/right/input/squeeze/value", XR_ACTION_TYPE_FLOAT_INPUT, "Grip"},
{"/user/hand/right/input/trigger/value", XR_ACTION_TYPE_FLOAT_INPUT, "Trigger"},
{"/user/hand/right/input/trigger/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "Trigger Touch"},
{"/user/hand/right/input/thumbstick/x", XR_ACTION_TYPE_FLOAT_INPUT, "Thumbstick X"},
{"/user/hand/right/input/thumbstick/y", XR_ACTION_TYPE_FLOAT_INPUT, "Thumbstick Y"},
{"/user/hand/right/input/thumbstick/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Thumbstick Click"},
{"/user/hand/right/input/thumbstick/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "Thumbstick Touch"},
{"/user/hand/right/input/thumbstick", XR_ACTION_TYPE_VECTOR2F_INPUT, "Thumbstick"},
// Rift S and Quest controllers lack thumbrests
{"/user/hand/right/input/thumbrest/touch", XR_ACTION_TYPE_BOOLEAN_INPUT},
{"/user/hand/right/input/grip/pose", XR_ACTION_TYPE_POSE_INPUT, "Grip"},
{"/user/hand/right/input/aim/pose", XR_ACTION_TYPE_POSE_INPUT, "Aim"},
{"/user/hand/right/output/haptic", XR_ACTION_TYPE_VIBRATION_OUTPUT, "Haptic"},
}},
// Valve Index Controller Profile
{
"Index Controller",
"/interaction_profiles/valve/index_controller",
0,
{"/user/hand/left",
"/user/hand/right"},
{
{"/user/hand/left/input/system/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "System"},
{"/user/hand/left/input/system/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "System Touch"},
{"/user/hand/left/input/a/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "A"},
{"/user/hand/left/input/a/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "A Touch"},
{"/user/hand/left/input/b/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "B"},
{"/user/hand/left/input/b/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "B Touch"},
{"/user/hand/left/input/squeeze/value", XR_ACTION_TYPE_FLOAT_INPUT, "Squeeze"},
{"/user/hand/left/input/squeeze/force", XR_ACTION_TYPE_FLOAT_INPUT, "Squeeze Force"},
{"/user/hand/left/input/trigger/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Trigger Click"},
{"/user/hand/left/input/trigger/value", XR_ACTION_TYPE_FLOAT_INPUT, "Trigger"},
{"/user/hand/left/input/trigger/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "Trigger Touch"},
{"/user/hand/left/input/thumbstick/x", XR_ACTION_TYPE_FLOAT_INPUT, "Thumbstick X"},
{"/user/hand/left/input/thumbstick/y", XR_ACTION_TYPE_FLOAT_INPUT, "Thumbstick Y"},
{"/user/hand/left/input/thumbstick/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Thumbstick Click"},
{"/user/hand/left/input/thumbstick/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "Thumbstick Touch"},
{"/user/hand/left/input/thumbstick", XR_ACTION_TYPE_VECTOR2F_INPUT, "Thumbstick"},
{"/user/hand/left/input/trackpad/x", XR_ACTION_TYPE_FLOAT_INPUT, "Trackpad X"},
{"/user/hand/left/input/trackpad/y", XR_ACTION_TYPE_FLOAT_INPUT, "Trackpad Y"},
{"/user/hand/left/input/trackpad/force", XR_ACTION_TYPE_FLOAT_INPUT, "Trackpad Force"},
{"/user/hand/left/input/trackpad/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "Trackpad Touch"},
{"/user/hand/left/input/trackpad", XR_ACTION_TYPE_VECTOR2F_INPUT, "Trackpad"},
{"/user/hand/left/input/grip/pose", XR_ACTION_TYPE_POSE_INPUT, "Grip"},
{"/user/hand/left/input/aim/pose", XR_ACTION_TYPE_POSE_INPUT, "Aim"},
{"/user/hand/left/output/haptic", XR_ACTION_TYPE_VIBRATION_OUTPUT, "Haptic"},
{"/user/hand/right/input/system/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "System"},
{"/user/hand/right/input/system/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "System Touch"},
{"/user/hand/right/input/a/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "A"},
{"/user/hand/right/input/a/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "A Touch"},
{"/user/hand/right/input/b/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "B"},
{"/user/hand/right/input/b/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "B Touch"},
{"/user/hand/right/input/squeeze/value", XR_ACTION_TYPE_FLOAT_INPUT, "Squeeze"},
{"/user/hand/right/input/squeeze/force", XR_ACTION_TYPE_FLOAT_INPUT, "Squeeze Force"},
{"/user/hand/right/input/trigger/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Trigger Click"},
{"/user/hand/right/input/trigger/value", XR_ACTION_TYPE_FLOAT_INPUT, "Trigger"},
{"/user/hand/right/input/trigger/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "Trigger Touch"},
{"/user/hand/right/input/thumbstick/x", XR_ACTION_TYPE_FLOAT_INPUT, "Thumbstick X"},
{"/user/hand/right/input/thumbstick/y", XR_ACTION_TYPE_FLOAT_INPUT, "Thumbstick Y"},
{"/user/hand/right/input/thumbstick/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Thumbstick Click"},
{"/user/hand/right/input/thumbstick/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "Thumbstick Touch"},
{"/user/hand/right/input/thumbstick", XR_ACTION_TYPE_VECTOR2F_INPUT, "Thumbstick"},
{"/user/hand/right/input/trackpad/x", XR_ACTION_TYPE_FLOAT_INPUT, "Trackpad X"},
{"/user/hand/right/input/trackpad/y", XR_ACTION_TYPE_FLOAT_INPUT, "Trackpad Y"},
{"/user/hand/right/input/trackpad/force", XR_ACTION_TYPE_FLOAT_INPUT, "Trackpad Force"},
{"/user/hand/right/input/trackpad/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "Trackpad Touch"},
{"/user/hand/right/input/trackpad", XR_ACTION_TYPE_VECTOR2F_INPUT, "Trackpad"},
{"/user/hand/right/input/grip/pose", XR_ACTION_TYPE_POSE_INPUT, "Grip"},
{"/user/hand/right/input/aim/pose", XR_ACTION_TYPE_POSE_INPUT, "Aim"},
{"/user/hand/right/output/haptic", XR_ACTION_TYPE_VIBRATION_OUTPUT, "Haptic"},
}},
// Eye gaze interaction extension
{
"Eye Gaze",
"/interaction_profiles/ext/eye_gaze_interaction",
MR_CREATE_EYE_GAZE_INTERACTION_EXT,
{"/user/eyes_ext"},
{{"/user/eyes_ext/input/gaze_ext/pose", XR_ACTION_TYPE_POSE_INPUT, "Gaze"}}},
// MSFT Hand Interaction extension
{
"Hand",
"/interaction_profiles/microsoft/hand_interaction",
MR_CREATE_MSFT_HAND_INTERACTION_EXT,
{"/user/hand/left", "/user/hand/right"},
{{"/user/hand/left/input/select/value", XR_ACTION_TYPE_FLOAT_INPUT, "Select"},
{"/user/hand/left/input/squeeze/value", XR_ACTION_TYPE_FLOAT_INPUT, "Squeeze"},
{"/user/hand/left/input/aim/pose", XR_ACTION_TYPE_POSE_INPUT, "Aim"},
{"/user/hand/left/input/grip/pose", XR_ACTION_TYPE_POSE_INPUT, "Grip"},
{"/user/hand/right/input/select/value", XR_ACTION_TYPE_FLOAT_INPUT, "Select"},
{"/user/hand/right/input/squeeze/value", XR_ACTION_TYPE_FLOAT_INPUT, "Squeeze"},
{"/user/hand/right/input/aim/pose", XR_ACTION_TYPE_POSE_INPUT, "Aim"},
{"/user/hand/right/input/grip/pose", XR_ACTION_TYPE_POSE_INPUT, "Grip"}}},
// Hand Interaction extension
{
"Hand Interaction",
"/interaction_profiles/ext/hand_interaction_ext",
MR_CREATE_HAND_INTERACTION_EXT,
{"/user/hand/left", "/user/hand/right"},
{
{"/user/hand/left/input/aim/pose", XR_ACTION_TYPE_POSE_INPUT, "Aim"},
{"/user/hand/left/input/grip/pose", XR_ACTION_TYPE_POSE_INPUT, "Grip"},
{"/user/hand/left/input/poke_ext/pose", XR_ACTION_TYPE_POSE_INPUT, "Poke"},
{"/user/hand/left/input/pinch_ext/pose", XR_ACTION_TYPE_POSE_INPUT, "Pinch"},
{"/user/hand/left/input/pinch_ext/value", XR_ACTION_TYPE_FLOAT_INPUT, "Pinch Value"},
{"/user/hand/left/input/pinch_ext/ready_ext", XR_ACTION_TYPE_BOOLEAN_INPUT, "Pinch Ready"},
{"/user/hand/left/input/aim_activate_ext/value", XR_ACTION_TYPE_FLOAT_INPUT, "Pointer Activate Value"},
{"/user/hand/left/input/aim_activate_ext/ready_ext", XR_ACTION_TYPE_BOOLEAN_INPUT, "Pointer Activate Ready"},
{"/user/hand/left/input/grasp_ext/value", XR_ACTION_TYPE_FLOAT_INPUT, "Grasp Value"},
{"/user/hand/left/input/grasp_ext/ready_ext", XR_ACTION_TYPE_BOOLEAN_INPUT, "Grasp Ready"},
{"/user/hand/right/input/aim/pose", XR_ACTION_TYPE_POSE_INPUT, "Aim"},
{"/user/hand/right/input/grip/pose", XR_ACTION_TYPE_POSE_INPUT, "Grip"},
{"/user/hand/right/input/poke_ext/pose", XR_ACTION_TYPE_POSE_INPUT, "Poke"},
{"/user/hand/right/input/pinch_ext/pose", XR_ACTION_TYPE_POSE_INPUT, "Pinch"},
{"/user/hand/right/input/pinch_ext/value", XR_ACTION_TYPE_FLOAT_INPUT, "Pinch Value"},
{"/user/hand/right/input/pinch_ext/ready_ext", XR_ACTION_TYPE_BOOLEAN_INPUT, "Pinch Ready"},
{"/user/hand/right/input/aim_activate_ext/value", XR_ACTION_TYPE_FLOAT_INPUT, "Pointer Activate Value"},
{"/user/hand/right/input/aim_activate_ext/ready_ext", XR_ACTION_TYPE_BOOLEAN_INPUT, "Pointer Activate Ready"},
{"/user/hand/right/input/grasp_ext/value", XR_ACTION_TYPE_FLOAT_INPUT, "Grasp Value"},
{"/user/hand/right/input/grasp_ext/ready_ext", XR_ACTION_TYPE_BOOLEAN_INPUT, "Grasp Ready"},
}},
// Meta Quest Pro Touch Controller Profile
{
"Quest Pro Touch Controller",
"/interaction_profiles/facebook/touch_controller_pro",
MR_CREATE_FB_TOUCH_CONTROLLER_PRO,
{"/user/hand/left",
"/user/hand/right"},
{
{"/user/hand/left/input/x/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "X"},
{"/user/hand/left/input/x/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "X Touch"},
{"/user/hand/left/input/y/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Y"},
{"/user/hand/left/input/y/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "Y Touch"},
{"/user/hand/left/input/menu/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Menu"},
{"/user/hand/left/input/squeeze/value", XR_ACTION_TYPE_FLOAT_INPUT, "Grip"},
{"/user/hand/left/input/trigger/value", XR_ACTION_TYPE_FLOAT_INPUT, "Trigger"},
{"/user/hand/left/input/trigger/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "Touch"},
{"/user/hand/left/input/thumbstick/x", XR_ACTION_TYPE_FLOAT_INPUT, "Thumbstick X"},
{"/user/hand/left/input/thumbstick/y", XR_ACTION_TYPE_FLOAT_INPUT, "Thumbstick Y"},
{"/user/hand/left/input/thumbstick/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Thumbstick Click"},
{"/user/hand/left/input/thumbstick/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "Thumbstick Touch"},
{"/user/hand/left/input/thumbstick", XR_ACTION_TYPE_VECTOR2F_INPUT, "Thumbstick"},
{"/user/hand/left/input/thumbrest/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "Thumbrest Touch"},
{"/user/hand/left/input/grip/pose", XR_ACTION_TYPE_POSE_INPUT, "Grip"},
{"/user/hand/left/input/aim/pose", XR_ACTION_TYPE_POSE_INPUT, "Aim"},
{"/user/hand/left/output/haptic", XR_ACTION_TYPE_VIBRATION_OUTPUT, "Haptic"},
{"/user/hand/left/input/thumbrest/force", XR_ACTION_TYPE_FLOAT_INPUT, "Thumbrest Force"},
{"/user/hand/left/input/stylus_fb/force", XR_ACTION_TYPE_FLOAT_INPUT, "Stylus Force"},
{"/user/hand/left/input/trigger/curl_fb", XR_ACTION_TYPE_FLOAT_INPUT, "Trigger Curl"},
{"/user/hand/left/input/trigger/slide_fb", XR_ACTION_TYPE_FLOAT_INPUT, "Trigger Slide"},
{"/user/hand/left/input/trigger/proximity_fb", XR_ACTION_TYPE_BOOLEAN_INPUT, "Trigger Proximity"},
{"/user/hand/left/input/thumb_fb/proximity_fb", XR_ACTION_TYPE_BOOLEAN_INPUT, "Thumb Proximity"},
{"/user/hand/left/output/trigger_haptic_fb", XR_ACTION_TYPE_VIBRATION_OUTPUT, "Haptic Trigger"},
{"/user/hand/left/output/thumb_haptic_fb", XR_ACTION_TYPE_VIBRATION_OUTPUT, "Haptic Thumb"},
{"/user/hand/right/input/a/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "A"},
{"/user/hand/right/input/a/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "A Touch"},
{"/user/hand/right/input/b/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "B"},
{"/user/hand/right/input/b/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "B Touch"},
// The system ("Oculus") button is reserved for system applications
{"/user/hand/right/input/system/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "System"},
{"/user/hand/right/input/squeeze/value", XR_ACTION_TYPE_FLOAT_INPUT, "Grip"},
{"/user/hand/right/input/trigger/value", XR_ACTION_TYPE_FLOAT_INPUT, "Trigger"},
{"/user/hand/right/input/trigger/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "Trigger Touch"},
{"/user/hand/right/input/thumbstick/x", XR_ACTION_TYPE_FLOAT_INPUT, "Thumbstick X"},
{"/user/hand/right/input/thumbstick/y", XR_ACTION_TYPE_FLOAT_INPUT, "Thumbstick Y"},
{"/user/hand/right/input/thumbstick/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Thumbstick Click"},
{"/user/hand/right/input/thumbstick/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "Thumbstick Touch"},
{"/user/hand/right/input/thumbstick", XR_ACTION_TYPE_VECTOR2F_INPUT, "Thumbstick"},
{"/user/hand/right/input/thumbrest/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "Thumbrest Touch"},
{"/user/hand/right/input/grip/pose", XR_ACTION_TYPE_POSE_INPUT, "Grip"},
{"/user/hand/right/input/aim/pose", XR_ACTION_TYPE_POSE_INPUT, "Aim"},
{"/user/hand/right/output/haptic", XR_ACTION_TYPE_VIBRATION_OUTPUT, "Haptic"},
{"/user/hand/right/input/thumbrest/force", XR_ACTION_TYPE_FLOAT_INPUT, "Thumbrest Force"},
{"/user/hand/right/input/stylus_fb/force", XR_ACTION_TYPE_FLOAT_INPUT, "Stylus Force"},
{"/user/hand/right/input/trigger/curl_fb", XR_ACTION_TYPE_FLOAT_INPUT, "Trigger Curl"},
{"/user/hand/right/input/trigger/slide_fb", XR_ACTION_TYPE_FLOAT_INPUT, "Trigger Slide"},
{"/user/hand/right/input/trigger/proximity_fb", XR_ACTION_TYPE_BOOLEAN_INPUT, "Trigger Proximity"},
{"/user/hand/right/input/thumb_fb/proximity_fb", XR_ACTION_TYPE_BOOLEAN_INPUT, "Thumb Proximity"},
{"/user/hand/right/output/trigger_haptic_fb", XR_ACTION_TYPE_VIBRATION_OUTPUT, "Haptic Trigger"},
{"/user/hand/right/output/thumb_haptic_fb", XR_ACTION_TYPE_VIBRATION_OUTPUT, "Haptic Thumb"},
}},
// HP Reverb G2 Controller Profile
{
"HP Reverb G2 Controller",
"/interaction_profiles/hp/mixed_reality_controller",
0,
{"/user/hand/left",
"/user/hand/right"},
{
{"/user/hand/left/input/x/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "X"},
{"/user/hand/left/input/y/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Y"},
{"/user/hand/left/input/menu/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Menu"},
{"/user/hand/left/input/squeeze/value", XR_ACTION_TYPE_FLOAT_INPUT, "Grip"},
{"/user/hand/left/input/trigger/value", XR_ACTION_TYPE_FLOAT_INPUT, "Trigger"},
{"/user/hand/left/input/thumbstick/x", XR_ACTION_TYPE_FLOAT_INPUT, "Thumbstick X"},
{"/user/hand/left/input/thumbstick/y", XR_ACTION_TYPE_FLOAT_INPUT, "Thumbstick Y"},
{"/user/hand/left/input/thumbstick/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Thumbstick Click"},
{"/user/hand/left/input/thumbstick", XR_ACTION_TYPE_VECTOR2F_INPUT, "Thumbstick"},
{"/user/hand/left/input/grip/pose", XR_ACTION_TYPE_POSE_INPUT, "Grip"},
{"/user/hand/left/input/aim/pose", XR_ACTION_TYPE_POSE_INPUT, "Aim"},
{"/user/hand/left/output/haptic", XR_ACTION_TYPE_VIBRATION_OUTPUT, "Haptic"},
{"/user/hand/right/input/a/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "A"},
{"/user/hand/right/input/b/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "B"},
{"/user/hand/right/input/menu/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Menu"},
{"/user/hand/right/input/squeeze/value", XR_ACTION_TYPE_FLOAT_INPUT, "Grip"},
{"/user/hand/right/input/trigger/value", XR_ACTION_TYPE_FLOAT_INPUT, "Trigger"},
{"/user/hand/right/input/thumbstick/x", XR_ACTION_TYPE_FLOAT_INPUT, "Thumbstick X"},
{"/user/hand/right/input/thumbstick/y", XR_ACTION_TYPE_FLOAT_INPUT, "Thumbstick Y"},
{"/user/hand/right/input/thumbstick/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Thumbstick Click"},
{"/user/hand/right/input/thumbstick", XR_ACTION_TYPE_VECTOR2F_INPUT, "Thumbstick"},
{"/user/hand/right/input/grip/pose", XR_ACTION_TYPE_POSE_INPUT, "Grip"},
{"/user/hand/right/input/aim/pose", XR_ACTION_TYPE_POSE_INPUT, "Aim"},
{"/user/hand/right/output/haptic", XR_ACTION_TYPE_VIBRATION_OUTPUT, "Haptic"},
}},
// Touch Controller Plus Profile
{
"Meta Quest Touch Plus Controller",
"/interaction_profiles/meta/touch_controller_plus",
MR_CREATE_META_TOUCH_CONTROLLER_PLUS,
{"/user/hand/left",
"/user/hand/right"},
{
{"/user/hand/left/input/x/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "X"},
{"/user/hand/left/input/x/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "X Touch"},
{"/user/hand/left/input/y/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Y"},
{"/user/hand/left/input/y/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "Y Touch"},
{"/user/hand/left/input/menu/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Menu"},
{"/user/hand/left/input/squeeze/value", XR_ACTION_TYPE_FLOAT_INPUT, "Grip"},
{"/user/hand/left/input/trigger/value", XR_ACTION_TYPE_FLOAT_INPUT, "Trigger"},
{"/user/hand/left/input/trigger/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "Touch"},
{"/user/hand/left/input/thumbstick/x", XR_ACTION_TYPE_FLOAT_INPUT, "Thumbstick X"},
{"/user/hand/left/input/thumbstick/y", XR_ACTION_TYPE_FLOAT_INPUT, "Thumbstick Y"},
{"/user/hand/left/input/thumbstick/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Thumbstick Click"},
{"/user/hand/left/input/thumbstick/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "Thumbstick Touch"},
{"/user/hand/left/input/thumbstick", XR_ACTION_TYPE_VECTOR2F_INPUT, "Thumbstick"},
{"/user/hand/left/input/thumbrest/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "Thumbrest Touch"},
{"/user/hand/left/input/grip/pose", XR_ACTION_TYPE_POSE_INPUT, "Grip"},
{"/user/hand/left/input/aim/pose", XR_ACTION_TYPE_POSE_INPUT, "Aim"},
{"/user/hand/left/output/haptic", XR_ACTION_TYPE_VIBRATION_OUTPUT, "Haptic"},
{"/user/hand/left/input/thumb_meta/proximity_meta", XR_ACTION_TYPE_BOOLEAN_INPUT, "Thumb Proximity"},
{"/user/hand/left/input/trigger/proximity_meta", XR_ACTION_TYPE_BOOLEAN_INPUT, "Trigger Proximity"},
{"/user/hand/left/input/trigger/curl_meta", XR_ACTION_TYPE_FLOAT_INPUT, "Trigger Curl"},
{"/user/hand/left/input/trigger/slide_meta", XR_ACTION_TYPE_FLOAT_INPUT, "Trigger Slide"},
{"/user/hand/left/input/trigger/force", XR_ACTION_TYPE_FLOAT_INPUT, "Trigger Force"},
{"/user/hand/right/input/a/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "A"},
{"/user/hand/right/input/a/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "A Touch"},
{"/user/hand/right/input/b/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "B"},
{"/user/hand/right/input/b/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "B Touch"},
// The system ("Oculus") button is reserved for system applications
{"/user/hand/right/input/system/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "System"},
{"/user/hand/right/input/squeeze/value", XR_ACTION_TYPE_FLOAT_INPUT, "Grip"},
{"/user/hand/right/input/trigger/value", XR_ACTION_TYPE_FLOAT_INPUT, "Trigger"},
{"/user/hand/right/input/trigger/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "Trigger Touch"},
{"/user/hand/right/input/thumbstick/x", XR_ACTION_TYPE_FLOAT_INPUT, "Thumbstick X"},
{"/user/hand/right/input/thumbstick/y", XR_ACTION_TYPE_FLOAT_INPUT, "Thumbstick Y"},
{"/user/hand/right/input/thumbstick/click", XR_ACTION_TYPE_BOOLEAN_INPUT, "Thumbstick Click"},
{"/user/hand/right/input/thumbstick/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "Thumbstick Touch"},
{"/user/hand/right/input/thumbstick", XR_ACTION_TYPE_VECTOR2F_INPUT, "Thumbstick"},
{"/user/hand/right/input/thumbrest/touch", XR_ACTION_TYPE_BOOLEAN_INPUT, "Thumbrest Touch"},
{"/user/hand/right/input/grip/pose", XR_ACTION_TYPE_POSE_INPUT, "Grip"},
{"/user/hand/right/input/aim/pose", XR_ACTION_TYPE_POSE_INPUT, "Aim"},
{"/user/hand/right/output/haptic", XR_ACTION_TYPE_VIBRATION_OUTPUT, "Haptic"},
{"/user/hand/right/input/thumb_meta/proximity_meta", XR_ACTION_TYPE_BOOLEAN_INPUT, "Thumb Proximity"},
{"/user/hand/right/input/trigger/proximity_meta", XR_ACTION_TYPE_BOOLEAN_INPUT, "Trigger Proximity"},
{"/user/hand/right/input/trigger/curl_meta", XR_ACTION_TYPE_FLOAT_INPUT, "Trigger Curl"},
{"/user/hand/right/input/trigger/slide_meta", XR_ACTION_TYPE_FLOAT_INPUT, "Trigger Slide"},
{"/user/hand/right/input/trigger/force", XR_ACTION_TYPE_FLOAT_INPUT, "Trigger Force"},
}}};
void MockRuntime::InitializeInteractionProfiles()
{
inputStates.clear();
interactionProfiles.reserve(s_InteractionProfiles.size());
for (MockInteractionProfileDef& def : s_InteractionProfiles)
{
// Require specific create flags to use this profile?
if ((def.requiredFlags & createFlags) != def.requiredFlags)
continue;
interactionProfiles.emplace_back();
MockInteractionProfile& mockProfile = interactionProfiles.back();
mockProfile.path = StringToPath(def.name);
mockProfile.userPaths.reserve(def.userPaths.size());
mockProfile.localizedName = def.localizedName;
for (const char* userPathString : def.userPaths)
{
mockProfile.userPaths.push_back(StringToPath(userPathString));
}
for (MockInputSourcePath& componentDef : def.inputSources)
{
AddMockInputState(mockProfile.path, StringToPath(componentDef.path), componentDef.type, componentDef.localizedName);
}
}
}
const MockRuntime::MockInteractionProfile* MockRuntime::GetMockInteractionProfile(XrPath interactionProfile) const
{
for (const MockInteractionProfile& mockProfile : interactionProfiles)
if (mockProfile.path == interactionProfile)
return &mockProfile;
return nullptr;
}

View File

@@ -0,0 +1,91 @@
#include "openxr/openxr.h"
// This data was dumped from oculus quest 2.
uint32_t s_VisibilityMaskVerticesSizes[2][3] =
{
// first view
{
// XR_VISIBILITY_MASK_TYPE_HIDDEN_TRIANGLE_MESH_KHR
52,
// XR_VISIBILITY_MASK_TYPE_VISIBLE_TRIANGLE_MESH_KHR
49,
// XR_VISIBILITY_MASK_TYPE_LINE_LOOP_KHR
48,
},
// second view
{
// XR_VISIBILITY_MASK_TYPE_HIDDEN_TRIANGLE_MESH_KHR
52,
// XR_VISIBILITY_MASK_TYPE_VISIBLE_TRIANGLE_MESH_KHR
49,
// XR_VISIBILITY_MASK_TYPE_LINE_LOOP_KHR
48,
}};
uint32_t s_VisibilityMaskIndicesSizes[2][3] =
{
// first view
{
// XR_VISIBILITY_MASK_TYPE_HIDDEN_TRIANGLE_MESH_KHR
156,
// XR_VISIBILITY_MASK_TYPE_VISIBLE_TRIANGLE_MESH_KHR
144,
// XR_VISIBILITY_MASK_TYPE_LINE_LOOP_KHR
48,
},
// second view
{
// XR_VISIBILITY_MASK_TYPE_HIDDEN_TRIANGLE_MESH_KHR
156,
// XR_VISIBILITY_MASK_TYPE_VISIBLE_TRIANGLE_MESH_KHR
144,
// XR_VISIBILITY_MASK_TYPE_LINE_LOOP_KHR
48,
}};
// clang-format off
XrVector2f s_VisibilityMaskVertices[2][3][99] =
{
// first view
{
// XR_VISIBILITY_MASK_TYPE_HIDDEN_TRIANGLE_MESH_KHR
{ { 1.01f, 1.12253f }, { 1.01f, -1.20286f }, { -1.29274f, -1.20286f }, { -1.29274f, 1.12253f }, { 0.0f, 1.11061f }, { 0.156813f, 1.10997f }, { 0.308857f, 1.07153f }, { 0.460177f, 1.02982f }, { 0.607778f, 0.971561f }, { 0.742182f, 0.886089f }, { 0.848528f, 0.767387f }, { 0.922751f, 0.626911f }, { 0.974118f, 0.481266f }, { 1.0f, 0.335506f }, { 1.0f, 0.192824f }, { 1.0f, 0.0543102f }, { 1.0f, -0.081141f }, { 1.0f, -0.216879f }, { 1.0f, -0.356927f }, { 1.0f, -0.502332f }, { 0.986307f, -0.650586f }, { 0.931474f, -0.795886f }, { 0.848528f, -0.929669f }, { 0.731909f, -1.03498f }, { 0.590278f, -1.10353f }, { 0.439847f, -1.14302f }, { 0.29074f, -1.1662f }, { 0.1458f, -1.1886f }, { -1.19209e-07f, -1.19175f }, { -0.156797f, -1.19175f }, { -0.327742f, -1.19175f }, { -0.510643f, -1.19175f }, { -0.699907f, -1.19175f }, { -0.886918f, -1.19175f }, { -1.06066f, -1.1418f }, { -1.19912f, -1.00126f }, { -1.27994f, -0.82503f }, { -1.27994f, -0.63388f }, { -1.27994f, -0.442625f }, { -1.27994f, -0.258665f }, { -1.27994f, -0.081141f }, { -1.27994f, 0.0980905f }, { -1.27994f, 0.285711f }, { -1.27994f, 0.481404f }, { -1.27994f, 0.677933f }, { -1.22896f, 0.861876f }, { -1.09602f, 1.01487f }, { -0.926783f, 1.11061f }, { -0.739629f, 1.11061f }, { -0.545324f, 1.11061f }, { -0.353049f, 1.11061f }, { -0.169805f, 1.11061f } }, // 52
// XR_VISIBILITY_MASK_TYPE_VISIBLE_TRIANGLE_MESH_KHR
{ { 0.0f, -0.081141f }, { 0.0f, 1.11061f }, { 0.156813f, 1.10997f }, { 0.308857f, 1.07153f }, { 0.460177f, 1.02982f }, { 0.607778f, 0.971561f }, { 0.742182f, 0.886089f }, { 0.848528f, 0.767387f }, { 0.922751f, 0.626911f }, { 0.974118f, 0.481266f }, { 1.0f, 0.335506f }, { 1.0f, 0.192824f }, { 1.0f, 0.0543102f }, { 1.0f, -0.081141f }, { 1.0f, -0.216879f }, { 1.0f, -0.356927f }, { 1.0f, -0.502332f }, { 0.986307f, -0.650586f }, { 0.931474f, -0.795886f }, { 0.848528f, -0.929669f }, { 0.731909f, -1.03498f }, { 0.590278f, -1.10353f }, { 0.439847f, -1.14302f }, { 0.29074f, -1.1662f }, { 0.1458f, -1.1886f }, { -1.19209e-07f, -1.19175f }, { -0.156797f, -1.19175f }, { -0.327742f, -1.19175f }, { -0.510643f, -1.19175f }, { -0.699907f, -1.19175f }, { -0.886918f, -1.19175f }, { -1.06066f, -1.1418f }, { -1.19912f, -1.00126f }, { -1.27994f, -0.82503f }, { -1.27994f, -0.63388f }, { -1.27994f, -0.442625f }, { -1.27994f, -0.258665f }, { -1.27994f, -0.081141f }, { -1.27994f, 0.0980905f }, { -1.27994f, 0.285711f }, { -1.27994f, 0.481404f }, { -1.27994f, 0.677933f }, { -1.22896f, 0.861876f }, { -1.09602f, 1.01487f }, { -0.926783f, 1.11061f }, { -0.739629f, 1.11061f }, { -0.545324f, 1.11061f }, { -0.353049f, 1.11061f }, { -0.169805f, 1.11061f } }, // 49
// XR_VISIBILITY_MASK_TYPE_LINE_LOOP_KHR
{ { 0.0f, 1.11061f }, { 0.156813f, 1.10997f }, { 0.308857f, 1.07153f }, { 0.460177f, 1.02982f }, { 0.607778f, 0.971561f }, { 0.742182f, 0.886089f }, { 0.848528f, 0.767387f }, { 0.922751f, 0.626911f }, { 0.974118f, 0.481266f }, { 1.0f, 0.335506f }, { 1.0f, 0.192824f }, { 1.0f, 0.0543102f }, { 1.0f, -0.081141f }, { 1.0f, -0.216879f }, { 1.0f, -0.356927f }, { 1.0f, -0.502332f }, { 0.986307f, -0.650586f }, { 0.931474f, -0.795886f }, { 0.848528f, -0.929669f }, { 0.731909f, -1.03498f }, { 0.590278f, -1.10353f }, { 0.439847f, -1.14302f }, { 0.29074f, -1.1662f }, { 0.1458f, -1.1886f }, { -1.19209e-07f, -1.19175f }, { -0.156797f, -1.19175f }, { -0.327742f, -1.19175f }, { -0.510643f, -1.19175f }, { -0.699907f, -1.19175f }, { -0.886918f, -1.19175f }, { -1.06066f, -1.1418f }, { -1.19912f, -1.00126f }, { -1.27994f, -0.82503f }, { -1.27994f, -0.63388f }, { -1.27994f, -0.442625f }, { -1.27994f, -0.258665f }, { -1.27994f, -0.081141f }, { -1.27994f, 0.0980905f }, { -1.27994f, 0.285711f }, { -1.27994f, 0.481404f }, { -1.27994f, 0.677933f }, { -1.22896f, 0.861876f }, { -1.09602f, 1.01487f }, { -0.926783f, 1.11061f }, { -0.739629f, 1.11061f }, { -0.545324f, 1.11061f }, { -0.353049f, 1.11061f }, { -0.169805f, 1.11061f } }, // 48
},
// second view
{
// XR_VISIBILITY_MASK_TYPE_HIDDEN_TRIANGLE_MESH_KHR
{ { -1.01f, 1.12253f }, { -1.01f, -1.20286f }, { 1.29274f, -1.20286f }, { 1.29274f, 1.12253f }, { 0.0f, 1.11061f }, { -0.156813f, 1.10997f }, { -0.308857f, 1.07153f }, { -0.460177f, 1.02982f }, { -0.607778f, 0.971561f }, { -0.742182f, 0.886089f }, { -0.848528f, 0.767387f }, { -0.922751f, 0.626911f }, { -0.974118f, 0.481266f }, { -1.0f, 0.335506f }, { -1.0f, 0.192824f }, { -1.0f, 0.0543102f }, { -1.0f, -0.081141f }, { -1.0f, -0.216879f }, { -1.0f, -0.356927f }, { -1.0f, -0.502332f }, { -0.986307f, -0.650586f }, { -0.931474f, -0.795886f }, { -0.848528f, -0.929669f }, { -0.731909f, -1.03498f }, { -0.590278f, -1.10353f }, { -0.439847f, -1.14302f }, { -0.29074f, -1.1662f }, { -0.1458f, -1.1886f }, { 0.0f, -1.19175f }, { 0.156797f, -1.19175f }, { 0.327742f, -1.19175f }, { 0.510643f, -1.19175f }, { 0.699907f, -1.19175f }, { 0.886918f, -1.19175f }, { 1.06066f, -1.1418f }, { 1.19912f, -1.00126f }, { 1.27994f, -0.82503f }, { 1.27994f, -0.63388f }, { 1.27994f, -0.442625f }, { 1.27994f, -0.258665f }, { 1.27994f, -0.081141f }, { 1.27994f, 0.0980905f }, { 1.27994f, 0.285711f }, { 1.27994f, 0.481404f }, { 1.27994f, 0.677933f }, { 1.22896f, 0.861876f }, { 1.09602f, 1.01487f }, { 0.926783f, 1.11061f }, { 0.739629f, 1.11061f }, { 0.545324f, 1.11061f }, { 0.353049f, 1.11061f }, { 0.169805f, 1.11061f } }, // 52
// XR_VISIBILITY_MASK_TYPE_VISIBLE_TRIANGLE_MESH_KHR
{ { 0.0f, -0.081141f }, { 0.0f, 1.11061f }, { -0.156813f, 1.10997f }, { -0.308857f, 1.07153f }, { -0.460177f, 1.02982f }, { -0.607778f, 0.971561f }, { -0.742182f, 0.886089f }, { -0.848528f, 0.767387f }, { -0.922751f, 0.626911f }, { -0.974118f, 0.481266f }, { -1.0f, 0.335506f }, { -1.0f, 0.192824f }, { -1.0f, 0.0543102f }, { -1.0f, -0.081141f }, { -1.0f, -0.216879f }, { -1.0f, -0.356927f }, { -1.0f, -0.502332f }, { -0.986307f, -0.650586f }, { -0.931474f, -0.795886f }, { -0.848528f, -0.929669f }, { -0.731909f, -1.03498f }, { -0.590278f, -1.10353f }, { -0.439847f, -1.14302f }, { -0.29074f, -1.1662f }, { -0.1458f, -1.1886f }, { 0.0f, -1.19175f }, { 0.156797f, -1.19175f }, { 0.327742f, -1.19175f }, { 0.510643f, -1.19175f }, { 0.699907f, -1.19175f }, { 0.886918f, -1.19175f }, { 1.06066f, -1.1418f }, { 1.19912f, -1.00126f }, { 1.27994f, -0.82503f }, { 1.27994f, -0.63388f }, { 1.27994f, -0.442625f }, { 1.27994f, -0.258665f }, { 1.27994f, -0.081141f }, { 1.27994f, 0.0980905f }, { 1.27994f, 0.285711f }, { 1.27994f, 0.481404f }, { 1.27994f, 0.677933f }, { 1.22896f, 0.861876f }, { 1.09602f, 1.01487f }, { 0.926783f, 1.11061f }, { 0.739629f, 1.11061f }, { 0.545324f, 1.11061f }, { 0.353049f, 1.11061f }, { 0.169805f, 1.11061f } }, // 49
// XR_VISIBILITY_MASK_TYPE_LINE_LOOP_KHR
{ { 0.00000000f, 1.11061263f }, { -0.156812787f, 1.10997009f }, { -0.308857441f, 1.07153058f }, { -0.460176885f, 1.02982426f }, { -0.607777834f, 0.971561193f }, { -0.742181718f, 0.886089087f }, { -0.848528206f, 0.767387271f }, { -0.922750771f, 0.626910567f }, { -0.974118292f, 0.481266260f }, { -1.00000000f, 0.335505605f }, { -1.00000000f, 0.192823887f }, { -1.00000000f, 0.0543102026f }, { -1.00000000f, -0.0811409950f }, { -1.00000000f, -0.216879249f }, { -1.00000000f, -0.356927097f }, { -1.00000000f, -0.502331913f }, { -0.986306727f, -0.650585532f }, { -0.931473970f, -0.795886219f }, { -0.848528206f, -0.929669261f }, { -0.731908858f, -1.03498316f }, { -0.590277910f, -1.10353208f }, { -0.439846814f, -1.14302492f }, { -0.290739954f, -1.16619778f }, { -0.145799756f, -1.18859875f }, { 0.00000000f, -1.19175363f }, { 0.156797290f, -1.19175363f }, { 0.327741623f, -1.19175363f }, { 0.510643244f, -1.19175363f }, { 0.699907303f, -1.19175363f }, { 0.886917710f, -1.19175363f }, { 1.06066012f, -1.14180124f }, { 1.19912076f, -1.00125873f }, { 1.27994156f, -0.825029850f }, { 1.27994156f, -0.633879662f }, { 1.27994156f, -0.442624867f }, { 1.27994156f, -0.258665323f }, { 1.27994156f, -0.0811409950f }, { 1.27994156f, 0.0980905294f }, { 1.27994156f, 0.285711050f }, { 1.27994156f, 0.481403828f }, { 1.27994156f, 0.677932978f }, { 1.22896290f, 0.861875772f }, { 1.09601569f, 1.01487422f }, { 0.926782608f, 1.11061263f }, { 0.739629149f, 1.11061263f }, { 0.545323849f, 1.11061263f }, { 0.353048563f, 1.11061263f }, { 0.169804931f, 1.11061263f } }, // 48
}
};
uint32_t s_VisibilityMaskIndices[2][3][200] =
{
// first view
{
// XR_VISIBILITY_MASK_TYPE_HIDDEN_TRIANGLE_MESH_KHR
{ 4, 0, 3, 16, 1, 0, 28, 2, 1, 40, 3, 2, 0, 4, 5, 0, 5, 6, 0, 6, 7, 0, 7, 8, 0, 8, 9, 0, 9, 10, 0, 10, 11, 0, 11, 12, 0, 12, 13, 0, 13, 14, 0, 14, 15, 0, 15, 16, 1, 16, 17, 1, 17, 18, 1, 18, 19, 1, 19, 20, 1, 20, 21, 1, 21, 22, 1, 22, 23, 1, 23, 24, 1, 24, 25, 1, 25, 26, 1, 26, 27, 1, 27, 28, 2, 28, 29, 2, 29, 30, 2, 30, 31, 2, 31, 32, 2, 32, 33, 2, 33, 34, 2, 34, 35, 2, 35, 36, 2, 36, 37, 2, 37, 38, 2, 38, 39, 2, 39, 40, 3, 40, 41, 3, 41, 42, 3, 42, 43, 3, 43, 44, 3, 44, 45, 3, 45, 46, 3, 46, 47, 3, 47, 48, 3, 48, 49, 3, 49, 50, 3, 50, 51, 3, 51, 4 }, // 156
// XR_VISIBILITY_MASK_TYPE_VISIBLE_TRIANGLE_MESH_KHR
{ 1, 0, 2, 2, 0, 3, 3, 0, 4, 4, 0, 5, 5, 0, 6, 6, 0, 7, 7, 0, 8, 8, 0, 9, 9, 0, 10, 10, 0, 11, 11, 0, 12, 12, 0, 13, 13, 0, 14, 14, 0, 15, 15, 0, 16, 16, 0, 17, 17, 0, 18, 18, 0, 19, 19, 0, 20, 20, 0, 21, 21, 0, 22, 22, 0, 23, 23, 0, 24, 24, 0, 25, 25, 0, 26, 26, 0, 27, 27, 0, 28, 28, 0, 29, 29, 0, 30, 30, 0, 31, 31, 0, 32, 32, 0, 33, 33, 0, 34, 34, 0, 35, 35, 0, 36, 36, 0, 37, 37, 0, 38, 38, 0, 39, 39, 0, 40, 40, 0, 41, 41, 0, 42, 42, 0, 43, 43, 0, 44, 44, 0, 45, 45, 0, 46, 46, 0, 47, 47, 0, 48, 48, 0, 1 }, // 144
// XR_VISIBILITY_MASK_TYPE_LINE_LOOP_KHR
{ 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }, // 48
},
// second view
{
// XR_VISIBILITY_MASK_TYPE_HIDDEN_TRIANGLE_MESH_KHR
{ 0, 4, 3, 1, 16, 0, 2, 28, 1, 3, 40, 2, 4, 0, 5, 5, 0, 6, 6, 0, 7, 7, 0, 8, 8, 0, 9, 9, 0, 10, 10, 0, 11, 11, 0, 12, 12, 0, 13, 13, 0, 14, 14, 0, 15, 15, 0, 16, 16, 1, 17, 17, 1, 18, 18, 1, 19, 19, 1, 20, 20, 1, 21, 21, 1, 22, 22, 1, 23, 23, 1, 24, 24, 1, 25, 25, 1, 26, 26, 1, 27, 27, 1, 28, 28, 2, 29, 29, 2, 30, 30, 2, 31, 31, 2, 32, 32, 2, 33, 33, 2, 34, 34, 2, 35, 35, 2, 36, 36, 2, 37, 37, 2, 38, 38, 2, 39, 39, 2, 40, 40, 3, 41, 41, 3, 42, 42, 3, 43, 43, 3, 44, 44, 3, 45, 45, 3, 46, 46, 3, 47, 47, 3, 48, 48, 3, 49, 49, 3, 50, 50, 3, 51, 51, 3, 4 }, // 156
// XR_VISIBILITY_MASK_TYPE_VISIBLE_TRIANGLE_MESH_KHR
{ 0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5, 0, 5, 6, 0, 6, 7, 0, 7, 8, 0, 8, 9, 0, 9, 10, 0, 10, 11, 0, 11, 12, 0, 12, 13, 0, 13, 14, 0, 14, 15, 0, 15, 16, 0, 16, 17, 0, 17, 18, 0, 18, 19, 0, 19, 20, 0, 20, 21, 0, 21, 22, 0, 22, 23, 0, 23, 24, 0, 24, 25, 0, 25, 26, 0, 26, 27, 0, 27, 28, 0, 28, 29, 0, 29, 30, 0, 30, 31, 0, 31, 32, 0, 32, 33, 0, 33, 34, 0, 34, 35, 0, 35, 36, 0, 36, 37, 0, 37, 38, 0, 38, 39, 0, 39, 40, 0, 40, 41, 0, 41, 42, 0, 42, 43, 0, 43, 44, 0, 44, 45, 0, 45, 46, 0, 46, 47, 0, 47, 48, 0, 48, 1 }, // 144
// XR_VISIBILITY_MASK_TYPE_LINE_LOOP_KHR
{ 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }, // 48
}
};

View File

@@ -0,0 +1,69 @@
#ifdef _WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif // !WIN32_LEAN_AND_MEAN
#include <d3d11.h>
#include <d3d12.h>
#include <windows.h>
#endif
#ifdef XR_USE_PLATFORM_ANDROID
#include <jni.h>
#endif
#ifdef XR_USE_GRAPHICS_API_OPENGL_ES
#include <EGL/egl.h>
#endif
#include <vulkan/vulkan.h>
#define XR_NO_PROTOTYPES
#include "XR/IUnityXRTrace.h"
#include "openxr/openxr.h"
#include "openxr/openxr_platform.h"
#include "plugin_load.h"
#include <openxr/loader_interfaces.h>
#include <openxr/openxr_reflection.h>
struct IUnityXRTrace;
extern IUnityXRTrace* s_Trace;
IUnityXRTrace* s_Trace = nullptr;
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrGetInstanceProcAddr(XrInstance instance, const char* name, PFN_xrVoidFunction* function);
PluginHandle s_PluginHandle = nullptr;
PFN_xrGetInstanceProcAddr s_GetInstanceProcAddr = nullptr;
static bool LoadMockRuntime()
{
if (nullptr != s_GetInstanceProcAddr)
return true;
s_PluginHandle = Plugin_LoadLibrary(L"mock_runtime");
if (nullptr == s_PluginHandle)
return false;
s_GetInstanceProcAddr = (PFN_xrGetInstanceProcAddr)Plugin_GetSymbol(s_PluginHandle, "xrGetInstanceProcAddr");
return nullptr != s_GetInstanceProcAddr;
}
extern "C" XrResult UNITY_INTERFACE_EXPORT XRAPI_PTR xrGetInstanceProcAddr(XrInstance instance, const char* name, PFN_xrVoidFunction* function)
{
if (!LoadMockRuntime())
return XR_ERROR_RUNTIME_FAILURE;
return s_GetInstanceProcAddr(instance, name, function);
}
extern "C" void UNITY_INTERFACE_EXPORT XRAPI_PTR SetXRTrace(IUnityXRTrace* trace)
{
if (!LoadMockRuntime())
return;
typedef void (*PFN_SetXRTrace)(IUnityXRTrace * trace);
PFN_SetXRTrace set = (PFN_SetXRTrace)Plugin_GetSymbol(s_PluginHandle, "SetXRTrace");
if (set != nullptr)
set(trace);
}