Files
flightgear/3rdparty/osgXR/src/OpenXR/Instance.cpp
T
2022-10-20 20:29:11 +08:00

406 lines
10 KiB
C++

// SPDX-License-Identifier: LGPL-2.1-only
// Copyright (C) 2021 James Hogan <james@albanarts.com>
#include "EventHandler.h"
#include "Instance.h"
#include "Session.h"
#include "System.h"
#include "generated/Version.h"
#include <osg/Notify>
#include <osg/Version>
#include <osg/ref_ptr>
#include <cstring>
#include <vector>
#define ENGINE_NAME "osgXR"
#define ENGINE_VERSION (OSGXR_MAJOR_VERSION << 16 | \
OSGXR_MINOR_VERSION << 8 | \
OSGXR_PATCH_VERSION)
#define API_VERSION XR_MAKE_VERSION(1, 0, 0)
using namespace osgXR::OpenXR;
static std::vector<XrApiLayerProperties> layers;
static std::vector<XrExtensionProperties> extensions;
static bool enumerateLayers(bool invalidate = false)
{
static bool layersEnumerated = false;
if (invalidate)
{
layers.resize(0);
layersEnumerated = false;
return false;
}
if (layersEnumerated)
{
return true;
}
// Count layers
uint32_t layerCount = 0;
XrResult res = xrEnumerateApiLayerProperties(0, &layerCount, nullptr);
if (XR_FAILED(res))
{
OSG_WARN << "Failed to count OpenXR API layers: " << res << std::endl;
return false;
}
if (layerCount)
{
// Allocate memory
layers.resize(layerCount);
for (auto &layer: layers)
{
layer.type = XR_TYPE_API_LAYER_PROPERTIES;
layer.next = nullptr;
}
// Enumerate layers
res = xrEnumerateApiLayerProperties(layers.size(), &layerCount, layers.data());
if (XR_FAILED(res))
{
OSG_WARN << "Failed to enumerate " << layerCount
<< " OpenXR API layers: " << res << std::endl;
return false;
}
// Layers may change at any time
layers.resize(layerCount);
}
layersEnumerated = true;
return true;
}
static bool enumerateExtensions(bool invalidate = false)
{
static bool extensionsEnumerated = false;
if (invalidate)
{
extensions.resize(0);
extensionsEnumerated = false;
return false;
}
if (extensionsEnumerated)
{
return true;
}
// Count extensions
uint32_t extensionCount;
XrResult res = xrEnumerateInstanceExtensionProperties(nullptr, 0, &extensionCount, nullptr);
if (XR_FAILED(res))
{
OSG_WARN << "Failed to count OpenXR instance extensions: " << res << std::endl;
return false;
}
if (extensionCount)
{
// Allocate memory
extensions.resize(extensionCount);
for (auto &extension: extensions)
{
extension.type = XR_TYPE_EXTENSION_PROPERTIES;
extension.next = nullptr;
}
// Enumerate extensions
res = xrEnumerateInstanceExtensionProperties(nullptr, extensions.size(),
&extensionCount, extensions.data());
if (XR_FAILED(res))
{
OSG_WARN << "Failed to enumerate " << extensionCount
<< " OpenXR instance extensions: " << res << std::endl;
return false;
}
// Extensions may change (?)
extensions.resize(extensionCount);
}
extensionsEnumerated = true;
return true;
}
void Instance::invalidateLayers()
{
enumerateLayers(true);
}
void Instance::invalidateExtensions()
{
enumerateExtensions(true);
}
bool Instance::hasLayer(const char *name)
{
enumerateLayers();
for (auto &layer: layers)
{
if (!strncmp(name, layer.layerName, XR_MAX_API_LAYER_NAME_SIZE))
{
return true;
}
}
return false;
}
bool Instance::hasExtension(const char *name)
{
enumerateExtensions();
for (auto &extension: extensions)
{
if (!strncmp(name, extension.extensionName, XR_MAX_EXTENSION_NAME_SIZE))
{
return true;
}
}
return false;
}
Instance *Instance::instance()
{
static osg::ref_ptr<Instance> s_instance = new Instance();
return s_instance;
}
Instance::Instance():
_layerValidation(false),
_depthInfo(false),
_visibilityMask(true),
_instance(XR_NULL_HANDLE),
_lost(false)
{
}
Instance::~Instance()
{
if (_instance != XR_NULL_HANDLE)
{
// Delete the systems
for (System *system: _systems)
{
delete system;
}
// Destroy the OpenXR instance
XrResult res = xrDestroyInstance(_instance);
if (XR_FAILED(res))
{
OSG_WARN << "Failed to destroy OpenXR instance" << std::endl;
}
}
}
Instance::InitResult Instance::init(const char *appName, uint32_t appVersion)
{
if (_instance != XR_NULL_HANDLE)
{
return INIT_SUCCESS;
}
std::vector<const char *> layerNames;
std::vector<const char *> extensionNames;
// Enable validation layer if selected
if (_layerValidation && hasLayer(XR_APILAYER_LUNARG_core_validation))
{
layerNames.push_back(XR_APILAYER_LUNARG_core_validation);
}
// We need OpenGL support
if (!hasExtension(XR_KHR_OPENGL_ENABLE_EXTENSION_NAME))
{
OSG_WARN << "OpenXR runtime doesn't support XR_KHR_opengl_enable extension" << std::endl;
return INIT_FAIL;
}
extensionNames.push_back(XR_KHR_OPENGL_ENABLE_EXTENSION_NAME);
// Enable depth composition layer support if supported
_supportsCompositionLayerDepth = hasExtension(XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME);
if (_depthInfo)
{
if (_supportsCompositionLayerDepth)
extensionNames.push_back(XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME);
else
_depthInfo = false;
}
// Enable visibility mask support if supported
_supportsVisibilityMask = hasExtension(XR_KHR_VISIBILITY_MASK_EXTENSION_NAME);
if (_visibilityMask)
{
if (_supportsVisibilityMask)
extensionNames.push_back(XR_KHR_VISIBILITY_MASK_EXTENSION_NAME);
else
_visibilityMask = false;
}
// Create the instance
XrInstanceCreateInfo info{ XR_TYPE_INSTANCE_CREATE_INFO };
strncpy(info.applicationInfo.applicationName, appName,
XR_MAX_APPLICATION_NAME_SIZE - 1);
info.applicationInfo.applicationVersion = appVersion;
strncpy(info.applicationInfo.engineName, ENGINE_NAME,
XR_MAX_ENGINE_NAME_SIZE - 1);
info.applicationInfo.engineVersion = ENGINE_VERSION;
info.applicationInfo.apiVersion = API_VERSION;
info.enabledApiLayerCount = layerNames.size();
info.enabledApiLayerNames = layerNames.data();
info.enabledExtensionCount = extensionNames.size();
info.enabledExtensionNames = extensionNames.data();
XrResult res = xrCreateInstance(&info, &_instance);
if (XR_FAILED(res))
{
OSG_WARN << "Failed to create OpenXR instance: " << res << std::endl;
switch (res)
{
case XR_ERROR_RUNTIME_UNAVAILABLE:
case XR_ERROR_RUNTIME_FAILURE: // Monado returns this when not running
return INIT_LATER;
default:
return INIT_FAIL;
}
}
// Log the runtime properties
_properties.type = XR_TYPE_INSTANCE_PROPERTIES;
_properties.next = nullptr;
if (XR_SUCCEEDED(xrGetInstanceProperties(_instance, &_properties)))
{
OSG_INFO << "OpenXR Runtime: \"" << _properties.runtimeName
<< "\" version " << XR_VERSION_MAJOR(_properties.runtimeVersion)
<< "." << XR_VERSION_MINOR(_properties.runtimeVersion)
<< "." << XR_VERSION_PATCH(_properties.runtimeVersion) << std::endl;
_quirks.probe(this);
}
// Get extension functions
_xrGetOpenGLGraphicsRequirementsKHR = (PFN_xrGetOpenGLGraphicsRequirementsKHR)getProcAddr("xrGetOpenGLGraphicsRequirementsKHR");
if (_visibilityMask)
_xrGetVisibilityMaskKHR = (PFN_xrGetVisibilityMaskKHR)getProcAddr("xrGetVisibilityMaskKHR");
return INIT_SUCCESS;
}
bool Instance::check(XrResult result, const char *warnMsg) const
{
if (XR_FAILED(result))
{
if (result == XR_ERROR_INSTANCE_LOST)
_lost = true;
char resultName[XR_MAX_RESULT_STRING_SIZE];
if (XR_FAILED(xrResultToString(_instance, result, resultName)))
{
OSG_WARN << warnMsg << ": " << result << std::endl;
}
else
{
OSG_WARN << warnMsg << ": " << resultName << std::endl;
}
return false;
}
return true;
}
PFN_xrVoidFunction Instance::getProcAddr(const char *name) const
{
PFN_xrVoidFunction ret = nullptr;
check(xrGetInstanceProcAddr(_instance, name, &ret),
"Failed to get OpenXR procedure address");
return ret;
}
System *Instance::getSystem(XrFormFactor formFactor, bool *supported)
{
unsigned long ffId = formFactor - 1;
if (ffId < _systems.size() && _systems[ffId])
{
if (supported)
*supported = true;
return _systems[ffId];
}
XrSystemGetInfo getInfo{ XR_TYPE_SYSTEM_GET_INFO };
getInfo.formFactor = formFactor;
XrSystemId systemId;
XrResult res = xrGetSystem(_instance, &getInfo, &systemId);
if (res == XR_ERROR_FORM_FACTOR_UNAVAILABLE)
{
// The system is only *TEMPORARILY* unavailable
if (supported)
*supported = true;
return nullptr;
}
else if (check(res, "Failed to get OpenXR system"))
{
if (ffId >= _systems.size())
_systems.resize(ffId+1, nullptr);
if (supported)
*supported = true;
return _systems[ffId] = new System(this, systemId);
}
if (supported)
*supported = false;
return nullptr;
}
void Instance::invalidateSystem(XrFormFactor formFactor)
{
unsigned long ffId = formFactor - 1;
if (ffId < _systems.size())
{
delete _systems[ffId];
_systems[ffId] = nullptr;
}
}
void Instance::registerSession(Session *session)
{
_sessions[session->getXrSession()] = session;
}
void Instance::unregisterSession(Session *session)
{
_sessions.erase(session->getXrSession());
}
Session *Instance::getSession(XrSession xrSession)
{
auto it = _sessions.find(xrSession);
if (it == _sessions.end())
return nullptr;
return (*it).second;
}
void Instance::pollEvents(EventHandler *handler)
{
for (;;)
{
XrEventDataBuffer event;
event.type = XR_TYPE_EVENT_DATA_BUFFER;
event.next = nullptr;
XrResult res = xrPollEvent(_instance, &event);
if (XR_FAILED(res))
break;
if (res == XR_EVENT_UNAVAILABLE)
break;
handler->onEvent(this, &event);
}
}