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/Common/Shaders/ShaderSerialize.cpp

1002 lines
30 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"
#ifdef SHADERS_SERIALIZING
bool CShaderSerialize::_OpenSResource(float fVersion, SSShaderRes* pSR, CShader* pSH, int nCache, CResFile* pRF, bool bReadOnly)
{
assert(nCache == CACHE_USER || nCache == CACHE_READONLY);
SSShaderCacheHeader hd;
ZeroStruct(hd);
bool bValid = true;
bool bCheckValid = true;
if (!CRenderer::CV_r_shadersAllowCompilation)
{
bCheckValid = false;
}
//uint64 writeTimeCFX=0;
//See if resfile is in assets dir
if (!pRF->mfOpen(RA_READ | (CParserBin::m_bEndians ? RA_ENDIANS : 0), NULL, NULL))
{
pRF->mfClose();
bValid = false;
}
if (bValid)
{
pRF->mfFileSeek(CShaderMan::s_cNameHEAD, 0, SEEK_SET);
pRF->mfFileRead2(CShaderMan::s_cNameHEAD, sizeof(SSShaderCacheHeader), &hd);
if (CParserBin::m_bEndians)
{
SwapEndian(hd, eBigEndian);
}
if (hd.m_SizeOf != sizeof(SSShaderCacheHeader))
{
bValid = false;
}
else if (fVersion && (hd.m_MajorVer != (int)fVersion || hd.m_MinorVer != (int)(((float)fVersion - (float)(int)fVersion) * 10.1f)))
{
bValid = false;
//if (CRenderer::CV_r_shadersdebug==2)
{
LogWarning("WARNING: Shader resource '%s' version mismatch (Resource: %s, Expected: %.1f)", pRF->mfGetFileName(), hd.m_szVer, fVersion);
}
}
if (bCheckValid)
{
char nameSrc[256];
sprintf_s(nameSrc, "%sCryFX/%s.%s", gRenDev->m_cEF.m_ShadersPath.c_str(), pSH->GetName(), "cfx");
uint32 srcCRC = pSH->m_SourceCRC32;
if (!srcCRC)
{
srcCRC = gEnv->pCryPak->ComputeCRC(nameSrc);
pSH->m_SourceCRC32 = srcCRC; //Propagate to shader, prevent recalculation
}
if (srcCRC && srcCRC != hd.m_SourceCRC32)
{
bValid = false;
//if (CRenderer::CV_r_shadersdebug==2)
{
LogWarning("WARNING: Shader resource '%s' src CRC mismatch", pRF->mfGetFileName());
}
}
}
// If we failed a version or CRC check, close our resource file since we may try opening it again later
if (!bValid)
{
pRF->mfClose();
}
if (bValid && nCache == CACHE_USER)
{
pRF->mfClose();
if (!pRF->mfOpen(RA_READ | (CParserBin::m_bEndians ? RA_ENDIANS : 0) | RA_WRITE, NULL, NULL))
{
pRF->mfClose();
bValid = false;
}
}
}
if (!bValid && nCache == CACHE_USER && !bReadOnly && pSH->m_CRC32) //Create ResFile
{
if (!pRF->mfOpen(RA_CREATE | (CParserBin::m_bEndians ? RA_ENDIANS : 0), NULL, NULL))
{
return false;
}
SDirEntry de;
de.Name = CShaderMan::s_cNameHEAD;
de.size = sizeof(SSShaderCacheHeader);
hd.m_SizeOf = sizeof(SSShaderCacheHeader);
hd.m_MinorVer = (int)(((float)fVersion - (float)(int)fVersion) * 10.1f);
hd.m_MajorVer = (int)fVersion;
hd.m_CRC32 = pSH->m_CRC32;
hd.m_SourceCRC32 = pSH->m_SourceCRC32;
sprintf_s(hd.m_szVer, "Ver: %.1f", fVersion);
SSShaderCacheHeader hdTemp, * pHD;
pHD = &hd;
if (CParserBin::m_bEndians)
{
hdTemp = hd;
SwapEndian(hdTemp, eBigEndian);
pHD = &hdTemp;
}
//create dir
pRF->mfFileAdd(&de);
//open dir and populate data
SDirEntryOpen* pOpenDir = pRF->mfOpenEntry(&de);
pOpenDir->pData = pHD;
pOpenDir->nSize = de.size;
pRF->mfFlush();
bValid = true;
}
if (!bValid)
{
SAFE_DELETE(pRF);
}
if (pSR->m_pRes[nCache] && (pSR->m_pRes[nCache] != pRF))
{
SAFE_DELETE(pSR->m_pRes[nCache]);
}
pSR->m_pRes[nCache] = pRF;
pSR->m_Header[nCache] = hd;
pSR->m_bReadOnly[nCache] = bReadOnly;
if (bValid && !pSH->m_CRC32)
{
pSH->m_CRC32 = hd.m_CRC32;
}
return bValid;
}
bool CShaderSerialize::OpenSResource(const char* szName, SSShaderRes* pSR, CShader* pSH, bool bDontUseUserFolder, bool bReadOnly)
{
stack_string szReadOnly = szName;
// ShaderCacheGen behavior:
// CACHE_READONLY is not really used when exporting the .fxb, so we append the @usercache@ alias to the relative shader path
// here as well. We cannot just leave this as the relative Shaders/Cache/Foo.fxb value because then it creates a new
// file in the asset cache as @assets@/Shaders/Cache/Foo.fxb, which is illegal (since only AP has the authority to write here)
// Game runtime behavior:
// We can't simply set both the CACHE_READONLY and CACHE_USER entries to be the same file path because then the shader caching
// system treats these entries the same. CACHE_READONLY acts more as a template while CACHE_USER is the actual file with all
// of the shader permutation entries. They need different file names (that have the same relative shader path) in order
// for the CResFiles to be treated differently by the caching system.
if (gRenDev->IsShaderCacheGenMode())
{
szReadOnly = stack_string(gRenDev->m_cEF.m_szCachePath.c_str()) + stack_string(szName);
}
CResFile* rfRO = new CResFile(szReadOnly);
float fVersion = FX_CACHE_VER + FX_SER_CACHE_VER;
bool bValidRO = _OpenSResource(fVersion, pSR, pSH, bDontUseUserFolder ? CACHE_READONLY : CACHE_USER, rfRO, bReadOnly);
bool bValidUser = false;
#if !defined(SHADER_NO_SOURCES)
CResFile* rfUser;
if (!bDontUseUserFolder)
{
stack_string szUser = stack_string(gRenDev->m_cEF.m_szCachePath.c_str()) + stack_string(szName);
rfUser = new CResFile(szUser.c_str());
bValidUser = _OpenSResource(fVersion, pSR, pSH, CACHE_USER, rfUser, bReadOnly);
}
#endif
return (bValidRO || bValidUser);
}
bool CShaderSerialize::CreateSResource(CShader* pSH, SSShaderRes* pSR, [[maybe_unused]] CCryNameTSCRC& SName, bool bDontUseUserFolder, bool bReadOnly)
{
AZStd::string dstName;
dstName.reserve(512);
if (m_customSerialisePath.size())
{
dstName = m_customSerialisePath.c_str();
}
dstName += gRenDev->m_cEF.m_ShadersCache;
dstName += pSH->GetName();
dstName += ".fxb";
bool bRes = OpenSResource(dstName.c_str(), pSR, pSH, bDontUseUserFolder, bReadOnly);
AZ_Error("CShaderSerialize", bRes, "Failed to open '%s' with bDontUseUserFolder=%s and bReadOnly=%s", dstName.c_str(), bDontUseUserFolder ? "True" : "False", bReadOnly ? "True" : "False");
return bRes;
}
SSShaderRes* CShaderSerialize::InitSResource(CShader* pSH, bool bDontUseUserFolder, bool bReadOnly)
{
SSShaderRes* pSR = NULL;
stack_string shaderName = pSH->GetName();
shaderName += "_GLOBAL";
CCryNameTSCRC SName = CCryNameTSCRC(shaderName.c_str());
FXSShaderResItor itS = m_SShaderResources.find(SName);
#if SHADER_NO_SOURCES
bool bCheckValid = false;
#else
bool bCheckValid = true;
#endif
if (itS != m_SShaderResources.end())
{
pSR = itS->second;
pSR->m_nRefCount++;
if (bCheckValid)
{
int nCache[2] = {-1, -1};
if (!bReadOnly || bDontUseUserFolder)
{
nCache[0] = CACHE_USER;
}
else
if (!bDontUseUserFolder || bReadOnly)
{
nCache[0] = CACHE_USER;
nCache[1] = CACHE_READONLY;
}
for (int i = 0; i < 2; i++)
{
if (nCache[i] < 0 || !pSR->m_pRes[i])
{
continue;
}
//if the shader has a CRC then we can test, generally it is only valid during cache gen
if (pSH->m_CRC32 != 0 && pSR->m_Header[i].m_CRC32 != pSH->m_CRC32)
{
//CryLogAlways("CRC check failed in serialise: 0x%x source: 0x%x\n", pSR->m_Header[i].m_CRC32, pSH->m_CRC32);
SAFE_DELETE(pSR->m_pRes[i]);
}
}
bool bValid = true;
if (!bReadOnly && !pSR->m_pRes[CACHE_USER])
{
bValid = false;
}
else
if ((!bDontUseUserFolder || bReadOnly) && !pSR->m_pRes[CACHE_READONLY] && !pSR->m_pRes[CACHE_USER])
{
bValid = false;
}
if (!bValid)
{
CreateSResource(pSH, pSR, SName, bDontUseUserFolder, bReadOnly);
}
else
{
//printf("Reusing existing .fxb for %s\n", pSH->GetName() );
}
}
}
else
{
pSR = new SSShaderRes;
bool bRes = CreateSResource(pSH, pSR, SName, bDontUseUserFolder, bReadOnly);
if (bRes)
{
m_SShaderResources.insert(FXSShaderResItor::value_type(SName, pSR));
}
else
{
SAFE_DELETE(pSR);
}
}
if (pSH->m_CRC32 == 0 && pSR)
{
if (pSR->m_pRes[CACHE_READONLY])
{
pSH->m_CRC32 = pSR->m_Header[CACHE_READONLY].m_CRC32;
}
else if (pSR->m_pRes[CACHE_USER])
{
pSH->m_CRC32 = pSR->m_Header[CACHE_USER].m_CRC32;
}
}
return pSR;
}
void CShaderSerialize::ClearSResourceCache()
{
const FXSShaderResItor end_it = m_SShaderResources.end();
FXSShaderResItor it = m_SShaderResources.begin();
for (; it != end_it; it++)
{
SAFE_DELETE(it->second);
}
m_SShaderResources.clear();
}
bool CShaderSerialize::DoesSResourceExist(CShader* pSH)
{
SSShaderRes* pSR = NULL;
stack_string shaderName = pSH->GetName();
shaderName += "_GLOBAL";
CCryNameTSCRC SName = CCryNameTSCRC(shaderName.c_str());
FXSShaderResItor itS = m_SShaderResources.find(SName);
if (itS != m_SShaderResources.end())
{
return true;
}
return false;
}
bool CShaderSerialize::ExportHWShader(CHWShader* pShader, SShaderSerializeContext& SC)
{
if (!pShader)
{
return false;
}
bool bRes = pShader->Export(SC);
return bRes;
}
CHWShader* CShaderSerialize::ImportHWShader(SShaderSerializeContext& SC, int nOffs, uint32 CRC32, CShader* pSH)
{
CHWShader* pRes = CHWShader::Import(SC, nOffs, CRC32, pSH);
return pRes;
}
void CShaderSerialize::ExportHWShaderStage(SShaderSerializeContext& SC, CHWShader* shader, uint32& outShaderOffset)
{
if ( shader )
{
outShaderOffset = SC.Data.Num();
if ( !ExportHWShader(shader,SC) )
{
outShaderOffset = -1;
CryFatalError("Shader export failed.");
}
}
else
{
outShaderOffset = -1;
}
}
bool CShaderSerialize::ExportShader(CShader* pSH, CShaderManBin& binShaderMgr)
{
#ifdef SHADER_SERIALIZE_VERBOSE
CryLogAlways("[CShaderSerialize] ExportShader: %s flags: 0x%llx mdvFlags: 0x%x\n", pSH->GetName(), pSH->m_nMaskGenFX, pSH->m_nMDV);
#endif
bool bRes = true;
//Use user folder on export?
SSShaderRes* pSR = InitSResource(pSH, false /*((gRenDev->m_cEF.m_nCombinations > 0) || !CRenderer::CV_r_shadersuserfolder)*/, false);
uint32 i;
int j;
if (!pSR || !pSR->m_pRes[CACHE_USER])
{
return false;
}
SShaderSerializeContext SC;
SC.SSR.m_eSHDType = pSH->m_eSHDType;
SC.SSR.m_Flags = pSH->m_Flags;
SC.SSR.m_Flags2 = pSH->m_Flags2;
SC.SSR.m_nMDV = pSH->m_nMDV;
SC.SSR.m_vertexFormatEnum = pSH->m_vertexFormat.GetEnum();
SC.SSR.m_eCull = pSH->m_eCull;
//SC.SSR.m_nMaskCB = pSH->m_nMaskCB; //maskCB generated on HW shader activation
SC.SSR.m_eShaderType = pSH->m_eShaderType;
SC.SSR.m_nMaskGenFX = pSH->m_nMaskGenFX;
SC.SSR.m_nTechniques = pSH->m_HWTechniques.Num();
SShaderFXParams& params = binShaderMgr.mfGetFXParams(pSH);
SC.SSR.m_nPublicParams = params.m_PublicParams.size();
for (i = 0; i < SC.SSR.m_nPublicParams; i++)
{
SSShaderParam PR;
SShaderParam& P = params.m_PublicParams[i];
PR.m_nameIdx = SC.AddString(P.m_Name.c_str());
PR.m_Type = P.m_Type;
PR.m_Value = P.m_Value;
PR.m_nScriptOffs = SC.AddString(P.m_Script.c_str());
PR.m_eSemantic = P.m_eSemantic;
SC.Params.Add(PR);
}
SC.SSR.m_nFXParams = params.m_FXParams.size();
for (i = 0; i < SC.SSR.m_nFXParams; i++)
{
params.m_FXParams[i].Export(SC);
}
SC.SSR.m_nFXSamplers = params.m_FXSamplers.size();
for (i = 0; i < SC.SSR.m_nFXSamplers; i++)
{
params.m_FXSamplers[i].Export(SC);
}
SC.SSR.m_nFXTextures = params.m_FXTextures.size();
for (i = 0; i < SC.SSR.m_nFXTextures; i++)
{
params.m_FXTextures[i].Export(SC);
}
SC.SSR.m_nFXTexSamplers = params.m_FXSamplersOld.size();
for (i = 0; i < SC.SSR.m_nFXTexSamplers; i++)
{
params.m_FXSamplersOld[i].Export(SC);
}
SC.SSR.m_nFXTexRTs = SC.FXTexRTs.Num();
for (i = 0; i < SC.SSR.m_nTechniques; i++)
{
SSShaderTechnique ST;
SShaderTechnique* pT = pSH->m_HWTechniques[i];
ST.m_nPreprocessFlags = pT->m_nPreprocessFlags;
ST.m_nNameOffs = SC.AddString(pT->m_NameStr.c_str());
ST.m_Flags = pT->m_Flags;
int TECH_MAX = TTYPE_MAX;
for (j = 0; j < TECH_MAX; j++)
{
ST.m_nTechnique[j] = pT->m_nTechnique[j];
}
ST.m_nREs = pT->m_REs.Num();
ST.m_nPassesOffs = SC.Passes.Num();
ST.m_nPasses = pT->m_Passes.Num();
SC.SSR.m_nPasses += ST.m_nPasses;
for (j = 0; j < ST.m_nPasses; j++)
{
SSShaderPass PS;
SShaderPass& P = pT->m_Passes[j];
PS.m_RenderState = P.m_RenderState;
PS.m_eCull = P.m_eCull;
PS.m_AlphaRef = P.m_AlphaRef;
PS.m_PassFlags = P.m_PassFlags;
assert(!(SC.Data.Num() & 0x3));
ExportHWShaderStage( SC, P.m_VShader, PS.m_nVShaderOffs );
ExportHWShaderStage( SC, P.m_HShader, PS.m_nHShaderOffs );
ExportHWShaderStage( SC, P.m_DShader, PS.m_nDShaderOffs );
ExportHWShaderStage( SC, P.m_GShader, PS.m_nGShaderOffs );
ExportHWShaderStage( SC, P.m_PShader, PS.m_nPShaderOffs );
ExportHWShaderStage( SC, P.m_CShader, PS.m_nCShaderOffs );
SC.Passes.Add(PS);
}
ST.m_nREsOffs = (ST.m_nREs > 0) ? SC.Data.Num() : -1;
for (j = 0; j < ST.m_nREs; j++)
{
CRendElementBase* pRE = pT->m_REs[j];
uint32 type = pRE->m_Type;
sAddData(SC.Data, type);
pRE->mfExport(SC);
sAlignData(SC.Data, 4);
}
SC.Techniques.AddElem(ST);
}
TArray<byte> Data;
//DEBUG - prevent Data reallocs
//Data.Alloc(1024*1024);
uint32 nPublicParamsOffset;
uint32 nFXParamsOffset;
uint32 nFXSamplersOffset;
uint32 nFXTexturesOffset;
uint32 nFXTexSamplersOffset;
uint32 nFXTexRTsOffset;
uint32 nTechOffset;
uint32 nPassOffset;
uint32 nStringsOffset;
uint32 nDataOffset;
//sAddData(Data, SC.SSR);
SC.SSR.Export(Data);
sAddDataArray(Data, SC.Params, nPublicParamsOffset);
sAddDataArray(Data, SC.FXParams, nFXParamsOffset);
sAddDataArray(Data, SC.FXSamplers, nFXSamplersOffset);
sAddDataArray(Data, SC.FXTextures, nFXTexturesOffset);
sAddDataArray(Data, SC.FXTexSamplers, nFXTexSamplersOffset);
sAddDataArray(Data, SC.FXTexRTs, nFXTexRTsOffset);
sAddDataArray(Data, SC.Techniques, nTechOffset);
sAddDataArray(Data, SC.Passes, nPassOffset);
sAddDataArray_POD(Data, SC.Strings, nStringsOffset);
sAddDataArray_POD(Data, SC.Data, nDataOffset);
SSShader* pSSR = (SSShader*)&Data[0];
pSSR->m_nPublicParamsOffset = nPublicParamsOffset;
pSSR->m_nFXParamsOffset = nFXParamsOffset;
pSSR->m_nFXSamplersOffset = nFXSamplersOffset;
pSSR->m_nFXTexturesOffset = nFXTexturesOffset;
pSSR->m_nFXTexSamplersOffset = nFXTexSamplersOffset;
pSSR->m_nFXTexRTsOffset = nFXTexRTsOffset;
pSSR->m_nTechOffset = nTechOffset;
pSSR->m_nPassOffset = nPassOffset;
pSSR->m_nStringsOffset = nStringsOffset;
pSSR->m_nDataOffset = nDataOffset;
pSSR->m_nDataSize = SC.Data.Num();
pSSR->m_nStringsSize = SC.Strings.Num();
if (CParserBin::m_bEndians)
{
SwapEndian(pSSR->m_nPublicParamsOffset, eBigEndian);
SwapEndian(pSSR->m_nFXParamsOffset, eBigEndian);
SwapEndian(pSSR->m_nFXSamplersOffset, eBigEndian);
SwapEndian(pSSR->m_nFXTexturesOffset, eBigEndian);
SwapEndian(pSSR->m_nFXTexRTsOffset, eBigEndian);
SwapEndian(pSSR->m_nTechOffset, eBigEndian);
SwapEndian(pSSR->m_nPassOffset, eBigEndian);
SwapEndian(pSSR->m_nStringsOffset, eBigEndian);
SwapEndian(pSSR->m_nDataOffset, eBigEndian);
SwapEndian(pSSR->m_nDataSize, eBigEndian);
SwapEndian(pSSR->m_nStringsSize, eBigEndian);
}
int nLen = Data.Num();
SDirEntry de;
char sName[128];
sprintf_s(sName, "(%llx)(%llx)", pSH->m_nMaskGenFX, pSH->m_maskGenStatic);
de.Name = CCryNameTSCRC(sName);
de.size = nLen;
de.flags |= RF_COMPRESS;
pSR->m_pRes[CACHE_USER]->mfFileAdd(&de);
//create open dir and populate data
SDirEntryOpen* pOpenDir = pSR->m_pRes[CACHE_USER]->mfOpenEntry(&de);
pOpenDir->pData = &Data[0];
pOpenDir->nSize = de.size;
//Preserve modification time
uint64 modTime = pSR->m_pRes[CACHE_USER]->mfGetModifTime();
pSR->m_pRes[CACHE_USER]->mfFlush();
return bRes;
}
float g_fTime0;
float g_fTime1;
float g_fTime2;
bool CShaderSerialize::CheckFXBExists(CShader* pSH)
{
SSShaderRes* pSR = InitSResource(pSH, false, true);
if (!pSR || (!pSR->m_Header[CACHE_USER].m_CRC32 && !pSR->m_Header[CACHE_READONLY].m_CRC32))
{
return false;
}
char sName[128];
sprintf_s(sName, "(%llx)(%llx)", pSH->m_nMaskGenFX, pSH->m_maskGenStatic);
CCryNameTSCRC CName = CCryNameTSCRC(sName);
SDirEntry* pDE = NULL;
CResFile* pRes = NULL;
for (int i = 0; i < 2; i++)
{
pRes = pSR->m_pRes[i];
if (!pRes)
{
continue;
}
pDE = pRes->mfGetEntry(CName);
if (pDE)
{
return true;
}
}
return false;
}
CShaderSerialize::ShaderImportResults CShaderSerialize::ImportShader(CShader* pSH, CShaderManBin& binShaderMgr)
{
if (CParserBin::m_bEndians)
{
CryFatalError("CShaderSerialize - cross platform import not supported");
}
float fTime0 = iTimer->GetAsyncCurTime();
SSShaderRes* pSR = NULL;
uint32 i;
int j;
char sName[128];
sprintf_s(sName, "(%llx)(%llx)", pSH->m_nMaskGenFX, pSH->m_maskGenStatic);
CCryNameTSCRC CName = CCryNameTSCRC(sName);
SDirEntry* pDE = NULL;
CResFile* pRes = NULL;
// Not found yet
if (!pDE || !pRes)
{
//try global cache
pSR = InitSResource(pSH, !CRenderer::CV_r_shadersAllowCompilation, true);
if (pSR && (pSR->m_Header[CACHE_USER].m_CRC32 != 0 || pSR->m_Header[CACHE_READONLY].m_CRC32 != 0))
{
for (i = 0; i < 2; i++)
{
pRes = pSR->m_pRes[i];
if (!pRes)
{
continue;
}
pDE = pRes->mfGetEntry(CName);
if (pDE)
{
break;
}
}
}
if (!pDE && !pSR)
{
// The .cfx has no associated .fxb, so this is a guaranteed failure on import.
return SHADER_IMPORT_FAILURE;
}
else if (!pDE)
{
// We have a shader import table but this specific permutation is missing
return SHADER_IMPORT_MISSING_ENTRY;
}
}
CShader* pSave = gRenDev->m_RP.m_pShader;
gRenDev->m_RP.m_pShader = pSH;
assert(gRenDev->m_RP.m_pShader != 0);
int nSize = pRes->mfFileRead(pDE);
byte* pData = (byte*)pRes->mfFileGetBuf(pDE);
if (!pData)
{
// Malformed fxb
return SHADER_IMPORT_FAILURE;
}
//printf("[CShaderSerialize] Import Shader: %s flags: 0x%llx mdvFlags: 0x%x from %s cache %s\n", pSH->GetName(), pSH->m_nMaskGenFX, pSH->m_nMDV, bLoadedFromLevel ? "LEVEL" : "GLOBAL", pSR->m_pRes[i]->mfGetFileName());
byte* pSrc = pData;
g_fTime0 += iTimer->GetAsyncCurTime() - fTime0;
float fTime1 = iTimer->GetAsyncCurTime();
SShaderFXParams& fxParams = binShaderMgr.mfGetFXParams(pSH);
SShaderSerializeContext SC;
SC.SSR.Import(pSrc);
#ifdef SHADER_SERIALIZE_VERBOSE
CryLog("[CShaderSerialize] Import Shader: %s flags: 0x%llx mdvFlags: 0x%x from global cache %s\n", pSH->GetName(), pSH->m_nMaskGenFX, pSH->m_nMDV, pSR->m_pRes[i]->mfGetFileName());
#endif
if (SC.SSR.m_nPublicParams)
{
SC.Params.ReserveNoClear(SC.SSR.m_nPublicParams);
if (!CParserBin::m_bEndians)
{
memcpy(&SC.Params[0], &pSrc[SC.SSR.m_nPublicParamsOffset], sizeof(SSShaderParam) * SC.SSR.m_nPublicParams);
}
else
{
uint32 offset = SC.SSR.m_nPublicParamsOffset;
for (i = 0; i < SC.SSR.m_nPublicParams; i++)
{
SC.Params[i].Import(&pSrc[offset]);
offset += sizeof(SSShaderParam);
}
}
}
if (SC.SSR.m_nFXParams)
{
SC.FXParams.ReserveNoClear(SC.SSR.m_nFXParams);
if (!CParserBin::m_bEndians)
{
memcpy(&SC.FXParams[0], &pSrc[SC.SSR.m_nFXParamsOffset], sizeof(SSFXParam) * SC.SSR.m_nFXParams);
}
else
{
uint32 offset = SC.SSR.m_nFXParamsOffset;
for (i = 0; i < SC.SSR.m_nFXParams; i++)
{
SC.FXParams[i].Import(&pSrc[offset]);
offset += sizeof(SSFXParam);
}
}
}
if (SC.SSR.m_nFXSamplers)
{
SC.FXSamplers.ReserveNoClear(SC.SSR.m_nFXSamplers);
if (!CParserBin::m_bEndians)
{
memcpy(&SC.FXSamplers[0], &pSrc[SC.SSR.m_nFXSamplersOffset], sizeof(SSFXSampler) * SC.SSR.m_nFXSamplers);
}
else
{
uint32 offset = SC.SSR.m_nFXSamplersOffset;
for (i = 0; i < SC.SSR.m_nFXSamplers; i++)
{
SC.FXSamplers[i].Import(&pSrc[offset]);
offset += sizeof(SSTexSamplerFX);
}
}
}
if (SC.SSR.m_nFXTextures)
{
SC.FXTextures.ReserveNoClear(SC.SSR.m_nFXTextures);
memcpy(&SC.FXTextures[0], &pSrc[SC.SSR.m_nFXTexturesOffset], sizeof(SSFXTexture) * SC.SSR.m_nFXTextures);
}
if (SC.SSR.m_nFXTexSamplers)
{
SC.FXTexSamplers.ReserveNoClear(SC.SSR.m_nFXTexSamplers);
if (!CParserBin::m_bEndians)
{
memcpy(&SC.FXTexSamplers[0], &pSrc[SC.SSR.m_nFXTexSamplersOffset], sizeof(SSTexSamplerFX) * SC.SSR.m_nFXTexSamplers);
}
else
{
uint32 offset = SC.SSR.m_nFXTexSamplersOffset;
for (i = 0; i < SC.SSR.m_nFXTexSamplers; i++)
{
SC.FXTexSamplers[i].Import(&pSrc[offset]);
offset += sizeof(SSTexSamplerFX);
}
}
}
if (SC.SSR.m_nFXTexRTs)
{
SC.FXTexRTs.ReserveNoClear(SC.SSR.m_nFXTexRTs);
if (!CParserBin::m_bEndians)
{
memcpy(&SC.FXTexRTs[0], &pSrc[SC.SSR.m_nFXTexRTsOffset], sizeof(SSHRenderTarget) * SC.SSR.m_nFXTexRTs);
}
else
{
uint32 offset = SC.SSR.m_nFXTexRTsOffset;
for (i = 0; i < SC.SSR.m_nFXTexRTs; i++)
{
SC.FXTexRTs[i].Import(&pSrc[offset]);
offset += sizeof(SSHRenderTarget);
}
}
}
if (SC.SSR.m_nTechniques)
{
SC.Techniques.ReserveNoClear(SC.SSR.m_nTechniques);
if (!CParserBin::m_bEndians)
{
memcpy(&SC.Techniques[0], &pSrc[SC.SSR.m_nTechOffset], sizeof(SSShaderTechnique) * SC.SSR.m_nTechniques);
}
else
{
uint32 offset = SC.SSR.m_nTechOffset;
for (i = 0; i < SC.SSR.m_nTechniques; i++)
{
SC.Techniques[i].Import(&pSrc[offset]);
offset += sizeof(SSShaderTechnique);
}
}
}
if (SC.SSR.m_nPasses)
{
SC.Passes.ReserveNoClear(SC.SSR.m_nPasses);
if (!CParserBin::m_bEndians)
{
memcpy(&SC.Passes[0], &pSrc[SC.SSR.m_nPassOffset], sizeof(SSShaderPass) * SC.SSR.m_nPasses);
}
else
{
uint32 offset = SC.SSR.m_nPassOffset;
for (i = 0; i < SC.SSR.m_nPasses; i++)
{
SC.Passes[i].Import(&pSrc[offset]);
offset += sizeof(SSShaderPass);
}
}
}
if (SC.SSR.m_nStringsSize)
{
SC.Strings.ReserveNoClear(SC.SSR.m_nStringsSize);
memcpy(&SC.Strings[0], &pSrc[SC.SSR.m_nStringsOffset], SC.SSR.m_nStringsSize);
}
if (SC.SSR.m_nDataSize)
{
SC.Data.ReserveNoClear(SC.SSR.m_nDataSize);
memcpy(&SC.Data[0], &pSrc[SC.SSR.m_nDataOffset], SC.SSR.m_nDataSize);
}
pRes->mfFileClose(pDE);
g_fTime1 += iTimer->GetAsyncCurTime() - fTime1;
float fTime2 = iTimer->GetAsyncCurTime();
pSH->m_eSHDType = SC.SSR.m_eSHDType;
//TODO |= on flags? will we lose flags at runtime
pSH->m_Flags = SC.SSR.m_Flags;
pSH->m_Flags2 = SC.SSR.m_Flags2;
pSH->m_nMDV = SC.SSR.m_nMDV;
AZ_Assert(SC.SSR.m_vertexFormatEnum < eVF_Max, "Bad vertex format index. Is the shader cache out of date?");
pSH->m_vertexFormat = gRenDev->m_RP.m_vertexFormats[SC.SSR.m_vertexFormatEnum];
pSH->m_eCull = SC.SSR.m_eCull;
pSH->m_eShaderType = SC.SSR.m_eShaderType;
pSH->m_nMaskGenFX = SC.SSR.m_nMaskGenFX;
fxParams.m_PublicParams.reserve(fxParams.m_PublicParams.size() + SC.SSR.m_nPublicParams);
for (i = 0; i < SC.SSR.m_nPublicParams; i++)
{
SSShaderParam& PR = SC.Params[i];
SShaderParam P;
const char* pName = sString(PR.m_nameIdx, SC.Strings);
P.m_Name = pName;
P.m_Type = PR.m_Type;
P.m_Value = PR.m_Value;
P.m_Script = sString(PR.m_nScriptOffs, SC.Strings);
fxParams.m_PublicParams.push_back(P);
}
fxParams.m_FXParams.reserve(fxParams.m_FXParams.size() + SC.SSR.m_nFXParams);
for (i = 0; i < SC.SSR.m_nFXParams; i++)
{
SFXParam fxParam;
fxParam.Import(SC, &SC.FXParams[i]);
fxParams.m_FXParams.push_back(fxParam);
}
fxParams.m_FXSamplersOld.reserve(fxParams.m_FXSamplersOld.size() + SC.SSR.m_nFXTexSamplers);
for (i = 0; i < SC.SSR.m_nFXTexSamplers; i++)
{
STexSamplerFX fxTexSampler;
fxTexSampler.Import(SC, &SC.FXTexSamplers[i]);
fxParams.m_FXSamplersOld.push_back(fxTexSampler);
}
fxParams.m_FXSamplers.reserve(fxParams.m_FXSamplers.size() + SC.SSR.m_nFXSamplers);
for (i = 0; i < SC.SSR.m_nFXSamplers; i++)
{
SFXSampler fxSampler;
fxSampler.Import(SC, &SC.FXSamplers[i]);
fxParams.m_FXSamplers.push_back(fxSampler);
}
fxParams.m_FXTextures.reserve(fxParams.m_FXTextures.size() + SC.SSR.m_nFXTextures);
for (i = 0; i < SC.SSR.m_nFXTextures; i++)
{
SFXTexture fxTexture;
fxTexture.Import(SC, &SC.FXTextures[i]);
fxParams.m_FXTextures.push_back(fxTexture);
}
for (i = 0; i < SC.SSR.m_nTechniques; i++)
{
SSShaderTechnique& ST = SC.Techniques[i];
SShaderTechnique* pT = new SShaderTechnique(pSH);
pT->m_NameStr = sString(ST.m_nNameOffs, SC.Strings);
pT->m_NameCRC = pT->m_NameStr.c_str();
pT->m_Flags = ST.m_Flags;
pT->m_nPreprocessFlags = ST.m_nPreprocessFlags;
for (j = 0; j < TTYPE_MAX; j++)
{
pT->m_nTechnique[j] = ST.m_nTechnique[j];
}
if (ST.m_nPasses)
{
int nOffs = ST.m_nPassesOffs;
pT->m_Passes.reserve(ST.m_nPasses);
for (j = 0; j < ST.m_nPasses; j++)
{
SSShaderPass& PS = SC.Passes[j + nOffs];
SShaderPass* P = pT->m_Passes.AddIndex(1);
P->m_RenderState = PS.m_RenderState;
P->m_eCull = PS.m_eCull;
P->m_AlphaRef = PS.m_AlphaRef;
P->m_PassFlags = PS.m_PassFlags;
P->m_VShader = ImportHWShader(SC, PS.m_nVShaderOffs, pSH->m_CRC32, pSH);
P->m_PShader = ImportHWShader(SC, PS.m_nPShaderOffs, pSH->m_CRC32, pSH);
P->m_GShader = ImportHWShader(SC, PS.m_nGShaderOffs, pSH->m_CRC32, pSH);
P->m_HShader = ImportHWShader(SC, PS.m_nHShaderOffs, pSH->m_CRC32, pSH);
P->m_DShader = ImportHWShader(SC, PS.m_nDShaderOffs, pSH->m_CRC32, pSH);
P->m_CShader = ImportHWShader(SC, PS.m_nCShaderOffs, pSH->m_CRC32, pSH);
}
}
uint32 nREOffset = ST.m_nREsOffs;
for (j = 0; j < ST.m_nREs; j++)
{
EDataType dataType = *((EDataType*)&SC.Data[nREOffset]);
if (CParserBin::m_bEndians)
{
SwapEndianEnum(dataType, eBigEndian);
}
nREOffset += sizeof(EDataType);
switch (dataType)
{
case eDATA_LensOptics:
{
CRELensOptics* pLensOptics = new CRELensOptics;
pLensOptics->mfImport(SC, nREOffset);
pT->m_REs.push_back(pLensOptics);
}
break;
case eDATA_Beam:
{
CREBeam* pBeam = new CREBeam;
pBeam->mfImport(SC, nREOffset);
pT->m_REs.push_back(pBeam);
}
break;
default:
CryFatalError("Render element not supported for shader serialising");
break;
}
//expects 4 byte aligned
assert(!(nREOffset & 3));
}
pSH->m_HWTechniques.AddElem(pT);
}
gRenDev->m_RP.m_pShader = pSave;
g_fTime2 += iTimer->GetAsyncCurTime() - fTime2;
return SHADER_IMPORT_SUCCESS;
}
#endif