!I (1670409):
[CRYENGINE.git] / Code / CryEngine / RenderDll / XRenderD3D9 / D3DHWShaderCompiling.cpp
blobcf7addbf7d7951e9120ad00e03f00048a5b62f54
1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
3 #include "StdAfx.h"
5 #include <lzss/LZSS.H>
6 #include <lzma/Lzma86.h>
8 #if !CRY_PLATFORM_ORBIS && !CRY_RENDERER_OPENGL && !CRY_RENDERER_OPENGLES && !CRY_RENDERER_VULKAN
9 #if CRY_PLATFORM_DURANGO
10 #include <D3D11Shader_x.h>
11 #include <D3DCompiler_x.h>
12 #else
13 #include <D3D11Shader.h>
14 #include <D3DCompiler.h>
15 #endif
16 #endif
18 #if defined(USE_NV_API)
19 #include NV_API_HEADER
20 #endif
22 #include "../Common/Shaders/RemoteCompiler.h"
24 static CryCriticalSection g_cAILock;
25 static SShaderAsyncInfo g_PendingList;
26 static SShaderAsyncInfo g_PendingListT;
27 #ifdef SHADER_ASYNC_COMPILATION
28 static SShaderAsyncInfo g_BuildList;
29 #endif
31 SShaderAsyncInfo& SShaderAsyncInfo::PendingList() { return g_PendingList; }
32 SShaderAsyncInfo& SShaderAsyncInfo::PendingListT() { return g_PendingListT; }
33 #ifdef SHADER_ASYNC_COMPILATION
34 SShaderAsyncInfo& CAsyncShaderTask::BuildList() { return g_BuildList; }
35 #endif
37 CryEvent SShaderAsyncInfo::s_RequestEv;
39 int CHWShader_D3D::s_nDevicePSDataSize = 0;
40 int CHWShader_D3D::s_nDeviceVSDataSize = 0;
42 namespace
44 inline int GetCurrentFrameID()
46 return (gRenDev->m_pRT->IsRenderThread()) ? gRenDev->GetRenderFrameID() : gRenDev->GetMainFrameID();
50 class CSpinLock
52 public:
53 CSpinLock()
55 #if CRY_PLATFORM_WINDOWS || CRY_PLATFORM_LINUX || CRY_PLATFORM_ANDROID || CRY_PLATFORM_APPLE
56 while (CryInterlockedCompareExchange(&s_locked, 1L, 0L) == 1L)
57 CrySleep(0);
58 #endif
61 ~CSpinLock()
63 #if CRY_PLATFORM_WINDOWS
64 InterlockedExchange(&s_locked, 0L);
65 #elif CRY_PLATFORM_LINUX || CRY_PLATFORM_ANDROID || CRY_PLATFORM_APPLE
66 while (CryInterlockedCompareExchange(&s_locked, 0L, 1L) == 0L);
67 #endif
70 private:
71 static volatile LONG s_locked;
74 volatile LONG CSpinLock::s_locked = 0L;
76 volatile int SShaderAsyncInfo::s_nPendingAsyncShaders = 0;
77 int SShaderAsyncInfo::s_nPendingAsyncShadersFXC = 0;
79 //==============================================================================================================
81 bool CHWShader_D3D::mfAddFXSampler(SHWSInstance* pInst, SShaderFXParams& FXParams, SFXSampler* pr, const char* ParamName, SCGBind* pBind, CShader* ef, EHWShaderClass eSHClass)
83 assert(pBind);
84 if (!pBind)
85 return false;
87 std::vector<SCGSampler>* pParams;
88 pParams = &pInst->m_Samplers;
89 uint32 nOffs = pParams->size();
90 bool bRes = gRenDev->m_cEF.mfParseFXSampler(FXParams, pr, ParamName, ef, pBind->m_nParameters, pParams, eSHClass);
91 if (pParams->size() > nOffs)
93 for (uint32 i = 0; i < pParams->size() - nOffs; i++)
95 SCGSampler& p = (*pParams)[nOffs + i];
96 p.m_dwBind = pBind->m_dwBind + i;
97 p.m_dwCBufSlot = pBind->m_dwCBufSlot;
98 p.m_Name = pBind->m_Name;
101 // Parameter without semantic
102 return bRes;
105 bool CHWShader_D3D::mfAddFXTexture(SHWSInstance* pInst, SShaderFXParams& FXParams, SFXTexture* pr, const char* ParamName, SCGBind* pBind, CShader* ef, EHWShaderClass eSHClass)
107 assert(pBind);
108 if (!pBind)
109 return false;
111 std::vector<SCGTexture>* pParams;
112 pParams = &pInst->m_Textures;
113 uint32 nOffs = pParams->size();
114 bool bRes = gRenDev->m_cEF.mfParseFXTexture(FXParams, pr, ParamName, ef, pBind->m_nParameters, pParams, eSHClass);
115 if (!bRes)
117 int nnn = 0;
119 if (pParams->size() > nOffs)
121 for (uint32 i = 0; i < pParams->size() - nOffs; i++)
123 SCGTexture& p = (*pParams)[nOffs + i];
124 p.m_dwBind = pBind->m_dwBind + i;
125 p.m_dwCBufSlot = pBind->m_dwCBufSlot;
126 p.m_Name = pBind->m_Name;
129 // Parameter without semantic
130 return bRes;
133 void CHWShader_D3D::mfAddFXParameter(SHWSInstance* pInst, SParamsGroup& OutParams, SShaderFXParams& FXParams, SFXParam* pr, const char* ParamName, SCGBind* pBind, CShader* ef, bool bInstParam, EHWShaderClass eSHClass)
135 SCGParam CGpr;
137 assert(pBind);
138 if (!pBind)
139 return;
141 int nComps = 0;
142 int nParams = pBind->m_nParameters;
143 if (!pr->m_Semantic.empty())
144 nComps = pr->m_nComps;
145 else
147 for (int i = 0; i < pr->m_nComps; i++)
149 CryFixedStringT<128> cur;
150 pr->GetParamComp(i, cur);
151 if (cur.empty())
152 break;
153 nComps++;
156 // Process parameters only with semantics
157 if (nComps && nParams)
159 std::vector<SCGParam>* pParams;
160 if (pr->m_nParameters > 1)
162 if (!bInstParam)
164 //if (!pInst->m_pParams[0])
165 // pInst->m_pParams[0] = new std::vector<SCGParam>;
166 pParams = &OutParams.Params[0];
168 else
170 //if (!pInst->m_pParams_Inst)
171 // pInst->m_pParams_Inst = new std::vector<SCGParam>;
172 pParams = &OutParams.Params_Inst;
175 else if (bInstParam)
177 //if (!pInst->m_pParams_Inst)
178 // pInst->m_pParams_Inst = new std::vector<SCGParam>;
179 pParams = &OutParams.Params_Inst;
181 else
183 //if (!pInst->m_pParams[0])
184 // pInst->m_pParams[0] = new std::vector<SCGParam>;
185 pParams = &OutParams.Params[0];
187 uint32 nOffs = pParams->size();
188 bool bRes = gRenDev->m_cEF.mfParseFXParameter(FXParams, pr, ParamName, ef, bInstParam, pBind->m_nParameters, pParams, eSHClass, false);
189 assert(bRes);
190 if (pParams->size() > nOffs)
192 for (uint32 i = 0; i < pParams->size() - nOffs; i++)
194 //assert(pBind->m_nComponents == 1);
195 SCGParam& p = (*pParams)[nOffs + i];
196 p.m_dwBind = pBind->m_dwBind + i;
197 p.m_dwCBufSlot = pBind->m_dwCBufSlot;
201 // Parameter without semantic
204 struct SAliasSampler
206 STexSamplerRT Sampler;
207 string NameTex;
210 bool CHWShader_D3D::mfAddFXParameter(SHWSInstance* pInst, SParamsGroup& OutParams, SShaderFXParams& FXParams, const char* param, SCGBind* bn, bool bInstParam, EHWShaderClass eSHClass, CShader* pFXShader)
212 if (bn->m_dwBind & SHADER_BIND_TEXTURE)
214 SFXTexture* pr = gRenDev->m_cEF.mfGetFXTexture(FXParams.m_FXTextures, param);
215 if (pr)
217 if (bn->m_nParameters < 0)
218 bn->m_nParameters = pr->m_nArray;
219 bool bRes = mfAddFXTexture(pInst, FXParams, pr, param, bn, pFXShader, eSHClass);
220 return true;
223 else if (bn->m_dwBind & SHADER_BIND_SAMPLER)
225 SFXSampler* pr = gRenDev->m_cEF.mfGetFXSampler(FXParams.m_FXSamplers, param);
226 if (pr)
228 if (bn->m_nParameters < 0)
229 bn->m_nParameters = pr->m_nArray;
230 bool bRes = mfAddFXSampler(pInst, FXParams, pr, param, bn, pFXShader, eSHClass);
231 return true;
234 else
236 SFXParam* pr = gRenDev->m_cEF.mfGetFXParameter(FXParams.m_FXParams, param);
237 if (pr)
239 if (bn->m_nParameters < 0)
240 bn->m_nParameters = pr->m_nParameters;
241 mfAddFXParameter(pInst, OutParams, FXParams, pr, param, bn, pFXShader, bInstParam, eSHClass);
242 return true;
245 return false;
248 //==================================================================================================================
250 int CGBindCallback(const VOID* arg1, const VOID* arg2)
252 SCGBind* pi1 = (SCGBind*)arg1;
253 SCGBind* pi2 = (SCGBind*)arg2;
255 if (pi1->m_dwBind < pi2->m_dwBind)
256 return -1;
257 if (pi1->m_dwBind > pi2->m_dwBind)
258 return 1;
260 return 0;
263 const char* szNamesCB[CB_NUM] = { "PER_BATCH", "PER_INSTANCE", "PER_FRAME", "PER_MATERIAL", "PER_LIGHT", "PER_SHADOWGEN", "SKIN_DATA", "INSTANCE_DATA" };
265 void CHWShader_D3D::mfCreateBinds(SHWSInstance* pInst, void* pConstantTable, byte* pShader, int nSize)
267 uint32 i;
268 ID3D11ShaderReflection* pShaderReflection = (ID3D11ShaderReflection*)pConstantTable;
269 D3D11_SHADER_DESC Desc;
270 pShaderReflection->GetDesc(&Desc);
271 ID3D11ShaderReflectionConstantBuffer* pCB = NULL;
272 for (uint32 n = 0; n < Desc.ConstantBuffers; n++)
274 pCB = pShaderReflection->GetConstantBufferByIndex(n);
275 D3D11_SHADER_BUFFER_DESC SBDesc;
276 pCB->GetDesc(&SBDesc);
277 if (SBDesc.Type == D3D11_CT_RESOURCE_BIND_INFO)
278 continue;
279 int nCB;
280 if (!strcmp("$Globals", SBDesc.Name))
281 nCB = CB_PER_BATCH;
282 else
283 for (nCB = 0; nCB < CB_NUM; nCB++)
285 if (!strcmp(szNamesCB[nCB], SBDesc.Name))
286 break;
288 //assert(nCB != CB_NUM);
289 if (nCB >= CB_NUM) // Allow having custom cbuffers in shaders
290 continue;
291 for (i = 0; i < SBDesc.Variables; i++)
293 uint32 nCount = 1;
294 ID3D11ShaderReflectionVariable* pCV = pCB->GetVariableByIndex(i);
295 ID3D11ShaderReflectionType* pVT = pCV->GetType();
296 D3D11_SHADER_VARIABLE_DESC CDesc;
297 D3D11_SHADER_TYPE_DESC CTDesc;
298 pVT->GetDesc(&CTDesc);
299 pCV->GetDesc(&CDesc);
300 if (!(CDesc.uFlags & D3D10_SVF_USED))
301 continue;
302 if (CTDesc.Class == D3D10_SVC_VECTOR || CTDesc.Class == D3D10_SVC_SCALAR || CTDesc.Class == D3D10_SVC_MATRIX_COLUMNS || CTDesc.Class == D3D10_SVC_MATRIX_ROWS)
304 SCGBind cgp;
305 assert(!(CDesc.StartOffset & 0xf));
306 //assert(!(CDesc.Size & 0xf));
307 int nReg = CDesc.StartOffset >> 4;
308 cgp.m_dwBind = nReg; //<<2;
309 cgp.m_dwCBufSlot = nCB;
310 cgp.m_nParameters = (CDesc.Size + 15) >> 4;
311 cgp.m_Name = CDesc.Name;
312 cgp.m_Flags = CParserBin::GetCRC32(CDesc.Name);
313 pInst->m_pBindVars.push_back(cgp);
315 else
317 assert(false);
322 D3D11_SHADER_INPUT_BIND_DESC IBDesc;
323 for (i = 0; i < Desc.BoundResources; i++)
325 ZeroStruct(IBDesc);
326 pShaderReflection->GetResourceBindingDesc(i, &IBDesc);
327 SCGBind cgp;
328 if (IBDesc.Type == D3D10_SIT_TEXTURE)
329 cgp.m_dwBind = IBDesc.BindPoint | SHADER_BIND_TEXTURE;
330 else if (IBDesc.Type == D3D10_SIT_SAMPLER)
331 cgp.m_dwBind = IBDesc.BindPoint | SHADER_BIND_SAMPLER;
332 else
333 continue;
335 if (IBDesc.Dimension == D3D10_SRV_DIMENSION_BUFFER)
336 continue;
338 cgp.m_dwCBufSlot = IBDesc.BindPoint;
339 cgp.m_nParameters = IBDesc.BindCount;
340 cgp.m_Name = IBDesc.Name;
341 cgp.m_Flags = CParserBin::GetCRC32(IBDesc.Name);
342 pInst->m_pBindVars.push_back(cgp);
346 void CHWShader_D3D::mfGatherFXParameters(SHWSInstance* pInst, std::vector<SCGBind>* BindVars, std::vector<SCGBind>* InstBindVars, CHWShader_D3D* pSH, int nFlags, CShader* pFXShader)
348 // LOADING_TIME_PROFILE_SECTION(iSystem);
350 uint32 i, j;
351 SAliasSampler samps[MAX_TMU];
352 int nMaxSampler = -1;
353 int nParam = 0;
354 SParamsGroup Group;
355 SShaderFXParams& FXParams = gRenDev->m_cEF.m_Bin.mfGetFXParams(pInst->m_bFallback ? CShaderMan::s_ShaderFallback : pFXShader);
356 if (pInst->m_pBindVars.size())
358 std::list<uint32> skipped;
360 for (i = 0; i < pInst->m_pBindVars.size(); i++)
362 SCGBind* bn = &(*BindVars)[i];
363 const char* param = bn->m_Name.c_str();
365 if (!strncmp(param, "_g_", 3))
366 continue;
367 bool bRes = mfAddFXParameter(pInst, Group, FXParams, param, bn, false, pSH->m_eSHClass, pFXShader);
368 if (!bRes && !(bn->m_dwBind & (SHADER_BIND_TEXTURE | SHADER_BIND_SAMPLER)))
370 //iLog->LogWarning("WARNING: Couldn't find parameter '%s' for shader '%s'", param, pSH->GetName());
371 // const parameters aren't listed in Params
372 // assert(0);
374 else if (!bRes && (bn->m_dwBind & SHADER_BIND_TEXTURE)) // try to find old samplers (Without semantics)
376 skipped.push_back(i);
380 bool setSamplers[256] = { false };
381 bool setTextures[256] = { false };
383 for (i = 0; i < pInst->m_Samplers.size(); i++)
384 setSamplers[pInst->m_Samplers[i].m_dwBind & 0xff] = true;
385 for (i = 0; i < pInst->m_Textures.size(); i++)
386 setTextures[pInst->m_Textures[i].m_dwBind & 0xff] = true;
388 while (skipped.size() > 0)
390 i = skipped.front();
391 skipped.pop_front();
393 SCGBind* bn = &(*BindVars)[i];
394 const char* param = bn->m_Name.c_str();
397 for (j = 0; j < (uint32)FXParams.m_FXSamplersOld.size(); j++)
399 STexSamplerFX* sm = &FXParams.m_FXSamplersOld[j];
400 if (!stricmp(sm->m_szName.c_str(), param))
402 int nSampler = bn->m_dwBind & 0x7f;
403 if (nSampler < MAX_TMU)
405 nMaxSampler = max(nSampler, nMaxSampler);
406 samps[nSampler].Sampler = STexSamplerRT(*sm);
407 samps[nSampler].NameTex = sm->m_szTexture;
408 samps[nSampler].Sampler.m_nSamplerSlot = (int8)(bn->m_dwCBufSlot & 0xff);
409 samps[nSampler].Sampler.m_nTextureSlot = nSampler;
411 // Solve slot-assignment when Sampler2D gets distinct t? and s? slot assigned by fxc (2 binds exist then)
412 for (int k = 0; k < pInst->m_pBindVars.size(); k++)
413 if ((*BindVars)[k].m_dwBind & SHADER_BIND_TEXTURE)
414 if (!stricmp((*BindVars)[k].m_Name.c_str(), param))
415 samps[nSampler].Sampler.m_nTextureSlot = (int8)(*BindVars)[k].m_dwCBufSlot;
417 for (int k = 0; k < pInst->m_pBindVars.size(); k++)
418 if ((*BindVars)[k].m_dwBind & SHADER_BIND_SAMPLER)
419 if (!stricmp((*BindVars)[k].m_Name.c_str(), param))
420 samps[nSampler].Sampler.m_nSamplerSlot = (int8)(*BindVars)[k].m_dwCBufSlot;
422 // Texture slot occupied, search an alternative
423 if (setSamplers[samps[nSampler].Sampler.m_nSamplerSlot])
425 uint32 f = 0;
426 while (setSamplers[f])
427 ++f;
428 samps[nSampler].Sampler.m_nSamplerSlot = f;
429 assert(f < 16);
432 // Sampler slot occupied, search an alternative
433 if (setTextures[samps[nSampler].Sampler.m_nTextureSlot])
435 uint32 f = 0;
436 while (setTextures[f])
437 ++f;
438 samps[nSampler].Sampler.m_nTextureSlot = f;
439 assert(f < 256);
442 setTextures[samps[nSampler].Sampler.m_nTextureSlot] = true;
443 setSamplers[samps[nSampler].Sampler.m_nSamplerSlot] = true;
445 break;
450 if (j == FXParams.m_FXSamplersOld.size())
452 for (j = 0; j < (uint32)FXParams.m_FXSamplersOld.size(); j++)
454 STexSamplerFX* sm = &FXParams.m_FXSamplersOld[j];
455 const char* src = sm->m_szName.c_str();
456 char name[128];
457 int n = 0;
458 while (src[n])
460 if (src[n] <= 0x20 || src[n] == '[')
461 break;
462 name[n] = src[n];
463 n++;
465 name[n] = 0;
466 if (!stricmp(name, param))
468 int nSampler = bn->m_dwBind & 0x7f;
469 if (nSampler < MAX_TMU)
471 samps[nSampler].Sampler = STexSamplerRT(*sm);
472 samps[nSampler].NameTex = sm->m_szTexture;
473 samps[nSampler].Sampler.m_nSamplerSlot = (int8)(bn->m_dwCBufSlot & 0xff);
474 samps[nSampler].Sampler.m_nTextureSlot = nSampler;
476 // Solve slot-assignment when Sampler2D gets distinct t? and s? slot assigned by fxc (2 binds exist then)
477 for (int k = 0; k < pInst->m_pBindVars.size(); k++)
478 if ((*BindVars)[k].m_dwBind & SHADER_BIND_TEXTURE)
479 if (!stricmp((*BindVars)[k].m_Name.c_str(), param))
480 samps[nSampler].Sampler.m_nTextureSlot = (int8)(*BindVars)[k].m_dwCBufSlot;
482 for (int k = 0; k < pInst->m_pBindVars.size(); k++)
483 if ((*BindVars)[k].m_dwBind & SHADER_BIND_SAMPLER)
484 if (!stricmp((*BindVars)[k].m_Name.c_str(), param))
485 samps[nSampler].Sampler.m_nSamplerSlot = (int8)(*BindVars)[k].m_dwCBufSlot;
487 // Texture slot occupied, search an alternative
488 if (setSamplers[samps[nSampler].Sampler.m_nSamplerSlot])
490 uint32 f = 0;
491 while (setSamplers[f])
492 ++f;
493 samps[nSampler].Sampler.m_nSamplerSlot = f;
494 assert(f < 16);
497 // Sampler slot occupied, search an alternative
498 if (setTextures[samps[nSampler].Sampler.m_nTextureSlot])
500 uint32 f = 0;
501 while (setTextures[f])
502 ++f;
503 samps[nSampler].Sampler.m_nTextureSlot = f;
504 assert(f < 256);
507 setTextures[samps[nSampler].Sampler.m_nTextureSlot] = true;
508 setSamplers[samps[nSampler].Sampler.m_nSamplerSlot] = true;
510 for (int nS = 0; nS < bn->m_nParameters; nS++)
512 nMaxSampler = max(nSampler + nS, nMaxSampler);
513 samps[nSampler + nS].Sampler = samps[nSampler].Sampler;
514 samps[nSampler + nS].NameTex = sm->m_szTexture;
516 break;
520 if (j == FXParams.m_FXSamplersOld.size())
522 // const parameters aren't listed in Params
523 //iLog->LogWarning("WARNING: Couldn't find parameter '%s' for shader '%s'", param, pSH->GetName());
524 //assert(0);
530 if (nFlags != 1)
532 for (i = 0; (int)i <= nMaxSampler; i++)
534 STexSamplerRT& smp = samps[i].Sampler;
535 smp.m_pTex = gRenDev->m_cEF.mfParseFXTechnique_LoadShaderTexture(&smp, samps[i].NameTex.c_str(), NULL, NULL, i, eCO_NOSET, eCO_NOSET, DEF_TEXARG0, DEF_TEXARG0);
536 if (!smp.m_pTex)
537 continue;
538 assert(!smp.m_pDynTexSource);
539 if (smp.m_bGlobal)
541 //mfAddGlobalSampler(smp);
543 else
544 pInst->m_pSamplers.push_back(smp);
547 else
549 assert(pInst->m_pAsync);
550 if (pInst->m_pAsync && nMaxSampler >= 0)
551 pInst->m_pAsync->m_bPendedSamplers = true;
554 pInst->m_nMaxVecs[0] = pInst->m_nMaxVecs[1] = 0;
555 if (pInst->m_pBindVars.size())
557 for (i = 0; i < pInst->m_pBindVars.size(); i++)
559 SCGBind* pB = &pInst->m_pBindVars[i];
560 if (pB->m_dwBind & (SHADER_BIND_SAMPLER | SHADER_BIND_TEXTURE))
561 continue;
562 if (pB->m_dwCBufSlot < 0 || pB->m_dwCBufSlot > 2)
563 continue;
564 for (j = 0; j < Group.Params[0].size(); j++)
566 SCGParam* pr = &Group.Params[0][j];
567 if (pr->m_dwBind == pB->m_dwBind && pr->m_Name == pB->m_Name)
568 break;
570 if (j != Group.Params[0].size())
571 continue;
572 if (pB->m_dwCBufSlot < 3)
573 pInst->m_nMaxVecs[pB->m_dwCBufSlot] = max(pB->m_dwBind + pB->m_nParameters, pInst->m_nMaxVecs[pB->m_dwCBufSlot]);
576 if (Group.Params[0].size())
578 for (i = 0; i < Group.Params[0].size(); i++)
580 SCGParam* pr = &Group.Params[0][i];
582 if (pr->m_Flags & PF_MATERIAL)
583 pInst->m_bHasPMParams = true;
586 gRenDev->m_cEF.mfCheckObjectDependParams(Group.Params[0], Group.Params[1], pSH->m_eSHClass, pFXShader);
589 for (i = 0; i < 2; i++)
591 if (Group.Params[i].size())
593 for (j = 0; j < Group.Params[i].size(); j++)
595 SCGParam* pr = &Group.Params[i][j];
596 pInst->m_nMaxVecs[i] = max(pr->m_dwBind + pr->m_nParameters, pInst->m_nMaxVecs[i]);
600 int nMax = 0;
601 if (pSH->m_eSHClass == eHWSC_Vertex)
602 nMax = MAX_CONSTANTS_VS;
603 else if (pSH->m_eSHClass == eHWSC_Pixel)
604 nMax = MAX_CONSTANTS_PS;
605 else if (pSH->m_eSHClass == eHWSC_Geometry)
606 nMax = MAX_CONSTANTS_GS;
607 else if (pSH->m_eSHClass == eHWSC_Domain)
608 nMax = MAX_CONSTANTS_DS;
609 else if (pSH->m_eSHClass == eHWSC_Hull)
610 nMax = MAX_CONSTANTS_HS;
611 else if (pSH->m_eSHClass == eHWSC_Compute)
612 nMax = MAX_CONSTANTS_CS;
613 assert(pInst->m_nMaxVecs[0] < nMax);
614 assert(pInst->m_nMaxVecs[1] < nMax);
616 if (Group.Params[0].size() > 0)
618 qsort(&Group.Params[0][0], Group.Params[0].size(), sizeof(SCGParam), CGBindCallback);
619 pInst->m_nParams[0] = CGParamManager::GetParametersGroup(Group, 0);
621 if (Group.Params[1].size() > 0)
623 qsort(&Group.Params[1][0], Group.Params[1].size(), sizeof(SCGParam), CGBindCallback);
624 pInst->m_nParams[1] = CGParamManager::GetParametersGroup(Group, 1);
628 // Vertex shader specific
629 void CHWShader_D3D::mfUpdateFXVertexFormat(SHWSInstance* pInst, CShader* pSH)
631 // Update global FX shader's vertex format / flags
632 if (pSH)
634 InputLayoutHandle eVFormat = pSH->m_eVertexFormat;
635 bool bCurrent = false;
636 for (uint32 i = 0; i < pSH->m_HWTechniques.Num(); i++)
638 SShaderTechnique* hw = pSH->m_HWTechniques[i];
639 for (uint32 j = 0; j < hw->m_Passes.Num(); j++)
641 SShaderPass* pass = &hw->m_Passes[j];
642 if (pass->m_VShader)
644 if (pass->m_VShader == this)
645 bCurrent = true;
646 bool bUseLM = false;
647 bool bUseTangs = false;
648 bool bUseHWSkin = false;
649 InputLayoutHandle eCurVFormat = pass->m_VShader->mfVertexFormat(bUseTangs, bUseLM, bUseHWSkin);
650 if (eCurVFormat >= EDefaultInputLayouts::Empty)
651 eVFormat = max(eVFormat, eCurVFormat);
652 if (bUseTangs)
653 pass->m_PassFlags |= VSM_TANGENTS;
654 if (bUseHWSkin)
656 pass->m_PassFlags |= VSM_HWSKIN;
657 pass->m_PassFlags |= VSM_VERTEX_VELOCITY;
662 //assert (bCurrent);
663 pSH->m_eVertexFormat = eVFormat;
667 void CHWShader_D3D::mfPostVertexFormat(SHWSInstance* pInst, CHWShader_D3D* pHWSH, bool bCol, byte bNormal, bool bTC0, bool bTC1[2], bool bPSize, bool bTangent[2], bool bBitangent[2], bool bHWSkin, bool bSH[2], bool bVelocity, bool bMorph)
669 if (bBitangent[0])
670 pInst->m_VStreamMask_Decl |= 1 << VSF_TANGENTS;
671 else if (bTangent[0])
672 pInst->m_VStreamMask_Decl |= 1 << VSF_QTANGENTS;
673 if (bBitangent[1])
674 pInst->m_VStreamMask_Stream |= 1 << VSF_TANGENTS;
675 else if (bTangent[1])
676 pInst->m_VStreamMask_Stream |= 1 << VSF_QTANGENTS;
677 if (pInst->m_VStreamMask_Decl & (1 << VSF_TANGENTS))
678 bNormal = false;
680 if (bHWSkin)
682 pInst->m_VStreamMask_Decl |= VSM_HWSKIN;
683 pInst->m_VStreamMask_Stream |= VSM_HWSKIN;
686 if (bVelocity)
688 pInst->m_VStreamMask_Decl |= VSM_VERTEX_VELOCITY;
689 pInst->m_VStreamMask_Stream |= VSM_VERTEX_VELOCITY;
691 if (bMorph)
693 pInst->m_VStreamMask_Decl |= VSM_MORPHBUDDY;
694 pInst->m_VStreamMask_Stream |= VSM_MORPHBUDDY;
697 InputLayoutHandle eVF = VertFormatForComponents(bCol, bTC0, bPSize, bNormal != 0);
698 pInst->m_nVertexFormat = eVF;
701 InputLayoutHandle CHWShader_D3D::mfVertexFormat(bool& bUseTangents, bool& bUseLM, bool& bUseHWSkin)
703 uint32 i;
705 assert(m_eSHClass == eHWSC_Vertex);
707 InputLayoutHandle eVFormat = EDefaultInputLayouts::P3F_C4B_T2F;
708 int nStream = 0;
709 for (i = 0; i < m_Insts.size(); i++)
711 SHWSInstance* pInst = m_Insts[i];
712 eVFormat = (InputLayoutHandle)max((uint32)eVFormat, (uint32)pInst->m_nVertexFormat);
713 nStream |= pInst->m_VStreamMask_Stream;
715 bUseTangents = (nStream & VSM_TANGENTS) != 0;
716 bUseLM = false;
717 bUseHWSkin = (nStream & VSM_HWSKIN) != 0;
718 assert(eVFormat < EDefaultInputLayouts::PreAllocated);
720 return eVFormat;
723 InputLayoutHandle CHWShader_D3D::mfVertexFormat(SHWSInstance* pInst, CHWShader_D3D* pSH, D3DBlob* pShader, void* pConstantTable)
725 /*if (!stricmp(pSH->m_EntryFunc.c_str(), "ParticleVS"))
727 int nnn = 0;
730 assert(pSH->m_eSHClass == eHWSC_Vertex);
732 byte bNormal = false;
733 bool bTangent[2] = { false, false };
734 bool bBitangent[2] = { false, false };
735 bool bHWSkin = false;
736 bool bVelocity = false;
737 bool bMorph = false;
738 bool bBoneSpace = false;
739 bool bPSize = false;
740 bool bSH[2] = { false, false };
741 bool bTC0 = false;
742 bool bTC1[2] = { false, false };
743 bool bCol = false;
744 bool bSecCol = false;
745 bool bPos = false;
746 InputLayoutHandle eVFormat = EDefaultInputLayouts::P3F_C4B_T2F;
748 size_t nSize = pShader->GetBufferSize();
749 void* pData = pShader->GetBufferPointer();
750 void* pShaderReflBuf = pConstantTable;
751 HRESULT hr = pConstantTable ? S_OK : D3DReflect(pData, nSize, IID_ID3D11ShaderReflection, &pShaderReflBuf);
752 assert(SUCCEEDED(hr));
753 ID3D11ShaderReflection* pShaderReflection = (ID3D11ShaderReflection*)pShaderReflBuf;
754 if (!SUCCEEDED(hr))
755 return InputLayoutHandle::Unspecified;
756 D3D11_SHADER_DESC Desc;
757 pShaderReflection->GetDesc(&Desc);
758 if (!Desc.InputParameters)
759 return InputLayoutHandle::Unspecified;
760 D3D11_SIGNATURE_PARAMETER_DESC IDesc;
761 for (uint32 i = 0; i < Desc.InputParameters; i++)
763 pShaderReflection->GetInputParameterDesc(i, &IDesc);
764 //if (!IDesc.ReadWriteMask)
765 // continue;
766 if (!IDesc.SemanticName)
767 continue;
768 int nIndex;
769 if (!strnicmp(IDesc.SemanticName, "POSITION", 8) || !strnicmp(IDesc.SemanticName, "SV_POSITION", 11))
771 nIndex = IDesc.SemanticIndex;
772 if (nIndex == 0)
773 bPos = true;
774 else if (nIndex == 3)
775 bVelocity = true;
776 else if (nIndex == 4)
777 bHWSkin = true;
778 else if (nIndex == 8)
779 bMorph = true;
780 else
781 assert(false);
783 else if (!strnicmp(IDesc.SemanticName, "NORMAL", 6))
785 bNormal = true;
787 else if (!strnicmp(IDesc.SemanticName, "TEXCOORD", 8))
789 nIndex = IDesc.SemanticIndex;
790 if (nIndex == 0)
791 bTC0 = true;
792 else
794 if (nIndex == 1)
796 bTC1[0] = true;
797 if (IDesc.ReadWriteMask)
798 bTC1[1] = true;
800 else if (nIndex == 8)
801 bMorph = true;
804 else if (!strnicmp(IDesc.SemanticName, "COLOR", 5))
806 nIndex = IDesc.SemanticIndex;
807 if (nIndex == 0)
808 bCol = true;
809 else if (nIndex == 1)
810 bSecCol = true;
811 else
813 if (nIndex == 2 || nIndex == 3)
815 bSH[0] = true;
816 if (IDesc.ReadWriteMask)
817 bSH[1] = true;
819 else
820 assert(false);
823 else if (!stricmp(IDesc.SemanticName, "TANGENT"))
825 bTangent[0] = true;
826 if (IDesc.ReadWriteMask)
827 bTangent[1] = true;
829 else if (!stricmp(IDesc.SemanticName, "BITANGENT"))
831 bBitangent[0] = true;
832 if (IDesc.ReadWriteMask)
833 bBitangent[1] = true;
835 else if (!strnicmp(IDesc.SemanticName, "PSIZE", 5) || !strnicmp(IDesc.SemanticName, "AXIS", 4))
837 bPSize = true;
839 else if (!strnicmp(IDesc.SemanticName, "BLENDWEIGHT", 11) || !strnicmp(IDesc.SemanticName, "BLENDINDICES", 12))
841 nIndex = IDesc.SemanticIndex;
842 if (nIndex == 0)
843 bHWSkin = true;
844 else if (nIndex == 1)
845 bMorph = true;
846 else
847 assert(0);
849 else if (!strnicmp(IDesc.SemanticName, "SV_", 3))
851 // SV_ are valid semantics
853 #if CRY_PLATFORM_ORBIS
854 else if (!strnicmp(IDesc.SemanticName, "S_VERTEX_ID", 11) || !strnicmp(IDesc.SemanticName, "S_INSTANCE_ID", 13))
856 // S_VERTEX_ID and S_INSTANCE_ID are valid names
858 #endif
859 else
861 CRY_ASSERT_TRACE(0, ("Invalid SemanticName %s", IDesc.SemanticName));
864 #if CRY_RENDERER_VULKAN
865 pInst->m_VSInputStreams.emplace_back(IDesc.SemanticName, IDesc.SemanticIndex, IDesc.AttributeLocation);
866 #endif
869 mfPostVertexFormat(pInst, pSH, bCol, bNormal, bTC0, bTC1, bPSize, bTangent, bBitangent, bHWSkin, bSH, bVelocity, bMorph);
871 if (pConstantTable != pShaderReflection)
873 SAFE_RELEASE(pShaderReflection);
876 return (InputLayoutHandle)pInst->m_nVertexFormat;
879 void CHWShader_D3D::mfSetDefaultRT(uint64& nAndMask, uint64& nOrMask)
881 uint32 i, j;
882 SShaderGen* pGen = gRenDev->m_cEF.m_pGlobalExt;
884 uint32 nBitsPlatform = 0;
885 if (CParserBin::m_nPlatform == SF_ORBIS)
886 nBitsPlatform |= SHGD_HW_ORBIS;
887 else if (CParserBin::m_nPlatform == SF_DURANGO)
888 nBitsPlatform |= SHGD_HW_DURANGO;
889 else if (CParserBin::m_nPlatform == SF_D3D11)
890 nBitsPlatform |= SHGD_HW_DX11;
891 else if (CParserBin::m_nPlatform == SF_GL4)
892 nBitsPlatform |= SHGD_HW_GL4;
893 else if (CParserBin::m_nPlatform == SF_GLES3)
894 nBitsPlatform |= SHGD_HW_GLES3;
895 else if (CParserBin::m_nPlatform == SF_VULKAN)
896 nBitsPlatform |= SHGD_HW_VULKAN;
898 // Make a mask of flags affected by this type of shader
899 uint32 nType = m_dwShaderType;
900 if (nType)
902 for (i = 0; i < pGen->m_BitMask.size(); i++)
904 SShaderGenBit* pBit = pGen->m_BitMask[i];
905 if (!pBit->m_Mask)
906 continue;
907 if (nBitsPlatform & pBit->m_nDependencyReset)
909 nAndMask &= ~pBit->m_Mask;
910 continue;
912 for (j = 0; j < pBit->m_PrecacheNames.size(); j++)
914 if (pBit->m_PrecacheNames[j] == nType)
916 if (nBitsPlatform & pBit->m_nDependencySet)
917 nOrMask |= pBit->m_Mask;
918 break;
925 //==================================================================================================================
927 static bool sGetMask(char* str, SShaderGen* pGen, uint64& nMask)
929 uint32 i;
931 for (i = 0; i < pGen->m_BitMask.Num(); i++)
933 SShaderGenBit* pBit = pGen->m_BitMask[i];
934 if (!strcmp(str, pBit->m_ParamName.c_str()))
936 nMask |= pBit->m_Mask;
937 return true;
940 return false;
943 void CHWShader::mfValidateTokenData(CResFile* pRes)
945 #ifdef _DEBUG
946 if (pRes == 0)
947 return;
949 bool bTokenValid = true;
950 ResDir* Dir = pRes->mfGetDirectory();
951 for (unsigned int i = 0; i < Dir->size(); i++)
953 CDirEntry* pDE = &(*Dir)[i];
954 if (pDE->GetFlags() & RF_RES_$TOKENS)
956 uint32 nSize = pRes->mfFileRead(pDE);
957 byte* pData = (byte*)pRes->mfFileGetBuf(pDE);
958 if (!pData)
960 bTokenValid = false;
961 break;
964 uint32 nL = *(uint32*)pData;
965 if (CParserBin::m_bEndians)
966 SwapEndian(nL, eBigEndian);
968 if (nL * sizeof(uint32) > nSize)
970 bTokenValid = false;
971 break;
974 int nTableSize = nSize - (4 + nL * sizeof(uint32));
975 if (nTableSize < 0)
977 bTokenValid = false;
978 break;
981 pRes->mfCloseEntry(pDE->GetName(), pDE->GetFlags());
985 if (!bTokenValid)
986 CryFatalError("Invalid token data in shader cache file");
987 #endif
990 void CHWShader::mfValidateDirEntries(CResFile* pRF)
992 #ifdef _DEBUG
993 auto dirEntries = pRF->mfGetDirectory();
994 for (auto it1 = dirEntries->begin(); it1 != dirEntries->end(); it1++)
996 for (auto it2 = it1 + 1; it2 != dirEntries->end(); ++it2)
998 if (it1->GetName() == it2->GetName())
1000 CryFatalError("Duplicate dir entry in shader cache file");
1004 #endif
1008 bool CHWShader_D3D::mfStoreCacheTokenMap(FXShaderToken*& Table, TArray<uint32>*& pSHData, const char* szName)
1010 TArray<byte> Data;
1012 FXShaderTokenItor itor;
1013 uint32 nSize = pSHData->size();
1014 if (CParserBin::m_bEndians)
1016 uint32 nSizeEnd = nSize;
1017 SwapEndian(nSizeEnd, eBigEndian);
1018 Data.Copy((byte*)&nSizeEnd, sizeof(uint32));
1019 for (uint32 i = 0; i < nSize; i++)
1021 uint32 nToken = (*pSHData)[i];
1022 SwapEndian(nToken, eBigEndian);
1023 Data.Copy((byte*)&nToken, sizeof(uint32));
1026 else
1028 Data.Copy((byte*)&nSize, sizeof(uint32));
1029 Data.Copy((byte*)&(*pSHData)[0], nSize * sizeof(uint32));
1031 for (itor = Table->begin(); itor != Table->end(); itor++)
1033 STokenD T = *itor;
1034 if (CParserBin::m_bEndians)
1035 SwapEndian(T.Token, eBigEndian);
1036 Data.Copy((byte*)&T.Token, sizeof(DWORD));
1037 Data.Copy((byte*)T.SToken.c_str(), T.SToken.size() + 1);
1039 if (!Data.size())
1040 return false;
1042 CDirEntry de(szName, Data.size(), RF_RES_$TOKENS);
1043 m_pGlobalCache->m_pRes[CACHE_USER]->mfFileAdd(&de);
1044 SDirEntryOpen* pOE = m_pGlobalCache->m_pRes[CACHE_USER]->mfOpenEntry(de.GetName());
1045 pOE->pData = &Data[0];
1046 m_pGlobalCache->m_pRes[CACHE_USER]->mfFlush();
1047 m_pGlobalCache->m_pRes[CACHE_USER]->mfCloseEntry(de.GetName(), de.GetFlags());
1049 return true;
1052 void CHWShader_D3D::mfGetTokenMap(CResFile* pRes, CDirEntry* pDE, FXShaderToken*& Table, TArray<uint32>*& pSHData)
1054 uint32 i;
1055 int nSize = pRes->mfFileRead(pDE);
1056 byte* pData = (byte*)pRes->mfFileGetBuf(pDE);
1057 if (!pData)
1059 Table = NULL;
1060 return;
1062 Table = new FXShaderToken;
1063 pSHData = new TArray<uint32>;
1064 uint32 nL = *(uint32*)pData;
1065 if (CParserBin::m_bEndians)
1066 SwapEndian(nL, eBigEndian);
1067 pSHData->resize(nL);
1068 if (CParserBin::m_bEndians)
1070 uint32* pTokens = (uint32*)&pData[4];
1071 for (i = 0; i < nL; i++)
1073 uint32 nToken = pTokens[i];
1074 SwapEndian(nToken, eBigEndian);
1075 (*pSHData)[i] = nToken;
1078 else
1080 memcpy(&(*pSHData)[0], &pData[4], nL * sizeof(uint32));
1082 pData += 4 + nL * sizeof(uint32);
1083 nSize -= 4 + nL * sizeof(uint32);
1084 int nOffs = 0;
1086 while (nOffs < nSize)
1088 char* pStr = (char*)&pData[nOffs + sizeof(DWORD)];
1089 DWORD nToken;
1090 LoadUnaligned(pData + nOffs, nToken);
1091 if (CParserBin::m_bEndians)
1092 SwapEndian(nToken, eBigEndian);
1093 int nLen = strlen(pStr) + 1;
1094 STokenD TD;
1095 TD.Token = nToken;
1096 TD.SToken = pStr;
1097 Table->push_back(TD);
1098 nOffs += sizeof(DWORD) + nLen;
1102 bool CHWShader_D3D::mfGetCacheTokenMap(FXShaderToken*& Table, TArray<uint32>*& pSHData, uint64 nMaskGenFX)
1104 if (!m_pGlobalCache || !m_pGlobalCache->isValid())
1106 if (m_pGlobalCache)
1107 m_pGlobalCache->Release(false);
1109 const bool initReadOnly = CRenderer::CV_r_shadersAllowCompilation == 0;
1110 const bool initAsync = CRenderer::CV_r_shadersasyncactivation != 0;
1111 m_pGlobalCache = mfInitCache(NULL, this, true, m_CRC32, initReadOnly, initAsync);
1113 if (!m_pGlobalCache)
1115 assert(false);
1116 return false;
1119 char strName[256];
1120 #if defined(__GNUC__)
1121 cry_sprintf(strName, "$MAP_%llx", nMaskGenFX);
1122 #else
1123 cry_sprintf(strName, "$MAP_%I64x", nMaskGenFX);
1124 #endif
1126 if (Table)
1128 if (m_pGlobalCache->m_pRes[CACHE_READONLY] && m_pGlobalCache->m_pRes[CACHE_READONLY]->mfFileExist(strName))
1129 return true;
1130 if (!m_pGlobalCache->m_pRes[CACHE_USER])
1132 m_pGlobalCache->Release(false);
1133 m_pGlobalCache = mfInitCache(NULL, this, true, m_CRC32, false);
1135 if (!m_pGlobalCache || !m_pGlobalCache->m_pRes[CACHE_USER])
1137 assert(false);
1138 return false;
1140 if (!m_pGlobalCache->m_pRes[CACHE_USER]->mfFileExist(strName))
1142 if (!CRenderer::CV_r_shadersAllowCompilation)
1143 return false;
1145 //CryLogAlways("Storing MAP entry '%s' in shader cache file '%s'", strName, m_pGlobalCache->m_Name.c_str());
1147 return mfStoreCacheTokenMap(Table, pSHData, strName);
1149 return true;
1151 CDirEntry* pDE = nullptr;
1152 CResFile* pRes = nullptr;
1153 for (int i = 0; i < 2; i++)
1155 pRes = m_pGlobalCache->m_pRes[i];
1156 if (!pRes)
1157 continue;
1158 pDE = pRes->mfGetEntry(strName);
1159 if (pDE)
1160 break;
1162 if (!pDE || !pRes)
1164 Warning("Couldn't find tokens MAP entry '%s' in shader cache file '%s'", strName, m_pGlobalCache->m_Name.c_str());
1165 ASSERT_IN_SHADER(0);
1166 return false;
1168 mfGetTokenMap(pRes, pDE, Table, pSHData);
1169 pRes->mfFileClose(pDE->GetName(), pDE->GetFlags());
1171 return true;
1174 //==============================================================================================================================================================
1176 bool CHWShader_D3D::mfGenerateScript(CShader* pSH, SHWSInstance* pInst, std::vector<SCGBind>& InstBindVars, uint32 nFlags, FXShaderToken* Table, TArray<uint32>* pSHData, TArray<char>& sNewScr)
1178 char* cgs = NULL;
1180 uint32 nSFlags = m_Flags;
1181 bool bTempMap = (Table == NULL);
1182 assert((Table && pSHData) || (!Table && !pSHData));
1183 assert(m_pGlobalCache);
1184 if (CParserBin::m_bEditable && !Table) // Fast path for offline shaders builder
1186 Table = &m_TokenTable;
1187 pSHData = &m_TokenData;
1188 bTempMap = false;
1190 else
1192 if (m_pGlobalCache && !(nSFlags & HWSG_GS_MULTIRES))
1193 mfGetCacheTokenMap(Table, pSHData, m_nMaskGenShader);
1194 if (CParserBin::m_bEditable)
1196 if (bTempMap)
1198 SAFE_DELETE(Table);
1199 SAFE_DELETE(pSHData);
1201 Table = &m_TokenTable;
1202 pSHData = &m_TokenData;
1203 bTempMap = false;
1206 if (!(nSFlags & HWSG_GS_MULTIRES))
1208 assert(Table && pSHData);
1209 if (!Table || !pSHData)
1210 return false;
1213 ShaderTokensVec NewTokens;
1215 uint32 eT = eT_unknown;
1217 switch (pInst->m_eClass)
1219 case eHWSC_Vertex:
1220 eT = eT__VS;
1221 break;
1222 case eHWSC_Pixel:
1223 eT = eT__PS;
1224 break;
1225 case eHWSC_Geometry:
1226 eT = eT__GS;
1227 break;
1228 case eHWSC_Hull:
1229 eT = eT__HS;
1230 break;
1231 case eHWSC_Compute:
1232 eT = eT__CS;
1233 break;
1234 case eHWSC_Domain:
1235 eT = eT__DS;
1236 break;
1238 default:
1239 assert(0);
1241 if (eT != eT_unknown)
1242 CParserBin::AddDefineToken(eT, NewTokens);
1244 if (nSFlags & HWSG_GS_MULTIRES)
1246 // Generate script vor VS first;
1247 //@TODO: Do this without global variable
1248 //pInst = s_pCurInstVS;
1249 assert(pInst);
1251 CHWShader_D3D* curVS = (CHWShader_D3D *)s_pCurHWVS;
1252 Table = &curVS->m_TokenTable;
1253 pSHData = &curVS->m_TokenData;
1254 nSFlags = curVS->m_Flags;
1256 bTempMap = false;
1259 // Include runtime mask definitions in the script
1260 SShaderGen* shg = gRenDev->m_cEF.m_pGlobalExt;
1261 if (shg && pInst->m_Ident.m_RTMask)
1263 for (uint32 i = 0; i < shg->m_BitMask.Num(); i++)
1265 SShaderGenBit* bit = shg->m_BitMask[i];
1266 if (!(bit->m_Mask & pInst->m_Ident.m_RTMask))
1267 continue;
1268 CParserBin::AddDefineToken(bit->m_dwToken, NewTokens);
1272 // Include light mask definitions in the script
1273 if (nSFlags & HWSG_SUPPORTS_MULTILIGHTS)
1275 int nLights = pInst->m_Ident.m_LightMask & 0xf;
1276 if (nLights)
1277 CParserBin::AddDefineToken(eT__LT_LIGHTS, NewTokens);
1278 CParserBin::AddDefineToken(eT__LT_NUM, nLights + eT_0, NewTokens);
1279 bool bHasProj = false;
1280 for (int i = 0; i < 4; i++)
1282 int nLightType = (pInst->m_Ident.m_LightMask >> (SLMF_LTYPE_SHIFT + i * SLMF_LTYPE_BITS)) & SLMF_TYPE_MASK;
1283 if (nLightType == SLMF_PROJECTED)
1284 bHasProj = true;
1286 CParserBin::AddDefineToken(eT__LT_0_TYPE + i, nLightType + eT_0, NewTokens);
1288 if (bHasProj)
1289 CParserBin::AddDefineToken(eT__LT_HASPROJ, eT_1, NewTokens);
1291 else if (nSFlags & HWSG_SUPPORTS_LIGHTING)
1293 CParserBin::AddDefineToken(eT__LT_LIGHTS, NewTokens);
1294 int nLightType = (pInst->m_Ident.m_LightMask >> SLMF_LTYPE_SHIFT) & SLMF_TYPE_MASK;
1295 if (nLightType == SLMF_PROJECTED)
1296 CParserBin::AddDefineToken(eT__LT_HASPROJ, eT_1, NewTokens);
1299 // Include modificator mask definitions in the script
1300 if ((nSFlags & HWSG_SUPPORTS_MODIF) && pInst->m_Ident.m_MDMask)
1302 const uint32 tcProjMask = HWMD_TEXCOORD_PROJ;
1303 const uint32 tcMatrixMask = HWMD_TEXCOORD_MATRIX;
1304 const uint32 tcGenObjectLinearMask = HWMD_TEXCOORD_GEN_OBJECT_LINEAR;
1306 if (pInst->m_Ident.m_MDMask & tcProjMask)
1307 CParserBin::AddDefineToken(eT__TT_TEXCOORD_PROJ, NewTokens);
1308 if (pInst->m_Ident.m_MDMask & tcMatrixMask)
1309 CParserBin::AddDefineToken(eT__TT_TEXCOORD_MATRIX, NewTokens);
1310 if (pInst->m_Ident.m_MDMask & tcGenObjectLinearMask)
1311 CParserBin::AddDefineToken(eT__TT_TEXCOORD_GEN_OBJECT_LINEAR, NewTokens);
1314 // Include vertex modificator mask definitions in the script
1315 if ((nSFlags & HWSG_SUPPORTS_VMODIF) && pInst->m_Ident.m_MDVMask)
1317 int nMDV = pInst->m_Ident.m_MDVMask & 0x0fffffff;
1318 int nType = nMDV & 0xf;
1319 if (nType)
1320 CParserBin::AddDefineToken(eT__VT_TYPE, eT_0 + nType, NewTokens);
1321 if ((nMDV & MDV_BENDING) || nType == eDT_Bending)
1323 CParserBin::AddDefineToken(eT__VT_BEND, eT_1, NewTokens);
1324 if (!(nMDV & 0xf))
1326 nType = eDT_Bending;
1327 CParserBin::AddDefineToken(eT__VT_TYPE, eT_0 + nType, NewTokens);
1330 if (nMDV & MDV_DEPTH_OFFSET)
1331 CParserBin::AddDefineToken(eT__VT_DEPTH_OFFSET, eT_1, NewTokens);
1332 if (nMDV & MDV_WIND)
1333 CParserBin::AddDefineToken(eT__VT_WIND, eT_1, NewTokens);
1334 if (nMDV & MDV_DET_BENDING)
1335 CParserBin::AddDefineToken(eT__VT_DET_BEND, eT_1, NewTokens);
1336 if (nMDV & MDV_DET_BENDING_GRASS)
1337 CParserBin::AddDefineToken(eT__VT_GRASS, eT_1, NewTokens);
1338 if (nMDV & ~0xf)
1339 CParserBin::AddDefineToken(eT__VT_TYPE_MODIF, eT_1, NewTokens);
1342 if (nSFlags & HWSG_FP_EMULATION)
1344 CParserBin::AddDefineToken(eT__FT0_COP, eT_0 + (pInst->m_Ident.m_LightMask & 0xff), NewTokens);
1345 CParserBin::AddDefineToken(eT__FT0_AOP, eT_0 + ((pInst->m_Ident.m_LightMask & 0xff00) >> 8), NewTokens);
1347 byte CO_0 = ((pInst->m_Ident.m_LightMask & 0xff0000) >> 16) & 7;
1348 CParserBin::AddDefineToken(eT__FT0_CARG1, eT_0 + CO_0, NewTokens);
1350 byte CO_1 = ((pInst->m_Ident.m_LightMask & 0xff0000) >> 19) & 7;
1351 CParserBin::AddDefineToken(eT__FT0_CARG2, eT_0 + CO_1, NewTokens);
1353 byte AO_0 = ((pInst->m_Ident.m_LightMask & 0xff000000) >> 24) & 7;
1354 CParserBin::AddDefineToken(eT__FT0_AARG1, eT_0 + AO_0, NewTokens);
1356 byte AO_1 = ((pInst->m_Ident.m_LightMask & 0xff000000) >> 27) & 7;
1357 CParserBin::AddDefineToken(eT__FT0_AARG2, eT_0 + AO_1, NewTokens);
1359 if (CO_0 == eCA_Specular || CO_1 == eCA_Specular || AO_0 == eCA_Specular || AO_1 == eCA_Specular)
1360 CParserBin::AddDefineToken(eT__FT_SPECULAR, NewTokens);
1361 if (CO_0 == eCA_Diffuse || CO_1 == eCA_Diffuse || AO_0 == eCA_Diffuse || AO_1 == eCA_Diffuse)
1362 CParserBin::AddDefineToken(eT__FT_DIFFUSE, NewTokens);
1363 if (CO_0 == eCA_Texture || CO_1 == eCA_Texture || AO_0 == eCA_Texture || AO_1 == eCA_Texture)
1364 CParserBin::AddDefineToken(eT__FT_TEXTURE, NewTokens);
1365 if (CO_0 == eCA_Texture1 || (CO_1 == eCA_Texture1) || AO_0 == eCA_Texture1 || AO_1 == eCA_Texture1
1366 || CO_0 == eCA_Previous || (CO_1 == eCA_Previous) || AO_0 == eCA_Previous || AO_1 == eCA_Previous)
1367 CParserBin::AddDefineToken(eT__FT_TEXTURE1, NewTokens);
1368 if (CO_0 == eCA_Normal || CO_1 == eCA_Normal || AO_0 == eCA_Normal || AO_1 == eCA_Normal)
1369 CParserBin::AddDefineToken(eT__FT_NORMAL, NewTokens);
1370 if (CO_0 == eCA_Constant || (CO_1 == eCA_Constant) || AO_0 == eCA_Constant || AO_1 == eCA_Constant
1371 || CO_0 == eCA_Previous || (CO_1 == eCA_Previous) || AO_0 == eCA_Previous || AO_1 == eCA_Previous)
1372 CParserBin::AddDefineToken(eT__FT_PSIZE, NewTokens);
1374 if (nFlags & HWSF_STOREDATA)
1376 int nStreams = pInst->m_Ident.m_LightMask & 0xff;
1377 if (nStreams & (1 << VSF_QTANGENTS))
1378 CParserBin::AddDefineToken(eT__FT_QTANGENT_STREAM, NewTokens);
1379 if (nStreams & (1 << VSF_TANGENTS))
1380 CParserBin::AddDefineToken(eT__FT_TANGENT_STREAM, NewTokens);
1381 if (nStreams & VSM_HWSKIN)
1382 CParserBin::AddDefineToken(eT__FT_SKIN_STREAM, NewTokens);
1383 #if ENABLE_NORMALSTREAM_SUPPORT
1384 if (CParserBin::m_nPlatform & (SF_D3D11 | SF_DURANGO | SF_ORBIS | SF_GL4 | SF_GLES3))
1386 if (nStreams & VSM_NORMALS)
1387 CParserBin::AddDefineToken(eT__FT_NORMAL, NewTokens);
1389 #endif
1390 if (nStreams & VSM_VERTEX_VELOCITY)
1391 CParserBin::AddDefineToken(eT__FT_VERTEX_VELOCITY_STREAM, NewTokens);
1395 int nT = NewTokens.size();
1396 NewTokens.resize(nT + pSHData->size());
1397 memcpy(&NewTokens[nT], &(*pSHData)[0], pSHData->size() * sizeof(uint32));
1399 CParserBin Parser(NULL, pSH);
1400 Parser.Preprocess(1, NewTokens, Table);
1401 CorrectScriptEnums(Parser, pInst, InstBindVars, Table);
1402 RemoveUnaffectedParameters_D3D10(Parser, pInst, InstBindVars);
1403 ConvertBinScriptToASCII(Parser, pInst, InstBindVars, Table, sNewScr);
1404 AddResourceLayoutToScript(pInst, mfProfileString(pInst->m_eClass), m_EntryFunc.c_str(), sNewScr);
1406 // Generate geometry shader
1407 if (m_Flags & HWSG_GS_MULTIRES)
1409 bool bResult = AutoGenMultiresGS(sNewScr, pSH);
1410 if (!bResult)
1411 return false;
1414 if (bTempMap)
1416 SAFE_DELETE(Table);
1417 SAFE_DELETE(pSHData);
1420 /* FILE *fp = gEnv->pCryPak->FOpen("fff", "w");
1421 if (fp)
1423 gEnv->pCryPak->FPrintf(fp, "%s", &sNewScr[0]);
1424 gEnv->pCryPak->FClose (fp);
1427 return sNewScr.Num() && sNewScr[0];
1430 bool CHWShader_D3D::AutoGenMultiresGS(TArray<char>& sNewScr, CShader *pSH)
1432 CHWShader_D3D* curVS = (CHWShader_D3D *)s_pCurHWVS;
1433 char szEntryVS[128];
1434 strcpy(szEntryVS, curVS->m_EntryFunc.c_str());
1435 strcat(szEntryVS, "(");
1436 char *szStart = strstr(&sNewScr[0], szEntryVS);
1437 assert(szStart);
1438 if (szStart)
1440 char *szEnd = szStart - 1;
1441 while (*szEnd == 0x20) --szEnd;
1442 char *szS = szEnd;
1443 while (*szS > 0x20) --szS;
1444 char szStrName[128];
1445 ptrdiff_t nSize = szEnd - szS;
1446 strncpy(szStrName, &szS[1], nSize);
1447 szStrName[nSize] = 0;
1449 char szStruct[128];
1450 strcpy(szStruct, "struct ");
1451 strcat(szStruct, szStrName);
1452 char *szStrStart = strstr(&sNewScr[0], szStruct);
1453 assert(szStrStart);
1455 char *szStrEnd = strstr(szStrStart, "};");
1456 szStrEnd += 2;
1458 char szPosName[128];
1459 char *szPosA = strstr(szStrStart, ":POSITION");
1460 if (!szPosA || szPosA >= szStrEnd)
1461 szPosA = strstr(szStrStart, ":SV_Position");
1462 if (!szPosA || szPosA >= szStrEnd)
1464 #if !defined(_RELEASE)
1465 CRY_ASSERT_MESSAGE(false, "Cannot generate a GS for a VS with no SV_Position output");
1466 #endif
1467 return false;
1469 char *szPosAB = szPosA - 1;
1470 while (*szPosAB == 0x20) --szPosAB;
1471 char *szP = szPosAB;
1472 while (*szP > 0x20) --szP;
1473 nSize = szPosAB - szP;
1474 strncpy(szPosName, &szP[1], nSize);
1475 szPosName[nSize] = 0;
1477 TArray<char> szNewS;
1478 //szNewS.Copy(&sNewScr[0], szStrStart - &sNewScr[0]);
1479 szNewS.Copy(szStrStart, uint32(szStrEnd-szStrStart)+1);
1481 m_EntryFunc.Format("%s_GS", curVS->m_EntryFunc.c_str());
1483 string GSDefine;
1484 GSDefine.Format(
1485 "#define NV_VR_FASTGS_FUNCTION_NAME %s\n"
1486 "#define NV_VR_FASTGS_PASSTHROUGH_STRUCT %s\n"
1487 "#define NV_VR_FASTGS_OUTPUT_STRUCT %s_gs\n"
1488 "#define NV_VR_FASTGS_POSITION_ATTRIBUTE %s\n\n",
1489 m_EntryFunc.c_str(), szStrName, szStrName, szPosName);
1490 szNewS.Copy(GSDefine.c_str(), GSDefine.size());
1492 ShaderTokensVec NewTokens;
1494 uint32 eT = eT__GS;
1495 CParserBin::AddDefineToken(eT, NewTokens);
1497 // Include runtime mask definitions in the script
1498 SShaderGen* shg = gRenDev->m_cEF.m_pGlobalExt;
1499 if (shg && m_pCurInst->m_Ident.m_RTMask)
1501 for (uint32 i = 0; i < shg->m_BitMask.Num(); i++)
1503 SShaderGenBit* bit = shg->m_BitMask[i];
1504 if (!(bit->m_Mask & m_pCurInst->m_Ident.m_RTMask))
1505 continue;
1506 CParserBin::AddDefineToken(bit->m_dwToken, NewTokens);
1509 int nT = NewTokens.size();
1510 NewTokens.resize(nT + m_TokenData.size());
1511 memcpy(&NewTokens[nT], &m_TokenData[0], m_TokenData.size() * sizeof(uint32));
1513 std::vector<SCGBind> InstBindVars;
1514 CParserBin Parser(NULL, pSH);
1515 Parser.Preprocess(1, NewTokens, &m_TokenTable);
1516 ConvertBinScriptToASCII(Parser, m_pCurInst, InstBindVars, &m_TokenTable, szNewS);
1518 sNewScr.Copy(szNewS);
1520 else
1521 return false;
1523 return true;
1526 /*static uint32 sFindVar(CParserBin& Parser, int& nStart)
1528 const uint32 *pTokens = Parser.GetTokens(0);
1529 int nLast = Parser.GetNumTokens()-1;
1531 while (nStart <= nLast)
1533 if (pTokens[nStart] == eT_br_cv_1)
1535 int nRecurs = 1;
1536 nStart++;
1537 while(nStart <= nLast)
1539 if (pTokens[nStart++] == eT_br_cv_1)
1540 nRecurs++;
1541 else
1542 if (pTokens[nStart++] == eT_br_cv_2)
1544 nRecurs--;
1545 if (nRecurs == 0)
1546 break;
1550 if (nStart <= nLast)
1551 break;
1552 if (pTokens[nStart] >= eT_float && pTokens[nStart] <= eT_int)
1554 if (nStart+3 <= nLast)
1556 uint32 nName = pTokens[nStart+1];
1557 uint32 nN = pTokens[nStart+2];
1558 if (nN != eT_colon)
1560 if (nN == eT_br_sq_1)
1562 assert(pTokens[nStart+4] == eT_br_sq_2);
1563 if (pTokens[nStart+4] == eT_br_sq_2)
1564 nN = pTokens[nStart+5];
1567 if (nN == eT_colon)
1568 return nName;
1569 nStart += 3;
1571 else
1572 break;
1574 nStart++;
1576 nStart = -1;
1577 return 0;
1580 bool sIsAffectFuncs(CParserBin& Parser, uint32 nName)
1582 const uint32 *pTokens = Parser.GetTokens(0);
1583 int nStart = 0;
1584 int nLast = Parser.GetNumTokens()-1;
1586 while (nStart <= nLast)
1588 if (pTokens[nStart] == eT_br_cv_1)
1590 int nRecurs = 1;
1591 nStart++;
1592 int nBegin = nStart;
1593 while(nStart <= nLast)
1595 if (pTokens[nStart++] == eT_br_cv_1)
1596 nRecurs++;
1597 else
1598 if (pTokens[nStart++] == eT_br_cv_2)
1600 nRecurs--;
1601 if (nRecurs == 0)
1602 break;
1605 if (nStart <= nLast)
1606 break;
1607 int nPos = Parser.FindToken(nBegin, nStart, nName);
1608 if (nPos >= 0)
1609 return true;
1611 nStart++;
1613 return false;
1616 void CHWShader_D3D::RemoveUnaffectedParameters_D3D10(CParserBin& Parser, SHWSInstance* pInst, std::vector<SCGBind>& InstBindVars)
1618 int nPos = Parser.FindToken(0, Parser.m_Tokens.size() - 1, eT_cbuffer);
1619 while (nPos >= 0)
1621 uint32 nName = Parser.m_Tokens[nPos + 1];
1622 if (nName == eT_PER_BATCH || nName == eT_PER_INSTANCE)
1624 int nPosEnd = Parser.FindToken(nPos + 3, Parser.m_Tokens.size() - 1, eT_br_cv_2);
1625 assert(nPosEnd >= 0);
1626 int nPosN = Parser.FindToken(nPos + 1, Parser.m_Tokens.size() - 1, eT_br_cv_1);
1627 assert(nPosN >= 0);
1628 nPosN++;
1629 while (nPosN < nPosEnd)
1631 uint32 nT = Parser.m_Tokens[nPosN + 1];
1632 int nPosCode = Parser.FindToken(nPosEnd + 1, Parser.m_Tokens.size() - 1, nT);
1633 if (nPosCode < 0)
1635 assert(nPosN > 0 && nPosN < (int)Parser.m_Tokens.size());
1636 if (InstBindVars.size())
1638 size_t i = 0;
1639 CCryNameR nm(Parser.GetString(nT));
1640 for (; i < InstBindVars.size(); i++)
1642 SCGBind& b = InstBindVars[i];
1643 if (b.m_Name == nm)
1644 break;
1646 if (i == InstBindVars.size())
1647 Parser.m_Tokens[nPosN] = eT_comment;
1649 else
1650 Parser.m_Tokens[nPosN] = eT_comment;
1652 nPosN = Parser.FindToken(nPosN + 2, nPosEnd, eT_semicolumn);
1653 assert(nPosN >= 0);
1654 nPosN++;
1656 nPos = Parser.FindToken(nPosEnd + 1, Parser.m_Tokens.size() - 1, eT_cbuffer);
1658 else
1659 nPos = Parser.FindToken(nPos + 2, Parser.m_Tokens.size() - 1, eT_cbuffer);
1661 //#else
1662 /*int nStart = 0;
1663 while (true)
1665 uint32 nName = sFindVar(Parser, nStart);
1666 if (nStart < 0)
1667 break;
1668 bool bAffect = sIsAffectFuncs(Parser, nName);
1669 if (!bAffect)
1670 Parser.m_Tokens[nStart] = eT_comment;
1671 nStart++;
1673 //#endif
1676 struct SStructData
1678 uint32 m_nName;
1679 uint32 m_nTCs;
1680 int m_nPos;
1683 void CHWShader_D3D::CorrectScriptEnums(CParserBin& Parser, SHWSInstance* pInst, std::vector<SCGBind>& InstBindVars, FXShaderToken* Table)
1685 // correct enumeration of TEXCOORD# interpolators after preprocessing
1686 int nCur = 0;
1687 int nSize = Parser.m_Tokens.size();
1688 uint32* pTokens = &Parser.m_Tokens[0];
1689 int nInstParam = 0;
1690 const uint32 Toks[] = { eT_TEXCOORDN, eT_TEXCOORDN_centroid, eT_unknown };
1692 std::vector<SStructData> SData;
1693 uint32 i;
1694 while (true)
1696 nCur = Parser.FindToken(nCur, nSize - 1, eT_struct);
1697 if (nCur < 0)
1698 break;
1699 int nLastStr = Parser.FindToken(nCur, nSize - 1, eT_br_cv_2);
1700 assert(nLastStr >= 0);
1701 if (nLastStr < 0)
1702 break;
1703 bool bNested = false;
1704 for (i = 0; i < SData.size(); i++)
1706 SStructData& Data = SData[i];
1707 Data.m_nPos = Parser.FindToken(nCur, nLastStr, Data.m_nName);
1708 if (Data.m_nPos > 0)
1709 bNested = true;
1711 uint32 nName = pTokens[nCur + 1];
1712 int n = 0;
1713 while (nCur < nLastStr)
1715 int nTN = Parser.FindToken(nCur, nLastStr, Toks);
1716 if (nTN < 0)
1718 nCur = nLastStr + 1;
1719 break;
1721 int nNested = 0;
1722 if (bNested)
1724 for (i = 0; i < SData.size(); i++)
1726 SStructData& Data = SData[i];
1727 if (Data.m_nPos > 0 && nTN > Data.m_nPos)
1728 nNested += Data.m_nTCs;
1731 assert(pTokens[nTN - 1] == eT_colon);
1732 int nArrSize = 1;
1733 uint32 nTokName;
1734 if (pTokens[nTN - 2] == eT_br_sq_2)
1736 nArrSize = pTokens[nTN - 3] - eT_0;
1737 if ((unsigned int) nArrSize > 15)
1739 const char* szArrSize = Parser.GetString(pTokens[nTN - 3], *Table);
1740 nArrSize = szArrSize ? atoi(szArrSize) : 0;
1742 assert(pTokens[nTN - 4] == eT_br_sq_1);
1743 //const char *szName = Parser.GetString(pTokens[nTN-5], *Table);
1744 nTokName = pTokens[nTN - 5];
1746 else
1748 uint32 nType = pTokens[nTN - 3];
1749 assert(nType == eT_float || nType == eT_float2 || nType == eT_float3 || nType == eT_float4 || nType == eT_float4x4 || nType == eT_float3x4 || nType == eT_float2x4 || nType == eT_float3x3 ||
1750 nType == eT_half || nType == eT_half2 || nType == eT_half3 || nType == eT_half4 || nType == eT_half4x4 || nType == eT_half3x4 || nType == eT_half2x4 || nType == eT_half3x3);
1751 if (nType == eT_float4x4 || nType == eT_half4x4)
1752 nArrSize = 4;
1753 else if (nType == eT_float3x4 || nType == eT_float3x3 || nType == eT_half3x4 || nType == eT_half3x3)
1754 nArrSize = 3;
1755 else if (nType == eT_float2x4 || nType == eT_half2x4)
1756 nArrSize = 2;
1757 nTokName = pTokens[nTN - 2];
1759 assert(nArrSize > 0 && nArrSize < 16);
1761 EToken eT = (pTokens[nTN] == eT_TEXCOORDN) ? eT_TEXCOORD0 : eT_TEXCOORD0_centroid;
1763 pTokens[nTN] = n + nNested + eT;
1764 n += nArrSize;
1765 nCur = nTN + 1;
1767 SStructData SD;
1768 SD.m_nName = nName;
1769 SD.m_nPos = -1;
1770 SD.m_nTCs = n;
1771 SData.push_back(SD);
1773 if (InstBindVars.size())
1774 qsort(&InstBindVars[0], InstBindVars.size(), sizeof(SCGBind), CGBindCallback);
1775 pInst->m_nNumInstAttributes = nInstParam;
1778 static int sFetchInst(uint32& nCur, uint32* pTokens, uint32 nT, std::vector<uint32>& Parameter)
1780 while (true)
1782 uint32 nTok = pTokens[nCur];
1783 if (nTok != eT_br_rnd_1 && nTok != eT_br_rnd_2 && nTok != eT_comma)
1784 break;
1785 nCur++;
1787 int nC = 0;
1788 Parameter.push_back(pTokens[nCur]);
1789 nCur++;
1790 while (pTokens[nCur] == eT_dot)
1792 nC = 2;
1793 Parameter.push_back(pTokens[nCur]);
1794 Parameter.push_back(pTokens[nCur + 1]);
1795 nCur += 2;
1797 return nC;
1800 static void sCR(TArray<char>& Text, int nLevel)
1802 Text.AddElem('\n');
1803 for (int i = 0; i < nLevel; i++)
1805 Text.AddElem(' ');
1806 Text.AddElem(' ');
1810 bool CHWShader_D3D::ConvertBinScriptToASCII(CParserBin& Parser, SHWSInstance* pInst, std::vector<SCGBind>& InstBindVars, FXShaderToken* Table, TArray<char>& Text)
1812 uint32 i;
1813 bool bRes = true;
1815 /*if (pInst->m_RTMask == 0x2000020000680104)
1817 TArray<char> TempTx;
1818 CParserBin::ConvertToAscii(&Parser.m_Tokens[0], Parser.m_Tokens.size(), *Table, TempTx);
1819 FILE *fp = gEnv->pCryPak->FOpen("inst.txt", "w");
1820 if (fp)
1822 gEnv->pCryPak->FPrintf(fp, "%s", &TempTx[0]);
1823 gEnv->pCryPak->FClose (fp);
1826 uint32* pTokens = &Parser.m_Tokens[0];
1827 uint32 nT = Parser.m_Tokens.size();
1828 const char* szPrev = " ";
1829 int nLevel = 0;
1830 for (i = 0; i < nT; i++)
1832 uint32 nToken = pTokens[i];
1833 if (nToken == 0)
1835 Text.Copy("\n", 1);
1836 continue;
1838 if (nToken == eT_skip)
1840 i++;
1841 continue;
1843 if (nToken == eT_skip_1)
1845 while (i < nT)
1847 nToken = pTokens[i];
1848 if (nToken == eT_skip_2)
1849 break;
1850 i++;
1852 assert(i < nT);
1853 continue;
1855 if (nToken == eT_fetchinst)
1857 char str[512];
1858 i++;
1859 std::vector<uint32> ParamDst, ParamSrc;
1860 TArray<char> sParamDstFull, sParamDstName, sParamSrc;
1861 int nDst = sFetchInst(i, &Parser.m_Tokens[0], Parser.m_Tokens.size(), ParamDst);
1862 assert(Parser.m_Tokens[i] == eT_eq);
1863 if (Parser.m_Tokens[i] != eT_eq)
1865 // Should never happen
1866 int n = CParserBin::FindToken(i, Parser.m_Tokens.size() - 1, &Parser.m_Tokens[0], eT_semicolumn);
1867 if (n > 0)
1868 i = n + 1;
1869 continue;
1871 i++;
1872 int nSrc = sFetchInst(i, &Parser.m_Tokens[0], Parser.m_Tokens.size(), ParamSrc);
1873 CParserBin::ConvertToAscii(&ParamDst[0], ParamDst.size(), *Table, sParamDstFull);
1874 CParserBin::ConvertToAscii(&ParamDst[nDst], 1, *Table, sParamDstName);
1875 CParserBin::ConvertToAscii(&ParamSrc[nSrc], 1, *Table, sParamSrc);
1876 assert(strncmp(&sParamSrc[0], "Inst", 4) == 0);
1879 sParamSrc.Free();
1880 CParserBin::ConvertToAscii(&ParamSrc[0], ParamSrc.size(), *Table, sParamSrc);
1881 cry_sprintf(str, "%s = %s;\n", &sParamDstFull[0], &sParamSrc[0]);
1882 Text.Copy(str, strlen(str));
1884 while (Parser.m_Tokens[i] != eT_semicolumn)
1886 i++;
1888 continue;
1890 const char* szStr = CParserBin::GetString(nToken, *Table, false);
1891 assert(szStr);
1892 if (!szStr || !szStr[0])
1894 assert(0);
1895 bRes = CParserBin::CorrectScript(pTokens, i, nT, Text);
1897 else
1899 #if defined(_DEBUG) && !CRY_PLATFORM_ORBIS
1900 int n = 0;
1901 while (szStr[n])
1903 char c = szStr[n++];
1904 bool bASC = isascii(c);
1905 assert(bASC);
1907 #endif
1908 if (nToken == eT_semicolumn || nToken == eT_br_cv_1)
1910 if (nToken == eT_br_cv_1)
1912 sCR(Text, nLevel);
1913 nLevel++;
1915 Text.Copy(szStr, strlen(szStr));
1916 if (nToken == eT_semicolumn)
1918 if (i + 1 < nT && pTokens[i + 1] == eT_br_cv_2)
1919 sCR(Text, nLevel - 1);
1920 else
1921 sCR(Text, nLevel);
1923 else if (i + 1 < nT)
1925 if (pTokens[i + 1] < eT_br_rnd_1 || pTokens[i + 1] >= eT_float)
1926 sCR(Text, nLevel);
1929 else
1931 if (i + 1 < nT)
1933 if (Text.Num())
1935 char cPrev = Text[Text.Num() - 1];
1936 if (!SkipChar((uint8)cPrev) && !SkipChar((uint8)szStr[0]))
1937 Text.AddElem(' ');
1940 Text.Copy(szStr, strlen(szStr));
1941 if (nToken == eT_br_cv_2)
1943 nLevel--;
1944 if (i + 1 < nT && pTokens[i + 1] != eT_semicolumn)
1945 sCR(Text, nLevel);
1950 Text.AddElem(0);
1952 return bRes;
1955 int OrigToBase64Size(int orig_size)
1957 return ((orig_size + 2) / 3) * 4;
1960 static const uint8 BASE64_TABLE[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1962 void Base64EncodeBuffer(const void* orig_buf, int orig_buf_size, void* b64_buf)
1964 const uint8* p = (const uint8*)orig_buf;
1965 uint8* q = (uint8*)b64_buf;
1966 int w;
1968 for (int i = 0, e = orig_buf_size / 3; i < e; ++i, p += 3, q += 4)
1970 // assuming little endian
1971 w = (p[0] << 16) | (p[1] << 8) | p[2];
1972 q[0] = BASE64_TABLE[w >> 18];
1973 q[1] = BASE64_TABLE[(w >> 12) & 0x3F];
1974 q[2] = BASE64_TABLE[(w >> 6) & 0x3F];
1975 q[3] = BASE64_TABLE[w & 0x3F];
1978 switch (orig_buf_size % 3)
1980 case 1:
1981 w = p[0];
1982 q[0] = BASE64_TABLE[w >> 2];
1983 q[1] = BASE64_TABLE[(w << 4) & 0x3F];
1984 q[2] = '=';
1985 q[3] = '=';
1986 break;
1987 case 2:
1988 w = (p[0] << 8) | p[1];
1989 q[0] = BASE64_TABLE[w >> 10];
1990 q[1] = BASE64_TABLE[(w >> 4) & 0x3F];
1991 q[2] = BASE64_TABLE[(w << 2) & 0x3F];
1992 q[3] = '=';
1993 break;
1997 bool CHWShader_D3D::AddResourceLayoutToScript(SHWSInstance* pInst, const char* szProfile, const char* pFunCCryName, TArray<char>& Scr)
1999 #if CRY_RENDERER_VULKAN
2000 if (auto pEncodedLayout = GetDeviceObjectFactory().LookupResourceLayoutEncoding(pInst->m_Ident.m_pipelineState.VULKAN.resourceLayoutHash))
2002 const int TempBufferSize = 4096;
2003 int bin[TempBufferSize];
2004 int pointer = 0;
2006 bin[pointer++] = strlen(szProfile);
2007 bin[pointer + ((strlen(szProfile) + 3) / 4) - 1] = 0;
2008 memcpy(&bin[pointer], szProfile, strlen(szProfile));
2009 pointer += (strlen(szProfile) + 3) / 4;
2011 bin[pointer++] = strlen(pFunCCryName);
2012 bin[pointer + ((strlen(pFunCCryName) + 3) / 4) - 1] = 0;
2013 memcpy(&bin[pointer], pFunCCryName, strlen(pFunCCryName));
2014 pointer += (strlen(pFunCCryName) + 3) / 4;
2016 CRY_ASSERT(TempBufferSize - pointer - pEncodedLayout->size() > 0);
2017 memcpy(&bin[pointer], pEncodedLayout->data(), pEncodedLayout->size());
2018 pointer += (pEncodedLayout->size() + 3) / 4;
2020 // vertex input description: currently disabled.
2021 bin[pointer++] = 0;
2022 bin[pointer++] = 0;
2024 string head = "/*\n";
2025 string tail = "\n*/\n\n";
2027 Scr.Insert(0, head.length() + OrigToBase64Size(pointer * 4) + tail.length());
2029 memcpy(&Scr[0], head.c_str(), head.length());
2030 Base64EncodeBuffer(bin, pointer * 4, &Scr[head.length()]);
2031 memcpy(&Scr[head.length() + OrigToBase64Size(pointer * 4)], tail.c_str(), tail.length());
2033 return true;
2035 #endif
2037 return false;
2040 void CHWShader_D3D::mfGetSrcFileName(char* srcName, int nSize)
2042 if (!srcName || nSize <= 0)
2043 return;
2044 if (!m_NameSourceFX.empty())
2046 cry_strcpy(srcName, nSize, m_NameSourceFX.c_str());
2047 return;
2049 cry_strcpy(srcName, nSize, gRenDev->m_cEF.m_HWPath);
2050 if (m_eSHClass == eHWSC_Vertex)
2051 cry_strcat(srcName, nSize, "Declarations/CGVShaders/");
2052 else if (m_eSHClass == eHWSC_Pixel)
2053 cry_strcat(srcName, nSize, "Declarations/CGPShaders/");
2054 else
2055 cry_strcat(srcName, nSize, "Declarations/CGGShaders/");
2056 cry_strcat(srcName, nSize, GetName());
2057 cry_strcat(srcName, nSize, ".crycg");
2060 void CHWShader_D3D::mfGenName(SHWSInstance* pInst, char* dstname, int nSize, byte bType)
2062 if (bType)
2063 CHWShader::mfGenName(pInst->m_Ident.m_GLMask, pInst->m_Ident.m_RTMask, pInst->m_Ident.m_LightMask, pInst->m_Ident.m_MDMask, pInst->m_Ident.m_MDVMask, pInst->m_Ident.m_pipelineState.opaque, pInst->m_eClass, dstname, nSize, bType);
2064 else
2065 CHWShader::mfGenName(0, 0, 0, 0, 0, 0, eHWSC_Num, dstname, nSize, bType);
2068 void CHWShader_D3D::mfGetDstFileName(SHWSInstance* pInst, CHWShader_D3D* pSH, char* dstname, int nSize, byte bType)
2070 cry_strcpy(dstname, nSize, gRenDev->m_cEF.m_ShadersCache);
2072 if (pSH->m_eSHClass == eHWSC_Vertex)
2074 if (bType == 1 || bType == 4)
2075 cry_strcat(dstname, nSize, "CGVShaders/Debug/");
2076 else if (bType == 0)
2077 cry_strcat(dstname, nSize, "CGVShaders/");
2078 else if (bType == 2 || bType == 3)
2079 cry_strcat(dstname, nSize, "CGVShaders/Pending/");
2081 else if (pSH->m_eSHClass == eHWSC_Pixel)
2083 if (bType == 1 || bType == 4)
2084 cry_strcat(dstname, nSize, "CGPShaders/Debug/");
2085 else if (bType == 0)
2086 cry_strcat(dstname, nSize, "CGPShaders/");
2087 else if (bType == 2 || bType == 3)
2088 cry_strcat(dstname, nSize, "CGPShaders/Pending/");
2090 else if (GEOMETRYSHADER_SUPPORT && pSH->m_eSHClass == eHWSC_Geometry)
2092 if (bType == 1 || bType == 4)
2093 cry_strcat(dstname, nSize, "CGGShaders/Debug/");
2094 else if (bType == 0)
2095 cry_strcat(dstname, nSize, "CGGShaders/");
2096 else if (bType == 2 || bType == 3)
2097 cry_strcat(dstname, nSize, "CGGShaders/Pending/");
2099 else if (GEOMETRYSHADER_SUPPORT && pSH->m_eSHClass == eHWSC_Hull)
2101 if (bType == 1 || bType == 4)
2102 cry_strcat(dstname, nSize, "CGHShaders/Debug/");
2103 else if (bType == 0)
2104 cry_strcat(dstname, nSize, "CGHShaders/");
2105 else if (bType == 2 || bType == 3)
2106 cry_strcat(dstname, nSize, "CGHShaders/Pending/");
2108 else if (GEOMETRYSHADER_SUPPORT && pSH->m_eSHClass == eHWSC_Domain)
2110 if (bType == 1 || bType == 4)
2111 cry_strcat(dstname, nSize, "CGDShaders/Debug/");
2112 else if (bType == 0)
2113 cry_strcat(dstname, nSize, "CGDShaders/");
2114 else if (bType == 2 || bType == 3)
2115 cry_strcat(dstname, nSize, "CGDShaders/Pending/");
2117 else if (GEOMETRYSHADER_SUPPORT && pSH->m_eSHClass == eHWSC_Compute)
2119 if (bType == 1 || bType == 4)
2120 cry_strcat(dstname, nSize, "CGCShaders/Debug/");
2121 else if (bType == 0)
2122 cry_strcat(dstname, nSize, "CGCShaders/");
2123 else if (bType == 2 || bType == 3)
2124 cry_strcat(dstname, nSize, "CGCShaders/Pending/");
2127 cry_strcat(dstname, nSize, pSH->GetName());
2129 if (bType == 2)
2130 cry_strcat(dstname, nSize, "_out");
2132 if (bType == 0)
2134 char* s = strchr(dstname, '(');
2135 if (s)
2136 s[0] = 0;
2139 char szGenName[256];
2140 mfGenName(pInst, szGenName, 256, bType);
2142 cry_strcat(dstname, nSize, szGenName);
2145 //========================================================================================================
2146 // Binary cache support
2148 SShaderCache::~SShaderCache()
2150 if (m_pStreamInfo)
2152 CResFile* pRes = m_pStreamInfo->m_pRes;
2153 bool bWarn = false;
2154 if (pRes)
2156 assert(pRes == m_pRes[0] || pRes == m_pRes[1]);
2157 assert(!pRes->mfIsDirStreaming());
2158 //bWarn = pRes->mfIsDirStreaming();
2160 /*if (m_pStreamInfo->m_EntriesQueue.size())
2161 bWarn = true;
2162 if (bWarn)
2163 Warning("Warning: SShader`Cache::~SShaderCache(): '%s' Streaming tasks is still in progress!: %d", m_Name.c_str(), m_pStreamInfo->m_EntriesQueue.size());*/
2165 m_pStreamInfo->AbortJobs();
2168 CHWShader::m_ShaderCache.erase(m_Name);
2169 SAFE_DELETE(m_pRes[CACHE_USER]);
2170 SAFE_DELETE(m_pRes[CACHE_READONLY]);
2171 SAFE_RELEASE(m_pStreamInfo);
2174 void SShaderCache::Cleanup()
2176 if (m_pRes[0])
2177 m_pRes[0]->mfDeactivate(true);
2178 if (m_pRes[1])
2179 m_pRes[1]->mfDeactivate(true);
2182 bool SShaderCache::isValid()
2184 return ((m_pRes[CACHE_READONLY] || m_pRes[CACHE_USER]) && CParserBin::m_nPlatform == m_nPlatform);
2187 int SShaderCache::Size()
2189 int nSize = sizeof(SShaderCache);
2191 if (m_pRes[0])
2192 nSize += m_pRes[0]->Size();
2193 if (m_pRes[1])
2194 nSize += m_pRes[1]->Size();
2196 return nSize;
2198 int SShaderDevCache::Size()
2200 int nSize = sizeof(SShaderDevCache);
2202 nSize += m_DeviceShaders.size() * sizeof(SD3DShader);
2204 return nSize;
2207 void SShaderCache::GetMemoryUsage(ICrySizer* pSizer) const
2209 pSizer->AddObject(this, sizeof(*this));
2210 pSizer->AddObject(m_pRes[0]);
2211 pSizer->AddObject(m_pRes[1]);
2214 bool SShaderCache::ReadResource(CResFile* rf, int nCache)
2216 if (CRenderer::CV_r_shadersdebug == 3 || CRenderer::CV_r_shadersdebug == 4)
2217 iLog->Log("---Shader Cache: Loading into in-memory cache %s", rf->mfGetFileName());
2219 CResFileOpenScope rfOpenGuard(rf);
2221 auto handle = rfOpenGuard.getHandle()->mfGetHandle();
2222 if (!handle)
2224 // Open without streaming
2225 if (!rfOpenGuard.open(RA_READ | (CParserBin::m_bEndians ? RA_ENDIANS : 0),
2226 &gRenDev->m_cEF.m_ResLookupDataMan[nCache],
2227 nullptr))
2228 return false;
2229 handle = rfOpenGuard.getHandle()->mfGetHandle();
2230 if (!handle)
2231 return false;
2234 const auto librarySize = rfOpenGuard.getHandle()->mfGetResourceSize();
2235 const auto name = rfOpenGuard.getHandle()->mfGetFileName();
2236 if (librarySize > 0)
2238 m_pBinary[nCache] = std::unique_ptr<byte[]>(new byte[librarySize]);
2239 gEnv->pCryPak->FSeek(handle, 0, SEEK_SET);
2240 const auto readBytes = gEnv->pCryPak->FReadRaw(m_pBinary[nCache].get(), librarySize, 1, handle);
2241 if (readBytes != 1)
2243 CryWarning(EValidatorModule::VALIDATOR_MODULE_RENDERER, EValidatorSeverity::VALIDATOR_WARNING, "SShaderCache: \"%s\" invalid!", name);
2244 m_pBinary[nCache] = nullptr;
2246 return false;
2249 return true;
2252 return false;
2255 std::pair<std::unique_ptr<byte[]>, uint32> SShaderCache::DecompressResource(int resVersion, int i, size_t offset, size_t size, bool swapEndian)
2257 using ReturnType = std::pair<std::unique_ptr<byte[]>, size_t>;
2259 uint32 decompressedSize = 0;
2260 std::unique_ptr<byte[]> pData = nullptr;
2262 const auto buf = m_pBinary[i].get() + offset;
2264 switch(resVersion)
2266 case RESVERSION_LZSS:
2267 decompressedSize = *reinterpret_cast<uint32*>(buf);
2268 if (size >= 10000000)
2269 return ReturnType{};
2270 if (swapEndian)
2271 SwapEndian(decompressedSize, eBigEndian);
2272 pData = std::unique_ptr<byte[]>(new byte[decompressedSize]);
2273 if (!pData)
2275 CryWarning(EValidatorModule::VALIDATOR_MODULE_RENDERER, EValidatorSeverity::VALIDATOR_ERROR, "FileRead - Allocation fault");
2276 return ReturnType{};
2278 if (!Decodem(&buf[4], pData.get(), size - 4, decompressedSize))
2280 CryWarning(EValidatorModule::VALIDATOR_MODULE_RENDERER, EValidatorSeverity::VALIDATOR_ERROR, "FileRead - Decodem fault");
2281 return ReturnType{};
2284 break;
2286 case RESVERSION_LZMA:
2287 uint64 outSize64;
2288 if (Lzma86_GetUnpackSize(buf, size, &outSize64) != 0)
2290 CryWarning(EValidatorModule::VALIDATOR_MODULE_RENDERER, EValidatorSeverity::VALIDATOR_ERROR, "FileRead - data error");
2291 return ReturnType{};
2293 decompressedSize = static_cast<uint32>(outSize64);
2294 if (decompressedSize != 0)
2296 pData = std::unique_ptr<byte[]>(new byte[decompressedSize]);
2297 if (!pData)
2299 CryWarning(EValidatorModule::VALIDATOR_MODULE_RENDERER, EValidatorSeverity::VALIDATOR_ERROR, "FileRead - can't allocate");
2300 return ReturnType{};
2302 size_t sizeOut = decompressedSize;
2303 const auto res = Lzma86_Decode(pData.get(), &sizeOut, buf, &size);
2304 decompressedSize = static_cast<uint32_t>(sizeOut);
2305 if (res != 0)
2307 CryWarning(EValidatorModule::VALIDATOR_MODULE_RENDERER, EValidatorSeverity::VALIDATOR_ERROR, "FileRead - LzmaDecoder error");
2308 return ReturnType{};
2312 break;
2314 case RESVERSION_DEBUG:
2315 decompressedSize = size - 20;
2316 if (decompressedSize < 0 || decompressedSize > 128 * 1024 * 1024)
2318 CryWarning(EValidatorModule::VALIDATOR_MODULE_RENDERER, EValidatorSeverity::VALIDATOR_ERROR, "FileRead - Corrupt DirEntiy size");
2319 return ReturnType{};
2321 pData = std::unique_ptr<byte[]>(new byte[decompressedSize]);
2322 memcpy(pData.get(), &buf[10], decompressedSize);
2324 break;
2327 return std::make_pair(std::move(pData), decompressedSize);
2330 void SShaderDevCache::GetMemoryUsage(ICrySizer* pSizer) const
2332 pSizer->AddObject(this, sizeof(*this));
2333 pSizer->AddObject(m_DeviceShaders);
2336 SShaderDevCache* CHWShader::mfInitDevCache(const char* name, CHWShader* pSH)
2338 SShaderDevCache* pCache = NULL;
2339 FXShaderDevCacheItor it = m_ShaderDevCache.find(CCryNameR(name));
2340 if (it != m_ShaderDevCache.end())
2342 pCache = it->second;
2343 pCache->m_nRefCount++;
2345 else
2347 pCache = new SShaderDevCache;
2348 pCache->m_Name = name;
2350 return pCache;
2353 std::unique_ptr<byte[]> CHWShader_D3D::mfGetCacheItem(uint32& nFlags, int32& nSize)
2355 LOADING_TIME_PROFILE_SECTION(gEnv->pSystem);
2356 SHWSInstance* pInst = m_pCurInst;
2357 std::unique_ptr<byte[]> pData;
2358 nSize = 0;
2359 if (!m_pGlobalCache || !m_pGlobalCache->isValid())
2360 return nullptr;
2362 char name[128];
2363 mfGenName(pInst, name, 128, 1);
2365 CResFile* rf = nullptr;
2366 CDirEntry* de = nullptr;
2368 int nCache;
2369 bool bAsync = false;
2370 int n = CRenderer::CV_r_shadersAllowCompilation == 0 ? 1 : 2;
2371 for (nCache = 0; nCache < n; nCache++)
2373 rf = m_pGlobalCache->m_pRes[nCache];
2374 if (!rf)
2375 continue;
2376 de = rf->mfGetEntry(name, &bAsync);
2377 if (de || bAsync)
2378 break;
2380 if (de)
2382 pInst->m_nCache = nCache;
2384 pInst->m_bAsyncActivating = false;
2386 // Attempt to cache the whole entry
2387 if (!m_pGlobalCache->m_pBinary[nCache] && CRenderer::CV_r_shaderscacheinmemory != 0)
2389 m_pGlobalCache->ReadResource(rf, nCache);
2390 // Needs to be re-read after (re-)opening the cache entry
2391 de = rf->mfGetEntry(name, &bAsync);
2394 if (m_pGlobalCache->m_pBinary[nCache] && CRenderer::CV_r_shaderscacheinmemory != 0)
2396 if (de->IsValid())
2398 // Decompress from library
2399 auto pair = m_pGlobalCache->DecompressResource(rf->mfGetVersion(), nCache, de->GetOffset(), de->GetSize(), rf->RequiresSwapEndianOnRead());
2400 nSize = static_cast<int32>(pair.second);
2401 pData = std::move(pair).first;
2403 if (CRenderer::CV_r_shadersdebug == 3 || CRenderer::CV_r_shadersdebug == 4)
2404 iLog->Log("---Shader Cache: Loaded from in-memory cache %s: 0x%x", rf->mfGetFileName(), de->GetName().get());
2407 else
2409 nSize = rf->mfFileRead(de);
2410 pInst->m_bAsyncActivating = (nSize == -1);
2411 byte* pD = (byte*)rf->mfFileGetBuf(de);
2413 if (pD && nSize > 0)
2415 pData = std::unique_ptr<byte[]>(new byte[nSize]);
2416 memcpy(pData.get(), pD, nSize);
2419 rf->mfFileClose(de->GetName(), de->GetFlags());
2421 if (CRenderer::CV_r_shadersdebug == 3 || CRenderer::CV_r_shadersdebug == 4)
2422 iLog->Log("---Shader Cache: Loaded from disk %s: 0x%x", rf->mfGetFileName(), de->GetName().get());
2425 if (pData && nSize > 0)
2427 if (CParserBin::m_bEndians)
2428 SwapEndian(*reinterpret_cast<SShaderCacheHeaderItem*>(pData.get()), eBigEndian);
2429 pInst->m_DeviceObjectID = de->GetName().get();
2431 if (nCache == CACHE_USER)
2432 nFlags |= HWSG_CACHE_USER;
2433 return pData;
2435 else
2437 pInst->m_bAsyncActivating = bAsync;
2438 return nullptr;
2442 bool CHWShader_D3D::mfAddCacheItem(SShaderCache* pCache, SShaderCacheHeaderItem* pItem, const byte* pData, int nLen, bool bFlush, CCryNameTSCRC Name)
2444 if (!pCache)
2445 return false;
2446 if (!pCache->m_pRes[CACHE_USER])
2447 return false;
2449 if (CRenderer::CV_r_shadersdebug == 3 || CRenderer::CV_r_shadersdebug == 4)
2450 iLog->Log("---Cache: StoredToGlobal %s': 0x%x", pCache->m_pRes[CACHE_USER]->mfGetFileName(), Name.get());
2452 pItem->m_CRC32 = CCrc32::Compute(pData, nLen);
2453 //CryLog("Size: %d: CRC: %x", nLen, pItem->m_CRC32);
2455 byte* pNew = new byte[sizeof(SShaderCacheHeaderItem) + nLen];
2456 if (CParserBin::m_bEndians)
2458 SShaderCacheHeaderItem IT = *pItem;
2459 SwapEndian(IT, eBigEndian);
2460 memcpy(pNew, &IT, sizeof(SShaderCacheHeaderItem));
2462 else
2463 memcpy(pNew, pItem, sizeof(SShaderCacheHeaderItem));
2464 memcpy(&pNew[sizeof(SShaderCacheHeaderItem)], pData, nLen);
2466 CDirEntry de(Name, nLen + sizeof(SShaderCacheHeaderItem), RF_COMPRESS | RF_TEMPDATA);
2467 pCache->m_pRes[CACHE_USER]->mfFileAdd(&de);
2468 SDirEntryOpen* pOE = pCache->m_pRes[CACHE_USER]->mfOpenEntry(de.GetName());
2469 pOE->pData = pNew;
2470 if (bFlush)
2472 pCache->m_pRes[CACHE_USER]->mfFlush();
2474 // Also evict in-memory image of user cache
2475 pCache->m_pBinary[CACHE_USER] = nullptr;
2478 return true;
2481 std::vector<SEmptyCombination> SEmptyCombination::s_Combinations;
2483 bool CHWShader_D3D::mfAddEmptyCombination(CShader* pSH, uint64 nRT, uint64 nGL, uint32 nLT, const SCacheCombination& cmbSaved)
2485 SEmptyCombination Comb;
2486 Comb.nGLNew = m_nMaskGenShader;
2487 Comb.nRTNew = cmbSaved.Ident.m_RTMask & m_nMaskAnd_RT | m_nMaskOr_RT;
2488 Comb.nLTNew = cmbSaved.Ident.m_LightMask;
2489 Comb.nGLOrg = nGL;
2490 Comb.nRTOrg = nRT & m_nMaskAnd_RT | m_nMaskOr_RT;
2491 Comb.nLTOrg = nLT;
2492 Comb.nMD = cmbSaved.Ident.m_MDMask;
2493 Comb.nMDV = cmbSaved.Ident.m_MDVMask;
2494 if (m_eSHClass == eHWSC_Pixel)
2496 Comb.nMD &= ~HWMD_TEXCOORD_FLAG_MASK;
2497 Comb.nMDV = 0;
2500 Comb.pShader = this;
2501 if (Comb.nRTNew != Comb.nRTOrg || Comb.nGLNew != Comb.nGLOrg || Comb.nLTNew != Comb.nLTOrg)
2502 SEmptyCombination::s_Combinations.push_back(Comb);
2504 m_nMaskGenShader = nGL;
2506 return true;
2509 bool CHWShader_D3D::mfStoreEmptyCombination(CShader* pSH, SEmptyCombination& Comb)
2511 if (!m_pGlobalCache || !m_pGlobalCache->m_pRes[CACHE_USER])
2512 return false;
2514 CResFile* rf = m_pGlobalCache->m_pRes[CACHE_USER];
2515 char nameOrg[128];
2516 char nameNew[128];
2517 SShaderCombIdent Ident;
2518 Ident.m_GLMask = Comb.nGLNew;
2519 Ident.m_RTMask = Comb.nRTNew;
2520 Ident.m_LightMask = Comb.nLTNew;
2521 Ident.m_MDMask = Comb.nMD;
2522 Ident.m_MDVMask = Comb.nMDV;
2523 SHWSInstance* pInstNew = mfGetInstance(pSH, Ident, 0);
2524 mfGenName(pInstNew, nameNew, 128, 1);
2525 CDirEntry* deNew = rf->mfGetEntry(nameNew);
2526 //assert(deNew);
2527 if (!deNew)
2528 return false;
2530 Ident.m_GLMask = Comb.nGLOrg;
2531 Ident.m_RTMask = Comb.nRTOrg;
2532 Ident.m_LightMask = Comb.nLTOrg;
2533 Ident.m_MDMask = Comb.nMD;
2534 Ident.m_MDVMask = Comb.nMDV;
2535 SHWSInstance* pInstOrg = mfGetInstance(pSH, Ident, 0);
2536 mfGenName(pInstOrg, nameOrg, 128, 1);
2537 CDirEntry* deOrg = rf->mfGetEntry(nameOrg);
2538 if (deOrg)
2540 if (deOrg->GetOffset() != deNew->GetOffset())
2541 deOrg->MarkNotSaved();
2543 // Also evict in-memory image of user cache
2544 m_pGlobalCache->m_pBinary[CACHE_USER] = nullptr;
2546 return true;
2548 CDirEntry de(nameOrg, deNew->GetSize(), deNew->GetOffset(), deNew->GetFlags());
2549 de.MarkNotSaved();
2550 rf->mfFileAdd(&de);
2552 return true;
2555 bool CHWShader_D3D::mfFlushCacheFile()
2557 uint32 i;
2559 for (i = 0; i < m_Insts.size(); i++)
2561 SHWSInstance* pInst = m_Insts[i];
2562 if (pInst->m_Handle.m_bStatus == 2) // Fake
2564 pInst->m_Handle.SetShader(NULL);
2568 // Also evict in-memory image of user cache
2569 if (m_pGlobalCache)
2570 m_pGlobalCache->m_pBinary[CACHE_USER] = nullptr;
2572 return m_pGlobalCache && m_pGlobalCache->m_pRes[CACHE_USER] && m_pGlobalCache->m_pRes[CACHE_USER]->mfFlush();
2575 struct SData
2577 CCryNameTSCRC Name;
2578 uint32 nSizeDecomp;
2579 uint32 nSizeComp;
2580 uint32 nOffset;
2581 uint16 flags;
2582 bool needsProcessing;
2583 byte* pData;
2585 bool operator<(const SData& o) const
2587 return Name < o.Name;
2590 #if CRY_PLATFORM_DESKTOP
2591 // Remove shader duplicates
2592 bool CHWShader::mfOptimiseCacheFile(SShaderCache* pCache, bool bForce, SOptimiseStats* pStats)
2594 CResFile* pRes = pCache->m_pRes[CACHE_USER];
2595 pRes->mfFlush();
2596 ResDir* Dir = pRes->mfGetDirectory();
2597 uint32 i, j;
2599 #ifdef _DEBUG
2600 mfValidateDirEntries(pRes);
2601 mfValidateTokenData(pRes);
2602 #endif
2604 std::vector<SData> Data;
2606 if (pStats)
2607 pStats->nEntries += Dir->size();
2609 for (i = 0; i < Dir->size(); i++)
2611 CDirEntry* pDE = &(*Dir)[i];
2612 if (!pDE->IsValid())
2613 continue;
2615 if (pDE->GetFlags() & RF_RES_$)
2617 if (pDE->GetName() == CShaderMan::s_cNameHEAD)
2618 continue;
2620 SData d;
2621 d.nSizeComp = d.nSizeDecomp = 0;
2622 d.pData = pRes->mfFileReadCompressed(pDE, d.nSizeDecomp, d.nSizeComp);
2623 assert(d.pData && d.nSizeComp && d.nSizeDecomp);
2624 if (!d.pData || !d.nSizeComp || !d.nSizeDecomp)
2625 continue;
2626 if (pStats)
2627 pStats->nTokenDataSize += d.nSizeDecomp;
2628 d.nOffset = 0;
2629 d.needsProcessing = false;
2630 d.Name = pDE->GetName();
2631 d.flags = pDE->GetFlags();
2632 Data.push_back(d);
2634 else
2636 SData d;
2637 d.flags = pDE->GetFlags();
2638 d.nSizeComp = d.nSizeDecomp = 0;
2639 d.pData = pRes->mfFileReadCompressed(pDE, d.nSizeDecomp, d.nSizeComp);
2640 assert(d.pData && d.nSizeComp && d.nSizeDecomp);
2641 if (!d.pData || !d.nSizeComp || !d.nSizeDecomp)
2642 continue;
2643 d.nOffset = pDE->GetOffset();
2644 d.needsProcessing = true;
2645 d.Name = pDE->GetName();
2646 Data.push_back(d);
2647 pRes->mfCloseEntry(pDE->GetName(), pDE->GetFlags());
2651 int nOutFiles = Data.size();
2653 // detect duplicates
2654 for (i = 0; i < Data.size(); i++)
2656 if (!Data[i].needsProcessing)
2657 continue;
2659 Data[i].needsProcessing = false;
2660 int nSizeComp = Data[i].nSizeComp;
2661 int nSizeDecomp = Data[i].nSizeDecomp;
2662 for (j = i + 1; j < Data.size(); j++)
2664 if (!Data[j].needsProcessing)
2665 continue;
2667 if (nSizeComp != Data[j].nSizeComp || nSizeDecomp != Data[j].nSizeDecomp)
2668 continue;
2670 if (!memcmp(Data[i].pData, Data[j].pData, nSizeComp))
2672 Data[j].needsProcessing = false;
2673 Data[j].nOffset = Data[i].nOffset;
2674 Data[j].flags |= RF_DUPLICATE;
2675 nOutFiles--;
2680 if (nOutFiles != Data.size() || CRenderer::CV_r_shaderscachedeterministic)
2682 if (nOutFiles == Data.size())
2684 iLog->Log(" Forcing optimise for deterministic order...");
2687 iLog->Log(" Optimising shaders resource '%s' (%" PRISIZE_T " items)...", pCache->m_Name.c_str(), Data.size() - 1);
2689 pRes->mfClose();
2690 pRes->mfOpen(RA_CREATE | (CParserBin::m_bEndians ? RA_ENDIANS : 0), &gRenDev->m_cEF.m_ResLookupDataMan[CACHE_USER]);
2692 float fVersion = FX_CACHE_VER;
2693 uint32 nMinor = (int)(((float)fVersion - (float)(int)fVersion) * 10.1f);
2694 uint32 nMajor = (int)fVersion;
2696 SResFileLookupData* pLookupCache = pCache->m_pRes[CACHE_USER]->GetLookupData(false, 0, 0);
2697 CRY_ASSERT(pLookupCache != NULL);
2699 if (pLookupCache == NULL || pLookupCache->m_CacheMajorVer != nMajor || pLookupCache->m_CacheMinorVer != nMinor)
2701 CRY_ASSERT_MESSAGE(pLookupCache == NULL, "Losing ShaderIdents by recreating lookupdata cache");
2702 pLookupCache = pRes->GetLookupData(true, 0, (float)FX_CACHE_VER);
2705 pRes->mfFlush();
2707 if (CRenderer::CV_r_shaderscachedeterministic)
2708 std::sort(Data.begin(), Data.end());
2710 for (i = 0; i < Data.size(); i++)
2712 SData* pD = &Data[i];
2713 CDirEntry de;
2715 if (pD->flags & RF_RES_$)
2717 de = CDirEntry(pD->Name, pD->nSizeDecomp, pD->flags);
2718 SDirEntryOpen* pOE = pRes->mfOpenEntry(pD->Name);
2719 pOE->pData = pD->pData;
2721 else if (pD->flags & RF_DUPLICATE)
2723 de = CDirEntry(pD->Name, pD->nSizeComp + 4, pD->nOffset, pD->flags | RF_COMPRESS);
2724 SAFE_DELETE_ARRAY(pD->pData);
2726 else
2728 if (pStats)
2730 pStats->nSizeUncompressed += pD->nSizeDecomp;
2731 pStats->nSizeCompressed += pD->nSizeComp;
2732 pStats->nUniqueEntries++;
2734 assert(pD->pData);
2735 if (pD->pData)
2737 de = CDirEntry(pD->Name, pD->nSizeComp + 4, pD->nOffset, pD->flags | RF_TEMPDATA | RF_COMPRESS | RF_COMPRESSED);
2739 SDirEntryOpen* pOE = pRes->mfOpenEntry(pD->Name);
2740 byte* pData = new byte[de.GetSize()];
2741 uint32 nSize = pD->nSizeDecomp;
2742 memcpy(pData, &nSize, sizeof(uint32));
2743 memcpy(pData+sizeof(uint32), pD->pData, pD->nSizeComp);
2744 pOE->pData = pData;
2745 SAFE_DELETE_ARRAY(pD->pData);
2748 pRes->mfFileAdd(&de);
2752 if (nOutFiles != Data.size())
2753 iLog->Log(" -- Removed %" PRISIZE_T " duplicated shaders", Data.size() - nOutFiles);
2755 Data.clear();
2756 int nSizeDir = pRes->mfFlush();
2757 //int nSizeCompr = pRes->mfFlush();
2759 #ifdef _DEBUG
2760 mfValidateTokenData(pRes);
2761 #endif
2763 if (pStats)
2764 pStats->nDirDataSize += nSizeDir;
2766 for (i = 0; i < Data.size(); i++)
2768 SData* pD = &Data[i];
2769 SAFE_DELETE_ARRAY(pD->pData);
2772 if (pStats)
2773 CryLog(" -- Shader cache '%s' stats: Entries: %d, Unique Entries: %d, Size: %.3f Mb, Compressed Size: %.3f Mb, Token data size: %3f Mb, Directory Size: %.3f Mb", pCache->m_Name.c_str(), pStats->nEntries, pStats->nUniqueEntries, pStats->nSizeUncompressed / 1024.0f / 1024.0f, pStats->nSizeCompressed / 1024.0f / 1024.0f, pStats->nTokenDataSize / 1024.0f / 1024.0f, pStats->nDirDataSize / 1024.0f / 1024.0f);
2775 return true;
2777 #endif
2779 int __cdecl sSort(const VOID* arg1, const VOID* arg2)
2781 CDirEntry** pi1 = (CDirEntry**)arg1;
2782 CDirEntry** pi2 = (CDirEntry**)arg2;
2783 CDirEntry* ti1 = *pi1;
2784 CDirEntry* ti2 = *pi2;
2785 if (ti1->GetName() < ti2->GetName())
2786 return -1;
2787 if (ti1->GetName() == ti2->GetName())
2788 return 0;
2789 return 1;
2792 bool CHWShader::_OpenCacheFile(float fVersion, SShaderCache* pCache, CHWShader* pSH, bool bCheckValid, uint32 CRC32, int nCache, CResFile* pRF, bool bReadOnly)
2794 assert(nCache == CACHE_USER || nCache == CACHE_READONLY);
2796 bool bValid = true;
2797 CHWShader_D3D* pSHHW = (CHWShader_D3D*)pSH;
2798 int nRes = pRF->mfOpen(RA_READ | (CParserBin::m_bEndians ? RA_ENDIANS : 0), &gRenDev->m_cEF.m_ResLookupDataMan[nCache], (nCache == CACHE_READONLY && pCache->m_pStreamInfo) ? pCache->m_pStreamInfo : NULL);
2799 if (nRes == 0)
2801 pRF->mfClose();
2802 bValid = false;
2804 else if (nRes > 0)
2806 if (bValid)
2808 SResFileLookupData* pLookup = pRF->GetLookupData(false, 0, 0);
2809 if (!pLookup)
2810 bValid = false;
2811 else if (bCheckValid)
2813 if (fVersion && (pLookup->m_CacheMajorVer != (int)fVersion || pLookup->m_CacheMinorVer != (int)(((float)fVersion - (float)(int)fVersion) * 10.1f)))
2814 bValid = false;
2815 if (!bValid && (CRenderer::CV_r_shadersdebug == 2 || nCache == CACHE_READONLY))
2817 LogWarningEngineOnly("WARNING: Shader cache '%s' version mismatch (Cache: %d.%d, Expected: %.1f)", pRF->mfGetFileName(), pLookup->m_CacheMajorVer, pLookup->m_CacheMinorVer, fVersion);
2819 if (pSH)
2821 if (bValid && pLookup->m_CRC32 != pSHHW->m_CRC32)
2823 bValid = false;
2824 if (CRenderer::CV_r_shadersdebug == 2 && (CRenderer::CV_r_shadersdebug == 2 || nCache == CACHE_READONLY))
2826 LogWarningEngineOnly("WARNING: Shader cache '%s' CRC mismatch", pRF->mfGetFileName());
2833 if (nCache == CACHE_USER)
2835 pRF->mfClose();
2836 if (bValid)
2838 int nAcc = CRenderer::CV_r_shadersAllowCompilation != 0 ? (RA_READ | RA_WRITE) : RA_READ;
2839 if (!pRF->mfOpen(nAcc | (CParserBin::m_bEndians ? RA_ENDIANS : 0), &gRenDev->m_cEF.m_ResLookupDataMan[nCache]))
2841 pRF->mfClose();
2842 bValid = false;
2847 if (!bValid && bCheckValid)
2849 if (nCache == CACHE_USER && !bReadOnly)
2851 if (!pRF->mfOpen(RA_CREATE | (CParserBin::m_bEndians ? RA_ENDIANS : 0), &gRenDev->m_cEF.m_ResLookupDataMan[nCache]))
2853 pRF->mfClose();
2854 SAFE_DELETE(pRF);
2855 return false;
2858 SResFileLookupData* pLookup = pRF->GetLookupData(true, CRC32, (float)FX_CACHE_VER);
2859 if (pSHHW)
2860 pRF->mfFlush();
2861 pCache->m_bNeedPrecache = true;
2862 bValid = true;
2864 else
2866 SAFE_DELETE(pRF);
2869 pCache->m_pRes[nCache] = pRF;
2870 pCache->m_bReadOnly[nCache] = bReadOnly;
2872 #ifdef _DEBUG
2873 mfValidateTokenData(pRF);
2874 #endif
2876 return bValid;
2879 bool CHWShader::mfOpenCacheFile(const char* szName, float fVersion, SShaderCache* pCache, CHWShader* pSH, bool bCheckValid, uint32 CRC32, bool bReadOnly)
2881 bool bValidRO = false;
2882 bool bValidUser = true;
2883 // don't load the readonly cache, when shaderediting is true
2884 if (!CRenderer::CV_r_shadersediting && !pCache->m_pRes[CACHE_READONLY])
2886 stack_string szEngine = stack_string("%ENGINE%/") + stack_string(szName);
2887 CResFile* rfRO = new CResFile(szEngine);
2888 bool bRO = bReadOnly;
2889 if (!CRenderer::CV_r_shadersAllowCompilation)
2890 bRO = true;
2891 bValidRO = _OpenCacheFile(fVersion, pCache, pSH, bCheckValid, CRC32, CACHE_READONLY, rfRO, bRO);
2893 if (!CRenderer::CV_r_shadersAllowCompilation)
2895 assert(bReadOnly);
2897 if ((!bReadOnly || gRenDev->IsShaderCacheGenMode()) && !pCache->m_pRes[CACHE_USER])
2899 stack_string szUser = stack_string(gRenDev->m_cEF.m_szUserPath.c_str()) + stack_string(szName);
2900 CResFile* rfUser = new CResFile(szUser.c_str());
2901 bValidUser = _OpenCacheFile(fVersion, pCache, pSH, bCheckValid, CRC32, CACHE_USER, rfUser, bReadOnly);
2904 return (bValidRO || bValidUser);
2907 SShaderCache* CHWShader::mfInitCache(const char* name, CHWShader* pSH, bool bCheckValid, uint32 CRC32, bool bReadOnly, bool bAsync)
2909 // LOADING_TIME_PROFILE_SECTION(iSystem);
2911 CHWShader_D3D* pSHHW = (CHWShader_D3D*)pSH;
2913 if (!CRenderer::CV_r_shadersAllowCompilation)
2914 bCheckValid = false;
2916 if (CRenderer::CV_r_shadersediting)
2917 bReadOnly = false;
2919 if (!name)
2921 char namedst[256];
2922 pSHHW->mfGetDstFileName(pSHHW->m_pCurInst, pSHHW, namedst, 256, 0);
2923 PathUtil::ReplaceExtension(namedst, "fxcb");
2924 name = namedst;
2927 SShaderCache* pCache = NULL;
2928 FXShaderCacheItor it = m_ShaderCache.find(CCryNameR(name));
2929 if (it != m_ShaderCache.end())
2931 pCache = it->second;
2932 pCache->AddRef();
2933 if (pSHHW)
2935 if (bCheckValid)
2937 int nCache[2] = { -1, -1 };
2938 if (!CRenderer::CV_r_shadersAllowCompilation)
2939 nCache[0] = CACHE_READONLY;
2940 else
2942 nCache[0] = CACHE_USER;
2943 nCache[1] = CACHE_READONLY;
2945 bool bValid;
2946 for (int i = 0; i < 2; i++)
2948 if (nCache[i] < 0 || !pCache->m_pRes[i])
2949 continue;
2950 CResFile* pRF = pCache->m_pRes[i];
2951 SResFileLookupData* pLookup = pRF->GetLookupData(false, 0, (float)FX_CACHE_VER);
2952 bValid = (pLookup && pLookup->m_CRC32 == CRC32);
2953 if (!bValid)
2955 SAFE_DELETE(pCache->m_pRes[i]);
2958 bValid = true;
2959 if (!CRenderer::CV_r_shadersAllowCompilation && !pCache->m_pRes[CACHE_READONLY])
2960 bValid = false;
2961 else
2963 if (bReadOnly && (!pCache->m_pRes[CACHE_READONLY] || !pCache->m_pRes[CACHE_USER]))
2964 bValid = false;
2965 if (!bReadOnly && !pCache->m_pRes[CACHE_USER])
2966 bValid = false;
2968 if (!bValid)
2970 mfOpenCacheFile(name, (float)FX_CACHE_VER, pCache, pSH, bCheckValid, CRC32, bReadOnly);
2975 else
2977 pCache = new SShaderCache;
2978 if (bAsync)
2979 pCache->m_pStreamInfo = new SResStreamInfo(pCache);
2980 pCache->m_nPlatform = CParserBin::m_nPlatform;
2981 pCache->m_Name = name;
2982 mfOpenCacheFile(name, (float)FX_CACHE_VER, pCache, pSH, bCheckValid, CRC32, bReadOnly);
2983 m_ShaderCache.insert(FXShaderCacheItor::value_type(CCryNameR(name), pCache));
2986 return pCache;
2989 byte* CHWShader_D3D::mfBindsToCache(SHWSInstance* pInst, std::vector<SCGBind>* Binds, int nParams, byte* pP)
2991 int i;
2992 for (i = 0; i < nParams; i++)
2994 SCGBind* cgb = &(*Binds)[i];
2995 SShaderCacheHeaderItemVar* pVar = (SShaderCacheHeaderItemVar*)pP;
2996 pVar->m_nCount = cgb->m_nParameters;
2997 pVar->m_Reg = cgb->m_dwBind;
2998 if (CParserBin::m_bEndians)
3000 SwapEndian(pVar->m_nCount, eBigEndian);
3001 SwapEndian(pVar->m_Reg, eBigEndian);
3003 int len = strlen(cgb->m_Name.c_str()) + 1;
3004 memcpy(pVar->m_Name, cgb->m_Name.c_str(), len);
3005 pP += offsetof(SShaderCacheHeaderItemVar, m_Name) + strlen(pVar->m_Name) + 1;
3007 return pP;
3010 byte* CHWShader_D3D::mfBindsFromCache(std::vector<SCGBind>*& Binds, int nParams, byte* pP)
3012 int i;
3013 for (i = 0; i < nParams; i++)
3015 if (!Binds)
3016 Binds = new std::vector<SCGBind>;
3017 SCGBind cgb;
3018 SShaderCacheHeaderItemVar* pVar = (SShaderCacheHeaderItemVar*)pP;
3020 short nParameters = pVar->m_nCount;
3021 if (CParserBin::m_bEndians)
3022 SwapEndian(nParameters, eBigEndian);
3023 cgb.m_nParameters = nParameters;
3025 cgb.m_Name = pVar->m_Name;
3027 int dwBind = pVar->m_Reg;
3028 if (CParserBin::m_bEndians)
3029 SwapEndian(dwBind, eBigEndian);
3030 cgb.m_dwBind = dwBind;
3032 Binds->push_back(cgb);
3033 pP += offsetof(SShaderCacheHeaderItemVar, m_Name) + strlen(pVar->m_Name) + 1;
3035 return pP;
3038 byte* CHWShader::mfIgnoreBindsFromCache(int nParams, byte* pP)
3040 int i;
3041 for (i = 0; i < nParams; i++)
3043 SShaderCacheHeaderItemVar* pVar = (SShaderCacheHeaderItemVar*)pP;
3044 pP += offsetof(SShaderCacheHeaderItemVar, m_Name) + strlen(pVar->m_Name) + 1;
3046 return pP;
3049 bool CHWShader_D3D::mfUploadHW(SHWSInstance* pInst, byte* pBuf, uint32 nSize, CShader* pSH, uint32 nFlags)
3051 PROFILE_FRAME(Shader_mfUploadHW);
3053 const char* sHwShaderName = _HELP("Vertex Shader");
3054 if (m_eSHClass == eHWSC_Pixel)
3055 sHwShaderName = _HELP("Pixel Shader");
3056 MEMSTAT_CONTEXT_FMT(EMemStatContextTypes::MSC_D3D, 0, "D3D HW %s", sHwShaderName);
3058 HRESULT hr = S_OK;
3059 if (!pInst->m_Handle.m_pShader)
3060 pInst->m_Handle.SetShader(new SD3DShader);
3062 assert(pInst->m_Handle.m_pShader != nullptr);
3064 if ((m_eSHClass == eHWSC_Vertex) && (!(nFlags & HWSF_PRECACHE)) && !pInst->m_bFallback)
3065 mfUpdateFXVertexFormat(pInst, pSH);
3067 pInst->m_Shader.m_nDataSize = nSize;
3068 if (m_eSHClass == eHWSC_Pixel)
3069 s_nDevicePSDataSize += nSize;
3070 else
3071 s_nDeviceVSDataSize += nSize;
3073 if (m_eSHClass == eHWSC_Pixel)
3074 hr = (pInst->m_Handle.m_pShader->m_pHandle = GetDeviceObjectFactory().CreatePixelShader(pBuf, nSize)) ? S_OK : E_FAIL;
3075 else if (m_eSHClass == eHWSC_Vertex)
3076 hr = (pInst->m_Handle.m_pShader->m_pHandle = GetDeviceObjectFactory().CreateVertexShader(pBuf, nSize)) ? S_OK : E_FAIL;
3077 else if (m_eSHClass == eHWSC_Geometry)
3079 #if 1 // use 0 for FastGS emulation mode
3080 if (m_Flags & HWSG_GS_MULTIRES)
3082 #if defined(USE_NV_API) && (CRY_RENDERER_DIRECT3D >= 110) && (CRY_RENDERER_DIRECT3D < 120)
3083 if (CVrProjectionManager::IsMultiResEnabledStatic())
3085 NvAPI_D3D11_CREATE_FASTGS_EXPLICIT_DESC FastGSArgs = { NVAPI_D3D11_CREATEFASTGSEXPLICIT_VER, NV_FASTGS_USE_VIEWPORT_MASK };
3086 NvAPI_Status Status = NvAPI_D3D11_CreateFastGeometryShaderExplicit(gcpRendD3D->GetDevice().GetRealDevice(), alias_cast<DWORD*>(pBuf), nSize, NULL, &FastGSArgs, alias_cast<ID3D11GeometryShader**>(&pInst->m_Handle.m_pShader->m_pHandle));
3087 hr = (Status == NVAPI_OK) ? S_OK : E_FAIL;
3089 else
3090 #endif
3092 pInst->m_Handle.m_pShader->m_bDisabled = true;
3093 pInst->m_Handle.m_pShader->m_pHandle = nullptr;
3094 hr = S_OK;
3097 else
3098 #endif
3100 hr = (pInst->m_Handle.m_pShader->m_pHandle = GetDeviceObjectFactory().CreateGeometryShader(pBuf, nSize)) ? S_OK : E_FAIL;
3103 else if (m_eSHClass == eHWSC_Hull)
3104 hr = (pInst->m_Handle.m_pShader->m_pHandle = GetDeviceObjectFactory().CreateHullShader(pBuf, nSize)) ? S_OK : E_FAIL;
3105 else if (m_eSHClass == eHWSC_Compute)
3106 hr = (pInst->m_Handle.m_pShader->m_pHandle = GetDeviceObjectFactory().CreateComputeShader(pBuf, nSize)) ? S_OK : E_FAIL;
3107 else if (m_eSHClass == eHWSC_Domain)
3108 hr = (pInst->m_Handle.m_pShader->m_pHandle = GetDeviceObjectFactory().CreateDomainShader(pBuf, nSize)) ? S_OK : E_FAIL;
3109 else
3111 assert(0);
3114 if (pInst->m_Handle.m_pShader->m_pHandle)
3116 #if defined(ORBIS_GPU_DEBUGGER_SUPPORT) && !CRY_RENDERER_GNM
3117 char name[1024];
3118 cry_sprintf(name, "%s_%s(LT%x)@(RT%llx)(MD%x)(MDV%x)(GL%llx)(PSS%llx)", pSH->GetName(), m_EntryFunc.c_str(), pInst->m_Ident.m_LightMask, pInst->m_Ident.m_RTMask, pInst->m_Ident.m_MDMask, pInst->m_Ident.m_MDVMask, pInst->m_Ident.m_GLMask, pInst->m_Ident.m_pipelineState.opaque);
3119 ((CCryDXOrbisShader*)pInst->m_Handle.m_pShader->m_pHandle)->RegisterWithGPUDebugger(name);
3120 #endif
3122 // Assign name to Shader for enhanced debugging
3123 #if !defined(RELEASE) && (CRY_PLATFORM_WINDOWS || CRY_PLATFORM_ORBIS)
3124 char name[1024];
3125 sprintf(name, "%s_%s(LT%x)@(RT%llx)(MD%x)(MDV%x)(GL%llx)(PSS%llx)", pSH->GetName(), m_EntryFunc.c_str(), pInst->m_Ident.m_LightMask, pInst->m_Ident.m_RTMask, pInst->m_Ident.m_MDMask, pInst->m_Ident.m_MDVMask, pInst->m_Ident.m_GLMask, pInst->m_Ident.m_pipelineState.opaque);
3126 #if CRY_PLATFORM_WINDOWS
3127 #if CRY_RENDERER_DIRECT3D
3128 ((ID3D11DeviceChild*)pInst->m_Handle.m_pShader->m_pHandle)->SetPrivateData(WKPDID_D3DDebugObjectName, strlen(name), name);
3129 #elif CRY_RENDERER_VULKAN
3130 reinterpret_cast<NCryVulkan::CShader*>(pInst->m_Handle.m_pShader->m_pHandle)->DebugSetName(name);
3131 #endif
3132 #elif CRY_PLATFORM_ORBIS && !CRY_RENDERER_GNM
3133 ((CCryDXOrbisShader*)pInst->m_Handle.m_pShader->m_pHandle)->DebugSetName(name);
3134 #endif
3135 #endif
3138 return (hr == S_OK);
3141 bool CHWShader_D3D::mfUploadHW(D3DBlob* pShader, SHWSInstance* pInst, CShader* pSH, uint32 nFlags)
3143 bool bResult = true;
3144 if (m_eSHClass == eHWSC_Vertex && !pInst->m_bFallback)
3145 mfUpdateFXVertexFormat(pInst, pSH);
3146 if (pShader && !(m_Flags & HWSG_PRECACHEPHASE))
3148 DWORD* pCode = (DWORD*)pShader->GetBufferPointer();
3149 if (gcpRendD3D->m_cEF.m_nCombinationsProcess >= 0)
3151 pInst->m_Handle.SetFake();
3153 else
3155 bResult = mfUploadHW(pInst, (byte*)pCode, (uint32)pShader->GetBufferSize(), pSH, nFlags);
3156 if (m_eSHClass == eHWSC_Vertex)
3158 size_t nSize = pShader->GetBufferSize();
3159 pInst->m_Shader.m_pShaderData = new byte[nSize];
3160 pInst->m_Shader.m_nDataSize = nSize;
3161 memcpy(pInst->m_Shader.m_pShaderData, pCode, nSize);
3164 if (!bResult)
3166 if (m_eSHClass == eHWSC_Vertex)
3167 Warning("CHWShader_D3D::mfUploadHW: Could not create vertex shader '%s'(0x%" PRIx64 ")\n", GetName(), pInst->m_Ident.m_GLMask);
3168 else if (m_eSHClass == eHWSC_Pixel)
3169 Warning("CHWShader_D3D::mfUploadHW: Could not create pixel shader '%s'(0x%" PRIx64 ")\n", GetName(), pInst->m_Ident.m_GLMask);
3170 else if (m_eSHClass == eHWSC_Geometry)
3171 Warning("CHWShader_D3D::mfUploadHW: Could not create geometry shader '%s'(0x%" PRIx64 ")\n", GetName(), pInst->m_Ident.m_GLMask);
3172 else if (m_eSHClass == eHWSC_Domain)
3173 Warning("CHWShader_D3D::mfUploadHW: Could not create domain shader '%s'(0x%" PRIx64 ")\n", GetName(), pInst->m_Ident.m_GLMask);
3174 else if (m_eSHClass == eHWSC_Hull)
3175 Warning("CHWShader_D3D::mfUploadHW: Could not create hull shader '%s'(0x%" PRIx64 ")\n", GetName(), pInst->m_Ident.m_GLMask);
3176 else if (m_eSHClass == eHWSC_Compute)
3177 Warning("CHWShader_D3D::mfUploadHW: Could not create compute shader '%s'(0x%" PRIx64 ")\n", GetName(), pInst->m_Ident.m_GLMask);
3180 return bResult;
3183 bool CHWShader_D3D::mfActivateCacheItem(CShader* pSH, SShaderCacheHeaderItem* pItem, uint32 nSize, uint32 nFlags)
3185 SHWSInstance* pInst = m_pCurInst;
3186 byte* pData = (byte*)pItem;
3187 pData += sizeof(SShaderCacheHeaderItem);
3188 byte* pBuf = pData;
3189 std::vector<SCGBind>* pInstBinds = NULL;
3190 pInst->Release(m_pDevCache, false);
3191 pBuf = mfBindsFromCache(pInstBinds, pItem->m_nInstBinds, pBuf);
3192 nSize -= (uint32)(pBuf - (byte*)pItem);
3193 pInst->m_eClass = (EHWShaderClass)pItem->m_Class;
3194 pInst->m_nVertexFormat = pItem->m_nVertexFormat;
3195 pInst->m_nInstructions = pItem->m_nInstructions;
3196 pInst->m_VStreamMask_Decl = pItem->m_StreamMask_Decl;
3197 pInst->m_VStreamMask_Stream = pItem->m_StreamMask_Stream;
3198 bool bResult = true;
3199 SD3DShader* pHandle = NULL;
3200 SShaderDevCache* pCache = m_pDevCache;
3201 if (!(nFlags & HWSG_CACHE_USER))
3203 if (pCache)
3205 FXDeviceShaderItor it = pCache->m_DeviceShaders.find(pInst->m_DeviceObjectID);
3206 if (it != pCache->m_DeviceShaders.end())
3207 pHandle = it->second;
3210 HRESULT hr = S_OK;
3211 if (pHandle)
3213 pInst->m_Handle.SetShader(pHandle);
3214 pInst->m_Handle.AddRef();
3216 #if CRY_PLATFORM_ORBIS || CRY_PLATFORM_DURANGO || CRY_RENDERER_VULKAN
3217 if (m_eSHClass == eHWSC_Vertex)
3219 D3DBlob* pS = NULL;
3220 D3DCreateBlob(nSize, (D3DBlob**)&pS);
3221 DWORD* pBuffer = (DWORD*)pS->GetBufferPointer();
3222 memcpy(pBuffer, pBuf, nSize);
3223 mfVertexFormat(pInst, this, pS, nullptr);
3224 SAFE_RELEASE(pS);
3226 #endif
3227 if ((m_eSHClass == eHWSC_Vertex) && (!(nFlags & HWSF_PRECACHE)) && !pInst->m_bFallback)
3228 mfUpdateFXVertexFormat(pInst, pSH);
3230 else
3232 if (gcpRendD3D->m_cEF.m_nCombinationsProcess > 0)
3234 pInst->m_Handle.SetFake();
3236 else
3238 #if CRY_PLATFORM_ORBIS || CRY_PLATFORM_DURANGO || CRY_RENDERER_VULKAN
3239 if (m_eSHClass == eHWSC_Vertex)
3241 D3DBlob* pS = NULL;
3242 D3DCreateBlob(nSize, (D3DBlob**)&pS);
3243 DWORD* pBuffer = (DWORD*)pS->GetBufferPointer();
3244 memcpy(pBuffer, pBuf, nSize);
3245 mfVertexFormat(pInst, this, pS, nullptr);
3246 SAFE_RELEASE(pS);
3248 #endif
3250 bResult = mfUploadHW(pInst, pBuf, nSize, pSH, nFlags);
3252 if (!bResult)
3254 SAFE_DELETE(pInstBinds);
3255 assert(!"Shader creation error");
3256 iLog->Log("WARNING: cannot create shader '%s' (FX: %s)", m_EntryFunc.c_str(), GetName());
3257 return true;
3259 pCache->m_DeviceShaders.insert(FXDeviceShaderItor::value_type(pInst->m_DeviceObjectID, pInst->m_Handle.m_pShader));
3261 void* pConstantTable = NULL;
3262 void* pShaderReflBuf = NULL;
3263 hr = D3DReflect(pBuf, nSize, IID_ID3D11ShaderReflection, &pShaderReflBuf);
3264 ID3D11ShaderReflection* pShaderReflection = (ID3D11ShaderReflection*)pShaderReflBuf;
3265 if (SUCCEEDED(hr))
3266 pConstantTable = (void*)pShaderReflection;
3267 if (m_eSHClass == eHWSC_Vertex || gRenDev->IsEditorMode())
3269 pInst->m_Shader.m_pShaderData = new byte[nSize];
3270 pInst->m_Shader.m_nDataSize = nSize;
3271 memcpy(pInst->m_Shader.m_pShaderData, pBuf, nSize);
3273 assert(hr == S_OK);
3274 bResult &= (hr == S_OK);
3275 if (pConstantTable)
3276 mfCreateBinds(pInst, pConstantTable, pBuf, nSize);
3278 mfGatherFXParameters(pInst, &pInst->m_pBindVars, pInstBinds, this, 0, pSH);
3279 SAFE_DELETE(pInstBinds);
3280 SAFE_RELEASE(pShaderReflection);
3282 return bResult;
3285 /*CHWShader_D3D::SHWSInstance *g_pInst;
3286 CHWShader_D3D::SHWSInstance g_Inst;
3287 CHWShader_D3D::SHWSInstance *g_pInst0;
3288 CHWShader_D3D::SHWSInstance g_Inst0;
3289 CHWShader_D3D *g_pSH;*/
3291 bool CHWShader_D3D::mfCreateCacheItem(SHWSInstance* pInst, std::vector<SCGBind>& InstBinds, byte* pData, int nLen, CHWShader_D3D* pSH, bool bShaderThread)
3293 if (!pSH->m_pGlobalCache || !pSH->m_pGlobalCache->m_pRes[CACHE_USER])
3295 if (pSH->m_pGlobalCache)
3296 pSH->m_pGlobalCache->Release(false);
3297 pSH->m_pGlobalCache = mfInitCache(NULL, pSH, true, pSH->m_CRC32, false, false);
3299 assert(pSH->m_pGlobalCache);
3300 if (!pSH->m_pGlobalCache || !pSH->m_pGlobalCache->m_pRes[CACHE_USER])
3301 return false;
3303 byte* byteData = NULL;
3304 DWORD* dwordData = NULL;
3306 SShaderCacheHeaderItem h;
3307 h.m_nInstBinds = static_cast<byte>(InstBinds.size());
3308 h.m_nInstructions = pInst->m_nInstructions;
3309 h.m_nVertexFormat = pInst->m_nVertexFormat;
3310 h.m_Class = pData ? pInst->m_eClass : 255;
3311 h.m_StreamMask_Decl = pInst->m_VStreamMask_Decl;
3312 h.m_StreamMask_Stream = (byte)pInst->m_VStreamMask_Stream;
3313 int nNewSize = (h.m_nInstBinds) * sizeof(SShaderCacheHeaderItemVar) + nLen;
3314 byte* pNewData = new byte[nNewSize];
3315 byte* pP = pNewData;
3316 pP = mfBindsToCache(pInst, &InstBinds, h.m_nInstBinds, pP);
3317 PREFAST_ASSUME(pData);
3318 memcpy(pP, pData, nLen);
3319 delete[] byteData;
3320 delete[] dwordData;
3321 pP += nLen;
3322 char name[256];
3323 mfGenName(pInst, name, 256, 1);
3324 CCryNameTSCRC nm = CCryNameTSCRC(name);
3325 bool bRes = mfAddCacheItem(pSH->m_pGlobalCache, &h, pNewData, (int)(pP - pNewData), false, nm);
3326 SAFE_DELETE_ARRAY(pNewData);
3327 if ((!(pSH->m_Flags & HWSG_PRECACHEPHASE) && gRenDev->m_cEF.m_nCombinationsProcess <= 0))
3329 if (bShaderThread && false)
3331 if (pInst->m_pAsync)
3332 pInst->m_pAsync->m_bPendedFlush = true;
3334 else
3335 pSH->mfFlushCacheFile();
3336 cry_strcpy(name, pSH->GetName());
3337 char* s = strchr(name, '(');
3338 if (s)
3339 s[0] = 0;
3340 if (!bShaderThread || true)
3342 byte bStore = 1;
3343 if (pSH->m_Flags & HWSG_FP_EMULATION)
3344 bStore = 2;
3345 SShaderCombIdent Ident = pInst->m_Ident;
3347 Ident.m_GLMask = pSH->m_nMaskGenFX;
3348 gRenDev->m_cEF.mfInsertNewCombination(Ident, pInst->m_eClass, name, 0, NULL, bStore);
3351 pInst->m_nCache = CACHE_USER;
3353 return bRes;
3356 //============================================================================
3358 void CHWShader_D3D::mfSaveCGFile(const char* scr, const char* path)
3360 if (CRenderer::CV_r_shadersdebug < 1)
3361 return;
3362 char name[1024];
3363 if (path && path[0])
3365 #if defined(__GNUC__)
3366 cry_sprintf(name, "%s/%s(LT%x)@(RT%llx)(MD%x)(MDV%x)(GL%llx)(PSS%llx).cg", path, GetName(), m_pCurInst->m_Ident.m_LightMask, m_pCurInst->m_Ident.m_RTMask, m_pCurInst->m_Ident.m_MDMask, m_pCurInst->m_Ident.m_MDVMask, m_pCurInst->m_Ident.m_GLMask, m_pCurInst->m_Ident.m_pipelineState.opaque);
3367 #else
3368 cry_sprintf(name, "%s/%s(LT%x)/(RT%I64x)(MD%x)(MDV%x)(GL%I64x)(PSS%llx).cg", path, GetName(), m_pCurInst->m_Ident.m_LightMask, m_pCurInst->m_Ident.m_RTMask, m_pCurInst->m_Ident.m_MDMask, m_pCurInst->m_Ident.m_MDVMask, m_pCurInst->m_Ident.m_GLMask, m_pCurInst->m_Ident.m_pipelineState.opaque);
3369 #endif
3371 else
3373 #if defined(__GNUC__)
3374 cry_sprintf(name, "Shaders/Cache/D3D10/fxerror/%s(GL%llx)@(LT%x)(RT%llx)@(MD%x)(MDV%x)(PSS%llx).cg", GetName(), m_pCurInst->m_Ident.m_GLMask, m_pCurInst->m_Ident.m_LightMask, m_pCurInst->m_Ident.m_RTMask, m_pCurInst->m_Ident.m_MDMask, m_pCurInst->m_Ident.m_MDVMask, m_pCurInst->m_Ident.m_pipelineState.opaque);
3375 #else
3376 cry_sprintf(name, "FXError/%s(GL%I64x)/(LT%x)(RT%I64x)/(MD%x)(MDV%x)(PSS%llx).cg", GetName(), m_pCurInst->m_Ident.m_GLMask, m_pCurInst->m_Ident.m_LightMask, m_pCurInst->m_Ident.m_RTMask, m_pCurInst->m_Ident.m_MDMask, m_pCurInst->m_Ident.m_MDVMask, m_pCurInst->m_Ident.m_pipelineState.opaque);
3377 #endif
3380 FILE* fp;
3382 fp = gEnv->pCryPak->FOpen(name, "w");
3384 if (fp)
3386 size_t len = strlen(scr);
3387 gEnv->pCryPak->FWrite(scr, len, fp);
3388 gEnv->pCryPak->FClose(fp);
3392 void CHWShader_D3D::mfOutputCompilerError(string& strErr, const char* szSrc)
3394 if (CRenderer::CV_r_shadersdebug)
3396 FILE* fp = fxopen("$$err", "w");
3397 if (fp)
3399 fputs(szSrc, fp);
3400 fclose(fp);
3404 string strE = strErr;
3406 size_t newlinePos = strE.find('\n');
3408 while (newlinePos != string::npos)
3410 iLog->LogError("%s", strE.substr(0, newlinePos).c_str());
3411 strE = strE.substr(newlinePos + 1);
3412 newlinePos = strE.find('\n');
3415 if (strE.size())
3416 iLog->LogError("%s", strE.c_str());
3419 SShaderAsyncInfo::~SShaderAsyncInfo()
3422 AUTO_LOCK(g_cAILock);
3423 Unlink();
3425 if (m_pFXShader)
3427 assert(m_pFXShader->GetID() >= 0 && m_pFXShader->GetID() < MAX_REND_SHADERS);
3429 SAFE_RELEASE(m_pFXShader);
3430 SAFE_RELEASE(m_pShader);
3431 SAFE_RELEASE(m_pErrors);
3433 if (ID3D11ShaderReflection* pShaderReflection = static_cast<ID3D11ShaderReflection*>(m_pConstants))
3435 pShaderReflection->Release();
3436 m_pConstants = nullptr;
3440 // Flush pended or processed shaders (main thread task)
3441 void SShaderAsyncInfo::FlushPendingShaders()
3443 //assert (gRenDev->m_pRT->IsRenderThread());
3445 if (!SShaderAsyncInfo::PendingList().m_Next)
3447 SShaderAsyncInfo::PendingList().m_Next = &SShaderAsyncInfo::PendingList();
3448 SShaderAsyncInfo::PendingList().m_Prev = &SShaderAsyncInfo::PendingList();
3449 SShaderAsyncInfo::PendingListT().m_Next = &SShaderAsyncInfo::PendingListT();
3450 SShaderAsyncInfo::PendingListT().m_Prev = &SShaderAsyncInfo::PendingListT();
3453 SShaderAsyncInfo* pAI, * pAINext;
3455 AUTO_LOCK(g_cAILock);
3456 for (pAI = PendingListT().m_Next; pAI != &PendingListT(); pAI = pAINext)
3458 pAINext = pAI->m_Next;
3459 pAI->Unlink();
3460 pAI->Link(&PendingList());
3464 for (pAI = PendingList().m_Next; pAI != &PendingList(); pAI = pAINext)
3466 pAINext = pAI->m_Next;
3468 CHWShader_D3D* pSH = pAI->m_pShader;
3469 if (pSH)
3471 SShaderCombIdent Ident;
3472 Ident.m_GLMask = pSH->m_nMaskGenShader;
3473 Ident.m_LightMask = pAI->m_LightMask;
3474 Ident.m_RTMask = pAI->m_RTMask;
3475 Ident.m_MDMask = pAI->m_MDMask;
3476 Ident.m_MDVMask = pAI->m_MDVMask;
3477 Ident.m_pipelineState.opaque = pAI->m_pipelineState.opaque;
3478 CHWShader_D3D::SHWSInstance* pInst = pSH->mfGetInstance(pAI->m_pFXShader, pAI->m_nHashInstance, Ident);
3479 if (pInst)
3481 if (pInst->m_pAsync != pAI)
3482 CryFatalError("Shader instance async info doesn't match queued async info.");
3483 pSH->mfAsyncCompileReady(pInst);
3488 void CShader::mfFlushPendedShaders()
3490 SShaderAsyncInfo::FlushPendingShaders();
3493 void CHWShader::mfFlushPendedShadersWait(int nMaxAllowed)
3495 if (nMaxAllowed > 0 && SShaderAsyncInfo::s_nPendingAsyncShaders < nMaxAllowed)
3496 return;
3497 if (CRenderer::CV_r_shadersasynccompiling > 0)
3499 if (!gRenDev->IsShaderCacheGenMode())
3501 iLog->Log("Flushing pended shaders...");
3503 Start:
3504 while (true)
3506 if (SShaderAsyncInfo::s_nPendingAsyncShaders <= 0)
3507 break;
3508 int n = (int)iTimer->GetAsyncCurTime();
3509 if (!(n % 2))
3510 iLog->Update();
3511 if (!(n % 8))
3513 SShaderAsyncInfo::FlushPendingShaders();
3515 else
3516 CrySleep(1);
3518 // Compile FXC shaders or next iteration of internal shaders
3519 SShaderAsyncInfo::FlushPendingShaders();
3521 if (SShaderAsyncInfo::s_nPendingAsyncShaders)
3522 goto Start;
3523 if (!gRenDev->IsShaderCacheGenMode())
3525 iLog->Log("Finished flushing pended shaders...");
3530 int CHWShader_D3D::mfAsyncCompileReady(SHWSInstance* pInst)
3532 //SHWSInstance *pInst = m_pCurInst;
3533 //assert(pInst->m_pAsync);
3534 if (!pInst->m_pAsync)
3535 return 0;
3537 gRenDev->m_cEF.m_ShaderCacheStats.m_nNumShaderAsyncCompiles = SShaderAsyncInfo::s_nPendingAsyncShaders;
3539 SShaderAsyncInfo* pAsync = pInst->m_pAsync;
3540 int nFrame = GetCurrentFrameID();
3541 if (pAsync->m_nFrame != nFrame)
3543 pAsync->m_nFrame = nFrame;
3546 std::vector<SCGBind> InstBindVars;
3547 D3DBlob* pShader = NULL;
3548 D3DBlob* pErrorMsgs = NULL;
3549 string strErr;
3550 char nmDst[256], nameSrc[256];
3551 bool bResult = true;
3552 int nRefCount;
3554 SShaderTechnique* pTech = nullptr;//gRenDev->m_RP.m_pCurTechnique;
3555 CShader* pSH = pAsync->m_pFXShader;
3557 if (pAsync->m_bPending)
3558 return 0;
3560 if (pSH)
3562 if (pSH->m_fMinVisibleDistance < pAsync->m_fMinDistance)
3563 pAsync->m_fMinDistance = pSH->m_fMinVisibleDistance;
3566 mfPrintCompileInfo(pInst);
3568 mfGetDstFileName(pInst, this, nmDst, 256, 3);
3569 gEnv->pCryPak->AdjustFileName(nmDst, nameSrc, 0);
3570 if (pAsync->m_pFXShader && pAsync->m_pFXShader->m_HWTechniques.Num())
3571 pTech = pAsync->m_pFXShader->m_HWTechniques[0];
3572 if ((pAsync->m_pErrors && !pAsync->m_Errors.empty()) || !pAsync->m_pDevShader)
3574 if (CRenderer::CV_r_logShaders)
3575 gcpRendD3D->LogShv("Async %d: **Failed to compile 0x%x '%s' shader\n", GetCurrentFrameID(), pInst, nameSrc);
3576 string Errors = pAsync->m_Errors;
3577 string Text = pAsync->m_Text;
3578 CShader* pFXShader = pAsync->m_pFXShader;
3579 nRefCount = pFXShader ? pFXShader->GetRefCounter() : 0;
3580 nRefCount = min(nRefCount, pAsync->m_pShader ? pAsync->m_pShader->GetRefCounter() : 0);
3581 if (nRefCount <= 1) // Just exit if shader was deleted
3583 pInst->m_pAsync = NULL;
3584 SAFE_DELETE(pAsync);
3585 return -1;
3588 mfOutputCompilerError(Errors, Text.c_str());
3590 Warning("Couldn't compile HW shader '%s'", GetName());
3591 mfSaveCGFile(Text.c_str(), NULL);
3593 bResult = false;
3595 else if (CRenderer::CV_r_logShaders)
3596 gcpRendD3D->LogShv("Async %d: Finished compiling 0x%x '%s' shader\n", GetCurrentFrameID(), pInst, nameSrc);
3597 pShader = pAsync->m_pDevShader;
3598 pErrorMsgs = pAsync->m_pErrors;
3599 strErr = pAsync->m_Errors;
3600 InstBindVars = pAsync->m_InstBindVars;
3602 if (pAsync->m_bPendedEnv)
3604 bResult &= CHWShader_D3D::mfCreateShaderEnv(pAsync->m_nThread, pInst, pAsync->m_pDevShader, pAsync->m_pConstants, pAsync->m_pErrors, pAsync->m_InstBindVars, this, false, pAsync->m_pFXShader, pAsync->m_nCombination);
3605 assert(bResult == true);
3608 // Load samplers
3609 if (pAsync->m_bPendedSamplers)
3610 mfGatherFXParameters(pInst, &pInst->m_pBindVars, &InstBindVars, this, 2, pAsync->m_pFXShader);
3612 if (pAsync->m_bPendedFlush)
3614 mfFlushCacheFile();
3615 cry_strcpy(nmDst, GetName());
3616 char* s = strchr(nmDst, '(');
3617 if (s)
3618 s[0] = 0;
3619 SShaderCombIdent Ident = pInst->m_Ident;
3620 Ident.m_GLMask = m_nMaskGenFX;
3621 gRenDev->m_cEF.mfInsertNewCombination(Ident, pInst->m_eClass, nmDst, 0);
3624 nRefCount = pAsync->m_pFXShader ? pAsync->m_pFXShader->GetRefCounter() : 0;
3625 nRefCount = min(nRefCount, pAsync->m_pShader ? pAsync->m_pShader->GetRefCounter() : 0);
3626 if (nRefCount <= 1) // Just exit if shader was deleted
3628 pInst->m_pAsync = NULL;
3629 SAFE_DELETE(pAsync);
3630 return -1;
3632 SAFE_DELETE(pInst->m_pAsync);
3635 if (pErrorMsgs && !strErr.empty())
3636 return -1;
3638 bResult &= mfUploadHW(pShader, pInst, pSH, 0);
3639 SAFE_RELEASE(pShader);
3641 if (bResult)
3643 if (pTech)
3644 mfUpdatePreprocessFlags(pTech);
3645 return 1;
3647 return -1;
3650 bool CHWShader_D3D::mfRequestAsync(CShader* pSH, SHWSInstance* pInst, std::vector<SCGBind>& InstBindVars, const char* prog_text, const char* szProfile, const char* szEntry)
3652 #ifdef SHADER_ASYNC_COMPILATION
3653 char nameSrc[256], nmDst[256];
3654 mfGetDstFileName(pInst, this, nmDst, 256, 3);
3655 gEnv->pCryPak->AdjustFileName(nmDst, nameSrc, 0);
3657 if (!SShaderAsyncInfo::PendingList().m_Next)
3659 SShaderAsyncInfo::PendingList().m_Next = &SShaderAsyncInfo::PendingList();
3660 SShaderAsyncInfo::PendingList().m_Prev = &SShaderAsyncInfo::PendingList();
3661 SShaderAsyncInfo::PendingListT().m_Next = &SShaderAsyncInfo::PendingListT();
3662 SShaderAsyncInfo::PendingListT().m_Prev = &SShaderAsyncInfo::PendingListT();
3665 if (!m_pGlobalCache || !m_pGlobalCache->m_pRes[CACHE_USER])
3667 if (m_pGlobalCache)
3668 m_pGlobalCache->Release(false);
3669 m_pGlobalCache = mfInitCache(NULL, this, true, m_CRC32, false, false);
3672 pInst->m_pAsync = new SShaderAsyncInfo;
3673 pInst->m_pAsync->m_nFrame = GetCurrentFrameID();
3674 pInst->m_pAsync->m_InstBindVars = InstBindVars;
3675 pInst->m_pAsync->m_pShader = this;
3676 pInst->m_pAsync->m_pShader->AddRef();
3677 pInst->m_pAsync->m_pFXShader = pSH;
3678 pInst->m_pAsync->m_pFXShader->AddRef();
3679 pInst->m_pAsync->m_nCombination = gRenDev->m_cEF.m_nCombinationsProcess;
3680 assert(!stricmp(m_NameSourceFX.c_str(), pInst->m_pAsync->m_pFXShader->m_NameFile.c_str()));
3681 InstContainer* pInstCont = &m_Insts;
3682 pInst->m_pAsync->m_nHashInstance = pInst->m_Ident.m_nHash;
3683 pInst->m_pAsync->m_RTMask = pInst->m_Ident.m_RTMask;
3684 pInst->m_pAsync->m_LightMask = pInst->m_Ident.m_LightMask;
3685 pInst->m_pAsync->m_MDMask = pInst->m_Ident.m_MDMask;
3686 pInst->m_pAsync->m_MDVMask = pInst->m_Ident.m_MDVMask;
3687 pInst->m_pAsync->m_pipelineState.opaque = pInst->m_Ident.m_pipelineState.opaque;
3688 pInst->m_pAsync->m_eClass = pInst->m_eClass;
3689 pInst->m_pAsync->m_Text = prog_text;
3690 pInst->m_pAsync->m_Name = szEntry;
3691 pInst->m_pAsync->m_Profile = szProfile;
3693 if (pSH)
3695 pInst->m_pAsync->m_fMinDistance = pSH->m_fMinVisibleDistance;
3698 // Generate request line text to store on the shaderlist for next shader cache gen
3700 char szShaderGenName[512];
3701 cry_strcpy(szShaderGenName, GetName());
3702 char* s = strchr(szShaderGenName, '(');
3703 if (s)
3704 s[0] = 0;
3705 string RequestLine;
3706 SShaderCombIdent Ident = pInst->m_Ident;
3707 Ident.m_GLMask = m_nMaskGenFX;
3708 gRenDev->m_cEF.mfInsertNewCombination(Ident, pInst->m_eClass, szShaderGenName, 0, &RequestLine, false);
3710 pInst->m_pAsync->m_RequestLine = RequestLine;
3713 CAsyncShaderTask::InsertPendingShader(pInst->m_pAsync);
3715 if (CRenderer::CV_r_logShaders)
3716 gcpRendD3D->LogShv("Async %d: Requested compiling 0x%x '%s' shader\n", GetCurrentFrameID(), pInst, nameSrc);
3717 #endif
3718 return false;
3721 void CHWShader_D3D::mfSubmitRequestLine(SHWSInstance* pInst, string* pRequestLine)
3723 // Generate request line text.
3724 char szShaderGenName[512];
3725 cry_strcpy(szShaderGenName, GetName());
3726 char* s = strchr(szShaderGenName, '(');
3727 if (s)
3728 s[0] = 0;
3729 string RequestLine;
3730 SShaderCombIdent Ident = pInst->m_Ident;
3731 Ident.m_GLMask = m_nMaskGenFX;
3732 gRenDev->m_cEF.mfInsertNewCombination(Ident, pInst->m_eClass, szShaderGenName, 0, &RequestLine, false);
3734 if (pRequestLine)
3735 *pRequestLine = RequestLine;
3737 if (!CRenderer::CV_r_shaderssubmitrequestline || !CRenderer::CV_r_shadersremotecompiler || pInst->m_bHasSendRequest)
3738 return;
3740 // make sure we only send the request once
3741 pInst->m_bHasSendRequest = true;
3743 #ifdef SHADER_ASYNC_COMPILATION
3744 if (CRenderer::CV_r_shadersasynccompiling && !(m_Flags & HWSG_SYNC))
3746 if (!SShaderAsyncInfo::PendingList().m_Next)
3748 SShaderAsyncInfo::PendingList().m_Next = &SShaderAsyncInfo::PendingList();
3749 SShaderAsyncInfo::PendingList().m_Prev = &SShaderAsyncInfo::PendingList();
3750 SShaderAsyncInfo::PendingListT().m_Next = &SShaderAsyncInfo::PendingListT();
3751 SShaderAsyncInfo::PendingListT().m_Prev = &SShaderAsyncInfo::PendingListT();
3754 SShaderAsyncInfo* pAsync = new SShaderAsyncInfo;
3756 if (pAsync)
3758 pAsync->m_RequestLine = RequestLine;
3759 pAsync->m_Text = "";
3760 pAsync->m_bDeleteAfterRequest = true;
3762 CAsyncShaderTask::InsertPendingShader(pAsync);
3765 else
3766 #endif
3768 NRemoteCompiler::CShaderSrv::Instance().RequestLine(
3769 #if CRY_PLATFORM_ORBIS
3770 "ShaderList_Orbis.txt",
3771 #elif CRY_PLATFORM_DURANGO
3772 "ShaderList_Durango.txt",
3773 #elif CRY_RENDERER_OPENGLES && DXGL_INPUT_GLSL
3774 "ShaderList_GLES3.txt",
3775 #elif CRY_RENDERER_OPENGL && DXGL_INPUT_GLSL
3776 "ShaderList_GL4.txt",
3777 #else
3778 "ShaderList_PC.txt",
3779 #endif
3780 RequestLine.c_str());
3784 bool CHWShader_D3D::mfCompileHLSL_Int(CShader* pSH, char* prog_text, D3DBlob** ppShader, void** ppConstantTable, D3DBlob** ppErrorMsgs, string& strErr, std::vector<SCGBind>& InstBindVars)
3786 HRESULT hr = S_OK;
3787 SHWSInstance* pInst = m_pCurInst;
3788 const char* szProfile = mfProfileString(pInst->m_eClass);
3789 const char* pFunCCryName = m_EntryFunc.c_str();
3791 bool bRes = true;
3792 if (CRenderer::CV_r_shadersdebug == 2)
3794 mfSaveCGFile(prog_text, "TestCG");
3797 #if CRY_RENDERER_VULKAN || CRY_RENDERER_GNM
3798 if (pInst->m_Ident.m_pipelineState.opaque == UPipelineState().opaque)
3800 CryWarning(VALIDATOR_MODULE_RENDERER, VALIDATOR_WARNING,"Cannot compile %s(LT%x)/(RT%I64x)(MD%x)(MDV%x)(GL%I64x)(PSS%llx).cg. Resource layout missing!",
3801 GetName(), m_pCurInst->m_Ident.m_LightMask, m_pCurInst->m_Ident.m_RTMask, m_pCurInst->m_Ident.m_MDMask,
3802 m_pCurInst->m_Ident.m_MDVMask, m_pCurInst->m_Ident.m_GLMask, m_pCurInst->m_Ident.m_pipelineState.opaque);
3804 return false;
3806 #endif
3808 if (CRenderer::CV_r_shadersasynccompiling && !(m_Flags & HWSG_SYNC))
3810 return mfRequestAsync(pSH, pInst, InstBindVars, prog_text, szProfile, pFunCCryName);
3812 else if (CRenderer::CV_r_shadersremotecompiler)
3814 string sCompiler = gRenDev->m_cEF.mfGetShaderCompileFlags(pInst->m_eClass, pInst->m_Ident.m_pipelineState);
3816 string RequestLine;
3817 mfSubmitRequestLine(pInst, &RequestLine);
3819 std::vector<uint8> Data;
3820 if (NRemoteCompiler::ESOK != NRemoteCompiler::CShaderSrv::Instance().Compile(Data, szProfile, prog_text, pFunCCryName, sCompiler.c_str(), RequestLine.c_str()))
3822 string sErrorText;
3823 sErrorText.reserve(Data.size());
3824 for (uint32 i = 0; i < Data.size(); i++)
3825 sErrorText += Unicode::ConvertSafe<Unicode::eErrorRecovery_FallbackWin1252ThenDiscard, string>(Data[i]); // HLSLcc may return garbage data, need to sanitize.
3826 strErr = sErrorText;
3828 return false;
3831 D3DCreateBlob(Data.size(), (D3DBlob**)ppShader);
3832 D3DBlob* pShader = (D3DBlob*) *ppShader;
3833 DWORD* pBuf = (DWORD*) pShader->GetBufferPointer();
3834 memcpy(pBuf, &Data[0], Data.size());
3836 *ppShader = (D3DBlob*) pShader;
3837 pBuf = (DWORD*)pShader->GetBufferPointer();
3838 size_t nSize = pShader->GetBufferSize();
3840 bool bReflect = true;
3842 #if CRY_PLATFORM_DESKTOP
3843 if (CParserBin::PlatformIsConsole())
3844 bReflect = false;
3845 #endif
3847 if (bReflect)
3849 void* pShaderReflBuf;
3850 hr = D3DReflect(pBuf, nSize, IID_ID3D11ShaderReflection, &pShaderReflBuf);
3851 if (SUCCEEDED(hr))
3853 ID3D11ShaderReflection* pShaderReflection = (ID3D11ShaderReflection*)pShaderReflBuf;
3854 *ppConstantTable = (void*)pShaderReflection;
3856 else
3858 assert(0);
3862 return hr == S_OK;
3864 #if CRY_PLATFORM_WINDOWS
3865 else
3867 static bool s_logOnce_WrongPlatform = false;
3868 #if !CRY_RENDERER_OPENGL
3869 #if !defined(_RELEASE)
3870 if (!s_logOnce_WrongPlatform && (CParserBin::m_nPlatform & (SF_D3D11 | SF_DURANGO)) == 0)
3872 s_logOnce_WrongPlatform = true;
3873 iLog->LogError("Trying to build non DX11 shader via internal compiler which is not supported. Please use remote compiler instead!");
3875 #endif
3876 uint32 nFlags = D3D10_SHADER_PACK_MATRIX_ROW_MAJOR | D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY;
3877 if (CRenderer::CV_r_shadersdebug == 3 || CRenderer::CV_r_shadersdebug == 4)
3878 nFlags |= D3D10_SHADER_DEBUG | D3D10_SHADER_SKIP_OPTIMIZATION;
3880 hr = D3DCompile(prog_text, strlen(prog_text), GetName(), NULL, NULL, pFunCCryName, szProfile, nFlags, 0, (ID3DBlob**) ppShader, (ID3DBlob**) ppErrorMsgs);
3881 if (FAILED(hr) || !*ppShader)
3883 if (ppErrorMsgs && *ppErrorMsgs)
3885 const char* err = (const char*)ppErrorMsgs[0]->GetBufferPointer();
3886 strErr += err;
3888 else
3890 strErr += "D3DXCompileShader failed";
3892 bRes = false;
3894 else
3896 void* pShaderReflBuf;
3897 UINT* pData = (UINT*)ppShader[0]->GetBufferPointer();
3898 UINT nSize = (uint32)ppShader[0]->GetBufferSize();
3899 hr = D3DReflect(pData, nSize, IID_ID3D11ShaderReflection, &pShaderReflBuf);
3900 if (SUCCEEDED(hr))
3902 ID3D11ShaderReflection* pShaderReflection = (ID3D11ShaderReflection*)pShaderReflBuf;
3903 *ppConstantTable = (void*)pShaderReflection;
3905 else
3907 assert(0);
3910 return bRes;
3911 #endif
3913 #endif // #if CRY_PLATFORM_WINDOWS || CRY_PLATFORM_DURANGO
3915 return false;
3918 D3DBlob* CHWShader_D3D::mfCompileHLSL(CShader* pSH, char* prog_text, void** ppConstantTable, D3DBlob** ppErrorMsgs, uint32 nFlags, std::vector<SCGBind>& InstBindVars)
3920 // LOADING_TIME_PROFILE_SECTION(iSystem);
3922 // Test adding source text to context
3923 SHWSInstance* pInst = m_pCurInst;
3924 string strErr;
3925 D3DBlob* pCode = NULL;
3926 HRESULT hr = S_OK;
3927 if (!prog_text)
3929 assert(0);
3930 return NULL;
3932 if (!CRenderer::CV_r_shadersAllowCompilation)
3933 return NULL;
3935 bool bResult = mfCompileHLSL_Int(pSH, prog_text, &pCode, ppConstantTable, ppErrorMsgs, strErr, InstBindVars);
3936 if (!pCode)
3938 if (CRenderer::CV_r_shadersasynccompiling)
3939 return NULL;
3940 if (!pCode)
3943 mfOutputCompilerError(strErr, prog_text);
3945 Warning("Couldn't compile HW shader '%s'", GetName());
3946 mfSaveCGFile(prog_text, NULL);
3951 return pCode;
3954 void CHWShader_D3D::mfPrepareShaderDebugInfo(SHWSInstance* pInst, CHWShader_D3D* pSH, const char* szAsm, std::vector<SCGBind>& InstBindVars, void* pConstantTable)
3956 if (szAsm)
3958 char* szInst = strstr((char*)szAsm, "pproximately ");
3959 if (szInst)
3960 pInst->m_nInstructions = atoi(&szInst[13]);
3963 if (CParserBin::m_nPlatform & (SF_D3D11 | SF_DURANGO | SF_GL4 | SF_GLES3))
3965 ID3D11ShaderReflection* pShaderReflection = (ID3D11ShaderReflection*)pConstantTable;
3967 if (pShaderReflection)
3969 D3D11_SHADER_DESC Desc;
3970 pShaderReflection->GetDesc(&Desc);
3972 pInst->m_nInstructions = Desc.InstructionCount;
3973 pInst->m_nTempRegs = Desc.TempRegisterCount;
3977 if (CRenderer::CV_r_shadersdebug)
3979 char nmdst[256];
3980 mfGetDstFileName(pInst, pSH, nmdst, 256, 4);
3982 string szName;
3983 FILE* statusdst;
3986 szName = gRenDev->m_cEF.m_szUserPath + string(nmdst) + string(".fxca");
3987 statusdst = gEnv->pCryPak->FOpen(szName.c_str(), "wb");
3990 if (statusdst)
3992 gEnv->pCryPak->FPrintf(statusdst, "\n// %s %s\n\n", "%STARTSHADER", mfProfileString(pInst->m_eClass));
3993 if (pSH->m_eSHClass == eHWSC_Vertex)
3995 for (uint32 i = 0; i < (uint32)InstBindVars.size(); i++)
3997 SCGBind* pBind = &InstBindVars[i];
3998 gEnv->pCryPak->FPrintf(statusdst, "// %s %s %d %d\n", "%%", pBind->m_Name.c_str(), pBind->m_nParameters, pBind->m_dwBind);
4001 gEnv->pCryPak->FPrintf(statusdst, "%s", szAsm);
4002 gEnv->pCryPak->FPrintf(statusdst, "\n// %s\n", "%ENDSHADER");
4003 gEnv->pCryPak->FClose(statusdst);
4005 pInst->m_Handle.m_pShader = NULL;
4009 void CHWShader_D3D::mfPrintCompileInfo(SHWSInstance* pInst)
4011 int nConsts = 0;
4012 int nParams = pInst->m_pBindVars.size();
4013 for (int i = 0; i < nParams; i++)
4015 SCGBind* pB = &pInst->m_pBindVars[i];
4016 nConsts += pB->m_nParameters;
4019 char szGenName[512];
4020 cry_strcpy(szGenName, GetName());
4021 char* s = strchr(szGenName, '(');
4022 if (s)
4023 s[0] = 0;
4024 if (CRenderer::CV_r_shadersdebug == 2)
4026 string pName;
4027 SShaderCombIdent Ident(m_nMaskGenFX, pInst->m_Ident);
4028 gRenDev->m_cEF.mfInsertNewCombination(Ident, pInst->m_eClass, szGenName, 0, &pName, false);
4029 CryLog(" Compile (FX:0x%I64x, GL:0x%I64x) %s (%d instructions, %d tempregs, %d/%d constants) ... ", m_nMaskGenFX, pInst->m_Ident.m_GLMask, pName.c_str(), pInst->m_nInstructions, pInst->m_nTempRegs, nParams, nConsts);
4030 int nSize = strlen(szGenName);
4031 mfGenName(pInst, &szGenName[nSize], 512 - nSize, 1);
4032 CryLog(" --- Cache entry: %s", szGenName);
4034 else
4036 int nSize = strlen(szGenName);
4037 mfGenName(pInst, &szGenName[nSize], 512 - nSize, 1);
4038 CryLog(" Compile %s (%d instructions, %d tempregs, %d/%d constants) ... ", szGenName, pInst->m_nInstructions, pInst->m_nTempRegs, nParams, nConsts);
4041 if (gRenDev->m_cEF.m_bActivated && CRenderer::CV_r_shadersdebug > 0)
4042 CryLog(
4043 " Shader %s"
4044 #if defined(__GNUC__)
4045 "(%llx)"
4046 #else
4047 "(%I64x)"
4048 #endif
4049 "(%x)(%x)(%x)(%llx)(%s) wasn't compiled before preactivating phase",
4050 GetName(), pInst->m_Ident.m_RTMask, pInst->m_Ident.m_LightMask, pInst->m_Ident.m_MDMask, pInst->m_Ident.m_MDVMask, pInst->m_Ident.m_pipelineState.opaque, mfProfileString(pInst->m_eClass));
4053 bool CHWShader_D3D::mfCreateShaderEnv(int nThread, SHWSInstance* pInst, D3DBlob* pShader, void*& pConstantTable, D3DBlob*& pErrorMsgs, std::vector<SCGBind>& InstBindVars, CHWShader_D3D* pSH, bool bShaderThread, CShader* pFXShader, int nCombination, const char* src)
4055 // Create asm (.fxca) cache file
4056 assert(pInst);
4057 if (!pInst)
4058 return false;
4060 CSpinLock lock;
4062 if (pInst->m_pBindVars.size())
4063 return true;
4065 if (pShader && (nCombination < 0))
4067 #if !CRY_RENDERER_OPENGL
4068 D3DBlob* pAsm = NULL;
4069 D3DBlob* pSrc = (D3DBlob*)pShader;
4070 UINT* pBuf = (UINT*)pSrc->GetBufferPointer();
4071 D3DDisassemble(pBuf, pSrc->GetBufferSize(), 0, NULL, &pAsm);
4072 if (pAsm)
4074 char* szAsm = (char*)pAsm->GetBufferPointer();
4075 mfPrepareShaderDebugInfo(pInst, pSH, szAsm, InstBindVars, pConstantTable);
4077 SAFE_RELEASE(pAsm);
4078 #endif
4080 //assert(!pInst->m_pBindVars);
4082 if (pShader)
4084 bool bVF = pSH->m_eSHClass == eHWSC_Vertex;
4085 #if CRY_PLATFORM_DESKTOP
4086 if (CParserBin::PlatformIsConsole())
4087 bVF = false;
4088 #endif
4089 #if !CRY_RENDERER_OPENGL
4090 if (CParserBin::m_nPlatform & (SF_GL4 | SF_GLES3))
4091 bVF = false;
4092 #endif
4093 if (bVF)
4094 mfVertexFormat(pInst, pSH, pShader, pConstantTable);
4095 if (pConstantTable)
4096 mfCreateBinds(pInst, pConstantTable, (byte*)pShader->GetBufferPointer(), (uint32)pShader->GetBufferSize());
4098 if (!(pSH->m_Flags & HWSG_PRECACHEPHASE))
4100 int nConsts = 0;
4101 int nParams = pInst->m_pBindVars.size();
4102 for (int i = 0; i < nParams; i++)
4104 SCGBind* pB = &pInst->m_pBindVars[i];
4105 nConsts += pB->m_nParameters;
4107 if (gRenDev->m_cEF.m_nCombinationsProcess >= 0)
4109 //assert(!bShaderThread);
4111 //if (!(gRenDev->m_cEF.m_nCombination & 0xff))
4112 if (!CParserBin::m_nPlatform)
4114 CryLog("%d: Compile %s %s (%d out of %d) - (%d/%d constants) ... ", nThread,
4115 mfProfileString(pInst->m_eClass), pSH->GetName(), nCombination, gRenDev->m_cEF.m_nCombinationsProcessOverall,
4116 nParams, nConsts);
4118 else
4120 CryLog("%d: Compile %s %s (%d out of %d) ... ", nThread,
4121 mfProfileString(pInst->m_eClass), pSH->GetName(), nCombination, gRenDev->m_cEF.m_nCombinationsProcessOverall);
4126 mfGatherFXParameters(pInst, &pInst->m_pBindVars, &InstBindVars, pSH, bShaderThread ? 1 : 0, pFXShader);
4128 if (pShader)
4129 mfCreateCacheItem(pInst, InstBindVars, (byte*)pShader->GetBufferPointer(), (uint32)pShader->GetBufferSize(), pSH, bShaderThread);
4130 else
4131 mfCreateCacheItem(pInst, InstBindVars, NULL, 0, pSH, bShaderThread);
4133 SAFE_RELEASE(pErrorMsgs);
4134 if (ID3D11ShaderReflection* pShaderReflection = (ID3D11ShaderReflection*)pConstantTable)
4136 pShaderReflection->Release();
4137 pConstantTable = nullptr;
4140 return true;
4143 // Compile pixel/vertex shader for the current instance properties
4144 bool CHWShader_D3D::mfActivate(CShader* pSH, uint32 nFlags, FXShaderToken* Table, TArray<uint32>* pSHData)
4146 PROFILE_FRAME(Shader_HWShaderActivate);
4148 bool bResult = true;
4149 SHWSInstance* pInst = m_pCurInst;
4151 mfLogShaderRequest(pInst);
4153 if (mfIsValid(pInst, true) == ED3DShError_NotCompiled)
4155 //if (!(m_Flags & HWSG_PRECACHEPHASE) && !(nFlags & HWSF_NEXT))
4156 // mfSetHWStartProfile(nFlags);
4158 bool bCreate = false;
4159 // We need a different source and desination for fpStripExtension
4160 // since a call to strcpy with the same src and dst results in
4161 // undefined behaviour
4162 char nameCacheUnstripped[256];
4163 char nameCache[256];
4164 float t0 = gEnv->pTimer->GetAsyncCurTime();
4166 /*if (CRenderer::CV_r_shaderspreactivate == 2 || (nFlags & HWSF_STORECOMBINATION))
4168 cry_strcpy(nameCache, GetName());
4169 char *s = strchr(nameCache, '(');
4170 if (s)
4171 s[0] = 0;
4172 gRenDev->m_cEF.mfInsertNewCombination(m_nMaskGenFX, pInst->m_RTMask, pInst->m_LightMask, pInst->m_MDMask, pInst->m_MDVMask, pInst->m_pipelineState.opaque, pInst->m_eSHClass, nameCache, 1);
4173 if (nFlags & HWSF_STORECOMBINATION)
4174 return false;
4176 mfGetDstFileName(pInst, this, nameCacheUnstripped, 256, 0);
4178 cry_strcpy(nameCache, nameCacheUnstripped);
4179 PathUtil::ReplaceExtension(nameCache, "fxcb");
4180 if (!m_pDevCache)
4181 m_pDevCache = mfInitDevCache(nameCache, this);
4184 int32 nSize;
4185 std::unique_ptr<byte[]> pCacheItemBuffer = nullptr;
4187 // if shader compiling is enabled, make sure the user folder shader caches are also available
4188 bool bReadOnly = CRenderer::CV_r_shadersAllowCompilation == 0;
4189 if (!m_pGlobalCache || m_pGlobalCache->m_nPlatform != CParserBin::m_nPlatform ||
4190 (!bReadOnly && !m_pGlobalCache->m_pRes[CACHE_USER]))
4192 SAFE_RELEASE(m_pGlobalCache);
4193 bool bAsync = CRenderer::CV_r_shadersasyncactivation != 0;
4194 if (nFlags & HWSF_PRECACHE)
4195 bAsync = false;
4196 m_pGlobalCache = mfInitCache(nameCache, this, true, m_CRC32, bReadOnly, bAsync);
4198 if (gRenDev->m_cEF.m_nCombinationsProcess >= 0)
4200 mfGetDstFileName(pInst, this, nameCache, 256, 0);
4201 PathUtil::ReplaceExtension(nameCache, "fxcb");
4202 FXShaderCacheNamesItor it = m_ShaderCacheList.find(nameCache);
4203 if (it == m_ShaderCacheList.end())
4204 m_ShaderCacheList.insert(FXShaderCacheNamesItor::value_type(nameCache, m_CRC32));
4206 pCacheItemBuffer = mfGetCacheItem(nFlags, nSize);
4209 auto pCacheItem = reinterpret_cast<SShaderCacheHeaderItem*>(pCacheItemBuffer.get());
4210 if (pCacheItem && pCacheItem->m_Class != 255)
4212 if (Table && CRenderer::CV_r_shadersAllowCompilation)
4213 mfGetCacheTokenMap(Table, pSHData, m_nMaskGenShader);
4214 if (((m_Flags & HWSG_PRECACHEPHASE) || gRenDev->m_cEF.m_nCombinationsProcess >= 0))
4216 return true;
4218 bool bRes = mfActivateCacheItem(pSH, pCacheItem, nSize, nFlags);
4220 if (bRes)
4221 return (pInst->m_Handle.m_pShader != NULL);
4223 else if (pCacheItem && pCacheItem->m_Class == 255 && (nFlags & HWSF_PRECACHE) == 0)
4225 return false;
4229 //assert(!m_TokenData.empty());
4231 TArray<char> newScr;
4233 if (nFlags & HWSF_PRECACHE)
4234 gRenDev->m_cEF.m_nCombinationsCompiled++;
4235 /*if (strstr(m_NameSourceFX.c_str(), "Cloak") && !strcmp(m_EntryFunc.c_str(), "Common_ZPassVS"))
4237 int nnn = 0;
4240 float fTime0 = iTimer->GetAsyncCurTime();
4241 D3DBlob* pShader = NULL;
4242 void* pConstantTable = NULL;
4243 D3DBlob* pErrorMsgs = NULL;
4244 std::vector<SCGBind> InstBindVars;
4245 m_Flags |= HWSG_WASGENERATED;
4247 bool bScriptSuccess = false;
4249 if (CRenderer::CV_r_shadersAllowCompilation)
4251 // MemReplay shows that 16kb should be enough memory to hold the script without having to reallocate
4252 newScr.reserve(16 * 1024);
4253 bScriptSuccess = mfGenerateScript(pSH, pInst, InstBindVars, nFlags, Table, pSHData, newScr);
4254 ASSERT_IN_SHADER(bScriptSuccess);
4257 if (!pInst->m_bAsyncActivating)
4259 // report miss in global cache to log and/or callback
4260 mfLogShaderCacheMiss(pInst);
4262 // still sumit the request line when no compiling to be sure that the shadercompiler will
4263 // compile it in the next build
4264 if (!CRenderer::CV_r_shadersAllowCompilation)
4265 mfSubmitRequestLine(pInst);
4268 if (!bScriptSuccess)
4270 if (!pInst->m_bAsyncActivating)
4272 #ifdef __GNUC__
4273 Warning("Warning: Shader %s(%llx)(%x)(%x)(%x)(%llx)(%s) is not existing in the cache\n",
4274 #else
4275 Warning("Warning: Shader %s(%I64x)(%x)(%x)(%x)(%llx)(%s) is not existing in the cache\n",
4276 #endif
4277 GetName(), pInst->m_Ident.m_RTMask, pInst->m_Ident.m_LightMask, pInst->m_Ident.m_MDMask, pInst->m_Ident.m_MDVMask, pInst->m_Ident.m_pipelineState.opaque, mfProfileString(pInst->m_eClass));
4279 return false;
4283 PROFILE_FRAME(Shader_CompileHLSL);
4284 pShader = mfCompileHLSL(pSH, newScr.Data(), &pConstantTable, &pErrorMsgs, nFlags, InstBindVars);
4287 gRenDev->m_cEF.m_ShaderCacheStats.m_nNumShaderAsyncCompiles = SShaderAsyncInfo::s_nPendingAsyncShaders;
4289 if (!pShader)
4291 if (!CRenderer::CV_r_shadersAllowCompilation || pInst->IsAsyncCompiling())
4292 return false;
4294 bResult = mfCreateShaderEnv(0, pInst, pShader, pConstantTable, pErrorMsgs, InstBindVars, this, false, pSH, gRenDev->m_cEF.m_nCombinationsProcess, newScr.Data());
4295 bResult &= mfUploadHW(pShader, pInst, pSH, nFlags);
4296 SAFE_RELEASE(pShader);
4297 SAFE_RELEASE(pErrorMsgs);
4298 if (ID3D11ShaderReflection* pShaderReflection = static_cast<ID3D11ShaderReflection*>(pConstantTable))
4300 pShaderReflection->Release();
4301 pConstantTable = nullptr;
4304 fTime0 = iTimer->GetAsyncCurTime() - fTime0;
4305 //iLog->LogToConsole(" Time activate: %.3f", fTime0);
4307 else if (pSHData)
4308 mfGetCacheTokenMap(Table, pSHData, m_nMaskGenShader);
4310 ED3DShError shResult = mfIsValid(pInst, true);
4311 bool bSuccess = (shResult == ED3DShError_Ok) || (shResult == ED3DShError_Fake);
4313 return bSuccess;
4316 //////////////////////////////////////////////////////////////////////////
4318 #ifdef SHADER_ASYNC_COMPILATION
4320 #pragma warning(disable: 4355)// warning C4355: 'this' : used in base member initializer list
4322 CAsyncShaderTask::CAsyncShaderTask()
4323 : m_nThread(0)
4324 , m_nThreadFXC(0)
4325 , m_thread(this)
4329 void CAsyncShaderTask::InsertPendingShader(SShaderAsyncInfo* pAsync)
4331 AUTO_LOCK(g_cAILock);
4332 pAsync->Link(&BuildList());
4333 CryInterlockedIncrement(&SShaderAsyncInfo::s_nPendingAsyncShaders);
4336 void CAsyncShaderTask::FlushPendingShaders()
4338 SShaderAsyncInfo* pAI, * pAI2, * pAINext;
4339 assert(m_flush_list.m_Prev == &m_flush_list && m_flush_list.m_Next == &m_flush_list); // the flush list must be empty - cleared by the shader compile thread
4340 if (BuildList().m_Prev == &BuildList() && BuildList().m_Next == &BuildList())
4341 return; // the build list is empty, might need to do some assert here
4343 AUTO_LOCK(g_cAILock);
4344 int n = 0;
4345 for (pAI = BuildList().m_Prev; pAI != &BuildList(); pAI = pAINext)
4347 pAINext = pAI->m_Prev;
4348 pAI->Unlink();
4349 pAI->Link(&m_flush_list);
4353 // Sorting by distance
4354 if (gRenDev->m_cEF.m_nCombinationsProcess < 0)
4355 for (pAI = m_flush_list.m_Next; pAI != &m_flush_list; pAI = pAI->m_Next)
4357 assert(pAI);
4358 PREFAST_ASSUME(pAI);
4359 pAINext = NULL;
4360 int nFrame = pAI->m_nFrame;
4361 float fDist = pAI->m_fMinDistance;
4362 for (pAI2 = pAI->m_Next; pAI2 != &m_flush_list; pAI2 = pAI2->m_Next)
4364 if (pAI2->m_nFrame < nFrame)
4365 continue;
4366 if (pAI2->m_nFrame > nFrame || pAI2->m_fMinDistance < fDist)
4368 pAINext = pAI2;
4369 nFrame = pAI2->m_nFrame;
4370 fDist = pAI2->m_fMinDistance;
4373 if (pAINext)
4375 assert(pAI != pAINext);
4376 SShaderAsyncInfo* pAIP0 = pAI->m_Prev;
4377 SShaderAsyncInfo* pAIP1 = pAINext->m_Prev == pAI ? pAINext : pAINext->m_Prev;
4379 pAI->m_Next->m_Prev = pAI->m_Prev;
4380 pAI->m_Prev->m_Next = pAI->m_Next;
4381 pAI->m_Next = pAIP1->m_Next;
4382 pAIP1->m_Next->m_Prev = pAI;
4383 pAIP1->m_Next = pAI;
4384 pAI->m_Prev = pAIP1;
4386 pAI = pAINext;
4388 pAI->m_Next->m_Prev = pAI->m_Prev;
4389 pAI->m_Prev->m_Next = pAI->m_Next;
4390 pAI->m_Next = pAIP0->m_Next;
4391 pAIP0->m_Next->m_Prev = pAI;
4392 pAIP0->m_Next = pAI;
4393 pAI->m_Prev = pAIP0;
4397 for (pAI = m_flush_list.m_Next; pAI != &m_flush_list; pAI = pAINext)
4399 pAINext = pAI->m_Next;
4400 assert(pAI->m_bPending);
4401 SubmitAsyncRequestLine(pAI);
4402 if (pAI->m_Text.length() > 0)
4403 CompileAsyncShader(pAI);
4405 CryInterlockedDecrement(&SShaderAsyncInfo::s_nPendingAsyncShaders);
4407 AUTO_LOCK(g_cAILock);
4409 pAI->Unlink();
4410 pAI->m_bPending = 0;
4411 pAI->Link(&SShaderAsyncInfo::PendingListT());
4414 if (pAI->m_bDeleteAfterRequest)
4416 SAFE_DELETE(pAI);
4421 bool CAsyncShaderTask::PostCompile(SShaderAsyncInfo* pAsync)
4423 bool bResult = true;
4424 /*if (pAsync->m_nCombination < 0 && false)
4426 CHWShader_D3D *pSH = pAsync->m_pShader;
4427 CHWShader_D3D::SHWSInstance *pInst = pSH->mfGetInstance(pAsync->m_nOwner, pSH->m_nMaskGenShader);
4428 bResult = CHWShader_D3D::mfCreateShaderEnv(m_nThread, pInst, pAsync->m_pDevShader, pAsync->m_pConstants, pAsync->m_pErrors, pAsync->m_InstBindVars, pSH, true, pAsync->m_pFXShader, pAsync->m_nCombination);
4429 assert(bResult == true);
4431 else*/
4433 pAsync->m_nThread = m_nThread;
4434 pAsync->m_bPendedEnv = true;
4436 return bResult;
4439 void CAsyncShaderTask::SubmitAsyncRequestLine(SShaderAsyncInfo* pAsync)
4441 if (CRenderer::CV_r_shadersremotecompiler)
4443 if (!pAsync->m_shaderList.empty())
4445 NRemoteCompiler::CShaderSrv::Instance().RequestLine(pAsync->m_shaderList.c_str(), pAsync->m_RequestLine.c_str());
4447 else
4449 NRemoteCompiler::CShaderSrv::Instance().RequestLine(
4450 #if CRY_PLATFORM_ORBIS
4451 "ShaderList_Orbis.txt",
4452 #elif CRY_PLATFORM_DURANGO
4453 "ShaderList_Durango.txt",
4454 #elif CRY_RENDERER_OPENGLES && DXGL_INPUT_GLSL
4455 "ShaderList_GLES3.txt",
4456 #elif CRY_RENDERER_OPENGL && DXGL_INPUT_GLSL
4457 "ShaderList_GL4.txt",
4458 #else
4459 "ShaderList_PC.txt",
4460 #endif
4461 pAsync->m_RequestLine.c_str());
4466 bool CAsyncShaderTask::CompileAsyncShader(SShaderAsyncInfo* pAsync)
4468 bool bResult = true;
4469 if (CRenderer::CV_r_shadersremotecompiler)
4471 string sCompiler = gRenDev->m_cEF.mfGetShaderCompileFlags(pAsync->m_eClass, pAsync->m_pipelineState);
4473 std::vector<uint8> Data;
4474 if (NRemoteCompiler::ESOK != NRemoteCompiler::CShaderSrv::Instance().Compile(Data, pAsync->m_Profile, pAsync->m_Text.c_str(), pAsync->m_Name.c_str(), sCompiler.c_str(), pAsync->m_RequestLine.c_str()))
4477 D3DCreateBlob(sizeof("D3DXCompileShader failed"), (D3DBlob**)&pAsync->m_pErrors);
4478 DWORD* pBuf = (DWORD*) pAsync->m_pErrors->GetBufferPointer();
4479 memcpy(pBuf, "D3DXCompileShader failed", sizeof("D3DXCompileShader failed"));
4481 string sErrorText;
4483 if (!Data.empty())
4485 sErrorText.reserve(Data.size());
4486 for (uint32 i = 0; i < Data.size(); i++)
4487 sErrorText += Data[i];
4489 else
4491 sErrorText.assign("Unknown Error");
4494 pAsync->m_Errors += sErrorText;
4496 return false;
4499 HRESULT hr = S_OK;
4500 D3DCreateBlob(Data.size(), (D3DBlob**) &pAsync->m_pDevShader);
4501 D3DBlob* pShader = (D3DBlob*)*&pAsync->m_pDevShader;
4502 DWORD* pBuf = (DWORD*)pShader->GetBufferPointer();
4503 memcpy(pBuf, &Data[0], Data.size());
4505 pAsync->m_pDevShader = (D3DBlob*)pShader;
4506 pBuf = (DWORD*)pShader->GetBufferPointer();
4507 size_t nSize = pShader->GetBufferSize();
4509 bool bReflect = true;
4511 #if CRY_PLATFORM_DESKTOP
4512 if (CParserBin::PlatformIsConsole())
4513 bReflect = false;
4514 #endif
4515 #if !CRY_RENDERER_OPENGL
4516 if (CParserBin::m_nPlatform & (SF_GL4 | SF_GLES3))
4517 bReflect = false;
4518 #endif
4520 if (bReflect)
4522 ID3D11ShaderReflection* pShaderReflection;
4523 hr = D3DReflect(pBuf, nSize, IID_ID3D11ShaderReflection, (void**)&pShaderReflection);
4524 if (SUCCEEDED(hr))
4526 pAsync->m_pConstants = (void*)pShaderReflection;
4530 if (SUCCEEDED(hr))
4532 bResult = PostCompile(pAsync);
4534 else
4536 pAsync->m_pDevShader = 0;
4537 assert(0);
4540 #if CRY_PLATFORM_WINDOWS && !CRY_RENDERER_OPENGL
4541 else
4543 static bool s_logOnce_WrongPlatform = false;
4544 #if !defined(_RELEASE)
4545 if (!s_logOnce_WrongPlatform && (CParserBin::m_nPlatform & (SF_D3D11 | SF_DURANGO)) == 0)
4547 s_logOnce_WrongPlatform = true;
4548 iLog->LogError("Trying to build non DX11 shader via internal compiler which is not supported. Please use remote compiler instead!");
4550 #endif
4551 uint32 nFlags = D3D10_SHADER_PACK_MATRIX_ROW_MAJOR | D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY;
4552 if (CRenderer::CV_r_shadersdebug == 3 || CRenderer::CV_r_shadersdebug == 4)
4553 nFlags |= D3D10_SHADER_DEBUG | D3D10_SHADER_SKIP_OPTIMIZATION;
4555 const char* Name = pAsync->m_pShader ? pAsync->m_pShader->GetName() : "Unknown";
4556 HRESULT hr = S_OK;
4557 hr = D3DCompile(pAsync->m_Text.c_str(), pAsync->m_Text.size(), Name, NULL, NULL, pAsync->m_Name.c_str(), pAsync->m_Profile.c_str(), nFlags, 0, (ID3DBlob**) &pAsync->m_pDevShader, (ID3DBlob**) &pAsync->m_pErrors);
4558 if (FAILED(hr) || !pAsync->m_pDevShader)
4560 if (pAsync->m_pErrors)
4562 const char* err = (const char*)pAsync->m_pErrors->GetBufferPointer();
4563 pAsync->m_Errors += err;
4565 else
4567 pAsync->m_Errors += "D3DXCompileShader failed";
4569 bResult = false;
4571 else
4573 ID3D11ShaderReflection* pShaderReflection;
4574 UINT* pData = (UINT*)pAsync->m_pDevShader->GetBufferPointer();
4575 size_t nSize = pAsync->m_pDevShader->GetBufferSize();
4576 hr = D3DReflect(pData, nSize, IID_ID3D11ShaderReflection, (void**)&pShaderReflection);
4577 if (SUCCEEDED(hr))
4579 pAsync->m_pConstants = (void*)pShaderReflection;
4580 bResult = PostCompile(pAsync);
4582 else
4584 assert(0);
4588 #endif // #if CRY_PLATFORM_WINDOWS
4589 return bResult;
4592 void CAsyncShaderTask::CShaderThread::ThreadEntry()
4594 while (!m_quit)
4596 m_task->FlushPendingShaders();
4597 if (!CRenderer::CV_r_shadersasynccompiling)
4598 CrySleep(250);
4599 else
4600 CrySleep(25);
4604 #endif
4606 //===============================================================================================
4607 // Export/Import
4609 #ifdef SHADERS_SERIALIZING
4611 bool STexSamplerFX::Export(SShaderSerializeContext& SC)
4613 bool bRes = true;
4614 SSTexSamplerFX TS;
4616 TS.m_nRTIdx = -1;
4617 TS.m_nsName = SC.AddString(m_szName.c_str());
4618 TS.m_nsNameTexture = SC.AddString(m_szTexture.c_str());
4619 TS.m_eTexType = m_eTexType;
4620 TS.m_nSamplerSlot = m_nSlotId;
4621 TS.m_nTexFlags = m_nTexFlags;
4623 if (m_nTexState != EDefaultSamplerStates::Unspecified)
4625 const SSamplerState& pTS = CDeviceObjectFactory::LookupSamplerState(m_nTexState).first;
4627 TS.m_bTexState = 1;
4628 TS.m_nMinFilter = pTS.m_nMinFilter;
4629 TS.m_nMagFilter = pTS.m_nMagFilter;
4630 TS.m_nMipFilter = pTS.m_nMipFilter;
4631 TS.m_nAddressU = pTS.m_nAddressU;
4632 TS.m_nAddressV = pTS.m_nAddressV;
4633 TS.m_nAddressW = pTS.m_nAddressW;
4634 TS.m_nAnisotropy = pTS.m_nAnisotropy;
4635 TS.m_dwBorderColor = pTS.m_dwBorderColor;
4636 TS.m_bActive = pTS.m_bActive;
4637 TS.m_bComparison = pTS.m_bComparison;
4638 TS.m_bSRGBLookup = pTS.m_bSRGBLookup;
4641 if (m_pTarget)
4643 TS.m_nRTIdx = SC.FXTexRTs.Num();
4645 SHRenderTarget* pRT = m_pTarget;
4646 SSHRenderTarget RT;
4648 RT.m_eOrder = pRT->m_eOrder;
4649 RT.m_nProcessFlags = pRT->m_nProcessFlags;
4650 RT.m_nsTargetName = SC.AddString(pRT->m_TargetName.c_str());
4651 RT.m_nWidth = pRT->m_nWidth;
4652 RT.m_nHeight = pRT->m_nHeight;
4653 RT.m_eTF = pRT->m_eTF;
4654 RT.m_nIDInPool = pRT->m_nIDInPool;
4655 RT.m_eUpdateType = pRT->m_eUpdateType;
4656 RT.m_bTempDepth = pRT->m_bTempDepth;
4657 RT.m_ClearColor = pRT->m_ClearColor;
4658 RT.m_fClearDepth = pRT->m_fClearDepth;
4659 RT.m_nFlags = pRT->m_nFlags;
4660 RT.m_nFilterFlags = pRT->m_nFilterFlags;
4662 SC.FXTexRTs.push_back(RT);
4665 //crude workaround for TArray push_back() bug a=b operator. Does not init a, breaks texState dtor for a
4666 SSTexSamplerFX* pNewSampler = SC.FXTexSamplers.AddIndex(1);
4667 memcpy(pNewSampler, &TS, sizeof(SSTexSamplerFX));
4669 return bRes;
4671 bool STexSamplerFX::Import(SShaderSerializeContext& SC, SSTexSamplerFX* pTS)
4673 bool bRes = true;
4675 m_szName = sString(pTS->m_nsName, SC.Strings);
4676 m_szTexture = sString(pTS->m_nsNameTexture, SC.Strings);
4677 m_eTexType = pTS->m_eTexType;
4678 m_nSlotId = pTS->m_nSamplerSlot;
4679 m_nTexFlags = pTS->m_nTexFlags;
4681 if (pTS->m_bTexState)
4683 SSamplerState TS;
4685 TS.m_nMinFilter = pTS->m_nMinFilter;
4686 TS.m_nMagFilter = pTS->m_nMagFilter;
4687 TS.m_nMipFilter = pTS->m_nMipFilter;
4688 TS.m_nAddressU = pTS->m_nAddressU;
4689 TS.m_nAddressV = pTS->m_nAddressV;
4690 TS.m_nAddressW = pTS->m_nAddressW;
4691 TS.m_nAnisotropy = pTS->m_nAnisotropy;
4692 TS.m_dwBorderColor = pTS->m_dwBorderColor;
4693 TS.m_bActive = pTS->m_bActive;
4694 TS.m_bComparison = pTS->m_bComparison;
4695 TS.m_bSRGBLookup = pTS->m_bSRGBLookup;
4697 m_nTexState = CDeviceObjectFactory::GetOrCreateSamplerStateHandle(TS);
4700 if (pTS->m_nRTIdx != -1)
4702 SSHRenderTarget* pRT = &SC.FXTexRTs[pTS->m_nRTIdx];
4703 SHRenderTarget* pDst = new SHRenderTarget;
4705 pDst->m_eOrder = pRT->m_eOrder;
4706 pDst->m_nProcessFlags = pRT->m_nProcessFlags;
4707 pDst->m_TargetName = sString(pRT->m_nsTargetName, SC.Strings);
4708 pDst->m_nWidth = pRT->m_nWidth;
4709 pDst->m_nHeight = pRT->m_nHeight;
4710 pDst->m_eTF = pRT->m_eTF;
4711 pDst->m_nIDInPool = pRT->m_nIDInPool;
4712 pDst->m_eUpdateType = pRT->m_eUpdateType;
4713 pDst->m_bTempDepth = pRT->m_bTempDepth != 0;
4714 pDst->m_ClearColor = pRT->m_ClearColor;
4715 pDst->m_fClearDepth = pRT->m_fClearDepth;
4716 pDst->m_nFlags = pRT->m_nFlags;
4717 pDst->m_nFilterFlags = pRT->m_nFilterFlags;
4719 m_pTarget = pDst;
4722 PostLoad();
4724 return bRes;
4727 bool SFXParam::Export(SShaderSerializeContext& SC)
4729 bool bRes = true;
4731 SSFXParam PR;
4732 PR.m_nsName = SC.AddString(m_Name.c_str());
4733 PR.m_nsAnnotations = SC.AddString(m_Annotations.c_str());
4734 PR.m_nsSemantic = SC.AddString(m_Semantic.c_str());
4735 PR.m_nsValues = SC.AddString(m_Values.c_str());
4737 PR.m_eType = m_eType;
4738 PR.m_nCB = m_nCB;
4739 PR.m_nComps = m_nComps;
4740 PR.m_nFlags = m_nFlags;
4741 PR.m_nParameters = m_nParameters;
4742 PR.m_nRegister[0] = m_nRegister[0];
4743 PR.m_nRegister[1] = m_nRegister[1];
4744 PR.m_nRegister[2] = m_nRegister[2];
4746 SC.FXParams.push_back(PR);
4748 return bRes;
4750 bool SFXParam::Import(SShaderSerializeContext& SC, SSFXParam* pPR)
4752 bool bRes = true;
4754 m_Name = sString(pPR->m_nsName, SC.Strings);
4755 m_Annotations = sString(pPR->m_nsAnnotations, SC.Strings);
4756 m_Semantic = sString(pPR->m_nsSemantic, SC.Strings);
4757 m_Values = sString(pPR->m_nsValues, SC.Strings);
4759 m_eType = pPR->m_eType;
4760 m_nCB = pPR->m_nCB;
4761 m_nComps = pPR->m_nComps;
4762 m_nFlags = pPR->m_nFlags;
4763 m_nParameters = pPR->m_nParameters;
4764 m_nRegister[0] = pPR->m_nRegister[0];
4765 m_nRegister[1] = pPR->m_nRegister[1];
4766 m_nRegister[2] = pPR->m_nRegister[2];
4768 return bRes;
4771 bool SFXSampler::Export(SShaderSerializeContext& SC)
4773 bool bRes = true;
4775 SSFXSampler PR;
4776 PR.m_nsName = SC.AddString(m_Name.c_str());
4777 PR.m_nsAnnotations = SC.AddString(m_Annotations.c_str());
4778 PR.m_nsSemantic = SC.AddString(m_Semantic.c_str());
4779 PR.m_nsValues = SC.AddString(m_Values.c_str());
4781 PR.m_eType = m_eType;
4782 PR.m_nArray = m_nArray;
4783 PR.m_nFlags = m_nFlags;
4784 PR.m_nRegister[0] = m_nRegister[0];
4785 PR.m_nRegister[1] = m_nRegister[1];
4786 PR.m_nRegister[2] = m_nRegister[2];
4788 SC.FXSamplers.push_back(PR);
4790 return bRes;
4792 bool SFXSampler::Import(SShaderSerializeContext& SC, SSFXSampler* pPR)
4794 bool bRes = true;
4796 m_Name = sString(pPR->m_nsName, SC.Strings);
4797 m_Annotations = sString(pPR->m_nsAnnotations, SC.Strings);
4798 m_Semantic = sString(pPR->m_nsSemantic, SC.Strings);
4799 m_Values = sString(pPR->m_nsValues, SC.Strings);
4801 m_eType = pPR->m_eType;
4802 m_nArray = pPR->m_nArray;
4803 m_nFlags = pPR->m_nFlags;
4804 m_nRegister[0] = pPR->m_nRegister[0];
4805 m_nRegister[1] = pPR->m_nRegister[1];
4806 m_nRegister[2] = pPR->m_nRegister[2];
4808 return bRes;
4811 bool SFXTexture::Export(SShaderSerializeContext& SC)
4813 bool bRes = true;
4815 SSFXTexture PR;
4816 PR.m_nsName = SC.AddString(m_Name.c_str());
4817 PR.m_nsAnnotations = SC.AddString(m_Annotations.c_str());
4818 PR.m_nsSemantic = SC.AddString(m_Semantic.c_str());
4819 PR.m_nsValues = SC.AddString(m_Values.c_str());
4821 PR.m_nsNameTexture = SC.AddString(m_szTexture.c_str());
4822 PR.m_bSRGBLookup = m_bSRGBLookup;
4823 PR.m_eType = m_eType;
4824 PR.m_nArray = m_nArray;
4825 PR.m_nFlags = m_nFlags;
4826 PR.m_nRegister[0] = m_nRegister[0];
4827 PR.m_nRegister[1] = m_nRegister[1];
4828 PR.m_nRegister[2] = m_nRegister[2];
4830 SC.FXTextures.push_back(PR);
4832 return bRes;
4834 bool SFXTexture::Import(SShaderSerializeContext& SC, SSFXTexture* pPR)
4836 bool bRes = true;
4838 m_Name = sString(pPR->m_nsName, SC.Strings);
4839 m_Annotations = sString(pPR->m_nsAnnotations, SC.Strings);
4840 m_Semantic = sString(pPR->m_nsSemantic, SC.Strings);
4841 m_Values = sString(pPR->m_nsValues, SC.Strings);
4843 m_szTexture = sString(pPR->m_nsNameTexture, SC.Strings);
4844 m_bSRGBLookup = pPR->m_bSRGBLookup;
4845 m_eType = pPR->m_eType;
4846 m_nArray = pPR->m_nArray;
4847 m_nFlags = pPR->m_nFlags;
4848 m_nRegister[0] = pPR->m_nRegister[0];
4849 m_nRegister[1] = pPR->m_nRegister[1];
4850 m_nRegister[2] = pPR->m_nRegister[2];
4852 return bRes;
4855 bool CHWShader_D3D::ExportSamplers(SCHWShader& SHW, SShaderSerializeContext& SC)
4857 bool bRes = true;
4859 //Samplers no longer stored here
4860 #if 0
4861 int i;
4862 SHW.m_nSamplers = m_Samplers.size();
4863 for (i = 0; i < m_Samplers.size(); i++)
4865 STexSampler& TS = m_Samplers[i];
4866 bRes &= TS.Export(SC);
4868 #endif
4870 return bRes;
4872 bool CHWShader::ImportSamplers(SShaderSerializeContext& SC, SCHWShader* pSHW, byte*& pData, std::vector<STexSamplerRT>& Samplers)
4874 bool bRes = true;
4876 //Samplers no longer stored here
4877 #if 0
4878 int i;
4880 for (i = 0; i < pSHW->m_nSamplers; i++)
4882 STexSamplerRT TS;
4883 bRes &= TS.Import(SC, pData);
4884 if (bRes)
4885 Samplers.push_back(TS);
4887 #endif
4888 return bRes;
4891 bool CHWShader_D3D::ExportParams(SCHWShader& SHW, SShaderSerializeContext& SC)
4893 bool bRes = true;
4895 //params no longer here
4896 #if 0
4897 int i;
4898 SHW.m_nParams = m_Params.size();
4899 for (i = 0; i < m_Params.size(); i++)
4901 SFXParam& PR = m_Params[i];
4902 bRes &= PR.Export(SC);
4904 #else
4905 SHW.m_nParams = 0;
4906 #endif
4908 return bRes;
4910 bool CHWShader::ImportParams(SShaderSerializeContext& SC, SCHWShader* pSHW, byte*& pData, std::vector<SFXParam>& Params)
4912 bool bRes = true;
4914 //params no longer here
4915 #if 0
4916 uint32 i;
4918 for (i = 0; i < pSHW->m_nParams; i++)
4920 SFXParam PR;
4921 bRes &= PR.Import(SC, pData);
4922 if (bRes)
4923 Params.push_back(PR);
4925 #endif
4926 return bRes;
4929 bool CHWShader_D3D::Export(SShaderSerializeContext& SC)
4931 bool bRes = true;
4933 SCHWShader SHW;
4935 char str[256];
4936 cry_strcpy(str, GetName());
4937 char* c = strchr(str, '(');
4938 if (c)
4939 c[0] = 0;
4941 SHW.m_nsName = SC.AddString(str);
4942 SHW.m_nsNameSourceFX = SC.AddString(m_NameSourceFX.c_str());
4943 SHW.m_nsEntryFunc = SC.AddString(m_EntryFunc.c_str());
4945 SHW.m_eSHClass = m_eSHClass;
4946 SHW.m_dwShaderType = m_dwShaderType;
4947 SHW.m_nMaskGenFX = m_nMaskGenFX;
4948 SHW.m_nMaskGenShader = m_nMaskGenShader;
4949 SHW.m_nMaskOr_RT = m_nMaskOr_RT;
4950 SHW.m_nMaskAnd_RT = m_nMaskAnd_RT;
4951 SHW.m_Flags = m_Flags;
4953 FXShaderToken* pMap = NULL;
4954 TArray<uint32>* pData = &m_TokenData;
4955 bool bDeleteTokenData = false;
4957 // No longer export any token data, slow and bloated!
4958 const bool bOutputTokens = false;
4960 if (bOutputTokens) // && !pData->size())
4962 //always evaluate?
4963 if (1)
4965 bDeleteTokenData = true;
4966 mfGetCacheTokenMap(pMap, pData, m_nMaskGenShader /*is this correct? m_nMaskGenFX*/);
4968 else
4969 assert(0);
4972 if (bOutputTokens && !pMap)
4974 assert(0);
4975 return false;
4978 SHW.m_nTokens = bOutputTokens ? pData->size() : 0;
4979 SHW.m_nTableEntries = bOutputTokens ? pMap->size() : 0;
4981 SCHWShader SHWTemp = SHW;
4983 SHW.Export(SC.Data);
4984 uint32 nOffs = 0;
4986 if (bOutputTokens)
4988 sAddDataArray_POD(SC.Data, *pData, nOffs);
4990 FXShaderTokenItor itor;
4991 for (itor = pMap->begin(); itor != pMap->end(); itor++)
4993 //String pool method
4994 sAddData(SC.Data, itor->Token);
4995 uint32 tokenStrIdx = SC.AddString(itor->SToken.c_str());
4996 sAddData(SC.Data, tokenStrIdx);
5000 bRes &= ExportSamplers(SHW, SC);
5001 bRes &= ExportParams(SHW, SC);
5003 if (bRes)
5005 if (memcmp(&SHW, &SHWTemp, sizeof(SCHWShader)))
5007 CryFatalError("Export failed");
5011 if (bDeleteTokenData)
5013 SAFE_DELETE(pData);
5014 SAFE_DELETE(pMap);
5017 return bRes;
5020 CHWShader* CHWShader::Import(SShaderSerializeContext& SC, int nOffs, uint32 CRC32, CShader* pSH)
5022 if (nOffs < 0)
5023 return NULL;
5025 CHWShader* pHWSH = NULL;
5026 SCHWShader shaderHW;
5027 shaderHW.Import(&SC.Data[nOffs]);
5028 SCHWShader* pSHW = &shaderHW;
5030 byte* pData = &SC.Data[nOffs + sizeof(SCHWShader)];
5032 const char* szName = sString(pSHW->m_nsName, SC.Strings);
5033 const char* szNameSource = sString(pSHW->m_nsNameSourceFX, SC.Strings);
5034 const char* szNameEntry = sString(pSHW->m_nsEntryFunc, SC.Strings);
5036 TArray<uint32> SHData;
5037 SHData.resize(pSHW->m_nTokens);
5038 memcpy(&SHData[0], pData, pSHW->m_nTokens * sizeof(uint32));
5039 pData += pSHW->m_nTokens * sizeof(uint32);
5041 FXShaderToken Table, * pTable = NULL;
5042 Table.reserve(pSHW->m_nTableEntries);
5044 nOffs = 0;
5046 //Copy string pool, TODO separate string pool for tokens!
5047 //TArray<char> tokenStringPool = SC.Strings;
5049 // Token data is no longer in export data
5050 if (0) //CRenderer::CV_r_shadersAllowCompilation)
5052 pTable = &Table;
5053 for (uint32 i = 0; i < pSHW->m_nTableEntries; i++)
5055 // string pool method
5056 DWORD nToken = *(DWORD*)&pData[nOffs];
5057 nOffs += sizeof(DWORD);
5058 uint32 nTokenStrIdx = *(DWORD*)&pData[nOffs];
5059 nOffs += sizeof(uint32);
5061 if (CParserBin::m_bEndians)
5063 SwapEndian(nToken, eBigEndian);
5064 SwapEndian(nTokenStrIdx, eBigEndian);
5067 STokenD TD;
5068 TD.SToken = sString(nTokenStrIdx, SC.Strings);
5070 TD.Token = nToken;
5072 Table.push_back(TD);
5074 pData += nOffs;
5076 std::vector<STexSamplerRT> Samplers;
5077 ImportSamplers(SC, pSHW, pData, Samplers);
5079 std::vector<SFXParam> Params;
5080 ImportParams(SC, pSHW, pData, Params);
5083 bool bPrecache = (SC.SSR.m_Flags & EF_PRECACHESHADER) != 0;
5085 //static CHWShader *mfForName(const char *name, const char *nameSource, uint32 CRC32, const char *szEntryFunc, EHWShaderClass eClass, TArray<uint32>& SHData, FXShaderToken *pTable, uint32 dwType, CShader *pFX, uint64 nMaskGen=0, uint64 nMaskGenFX=0);
5086 pHWSH = CHWShader::mfForName(szName, szNameSource, CRC32, szNameEntry, pSHW->m_eSHClass, SHData, pTable, pSHW->m_dwShaderType, pSH, pSHW->m_nMaskGenShader, pSHW->m_nMaskGenFX);
5088 pHWSH->m_eSHClass = shaderHW.m_eSHClass;
5089 pHWSH->m_dwShaderType = shaderHW.m_dwShaderType;
5090 pHWSH->m_nMaskGenFX = shaderHW.m_nMaskGenFX;
5091 pHWSH->m_nMaskGenShader = shaderHW.m_nMaskGenShader;
5092 pHWSH->m_nMaskOr_RT = shaderHW.m_nMaskOr_RT;
5093 pHWSH->m_nMaskAnd_RT = shaderHW.m_nMaskAnd_RT;
5094 pHWSH->m_Flags = shaderHW.m_Flags;
5096 return pHWSH;
5099 #else
5100 bool CHWShader_D3D::Export(SShaderSerializeContext& SC)
5102 return false;
5104 #endif
5106 const char* CHWShader_D3D::mfGetActivatedCombinations(bool bForLevel)
5108 TArray<char> Combinations;
5109 char* pPtr = NULL;
5110 uint32 i;
5112 for (i = 0; i < m_Insts.size(); i++)
5114 SHWSInstance* pInst = m_Insts[i];
5115 char name[256];
5116 cry_strcpy(name, GetName());
5117 char* s = strchr(name, '(');
5118 if (s)
5119 s[0] = 0;
5120 string str;
5121 SShaderCombIdent Ident(m_nMaskGenFX, pInst->m_Ident);
5122 gRenDev->m_cEF.mfInsertNewCombination(Ident, pInst->m_eClass, name, 0, &str, false);
5123 assert(str.size());
5124 if (str.size())
5126 assert(str[0] == '<' && str[2] == '>');
5127 string s1;
5128 if (str[0] == '<' && str[2] == '>')
5129 s1.Format("<%d>%s", pInst->m_nUsed, &str[3]);
5130 else
5131 s1 = str;
5132 Combinations.Copy(s1.c_str(), s1.size());
5133 Combinations.Copy("\n", 1);
5137 if (!Combinations.Num())
5138 return NULL;
5139 pPtr = new char[Combinations.Num() + 1];
5140 memcpy(pPtr, &Combinations[0], Combinations.Num());
5141 pPtr[Combinations.Num()] = 0;
5142 return pPtr;
5145 const char* CHWShader::GetCurrentShaderCombinations(bool bForLevel) threadsafe
5147 CryAutoReadLock<CryRWLock> lock(CBaseResource::s_cResLock);
5149 TArray<char> Combinations;
5150 char* pPtr = NULL;
5151 CCryNameTSCRC Name;
5152 SResourceContainer* pRL;
5154 Name = CHWShader::mfGetClassName(eHWSC_Vertex);
5155 pRL = CBaseResource::GetResourcesForClass(Name);
5156 int nVS = 0;
5157 int nPS = 0;
5158 if (pRL)
5160 ResourcesMapItor itor;
5161 for (itor = pRL->m_RMap.begin(); itor != pRL->m_RMap.end(); itor++)
5163 CHWShader* vs = (CHWShader*)itor->second;
5164 if (!vs)
5165 continue;
5166 const char* szCombs = vs->mfGetActivatedCombinations(bForLevel);
5167 if (!szCombs)
5168 continue;
5169 Combinations.Copy(szCombs, strlen(szCombs));
5170 delete[] szCombs;
5171 nVS++;
5175 Name = CHWShader::mfGetClassName(eHWSC_Pixel);
5176 pRL = CBaseResource::GetResourcesForClass(Name);
5177 int n = 0;
5178 if (pRL)
5180 ResourcesMapItor itor;
5181 for (itor = pRL->m_RMap.begin(); itor != pRL->m_RMap.end(); itor++)
5183 CHWShader* ps = (CHWShader*)itor->second;
5184 if (!ps)
5185 continue;
5186 const char* szCombs = ps->mfGetActivatedCombinations(bForLevel);
5187 if (!szCombs)
5188 continue;
5189 Combinations.Copy(szCombs, strlen(szCombs));
5190 delete[] szCombs;
5191 nPS++;
5195 if (!Combinations.Num())
5196 return NULL;
5197 pPtr = new char[Combinations.Num() + 1];
5198 memcpy(pPtr, &Combinations[0], Combinations.Num());
5199 pPtr[Combinations.Num()] = 0;
5200 return pPtr;