BsMaterial.cpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140
  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 == 0;
  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. HGpuProgram vertProgram = curPass->getVertexProgram();
  299. if (vertProgram)
  300. {
  301. vertProgram.blockUntilLoaded();
  302. vertProgram->blockUntilCoreInitialized();
  303. allParamDescs.push_back(vertProgram->getParamDesc());
  304. }
  305. HGpuProgram fragProgram = curPass->getFragmentProgram();
  306. if (fragProgram)
  307. {
  308. fragProgram.blockUntilLoaded();
  309. fragProgram->blockUntilCoreInitialized();
  310. allParamDescs.push_back(fragProgram->getParamDesc());
  311. }
  312. HGpuProgram geomProgram = curPass->getGeometryProgram();
  313. if (geomProgram)
  314. {
  315. geomProgram.blockUntilLoaded();
  316. geomProgram->blockUntilCoreInitialized();
  317. allParamDescs.push_back(geomProgram->getParamDesc());
  318. }
  319. HGpuProgram hullProgram = curPass->getHullProgram();
  320. if (hullProgram)
  321. {
  322. hullProgram.blockUntilLoaded();
  323. hullProgram->blockUntilCoreInitialized();
  324. allParamDescs.push_back(hullProgram->getParamDesc());
  325. }
  326. HGpuProgram domainProgram = curPass->getDomainProgram();
  327. if (domainProgram)
  328. {
  329. domainProgram.blockUntilLoaded();
  330. domainProgram->blockUntilCoreInitialized();
  331. allParamDescs.push_back(domainProgram->getParamDesc());
  332. }
  333. HGpuProgram computeProgram = curPass->getComputeProgram();
  334. if (computeProgram)
  335. {
  336. computeProgram.blockUntilLoaded();
  337. computeProgram->blockUntilCoreInitialized();
  338. allParamDescs.push_back(computeProgram->getParamDesc());
  339. }
  340. }
  341. return allParamDescs;
  342. }
  343. Vector<GpuParamDescPtr> MaterialBase::getAllParamDescs(const SPtr<TechniqueCore>& technique)
  344. {
  345. Vector<GpuParamDescPtr> allParamDescs;
  346. // Make sure all gpu programs are fully loaded
  347. for (UINT32 i = 0; i < technique->getNumPasses(); i++)
  348. {
  349. SPtr<PassCore> curPass = technique->getPass(i);
  350. SPtr<GpuProgramCore> vertProgram = curPass->getVertexProgram();
  351. if (vertProgram)
  352. allParamDescs.push_back(vertProgram->getParamDesc());
  353. SPtr<GpuProgramCore> fragProgram = curPass->getFragmentProgram();
  354. if (fragProgram)
  355. allParamDescs.push_back(fragProgram->getParamDesc());
  356. SPtr<GpuProgramCore> geomProgram = curPass->getGeometryProgram();
  357. if (geomProgram)
  358. allParamDescs.push_back(geomProgram->getParamDesc());
  359. SPtr<GpuProgramCore> hullProgram = curPass->getHullProgram();
  360. if (hullProgram)
  361. allParamDescs.push_back(hullProgram->getParamDesc());
  362. SPtr<GpuProgramCore> domainProgram = curPass->getDomainProgram();
  363. if (domainProgram)
  364. allParamDescs.push_back(domainProgram->getParamDesc());
  365. SPtr<GpuProgramCore> computeProgram = curPass->getComputeProgram();
  366. if (computeProgram)
  367. allParamDescs.push_back(computeProgram->getParamDesc());
  368. }
  369. return allParamDescs;
  370. }
  371. template<bool Core>
  372. UINT32 TMaterial<Core>::getNumPasses() const
  373. {
  374. throwIfNotInitialized();
  375. return mShader->getBestTechnique()->getNumPasses();
  376. }
  377. template<bool Core>
  378. typename TMaterial<Core>::PassType TMaterial<Core>::getPass(UINT32 passIdx) const
  379. {
  380. if (passIdx < 0 || passIdx >= mShader->getBestTechnique()->getNumPasses())
  381. BS_EXCEPT(InvalidParametersException, "Invalid pass index.");
  382. return mShader->getBestTechnique()->getPass(passIdx);
  383. }
  384. template<bool Core>
  385. TMaterialParamStruct<Core> TMaterial<Core>::getParamStruct(const String& name) const
  386. {
  387. throwIfNotInitialized();
  388. auto iterFind = mValidParams.find(name);
  389. if (iterFind == mValidParams.end())
  390. {
  391. LOGWRN("Material doesn't have a parameter named " + name);
  392. return TMaterialParamStruct<Core>();
  393. }
  394. const String& gpuVarName = iterFind->second;
  395. Vector<TGpuParamStruct<Core>> gpuParams;
  396. for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
  397. {
  398. SPtr<TPassParameters<Core>> params = *iter;
  399. for (UINT32 i = 0; i < params->getNumParams(); i++)
  400. {
  401. GpuParamsType& paramPtr = params->getParamByIdx(i);
  402. if (paramPtr)
  403. {
  404. if (paramPtr->hasParam(gpuVarName))
  405. {
  406. gpuParams.push_back(TGpuParamStruct<Core>());
  407. paramPtr->getStructParam(gpuVarName, gpuParams.back());
  408. }
  409. }
  410. }
  411. }
  412. return TMaterialParamStruct<Core>(gpuParams);
  413. }
  414. template<bool Core>
  415. TMaterialParamTexture<Core> TMaterial<Core>::getParamTexture(const String& name) const
  416. {
  417. throwIfNotInitialized();
  418. auto iterFind = mValidParams.find(name);
  419. if (iterFind == mValidParams.end())
  420. {
  421. LOGWRN("Material doesn't have a parameter named " + name);
  422. return TMaterialParamTexture<Core>();
  423. }
  424. const String& gpuVarName = iterFind->second;
  425. Vector<TGpuParamTexture<Core>> gpuParams;
  426. for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
  427. {
  428. SPtr<TPassParameters<Core>> params = *iter;
  429. for (UINT32 i = 0; i < params->getNumParams(); i++)
  430. {
  431. GpuParamsType& paramPtr = params->getParamByIdx(i);
  432. if (paramPtr)
  433. {
  434. if (paramPtr->hasTexture(gpuVarName))
  435. {
  436. gpuParams.push_back(TGpuParamTexture<Core>());
  437. paramPtr->getTextureParam(gpuVarName, gpuParams.back());
  438. }
  439. }
  440. }
  441. }
  442. return TMaterialParamTexture<Core>(gpuParams);
  443. }
  444. template<bool Core>
  445. TMaterialParamLoadStoreTexture<Core> TMaterial<Core>::getParamLoadStoreTexture(const String& name) const
  446. {
  447. throwIfNotInitialized();
  448. auto iterFind = mValidParams.find(name);
  449. if (iterFind == mValidParams.end())
  450. {
  451. LOGWRN("Material doesn't have a parameter named " + name);
  452. return TMaterialParamLoadStoreTexture<Core>();
  453. }
  454. const String& gpuVarName = iterFind->second;
  455. Vector<TGpuParamLoadStoreTexture<Core>> gpuParams;
  456. for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
  457. {
  458. SPtr<TPassParameters<Core>> params = *iter;
  459. for (UINT32 i = 0; i < params->getNumParams(); i++)
  460. {
  461. GpuParamsType& paramPtr = params->getParamByIdx(i);
  462. if (paramPtr)
  463. {
  464. if (paramPtr->hasTexture(gpuVarName))
  465. {
  466. gpuParams.push_back(TGpuParamLoadStoreTexture<Core>());
  467. paramPtr->getLoadStoreTextureParam(gpuVarName, gpuParams.back());
  468. }
  469. }
  470. }
  471. }
  472. return TMaterialParamLoadStoreTexture<Core>(gpuParams);
  473. }
  474. template<bool Core>
  475. TMaterialParamSampState<Core> TMaterial<Core>::getParamSamplerState(const String& name) const
  476. {
  477. throwIfNotInitialized();
  478. auto iterFind = mValidParams.find(name);
  479. if (iterFind == mValidParams.end())
  480. {
  481. LOGWRN("Material doesn't have a parameter named " + name);
  482. return TMaterialParamSampState<Core>();
  483. }
  484. const String& gpuVarName = iterFind->second;
  485. Vector<TGpuParamSampState<Core>> gpuParams;
  486. for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
  487. {
  488. SPtr<TPassParameters<Core>> params = *iter;
  489. for (UINT32 i = 0; i < params->getNumParams(); i++)
  490. {
  491. GpuParamsType& paramPtr = params->getParamByIdx(i);
  492. if (paramPtr)
  493. {
  494. if (paramPtr->hasSamplerState(gpuVarName))
  495. {
  496. gpuParams.push_back(TGpuParamSampState<Core>());
  497. paramPtr->getSamplerStateParam(gpuVarName, gpuParams.back());
  498. }
  499. }
  500. }
  501. }
  502. return TMaterialParamSampState<Core>(gpuParams);
  503. }
  504. template<bool Core>
  505. void TMaterial<Core>::setParamBlockBuffer(const String& name, const ParamBlockPtrType& paramBlock)
  506. {
  507. auto iterFind = mValidShareableParamBlocks.find(name);
  508. if (iterFind == mValidShareableParamBlocks.end())
  509. {
  510. LOGWRN("Material doesn't have a parameter block named " + name);
  511. return;
  512. }
  513. for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
  514. {
  515. SPtr<TPassParameters<Core>> params = *iter;
  516. for (UINT32 i = 0; i < params->getNumParams(); i++)
  517. {
  518. GpuParamsType& paramPtr = params->getParamByIdx(i);
  519. if (paramPtr)
  520. {
  521. if (paramPtr->hasParamBlock(name))
  522. paramPtr->setParamBlockBuffer(name, paramBlock);
  523. }
  524. }
  525. }
  526. }
  527. template<bool Core>
  528. void TMaterial<Core>::initBestTechnique()
  529. {
  530. mBestTechnique = nullptr;
  531. mParametersPerPass.clear();
  532. if (mShader)
  533. {
  534. mBestTechnique = mShader->getBestTechnique();
  535. if (mBestTechnique == nullptr)
  536. return;
  537. mValidShareableParamBlocks.clear();
  538. Vector<GpuParamDescPtr> allParamDescs = getAllParamDescs(mBestTechnique);
  539. mValidParams = determineParamMappings(allParamDescs, mShader->getDataParams(), mShader->getObjectParams());
  540. // Fill out various helper structures
  541. Set<String> validShareableParamBlocks = determineValidShareableParamBlocks(allParamDescs);
  542. Vector<ShaderBlockDesc> paramBlockData = determineShaderBlockData(validShareableParamBlocks, allParamDescs, mShader->getParamBlocks());
  543. Map<String, ParamBlockPtrType> paramBlockBuffers;
  544. // Create param blocks
  545. for (auto& paramBlock : paramBlockData)
  546. {
  547. ParamBlockPtrType newParamBlockBuffer;
  548. if (paramBlock.create)
  549. {
  550. newParamBlockBuffer = ParamBlockType::create(paramBlock.size, paramBlock.usage);
  551. }
  552. paramBlockBuffers[paramBlock.name] = newParamBlockBuffer;
  553. mValidShareableParamBlocks.insert(paramBlock.name);
  554. }
  555. for (UINT32 i = 0; i < mBestTechnique->getNumPasses(); i++)
  556. {
  557. PassType curPass = mBestTechnique->getPass(i);
  558. SPtr<TPassParameters<Core>> params = SPtr<TPassParameters<Core>>(new TPassParameters<Core>());
  559. GpuProgramType vertProgram = curPass->getVertexProgram();
  560. if (vertProgram)
  561. params->mVertParams = vertProgram->createParameters();
  562. GpuProgramType fragProgram = curPass->getFragmentProgram();
  563. if (fragProgram)
  564. params->mFragParams = fragProgram->createParameters();
  565. GpuProgramType geomProgram = curPass->getGeometryProgram();
  566. if (geomProgram)
  567. params->mGeomParams = geomProgram->createParameters();
  568. GpuProgramType hullProgram = curPass->getHullProgram();
  569. if (hullProgram)
  570. params->mHullParams = hullProgram->createParameters();
  571. GpuProgramType domainProgram = curPass->getDomainProgram();
  572. if (domainProgram)
  573. params->mDomainParams = domainProgram->createParameters();
  574. GpuProgramType computeProgram = curPass->getComputeProgram();
  575. if (computeProgram)
  576. params->mComputeParams = computeProgram->createParameters();
  577. mParametersPerPass.push_back(params);
  578. }
  579. // Assign param block buffers
  580. for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
  581. {
  582. SPtr<TPassParameters<Core>> params = *iter;
  583. for (UINT32 i = 0; i < params->getNumParams(); i++)
  584. {
  585. GpuParamsType& paramPtr = params->getParamByIdx(i);
  586. if (paramPtr)
  587. {
  588. // Assign shareable buffers
  589. for (auto iterBlock = mValidShareableParamBlocks.begin(); iterBlock != mValidShareableParamBlocks.end(); ++iterBlock)
  590. {
  591. const String& paramBlockName = *iterBlock;
  592. if (paramPtr->hasParamBlock(paramBlockName))
  593. {
  594. ParamBlockPtrType blockBuffer = paramBlockBuffers[paramBlockName];
  595. paramPtr->setParamBlockBuffer(paramBlockName, blockBuffer);
  596. }
  597. }
  598. // Create non-shareable ones
  599. const GpuParamDesc& desc = paramPtr->getParamDesc();
  600. for (auto iterBlockDesc = desc.paramBlocks.begin(); iterBlockDesc != desc.paramBlocks.end(); ++iterBlockDesc)
  601. {
  602. if (!iterBlockDesc->second.isShareable)
  603. {
  604. ParamBlockPtrType newParamBlockBuffer = ParamBlockType::create(iterBlockDesc->second.blockSize * sizeof(UINT32));
  605. paramPtr->setParamBlockBuffer(iterBlockDesc->first, newParamBlockBuffer);
  606. }
  607. }
  608. }
  609. }
  610. }
  611. }
  612. }
  613. template <bool Core>
  614. template <typename T>
  615. void TMaterial<Core>::getParam(const String& name, TMaterialDataParam<T, Core>& output) const
  616. {
  617. throwIfNotInitialized();
  618. auto iterFind = mValidParams.find(name);
  619. if (iterFind == mValidParams.end())
  620. {
  621. LOGWRN("Material doesn't have a parameter named " + name);
  622. return;
  623. }
  624. const String& gpuVarName = iterFind->second;
  625. Vector<TGpuDataParam<T, Core>> gpuParams;
  626. for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
  627. {
  628. SPtr<TPassParameters<Core>> params = *iter;
  629. for (UINT32 i = 0; i < params->getNumParams(); i++)
  630. {
  631. GpuParamsType& paramPtr = params->getParamByIdx(i);
  632. if (paramPtr)
  633. {
  634. if (paramPtr->hasParam(gpuVarName))
  635. {
  636. gpuParams.push_back(TGpuDataParam<T, Core>());
  637. paramPtr->getParam<T>(gpuVarName, gpuParams.back());
  638. }
  639. }
  640. }
  641. }
  642. output = TMaterialDataParam<T, Core>(gpuParams);
  643. }
  644. template<bool Core>
  645. void TMaterial<Core>::throwIfNotInitialized() const
  646. {
  647. if (mShader == nullptr)
  648. {
  649. BS_EXCEPT(InternalErrorException, "Material does not have shader set.");
  650. }
  651. if (mBestTechnique == nullptr)
  652. {
  653. BS_EXCEPT(InternalErrorException, "Shader does not contain a supported technique.");
  654. }
  655. }
  656. template class TMaterial < false > ;
  657. template class TMaterial < true > ;
  658. template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<float, false>&) const;
  659. template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Color, false>&) const;
  660. template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Vector2, false>&) const;
  661. template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Vector3, false>&) const;
  662. template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Vector4, false>&) const;
  663. template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Matrix3, false>&) const;
  664. template BS_CORE_EXPORT void TMaterial<false>::getParam(const String&, TMaterialDataParam<Matrix4, false>&) const;
  665. template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<float, true>&) const;
  666. template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Color, true>&) const;
  667. template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Vector2, true>&) const;
  668. template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Vector3, true>&) const;
  669. template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Vector4, true>&) const;
  670. template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Matrix3, true>&) const;
  671. template BS_CORE_EXPORT void TMaterial<true>::getParam(const String&, TMaterialDataParam<Matrix4, true>&) const;
  672. MaterialCore::MaterialCore(const SPtr<ShaderCore>& shader)
  673. {
  674. setShader(shader);
  675. }
  676. MaterialCore::MaterialCore(const SPtr<ShaderCore>& shader, const SPtr<TechniqueCore>& bestTechnique,
  677. const Set<String>& validShareableParamBlocks, const Map<String, String>& validParams,
  678. const Vector<SPtr<PassParametersCore>>& passParams)
  679. {
  680. mShader = shader;
  681. mBestTechnique = bestTechnique;
  682. mValidShareableParamBlocks = validShareableParamBlocks;
  683. mValidParams = validParams;
  684. mParametersPerPass = passParams;
  685. }
  686. void MaterialCore::setShader(const SPtr<ShaderCore>& shader)
  687. {
  688. mShader = shader;
  689. initBestTechnique();
  690. _markCoreDirty();
  691. }
  692. void MaterialCore::syncToCore(const CoreSyncData& data)
  693. {
  694. char* dataPtr = (char*)data.getBuffer();
  695. mValidShareableParamBlocks.clear();
  696. mValidParams.clear();
  697. mParametersPerPass.clear();
  698. UINT32 numPasses = 0;
  699. dataPtr = rttiReadElem(mValidShareableParamBlocks, dataPtr);
  700. dataPtr = rttiReadElem(mValidParams, dataPtr);
  701. dataPtr = rttiReadElem(numPasses, dataPtr);
  702. for (UINT32 i = 0; i < numPasses; i++)
  703. {
  704. SPtr<PassParametersCore>* passParameters = (SPtr<PassParametersCore>*)dataPtr;
  705. mParametersPerPass.push_back(*passParameters);
  706. passParameters->~SPtr<PassParametersCore>();
  707. dataPtr += sizeof(SPtr<PassParametersCore>);
  708. }
  709. SPtr<ShaderCore>* shader = (SPtr<ShaderCore>*)dataPtr;
  710. mShader = *shader;
  711. shader->~SPtr<ShaderCore>();
  712. dataPtr += sizeof(SPtr<ShaderCore>);
  713. SPtr<TechniqueCore>* technique = (SPtr<TechniqueCore>*)dataPtr;
  714. mBestTechnique = *technique;
  715. technique->~SPtr<TechniqueCore>();
  716. dataPtr += sizeof(SPtr<TechniqueCore>);
  717. }
  718. SPtr<MaterialCore> MaterialCore::create(const SPtr<ShaderCore>& shader)
  719. {
  720. MaterialCore* material = new (bs_alloc<MaterialCore>()) MaterialCore(shader);
  721. SPtr<MaterialCore> materialPtr = bs_shared_ptr<MaterialCore, GenAlloc>(material);
  722. materialPtr->_setThisPtr(materialPtr);
  723. materialPtr->initialize();
  724. return materialPtr;
  725. }
  726. Material::Material()
  727. :mLoadFlags(Load_None)
  728. { }
  729. Material::Material(const HShader& shader)
  730. :mLoadFlags(Load_None)
  731. {
  732. mShader = shader;
  733. }
  734. void Material::initialize()
  735. {
  736. setShader(mShader); // Not calling directly in constructor because it calls virtual methods
  737. Resource::initialize();
  738. }
  739. void Material::setShader(const HShader& shader)
  740. {
  741. mShader = shader;
  742. mBestTechnique = nullptr;
  743. mLoadFlags = Load_None;
  744. _markResourcesDirty();
  745. initializeIfLoaded();
  746. }
  747. void Material::_markCoreDirty()
  748. {
  749. markCoreDirty();
  750. }
  751. void Material::_markResourcesDirty()
  752. {
  753. markResourcesDirty();
  754. }
  755. SPtr<MaterialCore> Material::getCore() const
  756. {
  757. return std::static_pointer_cast<MaterialCore>(mCoreSpecific);
  758. }
  759. SPtr<CoreObjectCore> Material::createCore() const
  760. {
  761. MaterialCore* material = nullptr;
  762. SPtr<ShaderCore> shader;
  763. if (mShader != nullptr)
  764. {
  765. shader = mShader->getCore();
  766. if (mBestTechnique != nullptr)
  767. {
  768. SPtr<TechniqueCore> technique = mBestTechnique->getCore();
  769. Vector<SPtr<PassParametersCore>> passParams;
  770. for (auto& passParam : mParametersPerPass)
  771. passParams.push_back(convertParamsToCore(passParam));
  772. material = new (bs_alloc<MaterialCore>()) MaterialCore(shader, technique, mValidShareableParamBlocks, mValidParams, passParams);
  773. }
  774. }
  775. if (material == nullptr)
  776. material = new (bs_alloc<MaterialCore>()) MaterialCore(shader);
  777. SPtr<MaterialCore> materialPtr = bs_shared_ptr<MaterialCore, GenAlloc>(material);
  778. materialPtr->_setThisPtr(materialPtr);
  779. return materialPtr;
  780. }
  781. CoreSyncData Material::syncToCore(FrameAlloc* allocator)
  782. {
  783. UINT32 numPasses = (UINT32)mParametersPerPass.size();
  784. UINT32 size = sizeof(UINT32) + numPasses * sizeof(SPtr<PassParametersCore>)
  785. + sizeof(SPtr<ShaderCore>) + sizeof(SPtr<TechniqueCore>) + rttiGetElemSize(mValidShareableParamBlocks)
  786. + rttiGetElemSize(mValidParams);
  787. UINT8* buffer = allocator->alloc(size);
  788. char* dataPtr = (char*)buffer;
  789. dataPtr = rttiWriteElem(mValidShareableParamBlocks, dataPtr);
  790. dataPtr = rttiWriteElem(mValidParams, dataPtr);
  791. dataPtr = rttiWriteElem(numPasses, dataPtr);
  792. for (UINT32 i = 0; i < numPasses; i++)
  793. {
  794. SPtr<PassParametersCore>* passParameters = new (dataPtr) SPtr<PassParametersCore>();
  795. *passParameters = convertParamsToCore(mParametersPerPass[i]);
  796. dataPtr += sizeof(SPtr<PassParametersCore>);
  797. }
  798. SPtr<ShaderCore>* shader = new (dataPtr)SPtr<ShaderCore>();
  799. if (mShader != nullptr)
  800. *shader = mShader->getCore();
  801. else
  802. *shader = nullptr;
  803. dataPtr += sizeof(SPtr<ShaderCore>);
  804. SPtr<TechniqueCore>* technique = new (dataPtr)SPtr<TechniqueCore>();
  805. if (mBestTechnique != nullptr)
  806. *technique = mBestTechnique->getCore();
  807. else
  808. *technique = nullptr;
  809. dataPtr += sizeof(SPtr<TechniqueCore>);
  810. return CoreSyncData(buffer, size);
  811. }
  812. void Material::getCoreDependencies(Vector<SPtr<CoreObject>>& dependencies)
  813. {
  814. if (mShader.isLoaded())
  815. dependencies.push_back(mShader.getInternalPtr());
  816. for (auto& params : mParametersPerPass)
  817. {
  818. UINT32 numParams = params->getNumParams();
  819. for (UINT32 i = 0; i < numParams; i++)
  820. {
  821. GpuParamsPtr gpuParams = params->getParamByIdx(i);
  822. if (gpuParams != nullptr)
  823. dependencies.push_back(gpuParams);
  824. }
  825. }
  826. }
  827. void Material::getResourceDependencies(Vector<HResource>& resources)
  828. {
  829. if (mShader != nullptr)
  830. {
  831. resources.push_back(mShader);
  832. if (mShader.isLoaded())
  833. {
  834. TechniquePtr bestTechnique = mShader->getBestTechnique();
  835. if (bestTechnique != nullptr)
  836. {
  837. UINT32 numPasses = bestTechnique->getNumPasses();
  838. for (UINT32 i = 0; i < numPasses; i++)
  839. {
  840. PassPtr pass = bestTechnique->getPass(i);
  841. HGpuProgram vertProg = pass->getVertexProgram();
  842. if (vertProg != nullptr)
  843. resources.push_back(vertProg);
  844. HGpuProgram fragProg = pass->getFragmentProgram();
  845. if (fragProg != nullptr)
  846. resources.push_back(fragProg);
  847. HGpuProgram geomProg = pass->getGeometryProgram();
  848. if (geomProg != nullptr)
  849. resources.push_back(geomProg);
  850. HGpuProgram domProg = pass->getDomainProgram();
  851. if (domProg != nullptr)
  852. resources.push_back(domProg);
  853. HGpuProgram hullProg = pass->getHullProgram();
  854. if (hullProg != nullptr)
  855. resources.push_back(hullProg);
  856. HGpuProgram computeProg = pass->getComputeProgram();
  857. if (computeProg != nullptr)
  858. resources.push_back(computeProg);
  859. HBlendState blendState = pass->getBlendState();
  860. if (blendState != nullptr)
  861. resources.push_back(blendState);
  862. HRasterizerState rasterizerState = pass->getRasterizerState();
  863. if (rasterizerState != nullptr)
  864. resources.push_back(rasterizerState);
  865. HDepthStencilState depthStencilState = pass->getDepthStencilState();
  866. if (depthStencilState != nullptr)
  867. resources.push_back(depthStencilState);
  868. }
  869. }
  870. }
  871. }
  872. }
  873. bool Material::areDependenciesLoaded() const
  874. {
  875. if (mShader == nullptr) // No shader, so everything is technically loaded
  876. return true;
  877. return mShader.isLoaded();
  878. }
  879. void Material::initializeIfLoaded()
  880. {
  881. if (areDependenciesLoaded())
  882. {
  883. if (mLoadFlags != Load_All)
  884. {
  885. mLoadFlags = Load_All;
  886. initBestTechnique();
  887. markCoreDirty();
  888. }
  889. }
  890. else
  891. {
  892. if (mShader.isLoaded() && mLoadFlags == Load_None)
  893. {
  894. mLoadFlags = Load_Shader;
  895. markResourcesDirty(); // Need to register resources dependent on shader now
  896. }
  897. }
  898. }
  899. void Material::notifyResourceLoaded(const HResource& resource)
  900. {
  901. initializeIfLoaded();
  902. }
  903. void Material::notifyResourceDestroyed(const HResource& resource)
  904. {
  905. initializeIfLoaded();
  906. }
  907. void Material::notifyResourceChanged(const HResource& resource)
  908. {
  909. initializeIfLoaded();
  910. }
  911. HMaterial Material::create()
  912. {
  913. MaterialPtr materialPtr = MaterialManager::instance().create();
  914. return static_resource_cast<Material>(gResources()._createResourceHandle(materialPtr));
  915. }
  916. HMaterial Material::create(const HShader& shader)
  917. {
  918. MaterialPtr materialPtr = MaterialManager::instance().create(shader);
  919. return static_resource_cast<Material>(gResources()._createResourceHandle(materialPtr));
  920. }
  921. RTTITypeBase* Material::getRTTIStatic()
  922. {
  923. return MaterialRTTI::instance();
  924. }
  925. RTTITypeBase* Material::getRTTI() const
  926. {
  927. return Material::getRTTIStatic();
  928. }
  929. }