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.
6375 lines
189 KiB
C++
6375 lines
189 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 <AzCore/NativeUI/NativeUIRequests.h>
|
|
#include <AzFramework/Archive/IArchive.h>
|
|
#include "UnalignedBlit.h"
|
|
|
|
#include "DeviceManager/Enums.h"
|
|
#include "PoundPoundParser.h"
|
|
|
|
static FOURCC FOURCC_SHADERBIN = MAKEFOURCC('F', 'X', 'B', '0');
|
|
|
|
|
|
SShaderBin SShaderBin::s_Root;
|
|
uint32 SShaderBin::s_nCache = 0;
|
|
uint32 SShaderBin::s_nMaxFXBinCache = MAX_FXBIN_CACHE;
|
|
CShaderManBin::CShaderManBin()
|
|
{
|
|
m_pCEF = gRenDev ? &gRenDev->m_cEF : nullptr;
|
|
}
|
|
|
|
int CShaderManBin::Size()
|
|
{
|
|
SShaderBin* pSB;
|
|
int nSize = 0;
|
|
nSize += sizeOfMapStr(m_BinPaths);
|
|
nSize += m_BinValidCRCs.size() * sizeof(bool) * sizeof(stl::MapLikeStruct);
|
|
|
|
for (pSB = SShaderBin::s_Root.m_Prev; pSB != &SShaderBin::s_Root; pSB = pSB->m_Prev)
|
|
{
|
|
nSize += pSB->Size();
|
|
}
|
|
return nSize;
|
|
}
|
|
|
|
void CShaderManBin::GetMemoryUsage(ICrySizer* pSizer) const
|
|
{
|
|
pSizer->AddObject(m_BinPaths);
|
|
pSizer->AddObject(m_BinValidCRCs);
|
|
|
|
SShaderBin* pSB;
|
|
for (pSB = SShaderBin::s_Root.m_Prev; pSB != &SShaderBin::s_Root; pSB = pSB->m_Prev)
|
|
{
|
|
pSB->GetMemoryUsage(pSizer);
|
|
}
|
|
}
|
|
|
|
uint32 SShaderBin::ComputeCRC()
|
|
{
|
|
if (!m_Tokens.size())
|
|
{
|
|
return 0;
|
|
}
|
|
uint32 CRC32;
|
|
if (CParserBin::m_bEndians)
|
|
{
|
|
DWORD* pT = new DWORD [m_Tokens.size()];
|
|
memcpy(pT, &m_Tokens[0], m_Tokens.size() * sizeof(uint32));
|
|
SwapEndian(pT, (size_t)m_Tokens.size(), eBigEndian);
|
|
CRC32 = CCrc32::Compute((char*)pT, m_Tokens.size() * sizeof(uint32));
|
|
delete [] pT;
|
|
}
|
|
else
|
|
{
|
|
CRC32 = CCrc32::Compute((char*)&m_Tokens[0], m_Tokens.size() * sizeof(uint32));
|
|
}
|
|
int nCur = 0;
|
|
Lock();
|
|
while (nCur >= 0)
|
|
{
|
|
nCur = CParserBin::FindToken(nCur, m_Tokens.size() - 1, &m_Tokens[0], eT_include);
|
|
if (nCur >= 0)
|
|
{
|
|
nCur++;
|
|
uint32 nTokName = m_Tokens[nCur];
|
|
const char* szNameInc = CParserBin::GetString(nTokName, m_TokenTable);
|
|
SShaderBin* pBinIncl = gRenDev->m_cEF.m_Bin.GetBinShader(szNameInc, true, 0);
|
|
AZ_Assert(pBinIncl, "Error loading shader '%s' while trying to compute the shader CRC.", szNameInc);
|
|
if (pBinIncl)
|
|
{
|
|
CRC32 += pBinIncl->ComputeCRC();
|
|
}
|
|
}
|
|
}
|
|
Unlock();
|
|
|
|
return CRC32;
|
|
}
|
|
|
|
SShaderBin* CShaderManBin::SaveBinShader(
|
|
uint32 nSourceCRC32, const char* szName, bool bInclude, AZ::IO::HandleType srcFileHandle)
|
|
{
|
|
SShaderBin* pBin = new SShaderBin;
|
|
|
|
CParserBin Parser(pBin);
|
|
|
|
int nSize = gEnv->pCryPak->FGetSize(srcFileHandle);
|
|
char* buf = new char [nSize + 1];
|
|
char* pBuf = buf;
|
|
buf[nSize] = 0;
|
|
gEnv->pCryPak->FSeek(srcFileHandle, 0, SEEK_SET);
|
|
gEnv->pCryPak->FRead(buf, nSize, srcFileHandle);
|
|
|
|
RemoveCR(buf);
|
|
const char* whiteSpace = " ";
|
|
|
|
{
|
|
// Hold the parsing context used to get rid of the ## directives. The constructor will
|
|
// take care of setting AZ_RESTRICTED_PLATFORM appropriately
|
|
PoundPoundContext poundPoundContext(m_pCEF->m_ShadersFilter);
|
|
|
|
// Keep parsing until we hit the real EOB.
|
|
bool layerSwitch;
|
|
while (!poundPoundContext.IsEndOfBuffer(&buf, &layerSwitch))
|
|
{
|
|
// This loop handles stripping the input text of comments, whitespace, and the
|
|
// ## include directives
|
|
do
|
|
{
|
|
SkipCharacters(&buf, whiteSpace);
|
|
SkipComments(&buf, true);
|
|
|
|
// If we find the ## characters, preprocess the token lines, allowing it to consume
|
|
// any disabled text between ## directives and then whitespace and comments again
|
|
while (buf[0] == '#' && buf[1] == '#')
|
|
{
|
|
poundPoundContext.PreprocessLines(&buf);
|
|
SkipCharacters(&buf, whiteSpace);
|
|
SkipComments(&buf, true);
|
|
}
|
|
|
|
// We need to be able to catch the case where a ##include file has hit end of buffer,
|
|
// but not the parent buffer, in which case we have to keep skipping whitespace and
|
|
// comments again
|
|
layerSwitch = false;
|
|
} while (!poundPoundContext.IsEndOfBuffer(&buf, &layerSwitch) && layerSwitch);
|
|
|
|
// Quit parsing if we have hit the real EOB.
|
|
if (poundPoundContext.IsEndOfBuffer(&buf, &layerSwitch))
|
|
{
|
|
break;
|
|
}
|
|
|
|
char com[1024];
|
|
bool bKey = false;
|
|
uint32 dwToken = CParserBin::NextToken(buf, com, bKey);
|
|
// If the token is not a key token, find/create a user token for it.
|
|
dwToken = Parser.NewUserToken(dwToken, com, false);
|
|
pBin->m_Tokens.push_back(dwToken);
|
|
|
|
SkipCharacters (&buf, whiteSpace);
|
|
SkipComments (&buf, true);
|
|
if (dwToken == eT_include)
|
|
{
|
|
// Skip whitespace to get to the < or " bracket for the include
|
|
SkipCharacters(&buf, whiteSpace);
|
|
AZ_Assert(*buf == '"' || *buf == '<', "Error saving shader %s. Include should be followed by \" or <.", szName);
|
|
char brak = *buf;
|
|
++buf;
|
|
int n = 0;
|
|
|
|
// Get the value in-between the include brackets
|
|
while (*buf != brak)
|
|
{
|
|
if (*buf <= 0x20)
|
|
{
|
|
AZ_Assert(false, "Error saving shader %s. Invalid special character found between include brackets.", szName);
|
|
break;
|
|
}
|
|
com[n++] = *buf;
|
|
++buf;
|
|
}
|
|
if (*buf == brak)
|
|
{
|
|
++buf;
|
|
}
|
|
com[n] = 0;
|
|
|
|
fpStripExtension(com, com);
|
|
|
|
// Get or load the included shader
|
|
SShaderBin* pBIncl = GetBinShader(com, true, 0);
|
|
|
|
dwToken = CParserBin::fxToken(com, NULL);
|
|
dwToken = Parser.NewUserToken(dwToken, com, false);
|
|
pBin->m_Tokens.push_back(dwToken);
|
|
}
|
|
else if (dwToken == eT_if || dwToken == eT_ifdef || dwToken == eT_ifndef)
|
|
{
|
|
bool bFirst = fxIsFirstPass(buf);
|
|
if (!bFirst)
|
|
{
|
|
if (dwToken == eT_if)
|
|
{
|
|
dwToken = eT_if_2;
|
|
}
|
|
else if (dwToken == eT_ifdef)
|
|
{
|
|
dwToken = eT_ifdef_2;
|
|
}
|
|
else
|
|
{
|
|
dwToken = eT_ifndef_2;
|
|
}
|
|
pBin->m_Tokens[pBin->m_Tokens.size() - 1] = dwToken;
|
|
}
|
|
}
|
|
else if (dwToken == eT_define)
|
|
{
|
|
shFill(&buf, com);
|
|
if (com[0] == '%')
|
|
{
|
|
pBin->m_Tokens[pBin->m_Tokens.size() - 1] = eT_define_2;
|
|
}
|
|
dwToken = Parser.NewUserToken(eT_unknown, com, false);
|
|
pBin->m_Tokens.push_back(dwToken);
|
|
|
|
TArray<char> macro;
|
|
while (*buf == 0x20 || *buf == 0x9)
|
|
{
|
|
buf++;
|
|
}
|
|
while (*buf != 0xa)
|
|
{
|
|
if (*buf == '\\')
|
|
{
|
|
macro.AddElem('\n');
|
|
while (*buf != '\n')
|
|
{
|
|
buf++;
|
|
}
|
|
buf++;
|
|
continue;
|
|
}
|
|
macro.AddElem(*buf);
|
|
buf++;
|
|
}
|
|
macro.AddElem(0);
|
|
int n = macro.Num() - 2;
|
|
while (n >= 0 && macro[n] <= 0x20)
|
|
{
|
|
macro[n] = 0;
|
|
n--;
|
|
}
|
|
char* b = ¯o[0];
|
|
while (*b)
|
|
{
|
|
SkipCharacters (&b, whiteSpace);
|
|
SkipComments (&b, true);
|
|
if (!b || !b[0])
|
|
{
|
|
break;
|
|
}
|
|
bKey = false;
|
|
dwToken = CParserBin::NextToken(b, com, bKey);
|
|
dwToken = Parser.NewUserToken(dwToken, com, false);
|
|
if (dwToken == eT_if || dwToken == eT_ifdef || dwToken == eT_ifndef)
|
|
{
|
|
bool bFirst = fxIsFirstPass(b);
|
|
if (!bFirst)
|
|
{
|
|
if (dwToken == eT_if)
|
|
{
|
|
dwToken = eT_if_2;
|
|
}
|
|
else
|
|
if (dwToken == eT_ifdef)
|
|
{
|
|
dwToken = eT_ifdef_2;
|
|
}
|
|
else
|
|
{
|
|
dwToken = eT_ifndef_2;
|
|
}
|
|
}
|
|
}
|
|
pBin->m_Tokens.push_back(dwToken);
|
|
}
|
|
pBin->m_Tokens.push_back(0);
|
|
}
|
|
}
|
|
}
|
|
if (pBin->m_Tokens.size() == 0 || !pBin->m_Tokens[0])
|
|
{
|
|
pBin->m_Tokens.push_back(eT_skip);
|
|
}
|
|
|
|
pBin->SetCRC(pBin->ComputeCRC());
|
|
pBin->m_bReadOnly = false;
|
|
|
|
char nameFile[256];
|
|
sprintf_s(nameFile, "%s%s.%s", m_pCEF->m_ShadersCache.c_str(), szName, bInclude ? "cfib" : "cfxb");
|
|
stack_string szDst = stack_string(m_pCEF->m_szCachePath.c_str()) + stack_string(nameFile);
|
|
const char* szFileName = szDst;
|
|
|
|
AZ::IO::HandleType dstFileHandle = gEnv->pCryPak->FOpen(szFileName, "wb", AZ::IO::IArchive::FLAGS_NEVER_IN_PAK | AZ::IO::IArchive::FLAGS_PATH_REAL | AZ::IO::IArchive::FOPEN_ONDISK);
|
|
if (dstFileHandle != AZ::IO::InvalidHandle)
|
|
{
|
|
SShaderBinHeader Header;
|
|
Header.m_nTokens = pBin->m_Tokens.size();
|
|
Header.m_Magic = FOURCC_SHADERBIN;
|
|
Header.m_CRC32 = pBin->m_CRC32;
|
|
float fVersion = FX_CACHE_VER;
|
|
Header.m_VersionLow = (uint16)(((float)fVersion - (float)(int)fVersion) * 10.1f);
|
|
Header.m_VersionHigh = (uint16)fVersion;
|
|
Header.m_nOffsetStringTable = pBin->m_Tokens.size() * sizeof(DWORD) + sizeof(Header);
|
|
Header.m_nOffsetParamsLocal = 0;
|
|
Header.m_nSourceCRC32 = nSourceCRC32;
|
|
SShaderBinHeader hdTemp, * pHD;
|
|
pHD = &Header;
|
|
if (CParserBin::m_bEndians)
|
|
{
|
|
hdTemp = Header;
|
|
SwapEndian(hdTemp, eBigEndian);
|
|
pHD = &hdTemp;
|
|
}
|
|
gEnv->pCryPak->FWrite((void*)pHD, sizeof(Header), 1, dstFileHandle);
|
|
if (CParserBin::m_bEndians)
|
|
{
|
|
DWORD* pT = new DWORD [pBin->m_Tokens.size()];
|
|
memcpy(pT, &pBin->m_Tokens[0], pBin->m_Tokens.size() * sizeof(DWORD));
|
|
SwapEndian(pT, (size_t)pBin->m_Tokens.size(), eBigEndian);
|
|
gEnv->pCryPak->FWrite((void*)pT, pBin->m_Tokens.size() * sizeof(DWORD), 1, dstFileHandle);
|
|
delete [] pT;
|
|
}
|
|
else
|
|
{
|
|
gEnv->pCryPak->FWrite(&pBin->m_Tokens[0], pBin->m_Tokens.size() * sizeof(DWORD), 1, dstFileHandle);
|
|
}
|
|
FXShaderTokenItor itor;
|
|
for (itor = pBin->m_TokenTable.begin(); itor != pBin->m_TokenTable.end(); itor++)
|
|
{
|
|
STokenD T = *itor;
|
|
if (CParserBin::m_bEndians)
|
|
{
|
|
SwapEndian(T.Token, eBigEndian);
|
|
}
|
|
gEnv->pCryPak->FWrite(&T.Token, sizeof(DWORD), 1, dstFileHandle);
|
|
gEnv->pCryPak->FWrite(T.SToken.c_str(), T.SToken.size() + 1, 1, dstFileHandle);
|
|
}
|
|
Header.m_nOffsetParamsLocal = aznumeric_caster(gEnv->pCryPak->FTell(dstFileHandle));
|
|
gEnv->pCryPak->FSeek(dstFileHandle, 0, SEEK_SET);
|
|
if (CParserBin::m_bEndians)
|
|
{
|
|
hdTemp = Header;
|
|
SwapEndian(hdTemp, eBigEndian);
|
|
pHD = &hdTemp;
|
|
}
|
|
gEnv->pCryPak->FWrite((void*)pHD, sizeof(Header), 1, dstFileHandle);
|
|
gEnv->pCryPak->FClose(dstFileHandle);
|
|
}
|
|
else
|
|
{
|
|
iLog->LogWarning("WARN: CShaderManBin::SaveBinShader: Cannot write shader to file '%s'.", nameFile);
|
|
pBin->m_bReadOnly = true;
|
|
}
|
|
|
|
SAFE_DELETE_ARRAY(pBuf);
|
|
|
|
return pBin;
|
|
}
|
|
|
|
//=========================================================================================================================================
|
|
|
|
static void sParseCSV(string& sFlt, std::vector<string>& Filters)
|
|
{
|
|
const char* cFlt = sFlt.c_str();
|
|
char Flt[64];
|
|
int nFlt = 0;
|
|
while (true)
|
|
{
|
|
char c = *cFlt++;
|
|
if (!c)
|
|
{
|
|
break;
|
|
}
|
|
if (SkipChar((unsigned char)c))
|
|
{
|
|
if (nFlt)
|
|
{
|
|
Flt[nFlt] = 0;
|
|
Filters.push_back(string(Flt));
|
|
nFlt = 0;
|
|
}
|
|
continue;
|
|
}
|
|
Flt[nFlt++] = c;
|
|
}
|
|
if (nFlt)
|
|
{
|
|
Flt[nFlt] = 0;
|
|
Filters.push_back(string(Flt));
|
|
}
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
|
|
struct FXParamsSortByName
|
|
{
|
|
bool operator () (const SFXParam& left, const SFXParam& right) const
|
|
{
|
|
return left.m_dwName[0] < right.m_dwName[0];
|
|
}
|
|
bool operator () (const uint32 left, const SFXParam& right) const
|
|
{
|
|
return left < right.m_dwName[0];
|
|
}
|
|
bool operator () (const SFXParam& left, uint32 right) const
|
|
{
|
|
return left.m_dwName[0] < right;
|
|
}
|
|
};
|
|
struct FXSamplersOldSortByName
|
|
{
|
|
bool operator () (const STexSamplerFX& left, const STexSamplerFX& right) const
|
|
{
|
|
return left.m_szName < right.m_szName;
|
|
}
|
|
bool operator () (const string left, const STexSamplerFX& right) const
|
|
{
|
|
return left < right.m_szName;
|
|
}
|
|
bool operator () (const STexSamplerFX& left, string right) const
|
|
{
|
|
return left.m_szName < right;
|
|
}
|
|
};
|
|
struct FXSamplersSortByName
|
|
{
|
|
bool operator () (const SFXSampler& left, const SFXSampler& right) const
|
|
{
|
|
return left.m_dwName[0] < right.m_dwName[0];
|
|
}
|
|
bool operator () (const uint32 left, const SFXSampler& right) const
|
|
{
|
|
return left < right.m_dwName[0];
|
|
}
|
|
bool operator () (const SFXSampler& left, const uint32 right) const
|
|
{
|
|
return left.m_dwName[0] < right;
|
|
}
|
|
};
|
|
struct FXTexturesSortByName
|
|
{
|
|
bool operator () (const SFXTexture& left, const SFXTexture& right) const
|
|
{
|
|
return left.m_dwName[0] < right.m_dwName[0];
|
|
}
|
|
bool operator () (const uint32 left, const SFXTexture& right) const
|
|
{
|
|
return left < right.m_dwName[0];
|
|
}
|
|
bool operator () (const SFXTexture& left, const uint32 right) const
|
|
{
|
|
return left.m_dwName[0] < right;
|
|
}
|
|
};
|
|
|
|
int CShaderManBin::mfSizeFXParams(uint32& nCount)
|
|
{
|
|
nCount = m_ShaderFXParams.size();
|
|
int nSize = sizeOfMap(m_ShaderFXParams);
|
|
return nSize;
|
|
}
|
|
|
|
void CShaderManBin::mfReleaseFXParams()
|
|
{
|
|
m_ShaderFXParams.clear();
|
|
}
|
|
|
|
SShaderFXParams& CShaderManBin::mfGetFXParams(CShader* pSH)
|
|
{
|
|
CCryNameTSCRC s = pSH->GetNameCRC();
|
|
ShaderFXParamsItor it = m_ShaderFXParams.find(s);
|
|
if (it != m_ShaderFXParams.end())
|
|
{
|
|
return it->second;
|
|
}
|
|
SShaderFXParams pr;
|
|
std::pair<ShaderFXParams::iterator, bool> insertLocation =
|
|
m_ShaderFXParams.insert(std::pair<CCryNameTSCRC, SShaderFXParams>(s, pr));
|
|
CRY_ASSERT(insertLocation.second);
|
|
return insertLocation.first->second;
|
|
}
|
|
|
|
void CShaderManBin::mfRemoveFXParams(CShader* pSH)
|
|
{
|
|
CCryNameTSCRC s = pSH->GetNameCRC();
|
|
ShaderFXParamsItor it = m_ShaderFXParams.find(s);
|
|
if (it != m_ShaderFXParams.end())
|
|
{
|
|
m_ShaderFXParams.erase(it);
|
|
}
|
|
}
|
|
|
|
SFXParam* CShaderManBin::mfAddFXParam(SShaderFXParams& FXP, const SFXParam* pParam)
|
|
{
|
|
FXParamsIt it = std::lower_bound(FXP.m_FXParams.begin(), FXP.m_FXParams.end(), pParam->m_dwName[0], FXParamsSortByName());
|
|
if (it != FXP.m_FXParams.end() && pParam->m_dwName[0] == (*it).m_dwName[0])
|
|
{
|
|
SFXParam& pr = *it;
|
|
pr.m_nFlags = pParam->m_nFlags;
|
|
int n = 6;
|
|
SFXParam& p = *it;
|
|
for (int i = 0; i < n; i++)
|
|
{
|
|
if (p.m_Register[i] == 10000)
|
|
{
|
|
p.m_Register[i] = pParam->m_Register[i];
|
|
}
|
|
}
|
|
//CRY_ASSERT(p == *pParam);
|
|
return &(*it);
|
|
}
|
|
FXP.m_FXParams.insert(it, *pParam);
|
|
it = std::lower_bound(FXP.m_FXParams.begin(), FXP.m_FXParams.end(), pParam->m_dwName[0], FXParamsSortByName());
|
|
SFXParam* pFX = &(*it);
|
|
if (pFX->m_Semantic.empty() && pFX->m_Values.c_str()[0] == '(')
|
|
{
|
|
pFX->m_BindingSlot = eConstantBufferShaderSlot_PerMaterial;
|
|
}
|
|
FXP.m_nFlags |= FXP_PARAMS_DIRTY;
|
|
|
|
return pFX;
|
|
}
|
|
SFXParam* CShaderManBin::mfAddFXParam(CShader* pSH, const SFXParam* pParam)
|
|
{
|
|
if (!pParam)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
SShaderFXParams& FXP = mfGetFXParams(pSH);
|
|
return mfAddFXParam(FXP, pParam);
|
|
}
|
|
void CShaderManBin::mfAddFXSampler(CShader* pSH, const STexSamplerFX* pSamp)
|
|
{
|
|
if (!pSamp)
|
|
{
|
|
return;
|
|
}
|
|
|
|
SShaderFXParams& FXP = mfGetFXParams(pSH);
|
|
|
|
FXSamplersOldIt it = std::lower_bound(FXP.m_FXSamplersOld.begin(), FXP.m_FXSamplersOld.end(), pSamp->m_szName, FXSamplersOldSortByName());
|
|
if (it != FXP.m_FXSamplersOld.end() && pSamp->m_szName == (*it).m_szName)
|
|
{
|
|
CRY_ASSERT(*it == *pSamp);
|
|
return;
|
|
}
|
|
FXP.m_FXSamplersOld.insert(it, *pSamp);
|
|
FXP.m_nFlags |= FXP_SAMPLERS_DIRTY;
|
|
}
|
|
void CShaderManBin::mfAddFXSampler(CShader* pSH, const SFXSampler* pSamp)
|
|
{
|
|
if (!pSamp)
|
|
{
|
|
return;
|
|
}
|
|
|
|
SShaderFXParams& FXP = mfGetFXParams(pSH);
|
|
|
|
FXSamplersIt it = std::lower_bound(FXP.m_FXSamplers.begin(), FXP.m_FXSamplers.end(), pSamp->m_dwName[0], FXSamplersSortByName());
|
|
if (it != FXP.m_FXSamplers.end() && pSamp->m_dwName[0] == (*it).m_dwName[0])
|
|
{
|
|
CRY_ASSERT(*it == *pSamp);
|
|
return;
|
|
}
|
|
FXP.m_FXSamplers.insert(it, *pSamp);
|
|
FXP.m_nFlags |= FXP_SAMPLERS_DIRTY;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Add a new texture to the shader's textures array based on the texture name
|
|
//------------------------------------------------------------------------------
|
|
void CShaderManBin::mfAddFXTexture(CShader* pSH, const SFXTexture* pTexture)
|
|
{
|
|
if (!pTexture)
|
|
{
|
|
return;
|
|
}
|
|
|
|
SShaderFXParams& FXP = mfGetFXParams(pSH);
|
|
FXTexturesIt it = std::lower_bound(FXP.m_FXTextures.begin(), FXP.m_FXTextures.end(), pTexture->m_dwName[0], FXTexturesSortByName());
|
|
|
|
if (it != FXP.m_FXTextures.end() && pTexture->m_dwName[0] == (*it).m_dwName[0])
|
|
{
|
|
CRY_ASSERT(*it == *pTexture);
|
|
return;
|
|
}
|
|
FXP.m_FXTextures.insert(it, *pTexture);
|
|
FXP.m_nFlags |= FXP_TEXTURES_DIRTY;
|
|
}
|
|
|
|
void CShaderManBin::mfGeneratePublicFXParams(CShader* pSH, CParserBin& Parser)
|
|
{
|
|
SShaderFXParams& FXP = mfGetFXParams(pSH);
|
|
if (!(FXP.m_nFlags & FXP_PARAMS_DIRTY))
|
|
{
|
|
return;
|
|
}
|
|
FXP.m_nFlags &= ~FXP_PARAMS_DIRTY;
|
|
|
|
uint32 i;
|
|
// Generate public parameters
|
|
for (i = 0; i < FXP.m_FXParams.size(); i++)
|
|
{
|
|
SFXParam* pr = &FXP.m_FXParams[i];
|
|
uint32 nFlags = pr->GetFlags();
|
|
if (nFlags & PF_AUTOMERGED)
|
|
{
|
|
continue;
|
|
}
|
|
if (nFlags & PF_TWEAKABLE_MASK)
|
|
{
|
|
const char* szName = Parser.GetString(pr->m_dwName[0]);
|
|
// Avoid duplicating of public parameters
|
|
int32 j;
|
|
for (j = 0; j < FXP.m_PublicParams.size(); j++)
|
|
{
|
|
SShaderParam* p = &FXP.m_PublicParams[j];
|
|
if (azstricmp(p->m_Name.c_str(), szName) == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (j == FXP.m_PublicParams.size())
|
|
{
|
|
SShaderParam sp;
|
|
sp.m_Name = szName;
|
|
EParamType eType;
|
|
string szWidget = pr->GetValueForName("UIWidget", eType);
|
|
const char* szVal = pr->m_Values.c_str();
|
|
if (szWidget == "color")
|
|
{
|
|
sp.m_Type = eType_FCOLOR;
|
|
if (szVal[0] == '{')
|
|
{
|
|
szVal++;
|
|
}
|
|
int n = azsscanf(szVal, "%f, %f, %f, %f", &sp.m_Value.m_Color[0], &sp.m_Value.m_Color[1], &sp.m_Value.m_Color[2], &sp.m_Value.m_Color[3]);
|
|
AZ_Warning("Shaders", n == 4, "color value only has %d components", n);
|
|
}
|
|
else if (szWidget == "colora")
|
|
{
|
|
sp.m_Type = eType_FCOLORA;
|
|
if (szVal[0] == '{')
|
|
{
|
|
szVal++;
|
|
}
|
|
int n = azsscanf(szVal, "%f, %f, %f, %f", &sp.m_Value.m_Color[0], &sp.m_Value.m_Color[1], &sp.m_Value.m_Color[2], &sp.m_Value.m_Color[3]);
|
|
AZ_Warning("Shaders", n == 4, "color value only has %d components", n);
|
|
}
|
|
else
|
|
{
|
|
sp.m_Type = eType_FLOAT;
|
|
sp.m_Value.m_Float = (float)atof(szVal);
|
|
}
|
|
|
|
bool bAdd = true;
|
|
if (!pr->m_Annotations.empty() && gRenDev->IsEditorMode())
|
|
{
|
|
//EParamType eType;
|
|
string sFlt = pr->GetValueForName("Filter", eType);
|
|
bool bUseScript = true;
|
|
if (!sFlt.empty())
|
|
{
|
|
std::vector<string> Filters;
|
|
sParseCSV(sFlt, Filters);
|
|
string strShader = Parser.m_pCurShader->GetName();
|
|
uint32 h;
|
|
for (h = 0; h < Filters.size(); h++)
|
|
{
|
|
if (!_strnicmp(Filters[h].c_str(), strShader.c_str(), Filters[h].size()))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (h == Filters.size())
|
|
{
|
|
bUseScript = false;
|
|
bAdd = false;
|
|
}
|
|
}
|
|
|
|
if (bUseScript)
|
|
{
|
|
sp.m_Script = pr->m_Annotations.c_str();
|
|
}
|
|
}
|
|
|
|
if (bAdd)
|
|
{
|
|
FXP.m_PublicParams.push_back(sp);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SParamCacheInfo* CShaderManBin::GetParamInfo(SShaderBin* pBin, uint32 dwName, uint64 nMaskGenFX, uint64 maskGenStatic)
|
|
{
|
|
const int n = pBin->m_ParamsCache.size();
|
|
for (int i = 0; i < n; i++)
|
|
{
|
|
SParamCacheInfo* pInf = &pBin->m_ParamsCache[i];
|
|
if (pInf->m_dwName == dwName && pInf->m_nMaskGenFX == nMaskGenFX && pInf->m_maskGenStatic == maskGenStatic)
|
|
{
|
|
pBin->m_nCurParamsID = i;
|
|
return pInf;
|
|
}
|
|
}
|
|
pBin->m_nCurParamsID = -1;
|
|
return NULL;
|
|
}
|
|
|
|
bool CShaderManBin::SaveBinShaderLocalInfo(SShaderBin* pBin, uint32 dwName, uint64 nMaskGenFX, uint64 maskGenStatic, TArray<int32>& Funcs, std::vector<SFXParam>& Params, std::vector<SFXSampler>& Samplers, std::vector<SFXTexture>& Textures)
|
|
{
|
|
if (GetParamInfo(pBin, dwName, nMaskGenFX, maskGenStatic))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (pBin->IsReadOnly() && !gEnv->IsEditor()) // if in the editor, allow params to be added in-memory, but not saved to disk
|
|
{
|
|
return false;
|
|
}
|
|
TArray<int32> EParams;
|
|
TArray<int32> ESamplers;
|
|
TArray<int32> ETextures;
|
|
TArray<int32> EFuncs;
|
|
for (uint32 i = 0; i < Params.size(); i++)
|
|
{
|
|
SFXParam& pr = Params[i];
|
|
CRY_ASSERT(pr.m_dwName.size());
|
|
if (pr.m_dwName.size())
|
|
{
|
|
EParams.push_back(pr.m_dwName[0]);
|
|
}
|
|
}
|
|
for (uint32 i = 0; i < Samplers.size(); i++)
|
|
{
|
|
SFXSampler& pr = Samplers[i];
|
|
CRY_ASSERT(pr.m_dwName.size());
|
|
if (pr.m_dwName.size())
|
|
{
|
|
ESamplers.push_back(pr.m_dwName[0]);
|
|
}
|
|
}
|
|
for (uint32 i = 0; i < Textures.size(); i++)
|
|
{
|
|
SFXTexture& pr = Textures[i];
|
|
CRY_ASSERT(pr.m_dwName.size());
|
|
if (pr.m_dwName.size())
|
|
{
|
|
ETextures.push_back(pr.m_dwName[0]);
|
|
}
|
|
}
|
|
pBin->m_nCurParamsID = pBin->m_ParamsCache.size();
|
|
pBin->m_ParamsCache.push_back(SParamCacheInfo());
|
|
SParamCacheInfo& pr = pBin->m_ParamsCache.back();
|
|
pr.m_nMaskGenFX = nMaskGenFX;
|
|
pr.m_maskGenStatic = maskGenStatic;
|
|
pr.m_dwName = dwName;
|
|
pr.m_AffectedFuncs.assign(Funcs.begin(), Funcs.end());
|
|
pr.m_AffectedParams.assign(EParams.begin(), EParams.end());
|
|
pr.m_AffectedSamplers.assign(ESamplers.begin(), ESamplers.end());
|
|
pr.m_AffectedTextures.assign(ETextures.begin(), ETextures.end());
|
|
if (pBin->IsReadOnly())
|
|
{
|
|
return false;
|
|
}
|
|
AZ::IO::HandleType binFileHandle = gEnv->pCryPak->FOpen(pBin->m_szName, "r+b", AZ::IO::IArchive::FLAGS_NEVER_IN_PAK | AZ::IO::IArchive::FLAGS_PATH_REAL | AZ::IO::IArchive::FOPEN_ONDISK);
|
|
CRY_ASSERT(binFileHandle != AZ::IO::InvalidHandle);
|
|
if (binFileHandle == AZ::IO::InvalidHandle)
|
|
{
|
|
return false;
|
|
}
|
|
gEnv->pCryPak->FSeek(binFileHandle, 0, SEEK_END);
|
|
uint64_t nSeek = gEnv->pCryPak->FTell(binFileHandle);
|
|
CRY_ASSERT(nSeek > 0);
|
|
if (nSeek == 0)
|
|
{
|
|
return false;
|
|
}
|
|
SShaderBinParamsHeader sd;
|
|
int32* pFuncs = &Funcs[0];
|
|
int32* pParams = EParams.size() ? &EParams[0] : NULL;
|
|
int32* pSamplers = ESamplers.size() ? &ESamplers[0] : NULL;
|
|
int32* pTextures = ETextures.size() ? &ETextures[0] : NULL;
|
|
sd.nMask = nMaskGenFX;
|
|
sd.nstaticMask = maskGenStatic;
|
|
sd.nName = dwName;
|
|
sd.nFuncs = Funcs.size();
|
|
sd.nParams = EParams.size();
|
|
sd.nSamplers = ESamplers.size();
|
|
sd.nTextures = ETextures.size();
|
|
if (CParserBin::m_bEndians)
|
|
{
|
|
SwapEndian(sd, eBigEndian);
|
|
EFuncs = Funcs;
|
|
if (EParams.size())
|
|
{
|
|
SwapEndian(&EParams[0], (size_t)EParams.size(), eBigEndian);
|
|
}
|
|
if (ESamplers.size())
|
|
{
|
|
SwapEndian(&ESamplers[0], (size_t)ESamplers.size(), eBigEndian);
|
|
}
|
|
if (ETextures.size())
|
|
{
|
|
SwapEndian(&ETextures[0], (size_t)ETextures.size(), eBigEndian);
|
|
}
|
|
SwapEndian(&EFuncs[0], (size_t)EFuncs.size(), eBigEndian);
|
|
pFuncs = &EFuncs[0];
|
|
}
|
|
gEnv->pCryPak->FWrite(&sd, sizeof(sd), 1, binFileHandle);
|
|
|
|
if (EParams.size())
|
|
{
|
|
gEnv->pCryPak->FWrite(pParams, EParams.size(), sizeof(int32), binFileHandle);
|
|
}
|
|
if (ESamplers.size())
|
|
{
|
|
gEnv->pCryPak->FWrite(pSamplers, ESamplers.size(), sizeof(int32), binFileHandle);
|
|
}
|
|
if (ETextures.size())
|
|
{
|
|
gEnv->pCryPak->FWrite(pTextures, ETextures.size(), sizeof(int32), binFileHandle);
|
|
}
|
|
gEnv->pCryPak->FWrite(pFuncs, Funcs.size(), sizeof(int32), binFileHandle);
|
|
gEnv->pCryPak->FClose(binFileHandle);
|
|
|
|
return true;
|
|
}
|
|
|
|
SShaderBin* CShaderManBin::LoadBinShader(AZ::IO::HandleType fpBin, const char* szName, const char* szNameBin, bool bReadParams)
|
|
{
|
|
LOADING_TIME_PROFILE_SECTION(iSystem);
|
|
|
|
gEnv->pCryPak->FSeek(fpBin, 0, SEEK_SET);
|
|
SShaderBinHeader Header;
|
|
size_t sizeRead = gEnv->pCryPak->FReadRaw(&Header, 1, sizeof(SShaderBinHeader), fpBin);
|
|
if (sizeRead != sizeof(SShaderBinHeader))
|
|
{
|
|
CryWarning(VALIDATOR_MODULE_RENDERER, VALIDATOR_ERROR, "Failed to read header for %s in CShaderManBin::LoadBinShader. Expected %" PRISIZE_T ", got %" PRISIZE_T "", szName, sizeof(SShaderBinHeader), sizeRead);
|
|
return NULL;
|
|
}
|
|
|
|
if (CParserBin::m_bEndians)
|
|
{
|
|
SwapEndian(Header, eBigEndian);
|
|
}
|
|
float fVersion = FX_CACHE_VER;
|
|
uint16 MinorVer = (uint16)(((float)fVersion - (float)(int)fVersion) * 10.1f);
|
|
uint16 MajorVer = (uint16)fVersion;
|
|
bool bCheckValid = CRenderer::CV_r_shadersAllowCompilation != 0;
|
|
if (bCheckValid && (Header.m_VersionLow != MinorVer || Header.m_VersionHigh != MajorVer || Header.m_Magic != FOURCC_SHADERBIN))
|
|
{
|
|
return NULL;
|
|
}
|
|
if (Header.m_VersionHigh > 10)
|
|
{
|
|
return NULL;
|
|
}
|
|
SShaderBin* pBin = new SShaderBin;
|
|
|
|
pBin->m_SourceCRC32 = Header.m_nSourceCRC32;
|
|
pBin->m_nOffsetLocalInfo = Header.m_nOffsetParamsLocal;
|
|
|
|
uint32 CRC32 = Header.m_CRC32;
|
|
pBin->m_CRC32 = CRC32;
|
|
pBin->m_Tokens.resize(Header.m_nTokens);
|
|
sizeRead = gEnv->pCryPak->FReadRaw(&pBin->m_Tokens[0], sizeof(uint32), Header.m_nTokens, fpBin);
|
|
if (sizeRead != Header.m_nTokens)
|
|
{
|
|
CryWarning(VALIDATOR_MODULE_RENDERER, VALIDATOR_ERROR, "Failed to read Tokens for %s in CShaderManBin::LoadBinShader. Expected %d, got %" PRISIZE_T "", szName, Header.m_nTokens, sizeRead);
|
|
return NULL;
|
|
}
|
|
if (CParserBin::m_bEndians)
|
|
{
|
|
SwapEndian(&pBin->m_Tokens[0], (size_t)Header.m_nTokens, eBigEndian);
|
|
}
|
|
|
|
int nSizeTable = Header.m_nOffsetParamsLocal - Header.m_nOffsetStringTable;
|
|
if (nSizeTable < 0)
|
|
{
|
|
return NULL;
|
|
}
|
|
else if (nSizeTable > 0)
|
|
{
|
|
char* bufTable = new char[nSizeTable];
|
|
char* bufT = bufTable;
|
|
sizeRead = gEnv->pCryPak->FReadRaw(bufTable, 1, nSizeTable, fpBin);
|
|
if (sizeRead != nSizeTable)
|
|
{
|
|
CryWarning(VALIDATOR_MODULE_RENDERER, VALIDATOR_ERROR, "Failed to read bufTable for %s in CShaderManBin::LoadBinShader. Expected %d, got %" PRISIZE_T "", szName, nSizeTable, sizeRead);
|
|
return NULL;
|
|
}
|
|
char* bufEnd = &bufTable[nSizeTable];
|
|
|
|
// First pass to count the tokens
|
|
uint32 nTokens(0);
|
|
while (bufTable < bufEnd)
|
|
{
|
|
STokenD TD;
|
|
LoadUnaligned(bufTable, TD.Token);
|
|
int nIncr = 4 + strlen(&bufTable[4]) + 1;
|
|
bufTable += nIncr;
|
|
++nTokens;
|
|
}
|
|
|
|
pBin->m_TokenTable.reserve(nTokens);
|
|
bufTable = bufT;
|
|
while (bufTable < bufEnd)
|
|
{
|
|
STokenD TD;
|
|
LoadUnaligned(bufTable, TD.Token);
|
|
if (CParserBin::m_bEndians)
|
|
{
|
|
SwapEndian(TD.Token, eBigEndian);
|
|
}
|
|
FXShaderTokenItor itor = std::lower_bound(pBin->m_TokenTable.begin(), pBin->m_TokenTable.end(), TD.Token, SortByToken());
|
|
assert (itor == pBin->m_TokenTable.end() || (*itor).Token != TD.Token);
|
|
TD.SToken = &bufTable[4];
|
|
pBin->m_TokenTable.insert(itor, TD);
|
|
int nIncr = 4 + strlen(&bufTable[4]) + 1;
|
|
bufTable += nIncr;
|
|
}
|
|
SAFE_DELETE_ARRAY(bufT);
|
|
}
|
|
|
|
//if (CRenderer::CV_r_shadersnocompile)
|
|
// bReadParams = false;
|
|
if (bReadParams)
|
|
{
|
|
int nSeek = pBin->m_nOffsetLocalInfo;
|
|
gEnv->pCryPak->FSeek(fpBin, nSeek, SEEK_SET);
|
|
while (true)
|
|
{
|
|
SShaderBinParamsHeader sd;
|
|
int nSize = gEnv->pCryPak->FReadRaw(&sd, 1, sizeof(sd), fpBin);
|
|
if (nSize != sizeof(sd))
|
|
{
|
|
break;
|
|
}
|
|
if (CParserBin::m_bEndians)
|
|
{
|
|
SwapEndian(sd, eBigEndian);
|
|
}
|
|
|
|
if (sd.nParams < 0 || sd.nSamplers < 0 || sd.nTextures < 0 || sd.nFuncs < 0)
|
|
{
|
|
AZ_Assert(false, "Error attempting to read shader binary %s. You may need to delete and re-compile this shader binary from your cache folder.", szNameBin);
|
|
return nullptr;
|
|
}
|
|
|
|
SParamCacheInfo pr;
|
|
int n = pBin->m_ParamsCache.size();
|
|
pBin->m_ParamsCache.push_back(pr);
|
|
SParamCacheInfo& prc = pBin->m_ParamsCache[n];
|
|
prc.m_dwName = sd.nName;
|
|
prc.m_nMaskGenFX = sd.nMask;
|
|
prc.m_maskGenStatic = sd.nstaticMask;
|
|
prc.m_AffectedParams.resize(sd.nParams);
|
|
prc.m_AffectedSamplers.resize(sd.nSamplers);
|
|
prc.m_AffectedTextures.resize(sd.nTextures);
|
|
prc.m_AffectedFuncs.resize(sd.nFuncs);
|
|
|
|
if (sd.nParams)
|
|
{
|
|
nSize = gEnv->pCryPak->FReadRaw(&prc.m_AffectedParams[0], sizeof(int32), sd.nParams, fpBin);
|
|
if (nSize != sd.nParams)
|
|
{
|
|
CryWarning(VALIDATOR_MODULE_RENDERER, VALIDATOR_ERROR, "Failed to read m_AffectedParams for %s in CShaderManBin::LoadBinShader. Expected %d, got %" PRISIZE_T "", szName, sd.nParams, sizeRead);
|
|
return NULL;
|
|
}
|
|
if (CParserBin::m_bEndians)
|
|
{
|
|
SwapEndian(&prc.m_AffectedParams[0], sd.nParams, eBigEndian);
|
|
}
|
|
}
|
|
if (sd.nSamplers)
|
|
{
|
|
nSize = gEnv->pCryPak->FReadRaw(&prc.m_AffectedSamplers[0], sizeof(int32), sd.nSamplers, fpBin);
|
|
if (nSize != sd.nSamplers)
|
|
{
|
|
CryWarning(VALIDATOR_MODULE_RENDERER, VALIDATOR_ERROR, "Failed to read m_AffectedSamplers for %s in CShaderManBin::LoadBinShader. Expected %d, got %" PRISIZE_T, szName, sd.nSamplers, sizeRead);
|
|
return NULL;
|
|
}
|
|
if (CParserBin::m_bEndians)
|
|
{
|
|
SwapEndian(&prc.m_AffectedSamplers[0], sd.nSamplers, eBigEndian);
|
|
}
|
|
}
|
|
if (sd.nTextures)
|
|
{
|
|
nSize = gEnv->pCryPak->FReadRaw(&prc.m_AffectedTextures[0], sizeof(int32), sd.nTextures, fpBin);
|
|
if (nSize != sd.nTextures)
|
|
{
|
|
CryWarning(VALIDATOR_MODULE_RENDERER, VALIDATOR_ERROR, "Failed to read m_AffectedTextures for %s in CShaderManBin::LoadBinShader. Expected %d, got %" PRISIZE_T, szName, sd.nTextures, sizeRead);
|
|
return NULL;
|
|
}
|
|
if (CParserBin::m_bEndians)
|
|
{
|
|
SwapEndian(&prc.m_AffectedTextures[0], sd.nTextures, eBigEndian);
|
|
}
|
|
}
|
|
|
|
CRY_ASSERT(sd.nFuncs > 0);
|
|
nSize = gEnv->pCryPak->FReadRaw(&prc.m_AffectedFuncs[0], sizeof(int32), sd.nFuncs, fpBin);
|
|
if (nSize != sd.nFuncs)
|
|
{
|
|
CryWarning(VALIDATOR_MODULE_RENDERER, VALIDATOR_ERROR, "Failed to read nFuncs for %s in CShaderManBin::LoadBinShader. Expected %d, got %" PRISIZE_T "", szName, sd.nFuncs, sizeRead);
|
|
return NULL;
|
|
}
|
|
if (CParserBin::m_bEndians)
|
|
{
|
|
SwapEndian(&prc.m_AffectedFuncs[0], sd.nFuncs, eBigEndian);
|
|
}
|
|
|
|
nSeek += (sd.nFuncs) * sizeof(int32) + sizeof(sd);
|
|
}
|
|
}
|
|
|
|
char nameLwr[256];
|
|
cry_strcpy(nameLwr, szName);
|
|
azstrlwr(nameLwr, AZ_ARRAY_SIZE(nameLwr));
|
|
pBin->SetName(szNameBin);
|
|
pBin->m_dwName = CParserBin::GetCRC32(nameLwr);
|
|
|
|
return pBin;
|
|
}
|
|
|
|
SShaderBin* CShaderManBin::SearchInCache(const char* szName, bool bInclude)
|
|
{
|
|
char nameFile[256], nameLwr[256];
|
|
cry_strcpy(nameLwr, szName);
|
|
azstrlwr(nameLwr, AZ_ARRAY_SIZE(nameLwr));
|
|
sprintf_s(nameFile, "%s.%s", nameLwr, bInclude ? "cfi" : "cfx");
|
|
uint32 dwName = CParserBin::GetCRC32(nameFile);
|
|
|
|
SShaderBin* pSB;
|
|
for (pSB = SShaderBin::s_Root.m_Prev; pSB != &SShaderBin::s_Root; pSB = pSB->m_Prev)
|
|
{
|
|
if (pSB->m_dwName == dwName)
|
|
{
|
|
pSB->Unlink();
|
|
pSB->Link(&SShaderBin::s_Root);
|
|
return pSB;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
bool CShaderManBin::AddToCache(SShaderBin* pSB, bool bInclude)
|
|
{
|
|
if IsCVarConstAccess(constexpr) (!CRenderer::CV_r_shadersediting)
|
|
{
|
|
if (SShaderBin::s_nCache >= SShaderBin::s_nMaxFXBinCache)
|
|
{
|
|
SShaderBin* pS;
|
|
for (pS = SShaderBin::s_Root.m_Prev; pS != &SShaderBin::s_Root; pS = pS->m_Prev)
|
|
{
|
|
if (!pS->m_bLocked)
|
|
{
|
|
DeleteFromCache(pS);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
CRY_ASSERT(SShaderBin::s_nCache < SShaderBin::s_nMaxFXBinCache);
|
|
}
|
|
|
|
pSB->m_bInclude = bInclude;
|
|
pSB->Link(&SShaderBin::s_Root);
|
|
SShaderBin::s_nCache++;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CShaderManBin::DeleteFromCache(SShaderBin* pSB)
|
|
{
|
|
CRY_ASSERT(pSB != &SShaderBin::s_Root);
|
|
pSB->Unlink();
|
|
SAFE_DELETE(pSB);
|
|
SShaderBin::s_nCache--;
|
|
|
|
return true;
|
|
}
|
|
|
|
void CShaderManBin::InvalidateCache(bool bIncludesOnly)
|
|
{
|
|
SShaderBin* pSB, * Next;
|
|
for (pSB = SShaderBin::s_Root.m_Next; pSB != &SShaderBin::s_Root; pSB = Next)
|
|
{
|
|
Next = pSB->m_Next;
|
|
if (bIncludesOnly && !pSB->m_bInclude)
|
|
{
|
|
continue;
|
|
}
|
|
DeleteFromCache(pSB);
|
|
}
|
|
SShaderBin::s_nMaxFXBinCache = MAX_FXBIN_CACHE;
|
|
m_bBinaryShadersLoaded = false;
|
|
|
|
g_shaderBucketAllocator.cleanup();
|
|
|
|
#if defined(SHADERS_SERIALIZING)
|
|
// Clear our .fxb cache if we are deleting our shader binary cache.
|
|
// We end up initializing part of the shader system with D3D11 as the platform
|
|
// and then switch to the real platform soon after, so make sure this cache is clean.
|
|
gRenDev->m_cEF.ClearSResourceCache();
|
|
#endif
|
|
}
|
|
|
|
#define SEC5_FILETIME 10*1000*1000*5
|
|
|
|
|
|
SShaderBin* CShaderManBin::GetBinShader(const char* szName, bool bInclude, uint32 nRefCRC, bool* pbChanged)
|
|
{
|
|
//static float sfTotalTime = 0.0f;
|
|
|
|
if (pbChanged)
|
|
{
|
|
if (gRenDev->IsEditorMode())
|
|
{
|
|
*pbChanged = false;
|
|
}
|
|
}
|
|
|
|
//float fTime0 = iTimer->GetAsyncCurTime();
|
|
|
|
SShaderBin* pSHB = SearchInCache(szName, bInclude);
|
|
if (pSHB)
|
|
{
|
|
return pSHB;
|
|
}
|
|
SShaderBinHeader Header[2];
|
|
memset(&Header, 0, 2 * sizeof(SShaderBinHeader));
|
|
char nameFile[256], nameBin[256];
|
|
AZ::IO::HandleType srcFileHandle = AZ::IO::InvalidHandle;
|
|
uint32 nSourceCRC32 = 0;
|
|
sprintf_s(nameFile, "%sCryFX/%s.%s", gRenDev->m_cEF.m_ShadersPath.c_str(), szName, bInclude ? "cfi" : "cfx");
|
|
#if !defined(_RELEASE)
|
|
{
|
|
srcFileHandle = gEnv->pCryPak->FOpen(nameFile, "rb");
|
|
nSourceCRC32 = srcFileHandle != AZ::IO::InvalidHandle ? gEnv->pCryPak->ComputeCRC(nameFile) : 0;
|
|
}
|
|
#endif
|
|
//char szPath[1024];
|
|
//getcwd(szPath, 1024);
|
|
sprintf_s(nameBin, "%s%s.%s", m_pCEF->m_ShadersCache.c_str(), szName, bInclude ? "cfib" : "cfxb");
|
|
AZ::IO::HandleType dstFileHandle = AZ::IO::InvalidHandle;
|
|
int i = 0, n = 2;
|
|
|
|
// don't load from the shadercache.pak when in editing mode
|
|
if IsCVarConstAccess(constexpr) (CRenderer::CV_r_shadersediting)
|
|
{
|
|
i = 1;
|
|
}
|
|
|
|
AZStd::string szDst = m_pCEF->m_szCachePath + nameBin;
|
|
byte bValid = 0;
|
|
float fVersion = FX_CACHE_VER;
|
|
for (; i < n; i++)
|
|
{
|
|
if (dstFileHandle != AZ::IO::InvalidHandle)
|
|
{
|
|
gEnv->pCryPak->FClose(dstFileHandle);
|
|
}
|
|
if (!i)
|
|
{
|
|
if (n == 2)
|
|
{
|
|
char nameLwr[256];
|
|
sprintf_s(nameLwr, "%s.%s", szName, bInclude ? "cfi" : "cfx");
|
|
azstrlwr(nameLwr, AZ_ARRAY_SIZE(nameLwr));
|
|
uint32 dwName = CParserBin::GetCRC32(nameLwr);
|
|
FXShaderBinValidCRCItor itor = m_BinValidCRCs.find(dwName);
|
|
if (itor != m_BinValidCRCs.end())
|
|
{
|
|
CRY_ASSERT(itor->second == false);
|
|
continue;
|
|
}
|
|
}
|
|
dstFileHandle = gEnv->pCryPak->FOpen(nameBin, "rb");
|
|
}
|
|
else
|
|
{
|
|
dstFileHandle = gEnv->pCryPak->FOpen(szDst.c_str(), "rb", AZ::IO::IArchive::FLAGS_NEVER_IN_PAK | AZ::IO::IArchive::FLAGS_PATH_REAL | AZ::IO::IArchive::FOPEN_ONDISK);
|
|
}
|
|
if (dstFileHandle == AZ::IO::InvalidHandle)
|
|
{
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
gEnv->pCryPak->FReadRaw(&Header[i], 1, sizeof(SShaderBinHeader), dstFileHandle);
|
|
if (CParserBin::m_bEndians)
|
|
{
|
|
SwapEndian(Header[i], eBigEndian);
|
|
}
|
|
|
|
#if !defined(_RELEASE)
|
|
// check source crc changes
|
|
if (nSourceCRC32 && nSourceCRC32 != Header[i].m_nSourceCRC32)
|
|
{
|
|
bValid |= 1 << i;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
uint16 MinorVer = (uint16)(((float)fVersion - (float)(int)fVersion) * 10.1f);
|
|
uint16 MajorVer = (uint16)fVersion;
|
|
if (Header[i].m_VersionLow != MinorVer || Header[i].m_VersionHigh != MajorVer || Header[i].m_Magic != FOURCC_SHADERBIN)
|
|
{
|
|
bValid |= 4 << i;
|
|
}
|
|
else
|
|
if (nRefCRC && Header[i].m_CRC32 != nRefCRC)
|
|
{
|
|
bValid |= 0x10 << i;
|
|
}
|
|
}
|
|
}
|
|
if (!(bValid & (0x15 << i)))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (i == n)
|
|
{
|
|
#if !defined(_RELEASE) && !defined(CONSOLE_CONST_CVAR_MODE)
|
|
{
|
|
char acTemp[512];
|
|
if (bValid & 1)
|
|
{
|
|
sprintf_s(acTemp, 512, "WARNING: Bin FXShader '%s' source crc mismatch", nameBin);
|
|
}
|
|
if (bValid & 4)
|
|
{
|
|
sprintf_s(acTemp, 512, "WARNING: Bin FXShader '%s' version mismatch (Cache: %d.%d, Expected: %.1f)", nameBin, Header[0].m_VersionHigh, Header[0].m_VersionLow, fVersion);
|
|
}
|
|
if (bValid & 0x10)
|
|
{
|
|
sprintf_s(acTemp, 512, "WARNING: Bin FXShader '%s' CRC mismatch", nameBin);
|
|
}
|
|
|
|
if (bValid & 2)
|
|
{
|
|
sprintf_s(acTemp, 512, "WARNING: Bin FXShader USER '%s' source crc mismatch", nameBin);
|
|
}
|
|
if (bValid & 8)
|
|
{
|
|
sprintf_s(acTemp, 512, "WARNING: Bin FXShader USER '%s' version mismatch (Cache: %d.%d, Expected: %.1f)", nameBin, Header[1].m_VersionHigh, Header[1].m_VersionLow, fVersion);
|
|
}
|
|
if (bValid & 0x20)
|
|
{
|
|
sprintf_s(acTemp, 512, "WARNING: Bin FXShader USER '%s' CRC mismatch", nameBin);
|
|
}
|
|
|
|
if (bValid)
|
|
{
|
|
LogWarningEngineOnly(acTemp);
|
|
}
|
|
|
|
if (dstFileHandle != AZ::IO::InvalidHandle)
|
|
{
|
|
gEnv->pCryPak->FClose(dstFileHandle);
|
|
dstFileHandle = AZ::IO::InvalidHandle;
|
|
}
|
|
|
|
if (srcFileHandle != AZ::IO::InvalidHandle)
|
|
{
|
|
// enable shader compilation again, and show big error message
|
|
if (!CRenderer::CV_r_shadersAllowCompilation)
|
|
{
|
|
if (CRenderer::CV_r_shaderscompileautoactivate)
|
|
{
|
|
CRenderer::CV_r_shadersAllowCompilation = 1;
|
|
CRenderer::CV_r_shadersasyncactivation = 0;
|
|
|
|
gEnv->pLog->LogError("ERROR: LOADING BIN SHADER - REACTIVATING SHADER COMPILATION !");
|
|
}
|
|
else
|
|
{
|
|
static bool bShowMessageBox = true;
|
|
|
|
if (bShowMessageBox)
|
|
{
|
|
AZStd::string result;
|
|
EBUS_EVENT_RESULT(result, AZ::NativeUI::NativeUIRequestBus, DisplayOkDialog, "Invalid ShaderCache", acTemp, true);
|
|
if (result == "Cancel")
|
|
{
|
|
DebugBreak();
|
|
}
|
|
else if (!result.empty())
|
|
{
|
|
bShowMessageBox = false;
|
|
Sleep(33);
|
|
}
|
|
else
|
|
{
|
|
Warning("Invalid ShaderCache");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (CRenderer::CV_r_shadersAllowCompilation)
|
|
{
|
|
pSHB = SaveBinShader(nSourceCRC32, szName, bInclude, srcFileHandle);
|
|
CRY_ASSERT(!pSHB->m_Next);
|
|
if (pbChanged)
|
|
{
|
|
*pbChanged = true;
|
|
}
|
|
|
|
// remove the entries in the looupdata, to be sure that level and global caches have also become invalid for these shaders!
|
|
gRenDev->m_cEF.m_ResLookupDataMan[CACHE_READONLY].RemoveData(Header[0].m_CRC32);
|
|
gRenDev->m_cEF.m_ResLookupDataMan[CACHE_USER].RemoveData(Header[1].m_CRC32);
|
|
|
|
// has the shader been successfully written to the dest address
|
|
dstFileHandle = gEnv->pCryPak->FOpen(szDst.c_str(), "rb", AZ::IO::IArchive::FLAGS_NEVER_IN_PAK | AZ::IO::IArchive::FLAGS_PATH_REAL | AZ::IO::IArchive::FOPEN_ONDISK);
|
|
if (dstFileHandle != AZ::IO::InvalidHandle)
|
|
{
|
|
SAFE_DELETE(pSHB);
|
|
i = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
if (srcFileHandle != AZ::IO::InvalidHandle)
|
|
{
|
|
gEnv->pCryPak->FClose(srcFileHandle);
|
|
srcFileHandle = AZ::IO::InvalidHandle;
|
|
}
|
|
|
|
if (!CRenderer::CV_r_shadersAllowCompilation)
|
|
{
|
|
if (pSHB == 0 && dstFileHandle == AZ::IO::InvalidHandle)
|
|
{
|
|
//do only perform the necessary stuff
|
|
dstFileHandle = gEnv->pCryPak->FOpen(nameBin, "rb");
|
|
}
|
|
}
|
|
if (pSHB == 0 && dstFileHandle != AZ::IO::InvalidHandle)
|
|
{
|
|
sprintf_s(nameFile, "%s.%s", szName, bInclude ? "cfi" : "cfx");
|
|
pSHB = LoadBinShader(dstFileHandle, nameFile, i == 0 ? nameBin : szDst.c_str(), !bInclude);
|
|
gEnv->pCryPak->FClose(dstFileHandle);
|
|
dstFileHandle = AZ::IO::InvalidHandle;
|
|
AZ_Assert(pSHB, "Error loading binary shader '%s'.", nameFile);
|
|
}
|
|
|
|
if (pSHB)
|
|
{
|
|
if (i == 0)
|
|
{
|
|
pSHB->m_bReadOnly = true;
|
|
}
|
|
else
|
|
{
|
|
pSHB->m_bReadOnly = false;
|
|
}
|
|
|
|
AddToCache(pSHB, bInclude);
|
|
if (!bInclude)
|
|
{
|
|
char nm[128];
|
|
nm[0] = '$';
|
|
azstrcpy(&nm[1], AZ_ARRAY_SIZE(nm) - 1, szName);
|
|
CCryNameTSCRC NM = CParserBin::GetPlatformSpecName(nm);
|
|
FXShaderBinPathItor it = m_BinPaths.find(NM);
|
|
if (it == m_BinPaths.end())
|
|
{
|
|
m_BinPaths.insert(FXShaderBinPath::value_type(NM, i == 0 ? nameBin : szDst.c_str()));
|
|
}
|
|
else
|
|
{
|
|
it->second = (i == 0) ? nameBin : szDst.c_str();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (dstFileHandle != AZ::IO::InvalidHandle)
|
|
{
|
|
Warning("Error: Failed to get binary shader '%s'", nameFile);
|
|
}
|
|
else
|
|
{
|
|
sprintf_s(nameFile, "%s.%s", szName, bInclude ? "cfi" : "cfx");
|
|
const char* matName = 0;
|
|
if (m_pCEF && m_pCEF->m_pCurInputResources)
|
|
{
|
|
matName = m_pCEF->m_pCurInputResources->m_szMaterialName;
|
|
}
|
|
iLog->LogWarning("WARN: Shader \"%s\" doesn't exist (used in material \"%s\")", nameFile, matName != 0 ? matName : "$unknown$");
|
|
}
|
|
}
|
|
|
|
/*
|
|
sfTotalTime += iTimer->GetAsyncCurTime() - fTime0;
|
|
|
|
{
|
|
char acTmp[1024];
|
|
sprintf_s(acTmp, "Parsing of bin took: %f \n", sfTotalTime);
|
|
OutputDebugString(acTmp);
|
|
}
|
|
*/
|
|
|
|
return pSHB;
|
|
}
|
|
|
|
void CShaderManBin::AddGenMacroses(SShaderGen* shG, CParserBin& Parser, uint64 nMaskGen, bool ignoreShaderGenMask /*=false*/)
|
|
{
|
|
if (!nMaskGen || !shG)
|
|
{
|
|
return;
|
|
}
|
|
|
|
uint32 dwMacro = eT_1;
|
|
for (uint32 i = 0; i < shG->m_BitMask.Num(); i++)
|
|
{
|
|
if (shG->m_BitMask[i]->m_Mask & nMaskGen)
|
|
{
|
|
Parser.AddMacro(shG->m_BitMask[i]->m_dwToken, &dwMacro, 1, ignoreShaderGenMask ? 0 : shG->m_BitMask[i]->m_Mask, Parser.m_Macros[1]);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CShaderManBin::ParseBinFX_Global_Annotations(CParserBin& Parser, SParserFrame& Frame, bool* bPublic, [[maybe_unused]] CCryNameR techStart[2])
|
|
{
|
|
bool bRes = true;
|
|
|
|
SParserFrame OldFrame = Parser.BeginFrame(Frame);
|
|
|
|
FX_BEGIN_TOKENS
|
|
FX_TOKEN(ShaderType)
|
|
FX_TOKEN(ShaderDrawType)
|
|
FX_TOKEN(PreprType)
|
|
FX_TOKEN(Public)
|
|
FX_TOKEN(NoPreview)
|
|
FX_TOKEN(LocalConstants)
|
|
FX_TOKEN(Cull)
|
|
FX_TOKEN(SupportsAttrInstancing)
|
|
FX_TOKEN(SupportsConstInstancing)
|
|
FX_TOKEN(SupportsDeferredShading)
|
|
FX_TOKEN(SupportsFullDeferredShading)
|
|
FX_TOKEN(Decal)
|
|
FX_TOKEN(DecalNoDepthOffset)
|
|
FX_TOKEN(HWTessellation)
|
|
FX_TOKEN(ZPrePass)
|
|
FX_TOKEN(VertexColors)
|
|
FX_TOKEN(NoChunkMerging)
|
|
FX_TOKEN(ForceTransPass)
|
|
FX_TOKEN(AfterHDRPostProcess)
|
|
FX_TOKEN(AfterPostProcess)
|
|
FX_TOKEN(ForceZpass)
|
|
FX_TOKEN(ForceWaterPass)
|
|
FX_TOKEN(ForceDrawLast)
|
|
FX_TOKEN(ForceDrawFirst)
|
|
FX_TOKEN(Hair)
|
|
FX_TOKEN(SkinPass)
|
|
FX_TOKEN(ForceGeneralPass)
|
|
FX_TOKEN(ForceDrawAfterWater)
|
|
FX_TOKEN(DepthFixup)
|
|
FX_TOKEN(SingleLightPass)
|
|
FX_TOKEN(Refractive)
|
|
FX_TOKEN(ForceRefractionUpdate)
|
|
FX_TOKEN(WaterParticle)
|
|
FX_TOKEN(VT_DetailBending)
|
|
FX_TOKEN(VT_DetailBendingGrass)
|
|
FX_TOKEN(VT_WindBending)
|
|
FX_TOKEN(AlphaBlendShadows)
|
|
FX_TOKEN(EyeOverlay)
|
|
FX_END_TOKENS
|
|
|
|
int nIndex;
|
|
CShader* ef = Parser.m_pCurShader;
|
|
|
|
while (Parser.ParseObject(sCommands, nIndex))
|
|
{
|
|
EToken eT = Parser.GetToken();
|
|
switch (eT)
|
|
{
|
|
case eT_Public:
|
|
if (bPublic)
|
|
{
|
|
*bPublic = true;
|
|
}
|
|
break;
|
|
|
|
case eT_NoPreview:
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
ef->m_Flags |= EF_NOPREVIEW;
|
|
break;
|
|
|
|
case eT_Decal:
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
ef->m_Flags |= EF_DECAL;
|
|
ef->m_nMDV |= MDV_DEPTH_OFFSET;
|
|
break;
|
|
|
|
case eT_DecalNoDepthOffset:
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
ef->m_Flags |= EF_DECAL;
|
|
break;
|
|
|
|
|
|
case eT_LocalConstants:
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
ef->m_Flags |= EF_LOCALCONSTANTS;
|
|
break;
|
|
|
|
case eT_VT_DetailBending:
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
ef->m_nMDV |= MDV_DET_BENDING;
|
|
break;
|
|
case eT_VT_DetailBendingGrass:
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
ef->m_nMDV |= MDV_DET_BENDING | MDV_DET_BENDING_GRASS;
|
|
break;
|
|
case eT_VT_WindBending:
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
ef->m_nMDV |= MDV_WIND;
|
|
break;
|
|
|
|
case eT_NoChunkMerging:
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
ef->m_Flags |= EF_NOCHUNKMERGING;
|
|
break;
|
|
|
|
case eT_SupportsAttrInstancing:
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
if (gRenDev->m_bDeviceSupportsInstancing)
|
|
{
|
|
ef->m_Flags |= EF_SUPPORTSINSTANCING_ATTR;
|
|
}
|
|
break;
|
|
case eT_SupportsConstInstancing:
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
if (gRenDev->m_bDeviceSupportsInstancing)
|
|
{
|
|
ef->m_Flags |= EF_SUPPORTSINSTANCING_CONST;
|
|
}
|
|
break;
|
|
|
|
case eT_SupportsDeferredShading:
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
ef->m_Flags |= EF_SUPPORTSDEFERREDSHADING_MIXED;
|
|
break;
|
|
|
|
case eT_SupportsFullDeferredShading:
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
ef->m_Flags |= EF_SUPPORTSDEFERREDSHADING_FULL;
|
|
break;
|
|
|
|
case eT_ForceTransPass:
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
ef->m_Flags2 |= EF2_FORCE_TRANSPASS;
|
|
break;
|
|
|
|
case eT_AfterHDRPostProcess:
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
ef->m_Flags2 |= EF2_AFTERHDRPOSTPROCESS;
|
|
break;
|
|
|
|
case eT_AfterPostProcess:
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
ef->m_Flags2 |= EF2_AFTERPOSTPROCESS;
|
|
break;
|
|
|
|
case eT_ForceZpass:
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
ef->m_Flags2 |= EF2_FORCE_ZPASS;
|
|
break;
|
|
|
|
case eT_ForceWaterPass:
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
ef->m_Flags2 |= EF2_FORCE_WATERPASS;
|
|
break;
|
|
|
|
case eT_ForceDrawLast:
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
ef->m_Flags2 |= EF2_FORCE_DRAWLAST;
|
|
break;
|
|
case eT_ForceDrawFirst:
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
ef->m_Flags2 |= EF2_FORCE_DRAWFIRST;
|
|
break;
|
|
|
|
case eT_Hair:
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
ef->m_Flags2 |= EF2_HAIR;
|
|
break;
|
|
|
|
case eT_ForceGeneralPass:
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
ef->m_Flags2 |= EF2_FORCE_GENERALPASS;
|
|
break;
|
|
|
|
case eT_ForceDrawAfterWater:
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
ef->m_Flags2 |= EF2_FORCE_DRAWAFTERWATER;
|
|
break;
|
|
case eT_DepthFixup:
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
ef->m_Flags2 |= EF2_DEPTH_FIXUP;
|
|
break;
|
|
case eT_SingleLightPass:
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
ef->m_Flags2 |= EF2_SINGLELIGHTPASS;
|
|
break;
|
|
case eT_WaterParticle:
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
ef->m_Flags |= EF_WATERPARTICLE;
|
|
break;
|
|
case eT_Refractive:
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
ef->m_Flags |= EF_REFRACTIVE;
|
|
break;
|
|
case eT_ForceRefractionUpdate:
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
ef->m_Flags |= EF_FORCEREFRACTIONUPDATE;
|
|
break;
|
|
|
|
case eT_ZPrePass:
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
ef->m_Flags2 |= EF2_ZPREPASS;
|
|
break;
|
|
|
|
case eT_HWTessellation:
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
ef->m_Flags2 |= EF2_HW_TESSELLATION;
|
|
break;
|
|
|
|
case eT_AlphaBlendShadows:
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
ef->m_Flags2 |= EF2_ALPHABLENDSHADOWS;
|
|
break;
|
|
|
|
case eT_SkinPass:
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
ef->m_Flags2 |= EF2_SKINPASS;
|
|
break;
|
|
|
|
case eT_EyeOverlay:
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
ef->m_Flags2 |= EF2_EYE_OVERLAY;
|
|
break;
|
|
|
|
case eT_VertexColors:
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
ef->m_Flags2 |= EF2_VERTEXCOLORS;
|
|
break;
|
|
|
|
case eT_ShaderDrawType:
|
|
{
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
eT = Parser.GetToken(Parser.m_Data);
|
|
if (eT == eT_Light)
|
|
{
|
|
ef->m_eSHDType = eSHDT_Light;
|
|
}
|
|
else
|
|
if (eT == eT_Shadow)
|
|
{
|
|
ef->m_eSHDType = eSHDT_Shadow;
|
|
}
|
|
else
|
|
if (eT == eT_Fur)
|
|
{
|
|
ef->m_eSHDType = eSHDT_Fur;
|
|
}
|
|
else
|
|
if (eT == eT_General)
|
|
{
|
|
ef->m_eSHDType = eSHDT_General;
|
|
}
|
|
else
|
|
if (eT == eT_Terrain)
|
|
{
|
|
ef->m_eSHDType = eSHDT_Terrain;
|
|
}
|
|
else
|
|
if (eT == eT_Overlay)
|
|
{
|
|
ef->m_eSHDType = eSHDT_Overlay;
|
|
}
|
|
else
|
|
if (eT == eT_NoDraw)
|
|
{
|
|
ef->m_eSHDType = eSHDT_NoDraw;
|
|
ef->m_Flags |= EF_NODRAW;
|
|
}
|
|
else
|
|
if (eT == eT_Custom)
|
|
{
|
|
ef->m_eSHDType = eSHDT_CustomDraw;
|
|
}
|
|
else
|
|
if (eT == eT_Sky)
|
|
{
|
|
ef->m_eSHDType = eSHDT_Sky;
|
|
ef->m_Flags |= EF_SKY;
|
|
}
|
|
else
|
|
if (eT == eT_OceanShore)
|
|
{
|
|
ef->m_eSHDType = eSHDT_OceanShore;
|
|
}
|
|
else
|
|
{
|
|
Warning("Unknown shader draw type '%s'", Parser.GetString(eT));
|
|
CRY_ASSERT(0);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case eT_ShaderType:
|
|
{
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
eT = Parser.GetToken(Parser.m_Data);
|
|
if (eT == eT_General)
|
|
{
|
|
ef->m_eShaderType = eST_General;
|
|
}
|
|
else
|
|
if (eT == eT_Metal)
|
|
{
|
|
ef->m_eShaderType = eST_Metal;
|
|
}
|
|
else
|
|
if (eT == eT_Ice)
|
|
{
|
|
ef->m_eShaderType = eST_Ice;
|
|
}
|
|
else
|
|
if (eT == eT_Shadow)
|
|
{
|
|
ef->m_eShaderType = eST_Shadow;
|
|
}
|
|
else
|
|
if (eT == eT_Water)
|
|
{
|
|
ef->m_eShaderType = eST_Water;
|
|
}
|
|
else
|
|
if (eT == eT_FX)
|
|
{
|
|
ef->m_eShaderType = eST_FX;
|
|
}
|
|
else
|
|
if (eT == eT_PostProcess)
|
|
{
|
|
ef->m_eShaderType = eST_PostProcess;
|
|
}
|
|
else
|
|
if (eT == eT_HDR)
|
|
{
|
|
ef->m_eShaderType = eST_HDR;
|
|
}
|
|
else
|
|
if (eT == eT_Sky)
|
|
{
|
|
ef->m_eShaderType = eST_Sky;
|
|
}
|
|
else
|
|
if (eT == eT_Glass)
|
|
{
|
|
ef->m_eShaderType = eST_Glass;
|
|
}
|
|
else
|
|
if (eT == eT_Vegetation)
|
|
{
|
|
// Do nothing here
|
|
}
|
|
else
|
|
if (eT == eT_Particle)
|
|
{
|
|
// Do nothing here
|
|
}
|
|
else
|
|
if (eT == eT_Terrain)
|
|
{
|
|
//Do nothing here
|
|
}
|
|
else
|
|
if (eT == eT_Compute)
|
|
{
|
|
ef->m_eShaderType = eST_Compute;
|
|
}
|
|
else
|
|
{
|
|
Warning("Unknown shader type '%s'", Parser.GetString(eT));
|
|
CRY_ASSERT(0);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case eT_PreprType:
|
|
{
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
eT = Parser.GetToken(Parser.m_Data);
|
|
if (eT == eT_GenerateSprites)
|
|
{
|
|
; // We can't get of the token without cleaning out all the content but we can make it not do anything;
|
|
}
|
|
else
|
|
if (eT == eT_GenerateClouds)
|
|
{
|
|
ef->m_Flags2 |= EF2_PREPR_GENCLOUDS;
|
|
}
|
|
else
|
|
if (eT == eT_ScanWater)
|
|
{
|
|
ef->m_Flags2 |= EF2_PREPR_SCANWATER;
|
|
}
|
|
else
|
|
{
|
|
Warning("Unknown preprocess type '%s'", Parser.GetString(eT));
|
|
CRY_ASSERT(0);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case eT_Cull:
|
|
{
|
|
if (!ef)
|
|
{
|
|
break;
|
|
}
|
|
eT = Parser.GetToken(Parser.m_Data);
|
|
if (eT == eT_None || eT == eT_NONE)
|
|
{
|
|
ef->m_eCull = eCULL_None;
|
|
}
|
|
else
|
|
if (eT == eT_CCW || eT == eT_Back)
|
|
{
|
|
ef->m_eCull = eCULL_Back;
|
|
}
|
|
else
|
|
if (eT == eT_CW || eT == eT_Front)
|
|
{
|
|
ef->m_eCull = eCULL_Front;
|
|
}
|
|
else
|
|
{
|
|
CRY_ASSERT(0);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
CRY_ASSERT(0);
|
|
}
|
|
}
|
|
|
|
Parser.EndFrame(OldFrame);
|
|
|
|
return bRes;
|
|
}
|
|
|
|
bool CShaderManBin::ParseBinFX_Global(CParserBin& Parser, SParserFrame& Frame, bool* bPublic, CCryNameR techStart[2])
|
|
{
|
|
bool bRes = true;
|
|
|
|
SParserFrame OldFrame = Parser.BeginFrame(Frame);
|
|
|
|
FX_BEGIN_TOKENS
|
|
FX_TOKEN(string)
|
|
FX_END_TOKENS
|
|
|
|
int nIndex;
|
|
while (Parser.ParseObject(sCommands, nIndex))
|
|
{
|
|
EToken eT = Parser.GetToken();
|
|
switch (eT)
|
|
{
|
|
case eT_string:
|
|
{
|
|
eT = Parser.GetToken(Parser.m_Name);
|
|
CRY_ASSERT(eT == eT_Script);
|
|
bRes &= ParseBinFX_Global_Annotations(Parser, Parser.m_Data, bPublic, techStart);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
CRY_ASSERT(0);
|
|
}
|
|
}
|
|
|
|
Parser.EndFrame(OldFrame);
|
|
|
|
return bRes;
|
|
}
|
|
|
|
static int sGetTAddress(uint32 nToken)
|
|
{
|
|
switch (nToken)
|
|
{
|
|
case eT_Clamp:
|
|
return TADDR_CLAMP;
|
|
case eT_Border:
|
|
return TADDR_BORDER;
|
|
case eT_Wrap:
|
|
return TADDR_WRAP;
|
|
case eT_Mirror:
|
|
return TADDR_MIRROR;
|
|
default:
|
|
CRY_ASSERT(0);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void STexSamplerFX::PostLoad()
|
|
{
|
|
SHRenderTarget* pRt = m_pTarget;
|
|
if (!pRt)
|
|
{
|
|
return;
|
|
}
|
|
if (!_strnicmp(m_szTexture.c_str(), "$RT_2D", 6))
|
|
{
|
|
if (pRt->m_nIDInPool >= 0)
|
|
{
|
|
if ((int)CTexture::s_CustomRT_2D->Num() <= pRt->m_nIDInPool)
|
|
{
|
|
CTexture::s_CustomRT_2D->Expand(pRt->m_nIDInPool + 1);
|
|
}
|
|
}
|
|
pRt->m_pTarget[0] = CTexture::s_ptexRT_2D;
|
|
}
|
|
}
|
|
|
|
bool CShaderManBin::ParseBinFX_Sampler_Annotations_Script(CParserBin& Parser, SParserFrame& Frame, STexSamplerFX* pSampler)
|
|
{
|
|
bool bRes = true;
|
|
|
|
SParserFrame OldFrame = Parser.BeginFrame(Frame);
|
|
|
|
FX_BEGIN_TOKENS
|
|
FX_TOKEN(RenderOrder)
|
|
FX_TOKEN(ProcessOrder)
|
|
FX_TOKEN(RenderCamera)
|
|
FX_TOKEN(RenderType)
|
|
FX_TOKEN(RenderFilter)
|
|
FX_TOKEN(RenderColorTarget1)
|
|
FX_TOKEN(RenderDepthStencilTarget)
|
|
FX_TOKEN(ClearSetColor)
|
|
FX_TOKEN(ClearSetDepth)
|
|
FX_TOKEN(ClearTarget)
|
|
FX_TOKEN(RenderTarget_IDPool)
|
|
FX_TOKEN(RenderTarget_UpdateType)
|
|
FX_TOKEN(RenderTarget_Width)
|
|
FX_TOKEN(RenderTarget_Height)
|
|
FX_TOKEN(GenerateMips)
|
|
FX_END_TOKENS
|
|
|
|
SHRenderTarget * pRt = new SHRenderTarget;
|
|
int nIndex;
|
|
|
|
while (Parser.ParseObject(sCommands, nIndex))
|
|
{
|
|
EToken eT = Parser.GetToken();
|
|
switch (eT)
|
|
{
|
|
case eT_RenderOrder:
|
|
{
|
|
eT = Parser.GetToken(Parser.m_Data);
|
|
if (eT == eT_PreProcess)
|
|
{
|
|
pRt->m_eOrder = eRO_PreProcess;
|
|
}
|
|
else
|
|
if (eT == eT_PostProcess)
|
|
{
|
|
pRt->m_eOrder = eRO_PostProcess;
|
|
}
|
|
else
|
|
if (eT == eT_PreDraw)
|
|
{
|
|
pRt->m_eOrder = eRO_PreDraw;
|
|
}
|
|
else
|
|
{
|
|
CRY_ASSERT(0);
|
|
Warning("Unknown RenderOrder type '%s'", Parser.GetString(eT));
|
|
}
|
|
}
|
|
break;
|
|
|
|
case eT_ProcessOrder:
|
|
{
|
|
eT = Parser.GetToken(Parser.m_Data);
|
|
if (eT == eT_WaterReflection)
|
|
{
|
|
pRt->m_nProcessFlags = FSPR_SCANTEXWATER;
|
|
}
|
|
else
|
|
{
|
|
CRY_ASSERT(0);
|
|
Warning("Unknown ProcessOrder type '%s'", Parser.GetString(eT));
|
|
}
|
|
}
|
|
break;
|
|
|
|
case eT_RenderCamera:
|
|
{
|
|
eT = Parser.GetToken(Parser.m_Data);
|
|
if (eT == eT_WaterPlaneReflected)
|
|
{
|
|
pRt->m_nFlags |= FRT_CAMERA_REFLECTED_WATERPLANE;
|
|
}
|
|
else
|
|
if (eT == eT_PlaneReflected)
|
|
{
|
|
pRt->m_nFlags |= FRT_CAMERA_REFLECTED_PLANE;
|
|
}
|
|
else
|
|
if (eT == eT_Current)
|
|
{
|
|
pRt->m_nFlags |= FRT_CAMERA_CURRENT;
|
|
}
|
|
else
|
|
{
|
|
CRY_ASSERT(0);
|
|
Warning("Unknown RenderCamera type '%s'", Parser.GetString(eT));
|
|
}
|
|
}
|
|
break;
|
|
|
|
case eT_GenerateMips:
|
|
pRt->m_nFlags |= FRT_GENERATE_MIPS;
|
|
break;
|
|
|
|
case eT_RenderType:
|
|
{
|
|
eT = Parser.GetToken(Parser.m_Data);
|
|
if (eT == eT_CurObject)
|
|
{
|
|
pRt->m_nFlags |= FRT_RENDTYPE_CUROBJECT;
|
|
}
|
|
else
|
|
if (eT == eT_CurScene)
|
|
{
|
|
pRt->m_nFlags |= FRT_RENDTYPE_CURSCENE;
|
|
}
|
|
else
|
|
if (eT == eT_RecursiveScene)
|
|
{
|
|
pRt->m_nFlags |= FRT_RENDTYPE_RECURSIVECURSCENE;
|
|
}
|
|
else
|
|
if (eT == eT_CopyScene)
|
|
{
|
|
pRt->m_nFlags |= FRT_RENDTYPE_COPYSCENE;
|
|
}
|
|
else
|
|
{
|
|
CRY_ASSERT(0);
|
|
Warning("Unknown RenderType type '%s'", Parser.GetString(eT));
|
|
}
|
|
}
|
|
break;
|
|
|
|
case eT_RenderFilter:
|
|
{
|
|
eT = Parser.GetToken(Parser.m_Data);
|
|
if (eT == eT_Refractive)
|
|
{
|
|
pRt->m_nFilterFlags |= FRF_REFRACTIVE;
|
|
}
|
|
else
|
|
if (eT == eT_Heat)
|
|
{
|
|
pRt->m_nFilterFlags |= FRF_HEAT;
|
|
}
|
|
else
|
|
{
|
|
CRY_ASSERT(0);
|
|
Warning("Unknown RenderFilter type '%s'", Parser.GetString(eT));
|
|
}
|
|
}
|
|
break;
|
|
|
|
case eT_RenderDepthStencilTarget:
|
|
{
|
|
eT = Parser.GetToken(Parser.m_Data);
|
|
if (eT == eT_DepthBuffer || eT == eT_DepthBufferTemp)
|
|
{
|
|
pRt->m_bTempDepth = true;
|
|
}
|
|
else
|
|
if (eT == eT_DepthBufferOrig)
|
|
{
|
|
pRt->m_bTempDepth = false;
|
|
}
|
|
else
|
|
{
|
|
CRY_ASSERT(0);
|
|
Warning("Unknown RenderDepthStencilTarget type '%s'", Parser.GetString(eT));
|
|
}
|
|
}
|
|
break;
|
|
|
|
case eT_RenderTarget_IDPool:
|
|
pRt->m_nIDInPool = Parser.GetInt(Parser.GetToken(Parser.m_Data));
|
|
CRY_ASSERT(pRt->m_nIDInPool >= 0 && pRt->m_nIDInPool < 64);
|
|
break;
|
|
|
|
case eT_RenderTarget_Width:
|
|
{
|
|
eT = Parser.GetToken(Parser.m_Data);
|
|
if (eT == eT_$ScreenSize)
|
|
{
|
|
pRt->m_nWidth = -1;
|
|
}
|
|
else
|
|
{
|
|
pRt->m_nWidth = Parser.GetInt(eT);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case eT_RenderTarget_Height:
|
|
{
|
|
eT = Parser.GetToken(Parser.m_Data);
|
|
if (eT == eT_$ScreenSize)
|
|
{
|
|
pRt->m_nHeight = -1;
|
|
}
|
|
else
|
|
{
|
|
pRt->m_nHeight = Parser.GetInt(eT);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case eT_RenderTarget_UpdateType:
|
|
{
|
|
eT = Parser.GetToken(Parser.m_Data);
|
|
if (eT == eT_WaterReflect)
|
|
{
|
|
pRt->m_eUpdateType = eRTUpdate_WaterReflect;
|
|
}
|
|
else
|
|
if (eT == eT_Allways)
|
|
{
|
|
pRt->m_eUpdateType = eRTUpdate_Always;
|
|
}
|
|
else
|
|
{
|
|
CRY_ASSERT(0);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case eT_ClearSetColor:
|
|
{
|
|
eT = Parser.GetToken(Parser.m_Data);
|
|
if (eT == eT_FogColor)
|
|
{
|
|
pRt->m_nFlags |= FRT_CLEAR_FOGCOLOR;
|
|
}
|
|
else
|
|
{
|
|
string sStr = Parser.GetString(Parser.m_Data);
|
|
shGetColor(sStr.c_str(), pRt->m_ClearColor);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case eT_ClearSetDepth:
|
|
pRt->m_fClearDepth = Parser.GetFloat(Parser.m_Data);
|
|
break;
|
|
|
|
case eT_ClearTarget:
|
|
{
|
|
eT = Parser.GetToken(Parser.m_Data);
|
|
if (eT == eT_Color)
|
|
{
|
|
pRt->m_nFlags |= FRT_CLEAR_COLOR;
|
|
}
|
|
else
|
|
if (eT == eT_Depth)
|
|
{
|
|
pRt->m_nFlags |= FRT_CLEAR_DEPTH;
|
|
}
|
|
else
|
|
{
|
|
CRY_ASSERT(0);
|
|
Warning("Unknown ClearTarget type '%s'", Parser.GetString(eT));
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
CRY_ASSERT(0);
|
|
}
|
|
}
|
|
if (pRt->m_eOrder == eRO_PreProcess)
|
|
{
|
|
Parser.m_pCurShader->m_Flags |= EF_PRECACHESHADER;
|
|
}
|
|
pSampler->m_pTarget = pRt;
|
|
pSampler->PostLoad();
|
|
|
|
Parser.EndFrame(OldFrame);
|
|
|
|
return bRes;
|
|
}
|
|
|
|
bool CShaderManBin::ParseBinFX_Sampler_Annotations(CParserBin& Parser, SParserFrame& Annotations, STexSamplerFX* pSampler)
|
|
{
|
|
bool bRes = true;
|
|
|
|
SParserFrame OldFrame = Parser.BeginFrame(Annotations);
|
|
|
|
FX_BEGIN_TOKENS
|
|
FX_TOKEN(string)
|
|
FX_END_TOKENS
|
|
|
|
int nIndex = 0;
|
|
|
|
while (Parser.ParseObject(sCommands, nIndex))
|
|
{
|
|
EToken eT = Parser.GetToken();
|
|
SCodeFragment Fr;
|
|
switch (eT)
|
|
{
|
|
case eT_string:
|
|
{
|
|
eT = Parser.GetToken(Parser.m_Name);
|
|
CRY_ASSERT(eT == eT_Script);
|
|
bRes &= ParseBinFX_Sampler_Annotations_Script(Parser, Parser.m_Data, pSampler);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
CRY_ASSERT(0);
|
|
}
|
|
}
|
|
|
|
Parser.EndFrame(OldFrame);
|
|
|
|
return bRes;
|
|
}
|
|
|
|
bool CShaderManBin::ParseBinFX_Sampler(CParserBin& Parser, SParserFrame& Frame, uint32 dwName, SParserFrame Annotations, EToken samplerType)
|
|
{
|
|
bool bRes = true;
|
|
|
|
SParserFrame OldFrame = Parser.BeginFrame(Frame);
|
|
|
|
FX_BEGIN_TOKENS
|
|
FX_TOKEN(string)
|
|
FX_TOKEN(Texture)
|
|
FX_TOKEN(MinFilter)
|
|
FX_TOKEN(MagFilter)
|
|
FX_TOKEN(MipFilter)
|
|
FX_TOKEN(AddressU)
|
|
FX_TOKEN(AddressV)
|
|
FX_TOKEN(AddressW)
|
|
FX_TOKEN(BorderColor)
|
|
FX_TOKEN(AnisotropyLevel)
|
|
FX_TOKEN(sRGBLookup)
|
|
FX_TOKEN(Global)
|
|
FX_END_TOKENS
|
|
|
|
STexSamplerFX samp;
|
|
STexState ST;
|
|
DWORD dwBorderColor = 0;
|
|
uint32 nFilter = 0;
|
|
uint32 nFiltMin = 0;
|
|
uint32 nFiltMip = 0;
|
|
uint32 nFiltMag = 0;
|
|
uint32 nAddressU = 0;
|
|
uint32 nAddressV = 0;
|
|
uint32 nAddressW = 0;
|
|
uint32 nAnisotropyLevel = 0;
|
|
|
|
int nIndex = -1;
|
|
|
|
while (Parser.ParseObject(sCommands, nIndex))
|
|
{
|
|
EToken eT = Parser.GetToken();
|
|
switch (eT)
|
|
{
|
|
case eT_string:
|
|
{
|
|
eT = Parser.GetToken(Parser.m_Name);
|
|
|
|
SParserFrame stringData = Parser.m_Data;
|
|
|
|
// string could have ""s still, if so trim them off.
|
|
if (Parser.GetToken(stringData) == eT_quote)
|
|
{
|
|
stringData.m_nFirstToken++;
|
|
stringData.m_nLastToken--;
|
|
}
|
|
|
|
#if SHADER_REFLECT_TEXTURE_SLOTS
|
|
if (eT == eT_UIName)
|
|
{
|
|
samp.m_szUIName = Parser.GetString(stringData);
|
|
}
|
|
else if (eT == eT_UIDescription)
|
|
{
|
|
samp.m_szUIDescription = Parser.GetString(stringData);
|
|
}
|
|
#endif
|
|
}
|
|
break;
|
|
|
|
case eT_Texture:
|
|
samp.m_szTexture = Parser.GetString(Parser.m_Data);
|
|
break;
|
|
|
|
case eT_BorderColor:
|
|
{
|
|
string Str = Parser.GetString(Parser.m_Data);
|
|
ColorF colBorder = Col_Black;
|
|
shGetColor(Str.c_str(), colBorder);
|
|
dwBorderColor = colBorder.pack_argb8888();
|
|
ST.m_bActive = true;
|
|
}
|
|
break;
|
|
|
|
case eT_sRGBLookup:
|
|
ST.m_bSRGBLookup = Parser.GetBool(Parser.m_Data);
|
|
break;
|
|
|
|
case eT_Global:
|
|
break;
|
|
|
|
case eT_AnisotropyLevel:
|
|
nAnisotropyLevel = Parser.GetToken(Parser.m_Data);
|
|
break;
|
|
|
|
case eT_Filter:
|
|
nFilter = Parser.GetToken(Parser.m_Data);
|
|
ST.m_bActive = true;
|
|
break;
|
|
case eT_MinFilter:
|
|
nFiltMin = Parser.GetToken(Parser.m_Data);
|
|
ST.m_bActive = true;
|
|
break;
|
|
case eT_MagFilter:
|
|
nFiltMag = Parser.GetToken(Parser.m_Data);
|
|
ST.m_bActive = true;
|
|
break;
|
|
case eT_MipFilter:
|
|
nFiltMip = Parser.GetToken(Parser.m_Data);
|
|
ST.m_bActive = true;
|
|
break;
|
|
case eT_AddressU:
|
|
nAddressU = sGetTAddress(Parser.GetToken(Parser.m_Data));
|
|
ST.m_bActive = true;
|
|
break;
|
|
case eT_AddressV:
|
|
nAddressV = sGetTAddress(Parser.GetToken(Parser.m_Data));
|
|
ST.m_bActive = true;
|
|
break;
|
|
case eT_AddressW:
|
|
nAddressW = sGetTAddress(Parser.GetToken(Parser.m_Data));
|
|
ST.m_bActive = true;
|
|
break;
|
|
|
|
default:
|
|
CRY_ASSERT(0);
|
|
}
|
|
}
|
|
|
|
samp.m_szName = Parser.GetString(dwName);
|
|
if (nFilter > 0)
|
|
{
|
|
switch (nFilter)
|
|
{
|
|
case eT_MIN_MAG_MIP_POINT:
|
|
ST.SetFilterMode(FILTER_POINT);
|
|
break;
|
|
case eT_MIN_MAG_MIP_LINEAR:
|
|
ST.SetFilterMode(FILTER_TRILINEAR);
|
|
break;
|
|
case eT_MIN_MAG_LINEAR_MIP_POINT:
|
|
ST.SetFilterMode(FILTER_BILINEAR);
|
|
break;
|
|
case eT_COMPARISON_MIN_MAG_LINEAR_MIP_POINT:
|
|
ST.SetFilterMode(FILTER_BILINEAR);
|
|
ST.SetComparisonFilter(true);
|
|
break;
|
|
default:
|
|
{
|
|
const char* szFilter = Parser.GetString(nFilter);
|
|
assert(0);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (nFiltMag > 0 && nFiltMin > 0 && nFiltMip > 0)
|
|
{
|
|
if (nFiltMag == eT_LINEAR && nFiltMin == eT_LINEAR && nFiltMip == eT_LINEAR)
|
|
{
|
|
ST.SetFilterMode(FILTER_TRILINEAR);
|
|
}
|
|
else
|
|
if (nFiltMag == eT_LINEAR && nFiltMin == eT_LINEAR && nFiltMip == eT_POINT)
|
|
{
|
|
ST.SetFilterMode(FILTER_BILINEAR);
|
|
}
|
|
else
|
|
if (nFiltMag == eT_LINEAR && nFiltMin == eT_LINEAR && nFiltMip == eT_NONE)
|
|
{
|
|
ST.SetFilterMode(FILTER_LINEAR);
|
|
}
|
|
else
|
|
if (nFiltMag == eT_POINT && nFiltMin == eT_POINT && nFiltMip == eT_POINT)
|
|
{
|
|
ST.SetFilterMode(FILTER_POINT);
|
|
}
|
|
else
|
|
if (nFiltMag == eT_POINT && nFiltMin == eT_POINT && nFiltMip == eT_NONE)
|
|
{
|
|
ST.SetFilterMode(FILTER_NONE);
|
|
}
|
|
else
|
|
if (nFiltMag == eT_ANISOTROPIC || nFiltMin == eT_ANISOTROPIC)
|
|
{
|
|
if (nAnisotropyLevel == eT_0 + 4)
|
|
{
|
|
ST.SetFilterMode(FILTER_ANISO4X);
|
|
}
|
|
else
|
|
if (nAnisotropyLevel == eT_0 + 8)
|
|
{
|
|
ST.SetFilterMode(FILTER_ANISO8X);
|
|
}
|
|
else
|
|
if (nAnisotropyLevel == eT_0 + 16)
|
|
{
|
|
ST.SetFilterMode(FILTER_ANISO16X);
|
|
}
|
|
else
|
|
{
|
|
ST.SetFilterMode(FILTER_ANISO2X);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Warning("!Unknown sampler filter mode (Min=%s, Mag=%s, Mip=%s) for sampler '%s'", Parser.GetString(nFiltMin), Parser.GetString(nFiltMag), Parser.GetString(nFiltMip), samp.m_szName.c_str());
|
|
CRY_ASSERT(0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ST.SetFilterMode(-1);
|
|
}
|
|
|
|
ST.SetClampMode(nAddressU, nAddressV, nAddressW);
|
|
ST.SetBorderColor(dwBorderColor);
|
|
|
|
samp.m_nTexState = CTexture::GetTexState(ST);
|
|
samp.m_nSlotId = m_pCEF->mfCheckTextureSlotName(samp.m_szTexture);
|
|
|
|
if (!Annotations.IsEmpty())
|
|
{
|
|
bRes &= ParseBinFX_Sampler_Annotations(Parser, Annotations, &samp);
|
|
}
|
|
|
|
switch (samplerType)
|
|
{
|
|
case eT_sampler1D:
|
|
samp.m_eTexType = eTT_1D;
|
|
break;
|
|
case eT_sampler2D:
|
|
case eT_Texture2D:
|
|
samp.m_eTexType = eTT_2D;
|
|
break;
|
|
case eT_Texture2DArray:
|
|
samp.m_eTexType = eTT_2DArray;
|
|
break;
|
|
case eT_Texture2DMS:
|
|
samp.m_eTexType = eTT_2DMS;
|
|
break;
|
|
case eT_sampler3D:
|
|
case eT_Texture3D:
|
|
samp.m_eTexType = eTT_3D;
|
|
break;
|
|
case eT_samplerCUBE:
|
|
case eT_TextureCube:
|
|
samp.m_eTexType = eTT_Cube;
|
|
break;
|
|
case eT_TextureCubeArray:
|
|
samp.m_eTexType = eTT_CubeArray;
|
|
break;
|
|
default:
|
|
#if !defined(_RELEASE)
|
|
__debugbreak();
|
|
#endif
|
|
samp.m_eTexType = eTT_2D;
|
|
break;
|
|
}
|
|
|
|
mfAddFXSampler(Parser.m_pCurShader, &samp);
|
|
|
|
Parser.EndFrame(OldFrame);
|
|
|
|
return bRes;
|
|
}
|
|
|
|
bool CShaderManBin::ParseBinFX_Sampler(CParserBin& Parser, SParserFrame& Frame, SFXSampler& Sampl)
|
|
{
|
|
bool bRes = true;
|
|
|
|
SParserFrame OldFrame = Parser.BeginFrame(Frame);
|
|
|
|
FX_BEGIN_TOKENS
|
|
FX_TOKEN(string)
|
|
FX_TOKEN(Filter)
|
|
FX_TOKEN(MinFilter)
|
|
FX_TOKEN(MagFilter)
|
|
FX_TOKEN(MipFilter)
|
|
FX_TOKEN(AddressU)
|
|
FX_TOKEN(AddressV)
|
|
FX_TOKEN(AddressW)
|
|
FX_TOKEN(BorderColor)
|
|
FX_TOKEN(AnisotropyLevel)
|
|
FX_TOKEN(sRGBLookup)
|
|
FX_TOKEN(Global)
|
|
FX_END_TOKENS
|
|
|
|
STexState ST;
|
|
DWORD dwBorderColor = 0;
|
|
uint32 nFilter = 0;
|
|
uint32 nFiltMin = 0;
|
|
uint32 nFiltMip = 0;
|
|
uint32 nFiltMag = 0;
|
|
uint32 nAddressU = 0;
|
|
uint32 nAddressV = 0;
|
|
uint32 nAddressW = 0;
|
|
uint32 nAnisotropyLevel = 0;
|
|
|
|
int nIndex = -1;
|
|
|
|
while (Parser.ParseObject(sCommands, nIndex))
|
|
{
|
|
EToken eT = Parser.GetToken();
|
|
switch (eT)
|
|
{
|
|
case eT_BorderColor:
|
|
{
|
|
string Str = Parser.GetString(Parser.m_Data);
|
|
ColorF colBorder = Col_Black;
|
|
shGetColor(Str.c_str(), colBorder);
|
|
dwBorderColor = colBorder.pack_argb8888();
|
|
ST.m_bActive = true;
|
|
}
|
|
break;
|
|
|
|
case eT_sRGBLookup:
|
|
ST.m_bSRGBLookup = Parser.GetBool(Parser.m_Data);
|
|
break;
|
|
|
|
case eT_AnisotropyLevel:
|
|
nAnisotropyLevel = Parser.GetToken(Parser.m_Data);
|
|
break;
|
|
|
|
case eT_Filter:
|
|
nFilter = Parser.GetToken(Parser.m_Data);
|
|
ST.m_bActive = true;
|
|
break;
|
|
|
|
case eT_MinFilter:
|
|
nFiltMin = Parser.GetToken(Parser.m_Data);
|
|
ST.m_bActive = true;
|
|
break;
|
|
case eT_MagFilter:
|
|
nFiltMag = Parser.GetToken(Parser.m_Data);
|
|
ST.m_bActive = true;
|
|
break;
|
|
case eT_MipFilter:
|
|
nFiltMip = Parser.GetToken(Parser.m_Data);
|
|
ST.m_bActive = true;
|
|
break;
|
|
case eT_AddressU:
|
|
nAddressU = sGetTAddress(Parser.GetToken(Parser.m_Data));
|
|
ST.m_bActive = true;
|
|
break;
|
|
case eT_AddressV:
|
|
nAddressV = sGetTAddress(Parser.GetToken(Parser.m_Data));
|
|
ST.m_bActive = true;
|
|
break;
|
|
case eT_AddressW:
|
|
nAddressW = sGetTAddress(Parser.GetToken(Parser.m_Data));
|
|
ST.m_bActive = true;
|
|
break;
|
|
|
|
default:
|
|
CRY_ASSERT(0);
|
|
}
|
|
}
|
|
|
|
if (nFilter > 0)
|
|
{
|
|
switch (nFilter)
|
|
{
|
|
case eT_MIN_MAG_MIP_POINT:
|
|
ST.SetFilterMode(FILTER_POINT);
|
|
break;
|
|
case eT_MIN_MAG_LINEAR_MIP_POINT:
|
|
ST.SetFilterMode(FILTER_BILINEAR);
|
|
break;
|
|
case eT_MIN_MAG_MIP_LINEAR:
|
|
ST.SetFilterMode(FILTER_TRILINEAR);
|
|
break;
|
|
case eT_COMPARISON_MIN_MAG_LINEAR_MIP_POINT:
|
|
ST.SetFilterMode(FILTER_BILINEAR);
|
|
ST.SetComparisonFilter(true);
|
|
break;
|
|
default:
|
|
{
|
|
const char* szFilter = Parser.GetString(nFilter);
|
|
CRY_ASSERT(0);
|
|
int nnn = 0;
|
|
}
|
|
break;
|
|
}
|
|
int nnn = 0;
|
|
}
|
|
if (nFiltMag > 0 && nFiltMin > 0 && nFiltMip > 0)
|
|
{
|
|
if (nFiltMag == eT_LINEAR && nFiltMin == eT_LINEAR && nFiltMip == eT_LINEAR)
|
|
{
|
|
ST.SetFilterMode(FILTER_TRILINEAR);
|
|
}
|
|
else
|
|
if (nFiltMag == eT_LINEAR && nFiltMin == eT_LINEAR && nFiltMip == eT_POINT)
|
|
{
|
|
ST.SetFilterMode(FILTER_BILINEAR);
|
|
}
|
|
else
|
|
if (nFiltMag == eT_LINEAR && nFiltMin == eT_LINEAR && nFiltMip == eT_NONE)
|
|
{
|
|
ST.SetFilterMode(FILTER_LINEAR);
|
|
}
|
|
else
|
|
if (nFiltMag == eT_POINT && nFiltMin == eT_POINT && nFiltMip == eT_POINT)
|
|
{
|
|
ST.SetFilterMode(FILTER_POINT);
|
|
}
|
|
else
|
|
if (nFiltMag == eT_POINT && nFiltMin == eT_POINT && nFiltMip == eT_NONE)
|
|
{
|
|
ST.SetFilterMode(FILTER_NONE);
|
|
}
|
|
else
|
|
if (nFiltMag == eT_ANISOTROPIC || nFiltMin == eT_ANISOTROPIC)
|
|
{
|
|
if (nAnisotropyLevel == eT_0 + 4)
|
|
{
|
|
ST.SetFilterMode(FILTER_ANISO4X);
|
|
}
|
|
else
|
|
if (nAnisotropyLevel == eT_0 + 8)
|
|
{
|
|
ST.SetFilterMode(FILTER_ANISO8X);
|
|
}
|
|
else
|
|
if (nAnisotropyLevel == eT_0 + 16)
|
|
{
|
|
ST.SetFilterMode(FILTER_ANISO16X);
|
|
}
|
|
else
|
|
{
|
|
ST.SetFilterMode(FILTER_ANISO2X);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Warning("!Unknown sampler filter mode (Min=%s, Mag=%s, Mip=%s) for sampler '%s'", Parser.GetString(nFiltMin), Parser.GetString(nFiltMag), Parser.GetString(nFiltMip), Sampl.m_Name.c_str());
|
|
CRY_ASSERT(0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ST.SetFilterMode(-1);
|
|
}
|
|
|
|
if (ST.m_bActive)
|
|
{
|
|
ST.SetClampMode(nAddressU, nAddressV, nAddressW);
|
|
ST.SetBorderColor(dwBorderColor);
|
|
|
|
Sampl.m_nTexState = CTexture::GetTexState(ST);
|
|
}
|
|
|
|
Parser.EndFrame(OldFrame);
|
|
|
|
return bRes;
|
|
}
|
|
|
|
bool CShaderManBin::ParseBinFX_Texture(CParserBin& Parser, SParserFrame& Frame, SFXTexture& Tex)
|
|
{
|
|
bool bRes = true;
|
|
|
|
SParserFrame OldFrame = Parser.BeginFrame(Frame);
|
|
|
|
FX_BEGIN_TOKENS
|
|
FX_TOKEN(Texture)
|
|
FX_TOKEN(UIName)
|
|
FX_TOKEN(UIDescription)
|
|
FX_TOKEN(sRGBLookup)
|
|
FX_TOKEN(Global)
|
|
FX_TOKEN(slot)
|
|
FX_TOKEN(vsslot)
|
|
FX_TOKEN(psslot)
|
|
FX_TOKEN(hsslot)
|
|
FX_TOKEN(dsslot)
|
|
FX_TOKEN(gsslot)
|
|
FX_TOKEN(csslot)
|
|
FX_END_TOKENS
|
|
|
|
int nIndex = -1;
|
|
|
|
while (Parser.ParseObject(sCommands, nIndex))
|
|
{
|
|
EToken eT = Parser.GetToken();
|
|
switch (eT)
|
|
{
|
|
case eT_Texture:
|
|
{
|
|
Tex.m_szTexture = Parser.GetString(Parser.m_Data);
|
|
}
|
|
break;
|
|
case eT_UIName:
|
|
{
|
|
if (Parser.GetToken(Parser.m_Data) == eT_quote)
|
|
{
|
|
Parser.m_Data.m_nFirstToken++;
|
|
Parser.m_Data.m_nLastToken--;
|
|
}
|
|
Tex.m_szUIName = Parser.GetString(Parser.m_Data);
|
|
}
|
|
break;
|
|
case eT_UIDescription:
|
|
{
|
|
if (Parser.GetToken(Parser.m_Data) == eT_quote)
|
|
{
|
|
Parser.m_Data.m_nFirstToken++;
|
|
Parser.m_Data.m_nLastToken--;
|
|
}
|
|
Tex.m_szUIDesc = Parser.GetString(Parser.m_Data);
|
|
}
|
|
break;
|
|
|
|
case eT_sRGBLookup:
|
|
Tex.m_bSRGBLookup = Parser.GetBool(Parser.m_Data);
|
|
break;
|
|
|
|
case eT_Global:
|
|
Tex.m_nFlags |= PF_GLOBAL;
|
|
break;
|
|
|
|
case eT_slot:
|
|
case eT_vsslot:
|
|
case eT_psslot:
|
|
case eT_hsslot:
|
|
case eT_dsslot:
|
|
case eT_gsslot:
|
|
case eT_csslot:
|
|
break;
|
|
|
|
default:
|
|
CRY_ASSERT(0);
|
|
}
|
|
}
|
|
|
|
|
|
Parser.EndFrame(OldFrame);
|
|
|
|
return bRes;
|
|
}
|
|
|
|
void CShaderManBin::AddAffectedParameter(CParserBin& Parser, std::vector<SFXParam>& AffectedParams, TArray<int>& AffectedFunc, SFXParam* pParam, EHWShaderClass eSHClass, [[maybe_unused]] uint32 dwType, SShaderTechnique* pShTech)
|
|
{
|
|
static uint32 eT_ShadowGen[] = {CParserBin::GetCRC32("ShadowGenVS"), CParserBin::GetCRC32("ShadowGenPS"), CParserBin::GetCRC32("ShadowGenGS")};
|
|
if (!CParserBin::PlatformSupportsConstantBuffers())
|
|
{
|
|
//if (pParam->m_Name.c_str()[0] != '_')
|
|
{
|
|
if (!(Parser.m_pCurShader->m_Flags & EF_LOCALCONSTANTS))
|
|
{
|
|
if (pParam->m_Register[eSHClass] >= 0 && pParam->m_Register[eSHClass] < 10000)
|
|
{
|
|
if ((pShTech->m_Flags & FHF_NOLIGHTS) && pParam->m_BindingSlot == eConstantBufferShaderSlot_PerMaterial && !(pParam->m_nFlags & PF_TWEAKABLE_MASK))
|
|
{
|
|
return;
|
|
}
|
|
if (pParam->m_Semantic.empty() && pParam->m_Values.c_str()[0] == '(')
|
|
{
|
|
pParam->m_BindingSlot = eConstantBufferShaderSlot_PerMaterial;
|
|
}
|
|
AffectedParams.push_back(*pParam);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
if (pParam->m_BindingSlot == eConstantBufferShaderSlot_PerMaterial)
|
|
{
|
|
if (pParam->m_Register[eSHClass] < 0 || pParam->m_Register[eSHClass] >= 1000)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
int nFlags = pParam->GetFlags();
|
|
bool bCheckAffect = CParserBin::m_bParseFX ? true : false;
|
|
|
|
if (CParserBin::m_nPlatform == SF_D3D11 || CParserBin::m_nPlatform == SF_JASPER || CParserBin::m_nPlatform == SF_ORBIS || CParserBin::m_nPlatform == SF_GL4 || CParserBin::m_nPlatform == SF_GLES3 || CParserBin::m_nPlatform == SF_METAL)
|
|
{
|
|
CRY_ASSERT(eSHClass < eHWSC_Num);
|
|
if (((nFlags & PF_TWEAKABLE_MASK) || pParam->m_Values.c_str()[0] == '(') && pParam->m_Register[eSHClass] >= 0 && pParam->m_Register[eSHClass] < 1000)
|
|
{
|
|
bCheckAffect = false;
|
|
}
|
|
}
|
|
for (uint32 j = 0; j < AffectedFunc.size(); j++)
|
|
{
|
|
SCodeFragment* pCF = &Parser.m_CodeFragments[AffectedFunc[j]];
|
|
if (!bCheckAffect || Parser.FindToken(pCF->m_nFirstToken, pCF->m_nLastToken, pParam->m_dwName[0]) >= 0)
|
|
{
|
|
AffectedParams.push_back(*pParam);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CShaderManBin::InitShaderDependenciesList(CParserBin& Parser, SCodeFragment* pFunc, TArray<byte>& bChecked, TArray<int>& AffectedFunc)
|
|
{
|
|
uint32 i;
|
|
const uint32 numFrags = Parser.m_CodeFragments.size();
|
|
|
|
for (i = 0; i < numFrags; ++i)
|
|
{
|
|
if (bChecked[i])
|
|
{
|
|
continue;
|
|
}
|
|
SCodeFragment* s = &Parser.m_CodeFragments[i];
|
|
if (!s->m_dwName)
|
|
{
|
|
bChecked[i] = 1;
|
|
continue;
|
|
}
|
|
if (s->m_eType == eFT_Function || s->m_eType == eFT_StorageClass)
|
|
{
|
|
if (Parser.FindToken(pFunc->m_nFirstToken, pFunc->m_nLastToken, s->m_dwName) >= 0)
|
|
{
|
|
bChecked[i] = 1;
|
|
AffectedFunc.push_back(i);
|
|
InitShaderDependenciesList(Parser, s, bChecked, AffectedFunc);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CShaderManBin::AddAffectedSampler(CParserBin& Parser, std::vector<SFXSampler>& AffectedSamplers, TArray<int>& AffectedFunc, SFXSampler* pSampler, [[maybe_unused]] EHWShaderClass eSHClass, [[maybe_unused]] uint32 dwType, [[maybe_unused]] SShaderTechnique* pShTech)
|
|
{
|
|
for (uint32 j = 0; j < AffectedFunc.size(); j++)
|
|
{
|
|
SCodeFragment* pCF = &Parser.m_CodeFragments[AffectedFunc[j]];
|
|
if (Parser.FindToken(pCF->m_nFirstToken, pCF->m_nLastToken, pSampler->m_dwName[0]) >= 0)
|
|
{
|
|
AffectedSamplers.push_back(*pSampler);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
void CShaderManBin::AddAffectedTexture(CParserBin& Parser, std::vector<SFXTexture>& AffectedTextures, TArray<int>& AffectedFunc, SFXTexture* pTexture, [[maybe_unused]] EHWShaderClass eSHClass, [[maybe_unused]] uint32 dwType, [[maybe_unused]] SShaderTechnique* pShTech)
|
|
{
|
|
for (uint32 j = 0; j < AffectedFunc.size(); j++)
|
|
{
|
|
SCodeFragment* pCF = &Parser.m_CodeFragments[AffectedFunc[j]];
|
|
if (Parser.FindToken(pCF->m_nFirstToken, pCF->m_nLastToken, pTexture->m_dwName[0]) >= 0)
|
|
{
|
|
AffectedTextures.push_back(*pTexture);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CShaderManBin::CheckStructuresDependencies(CParserBin& Parser, SCodeFragment* pFrag, TArray<byte>& bChecked, TArray<int>& AffectedFunc)
|
|
{
|
|
uint32 i;
|
|
const uint32 numFrags = Parser.m_CodeFragments.size();
|
|
|
|
for (i = 0; i < numFrags; ++i)
|
|
{
|
|
if (bChecked[i])
|
|
{
|
|
continue;
|
|
}
|
|
SCodeFragment* s = &Parser.m_CodeFragments[i];
|
|
if (s->m_eType == eFT_Structure)
|
|
{
|
|
if (Parser.FindToken(pFrag->m_nFirstToken, pFrag->m_nLastToken, s->m_dwName) >= 0)
|
|
{
|
|
bChecked[i] = 1;
|
|
AffectedFunc.push_back(i);
|
|
CheckStructuresDependencies(Parser, s, bChecked, AffectedFunc);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CShaderManBin::CheckFragmentsDependencies(CParserBin& Parser, TArray<byte>& bChecked, TArray<int>& AffectedFrags)
|
|
{
|
|
uint32 i, j;
|
|
const uint32 numFuncs = AffectedFrags.size();
|
|
const uint32 numFrags = Parser.m_CodeFragments.size();
|
|
|
|
for (i = 0; i < numFuncs; ++i)
|
|
{
|
|
int nFunc = AffectedFrags[i];
|
|
SCodeFragment* pFunc = &Parser.m_CodeFragments[nFunc];
|
|
for (j = 0; j < numFrags; j++)
|
|
{
|
|
SCodeFragment* s = &Parser.m_CodeFragments[j];
|
|
if (bChecked[j])
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (s->m_eType == eFT_Sampler || s->m_eType == eFT_Structure)
|
|
{
|
|
if (Parser.FindToken(pFunc->m_nFirstToken, pFunc->m_nLastToken, s->m_dwName) >= 0)
|
|
{
|
|
bChecked[j] = 1;
|
|
AffectedFrags.push_back(j);
|
|
if (s->m_eType == eFT_Structure)
|
|
{
|
|
CheckStructuresDependencies(Parser, s, bChecked, AffectedFrags);
|
|
}
|
|
}
|
|
}
|
|
else if (s->m_eType == eFT_ConstBuffer)
|
|
{
|
|
// Make sure cbuffer declaration does not get stripped
|
|
bChecked[j] = 1;
|
|
AffectedFrags.push_back(j);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
struct SFXRegisterBin
|
|
{
|
|
int nReg;
|
|
int nComp;
|
|
int m_nCB;
|
|
uint32 m_nFlags;
|
|
EParamType eType;
|
|
uint32 dwName;
|
|
CCryNameR m_Value;
|
|
SFXRegisterBin()
|
|
{
|
|
eType = eType_UNKNOWN;
|
|
m_nCB = -1;
|
|
}
|
|
};
|
|
|
|
struct SFXPackedName
|
|
{
|
|
uint32 dwName[4];
|
|
|
|
SFXPackedName()
|
|
{
|
|
dwName[0] = dwName[1] = dwName[2] = dwName[3] = 0;
|
|
}
|
|
};
|
|
|
|
inline bool Compar(const SFXRegisterBin& a, const SFXRegisterBin& b)
|
|
{
|
|
if (CParserBin::PlatformSupportsConstantBuffers())
|
|
{
|
|
if (a.m_nCB != b.m_nCB)
|
|
{
|
|
return a.m_nCB < b.m_nCB;
|
|
}
|
|
}
|
|
if (a.nReg != b.nReg)
|
|
{
|
|
return a.nReg < b.nReg;
|
|
}
|
|
if (a.nComp != b.nComp)
|
|
{
|
|
return a.nComp < b.nComp;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static void sFlushRegs(CParserBin& Parser, int nReg, SFXRegisterBin* MergedRegs[4], std::vector<SFXParam>& NewParams, EHWShaderClass eSHClass, std::vector<SFXPackedName>& PackedNames)
|
|
{
|
|
NewParams.resize(NewParams.size() + 1);
|
|
PackedNames.resize(PackedNames.size() + 1);
|
|
SFXParam& p = NewParams[NewParams.size() - 1];
|
|
SFXPackedName& pN = PackedNames[PackedNames.size() - 1];
|
|
int nMaxComp = -1;
|
|
int j;
|
|
|
|
int nCompMerged = 0;
|
|
EParamType eType = eType_UNKNOWN;
|
|
int nCB = -1;
|
|
for (j = 0; j < 4; j++)
|
|
{
|
|
if (MergedRegs[j] && MergedRegs[j]->eType != eType_UNKNOWN)
|
|
{
|
|
if (nCB == -1)
|
|
{
|
|
nCB = MergedRegs[j]->m_nCB;
|
|
}
|
|
else
|
|
if (nCB != MergedRegs[j]->m_nCB)
|
|
{
|
|
CRY_ASSERT(0);
|
|
}
|
|
if (eType == eType_UNKNOWN)
|
|
{
|
|
eType = MergedRegs[j]->eType;
|
|
}
|
|
else
|
|
if (eType != MergedRegs[j]->eType)
|
|
{
|
|
//CRY_ASSERT(0);
|
|
}
|
|
}
|
|
}
|
|
for (j = 0; j < 4; j++)
|
|
{
|
|
char s[16];
|
|
sprintf_s(s, "__%d", j);
|
|
p.m_Name = stack_string(p.m_Name.c_str()) + s;
|
|
if (MergedRegs[j])
|
|
{
|
|
if (MergedRegs[j]->m_nFlags & PF_TWEAKABLE_MASK)
|
|
{
|
|
p.m_nFlags |= (PF_TWEAKABLE_0 << j);
|
|
}
|
|
p.m_nFlags |= MergedRegs[j]->m_nFlags & ~(PF_TWEAKABLE_MASK | PF_SCALAR | PF_SINGLE_COMP | PF_MERGE_MASK);
|
|
nMaxComp = max(nMaxComp, j);
|
|
pN.dwName[j] = MergedRegs[j]->dwName;
|
|
if (nCompMerged)
|
|
{
|
|
p.m_Values = stack_string(p.m_Values.c_str()) += ", ";
|
|
}
|
|
p.m_Name = stack_string(p.m_Name.c_str()) + Parser.GetString(pN.dwName[j]);
|
|
p.m_Values = stack_string(p.m_Values.c_str()) + MergedRegs[j]->m_Value.c_str();
|
|
nCompMerged++;
|
|
}
|
|
else
|
|
{
|
|
if (nCompMerged)
|
|
{
|
|
p.m_Values = stack_string(p.m_Values.c_str()) + ", ";
|
|
}
|
|
p.m_Values = stack_string(p.m_Values.c_str()) + "NULL";
|
|
nCompMerged++;
|
|
}
|
|
}
|
|
p.m_ComponentCount = nMaxComp + 1;
|
|
if (eSHClass == eHWSC_Geometry && !CParserBin::PlatformSupportsGeometryShaders())
|
|
{
|
|
return;
|
|
}
|
|
if (eSHClass == eHWSC_Domain && !CParserBin::PlatformSupportsDomainShaders())
|
|
{
|
|
return;
|
|
}
|
|
if (eSHClass == eHWSC_Hull && !CParserBin::PlatformSupportsHullShaders())
|
|
{
|
|
return;
|
|
}
|
|
if (eSHClass == eHWSC_Compute && !CParserBin::PlatformSupportsComputeShaders())
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Get packed name token.
|
|
p.m_dwName.push_back(Parser.NewUserToken(eT_unknown, p.m_Name.c_str(), true)); //pass by crysting so that string references work.
|
|
CRY_ASSERT(eSHClass < eHWSC_Num);
|
|
p.m_Register[eSHClass] = nReg;
|
|
if (eSHClass == eHWSC_Domain || eSHClass == eHWSC_Hull || eSHClass == eHWSC_Compute)
|
|
{
|
|
p.m_Register[eHWSC_Vertex] = nReg;
|
|
}
|
|
p.m_RegisterCount = 1;
|
|
if (eType == eType_HALF)
|
|
{
|
|
eType = eType_FLOAT;
|
|
}
|
|
p.m_eType = eType;
|
|
CRY_ASSERT(eType != eType_UNKNOWN);
|
|
p.m_BindingSlot = nCB;
|
|
p.m_nFlags |= PF_AUTOMERGED;
|
|
}
|
|
|
|
static EToken sCompToken[4] = {eT_x, eT_y, eT_z, eT_w};
|
|
bool CShaderManBin::ParseBinFX_Technique_Pass_PackParameters (CParserBin& Parser, std::vector<SFXParam>& AffectedParams, TArray<int>& AffectedFunc, [[maybe_unused]] SCodeFragment* pFunc, EHWShaderClass eSHClass, uint32 dwSHName, std::vector<SFXParam>& PackedParams, TArray<SCodeFragment>& Replaces, TArray<uint32>& NewTokens, TArray<byte>& bMerged)
|
|
{
|
|
bool bRes = true;
|
|
|
|
uint32 i, j;
|
|
|
|
std::vector<SFXRegisterBin> Registers;
|
|
std::vector<SFXPackedName> PackedNames;
|
|
uint32 nMergeMask = (eSHClass == eHWSC_Pixel) ? 1 : 2;
|
|
for (i = 0; i < AffectedParams.size(); i++)
|
|
{
|
|
SFXParam* pr = &AffectedParams[i];
|
|
if (pr->m_Annotations.empty())
|
|
{
|
|
continue; // Parameter doesn't have custom register definition
|
|
}
|
|
const char* src = strstr(pr->m_Annotations.c_str(), "register");
|
|
if (src)
|
|
{
|
|
char* b = (char*)&src[8];
|
|
SkipCharacters (&b, kWhiteSpace);
|
|
CRY_ASSERT(b[0] == '=');
|
|
b++;
|
|
SkipCharacters (&b, kWhiteSpace);
|
|
CRY_ASSERT(b[0] == 'c');
|
|
if (b[0] == 'c')
|
|
{
|
|
int nReg = atoi(&b[1]);
|
|
b++;
|
|
while (*b != '.' && *b != ';')
|
|
{
|
|
if (*b == 0) // Vector without swizzling
|
|
{
|
|
break;
|
|
}
|
|
b++;
|
|
}
|
|
if (*b == '.')
|
|
{
|
|
bMerged[i] = 0xff;
|
|
b++;
|
|
int nComp = -1;
|
|
switch (b[0])
|
|
{
|
|
case 'x':
|
|
case 'r':
|
|
nComp = 0;
|
|
break;
|
|
case 'y':
|
|
case 'g':
|
|
nComp = 1;
|
|
break;
|
|
case 'z':
|
|
case 'b':
|
|
nComp = 2;
|
|
break;
|
|
case 'w':
|
|
case 'a':
|
|
nComp = 3;
|
|
break;
|
|
default:
|
|
CRY_ASSERT(0);
|
|
}
|
|
if (nComp >= 0)
|
|
{
|
|
pr->m_nFlags |= PF_MERGE;
|
|
SFXRegisterBin rg;
|
|
rg.nReg = nReg;
|
|
rg.nComp = nComp;
|
|
rg.dwName = pr->m_dwName[0];
|
|
rg.m_Value = pr->m_Values;
|
|
rg.m_nFlags = pr->m_nFlags;
|
|
rg.eType = (EParamType)pr->m_eType;
|
|
rg.m_nCB = pr->m_BindingSlot;
|
|
CRY_ASSERT(rg.m_Value.c_str()[0]);
|
|
Registers.push_back(rg);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (Registers.empty())
|
|
{
|
|
return false;
|
|
}
|
|
std::sort(Registers.begin(), Registers.end(), Compar);
|
|
int nReg = -1;
|
|
int nCB = -1;
|
|
SFXRegisterBin* MergedRegs[4];
|
|
MergedRegs[0] = MergedRegs[1] = MergedRegs[2] = MergedRegs[3] = NULL;
|
|
for (i = 0; i < Registers.size(); i++)
|
|
{
|
|
SFXRegisterBin* rg = &Registers[i];
|
|
if ((!CParserBin::PlatformSupportsConstantBuffers() && rg->nReg != nReg) || (CParserBin::PlatformSupportsConstantBuffers() && (rg->m_nCB != nCB || rg->nReg != nReg)))
|
|
{
|
|
if (nReg >= 0)
|
|
{
|
|
sFlushRegs(Parser, nReg, MergedRegs, PackedParams, eSHClass, PackedNames);
|
|
}
|
|
nReg = rg->nReg;
|
|
nCB = rg->m_nCB;
|
|
MergedRegs[0] = MergedRegs[1] = MergedRegs[2] = MergedRegs[3] = NULL;
|
|
}
|
|
CRY_ASSERT(!MergedRegs[rg->nComp]);
|
|
if (MergedRegs[rg->nComp])
|
|
{
|
|
Warning("register c%d (comp: %d) is used by the %s shader '%s' already", rg->nReg, rg->nComp, eSHClass == eHWSC_Pixel ? "pixel" : "vertex", Parser.GetString(dwSHName));
|
|
CRY_ASSERT(0);
|
|
}
|
|
MergedRegs[rg->nComp] = rg;
|
|
}
|
|
if (MergedRegs[0] || MergedRegs[1] || MergedRegs[2] || MergedRegs[3])
|
|
{
|
|
sFlushRegs(Parser, nReg, MergedRegs, PackedParams, eSHClass, PackedNames);
|
|
}
|
|
|
|
// Replace new parameters in shader tokens
|
|
for (uint32 n = 0; n < AffectedFunc.size(); n++)
|
|
{
|
|
SCodeFragment* st = &Parser.m_CodeFragments[AffectedFunc[n]];
|
|
//const char *szName = Parser.GetString(st->m_dwName);
|
|
|
|
for (i = 0; i < PackedParams.size(); i++)
|
|
{
|
|
SFXParam* pr = &PackedParams[i];
|
|
SFXPackedName* pn = &PackedNames[i];
|
|
for (j = 0; j < 4; j++)
|
|
{
|
|
uint32 nP = pn->dwName[j];
|
|
if (nP == 0)
|
|
{
|
|
continue;
|
|
}
|
|
int32 nPos = st->m_nFirstToken;
|
|
while (true)
|
|
{
|
|
nPos = Parser.FindToken(nPos, st->m_nLastToken, nP);
|
|
if (nPos < 0)
|
|
{
|
|
break;
|
|
}
|
|
SCodeFragment Fr;
|
|
Fr.m_nFirstToken = Fr.m_nLastToken = nPos;
|
|
Fr.m_dwName = n;
|
|
Replaces.push_back(Fr);
|
|
|
|
Fr.m_nFirstToken = NewTokens.size();
|
|
NewTokens.push_back(pr->m_dwName[0]);
|
|
NewTokens.push_back(eT_dot);
|
|
NewTokens.push_back(sCompToken[j]);
|
|
Fr.m_nLastToken = NewTokens.size() - 1;
|
|
Replaces.push_back(Fr);
|
|
nPos++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < Replaces.size(); i += 2)
|
|
{
|
|
SCodeFragment* pFR1 = &Replaces[i];
|
|
for (j = i + 2; j < Replaces.size(); j += 2)
|
|
{
|
|
SCodeFragment* pFR2 = &Replaces[j];
|
|
if (pFR1->m_dwName != pFR2->m_dwName)
|
|
{
|
|
continue;
|
|
}
|
|
if (pFR2->m_nFirstToken < pFR1->m_nFirstToken)
|
|
{
|
|
std::swap(Replaces[i], Replaces[j]);
|
|
std::swap(Replaces[i + 1], Replaces[j + 1]);
|
|
}
|
|
}
|
|
}
|
|
|
|
return bRes;
|
|
}
|
|
|
|
//===================================================================================================
|
|
|
|
void CShaderManBin::AddParameterToScript(CParserBin& Parser, SFXParam* pr, PodArray<uint32>& SHData, EHWShaderClass eSHClass, int nCB)
|
|
{
|
|
char str[256];
|
|
int nReg = pr->m_Register[eSHClass];
|
|
if (pr->m_eType == eType_BOOL)
|
|
{
|
|
SHData.push_back(eT_bool);
|
|
}
|
|
else
|
|
if (pr->m_eType == eType_INT)
|
|
{
|
|
SHData.push_back(eT_int);
|
|
}
|
|
else
|
|
{
|
|
int nVal = pr->m_RegisterCount * 4 + pr->m_ComponentCount;
|
|
EToken eT = eT_unknown;
|
|
switch (nVal)
|
|
{
|
|
case 4 + 1:
|
|
eT = (pr->m_eType == eType_FLOAT) ? eT_float : eT_half;
|
|
break;
|
|
case 4 + 2:
|
|
//eT = eT_float2;
|
|
eT = (pr->m_eType == eType_FLOAT) ? eT_float2 : eT_half2;
|
|
break;
|
|
case 4 + 3:
|
|
//eT = eT_float3;
|
|
eT = (pr->m_eType == eType_FLOAT) ? eT_float3 : eT_half3;
|
|
break;
|
|
case 4 + 4:
|
|
//eT = eT_float4;
|
|
eT = (pr->m_eType == eType_FLOAT) ? eT_float4 : eT_half4;
|
|
break;
|
|
case 2 * 4 + 4:
|
|
//eT = eT_float2x4;
|
|
eT = (pr->m_eType == eType_FLOAT) ? eT_float2x4 : eT_half2x4;
|
|
break;
|
|
case 3 * 4 + 4:
|
|
//eT = eT_float3x4;
|
|
eT = (pr->m_eType == eType_FLOAT) ? eT_float3x4 : eT_half3x4;
|
|
break;
|
|
case 4 * 4 + 4:
|
|
//eT = eT_float4x4;
|
|
eT = (pr->m_eType == eType_FLOAT) ? eT_float4x4 : eT_half4x4;
|
|
break;
|
|
case 3 * 4 + 3:
|
|
//eT = eT_float3x3;
|
|
eT = (pr->m_eType == eType_FLOAT) ? eT_float3x3 : eT_half3x3;
|
|
break;
|
|
}
|
|
CRY_ASSERT(eT != eT_unknown);
|
|
if (eT == eT_unknown)
|
|
{
|
|
return;
|
|
}
|
|
SHData.push_back(eT);
|
|
}
|
|
for (uint32 i = 0; i < pr->m_dwName.size(); i++)
|
|
{
|
|
SHData.push_back(pr->m_dwName[i]);
|
|
}
|
|
|
|
if (nReg >= 0 && nReg < 10000)
|
|
{
|
|
SHData.push_back(eT_colon);
|
|
if (nCB == eConstantBufferShaderSlot_PerMaterial)
|
|
{
|
|
SHData.push_back(eT_packoffset);
|
|
}
|
|
else
|
|
{
|
|
SHData.push_back(eT_register);
|
|
}
|
|
SHData.push_back(eT_br_rnd_1);
|
|
sprintf_s(str, "c%d", nReg);
|
|
SHData.push_back(Parser.NewUserToken(eT_unknown, str, true));
|
|
SHData.push_back(eT_br_rnd_2);
|
|
}
|
|
SHData.push_back(eT_semicolumn);
|
|
}
|
|
|
|
void CShaderManBin::AddSamplerToScript(CParserBin& Parser, SFXSampler* pr, PodArray<uint32>& SHData, EHWShaderClass eSHClass)
|
|
{
|
|
char str[256];
|
|
int nReg = pr->m_Register[eSHClass];
|
|
if (pr->m_eType == eSType_Sampler)
|
|
{
|
|
SHData.push_back(eT_SamplerState);
|
|
}
|
|
else
|
|
if (pr->m_eType == eSType_SamplerComp)
|
|
{
|
|
SHData.push_back(eT_SamplerComparisonState);
|
|
}
|
|
else
|
|
{
|
|
CRY_ASSERT(0);
|
|
}
|
|
for (uint32 i = 0; i < pr->m_dwName.size(); i++)
|
|
{
|
|
SHData.push_back(pr->m_dwName[i]);
|
|
}
|
|
|
|
if (nReg >= 0 && nReg < 10000)
|
|
{
|
|
SHData.push_back(eT_colon);
|
|
SHData.push_back(eT_register);
|
|
SHData.push_back(eT_br_rnd_1);
|
|
azsprintf(str, "s%d", nReg);
|
|
SHData.push_back(Parser.NewUserToken(eT_unknown, str, true));
|
|
SHData.push_back(eT_br_rnd_2);
|
|
}
|
|
SHData.push_back(eT_semicolumn);
|
|
}
|
|
void CShaderManBin::AddTextureToScript(CParserBin& Parser, SFXTexture* pr, PodArray<uint32>& SHData, EHWShaderClass eSHClass)
|
|
{
|
|
char str[256];
|
|
int nReg = pr->m_Register[eSHClass];
|
|
if (pr->m_eType == eTT_2D)
|
|
{
|
|
SHData.push_back(eT_Texture2D);
|
|
}
|
|
else
|
|
if (pr->m_eType == eTT_3D)
|
|
{
|
|
SHData.push_back(eT_Texture3D);
|
|
}
|
|
else
|
|
if (pr->m_eType == eTT_2DArray)
|
|
{
|
|
SHData.push_back(eT_Texture2DArray);
|
|
}
|
|
else
|
|
if (pr->m_eType == eTT_2DMS)
|
|
{
|
|
SHData.push_back(eT_Texture2DMS);
|
|
}
|
|
else
|
|
if (pr->m_eType == eTT_Cube)
|
|
{
|
|
SHData.push_back(eT_TextureCube);
|
|
}
|
|
else
|
|
if (pr->m_eType == eTT_CubeArray)
|
|
{
|
|
SHData.push_back(eT_TextureCubeArray);
|
|
}
|
|
else
|
|
{
|
|
CRY_ASSERT(0);
|
|
}
|
|
if (pr->m_Type != eT_unknown)
|
|
{
|
|
SHData.push_back(eT_br_tr_1);
|
|
SHData.push_back(pr->m_Type);
|
|
SHData.push_back(eT_br_tr_2);
|
|
}
|
|
for (uint32 i = 0; i < pr->m_dwName.size(); i++)
|
|
{
|
|
SHData.push_back(pr->m_dwName[i]);
|
|
}
|
|
|
|
if (nReg >= 0 && nReg < 10000)
|
|
{
|
|
SHData.push_back(eT_colon);
|
|
SHData.push_back(eT_register);
|
|
SHData.push_back(eT_br_rnd_1);
|
|
azsprintf(str, "t%d", nReg);
|
|
SHData.push_back(Parser.NewUserToken(eT_unknown, str, true));
|
|
SHData.push_back(eT_br_rnd_2);
|
|
}
|
|
SHData.push_back(eT_semicolumn);
|
|
}
|
|
|
|
static EToken GeneratedConstantBufferNames[] = { eT_PER_BATCH, eT_PER_INSTANCE, eT_PER_MATERIAL };
|
|
|
|
bool CShaderManBin::ParseBinFX_Technique_Pass_GenerateShaderData(CParserBin& Parser, FXMacroBin& Macros, SShaderFXParams& FXParams, uint32 dwSHName, EHWShaderClass eSHClass, uint64& nAffectMask, uint32 dwSHType, PodArray<uint32>& SHData, SShaderTechnique* pShTech)
|
|
{
|
|
LOADING_TIME_PROFILE_SECTION(iSystem);
|
|
CRY_ASSERT(gRenDev->m_pRT->IsRenderThread());
|
|
|
|
bool bRes = true;
|
|
|
|
std::vector<SFXParam> AffectedParams;
|
|
std::vector<SFXSampler> AffectedSamplers;
|
|
std::vector<SFXTexture> AffectedTextures;
|
|
|
|
uint32 i, j;
|
|
uint32 nNum;
|
|
static TArray<int> AffectedFragments;
|
|
AffectedFragments.reserve(120);
|
|
AffectedFragments.SetUse(0);
|
|
|
|
for (nNum = 0; nNum < Parser.m_CodeFragments.size(); nNum++)
|
|
{
|
|
if (dwSHName == Parser.m_CodeFragments[nNum].m_dwName)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (nNum == Parser.m_CodeFragments.size())
|
|
{
|
|
AZ_Assert(false, "Couldn't find entry function '%s'", Parser.GetString(dwSHName));
|
|
return false;
|
|
}
|
|
|
|
SCodeFragment* pFunc = &Parser.m_CodeFragments[nNum];
|
|
SShaderBin* pBin = Parser.m_pCurBinShader;
|
|
SParamCacheInfo* pCache = GetParamInfo(pBin, pFunc->m_dwName, Parser.m_pCurShader->m_nMaskGenFX, Parser.m_pCurShader->m_maskGenStatic);
|
|
if (pCache)
|
|
{
|
|
AffectedFragments.SetUse(0);
|
|
AffectedFragments.reserve(pCache->m_AffectedFuncs.size());
|
|
if (pCache->m_AffectedFuncs.empty() == false)
|
|
{
|
|
AffectedFragments.Copy(&pCache->m_AffectedFuncs[0], pCache->m_AffectedFuncs.size());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AffectedFragments.push_back(nNum);
|
|
if (CParserBin::m_bParseFX)
|
|
{
|
|
TArray<byte> bChecked;
|
|
bChecked.resize(Parser.m_CodeFragments.size());
|
|
if (bChecked.size() > 0)
|
|
{
|
|
memset(&bChecked[0], 0, sizeof(byte) * bChecked.size());
|
|
}
|
|
bChecked[nNum] = 1;
|
|
InitShaderDependenciesList(Parser, pFunc, bChecked, AffectedFragments);
|
|
CheckFragmentsDependencies(Parser, bChecked, AffectedFragments);
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < Parser.m_CodeFragments.size(); i++)
|
|
{
|
|
if (i != nNum)
|
|
{
|
|
AffectedFragments.push_back(i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
nAffectMask = 0;
|
|
for (i = 0; i < AffectedFragments.size(); i++)
|
|
{
|
|
SCodeFragment* s = &Parser.m_CodeFragments[AffectedFragments[i]];
|
|
if (s->m_eType != eFT_Function && s->m_eType != eFT_Structure && s->m_eType != eFT_ConstBuffer && s->m_eType != eFT_StorageClass)
|
|
{
|
|
continue;
|
|
}
|
|
FXMacroBinItor itor;
|
|
for (itor = Macros.begin(); itor != Macros.end(); ++itor)
|
|
{
|
|
SMacroBinFX* pr = &itor->second;
|
|
if (!pr->m_nMask)
|
|
{
|
|
continue;
|
|
}
|
|
if ((pr->m_nMask & nAffectMask) == pr->m_nMask)
|
|
{
|
|
continue;
|
|
}
|
|
uint32 dwName = itor->first;
|
|
if (Parser.FindToken(s->m_nFirstToken, s->m_nLastToken, dwName) >= 0)
|
|
{
|
|
nAffectMask |= pr->m_nMask;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Generate list of params before first preprocessor pass for affected functions
|
|
TArray<byte> bMerged;
|
|
bMerged.Reserve(FXParams.m_FXParams.size());
|
|
if (pCache)
|
|
{
|
|
for (i = 0; i < pCache->m_AffectedParams.size(); i++)
|
|
{
|
|
uint32 nParam = pCache->m_AffectedParams[i];
|
|
FXParamsIt it = std::lower_bound(FXParams.m_FXParams.begin(), FXParams.m_FXParams.end(), nParam, FXParamsSortByName());
|
|
if (it != FXParams.m_FXParams.end() && nParam == (*it).m_dwName[0])
|
|
{
|
|
SFXParam& pr = (*it);
|
|
if (!(pr.GetFlags() & PF_AUTOMERGED))
|
|
{
|
|
if (pr.m_Semantic.empty() && pr.m_Values.c_str()[0] == '(')
|
|
{
|
|
pr.m_BindingSlot = eConstantBufferShaderSlot_PerMaterial;
|
|
}
|
|
AffectedParams.push_back(pr);
|
|
}
|
|
}
|
|
}
|
|
for (i = 0; i < pCache->m_AffectedSamplers.size(); i++)
|
|
{
|
|
uint32 nParam = pCache->m_AffectedSamplers[i];
|
|
FXSamplersIt it = std::lower_bound(FXParams.m_FXSamplers.begin(), FXParams.m_FXSamplers.end(), nParam, FXSamplersSortByName());
|
|
if (it != FXParams.m_FXSamplers.end() && nParam == (*it).m_dwName[0])
|
|
{
|
|
SFXSampler& pr = (*it);
|
|
AffectedSamplers.push_back(pr);
|
|
}
|
|
}
|
|
for (i = 0; i < pCache->m_AffectedTextures.size(); i++)
|
|
{
|
|
uint32 nParam = pCache->m_AffectedTextures[i];
|
|
FXTexturesIt it = std::lower_bound(FXParams.m_FXTextures.begin(), FXParams.m_FXTextures.end(), nParam, FXTexturesSortByName());
|
|
if (it != FXParams.m_FXTextures.end() && nParam == (*it).m_dwName[0])
|
|
{
|
|
SFXTexture& pr = (*it);
|
|
AffectedTextures.push_back(pr);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < FXParams.m_FXParams.size(); i++)
|
|
{
|
|
SFXParam* pr = &FXParams.m_FXParams[i];
|
|
if (!(pr->GetFlags() & PF_AUTOMERGED))
|
|
{
|
|
AddAffectedParameter(Parser, AffectedParams, AffectedFragments, pr, eSHClass, dwSHType, pShTech);
|
|
}
|
|
}
|
|
for (i = 0; i < FXParams.m_FXSamplers.size(); i++)
|
|
{
|
|
SFXSampler* pr = &FXParams.m_FXSamplers[i];
|
|
AddAffectedSampler(Parser, AffectedSamplers, AffectedFragments, pr, eSHClass, dwSHType, pShTech);
|
|
}
|
|
for (i = 0; i < FXParams.m_FXTextures.size(); i++)
|
|
{
|
|
SFXTexture* pr = &FXParams.m_FXTextures[i];
|
|
AddAffectedTexture(Parser, AffectedTextures, AffectedFragments, pr, eSHClass, dwSHType, pShTech);
|
|
}
|
|
}
|
|
|
|
if (CParserBin::m_bParseFX)
|
|
{
|
|
FXMacroBinItor itor;
|
|
for (itor = Macros.begin(); itor != Macros.end(); ++itor)
|
|
{
|
|
if (itor->second.m_nMask && !(itor->second.m_nMask & nAffectMask))
|
|
{
|
|
continue;
|
|
}
|
|
SHData.push_back(eT_define);
|
|
SHData.push_back(itor->first);
|
|
SHData.push_back(0);
|
|
}
|
|
std::vector<SFXParam> PackedParams;
|
|
TArray<SCodeFragment> Replaces;
|
|
TArray<uint32> NewTokens;
|
|
ParseBinFX_Technique_Pass_PackParameters (Parser, AffectedParams, AffectedFragments, pFunc, eSHClass, dwSHName, PackedParams, Replaces, NewTokens, bMerged);
|
|
|
|
if (!pCache)
|
|
{
|
|
// Update new parameters in shader structures
|
|
for (i = 0; i < PackedParams.size(); i++)
|
|
{
|
|
SFXParam* pr = &PackedParams[i];
|
|
AffectedParams.push_back(*pr);
|
|
}
|
|
if (CRenderer::CV_r_shadersAllowCompilation)
|
|
{
|
|
SaveBinShaderLocalInfo(pBin, pFunc->m_dwName, Parser.m_pCurShader->m_nMaskGenFX, Parser.m_pCurShader->m_maskGenStatic, AffectedFragments, AffectedParams, AffectedSamplers, AffectedTextures);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < pCache->m_AffectedParams.size(); i++)
|
|
{
|
|
int32 nParam = pCache->m_AffectedParams[i];
|
|
for (j = 0; j < PackedParams.size(); j++)
|
|
{
|
|
SFXParam& pr = PackedParams[j];
|
|
if (pr.m_dwName[0] == nParam)
|
|
{
|
|
AffectedParams.push_back(pr);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update FX parameters
|
|
for (i = 0; i < AffectedParams.size(); i++)
|
|
{
|
|
SFXParam* pr = &AffectedParams[i];
|
|
mfAddFXParam(FXParams, pr);
|
|
}
|
|
|
|
// Include all affected functions/structures/parameters in the final script
|
|
if (CParserBin::PlatformSupportsConstantBuffers()) // use CB scopes for D3D10 shaders
|
|
{
|
|
int8 nPrevCB = -1;
|
|
std::vector<SFXParam*> ParamsData;
|
|
|
|
for (i = 0; i < AffectedParams.size(); i++)
|
|
{
|
|
SFXParam& pr = AffectedParams[i];
|
|
if (bMerged[i] == 0xff)
|
|
{
|
|
continue;
|
|
}
|
|
if (pr.m_BindingSlot >= 0)
|
|
{
|
|
ParamsData.push_back(&pr);
|
|
}
|
|
}
|
|
|
|
const int shaderClassIndex = (eSHClass == eHWSC_Vertex) ? 0 : (eSHClass == eHWSC_Pixel) ? 1 : 2;
|
|
|
|
std::sort(ParamsData.begin(), ParamsData.end(),
|
|
[shaderClassIndex](const SFXParam* a, const SFXParam* b)
|
|
{
|
|
const uint16 bindSlot0 = a->m_BindingSlot;
|
|
const uint16 bindSlot1 = b->m_BindingSlot;
|
|
const int16 register0 = a->m_Register[shaderClassIndex];
|
|
const int16 register1 = b->m_Register[shaderClassIndex];
|
|
|
|
if (bindSlot0 != bindSlot1)
|
|
{
|
|
return (bindSlot0 < bindSlot1);
|
|
}
|
|
return (register0 < register1);
|
|
});
|
|
|
|
// First we need to declare semantic variables (in CB scopes in case of DX11)
|
|
for (i = 0; i < ParamsData.size(); i++)
|
|
{
|
|
SFXParam* pPr = ParamsData[i];
|
|
int nCB = pPr->m_BindingSlot;
|
|
nCB = pPr->m_BindingSlot;
|
|
if (nPrevCB != nCB)
|
|
{
|
|
if (nPrevCB != -1)
|
|
{
|
|
SHData.push_back(eT_br_cv_2);
|
|
SHData.push_back(eT_semicolumn);
|
|
}
|
|
SHData.push_back(eT_cbuffer);
|
|
|
|
AZ_Assert(nCB < AZ_ARRAY_SIZE(GeneratedConstantBufferNames), "Trying to generate a constant buffer at an invalid slot");
|
|
SHData.push_back(GeneratedConstantBufferNames[nCB]);
|
|
SHData.push_back(eT_colon);
|
|
SHData.push_back(eT_register);
|
|
char str[32];
|
|
sprintf_s(str, "b%d", nCB);
|
|
SHData.push_back(eT_br_rnd_1);
|
|
SHData.push_back(Parser.NewUserToken(eT_unknown, str, true));
|
|
SHData.push_back(eT_br_rnd_2);
|
|
SHData.push_back(eT_br_cv_1);
|
|
}
|
|
nPrevCB = nCB;
|
|
AddParameterToScript(Parser, pPr, SHData, eSHClass, nCB);
|
|
}
|
|
if (nPrevCB >= 0)
|
|
{
|
|
nPrevCB = -1;
|
|
SHData.push_back(eT_br_cv_2);
|
|
SHData.push_back(eT_semicolumn);
|
|
}
|
|
|
|
for (i = 0; i < AffectedSamplers.size(); i++)
|
|
{
|
|
SFXSampler* pr = &AffectedSamplers[i];
|
|
AddSamplerToScript(Parser, pr, SHData, eSHClass);
|
|
}
|
|
for (i = 0; i < AffectedTextures.size(); i++)
|
|
{
|
|
SFXTexture* pr = &AffectedTextures[i];
|
|
AddTextureToScript(Parser, pr, SHData, eSHClass);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Update affected parameters in script
|
|
#ifdef _DEBUG
|
|
for (i = 0; i < AffectedParams.size(); i++)
|
|
{
|
|
SFXParam* pr = &AffectedParams[i];
|
|
for (j = i + 1; j < AffectedParams.size(); j++)
|
|
{
|
|
SFXParam* pr1 = &AffectedParams[j];
|
|
if (pr->m_dwName[0] == pr1->m_dwName[0])
|
|
{
|
|
CRY_ASSERT(0);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
for (i = 0; i < AffectedParams.size(); i++)
|
|
{
|
|
SFXParam* pr = &AffectedParams[i];
|
|
// Ignore parameters which where packed
|
|
if (bMerged[i] == 0xff)
|
|
{
|
|
continue;
|
|
}
|
|
AddParameterToScript(Parser, pr, SHData, eSHClass, -1);
|
|
}
|
|
}
|
|
|
|
// Generate fragment tokens
|
|
for (i = 0; i < Parser.m_CodeFragments.size(); i++)
|
|
{
|
|
int h = -1;
|
|
SCodeFragment* cf = &Parser.m_CodeFragments[i];
|
|
if (cf->m_dwName)
|
|
{
|
|
for (h = 0; h < (int)AffectedFragments.size(); h++)
|
|
{
|
|
if (AffectedFragments[h] == i)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (h == AffectedFragments.size())
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
Parser.CopyTokens(cf, SHData, Replaces, NewTokens, h);
|
|
if (cf->m_eType == eFT_Sampler)
|
|
{
|
|
if (CParserBin::m_nPlatform == SF_D3D11 || CParserBin::m_nPlatform == SF_JASPER || CParserBin::m_nPlatform == SF_GL4 || CParserBin::m_nPlatform == SF_GLES3 || CParserBin::m_nPlatform == SF_METAL)
|
|
{
|
|
int nT = Parser.m_Tokens[cf->m_nLastToken - 1];
|
|
//CRY_ASSERT(nT >= eT_s0 && nT <= eT_s15);
|
|
if (nT >= eT_s0 && nT <= eT_s15)
|
|
{
|
|
nT = nT - eT_s0 + eT_t0;
|
|
SHData.push_back(eT_colon);
|
|
SHData.push_back(eT_register);
|
|
SHData.push_back(eT_br_rnd_1);
|
|
SHData.push_back(nT);
|
|
SHData.push_back(eT_br_rnd_2);
|
|
}
|
|
}
|
|
SHData.push_back(eT_semicolumn);
|
|
}
|
|
}
|
|
}
|
|
return bRes;
|
|
}
|
|
|
|
bool CShaderManBin::ParseBinFX_Technique_Pass_LoadShader([[maybe_unused]] CParserBin& Parser, [[maybe_unused]] FXMacroBin& Macros, [[maybe_unused]] SParserFrame& SHFrame, [[maybe_unused]] SShaderTechnique* pShTech, [[maybe_unused]] SShaderPass* pPass, [[maybe_unused]] EHWShaderClass eSHClass, [[maybe_unused]] SShaderFXParams& FXParams)
|
|
{
|
|
assert (gRenDev->m_pRT->IsRenderThread());
|
|
|
|
LOADING_TIME_PROFILE_SECTION(iSystem);
|
|
bool bRes = true;
|
|
|
|
#ifndef NULL_RENDERER
|
|
|
|
CRY_ASSERT(!SHFrame.IsEmpty());
|
|
|
|
uint32 dwSHName;
|
|
uint32 dwSHType = 0;
|
|
|
|
uint32* pTokens = &Parser.m_Tokens[0];
|
|
|
|
dwSHName = pTokens[SHFrame.m_nFirstToken];
|
|
uint32 nCur = SHFrame.m_nFirstToken + 1;
|
|
uint32 nTok = pTokens[nCur];
|
|
if (nTok != eT_br_rnd_1)
|
|
{
|
|
nCur += 2;
|
|
nTok = pTokens[nCur];
|
|
}
|
|
nCur++;
|
|
assert (nTok == eT_br_rnd_1);
|
|
if (nTok == eT_br_rnd_1)
|
|
{
|
|
nTok = pTokens[nCur];
|
|
if (nTok != eT_br_rnd_2)
|
|
{
|
|
CRY_ASSERT(!"Local function parameters aren't supported anymore");
|
|
}
|
|
}
|
|
nCur++;
|
|
if (nCur <= SHFrame.m_nLastToken)
|
|
{
|
|
dwSHType = pTokens[nCur];
|
|
}
|
|
|
|
enum
|
|
{
|
|
SHDATA_BUFFER_SIZE = 131072
|
|
};
|
|
|
|
uint64 nGenMask = 0;
|
|
PodArray<uint32> SHDataBuffer(SHDATA_BUFFER_SIZE);
|
|
bRes &= ParseBinFX_Technique_Pass_GenerateShaderData(Parser, Macros, FXParams, dwSHName, eSHClass, nGenMask, dwSHType, SHDataBuffer, pShTech);
|
|
#if !defined(_RELEASE)
|
|
if (SHDataBuffer.size() > SHDATA_BUFFER_SIZE)
|
|
{
|
|
CryLogAlways("CShaderManBin::ParseBinFX_Technique_Pass_LoadShader: SHDataBuffer has been exceeded (buffer=%u, count=%u). Adjust buffer size to remove unnecessary allocs", SHDATA_BUFFER_SIZE, SHDataBuffer.Size());
|
|
}
|
|
#endif
|
|
TArray<uint32> SHData(0, SHDataBuffer.Size());
|
|
SHData.Copy(SHDataBuffer.GetElements(), SHDataBuffer.size());
|
|
|
|
CHWShader* pSH = NULL;
|
|
bool bValidShader = false;
|
|
|
|
CShader* efSave = gRenDev->m_RP.m_pShader;
|
|
gRenDev->m_RP.m_pShader = Parser.m_pCurShader;
|
|
CRY_ASSERT(gRenDev->m_RP.m_pShader != 0);
|
|
if (bRes && (!CParserBin::m_bParseFX || !SHData.empty()))
|
|
{
|
|
const char* szName = Parser.GetString(dwSHName);
|
|
char str[1024];
|
|
sprintf_s(str, "%s@%s", Parser.m_pCurShader->m_NameShader.c_str(), szName);
|
|
pSH = CHWShader::mfForName(str, Parser.m_pCurShader->m_NameFile, Parser.m_pCurShader->m_CRC32, szName, eSHClass, SHData, &Parser.m_TokenTable, dwSHType, Parser.m_pCurShader, nGenMask, Parser.m_pCurShader->m_nMaskGenFX);
|
|
}
|
|
if (pSH)
|
|
{
|
|
bValidShader = true;
|
|
|
|
if (eSHClass == eHWSC_Vertex)
|
|
{
|
|
pPass->m_VShader = pSH;
|
|
}
|
|
else
|
|
if (eSHClass == eHWSC_Pixel)
|
|
{
|
|
pPass->m_PShader = pSH;
|
|
}
|
|
else
|
|
if (CParserBin::PlatformSupportsGeometryShaders() && eSHClass == eHWSC_Geometry)
|
|
{
|
|
pPass->m_GShader = pSH;
|
|
}
|
|
else
|
|
if (CParserBin::PlatformSupportsDomainShaders() && eSHClass == eHWSC_Domain)
|
|
{
|
|
pPass->m_DShader = pSH;
|
|
}
|
|
else
|
|
if (CParserBin::PlatformSupportsHullShaders() && eSHClass == eHWSC_Hull)
|
|
{
|
|
pPass->m_HShader = pSH;
|
|
}
|
|
else
|
|
if (CParserBin::PlatformSupportsComputeShaders() && eSHClass == eHWSC_Compute)
|
|
{
|
|
pPass->m_CShader = pSH;
|
|
}
|
|
else
|
|
{
|
|
CryLog("Unsupported/unrecognised shader: %s[%d]", pSH->m_Name.c_str(), eSHClass);
|
|
}
|
|
}
|
|
|
|
gRenDev->m_RP.m_pShader = efSave;
|
|
#endif
|
|
|
|
return bRes;
|
|
}
|
|
|
|
bool CShaderManBin::ParseBinFX_Technique_Pass(CParserBin& Parser, SParserFrame& Frame, SShaderTechnique* pShTech)
|
|
{
|
|
SParserFrame OldFrame = Parser.BeginFrame(Frame);
|
|
|
|
FX_BEGIN_TOKENS
|
|
FX_TOKEN(VertexShader)
|
|
FX_TOKEN(PixelShader)
|
|
FX_TOKEN(GeometryShader)
|
|
FX_TOKEN(DomainShader)
|
|
FX_TOKEN(HullShader)
|
|
FX_TOKEN(ComputeShader)
|
|
FX_TOKEN(ZEnable)
|
|
FX_TOKEN(ZWriteEnable)
|
|
FX_TOKEN(CullMode)
|
|
FX_TOKEN(SrcBlend)
|
|
FX_TOKEN(DestBlend)
|
|
FX_TOKEN(AlphaBlendEnable)
|
|
FX_TOKEN(AlphaFunc)
|
|
FX_TOKEN(AlphaRef)
|
|
FX_TOKEN(ZFunc)
|
|
FX_TOKEN(ColorWriteEnable)
|
|
FX_TOKEN(IgnoreMaterialState)
|
|
FX_END_TOKENS
|
|
|
|
bool bRes = true;
|
|
int n = pShTech->m_Passes.Num();
|
|
pShTech->m_Passes.ReserveNew(n + 1);
|
|
SShaderPass* sm = &pShTech->m_Passes[n];
|
|
sm->m_eCull = -1;
|
|
sm->m_AlphaRef = ~0;
|
|
|
|
SParserFrame VS, PS, GS, DS, HS, CS;
|
|
FXMacroBin VSMacro, PSMacro, GSMacro, DSMacro, HSMacro, CSMacro;
|
|
|
|
byte ZFunc = eCF_LEqual;
|
|
|
|
byte ColorWriteMask = 0xff;
|
|
|
|
byte AlphaFunc = eCF_Disable;
|
|
byte AlphaRef = 0;
|
|
int State = GS_DEPTHWRITE;
|
|
|
|
int nMaxTMU = 0;
|
|
signed char Cull = -1;
|
|
int nIndex;
|
|
EToken eSrcBlend = eT_unknown;
|
|
EToken eDstBlend = eT_unknown;
|
|
bool bBlend = false;
|
|
|
|
while (Parser.ParseObject(sCommands, nIndex))
|
|
{
|
|
EToken eT = Parser.GetToken();
|
|
switch (eT)
|
|
{
|
|
case eT_VertexShader:
|
|
VS = Parser.m_Data;
|
|
VSMacro = Parser.m_Macros[1];
|
|
break;
|
|
case eT_PixelShader:
|
|
PS = Parser.m_Data;
|
|
PSMacro = Parser.m_Macros[1];
|
|
break;
|
|
case eT_GeometryShader:
|
|
GS = Parser.m_Data;
|
|
GSMacro = Parser.m_Macros[1];
|
|
break;
|
|
case eT_DomainShader:
|
|
DS = Parser.m_Data;
|
|
DSMacro = Parser.m_Macros[1];
|
|
break;
|
|
case eT_HullShader:
|
|
HS = Parser.m_Data;
|
|
HSMacro = Parser.m_Macros[1];
|
|
break;
|
|
case eT_ComputeShader:
|
|
CS = Parser.m_Data;
|
|
CSMacro = Parser.m_Macros[1];
|
|
break;
|
|
|
|
case eT_ZEnable:
|
|
if (Parser.GetBool(Parser.m_Data))
|
|
{
|
|
State &= ~GS_NODEPTHTEST;
|
|
}
|
|
else
|
|
{
|
|
State |= GS_NODEPTHTEST;
|
|
}
|
|
break;
|
|
case eT_ZWriteEnable:
|
|
if (Parser.GetBool(Parser.m_Data))
|
|
{
|
|
State |= GS_DEPTHWRITE;
|
|
}
|
|
else
|
|
{
|
|
State &= ~GS_DEPTHWRITE;
|
|
}
|
|
break;
|
|
case eT_CullMode:
|
|
eT = Parser.GetToken(Parser.m_Data);
|
|
if (eT == eT_None)
|
|
{
|
|
Cull = eCULL_None;
|
|
}
|
|
else
|
|
if (eT == eT_CCW || eT == eT_Back)
|
|
{
|
|
Cull = eCULL_Back;
|
|
}
|
|
else
|
|
if (eT == eT_CW || eT == eT_Front)
|
|
{
|
|
Cull = eCULL_Front;
|
|
}
|
|
else
|
|
{
|
|
Warning("unknown CullMode parameter '%s' (Skipping)\n", Parser.GetString(eT));
|
|
CRY_ASSERT(0);
|
|
}
|
|
break;
|
|
case eT_AlphaFunc:
|
|
AlphaFunc = Parser.GetCompareFunc(Parser.GetToken(Parser.m_Data));
|
|
break;
|
|
case eT_ColorWriteEnable:
|
|
{
|
|
if (ColorWriteMask == 0xff)
|
|
{
|
|
ColorWriteMask = 0;
|
|
}
|
|
uint32 nCur = Parser.m_Data.m_nFirstToken;
|
|
while (nCur <= Parser.m_Data.m_nLastToken)
|
|
{
|
|
uint32 nT = Parser.m_Tokens[nCur++];
|
|
if (nT == eT_or)
|
|
{
|
|
continue;
|
|
}
|
|
if (nT == eT_0)
|
|
{
|
|
ColorWriteMask |= 0;
|
|
}
|
|
else
|
|
if (nT == eT_RED)
|
|
{
|
|
ColorWriteMask |= 1;
|
|
}
|
|
else
|
|
if (nT == eT_GREEN)
|
|
{
|
|
ColorWriteMask |= 2;
|
|
}
|
|
else
|
|
if (nT == eT_BLUE)
|
|
{
|
|
ColorWriteMask |= 4;
|
|
}
|
|
else
|
|
if (nT == eT_ALPHA)
|
|
{
|
|
ColorWriteMask |= 8;
|
|
}
|
|
else
|
|
{
|
|
Warning("unknown WriteMask parameter '%s' (Skipping)\n", Parser.GetString(eT));
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case eT_ZFunc:
|
|
ZFunc = Parser.GetCompareFunc(Parser.GetToken(Parser.m_Data));
|
|
sm->m_PassFlags |= SHPF_FORCEZFUNC;
|
|
break;
|
|
case eT_AlphaRef:
|
|
AlphaRef = Parser.GetInt(Parser.GetToken(Parser.m_Data));
|
|
break;
|
|
case eT_SrcBlend:
|
|
eSrcBlend = Parser.GetToken(Parser.m_Data);
|
|
break;
|
|
case eT_DestBlend:
|
|
eDstBlend = Parser.GetToken(Parser.m_Data);
|
|
break;
|
|
case eT_AlphaBlendEnable:
|
|
bBlend = Parser.GetBool(Parser.m_Data);
|
|
break;
|
|
|
|
case eT_IgnoreMaterialState:
|
|
sm->m_PassFlags |= SHPF_NOMATSTATE;
|
|
break;
|
|
|
|
default:
|
|
CRY_ASSERT(0);
|
|
}
|
|
}
|
|
|
|
if (bBlend && eSrcBlend && eDstBlend)
|
|
{
|
|
int nSrc = Parser.GetSrcBlend(eSrcBlend);
|
|
int nDst = Parser.GetDstBlend(eDstBlend);
|
|
if (nSrc >= 0 && nDst >= 0)
|
|
{
|
|
State |= nSrc;
|
|
State |= nDst;
|
|
}
|
|
}
|
|
if (ColorWriteMask != 0xff)
|
|
{
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
if (!(ColorWriteMask & (1 << i)))
|
|
{
|
|
State |= GS_NOCOLMASK_R << i;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (AlphaFunc)
|
|
{
|
|
switch (AlphaFunc)
|
|
{
|
|
case eCF_Greater:
|
|
State |= GS_ALPHATEST_GREATER;
|
|
break;
|
|
case eCF_GEqual:
|
|
State |= GS_ALPHATEST_GEQUAL;
|
|
break;
|
|
case eCF_Less:
|
|
State |= GS_ALPHATEST_LESS;
|
|
break;
|
|
case eCF_LEqual:
|
|
State |= GS_ALPHATEST_LEQUAL;
|
|
break;
|
|
default:
|
|
CRY_ASSERT(0);
|
|
}
|
|
}
|
|
|
|
switch (ZFunc)
|
|
{
|
|
case eCF_Equal:
|
|
State |= GS_DEPTHFUNC_EQUAL;
|
|
break;
|
|
case eCF_Greater:
|
|
State |= GS_DEPTHFUNC_GREAT;
|
|
break;
|
|
case eCF_GEqual:
|
|
State |= GS_DEPTHFUNC_GEQUAL;
|
|
break;
|
|
case eCF_Less:
|
|
State |= GS_DEPTHFUNC_LESS;
|
|
break;
|
|
case eCF_NotEqual:
|
|
State |= GS_DEPTHFUNC_NOTEQUAL;
|
|
break;
|
|
case eCF_LEqual:
|
|
State |= GS_DEPTHFUNC_LEQUAL;
|
|
break;
|
|
case eCF_Always:
|
|
State |= GS_DEPTHFUNC_ALWAYS;
|
|
break;
|
|
default:
|
|
CRY_ASSERT(0);
|
|
}
|
|
|
|
sm->m_RenderState = State;
|
|
sm->m_eCull = Cull;
|
|
|
|
mfGeneratePublicFXParams(Parser.m_pCurShader, Parser);
|
|
SShaderFXParams& FXParams = mfGetFXParams(Parser.m_pCurShader);
|
|
|
|
if (!VS.IsEmpty())
|
|
{
|
|
bRes &= ParseBinFX_Technique_Pass_LoadShader(Parser, VSMacro, VS, pShTech, sm, eHWSC_Vertex, FXParams);
|
|
}
|
|
if (!PS.IsEmpty())
|
|
{
|
|
bRes &= ParseBinFX_Technique_Pass_LoadShader(Parser, PSMacro, PS, pShTech, sm, eHWSC_Pixel, FXParams);
|
|
}
|
|
if (CParserBin::PlatformSupportsGeometryShaders() && !GS.IsEmpty())
|
|
{
|
|
bRes &= ParseBinFX_Technique_Pass_LoadShader(Parser, GSMacro, GS, pShTech, sm, eHWSC_Geometry, FXParams);
|
|
}
|
|
if (CParserBin::PlatformSupportsHullShaders() && !HS.IsEmpty())
|
|
{
|
|
bRes &= ParseBinFX_Technique_Pass_LoadShader(Parser, HSMacro, HS, pShTech, sm, eHWSC_Hull, FXParams);
|
|
}
|
|
if (CParserBin::PlatformSupportsDomainShaders() && !DS.IsEmpty())
|
|
{
|
|
bRes &= ParseBinFX_Technique_Pass_LoadShader(Parser, DSMacro, DS, pShTech, sm, eHWSC_Domain, FXParams);
|
|
}
|
|
if (CParserBin::PlatformSupportsComputeShaders() && !CS.IsEmpty())
|
|
{
|
|
bRes &= ParseBinFX_Technique_Pass_LoadShader(Parser, CSMacro, CS, pShTech, sm, eHWSC_Compute, FXParams);
|
|
}
|
|
|
|
Parser.EndFrame(OldFrame);
|
|
|
|
return bRes;
|
|
}
|
|
|
|
bool CShaderManBin::ParseBinFX_LightStyle_Val(CParserBin& Parser, SParserFrame& Frame, CLightStyle* ls)
|
|
{
|
|
int i;
|
|
char str[64];
|
|
const char* pstr1, * pstr2;
|
|
SLightStyleKeyFrame pKeyFrame;
|
|
|
|
ls->m_Map.Free();
|
|
string sr = Parser.GetString(Frame);
|
|
const char* lstr = sr.c_str();
|
|
|
|
// First count the keyframes
|
|
size_t nKeyFrames = 0;
|
|
while (true)
|
|
{
|
|
pstr1 = strchr(lstr, '|');
|
|
if (!pstr1)
|
|
{
|
|
break;
|
|
}
|
|
pstr2 = strchr(pstr1 + 1, '|');
|
|
if (!pstr2)
|
|
{
|
|
break;
|
|
}
|
|
if (pstr2 - pstr1 - 1 > 0)
|
|
{
|
|
++nKeyFrames;
|
|
}
|
|
lstr = pstr2;
|
|
}
|
|
ls->m_Map.reserve(nKeyFrames);
|
|
|
|
lstr = sr.c_str();
|
|
int n = 0;
|
|
while (true)
|
|
{
|
|
pstr1 = strchr(lstr, '|');
|
|
if (!pstr1)
|
|
{
|
|
break;
|
|
}
|
|
pstr2 = strchr(pstr1 + 1, '|');
|
|
if (!pstr2)
|
|
{
|
|
break;
|
|
}
|
|
if (pstr2 - pstr1 - 1 > 0)
|
|
{
|
|
azstrncpy(str, AZ_ARRAY_SIZE(str), pstr1 + 1, pstr2 - pstr1 - 1);
|
|
str[pstr2 - pstr1 - 1] = 0;
|
|
i = azsscanf(str, "%f %f %f %f %f %f %f", &pKeyFrame.cColor.r, &pKeyFrame.cColor.g, &pKeyFrame.cColor.b, &pKeyFrame.cColor.a,
|
|
&pKeyFrame.vPosOffset.x, &pKeyFrame.vPosOffset.y, &pKeyFrame.vPosOffset.z);
|
|
switch (i)
|
|
{
|
|
case 1:
|
|
{
|
|
// Only luminance updates
|
|
pKeyFrame.cColor.g = pKeyFrame.cColor.b = pKeyFrame.cColor.r;
|
|
pKeyFrame.cColor.a = 1.0f;
|
|
pKeyFrame.vPosOffset = Vec3(0);
|
|
}
|
|
break;
|
|
|
|
case 3:
|
|
{
|
|
// No position/spec mult updates
|
|
pKeyFrame.cColor.a = 1.0f;
|
|
pKeyFrame.vPosOffset = Vec3(0);
|
|
}
|
|
break;
|
|
|
|
case 4:
|
|
{
|
|
// No position
|
|
pKeyFrame.vPosOffset = Vec3(0);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
ls->m_Map.AddElem(pKeyFrame);
|
|
n++;
|
|
}
|
|
|
|
lstr = pstr2;
|
|
}
|
|
ls->m_Map.Shrink();
|
|
CRY_ASSERT(ls->m_Map.Num() == n);
|
|
if (ls->m_Map.Num() == n)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool CShaderManBin::ParseBinFX_LightStyle(CParserBin& Parser, SParserFrame& Frame, int nStyle)
|
|
{
|
|
SParserFrame OldFrame = Parser.BeginFrame(Frame);
|
|
|
|
FX_BEGIN_TOKENS
|
|
FX_TOKEN(KeyFrameParams)
|
|
FX_TOKEN(KeyFrameRandColor)
|
|
FX_TOKEN(KeyFrameRandIntensity)
|
|
FX_TOKEN(KeyFrameRandSpecMult)
|
|
FX_TOKEN(KeyFrameRandPosOffset)
|
|
FX_TOKEN(Speed)
|
|
FX_END_TOKENS
|
|
|
|
bool bRes = true;
|
|
|
|
Parser.m_pCurShader->m_Flags |= EF_LIGHTSTYLE;
|
|
if (CLightStyle::s_LStyles.Num() <= (uint32)nStyle)
|
|
{
|
|
CLightStyle::s_LStyles.ReserveNew(nStyle + 1);
|
|
}
|
|
CLightStyle* ls = CLightStyle::s_LStyles[nStyle];
|
|
if (!ls)
|
|
{
|
|
ls = new CLightStyle;
|
|
ls->m_LastTime = 0;
|
|
ls->m_Color = Col_White;
|
|
CLightStyle::s_LStyles[nStyle] = ls;
|
|
}
|
|
ls->m_TimeIncr = 60;
|
|
int nIndex;
|
|
|
|
while (Parser.ParseObject(sCommands, nIndex))
|
|
{
|
|
EToken eT = Parser.GetToken();
|
|
switch (eT)
|
|
{
|
|
case eT_KeyFrameRandColor:
|
|
ls->m_bRandColor = Parser.GetBool(Parser.m_Data);
|
|
break;
|
|
|
|
case eT_KeyFrameRandIntensity:
|
|
ls->m_bRandIntensity = Parser.GetBool(Parser.m_Data);
|
|
break;
|
|
|
|
case eT_KeyFrameRandSpecMult:
|
|
ls->m_bRandSpecMult = Parser.GetBool(Parser.m_Data);
|
|
break;
|
|
|
|
case eT_KeyFrameRandPosOffset:
|
|
ls->m_bRandPosOffset = Parser.GetBool(Parser.m_Data);
|
|
break;
|
|
|
|
case eT_KeyFrameParams:
|
|
bRes &= ParseBinFX_LightStyle_Val(Parser, Parser.m_Data, ls);
|
|
break;
|
|
|
|
case eT_Speed:
|
|
ls->m_TimeIncr = Parser.GetFloat(Parser.m_Data);
|
|
break;
|
|
default:
|
|
CRY_ASSERT(0);
|
|
}
|
|
}
|
|
|
|
if (ls->m_Map.Num() && (ls->m_bRandPosOffset || ls->m_bRandIntensity || ls->m_bRandSpecMult || ls->m_bRandColor))
|
|
{
|
|
int32 nCount = ls->m_Map.Num();
|
|
for (int f = 0; f < nCount; ++f)
|
|
{
|
|
SLightStyleKeyFrame& pKeyFrame = ls->m_Map[f];
|
|
if (ls->m_bRandPosOffset)
|
|
{
|
|
pKeyFrame.vPosOffset = Vec3(cry_random(-1.0f, 1.0f), cry_random(-1.0f, 1.0f), cry_random(-1.0f, 1.0f));
|
|
}
|
|
|
|
if (ls->m_bRandColor)
|
|
{
|
|
pKeyFrame.cColor *= ColorF(cry_random(0.0f, 1.0f), cry_random(0.0f, 1.0f), cry_random(0.0f, 1.0f), 1.0f);
|
|
}
|
|
|
|
if (ls->m_bRandIntensity)
|
|
{
|
|
pKeyFrame.cColor *= cry_random(0.0f, 1.0f);
|
|
}
|
|
|
|
if (ls->m_bRandSpecMult)
|
|
{
|
|
pKeyFrame.cColor.a = cry_random(0.0f, 1.0f);
|
|
}
|
|
}
|
|
}
|
|
|
|
Parser.EndFrame(OldFrame);
|
|
|
|
return bRes;
|
|
}
|
|
|
|
bool CShaderManBin::ParseBinFX_Technique_Annotations_String(CParserBin& Parser, SParserFrame& Frame, SShaderTechnique* pShTech, std::vector<SShaderTechParseParams>& techParams, bool* bPublic)
|
|
{
|
|
SParserFrame OldFrame = Parser.BeginFrame(Frame);
|
|
|
|
FX_BEGIN_TOKENS
|
|
FX_TOKEN(Public)
|
|
FX_TOKEN(NoLights)
|
|
FX_TOKEN(NoMaterialState)
|
|
FX_TOKEN(PositionInvariant)
|
|
FX_TOKEN(TechniqueZ)
|
|
FX_TOKEN(TechniqueZPrepass)
|
|
FX_TOKEN(TechniqueShadowGen)
|
|
FX_TOKEN(TechniqueMotionBlur)
|
|
FX_TOKEN(TechniqueCustomRender)
|
|
FX_TOKEN(TechniqueEffectLayer)
|
|
FX_TOKEN(TechniqueDebug)
|
|
FX_TOKEN(TechniqueSoftAlphaTest)
|
|
FX_TOKEN(TechniqueWaterRefl)
|
|
FX_TOKEN(TechniqueWaterCaustic)
|
|
FX_TOKEN(TechniqueThickness)
|
|
FX_END_TOKENS
|
|
|
|
bool bRes = true;
|
|
int nIndex;
|
|
|
|
while (Parser.ParseObject(sCommands, nIndex))
|
|
{
|
|
EToken eT = Parser.GetToken();
|
|
switch (eT)
|
|
{
|
|
case eT_Public:
|
|
if (pShTech)
|
|
{
|
|
pShTech->m_Flags |= FHF_PUBLIC;
|
|
}
|
|
else
|
|
if (bPublic)
|
|
{
|
|
*bPublic = true;
|
|
}
|
|
break;
|
|
|
|
case eT_PositionInvariant:
|
|
if (pShTech)
|
|
{
|
|
pShTech->m_Flags |= FHF_POSITION_INVARIANT;
|
|
}
|
|
break;
|
|
|
|
case eT_NoLights:
|
|
if (pShTech)
|
|
{
|
|
pShTech->m_Flags |= FHF_NOLIGHTS;
|
|
}
|
|
break;
|
|
|
|
case eT_NoMaterialState:
|
|
if (Parser.m_pCurShader)
|
|
{
|
|
Parser.m_pCurShader->m_Flags2 |= EF2_IGNORERESOURCESTATES;
|
|
}
|
|
break;
|
|
|
|
// Note: When adding/removing batch flags, please, update sDescList in D3DRendPipeline.cpp
|
|
case eT_TechniqueDebug:
|
|
{
|
|
}
|
|
|
|
case eT_TechniqueZ:
|
|
case eT_TechniqueZPrepass:
|
|
case eT_TechniqueShadowGen:
|
|
case eT_TechniqueMotionBlur:
|
|
case eT_TechniqueCustomRender:
|
|
case eT_TechniqueEffectLayer:
|
|
case eT_TechniqueSoftAlphaTest:
|
|
case eT_TechniqueWaterRefl:
|
|
case eT_TechniqueWaterCaustic:
|
|
case eT_TechniqueThickness:
|
|
{
|
|
if (!Parser.m_pCurShader)
|
|
{
|
|
break;
|
|
}
|
|
|
|
static const uint32 pTechTable[eT_TechniqueMax - eT_TechniqueZ] =
|
|
{
|
|
TTYPE_Z, //eT_TechniqueZ
|
|
TTYPE_SHADOWGEN, //eT_TechniqueShadowGen
|
|
TTYPE_MOTIONBLURPASS, //eT_TechniqueMotionBlur
|
|
TTYPE_CUSTOMRENDERPASS, //eT_TechniqueCustomRender
|
|
TTYPE_EFFECTLAYER, //eT_TechniqueEffectLayer
|
|
TTYPE_DEBUG, //eT_TechniqueDebug
|
|
TTYPE_SOFTALPHATESTPASS, //eT_TechniqueSoftAlphaTest
|
|
TTYPE_WATERREFLPASS, //eT_TechniqueWaterRefl
|
|
TTYPE_WATERCAUSTICPASS, //eT_TechniqueWaterCaustic
|
|
TTYPE_ZPREPASS, //eT_TechniqueZPrepass
|
|
TTYPE_PARTICLESTHICKNESSPASS //eT_TechniqueThickness
|
|
};
|
|
|
|
const CCryNameR pszNameTech = Parser.GetNameString(Parser.m_Data);
|
|
int idx = techParams.size() - 1;
|
|
CRY_ASSERT(idx >= 0);
|
|
CRY_ASSERT(eT - eT_TechniqueZ >= 0);
|
|
techParams[idx].techName[ pTechTable[eT - eT_TechniqueZ] ] = pszNameTech;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
CRY_ASSERT(0);
|
|
}
|
|
}
|
|
|
|
Parser.EndFrame(OldFrame);
|
|
|
|
return bRes;
|
|
}
|
|
|
|
bool CShaderManBin::ParseBinFX_Technique_Annotations(CParserBin& Parser, SParserFrame& Frame, SShaderTechnique* pShTech, std::vector<SShaderTechParseParams>& techParams, bool* bPublic)
|
|
{
|
|
SParserFrame OldFrame = Parser.BeginFrame(Frame);
|
|
|
|
FX_BEGIN_TOKENS
|
|
FX_TOKEN(string)
|
|
FX_END_TOKENS
|
|
|
|
bool bRes = true;
|
|
int nIndex;
|
|
|
|
while (Parser.ParseObject(sCommands, nIndex))
|
|
{
|
|
EToken eT = Parser.GetToken();
|
|
switch (eT)
|
|
{
|
|
case eT_string:
|
|
{
|
|
eT = Parser.GetToken(Parser.m_Name);
|
|
CRY_ASSERT(eT == eT_Script);
|
|
bRes &= ParseBinFX_Technique_Annotations_String(Parser, Parser.m_Data, pShTech, techParams, bPublic);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
CRY_ASSERT(0);
|
|
}
|
|
}
|
|
|
|
Parser.EndFrame(OldFrame);
|
|
|
|
return bRes;
|
|
}
|
|
|
|
bool CShaderManBin::ParseBinFX_Technique_CustomRE(CParserBin& Parser, SParserFrame& Frame, SParserFrame& Name, SShaderTechnique* pShTech)
|
|
{
|
|
uint32 nName = Parser.GetToken(Name);
|
|
|
|
if (nName == eT_LensOptics)
|
|
{
|
|
CRELensOptics* ps = new CRELensOptics;
|
|
if (ps->mfCompile(Parser, Frame))
|
|
{
|
|
pShTech->m_REs.AddElem(ps);
|
|
pShTech->m_Flags |= FHF_RE_LENSOPTICS;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
delete ps;
|
|
}
|
|
}
|
|
#if 0
|
|
else
|
|
if (nName == eT_Cloud)
|
|
{
|
|
CRECloud* ps = new CRECloud;
|
|
if (ps->mfCompile(Parser, Frame))
|
|
{
|
|
pShTech->m_REs.AddElem(ps);
|
|
pShTech->m_Flags |= FHF_RE_CLOUD;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
delete ps;
|
|
}
|
|
}
|
|
#endif
|
|
else
|
|
if (nName == eT_Beam)
|
|
{
|
|
CREBeam* ps = new CREBeam;
|
|
if (ps->mfCompile(Parser, Frame))
|
|
{
|
|
pShTech->m_REs.AddElem(ps);
|
|
}
|
|
else
|
|
{
|
|
delete ps;
|
|
}
|
|
}
|
|
else
|
|
if (nName == eT_Ocean)
|
|
{
|
|
CRY_ASSERT(0);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
SShaderTechnique* CShaderManBin::ParseBinFX_Technique(CParserBin& Parser, SParserFrame& Frame, SParserFrame Annotations, std::vector<SShaderTechParseParams>& techParams, bool* bPublic)
|
|
{
|
|
LOADING_TIME_PROFILE_SECTION(iSystem);
|
|
|
|
SParserFrame OldFrame = Parser.BeginFrame(Frame);
|
|
|
|
FX_BEGIN_TOKENS
|
|
FX_TOKEN(pass)
|
|
FX_TOKEN(CustomRE)
|
|
FX_TOKEN(Style)
|
|
FX_END_TOKENS
|
|
|
|
bool bRes = true;
|
|
SShaderTechnique* pShTech = NULL;
|
|
if (Parser.m_pCurShader)
|
|
{
|
|
pShTech = new SShaderTechnique(Parser.m_pCurShader);
|
|
}
|
|
|
|
if (Parser.m_pCurShader)
|
|
{
|
|
SShaderTechParseParams ps;
|
|
techParams.push_back(ps);
|
|
}
|
|
|
|
if (!Annotations.IsEmpty())
|
|
{
|
|
ParseBinFX_Technique_Annotations(Parser, Annotations, pShTech, techParams, bPublic);
|
|
}
|
|
|
|
while (Parser.ParseObject(sCommands))
|
|
{
|
|
EToken eT = Parser.GetToken();
|
|
switch (eT)
|
|
{
|
|
case eT_pass:
|
|
if (pShTech)
|
|
{
|
|
bRes &= ParseBinFX_Technique_Pass(Parser, Parser.m_Data, pShTech);
|
|
}
|
|
break;
|
|
|
|
case eT_Style:
|
|
if (pShTech)
|
|
{
|
|
ParseBinFX_LightStyle(Parser, Parser.m_Data, Parser.GetInt(Parser.GetToken(Parser.m_Name)));
|
|
}
|
|
break;
|
|
|
|
case eT_CustomRE:
|
|
if (pShTech)
|
|
{
|
|
bRes &= ParseBinFX_Technique_CustomRE(Parser, Parser.m_Data, Parser.m_Name, pShTech);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
CRY_ASSERT(0);
|
|
}
|
|
}
|
|
|
|
if (bRes)
|
|
{
|
|
if (Parser.m_pCurShader && pShTech)
|
|
{
|
|
Parser.m_pCurShader->m_HWTechniques.AddElem(pShTech);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
techParams.pop_back();
|
|
}
|
|
|
|
Parser.EndFrame(OldFrame);
|
|
|
|
return pShTech;
|
|
}
|
|
|
|
float g_fTimeA;
|
|
|
|
bool CShaderManBin::ParseBinFX(SShaderBin* pBin, CShader* ef, uint64 nMaskGen)
|
|
{
|
|
LOADING_TIME_PROFILE_SECTION_ARGS(pBin->m_szName);
|
|
|
|
bool bRes = true;
|
|
|
|
float fTimeA = iTimer->GetAsyncCurTime();
|
|
|
|
#if !defined(SHADER_NO_SOURCES)
|
|
CParserBin Parser(pBin, ef);
|
|
|
|
CShader* efGen = ef->m_pGenShader;
|
|
|
|
if (efGen && efGen->m_ShaderGenParams)
|
|
{
|
|
AddGenMacroses(efGen->m_ShaderGenParams, Parser, nMaskGen);
|
|
}
|
|
|
|
if (ef->m_ShaderGenStaticParams)
|
|
{
|
|
// Just add the defines and not the masks because they could clash with the gen params masks.
|
|
AddGenMacroses(ef->m_ShaderGenStaticParams, Parser, ef->m_maskGenStatic, true);
|
|
}
|
|
|
|
pBin->Lock();
|
|
Parser.Preprocess(0, pBin->m_Tokens, &pBin->m_TokenTable);
|
|
ef->m_CRC32 = pBin->m_CRC32;
|
|
ef->m_SourceCRC32 = pBin->m_SourceCRC32;
|
|
pBin->Unlock();
|
|
#endif
|
|
|
|
#if defined(SHADER_NO_SOURCES)
|
|
iLog->LogError("ERROR: Couldn't find binary shader '%s' (0x%x)", ef->GetName(), ef->m_nMaskGenFX);
|
|
return false;
|
|
#else
|
|
SParserFrame Frame(0, (Parser.m_Tokens.size() > 0 ? Parser.m_Tokens.size() - 1 : 0));
|
|
Parser.BeginFrame(Frame);
|
|
|
|
FX_BEGIN_TOKENS
|
|
FX_TOKEN(static)
|
|
FX_TOKEN(half)
|
|
FX_TOKEN(half2)
|
|
FX_TOKEN(half3)
|
|
FX_TOKEN(half4)
|
|
FX_TOKEN(half2x4)
|
|
FX_TOKEN(half3x4)
|
|
FX_TOKEN(half4x4)
|
|
FX_TOKEN(float)
|
|
FX_TOKEN(float2)
|
|
FX_TOKEN(float3)
|
|
FX_TOKEN(float4)
|
|
FX_TOKEN(float2x4)
|
|
FX_TOKEN(float3x4)
|
|
FX_TOKEN(float4x4)
|
|
FX_TOKEN(bool)
|
|
FX_TOKEN(int)
|
|
FX_TOKEN(struct)
|
|
FX_TOKEN(sampler1D)
|
|
FX_TOKEN(sampler2D)
|
|
FX_TOKEN(sampler3D)
|
|
FX_TOKEN(samplerCUBE)
|
|
FX_TOKEN(Texture2D)
|
|
FX_TOKEN(RWTexture2D)
|
|
FX_TOKEN(RWTexture2DArray)
|
|
FX_TOKEN(Texture2DArray)
|
|
FX_TOKEN(Texture2DMS)
|
|
FX_TOKEN(TextureCube)
|
|
FX_TOKEN(TextureCubeArray)
|
|
FX_TOKEN(Texture3D)
|
|
FX_TOKEN(RWTexture3D)
|
|
FX_TOKEN(technique)
|
|
FX_TOKEN(SamplerState)
|
|
FX_TOKEN(SamplerComparisonState)
|
|
FX_TOKEN(Buffer)
|
|
FX_TOKEN(RWBuffer)
|
|
FX_TOKEN(StructuredBuffer)
|
|
FX_TOKEN(RWStructuredBuffer)
|
|
FX_TOKEN(ByteAddressBuffer)
|
|
FX_TOKEN(RWByteAddressBuffer)
|
|
FX_TOKEN(cbuffer)
|
|
FX_TOKEN(RasterizerOrderedBuffer)
|
|
FX_TOKEN(RasterizerOrderedByteAddressBuffer)
|
|
FX_TOKEN(RasterizerOrderedStructuredBuffer)
|
|
FX_END_TOKENS
|
|
|
|
std::vector<SShaderTechParseParams> techParams;
|
|
CCryNameR techStart[2];
|
|
|
|
// From MemReplay analysis of shader params, 200 should be more than enough space
|
|
static decltype(SShaderFXParams::m_FXParams) s_tempFXParams;
|
|
s_tempFXParams.reserve(200);
|
|
s_tempFXParams.clear();
|
|
|
|
SShaderFXParams& FXP = mfGetFXParams(Parser.m_pCurShader);
|
|
FXP.m_FXParams.swap(s_tempFXParams);
|
|
|
|
ef->mfFree();
|
|
|
|
assert (ef->m_HWTechniques.Num() == 0);
|
|
int nInd = 0;
|
|
|
|
ETokenStorageClass nTokenStorageClass;
|
|
while (nTokenStorageClass = Parser.ParseObject(sCommands))
|
|
{
|
|
EToken eT = Parser.GetToken();
|
|
SCodeFragment Fr;
|
|
SFXParam P;
|
|
string szR;
|
|
switch (eT)
|
|
{
|
|
case eT_struct:
|
|
case eT_cbuffer:
|
|
Fr.m_nFirstToken = Parser.FirstToken();
|
|
Fr.m_nLastToken = Parser.m_CurFrame.m_nCurToken - 1;
|
|
Fr.m_dwName = Parser.m_Tokens[Fr.m_nFirstToken + 1];
|
|
#ifdef _DEBUG
|
|
//Fr.m_Name = Parser.GetString(Fr.m_dwName);
|
|
#endif
|
|
Fr.m_eType = (eT == eT_cbuffer) ? eFT_ConstBuffer : eFT_Structure;
|
|
Parser.m_CodeFragments.push_back(Fr);
|
|
break;
|
|
|
|
case eT_SamplerState:
|
|
case eT_SamplerComparisonState:
|
|
{
|
|
SFXSampler Pr;
|
|
Parser.CopyTokens(Parser.m_Name, Pr.m_dwName);
|
|
#ifdef _DEBUG
|
|
const char* sampName = Parser.GetString(Parser.m_Name);
|
|
#endif
|
|
if (eT == eT_SamplerState)
|
|
{
|
|
Pr.m_eType = eSType_Sampler;
|
|
}
|
|
else
|
|
if (eT == eT_SamplerComparisonState)
|
|
{
|
|
Pr.m_eType = eSType_SamplerComp;
|
|
}
|
|
else
|
|
{
|
|
CRY_ASSERT(0);
|
|
}
|
|
|
|
uint32 nTokAssign = 0;
|
|
if (Parser.m_Assign.IsEmpty() && !Parser.m_Value.IsEmpty())
|
|
{
|
|
nTokAssign = Parser.m_Tokens[Parser.m_Value.m_nFirstToken];
|
|
if (nTokAssign == eT_br_cv_1)
|
|
{
|
|
nTokAssign = Parser.m_Tokens[Parser.m_Value.m_nFirstToken + 1];
|
|
}
|
|
}
|
|
else
|
|
if (!Parser.m_Assign.IsEmpty())
|
|
{
|
|
nTokAssign = Parser.m_Tokens[Parser.m_Assign.m_nFirstToken];
|
|
}
|
|
if (nTokAssign)
|
|
{
|
|
const char* assign = Parser.GetString(nTokAssign);
|
|
int nnn = 0;
|
|
}
|
|
Pr.PostLoad(Parser, Parser.m_Name, Parser.m_Annotations, Parser.m_Value, Parser.m_Assign);
|
|
|
|
bRes &= ParseBinFX_Sampler(Parser, Parser.m_Data, Pr);
|
|
|
|
mfAddFXSampler(Parser.m_pCurShader, &Pr);
|
|
}
|
|
break;
|
|
|
|
case eT_Texture2D:
|
|
case eT_Texture2DMS:
|
|
case eT_Texture2DArray:
|
|
case eT_TextureCube:
|
|
case eT_TextureCubeArray:
|
|
case eT_Texture3D:
|
|
{
|
|
SFXTexture Pr;
|
|
Parser.CopyTokens(Parser.m_Name, Pr.m_dwName);
|
|
|
|
if (eT == eT_Texture2D)
|
|
{
|
|
Pr.m_eType = eTT_2D;
|
|
}
|
|
else
|
|
if (eT == eT_Texture2DMS)
|
|
{
|
|
Pr.m_eType = eTT_2DMS;
|
|
}
|
|
else
|
|
if (eT == eT_Texture2DArray)
|
|
{
|
|
Pr.m_eType = eTT_2DArray;
|
|
}
|
|
else
|
|
if (eT == eT_Texture3D)
|
|
{
|
|
Pr.m_eType = eTT_3D;
|
|
}
|
|
else
|
|
if (eT == eT_TextureCube)
|
|
{
|
|
Pr.m_eType = eTT_Cube;
|
|
}
|
|
else
|
|
if (eT == eT_TextureCubeArray)
|
|
{
|
|
Pr.m_eType = eTT_CubeArray;
|
|
}
|
|
else
|
|
{
|
|
CRY_ASSERT(0);
|
|
}
|
|
|
|
Pr.PostLoad(Parser, Parser.m_Name, Parser.m_Annotations, Parser.m_Value, Parser.m_Assign);
|
|
|
|
bRes &= ParseBinFX_Texture(Parser, Parser.m_Data, Pr);
|
|
bRes &= ParseBinFX_Texture(Parser, Parser.m_Annotations, Pr);
|
|
|
|
// Texture2D something = TS_identifiersearch;
|
|
if (!azstrnicmp(Pr.m_Values.c_str(), "TM_", 3) ||
|
|
!azstrnicmp(Pr.m_Values.c_str(), "TS_", 3) ||
|
|
!azstrnicmp(Pr.m_Values.c_str(), "TP_", 3))
|
|
{
|
|
Pr.m_Semantic = Pr.m_Values;
|
|
Pr.m_szTexture = "";
|
|
Pr.m_Values = "";
|
|
}
|
|
|
|
// Texture2D something = "filepathsearch";
|
|
// Texture2D something = $databasesearch;
|
|
if (Pr.m_Values.c_str()[0])
|
|
{
|
|
Pr.m_Semantic = "";
|
|
Pr.m_szTexture = Pr.m_Values.c_str();
|
|
Pr.m_Values = "";
|
|
}
|
|
|
|
mfAddFXTexture(Parser.m_pCurShader, &Pr);
|
|
}
|
|
break;
|
|
|
|
case eT_int:
|
|
case eT_bool:
|
|
case eT_half:
|
|
case eT_half2:
|
|
case eT_half3:
|
|
case eT_half4:
|
|
case eT_half2x4:
|
|
case eT_half3x4:
|
|
case eT_half4x4:
|
|
case eT_float:
|
|
case eT_float2:
|
|
case eT_float3:
|
|
case eT_float4:
|
|
case eT_float2x4:
|
|
case eT_float3x4:
|
|
case eT_float4x4:
|
|
{
|
|
SFXParam Pr;
|
|
Parser.CopyTokens(Parser.m_Name, Pr.m_dwName);
|
|
|
|
if (eT == eT_float2x4 || eT == eT_half2x4)
|
|
{
|
|
Pr.m_RegisterCount = 2;
|
|
}
|
|
else
|
|
if (eT == eT_float3x4 || eT == eT_half3x4)
|
|
{
|
|
Pr.m_RegisterCount = 3;
|
|
}
|
|
else
|
|
if (eT == eT_float4x4 || eT == eT_half4x4)
|
|
{
|
|
Pr.m_RegisterCount = 4;
|
|
}
|
|
else
|
|
{
|
|
Pr.m_RegisterCount = 1;
|
|
}
|
|
|
|
if (eT == eT_float || eT == eT_half || eT == eT_int || eT == eT_bool)
|
|
{
|
|
Pr.m_ComponentCount = 1;
|
|
}
|
|
else
|
|
if (eT == eT_float2 || eT == eT_half2)
|
|
{
|
|
Pr.m_ComponentCount = 2;
|
|
}
|
|
else
|
|
if (eT == eT_float3 || eT == eT_half3)
|
|
{
|
|
Pr.m_ComponentCount = 3;
|
|
}
|
|
else
|
|
if (eT == eT_float4 || eT == eT_float2x4 || eT == eT_float3x4 || eT == eT_float4x4 ||
|
|
eT == eT_half4 || eT == eT_half2x4 || eT == eT_half3x4 || eT == eT_half4x4)
|
|
{
|
|
Pr.m_ComponentCount = 4;
|
|
}
|
|
|
|
if (eT == eT_int)
|
|
{
|
|
Pr.m_eType = eType_INT;
|
|
}
|
|
else
|
|
if (eT == eT_bool)
|
|
{
|
|
Pr.m_eType = eType_BOOL;
|
|
}
|
|
else
|
|
if (eT >= eT_half && eT <= eT_half3x3)
|
|
{
|
|
Pr.m_eType = eType_HALF;
|
|
}
|
|
else
|
|
{
|
|
Pr.m_eType = eType_FLOAT;
|
|
}
|
|
|
|
if (!Parser.m_Assign.IsEmpty() && Parser.GetToken(Parser.m_Assign) == eT_STANDARDSGLOBAL)
|
|
{
|
|
ParseBinFX_Global(Parser, Parser.m_Annotations, NULL, techStart);
|
|
}
|
|
else
|
|
{
|
|
uint32 nTokAssign = 0;
|
|
if (Parser.m_Assign.IsEmpty() && !Parser.m_Value.IsEmpty())
|
|
{
|
|
nTokAssign = Parser.m_Tokens[Parser.m_Value.m_nFirstToken];
|
|
if (nTokAssign == eT_br_cv_1)
|
|
{
|
|
nTokAssign = Parser.m_Tokens[Parser.m_Value.m_nFirstToken + 1];
|
|
}
|
|
}
|
|
else
|
|
if (!Parser.m_Assign.IsEmpty())
|
|
{
|
|
nTokAssign = Parser.m_Tokens[Parser.m_Assign.m_nFirstToken];
|
|
}
|
|
if (nTokAssign)
|
|
{
|
|
const char* assign = Parser.GetString(nTokAssign);
|
|
if (!assign[0] || !_strnicmp(assign, "PB_", 3))
|
|
{
|
|
Pr.m_BindingSlot = eConstantBufferShaderSlot_PerBatch;
|
|
}
|
|
else
|
|
if (!_strnicmp(assign, "PI_", 3) || !_strnicmp(assign, "SI_", 3))
|
|
{
|
|
Pr.m_BindingSlot = eConstantBufferShaderSlot_PerInstanceLegacy;
|
|
}
|
|
else
|
|
if (!_strnicmp(assign, "PM_", 3))
|
|
{
|
|
Pr.m_BindingSlot = eConstantBufferShaderSlot_PerMaterial;
|
|
}
|
|
else
|
|
if (!_strnicmp(assign, "register", 8))
|
|
{
|
|
Pr.m_BindingSlot = eConstantBufferShaderSlot_PerBatch;
|
|
}
|
|
else
|
|
{
|
|
Pr.m_BindingSlot = eConstantBufferShaderSlot_PerBatch;
|
|
}
|
|
}
|
|
else
|
|
if (CParserBin::m_nPlatform & (SF_D3D11 | SF_ORBIS | SF_JASPER | SF_GL4 | SF_GLES3 | SF_METAL))
|
|
{
|
|
uint32 nTokName = Parser.GetToken(Parser.m_Name);
|
|
const char* name = Parser.GetString(nTokName);
|
|
if (!strncmp(name, "PI_", 3))
|
|
{
|
|
Pr.m_BindingSlot = eConstantBufferShaderSlot_PerInstanceLegacy;
|
|
}
|
|
else
|
|
{
|
|
Pr.m_BindingSlot = eConstantBufferShaderSlot_PerBatch;
|
|
}
|
|
}
|
|
|
|
Pr.PostLoad(Parser, Parser.m_Name, Parser.m_Annotations, Parser.m_Value, Parser.m_Assign);
|
|
|
|
EParamType eType;
|
|
string szReg = Pr.GetValueForName("register", eType);
|
|
if (!szReg.empty())
|
|
{
|
|
CRY_ASSERT(szReg[0] == 'c');
|
|
Pr.m_Register[eHWSC_Vertex] = atoi(&szReg[1]);
|
|
Pr.m_Register[eHWSC_Pixel] = Pr.m_Register[eHWSC_Vertex];
|
|
|
|
if (CParserBin::PlatformSupportsGeometryShaders())
|
|
{
|
|
Pr.m_Register[eHWSC_Geometry] = Pr.m_Register[eHWSC_Vertex];
|
|
}
|
|
if (CParserBin::PlatformSupportsDomainShaders())
|
|
{
|
|
Pr.m_Register[eHWSC_Domain] = Pr.m_Register[eHWSC_Vertex];
|
|
}
|
|
}
|
|
uint32 prFlags = Pr.GetFlags();
|
|
if (prFlags & PF_TWEAKABLE_MASK)
|
|
{
|
|
Pr.m_BindingSlot = eConstantBufferShaderSlot_PerMaterial;
|
|
CRY_ASSERT(prFlags & PF_CUSTOM_BINDED);
|
|
}
|
|
mfAddFXParam(Parser.m_pCurShader, &Pr);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case eT_sampler1D:
|
|
case eT_sampler2D:
|
|
case eT_sampler3D:
|
|
case eT_samplerCUBE:
|
|
{
|
|
Fr.m_nFirstToken = Parser.FirstToken();
|
|
|
|
uint32 nTokenOffset = 1;
|
|
|
|
// For DX11 style texture definitions, need to parse out templated type. Also unlike HLSL we *require* it.
|
|
if (eT == eT_Texture2DMS || eT == eT_Texture2D || eT == eT_Texture2DArray || eT == eT_TextureCube || eT == eT_TextureCubeArray || eT == eT_Texture3D)
|
|
{
|
|
// Texture2DMS is particular case, requires (at minimum) type to be specified - parse Texture2DMS<type> tokens
|
|
// Texture2D for typeless resources, is also a particular case, type has to explicitly be specified - parse Texture2D<type> tokens
|
|
nTokenOffset = 4;
|
|
|
|
if (Parser.m_Tokens[Fr.m_nFirstToken + 1] != eT_br_tr_1 || // <
|
|
Parser.m_Tokens[Fr.m_nFirstToken + 3] != eT_br_tr_2) // >
|
|
{
|
|
// Parser.m_Tokens[Fr.m_nFirstToken + 2] is the templated type, e.g. float4
|
|
CryWarning(VALIDATOR_MODULE_RENDERER, VALIDATOR_ERROR_DBGBRK, "[SHADERS] FAILED TO PARSE '%s': Invalid Texture definition without templated type:", ef->GetName());
|
|
CryWarning(VALIDATOR_MODULE_RENDERER, VALIDATOR_ERROR_DBGBRK, "[SHADERS] %s %s %s %s"
|
|
, Parser.GetString(Parser.m_Tokens[Fr.m_nFirstToken])
|
|
, Parser.GetString(Parser.m_Tokens[Fr.m_nFirstToken + 1])
|
|
, Parser.GetString(Parser.m_Tokens[Fr.m_nFirstToken + 2])
|
|
, Parser.GetString(Parser.m_Tokens[Fr.m_nFirstToken + 3])
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
|
|
Fr.m_nLastToken = Fr.m_nFirstToken + nTokenOffset;
|
|
if (!Parser.m_Assign.IsEmpty())
|
|
{
|
|
Fr.m_nLastToken = Parser.m_Assign.m_nLastToken;
|
|
}
|
|
Fr.m_dwName = Parser.m_Tokens[Fr.m_nFirstToken + nTokenOffset];
|
|
Fr.m_eType = eFT_Sampler;
|
|
Parser.m_CodeFragments.push_back(Fr);
|
|
|
|
//// handy for debugging - do not remove plz
|
|
//const char *pszToken0 = Parser.GetString( Parser.m_Tokens[Fr.m_nFirstToken] );
|
|
//const char *pszToken1 = Parser.GetString( Parser.m_Tokens[Fr.m_nFirstToken+1] );
|
|
//const char *pszToken2 = Parser.GetString( Parser.m_Tokens[Fr.m_nFirstToken+2] );
|
|
|
|
bRes &= ParseBinFX_Sampler(Parser, Parser.m_Data, Fr.m_dwName, Parser.m_Annotations, eT);
|
|
}
|
|
break;
|
|
|
|
case eT_Buffer:
|
|
case eT_RWBuffer:
|
|
case eT_StructuredBuffer:
|
|
case eT_RWStructuredBuffer:
|
|
case eT_ByteAddressBuffer:
|
|
case eT_RWByteAddressBuffer:
|
|
case eT_RWTexture2D:
|
|
case eT_RWTexture2DArray:
|
|
case eT_RWTexture3D:
|
|
case eT_RasterizerOrderedBuffer:
|
|
case eT_RasterizerOrderedByteAddressBuffer:
|
|
case eT_RasterizerOrderedStructuredBuffer:
|
|
{
|
|
Fr.m_nFirstToken = Parser.FirstToken();
|
|
Fr.m_nLastToken = Fr.m_nFirstToken + 1;
|
|
if (!Parser.m_Assign.IsEmpty())
|
|
{
|
|
Fr.m_nLastToken = Parser.m_Assign.m_nLastToken + 1;
|
|
}
|
|
Fr.m_dwName = Parser.m_Tokens[Parser.m_Name.m_nFirstToken];
|
|
Fr.m_eType = eFT_Structure;
|
|
Parser.m_CodeFragments.push_back(Fr);
|
|
}
|
|
break;
|
|
|
|
case eT_technique:
|
|
{
|
|
uint32 nToken = Parser.m_Tokens[Parser.m_Name.m_nFirstToken];
|
|
const char* szName = Parser.GetString(nToken);
|
|
SShaderTechnique* pShTech = ParseBinFX_Technique(Parser, Parser.m_Data, Parser.m_Annotations, techParams, NULL);
|
|
if (szName)
|
|
{
|
|
pShTech->m_NameStr = szName;
|
|
pShTech->m_NameCRC = szName;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
//CRY_ASSERT(0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
FXP.m_FXParams.swap(s_tempFXParams);
|
|
FXP.m_FXParams.reserve(FXP.m_FXParams.size() + s_tempFXParams.size());
|
|
FXP.m_FXParams.insert(FXP.m_FXParams.end(), s_tempFXParams.begin(), s_tempFXParams.end());
|
|
|
|
m_pCEF->mfPostLoadFX(ef, techParams, techStart);
|
|
|
|
#if SHADER_REFLECT_TEXTURE_SLOTS
|
|
for (uint32 i = 0; i < min((uint32)TTYPE_MAX, ef->m_HWTechniques.size()); i++)
|
|
{
|
|
if (!ef->GetUsedTextureSlots(i))
|
|
{
|
|
ef->m_ShaderTexSlots[i] = GetTextureSlots(Parser, pBin, ef, i, -1);
|
|
}
|
|
}
|
|
|
|
for (uint32 i = 0; i < min((uint32)TTYPE_MAX, ef->m_HWTechniques.size()); i++)
|
|
{
|
|
if (ef->m_ShaderTexSlots[i])
|
|
{
|
|
SShaderTechParseParams* linkedTechs = &techParams[i];
|
|
|
|
// look through linked techniques (e.g. general has links to zpass, shadowgen, etc)
|
|
for (int j = 0; j < TTYPE_MAX; j++)
|
|
{
|
|
// if we have a linked technique
|
|
if (!linkedTechs->techName[j].empty())
|
|
{
|
|
// find it in our technique list
|
|
for (int k = 0; k < ef->m_HWTechniques.size(); k++)
|
|
{
|
|
if (linkedTechs->techName[j] == ef->m_HWTechniques[k]->m_NameStr)
|
|
{
|
|
// merge slots - any slots that are empty in the master will be filled with the overlay
|
|
// This leaves the general/main technique authoratitve on slots, but stops slots disappearing
|
|
// if they're still used in some sub-pass
|
|
MergeTextureSlots(ef->m_ShaderTexSlots[i], ef->m_ShaderTexSlots[k]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
g_fTimeA += iTimer->GetAsyncCurTime() - fTimeA;
|
|
|
|
return bRes;
|
|
#endif
|
|
}
|
|
|
|
void CShaderManBin::MergeTextureSlots(SShaderTexSlots* master, SShaderTexSlots* overlay)
|
|
{
|
|
if (!master || !overlay)
|
|
{
|
|
return;
|
|
}
|
|
/* [Shader System] - TO DO: switch back to the map usage and replace with this
|
|
for (auto& iter : overlay->m_UsedTextureSlots)
|
|
{
|
|
auto masterIter = master->m_UsedTextureSlots.find(iter->first);
|
|
if (masterIter == master->m_UsedTextureSlots.end()) // slot was not found - insert the overlay one
|
|
{
|
|
// these structures are never deleted so we can safely share pointers
|
|
// without ref counting. See below in GetTextureSlots for the allocation
|
|
master->m_UsedTextureSlots[iter->first] = iter->second;
|
|
}
|
|
}
|
|
*/
|
|
// [Shader System] - TO DO - replace this part with code above after testing
|
|
for (int i = 0; i < EFTT_MAX; i++)
|
|
{
|
|
// these structures are never deleted so we can safely share pointers
|
|
// without ref counting. See below in GetTextureSlots for the allocation
|
|
if (master->m_UsedTextureSlots[i] == NULL && overlay->m_UsedTextureSlots[i] != NULL)
|
|
{
|
|
master->m_UsedTextureSlots[i] = overlay->m_UsedTextureSlots[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
// [Shader System TO DO] - this methods needs to be either removed or become full data driven
|
|
SShaderTexSlots* CShaderManBin::GetTextureSlots([[maybe_unused]] CParserBin& Parser, [[maybe_unused]] SShaderBin* pBin, [[maybe_unused]] CShader* ef, [[maybe_unused]] int nTech, int nPass)
|
|
{
|
|
#if !SHADER_REFLECT_TEXTURE_SLOTS
|
|
return NULL;
|
|
#else
|
|
TArray<uint32> referencedSamplers;
|
|
|
|
bool bIterPasses = false;
|
|
int nMaxPasses = 1;
|
|
|
|
if (nPass == -1)
|
|
{
|
|
bIterPasses = true;
|
|
nPass = 0;
|
|
}
|
|
|
|
if (nTech < 0 || nPass < 0)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// if the technique's pixel shader exists
|
|
if (ef->m_HWTechniques.size() && nTech < ef->m_HWTechniques.size() &&
|
|
ef->m_HWTechniques[nTech]->m_Passes.size() && nPass < ef->m_HWTechniques[nTech]->m_Passes.size() &&
|
|
ef->m_HWTechniques[nTech]->m_Passes[nPass].m_PShader)
|
|
{
|
|
if (bIterPasses)
|
|
{
|
|
nMaxPasses = ef->m_HWTechniques[nTech]->m_Passes.size();
|
|
}
|
|
|
|
for (int nPassIter = nPass; nPassIter < nMaxPasses; nPassIter++)
|
|
{
|
|
uint32 dwEntryFuncName = Parser.GetCRC32(ef->m_HWTechniques[nTech]->m_Passes[nPassIter].m_PShader->m_EntryFunc);
|
|
|
|
// get the cached info for the entry func
|
|
SParamCacheInfo* pCache = GetParamInfo(pBin, dwEntryFuncName, ef->m_nMaskGenFX, ef->m_maskGenStatic);
|
|
|
|
if (pCache)
|
|
{
|
|
// loop over affected fragments from this entry func
|
|
SParamCacheInfo::AffectedFuncsVec& AffectedFragments = pCache->m_AffectedFuncs;
|
|
for (uint32 i = 0; i < AffectedFragments.size(); i++)
|
|
{
|
|
SCodeFragment* s = &Parser.m_CodeFragments[AffectedFragments[i]];
|
|
|
|
// if it's a sampler, include this sampler name CRC
|
|
if (s->m_eType == eFT_Sampler)
|
|
{
|
|
referencedSamplers.AddElem(s->m_dwName);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
uint32 dependencySlots = 0;
|
|
|
|
// check the gen params
|
|
SShaderGen* genParams = ef->GetGenerationParams();
|
|
if (genParams)
|
|
{
|
|
for (uint32 i = 0; i < genParams->m_BitMask.Num(); i++)
|
|
{
|
|
SShaderGenBit* pBit = genParams->m_BitMask[i];
|
|
if (!pBit || (!pBit->m_nDependencySet && !pBit->m_nDependencyReset))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// if any dependency set/reset is allowed for a texture, we must be conservative
|
|
// and count this slot as used
|
|
uint32 setReset = pBit->m_nDependencySet | pBit->m_nDependencyReset;
|
|
|
|
// bitmask will fail if we have > 32 fixed texture slots
|
|
CRY_ASSERT(EFTT_MAX <= 32);
|
|
|
|
if (setReset & SHGD_TEX_MASK)
|
|
{
|
|
if (setReset & SHGD_TEX_NORMALS)
|
|
{
|
|
dependencySlots |= 1 << EFTT_NORMALS;
|
|
}
|
|
|
|
if (setReset & SHGD_TEX_HEIGHT)
|
|
{
|
|
dependencySlots |= 1 << EFTT_HEIGHT;
|
|
}
|
|
|
|
if (setReset & SHGD_TEX_DETAIL)
|
|
{
|
|
dependencySlots |= 1 << EFTT_DETAIL_OVERLAY;
|
|
}
|
|
|
|
if (setReset & SHGD_TEX_SECOND_SMOOTHNESS)
|
|
{
|
|
dependencySlots |= 1 << EFTT_SECOND_SMOOTHNESS;
|
|
}
|
|
|
|
if (setReset & SHGD_TEX_SPECULAR)
|
|
{
|
|
dependencySlots |= 1 << EFTT_SPECULAR;
|
|
}
|
|
|
|
if (setReset & SHGD_TEX_ENVCM)
|
|
{
|
|
dependencySlots |= 1 << EFTT_ENV;
|
|
}
|
|
|
|
if (setReset & SHGD_TEX_SUBSURFACE)
|
|
{
|
|
dependencySlots |= 1 << EFTT_SUBSURFACE;
|
|
}
|
|
|
|
if (setReset & SHGD_TEX_DECAL)
|
|
{
|
|
dependencySlots |= 1 << EFTT_DECAL_OVERLAY;
|
|
}
|
|
|
|
if (setReset & SHGD_TEX_CUSTOM)
|
|
{
|
|
dependencySlots |= 1 << EFTT_CUSTOM;
|
|
}
|
|
|
|
if (setReset & SHGD_TEX_CUSTOM_SECONDARY)
|
|
{
|
|
dependencySlots |= 1 << EFTT_CUSTOM_SECONDARY;
|
|
}
|
|
|
|
if (setReset & SHGD_TEX_OCC)
|
|
{
|
|
dependencySlots |= 1 << EFTT_OCCLUSION;
|
|
}
|
|
|
|
if (setReset & SHGD_TEX_SPECULAR_2)
|
|
{
|
|
dependencySlots |= 1 << EFTT_SPECULAR_2;
|
|
}
|
|
|
|
if (setReset & SHGD_TEX_EMITTANCE)
|
|
{
|
|
// Both emittance and decal overlay (emissive intensity) are set by SHGD_TEX_EMITTANCE
|
|
dependencySlots |= 1 << EFTT_EMITTANCE;
|
|
dependencySlots |= 1 << EFTT_DECAL_OVERLAY;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// since we might find samplers referencing a slot more than once,
|
|
// keep track of the priority of each sampler found.
|
|
int namePriority[EFTT_MAX]; // [Shader System TO DO] - data driven please!
|
|
memset(namePriority, 0, sizeof(namePriority));
|
|
|
|
// deliberately 'leaking', these are kept around permanently (this info is only gathered in the editor),
|
|
// and cleaned up at shutdown when the app memory is released.
|
|
SShaderTexSlots* pSlots = new SShaderTexSlots;
|
|
|
|
// Priority order:
|
|
// 0 = forced in because of the dependency set as above, can be overridden if we find a better sampler
|
|
// 1 = referenced from the shader but doesn't include a UIName
|
|
// 2 = includes a UIName but isn't directly referenced. In the case we've forced the sampler because of dependency,
|
|
// this is probably more descriptive than a priority=1 sampler
|
|
// 3 = both from above, referenced and has UIName. We shouldn't find multiple samplers like this, shader samplers
|
|
// should be set up so only ever one sampler using a slot has a UIName.
|
|
enum
|
|
{
|
|
PRIORITY_REFERENCED = 0x1, PRIORITY_HASUINAME = 0x2
|
|
};
|
|
|
|
SShaderFXParams& FXP = mfGetFXParams(ef);
|
|
|
|
// loop over all samplers for this shader
|
|
FXSamplersOldIt it = FXP.m_FXSamplersOld.begin();
|
|
FXSamplersOldIt end = FXP.m_FXSamplersOld.end();
|
|
for (; it != end; ++it)
|
|
{
|
|
int slot = it->m_nSlotId;
|
|
|
|
// if the slot is invalid this texture refers something else, skip it
|
|
if (slot == EFTT_MAX) // [Shader System TO DO] - data driven
|
|
{
|
|
continue;
|
|
}
|
|
|
|
uint32 dwName = Parser.GetCRC32(it->m_szName);
|
|
|
|
// check if this sampler must be included for dependency set/reset reasons
|
|
bool dependency = (dependencySlots & (1 << slot)) > 0;
|
|
|
|
// check if this sampler is referenced from the shader
|
|
bool referenced = referencedSamplers.Find(dwName) >= 0;
|
|
|
|
if (dependency || referenced)
|
|
{
|
|
// calculate priority. See above.
|
|
int priority = (referenced ? PRIORITY_REFERENCED : 0) | (it->m_szUIName.length() ? PRIORITY_HASUINAME : 0);
|
|
SShaderTextureSlot* pUsedTexSlot = pSlots->m_UsedTextureSlots[slot];
|
|
|
|
// if we don't have this slot filled yet, create a new slot
|
|
if (!pUsedTexSlot)
|
|
{
|
|
// !!IMPORTANT!! - if these slots are deleted/cleaned instead of being allowed to live forever,
|
|
// MAKE SURE you refcount or refactor MergeTextureSlots above - as it will share pointers.
|
|
pUsedTexSlot = new SShaderTextureSlot;
|
|
|
|
pUsedTexSlot->m_Name = it->m_szUIName;
|
|
pUsedTexSlot->m_Description = it->m_szUIDescription;
|
|
pUsedTexSlot->m_TexType = it->m_eTexType;
|
|
|
|
// store current priority
|
|
namePriority[slot] = priority;
|
|
pSlots->m_UsedTextureSlots[slot] = pUsedTexSlot; // insertion to the map
|
|
}
|
|
else
|
|
{
|
|
// we shouldn't encounter two samplers that are used and have a UIName for the same slot,
|
|
// error in this case
|
|
if (priority == (PRIORITY_REFERENCED | PRIORITY_HASUINAME) && priority == namePriority[slot])
|
|
{
|
|
CryWarning(VALIDATOR_MODULE_RENDERER, VALIDATOR_ERROR, "Encountered two samplers with UINames referenced for same slot in shader '%s': '%s' and '%s'\n",
|
|
ef->GetName(), pUsedTexSlot->m_Name.c_str(), it->m_szUIName.c_str());
|
|
CRY_ASSERT(0);
|
|
}
|
|
// override if we have a higher priority
|
|
else if (priority > namePriority[slot])
|
|
{
|
|
pUsedTexSlot->m_Name = it->m_szUIName;
|
|
pUsedTexSlot->m_Description = it->m_szUIDescription;
|
|
pUsedTexSlot->m_TexType = it->m_eTexType;
|
|
|
|
namePriority[slot] = priority;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return pSlots;
|
|
#endif
|
|
}
|
|
|
|
bool CShaderManBin::ParseBinFX_Dummy(SShaderBin* pBin, std::vector<string>& ShaderNames, const char* szName)
|
|
{
|
|
bool bRes = true;
|
|
CParserBin Parser(pBin, NULL);
|
|
|
|
pBin->Lock();
|
|
bool preprocessResult = Parser.Preprocess(0, pBin->m_Tokens, &pBin->m_TokenTable);
|
|
pBin->Unlock();
|
|
|
|
if(!preprocessResult)
|
|
{
|
|
// Preprocess already outputs an error, no need to do so here.
|
|
return false;
|
|
}
|
|
|
|
SParserFrame Frame(0, Parser.m_Tokens.size() - 1);
|
|
Parser.BeginFrame(Frame);
|
|
|
|
FX_BEGIN_TOKENS
|
|
FX_TOKEN(static)
|
|
FX_TOKEN(half)
|
|
FX_TOKEN(half2)
|
|
FX_TOKEN(half3)
|
|
FX_TOKEN(half4)
|
|
FX_TOKEN(half2x4)
|
|
FX_TOKEN(half3x4)
|
|
FX_TOKEN(half4x4)
|
|
FX_TOKEN(float)
|
|
FX_TOKEN(float2)
|
|
FX_TOKEN(float3)
|
|
FX_TOKEN(float4)
|
|
FX_TOKEN(float2x4)
|
|
FX_TOKEN(float3x4)
|
|
FX_TOKEN(float4x4)
|
|
FX_TOKEN(bool)
|
|
FX_TOKEN(int)
|
|
FX_TOKEN(Buffer)
|
|
FX_TOKEN(RWBuffer)
|
|
FX_TOKEN(StructuredBuffer)
|
|
FX_TOKEN(RWStructuredBuffer)
|
|
FX_TOKEN(cbuffer)
|
|
FX_TOKEN(struct)
|
|
FX_TOKEN(sampler1D)
|
|
FX_TOKEN(sampler2D)
|
|
FX_TOKEN(sampler3D)
|
|
FX_TOKEN(samplerCUBE)
|
|
FX_TOKEN(technique)
|
|
FX_TOKEN(SamplerState)
|
|
FX_TOKEN(SamplerComparisonState)
|
|
FX_TOKEN(Texture2D)
|
|
FX_TOKEN(RWTexture2D)
|
|
FX_TOKEN(RWTexture2DArray)
|
|
FX_TOKEN(Texture2DArray)
|
|
FX_TOKEN(Texture2DMS)
|
|
FX_TOKEN(TextureCube)
|
|
FX_TOKEN(TextureCubeArray)
|
|
FX_TOKEN(Texture3D)
|
|
FX_TOKEN(RWTexture3D)
|
|
FX_TOKEN(RasterizerOrderedBuffer)
|
|
FX_TOKEN(RasterizerOrderedByteAddressBuffer)
|
|
FX_TOKEN(RasterizerOrderedStructuredBuffer)
|
|
FX_END_TOKENS
|
|
|
|
std::vector<SShaderTechParseParams> techParams;
|
|
CCryNameR techStart[2];
|
|
bool bPublic = false;
|
|
std::vector<string> PubTechniques;
|
|
|
|
ETokenStorageClass nTokenStorageClass;
|
|
|
|
while (nTokenStorageClass = Parser.ParseObject(sCommands))
|
|
{
|
|
EToken eT = Parser.GetToken();
|
|
SCodeFragment Fr;
|
|
switch (eT)
|
|
{
|
|
case eT_half:
|
|
case eT_float:
|
|
if (!Parser.m_Assign.IsEmpty() && Parser.GetToken(Parser.m_Assign) == eT_STANDARDSGLOBAL)
|
|
{
|
|
ParseBinFX_Global(Parser, Parser.m_Annotations, &bPublic, techStart);
|
|
}
|
|
break;
|
|
case eT_Buffer:
|
|
case eT_RWBuffer:
|
|
case eT_StructuredBuffer:
|
|
case eT_RWStructuredBuffer:
|
|
case eT_cbuffer:
|
|
case eT_struct:
|
|
case eT_SamplerState:
|
|
case eT_SamplerComparisonState:
|
|
case eT_int:
|
|
case eT_bool:
|
|
|
|
case eT_half2:
|
|
case eT_half3:
|
|
case eT_half4:
|
|
case eT_half2x4:
|
|
case eT_half3x4:
|
|
case eT_half4x4:
|
|
|
|
case eT_float2:
|
|
case eT_float3:
|
|
case eT_float4:
|
|
case eT_float2x4:
|
|
case eT_float3x4:
|
|
case eT_float4x4:
|
|
|
|
case eT_Texture2D:
|
|
case eT_RWTexture2D:
|
|
case eT_Texture2DMS:
|
|
case eT_Texture2DArray:
|
|
case eT_RWTexture2DArray:
|
|
case eT_TextureCube:
|
|
case eT_TextureCubeArray:
|
|
case eT_Texture3D:
|
|
case eT_RWTexture3D:
|
|
case eT_sampler1D:
|
|
case eT_sampler2D:
|
|
case eT_sampler3D:
|
|
case eT_samplerCUBE:
|
|
case eT_RasterizerOrderedBuffer:
|
|
case eT_RasterizerOrderedByteAddressBuffer:
|
|
case eT_RasterizerOrderedStructuredBuffer:
|
|
break;
|
|
|
|
case eT_technique:
|
|
{
|
|
uint32 nToken = Parser.m_Tokens[Parser.m_Name.m_nFirstToken];
|
|
bool bPublicTechnique = false;
|
|
SShaderTechnique* pShTech = ParseBinFX_Technique(Parser, Parser.m_Data, Parser.m_Annotations, techParams, &bPublicTechnique);
|
|
if (bPublicTechnique)
|
|
{
|
|
const char* name = Parser.GetString(nToken);
|
|
PubTechniques.push_back(name);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
CRY_ASSERT(0);
|
|
}
|
|
}
|
|
|
|
if (bPublic)
|
|
{
|
|
ShaderNames.push_back(szName);
|
|
}
|
|
if (PubTechniques.size())
|
|
{
|
|
uint32 i;
|
|
for (i = 0; i < PubTechniques.size(); i++)
|
|
{
|
|
string str = szName;
|
|
str += ".";
|
|
str += PubTechniques[i];
|
|
ShaderNames.push_back(str);
|
|
}
|
|
}
|
|
|
|
return bRes;
|
|
}
|
|
|
|
inline bool CompareInstParams(const SCGParam& a, const SCGParam& b)
|
|
{
|
|
return (a.m_RegisterOffset < b.m_RegisterOffset);
|
|
}
|
|
|
|
void CShaderMan::mfPostLoadFX(CShader* ef, std::vector<SShaderTechParseParams>& techParams, [[maybe_unused]] CCryNameR techStart[2])
|
|
{
|
|
ef->m_HWTechniques.Shrink();
|
|
|
|
uint32 i;
|
|
|
|
CRY_ASSERT(techParams.size() == ef->m_HWTechniques.Num());
|
|
for (i = 0; i < ef->m_HWTechniques.Num(); i++)
|
|
{
|
|
SShaderTechnique* hw = ef->m_HWTechniques[i];
|
|
SShaderTechParseParams* ps = &techParams[i];
|
|
uint32 n;
|
|
for (n = 0; n < TTYPE_MAX; n++)
|
|
{
|
|
if (ps->techName[n].c_str()[0])
|
|
{
|
|
if (hw->m_NameStr == ps->techName[n])
|
|
{
|
|
iLog->LogWarning("WARN: technique '%s' refers to itself as the next technique (ignored)", hw->m_NameStr.c_str());
|
|
}
|
|
else
|
|
{
|
|
uint32 j;
|
|
for (j = 0; j < ef->m_HWTechniques.Num(); j++)
|
|
{
|
|
SShaderTechnique* hw2 = ef->m_HWTechniques[j];
|
|
if (hw2->m_NameStr == ps->techName[n])
|
|
{
|
|
hw->m_nTechnique[n] = j;
|
|
break;
|
|
}
|
|
}
|
|
if (j == ef->m_HWTechniques.Num())
|
|
{
|
|
iLog->LogWarning("WARN: couldn't find technique '%s' in the sequence for technique '%s' (ignored)", ps->techName[n].c_str(), hw->m_NameStr.c_str());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SShaderTechnique* hwZWrite = (hw->m_nTechnique[TTYPE_Z] >= 0) ? ef->m_HWTechniques[hw->m_nTechnique[TTYPE_Z]] : NULL;
|
|
hwZWrite = (hw->m_nTechnique[TTYPE_ZPREPASS] >= 0) ? ef->m_HWTechniques[hw->m_nTechnique[TTYPE_ZPREPASS]] : hwZWrite;
|
|
if (hwZWrite && hwZWrite->m_Passes.Num())
|
|
{
|
|
SShaderPass* pass = &hwZWrite->m_Passes[0];
|
|
if (pass->m_RenderState & GS_DEPTHWRITE)
|
|
{
|
|
hw->m_Flags |= FHF_WASZWRITE;
|
|
}
|
|
}
|
|
|
|
bool bTransparent = true;
|
|
for (uint32 j = 0; j < hw->m_Passes.Num(); j++)
|
|
{
|
|
SShaderPass* pass = &hw->m_Passes[j];
|
|
if (CParserBin::PlatformSupportsGeometryShaders() && pass->m_GShader)
|
|
{
|
|
hw->m_Flags |= FHF_USE_GEOMETRY_SHADER;
|
|
}
|
|
if (CParserBin::PlatformSupportsHullShaders() && pass->m_HShader)
|
|
{
|
|
hw->m_Flags |= FHF_USE_HULL_SHADER;
|
|
}
|
|
if (CParserBin::PlatformSupportsDomainShaders() && pass->m_DShader)
|
|
{
|
|
hw->m_Flags |= FHF_USE_DOMAIN_SHADER;
|
|
}
|
|
if (!(pass->m_RenderState & GS_BLEND_MASK))
|
|
{
|
|
bTransparent = false;
|
|
}
|
|
}
|
|
if (bTransparent)
|
|
{
|
|
hw->m_Flags |= FHF_TRANSPARENT;
|
|
}
|
|
}
|
|
}
|
|
|
|
//===========================================================================================
|
|
|
|
void STexSamplerRT::Update()
|
|
{
|
|
if (m_pAnimInfo && m_pAnimInfo->m_Time && gRenDev->m_bPauseTimer == 0)
|
|
{
|
|
CRY_ASSERT(gRenDev->m_RP.m_TI[gRenDev->m_RP.m_nProcessThreadID].m_RealTime >= 0);
|
|
uint32 m = (uint32)(gRenDev->m_RP.m_TI[gRenDev->m_RP.m_nProcessThreadID].m_RealTime / m_pAnimInfo->m_Time) % (m_pAnimInfo->m_NumAnimTexs);
|
|
CRY_ASSERT(m < (uint32)m_pAnimInfo->m_TexPics.Num());
|
|
|
|
if (m_pTex && (m_pTex != m_pAnimInfo->m_TexPics[m]))
|
|
{
|
|
m_pTex->Release();
|
|
|
|
m_pTex = m_pAnimInfo->m_TexPics[m];
|
|
|
|
m_pTex->AddRef();
|
|
}
|
|
}
|
|
}
|
|
|
|
void SFXParam::GetCompName(uint32 nId, CryFixedStringT<128>& name)
|
|
{
|
|
if (nId < 0 || nId > 3)
|
|
{
|
|
name = "";
|
|
return;
|
|
}
|
|
|
|
char nm[16];
|
|
sprintf_s(nm, "__%d", nId);
|
|
const char* s = strstr(m_Name.c_str(), nm);
|
|
|
|
if (!s)
|
|
{
|
|
name = "";
|
|
return;
|
|
}
|
|
|
|
s += 3;
|
|
|
|
uint32 n;
|
|
for (n = 0; s[n] != 0; ++n)
|
|
{
|
|
if (s[n] <= 0x20 || (s[n] == '_' && s[n + 1] == '_'))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
name.append(s, n);
|
|
}
|
|
|
|
void SFXParam::GetParamComp(uint32 nOffset, CryFixedStringT<128>& param)
|
|
{
|
|
const char* szValue = m_Values.c_str();
|
|
|
|
if (!szValue[0])
|
|
{
|
|
param = "";
|
|
return;
|
|
}
|
|
|
|
if (szValue[0] == '{')
|
|
{
|
|
++szValue;
|
|
}
|
|
|
|
for (uint32 n = 0; n != nOffset; ++n)
|
|
{
|
|
while (szValue[0] != ',' && szValue[0] != ';' && szValue[0] != '}' && szValue[0] != 0)
|
|
{
|
|
++szValue;
|
|
}
|
|
|
|
if (szValue[0] == ';' || szValue[0] == '}' || szValue[0] == 0)
|
|
{
|
|
param = "";
|
|
return;
|
|
}
|
|
|
|
++szValue;
|
|
}
|
|
|
|
while (*szValue == ' ' || *szValue == 8)
|
|
{
|
|
++szValue;
|
|
}
|
|
|
|
uint32 n;
|
|
for (n = 0; szValue[n] != 0; ++n)
|
|
{
|
|
if (szValue[n] == ',' || szValue[n] == ';' || szValue[n] == '}')
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
param.append(szValue, n);
|
|
}
|
|
|
|
string SFXParam::GetValueForName(const char* szName, EParamType& eType)
|
|
{
|
|
eType = eType_UNKNOWN;
|
|
if (m_Annotations.empty())
|
|
{
|
|
return "";
|
|
}
|
|
|
|
char buf[256];
|
|
char tok[128];
|
|
char* szA = (char*)m_Annotations.c_str();
|
|
SkipCharacters(&szA, kWhiteSpace);
|
|
while (true)
|
|
{
|
|
if (!fxFill(&szA, buf))
|
|
{
|
|
break;
|
|
}
|
|
char* b = buf;
|
|
fxFillPr(&b, tok);
|
|
eType = eType_UNKNOWN;
|
|
if (!azstricmp(tok, "string"))
|
|
{
|
|
eType = eType_STRING;
|
|
}
|
|
else
|
|
if (!azstricmp(tok, "float"))
|
|
{
|
|
eType = eType_FLOAT;
|
|
}
|
|
else
|
|
if (!azstricmp(tok, "half"))
|
|
{
|
|
eType = eType_HALF;
|
|
}
|
|
|
|
if (eType != eType_UNKNOWN)
|
|
{
|
|
if (!fxFillPr(&b, tok))
|
|
{
|
|
continue;
|
|
}
|
|
if (azstricmp(tok, szName))
|
|
{
|
|
continue;
|
|
}
|
|
SkipCharacters(&b, kWhiteSpace);
|
|
if (b[0] == '=')
|
|
{
|
|
b++;
|
|
if (!fxFillPrC(&b, tok))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return tok;
|
|
}
|
|
else
|
|
{
|
|
if (azstricmp(tok, szName))
|
|
{
|
|
continue;
|
|
}
|
|
eType = eType_STRING;
|
|
if (!fxFillPr(&b, tok))
|
|
{
|
|
continue;
|
|
}
|
|
if (tok[0] == '=')
|
|
{
|
|
if (!fxFillPr(&b, tok))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return tok;
|
|
}
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
const char* CShaderMan::mfParseFX_Parameter (const string& script, EParamType eType, const char* szName)
|
|
{
|
|
static char sRet[128];
|
|
int nLen = script.length();
|
|
char* pTemp = new char [nLen + 1];
|
|
azstrcpy(pTemp, nLen + 1, script.c_str());
|
|
sRet[0] = 0;
|
|
char* buf = pTemp;
|
|
|
|
char* name;
|
|
long cmd;
|
|
char* data;
|
|
|
|
enum
|
|
{
|
|
eString = 1
|
|
};
|
|
|
|
static STokenDesc commands[] =
|
|
{
|
|
{eString, "String"},
|
|
|
|
{0, 0}
|
|
};
|
|
|
|
while ((cmd = shGetObject (&buf, commands, &name, &data)) > 0)
|
|
{
|
|
switch (cmd)
|
|
{
|
|
case eString:
|
|
{
|
|
if (eType != eType_STRING)
|
|
{
|
|
break;
|
|
}
|
|
char* szScr = data;
|
|
if (*szScr == '"')
|
|
{
|
|
szScr++;
|
|
}
|
|
int n = 0;
|
|
while (szScr[n] != 0)
|
|
{
|
|
if (szScr[n] == '"')
|
|
{
|
|
szScr[n] = ' ';
|
|
}
|
|
n++;
|
|
}
|
|
if (!azstricmp(szName, name))
|
|
{
|
|
azstrcpy(sRet, AZ_ARRAY_SIZE(sRet), data);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
SAFE_DELETE_ARRAY(pTemp);
|
|
|
|
if (sRet[0])
|
|
{
|
|
return sRet;
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Searches the constant params array for a desired constant based on name.
|
|
// Can be optimized if has performance hit.
|
|
//------------------------------------------------------------------------------
|
|
SFXParam* CShaderMan::mfGetFXParameter(std::vector<SFXParam>& Params, const char* param)
|
|
{
|
|
uint32 j;
|
|
for (j = 0; j < Params.size(); j++)
|
|
{
|
|
SFXParam* pr = &Params[j];
|
|
char nameParam[256];
|
|
int n = 0;
|
|
const char* szSrc = pr->m_Name.c_str();
|
|
while (*szSrc != 0)
|
|
{
|
|
if (*szSrc == '[')
|
|
{
|
|
break;
|
|
}
|
|
nameParam[n++] = *szSrc;
|
|
szSrc++;
|
|
}
|
|
nameParam[n] = 0;
|
|
if (!azstricmp(nameParam, param))
|
|
{
|
|
return pr;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Searches the samplers params array for a desired sampler based on name.
|
|
// Can be optimized if has performance hit.
|
|
//------------------------------------------------------------------------------
|
|
SFXSampler* CShaderMan::mfGetFXSampler(std::vector<SFXSampler>& Params, const char* param)
|
|
{
|
|
uint32 j;
|
|
for (j = 0; j < Params.size(); j++)
|
|
{
|
|
SFXSampler* pr = &Params[j];
|
|
char nameParam[256];
|
|
int n = 0;
|
|
const char* szSrc = pr->m_Name.c_str();
|
|
while (*szSrc != 0)
|
|
{
|
|
if (*szSrc == '[')
|
|
{
|
|
break;
|
|
}
|
|
nameParam[n++] = *szSrc;
|
|
szSrc++;
|
|
}
|
|
nameParam[n] = 0;
|
|
if (!azstricmp(nameParam, param))
|
|
{
|
|
return pr;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Searches the texture params array for a desired texture based on name.
|
|
// Can be optimized if has performance hit.
|
|
//------------------------------------------------------------------------------
|
|
SFXTexture* CShaderMan::mfGetFXTexture(std::vector<SFXTexture>& Params, const char* param)
|
|
{
|
|
uint32 j;
|
|
for (j = 0; j < Params.size(); j++)
|
|
{
|
|
SFXTexture* pr = &Params[j];
|
|
char nameParam[256];
|
|
int n = 0;
|
|
const char* szSrc = pr->m_Name.c_str();
|
|
while (*szSrc != 0)
|
|
{
|
|
if (*szSrc == '[')
|
|
{
|
|
break;
|
|
}
|
|
nameParam[n++] = *szSrc;
|
|
szSrc++;
|
|
}
|
|
nameParam[n] = 0;
|
|
if (!azstricmp(nameParam, param))
|
|
{
|
|
return pr;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
// We have to parse part of the shader to enumerate public techniques
|
|
bool CShaderMan::mfAddFXShaderNames(const char* szName, std::vector<string>* ShaderNames, bool bUpdateCRC)
|
|
{
|
|
bool bRes = true;
|
|
SShaderBin* pBin = m_Bin.GetBinShader(szName, false, 0);
|
|
if (!pBin)
|
|
{
|
|
return false;
|
|
}
|
|
if (bUpdateCRC)
|
|
{
|
|
uint32 nCRC32 = pBin->ComputeCRC();
|
|
if (nCRC32 != pBin->m_CRC32)
|
|
{
|
|
FXShaderBinValidCRCItor itor = gRenDev->m_cEF.m_Bin.m_BinValidCRCs.find(pBin->m_dwName);
|
|
if (itor == gRenDev->m_cEF.m_Bin.m_BinValidCRCs.end())
|
|
{
|
|
gRenDev->m_cEF.m_Bin.m_BinValidCRCs.insert(FXShaderBinValidCRCItor::value_type(pBin->m_dwName, false));
|
|
}
|
|
|
|
m_Bin.DeleteFromCache(pBin);
|
|
pBin = m_Bin.GetBinShader(szName, false, nCRC32);
|
|
if (!pBin)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Do not parse techniques for consoles
|
|
if (ShaderNames)
|
|
{
|
|
bRes &= m_Bin.ParseBinFX_Dummy(pBin, *ShaderNames, szName);
|
|
}
|
|
|
|
return bRes;
|
|
}
|
|
|
|
CTexture* CShaderMan::mfParseFXTechnique_LoadShaderTexture (STexSamplerRT* smp, const char* szName, [[maybe_unused]] SShaderPass* pShPass, [[maybe_unused]] CShader* ef, [[maybe_unused]] int nIndex, [[maybe_unused]] byte ColorOp, [[maybe_unused]] byte AlphaOp, [[maybe_unused]] byte ColorArg, [[maybe_unused]] byte AlphaArg)
|
|
{
|
|
CTexture* tp = NULL;
|
|
if (!szName || !szName[0] || gRenDev->m_bShaderCacheGen) // Sampler without texture specified
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
#if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
|
|
// store the CRC for this sampler's texture name for fast lookup
|
|
// this is particularly useful for shared engine textures
|
|
CCryNameTSCRC crc(szName);
|
|
smp->m_nCrc = crc.get();
|
|
#endif // #if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
|
|
|
|
if (szName[0] == '$')
|
|
{
|
|
tp = mfCheckTemplateTexName(szName, (ETEX_Type)smp->m_eTexType);
|
|
if (tp)
|
|
{
|
|
tp->AddRef();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
smp->m_nTexFlags |= FT_DONT_STREAM; // disable streaming for explicitly specified textures
|
|
}
|
|
if (!tp)
|
|
{
|
|
tp = mfTryToLoadTexture(szName, smp, smp->GetTexFlags(), false);
|
|
}
|
|
|
|
return tp;
|
|
}
|
|
|