!IB (Renderer) Fixes vulkan shader cache generation. The encoded resource layout...
[CRYENGINE.git] / Code / CryEngine / RenderDll / Common / Shaders / ShaderCache.cpp
blob0ccb7e7ad2e312fe4320ec9d4d3a34cfa3419e1c
1 // Copyright 2001-2017 Crytek GmbH / Crytek Group. All rights reserved.
3 /*=============================================================================
4 ShaderCache.cpp : implementation of the Shaders cache management.
6 Revision history:
7 * Created by Honich Andrey
9 =============================================================================*/
11 #include "StdAfx.h"
12 #include <Cry3DEngine/I3DEngine.h>
13 #include "RemoteCompiler.h"
14 #include <CryCore/Base64.h>
16 bool SShaderCombIdent::operator==(const SShaderCombIdent& other) const
18 if ((m_MDVMask & ~SF_PLATFORM) == other.m_MDVMask && m_RTMask == other.m_RTMask
19 && m_GLMask == other.m_GLMask && m_FastCompare1 == other.m_FastCompare1
20 && m_pipelineState.opaque == other.m_pipelineState.opaque)
21 return true;
22 return false;
25 uint32 SShaderCombIdent::PostCreate()
27 FUNCTION_PROFILER_RENDER_FLAT
28 // using actual CRC is to expensive, so replace with cheaper version with
29 // has more changes of hits
30 //uint32 hash = CCrc32::Compute(&m_RTMask, sizeof(SShaderCombIdent)-sizeof(uint32));
31 const uint32* acBuffer = alias_cast<uint32*>(&m_RTMask);
32 int len = (sizeof(SShaderCombIdent) - sizeof(uint32)) / sizeof(uint32);
33 uint32 hash = 5381;
34 while (len--)
36 int c = *acBuffer++;
37 // hash = hash*33 + c
38 hash = ((hash << 5) + hash) + c;
41 m_nHash = hash;
42 m_MDVMask &= ~SF_PLATFORM;
43 return hash;
46 bool CShader::mfPrecache(SShaderCombination& cmb, bool bForce, CShaderResources* pRes)
48 bool bRes = true;
50 if (!CRenderer::CV_r_shadersAllowCompilation && !bForce)
51 return bRes;
53 int nAsync = CRenderer::CV_r_shadersasynccompiling;
54 CRenderer::CV_r_shadersasynccompiling = 0;
56 uint32 i, j;
58 for (i = 0; i < m_HWTechniques.Num(); i++)
60 SShaderTechnique* pTech = m_HWTechniques[i];
61 for (j = 0; j < pTech->m_Passes.Num(); j++)
63 SShaderPass& Pass = pTech->m_Passes[j];
64 SShaderCombination c = cmb;
66 CHWShader* const shadersToCompile[] = {
67 Pass.m_VShader, // Vertex shader
68 Pass.m_PShader, // Pixel shader
69 Pass.m_GShader, // Geometry shader
70 Pass.m_HShader, // Hull shader
71 Pass.m_DShader, // Domain shader
72 Pass.m_CShader, // Compute shader
75 for (const auto &shader : shadersToCompile)
77 uint32 nFlagsShader_MD = cmb.m_MDMask;
78 if (shader)
79 bRes &= shader->mfPrecache(cmb, bForce, false, this, pRes);
80 cmb.m_MDMask = nFlagsShader_MD;
83 cmb = c;
86 CRenderer::CV_r_shadersasynccompiling = nAsync;
88 return bRes;
91 SShaderGenComb* CShaderMan::mfGetShaderGenInfo(const char* nmFX)
93 SShaderGenComb* c = NULL;
94 uint32 i;
95 for (i = 0; i < m_SGC.size(); i++)
97 c = &m_SGC[i];
98 if (!stricmp(c->Name.c_str(), nmFX))
99 break;
101 SShaderGenComb cmb;
102 if (i == m_SGC.size())
104 cmb.pGen = mfCreateShaderGenInfo(nmFX, false);
105 cmb.Name = CCryNameR(nmFX);
106 m_SGC.push_back(cmb);
107 c = &m_SGC[i];
109 return c;
112 static uint64 sGetGL(char** s, CCryNameR& name, uint32& nHWFlags)
114 uint32 i;
116 nHWFlags = 0;
117 SShaderGenComb* c = NULL;
118 const char* m = strchr(name.c_str(), '@');
119 if (!m)
120 m = strchr(name.c_str(), '/');
121 assert(m);
122 if (!m)
123 return -1;
124 char nmFX[128];
125 char nameExt[128];
126 nameExt[0] = 0;
127 cry_strcpy(nmFX, name.c_str(), (size_t)(m - name.c_str()));
128 c = gRenDev->m_cEF.mfGetShaderGenInfo(nmFX);
129 if (!c || !c->pGen || !c->pGen->m_BitMask.Num())
130 return 0;
131 uint64 nGL = 0;
132 SShaderGen* pG = c->pGen;
133 while (true)
135 char theChar;
136 int n = 0;
137 while ((theChar = **s) != 0)
139 if (theChar == ')' || theChar == '|')
141 nameExt[n] = 0;
142 break;
144 nameExt[n++] = theChar;
145 ++*s;
147 if (!nameExt[0])
148 break;
149 for (i = 0; i < pG->m_BitMask.Num(); i++)
151 SShaderGenBit* pBit = pG->m_BitMask[i];
152 if (!stricmp(pBit->m_ParamName.c_str(), nameExt))
154 nGL |= pBit->m_Mask;
155 break;
158 if (i == pG->m_BitMask.Num())
160 if (!strncmp(nameExt, "0x", 2))
162 //nGL |= shGetHex(&nameExt[2]);
164 else
166 //assert(0);
167 if (CRenderer::CV_r_shadersdebug)
168 iLog->Log("WARNING: Couldn't find global flag '%s' in shader '%s' (skipped)", nameExt, c->Name.c_str());
171 if (**s == '|')
172 ++*s;
174 return nGL;
177 static uint64 sGetRT(char** s)
179 uint32 i;
181 SShaderGen* pG = gRenDev->m_cEF.m_pGlobalExt;
182 if (!pG)
183 return 0;
184 uint64 nRT = 0;
185 char nm[128] = { 0 };
186 while (true)
188 char theChar;
189 int n = 0;
190 while ((theChar = **s) != 0)
192 if (theChar == ')' || theChar == '|')
194 nm[n] = 0;
195 break;
197 nm[n++] = theChar;
198 ++*s;
200 if (!nm[0])
201 break;
202 for (i = 0; i < pG->m_BitMask.Num(); i++)
204 SShaderGenBit* pBit = pG->m_BitMask[i];
205 if (!stricmp(pBit->m_ParamName.c_str(), nm))
207 nRT |= pBit->m_Mask;
208 break;
211 if (i == pG->m_BitMask.Num())
213 //assert(0);
214 // iLog->Log("WARNING: Couldn't find runtime flag '%s' (skipped)", nm);
216 if (**s == '|')
217 ++*s;
219 return nRT;
222 static int sEOF(bool bFromFile, char* pPtr, FILE* fp)
224 int nStatus;
225 if (bFromFile)
226 nStatus = gEnv->pCryPak->FEof(fp);
227 else
229 SkipCharacters(&pPtr, kWhiteSpace);
230 if (!*pPtr)
231 nStatus = 1;
232 else
233 nStatus = 0;
235 return nStatus;
238 void CShaderMan::mfCloseShadersCache(int nID)
240 if (m_FPCacheCombinations[nID])
242 gEnv->pCryPak->FClose(m_FPCacheCombinations[nID]);
243 m_FPCacheCombinations[nID] = NULL;
247 void sSkipLine(char*& s)
249 if (!s) return;
251 char* sEnd = strchr(s, '\n');
252 if (sEnd)
254 sEnd++;
255 s = sEnd;
259 static void sIterateHW_r(FXShaderCacheCombinations* Combinations, SCacheCombination& cmb, int i, uint64 nHW, const char* szName)
261 string str;
262 gRenDev->m_cEF.mfInsertNewCombination(cmb.Ident, cmb.eCL, szName, 0, &str, false);
263 CCryNameR nm = CCryNameR(str.c_str());
264 FXShaderCacheCombinationsItor it = Combinations->find(nm);
265 if (it == Combinations->end())
267 cmb.CacheName = str.c_str();
268 Combinations->insert(FXShaderCacheCombinationsItor::value_type(nm, cmb));
270 for (int j = i; j < 64; j++)
272 if (((uint64)1 << j) & nHW)
274 cmb.Ident.m_GLMask &= ~((uint64)1 << j);
275 sIterateHW_r(Combinations, cmb, j + 1, nHW, szName);
276 cmb.Ident.m_GLMask |= ((uint64)1 << j);
277 sIterateHW_r(Combinations, cmb, j + 1, nHW, szName);
283 void CShaderMan::mfGetShaderListPath(stack_string& nameOut, int nType)
285 if (nType == 0)
286 nameOut = stack_string(m_szUserPath.c_str()) + stack_string("shaders/shaderlist.txt");
287 else
288 nameOut = stack_string(m_szUserPath.c_str()) + stack_string("shaders/cache/shaderlistactivate.txt");
291 void CShaderMan::mfMergeShadersCombinations(FXShaderCacheCombinations* Combinations, int nType)
293 FXShaderCacheCombinationsItor itor;
294 for (itor = m_ShaderCacheCombinations[nType].begin(); itor != m_ShaderCacheCombinations[nType].end(); itor++)
296 SCacheCombination* cmb = &itor->second;
297 FXShaderCacheCombinationsItor it = Combinations->find(cmb->CacheName);
298 if (it == Combinations->end())
300 Combinations->insert(FXShaderCacheCombinationsItor::value_type(cmb->CacheName, *cmb));
305 //==========================================================================================================================================
307 struct CompareCombItem
309 bool operator()(const SCacheCombination& p1, const SCacheCombination& p2) const
311 int n = stricmp(p1.Name.c_str(), p2.Name.c_str());
312 if (n)
313 return n < 0;
314 n = p1.nCount - p2.nCount;
315 if (n)
316 return n > 0;
317 return (stricmp(p1.CacheName.c_str(), p2.CacheName.c_str()) < 0);
321 #define g_szTestResults "%USER%/TestResults"
323 void CShaderMan::mfInitShadersCacheMissLog()
325 m_ShaderCacheMissCallback = 0;
326 m_ShaderCacheMissPath = "";
328 // don't access the HD if we don't have any logging to file enabled
329 if (!CRenderer::CV_r_shaderslogcachemisses)
331 return;
334 // create valid path (also for xbox dvd emu)
335 gEnv->pCryPak->MakeDir(g_szTestResults);
337 char path[ICryPak::g_nMaxPath];
338 path[sizeof(path) - 1] = 0;
339 gEnv->pCryPak->AdjustFileName("%USER%\\Shaders\\ShaderCacheMisses.txt",
340 path, ICryPak::FLAGS_PATH_REAL | ICryPak::FLAGS_FOR_WRITING);
342 m_ShaderCacheMissPath = string(path);
344 // load data which is already stored
345 FILE* fp = fopen(path, "r");
346 if (fp)
348 char str[2048];
349 int nLine = 0;
351 while (!feof(fp))
353 nLine++;
354 str[0] = 0;
355 fgets(str, 2047, fp);
356 if (!str[0])
357 continue;
359 // remove new line at end
360 int len = strlen(str);
361 if (len > 0)
362 str[strlen(str) - 1] = 0;
364 m_ShaderCacheMisses.push_back(str);
367 std::sort(m_ShaderCacheMisses.begin(), m_ShaderCacheMisses.end());
369 fclose(fp);
370 fp = NULL;
374 static inline bool IsHexDigit(int ch)
376 const int nDigit = (ch - int('0'));
377 const int bHex = (ch - int('a'));
378 return ((nDigit >= 0) && (nDigit <= 9)) || ((bHex >= 0) && (bHex < 6));
381 void CShaderMan::mfInitShadersCache(byte bForLevel, FXShaderCacheCombinations* Combinations, const char* pCombinations, int nType)
383 static_assert(SHADER_LIST_VER != SHADER_SERIALISE_VER, "Version mismatch!");
385 char str[2048];
386 bool bFromFile = (Combinations == NULL);
387 stack_string nameComb;
388 m_ShaderCacheExportCombinations.clear();
389 FILE* fp = NULL;
390 if (bFromFile)
392 if (!gRenDev->IsEditorMode() && !CRenderer::CV_r_shadersdebug && !gRenDev->IsShaderCacheGenMode())
393 return;
394 mfGetShaderListPath(nameComb, nType);
395 fp = gEnv->pCryPak->FOpen(nameComb.c_str(), "r+");
396 if (!fp)
397 fp = gEnv->pCryPak->FOpen(nameComb.c_str(), "w+");
398 if (!fp)
400 gEnv->pCryPak->AdjustFileName(nameComb.c_str(), str, 0);
401 FILE* statusdst = fopen(str, "rb");
402 if (statusdst)
404 fclose(statusdst);
405 CrySetFileAttributes(str, FILE_ATTRIBUTE_ARCHIVE);
406 fp = gEnv->pCryPak->FOpen(nameComb.c_str(), "r+");
409 m_FPCacheCombinations[nType] = fp;
410 Combinations = &m_ShaderCacheCombinations[nType];
413 int nLine = 0;
414 char* pPtr = (char*)pCombinations;
415 char* ss;
416 if (fp || !bFromFile)
418 while (!sEOF(bFromFile, pPtr, fp))
420 nLine++;
422 str[0] = 0;
423 if (bFromFile)
424 gEnv->pCryPak->FGets(str, 2047, fp);
425 else
426 fxFillCR(&pPtr, str);
427 if (!str[0])
428 continue;
429 bool bNewFormat = false;
431 if (str[0] == '/' && str[1] == '/') // commented line e.g. // BadLine: Metal@Common_ShadowPS(%BIllum@IlluminationPS(%DIFFUSE|%ENVCMAMB|%ALPHAGLOW|%STAT_BRANCHING)(%_RT_AMBIENT|%_RT_BUMP|%_RT_GLOW)(101)(0)(0)(ps_2_0)
432 continue;
434 bool bExportEntry = false;
435 int size = strlen(str);
436 if (str[size - 1] == 0xa)
437 str[size - 1] = 0;
438 SCacheCombination cmb;
439 char* s = str;
440 SkipCharacters(&s, kWhiteSpace);
441 if (s[0] != '<')
442 continue;
443 char* st;
444 if (!bForLevel)
446 int nVer = atoi(&s[1]);
447 if (nVer != SHADER_LIST_VER)
449 if (nVer == SHADER_SERIALISE_VER && bFromFile)
451 bExportEntry = true;
453 else
455 continue;
458 if (s[2] != '>')
459 continue;
460 s += 3;
462 else
464 st = s;
465 s = strchr(&st[1], '>');
466 if (!s)
467 continue;
468 cmb.nCount = atoi(st);
469 s++;
471 if (bForLevel == 2)
473 st = s;
474 if (s[0] != '<')
475 continue;
476 s = strchr(st, '>');
477 if (!s)
478 continue;
479 int nVer = atoi(&st[1]);
481 if (nVer != SHADER_LIST_VER)
483 if (nVer == SHADER_SERIALISE_VER)
485 bExportEntry = true;
487 else
489 continue;
492 s++;
494 st = s;
495 s = strchr(s, '(');
496 char name[128];
497 if (s)
499 memcpy(name, st, s - st);
500 name[s - st] = 0;
501 cmb.Name = name;
502 s++;
504 else
506 continue;
508 uint32 nHW = 0;
509 cmb.Ident.m_GLMask = sGetGL(&s, cmb.Name, nHW);
510 if (cmb.Ident.m_GLMask == -1)
512 const char* szFileName = nameComb.c_str();
513 if (szFileName)
515 iLog->Log("Error: Error in '%s' file (Line: %d)", szFileName, nLine);
517 else
519 assert(!bFromFile);
520 iLog->Log("Error: Error in non-file shader (Line: %d)", nLine);
522 sSkipLine(s);
523 goto end;
526 ss = strchr(s, '(');
527 if (!ss)
529 sSkipLine(s);
530 goto end;
532 s = ss + 1;
533 cmb.Ident.m_RTMask = sGetRT(&s);
535 ss = strchr(s, '(');
536 if (!ss)
538 sSkipLine(s);
539 goto end;
541 s = ss + 1;
542 cmb.Ident.m_LightMask = shGetHex(s);
544 ss = strchr(s, '(');
545 if (!ss)
547 sSkipLine(s);
548 goto end;
550 s = ss + 1;
551 cmb.Ident.m_MDMask = shGetHex(s);
553 ss = strchr(s, '(');
554 if (!ss)
556 sSkipLine(s);
557 goto end;
559 s = ss + 1;
560 cmb.Ident.m_MDVMask = shGetHex(s);
562 ss = strchr(s, '(');
563 if (!ss)
565 sSkipLine(s);
566 goto end;
568 if (IsHexDigit(ss[1]) && (ss[2] != 'S'))
570 s = ss + 1;
571 cmb.Ident.m_pipelineState.opaque = shGetHex64(s);
572 bNewFormat = true;
573 s = strchr(s, '(');
575 else
577 cmb.Ident.m_pipelineState.opaque = 0;
578 s = ss;
580 if (s)
582 s++;
583 cmb.eCL = CHWShader::mfStringClass(s);
584 assert(cmb.eCL < eHWSC_Num);
586 else
588 cmb.eCL = eHWSC_Num;
589 s++;
591 #if CRY_RENDERER_VULKAN
592 ss = strchr(s, '(');
593 if (!ss)
595 sSkipLine(s);
596 goto end;
598 const char* descriptorSetBegin = ss + 1;
599 const char* descriptorSetEnd = strchr(descriptorSetBegin, ')');
600 const unsigned int descriptorSetLength = static_cast<int>(descriptorSetEnd - descriptorSetBegin);
601 if (descriptorSetLength > 0)
603 unsigned int decodedBufferSize = Base64::decodedsize_base64(descriptorSetLength);
604 std::vector<uint8> encodedLayout(decodedBufferSize);
605 Base64::decode_base64((char*)&encodedLayout[0], descriptorSetBegin, descriptorSetLength, false);
606 encodedLayout.resize(GetDeviceObjectFactory().GetEncodedResourceLayoutSize(encodedLayout));
608 if (!GetDeviceObjectFactory().LookupResourceLayoutEncoding(cmb.Ident.m_pipelineState.VULKAN.resourceLayoutHash))
610 GetDeviceObjectFactory().RegisterEncodedResourceLayout(cmb.Ident.m_pipelineState.VULKAN.resourceLayoutHash, std::move(encodedLayout));
613 #endif
614 if (bNewFormat)
616 CCryNameR nm = CCryNameR(st);
617 if (bExportEntry)
619 FXShaderCacheCombinationsItor it = m_ShaderCacheExportCombinations.find(nm);
620 if (it == m_ShaderCacheExportCombinations.end())
622 cmb.CacheName = nm;
623 m_ShaderCacheExportCombinations.insert(FXShaderCacheCombinationsItor::value_type(nm, cmb));
626 else
628 FXShaderCacheCombinationsItor it = Combinations->find(nm);
629 if (it != Combinations->end())
631 //assert(false);
633 else
635 cmb.CacheName = nm;
636 Combinations->insert(FXShaderCacheCombinationsItor::value_type(nm, cmb));
638 if (nHW)
640 for (int j = 0; j < 64; j++)
642 if (((uint64)1 << j) & nHW)
644 cmb.Ident.m_GLMask &= ~((uint64)1 << j);
645 sIterateHW_r(Combinations, cmb, j + 1, nHW, name);
646 cmb.Ident.m_GLMask |= ((uint64)1 << j);
647 sIterateHW_r(Combinations, cmb, j + 1, nHW, name);
648 cmb.Ident.m_GLMask &= ~((uint64)1 << j);
654 continue;
655 end:
656 iLog->Log("Error: Error in '%s' file (Line: %d)", nameComb.c_str(), nLine);
661 #if CRY_PLATFORM_DESKTOP
662 static void sResetDepend_r(SShaderGen* pGen, SShaderGenBit* pBit, SCacheCombination& cm)
664 if (!pBit->m_DependResets.size())
665 return;
666 uint32 i, j;
668 for (i = 0; i < pBit->m_DependResets.size(); i++)
670 const char* c = pBit->m_DependResets[i].c_str();
671 for (j = 0; j < pGen->m_BitMask.Num(); j++)
673 SShaderGenBit* pBit1 = pGen->m_BitMask[j];
674 if (!stricmp(pBit1->m_ParamName.c_str(), c))
676 cm.Ident.m_RTMask &= ~pBit1->m_Mask;
677 sResetDepend_r(pGen, pBit1, cm);
678 break;
684 static void sSetDepend_r(SShaderGen* pGen, SShaderGenBit* pBit, SCacheCombination& cm)
686 if (!pBit->m_DependSets.size())
687 return;
688 uint32 i, j;
690 for (i = 0; i < pBit->m_DependSets.size(); i++)
692 const char* c = pBit->m_DependSets[i].c_str();
693 for (j = 0; j < pGen->m_BitMask.Num(); j++)
695 SShaderGenBit* pBit1 = pGen->m_BitMask[j];
696 if (!stricmp(pBit1->m_ParamName.c_str(), c))
698 cm.Ident.m_RTMask |= pBit1->m_Mask;
699 sSetDepend_r(pGen, pBit1, cm);
700 break;
706 // Support for single light only
707 static bool sIterateDL(DWORD& dwDL)
709 int nLights = dwDL & 0xf;
710 int nType[4];
711 int i;
713 if (!nLights)
715 dwDL = 1;
716 return true;
718 for (i = 0; i < nLights; i++)
720 nType[i] = (dwDL >> (SLMF_LTYPE_SHIFT + (i * SLMF_LTYPE_BITS))) & ((1 << SLMF_LTYPE_BITS) - 1);
722 switch (nLights)
724 case 1:
725 if ((nType[0] & 3) < 2)
727 nType[0]++;
729 else
731 return false;
732 nLights = 2;
733 nType[0] = SLMF_DIRECT;
734 nType[1] = SLMF_POINT;
736 break;
737 case 2:
738 if ((nType[0] & 3) == SLMF_DIRECT)
740 nType[0] = SLMF_POINT;
741 nType[1] = SLMF_POINT;
743 else
745 nLights = 3;
746 nType[0] = SLMF_DIRECT;
747 nType[1] = SLMF_POINT;
748 nType[2] = SLMF_POINT;
750 break;
751 case 3:
752 if ((nType[0] & 3) == SLMF_DIRECT)
754 nType[0] = SLMF_POINT;
755 nType[1] = SLMF_POINT;
756 nType[2] = SLMF_POINT;
758 else
760 nLights = 4;
761 nType[0] = SLMF_DIRECT;
762 nType[1] = SLMF_POINT;
763 nType[2] = SLMF_POINT;
764 nType[3] = SLMF_POINT;
766 break;
767 case 4:
768 if ((nType[0] & 3) == SLMF_DIRECT)
770 nType[0] = SLMF_POINT;
771 nType[1] = SLMF_POINT;
772 nType[2] = SLMF_POINT;
773 nType[3] = SLMF_POINT;
775 else
776 return false;
778 dwDL = nLights;
779 for (i = 0; i < nLights; i++)
781 dwDL |= nType[i] << (SLMF_LTYPE_SHIFT + i * SLMF_LTYPE_BITS);
783 return true;
786 /*static bool sIterateDL(DWORD& dwDL)
788 int nLights = dwDL & 0xf;
789 int nType[4];
790 int i;
792 if (!nLights)
794 dwDL = 1;
795 return true;
797 for (i=0; i<nLights; i++)
799 nType[i] = (dwDL >> (SLMF_LTYPE_SHIFT + (i*SLMF_LTYPE_BITS))) & ((1<<SLMF_LTYPE_BITS)-1);
801 switch (nLights)
803 case 1:
804 if (!(nType[0] & SLMF_RAE_ENABLED))
805 nType[0] |= SLMF_RAE_ENABLED;
806 else
807 if (nType[0]<2)
808 nType[0]++;
809 else
811 nLights = 2;
812 nType[0] = SLMF_DIRECT;
813 nType[1] = SLMF_POINT;
815 break;
816 case 2:
817 if (!(nType[0] & SLMF_RAE_ENABLED))
818 nType[0] |= SLMF_RAE_ENABLED;
819 else
820 if (!(nType[1] & SLMF_RAE_ENABLED))
821 nType[1] |= SLMF_RAE_ENABLED;
822 else
823 if (nType[0] == SLMF_DIRECT)
824 nType[0] = SLMF_POINT;
825 else
827 nLights = 3;
828 nType[0] = SLMF_DIRECT;
829 nType[1] = SLMF_POINT;
830 nType[2] = SLMF_POINT;
832 break;
833 case 3:
834 if (!(nType[0] & SLMF_RAE_ENABLED))
835 nType[0] |= SLMF_RAE_ENABLED;
836 else
837 if (!(nType[1] & SLMF_RAE_ENABLED))
838 nType[1] |= SLMF_RAE_ENABLED;
839 else
840 if (!(nType[2] & SLMF_RAE_ENABLED))
841 nType[2] |= SLMF_RAE_ENABLED;
842 else
843 if (nType[0] == SLMF_DIRECT)
844 nType[0] = SLMF_POINT;
845 else
847 nLights = 4;
848 nType[0] = SLMF_DIRECT;
849 nType[1] = SLMF_POINT;
850 nType[2] = SLMF_POINT;
851 nType[3] = SLMF_POINT;
853 break;
854 case 4:
855 if (!(nType[0] & SLMF_RAE_ENABLED))
856 nType[0] |= SLMF_RAE_ENABLED;
857 else
858 if (!(nType[1] & SLMF_RAE_ENABLED))
859 nType[1] |= SLMF_RAE_ENABLED;
860 else
861 if (!(nType[2] & SLMF_RAE_ENABLED))
862 nType[2] |= SLMF_RAE_ENABLED;
863 else
864 if (!(nType[3] & SLMF_RAE_ENABLED))
865 nType[3] |= SLMF_RAE_ENABLED;
866 else
867 if (nType[0] == SLMF_DIRECT)
868 nType[0] = SLMF_POINT;
869 else
870 return false;
872 dwDL = nLights;
873 for (i=0; i<nLights; i++)
875 dwDL |= nType[i] << (SLMF_LTYPE_SHIFT + i*SLMF_LTYPE_BITS);
877 return true;
880 void CShaderMan::mfAddLTCombination(SCacheCombination* cmb, FXShaderCacheCombinations& CmbsMapDst, DWORD dwL)
882 char str[1024];
883 char sLT[64];
885 SCacheCombination cm;
886 cm = *cmb;
887 cm.Ident.m_LightMask = dwL;
889 const char* c = strchr(cmb->CacheName.c_str(), ')');
890 c = strchr(&c[1], ')');
891 int len = (int)(c - cmb->CacheName.c_str() + 1);
892 assert(len < sizeof(str));
893 cry_strcpy(str, cmb->CacheName.c_str(), len);
894 cry_strcat(str, "(");
895 cry_sprintf(sLT, "%x", (uint32)dwL);
896 cry_strcat(str, sLT);
897 c = strchr(&c[2], ')');
898 cry_strcat(str, c);
899 CCryNameR nm = CCryNameR(str);
900 cm.CacheName = nm;
901 FXShaderCacheCombinationsItor it = CmbsMapDst.find(nm);
902 if (it == CmbsMapDst.end())
904 CmbsMapDst.insert(FXShaderCacheCombinationsItor::value_type(nm, cm));
908 void CShaderMan::mfAddLTCombinations(SCacheCombination* cmb, FXShaderCacheCombinations& CmbsMapDst)
910 if (!CRenderer::CV_r_shadersprecachealllights)
911 return;
913 DWORD dwL = 0; // 0 lights
914 bool bRes = false;
917 // !HACK: Do not iterate multiple lights for low spec
918 if ((cmb->Ident.m_RTMask & (g_HWSR_MaskBit[HWSR_QUALITY] | g_HWSR_MaskBit[HWSR_QUALITY1])) || (dwL & 0xf) <= 1)
919 mfAddLTCombination(cmb, CmbsMapDst, dwL);
920 bRes = sIterateDL(dwL);
922 while (bRes);
925 void CShaderMan::mfAddRTCombination_r(int nComb, FXShaderCacheCombinations& CmbsMapDst, SCacheCombination* cmb, CHWShader* pSH, bool bAutoPrecache)
927 uint32 i, j, n;
928 uint32 dwType = pSH->m_dwShaderType;
929 if (!dwType)
930 return;
931 for (i = nComb; i < m_pGlobalExt->m_BitMask.Num(); i++)
933 SShaderGenBit* pBit = m_pGlobalExt->m_BitMask[i];
934 if (bAutoPrecache && !(pBit->m_Flags & (SHGF_AUTO_PRECACHE | SHGF_LOWSPEC_AUTO_PRECACHE)))
935 continue;
937 // Precache this flag on low-spec only
938 if (pBit->m_Flags & SHGF_LOWSPEC_AUTO_PRECACHE)
940 if (cmb->Ident.m_RTMask & (g_HWSR_MaskBit[HWSR_QUALITY] | g_HWSR_MaskBit[HWSR_QUALITY1]))
941 continue;
943 // Only in runtime used
944 if (pBit->m_Flags & SHGF_RUNTIME)
945 continue;
946 for (n = 0; n < pBit->m_PrecacheNames.size(); n++)
948 if (pBit->m_PrecacheNames[n] == dwType)
949 break;
951 if (n < pBit->m_PrecacheNames.size())
953 SCacheCombination cm;
954 cm = *cmb;
955 cm.Ident.m_RTMask &= ~pBit->m_Mask;
956 cm.Ident.m_RTMask |= (pBit->m_Mask ^ cmb->Ident.m_RTMask) & pBit->m_Mask;
957 if (!bAutoPrecache)
959 uint64 nBitSet = pBit->m_Mask & cmb->Ident.m_RTMask;
960 if (nBitSet)
961 sSetDepend_r(m_pGlobalExt, pBit, cm);
962 else
963 sResetDepend_r(m_pGlobalExt, pBit, cm);
966 char str[1024];
967 const char* c = strchr(cmb->CacheName.c_str(), '(');
968 const size_t len = (size_t)(c - cmb->CacheName.c_str());
969 cry_strcpy(str, cmb->CacheName.c_str(), len);
970 const char* c1 = strchr(&c[1], '(');
971 cry_strcat(str, c, (size_t)(c1 - c));
972 cry_strcat(str, "(");
973 SShaderGen* pG = m_pGlobalExt;
974 stack_string sRT;
975 for (j = 0; j < pG->m_BitMask.Num(); j++)
977 SShaderGenBit* pBit = pG->m_BitMask[j];
978 if (pBit->m_Mask & cm.Ident.m_RTMask)
980 if (!sRT.empty())
981 sRT += "|";
982 sRT += pBit->m_ParamName.c_str();
985 cry_strcat(str, sRT.c_str());
986 c1 = strchr(&c1[1], ')');
987 cry_strcat(str, c1);
988 CCryNameR nm = CCryNameR(str);
989 cm.CacheName = nm;
990 // HACK: don't allow unsupported quality mode
991 uint64 nQMask = g_HWSR_MaskBit[HWSR_QUALITY] | g_HWSR_MaskBit[HWSR_QUALITY1];
992 if ((cm.Ident.m_RTMask & nQMask) != nQMask)
994 FXShaderCacheCombinationsItor it = CmbsMapDst.find(nm);
995 if (it == CmbsMapDst.end())
997 CmbsMapDst.insert(FXShaderCacheCombinationsItor::value_type(nm, cm));
1000 if (pSH->m_Flags & (HWSG_SUPPORTS_MULTILIGHTS | HWSG_SUPPORTS_LIGHTING))
1001 mfAddLTCombinations(&cm, CmbsMapDst);
1002 mfAddRTCombination_r(i + 1, CmbsMapDst, &cm, pSH, bAutoPrecache);
1007 void CShaderMan::mfAddRTCombinations(FXShaderCacheCombinations& CmbsMapSrc, FXShaderCacheCombinations& CmbsMapDst, CHWShader* pSH, bool bListOnly)
1009 if (pSH->m_nFrameLoad == gRenDev->GetMainFrameID())
1010 return;
1011 pSH->m_nFrameLoad = gRenDev->GetMainFrameID();
1012 uint32 dwType = pSH->m_dwShaderType;
1013 if (!dwType)
1014 return;
1015 const char* str2 = pSH->mfGetEntryName();
1016 FXShaderCacheCombinationsItor itor;
1017 for (itor = CmbsMapSrc.begin(); itor != CmbsMapSrc.end(); itor++)
1019 SCacheCombination* cmb = &itor->second;
1020 const char* c = strchr(cmb->Name.c_str(), '@');
1021 if (!c)
1022 c = strchr(cmb->Name.c_str(), '/');
1023 assert(c);
1024 if (!c)
1025 continue;
1026 if (stricmp(&c[1], str2))
1027 continue;
1028 /*if (!stricmp(str2, "MetalReflVS"))
1030 if (cmb->nGL == 0x1093)
1032 int nnn = 0;
1035 if (bListOnly)
1037 if (pSH->m_Flags & (HWSG_SUPPORTS_MULTILIGHTS | HWSG_SUPPORTS_LIGHTING))
1038 mfAddLTCombinations(cmb, CmbsMapDst);
1039 mfAddRTCombination_r(0, CmbsMapDst, cmb, pSH, true);
1041 else
1042 mfAddRTCombination_r(0, CmbsMapDst, cmb, pSH, false);
1045 #endif // CRY_PLATFORM_DESKTOP
1047 void CShaderMan::mfInsertNewCombination(SShaderCombIdent& Ident, EHWShaderClass eCL, const char* name, int nID, string* Str, byte bStore)
1049 char str[2048];
1050 if (!m_FPCacheCombinations[nID] && bStore)
1051 return;
1053 stack_string sGL;
1054 stack_string sRT;
1055 uint32 i, j;
1056 SShaderGenComb* c = NULL;
1057 if (Ident.m_GLMask)
1059 const char* m = strchr(name, '@');
1060 if (!m)
1061 m = strchr(name, '/');
1062 assert(m);
1063 char nmFX[128];
1064 if (m)
1066 cry_strcpy(nmFX, name, (size_t)(m - name));
1067 c = mfGetShaderGenInfo(nmFX);
1068 if (c && c->pGen && c->pGen->m_BitMask.Num())
1070 SShaderGen* pG = c->pGen;
1071 for (i = 0; i < 64; i++)
1073 if (Ident.m_GLMask & ((uint64)1 << i))
1075 for (j = 0; j < pG->m_BitMask.Num(); j++)
1077 SShaderGenBit* pBit = pG->m_BitMask[j];
1078 if (pBit->m_Mask & (Ident.m_GLMask & ((uint64)1 << i)))
1080 if (!sGL.empty())
1081 sGL += "|";
1082 sGL += pBit->m_ParamName.c_str();
1083 break;
1091 if (Ident.m_RTMask)
1093 SShaderGen* pG = m_pGlobalExt;
1094 if (pG)
1096 for (i = 0; i < pG->m_BitMask.Num(); i++)
1098 SShaderGenBit* pBit = pG->m_BitMask[i];
1099 if (pBit->m_Mask & Ident.m_RTMask)
1101 if (!sRT.empty())
1102 sRT += "|";
1103 sRT += pBit->m_ParamName.c_str();
1108 uint32 nLT = Ident.m_LightMask;
1109 if (bStore == 1 && Ident.m_LightMask)
1110 nLT = 1;
1112 #ifdef CRY_RENDERER_VULKAN
1113 std::string base64EncodedLayout;
1114 const std::vector<uint8>* pEncodedLayout = GetDeviceObjectFactory().LookupResourceLayoutEncoding(Ident.m_pipelineState.VULKAN.resourceLayoutHash);
1115 if (pEncodedLayout)
1117 size_t base64EncodedLayoutSize = (Base64::encodedsize_base64(pEncodedLayout->size()));
1118 base64EncodedLayout.resize(base64EncodedLayoutSize);
1119 Base64::encode_base64((char*)&base64EncodedLayout[0], (const char*)pEncodedLayout->data(), pEncodedLayout->size(), false);
1121 sprintf(str, "<%d>%s(%s)(%s)(%x)(%x)(%x)(%llx)(%s)(%s)", SHADER_LIST_VER, name, sGL.c_str(), sRT.c_str(), nLT, Ident.m_MDMask, Ident.m_MDVMask, Ident.m_pipelineState.opaque, CHWShader::mfClassString(eCL), base64EncodedLayout.c_str());
1122 #else
1123 sprintf(str, "<%d>%s(%s)(%s)(%x)(%x)(%x)(%llx)(%s)", SHADER_LIST_VER, name, sGL.c_str(), sRT.c_str(), nLT, Ident.m_MDMask, Ident.m_MDVMask, Ident.m_pipelineState.opaque, CHWShader::mfClassString(eCL));
1124 #endif
1125 if (!bStore)
1127 if (Str)
1128 *Str = str;
1129 return;
1131 CCryNameR nm;
1132 if (str[0] == '<' && str[2] == '>')
1133 nm = CCryNameR(&str[3]);
1134 else
1135 nm = CCryNameR(str);
1136 FXShaderCacheCombinationsItor it = m_ShaderCacheCombinations[nID].find(nm);
1137 if (it != m_ShaderCacheCombinations[nID].end())
1138 return;
1139 SCacheCombination cmb;
1140 cmb.Name = name;
1141 cmb.CacheName = nm;
1142 cmb.Ident = Ident;
1143 cmb.eCL = eCL;
1145 stack_string nameOut;
1146 mfGetShaderListPath(nameOut, nID);
1148 static CryCriticalSection s_cResLock;
1149 AUTO_LOCK(s_cResLock); // Not thread safe without this
1151 if (m_FPCacheCombinations[nID])
1153 m_ShaderCacheCombinations[nID].insert(FXShaderCacheCombinationsItor::value_type(nm, cmb));
1154 gEnv->pCryPak->FPrintf(m_FPCacheCombinations[nID], "%s\n", str);
1155 gEnv->pCryPak->FFlush(m_FPCacheCombinations[nID]);
1158 if (Str)
1159 *Str = str;
1162 string CShaderMan::mfGetShaderCompileFlags(EHWShaderClass eClass, UPipelineState pipelineState) const
1164 string result;
1166 #define STRICT_MODE " /Ges"
1167 #define COMPATIBLE_MODE " /Gec"
1168 // NOTE: when updating remote compiler folders, please ensure folders path is matching
1169 const char* pCompilerOrbis = "ORBIS/V033/DXOrbisShaderCompiler.exe %s %s %s %s";
1170 const char* pCompilerDurango = "Durango/March2017/fxc.exe /nologo /E %s /T %s /Zpr" COMPATIBLE_MODE "" STRICT_MODE " /Fo %s %s";
1171 const char* pCompilerD3D11 = "PCD3D11/v007/fxc.exe /nologo /E %s /T %s /Zpr" COMPATIBLE_MODE "" STRICT_MODE " /Fo %s %s";
1172 const char *pCompilerSPIRV = "SPIRV/V002/HLSL2SPIRV.exe %s %s %s %s";
1174 #define ESSL_VERSION "es310"
1175 #if DXGL_REQUIRED_VERSION >= DXGL_VERSION_45
1176 #define GLSL_VERSION "450"
1177 #elif DXGL_REQUIRED_VERSION >= DXGL_VERSION_44
1178 #define GLSL_VERSION "440"
1179 #elif DXGL_REQUIRED_VERSION >= DXGL_VERSION_43
1180 #define GLSL_VERSION "430"
1181 #elif DXGL_REQUIRED_VERSION >= DXGL_VERSION_42
1182 #define GLSL_VERSION "420"
1183 #elif DXGL_REQUIRED_VERSION >= DXGL_VERSION_41
1184 #define GLSL_VERSION "410"
1185 #elif DXGLES_REQUIRED_VERSION >= DXGLES_VERSION_31
1186 #define GLSL_VERSION "310"
1187 #elif DXGLES_REQUIRED_VERSION >= DXGLES_VERSION_30
1188 #define GLSL_VERSION "300"
1189 #else
1190 #error "Shading language revision not defined for this GL version"
1191 #endif
1193 const char* pCompilerGL4 = "PCGL/V012/HLSLcc.exe -lang=" GLSL_VERSION " -flags=36609 -fxc=\"..\\..\\PCD3D11\\v007\\fxc.exe /nologo /E %s /T %s /Zpr" COMPATIBLE_MODE "" STRICT_MODE " /Fo\" -out=%s -in=%s";
1194 const char* pCompilerGLES3 = "PCGL/V012/HLSLcc.exe -lang=" ESSL_VERSION " -flags=36609 -fxc=\"..\\..\\PCD3D11\\v007\\fxc.exe /nologo /E %s /T %s /Zpr" COMPATIBLE_MODE "" STRICT_MODE " /Fo\" -out=%s -in=%s";
1196 if (CRenderer::CV_r_shadersdebug == 3)
1198 // Set debug information
1199 pCompilerD3D11 = "PCD3D11/v007/fxc.exe /nologo /E %s /T %s /Zpr" COMPATIBLE_MODE "" STRICT_MODE " /Zi /Od /Fo %s %s";
1200 pCompilerDurango = "Durango/March2017/fxc.exe /nologo /E %s /T %s /Zpr" COMPATIBLE_MODE "" STRICT_MODE " /Zi /Od /Fo %s %s";
1202 else if (CRenderer::CV_r_shadersdebug == 4)
1204 // Set debug information, optimized shaders
1205 pCompilerD3D11 = "PCD3D11/v007/fxc.exe /nologo /E %s /T %s /Zpr" COMPATIBLE_MODE "" STRICT_MODE " /Zi /O3 /Fo %s %s";
1206 pCompilerDurango = "Durango/March2017/fxc.exe /nologo /E %s /T %s /Zpr" COMPATIBLE_MODE "" STRICT_MODE " /Zi /O3 /Fo %s %s";
1209 if (pipelineState.opaque != 0)
1211 if (CParserBin::m_nPlatform == SF_ORBIS)
1213 const char* const pCompilerGnm = "ORBIS/V033/GnmShaderCompiler.exe %s %s %s %s --RowMajorMatrixStorage --UpgradeLegacySamplers --DebugHelperFiles";
1215 static const char* kVsStages[] =
1217 "V2P",
1218 "V2H",
1219 "V2G",
1220 "V2L",
1221 "C2V2P",
1222 "C2I2P",
1223 nullptr,
1224 nullptr
1226 static const int kPsDepthBits[] =
1233 static const char kISA[] =
1235 'B',
1236 'C',
1237 'N',
1238 'R',
1241 switch (eClass)
1243 case eHWSC_Vertex:
1244 result.Format("%s -HwStage=%s -HwISA=%c", pCompilerGnm, kVsStages[pipelineState.GNM.VS.targetStage & 7], kISA[(pipelineState.GNM.VS.targetStage >> 5) & 3]);
1245 break;
1246 case eHWSC_Hull:
1247 result.Format("%s -HwStage=%s -HwISA=%c", pCompilerGnm, (pipelineState.GNM.HS.targetStage & 1) ? "H2D" : "H2M", kISA[(pipelineState.GNM.HS.targetStage >> 5) & 3]);
1248 break;
1249 case eHWSC_Domain:
1250 result.Format("%s -HwStage=%s -HwISA=%c", pCompilerGnm, (pipelineState.GNM.DS.targetStage & 1) ? "D2P" : "M2P", kISA[(pipelineState.GNM.DS.targetStage >> 5) & 3]);
1251 break;
1252 case eHWSC_Geometry:
1253 result.Format("%s -HwStage=%s -HwISA=%c", pCompilerGnm, (pipelineState.GNM.GS.targetStage & 1) ? "L2C2P" : "G2C2P", kISA[(pipelineState.GNM.GS.targetStage >> 5) & 3]);
1254 break;
1255 case eHWSC_Pixel:
1256 result.Format("%s -HwStage=%s -HwISA=%c -PsColor=0x%x -PsDepth=%d -PsStencil=%d", pCompilerGnm, "P", kISA[(pipelineState.GNM.PS.depthStencilInfo >> 29) & 3], pipelineState.GNM.PS.targetFormats, kPsDepthBits[(pipelineState.GNM.PS.depthStencilInfo >> 1) & 3], pipelineState.GNM.PS.depthStencilInfo & 1 ? 8 : 0);
1257 break;
1258 case eHWSC_Compute:
1259 result.Format("%s -HwStage=%s -HwISA=%c", pCompilerGnm, "C", kISA[(pipelineState.GNM.CS.targetStage >> 5) & 3]);
1260 break;
1261 default:
1262 CRY_ASSERT(false && "Unknown stage");
1263 break;
1266 return result;
1270 #if CRY_PLATFORM_ORBIS
1271 result = pCompilerOrbis;
1272 #elif CRY_PLATFORM_DURANGO
1273 result = pCompilerDurango;
1274 #elif CRY_RENDERER_OPENGLES && DXGL_INPUT_GLSL
1275 result = pCompilerGLES3;
1276 #elif CRY_RENDERER_OPENGL && DXGL_INPUT_GLSL
1277 result = pCompilerGL4;
1278 #else
1279 if (CParserBin::m_nPlatform == SF_D3D11)
1280 result = pCompilerD3D11;
1281 else if (CParserBin::m_nPlatform == SF_ORBIS)
1282 result = pCompilerOrbis;
1283 else if (CParserBin::m_nPlatform == SF_DURANGO)
1284 result = pCompilerDurango;
1285 else if (CParserBin::m_nPlatform == SF_GL4)
1286 result = pCompilerGL4;
1287 else if (CParserBin::m_nPlatform == SF_GLES3)
1288 result = pCompilerGLES3;
1289 else if (CParserBin::m_nPlatform == SF_VULKAN)
1290 result = pCompilerSPIRV;
1291 else
1293 CryFatalError("Compiling shaders for unsupported platform");
1294 result = "";
1296 #endif
1298 if (!CRenderer::CV_r_shadersCompileStrict)
1300 result = result.replace("" STRICT_MODE "", "");
1303 if (!CRenderer::CV_r_shadersCompileCompatible)
1305 result = result.replace("" COMPATIBLE_MODE "", "");
1308 return result;
1311 inline bool sCompareComb(const SCacheCombination& a, const SCacheCombination& b)
1313 int32 dif;
1315 char shader1[128], shader2[128];
1316 char* tech1 = NULL, * tech2 = NULL;
1317 cry_strcpy(shader1, a.Name.c_str());
1318 cry_strcpy(shader2, b.Name.c_str());
1319 char* c = strchr(shader1, '@');
1320 if (!c)
1321 c = strchr(shader1, '/');
1322 //assert(c);
1323 if (c)
1325 *c = 0;
1326 tech1 = c + 1;
1328 c = strchr(shader2, '@');
1329 if (!c)
1330 c = strchr(shader2, '/');
1331 //assert(c);
1332 if (c)
1334 *c = 0;
1335 tech2 = c + 1;
1338 dif = stricmp(shader1, shader2);
1339 if (dif != 0)
1340 return dif < 0;
1342 if (tech1 == NULL && tech2 != NULL)
1343 return true;
1344 if (tech1 != NULL && tech2 == NULL)
1345 return false;
1347 if (tech1 != NULL && tech2 != NULL)
1349 dif = stricmp(tech1, tech2);
1350 if (dif != 0)
1351 return dif < 0;
1354 if (a.Ident.m_GLMask != b.Ident.m_GLMask)
1355 return a.Ident.m_GLMask < b.Ident.m_GLMask;
1357 if (a.Ident.m_RTMask != b.Ident.m_RTMask)
1358 return a.Ident.m_RTMask < b.Ident.m_RTMask;
1360 if (a.Ident.m_pipelineState.opaque != b.Ident.m_pipelineState.opaque)
1361 return a.Ident.m_pipelineState.opaque < b.Ident.m_pipelineState.opaque;
1363 if (a.Ident.m_FastCompare1 != b.Ident.m_FastCompare1)
1364 return a.Ident.m_FastCompare1 < b.Ident.m_FastCompare1;
1366 if (a.Ident.m_FastCompare2 != b.Ident.m_FastCompare2)
1367 return a.Ident.m_FastCompare2 < b.Ident.m_FastCompare2;
1369 return false;
1372 #if CRY_PLATFORM_DESKTOP
1374 void CShaderMan::AddGLCombinations(CShader* pSH, std::vector<SCacheCombination>& CmbsGL)
1376 int i, j;
1377 uint64 nMask = 0;
1378 if (pSH->m_pGenShader)
1380 SShaderGen* pG = pSH->m_pGenShader->m_ShaderGenParams;
1381 for (i = 0; i < pG->m_BitMask.size(); i++)
1383 SShaderGenBit* pB = pG->m_BitMask[i];
1384 SCacheCombination cc;
1385 cc.Name = pB->m_ParamName;
1386 for (j = 0; j < m_pGlobalExt->m_BitMask.size(); j++)
1388 SShaderGenBit* pB1 = m_pGlobalExt->m_BitMask[j];
1389 if (pB1->m_ParamName == pB->m_ParamName)
1391 nMask |= pB1->m_Mask;
1392 break;
1395 assert(j != m_pGlobalExt->m_BitMask.size());
1396 for (i = 0; i < 64; i++)
1398 //if (nMask & (1<<i))
1399 // SetBit_r(i, CmbsGL);
1403 else
1405 SCacheCombination cc;
1406 cc.Ident.m_GLMask = 0;
1407 CmbsGL.push_back(cc);
1411 void CShaderMan::AddGLCombination(FXShaderCacheCombinations& CmbsMap, SCacheCombination& cmb)
1413 char str[1024];
1414 const char* st = cmb.CacheName.c_str();
1415 if (st[0] == '<')
1416 st += 3;
1417 const char* s = strchr(st, '@');
1418 char name[128];
1419 if (!s)
1420 s = strchr(st, '/');
1421 if (s)
1423 memcpy(name, st, s - st);
1424 name[s - st] = 0;
1426 else
1427 cry_strcpy(name, st);
1428 #ifdef __GNUC__
1429 cry_sprintf(str, "%s(%llx)(%x)(%x)", name, cmb.Ident.m_GLMask, cmb.Ident.m_MDMask, cmb.Ident.m_MDVMask);
1430 #else
1431 cry_sprintf(str, "%s(%I64x)(%x)(%x)", name, cmb.Ident.m_GLMask, cmb.Ident.m_MDMask, cmb.Ident.m_MDVMask);
1432 #endif
1433 CCryNameR nm = CCryNameR(str);
1434 FXShaderCacheCombinationsItor it = CmbsMap.find(nm);
1435 if (it == CmbsMap.end())
1437 cmb.CacheName = nm;
1438 cmb.Name = nm;
1439 CmbsMap.insert(FXShaderCacheCombinationsItor::value_type(nm, cmb));
1443 /*string str;
1444 gRenDev->m_cEF.mfInsertNewCombination(cmb.nGL, cmb.nRT, cmb.nLT, cmb.nMD, cmb.nMDV, cmb.ePR, szName, 0, &str, false);
1445 CCryNameTSCRC nm = CCryNameTSCRC(str.c_str());
1446 FXShaderCacheCombinationsItor it = Combinations->find(nm);
1447 if (it == Combinations->end())
1449 cmb.CacheName = nm;
1450 Combinations->insert(FXShaderCacheCombinationsItor::value_type(nm, cmb));
1452 for (int j=i; j<64; j++)
1454 if (((uint64)1<<j) & nHW)
1456 cmb.nGL &= ~((uint64)1<<j);
1457 sIterateHW_r(Combinations, cmb, j+1, nHW, szName);
1458 cmb.nGL |= ((uint64)1<<j);
1459 sIterateHW_r(Combinations, cmb, j+1, nHW, szName);
1463 void CShaderMan::AddCombination(SCacheCombination& cmb, FXShaderCacheCombinations& CmbsMap, CHWShader* pHWS)
1465 char str[2048];
1466 #ifdef __GNUC__
1467 sprintf(str, "%s(%llx)(%llx)(%d)(%d)(%d)(%llx)", cmb.Name.c_str(), cmb.Ident.m_GLMask, cmb.Ident.m_RTMask, cmb.Ident.m_LightMask, cmb.Ident.m_MDMask, cmb.Ident.m_MDVMask, cmb.Ident.m_pipelineState.opaque);
1468 #else
1469 sprintf(str, "%s(%I64x)(%I64x)(%d)(%d)(%d)(%llx)", cmb.Name.c_str(), cmb.Ident.m_GLMask, cmb.Ident.m_RTMask, cmb.Ident.m_LightMask, cmb.Ident.m_MDMask, cmb.Ident.m_MDVMask, cmb.Ident.m_pipelineState.opaque);
1470 #endif
1471 CCryNameR nm = CCryNameR(str);
1472 FXShaderCacheCombinationsItor it = CmbsMap.find(nm);
1473 if (it == CmbsMap.end())
1475 cmb.CacheName = nm;
1476 CmbsMap.insert(FXShaderCacheCombinationsItor::value_type(nm, cmb));
1480 void CShaderMan::AddLTCombinations(SCacheCombination& cmb, FXShaderCacheCombinations& CmbsMap, CHWShader* pHWS)
1482 assert(pHWS->m_Flags & HWSG_SUPPORTS_LIGHTING);
1484 // Just single light support
1486 // Directional light
1487 cmb.Ident.m_LightMask = 1;
1488 AddCombination(cmb, CmbsMap, pHWS);
1490 // Point light
1491 cmb.Ident.m_LightMask = 0x101;
1492 AddCombination(cmb, CmbsMap, pHWS);
1494 // Projected light
1495 cmb.Ident.m_LightMask = 0x201;
1496 AddCombination(cmb, CmbsMap, pHWS);
1499 void CShaderMan::AddRTCombinations(FXShaderCacheCombinations& CmbsMap, CHWShader* pHWS, CShader* pSH, FXShaderCacheCombinations* Combinations)
1501 SCacheCombination cmb;
1503 uint32 nType = pHWS->m_dwShaderType;
1505 uint32 i, j;
1506 SShaderGen* pGen = m_pGlobalExt;
1507 int nBits = 0;
1509 uint32 nBitsPlatform = 0;
1510 if (CParserBin::m_nPlatform == SF_ORBIS)
1511 nBitsPlatform |= SHGD_HW_ORBIS;
1512 else if (CParserBin::m_nPlatform == SF_DURANGO)
1513 nBitsPlatform |= SHGD_HW_DURANGO;
1514 else if (CParserBin::m_nPlatform == SF_D3D11)
1515 nBitsPlatform |= SHGD_HW_DX11;
1516 else if (CParserBin::m_nPlatform == SF_GL4)
1517 nBitsPlatform |= SHGD_HW_GL4;
1518 else if (CParserBin::m_nPlatform == SF_GLES3)
1519 nBitsPlatform |= SHGD_HW_GLES3;
1520 else if (CParserBin::m_nPlatform == SF_VULKAN)
1521 nBitsPlatform |= SHGD_HW_VULKAN;
1523 uint64 BitMask[64];
1524 memset(BitMask, 0, sizeof(BitMask));
1526 // Make a mask of flags affected by this type of shader
1527 uint64 nRTMask = 0;
1528 uint64 nSetMask = 0;
1530 if (nType)
1532 for (i = 0; i < pGen->m_BitMask.size(); i++)
1534 SShaderGenBit* pBit = pGen->m_BitMask[i];
1535 if (!pBit->m_Mask)
1536 continue;
1537 if (pBit->m_Flags & SHGF_RUNTIME)
1538 continue;
1539 if (nBitsPlatform & pBit->m_nDependencyReset)
1540 continue;
1541 for (j = 0; j < pBit->m_PrecacheNames.size(); j++)
1543 if (pBit->m_PrecacheNames[j] == nType)
1545 if (nBitsPlatform & pBit->m_nDependencySet)
1547 nSetMask |= pBit->m_Mask;
1548 continue;
1550 BitMask[nBits++] = pBit->m_Mask;
1551 nRTMask |= pBit->m_Mask;
1552 break;
1557 if (nBits > 10)
1558 CryLog("WARNING: Number of runtime bits for shader '%s' - %d: exceed 10 (too many combinations will be produced)...", pHWS->GetName(), nBits);
1559 if (nBits > 30)
1561 CryLog("Error: Ignore...");
1562 return;
1565 cmb.eCL = pHWS->m_eSHClass;
1566 string szName = string(pSH->GetName());
1567 szName += string("@") + string(pHWS->m_EntryFunc.c_str());
1568 cmb.Name = szName;
1569 cmb.Ident.m_GLMask = pHWS->m_nMaskGenShader;
1571 // For unknown shader type just add combinations from the list
1572 if (!nType)
1574 FXShaderCacheCombinationsItor itor;
1575 for (itor = Combinations->begin(); itor != Combinations->end(); itor++)
1577 SCacheCombination* c = &itor->second;
1578 if (c->Name == cmb.Name && c->Ident.m_GLMask == pHWS->m_nMaskGenFX)
1580 cmb = *c;
1581 AddCombination(cmb, CmbsMap, pHWS);
1584 return;
1587 cmb.Ident.m_LightMask = 0;
1588 cmb.Ident.m_MDMask = 0;
1589 cmb.Ident.m_MDVMask = 0;
1590 cmb.Ident.m_RTMask = 0;
1592 int nIterations = 1 << nBits;
1593 for (i = 0; i < nIterations; i++)
1595 cmb.Ident.m_RTMask = nSetMask;
1596 cmb.Ident.m_LightMask = 0;
1597 for (j = 0; j < nBits; j++)
1599 if ((1 << j) & i)
1600 cmb.Ident.m_RTMask |= BitMask[j];
1602 /*if (cmb.nRT == 0x40002)
1604 int nnn = 0;
1606 AddCombination(cmb, CmbsMap, pHWS);
1607 if (pHWS->m_Flags & HWSG_SUPPORTS_LIGHTING)
1608 AddLTCombinations(cmb, CmbsMap, pHWS);
1612 void CShaderMan::_PrecacheShaderList(bool bStatsOnly)
1614 float t0 = gEnv->pTimer->GetAsyncCurTime();
1616 if (!m_pGlobalExt)
1617 return;
1619 m_eCacheMode = eSC_BuildGlobalList;
1621 uint32 nSaveFeatures = gRenDev->m_Features;
1622 int nAsync = CRenderer::CV_r_shadersasynccompiling;
1623 if (nAsync != 3)
1624 CRenderer::CV_r_shadersasynccompiling = 0;
1626 // Command line shaders precaching
1627 gRenDev->m_Features |= RFT_HW_SM20 | RFT_HW_SM2X | RFT_HW_SM30;
1628 FXShaderCacheCombinations* Combinations = &m_ShaderCacheCombinations[0];
1630 std::vector<SCacheCombination> Cmbs;
1631 std::vector<SCacheCombination> CmbsRT;
1632 FXShaderCacheCombinations CmbsMap;
1633 char str1[128], str2[128];
1635 // Extract global combinations only (including MD and MDV)
1636 for (FXShaderCacheCombinationsItor itor = Combinations->begin(); itor != Combinations->end(); itor++)
1638 SCacheCombination* cmb = &itor->second;
1639 FXShaderCacheCombinationsItor it = CmbsMap.find(cmb->CacheName);
1640 if (it == CmbsMap.end())
1642 CmbsMap.insert(FXShaderCacheCombinationsItor::value_type(cmb->CacheName, *cmb));
1645 for (FXShaderCacheCombinationsItor itor = CmbsMap.begin(); itor != CmbsMap.end(); itor++)
1647 SCacheCombination* cmb = &itor->second;
1648 Cmbs.push_back(*cmb);
1651 mfExportShaders();
1653 int nEmpty = 0;
1654 int nProcessed = 0;
1655 int nCompiled = 0;
1656 int nMaterialCombinations = 0;
1658 if (Cmbs.size() >= 1)
1660 std::stable_sort(Cmbs.begin(), Cmbs.end(), sCompareComb);
1662 nMaterialCombinations = Cmbs.size();
1664 m_nCombinationsProcess = Cmbs.size();
1665 m_bReload = true;
1666 m_nCombinationsCompiled = 0;
1667 m_nCombinationsEmpty = 0;
1668 uint64 nGLLast = -1;
1669 for (int i = 0; i < Cmbs.size(); i++)
1671 SCacheCombination* cmb = &Cmbs[i];
1672 cry_strcpy(str1, cmb->Name.c_str());
1673 char* c = strchr(str1, '@');
1674 if (!c)
1675 c = strchr(str1, '/');
1676 //assert(c);
1677 if (c)
1679 *c = 0;
1680 m_szShaderPrecache = &c[1];
1682 else
1684 c = strchr(str1, '(');
1685 if (c)
1687 *c = 0;
1688 m_szShaderPrecache = "";
1692 CShader* pSH = CShaderMan::mfForName(str1, 0, NULL, cmb->Ident.m_GLMask);
1693 if (!pSH)
1694 continue;
1696 std::vector<SCacheCombination>* pCmbs = &Cmbs;
1697 FXShaderCacheCombinations CmbsMapRTSrc;
1698 FXShaderCacheCombinations CmbsMapRTDst;
1700 for (int m = 0; m < pSH->m_HWTechniques.Num(); m++)
1702 SShaderTechnique* pTech = pSH->m_HWTechniques[m];
1703 for (int n = 0; n < pTech->m_Passes.Num(); n++)
1705 SShaderPass* pPass = &pTech->m_Passes[n];
1706 if (pPass->m_PShader)
1707 pPass->m_PShader->m_nFrameLoad = -10;
1708 if (pPass->m_VShader)
1709 pPass->m_VShader->m_nFrameLoad = -10;
1713 for (; i < Cmbs.size(); i++)
1715 SCacheCombination* cmba = &Cmbs[i];
1716 cry_strcpy(str2, cmba->Name.c_str());
1717 c = strchr(str2, '@');
1718 if (!c)
1719 c = strchr(str2, '/');
1720 assert(c);
1721 if (c)
1722 *c = 0;
1723 if (stricmp(str1, str2) || cmb->Ident.m_GLMask != cmba->Ident.m_GLMask)
1724 break;
1725 CmbsMapRTSrc.insert(FXShaderCacheCombinationsItor::value_type(cmba->CacheName, *cmba));
1727 // surrounding for(;;i++) will increment this again
1728 i--;
1729 m_nCombinationsProcess -= CmbsMapRTSrc.size();
1731 for (FXShaderCacheCombinationsItor itor = CmbsMapRTSrc.begin(); itor != CmbsMapRTSrc.end(); itor++)
1733 SCacheCombination* cmb = &itor->second;
1734 cry_strcpy(str2, cmb->Name.c_str());
1735 FXShaderCacheCombinationsItor it = CmbsMapRTDst.find(cmb->CacheName);
1736 if (it == CmbsMapRTDst.end())
1738 CmbsMapRTDst.insert(FXShaderCacheCombinationsItor::value_type(cmb->CacheName, *cmb));
1742 for (int m = 0; m < pSH->m_HWTechniques.Num(); m++)
1744 SShaderTechnique* pTech = pSH->m_HWTechniques[m];
1745 for (int n = 0; n < pTech->m_Passes.Num(); n++)
1747 SShaderPass* pPass = &pTech->m_Passes[n];
1748 if (pPass->m_PShader)
1749 mfAddRTCombinations(CmbsMapRTSrc, CmbsMapRTDst, pPass->m_PShader, true);
1750 if (pPass->m_VShader)
1751 mfAddRTCombinations(CmbsMapRTSrc, CmbsMapRTDst, pPass->m_VShader, true);
1755 CmbsRT.clear();
1756 for (FXShaderCacheCombinationsItor itor = CmbsMapRTDst.begin(); itor != CmbsMapRTDst.end(); itor++)
1758 SCacheCombination* cmb = &itor->second;
1759 CmbsRT.push_back(*cmb);
1761 pCmbs = &CmbsRT;
1762 m_nCombinationsProcessOverall = CmbsRT.size();
1763 m_nCombinationsProcess = 0;
1765 CmbsMapRTDst.clear();
1766 CmbsMapRTSrc.clear();
1767 uint32 nFlags = HWSF_PRECACHE;
1768 if (CParserBin::m_nPlatform & (SF_D3D11 | SF_DURANGO | SF_ORBIS | SF_GL4 | SF_GLES3 | SF_VULKAN))
1769 nFlags |= HWSF_STOREDATA;
1770 if (bStatsOnly)
1771 nFlags |= HWSF_FAKE;
1772 for (int jj = 0; jj < pCmbs->size(); jj++)
1774 m_nCombinationsProcess++;
1775 SCacheCombination* cmba = &(*pCmbs)[jj];
1776 c = (char*)strchr(cmba->Name.c_str(), '@');
1777 if (!c)
1778 c = (char*)strchr(cmba->Name.c_str(), '/');
1779 assert(c);
1780 if (!c)
1781 continue;
1782 m_szShaderPrecache = &c[1];
1783 /*if (!stricmp(m_szShaderPrecache, "IlluminationVS") && cmba->nRT == 0x10050000)
1785 int nnn = 0;
1787 //if (!stricmp(pSH->GetName(), "ParticlesNoMat"))*/
1788 /*if (!stricmp(cmba->CacheName.c_str(), "Cloth@Common_SG_VS(%STAT_BRANCHING|%WIND_BENDING)(%_RT_ALPHATEST|%_RT_QUALITY1|%_RT_INSTANCING_ROT|%_RT_INSTANCING_ATTR|%_RT_PSM|%_RT_HW_PCF_COMPARE)(0)(0)(800)(vs_2_0)"))
1790 int nnn = 0;
1792 /*if ((cmba->nRT == 0x10902200402)) // && cmba->nLT == 0)
1794 int nnn = 0;
1797 for (int m = 0; m < pSH->m_HWTechniques.Num(); m++)
1799 SShaderTechnique* pTech = pSH->m_HWTechniques[m];
1800 for (int n = 0; n < pTech->m_Passes.Num(); n++)
1802 SShaderPass* pPass = &pTech->m_Passes[n];
1803 SCacheCombination cmbSaved = *cmba;
1805 // Adjust some flags for low spec
1806 CHWShader* shaders[] = { pPass->m_PShader, pPass->m_VShader };
1807 for (int i = 0; i < 2; i++)
1809 CHWShader* shader = shaders[i];
1810 if (shader && (!m_szShaderPrecache || !stricmp(m_szShaderPrecache, shader->m_EntryFunc.c_str()) != 0))
1812 uint64 nFlagsOrigShader_RT = cmbSaved.Ident.m_RTMask & shader->m_nMaskAnd_RT | shader->m_nMaskOr_RT;
1813 uint64 nFlagsOrigShader_GL = shader->m_nMaskGenShader;
1814 uint32 nFlagsOrigShader_LT = cmbSaved.Ident.m_LightMask;
1816 shader->PrecacheShader(pSH, cmba->Ident, nFlags);
1818 if (nFlagsOrigShader_RT != cmbSaved.Ident.m_RTMask || nFlagsOrigShader_GL != shader->m_nMaskGenShader || nFlagsOrigShader_LT != cmbSaved.Ident.m_LightMask)
1820 m_nCombinationsEmpty++;
1821 if (!bStatsOnly)
1822 shader->mfAddEmptyCombination(pSH, nFlagsOrigShader_RT, nFlagsOrigShader_GL, nFlagsOrigShader_LT, cmbSaved);
1828 if (CParserBin::m_nPlatform & (SF_D3D11 | SF_DURANGO | SF_ORBIS | SF_GL4 | SF_VULKAN))
1830 CHWShader* d3d11Shaders[] = { pPass->m_GShader, pPass->m_HShader, pPass->m_CShader, pPass->m_DShader };
1831 for (int i = 0; i < 4; i++)
1833 CHWShader* shader = d3d11Shaders[i];
1834 if (shader && (!m_szShaderPrecache || !stricmp(m_szShaderPrecache, shader->m_EntryFunc.c_str()) != 0))
1836 shader->PrecacheShader(pSH,cmba->Ident,nFlags);
1841 if (bStatsOnly)
1843 static int nLastCombs = 0;
1844 if (m_nCombinationsCompiled != nLastCombs && !(m_nCombinationsCompiled & 0x7f))
1846 nLastCombs = m_nCombinationsCompiled;
1847 CryLog("-- Processed: %d, Compiled: %d, Referenced (Empty): %d...", m_nCombinationsProcess, m_nCombinationsCompiled, m_nCombinationsEmpty);
1850 #if CRY_PLATFORM_WINDOWS
1851 gEnv->pSystem->PumpWindowMessage(true);
1852 #endif
1855 pSH->mfFlushPendedShaders();
1856 iLog->Update();
1859 pSH->mfFlushCache();
1861 // HACK HACK HACK:
1862 // should be bigger than 0, but could cause issues right now when checking for RT
1863 // combinations when no shadertype is defined and the previous shader line
1864 // was still async compiling -- needs fix in HWShader for m_nMaskGenFX
1865 CHWShader::mfFlushPendedShadersWait(0);
1866 SAFE_RELEASE(pSH);
1868 nProcessed += m_nCombinationsProcess;
1869 nCompiled += m_nCombinationsCompiled;
1870 nEmpty += m_nCombinationsEmpty;
1872 m_nCombinationsProcess = 0;
1873 m_nCombinationsCompiled = 0;
1874 m_nCombinationsEmpty = 0;
1877 CHWShader::mfFlushPendedShadersWait(-1);
1879 // Optimise shader resources
1880 SOptimiseStats Stats;
1881 for (FXShaderCacheNamesItor it = CHWShader::m_ShaderCacheList.begin(); it != CHWShader::m_ShaderCacheList.end(); it++)
1883 const char* szName = it->first.c_str();
1884 SShaderCache* c = CHWShader::mfInitCache(szName, NULL, false, it->second, false);
1885 if (c)
1887 SOptimiseStats _Stats;
1888 CHWShader::mfOptimiseCacheFile(c, false, &_Stats);
1889 Stats.nEntries += _Stats.nEntries;
1890 Stats.nUniqueEntries += _Stats.nUniqueEntries;
1891 Stats.nSizeCompressed += _Stats.nSizeCompressed;
1892 Stats.nSizeUncompressed += _Stats.nSizeUncompressed;
1893 Stats.nTokenDataSize += _Stats.nTokenDataSize;
1895 c->Release();
1898 string sShaderPath(gRenDev->m_cEF.m_szUserPath);
1899 sShaderPath += gRenDev->m_cEF.m_ShadersCache;
1901 //CResFileLookupDataMan kLookupDataMan;
1902 //kDirDataMan.LoadData(sShaderPath + "direntrydata.bin", CParserBin::m_bEndians);
1903 //GenerateResFileDirData(sShaderPath, &kLookupDataMan);
1904 //kLookupDataMan.SaveData(sShaderPath + "lookupdata.bin", CParserBin::m_bEndians);
1906 /*FILE *FP = gEnv->pCryPak->FOpen("Shaders/Cache/ShaderListDone", "w");
1907 if (FP)
1909 gEnv->pCryPak->FPrintf(FP, "done: %d", m_nCombinationsProcess);
1910 gEnv->pCryPak->FClose(FP);
1912 CHWShader::m_ShaderCacheList.clear();
1914 m_eCacheMode = eSC_Normal;
1915 m_bReload = false;
1916 m_szShaderPrecache = NULL;
1917 CRenderer::CV_r_shadersasynccompiling = nAsync;
1919 gRenDev->m_Features = nSaveFeatures;
1921 float t1 = gEnv->pTimer->GetAsyncCurTime();
1922 CryLogAlways("All shaders combinations compiled in %.2f seconds", (t1 - t0));
1923 CryLogAlways("Combinations: (Material: %d, Processed: %d; Compiled: %d; Removed: %d)", nMaterialCombinations, nProcessed, nCompiled, nEmpty);
1924 CryLogAlways("-- Shader cache overall stats: Entries: %d, Unique Entries: %d, Size: %d, Compressed Size: %d, Token data size: %d", Stats.nEntries, Stats.nUniqueEntries, Stats.nSizeUncompressed, Stats.nSizeCompressed, Stats.nTokenDataSize);
1926 m_nCombinationsProcess = -1;
1927 m_nCombinationsCompiled = -1;
1928 m_nCombinationsEmpty = -1;
1931 #endif
1933 void CHWShader::mfGenName(uint64 GLMask, uint64 RTMask, uint32 LightMask, uint32 MDMask, uint32 MDVMask, uint64 PSS, EHWShaderClass eClass, char* dstname, int nSize, byte bType)
1935 assert(dstname);
1936 dstname[0] = 0;
1938 char str[32];
1939 if (bType != 0 && GLMask)
1941 #if defined(__GNUC__)
1942 cry_sprintf(str, "(GL%llx)", GLMask);
1943 #else
1944 cry_sprintf(str, "(GL%I64x)", GLMask);
1945 #endif
1946 cry_strcat(dstname, nSize, str);
1948 if (bType != 0)
1950 #if defined(__GNUC__)
1951 cry_sprintf(str, "(RT%llx)", RTMask);
1952 #else
1953 cry_sprintf(str, "(RT%I64x)", RTMask);
1954 #endif
1955 cry_strcat(dstname, nSize, str);
1957 if (bType != 0 && LightMask)
1959 cry_sprintf(str, "(LT%x)", LightMask);
1960 cry_strcat(dstname, nSize, str);
1962 if (bType != 0 && MDMask)
1964 cry_sprintf(str, "(MD%x)", MDMask);
1965 cry_strcat(dstname, nSize, str);
1967 if (bType != 0 && MDVMask)
1969 cry_sprintf(str, "(MDV%x)", MDVMask);
1970 cry_strcat(dstname, nSize, str);
1972 if (bType != 0 && PSS)
1974 sprintf(str, "(PSS%llx)", PSS);
1975 cry_strcat(dstname, nSize, str);
1977 if (bType != 0)
1979 cry_sprintf(str, "(%s)", mfClassString(eClass));
1980 cry_strcat(dstname, nSize, str);
1984 #if CRY_PLATFORM_DESKTOP
1986 void CShaderMan::mfPrecacheShaders(bool bStatsOnly)
1988 CHWShader::mfFlushPendedShadersWait(-1);
1990 if (CRenderer::ShaderTargetFlag & SF_ORBIS)
1992 #ifdef WATER_TESSELLATION_RENDERER
1993 CRenderer::CV_r_WaterTessellationHW = 0;
1994 #endif
1997 gRenDev->m_bDeviceSupportsTessellation = CRenderer::ShaderTargetFlag & (SF_D3D11 | SF_GL4 | SF_VULKAN);
1998 gRenDev->m_bDeviceSupportsGeometryShaders = CRenderer::ShaderTargetFlag & (SF_D3D11 | SF_GL4 | SF_VULKAN | SF_DURANGO | SF_ORBIS);
2000 CParserBin::m_bShaderCacheGen = true;
2001 gRenDev->m_Features |= RFT_HW_SM50;
2002 CParserBin::SetupForPlatform(CRenderer::ShaderTargetFlag);
2003 CryLogAlways("\nStarting shader compilation for %s...", CRenderer::CV_r_ShaderTarget->GetString());
2004 mfInitShadersList(NULL);
2005 mfPreloadShaderExts();
2006 _PrecacheShaderList(bStatsOnly);
2008 if (CRenderer::ShaderTargetFlag & SF_ORBIS)
2009 CRenderer::ShaderTargetFlag &= ~SF_ORBIS;
2011 CParserBin::SetupForPlatform(SF_D3D11);
2013 gRenDev->m_cEF.m_Bin.InvalidateCache();
2016 static SResFileLookupData* sStoreLookupData(CResFileLookupDataMan& LevelLookup, CResFile* pRF, uint32 CRC, float fVersion)
2018 CCryNameTSCRC name = pRF->mfGetFileName();
2019 SResFileLookupData* pData = LevelLookup.GetData(name);
2020 uint32 nMinor = (int)(((float)fVersion - (float)(int)fVersion) * 10.1f);
2021 uint32 nMajor = (int)fVersion;
2022 if (!pData || (CRC && pData->m_CRC32 != CRC) || pData->m_CacheMinorVer != nMinor || pData->m_CacheMajorVer != nMajor)
2024 LevelLookup.AddData(pRF, CRC);
2025 pData = LevelLookup.GetData(name);
2026 LevelLookup.MarkDirty(true);
2028 assert(pData);
2029 return pData;
2032 void CShaderMan::mfExportShaders()
2036 void CShaderMan::mfOptimiseShaders(const char* szFolder, bool bForce)
2038 CHWShader::mfFlushPendedShadersWait(-1);
2040 float t0 = gEnv->pTimer->GetAsyncCurTime();
2041 SShaderCache* pCache;
2042 uint32 i;
2044 std::vector<CCryNameR> Names;
2045 mfGatherFilesList(szFolder, Names, 0, false);
2047 SOptimiseStats Stats;
2048 for (i = 0; i < Names.size(); i++)
2050 const char* szName = Names[i].c_str();
2051 if (!strncmp(szName, "%USER%/", 7))
2052 szName += 7;
2053 pCache = CHWShader::mfInitCache(szName, NULL, false, 0, false);
2054 if (!pCache || !pCache->m_pRes[CACHE_USER])
2055 continue;
2056 SOptimiseStats _Stats;
2057 CHWShader::mfOptimiseCacheFile(pCache, bForce, &_Stats);
2058 Stats.nEntries += _Stats.nEntries;
2059 Stats.nUniqueEntries += _Stats.nUniqueEntries;
2060 Stats.nSizeCompressed += _Stats.nSizeCompressed;
2061 Stats.nSizeUncompressed += _Stats.nSizeUncompressed;
2062 Stats.nTokenDataSize += _Stats.nTokenDataSize;
2063 Stats.nDirDataSize += _Stats.nDirDataSize;
2064 pCache->Release();
2067 float t1 = gEnv->pTimer->GetAsyncCurTime();
2068 CryLog("-- All shaders combinations optimized in %.2f seconds", t1 - t0);
2069 CryLog("-- Shader cache overall stats: Entries: %d, Unique Entries: %d, Size: %.3f, Compressed Size: %.3f, Token data size: %.3f, Directory Size: %.3f Mb", Stats.nEntries, Stats.nUniqueEntries, Stats.nSizeUncompressed / 1024.0f / 1024.0f, Stats.nSizeCompressed / 1024.0f / 1024.0f, Stats.nTokenDataSize / 1024.0f / 1024.0f, Stats.nDirDataSize / 1024.0f / 1024.0f);
2072 struct SMgData
2074 CCryNameTSCRC Name;
2075 int nSize;
2076 uint32 CRC;
2077 uint32 flags;
2078 byte* pData;
2079 int nID;
2080 byte bProcessed;
2083 static int snCurListID;
2084 typedef std::map<CCryNameTSCRC, SMgData> ShaderData;
2085 typedef ShaderData::iterator ShaderDataItor;
2087 struct SNameData
2089 CCryNameR Name;
2090 bool bProcessed;
2093 //////////////////////////////////////////////////////////////////////////
2094 bool CShaderMan::CheckAllFilesAreWritable(const char* szDir) const
2096 #if CRY_PLATFORM_WINDOWS
2097 assert(szDir);
2099 ICryPak* pack = gEnv->pCryPak;
2100 assert(pack);
2102 string sPathWithFilter = string(szDir) + "/*.*";
2104 // Search files that match filter specification.
2105 _finddata_t fd;
2106 int res;
2107 intptr_t handle;
2108 if ((handle = pack->FindFirst(sPathWithFilter.c_str(), &fd)) != -1)
2112 if ((fd.attrib & _A_SUBDIR) == 0)
2114 string fullpath = string(szDir) + "/" + fd.name;
2116 FILE* out = pack->FOpen(fullpath.c_str(), "rb");
2117 if (!out)
2119 res = pack->FindNext(handle, &fd);
2120 continue;
2122 if (pack->IsInPak(out))
2124 pack->FClose(out);
2125 res = pack->FindNext(handle, &fd);
2126 continue;
2128 pack->FClose(out);
2130 out = pack->FOpen(fullpath.c_str(), "ab");
2132 if (out)
2133 pack->FClose(out);
2134 else
2136 gEnv->pLog->LogError("ERROR: Shader cache is not writable (file: '%s')", fullpath.c_str());
2137 return false;
2141 res = pack->FindNext(handle, &fd);
2143 while (res >= 0);
2145 pack->FindClose(handle);
2147 gEnv->pLog->LogToFile("Shader cache directory '%s' was successfully tested for being writable", szDir);
2149 else
2150 CryLog("Shader cache directory '%s' does not exist", szDir);
2152 #endif
2154 return true;
2157 #endif // CRY_PLATFORM_DESKTOP
2159 bool CShaderMan::mfPreloadBinaryShaders()
2161 LOADING_TIME_PROFILE_SECTION;
2162 // don't preload binary shaders if we are in editing mode
2163 if (CRenderer::CV_r_shadersediting)
2164 return false;
2166 // don't load all binary shaders twice
2167 if (m_Bin.m_bBinaryShadersLoaded)
2168 return true;
2170 //bool bFound = iSystem->GetIPak()->LoadPakToMemory("Engine/ShadersBin.pak", ICryPak::eInMemoryPakLocale_CPU);
2171 //if (!bFound)
2172 // return false;
2174 #ifndef _RELEASE
2175 // also load shaders pak file to memory because shaders are also read, when data not found in bin, and to check the CRC
2176 // of the source shaders against the binary shaders in non release mode
2177 iSystem->GetIPak()->LoadPakToMemory("%ENGINE%/Shaders.pak", ICryPak::eInMemoryPakLocale_CPU);
2178 #endif
2180 stack_string szPath = stack_string("%ENGINE%/") + m_ShadersCache;
2182 struct _finddata_t fileinfo;
2183 intptr_t handle;
2185 handle = gEnv->pCryPak->FindFirst(szPath + "/*.*", &fileinfo);
2186 if (handle == -1)
2187 return false;
2188 std::vector<string> FilesCFX;
2189 std::vector<string> FilesCFI;
2193 if (gEnv->pSystem && gEnv->pSystem->IsQuitting())
2194 return false;
2195 if (fileinfo.name[0] == '.')
2196 continue;
2197 if (fileinfo.attrib & _A_SUBDIR)
2198 continue;
2199 const char* szExt = PathUtil::GetExt(fileinfo.name);
2200 if (!stricmp(szExt, "cfib"))
2201 FilesCFI.push_back(fileinfo.name);
2202 else if (!stricmp(szExt, "cfxb"))
2203 FilesCFX.push_back(fileinfo.name);
2205 while (gEnv->pCryPak->FindNext(handle, &fileinfo) != -1);
2207 if (FilesCFX.size() + FilesCFI.size() > MAX_FXBIN_CACHE)
2208 SShaderBin::s_nMaxFXBinCache = FilesCFX.size() + FilesCFI.size();
2209 uint32 i;
2210 char sName[256];
2213 LOADING_TIME_PROFILE_SECTION_NAMED("CShaderMan::mfPreloadBinaryShaders(): FilesCFI");
2214 for (i = 0; i < FilesCFI.size(); i++)
2216 if (gEnv->pSystem && gEnv->pSystem->IsQuitting())
2217 return false;
2219 const string& file = FilesCFI[i];
2220 cry_strcpy(sName, file.c_str());
2221 PathUtil::RemoveExtension(sName);
2222 SShaderBin* pBin = m_Bin.GetBinShader(sName, true, 0);
2223 assert(pBin);
2228 LOADING_TIME_PROFILE_SECTION_NAMED("CShaderMan::mfPreloadBinaryShaders(): FilesCFX");
2229 for (i = 0; i < FilesCFX.size(); i++)
2231 if (gEnv->pSystem && gEnv->pSystem->IsQuitting())
2232 return false;
2234 const string& file = FilesCFX[i];
2235 cry_strcpy(sName, file.c_str());
2236 PathUtil::RemoveExtension(sName);
2237 SShaderBin* pBin = m_Bin.GetBinShader(sName, false, 0);
2238 assert(pBin);
2242 gEnv->pCryPak->FindClose(handle);
2244 // Unload pak from memory.
2245 //iSystem->GetIPak()->LoadPakToMemory("Engine/ShadersBin.pak", ICryPak::eInMemoryPakLocale_Unload);
2247 #ifndef _RELEASE
2248 iSystem->GetIPak()->LoadPakToMemory("%ENGINE%/Shaders.pak", ICryPak::eInMemoryPakLocale_Unload);
2249 #endif
2251 m_Bin.m_bBinaryShadersLoaded = true;
2253 return SShaderBin::s_nMaxFXBinCache > 0;