Merge remote-tracking branch 'public/release_candidate' into release
[CRYENGINE.git] / Code / CryEngine / RenderDll / XRenderD3D9 / D3DHWShaderCompiling.cpp
blobb1b8ee43ba71654f69289b27b8254cd5be3c671d
1 // Copyright 2001-2019 Crytek GmbH / Crytek Group. All rights reserved.
3 #include "StdAfx.h"
5 #include <lzss/LZSS.H>
6 #include <lzma/Lzma86.h>
7 #include <cstring>
9 #if !CRY_RENDERER_VULKAN && !CRY_RENDERER_GNM
10 #if CRY_RENDERER_DIRECT3D >= 120
11 #if CRY_PLATFORM_DURANGO
12 #include <D3D12Shader_x.h>
13 #include <D3DCompiler_x.h>
14 #else
15 #include <D3D12Shader.h>
16 #include <D3DCompiler.h>
17 #endif
18 #else
19 #if CRY_PLATFORM_DURANGO
20 #include <D3D11Shader_x.h>
21 #include <D3DCompiler_x.h>
22 #else
23 #include <D3D11Shader.h>
24 #include <D3DCompiler.h>
25 #endif
26 #endif
27 #endif
29 #if defined(USE_NV_API)
30 #include NV_API_HEADER
31 #endif
33 #include "../Common/Shaders/RemoteCompiler.h"
35 static CryCriticalSection g_cAILock;
36 static SShaderAsyncInfo g_PendingList;
37 static SShaderAsyncInfo g_PendingListT;
38 #ifdef SHADER_ASYNC_COMPILATION
39 static SShaderAsyncInfo g_BuildList;
40 #endif
42 SShaderAsyncInfo& SShaderAsyncInfo::PendingList() { return g_PendingList; }
43 SShaderAsyncInfo& SShaderAsyncInfo::PendingListT() { return g_PendingListT; }
44 #ifdef SHADER_ASYNC_COMPILATION
45 SShaderAsyncInfo& CAsyncShaderTask::BuildList() { return g_BuildList; }
46 #endif
48 CryEvent SShaderAsyncInfo::s_RequestEv;
50 int CHWShader_D3D::s_nDevicePSDataSize = 0;
51 int CHWShader_D3D::s_nDeviceVSDataSize = 0;
53 namespace
55 inline int GetCurrentFrameID()
57 return (gRenDev->m_pRT->IsRenderThread()) ? gRenDev->GetRenderFrameID() : gRenDev->GetMainFrameID();
61 class CSpinLock
63 public:
64 CSpinLock()
66 #if CRY_PLATFORM_WINDOWS || CRY_PLATFORM_LINUX || CRY_PLATFORM_ANDROID || CRY_PLATFORM_APPLE
67 while (CryInterlockedCompareExchange(&s_locked, 1L, 0L) == 1L)
68 CrySleep(0);
69 #endif
72 ~CSpinLock()
74 #if CRY_PLATFORM_WINDOWS
75 InterlockedExchange(&s_locked, 0L);
76 #elif CRY_PLATFORM_LINUX || CRY_PLATFORM_ANDROID || CRY_PLATFORM_APPLE
77 while (CryInterlockedCompareExchange(&s_locked, 0L, 1L) == 0L);
78 #endif
81 private:
82 static volatile LONG s_locked;
85 volatile LONG CSpinLock::s_locked = 0L;
87 volatile int SShaderAsyncInfo::s_nPendingAsyncShaders = 0;
88 int SShaderAsyncInfo::s_nPendingAsyncShadersFXC = 0;
90 //==============================================================================================================
92 bool CHWShader_D3D::mfAddFXSampler(SHWSInstance* pInst, SShaderFXParams& FXParams, SFXSampler* pr, const char* ParamName, SCGBind* pBind, CShader* ef, EHWShaderClass eSHClass)
94 assert(pBind);
95 if (!pBind)
96 return false;
98 std::vector<SCGSampler>* pParams;
99 pParams = &pInst->m_Samplers;
100 uint32 nOffs = pParams->size();
101 bool bRes = gRenDev->m_cEF.mfParseFXSampler(FXParams, pr, ParamName, ef, pBind->m_nParameters, pParams, eSHClass);
102 if (pParams->size() > nOffs)
104 for (uint32 i = 0; i < pParams->size() - nOffs; i++)
106 SCGSampler& p = (*pParams)[nOffs + i];
107 p.m_dwBind = pBind->m_dwBind + i;
108 p.m_dwCBufSlot = pBind->m_dwCBufSlot;
109 p.m_Name = pBind->m_Name;
112 // Parameter without semantic
113 return bRes;
116 bool CHWShader_D3D::mfAddFXTexture(SHWSInstance* pInst, SShaderFXParams& FXParams, SFXTexture* pr, const char* ParamName, SCGBind* pBind, CShader* ef, EHWShaderClass eSHClass)
118 assert(pBind);
119 if (!pBind)
120 return false;
122 std::vector<SCGTexture>* pParams;
123 pParams = &pInst->m_Textures;
124 uint32 nOffs = pParams->size();
125 bool bRes = gRenDev->m_cEF.mfParseFXTexture(FXParams, pr, ParamName, ef, pBind->m_nParameters, pParams, eSHClass);
127 if (pParams->size() > nOffs)
129 for (uint32 i = 0; i < pParams->size() - nOffs; i++)
131 SCGTexture& p = (*pParams)[nOffs + i];
132 p.m_dwBind = pBind->m_dwBind + i;
133 p.m_dwCBufSlot = pBind->m_dwCBufSlot;
134 p.m_Name = pBind->m_Name;
137 // Parameter without semantic
138 return bRes;
141 void CHWShader_D3D::mfAddFXParameter(SHWSInstance* pInst, SParamsGroup& OutParams, SShaderFXParams& FXParams, SFXParam* pr, const char* ParamName, SCGBind* pBind, CShader* ef, bool bInstParam, EHWShaderClass eSHClass)
143 SCGParam CGpr;
145 assert(pBind);
146 if (!pBind)
147 return;
149 int nComps = 0;
150 int nParams = pBind->m_nParameters;
151 if (!pr->m_Semantic.empty())
152 nComps = pr->m_nComps;
153 else
155 for (int i = 0; i < pr->m_nComps; i++)
157 CryFixedStringT<128> cur;
158 pr->GetParamComp(i, cur);
159 if (cur.empty())
160 break;
161 nComps++;
164 // Process parameters only with semantics
165 if (nComps && nParams)
167 std::vector<SCGParam>* pParams;
168 if (pr->m_nParameters > 1)
170 if (!bInstParam)
172 //if (!pInst->m_pParams[0])
173 // pInst->m_pParams[0] = new std::vector<SCGParam>;
174 pParams = &OutParams.Params[0];
176 else
178 //if (!pInst->m_pParams_Inst)
179 // pInst->m_pParams_Inst = new std::vector<SCGParam>;
180 pParams = &OutParams.Params_Inst;
183 else if (bInstParam)
185 //if (!pInst->m_pParams_Inst)
186 // pInst->m_pParams_Inst = new std::vector<SCGParam>;
187 pParams = &OutParams.Params_Inst;
189 else
191 //if (!pInst->m_pParams[0])
192 // pInst->m_pParams[0] = new std::vector<SCGParam>;
193 pParams = &OutParams.Params[0];
195 uint32 nOffs = pParams->size();
196 CRY_VERIFY(gRenDev->m_cEF.mfParseFXParameter(FXParams, pr, ParamName, ef, bInstParam, pBind->m_nParameters, pParams, eSHClass, false));
197 if (pParams->size() > nOffs)
199 for (uint32 i = 0; i < pParams->size() - nOffs; i++)
201 //assert(pBind->m_nComponents == 1);
202 SCGParam& p = (*pParams)[nOffs + i];
203 p.m_dwBind = pBind->m_dwBind + i;
204 p.m_dwCBufSlot = pBind->m_dwCBufSlot;
208 // Parameter without semantic
211 struct SAliasSampler
213 STexSamplerRT Sampler;
214 string NameTex;
217 bool CHWShader_D3D::mfAddFXParameter(SHWSInstance* pInst, SParamsGroup& OutParams, SShaderFXParams& FXParams, const char* param, SCGBind* bn, bool bInstParam, EHWShaderClass eSHClass, CShader* pFXShader)
219 if (bn->m_dwBind & SHADER_BIND_TEXTURE)
221 SFXTexture* pr = gRenDev->m_cEF.mfGetFXTexture(FXParams.m_FXTextures, param);
222 if (pr)
224 if (bn->m_nParameters < 0)
225 bn->m_nParameters = pr->m_nArray;
226 mfAddFXTexture(pInst, FXParams, pr, param, bn, pFXShader, eSHClass);
227 return true;
230 else if (bn->m_dwBind & SHADER_BIND_SAMPLER)
232 SFXSampler* pr = gRenDev->m_cEF.mfGetFXSampler(FXParams.m_FXSamplers, param);
233 if (pr)
235 if (bn->m_nParameters < 0)
236 bn->m_nParameters = pr->m_nArray;
237 mfAddFXSampler(pInst, FXParams, pr, param, bn, pFXShader, eSHClass);
238 return true;
241 else
243 SFXParam* pr = gRenDev->m_cEF.mfGetFXParameter(FXParams.m_FXParams, param);
244 if (pr)
246 if (bn->m_nParameters < 0)
247 bn->m_nParameters = pr->m_nParameters;
248 mfAddFXParameter(pInst, OutParams, FXParams, pr, param, bn, pFXShader, bInstParam, eSHClass);
249 return true;
252 return false;
255 //==================================================================================================================
257 int CGBindCallback(const VOID* arg1, const VOID* arg2)
259 SCGBind* pi1 = (SCGBind*)arg1;
260 SCGBind* pi2 = (SCGBind*)arg2;
262 if (pi1->m_dwBind < pi2->m_dwBind)
263 return -1;
264 if (pi1->m_dwBind > pi2->m_dwBind)
265 return 1;
267 return 0;
270 const char* szNamesCB[CB_NUM] = { "PER_BATCH", "PER_MATERIAL" };
272 void CHWShader_D3D::mfCreateBinds(std::vector<SCGBind>& binds, const void* pConstantTable, std::size_t nSize)
274 uint32 i;
275 D3DShaderReflection* pShaderReflection = (D3DShaderReflection*)pConstantTable;
276 D3D_SHADER_DESC Desc;
277 pShaderReflection->GetDesc(&Desc);
278 D3DShaderReflectionConstantBuffer* pCB = NULL;
279 for (uint32 n = 0; n < Desc.ConstantBuffers; n++)
281 pCB = pShaderReflection->GetConstantBufferByIndex(n);
282 D3D_SHADER_BUFFER_DESC SBDesc;
283 pCB->GetDesc(&SBDesc);
284 if (SBDesc.Type == D3D11_CT_RESOURCE_BIND_INFO)
285 continue;
286 int nCB;
287 if (!strcmp("$Globals", SBDesc.Name))
288 nCB = CB_PER_DRAW;
289 else
290 for (nCB = 0; nCB < CB_NUM; nCB++)
292 if (!strcmp(szNamesCB[nCB], SBDesc.Name))
293 break;
295 //assert(nCB != CB_NUM);
296 if (nCB >= CB_NUM) // Allow having custom cbuffers in shaders
297 continue;
298 for (i = 0; i < SBDesc.Variables; i++)
300 D3DShaderReflectionVariable* pCV = pCB->GetVariableByIndex(i);
301 D3DShaderReflectionType* pVT = pCV->GetType();
302 D3D_SHADER_VARIABLE_DESC CDesc;
303 D3D_SHADER_TYPE_DESC CTDesc;
304 pVT->GetDesc(&CTDesc);
305 pCV->GetDesc(&CDesc);
306 if (!(CDesc.uFlags & D3D10_SVF_USED))
307 continue;
308 if (CTDesc.Class == D3D10_SVC_VECTOR || CTDesc.Class == D3D10_SVC_SCALAR || CTDesc.Class == D3D10_SVC_MATRIX_COLUMNS || CTDesc.Class == D3D10_SVC_MATRIX_ROWS)
310 SCGBind cgp;
311 assert(!(CDesc.StartOffset & 0xf));
312 //assert(!(CDesc.Size & 0xf));
313 int nReg = CDesc.StartOffset >> 4;
314 cgp.m_dwBind = nReg; //<<2;
315 cgp.m_dwCBufSlot = nCB;
316 cgp.m_nParameters = (CDesc.Size + 15) >> 4;
317 cgp.m_Name = CDesc.Name;
318 cgp.m_Flags = CParserBin::GetCRC32(CDesc.Name);
319 binds.push_back(cgp);
321 else
323 assert(false);
328 D3D_SHADER_INPUT_BIND_DESC IBDesc;
329 for (i = 0; i < Desc.BoundResources; i++)
331 ZeroStruct(IBDesc);
332 pShaderReflection->GetResourceBindingDesc(i, &IBDesc);
333 SCGBind cgp;
334 if (IBDesc.Type == D3D10_SIT_TEXTURE)
335 cgp.m_dwBind = IBDesc.BindPoint | SHADER_BIND_TEXTURE;
336 else if (IBDesc.Type == D3D10_SIT_SAMPLER)
337 cgp.m_dwBind = IBDesc.BindPoint | SHADER_BIND_SAMPLER;
338 else
339 continue;
341 if (IBDesc.Dimension == D3D10_SRV_DIMENSION_BUFFER)
342 continue;
344 cgp.m_dwCBufSlot = IBDesc.BindPoint;
345 cgp.m_nParameters = IBDesc.BindCount;
346 cgp.m_Name = IBDesc.Name;
347 cgp.m_Flags = CParserBin::GetCRC32(IBDesc.Name);
348 binds.push_back(cgp);
352 void CHWShader_D3D::mfGatherFXParameters(SHWSInstance* pInst, std::vector<SCGBind>& BindVars, CHWShader_D3D* pSH, int nFlags, CShader* pFXShader)
354 // CRY_PROFILE_FUNCTION(PROFILE_LOADING_ONLY)(iSystem);
356 uint32 i, j;
357 SAliasSampler samps[MAX_TMU];
358 SParamsGroup Group;
359 SShaderFXParams& FXParams = gRenDev->m_cEF.m_Bin.mfGetFXParams(pInst->m_bFallback ? CShaderMan::s_ShaderFallback : pFXShader);
360 if (pInst->m_pBindVars.size())
362 for (i = 0; i < pInst->m_pBindVars.size(); i++)
364 SCGBind* bn = &BindVars[i];
365 const char* param = bn->m_Name.c_str();
367 if (!strncmp(param, "_g_", 3))
368 continue;
369 mfAddFXParameter(pInst, Group, FXParams, param, bn, false, pSH->m_eSHClass, pFXShader);
372 bool setSamplers[256] = { false };
373 bool setTextures[256] = { false };
375 for (i = 0; i < pInst->m_Samplers.size(); i++)
376 setSamplers[pInst->m_Samplers[i].m_dwBind & 0xff] = true;
377 for (i = 0; i < pInst->m_Textures.size(); i++)
378 setTextures[pInst->m_Textures[i].m_dwBind & 0xff] = true;
380 if (nFlags != 1)
382 pInst->m_pFXTextures.reserve(FXParams.m_FXTextures.size());
383 for (const auto& t : FXParams.m_FXTextures)
384 pInst->m_pFXTextures.push_back(&t);
386 else
388 assert(pInst->m_pAsync);
391 pInst->m_nMaxVecs[0] = pInst->m_nMaxVecs[1] = 0;
392 if (pInst->m_pBindVars.size())
394 for (i = 0; i < pInst->m_pBindVars.size(); i++)
396 SCGBind* pB = &pInst->m_pBindVars[i];
397 if (pB->m_dwBind & (SHADER_BIND_SAMPLER | SHADER_BIND_TEXTURE))
398 continue;
399 if (pB->m_dwCBufSlot < 0 || pB->m_dwCBufSlot > CB_NUM)
400 continue;
401 for (j = 0; j < Group.Params[0].size(); j++)
403 SCGParam* pr = &Group.Params[0][j];
404 if (pr->m_dwBind == pB->m_dwBind && pr->m_Name == pB->m_Name)
405 break;
407 if (j != Group.Params[0].size())
408 continue;
409 pInst->m_nMaxVecs[pB->m_dwCBufSlot] = max(pB->m_dwBind + pB->m_nParameters, pInst->m_nMaxVecs[pB->m_dwCBufSlot]);
412 if (Group.Params[0].size())
414 for (i = 0; i < Group.Params[0].size(); i++)
416 SCGParam* pr = &Group.Params[0][i];
418 if (pr->m_Flags & PF_MATERIAL)
419 pInst->m_bHasPMParams = true;
422 gRenDev->m_cEF.mfCheckObjectDependParams(Group.Params[0], Group.Params[1], pSH->m_eSHClass, pFXShader);
425 for (i = 0; i < CB_NUM; i++)
427 if (Group.Params[i].size())
429 for (j = 0; j < Group.Params[i].size(); j++)
431 SCGParam* pr = &Group.Params[i][j];
432 pInst->m_nMaxVecs[i] = max(pr->m_dwBind + pr->m_nParameters, pInst->m_nMaxVecs[i]);
436 int nMax = 0;
437 if (pSH->m_eSHClass == eHWSC_Vertex)
438 nMax = MAX_CONSTANTS_VS;
439 else if (pSH->m_eSHClass == eHWSC_Pixel)
440 nMax = MAX_CONSTANTS_PS;
441 else if (pSH->m_eSHClass == eHWSC_Geometry)
442 nMax = MAX_CONSTANTS_GS;
443 else if (pSH->m_eSHClass == eHWSC_Domain)
444 nMax = MAX_CONSTANTS_DS;
445 else if (pSH->m_eSHClass == eHWSC_Hull)
446 nMax = MAX_CONSTANTS_HS;
447 else if (pSH->m_eSHClass == eHWSC_Compute)
448 nMax = MAX_CONSTANTS_CS;
449 assert(pInst->m_nMaxVecs[0] < nMax);
450 assert(pInst->m_nMaxVecs[1] < nMax);
452 if (Group.Params[0].size() > 0)
454 qsort(&Group.Params[0][0], Group.Params[0].size(), sizeof(SCGParam), CGBindCallback);
455 pInst->m_nParams[0] = CGParamManager::GetParametersGroup(Group, 0);
457 if (Group.Params[1].size() > 0)
459 qsort(&Group.Params[1][0], Group.Params[1].size(), sizeof(SCGParam), CGBindCallback);
460 pInst->m_nParams[1] = CGParamManager::GetParametersGroup(Group, 1);
464 // Vertex shader specific
465 void CHWShader_D3D::mfUpdateFXVertexFormat(SHWSInstance* pInst, CShader* pSH)
467 // Update global FX shader's vertex format / flags
468 if (pSH)
470 InputLayoutHandle eVFormat = pSH->m_eVertexFormat;
471 bool bCurrent = false;
472 for (uint32 i = 0; i < pSH->m_HWTechniques.Num(); i++)
474 SShaderTechnique* hw = pSH->m_HWTechniques[i];
475 for (uint32 j = 0; j < hw->m_Passes.Num(); j++)
477 SShaderPass* pass = &hw->m_Passes[j];
478 if (pass->m_VShader)
480 if (pass->m_VShader == this)
481 bCurrent = true;
482 bool bUseLM = false;
483 bool bUseTangs = false;
484 bool bUseHWSkin = false;
485 InputLayoutHandle eCurVFormat = pass->m_VShader->mfVertexFormat(bUseTangs, bUseLM, bUseHWSkin);
486 if (eCurVFormat >= EDefaultInputLayouts::Empty)
487 eVFormat = max(eVFormat, eCurVFormat);
488 if (bUseTangs)
489 pass->m_PassFlags |= VSM_TANGENTS;
490 if (bUseHWSkin)
492 pass->m_PassFlags |= VSM_HWSKIN;
493 pass->m_PassFlags |= VSM_VERTEX_VELOCITY;
498 //assert (bCurrent);
499 pSH->m_eVertexFormat = eVFormat;
503 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)
505 if (bBitangent[0])
506 pInst->m_VStreamMask_Decl |= EStreamMasks(1 << VSF_TANGENTS);
507 else if (bTangent[0])
508 pInst->m_VStreamMask_Decl |= EStreamMasks(1 << VSF_QTANGENTS);
509 if (bBitangent[1])
510 pInst->m_VStreamMask_Stream |= EStreamMasks(1 << VSF_TANGENTS);
511 else if (bTangent[1])
512 pInst->m_VStreamMask_Stream |= EStreamMasks(1 << VSF_QTANGENTS);
514 if (pInst->m_VStreamMask_Decl & EStreamMasks(1 << VSF_TANGENTS))
515 bNormal = false;
517 if (bHWSkin)
519 pInst->m_VStreamMask_Decl |= VSM_HWSKIN;
520 pInst->m_VStreamMask_Stream |= VSM_HWSKIN;
523 if (bVelocity)
525 pInst->m_VStreamMask_Decl |= VSM_VERTEX_VELOCITY;
526 pInst->m_VStreamMask_Stream |= VSM_VERTEX_VELOCITY;
528 if (bMorph)
530 pInst->m_VStreamMask_Decl |= VSM_MORPHBUDDY;
531 pInst->m_VStreamMask_Stream |= VSM_MORPHBUDDY;
534 InputLayoutHandle eVF = VertFormatForComponents(bCol, bTC0, bPSize, bNormal != 0);
535 pInst->m_nVertexFormat = eVF;
538 InputLayoutHandle CHWShader_D3D::mfVertexFormat(bool& bUseTangents, bool& bUseLM, bool& bUseHWSkin)
540 uint32 i;
542 assert(m_eSHClass == eHWSC_Vertex);
544 InputLayoutHandle eVFormat = EDefaultInputLayouts::P3F_C4B_T2F;
545 int nStream = 0;
546 for (i = 0; i < m_Insts.size(); i++)
548 SHWSInstance* pInst = m_Insts[i];
549 eVFormat = (InputLayoutHandle)max((uint32)eVFormat, (uint32)pInst->m_nVertexFormat);
550 nStream |= pInst->m_VStreamMask_Stream;
552 bUseTangents = (nStream & VSM_TANGENTS) != 0;
553 bUseLM = false;
554 bUseHWSkin = (nStream & VSM_HWSKIN) != 0;
555 assert(eVFormat < EDefaultInputLayouts::PreAllocated);
557 return eVFormat;
560 InputLayoutHandle CHWShader_D3D::mfVertexFormat(SHWSInstance* pInst, CHWShader_D3D* pSH, D3DBlob* pShader, void* pConstantTable)
562 /*if (!stricmp(pSH->m_EntryFunc.c_str(), "ParticleVS"))
564 int nnn = 0;
567 assert(pSH->m_eSHClass == eHWSC_Vertex);
569 byte bNormal = false;
570 bool bTangent[2] = { false, false };
571 bool bBitangent[2] = { false, false };
572 bool bHWSkin = false;
573 bool bVelocity = false;
574 bool bMorph = false;
575 bool bPSize = false;
576 bool bSH[2] = { false, false };
577 bool bTC0 = false;
578 bool bTC1[2] = { false, false };
579 bool bCol = false;
580 bool bSecCol = false;
581 bool bPos = false;
583 size_t nSize = pShader->GetBufferSize();
584 void* pData = pShader->GetBufferPointer();
585 void* pShaderReflBuf = pConstantTable;
586 HRESULT hr = pConstantTable ? S_OK : D3DReflection(pData, nSize, IID_D3DShaderReflection, &pShaderReflBuf);
587 assert(SUCCEEDED(hr));
588 D3DShaderReflection* pShaderReflection = (D3DShaderReflection*)pShaderReflBuf;
589 if (!SUCCEEDED(hr))
590 return InputLayoutHandle::Unspecified;
591 D3D_SHADER_DESC Desc;
592 pShaderReflection->GetDesc(&Desc);
593 if (!Desc.InputParameters)
594 return InputLayoutHandle::Unspecified;
595 D3D_SIGNATURE_PARAMETER_DESC IDesc;
596 for (uint32 i = 0; i < Desc.InputParameters; i++)
598 pShaderReflection->GetInputParameterDesc(i, &IDesc);
599 //if (!IDesc.ReadWriteMask)
600 // continue;
601 if (!IDesc.SemanticName)
602 continue;
603 int nIndex;
604 if (!strnicmp(IDesc.SemanticName, "POSITION", 8) || !strnicmp(IDesc.SemanticName, "SV_POSITION", 11))
606 nIndex = IDesc.SemanticIndex;
607 if (nIndex == 0)
608 bPos = true;
609 else if (nIndex == 3)
610 bVelocity = true;
611 else if (nIndex == 4)
612 bHWSkin = true;
613 else if (nIndex == 8)
614 bMorph = true;
615 else
616 assert(false);
618 else if (!strnicmp(IDesc.SemanticName, "NORMAL", 6))
620 bNormal = true;
622 else if (!strnicmp(IDesc.SemanticName, "TEXCOORD", 8))
624 nIndex = IDesc.SemanticIndex;
625 if (nIndex == 0)
626 bTC0 = true;
627 else
629 if (nIndex == 1)
631 bTC1[0] = true;
632 if (IDesc.ReadWriteMask)
633 bTC1[1] = true;
635 else if (nIndex == 8)
636 bMorph = true;
639 else if (!strnicmp(IDesc.SemanticName, "COLOR", 5))
641 nIndex = IDesc.SemanticIndex;
642 if (nIndex == 0)
643 bCol = true;
644 else if (nIndex == 1)
645 bSecCol = true;
646 else
648 if (nIndex == 2 || nIndex == 3)
650 bSH[0] = true;
651 if (IDesc.ReadWriteMask)
652 bSH[1] = true;
654 else
655 assert(false);
658 else if (!stricmp(IDesc.SemanticName, "TANGENT"))
660 bTangent[0] = true;
661 if (IDesc.ReadWriteMask)
662 bTangent[1] = true;
664 else if (!stricmp(IDesc.SemanticName, "BITANGENT"))
666 bBitangent[0] = true;
667 if (IDesc.ReadWriteMask)
668 bBitangent[1] = true;
670 else if (!strnicmp(IDesc.SemanticName, "PSIZE", 5) || !strnicmp(IDesc.SemanticName, "AXIS", 4))
672 bPSize = true;
674 else if (!strnicmp(IDesc.SemanticName, "BLENDWEIGHT", 11) || !strnicmp(IDesc.SemanticName, "BLENDINDICES", 12))
676 nIndex = IDesc.SemanticIndex;
677 if (nIndex == 0)
678 bHWSkin = true;
679 else if (nIndex == 1)
680 bMorph = true;
681 else
682 assert(0);
684 else if (!strnicmp(IDesc.SemanticName, "SV_", 3))
686 // SV_ are valid semantics
688 #if CRY_PLATFORM_ORBIS
689 else if (!strnicmp(IDesc.SemanticName, "S_VERTEX_ID", 11) || !strnicmp(IDesc.SemanticName, "S_INSTANCE_ID", 13))
691 // S_VERTEX_ID and S_INSTANCE_ID are valid names
693 #endif
694 else
696 CRY_ASSERT(0, "Invalid SemanticName %s", IDesc.SemanticName);
699 #if CRY_RENDERER_VULKAN
700 pInst->m_VSInputStreams.emplace_back(IDesc.SemanticName, IDesc.SemanticIndex, IDesc.AttributeLocation);
701 #endif
704 mfPostVertexFormat(pInst, pSH, bCol, bNormal, bTC0, bTC1, bPSize, bTangent, bBitangent, bHWSkin, bSH, bVelocity, bMorph);
706 if (pConstantTable != pShaderReflection)
708 SAFE_RELEASE(pShaderReflection);
711 return (InputLayoutHandle)pInst->m_nVertexFormat;
714 void CHWShader_D3D::mfSetDefaultRT(uint64& nAndMask, uint64& nOrMask)
716 uint32 i, j;
717 SShaderGen* pGen = gRenDev->m_cEF.m_pGlobalExt;
719 uint32 nBitsPlatform = 0;
720 if (CParserBin::m_nPlatform == SF_ORBIS)
721 nBitsPlatform |= SHGD_HW_ORBIS;
722 else if (CParserBin::m_nPlatform == SF_DURANGO)
723 nBitsPlatform |= SHGD_HW_DURANGO;
724 else if (CParserBin::m_nPlatform == SF_D3D11)
725 nBitsPlatform |= SHGD_HW_DX11;
726 else if (CParserBin::m_nPlatform == SF_D3D12)
727 nBitsPlatform |= SHGD_HW_DX12;
728 else if (CParserBin::m_nPlatform == SF_VULKAN)
729 nBitsPlatform |= SHGD_HW_VULKAN;
731 // Make a mask of flags affected by this type of shader
732 uint32 nType = m_dwShaderType;
733 if (nType)
735 for (i = 0; i < pGen->m_BitMask.size(); i++)
737 SShaderGenBit* pBit = pGen->m_BitMask[i];
738 if (!pBit->m_Mask)
739 continue;
740 if (nBitsPlatform & pBit->m_nDependencyReset)
742 nAndMask &= ~pBit->m_Mask;
743 continue;
745 for (j = 0; j < pBit->m_PrecacheNames.size(); j++)
747 if (pBit->m_PrecacheNames[j] == nType)
749 if (nBitsPlatform & pBit->m_nDependencySet)
750 nOrMask |= pBit->m_Mask;
751 break;
758 //==================================================================================================================
760 static bool sGetMask(char* str, SShaderGen* pGen, uint64& nMask)
762 uint32 i;
764 for (i = 0; i < pGen->m_BitMask.Num(); i++)
766 SShaderGenBit* pBit = pGen->m_BitMask[i];
767 if (!strcmp(str, pBit->m_ParamName.c_str()))
769 nMask |= pBit->m_Mask;
770 return true;
773 return false;
776 void CHWShader::mfValidateDirEntries(CResFile* pRF)
778 #ifdef _DEBUG
779 auto dirEntries = pRF->mfGetDirectory();
780 for (auto it1 = dirEntries->begin(); it1 != dirEntries->end(); it1++)
782 for (auto it2 = it1 + 1; it2 != dirEntries->end(); ++it2)
784 if (it1->GetName() == it2->GetName())
786 CryFatalError("Duplicate dir entry in shader cache file");
790 #endif
793 bool CHWShader_D3D::mfStoreCacheTokenMap(const FXShaderToken& Table, const TArray<uint32>& SHData)
795 TArray<byte> Data;
796 uint32 nSize = SHData.size();
797 if (CParserBin::m_bEndians)
799 uint32 nSizeEnd = nSize;
800 SwapEndian(nSizeEnd, eBigEndian);
801 Data.Copy((byte*)&nSizeEnd, sizeof(uint32));
802 for (uint32 i = 0; i < nSize; i++)
804 uint32 nToken = SHData[i];
805 SwapEndian(nToken, eBigEndian);
806 Data.Copy((byte*)&nToken, sizeof(uint32));
809 else
811 Data.Copy((byte*)&nSize, sizeof(uint32));
812 Data.Copy((byte*)&SHData[0], nSize * sizeof(uint32));
814 for (auto T : Table)
816 if (CParserBin::m_bEndians)
817 SwapEndian(T.Token, eBigEndian);
818 Data.Copy((byte*)&T.Token, sizeof(DWORD));
819 Data.Copy((byte*)T.SToken.c_str(), T.SToken.size() + 1);
821 if (!Data.size())
822 return false;
824 m_CachedTokens.resize(Data.size());
825 std::memcpy(&m_CachedTokens[0], Data.Data(), Data.size());
827 return true;
830 bool CHWShader_D3D::mfGetCacheTokenMap(FXShaderToken& Table, TArray<uint32>& SHData)
832 std::size_t nSize = m_CachedTokens.size();
833 const auto* pData = reinterpret_cast<const byte*>(m_CachedTokens.data());
834 if (!pData)
836 Table = {};
837 return false;
840 uint32 nL = *(uint32*)pData;
841 if (CParserBin::m_bEndians)
842 SwapEndian(nL, eBigEndian);
843 SHData.resize(nL);
844 if (CParserBin::m_bEndians)
846 uint32* pTokens = (uint32*)&pData[4];
847 for (uint32_t i = 0; i < nL; i++)
849 uint32 nToken = pTokens[i];
850 SwapEndian(nToken, eBigEndian);
851 SHData[i] = nToken;
854 else
856 memcpy(&SHData[0], &pData[4], nL * sizeof(uint32));
858 pData += 4 + nL * sizeof(uint32);
859 nSize -= 4 + nL * sizeof(uint32);
860 int nOffs = 0;
862 while (nOffs < nSize)
864 char* pStr = (char*)&pData[nOffs + sizeof(DWORD)];
865 DWORD nToken;
866 LoadUnaligned(pData + nOffs, nToken);
867 if (CParserBin::m_bEndians)
868 SwapEndian(nToken, eBigEndian);
869 int nLen = strlen(pStr) + 1;
870 STokenD TD;
871 TD.Token = nToken;
872 TD.SToken = pStr;
873 Table.push_back(TD);
874 nOffs += sizeof(DWORD) + nLen;
877 return true;
880 //==============================================================================================================================================================
882 bool CHWShader_D3D::mfGenerateScript(CShader* pSH, SHWSInstance* pInst, std::vector<SCGBind>& InstBindVars, uint32 nFlags, TArray<char>& sNewScr)
884 uint32 nSFlags = m_Flags;
885 FXShaderToken Table;
886 TArray<uint32> SHData;
888 if (CParserBin::m_bEditable) // Fast path for offline shaders builder
890 Table = m_TokenTable;
891 SHData = m_TokenData;
893 else
895 if (!(nSFlags & HWSG_GS_MULTIRES))
897 if (!mfGetCacheTokenMap(Table, SHData))
898 return false;
900 if (CParserBin::m_bEditable)
902 Table = m_TokenTable;
903 SHData = m_TokenData;
906 if (!(nSFlags & HWSG_GS_MULTIRES))
908 assert(Table.size() && SHData.size());
909 if (!Table.size() || !SHData.size())
910 return false;
913 ShaderTokensVec NewTokens;
915 uint32 eT = eT_unknown;
917 switch (pInst->m_eClass)
919 case eHWSC_Vertex:
920 eT = eT__VS;
921 break;
922 case eHWSC_Pixel:
923 eT = eT__PS;
924 break;
925 case eHWSC_Geometry:
926 eT = eT__GS;
927 break;
928 case eHWSC_Hull:
929 eT = eT__HS;
930 break;
931 case eHWSC_Compute:
932 eT = eT__CS;
933 break;
934 case eHWSC_Domain:
935 eT = eT__DS;
936 break;
938 default:
939 assert(0);
941 if (eT != eT_unknown)
942 CParserBin::AddDefineToken(eT, NewTokens);
944 if (nSFlags & HWSG_GS_MULTIRES)
946 // Generate script vor VS first;
947 //@TODO: Do this without global variable
948 //pInst = s_pCurInstVS;
949 assert(pInst);
951 CHWShader_D3D* curVS = (CHWShader_D3D*)s_pCurHWVS;
952 Table = curVS->m_TokenTable;
953 SHData = curVS->m_TokenData;
954 nSFlags = curVS->m_Flags;
957 // Include runtime mask definitions in the script
958 SShaderGen* shg = gRenDev->m_cEF.m_pGlobalExt;
959 if (shg && pInst->m_Ident.m_RTMask)
961 for (uint32 i = 0; i < shg->m_BitMask.Num(); i++)
963 SShaderGenBit* bit = shg->m_BitMask[i];
964 if (!(bit->m_Mask & pInst->m_Ident.m_RTMask))
965 continue;
966 CParserBin::AddDefineToken(bit->m_dwToken, NewTokens);
970 // Include light mask definitions in the script
971 if (nSFlags & HWSG_SUPPORTS_MULTILIGHTS)
973 int nLights = pInst->m_Ident.m_LightMask & 0xf;
974 if (nLights)
975 CParserBin::AddDefineToken(eT__LT_LIGHTS, NewTokens);
976 CParserBin::AddDefineToken(eT__LT_NUM, nLights + eT_0, NewTokens);
977 bool bHasProj = false;
978 for (int i = 0; i < 4; i++)
980 int nLightType = (pInst->m_Ident.m_LightMask >> (SLMF_LTYPE_SHIFT + i * SLMF_LTYPE_BITS)) & SLMF_TYPE_MASK;
981 if (nLightType == SLMF_PROJECTED)
982 bHasProj = true;
984 CParserBin::AddDefineToken(eT__LT_0_TYPE + i, nLightType + eT_0, NewTokens);
986 if (bHasProj)
987 CParserBin::AddDefineToken(eT__LT_HASPROJ, eT_1, NewTokens);
989 else if (nSFlags & HWSG_SUPPORTS_LIGHTING)
991 CParserBin::AddDefineToken(eT__LT_LIGHTS, NewTokens);
992 int nLightType = (pInst->m_Ident.m_LightMask >> SLMF_LTYPE_SHIFT) & SLMF_TYPE_MASK;
993 if (nLightType == SLMF_PROJECTED)
994 CParserBin::AddDefineToken(eT__LT_HASPROJ, eT_1, NewTokens);
997 // Include modificator mask definitions in the script
998 if ((nSFlags & HWSG_SUPPORTS_MODIF) && pInst->m_Ident.m_MDMask)
1000 const uint32 tcProjMask = HWMD_TEXCOORD_PROJ;
1001 const uint32 tcMatrixMask = HWMD_TEXCOORD_MATRIX;
1002 const uint32 tcGenObjectLinearMask = HWMD_TEXCOORD_GEN_OBJECT_LINEAR;
1004 if (pInst->m_Ident.m_MDMask & tcProjMask)
1005 CParserBin::AddDefineToken(eT__TT_TEXCOORD_PROJ, NewTokens);
1006 if (pInst->m_Ident.m_MDMask & tcMatrixMask)
1007 CParserBin::AddDefineToken(eT__TT_TEXCOORD_MATRIX, NewTokens);
1008 if (pInst->m_Ident.m_MDMask & tcGenObjectLinearMask)
1009 CParserBin::AddDefineToken(eT__TT_TEXCOORD_GEN_OBJECT_LINEAR, NewTokens);
1012 // Include vertex modificator mask definitions in the script
1013 if ((nSFlags & HWSG_SUPPORTS_VMODIF) && pInst->m_Ident.m_MDVMask)
1015 int nMDV = pInst->m_Ident.m_MDVMask & 0x0fffffff;
1016 int nType = nMDV & MDV_DEFORMTYPE_MASK;
1017 if (nType)
1018 CParserBin::AddDefineToken(eT__VT_TYPE, eT_0 + nType, NewTokens);
1019 if ((nMDV & MDV_BENDING) || nType == eDT_Bending)
1021 CParserBin::AddDefineToken(eT__VT_BEND, eT_1, NewTokens);
1022 if (!(nMDV & MDV_DEFORMTYPE_MASK))
1024 nType = eDT_Bending;
1025 CParserBin::AddDefineToken(eT__VT_TYPE, eT_0 + nType, NewTokens);
1028 if (nMDV & MDV_DEPTH_OFFSET)
1029 CParserBin::AddDefineToken(eT__VT_DEPTH_OFFSET, eT_1, NewTokens);
1030 if (nMDV & MDV_WIND)
1031 CParserBin::AddDefineToken(eT__VT_WIND, eT_1, NewTokens);
1032 if (nMDV & MDV_DET_BENDING)
1033 CParserBin::AddDefineToken(eT__VT_DET_BEND, eT_1, NewTokens);
1034 if (nMDV & MDV_DET_BENDING_GRASS)
1035 CParserBin::AddDefineToken(eT__VT_GRASS, eT_1, NewTokens);
1036 if (nMDV & ~MDV_DEFORMTYPE_MASK)
1037 CParserBin::AddDefineToken(eT__VT_TYPE_MODIF, eT_1, NewTokens);
1040 if (nSFlags & HWSG_FP_EMULATION)
1042 CParserBin::AddDefineToken(eT__FT0_COP, eT_0 + (pInst->m_Ident.m_LightMask & 0xff), NewTokens);
1043 CParserBin::AddDefineToken(eT__FT0_AOP, eT_0 + ((pInst->m_Ident.m_LightMask & 0xff00) >> 8), NewTokens);
1045 byte CO_0 = ((pInst->m_Ident.m_LightMask & 0xff0000) >> 16) & 7;
1046 CParserBin::AddDefineToken(eT__FT0_CARG1, eT_0 + CO_0, NewTokens);
1048 byte CO_1 = ((pInst->m_Ident.m_LightMask & 0xff0000) >> 19) & 7;
1049 CParserBin::AddDefineToken(eT__FT0_CARG2, eT_0 + CO_1, NewTokens);
1051 byte AO_0 = ((pInst->m_Ident.m_LightMask & 0xff000000) >> 24) & 7;
1052 CParserBin::AddDefineToken(eT__FT0_AARG1, eT_0 + AO_0, NewTokens);
1054 byte AO_1 = ((pInst->m_Ident.m_LightMask & 0xff000000) >> 27) & 7;
1055 CParserBin::AddDefineToken(eT__FT0_AARG2, eT_0 + AO_1, NewTokens);
1057 if (CO_0 == eCA_Specular || CO_1 == eCA_Specular || AO_0 == eCA_Specular || AO_1 == eCA_Specular)
1058 CParserBin::AddDefineToken(eT__FT_SPECULAR, NewTokens);
1059 if (CO_0 == eCA_Diffuse || CO_1 == eCA_Diffuse || AO_0 == eCA_Diffuse || AO_1 == eCA_Diffuse)
1060 CParserBin::AddDefineToken(eT__FT_DIFFUSE, NewTokens);
1061 if (CO_0 == eCA_Texture || CO_1 == eCA_Texture || AO_0 == eCA_Texture || AO_1 == eCA_Texture)
1062 CParserBin::AddDefineToken(eT__FT_TEXTURE, NewTokens);
1063 if (CO_0 == eCA_Texture1 || (CO_1 == eCA_Texture1) || AO_0 == eCA_Texture1 || AO_1 == eCA_Texture1
1064 || CO_0 == eCA_Previous || (CO_1 == eCA_Previous) || AO_0 == eCA_Previous || AO_1 == eCA_Previous)
1065 CParserBin::AddDefineToken(eT__FT_TEXTURE1, NewTokens);
1066 if (CO_0 == eCA_Normal || CO_1 == eCA_Normal || AO_0 == eCA_Normal || AO_1 == eCA_Normal)
1067 CParserBin::AddDefineToken(eT__FT_NORMAL, NewTokens);
1068 if (CO_0 == eCA_Constant || (CO_1 == eCA_Constant) || AO_0 == eCA_Constant || AO_1 == eCA_Constant
1069 || CO_0 == eCA_Previous || (CO_1 == eCA_Previous) || AO_0 == eCA_Previous || AO_1 == eCA_Previous)
1070 CParserBin::AddDefineToken(eT__FT_PSIZE, NewTokens);
1072 if (nFlags & HWSF_STOREDATA)
1074 int nStreams = pInst->m_Ident.m_LightMask & 0xff;
1075 if (nStreams & (1 << VSF_QTANGENTS))
1076 CParserBin::AddDefineToken(eT__FT_QTANGENT_STREAM, NewTokens);
1077 if (nStreams & (1 << VSF_TANGENTS))
1078 CParserBin::AddDefineToken(eT__FT_TANGENT_STREAM, NewTokens);
1079 if (nStreams & VSM_HWSKIN)
1080 CParserBin::AddDefineToken(eT__FT_SKIN_STREAM, NewTokens);
1081 #if ENABLE_NORMALSTREAM_SUPPORT
1082 if (CParserBin::m_nPlatform & (SF_D3D11 | SF_D3D12 | SF_DURANGO | SF_ORBIS))
1084 if (nStreams & VSM_NORMALS)
1085 CParserBin::AddDefineToken(eT__FT_NORMAL, NewTokens);
1087 #endif
1088 if (nStreams & VSM_VERTEX_VELOCITY)
1089 CParserBin::AddDefineToken(eT__FT_VERTEX_VELOCITY_STREAM, NewTokens);
1093 int nT = NewTokens.size();
1094 NewTokens.resize(nT + SHData.size());
1095 memcpy(&NewTokens[nT], &SHData[0], SHData.size() * sizeof(uint32));
1097 CParserBin Parser(nullptr, pSH);
1098 Parser.Preprocess(1, NewTokens, Table);
1099 CorrectScriptEnums(Parser, pInst, InstBindVars, Table);
1100 RemoveUnaffectedParameters_D3D10(Parser, pInst, InstBindVars);
1101 AddResourceLayoutToBinScript(Parser, pInst, &Table);
1102 ConvertBinScriptToASCII(Parser, pInst, InstBindVars, Table, sNewScr);
1103 AddResourceLayoutToScriptHeader(pInst, mfProfileString(pInst->m_eClass), m_EntryFunc.c_str(), sNewScr);
1105 // Generate geometry shader
1106 if (m_Flags & HWSG_GS_MULTIRES)
1108 bool bResult = AutoGenMultiresGS(sNewScr, pSH);
1109 if (!bResult)
1110 return false;
1113 return sNewScr.Num() && sNewScr[0];
1116 bool CHWShader_D3D::AutoGenMultiresGS(TArray<char>& sNewScr, CShader* pSH)
1118 CHWShader_D3D* curVS = (CHWShader_D3D*)s_pCurHWVS;
1119 char szEntryVS[128];
1120 strcpy(szEntryVS, curVS->m_EntryFunc.c_str());
1121 strcat(szEntryVS, "(");
1122 char* szStart = strstr(&sNewScr[0], szEntryVS);
1123 assert(szStart);
1124 if (szStart)
1126 char* szEnd = szStart - 1;
1127 while (*szEnd == 0x20)
1128 --szEnd;
1129 char* szS = szEnd;
1130 while (*szS > 0x20)
1131 --szS;
1132 char szStrName[128];
1133 ptrdiff_t nSize = szEnd - szS;
1134 strncpy(szStrName, &szS[1], nSize);
1135 szStrName[nSize] = 0;
1137 char szStruct[128];
1138 strcpy(szStruct, "struct ");
1139 strcat(szStruct, szStrName);
1140 char* szStrStart = strstr(&sNewScr[0], szStruct);
1141 assert(szStrStart);
1143 char* szStrEnd = strstr(szStrStart, "};");
1144 szStrEnd += 2;
1146 char szPosName[128];
1147 char* szPosA = strstr(szStrStart, ":POSITION");
1148 if (!szPosA || szPosA >= szStrEnd)
1149 szPosA = strstr(szStrStart, ":SV_Position");
1150 if (!szPosA || szPosA >= szStrEnd)
1152 #if !defined(_RELEASE)
1153 CRY_ASSERT(false, "Cannot generate a GS for a VS with no SV_Position output");
1154 #endif
1155 return false;
1157 char* szPosAB = szPosA - 1;
1158 while (*szPosAB == 0x20)
1159 --szPosAB;
1160 char* szP = szPosAB;
1161 while (*szP > 0x20)
1162 --szP;
1163 nSize = szPosAB - szP;
1164 strncpy(szPosName, &szP[1], nSize);
1165 szPosName[nSize] = 0;
1167 TArray<char> szNewS;
1168 //szNewS.Copy(&sNewScr[0], szStrStart - &sNewScr[0]);
1169 szNewS.Copy(szStrStart, uint32(szStrEnd - szStrStart) + 1);
1171 m_EntryFunc.Format("%s_GS", curVS->m_EntryFunc.c_str());
1173 string GSDefine;
1174 GSDefine.Format(
1175 "#define NV_VR_FASTGS_FUNCTION_NAME %s\n"
1176 "#define NV_VR_FASTGS_PASSTHROUGH_STRUCT %s\n"
1177 "#define NV_VR_FASTGS_OUTPUT_STRUCT %s_gs\n"
1178 "#define NV_VR_FASTGS_POSITION_ATTRIBUTE %s\n\n",
1179 m_EntryFunc.c_str(), szStrName, szStrName, szPosName);
1180 szNewS.Copy(GSDefine.c_str(), GSDefine.size());
1182 ShaderTokensVec NewTokens;
1184 uint32 eT = eT__GS;
1185 CParserBin::AddDefineToken(eT, NewTokens);
1187 // Include runtime mask definitions in the script
1188 SShaderGen* shg = gRenDev->m_cEF.m_pGlobalExt;
1189 if (shg && m_pCurInst->m_Ident.m_RTMask)
1191 for (uint32 i = 0; i < shg->m_BitMask.Num(); i++)
1193 SShaderGenBit* bit = shg->m_BitMask[i];
1194 if (!(bit->m_Mask & m_pCurInst->m_Ident.m_RTMask))
1195 continue;
1196 CParserBin::AddDefineToken(bit->m_dwToken, NewTokens);
1199 int nT = NewTokens.size();
1200 NewTokens.resize(nT + m_TokenData.size());
1201 memcpy(&NewTokens[nT], &m_TokenData[0], m_TokenData.size() * sizeof(uint32));
1203 std::vector<SCGBind> InstBindVars;
1204 CParserBin Parser(nullptr, pSH);
1205 Parser.Preprocess(1, NewTokens, m_TokenTable);
1206 ConvertBinScriptToASCII(Parser, m_pCurInst, InstBindVars, m_TokenTable, szNewS);
1208 sNewScr.Copy(szNewS);
1210 else
1211 return false;
1213 return true;
1216 void CHWShader_D3D::RemoveUnaffectedParameters_D3D10(CParserBin& Parser, SHWSInstance* pInst, std::vector<SCGBind>& InstBindVars)
1218 int nPos = Parser.FindToken(0, Parser.m_Tokens.size() - 1, eT_cbuffer);
1219 while (nPos >= 0)
1221 uint32 nName = Parser.m_Tokens[nPos + 1];
1222 if (nName == eT_PER_BATCH || nName == eT_PER_INSTANCE)
1224 int nPosEnd = Parser.FindToken(nPos + 3, Parser.m_Tokens.size() - 1, eT_br_cv_2);
1225 assert(nPosEnd >= 0);
1226 int nPosN = Parser.FindToken(nPos + 1, Parser.m_Tokens.size() - 1, eT_br_cv_1);
1227 assert(nPosN >= 0);
1228 nPosN++;
1229 while (nPosN < nPosEnd)
1231 uint32 nT = Parser.m_Tokens[nPosN + 1];
1232 int nPosCode = Parser.FindToken(nPosEnd + 1, Parser.m_Tokens.size() - 1, nT);
1233 if (nPosCode < 0)
1235 assert(nPosN > 0 && nPosN < (int)Parser.m_Tokens.size());
1236 if (InstBindVars.size())
1238 size_t i = 0;
1239 CCryNameR nm(Parser.GetString(nT));
1240 for (; i < InstBindVars.size(); i++)
1242 SCGBind& b = InstBindVars[i];
1243 if (b.m_Name == nm)
1244 break;
1246 if (i == InstBindVars.size())
1247 Parser.m_Tokens[nPosN] = eT_comment;
1249 else
1250 Parser.m_Tokens[nPosN] = eT_comment;
1252 nPosN = Parser.FindToken(nPosN + 2, nPosEnd, eT_semicolumn);
1253 assert(nPosN >= 0);
1254 nPosN++;
1256 nPos = Parser.FindToken(nPosEnd + 1, Parser.m_Tokens.size() - 1, eT_cbuffer);
1258 else
1259 nPos = Parser.FindToken(nPos + 2, Parser.m_Tokens.size() - 1, eT_cbuffer);
1261 //#else
1262 /*int nStart = 0;
1263 while (true)
1265 uint32 nName = sFindVar(Parser, nStart);
1266 if (nStart < 0)
1267 break;
1268 bool bAffect = sIsAffectFuncs(Parser, nName);
1269 if (!bAffect)
1270 Parser.m_Tokens[nStart] = eT_comment;
1271 nStart++;
1273 //#endif
1276 #if CRY_RENDERER_VULKAN
1277 std::string resourceTypeToString(SResourceBindPoint::ESlotType type)
1279 switch (type)
1281 case SResourceBindPoint::ESlotType::ConstantBuffer:
1282 return "b";
1283 case SResourceBindPoint::ESlotType::Sampler:
1284 return "s";
1285 case SResourceBindPoint::ESlotType::TextureAndBuffer:
1286 return "t";
1287 case SResourceBindPoint::ESlotType::UnorderedAccessView:
1288 return "u";
1289 default:
1290 CRY_ASSERT(false, "Type is not defined.");
1291 return "";
1295 struct ResourceSetBindingInfo
1297 uint8 set;
1298 uint8 binding;
1299 SResourceBindPoint::ESlotType type;
1301 ResourceSetBindingInfo(uint8 s = (uint8)~0u, uint8 b = (uint8)~0u, SResourceBindPoint::ESlotType t = SResourceBindPoint::ESlotType::ConstantBuffer)
1302 : set(s), binding(b), type(t) {}
1304 std::string ToString() const
1306 return resourceTypeToString(type) + std::to_string(binding) + ", space" + std::to_string(set);
1310 uint32 AddNewTableEntry(FXShaderToken& tokenTable, const char* newTokenStr)
1312 uint32 nToken = CParserBin::GetCRC32(newTokenStr);
1313 FXShaderTokenItor itor = std::lower_bound(tokenTable.begin(), tokenTable.end(), nToken, SortByToken());
1314 if (itor != tokenTable.end() && (*itor).Token == nToken)
1316 assert(!strcmp((*itor).SToken.c_str(), newTokenStr));
1317 return nToken;
1319 STokenD TD;
1320 TD.SToken = newTokenStr;
1321 TD.Token = nToken;
1322 tokenTable.insert(itor, TD);
1324 return nToken;
1327 struct SRegisterRangeDesc
1329 SRegisterRangeDesc()
1330 : type(SResourceBindPoint::ESlotType::InvalidSlotType)
1331 , start(0)
1332 , count(0)
1333 , shaderStageMask(0)
1336 void setTypeAndStage(uint8_t typeAndStageByte)
1338 shaderStageMask = typeAndStageByte & 0x3F;
1339 type = (SResourceBindPoint::ESlotType)(typeAndStageByte >> 6);
1342 void setSlotNumberAndDescCount(uint8_t slotNumberAndDescCount)
1344 start = slotNumberAndDescCount & 0x3F;
1345 count = slotNumberAndDescCount >> 6;
1348 SResourceBindPoint::ESlotType type;
1349 uint32_t start;
1350 uint32_t count;
1351 uint32_t shaderStageMask;
1354 typedef std::vector<std::vector<SRegisterRangeDesc>> RegisterRanges;
1356 RegisterRanges ExtractRegisterRanges(const std::vector<uint8>& RsrcLayoutEncoding)
1358 RegisterRanges registerRanges;
1360 if (RsrcLayoutEncoding.size() > 0)
1362 const uint8_t* pLayoutData = (&RsrcLayoutEncoding[0]);
1364 int setCount = *pLayoutData++;
1365 registerRanges.resize(setCount);
1367 for (int i = 0; i < setCount; i++)
1369 int rangeCount = *pLayoutData++;
1370 registerRanges[i].resize(rangeCount);
1372 for (int j = 0; j < rangeCount; j++)
1374 uint8_t slotTypeStagesByte = *pLayoutData++;
1375 uint8_t slotNumberDescCountByte = *pLayoutData++;
1376 registerRanges[i][j].setTypeAndStage(slotTypeStagesByte);
1377 registerRanges[i][j].setSlotNumberAndDescCount(slotNumberDescCountByte);
1382 return registerRanges;
1385 extern VkShaderStageFlags GetShaderStageFlags(EShaderStage shaderStages);
1386 #endif
1388 void CHWShader_D3D::AddResourceLayoutToBinScript(CParserBin& Parser, SHWSInstance* pInst, FXShaderToken* Table)
1390 #if CRY_RENDERER_VULKAN
1392 if (CRendererCVars::CV_r_VkShaderCompiler && strcmp(CRendererCVars::CV_r_VkShaderCompiler->GetString(), STR_VK_SHADER_COMPILER_HLSLCC) == 0)
1393 return;
1395 // Extract mapping from HLSL register definition to vulkan descriptor set and binding.
1396 // The mapping is stored in vkResourceMapping and will be used later for modifying the shaders.
1397 std::map<std::string, ResourceSetBindingInfo> vkResourceMapping;
1398 const std::vector<uint8>* LayoutEncoding = GetDeviceObjectFactory().LookupResourceLayoutEncoding(pInst->m_Ident.m_pipelineState.VULKAN.resourceLayoutHash);
1399 if (LayoutEncoding)
1401 RegisterRanges registerRanges = ExtractRegisterRanges(*LayoutEncoding);
1403 uint32_t bindingIndex;
1404 uint32_t setIndex;
1405 for (setIndex = 0; setIndex < (uint32_t)registerRanges.size(); setIndex++)
1407 bindingIndex = 0;
1408 for (size_t i = 0; i < registerRanges[setIndex].size(); i++)
1410 const SRegisterRangeDesc& rangeDesc = registerRanges[setIndex][i];
1412 for (uint32_t registerIdxOffset = 0; registerIdxOffset < rangeDesc.count; ++registerIdxOffset)
1414 if (GetShaderStageFlags(SHADERSTAGE_FROM_SHADERCLASS(pInst->m_eClass)) & rangeDesc.shaderStageMask)
1416 std::string resourceRegisterName = resourceTypeToString(rangeDesc.type);
1417 resourceRegisterName += std::to_string(rangeDesc.start + registerIdxOffset);
1418 vkResourceMapping[resourceRegisterName] = ResourceSetBindingInfo(setIndex, bindingIndex, rangeDesc.type);
1422 bindingIndex += rangeDesc.count;
1427 // Check for all the used registers in the shader code and replace them with vulkan descriptor set and binding
1428 // if they were part of resource layout description.
1429 int nCur = 0;
1430 int nSize = Parser.m_Tokens.size();
1431 const uint32* pTokens = &Parser.m_Tokens[0];
1432 std::map<uint32, uint32> alreadyProcessed;
1433 while (true)
1435 // Look for "register(*)" in the shader code.
1436 nCur = Parser.FindToken(nCur, nSize - 1, eT_register);
1437 if (nCur < 0)
1438 break;
1439 int32 OpenBacketToken = Parser.FindToken(nCur, nSize - 1, eT_br_rnd_1);
1440 int32 CloseBacketToken = Parser.FindToken(nCur, nSize - 1, eT_br_rnd_2);
1441 assert(OpenBacketToken >= 0 && CloseBacketToken >= 0);
1442 if (CloseBacketToken < 0 || OpenBacketToken < 0)
1443 break;
1445 uint32_t BegRegisterToken = (uint32_t)OpenBacketToken + 1;
1446 uint32_t EndRegisterToken = (uint32_t)CloseBacketToken;
1447 auto nToken = CParserBin::NextToken(pTokens, BegRegisterToken, EndRegisterToken);
1449 // if the register is already hit, use the previously created token for it.
1450 if (alreadyProcessed.find(nToken) != alreadyProcessed.end())
1452 Parser.m_Tokens[BegRegisterToken - 1] = alreadyProcessed[nToken];
1453 nCur = EndRegisterToken;
1454 continue;
1457 // Map the newly found register if it is necessary.
1458 uint32 newToken = nToken;
1459 const char* registerName = Parser.GetString(nToken, *Table, false);
1460 auto resource = vkResourceMapping.find(registerName);
1461 if (resource != vkResourceMapping.end())
1463 std::string newTokenStr = resource->second.ToString();
1464 newToken = AddNewTableEntry(*Table, newTokenStr.c_str());
1465 Parser.m_Tokens[BegRegisterToken - 1] = newToken;
1468 alreadyProcessed[nToken] = newToken;
1469 nCur = EndRegisterToken;
1471 #endif
1474 struct SStructData
1476 uint32 m_nName;
1477 uint32 m_nTCs;
1478 int m_nPos;
1481 void CHWShader_D3D::CorrectScriptEnums(CParserBin& Parser, SHWSInstance* pInst, std::vector<SCGBind>& InstBindVars, const FXShaderToken& Table)
1483 // correct enumeration of TEXCOORD# interpolators after preprocessing
1484 int nCur = 0;
1485 int nSize = Parser.m_Tokens.size();
1486 uint32* pTokens = &Parser.m_Tokens[0];
1487 int nInstParam = 0;
1488 const uint32 Toks[] = { eT_TEXCOORDN, eT_TEXCOORDN_centroid, eT_unknown };
1490 std::vector<SStructData> SData;
1491 uint32 i;
1492 while (true)
1494 nCur = Parser.FindToken(nCur, nSize - 1, eT_struct);
1495 if (nCur < 0)
1496 break;
1497 int nLastStr = Parser.FindToken(nCur, nSize - 1, eT_br_cv_2);
1498 assert(nLastStr >= 0);
1499 if (nLastStr < 0)
1500 break;
1501 bool bNested = false;
1502 for (i = 0; i < SData.size(); i++)
1504 SStructData& Data = SData[i];
1505 Data.m_nPos = Parser.FindToken(nCur, nLastStr, Data.m_nName);
1506 if (Data.m_nPos > 0)
1507 bNested = true;
1509 uint32 nName = pTokens[nCur + 1];
1510 int n = 0;
1511 while (nCur < nLastStr)
1513 int nTN = Parser.FindToken(nCur, nLastStr, Toks);
1514 if (nTN < 0)
1516 nCur = nLastStr + 1;
1517 break;
1519 int nNested = 0;
1520 if (bNested)
1522 for (i = 0; i < SData.size(); i++)
1524 SStructData& Data = SData[i];
1525 if (Data.m_nPos > 0 && nTN > Data.m_nPos)
1526 nNested += Data.m_nTCs;
1529 assert(pTokens[nTN - 1] == eT_colon);
1530 int nArrSize = 1;
1531 uint32 nTokName;
1532 if (pTokens[nTN - 2] == eT_br_sq_2)
1534 nArrSize = pTokens[nTN - 3] - eT_0;
1535 if ((unsigned int) nArrSize > 15)
1537 const char* szArrSize = Parser.GetString(pTokens[nTN - 3], Table);
1538 nArrSize = szArrSize ? atoi(szArrSize) : 0;
1540 assert(pTokens[nTN - 4] == eT_br_sq_1);
1541 //const char *szName = Parser.GetString(pTokens[nTN-5], *Table);
1542 nTokName = pTokens[nTN - 5];
1544 else
1546 uint32 nType = pTokens[nTN - 3];
1547 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 ||
1548 nType == eT_half || nType == eT_half2 || nType == eT_half3 || nType == eT_half4 || nType == eT_half4x4 || nType == eT_half3x4 || nType == eT_half2x4 || nType == eT_half3x3);
1549 if (nType == eT_float4x4 || nType == eT_half4x4)
1550 nArrSize = 4;
1551 else if (nType == eT_float3x4 || nType == eT_float3x3 || nType == eT_half3x4 || nType == eT_half3x3)
1552 nArrSize = 3;
1553 else if (nType == eT_float2x4 || nType == eT_half2x4)
1554 nArrSize = 2;
1555 nTokName = pTokens[nTN - 2];
1557 assert(nArrSize > 0 && nArrSize < 16);
1559 EToken eT = (pTokens[nTN] == eT_TEXCOORDN) ? eT_TEXCOORD0 : eT_TEXCOORD0_centroid;
1561 pTokens[nTN] = n + nNested + eT;
1562 n += nArrSize;
1563 nCur = nTN + 1;
1565 SStructData SD;
1566 SD.m_nName = nName;
1567 SD.m_nPos = -1;
1568 SD.m_nTCs = n;
1569 SData.push_back(SD);
1571 if (InstBindVars.size())
1572 qsort(&InstBindVars[0], InstBindVars.size(), sizeof(SCGBind), CGBindCallback);
1573 pInst->m_nNumInstAttributes = nInstParam;
1576 static int sFetchInst(uint32& nCur, uint32* pTokens, uint32 nT, std::vector<uint32>& Parameter)
1578 while (true)
1580 uint32 nTok = pTokens[nCur];
1581 if (nTok != eT_br_rnd_1 && nTok != eT_br_rnd_2 && nTok != eT_comma)
1582 break;
1583 nCur++;
1585 int nC = 0;
1586 Parameter.push_back(pTokens[nCur]);
1587 nCur++;
1588 while (pTokens[nCur] == eT_dot)
1590 nC = 2;
1591 Parameter.push_back(pTokens[nCur]);
1592 Parameter.push_back(pTokens[nCur + 1]);
1593 nCur += 2;
1595 return nC;
1598 static void sCR(TArray<char>& Text, int nLevel)
1600 Text.AddElem('\n');
1601 for (int i = 0; i < nLevel; i++)
1603 Text.AddElem(' ');
1604 Text.AddElem(' ');
1608 bool CHWShader_D3D::ConvertBinScriptToASCII(CParserBin& Parser, SHWSInstance* pInst, std::vector<SCGBind>& InstBindVars, const FXShaderToken& Table, TArray<char>& Text)
1610 uint32 i;
1611 bool bRes = true;
1613 uint32* pTokens = &Parser.m_Tokens[0];
1614 uint32 nT = Parser.m_Tokens.size();
1615 int nLevel = 0;
1616 for (i = 0; i < nT; i++)
1618 uint32 nToken = pTokens[i];
1619 if (nToken == 0)
1621 Text.Copy("\n", 1);
1622 continue;
1624 if (nToken == eT_skip)
1626 i++;
1627 continue;
1629 if (nToken == eT_skip_1)
1631 while (i < nT)
1633 nToken = pTokens[i];
1634 if (nToken == eT_skip_2)
1635 break;
1636 i++;
1638 assert(i < nT);
1639 continue;
1641 if (nToken == eT_fetchinst)
1643 char str[512];
1644 i++;
1645 std::vector<uint32> ParamDst, ParamSrc;
1646 TArray<char> sParamDstFull, sParamDstName, sParamSrc;
1647 int nDst = sFetchInst(i, &Parser.m_Tokens[0], Parser.m_Tokens.size(), ParamDst);
1648 assert(Parser.m_Tokens[i] == eT_eq);
1649 if (Parser.m_Tokens[i] != eT_eq)
1651 // Should never happen
1652 int n = CParserBin::FindToken(i, Parser.m_Tokens.size() - 1, &Parser.m_Tokens[0], eT_semicolumn);
1653 if (n > 0)
1654 i = n + 1;
1655 continue;
1657 i++;
1658 int nSrc = sFetchInst(i, &Parser.m_Tokens[0], Parser.m_Tokens.size(), ParamSrc);
1659 CParserBin::ConvertToAscii(&ParamDst[0], ParamDst.size(), Table, sParamDstFull);
1660 CParserBin::ConvertToAscii(&ParamDst[nDst], 1, Table, sParamDstName);
1661 CParserBin::ConvertToAscii(&ParamSrc[nSrc], 1, Table, sParamSrc);
1662 assert(strncmp(&sParamSrc[0], "Inst", 4) == 0);
1665 sParamSrc.Free();
1666 CParserBin::ConvertToAscii(&ParamSrc[0], ParamSrc.size(), Table, sParamSrc);
1667 cry_sprintf(str, "%s = %s;\n", &sParamDstFull[0], &sParamSrc[0]);
1668 Text.Copy(str, strlen(str));
1670 while (Parser.m_Tokens[i] != eT_semicolumn)
1672 i++;
1674 continue;
1676 const char* szStr = CParserBin::GetString(nToken, Table, false);
1677 assert(szStr);
1678 if (!szStr || !szStr[0])
1680 assert(0);
1681 bRes = CParserBin::CorrectScript(pTokens, i, nT, Text);
1683 else
1685 #if defined(_DEBUG) && !CRY_PLATFORM_ORBIS
1686 int n = 0;
1687 while (szStr[n])
1689 char c = szStr[n++];
1690 bool bASC = isascii(c);
1691 assert(bASC);
1693 #endif
1694 if (nToken == eT_semicolumn || nToken == eT_br_cv_1)
1696 if (nToken == eT_br_cv_1)
1698 sCR(Text, nLevel);
1699 nLevel++;
1701 Text.Copy(szStr, strlen(szStr));
1702 if (nToken == eT_semicolumn)
1704 if (i + 1 < nT && pTokens[i + 1] == eT_br_cv_2)
1705 sCR(Text, nLevel - 1);
1706 else
1707 sCR(Text, nLevel);
1709 else if (i + 1 < nT)
1711 if (pTokens[i + 1] < eT_br_rnd_1 || pTokens[i + 1] >= eT_float)
1712 sCR(Text, nLevel);
1715 else
1717 if (i + 1 < nT)
1719 if (Text.Num())
1721 char cPrev = Text[Text.Num() - 1];
1722 if (!SkipChar((uint8)cPrev) && !SkipChar((uint8)szStr[0]))
1723 Text.AddElem(' ');
1726 Text.Copy(szStr, strlen(szStr));
1727 if (nToken == eT_br_cv_2)
1729 nLevel--;
1730 if (i + 1 < nT && pTokens[i + 1] != eT_semicolumn)
1731 sCR(Text, nLevel);
1736 Text.AddElem(0);
1738 return bRes;
1741 int OrigToBase64Size(int orig_size)
1743 return ((orig_size + 2) / 3) * 4;
1746 static const uint8 BASE64_TABLE[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1748 void Base64EncodeBuffer(const void* orig_buf, int orig_buf_size, void* b64_buf)
1750 const uint8* p = (const uint8*)orig_buf;
1751 uint8* q = (uint8*)b64_buf;
1752 int w;
1754 for (int i = 0, e = orig_buf_size / 3; i < e; ++i, p += 3, q += 4)
1756 // assuming little endian
1757 w = (p[0] << 16) | (p[1] << 8) | p[2];
1758 q[0] = BASE64_TABLE[w >> 18];
1759 q[1] = BASE64_TABLE[(w >> 12) & 0x3F];
1760 q[2] = BASE64_TABLE[(w >> 6) & 0x3F];
1761 q[3] = BASE64_TABLE[w & 0x3F];
1764 switch (orig_buf_size % 3)
1766 case 1:
1767 w = p[0];
1768 q[0] = BASE64_TABLE[w >> 2];
1769 q[1] = BASE64_TABLE[(w << 4) & 0x3F];
1770 q[2] = '=';
1771 q[3] = '=';
1772 break;
1773 case 2:
1774 w = (p[0] << 8) | p[1];
1775 q[0] = BASE64_TABLE[w >> 10];
1776 q[1] = BASE64_TABLE[(w >> 4) & 0x3F];
1777 q[2] = BASE64_TABLE[(w << 2) & 0x3F];
1778 q[3] = '=';
1779 break;
1783 bool CHWShader_D3D::AddResourceLayoutToScriptHeader(SHWSInstance* pInst, const char* szProfile, const char* pFunCCryName, TArray<char>& Scr)
1785 #if CRY_RENDERER_VULKAN
1787 if (CRendererCVars::CV_r_VkShaderCompiler && strcmp(CRendererCVars::CV_r_VkShaderCompiler->GetString(), STR_VK_SHADER_COMPILER_GLSLANG) == 0)
1789 string pragmaRowMajor = "#pragma pack_matrix(row_major)\n";
1790 Scr.Insert(0, pragmaRowMajor.length());
1791 memcpy(&Scr[0], pragmaRowMajor.c_str(), pragmaRowMajor.length());
1794 if (auto pEncodedLayout = GetDeviceObjectFactory().LookupResourceLayoutEncoding(pInst->m_Ident.m_pipelineState.VULKAN.resourceLayoutHash))
1796 const int TempBufferSize = 4096;
1797 int bin[TempBufferSize];
1798 int pointer = 0;
1800 bin[pointer++] = strlen(szProfile);
1801 bin[pointer + ((strlen(szProfile) + 3) / 4) - 1] = 0;
1802 memcpy(&bin[pointer], szProfile, strlen(szProfile));
1803 pointer += (strlen(szProfile) + 3) / 4;
1805 bin[pointer++] = strlen(pFunCCryName);
1806 bin[pointer + ((strlen(pFunCCryName) + 3) / 4) - 1] = 0;
1807 memcpy(&bin[pointer], pFunCCryName, strlen(pFunCCryName));
1808 pointer += (strlen(pFunCCryName) + 3) / 4;
1810 CRY_ASSERT(TempBufferSize - pointer - pEncodedLayout->size() > 0);
1811 memcpy(&bin[pointer], pEncodedLayout->data(), pEncodedLayout->size());
1812 pointer += (pEncodedLayout->size() + 3) / 4;
1814 // vertex input description: currently disabled.
1815 bin[pointer++] = 0;
1816 bin[pointer++] = 0;
1818 string head = "/*\n";
1819 string tail = "\n*/\n\n";
1821 Scr.Insert(0, head.length() + OrigToBase64Size(pointer * 4) + tail.length());
1823 memcpy(&Scr[0], head.c_str(), head.length());
1824 Base64EncodeBuffer(bin, pointer * 4, &Scr[head.length()]);
1825 memcpy(&Scr[head.length() + OrigToBase64Size(pointer * 4)], tail.c_str(), tail.length());
1827 return true;
1829 #endif
1831 return false;
1834 void CHWShader_D3D::mfGetSrcFileName(char* srcName, int nSize)
1836 if (!srcName || nSize <= 0)
1837 return;
1838 if (!m_NameSourceFX.empty())
1840 cry_strcpy(srcName, nSize, m_NameSourceFX.c_str());
1841 return;
1843 cry_strcpy(srcName, nSize, gRenDev->m_cEF.m_HWPath);
1844 if (m_eSHClass == eHWSC_Vertex)
1845 cry_strcat(srcName, nSize, "Declarations/CGVShaders/");
1846 else if (m_eSHClass == eHWSC_Pixel)
1847 cry_strcat(srcName, nSize, "Declarations/CGPShaders/");
1848 else
1849 cry_strcat(srcName, nSize, "Declarations/CGGShaders/");
1850 cry_strcat(srcName, nSize, GetName());
1851 cry_strcat(srcName, nSize, ".crycg");
1854 void CHWShader_D3D::mfGenName(SHWSInstance* pInst, char* dstname, int nSize, byte bType)
1856 if (bType)
1857 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);
1858 else
1859 CHWShader::mfGenName(0, 0, 0, 0, 0, 0, eHWSC_Num, dstname, nSize, bType);
1862 void CHWShader_D3D::mfGetDstFileName(SHWSInstance* pInst, char* dstname, int nSize, byte bType)
1864 cry_strcpy(dstname, nSize, gRenDev->m_cEF.m_ShadersCache);
1866 if (m_eSHClass == eHWSC_Vertex)
1868 if (bType == 1 || bType == 4)
1869 cry_strcat(dstname, nSize, "CGVShaders/Debug/");
1870 else if (bType == 0)
1871 cry_strcat(dstname, nSize, "CGVShaders/");
1872 else if (bType == 2 || bType == 3)
1873 cry_strcat(dstname, nSize, "CGVShaders/Pending/");
1875 else if (m_eSHClass == eHWSC_Pixel)
1877 if (bType == 1 || bType == 4)
1878 cry_strcat(dstname, nSize, "CGPShaders/Debug/");
1879 else if (bType == 0)
1880 cry_strcat(dstname, nSize, "CGPShaders/");
1881 else if (bType == 2 || bType == 3)
1882 cry_strcat(dstname, nSize, "CGPShaders/Pending/");
1884 else if (m_eSHClass == eHWSC_Geometry)
1886 if (bType == 1 || bType == 4)
1887 cry_strcat(dstname, nSize, "CGGShaders/Debug/");
1888 else if (bType == 0)
1889 cry_strcat(dstname, nSize, "CGGShaders/");
1890 else if (bType == 2 || bType == 3)
1891 cry_strcat(dstname, nSize, "CGGShaders/Pending/");
1893 else if (m_eSHClass == eHWSC_Hull)
1895 if (bType == 1 || bType == 4)
1896 cry_strcat(dstname, nSize, "CGHShaders/Debug/");
1897 else if (bType == 0)
1898 cry_strcat(dstname, nSize, "CGHShaders/");
1899 else if (bType == 2 || bType == 3)
1900 cry_strcat(dstname, nSize, "CGHShaders/Pending/");
1902 else if (m_eSHClass == eHWSC_Domain)
1904 if (bType == 1 || bType == 4)
1905 cry_strcat(dstname, nSize, "CGDShaders/Debug/");
1906 else if (bType == 0)
1907 cry_strcat(dstname, nSize, "CGDShaders/");
1908 else if (bType == 2 || bType == 3)
1909 cry_strcat(dstname, nSize, "CGDShaders/Pending/");
1911 else if (m_eSHClass == eHWSC_Compute)
1913 if (bType == 1 || bType == 4)
1914 cry_strcat(dstname, nSize, "CGCShaders/Debug/");
1915 else if (bType == 0)
1916 cry_strcat(dstname, nSize, "CGCShaders/");
1917 else if (bType == 2 || bType == 3)
1918 cry_strcat(dstname, nSize, "CGCShaders/Pending/");
1921 cry_strcat(dstname, nSize, GetName());
1923 if (bType == 2)
1924 cry_strcat(dstname, nSize, "_out");
1926 if (bType == 0)
1928 char* s = strchr(dstname, '(');
1929 if (s)
1930 s[0] = 0;
1933 char szGenName[256];
1934 mfGenName(pInst, szGenName, 256, bType);
1936 cry_strcat(dstname, nSize, szGenName);
1939 //========================================================================================================
1940 // Binary cache support
1942 SDiskShaderCache::SDiskShaderCache(const char* name, cacheSource cacheType) : cacheType(cacheType)
1944 OpenCacheFile(name, cacheType);
1947 SDiskShaderCache::SDiskShaderCache(recreateUserCacheTag, const char* name, std::uint32_t CRC32, float cacheVer) : cacheType(cacheSource::user)
1949 stack_string szUser = stack_string(gRenDev->m_cEF.m_szUserPath.c_str()) + stack_string(name);
1950 CResFile* rfUser = new CResFile(szUser.c_str());
1952 bool result = rfUser->mfOpen(RA_CREATE | (CParserBin::m_bEndians ? RA_ENDIANS : 0), &gRenDev->m_cEF.m_ResLookupDataMan[static_cast<int>(cacheType)]) > 0;
1953 if (!result)
1955 rfUser->mfClose();
1956 SAFE_DELETE(rfUser);
1957 return;
1959 rfUser->StoreLookupData(CRC32, cacheVer);
1960 rfUser->mfFlush();
1962 m_pRes = rfUser;
1965 SDiskShaderCache::~SDiskShaderCache() noexcept
1967 SAFE_DELETE(m_pRes);
1970 std::pair<std::unique_ptr<byte[]>, uint32> SDiskShaderCache::DecompressResource(CResFileOpenScope& scope, size_t offset, size_t size) const
1972 using ReturnType = std::pair<std::unique_ptr<byte[]>, size_t>;
1974 auto* handle = scope.getHandle();
1976 // Read resource
1977 gEnv->pCryPak->FSeek(handle->mfGetHandle(), offset, SEEK_SET);
1978 std::unique_ptr<byte[]> dataSource = std::unique_ptr<byte[]>(new byte[size]);
1979 const auto readBytes = gEnv->pCryPak->FReadRaw(dataSource.get(), size, 1, handle->mfGetHandle());
1980 gEnv->pCryPak->FSeek(handle->mfGetHandle(), 0, SEEK_SET);
1982 if (!readBytes)
1983 return ReturnType{};
1984 byte* buf = dataSource.get();
1986 const auto resVersion = handle->mfGetVersion();
1987 const auto swapEndian = handle->RequiresSwapEndianOnRead();
1989 uint32 decompressedSize = 0;
1990 std::unique_ptr<byte[]> pData = nullptr;
1991 switch(resVersion)
1993 case RESVERSION_LZSS:
1994 decompressedSize = *reinterpret_cast<uint32*>(buf);
1995 if (size >= 10000000)
1996 return ReturnType{};
1997 if (swapEndian)
1998 SwapEndian(decompressedSize, eBigEndian);
1999 pData = std::unique_ptr<byte[]>(new byte[decompressedSize]);
2000 if (!pData)
2002 CryWarning(EValidatorModule::VALIDATOR_MODULE_RENDERER, EValidatorSeverity::VALIDATOR_ERROR, "FileRead - Allocation fault");
2003 return ReturnType{};
2005 if (!Decodem(&buf[4], pData.get(), size - 4, decompressedSize))
2007 CryWarning(EValidatorModule::VALIDATOR_MODULE_RENDERER, EValidatorSeverity::VALIDATOR_ERROR, "FileRead - Decodem fault");
2008 return ReturnType{};
2011 break;
2013 case RESVERSION_LZMA:
2014 uint64 outSize64;
2015 if (Lzma86_GetUnpackSize(buf, size, &outSize64) != 0)
2017 CryWarning(EValidatorModule::VALIDATOR_MODULE_RENDERER, EValidatorSeverity::VALIDATOR_ERROR, "FileRead - data error");
2018 return ReturnType{};
2020 decompressedSize = static_cast<uint32>(outSize64);
2021 if (decompressedSize != 0)
2023 pData = std::unique_ptr<byte[]>(new byte[decompressedSize]);
2024 if (!pData)
2026 CryWarning(EValidatorModule::VALIDATOR_MODULE_RENDERER, EValidatorSeverity::VALIDATOR_ERROR, "FileRead - can't allocate");
2027 return ReturnType{};
2029 size_t sizeOut = decompressedSize;
2030 const auto res = Lzma86_Decode(pData.get(), &sizeOut, buf, &size);
2031 decompressedSize = static_cast<uint32_t>(sizeOut);
2032 if (res != 0)
2034 CryWarning(EValidatorModule::VALIDATOR_MODULE_RENDERER, EValidatorSeverity::VALIDATOR_ERROR, "FileRead - LzmaDecoder error");
2035 return ReturnType{};
2039 break;
2041 case RESVERSION_DEBUG:
2042 decompressedSize = size - 20;
2043 if (size <= 20 || decompressedSize > 128 * 1024 * 1024)
2045 CryWarning(EValidatorModule::VALIDATOR_MODULE_RENDERER, EValidatorSeverity::VALIDATOR_ERROR, "FileRead - Corrupt DirEntiy size");
2046 return ReturnType{};
2048 pData = std::unique_ptr<byte[]>(new byte[decompressedSize]);
2049 memcpy(pData.get(), &buf[10], decompressedSize);
2051 break;
2054 return std::make_pair(std::move(pData), decompressedSize);
2057 void SDiskShaderCache::GetMemoryUsage(ICrySizer* pSizer) const
2059 pSizer->AddObject(this, sizeof(*this));
2060 pSizer->AddObject(m_pRes);
2063 bool SDiskShaderCache::OpenCacheFileImpl(cacheSource cacheType, CResFile* pRF)
2065 bool bValid = true;
2066 int nRes = pRF->mfOpen(RA_READ | (CParserBin::m_bEndians ? RA_ENDIANS : 0), &gRenDev->m_cEF.m_ResLookupDataMan[static_cast<int>(cacheType)], nullptr);
2067 if (nRes == 0)
2069 pRF->mfClose();
2070 bValid = false;
2072 else if (nRes > 0)
2074 if (cacheType == cacheSource::user)
2076 // User cache, reopen with read-write access.
2077 pRF->mfClose();
2078 if (bValid)
2080 int nAcc = CRenderer::CV_r_shadersAllowCompilation != 0 ? (RA_READ | RA_WRITE) : RA_READ;
2081 if (!pRF->mfOpen(nAcc | (CParserBin::m_bEndians ? RA_ENDIANS : 0), &gRenDev->m_cEF.m_ResLookupDataMan[static_cast<int>(cacheType)]))
2083 pRF->mfClose();
2084 bValid = false;
2090 if (!bValid)
2092 SAFE_DELETE(pRF);
2094 else
2095 m_pRes = pRF;
2097 return bValid;
2100 bool SDiskShaderCache::OpenCacheFile(const char* szName, cacheSource src)
2102 bool bValidRO = false;
2103 bool bValidUser = true;
2105 // don't load the readonly cache, when shaderediting is true
2106 if (!CRenderer::CV_r_shadersediting && src == cacheSource::readonly)
2108 stack_string szEngine = stack_string("%ENGINE%/") + stack_string(szName);
2109 CResFile* rfRO = new CResFile(szEngine);
2110 bValidRO = OpenCacheFileImpl(cacheSource::readonly, rfRO);
2112 else if (src == cacheSource::user)
2114 stack_string szUser = stack_string(gRenDev->m_cEF.m_szUserPath.c_str()) + stack_string(szName);
2115 CResFile* rfUser = new CResFile(szUser.c_str());
2116 bValidUser = OpenCacheFileImpl(cacheSource::user, rfUser);
2119 return (bValidRO || bValidUser);
2122 SDeviceShaderEntry CHWShader_D3D::mfGetCacheItem(CShader* pFX, const char* name, SDiskShaderCache* cache, uint32& nFlags)
2124 if (!cache || !cache->m_pRes)
2125 return {};
2127 CRY_PROFILE_FUNCTION(PROFILE_LOADING_ONLY)(gEnv->pSystem);
2129 CResFileOpenScope rfOpenGuard(cache->m_pRes);
2130 if (!rfOpenGuard.open(RA_READ | (CParserBin::m_bEndians ? RA_ENDIANS : 0), &gRenDev->m_cEF.m_ResLookupDataMan[static_cast<int>(cache->GetType())], nullptr))
2131 return {};
2133 bool bAsync = false;
2134 const CDirEntry* de = rfOpenGuard.getHandle()->mfGetEntry(name, &bAsync);
2135 if (de)
2137 // Validate
2138 if (mfValidateCache(*cache) != cacheValidationResult::ok)
2139 return {};
2141 m_pCurInst->m_bAsyncActivating = false;
2142 auto entity = mfShaderEntryFromCache(pFX, *de, rfOpenGuard, *cache);
2143 if (cache->GetType() == cacheSource::user)
2144 nFlags |= HWSG_CACHE_USER;
2145 return entity;
2147 else
2149 m_pCurInst->m_bAsyncActivating = bAsync;
2150 return {};
2154 bool CHWShader_D3D::mfAddCacheItem(SDiskShaderCache* pCache, SShaderCacheHeaderItem* pItem, const byte* pData, int nLen, bool bFlush, CCryNameTSCRC Name)
2156 if (!pCache || !pCache->m_pRes)
2158 CRY_ASSERT(false);
2159 return false;
2162 if (CRenderer::CV_r_shadersdebug == 3 || CRenderer::CV_r_shadersdebug == 4)
2163 CryLog("---Cache: StoredToGlobal %s': 0x%x", pCache->m_pRes->mfGetFileName(), Name.get());
2165 pItem->m_CRC32 = CCrc32::Compute(pData, nLen);
2166 //CryLog("Size: %d: CRC: %x", nLen, pItem->m_CRC32);
2168 byte* pNew = new byte[sizeof(SShaderCacheHeaderItem) + nLen];
2169 if (CParserBin::m_bEndians)
2171 SShaderCacheHeaderItem IT = *pItem;
2172 SwapEndian(IT, eBigEndian);
2173 memcpy(pNew, &IT, sizeof(SShaderCacheHeaderItem));
2175 else
2176 memcpy(pNew, pItem, sizeof(SShaderCacheHeaderItem));
2177 memcpy(&pNew[sizeof(SShaderCacheHeaderItem)], pData, nLen);
2179 CDirEntry de(Name, nLen + sizeof(SShaderCacheHeaderItem), RF_COMPRESS | RF_TEMPDATA);
2181 CResFileOpenScope rfOpenGuard(pCache->m_pRes);
2182 rfOpenGuard.open(RA_WRITE | RA_READ | (CParserBin::m_bEndians ? RA_ENDIANS : 0), &gRenDev->m_cEF.m_ResLookupDataMan[static_cast<int>(pCache->GetType())], nullptr);
2183 pCache->m_pRes->mfFileAdd(&de);
2184 SDirEntryOpen* pOE = pCache->m_pRes->mfOpenEntry(de.GetName());
2185 if (!pOE)
2187 CRY_ASSERT(false, "CHWShader_D3D::mfAddCacheItem(): Couldn't add/open cache entry");
2188 delete[] pNew;
2189 return false;
2192 pOE->pData = pNew;
2193 if (bFlush)
2194 pCache->m_pRes->mfFlush();
2196 return true;
2199 std::vector<SEmptyCombination> SEmptyCombination::s_Combinations;
2201 bool CHWShader_D3D::mfAddEmptyCombination(uint64 nRT, uint64 nGL, uint32 nLT, const SCacheCombination& cmbSaved)
2203 SEmptyCombination Comb;
2204 Comb.nGLNew = m_nMaskGenShader;
2205 Comb.nRTNew = (cmbSaved.Ident.m_RTMask & m_nMaskAnd_RT) | m_nMaskOr_RT;
2206 Comb.nLTNew = cmbSaved.Ident.m_LightMask;
2207 Comb.nGLOrg = nGL;
2208 Comb.nRTOrg = (nRT & m_nMaskAnd_RT) | m_nMaskOr_RT;
2209 Comb.nLTOrg = nLT;
2210 Comb.nMD = cmbSaved.Ident.m_MDMask;
2211 Comb.nMDV = cmbSaved.Ident.m_MDVMask;
2212 if (m_eSHClass == eHWSC_Pixel)
2214 Comb.nMD &= ~HWMD_TEXCOORD_FLAG_MASK;
2215 Comb.nMDV = 0;
2218 Comb.pShader = this;
2219 if (Comb.nRTNew != Comb.nRTOrg || Comb.nGLNew != Comb.nGLOrg || Comb.nLTNew != Comb.nLTOrg)
2220 SEmptyCombination::s_Combinations.push_back(Comb);
2222 m_nMaskGenShader = nGL;
2224 return true;
2227 bool CHWShader_D3D::mfStoreEmptyCombination(SEmptyCombination& Comb)
2229 auto cache = QueryDiskCache(cacheSource::user);
2230 if (!cache || !cache->m_pRes)
2231 return false;
2233 CResFile* rf = cache->m_pRes;
2234 char nameOrg[128];
2235 char nameNew[128];
2236 SShaderCombIdent Ident;
2237 Ident.m_GLMask = Comb.nGLNew;
2238 Ident.m_RTMask = Comb.nRTNew;
2239 Ident.m_LightMask = Comb.nLTNew;
2240 Ident.m_MDMask = Comb.nMD;
2241 Ident.m_MDVMask = Comb.nMDV;
2242 SHWSInstance* pInstNew = mfGetInstance(Ident, 0);
2243 mfGenName(pInstNew, nameNew, 128, 1);
2244 CDirEntry* deNew = rf->mfGetEntry(nameNew);
2245 //assert(deNew);
2246 if (!deNew)
2247 return false;
2249 Ident.m_GLMask = Comb.nGLOrg;
2250 Ident.m_RTMask = Comb.nRTOrg;
2251 Ident.m_LightMask = Comb.nLTOrg;
2252 Ident.m_MDMask = Comb.nMD;
2253 Ident.m_MDVMask = Comb.nMDV;
2254 SHWSInstance* pInstOrg = mfGetInstance(Ident, 0);
2255 mfGenName(pInstOrg, nameOrg, 128, 1);
2256 CDirEntry* deOrg = rf->mfGetEntry(nameOrg);
2257 if (deOrg)
2259 if (deOrg->GetOffset() != deNew->GetOffset())
2260 deOrg->MarkNotSaved();
2262 // Also evict in-memory image of user cache
2263 InvalidateCache(cacheSource::user);
2265 return true;
2267 CDirEntry de(nameOrg, deNew->GetSize(), deNew->GetOffset(), deNew->GetFlags());
2268 de.MarkNotSaved();
2269 rf->mfFileAdd(&de);
2271 return true;
2274 bool CHWShader_D3D::mfFlushCacheFile()
2276 uint32 i;
2278 for (i = 0; i < m_Insts.size(); i++)
2280 SHWSInstance* pInst = m_Insts[i];
2281 if (pInst->m_Handle.m_bStatus == 2) // Fake
2282 pInst->m_Handle = SD3DShaderHandle{};
2285 // Flush
2286 auto cache = QueryDiskCache(cacheSource::user);
2287 if (cache && cache->m_pRes)
2289 cache->m_pRes->mfFlush();
2290 return true;
2293 return false;
2296 struct SData
2298 CCryNameTSCRC Name;
2299 uint32 nSizeDecomp;
2300 uint32 nSizeComp;
2301 uint32 nOffset;
2302 uint16 flags;
2303 bool needsProcessing;
2304 byte* pData;
2306 bool operator<(const SData& o) const
2308 return Name < o.Name;
2311 #if CRY_PLATFORM_DESKTOP
2312 // Remove shader duplicates
2313 bool SDiskShaderCache::mfOptimiseCacheFile(SOptimiseStats* pStats)
2315 if (!m_pRes)
2316 return false;
2318 CResFileOpenScope rfOpenGuard(m_pRes);
2319 const auto openResult = rfOpenGuard.open(RA_READ | (CParserBin::m_bEndians ? RA_ENDIANS : 0), &gRenDev->m_cEF.m_ResLookupDataMan[static_cast<int>(cacheType)], nullptr);
2320 if (!openResult)
2321 return false;
2323 ResDir* Dir = m_pRes->mfGetDirectory();
2324 uint32 i, j;
2325 std::vector<SData> Data;
2327 if (pStats)
2328 pStats->nEntries += Dir->size();
2330 for (CDirEntry& DE : *Dir)
2332 if (!DE.IsValid())
2333 continue;
2335 SData d;
2336 d.flags = DE.GetFlags();
2337 d.nSizeComp = d.nSizeDecomp = 0;
2338 d.pData = m_pRes->mfFileReadCompressed(&DE, d.nSizeDecomp, d.nSizeComp);
2339 assert(d.pData && d.nSizeComp && d.nSizeDecomp);
2340 if (!d.pData || !d.nSizeComp || !d.nSizeDecomp)
2341 continue;
2342 d.nOffset = DE.GetOffset();
2343 d.needsProcessing = true;
2344 d.Name = DE.GetName();
2345 Data.push_back(d);
2346 m_pRes->mfCloseEntry(DE.GetName(), DE.GetFlags());
2349 int nOutFiles = Data.size();
2351 // detect duplicates
2352 for (i = 0; i < Data.size(); i++)
2354 if (!Data[i].needsProcessing)
2355 continue;
2357 Data[i].needsProcessing = false;
2358 int nSizeComp = Data[i].nSizeComp;
2359 int nSizeDecomp = Data[i].nSizeDecomp;
2360 for (j = i + 1; j < Data.size(); j++)
2362 if (!Data[j].needsProcessing)
2363 continue;
2365 if (nSizeComp != Data[j].nSizeComp || nSizeDecomp != Data[j].nSizeDecomp)
2366 continue;
2368 if (!memcmp(Data[i].pData, Data[j].pData, nSizeComp))
2370 Data[j].needsProcessing = false;
2371 Data[j].nOffset = Data[i].nOffset;
2372 Data[j].flags |= RF_DUPLICATE;
2373 nOutFiles--;
2378 if (nOutFiles != Data.size() || CRenderer::CV_r_shaderscachedeterministic)
2380 if (nOutFiles == Data.size())
2382 iLog->Log(" Force optimizing for deterministic order...");
2385 iLog->Log(" Optimizing shaders resource '%s' (%" PRISIZE_T " items)...", m_pRes->mfGetFileName(), Data.size());
2387 m_pRes->mfClose();
2388 m_pRes->mfOpen(RA_CREATE | (CParserBin::m_bEndians ? RA_ENDIANS : 0), &gRenDev->m_cEF.m_ResLookupDataMan[static_cast<int>(GetType())]);
2390 float fVersion = FX_CACHE_VER;
2391 uint32 nMinor = (int)(((float)fVersion - (float)(int)fVersion) * 10.1f);
2392 uint32 nMajor = (int)fVersion;
2394 SResFileLookupData* pLookupCache = m_pRes->GetLookupData();
2395 if (pLookupCache == NULL || pLookupCache->m_CacheMajorVer != nMajor || pLookupCache->m_CacheMinorVer != nMinor)
2397 CRY_ASSERT(pLookupCache == NULL, "Losing ShaderIdents by recreating lookupdata cache");
2398 m_pRes->StoreLookupData(0, (float)FX_CACHE_VER);
2401 m_pRes->mfFlush();
2403 if (CRenderer::CV_r_shaderscachedeterministic)
2404 std::sort(Data.begin(), Data.end());
2406 for (i = 0; i < Data.size(); i++)
2408 SData* pD = &Data[i];
2409 CDirEntry de;
2411 if (pD->flags & RF_DUPLICATE)
2413 de = CDirEntry(pD->Name, pD->nSizeComp + 4, pD->nOffset, pD->flags | RF_COMPRESS);
2414 SAFE_DELETE_ARRAY(pD->pData);
2416 else
2418 if (pStats)
2420 pStats->nSizeUncompressed += pD->nSizeDecomp;
2421 pStats->nSizeCompressed += pD->nSizeComp;
2422 pStats->nUniqueEntries++;
2424 assert(pD->pData);
2425 if (pD->pData)
2427 de = CDirEntry(pD->Name, pD->nSizeComp + 4, pD->nOffset, pD->flags | RF_TEMPDATA | RF_COMPRESS | RF_COMPRESSED);
2429 SDirEntryOpen* pOE = m_pRes->mfOpenEntry(pD->Name);
2430 byte* pData = new byte[de.GetSize()];
2431 uint32 nSize = pD->nSizeDecomp;
2432 memcpy(pData, &nSize, sizeof(uint32));
2433 memcpy(pData + sizeof(uint32), pD->pData, pD->nSizeComp);
2434 pOE->pData = pData;
2435 SAFE_DELETE_ARRAY(pD->pData);
2438 m_pRes->mfFileAdd(&de);
2442 if (nOutFiles != Data.size())
2443 iLog->Log(" -- Removed %" PRISIZE_T " duplicated shaders", Data.size() - nOutFiles);
2445 Data.clear();
2446 int nSizeDir = m_pRes->mfFlush();
2448 if (pStats)
2449 pStats->nDirDataSize += nSizeDir;
2451 for (i = 0; i < Data.size(); i++)
2453 SData* pD = &Data[i];
2454 SAFE_DELETE_ARRAY(pD->pData);
2457 if (pStats)
2458 CryLog(" -- Shader cache '%s' stats: Entries: %d, Unique Entries: %d, Size: %.3f Mb, Compressed Size: %.3f Mb, Directory Size: %.3f Mb", m_pRes->mfGetFileName(), pStats->nEntries, pStats->nUniqueEntries, pStats->nSizeUncompressed / 1024.0f / 1024.0f, pStats->nSizeCompressed / 1024.0f / 1024.0f, pStats->nDirDataSize / 1024.0f / 1024.0f);
2460 return true;
2462 #endif
2464 int __cdecl sSort(const VOID* arg1, const VOID* arg2)
2466 CDirEntry** pi1 = (CDirEntry**)arg1;
2467 CDirEntry** pi2 = (CDirEntry**)arg2;
2468 CDirEntry* ti1 = *pi1;
2469 CDirEntry* ti2 = *pi2;
2470 if (ti1->GetName() < ti2->GetName())
2471 return -1;
2472 if (ti1->GetName() == ti2->GetName())
2473 return 0;
2474 return 1;
2477 byte* CHWShader_D3D::mfBindsToCache(SHWSInstance* pInst, std::vector<SCGBind>* Binds, int nParams, byte* pP)
2479 int i;
2480 for (i = 0; i < nParams; i++)
2482 SCGBind* cgb = &(*Binds)[i];
2483 SShaderCacheHeaderItemVar* pVar = (SShaderCacheHeaderItemVar*)pP;
2484 pVar->m_nCount = cgb->m_nParameters;
2485 pVar->m_Reg = cgb->m_dwBind;
2486 if (CParserBin::m_bEndians)
2488 SwapEndian(pVar->m_nCount, eBigEndian);
2489 SwapEndian(pVar->m_Reg, eBigEndian);
2491 int len = strlen(cgb->m_Name.c_str()) + 1;
2492 memcpy(pVar->m_Name, cgb->m_Name.c_str(), len);
2493 pP += offsetof(SShaderCacheHeaderItemVar, m_Name) + strlen(pVar->m_Name) + 1;
2495 return pP;
2498 const byte* CHWShader_D3D::mfBindsFromCache(std::vector<SCGBind>& Binds, int nParams, const byte* pP)
2500 for (int i = 0; i < nParams; i++)
2502 SCGBind cgb;
2503 SShaderCacheHeaderItemVar* pVar = (SShaderCacheHeaderItemVar*)pP;
2505 short nParameters = pVar->m_nCount;
2506 if (CParserBin::m_bEndians)
2507 SwapEndian(nParameters, eBigEndian);
2508 cgb.m_nParameters = nParameters;
2510 cgb.m_Name = pVar->m_Name;
2512 int dwBind = pVar->m_Reg;
2513 if (CParserBin::m_bEndians)
2514 SwapEndian(dwBind, eBigEndian);
2515 cgb.m_dwBind = dwBind;
2517 Binds.push_back(cgb);
2518 pP += offsetof(SShaderCacheHeaderItemVar, m_Name) + strlen(pVar->m_Name) + 1;
2520 return pP;
2523 byte* CHWShader::mfIgnoreBindsFromCache(int nParams, byte* pP)
2525 int i;
2526 for (i = 0; i < nParams; i++)
2528 SShaderCacheHeaderItemVar* pVar = (SShaderCacheHeaderItemVar*)pP;
2529 pP += offsetof(SShaderCacheHeaderItemVar, m_Name) + strlen(pVar->m_Name) + 1;
2531 return pP;
2534 bool CHWShader_D3D::mfUploadHW(SHWSInstance* pInst, const byte* pBuf, uint32 nSize, CShader* pSH, uint32 nFlags)
2536 PROFILE_FRAME(Shader_mfUploadHW);
2538 const char* sHwShaderName = _HELP("Vertex Shader");
2539 if (m_eSHClass == eHWSC_Pixel)
2540 sHwShaderName = _HELP("Pixel Shader");
2541 MEMSTAT_CONTEXT_FMT(EMemStatContextType::D3D, "D3D HW %s", sHwShaderName);
2543 HRESULT hr = S_OK;
2544 if (!pInst->m_Handle.m_pShader)
2546 d3dShaderHandleType* handle = nullptr;
2548 if (m_eSHClass == eHWSC_Pixel)
2549 hr = (handle = GetDeviceObjectFactory().CreatePixelShader(pBuf, nSize)) ? S_OK : E_FAIL;
2550 else if (m_eSHClass == eHWSC_Vertex)
2551 hr = (handle = GetDeviceObjectFactory().CreateVertexShader(pBuf, nSize)) ? S_OK : E_FAIL;
2552 else if (m_eSHClass == eHWSC_Geometry)
2554 #if 1 // use 0 for FastGS emulation mode
2555 if (m_Flags & HWSG_GS_MULTIRES)
2557 #if defined(USE_NV_API) && (CRY_RENDERER_DIRECT3D >= 110) && (CRY_RENDERER_DIRECT3D < 120)
2558 if (gcpRendD3D->GetVrProjectionManager()->IsMultiResEnabledStatic())
2560 NvAPI_D3D11_CREATE_FASTGS_EXPLICIT_DESC FastGSArgs = { NVAPI_D3D11_CREATEFASTGSEXPLICIT_VER, NV_FASTGS_USE_VIEWPORT_MASK };
2561 NvAPI_Status Status = NvAPI_D3D11_CreateFastGeometryShaderExplicit(gcpRendD3D->GetDevice(), alias_cast<DWORD*>(pBuf), nSize, NULL, &FastGSArgs, alias_cast<ID3D11GeometryShader**>(&handle));
2562 hr = (Status == NVAPI_OK) ? S_OK : E_FAIL;
2564 else
2565 #endif
2567 pInst->m_Handle.m_pShader->m_bDisabled = true;
2568 handle = nullptr;
2569 hr = S_OK;
2572 else
2573 #endif
2575 hr = (handle = GetDeviceObjectFactory().CreateGeometryShader(pBuf, nSize)) ? S_OK : E_FAIL;
2578 else if (m_eSHClass == eHWSC_Hull)
2579 hr = (handle = GetDeviceObjectFactory().CreateHullShader(pBuf, nSize)) ? S_OK : E_FAIL;
2580 else if (m_eSHClass == eHWSC_Compute)
2581 hr = (handle = GetDeviceObjectFactory().CreateComputeShader(pBuf, nSize)) ? S_OK : E_FAIL;
2582 else if (m_eSHClass == eHWSC_Domain)
2583 hr = (handle = GetDeviceObjectFactory().CreateDomainShader(pBuf, nSize)) ? S_OK : E_FAIL;
2584 else
2585 assert(0);
2587 if (handle && hr == S_OK)
2588 pInst->m_Handle = SD3DShaderHandle(handle, m_eSHClass, nSize);
2591 CRY_ASSERT(pInst->m_Handle.m_pShader && pInst->m_Handle.m_pShader->GetHandle(), "Shader creation failed");
2593 if ((m_eSHClass == eHWSC_Vertex) && (!(nFlags & HWSF_PRECACHE)) && !pInst->m_bFallback)
2594 mfUpdateFXVertexFormat(pInst, pSH);
2596 pInst->m_Shader.m_nDataSize = nSize;
2597 if (m_eSHClass == eHWSC_Pixel)
2598 s_nDevicePSDataSize += nSize;
2599 else
2600 s_nDeviceVSDataSize += nSize;
2602 if (pInst->m_Handle.m_pShader->GetHandle())
2604 #if defined(ORBIS_GPU_DEBUGGER_SUPPORT) && !CRY_RENDERER_GNM
2605 char name[1024];
2606 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);
2607 ((CCryDXOrbisShader*)pInst->m_Handle.m_pShader->GetHandle())->RegisterWithGPUDebugger(name);
2608 #endif
2610 // Assign name to Shader for enhanced debugging
2611 #if !defined(RELEASE) && (CRY_PLATFORM_WINDOWS)
2612 char name[1024];
2613 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);
2615 #if CRY_PLATFORM_WINDOWS
2616 #if CRY_RENDERER_DIRECT3D
2617 auto pObject = (ID3D11DeviceChild*)pInst->m_Handle.m_pShader->GetHandle();
2618 SetDebugName(pObject, name);
2619 #elif CRY_RENDERER_VULKAN
2620 auto pObject = reinterpret_cast<NCryVulkan::CShader*>(pInst->m_Handle.m_pShader->GetHandle());
2621 SetDebugName(pObject, name);
2622 #endif
2623 #endif
2624 #endif
2627 return (hr == S_OK);
2630 bool CHWShader_D3D::mfUploadHW(D3DBlob* pShader, SHWSInstance* pInst, CShader* pSH, uint32 nFlags)
2632 bool bResult = true;
2633 if (m_eSHClass == eHWSC_Vertex && !pInst->m_bFallback)
2634 mfUpdateFXVertexFormat(pInst, pSH);
2635 if (pShader)
2637 DWORD* pCode = (DWORD*)pShader->GetBufferPointer();
2638 if (gcpRendD3D->m_cEF.m_nCombinationsProcess >= 0)
2640 pInst->m_Handle.SetFake();
2642 else
2644 bResult = mfUploadHW(pInst, (byte*)pCode, (uint32)pShader->GetBufferSize(), pSH, nFlags);
2645 if (m_eSHClass == eHWSC_Vertex)
2647 size_t nSize = pShader->GetBufferSize();
2648 pInst->m_Shader.m_pShaderData = new byte[nSize];
2649 pInst->m_Shader.m_nDataSize = nSize;
2650 memcpy(pInst->m_Shader.m_pShaderData, pCode, nSize);
2653 if (!bResult)
2655 if (m_eSHClass == eHWSC_Vertex)
2656 Warning("CHWShader_D3D::mfUploadHW: Could not create vertex shader '%s'(0x%" PRIx64 ")\n", GetName(), pInst->m_Ident.m_GLMask);
2657 else if (m_eSHClass == eHWSC_Pixel)
2658 Warning("CHWShader_D3D::mfUploadHW: Could not create pixel shader '%s'(0x%" PRIx64 ")\n", GetName(), pInst->m_Ident.m_GLMask);
2659 else if (m_eSHClass == eHWSC_Geometry)
2660 Warning("CHWShader_D3D::mfUploadHW: Could not create geometry shader '%s'(0x%" PRIx64 ")\n", GetName(), pInst->m_Ident.m_GLMask);
2661 else if (m_eSHClass == eHWSC_Domain)
2662 Warning("CHWShader_D3D::mfUploadHW: Could not create domain shader '%s'(0x%" PRIx64 ")\n", GetName(), pInst->m_Ident.m_GLMask);
2663 else if (m_eSHClass == eHWSC_Hull)
2664 Warning("CHWShader_D3D::mfUploadHW: Could not create hull shader '%s'(0x%" PRIx64 ")\n", GetName(), pInst->m_Ident.m_GLMask);
2665 else if (m_eSHClass == eHWSC_Compute)
2666 Warning("CHWShader_D3D::mfUploadHW: Could not create compute shader '%s'(0x%" PRIx64 ")\n", GetName(), pInst->m_Ident.m_GLMask);
2669 return bResult;
2672 bool CHWShader_D3D::mfActivateCacheItem(CShader* pSH, const SDeviceShaderEntry* cacheEntry, uint32 nFlags)
2674 bool bResult = true;
2676 SHWSInstance* pInst = m_pCurInst;
2678 pInst->m_eClass = (EHWShaderClass)cacheEntry->header.m_Class;
2679 pInst->m_nVertexFormat = cacheEntry->header.m_nVertexFormat;
2680 pInst->m_nInstructions = cacheEntry->header.m_nInstructions;
2681 pInst->m_VStreamMask_Decl = EStreamMasks(cacheEntry->header.m_StreamMask_Decl);
2682 pInst->m_VStreamMask_Stream = EStreamMasks(cacheEntry->header.m_StreamMask_Stream);
2683 #if CRY_RENDERER_VULKAN
2684 pInst->m_VSInputStreams = cacheEntry->m_VSInputStreams;
2685 #endif
2687 pInst->m_pBindVars = cacheEntry->bindVars;
2690 auto handle = cacheEntry->shader;
2691 pInst->m_Handle = SD3DShaderHandle(std::move(handle));
2693 #if CRY_PLATFORM_ORBIS || CRY_PLATFORM_DURANGO || CRY_RENDERER_VULKAN
2694 if (m_eSHClass == eHWSC_Vertex)
2696 D3DBlob* pS = NULL;
2697 D3DCreateBlob(cacheEntry->m_VertexShaderBinarySize, (D3DBlob**)&pS);
2698 DWORD* pBuffer = (DWORD*)pS->GetBufferPointer();
2699 memcpy(pBuffer, cacheEntry->m_pVertexShaderBinary.get(), cacheEntry->m_VertexShaderBinarySize);
2700 mfVertexFormat(pInst, this, pS, nullptr);
2701 SAFE_RELEASE(pS);
2703 #endif
2704 if ((m_eSHClass == eHWSC_Vertex) && (!(nFlags & HWSF_PRECACHE)) && !pInst->m_bFallback)
2705 mfUpdateFXVertexFormat(pInst, pSH);
2708 if (m_eSHClass == eHWSC_Vertex)
2710 pInst->m_Shader.m_pShaderData = cacheEntry->m_pVertexShaderBinary.get();
2711 pInst->m_Shader.m_nDataSize = cacheEntry->m_VertexShaderBinarySize;
2714 mfGatherFXParameters(pInst, pInst->m_pBindVars, this, 0, pSH);
2716 return bResult;
2719 /*CHWShader_D3D::SHWSInstance *g_pInst;
2720 CHWShader_D3D::SHWSInstance g_Inst;
2721 CHWShader_D3D::SHWSInstance *g_pInst0;
2722 CHWShader_D3D::SHWSInstance g_Inst0;
2723 CHWShader_D3D *g_pSH;*/
2725 bool CHWShader_D3D::mfCreateCacheItem(SHWSInstance* pInst, CShader* ef, std::vector<SCGBind>& InstBinds, byte* pData, int nLen, bool bShaderThread)
2727 auto cache = AcquireDiskCache(cacheSource::user);
2728 if (!cache->m_pRes)
2729 return false;
2731 byte* byteData = NULL;
2732 DWORD* dwordData = NULL;
2734 SShaderCacheHeaderItem h;
2735 h.m_nInstBinds = static_cast<byte>(InstBinds.size());
2736 h.m_nInstructions = pInst->m_nInstructions;
2737 h.m_nVertexFormat = pInst->m_nVertexFormat;
2738 h.m_Class = pData ? pInst->m_eClass : 255;
2739 h.m_StreamMask_Decl = pInst->m_VStreamMask_Decl;
2740 h.m_StreamMask_Stream = (byte)pInst->m_VStreamMask_Stream;
2741 int nNewSize = (h.m_nInstBinds) * sizeof(SShaderCacheHeaderItemVar) + nLen;
2742 byte* pNewData = new byte[nNewSize];
2743 byte* pP = pNewData;
2744 pP = mfBindsToCache(pInst, &InstBinds, h.m_nInstBinds, pP);
2745 PREFAST_ASSUME(pData);
2746 memcpy(pP, pData, nLen);
2747 delete[] byteData;
2748 delete[] dwordData;
2749 pP += nLen;
2750 char name[256];
2751 mfGenName(pInst, name, 256, 1);
2752 CCryNameTSCRC nm = CCryNameTSCRC(name);
2753 bool bRes = mfAddCacheItem(cache, &h, pNewData, (int)(pP - pNewData), false, nm);
2754 SAFE_DELETE_ARRAY(pNewData);
2755 if (gRenDev->m_cEF.m_nCombinationsProcess <= 0)
2757 if (bShaderThread && false)
2759 if (pInst->m_pAsync)
2760 pInst->m_pAsync->m_bPendedFlush = true;
2762 cry_strcpy(name, GetName());
2763 char* s = strchr(name, '(');
2764 if (s)
2765 s[0] = 0;
2766 if (!bShaderThread || true)
2768 byte bStore = 1;
2769 if (m_Flags & HWSG_FP_EMULATION)
2770 bStore = 2;
2771 SShaderCombIdent Ident = pInst->m_Ident;
2772 Ident.m_GLMask = m_nMaskGenFX;
2773 gRenDev->m_cEF.mfInsertNewCombination(Ident, pInst->m_eClass, name, 0, NULL, bStore);
2777 return bRes;
2780 //============================================================================
2782 void CHWShader_D3D::mfSaveCGFile(const char* scr, const char* path)
2784 if (CRenderer::CV_r_shadersdebug < 1)
2785 return;
2786 char name[1024];
2787 if (path && path[0])
2789 #if defined(CRY_COMPILER_GCC) || defined(CRY_COMPILER_CLANG)
2790 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);
2791 #else
2792 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);
2793 #endif
2795 else
2797 #if defined(CRY_COMPILER_GCC) || defined(CRY_COMPILER_CLANG)
2798 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);
2799 #else
2800 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);
2801 #endif
2804 FILE* fp;
2806 fp = gEnv->pCryPak->FOpen(name, "w");
2808 if (fp)
2810 size_t len = strlen(scr);
2811 gEnv->pCryPak->FWrite(scr, len, fp);
2812 gEnv->pCryPak->FClose(fp);
2816 void CHWShader_D3D::mfOutputCompilerError(string& strErr, const char* szSrc)
2818 if (CRenderer::CV_r_shadersdebug)
2820 FILE* fp = fxopen("$$err", "w");
2821 if (fp)
2823 fputs(szSrc, fp);
2824 fclose(fp);
2828 string strE = strErr;
2830 size_t newlinePos = strE.find('\n');
2832 while (newlinePos != string::npos)
2834 iLog->LogError("%s", strE.substr(0, newlinePos).c_str());
2835 strE = strE.substr(newlinePos + 1);
2836 newlinePos = strE.find('\n');
2839 if (strE.size())
2840 iLog->LogError("%s", strE.c_str());
2843 SShaderAsyncInfo::~SShaderAsyncInfo()
2846 AUTO_LOCK(g_cAILock);
2847 Unlink();
2849 if (m_pFXShader)
2851 assert(m_pFXShader->GetID() >= 0 && m_pFXShader->GetID() < MAX_REND_SHADERS);
2853 SAFE_RELEASE(m_pFXShader);
2854 SAFE_RELEASE(m_pShader);
2855 SAFE_RELEASE(m_pErrors);
2857 if (D3DShaderReflection* pShaderReflection = static_cast<D3DShaderReflection*>(m_pConstants))
2859 pShaderReflection->Release();
2860 m_pConstants = nullptr;
2864 // Flush pended or processed shaders (main thread task)
2865 void SShaderAsyncInfo::FlushPendingShaders()
2867 //assert (gRenDev->m_pRT->IsRenderThread());
2869 if (!SShaderAsyncInfo::PendingList().m_Next)
2871 SShaderAsyncInfo::PendingList().m_Next = &SShaderAsyncInfo::PendingList();
2872 SShaderAsyncInfo::PendingList().m_Prev = &SShaderAsyncInfo::PendingList();
2873 SShaderAsyncInfo::PendingListT().m_Next = &SShaderAsyncInfo::PendingListT();
2874 SShaderAsyncInfo::PendingListT().m_Prev = &SShaderAsyncInfo::PendingListT();
2877 SShaderAsyncInfo* pAI, * pAINext;
2879 AUTO_LOCK(g_cAILock);
2880 for (pAI = PendingListT().m_Next; pAI != &PendingListT(); pAI = pAINext)
2882 pAINext = pAI->m_Next;
2883 pAI->Unlink();
2884 pAI->Link(&PendingList());
2888 for (pAI = PendingList().m_Next; pAI != &PendingList(); pAI = pAINext)
2890 pAINext = pAI->m_Next;
2892 CHWShader_D3D* pSH = pAI->m_pShader;
2893 if (pSH)
2895 SShaderCombIdent Ident;
2896 Ident.m_GLMask = pSH->m_nMaskGenShader;
2897 Ident.m_LightMask = pAI->m_LightMask;
2898 Ident.m_RTMask = pAI->m_RTMask;
2899 Ident.m_MDMask = pAI->m_MDMask;
2900 Ident.m_MDVMask = pAI->m_MDVMask;
2901 Ident.m_pipelineState.opaque = pAI->m_pipelineState.opaque;
2902 CHWShader_D3D::SHWSInstance* pInst = pSH->mfGetInstance(pAI->m_nHashInstance, Ident);
2903 if (pInst)
2905 if (pInst->m_pAsync != pAI)
2906 CryFatalError("Shader instance async info doesn't match queued async info.");
2907 pSH->mfAsyncCompileReady(pInst);
2912 void CShader::mfFlushPendedShaders()
2914 SShaderAsyncInfo::FlushPendingShaders();
2917 void CHWShader::mfFlushPendedShadersWait(int nMaxAllowed)
2919 if (nMaxAllowed > 0 && SShaderAsyncInfo::s_nPendingAsyncShaders < nMaxAllowed)
2920 return;
2921 if (CRenderer::CV_r_shadersasynccompiling > 0)
2923 if (!gRenDev->IsShaderCacheGenMode())
2925 iLog->Log("Flushing pended shaders...");
2927 Start:
2928 while (true)
2930 if (SShaderAsyncInfo::s_nPendingAsyncShaders <= 0)
2931 break;
2932 int n = (int)iTimer->GetAsyncCurTime();
2933 if (!(n % 2))
2934 iLog->Update();
2935 if (!(n % 8))
2937 SShaderAsyncInfo::FlushPendingShaders();
2939 else
2940 CrySleep(1);
2942 // Compile FXC shaders or next iteration of internal shaders
2943 SShaderAsyncInfo::FlushPendingShaders();
2945 if (SShaderAsyncInfo::s_nPendingAsyncShaders)
2946 goto Start;
2947 if (!gRenDev->IsShaderCacheGenMode())
2949 iLog->Log("Finished flushing pended shaders...");
2954 int CHWShader_D3D::mfAsyncCompileReady(SHWSInstance* pInst)
2956 //SHWSInstance *pInst = m_pCurInst;
2957 //assert(pInst->m_pAsync);
2958 if (!pInst->m_pAsync)
2959 return 0;
2961 gRenDev->m_cEF.m_ShaderCacheStats.m_nNumShaderAsyncCompiles = SShaderAsyncInfo::s_nPendingAsyncShaders;
2963 SShaderAsyncInfo* pAsync = pInst->m_pAsync;
2964 int nFrame = GetCurrentFrameID();
2965 if (pAsync->m_nFrame != nFrame)
2967 pAsync->m_nFrame = nFrame;
2970 std::vector<SCGBind> InstBindVars;
2971 D3DBlob* pShader = NULL;
2972 D3DBlob* pErrorMsgs = NULL;
2973 string strErr;
2974 char nmDst[256];
2975 bool bResult = true;
2976 int nRefCount;
2978 SShaderTechnique* pTech = nullptr;//gRenDev->m_RP.m_pCurTechnique;
2979 CShader* pSH = pAsync->m_pFXShader;
2981 if (pAsync->m_bPending)
2982 return 0;
2984 if (pSH)
2986 if (pSH->m_fMinVisibleDistance < pAsync->m_fMinDistance)
2987 pAsync->m_fMinDistance = pSH->m_fMinVisibleDistance;
2990 mfPrintCompileInfo(pInst);
2992 CryPathString adjustedName;
2993 if (CRenderer::CV_r_logShaders)
2995 mfGetDstFileName(pInst, nmDst, 256, 3);
2996 gEnv->pCryPak->AdjustFileName(nmDst, adjustedName, 0);
2999 if (pAsync->m_pFXShader && pAsync->m_pFXShader->m_HWTechniques.Num())
3000 pTech = pAsync->m_pFXShader->m_HWTechniques[0];
3001 if ((pAsync->m_pErrors && !pAsync->m_Errors.empty()) || !pAsync->m_pDevShader)
3003 if (CRenderer::CV_r_logShaders)
3004 gcpRendD3D->LogShv("Async %d: **Failed to compile 0x%x '%s' shader\n", GetCurrentFrameID(), pInst, adjustedName.c_str());
3005 string Errors = pAsync->m_Errors;
3006 string Text = pAsync->m_Text;
3007 CShader* pFXShader = pAsync->m_pFXShader;
3008 nRefCount = pFXShader ? pFXShader->GetRefCounter() : 0;
3009 nRefCount = min(nRefCount, pAsync->m_pShader ? pAsync->m_pShader->GetRefCounter() : 0);
3010 if (nRefCount <= 1) // Just exit if shader was deleted
3012 pInst->m_pAsync = NULL;
3013 SAFE_DELETE(pAsync);
3014 return -1;
3017 mfOutputCompilerError(Errors, Text.c_str());
3019 Warning("Couldn't compile HW shader '%s'", GetName());
3020 mfSaveCGFile(Text.c_str(), NULL);
3022 bResult = false;
3024 else if (CRenderer::CV_r_logShaders)
3025 gcpRendD3D->LogShv("Async %d: Finished compiling 0x%x '%s' shader\n", GetCurrentFrameID(), pInst, adjustedName.c_str());
3026 pShader = pAsync->m_pDevShader;
3027 pErrorMsgs = pAsync->m_pErrors;
3028 strErr = pAsync->m_Errors;
3029 InstBindVars = pAsync->m_InstBindVars;
3031 if (pAsync->m_bPendedEnv)
3033 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);
3034 assert(bResult == true);
3037 // Load samplers
3038 if (pAsync->m_bPendedSamplers)
3039 mfGatherFXParameters(pInst, pInst->m_pBindVars, this, 2, pAsync->m_pFXShader);
3041 if (pAsync->m_bPendedFlush)
3043 mfFlushCacheFile();
3044 cry_strcpy(nmDst, GetName());
3045 char* s = strchr(nmDst, '(');
3046 if (s) s[0] = '\0';
3047 SShaderCombIdent Ident = pInst->m_Ident;
3048 Ident.m_GLMask = m_nMaskGenFX;
3049 gRenDev->m_cEF.mfInsertNewCombination(Ident, pInst->m_eClass, nmDst, 0);
3052 nRefCount = pAsync->m_pFXShader ? pAsync->m_pFXShader->GetRefCounter() : 0;
3053 nRefCount = min(nRefCount, pAsync->m_pShader ? pAsync->m_pShader->GetRefCounter() : 0);
3054 if (nRefCount <= 1) // Just exit if shader was deleted
3056 pInst->m_pAsync = NULL;
3057 SAFE_DELETE(pAsync);
3058 return -1;
3060 SAFE_DELETE(pInst->m_pAsync);
3063 if (pErrorMsgs && !strErr.empty())
3064 return -1;
3066 bResult &= mfUploadHW(pShader, pInst, pSH, 0);
3067 SAFE_RELEASE(pShader);
3069 if (bResult)
3071 if (pTech)
3072 mfUpdatePreprocessFlags(pTech);
3073 return 1;
3075 return -1;
3078 bool CHWShader_D3D::mfRequestAsync(CShader* pSH, SHWSInstance* pInst, std::vector<SCGBind>& InstBindVars, const char* prog_text, const char* szProfile, const char* szEntry)
3080 #ifdef SHADER_ASYNC_COMPILATION
3081 if (!SShaderAsyncInfo::PendingList().m_Next)
3083 SShaderAsyncInfo::PendingList().m_Next = &SShaderAsyncInfo::PendingList();
3084 SShaderAsyncInfo::PendingList().m_Prev = &SShaderAsyncInfo::PendingList();
3085 SShaderAsyncInfo::PendingListT().m_Next = &SShaderAsyncInfo::PendingListT();
3086 SShaderAsyncInfo::PendingListT().m_Prev = &SShaderAsyncInfo::PendingListT();
3089 pInst->m_pAsync = new SShaderAsyncInfo;
3090 pInst->m_pAsync->m_nFrame = GetCurrentFrameID();
3091 pInst->m_pAsync->m_InstBindVars = InstBindVars;
3092 pInst->m_pAsync->m_pShader = this;
3093 pInst->m_pAsync->m_pShader->AddRef();
3094 pInst->m_pAsync->m_pFXShader = pSH;
3095 pInst->m_pAsync->m_pFXShader->AddRef();
3096 pInst->m_pAsync->m_nCombination = gRenDev->m_cEF.m_nCombinationsProcess;
3097 assert(!stricmp(m_NameSourceFX.c_str(), pInst->m_pAsync->m_pFXShader->m_NameFile.c_str()));
3098 pInst->m_pAsync->m_nHashInstance = pInst->m_Ident.m_nHash;
3099 pInst->m_pAsync->m_RTMask = pInst->m_Ident.m_RTMask;
3100 pInst->m_pAsync->m_LightMask = pInst->m_Ident.m_LightMask;
3101 pInst->m_pAsync->m_MDMask = pInst->m_Ident.m_MDMask;
3102 pInst->m_pAsync->m_MDVMask = pInst->m_Ident.m_MDVMask;
3103 pInst->m_pAsync->m_pipelineState.opaque = pInst->m_Ident.m_pipelineState.opaque;
3104 pInst->m_pAsync->m_eClass = pInst->m_eClass;
3105 pInst->m_pAsync->m_Text = prog_text;
3106 pInst->m_pAsync->m_Name = szEntry;
3107 pInst->m_pAsync->m_Profile = szProfile;
3109 if (pSH)
3111 pInst->m_pAsync->m_fMinDistance = pSH->m_fMinVisibleDistance;
3114 // Generate request line text to store on the shaderlist for next shader cache gen
3116 char szShaderGenName[512];
3117 cry_strcpy(szShaderGenName, GetName());
3118 char* s = strchr(szShaderGenName, '(');
3119 if (s)
3120 s[0] = 0;
3121 string RequestLine;
3122 SShaderCombIdent Ident = pInst->m_Ident;
3123 Ident.m_GLMask = m_nMaskGenFX;
3124 gRenDev->m_cEF.mfInsertNewCombination(Ident, pInst->m_eClass, szShaderGenName, 0, &RequestLine, false);
3126 pInst->m_pAsync->m_RequestLine = RequestLine;
3129 CAsyncShaderTask::InsertPendingShader(pInst->m_pAsync);
3131 if (CRenderer::CV_r_logShaders)
3133 char nameRaw[256];
3134 mfGetDstFileName(pInst, nameRaw, sizeof(nameRaw), 3);
3135 CryPathString nameAdjusted;
3136 gEnv->pCryPak->AdjustFileName(nameRaw, nameAdjusted, 0);
3137 gcpRendD3D->LogShv("Async %d: Requested compiling 0x%x '%s' shader\n", GetCurrentFrameID(), pInst, nameAdjusted.c_str());
3139 #endif
3140 return false;
3143 void CHWShader_D3D::mfSubmitRequestLine(SHWSInstance* pInst, string* pRequestLine)
3145 // Generate request line text.
3146 char szShaderGenName[512];
3147 cry_strcpy(szShaderGenName, GetName());
3148 char* s = strchr(szShaderGenName, '(');
3149 if (s)
3150 s[0] = 0;
3151 string RequestLine;
3152 SShaderCombIdent Ident = pInst->m_Ident;
3153 Ident.m_GLMask = m_nMaskGenFX;
3154 gRenDev->m_cEF.mfInsertNewCombination(Ident, pInst->m_eClass, szShaderGenName, 0, &RequestLine, false);
3156 if (pRequestLine)
3157 *pRequestLine = RequestLine;
3159 if (!CRenderer::CV_r_shaderssubmitrequestline || !CRenderer::CV_r_shadersremotecompiler || pInst->m_bHasSendRequest)
3160 return;
3162 // make sure we only send the request once
3163 pInst->m_bHasSendRequest = true;
3165 #ifdef SHADER_ASYNC_COMPILATION
3166 if (CRenderer::CV_r_shadersasynccompiling && !(m_Flags & HWSG_SYNC))
3168 if (!SShaderAsyncInfo::PendingList().m_Next)
3170 SShaderAsyncInfo::PendingList().m_Next = &SShaderAsyncInfo::PendingList();
3171 SShaderAsyncInfo::PendingList().m_Prev = &SShaderAsyncInfo::PendingList();
3172 SShaderAsyncInfo::PendingListT().m_Next = &SShaderAsyncInfo::PendingListT();
3173 SShaderAsyncInfo::PendingListT().m_Prev = &SShaderAsyncInfo::PendingListT();
3176 SShaderAsyncInfo* pAsync = new SShaderAsyncInfo;
3178 if (pAsync)
3180 pAsync->m_RequestLine = RequestLine;
3181 pAsync->m_Text = "";
3182 pAsync->m_bDeleteAfterRequest = true;
3184 CAsyncShaderTask::InsertPendingShader(pAsync);
3187 else
3188 #endif
3190 NRemoteCompiler::CShaderSrv::Instance().RequestLine(
3191 #if CRY_PLATFORM_ORBIS
3192 "ShaderList_Orbis.txt",
3193 #elif CRY_PLATFORM_DURANGO
3194 "ShaderList_Durango.txt",
3195 #elif CRY_RENDERER_VULKAN
3196 "ShaderList_Vulkan.txt",
3197 #else
3198 "ShaderList_PC.txt",
3199 #endif
3200 RequestLine.c_str());
3204 bool CHWShader_D3D::mfCompileHLSL_Int(CShader* pSH, char* prog_text, D3DBlob** ppShader, void** ppConstantTable, D3DBlob** ppErrorMsgs, string& strErr, std::vector<SCGBind>& InstBindVars)
3206 HRESULT hr = S_OK;
3207 SHWSInstance* pInst = m_pCurInst;
3208 const char* szProfile = mfProfileString(pInst->m_eClass);
3209 const char* pFunCCryName = m_EntryFunc.c_str();
3211 #if CRY_PLATFORM_WINDOWS
3212 bool bRes = true;
3213 #endif
3215 if (CRenderer::CV_r_shadersdebug == 2)
3217 mfSaveCGFile(prog_text, "TestCG");
3220 #if CRY_RENDERER_VULKAN || CRY_RENDERER_GNM
3221 if (pInst->m_Ident.m_pipelineState.opaque == UPipelineState().opaque)
3223 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!",
3224 GetName(), m_pCurInst->m_Ident.m_LightMask, m_pCurInst->m_Ident.m_RTMask, m_pCurInst->m_Ident.m_MDMask,
3225 m_pCurInst->m_Ident.m_MDVMask, m_pCurInst->m_Ident.m_GLMask, m_pCurInst->m_Ident.m_pipelineState.opaque);
3227 return false;
3229 #endif
3231 if (CRenderer::CV_r_shadersasynccompiling && !(m_Flags & HWSG_SYNC))
3233 return mfRequestAsync(pSH, pInst, InstBindVars, prog_text, szProfile, pFunCCryName);
3235 else if (CRenderer::CV_r_shadersremotecompiler)
3237 string sCompiler = gRenDev->m_cEF.mfGetShaderCompileFlags(pInst->m_eClass, pInst->m_Ident.m_pipelineState);
3239 string RequestLine;
3240 mfSubmitRequestLine(pInst, &RequestLine);
3242 std::vector<uint8> Data;
3243 if (NRemoteCompiler::ESOK != NRemoteCompiler::CShaderSrv::Instance().Compile(Data, szProfile, prog_text, pFunCCryName, sCompiler.c_str(), RequestLine.c_str()))
3245 string sErrorText;
3246 sErrorText.reserve(Data.size());
3247 for (uint32 i = 0; i < Data.size(); i++)
3248 sErrorText += Unicode::ConvertSafe<Unicode::eErrorRecovery_FallbackWin1252ThenDiscard, string>(Data[i]); // HLSLcc may return garbage data, need to sanitize.
3249 strErr = sErrorText;
3251 return false;
3254 D3DCreateBlob(Data.size(), (D3DBlob**)ppShader);
3255 D3DBlob* pShader = (D3DBlob*) *ppShader;
3256 DWORD* pBuf = (DWORD*) pShader->GetBufferPointer();
3257 memcpy(pBuf, &Data[0], Data.size());
3259 *ppShader = (D3DBlob*) pShader;
3260 pBuf = (DWORD*)pShader->GetBufferPointer();
3261 size_t nSize = pShader->GetBufferSize();
3263 bool bReflect = true;
3265 #if CRY_PLATFORM_DESKTOP
3266 if (CParserBin::PlatformIsConsole())
3267 bReflect = false;
3268 #endif
3270 if (bReflect)
3272 void* pShaderReflBuf;
3273 hr = D3DReflection(pBuf, nSize, IID_D3DShaderReflection, &pShaderReflBuf);
3274 if (SUCCEEDED(hr))
3276 D3DShaderReflection* pShaderReflection = (D3DShaderReflection*)pShaderReflBuf;
3277 *ppConstantTable = (void*)pShaderReflection;
3279 else
3281 assert(0);
3285 return hr == S_OK;
3287 #if CRY_PLATFORM_WINDOWS
3288 else
3290 static bool s_logOnce_WrongPlatform = false;
3291 #if !defined(_RELEASE)
3292 if (!s_logOnce_WrongPlatform && (CParserBin::m_nPlatform& (SF_D3D11 | SF_D3D12 | SF_DURANGO | SF_VULKAN)) == 0)
3294 s_logOnce_WrongPlatform = true;
3295 iLog->LogError("Trying to build non DX11 shader via internal compiler which is not supported. Please use remote compiler instead!");
3297 #endif
3298 uint32 nFlags = D3D10_SHADER_PACK_MATRIX_ROW_MAJOR | D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY;
3299 if (CRenderer::CV_r_shadersdebug == 3 || CRenderer::CV_r_shadersdebug == 4)
3300 nFlags |= D3D10_SHADER_DEBUG | D3D10_SHADER_SKIP_OPTIMIZATION;
3302 hr = D3DCompile(prog_text, strlen(prog_text), GetName(), NULL, NULL, pFunCCryName, szProfile, nFlags, 0, (ID3DBlob**) ppShader, (ID3DBlob**) ppErrorMsgs);
3303 if (FAILED(hr) || !*ppShader)
3305 if (ppErrorMsgs && *ppErrorMsgs)
3307 const char* err = (const char*)ppErrorMsgs[0]->GetBufferPointer();
3308 strErr += err;
3310 else
3312 strErr += "D3DXCompileShader failed";
3314 bRes = false;
3316 else
3318 void* pShaderReflBuf;
3319 UINT* pData = (UINT*)ppShader[0]->GetBufferPointer();
3320 UINT nSize = (uint32)ppShader[0]->GetBufferSize();
3321 hr = D3DReflection(pData, nSize, IID_D3DShaderReflection, &pShaderReflBuf);
3322 if (SUCCEEDED(hr))
3324 D3DShaderReflection* pShaderReflection = (D3DShaderReflection*)pShaderReflBuf;
3325 *ppConstantTable = (void*)pShaderReflection;
3327 else
3329 assert(0);
3332 return bRes;
3334 #endif // #if CRY_PLATFORM_WINDOWS || CRY_PLATFORM_DURANGO
3336 return false;
3339 D3DBlob* CHWShader_D3D::mfCompileHLSL(CShader* pSH, char* prog_text, void** ppConstantTable, D3DBlob** ppErrorMsgs, uint32 nFlags, std::vector<SCGBind>& InstBindVars)
3341 // CRY_PROFILE_FUNCTION(PROFILE_LOADING_ONLY)(iSystem);
3343 // Test adding source text to context
3344 string strErr;
3345 D3DBlob* pCode = NULL;
3347 if (!prog_text)
3349 assert(0);
3350 return NULL;
3352 if (!CRenderer::CV_r_shadersAllowCompilation)
3353 return NULL;
3355 mfCompileHLSL_Int(pSH, prog_text, &pCode, ppConstantTable, ppErrorMsgs, strErr, InstBindVars);
3357 if (!pCode)
3359 if (CRenderer::CV_r_shadersasynccompiling)
3360 return NULL;
3361 if (!pCode)
3364 mfOutputCompilerError(strErr, prog_text);
3366 Warning("Couldn't compile HW shader '%s'", GetName());
3367 mfSaveCGFile(prog_text, NULL);
3372 return pCode;
3375 void CHWShader_D3D::mfPrepareShaderDebugInfo(SHWSInstance* pInst, const char* szAsm, std::vector<SCGBind>& InstBindVars, void* pConstantTable)
3377 if (szAsm)
3379 char* szInst = strstr((char*)szAsm, "pproximately ");
3380 if (szInst)
3381 pInst->m_nInstructions = atoi(&szInst[13]);
3384 if (CParserBin::m_nPlatform & (SF_D3D11 | SF_D3D12 | SF_DURANGO))
3386 D3DShaderReflection* pShaderReflection = (D3DShaderReflection*)pConstantTable;
3388 if (pShaderReflection)
3390 D3D_SHADER_DESC Desc;
3391 pShaderReflection->GetDesc(&Desc);
3393 pInst->m_nInstructions = Desc.InstructionCount;
3394 pInst->m_nTempRegs = Desc.TempRegisterCount;
3398 if (CRenderer::CV_r_shadersdebug)
3400 char nmdst[256];
3401 mfGetDstFileName(pInst, nmdst, 256, 4);
3403 string szName;
3404 FILE* statusdst;
3407 szName = gRenDev->m_cEF.m_szUserPath + string(nmdst) + string(".fxca");
3408 statusdst = gEnv->pCryPak->FOpen(szName.c_str(), "wb");
3411 if (statusdst)
3413 gEnv->pCryPak->FPrintf(statusdst, "\n// %s %s\n\n", "%STARTSHADER", mfProfileString(pInst->m_eClass));
3414 if (m_eSHClass == eHWSC_Vertex)
3416 for (uint32 i = 0; i < (uint32)InstBindVars.size(); i++)
3418 SCGBind* pBind = &InstBindVars[i];
3419 gEnv->pCryPak->FPrintf(statusdst, "// %s %s %d %d\n", "%%", pBind->m_Name.c_str(), pBind->m_nParameters, pBind->m_dwBind);
3422 gEnv->pCryPak->FPrintf(statusdst, "%s", szAsm);
3423 gEnv->pCryPak->FPrintf(statusdst, "\n// %s\n", "%ENDSHADER");
3424 gEnv->pCryPak->FClose(statusdst);
3426 pInst->m_Handle = {};
3430 void CHWShader_D3D::mfPrintCompileInfo(SHWSInstance* pInst)
3432 int nConsts = 0;
3433 int nParams = pInst->m_pBindVars.size();
3434 for (int i = 0; i < nParams; i++)
3436 SCGBind* pB = &pInst->m_pBindVars[i];
3437 nConsts += pB->m_nParameters;
3440 char szGenName[512];
3441 cry_strcpy(szGenName, GetName());
3442 char* s = strchr(szGenName, '(');
3443 if (s)
3444 s[0] = 0;
3445 if (CRenderer::CV_r_shadersdebug == 2)
3447 string pName;
3448 SShaderCombIdent Ident(m_nMaskGenFX, pInst->m_Ident);
3449 gRenDev->m_cEF.mfInsertNewCombination(Ident, pInst->m_eClass, szGenName, 0, &pName, false);
3450 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);
3451 int nSize = strlen(szGenName);
3452 mfGenName(pInst, &szGenName[nSize], 512 - nSize, 1);
3453 CryLog(" --- Cache entry: %s", szGenName);
3455 else
3457 int nSize = strlen(szGenName);
3458 mfGenName(pInst, &szGenName[nSize], 512 - nSize, 1);
3459 CryLog(" Compile %s (%d instructions, %d tempregs, %d/%d constants) ... ", szGenName, pInst->m_nInstructions, pInst->m_nTempRegs, nParams, nConsts);
3462 if (gRenDev->m_cEF.m_bActivated && CRenderer::CV_r_shadersdebug > 0)
3463 CryLog(
3464 " Shader %s"
3465 #if defined(CRY_COMPILER_GCC) || defined(CRY_COMPILER_CLANG)
3466 "(%llx)"
3467 #else
3468 "(%I64x)"
3469 #endif
3470 "(%x)(%x)(%x)(%llx)(%s) wasn't compiled before preactivating phase",
3471 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));
3474 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)
3476 // Create asm (.fxca) cache file
3477 assert(pInst);
3478 if (!pInst)
3479 return false;
3481 CSpinLock lock;
3483 if (pInst->m_pBindVars.size())
3484 return true;
3486 if (pShader && (nCombination < 0))
3488 D3DBlob* pAsm = NULL;
3489 D3DBlob* pSrc = (D3DBlob*)pShader;
3490 UINT* pBuf = (UINT*)pSrc->GetBufferPointer();
3491 D3DDisassemble(pBuf, pSrc->GetBufferSize(), 0, NULL, &pAsm);
3492 if (pAsm)
3494 char* szAsm = (char*)pAsm->GetBufferPointer();
3495 pSH->mfPrepareShaderDebugInfo(pInst, szAsm, InstBindVars, pConstantTable);
3497 SAFE_RELEASE(pAsm);
3499 //assert(!pInst->m_pBindVars);
3501 if (pShader)
3503 bool bVF = pSH->m_eSHClass == eHWSC_Vertex;
3504 #if CRY_PLATFORM_DESKTOP
3505 if (CParserBin::PlatformIsConsole())
3506 bVF = false;
3507 #endif
3508 if (bVF)
3509 mfVertexFormat(pInst, pSH, pShader, pConstantTable);
3510 if (pConstantTable)
3511 mfCreateBinds(pInst->m_pBindVars, pConstantTable, (std::size_t)pShader->GetBufferSize());
3513 int nConsts = 0;
3514 int nParams = pInst->m_pBindVars.size();
3515 for (int i = 0; i < nParams; i++)
3517 SCGBind* pB = &pInst->m_pBindVars[i];
3518 nConsts += pB->m_nParameters;
3520 if (gRenDev->m_cEF.m_nCombinationsProcess >= 0)
3522 if (!CParserBin::m_nPlatform)
3524 CryLog("%d: Compile %s %s (%d out of %d) - (%d/%d constants) ... ", nThread,
3525 mfProfileString(pInst->m_eClass), pSH->GetName(), nCombination, gRenDev->m_cEF.m_nCombinationsProcessOverall,
3526 nParams, nConsts);
3528 else
3530 CryLog("%d: Compile %s %s (%d out of %d) ... ", nThread,
3531 mfProfileString(pInst->m_eClass), pSH->GetName(), nCombination, gRenDev->m_cEF.m_nCombinationsProcessOverall);
3535 if(!gRenDev->IsShaderCacheGenMode())
3536 mfGatherFXParameters(pInst, pInst->m_pBindVars, pSH, bShaderThread ? 1 : 0, pFXShader);
3538 if (pShader)
3539 pSH->mfCreateCacheItem(pInst, pFXShader, InstBindVars, (byte*)pShader->GetBufferPointer(), (uint32)pShader->GetBufferSize(), bShaderThread);
3540 else
3541 pSH->mfCreateCacheItem(pInst, pFXShader, InstBindVars, NULL, 0, bShaderThread);
3543 SAFE_RELEASE(pErrorMsgs);
3544 if (D3DShaderReflection* pShaderReflection = (D3DShaderReflection*)pConstantTable)
3546 pShaderReflection->Release();
3547 pConstantTable = nullptr;
3550 return true;
3553 // Compile pixel/vertex shader for the current instance properties
3554 bool CHWShader_D3D::mfActivate(CShader* pSH, uint32 nFlags)
3556 PROFILE_FRAME(Shader_HWShaderActivate);
3558 bool bResult = true;
3559 SHWSInstance* pInst = m_pCurInst;
3561 mfLogShaderRequest(pInst);
3563 if (mfIsValid(pInst, true) == ED3DShError_NotCompiled)
3565 char name[128];
3566 mfGenName(pInst, name, 128, 1);
3567 pInst->m_DeviceObjectID = CCryNameTSCRC{ name }.get();
3568 const auto devCacheKey = static_cast<SHWShaderCache::deviceShaderCacheKey>(pInst->m_DeviceObjectID);
3570 const SDeviceShaderEntry* entry = nullptr;
3572 // Try to find in cache
3573 auto& devCache = GetDevCache();
3574 auto it = devCache.find(devCacheKey);
3575 if (it == devCache.end())
3577 // Read from disk cache and store in cache
3578 std::vector<cacheSource> cacheTypes = { cacheSource::readonly };
3579 if (CRendererCVars::CV_r_shadersAllowCompilation)
3580 cacheTypes = { cacheSource::user, cacheSource::readonly };
3581 if (CRendererCVars::CV_r_shadersediting || gRenDev->IsShaderCacheGenMode())
3582 cacheTypes = { cacheSource::user };
3584 for (const auto& cacheType : cacheTypes)
3586 auto cache = QueryDiskCache(cacheType);
3587 auto newEntry = mfGetCacheItem(pSH, name, cache, nFlags);
3588 if (newEntry)
3590 CryLog("CHWShader_D3D::mfActivate(): Shader '%s' not found in device cache but found in disk cache.", m_Name.c_str());
3592 // Store in cache
3593 SHWShaderCache::deviceShaderCacheValue v;
3594 v.emplace<SDeviceShaderEntry>(std::move(newEntry));
3595 auto insertResult = devCache.emplace(
3596 std::piecewise_construct,
3597 std::forward_as_tuple(devCacheKey),
3598 std::forward_as_tuple(std::move(v)));
3599 entry = &stl::get<SDeviceShaderEntry>(insertResult.first->second);
3601 break;
3605 else
3607 const SHWShaderCache::deviceShaderCacheValue& cacheValue = it->second;
3608 entry = stl::holds_alternative<SDeviceShaderEntry>(cacheValue) ?
3609 &stl::get<SDeviceShaderEntry>(cacheValue) :
3610 stl::get<const SDeviceShaderEntry*>(cacheValue);
3613 if (entry)
3615 if (gRenDev->m_cEF.m_nCombinationsProcess >= 0)
3616 return true;
3618 if (mfActivateCacheItem(pSH, entry, nFlags))
3619 return (pInst->m_Handle.m_pShader != nullptr);
3621 if ((nFlags & HWSF_PRECACHE) == 0)
3622 return false;
3625 TArray<char> newScr;
3627 if (nFlags & HWSF_PRECACHE)
3628 gRenDev->m_cEF.m_nCombinationsCompiled++;
3630 D3DBlob* pShader = NULL;
3631 void* pConstantTable = NULL;
3632 D3DBlob* pErrorMsgs = NULL;
3633 std::vector<SCGBind> InstBindVars;
3634 m_Flags |= HWSG_WASGENERATED;
3636 bool bScriptSuccess = false;
3638 if (CRenderer::CV_r_shadersAllowCompilation)
3640 // MemReplay shows that 16kb should be enough memory to hold the script without having to reallocate
3641 newScr.reserve(16 * 1024);
3642 bScriptSuccess = mfGenerateScript(pSH, pInst, InstBindVars, nFlags, newScr);
3643 ASSERT_IN_SHADER(bScriptSuccess);
3646 if (!pInst->m_bAsyncActivating)
3648 // report miss in global cache to log and/or callback
3649 mfLogShaderCacheMiss(pInst);
3651 // still sumit the request line when no compiling to be sure that the shadercompiler will
3652 // compile it in the next build
3653 if (!CRenderer::CV_r_shadersAllowCompilation)
3654 mfSubmitRequestLine(pInst);
3657 if (!bScriptSuccess)
3659 if (!pInst->m_bAsyncActivating)
3661 #if defined(CRY_COMPILER_GCC) || defined(CRY_COMPILER_CLANG)
3662 Warning("Warning: Shader %s(%llx)(%x)(%x)(%x)(%llx)(%s) is not existing in the cache\n",
3663 #else
3664 Warning("Warning: Shader %s(%I64x)(%x)(%x)(%x)(%llx)(%s) is not existing in the cache\n",
3665 #endif
3666 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));
3668 return false;
3672 PROFILE_FRAME(Shader_CompileHLSL);
3673 pShader = mfCompileHLSL(pSH, newScr.Data(), &pConstantTable, &pErrorMsgs, nFlags, InstBindVars);
3676 gRenDev->m_cEF.m_ShaderCacheStats.m_nNumShaderAsyncCompiles = SShaderAsyncInfo::s_nPendingAsyncShaders;
3678 if (!pShader)
3680 if (!CRenderer::CV_r_shadersAllowCompilation || pInst->IsAsyncCompiling())
3681 return false;
3683 bResult = mfCreateShaderEnv(0, pInst, pShader, pConstantTable, pErrorMsgs, InstBindVars, this, false, pSH, gRenDev->m_cEF.m_nCombinationsProcess, newScr.Data());
3684 bResult &= mfUploadHW(pShader, pInst, pSH, nFlags);
3685 SAFE_RELEASE(pShader);
3686 SAFE_RELEASE(pErrorMsgs);
3687 if (D3DShaderReflection* pShaderReflection = static_cast<D3DShaderReflection*>(pConstantTable))
3689 pShaderReflection->Release();
3690 pConstantTable = nullptr;
3694 ED3DShError shResult = mfIsValid(pInst, true);
3695 bool bSuccess = (shResult == ED3DShError_Ok) || (shResult == ED3DShError_Fake);
3697 return bSuccess;
3700 //////////////////////////////////////////////////////////////////////////
3702 #ifdef SHADER_ASYNC_COMPILATION
3704 #pragma warning(disable: 4355)// warning C4355: 'this' : used in base member initializer list
3706 CAsyncShaderTask::CAsyncShaderTask()
3707 : m_nThread(0)
3708 , m_nThreadFXC(0)
3709 , m_thread(this)
3713 void CAsyncShaderTask::InsertPendingShader(SShaderAsyncInfo* pAsync)
3715 AUTO_LOCK(g_cAILock);
3716 pAsync->Link(&BuildList());
3717 CryInterlockedIncrement(&SShaderAsyncInfo::s_nPendingAsyncShaders);
3720 void CAsyncShaderTask::FlushPendingShaders()
3722 SShaderAsyncInfo* pAI, * pAI2, * pAINext;
3723 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
3724 if (BuildList().m_Prev == &BuildList() && BuildList().m_Next == &BuildList())
3725 return; // the build list is empty, might need to do some assert here
3727 AUTO_LOCK(g_cAILock);
3728 for (pAI = BuildList().m_Prev; pAI != &BuildList(); pAI = pAINext)
3730 pAINext = pAI->m_Prev;
3731 pAI->Unlink();
3732 pAI->Link(&m_flush_list);
3736 // Sorting by distance
3737 if (gRenDev->m_cEF.m_nCombinationsProcess < 0)
3738 for (pAI = m_flush_list.m_Next; pAI != &m_flush_list; pAI = pAI->m_Next)
3740 assert(pAI);
3741 PREFAST_ASSUME(pAI);
3742 pAINext = NULL;
3743 int nFrame = pAI->m_nFrame;
3744 float fDist = pAI->m_fMinDistance;
3745 for (pAI2 = pAI->m_Next; pAI2 != &m_flush_list; pAI2 = pAI2->m_Next)
3747 if (pAI2->m_nFrame < nFrame)
3748 continue;
3749 if (pAI2->m_nFrame > nFrame || pAI2->m_fMinDistance < fDist)
3751 pAINext = pAI2;
3752 nFrame = pAI2->m_nFrame;
3753 fDist = pAI2->m_fMinDistance;
3756 if (pAINext)
3758 assert(pAI != pAINext);
3759 SShaderAsyncInfo* pAIP0 = pAI->m_Prev;
3760 SShaderAsyncInfo* pAIP1 = pAINext->m_Prev == pAI ? pAINext : pAINext->m_Prev;
3762 pAI->m_Next->m_Prev = pAI->m_Prev;
3763 pAI->m_Prev->m_Next = pAI->m_Next;
3764 pAI->m_Next = pAIP1->m_Next;
3765 pAIP1->m_Next->m_Prev = pAI;
3766 pAIP1->m_Next = pAI;
3767 pAI->m_Prev = pAIP1;
3769 pAI = pAINext;
3771 pAI->m_Next->m_Prev = pAI->m_Prev;
3772 pAI->m_Prev->m_Next = pAI->m_Next;
3773 pAI->m_Next = pAIP0->m_Next;
3774 pAIP0->m_Next->m_Prev = pAI;
3775 pAIP0->m_Next = pAI;
3776 pAI->m_Prev = pAIP0;
3780 for (pAI = m_flush_list.m_Next; pAI != &m_flush_list; pAI = pAINext)
3782 pAINext = pAI->m_Next;
3783 assert(pAI->m_bPending);
3784 SubmitAsyncRequestLine(pAI);
3785 if (pAI->m_Text.length() > 0)
3786 CompileAsyncShader(pAI);
3788 CryInterlockedDecrement(&SShaderAsyncInfo::s_nPendingAsyncShaders);
3790 AUTO_LOCK(g_cAILock);
3792 pAI->Unlink();
3793 pAI->m_bPending = 0;
3794 pAI->Link(&SShaderAsyncInfo::PendingListT());
3797 if (pAI->m_bDeleteAfterRequest)
3799 SAFE_DELETE(pAI);
3804 bool CAsyncShaderTask::PostCompile(SShaderAsyncInfo* pAsync)
3806 bool bResult = true;
3807 /*if (pAsync->m_nCombination < 0 && false)
3809 CHWShader_D3D *pSH = pAsync->m_pShader;
3810 CHWShader_D3D::SHWSInstance *pInst = pSH->mfGetInstance(pAsync->m_nOwner, pSH->m_nMaskGenShader);
3811 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);
3812 assert(bResult == true);
3814 else*/
3816 pAsync->m_nThread = m_nThread;
3817 pAsync->m_bPendedEnv = true;
3819 return bResult;
3822 void CAsyncShaderTask::SubmitAsyncRequestLine(SShaderAsyncInfo* pAsync)
3824 if (CRenderer::CV_r_shadersremotecompiler)
3826 if (!pAsync->m_shaderList.empty())
3828 NRemoteCompiler::CShaderSrv::Instance().RequestLine(pAsync->m_shaderList.c_str(), pAsync->m_RequestLine.c_str());
3830 else
3832 NRemoteCompiler::CShaderSrv::Instance().RequestLine(
3833 #if CRY_PLATFORM_ORBIS
3834 "ShaderList_Orbis.txt",
3835 #elif CRY_PLATFORM_DURANGO
3836 "ShaderList_Durango.txt",
3837 #elif CRY_RENDERER_VULKAN
3838 "ShaderList_Vulkan.txt",
3839 #else
3840 "ShaderList_PC.txt",
3841 #endif
3842 pAsync->m_RequestLine.c_str());
3847 bool CAsyncShaderTask::CompileAsyncShader(SShaderAsyncInfo* pAsync)
3849 bool bResult = true;
3850 if (CRenderer::CV_r_shadersremotecompiler)
3852 string sCompiler = gRenDev->m_cEF.mfGetShaderCompileFlags(pAsync->m_eClass, pAsync->m_pipelineState);
3854 std::vector<uint8> Data;
3855 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()))
3858 D3DCreateBlob(sizeof("D3DXCompileShader failed"), (D3DBlob**)&pAsync->m_pErrors);
3859 DWORD* pBuf = (DWORD*) pAsync->m_pErrors->GetBufferPointer();
3860 memcpy(pBuf, "D3DXCompileShader failed", sizeof("D3DXCompileShader failed"));
3862 string sErrorText;
3864 if (!Data.empty())
3866 sErrorText.reserve(Data.size());
3867 for (uint32 i = 0; i < Data.size(); i++)
3868 sErrorText += Data[i];
3870 else
3872 sErrorText.assign("Unknown Error");
3875 pAsync->m_Errors += sErrorText;
3877 return false;
3880 HRESULT hr = S_OK;
3881 D3DCreateBlob(Data.size(), (D3DBlob**) &pAsync->m_pDevShader);
3882 D3DBlob* pShader = (D3DBlob*)*&pAsync->m_pDevShader;
3883 DWORD* pBuf = (DWORD*)pShader->GetBufferPointer();
3884 memcpy(pBuf, &Data[0], Data.size());
3886 pAsync->m_pDevShader = (D3DBlob*)pShader;
3887 pBuf = (DWORD*)pShader->GetBufferPointer();
3888 size_t nSize = pShader->GetBufferSize();
3890 bool bReflect = true;
3892 #if CRY_PLATFORM_DESKTOP
3893 if (CParserBin::PlatformIsConsole())
3894 bReflect = false;
3895 #endif
3896 if (bReflect)
3898 D3DShaderReflection* pShaderReflection;
3899 hr = D3DReflection(pBuf, nSize, IID_D3DShaderReflection, (void**)&pShaderReflection);
3900 if (SUCCEEDED(hr))
3902 pAsync->m_pConstants = (void*)pShaderReflection;
3906 if (SUCCEEDED(hr))
3908 bResult = PostCompile(pAsync);
3910 else
3912 pAsync->m_pDevShader = 0;
3913 assert(0);
3916 #if CRY_PLATFORM_WINDOWS
3917 else
3919 static bool s_logOnce_WrongPlatform = false;
3920 #if !defined(_RELEASE)
3921 if (!s_logOnce_WrongPlatform && (CParserBin::m_nPlatform& (SF_D3D11 | SF_D3D12 | SF_DURANGO | SF_VULKAN)) == 0)
3923 s_logOnce_WrongPlatform = true;
3924 iLog->LogError("Trying to build non DX11 shader via internal compiler which is not supported. Please use remote compiler instead!");
3926 #endif
3927 uint32 nFlags = D3D10_SHADER_PACK_MATRIX_ROW_MAJOR | D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY;
3928 if (CRenderer::CV_r_shadersdebug == 3 || CRenderer::CV_r_shadersdebug == 4)
3929 nFlags |= D3D10_SHADER_DEBUG | D3D10_SHADER_SKIP_OPTIMIZATION;
3931 const char* Name = pAsync->m_pShader ? pAsync->m_pShader->GetName() : "Unknown";
3932 HRESULT hr = S_OK;
3933 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);
3934 if (FAILED(hr) || !pAsync->m_pDevShader)
3936 if (pAsync->m_pErrors)
3938 const char* err = (const char*)pAsync->m_pErrors->GetBufferPointer();
3939 pAsync->m_Errors += err;
3941 else
3943 pAsync->m_Errors += "D3DXCompileShader failed";
3945 bResult = false;
3947 else
3949 D3DShaderReflection* pShaderReflection;
3950 UINT* pData = (UINT*)pAsync->m_pDevShader->GetBufferPointer();
3951 size_t nSize = pAsync->m_pDevShader->GetBufferSize();
3952 hr = D3DReflection(pData, nSize, IID_D3DShaderReflection, (void**)&pShaderReflection);
3953 if (SUCCEEDED(hr))
3955 pAsync->m_pConstants = (void*)pShaderReflection;
3956 bResult = PostCompile(pAsync);
3958 else
3960 assert(0);
3964 #endif // #if CRY_PLATFORM_WINDOWS
3965 return bResult;
3968 void CAsyncShaderTask::CShaderThread::ThreadEntry()
3970 while (!m_quit)
3972 m_task->FlushPendingShaders();
3973 if (!CRenderer::CV_r_shadersasynccompiling)
3974 CrySleep(250);
3975 else
3976 CrySleep(25);
3980 #endif
3982 //===============================================================================================
3983 // Export/Import
3985 #ifdef SHADERS_SERIALIZING
3987 bool SFXParam::Export(SShaderSerializeContext& SC)
3989 bool bRes = true;
3991 SSFXParam PR;
3992 PR.m_nsName = SC.AddString(m_Name.c_str());
3993 PR.m_nsAnnotations = SC.AddString(m_Annotations.c_str());
3994 PR.m_nsSemantic = SC.AddString(m_Semantic.c_str());
3995 PR.m_nsValues = SC.AddString(m_Values.c_str());
3997 PR.m_eType = m_eType;
3998 PR.m_nCB = m_nCB;
3999 PR.m_nComps = m_nComps;
4000 PR.m_nFlags = m_nFlags;
4001 PR.m_mask = m_mask;
4002 PR.m_nParameters = m_nParameters;
4003 PR.m_nRegister[0] = m_nRegister[0];
4004 PR.m_nRegister[1] = m_nRegister[1];
4005 PR.m_nRegister[2] = m_nRegister[2];
4007 SC.FXParams.push_back(PR);
4009 return bRes;
4011 bool SFXParam::Import(SShaderSerializeContext& SC, SSFXParam* pPR)
4013 bool bRes = true;
4015 m_Name = sString(pPR->m_nsName, SC.Strings);
4016 m_Annotations = sString(pPR->m_nsAnnotations, SC.Strings);
4017 m_Semantic = sString(pPR->m_nsSemantic, SC.Strings);
4018 m_Values = sString(pPR->m_nsValues, SC.Strings);
4020 m_eType = pPR->m_eType;
4021 m_nCB = pPR->m_nCB;
4022 m_nComps = pPR->m_nComps;
4023 m_nFlags = pPR->m_nFlags;
4024 m_mask = pPR->m_mask;
4025 m_nParameters = pPR->m_nParameters;
4026 m_nRegister[0] = pPR->m_nRegister[0];
4027 m_nRegister[1] = pPR->m_nRegister[1];
4028 m_nRegister[2] = pPR->m_nRegister[2];
4030 return bRes;
4033 bool SFXSampler::Export(SShaderSerializeContext& SC)
4035 bool bRes = true;
4037 SSFXSampler PR;
4038 PR.m_nsName = SC.AddString(m_Name.c_str());
4039 PR.m_nsAnnotations = SC.AddString(m_Annotations.c_str());
4040 PR.m_nsSemantic = SC.AddString(m_Semantic.c_str());
4041 PR.m_nsValues = SC.AddString(m_Values.c_str());
4043 PR.m_eType = m_eType;
4044 PR.m_nArray = m_nArray;
4045 PR.m_nFlags = m_nFlags;
4046 PR.m_nRegister[0] = m_nRegister[0];
4047 PR.m_nRegister[1] = m_nRegister[1];
4048 PR.m_nRegister[2] = m_nRegister[2];
4050 SC.FXSamplers.push_back(PR);
4052 return bRes;
4054 bool SFXSampler::Import(SShaderSerializeContext& SC, SSFXSampler* pPR)
4056 bool bRes = true;
4058 m_Name = sString(pPR->m_nsName, SC.Strings);
4059 m_Annotations = sString(pPR->m_nsAnnotations, SC.Strings);
4060 m_Semantic = sString(pPR->m_nsSemantic, SC.Strings);
4061 m_Values = sString(pPR->m_nsValues, SC.Strings);
4063 m_eType = pPR->m_eType;
4064 m_nArray = pPR->m_nArray;
4065 m_nFlags = pPR->m_nFlags;
4066 m_nRegister[0] = pPR->m_nRegister[0];
4067 m_nRegister[1] = pPR->m_nRegister[1];
4068 m_nRegister[2] = pPR->m_nRegister[2];
4070 return bRes;
4073 bool SFXTexture::Export(SShaderSerializeContext& SC)
4075 bool bRes = true;
4077 SSFXTexture PR;
4078 PR.m_nsName = SC.AddString(m_Name.c_str());
4079 PR.m_nsAnnotations = SC.AddString(m_Annotations.c_str());
4080 PR.m_nsSemantic = SC.AddString(m_Semantic.c_str());
4081 PR.m_nsValues = SC.AddString(m_Values.c_str());
4083 PR.m_nsNameTexture = SC.AddString(m_szTexture.c_str());
4084 PR.m_bSRGBLookup = m_bSRGBLookup;
4085 PR.m_eType = m_eType;
4086 PR.m_nArray = m_nArray;
4087 PR.m_nFlags = m_nFlags;
4088 PR.m_nRegister[0] = m_nRegister[0];
4089 PR.m_nRegister[1] = m_nRegister[1];
4090 PR.m_nRegister[2] = m_nRegister[2];
4092 SC.FXTextures.push_back(PR);
4094 return bRes;
4096 bool SFXTexture::Import(SShaderSerializeContext& SC, SSFXTexture* pPR)
4098 bool bRes = true;
4100 m_Name = sString(pPR->m_nsName, SC.Strings);
4101 m_Annotations = sString(pPR->m_nsAnnotations, SC.Strings);
4102 m_Semantic = sString(pPR->m_nsSemantic, SC.Strings);
4103 m_Values = sString(pPR->m_nsValues, SC.Strings);
4105 m_szTexture = sString(pPR->m_nsNameTexture, SC.Strings);
4106 m_bSRGBLookup = pPR->m_bSRGBLookup;
4107 m_eType = pPR->m_eType;
4108 m_nArray = pPR->m_nArray;
4109 m_nFlags = pPR->m_nFlags;
4110 m_nRegister[0] = pPR->m_nRegister[0];
4111 m_nRegister[1] = pPR->m_nRegister[1];
4112 m_nRegister[2] = pPR->m_nRegister[2];
4114 return bRes;
4117 bool CHWShader_D3D::ExportSamplers(SCHWShader& SHW, SShaderSerializeContext& SC)
4119 bool bRes = true;
4121 //Samplers no longer stored here
4122 #if 0
4123 int i;
4124 SHW.m_nSamplers = m_Samplers.size();
4125 for (i = 0; i < m_Samplers.size(); i++)
4127 STexSampler& TS = m_Samplers[i];
4128 bRes &= TS.Export(SC);
4130 #endif
4132 return bRes;
4134 bool CHWShader::ImportSamplers(SShaderSerializeContext& SC, SCHWShader* pSHW, byte*& pData, std::vector<STexSamplerRT>& Samplers)
4136 bool bRes = true;
4138 //Samplers no longer stored here
4139 #if 0
4140 int i;
4142 for (i = 0; i < pSHW->m_nSamplers; i++)
4144 STexSamplerRT TS;
4145 bRes &= TS.Import(SC, pData);
4146 if (bRes)
4147 Samplers.push_back(TS);
4149 #endif
4150 return bRes;
4153 bool CHWShader_D3D::ExportParams(SCHWShader& SHW, SShaderSerializeContext& SC)
4155 bool bRes = true;
4157 //params no longer here
4158 #if 0
4159 int i;
4160 SHW.m_nParams = m_Params.size();
4161 for (i = 0; i < m_Params.size(); i++)
4163 SFXParam& PR = m_Params[i];
4164 bRes &= PR.Export(SC);
4166 #else
4167 SHW.m_nParams = 0;
4168 #endif
4170 return bRes;
4172 bool CHWShader::ImportParams(SShaderSerializeContext& SC, SCHWShader* pSHW, byte*& pData, std::vector<SFXParam>& Params)
4174 bool bRes = true;
4176 //params no longer here
4177 #if 0
4178 uint32 i;
4180 for (i = 0; i < pSHW->m_nParams; i++)
4182 SFXParam PR;
4183 bRes &= PR.Import(SC, pData);
4184 if (bRes)
4185 Params.push_back(PR);
4187 #endif
4188 return bRes;
4191 bool CHWShader_D3D::Export(CShader* pSH, SShaderSerializeContext& SC)
4193 bool bRes = true;
4195 SCHWShader SHW;
4197 char str[256];
4198 cry_strcpy(str, GetName());
4199 char* c = strchr(str, '(');
4200 if (c)
4201 c[0] = 0;
4203 SHW.m_nsName = SC.AddString(str);
4204 SHW.m_nsNameSourceFX = SC.AddString(m_NameSourceFX.c_str());
4205 SHW.m_nsEntryFunc = SC.AddString(m_EntryFunc.c_str());
4207 SHW.m_eSHClass = m_eSHClass;
4208 SHW.m_dwShaderType = m_dwShaderType;
4209 SHW.m_nMaskGenFX = m_nMaskGenFX;
4210 SHW.m_nMaskGenShader = m_nMaskGenShader;
4211 SHW.m_nMaskOr_RT = m_nMaskOr_RT;
4212 SHW.m_nMaskAnd_RT = m_nMaskAnd_RT;
4213 SHW.m_Flags = m_Flags;
4215 FXShaderToken Table;
4216 TArray<uint32_t> SHData;
4218 // No longer export any token data, slow and bloated!
4219 const bool bOutputTokens = false;
4221 if (bOutputTokens)
4222 mfGetCacheTokenMap(Table, SHData);
4223 else
4224 SHData = m_TokenData;
4226 if (bOutputTokens && !Table.size())
4228 assert(0);
4229 return false;
4232 SHW.m_nTokens = bOutputTokens ? SHData.size() : 0;
4233 SHW.m_nTableEntries = bOutputTokens ? SHData.size() : 0;
4235 SCHWShader SHWTemp = SHW;
4237 SHW.Export(SC.Data);
4238 uint32 nOffs = 0;
4240 if (bOutputTokens)
4242 sAddDataArray_POD(SC.Data, SHData, nOffs);
4244 for (const auto& T : Table)
4246 //String pool method
4247 sAddData(SC.Data, T.Token);
4248 uint32 tokenStrIdx = SC.AddString(T.SToken.c_str());
4249 sAddData(SC.Data, tokenStrIdx);
4253 bRes &= ExportSamplers(SHW, SC);
4254 bRes &= ExportParams(SHW, SC);
4256 if (bRes)
4258 if (memcmp(&SHW, &SHWTemp, sizeof(SCHWShader)))
4260 CryFatalError("Export failed");
4264 return bRes;
4267 CHWShader* CHWShader::Import(SShaderSerializeContext& SC, int nOffs, uint32 CRC32, CShader* pSH)
4269 if (nOffs < 0)
4270 return NULL;
4272 CHWShader* pHWSH = NULL;
4273 SCHWShader shaderHW;
4274 shaderHW.Import(&SC.Data[nOffs]);
4275 SCHWShader* pSHW = &shaderHW;
4277 byte* pData = &SC.Data[nOffs + sizeof(SCHWShader)];
4279 const char* szName = sString(pSHW->m_nsName, SC.Strings);
4280 const char* szNameSource = sString(pSHW->m_nsNameSourceFX, SC.Strings);
4281 const char* szNameEntry = sString(pSHW->m_nsEntryFunc, SC.Strings);
4283 TArray<uint32> SHData;
4284 SHData.resize(pSHW->m_nTokens);
4285 memcpy(&SHData[0], pData, pSHW->m_nTokens * sizeof(uint32));
4287 pHWSH = CHWShader::mfForName(szName, szNameSource, CRC32, szNameEntry, pSHW->m_eSHClass, SHData, FXShaderToken{}, pSHW->m_dwShaderType, pSH, pSHW->m_nMaskGenShader, pSHW->m_nMaskGenFX);
4289 pHWSH->m_eSHClass = shaderHW.m_eSHClass;
4290 pHWSH->m_dwShaderType = shaderHW.m_dwShaderType;
4291 pHWSH->m_nMaskGenFX = shaderHW.m_nMaskGenFX;
4292 pHWSH->m_nMaskGenShader = shaderHW.m_nMaskGenShader;
4293 pHWSH->m_nMaskOr_RT = shaderHW.m_nMaskOr_RT;
4294 pHWSH->m_nMaskAnd_RT = shaderHW.m_nMaskAnd_RT;
4295 pHWSH->m_Flags = shaderHW.m_Flags;
4297 return pHWSH;
4300 #else
4301 bool CHWShader_D3D::Export(SShaderSerializeContext& SC)
4303 return false;
4305 #endif
4307 const char* CHWShader_D3D::mfGetActivatedCombinations(bool bForLevel)
4309 TArray<char> Combinations;
4310 char* pPtr = NULL;
4311 uint32 i;
4313 for (i = 0; i < m_Insts.size(); i++)
4315 SHWSInstance* pInst = m_Insts[i];
4316 char name[256];
4317 cry_strcpy(name, GetName());
4318 char* s = strchr(name, '(');
4319 if (s)
4320 s[0] = 0;
4321 string str;
4322 SShaderCombIdent Ident(m_nMaskGenFX, pInst->m_Ident);
4323 gRenDev->m_cEF.mfInsertNewCombination(Ident, pInst->m_eClass, name, 0, &str, false);
4324 assert(str.size());
4325 if (str.size())
4327 assert(str[0] == '<' && str[2] == '>');
4328 string s1;
4329 if (str[0] == '<' && str[2] == '>')
4330 s1.Format("<%d>%s", pInst->m_nUsed, &str[3]);
4331 else
4332 s1 = str;
4333 Combinations.Copy(s1.c_str(), s1.size());
4334 Combinations.Copy("\n", 1);
4338 if (!Combinations.Num())
4339 return NULL;
4340 pPtr = new char[Combinations.Num() + 1];
4341 memcpy(pPtr, &Combinations[0], Combinations.Num());
4342 pPtr[Combinations.Num()] = 0;
4343 return pPtr;
4346 const char* CHWShader::GetCurrentShaderCombinations(bool bForLevel) threadsafe
4348 CryAutoReadLock<CryRWLock> lock(CBaseResource::s_cResLock);
4350 TArray<char> Combinations;
4351 char* pPtr = NULL;
4352 CCryNameTSCRC Name;
4353 SResourceContainer* pRL;
4355 Name = CHWShader::mfGetClassName(eHWSC_Vertex);
4356 pRL = CBaseResource::GetResourcesForClass(Name);
4357 int nVS = 0;
4358 int nPS = 0;
4359 if (pRL)
4361 ResourcesMapItor itor;
4362 for (itor = pRL->m_RMap.begin(); itor != pRL->m_RMap.end(); itor++)
4364 CHWShader* vs = (CHWShader*)itor->second;
4365 if (!vs)
4366 continue;
4367 const char* szCombs = vs->mfGetActivatedCombinations(bForLevel);
4368 if (!szCombs)
4369 continue;
4370 Combinations.Copy(szCombs, strlen(szCombs));
4371 delete[] szCombs;
4372 nVS++;
4376 Name = CHWShader::mfGetClassName(eHWSC_Pixel);
4377 pRL = CBaseResource::GetResourcesForClass(Name);
4378 if (pRL)
4380 ResourcesMapItor itor;
4381 for (itor = pRL->m_RMap.begin(); itor != pRL->m_RMap.end(); itor++)
4383 CHWShader* ps = (CHWShader*)itor->second;
4384 if (!ps)
4385 continue;
4386 const char* szCombs = ps->mfGetActivatedCombinations(bForLevel);
4387 if (!szCombs)
4388 continue;
4389 Combinations.Copy(szCombs, strlen(szCombs));
4390 delete[] szCombs;
4391 nPS++;
4395 if (!Combinations.Num())
4396 return NULL;
4397 pPtr = new char[Combinations.Num() + 1];
4398 memcpy(pPtr, &Combinations[0], Combinations.Num());
4399 pPtr[Combinations.Num()] = 0;
4400 return pPtr;