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.
1089 lines
34 KiB
C++
1089 lines
34 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 "Shaders/CShader.h"
|
|
#include "DevBuffer.h"
|
|
#include "RenderCapabilities.h"
|
|
#include <AzCore/std/string/conversions.h>
|
|
#include <I3DEngine.h>
|
|
#include <IResourceManager.h>
|
|
#include <AzFramework/Archive/IArchive.h>
|
|
|
|
//==================================================================================
|
|
|
|
bool CShader::FXSetTechnique(const CCryNameTSCRC& Name)
|
|
{
|
|
assert (gRenDev->m_pRT->IsRenderThread());
|
|
|
|
uint32 i;
|
|
SShaderTechnique* pTech = NULL;
|
|
for (i = 0; i < m_HWTechniques.Num(); i++)
|
|
{
|
|
pTech = m_HWTechniques[i];
|
|
if (pTech && Name == pTech->m_NameCRC)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
CRenderer* rd = gRenDev;
|
|
|
|
if (i == m_HWTechniques.Num())
|
|
{ // not found and not set
|
|
rd->m_RP.m_nShaderTechnique = -1;
|
|
rd->m_RP.m_pCurTechnique = NULL;
|
|
return false;
|
|
}
|
|
|
|
rd->m_RP.m_pShader = this;
|
|
rd->m_RP.m_nShaderTechnique = i;
|
|
rd->m_RP.m_pCurTechnique = m_HWTechniques[i];
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CShader::FXSetCSFloat(const CCryNameR& NameParam, const Vec4 fParams[], int nParams)
|
|
{
|
|
CRenderer* rd = gRenDev;
|
|
if (!rd->m_RP.m_pShader || !rd->m_RP.m_pCurTechnique)
|
|
{
|
|
return false;
|
|
}
|
|
SShaderPass* pPass = rd->m_RP.m_pCurPass;
|
|
if (!pPass)
|
|
{
|
|
return false;
|
|
}
|
|
CHWShader_D3D* curCS = (CHWShader_D3D*)pPass->m_CShader;
|
|
if (!curCS)
|
|
{
|
|
return false;
|
|
}
|
|
SCGBind* pBind = curCS->mfGetParameterBind(NameParam);
|
|
if (!pBind)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const AZ::u32 registerCountMax = curCS->m_pCurInst->m_nMaxVecs[pBind->m_BindingSlot];
|
|
AzRHI::ConstantBufferCache::GetInstance().WriteConstants(eHWSC_Compute, pBind, fParams, nParams, registerCountMax);
|
|
return true;
|
|
}
|
|
|
|
bool CShader::FXSetCSFloat(const char* NameParam, const Vec4 fParams[], int nParams)
|
|
{
|
|
return FXSetCSFloat(CCryNameR(NameParam), fParams, nParams);
|
|
}
|
|
|
|
bool CShader::FXSetPSFloat(const CCryNameR& NameParam, const Vec4* fParams, int nParams)
|
|
{
|
|
CRenderer* rd = gRenDev;
|
|
if (!rd->m_RP.m_pShader || !rd->m_RP.m_pCurTechnique)
|
|
{
|
|
return false;
|
|
}
|
|
SShaderPass* pPass = rd->m_RP.m_pCurPass;
|
|
if (!pPass)
|
|
{
|
|
return false;
|
|
}
|
|
CHWShader_D3D* curPS = (CHWShader_D3D*)pPass->m_PShader;
|
|
if (!curPS)
|
|
{
|
|
return false;
|
|
}
|
|
SCGBind* pBind = curPS->mfGetParameterBind(NameParam);
|
|
if (!pBind)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const AZ::u32 registerCountMax = curPS->m_pCurInst->m_nMaxVecs[pBind->m_BindingSlot];
|
|
AzRHI::ConstantBufferCache::GetInstance().WriteConstants(eHWSC_Pixel, pBind, fParams, nParams, registerCountMax);
|
|
return true;
|
|
}
|
|
|
|
bool CShader::FXSetPSFloat(const char* NameParam, const Vec4* fParams, int nParams)
|
|
{
|
|
return FXSetPSFloat(CCryNameR(NameParam), fParams, nParams);
|
|
}
|
|
|
|
bool CShader::FXSetVSFloat(const CCryNameR& NameParam, const Vec4* fParams, int nParams)
|
|
{
|
|
CRenderer* rd = gRenDev;
|
|
if (!rd->m_RP.m_pShader || !rd->m_RP.m_pCurTechnique)
|
|
{
|
|
return false;
|
|
}
|
|
SShaderPass* pPass = rd->m_RP.m_pCurPass;
|
|
if (!pPass)
|
|
{
|
|
return false;
|
|
}
|
|
CHWShader_D3D* curVS = (CHWShader_D3D*)pPass->m_VShader;
|
|
if (!curVS)
|
|
{
|
|
return false;
|
|
}
|
|
SCGBind* pBind = curVS->mfGetParameterBind(NameParam);
|
|
if (!pBind)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const AZ::u32 registerCountMax = curVS->m_pCurInst->m_nMaxVecs[pBind->m_BindingSlot];
|
|
AzRHI::ConstantBufferCache::GetInstance().WriteConstants(eHWSC_Vertex, pBind, fParams, nParams, registerCountMax);
|
|
return true;
|
|
}
|
|
|
|
bool CShader::FXSetVSFloat(const char* NameParam, const Vec4* fParams, int nParams)
|
|
{
|
|
return FXSetVSFloat(CCryNameR(NameParam), fParams, nParams);
|
|
}
|
|
|
|
bool CShader::FXSetGSFloat(const CCryNameR& NameParam, const Vec4* fParams, int nParams)
|
|
{
|
|
CRenderer* rd = gRenDev;
|
|
if (!rd->m_RP.m_pShader || !rd->m_RP.m_pCurTechnique)
|
|
{
|
|
return false;
|
|
}
|
|
SShaderPass* pPass = rd->m_RP.m_pCurPass;
|
|
if (!pPass)
|
|
{
|
|
return false;
|
|
}
|
|
CHWShader_D3D* curGS = (CHWShader_D3D*)pPass->m_GShader;
|
|
if (!curGS)
|
|
{
|
|
return false;
|
|
}
|
|
SCGBind* pBind = curGS->mfGetParameterBind(NameParam);
|
|
if (!pBind)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const AZ::u32 registerCountMax = curGS->m_pCurInst->m_nMaxVecs[pBind->m_BindingSlot];
|
|
AzRHI::ConstantBufferCache::GetInstance().WriteConstants(eHWSC_Geometry, pBind, fParams, nParams, registerCountMax);
|
|
return true;
|
|
}
|
|
|
|
bool CShader::FXSetGSFloat(const char* NameParam, const Vec4* fParams, int nParams)
|
|
{
|
|
return FXSetGSFloat(CCryNameR(NameParam), fParams, nParams);
|
|
}
|
|
|
|
bool CShader::FXBegin(uint32* uiPassCount, uint32 nFlags)
|
|
{
|
|
CRenderer* rd = gRenDev;
|
|
if (!rd->m_RP.m_pShader || !rd->m_RP.m_pCurTechnique || !rd->m_RP.m_pCurTechnique->m_Passes.Num())
|
|
{
|
|
return false;
|
|
}
|
|
*uiPassCount = rd->m_RP.m_pCurTechnique->m_Passes.Num();
|
|
rd->m_RP.m_nFlagsShaderBegin = nFlags;
|
|
rd->m_RP.m_pCurPass = &rd->m_RP.m_pCurTechnique->m_Passes[0];
|
|
return true;
|
|
}
|
|
|
|
bool CShader::FXBeginPass(uint32 uiPass)
|
|
{
|
|
FUNCTION_PROFILER_RENDER_FLAT
|
|
CD3D9Renderer* rd = gcpRendD3D;
|
|
if (!rd->m_RP.m_pShader || !rd->m_RP.m_pCurTechnique || uiPass >= rd->m_RP.m_pCurTechnique->m_Passes.Num())
|
|
{
|
|
return false;
|
|
}
|
|
rd->m_RP.m_pCurPass = &rd->m_RP.m_pCurTechnique->m_Passes[uiPass];
|
|
SShaderPass* pPass = rd->m_RP.m_pCurPass;
|
|
//assert (pPass->m_VShader && pPass->m_PShader);
|
|
//if (!pPass->m_VShader || !pPass->m_PShader)
|
|
// return false;
|
|
CHWShader_D3D* curVS = (CHWShader_D3D*)pPass->m_VShader;
|
|
CHWShader_D3D* curPS = (CHWShader_D3D*)pPass->m_PShader;
|
|
CHWShader_D3D* curGS = (CHWShader_D3D*)pPass->m_GShader;
|
|
CHWShader_D3D* curCS = (CHWShader_D3D*)pPass->m_CShader;
|
|
|
|
bool bResult = true;
|
|
|
|
// Set Pixel-shader and all associated textures
|
|
if (curPS)
|
|
{
|
|
if (rd->m_RP.m_nFlagsShaderBegin & FEF_DONTSETTEXTURES)
|
|
{
|
|
bResult &= curPS->mfSet(0);
|
|
}
|
|
else
|
|
{
|
|
bResult &= curPS->mfSet(HWSF_SETTEXTURES);
|
|
}
|
|
curPS->UpdatePerInstanceConstantBuffer();
|
|
}
|
|
// Set Vertex-shader
|
|
if (curVS)
|
|
{
|
|
// Allow vertex shaders to bind textures.
|
|
// Some existing vertex shaders do try to read textures, for example the shader function GetVolumetricFogAnalyticalColor
|
|
if (rd->m_RP.m_nFlagsShaderBegin & FEF_DONTSETTEXTURES)
|
|
{
|
|
bResult &= curVS->mfSet(0);
|
|
}
|
|
else
|
|
{
|
|
bResult &= curVS->mfSet(HWSF_SETTEXTURES);
|
|
}
|
|
|
|
curVS->UpdatePerInstanceConstantBuffer();
|
|
}
|
|
|
|
// Set Geometry-shader
|
|
if (curGS)
|
|
{
|
|
if (rd->m_RP.m_nFlagsShaderBegin & FEF_DONTSETTEXTURES)
|
|
{
|
|
bResult &= curGS->mfSet(0);
|
|
}
|
|
else
|
|
{
|
|
bResult &= curGS->mfSet(HWSF_SETTEXTURES);
|
|
}
|
|
|
|
curGS->UpdatePerInstanceConstantBuffer();
|
|
}
|
|
else
|
|
{
|
|
CHWShader_D3D::mfBindGS(NULL, NULL);
|
|
}
|
|
|
|
// Set Compute-shader
|
|
if (curCS)
|
|
{
|
|
if (rd->m_RP.m_nFlagsShaderBegin & FEF_DONTSETTEXTURES)
|
|
{
|
|
bResult &= curCS->mfSet(0);
|
|
}
|
|
else
|
|
{
|
|
bResult &= curCS->mfSet(HWSF_SETTEXTURES);
|
|
}
|
|
curCS->UpdatePerInstanceConstantBuffer();
|
|
}
|
|
else
|
|
{
|
|
CHWShader_D3D::mfBindCS(NULL, NULL);
|
|
}
|
|
|
|
if (!(rd->m_RP.m_nFlagsShaderBegin & FEF_DONTSETSTATES))
|
|
{
|
|
rd->FX_SetState(pPass->m_RenderState);
|
|
if (pPass->m_eCull != -1)
|
|
{
|
|
rd->D3DSetCull((ECull)pPass->m_eCull);
|
|
}
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
bool CShader::FXEndPass()
|
|
{
|
|
CRenderer* rd = gRenDev;
|
|
if (!rd->m_RP.m_pShader || !rd->m_RP.m_pCurTechnique || !rd->m_RP.m_pCurTechnique->m_Passes.Num())
|
|
{
|
|
return false;
|
|
}
|
|
rd->m_RP.m_pCurPass = NULL;
|
|
return true;
|
|
}
|
|
|
|
bool CShader::FXEnd()
|
|
{
|
|
CRenderer* rd = gRenDev;
|
|
if (!rd->m_RP.m_pShader || !rd->m_RP.m_pCurTechnique)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool CShader::FXCommit([[maybe_unused]] const uint32 nFlags)
|
|
{
|
|
gcpRendD3D->FX_Commit();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void* CHWShader_D3D::GetVSDataForDecl(const D3D11_INPUT_ELEMENT_DESC* pDecl, int nCount, int& nDataSize)
|
|
{
|
|
nDataSize = 0;
|
|
CShader* pSh = CShaderMan::s_ShaderFPEmu;
|
|
if (!pSh || !pSh->m_HWTechniques.Num() || !nCount)
|
|
{
|
|
return NULL;
|
|
}
|
|
uint32 i, j;
|
|
|
|
SShaderTechnique* pTech = NULL;
|
|
for (i = 0; i < pSh->m_HWTechniques.Num(); i++)
|
|
{
|
|
if (!azstricmp(pSh->m_HWTechniques[i]->m_NameStr.c_str(), "InputLayout"))
|
|
{
|
|
pTech = pSh->m_HWTechniques[i];
|
|
break;
|
|
}
|
|
}
|
|
if (!pTech || !pTech->m_Passes.Num())
|
|
{
|
|
return NULL;
|
|
}
|
|
SShaderPass& Pass = pTech->m_Passes[0];
|
|
CHWShader_D3D* pVS = (CHWShader_D3D*)Pass.m_VShader;
|
|
if (!pVS)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
uint32 nMask = 0;
|
|
//m_RP.m_FlagsShader_LT = m_RP.m_TI[m_RP.m_nProcessThreadID].m_eCurColorOp[0] | (m_RP.m_TI[m_RP.m_nProcessThreadID].m_eCurAlphaOp[0] << 8) | (m_RP.m_TI[m_RP.m_nProcessThreadID].m_eCurColorArg[0] << 16) | (m_RP.m_TI[m_RP.m_nProcessThreadID].m_eCurAlphaArg[0] << 24);
|
|
|
|
for (i = 0; i < nCount; i++)
|
|
{
|
|
const D3D11_INPUT_ELEMENT_DESC& Desc = pDecl[i];
|
|
if (Desc.InputSlot != 0)
|
|
{
|
|
nMask |= 1 << Desc.InputSlot;
|
|
if (nMask & VSM_TANGENTS)
|
|
{
|
|
for (j = 0; j < nCount; j++)
|
|
{
|
|
const D3D11_INPUT_ELEMENT_DESC& Desc2 = pDecl[j];
|
|
if (!strcmp(Desc2.SemanticName, "BITANGENT") || !strcmp(Desc2.SemanticName, "BINORMAL"))
|
|
{
|
|
nMask |= (1 << VSF_QTANGENTS);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
if (!strcmp(Desc.SemanticName, "POSITION"))
|
|
{
|
|
if (Desc.Format == DXGI_FORMAT_R32G32_FLOAT)
|
|
{
|
|
nMask |= 0 << 8;
|
|
}
|
|
else
|
|
if (Desc.Format == DXGI_FORMAT_R32G32B32_FLOAT)
|
|
{
|
|
nMask |= 1 << 8;
|
|
}
|
|
else
|
|
if (Desc.Format == DXGI_FORMAT_R16G16B16A16_FLOAT || Desc.Format == DXGI_FORMAT_R32G32B32A32_FLOAT)
|
|
{
|
|
nMask |= 2 << 8;
|
|
}
|
|
else
|
|
{
|
|
assert(0);
|
|
}
|
|
}
|
|
else
|
|
if (!strcmp(Desc.SemanticName, "TEXCOORD"))
|
|
{
|
|
int nShift = 0;
|
|
if (Desc.SemanticIndex == 0)
|
|
{
|
|
nMask |= eCA_Texture << 16;
|
|
nShift = 10;
|
|
if (Desc.Format == DXGI_FORMAT_R32G32_FLOAT || Desc.Format == DXGI_FORMAT_R16G16_FLOAT)
|
|
{
|
|
nMask |= 0 << nShift;
|
|
}
|
|
else
|
|
if (Desc.Format == DXGI_FORMAT_R32G32B32_FLOAT)
|
|
{
|
|
nMask |= 1 << nShift;
|
|
}
|
|
else
|
|
if (Desc.Format == DXGI_FORMAT_R16G16B16A16_FLOAT || Desc.Format == DXGI_FORMAT_R32G32B32A32_FLOAT)
|
|
{
|
|
nMask |= 2 << nShift;
|
|
}
|
|
else
|
|
{
|
|
assert(0);
|
|
}
|
|
}
|
|
else
|
|
if (Desc.SemanticIndex == 1)
|
|
{
|
|
if (nMask & (eCA_Constant << 19))
|
|
{
|
|
// PSIZE and TEX1 used together
|
|
nMask &= ~(0x7 << 19);
|
|
nMask |= eCA_Previous << 19;
|
|
}
|
|
else
|
|
{
|
|
nMask |= eCA_Texture1 << 19;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
assert(0);
|
|
}
|
|
}
|
|
else
|
|
if (!strcmp(Desc.SemanticName, "COLOR"))
|
|
{
|
|
int nShift = 0;
|
|
if (Desc.SemanticIndex == 0)
|
|
{
|
|
nMask |= eCA_Diffuse << 24;
|
|
nShift = 12;
|
|
if (Desc.Format == DXGI_FORMAT_R32G32B32_FLOAT)
|
|
{
|
|
nMask |= 1 << nShift;
|
|
}
|
|
else
|
|
if (Desc.Format == DXGI_FORMAT_R8G8B8A8_UNORM || Desc.Format == DXGI_FORMAT_R32G32B32A32_FLOAT)
|
|
{
|
|
nMask |= 2 << nShift;
|
|
}
|
|
else
|
|
{
|
|
assert(0);
|
|
}
|
|
}
|
|
else
|
|
if (Desc.SemanticIndex == 1)
|
|
{
|
|
nMask |= eCA_Specular << 27;
|
|
}
|
|
else
|
|
{
|
|
assert(0);
|
|
}
|
|
}
|
|
else
|
|
if (!strcmp(Desc.SemanticName, "NORMAL"))
|
|
{
|
|
if (Desc.SemanticIndex == 0)
|
|
{
|
|
nMask |= eCA_Normal << 27;
|
|
}
|
|
else
|
|
{
|
|
assert(0);
|
|
}
|
|
//assert (Desc.Format == DXGI_FORMAT_R8G8B8A8_UNORM);
|
|
}
|
|
else
|
|
if (!strcmp(Desc.SemanticName, "PSIZE"))
|
|
{
|
|
if (Desc.SemanticIndex == 0)
|
|
{
|
|
if (nMask & (eCA_Texture1 << 19))
|
|
{
|
|
// PSIZE and TEX1 used together
|
|
nMask &= ~(0x7 << 19);
|
|
nMask |= eCA_Previous << 19;
|
|
}
|
|
else
|
|
{
|
|
nMask |= eCA_Constant << 19;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
assert(0);
|
|
}
|
|
assert (Desc.Format == DXGI_FORMAT_R32G32B32A32_FLOAT);
|
|
}
|
|
else
|
|
{
|
|
assert(0);
|
|
}
|
|
}
|
|
|
|
SShaderCombIdent Ident;
|
|
Ident.m_LightMask = nMask;
|
|
Ident.m_RTMask = 0;
|
|
Ident.m_MDMask = 0;
|
|
Ident.m_MDVMask = 0;
|
|
Ident.m_GLMask = 0;
|
|
Ident.m_STMask = 0;
|
|
|
|
SHWSInstance* pI = pVS->m_pCurInst;
|
|
|
|
uint32 nFlags = HWSF_STOREDATA;
|
|
SHWSInstance* pInst = pVS->mfGetInstance(pSh, Ident, nFlags);
|
|
if (!pVS->mfCheckActivation(pSh, pInst, nFlags))
|
|
{
|
|
pVS->m_pCurInst = pI;
|
|
return NULL;
|
|
}
|
|
pVS->m_pCurInst = pI;
|
|
|
|
nDataSize = pInst->m_nDataSize;
|
|
return pInst->m_pShaderData;
|
|
}
|
|
|
|
//===================================================================================
|
|
|
|
void CRenderer::RefreshSystemShaders()
|
|
{
|
|
// make sure all system shaders are properly refreshed during loading!
|
|
#if defined(FEATURE_SVO_GI)
|
|
gRenDev->m_cEF.mfRefreshSystemShader("Total_Illumination", CShaderMan::s_ShaderSVOGI);
|
|
#endif
|
|
gRenDev->m_cEF.mfRefreshSystemShader("Common", CShaderMan::s_ShaderCommon);
|
|
gRenDev->m_cEF.mfRefreshSystemShader("Debug", CShaderMan::s_ShaderDebug);
|
|
gRenDev->m_cEF.mfRefreshSystemShader("DeferredCaustics", CShaderMan::s_ShaderDeferredCaustics);
|
|
gRenDev->m_cEF.mfRefreshSystemShader("DeferredRain", CShaderMan::s_ShaderDeferredRain);
|
|
gRenDev->m_cEF.mfRefreshSystemShader("DeferredSnow", CShaderMan::s_ShaderDeferredSnow);
|
|
gRenDev->m_cEF.mfRefreshSystemShader("DeferredShading", CShaderMan::s_shDeferredShading);
|
|
gRenDev->m_cEF.mfRefreshSystemShader("DepthOfField", CShaderMan::s_shPostDepthOfField);
|
|
gRenDev->m_cEF.mfRefreshSystemShader("DXTCompress", CShaderMan::s_ShaderDXTCompress);
|
|
gRenDev->m_cEF.mfRefreshSystemShader("LensOptics", CShaderMan::s_ShaderLensOptics);
|
|
gRenDev->m_cEF.mfRefreshSystemShader("SoftOcclusionQuery", CShaderMan::s_ShaderSoftOcclusionQuery);
|
|
gRenDev->m_cEF.mfRefreshSystemShader("MotionBlur", CShaderMan::s_shPostMotionBlur);
|
|
gRenDev->m_cEF.mfRefreshSystemShader("OcclusionTest", CShaderMan::s_ShaderOcclTest);
|
|
gRenDev->m_cEF.mfRefreshSystemShader("PostEffectsGame", CShaderMan::s_shPostEffectsGame);
|
|
gRenDev->m_cEF.mfRefreshSystemShader("ShadowBlur", CShaderMan::s_ShaderShadowBlur);
|
|
gRenDev->m_cEF.mfRefreshSystemShader("Stereo", CShaderMan::s_ShaderStereo);
|
|
gRenDev->m_cEF.mfRefreshSystemShader("Sunshafts", CShaderMan::s_shPostSunShafts);
|
|
gRenDev->m_cEF.mfRefreshSystemShader("Fur", CShaderMan::s_ShaderFur);
|
|
}
|
|
|
|
bool CD3D9Renderer::FX_SetFPMode()
|
|
{
|
|
assert (gRenDev->m_pRT->IsRenderThread());
|
|
|
|
if (!(m_RP.m_TI[m_RP.m_nProcessThreadID].m_PersFlags & RBPF_FP_DIRTY) && CShaderMan::s_ShaderFPEmu == m_RP.m_pShader)
|
|
{
|
|
return true;
|
|
}
|
|
if (m_bDeviceLost)
|
|
{
|
|
return false;
|
|
}
|
|
m_RP.m_TI[m_RP.m_nProcessThreadID].m_PersFlags &= ~RBPF_FP_DIRTY;
|
|
m_RP.m_pCurObject = m_RP.m_pIdendityRenderObject;
|
|
CShader* pSh = CShaderMan::s_ShaderFPEmu;
|
|
if (!pSh || !pSh->m_HWTechniques.Num())
|
|
{
|
|
return false;
|
|
}
|
|
m_RP.m_FlagsShader_LT = m_RP.m_TI[m_RP.m_nProcessThreadID].m_eCurColorOp | (m_RP.m_TI[m_RP.m_nProcessThreadID].m_eCurAlphaOp << 8) | (m_RP.m_TI[m_RP.m_nProcessThreadID].m_eCurColorArg << 16) | (m_RP.m_TI[m_RP.m_nProcessThreadID].m_eCurAlphaArg << 24);
|
|
m_RP.m_FlagsShader_LT |= (m_RP.m_TI[m_RP.m_nProcessThreadID].m_sRGBWrite ? 1 : 0) << 22;
|
|
|
|
if (CTexture::s_TexStages[0].m_DevTexture && CTexture::s_TexStages[0].m_DevTexture->IsCube())
|
|
{
|
|
m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_CUBEMAP0];
|
|
}
|
|
else
|
|
{
|
|
m_RP.m_FlagsShader_RT &= ~g_HWSR_MaskBit[HWSR_CUBEMAP0];
|
|
}
|
|
|
|
m_RP.m_pShader = pSh;
|
|
m_RP.m_pCurTechnique = pSh->m_HWTechniques[0];
|
|
|
|
bool bRes = pSh->FXBegin(&m_RP.m_nNumRendPasses, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
|
|
if (!bRes)
|
|
{
|
|
return false;
|
|
}
|
|
bRes = pSh->FXBeginPass(0);
|
|
FX_Commit();
|
|
return bRes;
|
|
}
|
|
|
|
bool CD3D9Renderer::FX_SetUIMode()
|
|
{
|
|
assert (gRenDev->m_pRT->IsRenderThread());
|
|
|
|
if (!(m_RP.m_TI[m_RP.m_nProcessThreadID].m_PersFlags & RBPF_FP_DIRTY) && CShaderMan::s_ShaderUI == m_RP.m_pShader)
|
|
{
|
|
return true;
|
|
}
|
|
if (m_bDeviceLost)
|
|
{
|
|
return false;
|
|
}
|
|
m_RP.m_TI[m_RP.m_nProcessThreadID].m_PersFlags &= ~RBPF_FP_DIRTY;
|
|
m_RP.m_pCurObject = m_RP.m_pIdendityRenderObject;
|
|
CShader* pSh = CShaderMan::s_ShaderUI;
|
|
if (!pSh || !pSh->m_HWTechniques.Num())
|
|
{
|
|
return false;
|
|
}
|
|
m_RP.m_FlagsShader_LT = m_RP.m_TI[m_RP.m_nProcessThreadID].m_eCurColorOp | (m_RP.m_TI[m_RP.m_nProcessThreadID].m_eCurAlphaOp << 8) | (m_RP.m_TI[m_RP.m_nProcessThreadID].m_eCurColorArg << 16) | (m_RP.m_TI[m_RP.m_nProcessThreadID].m_eCurAlphaArg << 24);
|
|
m_RP.m_FlagsShader_LT |= (m_RP.m_TI[m_RP.m_nProcessThreadID].m_sRGBWrite ? 1 : 0) << 22;
|
|
|
|
if (CTexture::s_TexStages[0].m_DevTexture && CTexture::s_TexStages[0].m_DevTexture->IsCube())
|
|
{
|
|
m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_CUBEMAP0];
|
|
}
|
|
else
|
|
{
|
|
m_RP.m_FlagsShader_RT &= ~g_HWSR_MaskBit[HWSR_CUBEMAP0];
|
|
}
|
|
|
|
m_RP.m_pShader = pSh;
|
|
m_RP.m_pCurTechnique = pSh->m_HWTechniques[0];
|
|
|
|
bool bRes = pSh->FXBegin(&m_RP.m_nNumRendPasses, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
|
|
if (!bRes)
|
|
{
|
|
return false;
|
|
}
|
|
bRes = pSh->FXBeginPass(0);
|
|
FX_Commit();
|
|
return bRes;
|
|
}
|
|
|
|
void CShaderMan::mfCheckObjectDependParams(std::vector<SCGParam>& PNoObj, std::vector<SCGParam>& PObj, [[maybe_unused]] EHWShaderClass eSH, [[maybe_unused]] CShader* pFXShader)
|
|
{
|
|
if (!PNoObj.size())
|
|
{
|
|
return;
|
|
}
|
|
uint32 i;
|
|
for (i = 0; i < PNoObj.size(); i++)
|
|
{
|
|
SCGParam* prNoObj = &PNoObj[i];
|
|
if ((prNoObj->m_eCGParamType & 0xff) == ECGP_PM_Tweakable)
|
|
{
|
|
int nType = prNoObj->m_eCGParamType & 0xff;
|
|
prNoObj->m_eCGParamType = (ECGParam)nType;
|
|
}
|
|
|
|
if (prNoObj->m_Flags & PF_INSTANCE)
|
|
{
|
|
PObj.push_back(PNoObj[i]);
|
|
PNoObj.erase(PNoObj.begin() + i);
|
|
i--;
|
|
}
|
|
else
|
|
if (prNoObj->m_Flags & PF_MATERIAL)
|
|
{
|
|
PNoObj.erase(PNoObj.begin() + i);
|
|
i--;
|
|
}
|
|
}
|
|
if (PObj.size())
|
|
{
|
|
int n = -1;
|
|
for (i = 0; i < PObj.size(); i++)
|
|
{
|
|
if (PObj[i].m_eCGParamType == ECGP_Matr_PI_ViewProj)
|
|
{
|
|
n = i;
|
|
break;
|
|
}
|
|
}
|
|
if (n > 0)
|
|
{
|
|
SCGParam pr = PObj[n];
|
|
PObj[n] = PObj[0];
|
|
PObj[0] = pr;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CShaderMan::mfPreactivate2(CResFileLookupDataMan& LevelLookup,
|
|
const AZStd::string& pathPerLevel, const AZStd::string& pathGlobal,
|
|
bool bVS, bool bPersistent)
|
|
{
|
|
bool bRes = true;
|
|
|
|
AZStd::string allFilesPath = pathPerLevel + "/*.*";
|
|
|
|
AZ::IO::ArchiveFileIterator handle = gEnv->pCryPak->FindFirst(allFilesPath.c_str());
|
|
if (!handle)
|
|
{
|
|
return bRes;
|
|
}
|
|
|
|
do
|
|
{
|
|
if (handle.m_filename.front() == '.')
|
|
{
|
|
continue;
|
|
}
|
|
|
|
AZStd::string fileInfoPerLevel = AZStd::string::format("%s/%.*s", pathPerLevel.c_str(), aznumeric_cast<int>(handle.m_filename.size()), handle.m_filename.data());
|
|
AZStd::string fileInfoGlobal = AZStd::string::format("%s/%.*s", pathGlobal.c_str(), aznumeric_cast<int>(handle.m_filename.size()), handle.m_filename.data());
|
|
|
|
if((handle.m_fileDesc.nAttrib & AZ::IO::FileDesc::Attribute::Subdirectory) == AZ::IO::FileDesc::Attribute::Subdirectory)
|
|
{
|
|
bRes &= mfPreactivate2(LevelLookup, fileInfoPerLevel, fileInfoGlobal, bVS, bPersistent);
|
|
continue;
|
|
}
|
|
CResFile* pRes = new CResFile(fileInfoPerLevel.c_str());
|
|
int bR = pRes ? pRes->mfOpen(RA_READ, &LevelLookup) : 0;
|
|
if (!bR)
|
|
{
|
|
Warning("ShaderCache rejected (damaged?) file %s: %s", fileInfoPerLevel.c_str(), pRes->mfGetError() ? pRes->mfGetError() : "<unknown reason>");
|
|
bRes = false;
|
|
SAFE_DELETE(pRes);
|
|
continue;
|
|
}
|
|
|
|
SResFileLookupData* pLookupGlobal = gRenDev->m_cEF.m_ResLookupDataMan[CACHE_READONLY].GetData(fileInfoGlobal.c_str());
|
|
if (!pLookupGlobal)
|
|
{
|
|
SAFE_DELETE(pRes);
|
|
continue;
|
|
}
|
|
SResFileLookupData* pLookupLevel = NULL;
|
|
if (!bPersistent)
|
|
{
|
|
CCryNameTSCRC name = LevelLookup.AdjustName(pRes->mfGetFileName());
|
|
pLookupLevel = LevelLookup.GetData(name);
|
|
}
|
|
else
|
|
{
|
|
// Startup cache
|
|
const char* szName = pRes->mfGetFileName();
|
|
CCryNameTSCRC name;
|
|
if (_strnicmp(szName, "ShaderCache/", 12) == 0)
|
|
{
|
|
stack_string sName = stack_string(g_shaderCache) + stack_string(&szName[12]);
|
|
name = sName.c_str();
|
|
}
|
|
else if (_strnicmp(szName, g_shaderCache, 14) == 0)
|
|
{
|
|
name = LevelLookup.AdjustName(pRes->mfGetFileName());
|
|
}
|
|
else
|
|
{
|
|
Warning("Wrong virtual directory in ShaderCacheStartup.pak");
|
|
SAFE_DELETE(pRes);
|
|
continue;
|
|
}
|
|
pLookupLevel = LevelLookup.GetData(name);
|
|
}
|
|
if (!pLookupLevel)
|
|
{
|
|
SAFE_DELETE(pRes);
|
|
continue;
|
|
}
|
|
if (pLookupLevel->m_CacheMajorVer != pLookupGlobal->m_CacheMajorVer || pLookupLevel->m_CacheMinorVer != pLookupGlobal->m_CacheMinorVer || pLookupLevel->m_CRC32 != pLookupGlobal->m_CRC32)
|
|
{
|
|
SAFE_DELETE(pRes);
|
|
continue;
|
|
}
|
|
const char* s = fileInfoPerLevel.c_str();
|
|
const uint32 nLen = strlen(s);
|
|
int nStart = -1;
|
|
int nEnd = -1;
|
|
bool bPC = false;
|
|
for (uint32 i = 0; i < nLen; i++)
|
|
{
|
|
uint32 n = nLen - i - 1;
|
|
char c = s[n];
|
|
if (c == '.')
|
|
{
|
|
nEnd = n;
|
|
}
|
|
else
|
|
if (!bPC)
|
|
{
|
|
if (c == '@' || c == '/')
|
|
{
|
|
bPC = true;
|
|
}
|
|
}
|
|
else
|
|
if (c == '/')
|
|
{
|
|
nStart = n + 1;
|
|
break;
|
|
}
|
|
}
|
|
if (nStart < 0 || nEnd < 0)
|
|
{
|
|
SAFE_DELETE(pRes);
|
|
continue;
|
|
}
|
|
char str[128];
|
|
memcpy(str, &s[nStart], nEnd - nStart);
|
|
str[nEnd - nStart] = 0;
|
|
CCryNameTSCRC Name = str;
|
|
FXCompressedShadersItor it = CHWShader::m_CompressedShaders.find(Name);
|
|
SHWActivatedShader* pAS = NULL;
|
|
if (it == CHWShader::m_CompressedShaders.end())
|
|
{
|
|
pAS = new SHWActivatedShader;
|
|
pAS->m_bPersistent = bPersistent;
|
|
CHWShader::m_CompressedShaders.insert(FXCompressedShadersItor::value_type(Name, pAS));
|
|
}
|
|
else
|
|
{
|
|
pAS = it->second;
|
|
}
|
|
ResDir* pDir = pRes->mfGetDirectory();
|
|
for (uint32 i = 0; i < pDir->size(); i++)
|
|
{
|
|
SDirEntry& DE = (*pDir)[i];
|
|
if IsCVarConstAccess(constexpr) (CRenderer::CV_r_shadersdebug == 3 || CRenderer::CV_r_shadersdebug == 4)
|
|
{
|
|
iLog->Log("---Cache: PreactivateForLevel %s': 0x%x", pRes->mfGetFileName(), DE.Name.get());
|
|
}
|
|
|
|
FXCompressedShaderRemapItor itR = pAS->m_Remap.find(DE.Name);
|
|
uint32 nIDDev = DE.Name.get();
|
|
assert(DE.offset > 0);
|
|
if (itR == pAS->m_Remap.end())
|
|
{
|
|
pAS->m_Remap.insert(FXCompressedShaderRemapItor::value_type(DE.Name, nIDDev));
|
|
itR = pAS->m_Remap.find(DE.Name);
|
|
}
|
|
FXCompressedShaderItor itS = pAS->m_CompressedShaders.find(itR->second);
|
|
if (itS == pAS->m_CompressedShaders.end())
|
|
{
|
|
uint32 nSizeCompressed;
|
|
uint32 nSizeDecompressed;
|
|
byte* pDataCompressed = pRes->mfFileReadCompressed(&DE, nSizeDecompressed, nSizeCompressed);
|
|
if (!pDataCompressed)
|
|
{
|
|
SAFE_DELETE_ARRAY(pDataCompressed);
|
|
bRes = false;
|
|
continue;
|
|
}
|
|
|
|
// only store compressed data - don't store token data for example because this is not compressed
|
|
if (nSizeCompressed == nSizeDecompressed)
|
|
{
|
|
SAFE_DELETE_ARRAY(pDataCompressed);
|
|
continue;
|
|
}
|
|
|
|
if (nSizeCompressed > std::numeric_limits<uint32>::max() || nSizeDecompressed > std::numeric_limits<uint32>::max())
|
|
{
|
|
CryFatalError("size of shader %s (compressed: %u, decompressed: %u) is too big to be stored in uint32", pRes->mfGetFileName(), (uint)nSizeCompressed, (uint)nSizeDecompressed);
|
|
SAFE_DELETE_ARRAY(pDataCompressed);
|
|
bRes = false;
|
|
continue;
|
|
}
|
|
|
|
SCompressedData CD;
|
|
CD.m_nSizeCompressedShader = nSizeCompressed;
|
|
CD.m_nSizeDecompressedShader = nSizeDecompressed;
|
|
CD.m_pCompressedShader = pDataCompressed;
|
|
assert (CD.m_nSizeCompressedShader != CD.m_nSizeDecompressedShader);
|
|
|
|
/*byte *pData = new byte[CD.m_nSizeDecompressedShader+1];
|
|
pData[CD.m_nSizeDecompressedShader] = 0xaa;
|
|
Decodem(CD.m_pCompressedShader, pData, CD.m_nSizeCompressedShader);
|
|
assert(pData[CD.m_nSizeDecompressedShader] == 0xaa);
|
|
SShaderCacheHeaderItem *pIt = (SShaderCacheHeaderItem *)pData;
|
|
if (CParserBin::m_bEndians)
|
|
SwapEndian(*pIt, eBigEndian);
|
|
SAFE_DELETE_ARRAY(pData);*/
|
|
|
|
pAS->m_CompressedShaders.insert(FXCompressedShaderItor::value_type(nIDDev, CD));
|
|
}
|
|
else
|
|
{
|
|
#ifdef _DEBUG
|
|
uint32 nSizeCompressed;
|
|
uint32 nSizeDecompressed;
|
|
byte* pDataCompressed = pRes->mfFileReadCompressed(&DE, nSizeDecompressed, nSizeCompressed);
|
|
assert(nSizeCompressed < 65536 && nSizeDecompressed < 65536);
|
|
assert(pDataCompressed);
|
|
if (pDataCompressed)
|
|
{
|
|
SCompressedData& CD1 = itS->second;
|
|
assert(CD1.m_nSizeCompressedShader == nSizeCompressed);
|
|
SAFE_DELETE_ARRAY(pDataCompressed);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
SAFE_DELETE(pRes);
|
|
} while (handle = gEnv->pCryPak->FindNext(handle));
|
|
|
|
gEnv->pCryPak->FindClose (handle);
|
|
|
|
return bRes;
|
|
}
|
|
|
|
int SHWActivatedShader::Size()
|
|
{
|
|
int nSize = sizeof(SHWActivatedShader);
|
|
nSize += sizeOfMap(m_CompressedShaders);
|
|
nSize += sizeOfMapS(m_Remap);
|
|
|
|
return nSize;
|
|
}
|
|
|
|
void SHWActivatedShader::GetMemoryUsage(ICrySizer* pSizer) const
|
|
{
|
|
pSizer->AddObject(this, sizeof(SHWActivatedShader));
|
|
pSizer->AddObject(m_CompressedShaders);
|
|
pSizer->AddObject(m_Remap);
|
|
}
|
|
|
|
SHWActivatedShader::~SHWActivatedShader()
|
|
{
|
|
FXCompressedShaderItor it;
|
|
for (it = m_CompressedShaders.begin(); it != m_CompressedShaders.end(); ++it)
|
|
{
|
|
SCompressedData& Data = it->second;
|
|
SAFE_DELETE_ARRAY(Data.m_pCompressedShader);
|
|
}
|
|
m_CompressedShaders.clear();
|
|
m_Remap.clear();
|
|
}
|
|
bool CShaderMan::mfReleasePreactivatedShaderData()
|
|
{
|
|
bool bRes = true;
|
|
FXCompressedShadersItor it;
|
|
std::vector<CCryNameTSCRC> DelStuff;
|
|
for (it = CHWShader::m_CompressedShaders.begin(); it != CHWShader::m_CompressedShaders.end(); ++it)
|
|
{
|
|
SHWActivatedShader* pAS = it->second;
|
|
if (pAS && !pAS->m_bPersistent)
|
|
{
|
|
SAFE_DELETE(pAS);
|
|
DelStuff.push_back(it->first);
|
|
}
|
|
}
|
|
uint32 i;
|
|
for (i = 0; i < DelStuff.size(); i++)
|
|
{
|
|
CHWShader::m_CompressedShaders.erase(DelStuff[i]);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool CShaderMan::mfPreactivateShaders2(
|
|
[[maybe_unused]] const char* szPak, const char* szPath, bool bPersistent, [[maybe_unused]] const char* szBindRoot)
|
|
{
|
|
mfReleasePreactivatedShaderData();
|
|
|
|
bool bRes = true;
|
|
|
|
// Get shader platform name and make it lower
|
|
AZStd::string shaderLanguageName = GetShaderLanguageName();
|
|
AZStd::to_lower(shaderLanguageName.begin(), shaderLanguageName.end());
|
|
|
|
const AZStd::string pathPerLevel = AZStd::string::format( "%s%s/", szPath, shaderLanguageName.c_str());
|
|
|
|
CResFileLookupDataMan LevelLookup;
|
|
bool bLoaded = LevelLookup.LoadData((pathPerLevel + "lookupdata.bin").c_str(), CParserBin::m_bEndians, true);
|
|
if (bLoaded)
|
|
{
|
|
const AZStd::string& pathGlobal = gRenDev->m_cEF.m_ShadersCache;
|
|
|
|
const char* cgcShaders = "cgcshaders";
|
|
const char* cgdShaders = "cgdshaders";
|
|
const char* cggShaders = "cggshaders";
|
|
const char* cghShaders = "cghshaders";
|
|
const char* cgpShaders = "cgpshaders";
|
|
const char* cgvShaders = "cgvshaders";
|
|
|
|
bRes &= mfPreactivate2(LevelLookup, pathPerLevel + cgcShaders, pathPerLevel + cgcShaders, false, bPersistent);
|
|
bRes &= mfPreactivate2(LevelLookup, pathPerLevel + cgdShaders, pathPerLevel + cgdShaders, false, bPersistent);
|
|
bRes &= mfPreactivate2(LevelLookup, pathPerLevel + cggShaders, pathPerLevel + cggShaders, false, bPersistent);
|
|
bRes &= mfPreactivate2(LevelLookup, pathPerLevel + cghShaders, pathPerLevel + cghShaders, false, bPersistent);
|
|
bRes &= mfPreactivate2(LevelLookup, pathPerLevel + cgpShaders, pathPerLevel + cgpShaders, false, bPersistent);
|
|
bRes &= mfPreactivate2(LevelLookup, pathPerLevel + cgvShaders, pathPerLevel + cgvShaders, true, bPersistent);
|
|
}
|
|
|
|
return bRes;
|
|
}
|
|
|
|
|
|
void CHWShader_D3D::mfLogShaderCacheMiss(SHWSInstance* pInst)
|
|
{
|
|
CShaderMan& Man = gRenDev->m_cEF;
|
|
|
|
// update the stats
|
|
Man.m_ShaderCacheStats.m_nGlobalShaderCacheMisses++;
|
|
|
|
// don't do anything else if CVar is disabled and no callback is registered
|
|
if (CRenderer::CV_r_shaderslogcachemisses == 0 && Man.m_ShaderCacheMissCallback == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
char nameCache[256];
|
|
azstrcpy(nameCache, AZ_ARRAY_SIZE(nameCache), GetName());
|
|
char* s = strchr(nameCache, '(');
|
|
if (s)
|
|
{
|
|
s[0] = 0;
|
|
}
|
|
string sNew;
|
|
SShaderCombIdent Ident = pInst->m_Ident;
|
|
Ident.m_GLMask = m_nMaskGenFX;
|
|
gRenDev->m_cEF.mfInsertNewCombination(Ident, pInst->m_eClass, nameCache, 0, &sNew, 0);
|
|
|
|
if (CRenderer::CV_r_shaderslogcachemisses > 1 && !gRenDev->m_bShaderCacheGen && !gEnv->IsEditor())
|
|
{
|
|
CryWarning(VALIDATOR_MODULE_RENDERER, VALIDATOR_WARNING, "[SHADERS] GCM Global Cache Miss: %s\n", sNew.c_str());
|
|
}
|
|
|
|
string sEntry;
|
|
|
|
sEntry = "[";
|
|
sEntry += GetShaderListFilename().c_str();
|
|
sEntry += "]";
|
|
sEntry += sNew;
|
|
|
|
CCryNameTSCRC cryName(sEntry);
|
|
|
|
// do we already contain this entry (vec is sorted so lower bound gives us already the good position to insert)
|
|
CShaderMan::ShaderCacheMissesVec::iterator it = std::lower_bound(Man.m_ShaderCacheMisses.begin(), Man.m_ShaderCacheMisses.end(), cryName);
|
|
if (it == Man.m_ShaderCacheMisses.end() || cryName != (*it))
|
|
{
|
|
Man.m_ShaderCacheMisses.insert(it, cryName);
|
|
|
|
if (CRenderer::CV_r_shaderslogcachemisses)
|
|
{
|
|
AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle;
|
|
gEnv->pFileIO->Open(Man.m_ShaderCacheMissPath.c_str(), AZ::IO::OpenMode::ModeAppend | AZ::IO::OpenMode::ModeUpdate, fileHandle);
|
|
if (fileHandle != AZ::IO::InvalidHandle)
|
|
{
|
|
AZ::IO::Print(fileHandle, "%s\n", sEntry.c_str());
|
|
gEnv->pFileIO->Close(fileHandle);
|
|
}
|
|
}
|
|
|
|
// call callback if provided to inform client about misses
|
|
if (Man.m_ShaderCacheMissCallback)
|
|
{
|
|
(*Man.m_ShaderCacheMissCallback)(sEntry.c_str());
|
|
}
|
|
}
|
|
}
|
|
|
|
void CHWShader_D3D::mfLogShaderRequest([[maybe_unused]] SHWSInstance* pInst)
|
|
{
|
|
#if !defined(_RELEASE)
|
|
IF (CRenderer::CV_r_shaderssubmitrequestline > 1, 0)
|
|
{
|
|
mfSubmitRequestLine(pInst);
|
|
}
|
|
#endif
|
|
}
|