Merge remote-tracking branch 'remotes/origin/directx_swapchains' into openxr_vr_geometryshader_feature_branch
commit
11a3961d65
@ -0,0 +1,656 @@
|
|||||||
|
#include "openxrswapchainimage.hpp"
|
||||||
|
#include "openxrmanagerimpl.hpp"
|
||||||
|
#include "openxrplatform.hpp"
|
||||||
|
#include "vrenvironment.hpp"
|
||||||
|
|
||||||
|
// The OpenXR SDK's platform headers assume we've included platform headers
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <objbase.h>
|
||||||
|
|
||||||
|
#ifdef XR_USE_GRAPHICS_API_D3D11
|
||||||
|
#include <d3d11_1.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif __linux__
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <GL/glx.h>
|
||||||
|
#undef None
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error Unsupported platform
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <openxr/openxr.h>
|
||||||
|
#include <openxr/openxr_platform.h>
|
||||||
|
#include <openxr/openxr_platform_defines.h>
|
||||||
|
#include <openxr/openxr_reflection.h>
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <deque>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
namespace MWVR
|
||||||
|
{
|
||||||
|
|
||||||
|
XrResult CheckXrResult(XrResult res, const char* originator, const char* sourceLocation) {
|
||||||
|
static bool initialized = false;
|
||||||
|
static bool sLogAllXrCalls = false;
|
||||||
|
static bool sContinueOnErrors = false;
|
||||||
|
if (!initialized)
|
||||||
|
{
|
||||||
|
initialized = true;
|
||||||
|
sLogAllXrCalls = Settings::Manager::getBool("log all openxr calls", "VR Debug");
|
||||||
|
sContinueOnErrors = Settings::Manager::getBool("continue on errors", "VR Debug");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto resultString = XrResultString(res);
|
||||||
|
|
||||||
|
if (XR_FAILED(res)) {
|
||||||
|
std::stringstream ss;
|
||||||
|
#ifdef _WIN32
|
||||||
|
ss << sourceLocation << ": OpenXR[Error: " << resultString << "][Thread: " << std::this_thread::get_id() << "]: " << originator;
|
||||||
|
#elif __linux__
|
||||||
|
ss << sourceLocation << ": OpenXR[Error: " << resultString << "][Thread: " << std::this_thread::get_id() << "]: " << originator;
|
||||||
|
#endif
|
||||||
|
Log(Debug::Error) << ss.str();
|
||||||
|
if (res == XR_ERROR_TIME_INVALID)
|
||||||
|
Log(Debug::Error) << "Breakpoint";
|
||||||
|
if (!sContinueOnErrors)
|
||||||
|
throw std::runtime_error(ss.str().c_str());
|
||||||
|
}
|
||||||
|
else if (res != XR_SUCCESS || sLogAllXrCalls)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
Log(Debug::Verbose) << sourceLocation << ": OpenXR[" << resultString << "][" << std::this_thread::get_id() << "]: " << originator;
|
||||||
|
#elif __linux__
|
||||||
|
Log(Debug::Verbose) << sourceLocation << ": OpenXR[" << resultString << "][" << std::this_thread::get_id() << "]: " << originator;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenXRPlatform::enumerateExtensions(const char* layerName, int logIndent)
|
||||||
|
{
|
||||||
|
uint32_t extensionCount = 0;
|
||||||
|
std::vector<XrExtensionProperties> availableExtensions;
|
||||||
|
xrEnumerateInstanceExtensionProperties(layerName, 0, &extensionCount, nullptr);
|
||||||
|
availableExtensions.resize(extensionCount, XrExtensionProperties{ XR_TYPE_EXTENSION_PROPERTIES });
|
||||||
|
xrEnumerateInstanceExtensionProperties(layerName, availableExtensions.size(), &extensionCount, availableExtensions.data());
|
||||||
|
|
||||||
|
std::vector<std::string> extensionNames;
|
||||||
|
const std::string indentStr(logIndent, ' ');
|
||||||
|
for (auto& extension : availableExtensions)
|
||||||
|
{
|
||||||
|
if (layerName)
|
||||||
|
mAvailableLayerExtensions[layerName][extension.extensionName] = extension;
|
||||||
|
else
|
||||||
|
mAvailableExtensions[extension.extensionName] = extension;
|
||||||
|
|
||||||
|
Log(Debug::Verbose) << indentStr << "Name=" << extension.extensionName << " SpecVersion=" << extension.extensionVersion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct OpenXRPlatformPrivate
|
||||||
|
{
|
||||||
|
OpenXRPlatformPrivate(osg::GraphicsContext* gc);
|
||||||
|
~OpenXRPlatformPrivate();
|
||||||
|
|
||||||
|
#ifdef XR_USE_GRAPHICS_API_D3D11
|
||||||
|
typedef BOOL(WINAPI* P_wglDXSetResourceShareHandleNV)(void* dxObject, HANDLE shareHandle);
|
||||||
|
typedef HANDLE(WINAPI* P_wglDXOpenDeviceNV)(void* dxDevice);
|
||||||
|
typedef BOOL(WINAPI* P_wglDXCloseDeviceNV)(HANDLE hDevice);
|
||||||
|
typedef HANDLE(WINAPI* P_wglDXRegisterObjectNV)(HANDLE hDevice, void* dxObject,
|
||||||
|
GLuint name, GLenum type, GLenum access);
|
||||||
|
typedef BOOL(WINAPI* P_wglDXUnregisterObjectNV)(HANDLE hDevice, HANDLE hObject);
|
||||||
|
typedef BOOL(WINAPI* P_wglDXObjectAccessNV)(HANDLE hObject, GLenum access);
|
||||||
|
typedef BOOL(WINAPI* P_wglDXLockObjectsNV)(HANDLE hDevice, GLint count, HANDLE* hObjects);
|
||||||
|
typedef BOOL(WINAPI* P_wglDXUnlockObjectsNV)(HANDLE hDevice, GLint count, HANDLE* hObjects);
|
||||||
|
|
||||||
|
void initializeD3D11(XrGraphicsRequirementsD3D11KHR requirements)
|
||||||
|
{
|
||||||
|
mD3D11Dll = LoadLibrary("D3D11.dll");
|
||||||
|
|
||||||
|
if (!mD3D11Dll)
|
||||||
|
throw std::runtime_error("Current OpenXR runtime requires DirectX >= 11.0 but D3D11.dll was not found.");
|
||||||
|
|
||||||
|
pD3D11CreateDevice = reinterpret_cast<PFN_D3D11_CREATE_DEVICE>(GetProcAddress(mD3D11Dll, "D3D11CreateDevice"));
|
||||||
|
|
||||||
|
if (!pD3D11CreateDevice)
|
||||||
|
throw std::runtime_error("Symbol 'D3D11CreateDevice' not found in D3D11.dll");
|
||||||
|
|
||||||
|
// Create the device and device context objects
|
||||||
|
pD3D11CreateDevice(
|
||||||
|
nullptr,
|
||||||
|
D3D_DRIVER_TYPE_HARDWARE,
|
||||||
|
nullptr,
|
||||||
|
0,
|
||||||
|
nullptr,
|
||||||
|
0,
|
||||||
|
D3D11_SDK_VERSION,
|
||||||
|
&mD3D11Device,
|
||||||
|
nullptr,
|
||||||
|
&mD3D11ImmediateContext);
|
||||||
|
|
||||||
|
mD3D11bindings.device = mD3D11Device;
|
||||||
|
|
||||||
|
//typedef HANDLE (WINAPI* P_wglDXOpenDeviceNV)(void* dxDevice);
|
||||||
|
//P_wglDXOpenDeviceNV wglDXOpenDeviceNV = reinterpret_cast<P_wglDXOpenDeviceNV>(wglGetProcAddress("wglDXOpenDeviceNV"));
|
||||||
|
//P_wglDXOpenDeviceNV wglDXOpenDeviceNV = reinterpret_cast<P_wglDXOpenDeviceNV>(wglGetProcAddress("wglDXOpenDeviceNV"));
|
||||||
|
|
||||||
|
#define LOAD_WGL(a) a = reinterpret_cast<decltype(a)>(wglGetProcAddress(#a)); if(!a) throw std::runtime_error("Extension WGL_NV_DX_interop2 required to run OpenMW VR via DirectX missing expected symbol '" #a "'.")
|
||||||
|
LOAD_WGL(wglDXSetResourceShareHandleNV);
|
||||||
|
LOAD_WGL(wglDXOpenDeviceNV);
|
||||||
|
LOAD_WGL(wglDXCloseDeviceNV);
|
||||||
|
LOAD_WGL(wglDXRegisterObjectNV);
|
||||||
|
LOAD_WGL(wglDXUnregisterObjectNV);
|
||||||
|
LOAD_WGL(wglDXObjectAccessNV);
|
||||||
|
LOAD_WGL(wglDXLockObjectsNV);
|
||||||
|
LOAD_WGL(wglDXUnlockObjectsNV);
|
||||||
|
#undef LOAD_WGL
|
||||||
|
|
||||||
|
wglDXDevice = wglDXOpenDeviceNV(mD3D11Device);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mWGL_NV_DX_interop2 = false;
|
||||||
|
XrGraphicsBindingD3D11KHR mD3D11bindings{ XR_TYPE_GRAPHICS_BINDING_D3D11_KHR };
|
||||||
|
ID3D11Device* mD3D11Device = nullptr;
|
||||||
|
ID3D11DeviceContext* mD3D11ImmediateContext = nullptr;
|
||||||
|
HMODULE mD3D11Dll = nullptr;
|
||||||
|
PFN_D3D11_CREATE_DEVICE pD3D11CreateDevice = nullptr;
|
||||||
|
|
||||||
|
P_wglDXSetResourceShareHandleNV wglDXSetResourceShareHandleNV = nullptr;
|
||||||
|
P_wglDXOpenDeviceNV wglDXOpenDeviceNV = nullptr;
|
||||||
|
P_wglDXCloseDeviceNV wglDXCloseDeviceNV = nullptr;
|
||||||
|
P_wglDXRegisterObjectNV wglDXRegisterObjectNV = nullptr;
|
||||||
|
P_wglDXUnregisterObjectNV wglDXUnregisterObjectNV = nullptr;
|
||||||
|
P_wglDXObjectAccessNV wglDXObjectAccessNV = nullptr;
|
||||||
|
P_wglDXLockObjectsNV wglDXLockObjectsNV = nullptr;
|
||||||
|
P_wglDXUnlockObjectsNV wglDXUnlockObjectsNV = nullptr;
|
||||||
|
|
||||||
|
HANDLE wglDXDevice = nullptr;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
OpenXRPlatformPrivate::OpenXRPlatformPrivate(osg::GraphicsContext* gc)
|
||||||
|
{
|
||||||
|
#ifdef XR_USE_GRAPHICS_API_D3D11
|
||||||
|
typedef const char* (WINAPI* PFNWGLGETEXTENSIONSSTRINGARBPROC) (HDC hdc);
|
||||||
|
PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = 0;
|
||||||
|
wglGetExtensionsStringARB = reinterpret_cast<PFNWGLGETEXTENSIONSSTRINGARBPROC>(wglGetProcAddress("wglGetExtensionsStringARB"));
|
||||||
|
if (wglGetExtensionsStringARB)
|
||||||
|
{
|
||||||
|
std::string wglExtensions = wglGetExtensionsStringARB(wglGetCurrentDC());
|
||||||
|
Log(Debug::Verbose) << "WGL Extensions: " << wglExtensions;
|
||||||
|
mWGL_NV_DX_interop2 = wglExtensions.find("WGL_NV_DX_interop2") != std::string::npos;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Log(Debug::Verbose) << "Unable to query WGL extensions";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenXRPlatformPrivate::~OpenXRPlatformPrivate()
|
||||||
|
{
|
||||||
|
#ifdef XR_USE_GRAPHICS_API_D3D11
|
||||||
|
if (wglDXDevice)
|
||||||
|
wglDXCloseDeviceNV(wglDXDevice);
|
||||||
|
if (mD3D11ImmediateContext)
|
||||||
|
mD3D11ImmediateContext->Release();
|
||||||
|
if (mD3D11Device)
|
||||||
|
mD3D11Device->Release();
|
||||||
|
if (mD3D11Dll)
|
||||||
|
FreeLibrary(mD3D11Dll);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenXRPlatform::OpenXRPlatform(osg::GraphicsContext* gc)
|
||||||
|
: mPrivate(new OpenXRPlatformPrivate(gc))
|
||||||
|
{
|
||||||
|
// Enumerate layers and their extensions.
|
||||||
|
uint32_t layerCount;
|
||||||
|
CHECK_XRCMD(xrEnumerateApiLayerProperties(0, &layerCount, nullptr));
|
||||||
|
std::vector<XrApiLayerProperties> layers(layerCount, XrApiLayerProperties{ XR_TYPE_API_LAYER_PROPERTIES });
|
||||||
|
CHECK_XRCMD(xrEnumerateApiLayerProperties((uint32_t)layers.size(), &layerCount, layers.data()));
|
||||||
|
|
||||||
|
Log(Debug::Verbose) << "Available Extensions: ";
|
||||||
|
enumerateExtensions(nullptr, 2);
|
||||||
|
Log(Debug::Verbose) << "Available Layers: ";
|
||||||
|
|
||||||
|
if (layers.size() == 0)
|
||||||
|
{
|
||||||
|
Log(Debug::Verbose) << " No layers available";
|
||||||
|
}
|
||||||
|
for (const XrApiLayerProperties& layer : layers) {
|
||||||
|
Log(Debug::Verbose) << " Name=" << layer.layerName << " SpecVersion=" << layer.layerVersion;
|
||||||
|
mAvailableLayers[layer.layerName] = layer;
|
||||||
|
enumerateExtensions(layer.layerName, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
setupExtensions();
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenXRPlatform::~OpenXRPlatform()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !XR_KHR_composition_layer_depth \
|
||||||
|
|| !XR_EXT_hp_mixed_reality_controller \
|
||||||
|
|| !XR_EXT_debug_utils \
|
||||||
|
|| !XR_HTC_vive_cosmos_controller_interaction \
|
||||||
|
|| !XR_HUAWEI_controller_interaction
|
||||||
|
|
||||||
|
#error "OpenXR extensions missing. Please upgrade your copy of the OpenXR SDK to 1.0.13 minimum"
|
||||||
|
#endif
|
||||||
|
void OpenXRPlatform::setupExtensions()
|
||||||
|
{
|
||||||
|
std::vector<const char*> optionalExtensions = {
|
||||||
|
XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME,
|
||||||
|
XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME,
|
||||||
|
XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME,
|
||||||
|
XR_HUAWEI_CONTROLLER_INTERACTION_EXTENSION_NAME
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Settings::Manager::getBool("enable XR_EXT_debug_utils", "VR Debug"))
|
||||||
|
optionalExtensions.emplace_back(XR_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||||
|
|
||||||
|
selectGraphicsAPIExtension();
|
||||||
|
|
||||||
|
Log(Debug::Verbose) << "Using extensions:";
|
||||||
|
|
||||||
|
auto* graphicsAPIExtension = graphicsAPIExtensionName();
|
||||||
|
if (!graphicsAPIExtension || !enableExtension(graphicsAPIExtension, true))
|
||||||
|
{
|
||||||
|
throw std::runtime_error("No graphics APIs supported by openmw are supported by the OpenXR runtime.");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto optionalExtension : optionalExtensions)
|
||||||
|
enableExtension(optionalExtension, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenXRPlatform::selectDirectX()
|
||||||
|
{
|
||||||
|
#ifdef XR_USE_GRAPHICS_API_D3D11
|
||||||
|
if (mPrivate->mWGL_NV_DX_interop2)
|
||||||
|
{
|
||||||
|
if (mAvailableExtensions.count(XR_KHR_D3D11_ENABLE_EXTENSION_NAME))
|
||||||
|
{
|
||||||
|
mGraphicsAPIExtension = XR_KHR_D3D11_ENABLE_EXTENSION_NAME;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Log(Debug::Warning) << "Warning: Failed to select DirectX swapchains: OpenXR runtime does not support essential extension '" << XR_KHR_D3D11_ENABLE_EXTENSION_NAME << "'";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Log(Debug::Warning) << "Warning: Failed to select DirectX swapchains: Essential WGL extension 'WGL_NV_DX_interop2' not supported by the graphics driver.";
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenXRPlatform::selectOpenGL()
|
||||||
|
{
|
||||||
|
#ifdef XR_USE_GRAPHICS_API_OPENGL
|
||||||
|
if (mAvailableExtensions.count(XR_KHR_OPENGL_ENABLE_EXTENSION_NAME))
|
||||||
|
{
|
||||||
|
mGraphicsAPIExtension = XR_KHR_OPENGL_ENABLE_EXTENSION_NAME;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Log(Debug::Warning) << "Warning: Failed to select OpenGL swapchains: OpenXR runtime does not support essential extension '" << XR_KHR_OPENGL_ENABLE_EXTENSION_NAME << "'";
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef XR_USE_GRAPHICS_API_OPENGL
|
||||||
|
#if !XR_KHR_opengl_enable
|
||||||
|
#error "OpenXR extensions missing. Please upgrade your copy of the OpenXR SDK to 1.0.13 minimum"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef XR_USE_GRAPHICS_API_D3D11
|
||||||
|
#if !XR_KHR_D3D11_enable
|
||||||
|
#error "OpenXR extensions missing. Please upgrade your copy of the OpenXR SDK to 1.0.13 minimum"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const char* OpenXRPlatform::graphicsAPIExtensionName()
|
||||||
|
{
|
||||||
|
return mGraphicsAPIExtension;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenXRPlatform::selectGraphicsAPIExtension()
|
||||||
|
{
|
||||||
|
bool preferDirectX = Settings::Manager::getBool("Prefer DirectX swapchains", "VR");
|
||||||
|
|
||||||
|
if (preferDirectX)
|
||||||
|
if (selectDirectX() || selectOpenGL())
|
||||||
|
return;
|
||||||
|
if (selectOpenGL() || selectDirectX())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Log(Debug::Verbose) << "Error: No graphics API supported by OpenMW VR is supported by the OpenXR runtime.";
|
||||||
|
throw std::runtime_error("Error: No graphics API supported by OpenMW VR is supported by the OpenXR runtime.");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenXRPlatform::supportsExtension(const std::string& extensionName) const
|
||||||
|
{
|
||||||
|
return mAvailableExtensions.count(extensionName) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenXRPlatform::supportsExtension(const std::string& extensionName, uint32_t minimumVersion) const
|
||||||
|
{
|
||||||
|
auto it = mAvailableExtensions.find(extensionName);
|
||||||
|
return it != mAvailableExtensions.end() && it->second.extensionVersion > minimumVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenXRPlatform::supportsLayer(const std::string& layerName) const
|
||||||
|
{
|
||||||
|
return mAvailableLayers.count(layerName) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenXRPlatform::supportsLayer(const std::string& layerName, uint32_t minimumVersion) const
|
||||||
|
{
|
||||||
|
auto it = mAvailableLayers.find(layerName);
|
||||||
|
return it != mAvailableLayers.end() && it->second.layerVersion > minimumVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenXRPlatform::enableExtension(const std::string& extensionName, bool optional)
|
||||||
|
{
|
||||||
|
auto it = mAvailableExtensions.find(extensionName);
|
||||||
|
if (it != mAvailableExtensions.end())
|
||||||
|
{
|
||||||
|
Log(Debug::Verbose) << " " << extensionName << ": enabled";
|
||||||
|
mEnabledExtensions.push_back(it->second.extensionName);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log(Debug::Verbose) << " " << extensionName << ": disabled (not supported)";
|
||||||
|
if (!optional)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(std::string("Required OpenXR extension ") + extensionName + " not supported by the runtime");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenXRPlatform::enableExtension(const std::string& extensionName, bool optional, uint32_t minimumVersion)
|
||||||
|
{
|
||||||
|
auto it = mAvailableExtensions.find(extensionName);
|
||||||
|
if (it != mAvailableExtensions.end() && it->second.extensionVersion > minimumVersion)
|
||||||
|
{
|
||||||
|
Log(Debug::Verbose) << " " << extensionName << ": enabled";
|
||||||
|
mEnabledExtensions.push_back(it->second.extensionName);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log(Debug::Verbose) << " " << extensionName << ": disabled (not supported)";
|
||||||
|
if (!optional)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(std::string("Required OpenXR extension ") + extensionName + " not supported by the runtime");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool OpenXRPlatform::extensionEnabled(const std::string& extensionName) const
|
||||||
|
{
|
||||||
|
for (auto* extension : mEnabledExtensions)
|
||||||
|
if (extension == extensionName)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
XrInstance OpenXRPlatform::createXrInstance(const std::string& name)
|
||||||
|
{
|
||||||
|
XrInstance instance = XR_NULL_HANDLE;
|
||||||
|
XrInstanceCreateInfo createInfo{ XR_TYPE_INSTANCE_CREATE_INFO };
|
||||||
|
createInfo.next = nullptr;
|
||||||
|
createInfo.enabledExtensionCount = mEnabledExtensions.size();
|
||||||
|
createInfo.enabledExtensionNames = mEnabledExtensions.data();
|
||||||
|
strcpy(createInfo.applicationInfo.applicationName, "openmw_vr");
|
||||||
|
createInfo.applicationInfo.apiVersion = XR_CURRENT_API_VERSION;
|
||||||
|
CHECK_XRCMD(xrCreateInstance(&createInfo, &instance));
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
XrSession OpenXRPlatform::createXrSession(XrInstance instance, XrSystemId systemId)
|
||||||
|
{
|
||||||
|
XrSession session = XR_NULL_HANDLE;
|
||||||
|
#ifdef _WIN32
|
||||||
|
std::string graphicsAPIExtension = graphicsAPIExtensionName();
|
||||||
|
if(graphicsAPIExtension == XR_KHR_OPENGL_ENABLE_EXTENSION_NAME)
|
||||||
|
{
|
||||||
|
// Get system requirements
|
||||||
|
PFN_xrGetOpenGLGraphicsRequirementsKHR p_getRequirements = nullptr;
|
||||||
|
xrGetInstanceProcAddr(instance, "xrGetOpenGLGraphicsRequirementsKHR", reinterpret_cast<PFN_xrVoidFunction*>(&p_getRequirements));
|
||||||
|
XrGraphicsRequirementsOpenGLKHR requirements{ XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR };
|
||||||
|
CHECK_XRCMD(p_getRequirements(instance, systemId, &requirements));
|
||||||
|
|
||||||
|
// TODO: Actually get system version
|
||||||
|
const XrVersion systemApiVersion = XR_MAKE_VERSION(4, 6, 0);
|
||||||
|
if (requirements.minApiVersionSupported > systemApiVersion) {
|
||||||
|
std::cout << "Runtime does not support desired Graphics API and/or version" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create Session
|
||||||
|
auto DC = wglGetCurrentDC();
|
||||||
|
auto GLRC = wglGetCurrentContext();
|
||||||
|
|
||||||
|
XrGraphicsBindingOpenGLWin32KHR graphicsBindings;
|
||||||
|
graphicsBindings.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR;
|
||||||
|
graphicsBindings.next = nullptr;
|
||||||
|
graphicsBindings.hDC = DC;
|
||||||
|
graphicsBindings.hGLRC = GLRC;
|
||||||
|
|
||||||
|
if (!graphicsBindings.hDC)
|
||||||
|
Log(Debug::Warning) << "Missing DC";
|
||||||
|
|
||||||
|
XrSessionCreateInfo createInfo{ XR_TYPE_SESSION_CREATE_INFO };
|
||||||
|
createInfo.next = &graphicsBindings;
|
||||||
|
createInfo.systemId = systemId;
|
||||||
|
CHECK_XRCMD(xrCreateSession(instance, &createInfo, &session));
|
||||||
|
}
|
||||||
|
#ifdef XR_USE_GRAPHICS_API_D3D11
|
||||||
|
else if(graphicsAPIExtension == XR_KHR_D3D11_ENABLE_EXTENSION_NAME)
|
||||||
|
{
|
||||||
|
PFN_xrGetD3D11GraphicsRequirementsKHR p_getRequirements = nullptr;
|
||||||
|
xrGetInstanceProcAddr(instance, "xrGetD3D11GraphicsRequirementsKHR", reinterpret_cast<PFN_xrVoidFunction*>(&p_getRequirements));
|
||||||
|
XrGraphicsRequirementsD3D11KHR requirements{ XR_TYPE_GRAPHICS_REQUIREMENTS_D3D11_KHR };
|
||||||
|
CHECK_XRCMD(p_getRequirements(instance, systemId, &requirements));
|
||||||
|
mPrivate->initializeD3D11(requirements);
|
||||||
|
|
||||||
|
XrSessionCreateInfo createInfo{ XR_TYPE_SESSION_CREATE_INFO };
|
||||||
|
createInfo.next = &mPrivate->mD3D11bindings;
|
||||||
|
createInfo.systemId = systemId;
|
||||||
|
CHECK_XRCMD(xrCreateSession(instance, &createInfo, &session));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::logic_error("Enum value not implemented");
|
||||||
|
}
|
||||||
|
#elif __linux__
|
||||||
|
{ // Create Session
|
||||||
|
Display* xDisplay = XOpenDisplay(NULL);
|
||||||
|
GLXContext glxContext = glXGetCurrentContext();
|
||||||
|
GLXDrawable glxDrawable = glXGetCurrentDrawable();
|
||||||
|
|
||||||
|
// TODO: runtimes don't actually care (yet)
|
||||||
|
GLXFBConfig glxFBConfig = 0;
|
||||||
|
uint32_t visualid = 0;
|
||||||
|
|
||||||
|
XrGraphicsBindingOpenGLXlibKHR graphicsBindings;
|
||||||
|
graphicsBindings.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR;
|
||||||
|
graphicsBindings.next = nullptr;
|
||||||
|
graphicsBindings.xDisplay = xDisplay;
|
||||||
|
graphicsBindings.glxContext = glxContext;
|
||||||
|
graphicsBindings.glxDrawable = glxDrawable;
|
||||||
|
graphicsBindings.glxFBConfig = glxFBConfig;
|
||||||
|
graphicsBindings.visualid = visualid;
|
||||||
|
|
||||||
|
if (!graphicsBindings.glxContext)
|
||||||
|
Log(Debug::Warning) << "Missing glxContext";
|
||||||
|
|
||||||
|
if (!graphicsBindings.glxDrawable)
|
||||||
|
Log(Debug::Warning) << "Missing glxDrawable";
|
||||||
|
|
||||||
|
XrSessionCreateInfo createInfo{ XR_TYPE_SESSION_CREATE_INFO };
|
||||||
|
createInfo.next = &graphicsBindings;
|
||||||
|
createInfo.systemId = systemId;
|
||||||
|
CHECK_XRCMD(xrCreateSession(instance, &createInfo, &session));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
assert(session);
|
||||||
|
|
||||||
|
uint32_t swapchainFormatCount;
|
||||||
|
CHECK_XRCMD(xrEnumerateSwapchainFormats(session, 0, &swapchainFormatCount, nullptr));
|
||||||
|
mSwapchainFormats.resize(swapchainFormatCount);
|
||||||
|
CHECK_XRCMD(xrEnumerateSwapchainFormats(session, (uint32_t)mSwapchainFormats.size(), &swapchainFormatCount, mSwapchainFormats.data()));
|
||||||
|
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "Available Swapchain formats: (" << swapchainFormatCount << ")" << std::endl;
|
||||||
|
|
||||||
|
for (auto format : mSwapchainFormats)
|
||||||
|
{
|
||||||
|
ss << " Enum=" << std::dec << format << " (0x=" << std::hex << format << ")" << std::dec << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log(Debug::Verbose) << ss.str();
|
||||||
|
|
||||||
|
return session;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For reference: These are the DXGI formats offered by WMR when using D3D11:
|
||||||
|
Enum=29 //(0x=1d) DXGI_FORMAT_R8G8B8A8_UNORM_SRGB
|
||||||
|
Enum=91 //(0x=5b) DXGI_FORMAT_B8G8R8A8_UNORM_SRGB
|
||||||
|
Enum=28 //(0x=1c) DXGI_FORMAT_R8G8B8A8_UNORM
|
||||||
|
Enum=87 //(0x=57) DXGI_FORMAT_B8G8R8A8_UNORM
|
||||||
|
Enum=40 //(0x=28) DXGI_FORMAT_D32_FLOAT
|
||||||
|
Enum=20 //(0x=14) DXGI_FORMAT_D32_FLOAT_S8X24_UINT
|
||||||
|
Enum=45 //(0x=2d) DXGI_FORMAT_D24_UNORM_S8_UINT
|
||||||
|
Enum=55 //(0x=37) DXGI_FORMAT_D16_UNORM
|
||||||
|
* And these extra formats are offered by SteamVR:
|
||||||
|
0xa , // DXGI_FORMAT_R16G16B16A16_FLOAT
|
||||||
|
0x18 , // DXGI_FORMAT_R10G10B10A2_UNORM
|
||||||
|
*/
|
||||||
|
|
||||||
|
int64_t OpenXRPlatform::selectColorFormat()
|
||||||
|
{
|
||||||
|
std::string graphicsAPIExtension = graphicsAPIExtensionName();
|
||||||
|
if (graphicsAPIExtension == XR_KHR_OPENGL_ENABLE_EXTENSION_NAME)
|
||||||
|
{
|
||||||
|
// 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
|
||||||
|
// Don't need srgb: 0x8C43, // GL_SRGB8_ALPHA8
|
||||||
|
// Don't need srgb: 0x8C41, // GL_SRGB8
|
||||||
|
};
|
||||||
|
return selectFormat(requestedColorSwapchainFormats);
|
||||||
|
}
|
||||||
|
#ifdef XR_USE_GRAPHICS_API_D3D11
|
||||||
|
else if (graphicsAPIExtension == XR_KHR_D3D11_ENABLE_EXTENSION_NAME)
|
||||||
|
{
|
||||||
|
// Find supported color swapchain format.
|
||||||
|
std::vector<int64_t> requestedColorSwapchainFormats = {
|
||||||
|
0x1c, // DXGI_FORMAT_R8G8B8A8_UNORM
|
||||||
|
0x57, // DXGI_FORMAT_B8G8R8A8_UNORM
|
||||||
|
0xa , // DXGI_FORMAT_R16G16B16A16_FLOAT
|
||||||
|
0x18, // DXGI_FORMAT_R10G10B10A2_UNORM
|
||||||
|
// Don't need srgb: 0x1d, // DXGI_FORMAT_R8G8B8A8_UNORM_SRGB
|
||||||
|
// Don't need srgb: 0x5b, // DXGI_FORMAT_B8G8R8A8_UNORM_SRGB
|
||||||
|
};
|
||||||
|
return selectFormat(requestedColorSwapchainFormats);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::logic_error("Enum value not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t OpenXRPlatform::selectDepthFormat()
|
||||||
|
{
|
||||||
|
std::string graphicsAPIExtension = graphicsAPIExtensionName();
|
||||||
|
if (graphicsAPIExtension == XR_KHR_OPENGL_ENABLE_EXTENSION_NAME)
|
||||||
|
{
|
||||||
|
// Find supported depth swapchain format.
|
||||||
|
std::vector<int64_t> requestedDepthSwapchainFormats = {
|
||||||
|
0x88F0, // GL_DEPTH24_STENCIL8
|
||||||
|
0x8CAC, // GL_DEPTH_COMPONENT32F
|
||||||
|
0x81A7, // GL_DEPTH_COMPONENT32
|
||||||
|
0x8DAB, // GL_DEPTH_COMPONENT32F_NV
|
||||||
|
0x8CAD, // GL_DEPTH32_STENCIL8
|
||||||
|
0x81A6, // GL_DEPTH_COMPONENT24
|
||||||
|
// Need 32bit minimum: // 0x81A5, // GL_DEPTH_COMPONENT16
|
||||||
|
};
|
||||||
|
|
||||||
|
return selectFormat(requestedDepthSwapchainFormats);
|
||||||
|
}
|
||||||
|
#ifdef XR_USE_GRAPHICS_API_D3D11
|
||||||
|
else if (graphicsAPIExtension == XR_KHR_D3D11_ENABLE_EXTENSION_NAME)
|
||||||
|
{
|
||||||
|
// Find supported color swapchain format.
|
||||||
|
std::vector<int64_t> requestedDepthSwapchainFormats = {
|
||||||
|
0x2d, // DXGI_FORMAT_D24_UNORM_S8_UINT
|
||||||
|
0x14, // DXGI_FORMAT_D32_FLOAT_S8X24_UINT
|
||||||
|
0x28, // DXGI_FORMAT_D32_FLOAT
|
||||||
|
// Need 32bit minimum: 0x37, // DXGI_FORMAT_D16_UNORM
|
||||||
|
};
|
||||||
|
return selectFormat(requestedDepthSwapchainFormats);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::logic_error("Enum value not implemented");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t OpenXRPlatform::selectFormat(const std::vector<int64_t>& requestedFormats)
|
||||||
|
{
|
||||||
|
auto it =
|
||||||
|
std::find_first_of(std::begin(requestedFormats), std::end(requestedFormats),
|
||||||
|
mSwapchainFormats.begin(), mSwapchainFormats.end());
|
||||||
|
if (it == std::end(requestedFormats))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return *it;
|
||||||
|
}
|
||||||
|
void* OpenXRPlatform::DXRegisterObject(void* dxResource, uint32_t glName, uint32_t glType, bool discard, void* ntShareHandle)
|
||||||
|
{
|
||||||
|
#ifdef XR_USE_GRAPHICS_API_D3D11
|
||||||
|
if (ntShareHandle)
|
||||||
|
{
|
||||||
|
mPrivate->wglDXSetResourceShareHandleNV(dxResource, ntShareHandle);
|
||||||
|
}
|
||||||
|
return mPrivate->wglDXRegisterObjectNV(mPrivate->wglDXDevice, dxResource, glName, glType, 1);
|
||||||
|
#else
|
||||||
|
return nullptr;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
void OpenXRPlatform::DXUnregisterObject(void* dxResourceShareHandle)
|
||||||
|
{
|
||||||
|
#ifdef XR_USE_GRAPHICS_API_D3D11
|
||||||
|
mPrivate->wglDXUnregisterObjectNV(mPrivate->wglDXDevice, dxResourceShareHandle);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
void OpenXRPlatform::DXLockObject(void* dxResourceShareHandle)
|
||||||
|
{
|
||||||
|
#ifdef XR_USE_GRAPHICS_API_D3D11
|
||||||
|
mPrivate->wglDXLockObjectsNV(mPrivate->wglDXDevice, 1, &dxResourceShareHandle);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
void OpenXRPlatform::DXUnlockObject(void* dxResourceShareHandle)
|
||||||
|
{
|
||||||
|
#ifdef XR_USE_GRAPHICS_API_D3D11
|
||||||
|
mPrivate->wglDXUnlockObjectsNV(mPrivate->wglDXDevice, 1, &dxResourceShareHandle);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
#ifndef OPENXR_PLATFORM_HPP
|
||||||
|
#define OPENXR_PLATFORM_HPP
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <openxr/openxr.h>
|
||||||
|
|
||||||
|
namespace MWVR
|
||||||
|
{
|
||||||
|
// Error management macros and functions. Should be used on every openxr call.
|
||||||
|
#define CHK_STRINGIFY(x) #x
|
||||||
|
#define TOSTRING(x) CHK_STRINGIFY(x)
|
||||||
|
#define FILE_AND_LINE __FILE__ ":" TOSTRING(__LINE__)
|
||||||
|
#define CHECK_XRCMD(cmd) CheckXrResult(cmd, #cmd, FILE_AND_LINE)
|
||||||
|
#define CHECK_XRRESULT(res, cmdStr) CheckXrResult(res, cmdStr, FILE_AND_LINE)
|
||||||
|
XrResult CheckXrResult(XrResult res, const char* originator = nullptr, const char* sourceLocation = nullptr);
|
||||||
|
std::string XrResultString(XrResult res);
|
||||||
|
|
||||||
|
struct OpenXRPlatformPrivate;
|
||||||
|
|
||||||
|
class OpenXRPlatform
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using ExtensionMap = std::map<std::string, XrExtensionProperties>;
|
||||||
|
using LayerMap = std::map<std::string, XrApiLayerProperties>;
|
||||||
|
using LayerExtensionMap = std::map<std::string, ExtensionMap>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
OpenXRPlatform(osg::GraphicsContext* gc);
|
||||||
|
~OpenXRPlatform();
|
||||||
|
|
||||||
|
const char* graphicsAPIExtensionName();
|
||||||
|
bool supportsExtension(const std::string& extensionName) const;
|
||||||
|
bool supportsExtension(const std::string& extensionName, uint32_t minimumVersion) const;
|
||||||
|
bool supportsLayer(const std::string& layerName) const;
|
||||||
|
bool supportsLayer(const std::string& layerName, uint32_t minimumVersion) const;
|
||||||
|
|
||||||
|
bool enableExtension(const std::string& extensionName, bool optional);
|
||||||
|
bool enableExtension(const std::string& extensionName, bool optional, uint32_t minimumVersion);
|
||||||
|
|
||||||
|
bool extensionEnabled(const std::string& extensionName) const;
|
||||||
|
|
||||||
|
XrInstance createXrInstance(const std::string& name);
|
||||||
|
XrSession createXrSession(XrInstance instance, XrSystemId systemId);
|
||||||
|
|
||||||
|
int64_t selectColorFormat();
|
||||||
|
int64_t selectDepthFormat();
|
||||||
|
int64_t selectFormat(const std::vector<int64_t>& requestedFormats);
|
||||||
|
std::vector<int64_t> mSwapchainFormats{};
|
||||||
|
|
||||||
|
/// Registers an object for sharing as if calling wglDXRegisterObjectNV requesting write access.
|
||||||
|
/// If ntShareHandle is not null, wglDXSetResourceShareHandleNV is called first to register the share handle
|
||||||
|
void* DXRegisterObject(void* dxResource, uint32_t glName, uint32_t glType, bool discard, void* ntShareHandle);
|
||||||
|
/// Unregisters an object from sharing as if calling wglDXUnregisterObjectNV
|
||||||
|
void DXUnregisterObject(void* dxResourceShareHandle);
|
||||||
|
/// Locks a DX object for use by OpenGL as if calling wglDXLockObjectsNV
|
||||||
|
void DXLockObject(void* dxResourceShareHandle);
|
||||||
|
/// Unlocks a DX object for use by DirectX as if calling wglDXUnlockObjectsNV
|
||||||
|
void DXUnlockObject(void* dxResourceShareHandle);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
void enumerateExtensions(const char* layerName, int logIndent);
|
||||||
|
void setupExtensions();
|
||||||
|
void selectGraphicsAPIExtension();
|
||||||
|
bool selectDirectX();
|
||||||
|
bool selectOpenGL();
|
||||||
|
|
||||||
|
ExtensionMap mAvailableExtensions;
|
||||||
|
LayerMap mAvailableLayers;
|
||||||
|
LayerExtensionMap mAvailableLayerExtensions;
|
||||||
|
std::vector<const char*> mEnabledExtensions;
|
||||||
|
const char* mGraphicsAPIExtension = nullptr;
|
||||||
|
|
||||||
|
std::unique_ptr< OpenXRPlatformPrivate > mPrivate;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,223 @@
|
|||||||
|
#include "openxrswapchainimage.hpp"
|
||||||
|
#include "openxrmanagerimpl.hpp"
|
||||||
|
#include "vrenvironment.hpp"
|
||||||
|
#include "vrframebuffer.hpp"
|
||||||
|
|
||||||
|
// The OpenXR SDK's platform headers assume we've included platform headers
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <objbase.h>
|
||||||
|
|
||||||
|
#ifdef XR_USE_GRAPHICS_API_D3D11
|
||||||
|
#include <d3d11.h>
|
||||||
|
#include <dxgi1_2.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif __linux__
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <GL/glx.h>
|
||||||
|
#undef None
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error Unsupported platform
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <openxr/openxr.h>
|
||||||
|
#include <openxr/openxr_platform.h>
|
||||||
|
#include <openxr/openxr_platform_defines.h>
|
||||||
|
#include <openxr/openxr_reflection.h>
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#define GLERR if(auto err = glGetError() != GL_NO_ERROR) Log(Debug::Verbose) << __FILE__ << "." << __LINE__ << ": " << glGetError()
|
||||||
|
|
||||||
|
namespace MWVR {
|
||||||
|
|
||||||
|
template<typename Image>
|
||||||
|
class OpenXRSwapchainImageTemplate;
|
||||||
|
|
||||||
|
template<>
|
||||||
|
class OpenXRSwapchainImageTemplate< XrSwapchainImageOpenGLKHR > : public OpenXRSwapchainImage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr XrStructureType XrType = XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR;
|
||||||
|
|
||||||
|
public:
|
||||||
|
OpenXRSwapchainImageTemplate(osg::GraphicsContext* gc, XrSwapchainCreateInfo swapchainCreateInfo, const XrSwapchainImageOpenGLKHR& xrImage)
|
||||||
|
: OpenXRSwapchainImage()
|
||||||
|
, mXrImage(xrImage)
|
||||||
|
, mBufferBits(0)
|
||||||
|
, mFramebuffer(nullptr)
|
||||||
|
{
|
||||||
|
mFramebuffer.reset(new VRFramebuffer(gc->getState(), swapchainCreateInfo.width, swapchainCreateInfo.height, swapchainCreateInfo.sampleCount));
|
||||||
|
if (swapchainCreateInfo.usageFlags & XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)
|
||||||
|
{
|
||||||
|
mFramebuffer->setDepthBuffer(gc, mXrImage.image, false);
|
||||||
|
mBufferBits = GL_DEPTH_BUFFER_BIT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mFramebuffer->setColorBuffer(gc, mXrImage.image, false);
|
||||||
|
mBufferBits = GL_COLOR_BUFFER_BIT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void blit(osg::GraphicsContext* gc, VRFramebuffer& readBuffer, int offset_x, int offset_y) override
|
||||||
|
{
|
||||||
|
mFramebuffer->bindFramebuffer(gc, GL_FRAMEBUFFER_EXT);
|
||||||
|
readBuffer.blit(gc, offset_x, offset_y, offset_x + mFramebuffer->width(), offset_y + mFramebuffer->height(), 0, 0, mFramebuffer->width(), mFramebuffer->height(), mBufferBits, GL_NEAREST);
|
||||||
|
readBuffer.bindFramebuffer(gc, GL_FRAMEBUFFER_EXT);
|
||||||
|
}
|
||||||
|
|
||||||
|
XrSwapchainImageOpenGLKHR mXrImage;
|
||||||
|
uint32_t mBufferBits;
|
||||||
|
std::unique_ptr<VRFramebuffer> mFramebuffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef XR_USE_GRAPHICS_API_D3D11
|
||||||
|
template<>
|
||||||
|
class OpenXRSwapchainImageTemplate< XrSwapchainImageD3D11KHR > : public OpenXRSwapchainImage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr XrStructureType XrType = XR_TYPE_SWAPCHAIN_IMAGE_D3D11_KHR;
|
||||||
|
public:
|
||||||
|
OpenXRSwapchainImageTemplate(osg::GraphicsContext* gc, XrSwapchainCreateInfo swapchainCreateInfo, const XrSwapchainImageD3D11KHR& xrImage)
|
||||||
|
: OpenXRSwapchainImage()
|
||||||
|
, mXrImage(xrImage)
|
||||||
|
, mBufferBits(0)
|
||||||
|
, mFramebuffer(nullptr)
|
||||||
|
{
|
||||||
|
mXrImage.texture->GetDevice(&mDevice);
|
||||||
|
mDevice->GetImmediateContext(&mDeviceContext);
|
||||||
|
|
||||||
|
mXrImage.texture->GetDesc(&mDesc);
|
||||||
|
|
||||||
|
glGenTextures(1, &mGlTextureName);
|
||||||
|
|
||||||
|
auto* xr = Environment::get().getManager();
|
||||||
|
//mDxResourceShareHandle = xr->impl().platform().DXRegisterObject(mXrImage.texture, mGlTextureName, GL_TEXTURE_2D, true, nullptr);
|
||||||
|
|
||||||
|
if (!mDxResourceShareHandle)
|
||||||
|
{
|
||||||
|
// Some OpenXR runtimes return textures that cannot be directly shared.
|
||||||
|
// So we need to make a redundant texture to use as an intermediary...
|
||||||
|
mSharedTextureDesc.Width = mDesc.Width;
|
||||||
|
mSharedTextureDesc.Height = mDesc.Height;
|
||||||
|
mSharedTextureDesc.MipLevels = mDesc.MipLevels;
|
||||||
|
mSharedTextureDesc.ArraySize = mDesc.ArraySize;
|
||||||
|
mSharedTextureDesc.Format = static_cast<DXGI_FORMAT>(swapchainCreateInfo.format);
|
||||||
|
mSharedTextureDesc.SampleDesc = mDesc.SampleDesc;
|
||||||
|
mSharedTextureDesc.Usage = D3D11_USAGE_DEFAULT;
|
||||||
|
mSharedTextureDesc.BindFlags = 0;
|
||||||
|
mSharedTextureDesc.CPUAccessFlags = 0;
|
||||||
|
mSharedTextureDesc.MiscFlags = 0;;
|
||||||
|
|
||||||
|
mDevice->CreateTexture2D(&mSharedTextureDesc, nullptr, &mSharedTexture);
|
||||||
|
mXrImage.texture->GetDesc(&mSharedTextureDesc);
|
||||||
|
mDxResourceShareHandle = xr->impl().platform().DXRegisterObject(mSharedTexture, mGlTextureName, GL_TEXTURE_2D, true, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up shared texture as blit target
|
||||||
|
mFramebuffer.reset(new VRFramebuffer(gc->getState(), swapchainCreateInfo.width, swapchainCreateInfo.height, swapchainCreateInfo.sampleCount));
|
||||||
|
|
||||||
|
if (swapchainCreateInfo.usageFlags & XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)
|
||||||
|
{
|
||||||
|
mFramebuffer->setDepthBuffer(gc, mGlTextureName, false);
|
||||||
|
mBufferBits = GL_DEPTH_BUFFER_BIT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mFramebuffer->setColorBuffer(gc, mGlTextureName, false);
|
||||||
|
mBufferBits = GL_COLOR_BUFFER_BIT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~OpenXRSwapchainImageTemplate()
|
||||||
|
{
|
||||||
|
auto* xr = Environment::get().getManager();
|
||||||
|
if (mDxResourceShareHandle)
|
||||||
|
xr->impl().platform().DXUnregisterObject(mDxResourceShareHandle);
|
||||||
|
glDeleteTextures(1, &mGlTextureName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void blit(osg::GraphicsContext* gc, VRFramebuffer& readBuffer, int offset_x, int offset_y) override
|
||||||
|
{
|
||||||
|
// Blit readBuffer into directx texture, while flipping the Y axis.
|
||||||
|
auto* xr = Environment::get().getManager();
|
||||||
|
xr->impl().platform().DXLockObject(mDxResourceShareHandle);
|
||||||
|
mFramebuffer->bindFramebuffer(gc, GL_FRAMEBUFFER_EXT);
|
||||||
|
readBuffer.blit(gc, offset_x, offset_y, offset_x + mFramebuffer->width(), offset_y + mFramebuffer->height(), 0, mFramebuffer->height(), mFramebuffer->width(), 0, mBufferBits, GL_NEAREST);
|
||||||
|
xr->impl().platform().DXUnlockObject(mDxResourceShareHandle);
|
||||||
|
readBuffer.bindFramebuffer(gc, GL_FRAMEBUFFER_EXT);
|
||||||
|
|
||||||
|
|
||||||
|
// If the d3d11 texture couldn't be shared directly, blit it again.
|
||||||
|
if (mSharedTexture)
|
||||||
|
{
|
||||||
|
mDeviceContext->CopyResource(mXrImage.texture, mSharedTexture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ID3D11Device* mDevice = nullptr;
|
||||||
|
ID3D11DeviceContext* mDeviceContext = nullptr;
|
||||||
|
D3D11_TEXTURE2D_DESC mDesc;
|
||||||
|
D3D11_TEXTURE2D_DESC mSharedTextureDesc;
|
||||||
|
ID3D11Texture2D* mSharedTexture = nullptr;
|
||||||
|
uint32_t mGlTextureName = 0;
|
||||||
|
void* mDxResourceShareHandle = nullptr;
|
||||||
|
|
||||||
|
XrSwapchainImageD3D11KHR mXrImage;
|
||||||
|
uint32_t mBufferBits;
|
||||||
|
std::unique_ptr<VRFramebuffer> mFramebuffer;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
template< typename Image > static inline
|
||||||
|
std::vector<std::unique_ptr<OpenXRSwapchainImage> >
|
||||||
|
enumerateSwapchainImagesImpl(osg::GraphicsContext* gc, XrSwapchain swapchain, XrSwapchainCreateInfo swapchainCreateInfo)
|
||||||
|
{
|
||||||
|
using SwapchainImage = OpenXRSwapchainImageTemplate<Image>;
|
||||||
|
|
||||||
|
uint32_t imageCount = 0;
|
||||||
|
std::vector< Image > images;
|
||||||
|
CHECK_XRCMD(xrEnumerateSwapchainImages(swapchain, 0, &imageCount, nullptr));
|
||||||
|
images.resize(imageCount, { SwapchainImage::XrType });
|
||||||
|
CHECK_XRCMD(xrEnumerateSwapchainImages(swapchain, imageCount, &imageCount, reinterpret_cast<XrSwapchainImageBaseHeader*>(images.data())));
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<OpenXRSwapchainImage> > swapchainImages;
|
||||||
|
for(auto& image: images)
|
||||||
|
{
|
||||||
|
swapchainImages.emplace_back(new OpenXRSwapchainImageTemplate<Image>(gc, swapchainCreateInfo, image));
|
||||||
|
}
|
||||||
|
|
||||||
|
return swapchainImages;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<OpenXRSwapchainImage> >
|
||||||
|
OpenXRSwapchainImage::enumerateSwapchainImages(osg::GraphicsContext* gc, XrSwapchain swapchain, XrSwapchainCreateInfo swapchainCreateInfo)
|
||||||
|
{
|
||||||
|
auto* xr = Environment::get().getManager();
|
||||||
|
|
||||||
|
if (xr->xrExtensionIsEnabled(XR_KHR_OPENGL_ENABLE_EXTENSION_NAME))
|
||||||
|
{
|
||||||
|
return enumerateSwapchainImagesImpl<XrSwapchainImageOpenGLKHR>(gc, swapchain, swapchainCreateInfo);
|
||||||
|
}
|
||||||
|
#ifdef XR_USE_GRAPHICS_API_D3D11
|
||||||
|
else if (xr->xrExtensionIsEnabled(XR_KHR_D3D11_ENABLE_EXTENSION_NAME))
|
||||||
|
{
|
||||||
|
return enumerateSwapchainImagesImpl<XrSwapchainImageD3D11KHR>(gc, swapchain, swapchainCreateInfo);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::logic_error("Implementation missing for selected graphics API");
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::vector<std::unique_ptr<OpenXRSwapchainImage>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenXRSwapchainImage::OpenXRSwapchainImage()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
#ifndef OPENXR_SWAPCHAINIMAGE_HPP
|
||||||
|
#define OPENXR_SWAPCHAINIMAGE_HPP
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <openxr/openxr.h>
|
||||||
|
#include <osg/GraphicsContext>
|
||||||
|
|
||||||
|
#include "vrframebuffer.hpp"
|
||||||
|
|
||||||
|
namespace MWVR
|
||||||
|
{
|
||||||
|
class OpenXRSwapchainImage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static std::vector< std::unique_ptr<OpenXRSwapchainImage> >
|
||||||
|
enumerateSwapchainImages(osg::GraphicsContext* gc, XrSwapchain swapchain, XrSwapchainCreateInfo swapchainCreateInfo);
|
||||||
|
|
||||||
|
OpenXRSwapchainImage();
|
||||||
|
virtual ~OpenXRSwapchainImage() {};
|
||||||
|
|
||||||
|
virtual void blit(osg::GraphicsContext* gc, VRFramebuffer& readBuffer, int offset_x, int offset_y) = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue