Make threaded submit in OpenVR controllable from menu

This commit is contained in:
Brad Davis 2016-10-26 10:36:17 -07:00
parent 857f5a69d6
commit 1c89fa2291
4 changed files with 90 additions and 89 deletions

View file

@ -338,6 +338,9 @@ Menu::Menu() {
// Developer > Render > Throttle FPS If Not Focus // Developer > Render > Throttle FPS If Not Focus
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::ThrottleFPSIfNotFocus, 0, true); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::ThrottleFPSIfNotFocus, 0, true);
// Developer > Render > OpenVR threaded submit
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::OpenVrThreadedSubmit, 0, true);
// Developer > Render > Resolution // Developer > Render > Resolution
MenuWrapper* resolutionMenu = renderOptionsMenu->addMenu(MenuOption::RenderResolution); MenuWrapper* resolutionMenu = renderOptionsMenu->addMenu(MenuOption::RenderResolution);
QActionGroup* resolutionGroup = new QActionGroup(resolutionMenu); QActionGroup* resolutionGroup = new QActionGroup(resolutionMenu);

View file

@ -136,6 +136,7 @@ namespace MenuOption {
const QString OctreeStats = "Entity Statistics"; const QString OctreeStats = "Entity Statistics";
const QString OnePointCalibration = "1 Point Calibration"; const QString OnePointCalibration = "1 Point Calibration";
const QString OnlyDisplayTopTen = "Only Display Top Ten"; const QString OnlyDisplayTopTen = "Only Display Top Ten";
const QString OpenVrThreadedSubmit = "OpenVR Threaded Submit";
const QString OutputMenu = "Display"; const QString OutputMenu = "Display";
const QString Overlays = "Overlays"; const QString Overlays = "Overlays";
const QString PackageModel = "Package Model..."; const QString PackageModel = "Package Model...";

View file

@ -35,6 +35,7 @@ Q_DECLARE_LOGGING_CATEGORY(displayplugins)
const QString OpenVrDisplayPlugin::NAME("OpenVR (Vive)"); const QString OpenVrDisplayPlugin::NAME("OpenVR (Vive)");
const QString StandingHMDSensorMode = "Standing HMD Sensor Mode"; // this probably shouldn't be hardcoded here const QString StandingHMDSensorMode = "Standing HMD Sensor Mode"; // this probably shouldn't be hardcoded here
const QString OpenVrThreadedSubmit = "OpenVR Threaded Submit"; // this probably shouldn't be hardcoded here
PoseData _nextRenderPoseData; PoseData _nextRenderPoseData;
PoseData _nextSimPoseData; PoseData _nextSimPoseData;
@ -49,8 +50,6 @@ bool _openVrDisplayActive { false };
static vr::VRTextureBounds_t OPENVR_TEXTURE_BOUNDS_LEFT{ 0, 0, 0.5f, 1 }; static vr::VRTextureBounds_t OPENVR_TEXTURE_BOUNDS_LEFT{ 0, 0, 0.5f, 1 };
static vr::VRTextureBounds_t OPENVR_TEXTURE_BOUNDS_RIGHT{ 0.5f, 0, 1, 1 }; static vr::VRTextureBounds_t OPENVR_TEXTURE_BOUNDS_RIGHT{ 0.5f, 0, 1, 1 };
#if OPENVR_THREADED_SUBMIT
#define REPROJECTION_BINDING 1 #define REPROJECTION_BINDING 1
static const char* HMD_REPROJECTION_VERT = R"SHADER( static const char* HMD_REPROJECTION_VERT = R"SHADER(
@ -351,8 +350,6 @@ public:
OpenVrDisplayPlugin& _plugin; OpenVrDisplayPlugin& _plugin;
}; };
#endif
bool OpenVrDisplayPlugin::isSupported() const { bool OpenVrDisplayPlugin::isSupported() const {
return openVrSupported(); return openVrSupported();
} }
@ -394,6 +391,9 @@ bool OpenVrDisplayPlugin::internalActivate() {
return false; return false;
} }
_threadedSubmit = _container->isOptionChecked(OpenVrThreadedSubmit);
qDebug() << "OpenVR Threaded submit enabled: " << _threadedSubmit;
_openVrDisplayActive = true; _openVrDisplayActive = true;
_container->setIsOptionChecked(StandingHMDSensorMode, true); _container->setIsOptionChecked(StandingHMDSensorMode, true);
@ -434,16 +434,16 @@ bool OpenVrDisplayPlugin::internalActivate() {
#endif #endif
} }
#if OPENVR_THREADED_SUBMIT if (_threadedSubmit) {
_submitThread = std::make_shared<OpenVrSubmitThread>(*this); _submitThread = std::make_shared<OpenVrSubmitThread>(*this);
if (!_submitCanvas) { if (!_submitCanvas) {
withMainThreadContext([&] { withMainThreadContext([&] {
_submitCanvas = std::make_shared<gl::OffscreenContext>(); _submitCanvas = std::make_shared<gl::OffscreenContext>();
_submitCanvas->create(); _submitCanvas->create();
_submitCanvas->doneCurrent(); _submitCanvas->doneCurrent();
}); });
}
} }
#endif
return Parent::internalActivate(); return Parent::internalActivate();
} }
@ -473,27 +473,27 @@ void OpenVrDisplayPlugin::customizeContext() {
Parent::customizeContext(); Parent::customizeContext();
#if OPENVR_THREADED_SUBMIT if (_threadedSubmit) {
_compositeInfos[0].texture = _compositeFramebuffer->getRenderBuffer(0); _compositeInfos[0].texture = _compositeFramebuffer->getRenderBuffer(0);
for (size_t i = 0; i < COMPOSITING_BUFFER_SIZE; ++i) { for (size_t i = 0; i < COMPOSITING_BUFFER_SIZE; ++i) {
if (0 != i) { if (0 != i) {
_compositeInfos[i].texture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, _renderTargetSize.x, _renderTargetSize.y, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT))); _compositeInfos[i].texture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, _renderTargetSize.x, _renderTargetSize.y, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT)));
}
_compositeInfos[i].textureID = getGLBackend()->getTextureID(_compositeInfos[i].texture, false);
} }
_compositeInfos[i].textureID = getGLBackend()->getTextureID(_compositeInfos[i].texture, false); _submitThread->_canvas = _submitCanvas;
_submitThread->start(QThread::HighPriority);
} }
_submitThread->_canvas = _submitCanvas;
_submitThread->start(QThread::HighPriority);
#endif
} }
void OpenVrDisplayPlugin::uncustomizeContext() { void OpenVrDisplayPlugin::uncustomizeContext() {
Parent::uncustomizeContext(); Parent::uncustomizeContext();
#if OPENVR_THREADED_SUBMIT if (_threadedSubmit) {
_submitThread->_quit = true; _submitThread->_quit = true;
_submitThread->wait(); _submitThread->wait();
_submitThread.reset(); _submitThread.reset();
#endif }
} }
void OpenVrDisplayPlugin::resetSensors() { void OpenVrDisplayPlugin::resetSensors() {
@ -582,76 +582,77 @@ bool OpenVrDisplayPlugin::beginFrameRender(uint32_t frameIndex) {
} }
void OpenVrDisplayPlugin::compositeLayers() { void OpenVrDisplayPlugin::compositeLayers() {
#if OPENVR_THREADED_SUBMIT if (_threadedSubmit) {
++_renderingIndex; ++_renderingIndex;
_renderingIndex %= COMPOSITING_BUFFER_SIZE; _renderingIndex %= COMPOSITING_BUFFER_SIZE;
auto& newComposite = _compositeInfos[_renderingIndex]; auto& newComposite = _compositeInfos[_renderingIndex];
newComposite.pose = _currentPresentFrameInfo.presentPose; newComposite.pose = _currentPresentFrameInfo.presentPose;
_compositeFramebuffer->setRenderBuffer(0, newComposite.texture); _compositeFramebuffer->setRenderBuffer(0, newComposite.texture);
#endif }
Parent::compositeLayers(); Parent::compositeLayers();
#if OPENVR_THREADED_SUBMIT if (_threadedSubmit) {
newComposite.fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); auto& newComposite = _compositeInfos[_renderingIndex];
// https://www.opengl.org/registry/specs/ARB/sync.txt: newComposite.fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
// > The simple flushing behavior defined by // https://www.opengl.org/registry/specs/ARB/sync.txt:
// > SYNC_FLUSH_COMMANDS_BIT will not help when waiting for a fence // > The simple flushing behavior defined by
// > command issued in another context's command stream to complete. // > SYNC_FLUSH_COMMANDS_BIT will not help when waiting for a fence
// > Applications which block on a fence sync object must take // > command issued in another context's command stream to complete.
// > additional steps to assure that the context from which the // > Applications which block on a fence sync object must take
// > corresponding fence command was issued has flushed that command // > additional steps to assure that the context from which the
// > to the graphics pipeline. // > corresponding fence command was issued has flushed that command
glFlush(); // > to the graphics pipeline.
glFlush();
if (!newComposite.textureID) { if (!newComposite.textureID) {
newComposite.textureID = getGLBackend()->getTextureID(newComposite.texture, false); newComposite.textureID = getGLBackend()->getTextureID(newComposite.texture, false);
}
withPresentThreadLock([&] {
_submitThread->update(newComposite);
});
} }
withPresentThreadLock([&] {
_submitThread->update(newComposite);
});
#endif
} }
void OpenVrDisplayPlugin::hmdPresent() { void OpenVrDisplayPlugin::hmdPresent() {
PROFILE_RANGE_EX(__FUNCTION__, 0xff00ff00, (uint64_t)_currentFrame->frameIndex) PROFILE_RANGE_EX(__FUNCTION__, 0xff00ff00, (uint64_t)_currentFrame->frameIndex)
#if OPENVR_THREADED_SUBMIT if (_threadedSubmit) {
_submitThread->waitForPresent(); _submitThread->waitForPresent();
#else } else {
GLuint glTexId = getGLBackend()->getTextureID(_compositeFramebuffer->getRenderBuffer(0), false); GLuint glTexId = getGLBackend()->getTextureID(_compositeFramebuffer->getRenderBuffer(0), false);
vr::Texture_t vrTexture{ (void*)glTexId, vr::API_OpenGL, vr::ColorSpace_Auto }; vr::Texture_t vrTexture { (void*)glTexId, vr::API_OpenGL, vr::ColorSpace_Auto };
vr::VRCompositor()->Submit(vr::Eye_Left, &vrTexture, &OPENVR_TEXTURE_BOUNDS_LEFT); vr::VRCompositor()->Submit(vr::Eye_Left, &vrTexture, &OPENVR_TEXTURE_BOUNDS_LEFT);
vr::VRCompositor()->Submit(vr::Eye_Right, &vrTexture, &OPENVR_TEXTURE_BOUNDS_RIGHT); vr::VRCompositor()->Submit(vr::Eye_Right, &vrTexture, &OPENVR_TEXTURE_BOUNDS_RIGHT);
vr::VRCompositor()->PostPresentHandoff(); vr::VRCompositor()->PostPresentHandoff();
_presentRate.increment(); _presentRate.increment();
#endif }
} }
void OpenVrDisplayPlugin::postPreview() { void OpenVrDisplayPlugin::postPreview() {
PROFILE_RANGE_EX(__FUNCTION__, 0xff00ff00, (uint64_t)_currentFrame->frameIndex) PROFILE_RANGE_EX(__FUNCTION__, 0xff00ff00, (uint64_t)_currentFrame->frameIndex)
PoseData nextRender, nextSim; PoseData nextRender, nextSim;
nextRender.frameIndex = presentCount(); nextRender.frameIndex = presentCount();
#if !OPENVR_THREADED_SUBMIT if (_threadedSubmit) {
vr::VRCompositor()->WaitGetPoses(nextRender.vrPoses, vr::k_unMaxTrackedDeviceCount, nextSim.vrPoses, vr::k_unMaxTrackedDeviceCount); _hmdActivityLevel = _system->GetTrackedDeviceActivityLevel(vr::k_unTrackedDeviceIndex_Hmd);
} else {
vr::VRCompositor()->WaitGetPoses(nextRender.vrPoses, vr::k_unMaxTrackedDeviceCount, nextSim.vrPoses, vr::k_unMaxTrackedDeviceCount);
glm::mat4 resetMat; glm::mat4 resetMat;
withPresentThreadLock([&] { withPresentThreadLock([&] {
resetMat = _sensorResetMat; resetMat = _sensorResetMat;
}); });
nextRender.update(resetMat); nextRender.update(resetMat);
nextSim.update(resetMat); nextSim.update(resetMat);
withPresentThreadLock([&] { withPresentThreadLock([&] {
_nextSimPoseData = nextSim; _nextSimPoseData = nextSim;
}); });
_nextRenderPoseData = nextRender; _nextRenderPoseData = nextRender;
// FIXME - this looks wrong! // FIXME - this looks wrong!
_hmdActivityLevel = vr::k_EDeviceActivityLevel_UserInteraction; // _system->GetTrackedDeviceActivityLevel(vr::k_unTrackedDeviceIndex_Hmd); _hmdActivityLevel = vr::k_EDeviceActivityLevel_UserInteraction; // _system->GetTrackedDeviceActivityLevel(vr::k_unTrackedDeviceIndex_Hmd);
#else }
_hmdActivityLevel = _system->GetTrackedDeviceActivityLevel(vr::k_unTrackedDeviceIndex_Hmd);
#endif
} }
bool OpenVrDisplayPlugin::isHmdMounted() const { bool OpenVrDisplayPlugin::isHmdMounted() const {
@ -685,3 +686,7 @@ void OpenVrDisplayPlugin::unsuppressKeyboard() {
bool OpenVrDisplayPlugin::isKeyboardVisible() { bool OpenVrDisplayPlugin::isKeyboardVisible() {
return isOpenVrKeyboardShown(); return isOpenVrKeyboardShown();
} }
int OpenVrDisplayPlugin::getRequiredThreadCount() const {
return Parent::getRequiredThreadCount() + (_threadedSubmit ? 1 : 0);
}

View file

@ -15,9 +15,6 @@
const float TARGET_RATE_OpenVr = 90.0f; // FIXME: get from sdk tracked device property? This number is vive-only. const float TARGET_RATE_OpenVr = 90.0f; // FIXME: get from sdk tracked device property? This number is vive-only.
#define OPENVR_THREADED_SUBMIT 0
#if OPENVR_THREADED_SUBMIT
namespace gl { namespace gl {
class OffscreenContext; class OffscreenContext;
} }
@ -34,7 +31,6 @@ struct CompositeInfo {
glm::mat4 pose; glm::mat4 pose;
GLsync fence{ 0 }; GLsync fence{ 0 };
}; };
#endif
class OpenVrDisplayPlugin : public HmdDisplayPlugin { class OpenVrDisplayPlugin : public HmdDisplayPlugin {
using Parent = HmdDisplayPlugin; using Parent = HmdDisplayPlugin;
@ -58,10 +54,8 @@ public:
void unsuppressKeyboard() override; void unsuppressKeyboard() override;
bool isKeyboardVisible() override; bool isKeyboardVisible() override;
#if OPENVR_THREADED_SUBMIT // Possibly needs an additional thread for VR submission
// Needs an additional thread for VR submission int getRequiredThreadCount() const override;
int getRequiredThreadCount() const override { return Parent::getRequiredThreadCount() + 1; }
#endif
protected: protected:
bool internalActivate() override; bool internalActivate() override;
@ -73,7 +67,6 @@ protected:
bool isHmdMounted() const override; bool isHmdMounted() const override;
void postPreview() override; void postPreview() override;
private: private:
vr::IVRSystem* _system { nullptr }; vr::IVRSystem* _system { nullptr };
std::atomic<vr::EDeviceActivityLevel> _hmdActivityLevel { vr::k_EDeviceActivityLevel_Unknown }; std::atomic<vr::EDeviceActivityLevel> _hmdActivityLevel { vr::k_EDeviceActivityLevel_Unknown };
@ -82,12 +75,11 @@ private:
vr::HmdMatrix34_t _lastGoodHMDPose; vr::HmdMatrix34_t _lastGoodHMDPose;
mat4 _sensorResetMat; mat4 _sensorResetMat;
bool _threadedSubmit { true };
#if OPENVR_THREADED_SUBMIT
CompositeInfo::Array _compositeInfos; CompositeInfo::Array _compositeInfos;
size_t _renderingIndex { 0 }; size_t _renderingIndex { 0 };
std::shared_ptr<OpenVrSubmitThread> _submitThread; std::shared_ptr<OpenVrSubmitThread> _submitThread;
std::shared_ptr<gl::OffscreenContext> _submitCanvas; std::shared_ptr<gl::OffscreenContext> _submitCanvas;
friend class OpenVrSubmitThread; friend class OpenVrSubmitThread;
#endif
}; };