Procházet zdrojové kódy

Use a single render target for VR rendering (#977)

This allows the game to render to a single FB and
pass that into existing post process pipeline.
Matthew Endsley před 9 roky
rodič
revize
e090bb9851
6 změnil soubory, kde provedl 371 přidání a 322 odebrání
  1. 13 7
      src/hmd.cpp
  2. 3 2
      src/hmd.h
  3. 10 7
      src/hmd_ovr.cpp
  4. 1 1
      src/hmd_ovr.h
  5. 157 151
      src/renderer_d3d11.cpp
  6. 187 154
      src/renderer_gl.cpp

+ 13 - 7
src/hmd.cpp

@@ -58,16 +58,22 @@ namespace bgfx
 		m_enabled = false;
 	}
 
-	void VR::renderEyeStart(uint8_t _eye, Rect* _viewport)
+	void VR::getViewport(uint8_t _eye, Rect* _viewport) const
 	{
-		BX_CHECK(m_enabled, "VR::renderEyeStart called while not enabled - render usage error");
+		_viewport->m_width = m_desc.m_eyeSize[_eye].m_w;
+		_viewport->m_x = _eye * (m_desc.m_eyeSize[_eye].m_w + 1);
+		_viewport->m_height = (uint16_t)m_desc.m_eyeSize[_eye].m_h;
+		_viewport->m_y = 0;
+	}
 
-		_viewport->m_x      = 0;
-		_viewport->m_y      = 0;
-		_viewport->m_width  = uint16_t(m_desc.m_eyeSize[_eye].m_w);
-		_viewport->m_height = uint16_t(m_desc.m_eyeSize[_eye].m_h);
+	void VR::makeRenderTargetActive()
+	{
+		BX_CHECK(m_enabled, "VR::renderEyeStart called while not enabled - render usage error");
 
-		m_impl->renderEyeStart(m_desc, _eye);
+		if (NULL != m_impl)
+		{
+			m_impl->makeRenderTargetActive(m_desc);
+		}
 	}
 
 	void VR::recenter()

+ 3 - 2
src/hmd.h

@@ -51,7 +51,7 @@ namespace bgfx
 		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 void makeRenderTargetActive(const VRDesc& _desc) = 0;
 		virtual bool submitSwapChain(const VRDesc& _desc) = 0;
 	};
 
@@ -77,7 +77,8 @@ namespace bgfx
 			return m_enabled;
 		}
 
-		void renderEyeStart(uint8_t _eye, Rect* _viewport);
+		void getViewport(uint8_t _eye, Rect* _viewport) const;
+		void makeRenderTargetActive();
 		void recenter();
 
 		void preReset();

+ 10 - 7
src/hmd_ovr.cpp

@@ -117,13 +117,16 @@ namespace bgfx
 		// build constant layer settings
 		m_renderLayer.Header.Type = ovrLayerType_EyeFov;
 		m_renderLayer.Header.Flags = 0;
-		for (int eye = 0; eye < 2; ++eye)
-		{
-			m_renderLayer.Fov[eye] = hmdDesc.DefaultEyeFov[eye];
-			m_renderLayer.Viewport[eye].Pos.x = 0;
-			m_renderLayer.Viewport[eye].Pos.y = 0;
-			m_renderLayer.Viewport[eye].Size = eyeSize[eye];
-		}
+		m_renderLayer.Fov[0] = hmdDesc.DefaultEyeFov[0];
+		m_renderLayer.Fov[1] = hmdDesc.DefaultEyeFov[1];
+		m_renderLayer.Viewport[0].Pos.x = 0;
+		m_renderLayer.Viewport[0].Pos.y = 0;
+		m_renderLayer.Viewport[0].Size.w = _desc->m_eyeSize[0].m_w;
+		m_renderLayer.Viewport[0].Size.h = _desc->m_eyeSize[0].m_h;
+		m_renderLayer.Viewport[1].Pos.x = _desc->m_eyeSize[0].m_w+1;
+		m_renderLayer.Viewport[1].Pos.y = 0;
+		m_renderLayer.Viewport[1].Size.w = _desc->m_eyeSize[1].m_w;
+		m_renderLayer.Viewport[1].Size.h = _desc->m_eyeSize[1].m_h;
 
 		m_viewScale.HmdSpaceToWorldScaleInMeters = 1.0f;
 		for (int eye = 0; eye < 2; ++eye)

+ 1 - 1
src/hmd_ovr.h

@@ -52,7 +52,7 @@ namespace bgfx
 		virtual bool createSwapChain(const VRDesc& _desc, int _msaaSamples, int _mirrorWidth, int _mirrorHeight) BX_OVERRIDE = 0;
 		virtual void destroySwapChain() BX_OVERRIDE = 0;
 		virtual void destroyMirror() BX_OVERRIDE = 0;
-		virtual void renderEyeStart(const VRDesc& _desc, uint8_t _eye) BX_OVERRIDE = 0;
+		virtual void makeRenderTargetActive(const VRDesc& _desc) BX_OVERRIDE = 0;
 		virtual bool submitSwapChain(const VRDesc& _desc) BX_OVERRIDE = 0;
 
 	protected:

+ 157 - 151
src/renderer_d3d11.cpp

@@ -625,17 +625,16 @@ namespace bgfx { namespace d3d11
 		virtual bool createSwapChain(const VRDesc& _desc, int _msaaSamples, int _mirrorWidth, int _mirrorHeight) BX_OVERRIDE;
 		virtual void destroySwapChain() BX_OVERRIDE;
 		virtual void destroyMirror() BX_OVERRIDE;
-		virtual void renderEyeStart(const VRDesc& _desc, uint8_t _eye) BX_OVERRIDE;
+		virtual void makeRenderTargetActive(const VRDesc& _desc) BX_OVERRIDE;
 		virtual bool submitSwapChain(const VRDesc& _desc) BX_OVERRIDE;
 
 	private:
-		ID3D11RenderTargetView* m_eyeRtv[2][4];
-		ID3D11DepthStencilView* m_depthBuffer[2];
-		ID3D11Texture2D* m_msaaTexture[2];
-		ID3D11ShaderResourceView* m_msaaSv[2];
-		ID3D11RenderTargetView* m_msaaRtv[2];
+		ID3D11DepthStencilView* m_depthBuffer;
+		ID3D11RenderTargetView* m_eyeRtv[4];
+		ID3D11RenderTargetView* m_msaaRtv;
+		ID3D11Texture2D* m_msaaTexture;
 
-		ovrTextureSwapChain m_textureSwapChain[2];
+		ovrTextureSwapChain m_textureSwapChain;
 		ovrMirrorTexture m_mirrorTexture;
 	};
 #endif // BGFX_CONFIG_USE_OVR
@@ -2233,7 +2232,14 @@ BX_PRAGMA_DIAGNOSTIC_POP();
 				DX_RELEASE(depthStencil, 0);
 			}
 
-			m_deviceCtx->OMSetRenderTargets(1, &m_backBufferColor, m_backBufferDepthStencil);
+			if (m_ovr.isEnabled() )
+			{
+				m_ovr.makeRenderTargetActive();
+			}
+			else
+			{
+				m_deviceCtx->OMSetRenderTargets(1, &m_backBufferColor, m_backBufferDepthStencil);
+			}
 
 			m_currentColor = m_backBufferColor;
 			m_currentDepthStencil = m_backBufferDepthStencil;
@@ -2575,11 +2581,18 @@ BX_PRAGMA_DIAGNOSTIC_POP();
 
 			if (!isValid(_fbh) )
 			{
-				m_deviceCtx->OMSetRenderTargets(1, &m_backBufferColor, m_backBufferDepthStencil);
+				if (m_ovr.isEnabled() )
+				{
+					m_ovr.makeRenderTargetActive();
+				}
+				else
+				{
+					m_currentColor = m_backBufferColor;
+					m_currentDepthStencil = m_backBufferDepthStencil;
+				}
 
+				m_deviceCtx->OMSetRenderTargets(1, &m_currentColor, m_currentDepthStencil);
 				m_needPresent |= _needPresent;
-				m_currentColor = m_backBufferColor;
-				m_currentDepthStencil = m_backBufferDepthStencil;
 			}
 			else
 			{
@@ -3651,99 +3664,109 @@ BX_PRAGMA_DIAGNOSTIC_POP();
 #if BGFX_CONFIG_USE_OVR
 
 	VRImplOVRD3D11::VRImplOVRD3D11()
-		: m_mirrorTexture(NULL)
+		: m_depthBuffer(NULL)
+		, m_msaaRtv(NULL)
+		, m_msaaTexture(NULL)
+		, m_textureSwapChain(NULL)
+		, m_mirrorTexture(NULL)
 	{
-		memset(m_textureSwapChain, 0, sizeof(m_textureSwapChain));
+		memset(m_eyeRtv, 0, sizeof(m_eyeRtv));
 	}
 
 	bool VRImplOVRD3D11::createSwapChain(const VRDesc& _desc, int _msaaSamples, int _mirrorWidth, int _mirrorHeight)
 	{
+		if (!m_session)
+		{
+			return false;
+		}
+
 		ID3D11Device* device = s_renderD3D11->m_device;
 
-		for (int eye = 0; eye < 2; ++eye)
-		{
-			if (NULL == m_textureSwapChain[eye])
+		if (NULL == m_textureSwapChain)
+		{
+			ovrTextureSwapChainDesc swapchainDesc = {};
+			swapchainDesc.Type = ovrTexture_2D;
+			swapchainDesc.Width = _desc.m_eyeSize[0].m_w + _desc.m_eyeSize[1].m_w;
+			swapchainDesc.Height = bx::uint32_max(_desc.m_eyeSize[0].m_h, _desc.m_eyeSize[1].m_h);
+			swapchainDesc.MipLevels = 1;
+			swapchainDesc.ArraySize = 1;
+			swapchainDesc.SampleCount = 1;
+			swapchainDesc.MiscFlags = ovrTextureMisc_DX_Typeless;
+			swapchainDesc.BindFlags = ovrTextureBind_DX_RenderTarget;
+			swapchainDesc.StaticImage = ovrFalse;
+			swapchainDesc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB;
+
+			ovrResult result = ovr_CreateTextureSwapChainDX(m_session, device, &swapchainDesc, &m_textureSwapChain);
+			if (!OVR_SUCCESS(result) )
 			{
-				m_msaaTexture[eye] = NULL;
-				m_msaaRtv[eye] = NULL;
-				m_msaaSv[eye] = NULL;
-
-				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))
-				{
-					destroySwapChain();
-					return false;
-				}
+				return false;
+			}
 
-				memset(m_eyeRtv[eye], 0, sizeof(m_eyeRtv[eye]));
-				int textureCount;
-				ovr_GetTextureSwapChainLength(m_session, m_textureSwapChain[eye], &textureCount);
+			for (int eye = 0; eye < 2; ++eye)
+			{
+				m_renderLayer.ColorTexture[eye] = m_textureSwapChain;
+			}
 
-				for (int ii = 0; ii < textureCount; ++ii)
+			// create MSAA target
+			if (_msaaSamples > 1)
+			{
+				D3D11_TEXTURE2D_DESC msDesc;
+				msDesc.Width = swapchainDesc.Width;
+				msDesc.Height = swapchainDesc.Height;
+				msDesc.MipLevels = 1;
+				msDesc.ArraySize = 1;
+				msDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+				msDesc.SampleDesc.Count = _msaaSamples;
+				msDesc.SampleDesc.Quality = 0;
+				msDesc.Usage = D3D11_USAGE_DEFAULT;
+				msDesc.CPUAccessFlags = 0;
+				msDesc.MiscFlags = 0;
+				msDesc.BindFlags = D3D11_BIND_RENDER_TARGET;
+				DX_CHECK(device->CreateTexture2D(&msDesc, NULL, &m_msaaTexture) );
+				DX_CHECK(device->CreateRenderTargetView(m_msaaTexture, NULL, &m_msaaRtv) );
+			}
+			else
+			{
+				int swapchainSize;
+				result = ovr_GetTextureSwapChainLength(m_session, m_textureSwapChain, &swapchainSize);
+				if (!OVR_SUCCESS(result) )
 				{
-					ID3D11Texture2D* tex = NULL;
-					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));
-					m_eyeRtv[eye][ii] = rtv;
-					DX_RELEASE(tex, 1);
+					destroySwapChain();
+					return false;
 				}
 
-				// setup depth buffer
-				D3D11_TEXTURE2D_DESC dbDesc;
-				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;
-				dbDesc.SampleDesc.Count = _msaaSamples;
-				dbDesc.SampleDesc.Quality = 0;
-				dbDesc.Usage = D3D11_USAGE_DEFAULT;
-				dbDesc.CPUAccessFlags = 0;
-				dbDesc.MiscFlags = 0;
-				dbDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
-				ID3D11Texture2D* tex;
-				DX_CHECK(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)
+				BX_CHECK(swapchainSize <= BX_COUNTOF(m_eyeRtv), "Too many OVR swap chain entries %d", swapchainSize);
+				for (int ii = 0; ii < swapchainSize; ++ii)
 				{
-					D3D11_TEXTURE2D_DESC dsDesc;
-					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;
-					dsDesc.SampleDesc.Count = _msaaSamples;
-					dsDesc.SampleDesc.Quality = 0;
-					dsDesc.Usage = D3D11_USAGE_DEFAULT;
-					dsDesc.CPUAccessFlags = 0;
-					dsDesc.MiscFlags = 0;
-					dsDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
-
-					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]));
+					ID3D11Texture2D* texture;
+					ovr_GetTextureSwapChainBufferDX(m_session, m_textureSwapChain, ii, IID_PPV_ARGS(&texture) );
+
+					D3D11_RENDER_TARGET_VIEW_DESC viewDesc;
+					viewDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+					viewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
+					viewDesc.Texture2D.MipSlice = 0;
+					DX_CHECK(device->CreateRenderTargetView(texture, &viewDesc, &m_eyeRtv[ii]) );
+					DX_RELEASE(texture, 1);
 				}
 			}
+
+			// create depth buffer
+			D3D11_TEXTURE2D_DESC dbDesc = {};
+			dbDesc.Width = swapchainDesc.Width;
+			dbDesc.Height = swapchainDesc.Height;
+			dbDesc.MipLevels = 1;
+			dbDesc.ArraySize = 1;
+			dbDesc.Format = DXGI_FORMAT_D32_FLOAT;
+			dbDesc.SampleDesc.Count = _msaaSamples;
+			dbDesc.SampleDesc.Quality = 0;
+			dbDesc.Usage = D3D11_USAGE_DEFAULT;
+			dbDesc.CPUAccessFlags = 0;
+			dbDesc.MiscFlags = 0;
+			dbDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
+			ID3D11Texture2D* depthTexture;
+			DX_CHECK(device->CreateTexture2D(&dbDesc, NULL, &depthTexture) );
+			DX_CHECK(device->CreateDepthStencilView(depthTexture, NULL, &m_depthBuffer) );
+			DX_RELEASE(depthTexture, 0);
 		}
 
 		if (NULL == m_mirrorTexture)
@@ -3757,46 +3780,27 @@ BX_PRAGMA_DIAGNOSTIC_POP();
 			BX_UNUSED(result);
 		}
 
-		m_renderLayer.ColorTexture[0] = m_textureSwapChain[0];
-		m_renderLayer.ColorTexture[1] = m_textureSwapChain[1];
 		return true;
 	}
 
 	void VRImplOVRD3D11::destroySwapChain()
 	{
-		for (int eye = 0; eye < 2; ++eye)
+		if (NULL != m_textureSwapChain)
 		{
-			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;
-				}
+			BX_CHECK(m_session, "VRSWapChain destroyed without valid OVR session");
+			ovr_DestroyTextureSwapChain(m_session, m_textureSwapChain);
+			m_textureSwapChain = NULL;
+		}
 
-				if (NULL != m_msaaRtv[eye])
-				{
-					m_msaaRtv[eye]->Release();
-					m_msaaRtv[eye] = NULL;
-				}
-			}
+		for (int ii = 0, nn = BX_COUNTOF(m_eyeRtv); ii < nn; ++ii)
+		{
+			DX_RELEASE(m_eyeRtv[ii], 0);
 		}
 
+		DX_RELEASE(m_msaaRtv, 0);
+		DX_RELEASE(m_msaaTexture, 0);
+		DX_RELEASE(m_depthBuffer, 0);
+
 		destroyMirror();
 	}
 
@@ -3809,59 +3813,60 @@ BX_PRAGMA_DIAGNOSTIC_POP();
 		}
 	}
 
-	void VRImplOVRD3D11::renderEyeStart(const VRDesc& _desc, uint8_t _eye)
+	void VRImplOVRD3D11::makeRenderTargetActive(const VRDesc& /*_desc*/)
 	{
-		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[_eye])
+		if (NULL != m_msaaRtv)
 		{
-			deviceCtx->OMSetRenderTargets(1, &m_msaaRtv[_eye], m_depthBuffer[_eye]);
+			s_renderD3D11->m_currentColor = m_msaaRtv;
 		}
-		else // MSAA disabled? render directly to eye buffer
+		else
 		{
-			int texIndex = 0;
-			ovr_GetTextureSwapChainCurrentIndex(m_session, m_textureSwapChain[_eye], &texIndex);
-			deviceCtx->OMSetRenderTargets(1, &m_eyeRtv[_eye][texIndex], m_depthBuffer[_eye]);
+			int index;
+			ovr_GetTextureSwapChainCurrentIndex(m_session, m_textureSwapChain, &index);
+			s_renderD3D11->m_currentColor = m_eyeRtv[index];
 		}
+
+		s_renderD3D11->m_currentDepthStencil = m_depthBuffer;
 	}
 
 	bool VRImplOVRD3D11::submitSwapChain(const VRDesc& /* _desc */)
 	{
+		BX_CHECK(NULL != m_session, "No session in VRImplOVRD3D11::submitSwapChain. Usage error");
+		BX_CHECK(NULL != m_textureSwapChain, "VRImplOVRD3D11 submitted without a valid swap chain");
+
 		ID3D11DeviceContext* deviceCtx = s_renderD3D11->m_deviceCtx;
-		IDXGISwapChain* swapChain = s_renderD3D11->m_swapChain;
 
-		// resolve MSAA render targets
-		for (int eye = 0; eye < 2; ++eye)
-		{
-			if (NULL != m_msaaTexture[eye])
-			{
-				int destIndex = 0;
-				ovr_GetTextureSwapChainCurrentIndex(m_session, m_textureSwapChain[eye], &destIndex);
+		int index;
+		ovr_GetTextureSwapChainCurrentIndex(m_session, m_textureSwapChain, &index);
 
-				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();
-			}
+		ID3D11Texture2D* eyeTexture;
+		ovr_GetTextureSwapChainBufferDX(m_session, m_textureSwapChain, index, IID_PPV_ARGS(&eyeTexture));
 
-			ovrResult result = ovr_CommitTextureSwapChain(m_session, m_textureSwapChain[eye]);
-			if (!OVR_SUCCESS(result))
-			{
-				return false;
-			}
+		// resolve MSAA
+		if (NULL != m_msaaRtv)
+		{
+			deviceCtx->ResolveSubresource(eyeTexture, 0, m_msaaTexture, 0, DXGI_FORMAT_R8G8B8A8_UNORM);
+		}
+
+		ovrResult result = ovr_CommitTextureSwapChain(m_session, m_textureSwapChain);
+		if (!OVR_SUCCESS(result) )
+		{
+			return false;
+			DX_RELEASE(eyeTexture, 1);
 		}
 
 		ovrLayerHeader* layerList = &m_renderLayer.Header;
-		ovrResult result = ovr_SubmitFrame(m_session, 0, NULL, &layerList, 1);
-		if (!OVR_SUCCESS(result))
+		result = ovr_SubmitFrame(m_session, 0, NULL, &layerList, 1);
+		if (!OVR_SUCCESS(result) )
 		{
+			DX_RELEASE(eyeTexture, 1);
 			return false;
 		}
 
 		if (result != ovrSuccess_NotVisible && NULL != m_mirrorTexture)
 		{
+			IDXGISwapChain* swapChain = s_renderD3D11->m_swapChain;
+
 			ID3D11Texture2D* tex = NULL;
 			ovr_GetMirrorTextureBufferDX(m_session, m_mirrorTexture, IID_PPV_ARGS(&tex));
 			ID3D11Texture2D* backBuffer;
@@ -3874,6 +3879,7 @@ BX_PRAGMA_DIAGNOSTIC_POP();
 			DX_RELEASE(backBuffer, 0);
 		}
 
+		DX_RELEASE(eyeTexture, 1);
 		return true;
 	}
 
@@ -5383,7 +5389,7 @@ BX_PRAGMA_DIAGNOSTIC_POP();
 
 						if (m_ovr.isEnabled() )
 						{
-							m_ovr.renderEyeStart(eye, &viewState.m_rect);
+							m_ovr.getViewport(eye, &viewState.m_rect);
 						}
 						else
 						{

+ 187 - 154
src/renderer_gl.cpp

@@ -1376,21 +1376,19 @@ namespace bgfx { namespace gl
 		virtual bool createSwapChain(const VRDesc& _desc, int _msaaSamples, int _mirrorWidth, int _mirrorHeight) BX_OVERRIDE;
 		virtual void destroySwapChain() BX_OVERRIDE;
 		virtual void destroyMirror() BX_OVERRIDE;
-		virtual void renderEyeStart(const VRDesc& _desc, uint8_t _eye) BX_OVERRIDE;
+		virtual void makeRenderTargetActive(const VRDesc& _desc) BX_OVERRIDE;
 		virtual bool submitSwapChain(const VRDesc& _desc) BX_OVERRIDE;
 
 	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_eyeTarget[4];
+		GLuint m_depthRbo;
+		GLuint m_msaaTexture;
+		GLuint m_msaaTarget;
 		GLuint m_mirrorFbo;
 		GLint m_mirrorWidth;
 		GLint m_mirrorHeight;
 
-		ovrTextureSwapChain m_textureSwapChain[2];
+		ovrTextureSwapChain m_textureSwapChain;
 		ovrMirrorTexture m_mirrorTexture;
 	};
 #endif // BGFX_CONFIG_USE_OVR
@@ -2708,6 +2706,17 @@ namespace bgfx { namespace gl
 
 				ovrPreReset();
 				ovrPostReset();
+
+				if (m_ovr.isEnabled() )
+				{
+					m_ovr.makeRenderTargetActive();
+				}
+				else
+				{
+					m_currentFbo = 0;
+				}
+
+				GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_currentFbo) );
 			}
 
 			if (recenter)
@@ -2753,7 +2762,15 @@ namespace bgfx { namespace gl
 			if (!isValid(_fbh) )
 			{
 				m_needPresent |= true;
-				GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_msaaBackBufferFbo) );
+
+				if (m_ovr.isEnabled() )
+				{
+					m_ovr.makeRenderTargetActive();
+				}
+				else
+				{
+					m_currentFbo = m_msaaBackBufferFbo;
+				}
 
 				if (m_srgbWriteControlSupport)
 				{
@@ -2775,14 +2792,17 @@ namespace bgfx { namespace gl
 				{
 					m_glctx.makeCurrent(frameBuffer.m_swapChain);
 					frameBuffer.m_needPresent = true;
+					m_currentFbo = 0;
 				}
 				else
 				{
 					m_glctx.makeCurrent(NULL);
-					GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer.m_fbo[0]) );
+					m_currentFbo = frameBuffer.m_fbo[0];
 				}
 			}
 
+			GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_currentFbo) );
+
 			m_fbh       = _fbh;
 			m_fbDiscard = _discard;
 			m_rtMsaa    = _msaa;
@@ -3472,6 +3492,8 @@ namespace bgfx { namespace gl
 		const char* m_version;
 		const char* m_glslVersion;
 
+		GLuint m_currentFbo;
+
 		VR m_ovr;
 #if BGFX_CONFIG_USE_OVR
 		VRImplOVRGL m_ovrRender;
@@ -3494,12 +3516,27 @@ namespace bgfx { namespace gl
 		s_renderGL = NULL;
 	}
 
+	static void frameBufferValidate()
+	{
+		GLenum complete = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+		BX_CHECK(GL_FRAMEBUFFER_COMPLETE == complete
+			, "glCheckFramebufferStatus failed 0x%08x: %s"
+			, complete
+			, glEnumName(complete)
+		);
+		BX_UNUSED(complete);
+	}
+
 #if BGFX_CONFIG_USE_OVR
 
 	VRImplOVRGL::VRImplOVRGL()
-		: m_mirrorTexture(NULL)
+		: m_depthRbo(0)
+		, m_msaaTexture(0)
+		, m_msaaTarget(0)
+		, m_textureSwapChain(NULL)
+		, m_mirrorTexture(NULL)
 	{
-		memset(&m_textureSwapChain, 0, sizeof(m_textureSwapChain) );
+		memset(&m_eyeTarget, 0, sizeof(m_eyeTarget) );
 	}
 
 	static void setDefaultSamplerState()
@@ -3512,85 +3549,98 @@ namespace bgfx { namespace gl
 
 	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_depthBuffer[eye] = 0;
-				m_msaaEyeFbo[eye] = 0;
-				m_msaaEyeTexId[eye] = 0;
-				m_msaaDepthBuffer[eye] = 0;
-				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;
-				}
+		if (!m_session)
+		{
+			return false;
+		}
 
-				int textureCount = 0;
-				ovr_GetTextureSwapChainLength(m_session, m_textureSwapChain[eye], &textureCount);
-				for (int ii = 0; ii < textureCount; ++ii)
-				{
-					ovr_GetTextureSwapChainBufferGL(m_session, m_textureSwapChain[eye], ii, &m_eyeTexId[eye][ii]);
-					GL_CHECK(glBindTexture(GL_TEXTURE_2D, m_eyeTexId[eye][ii]) );
-					setDefaultSamplerState();
-				}
+		if (NULL == m_textureSwapChain)
+		{
+			const GLsizei width = _desc.m_eyeSize[0].m_w + _desc.m_eyeSize[1].m_w;
+			const GLsizei height = bx::uint16_max(_desc.m_eyeSize[0].m_h, _desc.m_eyeSize[1].m_h);
 
-				GL_CHECK(glGenFramebuffers(1, &m_eyeFbo[eye]) );
+			ovrTextureSwapChainDesc swapchainDesc = {};
+			swapchainDesc.Type = ovrTexture_2D;
+			swapchainDesc.Width = width;
+			swapchainDesc.Height = height;
+			swapchainDesc.MipLevels = 1;
+			swapchainDesc.ArraySize = 1;
+			swapchainDesc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB;
+			swapchainDesc.SampleCount = 1;
+			swapchainDesc.StaticImage = ovrFalse;
 
-				// create depth buffer
-				GL_CHECK(glGenTextures(1, &m_depthBuffer[eye]) );
-				GL_CHECK(glBindTexture(GL_TEXTURE_2D, m_depthBuffer[eye]) );
-				setDefaultSamplerState();
+			ovrResult result = ovr_CreateTextureSwapChainGL(m_session, &swapchainDesc, &m_textureSwapChain);
+			if (!OVR_SUCCESS(result) )
+			{
+				destroySwapChain();
+				return false;
+			}
+
+			m_renderLayer.Header.Flags |= ovrLayerFlag_TextureOriginAtBottomLeft;
+			for (int eye = 0; eye < 2; ++eye)
+			{
+				m_renderLayer.ColorTexture[eye] = m_textureSwapChain;
+			}
+
+			// create depth buffer
+			GL_CHECK(glGenRenderbuffers(1, &m_depthRbo));
+			GL_CHECK(glBindRenderbuffer(GL_RENDERBUFFER, m_depthRbo));
+			if (_msaaSamples > 1)
+			{
+				GL_CHECK(glRenderbufferStorageMultisample(GL_RENDERBUFFER, _msaaSamples, GL_DEPTH_COMPONENT32F, width, height));
+			}
+			else
+			{
+				GL_CHECK(glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32F, width, height));
+			}
+			GL_CHECK(glBindRenderbuffer(GL_RENDERBUFFER, 0));
 
-				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) );
+			int count;
+			result = ovr_GetTextureSwapChainLength(m_session, m_textureSwapChain, &count);
+			if (!OVR_SUCCESS(result) )
+			{
+				destroySwapChain();
+				return false;
+			}
 
-				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) );
+			BX_CHECK(count <= BX_COUNTOF(m_eyeTarget), "Too many OVR swap chain textures. %d", count);
+			for (int ii = 0; ii < count; ++ii)
+			{
+				GLuint texture;
+				ovr_GetTextureSwapChainBufferGL(m_session, m_textureSwapChain, ii, &texture);
 
-				// create MSAA targets if needed
-				if (_msaaSamples > 1)
+				// create eye target
+				GL_CHECK(glGenFramebuffers(1, &m_eyeTarget[ii]) );
+				GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_eyeTarget[ii]) );
+				GL_CHECK(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0) );
+				if (2 > _msaaSamples && 0 != m_depthRbo)
 				{
-					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, _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_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) );
+					GL_CHECK(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthRbo) );
 				}
+				frameBufferValidate();
+				GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, 0) );
+			}
+
+			// create MSAA target
+			if (1 < _msaaSamples)
+			{
+				GL_CHECK(glGenTextures(1, &m_msaaTexture) );
+				GL_CHECK(glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_msaaTexture) );
+				GL_CHECK(glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, _msaaSamples, GL_RGBA, width, height, GL_TRUE) );
+				setDefaultSamplerState();
 
-				m_renderLayer.ColorTexture[eye] = m_textureSwapChain[eye];
+				GL_CHECK(glGenFramebuffers(1, &m_msaaTarget) );
+				GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_msaaTarget) );
+				GL_CHECK(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, m_msaaTexture, 0) );
+				if (0 != m_depthRbo)
+				{
+					GL_CHECK(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthRbo) );
+				}
+				frameBufferValidate();
+				GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, 0) );
 			}
 		}
 
-		m_renderLayer.Header.Flags |= ovrLayerFlag_TextureOriginAtBottomLeft;
-
 		if (NULL == m_mirrorTexture)
 		{
 			m_mirrorFbo = 0;
@@ -3611,18 +3661,11 @@ namespace bgfx { namespace gl
 				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!");
-				}
+				GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_mirrorFbo) );
+				GL_CHECK(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texId, 0) );
+				GL_CHECK(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0) );
+				frameBufferValidate();
+				GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, 0) );
 			}
 		}
 
@@ -3631,27 +3674,40 @@ namespace bgfx { namespace gl
 
 	void VRImplOVRGL::destroySwapChain()
 	{
-		for (int eye = 0; eye < 2; ++eye)
+		destroyMirror();
+
+		if (0 != m_msaaTarget)
 		{
-			if (NULL != m_textureSwapChain[eye])
-			{
-				GL_CHECK(glDeleteFramebuffers(1, &m_eyeFbo[eye]) );
-				GL_CHECK(glDeleteTextures(1, &m_depthBuffer[eye]) );
+			GL_CHECK(glDeleteFramebuffers(1, &m_msaaTarget) );
+			m_msaaTarget = 0;
+		}
 
-				ovr_DestroyTextureSwapChain(m_session, m_textureSwapChain[eye]);
-				m_textureSwapChain[eye] = NULL;
+		if (0 != m_msaaTexture)
+		{
+			GL_CHECK(glDeleteTextures(1, &m_msaaTexture) );
+			m_msaaTexture = 0;
+		}
 
-				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;
-				}
+		if (0 != m_depthRbo)
+		{
+			GL_CHECK(glDeleteRenderbuffers(1, &m_depthRbo) );
+			m_depthRbo = 0;
+		}
+
+		for (int ii = 0, nn = BX_COUNTOF(m_eyeTarget); ii < nn; ++ii)
+		{
+			if (0 != m_eyeTarget[ii])
+			{
+				GL_CHECK(glDeleteFramebuffers(1, &m_eyeTarget[ii]) );
+				m_eyeTarget[ii] = 0;
 			}
 		}
 
-		destroyMirror();
+		if (NULL != m_textureSwapChain)
+		{
+			ovr_DestroyTextureSwapChain(m_session, m_textureSwapChain);
+			m_textureSwapChain = NULL;
+		}
 	}
 
 	void VRImplOVRGL::destroyMirror()
@@ -3664,59 +3720,47 @@ namespace bgfx { namespace gl
 		}
 	}
 
-	void VRImplOVRGL::renderEyeStart(const VRDesc& _desc, uint8_t _eye)
+	void VRImplOVRGL::makeRenderTargetActive(const VRDesc& /*_desc*/)
 	{
-		// set the current eye texture in the swap chain
-		if (0 != m_msaaEyeFbo[_eye])
+		if (0 != m_msaaTarget)
 		{
-			GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_msaaEyeFbo[_eye]) );
+			s_renderGL->m_currentFbo = m_msaaTarget;
 		}
 		else
 		{
-			int texIndex;
-			ovr_GetTextureSwapChainCurrentIndex(m_session, m_textureSwapChain[_eye], &texIndex);
-
-			GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_eyeFbo[_eye]) );
-			GL_CHECK(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_eyeTexId[_eye][texIndex], 0) );
+			int index;
+			ovr_GetTextureSwapChainCurrentIndex(m_session, m_textureSwapChain, &index);
+			s_renderGL->m_currentFbo = m_eyeTarget[index];
 		}
 	}
 
 	bool VRImplOVRGL::submitSwapChain(const VRDesc& _desc)
 	{
-		for (int eye = 0; eye < 2; ++eye)
-		{
-			if (0 != m_msaaEyeFbo[eye])
-			{
-				// 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);
+		BX_CHECK(NULL != m_textureSwapChain, "VRImplOVRGL submitted without a valid swap chain");
 
-				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)
-						);
+		if (0 != m_msaaTarget)
+		{
+			const uint32_t width = _desc.m_eyeSize[0].m_w+_desc.m_eyeSize[1].m_w;
+			const uint32_t height = _desc.m_eyeSize[0].m_h;
 
-				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)
-						);
+			int index;
+			ovr_GetTextureSwapChainCurrentIndex(m_session, m_textureSwapChain, &index);
 
-				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) );
-			}
+			// resolve MSAA
+			GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, m_msaaTarget) );
+			GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_eyeTarget[index]) );
+			GL_CHECK(glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST) );
+			GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, 0) );
+		}
 
-			ovrResult result = ovr_CommitTextureSwapChain(m_session, m_textureSwapChain[eye]);
-			if (!OVR_SUCCESS(result) )
-			{
-				return false;
-			}
+		ovrResult result = ovr_CommitTextureSwapChain(m_session, m_textureSwapChain);
+		if (!OVR_SUCCESS(result) )
+		{
+			return false;
 		}
 
 		ovrLayerHeader* layerList = &m_renderLayer.Header;
-		ovrResult result = ovr_SubmitFrame(m_session, 0, &m_viewScale, &layerList, 1);
+		result = ovr_SubmitFrame(m_session, 0, &m_viewScale, &layerList, 1);
 		if (!OVR_SUCCESS(result) )
 		{
 			return false;
@@ -5764,17 +5808,6 @@ namespace bgfx { namespace gl
 		}
 	}
 
-	static void frameBufferValidate()
-	{
-		GLenum complete = glCheckFramebufferStatus(GL_FRAMEBUFFER);
-		BX_CHECK(GL_FRAMEBUFFER_COMPLETE == complete
-			, "glCheckFramebufferStatus failed 0x%08x: %s"
-			, complete
-			, glEnumName(complete)
-		);
-		BX_UNUSED(complete);
-	}
-
 	void FrameBufferGL::create(uint8_t _num, const Attachment* _attachment)
 	{
 		GL_CHECK(glGenFramebuffers(1, &m_fbo[0]) );
@@ -6300,7 +6333,7 @@ namespace bgfx { namespace gl
 
 						if (m_ovr.isEnabled() )
 						{
-							m_ovr.renderEyeStart(eye, &viewState.m_rect);
+							m_ovr.getViewport(eye, &viewState.m_rect);
 						}
 						else
 						{