2020-06-24 20:22:09 +00:00
# include "openxrswapchainimpl.hpp"
2020-10-17 19:11:31 +00:00
# include "openxrdebug.hpp"
2020-06-24 20:22:09 +00:00
# include "vrenvironment.hpp"
2020-06-28 09:33:01 +00:00
# include "vrframebuffer.hpp"
2020-06-24 20:22:09 +00:00
# include <components/debug/debuglog.hpp>
2020-10-30 23:29:24 +00:00
# ifdef _WIN32
2020-06-24 20:22:09 +00:00
# include <Windows.h>
2020-10-17 10:33:46 +00:00
# include <objbase.h>
2020-06-24 20:22:09 +00:00
2020-10-30 23:29:24 +00:00
# elif __linux__
# include <X11/Xlib.h>
# include <GL/glx.h>
# undef None
# else
# error Unsupported platform
# endif
2020-06-24 20:22:09 +00:00
# include <openxr/openxr.h>
# include <openxr/openxr_platform.h>
# include <openxr/openxr_platform_defines.h>
# include <openxr/openxr_reflection.h>
namespace MWVR {
OpenXRSwapchainImpl : : OpenXRSwapchainImpl ( osg : : ref_ptr < osg : : State > state , SwapchainConfig config )
2020-11-22 14:23:11 +00:00
: mConfig ( config )
2020-06-24 20:22:09 +00:00
{
2020-11-22 14:23:11 +00:00
if ( mConfig . selectedWidth < = 0 )
2020-06-24 20:22:09 +00:00
throw std : : invalid_argument ( " Width must be a positive integer " ) ;
2020-11-22 14:23:11 +00:00
if ( mConfig . selectedHeight < = 0 )
2020-06-24 20:22:09 +00:00
throw std : : invalid_argument ( " Height must be a positive integer " ) ;
2020-11-22 14:23:11 +00:00
if ( mConfig . selectedSamples < = 0 )
2020-06-24 20:22:09 +00:00
throw std : : invalid_argument ( " Samples must be a positive integer " ) ;
2020-11-22 14:23:11 +00:00
mSwapchain . reset ( new SwapchainPrivate ( state , mConfig , SwapchainPrivate : : Use : : COLOR ) ) ;
mConfig . selectedSamples = mSwapchain - > samples ( ) ;
auto * xr = Environment : : get ( ) . getManager ( ) ;
if ( xr - > xrExtensionIsEnabled ( XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME ) )
{
try
{
mSwapchainDepth . reset ( new SwapchainPrivate ( state , mConfig , SwapchainPrivate : : Use : : DEPTH ) ) ;
}
catch ( std : : exception & e )
{
Log ( Debug : : Warning ) < < " XR_KHR_composition_layer_depth was enabled but creating depth swapchain failed: " < < e . what ( ) ;
mSwapchainDepth = nullptr ;
}
}
uint32_t imageCount = mSwapchain - > count ( ) ;
for ( uint32_t i = 0 ; i < imageCount ; i + + )
{
uint32_t colorBuffer = mSwapchain - > bufferAt ( i ) ;
uint32_t depthBuffer = mSwapchainDepth ? mSwapchainDepth - > bufferAt ( i ) : 0 ;
mRenderBuffers . emplace_back ( new VRFramebuffer ( state , mSwapchain - > width ( ) , mSwapchain - > height ( ) , mSwapchain - > samples ( ) , colorBuffer , depthBuffer ) ) ;
}
}
OpenXRSwapchainImpl : : ~ OpenXRSwapchainImpl ( )
{
}
VRFramebuffer * OpenXRSwapchainImpl : : renderBuffer ( ) const
{
checkAcquired ( ) ;
// Note that I am trusting that the openxr runtime won't diverge the indexes of the depth and color swapchains so long as these are always acquired together.
// If some dumb ass implementation decides to violate this we'll just have to work around that if it actually happens.
return mRenderBuffers [ mSwapchain - > acuiredIndex ( ) ] . get ( ) ;
}
uint32_t OpenXRSwapchainImpl : : acquiredColorTexture ( ) const
{
checkAcquired ( ) ;
return mSwapchain - > acuiredBuffer ( ) ;
}
uint32_t OpenXRSwapchainImpl : : acquiredDepthTexture ( ) const
{
if ( mSwapchainDepth )
{
checkAcquired ( ) ;
return mSwapchainDepth - > acuiredBuffer ( ) ;
}
return 0 ;
}
bool OpenXRSwapchainImpl : : isAcquired ( ) const
{
return mFormallyAcquired ;
}
void OpenXRSwapchainImpl : : beginFrame ( osg : : GraphicsContext * gc )
{
acquire ( ) ;
renderBuffer ( ) - > bindFramebuffer ( gc , GL_FRAMEBUFFER_EXT ) ;
}
int swapCount = 0 ;
void OpenXRSwapchainImpl : : endFrame ( osg : : GraphicsContext * gc )
{
checkAcquired ( ) ;
release ( ) ;
}
void OpenXRSwapchainImpl : : acquire ( )
{
if ( isAcquired ( ) )
throw std : : logic_error ( " Trying to acquire already acquired swapchain " ) ;
if ( ! mShouldRelease )
{
mSwapchain - > acquire ( ) ;
mShouldRelease = mSwapchain - > isAcquired ( ) ;
if ( mSwapchainDepth & & mSwapchain - > isAcquired ( ) )
{
mSwapchainDepth - > acquire ( ) ;
mShouldRelease = mSwapchainDepth - > isAcquired ( ) ;
}
}
mFormallyAcquired = true ;
}
void OpenXRSwapchainImpl : : release ( )
{
if ( mShouldRelease )
{
mSwapchain - > release ( ) ;
mShouldRelease = mSwapchain - > isAcquired ( ) ;
if ( mSwapchainDepth )
{
mSwapchainDepth - > release ( ) ;
mShouldRelease = mSwapchainDepth - > isAcquired ( ) ;
}
}
mFormallyAcquired = false ;
}
void OpenXRSwapchainImpl : : checkAcquired ( ) const
{
if ( ! isAcquired ( ) )
throw std : : logic_error ( " Swapchain must be acquired before use. Call between OpenXRSwapchain::beginFrame() and OpenXRSwapchain::endFrame() " ) ;
}
2020-12-06 11:03:34 +00:00
static int64_t selectFormat ( const std : : vector < int64_t > & eligibleFormats , const std : : vector < int64_t > & requestedFormats )
{
auto it =
std : : find_first_of ( std : : begin ( requestedFormats ) , std : : end ( requestedFormats ) ,
eligibleFormats . begin ( ) , eligibleFormats . end ( ) ) ;
if ( it = = std : : end ( requestedFormats ) )
{
return 0 ;
}
return * it ;
}
static int64_t selectColorFormat ( const std : : vector < int64_t > & eligibleFormats )
{
// Find supported color swapchain format.
std : : vector < int64_t > requestedColorSwapchainFormats = {
0x8058 , // GL_RGBA8
0x8F97 , // GL_RGBA8_SNORM
0x881A , // GL_RGBA16F
0x881B , // GL_RGB16F
// Offered by SteamVR but is broken: // 0x805B, // GL_RGBA16
0x8C3A , // GL_R11F_G11F_B10F
// We manage gamma ourselves: 0x8C43, // GL_SRGB8_ALPHA8
// We manage gamma ourselves: 0x8C41, // GL_SRGB8
} ;
return selectFormat ( eligibleFormats , requestedColorSwapchainFormats ) ;
}
static int64_t selectDepthFormat ( const std : : vector < int64_t > & eligibleFormats )
{
// Find supported depth swapchain format.
std : : vector < int64_t > requestedDepthSwapchainFormats = {
0x81A6 , // GL_DEPTH_COMPONENT24
0x88F0 , // GL_DEPTH24_STENCIL8
0x8CAC , // GL_DEPTH_COMPONENT32F
0x81A7 , // GL_DEPTH_COMPONENT32
0x8DAB , // GL_DEPTH_COMPONENT32F_NV
0x8CAD , // GL_DEPTH32_STENCIL8
// Need 32bit minimum: // 0x81A5, // GL_DEPTH_COMPONENT16
} ;
return selectFormat ( eligibleFormats , requestedDepthSwapchainFormats ) ;
}
2020-11-22 14:23:11 +00:00
OpenXRSwapchainImpl : : SwapchainPrivate : : SwapchainPrivate ( osg : : ref_ptr < osg : : State > state , SwapchainConfig config , Use use )
: mBuffers ( )
, mWidth ( config . selectedWidth )
, mHeight ( config . selectedHeight )
, mSamples ( config . selectedSamples )
{
2020-06-24 20:22:09 +00:00
auto * xr = Environment : : get ( ) . getManager ( ) ;
// Select a swapchain format.
uint32_t swapchainFormatCount ;
CHECK_XRCMD ( xrEnumerateSwapchainFormats ( xr - > impl ( ) . xrSession ( ) , 0 , & swapchainFormatCount , nullptr ) ) ;
std : : vector < int64_t > swapchainFormats ( swapchainFormatCount ) ;
CHECK_XRCMD ( xrEnumerateSwapchainFormats ( xr - > impl ( ) . xrSession ( ) , ( uint32_t ) swapchainFormats . size ( ) , & swapchainFormatCount , swapchainFormats . data ( ) ) ) ;
2020-12-06 11:03:34 +00:00
if ( use = = Use : : COLOR )
mFormat = selectColorFormat ( swapchainFormats ) ;
else
mFormat = selectDepthFormat ( swapchainFormats ) ;
2020-11-22 14:23:11 +00:00
std : : string typeString = use = = Use : : COLOR ? " color " : " depth " ;
2020-12-06 11:03:34 +00:00
if ( mFormat = = 0 ) {
2020-11-22 14:23:11 +00:00
throw std : : runtime_error ( std : : string ( " Swapchain " ) + typeString + " format not supported " ) ;
2020-06-24 20:22:09 +00:00
}
2020-11-22 14:23:11 +00:00
Log ( Debug : : Verbose ) < < " Selected " < < typeString < < " format: " < < std : : dec < < mFormat < < " ( " < < std : : hex < < mFormat < < " ) " < < std : : dec ;
2020-06-24 20:22:09 +00:00
2020-08-02 10:34:46 +00:00
if ( xr - > xrExtensionIsEnabled ( XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME ) )
{
2020-11-22 14:23:11 +00:00
// TODO
2020-06-26 21:02:48 +00:00
}
2020-08-02 10:34:46 +00:00
XrSwapchainCreateInfo swapchainCreateInfo { XR_TYPE_SWAPCHAIN_CREATE_INFO } ;
swapchainCreateInfo . arraySize = 1 ;
swapchainCreateInfo . width = mWidth ;
swapchainCreateInfo . height = mHeight ;
swapchainCreateInfo . mipCount = 1 ;
swapchainCreateInfo . faceCount = 1 ;
while ( mSamples > 0 & & mSwapchain = = XR_NULL_HANDLE )
2020-06-24 20:22:09 +00:00
{
Log ( Debug : : Verbose ) < < " Creating swapchain with dimensions Width= " < < mWidth < < " Heigh= " < < mHeight < < " SampleCount= " < < mSamples ;
2020-06-26 21:02:48 +00:00
// First create the swapchain of color buffers.
2020-11-22 14:23:11 +00:00
swapchainCreateInfo . format = mFormat ;
2020-06-26 21:02:48 +00:00
swapchainCreateInfo . sampleCount = mSamples ;
2020-06-24 20:22:09 +00:00
swapchainCreateInfo . usageFlags = XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT ;
auto res = xrCreateSwapchain ( xr - > impl ( ) . xrSession ( ) , & swapchainCreateInfo , & mSwapchain ) ;
2020-06-26 21:02:48 +00:00
if ( ! XR_SUCCEEDED ( res ) )
2020-06-24 20:22:09 +00:00
{
Log ( Debug : : Verbose ) < < " Failed to create swapchain with SampleCount= " < < mSamples < < " : " < < XrResultString ( res ) ;
mSamples / = 2 ;
2020-06-26 21:02:48 +00:00
if ( mSamples = = 0 )
throw std : : runtime_error ( XrResultString ( res ) ) ;
continue ;
2020-06-24 20:22:09 +00:00
}
2020-10-17 19:11:31 +00:00
VrDebug : : setName ( mSwapchain , " OpenMW XR Color Swapchain " + config . name ) ;
2020-06-24 20:22:09 +00:00
}
uint32_t imageCount = 0 ;
CHECK_XRCMD ( xrEnumerateSwapchainImages ( mSwapchain , 0 , & imageCount , nullptr ) ) ;
2020-11-22 14:23:11 +00:00
mBuffers . resize ( imageCount , { XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR } ) ;
CHECK_XRCMD ( xrEnumerateSwapchainImages ( mSwapchain , imageCount , & imageCount , reinterpret_cast < XrSwapchainImageBaseHeader * > ( mBuffers . data ( ) ) ) ) ;
2020-06-24 20:22:09 +00:00
mSubImage . swapchain = mSwapchain ;
mSubImage . imageRect . offset = { 0 , 0 } ;
mSubImage . imageRect . extent = { mWidth , mHeight } ;
}
2020-11-22 14:23:11 +00:00
OpenXRSwapchainImpl : : SwapchainPrivate : : ~ SwapchainPrivate ( )
2020-06-24 20:22:09 +00:00
{
if ( mSwapchain )
CHECK_XRCMD ( xrDestroySwapchain ( mSwapchain ) ) ;
}
2020-11-22 14:23:11 +00:00
uint32_t OpenXRSwapchainImpl : : SwapchainPrivate : : bufferAt ( uint32_t index ) const
2020-06-24 20:22:09 +00:00
{
2020-11-22 14:23:11 +00:00
return mBuffers [ index ] . image ;
2020-06-24 20:22:09 +00:00
}
2020-11-22 14:23:11 +00:00
uint32_t OpenXRSwapchainImpl : : SwapchainPrivate : : count ( ) const
2020-06-24 20:22:09 +00:00
{
2020-11-22 14:23:11 +00:00
return mBuffers . size ( ) ;
2020-06-28 09:33:01 +00:00
}
2020-11-22 14:23:11 +00:00
uint32_t OpenXRSwapchainImpl : : SwapchainPrivate : : acuiredBuffer ( ) const
2020-06-28 09:33:01 +00:00
{
checkAcquired ( ) ;
2020-11-22 14:23:11 +00:00
return mBuffers [ mAcquiredIndex ] . image ;
2020-06-24 20:22:09 +00:00
}
2020-11-22 14:23:11 +00:00
bool OpenXRSwapchainImpl : : SwapchainPrivate : : isAcquired ( ) const
2020-06-24 20:22:09 +00:00
{
2020-11-22 14:23:11 +00:00
return mIsReady ;
2020-06-24 20:22:09 +00:00
}
2020-11-22 14:23:11 +00:00
void OpenXRSwapchainImpl : : SwapchainPrivate : : acquire ( )
2020-06-24 20:22:09 +00:00
{
2020-07-21 10:28:39 +00:00
auto xr = Environment : : get ( ) . getManager ( ) ;
2020-06-24 20:22:09 +00:00
XrSwapchainImageAcquireInfo acquireInfo { XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO } ;
2020-08-02 10:34:46 +00:00
XrSwapchainImageWaitInfo waitInfo { XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO } ;
waitInfo . timeout = XR_INFINITE_DURATION ;
2020-11-22 14:23:11 +00:00
if ( ! mIsIndexAcquired )
2020-08-02 10:34:46 +00:00
{
2020-11-22 14:23:11 +00:00
mIsIndexAcquired = XR_SUCCEEDED ( CHECK_XRCMD ( xrAcquireSwapchainImage ( mSwapchain , & acquireInfo , & mAcquiredIndex ) ) ) ;
if ( mIsIndexAcquired )
xr - > xrResourceAcquired ( ) ;
}
if ( mIsIndexAcquired & & ! mIsReady )
{
mIsReady = XR_SUCCEEDED ( CHECK_XRCMD ( xrWaitSwapchainImage ( mSwapchain , & waitInfo ) ) ) ;
2020-08-02 10:34:46 +00:00
}
2020-06-24 20:22:09 +00:00
}
2020-11-22 14:23:11 +00:00
void OpenXRSwapchainImpl : : SwapchainPrivate : : release ( )
2020-06-24 20:22:09 +00:00
{
2020-07-21 10:28:39 +00:00
auto xr = Environment : : get ( ) . getManager ( ) ;
2020-06-24 20:22:09 +00:00
XrSwapchainImageReleaseInfo releaseInfo { XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO } ;
2020-11-22 14:23:11 +00:00
if ( mIsReady )
2020-08-02 10:34:46 +00:00
{
2020-11-22 14:23:11 +00:00
mIsReady = ! XR_SUCCEEDED ( CHECK_XRCMD ( xrReleaseSwapchainImage ( mSwapchain , & releaseInfo ) ) ) ;
if ( ! mIsReady )
{
mIsIndexAcquired = false ;
xr - > xrResourceReleased ( ) ;
}
2020-08-02 10:34:46 +00:00
}
2020-06-24 20:22:09 +00:00
}
2020-11-22 14:23:11 +00:00
void OpenXRSwapchainImpl : : SwapchainPrivate : : checkAcquired ( ) const
2020-06-28 09:33:01 +00:00
{
if ( ! isAcquired ( ) )
throw std : : logic_error ( " Swapchain must be acquired before use. Call between OpenXRSwapchain::beginFrame() and OpenXRSwapchain::endFrame() " ) ;
}
2020-06-24 20:22:09 +00:00
}