1 // Copyright 2001-2019 Crytek GmbH / Crytek Group. All rights reserved.
6 #include <lzma/Lzma86.h>
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>
15 #include <D3D12Shader.h>
16 #include <D3DCompiler.h>
19 #if CRY_PLATFORM_DURANGO
20 #include <D3D11Shader_x.h>
21 #include <D3DCompiler_x.h>
23 #include <D3D11Shader.h>
24 #include <D3DCompiler.h>
29 #if defined(USE_NV_API)
30 #include NV_API_HEADER
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
;
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
; }
48 CryEvent
SShaderAsyncInfo::s_RequestEv
;
50 int CHWShader_D3D::s_nDevicePSDataSize
= 0;
51 int CHWShader_D3D::s_nDeviceVSDataSize
= 0;
55 inline int GetCurrentFrameID()
57 return (gRenDev
->m_pRT
->IsRenderThread()) ? gRenDev
->GetRenderFrameID() : gRenDev
->GetMainFrameID();
66 #if CRY_PLATFORM_WINDOWS || CRY_PLATFORM_LINUX || CRY_PLATFORM_ANDROID || CRY_PLATFORM_APPLE
67 while (CryInterlockedCompareExchange(&s_locked
, 1L, 0L) == 1L)
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);
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
)
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
116 bool CHWShader_D3D::mfAddFXTexture(SHWSInstance
* pInst
, SShaderFXParams
& FXParams
, SFXTexture
* pr
, const char* ParamName
, SCGBind
* pBind
, CShader
* ef
, EHWShaderClass eSHClass
)
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
141 void CHWShader_D3D::mfAddFXParameter(SHWSInstance
* pInst
, SParamsGroup
& OutParams
, SShaderFXParams
& FXParams
, SFXParam
* pr
, const char* ParamName
, SCGBind
* pBind
, CShader
* ef
, bool bInstParam
, EHWShaderClass eSHClass
)
150 int nParams
= pBind
->m_nParameters
;
151 if (!pr
->m_Semantic
.empty())
152 nComps
= pr
->m_nComps
;
155 for (int i
= 0; i
< pr
->m_nComps
; i
++)
157 CryFixedStringT
<128> cur
;
158 pr
->GetParamComp(i
, cur
);
164 // Process parameters only with semantics
165 if (nComps
&& nParams
)
167 std::vector
<SCGParam
>* pParams
;
168 if (pr
->m_nParameters
> 1)
172 //if (!pInst->m_pParams[0])
173 // pInst->m_pParams[0] = new std::vector<SCGParam>;
174 pParams
= &OutParams
.Params
[0];
178 //if (!pInst->m_pParams_Inst)
179 // pInst->m_pParams_Inst = new std::vector<SCGParam>;
180 pParams
= &OutParams
.Params_Inst
;
185 //if (!pInst->m_pParams_Inst)
186 // pInst->m_pParams_Inst = new std::vector<SCGParam>;
187 pParams
= &OutParams
.Params_Inst
;
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
213 STexSamplerRT Sampler
;
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
);
224 if (bn
->m_nParameters
< 0)
225 bn
->m_nParameters
= pr
->m_nArray
;
226 mfAddFXTexture(pInst
, FXParams
, pr
, param
, bn
, pFXShader
, eSHClass
);
230 else if (bn
->m_dwBind
& SHADER_BIND_SAMPLER
)
232 SFXSampler
* pr
= gRenDev
->m_cEF
.mfGetFXSampler(FXParams
.m_FXSamplers
, param
);
235 if (bn
->m_nParameters
< 0)
236 bn
->m_nParameters
= pr
->m_nArray
;
237 mfAddFXSampler(pInst
, FXParams
, pr
, param
, bn
, pFXShader
, eSHClass
);
243 SFXParam
* pr
= gRenDev
->m_cEF
.mfGetFXParameter(FXParams
.m_FXParams
, param
);
246 if (bn
->m_nParameters
< 0)
247 bn
->m_nParameters
= pr
->m_nParameters
;
248 mfAddFXParameter(pInst
, OutParams
, FXParams
, pr
, param
, bn
, pFXShader
, bInstParam
, eSHClass
);
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
)
264 if (pi1
->m_dwBind
> pi2
->m_dwBind
)
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
)
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
)
287 if (!strcmp("$Globals", SBDesc
.Name
))
290 for (nCB
= 0; nCB
< CB_NUM
; nCB
++)
292 if (!strcmp(szNamesCB
[nCB
], SBDesc
.Name
))
295 //assert(nCB != CB_NUM);
296 if (nCB
>= CB_NUM
) // Allow having custom cbuffers in shaders
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
))
308 if (CTDesc
.Class
== D3D10_SVC_VECTOR
|| CTDesc
.Class
== D3D10_SVC_SCALAR
|| CTDesc
.Class
== D3D10_SVC_MATRIX_COLUMNS
|| CTDesc
.Class
== D3D10_SVC_MATRIX_ROWS
)
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
);
328 D3D_SHADER_INPUT_BIND_DESC IBDesc
;
329 for (i
= 0; i
< Desc
.BoundResources
; i
++)
332 pShaderReflection
->GetResourceBindingDesc(i
, &IBDesc
);
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
;
341 if (IBDesc
.Dimension
== D3D10_SRV_DIMENSION_BUFFER
)
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);
357 SAliasSampler samps
[MAX_TMU
];
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))
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;
382 pInst
->m_pFXTextures
.reserve(FXParams
.m_FXTextures
.size());
383 for (const auto& t
: FXParams
.m_FXTextures
)
384 pInst
->m_pFXTextures
.push_back(&t
);
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
))
399 if (pB
->m_dwCBufSlot
< 0 || pB
->m_dwCBufSlot
> CB_NUM
)
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
)
407 if (j
!= Group
.Params
[0].size())
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
]);
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
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
];
480 if (pass
->m_VShader
== this)
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
);
489 pass
->m_PassFlags
|= VSM_TANGENTS
;
492 pass
->m_PassFlags
|= VSM_HWSKIN
;
493 pass
->m_PassFlags
|= VSM_VERTEX_VELOCITY
;
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
)
506 pInst
->m_VStreamMask_Decl
|= EStreamMasks(1 << VSF_TANGENTS
);
507 else if (bTangent
[0])
508 pInst
->m_VStreamMask_Decl
|= EStreamMasks(1 << VSF_QTANGENTS
);
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
))
519 pInst
->m_VStreamMask_Decl
|= VSM_HWSKIN
;
520 pInst
->m_VStreamMask_Stream
|= VSM_HWSKIN
;
525 pInst
->m_VStreamMask_Decl
|= VSM_VERTEX_VELOCITY
;
526 pInst
->m_VStreamMask_Stream
|= VSM_VERTEX_VELOCITY
;
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
)
542 assert(m_eSHClass
== eHWSC_Vertex
);
544 InputLayoutHandle eVFormat
= EDefaultInputLayouts::P3F_C4B_T2F
;
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;
554 bUseHWSkin
= (nStream
& VSM_HWSKIN
) != 0;
555 assert(eVFormat
< EDefaultInputLayouts::PreAllocated
);
560 InputLayoutHandle
CHWShader_D3D::mfVertexFormat(SHWSInstance
* pInst
, CHWShader_D3D
* pSH
, D3DBlob
* pShader
, void* pConstantTable
)
562 /*if (!stricmp(pSH->m_EntryFunc.c_str(), "ParticleVS"))
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;
576 bool bSH
[2] = { false, false };
578 bool bTC1
[2] = { false, false };
580 bool bSecCol
= 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
;
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)
601 if (!IDesc
.SemanticName
)
604 if (!strnicmp(IDesc
.SemanticName
, "POSITION", 8) || !strnicmp(IDesc
.SemanticName
, "SV_POSITION", 11))
606 nIndex
= IDesc
.SemanticIndex
;
609 else if (nIndex
== 3)
611 else if (nIndex
== 4)
613 else if (nIndex
== 8)
618 else if (!strnicmp(IDesc
.SemanticName
, "NORMAL", 6))
622 else if (!strnicmp(IDesc
.SemanticName
, "TEXCOORD", 8))
624 nIndex
= IDesc
.SemanticIndex
;
632 if (IDesc
.ReadWriteMask
)
635 else if (nIndex
== 8)
639 else if (!strnicmp(IDesc
.SemanticName
, "COLOR", 5))
641 nIndex
= IDesc
.SemanticIndex
;
644 else if (nIndex
== 1)
648 if (nIndex
== 2 || nIndex
== 3)
651 if (IDesc
.ReadWriteMask
)
658 else if (!stricmp(IDesc
.SemanticName
, "TANGENT"))
661 if (IDesc
.ReadWriteMask
)
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))
674 else if (!strnicmp(IDesc
.SemanticName
, "BLENDWEIGHT", 11) || !strnicmp(IDesc
.SemanticName
, "BLENDINDICES", 12))
676 nIndex
= IDesc
.SemanticIndex
;
679 else if (nIndex
== 1)
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
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
);
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
)
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
;
735 for (i
= 0; i
< pGen
->m_BitMask
.size(); i
++)
737 SShaderGenBit
* pBit
= pGen
->m_BitMask
[i
];
740 if (nBitsPlatform
& pBit
->m_nDependencyReset
)
742 nAndMask
&= ~pBit
->m_Mask
;
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
;
758 //==================================================================================================================
760 static bool sGetMask(char* str
, SShaderGen
* pGen
, uint64
& nMask
)
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
;
776 void CHWShader::mfValidateDirEntries(CResFile
* pRF
)
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");
793 bool CHWShader_D3D::mfStoreCacheTokenMap(const FXShaderToken
& Table
, const TArray
<uint32
>& SHData
)
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
));
811 Data
.Copy((byte
*)&nSize
, sizeof(uint32
));
812 Data
.Copy((byte
*)&SHData
[0], nSize
* sizeof(uint32
));
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);
824 m_CachedTokens
.resize(Data
.size());
825 std::memcpy(&m_CachedTokens
[0], Data
.Data(), Data
.size());
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());
840 uint32 nL
= *(uint32
*)pData
;
841 if (CParserBin::m_bEndians
)
842 SwapEndian(nL
, eBigEndian
);
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
);
856 memcpy(&SHData
[0], &pData
[4], nL
* sizeof(uint32
));
858 pData
+= 4 + nL
* sizeof(uint32
);
859 nSize
-= 4 + nL
* sizeof(uint32
);
862 while (nOffs
< nSize
)
864 char* pStr
= (char*)&pData
[nOffs
+ sizeof(DWORD
)];
866 LoadUnaligned(pData
+ nOffs
, nToken
);
867 if (CParserBin::m_bEndians
)
868 SwapEndian(nToken
, eBigEndian
);
869 int nLen
= strlen(pStr
) + 1;
874 nOffs
+= sizeof(DWORD
) + nLen
;
880 //==============================================================================================================================================================
882 bool CHWShader_D3D::mfGenerateScript(CShader
* pSH
, SHWSInstance
* pInst
, std::vector
<SCGBind
>& InstBindVars
, uint32 nFlags
, TArray
<char>& sNewScr
)
884 uint32 nSFlags
= m_Flags
;
886 TArray
<uint32
> SHData
;
888 if (CParserBin::m_bEditable
) // Fast path for offline shaders builder
890 Table
= m_TokenTable
;
891 SHData
= m_TokenData
;
895 if (!(nSFlags
& HWSG_GS_MULTIRES
))
897 if (!mfGetCacheTokenMap(Table
, SHData
))
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())
913 ShaderTokensVec NewTokens
;
915 uint32 eT
= eT_unknown
;
917 switch (pInst
->m_eClass
)
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;
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
))
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;
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
)
984 CParserBin::AddDefineToken(eT__LT_0_TYPE
+ i
, nLightType
+ eT_0
, NewTokens
);
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
;
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
);
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
);
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
);
1126 char* szEnd
= szStart
- 1;
1127 while (*szEnd
== 0x20)
1132 char szStrName
[128];
1133 ptrdiff_t nSize
= szEnd
- szS
;
1134 strncpy(szStrName
, &szS
[1], nSize
);
1135 szStrName
[nSize
] = 0;
1138 strcpy(szStruct
, "struct ");
1139 strcat(szStruct
, szStrName
);
1140 char* szStrStart
= strstr(&sNewScr
[0], szStruct
);
1143 char* szStrEnd
= strstr(szStrStart
, "};");
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");
1157 char* szPosAB
= szPosA
- 1;
1158 while (*szPosAB
== 0x20)
1160 char* szP
= szPosAB
;
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());
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
;
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
))
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
);
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
);
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
);
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
);
1235 assert(nPosN
> 0 && nPosN
< (int)Parser
.m_Tokens
.size());
1236 if (InstBindVars
.size())
1239 CCryNameR
nm(Parser
.GetString(nT
));
1240 for (; i
< InstBindVars
.size(); i
++)
1242 SCGBind
& b
= InstBindVars
[i
];
1246 if (i
== InstBindVars
.size())
1247 Parser
.m_Tokens
[nPosN
] = eT_comment
;
1250 Parser
.m_Tokens
[nPosN
] = eT_comment
;
1252 nPosN
= Parser
.FindToken(nPosN
+ 2, nPosEnd
, eT_semicolumn
);
1256 nPos
= Parser
.FindToken(nPosEnd
+ 1, Parser
.m_Tokens
.size() - 1, eT_cbuffer
);
1259 nPos
= Parser
.FindToken(nPos
+ 2, Parser
.m_Tokens
.size() - 1, eT_cbuffer
);
1265 uint32 nName = sFindVar(Parser, nStart);
1268 bool bAffect = sIsAffectFuncs(Parser, nName);
1270 Parser.m_Tokens[nStart] = eT_comment;
1276 #if CRY_RENDERER_VULKAN
1277 std::string
resourceTypeToString(SResourceBindPoint::ESlotType type
)
1281 case SResourceBindPoint::ESlotType::ConstantBuffer
:
1283 case SResourceBindPoint::ESlotType::Sampler
:
1285 case SResourceBindPoint::ESlotType::TextureAndBuffer
:
1287 case SResourceBindPoint::ESlotType::UnorderedAccessView
:
1290 CRY_ASSERT(false, "Type is not defined.");
1295 struct ResourceSetBindingInfo
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
));
1320 TD
.SToken
= newTokenStr
;
1322 tokenTable
.insert(itor
, TD
);
1327 struct SRegisterRangeDesc
1329 SRegisterRangeDesc()
1330 : type(SResourceBindPoint::ESlotType::InvalidSlotType
)
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
;
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
);
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)
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
);
1401 RegisterRanges registerRanges
= ExtractRegisterRanges(*LayoutEncoding
);
1403 uint32_t bindingIndex
;
1405 for (setIndex
= 0; setIndex
< (uint32_t)registerRanges
.size(); setIndex
++)
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.
1430 int nSize
= Parser
.m_Tokens
.size();
1431 const uint32
* pTokens
= &Parser
.m_Tokens
[0];
1432 std::map
<uint32
, uint32
> alreadyProcessed
;
1435 // Look for "register(*)" in the shader code.
1436 nCur
= Parser
.FindToken(nCur
, nSize
- 1, eT_register
);
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)
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
;
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
;
1481 void CHWShader_D3D::CorrectScriptEnums(CParserBin
& Parser
, SHWSInstance
* pInst
, std::vector
<SCGBind
>& InstBindVars
, const FXShaderToken
& Table
)
1483 // correct enumeration of TEXCOORD# interpolators after preprocessing
1485 int nSize
= Parser
.m_Tokens
.size();
1486 uint32
* pTokens
= &Parser
.m_Tokens
[0];
1488 const uint32 Toks
[] = { eT_TEXCOORDN
, eT_TEXCOORDN_centroid
, eT_unknown
};
1490 std::vector
<SStructData
> SData
;
1494 nCur
= Parser
.FindToken(nCur
, nSize
- 1, eT_struct
);
1497 int nLastStr
= Parser
.FindToken(nCur
, nSize
- 1, eT_br_cv_2
);
1498 assert(nLastStr
>= 0);
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)
1509 uint32 nName
= pTokens
[nCur
+ 1];
1511 while (nCur
< nLastStr
)
1513 int nTN
= Parser
.FindToken(nCur
, nLastStr
, Toks
);
1516 nCur
= nLastStr
+ 1;
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
);
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];
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
)
1551 else if (nType
== eT_float3x4
|| nType
== eT_float3x3
|| nType
== eT_half3x4
|| nType
== eT_half3x3
)
1553 else if (nType
== eT_float2x4
|| nType
== eT_half2x4
)
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
;
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
)
1580 uint32 nTok
= pTokens
[nCur
];
1581 if (nTok
!= eT_br_rnd_1
&& nTok
!= eT_br_rnd_2
&& nTok
!= eT_comma
)
1586 Parameter
.push_back(pTokens
[nCur
]);
1588 while (pTokens
[nCur
] == eT_dot
)
1591 Parameter
.push_back(pTokens
[nCur
]);
1592 Parameter
.push_back(pTokens
[nCur
+ 1]);
1598 static void sCR(TArray
<char>& Text
, int nLevel
)
1601 for (int i
= 0; i
< nLevel
; i
++)
1608 bool CHWShader_D3D::ConvertBinScriptToASCII(CParserBin
& Parser
, SHWSInstance
* pInst
, std::vector
<SCGBind
>& InstBindVars
, const FXShaderToken
& Table
, TArray
<char>& Text
)
1613 uint32
* pTokens
= &Parser
.m_Tokens
[0];
1614 uint32 nT
= Parser
.m_Tokens
.size();
1616 for (i
= 0; i
< nT
; i
++)
1618 uint32 nToken
= pTokens
[i
];
1624 if (nToken
== eT_skip
)
1629 if (nToken
== eT_skip_1
)
1633 nToken
= pTokens
[i
];
1634 if (nToken
== eT_skip_2
)
1641 if (nToken
== eT_fetchinst
)
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
);
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);
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
)
1676 const char* szStr
= CParserBin::GetString(nToken
, Table
, false);
1678 if (!szStr
|| !szStr
[0])
1681 bRes
= CParserBin::CorrectScript(pTokens
, i
, nT
, Text
);
1685 #if defined(_DEBUG) && !CRY_PLATFORM_ORBIS
1689 char c
= szStr
[n
++];
1690 bool bASC
= isascii(c
);
1694 if (nToken
== eT_semicolumn
|| nToken
== eT_br_cv_1
)
1696 if (nToken
== eT_br_cv_1
)
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);
1709 else if (i
+ 1 < nT
)
1711 if (pTokens
[i
+ 1] < eT_br_rnd_1
|| pTokens
[i
+ 1] >= eT_float
)
1721 char cPrev
= Text
[Text
.Num() - 1];
1722 if (!SkipChar((uint8
)cPrev
) && !SkipChar((uint8
)szStr
[0]))
1726 Text
.Copy(szStr
, strlen(szStr
));
1727 if (nToken
== eT_br_cv_2
)
1730 if (i
+ 1 < nT
&& pTokens
[i
+ 1] != eT_semicolumn
)
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
;
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)
1768 q
[0] = BASE64_TABLE
[w
>> 2];
1769 q
[1] = BASE64_TABLE
[(w
<< 4) & 0x3F];
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];
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
];
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.
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());
1834 void CHWShader_D3D::mfGetSrcFileName(char* srcName
, int nSize
)
1836 if (!srcName
|| nSize
<= 0)
1838 if (!m_NameSourceFX
.empty())
1840 cry_strcpy(srcName
, nSize
, m_NameSourceFX
.c_str());
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/");
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
)
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
);
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());
1924 cry_strcat(dstname
, nSize
, "_out");
1928 char* s
= strchr(dstname
, '(');
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;
1956 SAFE_DELETE(rfUser
);
1959 rfUser
->StoreLookupData(CRC32
, cacheVer
);
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();
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
);
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;
1993 case RESVERSION_LZSS
:
1994 decompressedSize
= *reinterpret_cast<uint32
*>(buf
);
1995 if (size
>= 10000000)
1996 return ReturnType
{};
1998 SwapEndian(decompressedSize
, eBigEndian
);
1999 pData
= std::unique_ptr
<byte
[]>(new byte
[decompressedSize
]);
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
{};
2013 case RESVERSION_LZMA
:
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
]);
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
);
2034 CryWarning(EValidatorModule::VALIDATOR_MODULE_RENDERER
, EValidatorSeverity::VALIDATOR_ERROR
, "FileRead - LzmaDecoder error");
2035 return ReturnType
{};
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
);
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
)
2066 int nRes
= pRF
->mfOpen(RA_READ
| (CParserBin::m_bEndians
? RA_ENDIANS
: 0), &gRenDev
->m_cEF
.m_ResLookupDataMan
[static_cast<int>(cacheType
)], nullptr);
2074 if (cacheType
== cacheSource::user
)
2076 // User cache, reopen with read-write access.
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
)]))
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
)
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))
2133 bool bAsync
= false;
2134 const CDirEntry
* de
= rfOpenGuard
.getHandle()->mfGetEntry(name
, &bAsync
);
2138 if (mfValidateCache(*cache
) != cacheValidationResult::ok
)
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
;
2149 m_pCurInst
->m_bAsyncActivating
= bAsync
;
2154 bool CHWShader_D3D::mfAddCacheItem(SDiskShaderCache
* pCache
, SShaderCacheHeaderItem
* pItem
, const byte
* pData
, int nLen
, bool bFlush
, CCryNameTSCRC Name
)
2156 if (!pCache
|| !pCache
->m_pRes
)
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
));
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());
2187 CRY_ASSERT(false, "CHWShader_D3D::mfAddCacheItem(): Couldn't add/open cache entry");
2194 pCache
->m_pRes
->mfFlush();
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
;
2208 Comb
.nRTOrg
= (nRT
& m_nMaskAnd_RT
) | m_nMaskOr_RT
;
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
;
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
;
2227 bool CHWShader_D3D::mfStoreEmptyCombination(SEmptyCombination
& Comb
)
2229 auto cache
= QueryDiskCache(cacheSource::user
);
2230 if (!cache
|| !cache
->m_pRes
)
2233 CResFile
* rf
= cache
->m_pRes
;
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
);
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
);
2259 if (deOrg
->GetOffset() != deNew
->GetOffset())
2260 deOrg
->MarkNotSaved();
2262 // Also evict in-memory image of user cache
2263 InvalidateCache(cacheSource::user
);
2267 CDirEntry
de(nameOrg
, deNew
->GetSize(), deNew
->GetOffset(), deNew
->GetFlags());
2274 bool CHWShader_D3D::mfFlushCacheFile()
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
{};
2286 auto cache
= QueryDiskCache(cacheSource::user
);
2287 if (cache
&& cache
->m_pRes
)
2289 cache
->m_pRes
->mfFlush();
2303 bool needsProcessing
;
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
)
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);
2323 ResDir
* Dir
= m_pRes
->mfGetDirectory();
2325 std::vector
<SData
> Data
;
2328 pStats
->nEntries
+= Dir
->size();
2330 for (CDirEntry
& DE
: *Dir
)
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
)
2342 d
.nOffset
= DE
.GetOffset();
2343 d
.needsProcessing
= true;
2344 d
.Name
= DE
.GetName();
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
)
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
)
2365 if (nSizeComp
!= Data
[j
].nSizeComp
|| nSizeDecomp
!= Data
[j
].nSizeDecomp
)
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
;
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());
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
);
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
];
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
);
2420 pStats
->nSizeUncompressed
+= pD
->nSizeDecomp
;
2421 pStats
->nSizeCompressed
+= pD
->nSizeComp
;
2422 pStats
->nUniqueEntries
++;
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
);
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
);
2446 int nSizeDir
= m_pRes
->mfFlush();
2449 pStats
->nDirDataSize
+= nSizeDir
;
2451 for (i
= 0; i
< Data
.size(); i
++)
2453 SData
* pD
= &Data
[i
];
2454 SAFE_DELETE_ARRAY(pD
->pData
);
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
);
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())
2472 if (ti1
->GetName() == ti2
->GetName())
2477 byte
* CHWShader_D3D::mfBindsToCache(SHWSInstance
* pInst
, std::vector
<SCGBind
>* Binds
, int nParams
, byte
* pP
)
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;
2498 const byte
* CHWShader_D3D::mfBindsFromCache(std::vector
<SCGBind
>& Binds
, int nParams
, const byte
* pP
)
2500 for (int i
= 0; i
< nParams
; i
++)
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;
2523 byte
* CHWShader::mfIgnoreBindsFromCache(int nParams
, byte
* pP
)
2526 for (i
= 0; i
< nParams
; i
++)
2528 SShaderCacheHeaderItemVar
* pVar
= (SShaderCacheHeaderItemVar
*)pP
;
2529 pP
+= offsetof(SShaderCacheHeaderItemVar
, m_Name
) + strlen(pVar
->m_Name
) + 1;
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
);
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
;
2567 pInst
->m_Handle
.m_pShader
->m_bDisabled
= true;
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
;
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
;
2600 s_nDeviceVSDataSize
+= nSize
;
2602 if (pInst
->m_Handle
.m_pShader
->GetHandle())
2604 #if defined(ORBIS_GPU_DEBUGGER_SUPPORT) && !CRY_RENDERER_GNM
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
);
2610 // Assign name to Shader for enhanced debugging
2611 #if !defined(RELEASE) && (CRY_PLATFORM_WINDOWS)
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
);
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
);
2637 DWORD
* pCode
= (DWORD
*)pShader
->GetBufferPointer();
2638 if (gcpRendD3D
->m_cEF
.m_nCombinationsProcess
>= 0)
2640 pInst
->m_Handle
.SetFake();
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
);
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
);
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
;
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
)
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);
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
);
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
);
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
);
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
, '(');
2766 if (!bShaderThread
|| true)
2769 if (m_Flags
& HWSG_FP_EMULATION
)
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
);
2780 //============================================================================
2782 void CHWShader_D3D::mfSaveCGFile(const char* scr
, const char* path
)
2784 if (CRenderer::CV_r_shadersdebug
< 1)
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
);
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
);
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
);
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
);
2806 fp
= gEnv
->pCryPak
->FOpen(name
, "w");
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");
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');
2840 iLog
->LogError("%s", strE
.c_str());
2843 SShaderAsyncInfo::~SShaderAsyncInfo()
2846 AUTO_LOCK(g_cAILock
);
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
;
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
;
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
);
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
)
2921 if (CRenderer::CV_r_shadersasynccompiling
> 0)
2923 if (!gRenDev
->IsShaderCacheGenMode())
2925 iLog
->Log("Flushing pended shaders...");
2930 if (SShaderAsyncInfo::s_nPendingAsyncShaders
<= 0)
2932 int n
= (int)iTimer
->GetAsyncCurTime();
2937 SShaderAsyncInfo::FlushPendingShaders();
2942 // Compile FXC shaders or next iteration of internal shaders
2943 SShaderAsyncInfo::FlushPendingShaders();
2945 if (SShaderAsyncInfo::s_nPendingAsyncShaders
)
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
)
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
;
2975 bool bResult
= true;
2978 SShaderTechnique
* pTech
= nullptr;//gRenDev->m_RP.m_pCurTechnique;
2979 CShader
* pSH
= pAsync
->m_pFXShader
;
2981 if (pAsync
->m_bPending
)
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
);
3017 mfOutputCompilerError(Errors
, Text
.c_str());
3019 Warning("Couldn't compile HW shader '%s'", GetName());
3020 mfSaveCGFile(Text
.c_str(), NULL
);
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);
3038 if (pAsync
->m_bPendedSamplers
)
3039 mfGatherFXParameters(pInst
, pInst
->m_pBindVars
, this, 2, pAsync
->m_pFXShader
);
3041 if (pAsync
->m_bPendedFlush
)
3044 cry_strcpy(nmDst
, GetName());
3045 char* s
= strchr(nmDst
, '(');
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
);
3060 SAFE_DELETE(pInst
->m_pAsync
);
3063 if (pErrorMsgs
&& !strErr
.empty())
3066 bResult
&= mfUploadHW(pShader
, pInst
, pSH
, 0);
3067 SAFE_RELEASE(pShader
);
3072 mfUpdatePreprocessFlags(pTech
);
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
;
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
, '(');
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
)
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());
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
, '(');
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);
3157 *pRequestLine
= RequestLine
;
3159 if (!CRenderer::CV_r_shaderssubmitrequestline
|| !CRenderer::CV_r_shadersremotecompiler
|| pInst
->m_bHasSendRequest
)
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
;
3180 pAsync
->m_RequestLine
= RequestLine
;
3181 pAsync
->m_Text
= "";
3182 pAsync
->m_bDeleteAfterRequest
= true;
3184 CAsyncShaderTask::InsertPendingShader(pAsync
);
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",
3198 "ShaderList_PC.txt",
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
)
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
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
);
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
);
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()))
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
;
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())
3272 void* pShaderReflBuf
;
3273 hr
= D3DReflection(pBuf
, nSize
, IID_D3DShaderReflection
, &pShaderReflBuf
);
3276 D3DShaderReflection
* pShaderReflection
= (D3DShaderReflection
*)pShaderReflBuf
;
3277 *ppConstantTable
= (void*)pShaderReflection
;
3287 #if CRY_PLATFORM_WINDOWS
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!");
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();
3312 strErr
+= "D3DXCompileShader failed";
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
);
3324 D3DShaderReflection
* pShaderReflection
= (D3DShaderReflection
*)pShaderReflBuf
;
3325 *ppConstantTable
= (void*)pShaderReflection
;
3334 #endif // #if CRY_PLATFORM_WINDOWS || CRY_PLATFORM_DURANGO
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
3345 D3DBlob
* pCode
= NULL
;
3352 if (!CRenderer::CV_r_shadersAllowCompilation
)
3355 mfCompileHLSL_Int(pSH
, prog_text
, &pCode
, ppConstantTable
, ppErrorMsgs
, strErr
, InstBindVars
);
3359 if (CRenderer::CV_r_shadersasynccompiling
)
3364 mfOutputCompilerError(strErr
, prog_text
);
3366 Warning("Couldn't compile HW shader '%s'", GetName());
3367 mfSaveCGFile(prog_text
, NULL
);
3375 void CHWShader_D3D::mfPrepareShaderDebugInfo(SHWSInstance
* pInst
, const char* szAsm
, std::vector
<SCGBind
>& InstBindVars
, void* pConstantTable
)
3379 char* szInst
= strstr((char*)szAsm
, "pproximately ");
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
)
3401 mfGetDstFileName(pInst
, nmdst
, 256, 4);
3407 szName
= gRenDev
->m_cEF
.m_szUserPath
+ string(nmdst
) + string(".fxca");
3408 statusdst
= gEnv
->pCryPak
->FOpen(szName
.c_str(), "wb");
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
)
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
, '(');
3445 if (CRenderer::CV_r_shadersdebug
== 2)
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
);
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)
3465 #if defined(CRY_COMPILER_GCC) || defined(CRY_COMPILER_CLANG)
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
3483 if (pInst
->m_pBindVars
.size())
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
);
3494 char* szAsm
= (char*)pAsm
->GetBufferPointer();
3495 pSH
->mfPrepareShaderDebugInfo(pInst
, szAsm
, InstBindVars
, pConstantTable
);
3499 //assert(!pInst->m_pBindVars);
3503 bool bVF
= pSH
->m_eSHClass
== eHWSC_Vertex
;
3504 #if CRY_PLATFORM_DESKTOP
3505 if (CParserBin::PlatformIsConsole())
3509 mfVertexFormat(pInst
, pSH
, pShader
, pConstantTable
);
3511 mfCreateBinds(pInst
->m_pBindVars
, pConstantTable
, (std::size_t)pShader
->GetBufferSize());
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
,
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
);
3539 pSH
->mfCreateCacheItem(pInst
, pFXShader
, InstBindVars
, (byte
*)pShader
->GetBufferPointer(), (uint32
)pShader
->GetBufferSize(), bShaderThread
);
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;
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
)
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
);
3590 CryLog("CHWShader_D3D::mfActivate(): Shader '%s' not found in device cache but found in disk cache.", m_Name
.c_str());
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
);
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
);
3615 if (gRenDev
->m_cEF
.m_nCombinationsProcess
>= 0)
3618 if (mfActivateCacheItem(pSH
, entry
, nFlags
))
3619 return (pInst
->m_Handle
.m_pShader
!= nullptr);
3621 if ((nFlags
& HWSF_PRECACHE
) == 0)
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",
3664 Warning("Warning: Shader %s(%I64x)(%x)(%x)(%x)(%llx)(%s) is not existing in the cache\n",
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
));
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
;
3680 if (!CRenderer::CV_r_shadersAllowCompilation
|| pInst
->IsAsyncCompiling())
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
);
3700 //////////////////////////////////////////////////////////////////////////
3702 #ifdef SHADER_ASYNC_COMPILATION
3704 #pragma warning(disable: 4355)// warning C4355: 'this' : used in base member initializer list
3706 CAsyncShaderTask::CAsyncShaderTask()
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
;
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
)
3741 PREFAST_ASSUME(pAI
);
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
)
3749 if (pAI2
->m_nFrame
> nFrame
|| pAI2
->m_fMinDistance
< fDist
)
3752 nFrame
= pAI2
->m_nFrame
;
3753 fDist
= pAI2
->m_fMinDistance
;
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
;
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
);
3793 pAI
->m_bPending
= 0;
3794 pAI
->Link(&SShaderAsyncInfo::PendingListT());
3797 if (pAI
->m_bDeleteAfterRequest
)
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);
3816 pAsync
->m_nThread
= m_nThread
;
3817 pAsync
->m_bPendedEnv
= true;
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());
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",
3840 "ShaderList_PC.txt",
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"));
3866 sErrorText
.reserve(Data
.size());
3867 for (uint32 i
= 0; i
< Data
.size(); i
++)
3868 sErrorText
+= Data
[i
];
3872 sErrorText
.assign("Unknown Error");
3875 pAsync
->m_Errors
+= sErrorText
;
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())
3898 D3DShaderReflection
* pShaderReflection
;
3899 hr
= D3DReflection(pBuf
, nSize
, IID_D3DShaderReflection
, (void**)&pShaderReflection
);
3902 pAsync
->m_pConstants
= (void*)pShaderReflection
;
3908 bResult
= PostCompile(pAsync
);
3912 pAsync
->m_pDevShader
= 0;
3916 #if CRY_PLATFORM_WINDOWS
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!");
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";
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
;
3943 pAsync
->m_Errors
+= "D3DXCompileShader failed";
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
);
3955 pAsync
->m_pConstants
= (void*)pShaderReflection
;
3956 bResult
= PostCompile(pAsync
);
3964 #endif // #if CRY_PLATFORM_WINDOWS
3968 void CAsyncShaderTask::CShaderThread::ThreadEntry()
3972 m_task
->FlushPendingShaders();
3973 if (!CRenderer::CV_r_shadersasynccompiling
)
3982 //===============================================================================================
3985 #ifdef SHADERS_SERIALIZING
3987 bool SFXParam::Export(SShaderSerializeContext
& SC
)
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
;
3999 PR
.m_nComps
= m_nComps
;
4000 PR
.m_nFlags
= m_nFlags
;
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
);
4011 bool SFXParam::Import(SShaderSerializeContext
& SC
, SSFXParam
* pPR
)
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
;
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];
4033 bool SFXSampler::Export(SShaderSerializeContext
& SC
)
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
);
4054 bool SFXSampler::Import(SShaderSerializeContext
& SC
, SSFXSampler
* pPR
)
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];
4073 bool SFXTexture::Export(SShaderSerializeContext
& SC
)
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
);
4096 bool SFXTexture::Import(SShaderSerializeContext
& SC
, SSFXTexture
* pPR
)
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];
4117 bool CHWShader_D3D::ExportSamplers(SCHWShader
& SHW
, SShaderSerializeContext
& SC
)
4121 //Samplers no longer stored here
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
);
4134 bool CHWShader::ImportSamplers(SShaderSerializeContext
& SC
, SCHWShader
* pSHW
, byte
*& pData
, std::vector
<STexSamplerRT
>& Samplers
)
4138 //Samplers no longer stored here
4142 for (i
= 0; i
< pSHW
->m_nSamplers
; i
++)
4145 bRes
&= TS
.Import(SC
, pData
);
4147 Samplers
.push_back(TS
);
4153 bool CHWShader_D3D::ExportParams(SCHWShader
& SHW
, SShaderSerializeContext
& SC
)
4157 //params no longer here
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
);
4172 bool CHWShader::ImportParams(SShaderSerializeContext
& SC
, SCHWShader
* pSHW
, byte
*& pData
, std::vector
<SFXParam
>& Params
)
4176 //params no longer here
4180 for (i
= 0; i
< pSHW
->m_nParams
; i
++)
4183 bRes
&= PR
.Import(SC
, pData
);
4185 Params
.push_back(PR
);
4191 bool CHWShader_D3D::Export(CShader
* pSH
, SShaderSerializeContext
& SC
)
4198 cry_strcpy(str
, GetName());
4199 char* c
= strchr(str
, '(');
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;
4222 mfGetCacheTokenMap(Table
, SHData
);
4224 SHData
= m_TokenData
;
4226 if (bOutputTokens
&& !Table
.size())
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
);
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
);
4258 if (memcmp(&SHW
, &SHWTemp
, sizeof(SCHWShader
)))
4260 CryFatalError("Export failed");
4267 CHWShader
* CHWShader::Import(SShaderSerializeContext
& SC
, int nOffs
, uint32 CRC32
, CShader
* pSH
)
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
;
4301 bool CHWShader_D3D::Export(SShaderSerializeContext
& SC
)
4307 const char* CHWShader_D3D::mfGetActivatedCombinations(bool bForLevel
)
4309 TArray
<char> Combinations
;
4313 for (i
= 0; i
< m_Insts
.size(); i
++)
4315 SHWSInstance
* pInst
= m_Insts
[i
];
4317 cry_strcpy(name
, GetName());
4318 char* s
= strchr(name
, '(');
4322 SShaderCombIdent
Ident(m_nMaskGenFX
, pInst
->m_Ident
);
4323 gRenDev
->m_cEF
.mfInsertNewCombination(Ident
, pInst
->m_eClass
, name
, 0, &str
, false);
4327 assert(str
[0] == '<' && str
[2] == '>');
4329 if (str
[0] == '<' && str
[2] == '>')
4330 s1
.Format("<%d>%s", pInst
->m_nUsed
, &str
[3]);
4333 Combinations
.Copy(s1
.c_str(), s1
.size());
4334 Combinations
.Copy("\n", 1);
4338 if (!Combinations
.Num())
4340 pPtr
= new char[Combinations
.Num() + 1];
4341 memcpy(pPtr
, &Combinations
[0], Combinations
.Num());
4342 pPtr
[Combinations
.Num()] = 0;
4346 const char* CHWShader::GetCurrentShaderCombinations(bool bForLevel
) threadsafe
4348 CryAutoReadLock
<CryRWLock
> lock(CBaseResource::s_cResLock
);
4350 TArray
<char> Combinations
;
4353 SResourceContainer
* pRL
;
4355 Name
= CHWShader::mfGetClassName(eHWSC_Vertex
);
4356 pRL
= CBaseResource::GetResourcesForClass(Name
);
4361 ResourcesMapItor itor
;
4362 for (itor
= pRL
->m_RMap
.begin(); itor
!= pRL
->m_RMap
.end(); itor
++)
4364 CHWShader
* vs
= (CHWShader
*)itor
->second
;
4367 const char* szCombs
= vs
->mfGetActivatedCombinations(bForLevel
);
4370 Combinations
.Copy(szCombs
, strlen(szCombs
));
4376 Name
= CHWShader::mfGetClassName(eHWSC_Pixel
);
4377 pRL
= CBaseResource::GetResourcesForClass(Name
);
4380 ResourcesMapItor itor
;
4381 for (itor
= pRL
->m_RMap
.begin(); itor
!= pRL
->m_RMap
.end(); itor
++)
4383 CHWShader
* ps
= (CHWShader
*)itor
->second
;
4386 const char* szCombs
= ps
->mfGetActivatedCombinations(bForLevel
);
4389 Combinations
.Copy(szCombs
, strlen(szCombs
));
4395 if (!Combinations
.Num())
4397 pPtr
= new char[Combinations
.Num() + 1];
4398 memcpy(pPtr
, &Combinations
[0], Combinations
.Num());
4399 pPtr
[Combinations
.Num()] = 0;