!I (1670409):
[CRYENGINE.git] / Code / CryEngine / RenderDll / XRenderD3D9 / D3DOpenVR.cpp
blob14befffaf878be686159d340c1972be61fe41bbd
1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
3 #include "StdAfx.h"
5 #if defined(INCLUDE_VR_RENDERING)
7 #include "D3DOpenVR.h"
8 #include "D3DPostProcess.h"
9 #include "DeviceInfo.h"
11 #include <Common/RenderDisplayContext.h>
13 #include <CrySystem/VR/IHMDManager.h>
14 #include <CrySystem/VR/IHMDDevice.h>
15 #ifdef ENABLE_BENCHMARK_SENSOR
16 #include <IBenchmarkFramework.h>
17 #include <IBenchmarkRendererSensorManager.h>
18 #endif
20 CD3DOpenVRRenderer::CD3DOpenVRRenderer(CryVR::OpenVR::IOpenVRDevice* openVRDevice, CD3D9Renderer* renderer, CD3DStereoRenderer* stereoRenderer)
21 : m_pOpenVRDevice(openVRDevice)
22 , m_pRenderer(renderer)
23 , m_pStereoRenderer(stereoRenderer)
24 , m_eyeWidth(~0L)
25 , m_eyeHeight(~0L)
26 , m_numFrames(0)
27 , m_currentFrame(0)
29 ZeroArray(m_scene3DRenderData);
30 ZeroArray(m_quadLayerRenderData);
31 ZeroArray(m_mirrorTextures);
33 for (uint32 i = RenderLayer::eQuadLayers_0; i < RenderLayer::eQuadLayers_Total; ++i)
35 m_quadLayerProperties[i].SetType(RenderLayer::eLayer_Quad);
36 m_quadLayerProperties[i].SetPose(QuatTS(Quat(IDENTITY), Vec3(0.f, 0.f, -0.6f), 1.f));
37 m_quadLayerProperties[i].SetId(i);
40 m_Param0Name = CCryNameR("texToTexParams0");
41 m_Param1Name = CCryNameR("texToTexParams1");
42 m_textureToTexture = CCryNameTSCRC("TextureToTexture");
45 CD3DOpenVRRenderer::~CD3DOpenVRRenderer()
49 bool CD3DOpenVRRenderer::Initialize(int initialWidth, int initialeight)
51 D3DDevice* d3d11Device = m_pRenderer->GetDevice_Unsynchronized().GetRealDevice();
53 m_eyeWidth = initialWidth;
54 m_eyeHeight = initialeight;
56 CryVR::OpenVR::TextureDesc eyeTextureDesc;
57 eyeTextureDesc.width = m_eyeWidth;
58 eyeTextureDesc.height = m_eyeHeight;
59 eyeTextureDesc.format = (uint32)DXGI_FORMAT_R8G8B8A8_UNORM;
61 CryVR::OpenVR::TextureDesc quadTextureDesc;
62 quadTextureDesc.width = m_eyeWidth;
63 quadTextureDesc.height = m_eyeHeight;
64 quadTextureDesc.format = (uint32)DXGI_FORMAT_R8G8B8A8_UNORM;
66 CryVR::OpenVR::TextureDesc mirrorTextureDesc;
67 mirrorTextureDesc.width = m_eyeWidth;
68 mirrorTextureDesc.height = m_eyeHeight;
69 mirrorTextureDesc.format = (uint32)DXGI_FORMAT_R8G8B8A8_UNORM;
71 if (!InitializeEyeTarget(d3d11Device, EEyeType::eEyeType_LeftEye, eyeTextureDesc, "$LeftEye") ||
72 !InitializeEyeTarget(d3d11Device, EEyeType::eEyeType_RightEye, eyeTextureDesc, "$RightEye") ||
73 !InitializeQuadLayer(d3d11Device, RenderLayer::eQuadLayers_0, quadTextureDesc, "$QuadLayer0") ||
74 !InitializeQuadLayer(d3d11Device, RenderLayer::eQuadLayers_1, quadTextureDesc, "$QuadLayer1") ||
75 !InitializeMirrorTexture(d3d11Device, EEyeType::eEyeType_LeftEye, mirrorTextureDesc, "$LeftMirror") ||
76 !InitializeMirrorTexture(d3d11Device, EEyeType::eEyeType_RightEye, mirrorTextureDesc, "$RightMirror"))
78 CryLogAlways("[HMD][OpenVR] Texture creation failed");
79 Shutdown();
80 return false;
83 // Scene3D layers
84 m_pOpenVRDevice->OnSetupEyeTargets(
85 CryVR::OpenVR::ERenderAPI::eRenderAPI_DirectX,
86 CryVR::OpenVR::ERenderColorSpace::eRenderColorSpace_Auto,
87 m_scene3DRenderData[EEyeType::eEyeType_LeftEye].texture->GetDevTexture()->Get2DTexture(),
88 m_scene3DRenderData[EEyeType::eEyeType_RightEye].texture->GetDevTexture()->Get2DTexture()
91 // Quad layers
92 for (int i = 0; i < RenderLayer::eQuadLayers_Total; i++)
94 m_pOpenVRDevice->OnSetupOverlay(i,
95 CryVR::OpenVR::ERenderAPI::eRenderAPI_DirectX,
96 CryVR::OpenVR::ERenderColorSpace::eRenderColorSpace_Auto,
97 m_quadLayerRenderData[i].texture->GetDevTexture()->Get2DTexture()
101 // Mirror texture
102 void* srv = nullptr;
103 for (uint32 eye = 0; eye < 2; ++eye)
105 // Request the resource-view from openVR
106 m_pOpenVRDevice->GetMirrorImageView(static_cast<EEyeType>(eye), m_mirrorTextures[eye]->GetDevTexture()->Get2DTexture(), &srv);
107 m_mirrorTextures[eye]->SetDefaultShaderResourceView(static_cast<D3DShaderResource*>(srv), false);
110 return true;
113 bool CD3DOpenVRRenderer::InitializeEyeTarget(D3DDevice* d3d11Device, EEyeType eye, CryVR::OpenVR::TextureDesc desc, const char* name)
115 D3D11_TEXTURE2D_DESC textureDesc;
116 textureDesc.Width = desc.width;
117 textureDesc.Height = desc.height;
118 textureDesc.MipLevels = 1;
119 textureDesc.ArraySize = 1;
120 textureDesc.Format = (DXGI_FORMAT)desc.format;
121 textureDesc.SampleDesc.Count = 1;
122 textureDesc.SampleDesc.Quality = 0;
123 textureDesc.Usage = D3D11_USAGE_DEFAULT;
124 textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
125 textureDesc.CPUAccessFlags = 0;
126 textureDesc.MiscFlags = 0;
127 ID3D11Texture2D* texture;
128 d3d11Device->CreateTexture2D(&textureDesc, nullptr, &texture);
130 m_scene3DRenderData[eye].texture = m_pStereoRenderer->WrapD3DRenderTarget(static_cast<D3DTexture*>(texture), desc.width, desc.height, (DXGI_FORMAT)desc.format, name, true);
132 return true;
135 bool CD3DOpenVRRenderer::InitializeQuadLayer(D3DDevice* d3d11Device, RenderLayer::EQuadLayers quadLayer, CryVR::OpenVR::TextureDesc desc, const char* name)
137 D3D11_TEXTURE2D_DESC textureDesc;
138 textureDesc.Width = desc.width;
139 textureDesc.Height = desc.height;
140 textureDesc.MipLevels = 1;
141 textureDesc.ArraySize = 1;
142 textureDesc.Format = (DXGI_FORMAT)desc.format;
143 textureDesc.SampleDesc.Count = 1;
144 textureDesc.SampleDesc.Quality = 0;
145 textureDesc.Usage = D3D11_USAGE_DEFAULT;
146 textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
147 textureDesc.CPUAccessFlags = 0;
148 textureDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
149 ID3D11Texture2D* texture;
150 d3d11Device->CreateTexture2D(&textureDesc, nullptr, &texture);
152 char textureName[16];
153 cry_sprintf(textureName, name, quadLayer);
155 m_quadLayerRenderData[quadLayer].texture = m_pStereoRenderer->WrapD3DRenderTarget(static_cast<D3DTexture*>(texture), desc.width, desc.height, (DXGI_FORMAT)desc.format, textureName, true);
157 return true;
160 bool CD3DOpenVRRenderer::InitializeMirrorTexture(D3DDevice* d3d11Device, EEyeType eye, CryVR::OpenVR::TextureDesc desc, const char* name)
162 D3D11_TEXTURE2D_DESC textureDesc;
163 textureDesc.Width = desc.width;
164 textureDesc.Height = desc.height;
165 textureDesc.MipLevels = 1;
166 textureDesc.ArraySize = 1;
167 textureDesc.Format = (DXGI_FORMAT)desc.format;
168 textureDesc.SampleDesc.Count = 1;
169 textureDesc.SampleDesc.Quality = 0;
170 textureDesc.Usage = D3D11_USAGE_DEFAULT;
171 textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
172 textureDesc.CPUAccessFlags = 0;
173 textureDesc.MiscFlags = 0;
175 ID3D11Texture2D* texture;
176 d3d11Device->CreateTexture2D(&textureDesc, nullptr, &texture);
178 m_mirrorTextures[eye] = m_pStereoRenderer->WrapD3DRenderTarget(static_cast<D3DTexture*>(texture), desc.width, desc.height, (DXGI_FORMAT)desc.format, name, false);
180 return true;
183 void CD3DOpenVRRenderer::Shutdown()
185 m_pStereoRenderer->SetEyeTextures(nullptr, nullptr);
187 // Scene3D layers
188 for (uint32 eye = 0; eye < 2; ++eye)
190 m_scene3DRenderData[eye].texture->ReleaseForce();
191 m_scene3DRenderData[eye].texture = nullptr;
194 // Quad layers
195 for (uint32 i = 0; i < RenderLayer::eQuadLayers_Total; ++i)
197 m_pOpenVRDevice->OnDeleteOverlay(i);
198 m_quadLayerRenderData[i].texture->ReleaseForce();
199 m_quadLayerRenderData[i].texture = nullptr;
202 // Mirror texture
203 for (uint32 eye = 0; eye < 2; ++eye)
205 if (m_mirrorTextures[eye] != nullptr)
207 m_mirrorTextures[eye]->ReleaseForce();
208 m_mirrorTextures[eye] = nullptr;
212 ReleaseBuffers();
215 void CD3DOpenVRRenderer::OnResolutionChanged(int newWidth, int newHeight)
217 if (m_eyeWidth != newWidth ||
218 m_eyeHeight != newHeight)
220 Shutdown();
221 Initialize(newWidth, newHeight);
225 void CD3DOpenVRRenderer::ReleaseBuffers()
229 void CD3DOpenVRRenderer::PrepareFrame()
231 // Scene3D layer
232 m_pStereoRenderer->SetEyeTextures(m_scene3DRenderData[0].texture, m_scene3DRenderData[1].texture);
234 // Quad layers
235 for (int i = 0; i < RenderLayer::eQuadLayers_Total; i++)
236 m_pStereoRenderer->SetVrQuadLayerTexture(static_cast<RenderLayer::EQuadLayers>(i), m_quadLayerRenderData[i].texture);
238 m_pOpenVRDevice->OnPrepare();
241 void CD3DOpenVRRenderer::SubmitFrame()
243 #ifdef ENABLE_BENCHMARK_SENSOR
244 gcpRendD3D->m_benchmarkRendererSensor->PreStereoFrameSubmit(m_scene3DRenderData[0].texture, m_scene3DRenderData[1].texture);
245 #endif
247 // Quad layers
248 for (uint32 i = 0; i < RenderLayer::eQuadLayers_Total; ++i)
250 const RenderLayer::CProperties* pQuadProperties = GetQuadLayerProperties(static_cast<RenderLayer::EQuadLayers>(i));
252 if (pQuadProperties->IsActive())
254 m_pOpenVRDevice->SubmitOverlay(i, pQuadProperties);
258 // Pass the final images and layer configuration to the OpenVR device
259 m_pOpenVRDevice->SubmitFrame();
261 #ifdef ENABLE_BENCHMARK_SENSOR
262 gcpRendD3D->m_benchmarkRendererSensor->AfterStereoFrameSubmit();
263 #endif
265 // Deactivate layers
266 GetQuadLayerProperties(RenderLayer::eQuadLayers_0)->SetActive(false);
267 GetQuadLayerProperties(RenderLayer::eQuadLayers_1)->SetActive(false);
270 void CD3DOpenVRRenderer::OnPostPresent()
272 m_pOpenVRDevice->OnPostPresent();
275 struct CD3DOpenVRRenderer::SSocialScreenRenderAutoRestore
277 SSocialScreenRenderAutoRestore(CTexture* pRenderTarget)
279 ASSERT_LEGACY_PIPELINE
281 #if 0
282 shaderFlags = gRenDev->m_RP.m_FlagsShader_RT;
283 gRenDev->GetViewport(&x, &y, &w, &h);
285 gRenDev->m_RP.m_FlagsShader_RT &= ~g_HWSR_MaskBit[HWSR_SAMPLE0];
286 gRenDev->m_RP.m_FlagsShader_RT &= ~g_HWSR_MaskBit[HWSR_SAMPLE2];
287 gRenDev->m_RP.m_FlagsShader_RT &= ~g_HWSR_MaskBit[HWSR_SAMPLE5];
289 gcpRendD3D->FX_PushRenderTarget(0, pRenderTarget, nullptr);
290 gcpRendD3D->FX_SetActiveRenderTargets();
292 gcpRendD3D->FX_SetState(GS_NODEPTHTEST);
293 #endif
295 ~SSocialScreenRenderAutoRestore()
297 ASSERT_LEGACY_PIPELINE
299 #if 0
300 gRenDev->m_RP.m_FlagsShader_RT = shaderFlags;
302 gcpRendD3D->FX_PopRenderTarget(0);
303 gcpRendD3D->SetViewport(x, y, w, h);
304 #endif
307 int x;
308 int y;
309 int w;
310 int h;
311 uint64 shaderFlags;
314 void CD3DOpenVRRenderer::RenderQuadLayers()
316 // Since Quad layers do not get rendered (yet) with orientation in the social screen, we will render only the first quad layer which is the one that contains the Flash textures
317 const uint32 numQuadLayersToRender = 2;
319 for (uint32 layerIdx = 0; layerIdx < numQuadLayersToRender; ++layerIdx)
321 if (m_pOpenVRDevice->IsActiveOverlay(layerIdx))
323 if (CTexture* pQuadTex = m_quadLayerRenderData[layerIdx].texture)
325 ASSERT_LEGACY_PIPELINE
327 #if 0
328 GetUtils().ShBeginPass(CShaderMan::s_shPostEffects, m_textureToTexture, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
330 gRenDev->FX_SetState(GS_NODEPTHTEST | GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA);
331 pQuadTex->Apply(0, EDefaultSamplerStates::LinearClamp);
333 GetUtils().DrawFullScreenTri(0, 0);
334 GetUtils().ShEndPass();
335 #endif
341 void CD3DOpenVRRenderer::RenderSocialScreen()
343 CTexture* pBackbufferTexture = gcpRendD3D->GetActiveDisplayContext()->GetCurrentBackBuffer();
345 if (const IHmdManager* pHmdManager = gEnv->pSystem->GetHmdManager())
347 if (const IHmdDevice* pDev = pHmdManager->GetHmdDevice())
349 const int backBufferWidth = pBackbufferTexture->GetWidth();
350 const int backBufferHeight = pBackbufferTexture->GetHeight();
352 bool bKeepAspect = false;
353 const EHmdSocialScreen socialScreen = pDev->GetSocialScreenType(&bKeepAspect);
355 switch (socialScreen)
357 case EHmdSocialScreen::Off:
358 // TODO: Clear backbuffer texture? Show a selected wallpaper?
359 GetUtils().ClearScreen(0.1f, 0.1f, 0.1f, 1.0f); // we don't want true black, to distinguish between rendering error and no-social-screen. NOTE: THE CONSOLE WILL NOT BE DISPLAYED!!!
360 break;
361 // intentional fall through
362 case EHmdSocialScreen::UndistortedLeftEye:
363 case EHmdSocialScreen::UndistortedRightEye:
365 ASSERT_LEGACY_PIPELINE
367 #if 0
368 if (CShaderMan::s_shPostEffects)
370 CTexture* pTex = m_pStereoRenderer->GetEyeTarget(socialScreen == EHmdSocialScreen::UndistortedLeftEye ? LEFT_EYE : RIGHT_EYE);
371 if (bKeepAspect)
373 const SSocialScreenRenderAutoRestore renderStateAutoRestore(pBackbufferTexture);
375 gcpRendD3D->RT_SetViewport(backBufferWidth >> 2, 0, backBufferWidth >> 1, backBufferHeight);
376 gcpRendD3D->FX_ClearTarget(pBackbufferTexture, Clr_Empty);
378 uint nPasses;
379 CShaderMan::s_shPostEffects->FXSetTechnique(m_textureToTexture); // TextureToTexture technique
380 CShaderMan::s_shPostEffects->FXBegin(&nPasses, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
381 CShaderMan::s_shPostEffects->FXBeginPass(0);
382 pTex->Apply(0, EDefaultSamplerStates::LinearClamp); // Bind left-eye texture for rendering
383 GetUtils().DrawFullScreenTri(pTex->GetWidth(), pTex->GetHeight(), 0);
384 CShaderMan::s_shPostEffects->FXEndPass();
385 CShaderMan::s_shPostEffects->FXEnd();
387 RenderQuadLayers();
389 else
391 GetUtils().StretchRect(pTex, pBackbufferTexture);
394 #endif
397 break;
399 case EHmdSocialScreen::UndistortedDualImage: // intentional fall through - default to undistorted dual image
400 case EHmdSocialScreen::DistortedDualImage: // intentional fall through - OpenVR does not return distorted eye targets, therefore the only display the undistorted eye targets
401 default:
402 if (CShaderMan::s_shPostEffects)
404 ASSERT_LEGACY_PIPELINE
406 #if 0
407 const bool bUseMirrorTexture = socialScreen == EHmdSocialScreen::DistortedDualImage;
409 // Get eye textures
410 CTexture* pTexLeft = bUseMirrorTexture ? m_mirrorTextures[LEFT_EYE] : m_pStereoRenderer->GetEyeTarget(LEFT_EYE);
411 CTexture* pTexRight = bUseMirrorTexture ? m_mirrorTextures[RIGHT_EYE] : m_pStereoRenderer->GetEyeTarget(RIGHT_EYE);
413 // Store previous viewport and set new render target. Use RAII to restore previous state.
414 const SSocialScreenRenderAutoRestore renderStateAutoRestore(pBackbufferTexture);
416 // Left-Eye Pass
417 gcpRendD3D->RT_SetViewport(0, 0, backBufferWidth >> 1, backBufferHeight); // Set viewport (left half of backbuffer)
419 uint nPasses;
420 CShaderMan::s_shPostEffects->FXSetTechnique(m_textureToTexture); // TextureToTexture technique
421 CShaderMan::s_shPostEffects->FXBegin(&nPasses, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
422 CShaderMan::s_shPostEffects->FXBeginPass(0);
423 pTexLeft->Apply(0, EDefaultSamplerStates::LinearClamp); // Bind left-eye texture for rendering
424 GetUtils().DrawFullScreenTri(pTexLeft->GetWidth(), pTexLeft->GetHeight(), 0);
425 CShaderMan::s_shPostEffects->FXEndPass();
426 CShaderMan::s_shPostEffects->FXEnd();
428 if (!bUseMirrorTexture)
430 RenderQuadLayers();
433 // Right-Eye Pass
434 gcpRendD3D->RT_SetViewport(backBufferWidth >> 1, 0, backBufferWidth >> 1, backBufferHeight); // set viewport (right half of backbuffer)
436 CShaderMan::s_shPostEffects->FXSetTechnique(m_textureToTexture); // TextureToTexture technique
437 CShaderMan::s_shPostEffects->FXBegin(&nPasses, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
438 CShaderMan::s_shPostEffects->FXBeginPass(0);
439 pTexRight->Apply(0, EDefaultSamplerStates::LinearClamp); // Bind right-eye texture for rendering
440 GetUtils().DrawFullScreenTri(pTexRight->GetWidth(), pTexRight->GetHeight(), 1);
441 CShaderMan::s_shPostEffects->FXEndPass();
442 CShaderMan::s_shPostEffects->FXEnd();
444 if (!bUseMirrorTexture)
446 RenderQuadLayers();
448 #endif
450 break;
456 RenderLayer::CProperties* CD3DOpenVRRenderer::GetQuadLayerProperties(RenderLayer::EQuadLayers id)
458 if (id < RenderLayer::eQuadLayers_Total)
460 return &(m_quadLayerProperties[id]);
462 return nullptr;
465 #endif //defined(INCLUDE_VR_RENDERING)