mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 22:23:51 +00:00
Merge remote-tracking branch 'remotes/origin/directx_swapchains' into openxr_vr_geometryshader_feature_branch
This commit is contained in:
commit
11a3961d65
24 changed files with 1285 additions and 614 deletions
|
@ -247,7 +247,7 @@ if(BUILD_OPENMW_VR)
|
|||
vrengine.cpp
|
||||
)
|
||||
add_openmw_dir (mwvr
|
||||
openxraction openxractionset openxrdebug openxrinput openxrmanager openxrmanagerimpl openxrswapchain openxrswapchainimpl
|
||||
openxraction openxractionset openxrdebug openxrinput openxrmanager openxrmanagerimpl openxrplatform openxrswapchain openxrswapchainimage openxrswapchainimpl
|
||||
realisticcombat
|
||||
vranimation vrcamera vrenvironment vrframebuffer vrgui vrinputmanager vrinput vrmetamenu vrsession vrshadow vrtypes vrview vrviewer vrvirtualkeyboard
|
||||
)
|
||||
|
@ -280,7 +280,7 @@ if(BUILD_OPENMW_VR)
|
|||
|
||||
# Preprocessor variable used to control code paths to vr code
|
||||
if (WIN32)
|
||||
target_compile_options(openmw_vr PUBLIC -DUSE_OPENXR -DXR_USE_GRAPHICS_API_OPENGL -DXR_USE_PLATFORM_WIN32)
|
||||
target_compile_options(openmw_vr PUBLIC -DUSE_OPENXR -DXR_USE_GRAPHICS_API_OPENGL -DXR_USE_GRAPHICS_API_D3D11 -DXR_USE_PLATFORM_WIN32)
|
||||
elseif(UNIX)
|
||||
target_compile_options(openmw_vr PUBLIC -DUSE_OPENXR -DXR_USE_GRAPHICS_API_OPENGL -DXR_USE_PLATFORM_XLIB)
|
||||
find_package(X11 REQUIRED)
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#error Unsupported platform
|
||||
#endif
|
||||
|
||||
#include <openxr/openxr_platform.h>
|
||||
#include <openxr/openxr_platform_defines.h>
|
||||
#include <openxr/openxr_reflection.h>
|
||||
|
||||
|
|
|
@ -77,13 +77,13 @@ namespace MWVR
|
|||
{
|
||||
gc->makeCurrent();
|
||||
try {
|
||||
mPrivate = std::make_shared<OpenXRManagerImpl>();
|
||||
mPrivate = std::make_shared<OpenXRManagerImpl>(gc);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
Log(Debug::Error) << "Exception thrown by OpenXR: " << e.what();
|
||||
osg::ref_ptr<osg::State> state = gc->getState();
|
||||
|
||||
std::string error = std::string("Exception thrown while initializing OpenXR: ") + e.what();
|
||||
Log(Debug::Error) << error;
|
||||
throw std::runtime_error(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -138,6 +138,16 @@ namespace MWVR
|
|||
return impl().xrExtensionIsEnabled(extensionName);
|
||||
}
|
||||
|
||||
int64_t OpenXRManager::selectColorFormat()
|
||||
{
|
||||
return impl().selectColorFormat();
|
||||
}
|
||||
|
||||
int64_t OpenXRManager::selectDepthFormat()
|
||||
{
|
||||
return impl().selectDepthFormat();
|
||||
}
|
||||
|
||||
void
|
||||
OpenXRManager::CleanupOperation::operator()(
|
||||
osg::GraphicsContext* gc)
|
||||
|
|
|
@ -98,6 +98,14 @@ namespace MWVR
|
|||
//! Check whether a given openxr extension is enabled or not
|
||||
bool xrExtensionIsEnabled(const char* extensionName) const;
|
||||
|
||||
//! Selects a color format from among formats offered by the runtime
|
||||
//! Returns 0 if no format is supported.
|
||||
int64_t selectColorFormat();
|
||||
|
||||
//! Selects a depth format from among formats offered by the runtime
|
||||
//! Returns 0 if no format is supported.
|
||||
int64_t selectDepthFormat();
|
||||
|
||||
OpenXRManagerImpl& impl() { return *mPrivate; }
|
||||
const OpenXRManagerImpl& impl() const { return *mPrivate; }
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "openxrmanagerimpl.hpp"
|
||||
#include "openxrdebug.hpp"
|
||||
#include "openxrplatform.hpp"
|
||||
#include "openxrswapchain.hpp"
|
||||
#include "openxrswapchainimpl.hpp"
|
||||
#include "vrenvironment.hpp"
|
||||
|
@ -18,22 +19,6 @@
|
|||
#include "../mwworld/player.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
// The OpenXR SDK's platform headers assume we've included platform headers
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#include <objbase.h>
|
||||
|
||||
#elif __linux__
|
||||
#include <X11/Xlib.h>
|
||||
#include <GL/glx.h>
|
||||
#undef None
|
||||
|
||||
#else
|
||||
#error Unsupported platform
|
||||
#endif
|
||||
|
||||
#include <openxr/openxr_platform.h>
|
||||
#include <openxr/openxr_platform_defines.h>
|
||||
#include <openxr/openxr_reflection.h>
|
||||
|
||||
#include <osg/Camera>
|
||||
|
@ -61,30 +46,13 @@ MAKE_TO_STRING_FUNC(XrStructureType);
|
|||
|
||||
namespace MWVR
|
||||
{
|
||||
OpenXRManagerImpl::OpenXRManagerImpl()
|
||||
OpenXRManagerImpl::OpenXRManagerImpl(osg::GraphicsContext* gc)
|
||||
: mPlatform(gc)
|
||||
{
|
||||
logLayersAndExtensions();
|
||||
setupExtensionsAndLayers();
|
||||
|
||||
std::vector<const char*> extensions;
|
||||
for (auto& extension : mEnabledExtensions)
|
||||
extensions.push_back(extension.c_str());
|
||||
|
||||
|
||||
{ // Create Instance
|
||||
XrInstanceCreateInfo createInfo{ XR_TYPE_INSTANCE_CREATE_INFO };
|
||||
createInfo.next = nullptr;
|
||||
createInfo.enabledExtensionCount = extensions.size();
|
||||
createInfo.enabledExtensionNames = extensions.data();
|
||||
strcpy(createInfo.applicationInfo.applicationName, "openmw_vr");
|
||||
createInfo.applicationInfo.apiVersion = XR_CURRENT_API_VERSION;
|
||||
CHECK_XRCMD(xrCreateInstance(&createInfo, &mInstance));
|
||||
assert(mInstance);
|
||||
}
|
||||
mInstance = mPlatform.createXrInstance("openmw_vr");
|
||||
|
||||
setupDebugMessenger();
|
||||
|
||||
{
|
||||
// Layer depth is enabled, cache the invariant values
|
||||
if (xrExtensionIsEnabled(XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME))
|
||||
{
|
||||
|
@ -101,86 +69,18 @@ namespace MWVR
|
|||
layer.nearZ = nearClip;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{ // Get system ID
|
||||
// Get system ID
|
||||
XrSystemGetInfo systemInfo{ XR_TYPE_SYSTEM_GET_INFO };
|
||||
systemInfo.formFactor = mFormFactor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;
|
||||
CHECK_XRCMD(xrGetSystem(mInstance, &systemInfo, &mSystemId));
|
||||
assert(mSystemId);
|
||||
}
|
||||
|
||||
{ // Initialize OpenGL device
|
||||
// Despite its name, xrGetOpenGLGraphicsRequirementsKHR is a required function call that sets up an opengl instance.
|
||||
PFN_xrGetOpenGLGraphicsRequirementsKHR p_getRequirements = nullptr;
|
||||
xrGetInstanceProcAddr(mInstance, "xrGetOpenGLGraphicsRequirementsKHR", reinterpret_cast<PFN_xrVoidFunction*>(&p_getRequirements));
|
||||
XrGraphicsRequirementsOpenGLKHR requirements{ XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR };
|
||||
CHECK_XRCMD(p_getRequirements(mInstance, mSystemId, &requirements));
|
||||
|
||||
const XrVersion desiredApiVersion = XR_MAKE_VERSION(4, 6, 0);
|
||||
if (requirements.minApiVersionSupported > desiredApiVersion) {
|
||||
std::cout << "Runtime does not support desired Graphics API and/or version" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
{ // Create Session
|
||||
auto DC = wglGetCurrentDC();
|
||||
auto GLRC = wglGetCurrentContext();
|
||||
auto XRGLRC = wglCreateContext(DC);
|
||||
wglShareLists(GLRC, XRGLRC);
|
||||
|
||||
XrGraphicsBindingOpenGLWin32KHR graphicsBindings;
|
||||
graphicsBindings.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR;
|
||||
graphicsBindings.next = nullptr;
|
||||
graphicsBindings.hDC = DC;
|
||||
graphicsBindings.hGLRC = XRGLRC;
|
||||
|
||||
if (!graphicsBindings.hDC)
|
||||
Log(Debug::Warning) << "Missing DC";
|
||||
|
||||
XrSessionCreateInfo createInfo{ XR_TYPE_SESSION_CREATE_INFO };
|
||||
createInfo.next = &graphicsBindings;
|
||||
createInfo.systemId = mSystemId;
|
||||
CHECK_XRCMD(xrCreateSession(mInstance, &createInfo, &mSession));
|
||||
assert(mSession);
|
||||
}
|
||||
#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 = mSystemId;
|
||||
CHECK_XRCMD(xrCreateSession(mInstance, &createInfo, &mSession));
|
||||
assert(mSession);
|
||||
}
|
||||
#endif
|
||||
// Create session
|
||||
mSession = mPlatform.createXrSession(mInstance, mSystemId);
|
||||
|
||||
LogInstanceInfo();
|
||||
LogReferenceSpaces();
|
||||
LogSwapchainFormats();
|
||||
|
||||
{ // Set up reference space
|
||||
XrReferenceSpaceCreateInfo createInfo{ XR_TYPE_REFERENCE_SPACE_CREATE_INFO };
|
||||
|
@ -218,42 +118,6 @@ 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");
|
||||
}
|
||||
|
||||
if (XR_FAILED(res)) {
|
||||
std::stringstream ss;
|
||||
#ifdef _WIN32
|
||||
ss << sourceLocation << ": OpenXR[Error: " << to_string(res) << "][Thread: " << std::this_thread::get_id() << "]: " << originator;
|
||||
#elif __linux__
|
||||
ss << sourceLocation << ": OpenXR[Error: " << to_string(res) << "][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[" << to_string(res) << "][" << std::this_thread::get_id() << "]: " << originator;
|
||||
#elif __linux__
|
||||
Log(Debug::Verbose) << sourceLocation << ": OpenXR[" << to_string(res) << "][" << std::this_thread::get_id() << "]: " << originator;
|
||||
#endif
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string XrResultString(XrResult res)
|
||||
{
|
||||
return to_string(res);
|
||||
|
@ -264,82 +128,10 @@ namespace MWVR
|
|||
|
||||
}
|
||||
|
||||
|
||||
static std::vector<std::string> enumerateExtensions(const char* layerName, bool log = false, int logIndent = 2)
|
||||
{
|
||||
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)
|
||||
{
|
||||
extensionNames.push_back(extension.extensionName);
|
||||
if (log)
|
||||
Log(Debug::Verbose) << indentStr << "Name=" << extension.extensionName << " SpecVersion=" << extension.extensionVersion;
|
||||
}
|
||||
return extensionNames;
|
||||
}
|
||||
|
||||
#if !XR_KHR_composition_layer_depth \
|
||||
|| !XR_KHR_opengl_enable \
|
||||
|| !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 OpenXRManagerImpl::setupExtensionsAndLayers()
|
||||
{
|
||||
std::vector<const char*> requiredExtensions = {
|
||||
XR_KHR_OPENGL_ENABLE_EXTENSION_NAME,
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
for (auto& extension : enumerateExtensions(nullptr))
|
||||
mAvailableExtensions.insert(extension);
|
||||
|
||||
Log(Debug::Verbose) << "Using extensions:";
|
||||
|
||||
for (auto requiredExtension : requiredExtensions)
|
||||
enableExtension(requiredExtension, false);
|
||||
|
||||
for (auto optionalExtension : optionalExtensions)
|
||||
enableExtension(optionalExtension, true);
|
||||
|
||||
}
|
||||
|
||||
void OpenXRManagerImpl::enableExtension(const std::string& extension, bool optional)
|
||||
{
|
||||
if (mAvailableExtensions.count(extension) > 0)
|
||||
{
|
||||
Log(Debug::Verbose) << " " << extension << ": enabled";
|
||||
mEnabledExtensions.insert(extension);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log(Debug::Verbose) << " " << extension << ": disabled (not supported)";
|
||||
if (!optional)
|
||||
{
|
||||
throw std::runtime_error(std::string("Required OpenXR extension ") + extension + " not supported by the runtime");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static XrBool32 xrDebugCallback(
|
||||
XrDebugUtilsMessageSeverityFlagsEXT messageSeverity,
|
||||
XrDebugUtilsMessageTypeFlagsEXT messageType,
|
||||
|
@ -419,28 +211,6 @@ namespace MWVR
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
OpenXRManagerImpl::logLayersAndExtensions() {
|
||||
// Log layers and any of 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, true, 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;
|
||||
enumerateExtensions(layer.layerName, true, 4);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
OpenXRManagerImpl::LogInstanceInfo() {
|
||||
|
||||
|
@ -465,24 +235,6 @@ namespace MWVR
|
|||
Log(Debug::Verbose) << ss.str();
|
||||
}
|
||||
|
||||
void OpenXRManagerImpl::LogSwapchainFormats()
|
||||
{
|
||||
uint32_t swapchainFormatCount;
|
||||
CHECK_XRCMD(xrEnumerateSwapchainFormats(xrSession(), 0, &swapchainFormatCount, nullptr));
|
||||
std::vector<int64_t> swapchainFormats(swapchainFormatCount);
|
||||
CHECK_XRCMD(xrEnumerateSwapchainFormats(xrSession(), (uint32_t)swapchainFormats.size(), &swapchainFormatCount, swapchainFormats.data()));
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "Available Swapchain formats: (" << swapchainFormatCount << ")" << std::endl;
|
||||
|
||||
for (auto format : swapchainFormats)
|
||||
{
|
||||
ss << " Enum=" << std::dec << format << " (0x=" << std::hex << format << ")" << std::dec << std::endl;
|
||||
}
|
||||
|
||||
Log(Debug::Verbose) << ss.str();
|
||||
}
|
||||
|
||||
FrameInfo
|
||||
OpenXRManagerImpl::waitFrame()
|
||||
{
|
||||
|
@ -501,15 +253,6 @@ namespace MWVR
|
|||
return frameInfo;
|
||||
}
|
||||
|
||||
static void clearGlErrors()
|
||||
{
|
||||
auto error = glGetError();
|
||||
while (error != GL_NO_ERROR)
|
||||
{
|
||||
Log(Debug::Warning) << "glGetError: " << std::dec << error << " (0x" << std::hex << error << ")" << std::dec;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
OpenXRManagerImpl::beginFrame()
|
||||
{
|
||||
|
@ -859,7 +602,7 @@ namespace MWVR
|
|||
|
||||
bool OpenXRManagerImpl::xrExtensionIsEnabled(const char* extensionName) const
|
||||
{
|
||||
return mEnabledExtensions.count(extensionName) != 0;
|
||||
return mPlatform.extensionEnabled(extensionName);
|
||||
}
|
||||
|
||||
void OpenXRManagerImpl::xrResourceAcquired()
|
||||
|
@ -891,6 +634,18 @@ namespace MWVR
|
|||
return function;
|
||||
}
|
||||
|
||||
int64_t OpenXRManagerImpl::selectColorFormat()
|
||||
{
|
||||
// Find supported color swapchain format.
|
||||
return mPlatform.selectColorFormat();
|
||||
}
|
||||
|
||||
int64_t OpenXRManagerImpl::selectDepthFormat()
|
||||
{
|
||||
// Find supported depth swapchain format.
|
||||
return mPlatform.selectDepthFormat();
|
||||
}
|
||||
|
||||
void OpenXRManagerImpl::enablePredictions()
|
||||
{
|
||||
mPredictionsEnabled = true;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define OPENXR_MANAGER_IMPL_HPP
|
||||
|
||||
#include "openxrmanager.hpp"
|
||||
#include "openxrplatform.hpp"
|
||||
#include "../mwinput/inputmanagerimp.hpp"
|
||||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
|
@ -19,16 +20,6 @@
|
|||
|
||||
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);
|
||||
|
||||
/// Conversion methods from openxr types to osg/mwvr types. Includes managing the differing conventions.
|
||||
MWVR::Pose fromXR(XrPosef pose);
|
||||
MWVR::FieldOfView fromXR(XrFovf fov);
|
||||
|
@ -45,9 +36,10 @@ namespace MWVR
|
|||
XrSwapchainSubImage toXR(MWVR::SubImage, bool depthImage);
|
||||
|
||||
/// \brief Implementation of OpenXRManager
|
||||
struct OpenXRManagerImpl
|
||||
class OpenXRManagerImpl
|
||||
{
|
||||
OpenXRManagerImpl(void);
|
||||
public:
|
||||
OpenXRManagerImpl(osg::GraphicsContext* gc);
|
||||
~OpenXRManagerImpl(void);
|
||||
|
||||
FrameInfo waitFrame();
|
||||
|
@ -72,15 +64,15 @@ namespace MWVR
|
|||
void xrResourceReleased();
|
||||
void xrUpdateNames();
|
||||
PFN_xrVoidFunction xrGetFunction(const std::string& name);
|
||||
int64_t selectColorFormat();
|
||||
int64_t selectDepthFormat();
|
||||
OpenXRPlatform& platform() { return mPlatform; };
|
||||
|
||||
protected:
|
||||
void setupExtensionsAndLayers();
|
||||
void enableExtension(const std::string& extension, bool optional);
|
||||
void setupDebugMessenger(void);
|
||||
void logLayersAndExtensions();
|
||||
void LogInstanceInfo();
|
||||
void LogReferenceSpaces();
|
||||
void LogSwapchainFormats();
|
||||
bool xrNextEvent(XrEventDataBuffer& eventBuffer);
|
||||
void xrQueueEvents();
|
||||
const XrEventDataBaseHeader* nextEvent();
|
||||
|
@ -108,6 +100,8 @@ namespace MWVR
|
|||
XrSessionState mSessionState = XR_SESSION_STATE_UNKNOWN;
|
||||
XrDebugUtilsMessengerEXT mDebugMessenger{ nullptr };
|
||||
|
||||
OpenXRPlatform mPlatform;
|
||||
|
||||
bool mXrSessionShouldStop = false;
|
||||
bool mAppShouldSyncFrameLoop = false;
|
||||
bool mAppShouldRender = false;
|
||||
|
@ -115,8 +109,6 @@ namespace MWVR
|
|||
|
||||
uint32_t mAcquiredResources = 0;
|
||||
std::mutex mMutex{};
|
||||
std::set<std::string> mAvailableExtensions;
|
||||
std::set<std::string> mEnabledExtensions;
|
||||
std::queue<XrEventDataBuffer> mEventQueue;
|
||||
|
||||
std::array<XrCompositionLayerDepthInfoKHR, 2> mLayerDepth;
|
||||
|
|
656
apps/openmw/mwvr/openxrplatform.cpp
Normal file
656
apps/openmw/mwvr/openxrplatform.cpp
Normal file
|
@ -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
|
||||
}
|
||||
}
|
82
apps/openmw/mwvr/openxrplatform.hpp
Normal file
82
apps/openmw/mwvr/openxrplatform.hpp
Normal file
|
@ -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
|
|
@ -21,19 +21,9 @@ namespace MWVR {
|
|||
return impl().beginFrame(gc);
|
||||
}
|
||||
|
||||
void OpenXRSwapchain::endFrame(osg::GraphicsContext* gc)
|
||||
void OpenXRSwapchain::endFrame(osg::GraphicsContext* gc, VRFramebuffer& readBuffer)
|
||||
{
|
||||
return impl().endFrame(gc);
|
||||
}
|
||||
|
||||
uint32_t OpenXRSwapchain::acquiredColorTexture() const
|
||||
{
|
||||
return impl().acquiredColorTexture();
|
||||
}
|
||||
|
||||
uint32_t OpenXRSwapchain::acquiredDepthTexture() const
|
||||
{
|
||||
return impl().acquiredDepthTexture();
|
||||
return impl().endFrame(gc, readBuffer);
|
||||
}
|
||||
|
||||
int OpenXRSwapchain::width() const
|
||||
|
@ -55,9 +45,4 @@ namespace MWVR {
|
|||
{
|
||||
return impl().isAcquired();
|
||||
}
|
||||
|
||||
VRFramebuffer* OpenXRSwapchain::renderBuffer() const
|
||||
{
|
||||
return impl().renderBuffer();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,13 +22,7 @@ namespace MWVR
|
|||
void beginFrame(osg::GraphicsContext* gc);
|
||||
|
||||
//! Finalize render
|
||||
void endFrame(osg::GraphicsContext* gc);
|
||||
|
||||
//! Currently acquired color texture
|
||||
uint32_t acquiredColorTexture() const;
|
||||
|
||||
//! Currently acquired depth texture
|
||||
uint32_t acquiredDepthTexture() const;
|
||||
void endFrame(osg::GraphicsContext* gc, VRFramebuffer& readBuffer);
|
||||
|
||||
//! Whether subchain is currently acquired (true) or released (false)
|
||||
bool isAcquired() const;
|
||||
|
@ -42,9 +36,6 @@ namespace MWVR
|
|||
//! Samples of the view surface
|
||||
int samples() const;
|
||||
|
||||
//! Get the current texture
|
||||
VRFramebuffer* renderBuffer() const;
|
||||
|
||||
//! Get the private implementation
|
||||
OpenXRSwapchainImpl& impl() { return *mPrivate; }
|
||||
|
||||
|
|
223
apps/openmw/mwvr/openxrswapchainimage.cpp
Normal file
223
apps/openmw/mwvr/openxrswapchainimage.cpp
Normal file
|
@ -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()
|
||||
{
|
||||
}
|
||||
}
|
27
apps/openmw/mwvr/openxrswapchainimage.hpp
Normal file
27
apps/openmw/mwvr/openxrswapchainimage.hpp
Normal file
|
@ -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
|
|
@ -5,24 +5,6 @@
|
|||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#include <objbase.h>
|
||||
|
||||
#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>
|
||||
|
||||
namespace MWVR {
|
||||
OpenXRSwapchainImpl::OpenXRSwapchainImpl(osg::ref_ptr<osg::State> state, SwapchainConfig config)
|
||||
: mConfig(config)
|
||||
|
@ -51,44 +33,12 @@ namespace MWVR {
|
|||
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;
|
||||
|
@ -96,29 +46,32 @@ namespace MWVR {
|
|||
|
||||
void OpenXRSwapchainImpl::beginFrame(osg::GraphicsContext* gc)
|
||||
{
|
||||
acquire();
|
||||
acquire(gc);
|
||||
}
|
||||
|
||||
int swapCount = 0;
|
||||
|
||||
void OpenXRSwapchainImpl::endFrame(osg::GraphicsContext* gc)
|
||||
void OpenXRSwapchainImpl::endFrame(osg::GraphicsContext* gc, VRFramebuffer& readBuffer)
|
||||
{
|
||||
checkAcquired();
|
||||
release();
|
||||
release(gc, readBuffer);
|
||||
}
|
||||
|
||||
void OpenXRSwapchainImpl::acquire()
|
||||
void OpenXRSwapchainImpl::acquire(osg::GraphicsContext* gc)
|
||||
{
|
||||
if (isAcquired())
|
||||
throw std::logic_error("Trying to acquire already acquired swapchain");
|
||||
|
||||
// The openxr runtime may fail to acquire/release.
|
||||
// Do not re-acquire a swapchain before having successfully released it.
|
||||
// Lest the swapchain fall out of sync.
|
||||
if (!mShouldRelease)
|
||||
{
|
||||
mSwapchain->acquire();
|
||||
mSwapchain->acquire(gc);
|
||||
mShouldRelease = mSwapchain->isAcquired();
|
||||
if (mSwapchainDepth && mSwapchain->isAcquired())
|
||||
{
|
||||
mSwapchainDepth->acquire();
|
||||
mSwapchainDepth->acquire(gc);
|
||||
mShouldRelease = mSwapchainDepth->isAcquired();
|
||||
}
|
||||
}
|
||||
|
@ -126,15 +79,17 @@ namespace MWVR {
|
|||
mFormallyAcquired = true;
|
||||
}
|
||||
|
||||
void OpenXRSwapchainImpl::release()
|
||||
void OpenXRSwapchainImpl::release(osg::GraphicsContext* gc, VRFramebuffer& readBuffer)
|
||||
{
|
||||
// The openxr runtime may fail to acquire/release.
|
||||
// Do not release a swapchain before having successfully acquire it.
|
||||
if (mShouldRelease)
|
||||
{
|
||||
mSwapchain->release();
|
||||
mSwapchain->blitAndRelease(gc, readBuffer);
|
||||
mShouldRelease = mSwapchain->isAcquired();
|
||||
if (mSwapchainDepth)
|
||||
{
|
||||
mSwapchainDepth->release();
|
||||
mSwapchainDepth->blitAndRelease(gc, readBuffer);
|
||||
mShouldRelease = mSwapchainDepth->isAcquired();
|
||||
}
|
||||
}
|
||||
|
@ -148,69 +103,21 @@ namespace MWVR {
|
|||
throw std::logic_error("Swapchain must be acquired before use. Call between OpenXRSwapchain::beginFrame() and OpenXRSwapchain::endFrame()");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
OpenXRSwapchainImpl::SwapchainPrivate::SwapchainPrivate(osg::ref_ptr<osg::State> state, SwapchainConfig config, Use use)
|
||||
: mBuffers()
|
||||
: mConfig(config)
|
||||
, mImages()
|
||||
, mWidth(config.selectedWidth)
|
||||
, mHeight(config.selectedHeight)
|
||||
, mSamples(config.selectedSamples)
|
||||
, mSamples(1)
|
||||
, mUsage(use)
|
||||
{
|
||||
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()));
|
||||
|
||||
if (use == Use::COLOR)
|
||||
mFormat = selectColorFormat(swapchainFormats);
|
||||
mFormat = xr->selectColorFormat();
|
||||
else
|
||||
mFormat = selectDepthFormat(swapchainFormats);
|
||||
mFormat = xr->selectDepthFormat();
|
||||
std::string typeString = use == Use::COLOR ? "color" : "depth";
|
||||
|
||||
if (mFormat == 0) {
|
||||
|
@ -236,7 +143,10 @@ namespace MWVR {
|
|||
// First create the swapchain of color buffers.
|
||||
swapchainCreateInfo.format = mFormat;
|
||||
swapchainCreateInfo.sampleCount = mSamples;
|
||||
if(use == Use::COLOR)
|
||||
swapchainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
else
|
||||
swapchainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
auto res = xrCreateSwapchain(xr->impl().xrSession(), &swapchainCreateInfo, &mSwapchain);
|
||||
if (!XR_SUCCEEDED(res))
|
||||
{
|
||||
|
@ -249,10 +159,8 @@ namespace MWVR {
|
|||
VrDebug::setName(mSwapchain, "OpenMW XR Color Swapchain " + config.name);
|
||||
}
|
||||
|
||||
uint32_t imageCount = 0;
|
||||
CHECK_XRCMD(xrEnumerateSwapchainImages(mSwapchain, 0, &imageCount, nullptr));
|
||||
mBuffers.resize(imageCount, { XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR });
|
||||
CHECK_XRCMD(xrEnumerateSwapchainImages(mSwapchain, imageCount, &imageCount, reinterpret_cast<XrSwapchainImageBaseHeader*>(mBuffers.data())));
|
||||
// TODO: here
|
||||
mImages = OpenXRSwapchainImage::enumerateSwapchainImages(state->getGraphicsContext(), mSwapchain, swapchainCreateInfo);
|
||||
mSubImage.swapchain = mSwapchain;
|
||||
mSubImage.imageRect.offset = { 0, 0 };
|
||||
mSubImage.imageRect.extent = { mWidth, mHeight };
|
||||
|
@ -264,27 +172,17 @@ namespace MWVR {
|
|||
CHECK_XRCMD(xrDestroySwapchain(mSwapchain));
|
||||
}
|
||||
|
||||
uint32_t OpenXRSwapchainImpl::SwapchainPrivate::bufferAt(uint32_t index) const
|
||||
{
|
||||
return mBuffers[index].image;
|
||||
}
|
||||
|
||||
uint32_t OpenXRSwapchainImpl::SwapchainPrivate::count() const
|
||||
{
|
||||
return mBuffers.size();
|
||||
return mImages.size();
|
||||
}
|
||||
|
||||
uint32_t OpenXRSwapchainImpl::SwapchainPrivate::acuiredBuffer() const
|
||||
{
|
||||
checkAcquired();
|
||||
return mBuffers[mAcquiredIndex].image;
|
||||
}
|
||||
bool OpenXRSwapchainImpl::SwapchainPrivate::isAcquired() const
|
||||
{
|
||||
return mIsReady;
|
||||
}
|
||||
|
||||
void OpenXRSwapchainImpl::SwapchainPrivate::acquire()
|
||||
void OpenXRSwapchainImpl::SwapchainPrivate::acquire(osg::GraphicsContext* gc)
|
||||
{
|
||||
auto xr = Environment::get().getManager();
|
||||
XrSwapchainImageAcquireInfo acquireInfo{ XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO };
|
||||
|
@ -301,13 +199,15 @@ namespace MWVR {
|
|||
mIsReady = XR_SUCCEEDED(CHECK_XRCMD(xrWaitSwapchainImage(mSwapchain, &waitInfo)));
|
||||
}
|
||||
}
|
||||
void OpenXRSwapchainImpl::SwapchainPrivate::release()
|
||||
void OpenXRSwapchainImpl::SwapchainPrivate::blitAndRelease(osg::GraphicsContext* gc, VRFramebuffer& readBuffer)
|
||||
{
|
||||
auto xr = Environment::get().getManager();
|
||||
|
||||
XrSwapchainImageReleaseInfo releaseInfo{ XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO };
|
||||
if (mIsReady)
|
||||
{
|
||||
mImages[mAcquiredIndex]->blit(gc, readBuffer, mConfig.offsetWidth, mConfig.offsetHeight);
|
||||
|
||||
mIsReady = !XR_SUCCEEDED(CHECK_XRCMD(xrReleaseSwapchainImage(mSwapchain, &releaseInfo)));
|
||||
if (!mIsReady)
|
||||
{
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
#ifndef OPENXR_SWAPCHAINIMPL_HPP
|
||||
#define OPENXR_SWAPCHAINIMPL_HPP
|
||||
|
||||
#include "openxrswapchain.hpp"
|
||||
#include "openxrswapchainimage.hpp"
|
||||
#include "openxrmanagerimpl.hpp"
|
||||
|
||||
struct XrSwapchainSubImage;
|
||||
struct XrSwapchainImageOpenGLKHR;
|
||||
|
||||
namespace MWVR
|
||||
{
|
||||
class VRFramebuffer;
|
||||
|
||||
/// \brief Implementation of OpenXRSwapchain
|
||||
class OpenXRSwapchainImpl
|
||||
{
|
||||
|
@ -23,30 +24,32 @@ namespace MWVR
|
|||
SwapchainPrivate(osg::ref_ptr<osg::State> state, SwapchainConfig config, Use use);
|
||||
~SwapchainPrivate();
|
||||
|
||||
uint32_t bufferAt(uint32_t index) const;
|
||||
uint32_t count() const;
|
||||
uint32_t acuiredBuffer() const;
|
||||
uint32_t acuiredIndex() const { return mAcquiredIndex; };
|
||||
bool isAcquired() const;
|
||||
uint32_t acuiredIndex() const { return mAcquiredIndex; };
|
||||
XrSwapchain xrSwapchain(void) const { return mSwapchain; };
|
||||
XrSwapchainSubImage xrSubImage(void) const { return mSubImage; };
|
||||
int width() const { return mWidth; };
|
||||
int height() const { return mHeight; };
|
||||
int samples() const { return mSamples; };
|
||||
|
||||
void acquire();
|
||||
void release();
|
||||
void acquire(osg::GraphicsContext* gc);
|
||||
void blitAndRelease(osg::GraphicsContext* gc, VRFramebuffer& readBuffer);
|
||||
void checkAcquired() const;
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
SwapchainConfig mConfig;
|
||||
XrSwapchain mSwapchain = XR_NULL_HANDLE;
|
||||
XrSwapchainSubImage mSubImage{};
|
||||
std::vector<XrSwapchainImageOpenGLKHR> mBuffers;
|
||||
std::vector< std::unique_ptr<OpenXRSwapchainImage> > mImages;
|
||||
int32_t mWidth = -1;
|
||||
int32_t mHeight = -1;
|
||||
int32_t mSamples = -1;
|
||||
int64_t mFormat = -1;
|
||||
uint32_t mAcquiredIndex{ 0 };
|
||||
Use mUsage;
|
||||
bool mIsIndexAcquired{ false };
|
||||
bool mIsReady{ false };
|
||||
};
|
||||
|
@ -56,11 +59,7 @@ namespace MWVR
|
|||
~OpenXRSwapchainImpl();
|
||||
|
||||
void beginFrame(osg::GraphicsContext* gc);
|
||||
void endFrame(osg::GraphicsContext* gc);
|
||||
|
||||
VRFramebuffer* renderBuffer() const;
|
||||
uint32_t acquiredColorTexture() const;
|
||||
uint32_t acquiredDepthTexture() const;
|
||||
void endFrame(osg::GraphicsContext* gc, VRFramebuffer& readBuffer);
|
||||
|
||||
bool isAcquired() const;
|
||||
XrSwapchain xrSwapchain(void) const { return mSwapchain->xrSwapchain(); };
|
||||
|
@ -75,15 +74,14 @@ namespace MWVR
|
|||
OpenXRSwapchainImpl(const OpenXRSwapchainImpl&) = delete;
|
||||
void operator=(const OpenXRSwapchainImpl&) = delete;
|
||||
|
||||
void acquire();
|
||||
void release();
|
||||
void acquire(osg::GraphicsContext* gc);
|
||||
void release(osg::GraphicsContext* gc, VRFramebuffer& readBuffer);
|
||||
void checkAcquired() const;
|
||||
|
||||
private:
|
||||
SwapchainConfig mConfig;
|
||||
std::unique_ptr<SwapchainPrivate> mSwapchain{ nullptr };
|
||||
std::unique_ptr<SwapchainPrivate> mSwapchainDepth{ nullptr };
|
||||
std::vector<std::unique_ptr<VRFramebuffer> > mRenderBuffers{};
|
||||
bool mFormallyAcquired{ false };
|
||||
bool mShouldRelease{ false };
|
||||
};
|
||||
|
|
|
@ -11,65 +11,50 @@
|
|||
namespace MWVR
|
||||
{
|
||||
|
||||
VRFramebuffer::VRFramebuffer(osg::ref_ptr<osg::State> state, std::size_t width, std::size_t height, uint32_t msaaSamples, uint32_t colorBuffer, uint32_t depthBuffer)
|
||||
VRFramebuffer::VRFramebuffer(osg::ref_ptr<osg::State> state, std::size_t width, std::size_t height, uint32_t msaaSamples)
|
||||
: mState(state)
|
||||
, mWidth(width)
|
||||
, mHeight(height)
|
||||
, mDepthBuffer(depthBuffer)
|
||||
, mColorBuffer(colorBuffer)
|
||||
, mDepthBuffer()
|
||||
, mColorBuffer()
|
||||
, mSamples(msaaSamples)
|
||||
{
|
||||
auto* gl = osg::GLExtensions::Get(state->getContextID(), false);
|
||||
|
||||
gl->glGenFramebuffers(1, &mBlitFBO);
|
||||
gl->glBindFramebuffer(GL_FRAMEBUFFER_EXT, mBlitFBO);
|
||||
|
||||
gl->glGenFramebuffers(1, &mFBO);
|
||||
|
||||
if (mSamples <= 1)
|
||||
mTextureTarget = GL_TEXTURE_2D;
|
||||
else
|
||||
mTextureTarget = GL_TEXTURE_2D_MULTISAMPLE;
|
||||
|
||||
if (mColorBuffer == 0)
|
||||
{
|
||||
glGenTextures(1, &mColorBuffer);
|
||||
glBindTexture(mTextureTarget, mColorBuffer);
|
||||
if (mSamples <= 1)
|
||||
glTexImage2D(mTextureTarget, 0, GL_RGBA, mWidth, mHeight, 0, GL_RGBA, GL_UNSIGNED_INT, nullptr);
|
||||
else
|
||||
gl->glTexImage2DMultisample(mTextureTarget, mSamples, GL_RGBA, mWidth, mHeight, false);
|
||||
glTexParameteri(mTextureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER_ARB);
|
||||
glTexParameteri(mTextureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER_ARB);
|
||||
glTexParameteri(mTextureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(mTextureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(mTextureTarget, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
}
|
||||
|
||||
if (mDepthBuffer == 0)
|
||||
void VRFramebuffer::setColorBuffer(osg::GraphicsContext* gc, uint32_t colorBuffer, bool takeOwnership)
|
||||
{
|
||||
glGenTextures(1, &mDepthBuffer);
|
||||
glBindTexture(mTextureTarget, mDepthBuffer);
|
||||
if (mSamples <= 1)
|
||||
glTexImage2D(mTextureTarget, 0, GL_DEPTH_COMPONENT24, mWidth, mHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
|
||||
else
|
||||
gl->glTexImage2DMultisample(mTextureTarget, mSamples, GL_DEPTH_COMPONENT, mWidth, mHeight, false);
|
||||
glTexParameteri(mTextureTarget, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(mTextureTarget, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
glTexParameteri(mTextureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(mTextureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(mTextureTarget, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
auto* gl = osg::GLExtensions::Get(gc->getState()->getContextID(), false);
|
||||
mColorBuffer.setTexture(colorBuffer, takeOwnership);
|
||||
bindFramebuffer(gc, GL_FRAMEBUFFER_EXT);
|
||||
gl->glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, mTextureTarget, mColorBuffer.mImage, 0);
|
||||
}
|
||||
|
||||
void VRFramebuffer::setDepthBuffer(osg::GraphicsContext* gc, uint32_t depthBuffer, bool takeOwnership)
|
||||
{
|
||||
auto* gl = osg::GLExtensions::Get(gc->getState()->getContextID(), false);
|
||||
mDepthBuffer.setTexture(depthBuffer, takeOwnership);
|
||||
bindFramebuffer(gc, GL_FRAMEBUFFER_EXT);
|
||||
gl->glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, mTextureTarget, mDepthBuffer.mImage, 0);
|
||||
}
|
||||
|
||||
gl->glBindFramebuffer(GL_FRAMEBUFFER_EXT, mFBO);
|
||||
gl->glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, mTextureTarget, mColorBuffer, 0);
|
||||
gl->glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, mTextureTarget, mDepthBuffer, 0);
|
||||
if (gl->glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)
|
||||
throw std::runtime_error("Failed to create OpenXR framebuffer");
|
||||
void VRFramebuffer::createColorBuffer(osg::GraphicsContext* gc)
|
||||
{
|
||||
auto colorBuffer = createImage(gc, GL_RGBA8, GL_RGBA);
|
||||
setColorBuffer(gc, colorBuffer, true);
|
||||
}
|
||||
|
||||
|
||||
gl->glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
|
||||
void VRFramebuffer::createDepthBuffer(osg::GraphicsContext* gc)
|
||||
{
|
||||
auto depthBuffer = createImage(gc, GL_DEPTH24_STENCIL8_EXT, GL_DEPTH_COMPONENT);
|
||||
setDepthBuffer(gc, depthBuffer, true);
|
||||
}
|
||||
|
||||
VRFramebuffer::~VRFramebuffer()
|
||||
|
@ -94,28 +79,65 @@ namespace MWVR
|
|||
else if (mFBO)
|
||||
// Without access to glDeleteFramebuffers, i'll have to leak FBOs.
|
||||
Log(Debug::Warning) << "destroy() called without a State. Leaking FBO";
|
||||
mFBO = 0;
|
||||
|
||||
if (mDepthBuffer)
|
||||
glDeleteTextures(1, &mDepthBuffer);
|
||||
if (mColorBuffer)
|
||||
glDeleteTextures(1, &mColorBuffer);
|
||||
|
||||
mFBO = mDepthBuffer = mColorBuffer = 0;
|
||||
mColorBuffer.delet();
|
||||
mDepthBuffer.delet();
|
||||
}
|
||||
|
||||
void VRFramebuffer::bindFramebuffer(osg::GraphicsContext* gc, uint32_t target)
|
||||
{
|
||||
auto state = gc->getState();
|
||||
auto* gl = osg::GLExtensions::Get(state->getContextID(), false);
|
||||
//if (gl->glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)
|
||||
// throw std::runtime_error("Tried to bind incomplete framebuffer");
|
||||
gl->glBindFramebuffer(target, mFBO);
|
||||
}
|
||||
|
||||
void VRFramebuffer::blit(osg::GraphicsContext* gc, int x, int y, int w, int h)
|
||||
void VRFramebuffer::blit(osg::GraphicsContext* gc, int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0, int dstX1, int dstY1, uint32_t bits, uint32_t filter)
|
||||
{
|
||||
#define GLERR if(auto err = glGetError() != GL_NO_ERROR) Log(Debug::Verbose) << __FILE__ << "." << __LINE__ << ": " << glGetError()
|
||||
auto* state = gc->getState();
|
||||
auto* gl = osg::GLExtensions::Get(state->getContextID(), false);
|
||||
gl->glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, mFBO);
|
||||
gl->glBlitFramebuffer(0, 0, mWidth, mHeight, x, y, w, h, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||
gl->glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, bits, filter);
|
||||
gl->glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, 0);
|
||||
}
|
||||
|
||||
uint32_t VRFramebuffer::createImage(osg::GraphicsContext* gc, uint32_t formatInternal, uint32_t format)
|
||||
{
|
||||
auto* gl = osg::GLExtensions::Get(gc->getState()->getContextID(), false);
|
||||
uint32_t image;
|
||||
glGenTextures(1, &image);
|
||||
glBindTexture(mTextureTarget, image);
|
||||
if (mSamples <= 1)
|
||||
glTexImage2D(mTextureTarget, 0, formatInternal, mWidth, mHeight, 0, format, GL_UNSIGNED_INT, nullptr);
|
||||
else
|
||||
gl->glTexImage2DMultisample(mTextureTarget, mSamples, format, mWidth, mHeight, false);
|
||||
glTexParameteri(mTextureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER_ARB);
|
||||
glTexParameteri(mTextureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER_ARB);
|
||||
glTexParameteri(mTextureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(mTextureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(mTextureTarget, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
void VRFramebuffer::Texture::delet()
|
||||
{
|
||||
if (mOwner)
|
||||
glDeleteTextures(1, &mImage);
|
||||
|
||||
mImage = 0;
|
||||
mOwner = false;
|
||||
}
|
||||
|
||||
void VRFramebuffer::Texture::setTexture(uint32_t image, bool owner)
|
||||
{
|
||||
if (mImage)
|
||||
delet();
|
||||
|
||||
mImage = image;
|
||||
mOwner = owner;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,10 +13,20 @@ namespace MWVR
|
|||
/// \brief Manages an opengl framebuffer
|
||||
///
|
||||
/// Intended for managing the vr swapchain, but is also use to manage the mirror texture as a convenience.
|
||||
class VRFramebuffer : public osg::Referenced
|
||||
class VRFramebuffer
|
||||
{
|
||||
private:
|
||||
struct Texture
|
||||
{
|
||||
uint32_t mImage = 0;
|
||||
bool mOwner = false;
|
||||
|
||||
void delet();
|
||||
void setTexture(uint32_t image, bool owner);
|
||||
};
|
||||
|
||||
public:
|
||||
VRFramebuffer(osg::ref_ptr<osg::State> state, std::size_t width, std::size_t height, uint32_t msaaSamples, uint32_t colorBuffer = 0, uint32_t depthBuffer = 0);
|
||||
VRFramebuffer(osg::ref_ptr<osg::State> state, std::size_t width, std::size_t height, uint32_t msaaSamples);
|
||||
~VRFramebuffer();
|
||||
|
||||
void destroy(osg::State* state);
|
||||
|
@ -27,13 +37,20 @@ namespace MWVR
|
|||
|
||||
void bindFramebuffer(osg::GraphicsContext* gc, uint32_t target);
|
||||
|
||||
uint32_t fbo(void) const { return mFBO; }
|
||||
uint32_t colorBuffer(void) const { return mColorBuffer; }
|
||||
void setColorBuffer(osg::GraphicsContext* gc, uint32_t colorBuffer, bool takeOwnership);
|
||||
void setDepthBuffer(osg::GraphicsContext* gc, uint32_t depthBuffer, bool takeOwnership);
|
||||
void createColorBuffer(osg::GraphicsContext* gc);
|
||||
void createDepthBuffer(osg::GraphicsContext* gc);
|
||||
|
||||
//! Blit to region in currently bound draw fbo
|
||||
void blit(osg::GraphicsContext* gc, int x, int y, int w, int h);
|
||||
//! ref glBlitFramebuffer
|
||||
void blit(osg::GraphicsContext* gc, int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0, int dstX1, int dstY1, uint32_t bits, uint32_t filter = GL_LINEAR);
|
||||
|
||||
uint32_t colorBuffer() const { return mColorBuffer.mImage; };
|
||||
uint32_t depthBuffer() const { return mDepthBuffer.mImage; };
|
||||
|
||||
private:
|
||||
uint32_t createImage(osg::GraphicsContext* gc, uint32_t formatInternal, uint32_t format);
|
||||
|
||||
// Set aside a weak pointer to the constructor state to use when freeing FBOs, if no state is given to destroy()
|
||||
osg::observer_ptr<osg::State> mState;
|
||||
|
||||
|
@ -43,11 +60,8 @@ namespace MWVR
|
|||
|
||||
// Render Target
|
||||
uint32_t mFBO = 0;
|
||||
uint32_t mBlitFBO = 0;
|
||||
uint32_t mDepthBuffer = 0;
|
||||
bool mOwnDepthBuffer = false;
|
||||
uint32_t mColorBuffer = 0;
|
||||
bool mOwnColorBuffer = false;
|
||||
Texture mDepthBuffer;
|
||||
Texture mColorBuffer;
|
||||
uint32_t mSamples = 0;
|
||||
uint32_t mTextureTarget = 0;
|
||||
};
|
||||
|
|
|
@ -218,7 +218,7 @@ namespace MWVR
|
|||
{
|
||||
std::string extension = requireAttribute(extensionElement, "Name");
|
||||
auto xr = MWVR::Environment::get().getManager();
|
||||
if (!xr->xrExtensionIsEnabled(XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME))
|
||||
if (!xr->xrExtensionIsEnabled(extension.c_str()))
|
||||
{
|
||||
Log(Debug::Verbose) << " Required extension '" << extension << "' not supported. Skipping interaction profile.";
|
||||
return;
|
||||
|
|
|
@ -143,7 +143,7 @@ namespace MWVR
|
|||
{
|
||||
if (frameMeta->mShouldRender)
|
||||
{
|
||||
viewer.blitEyesToMirrorTexture(gc);
|
||||
viewer.blit(gc);
|
||||
gc->swapBuffersImplementation();
|
||||
std::array<CompositionLayerProjectionView, 2> layerStack{};
|
||||
layerStack[(int)Side::LEFT_SIDE].subImage = viewer.subImage(Side::LEFT_SIDE);
|
||||
|
@ -239,8 +239,8 @@ namespace MWVR
|
|||
xr->enablePredictions();
|
||||
predictedPoses.head = xr->getPredictedHeadPose(frame->mPredictedDisplayTime, ReferenceSpace::STAGE) * mPlayerScale;
|
||||
auto hmdViews = xr->getPredictedViews(frame->mPredictedDisplayTime, ReferenceSpace::VIEW);
|
||||
predictedPoses.view[(int)Side::LEFT_SIDE].pose = hmdViews[(int)Side::LEFT_SIDE].pose * mPlayerScale;
|
||||
predictedPoses.view[(int)Side::RIGHT_SIDE].pose = hmdViews[(int)Side::RIGHT_SIDE].pose * mPlayerScale;
|
||||
predictedPoses.view[(int)Side::LEFT_SIDE].pose = hmdViews[(int)Side::LEFT_SIDE].pose * mPlayerScale * Constants::UnitsPerMeter;
|
||||
predictedPoses.view[(int)Side::RIGHT_SIDE].pose = hmdViews[(int)Side::RIGHT_SIDE].pose * mPlayerScale * Constants::UnitsPerMeter;
|
||||
predictedPoses.view[(int)Side::LEFT_SIDE].fov = hmdViews[(int)Side::LEFT_SIDE].fov;
|
||||
predictedPoses.view[(int)Side::RIGHT_SIDE].fov = hmdViews[(int)Side::RIGHT_SIDE].fov;
|
||||
auto stageViews = xr->getPredictedViews(frame->mPredictedDisplayTime, ReferenceSpace::STAGE);
|
||||
|
|
|
@ -122,6 +122,8 @@ namespace MWVR
|
|||
int selectedWidth = -1;
|
||||
int selectedHeight = -1;
|
||||
int selectedSamples = -1;
|
||||
int offsetWidth = 0;
|
||||
int offsetHeight = 0;
|
||||
std::string name = "";
|
||||
};
|
||||
|
||||
|
|
|
@ -42,10 +42,11 @@ namespace MWVR
|
|||
: mViewer(viewer)
|
||||
, mPreDraw(new PredrawCallback(this))
|
||||
, mPostDraw(new PostdrawCallback(this))
|
||||
, mUpdateViewCallback(new UpdateViewCallback(this))
|
||||
, mMsaaResolveTexture{}
|
||||
, mMirrorTexture{ nullptr }
|
||||
, mOpenXRConfigured(false)
|
||||
, mCallbacksConfigured(false)
|
||||
, mMsaaResolveMirrorTexture{}
|
||||
, mMirrorTexture{ nullptr }
|
||||
{
|
||||
mViewer->setRealizeOperation(new RealizeOperation());
|
||||
}
|
||||
|
@ -94,7 +95,7 @@ namespace MWVR
|
|||
return VRViewer::MirrorTextureEye::Both;
|
||||
}
|
||||
|
||||
void VRViewer::configureXR(osg::GraphicsContext* context)
|
||||
void VRViewer::configureXR(osg::GraphicsContext* gc)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mMutex);
|
||||
|
||||
|
@ -105,14 +106,14 @@ namespace MWVR
|
|||
|
||||
|
||||
auto* xr = Environment::get().getManager();
|
||||
xr->realize(context);
|
||||
xr->realize(gc);
|
||||
|
||||
// Run through initial events to start session
|
||||
// For the rest of runtime this is handled by vrsession
|
||||
xr->handleEvents();
|
||||
|
||||
// Set up swapchain config
|
||||
auto config = xr->getRecommendedSwapchainConfig();
|
||||
mSwapchainConfig = xr->getRecommendedSwapchainConfig();
|
||||
|
||||
std::array<std::string, 2> xConfString;
|
||||
std::array<std::string, 2> yConfString;
|
||||
|
@ -126,41 +127,41 @@ namespace MWVR
|
|||
{
|
||||
auto name = sViewNames[i];
|
||||
|
||||
config[i].selectedWidth = parseResolution(xConfString[i], config[i].recommendedWidth, config[i].maxWidth);
|
||||
config[i].selectedHeight = parseResolution(yConfString[i], config[i].recommendedHeight, config[i].maxHeight);
|
||||
mSwapchainConfig[i].selectedWidth = parseResolution(xConfString[i], mSwapchainConfig[i].recommendedWidth, mSwapchainConfig[i].maxWidth);
|
||||
mSwapchainConfig[i].selectedHeight = parseResolution(yConfString[i], mSwapchainConfig[i].recommendedHeight, mSwapchainConfig[i].maxHeight);
|
||||
|
||||
config[i].selectedSamples = Settings::Manager::getInt("antialiasing", "Video");
|
||||
// OpenXR requires a non-zero value
|
||||
if (config[i].selectedSamples < 1)
|
||||
config[i].selectedSamples = 1;
|
||||
mSwapchainConfig[i].selectedSamples =
|
||||
std::max(1, // OpenXR requires a non-zero value
|
||||
std::min(mSwapchainConfig[i].maxSamples,
|
||||
Settings::Manager::getInt("antialiasing", "Video")
|
||||
)
|
||||
);
|
||||
|
||||
Log(Debug::Verbose) << name << " resolution: Recommended x=" << config[i].recommendedWidth << ", y=" << config[i].recommendedHeight;
|
||||
Log(Debug::Verbose) << name << " resolution: Max x=" << config[i].maxWidth << ", y=" << config[i].maxHeight;
|
||||
Log(Debug::Verbose) << name << " resolution: Selected x=" << config[i].selectedWidth << ", y=" << config[i].selectedHeight;
|
||||
Log(Debug::Verbose) << name << " resolution: Recommended x=" << mSwapchainConfig[i].recommendedWidth << ", y=" << mSwapchainConfig[i].recommendedHeight;
|
||||
Log(Debug::Verbose) << name << " resolution: Max x=" << mSwapchainConfig[i].maxWidth << ", y=" << mSwapchainConfig[i].maxHeight;
|
||||
Log(Debug::Verbose) << name << " resolution: Selected x=" << mSwapchainConfig[i].selectedWidth << ", y=" << mSwapchainConfig[i].selectedHeight;
|
||||
|
||||
config[i].name = sViewNames[i];
|
||||
|
||||
mSubImages[i].width = config[i].selectedWidth;
|
||||
mSubImages[i].height = config[i].selectedHeight;
|
||||
mSwapchainConfig[i].name = sViewNames[i];
|
||||
if (i > 0)
|
||||
{
|
||||
mSubImages[i].x = mSubImages[i - 1].x + mSubImages[i - 1].width;
|
||||
}
|
||||
else
|
||||
{
|
||||
mSubImages[i].x = 0;
|
||||
}
|
||||
mSubImages[i].y = 0;
|
||||
mSwapchainConfig[i].offsetWidth = mSwapchainConfig[i].selectedWidth + mSwapchainConfig[i].offsetWidth;
|
||||
|
||||
mSwapchain[i].reset(new OpenXRSwapchain(gc->getState(), mSwapchainConfig[i]));
|
||||
mSubImages[i].width = mSwapchainConfig[i].selectedWidth;
|
||||
mSubImages[i].height = mSwapchainConfig[i].selectedHeight;
|
||||
mSubImages[i].x = mSubImages[i].y = 0;
|
||||
mSubImages[i].swapchain = mSwapchain[i].get();
|
||||
}
|
||||
|
||||
mSwapchainConfig.name = "Main";
|
||||
mSwapchainConfig.selectedWidth = config[0].selectedWidth + config[1].selectedWidth;
|
||||
mSwapchainConfig.selectedHeight = std::max(config[0].selectedHeight, config[1].selectedHeight);
|
||||
mSwapchainConfig.selectedSamples = std::max(config[0].selectedSamples, config[1].selectedSamples);
|
||||
int width = mSubImages[0].width + mSubImages[1].width;
|
||||
int height = std::max(mSubImages[0].height, mSubImages[1].height);
|
||||
int samples = std::max(mSwapchainConfig[0].selectedSamples, mSwapchainConfig[1].selectedSamples);
|
||||
|
||||
mSwapchain.reset(new OpenXRSwapchain(context->getState(), mSwapchainConfig));
|
||||
|
||||
mSubImages[0].swapchain = mSubImages[1].swapchain = mSwapchain.get();
|
||||
mFramebuffer.reset(new VRFramebuffer(gc->getState(),width,height, samples));
|
||||
mFramebuffer->createColorBuffer(gc);
|
||||
mFramebuffer->createDepthBuffer(gc);
|
||||
mMsaaResolveTexture.reset(new VRFramebuffer(gc->getState(),width,height,0));
|
||||
mMsaaResolveTexture->createColorBuffer(gc);
|
||||
mMsaaResolveTexture->createDepthBuffer(gc);
|
||||
|
||||
mViewer->setReleaseContextAtEndOfFrameHint(false);
|
||||
mViewer->getCamera()->getGraphicsContext()->setSwapCallback(new VRViewer::SwapBuffersCallback(this));
|
||||
|
@ -176,6 +177,7 @@ namespace MWVR
|
|||
return;
|
||||
|
||||
// Give the main camera an initial draw callback that disables camera setup (we don't want it)
|
||||
Misc::StereoView::instance().setUpdateViewCallback(mUpdateViewCallback);
|
||||
Misc::StereoView::instance().setInitialDrawCallback(new InitialDrawCallback(this));
|
||||
Misc::StereoView::instance().setPredrawCallback(mPreDraw);
|
||||
Misc::StereoView::instance().setPostdrawCallback(mPostDraw);
|
||||
|
@ -234,12 +236,11 @@ namespace MWVR
|
|||
return mSubImages[static_cast<int>(side)];
|
||||
}
|
||||
|
||||
void VRViewer::blitEyesToMirrorTexture(osg::GraphicsContext* gc)
|
||||
void VRViewer::blit(osg::GraphicsContext* gc)
|
||||
{
|
||||
if (mMirrorTextureShouldBeCleanedUp)
|
||||
{
|
||||
mMirrorTexture = nullptr;
|
||||
mMsaaResolveMirrorTexture = nullptr;
|
||||
mMirrorTextureShouldBeCleanedUp = false;
|
||||
}
|
||||
if (!mMirrorTextureEnabled)
|
||||
|
@ -255,10 +256,7 @@ namespace MWVR
|
|||
screenWidth,
|
||||
screenHeight,
|
||||
0));
|
||||
mMsaaResolveMirrorTexture.reset(new VRFramebuffer(gc->getState(),
|
||||
mSwapchain->width(),
|
||||
mSwapchain->height(),
|
||||
0));
|
||||
mMirrorTexture->createColorBuffer(gc);
|
||||
}
|
||||
|
||||
auto* state = gc->getState();
|
||||
|
@ -268,22 +266,18 @@ namespace MWVR
|
|||
|
||||
//// Since OpenXR does not include native support for mirror textures, we have to generate them ourselves
|
||||
//// which means resolving msaa twice.
|
||||
mMsaaResolveMirrorTexture->bindFramebuffer(gc, GL_FRAMEBUFFER_EXT);
|
||||
mSwapchain->renderBuffer()->blit(gc, 0, 0, mSwapchain->width(), mSwapchain->height());
|
||||
mMirrorTexture->bindFramebuffer(gc, GL_FRAMEBUFFER_EXT);
|
||||
mMsaaResolveMirrorTexture->blit(gc, 0, 0, screenWidth, screenHeight);
|
||||
//for (unsigned i = 0; i < mMirrorTextureViews.size(); i++)
|
||||
//{
|
||||
// mMsaaResolveMirrorTexture->blit(gc, );
|
||||
// mMsaaResolveMirrorTexture->bindFramebuffer(gc, GL_READ_FRAMEBUFFER_EXT);
|
||||
// gl->glBlitFramebuffer(0, 0, mWidth, mHeight, i * mirrorWidth, 0, (i + 1) * mirrorWidth, screenHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||
// gl->glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, 0);
|
||||
//}
|
||||
|
||||
mMsaaResolveTexture->bindFramebuffer(gc, GL_FRAMEBUFFER_EXT);
|
||||
//mSwapchain->framebuffer()->blit(gc, 0, 0, mMsaaResolveMirrorTexture->width(), mMsaaResolveMirrorTexture->height(), GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||
mFramebuffer->blit(gc, 0, 0, mFramebuffer->width(), mFramebuffer->height(), 0, 0, mMsaaResolveTexture->width(), mMsaaResolveTexture->height(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
mFramebuffer->blit(gc, 0, 0, mFramebuffer->width(), mFramebuffer->height(), 0, 0, mMsaaResolveTexture->width(), mMsaaResolveTexture->height(), GL_DEPTH_BUFFER_BIT, GL_NEAREST);
|
||||
//mMirrorTexture->bindFramebuffer(gc, GL_FRAMEBUFFER_EXT);
|
||||
gl->glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
|
||||
mMirrorTexture->blit(gc, 0, 0, screenWidth, screenHeight);
|
||||
mMsaaResolveTexture->blit(gc, 0, 0, mMsaaResolveTexture->width(), mMsaaResolveTexture->height(), 0, 0, screenWidth, screenHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||
|
||||
mSwapchain->endFrame(gc);
|
||||
//mMirrorTexture->blit(gc, 0, 0, screenWidth, screenHeight, GL_COLOR_BUFFER_BIT);
|
||||
|
||||
mSwapchain[0]->endFrame(gc, *mMsaaResolveTexture);
|
||||
mSwapchain[1]->endFrame(gc, *mMsaaResolveTexture);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -313,8 +307,11 @@ namespace MWVR
|
|||
|
||||
Environment::get().getSession()->beginPhase(VRSession::FramePhase::Draw);
|
||||
if (Environment::get().getSession()->getFrame(VRSession::FramePhase::Draw)->mShouldRender)
|
||||
mSwapchain->beginFrame(info.getState()->getGraphicsContext());
|
||||
mViewer->getCamera()->setViewport(0, 0, mSwapchainConfig.selectedWidth, mSwapchainConfig.selectedHeight);
|
||||
{
|
||||
mSwapchain[0]->beginFrame(info.getState()->getGraphicsContext());
|
||||
mSwapchain[1]->beginFrame(info.getState()->getGraphicsContext());
|
||||
}
|
||||
mViewer->getCamera()->setViewport(0, 0, mFramebuffer->width(), mFramebuffer->height());
|
||||
|
||||
osg::GraphicsOperation* graphicsOperation = info.getCurrentCamera()->getRenderer();
|
||||
osgViewer::Renderer* renderer = dynamic_cast<osgViewer::Renderer*>(graphicsOperation);
|
||||
|
@ -330,7 +327,10 @@ namespace MWVR
|
|||
void VRViewer::preDrawCallback(osg::RenderInfo& info)
|
||||
{
|
||||
if (Environment::get().getSession()->getFrame(VRSession::FramePhase::Draw)->mShouldRender)
|
||||
mSwapchain->renderBuffer()->bindFramebuffer(info.getState()->getGraphicsContext(), GL_FRAMEBUFFER_EXT);
|
||||
{
|
||||
mFramebuffer->bindFramebuffer(info.getState()->getGraphicsContext(), GL_FRAMEBUFFER_EXT);
|
||||
//mSwapchain->framebuffer()->bindFramebuffer(info.getState()->getGraphicsContext(), GL_FRAMEBUFFER_EXT);
|
||||
}
|
||||
}
|
||||
|
||||
void VRViewer::postDrawCallback(osg::RenderInfo& info)
|
||||
|
|
|
@ -109,7 +109,7 @@ namespace MWVR
|
|||
void initialDrawCallback(osg::RenderInfo& info);
|
||||
void preDrawCallback(osg::RenderInfo& info);
|
||||
void postDrawCallback(osg::RenderInfo& info);
|
||||
void blitEyesToMirrorTexture(osg::GraphicsContext* gc);
|
||||
void blit(osg::GraphicsContext* gc);
|
||||
void configureXR(osg::GraphicsContext* gc);
|
||||
void configureCallbacks();
|
||||
void setupMirrorTexture();
|
||||
|
@ -129,9 +129,9 @@ namespace MWVR
|
|||
osg::ref_ptr<osgViewer::Viewer> mViewer = nullptr;
|
||||
osg::ref_ptr<PredrawCallback> mPreDraw{ nullptr };
|
||||
osg::ref_ptr<PostdrawCallback> mPostDraw{ nullptr };
|
||||
std::shared_ptr<UpdateViewCallback> mUpdateViewCallback{ nullptr };
|
||||
bool mRenderingReady{ false };
|
||||
|
||||
std::unique_ptr<VRFramebuffer> mMsaaResolveMirrorTexture;
|
||||
std::unique_ptr<VRFramebuffer> mMirrorTexture;
|
||||
std::vector<std::string> mMirrorTextureViews;
|
||||
bool mMirrorTextureShouldBeCleanedUp{ false };
|
||||
|
@ -139,9 +139,11 @@ namespace MWVR
|
|||
bool mFlipMirrorTextureOrder{ false };
|
||||
MirrorTextureEye mMirrorTextureEye{ MirrorTextureEye::Both };
|
||||
|
||||
std::unique_ptr<OpenXRSwapchain> mSwapchain;
|
||||
std::unique_ptr<VRFramebuffer> mFramebuffer;
|
||||
std::unique_ptr<VRFramebuffer> mMsaaResolveTexture;
|
||||
std::array<std::unique_ptr<OpenXRSwapchain>, 2> mSwapchain;
|
||||
std::array<SubImage, 2> mSubImages;
|
||||
SwapchainConfig mSwapchainConfig;
|
||||
std::array<SwapchainConfig, 2> mSwapchainConfig;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -485,11 +485,13 @@ namespace Misc
|
|||
View right{};
|
||||
double near_ = 1.f;
|
||||
double far_ = 10000.f;
|
||||
if (!mUpdateViewCallback)
|
||||
auto updateViewCallback = mUpdateViewCallback.lock();
|
||||
if (!updateViewCallback)
|
||||
{
|
||||
Log(Debug::Error) << "No update view callback. Stereo rendering will not work.";
|
||||
Log(Debug::Error) << "StereoView: No update view callback. Stereo rendering will not work.";
|
||||
return;
|
||||
}
|
||||
mUpdateViewCallback->updateView(left, right);
|
||||
updateViewCallback->updateView(left, right);
|
||||
near_ = Settings::Manager::getFloat("near clip", "Camera");
|
||||
far_ = Settings::Manager::getFloat("viewing distance", "Camera");
|
||||
|
||||
|
|
|
@ -48,10 +48,10 @@ namespace Misc
|
|||
|
||||
//! Fov that defines all 4 angles from center
|
||||
struct FieldOfView {
|
||||
float angleLeft{ -osg::PI_2 };
|
||||
float angleRight{ osg::PI_2 };
|
||||
float angleDown{ -osg::PI_2 };
|
||||
float angleUp{ osg::PI_2 };
|
||||
float angleLeft{ 0.f };
|
||||
float angleRight{ 0.f };
|
||||
float angleUp{ 0.f };
|
||||
float angleDown{ 0.f };
|
||||
|
||||
bool operator==(const FieldOfView& rhs) const;
|
||||
|
||||
|
@ -173,7 +173,7 @@ namespace Misc
|
|||
bool flipViewOrder{ true };
|
||||
|
||||
// Updates stereo configuration during the update pass
|
||||
std::shared_ptr<UpdateViewCallback> mUpdateViewCallback{ new DefaultUpdateViewCallback };
|
||||
std::weak_ptr<UpdateViewCallback> mUpdateViewCallback{};
|
||||
|
||||
// OSG camera callbacks set using set*callback. StereoView manages that these are always set on the appropriate camera(s);
|
||||
osg::ref_ptr<osg::NodeCallback> mCullCallback{ nullptr };
|
||||
|
|
|
@ -963,7 +963,7 @@ stereo enabled = false
|
|||
# Must be one of the following: BruteForce, GeometryShader
|
||||
# BruteForce: Generates stereo using two cameras and two cull/render passes. Choose this if your game is GPU-bound.
|
||||
# GeometryShader: Generates stereo in a single pass using automatically generated geometry shaders. May break custom shaders. Choose this if your game is CPU-bound.
|
||||
stereo method = GeometryShader
|
||||
stereo method = BruteForce
|
||||
|
||||
# May accelerate the BruteForce method when shadows are enabled
|
||||
shared shadow maps = true
|
||||
|
@ -1003,6 +1003,9 @@ hand directed movement = false
|
|||
# Valid options are: top, wrist
|
||||
left hand hud position = wrist
|
||||
|
||||
# If true, OpenMW will try to use DirectX swapchains instead of OpenGL swapchains. They are HW bridged to OpenGL using the WGL_NV_DX_interop2 extension.
|
||||
# As the general quality of OpenXR DirectX runtimes is better than OpenGL runtimes, i default this to true.
|
||||
Prefer DirectX swapchains = true
|
||||
|
||||
[VR Debug]
|
||||
# Openmw will sync with openxr at the beginning of this phase in the rendering pipeline. From early to late in the pipeline the options are update, cull, draw, and swap in that order. If you experience visual glitches such as frames jittering across your vision, try changing this to an earlier phase.
|
||||
|
|
Loading…
Reference in a new issue