Skip to content

Commit e09a8cc

Browse files
committed
Don't check if required extensions are available, just try to enable them
If unavailable, should fail with XR_ERROR_EXTENSION_NOT_PRESENT, which can then be handled, and retried. We can't actually reliably check if it's available by any other mechanism given the varied quality of implementations of xrEnumerateInstanceExtensionProperties, and the current spec wording - KhronosGroup/OpenXR-SDK-Source#490
1 parent db7456a commit e09a8cc

File tree

7 files changed

+747
-860
lines changed

7 files changed

+747
-860
lines changed

src/APILayer/APILayer_loader.cpp

Lines changed: 75 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -320,82 +320,6 @@ static XrResult xrGetInstanceProcAddr(
320320
return XR_ERROR_FUNCTION_UNSUPPORTED;
321321
}
322322

323-
static void EnumerateExtensions(OpenXRNext* oxr) {
324-
uint32_t extensionCount = 0;
325-
326-
auto nextResult = oxr->xrEnumerateInstanceExtensionProperties(
327-
nullptr, 0, &extensionCount, nullptr);
328-
329-
// Workaround for Meta Link PTC as of 2024-07-22:
330-
//
331-
// XR_ERROR_SIZE_SUFFICIENT should *never* be returned for a buffer size of 0:
332-
// https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#buffer-size-parameters
333-
const auto workAroundNonConformantImplementations
334-
= Config::Quirk_Conformance_ExtensionCount
335-
&& (nextResult == XR_ERROR_SIZE_INSUFFICIENT) && (extensionCount > 0);
336-
if (workAroundNonConformantImplementations) {
337-
DebugPrint(
338-
"Buggy OpenXR runtime or other API layer; ignoring incorrect "
339-
"XR_ERROR_SIZE_INSUFFICIENT response from "
340-
"xrEnumerateInstanceExtensionProperties(nulllptr, 0, &count, nullptr)");
341-
}
342-
if (nextResult != XR_SUCCESS && !workAroundNonConformantImplementations) {
343-
DebugPrint("Getting extension count failed: {}", nextResult);
344-
return;
345-
}
346-
347-
if (extensionCount == 0) {
348-
DebugPrint(
349-
"Runtime supports no extensions, so definitely doesn't support hand "
350-
"tracking. Reporting success but doing nothing.");
351-
return;
352-
}
353-
354-
std::vector<XrExtensionProperties> extensions(
355-
extensionCount, XrExtensionProperties {XR_TYPE_EXTENSION_PROPERTIES});
356-
nextResult = oxr->xrEnumerateInstanceExtensionProperties(
357-
nullptr, extensionCount, &extensionCount, extensions.data());
358-
if (nextResult != XR_SUCCESS) {
359-
DebugPrint("Enumerating extensions failed: {}", nextResult);
360-
return;
361-
}
362-
363-
for (const auto& it: extensions) {
364-
const std::string_view name {it.extensionName};
365-
if (Config::VerboseDebug) {
366-
DebugPrint("Found {}", name);
367-
}
368-
369-
if (name == XR_EXT_HAND_TRACKING_EXTENSION_NAME) {
370-
Environment::Have_XR_EXT_HandTracking = true;
371-
continue;
372-
}
373-
if (
374-
name == XR_FB_HAND_TRACKING_AIM_EXTENSION_NAME
375-
&& Config::EnableFBOpenXRExtensions) {
376-
Environment::Have_XR_FB_HandTracking_Aim = true;
377-
continue;
378-
}
379-
if (name == XR_KHR_WIN32_CONVERT_PERFORMANCE_COUNTER_TIME_EXTENSION_NAME) {
380-
Environment::Have_XR_KHR_win32_convert_performance_counter_time = true;
381-
continue;
382-
}
383-
}
384-
385-
DebugPrint(
386-
"{}: {}",
387-
XR_EXT_HAND_TRACKING_EXTENSION_NAME,
388-
Environment::Have_XR_EXT_HandTracking);
389-
DebugPrint(
390-
"{}: {}",
391-
XR_FB_HAND_TRACKING_AIM_EXTENSION_NAME,
392-
Environment::Have_XR_FB_HandTracking_Aim);
393-
DebugPrint(
394-
"{}: {}",
395-
XR_KHR_WIN32_CONVERT_PERFORMANCE_COUNTER_TIME_EXTENSION_NAME,
396-
Environment::Have_XR_KHR_win32_convert_performance_counter_time);
397-
}
398-
399323
static XrResult xrCreateApiLayerInstance(
400324
const XrInstanceCreateInfo* originalInfo,
401325
const struct XrApiLayerCreateInfo* layerInfo,
@@ -414,97 +338,97 @@ static XrResult xrCreateApiLayerInstance(
414338

415339
// TODO: check version fields etc in layerInfo
416340

417-
XrInstance dummyInstance {};
418-
{
419-
// While the OpenXR specification says that
420-
// `xrEnumerateInstanceExtensionProperties()` does not require an
421-
// `XrInstance`, if there is a 'next' API layer, it will not be able to
422-
// retrieve the extension list from the runtime or an n+2 API layer unless
423-
// an instance has been created, as it won't have the next
424-
// `xrGetInstanceProcAddr()` pointer yet.
425-
XrInstanceCreateInfo dummyInfo {
426-
.type = XR_TYPE_INSTANCE_CREATE_INFO,
427-
.applicationInfo = {
428-
.applicationVersion = originalInfo->applicationInfo.applicationVersion,
429-
.engineName = "FREDEMMOTT_HTCC",
430-
.engineVersion = 1,
431-
.apiVersion = XR_CURRENT_API_VERSION,
432-
},
433-
};
434-
{
435-
auto [it, count] = std::format_to_n(
436-
dummyInfo.applicationInfo.applicationName,
437-
XR_MAX_APPLICATION_NAME_SIZE - 1,
438-
"FREDEMMOTT_HTCC Init: {}",
439-
originalInfo->applicationInfo.applicationName);
440-
*it = '\0';
441-
}
442-
auto dummyLayerInfo = *layerInfo;
443-
dummyLayerInfo.nextInfo = dummyLayerInfo.nextInfo->next;
444-
layerInfo->nextInfo->nextCreateApiLayerInstance(
445-
&dummyInfo, &dummyLayerInfo, &dummyInstance);
446-
}
447-
448-
OpenXRNext next(dummyInstance, layerInfo->nextInfo->nextGetInstanceProcAddr);
449-
450341
XrInstanceCreateInfo info {XR_TYPE_INSTANCE_CREATE_INFO};
451342
if (originalInfo) {
452343
info = *originalInfo;
453344
}
454345

455346
std::vector<const char*> enabledExtensions;
456347
if (Config::Enabled) {
457-
EnumerateExtensions(&next);
458-
if (Environment::Have_XR_EXT_HandTracking) {
459-
DebugPrint("Original extensions:");
460-
for (auto i = 0; i < originalInfo->enabledExtensionCount; ++i) {
461-
DebugPrint("- {}", originalInfo->enabledExtensionNames[i]);
462-
enabledExtensions.push_back(originalInfo->enabledExtensionNames[i]);
463-
}
464-
465-
enabledExtensions.push_back(XR_EXT_HAND_TRACKING_EXTENSION_NAME);
466-
// We need 'real time' units to rotate the hand at a known speed for
467-
// MSFS
468-
if (Environment::Have_XR_KHR_win32_convert_performance_counter_time) {
469-
enabledExtensions.push_back(
470-
XR_KHR_WIN32_CONVERT_PERFORMANCE_COUNTER_TIME_EXTENSION_NAME);
471-
}
472-
// Required for enhanced pinch gestures on Quest
473-
if (Environment::Have_XR_FB_HandTracking_Aim) {
474-
enabledExtensions.push_back(XR_FB_HAND_TRACKING_AIM_EXTENSION_NAME);
475-
}
476-
477-
{
478-
auto last
479-
= std::unique(enabledExtensions.begin(), enabledExtensions.end());
480-
enabledExtensions.erase(last, enabledExtensions.end());
481-
}
482-
483-
DebugPrint("Requesting extensions:");
484-
for (const auto& ext: enabledExtensions) {
485-
DebugPrint("- {}", ext);
486-
}
487-
488-
info.enabledExtensionCount = enabledExtensions.size();
489-
info.enabledExtensionNames = enabledExtensions.data();
348+
DebugPrint("Original extensions:");
349+
for (auto i = 0; i < originalInfo->enabledExtensionCount; ++i) {
350+
DebugPrint("- {}", originalInfo->enabledExtensionNames[i]);
351+
enabledExtensions.push_back(originalInfo->enabledExtensionNames[i]);
352+
}
353+
354+
enabledExtensions.push_back(
355+
XR_KHR_WIN32_CONVERT_PERFORMANCE_COUNTER_TIME_EXTENSION_NAME);
356+
enabledExtensions.push_back(XR_EXT_HAND_TRACKING_EXTENSION_NAME);
357+
enabledExtensions.push_back(XR_FB_HAND_TRACKING_AIM_EXTENSION_NAME);
358+
359+
{
360+
auto last
361+
= std::unique(enabledExtensions.begin(), enabledExtensions.end());
362+
enabledExtensions.erase(last, enabledExtensions.end());
490363
}
364+
365+
DebugPrint("Requesting extensions:");
366+
for (const auto& ext: enabledExtensions) {
367+
DebugPrint("- {}", ext);
368+
}
369+
370+
info.enabledExtensionCount = enabledExtensions.size();
371+
info.enabledExtensionNames = enabledExtensions.data();
491372
}
492-
next.check_xrDestroyInstance(dummyInstance);
493373

494374
XrApiLayerCreateInfo nextLayerInfo = *layerInfo;
495375
nextLayerInfo.nextInfo = layerInfo->nextInfo->next;
496376

497-
auto nextResult = layerInfo->nextInfo->nextCreateApiLayerInstance(
498-
&info, &nextLayerInfo, instance);
499-
if (nextResult != XR_SUCCESS) {
500-
DebugPrint("Next failed.");
501-
return nextResult;
377+
//// Attempt 1: all 3 extensions
378+
{
379+
const auto nextResult = layerInfo->nextInfo->nextCreateApiLayerInstance(
380+
&info, &nextLayerInfo, instance);
381+
if (XR_SUCCEEDED(nextResult)) {
382+
Environment::Have_XR_EXT_HandTracking = true;
383+
Environment::Have_XR_FB_HandTracking_Aim = true;
384+
gNext = std::make_shared<OpenXRNext>(
385+
*instance, layerInfo->nextInfo->nextGetInstanceProcAddr);
386+
DebugPrint("Initialized with all extensions");
387+
return nextResult;
388+
}
389+
390+
if (nextResult != XR_ERROR_EXTENSION_NOT_PRESENT) {
391+
DebugPrint("all-in xrCreateApiLayerInstance failed: {}", nextResult);
392+
return nextResult;
393+
}
502394
}
503395

504-
gNext = std::make_shared<OpenXRNext>(
505-
*instance, layerInfo->nextInfo->nextGetInstanceProcAddr);
396+
///// Attempt 2: without XR_FB_hand_tracking_aim
397+
enabledExtensions.erase(
398+
std::ranges::find(
399+
enabledExtensions, XR_FB_HAND_TRACKING_AIM_EXTENSION_NAME));
400+
info.enabledExtensionCount = enabledExtensions.size();
401+
info.enabledExtensionNames = enabledExtensions.data();
402+
{
403+
const auto nextResult = layerInfo->nextInfo->nextCreateApiLayerInstance(
404+
&info, &nextLayerInfo, instance);
405+
if (XR_SUCCEEDED(nextResult)) {
406+
Environment::Have_XR_EXT_HandTracking = true;
407+
Environment::Have_XR_FB_HandTracking_Aim = false;
408+
gNext = std::make_shared<OpenXRNext>(
409+
*instance, layerInfo->nextInfo->nextGetInstanceProcAddr);
410+
DebugPrint(
411+
"Initialized without {}", XR_FB_HAND_TRACKING_AIM_EXTENSION_NAME);
412+
return nextResult;
413+
}
414+
415+
if (nextResult != XR_ERROR_EXTENSION_NOT_PRESENT) {
416+
DebugPrint(
417+
"bare-minimum xrCreateApiLayerInstance failed: {}", nextResult);
418+
return nextResult;
419+
}
420+
}
506421

507-
return XR_SUCCESS;
422+
///// Attempt 3: nope, no hand tracking. Just pass through.
423+
const auto nextResult = layerInfo->nextInfo->nextCreateApiLayerInstance(
424+
originalInfo, &nextLayerInfo, instance);
425+
if (XR_SUCCEEDED(nextResult)) {
426+
DebugPrint("No-op passthrough xrCreateAPILayerInstance succeeded");
427+
} else {
428+
DebugPrint(
429+
"No-op passthrough xrCreateApiLayerInstance failed: {}", nextResult);
430+
}
431+
return nextResult;
508432
}
509433

510434
}// namespace HandTrackedCockpitClicking::Loader

src/APILayer/VirtualControllerSink.cpp

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -92,18 +92,7 @@ VirtualControllerSink::VirtualControllerSink(
9292
}
9393

9494
bool VirtualControllerSink::IsPointerSink() {
95-
if (Config::PointerSink == PointerSink::VirtualVRController) {
96-
if (!Environment::Have_XR_KHR_win32_convert_performance_counter_time) {
97-
// This should pretty much never happen: every runtime supports this
98-
// extension
99-
DebugPrint(
100-
"Configured to use VirtualControllerSink, but don't have {}",
101-
XR_KHR_WIN32_CONVERT_PERFORMANCE_COUNTER_TIME_EXTENSION_NAME);
102-
return false;
103-
}
104-
return true;
105-
}
106-
return false;
95+
return Config::PointerSink == PointerSink::VirtualVRController;
10796
}
10897

10998
static bool IsActionSink(ActionSink actionSink) {

0 commit comments

Comments
 (0)