BsMaterial.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  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. #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. bool areParamsEqual(const GpuParamDataDesc& paramA, const GpuParamDataDesc& paramB, bool ignoreBufferOffsets)
  26. {
  27. bool equal = paramA.arraySize == paramB.arraySize && paramA.elementSize == paramB.elementSize
  28. && paramA.type == paramB.type && paramA.arrayElementStride == paramB.arrayElementStride;
  29. if (!ignoreBufferOffsets)
  30. equal &= paramA.cpuMemOffset == paramB.cpuMemOffset && paramA.gpuMemOffset == paramB.gpuMemOffset;
  31. return equal;
  32. }
  33. Map<String, const GpuParamDataDesc*> determineValidDataParameters(const Vector<GpuParamDescPtr>& paramDescs)
  34. {
  35. Map<String, const GpuParamDataDesc*> foundDataParams;
  36. Map<String, bool> validParams;
  37. for (auto iter = paramDescs.begin(); iter != paramDescs.end(); ++iter)
  38. {
  39. const GpuParamDesc& curDesc = **iter;
  40. // Check regular data params
  41. for (auto iter2 = curDesc.params.begin(); iter2 != curDesc.params.end(); ++iter2)
  42. {
  43. bool isParameterValid = true;
  44. const GpuParamDataDesc& curParam = iter2->second;
  45. auto dataFindIter = validParams.find(iter2->first);
  46. if (dataFindIter == validParams.end())
  47. {
  48. validParams[iter2->first] = true;
  49. foundDataParams[iter2->first] = &curParam;
  50. }
  51. else
  52. {
  53. if (validParams[iter2->first])
  54. {
  55. auto dataFindIter2 = foundDataParams.find(iter2->first);
  56. const GpuParamDataDesc* otherParam = dataFindIter2->second;
  57. if (!areParamsEqual(curParam, *otherParam, true))
  58. {
  59. validParams[iter2->first] = false;
  60. foundDataParams.erase(dataFindIter2);
  61. }
  62. }
  63. }
  64. }
  65. }
  66. return foundDataParams;
  67. }
  68. Vector<const GpuParamObjectDesc*> determineValidObjectParameters(const Vector<GpuParamDescPtr>& paramDescs)
  69. {
  70. Vector<const GpuParamObjectDesc*> validParams;
  71. for (auto iter = paramDescs.begin(); iter != paramDescs.end(); ++iter)
  72. {
  73. const GpuParamDesc& curDesc = **iter;
  74. // Check sampler params
  75. for (auto iter2 = curDesc.samplers.begin(); iter2 != curDesc.samplers.end(); ++iter2)
  76. {
  77. validParams.push_back(&iter2->second);
  78. }
  79. // Check texture params
  80. for (auto iter2 = curDesc.textures.begin(); iter2 != curDesc.textures.end(); ++iter2)
  81. {
  82. validParams.push_back(&iter2->second);
  83. }
  84. // Check buffer params
  85. for (auto iter2 = curDesc.buffers.begin(); iter2 != curDesc.buffers.end(); ++iter2)
  86. {
  87. validParams.push_back(&iter2->second);
  88. }
  89. }
  90. return validParams;
  91. }
  92. Set<String> determineValidShareableParamBlocks(const Vector<GpuParamDescPtr>& paramDescs)
  93. {
  94. // Make sure param blocks with the same name actually are the same
  95. Map<String, std::pair<String, GpuParamDescPtr>> uniqueParamBlocks;
  96. Map<String, bool> validParamBlocks;
  97. for (auto iter = paramDescs.begin(); iter != paramDescs.end(); ++iter)
  98. {
  99. const GpuParamDesc& curDesc = **iter;
  100. for (auto blockIter = curDesc.paramBlocks.begin(); blockIter != curDesc.paramBlocks.end(); ++blockIter)
  101. {
  102. bool isBlockValid = true;
  103. const GpuParamBlockDesc& curBlock = blockIter->second;
  104. if (!curBlock.isShareable) // Non-shareable buffers are handled differently, they're allowed same names
  105. continue;
  106. auto iterFind = uniqueParamBlocks.find(blockIter->first);
  107. if (iterFind == uniqueParamBlocks.end())
  108. {
  109. uniqueParamBlocks[blockIter->first] = std::make_pair(blockIter->first, *iter);
  110. validParamBlocks[blockIter->first] = true;
  111. continue;
  112. }
  113. String otherBlockName = iterFind->second.first;
  114. GpuParamDescPtr otherDesc = iterFind->second.second;
  115. for (auto myParamIter = curDesc.params.begin(); myParamIter != curDesc.params.end(); ++myParamIter)
  116. {
  117. const GpuParamDataDesc& myParam = myParamIter->second;
  118. if (myParam.paramBlockSlot != curBlock.slot)
  119. continue; // Param is in another block, so we will check it when its time for that block
  120. auto otherParamFind = otherDesc->params.find(myParamIter->first);
  121. // Cannot find other param, blocks aren't equal
  122. if (otherParamFind == otherDesc->params.end())
  123. {
  124. isBlockValid = false;
  125. break;
  126. }
  127. const GpuParamDataDesc& otherParam = otherParamFind->second;
  128. if (!areParamsEqual(myParam, otherParam, false) || curBlock.name != otherBlockName)
  129. {
  130. isBlockValid = false;
  131. break;
  132. }
  133. }
  134. if (!isBlockValid)
  135. {
  136. if (validParamBlocks[blockIter->first])
  137. {
  138. LOGWRN("Found two param blocks with the same name but different contents: " + blockIter->first);
  139. validParamBlocks[blockIter->first] = false;
  140. }
  141. }
  142. }
  143. }
  144. Set<String> validParamBlocksReturn;
  145. for (auto iter = validParamBlocks.begin(); iter != validParamBlocks.end(); ++iter)
  146. {
  147. if (iter->second)
  148. validParamBlocksReturn.insert(iter->first);
  149. }
  150. return validParamBlocksReturn;
  151. }
  152. Map<String, String> determineParameterToBlockMapping(const Vector<GpuParamDescPtr>& paramDescs)
  153. {
  154. Map<String, String> paramToParamBlock;
  155. for (auto iter = paramDescs.begin(); iter != paramDescs.end(); ++iter)
  156. {
  157. const GpuParamDesc& curDesc = **iter;
  158. for (auto iter2 = curDesc.params.begin(); iter2 != curDesc.params.end(); ++iter2)
  159. {
  160. const GpuParamDataDesc& curParam = iter2->second;
  161. auto iterFind = paramToParamBlock.find(curParam.name);
  162. if (iterFind != paramToParamBlock.end())
  163. continue;
  164. for (auto iterBlock = curDesc.paramBlocks.begin(); iterBlock != curDesc.paramBlocks.end(); ++iterBlock)
  165. {
  166. if (iterBlock->second.slot == curParam.paramBlockSlot)
  167. {
  168. paramToParamBlock[curParam.name] = iterBlock->second.name;
  169. break;
  170. }
  171. }
  172. }
  173. }
  174. return paramToParamBlock;
  175. }
  176. Map<String, String> determineParamMappings(const Vector<GpuParamDescPtr>& paramDescs, const Map<String, SHADER_DATA_PARAM_DESC>& dataParams,
  177. const Map<String, SHADER_OBJECT_PARAM_DESC>& objectParam)
  178. {
  179. Map<String, String> validParams;
  180. Map<String, const GpuParamDataDesc*> validDataParameters = determineValidDataParameters(paramDescs);
  181. Vector<const GpuParamObjectDesc*> validObjectParameters = determineValidObjectParameters(paramDescs);
  182. Map<String, String> paramToParamBlockMap = determineParameterToBlockMapping(paramDescs);
  183. // Create data param mappings
  184. for (auto iter = dataParams.begin(); iter != dataParams.end(); ++iter)
  185. {
  186. auto findIter = validDataParameters.find(iter->second.gpuVariableName);
  187. // Not valid so we skip it
  188. if (findIter == validDataParameters.end())
  189. continue;
  190. if (findIter->second->type != iter->second.type)
  191. {
  192. LOGWRN("Ignoring shader parameter \"" + iter->first + "\". Type doesn't match the one defined in the gpu program. "
  193. + "Shader defined type: " + toString(iter->second.type) + " - Gpu program defined type: " + toString(findIter->second->type));
  194. continue;
  195. }
  196. if (findIter->second->arraySize != iter->second.arraySize)
  197. {
  198. LOGWRN("Ignoring shader parameter \"" + iter->first + "\". Array size doesn't match the one defined in the gpu program."
  199. + "Shader defined array size: " + toString(iter->second.arraySize) + " - Gpu program defined array size: " + toString(findIter->second->arraySize));
  200. continue;
  201. }
  202. auto findBlockIter = paramToParamBlockMap.find(iter->second.gpuVariableName);
  203. if (findBlockIter == paramToParamBlockMap.end())
  204. BS_EXCEPT(InternalErrorException, "Parameter doesn't exist in param to param block map but exists in valid param map.");
  205. String& paramBlockName = findBlockIter->second;
  206. validParams[iter->first] = iter->second.gpuVariableName;
  207. }
  208. // Create object param mappings
  209. for (auto iter = objectParam.begin(); iter != objectParam.end(); ++iter)
  210. {
  211. const Vector<String>& gpuVariableNames = iter->second.gpuVariableNames;
  212. for (auto iter2 = gpuVariableNames.begin(); iter2 != gpuVariableNames.end(); ++iter2)
  213. {
  214. for (auto iter3 = validObjectParameters.begin(); iter3 != validObjectParameters.end(); ++iter3)
  215. {
  216. if ((*iter3)->name == (*iter2) && (*iter3)->type == iter->second.type)
  217. {
  218. validParams[iter->first] = *iter2;
  219. break;
  220. }
  221. }
  222. }
  223. }
  224. return validParams;
  225. }
  226. Vector<ShaderBlockDesc> determineShaderBlockData(const Set<String>& paramBlocks, const Vector<GpuParamDescPtr>& paramDescs,
  227. const Map<String, SHADER_PARAM_BLOCK_DESC>& shaderDesc)
  228. {
  229. Vector<ShaderBlockDesc> output;
  230. for (auto iter = paramBlocks.begin(); iter != paramBlocks.end(); ++iter)
  231. {
  232. ShaderBlockDesc shaderBlockDesc;
  233. shaderBlockDesc.create = true;
  234. shaderBlockDesc.usage = GPBU_STATIC;
  235. shaderBlockDesc.size = 0;
  236. shaderBlockDesc.name = *iter;
  237. auto iterFind = shaderDesc.find(*iter);
  238. if (iterFind != shaderDesc.end())
  239. {
  240. shaderBlockDesc.create = !iterFind->second.shared && iterFind->second.rendererSemantic == 0;
  241. shaderBlockDesc.usage = iterFind->second.usage;
  242. }
  243. for (auto iter2 = paramDescs.begin(); iter2 != paramDescs.end(); ++iter2)
  244. {
  245. auto findParamBlockDesc = (*iter2)->paramBlocks.find(*iter);
  246. if (findParamBlockDesc != (*iter2)->paramBlocks.end())
  247. {
  248. shaderBlockDesc.size = findParamBlockDesc->second.blockSize * sizeof(UINT32);
  249. break;
  250. }
  251. }
  252. output.push_back(shaderBlockDesc);
  253. }
  254. return output;
  255. }
  256. Vector<GpuParamDescPtr> MaterialBase::getAllParamDescs(const SPtr<Technique>& technique)
  257. {
  258. Vector<GpuParamDescPtr> allParamDescs;
  259. // Make sure all gpu programs are fully loaded
  260. for (UINT32 i = 0; i < technique->getNumPasses(); i++)
  261. {
  262. PassPtr curPass = technique->getPass(i);
  263. HGpuProgram vertProgram = curPass->getVertexProgram();
  264. if (vertProgram)
  265. {
  266. vertProgram.synchronize();
  267. allParamDescs.push_back(vertProgram->getParamDesc());
  268. }
  269. HGpuProgram fragProgram = curPass->getFragmentProgram();
  270. if (fragProgram)
  271. {
  272. fragProgram.synchronize();
  273. allParamDescs.push_back(fragProgram->getParamDesc());
  274. }
  275. HGpuProgram geomProgram = curPass->getGeometryProgram();
  276. if (geomProgram)
  277. {
  278. geomProgram.synchronize();
  279. allParamDescs.push_back(geomProgram->getParamDesc());
  280. }
  281. HGpuProgram hullProgram = curPass->getHullProgram();
  282. if (hullProgram)
  283. {
  284. hullProgram.synchronize();
  285. allParamDescs.push_back(hullProgram->getParamDesc());
  286. }
  287. HGpuProgram domainProgram = curPass->getDomainProgram();
  288. if (domainProgram)
  289. {
  290. domainProgram.synchronize();
  291. allParamDescs.push_back(domainProgram->getParamDesc());
  292. }
  293. HGpuProgram computeProgram = curPass->getComputeProgram();
  294. if (computeProgram)
  295. {
  296. computeProgram.synchronize();
  297. allParamDescs.push_back(computeProgram->getParamDesc());
  298. }
  299. }
  300. return allParamDescs;
  301. }
  302. Vector<GpuParamDescPtr> MaterialBase::getAllParamDescs(const SPtr<TechniqueCore>& technique)
  303. {
  304. Vector<GpuParamDescPtr> allParamDescs;
  305. // Make sure all gpu programs are fully loaded
  306. for (UINT32 i = 0; i < technique->getNumPasses(); i++)
  307. {
  308. SPtr<PassCore> curPass = technique->getPass(i);
  309. SPtr<GpuProgramCore> vertProgram = curPass->getVertexProgram();
  310. if (vertProgram)
  311. allParamDescs.push_back(vertProgram->getParamDesc());
  312. SPtr<GpuProgramCore> fragProgram = curPass->getFragmentProgram();
  313. if (fragProgram)
  314. allParamDescs.push_back(fragProgram->getParamDesc());
  315. SPtr<GpuProgramCore> geomProgram = curPass->getGeometryProgram();
  316. if (geomProgram)
  317. allParamDescs.push_back(geomProgram->getParamDesc());
  318. SPtr<GpuProgramCore> hullProgram = curPass->getHullProgram();
  319. if (hullProgram)
  320. allParamDescs.push_back(hullProgram->getParamDesc());
  321. SPtr<GpuProgramCore> domainProgram = curPass->getDomainProgram();
  322. if (domainProgram)
  323. allParamDescs.push_back(domainProgram->getParamDesc());
  324. SPtr<GpuProgramCore> computeProgram = curPass->getComputeProgram();
  325. if (computeProgram)
  326. allParamDescs.push_back(computeProgram->getParamDesc());
  327. }
  328. return allParamDescs;
  329. }
  330. template<bool Core>
  331. void TMaterial<Core>::initBestTechnique()
  332. {
  333. mBestTechnique = nullptr;
  334. mParametersPerPass.clear();
  335. if (mShader)
  336. {
  337. mBestTechnique = mShader->getBestTechnique();
  338. if (mBestTechnique == nullptr)
  339. return;
  340. mValidShareableParamBlocks.clear();
  341. Vector<GpuParamDescPtr> allParamDescs = getAllParamDescs(mBestTechnique);
  342. mValidParams = determineParamMappings(allParamDescs, mShader->getDataParams(), mShader->getObjectParams());
  343. // Fill out various helper structures
  344. Set<String> validShareableParamBlocks = determineValidShareableParamBlocks(allParamDescs);
  345. Vector<ShaderBlockDesc> paramBlockData = determineShaderBlockData(validShareableParamBlocks, allParamDescs, mShader->getParamBlocks());
  346. Map<String, ParamBlockPtrType> paramBlockBuffers;
  347. // Create param blocks
  348. for (auto& paramBlock : paramBlockData)
  349. {
  350. ParamBlockPtrType newParamBlockBuffer;
  351. if (paramBlock.create)
  352. {
  353. newParamBlockBuffer = ParamBlockType::create(paramBlock.size, paramBlock.usage);
  354. }
  355. paramBlockBuffers[paramBlock.name] = newParamBlockBuffer;
  356. mValidShareableParamBlocks.insert(paramBlock.name);
  357. }
  358. for (UINT32 i = 0; i < mBestTechnique->getNumPasses(); i++)
  359. {
  360. PassType curPass = mBestTechnique->getPass(i);
  361. SPtr<TPassParameters<Core>> params = SPtr<TPassParameters<Core>>(new TPassParameters<Core>());
  362. GpuProgramType vertProgram = curPass->getVertexProgram();
  363. if (vertProgram)
  364. params->mVertParams = vertProgram->createParameters();
  365. GpuProgramType fragProgram = curPass->getFragmentProgram();
  366. if (fragProgram)
  367. params->mFragParams = fragProgram->createParameters();
  368. GpuProgramType geomProgram = curPass->getGeometryProgram();
  369. if (geomProgram)
  370. params->mGeomParams = geomProgram->createParameters();
  371. GpuProgramType hullProgram = curPass->getHullProgram();
  372. if (hullProgram)
  373. params->mHullParams = hullProgram->createParameters();
  374. GpuProgramType domainProgram = curPass->getDomainProgram();
  375. if (domainProgram)
  376. params->mDomainParams = domainProgram->createParameters();
  377. GpuProgramType computeProgram = curPass->getComputeProgram();
  378. if (computeProgram)
  379. params->mComputeParams = computeProgram->createParameters();
  380. mParametersPerPass.push_back(params);
  381. }
  382. // Assign param block buffers
  383. for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
  384. {
  385. SPtr<TPassParameters<Core>> params = *iter;
  386. for (UINT32 i = 0; i < params->getNumParams(); i++)
  387. {
  388. GpuParamsType& paramPtr = params->getParamByIdx(i);
  389. if (paramPtr)
  390. {
  391. // Assign shareable buffers
  392. for (auto iterBlock = mValidShareableParamBlocks.begin(); iterBlock != mValidShareableParamBlocks.end(); ++iterBlock)
  393. {
  394. const String& paramBlockName = *iterBlock;
  395. if (paramPtr->hasParamBlock(paramBlockName))
  396. {
  397. ParamBlockPtrType blockBuffer = paramBlockBuffers[paramBlockName];
  398. paramPtr->setParamBlockBuffer(paramBlockName, blockBuffer);
  399. }
  400. }
  401. // Create non-shareable ones
  402. const GpuParamDesc& desc = paramPtr->getParamDesc();
  403. for (auto iterBlockDesc = desc.paramBlocks.begin(); iterBlockDesc != desc.paramBlocks.end(); ++iterBlockDesc)
  404. {
  405. if (!iterBlockDesc->second.isShareable)
  406. {
  407. ParamBlockPtrType newParamBlockBuffer = ParamBlockType::create(iterBlockDesc->second.blockSize * sizeof(UINT32));
  408. paramPtr->setParamBlockBuffer(iterBlockDesc->first, newParamBlockBuffer);
  409. }
  410. }
  411. }
  412. }
  413. }
  414. }
  415. }
  416. template class TMaterial < false > ;
  417. template class TMaterial < true > ;
  418. Material::Material()
  419. {
  420. }
  421. Material::~Material()
  422. {
  423. }
  424. void Material::_markCoreDirty()
  425. {
  426. markCoreDirty();
  427. }
  428. SPtr<MaterialCore> Material::getCore() const
  429. {
  430. return std::static_pointer_cast<MaterialCore>(mCoreSpecific);
  431. }
  432. SPtr<CoreObjectCore> Material::createCore() const
  433. {
  434. MaterialCore* material = new (bs_alloc<MaterialCore>()) MaterialCore();
  435. SPtr<MaterialCore> materialPtr = bs_shared_ptr<MaterialCore, GenAlloc>(material);
  436. materialPtr->_setThisPtr(materialPtr);
  437. return materialPtr;
  438. }
  439. void Material::_markCoreDirty()
  440. {
  441. markCoreDirty();
  442. }
  443. HMaterial Material::create()
  444. {
  445. MaterialPtr materialPtr = MaterialManager::instance().create();
  446. return static_resource_cast<Material>(gResources()._createResourceHandle(materialPtr));
  447. }
  448. HMaterial Material::create(ShaderPtr shader)
  449. {
  450. MaterialPtr materialPtr = MaterialManager::instance().create(shader);
  451. return static_resource_cast<Material>(gResources()._createResourceHandle(materialPtr));
  452. }
  453. RTTITypeBase* Material::getRTTIStatic()
  454. {
  455. return MaterialRTTI::instance();
  456. }
  457. RTTITypeBase* Material::getRTTI() const
  458. {
  459. return Material::getRTTIStatic();
  460. }
  461. }