BsMaterial.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932
  1. #include "BsMaterial.h"
  2. #include "BsException.h"
  3. #include "BsShader.h"
  4. #include "BsTechnique.h"
  5. #include "BsPass.h"
  6. #include "BsRenderSystem.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. namespace BansheeEngine
  16. {
  17. Material::Material()
  18. :Resource(false), mCoreDirtyFlags(0xFFFFFFFF)
  19. {
  20. }
  21. Material::~Material()
  22. {
  23. }
  24. void Material::setShader(ShaderPtr shader)
  25. {
  26. mShader = shader;
  27. initBestTechnique();
  28. }
  29. void Material::initBestTechnique()
  30. {
  31. mBestTechnique = nullptr;
  32. mParametersPerPass.clear();
  33. freeParamBuffers();
  34. if(mShader)
  35. {
  36. mBestTechnique = mShader->getBestTechnique();
  37. if(mBestTechnique == nullptr)
  38. return;
  39. mValidShareableParamBlocks.clear();
  40. mValidParams.clear();
  41. Vector<GpuParamDescPtr> allParamDescs;
  42. // Make sure all gpu programs are fully loaded
  43. for(UINT32 i = 0; i < mBestTechnique->getNumPasses(); i++)
  44. {
  45. PassPtr curPass = mBestTechnique->getPass(i);
  46. HGpuProgram vertProgram = curPass->getVertexProgram();
  47. if(vertProgram)
  48. {
  49. vertProgram.synchronize();
  50. allParamDescs.push_back(vertProgram->getParamDesc());
  51. }
  52. HGpuProgram fragProgram = curPass->getFragmentProgram();
  53. if(fragProgram)
  54. {
  55. fragProgram.synchronize();
  56. allParamDescs.push_back(fragProgram->getParamDesc());
  57. }
  58. HGpuProgram geomProgram = curPass->getGeometryProgram();
  59. if(geomProgram)
  60. {
  61. geomProgram.synchronize();
  62. allParamDescs.push_back(geomProgram->getParamDesc());
  63. }
  64. HGpuProgram hullProgram = curPass->getHullProgram();
  65. if(hullProgram)
  66. {
  67. hullProgram.synchronize();
  68. allParamDescs.push_back(hullProgram->getParamDesc());
  69. }
  70. HGpuProgram domainProgram = curPass->getDomainProgram();
  71. if(domainProgram)
  72. {
  73. domainProgram.synchronize();
  74. allParamDescs.push_back(domainProgram->getParamDesc());
  75. }
  76. HGpuProgram computeProgram = curPass->getComputeProgram();
  77. if(computeProgram)
  78. {
  79. computeProgram.synchronize();
  80. allParamDescs.push_back(computeProgram->getParamDesc());
  81. }
  82. }
  83. // Fill out various helper structures
  84. Map<String, const GpuParamDataDesc*> validDataParameters = determineValidDataParameters(allParamDescs);
  85. Vector<const GpuParamObjectDesc*> validObjectParameters = determineValidObjectParameters(allParamDescs);
  86. Set<String> validShareableParamBlocks = determineValidShareableParamBlocks(allParamDescs);
  87. Map<String, String> paramToParamBlockMap = determineParameterToBlockMapping(allParamDescs);
  88. Map<String, GpuParamBlockBufferPtr> paramBlockBuffers;
  89. // Create param blocks
  90. const Map<String, SHADER_PARAM_BLOCK_DESC>& shaderDesc = mShader->_getParamBlocks();
  91. for(auto iter = validShareableParamBlocks.begin(); iter != validShareableParamBlocks.end(); ++iter)
  92. {
  93. bool createBlockBuffer = true;
  94. GpuParamBlockUsage usage = GPBU_STATIC;
  95. auto iterFind = shaderDesc.find(*iter);
  96. if(iterFind != shaderDesc.end())
  97. {
  98. createBlockBuffer = !iterFind->second.shared && iterFind->second.rendererSemantic == 0;
  99. usage = iterFind->second.usage;
  100. }
  101. GpuParamBlockDesc blockDesc;
  102. for(auto iter2 = allParamDescs.begin(); iter2 != allParamDescs.end(); ++iter2)
  103. {
  104. auto findParamBlockDesc = (*iter2)->paramBlocks.find(*iter);
  105. if(findParamBlockDesc != (*iter2)->paramBlocks.end())
  106. {
  107. blockDesc = findParamBlockDesc->second;
  108. break;
  109. }
  110. }
  111. GpuParamBlockBufferPtr newParamBlockBuffer;
  112. if(createBlockBuffer)
  113. {
  114. newParamBlockBuffer = HardwareBufferManager::instance().createGpuParamBlockBuffer(blockDesc.blockSize * sizeof(UINT32), usage);
  115. mParamBuffers.push_back(newParamBlockBuffer);
  116. }
  117. paramBlockBuffers[*iter] = newParamBlockBuffer;
  118. mValidShareableParamBlocks.insert(*iter);
  119. }
  120. // Create data param mappings
  121. const Map<String, SHADER_DATA_PARAM_DESC>& dataParamDesc = mShader->_getDataParams();
  122. for(auto iter = dataParamDesc.begin(); iter != dataParamDesc.end(); ++iter)
  123. {
  124. auto findIter = validDataParameters.find(iter->second.gpuVariableName);
  125. // Not valid so we skip it
  126. if(findIter == validDataParameters.end())
  127. continue;
  128. if(findIter->second->type != iter->second.type)
  129. {
  130. LOGWRN("Ignoring shader parameter \"" + iter->first +"\". Type doesn't match the one defined in the gpu program. "
  131. + "Shader defined type: " + toString(iter->second.type) + " - Gpu program defined type: " + toString(findIter->second->type));
  132. continue;
  133. }
  134. if(findIter->second->arraySize != iter->second.arraySize)
  135. {
  136. LOGWRN("Ignoring shader parameter \"" + iter->first +"\". Array size doesn't match the one defined in the gpu program."
  137. + "Shader defined array size: " + toString(iter->second.arraySize) + " - Gpu program defined array size: " + toString(findIter->second->arraySize));
  138. continue;
  139. }
  140. auto findBlockIter = paramToParamBlockMap.find(iter->second.gpuVariableName);
  141. if(findBlockIter == paramToParamBlockMap.end())
  142. BS_EXCEPT(InternalErrorException, "Parameter doesn't exist in param to param block map but exists in valid param map.");
  143. String& paramBlockName = findBlockIter->second;
  144. mValidParams[iter->first] = iter->second.gpuVariableName;
  145. }
  146. // Create object param mappings
  147. const Map<String, SHADER_OBJECT_PARAM_DESC>& objectParamDesc = mShader->_getObjectParams();
  148. for(auto iter = objectParamDesc.begin(); iter != objectParamDesc.end(); ++iter)
  149. {
  150. const Vector<String>& gpuVariableNames = iter->second.gpuVariableNames;
  151. for (auto iter2 = gpuVariableNames.begin(); iter2 != gpuVariableNames.end(); ++iter2)
  152. {
  153. for (auto iter3 = validObjectParameters.begin(); iter3 != validObjectParameters.end(); ++iter3)
  154. {
  155. if ((*iter3)->name == (*iter2) && (*iter3)->type == iter->second.type)
  156. {
  157. mValidParams[iter->first] = *iter2;
  158. break;
  159. }
  160. }
  161. }
  162. }
  163. for(UINT32 i = 0; i < mBestTechnique->getNumPasses(); i++)
  164. {
  165. PassPtr curPass = mBestTechnique->getPass(i);
  166. PassParametersPtr params = PassParametersPtr(new PassParameters());
  167. HGpuProgram vertProgram = curPass->getVertexProgram();
  168. if(vertProgram)
  169. params->mVertParams = vertProgram->createParameters();
  170. HGpuProgram fragProgram = curPass->getFragmentProgram();
  171. if(fragProgram)
  172. params->mFragParams = fragProgram->createParameters();
  173. HGpuProgram geomProgram = curPass->getGeometryProgram();
  174. if(geomProgram)
  175. params->mGeomParams = geomProgram->createParameters();
  176. HGpuProgram hullProgram = curPass->getHullProgram();
  177. if(hullProgram)
  178. params->mHullParams = hullProgram->createParameters();
  179. HGpuProgram domainProgram = curPass->getDomainProgram();
  180. if(domainProgram)
  181. params->mDomainParams = domainProgram->createParameters();
  182. HGpuProgram computeProgram = curPass->getComputeProgram();
  183. if(computeProgram)
  184. params->mComputeParams = computeProgram->createParameters();
  185. mParametersPerPass.push_back(params);
  186. }
  187. // Assign param block buffers
  188. for(auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
  189. {
  190. PassParametersPtr params = *iter;
  191. for(UINT32 i = 0; i < params->getNumParams(); i++)
  192. {
  193. GpuParamsPtr& paramPtr = params->getParamByIdx(i);
  194. if(paramPtr)
  195. {
  196. // Assign shareable buffers
  197. for(auto iterBlock = mValidShareableParamBlocks.begin(); iterBlock != mValidShareableParamBlocks.end(); ++iterBlock)
  198. {
  199. const String& paramBlockName = *iterBlock;
  200. if(paramPtr->hasParamBlock(paramBlockName))
  201. {
  202. GpuParamBlockBufferPtr blockBuffer = paramBlockBuffers[paramBlockName];
  203. paramPtr->setParamBlockBuffer(paramBlockName, blockBuffer);
  204. }
  205. }
  206. // Create non-shareable ones
  207. const GpuParamDesc& desc = paramPtr->getParamDesc();
  208. for(auto iterBlockDesc = desc.paramBlocks.begin(); iterBlockDesc != desc.paramBlocks.end(); ++iterBlockDesc)
  209. {
  210. if(!iterBlockDesc->second.isShareable)
  211. {
  212. GpuParamBlockBufferPtr newParamBlockBuffer = HardwareBufferManager::instance().createGpuParamBlockBuffer(iterBlockDesc->second.blockSize * sizeof(UINT32));
  213. mParamBuffers.push_back(newParamBlockBuffer);
  214. paramPtr->setParamBlockBuffer(iterBlockDesc->first, newParamBlockBuffer);
  215. }
  216. }
  217. }
  218. }
  219. }
  220. }
  221. mCoreDirtyFlags = 0xFFFFFFFF;
  222. }
  223. Map<String, const GpuParamDataDesc*> Material::determineValidDataParameters(const Vector<GpuParamDescPtr>& paramDescs) const
  224. {
  225. Map<String, const GpuParamDataDesc*> foundDataParams;
  226. Map<String, bool> validParams;
  227. for(auto iter = paramDescs.begin(); iter != paramDescs.end(); ++iter)
  228. {
  229. const GpuParamDesc& curDesc = **iter;
  230. // Check regular data params
  231. for(auto iter2 = curDesc.params.begin(); iter2 != curDesc.params.end(); ++iter2)
  232. {
  233. bool isParameterValid = true;
  234. const GpuParamDataDesc& curParam = iter2->second;
  235. auto dataFindIter = validParams.find(iter2->first);
  236. if(dataFindIter == validParams.end())
  237. {
  238. validParams[iter2->first] = true;
  239. foundDataParams[iter2->first] = &curParam;
  240. }
  241. else
  242. {
  243. if(validParams[iter2->first])
  244. {
  245. auto dataFindIter2 = foundDataParams.find(iter2->first);
  246. const GpuParamDataDesc* otherParam = dataFindIter2->second;
  247. if(!areParamsEqual(curParam, *otherParam, true))
  248. {
  249. validParams[iter2->first] = false;
  250. foundDataParams.erase(dataFindIter2);
  251. }
  252. }
  253. }
  254. }
  255. }
  256. return foundDataParams;
  257. }
  258. Vector<const GpuParamObjectDesc*> Material::determineValidObjectParameters(const Vector<GpuParamDescPtr>& paramDescs) const
  259. {
  260. Vector<const GpuParamObjectDesc*> validParams;
  261. for(auto iter = paramDescs.begin(); iter != paramDescs.end(); ++iter)
  262. {
  263. const GpuParamDesc& curDesc = **iter;
  264. // Check sampler params
  265. for(auto iter2 = curDesc.samplers.begin(); iter2 != curDesc.samplers.end(); ++iter2)
  266. {
  267. validParams.push_back(&iter2->second);
  268. }
  269. // Check texture params
  270. for(auto iter2 = curDesc.textures.begin(); iter2 != curDesc.textures.end(); ++iter2)
  271. {
  272. validParams.push_back(&iter2->second);
  273. }
  274. // Check buffer params
  275. for(auto iter2 = curDesc.buffers.begin(); iter2 != curDesc.buffers.end(); ++iter2)
  276. {
  277. validParams.push_back(&iter2->second);
  278. }
  279. }
  280. return validParams;
  281. }
  282. Set<String> Material::determineValidShareableParamBlocks(const Vector<GpuParamDescPtr>& paramDescs) const
  283. {
  284. // Make sure param blocks with the same name actually are the same
  285. Map<String, std::pair<String, GpuParamDescPtr>> uniqueParamBlocks;
  286. Map<String, bool> validParamBlocks;
  287. for(auto iter = paramDescs.begin(); iter != paramDescs.end(); ++iter)
  288. {
  289. const GpuParamDesc& curDesc = **iter;
  290. for(auto blockIter = curDesc.paramBlocks.begin(); blockIter != curDesc.paramBlocks.end(); ++blockIter)
  291. {
  292. bool isBlockValid = true;
  293. const GpuParamBlockDesc& curBlock = blockIter->second;
  294. if(!curBlock.isShareable) // Non-shareable buffers are handled differently, they're allowed same names
  295. continue;
  296. auto iterFind = uniqueParamBlocks.find(blockIter->first);
  297. if(iterFind == uniqueParamBlocks.end())
  298. {
  299. uniqueParamBlocks[blockIter->first] = std::make_pair(blockIter->first, *iter);
  300. validParamBlocks[blockIter->first] = true;
  301. continue;
  302. }
  303. String otherBlockName = iterFind->second.first;
  304. GpuParamDescPtr otherDesc = iterFind->second.second;
  305. for(auto myParamIter = curDesc.params.begin(); myParamIter != curDesc.params.end(); ++myParamIter)
  306. {
  307. const GpuParamDataDesc& myParam = myParamIter->second;
  308. if(myParam.paramBlockSlot != curBlock.slot)
  309. continue; // Param is in another block, so we will check it when its time for that block
  310. auto otherParamFind = otherDesc->params.find(myParamIter->first);
  311. // Cannot find other param, blocks aren't equal
  312. if(otherParamFind == otherDesc->params.end())
  313. {
  314. isBlockValid = false;
  315. break;
  316. }
  317. const GpuParamDataDesc& otherParam = otherParamFind->second;
  318. if(!areParamsEqual(myParam, otherParam) || curBlock.name != otherBlockName)
  319. {
  320. isBlockValid = false;
  321. break;
  322. }
  323. }
  324. if(!isBlockValid)
  325. {
  326. if(validParamBlocks[blockIter->first])
  327. {
  328. LOGWRN("Found two param blocks with the same name but different contents: " + blockIter->first);
  329. validParamBlocks[blockIter->first] = false;
  330. }
  331. }
  332. }
  333. }
  334. Set<String> validParamBlocksReturn;
  335. for(auto iter = validParamBlocks.begin(); iter != validParamBlocks.end(); ++iter)
  336. {
  337. if(iter->second)
  338. validParamBlocksReturn.insert(iter->first);
  339. }
  340. return validParamBlocksReturn;
  341. }
  342. Map<String, String> Material::determineParameterToBlockMapping(const Vector<GpuParamDescPtr>& paramDescs)
  343. {
  344. Map<String, String> paramToParamBlock;
  345. for(auto iter = paramDescs.begin(); iter != paramDescs.end(); ++iter)
  346. {
  347. const GpuParamDesc& curDesc = **iter;
  348. for(auto iter2 = curDesc.params.begin(); iter2 != curDesc.params.end(); ++iter2)
  349. {
  350. const GpuParamDataDesc& curParam = iter2->second;
  351. auto iterFind = paramToParamBlock.find(curParam.name);
  352. if(iterFind != paramToParamBlock.end())
  353. continue;
  354. for(auto iterBlock = curDesc.paramBlocks.begin(); iterBlock != curDesc.paramBlocks.end(); ++iterBlock)
  355. {
  356. if(iterBlock->second.slot == curParam.paramBlockSlot)
  357. {
  358. paramToParamBlock[curParam.name] = iterBlock->second.name;
  359. break;
  360. }
  361. }
  362. }
  363. }
  364. return paramToParamBlock;
  365. }
  366. bool Material::areParamsEqual(const GpuParamDataDesc& paramA, const GpuParamDataDesc& paramB, bool ignoreBufferOffsets) const
  367. {
  368. bool equal = paramA.arraySize == paramB.arraySize && paramA.elementSize == paramB.elementSize
  369. && paramA.type == paramB.type && paramA.arrayElementStride == paramB.arrayElementStride;
  370. if(!ignoreBufferOffsets)
  371. equal &= paramA.cpuMemOffset == paramB.cpuMemOffset && paramA.gpuMemOffset == paramB.gpuMemOffset;
  372. return equal;
  373. }
  374. void Material::throwIfNotInitialized() const
  375. {
  376. if(mShader == nullptr)
  377. {
  378. BS_EXCEPT(InternalErrorException, "Material does not have shader set.");
  379. }
  380. if(mBestTechnique == nullptr)
  381. {
  382. BS_EXCEPT(InternalErrorException, "Shader does not contain a supported technique.");
  383. }
  384. }
  385. void Material::setColor(const String& name, const Color& value, UINT32 arrayIdx)
  386. {
  387. return getParamVec4(name).set(Vector4(value.r, value.g, value.b, value.a), arrayIdx);
  388. }
  389. void Material::setParamBlockBuffer(const String& name, const GpuParamBlockBufferPtr& paramBlockBuffer)
  390. {
  391. auto iterFind = mValidShareableParamBlocks.find(name);
  392. if(iterFind == mValidShareableParamBlocks.end())
  393. {
  394. LOGWRN("Material doesn't have a parameter block named " + name);
  395. return;
  396. }
  397. for(auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
  398. {
  399. PassParametersPtr params = *iter;
  400. for(UINT32 i = 0; i < params->getNumParams(); i++)
  401. {
  402. GpuParamsPtr& paramPtr = params->getParamByIdx(i);
  403. if(paramPtr)
  404. {
  405. if(paramPtr->hasParamBlock(name))
  406. paramPtr->setParamBlockBuffer(name, paramBlockBuffer);
  407. }
  408. }
  409. }
  410. }
  411. UINT32 Material::getNumPasses() const
  412. {
  413. throwIfNotInitialized();
  414. return mShader->getBestTechnique()->getNumPasses();
  415. }
  416. PassPtr Material::getPass(UINT32 passIdx) const
  417. {
  418. if(passIdx < 0 || passIdx >= mShader->getBestTechnique()->getNumPasses())
  419. BS_EXCEPT(InvalidParametersException, "Invalid pass index.");
  420. return mShader->getBestTechnique()->getPass(passIdx);
  421. }
  422. PassParametersPtr Material::getPassParameters(UINT32 passIdx) const
  423. {
  424. if(passIdx < 0 || passIdx >= mParametersPerPass.size())
  425. BS_EXCEPT(InvalidParametersException, "Invalid pass index.");
  426. PassParametersPtr params = mParametersPerPass[passIdx];
  427. return params;
  428. }
  429. Material::StructData Material::getStructData(const String& name, UINT32 arrayIdx) const
  430. {
  431. GpuParamStruct structParam = getParamStruct(name);
  432. StructData data(structParam.getElementSize());
  433. structParam.get(data.data.get(), structParam.getElementSize(), arrayIdx);
  434. return data;
  435. }
  436. GpuParamFloat Material::getParamFloat(const String& name) const
  437. {
  438. TGpuDataParam<float> gpuParam;
  439. getParam(name, gpuParam);
  440. return gpuParam;
  441. }
  442. GpuParamVec2 Material::getParamVec2(const String& name) const
  443. {
  444. TGpuDataParam<Vector2> gpuParam;
  445. getParam(name, gpuParam);
  446. return gpuParam;
  447. }
  448. GpuParamVec3 Material::getParamVec3(const String& name) const
  449. {
  450. TGpuDataParam<Vector3> gpuParam;
  451. getParam(name, gpuParam);
  452. return gpuParam;
  453. }
  454. GpuParamVec4 Material::getParamVec4(const String& name) const
  455. {
  456. TGpuDataParam<Vector4> gpuParam;
  457. getParam(name, gpuParam);
  458. return gpuParam;
  459. }
  460. GpuParamMat3 Material::getParamMat3(const String& name) const
  461. {
  462. TGpuDataParam<Matrix3> gpuParam;
  463. getParam(name, gpuParam);
  464. return gpuParam;
  465. }
  466. GpuParamMat4 Material::getParamMat4(const String& name) const
  467. {
  468. TGpuDataParam<Matrix4> gpuParam;
  469. getParam(name, gpuParam);
  470. return gpuParam;
  471. }
  472. GpuParamStruct Material::getParamStruct(const String& name) const
  473. {
  474. throwIfNotInitialized();
  475. GpuParamStruct gpuParam;
  476. auto iterFind = mValidParams.find(name);
  477. if(iterFind == mValidParams.end())
  478. {
  479. LOGWRN("Material doesn't have a parameter named " + name);
  480. return gpuParam;
  481. }
  482. const String& gpuVarName = iterFind->second;
  483. GpuParamsPtr params = findParamsWithName(gpuVarName);
  484. params->getStructParam(gpuVarName, gpuParam);
  485. return gpuParam;
  486. }
  487. GpuParamTexture Material::getParamTexture(const String& name) const
  488. {
  489. throwIfNotInitialized();
  490. GpuParamTexture gpuParam;
  491. auto iterFind = mValidParams.find(name);
  492. if(iterFind == mValidParams.end())
  493. {
  494. LOGWRN("Material doesn't have a parameter named " + name);
  495. return gpuParam;
  496. }
  497. const String& gpuVarName = iterFind->second;
  498. GpuParamsPtr params = findTexWithName(gpuVarName);
  499. params->getTextureParam(gpuVarName, gpuParam);
  500. return gpuParam;
  501. }
  502. GpuParamSampState Material::getParamSamplerState(const String& name) const
  503. {
  504. throwIfNotInitialized();
  505. GpuParamSampState gpuParam;
  506. auto iterFind = mValidParams.find(name);
  507. if(iterFind == mValidParams.end())
  508. {
  509. LOGWRN("Material doesn't have a parameter named " + name);
  510. return gpuParam;
  511. }
  512. const String& gpuVarName = iterFind->second;
  513. GpuParamsPtr params = findSamplerStateWithName(gpuVarName);
  514. params->getSamplerStateParam(gpuVarName, gpuParam);
  515. return gpuParam;
  516. }
  517. GpuParamsPtr Material::findParamsWithName(const String& name) const
  518. {
  519. for(auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
  520. {
  521. PassParametersPtr params = *iter;
  522. for(UINT32 i = 0; i < params->getNumParams(); i++)
  523. {
  524. GpuParamsPtr& paramPtr = params->getParamByIdx(i);
  525. if(paramPtr)
  526. {
  527. if(paramPtr->hasParam(name))
  528. return paramPtr;
  529. }
  530. }
  531. }
  532. BS_EXCEPT(InternalErrorException, "Shader has no parameter with the name: " + name);
  533. }
  534. GpuParamsPtr Material::findTexWithName(const String& name) const
  535. {
  536. for(auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
  537. {
  538. PassParametersPtr params = *iter;
  539. for(UINT32 i = 0; i < params->getNumParams(); i++)
  540. {
  541. GpuParamsPtr& paramPtr = params->getParamByIdx(i);
  542. if(paramPtr)
  543. {
  544. if(paramPtr->hasTexture(name))
  545. return paramPtr;
  546. }
  547. }
  548. }
  549. BS_EXCEPT(InternalErrorException, "Shader has no parameter with the name: " + name);
  550. }
  551. GpuParamsPtr Material::findSamplerStateWithName(const String& name) const
  552. {
  553. for(auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
  554. {
  555. PassParametersPtr params = *iter;
  556. for(UINT32 i = 0; i < params->getNumParams(); i++)
  557. {
  558. GpuParamsPtr& paramPtr = params->getParamByIdx(i);
  559. if(paramPtr)
  560. {
  561. if(paramPtr->hasSamplerState(name))
  562. return paramPtr;
  563. }
  564. }
  565. }
  566. BS_EXCEPT(InternalErrorException, "Shader has no parameter with the name: " + name);
  567. }
  568. bool Material::_isCoreDirty(MaterialDirtyFlag flag) const
  569. {
  570. if (flag == MaterialDirtyFlag::Params)
  571. {
  572. for (auto& paramsPerPass : mParametersPerPass)
  573. {
  574. for (UINT32 i = 0; i < paramsPerPass->getNumParams(); i++)
  575. {
  576. GpuParamsPtr params = paramsPerPass->getParamByIdx(i);
  577. if (params != nullptr && params->_isCoreDirty())
  578. return true;
  579. }
  580. }
  581. return false;
  582. }
  583. else
  584. return (mCoreDirtyFlags & (UINT32)flag) != 0 || (mShader != nullptr && mShader->_isCoreDirty(ShaderDirtyFlag::Shader));
  585. }
  586. void Material::_markCoreClean(MaterialDirtyFlag flag)
  587. {
  588. mCoreDirtyFlags &= ~(UINT32)flag;
  589. if (flag == MaterialDirtyFlag::Material)
  590. {
  591. if (mShader != nullptr)
  592. mShader->_markCoreClean(ShaderDirtyFlag::Shader);
  593. }
  594. if (flag == MaterialDirtyFlag::Material || flag == MaterialDirtyFlag::Params)
  595. {
  596. for (auto& paramsPerPass : mParametersPerPass)
  597. {
  598. for (UINT32 i = 0; i < paramsPerPass->getNumParams(); i++)
  599. {
  600. GpuParamsPtr params = paramsPerPass->getParamByIdx(i);
  601. if (params != nullptr)
  602. params->_markCoreClean();
  603. }
  604. }
  605. }
  606. }
  607. Vector<MaterialProxy::ParamsBindInfo> Material::_getDirtyProxyParams()
  608. {
  609. Vector<MaterialProxy::ParamsBindInfo> dirtyParams;
  610. UINT32 idx = 0;
  611. UINT32 numPasses = mShader->getBestTechnique()->getNumPasses();
  612. for (UINT32 i = 0; i < numPasses; i++)
  613. {
  614. PassParametersPtr params = mParametersPerPass[i];
  615. PassPtr pass = mShader->getBestTechnique()->getPass(i);
  616. if (pass->hasVertexProgram())
  617. {
  618. if (params->mVertParams->_isCoreDirty())
  619. dirtyParams.push_back(MaterialProxy::ParamsBindInfo(idx, params->mVertParams));
  620. idx++;
  621. }
  622. if (pass->hasFragmentProgram())
  623. {
  624. if (params->mFragParams->_isCoreDirty())
  625. dirtyParams.push_back(MaterialProxy::ParamsBindInfo(idx, params->mFragParams));
  626. idx++;
  627. }
  628. if (pass->hasGeometryProgram())
  629. {
  630. if (params->mGeomParams->_isCoreDirty())
  631. dirtyParams.push_back(MaterialProxy::ParamsBindInfo(idx, params->mGeomParams));
  632. idx++;
  633. }
  634. if (pass->hasHullProgram())
  635. {
  636. if (params->mHullParams->_isCoreDirty())
  637. dirtyParams.push_back(MaterialProxy::ParamsBindInfo(idx, params->mHullParams));
  638. idx++;
  639. }
  640. if (pass->hasDomainProgram())
  641. {
  642. if (params->mDomainParams->_isCoreDirty())
  643. dirtyParams.push_back(MaterialProxy::ParamsBindInfo(idx, params->mDomainParams));
  644. idx++;
  645. }
  646. if (pass->hasComputeProgram())
  647. {
  648. if (params->mComputeParams->_isCoreDirty())
  649. dirtyParams.push_back(MaterialProxy::ParamsBindInfo(idx, params->mComputeParams));
  650. idx++;
  651. }
  652. }
  653. return dirtyParams;
  654. }
  655. MaterialProxyPtr Material::_createProxy()
  656. {
  657. throwIfNotInitialized();
  658. MaterialProxyPtr proxy = bs_shared_ptr<MaterialProxy>();
  659. UINT32 numPasses = mShader->getBestTechnique()->getNumPasses();
  660. for (UINT32 i = 0; i < numPasses; i++)
  661. {
  662. PassParametersPtr params = mParametersPerPass[i];
  663. PassPtr pass = mShader->getBestTechnique()->getPass(i);
  664. proxy->passes.push_back(MaterialProxyPass());
  665. MaterialProxyPass& passData = proxy->passes.back();
  666. if (pass->hasVertexProgram())
  667. {
  668. passData.vertexProg = pass->getVertexProgram();
  669. passData.vertexProgParamsIdx = (UINT32)proxy->params.size();
  670. proxy->params.push_back(params->mVertParams->_cloneForCore());
  671. }
  672. else
  673. passData.vertexProgParamsIdx = 0;
  674. if (pass->hasFragmentProgram())
  675. {
  676. passData.fragmentProg = pass->getFragmentProgram();
  677. passData.fragmentProgParamsIdx = (UINT32)proxy->params.size();
  678. proxy->params.push_back(params->mFragParams->_cloneForCore());
  679. }
  680. else
  681. passData.fragmentProgParamsIdx = 0;
  682. if (pass->hasGeometryProgram())
  683. {
  684. passData.geometryProg = pass->getGeometryProgram();
  685. passData.geometryProgParamsIdx = (UINT32)proxy->params.size();
  686. proxy->params.push_back(params->mGeomParams->_cloneForCore());
  687. }
  688. else
  689. passData.geometryProgParamsIdx = 0;
  690. if (pass->hasHullProgram())
  691. {
  692. passData.hullProg = pass->getHullProgram();
  693. passData.hullProgParamsIdx = (UINT32)proxy->params.size();
  694. proxy->params.push_back(params->mHullParams->_cloneForCore());
  695. }
  696. else
  697. passData.hullProgParamsIdx = 0;
  698. if (pass->hasDomainProgram())
  699. {
  700. passData.domainProg = pass->getDomainProgram();
  701. passData.domainProgParamsIdx = (UINT32)proxy->params.size();
  702. proxy->params.push_back(params->mDomainParams->_cloneForCore());
  703. }
  704. else
  705. passData.domainProgParamsIdx = 0;
  706. if (pass->hasComputeProgram())
  707. {
  708. passData.computeProg = pass->getComputeProgram();
  709. passData.computeProgParamsIdx = (UINT32)proxy->params.size();
  710. proxy->params.push_back(params->mComputeParams->_cloneForCore());
  711. }
  712. else
  713. passData.computeProgParamsIdx = 0;
  714. passData.blendState = pass->getBlendState();
  715. passData.rasterizerState = pass->getRasterizerState();
  716. passData.depthStencilState = pass->getDepthStencilState();
  717. passData.stencilRefValue = pass->getStencilRefValue();
  718. }
  719. if (mShader->_isCoreDirty(ShaderDirtyFlag::Proxy))
  720. {
  721. mShader->_setActiveProxy(mShader->_createProxy());
  722. mShader->_markCoreClean(ShaderDirtyFlag::Proxy);
  723. }
  724. proxy->shader = mShader->_getActiveProxy();
  725. return proxy;
  726. }
  727. void Material::destroy_internal()
  728. {
  729. freeParamBuffers();
  730. Resource::destroy_internal();
  731. }
  732. void Material::freeParamBuffers()
  733. {
  734. mParamBuffers.clear();
  735. }
  736. HMaterial Material::create()
  737. {
  738. MaterialPtr materialPtr = MaterialManager::instance().create();
  739. return static_resource_cast<Material>(gResources()._createResourceHandle(materialPtr));
  740. }
  741. HMaterial Material::create(ShaderPtr shader)
  742. {
  743. MaterialPtr materialPtr = MaterialManager::instance().create(shader);
  744. return static_resource_cast<Material>(gResources()._createResourceHandle(materialPtr));
  745. }
  746. RTTITypeBase* Material::getRTTIStatic()
  747. {
  748. return MaterialRTTI::instance();
  749. }
  750. RTTITypeBase* Material::getRTTI() const
  751. {
  752. return Material::getRTTIStatic();
  753. }
  754. }