work on openxr controllers

This commit is contained in:
2026-06-15 03:49:11 +03:00
parent b8aa36ccc0
commit c51080a903
16 changed files with 1030 additions and 75 deletions

View File

@@ -9,6 +9,29 @@
#include "tier0/lib.h"
#include "tier1/utlvector.h"
#include "materialsystem/imaterialsystem.h"
#include "tier1/utlstring.h"
#include "tier2/fileformats/json.h"
#include "tier2/ifilesystem.h"
static XrPath OpenXrGetPath( XrInstance i, const char *szString )
{
XrPath xrPath;
xrStringToPath(i, szString, &xrPath);
return xrPath;
}
static CUtlString OpenXrGetString( XrInstance i, XrPath path )
{
uint32_t l;
char t[XR_MAX_PATH_LENGTH];
XrResult r = xrPathToString(i, path, XR_MAX_PATH_LENGTH, &l, t);
if (r)
return NULL;
return t;
}
struct EyeSwapchain_t
{
@@ -19,8 +42,37 @@ struct EyeSwapchain_t
CUtlVector<IImage*> m_pImages;
IImage *m_pUserImage;
};
class COpenXRManager;
class COpenXRHeadset;
struct OpenXRAction
{
CUtlString m_szName;
XrAction m_action;
XrActionType m_eType;
XrSpace m_space;
};
class COpenXRController: public IXRController
{
public:
virtual EXRControllerType_t GetControllerType() override;
virtual EXRControllerSide_t GetControllerSide() override;
virtual IXRHeadset *GetHeadset() override;
virtual void SetInputCallback( XRInputCallbackFn fn ) override;
void Frame();
void ConfigureActionSets( const char *szDevice, const char *szProfile );
COpenXRHeadset *m_pHeadset;
EXRControllerType_t m_type;
EXRControllerSide_t m_side;
CUtlVector<OpenXRAction> m_actions;
XrActionSet m_actionSet;
XRInputCallbackFn m_callback = NULL;
};
class COpenXRHeadset: public IXRHeadset, public IAppSystem
{
public:
@@ -31,6 +83,9 @@ public:
virtual XRRenderSurface_t GetSurface( uint32_t i ) override;
virtual void SetSurfaceImage( uint32_t i, IImage *pImage ) override;
virtual uint32_t GetControllerCount() override;
virtual IXRController *GetController( uint32_t i ) override;
void Frame();
void BeforeRender();
void AfterRender();
@@ -46,12 +101,16 @@ public:
CUtlVector<XrCompositionLayerProjectionView> m_projviews;
CUtlVector<XrView> m_views;
float m_fPredictedTime;
COpenXRController *m_pLeftHand;
COpenXRController *m_pRightHand;
};
class COpenXRController: public IXRController
enum EOpenXRAPI
{
OPENXR_API_VULKAN,
OPENXR_API_VULKAN2,
};
class COpenXRManager: public IXRManager
@@ -73,9 +132,191 @@ public:
COpenXRHeadset m_headset;
XrInstance m_instance;
bool m_bIsDebugUtilsSupported = false;
bool m_bIsVulkanSupported = false;
bool m_bIsVulkan2Supported = false;
EOpenXRAPI m_gpuAPI;
};
EXPOSE_INTERFACE(COpenXRManager, IXRManager, OPEN_XR_INTERFACE_VERSION);
EXRControllerType_t COpenXRController::GetControllerType()
{
return m_type;
}
EXRControllerSide_t COpenXRController::GetControllerSide()
{
return m_side;
}
IXRHeadset *COpenXRController::GetHeadset()
{
return m_pHeadset;
}
void COpenXRController::SetInputCallback( XRInputCallbackFn fn )
{
m_callback = fn;
}
void COpenXRController::Frame()
{
for (auto &a: m_actions)
{
switch(a.m_eType)
{
case XR_ACTION_TYPE_BOOLEAN_INPUT:
{
XrActionStateGetInfo gi = {};
gi.type = XR_TYPE_ACTION_STATE_GET_INFO;
gi.action = a.m_action;
XrActionStateBoolean b = {};
b.type = XR_TYPE_ACTION_STATE_BOOLEAN;
xrGetActionStateBoolean(m_pHeadset->m_session, &gi, &b);
V_printf("%s %b\n", a.m_szName.GetString(), b.currentState);
break;
}
case XR_ACTION_TYPE_FLOAT_INPUT:
{
XrActionStateGetInfo gi = {};
gi.type = XR_TYPE_ACTION_STATE_GET_INFO;
gi.action = a.m_action;
XrActionStateFloat f32 = {};
f32.type = XR_TYPE_ACTION_STATE_FLOAT;
xrGetActionStateFloat(m_pHeadset->m_session, &gi, &f32);
V_printf("%s %f\n", a.m_szName.GetString(), f32.currentState);
break;
}
case XR_ACTION_TYPE_POSE_INPUT:
{
XrActionStateGetInfo gi = {};
gi.type = XR_TYPE_ACTION_STATE_GET_INFO;
gi.action = a.m_action;
XrActionStatePose pose = {};
pose.type = XR_TYPE_ACTION_STATE_POSE;
xrGetActionStatePose(m_pHeadset->m_session, &gi, &pose);
if (pose.isActive)
{
XrSpaceLocation s = {};
s.type = XR_TYPE_SPACE_LOCATION;
xrLocateSpace(a.m_space, m_pHeadset->m_space, m_pHeadset->m_fPredictedTime, &s);
EXRInputValue_t v;
v.type = k_EXRValue_Pose;
v.pose.pos = {s.pose.position.x, s.pose.position.y, s.pose.position.z};
if (m_callback)
m_callback( this, k_EXRInput_Grip, NULL, k_EXRInputAction_Pose, v );
}
break;
}
default:
break;
}
};
}
void COpenXRController::ConfigureActionSets( const char *szDevice, const char *szProfile )
{
XrActionSetCreateInfo setci = {};
setci.type = XR_TYPE_ACTION_SET_CREATE_INFO;
strcpy(setci.actionSetName, "funny");
strcpy(setci.localizedActionSetName, "funny");
xrCreateActionSet(m_pHeadset->m_pManager->m_instance, &setci, &m_actionSet);
XrSessionActionSetsAttachInfo attachi = {};
attachi.type = XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO;
attachi.actionSets = &m_actionSet;
attachi.countActionSets = 1;
xrAttachSessionActionSets(m_pHeadset->m_session, &attachi);
CUtlString szPath = CUtlString("game/core/openxr%s.json", szProfile);
IFileHandle *pHandle = filesystem->Open(szPath, FILEMODE_READ);
const char *sz = filesystem->ReadString(pHandle);
IJSONValue *pVal = JSONManager()->ReadString(sz);
IJSONValue *pDevice = (*pVal)[szDevice];
IJSONValue *pInputs = (*pDevice)["inputs"];
if (!pInputs)
return;
for (uint32_t i = 0; i < pInputs->GetArray()->GetCount(); i++ )
{
IJSONValue *pInput = (*pInputs)[i];
CUtlString szInputName = (*pInput)["name"]->GetStringValue();
IJSONValue *pActions = (*pInput)["actions"];
for (uint32_t y = 0; y < pActions->GetArray()->GetCount(); y++ )
{
IJSONValue *pAction = (*pActions)[y];
CUtlString szType = pAction->GetStringValue();
XrActionType eType = XR_ACTION_TYPE_MAX_ENUM;
if (szType == "click")
eType = XR_ACTION_TYPE_BOOLEAN_INPUT;
if (szType == "touch")
eType = XR_ACTION_TYPE_BOOLEAN_INPUT;
if (szType == "force")
eType = XR_ACTION_TYPE_FLOAT_INPUT;
if (szType == "value")
eType = XR_ACTION_TYPE_FLOAT_INPUT;
if (szType == "x")
eType = XR_ACTION_TYPE_FLOAT_INPUT;
if (szType == "y")
eType = XR_ACTION_TYPE_FLOAT_INPUT;
if (szType == "twist")
eType = XR_ACTION_TYPE_FLOAT_INPUT;
if (szType == "pose")
eType = XR_ACTION_TYPE_POSE_INPUT;
XrAction a = XR_NULL_HANDLE;
XrActionCreateInfo aci = {};
aci.type = XR_TYPE_ACTION_CREATE_INFO;
aci.actionType = eType;
CUtlString szName = CUtlString("%s/input/%s/%s", szDevice, szInputName.GetString(), szType.GetString());
V_strncpy(aci.actionName, szName.GetString(), XR_MAX_ACTION_NAME_SIZE);
V_strncpy(aci.localizedActionName, szName.GetString(), XR_MAX_LOCALIZED_ACTION_NAME_SIZE);
XrResult r = xrCreateAction(m_actionSet, &aci, &a);
OpenXRAction action = {};
action.m_szName = szName;
action.m_action = a;
action.m_eType = eType;
if (eType == XR_ACTION_TYPE_POSE_INPUT)
{
XrActionSpaceCreateInfo asci = {};
asci.type = XR_TYPE_ACTION_SPACE_CREATE_INFO;
asci.poseInActionSpace = {{0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f}};
asci.action = a;
XrResult r = xrCreateActionSpace(m_pHeadset->m_session, &asci, &action.m_space);
}
m_actions.AppendTail(action);
}
}
CUtlVector<XrActionSuggestedBinding> suggestions = {};
suggestions.Reserve(m_actions.GetSize());
for ( auto &a: m_actions )
{
suggestions.AppendTail({a.m_action, OpenXrGetPath(m_pHeadset->m_pManager->m_instance, a.m_szName)});
}
XrInteractionProfileSuggestedBinding binding = {};
binding.type = XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING;
binding.interactionProfile = OpenXrGetPath(m_pHeadset->m_pManager->m_instance, szProfile);
binding.countSuggestedBindings = suggestions.GetSize();
binding.suggestedBindings = suggestions.GetData();
xrSuggestInteractionProfileBindings(m_pHeadset->m_pManager->m_instance, &binding);
JSONManager()->FreeValue(pVal);
V_free((void*)sz);
}
void COpenXRManager::Init()
{
PFN_xrInitializeLoaderKHR fnInitLoader = NULL;
@@ -85,27 +326,66 @@ void COpenXRManager::Init()
V_printf("Failed to load OpenXR, we are not running OpenXR\n");
return;
}
XrApplicationInfo appInfo = {};
appInfo.apiVersion = XR_API_VERSION_1_1;
V_strncpy(appInfo.applicationName, "funny", XR_MAX_APPLICATION_NAME_SIZE);
V_strncpy(appInfo.engineName, "funny", XR_MAX_ENGINE_NAME_SIZE);
if (r != XR_SUCCESS)
Plat_FatalErrorFunc("Failed to load OpenXR\n");
const char *extensions[] = {
XR_EXT_DEBUG_UTILS_EXTENSION_NAME,
XR_KHR_VULKAN_ENABLE_EXTENSION_NAME,
};
uint32_t nInstanceExtension = 0;
xrEnumerateInstanceExtensionProperties(NULL, 0, &nInstanceExtension, NULL);
CUtlVector<XrExtensionProperties> availableExts(nInstanceExtension);
for (auto &e: availableExts)
e.type = XR_TYPE_EXTENSION_PROPERTIES;
xrEnumerateInstanceExtensionProperties(NULL, nInstanceExtension, &nInstanceExtension, availableExts.GetData());
CUtlVector<const char *> extensions = {};
for ( auto &e: availableExts )
{
if (!V_strncmp(XR_EXT_DEBUG_UTILS_EXTENSION_NAME, e.extensionName, XR_MAX_EXTENSION_NAME_SIZE))
{
extensions.AppendTail(XR_EXT_DEBUG_UTILS_EXTENSION_NAME);
m_bIsDebugUtilsSupported = false;
}
if (!V_strncmp(XR_KHR_VULKAN_ENABLE_EXTENSION_NAME, e.extensionName, XR_MAX_EXTENSION_NAME_SIZE))
{
extensions.AppendTail(XR_KHR_VULKAN_ENABLE_EXTENSION_NAME);
m_bIsVulkanSupported = true;
}
if (!V_strncmp(XR_KHR_VULKAN_ENABLE2_EXTENSION_NAME, e.extensionName, XR_MAX_EXTENSION_NAME_SIZE))
{
extensions.AppendTail(XR_KHR_VULKAN_ENABLE2_EXTENSION_NAME);
m_bIsVulkan2Supported = true;
}
}
if (m_pRenderContext->GetVulkanInstance() != NULL)
{
if (m_bIsVulkan2Supported) {
if (m_bIsVulkanSupported)
m_gpuAPI = OPENXR_API_VULKAN;
else
m_gpuAPI = OPENXR_API_VULKAN2;
}
if (m_bIsVulkanSupported)
{
m_gpuAPI = OPENXR_API_VULKAN;
}
}
for (auto &e: extensions)
V_printf("%s\n", e);
const char *layers[] = {
"XR_APILAYER_LUNARG_core_validation"
};
XrApplicationInfo appInfo = {};
appInfo.apiVersion = XR_API_VERSION_1_1;
V_strncpy(appInfo.applicationName, "funny", XR_MAX_APPLICATION_NAME_SIZE);
V_strncpy(appInfo.engineName, "funny", XR_MAX_ENGINE_NAME_SIZE);
XrInstanceCreateInfo createInfo = {};
createInfo.type = XR_TYPE_INSTANCE_CREATE_INFO;
createInfo.applicationInfo = appInfo;
createInfo.enabledExtensionCount = sizeof(extensions)/sizeof(*extensions);
createInfo.enabledExtensionNames = extensions;
createInfo.enabledExtensionCount = extensions.GetSize();
createInfo.enabledExtensionNames = extensions.GetData();
createInfo.enabledApiLayerCount = sizeof(layers)/sizeof(*layers);
createInfo.enabledApiLayerNames = layers;
r = xrCreateInstance(&createInfo, &m_instance);
@@ -127,6 +407,7 @@ void COpenXRManager::Init()
}
void COpenXRManager::Shutdown()
{
@@ -155,6 +436,15 @@ void COpenXRManager::CopySwapchain()
}
struct OpenXRProfile_t {
const char *m_szName;
EXRControllerType_t m_eType;
};
const static CUtlVector<OpenXRProfile_t> s_interactionProfiles = {
{"/interaction_profiles/khr/simple_controller", k_EXR_HandController},
{"/interaction_profiles/oculus/touch_controller", k_EXR_HandController},
};
void COpenXRHeadset::Init()
{
@@ -167,36 +457,85 @@ void COpenXRHeadset::Init()
if (r != XR_SUCCESS)
Plat_FatalErrorFunc("xrGetSystem\n");
/* each backend requires its own shit */
XrGraphicsRequirementsVulkanKHR requirements = {};
requirements.type = XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR;
PFN_xrGetVulkanGraphicsRequirementsKHR fnVulkanRequirements = NULL;
xrGetInstanceProcAddr(m_pManager->m_instance, "xrGetVulkanGraphicsRequirementsKHR", (PFN_xrVoidFunction*)&fnVulkanRequirements);
if (r != XR_SUCCESS)
Plat_FatalErrorFunc("Failed to get xrGetVulkanGraphicsRequirementsKHR\n");
fnVulkanRequirements( m_pManager->m_instance, m_systemId, &requirements);
switch (m_pManager->m_gpuAPI)
{
case OPENXR_API_VULKAN:
{
XrGraphicsRequirementsVulkanKHR requirements = {};
requirements.type = XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR;
PFN_xrGetVulkanGraphicsRequirementsKHR fnVulkanRequirements = NULL;
xrGetInstanceProcAddr(m_pManager->m_instance, "xrGetVulkanGraphicsRequirementsKHR", (PFN_xrVoidFunction*)&fnVulkanRequirements);
if (r != XR_SUCCESS)
Plat_FatalErrorFunc("Failed to get xrGetVulkanGraphicsRequirementsKHR\n");
fnVulkanRequirements( m_pManager->m_instance, m_systemId, &requirements);
PFN_xrGetVulkanGraphicsDeviceKHR fnVulkanDevice = NULL;
xrGetInstanceProcAddr(m_pManager->m_instance, "xrGetVulkanGraphicsDeviceKHR", (PFN_xrVoidFunction*)&fnVulkanDevice);
if (r != XR_SUCCESS)
Plat_FatalErrorFunc("Failed to get xrGetVulkanGraphicsDeviceKHR\n");
VkPhysicalDevice d = NULL;
fnVulkanDevice(m_pManager->m_instance, m_systemId, (VkInstance)m_pManager->m_pRenderContext->GetVulkanInstance(), &d);
PFN_xrGetVulkanGraphicsDeviceKHR fnVulkanDevice = NULL;
xrGetInstanceProcAddr(m_pManager->m_instance, "xrGetVulkanGraphicsDeviceKHR", (PFN_xrVoidFunction*)&fnVulkanDevice);
if (r != XR_SUCCESS)
Plat_FatalErrorFunc("Failed to get xrGetVulkanGraphicsDeviceKHR\n");
VkPhysicalDevice d = NULL;
fnVulkanDevice(m_pManager->m_instance, m_systemId, (VkInstance)m_pManager->m_pRenderContext->GetVulkanInstance(), &d);
XrGraphicsBindingVulkan2KHR vkBinding = {};
vkBinding.type = XR_TYPE_GRAPHICS_BINDING_VULKAN2_KHR;
vkBinding.instance = (VkInstance)m_pManager->m_pRenderContext->GetVulkanInstance();
vkBinding.physicalDevice = (VkPhysicalDevice)m_pManager->m_pRenderContext->GetVulkanPhysicalDevice();
vkBinding.device = (VkDevice)m_pManager->m_pRenderContext->GetVulkanDevice();
XrGraphicsBindingVulkan2KHR vkBinding = {};
vkBinding.type = XR_TYPE_GRAPHICS_BINDING_VULKAN2_KHR;
vkBinding.instance = (VkInstance)m_pManager->m_pRenderContext->GetVulkanInstance();
vkBinding.physicalDevice = (VkPhysicalDevice)m_pManager->m_pRenderContext->GetVulkanPhysicalDevice();
vkBinding.device = (VkDevice)m_pManager->m_pRenderContext->GetVulkanDevice();
XrSessionCreateInfo sessionCreateInfo = {};
sessionCreateInfo.type = XR_TYPE_SESSION_CREATE_INFO;
sessionCreateInfo.next = &vkBinding;
sessionCreateInfo.systemId = m_systemId;
r = xrCreateSession(m_pManager->m_instance, &sessionCreateInfo, &m_session);
if (r != XR_SUCCESS)
Plat_FatalErrorFunc("xrCreateSession\n");
}
break;
case OPENXR_API_VULKAN2:
{
XrGraphicsRequirementsVulkanKHR requirements = {};
requirements.type = XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR;
PFN_xrGetVulkanGraphicsRequirements2KHR fnVulkanRequirements = NULL;
xrGetInstanceProcAddr(m_pManager->m_instance, "xrGetVulkanGraphicsRequirements2KHR", (PFN_xrVoidFunction*)&fnVulkanRequirements);
if (r != XR_SUCCESS)
Plat_FatalErrorFunc("Failed to get xrGetVulkanGraphicsRequirements2KHR\n");
fnVulkanRequirements( m_pManager->m_instance, m_systemId, &requirements);
PFN_xrGetVulkanGraphicsDevice2KHR fnVulkanDevice = NULL;
xrGetInstanceProcAddr(m_pManager->m_instance, "xrGetVulkanGraphicsDevice2KHR", (PFN_xrVoidFunction*)&fnVulkanDevice);
if (r != XR_SUCCESS)
Plat_FatalErrorFunc("Failed to get xrGetVulkanGraphicsDevice2KHR\n");
VkPhysicalDevice d = NULL;
XrVulkanGraphicsDeviceGetInfoKHR dgi = {};
dgi.type = XR_TYPE_VULKAN_GRAPHICS_DEVICE_GET_INFO_KHR;
dgi.systemId = m_systemId;
dgi.vulkanInstance = (VkInstance)m_pManager->m_pRenderContext->GetVulkanInstance();
fnVulkanDevice(m_pManager->m_instance, &dgi, &d);
XrGraphicsBindingVulkan2KHR vkBinding = {};
vkBinding.type = XR_TYPE_GRAPHICS_BINDING_VULKAN2_KHR;
vkBinding.instance = (VkInstance)m_pManager->m_pRenderContext->GetVulkanInstance();
vkBinding.physicalDevice = (VkPhysicalDevice)m_pManager->m_pRenderContext->GetVulkanPhysicalDevice();
vkBinding.device = (VkDevice)m_pManager->m_pRenderContext->GetVulkanDevice();
XrSessionCreateInfo sessionCreateInfo = {};
sessionCreateInfo.type = XR_TYPE_SESSION_CREATE_INFO;
sessionCreateInfo.next = &vkBinding;
sessionCreateInfo.systemId = m_systemId;
r = xrCreateSession(m_pManager->m_instance, &sessionCreateInfo, &m_session);
if (r != XR_SUCCESS)
Plat_FatalErrorFunc("xrCreateSession\n");
}
break;
default:
break;
}
XrSessionCreateInfo sessionCreateInfo = {};
sessionCreateInfo.type = XR_TYPE_SESSION_CREATE_INFO;
sessionCreateInfo.next = &vkBinding;
sessionCreateInfo.systemId = m_systemId;
r = xrCreateSession(m_pManager->m_instance, &sessionCreateInfo, &m_session);
if (r != XR_SUCCESS)
Plat_FatalErrorFunc("xrCreateSession\n");
/* create swapchains for rendering pipeline */
@@ -215,7 +554,6 @@ void COpenXRHeadset::Init()
VkFormat eSelectedFormat = preferedSurfaceFormats[0];
for (auto &format: formats)
{
V_printf("Format: %s\n", string_VkFormat((VkFormat)format));
for (int i = 0; i < sizeof(preferedSurfaceFormats)/sizeof(VkFormat); i++)
{
if (format == preferedSurfaceFormats[i])
@@ -270,6 +608,77 @@ formatPicked:
viewLocale.viewConfigurationType = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO;
uint32_t vc = m_views.GetSize();
xrLocateViews(m_session, &viewLocale, &viewState, vc, &vc, m_views.GetData());
for (auto &p: s_interactionProfiles) {
/* load profile */
XrInteractionProfileSuggestedBinding bindings = {};
bindings.type = XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING;
bindings.interactionProfile = OpenXrGetPath(m_pManager->m_instance, p.m_szName);
xrSuggestInteractionProfileBindings(m_pManager->m_instance, &bindings);
}
CUtlVector<const char*> possibleControllers = {
"/user/hand/left",
"/user/hand/right",
};
XrActionSet quetySet = {};
XrActionSetCreateInfo setci = {};
setci.type = XR_TYPE_ACTION_SET_CREATE_INFO;
strcpy(setci.actionSetName, "funny");
strcpy(setci.localizedActionSetName, "funny");
xrCreateActionSet(m_pManager->m_instance, &setci, &quetySet);
XrSessionActionSetsAttachInfo attachi = {};
attachi.type = XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO;
attachi.actionSets = &quetySet;
attachi.countActionSets = 1;
xrAttachSessionActionSets(m_session, &attachi);
for ( auto &c: possibleControllers )
{
XrPath path = OpenXrGetPath(m_pManager->m_instance, c);
XrInteractionProfileState profile = {};
profile.type = XR_TYPE_INTERACTION_PROFILE_STATE;
XrResult r = xrGetCurrentInteractionProfile(m_session, path, &profile);
if (r)
{
V_printf("Controller not found: %s %i\n", c, r);
}
if (profile.interactionProfile == XR_NULL_PATH)
continue;
CUtlString s = OpenXrGetString(m_pManager->m_instance, profile.interactionProfile);
if (!V_strcmp(c, "/user/hand/left"))
{
m_pLeftHand = new COpenXRController;
m_pLeftHand->m_side = k_EXRController_Left;
m_pLeftHand->m_pHeadset = this;
for ( auto &p: s_interactionProfiles )
if (s == p.m_szName)
{
m_pLeftHand->m_type = p.m_eType;
m_pLeftHand->ConfigureActionSets(c, p.m_szName);
}
}
if (!V_strcmp(c, "/user/hand/right"))
{
m_pRightHand = new COpenXRController;
m_pRightHand->m_side = k_EXRController_Left;
m_pRightHand->m_pHeadset = this;
for ( auto &p: s_interactionProfiles )
if (s == p.m_szName)
{
m_pRightHand->m_type = p.m_eType;
m_pRightHand->ConfigureActionSets(c, p.m_szName);
}
}
}
xrDestroyActionSet(quetySet);
}
void COpenXRHeadset::Shutdown()
@@ -319,6 +728,16 @@ void COpenXRHeadset::Frame()
m_fPredictedTime = frameState.predictedDisplayTime;
XrActiveActionSet aas[2] = {};
aas[0].actionSet = m_pLeftHand->m_actionSet;
aas[1].actionSet = m_pRightHand->m_actionSet;
XrActionsSyncInfo si = {};
si.type = XR_TYPE_ACTIONS_SYNC_INFO;
si.activeActionSets = aas;
si.countActiveActionSets = 2;
xrSyncActions(m_session, &si);
m_views = m_eyeSwapchains.GetSize();
m_projviews = m_eyeSwapchains.GetSize();
for ( auto &v: m_views )
@@ -341,6 +760,11 @@ void COpenXRHeadset::Frame()
viewLocale.viewConfigurationType = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO;
uint32_t viewCount = m_views.GetSize();
xrLocateViews(m_session, &viewLocale, &viewState, viewCount, &viewCount, m_views.GetData());
if (m_pLeftHand)
m_pLeftHand->Frame();
if (m_pRightHand)
m_pRightHand->Frame();
}
void COpenXRHeadset::BeforeRender()
@@ -381,7 +805,8 @@ void COpenXRHeadset::CopySwapchain()
ImageSector_t sector = {};
sector.m_iWidth = eye.m_uWidth;
sector.m_iHeight = eye.m_uHeight;
pList->BlitImageToImage(eye.m_pUserImage, sector, eye.m_pImages[eye.m_uImageIndex], sector);
if (eye.m_pUserImage)
pList->BlitImageToImage(eye.m_pUserImage, sector, eye.m_pImages[eye.m_uImageIndex], sector);
}
pList->EndRecording();
pCtx->SubmitCommandList(pList);
@@ -417,25 +842,51 @@ void COpenXRHeadset::AfterRender()
uint32_t COpenXRHeadset::GetSurfaceCount()
{
V_printf("%i\n", m_eyeSwapchains.GetSize());
return m_eyeSwapchains.GetSize();
}
XRRenderSurface_t COpenXRHeadset::GetSurface( uint32_t i )
{
XRRenderSurface_t surface = {};
surface.m_fFov = m_projviews[i].fov.angleLeft+m_projviews[i].fov.angleRight;
surface.m_fFov = m_views[i].fov.angleLeft-m_views[i].fov.angleRight;
surface.m_uWidth = m_eyeSwapchains[i].m_uWidth;
surface.m_uHeight = m_eyeSwapchains[i].m_uHeight;
surface.m_vPosition = (Vector){
m_views[i].pose.position.x,
m_views[i].pose.position.y,
m_views[i].pose.position.z
};
surface.m_vRotation = (Quat){
m_views[i].pose.orientation.x,
m_views[i].pose.orientation.y,
m_views[i].pose.orientation.z,
m_views[i].pose.orientation.w,
};
return surface;
}
void COpenXRHeadset::SetSurfaceImage( uint32_t i, IImage *pImage )
{
m_eyeSwapchains[i].m_pUserImage = pImage;
V_printf("%p\n", pImage);
}
uint32_t COpenXRHeadset::GetControllerCount()
{
return 2;
}
IXRController *COpenXRHeadset::GetController( uint32_t i )
{
if (i == 0)
return m_pLeftHand;
if (i == 1)
return m_pRightHand;
return NULL;
}
void COpenXRHeadset::CreateSwapchainForEye( XrViewConfigurationView *pConf, VkFormat eVkFormat, EyeSwapchain_t *pEye )
{
XrSwapchainCreateInfo createInfo = {};
@@ -456,17 +907,39 @@ void COpenXRHeadset::CreateSwapchainForEye( XrViewConfigurationView *pConf, VkFo
uint32_t imageCount = 0;
xrEnumerateSwapchainImages(pEye->m_swapchain, 0, &imageCount, NULL);
CUtlVector<XrSwapchainImageVulkan2KHR> images = imageCount;
for ( auto &i: images )
CUtlVector<XrSwapchainImageVulkanKHR> images;
switch (m_pManager->m_gpuAPI)
{
i.type = XR_TYPE_SWAPCHAIN_IMAGE_VULKAN2_KHR;
case OPENXR_API_VULKAN:
{
xrEnumerateSwapchainImages(pEye->m_swapchain, 0, &imageCount, NULL);
images = imageCount;
pEye->m_pImages = imageCount;
for ( auto &i: images )
{
i.type = XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR;
}
xrEnumerateSwapchainImages(pEye->m_swapchain, imageCount, &imageCount, (XrSwapchainImageBaseHeader*)images.GetData());
pEye->m_pImages = imageCount;
}
break;
case OPENXR_API_VULKAN2:
{
xrEnumerateSwapchainImages(pEye->m_swapchain, 0, &imageCount, NULL);
images = imageCount;
pEye->m_pImages = imageCount;
for ( auto &i: images )
{
i.type = XR_TYPE_SWAPCHAIN_IMAGE_VULKAN2_KHR;
}
xrEnumerateSwapchainImages(pEye->m_swapchain, imageCount, &imageCount, (XrSwapchainImageBaseHeader*)images.GetData());
for ( auto &i: images )
V_printf("VkImage %p\n", i.image);
}
}
xrEnumerateSwapchainImages(pEye->m_swapchain, imageCount, &imageCount, (XrSwapchainImageBaseHeader*)images.GetData());
pEye->m_pImages = imageCount;
EImageFormat eFormat = IMAGE_FORMAT_RGBA8_UNORM;
switch(eVkFormat)
@@ -501,7 +974,7 @@ IXRHeadset *COpenXRManager::GetHeadset( uint32_t i )
{
if (i)
return 0;
if(bHasXR)
if(!bHasXR)
return 0;
return &m_headset;
@@ -512,3 +985,4 @@ void COpenXRManager::ConnectInterface( void *pIface, const char *szName )
if (!V_strcmp(szName, RENDER_CONTEXT_INTERFACE_VERSION))
m_pRenderContext = (IRenderContext*)pIface;
}