From f6cf4df3d3783d890348551f744ff8e8752d4910 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Branimir=20Karad=C5=BEi=C4=87?= Date: Tue, 28 Oct 2014 22:08:55 -0700 Subject: [PATCH] Added OculusVR support. --- examples/01-cubes/cubes.cpp | 26 ++- examples/common/entry/entry.cpp | 7 +- include/bgfx.c99.h | 38 +++- include/bgfx.h | 23 ++- include/bgfxdefines.h | 7 + src/bgfx.cpp | 27 ++- src/bgfx_p.h | 48 ++++- src/config.h | 5 + src/glcontext_wgl.cpp | 4 + src/ovr.cpp | 213 +++++++++++++++++++++ src/ovr.h | 131 +++++++++++++ src/renderer_d3d11.cpp | 323 +++++++++++++++++++++++++++----- src/renderer_d3d11.h | 10 +- src/renderer_d3d9.cpp | 6 +- src/renderer_gl.cpp | 300 ++++++++++++++++++++++++----- src/renderer_gl.h | 3 +- 16 files changed, 1053 insertions(+), 118 deletions(-) create mode 100644 src/ovr.cpp create mode 100644 src/ovr.h diff --git a/examples/01-cubes/cubes.cpp b/examples/01-cubes/cubes.cpp index 1dd90a2bd..54b297c27 100644 --- a/examples/01-cubes/cubes.cpp +++ b/examples/01-cubes/cubes.cpp @@ -103,15 +103,31 @@ int _main_(int /*_argc*/, char** /*_argv*/) while (!entry::processEvents(width, height, debug, reset) ) { float view[16]; - float proj[16]; bx::mtxLookAt(view, eye, at); - bx::mtxProj(proj, 60.0f, float(width)/float(height), 0.1f, 100.0f); // Set view and projection matrix for view 0. - bgfx::setViewTransform(0, view, proj); + const bgfx::HMD* hmd = bgfx::getHMD(); + if (NULL != hmd) + { + float proj[16]; + bx::mtxProj(proj, hmd->eye[0].fov, 0.1f, 100.0f); + bgfx::setViewTransform(0, view, proj); - // Set view 0 default viewport. - bgfx::setViewRect(0, 0, 0, width, height); + // Set view 0 default viewport. + // + // Use HMD's width/height since HMD's internal frame buffer size + // might be much larger than window size. + bgfx::setViewRect(0, 0, 0, hmd->width, hmd->height); + } + else + { + float proj[16]; + bx::mtxProj(proj, 60.0f, float(width)/float(height), 0.1f, 100.0f); + bgfx::setViewTransform(0, view, proj); + + // Set view 0 default viewport. + bgfx::setViewRect(0, 0, 0, width, height); + } // This dummy draw call is here to make sure that view 0 is cleared // if no other draw calls are submitted to view 0. diff --git a/examples/common/entry/entry.cpp b/examples/common/entry/entry.cpp index 3162c5e75..4ee37e37b 100644 --- a/examples/common/entry/entry.cpp +++ b/examples/common/entry/entry.cpp @@ -65,8 +65,10 @@ namespace entry { if (_argc > 1) { - if (setOrToggle(s_reset, "vsync", BGFX_RESET_VSYNC, 1, _argc, _argv) - || setOrToggle(s_reset, "msaa", BGFX_RESET_MSAA_X16, 1, _argc, _argv) ) + if (setOrToggle(s_reset, "vsync", BGFX_RESET_VSYNC, 1, _argc, _argv) + || setOrToggle(s_reset, "hmd", BGFX_RESET_HMD, 1, _argc, _argv) + || setOrToggle(s_reset, "hmddbg", BGFX_RESET_HMD_DEBUG, 1, _argc, _argv) + || setOrToggle(s_reset, "msaa", BGFX_RESET_MSAA_X16, 1, _argc, _argv) ) { return 0; } @@ -113,6 +115,7 @@ namespace entry { entry::Key::F1, entry::Modifier::None, 1, cmd, "graphics stats" }, { entry::Key::F1, entry::Modifier::LeftShift, 1, cmd, "graphics stats 0\ngraphics text 0" }, { entry::Key::F3, entry::Modifier::None, 1, cmd, "graphics wireframe" }, + { entry::Key::F4, entry::Modifier::None, 1, cmd, "graphics hmd" }, { entry::Key::F7, entry::Modifier::None, 1, cmd, "graphics vsync" }, { entry::Key::F8, entry::Modifier::None, 1, cmd, "graphics msaa" }, { entry::Key::Print, entry::Modifier::None, 1, cmd, "graphics screenshot" }, diff --git a/include/bgfx.c99.h b/include/bgfx.c99.h index a3b0aab64..804b957f0 100644 --- a/include/bgfx.c99.h +++ b/include/bgfx.c99.h @@ -176,11 +176,32 @@ typedef struct bgfx_memory */ typedef struct bgfx_transform { - float* data; //< Pointer to first matrix. - uint16_t num; //< Number of matrices. + float* data; + uint16_t num; } bgfx_transform_t; +/** + */ +typedef struct bgfx_hmd +{ + /** + * Eye + */ + struct Eye + { + float rotation[4]; + float translation[3]; + float fov[4]; + float adjust[3]; + float pixelsPerTanAngle[2]; + }; + + Eye eye[2]; + uint16_t width; + uint16_t height; +} bgfx_hmd_t; + /** * Vertex declaration. */ @@ -566,7 +587,12 @@ BGFX_C_API bgfx_renderer_type_t bgfx_get_renderer_type(); * NOTE: * Library must be initialized. */ -BGFX_C_API bgfx_caps_t* bgfx_get_caps(); +BGFX_C_API const bgfx_caps_t* bgfx_get_caps(); + +/** + * Returns HMD info. + */ +BGFX_C_API const bgfx_hmd_t* bgfx_get_hmd(); /** * Allocate buffer to pass to bgfx calls. Data will be freed inside bgfx. @@ -1125,6 +1151,12 @@ BGFX_C_API void bgfx_set_view_frame_buffer(uint8_t _id, bgfx_frame_buffer_handle */ BGFX_C_API void bgfx_set_view_transform(uint8_t _id, const void* _view, const void* _proj); +/** + * Set view view and projection matrices, all draw primitives in this + * view will use these matrices. + */ +BGFX_C_API void bgfx_set_view_transform_stereo(uint8_t _id, const void* _view, const void* _projL, uint8_t _flags, const void* _projR); + /** * Sets debug marker. */ diff --git a/include/bgfx.h b/include/bgfx.h index 92a879879..d9516f704 100644 --- a/include/bgfx.h +++ b/include/bgfx.h @@ -369,6 +369,24 @@ namespace bgfx uint16_t num; //!< Number of matrices. }; + /// HMD info. + struct HMD + { + /// Eye + struct Eye + { + float rotation[4]; //!< Eye rotation represented as quaternion. + float translation[3]; //!< Eye translation. + float fov[4]; //!< Field of view (up, down, left, right). + float adjust[3]; //!< Eye view matrix translation adjustment. + float pixelsPerTanAngle[2]; //!< + }; + + Eye eye[2]; + uint16_t width; //!< Framebuffer width. + uint16_t height; //!< Framebuffer width. + }; + /// Vertex declaration. struct VertexDecl { @@ -548,6 +566,9 @@ namespace bgfx /// const Caps* getCaps(); + /// Returns HMD info. + const HMD* getHMD(); + /// Allocate buffer to pass to bgfx calls. Data will be freed inside bgfx. const Memory* alloc(uint32_t _size); @@ -1038,7 +1059,7 @@ namespace bgfx /// Set view view and projection matrices, all draw primitives in this /// view will use these matrices. - void setViewTransform(uint8_t _id, const void* _view, const void* _proj); + void setViewTransform(uint8_t _id, const void* _view, const void* _projL, uint8_t _flags = BGFX_VIEW_STEREO, const void* _projR = NULL); /// Sets debug marker. void setMarker(const char* _marker); diff --git a/include/bgfxdefines.h b/include/bgfxdefines.h index 1159a9758..99ebe31b6 100644 --- a/include/bgfxdefines.h +++ b/include/bgfxdefines.h @@ -264,6 +264,8 @@ #define BGFX_RESET_MSAA_MASK UINT32_C(0x00000070) #define BGFX_RESET_VSYNC UINT32_C(0x00000080) #define BGFX_RESET_CAPTURE UINT32_C(0x00000100) +#define BGFX_RESET_HMD UINT32_C(0x00000200) +#define BGFX_RESET_HMD_DEBUG UINT32_C(0x00000400) /// #define BGFX_CAPS_TEXTURE_COMPARE_LEQUAL UINT64_C(0x0000000000000001) @@ -277,5 +279,10 @@ #define BGFX_CAPS_COMPUTE UINT64_C(0x0000000000000100) #define BGFX_CAPS_FRAGMENT_ORDERING UINT64_C(0x0000000000000200) #define BGFX_CAPS_SWAP_CHAIN UINT64_C(0x0000000000000400) +#define BGFX_CAPS_HMD UINT64_C(0x0000000000000800) + +/// +#define BGFX_VIEW_NONE UINT8_C(0x00) +#define BGFX_VIEW_STEREO UINT8_C(0x01) #endif // BGFX_DEFINES_H_HEADER_GUARD diff --git a/src/bgfx.cpp b/src/bgfx.cpp index 1f93ae963..ebeb1eed8 100644 --- a/src/bgfx.cpp +++ b/src/bgfx.cpp @@ -848,6 +848,9 @@ namespace bgfx CAPS_FLAGS(BGFX_CAPS_FRAGMENT_DEPTH), CAPS_FLAGS(BGFX_CAPS_BLEND_INDEPENDENT), CAPS_FLAGS(BGFX_CAPS_COMPUTE), + CAPS_FLAGS(BGFX_CAPS_FRAGMENT_ORDERING), + CAPS_FLAGS(BGFX_CAPS_SWAP_CHAIN), + CAPS_FLAGS(BGFX_CAPS_HMD), #undef CAPS_FLAGS }; @@ -1130,6 +1133,7 @@ namespace bgfx memcpy(m_submit->m_scissor, m_scissor, sizeof(m_scissor) ); memcpy(m_submit->m_view, m_view, sizeof(m_view) ); memcpy(m_submit->m_proj, m_proj, sizeof(m_proj) ); + memcpy(m_submit->m_viewFlags, m_viewFlags, sizeof(m_viewFlags) ); if (m_clearColorDirty > 0) { --m_clearColorDirty; @@ -1961,6 +1965,11 @@ again: return &g_caps; } + const HMD* getHMD() + { + return s_ctx->getHMD(); + } + RendererType::Enum getRendererType() { return g_caps.rendererType; @@ -2557,10 +2566,10 @@ again: s_ctx->setViewFrameBuffer(_id, _handle); } - void setViewTransform(uint8_t _id, const void* _view, const void* _proj) + void setViewTransform(uint8_t _id, const void* _view, const void* _projL, uint8_t _flags, const void* _projR) { BGFX_CHECK_MAIN_THREAD(); - s_ctx->setViewTransform(_id, _view, _proj); + s_ctx->setViewTransform(_id, _view, _projL, _flags, _projR); } void setMarker(const char* _marker) @@ -2853,9 +2862,14 @@ BGFX_C_API bgfx_renderer_type_t bgfx_get_renderer_type() return bgfx_renderer_type_t(bgfx::getRendererType() ); } -BGFX_C_API bgfx_caps_t* bgfx_get_caps() +BGFX_C_API const bgfx_caps_t* bgfx_get_caps() { - return (bgfx_caps_t*)bgfx::getCaps(); + return (const bgfx_caps_t*)bgfx::getCaps(); +} + +BGFX_C_API const bgfx_hmd_t* bgfx_get_hmd() +{ + return (const bgfx_hmd_t*)bgfx::getHMD(); } BGFX_C_API const bgfx_memory_t* bgfx_alloc(uint32_t _size) @@ -3195,6 +3209,11 @@ BGFX_C_API void bgfx_set_view_transform(uint8_t _id, const void* _view, const vo bgfx::setViewTransform(_id, _view, _proj); } +BGFX_C_API void bgfx_set_view_transform_stereo(uint8_t _id, const void* _view, const void* _projL, uint8_t _flags, const void* _projR) +{ + bgfx::setViewTransform(_id, _view, _projL, _flags, _projR); +} + BGFX_C_API void bgfx_set_marker(const char* _marker) { bgfx::setMarker(_marker); diff --git a/src/bgfx_p.h b/src/bgfx_p.h index 133bc29e1..6c5cfc43c 100644 --- a/src/bgfx_p.h +++ b/src/bgfx_p.h @@ -72,6 +72,7 @@ namespace bgfx #include #include +#include #include #include #include @@ -1149,7 +1150,13 @@ namespace bgfx Frame() : m_waitSubmit(0) , m_waitRender(0) + , m_hmdEnabled(false) { + SortKey term; + term.reset(); + term.m_program = invalidHandle; + m_sortKeys[BGFX_CONFIG_MAX_DRAW_CALLS] = term.encodeDraw(); + m_sortValues[BGFX_CONFIG_MAX_DRAW_CALLS] = BGFX_CONFIG_MAX_DRAW_CALLS; } ~Frame() @@ -1475,11 +1482,12 @@ namespace bgfx Rect m_rect[BGFX_CONFIG_MAX_VIEWS]; Rect m_scissor[BGFX_CONFIG_MAX_VIEWS]; Matrix4 m_view[BGFX_CONFIG_MAX_VIEWS]; - Matrix4 m_proj[BGFX_CONFIG_MAX_VIEWS]; + Matrix4 m_proj[2][BGFX_CONFIG_MAX_VIEWS]; + uint8_t m_viewFlags[BGFX_CONFIG_MAX_VIEWS]; - uint64_t m_sortKeys[BGFX_CONFIG_MAX_DRAW_CALLS]; - uint16_t m_sortValues[BGFX_CONFIG_MAX_DRAW_CALLS]; - RenderItem m_renderItem[BGFX_CONFIG_MAX_DRAW_CALLS]; + uint64_t m_sortKeys[BGFX_CONFIG_MAX_DRAW_CALLS+1]; + uint16_t m_sortValues[BGFX_CONFIG_MAX_DRAW_CALLS+1]; + RenderItem m_renderItem[BGFX_CONFIG_MAX_DRAW_CALLS+1]; RenderDraw m_draw; RenderCompute m_compute; uint64_t m_flags; @@ -1525,6 +1533,8 @@ namespace bgfx FrameBufferHandle m_freeFrameBufferHandle[BGFX_CONFIG_MAX_FRAME_BUFFERS]; UniformHandle m_freeUniformHandle[BGFX_CONFIG_MAX_UNIFORMS]; TextVideoMem* m_textVideoMem; + HMD m_hmd; + bool m_hmdEnabled; int64_t m_waitSubmit; int64_t m_waitRender; @@ -1825,6 +1835,16 @@ namespace bgfx m_submit->m_textVideoMem->printfVargs(_x, _y, _attr, _format, _argList); } + BGFX_API_FUNC(const HMD* getHMD() ) + { + if (m_submit->m_hmdEnabled) + { + return &m_submit->m_hmd; + } + + return NULL; + } + BGFX_API_FUNC(IndexBufferHandle createIndexBuffer(const Memory* _mem) ) { IndexBufferHandle handle = { m_indexBufferHandle.alloc() }; @@ -2733,8 +2753,10 @@ namespace bgfx m_fb[_id] = _handle; } - BGFX_API_FUNC(void setViewTransform(uint8_t _id, const void* _view, const void* _proj) ) + BGFX_API_FUNC(void setViewTransform(uint8_t _id, const void* _view, const void* _proj, uint8_t _flags, const void* _proj1) ) { + m_viewFlags[_id] = _flags; + if (NULL != _view) { memcpy(m_view[_id].un.val, _view, sizeof(Matrix4) ); @@ -2746,11 +2768,20 @@ namespace bgfx if (NULL != _proj) { - memcpy(m_proj[_id].un.val, _proj, sizeof(Matrix4) ); + memcpy(m_proj[0][_id].un.val, _proj, sizeof(Matrix4) ); } else { - m_proj[_id].setIdentity(); + m_proj[0][_id].setIdentity(); + } + + if (NULL != _proj1) + { + memcpy(m_proj[1][_id].un.val, _proj1, sizeof(Matrix4) ); + } + else + { + memcpy(m_proj[1][_id].un.val, m_proj[0][_id].un.val, sizeof(Matrix4) ); } } @@ -3041,7 +3072,8 @@ namespace bgfx Rect m_rect[BGFX_CONFIG_MAX_VIEWS]; Rect m_scissor[BGFX_CONFIG_MAX_VIEWS]; Matrix4 m_view[BGFX_CONFIG_MAX_VIEWS]; - Matrix4 m_proj[BGFX_CONFIG_MAX_VIEWS]; + Matrix4 m_proj[2][BGFX_CONFIG_MAX_VIEWS]; + uint8_t m_viewFlags[BGFX_CONFIG_MAX_VIEWS]; uint16_t m_seq[BGFX_CONFIG_MAX_VIEWS]; uint16_t m_seqMask[BGFX_CONFIG_MAX_VIEWS]; diff --git a/src/config.h b/src/config.h index 0748fa902..a1352b415 100644 --- a/src/config.h +++ b/src/config.h @@ -117,6 +117,11 @@ # define BGFX_CONFIG_USE_TINYSTL 1 #endif // BGFX_CONFIG_USE_TINYSTL +/// Enable OculusVR integration. +#ifndef BGFX_CONFIG_USE_OVR +# define BGFX_CONFIG_USE_OVR 0 +#endif // BGFX_CONFIG_USE_OVR + /// Enable nVidia PerfHUD integration. #ifndef BGFX_CONFIG_DEBUG_PERFHUD # define BGFX_CONFIG_DEBUG_PERFHUD 0 diff --git a/src/glcontext_wgl.cpp b/src/glcontext_wgl.cpp index 7f015b2d3..88d87ac99 100644 --- a/src/glcontext_wgl.cpp +++ b/src/glcontext_wgl.cpp @@ -42,6 +42,8 @@ namespace bgfx void makeCurrent() { wglMakeCurrent(m_hdc, m_context); + GLenum err = glGetError(); + BX_WARN(0 == err, "wglMakeCurrent failed with GL error: 0x%04x.", err); } void swapBuffers() @@ -319,6 +321,8 @@ namespace bgfx if (NULL == _swapChain) { wglMakeCurrent(m_hdc, m_context); + GLenum err = glGetError(); + BX_WARN(0 == err, "wglMakeCurrent failed with GL error: 0x%04x.", err); } else { diff --git a/src/ovr.cpp b/src/ovr.cpp new file mode 100644 index 000000000..4181e3328 --- /dev/null +++ b/src/ovr.cpp @@ -0,0 +1,213 @@ +/* +* Copyright 2011-2014 Branimir Karadzic. All rights reserved. +* License: http://www.opensource.org/licenses/BSD-2-Clause +*/ + +#include "ovr.h" + +#if BGFX_CONFIG_USE_OVR + +namespace bgfx +{ + OVR::OVR() + : m_hmd(NULL) + , m_initialized(false) + { + } + + OVR::~OVR() + { + BX_CHECK(!m_initialized, "OVR not shutdown properly."); + } + + void OVR::init() + { + m_initialized = !!ovr_Initialize(); + } + + void OVR::shutdown() + { + BX_CHECK(NULL == m_hmd, "HMD not destroyed."); + ovr_Shutdown(); + m_initialized = false; + } + + bool OVR::postReset(void* _nwh, ovrRenderAPIConfig* _config, bool _debug) + { + if (!m_initialized) + { + return false; + } + + if (!_debug) + { + m_hmd = ovrHmd_Create(0); + } + + if (NULL == m_hmd) + { + m_hmd = ovrHmd_CreateDebug(ovrHmd_DK2); + BX_WARN(NULL != m_hmd, "Unable to initialize OVR."); + + if (NULL == m_hmd) + { + return false; + } + } + + 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 + | ovrDistortionCap_Chromatic + | ovrDistortionCap_Vignette + | ovrDistortionCap_TimeWarp + | ovrDistortionCap_Overdrive + , 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."); + ovrHmd_Destroy(m_hmd); + m_hmd = NULL; + return false; + } + + 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; + m_rtSize.h = max(sizeL.h, sizeR.h); + + m_warning = true; + + return true; + } + + void OVR::postReset(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/2; + rect.Size.h = m_rtSize.h; + + m_texture[0].Header.RenderViewport = rect; + + rect.Pos.x += rect.Size.w; + m_texture[1].Header.RenderViewport = rect; + + m_timing = ovrHmd_BeginFrame(m_hmd, 0); + } + } + + void OVR::preReset() + { + if (NULL != m_hmd) + { + ovrHmd_EndFrame(m_hmd, m_pose, m_texture); + ovrHmd_Destroy(m_hmd); + m_hmd = NULL; + } + } + + bool OVR::swap() + { + if (NULL == m_hmd) + { + return false; + } + + ovrHmd_EndFrame(m_hmd, m_pose, m_texture); + + if (m_warning) + { + m_warning = !ovrHmd_DismissHSWDisplay(m_hmd); + } + + m_timing = ovrHmd_BeginFrame(m_hmd, 0); + + m_pose[0] = ovrHmd_GetEyePose(m_hmd, ovrEye_Left); + m_pose[1] = ovrHmd_GetEyePose(m_hmd, ovrEye_Right); + + return true; + } + + void OVR::recenter() + { + if (NULL != m_hmd) + { + ovrHmd_RecenterPose(m_hmd); + } + } + + void OVR::getEyePose(HMD& _hmd) + { + if (NULL != m_hmd) + { + ovrEyeType eye[2] = { ovrEye_Left, ovrEye_Right }; + for (int ii = 0; ii < 2; ++ii) + { + ovrPosef& pose = m_pose[ii]; + pose = ovrHmd_GetEyePose(m_hmd, eye[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; + eye.adjust[0] = erd.ViewAdjust.x; + eye.adjust[1] = erd.ViewAdjust.y; + eye.adjust[2] = erd.ViewAdjust.z; + eye.pixelsPerTanAngle[0] = erd.PixelsPerTanAngleAtCenter.x; + eye.pixelsPerTanAngle[1] = erd.PixelsPerTanAngleAtCenter.y; + } + + _hmd.width = uint16_t(m_rtSize.w); + _hmd.height = uint16_t(m_rtSize.h); + } + else + { + _hmd.width = 0; + _hmd.height = 0; + } + } + +} // namespace bgfx + +#endif // BGFX_CONFIG_USE_OVR diff --git a/src/ovr.h b/src/ovr.h new file mode 100644 index 000000000..5fc18ef6c --- /dev/null +++ b/src/ovr.h @@ -0,0 +1,131 @@ +/* + * Copyright 2011-2014 Branimir Karadzic. All rights reserved. + * License: http://www.opensource.org/licenses/BSD-2-Clause + */ + +#include "bgfx_p.h" + +#if BGFX_CONFIG_USE_OVR + +# include + +# if BGFX_CONFIG_RENDERER_DIRECT3D9 +# define OVR_D3D_VERSION 9 +# include +# endif // BGFX_CONFIG_RENDERER_DIRECT3D9 + +# if BGFX_CONFIG_RENDERER_DIRECT3D11 +# ifdef OVR_CAPI_D3D_h +# undef OVR_CAPI_D3D_h +# undef OVR_D3D_VERSION +# endif // OVR_CAPI_D3D_h +# define OVR_D3D_VERSION 11 +# include +# endif // BGFX_CONFIG_RENDERER_DIRECT3D11 + +# if BGFX_CONFIG_RENDERER_OPENGL +# include +# endif // BGFX_CONFIG_RENDERER_OPENGL + +namespace bgfx +{ + struct OVR + { + OVR(); + ~OVR(); + + bool isInitialized() const + { + return m_initialized; + } + + bool isEnabled() const + { + return NULL != m_hmd; + } + + void init(); + void shutdown(); + + bool postReset(void* _nwh, ovrRenderAPIConfig* _config, bool _debug = false); + void postReset(ovrTexture _texture); + void preReset(); + bool swap(); + 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; + ovrEyeRenderDesc m_erd[2]; + ovrRecti m_rect[2]; + ovrPosef m_pose[2]; + ovrTexture m_texture[2]; + ovrSizei m_rtSize; + bool m_warning; + bool m_initialized; + }; + +} // namespace bgfx + +#else + +namespace bgfx +{ + struct OVR + { + OVR() + { + } + + ~OVR() + { + } + + void init() + { + } + + void shutdown() + { + } + + bool isInitialized() const + { + return false; + } + + bool isEnabled() const + { + return false; + } + + bool swap() + { + return false; + } + + void recenter() + { + } + + void getEyePose(HMD& _hmd) + { + _hmd.width = 0; + _hmd.height = 0; + } + + void getSize(uint32_t& _width, uint32_t& _height) const + { + _width = 0; + _height = 0; + } + }; + +} // namespace bgfx + +#endif // BGFX_CONFIG_USE_OVR diff --git a/src/renderer_d3d11.cpp b/src/renderer_d3d11.cpp index 79b3e489c..cddbf0a64 100644 --- a/src/renderer_d3d11.cpp +++ b/src/renderer_d3d11.cpp @@ -543,7 +543,10 @@ RENDERDOC_IMPORT struct RendererContextD3D11 : public RendererContextI { RendererContextD3D11() - : m_lost(0) + : m_renderdocdll(NULL) + , m_lost(0) + , m_backBufferColor(NULL) + , m_backBufferDepthStencil(NULL) , m_captureTexture(NULL) , m_captureResolve(NULL) , m_wireframe(false) @@ -551,6 +554,8 @@ RENDERDOC_IMPORT , m_vsChanges(0) , m_fsChanges(0) , m_rtMsaa(false) + , m_ovrRtv(NULL) + , m_ovrDsv(NULL) { } @@ -560,7 +565,13 @@ RENDERDOC_IMPORT void init() { - m_renderdocdll = loadRenderDoc(); + // Must be before device creation, and before RenderDoc. + m_ovr.init(); + + if (!m_ovr.isInitialized() ) + { + m_renderdocdll = loadRenderDoc(); + } m_fbh.idx = invalidHandle; memset(m_uniforms, 0, sizeof(m_uniforms) ); @@ -761,6 +772,7 @@ RENDERDOC_IMPORT | BGFX_CAPS_COMPUTE | (getIntelExtensions(m_device) ? BGFX_CAPS_FRAGMENT_ORDERING : 0) | BGFX_CAPS_SWAP_CHAIN + | (m_ovr.isInitialized() ? BGFX_CAPS_HMD : 0) ); g_caps.maxTextureSize = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; g_caps.maxFBAttachments = bx::uint32_min(D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT, BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS); @@ -785,6 +797,7 @@ RENDERDOC_IMPORT void shutdown() { preReset(); + m_ovr.shutdown(); m_deviceCtx->ClearState(); @@ -1074,6 +1087,10 @@ RENDERDOC_IMPORT uint32_t width = m_scd.BufferDesc.Width; uint32_t height = m_scd.BufferDesc.Height; + if (m_ovr.isEnabled() ) + { + m_ovr.getSize(width, height); + } FrameBufferHandle fbh = BGFX_INVALID_HANDLE; setFrameBuffer(fbh, false); @@ -1139,6 +1156,8 @@ RENDERDOC_IMPORT void preReset() { + ovrPreReset(); + DX_RELEASE(m_backBufferDepthStencil, 0); DX_RELEASE(m_backBufferColor, 0); @@ -1156,7 +1175,7 @@ RENDERDOC_IMPORT DX_RELEASE(color, 0); D3D11_TEXTURE2D_DESC dsd; - dsd.Width = m_scd.BufferDesc.Width; + dsd.Width = m_scd.BufferDesc.Width; dsd.Height = m_scd.BufferDesc.Height; dsd.MipLevels = 1; dsd.ArraySize = 1; @@ -1167,10 +1186,16 @@ RENDERDOC_IMPORT dsd.CPUAccessFlags = 0; dsd.MiscFlags = 0; - ID3D11Texture2D* depthStencil; - DX_CHECK(m_device->CreateTexture2D(&dsd, NULL, &depthStencil) ); - DX_CHECK(m_device->CreateDepthStencilView(depthStencil, NULL, &m_backBufferDepthStencil) ); - DX_RELEASE(depthStencil, 0); + ovrPostReset(); + + // If OVR doesn't create separate depth stencil view, create default one. + if (NULL == m_backBufferDepthStencil) + { + ID3D11Texture2D* depthStencil; + DX_CHECK(m_device->CreateTexture2D(&dsd, NULL, &depthStencil) ); + DX_CHECK(m_device->CreateDepthStencilView(depthStencil, NULL, &m_backBufferDepthStencil) ); + DX_RELEASE(depthStencil, 0); + } m_deviceCtx->OMSetRenderTargets(1, &m_backBufferColor, m_backBufferDepthStencil); @@ -1194,7 +1219,7 @@ RENDERDOC_IMPORT { if (NULL != m_swapChain) { - HRESULT hr = 0; + HRESULT hr = S_OK; uint32_t syncInterval = !!(m_flags & BGFX_RESET_VSYNC); for (uint32_t ii = 1, num = m_numWindows; ii < num && SUCCEEDED(hr); ++ii) { @@ -1203,7 +1228,10 @@ RENDERDOC_IMPORT if (SUCCEEDED(hr) ) { - hr = m_swapChain->Present(syncInterval, 0); + if (!m_ovr.swap() ) + { + hr = m_swapChain->Present(syncInterval, 0); + } } if (FAILED(hr) @@ -1252,7 +1280,7 @@ RENDERDOC_IMPORT void updateResolution(const Resolution& _resolution) { - if ( (uint32_t)m_scd.BufferDesc.Width != _resolution.m_width + if ( (uint32_t)m_scd.BufferDesc.Width != _resolution.m_width || (uint32_t)m_scd.BufferDesc.Height != _resolution.m_height || m_flags != _resolution.m_flags) { @@ -1264,7 +1292,7 @@ RENDERDOC_IMPORT m_resolution = _resolution; - m_scd.BufferDesc.Width = _resolution.m_width; + m_scd.BufferDesc.Width = _resolution.m_width; m_scd.BufferDesc.Height = _resolution.m_height; preReset(); @@ -1720,6 +1748,96 @@ RENDERDOC_IMPORT commitTextureStage(); } + void ovrPostReset() + { +#if BGFX_CONFIG_USE_OVR + if (m_flags & (BGFX_RESET_HMD|BGFX_RESET_HMD_DEBUG) ) + { + ovrD3D11Config config; + config.D3D11.Header.API = ovrRenderAPI_D3D11; + config.D3D11.Header.RTSize.w = m_scd.BufferDesc.Width; + config.D3D11.Header.RTSize.h = m_scd.BufferDesc.Height; + 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_bgfxHwnd, &config.Config, !!(m_flags & BGFX_RESET_HMD_DEBUG) ) ) + { + uint32_t size = sizeof(uint32_t) + sizeof(TextureCreate); + const Memory* mem = alloc(size); + + 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; + 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); + + std::swap(m_ovrRtv, m_backBufferColor); + + BX_CHECK(NULL == m_backBufferDepthStencil, ""); + std::swap(m_ovrDsv, m_backBufferDepthStencil); + } + } +#endif // BGFX_CONFIG_USE_OVR + } + + void ovrPreReset() + { +#if BGFX_CONFIG_USE_OVR + if (NULL != m_ovrRtv) + { + m_ovr.preReset(); + std::swap(m_ovrRtv, m_backBufferColor); + std::swap(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 + } + void capturePostReset() { if (m_flags&BGFX_RESET_CAPTURE) @@ -2073,6 +2191,11 @@ RENDERDOC_IMPORT FrameBufferHandle m_fbh; bool m_rtMsaa; + + OVR m_ovr; + TextureD3D11 m_ovrRT; + ID3D11RenderTargetView* m_ovrRtv; + ID3D11DepthStencilView* m_ovrDsv; }; static RendererContextD3D11* s_renderD3D11; @@ -2816,18 +2939,63 @@ RENDERDOC_IMPORT currentState.m_flags = BGFX_STATE_NONE; currentState.m_stencil = packStencil(BGFX_STENCIL_NONE, BGFX_STENCIL_NONE); - Matrix4 viewProj[BGFX_CONFIG_MAX_VIEWS]; + Matrix4 mtxViewTmp[2][BGFX_CONFIG_MAX_VIEWS]; + Matrix4* mtxView[2] = { _render->m_view, mtxViewTmp[1] }; + Matrix4 mtxViewProj[2][BGFX_CONFIG_MAX_VIEWS]; + + const bool hmdEnabled = m_ovr.isEnabled(); + _render->m_hmdEnabled = hmdEnabled; + + if (hmdEnabled) + { + HMD& hmd = _render->m_hmd; + m_ovr.getEyePose(hmd); + + mtxView[0] = mtxViewTmp[0]; + Matrix4 viewAdjust; + bx::mtxIdentity(viewAdjust.un.val); + + for (uint32_t eye = 0; eye < 2; ++eye) + { + const HMD::Eye hmdEye = hmd.eye[eye]; + viewAdjust.un.val[12] = hmdEye.adjust[0]; + viewAdjust.un.val[13] = hmdEye.adjust[1]; + viewAdjust.un.val[14] = hmdEye.adjust[2]; + + for (uint32_t ii = 0; ii < BGFX_CONFIG_MAX_VIEWS; ++ii) + { + if (BGFX_VIEW_STEREO == (_render->m_viewFlags[ii] & BGFX_VIEW_STEREO) ) + { + bx::float4x4_mul(&mtxView[eye][ii].un.f4x4 + , &_render->m_view[ii].un.f4x4 + , &viewAdjust.un.f4x4 + ); + } + else + { + memcpy(&mtxView[0][ii].un.f4x4, &_render->m_view[ii].un.f4x4, sizeof(Matrix4) ); + } + } + } + } + for (uint32_t ii = 0; ii < BGFX_CONFIG_MAX_VIEWS; ++ii) { - bx::float4x4_mul(&viewProj[ii].un.f4x4, &_render->m_view[ii].un.f4x4, &_render->m_proj[ii].un.f4x4); + for (uint32_t eye = 0; eye < uint32_t(hmdEnabled)+1; ++eye) + { + bx::float4x4_mul(&mtxViewProj[eye][ii].un.f4x4 + , &mtxView[eye][ii].un.f4x4 + , &_render->m_proj[eye][ii].un.f4x4 + ); + } } Matrix4 invView; Matrix4 invProj; Matrix4 invViewProj; - uint8_t invViewCached = 0xff; - uint8_t invProjCached = 0xff; - uint8_t invViewProjCached = 0xff; + uint16_t invViewCached = UINT16_MAX; + uint16_t invProjCached = UINT16_MAX; + uint16_t invViewProjCached = UINT16_MAX; bool wireframe = !!(_render->m_debug&BGFX_DEBUG_WIREFRAME); bool scissorEnabled = false; @@ -2856,17 +3024,33 @@ RENDERDOC_IMPORT if (0 == (_render->m_debug&BGFX_DEBUG_IFH) ) { - for (uint32_t item = 0, numItems = _render->m_num; item < numItems; ++item) + bool viewRestart = false; + uint8_t eye = 0; + uint8_t restartState = 0; + Rect rect = _render->m_rect[0]; + + int32_t numItems = _render->m_num; + for (int32_t item = 0, restartItem = numItems; item < numItems || restartItem < numItems;) { const bool isCompute = key.decode(_render->m_sortKeys[item]); - const bool viewChanged = key.m_view != view; + const bool viewChanged = 0 + || key.m_view != view + || item == numItems + ; const RenderItem& renderItem = _render->m_renderItem[_render->m_sortValues[item] ]; + ++item; if (viewChanged) { - PIX_ENDEVENT(); - PIX_BEGINEVENT(D3DCOLOR_RGBA(0xff, 0x00, 0x00, 0xff), s_viewNameW[key.m_view]); + if (1 == restartState) + { + restartState = 2; + item = restartItem; + restartItem = numItems; + view = 0xff; + continue; + } view = key.m_view; programIdx = invalidHandle; @@ -2877,7 +3061,43 @@ RENDERDOC_IMPORT setFrameBuffer(fbh); } - const Rect& rect = _render->m_rect[view]; + viewRestart = ( (BGFX_VIEW_STEREO == (_render->m_viewFlags[view] & BGFX_VIEW_STEREO) ) ); + viewRestart &= hmdEnabled; + if (viewRestart) + { + if (0 == restartState) + { + restartState = 1; + restartItem = item - 1; + } + + eye = (restartState - 1) & 1; + restartState &= 1; + } + else + { + eye = 0; + } + + PIX_ENDEVENT(); + + rect = _render->m_rect[view]; + if (viewRestart) + { + wchar_t* viewNameW = s_viewNameW[view]; + viewNameW[3] = eye ? L'R' : L'L'; + PIX_BEGINEVENT(D3DCOLOR_RGBA(0xff, 0x00, 0x00, 0xff), viewNameW); + + rect.m_x = eye * (rect.m_width+1)/2; + rect.m_width /= 2; + } + else + { + wchar_t* viewNameW = s_viewNameW[view]; + viewNameW[3] = L' '; + PIX_BEGINEVENT(D3DCOLOR_RGBA(0xff, 0x00, 0x00, 0xff), viewNameW); + } + const Rect& scissorRect = _render->m_scissor[view]; viewHasScissor = !scissorRect.isZero(); viewScissorRect = viewHasScissor ? scissorRect : rect; @@ -3194,38 +3414,43 @@ RENDERDOC_IMPORT { case PredefinedUniform::ViewRect: { - float rect[4]; - rect[0] = _render->m_rect[view].m_x; - rect[1] = _render->m_rect[view].m_y; - rect[2] = _render->m_rect[view].m_width; - rect[3] = _render->m_rect[view].m_height; + float frect[4]; + frect[0] = rect.m_x; + frect[1] = rect.m_y; + frect[2] = rect.m_width; + frect[3] = rect.m_height; - setShaderConstant(flags, predefined.m_loc, &rect[0], 1); + setShaderConstant(flags, predefined.m_loc, &frect[0], 1); } break; case PredefinedUniform::ViewTexel: { - float rect[4]; - rect[0] = 1.0f/float(_render->m_rect[view].m_width); - rect[1] = 1.0f/float(_render->m_rect[view].m_height); + float frect[4]; + frect[0] = 1.0f/float(rect.m_width); + frect[1] = 1.0f/float(rect.m_height); - setShaderConstant(flags, predefined.m_loc, &rect[0], 1); + setShaderConstant(flags, predefined.m_loc, &frect[0], 1); } break; case PredefinedUniform::View: { - setShaderConstant(flags, predefined.m_loc, _render->m_view[view].un.val, bx::uint32_min(4, predefined.m_count) ); + setShaderConstant(flags + , predefined.m_loc + , mtxView[eye][view].un.val + , bx::uint32_min(4, predefined.m_count) + ); } break; case PredefinedUniform::InvView: { - if (view != invViewCached) + uint16_t viewEye = (view << 1) | eye; + if (viewEye != invViewCached) { - invViewCached = view; - bx::float4x4_inverse(&invView.un.f4x4, &_render->m_view[view].un.f4x4); + invViewCached = viewEye; + bx::float4x4_inverse(&invView.un.f4x4, &mtxView[eye][view].un.f4x4); } setShaderConstant(flags, predefined.m_loc, invView.un.val, bx::uint32_min(4, predefined.m_count) ); @@ -3234,16 +3459,17 @@ RENDERDOC_IMPORT case PredefinedUniform::Proj: { - setShaderConstant(flags, predefined.m_loc, _render->m_proj[view].un.val, bx::uint32_min(4, predefined.m_count) ); + setShaderConstant(flags, predefined.m_loc, _render->m_proj[eye][view].un.val, bx::uint32_min(4, predefined.m_count) ); } break; case PredefinedUniform::InvProj: { - if (view != invProjCached) + uint16_t viewEye = (view << 1) | eye; + if (viewEye != invProjCached) { - invProjCached = view; - bx::float4x4_inverse(&invProj.un.f4x4, &_render->m_proj[view].un.f4x4); + invProjCached = viewEye; + bx::float4x4_inverse(&invProj.un.f4x4, &_render->m_proj[eye][view].un.f4x4); } setShaderConstant(flags, predefined.m_loc, invProj.un.val, bx::uint32_min(4, predefined.m_count) ); @@ -3252,16 +3478,17 @@ RENDERDOC_IMPORT case PredefinedUniform::ViewProj: { - setShaderConstant(flags, predefined.m_loc, viewProj[view].un.val, bx::uint32_min(4, predefined.m_count) ); + setShaderConstant(flags, predefined.m_loc, mtxViewProj[eye][view].un.val, bx::uint32_min(4, predefined.m_count) ); } break; case PredefinedUniform::InvViewProj: { - if (view != invViewProjCached) + uint16_t viewEye = (view << 1) | eye; + if (viewEye != invViewProjCached) { - invViewProjCached = view; - bx::float4x4_inverse(&invViewProj.un.f4x4, &viewProj[view].un.f4x4); + invViewProjCached = viewEye; + bx::float4x4_inverse(&invViewProj.un.f4x4, &mtxViewProj[eye][view].un.f4x4); } setShaderConstant(flags, predefined.m_loc, invViewProj.un.val, bx::uint32_min(4, predefined.m_count) ); @@ -3279,7 +3506,7 @@ RENDERDOC_IMPORT { Matrix4 modelView; const Matrix4& model = _render->m_matrixCache.m_cache[draw.m_matrix]; - bx::float4x4_mul(&modelView.un.f4x4, &model.un.f4x4, &_render->m_view[view].un.f4x4); + bx::float4x4_mul(&modelView.un.f4x4, &model.un.f4x4, &mtxView[eye][view].un.f4x4); setShaderConstant(flags, predefined.m_loc, modelView.un.val, bx::uint32_min(4, predefined.m_count) ); } break; @@ -3288,7 +3515,7 @@ RENDERDOC_IMPORT { Matrix4 modelViewProj; const Matrix4& model = _render->m_matrixCache.m_cache[draw.m_matrix]; - bx::float4x4_mul(&modelViewProj.un.f4x4, &model.un.f4x4, &viewProj[view].un.f4x4); + bx::float4x4_mul(&modelViewProj.un.f4x4, &model.un.f4x4, &mtxViewProj[eye][view].un.f4x4); setShaderConstant(flags, predefined.m_loc, modelViewProj.un.val, bx::uint32_min(4, predefined.m_count) ); } break; @@ -3540,11 +3767,15 @@ RENDERDOC_IMPORT , freq/frameTime ); + char hmd[16]; + bx::snprintf(hmd, BX_COUNTOF(hmd), ", [%c] HMD ", hmdEnabled ? '\xfe' : ' '); + const uint32_t msaa = (m_resolution.m_flags&BGFX_RESET_MSAA_MASK)>>BGFX_RESET_MSAA_SHIFT; - tvm.printf(10, pos++, 0x8e, " Reset flags: [%c] vsync, [%c] MSAAx%d " + tvm.printf(10, pos++, 0x8e, " Reset flags: [%c] vsync, [%c] MSAAx%d%s" , !!(m_resolution.m_flags&BGFX_RESET_VSYNC) ? '\xfe' : ' ' , 0 != msaa ? '\xfe' : ' ' , 1<m_view[ii].un.f4x4, &_render->m_proj[ii].un.f4x4); + bx::float4x4_mul(&viewProj[ii].un.f4x4, &_render->m_view[ii].un.f4x4, &_render->m_proj[0][ii].un.f4x4); } Matrix4 invView; @@ -3212,7 +3212,7 @@ namespace bgfx case PredefinedUniform::Proj: { - setShaderConstantF(flags, predefined.m_loc, _render->m_proj[view].un.val, bx::uint32_min(4, predefined.m_count) ); + setShaderConstantF(flags, predefined.m_loc, _render->m_proj[0][view].un.val, bx::uint32_min(4, predefined.m_count) ); } break; @@ -3221,7 +3221,7 @@ namespace bgfx if (view != invProjCached) { invProjCached = view; - bx::float4x4_inverse(&invProj.un.f4x4, &_render->m_proj[view].un.f4x4); + bx::float4x4_inverse(&invProj.un.f4x4, &_render->m_proj[0][view].un.f4x4); } setShaderConstantF(flags, predefined.m_loc, invProj.un.val, bx::uint32_min(4, predefined.m_count) ); diff --git a/src/renderer_gl.cpp b/src/renderer_gl.cpp index 1e3ffdbde..c48e7733c 100644 --- a/src/renderer_gl.cpp +++ b/src/renderer_gl.cpp @@ -854,6 +854,7 @@ namespace bgfx , 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) ); } @@ -870,6 +871,9 @@ namespace bgfx setRenderContextSize(BGFX_DEFAULT_WIDTH, BGFX_DEFAULT_HEIGHT); + // Must be after context is initialized?! + m_ovr.init(); + m_vendor = getGLString(GL_VENDOR); m_renderer = getGLString(GL_RENDERER); m_version = getGLString(GL_VERSION); @@ -1364,10 +1368,15 @@ namespace bgfx { bx::snprintf(s_viewName[ii], BGFX_CONFIG_MAX_VIEW_NAME_RESERVED+1, "%3d ", ii); } + + ovrPostReset(); } void shutdown() { + ovrPreReset(); + m_ovr.shutdown(); + if (m_vaoSupport) { GL_CHECK(glBindVertexArray(0) ); @@ -1413,7 +1422,11 @@ namespace bgfx { m_glctx.swap(m_frameBuffers[m_windows[ii].idx].m_swapChain); } - m_glctx.swap(); + + if (!m_ovr.swap() ) + { + m_glctx.swap(); + } } } @@ -1575,7 +1588,7 @@ namespace bgfx uint32_t length = m_resolution.m_width*m_resolution.m_height*4; uint8_t* data = (uint8_t*)BX_ALLOC(g_allocator, length); - uint32_t width = m_resolution.m_width; + uint32_t width = m_resolution.m_width; uint32_t height = m_resolution.m_height; GL_CHECK(glReadPixels(0 @@ -1630,8 +1643,12 @@ namespace bgfx GL_CHECK(glBindVertexArray(m_vao) ); } - uint32_t width = m_resolution.m_width; + 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) ); @@ -1685,9 +1702,9 @@ namespace bgfx void updateResolution(const Resolution& _resolution) { - if (m_resolution.m_width != _resolution.m_width + if (m_resolution.m_width != _resolution.m_width || m_resolution.m_height != _resolution.m_height - || m_resolution.m_flags != _resolution.m_flags) + || m_resolution.m_flags != _resolution.m_flags) { m_textVideoMem.resize(false, _resolution.m_width, _resolution.m_height); m_textVideoMem.clear(); @@ -1699,6 +1716,9 @@ namespace bgfx bool vsync = !!(m_resolution.m_flags&BGFX_RESET_VSYNC); setRenderContextSize(_resolution.m_width, _resolution.m_height, msaa, vsync); updateCapture(); + + ovrPreReset(); + ovrPostReset(); } } @@ -1806,7 +1826,7 @@ namespace bgfx GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_backBufferFbo) ); GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, m_msaaBackBufferFbo) ); GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0) ); - uint32_t width = m_resolution.m_width; + uint32_t width = m_resolution.m_width; uint32_t height = m_resolution.m_height; GLenum filter = BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGL) || BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGLES < 30) ? GL_NEAREST @@ -1925,6 +1945,81 @@ namespace bgfx } } + void ovrPostReset() + { +#if BGFX_CONFIG_USE_OVR + if (m_resolution.m_flags & (BGFX_RESET_HMD|BGFX_RESET_HMD_DEBUG) ) + { + ovrGLConfig config; + config.OGL.Header.API = ovrRenderAPI_OpenGL; + config.OGL.Header.RTSize.w = m_resolution.m_width; + config.OGL.Header.RTSize.h = m_resolution.m_height; + config.OGL.Header.Multisample = 0; + config.OGL.Window = g_bgfxHwnd; + config.OGL.DC = GetDC(g_bgfxHwnd); + if (m_ovr.postReset(g_bgfxHwnd, &config.Config, !!(m_resolution.m_flags & BGFX_RESET_HMD_DEBUG) ) ) + { + uint32_t size = sizeof(uint32_t) + sizeof(TextureCreate); + const Memory* mem = alloc(size); + + 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; + 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); + } + } +#endif // BGFX_CONFIG_USE_OVR + } + + void ovrPreReset() + { +#if BGFX_CONFIG_USE_OVR + if (m_ovr.isEnabled() ) + { + m_ovr.preReset(); + 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 + } + void updateCapture() { if (m_resolution.m_flags&BGFX_RESET_CAPTURE) @@ -2324,6 +2419,10 @@ namespace bgfx const char* m_renderer; const char* m_version; const char* m_glslVersion; + + OVR m_ovr; + TextureGL m_ovrRT; + GLint m_ovrFbo; }; RendererContextGL* s_renderGL; @@ -4009,24 +4108,73 @@ namespace bgfx currentState.m_flags = BGFX_STATE_NONE; currentState.m_stencil = packStencil(BGFX_STENCIL_NONE, BGFX_STENCIL_NONE); - Matrix4 viewProj[BGFX_CONFIG_MAX_VIEWS]; + Matrix4 mtxViewTmp[2][BGFX_CONFIG_MAX_VIEWS]; + Matrix4* mtxView[2] = { _render->m_view, mtxViewTmp[1] }; + Matrix4 mtxViewProj[2][BGFX_CONFIG_MAX_VIEWS]; + + const bool hmdEnabled = m_ovr.isEnabled(); + _render->m_hmdEnabled = hmdEnabled; + + if (hmdEnabled) + { + HMD& hmd = _render->m_hmd; + m_ovr.getEyePose(hmd); + + mtxView[0] = mtxViewTmp[0]; + Matrix4 viewAdjust; + bx::mtxIdentity(viewAdjust.un.val); + + for (uint32_t eye = 0; eye < 2; ++eye) + { + const HMD::Eye hmdEye = hmd.eye[eye]; + viewAdjust.un.val[12] = hmdEye.adjust[0]; + viewAdjust.un.val[13] = hmdEye.adjust[1]; + viewAdjust.un.val[14] = hmdEye.adjust[2]; + + for (uint32_t ii = 0; ii < BGFX_CONFIG_MAX_VIEWS; ++ii) + { + if (BGFX_VIEW_STEREO == (_render->m_viewFlags[ii] & BGFX_VIEW_STEREO) ) + { + bx::float4x4_mul(&mtxView[eye][ii].un.f4x4 + , &_render->m_view[ii].un.f4x4 + , &viewAdjust.un.f4x4 + ); + } + else + { + memcpy(&mtxView[0][ii].un.f4x4, &_render->m_view[ii].un.f4x4, sizeof(Matrix4) ); + } + } + } + } + for (uint32_t ii = 0; ii < BGFX_CONFIG_MAX_VIEWS; ++ii) { - bx::float4x4_mul(&viewProj[ii].un.f4x4, &_render->m_view[ii].un.f4x4, &_render->m_proj[ii].un.f4x4); + for (uint32_t eye = 0; eye < uint32_t(hmdEnabled)+1; ++eye) + { + bx::float4x4_mul(&mtxViewProj[eye][ii].un.f4x4 + , &mtxView[eye][ii].un.f4x4 + , &_render->m_proj[eye][ii].un.f4x4 + ); + } } Matrix4 invView; Matrix4 invProj; Matrix4 invViewProj; - uint8_t invViewCached = 0xff; - uint8_t invProjCached = 0xff; - uint8_t invViewProjCached = 0xff; + uint16_t invViewCached = UINT16_MAX; + uint16_t invProjCached = UINT16_MAX; + uint16_t invViewProjCached = UINT16_MAX; uint16_t programIdx = invalidHandle; SortKey key; uint8_t view = 0xff; FrameBufferHandle fbh = BGFX_INVALID_HANDLE; - int32_t height = _render->m_resolution.m_height; + int32_t height = hmdEnabled + ? _render->m_hmd.height + : _render->m_resolution.m_height + ; + _render->m_resolution.m_height; float alphaRef = 0.0f; uint32_t blendFactor = 0; @@ -4054,16 +4202,33 @@ namespace bgfx { GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_msaaBackBufferFbo) ); - for (uint32_t item = 0, numItems = _render->m_num; item < numItems; ++item) + bool viewRestart = false; + uint8_t eye = 0; + uint8_t restartState = 0; + Rect rect = _render->m_rect[0]; + + int32_t numItems = _render->m_num; + for (int32_t item = 0, restartItem = numItems; item < numItems || restartItem < numItems;) { const bool isCompute = key.decode(_render->m_sortKeys[item]); - const bool viewChanged = key.m_view != view; + const bool viewChanged = 0 + || key.m_view != view + || item == numItems + ; const RenderItem& renderItem = _render->m_renderItem[_render->m_sortValues[item] ]; + ++item; if (viewChanged) { - GL_CHECK(glInsertEventMarker(0, s_viewName[key.m_view]) ); + if (1 == restartState) + { + restartState = 2; + item = restartItem; + restartItem = numItems; + view = 0xff; + continue; + } view = key.m_view; programIdx = invalidHandle; @@ -4071,15 +4236,57 @@ namespace bgfx if (_render->m_fb[view].idx != fbh.idx) { fbh = _render->m_fb[view]; - height = setFrameBuffer(fbh, _render->m_resolution.m_height); + height = hmdEnabled + ? _render->m_hmd.height + : _render->m_resolution.m_height + ; + height = setFrameBuffer(fbh, height); + } + + viewRestart = ( (BGFX_VIEW_STEREO == (_render->m_viewFlags[view] & BGFX_VIEW_STEREO) ) ); + viewRestart &= hmdEnabled; + if (viewRestart) + { + if (0 == restartState) + { + restartState = 1; + restartItem = item - 1; + } + + eye = (restartState - 1) & 1; + restartState &= 1; + } + else + { + eye = 0; + } + + rect = _render->m_rect[view]; + if (viewRestart) + { + char* viewName = s_viewName[view]; + viewName[3] = eye ? 'R' : 'L'; + GL_CHECK(glInsertEventMarker(0, viewName) ); + + rect.m_x = eye * (rect.m_width+1)/2; + rect.m_width /= 2; + } + else + { + char* viewName = s_viewName[view]; + viewName[3] = ' '; + GL_CHECK(glInsertEventMarker(0, viewName) ); } - const Rect& rect = _render->m_rect[view]; const Rect& scissorRect = _render->m_scissor[view]; viewHasScissor = !scissorRect.isZero(); viewScissorRect = viewHasScissor ? scissorRect : rect; - GL_CHECK(glViewport(rect.m_x, height-rect.m_height-rect.m_y, rect.m_width, rect.m_height) ); + GL_CHECK(glViewport(rect.m_x + , height-rect.m_height-rect.m_y + , rect.m_width + , rect.m_height + ) ); Clear& clear = _render->m_clear[view]; @@ -4473,28 +4680,28 @@ namespace bgfx { case PredefinedUniform::ViewRect: { - float rect[4]; - rect[0] = _render->m_rect[view].m_x; - rect[1] = _render->m_rect[view].m_y; - rect[2] = _render->m_rect[view].m_width; - rect[3] = _render->m_rect[view].m_height; + float frect[4]; + frect[0] = rect.m_x; + frect[1] = rect.m_y; + frect[2] = rect.m_width; + frect[3] = rect.m_height; GL_CHECK(glUniform4fv(predefined.m_loc , 1 - , &rect[0] + , &frect[0] ) ); } break; case PredefinedUniform::ViewTexel: { - float rect[4]; - rect[0] = 1.0f/float(_render->m_rect[view].m_width); - rect[1] = 1.0f/float(_render->m_rect[view].m_height); + float frect[4]; + frect[0] = 1.0f/float(rect.m_width); + frect[1] = 1.0f/float(rect.m_height); GL_CHECK(glUniform4fv(predefined.m_loc , 1 - , &rect[0] + , &frect[0] ) ); } break; @@ -4504,17 +4711,18 @@ namespace bgfx GL_CHECK(glUniformMatrix4fv(predefined.m_loc , 1 , GL_FALSE - , _render->m_view[view].un.val + , mtxView[eye][view].un.val ) ); } break; case PredefinedUniform::InvView: { - if (view != invViewCached) + uint16_t viewEye = (view << 1) | eye; + if (viewEye != invViewCached) { - invViewCached = view; - bx::float4x4_inverse(&invView.un.f4x4, &_render->m_view[view].un.f4x4); + invViewCached = viewEye; + bx::float4x4_inverse(&invView.un.f4x4, &mtxView[eye][view].un.f4x4); } GL_CHECK(glUniformMatrix4fv(predefined.m_loc @@ -4530,17 +4738,18 @@ namespace bgfx GL_CHECK(glUniformMatrix4fv(predefined.m_loc , 1 , GL_FALSE - , _render->m_proj[view].un.val + , _render->m_proj[0][view].un.val ) ); } break; case PredefinedUniform::InvProj: { - if (view != invProjCached) + uint16_t viewEye = (view << 1) | eye; + if (viewEye != invProjCached) { - invProjCached = view; - bx::float4x4_inverse(&invProj.un.f4x4, &_render->m_proj[view].un.f4x4); + invProjCached = viewEye; + bx::float4x4_inverse(&invProj.un.f4x4, &_render->m_proj[eye][view].un.f4x4); } GL_CHECK(glUniformMatrix4fv(predefined.m_loc @@ -4556,17 +4765,18 @@ namespace bgfx GL_CHECK(glUniformMatrix4fv(predefined.m_loc , 1 , GL_FALSE - , viewProj[view].un.val + , mtxViewProj[eye][view].un.val ) ); } break; case PredefinedUniform::InvViewProj: { - if (view != invViewProjCached) + uint16_t viewEye = (view << 1) | eye; + if (viewEye != invViewProjCached) { - invViewProjCached = view; - bx::float4x4_inverse(&invViewProj.un.f4x4, &viewProj[view].un.f4x4); + invViewProjCached = viewEye; + bx::float4x4_inverse(&invViewProj.un.f4x4, &mtxViewProj[eye][view].un.f4x4); } GL_CHECK(glUniformMatrix4fv(predefined.m_loc @@ -4592,7 +4802,7 @@ namespace bgfx { Matrix4 modelView; const Matrix4& model = _render->m_matrixCache.m_cache[draw.m_matrix]; - bx::float4x4_mul(&modelView.un.f4x4, &model.un.f4x4, &_render->m_view[view].un.f4x4); + bx::float4x4_mul(&modelView.un.f4x4, &model.un.f4x4, &mtxView[eye][view].un.f4x4); GL_CHECK(glUniformMatrix4fv(predefined.m_loc , 1 @@ -4606,7 +4816,7 @@ namespace bgfx { Matrix4 modelViewProj; const Matrix4& model = _render->m_matrixCache.m_cache[draw.m_matrix]; - bx::float4x4_mul(&modelViewProj.un.f4x4, &model.un.f4x4, &viewProj[view].un.f4x4); + bx::float4x4_mul(&modelViewProj.un.f4x4, &model.un.f4x4, &mtxViewProj[eye][view].un.f4x4); GL_CHECK(glUniformMatrix4fv(predefined.m_loc , 1 @@ -4924,11 +5134,15 @@ namespace bgfx , freq/frameTime ); + char hmd[16]; + bx::snprintf(hmd, BX_COUNTOF(hmd), ", [%c] HMD ", hmdEnabled ? '\xfe' : ' '); + const uint32_t msaa = (m_resolution.m_flags&BGFX_RESET_MSAA_MASK)>>BGFX_RESET_MSAA_SHIFT; - tvm.printf(10, pos++, 0x8e, " Reset flags: [%c] vsync, [%c] MSAAx%d " + tvm.printf(10, pos++, 0x8e, " Reset flags: [%c] vsync, [%c] MSAAx%d%s" , !!(m_resolution.m_flags&BGFX_RESET_VSYNC) ? '\xfe' : ' ' , 0 != msaa ? '\xfe' : ' ' , 1< # endif // BX_PLATFORM_EMSCRIPTEN - #endif // BGFX_CONFIG_RENDERER_OPENGL +#include "ovr.h" + #ifndef GL_LUMINANCE # define GL_LUMINANCE 0x1909 #endif // GL_LUMINANCE