You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
886 lines
22 KiB
C++
886 lines
22 KiB
C++
/*
|
|
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
* its licensors.
|
|
*
|
|
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
* distribution (the "License"). All use of this software is governed by the License,
|
|
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
*
|
|
*/
|
|
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
|
|
|
#include "RenderDll_precompiled.h"
|
|
|
|
#include "D3DStereo.h"
|
|
#include "DriverD3D.h"
|
|
#include "D3DPostProcess.h"
|
|
#include "D3DHMDRenderer.h"
|
|
|
|
|
|
#if defined(AZ_RESTRICTED_PLATFORM)
|
|
#undef AZ_RESTRICTED_SECTION
|
|
#define D3DSTEREO_CPP_SECTION_1 1
|
|
#define D3DSTEREO_CPP_SECTION_2 2
|
|
#endif
|
|
|
|
#include <MathConversion.h>
|
|
|
|
CD3DStereoRenderer::CD3DStereoRenderer(CD3D9Renderer& renderer, EStereoDevice device)
|
|
: m_renderer(renderer)
|
|
, m_device(device)
|
|
, m_deviceState(STEREO_DEVSTATE_UNSUPPORTED_DEVICE)
|
|
, m_mode(STEREO_MODE_NO_STEREO)
|
|
, m_output(STEREO_OUTPUT_STANDARD)
|
|
, m_driver(DRIVER_UNKNOWN)
|
|
, m_pLeftTex(nullptr)
|
|
, m_pRightTex(nullptr)
|
|
, m_nvStereoHandle(nullptr)
|
|
, m_nvStereoStrength(0.0f)
|
|
, m_nvStereoActivated(0)
|
|
, m_renderStatus(IStereoRenderer::Status::kIdle)
|
|
, m_frontBufWidth(0)
|
|
, m_frontBufHeight(0)
|
|
, m_stereoStrength(0.0f)
|
|
, m_zeroParallaxPlaneDist(0.25f)
|
|
, m_maxSeparationScene(0.0f)
|
|
, m_nearGeoScale(0.0f)
|
|
, m_gammaAdjustment(0)
|
|
, m_screenSize(0.0f)
|
|
, m_resourcesPatched(false)
|
|
, m_needClearLeft(true)
|
|
, m_needClearRight(true)
|
|
, m_hmdRenderer(nullptr)
|
|
{
|
|
if (device == STEREO_DEVICE_DEFAULT)
|
|
{
|
|
SelectDefaultDevice();
|
|
}
|
|
}
|
|
|
|
|
|
CD3DStereoRenderer::~CD3DStereoRenderer()
|
|
{
|
|
Shutdown();
|
|
}
|
|
|
|
|
|
void CD3DStereoRenderer::SelectDefaultDevice()
|
|
{
|
|
EStereoDevice device = STEREO_DEVICE_NONE;
|
|
|
|
#if D3DSTEREO_CPP_TRAIT_SELECTDEFAULTDEVICE_STEREODEVICEDRIVER
|
|
device = STEREO_DEVICE_DRIVER;
|
|
#elif defined(AZ_RESTRICTED_PLATFORM)
|
|
#define AZ_RESTRICTED_SECTION D3DSTEREO_CPP_SECTION_1
|
|
#include AZ_RESTRICTED_FILE(D3DStereo_cpp)
|
|
#elif AZ_TRAIT_OS_PLATFORM_APPLE || defined(AZ_PLATFORM_LINUX)
|
|
device = STEREO_DEVICE_FRAMECOMP;
|
|
#endif
|
|
|
|
m_device = device;
|
|
}
|
|
|
|
|
|
void CD3DStereoRenderer::InitDeviceBeforeD3D()
|
|
{
|
|
LOADING_TIME_PROFILE_SECTION;
|
|
|
|
if (m_device == STEREO_DEVICE_NONE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
bool success = true;
|
|
m_deviceState = STEREO_DEVSTATE_UNSUPPORTED_DEVICE;
|
|
|
|
#if defined(AZ_RESTRICTED_PLATFORM)
|
|
#define AZ_RESTRICTED_SECTION D3DSTEREO_CPP_SECTION_2
|
|
#include AZ_RESTRICTED_FILE(D3DStereo_cpp)
|
|
#endif
|
|
|
|
if (success)
|
|
{
|
|
m_deviceState = STEREO_DEVSTATE_OK;
|
|
}
|
|
else
|
|
{
|
|
iLog->LogError("Failed to create stereo device");
|
|
m_device = STEREO_DEVICE_NONE;
|
|
}
|
|
}
|
|
|
|
|
|
void CD3DStereoRenderer::InitDeviceAfterD3D()
|
|
{
|
|
LOADING_TIME_PROFILE_SECTION;
|
|
|
|
// Note: Resources will be created in EF_Init, so no need to create them here
|
|
AZ::StereoRendererRequestBus::Handler::BusConnect();
|
|
}
|
|
|
|
|
|
void CD3DStereoRenderer::CreateResources()
|
|
{
|
|
m_SourceSizeParamName = CCryNameR("SourceSize");
|
|
|
|
if (!CTexture::s_ptexStereoL || !CTexture::s_ptexStereoR)
|
|
{
|
|
CreateIntermediateBuffers();
|
|
}
|
|
}
|
|
|
|
|
|
void CD3DStereoRenderer::CreateIntermediateBuffers()
|
|
{
|
|
SAFE_RELEASE(CTexture::s_ptexStereoL);
|
|
SAFE_RELEASE(CTexture::s_ptexStereoR);
|
|
|
|
int nWidth = m_renderer.GetWidth();
|
|
int nHeight = m_renderer.GetHeight();
|
|
|
|
uint32 nFlags = FT_DONT_STREAM | FT_USAGE_RENDERTARGET;
|
|
|
|
CTexture::s_ptexStereoL = CTexture::CreateRenderTarget("$StereoL", nWidth, nHeight, Clr_Empty, eTT_2D, nFlags, eTF_R8G8B8A8);
|
|
CTexture::s_ptexStereoR = CTexture::CreateRenderTarget("$StereoR", nWidth, nHeight, Clr_Empty, eTT_2D, nFlags, eTF_R8G8B8A8);
|
|
}
|
|
|
|
void CD3DStereoRenderer::Shutdown()
|
|
{
|
|
AZ::StereoRendererRequestBus::Handler::BusDisconnect();
|
|
|
|
ReleaseResources();
|
|
|
|
ShutdownHmdRenderer();
|
|
}
|
|
|
|
|
|
void CD3DStereoRenderer::ReleaseResources()
|
|
{
|
|
if (m_device == STEREO_DEVICE_NONE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
SAFE_RELEASE(CTexture::s_ptexStereoL);
|
|
SAFE_RELEASE(CTexture::s_ptexStereoR);
|
|
}
|
|
|
|
|
|
bool CD3DStereoRenderer::EnableStereo()
|
|
{
|
|
if (!m_hmdRenderer)
|
|
{
|
|
return InitializeHmdRenderer();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void CD3DStereoRenderer::DisableStereo()
|
|
{
|
|
m_gammaAdjustment = 0;
|
|
|
|
ShutdownHmdRenderer();
|
|
}
|
|
|
|
|
|
void CD3DStereoRenderer::ChangeOutputFormat()
|
|
{
|
|
m_frontBufWidth = 0;
|
|
m_frontBufHeight = 0;
|
|
}
|
|
|
|
|
|
bool CD3DStereoRenderer::InitializeHmdRenderer()
|
|
{
|
|
assert(m_hmdRenderer == nullptr);
|
|
|
|
if (AZ::VR::HMDDeviceRequestBus::GetTotalNumOfEventHandlers() <= 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
m_hmdRenderer = new D3DHMDRenderer();
|
|
|
|
if (m_hmdRenderer != nullptr)
|
|
{
|
|
if (!m_hmdRenderer->Initialize(&m_renderer, this))
|
|
{
|
|
SAFE_DELETE(m_hmdRenderer);
|
|
return false;
|
|
}
|
|
}
|
|
return (m_hmdRenderer != nullptr);
|
|
}
|
|
|
|
|
|
void CD3DStereoRenderer::ShutdownHmdRenderer()
|
|
{
|
|
if (m_hmdRenderer != NULL)
|
|
{
|
|
m_hmdRenderer->Shutdown();
|
|
SAFE_DELETE(m_hmdRenderer);
|
|
}
|
|
}
|
|
|
|
|
|
void CD3DStereoRenderer::PrepareStereo(EStereoMode mode, EStereoOutput output)
|
|
{
|
|
if (m_mode != mode || m_output != output)
|
|
{
|
|
m_renderer.ForceFlushRTCommands();
|
|
|
|
if (m_mode != mode)
|
|
{
|
|
m_mode = mode;
|
|
m_output = output;
|
|
|
|
if (mode != STEREO_MODE_NO_STEREO)
|
|
{
|
|
EnableStereo();
|
|
ChangeOutputFormat();
|
|
}
|
|
}
|
|
else if (m_output != output)
|
|
{
|
|
m_output = output;
|
|
|
|
if (IsStereoEnabled())
|
|
{
|
|
ChangeOutputFormat();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (IsStereoEnabled())
|
|
{
|
|
// VR FIX ME
|
|
// These code was written for 3D TV stereo, not for VR.
|
|
// VR EyeDist concept is the half distance between the eyes, it can be different for 3D TV with reprojection
|
|
|
|
// Update stereo parameters
|
|
m_stereoStrength = CRenderer::CV_r_StereoStrength;
|
|
m_maxSeparationScene = CRenderer::CV_r_StereoEyeDist;
|
|
m_zeroParallaxPlaneDist = CRenderer::CV_r_StereoScreenDist;
|
|
m_nearGeoScale = CRenderer::CV_r_StereoNearGeoScale;
|
|
m_gammaAdjustment = CRenderer::CV_r_StereoGammaAdjustment;
|
|
|
|
float screenDiagonal = GetScreenDiagonalInInches();
|
|
if (screenDiagonal > 0.0f) // override CVar if we can determine the correct maximum separation
|
|
{
|
|
float aspect = 9.0f / 16.0f;
|
|
float horizontal = screenDiagonal / sqrtf(1.0f + aspect * aspect);
|
|
float typicalEyeSeperation = 2.5f; // In inches
|
|
m_maxSeparationScene = min(typicalEyeSeperation / horizontal, m_maxSeparationScene); // Get bleeding at edges so limit to CVar
|
|
}
|
|
|
|
// Apply stereo strength
|
|
m_maxSeparationScene *= m_stereoStrength;
|
|
|
|
if (m_hmdRenderer != NULL)
|
|
{
|
|
m_hmdRenderer->PrepareFrame();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CD3DStereoRenderer::HandleNVControl()
|
|
{
|
|
}
|
|
|
|
|
|
void CD3DStereoRenderer::SetEyeTextures(CTexture* leftTex, CTexture* rightTex)
|
|
{
|
|
m_pLeftTex = leftTex;
|
|
m_pRightTex = rightTex;
|
|
}
|
|
|
|
|
|
void CD3DStereoRenderer::Update()
|
|
{
|
|
if (m_device != STEREO_DEVICE_NONE)
|
|
{
|
|
m_renderer.m_pRT->RC_PrepareStereo(CRenderer::CV_r_StereoMode, CRenderer::CV_r_StereoOutput);
|
|
}
|
|
else
|
|
{
|
|
static int prevMode = 0;
|
|
if (CRenderer::CV_r_StereoMode != prevMode)
|
|
{
|
|
LogWarning("No stereo device enabled, ignoring stereo mode");
|
|
prevMode = CRenderer::CV_r_StereoMode;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
CCamera CD3DStereoRenderer::PrepareCamera(EStereoEye nEye, const CCamera& currentCamera, const SRenderingPassInfo& passInfo)
|
|
{
|
|
int nThreadID = passInfo.ThreadID();
|
|
CCamera cam = currentCamera;
|
|
|
|
if (IsRenderingToHMD())
|
|
{
|
|
AZ::VR::PerEyeCameraInfo cameraInfo;
|
|
EBUS_EVENT(AZ::VR::HMDDeviceRequestBus, GetPerEyeCameraInfo, nEye, cam.GetNearPlane(), cam.GetFarPlane(), cameraInfo);
|
|
|
|
const float asymmetricHorizontalTranslation = cameraInfo.frustumPlane.horizontalDistance * cam.GetNearPlane();
|
|
const float asymmetricVerticalTranslation = cameraInfo.frustumPlane.verticalDistance * cam.GetNearPlane();
|
|
|
|
Matrix34 stereoMat = Matrix34::CreateTranslationMat(AZVec3ToLYVec3(cameraInfo.eyeOffset));
|
|
cam.SetMatrix(cam.GetMatrix() * stereoMat);
|
|
cam.SetFrustum(1, 1, cameraInfo.fov, cam.GetNearPlane(), cam.GetFarPlane(), 1.0f / cameraInfo.aspectRatio);
|
|
cam.SetAsymmetry(asymmetricHorizontalTranslation, asymmetricHorizontalTranslation, asymmetricVerticalTranslation, asymmetricVerticalTranslation);
|
|
}
|
|
else
|
|
{
|
|
float fNear = cam.GetNearPlane();
|
|
float screenDist = CRenderer::CV_r_StereoScreenDist;
|
|
float z = 99999.0f; // Point which is far away
|
|
|
|
// standard 3D TV stereo projection parameters
|
|
float wT = tanf(cam.GetFov() * 0.5f) * fNear;
|
|
float wR = wT * cam.GetProjRatio(), wL = -wR;
|
|
float p00 = 2 * fNear / (wR - wL);
|
|
float p02 = (wL + wR) / (wL - wR);
|
|
|
|
// Compute required camera shift, so that a distant point gets the desired maximum separation
|
|
const float maxSeparation = CRenderer::CV_r_StereoEyeDist;
|
|
const float camOffset = (maxSeparation - p02) / (p00 / z - p00 / screenDist);
|
|
float frustumShift = camOffset * (fNear / screenDist);
|
|
//frustumShift *= (nEye == STEREO_EYE_LEFT ? 1 : -1); // Support postive and negative parallax for non-VR stereo
|
|
|
|
Matrix34 stereoMat = Matrix34::CreateTranslationMat(Vec3(nEye == STEREO_EYE_LEFT ? -camOffset : camOffset, 0, 0));
|
|
cam.SetMatrix(cam.GetMatrix() * stereoMat);
|
|
cam.SetAsymmetry(frustumShift, frustumShift, 0, 0);
|
|
}
|
|
|
|
return cam;
|
|
}
|
|
|
|
|
|
void CD3DStereoRenderer::ProcessScene(int sceneFlags, const SRenderingPassInfo& passInfo)
|
|
{
|
|
int nThreadID = passInfo.ThreadID();
|
|
|
|
//for recursive rendering (e.g. rendering to ocean reflection texture), stereo is not needed
|
|
//We also don't need stereo rendering if we're not rendering on the main viewport (don't check if main viewport when in the launcher)
|
|
if (CRenderer::CV_r_StereoMode == STEREO_MODE_DUAL_RENDERING && SRendItem::m_RecurseLevel[nThreadID] < 1
|
|
&& (!gEnv->IsEditor() || gcpRendD3D->m_CurrContext->m_bMainViewport))
|
|
{
|
|
CCamera cam = m_renderer.m_RP.m_TI[nThreadID].m_cam;
|
|
|
|
// Left eye
|
|
{
|
|
m_renderStatus = IStereoRenderer::Status::kRenderingFirstEye;
|
|
m_renderer.m_pRT->RC_SetStereoEye(STEREO_EYE_LEFT);
|
|
m_renderer.PushProfileMarker("LEFT_EYE");
|
|
|
|
CCamera camL = PrepareCamera(STEREO_EYE_LEFT, cam, passInfo);
|
|
m_renderer.SetCamera(camL);
|
|
|
|
CD3DStereoRenderer::RenderScene(sceneFlags, passInfo);
|
|
|
|
CopyToStereoFromMainThread(STEREO_EYE_LEFT);
|
|
m_renderer.PopProfileMarker("LEFT_EYE");
|
|
}
|
|
|
|
// Right eye
|
|
{
|
|
m_renderStatus = IStereoRenderer::Status::kRenderingSecondEye;
|
|
m_renderer.m_pRT->RC_SetStereoEye(STEREO_EYE_RIGHT);
|
|
m_renderer.PushProfileMarker("RIGHT_EYE");
|
|
|
|
CCamera camR = PrepareCamera(STEREO_EYE_RIGHT, cam, passInfo);
|
|
m_renderer.SetCamera(camR);
|
|
|
|
CD3DStereoRenderer::RenderScene(sceneFlags | SHDF_NO_SHADOWGEN, passInfo);
|
|
CopyToStereoFromMainThread(STEREO_EYE_RIGHT);
|
|
|
|
m_renderer.PopProfileMarker("RIGHT_EYE");
|
|
}
|
|
|
|
m_renderStatus = IStereoRenderer::Status::kIdle;
|
|
}
|
|
else
|
|
{
|
|
if (CRenderer::CV_r_StereoMode != STEREO_MODE_DUAL_RENDERING)
|
|
{
|
|
m_renderer.m_pRT->RC_SetStereoEye(0);
|
|
}
|
|
|
|
CD3DStereoRenderer::RenderScene(sceneFlags, passInfo);
|
|
}
|
|
}
|
|
|
|
|
|
void CD3DStereoRenderer::CopyToStereo(int channel)
|
|
{
|
|
assert(IsRenderThread());
|
|
|
|
PROFILE_LABEL_SCOPE("COPY_TO_STEREO");
|
|
|
|
CTexture* pTex;
|
|
|
|
if (channel == STEREO_EYE_LEFT)
|
|
{
|
|
pTex = GetLeftEye();
|
|
m_needClearLeft = false;
|
|
}
|
|
else
|
|
{
|
|
pTex = GetRightEye();
|
|
m_needClearRight = false;
|
|
}
|
|
|
|
if (pTex == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
GetUtils().CopyScreenToTexture(pTex);
|
|
|
|
CTexture* finalCompositeSource = GetUtils().GetFinalCompositeTarget();
|
|
if (gcpRendD3D->FX_GetCurrentRenderTarget(0) == finalCompositeSource && finalCompositeSource != nullptr)
|
|
{
|
|
gcpRendD3D->FX_PopRenderTarget(0);
|
|
}
|
|
}
|
|
|
|
|
|
void CD3DStereoRenderer::DisplayStereo()
|
|
{
|
|
assert(IsRenderThread());
|
|
|
|
if (!IsStereoEnabled() || m_renderer.m_bDeviceLost) // When unloading level, m_bDeviceLost is set to 2
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (m_hmdRenderer != NULL)
|
|
{
|
|
m_hmdRenderer->RenderSocialScreen();
|
|
m_hmdRenderer->SubmitFrame();
|
|
return;
|
|
}
|
|
|
|
ResolveStereoBuffers();
|
|
m_needClearLeft = true;
|
|
m_needClearRight = true;
|
|
|
|
m_renderer.m_cEF.mfRefreshSystemShader("Stereo", CShaderMan::s_ShaderStereo);
|
|
|
|
PROFILE_LABEL_SCOPE("DISPLAY_STEREO");
|
|
|
|
// TODO: Fix this properly
|
|
if (!gEnv->IsEditor())
|
|
{
|
|
m_renderer.RT_SetViewport(0, 0, m_renderer.GetBackbufferWidth(), m_renderer.GetBackbufferHeight());
|
|
}
|
|
|
|
if (m_renderer.m_pSecondBackBuffer != 0)
|
|
{
|
|
m_renderer.FX_PushRenderTarget(1, m_renderer.m_pSecondBackBuffer, NULL);
|
|
m_renderer.RT_SetViewport(0, 0, m_renderer.m_NewViewport.nWidth, m_renderer.m_NewViewport.nHeight);
|
|
}
|
|
|
|
CShader* pSH = m_renderer.m_cEF.s_ShaderStereo;
|
|
SelectShaderTechnique();
|
|
|
|
uint32 nPasses = 0;
|
|
pSH->FXBegin(&nPasses, FEF_DONTSETSTATES);
|
|
pSH->FXBeginPass(0);
|
|
|
|
m_renderer.FX_SetState(GS_NODEPTHTEST);
|
|
|
|
int width = m_renderer.GetWidth();
|
|
int height = m_renderer.GetHeight();
|
|
|
|
Vec4 pParams = Vec4((float) width, (float) height, 0, 0);
|
|
CShaderMan::s_shPostEffects->FXSetPSFloat(m_SourceSizeParamName, &pParams, 1);
|
|
|
|
GetUtils().SetTexture(!CRenderer::CV_r_StereoFlipEyes ? GetLeftEye() : GetRightEye(), 0, FILTER_LINEAR);
|
|
GetUtils().SetTexture(!CRenderer::CV_r_StereoFlipEyes ? GetRightEye() : GetLeftEye(), 1, FILTER_LINEAR);
|
|
|
|
GetUtils().DrawFullScreenTri(width, height);
|
|
|
|
pSH->FXEndPass();
|
|
pSH->FXEnd();
|
|
|
|
if (m_renderer.m_pSecondBackBuffer != 0)
|
|
{
|
|
m_renderer.FX_PopRenderTarget(1);
|
|
}
|
|
}
|
|
|
|
|
|
void CD3DStereoRenderer::BeginRenderingMRT(bool disableClear)
|
|
{
|
|
if (!IsStereoEnabled())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (disableClear)
|
|
{
|
|
m_needClearLeft = false;
|
|
m_needClearRight = false;
|
|
}
|
|
|
|
PushRenderTargets();
|
|
}
|
|
|
|
|
|
void CD3DStereoRenderer::EndRenderingMRT(bool bResolve)
|
|
{
|
|
if (!IsStereoEnabled())
|
|
{
|
|
return;
|
|
}
|
|
|
|
PopRenderTargets(bResolve);
|
|
}
|
|
|
|
|
|
void CD3DStereoRenderer::TakeScreenshot(const char path[])
|
|
{
|
|
stack_string pathL(path);
|
|
stack_string pathR(path);
|
|
|
|
pathL.insert(pathL.find('.'), "_L");
|
|
pathR.insert(pathR.find('.'), "_R");
|
|
|
|
((CD3D9Renderer*) gRenDev)->CaptureFrameBufferToFile(pathL.c_str(), GetLeftEye());
|
|
((CD3D9Renderer*) gRenDev)->CaptureFrameBufferToFile(pathR.c_str(), GetRightEye());
|
|
}
|
|
|
|
|
|
void CD3DStereoRenderer::ResolveStereoBuffers()
|
|
{
|
|
}
|
|
|
|
IStereoRenderer::Status ConvertFromEyeToStatus(const EStereoEye eye)
|
|
{
|
|
if (eye == STEREO_EYE_LEFT)
|
|
{
|
|
return IStereoRenderer::Status::kRenderingFirstEye;
|
|
}
|
|
else if (eye == STEREO_EYE_RIGHT)
|
|
{
|
|
return IStereoRenderer::Status::kRenderingSecondEye;
|
|
}
|
|
|
|
return IStereoRenderer::Status::kIdle;
|
|
}
|
|
|
|
void CD3DStereoRenderer::BeginRenderingTo(EStereoEye eye)
|
|
{
|
|
m_renderStatus = ConvertFromEyeToStatus(eye);
|
|
|
|
if (eye == STEREO_EYE_LEFT)
|
|
{
|
|
gRenDev->SetProfileMarker("LEFT_EYE", CRenderer::ESPM_PUSH);
|
|
if (m_needClearLeft)
|
|
{
|
|
m_renderer.FX_ClearTarget(GetLeftEye(), Clr_Transparent);
|
|
m_needClearLeft = false;
|
|
}
|
|
m_renderer.FX_PushRenderTarget(0, GetLeftEye(), &m_renderer.m_DepthBufferOrig);
|
|
}
|
|
else
|
|
{
|
|
gRenDev->SetProfileMarker("RIGHT_EYE", CRenderer::ESPM_PUSH);
|
|
if (m_needClearRight)
|
|
{
|
|
m_renderer.FX_ClearTarget(GetRightEye(), Clr_Transparent);
|
|
m_needClearRight = false;
|
|
}
|
|
m_renderer.FX_PushRenderTarget(0, GetRightEye(), &m_renderer.m_DepthBufferOrig);
|
|
}
|
|
|
|
m_renderer.FX_SetActiveRenderTargets();
|
|
|
|
if (eye == STEREO_EYE_LEFT)
|
|
{
|
|
GetLeftEye()->SetResolved(true);
|
|
}
|
|
else
|
|
{
|
|
GetRightEye()->SetResolved(true);
|
|
}
|
|
}
|
|
|
|
|
|
void CD3DStereoRenderer::EndRenderingTo(EStereoEye eye)
|
|
{
|
|
if (eye == STEREO_EYE_LEFT)
|
|
{
|
|
gRenDev->SetProfileMarker("LEFT_EYE", CRenderer::ESPM_POP);
|
|
GetLeftEye()->SetResolved(true);
|
|
m_renderer.FX_PopRenderTarget(0);
|
|
}
|
|
else
|
|
{
|
|
gRenDev->SetProfileMarker("RIGHT_EYE", CRenderer::ESPM_POP);
|
|
GetRightEye()->SetResolved(true);
|
|
m_renderer.FX_PopRenderTarget(0);
|
|
}
|
|
}
|
|
|
|
|
|
void CD3DStereoRenderer::SelectShaderTechnique()
|
|
{
|
|
gRenDev->m_cEF.mfRefreshSystemShader("Stereo", CShaderMan::s_ShaderStereo);
|
|
|
|
CShader* pSH = m_renderer.m_cEF.s_ShaderStereo;
|
|
|
|
if (m_device == STEREO_DEVICE_FRAMECOMP)
|
|
{
|
|
switch (GetStereoOutput())
|
|
{
|
|
case STEREO_OUTPUT_CHECKERBOARD:
|
|
pSH->FXSetTechnique("Checkerboard");
|
|
break;
|
|
case STEREO_OUTPUT_SIDE_BY_SIDE:
|
|
pSH->FXSetTechnique("SideBySide");
|
|
break;
|
|
case STEREO_OUTPUT_LINE_BY_LINE:
|
|
pSH->FXSetTechnique("LineByLine");
|
|
break;
|
|
#ifndef _RELEASE
|
|
case STEREO_OUTPUT_ANAGLYPH:
|
|
pSH->FXSetTechnique("Anaglyph");
|
|
break;
|
|
#endif
|
|
default:
|
|
pSH->FXSetTechnique("Emulation");
|
|
}
|
|
}
|
|
else if (IsDriver(DRIVER_NV))
|
|
{
|
|
pSH->FXSetTechnique("NV3DVision");
|
|
}
|
|
else if (m_device == STEREO_DEVICE_DUALHEAD)
|
|
{
|
|
switch (GetStereoOutput())
|
|
{
|
|
case STEREO_OUTPUT_STANDARD:
|
|
pSH->FXSetTechnique("DualHead");
|
|
break;
|
|
case STEREO_OUTPUT_IZ3D:
|
|
pSH->FXSetTechnique("IZ3D");
|
|
break;
|
|
default:
|
|
pSH->FXSetTechnique("Emulation");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pSH->FXSetTechnique("Emulation");
|
|
}
|
|
}
|
|
|
|
|
|
void CD3DStereoRenderer::RenderScene(int sceneFlags, const SRenderingPassInfo& passInfo)
|
|
{
|
|
m_renderer.EF_Scene3D(m_renderer.m_MainRTViewport, sceneFlags, passInfo);
|
|
}
|
|
|
|
|
|
bool CD3DStereoRenderer::IsRenderThread() const
|
|
{
|
|
return m_renderer.m_pRT->IsRenderThread();
|
|
}
|
|
|
|
|
|
void CD3DStereoRenderer::CopyToStereoFromMainThread(int channel)
|
|
{
|
|
m_renderer.m_pRT->RC_CopyToStereoTex(channel);
|
|
}
|
|
|
|
|
|
void CD3DStereoRenderer::PushRenderTargets()
|
|
{
|
|
if (m_needClearLeft)
|
|
{
|
|
m_needClearLeft = false;
|
|
m_renderer.FX_ClearTarget(GetLeftEye(), Clr_Transparent);
|
|
}
|
|
|
|
if (m_needClearRight)
|
|
{
|
|
m_needClearRight = false;
|
|
m_renderer.FX_ClearTarget(GetRightEye(), Clr_Transparent);
|
|
}
|
|
|
|
m_renderer.FX_PushRenderTarget(0, GetLeftEye(), &m_renderer.m_DepthBufferOrig);
|
|
m_renderer.FX_PushRenderTarget(1, GetRightEye(), NULL);
|
|
|
|
m_renderer.RT_SetViewport(0, 0, GetLeftEye()->GetWidth(), GetLeftEye()->GetHeight());
|
|
|
|
m_renderer.FX_SetActiveRenderTargets();
|
|
}
|
|
|
|
|
|
void CD3DStereoRenderer::PopRenderTargets([[maybe_unused]] bool bResolve)
|
|
{
|
|
m_renderer.FX_PopRenderTarget(1);
|
|
m_renderer.FX_PopRenderTarget(0);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// IStereoRenderer Interface
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
EStereoDevice CD3DStereoRenderer::GetDevice()
|
|
{
|
|
return m_device;
|
|
}
|
|
|
|
|
|
EStereoDeviceState CD3DStereoRenderer::GetDeviceState()
|
|
{
|
|
return m_deviceState;
|
|
}
|
|
|
|
|
|
void CD3DStereoRenderer::GetInfo(EStereoDevice* device, EStereoMode* mode, EStereoOutput* output, EStereoDeviceState* state) const
|
|
{
|
|
if (device)
|
|
{
|
|
*device = m_device;
|
|
}
|
|
if (mode)
|
|
{
|
|
*mode = m_mode;
|
|
}
|
|
if (output)
|
|
{
|
|
*output = m_output;
|
|
}
|
|
if (state)
|
|
{
|
|
*state = m_deviceState;
|
|
}
|
|
}
|
|
|
|
|
|
bool CD3DStereoRenderer::GetStereoEnabled()
|
|
{
|
|
return IsStereoEnabled();
|
|
}
|
|
|
|
|
|
float CD3DStereoRenderer::GetStereoStrength()
|
|
{
|
|
return m_stereoStrength;
|
|
}
|
|
|
|
|
|
float CD3DStereoRenderer::GetMaxSeparationScene(bool half)
|
|
{
|
|
return m_maxSeparationScene * (half ? 0.5f : 1.0f);
|
|
}
|
|
|
|
|
|
float CD3DStereoRenderer::GetZeroParallaxPlaneDist()
|
|
{
|
|
return m_zeroParallaxPlaneDist;
|
|
}
|
|
|
|
|
|
void CD3DStereoRenderer::GetNVControlValues(bool& stereoActivated, float& stereoStrength)
|
|
{
|
|
stereoActivated = m_nvStereoActivated != 0;
|
|
stereoStrength = m_nvStereoStrength;
|
|
}
|
|
|
|
|
|
void CD3DStereoRenderer::ReleaseBuffers()
|
|
{
|
|
}
|
|
|
|
void CD3DStereoRenderer::OnResolutionChanged()
|
|
{
|
|
// StereoL and StereoR buffers are used as temporary buffers in other passes and always required
|
|
CreateIntermediateBuffers();
|
|
|
|
if (m_device == STEREO_DEVICE_NONE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (m_hmdRenderer != NULL)
|
|
{
|
|
m_hmdRenderer->OnResolutionChanged();
|
|
}
|
|
}
|
|
|
|
|
|
void CD3DStereoRenderer::CalculateBackbufferResolution(int eyeWidth, int eyeHeight, int& backbufferWidth, int& backbufferHeight)
|
|
{
|
|
if (m_hmdRenderer != NULL)
|
|
{
|
|
m_hmdRenderer->CalculateBackbufferResolution(eyeWidth, eyeHeight, backbufferWidth, backbufferHeight);
|
|
}
|
|
else
|
|
{
|
|
switch (m_output)
|
|
{
|
|
case STEREO_OUTPUT_SIDE_BY_SIDE:
|
|
backbufferWidth = eyeWidth * 2;
|
|
backbufferHeight = eyeHeight;
|
|
break;
|
|
case STEREO_OUTPUT_ABOVE_AND_BELOW:
|
|
backbufferWidth = eyeWidth;
|
|
backbufferHeight = eyeHeight * 2;
|
|
break;
|
|
default:
|
|
backbufferWidth = eyeWidth;
|
|
backbufferHeight = eyeHeight;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CD3DStereoRenderer::OnHmdDeviceChanged()
|
|
{
|
|
if (m_hmdRenderer)
|
|
{
|
|
ShutdownHmdRenderer();
|
|
InitializeHmdRenderer();
|
|
}
|
|
}
|
|
|
|
bool CD3DStereoRenderer::IsRenderingToHMD()
|
|
{
|
|
bool valid = false;
|
|
if (m_hmdRenderer)
|
|
{
|
|
// If the renderer is valid, make sure that we're actually supposed to be rendering to the HMD.
|
|
|
|
EStereoDevice device = STEREO_DEVICE_NONE;
|
|
EStereoMode mode = STEREO_MODE_NO_STEREO;
|
|
EStereoOutput output = STEREO_OUTPUT_STANDARD;
|
|
|
|
GetInfo(&device, &mode, &output, nullptr);
|
|
|
|
const bool hmdSelected = (output == STEREO_OUTPUT_HMD);
|
|
if (hmdSelected)
|
|
{
|
|
// Make sure the mode and device are set to use the HMD.
|
|
valid = (mode == STEREO_MODE_DUAL_RENDERING);
|
|
}
|
|
}
|
|
|
|
return valid;
|
|
}
|
|
|
|
|