mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-04-01 19:36:42 +00:00
Make use of the layer depth extension
This commit is contained in:
parent
bb16d66e02
commit
47b7837d7c
6 changed files with 107 additions and 19 deletions
|
@ -111,6 +111,11 @@ namespace MWVR
|
||||||
return impl().getRecommendedSwapchainConfig();
|
return impl().getRecommendedSwapchainConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool OpenXRManager::xrExtensionIsEnabled(const char* extensionName) const
|
||||||
|
{
|
||||||
|
return impl().xrExtensionIsEnabled(extensionName);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
OpenXRManager::CleanupOperation::operator()(
|
OpenXRManager::CleanupOperation::operator()(
|
||||||
osg::GraphicsContext* gc)
|
osg::GraphicsContext* gc)
|
||||||
|
|
|
@ -83,6 +83,9 @@ namespace MWVR
|
||||||
//! Configuration hints for instantiating swapchains, queried from openxr.
|
//! Configuration hints for instantiating swapchains, queried from openxr.
|
||||||
std::array<SwapchainConfig, 2> getRecommendedSwapchainConfig() const;
|
std::array<SwapchainConfig, 2> getRecommendedSwapchainConfig() const;
|
||||||
|
|
||||||
|
//! Check whether a given openxr extension is enabled or not
|
||||||
|
bool xrExtensionIsEnabled(const char* extensionName) const;
|
||||||
|
|
||||||
OpenXRManagerImpl& impl() { return *mPrivate; }
|
OpenXRManagerImpl& impl() { return *mPrivate; }
|
||||||
const OpenXRManagerImpl& impl() const { return *mPrivate; }
|
const OpenXRManagerImpl& impl() const { return *mPrivate; }
|
||||||
|
|
||||||
|
|
|
@ -5,13 +5,16 @@
|
||||||
|
|
||||||
#include <components/debug/debuglog.hpp>
|
#include <components/debug/debuglog.hpp>
|
||||||
#include <components/sdlutil/sdlgraphicswindow.hpp>
|
#include <components/sdlutil/sdlgraphicswindow.hpp>
|
||||||
|
#include <components/esm/loadrace.hpp>
|
||||||
|
|
||||||
#include "../mwmechanics/actorutil.hpp"
|
#include "../mwmechanics/actorutil.hpp"
|
||||||
|
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
#include "../mwworld/player.hpp"
|
#include "../mwworld/player.hpp"
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
#include <components/esm/loadrace.hpp>
|
|
||||||
|
|
||||||
// The OpenXR SDK assumes we've included Windows.h
|
// The OpenXR SDK assumes we've included Windows.h
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
@ -45,13 +48,18 @@ MAKE_TO_STRING_FUNC(XrResult);
|
||||||
MAKE_TO_STRING_FUNC(XrFormFactor);
|
MAKE_TO_STRING_FUNC(XrFormFactor);
|
||||||
MAKE_TO_STRING_FUNC(XrStructureType);
|
MAKE_TO_STRING_FUNC(XrStructureType);
|
||||||
|
|
||||||
|
#if !XR_KHR_composition_layer_depth || !XR_KHR_opengl_enable
|
||||||
|
#error "OpenXR extensions missing. Please upgrade your copy of the OpenXR SDK"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace MWVR
|
namespace MWVR
|
||||||
{
|
{
|
||||||
OpenXRManagerImpl::OpenXRManagerImpl()
|
OpenXRManagerImpl::OpenXRManagerImpl()
|
||||||
{
|
{
|
||||||
|
|
||||||
std::vector<const char*> extensions = {
|
std::vector<const char*> extensions = {
|
||||||
XR_KHR_OPENGL_ENABLE_EXTENSION_NAME
|
XR_KHR_OPENGL_ENABLE_EXTENSION_NAME,
|
||||||
|
XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME,
|
||||||
};
|
};
|
||||||
|
|
||||||
{ // Create Instance
|
{ // Create Instance
|
||||||
|
@ -59,13 +67,57 @@ namespace MWVR
|
||||||
createInfo.next = nullptr;
|
createInfo.next = nullptr;
|
||||||
createInfo.enabledExtensionCount = extensions.size();
|
createInfo.enabledExtensionCount = extensions.size();
|
||||||
createInfo.enabledExtensionNames = extensions.data();
|
createInfo.enabledExtensionNames = extensions.data();
|
||||||
|
|
||||||
strcpy(createInfo.applicationInfo.applicationName, "openmw_vr");
|
strcpy(createInfo.applicationInfo.applicationName, "openmw_vr");
|
||||||
createInfo.applicationInfo.apiVersion = XR_CURRENT_API_VERSION;
|
createInfo.applicationInfo.apiVersion = XR_CURRENT_API_VERSION;
|
||||||
CHECK_XRCMD(xrCreateInstance(&createInfo, &mInstance));
|
// Iteratively strip extensions until instance creation succeeds.
|
||||||
|
XrResult result = xrCreateInstance(&createInfo, &mInstance);
|
||||||
|
while (result == XR_ERROR_EXTENSION_NOT_PRESENT)
|
||||||
|
{
|
||||||
|
createInfo.enabledExtensionCount--;
|
||||||
|
result = xrCreateInstance(&createInfo, &mInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
mEnabledExtensions.insert(extensions.begin(), extensions.end() + createInfo.enabledExtensionCount);
|
||||||
|
|
||||||
|
if (!xrExtensionIsEnabled(XR_KHR_OPENGL_ENABLE_EXTENSION_NAME))
|
||||||
|
throw std::runtime_error(std::string("Required OpenXR extension ") + XR_KHR_OPENGL_ENABLE_EXTENSION_NAME + " not supported");
|
||||||
|
|
||||||
|
Log(Debug::Verbose) << "OpenXR Extension status:";
|
||||||
|
for (auto* ext : extensions)
|
||||||
|
{
|
||||||
|
if (!xrExtensionIsEnabled(ext))
|
||||||
|
{
|
||||||
|
Log(Debug::Verbose) << " " << ext << ": disabled (not supported)";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log(Debug::Verbose) << " " << ext << ": enabled";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
assert(mInstance);
|
assert(mInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Layer depth is enabled, cache the invariant values
|
||||||
|
if (xrExtensionIsEnabled(XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME))
|
||||||
|
{
|
||||||
|
GLfloat depthRange[2] = { 0.f, 1.f };
|
||||||
|
glGetFloatv(GL_DEPTH_RANGE, depthRange);
|
||||||
|
auto nearClip = Settings::Manager::getFloat("near clip", "Camera");
|
||||||
|
|
||||||
|
for (auto& layer : mLayerDepth)
|
||||||
|
{
|
||||||
|
layer.type = XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR;
|
||||||
|
layer.next = nullptr;
|
||||||
|
layer.minDepth = depthRange[0];
|
||||||
|
layer.maxDepth = depthRange[1];
|
||||||
|
layer.nearZ = nearClip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
{ // Get system ID
|
{ // Get system ID
|
||||||
XrSystemGetInfo systemInfo{ XR_TYPE_SYSTEM_GET_INFO };
|
XrSystemGetInfo systemInfo{ XR_TYPE_SYSTEM_GET_INFO };
|
||||||
systemInfo.formFactor = mFormFactor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;
|
systemInfo.formFactor = mFormFactor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;
|
||||||
|
@ -321,6 +373,18 @@ namespace MWVR
|
||||||
layer.views = compositionLayerProjectionViews.data();
|
layer.views = compositionLayerProjectionViews.data();
|
||||||
auto* xrLayerStack = reinterpret_cast<XrCompositionLayerBaseHeader*>(&layer);
|
auto* xrLayerStack = reinterpret_cast<XrCompositionLayerBaseHeader*>(&layer);
|
||||||
|
|
||||||
|
std::array<XrCompositionLayerDepthInfoKHR, 2> compositionLayerDepth = mLayerDepth;
|
||||||
|
if (xrExtensionIsEnabled(XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME))
|
||||||
|
{
|
||||||
|
auto farClip = Settings::Manager::getFloat("viewing distance", "Camera");
|
||||||
|
compositionLayerDepth[(int)Side::LEFT_SIDE].farZ = farClip;
|
||||||
|
compositionLayerDepth[(int)Side::RIGHT_SIDE].farZ = farClip;
|
||||||
|
compositionLayerDepth[(int)Side::LEFT_SIDE].subImage = layerStack[(int)Side::LEFT_SIDE].swapchain->impl().xrSubImageDepth();
|
||||||
|
compositionLayerDepth[(int)Side::RIGHT_SIDE].subImage = layerStack[(int)Side::RIGHT_SIDE].swapchain->impl().xrSubImageDepth();
|
||||||
|
compositionLayerProjectionViews[(int)Side::LEFT_SIDE].next = &compositionLayerDepth[(int)Side::LEFT_SIDE];
|
||||||
|
compositionLayerProjectionViews[(int)Side::RIGHT_SIDE].next = &compositionLayerDepth[(int)Side::RIGHT_SIDE];
|
||||||
|
}
|
||||||
|
|
||||||
XrFrameEndInfo frameEndInfo{ XR_TYPE_FRAME_END_INFO };
|
XrFrameEndInfo frameEndInfo{ XR_TYPE_FRAME_END_INFO };
|
||||||
frameEndInfo.displayTime = displayTime;
|
frameEndInfo.displayTime = displayTime;
|
||||||
frameEndInfo.environmentBlendMode = mEnvironmentBlendMode;
|
frameEndInfo.environmentBlendMode = mEnvironmentBlendMode;
|
||||||
|
@ -513,6 +577,11 @@ namespace MWVR
|
||||||
return referenceSpace;
|
return referenceSpace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool OpenXRManagerImpl::xrExtensionIsEnabled(const char* extensionName) const
|
||||||
|
{
|
||||||
|
return mEnabledExtensions.count(extensionName) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
void OpenXRManagerImpl::enablePredictions()
|
void OpenXRManagerImpl::enablePredictions()
|
||||||
{
|
{
|
||||||
mPredictionsEnabled = true;
|
mPredictionsEnabled = true;
|
||||||
|
|
|
@ -69,6 +69,7 @@ namespace MWVR
|
||||||
XrSpace getReferenceSpace(ReferenceSpace space);
|
XrSpace getReferenceSpace(ReferenceSpace space);
|
||||||
XrSession xrSession() const { return mSession; };
|
XrSession xrSession() const { return mSession; };
|
||||||
XrInstance xrInstance() const { return mInstance; };
|
XrInstance xrInstance() const { return mInstance; };
|
||||||
|
bool xrExtensionIsEnabled(const char* extensionName) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void LogLayersAndExtensions();
|
void LogLayersAndExtensions();
|
||||||
|
@ -78,6 +79,7 @@ namespace MWVR
|
||||||
void HandleSessionStateChanged(const XrEventDataSessionStateChanged& stateChangedEvent);
|
void HandleSessionStateChanged(const XrEventDataSessionStateChanged& stateChangedEvent);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
bool initialized = false;
|
bool initialized = false;
|
||||||
bool mPredictionsEnabled = false;
|
bool mPredictionsEnabled = false;
|
||||||
XrInstance mInstance = XR_NULL_HANDLE;
|
XrInstance mInstance = XR_NULL_HANDLE;
|
||||||
|
@ -98,6 +100,9 @@ namespace MWVR
|
||||||
bool mSessionRunning = false;
|
bool mSessionRunning = false;
|
||||||
std::mutex mFrameStateMutex{};
|
std::mutex mFrameStateMutex{};
|
||||||
std::mutex mEventMutex{};
|
std::mutex mEventMutex{};
|
||||||
|
std::set<const char*> mEnabledExtensions;
|
||||||
|
|
||||||
|
std::array<XrCompositionLayerDepthInfoKHR, 2> mLayerDepth;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,7 @@ namespace MWVR {
|
||||||
// Now create the swapchain of depth buffers.
|
// Now create the swapchain of depth buffers.
|
||||||
swapchainCreateInfo.format = mSwapchainDepthFormat;
|
swapchainCreateInfo.format = mSwapchainDepthFormat;
|
||||||
swapchainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
swapchainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||||
res = xrCreateSwapchain(xr->impl().xrSession(), &swapchainCreateInfo, &mDepthSwapchain);
|
res = xrCreateSwapchain(xr->impl().xrSession(), &swapchainCreateInfo, &mSwapchainDepth);
|
||||||
if (XR_SUCCEEDED(res))
|
if (XR_SUCCEEDED(res))
|
||||||
break;
|
break;
|
||||||
else
|
else
|
||||||
|
@ -100,19 +100,22 @@ namespace MWVR {
|
||||||
|
|
||||||
uint32_t imageCount = 0;
|
uint32_t imageCount = 0;
|
||||||
CHECK_XRCMD(xrEnumerateSwapchainImages(mSwapchain, 0, &imageCount, nullptr));
|
CHECK_XRCMD(xrEnumerateSwapchainImages(mSwapchain, 0, &imageCount, nullptr));
|
||||||
mSwapchainImageBuffers.resize(imageCount, { XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR });
|
mSwapchainColorBuffers.resize(imageCount, { XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR });
|
||||||
CHECK_XRCMD(xrEnumerateSwapchainImages(mSwapchain, imageCount, &imageCount, reinterpret_cast<XrSwapchainImageBaseHeader*>(mSwapchainImageBuffers.data())));
|
CHECK_XRCMD(xrEnumerateSwapchainImages(mSwapchain, imageCount, &imageCount, reinterpret_cast<XrSwapchainImageBaseHeader*>(mSwapchainColorBuffers.data())));
|
||||||
|
|
||||||
CHECK_XRCMD(xrEnumerateSwapchainImages(mDepthSwapchain, 0, &imageCount, nullptr));
|
CHECK_XRCMD(xrEnumerateSwapchainImages(mSwapchainDepth, 0, &imageCount, nullptr));
|
||||||
mDepthSwapchainImageBuffers.resize(imageCount, { XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR });
|
mSwapchainDepthBuffers.resize(imageCount, { XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR });
|
||||||
CHECK_XRCMD(xrEnumerateSwapchainImages(mDepthSwapchain, imageCount, &imageCount, reinterpret_cast<XrSwapchainImageBaseHeader*>(mDepthSwapchainImageBuffers.data())));
|
CHECK_XRCMD(xrEnumerateSwapchainImages(mSwapchainDepth, imageCount, &imageCount, reinterpret_cast<XrSwapchainImageBaseHeader*>(mSwapchainDepthBuffers.data())));
|
||||||
|
|
||||||
for (unsigned i = 0; i < imageCount; i++)
|
for (unsigned i = 0; i < imageCount; i++)
|
||||||
mRenderBuffers.emplace_back(new VRFramebuffer(state, mWidth, mHeight, mSamples, mSwapchainImageBuffers[i].image, mDepthSwapchainImageBuffers[i].image));
|
mRenderBuffers.emplace_back(new VRFramebuffer(state, mWidth, mHeight, mSamples, mSwapchainColorBuffers[i].image, mSwapchainDepthBuffers[i].image));
|
||||||
|
|
||||||
mSubImage.swapchain = mSwapchain;
|
mSubImage.swapchain = mSwapchain;
|
||||||
mSubImage.imageRect.offset = { 0, 0 };
|
mSubImage.imageRect.offset = { 0, 0 };
|
||||||
mSubImage.imageRect.extent = { mWidth, mHeight };
|
mSubImage.imageRect.extent = { mWidth, mHeight };
|
||||||
|
mSubImageDepth.swapchain = mSwapchainDepth;
|
||||||
|
mSubImageDepth.imageRect.offset = { 0, 0 };
|
||||||
|
mSubImageDepth.imageRect.extent = { mWidth, mHeight };
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenXRSwapchainImpl::~OpenXRSwapchainImpl()
|
OpenXRSwapchainImpl::~OpenXRSwapchainImpl()
|
||||||
|
@ -130,13 +133,13 @@ namespace MWVR {
|
||||||
uint32_t OpenXRSwapchainImpl::acquiredColorTexture() const
|
uint32_t OpenXRSwapchainImpl::acquiredColorTexture() const
|
||||||
{
|
{
|
||||||
checkAcquired();
|
checkAcquired();
|
||||||
return mSwapchainImageBuffers[mAcquiredImageIndex].image;
|
return mSwapchainColorBuffers[mAcquiredImageIndex].image;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t OpenXRSwapchainImpl::acquiredDepthTexture() const
|
uint32_t OpenXRSwapchainImpl::acquiredDepthTexture() const
|
||||||
{
|
{
|
||||||
checkAcquired();
|
checkAcquired();
|
||||||
return mSwapchainImageBuffers[mAcquiredImageIndex].image;
|
return mSwapchainColorBuffers[mAcquiredImageIndex].image;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OpenXRSwapchainImpl::isAcquired() const
|
bool OpenXRSwapchainImpl::isAcquired() const
|
||||||
|
@ -167,14 +170,14 @@ namespace MWVR {
|
||||||
// If some dumb ass implementation decides to violate this we'll just have to work around that if it actually happens.
|
// If some dumb ass implementation decides to violate this we'll just have to work around that if it actually happens.
|
||||||
CHECK_XRCMD(xrAcquireSwapchainImage(mSwapchain, &acquireInfo, &mAcquiredImageIndex));
|
CHECK_XRCMD(xrAcquireSwapchainImage(mSwapchain, &acquireInfo, &mAcquiredImageIndex));
|
||||||
uint32_t depthIndex = 0;
|
uint32_t depthIndex = 0;
|
||||||
CHECK_XRCMD(xrAcquireSwapchainImage(mDepthSwapchain, &acquireInfo, &depthIndex));
|
CHECK_XRCMD(xrAcquireSwapchainImage(mSwapchainDepth, &acquireInfo, &depthIndex));
|
||||||
if (depthIndex != mAcquiredImageIndex)
|
if (depthIndex != mAcquiredImageIndex)
|
||||||
Log(Debug::Warning) << "Depth and color indices diverged";
|
Log(Debug::Warning) << "Depth and color indices diverged";
|
||||||
|
|
||||||
XrSwapchainImageWaitInfo waitInfo{ XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO };
|
XrSwapchainImageWaitInfo waitInfo{ XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO };
|
||||||
waitInfo.timeout = XR_INFINITE_DURATION;
|
waitInfo.timeout = XR_INFINITE_DURATION;
|
||||||
CHECK_XRCMD(xrWaitSwapchainImage(mSwapchain, &waitInfo));
|
CHECK_XRCMD(xrWaitSwapchainImage(mSwapchain, &waitInfo));
|
||||||
CHECK_XRCMD(xrWaitSwapchainImage(mDepthSwapchain, &waitInfo));
|
CHECK_XRCMD(xrWaitSwapchainImage(mSwapchainDepth, &waitInfo));
|
||||||
|
|
||||||
mIsAcquired = true;
|
mIsAcquired = true;
|
||||||
}
|
}
|
||||||
|
@ -185,7 +188,7 @@ namespace MWVR {
|
||||||
|
|
||||||
XrSwapchainImageReleaseInfo releaseInfo{ XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO };
|
XrSwapchainImageReleaseInfo releaseInfo{ XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO };
|
||||||
CHECK_XRCMD(xrReleaseSwapchainImage(mSwapchain, &releaseInfo));
|
CHECK_XRCMD(xrReleaseSwapchainImage(mSwapchain, &releaseInfo));
|
||||||
CHECK_XRCMD(xrReleaseSwapchainImage(mDepthSwapchain, &releaseInfo));
|
CHECK_XRCMD(xrReleaseSwapchainImage(mSwapchainDepth, &releaseInfo));
|
||||||
}
|
}
|
||||||
void OpenXRSwapchainImpl::checkAcquired() const
|
void OpenXRSwapchainImpl::checkAcquired() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,7 +24,9 @@ namespace MWVR
|
||||||
|
|
||||||
bool isAcquired() const;
|
bool isAcquired() const;
|
||||||
XrSwapchain xrSwapchain(void) const { return mSwapchain; };
|
XrSwapchain xrSwapchain(void) const { return mSwapchain; };
|
||||||
|
XrSwapchain xrSwapchainDepth(void) const { return mSwapchainDepth; };
|
||||||
XrSwapchainSubImage xrSubImage(void) const { return mSubImage; };
|
XrSwapchainSubImage xrSubImage(void) const { return mSubImage; };
|
||||||
|
XrSwapchainSubImage xrSubImageDepth(void) const { return mSubImageDepth; };
|
||||||
int width() const { return mWidth; };
|
int width() const { return mWidth; };
|
||||||
int height() const { return mHeight; };
|
int height() const { return mHeight; };
|
||||||
int samples() const { return mSamples; };
|
int samples() const { return mSamples; };
|
||||||
|
@ -39,10 +41,11 @@ namespace MWVR
|
||||||
|
|
||||||
private:
|
private:
|
||||||
XrSwapchain mSwapchain = XR_NULL_HANDLE;
|
XrSwapchain mSwapchain = XR_NULL_HANDLE;
|
||||||
XrSwapchain mDepthSwapchain = XR_NULL_HANDLE;
|
XrSwapchain mSwapchainDepth = XR_NULL_HANDLE;
|
||||||
std::vector<XrSwapchainImageOpenGLKHR> mSwapchainImageBuffers{};
|
std::vector<XrSwapchainImageOpenGLKHR> mSwapchainColorBuffers{};
|
||||||
std::vector<XrSwapchainImageOpenGLKHR> mDepthSwapchainImageBuffers{};
|
std::vector<XrSwapchainImageOpenGLKHR> mSwapchainDepthBuffers{};
|
||||||
XrSwapchainSubImage mSubImage{};
|
XrSwapchainSubImage mSubImage{};
|
||||||
|
XrSwapchainSubImage mSubImageDepth{};
|
||||||
int32_t mWidth = -1;
|
int32_t mWidth = -1;
|
||||||
int32_t mHeight = -1;
|
int32_t mHeight = -1;
|
||||||
int32_t mSamples = -1;
|
int32_t mSamples = -1;
|
||||||
|
|
Loading…
Reference in a new issue