diff --git a/README.md b/README.md index ca2f1c484..9c163f9c6 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Supported rendering backends: Supported HMD: - * OculusVR (0.4.2+) + * OculusVR (1.3.0) Supported platforms: diff --git a/examples/01-cubes/cubes.cpp b/examples/01-cubes/cubes.cpp index bf88eb3f7..97cf60529 100644 --- a/examples/01-cubes/cubes.cpp +++ b/examples/01-cubes/cubes.cpp @@ -143,11 +143,7 @@ class ExampleCubes : public entry::AppI { float view[16]; bx::mtxQuatTranslationHMD(view, hmd->eye[0].rotation, eye); - - float proj[16]; - bx::mtxProj(proj, hmd->eye[0].fov, 0.1f, 100.0f); - - bgfx::setViewTransform(0, view, proj); + bgfx::setViewTransform(0, view, hmd->eye[0].projection); // Set view 0 default viewport. // diff --git a/examples/02-metaballs/metaballs.cpp b/examples/02-metaballs/metaballs.cpp index bedf55497..f0f20e39c 100644 --- a/examples/02-metaballs/metaballs.cpp +++ b/examples/02-metaballs/metaballs.cpp @@ -577,11 +577,7 @@ class ExampleMetaballs : public entry::AppI { float view[16]; bx::mtxQuatTranslationHMD(view, hmd->eye[0].rotation, eye); - - float proj[16]; - bx::mtxProj(proj, hmd->eye[0].fov, 0.1f, 100.0f); - - bgfx::setViewTransform(0, view, proj); + bgfx::setViewTransform(0, view, hmd->eye[0].projection); // Set view 0 default viewport. // diff --git a/examples/04-mesh/mesh.cpp b/examples/04-mesh/mesh.cpp index bfe61df6a..f7f8b7e96 100644 --- a/examples/04-mesh/mesh.cpp +++ b/examples/04-mesh/mesh.cpp @@ -91,11 +91,7 @@ class ExampleMesh : public entry::AppI { float view[16]; bx::mtxQuatTranslationHMD(view, hmd->eye[0].rotation, eye); - - float proj[16]; - bx::mtxProj(proj, hmd->eye[0].fov, 0.1f, 100.0f); - - bgfx::setViewTransform(0, view, proj); + bgfx::setViewTransform(0, view, hmd->eye[0].projection); // Set view 0 default viewport. // diff --git a/examples/05-instancing/instancing.cpp b/examples/05-instancing/instancing.cpp index 6e854b207..1a0f0b69c 100644 --- a/examples/05-instancing/instancing.cpp +++ b/examples/05-instancing/instancing.cpp @@ -160,11 +160,7 @@ class ExampleInstancing : public entry::AppI { float view[16]; bx::mtxQuatTranslationHMD(view, hmd->eye[0].rotation, eye); - - float proj[16]; - bx::mtxProj(proj, hmd->eye[0].fov, 0.1f, 100.0f); - - bgfx::setViewTransform(0, view, proj); + bgfx::setViewTransform(0, view, hmd->eye[0].projection); // Set view 0 default viewport. // diff --git a/examples/06-bump/bump.cpp b/examples/06-bump/bump.cpp index bc5f9e74b..da6cff3d7 100644 --- a/examples/06-bump/bump.cpp +++ b/examples/06-bump/bump.cpp @@ -225,11 +225,7 @@ class ExampleBump : public entry::AppI { float view[16]; bx::mtxQuatTranslationHMD(view, hmd->eye[0].rotation, eye); - - float proj[16]; - bx::mtxProj(proj, hmd->eye[0].fov, 0.1f, 100.0f); - - bgfx::setViewTransform(0, view, proj); + bgfx::setViewTransform(0, view, hmd->eye[0].projection); // Set view 0 default viewport. // diff --git a/examples/12-lod/lod.cpp b/examples/12-lod/lod.cpp index ef37d254c..c66db5a24 100644 --- a/examples/12-lod/lod.cpp +++ b/examples/12-lod/lod.cpp @@ -174,11 +174,7 @@ class ExampleLod : public entry::AppI { float view[16]; bx::mtxQuatTranslationHMD(view, hmd->eye[0].rotation, eye); - - float proj[16]; - bx::mtxProj(proj, hmd->eye[0].fov, 0.1f, 100.0f); - - bgfx::setViewTransform(0, view, proj); + bgfx::setViewTransform(0, view, hmd->eye[0].projection); // Set view 0 default viewport. // diff --git a/examples/24-nbody/nbody.cpp b/examples/24-nbody/nbody.cpp index 79f722f96..f04766a58 100644 --- a/examples/24-nbody/nbody.cpp +++ b/examples/24-nbody/nbody.cpp @@ -305,11 +305,7 @@ int _main_(int _argc, char** _argv) float tmp[16]; bx::mtxMul(tmp, view, viewHead); - - float proj[16]; - bx::mtxProj(proj, hmd->eye[0].fov, 0.1f, 10000.0f); - - bgfx::setViewTransform(0, tmp, proj); + bgfx::setViewTransform(0, tmp, hmd->eye[0].projection); // Set view 0 default viewport. // diff --git a/examples/26-occlusion/occlusion.cpp b/examples/26-occlusion/occlusion.cpp index 81e00f0c5..8f03686ed 100644 --- a/examples/26-occlusion/occlusion.cpp +++ b/examples/26-occlusion/occlusion.cpp @@ -181,13 +181,10 @@ class ExampleOcclusion : public entry::AppI float tmp[16]; bx::mtxMul(tmp, view, viewHead); - float proj[16]; - bx::mtxProj(proj, hmd->eye[0].fov, 0.1f, 10000.0f); - - bgfx::setViewTransform(0, tmp, proj); + bgfx::setViewTransform(0, tmp, hmd->eye[0].projection); bgfx::setViewRect(0, 0, 0, hmd->width, hmd->height); - bgfx::setViewTransform(1, tmp, proj); + bgfx::setViewTransform(1, tmp, hmd->eye[1].projection); bgfx::setViewRect(1, 0, 0, hmd->width, hmd->height); } else diff --git a/include/bgfx/bgfx.h b/include/bgfx/bgfx.h index 456b3c03c..eda902ce2 100644 --- a/include/bgfx/bgfx.h +++ b/include/bgfx/bgfx.h @@ -615,6 +615,7 @@ namespace bgfx float translation[3]; //!< Eye translation. float fov[4]; //!< Field of view (up, down, left, right). float viewOffset[3]; //!< Eye view matrix translation adjustment. + float projection[16]; //!< Eye projection matrix float pixelsPerTanAngle[2]; //!< }; @@ -1914,7 +1915,7 @@ namespace bgfx /// void setViewRect(uint8_t _id, uint16_t _x, uint16_t _y, uint16_t _width, uint16_t _height); - /// @attention C99 equivalent is `bgfx_set_view_rect_auto`. + /// @attention C99 equivalent is `bgfx_set_view_rect_auto`. /// void setViewRect(uint8_t _id, uint16_t _x, uint16_t _y, BackbufferRatio::Enum _ratio); diff --git a/scripts/genie.lua b/scripts/genie.lua index 5ae3b4f73..f6a1895e1 100644 --- a/scripts/genie.lua +++ b/scripts/genie.lua @@ -178,42 +178,20 @@ function exampleProject(_name) "ws2_32", } - -- Check for LibOVR 5.0+ - if os.isdir(path.join(os.getenv("OVR_DIR"), "LibOVR/Lib/Windows/Win32/Debug/VS2012")) then + configuration { "x32", "Debug" } + libdirs { path.join("$(OVR_DIR)/LibOVR/Lib/Windows/Win32/Debug", _ACTION) } - configuration { "x32", "Debug" } - libdirs { path.join("$(OVR_DIR)/LibOVR/Lib/Windows/Win32/Debug", _ACTION) } + configuration { "x32", "Release" } + libdirs { path.join("$(OVR_DIR)/LibOVR/Lib/Windows/Win32/Release", _ACTION) } - configuration { "x32", "Release" } - libdirs { path.join("$(OVR_DIR)/LibOVR/Lib/Windows/Win32/Release", _ACTION) } + configuration { "x64", "Debug" } + libdirs { path.join("$(OVR_DIR)/LibOVR/Lib/Windows/x64/Debug", _ACTION) } - configuration { "x64", "Debug" } - libdirs { path.join("$(OVR_DIR)/LibOVR/Lib/Windows/x64/Debug", _ACTION) } + configuration { "x64", "Release" } + libdirs { path.join("$(OVR_DIR)/LibOVR/Lib/Windows/x64/Release", _ACTION) } - configuration { "x64", "Release" } - libdirs { path.join("$(OVR_DIR)/LibOVR/Lib/Windows/x64/Release", _ACTION) } - - configuration { "x32 or x64" } - links { "libovr" } - else - configuration { "x32" } - libdirs { path.join("$(OVR_DIR)/LibOVR/Lib/Win32", _ACTION) } - - configuration { "x64" } - libdirs { path.join("$(OVR_DIR)/LibOVR/Lib/x64", _ACTION) } - - configuration { "x32", "Debug" } - links { "libovrd" } - - configuration { "x32", "Release" } - links { "libovr" } - - configuration { "x64", "Debug" } - links { "libovr64d" } - - configuration { "x64", "Release" } - links { "libovr64" } - end + configuration { "x32 or x64" } + links { "libovr" } configuration {} end diff --git a/src/ovr.cpp b/src/ovr.cpp index 5cd62ef39..3f37680c9 100644 --- a/src/ovr.cpp +++ b/src/ovr.cpp @@ -9,17 +9,15 @@ namespace bgfx { -#if OVR_VERSION <= OVR_VERSION_050 -# define OVR_EYE_BUFFER 100 -#else -# define OVR_EYE_BUFFER 8 -#endif // OVR_VERSION... - OVR::OVR() : m_hmd(NULL) , m_isenabled(false) - , m_debug(false) + , m_mirror(NULL) + , m_hmdFrameReady(-1) + , m_frameIndex(0) + , m_sensorSampleTime(0) { + memset(m_eyeBuffers, 0, sizeof(m_eyeBuffers)); } OVR::~OVR() @@ -29,225 +27,162 @@ namespace bgfx void OVR::init() { - bool initialized = !!ovr_Initialize(); - BX_WARN(initialized, "Unable to create OVR device."); - if (!initialized) + ovrResult initialized = ovr_Initialize(NULL); + ovrGraphicsLuid luid; + + BX_WARN(initialized == ovrSuccess, "Unable to create OVR device."); + + if (initialized != ovrSuccess) { return; } - m_hmd = ovrHmd_Create(0); - if (NULL == m_hmd) + initialized = ovr_Create(&m_hmd, &luid); + if (initialized != ovrSuccess) { - m_hmd = ovrHmd_CreateDebug(ovrHmd_DK2); - BX_WARN(NULL != m_hmd, "Unable to create OVR device."); - if (NULL == m_hmd) - { - return; - } + BX_WARN(initialized == ovrSuccess, "Unable to create OVR device."); + return; } + m_hmdDesc = ovr_GetHmdDesc(m_hmd); + BX_TRACE("HMD: %s, %s, firmware: %d.%d" - , m_hmd->ProductName - , m_hmd->Manufacturer - , m_hmd->FirmwareMajor - , m_hmd->FirmwareMinor + , m_hmdDesc.ProductName + , m_hmdDesc.Manufacturer + , m_hmdDesc.FirmwareMajor + , m_hmdDesc.FirmwareMinor ); - ovrSizei sizeL = ovrHmd_GetFovTextureSize(m_hmd, ovrEye_Left, m_hmd->DefaultEyeFov[0], 1.0f); - ovrSizei sizeR = ovrHmd_GetFovTextureSize(m_hmd, ovrEye_Right, m_hmd->DefaultEyeFov[1], 1.0f); - m_rtSize.w = sizeL.w + sizeR.w + OVR_EYE_BUFFER; - m_rtSize.h = bx::uint32_max(sizeL.h, sizeR.h); - m_warning = true; + 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_isenabled, "HMD not disabled."); - ovrHmd_Destroy(m_hmd); + + for (int i = 0; i < 2; i++) + { + if (m_eyeBuffers[i]) + { + m_eyeBuffers[i]->destroy(m_hmd); + BX_DELETE(g_allocator, m_eyeBuffers[i]); + } + } + + if (m_mirror) + { + m_mirror->destroy(m_hmd); + BX_DELETE(g_allocator, m_mirror); + } + + ovr_Destroy(m_hmd); m_hmd = NULL; ovr_Shutdown(); } void OVR::getViewport(uint8_t _eye, Rect* _viewport) { - _viewport->m_x = _eye * (m_rtSize.w + OVR_EYE_BUFFER + 1)/2; + _viewport->m_x = 0; _viewport->m_y = 0; - _viewport->m_width = (m_rtSize.w - OVR_EYE_BUFFER)/2; - _viewport->m_height = m_rtSize.h; + _viewport->m_width = m_eyeBuffers[_eye]->m_eyeTextureSize.w; + _viewport->m_height = m_eyeBuffers[_eye]->m_eyeTextureSize.h; } - bool OVR::postReset(void* _nwh, ovrRenderAPIConfig* _config, bool _debug) + void OVR::renderEyeStart(uint8_t _eye) { - if (_debug) - { - switch (_config->Header.API) - { -#if BGFX_CONFIG_RENDERER_DIRECT3D11 - case ovrRenderAPI_D3D11: - { - ovrD3D11ConfigData* data = (ovrD3D11ConfigData*)_config; -# if OVR_VERSION > OVR_VERSION_043 - m_rtSize = data->Header.BackBufferSize; -# else - m_rtSize = data->Header.RTSize; -# endif // OVR_VERSION > OVR_VERSION_043 - } - break; -#endif // BGFX_CONFIG_RENDERER_DIRECT3D11 - -#if BGFX_CONFIG_RENDERER_OPENGL - case ovrRenderAPI_OpenGL: - { - ovrGLConfigData* data = (ovrGLConfigData*)_config; -# if OVR_VERSION > OVR_VERSION_043 - m_rtSize = data->Header.BackBufferSize; -# else - m_rtSize = data->Header.RTSize; -# endif // OVR_VERSION > OVR_VERSION_043 - } - break; -#endif // BGFX_CONFIG_RENDERER_OPENGL - - case ovrRenderAPI_None: - default: - BX_CHECK(false, "You should not be here!"); - break; - } - - m_debug = true; - return false; - } + m_eyeBuffers[_eye]->onRender(m_hmd); + } + bool OVR::postReset() + { if (NULL == m_hmd) { return false; } + for (int eyeIdx = 0; eyeIdx < ovrEye_Count; eyeIdx++) + { + m_erd[eyeIdx] = ovr_GetRenderDesc(m_hmd, (ovrEyeType)eyeIdx, m_hmdDesc.DefaultEyeFov[eyeIdx]); + } + m_isenabled = true; - ovrBool result; - result = ovrHmd_AttachToWindow(m_hmd, _nwh, NULL, NULL); - if (!result) { goto ovrError; } - - ovrFovPort eyeFov[2] = { m_hmd->DefaultEyeFov[0], m_hmd->DefaultEyeFov[1] }; - result = ovrHmd_ConfigureRendering(m_hmd - , _config - , 0 -#if OVR_VERSION < OVR_VERSION_050 - | ovrDistortionCap_Chromatic // permanently enabled >= v5.0 -#endif - | ovrDistortionCap_Vignette - | ovrDistortionCap_TimeWarp - | ovrDistortionCap_Overdrive - | ovrDistortionCap_NoRestore - | ovrDistortionCap_HqDistortion - , eyeFov - , m_erd - ); - if (!result) { goto ovrError; } - - ovrHmd_SetEnabledCaps(m_hmd - , 0 - | ovrHmdCap_LowPersistence - | ovrHmdCap_DynamicPrediction - ); - - result = ovrHmd_ConfigureTracking(m_hmd - , 0 - | ovrTrackingCap_Orientation - | ovrTrackingCap_MagYawCorrection - | ovrTrackingCap_Position - , 0 - ); - - if (!result) - { -ovrError: - BX_TRACE("Failed to initialize OVR."); - m_isenabled = false; - return false; - } - - m_warning = true; return true; } - void OVR::postReset(const ovrTexture& _texture) - { - if (NULL != m_hmd) - { - m_texture[0] = _texture; - m_texture[1] = _texture; - - ovrRecti rect; - rect.Pos.x = 0; - rect.Pos.y = 0; - rect.Size.w = (m_rtSize.w - OVR_EYE_BUFFER)/2; - rect.Size.h = m_rtSize.h; - - m_texture[0].Header.RenderViewport = rect; - - rect.Pos.x += rect.Size.w + OVR_EYE_BUFFER; - m_texture[1].Header.RenderViewport = rect; - - m_timing = ovrHmd_BeginFrame(m_hmd, 0); -#if OVR_VERSION > OVR_VERSION_042 - m_pose[0] = ovrHmd_GetHmdPosePerEye(m_hmd, ovrEye_Left); - m_pose[1] = ovrHmd_GetHmdPosePerEye(m_hmd, ovrEye_Right); -#else - m_pose[0] = ovrHmd_GetEyePose(m_hmd, ovrEye_Left); - m_pose[1] = ovrHmd_GetEyePose(m_hmd, ovrEye_Right); -#endif // OVR_VERSION > OVR_VERSION_042 - } - } - void OVR::preReset() { if (m_isenabled) { - ovrHmd_EndFrame(m_hmd, m_pose, m_texture); - ovrHmd_AttachToWindow(m_hmd, NULL, NULL, NULL); - ovrHmd_ConfigureRendering(m_hmd, NULL, 0, NULL, NULL); + // on window resize this will recreate the mirror texture in ovrPostReset + m_mirror->destroy(m_hmd); + BX_DELETE(g_allocator, m_mirror); + m_mirror = NULL; m_isenabled = false; } - - m_debug = false; } - bool OVR::swap(HMD& _hmd) + void OVR::commitEye(uint8_t _eye) + { + if (m_isenabled) + { + m_hmdFrameReady = ovr_CommitTextureSwapChain(m_hmd, m_eyeBuffers[_eye]->m_swapTextureChain); + } + } + + bool OVR::swap(HMD& _hmd, bool originBottomLeft) { _hmd.flags = BGFX_HMD_NONE; if (NULL != m_hmd) { _hmd.flags |= BGFX_HMD_DEVICE_RESOLUTION; - _hmd.deviceWidth = m_hmd->Resolution.w; - _hmd.deviceHeight = m_hmd->Resolution.h; + _hmd.deviceWidth = m_hmdDesc.Resolution.w; + _hmd.deviceHeight = m_hmdDesc.Resolution.h; } - if (!m_isenabled) + if (!m_isenabled || !OVR_SUCCESS(m_hmdFrameReady)) { return false; } _hmd.flags |= BGFX_HMD_RENDERING; - ovrHmd_EndFrame(m_hmd, m_pose, m_texture); - if (m_warning) + // 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 (int eye = 0; eye < ovrEye_Count; eye++) { - m_warning = !ovrHmd_DismissHSWDisplay(m_hmd); + eyeLayer.ColorTexture[eye] = m_eyeBuffers[eye]->m_swapTextureChain; + eyeLayer.Viewport[eye] = ::OVR::Recti(m_eyeBuffers[eye]->m_eyeTextureSize); + eyeLayer.Fov[eye] = m_hmdDesc.DefaultEyeFov[eye]; + eyeLayer.RenderPose[eye] = m_pose[eye]; + eyeLayer.SensorSampleTime = m_sensorSampleTime; } - m_timing = ovrHmd_BeginFrame(m_hmd, 0); + // append all the layers to global list + ovrLayerHeader* layerList = &eyeLayer.Header; -#if OVR_VERSION > OVR_VERSION_042 - m_pose[0] = ovrHmd_GetHmdPosePerEye(m_hmd, ovrEye_Left); - m_pose[1] = ovrHmd_GetHmdPosePerEye(m_hmd, ovrEye_Right); -#else - m_pose[0] = ovrHmd_GetEyePose(m_hmd, ovrEye_Left); - m_pose[1] = ovrHmd_GetEyePose(m_hmd, ovrEye_Right); -#endif // OVR_VERSION > OVR_VERSION_042 + ovr_SubmitFrame(m_hmd, m_frameIndex, NULL, &layerList, 1); + + // perform mirror texture blit right after the entire frame is submitted to HMD + m_mirror->blit(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); @@ -258,7 +193,7 @@ ovrError: { if (NULL != m_hmd) { - ovrHmd_RecenterPose(m_hmd); + ovr_RecenterTrackingOrigin(m_hmd); } } @@ -283,44 +218,27 @@ ovrError: eye.fov[1] = erd.Fov.DownTan; eye.fov[2] = erd.Fov.LeftTan; eye.fov[3] = erd.Fov.RightTan; -#if OVR_VERSION > OVR_VERSION_042 - eye.viewOffset[0] = erd.HmdToEyeViewOffset.x; - eye.viewOffset[1] = erd.HmdToEyeViewOffset.y; - eye.viewOffset[2] = erd.HmdToEyeViewOffset.z; -#else - eye.viewOffset[0] = erd.ViewAdjust.x; - eye.viewOffset[1] = erd.ViewAdjust.y; - eye.viewOffset[2] = erd.ViewAdjust.z; -#endif // OVR_VERSION > OVR_VERSION_042 + + ovrMatrix4f eyeProj = ovrMatrix4f_Projection(m_erd[ii].Fov, 0.01f, 1000.0f, ovrProjection_LeftHanded); + for (int jj = 0; jj < 4; ++jj) + { + for (int kk = 0; kk < 4; ++kk) + { + eye.projection[4 * jj + kk] = eyeProj.M[kk][jj]; + } + } + + 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; } } - else - { - for (int ii = 0; ii < 2; ++ii) - { - _hmd.eye[ii].rotation[0] = 0.0f; - _hmd.eye[ii].rotation[1] = 0.0f; - _hmd.eye[ii].rotation[2] = 0.0f; - _hmd.eye[ii].rotation[3] = 1.0f; - _hmd.eye[ii].translation[0] = 0.0f; - _hmd.eye[ii].translation[1] = 0.0f; - _hmd.eye[ii].translation[2] = 0.0f; - _hmd.eye[ii].fov[0] = 1.32928634f; - _hmd.eye[ii].fov[1] = 1.32928634f; - _hmd.eye[ii].fov[2] = 0 == ii ? 1.05865765f : 1.09236801f; - _hmd.eye[ii].fov[3] = 0 == ii ? 1.09236801f : 1.05865765f; - _hmd.eye[ii].viewOffset[0] = 0 == ii ? 0.0355070010f : -0.0375000015f; - _hmd.eye[ii].viewOffset[1] = 0.0f; - _hmd.eye[ii].viewOffset[2] = 0 == ii ? 0.00150949787f : -0.00150949787f; - _hmd.eye[ii].pixelsPerTanAngle[0] = 1; - _hmd.eye[ii].pixelsPerTanAngle[1] = 1; - } - } - _hmd.width = uint16_t(m_rtSize.w); - _hmd.height = uint16_t(m_rtSize.h); + _hmd.width = uint16_t(m_hmdSize.w); + _hmd.height = uint16_t(m_hmdSize.h); } } // namespace bgfx diff --git a/src/ovr.h b/src/ovr.h index b717d0d47..45bdad200 100644 --- a/src/ovr.h +++ b/src/ovr.h @@ -14,36 +14,44 @@ # define OVR_VERSION_(_a, _b, _c) (_a * 10000 + _b * 100 + _c) # define OVR_VERSION OVR_VERSION_(OVR_PRODUCT_VERSION, OVR_MAJOR_VERSION, OVR_MINOR_VERSION) -# define OVR_VERSION_042 OVR_VERSION_(0, 4, 2) -# define OVR_VERSION_043 OVR_VERSION_(0, 4, 3) -# define OVR_VERSION_044 OVR_VERSION_(0, 4, 4) -# define OVR_VERSION_050 OVR_VERSION_(0, 5, 0) -# if OVR_VERSION < OVR_VERSION_050 -# include -# else -# include -# endif // OVR_VERSION < OVR_VERSION_050 +# include # if BGFX_CONFIG_RENDERER_DIRECT3D11 -# if OVR_VERSION < OVR_VERSION_050 -# define OVR_D3D_VERSION 11 -# include -# else -# include -# endif +# include # endif // BGFX_CONFIG_RENDERER_DIRECT3D11 # if BGFX_CONFIG_RENDERER_OPENGL -# if OVR_VERSION < OVR_VERSION_050 -# include -# else -# include -# endif +# include # endif // BGFX_CONFIG_RENDERER_OPENGL +#include "Extras/OVR_Math.h" + namespace bgfx { + // single eye buffer + struct OVRBufferI + { + virtual ~OVRBufferI() {}; + virtual void onRender(const ovrSession &session) = 0; + virtual void destroy(const ovrSession &session) = 0; + + ovrSizei m_eyeTextureSize; + ovrTextureSwapChain m_swapTextureChain; + }; + + // mirrored window output + struct OVRMirrorI + { + virtual ~OVRMirrorI() {}; + virtual void init(const ovrSession &session, int windowWidth, int windowHeight) = 0; + virtual void destroy(const ovrSession &session) = 0; + virtual void blit(const ovrSession &session) = 0; + + ovrMirrorTexture m_mirrorTexture; + ovrMirrorTextureDesc m_mirrorDesc; + }; + struct OVR { OVR(); @@ -59,37 +67,31 @@ namespace bgfx return m_isenabled; } - bool isDebug() const - { - return m_debug; - } - void init(); void shutdown(); void getViewport(uint8_t _eye, Rect* _viewport); - bool postReset(void* _nwh, ovrRenderAPIConfig* _config, bool _debug = false); - void postReset(const ovrTexture& _texture); + void renderEyeStart(uint8_t _eye); + bool postReset(); void preReset(); - bool swap(HMD& _hmd); + void commitEye(uint8_t _eye); + bool swap(HMD& _hmd, bool originBottomLeft); void recenter(); void getEyePose(HMD& _hmd); - void getSize(uint32_t& _width, uint32_t& _height) const - { - _width = m_rtSize.w; - _height = m_rtSize.h; - } - ovrHmd m_hmd; - ovrFrameTiming m_timing; + ovrSession m_hmd; + ovrHmdDesc m_hmdDesc; ovrEyeRenderDesc m_erd[2]; - ovrRecti m_rect[2]; - ovrPosef m_pose[2]; - ovrTexture m_texture[2]; - ovrSizei m_rtSize; - bool m_warning; + ovrRecti m_rect[2]; + ovrPosef m_pose[2]; + ovrVector3f m_hmdToEyeOffset[2]; + ovrSizei m_hmdSize; + ovrResult m_hmdFrameReady; + OVRBufferI *m_eyeBuffers[2]; + OVRMirrorI *m_mirror; + long long m_frameIndex; + double m_sensorSampleTime; bool m_isenabled; - bool m_debug; }; } // namespace bgfx @@ -139,7 +141,15 @@ namespace bgfx _viewport->m_height = 0; } - bool swap(HMD& _hmd) + void commitEye(uint8_t /*_eye*/) + { + } + + void renderEyeStart(uint8_t /*_eye*/) + { + } + + bool swap(HMD& _hmd, bool /*originBottomLeft*/) { _hmd.flags = BGFX_HMD_NONE; getEyePose(_hmd); @@ -155,12 +165,6 @@ namespace bgfx _hmd.width = 0; _hmd.height = 0; } - - void getSize(uint32_t& _width, uint32_t& _height) const - { - _width = 0; - _height = 0; - } }; } // namespace bgfx diff --git a/src/renderer_d3d11.cpp b/src/renderer_d3d11.cpp index cd794028c..6d21d1361 100644 --- a/src/renderer_d3d11.cpp +++ b/src/renderer_d3d11.cpp @@ -601,6 +601,170 @@ namespace bgfx { namespace d3d11 static PFN_GET_DEBUG_INTERFACE1 DXGIGetDebugInterface1; #endif // USE_D3D11_DYNAMIC_LIB + +#if BGFX_CONFIG_USE_OVR + +#include + + // Oculus Rift eye buffer + struct OVRBufferDX11 : public OVRBufferI + { + OVRBufferDX11(const ovrSession& session, int eyeIdx, ID3D11Device* d3dDevice, ID3D11DeviceContext* d3dCtx) + { + m_d3dDevice = d3dDevice; + m_d3dContext = d3dCtx; + ovrHmdDesc hmdDesc = ovr_GetHmdDesc(session); + m_eyeTextureSize = ovr_GetFovTextureSize(session, (ovrEyeType)eyeIdx, hmdDesc.DefaultEyeFov[eyeIdx], 1.0f); + + ovrTextureSwapChainDesc desc = {}; + desc.Type = ovrTexture_2D; + desc.ArraySize = 1; + desc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB; + desc.Width = m_eyeTextureSize.w; + desc.Height = m_eyeTextureSize.h; + desc.MipLevels = 1; + desc.SampleCount = 1; + desc.MiscFlags = ovrTextureMisc_DX_Typeless; + desc.BindFlags = ovrTextureBind_DX_RenderTarget; + desc.StaticImage = ovrFalse; + + ovrResult result = ovr_CreateTextureSwapChainDX(session, d3dDevice, &desc, &m_swapTextureChain); + + if (!OVR_SUCCESS(result)) + { + BX_CHECK(false, "Could not create D3D11 OVR swap texture"); + } + + int textureCount = 0; + ovr_GetTextureSwapChainLength(session, m_swapTextureChain, &textureCount); + + for (int i = 0; i < textureCount; ++i) + { + ID3D11Texture2D* tex = NULL; + ovr_GetTextureSwapChainBufferDX(session, m_swapTextureChain, i, 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(d3dDevice->CreateRenderTargetView(tex, &rtvd, &rtv)); + m_eyeRtv.push_back(rtv); + tex->Release(); + } + + // setup depth buffer + D3D11_TEXTURE2D_DESC dbDesc; + dbDesc.Width = m_eyeTextureSize.w; + dbDesc.Height = m_eyeTextureSize.h; + dbDesc.MipLevels = 1; + dbDesc.ArraySize = 1; + dbDesc.Format = DXGI_FORMAT_D32_FLOAT; + dbDesc.SampleDesc.Count = 1; + dbDesc.SampleDesc.Quality = 0; + dbDesc.Usage = D3D11_USAGE_DEFAULT; + dbDesc.CPUAccessFlags = 0; + dbDesc.MiscFlags = 0; + dbDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; + ID3D11Texture2D* tex; + DX_CHECK(d3dDevice->CreateTexture2D(&dbDesc, NULL, &tex)); + DX_CHECK(d3dDevice->CreateDepthStencilView(tex, NULL, &m_depthBuffer)); + tex->Release(); + } + + void onRender(const ovrSession& session) + { + // Clear and set up rendertarget + int texIndex = 0; + ovr_GetTextureSwapChainCurrentIndex(session, m_swapTextureChain, &texIndex); + + float black[] = { 0.f, 0.f, 0.f, 0.f }; // Important that alpha=0, if want pixels to be transparent, for manual layers + m_d3dContext->OMSetRenderTargets(1, &m_eyeRtv[texIndex], m_depthBuffer); + m_d3dContext->ClearRenderTargetView(m_eyeRtv[texIndex], black); + m_d3dContext->ClearDepthStencilView(m_depthBuffer, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1, 0); + + D3D11_VIEWPORT D3Dvp; + D3Dvp.TopLeftX = 0; + D3Dvp.TopLeftY = 0; + D3Dvp.Width = (FLOAT)m_eyeTextureSize.w; + D3Dvp.Height = (FLOAT)m_eyeTextureSize.h; + D3Dvp.MinDepth = 0; + D3Dvp.MaxDepth = 1; + m_d3dContext->RSSetViewports(1, &D3Dvp); + } + + void destroy(const ovrSession& session) + { + for (size_t i = 0; i < m_eyeRtv.size(); ++i) + { + m_eyeRtv[i]->Release(); + } + + ovr_DestroyTextureSwapChain(session, m_swapTextureChain); + m_depthBuffer->Release(); + } + + ID3D11Device* m_d3dDevice; + ID3D11DeviceContext* m_d3dContext; + stl::vector m_eyeRtv; + ID3D11DepthStencilView* m_depthBuffer; + }; + + // Oculus Rift mirror + struct OVRMirrorDX11 : public OVRMirrorI + { + OVRMirrorDX11(ID3D11Device* d3dDevice, + ID3D11DeviceContext* d3dCtx, + IDXGISwapChain* d3dSc) : m_d3dDevice(d3dDevice) + , m_d3dContext(d3dCtx) + , m_d3dSwapChain(d3dSc) + { + } + + void init(const ovrSession& session, int windowWidth, int windowHeight) + { + m_mirrorDesc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB; + m_mirrorDesc.Width = windowWidth; + m_mirrorDesc.Height = windowHeight; + ovrResult result = ovr_CreateMirrorTextureDX(session, m_d3dDevice, &m_mirrorDesc, &m_mirrorTexture); + + if (!OVR_SUCCESS(result)) + { + BX_CHECK(false, "Could not create D3D11 OVR mirror texture"); + } + } + + void destroy(const ovrSession& session) + { + if (!m_mirrorTexture) + return; + + ovr_DestroyMirrorTexture(session, m_mirrorTexture); + m_mirrorTexture = NULL; + } + + void blit(const ovrSession& session) + { + if (!m_mirrorTexture) + return; + + ID3D11Texture2D* tex = NULL; + ovr_GetMirrorTextureBufferDX(session, m_mirrorTexture, IID_PPV_ARGS(&tex)); + ID3D11Texture2D* backBuffer; + DX_CHECK(m_d3dSwapChain->GetBuffer(0, IID_ID3D11Texture2D, (void**)&backBuffer)); + + m_d3dContext->CopyResource(backBuffer, tex); + DX_CHECK(m_d3dSwapChain->Present(0, 0)); + + tex->Release(); + backBuffer->Release(); + } + + ID3D11Device* m_d3dDevice; + ID3D11DeviceContext* m_d3dContext; + IDXGISwapChain* m_d3dSwapChain; + }; +#endif // BGFX_CONFIG_USE_OVR + struct RendererContextD3D11 : public RendererContextI { RendererContextD3D11() @@ -635,8 +799,6 @@ namespace bgfx { namespace d3d11 , m_fsChanges(0) , m_rtMsaa(false) , m_timerQuerySupport(false) - , m_ovrRtv(NULL) - , m_ovrDsv(NULL) { m_fbh.idx = invalidHandle; memset(&m_adapterDesc, 0, sizeof(m_adapterDesc) ); @@ -2001,10 +2163,6 @@ BX_PRAGMA_DIAGNOSTIC_POP(); uint32_t width = getBufferWidth(); uint32_t height = getBufferHeight(); - if (m_ovr.isEnabled() ) - { - m_ovr.getSize(width, height); - } FrameBufferHandle fbh = BGFX_INVALID_HANDLE; setFrameBuffer(fbh, false); @@ -2192,7 +2350,7 @@ BX_PRAGMA_DIAGNOSTIC_POP(); if (SUCCEEDED(hr) ) { - if (!m_ovr.swap(_hmd) ) + if (!m_ovr.swap(_hmd, false) ) { hr = m_swapChain->Present(syncInterval, 0); } @@ -3083,77 +3241,22 @@ BX_PRAGMA_DIAGNOSTIC_POP(); void ovrPostReset() { #if BGFX_CONFIG_USE_OVR - if (m_flags & (BGFX_RESET_HMD|BGFX_RESET_HMD_DEBUG) ) + if (m_resolution.m_flags & (BGFX_RESET_HMD|BGFX_RESET_HMD_DEBUG) ) { - ovrD3D11Config config; - config.D3D11.Header.API = ovrRenderAPI_D3D11; -# if OVR_VERSION > OVR_VERSION_043 - config.D3D11.Header.BackBufferSize.w = m_scd.BufferDesc.Width; - config.D3D11.Header.BackBufferSize.h = m_scd.BufferDesc.Height; - config.D3D11.pBackBufferUAV = NULL; -# else - config.D3D11.Header.RTSize.w = m_scd.BufferDesc.Width; - config.D3D11.Header.RTSize.h = m_scd.BufferDesc.Height; -# endif // OVR_VERSION > OVR_VERSION_042 - config.D3D11.Header.Multisample = 0; - config.D3D11.pDevice = m_device; - config.D3D11.pDeviceContext = m_deviceCtx; - config.D3D11.pBackBufferRT = m_backBufferColor; - config.D3D11.pSwapChain = m_swapChain; - if (m_ovr.postReset(g_platformData.nwh, &config.Config, !!(m_flags & BGFX_RESET_HMD_DEBUG) ) ) + if (m_ovr.postReset()) { - uint32_t size = sizeof(uint32_t) + sizeof(TextureCreate); - const Memory* mem = alloc(size); + for (int eyeIdx = 0; eyeIdx < ovrEye_Count; eyeIdx++) + { + // eye buffers need to be initialized only once during application lifetime + if (!m_ovr.m_eyeBuffers[eyeIdx]) + { + m_ovr.m_eyeBuffers[eyeIdx] = BX_NEW(g_allocator, OVRBufferDX11(m_ovr.m_hmd, eyeIdx, m_device, m_deviceCtx)); + } + } - bx::StaticMemoryBlockWriter writer(mem->data, mem->size); - uint32_t magic = BGFX_CHUNK_MAGIC_TEX; - bx::write(&writer, magic); - - TextureCreate tc; - tc.m_flags = BGFX_TEXTURE_RT|( ((m_flags & BGFX_RESET_MSAA_MASK) >> BGFX_RESET_MSAA_SHIFT) << BGFX_TEXTURE_RT_MSAA_SHIFT); - tc.m_width = m_ovr.m_rtSize.w; - tc.m_height = m_ovr.m_rtSize.h; - tc.m_sides = 0; - tc.m_depth = 0; - tc.m_numMips = 1; - tc.m_format = uint8_t(bgfx::TextureFormat::BGRA8); - tc.m_cubeMap = false; - tc.m_mem = NULL; - bx::write(&writer, tc); - m_ovrRT.create(mem, tc.m_flags, 0); - - release(mem); - - DX_CHECK(m_device->CreateRenderTargetView(m_ovrRT.m_ptr, NULL, &m_ovrRtv) ); - - D3D11_TEXTURE2D_DESC dsd; - dsd.Width = m_ovr.m_rtSize.w; - dsd.Height = m_ovr.m_rtSize.h; - dsd.MipLevels = 1; - dsd.ArraySize = 1; - dsd.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; - dsd.SampleDesc = m_scd.SampleDesc; - dsd.Usage = D3D11_USAGE_DEFAULT; - dsd.BindFlags = D3D11_BIND_DEPTH_STENCIL; - dsd.CPUAccessFlags = 0; - dsd.MiscFlags = 0; - - ID3D11Texture2D* depthStencil; - DX_CHECK(m_device->CreateTexture2D(&dsd, NULL, &depthStencil) ); - DX_CHECK(m_device->CreateDepthStencilView(depthStencil, NULL, &m_ovrDsv) ); - DX_RELEASE(depthStencil, 0); - - ovrD3D11Texture texture; - texture.D3D11.Header.API = ovrRenderAPI_D3D11; - texture.D3D11.Header.TextureSize = m_ovr.m_rtSize; - texture.D3D11.pTexture = m_ovrRT.m_texture2d; - texture.D3D11.pSRView = m_ovrRT.m_srv; - m_ovr.postReset(texture.Texture); - - bx::xchg(m_ovrRtv, m_backBufferColor); - - BX_CHECK(NULL == m_backBufferDepthStencil, ""); - bx::xchg(m_ovrDsv, m_backBufferDepthStencil); + // recreate mirror texture + m_ovr.m_mirror = BX_NEW(g_allocator, OVRMirrorDX11(m_device, m_deviceCtx, m_swapChain)); + m_ovr.m_mirror->init(m_ovr.m_hmd, m_resolution.m_width, m_resolution.m_height); } } #endif // BGFX_CONFIG_USE_OVR @@ -3163,16 +3266,6 @@ BX_PRAGMA_DIAGNOSTIC_POP(); { #if BGFX_CONFIG_USE_OVR m_ovr.preReset(); - if (NULL != m_ovrRtv) - { - bx::xchg(m_ovrRtv, m_backBufferColor); - bx::xchg(m_ovrDsv, m_backBufferDepthStencil); - BX_CHECK(NULL == m_backBufferDepthStencil, ""); - - DX_RELEASE(m_ovrRtv, 0); - DX_RELEASE(m_ovrDsv, 0); - m_ovrRT.destroy(); - } #endif // BGFX_CONFIG_USE_OVR } @@ -3564,9 +3657,6 @@ BX_PRAGMA_DIAGNOSTIC_POP(); bool m_timerQuerySupport; OVR m_ovr; - TextureD3D11 m_ovrRT; - ID3D11RenderTargetView* m_ovrRtv; - ID3D11DepthStencilView* m_ovrDsv; }; static RendererContextD3D11* s_renderD3D11; @@ -4864,7 +4954,7 @@ BX_PRAGMA_DIAGNOSTIC_POP(); _render->m_hmdInitialized = m_ovr.isInitialized(); - const bool hmdEnabled = m_ovr.isEnabled() || m_ovr.isDebug(); + const bool hmdEnabled = m_ovr.isEnabled(); ViewState viewState(_render, hmdEnabled); bool wireframe = !!(_render->m_debug&BGFX_DEBUG_WIREFRAME); @@ -4987,6 +5077,9 @@ BX_PRAGMA_DIAGNOSTIC_POP(); if (m_ovr.isEnabled() ) { m_ovr.getViewport(eye, &viewState.m_rect); + // commit previous eye to HMD and start rendering new frame + m_ovr.commitEye(eye); + m_ovr.renderEyeStart(eye); } else { diff --git a/src/renderer_gl.cpp b/src/renderer_gl.cpp index 72bdbfa5a..e78d52b21 100644 --- a/src/renderer_gl.cpp +++ b/src/renderer_gl.cpp @@ -1274,6 +1274,144 @@ namespace bgfx { namespace gl BX_UNUSED(supported); } +#if BGFX_CONFIG_USE_OVR + + // Oculus Rift eye buffer + struct OVRBufferGL : public OVRBufferI + { + OVRBufferGL(const ovrSession& session, int eyeIdx) + { + ovrHmdDesc hmdDesc = ovr_GetHmdDesc(session); + m_eyeTextureSize = ovr_GetFovTextureSize(session, (ovrEyeType)eyeIdx, hmdDesc.DefaultEyeFov[eyeIdx], 1.0f); + + ovrTextureSwapChainDesc desc = {}; + desc.Type = ovrTexture_2D; + desc.ArraySize = 1; + desc.Width = m_eyeTextureSize.w; + desc.Height = m_eyeTextureSize.h; + desc.MipLevels = 1; + desc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB; + desc.SampleCount = 1; + desc.StaticImage = ovrFalse; + + ovr_CreateTextureSwapChainGL(session, &desc, &m_swapTextureChain); + + int textureCount = 0; + ovr_GetTextureSwapChainLength(session, m_swapTextureChain, &textureCount); + + for (int j = 0; j < textureCount; ++j) + { + GLuint chainTexId; + ovr_GetTextureSwapChainBufferGL(session, m_swapTextureChain, 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)); + } + + GL_CHECK(glGenFramebuffers(1, &m_eyeFbo)); + + // create depth buffer + GL_CHECK(glGenTextures(1, &m_depthBuffer)); + GL_CHECK(glBindTexture(GL_TEXTURE_2D, m_depthBuffer)); + 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(glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, m_eyeTextureSize.w, m_eyeTextureSize.h, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL)); + } + + void onRender(const ovrSession& session) + { + // set the current eye texture in swap chain + int curIndex; + ovr_GetTextureSwapChainCurrentIndex(session, m_swapTextureChain, &curIndex); + ovr_GetTextureSwapChainBufferGL(session, m_swapTextureChain, curIndex, &m_eyeTexId); + + GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_eyeFbo)); + GL_CHECK(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_eyeTexId, 0)); + GL_CHECK(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_depthBuffer, 0)); + + GL_CHECK(glViewport(0, 0, m_eyeTextureSize.w, m_eyeTextureSize.h)); + GL_CHECK(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); + } + + void destroy(const ovrSession& session) + { + GL_CHECK(glDeleteFramebuffers(1, &m_eyeFbo)); + GL_CHECK(glDeleteTextures(1, &m_depthBuffer)); + + ovr_DestroyTextureSwapChain(session, m_swapTextureChain); + } + + GLuint m_eyeFbo; + GLuint m_eyeTexId; + GLuint m_depthBuffer; + }; + + // Oculus Rift mirror + struct OVRMirrorGL : public OVRMirrorI + { + void init(const ovrSession& session, int windowWidth, int windowHeight) + { + memset(&m_mirrorDesc, 0, sizeof(m_mirrorDesc)); + m_mirrorDesc.Width = windowWidth; + m_mirrorDesc.Height = windowHeight; + m_mirrorDesc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB; + + ovr_CreateMirrorTextureGL(session, &m_mirrorDesc, &m_mirrorTexture); + + // 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) + { + GL_CHECK(glDeleteFramebuffers(1, &m_mirrorFBO)); + BX_CHECK(false, "Could not initialize VR buffers!"); + } + } + + void destroy(const ovrSession& session) + { + if (!m_mirrorTexture) + return; + + GL_CHECK(glDeleteFramebuffers(1, &m_mirrorFBO)); + ovr_DestroyMirrorTexture(session, m_mirrorTexture); + m_mirrorTexture = NULL; + } + + void blit(const ovrSession& /*session*/) + { + if (!m_mirrorTexture) + return; + + // Blit mirror texture to back buffer + GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, m_mirrorFBO)); + GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0)); + GLint w = m_mirrorDesc.Width; + GLint h = m_mirrorDesc.Height; + GL_CHECK(glBlitFramebuffer(0, h, w, 0, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST)); + GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, 0)); + } + + GLuint m_mirrorFBO; + }; +#endif // BGFX_CONFIG_USE_OVR + struct RendererContextGL : public RendererContextI { RendererContextGL() @@ -1304,7 +1442,6 @@ namespace bgfx { namespace gl , m_hash( (BX_PLATFORM_WINDOWS<<1) | BX_ARCH_64BIT) , m_backBufferFbo(0) , m_msaaBackBufferFbo(0) - , m_ovrFbo(0) { memset(m_msaaBackBufferRbos, 0, sizeof(m_msaaBackBufferRbos) ); } @@ -2107,10 +2244,9 @@ namespace bgfx { namespace gl m_glctx.swap(m_frameBuffers[m_windows[ii].idx].m_swapChain); } - if (!m_ovr.swap(_hmd) ) - { - m_glctx.swap(); - } + m_ovr.swap(_hmd, true); + // need to swap GL render context even if OVR is enabled to get the mirror texture in the output + m_glctx.swap(); } } @@ -2397,10 +2533,6 @@ namespace bgfx { namespace gl uint32_t width = m_resolution.m_width; uint32_t height = m_resolution.m_height; - if (m_ovr.isEnabled() ) - { - m_ovr.getSize(width, height); - } GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_backBufferFbo) ); GL_CHECK(glViewport(0, 0, width, height) ); @@ -2857,63 +2989,22 @@ namespace bgfx { namespace gl void ovrPostReset() { #if BGFX_CONFIG_USE_OVR - if (m_resolution.m_flags & (BGFX_RESET_HMD|BGFX_RESET_HMD_DEBUG) ) + if (m_resolution.m_flags & (BGFX_RESET_HMD | BGFX_RESET_HMD_DEBUG)) { - ovrGLConfig config; - config.OGL.Header.API = ovrRenderAPI_OpenGL; -# if OVR_VERSION > OVR_VERSION_043 - config.OGL.Header.BackBufferSize.w = m_resolution.m_width; - config.OGL.Header.BackBufferSize.h = m_resolution.m_height; -# else - config.OGL.Header.RTSize.w = m_resolution.m_width; - config.OGL.Header.RTSize.h = m_resolution.m_height; -# endif // OVR_VERSION > OVR_VERSION_043 - config.OGL.Header.Multisample = 0; - config.OGL.Window = (HWND)g_platformData.nwh; - config.OGL.DC = GetDC(config.OGL.Window); - if (m_ovr.postReset(g_platformData.nwh, &config.Config, !!(m_resolution.m_flags & BGFX_RESET_HMD_DEBUG) ) ) + if (m_ovr.postReset()) { - uint32_t size = sizeof(uint32_t) + sizeof(TextureCreate); - const Memory* mem = alloc(size); + for (int eyeIdx = 0; eyeIdx < ovrEye_Count; eyeIdx++) + { + // eye buffers need to be initialized only once during application lifetime + if (!m_ovr.m_eyeBuffers[eyeIdx]) + { + m_ovr.m_eyeBuffers[eyeIdx] = BX_NEW(g_allocator, OVRBufferGL(m_ovr.m_hmd, eyeIdx)); + } + } - bx::StaticMemoryBlockWriter writer(mem->data, mem->size); - uint32_t magic = BGFX_CHUNK_MAGIC_TEX; - bx::write(&writer, magic); - - TextureCreate tc; - tc.m_flags = BGFX_TEXTURE_RT|( ((m_resolution.m_flags & BGFX_RESET_MSAA_MASK) >> BGFX_RESET_MSAA_SHIFT) << BGFX_TEXTURE_RT_MSAA_SHIFT);; - tc.m_width = m_ovr.m_rtSize.w; - tc.m_height = m_ovr.m_rtSize.h; - tc.m_sides = 0; - tc.m_depth = 0; - tc.m_numMips = 1; - tc.m_format = uint8_t(bgfx::TextureFormat::BGRA8); - tc.m_cubeMap = false; - tc.m_mem = NULL; - bx::write(&writer, tc); - - m_ovrRT.create(mem, tc.m_flags, 0); - release(mem); - - m_ovrFbo = m_msaaBackBufferFbo; - - GL_CHECK(glGenFramebuffers(1, &m_msaaBackBufferFbo) ); - GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_msaaBackBufferFbo) ); - - GL_CHECK(glFramebufferTexture2D(GL_FRAMEBUFFER - , GL_COLOR_ATTACHMENT0 - , GL_TEXTURE_2D - , m_ovrRT.m_id - , 0 - ) ); - - GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_ovrFbo) ); - - ovrGLTexture texture; - texture.OGL.Header.API = ovrRenderAPI_OpenGL; - texture.OGL.Header.TextureSize = m_ovr.m_rtSize; - texture.OGL.TexId = m_ovrRT.m_id; - m_ovr.postReset(texture.Texture); + // recreate mirror texture + m_ovr.m_mirror = BX_NEW(g_allocator, OVRMirrorGL); + m_ovr.m_mirror->init(m_ovr.m_hmd, m_resolution.m_width, m_resolution.m_height); } } #endif // BGFX_CONFIG_USE_OVR @@ -2923,14 +3014,6 @@ namespace bgfx { namespace gl { #if BGFX_CONFIG_USE_OVR m_ovr.preReset(); - if (m_ovr.isEnabled() ) - { - GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, 0) ); - GL_CHECK(glDeleteFramebuffers(1, &m_msaaBackBufferFbo) ); - m_msaaBackBufferFbo = m_ovrFbo; - m_ovrFbo = 0; - m_ovrRT.destroy(); - } #endif // BGFX_CONFIG_USE_OVR } @@ -3354,8 +3437,6 @@ namespace bgfx { namespace gl const char* m_glslVersion; OVR m_ovr; - TextureGL m_ovrRT; - GLint m_ovrFbo; }; RendererContextGL* s_renderGL; @@ -3647,7 +3728,7 @@ namespace bgfx { namespace gl } m_numPredefined = 0; - m_numSamplers = 0; + m_numSamplers = 0; BX_TRACE("Uniforms (%d):", activeUniforms); for (int32_t ii = 0; ii < activeUniforms; ++ii) @@ -5439,7 +5520,7 @@ namespace bgfx { namespace gl _render->m_hmdInitialized = m_ovr.isInitialized(); - const bool hmdEnabled = m_ovr.isEnabled() || m_ovr.isDebug(); + const bool hmdEnabled = m_ovr.isEnabled(); ViewState viewState(_render, hmdEnabled); uint16_t programIdx = invalidHandle; @@ -5491,12 +5572,13 @@ namespace bgfx { namespace gl m_occlusionQuery.resolve(_render); } + uint8_t eye = 0; + if (0 == (_render->m_debug&BGFX_DEBUG_IFH) ) { GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_msaaBackBufferFbo) ); bool viewRestart = false; - uint8_t eye = 0; uint8_t restartState = 0; viewState.m_rect = _render->m_rect[0]; @@ -5578,6 +5660,9 @@ namespace bgfx { namespace gl if (m_ovr.isEnabled() ) { m_ovr.getViewport(eye, &viewState.m_rect); + // commit previous eye to HMD and start rendering new frame + m_ovr.commitEye(eye); + m_ovr.renderEyeStart(eye); } else { @@ -5679,7 +5764,7 @@ namespace bgfx { namespace gl const RenderCompute& compute = renderItem.compute; ProgramGL& program = m_program[key.m_program]; - GL_CHECK(glUseProgram(program.m_id) ); + GL_CHECK(glUseProgram(program.m_id) ); GLbitfield barrier = 0; for (uint32_t ii = 0; ii < BGFX_MAX_COMPUTE_BINDINGS; ++ii)