1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#include "Material/BsShader.h"
4#include "Material/BsTechnique.h"
5#include "Error/BsException.h"
6#include "Debug/BsDebug.h"
7#include "Private/RTTI/BsShaderRTTI.h"
8#include "Resources/BsResources.h"
9#include "RenderAPI/BsGpuParams.h"
10#include "Material/BsPass.h"
11#include "RenderAPI/BsSamplerState.h"
12#include "Image/BsTexture.h"
13
14namespace bs
15{
16 RTTITypeBase* SubShader::getRTTIStatic()
17 {
18 return SubShaderRTTI::instance();
19 }
20
21 RTTITypeBase* SubShader::getRTTI() const
22 {
23 return SubShader::getRTTIStatic();
24 }
25
26 template<bool Core>
27 TSHADER_DESC<Core>::TSHADER_DESC()
28 :queueSortType(QueueSortType::None), queuePriority(0), separablePasses(false), flags(0)
29 {
30
31 }
32
33 template<bool Core>
34 void TSHADER_DESC<Core>::addParameter(SHADER_DATA_PARAM_DESC paramDesc, UINT8* defaultValue)
35 {
36 if(paramDesc.type == GPDT_STRUCT && paramDesc.elementSize <= 0)
37 {
38 LOGERR("You need to provide a non-zero element size for a struct parameter.");
39 return;
40 }
41
42 const auto iterFind = dataParams.find(paramDesc.name);
43 if(iterFind != dataParams.end())
44 return;
45
46 if (defaultValue != nullptr)
47 {
48 paramDesc.defaultValueIdx = (UINT32)dataDefaultValues.size();
49 UINT32 defaultValueSize = Shader::getDataParamSize(paramDesc.type);
50
51 dataDefaultValues.resize(paramDesc.defaultValueIdx + defaultValueSize);
52 memcpy(&dataDefaultValues[paramDesc.defaultValueIdx], defaultValue, defaultValueSize);
53 }
54 else
55 paramDesc.defaultValueIdx = (UINT32)-1;
56
57 dataParams[paramDesc.name] = paramDesc;
58 }
59
60 template<bool Core>
61 void TSHADER_DESC<Core>::addParameter(SHADER_OBJECT_PARAM_DESC paramDesc)
62 {
63 UINT32 defaultValueIdx = (UINT32)-1;
64
65 addParameterInternal(std::move(paramDesc), defaultValueIdx);
66 }
67
68 template<bool Core>
69 void TSHADER_DESC<Core>::addParameter(SHADER_OBJECT_PARAM_DESC paramDesc, const SamplerStateType& defaultValue)
70 {
71 UINT32 defaultValueIdx = (UINT32)-1;
72 if (Shader::isSampler(paramDesc.type) && defaultValue != nullptr)
73 {
74 defaultValueIdx = (UINT32)samplerDefaultValues.size();
75 samplerDefaultValues.push_back(defaultValue);
76 }
77
78 addParameterInternal(std::move(paramDesc), defaultValueIdx);
79 }
80
81 template<bool Core>
82 void TSHADER_DESC<Core>::addParameter(SHADER_OBJECT_PARAM_DESC paramDesc, const TextureType& defaultValue)
83 {
84 UINT32 defaultValueIdx = (UINT32)-1;
85 if (Shader::isTexture(paramDesc.type) && defaultValue != nullptr)
86 {
87 defaultValueIdx = (UINT32)textureDefaultValues.size();
88 textureDefaultValues.push_back(defaultValue);
89 }
90
91 addParameterInternal(std::move(paramDesc), defaultValueIdx);
92 }
93
94 template<bool Core>
95 void TSHADER_DESC<Core>::addParameterInternal(SHADER_OBJECT_PARAM_DESC paramDesc, UINT32 defaultValueIdx)
96 {
97 Map<String, SHADER_OBJECT_PARAM_DESC>* DEST_LOOKUP[] = { &textureParams, &bufferParams, &samplerParams };
98 UINT32 destIdx = 0;
99 if (Shader::isBuffer(paramDesc.type))
100 destIdx = 1;
101 else if (Shader::isSampler(paramDesc.type))
102 destIdx = 2;
103
104 Map<String, SHADER_OBJECT_PARAM_DESC>& paramsMap = *DEST_LOOKUP[destIdx];
105
106 auto iterFind = paramsMap.find(paramDesc.name);
107 if (iterFind == paramsMap.end())
108 {
109 paramDesc.defaultValueIdx = defaultValueIdx;
110 paramsMap[paramDesc.name] = paramDesc;
111 }
112 else
113 {
114 SHADER_OBJECT_PARAM_DESC& desc = iterFind->second;
115
116 // If same name but different properties, we ignore this param
117 if (desc.type != paramDesc.type || desc.rendererSemantic != paramDesc.rendererSemantic)
118 return;
119
120 Vector<String>& gpuVariableNames = desc.gpuVariableNames;
121 bool found = false;
122 for (UINT32 i = 0; i < (UINT32)gpuVariableNames.size(); i++)
123 {
124 if (gpuVariableNames[i] == paramDesc.gpuVariableName)
125 {
126 found = true;
127 break;
128 }
129 }
130
131 if (!found)
132 gpuVariableNames.push_back(paramDesc.gpuVariableName);
133 }
134 }
135
136 template<bool Core>
137 void TSHADER_DESC<Core>::setParameterAttribute(const String& name, const SHADER_PARAM_ATTRIBUTE& attrib)
138 {
139 SHADER_DATA_PARAM_DESC* paramDescData = nullptr;
140
141 const auto findIterData = dataParams.find(name);
142 if (findIterData != dataParams.end())
143 paramDescData = &findIterData->second;
144
145 SHADER_OBJECT_PARAM_DESC* paramDescObj = nullptr;
146 if(!paramDescData)
147 {
148 const auto findIterTexture = textureParams.find(name);
149 if (findIterTexture != textureParams.end())
150 paramDescObj = &findIterTexture->second;
151
152 if (!paramDescObj)
153 {
154 const auto findIterSampler = samplerParams.find(name);
155 if (findIterSampler != samplerParams.end())
156 paramDescObj = &findIterSampler->second;
157 }
158
159 if (!paramDescObj)
160 {
161 const auto findIterBuffer = bufferParams.find(name);
162 if (findIterBuffer != bufferParams.end())
163 paramDescObj = &findIterBuffer->second;
164 }
165 }
166
167 SHADER_PARAM_COMMON* paramDesc = paramDescData;
168 if(!paramDesc)
169 paramDesc = paramDescObj;
170
171 if(!paramDesc)
172 {
173 LOGWRN("Attempting to apply a shader parameter attribute to a non-existing parameter.");
174 return;
175 }
176
177 if(attrib.type == ShaderParamAttributeType::SpriteUV)
178 {
179 if(paramDescObj)
180 {
181 LOGWRN("Attempting to apply SpriteUV attribute to an object parameter is not supported.");
182 return;
183 }
184
185 if(paramDescData->type != GPDT_FLOAT4)
186 {
187 LOGWRN("SpriteUV attribute can only be applied to 4D vectors.");
188 return;
189 }
190 }
191
192 // Look for duplicate attributes
193 UINT32 curAttribIdx = paramDesc->attribIdx;
194 bool found = false;
195 while(curAttribIdx != (UINT32)-1)
196 {
197 SHADER_PARAM_ATTRIBUTE& curAttrib = paramAttributes[curAttribIdx];
198 if(curAttrib.type == attrib.type)
199 {
200 curAttrib = attrib;
201
202 found = true;
203 break;
204 }
205
206 curAttribIdx = curAttrib.nextParamIdx;
207 }
208
209 if(!found)
210 {
211 const auto attribIdx = (UINT32)paramAttributes.size();
212 paramAttributes.emplace_back(attrib);
213
214 if (paramDesc->attribIdx != (UINT32)-1)
215 paramAttributes.back().nextParamIdx = paramDesc->attribIdx;
216
217 paramDesc->attribIdx = attribIdx;
218 }
219 }
220
221 template<bool Core>
222 void TSHADER_DESC<Core>::setParamBlockAttribs(const String& name, bool shared, GpuBufferUsage usage,
223 StringID rendererSemantic)
224 {
225 SHADER_PARAM_BLOCK_DESC desc;
226 desc.name = name;
227 desc.shared = shared;
228 desc.usage = usage;
229 desc.rendererSemantic = rendererSemantic;
230
231 paramBlocks[name] = desc;
232 }
233
234 template struct TSHADER_DESC<false>;
235 template struct TSHADER_DESC<true>;
236
237 template<bool Core>
238 TShader<Core>::TShader(UINT32 id)
239 :mId(id)
240 { }
241
242 template<bool Core>
243 TShader<Core>::TShader(const String& name, const TSHADER_DESC<Core>& desc, UINT32 id)
244 :mName(name), mDesc(desc), mId(id)
245 { }
246
247 template<bool Core>
248 TShader<Core>::~TShader()
249 { }
250
251 template<bool Core>
252 GpuParamType TShader<Core>::getParamType(const String& name) const
253 {
254 auto findIterData = mDesc.dataParams.find(name);
255 if (findIterData != mDesc.dataParams.end())
256 return GPT_DATA;
257
258 auto findIterTexture = mDesc.textureParams.find(name);
259 if (findIterTexture != mDesc.textureParams.end())
260 return GPT_TEXTURE;
261
262 auto findIterBuffer = mDesc.bufferParams.find(name);
263 if (findIterBuffer != mDesc.bufferParams.end())
264 return GPT_BUFFER;
265
266 auto findIterSampler = mDesc.samplerParams.find(name);
267 if (findIterSampler != mDesc.samplerParams.end())
268 return GPT_SAMPLER;
269
270 BS_EXCEPT(InternalErrorException, "Cannot find the parameter with the name: " + name);
271 return GPT_DATA;
272 }
273
274 template<bool Core>
275 const SHADER_DATA_PARAM_DESC& TShader<Core>::getDataParamDesc(const String& name) const
276 {
277 auto findIterData = mDesc.dataParams.find(name);
278 if (findIterData != mDesc.dataParams.end())
279 return findIterData->second;
280
281 BS_EXCEPT(InternalErrorException, "Cannot find the parameter with the name: " + name);
282 static SHADER_DATA_PARAM_DESC dummy;
283 return dummy;
284 }
285
286 template<bool Core>
287 const SHADER_OBJECT_PARAM_DESC& TShader<Core>::getTextureParamDesc(const String& name) const
288 {
289 auto findIterObject = mDesc.textureParams.find(name);
290 if (findIterObject != mDesc.textureParams.end())
291 return findIterObject->second;
292
293 BS_EXCEPT(InternalErrorException, "Cannot find the parameter with the name: " + name);
294 static SHADER_OBJECT_PARAM_DESC dummy;
295 return dummy;
296 }
297
298 template<bool Core>
299 const SHADER_OBJECT_PARAM_DESC& TShader<Core>::getSamplerParamDesc(const String& name) const
300 {
301 auto findIterObject = mDesc.samplerParams.find(name);
302 if (findIterObject != mDesc.samplerParams.end())
303 return findIterObject->second;
304
305 BS_EXCEPT(InternalErrorException, "Cannot find the parameter with the name: " + name);
306 static SHADER_OBJECT_PARAM_DESC dummy;
307 return dummy;
308 }
309
310 template<bool Core>
311 const SHADER_OBJECT_PARAM_DESC& TShader<Core>::getBufferParamDesc(const String& name) const
312 {
313 auto findIterObject = mDesc.bufferParams.find(name);
314 if (findIterObject != mDesc.bufferParams.end())
315 return findIterObject->second;
316
317 BS_EXCEPT(InternalErrorException, "Cannot find the parameter with the name: " + name);
318 static SHADER_OBJECT_PARAM_DESC dummy;
319 return dummy;
320 }
321
322 template<bool Core>
323 bool TShader<Core>::hasDataParam(const String& name) const
324 {
325 auto findIterData = mDesc.dataParams.find(name);
326 if (findIterData != mDesc.dataParams.end())
327 return true;
328
329 return false;
330 }
331
332 template<bool Core>
333 bool TShader<Core>::hasTextureParam(const String& name) const
334 {
335 auto findIterObject = mDesc.textureParams.find(name);
336 if (findIterObject != mDesc.textureParams.end())
337 return true;
338
339 return false;
340 }
341
342 template<bool Core>
343 bool TShader<Core>::hasSamplerParam(const String& name) const
344 {
345 auto findIterObject = mDesc.samplerParams.find(name);
346 if (findIterObject != mDesc.samplerParams.end())
347 return true;
348
349 return false;
350 }
351
352 template<bool Core>
353 bool TShader<Core>::hasBufferParam(const String& name) const
354 {
355 auto findIterObject = mDesc.bufferParams.find(name);
356 if (findIterObject != mDesc.bufferParams.end())
357 return true;
358
359 return false;
360 }
361
362 template<bool Core>
363 bool TShader<Core>::hasParamBlock(const String& name) const
364 {
365 auto findIterObject = mDesc.paramBlocks.find(name);
366 if (findIterObject != mDesc.paramBlocks.end())
367 return true;
368
369 return false;
370 }
371
372 template<bool Core>
373 typename TShader<Core>::TextureType TShader<Core>::getDefaultTexture(UINT32 index) const
374 {
375 if (index < (UINT32)mDesc.textureDefaultValues.size())
376 return mDesc.textureDefaultValues[index];
377
378 return TextureType();
379 }
380
381 template<bool Core>
382 typename TShader<Core>::SamplerStateType TShader<Core>::getDefaultSampler(UINT32 index) const
383 {
384 if (index < (UINT32)mDesc.samplerDefaultValues.size())
385 return mDesc.samplerDefaultValues[index];
386
387 return SamplerStateType();
388 }
389
390 template<bool Core>
391 UINT8* TShader<Core>::getDefaultValue(UINT32 index) const
392 {
393 if (index < (UINT32)mDesc.dataDefaultValues.size())
394 return (UINT8*)&mDesc.dataDefaultValues[index];
395
396 return nullptr;
397 }
398
399 template<bool Core>
400 Vector<SPtr<typename TShader<Core>::TechniqueType>> TShader<Core>::getCompatibleTechniques() const
401 {
402 Vector<SPtr<TechniqueType>> output;
403 for (auto& technique : mDesc.techniques)
404 {
405 if (technique->isSupported())
406 output.push_back(technique);
407 }
408
409 return output;
410 }
411
412 template<bool Core>
413 Vector<SPtr<typename TShader<Core>::TechniqueType>> TShader<Core>::getCompatibleTechniques(
414 const ShaderVariation& variation, bool exact) const
415 {
416 Vector<SPtr<TechniqueType>> output;
417 for (auto& technique : mDesc.techniques)
418 {
419 if (technique->isSupported() && technique->getVariation().matches(variation, exact))
420 output.push_back(technique);
421 }
422
423 return output;
424 }
425
426 template class TShader < false > ;
427 template class TShader < true >;
428
429 Shader::Shader(const String& name, const SHADER_DESC& desc, UINT32 id)
430 :TShader(name, desc, id)
431 {
432 mMetaData = bs_shared_ptr_new<ShaderMetaData>();
433 }
434
435 Shader::Shader(UINT32 id)
436 :TShader(id)
437 { }
438
439 SPtr<ct::Shader> Shader::getCore() const
440 {
441 return std::static_pointer_cast<ct::Shader>(mCoreSpecific);
442 }
443
444 void Shader::setIncludeFiles(const Vector<String>& includes)
445 {
446 SPtr<ShaderMetaData> meta = std::static_pointer_cast<ShaderMetaData>(getMetaData());
447 meta->includes = includes;
448 }
449
450 SPtr<ct::CoreObject> Shader::createCore() const
451 {
452 Vector<SPtr<ct::Technique>> techniques;
453 for (auto& technique : mDesc.techniques)
454 techniques.push_back(technique->getCore());
455
456 ct::Shader* shaderCore = new (bs_alloc<ct::Shader>()) ct::Shader(mName, convertDesc(mDesc), mId);
457 SPtr<ct::Shader> shaderCorePtr = bs_shared_ptr<ct::Shader>(shaderCore);
458 shaderCorePtr->_setThisPtr(shaderCorePtr);
459
460 return shaderCorePtr;
461 }
462
463 ct::SHADER_DESC Shader::convertDesc(const SHADER_DESC& desc) const
464 {
465 ct::SHADER_DESC output;
466 output.dataParams = desc.dataParams;
467 output.textureParams = desc.textureParams;
468 output.samplerParams = desc.samplerParams;
469 output.bufferParams = desc.bufferParams;
470 output.paramBlocks = desc.paramBlocks;
471 output.paramAttributes = desc.paramAttributes;
472
473 output.dataDefaultValues = desc.dataDefaultValues;
474
475 output.samplerDefaultValues.resize(desc.samplerDefaultValues.size());
476 for (UINT32 i = 0; i < (UINT32)desc.samplerDefaultValues.size(); i++)
477 {
478 if (desc.samplerDefaultValues[i] != nullptr)
479 output.samplerDefaultValues[i] = desc.samplerDefaultValues[i]->getCore();
480 else
481 output.samplerDefaultValues[i] = nullptr;
482 }
483
484 output.textureDefaultValues.resize(desc.textureDefaultValues.size());
485 for (UINT32 i = 0; i < (UINT32)desc.textureDefaultValues.size(); i++)
486 {
487 if (desc.textureDefaultValues[i].isLoaded())
488 output.textureDefaultValues[i] = desc.textureDefaultValues[i]->getCore();
489 else
490 output.textureDefaultValues[i] = nullptr;
491 }
492
493 output.queuePriority = desc.queuePriority;
494 output.queueSortType = desc.queueSortType;
495 output.separablePasses = desc.separablePasses;
496 output.flags = desc.flags;
497
498 for(auto& entry : desc.techniques)
499 {
500 if(entry)
501 output.techniques.push_back(entry->getCore());
502 }
503
504 for(auto& entry : desc.subShaders)
505 {
506 ct::SubShader subShader;
507 subShader.name = entry.name;
508
509 if(entry.shader)
510 subShader.shader = entry.shader->getCore();
511
512 output.subShaders.push_back(subShader);
513 }
514
515 output.variationParams = desc.variationParams;
516
517 // Ignoring default values as they are not needed for syncing since
518 // they're initialized through the material.
519 return output;
520 }
521
522 void Shader::getCoreDependencies(Vector<CoreObject*>& dependencies)
523 {
524 for (auto& technique : mDesc.techniques)
525 dependencies.push_back(technique.get());
526 }
527
528 bool Shader::isSampler(GpuParamObjectType type)
529 {
530 switch(type)
531 {
532 case GPOT_SAMPLER1D:
533 case GPOT_SAMPLER2D:
534 case GPOT_SAMPLER3D:
535 case GPOT_SAMPLERCUBE:
536 case GPOT_SAMPLER2DMS:
537 return true;
538 default:
539 return false;
540 }
541 }
542
543 bool Shader::isTexture(GpuParamObjectType type)
544 {
545 switch(type)
546 {
547 case GPOT_TEXTURE1D:
548 case GPOT_TEXTURE2D:
549 case GPOT_TEXTURE3D:
550 case GPOT_TEXTURECUBE:
551 case GPOT_TEXTURE2DMS:
552 case GPOT_TEXTURE1DARRAY:
553 case GPOT_TEXTURE2DARRAY:
554 case GPOT_TEXTURE2DMSARRAY:
555 case GPOT_TEXTURECUBEARRAY:
556 return true;
557 default:
558 return false;
559 }
560 }
561
562 bool Shader::isLoadStoreTexture(GpuParamObjectType type)
563 {
564 switch (type)
565 {
566 case GPOT_RWTEXTURE1D:
567 case GPOT_RWTEXTURE2D:
568 case GPOT_RWTEXTURE3D:
569 case GPOT_RWTEXTURE2DMS:
570 case GPOT_RWTEXTURE1DARRAY:
571 case GPOT_RWTEXTURE2DARRAY:
572 case GPOT_RWTEXTURE2DMSARRAY:
573 return true;
574 default:
575 return false;
576 }
577 }
578
579 bool Shader::isBuffer(GpuParamObjectType type)
580 {
581 switch(type)
582 {
583 case GPOT_BYTE_BUFFER:
584 case GPOT_STRUCTURED_BUFFER:
585 case GPOT_RWBYTE_BUFFER:
586 case GPOT_RWAPPEND_BUFFER:
587 case GPOT_RWCONSUME_BUFFER:
588 case GPOT_RWSTRUCTURED_BUFFER:
589 case GPOT_RWSTRUCTURED_BUFFER_WITH_COUNTER:
590 case GPOT_RWTYPED_BUFFER:
591 return true;
592 default:
593 return false;
594 }
595 }
596
597 UINT32 Shader::getDataParamSize(GpuParamDataType type)
598 {
599 static const GpuDataParamInfos PARAM_SIZES;
600
601 UINT32 idx = (UINT32)type;
602 if (idx < sizeof(GpuParams::PARAM_SIZES.lookup))
603 return GpuParams::PARAM_SIZES.lookup[idx].size;
604
605 return 0;
606 }
607
608 HShader Shader::create(const String& name, const SHADER_DESC& desc)
609 {
610 SPtr<Shader> newShader = _createPtr(name, desc);
611
612 return static_resource_cast<Shader>(gResources()._createResourceHandle(newShader));
613 }
614
615 SPtr<Shader> Shader::_createPtr(const String& name, const SHADER_DESC& desc)
616 {
617 UINT32 id = ct::Shader::mNextShaderId.fetch_add(1, std::memory_order_relaxed);
618 assert(id < std::numeric_limits<UINT32>::max() && "Created too many shaders, reached maximum id.");
619
620 SPtr<Shader> newShader = bs_core_ptr<Shader>(new (bs_alloc<Shader>()) Shader(name, desc, id));
621 newShader->_setThisPtr(newShader);
622 newShader->initialize();
623
624 return newShader;
625 }
626
627 SPtr<Shader> Shader::createEmpty()
628 {
629 UINT32 id = ct::Shader::mNextShaderId.fetch_add(1, std::memory_order_relaxed);
630 assert(id < std::numeric_limits<UINT32>::max() && "Created too many shaders, reached maximum id.");
631
632 SPtr<Shader> newShader = bs_core_ptr<Shader>(new (bs_alloc<Shader>()) Shader(id));
633 newShader->_setThisPtr(newShader);
634
635 return newShader;
636 }
637
638 RTTITypeBase* Shader::getRTTIStatic()
639 {
640 return ShaderRTTI::instance();
641 }
642
643 RTTITypeBase* Shader::getRTTI() const
644 {
645 return Shader::getRTTIStatic();
646 }
647
648 RTTITypeBase* ShaderMetaData::getRTTIStatic()
649 {
650 return ShaderMetaDataRTTI::instance();
651 }
652
653 RTTITypeBase* ShaderMetaData::getRTTI() const
654 {
655 return ShaderMetaData::getRTTIStatic();
656 }
657
658 namespace ct
659 {
660 std::atomic<UINT32> Shader::mNextShaderId;
661
662 Shader::Shader(const String& name, const SHADER_DESC& desc, UINT32 id)
663 :TShader(name, desc, id)
664 {
665
666 }
667
668 SPtr<Shader> Shader::create(const String& name, const SHADER_DESC& desc)
669 {
670 UINT32 id = mNextShaderId.fetch_add(1, std::memory_order_relaxed);
671 assert(id < std::numeric_limits<UINT32>::max() && "Created too many shaders, reached maximum id.");
672
673 Shader* shaderCore = new (bs_alloc<Shader>()) Shader(name, desc, id);
674 SPtr<Shader> shaderCorePtr = bs_shared_ptr<Shader>(shaderCore);
675 shaderCorePtr->_setThisPtr(shaderCorePtr);
676 shaderCorePtr->initialize();
677
678 return shaderCorePtr;
679 }
680 }
681}