BsGpuParamsSet.cpp 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "BsGpuParamsSet.h"
  4. #include "BsShader.h"
  5. #include "BsTechnique.h"
  6. #include "BsPass.h"
  7. #include "BsGpuProgram.h"
  8. #include "BsGpuPipelineState.h"
  9. #include "BsMaterialParams.h"
  10. #include "BsGpuParamDesc.h"
  11. #include "BsRenderAPI.h"
  12. #include "BsGpuParamBlockBuffer.h"
  13. namespace bs
  14. {
  15. /** Uniquely identifies a GPU parameter. */
  16. struct ValidParamKey
  17. {
  18. ValidParamKey(const String& name, const MaterialParams::ParamType& type)
  19. :name(name), type(type)
  20. { }
  21. bool operator== (const ValidParamKey& rhs) const
  22. {
  23. return name == rhs.name && type == rhs.type;
  24. }
  25. bool operator!= (const ValidParamKey& rhs) const
  26. {
  27. return !(*this == rhs);
  28. }
  29. String name;
  30. MaterialParams::ParamType type;
  31. };
  32. }
  33. /** @cond STDLIB */
  34. namespace std
  35. {
  36. /** Hash value generator for ValidParamKey. */
  37. template<>
  38. struct hash<bs::ValidParamKey>
  39. {
  40. size_t operator()(const bs::ValidParamKey& key) const
  41. {
  42. size_t hash = 0;
  43. bs::hash_combine(hash, key.name);
  44. bs::hash_combine(hash, key.type);
  45. return hash;
  46. }
  47. };
  48. }
  49. /** @endcond */
  50. namespace bs
  51. {
  52. struct ShaderBlockDesc
  53. {
  54. String name;
  55. GpuParamBlockUsage usage;
  56. int size;
  57. bool external;
  58. UINT32 sequentialIdx;
  59. UINT32 set;
  60. UINT32 slot;
  61. };
  62. Vector<SPtr<GpuParamDesc>> getAllParamDescs(const SPtr<Technique>& technique)
  63. {
  64. Vector<SPtr<GpuParamDesc>> allParamDescs;
  65. // Make sure all gpu programs are fully loaded
  66. for (UINT32 i = 0; i < technique->getNumPasses(); i++)
  67. {
  68. SPtr<Pass> curPass = technique->getPass(i);
  69. SPtr<GpuProgram> vertProgram = curPass->getVertexProgram();
  70. if (vertProgram)
  71. {
  72. vertProgram->blockUntilCoreInitialized();
  73. allParamDescs.push_back(vertProgram->getParamDesc());
  74. }
  75. SPtr<GpuProgram> fragProgram = curPass->getFragmentProgram();
  76. if (fragProgram)
  77. {
  78. fragProgram->blockUntilCoreInitialized();
  79. allParamDescs.push_back(fragProgram->getParamDesc());
  80. }
  81. SPtr<GpuProgram> geomProgram = curPass->getGeometryProgram();
  82. if (geomProgram)
  83. {
  84. geomProgram->blockUntilCoreInitialized();
  85. allParamDescs.push_back(geomProgram->getParamDesc());
  86. }
  87. SPtr<GpuProgram> hullProgram = curPass->getHullProgram();
  88. if (hullProgram)
  89. {
  90. hullProgram->blockUntilCoreInitialized();
  91. allParamDescs.push_back(hullProgram->getParamDesc());
  92. }
  93. SPtr<GpuProgram> domainProgram = curPass->getDomainProgram();
  94. if (domainProgram)
  95. {
  96. domainProgram->blockUntilCoreInitialized();
  97. allParamDescs.push_back(domainProgram->getParamDesc());
  98. }
  99. SPtr<GpuProgram> computeProgram = curPass->getComputeProgram();
  100. if (computeProgram)
  101. {
  102. computeProgram->blockUntilCoreInitialized();
  103. allParamDescs.push_back(computeProgram->getParamDesc());
  104. }
  105. }
  106. return allParamDescs;
  107. }
  108. Vector<SPtr<GpuParamDesc>> getAllParamDescs(const SPtr<ct::Technique>& technique)
  109. {
  110. Vector<SPtr<GpuParamDesc>> allParamDescs;
  111. // Make sure all gpu programs are fully loaded
  112. for (UINT32 i = 0; i < technique->getNumPasses(); i++)
  113. {
  114. SPtr<ct::Pass> curPass = technique->getPass(i);
  115. SPtr<ct::GpuProgram> vertProgram = curPass->getVertexProgram();
  116. if (vertProgram)
  117. allParamDescs.push_back(vertProgram->getParamDesc());
  118. SPtr<ct::GpuProgram> fragProgram = curPass->getFragmentProgram();
  119. if (fragProgram)
  120. allParamDescs.push_back(fragProgram->getParamDesc());
  121. SPtr<ct::GpuProgram> geomProgram = curPass->getGeometryProgram();
  122. if (geomProgram)
  123. allParamDescs.push_back(geomProgram->getParamDesc());
  124. SPtr<ct::GpuProgram> hullProgram = curPass->getHullProgram();
  125. if (hullProgram)
  126. allParamDescs.push_back(hullProgram->getParamDesc());
  127. SPtr<ct::GpuProgram> domainProgram = curPass->getDomainProgram();
  128. if (domainProgram)
  129. allParamDescs.push_back(domainProgram->getParamDesc());
  130. SPtr<ct::GpuProgram> computeProgram = curPass->getComputeProgram();
  131. if (computeProgram)
  132. allParamDescs.push_back(computeProgram->getParamDesc());
  133. }
  134. return allParamDescs;
  135. }
  136. bool areParamsEqual(const GpuParamDataDesc& paramA, const GpuParamDataDesc& paramB, bool ignoreBufferOffsets)
  137. {
  138. bool equal = paramA.arraySize == paramB.arraySize && paramA.elementSize == paramB.elementSize
  139. && paramA.type == paramB.type && paramA.arrayElementStride == paramB.arrayElementStride;
  140. if (!ignoreBufferOffsets)
  141. equal &= paramA.cpuMemOffset == paramB.cpuMemOffset && paramA.gpuMemOffset == paramB.gpuMemOffset;
  142. return equal;
  143. }
  144. Vector<ShaderBlockDesc> determineValidShareableParamBlocks(const Vector<SPtr<GpuParamDesc>>& paramDescs,
  145. const Map<String, SHADER_PARAM_BLOCK_DESC>& shaderDesc)
  146. {
  147. struct BlockInfo
  148. {
  149. BlockInfo() { }
  150. BlockInfo(const GpuParamBlockDesc* blockDesc, const SPtr<GpuParamDesc>& paramDesc, bool isValid = true)
  151. :blockDesc(blockDesc), paramDesc(paramDesc), isValid(isValid)
  152. { }
  153. const GpuParamBlockDesc* blockDesc;
  154. SPtr<GpuParamDesc> paramDesc;
  155. bool isValid;
  156. UINT32 set;
  157. UINT32 slot;
  158. };
  159. // Make sure param blocks with the same name actually contain the same fields
  160. Map<String, BlockInfo> uniqueParamBlocks;
  161. for (auto iter = paramDescs.begin(); iter != paramDescs.end(); ++iter)
  162. {
  163. const GpuParamDesc& curDesc = **iter;
  164. for (auto blockIter = curDesc.paramBlocks.begin(); blockIter != curDesc.paramBlocks.end(); ++blockIter)
  165. {
  166. bool isBlockValid = true;
  167. const GpuParamBlockDesc& curBlock = blockIter->second;
  168. if (!curBlock.isShareable) // Non-shareable buffers are handled differently, they're allowed same names
  169. continue;
  170. auto iterFind = uniqueParamBlocks.find(blockIter->first);
  171. if (iterFind == uniqueParamBlocks.end())
  172. {
  173. uniqueParamBlocks[blockIter->first] = BlockInfo(&curBlock, *iter);
  174. continue;
  175. }
  176. const GpuParamBlockDesc& otherBlock = *iterFind->second.blockDesc;
  177. // The block was already determined as invalid, no need to check further
  178. if (!iterFind->second.isValid)
  179. continue;
  180. String otherBlockName = otherBlock.name;
  181. SPtr<GpuParamDesc> otherDesc = iterFind->second.paramDesc;
  182. for (auto myParamIter = curDesc.params.begin(); myParamIter != curDesc.params.end(); ++myParamIter)
  183. {
  184. const GpuParamDataDesc& myParam = myParamIter->second;
  185. if (myParam.paramBlockSet != curBlock.set || myParam.paramBlockSlot != curBlock.slot)
  186. continue; // Param is in another block, so we will check it when its time for that block
  187. auto otherParamFind = otherDesc->params.find(myParamIter->first);
  188. // Cannot find other param, blocks aren't equal
  189. if (otherParamFind == otherDesc->params.end())
  190. {
  191. isBlockValid = false;
  192. break;
  193. }
  194. const GpuParamDataDesc& otherParam = otherParamFind->second;
  195. if (!areParamsEqual(myParam, otherParam, false) || curBlock.name != otherBlockName)
  196. {
  197. isBlockValid = false;
  198. break;
  199. }
  200. }
  201. // Note: Ignoring mismatched blocks for now, because glslang parser doesn't report dead uniform entries,
  202. // meaning identical blocks can have different sets of uniforms reported depending on which are unused.
  203. //if (!isBlockValid)
  204. //{
  205. // LOGWRN("Found two param blocks with the same name but different contents: " + blockIter->first);
  206. // uniqueParamBlocks[blockIter->first] = BlockInfo(&curBlock, nullptr, false);
  207. // continue;
  208. //}
  209. }
  210. }
  211. Vector<ShaderBlockDesc> output;
  212. for (auto& entry : uniqueParamBlocks)
  213. {
  214. if (!entry.second.isValid)
  215. continue;
  216. const GpuParamBlockDesc& curBlock = *entry.second.blockDesc;
  217. ShaderBlockDesc shaderBlockDesc;
  218. shaderBlockDesc.external = false;
  219. shaderBlockDesc.usage = GPBU_STATIC;
  220. shaderBlockDesc.size = curBlock.blockSize * sizeof(UINT32);
  221. shaderBlockDesc.name = entry.first;
  222. shaderBlockDesc.set = curBlock.set;
  223. shaderBlockDesc.slot = curBlock.slot;
  224. auto iterFind = shaderDesc.find(entry.first);
  225. if (iterFind != shaderDesc.end())
  226. {
  227. shaderBlockDesc.external = iterFind->second.shared || iterFind->second.rendererSemantic != StringID::NONE;
  228. shaderBlockDesc.usage = iterFind->second.usage;
  229. }
  230. output.push_back(shaderBlockDesc);
  231. }
  232. return output;
  233. }
  234. Map<String, const GpuParamDataDesc*> determineValidDataParameters(const Vector<SPtr<GpuParamDesc>>& paramDescs)
  235. {
  236. Map<String, const GpuParamDataDesc*> foundDataParams;
  237. Map<String, bool> validParams;
  238. for (auto iter = paramDescs.begin(); iter != paramDescs.end(); ++iter)
  239. {
  240. const GpuParamDesc& curDesc = **iter;
  241. // Check regular data params
  242. for (auto iter2 = curDesc.params.begin(); iter2 != curDesc.params.end(); ++iter2)
  243. {
  244. const GpuParamDataDesc& curParam = iter2->second;
  245. auto dataFindIter = validParams.find(iter2->first);
  246. if (dataFindIter == validParams.end())
  247. {
  248. validParams[iter2->first] = true;
  249. foundDataParams[iter2->first] = &curParam;
  250. }
  251. else
  252. {
  253. if (validParams[iter2->first])
  254. {
  255. auto dataFindIter2 = foundDataParams.find(iter2->first);
  256. const GpuParamDataDesc* otherParam = dataFindIter2->second;
  257. if (!areParamsEqual(curParam, *otherParam, true))
  258. {
  259. validParams[iter2->first] = false;
  260. foundDataParams.erase(dataFindIter2);
  261. }
  262. }
  263. }
  264. }
  265. }
  266. return foundDataParams;
  267. }
  268. Vector<const GpuParamObjectDesc*> determineValidObjectParameters(const Vector<SPtr<GpuParamDesc>>& paramDescs)
  269. {
  270. Vector<const GpuParamObjectDesc*> validParams;
  271. for (auto iter = paramDescs.begin(); iter != paramDescs.end(); ++iter)
  272. {
  273. const GpuParamDesc& curDesc = **iter;
  274. // Check sampler params
  275. for (auto iter2 = curDesc.samplers.begin(); iter2 != curDesc.samplers.end(); ++iter2)
  276. {
  277. validParams.push_back(&iter2->second);
  278. }
  279. // Check texture params
  280. for (auto iter2 = curDesc.textures.begin(); iter2 != curDesc.textures.end(); ++iter2)
  281. {
  282. validParams.push_back(&iter2->second);
  283. }
  284. // Check load-store texture params
  285. for (auto iter2 = curDesc.loadStoreTextures.begin(); iter2 != curDesc.loadStoreTextures.end(); ++iter2)
  286. {
  287. validParams.push_back(&iter2->second);
  288. }
  289. // Check buffer params
  290. for (auto iter2 = curDesc.buffers.begin(); iter2 != curDesc.buffers.end(); ++iter2)
  291. {
  292. validParams.push_back(&iter2->second);
  293. }
  294. }
  295. return validParams;
  296. }
  297. Map<String, String> determineParameterToBlockMapping(const Vector<SPtr<GpuParamDesc>>& paramDescs)
  298. {
  299. Map<String, String> paramToParamBlock;
  300. for (auto iter = paramDescs.begin(); iter != paramDescs.end(); ++iter)
  301. {
  302. const GpuParamDesc& curDesc = **iter;
  303. for (auto iter2 = curDesc.params.begin(); iter2 != curDesc.params.end(); ++iter2)
  304. {
  305. const GpuParamDataDesc& curParam = iter2->second;
  306. auto iterFind = paramToParamBlock.find(curParam.name);
  307. if (iterFind != paramToParamBlock.end())
  308. continue;
  309. for (auto iterBlock = curDesc.paramBlocks.begin(); iterBlock != curDesc.paramBlocks.end(); ++iterBlock)
  310. {
  311. if (iterBlock->second.set == curParam.paramBlockSet && iterBlock->second.slot == curParam.paramBlockSlot)
  312. {
  313. paramToParamBlock[curParam.name] = iterBlock->second.name;
  314. break;
  315. }
  316. }
  317. }
  318. }
  319. return paramToParamBlock;
  320. }
  321. UnorderedMap<ValidParamKey, String> determineValidParameters(const Vector<SPtr<GpuParamDesc>>& paramDescs,
  322. const Map<String, SHADER_DATA_PARAM_DESC>& dataParams,
  323. const Map<String, SHADER_OBJECT_PARAM_DESC>& textureParams,
  324. const Map<String, SHADER_OBJECT_PARAM_DESC>& bufferParams,
  325. const Map<String, SHADER_OBJECT_PARAM_DESC>& samplerParams)
  326. {
  327. UnorderedMap<ValidParamKey, String> validParams;
  328. Map<String, const GpuParamDataDesc*> validDataParameters = determineValidDataParameters(paramDescs);
  329. Vector<const GpuParamObjectDesc*> validObjectParameters = determineValidObjectParameters(paramDescs);
  330. Map<String, String> paramToParamBlockMap = determineParameterToBlockMapping(paramDescs);
  331. // Create data param mappings
  332. for (auto iter = dataParams.begin(); iter != dataParams.end(); ++iter)
  333. {
  334. auto findIter = validDataParameters.find(iter->second.gpuVariableName);
  335. // Not valid so we skip it
  336. if (findIter == validDataParameters.end())
  337. continue;
  338. if (findIter->second->type != iter->second.type && !(iter->second.type == GPDT_COLOR && findIter->second->type == GPDT_FLOAT4))
  339. {
  340. LOGWRN("Ignoring shader parameter \"" + iter->first + "\". Type doesn't match the one defined in the gpu program. "
  341. + "Shader defined type: " + toString(iter->second.type) + " - Gpu program defined type: " + toString(findIter->second->type));
  342. continue;
  343. }
  344. auto findBlockIter = paramToParamBlockMap.find(iter->second.gpuVariableName);
  345. if (findBlockIter == paramToParamBlockMap.end())
  346. BS_EXCEPT(InternalErrorException, "Parameter doesn't exist in param to param block map but exists in valid param map.");
  347. ValidParamKey key(iter->second.gpuVariableName, MaterialParams::ParamType::Data);
  348. validParams.insert(std::make_pair(key, iter->first));
  349. }
  350. // Create object param mappings
  351. auto determineObjectMappings = [&](const Map<String, SHADER_OBJECT_PARAM_DESC>& params, MaterialParams::ParamType paramType)
  352. {
  353. for (auto iter = params.begin(); iter != params.end(); ++iter)
  354. {
  355. const Vector<String>& gpuVariableNames = iter->second.gpuVariableNames;
  356. for (auto iter2 = gpuVariableNames.begin(); iter2 != gpuVariableNames.end(); ++iter2)
  357. {
  358. for (auto iter3 = validObjectParameters.begin(); iter3 != validObjectParameters.end(); ++iter3)
  359. {
  360. if ((*iter3)->name == (*iter2))
  361. {
  362. ValidParamKey key(*iter2, paramType);
  363. validParams.insert(std::make_pair(key, iter->first));
  364. break;
  365. }
  366. }
  367. }
  368. }
  369. };
  370. determineObjectMappings(textureParams, MaterialParams::ParamType::Texture);
  371. determineObjectMappings(samplerParams, MaterialParams::ParamType::Sampler);
  372. determineObjectMappings(bufferParams, MaterialParams::ParamType::Buffer);
  373. return validParams;
  374. }
  375. template<bool Core>
  376. const UINT32 TGpuParamsSet<Core>::NUM_STAGES = 6;
  377. template<bool Core>
  378. TGpuParamsSet<Core>::TGpuParamsSet(const SPtr<TechniqueType>& technique, const ShaderType& shader,
  379. const SPtr<MaterialParamsType>& params)
  380. :mPassParams(technique->getNumPasses()), mParamVersion(0)
  381. {
  382. UINT32 numPasses = technique->getNumPasses();
  383. // Create GpuParams for each pass and shader stage
  384. for (UINT32 i = 0; i < numPasses; i++)
  385. {
  386. SPtr<PassType> curPass = technique->getPass(i);
  387. GraphicsPipelineStateType gfxPipeline = curPass->getGraphicsPipelineState();
  388. if(gfxPipeline != nullptr)
  389. mPassParams[i] = GpuParamsType::create(gfxPipeline);
  390. else
  391. {
  392. ComputePipelineStateType computePipeline = curPass->getComputePipelineState();
  393. mPassParams[i] = GpuParamsType::create(computePipeline);
  394. }
  395. }
  396. // Create and assign parameter block buffers
  397. Vector<SPtr<GpuParamDesc>> allParamDescs = getAllParamDescs(technique);
  398. //// Fill out various helper structures
  399. Vector<ShaderBlockDesc> paramBlockData = determineValidShareableParamBlocks(allParamDescs, shader->getParamBlocks());
  400. UnorderedMap<ValidParamKey, String> validParams = determineValidParameters(
  401. allParamDescs,
  402. shader->getDataParams(),
  403. shader->getTextureParams(),
  404. shader->getBufferParams(),
  405. shader->getSamplerParams());
  406. Map<String, ParamBlockPtrType> paramBlockBuffers;
  407. //// Create param blocks
  408. for (auto& paramBlock : paramBlockData)
  409. {
  410. ParamBlockPtrType newParamBlockBuffer;
  411. if (!paramBlock.external)
  412. newParamBlockBuffer = ParamBlockType::create(paramBlock.size, paramBlock.usage);
  413. paramBlock.sequentialIdx = (UINT32)mBlocks.size();
  414. paramBlockBuffers[paramBlock.name] = newParamBlockBuffer;
  415. mBlocks.push_back(BlockInfo(paramBlock.name, paramBlock.set, paramBlock.slot, newParamBlockBuffer, true));
  416. }
  417. //// Assign param block buffers and generate information about data parameters
  418. assert(numPasses < 64); // BlockInfo flags uses UINT64 for tracking usage
  419. for (UINT32 i = 0; i < numPasses; i++)
  420. {
  421. SPtr<GpuParamsType> paramPtr = mPassParams[i];
  422. for (UINT32 j = 0; j < NUM_STAGES; j++)
  423. {
  424. GpuProgramType progType = (GpuProgramType)j;
  425. // Assign shareable buffers
  426. for (auto& block : paramBlockData)
  427. {
  428. const String& paramBlockName = block.name;
  429. if (paramPtr->hasParamBlock(progType, paramBlockName))
  430. {
  431. ParamBlockPtrType blockBuffer = paramBlockBuffers[paramBlockName];
  432. paramPtr->setParamBlockBuffer(progType, paramBlockName, blockBuffer);
  433. }
  434. }
  435. // Create non-shareable ones (these are buffers defined by default by the RHI usually)
  436. SPtr<GpuParamDesc> desc = paramPtr->getParamDesc(progType);
  437. if (desc == nullptr)
  438. continue;
  439. for (auto iterBlockDesc = desc->paramBlocks.begin(); iterBlockDesc != desc->paramBlocks.end(); ++iterBlockDesc)
  440. {
  441. const GpuParamBlockDesc& blockDesc = iterBlockDesc->second;
  442. UINT32 globalBlockIdx = (UINT32)-1;
  443. if (!blockDesc.isShareable)
  444. {
  445. ParamBlockPtrType newParamBlockBuffer = ParamBlockType::create(blockDesc.blockSize * sizeof(UINT32));
  446. globalBlockIdx = (UINT32)mBlocks.size();
  447. paramPtr->setParamBlockBuffer(progType, iterBlockDesc->first, newParamBlockBuffer);
  448. mBlocks.emplace_back(iterBlockDesc->first, iterBlockDesc->second.set,
  449. iterBlockDesc->second.slot, newParamBlockBuffer, false);
  450. }
  451. else
  452. {
  453. auto iterFind = std::find_if(paramBlockData.begin(), paramBlockData.end(), [&](const auto& x)
  454. {
  455. return x.name == iterBlockDesc->first;
  456. });
  457. if(iterFind != paramBlockData.end())
  458. globalBlockIdx = iterFind->sequentialIdx;
  459. }
  460. // If this parameter block is valid, create data/struct mappings for it
  461. if (globalBlockIdx == (UINT32)-1)
  462. continue;
  463. for(auto& dataParam : desc->params)
  464. {
  465. if (dataParam.second.paramBlockSet != blockDesc.set || dataParam.second.paramBlockSlot != blockDesc.slot)
  466. continue;
  467. ValidParamKey key(dataParam.first, MaterialParams::ParamType::Data);
  468. auto iterFind = validParams.find(key);
  469. if (iterFind == validParams.end())
  470. continue;
  471. UINT32 paramIdx = params->getParamIndex(iterFind->second);
  472. // Parameter shouldn't be in the valid parameter list if it cannot be found
  473. assert(paramIdx != -1);
  474. mDataParamInfos.push_back(DataParamInfo());
  475. DataParamInfo& paramInfo = mDataParamInfos.back();
  476. paramInfo.paramIdx = paramIdx;
  477. paramInfo.blockIdx = globalBlockIdx;
  478. paramInfo.offset = dataParam.second.cpuMemOffset;
  479. }
  480. }
  481. }
  482. }
  483. // Add buffers defined in shader but not actually used by GPU programs (so we can check if user is providing a
  484. // valid buffer name)
  485. auto& allParamBlocks = shader->getParamBlocks();
  486. for (auto& entry : allParamBlocks)
  487. {
  488. auto iterFind = std::find_if(mBlocks.begin(), mBlocks.end(),
  489. [&](auto& x)
  490. {
  491. return x.name == entry.first;
  492. });
  493. if(iterFind == mBlocks.end())
  494. {
  495. mBlocks.push_back(BlockInfo(entry.first, 0, 0, nullptr, true));
  496. mBlocks.back().isUsed = false;
  497. }
  498. }
  499. // Generate information about object parameters
  500. bs_frame_mark();
  501. {
  502. FrameVector<ObjectParamInfo> objParamInfos;
  503. UINT32 offsetsSize = numPasses * NUM_STAGES * 4 * sizeof(UINT32);
  504. UINT32* offsets = (UINT32*)bs_frame_alloc(offsetsSize);
  505. memset(offsets, 0, offsetsSize);
  506. // First store all objects in temporary arrays since we don't know how many of them are
  507. UINT32 totalNumObjects = 0;
  508. UINT32* stageOffsets = offsets;
  509. for (UINT32 i = 0; i < numPasses; i++)
  510. {
  511. SPtr<GpuParamsType> paramPtr = mPassParams[i];
  512. for (UINT32 j = 0; j < NUM_STAGES; j++)
  513. {
  514. GpuProgramType progType = (GpuProgramType)j;
  515. auto processObjectParams = [&](const Map<String, GpuParamObjectDesc>& gpuParams,
  516. UINT32 stageIdx, MaterialParams::ParamType paramType)
  517. {
  518. for (auto& param : gpuParams)
  519. {
  520. ValidParamKey key(param.first, paramType);
  521. auto iterFind = validParams.find(key);
  522. if (iterFind == validParams.end())
  523. continue;
  524. UINT32 paramIdx;
  525. auto result = params->getParamIndex(iterFind->second, paramType, GPDT_UNKNOWN, 0, paramIdx);
  526. // Parameter shouldn't be in the valid parameter list if it cannot be found
  527. assert(result == MaterialParams::GetParamResult::Success);
  528. objParamInfos.push_back(ObjectParamInfo());
  529. ObjectParamInfo& paramInfo = objParamInfos.back();
  530. paramInfo.paramIdx = paramIdx;
  531. paramInfo.slotIdx = param.second.slot;
  532. paramInfo.setIdx = param.second.set;
  533. stageOffsets[stageIdx]++;
  534. totalNumObjects++;
  535. }
  536. };
  537. SPtr<GpuParamDesc> desc = paramPtr->getParamDesc(progType);
  538. if(desc == nullptr)
  539. {
  540. stageOffsets += 4;
  541. continue;
  542. }
  543. processObjectParams(desc->textures, 0, MaterialParams::ParamType::Texture);
  544. processObjectParams(desc->loadStoreTextures, 1, MaterialParams::ParamType::Texture);
  545. processObjectParams(desc->buffers, 2, MaterialParams::ParamType::Buffer);
  546. processObjectParams(desc->samplers, 3, MaterialParams::ParamType::Sampler);
  547. stageOffsets += 4;
  548. }
  549. }
  550. // Transfer all objects into their permanent storage
  551. UINT32 numBlocks = (UINT32)mBlocks.size();
  552. UINT32 blockBindingsSize = numBlocks * numPasses * sizeof(PassBlockBindings);
  553. UINT32 objectParamInfosSize = totalNumObjects * sizeof(ObjectParamInfo) + numPasses * sizeof(PassParamInfo);
  554. mData = (UINT8*)bs_alloc(objectParamInfosSize + blockBindingsSize);
  555. UINT8* dataIter = mData;
  556. mPassParamInfos = (PassParamInfo*)dataIter;
  557. memset(mPassParamInfos, 0, objectParamInfosSize);
  558. dataIter += objectParamInfosSize;
  559. StageParamInfo* stageInfos = (StageParamInfo*)mPassParamInfos;
  560. ObjectParamInfo* objInfos = (ObjectParamInfo*)(mPassParamInfos + numPasses);
  561. memcpy(objInfos, objParamInfos.data(), totalNumObjects * sizeof(ObjectParamInfo));
  562. UINT32 objInfoOffset = 0;
  563. stageOffsets = offsets;
  564. for (UINT32 i = 0; i < numPasses; i++)
  565. {
  566. for (UINT32 j = 0; j < NUM_STAGES; j++)
  567. {
  568. StageParamInfo& stage = stageInfos[i * NUM_STAGES + j];
  569. if(stageOffsets[0] > 0)
  570. {
  571. UINT32 numEntries = stageOffsets[0];
  572. stage.textures = objInfos + objInfoOffset;
  573. stage.numTextures = numEntries;
  574. objInfoOffset += numEntries;
  575. }
  576. if (stageOffsets[1] > 0)
  577. {
  578. UINT32 numEntries = stageOffsets[1];
  579. stage.loadStoreTextures = objInfos + objInfoOffset;
  580. stage.numLoadStoreTextures = numEntries;
  581. objInfoOffset += numEntries;
  582. }
  583. if (stageOffsets[2] > 0)
  584. {
  585. UINT32 numEntries = stageOffsets[2];
  586. stage.buffers = objInfos + objInfoOffset;
  587. stage.numBuffers = numEntries;
  588. objInfoOffset += numEntries;
  589. }
  590. if (stageOffsets[3] > 0)
  591. {
  592. UINT32 numEntries = stageOffsets[3];
  593. stage.samplerStates = objInfos + objInfoOffset;
  594. stage.numSamplerStates = numEntries;
  595. objInfoOffset += numEntries;
  596. }
  597. stageOffsets += 4;
  598. }
  599. }
  600. // Determine on which passes & stages are buffers used on
  601. for (auto& block : mBlocks)
  602. {
  603. block.passData = (PassBlockBindings*)dataIter;
  604. dataIter += sizeof(PassBlockBindings) * numPasses;
  605. }
  606. for (auto& block : mBlocks)
  607. {
  608. for (UINT32 i = 0; i < numPasses; i++)
  609. {
  610. SPtr<GpuParamsType> paramPtr = mPassParams[i];
  611. for (UINT32 j = 0; j < NUM_STAGES; j++)
  612. {
  613. GpuProgramType progType = (GpuProgramType)j;
  614. SPtr<GpuParamDesc> curDesc = paramPtr->getParamDesc(progType);
  615. if (curDesc == nullptr)
  616. {
  617. block.passData[i].bindings[j].set = -1;
  618. block.passData[i].bindings[j].slot = -1;
  619. continue;
  620. }
  621. auto iterFind = curDesc->paramBlocks.find(block.name);
  622. if (iterFind == curDesc->paramBlocks.end())
  623. {
  624. block.passData[i].bindings[j].set = -1;
  625. block.passData[i].bindings[j].slot = -1;
  626. continue;
  627. }
  628. block.passData[i].bindings[j].set = iterFind->second.set;
  629. block.passData[i].bindings[j].slot = iterFind->second.slot;
  630. }
  631. }
  632. }
  633. bs_frame_free(offsets);
  634. }
  635. bs_frame_clear();
  636. }
  637. template<bool Core>
  638. TGpuParamsSet<Core>::~TGpuParamsSet()
  639. {
  640. // All allocations share the same memory, so we just clear it all at once
  641. bs_free(mData);
  642. }
  643. template<bool Core>
  644. SPtr<typename TGpuParamsSet<Core>::GpuParamsType> TGpuParamsSet<Core>::getGpuParams(UINT32 passIdx)
  645. {
  646. if (passIdx >= mPassParams.size())
  647. return nullptr;
  648. return mPassParams[passIdx];
  649. }
  650. template<bool Core>
  651. UINT32 TGpuParamsSet<Core>::getParamBlockBufferIndex(const String& name) const
  652. {
  653. for (UINT32 i = 0; i < (UINT32)mBlocks.size(); i++)
  654. {
  655. const BlockInfo& block = mBlocks[i];
  656. if (block.name == name)
  657. return i;
  658. }
  659. return -1;
  660. }
  661. template<bool Core>
  662. void TGpuParamsSet<Core>::setParamBlockBuffer(UINT32 index, const ParamBlockPtrType& paramBlock,
  663. bool ignoreInUpdate)
  664. {
  665. BlockInfo& blockInfo = mBlocks[index];
  666. if (!blockInfo.shareable)
  667. {
  668. LOGERR("Cannot set parameter block buffer with the name \"" + blockInfo.name +
  669. "\". Buffer is not assignable. ");
  670. return;
  671. }
  672. if (!blockInfo.isUsed)
  673. return;
  674. blockInfo.allowUpdate = !ignoreInUpdate;
  675. if (blockInfo.buffer != paramBlock)
  676. {
  677. blockInfo.buffer = paramBlock;
  678. UINT32 numPasses = (UINT32)mPassParams.size();
  679. for (UINT32 j = 0; j < numPasses; j++)
  680. {
  681. SPtr<GpuParamsType> paramPtr = mPassParams[j];
  682. for (UINT32 i = 0; i < NUM_STAGES; i++)
  683. {
  684. GpuProgramType progType = (GpuProgramType)i;
  685. const BlockBinding& binding = blockInfo.passData[j].bindings[progType];
  686. if (binding.slot != -1)
  687. paramPtr->setParamBlockBuffer(binding.set, binding.slot, paramBlock);
  688. }
  689. }
  690. }
  691. }
  692. template<bool Core>
  693. void TGpuParamsSet<Core>::setParamBlockBuffer(const String& name, const ParamBlockPtrType& paramBlock,
  694. bool ignoreInUpdate)
  695. {
  696. UINT32 bufferIdx = getParamBlockBufferIndex(name);
  697. if(bufferIdx == (UINT32)-1)
  698. {
  699. LOGERR("Cannot set parameter block buffer with the name \"" + name + "\". Buffer name not found. ");
  700. return;
  701. }
  702. setParamBlockBuffer(bufferIdx, paramBlock, ignoreInUpdate);
  703. }
  704. template<bool Core>
  705. void TGpuParamsSet<Core>::update(const SPtr<MaterialParamsType>& params, bool updateAll)
  706. {
  707. // Note: Instead of iterating over every single parameter, it might be more efficient for @p params to keep
  708. // a ring buffer and a version number. Then we could just iterate over the ring buffer and only access dirty
  709. // parameters. If the version number is too high (larger than ring buffer can store), then we force update for all.
  710. // Update data params
  711. for(auto& paramInfo : mDataParamInfos)
  712. {
  713. ParamBlockPtrType paramBlock = mBlocks[paramInfo.blockIdx].buffer;
  714. if (paramBlock == nullptr || !mBlocks[paramInfo.blockIdx].allowUpdate)
  715. continue;
  716. const MaterialParams::ParamData* materialParamInfo = params->getParamData(paramInfo.paramIdx);
  717. if (materialParamInfo->version <= mParamVersion && !updateAll)
  718. continue;
  719. UINT32 arraySize = materialParamInfo->arraySize == 0 ? 1 : materialParamInfo->arraySize;
  720. const GpuParamDataTypeInfo& typeInfo = GpuParams::PARAM_SIZES.lookup[(int)materialParamInfo->dataType];
  721. UINT32 paramSize = typeInfo.numColumns * typeInfo.numRows * typeInfo.baseTypeSize;
  722. UINT8* data = params->getData(materialParamInfo->index);
  723. bool transposeMatrices = ct::RenderAPI::instance().getAPIInfo().isFlagSet(RenderAPIFeatureFlag::ColumnMajorMatrices);
  724. if (transposeMatrices)
  725. {
  726. auto writeTransposed = [&](auto& temp)
  727. {
  728. for (UINT32 i = 0; i < arraySize; i++)
  729. {
  730. UINT32 arrayOffset = i * paramSize;
  731. memcpy(&temp, data + arrayOffset, paramSize);
  732. temp = temp.transpose();
  733. paramBlock->write((paramInfo.offset + arrayOffset) * sizeof(UINT32), &temp, paramSize);
  734. }
  735. };
  736. switch (materialParamInfo->dataType)
  737. {
  738. case GPDT_MATRIX_2X2:
  739. {
  740. MatrixNxM<2, 2> matrix;
  741. writeTransposed(matrix);
  742. }
  743. break;
  744. case GPDT_MATRIX_2X3:
  745. {
  746. MatrixNxM<2, 3> matrix;
  747. writeTransposed(matrix);
  748. }
  749. break;
  750. case GPDT_MATRIX_2X4:
  751. {
  752. MatrixNxM<2, 4> matrix;
  753. writeTransposed(matrix);
  754. }
  755. break;
  756. case GPDT_MATRIX_3X2:
  757. {
  758. MatrixNxM<3, 2> matrix;
  759. writeTransposed(matrix);
  760. }
  761. break;
  762. case GPDT_MATRIX_3X3:
  763. {
  764. Matrix3 matrix;
  765. writeTransposed(matrix);
  766. }
  767. break;
  768. case GPDT_MATRIX_3X4:
  769. {
  770. MatrixNxM<3, 4> matrix;
  771. writeTransposed(matrix);
  772. }
  773. break;
  774. case GPDT_MATRIX_4X2:
  775. {
  776. MatrixNxM<4, 2> matrix;
  777. writeTransposed(matrix);
  778. }
  779. break;
  780. case GPDT_MATRIX_4X3:
  781. {
  782. MatrixNxM<4, 3> matrix;
  783. writeTransposed(matrix);
  784. }
  785. break;
  786. case GPDT_MATRIX_4X4:
  787. {
  788. Matrix4 matrix;
  789. writeTransposed(matrix);
  790. }
  791. break;
  792. default:
  793. {
  794. paramBlock->write(paramInfo.offset * sizeof(UINT32), data, paramSize * arraySize);
  795. break;
  796. }
  797. }
  798. }
  799. else
  800. paramBlock->write(paramInfo.offset * sizeof(UINT32), data, paramSize * arraySize);
  801. }
  802. // Update object params
  803. UINT32 numPasses = (UINT32)mPassParams.size();
  804. for(UINT32 i = 0; i < numPasses; i++)
  805. {
  806. SPtr<GpuParamsType> paramPtr = mPassParams[i];
  807. for(UINT32 j = 0; j < NUM_STAGES; j++)
  808. {
  809. GpuProgramType progType = (GpuProgramType)j;
  810. const StageParamInfo& stageInfo = mPassParamInfos[i].stages[j];
  811. for(UINT32 k = 0; k < stageInfo.numTextures; k++)
  812. {
  813. const ObjectParamInfo& paramInfo = stageInfo.textures[k];
  814. const MaterialParams::ParamData* materialParamInfo = params->getParamData(paramInfo.paramIdx);
  815. if (materialParamInfo->version <= mParamVersion && !updateAll)
  816. continue;
  817. TextureSurface surface;
  818. TextureType texture;
  819. params->getTexture(*materialParamInfo, texture, surface);
  820. paramPtr->setTexture(paramInfo.setIdx, paramInfo.slotIdx, texture, surface);
  821. }
  822. for (UINT32 k = 0; k < stageInfo.numLoadStoreTextures; k++)
  823. {
  824. const ObjectParamInfo& paramInfo = stageInfo.loadStoreTextures[k];
  825. const MaterialParams::ParamData* materialParamInfo = params->getParamData(paramInfo.paramIdx);
  826. if (materialParamInfo->version <= mParamVersion && !updateAll)
  827. continue;
  828. TextureSurface surface;
  829. TextureType texture;
  830. params->getLoadStoreTexture(*materialParamInfo, texture, surface);
  831. paramPtr->setLoadStoreTexture(paramInfo.setIdx, paramInfo.slotIdx, texture, surface);
  832. }
  833. for (UINT32 k = 0; k < stageInfo.numBuffers; k++)
  834. {
  835. const ObjectParamInfo& paramInfo = stageInfo.buffers[k];
  836. const MaterialParams::ParamData* materialParamInfo = params->getParamData(paramInfo.paramIdx);
  837. if (materialParamInfo->version <= mParamVersion && !updateAll)
  838. continue;
  839. BufferType buffer;
  840. params->getBuffer(*materialParamInfo, buffer);
  841. paramPtr->setBuffer(paramInfo.setIdx, paramInfo.slotIdx, buffer);
  842. }
  843. for (UINT32 k = 0; k < stageInfo.numSamplerStates; k++)
  844. {
  845. const ObjectParamInfo& paramInfo = stageInfo.samplerStates[k];
  846. const MaterialParams::ParamData* materialParamInfo = params->getParamData(paramInfo.paramIdx);
  847. if (materialParamInfo->version <= mParamVersion && !updateAll)
  848. continue;
  849. SamplerStateType samplerState;
  850. params->getSamplerState(*materialParamInfo, samplerState);
  851. paramPtr->setSamplerState(paramInfo.setIdx, paramInfo.slotIdx, samplerState);
  852. }
  853. }
  854. paramPtr->_markCoreDirty();
  855. }
  856. mParamVersion = params->getParamVersion();
  857. }
  858. template class TGpuParamsSet <false>;
  859. template class TGpuParamsSet <true>;
  860. }