BsMaterial.cpp 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081
  1. #include "BsMaterial.h"
  2. #include "BsException.h"
  3. #include "BsShader.h"
  4. #include "BsTechnique.h"
  5. #include "BsPass.h"
  6. #include "BsRenderAPI.h"
  7. #include "BsHardwareBufferManager.h"
  8. #include "BsGpuProgram.h"
  9. #include "BsGpuParamBlockBuffer.h"
  10. #include "BsGpuParamDesc.h"
  11. #include "BsMaterialRTTI.h"
  12. #include "BsMaterialManager.h"
  13. #include "BsDebug.h"
  14. #include "BsResources.h"
  15. #include "BsFrameAlloc.h"
  16. namespace BansheeEngine
  17. {
  18. struct ShaderBlockDesc
  19. {
  20. String name;
  21. GpuParamBlockUsage usage;
  22. int size;
  23. bool create;
  24. };
  25. enum MaterialLoadFlags
  26. {
  27. Load_None = 0,
  28. Load_Shader = 1,
  29. Load_All = 2
  30. };
  31. SPtr<PassParametersCore> convertParamsToCore(const SPtr<PassParameters>& passParams)
  32. {
  33. SPtr<PassParametersCore> passParameters = bs_shared_ptr<PassParametersCore>();
  34. if (passParams->mVertParams != nullptr)
  35. passParameters->mVertParams = passParams->mVertParams->getCore();
  36. else
  37. passParameters->mVertParams = nullptr;
  38. if (passParams->mFragParams != nullptr)
  39. passParameters->mFragParams = passParams->mFragParams->getCore();
  40. else
  41. passParameters->mFragParams = nullptr;
  42. if (passParams->mGeomParams != nullptr)
  43. passParameters->mGeomParams = passParams->mGeomParams->getCore();
  44. else
  45. passParameters->mGeomParams = nullptr;
  46. if (passParams->mHullParams != nullptr)
  47. passParameters->mHullParams = passParams->mHullParams->getCore();
  48. else
  49. passParameters->mHullParams = nullptr;
  50. if (passParams->mDomainParams != nullptr)
  51. passParameters->mDomainParams = passParams->mDomainParams->getCore();
  52. else
  53. passParameters->mDomainParams = nullptr;
  54. if (passParams->mComputeParams != nullptr)
  55. passParameters->mComputeParams = passParams->mComputeParams->getCore();
  56. else
  57. passParameters->mComputeParams = nullptr;
  58. return passParameters;
  59. }
  60. bool areParamsEqual(const GpuParamDataDesc& paramA, const GpuParamDataDesc& paramB, bool ignoreBufferOffsets)
  61. {
  62. bool equal = paramA.arraySize == paramB.arraySize && paramA.elementSize == paramB.elementSize
  63. && paramA.type == paramB.type && paramA.arrayElementStride == paramB.arrayElementStride;
  64. if (!ignoreBufferOffsets)
  65. equal &= paramA.cpuMemOffset == paramB.cpuMemOffset && paramA.gpuMemOffset == paramB.gpuMemOffset;
  66. return equal;
  67. }
  68. Map<String, const GpuParamDataDesc*> determineValidDataParameters(const Vector<GpuParamDescPtr>& paramDescs)
  69. {
  70. Map<String, const GpuParamDataDesc*> foundDataParams;
  71. Map<String, bool> validParams;
  72. for (auto iter = paramDescs.begin(); iter != paramDescs.end(); ++iter)
  73. {
  74. const GpuParamDesc& curDesc = **iter;
  75. // Check regular data params
  76. for (auto iter2 = curDesc.params.begin(); iter2 != curDesc.params.end(); ++iter2)
  77. {
  78. bool isParameterValid = true;
  79. const GpuParamDataDesc& curParam = iter2->second;
  80. auto dataFindIter = validParams.find(iter2->first);
  81. if (dataFindIter == validParams.end())
  82. {
  83. validParams[iter2->first] = true;
  84. foundDataParams[iter2->first] = &curParam;
  85. }
  86. else
  87. {
  88. if (validParams[iter2->first])
  89. {
  90. auto dataFindIter2 = foundDataParams.find(iter2->first);
  91. const GpuParamDataDesc* otherParam = dataFindIter2->second;
  92. if (!areParamsEqual(curParam, *otherParam, true))
  93. {
  94. validParams[iter2->first] = false;
  95. foundDataParams.erase(dataFindIter2);
  96. }
  97. }
  98. }
  99. }
  100. }
  101. return foundDataParams;
  102. }
  103. Vector<const GpuParamObjectDesc*> determineValidObjectParameters(const Vector<GpuParamDescPtr>& paramDescs)
  104. {
  105. Vector<const GpuParamObjectDesc*> validParams;
  106. for (auto iter = paramDescs.begin(); iter != paramDescs.end(); ++iter)
  107. {
  108. const GpuParamDesc& curDesc = **iter;
  109. // Check sampler params
  110. for (auto iter2 = curDesc.samplers.begin(); iter2 != curDesc.samplers.end(); ++iter2)
  111. {
  112. validParams.push_back(&iter2->second);
  113. }
  114. // Check texture params
  115. for (auto iter2 = curDesc.textures.begin(); iter2 != curDesc.textures.end(); ++iter2)
  116. {
  117. validParams.push_back(&iter2->second);
  118. }
  119. // Check buffer params
  120. for (auto iter2 = curDesc.buffers.begin(); iter2 != curDesc.buffers.end(); ++iter2)
  121. {
  122. validParams.push_back(&iter2->second);
  123. }
  124. }
  125. return validParams;
  126. }
  127. Set<String> determineValidShareableParamBlocks(const Vector<GpuParamDescPtr>& paramDescs)
  128. {
  129. // Make sure param blocks with the same name actually are the same
  130. Map<String, std::pair<String, GpuParamDescPtr>> uniqueParamBlocks;
  131. Map<String, bool> validParamBlocks;
  132. for (auto iter = paramDescs.begin(); iter != paramDescs.end(); ++iter)
  133. {
  134. const GpuParamDesc& curDesc = **iter;
  135. for (auto blockIter = curDesc.paramBlocks.begin(); blockIter != curDesc.paramBlocks.end(); ++blockIter)
  136. {
  137. bool isBlockValid = true;
  138. const GpuParamBlockDesc& curBlock = blockIter->second;
  139. if (!curBlock.isShareable) // Non-shareable buffers are handled differently, they're allowed same names
  140. continue;
  141. auto iterFind = uniqueParamBlocks.find(blockIter->first);
  142. if (iterFind == uniqueParamBlocks.end())
  143. {
  144. uniqueParamBlocks[blockIter->first] = std::make_pair(blockIter->first, *iter);
  145. validParamBlocks[blockIter->first] = true;
  146. continue;
  147. }
  148. String otherBlockName = iterFind->second.first;
  149. GpuParamDescPtr otherDesc = iterFind->second.second;
  150. for (auto myParamIter = curDesc.params.begin(); myParamIter != curDesc.params.end(); ++myParamIter)
  151. {
  152. const GpuParamDataDesc& myParam = myParamIter->second;
  153. if (myParam.paramBlockSlot != curBlock.slot)
  154. continue; // Param is in another block, so we will check it when its time for that block
  155. auto otherParamFind = otherDesc->params.find(myParamIter->first);
  156. // Cannot find other param, blocks aren't equal
  157. if (otherParamFind == otherDesc->params.end())
  158. {
  159. isBlockValid = false;
  160. break;
  161. }
  162. const GpuParamDataDesc& otherParam = otherParamFind->second;
  163. if (!areParamsEqual(myParam, otherParam, false) || curBlock.name != otherBlockName)
  164. {
  165. isBlockValid = false;
  166. break;
  167. }
  168. }
  169. if (!isBlockValid)
  170. {
  171. if (validParamBlocks[blockIter->first])
  172. {
  173. LOGWRN("Found two param blocks with the same name but different contents: " + blockIter->first);
  174. validParamBlocks[blockIter->first] = false;
  175. }
  176. }
  177. }
  178. }
  179. Set<String> validParamBlocksReturn;
  180. for (auto iter = validParamBlocks.begin(); iter != validParamBlocks.end(); ++iter)
  181. {
  182. if (iter->second)
  183. validParamBlocksReturn.insert(iter->first);
  184. }
  185. return validParamBlocksReturn;
  186. }
  187. Map<String, String> determineParameterToBlockMapping(const Vector<GpuParamDescPtr>& paramDescs)
  188. {
  189. Map<String, String> paramToParamBlock;
  190. for (auto iter = paramDescs.begin(); iter != paramDescs.end(); ++iter)
  191. {
  192. const GpuParamDesc& curDesc = **iter;
  193. for (auto iter2 = curDesc.params.begin(); iter2 != curDesc.params.end(); ++iter2)
  194. {
  195. const GpuParamDataDesc& curParam = iter2->second;
  196. auto iterFind = paramToParamBlock.find(curParam.name);
  197. if (iterFind != paramToParamBlock.end())
  198. continue;
  199. for (auto iterBlock = curDesc.paramBlocks.begin(); iterBlock != curDesc.paramBlocks.end(); ++iterBlock)
  200. {
  201. if (iterBlock->second.slot == curParam.paramBlockSlot)
  202. {
  203. paramToParamBlock[curParam.name] = iterBlock->second.name;
  204. break;
  205. }
  206. }
  207. }
  208. }
  209. return paramToParamBlock;
  210. }
  211. Map<String, String> determineParamMappings(const Vector<GpuParamDescPtr>& paramDescs, const Map<String, SHADER_DATA_PARAM_DESC>& dataParams,
  212. const Map<String, SHADER_OBJECT_PARAM_DESC>& objectParam)
  213. {
  214. Map<String, String> validParams;
  215. Map<String, const GpuParamDataDesc*> validDataParameters = determineValidDataParameters(paramDescs);
  216. Vector<const GpuParamObjectDesc*> validObjectParameters = determineValidObjectParameters(paramDescs);
  217. Map<String, String> paramToParamBlockMap = determineParameterToBlockMapping(paramDescs);
  218. // Create data param mappings
  219. for (auto iter = dataParams.begin(); iter != dataParams.end(); ++iter)
  220. {
  221. auto findIter = validDataParameters.find(iter->second.gpuVariableName);
  222. // Not valid so we skip it
  223. if (findIter == validDataParameters.end())
  224. continue;
  225. if (findIter->second->type != iter->second.type)
  226. {
  227. LOGWRN("Ignoring shader parameter \"" + iter->first + "\". Type doesn't match the one defined in the gpu program. "
  228. + "Shader defined type: " + toString(iter->second.type) + " - Gpu program defined type: " + toString(findIter->second->type));
  229. continue;
  230. }
  231. if (findIter->second->arraySize != iter->second.arraySize)
  232. {
  233. LOGWRN("Ignoring shader parameter \"" + iter->first + "\". Array size doesn't match the one defined in the gpu program."
  234. + "Shader defined array size: " + toString(iter->second.arraySize) + " - Gpu program defined array size: " + toString(findIter->second->arraySize));
  235. continue;
  236. }
  237. auto findBlockIter = paramToParamBlockMap.find(iter->second.gpuVariableName);
  238. if (findBlockIter == paramToParamBlockMap.end())
  239. BS_EXCEPT(InternalErrorException, "Parameter doesn't exist in param to param block map but exists in valid param map.");
  240. String& paramBlockName = findBlockIter->second;
  241. validParams[iter->first] = iter->second.gpuVariableName;
  242. }
  243. // Create object param mappings
  244. for (auto iter = objectParam.begin(); iter != objectParam.end(); ++iter)
  245. {
  246. const Vector<String>& gpuVariableNames = iter->second.gpuVariableNames;
  247. for (auto iter2 = gpuVariableNames.begin(); iter2 != gpuVariableNames.end(); ++iter2)
  248. {
  249. for (auto iter3 = validObjectParameters.begin(); iter3 != validObjectParameters.end(); ++iter3)
  250. {
  251. if ((*iter3)->name == (*iter2) && (*iter3)->type == iter->second.type)
  252. {
  253. validParams[iter->first] = *iter2;
  254. break;
  255. }
  256. }
  257. }
  258. }
  259. return validParams;
  260. }
  261. Vector<ShaderBlockDesc> determineShaderBlockData(const Set<String>& paramBlocks, const Vector<GpuParamDescPtr>& paramDescs,
  262. const Map<String, SHADER_PARAM_BLOCK_DESC>& shaderDesc)
  263. {
  264. Vector<ShaderBlockDesc> output;
  265. for (auto iter = paramBlocks.begin(); iter != paramBlocks.end(); ++iter)
  266. {
  267. ShaderBlockDesc shaderBlockDesc;
  268. shaderBlockDesc.create = true;
  269. shaderBlockDesc.usage = GPBU_STATIC;
  270. shaderBlockDesc.size = 0;
  271. shaderBlockDesc.name = *iter;
  272. auto iterFind = shaderDesc.find(*iter);
  273. if (iterFind != shaderDesc.end())
  274. {
  275. shaderBlockDesc.create = !iterFind->second.shared && iterFind->second.rendererSemantic == StringID::NONE;
  276. shaderBlockDesc.usage = iterFind->second.usage;
  277. }
  278. for (auto iter2 = paramDescs.begin(); iter2 != paramDescs.end(); ++iter2)
  279. {
  280. auto findParamBlockDesc = (*iter2)->paramBlocks.find(*iter);
  281. if (findParamBlockDesc != (*iter2)->paramBlocks.end())
  282. {
  283. shaderBlockDesc.size = findParamBlockDesc->second.blockSize * sizeof(UINT32);
  284. break;
  285. }
  286. }
  287. output.push_back(shaderBlockDesc);
  288. }
  289. return output;
  290. }
  291. Vector<GpuParamDescPtr> MaterialBase::getAllParamDescs(const SPtr<Technique>& technique)
  292. {
  293. Vector<GpuParamDescPtr> allParamDescs;
  294. // Make sure all gpu programs are fully loaded
  295. for (UINT32 i = 0; i < technique->getNumPasses(); i++)
  296. {
  297. PassPtr curPass = technique->getPass(i);
  298. GpuProgramPtr vertProgram = curPass->getVertexProgram();
  299. if (vertProgram)
  300. {
  301. vertProgram->blockUntilCoreInitialized();
  302. allParamDescs.push_back(vertProgram->getParamDesc());
  303. }
  304. GpuProgramPtr fragProgram = curPass->getFragmentProgram();
  305. if (fragProgram)
  306. {
  307. fragProgram->blockUntilCoreInitialized();
  308. allParamDescs.push_back(fragProgram->getParamDesc());
  309. }
  310. GpuProgramPtr geomProgram = curPass->getGeometryProgram();
  311. if (geomProgram)
  312. {
  313. geomProgram->blockUntilCoreInitialized();
  314. allParamDescs.push_back(geomProgram->getParamDesc());
  315. }
  316. GpuProgramPtr hullProgram = curPass->getHullProgram();
  317. if (hullProgram)
  318. {
  319. hullProgram->blockUntilCoreInitialized();
  320. allParamDescs.push_back(hullProgram->getParamDesc());
  321. }
  322. GpuProgramPtr domainProgram = curPass->getDomainProgram();
  323. if (domainProgram)
  324. {
  325. domainProgram->blockUntilCoreInitialized();
  326. allParamDescs.push_back(domainProgram->getParamDesc());
  327. }
  328. GpuProgramPtr computeProgram = curPass->getComputeProgram();
  329. if (computeProgram)
  330. {
  331. computeProgram->blockUntilCoreInitialized();
  332. allParamDescs.push_back(computeProgram->getParamDesc());
  333. }
  334. }
  335. return allParamDescs;
  336. }
  337. Vector<GpuParamDescPtr> MaterialBase::getAllParamDescs(const SPtr<TechniqueCore>& technique)
  338. {
  339. Vector<GpuParamDescPtr> allParamDescs;
  340. // Make sure all gpu programs are fully loaded
  341. for (UINT32 i = 0; i < technique->getNumPasses(); i++)
  342. {
  343. SPtr<PassCore> curPass = technique->getPass(i);
  344. SPtr<GpuProgramCore> vertProgram = curPass->getVertexProgram();
  345. if (vertProgram)
  346. allParamDescs.push_back(vertProgram->getParamDesc());
  347. SPtr<GpuProgramCore> fragProgram = curPass->getFragmentProgram();
  348. if (fragProgram)
  349. allParamDescs.push_back(fragProgram->getParamDesc());
  350. SPtr<GpuProgramCore> geomProgram = curPass->getGeometryProgram();
  351. if (geomProgram)
  352. allParamDescs.push_back(geomProgram->getParamDesc());
  353. SPtr<GpuProgramCore> hullProgram = curPass->getHullProgram();
  354. if (hullProgram)
  355. allParamDescs.push_back(hullProgram->getParamDesc());
  356. SPtr<GpuProgramCore> domainProgram = curPass->getDomainProgram();
  357. if (domainProgram)
  358. allParamDescs.push_back(domainProgram->getParamDesc());
  359. SPtr<GpuProgramCore> computeProgram = curPass->getComputeProgram();
  360. if (computeProgram)
  361. allParamDescs.push_back(computeProgram->getParamDesc());
  362. }
  363. return allParamDescs;
  364. }
  365. template<bool Core>
  366. UINT32 TMaterial<Core>::getNumPasses() const
  367. {
  368. throwIfNotInitialized();
  369. return mShader->getBestTechnique()->getNumPasses();
  370. }
  371. template<bool Core>
  372. typename TMaterial<Core>::PassType TMaterial<Core>::getPass(UINT32 passIdx) const
  373. {
  374. if (passIdx < 0 || passIdx >= mShader->getBestTechnique()->getNumPasses())
  375. BS_EXCEPT(InvalidParametersException, "Invalid pass index.");
  376. return mShader->getBestTechnique()->getPass(passIdx);
  377. }
  378. template<bool Core>
  379. TMaterialParamStruct<Core> TMaterial<Core>::getParamStruct(const String& name) const
  380. {
  381. throwIfNotInitialized();
  382. auto iterFind = mValidParams.find(name);
  383. if (iterFind == mValidParams.end())
  384. {
  385. LOGWRN("Material doesn't have a parameter named " + name);
  386. return TMaterialParamStruct<Core>();
  387. }
  388. const String& gpuVarName = iterFind->second;
  389. Vector<TGpuParamStruct<Core>> gpuParams;
  390. for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
  391. {
  392. SPtr<TPassParameters<Core>> params = *iter;
  393. for (UINT32 i = 0; i < params->getNumParams(); i++)
  394. {
  395. GpuParamsType& paramPtr = params->getParamByIdx(i);
  396. if (paramPtr)
  397. {
  398. if (paramPtr->hasParam(gpuVarName))
  399. {
  400. gpuParams.push_back(TGpuParamStruct<Core>());
  401. paramPtr->getStructParam(gpuVarName, gpuParams.back());
  402. }
  403. }
  404. }
  405. }
  406. return TMaterialParamStruct<Core>(gpuParams);
  407. }
  408. template<bool Core>
  409. TMaterialParamTexture<Core> TMaterial<Core>::getParamTexture(const String& name) const
  410. {
  411. throwIfNotInitialized();
  412. auto iterFind = mValidParams.find(name);
  413. if (iterFind == mValidParams.end())
  414. {
  415. LOGWRN("Material doesn't have a parameter named " + name);
  416. return TMaterialParamTexture<Core>();
  417. }
  418. const String& gpuVarName = iterFind->second;
  419. Vector<TGpuParamTexture<Core>> gpuParams;
  420. for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
  421. {
  422. SPtr<TPassParameters<Core>> params = *iter;
  423. for (UINT32 i = 0; i < params->getNumParams(); i++)
  424. {
  425. GpuParamsType& paramPtr = params->getParamByIdx(i);
  426. if (paramPtr)
  427. {
  428. if (paramPtr->hasTexture(gpuVarName))
  429. {
  430. gpuParams.push_back(TGpuParamTexture<Core>());
  431. paramPtr->getTextureParam(gpuVarName, gpuParams.back());
  432. }
  433. }
  434. }
  435. }
  436. return TMaterialParamTexture<Core>(gpuParams);
  437. }
  438. template<bool Core>
  439. TMaterialParamLoadStoreTexture<Core> TMaterial<Core>::getParamLoadStoreTexture(const String& name) const
  440. {
  441. throwIfNotInitialized();
  442. auto iterFind = mValidParams.find(name);
  443. if (iterFind == mValidParams.end())
  444. {
  445. LOGWRN("Material doesn't have a parameter named " + name);
  446. return TMaterialParamLoadStoreTexture<Core>();
  447. }
  448. const String& gpuVarName = iterFind->second;
  449. Vector<TGpuParamLoadStoreTexture<Core>> gpuParams;
  450. for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
  451. {
  452. SPtr<TPassParameters<Core>> params = *iter;
  453. for (UINT32 i = 0; i < params->getNumParams(); i++)
  454. {
  455. GpuParamsType& paramPtr = params->getParamByIdx(i);
  456. if (paramPtr)
  457. {
  458. if (paramPtr->hasTexture(gpuVarName))
  459. {
  460. gpuParams.push_back(TGpuParamLoadStoreTexture<Core>());
  461. paramPtr->getLoadStoreTextureParam(gpuVarName, gpuParams.back());
  462. }
  463. }
  464. }
  465. }
  466. return TMaterialParamLoadStoreTexture<Core>(gpuParams);
  467. }
  468. template<bool Core>
  469. TMaterialParamSampState<Core> TMaterial<Core>::getParamSamplerState(const String& name) const
  470. {
  471. throwIfNotInitialized();
  472. auto iterFind = mValidParams.find(name);
  473. if (iterFind == mValidParams.end())
  474. {
  475. LOGWRN("Material doesn't have a parameter named " + name);
  476. return TMaterialParamSampState<Core>();
  477. }
  478. const String& gpuVarName = iterFind->second;
  479. Vector<TGpuParamSampState<Core>> gpuParams;
  480. for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
  481. {
  482. SPtr<TPassParameters<Core>> params = *iter;
  483. for (UINT32 i = 0; i < params->getNumParams(); i++)
  484. {
  485. GpuParamsType& paramPtr = params->getParamByIdx(i);
  486. if (paramPtr)
  487. {
  488. if (paramPtr->hasSamplerState(gpuVarName))
  489. {
  490. gpuParams.push_back(TGpuParamSampState<Core>());
  491. paramPtr->getSamplerStateParam(gpuVarName, gpuParams.back());
  492. }
  493. }
  494. }
  495. }
  496. return TMaterialParamSampState<Core>(gpuParams);
  497. }
  498. template<bool Core>
  499. void TMaterial<Core>::setParamBlockBuffer(const String& name, const ParamBlockPtrType& paramBlock)
  500. {
  501. auto iterFind = mValidShareableParamBlocks.find(name);
  502. if (iterFind == mValidShareableParamBlocks.end())
  503. {
  504. LOGWRN("Material doesn't have a parameter block named " + name);
  505. return;
  506. }
  507. for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
  508. {
  509. SPtr<TPassParameters<Core>> params = *iter;
  510. for (UINT32 i = 0; i < params->getNumParams(); i++)
  511. {
  512. GpuParamsType& paramPtr = params->getParamByIdx(i);
  513. if (paramPtr)
  514. {
  515. if (paramPtr->hasParamBlock(name))
  516. paramPtr->setParamBlockBuffer(name, paramBlock);
  517. }
  518. }
  519. }
  520. }
  521. template<bool Core>
  522. void TMaterial<Core>::initBestTechnique()
  523. {
  524. mBestTechnique = nullptr;
  525. mParametersPerPass.clear();
  526. if (mShader)
  527. {
  528. mBestTechnique = mShader->getBestTechnique();
  529. if (mBestTechnique == nullptr)
  530. return;
  531. mValidShareableParamBlocks.clear();
  532. Vector<GpuParamDescPtr> allParamDescs = getAllParamDescs(mBestTechnique);
  533. mValidParams = determineParamMappings(allParamDescs, mShader->getDataParams(), mShader->getObjectParams());
  534. // Fill out various helper structures
  535. Set<String> validShareableParamBlocks = determineValidShareableParamBlocks(allParamDescs);
  536. Vector<ShaderBlockDesc> paramBlockData = determineShaderBlockData(validShareableParamBlocks, allParamDescs, mShader->getParamBlocks());
  537. Map<String, ParamBlockPtrType> paramBlockBuffers;
  538. // Create param blocks
  539. for (auto& paramBlock : paramBlockData)
  540. {
  541. ParamBlockPtrType newParamBlockBuffer;
  542. if (paramBlock.create)
  543. {
  544. newParamBlockBuffer = ParamBlockType::create(paramBlock.size, paramBlock.usage);
  545. }
  546. paramBlockBuffers[paramBlock.name] = newParamBlockBuffer;
  547. mValidShareableParamBlocks.insert(paramBlock.name);
  548. }
  549. for (UINT32 i = 0; i < mBestTechnique->getNumPasses(); i++)
  550. {
  551. PassType curPass = mBestTechnique->getPass(i);
  552. SPtr<TPassParameters<Core>> params = SPtr<TPassParameters<Core>>(new TPassParameters<Core>());
  553. GpuProgramType vertProgram = curPass->getVertexProgram();
  554. if (vertProgram)
  555. params->mVertParams = vertProgram->createParameters();
  556. GpuProgramType fragProgram = curPass->getFragmentProgram();
  557. if (fragProgram)
  558. params->mFragParams = fragProgram->createParameters();
  559. GpuProgramType geomProgram = curPass->getGeometryProgram();
  560. if (geomProgram)
  561. params->mGeomParams = geomProgram->createParameters();
  562. GpuProgramType hullProgram = curPass->getHullProgram();
  563. if (hullProgram)
  564. params->mHullParams = hullProgram->createParameters();
  565. GpuProgramType domainProgram = curPass->getDomainProgram();
  566. if (domainProgram)
  567. params->mDomainParams = domainProgram->createParameters();
  568. GpuProgramType computeProgram = curPass->getComputeProgram();
  569. if (computeProgram)
  570. params->mComputeParams = computeProgram->createParameters();
  571. mParametersPerPass.push_back(params);
  572. }
  573. // Assign param block buffers
  574. for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
  575. {
  576. SPtr<TPassParameters<Core>> params = *iter;
  577. for (UINT32 i = 0; i < params->getNumParams(); i++)
  578. {
  579. GpuParamsType& paramPtr = params->getParamByIdx(i);
  580. if (paramPtr)
  581. {
  582. // Assign shareable buffers
  583. for (auto iterBlock = mValidShareableParamBlocks.begin(); iterBlock != mValidShareableParamBlocks.end(); ++iterBlock)
  584. {
  585. const String& paramBlockName = *iterBlock;
  586. if (paramPtr->hasParamBlock(paramBlockName))
  587. {
  588. ParamBlockPtrType blockBuffer = paramBlockBuffers[paramBlockName];
  589. paramPtr->setParamBlockBuffer(paramBlockName, blockBuffer);
  590. }
  591. }
  592. // Create non-shareable ones
  593. const GpuParamDesc& desc = paramPtr->getParamDesc();
  594. for (auto iterBlockDesc = desc.paramBlocks.begin(); iterBlockDesc != desc.paramBlocks.end(); ++iterBlockDesc)
  595. {
  596. if (!iterBlockDesc->second.isShareable)
  597. {
  598. ParamBlockPtrType newParamBlockBuffer = ParamBlockType::create(iterBlockDesc->second.blockSize * sizeof(UINT32));
  599. paramPtr->setParamBlockBuffer(iterBlockDesc->first, newParamBlockBuffer);
  600. }
  601. }
  602. }
  603. }
  604. }
  605. }
  606. }
  607. template <bool Core>
  608. template <typename T>
  609. void TMaterial<Core>::getParam(const String& name, TMaterialDataParam<T, Core>& output) const
  610. {
  611. throwIfNotInitialized();
  612. auto iterFind = mValidParams.find(name);
  613. if (iterFind == mValidParams.end())
  614. {
  615. LOGWRN("Material doesn't have a parameter named " + name);
  616. return;
  617. }
  618. const String& gpuVarName = iterFind->second;
  619. Vector<TGpuDataParam<T, Core>> gpuParams;
  620. for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
  621. {
  622. SPtr<TPassParameters<Core>> params = *iter;
  623. for (UINT32 i = 0; i < params->getNumParams(); i++)
  624. {
  625. GpuParamsType& paramPtr = params->getParamByIdx(i);
  626. if (paramPtr)
  627. {
  628. if (paramPtr->hasParam(gpuVarName))
  629. {
  630. gpuParams.push_back(TGpuDataParam<T, Core>());
  631. paramPtr->getParam<T>(gpuVarName, gpuParams.back());
  632. }
  633. }
  634. }
  635. }
  636. output = TMaterialDataParam<T, Core>(gpuParams);
  637. }
  638. template<bool Core>
  639. void TMaterial<Core>::throwIfNotInitialized() const
  640. {
  641. if (mShader == nullptr)
  642. {
  643. BS_EXCEPT(InternalErrorException, "Material does not have shader set.");
  644. }
  645. if (mBestTechnique == nullptr)
  646. {
  647. BS_EXCEPT(InternalErrorException, "Shader does not contain a supported technique.");
  648. }
  649. }
  650. template class TMaterial < false > ;
  651. template class TMaterial < true > ;
  652. template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<float, false>&) const;
  653. template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Color, false>&) const;
  654. template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Vector2, false>&) const;
  655. template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Vector3, false>&) const;
  656. template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Vector4, false>&) const;
  657. template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Matrix3, false>&) const;
  658. template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Matrix4, false>&) const;
  659. template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<float, true>&) const;
  660. template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Color, true>&) const;
  661. template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Vector2, true>&) const;
  662. template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Vector3, true>&) const;
  663. template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Vector4, true>&) const;
  664. template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Matrix3, true>&) const;
  665. template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Matrix4, true>&) const;
  666. MaterialCore::MaterialCore(const SPtr<ShaderCore>& shader)
  667. {
  668. setShader(shader);
  669. }
  670. MaterialCore::MaterialCore(const SPtr<ShaderCore>& shader, const SPtr<TechniqueCore>& bestTechnique,
  671. const Set<String>& validShareableParamBlocks, const Map<String, String>& validParams,
  672. const Vector<SPtr<PassParametersCore>>& passParams)
  673. {
  674. mShader = shader;
  675. mBestTechnique = bestTechnique;
  676. mValidShareableParamBlocks = validShareableParamBlocks;
  677. mValidParams = validParams;
  678. mParametersPerPass = passParams;
  679. }
  680. void MaterialCore::setShader(const SPtr<ShaderCore>& shader)
  681. {
  682. mShader = shader;
  683. initBestTechnique();
  684. _markCoreDirty();
  685. }
  686. void MaterialCore::syncToCore(const CoreSyncData& data)
  687. {
  688. char* dataPtr = (char*)data.getBuffer();
  689. mValidShareableParamBlocks.clear();
  690. mValidParams.clear();
  691. mParametersPerPass.clear();
  692. UINT32 numPasses = 0;
  693. dataPtr = rttiReadElem(mValidShareableParamBlocks, dataPtr);
  694. dataPtr = rttiReadElem(mValidParams, dataPtr);
  695. dataPtr = rttiReadElem(numPasses, dataPtr);
  696. for (UINT32 i = 0; i < numPasses; i++)
  697. {
  698. SPtr<PassParametersCore>* passParameters = (SPtr<PassParametersCore>*)dataPtr;
  699. mParametersPerPass.push_back(*passParameters);
  700. passParameters->~SPtr<PassParametersCore>();
  701. dataPtr += sizeof(SPtr<PassParametersCore>);
  702. }
  703. SPtr<ShaderCore>* shader = (SPtr<ShaderCore>*)dataPtr;
  704. mShader = *shader;
  705. shader->~SPtr<ShaderCore>();
  706. dataPtr += sizeof(SPtr<ShaderCore>);
  707. SPtr<TechniqueCore>* technique = (SPtr<TechniqueCore>*)dataPtr;
  708. mBestTechnique = *technique;
  709. technique->~SPtr<TechniqueCore>();
  710. dataPtr += sizeof(SPtr<TechniqueCore>);
  711. }
  712. SPtr<MaterialCore> MaterialCore::create(const SPtr<ShaderCore>& shader)
  713. {
  714. MaterialCore* material = new (bs_alloc<MaterialCore>()) MaterialCore(shader);
  715. SPtr<MaterialCore> materialPtr = bs_shared_ptr<MaterialCore, GenAlloc>(material);
  716. materialPtr->_setThisPtr(materialPtr);
  717. materialPtr->initialize();
  718. return materialPtr;
  719. }
  720. Material::Material()
  721. :mLoadFlags(Load_None)
  722. { }
  723. Material::Material(const HShader& shader)
  724. :mLoadFlags(Load_None)
  725. {
  726. mShader = shader;
  727. }
  728. void Material::initialize()
  729. {
  730. setShader(mShader); // Not calling directly in constructor because it calls virtual methods
  731. Resource::initialize();
  732. }
  733. void Material::setShader(const HShader& shader)
  734. {
  735. mShader = shader;
  736. mBestTechnique = nullptr;
  737. mLoadFlags = Load_None;
  738. _markResourcesDirty();
  739. initializeIfLoaded();
  740. }
  741. void Material::_markCoreDirty()
  742. {
  743. markCoreDirty();
  744. }
  745. void Material::_markResourcesDirty()
  746. {
  747. markListenerResourcesDirty();
  748. }
  749. SPtr<MaterialCore> Material::getCore() const
  750. {
  751. return std::static_pointer_cast<MaterialCore>(mCoreSpecific);
  752. }
  753. SPtr<CoreObjectCore> Material::createCore() const
  754. {
  755. MaterialCore* material = nullptr;
  756. SPtr<ShaderCore> shader;
  757. if (mShader != nullptr)
  758. {
  759. shader = mShader->getCore();
  760. if (mBestTechnique != nullptr)
  761. {
  762. SPtr<TechniqueCore> technique = mBestTechnique->getCore();
  763. Vector<SPtr<PassParametersCore>> passParams;
  764. for (auto& passParam : mParametersPerPass)
  765. passParams.push_back(convertParamsToCore(passParam));
  766. material = new (bs_alloc<MaterialCore>()) MaterialCore(shader, technique, mValidShareableParamBlocks, mValidParams, passParams);
  767. }
  768. }
  769. if (material == nullptr)
  770. material = new (bs_alloc<MaterialCore>()) MaterialCore(shader);
  771. SPtr<MaterialCore> materialPtr = bs_shared_ptr<MaterialCore, GenAlloc>(material);
  772. materialPtr->_setThisPtr(materialPtr);
  773. return materialPtr;
  774. }
  775. CoreSyncData Material::syncToCore(FrameAlloc* allocator)
  776. {
  777. UINT32 numPasses = (UINT32)mParametersPerPass.size();
  778. UINT32 size = sizeof(UINT32) + numPasses * sizeof(SPtr<PassParametersCore>)
  779. + sizeof(SPtr<ShaderCore>) + sizeof(SPtr<TechniqueCore>) + rttiGetElemSize(mValidShareableParamBlocks)
  780. + rttiGetElemSize(mValidParams);
  781. UINT8* buffer = allocator->alloc(size);
  782. char* dataPtr = (char*)buffer;
  783. dataPtr = rttiWriteElem(mValidShareableParamBlocks, dataPtr);
  784. dataPtr = rttiWriteElem(mValidParams, dataPtr);
  785. dataPtr = rttiWriteElem(numPasses, dataPtr);
  786. for (UINT32 i = 0; i < numPasses; i++)
  787. {
  788. SPtr<PassParametersCore>* passParameters = new (dataPtr) SPtr<PassParametersCore>();
  789. *passParameters = convertParamsToCore(mParametersPerPass[i]);
  790. dataPtr += sizeof(SPtr<PassParametersCore>);
  791. }
  792. SPtr<ShaderCore>* shader = new (dataPtr)SPtr<ShaderCore>();
  793. if (mShader != nullptr)
  794. *shader = mShader->getCore();
  795. else
  796. *shader = nullptr;
  797. dataPtr += sizeof(SPtr<ShaderCore>);
  798. SPtr<TechniqueCore>* technique = new (dataPtr)SPtr<TechniqueCore>();
  799. if (mBestTechnique != nullptr)
  800. *technique = mBestTechnique->getCore();
  801. else
  802. *technique = nullptr;
  803. dataPtr += sizeof(SPtr<TechniqueCore>);
  804. return CoreSyncData(buffer, size);
  805. }
  806. void Material::getCoreDependencies(Vector<SPtr<CoreObject>>& dependencies)
  807. {
  808. if (mShader.isLoaded())
  809. dependencies.push_back(mShader.getInternalPtr());
  810. for (auto& params : mParametersPerPass)
  811. {
  812. UINT32 numParams = params->getNumParams();
  813. for (UINT32 i = 0; i < numParams; i++)
  814. {
  815. GpuParamsPtr gpuParams = params->getParamByIdx(i);
  816. if (gpuParams != nullptr)
  817. dependencies.push_back(gpuParams);
  818. }
  819. }
  820. }
  821. void Material::getListenerResources(Vector<HResource>& resources)
  822. {
  823. if (mShader != nullptr)
  824. resources.push_back(mShader);
  825. }
  826. void Material::getResourceDependencies(Vector<HResource>& dependencies) const
  827. {
  828. if (mShader != nullptr)
  829. dependencies.push_back(mShader);
  830. }
  831. void Material::initializeIfLoaded()
  832. {
  833. if (areDependenciesLoaded())
  834. {
  835. if (mLoadFlags != Load_All)
  836. {
  837. mLoadFlags = Load_All;
  838. initBestTechnique();
  839. markCoreDirty();
  840. }
  841. }
  842. else
  843. {
  844. if (mShader.isLoaded() && mLoadFlags == Load_None)
  845. {
  846. mLoadFlags = Load_Shader;
  847. markListenerResourcesDirty(); // Need to register resources dependent on shader now
  848. }
  849. }
  850. }
  851. void Material::notifyResourceLoaded(const HResource& resource)
  852. {
  853. initializeIfLoaded();
  854. }
  855. void Material::notifyResourceDestroyed(const HResource& resource)
  856. {
  857. initializeIfLoaded();
  858. }
  859. void Material::notifyResourceChanged(const HResource& resource)
  860. {
  861. initializeIfLoaded();
  862. }
  863. HMaterial Material::create()
  864. {
  865. MaterialPtr materialPtr = MaterialManager::instance().create();
  866. return static_resource_cast<Material>(gResources()._createResourceHandle(materialPtr));
  867. }
  868. HMaterial Material::create(const HShader& shader)
  869. {
  870. MaterialPtr materialPtr = MaterialManager::instance().create(shader);
  871. return static_resource_cast<Material>(gResources()._createResourceHandle(materialPtr));
  872. }
  873. RTTITypeBase* Material::getRTTIStatic()
  874. {
  875. return MaterialRTTI::instance();
  876. }
  877. RTTITypeBase* Material::getRTTI() const
  878. {
  879. return Material::getRTTIStatic();
  880. }
  881. }