Vive timewarp implementation

This commit is contained in:
Brad Davis 2016-04-10 11:34:58 -07:00
parent 88ca5520be
commit 3325c58ceb
9 changed files with 232 additions and 53 deletions

View file

@ -386,6 +386,11 @@ bool OpenGLDisplayPlugin::eventFilter(QObject* receiver, QEvent* event) {
} }
void OpenGLDisplayPlugin::submitSceneTexture(uint32_t frameIndex, const gpu::TexturePointer& sceneTexture) { void OpenGLDisplayPlugin::submitSceneTexture(uint32_t frameIndex, const gpu::TexturePointer& sceneTexture) {
if (_lockCurrentTexture) {
_container->releaseSceneTexture(sceneTexture);
return;
}
{ {
Lock lock(_mutex); Lock lock(_mutex);
_sceneTextureToFrameIndexMap[sceneTexture] = frameIndex; _sceneTextureToFrameIndexMap[sceneTexture] = frameIndex;
@ -424,9 +429,9 @@ void OpenGLDisplayPlugin::updateTextures() {
void OpenGLDisplayPlugin::updateFrameData() { void OpenGLDisplayPlugin::updateFrameData() {
Lock lock(_mutex); Lock lock(_mutex);
auto previousFrameIndex = _currentRenderFrameIndex; auto previousFrameIndex = _currentPresentFrameIndex;
_currentRenderFrameIndex = _sceneTextureToFrameIndexMap[_currentSceneTexture]; _currentPresentFrameIndex = _sceneTextureToFrameIndexMap[_currentSceneTexture];
auto skippedCount = (_currentRenderFrameIndex - previousFrameIndex) - 1; auto skippedCount = (_currentPresentFrameIndex - previousFrameIndex) - 1;
_droppedFrameRate.increment(skippedCount); _droppedFrameRate.increment(skippedCount);
} }
@ -435,6 +440,7 @@ void OpenGLDisplayPlugin::compositeOverlay() {
auto compositorHelper = DependencyManager::get<CompositorHelper>(); auto compositorHelper = DependencyManager::get<CompositorHelper>();
useProgram(_program);
// check the alpha // check the alpha
auto overlayAlpha = compositorHelper->getAlpha(); auto overlayAlpha = compositorHelper->getAlpha();
if (overlayAlpha > 0.0f) { if (overlayAlpha > 0.0f) {
@ -461,6 +467,7 @@ void OpenGLDisplayPlugin::compositePointer() {
using namespace oglplus; using namespace oglplus;
auto compositorHelper = DependencyManager::get<CompositorHelper>(); auto compositorHelper = DependencyManager::get<CompositorHelper>();
useProgram(_program);
// check the alpha // check the alpha
auto overlayAlpha = compositorHelper->getAlpha(); auto overlayAlpha = compositorHelper->getAlpha();
if (overlayAlpha > 0.0f) { if (overlayAlpha > 0.0f) {
@ -481,6 +488,13 @@ void OpenGLDisplayPlugin::compositePointer() {
Uniform<float>(*_program, _alphaUniform).Set(1.0); Uniform<float>(*_program, _alphaUniform).Set(1.0);
} }
void OpenGLDisplayPlugin::compositeScene() {
using namespace oglplus;
useProgram(_program);
Uniform<glm::mat4>(*_program, _mvpUniform).Set(mat4());
drawUnitQuad();
}
void OpenGLDisplayPlugin::compositeLayers() { void OpenGLDisplayPlugin::compositeLayers() {
using namespace oglplus; using namespace oglplus;
auto targetRenderSize = getRecommendedRenderSize(); auto targetRenderSize = getRecommendedRenderSize();
@ -492,9 +506,7 @@ void OpenGLDisplayPlugin::compositeLayers() {
Context::Viewport(targetRenderSize.x, targetRenderSize.y); Context::Viewport(targetRenderSize.x, targetRenderSize.y);
Context::Clear().DepthBuffer(); Context::Clear().DepthBuffer();
glBindTexture(GL_TEXTURE_2D, getSceneTextureId()); glBindTexture(GL_TEXTURE_2D, getSceneTextureId());
_program->Bind(); compositeScene();
Uniform<glm::mat4>(*_program, _mvpUniform).Set(mat4());
drawUnitQuad();
auto overlayTextureId = getOverlayTextureId(); auto overlayTextureId = getOverlayTextureId();
if (overlayTextureId) { if (overlayTextureId) {
glEnable(GL_BLEND); glEnable(GL_BLEND);
@ -540,6 +552,7 @@ void OpenGLDisplayPlugin::present() {
// Take the composite framebuffer and send it to the output device // Take the composite framebuffer and send it to the output device
internalPresent(); internalPresent();
_presentRate.increment(); _presentRate.increment();
_activeProgram.reset();
} }
} }
@ -556,7 +569,7 @@ float OpenGLDisplayPlugin::presentRate() const {
} }
void OpenGLDisplayPlugin::drawUnitQuad() { void OpenGLDisplayPlugin::drawUnitQuad() {
_program->Bind(); useProgram(_program);
_plane->Use(); _plane->Use();
_plane->Draw(); _plane->Draw();
} }
@ -655,3 +668,10 @@ bool OpenGLDisplayPlugin::hasFocus() const {
auto window = _container->getPrimaryWidget(); auto window = _container->getPrimaryWidget();
return window ? window->hasFocus() : false; return window ? window->hasFocus() : false;
} }
void OpenGLDisplayPlugin::useProgram(const ProgramPtr& program) {
if (_activeProgram != program) {
program->Bind();
_activeProgram = program;
}
}

View file

@ -71,6 +71,7 @@ protected:
glm::uvec2 getSurfacePixels() const; glm::uvec2 getSurfacePixels() const;
void compositeLayers(); void compositeLayers();
virtual void compositeScene();
virtual void compositeOverlay(); virtual void compositeOverlay();
virtual void compositePointer(); virtual void compositePointer();
@ -93,6 +94,7 @@ protected:
void withMainThreadContext(std::function<void()> f) const; void withMainThreadContext(std::function<void()> f) const;
void useProgram(const ProgramPtr& program);
void present(); void present();
void updateTextures(); void updateTextures();
void drawUnitQuad(); void drawUnitQuad();
@ -111,7 +113,7 @@ protected:
RateCounter<> _newFrameRate; RateCounter<> _newFrameRate;
RateCounter<> _presentRate; RateCounter<> _presentRate;
QMap<gpu::TexturePointer, uint32_t> _sceneTextureToFrameIndexMap; QMap<gpu::TexturePointer, uint32_t> _sceneTextureToFrameIndexMap;
uint32_t _currentRenderFrameIndex { 0 }; uint32_t _currentPresentFrameIndex { 0 };
gpu::TexturePointer _currentSceneTexture; gpu::TexturePointer _currentSceneTexture;
gpu::TexturePointer _currentOverlayTexture; gpu::TexturePointer _currentOverlayTexture;
@ -130,6 +132,10 @@ protected:
std::map<uint16_t, CursorData> _cursorsData; std::map<uint16_t, CursorData> _cursorsData;
BasicFramebufferWrapperPtr _compositeFramebuffer; BasicFramebufferWrapperPtr _compositeFramebuffer;
bool _lockCurrentTexture { false };
private:
ProgramPtr _activeProgram;
}; };

View file

@ -28,6 +28,7 @@ static const QString MONO_PREVIEW = "Mono Preview";
static const QString FRAMERATE = DisplayPlugin::MENU_PATH() + ">Framerate"; static const QString FRAMERATE = DisplayPlugin::MENU_PATH() + ">Framerate";
static const bool DEFAULT_MONO_VIEW = true; static const bool DEFAULT_MONO_VIEW = true;
glm::uvec2 HmdDisplayPlugin::getRecommendedUiSize() const { glm::uvec2 HmdDisplayPlugin::getRecommendedUiSize() const {
return CompositorHelper::VIRTUAL_SCREEN_SIZE; return CompositorHelper::VIRTUAL_SCREEN_SIZE;
} }
@ -42,15 +43,119 @@ bool HmdDisplayPlugin::internalActivate() {
}, true, _monoPreview); }, true, _monoPreview);
_container->removeMenu(FRAMERATE); _container->removeMenu(FRAMERATE);
for_each_eye([&](Eye eye) {
_eyeInverseProjections[eye] = glm::inverse(_eyeProjections[eye]);
});
return Parent::internalActivate(); return Parent::internalActivate();
} }
static const char * REPROJECTION_VS = R"VS(#version 450 core
in vec3 Position;
in vec2 TexCoord;
out vec3 vPosition;
out vec2 vTexCoord;
void main() {
gl_Position = vec4(Position, 1);
vTexCoord = TexCoord;
vPosition = Position;
}
)VS";
static const GLint REPROJECTION_MATRIX_LOCATION = 0;
static const GLint INVERSE_PROJECTION_MATRIX_LOCATION = 4;
static const GLint PROJECTION_MATRIX_LOCATION = 12;
static const char * REPROJECTION_FS = R"FS(#version 450 core
uniform sampler2D sampler;
layout (location = 0) uniform mat3 reprojection = mat3(1);
layout (location = 4) uniform mat4 inverseProjections[2];
layout (location = 12) uniform mat4 projections[2];
in vec2 vTexCoord;
in vec3 vPosition;
out vec4 FragColor;
void main() {
vec2 uv = vTexCoord;
vec3 Z_AXIS = vec3(0.0, 0.0, -1.0);
vec3 rotated = reprojection * Z_AXIS;
float angle = acos(dot(Z_AXIS, rotated));
if (angle < 0.001) {
FragColor = texture(sampler, uv);
return;
}
mat4 eyeInverseProjection;
mat4 eyeProjection;
float xoffset = 1.0;
vec2 uvmin = vec2(0.0);
vec2 uvmax = vec2(1.0);
// determine the correct projection and inverse projection to use.
if (vTexCoord.x < 0.5) {
uvmax.x = 0.5;
eyeInverseProjection = inverseProjections[0];
eyeProjection = projections[0];
} else {
xoffset = -1.0;
uvmin.x = 0.5;
uvmax.x = 1.0;
eyeInverseProjection = inverseProjections[1];
eyeProjection = projections[1];
}
// Account for stereo in calculating the per-eye NDC coordinates
vec4 ndcSpace = vec4(vPosition, 1.0);
ndcSpace.x *= 2.0;
ndcSpace.x += xoffset;
// Convert from NDC to eyespace
vec4 eyeSpace = eyeInverseProjection * ndcSpace;
eyeSpace /= eyeSpace.w;
// Convert to a noramlized ray
vec3 ray = eyeSpace.xyz;
ray = normalize(ray);
// Adjust the ray by the rotation
ray = reprojection * ray;
// Project back on to the texture plane
eyeSpace.xyz = ray * eyeSpace.z;
//eyeSpace.xyz = ray;
// Reproject back into NDC
ndcSpace = eyeProjection * eyeSpace;
ndcSpace /= ndcSpace.w;
ndcSpace.x -= xoffset;
ndcSpace.x /= 2.0;
// Calculate the new UV coordinates
uv = (ndcSpace.xy / 2.0) + 0.5;
if (any(greaterThan(uv, uvmax)) || any(lessThan(uv, uvmin))) {
FragColor = vec4(0.0, 0.0, 0.0, 1.0);
} else {
FragColor = texture(sampler, uv);
}
}
)FS";
void HmdDisplayPlugin::customizeContext() { void HmdDisplayPlugin::customizeContext() {
Parent::customizeContext(); Parent::customizeContext();
// Only enable mirroring if we know vsync is disabled // Only enable mirroring if we know vsync is disabled
enableVsync(false); enableVsync(false);
_enablePreview = !isVsyncEnabled(); _enablePreview = !isVsyncEnabled();
_sphereSection = loadSphereSection(_program, CompositorHelper::VIRTUAL_UI_TARGET_FOV.y, CompositorHelper::VIRTUAL_UI_ASPECT_RATIO); _sphereSection = loadSphereSection(_program, CompositorHelper::VIRTUAL_UI_TARGET_FOV.y, CompositorHelper::VIRTUAL_UI_ASPECT_RATIO);
compileProgram(_reprojectionProgram, REPROJECTION_VS, REPROJECTION_FS);
} }
void HmdDisplayPlugin::uncustomizeContext() { void HmdDisplayPlugin::uncustomizeContext() {
@ -59,21 +164,57 @@ void HmdDisplayPlugin::uncustomizeContext() {
Parent::uncustomizeContext(); Parent::uncustomizeContext();
} }
// By default assume we'll present with the same pose as the render
void HmdDisplayPlugin::updatePresentPose() {
_currentPresentFrameInfo.presentPose = _currentPresentFrameInfo.renderPose;
}
glm::mat3 HmdDisplayPlugin::FrameInfo::presentRotation() const {
if (renderPose == presentPose) {
return glm::mat3();
}
quat renderRotation = glm::quat_cast(renderPose);
quat presentRotation = glm::quat_cast(presentPose);
quat reprojection = glm::inverse(renderRotation) * presentRotation;
return glm::mat3_cast(reprojection);
}
void HmdDisplayPlugin::compositeScene() {
updatePresentPose();
glm::mat3 reprojection = _currentPresentFrameInfo.presentRotation();
if (glm::mat3() == reprojection) {
// No reprojection required
Parent::compositeScene();
return;
}
useProgram(_reprojectionProgram);
using namespace oglplus;
Uniform<glm::mat3>(*_reprojectionProgram, REPROJECTION_MATRIX_LOCATION).Set(reprojection);
// FIXME what's the right oglplus mechanism to do this?
glUniformMatrix4fv(INVERSE_PROJECTION_MATRIX_LOCATION, 2, GL_FALSE, &(_eyeInverseProjections[0][0][0]));
glUniformMatrix4fv(PROJECTION_MATRIX_LOCATION, 2, GL_FALSE, &(_eyeProjections[0][0][0]));
_plane->UseInProgram(*_reprojectionProgram);
_plane->Draw();
}
void HmdDisplayPlugin::compositeOverlay() { void HmdDisplayPlugin::compositeOverlay() {
using namespace oglplus; using namespace oglplus;
auto compositorHelper = DependencyManager::get<CompositorHelper>(); auto compositorHelper = DependencyManager::get<CompositorHelper>();
// check the alpha // check the alpha
useProgram(_program);
auto overlayAlpha = compositorHelper->getAlpha(); auto overlayAlpha = compositorHelper->getAlpha();
if (overlayAlpha > 0.0f) { if (overlayAlpha > 0.0f) {
// set the alpha // set the alpha
Uniform<float>(*_program, _alphaUniform).Set(overlayAlpha); Uniform<float>(*_program, _alphaUniform).Set(overlayAlpha);
auto eyePoses = _currentPresentFrameInfo.eyePoses;
_sphereSection->Use(); _sphereSection->Use();
for_each_eye([&](Eye eye) { for_each_eye([&](Eye eye) {
eyeViewport(eye); eyeViewport(eye);
auto modelView = glm::inverse(eyePoses[eye]); // *glm::translate(mat4(), vec3(0, 0, -1)); auto modelView = glm::inverse(_currentPresentFrameInfo.presentPose * getEyeToHeadTransform(eye));
auto mvp = _eyeProjections[eye] * modelView; auto mvp = _eyeProjections[eye] * modelView;
Uniform<glm::mat4>(*_program, _mvpUniform).Set(mvp); Uniform<glm::mat4>(*_program, _mvpUniform).Set(mvp);
_sphereSection->Draw(); _sphereSection->Draw();
@ -88,6 +229,7 @@ void HmdDisplayPlugin::compositePointer() {
auto compositorHelper = DependencyManager::get<CompositorHelper>(); auto compositorHelper = DependencyManager::get<CompositorHelper>();
// check the alpha // check the alpha
useProgram(_program);
auto overlayAlpha = compositorHelper->getAlpha(); auto overlayAlpha = compositorHelper->getAlpha();
if (overlayAlpha > 0.0f) { if (overlayAlpha > 0.0f) {
// set the alpha // set the alpha
@ -96,10 +238,11 @@ void HmdDisplayPlugin::compositePointer() {
// Mouse pointer // Mouse pointer
_plane->Use(); _plane->Use();
// Reconstruct the headpose from the eye poses // Reconstruct the headpose from the eye poses
auto headPosition = vec3(_currentPresentFrameInfo.headPose[3]); auto headPosition = vec3(_currentPresentFrameInfo.presentPose[3]);
for_each_eye([&](Eye eye) { for_each_eye([&](Eye eye) {
eyeViewport(eye); eyeViewport(eye);
auto reticleTransform = compositorHelper->getReticleTransform(_currentPresentFrameInfo.eyePoses[eye], headPosition); auto eyePose = _currentPresentFrameInfo.presentPose * getEyeToHeadTransform(eye);
auto reticleTransform = compositorHelper->getReticleTransform(eyePose, headPosition);
auto mvp = _eyeProjections[eye] * reticleTransform; auto mvp = _eyeProjections[eye] * reticleTransform;
Uniform<glm::mat4>(*_program, _mvpUniform).Set(mvp); Uniform<glm::mat4>(*_program, _mvpUniform).Set(mvp);
_plane->Draw(); _plane->Draw();
@ -160,16 +303,13 @@ void HmdDisplayPlugin::internalPresent() {
} }
void HmdDisplayPlugin::setEyeRenderPose(uint32_t frameIndex, Eye eye, const glm::mat4& pose) { void HmdDisplayPlugin::setEyeRenderPose(uint32_t frameIndex, Eye eye, const glm::mat4& pose) {
Lock lock(_mutex);
FrameInfo& frame = _frameInfos[frameIndex];
frame.eyePoses[eye] = pose;
} }
void HmdDisplayPlugin::updateFrameData() { void HmdDisplayPlugin::updateFrameData() {
// Check if we have old frame data to discard // Check if we have old frame data to discard
{ {
Lock lock(_mutex); Lock lock(_mutex);
auto itr = _frameInfos.find(_currentRenderFrameIndex); auto itr = _frameInfos.find(_currentPresentFrameIndex);
if (itr != _frameInfos.end()) { if (itr != _frameInfos.end()) {
_frameInfos.erase(itr); _frameInfos.erase(itr);
} }
@ -179,10 +319,10 @@ void HmdDisplayPlugin::updateFrameData() {
{ {
Lock lock(_mutex); Lock lock(_mutex);
_currentPresentFrameInfo = _frameInfos[_currentRenderFrameIndex]; _currentPresentFrameInfo = _frameInfos[_currentPresentFrameIndex];
} }
} }
glm::mat4 HmdDisplayPlugin::getHeadPose() const { glm::mat4 HmdDisplayPlugin::getHeadPose() const {
return _currentRenderFrameInfo.get().headPose; return _currentRenderFrameInfo.renderPose;
} }

View file

@ -28,13 +28,12 @@ public:
virtual glm::mat4 getHeadPose() const override; virtual glm::mat4 getHeadPose() const override;
using EyePoses = std::array<glm::mat4, 2>;
struct FrameInfo { struct FrameInfo {
EyePoses eyePoses; glm::mat4 renderPose;
glm::mat4 headPose; glm::mat4 presentPose;
double sensorSampleTime { 0 }; double sensorSampleTime { 0 };
double predictedDisplayTime { 0 }; double predictedDisplayTime { 0 };
glm::mat3 presentRotation() const;
}; };
@ -42,8 +41,10 @@ protected:
virtual void hmdPresent() = 0; virtual void hmdPresent() = 0;
virtual bool isHmdMounted() const = 0; virtual bool isHmdMounted() const = 0;
virtual void postPreview() {}; virtual void postPreview() {};
virtual void updatePresentPose();
bool internalActivate() override; bool internalActivate() override;
void compositeScene() override;
void compositeOverlay() override; void compositeOverlay() override;
void compositePointer() override; void compositePointer() override;
void internalPresent() override; void internalPresent() override;
@ -53,17 +54,20 @@ protected:
std::array<glm::mat4, 2> _eyeOffsets; std::array<glm::mat4, 2> _eyeOffsets;
std::array<glm::mat4, 2> _eyeProjections; std::array<glm::mat4, 2> _eyeProjections;
std::array<glm::mat4, 2> _eyeInverseProjections;
glm::mat4 _cullingProjection; glm::mat4 _cullingProjection;
glm::uvec2 _renderTargetSize; glm::uvec2 _renderTargetSize;
float _ipd { 0.064f }; float _ipd { 0.064f };
QMap<uint32_t, FrameInfo> _frameInfos; QMap<uint32_t, FrameInfo> _frameInfos;
FrameInfo _currentPresentFrameInfo; FrameInfo _currentPresentFrameInfo;
ThreadSafeValueCache<FrameInfo> _currentRenderFrameInfo; FrameInfo _currentRenderFrameInfo;
private: private:
bool _enablePreview { false }; bool _enablePreview { false };
bool _monoPreview { true }; bool _monoPreview { true };
ShapeWrapperPtr _sphereSection; ShapeWrapperPtr _sphereSection;
ProgramPtr _reprojectionProgram;
}; };

View file

@ -16,15 +16,14 @@ void OculusBaseDisplayPlugin::resetSensors() {
} }
void OculusBaseDisplayPlugin::beginFrameRender(uint32_t frameIndex) { void OculusBaseDisplayPlugin::beginFrameRender(uint32_t frameIndex) {
FrameInfo frame; _currentRenderFrameInfo = FrameInfo();
frame.sensorSampleTime = ovr_GetTimeInSeconds();; _currentRenderFrameInfo.sensorSampleTime = ovr_GetTimeInSeconds();;
frame.predictedDisplayTime = ovr_GetPredictedDisplayTime(_session, frameIndex); _currentRenderFrameInfo.predictedDisplayTime = ovr_GetPredictedDisplayTime(_session, frameIndex);
auto trackingState = ovr_GetTrackingState(_session, frame.predictedDisplayTime, ovrTrue); auto trackingState = ovr_GetTrackingState(_session, _currentRenderFrameInfo.predictedDisplayTime, ovrTrue);
frame.headPose = toGlm(trackingState.HeadPose.ThePose); _currentRenderFrameInfo.renderPose = toGlm(trackingState.HeadPose.ThePose);
_currentRenderFrameInfo.presentPose = _currentRenderFrameInfo.renderPose;
_currentRenderFrameInfo.set(frame);
Lock lock(_mutex); Lock lock(_mutex);
_frameInfos[frameIndex] = frame; _frameInfos[frameIndex] = _currentRenderFrameInfo;
} }
bool OculusBaseDisplayPlugin::isSupported() const { bool OculusBaseDisplayPlugin::isSupported() const {

View file

@ -84,7 +84,7 @@ void blit(const SrcFbo& srcFbo, const DstFbo& dstFbo) {
void OculusDisplayPlugin::hmdPresent() { void OculusDisplayPlugin::hmdPresent() {
PROFILE_RANGE_EX(__FUNCTION__, 0xff00ff00, (uint64_t)_currentRenderFrameIndex) PROFILE_RANGE_EX(__FUNCTION__, 0xff00ff00, (uint64_t)_currentPresentFrameIndex)
if (!_currentSceneTexture) { if (!_currentSceneTexture) {
return; return;
@ -94,10 +94,10 @@ void OculusDisplayPlugin::hmdPresent() {
_sceneFbo->Commit(); _sceneFbo->Commit();
{ {
_sceneLayer.SensorSampleTime = _currentPresentFrameInfo.sensorSampleTime; _sceneLayer.SensorSampleTime = _currentPresentFrameInfo.sensorSampleTime;
_sceneLayer.RenderPose[ovrEyeType::ovrEye_Left] = ovrPoseFromGlm(_currentPresentFrameInfo.headPose); _sceneLayer.RenderPose[ovrEyeType::ovrEye_Left] = ovrPoseFromGlm(_currentPresentFrameInfo.renderPose);
_sceneLayer.RenderPose[ovrEyeType::ovrEye_Right] = ovrPoseFromGlm(_currentPresentFrameInfo.headPose); _sceneLayer.RenderPose[ovrEyeType::ovrEye_Right] = ovrPoseFromGlm(_currentPresentFrameInfo.renderPose);
ovrLayerHeader* layers = &_sceneLayer.Header; ovrLayerHeader* layers = &_sceneLayer.Header;
ovrResult result = ovr_SubmitFrame(_session, _currentRenderFrameIndex, &_viewScaleDesc, &layers, 1); ovrResult result = ovr_SubmitFrame(_session, _currentPresentFrameIndex, &_viewScaleDesc, &layers, 1);
if (!OVR_SUCCESS(result)) { if (!OVR_SUCCESS(result)) {
logWarning("Failed to present"); logWarning("Failed to present");
} }

View file

@ -36,13 +36,12 @@ void OculusLegacyDisplayPlugin::resetSensors() {
} }
void OculusLegacyDisplayPlugin::beginFrameRender(uint32_t frameIndex) { void OculusLegacyDisplayPlugin::beginFrameRender(uint32_t frameIndex) {
FrameInfo frame; _currentRenderFrameInfo = FrameInfo();
frame.predictedDisplayTime = frame.sensorSampleTime = ovr_GetTimeInSeconds(); _currentRenderFrameInfo.predictedDisplayTime = _currentRenderFrameInfo.sensorSampleTime = ovr_GetTimeInSeconds();
_trackingState = ovrHmd_GetTrackingState(_hmd, frame.predictedDisplayTime); _trackingState = ovrHmd_GetTrackingState(_hmd, _currentRenderFrameInfo..predictedDisplayTime);
frame.headPose = toGlm(_trackingState.HeadPose.ThePose); _currentRenderFrameInfo.renderPose = toGlm(_trackingState.HeadPose.ThePose);
_currentRenderFrameInfo.set(frame);
Lock lock(_mutex); Lock lock(_mutex);
_frameInfos[frameIndex] = frame; _frameInfos[frameIndex] = _currentRenderFrameInfo;
} }
bool OculusLegacyDisplayPlugin::isSupported() const { bool OculusLegacyDisplayPlugin::isSupported() const {

View file

@ -42,8 +42,6 @@ bool OpenVrDisplayPlugin::isSupported() const {
} }
bool OpenVrDisplayPlugin::internalActivate() { bool OpenVrDisplayPlugin::internalActivate() {
Parent::internalActivate();
_container->setIsOptionChecked(StandingHMDSensorMode, true); _container->setIsOptionChecked(StandingHMDSensorMode, true);
if (!_system) { if (!_system) {
@ -91,7 +89,7 @@ bool OpenVrDisplayPlugin::internalActivate() {
qDebug() << "OpenVR: error could not get chaperone pointer"; qDebug() << "OpenVR: error could not get chaperone pointer";
} }
return true; return Parent::internalActivate();
} }
void OpenVrDisplayPlugin::internalDeactivate() { void OpenVrDisplayPlugin::internalDeactivate() {
@ -112,6 +110,7 @@ void OpenVrDisplayPlugin::customizeContext() {
GLenum err = glewInit(); GLenum err = glewInit();
glGetError(); // clear the potential error from glewExperimental glGetError(); // clear the potential error from glewExperimental
}); });
Parent::customizeContext(); Parent::customizeContext();
} }
@ -127,17 +126,17 @@ void OpenVrDisplayPlugin::beginFrameRender(uint32_t frameIndex) {
double frameDuration = 1.f / displayFrequency; double frameDuration = 1.f / displayFrequency;
double vsyncToPhotons = _system->GetFloatTrackedDeviceProperty(vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_SecondsFromVsyncToPhotons_Float); double vsyncToPhotons = _system->GetFloatTrackedDeviceProperty(vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_SecondsFromVsyncToPhotons_Float);
FrameInfo frame; _currentRenderFrameInfo = FrameInfo();
#if THREADED_PRESENT #if THREADED_PRESENT
// 3 frames of prediction + vsyncToPhotons = 44ms total // 3 frames of prediction + vsyncToPhotons = 44ms total
const double NUM_PREDICTION_FRAMES = 3.0f; const double NUM_PREDICTION_FRAMES = 3.0f;
frame.predictedDisplayTime = NUM_PREDICTION_FRAMES * frameDuration + vsyncToPhotons; _currentRenderFrameInfo.predictedDisplayTime = NUM_PREDICTION_FRAMES * frameDuration + vsyncToPhotons;
#else #else
frame.predictedDisplayTime = frameDuration + vsyncToPhotons; _currentRenderFrameInfo.predictedDisplayTime = frameDuration + vsyncToPhotons;
#endif #endif
vr::TrackedDevicePose_t predictedTrackedDevicePose[vr::k_unMaxTrackedDeviceCount]; vr::TrackedDevicePose_t predictedTrackedDevicePose[vr::k_unMaxTrackedDeviceCount];
_system->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseStanding, frame.predictedDisplayTime, predictedTrackedDevicePose, vr::k_unMaxTrackedDeviceCount); _system->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseStanding, _currentRenderFrameInfo.predictedDisplayTime, predictedTrackedDevicePose, vr::k_unMaxTrackedDeviceCount);
// copy and process predictedTrackedDevicePoses // copy and process predictedTrackedDevicePoses
for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) { for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) {
@ -146,16 +145,15 @@ void OpenVrDisplayPlugin::beginFrameRender(uint32_t frameIndex) {
_trackedDeviceLinearVelocities[i] = transformVectorFast(_sensorResetMat, toGlm(_trackedDevicePose[i].vVelocity)); _trackedDeviceLinearVelocities[i] = transformVectorFast(_sensorResetMat, toGlm(_trackedDevicePose[i].vVelocity));
_trackedDeviceAngularVelocities[i] = transformVectorFast(_sensorResetMat, toGlm(_trackedDevicePose[i].vAngularVelocity)); _trackedDeviceAngularVelocities[i] = transformVectorFast(_sensorResetMat, toGlm(_trackedDevicePose[i].vAngularVelocity));
} }
frame.headPose = _trackedDevicePoseMat4[0]; _currentRenderFrameInfo.renderPose = _trackedDevicePoseMat4[0];
_currentRenderFrameInfo.set(frame);
Lock lock(_mutex); Lock lock(_mutex);
_frameInfos[frameIndex] = frame; _frameInfos[frameIndex] = _currentRenderFrameInfo;
} }
void OpenVrDisplayPlugin::hmdPresent() { void OpenVrDisplayPlugin::hmdPresent() {
PROFILE_RANGE_EX(__FUNCTION__, 0xff00ff00, (uint64_t)_currentRenderFrameIndex) PROFILE_RANGE_EX(__FUNCTION__, 0xff00ff00, (uint64_t)_currentPresentFrameIndex)
// Flip y-axis since GL UV coords are backwards. // Flip y-axis since GL UV coords are backwards.
static vr::VRTextureBounds_t leftBounds{ 0, 0, 0.5f, 1 }; static vr::VRTextureBounds_t leftBounds{ 0, 0, 0.5f, 1 };
@ -168,7 +166,7 @@ void OpenVrDisplayPlugin::hmdPresent() {
} }
void OpenVrDisplayPlugin::postPreview() { void OpenVrDisplayPlugin::postPreview() {
PROFILE_RANGE_EX(__FUNCTION__, 0xff00ff00, (uint64_t)_currentRenderFrameIndex) PROFILE_RANGE_EX(__FUNCTION__, 0xff00ff00, (uint64_t)_currentPresentFrameIndex)
vr::TrackedDevicePose_t currentTrackedDevicePose[vr::k_unMaxTrackedDeviceCount]; vr::TrackedDevicePose_t currentTrackedDevicePose[vr::k_unMaxTrackedDeviceCount];
_compositor->WaitGetPoses(currentTrackedDevicePose, vr::k_unMaxTrackedDeviceCount, nullptr, 0); _compositor->WaitGetPoses(currentTrackedDevicePose, vr::k_unMaxTrackedDeviceCount, nullptr, 0);
@ -179,3 +177,14 @@ bool OpenVrDisplayPlugin::isHmdMounted() const {
return _hmdActivityLevel == vr::k_EDeviceActivityLevel_UserInteraction; return _hmdActivityLevel == vr::k_EDeviceActivityLevel_UserInteraction;
} }
void OpenVrDisplayPlugin::updatePresentPose() {
float fSecondsSinceLastVsync;
_system->GetTimeSinceLastVsync(&fSecondsSinceLastVsync, nullptr);
float fDisplayFrequency = _system->GetFloatTrackedDeviceProperty(vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_DisplayFrequency_Float);
float fFrameDuration = 1.f / fDisplayFrequency;
float fVsyncToPhotons = _system->GetFloatTrackedDeviceProperty(vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_SecondsFromVsyncToPhotons_Float);
float fPredictedSecondsFromNow = fFrameDuration - fSecondsSinceLastVsync + fVsyncToPhotons;
vr::TrackedDevicePose_t presentPoseOpenVR;
_system->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseStanding, fPredictedSecondsFromNow, &presentPoseOpenVR, 1);
_currentPresentFrameInfo.presentPose = _sensorResetMat * toGlm(presentPoseOpenVR.mDeviceToAbsoluteTracking);
}

View file

@ -28,10 +28,12 @@ public:
// Stereo specific methods // Stereo specific methods
virtual void resetSensors() override; virtual void resetSensors() override;
virtual void beginFrameRender(uint32_t frameIndex) override; virtual void beginFrameRender(uint32_t frameIndex) override;
void cycleDebugOutput() override { _lockCurrentTexture = !_lockCurrentTexture; }
protected: protected:
bool internalActivate() override; bool internalActivate() override;
void internalDeactivate() override; void internalDeactivate() override;
void updatePresentPose() override;
void hmdPresent() override; void hmdPresent() override;
bool isHmdMounted() const override; bool isHmdMounted() const override;