Преглед на файлове

Add platform agnostic bgfx::VR for renderers to interface

The new platform agnositic class bgfx::VR manages the
functionality that is shared across the various VR platforms.

The individual platform renderers no longer need
to interface with the internal VR tpyes (OVRRenderI) directly

This greatly simplifies the OVR object's surface area which
is now provided by the VRImplI interface. bgfx::VR now manages
core lifecycle issues of the headset.

The notable renderer API changes are the separation of sensor
sampling and rendering. We need these separate so we can control
the timing (later commit) of camera sampling with finer granularity
than at the start of the video frame.
Matthew Endsley преди 9 години
родител
ревизия
d9dd4bceb5
променени са 8 файла, в които са добавени 814 реда и са изтрити 668 реда
  1. 205 0
      src/hmd.cpp
  2. 102 0
      src/hmd.h
  3. 103 178
      src/hmd_ovr.cpp
  4. 27 145
      src/hmd_ovr.h
  5. 169 123
      src/renderer_d3d11.cpp
  6. 1 20
      src/renderer_d3d11.h
  7. 206 179
      src/renderer_gl.cpp
  8. 1 23
      src/renderer_gl.h

+ 205 - 0
src/hmd.cpp

@@ -0,0 +1,205 @@
+/*
+ * Copyright 2011-2016 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
+ */
+
+#include "hmd.h"
+
+namespace bgfx
+{
+	VR::VR()
+		: m_framesUntilReconnect(0)
+		, m_enabled(false)
+	{
+	}
+
+	void VR::init(VRImplI* _impl)
+	{
+		if (!_impl)
+		{
+			return;
+		}
+
+		if (!_impl->init())
+		{
+			return;
+		}
+
+		m_impl = _impl;
+		m_impl->connect(&m_desc);
+		if (!m_impl->isConnected())
+		{
+			connectFailed();
+			return;
+		}
+
+		m_hmdSize.m_w = m_desc.m_eyeSize[0].m_w + m_desc.m_eyeSize[1].m_w;
+		m_hmdSize.m_h = bx::uint32_max(m_desc.m_eyeSize[0].m_h, m_desc.m_eyeSize[1].m_h);
+	}
+
+	void VR::shutdown()
+	{
+		if (!m_impl)
+		{
+			return;
+		}
+
+		m_impl->destroySwapChain();
+		if (m_impl->isConnected())
+		{
+			m_impl->disconnect();
+		}
+
+		m_impl->shutdown();
+		m_impl = NULL;
+		m_enabled = false;
+	}
+
+	void VR::renderEyeStart(uint8_t _eye, Rect* _viewport)
+	{
+		BX_CHECK(m_enabled, "VR::renderEyeStart called while not enabled - render usage error");
+
+		_viewport->m_x      = 0;
+		_viewport->m_y      = 0;
+		_viewport->m_width  = m_desc.m_eyeSize[_eye].m_w;
+		_viewport->m_height = m_desc.m_eyeSize[_eye].m_h;
+
+		m_impl->renderEyeStart(m_desc, _eye);
+	}
+
+	void VR::recenter()
+	{
+		if (m_impl)
+		{
+			m_impl->recenter();
+		}
+	}
+
+	void VR::preReset()
+	{
+		if (m_impl)
+		{
+			m_impl->destroyMirror();
+		}
+
+		m_enabled = false;
+	}
+
+	void VR::postReset(int _msaaSamples, int _mirrorWidth, int _mirrorHeight)
+	{
+		if (m_impl && m_impl->createSwapChain(m_desc, _msaaSamples, _mirrorWidth, _mirrorHeight))
+		{
+			m_enabled = true;
+		}
+	}
+
+	void VR::flip()
+	{
+		if (!m_impl || !m_enabled)
+		{
+			return;
+		}
+		else if (!m_impl->isConnected() && !tryReconnect())
+		{
+			return;
+		}
+
+		if (!m_impl->submitSwapChain(m_desc))
+		{
+			m_impl->destroySwapChain();
+			m_impl->disconnect();
+			return;
+		}
+	}
+
+	void VR::swap(HMD& _hmd)
+	{
+		_hmd.flags = BGFX_HMD_NONE;
+
+		if (!m_impl)
+		{
+			return;
+		}
+
+		_hmd.flags = BGFX_HMD_DEVICE_RESOLUTION;
+		_hmd.deviceWidth = m_desc.m_deviceSize.m_w;
+		_hmd.deviceHeight = m_desc.m_deviceSize.m_h;
+		_hmd.width = m_hmdSize.m_w;
+		_hmd.height = m_hmdSize.m_h;
+
+		if (!m_impl->updateTracking(_hmd))
+		{
+			m_impl->destroySwapChain();
+			m_impl->disconnect();
+		}
+
+		if (!m_impl->isConnected())
+		{
+			return;
+		}
+
+		for (int eye = 0; eye < 2; ++eye)
+		{
+			_hmd.eye[eye].fov[0] = m_desc.m_eyeFov[eye].m_up;
+			_hmd.eye[eye].fov[1] = m_desc.m_eyeFov[eye].m_down;
+			_hmd.eye[eye].fov[2] = m_desc.m_eyeFov[eye].m_left;
+			_hmd.eye[eye].fov[3] = m_desc.m_eyeFov[eye].m_right;
+		}
+
+		m_impl->updateInput(_hmd);
+		if (m_enabled)
+		{
+			_hmd.flags |= BGFX_HMD_RENDERING;
+		}
+	}
+
+	bool VR::tryReconnect()
+	{
+		if (!m_impl)
+		{
+			return false;
+		}
+
+		BX_CHECK(!m_impl->isConnected(), "VR::tryReconnect called when already connected. Usage error");
+
+		--m_framesUntilReconnect;
+		if (m_framesUntilReconnect > 0)
+		{
+			return false;
+		}
+
+		m_framesUntilReconnect = 90;
+		m_impl->connect(&m_desc);
+		if (!m_impl->isConnected())
+		{
+			connectFailed();
+			return false;
+		}
+
+		m_hmdSize.m_w = m_desc.m_eyeSize[0].m_w + m_desc.m_eyeSize[1].m_w;
+		m_hmdSize.m_h = bx::uint32_max(m_desc.m_eyeSize[0].m_h, m_desc.m_eyeSize[1].m_h);
+		return true;
+	}
+
+	void VR::connectFailed()
+	{
+		// sane defaults
+		m_desc.m_deviceSize.m_w = 2160;
+		m_desc.m_deviceSize.m_h = 1200;
+		m_desc.m_deviceType = 0;
+		m_desc.m_refreshRate = 90.0f;
+		m_desc.m_neckOffset[0] = 0.0805f;
+		m_desc.m_neckOffset[1] = 0.075f;
+
+		for (int eye = 0; eye < 2; ++eye)
+		{
+			m_desc.m_eyeFov[eye].m_up = 1.32928634f;
+			m_desc.m_eyeFov[eye].m_down = 1.32928634f;
+		}
+		m_desc.m_eyeFov[0].m_left = 1.05865765f;
+		m_desc.m_eyeFov[0].m_right = 1.09236801f;
+		m_desc.m_eyeFov[1].m_left = 1.09236801f;
+		m_desc.m_eyeFov[1].m_right = 1.05865765f;
+	}
+
+} // namesapce bgfx

+ 102 - 0
src/hmd.h

@@ -0,0 +1,102 @@
+/*
+ * Copyright 2011-2016 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
+ */
+
+#ifndef BGFX_HMD_H_HEADER_GUARD
+#define BGFX_HMD_H_HEADER_GUARD
+
+#include "bgfx_p.h"
+
+namespace bgfx
+{
+	struct VRSize
+	{
+		uint32_t m_w;
+		uint32_t m_h;
+	};
+
+	struct VRFovTan
+	{
+		float m_up;
+		float m_down;
+		float m_left;
+		float m_right;
+	};
+
+	struct VRDesc
+	{
+		uint64_t m_adapterLuid;
+		uint32_t m_deviceType;
+		float m_refreshRate;
+		VRSize m_deviceSize;
+		VRSize m_eyeSize[2];
+		VRFovTan m_eyeFov[2];
+		float m_neckOffset[2];
+	};
+
+	struct BX_NO_VTABLE VRImplI
+	{
+		virtual ~VRImplI() = 0;
+
+		virtual bool init() = 0;
+		virtual void shutdown() = 0;
+		virtual void connect(VRDesc* _desc) = 0;
+		virtual void disconnect() = 0;
+		virtual bool isConnected() const = 0;
+
+		virtual bool updateTracking(HMD& _hmd) = 0;
+		virtual void updateInput(HMD& _hmd) = 0;
+		virtual void recenter() = 0;
+
+		virtual bool createSwapChain(const VRDesc& _desc, int _msaaSamples, int _mirrorWidth, int _mirrorHeight);
+		virtual void destroySwapChain() = 0;
+		virtual void destroyMirror() = 0;
+		virtual void renderEyeStart(const VRDesc& _desc, uint8_t _eye) = 0;
+		virtual bool submitSwapChain(const VRDesc& _desc) = 0;
+	};
+
+	inline VRImplI::~VRImplI()
+	{
+	}
+
+	class VR
+	{
+	public:
+		VR();
+
+		void init(VRImplI* _impl);
+		void shutdown();
+
+		bool isInitialized() const
+		{
+			return NULL != m_impl;
+		}
+
+		bool isEnabled() const
+		{
+			return m_enabled;
+		}
+
+		void renderEyeStart(uint8_t _eye, Rect* _viewport);
+		void recenter();
+
+		void preReset();
+		void postReset(int _msaaSamples, int _mirrorWidth, int _mirrorHeight);
+		void flip();
+		void swap(HMD& _hmd);
+
+	private:
+		bool tryReconnect();
+		void connectFailed();
+
+		VRDesc m_desc;
+		VRSize m_hmdSize;
+		VRImplI* m_impl;
+		uint32_t m_framesUntilReconnect;
+		bool m_enabled;
+	};
+
+} // namespace bgfx
+
+#endif // BGFX_HMD_H_HEADER_GUARD

+ 103 - 178
src/hmd_ovr.cpp

@@ -3,10 +3,12 @@
  * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
  */
 
-#include "hmd_ovr.h"
+#include "bgfx_p.h"
 
 #if BGFX_CONFIG_USE_OVR
 
+#include "hmd_ovr.h"
+
 namespace bgfx
 {
 #define _OVR_CHECK(_call) \
@@ -21,236 +23,159 @@ namespace bgfx
 #	define OVR_CHECK(_call) _call
 #endif // BGFX_CONFIG_DEBUG
 
-	OVR::OVR()
-		: m_hmd(NULL)
-		, m_enabled(false)
-		, m_render(NULL)
-		, m_frameIndex(0)
-		, m_sensorSampleTime(0)
+	VRImplOVR::VRImplOVR()
+		: m_session(NULL)
 	{
 	}
 
-	OVR::~OVR()
+	VRImplOVR::~VRImplOVR()
 	{
-		BX_CHECK(NULL == m_hmd, "OVR not shutdown properly.");
+		BX_CHECK(NULL == m_session, "OVR not shutdown properly.");
 	}
 
-	void OVR::init()
+	bool VRImplOVR::init()
 	{
-		ovrResult result = ovr_Initialize(NULL);
-
-		if (result != ovrSuccess)
+		ovrResult initialized = ovr_Initialize(NULL);
+		if (!OVR_SUCCESS(initialized))
 		{
-			BX_TRACE("Unable to create OVR device.");
-			return;
+			BX_TRACE("Unable to initialize OVR runtime.");
+			return false;
 		}
 
+		return true;
+	}
+
+	void VRImplOVR::shutdown()
+	{
+		ovr_Shutdown();
+	}
+
+	void VRImplOVR::connect(VRDesc* _desc)
+	{
 		ovrGraphicsLuid luid;
-		result = ovr_Create(&m_hmd, &luid);
-		if (result != ovrSuccess)
+		ovrResult result = ovr_Create(&m_session, &luid);
+		if (!OVR_SUCCESS(result))
 		{
-			BX_TRACE("Unable to create OVR device.");
+			BX_TRACE("Failed to create OVR device.");
 			return;
 		}
 
-		m_hmdDesc = ovr_GetHmdDesc(m_hmd);
+		BX_STATIC_ASSERT(sizeof(_desc->m_adapterLuid) >= sizeof(luid));
+		memcpy(&_desc->m_adapterLuid, &luid, sizeof(luid));
 
-		BX_TRACE("HMD: %s, %s, firmware: %d.%d"
-			, m_hmdDesc.ProductName
-			, m_hmdDesc.Manufacturer
-			, m_hmdDesc.FirmwareMajor
-			, m_hmdDesc.FirmwareMinor
-			);
+		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;
 
-		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);
-	}
+		BX_TRACE("OVR HMD: %s, %s, firmware: %d.%d"
+			, hmdDesc.ProductName
+			, hmdDesc.Manufacturer
+			, hmdDesc.FirmwareMajor
+			, hmdDesc.FirmwareMinor
+			);
 
-	void OVR::shutdown()
-	{
-		BX_CHECK(!m_enabled, "HMD not disabled.");
+		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),
+		};
 
-		if (NULL != m_render)
+		for (int eye = 0; eye < 2; ++eye)
 		{
-			m_render->destroy(m_hmd);
-			m_render = NULL;
+			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;
 		}
 
-		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);
-	}
+		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];
 
-	bool OVR::postReset()
-	{
-		if (NULL == m_hmd)
+		// build constant layer settings
+		m_renderLayer.Header.Type = ovrLayerType_EyeFov;
+		m_renderLayer.Header.Flags = 0;
+		for (int eye = 0; eye < 2; ++eye)
 		{
-			return false;
+			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];
 		}
 
-		for (uint32_t ii = 0; ii < 2; ++ii)
+		m_viewScale.HmdSpaceToWorldScaleInMeters = 1.0f;
+		for (int eye = 0; eye < 2; ++eye)
 		{
-			m_erd[ii] = ovr_GetRenderDesc(m_hmd, ovrEyeType(ii), m_hmdDesc.DefaultEyeFov[ii]);
+			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;
 		}
-
-		m_enabled = true;
-
-		return true;
 	}
 
-	void OVR::preReset()
+	void VRImplOVR::disconnect()
 	{
-		if (m_enabled)
+		if (NULL != m_session)
 		{
-			// on window resize this will recreate the mirror texture in ovrPostReset
-			m_render->preReset(m_hmd);
-			m_enabled = false;
+			ovr_Destroy(m_session);
+			m_session = NULL;
 		}
 	}
 
-	OVR::Enum OVR::swap(HMD& _hmd, bool originBottomLeft)
+	bool VRImplOVR::updateTracking(HMD& _hmd)
 	{
-		_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;
-		}
-
-		if (!m_enabled)
-		{
-			return NotEnabled;
+			return false;
 		}
 
-		ovrResult result;
+		ovr_GetEyePoses(m_session, 0, ovrTrue, m_viewScale.HmdToEyeOffset, m_renderLayer.RenderPose, &m_renderLayer.SensorSampleTime);
 
-		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;
+				for (uint32_t jj = 0; jj < 4; ++jj)
+				{
+					hmdEye.projection[4*ii + jj] = projection.M[jj][ii];
+				}
 			}
 		}
 
-		_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;
+		return true;
 	}
 
-	void OVR::recenter()
+	void VRImplOVR::updateInput(HMD& /* _hmd */)
 	{
-		if (NULL != m_hmd)
-		{
-			OVR_CHECK(ovr_RecenterTrackingOrigin(m_hmd) );
-		}
 	}
 
-	void OVR::getEyePose(HMD& _hmd)
+	void VRImplOVR::recenter()
 	{
-		if (NULL != m_hmd)
+		if (NULL != m_session)
 		{
-			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];
-					}
-				}
-
-				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;
-			}
+			ovr_RecenterTrackingOrigin(m_session);
 		}
-
-		_hmd.width  = uint16_t(m_hmdSize.w);
-		_hmd.height = uint16_t(m_hmdSize.h);
 	}
 
 } // namespace bgfx

+ 27 - 145
src/hmd_ovr.h

@@ -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()
-		{
-		}
-
-		bool isInitialized() const
-		{
-			return false;
-		}
-
-		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;
-		}
+		virtual bool updateTracking(HMD& _hmd);
+		virtual void updateInput(HMD& _hmd);
+		virtual void recenter();
+
+		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;
+
+	protected:
+		ovrSession m_session;
+		ovrLayerEyeFov m_renderLayer;
+		ovrViewScaleDesc m_viewScale;
+		ovrFovPort m_eyeFov[2];
+		ovrVector2f m_pixelsPerTanAngleAtCenter[2];
 	};
 
 } // namespace bgfx

+ 169 - 123
src/renderer_d3d11.cpp

@@ -29,6 +29,10 @@
 #	define BGFX_GPU_PROFILER_END() BX_NOOP()
 #endif
 
+#if BGFX_CONFIG_USE_OVR
+#	include "hmd_ovr.h"
+#endif // BGFX_CONFIG_USE_OVR
+
 namespace bgfx { namespace d3d11
 {
 	static wchar_t s_viewNameW[BGFX_CONFIG_MAX_VIEWS][BGFX_CONFIG_MAX_VIEW_NAME];
@@ -601,6 +605,30 @@ namespace bgfx { namespace d3d11
 	static PFN_GET_DEBUG_INTERFACE1 DXGIGetDebugInterface1;
 #endif // USE_D3D11_DYNAMIC_LIB
 
+#if BGFX_CONFIG_USE_OVR
+	class VRImplOVRD3D11 : public VRImplOVR
+	{
+	public:
+		VRImplOVRD3D11();
+
+		virtual bool createSwapChain(const VRDesc& _desc, int _msaaSamples, int _mirrorWidth, int _mirrorHeight);
+		virtual void destroySwapChain();
+		virtual void destroyMirror();
+		virtual void renderEyeStart(const VRDesc& _desc, uint8_t _eye);
+		virtual bool submitSwapChain(const VRDesc& _desc);
+
+	private:
+		ID3D11RenderTargetView* m_eyeRtv[2][4];
+		ID3D11DepthStencilView* m_depthBuffer[2];
+		ID3D11Texture2D* m_msaaTexture[2];
+		ID3D11ShaderResourceView* m_msaaSv[2];
+		ID3D11RenderTargetView* m_msaaRtv[2];
+
+		ovrTextureSwapChain m_textureSwapChain[2];
+		ovrMirrorTexture m_mirrorTexture;
+	};
+#endif // BGFX_CONFIG_USE_OVR
+
 	struct RendererContextD3D11 : public RendererContextI
 	{
 		RendererContextD3D11()
@@ -662,7 +690,11 @@ namespace bgfx { namespace d3d11
 			ErrorState::Enum errorState = ErrorState::Default;
 
 			// Must be before device creation, and before RenderDoc.
-			m_ovr.init();
+			VRImplI* vrImpl = NULL;
+#if BGFX_CONFIG_USE_OVR
+			vrImpl = &m_ovrRender;
+#endif // BGFX_CONFIG_USE_OVR
+			m_ovr.init(vrImpl);
 
 			if (!m_ovr.isInitialized() )
 			{
@@ -2226,18 +2258,12 @@ BX_PRAGMA_DIAGNOSTIC_POP();
 
 				if (SUCCEEDED(hr) )
 				{
-					switch (m_ovr.swap(_hmd, false) )
+					m_ovr.flip();
+					m_ovr.swap(_hmd); // TODO - move this out of end-of-frame
+
+					if (!m_ovr.isEnabled())
 					{
-					case OVR::NotEnabled:
 						hr = m_swapChain->Present(syncInterval, 0);
-						break;
-
-					case OVR::DeviceLost:
-						ovrPreReset();
-						break;
-
-					default:
-						break;
 					}
 				}
 
@@ -3148,13 +3174,8 @@ BX_PRAGMA_DIAGNOSTIC_POP();
 #if BGFX_CONFIG_USE_OVR
 			if (m_resolution.m_flags & (BGFX_RESET_HMD|BGFX_RESET_HMD_DEBUG) )
 			{
-				if (m_ovr.postReset() )
-				{
-					const uint32_t msaaSamples = 1 << ((m_resolution.m_flags&BGFX_RESET_MSAA_MASK) >> BGFX_RESET_MSAA_SHIFT);
-
-					m_ovr.m_render = &m_ovrRender;
-					m_ovr.m_render->create(m_ovr.m_hmd, msaaSamples, m_resolution.m_width, m_resolution.m_height);
-				}
+				const uint32_t msaaSamples = 1 << ((m_resolution.m_flags&BGFX_RESET_MSAA_MASK) >> BGFX_RESET_MSAA_SHIFT);
+				m_ovr.postReset(msaaSamples, m_resolution.m_width, m_resolution.m_height);
 			}
 #endif // BGFX_CONFIG_USE_OVR
 		}
@@ -3553,9 +3574,9 @@ BX_PRAGMA_DIAGNOSTIC_POP();
 		bool m_rtMsaa;
 		bool m_timerQuerySupport;
 
-		OVR m_ovr;
+		VR m_ovr;
 #if BGFX_CONFIG_USE_OVR
-		OVRRenderD3D11 m_ovrRender;
+		VRImplOVRD3D11 m_ovrRender;
 #endif // BGFX_CONFIG_USE_OVR
 	};
 
@@ -3610,62 +3631,66 @@ BX_PRAGMA_DIAGNOSTIC_POP();
 	}
 
 #if BGFX_CONFIG_USE_OVR
-	void OVRRenderD3D11::create(const ovrSession& _session, int _msaaSamples, int _mirrorWidth, int _mirrorHeight)
+
+	VRImplOVRD3D11::VRImplOVRD3D11()
+		: m_mirrorTexture(NULL)
 	{
-		ovrHmdDesc hmdDesc = ovr_GetHmdDesc(_session);
+		memset(m_textureSwapChain, 0, sizeof(m_textureSwapChain));
+	}
+
+	bool VRImplOVRD3D11::createSwapChain(const VRDesc& _desc, int _msaaSamples, int _mirrorWidth, int _mirrorHeight)
+	{
+		ID3D11Device* device = s_renderD3D11->m_device;
 
 		for (int eye = 0; eye < 2; ++eye)
 		{
 			if (NULL == m_textureSwapChain[eye])
 			{
-				m_eyeTextureSize[eye] = ovr_GetFovTextureSize(_session, (ovrEyeType)eye, hmdDesc.DefaultEyeFov[eye], 1.0f);
 				m_msaaTexture[eye] = NULL;
 				m_msaaRtv[eye] = NULL;
-				m_msaaSv[eye]  = NULL;
-
-				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;
-
-				ID3D11Device* device = s_renderD3D11->m_device;
-
-				ovrResult result = ovr_CreateTextureSwapChainDX(_session, device, &desc, &m_textureSwapChain[eye]);
+				m_msaaSv[eye] = NULL;
 
-				if (!OVR_SUCCESS(result) )
+				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;
+
+				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);
 
-			if (NULL != m_msaaSv[eye])
-			{
-				m_msaaSv[eye]->Release();
-				m_msaaSv[eye] = NULL;
+				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_msaaRtv[eye])
+			ovrResult result = ovr_CommitTextureSwapChain(m_session, m_textureSwapChain[eye]);
+			if (!OVR_SUCCESS(result))
 			{
-				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
 						{

+ 1 - 20
src/renderer_d3d11.h

@@ -32,7 +32,7 @@ BX_PRAGMA_DIAGNOSTIC_POP()
 #include "renderer.h"
 #include "renderer_d3d.h"
 #include "shader_dxbc.h"
-#include "hmd_ovr.h"
+#include "hmd.h"
 #include "hmd_openvr.h"
 #include "debug_renderdoc.h"
 
@@ -60,25 +60,6 @@ BX_PRAGMA_DIAGNOSTIC_POP()
 
 namespace bgfx { namespace d3d11
 {
-#if BGFX_CONFIG_USE_OVR
-	struct OVRRenderD3D11 : public OVRRenderI
-	{
-		virtual void create(const ovrSession& _session, int _msaaSamples, int _mirrorWidth, int _mirrorHeight);
-		virtual void destroy(const ovrSession& _session);
-		virtual void preReset(const ovrSession& _session);
-		virtual void startEyeRender(const ovrSession& _session, int _eyeIdx);
-		virtual void postRender(const ovrSession& _session, int _eyeIdx);
-		virtual void blitMirror(const ovrSession& _session);
-
-		ID3D11RenderTargetView* m_eyeRtv[2][4];
-		ID3D11DepthStencilView* m_depthBuffer[2];
-		ID3D11Texture2D* m_msaaTexture[2];
-		ID3D11ShaderResourceView* m_msaaSv[2];
-		ID3D11RenderTargetView* m_msaaRtv[2];
-	};
-
-#endif // BGFX_CONFIG_USE_OVR
-
 	struct BufferD3D11
 	{
 		BufferD3D11()

+ 206 - 179
src/renderer_gl.cpp

@@ -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;
-
-				ovrHmdDesc hmdDesc = ovr_GetHmdDesc(_session);
-				m_eyeTextureSize[eye] = ovr_GetFovTextureSize(_session, ovrEyeType(eye), hmdDesc.DefaultEyeFov[eye], 1.0f);
-
-				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]);
+				memset(&m_eyeTexId[eye], 0, sizeof(m_eyeTexId[eye]));
+
+				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;
+
+				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(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(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(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;
+			ovr_CreateMirrorTextureGL(m_session, &mirrorDesc, &m_mirrorTexture);
+			if (m_mirrorTexture)
+			{
+				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!");
+				}
+			}
+		}
 
-			// 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) );
+		return true;
+	}
 
-			if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
+	void VRImplOVRGL::destroySwapChain()
+	{
+		for (int eye = 0; eye < 2; ++eye)
+		{
+			if (NULL != m_textureSwapChain[eye])
 			{
-				GL_CHECK(glDeleteFramebuffers(1, &m_mirrorFBO) );
-				BX_CHECK(false, "Could not initialize VR buffers!");
+				GL_CHECK(glDeleteFramebuffers(1, &m_eyeFbo[eye]));
+				GL_CHECK(glDeleteTextures(1, &m_depthBuffer[eye]));
+
+				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 OVRRenderGL::startEyeRender(const ovrSession& _session, int _eyeIdx)
+	void VRImplOVRGL::destroyMirror()
 	{
-		// 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
+		if (NULL != m_mirrorTexture)
 		{
-			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(glDeleteFramebuffers(1, &m_mirrorFbo));
+			ovr_DestroyMirrorTexture(m_session, m_mirrorTexture);
+			m_mirrorTexture = NULL;
 		}
-		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)
+	void VRImplOVRGL::renderEyeStart(const VRDesc& _desc, uint8_t _eye)
 	{
-		if (0 != m_msaaEyeFbo[_eyeIdx] && 0 != m_eyeTexId[_eyeIdx])
+		// set the current eye texture in the swap chain
+		if (0 != m_msaaEyeFbo[_eye])
 		{
-			// 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, m_msaaEyeFbo[_eye]));
+		}
+		else
+		{
+			int texIndex;
+			ovr_GetTextureSwapChainCurrentIndex(m_session, m_textureSwapChain[_eye], &texIndex);
 
-			GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, 0) );
+			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));
 	}
 
-	void OVRRenderGL::destroy(const ovrSession& _session)
+	bool VRImplOVRGL::submitSwapChain(const VRDesc& _desc)
 	{
 		for (int eye = 0; eye < 2; ++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;
-
 			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);
 
-			if (0 != m_msaaEyeTexId[eye])
-			{
-				GL_CHECK(glDeleteTextures(1, &m_msaaEyeTexId[eye]));
-				m_msaaEyeTexId[eye] = 0;
+				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_msaaDepthBuffer[eye])
+			ovrResult result = ovr_CommitTextureSwapChain(m_session, m_textureSwapChain[eye]);
+			if (!OVR_SUCCESS(result))
 			{
-				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;
 		}
-	}
 
-	void OVRRenderGL::blitMirror(const ovrSession& /*_session*/)
-	{
-		if (NULL != m_mirrorTexture)
+		if (result != ovrSuccess_NotVisible && 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) );
+			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));
 		}
-	}
 
-	void OVRRenderGL::preReset(const ovrSession& _session)
-	{
-		if (NULL != m_mirrorTexture)
-		{
-			GL_CHECK(glDeleteFramebuffers(1, &m_mirrorFBO) );
-			ovr_DestroyMirrorTexture(_session, m_mirrorTexture);
-			m_mirrorTexture = NULL;
-		}
+		return true;
 	}
+
 #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
 						{

+ 1 - 23
src/renderer_gl.h

@@ -107,7 +107,7 @@ typedef uint64_t GLuint64;
 #endif // BGFX_CONFIG_RENDERER_OPENGL
 
 #include "renderer.h"
-#include "hmd_ovr.h"
+#include "hmd.h"
 #include "hmd_openvr.h"
 #include "debug_renderdoc.h"
 
@@ -950,28 +950,6 @@ namespace bgfx
 
 namespace bgfx { namespace gl
 {
-#if BGFX_CONFIG_USE_OVR
-	struct OVRRenderGL : public OVRRenderI
-	{
-		OVRRenderGL();
-		virtual void create(const ovrSession& _session, int _msaaSamples, int _mirrorWidth, int _mirrorHeight);
-		virtual void destroy(const ovrSession& _session);
-		virtual void preReset(const ovrSession& _session);
-		virtual void startEyeRender(const ovrSession& _session, int _eyeIdx);
-		virtual void postRender(const ovrSession& _session, int _eyeIdx);
-		virtual void blitMirror(const ovrSession& _session);
-
-		GLuint m_eyeFbo[2];
-		GLuint m_eyeTexId[2];
-		GLuint m_depthBuffer[2];
-		GLuint m_msaaEyeFbo[2];
-		GLuint m_msaaEyeTexId[2];
-		GLuint m_msaaDepthBuffer[2];
-		GLuint m_mirrorFBO;
-	};
-
-#endif // BGFX_CONFIG_USE_OVR
-
 	void dumpExtensions(const char* _extensions);
 
 	const char* glEnumName(GLenum _enum);