Skip to content

Commit 5dfaedf

Browse files
committed
Support static and dynamic actionset priorities.
1 parent 2d586f8 commit 5dfaedf

File tree

9 files changed

+248
-73
lines changed

9 files changed

+248
-73
lines changed

virtualdesktop-openxr/action.cpp

Lines changed: 124 additions & 33 deletions
Large diffs are not rendered by default.

virtualdesktop-openxr/framework/dispatch.gen.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2283,6 +2283,9 @@ namespace RUNTIME_NAMESPACE {
22832283
else if (extensionName == "XR_HTCX_vive_tracker_interaction") {
22842284
has_XR_HTCX_vive_tracker_interaction = true;
22852285
}
2286+
else if (extensionName == "XR_EXT_active_action_set_priority") {
2287+
has_XR_EXT_active_action_set_priority = true;
2288+
}
22862289

22872290
}
22882291

virtualdesktop-openxr/framework/dispatch.gen.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ namespace RUNTIME_NAMESPACE {
167167
bool has_XR_META_body_tracking_fidelity{false};
168168
bool has_XR_META_body_tracking_calibration{false};
169169
bool has_XR_HTCX_vive_tracker_interaction{false};
170+
bool has_XR_EXT_active_action_set_priority{false};
170171

171172

172173
};

virtualdesktop-openxr/framework/dispatch_generator.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@
4949
'XR_KHR_win32_convert_performance_counter_time', 'XR_KHR_convert_timespec_time', 'XR_FB_display_refresh_rate', 'XR_EXT_hand_tracking', 'XR_EXT_hand_tracking_data_source',
5050
'XR_EXT_eye_gaze_interaction', 'XR_EXT_uuid', 'XR_META_headset_id', 'XR_OCULUS_audio_device_guid', 'XR_MND_headless',
5151
'XR_FB_eye_tracking_social', 'XR_FB_face_tracking', 'XR_FB_face_tracking2', 'XR_FB_hand_tracking_aim',
52-
'XR_FB_body_tracking', 'XR_META_body_tracking_full_body', 'XR_META_body_tracking_fidelity', 'XR_META_body_tracking_calibration', 'XR_HTCX_vive_tracker_interaction']
52+
'XR_FB_body_tracking', 'XR_META_body_tracking_full_body', 'XR_META_body_tracking_fidelity', 'XR_META_body_tracking_calibration', 'XR_HTCX_vive_tracker_interaction',
53+
'XR_EXT_active_action_set_priority']
5354

5455
SILENT_ERRORS = {
5556
'xrSuggestInteractionProfileBindings': ['XR_ERROR_PATH_UNSUPPORTED'],

virtualdesktop-openxr/instance.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,9 @@ namespace virtualdesktop_openxr {
591591
m_extensionsTable.push_back( // Palm pose.
592592
{XR_EXT_PALM_POSE_EXTENSION_NAME, XR_EXT_palm_pose_SPEC_VERSION});
593593

594+
m_extensionsTable.push_back( // Unreal Engine 5 needs this.
595+
{XR_EXT_ACTIVE_ACTION_SET_PRIORITY_EXTENSION_NAME, XR_EXT_active_action_set_priority_SPEC_VERSION});
596+
594597
m_extensionsTable.push_back( // Audio GUID.
595598
{XR_OCULUS_AUDIO_DEVICE_GUID_EXTENSION_NAME, XR_OCULUS_audio_device_guid_SPEC_VERSION});
596599

virtualdesktop-openxr/mappings.cpp

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -281,80 +281,106 @@ namespace virtualdesktop_openxr {
281281
if (path == "/user/hand/left/input/x/click" || path == "/user/hand/left/input/x") {
282282
source.buttonMap = &m_cachedInputState.Buttons;
283283
source.buttonType = ovrButton_X;
284+
source.sourceIndex = ActionSourceIndex::X;
284285
} else if (path == "/user/hand/left/input/x/touch") {
285286
source.buttonMap = &m_cachedInputState.Touches;
286287
source.buttonType = (ovrButton)ovrTouch_X;
288+
source.sourceIndex = ActionSourceIndex::XTouch;
287289
} else if (path == "/user/hand/left/input/y/click" || path == "/user/hand/left/input/y") {
288290
source.buttonMap = &m_cachedInputState.Buttons;
289291
source.buttonType = ovrButton_Y;
292+
source.sourceIndex = ActionSourceIndex::Y;
290293
} else if (path == "/user/hand/left/input/y/touch") {
291294
source.buttonMap = &m_cachedInputState.Touches;
292295
source.buttonType = (ovrButton)ovrTouch_Y;
296+
source.sourceIndex = ActionSourceIndex::YTouch;
293297
} else if (path == "/user/hand/left/input/menu/click" || path == "/user/hand/left/menu") {
294298
source.buttonMap = &m_cachedInputState.Buttons;
295299
source.buttonType = ovrButton_Enter;
300+
source.sourceIndex = ActionSourceIndex::Menu;
296301
} else if (path == "/user/hand/right/input/a/click" || path == "/user/hand/right/input/a") {
297302
source.buttonMap = &m_cachedInputState.Buttons;
298303
source.buttonType = ovrButton_A;
304+
source.sourceIndex = ActionSourceIndex::A;
299305
} else if (path == "/user/hand/right/input/a/touch") {
300306
source.buttonMap = &m_cachedInputState.Touches;
301307
source.buttonType = (ovrButton)ovrTouch_A;
308+
source.sourceIndex = ActionSourceIndex::ATouch;
302309
} else if (path == "/user/hand/right/input/b/click" || path == "/user/hand/right/input/b") {
303310
source.buttonMap = &m_cachedInputState.Buttons;
304311
source.buttonType = ovrButton_B;
312+
source.sourceIndex = ActionSourceIndex::B;
305313
} else if (path == "/user/hand/right/input/b/touch") {
306314
source.buttonMap = &m_cachedInputState.Touches;
307315
source.buttonType = (ovrButton)ovrTouch_B;
316+
source.sourceIndex = ActionSourceIndex::BTouch;
308317
} else if (path == "/user/hand/right/input/system/click" || path == "/user/hand/right/input/system") {
309318
source.buttonMap = &m_cachedInputState.Buttons;
310319
source.buttonType = ovrButton_Home;
311320
} else if (endsWith(path, "/input/squeeze/click") || endsWith(path, "/input/squeeze/value") ||
312321
endsWith(path, "/input/squeeze")) {
313322
source.floatValue = m_cachedInputState.HandTrigger;
323+
source.sourceIndex = ActionSourceIndex::Squeeze;
314324
} else if (endsWith(path, "/input/squeeze/force")) {
315325
source.floatValue = m_cachedInputState.HandTrigger;
326+
source.sourceIndex = ActionSourceIndex::Squeeze;
316327
} else if (endsWith(path, "/input/trigger/click") || endsWith(path, "/input/trigger/value") ||
317328
endsWith(path, "/input/trigger")) {
318329
source.floatValue = m_cachedInputState.IndexTrigger;
330+
source.sourceIndex = ActionSourceIndex::Trigger;
319331
} else if (path == "/user/hand/left/input/trigger/touch") {
320332
source.buttonMap = &m_cachedInputState.Touches;
321333
source.buttonType = (ovrButton)ovrTouch_LIndexTrigger;
334+
source.sourceIndex = ActionSourceIndex::TriggerTouch;
322335
} else if (path == "/user/hand/right/input/trigger/touch") {
323336
source.buttonMap = &m_cachedInputState.Touches;
324337
source.buttonType = (ovrButton)ovrTouch_RIndexTrigger;
338+
source.sourceIndex = ActionSourceIndex::TriggerTouch;
325339
} else if (path == "/user/hand/left/input/thumbstick/click" ||
326340
(xrAction.type == XR_ACTION_TYPE_BOOLEAN_INPUT && path == "/user/hand/left/input/thumbstick")) {
327341
source.buttonMap = &m_cachedInputState.Buttons;
328342
source.buttonType = ovrButton_LThumb;
343+
source.sourceIndex = ActionSourceIndex::Thumbstick;
329344
} else if (path == "/user/hand/right/input/thumbstick/click" ||
330345
(xrAction.type == XR_ACTION_TYPE_BOOLEAN_INPUT && path == "/user/hand/right/input/thumbstick")) {
331346
source.buttonMap = &m_cachedInputState.Buttons;
332347
source.buttonType = ovrButton_RThumb;
348+
source.sourceIndex = ActionSourceIndex::Thumbstick;
333349
} else if (endsWith(path, "/input/thumbstick")) {
334350
source.vector2fValue = m_cachedInputState.ThumbstickNoDeadzone;
335351
source.vector2fIndex = -1;
352+
source.sourceIndex = ActionSourceIndex::ThumbstickXY;
336353
} else if (endsWith(path, "/input/thumbstick/x")) {
337354
source.vector2fValue = m_cachedInputState.ThumbstickNoDeadzone;
338355
source.vector2fIndex = 0;
356+
source.sourceIndex = ActionSourceIndex::ThumbstickX;
339357
} else if (endsWith(path, "/input/thumbstick/y")) {
340358
source.vector2fValue = m_cachedInputState.ThumbstickNoDeadzone;
341359
source.vector2fIndex = 1;
360+
source.sourceIndex = ActionSourceIndex::ThumbstickY;
342361
} else if (path == "/user/hand/left/input/thumbstick/touch") {
343362
source.buttonMap = &m_cachedInputState.Touches;
344363
source.buttonType = (ovrButton)ovrTouch_LThumb;
364+
source.sourceIndex = ActionSourceIndex::ThumbstickTouch;
345365
} else if (path == "/user/hand/right/input/thumbstick/touch") {
346366
source.buttonMap = &m_cachedInputState.Touches;
347367
source.buttonType = (ovrButton)ovrTouch_RThumb;
368+
source.sourceIndex = ActionSourceIndex::ThumbstickTouch;
348369
} else if (path == "/user/hand/left/input/thumbrest/touch" || path == "/user/hand/left/input/thumbrest") {
349370
source.buttonMap = &m_cachedInputState.Touches;
350371
source.buttonType = (ovrButton)ovrTouch_LThumbRest;
372+
source.sourceIndex = ActionSourceIndex::ThumbrestTouch;
351373
} else if (path == "/user/hand/right/input/thumbrest/touch" || path == "/user/hand/right/input/thumbrest") {
352374
source.buttonMap = &m_cachedInputState.Touches;
353375
source.buttonType = (ovrButton)ovrTouch_RThumbRest;
354-
} else if (endsWith(path, "/input/grip/pose") || endsWith(path, "/input/grip") ||
355-
endsWith(path, "/input/aim/pose") || endsWith(path, "/input/aim") ||
356-
endsWith(path, "/input/palm_ext/pose") || endsWith(path, "/input/palm_ext") ||
357-
endsWith(path, "/output/haptic")) {
376+
source.sourceIndex = ActionSourceIndex::ThumbrestTouch;
377+
} else if (endsWith(path, "/input/grip/pose") || endsWith(path, "/input/grip")) {
378+
source.sourceIndex = ActionSourceIndex::Grip;
379+
} else if (endsWith(path, "/input/aim/pose") || endsWith(path, "/input/aim")) {
380+
source.sourceIndex = ActionSourceIndex::Aim;
381+
} else if (endsWith(path, "/input/palm_ext/pose") || endsWith(path, "/input/palm_ext")) {
382+
source.sourceIndex = ActionSourceIndex::Palm;
383+
} else if (endsWith(path, "/output/haptic")) {
358384
// Do nothing.
359385
} else {
360386
// No possible binding.

virtualdesktop-openxr/runtime.h

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,34 @@ namespace virtualdesktop_openxr {
379379
XrPosef poseInSpace;
380380
};
381381

382+
enum class ActionSourceIndex {
383+
Invalid = 0,
384+
X,
385+
XTouch,
386+
Y,
387+
YTouch,
388+
Menu,
389+
A,
390+
ATouch,
391+
B,
392+
BTouch,
393+
System,
394+
Squeeze,
395+
Trigger,
396+
TriggerTouch,
397+
Thumbstick,
398+
ThumbstickXY,
399+
ThumbstickX,
400+
ThumbstickY,
401+
ThumbstickTouch,
402+
ThumbrestTouch,
403+
Grip,
404+
Aim,
405+
Palm,
406+
407+
Count
408+
};
409+
382410
struct ActionSource {
383411
const float* floatValue{nullptr};
384412

@@ -388,12 +416,15 @@ namespace virtualdesktop_openxr {
388416
const uint32_t* buttonMap{nullptr};
389417
ovrButton buttonType;
390418

419+
ActionSourceIndex sourceIndex = ActionSourceIndex::Invalid;
391420
std::string realPath;
392421
};
393422

394423
struct ActionSet {
395424
std::string name;
396425
std::string localizedName;
426+
uint32_t priority;
427+
uint32_t effectivePriority;
397428

398429
std::set<XrPath> subactionPaths;
399430

@@ -683,7 +714,7 @@ namespace virtualdesktop_openxr {
683714
std::shared_mutex m_actionsAndSpacesMutex;
684715
std::map<XrPath, std::string> m_strings; // protected by actionsAndSpacesMutex
685716
std::set<XrActionSet> m_actionSets;
686-
std::set<XrActionSet> m_activeActionSets;
717+
std::set<XrActionSet> m_attachedActionSets;
687718
std::set<XrAction> m_actions;
688719
std::set<XrAction> m_actionsForCleanup;
689720
std::shared_mutex m_handTrackersMutex;
@@ -806,6 +837,8 @@ namespace virtualdesktop_openxr {
806837
uint64_t m_lastCpuFrameTimeUs{0};
807838
uint64_t m_lastGpuFrameTimeUs{0};
808839
ovrInputState m_cachedInputState;
840+
std::set<XrActionSet> m_activeActionSets;
841+
uint32_t m_actionSourcePriority[(size_t)ActionSourceIndex::Count]{};
809842
BodyTracking::BodyStateV2 m_cachedBodyState{};
810843
XrTime m_lastPredictedDisplayTime{0};
811844
mutable std::optional<XrPosef> m_lastValidHmdPose;

virtualdesktop-openxr/session.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ namespace virtualdesktop_openxr {
174174
m_currentInteractionProfile[xr::Side::Left] = m_currentInteractionProfile[xr::Side::Right] = XR_NULL_PATH;
175175
rebindControllerActions(xr::Side::Left);
176176
rebindControllerActions(xr::Side::Right);
177+
m_attachedActionSets.clear();
177178
m_activeActionSets.clear();
178179

179180
m_sessionStartTime = ovr_GetTimeInSeconds();

virtualdesktop-openxr/space.cpp

Lines changed: 50 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -522,52 +522,68 @@ namespace virtualdesktop_openxr {
522522
} else if (xrSpace.action != XR_NULL_HANDLE) {
523523
// Action spaces for motion controllers.
524524
Action& xrAction = *(Action*)xrSpace.action;
525+
const ActionSet& xrActionSet = *(ActionSet*)xrAction.actionSet;
525526

526527
const std::string& subActionPath = getXrPath(xrSpace.subActionPath);
528+
const bool isActionSetActive = m_activeActionSets.count(xrAction.actionSet);
527529
for (const auto& source : xrAction.actionSources) {
528530
if (!startsWith(source.first, subActionPath)) {
529531
continue;
530532
}
531533

532534
const std::string& fullPath = source.first;
533-
TraceLoggingWrite(g_traceProvider, "xrLocateSpace", TLArg(fullPath.c_str(), "ActionSourcePath"));
535+
const auto& value = source.second;
536+
const bool isHighestPriority =
537+
value.sourceIndex == ActionSourceIndex::Invalid ||
538+
m_actionSourcePriority[(size_t)value.sourceIndex] == xrActionSet.effectivePriority;
539+
const bool isBound = isActionSetActive && isHighestPriority;
540+
TraceLoggingWrite(g_traceProvider,
541+
"xrLocateSpace",
542+
TLArg(fullPath.c_str(), "ActionSourcePath"),
543+
TLArg(m_actionSourcePriority[(size_t)value.sourceIndex], "ActionSourcePriority"),
544+
TLArg(xrActionSet.effectivePriority, "ActionSetPriority"),
545+
TLArg(isBound, "Bound"));
546+
547+
if (isBound) {
548+
const bool isEyeTracker = isActionEyeTracker(fullPath);
549+
const int trackerIndex = getTrackerIndex(fullPath);
550+
551+
if (isEyeTracker) {
552+
result = getEyeTrackerPose(time, pose, gazeSampleTime);
534553

535-
const bool isEyeTracker = isActionEyeTracker(fullPath);
536-
const int trackerIndex = getTrackerIndex(fullPath);
537-
538-
if (isEyeTracker) {
539-
result = getEyeTrackerPose(time, pose, gazeSampleTime);
540-
541-
// Per spec we must consistently pick one source. We pick the first one.
542-
break;
543-
} else if (trackerIndex >= 0) {
544-
result = getBodyJointPose(TrackerRoles[trackerIndex].joint, time, pose);
545-
546-
// Per spec we must consistently pick one source. We pick the first one.
547-
break;
548-
} else {
549-
const bool isGripPose = endsWith(fullPath, "/input/grip/pose") || endsWith(fullPath, "/input/grip");
550-
const bool isAimPose = endsWith(fullPath, "/input/aim/pose") || endsWith(fullPath, "/input/aim");
551-
const bool isPalmPose =
552-
endsWith(fullPath, "/input/palm_ext/pose") || endsWith(fullPath, "/input/palm_ext");
553-
const int side = getActionSide(fullPath);
554-
if ((isGripPose || isAimPose || isPalmPose) && side >= 0) {
555-
result = getControllerPose(side, time, pose, velocity);
556-
557-
// Apply the pose offsets.
558-
if (isAimPose) {
559-
// Try using the hand tracking first.
560-
if (!getPinchPose(side, pose, pose)) {
561-
pose = Pose::Multiply(m_controllerAimPose[side], pose);
562-
}
563-
} else if (isGripPose) {
564-
pose = Pose::Multiply(m_controllerGripPose[side], pose);
565-
} else {
566-
pose = Pose::Multiply(m_controllerPalmPose[side], pose);
567-
}
554+
// Per spec we must consistently pick one source. We pick the first one.
555+
break;
556+
} else if (trackerIndex >= 0) {
557+
result = getBodyJointPose(TrackerRoles[trackerIndex].joint, time, pose);
568558

569559
// Per spec we must consistently pick one source. We pick the first one.
570560
break;
561+
} else {
562+
const bool isGripPose =
563+
endsWith(fullPath, "/input/grip/pose") || endsWith(fullPath, "/input/grip");
564+
const bool isAimPose =
565+
endsWith(fullPath, "/input/aim/pose") || endsWith(fullPath, "/input/aim");
566+
const bool isPalmPose =
567+
endsWith(fullPath, "/input/palm_ext/pose") || endsWith(fullPath, "/input/palm_ext");
568+
const int side = getActionSide(fullPath);
569+
if ((isGripPose || isAimPose || isPalmPose) && side >= 0) {
570+
result = getControllerPose(side, time, pose, velocity);
571+
572+
// Apply the pose offsets.
573+
if (isAimPose) {
574+
// Try using the hand tracking first.
575+
if (!getPinchPose(side, pose, pose)) {
576+
pose = Pose::Multiply(m_controllerAimPose[side], pose);
577+
}
578+
} else if (isGripPose) {
579+
pose = Pose::Multiply(m_controllerGripPose[side], pose);
580+
} else {
581+
pose = Pose::Multiply(m_controllerPalmPose[side], pose);
582+
}
583+
584+
// Per spec we must consistently pick one source. We pick the first one.
585+
break;
586+
}
571587
}
572588
}
573589
}

0 commit comments

Comments
 (0)