1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
5 #if defined(INCLUDE_VR_RENDERING)
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>
20 CD3DOpenVRRenderer::CD3DOpenVRRenderer(CryVR::OpenVR::IOpenVRDevice
* openVRDevice
, CD3D9Renderer
* renderer
, CD3DStereoRenderer
* stereoRenderer
)
21 : m_pOpenVRDevice(openVRDevice
)
22 , m_pRenderer(renderer
)
23 , m_pStereoRenderer(stereoRenderer
)
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");
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()
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()
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);
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);
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);
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);
183 void CD3DOpenVRRenderer::Shutdown()
185 m_pStereoRenderer
->SetEyeTextures(nullptr, nullptr);
188 for (uint32 eye
= 0; eye
< 2; ++eye
)
190 m_scene3DRenderData
[eye
].texture
->ReleaseForce();
191 m_scene3DRenderData
[eye
].texture
= nullptr;
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;
203 for (uint32 eye
= 0; eye
< 2; ++eye
)
205 if (m_mirrorTextures
[eye
] != nullptr)
207 m_mirrorTextures
[eye
]->ReleaseForce();
208 m_mirrorTextures
[eye
] = nullptr;
215 void CD3DOpenVRRenderer::OnResolutionChanged(int newWidth
, int newHeight
)
217 if (m_eyeWidth
!= newWidth
||
218 m_eyeHeight
!= newHeight
)
221 Initialize(newWidth
, newHeight
);
225 void CD3DOpenVRRenderer::ReleaseBuffers()
229 void CD3DOpenVRRenderer::PrepareFrame()
232 m_pStereoRenderer
->SetEyeTextures(m_scene3DRenderData
[0].texture
, m_scene3DRenderData
[1].texture
);
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
);
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();
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
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
);
295 ~SSocialScreenRenderAutoRestore()
297 ASSERT_LEGACY_PIPELINE
300 gRenDev
->m_RP
.m_FlagsShader_RT
= shaderFlags
;
302 gcpRendD3D
->FX_PopRenderTarget(0);
303 gcpRendD3D
->SetViewport(x
, y
, w
, h
);
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
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();
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!!!
361 // intentional fall through
362 case EHmdSocialScreen::UndistortedLeftEye
:
363 case EHmdSocialScreen::UndistortedRightEye
:
365 ASSERT_LEGACY_PIPELINE
368 if (CShaderMan::s_shPostEffects
)
370 CTexture
* pTex
= m_pStereoRenderer
->GetEyeTarget(socialScreen
== EHmdSocialScreen::UndistortedLeftEye
? LEFT_EYE
: RIGHT_EYE
);
373 const SSocialScreenRenderAutoRestore
renderStateAutoRestore(pBackbufferTexture
);
375 gcpRendD3D
->RT_SetViewport(backBufferWidth
>> 2, 0, backBufferWidth
>> 1, backBufferHeight
);
376 gcpRendD3D
->FX_ClearTarget(pBackbufferTexture
, Clr_Empty
);
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();
391 GetUtils().StretchRect(pTex
, pBackbufferTexture
);
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
402 if (CShaderMan::s_shPostEffects
)
404 ASSERT_LEGACY_PIPELINE
407 const bool bUseMirrorTexture
= socialScreen
== EHmdSocialScreen::DistortedDualImage
;
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
);
417 gcpRendD3D
->RT_SetViewport(0, 0, backBufferWidth
>> 1, backBufferHeight
); // Set viewport (left half of backbuffer)
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
)
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
)
456 RenderLayer::CProperties
* CD3DOpenVRRenderer::GetQuadLayerProperties(RenderLayer::EQuadLayers id
)
458 if (id
< RenderLayer::eQuadLayers_Total
)
460 return &(m_quadLayerProperties
[id
]);
465 #endif //defined(INCLUDE_VR_RENDERING)