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.
o3de/Code/CryEngine/RenderDll/XRenderD3D9/D3DRenderThread.cpp

715 lines
21 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 "DriverD3D.h"
#include "D3DStereo.h"
#include "../Common/Textures/TextureManager.h"
//=======================================================================
bool CD3D9Renderer::RT_CreateDevice()
{
LOADING_TIME_PROFILE_SECTION;
#if (defined(WIN32) || defined(WIN64)) && !defined(SUPPORT_DEVICE_INFO)
if (!m_bShaderCacheGen && !SetWindow(m_width, m_height, m_bFullScreen, m_hWnd))
{
return false;
}
#endif
return SetRes();
}
void CD3D9Renderer::RT_ReleaseVBStream(void* pVB, [[maybe_unused]] int nStream)
{
D3DBuffer* pBuf = (D3DBuffer*)pVB;
SAFE_RELEASE(pBuf);
}
void CD3D9Renderer::RT_ReleaseCB(void* pVCB)
{
AzRHI::ConstantBuffer* pCB = (AzRHI::ConstantBuffer*)pVCB;
SAFE_RELEASE(pCB);
}
void CD3D9Renderer::RT_ClearTarget(ITexture* tex, const ColorF& color)
{
CTexture* pTex = reinterpret_cast<CTexture*>(tex);
if (pTex->GetFlags() & FT_USAGE_DEPTHSTENCIL)
{
D3DDepthSurface* pSurf = reinterpret_cast<D3DDepthSurface*>(pTex->GetDeviceDepthStencilSurf());
if (!pSurf)
{
return;
}
// NOTE: normalized depth in color.r and unnormalized stencil in color.g
GetDeviceContext().ClearDepthStencilView(pSurf, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, color.r, (uint8)color.g);
}
else
{
D3DSurface* pSurf = pTex->GetSurface(0, 0);
if (!pSurf)
{
return;
}
GetDeviceContext().ClearRenderTargetView(pSurf, (float*)&color);
}
}
void CD3D9Renderer::RT_DrawDynVB(SVF_P3F_C4B_T2F* pBuf, uint16* pInds, uint32 nVerts, uint32 nInds, const PublicRenderPrimitiveType nPrimType)
{
FX_SetFPMode();
if (!FAILED(FX_SetVertexDeclaration(0, eVF_P3F_C4B_T2F)))
{
// Create the temp buffer after we try to set the vertex declaration otherwise
// if that fails we won't call FX_DrawPrimitive that on a platform level
// cleans up some of the memory stuff that the TempDynVB creates
TempDynVB<SVF_P3F_C4B_T2F>::CreateFillAndBind(pBuf, nVerts, 0);
if (pInds)
{
TempDynIB16::CreateFillAndBind(pInds, nInds);
FX_DrawIndexedPrimitive(GetInternalPrimitiveType(nPrimType), 0, 0, nVerts, 0, nInds);
}
else
{
FX_DrawPrimitive(GetInternalPrimitiveType(nPrimType), 0, nVerts);
}
}
}
void CD3D9Renderer::RT_DrawDynVBUI(SVF_P2F_C4B_T2F_F4B* pBuf, uint16* pInds, uint32 nVerts, uint32 nInds, const PublicRenderPrimitiveType nPrimType)
{
FX_SetUIMode();
if (!FAILED(FX_SetVertexDeclaration(0, eVF_P2F_C4B_T2F_F4B)))
{
// Create the temp buffer after we try to set the vertex declaration otherwise
// if that fails we won't call FX_DrawPrimitive that on a platform level
// cleans up some of the memory stuff that the TempDynVB creates
TempDynVB<SVF_P2F_C4B_T2F_F4B>::CreateFillAndBind(pBuf, nVerts, 0);
if (pInds)
{
TempDynIB16::CreateFillAndBind(pInds, nInds);
FX_DrawIndexedPrimitive(GetInternalPrimitiveType(nPrimType), 0, 0, nVerts, 0, nInds);
}
else
{
FX_DrawPrimitive(GetInternalPrimitiveType(nPrimType), 0, nVerts);
}
}
}
void CD3D9Renderer::RT_Draw2dImageInternal(C2dImage* images, uint32 numImages, bool stereoLeftEye)
{
bool bSaveZTest = ((m_RP.m_CurState & GS_NODEPTHTEST) == 0);
SetCullMode(R_CULL_DISABLE);
float maxParallax = 0;
float screenDist = 0;
if (GetS3DRend().IsStereoEnabled())
{
maxParallax = GetS3DRend().GetMaxSeparationScene();
screenDist = GetS3DRend().GetZeroParallaxPlaneDist();
}
// Flush the current viewports.
// The GetViewport call below uses either m_MainRTViewport or m_NewViewport, then the image scaling code
// (ScaleCoordX/ScaleCoordY) uses m_CurViewport, so this could lead to different viewport settings being used unless we flush.
FX_SetViewport();
// Set orthographic projection
Matrix44A origMatProj = m_RP.m_TI[m_RP.m_nProcessThreadID].m_matProj;
Matrix44A* m = &m_RP.m_TI[m_RP.m_nProcessThreadID].m_matProj;
int vx, vy, vw, vh;
GetViewport(&vx, &vy, &vw, &vh);
mathMatrixOrthoOffCenterLH(m, (float)vx, (float)vw, (float)vh, (float)vy, 0.0f, 1.0f);
Matrix44A origMatView = m_RP.m_TI[m_RP.m_nProcessThreadID].m_matView;
m = &m_RP.m_TI[m_RP.m_nProcessThreadID].m_matView;
m_RP.m_TI[m_RP.m_nProcessThreadID].m_matView.SetIdentity();
// Create dynamic geometry
TempDynVB<SVF_P3F_C4B_T2F> vb(gcpRendD3D);
vb.Allocate(numImages * 4);
SVF_P3F_C4B_T2F* vQuad = vb.Lock();
for (uint32 i = 0; i < numImages; ++i)
{
C2dImage& img = images[i];
uint32 baseIdx = i * 4;
float parallax = 0;
if (img.stereoDepth > 0)
{
parallax = 800 * maxParallax * (1 - screenDist / img.stereoDepth);
}
float xpos = (float)ScaleCoordX(img.xpos + parallax * (stereoLeftEye ? -1 : 1));
float w = (float)ScaleCoordX(img.w);
float ypos = (float)ScaleCoordY(img.ypos);
float h = (float)ScaleCoordY(img.h);
if (img.angle != 0)
{
float xsub = (float)(xpos + w / 2.0f);
float ysub = (float)(ypos + h / 2.0f);
float x, y, x1, y1;
float mcos = cos_tpl(DEG2RAD(img.angle));
float msin = sin_tpl(DEG2RAD(img.angle));
x = xpos - xsub;
y = ypos - ysub;
x1 = x * mcos - y * msin;
y1 = x * msin + y * mcos;
x1 += xsub;
y1 += ysub;
vQuad[baseIdx].xyz.x = x1;
vQuad[baseIdx].xyz.y = y1;
x = xpos + w - xsub;
y = ypos - ysub;
x1 = x * mcos - y * msin;
y1 = x * msin + y * mcos;
x1 += xsub;
y1 += ysub;
vQuad[baseIdx + 1].xyz.x = x1;//xpos + fw;
vQuad[baseIdx + 1].xyz.y = y1;// fy;
x = xpos + w - xsub;
y = ypos + h - ysub;
x1 = x * mcos - y * msin;
y1 = x * msin + y * mcos;
x1 += xsub;
y1 += ysub;
vQuad[baseIdx + 3].xyz.x = x1;//xpos + fw;
vQuad[baseIdx + 3].xyz.y = y1;//fy + fh;
x = xpos - xsub;
y = ypos + h - ysub;
x1 = x * mcos - y * msin;
y1 = x * msin + y * mcos;
x1 += xsub;
y1 += ysub;
vQuad[baseIdx + 2].xyz.x = x1;//xpos;
vQuad[baseIdx + 2].xyz.y = y1;//fy + fh;
}
else
{
vQuad[baseIdx].xyz.x = xpos;
vQuad[baseIdx].xyz.y = ypos;
vQuad[baseIdx + 1].xyz.x = xpos + w;
vQuad[baseIdx + 1].xyz.y = ypos;
vQuad[baseIdx + 2].xyz.x = xpos;
vQuad[baseIdx + 2].xyz.y = ypos + h;
vQuad[baseIdx + 3].xyz.x = xpos + w;
vQuad[baseIdx + 3].xyz.y = ypos + h;
}
vQuad[baseIdx + 0].st = Vec2(img.s0, 1.0f - img.t0);
vQuad[baseIdx + 1].st = Vec2(img.s1, 1.0f - img.t0);
vQuad[baseIdx + 2].st = Vec2(img.s0, 1.0f - img.t1);
vQuad[baseIdx + 3].st = Vec2(img.s1, 1.0f - img.t1);
for (int j = 0; j < 4; ++j)
{
vQuad[baseIdx + j].color.dcolor = img.col;
vQuad[baseIdx + j].xyz.z = img.z;
}
}
vb.Unlock();
vb.Bind(0);
vb.Release();
CTexture* prevTex = NULL;
EF_SetColorOp(eCO_REPLACE, eCO_REPLACE, (eCA_Diffuse | (eCA_Diffuse << 3)), (eCA_Diffuse | (eCA_Diffuse << 3)));
EF_SetSrgbWrite(false);
FX_SetFPMode();
if (FAILED(FX_SetVertexDeclaration(0, eVF_P3F_C4B_T2F)))
{
m_RP.m_TI[m_RP.m_nProcessThreadID].m_matView = origMatView;
m_RP.m_TI[m_RP.m_nProcessThreadID].m_matProj = origMatProj;
return;
}
int nState = m_bDraw2dImageStretchMode ? CTexture::GetTexState(STexState(FILTER_TRILINEAR, true)) : CTexture::GetTexState(STexState(FILTER_POINT, true));
// Draw quads
for (uint32 i = 0; i < numImages; ++i)
{
C2dImage& img = images[i];
if (img.pTex != prevTex)
{
prevTex = img.pTex;
if (img.pTex)
{
img.pTex->Apply(0, nState);
EF_SetColorOp(eCO_MODULATE, eCO_MODULATE, DEF_TEXARG0, DEF_TEXARG0);
EF_SetSrgbWrite(false);
}
else
{
EF_SetColorOp(eCO_REPLACE, eCO_REPLACE, (eCA_Diffuse | (eCA_Diffuse << 3)), (eCA_Diffuse | (eCA_Diffuse << 3)));
EF_SetSrgbWrite(false);
}
FX_SetFPMode();
#if defined(AZ_RESTRICTED_PLATFORM)
#include AZ_RESTRICTED_FILE(D3DRenderThread_cpp)
#endif
}
FX_DrawPrimitive(eptTriangleStrip, i * 4, 4);
}
m_RP.m_TI[m_RP.m_nProcessThreadID].m_matView = origMatView;
m_RP.m_TI[m_RP.m_nProcessThreadID].m_matProj = origMatProj;
}
void CD3D9Renderer::RT_DrawStringU(IFFont_RenderProxy* pFont, float x, float y, float z, const char* pStr, const bool asciiMultiLine, const STextDrawContext& ctx) const
{
SetProfileMarker("DRAWSTRINGU", CRenderer::ESPM_PUSH);
pFont->RenderCallback(x, y, z, pStr, asciiMultiLine, ctx);
SetProfileMarker("DRAWSTRINGU", CRenderer::ESPM_POP);
}
void CD3D9Renderer::RT_DrawLines(Vec3 v[], int nump, ColorF& col, int flags, float fGround)
{
if (m_bDeviceLost)
{
return;
}
int i;
int st;
HRESULT hr = S_OK;
EF_SetColorOp(eCO_MODULATE, eCO_MODULATE, eCA_Texture | (eCA_Diffuse << 3), eCA_Texture | (eCA_Diffuse << 3));
EF_SetSrgbWrite(false);
st = GS_NODEPTHTEST;
if (flags & 1)
{
st |= GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA;
}
FX_SetState(st);
CTextureManager::Instance()->GetWhiteTexture()->Apply(0);
DWORD c = D3DRGBA(col.r, col.g, col.b, col.a);
if (fGround >= 0)
{
TempDynVB<SVF_P3F_C4B_T2F> vb(gcpRendD3D);
vb.Allocate(nump * 2);
SVF_P3F_C4B_T2F* vQuad = vb.Lock();
for (i = 0; i < nump; i++)
{
vQuad[i * 2 + 0].xyz.x = v[i][0];
vQuad[i * 2 + 0].xyz.y = fGround;
vQuad[i * 2 + 0].xyz.z = 0;
vQuad[i * 2 + 0].color.dcolor = c;
vQuad[i * 2 + 0].st = Vec2(0.0f, 0.0f);
vQuad[i * 2 + 1].xyz = v[i];
vQuad[i * 2 + 1].color.dcolor = c;
vQuad[i * 2 + 1].st = Vec2(0.0f, 0.0f);
}
vb.Unlock();
vb.Bind(0);
vb.Release();
FX_SetFPMode();
if (!FAILED(FX_SetVertexDeclaration(0, eVF_P3F_C4B_T2F)))
{
FX_DrawPrimitive(eptLineList, 0, nump * 2);
}
}
else
{
TempDynVB<SVF_P3F_C4B_T2F> vb(gcpRendD3D);
vb.Allocate(nump);
SVF_P3F_C4B_T2F* vQuad = vb.Lock();
for (i = 0; i < nump; i++)
{
vQuad[i].xyz = v[i];
vQuad[i].color.dcolor = c;
vQuad[i].st = Vec2(0, 0);
}
vb.Unlock();
vb.Bind(0);
vb.Release();
FX_SetFPMode();
if (!FAILED(FX_SetVertexDeclaration(0, eVF_P3F_C4B_T2F)))
{
FX_DrawPrimitive(eptLineStrip, 0, nump);
}
}
}
void CD3D9Renderer::RT_Draw2dImageStretchMode(bool bStretch)
{
m_bDraw2dImageStretchMode = bStretch;
}
void CD3D9Renderer::RT_Draw2dImage(float xpos, float ypos, float w, float h, CTexture* pTexture, float s0, float t0, float s1, float t1, float angle, DWORD col, float z)
{
C2dImage img(xpos, ypos, w, h, pTexture, s0, t0, s1, t1, angle, col, z, 0);
SetProfileMarker("DRAW2DIMAGE", CRenderer::ESPM_PUSH);
if (GetS3DRend().IsStereoEnabled())
{
GetS3DRend().BeginRenderingTo(STEREO_EYE_LEFT);
RT_Draw2dImageInternal(&img, 1, true);
GetS3DRend().EndRenderingTo(STEREO_EYE_LEFT);
GetS3DRend().BeginRenderingTo(STEREO_EYE_RIGHT);
RT_Draw2dImageInternal(&img, 1, false);
GetS3DRend().EndRenderingTo(STEREO_EYE_RIGHT);
}
else
{
RT_Draw2dImageInternal(&img, 1);
}
SetProfileMarker("DRAW2DIMAGE", CRenderer::ESPM_POP);
}
void CD3D9Renderer::RT_Push2dImage(float xpos, float ypos, float w, float h, CTexture* pTexture, float s0, float t0, float s1, float t1, float angle, DWORD col, float z, float stereoDepth)
{
m_2dImages.Add(C2dImage(xpos, ypos, w, h, pTexture, s0, t0, s1, t1, angle, col, z, stereoDepth));
}
void CD3D9Renderer::RT_Draw2dImageList()
{
if (m_2dImages.empty())
{
return;
}
SetProfileMarker("DRAW2DIMAGELIST", CRenderer::ESPM_PUSH);
if (GetS3DRend().IsStereoEnabled())
{
GetS3DRend().BeginRenderingTo(STEREO_EYE_LEFT);
RT_Draw2dImageInternal(m_2dImages.Data(), m_2dImages.size(), true);
GetS3DRend().EndRenderingTo(STEREO_EYE_LEFT);
GetS3DRend().BeginRenderingTo(STEREO_EYE_RIGHT);
RT_Draw2dImageInternal(m_2dImages.Data(), m_2dImages.size(), false);
GetS3DRend().EndRenderingTo(STEREO_EYE_RIGHT);
}
else
{
RT_Draw2dImageInternal(m_2dImages.Data(), m_2dImages.size());
}
SetProfileMarker("DRAW2DIMAGELIST", CRenderer::ESPM_POP);
m_2dImages.resize(0);
}
void CD3D9Renderer::RT_PushRenderTarget(int nTarget, CTexture* pTex, SDepthTexture* pDepth, int nS)
{
FX_PushRenderTarget(nTarget, pTex, pDepth, nS);
}
void CD3D9Renderer::RT_PopRenderTarget(int nTarget)
{
FX_PopRenderTarget(nTarget);
}
void CD3D9Renderer::RT_Init()
{
EF_Init();
}
void CD3D9Renderer::RT_CreateResource(SResourceAsync* pRes)
{
if (pRes->eClassName == eRCN_Texture)
{
CTexture* pTex = NULL;
if (pRes->nTexId)
{ // only create device texture
pTex = CTexture::GetByID(pRes->nTexId);
const byte* arrData[6] = { pRes->pData, 0, 0, 0, 0, 0 };
pTex->CreateDeviceTexture(arrData);
}
else
{ // create full texture
char* pName = pRes->Name;
char szName[128];
if (!pName)
{
sprintf_s(szName, "$AutoDownloadAsync_%d", m_TexGenID++);
pName = szName;
}
pTex = CTexture::Create2DTexture(pName, pRes->nWidth, pRes->nHeight, pRes->nMips, pRes->nTexFlags, pRes->pData, (ETEX_Format)pRes->nFormat, (ETEX_Format)pRes->nFormat);
}
SAFE_DELETE_ARRAY(pRes->pData);
pRes->pResource = pTex;
pRes->nReady = (CTexture::IsTextureExist(pTex));
}
else
{
assert(0);
}
delete pRes;
}
void CD3D9Renderer::RT_ReleaseResource(SResourceAsync* pRes)
{
if (pRes->eClassName == eRCN_Texture)
{
CTexture* pTex = (CTexture*)pRes->pResource;
pTex->Release();
}
else
{
assert(0);
}
delete pRes;
}
void CD3D9Renderer::RT_UnbindTMUs()
{
D3DShaderResourceView* pTex[MAX_TMU] = {NULL};
for (uint32 i = 0; i < MAX_TMU; ++i)
{
CTexture::s_TexStages[i].m_DevTexture = NULL;
}
m_DevMan.BindSRV(eHWSC_Vertex, pTex, 0, MAX_TMU);
m_DevMan.BindSRV(eHWSC_Geometry, pTex, 0, MAX_TMU);
m_DevMan.BindSRV(eHWSC_Domain, pTex, 0, MAX_TMU);
m_DevMan.BindSRV(eHWSC_Hull, pTex, 0, MAX_TMU);
m_DevMan.BindSRV(eHWSC_Compute, pTex, 0, MAX_TMU);
m_DevMan.BindSRV(eHWSC_Pixel, pTex, 0, MAX_TMU);
m_DevMan.CommitDeviceStates();
}
void CD3D9Renderer::RT_UnbindResources()
{
for (AZ::u32 shaderClass = 0; shaderClass < eHWSC_Num; ++shaderClass)
{
for (AZ::u32 shaderSlot = 0; shaderSlot < eConstantBufferShaderSlot_Count; ++shaderSlot)
{
m_DevMan.BindConstantBuffer(EHWShaderClass(shaderClass), nullptr, shaderSlot);
}
}
D3DBuffer* pBuffers[16] = { 0 };
UINT StrideOffset[16] = { 0 };
m_DevMan.BindIB(NULL, 0, DXGI_FORMAT_R16_UINT);
m_RP.m_pIndexStream = NULL;
m_DevMan.BindVB(0, 16, pBuffers, StrideOffset, StrideOffset);
m_RP.m_VertexStreams[0].pStream = NULL;
m_DevMan.BindVtxDecl(NULL);
m_pLastVDeclaration = NULL;
m_DevMan.BindShader(eHWSC_Pixel, NULL);
m_DevMan.BindShader(eHWSC_Vertex, NULL);
m_DevMan.BindShader(eHWSC_Geometry, NULL);
m_DevMan.BindShader(eHWSC_Domain, NULL);
m_DevMan.BindShader(eHWSC_Hull, NULL);
m_DevMan.BindShader(eHWSC_Compute, NULL);
CHWShader::s_pCurPS = nullptr;
CHWShader::s_pCurVS = nullptr;
CHWShader::s_pCurGS = nullptr;
CHWShader::s_pCurDS = nullptr;
CHWShader::s_pCurHS = nullptr;
CHWShader::s_pCurCS = nullptr;
m_DevMan.CommitDeviceStates();
}
void CD3D9Renderer::RT_ReleaseRenderResources()
{
GetGraphicsPipeline().Shutdown();
m_cEF.mfReleasePreactivatedShaderData();
m_cEF.m_Bin.InvalidateCache();
//m_cEF.m_Bin.m_BinPaths.clear();
ForceFlushRTCommands();
for (uint i = 0; i < CLightStyle::s_LStyles.Num(); i++)
{
delete CLightStyle::s_LStyles[i];
}
CLightStyle::s_LStyles.Free();
FX_PipelineShutdown();
ID3D11RenderTargetView* pRTV[RT_STACK_WIDTH] = { NULL };
GetDeviceContext().OMSetRenderTargets(RT_STACK_WIDTH, pRTV, NULL);
m_nMaxRT2Commit = -1;
}
void CD3D9Renderer::RT_CreateRenderResources()
{
EF_Init();
if (m_pPostProcessMgr)
{
m_pPostProcessMgr->CreateResources();
}
GetGraphicsPipeline().Init();
}
void CD3D9Renderer::RT_PrecacheDefaultShaders()
{
SShaderCombination cmb;
m_cEF.s_ShaderStereo->mfPrecache(cmb, true, true, NULL);
cmb.m_RTMask |= g_HWSR_MaskBit[HWSR_SAMPLE0];
cmb.m_RTMask |= g_HWSR_MaskBit[HWSR_SAMPLE1];
cmb.m_RTMask |= g_HWSR_MaskBit[HWSR_SAMPLE2];
m_cEF.s_ShaderVideo->mfPrecache(cmb, true, true, nullptr);
}
void CD3D9Renderer::RT_ResetGlass()
{
}
void CD3D9Renderer::SetRendererCVar(ICVar* pCVar, const char* pArgText, const bool bSilentMode)
{
m_pRT->RC_SetRendererCVar(pCVar, pArgText, bSilentMode);
}
void CD3D9Renderer::RT_SetRendererCVar(ICVar* pCVar, const char* pArgText, const bool bSilentMode)
{
if (pCVar)
{
pCVar->Set(pArgText);
if (!bSilentMode)
{
if (gEnv->IsEditor())
{
gEnv->pLog->LogWithType(ILog::eInputResponse, "%s = %s (Renderer CVar)", pCVar->GetName(), pCVar->GetString());
}
else
{
gEnv->pLog->LogWithType(ILog::eInputResponse, " $3%s = $6%s $5(Renderer CVar)", pCVar->GetName(), pCVar->GetString());
}
}
}
}
void CD3D9Renderer::RT_PostLevelLoading()
{
CRenderer::RT_PostLevelLoading();
// Clear our the shadow mask texture in case the level we are loading does not
// have any shadow casters. If we don't clear out the mask then whatever was
// previous in the mask, including a previously loaded level, will be used and
// incorrect shadows will be drawn.
FX_ClearShadowMaskTexture();
}
void CD3D9Renderer::StartLoadtimePlayback(ILoadtimeCallback* pCallback)
{
// make sure we can't access loading mode twice!
if (m_pRT->m_pLoadtimeCallback)
{
return;
}
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Renderer);
if (pCallback)
{
FlushRTCommands(true, true, true);
m_pRT->m_pLoadtimeCallback = pCallback;
SetViewport(0, 0, GetOverlayWidth(), GetOverlayHeight());
m_pRT->RC_StartVideoThread();
if (m_pRT->IsMultithreaded())
{
// wait until render thread has fully processed the start of the video
// to reduce the congestion on the IO reading (make sure nothing else
// beats the video to actually start reading something from the DVD)
while (m_pRT->m_eVideoThreadMode != SRenderThread::eVTM_Active)
{
m_pRT->FlushAndWait();
AZStd::this_thread::yield();
}
}
}
}
void CD3D9Renderer::StopLoadtimePlayback()
{
if (m_pRT->m_pLoadtimeCallback)
{
LOADING_TIME_PROFILE_SECTION;
FlushRTCommands(true, true, true);
m_pRT->RC_StopVideoThread();
if (m_pRT->IsMultithreaded())
{
// wait until render thread has fully processed the shutdown of the loading thread
while (m_pRT->m_eVideoThreadMode != SRenderThread::eVTM_Disabled)
{
m_pRT->FlushAndWait();
AZStd::this_thread::yield();
}
}
m_pRT->m_pLoadtimeCallback = nullptr;
m_pRT->RC_BeginFrame();
#if !defined(STRIP_RENDER_THREAD)
// Blit the accumulated commands from the renderloading thread into the current fill command queue
// : Currently hacked into the RC_UpdateMaterialConstants command
if (m_pRT->m_CommandsLoading.size())
{
void* buf = m_pRT->m_Commands[m_pRT->m_nCurThreadFill].Grow(m_pRT->m_CommandsLoading.size());
memcpy(buf, &m_pRT->m_CommandsLoading[0], m_pRT->m_CommandsLoading.size());
m_pRT->m_CommandsLoading.Free();
}
#endif // !defined(STRIP_RENDER_THREAD)
}
}
//////////////////////////////////////////////////////////////////////////