Merge pull request #920 from mendsley/vr_reorg

Add a new platform agnostic bgfx::VR internal class
This commit is contained in:
Branimir Karadžić
2016-09-16 20:12:16 -07:00
committed by GitHub
8 changed files with 845 additions and 699 deletions

205
src/hmd.cpp Normal file
View File

@@ -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

102
src/hmd.h Normal file
View File

@@ -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

View File

@@ -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<ovrEyeType>(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

View File

@@ -10,6 +10,7 @@
#if BGFX_CONFIG_USE_OVR
# include "hmd.h"
# include <OVR_Version.h>
# define OVR_VERSION_(_a, _b, _c) (_a * 10000 + _b * 100 + _c)
@@ -25,160 +26,41 @@
# include <OVR_CAPI_GL.h>
# 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

View File

@@ -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
{

View File

@@ -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()

View File

@@ -9,6 +9,7 @@
# include "renderer_gl.h"
# include <bx/timer.h>
# include <bx/uint32_t.h>
# 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
{

View File

@@ -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);