Files
flightgear/3rdparty/osgXR/src/OpenXR/Session.h
2022-10-20 20:29:11 +08:00

472 lines
15 KiB
C++

// SPDX-License-Identifier: LGPL-2.1-only
// Copyright (C) 2021 James Hogan <james@albanarts.com>
#ifndef OSGXR_OPENXR_SESSION
#define OSGXR_OPENXR_SESSION 1
#include "Path.h"
#include "System.h"
#include <osg/Geometry>
#include <osg/Referenced>
#include <osg/ref_ptr>
#include <osgViewer/GraphicsWindow>
#include <OpenThreads/Mutex>
#include <set>
namespace osgXR {
namespace OpenXR {
class Action;
class ActionSet;
class CompositionLayer;
class Space;
class Session : public osg::Referenced
{
public:
// GL context must not be bound in another thread
Session(System *system, osgViewer::GraphicsWindow *window);
// GL context must not be bound in another thread
virtual ~Session();
// GL context must not be bound in another thread
void releaseGLObjects(osg::State *state = nullptr);
// Error checking
inline bool valid() const
{
return _session != XR_NULL_HANDLE;
}
inline bool check(XrResult result, const char *warnMsg) const
{
return _system->check(result, warnMsg);
}
// Action set attachment
/// Add an action set to the list.
void addActionSet(ActionSet *actionSet);
/**
* Attach the added action sets to the OpenXR session.
* @return true on success, false on failure.
*/
bool attachActionSets();
/// Get the current interaction profile for the given subaction path.
Path getCurrentInteractionProfile(const Path &subactionPath) const;
/// Get a list of bound source paths for an action.
bool getActionBoundSources(Action *action,
std::vector<XrPath> &sourcePaths) const;
/**
* Get a localized name for an input source.
* @param sourcePath Input source path.
* @param whichComponents Which components to include.
* @return Localized name string
*/
std::string getInputSourceLocalizedName(XrPath sourcePath,
XrInputSourceLocalizedNameFlags whichComponents) const;
// Action syncing
/// Activate a certain action set.
void activateActionSet(ActionSet *actionSet,
Path subactionPath = Path());
/// Deactivate a certain action set.
void deactivateActionSet(ActionSet *actionSet,
Path subactionPath = Path());
/// Sync active action sets.
bool syncActions();
/// Get the number of action sync counts that have taken place.
unsigned int getActionSyncCount() const
{
return _actionSyncCount;
}
// Accessors
// Find whether the session is ready to begin
inline bool isReady() const
{
return _state == XR_SESSION_STATE_READY;
}
// Find whether the session is running
inline bool isRunning() const
{
return _running;
}
// Find whether the session is already in the process of exiting
inline bool isExiting() const
{
return _exiting;
}
inline osgViewer::GraphicsWindow *getWindow() const
{
return _window.get();
}
// State management
inline XrSessionState getState() const
{
return _state;
}
inline void setState(XrSessionState state)
{
_state = state;
}
// Conversions
inline const osg::ref_ptr<Instance> getInstance() const
{
return _instance;
}
inline const System *getSystem() const
{
return _system;
}
inline XrInstance getXrInstance() const
{
return _system->getXrInstance();
}
inline XrSystemId getXrSystemId() const
{
return _system->getXrSystemId();
}
inline XrSession getXrSession()
{
return _session;
}
// Queries
typedef std::vector<int64_t> SwapchainFormats;
const SwapchainFormats &getSwapchainFormats() const;
Space *getLocalSpace();
XrTime getLastDisplayTime() const
{
return _lastDisplayTime;
}
void updateVisibilityMasks(XrViewConfigurationType viewConfigurationType,
uint32_t viewIndex);
osg::ref_ptr<osg::Geometry> getVisibilityMask(uint32_t viewIndex,
XrVisibilityMaskTypeKHR visibilityMaskType,
bool force = false);
// Operations
/**
* Check whether the session's GLX context is current.
* This is intended for internal use only by the functions below.
* @return whether the session's GLX context is current.
*/
bool checkCurrent() const;
/**
* Make the GLX context current.
* This makes the GLX context current to workaround broken XR runtimes.
* It should be used to ensure the context is current before XR calls
* affected by QUIRK_GL_CONTEXT_IGNORED if shouldSwitchContext()
* (because the XR runtime will fail to do so), and to restore the
* context after XR calls affected by QUIRK_GL_CONTEXT_CLEARED if
* shouldRestoreContext() or getRestoreAction() == CONTEXT_RESTORE
* (because the XR runtime will have explicitly released the context).
*/
void makeCurrent() const;
/**
* Release the GLX context so that none is current.
* This makes no GLX context current to workaround broken XR runtimes.
* It should be used release the switched context after XR calls
* affected by QUIRK_GL_CONTEXT_IGNORED if shouldSwitchContext()
* (because we had to call makeCurrent() before the call), and after XR
* calls affected by QUIRK_GL_CONTEXT_CHANGED if getRestoreAction() ==
* CONTEXT_RELEASE (because the XR runtime failed to do so).
*/
void releaseContext() const;
/// Action to perform before or after XR call due to quirks.
typedef enum ContextAction {
/// No action is necessary.
CONTEXT_IGNORE = 0,
/// The GLX context should be restored.
CONTEXT_RESTORE,
/**
* The GLX context should be released leaving no context current.
* It is assumed that no other context will need restoring in its
* place.
*/
CONTEXT_RELEASE
} ContextAction;
/**
* Find whether for an XR call affected by QUIRK_GL_CONTEXT_IGNORED it
* is necessary to switch the context prior to the XR call with
* makeCurrent(), and also release it afterwards with releaseContext.
* @return true if the context should be switched and released,
* false otherwise.
*/
bool shouldSwitchContext() const
{
return _instance->getQuirk(QUIRK_GL_CONTEXT_IGNORED) &&
!checkCurrent();
}
/**
* Find whether for an XR call affected by QUIRK_GL_CONTEXT_CLEARED it
* is necessary to restore the context after the XR call.
* @return true if the context should be restored after,
* false otherwise.
*/
bool shouldRestoreContext() const
{
return _instance->getQuirk(QUIRK_GL_CONTEXT_CLEARED) &&
checkCurrent();
}
/**
* Find what GL context action to perform after an XR call affected by
* QUIRK_GL_CONTEXT_CLEARED or QUIRK_GL_CONTEXT_CHANGED.
* @return CONTEXT_RESTORE if the runtime may clear the context and it
* will need restoring.
* CONTEXT_RELEASE if the runtime may change the context and
* fail to release it.
* CONTEXT_IGNORE otherwise.
*/
ContextAction getRestoreAction() const
{
bool cleared = _instance->getQuirk(QUIRK_GL_CONTEXT_CLEARED);
bool changed = _instance->getQuirk(QUIRK_GL_CONTEXT_CHANGED);
if (cleared || changed)
{
bool current = checkCurrent();
if (cleared && current)
return CONTEXT_RESTORE;
if (changed && !current)
return CONTEXT_RELEASE;
}
return CONTEXT_IGNORE;
}
bool begin(const System::ViewConfiguration &viewConfiguration);
void end();
void requestExit();
const System::ViewConfiguration *getViewConfiguration() const
{
return _viewConfiguration;
}
class Frame : public osg::Referenced
{
public:
Frame(osg::ref_ptr<Session> session, XrFrameState *frameState);
virtual ~Frame();
// Error checking
inline bool check(XrResult result, const char *warnMsg) const
{
return _session->check(result, warnMsg);
}
// Accessors
inline Session *getSession()
{
return _session;
}
inline bool shouldRender() const
{
return _shouldRender;
}
inline bool hasBegun() const
{
return _begun;
}
inline XrTime getTime() const
{
return _time;
}
void locateViews();
void checkLocateViews()
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_locateViewsMutex);
if (!_locatedViews)
locateViews();
}
bool isOrientationValid()
{
checkLocateViews();
return _viewState.viewStateFlags & XR_VIEW_STATE_ORIENTATION_VALID_BIT;
}
bool isPositionValid()
{
checkLocateViews();
return _viewState.viewStateFlags & XR_VIEW_STATE_POSITION_VALID_BIT;
}
bool isOrientationTracked()
{
checkLocateViews();
return _viewState.viewStateFlags & XR_VIEW_STATE_ORIENTATION_TRACKED_BIT;
}
bool isPositionTracked()
{
checkLocateViews();
return _viewState.viewStateFlags & XR_VIEW_STATE_POSITION_TRACKED_BIT;
}
uint32_t getNumViews()
{
checkLocateViews();
return _views.size();
}
const XrFovf &getViewFov(uint32_t index)
{
checkLocateViews();
return _views[index].fov;
}
const XrPosef &getViewPose(uint32_t index)
{
checkLocateViews();
return _views[index].pose;
}
// Modifiers
inline void setEnvBlendMode(XrEnvironmentBlendMode envBlendMode)
{
_envBlendMode = envBlendMode;
}
inline XrEnvironmentBlendMode getEnvBlendMode() const
{
return _envBlendMode;
}
inline void setOsgFrameNumber(unsigned int osgFrameNumber)
{
_osgFrameNumber = osgFrameNumber;
}
inline unsigned int getOsgFrameNumber() const
{
return _osgFrameNumber;
}
void addLayer(osg::ref_ptr<CompositionLayer> layer);
// Operations
bool begin();
bool end();
protected:
// Frame info
osg::ref_ptr<Session> _session;
XrTime _time;
XrDuration _period;
bool _shouldRender;
// OpenSceneGraph frame
unsigned int _osgFrameNumber;
// For access to _locatedViews etc
OpenThreads::Mutex _locateViewsMutex;
// View locations (protected by _locateViewsMutex)
bool _locatedViews;
XrViewState _viewState;
std::vector<XrView> _views;
// Frame end info
bool _begun;
XrEnvironmentBlendMode _envBlendMode;
std::vector<osg::ref_ptr<CompositionLayer> > _layers;
};
osg::ref_ptr<Frame> waitFrame();
// OpenXR extension wrappers
XrResult xrGetVisibilityMask(const System::ViewConfiguration &viewConfiguration,
uint32_t viewIndex,
XrVisibilityMaskTypeKHR visibilityMaskType,
XrVisibilityMaskKHR *visibilityMask)
{
return _instance->xrGetVisibilityMask(_session,
viewConfiguration.getType(),
viewIndex, visibilityMaskType,
visibilityMask);
}
protected:
// Init data
osg::observer_ptr<osgViewer::GraphicsWindow> _window;
// Session data
osg::ref_ptr<Instance> _instance;
const System *_system;
XrSession _session;
const System::ViewConfiguration *_viewConfiguration;
// Action sets
std::set<osg::ref_ptr<ActionSet>> _actionSets;
typedef std::pair<ActionSet *, XrPath> ActionSetSubactionPair;
std::set<ActionSetSubactionPair> _activeActionSets;
unsigned int _actionSyncCount;
// Session state
XrSessionState _state;
bool _running;
bool _exiting;
// Swapchain formats
mutable bool _readSwapchainFormats;
mutable SwapchainFormats _swapchainFormats;
// Reference spaces
osg::ref_ptr<Space> _localSpace;
XrTime _lastDisplayTime;
/*
* Visibility mask geometry cache.
* We keep visibility mask geometries cached to avoid duplication and so
* we can update them after a VisibilityMaskChangedKHR event.
*/
typedef osg::ref_ptr<osg::Geometry> VisMaskGeometry;
typedef std::vector<VisMaskGeometry> VisMaskGeometryView;
typedef std::vector<VisMaskGeometryView> VisMaskGeometries;
VisMaskGeometries _visMaskCache;
};
} // osgXR::OpenXR
} // osgXR
#endif