diff --git a/src/hmd.cpp b/src/hmd.cpp new file mode 100644 index 000000000..6361d8b12 --- /dev/null +++ b/src/hmd.cpp @@ -0,0 +1,205 @@ +/* + * Copyright 2011-2016 Branimir Karadzic. All rights reserved. + * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause + */ + +#include "hmd.h" + +namespace bgfx +{ + VR::VR() + : m_framesUntilReconnect(0) + , m_enabled(false) + { + } + + void VR::init(VRImplI* _impl) + { + if (!_impl) + { + return; + } + + if (!_impl->init()) + { + return; + } + + m_impl = _impl; + m_impl->connect(&m_desc); + if (!m_impl->isConnected()) + { + connectFailed(); + return; + } + + m_hmdSize.m_w = m_desc.m_eyeSize[0].m_w + m_desc.m_eyeSize[1].m_w; + m_hmdSize.m_h = bx::uint32_max(m_desc.m_eyeSize[0].m_h, m_desc.m_eyeSize[1].m_h); + } + + void VR::shutdown() + { + if (!m_impl) + { + return; + } + + m_impl->destroySwapChain(); + if (m_impl->isConnected()) + { + m_impl->disconnect(); + } + + m_impl->shutdown(); + m_impl = NULL; + m_enabled = false; + } + + void VR::renderEyeStart(uint8_t _eye, Rect* _viewport) + { + BX_CHECK(m_enabled, "VR::renderEyeStart called while not enabled - render usage error"); + + _viewport->m_x = 0; + _viewport->m_y = 0; + _viewport->m_width = m_desc.m_eyeSize[_eye].m_w; + _viewport->m_height = m_desc.m_eyeSize[_eye].m_h; + + m_impl->renderEyeStart(m_desc, _eye); + } + + void VR::recenter() + { + if (m_impl) + { + m_impl->recenter(); + } + } + + void VR::preReset() + { + if (m_impl) + { + m_impl->destroyMirror(); + } + + m_enabled = false; + } + + void VR::postReset(int _msaaSamples, int _mirrorWidth, int _mirrorHeight) + { + if (m_impl && m_impl->createSwapChain(m_desc, _msaaSamples, _mirrorWidth, _mirrorHeight)) + { + m_enabled = true; + } + } + + void VR::flip() + { + if (!m_impl || !m_enabled) + { + return; + } + else if (!m_impl->isConnected() && !tryReconnect()) + { + return; + } + + if (!m_impl->submitSwapChain(m_desc)) + { + m_impl->destroySwapChain(); + m_impl->disconnect(); + return; + } + } + + void VR::swap(HMD& _hmd) + { + _hmd.flags = BGFX_HMD_NONE; + + if (!m_impl) + { + return; + } + + _hmd.flags = BGFX_HMD_DEVICE_RESOLUTION; + _hmd.deviceWidth = m_desc.m_deviceSize.m_w; + _hmd.deviceHeight = m_desc.m_deviceSize.m_h; + _hmd.width = m_hmdSize.m_w; + _hmd.height = m_hmdSize.m_h; + + if (!m_impl->updateTracking(_hmd)) + { + m_impl->destroySwapChain(); + m_impl->disconnect(); + } + + if (!m_impl->isConnected()) + { + return; + } + + for (int eye = 0; eye < 2; ++eye) + { + _hmd.eye[eye].fov[0] = m_desc.m_eyeFov[eye].m_up; + _hmd.eye[eye].fov[1] = m_desc.m_eyeFov[eye].m_down; + _hmd.eye[eye].fov[2] = m_desc.m_eyeFov[eye].m_left; + _hmd.eye[eye].fov[3] = m_desc.m_eyeFov[eye].m_right; + } + + m_impl->updateInput(_hmd); + if (m_enabled) + { + _hmd.flags |= BGFX_HMD_RENDERING; + } + } + + bool VR::tryReconnect() + { + if (!m_impl) + { + return false; + } + + BX_CHECK(!m_impl->isConnected(), "VR::tryReconnect called when already connected. Usage error"); + + --m_framesUntilReconnect; + if (m_framesUntilReconnect > 0) + { + return false; + } + + m_framesUntilReconnect = 90; + m_impl->connect(&m_desc); + if (!m_impl->isConnected()) + { + connectFailed(); + return false; + } + + m_hmdSize.m_w = m_desc.m_eyeSize[0].m_w + m_desc.m_eyeSize[1].m_w; + m_hmdSize.m_h = bx::uint32_max(m_desc.m_eyeSize[0].m_h, m_desc.m_eyeSize[1].m_h); + return true; + } + + void VR::connectFailed() + { + // sane defaults + m_desc.m_deviceSize.m_w = 2160; + m_desc.m_deviceSize.m_h = 1200; + m_desc.m_deviceType = 0; + m_desc.m_refreshRate = 90.0f; + m_desc.m_neckOffset[0] = 0.0805f; + m_desc.m_neckOffset[1] = 0.075f; + + for (int eye = 0; eye < 2; ++eye) + { + m_desc.m_eyeFov[eye].m_up = 1.32928634f; + m_desc.m_eyeFov[eye].m_down = 1.32928634f; + } + m_desc.m_eyeFov[0].m_left = 1.05865765f; + m_desc.m_eyeFov[0].m_right = 1.09236801f; + m_desc.m_eyeFov[1].m_left = 1.09236801f; + m_desc.m_eyeFov[1].m_right = 1.05865765f; + } + +} // namesapce bgfx diff --git a/src/hmd.h b/src/hmd.h new file mode 100644 index 000000000..5b2813f92 --- /dev/null +++ b/src/hmd.h @@ -0,0 +1,102 @@ +/* + * Copyright 2011-2016 Branimir Karadzic. All rights reserved. + * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause + */ + +#ifndef BGFX_HMD_H_HEADER_GUARD +#define BGFX_HMD_H_HEADER_GUARD + +#include "bgfx_p.h" + +namespace bgfx +{ + struct VRSize + { + uint32_t m_w; + uint32_t m_h; + }; + + struct VRFovTan + { + float m_up; + float m_down; + float m_left; + float m_right; + }; + + struct VRDesc + { + uint64_t m_adapterLuid; + uint32_t m_deviceType; + float m_refreshRate; + VRSize m_deviceSize; + VRSize m_eyeSize[2]; + VRFovTan m_eyeFov[2]; + float m_neckOffset[2]; + }; + + struct BX_NO_VTABLE VRImplI + { + virtual ~VRImplI() = 0; + + virtual bool init() = 0; + virtual void shutdown() = 0; + virtual void connect(VRDesc* _desc) = 0; + virtual void disconnect() = 0; + virtual bool isConnected() const = 0; + + virtual bool updateTracking(HMD& _hmd) = 0; + virtual void updateInput(HMD& _hmd) = 0; + virtual void recenter() = 0; + + virtual bool createSwapChain(const VRDesc& _desc, int _msaaSamples, int _mirrorWidth, int _mirrorHeight); + virtual void destroySwapChain() = 0; + virtual void destroyMirror() = 0; + virtual void renderEyeStart(const VRDesc& _desc, uint8_t _eye) = 0; + virtual bool submitSwapChain(const VRDesc& _desc) = 0; + }; + + inline VRImplI::~VRImplI() + { + } + + class VR + { + public: + VR(); + + void init(VRImplI* _impl); + void shutdown(); + + bool isInitialized() const + { + return NULL != m_impl; + } + + bool isEnabled() const + { + return m_enabled; + } + + void renderEyeStart(uint8_t _eye, Rect* _viewport); + void recenter(); + + void preReset(); + void postReset(int _msaaSamples, int _mirrorWidth, int _mirrorHeight); + void flip(); + void swap(HMD& _hmd); + + private: + bool tryReconnect(); + void connectFailed(); + + VRDesc m_desc; + VRSize m_hmdSize; + VRImplI* m_impl; + uint32_t m_framesUntilReconnect; + bool m_enabled; + }; + +} // namespace bgfx + +#endif // BGFX_HMD_H_HEADER_GUARD diff --git a/src/hmd_ovr.cpp b/src/hmd_ovr.cpp index ec25a9501..960db032c 100644 --- a/src/hmd_ovr.cpp +++ b/src/hmd_ovr.cpp @@ -3,10 +3,12 @@ * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause */ -#include "hmd_ovr.h" +#include "bgfx_p.h" #if BGFX_CONFIG_USE_OVR +#include "hmd_ovr.h" + namespace bgfx { #define _OVR_CHECK(_call) \ @@ -21,236 +23,159 @@ namespace bgfx # define OVR_CHECK(_call) _call #endif // BGFX_CONFIG_DEBUG - OVR::OVR() - : m_hmd(NULL) - , m_enabled(false) - , m_render(NULL) - , m_frameIndex(0) - , m_sensorSampleTime(0) + VRImplOVR::VRImplOVR() + : m_session(NULL) { } - OVR::~OVR() + VRImplOVR::~VRImplOVR() { - BX_CHECK(NULL == m_hmd, "OVR not shutdown properly."); + BX_CHECK(NULL == m_session, "OVR not shutdown properly."); } - void OVR::init() + bool VRImplOVR::init() { - ovrResult result = ovr_Initialize(NULL); - - if (result != ovrSuccess) - { - BX_TRACE("Unable to create OVR device."); - return; - } - - ovrGraphicsLuid luid; - result = ovr_Create(&m_hmd, &luid); - if (result != ovrSuccess) - { - BX_TRACE("Unable to create OVR device."); - return; - } - - m_hmdDesc = ovr_GetHmdDesc(m_hmd); - - BX_TRACE("HMD: %s, %s, firmware: %d.%d" - , m_hmdDesc.ProductName - , m_hmdDesc.Manufacturer - , m_hmdDesc.FirmwareMajor - , m_hmdDesc.FirmwareMinor - ); - - ovrSizei sizeL = ovr_GetFovTextureSize(m_hmd, ovrEye_Left, m_hmdDesc.DefaultEyeFov[0], 1.0f); - ovrSizei sizeR = ovr_GetFovTextureSize(m_hmd, ovrEye_Right, m_hmdDesc.DefaultEyeFov[1], 1.0f); - m_hmdSize.w = sizeL.w + sizeR.w; - m_hmdSize.h = bx::uint32_max(sizeL.h, sizeR.h); - } - - void OVR::shutdown() - { - BX_CHECK(!m_enabled, "HMD not disabled."); - - if (NULL != m_render) - { - m_render->destroy(m_hmd); - m_render = NULL; - } - - ovr_Destroy(m_hmd); - m_hmd = NULL; - ovr_Shutdown(); - } - - void OVR::getViewport(uint8_t _eye, Rect* _viewport) - { - _viewport->m_x = 0; - _viewport->m_y = 0; - _viewport->m_width = m_render->m_eyeTextureSize[_eye].w; - _viewport->m_height = m_render->m_eyeTextureSize[_eye].h; - } - - void OVR::renderEyeStart(uint8_t _eye) - { - m_render->startEyeRender(m_hmd, _eye); - } - - bool OVR::postReset() - { - if (NULL == m_hmd) + ovrResult initialized = ovr_Initialize(NULL); + if (!OVR_SUCCESS(initialized)) { + BX_TRACE("Unable to initialize OVR runtime."); return false; } - for (uint32_t ii = 0; ii < 2; ++ii) - { - m_erd[ii] = ovr_GetRenderDesc(m_hmd, ovrEyeType(ii), m_hmdDesc.DefaultEyeFov[ii]); - } - - m_enabled = true; - return true; } - void OVR::preReset() + void VRImplOVR::shutdown() { - if (m_enabled) + ovr_Shutdown(); + } + + void VRImplOVR::connect(VRDesc* _desc) + { + ovrGraphicsLuid luid; + ovrResult result = ovr_Create(&m_session, &luid); + if (!OVR_SUCCESS(result)) { - // on window resize this will recreate the mirror texture in ovrPostReset - m_render->preReset(m_hmd); - m_enabled = false; + BX_TRACE("Failed to create OVR device."); + return; + } + + BX_STATIC_ASSERT(sizeof(_desc->m_adapterLuid) >= sizeof(luid)); + memcpy(&_desc->m_adapterLuid, &luid, sizeof(luid)); + + ovrHmdDesc hmdDesc = ovr_GetHmdDesc(m_session); + _desc->m_deviceType = hmdDesc.Type; + _desc->m_refreshRate = hmdDesc.DisplayRefreshRate; + _desc->m_deviceSize.m_w = hmdDesc.Resolution.w; + _desc->m_deviceSize.m_h = hmdDesc.Resolution.h; + + BX_TRACE("OVR HMD: %s, %s, firmware: %d.%d" + , hmdDesc.ProductName + , hmdDesc.Manufacturer + , hmdDesc.FirmwareMajor + , hmdDesc.FirmwareMinor + ); + + ovrSizei eyeSize[2] = + { + ovr_GetFovTextureSize(m_session, ovrEye_Left, hmdDesc.DefaultEyeFov[0], 1.0f), + ovr_GetFovTextureSize(m_session, ovrEye_Right, hmdDesc.DefaultEyeFov[0], 1.0f), + }; + + for (int eye = 0; eye < 2; ++eye) + { + BX_STATIC_ASSERT(sizeof(_desc->m_eyeFov[eye]) == sizeof(hmdDesc.DefaultEyeFov[eye])); + memcpy(&_desc->m_eyeFov[eye], &hmdDesc.DefaultEyeFov[eye], sizeof(_desc->m_eyeFov[eye])); + _desc->m_eyeSize[eye].m_w = eyeSize[eye].w; + _desc->m_eyeSize[eye].m_h = eyeSize[eye].h; + } + + float neckOffset[2] = {OVR_DEFAULT_NECK_TO_EYE_HORIZONTAL, OVR_DEFAULT_NECK_TO_EYE_VERTICAL}; + ovr_GetFloatArray(m_session, OVR_KEY_NECK_TO_EYE_DISTANCE, neckOffset, 2); + _desc->m_neckOffset[0] = neckOffset[0]; + _desc->m_neckOffset[1] = neckOffset[1]; + + // build constant layer settings + m_renderLayer.Header.Type = ovrLayerType_EyeFov; + m_renderLayer.Header.Flags = 0; + for (int eye = 0; eye < 2; ++eye) + { + m_renderLayer.Fov[eye] = hmdDesc.DefaultEyeFov[eye]; + m_renderLayer.Viewport[eye].Pos.x = 0; + m_renderLayer.Viewport[eye].Pos.y = 0; + m_renderLayer.Viewport[eye].Size = eyeSize[eye]; + } + + m_viewScale.HmdSpaceToWorldScaleInMeters = 1.0f; + for (int eye = 0; eye < 2; ++eye) + { + ovrEyeRenderDesc erd = ovr_GetRenderDesc(m_session, static_cast(eye), hmdDesc.DefaultEyeFov[eye]); + m_viewScale.HmdToEyeOffset[eye] = erd.HmdToEyeOffset; + m_eyeFov[eye] = erd.Fov; + m_pixelsPerTanAngleAtCenter[eye] = erd.PixelsPerTanAngleAtCenter; } } - OVR::Enum OVR::swap(HMD& _hmd, bool originBottomLeft) + void VRImplOVR::disconnect() { - _hmd.flags = BGFX_HMD_NONE; - - if (NULL != m_hmd) + if (NULL != m_session) { - _hmd.flags |= BGFX_HMD_DEVICE_RESOLUTION; - _hmd.deviceWidth = m_hmdDesc.Resolution.w; - _hmd.deviceHeight = m_hmdDesc.Resolution.h; + ovr_Destroy(m_session); + m_session = NULL; + } + } + + bool VRImplOVR::updateTracking(HMD& _hmd) + { + if (NULL == m_session) + { + return false; } - if (!m_enabled) - { - return NotEnabled; - } + ovr_GetEyePoses(m_session, 0, ovrTrue, m_viewScale.HmdToEyeOffset, m_renderLayer.RenderPose, &m_renderLayer.SensorSampleTime); - ovrResult result; - - for (uint32_t ii = 0; ii < 2; ++ii) + for (int eye = 0; eye < 2; ++eye) { - m_render->postRender(m_hmd, ii); - result = ovr_CommitTextureSwapChain(m_hmd, m_render->m_textureSwapChain[ii]); - if (!OVR_SUCCESS(result) ) + const ovrPosef& pose = m_renderLayer.RenderPose[eye]; + HMD::Eye& hmdEye = _hmd.eye[eye]; + + hmdEye.rotation[0] = pose.Orientation.x; + hmdEye.rotation[1] = pose.Orientation.y; + hmdEye.rotation[2] = pose.Orientation.z; + hmdEye.rotation[3] = pose.Orientation.w; + hmdEye.translation[0] = pose.Position.x; + hmdEye.translation[1] = pose.Position.y; + hmdEye.translation[2] = pose.Position.z; + hmdEye.viewOffset[0] = -m_viewScale.HmdToEyeOffset[eye].x; + hmdEye.viewOffset[1] = -m_viewScale.HmdToEyeOffset[eye].y; + hmdEye.viewOffset[2] = -m_viewScale.HmdToEyeOffset[eye].z; + + hmdEye.pixelsPerTanAngle[0] = m_pixelsPerTanAngleAtCenter[eye].x; + hmdEye.pixelsPerTanAngle[1] = m_pixelsPerTanAngleAtCenter[eye].y; + + ovrMatrix4f projection = ovrMatrix4f_Projection(m_eyeFov[eye], 0.1f, 1000.0f, ovrProjection_LeftHanded); + for (uint32_t ii = 0; ii < 4; ++ii) { - return DeviceLost; - } - } - - _hmd.flags |= BGFX_HMD_RENDERING; - - // finish frame for current eye - ovrViewScaleDesc viewScaleDesc; - viewScaleDesc.HmdSpaceToWorldScaleInMeters = 1.0f; - viewScaleDesc.HmdToEyeOffset[0] = m_hmdToEyeOffset[0]; - viewScaleDesc.HmdToEyeOffset[1] = m_hmdToEyeOffset[1]; - - // create the main eye layer - ovrLayerEyeFov eyeLayer; - eyeLayer.Header.Type = ovrLayerType_EyeFov; - eyeLayer.Header.Flags = originBottomLeft ? ovrLayerFlag_TextureOriginAtBottomLeft : 0; - - for (uint32_t ii = 0; ii < 2; ++ii) - { - eyeLayer.ColorTexture[ii] = m_render->m_textureSwapChain[ii]; - eyeLayer.Viewport[ii].Pos.x = 0; - eyeLayer.Viewport[ii].Pos.y = 0; - eyeLayer.Viewport[ii].Size.w = m_render->m_eyeTextureSize[ii].w; - eyeLayer.Viewport[ii].Size.h = m_render->m_eyeTextureSize[ii].h; - eyeLayer.Fov[ii] = m_hmdDesc.DefaultEyeFov[ii]; - eyeLayer.RenderPose[ii] = m_pose[ii]; - eyeLayer.SensorSampleTime = m_sensorSampleTime; - } - - // append all the layers to global list - ovrLayerHeader* layerList = &eyeLayer.Header; - - result = ovr_SubmitFrame(m_hmd, m_frameIndex, NULL, &layerList, 1); - if (!OVR_SUCCESS(result) ) - { - return DeviceLost; - } - - // perform mirror texture blit right after the entire frame is submitted to HMD - if (result != ovrSuccess_NotVisible) - { - m_render->blitMirror(m_hmd); - } - - m_hmdToEyeOffset[0] = m_erd[0].HmdToEyeOffset; - m_hmdToEyeOffset[1] = m_erd[1].HmdToEyeOffset; - - ovr_GetEyePoses(m_hmd, m_frameIndex, ovrTrue, m_hmdToEyeOffset, m_pose, &m_sensorSampleTime); - - getEyePose(_hmd); - - return Success; - } - - void OVR::recenter() - { - if (NULL != m_hmd) - { - OVR_CHECK(ovr_RecenterTrackingOrigin(m_hmd) ); - } - } - - void OVR::getEyePose(HMD& _hmd) - { - if (NULL != m_hmd) - { - for (uint32_t ii = 0; ii < 2; ++ii) - { - const ovrPosef& pose = m_pose[ii]; - HMD::Eye& eye = _hmd.eye[ii]; - eye.rotation[0] = pose.Orientation.x; - eye.rotation[1] = pose.Orientation.y; - eye.rotation[2] = pose.Orientation.z; - eye.rotation[3] = pose.Orientation.w; - eye.translation[0] = pose.Position.x; - eye.translation[1] = pose.Position.y; - eye.translation[2] = pose.Position.z; - - const ovrEyeRenderDesc& erd = m_erd[ii]; - eye.fov[0] = erd.Fov.UpTan; - eye.fov[1] = erd.Fov.DownTan; - eye.fov[2] = erd.Fov.LeftTan; - eye.fov[3] = erd.Fov.RightTan; - - ovrMatrix4f eyeProj = ovrMatrix4f_Projection(m_erd[ii].Fov, 0.01f, 1000.0f, ovrProjection_LeftHanded); for (uint32_t jj = 0; jj < 4; ++jj) { - for (uint32_t kk = 0; kk < 4; ++kk) - { - eye.projection[4 * jj + kk] = eyeProj.M[kk][jj]; - } + hmdEye.projection[4*ii + jj] = projection.M[jj][ii]; } - - eye.viewOffset[0] = -erd.HmdToEyeOffset.x; - eye.viewOffset[1] = -erd.HmdToEyeOffset.y; - eye.viewOffset[2] = -erd.HmdToEyeOffset.z; - - eye.pixelsPerTanAngle[0] = erd.PixelsPerTanAngleAtCenter.x; - eye.pixelsPerTanAngle[1] = erd.PixelsPerTanAngleAtCenter.y; } } - _hmd.width = uint16_t(m_hmdSize.w); - _hmd.height = uint16_t(m_hmdSize.h); + return true; + } + + void VRImplOVR::updateInput(HMD& /* _hmd */) + { + } + + void VRImplOVR::recenter() + { + if (NULL != m_session) + { + ovr_RecenterTrackingOrigin(m_session); + } } } // namespace bgfx diff --git a/src/hmd_ovr.h b/src/hmd_ovr.h index eb275c4ea..0dbe388d0 100644 --- a/src/hmd_ovr.h +++ b/src/hmd_ovr.h @@ -10,6 +10,7 @@ #if BGFX_CONFIG_USE_OVR +# include "hmd.h" # include # define OVR_VERSION_(_a, _b, _c) (_a * 10000 + _b * 100 + _c) @@ -25,160 +26,41 @@ # include # endif // BGFX_CONFIG_RENDERER_OPENGL -namespace bgfx -{ - // render data for both eyes and mirrored output - struct BX_NO_VTABLE OVRRenderI - { - OVRRenderI(); - virtual ~OVRRenderI() = 0; - virtual void create(const ovrSession& _session, int _msaaSamples, int _mirrorWidth, int _mirrorHeight) = 0; - virtual void destroy(const ovrSession& _session) = 0; - virtual void preReset(const ovrSession& _session) = 0; - virtual void startEyeRender(const ovrSession& _session, int _eyeIdx) = 0; - virtual void postRender(const ovrSession& _session, int _eyeIdx) = 0; - virtual void blitMirror(const ovrSession& _session) = 0; - - ovrSizei m_eyeTextureSize[2]; - ovrTextureSwapChain m_textureSwapChain[2]; - ovrMirrorTexture m_mirrorTexture; - ovrMirrorTextureDesc m_mirrorTextureDesc; - }; - - inline OVRRenderI::OVRRenderI() - : m_mirrorTexture(NULL) - { - memset(&m_textureSwapChain, 0, sizeof(m_textureSwapChain)); - } - - inline OVRRenderI::~OVRRenderI() - { - } - - struct OVR - { - enum Enum - { - NotEnabled, - DeviceLost, - Success, - - Count - }; - - OVR(); - ~OVR(); - - bool isInitialized() const - { - return NULL != m_hmd; - } - - bool isEnabled() const - { - return m_enabled; - } - - void init(); - void shutdown(); - - void getViewport(uint8_t _eye, Rect* _viewport); - void renderEyeStart(uint8_t _eye); - bool postReset(); - void preReset(); - Enum swap(HMD& _hmd, bool originBottomLeft); - void recenter(); - void getEyePose(HMD& _hmd); - - ovrSession m_hmd; - ovrHmdDesc m_hmdDesc; - ovrEyeRenderDesc m_erd[2]; - ovrRecti m_rect[2]; - ovrPosef m_pose[2]; - ovrVector3f m_hmdToEyeOffset[2]; - ovrSizei m_hmdSize; - OVRRenderI *m_render; - uint64_t m_frameIndex; - double m_sensorSampleTime; - bool m_enabled; - }; - -} // namespace bgfx - -#else namespace bgfx { - struct OVR + class VRImplOVR : public VRImplI { - enum Enum - { - NotEnabled, - DeviceLost, - Success, + public: + VRImplOVR(); + virtual ~VRImplOVR() = 0; - Count - }; + virtual bool init(); + virtual void shutdown(); + virtual void connect(VRDesc* _desc); + virtual void disconnect(); - OVR() + virtual bool isConnected() const { + return NULL != m_session; } - ~OVR() - { - } + virtual bool updateTracking(HMD& _hmd); + virtual void updateInput(HMD& _hmd); + virtual void recenter(); - bool isInitialized() const - { - return false; - } + virtual bool createSwapChain(const VRDesc& _desc, int _msaaSamples, int _mirrorWidth, int _mirrorHeight) = 0; + virtual void destroySwapChain() = 0; + virtual void destroyMirror() = 0; + virtual void renderEyeStart(const VRDesc& _desc, uint8_t _eye) = 0; + virtual bool submitSwapChain(const VRDesc& _desc) = 0; - bool isEnabled() const - { - return false; - } - - bool isDebug() const - { - return false; - } - - void init() - { - } - - void shutdown() - { - } - - void getViewport(uint8_t /*_eye*/, Rect* _viewport) - { - _viewport->m_x = 0; - _viewport->m_y = 0; - _viewport->m_width = 0; - _viewport->m_height = 0; - } - - void renderEyeStart(uint8_t /*_eye*/) - { - } - - Enum swap(HMD& _hmd, bool /*originBottomLeft*/) - { - _hmd.flags = BGFX_HMD_NONE; - getEyePose(_hmd); - return NotEnabled; - } - - void recenter() - { - } - - void getEyePose(HMD& _hmd) - { - _hmd.width = 0; - _hmd.height = 0; - } + protected: + ovrSession m_session; + ovrLayerEyeFov m_renderLayer; + ovrViewScaleDesc m_viewScale; + ovrFovPort m_eyeFov[2]; + ovrVector2f m_pixelsPerTanAngleAtCenter[2]; }; } // namespace bgfx diff --git a/src/renderer_d3d11.cpp b/src/renderer_d3d11.cpp index 786ab304d..09a757a80 100644 --- a/src/renderer_d3d11.cpp +++ b/src/renderer_d3d11.cpp @@ -29,6 +29,10 @@ # define BGFX_GPU_PROFILER_END() BX_NOOP() #endif +#if BGFX_CONFIG_USE_OVR +# include "hmd_ovr.h" +#endif // BGFX_CONFIG_USE_OVR + namespace bgfx { namespace d3d11 { static wchar_t s_viewNameW[BGFX_CONFIG_MAX_VIEWS][BGFX_CONFIG_MAX_VIEW_NAME]; @@ -601,6 +605,30 @@ namespace bgfx { namespace d3d11 static PFN_GET_DEBUG_INTERFACE1 DXGIGetDebugInterface1; #endif // USE_D3D11_DYNAMIC_LIB +#if BGFX_CONFIG_USE_OVR + class VRImplOVRD3D11 : public VRImplOVR + { + public: + VRImplOVRD3D11(); + + virtual bool createSwapChain(const VRDesc& _desc, int _msaaSamples, int _mirrorWidth, int _mirrorHeight); + virtual void destroySwapChain(); + virtual void destroyMirror(); + virtual void renderEyeStart(const VRDesc& _desc, uint8_t _eye); + virtual bool submitSwapChain(const VRDesc& _desc); + + private: + ID3D11RenderTargetView* m_eyeRtv[2][4]; + ID3D11DepthStencilView* m_depthBuffer[2]; + ID3D11Texture2D* m_msaaTexture[2]; + ID3D11ShaderResourceView* m_msaaSv[2]; + ID3D11RenderTargetView* m_msaaRtv[2]; + + ovrTextureSwapChain m_textureSwapChain[2]; + ovrMirrorTexture m_mirrorTexture; + }; +#endif // BGFX_CONFIG_USE_OVR + struct RendererContextD3D11 : public RendererContextI { RendererContextD3D11() @@ -662,7 +690,11 @@ namespace bgfx { namespace d3d11 ErrorState::Enum errorState = ErrorState::Default; // Must be before device creation, and before RenderDoc. - m_ovr.init(); + VRImplI* vrImpl = NULL; +#if BGFX_CONFIG_USE_OVR + vrImpl = &m_ovrRender; +#endif // BGFX_CONFIG_USE_OVR + m_ovr.init(vrImpl); if (!m_ovr.isInitialized() ) { @@ -2226,18 +2258,12 @@ BX_PRAGMA_DIAGNOSTIC_POP(); if (SUCCEEDED(hr) ) { - switch (m_ovr.swap(_hmd, false) ) + m_ovr.flip(); + m_ovr.swap(_hmd); // TODO - move this out of end-of-frame + + if (!m_ovr.isEnabled()) { - case OVR::NotEnabled: hr = m_swapChain->Present(syncInterval, 0); - break; - - case OVR::DeviceLost: - ovrPreReset(); - break; - - default: - break; } } @@ -3148,13 +3174,8 @@ BX_PRAGMA_DIAGNOSTIC_POP(); #if BGFX_CONFIG_USE_OVR if (m_resolution.m_flags & (BGFX_RESET_HMD|BGFX_RESET_HMD_DEBUG) ) { - if (m_ovr.postReset() ) - { - const uint32_t msaaSamples = 1 << ((m_resolution.m_flags&BGFX_RESET_MSAA_MASK) >> BGFX_RESET_MSAA_SHIFT); - - m_ovr.m_render = &m_ovrRender; - m_ovr.m_render->create(m_ovr.m_hmd, msaaSamples, m_resolution.m_width, m_resolution.m_height); - } + const uint32_t msaaSamples = 1 << ((m_resolution.m_flags&BGFX_RESET_MSAA_MASK) >> BGFX_RESET_MSAA_SHIFT); + m_ovr.postReset(msaaSamples, m_resolution.m_width, m_resolution.m_height); } #endif // BGFX_CONFIG_USE_OVR } @@ -3553,9 +3574,9 @@ BX_PRAGMA_DIAGNOSTIC_POP(); bool m_rtMsaa; bool m_timerQuerySupport; - OVR m_ovr; + VR m_ovr; #if BGFX_CONFIG_USE_OVR - OVRRenderD3D11 m_ovrRender; + VRImplOVRD3D11 m_ovrRender; #endif // BGFX_CONFIG_USE_OVR }; @@ -3610,62 +3631,66 @@ BX_PRAGMA_DIAGNOSTIC_POP(); } #if BGFX_CONFIG_USE_OVR - void OVRRenderD3D11::create(const ovrSession& _session, int _msaaSamples, int _mirrorWidth, int _mirrorHeight) + + VRImplOVRD3D11::VRImplOVRD3D11() + : m_mirrorTexture(NULL) { - ovrHmdDesc hmdDesc = ovr_GetHmdDesc(_session); + memset(m_textureSwapChain, 0, sizeof(m_textureSwapChain)); + } + + bool VRImplOVRD3D11::createSwapChain(const VRDesc& _desc, int _msaaSamples, int _mirrorWidth, int _mirrorHeight) + { + ID3D11Device* device = s_renderD3D11->m_device; for (int eye = 0; eye < 2; ++eye) { if (NULL == m_textureSwapChain[eye]) { - m_eyeTextureSize[eye] = ovr_GetFovTextureSize(_session, (ovrEyeType)eye, hmdDesc.DefaultEyeFov[eye], 1.0f); m_msaaTexture[eye] = NULL; m_msaaRtv[eye] = NULL; - m_msaaSv[eye] = NULL; + m_msaaSv[eye] = NULL; - ovrTextureSwapChainDesc desc = {}; - desc.Type = ovrTexture_2D; - desc.ArraySize = 1; - desc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB; - desc.Width = m_eyeTextureSize[eye].w; - desc.Height = m_eyeTextureSize[eye].h; - desc.MipLevels = 1; - desc.SampleCount = 1; - desc.MiscFlags = ovrTextureMisc_DX_Typeless; - desc.BindFlags = ovrTextureBind_DX_RenderTarget; - desc.StaticImage = ovrFalse; + ovrTextureSwapChainDesc swapchainDesc = {}; + swapchainDesc.Type = ovrTexture_2D; + swapchainDesc.ArraySize = 1; + swapchainDesc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB; + swapchainDesc.Width = _desc.m_eyeSize[eye].m_w; + swapchainDesc.Height = _desc.m_eyeSize[eye].m_h; + swapchainDesc.MipLevels = 1; + swapchainDesc.SampleCount = 1; + swapchainDesc.MiscFlags = ovrTextureMisc_DX_Typeless; + swapchainDesc.BindFlags = ovrTextureBind_DX_RenderTarget; + swapchainDesc.StaticImage = ovrFalse; - ID3D11Device* device = s_renderD3D11->m_device; - - ovrResult result = ovr_CreateTextureSwapChainDX(_session, device, &desc, &m_textureSwapChain[eye]); - - if (!OVR_SUCCESS(result) ) + ovrResult result = ovr_CreateTextureSwapChainDX(m_session, device, &swapchainDesc, &m_textureSwapChain[eye]); + if (!OVR_SUCCESS(result)) { - BX_CHECK(false, "Could not create D3D11 OVR swap texture"); + destroySwapChain(); + return false; } - memset(m_eyeRtv[eye], 0, sizeof(m_eyeRtv[eye]) ); - int textureCount = 0; - ovr_GetTextureSwapChainLength(_session, m_textureSwapChain[eye], &textureCount); + memset(m_eyeRtv[eye], 0, sizeof(m_eyeRtv[eye])); + int textureCount; + ovr_GetTextureSwapChainLength(m_session, m_textureSwapChain[eye], &textureCount); for (int ii = 0; ii < textureCount; ++ii) { ID3D11Texture2D* tex = NULL; - ovr_GetTextureSwapChainBufferDX(_session, m_textureSwapChain[eye], ii, IID_PPV_ARGS(&tex) ); + ovr_GetTextureSwapChainBufferDX(m_session, m_textureSwapChain[eye], ii, IID_PPV_ARGS(&tex)); D3D11_RENDER_TARGET_VIEW_DESC rtvd = {}; rtvd.Format = DXGI_FORMAT_R8G8B8A8_UNORM; rtvd.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; ID3D11RenderTargetView* rtv; - DX_CHECK(device->CreateRenderTargetView(tex, &rtvd, &rtv) ); + DX_CHECK(device->CreateRenderTargetView(tex, &rtvd, &rtv)); m_eyeRtv[eye][ii] = rtv; DX_RELEASE(tex, 1); } // setup depth buffer D3D11_TEXTURE2D_DESC dbDesc; - dbDesc.Width = m_eyeTextureSize[eye].w; - dbDesc.Height = m_eyeTextureSize[eye].h; + dbDesc.Width = _desc.m_eyeSize[eye].m_w; + dbDesc.Height = _desc.m_eyeSize[eye].m_h; dbDesc.MipLevels = 1; dbDesc.ArraySize = 1; dbDesc.Format = DXGI_FORMAT_D32_FLOAT; @@ -3676,16 +3701,16 @@ BX_PRAGMA_DIAGNOSTIC_POP(); dbDesc.MiscFlags = 0; dbDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; ID3D11Texture2D* tex; - DX_CHECK(device->CreateTexture2D(&dbDesc, NULL, &tex) ); - DX_CHECK(device->CreateDepthStencilView(tex, NULL, &m_depthBuffer[eye]) ); + DX_CHECK(device->CreateTexture2D(&dbDesc, NULL, &tex)); + DX_CHECK(device->CreateDepthStencilView(tex, NULL, &m_depthBuffer[eye])); DX_RELEASE(tex, 0); // create MSAA render target if (_msaaSamples > 1) { D3D11_TEXTURE2D_DESC dsDesc; - dsDesc.Width = m_eyeTextureSize[eye].w; - dsDesc.Height = m_eyeTextureSize[eye].h; + dsDesc.Width = _desc.m_eyeSize[eye].m_w; + dsDesc.Height = _desc.m_eyeSize[eye].m_h; dsDesc.MipLevels = 1; dsDesc.ArraySize = 1; dsDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; @@ -3696,7 +3721,6 @@ BX_PRAGMA_DIAGNOSTIC_POP(); dsDesc.MiscFlags = 0; dsDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; - ID3D11Device* device = s_renderD3D11->m_device; DX_CHECK(device->CreateTexture2D(&dsDesc, NULL, &m_msaaTexture[eye])); DX_CHECK(device->CreateShaderResourceView(m_msaaTexture[eye], NULL, &m_msaaSv[eye])); DX_CHECK(device->CreateRenderTargetView(m_msaaTexture[eye], NULL, &m_msaaRtv[eye])); @@ -3706,124 +3730,147 @@ BX_PRAGMA_DIAGNOSTIC_POP(); if (NULL == m_mirrorTexture) { - m_mirrorTextureDesc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB; - m_mirrorTextureDesc.Width = _mirrorWidth; - m_mirrorTextureDesc.Height = _mirrorHeight; - ovrResult result = ovr_CreateMirrorTextureDX(_session, s_renderD3D11->m_device, &m_mirrorTextureDesc, &m_mirrorTexture); + ovrMirrorTextureDesc mirrorDesc = {}; + mirrorDesc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB; + mirrorDesc.Width = _mirrorWidth; + mirrorDesc.Height = _mirrorHeight; + ovrResult result = ovr_CreateMirrorTextureDX(m_session, device, &mirrorDesc, &m_mirrorTexture); BX_WARN(OVR_SUCCESS(result), "Could not create D3D11 OVR mirror texture"); BX_UNUSED(result); } + + m_renderLayer.ColorTexture[0] = m_textureSwapChain[0]; + m_renderLayer.ColorTexture[1] = m_textureSwapChain[1]; + return true; } - void OVRRenderD3D11::startEyeRender(const ovrSession& _session, int _eyeIdx) + void VRImplOVRD3D11::destroySwapChain() + { + for (int eye = 0; eye < 2; ++eye) + { + if (m_textureSwapChain[eye]) + { + for (uint32_t ii = 0; ii < BX_COUNTOF(m_eyeRtv[eye]); ++ii) + { + DX_RELEASE(m_eyeRtv[eye][ii], 0); + } + + ovr_DestroyTextureSwapChain(m_session, m_textureSwapChain[eye]); + m_textureSwapChain[eye] = NULL; + m_depthBuffer[eye]->Release(); + + if (NULL != m_msaaTexture[eye]) + { + m_msaaTexture[eye]->Release(); + m_msaaTexture[eye] = NULL; + } + + if (NULL != m_msaaSv[eye]) + { + m_msaaSv[eye]->Release(); + m_msaaSv[eye] = NULL; + } + + if (NULL != m_msaaRtv[eye]) + { + m_msaaRtv[eye]->Release(); + m_msaaRtv[eye] = NULL; + } + } + } + + destroyMirror(); + } + + void VRImplOVRD3D11::destroyMirror() + { + if (NULL != m_mirrorTexture) + { + ovr_DestroyMirrorTexture(m_session, m_mirrorTexture); + m_mirrorTexture = NULL; + } + } + + void VRImplOVRD3D11::renderEyeStart(const VRDesc& _desc, uint8_t _eye) { ID3D11DeviceContext* deviceCtx = s_renderD3D11->m_deviceCtx; float black[] = { 0.0f, 0.0f, 0.0f, 0.0f }; // Important that alpha=0, if want pixels to be transparent, for manual layers // render to MSAA target - if (NULL != m_msaaTexture[_eyeIdx]) + if (NULL != m_msaaTexture[_eye]) { - deviceCtx->OMSetRenderTargets(1, &m_msaaRtv[_eyeIdx], m_depthBuffer[_eyeIdx]); - deviceCtx->ClearRenderTargetView(m_msaaRtv[_eyeIdx], black); - deviceCtx->ClearDepthStencilView(m_depthBuffer[_eyeIdx], D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1, 0); + deviceCtx->OMSetRenderTargets(1, &m_msaaRtv[_eye], m_depthBuffer[_eye]); + deviceCtx->ClearRenderTargetView(m_msaaRtv[_eye], black); + deviceCtx->ClearDepthStencilView(m_depthBuffer[_eye], D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1, 0); } else // MSAA disabled? render directly to eye buffer { int texIndex = 0; - ovr_GetTextureSwapChainCurrentIndex(_session, m_textureSwapChain[_eyeIdx], &texIndex); + ovr_GetTextureSwapChainCurrentIndex(m_session, m_textureSwapChain[_eye], &texIndex); - deviceCtx->OMSetRenderTargets(1, &m_eyeRtv[_eyeIdx][texIndex], m_depthBuffer[_eyeIdx]); - deviceCtx->ClearRenderTargetView(m_eyeRtv[_eyeIdx][texIndex], black); - deviceCtx->ClearDepthStencilView(m_depthBuffer[_eyeIdx], D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1, 0); + deviceCtx->OMSetRenderTargets(1, &m_eyeRtv[_eye][texIndex], m_depthBuffer[_eye]); + deviceCtx->ClearRenderTargetView(m_eyeRtv[_eye][texIndex], black); + deviceCtx->ClearDepthStencilView(m_depthBuffer[_eye], D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1, 0); D3D11_VIEWPORT D3Dvp; D3Dvp.TopLeftX = 0; D3Dvp.TopLeftY = 0; - D3Dvp.Width = (FLOAT)m_eyeTextureSize[_eyeIdx].w; - D3Dvp.Height = (FLOAT)m_eyeTextureSize[_eyeIdx].h; + D3Dvp.Width = (FLOAT)_desc.m_eyeSize[_eye].m_w; + D3Dvp.Height = (FLOAT)_desc.m_eyeSize[_eye].m_h; D3Dvp.MinDepth = 0; D3Dvp.MaxDepth = 1; deviceCtx->RSSetViewports(1, &D3Dvp); } } - void OVRRenderD3D11::postRender(const ovrSession& _session, int _eyeIdx) + bool VRImplOVRD3D11::submitSwapChain(const VRDesc& /* _desc */) { - if (NULL != m_msaaTexture[_eyeIdx]) - { - ID3D11DeviceContext* deviceCtx = s_renderD3D11->m_deviceCtx; - int destIndex = 0; - ovr_GetTextureSwapChainCurrentIndex(_session, m_textureSwapChain[_eyeIdx], &destIndex); - ID3D11Resource* dstTex = NULL; - ovr_GetTextureSwapChainBufferDX(_session, m_textureSwapChain[_eyeIdx], destIndex, IID_PPV_ARGS(&dstTex)); - deviceCtx->ResolveSubresource(dstTex, 0, m_msaaTexture[_eyeIdx], 0, DXGI_FORMAT_R8G8B8A8_UNORM); - dstTex->Release(); - } - } + ID3D11DeviceContext* deviceCtx = s_renderD3D11->m_deviceCtx; + IDXGISwapChain* swapChain = s_renderD3D11->m_swapChain; - void OVRRenderD3D11::destroy(const ovrSession& _session) - { + // resolve MSAA render targets for (int eye = 0; eye < 2; ++eye) { - for (uint32_t ii = 0; ii < BX_COUNTOF(m_eyeRtv[eye]); ++ii) - { - DX_RELEASE(m_eyeRtv[eye][ii], 0); - } - - ovr_DestroyTextureSwapChain(_session, m_textureSwapChain[eye]); - m_textureSwapChain[eye] = NULL; - m_depthBuffer[eye]->Release(); - if (NULL != m_msaaTexture[eye]) { - m_msaaTexture[eye]->Release(); - m_msaaTexture[eye] = NULL; + int destIndex = 0; + ovr_GetTextureSwapChainCurrentIndex(m_session, m_textureSwapChain[eye], &destIndex); + + ID3D11Resource* dstTex = NULL; + ovr_GetTextureSwapChainBufferDX(m_session, m_textureSwapChain[eye], destIndex, IID_PPV_ARGS(&dstTex)); + deviceCtx->ResolveSubresource(dstTex, 0, m_msaaTexture[eye], 0, DXGI_FORMAT_R8G8B8A8_UNORM); + dstTex->Release(); } - if (NULL != m_msaaSv[eye]) + ovrResult result = ovr_CommitTextureSwapChain(m_session, m_textureSwapChain[eye]); + if (!OVR_SUCCESS(result)) { - m_msaaSv[eye]->Release(); - m_msaaSv[eye] = NULL; - } - - if (NULL != m_msaaRtv[eye]) - { - m_msaaRtv[eye]->Release(); - m_msaaRtv[eye] = NULL; + return false; } } - if (NULL != m_mirrorTexture) + ovrLayerHeader* layerList = &m_renderLayer.Header; + ovrResult result = ovr_SubmitFrame(m_session, 0, NULL, &layerList, 1); + if (!OVR_SUCCESS(result)) { - ovr_DestroyMirrorTexture(_session, m_mirrorTexture); - m_mirrorTexture = NULL; + return false; } - } - void OVRRenderD3D11::blitMirror(const ovrSession& _session) - { - if (NULL != m_mirrorTexture) + if (result != ovrSuccess_NotVisible && NULL != m_mirrorTexture) { ID3D11Texture2D* tex = NULL; - ovr_GetMirrorTextureBufferDX(_session, m_mirrorTexture, IID_PPV_ARGS(&tex) ); + ovr_GetMirrorTextureBufferDX(m_session, m_mirrorTexture, IID_PPV_ARGS(&tex)); ID3D11Texture2D* backBuffer; - DX_CHECK(s_renderD3D11->m_swapChain->GetBuffer(0, IID_ID3D11Texture2D, (void**)&backBuffer) ); + DX_CHECK(swapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer))); - s_renderD3D11->m_deviceCtx->CopyResource(backBuffer, tex); - DX_CHECK(s_renderD3D11->m_swapChain->Present(0, 0) ); + deviceCtx->CopyResource(backBuffer, tex); + DX_CHECK(swapChain->Present(0, 0)); DX_RELEASE(tex, 1); DX_RELEASE(backBuffer, 0); } - } - void OVRRenderD3D11::preReset(const ovrSession& _session) - { - if (NULL != m_mirrorTexture) - { - ovr_DestroyMirrorTexture(_session, m_mirrorTexture); - m_mirrorTexture = NULL; - } + return true; } #endif // BGFX_CONFIG_USE_OVR @@ -5307,8 +5354,7 @@ BX_PRAGMA_DIAGNOSTIC_POP(); if (m_ovr.isEnabled() ) { - m_ovr.getViewport(eye, &viewState.m_rect); - m_ovr.renderEyeStart(eye); + m_ovr.renderEyeStart(eye, &viewState.m_rect); } else { diff --git a/src/renderer_d3d11.h b/src/renderer_d3d11.h index f929c480e..796e99c39 100644 --- a/src/renderer_d3d11.h +++ b/src/renderer_d3d11.h @@ -32,7 +32,7 @@ BX_PRAGMA_DIAGNOSTIC_POP() #include "renderer.h" #include "renderer_d3d.h" #include "shader_dxbc.h" -#include "hmd_ovr.h" +#include "hmd.h" #include "hmd_openvr.h" #include "debug_renderdoc.h" @@ -60,25 +60,6 @@ BX_PRAGMA_DIAGNOSTIC_POP() namespace bgfx { namespace d3d11 { -#if BGFX_CONFIG_USE_OVR - struct OVRRenderD3D11 : public OVRRenderI - { - virtual void create(const ovrSession& _session, int _msaaSamples, int _mirrorWidth, int _mirrorHeight); - virtual void destroy(const ovrSession& _session); - virtual void preReset(const ovrSession& _session); - virtual void startEyeRender(const ovrSession& _session, int _eyeIdx); - virtual void postRender(const ovrSession& _session, int _eyeIdx); - virtual void blitMirror(const ovrSession& _session); - - ID3D11RenderTargetView* m_eyeRtv[2][4]; - ID3D11DepthStencilView* m_depthBuffer[2]; - ID3D11Texture2D* m_msaaTexture[2]; - ID3D11ShaderResourceView* m_msaaSv[2]; - ID3D11RenderTargetView* m_msaaRtv[2]; - }; - -#endif // BGFX_CONFIG_USE_OVR - struct BufferD3D11 { BufferD3D11() diff --git a/src/renderer_gl.cpp b/src/renderer_gl.cpp index 829840ad3..22c9a9e19 100644 --- a/src/renderer_gl.cpp +++ b/src/renderer_gl.cpp @@ -9,6 +9,7 @@ # include "renderer_gl.h" # include # include +# include "hmd_ovr.h" #if BGFX_CONFIG_PROFILER_REMOTERY # define BGFX_GPU_PROFILER_BIND() rmt_BindOpenGL() @@ -1352,6 +1353,34 @@ namespace bgfx { namespace gl BX_UNUSED(supported); } +#if BGFX_CONFIG_USE_OVR + class VRImplOVRGL : public VRImplOVR + { + public: + VRImplOVRGL(); + + virtual bool createSwapChain(const VRDesc& _desc, int _msaaSamples, int _mirrorWidth, int _mirrorHeight); + virtual void destroySwapChain(); + virtual void destroyMirror(); + virtual void renderEyeStart(const VRDesc& _desc, uint8_t _eye); + virtual bool submitSwapChain(const VRDesc& _desc); + + private: + GLuint m_eyeFbo[2]; + GLuint m_eyeTexId[2][4]; + GLuint m_depthBuffer[2]; + GLuint m_msaaEyeFbo[2]; + GLuint m_msaaEyeTexId[2]; + GLuint m_msaaDepthBuffer[2]; + GLuint m_mirrorFbo; + GLint m_mirrorWidth; + GLint m_mirrorHeight; + + ovrTextureSwapChain m_textureSwapChain[2]; + ovrMirrorTexture m_mirrorTexture; + }; +#endif // BGFX_CONFIG_USE_OVR + struct RendererContextGL : public RendererContextI { RendererContextGL() @@ -1401,7 +1430,11 @@ namespace bgfx { namespace gl setRenderContextSize(BGFX_DEFAULT_WIDTH, BGFX_DEFAULT_HEIGHT); // Must be after context is initialized?! - m_ovr.init(); + VRImplI* vrImpl = NULL; +#if BGFX_CONFIG_USE_OVR + vrImpl = &m_ovrRender; +#endif + m_ovr.init(vrImpl); m_vendor = getGLString(GL_VENDOR); m_renderer = getGLString(GL_RENDERER); @@ -2205,15 +2238,8 @@ namespace bgfx { namespace gl m_glctx.swap(m_frameBuffers[m_windows[ii].idx].m_swapChain); } - switch (m_ovr.swap(_hmd, true) ) - { - case OVR::DeviceLost: - ovrPreReset(); - break; - - default: - break; - } + m_ovr.flip(); + m_ovr.swap(_hmd); // TODO - move this out of end-of-frame // need to swap GL render context even if OVR is enabled to get the mirror texture in the output m_glctx.swap(); @@ -2957,13 +2983,8 @@ namespace bgfx { namespace gl #if BGFX_CONFIG_USE_OVR if (m_resolution.m_flags & (BGFX_RESET_HMD|BGFX_RESET_HMD_DEBUG) ) { - if (m_ovr.postReset() ) - { - const uint32_t msaaSamples = 1 << ((m_resolution.m_flags&BGFX_RESET_MSAA_MASK) >> BGFX_RESET_MSAA_SHIFT); - - m_ovr.m_render = &m_ovrRender; - m_ovr.m_render->create(m_ovr.m_hmd, msaaSamples, m_resolution.m_width, m_resolution.m_height); - } + const uint32_t msaaSamples = 1 << ((m_resolution.m_flags&BGFX_RESET_MSAA_MASK) >> BGFX_RESET_MSAA_SHIFT); + m_ovr.postReset(msaaSamples, m_resolution.m_width, m_resolution.m_height); } #endif // BGFX_CONFIG_USE_OVR } @@ -3394,9 +3415,9 @@ namespace bgfx { namespace gl const char* m_version; const char* m_glslVersion; - OVR m_ovr; + VR m_ovr; #if BGFX_CONFIG_USE_OVR - OVRRenderGL m_ovrRender; + VRImplOVRGL m_ovrRender; #endif // BGFX_CONFIG_USE_OVR }; @@ -3417,238 +3438,245 @@ namespace bgfx { namespace gl } #if BGFX_CONFIG_USE_OVR - OVRRenderGL::OVRRenderGL() + + VRImplOVRGL::VRImplOVRGL() + : m_mirrorTexture(NULL) { - memset(&m_eyeFbo, 0, sizeof(m_eyeFbo)); - m_mirrorFBO = 0; + memset(&m_textureSwapChain, 0, sizeof(m_textureSwapChain)); } - void OVRRenderGL::create(const ovrSession& _session, int _msaaSamples, int _mirrorWidth, int _mirrorHeight) + static void setDefaultSamplerState() + { + GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); + GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); + } + + bool VRImplOVRGL::createSwapChain(const VRDesc& _desc, int _msaaSamples, int _mirrorWidth, int _mirrorHeight) { for (int eye = 0; eye < 2; ++eye) { if (NULL == m_textureSwapChain[eye]) { m_eyeFbo[eye] = 0; - m_eyeTexId[eye] = 0; m_depthBuffer[eye] = 0; m_msaaEyeFbo[eye] = 0; m_msaaEyeTexId[eye] = 0; m_msaaDepthBuffer[eye] = 0; + memset(&m_eyeTexId[eye], 0, sizeof(m_eyeTexId[eye])); - ovrHmdDesc hmdDesc = ovr_GetHmdDesc(_session); - m_eyeTextureSize[eye] = ovr_GetFovTextureSize(_session, ovrEyeType(eye), hmdDesc.DefaultEyeFov[eye], 1.0f); + ovrTextureSwapChainDesc swapchainDesc = {}; + swapchainDesc.Type = ovrTexture_2D; + swapchainDesc.ArraySize = 1; + swapchainDesc.Width = _desc.m_eyeSize[eye].m_w; + swapchainDesc.Height = _desc.m_eyeSize[eye].m_h; + swapchainDesc.MipLevels = 1; + swapchainDesc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB; + swapchainDesc.SampleCount = 1; + swapchainDesc.StaticImage = ovrFalse; - ovrTextureSwapChainDesc desc = {}; - desc.Type = ovrTexture_2D; - desc.ArraySize = 1; - desc.Width = m_eyeTextureSize[eye].w; - desc.Height = m_eyeTextureSize[eye].h; - desc.MipLevels = 1; - desc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB; - desc.SampleCount = 1; - desc.StaticImage = ovrFalse; - - ovr_CreateTextureSwapChainGL(_session, &desc, &m_textureSwapChain[eye]); + ovrResult result = ovr_CreateTextureSwapChainGL(m_session, &swapchainDesc, &m_textureSwapChain[eye]); + if (!OVR_SUCCESS(result)) + { + destroySwapChain(); + return false; + } int textureCount = 0; - ovr_GetTextureSwapChainLength(_session, m_textureSwapChain[eye], &textureCount); - - for (int j = 0; j < textureCount; ++j) + ovr_GetTextureSwapChainLength(m_session, m_textureSwapChain[eye], &textureCount); + for (int ii = 0; ii < textureCount; ++ii) { - GLuint chainTexId; - ovr_GetTextureSwapChainBufferGL(_session, m_textureSwapChain[eye], j, &chainTexId); - GL_CHECK(glBindTexture(GL_TEXTURE_2D, chainTexId) ); - - GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) ); - GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) ); - GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) ); - GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE) ); + ovr_GetTextureSwapChainBufferGL(m_session, m_textureSwapChain[eye], ii, &m_eyeTexId[eye][ii]); + GL_CHECK(glBindTexture(GL_TEXTURE_2D, m_eyeTexId[eye][ii])); + setDefaultSamplerState(); } - GL_CHECK(glGenFramebuffers(1, &m_eyeFbo[eye]) ); + GL_CHECK(glGenFramebuffers(1, &m_eyeFbo[eye])); // create depth buffer - GL_CHECK(glGenTextures(1, &m_depthBuffer[eye]) ); - GL_CHECK(glBindTexture(GL_TEXTURE_2D, m_depthBuffer[eye]) ); - GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) ); - GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) ); - GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) ); - GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE) ); + GL_CHECK(glGenTextures(1, &m_depthBuffer[eye])); + GL_CHECK(glBindTexture(GL_TEXTURE_2D, m_depthBuffer[eye])); + setDefaultSamplerState(); - GL_CHECK(glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, m_eyeTextureSize[eye].w, m_eyeTextureSize[eye].h, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL) ); + GL_CHECK(glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, _desc.m_eyeSize[eye].m_w, _desc.m_eyeSize[eye].m_h, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL)); - // create MSAA buffers + GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, m_eyeFbo[eye])); + GL_CHECK(glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_depthBuffer[eye], 0)); + GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, 0)); + + // create MSAA targets if needed if (_msaaSamples > 1) { - GL_CHECK(glGenFramebuffers(1, &m_msaaEyeFbo[eye]) ); + GL_CHECK(glGenFramebuffers(1, &m_msaaEyeFbo[eye])); // create color MSAA texture - GL_CHECK(glGenTextures(1, &m_msaaEyeTexId[eye]) ); - GL_CHECK(glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_msaaEyeTexId[eye]) ); - - GL_CHECK(glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, _msaaSamples, GL_RGBA, m_eyeTextureSize[eye].w, m_eyeTextureSize[eye].h, false) ); - GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER) ); - GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER) ); - GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR) ); - GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) ); - GL_CHECK(glTexParameteri(GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_MAX_LEVEL, 0) ); + GL_CHECK(glGenTextures(1, &m_msaaEyeTexId[eye])); + GL_CHECK(glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_msaaEyeTexId[eye])); + GL_CHECK(glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, _msaaSamples, GL_RGBA, _desc.m_eyeSize[eye].m_w, _desc.m_eyeSize[eye].m_h, false)); + setDefaultSamplerState(); // create MSAA depth buffer - GL_CHECK(glGenTextures(1, &m_msaaDepthBuffer[eye]) ); - GL_CHECK(glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_msaaDepthBuffer[eye]) ); + GL_CHECK(glGenTextures(1, &m_msaaDepthBuffer[eye])); + GL_CHECK(glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_depthBuffer[eye])); + GL_CHECK(glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, _msaaSamples, GL_DEPTH_COMPONENT, _desc.m_eyeSize[eye].m_w, _desc.m_eyeSize[eye].m_h, false)); + setDefaultSamplerState(); - GL_CHECK(glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, _msaaSamples, GL_DEPTH_COMPONENT, m_eyeTextureSize[eye].w, m_eyeTextureSize[eye].h, false) ); - GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT) ); - GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT) ); - GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR) ); - GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) ); - GL_CHECK(glTexParameteri(GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_MAX_LEVEL, 0) ); + GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, m_msaaEyeFbo[eye])); + GL_CHECK(glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, m_msaaEyeTexId[eye], 0)); + GL_CHECK(glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0)); + GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, 0)); } + + m_renderLayer.ColorTexture[eye] = m_textureSwapChain[eye]; } } + m_renderLayer.Header.Flags |= ovrLayerFlag_TextureOriginAtBottomLeft; + if (NULL == m_mirrorTexture) { - memset(&m_mirrorTextureDesc, 0, sizeof(m_mirrorTextureDesc) ); - m_mirrorTextureDesc.Width = _mirrorWidth; - m_mirrorTextureDesc.Height = _mirrorHeight; - m_mirrorTextureDesc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB; + m_mirrorFbo = 0; - ovr_CreateMirrorTextureGL(_session, &m_mirrorTextureDesc, &m_mirrorTexture); + ovrMirrorTextureDesc mirrorDesc = {}; + mirrorDesc.Width = _mirrorWidth; + mirrorDesc.Height = _mirrorHeight; + mirrorDesc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB; // Fallback to doing nothing if mirror was not created. This is to prevent errors with fast window resizes - if (!m_mirrorTexture) - return; - - // Configure the mirror read buffer - GLuint texId; - ovr_GetMirrorTextureBufferGL(_session, m_mirrorTexture, &texId); - GL_CHECK(glGenFramebuffers(1, &m_mirrorFBO) ); - GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, m_mirrorFBO) ); - GL_CHECK(glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texId, 0) ); - GL_CHECK(glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0) ); - GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, 0) ); - - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + ovr_CreateMirrorTextureGL(m_session, &mirrorDesc, &m_mirrorTexture); + if (m_mirrorTexture) { - GL_CHECK(glDeleteFramebuffers(1, &m_mirrorFBO) ); - BX_CHECK(false, "Could not initialize VR buffers!"); + m_mirrorWidth = _mirrorWidth; + m_mirrorHeight = _mirrorHeight; + + // Configure the mirror read buffer + GLuint texId; + ovr_GetMirrorTextureBufferGL(m_session, m_mirrorTexture, &texId); + GL_CHECK(glGenFramebuffers(1, &m_mirrorFbo)); + GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, m_mirrorFbo)); + GL_CHECK(glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texId, 0)); + GL_CHECK(glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0)); + GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, 0)); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + { + GL_CHECK(glDeleteFramebuffers(1, &m_mirrorFbo)); + ovr_DestroyMirrorTexture(m_session, m_mirrorTexture); + m_mirrorTexture = NULL; + BX_CHECK(false, "Could not initialize VR mirror buffers!"); + } } } + + return true; } - void OVRRenderGL::startEyeRender(const ovrSession& _session, int _eyeIdx) - { - // set the current eye texture in swap chain - int curIndex; - ovr_GetTextureSwapChainCurrentIndex(_session, m_textureSwapChain[_eyeIdx], &curIndex); - ovr_GetTextureSwapChainBufferGL(_session, m_textureSwapChain[_eyeIdx], curIndex, &m_eyeTexId[_eyeIdx]); - - if (0 != m_msaaEyeFbo[_eyeIdx]) - { - GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_msaaEyeFbo[_eyeIdx]) ); - GL_CHECK(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, m_msaaEyeTexId[_eyeIdx], 0) ); - GL_CHECK(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D_MULTISAMPLE, m_msaaDepthBuffer[_eyeIdx], 0) ); - } - else // MSAA disabled? render directly to eye buffer - { - GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_eyeFbo[_eyeIdx]) ); - GL_CHECK(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_eyeTexId[_eyeIdx], 0) ); - GL_CHECK(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_depthBuffer[_eyeIdx], 0) ); - } - GL_CHECK(glViewport(0, 0, m_eyeTextureSize[_eyeIdx].w, m_eyeTextureSize[_eyeIdx].h) ); - GL_CHECK(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) ); - } - - void OVRRenderGL::postRender(const ovrSession& /*_sesion*/, int _eyeIdx) - { - if (0 != m_msaaEyeFbo[_eyeIdx] && 0 != m_eyeTexId[_eyeIdx]) - { - // blit the contents of MSAA FBO to the regular eye buffer "connected" to the HMD - GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, m_msaaEyeFbo[_eyeIdx])); - GL_CHECK(glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, m_msaaEyeTexId[_eyeIdx], 0) ); - GL_CHECK(glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0) ); - - BX_CHECK(GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_READ_FRAMEBUFFER) - , "glCheckFramebufferStatus failed 0x%08x" - , glCheckFramebufferStatus(GL_READ_FRAMEBUFFER) ); - - GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_eyeFbo[_eyeIdx])); - GL_CHECK(glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_eyeTexId[_eyeIdx], 0) ); - GL_CHECK(glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0) ); - - BX_CHECK(GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) - , "glCheckFramebufferStatus failed 0x%08x" - , glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) ); - - GL_CHECK(glBlitFramebuffer(0, 0, m_eyeTextureSize[_eyeIdx].w, m_eyeTextureSize[_eyeIdx].h, - 0, 0, m_eyeTextureSize[_eyeIdx].w, m_eyeTextureSize[_eyeIdx].h, GL_COLOR_BUFFER_BIT, GL_NEAREST) ); - - GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, 0) ); - } - } - - void OVRRenderGL::destroy(const ovrSession& _session) + void VRImplOVRGL::destroySwapChain() { for (int eye = 0; eye < 2; ++eye) { - GL_CHECK(glDeleteFramebuffers(1, &m_eyeFbo[eye]) ); - GL_CHECK(glDeleteTextures(1, &m_depthBuffer[eye]) ); + if (NULL != m_textureSwapChain[eye]) + { + GL_CHECK(glDeleteFramebuffers(1, &m_eyeFbo[eye])); + GL_CHECK(glDeleteTextures(1, &m_depthBuffer[eye])); - ovr_DestroyTextureSwapChain(_session, m_textureSwapChain[eye]); - m_textureSwapChain[eye] = NULL; + ovr_DestroyTextureSwapChain(m_session, m_textureSwapChain[eye]); + m_textureSwapChain[eye] = NULL; + if (0 != m_msaaEyeFbo[eye]) + { + GL_CHECK(glDeleteFramebuffers(1, &m_msaaEyeFbo[eye])); + GL_CHECK(glDeleteTextures(1, &m_msaaEyeTexId[eye])); + GL_CHECK(glDeleteTextures(1, &m_msaaDepthBuffer[eye])); + m_msaaEyeFbo[eye] = 0; + } + } + } + + destroyMirror(); + } + + void VRImplOVRGL::destroyMirror() + { + if (NULL != m_mirrorTexture) + { + GL_CHECK(glDeleteFramebuffers(1, &m_mirrorFbo)); + ovr_DestroyMirrorTexture(m_session, m_mirrorTexture); + m_mirrorTexture = NULL; + } + } + + void VRImplOVRGL::renderEyeStart(const VRDesc& _desc, uint8_t _eye) + { + // set the current eye texture in the swap chain + if (0 != m_msaaEyeFbo[_eye]) + { + GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_msaaEyeFbo[_eye])); + } + else + { + int texIndex; + ovr_GetTextureSwapChainCurrentIndex(m_session, m_textureSwapChain[_eye], &texIndex); + + GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_eyeFbo[_eye])); + GL_CHECK(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_eyeTexId[_eye][texIndex], 0)); + } + + GL_CHECK(glViewport(0, 0, _desc.m_eyeSize[_eye].m_w, _desc.m_eyeSize[_eye].m_h)); + GL_CHECK(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); + } + + bool VRImplOVRGL::submitSwapChain(const VRDesc& _desc) + { + for (int eye = 0; eye < 2; ++eye) + { if (0 != m_msaaEyeFbo[eye]) { - GL_CHECK(glDeleteFramebuffers(1, &m_msaaEyeFbo[eye]) ); - m_msaaEyeFbo[eye] = 0; + // blit the contents of MSAA FBO to the regulare eye buffer "connected" to the HMD + int destIndex; + ovr_GetTextureSwapChainCurrentIndex(m_session, m_textureSwapChain[eye], &destIndex); + + GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, m_msaaEyeFbo[eye])); + BX_CHECK(GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_READ_FRAMEBUFFER) + , "glCheckFramebufferStatus failed 0x%08x" + , glCheckFramebufferStatus(GL_READ_FRAMEBUFFER)); + + GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_eyeFbo[eye])); + GL_CHECK(glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_eyeTexId[eye][destIndex], 0)); + BX_CHECK(GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) + , "glCheckFramebufferStatus failed 0x%08x" + , glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER)); + + GL_CHECK(glBlitFramebuffer(0, 0, _desc.m_eyeSize[eye].m_w, _desc.m_eyeSize[eye].m_h, 0, 0, _desc.m_eyeSize[eye].m_w, _desc.m_eyeSize[eye].m_h, GL_COLOR_BUFFER_BIT, GL_NEAREST)); + GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, 0)); } - if (0 != m_msaaEyeTexId[eye]) + ovrResult result = ovr_CommitTextureSwapChain(m_session, m_textureSwapChain[eye]); + if (!OVR_SUCCESS(result)) { - GL_CHECK(glDeleteTextures(1, &m_msaaEyeTexId[eye])); - m_msaaEyeTexId[eye] = 0; - } - - if (0 != m_msaaDepthBuffer[eye]) - { - GL_CHECK(glDeleteTextures(1, &m_msaaDepthBuffer[eye])); - m_msaaDepthBuffer[eye] = 0; + return false; } } - if (NULL != m_mirrorTexture) + ovrLayerHeader* layerList = &m_renderLayer.Header; + ovrResult result = ovr_SubmitFrame(m_session, 0, &m_viewScale, &layerList, 1); + if (!OVR_SUCCESS(result)) { - GL_CHECK(glDeleteFramebuffers(1, &m_mirrorFBO) ); - ovr_DestroyMirrorTexture(_session, m_mirrorTexture); - m_mirrorTexture = NULL; + return false; } + + if (result != ovrSuccess_NotVisible && NULL != m_mirrorTexture) + { + GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, m_mirrorFbo)); + GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0)); + GL_CHECK(glBlitFramebuffer(0, m_mirrorHeight, m_mirrorWidth, 0, 0, 0, m_mirrorWidth, m_mirrorHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST)); + GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, 0)); + } + + return true; } - void OVRRenderGL::blitMirror(const ovrSession& /*_session*/) - { - if (NULL != m_mirrorTexture) - { - // Blit mirror texture to back buffer - GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, m_mirrorFBO) ); - GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0) ); - GLint width = m_mirrorTextureDesc.Width; - GLint height = m_mirrorTextureDesc.Height; - GL_CHECK(glBlitFramebuffer(0, height, width, 0, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST) ); - GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, 0) ); - } - } - - void OVRRenderGL::preReset(const ovrSession& _session) - { - if (NULL != m_mirrorTexture) - { - GL_CHECK(glDeleteFramebuffers(1, &m_mirrorFBO) ); - ovr_DestroyMirrorTexture(_session, m_mirrorTexture); - m_mirrorTexture = NULL; - } - } #endif // BGFX_CONFIG_USE_OVR const char* glslTypeName(GLuint _type) @@ -6183,8 +6211,7 @@ namespace bgfx { namespace gl if (m_ovr.isEnabled() ) { - m_ovr.getViewport(eye, &viewState.m_rect); - m_ovr.renderEyeStart(eye); + m_ovr.renderEyeStart(eye, &viewState.m_rect); } else { diff --git a/src/renderer_gl.h b/src/renderer_gl.h index a4f0e6fdc..733d55062 100644 --- a/src/renderer_gl.h +++ b/src/renderer_gl.h @@ -107,7 +107,7 @@ typedef uint64_t GLuint64; #endif // BGFX_CONFIG_RENDERER_OPENGL #include "renderer.h" -#include "hmd_ovr.h" +#include "hmd.h" #include "hmd_openvr.h" #include "debug_renderdoc.h" @@ -950,28 +950,6 @@ namespace bgfx namespace bgfx { namespace gl { -#if BGFX_CONFIG_USE_OVR - struct OVRRenderGL : public OVRRenderI - { - OVRRenderGL(); - virtual void create(const ovrSession& _session, int _msaaSamples, int _mirrorWidth, int _mirrorHeight); - virtual void destroy(const ovrSession& _session); - virtual void preReset(const ovrSession& _session); - virtual void startEyeRender(const ovrSession& _session, int _eyeIdx); - virtual void postRender(const ovrSession& _session, int _eyeIdx); - virtual void blitMirror(const ovrSession& _session); - - GLuint m_eyeFbo[2]; - GLuint m_eyeTexId[2]; - GLuint m_depthBuffer[2]; - GLuint m_msaaEyeFbo[2]; - GLuint m_msaaEyeTexId[2]; - GLuint m_msaaDepthBuffer[2]; - GLuint m_mirrorFBO; - }; - -#endif // BGFX_CONFIG_USE_OVR - void dumpExtensions(const char* _extensions); const char* glEnumName(GLenum _enum);