上传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