Parcourir la source

Merge pull request #920 from mendsley/vr_reorg

Add a new platform agnostic bgfx::VR internal class
Branimir Karadžić il y a 9 ans
Parent
commit
7fdbda0430
8 fichiers modifiés avec 814 ajouts et 668 suppressions
  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
  * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
  */
  */
 
 
-#include "hmd_ovr.h"
+#include "bgfx_p.h"
 
 
 #if BGFX_CONFIG_USE_OVR
 #if BGFX_CONFIG_USE_OVR
 
 
+#include "hmd_ovr.h"
+
 namespace bgfx
 namespace bgfx
 {
 {
 #define _OVR_CHECK(_call) \
 #define _OVR_CHECK(_call) \
@@ -21,236 +23,159 @@ namespace bgfx
 #	define OVR_CHECK(_call) _call
 #	define OVR_CHECK(_call) _call
 #endif // BGFX_CONFIG_DEBUG
 #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;
 		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;
 			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
 } // namespace bgfx

+ 27 - 145
src/hmd_ovr.h

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

+ 169 - 123
src/renderer_d3d11.cpp

@@ -29,6 +29,10 @@
 #	define BGFX_GPU_PROFILER_END() BX_NOOP()
 #	define BGFX_GPU_PROFILER_END() BX_NOOP()
 #endif
 #endif
 
 
+#if BGFX_CONFIG_USE_OVR
+#	include "hmd_ovr.h"
+#endif // BGFX_CONFIG_USE_OVR
+
 namespace bgfx { namespace d3d11
 namespace bgfx { namespace d3d11
 {
 {
 	static wchar_t s_viewNameW[BGFX_CONFIG_MAX_VIEWS][BGFX_CONFIG_MAX_VIEW_NAME];
 	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;
 	static PFN_GET_DEBUG_INTERFACE1 DXGIGetDebugInterface1;
 #endif // USE_D3D11_DYNAMIC_LIB
 #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
 	struct RendererContextD3D11 : public RendererContextI
 	{
 	{
 		RendererContextD3D11()
 		RendererContextD3D11()
@@ -662,7 +690,11 @@ namespace bgfx { namespace d3d11
 			ErrorState::Enum errorState = ErrorState::Default;
 			ErrorState::Enum errorState = ErrorState::Default;
 
 
 			// Must be before device creation, and before RenderDoc.
 			// 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() )
 			if (!m_ovr.isInitialized() )
 			{
 			{
@@ -2226,18 +2258,12 @@ BX_PRAGMA_DIAGNOSTIC_POP();
 
 
 				if (SUCCEEDED(hr) )
 				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);
 						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 BGFX_CONFIG_USE_OVR
 			if (m_resolution.m_flags & (BGFX_RESET_HMD|BGFX_RESET_HMD_DEBUG) )
 			if (m_resolution.m_flags & (BGFX_RESET_HMD|BGFX_RESET_HMD_DEBUG) )
 			{
 			{
-				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
 #endif // BGFX_CONFIG_USE_OVR
 		}
 		}
@@ -3553,9 +3574,9 @@ BX_PRAGMA_DIAGNOSTIC_POP();
 		bool m_rtMsaa;
 		bool m_rtMsaa;
 		bool m_timerQuerySupport;
 		bool m_timerQuerySupport;
 
 
-		OVR m_ovr;
+		VR m_ovr;
 #if BGFX_CONFIG_USE_OVR
 #if BGFX_CONFIG_USE_OVR
-		OVRRenderD3D11 m_ovrRender;
+		VRImplOVRD3D11 m_ovrRender;
 #endif // BGFX_CONFIG_USE_OVR
 #endif // BGFX_CONFIG_USE_OVR
 	};
 	};
 
 
@@ -3610,62 +3631,66 @@ BX_PRAGMA_DIAGNOSTIC_POP();
 	}
 	}
 
 
 #if BGFX_CONFIG_USE_OVR
 #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)
 		for (int eye = 0; eye < 2; ++eye)
 		{
 		{
 			if (NULL == m_textureSwapChain[eye])
 			if (NULL == m_textureSwapChain[eye])
 			{
 			{
-				m_eyeTextureSize[eye] = ovr_GetFovTextureSize(_session, (ovrEyeType)eye, hmdDesc.DefaultEyeFov[eye], 1.0f);
 				m_msaaTexture[eye] = NULL;
 				m_msaaTexture[eye] = NULL;
 				m_msaaRtv[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)
 				for (int ii = 0; ii < textureCount; ++ii)
 				{
 				{
 					ID3D11Texture2D* tex = NULL;
 					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 = {};
 					D3D11_RENDER_TARGET_VIEW_DESC rtvd = {};
 					rtvd.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
 					rtvd.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
 					rtvd.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
 					rtvd.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
 
 
 					ID3D11RenderTargetView* rtv;
 					ID3D11RenderTargetView* rtv;
-					DX_CHECK(device->CreateRenderTargetView(tex, &rtvd, &rtv) );
+					DX_CHECK(device->CreateRenderTargetView(tex, &rtvd, &rtv));
 					m_eyeRtv[eye][ii] = rtv;
 					m_eyeRtv[eye][ii] = rtv;
 					DX_RELEASE(tex, 1);
 					DX_RELEASE(tex, 1);
 				}
 				}
 
 
 				// setup depth buffer
 				// setup depth buffer
 				D3D11_TEXTURE2D_DESC dbDesc;
 				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.MipLevels = 1;
 				dbDesc.ArraySize = 1;
 				dbDesc.ArraySize = 1;
 				dbDesc.Format = DXGI_FORMAT_D32_FLOAT;
 				dbDesc.Format = DXGI_FORMAT_D32_FLOAT;
@@ -3676,16 +3701,16 @@ BX_PRAGMA_DIAGNOSTIC_POP();
 				dbDesc.MiscFlags = 0;
 				dbDesc.MiscFlags = 0;
 				dbDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
 				dbDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
 				ID3D11Texture2D* tex;
 				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);
 				DX_RELEASE(tex, 0);
 
 
 				// create MSAA render target
 				// create MSAA render target
 				if (_msaaSamples > 1)
 				if (_msaaSamples > 1)
 				{
 				{
 					D3D11_TEXTURE2D_DESC dsDesc;
 					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.MipLevels = 1;
 					dsDesc.ArraySize = 1;
 					dsDesc.ArraySize = 1;
 					dsDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
 					dsDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
@@ -3696,7 +3721,6 @@ BX_PRAGMA_DIAGNOSTIC_POP();
 					dsDesc.MiscFlags = 0;
 					dsDesc.MiscFlags = 0;
 					dsDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
 					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->CreateTexture2D(&dsDesc, NULL, &m_msaaTexture[eye]));
 					DX_CHECK(device->CreateShaderResourceView(m_msaaTexture[eye], NULL, &m_msaaSv[eye]));
 					DX_CHECK(device->CreateShaderResourceView(m_msaaTexture[eye], NULL, &m_msaaSv[eye]));
 					DX_CHECK(device->CreateRenderTargetView(m_msaaTexture[eye], NULL, &m_msaaRtv[eye]));
 					DX_CHECK(device->CreateRenderTargetView(m_msaaTexture[eye], NULL, &m_msaaRtv[eye]));
@@ -3706,124 +3730,147 @@ BX_PRAGMA_DIAGNOSTIC_POP();
 
 
 		if (NULL == m_mirrorTexture)
 		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_WARN(OVR_SUCCESS(result), "Could not create D3D11 OVR mirror texture");
 			BX_UNUSED(result);
 			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;
 		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
 		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
 		// 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
 		else // MSAA disabled? render directly to eye buffer
 		{
 		{
 			int texIndex = 0;
 			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;
 			D3D11_VIEWPORT D3Dvp;
 			D3Dvp.TopLeftX = 0;
 			D3Dvp.TopLeftX = 0;
 			D3Dvp.TopLeftY = 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.MinDepth = 0;
 			D3Dvp.MaxDepth = 1;
 			D3Dvp.MaxDepth = 1;
 			deviceCtx->RSSetViewports(1, &D3Dvp);
 			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 (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])
 			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;
 			ID3D11Texture2D* tex = NULL;
-			ovr_GetMirrorTextureBufferDX(_session, m_mirrorTexture, IID_PPV_ARGS(&tex) );
+			ovr_GetMirrorTextureBufferDX(m_session, m_mirrorTexture, IID_PPV_ARGS(&tex));
 			ID3D11Texture2D* backBuffer;
 			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(tex, 1);
 			DX_RELEASE(backBuffer, 0);
 			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
 #endif // BGFX_CONFIG_USE_OVR
@@ -5307,8 +5354,7 @@ BX_PRAGMA_DIAGNOSTIC_POP();
 
 
 						if (m_ovr.isEnabled() )
 						if (m_ovr.isEnabled() )
 						{
 						{
-							m_ovr.getViewport(eye, &viewState.m_rect);
-							m_ovr.renderEyeStart(eye);
+							m_ovr.renderEyeStart(eye, &viewState.m_rect);
 						}
 						}
 						else
 						else
 						{
 						{

+ 1 - 20
src/renderer_d3d11.h

@@ -32,7 +32,7 @@ BX_PRAGMA_DIAGNOSTIC_POP()
 #include "renderer.h"
 #include "renderer.h"
 #include "renderer_d3d.h"
 #include "renderer_d3d.h"
 #include "shader_dxbc.h"
 #include "shader_dxbc.h"
-#include "hmd_ovr.h"
+#include "hmd.h"
 #include "hmd_openvr.h"
 #include "hmd_openvr.h"
 #include "debug_renderdoc.h"
 #include "debug_renderdoc.h"
 
 
@@ -60,25 +60,6 @@ BX_PRAGMA_DIAGNOSTIC_POP()
 
 
 namespace bgfx { namespace d3d11
 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
 	struct BufferD3D11
 	{
 	{
 		BufferD3D11()
 		BufferD3D11()

+ 206 - 179
src/renderer_gl.cpp

@@ -9,6 +9,7 @@
 #	include "renderer_gl.h"
 #	include "renderer_gl.h"
 #	include <bx/timer.h>
 #	include <bx/timer.h>
 #	include <bx/uint32_t.h>
 #	include <bx/uint32_t.h>
+#	include "hmd_ovr.h"
 
 
 #if BGFX_CONFIG_PROFILER_REMOTERY
 #if BGFX_CONFIG_PROFILER_REMOTERY
 #	define BGFX_GPU_PROFILER_BIND() rmt_BindOpenGL()
 #	define BGFX_GPU_PROFILER_BIND() rmt_BindOpenGL()
@@ -1352,6 +1353,34 @@ namespace bgfx { namespace gl
 		BX_UNUSED(supported);
 		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
 	struct RendererContextGL : public RendererContextI
 	{
 	{
 		RendererContextGL()
 		RendererContextGL()
@@ -1401,7 +1430,11 @@ namespace bgfx { namespace gl
 			setRenderContextSize(BGFX_DEFAULT_WIDTH, BGFX_DEFAULT_HEIGHT);
 			setRenderContextSize(BGFX_DEFAULT_WIDTH, BGFX_DEFAULT_HEIGHT);
 
 
 			// Must be after context is initialized?!
 			// 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_vendor      = getGLString(GL_VENDOR);
 			m_renderer    = getGLString(GL_RENDERER);
 			m_renderer    = getGLString(GL_RENDERER);
@@ -2205,15 +2238,8 @@ namespace bgfx { namespace gl
 					m_glctx.swap(m_frameBuffers[m_windows[ii].idx].m_swapChain);
 					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
 				// need to swap GL render context even if OVR is enabled to get the mirror texture in the output
 				m_glctx.swap();
 				m_glctx.swap();
@@ -2957,13 +2983,8 @@ namespace bgfx { namespace gl
 #if BGFX_CONFIG_USE_OVR
 #if BGFX_CONFIG_USE_OVR
 			if (m_resolution.m_flags & (BGFX_RESET_HMD|BGFX_RESET_HMD_DEBUG) )
 			if (m_resolution.m_flags & (BGFX_RESET_HMD|BGFX_RESET_HMD_DEBUG) )
 			{
 			{
-				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
 #endif // BGFX_CONFIG_USE_OVR
 		}
 		}
@@ -3394,9 +3415,9 @@ namespace bgfx { namespace gl
 		const char* m_version;
 		const char* m_version;
 		const char* m_glslVersion;
 		const char* m_glslVersion;
 
 
-		OVR m_ovr;
+		VR m_ovr;
 #if BGFX_CONFIG_USE_OVR
 #if BGFX_CONFIG_USE_OVR
-		OVRRenderGL m_ovrRender;
+		VRImplOVRGL m_ovrRender;
 #endif // BGFX_CONFIG_USE_OVR
 #endif // BGFX_CONFIG_USE_OVR
 	};
 	};
 
 
@@ -3417,238 +3438,245 @@ namespace bgfx { namespace gl
 	}
 	}
 
 
 #if BGFX_CONFIG_USE_OVR
 #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)
 		for (int eye = 0; eye < 2; ++eye)
 		{
 		{
 			if (NULL == m_textureSwapChain[eye])
 			if (NULL == m_textureSwapChain[eye])
 			{
 			{
 				m_eyeFbo[eye] = 0;
 				m_eyeFbo[eye] = 0;
-				m_eyeTexId[eye] = 0;
 				m_depthBuffer[eye] = 0;
 				m_depthBuffer[eye] = 0;
 				m_msaaEyeFbo[eye] = 0;
 				m_msaaEyeFbo[eye] = 0;
 				m_msaaEyeTexId[eye] = 0;
 				m_msaaEyeTexId[eye] = 0;
 				m_msaaDepthBuffer[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;
 				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
 				// 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)
 				if (_msaaSamples > 1)
 				{
 				{
-					GL_CHECK(glGenFramebuffers(1, &m_msaaEyeFbo[eye]) );
+					GL_CHECK(glGenFramebuffers(1, &m_msaaEyeFbo[eye]));
 
 
 					// create color MSAA texture
 					// 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
 					// 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)
 		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
 			// 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)
 		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])
 			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
 #endif // BGFX_CONFIG_USE_OVR
 
 
 	const char* glslTypeName(GLuint _type)
 	const char* glslTypeName(GLuint _type)
@@ -6183,8 +6211,7 @@ namespace bgfx { namespace gl
 
 
 						if (m_ovr.isEnabled() )
 						if (m_ovr.isEnabled() )
 						{
 						{
-							m_ovr.getViewport(eye, &viewState.m_rect);
-							m_ovr.renderEyeStart(eye);
+							m_ovr.renderEyeStart(eye, &viewState.m_rect);
 						}
 						}
 						else
 						else
 						{
 						{

+ 1 - 23
src/renderer_gl.h

@@ -107,7 +107,7 @@ typedef uint64_t GLuint64;
 #endif // BGFX_CONFIG_RENDERER_OPENGL
 #endif // BGFX_CONFIG_RENDERER_OPENGL
 
 
 #include "renderer.h"
 #include "renderer.h"
-#include "hmd_ovr.h"
+#include "hmd.h"
 #include "hmd_openvr.h"
 #include "hmd_openvr.h"
 #include "debug_renderdoc.h"
 #include "debug_renderdoc.h"
 
 
@@ -950,28 +950,6 @@ namespace bgfx
 
 
 namespace bgfx { namespace gl
 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);
 	void dumpExtensions(const char* _extensions);
 
 
 	const char* glEnumName(GLenum _enum);
 	const char* glEnumName(GLenum _enum);