Threaded Oculus support

This commit is contained in:
Bradley Austin Davis 2016-07-29 13:01:51 -07:00 committed by Brad Davis
parent a0cc6f8817
commit d0912c6063
7 changed files with 92 additions and 156 deletions

View file

@ -6,7 +6,6 @@
# See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html # See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html
# #
if (FALSE)
if (WIN32) if (WIN32)
# we're using static GLEW, so define GLEW_STATIC # we're using static GLEW, so define GLEW_STATIC
@ -14,7 +13,7 @@ if (WIN32)
set(TARGET_NAME oculus) set(TARGET_NAME oculus)
setup_hifi_plugin(Multimedia) setup_hifi_plugin(Multimedia)
link_hifi_libraries(shared gl gpu controllers ui plugins ui-plugins display-plugins input-plugins audio-client networking) link_hifi_libraries(shared gl gpu gpu-gl controllers ui plugins ui-plugins display-plugins input-plugins audio-client networking)
include_hifi_library_headers(octree) include_hifi_library_headers(octree)
@ -25,4 +24,3 @@ if (WIN32)
target_link_libraries(${TARGET_NAME} Winmm.lib) target_link_libraries(${TARGET_NAME} Winmm.lib)
endif() endif()
endif()

View file

@ -10,6 +10,7 @@
#include <ViewFrustum.h> #include <ViewFrustum.h>
#include <controllers/Pose.h> #include <controllers/Pose.h>
#include <display-plugins/CompositorHelper.h> #include <display-plugins/CompositorHelper.h>
#include <gpu/Frame.h>
#include "OculusHelpers.h" #include "OculusHelpers.h"
@ -21,7 +22,7 @@ void OculusBaseDisplayPlugin::resetSensors() {
bool OculusBaseDisplayPlugin::beginFrameRender(uint32_t frameIndex) { bool OculusBaseDisplayPlugin::beginFrameRender(uint32_t frameIndex) {
_currentRenderFrameInfo = FrameInfo(); _currentRenderFrameInfo = FrameInfo();
_currentRenderFrameInfo.sensorSampleTime = ovr_GetTimeInSeconds();; _currentRenderFrameInfo.sensorSampleTime = ovr_GetTimeInSeconds();
_currentRenderFrameInfo.predictedDisplayTime = ovr_GetPredictedDisplayTime(_session, frameIndex); _currentRenderFrameInfo.predictedDisplayTime = ovr_GetPredictedDisplayTime(_session, frameIndex);
auto trackingState = ovr_GetTrackingState(_session, _currentRenderFrameInfo.predictedDisplayTime, ovrTrue); auto trackingState = ovr_GetTrackingState(_session, _currentRenderFrameInfo.predictedDisplayTime, ovrTrue);
_currentRenderFrameInfo.renderPose = toGlm(trackingState.HeadPose.ThePose); _currentRenderFrameInfo.renderPose = toGlm(trackingState.HeadPose.ThePose);
@ -40,7 +41,7 @@ bool OculusBaseDisplayPlugin::beginFrameRender(uint32_t frameIndex) {
handPoses[hand] = glm::translate(glm::mat4(), correctedPose.translation) * glm::mat4_cast(correctedPose.rotation * HAND_TO_LASER_ROTATION); handPoses[hand] = glm::translate(glm::mat4(), correctedPose.translation) * glm::mat4_cast(correctedPose.rotation * HAND_TO_LASER_ROTATION);
}); });
withRenderThreadLock([&] { withNonPresentThreadLock([&] {
_uiModelTransform = DependencyManager::get<CompositorHelper>()->getModelTransform(); _uiModelTransform = DependencyManager::get<CompositorHelper>()->getModelTransform();
_handPoses = handPoses; _handPoses = handPoses;
_frameInfos[frameIndex] = _currentRenderFrameInfo; _frameInfos[frameIndex] = _currentRenderFrameInfo;
@ -112,3 +113,12 @@ void OculusBaseDisplayPlugin::internalDeactivate() {
releaseOculusSession(); releaseOculusSession();
_session = nullptr; _session = nullptr;
} }
void OculusBaseDisplayPlugin::updatePresentPose() {
//mat4 sensorResetMat;
//_currentPresentFrameInfo.sensorSampleTime = ovr_GetTimeInSeconds();
//_currentPresentFrameInfo.predictedDisplayTime = ovr_GetPredictedDisplayTime(_session, _currentFrame->frameIndex);
//auto trackingState = ovr_GetTrackingState(_session, _currentRenderFrameInfo.predictedDisplayTime, ovrFalse);
//_currentPresentFrameInfo.presentPose = toGlm(trackingState.HeadPose.ThePose);
_currentPresentFrameInfo.presentPose = _currentPresentFrameInfo.renderPose;
}

View file

@ -28,6 +28,7 @@ protected:
void customizeContext() override; void customizeContext() override;
bool internalActivate() override; bool internalActivate() override;
void internalDeactivate() override; void internalDeactivate() override;
void updatePresentPose() override;
protected: protected:
ovrSession _session { nullptr }; ovrSession _session { nullptr };

View file

@ -13,6 +13,9 @@
#include <OVR_CAPI_Audio.h> #include <OVR_CAPI_Audio.h>
#include <shared/NsightHelpers.h> #include <shared/NsightHelpers.h>
#include <gpu/Frame.h>
#include <gpu/Context.h>
#include <gpu/gl/GLBackend.h>
#include "OculusHelpers.h" #include "OculusHelpers.h"
@ -43,67 +46,107 @@ void OculusDisplayPlugin::cycleDebugOutput() {
void OculusDisplayPlugin::customizeContext() { void OculusDisplayPlugin::customizeContext() {
Parent::customizeContext(); Parent::customizeContext();
_sceneFbo = SwapFboPtr(new SwapFramebufferWrapper(_session)); _outputFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_SRGBA_32, _renderTargetSize.x, _renderTargetSize.y));
_sceneFbo->Init(getRecommendedRenderSize()); ovrTextureSwapChainDesc desc = { };
desc.Type = ovrTexture_2D;
desc.ArraySize = 1;
desc.Width = _renderTargetSize.x;
desc.Height = _renderTargetSize.y;
desc.MipLevels = 1;
desc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB;
desc.SampleCount = 1;
desc.StaticImage = ovrFalse;
ovrResult result = ovr_CreateTextureSwapChainGL(_session, &desc, &_textureSwapChain);
if (!OVR_SUCCESS(result)) {
logFatal("Failed to create swap textures");
}
int length = 0;
result = ovr_GetTextureSwapChainLength(_session, _textureSwapChain, &length);
if (!OVR_SUCCESS(result) || !length) {
qFatal("Unable to count swap chain textures");
}
for (int i = 0; i < length; ++i) {
GLuint chainTexId;
ovr_GetTextureSwapChainBufferGL(_session, _textureSwapChain, i, &chainTexId);
glBindTexture(GL_TEXTURE_2D, chainTexId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
glBindTexture(GL_TEXTURE_2D, 0);
// We're rendering both eyes to the same texture, so only one of the // We're rendering both eyes to the same texture, so only one of the
// pointers is populated // pointers is populated
_sceneLayer.ColorTexture[0] = _sceneFbo->color; _sceneLayer.ColorTexture[0] = _textureSwapChain;
// not needed since the structure was zeroed on init, but explicit // not needed since the structure was zeroed on init, but explicit
_sceneLayer.ColorTexture[1] = nullptr; _sceneLayer.ColorTexture[1] = nullptr;
enableVsync(false); enableVsync(false);
// Only enable mirroring if we know vsync is disabled // Only enable mirroring if we know vsync is disabled
_enablePreview = !isVsyncEnabled(); _enablePreview = !isVsyncEnabled();
} }
void OculusDisplayPlugin::uncustomizeContext() { void OculusDisplayPlugin::uncustomizeContext() {
using namespace oglplus; #if 0
// Present a final black frame to the HMD // Present a final black frame to the HMD
_compositeFramebuffer->Bound(FramebufferTarget::Draw, [] { _compositeFramebuffer->Bound(FramebufferTarget::Draw, [] {
Context::ClearColor(0, 0, 0, 1); Context::ClearColor(0, 0, 0, 1);
Context::Clear().ColorBuffer(); Context::Clear().ColorBuffer();
}); });
hmdPresent(); hmdPresent();
#if (OVR_MAJOR_VERSION >= 6)
_sceneFbo.reset();
#endif #endif
ovr_DestroyTextureSwapChain(_session, _textureSwapChain);
_textureSwapChain = nullptr;
Parent::uncustomizeContext(); Parent::uncustomizeContext();
} }
template <typename SrcFbo, typename DstFbo>
void blit(const SrcFbo& srcFbo, const DstFbo& dstFbo) {
using namespace oglplus;
srcFbo->Bound(FramebufferTarget::Read, [&] {
dstFbo->Bound(FramebufferTarget::Draw, [&] {
Context::BlitFramebuffer(
0, 0, srcFbo->size.x, srcFbo->size.y,
0, 0, dstFbo->size.x, dstFbo->size.y,
BufferSelectBit::ColorBuffer, BlitFilter::Linear);
});
});
}
void OculusDisplayPlugin::hmdPresent() { void OculusDisplayPlugin::hmdPresent() {
PROFILE_RANGE_EX(__FUNCTION__, 0xff00ff00, (uint64_t)_currentPresentFrameIndex) PROFILE_RANGE_EX(__FUNCTION__, 0xff00ff00, (uint64_t)_currentFrame->frameIndex)
if (!_currentSceneTexture) { // Manually bind the texture to the FBO
return; auto& glBackend = dynamic_cast<gpu::gl::GLBackend&>(*_backend);
auto fbo = glBackend.getFramebufferID(_outputFramebuffer);
{
int curIndex;
ovr_GetTextureSwapChainCurrentIndex(_session, _textureSwapChain, &curIndex);
GLuint curTexId;
ovr_GetTextureSwapChainBufferGL(_session, _textureSwapChain, curIndex, &curTexId);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, curTexId, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
} }
blit(_compositeFramebuffer, _sceneFbo);
_sceneFbo->Commit();
{ {
gpu::Batch batch;
batch.enableStereo(false);
auto source = _currentFrame->framebuffer;
auto sourceRect = ivec4(ivec2(0), source->getSize());
auto dest = _outputFramebuffer;
auto destRect = ivec4(ivec2(0), dest->getSize());
batch.blit(source, sourceRect, dest, destRect);
_backend->render(batch);
}
{
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
}
{
auto result = ovr_CommitTextureSwapChain(_session, _textureSwapChain);
Q_ASSERT(OVR_SUCCESS(result));
_sceneLayer.SensorSampleTime = _currentPresentFrameInfo.sensorSampleTime; _sceneLayer.SensorSampleTime = _currentPresentFrameInfo.sensorSampleTime;
_sceneLayer.RenderPose[ovrEyeType::ovrEye_Left] = ovrPoseFromGlm(_currentPresentFrameInfo.renderPose); _sceneLayer.RenderPose[ovrEyeType::ovrEye_Left] = ovrPoseFromGlm(_currentPresentFrameInfo.renderPose);
_sceneLayer.RenderPose[ovrEyeType::ovrEye_Right] = ovrPoseFromGlm(_currentPresentFrameInfo.renderPose); _sceneLayer.RenderPose[ovrEyeType::ovrEye_Right] = ovrPoseFromGlm(_currentPresentFrameInfo.renderPose);
ovrLayerHeader* layers = &_sceneLayer.Header; ovrLayerHeader* layers = &_sceneLayer.Header;
ovrResult result = ovr_SubmitFrame(_session, _currentPresentFrameIndex, &_viewScaleDesc, &layers, 1); result = ovr_SubmitFrame(_session, _currentFrame->frameIndex, &_viewScaleDesc, &layers, 1);
if (!OVR_SUCCESS(result)) { if (!OVR_SUCCESS(result)) {
logWarning("Failed to present"); logWarning("Failed to present");
} }
@ -112,11 +155,11 @@ void OculusDisplayPlugin::hmdPresent() {
bool OculusDisplayPlugin::isHmdMounted() const { bool OculusDisplayPlugin::isHmdMounted() const {
ovrSessionStatus status; ovrSessionStatus status;
return (OVR_SUCCESS(ovr_GetSessionStatus(_session, &status)) && return (OVR_SUCCESS(ovr_GetSessionStatus(_session, &status)) &&
(ovrFalse != status.HmdMounted)); (ovrFalse != status.HmdMounted));
} }
QString OculusDisplayPlugin::getPreferredAudioInDevice() const { QString OculusDisplayPlugin::getPreferredAudioInDevice() const {
WCHAR buffer[OVR_AUDIO_MAX_DEVICE_STR_SIZE]; WCHAR buffer[OVR_AUDIO_MAX_DEVICE_STR_SIZE];
if (!OVR_SUCCESS(ovr_GetAudioDeviceInGuidStr(buffer))) { if (!OVR_SUCCESS(ovr_GetAudioDeviceInGuidStr(buffer))) {
return QString(); return QString();
@ -124,11 +167,10 @@ QString OculusDisplayPlugin::getPreferredAudioInDevice() const {
return AudioClient::friendlyNameForAudioDevice(buffer); return AudioClient::friendlyNameForAudioDevice(buffer);
} }
QString OculusDisplayPlugin::getPreferredAudioOutDevice() const { QString OculusDisplayPlugin::getPreferredAudioOutDevice() const {
WCHAR buffer[OVR_AUDIO_MAX_DEVICE_STR_SIZE]; WCHAR buffer[OVR_AUDIO_MAX_DEVICE_STR_SIZE];
if (!OVR_SUCCESS(ovr_GetAudioDeviceOutGuidStr(buffer))) { if (!OVR_SUCCESS(ovr_GetAudioDeviceOutGuidStr(buffer))) {
return QString(); return QString();
} }
return AudioClient::friendlyNameForAudioDevice(buffer); return AudioClient::friendlyNameForAudioDevice(buffer);
} }

View file

@ -9,9 +9,6 @@
#include "OculusBaseDisplayPlugin.h" #include "OculusBaseDisplayPlugin.h"
struct SwapFramebufferWrapper;
using SwapFboPtr = QSharedPointer<SwapFramebufferWrapper>;
class OculusDisplayPlugin : public OculusBaseDisplayPlugin { class OculusDisplayPlugin : public OculusBaseDisplayPlugin {
using Parent = OculusBaseDisplayPlugin; using Parent = OculusBaseDisplayPlugin;
public: public:
@ -34,7 +31,7 @@ private:
static const QString NAME; static const QString NAME;
bool _enablePreview { false }; bool _enablePreview { false };
bool _monoPreview { true }; bool _monoPreview { true };
ovrTextureSwapChain _textureSwapChain;
SwapFboPtr _sceneFbo; gpu::FramebufferPointer _outputFramebuffer;
}; };

View file

@ -18,6 +18,7 @@
#include <controllers/Input.h> #include <controllers/Input.h>
#include <controllers/Pose.h> #include <controllers/Pose.h>
#include <NumericalConstants.h>
using Mutex = std::mutex; using Mutex = std::mutex;
using Lock = std::unique_lock<Mutex>; using Lock = std::unique_lock<Mutex>;
@ -116,94 +117,6 @@ void releaseOculusSession() {
} }
// A wrapper for constructing and using a swap texture set,
// where each frame you draw to a texture via the FBO,
// then submit it and increment to the next texture.
// The Oculus SDK manages the creation and destruction of
// the textures
SwapFramebufferWrapper::SwapFramebufferWrapper(const ovrSession& session)
: _session(session) {
color = nullptr;
depth = nullptr;
}
SwapFramebufferWrapper::~SwapFramebufferWrapper() {
destroyColor();
}
void SwapFramebufferWrapper::Commit() {
auto result = ovr_CommitTextureSwapChain(_session, color);
Q_ASSERT(OVR_SUCCESS(result));
}
void SwapFramebufferWrapper::Resize(const uvec2 & size) {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oglplus::GetName(fbo));
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
this->size = size;
initColor();
initDone();
}
void SwapFramebufferWrapper::destroyColor() {
if (color) {
ovr_DestroyTextureSwapChain(_session, color);
color = nullptr;
}
}
void SwapFramebufferWrapper::initColor() {
destroyColor();
ovrTextureSwapChainDesc desc = {};
desc.Type = ovrTexture_2D;
desc.ArraySize = 1;
desc.Width = size.x;
desc.Height = size.y;
desc.MipLevels = 1;
desc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB;
desc.SampleCount = 1;
desc.StaticImage = ovrFalse;
ovrResult result = ovr_CreateTextureSwapChainGL(_session, &desc, &color);
if (!OVR_SUCCESS(result)) {
logFatal("Failed to create swap textures");
}
int length = 0;
result = ovr_GetTextureSwapChainLength(_session, color, &length);
if (!OVR_SUCCESS(result) || !length) {
qFatal("Unable to count swap chain textures");
}
for (int i = 0; i < length; ++i) {
GLuint chainTexId;
ovr_GetTextureSwapChainBufferGL(_session, color, i, &chainTexId);
glBindTexture(GL_TEXTURE_2D, chainTexId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
glBindTexture(GL_TEXTURE_2D, 0);
}
void SwapFramebufferWrapper::initDone() {
}
void SwapFramebufferWrapper::onBind(oglplus::Framebuffer::Target target) {
int curIndex;
ovr_GetTextureSwapChainCurrentIndex(_session, color, &curIndex);
GLuint curTexId;
ovr_GetTextureSwapChainBufferGL(_session, color, curIndex, &curTexId);
glFramebufferTexture2D(toEnum(target), GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, curTexId, 0);
}
void SwapFramebufferWrapper::onUnbind(oglplus::Framebuffer::Target target) {
glFramebufferTexture2D(toEnum(target), GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
}
controller::Pose ovrControllerPoseToHandPose( controller::Pose ovrControllerPoseToHandPose(
ovrHandType hand, ovrHandType hand,
const ovrPoseStatef& handPose) { const ovrPoseStatef& handPose) {

View file

@ -12,7 +12,6 @@
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
#include <gl/OglplusHelpers.h>
#include <controllers/Forward.h> #include <controllers/Forward.h>
void logWarning(const char* what); void logWarning(const char* what);
@ -106,30 +105,6 @@ inline ovrPosef ovrPoseFromGlm(const glm::mat4 & m) {
return result; return result;
} }
// A wrapper for constructing and using a swap texture set,
// where each frame you draw to a texture via the FBO,
// then submit it and increment to the next texture.
// The Oculus SDK manages the creation and destruction of
// the textures
struct SwapFramebufferWrapper : public FramebufferWrapper<ovrTextureSwapChain, void*> {
SwapFramebufferWrapper(const ovrSession& session);
~SwapFramebufferWrapper();
void Commit();
void Resize(const uvec2 & size);
protected:
void initColor() override final;
void initDepth() override final {}
void initDone() override final;
void onBind(oglplus::Framebuffer::Target target) override final;
void onUnbind(oglplus::Framebuffer::Target target) override final;
void destroyColor();
private:
ovrSession _session;
};
controller::Pose ovrControllerPoseToHandPose( controller::Pose ovrControllerPoseToHandPose(
ovrHandType hand, ovrHandType hand,
const ovrPoseStatef& handPose); const ovrPoseStatef& handPose);