BsGpuParamsSet.cpp 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061
  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. if (findIter->second->arraySize != iter->second.arraySize)
  345. {
  346. LOGWRN("Ignoring shader parameter \"" + iter->first + "\". Array size doesn't match the one defined in the gpu program."
  347. + "Shader defined array size: " + toString(iter->second.arraySize) + " - Gpu program defined array size: " + toString(findIter->second->arraySize));
  348. continue;
  349. }
  350. auto findBlockIter = paramToParamBlockMap.find(iter->second.gpuVariableName);
  351. if (findBlockIter == paramToParamBlockMap.end())
  352. BS_EXCEPT(InternalErrorException, "Parameter doesn't exist in param to param block map but exists in valid param map.");
  353. ValidParamKey key(iter->second.gpuVariableName, MaterialParams::ParamType::Data);
  354. validParams.insert(std::make_pair(key, iter->first));
  355. }
  356. // Create object param mappings
  357. auto determineObjectMappings = [&](const Map<String, SHADER_OBJECT_PARAM_DESC>& params, MaterialParams::ParamType paramType)
  358. {
  359. for (auto iter = params.begin(); iter != params.end(); ++iter)
  360. {
  361. const Vector<String>& gpuVariableNames = iter->second.gpuVariableNames;
  362. for (auto iter2 = gpuVariableNames.begin(); iter2 != gpuVariableNames.end(); ++iter2)
  363. {
  364. for (auto iter3 = validObjectParameters.begin(); iter3 != validObjectParameters.end(); ++iter3)
  365. {
  366. if ((*iter3)->name == (*iter2) && (*iter3)->type == iter->second.type)
  367. {
  368. ValidParamKey key(*iter2, paramType);
  369. validParams.insert(std::make_pair(key, iter->first));
  370. break;
  371. }
  372. }
  373. }
  374. }
  375. };
  376. determineObjectMappings(textureParams, MaterialParams::ParamType::Texture);
  377. determineObjectMappings(samplerParams, MaterialParams::ParamType::Sampler);
  378. determineObjectMappings(bufferParams, MaterialParams::ParamType::Buffer);
  379. return validParams;
  380. }
  381. template<bool Core>
  382. const UINT32 TGpuParamsSet<Core>::NUM_STAGES = 6;
  383. template<bool Core>
  384. TGpuParamsSet<Core>::TGpuParamsSet(const SPtr<TechniqueType>& technique, const ShaderType& shader,
  385. const SPtr<MaterialParamsType>& params)
  386. :mPassParams(technique->getNumPasses()), mParamVersion(0)
  387. {
  388. UINT32 numPasses = technique->getNumPasses();
  389. // Create GpuParams for each pass and shader stage
  390. for (UINT32 i = 0; i < numPasses; i++)
  391. {
  392. SPtr<PassType> curPass = technique->getPass(i);
  393. GraphicsPipelineStateType gfxPipeline = curPass->getGraphicsPipelineState();
  394. if(gfxPipeline != nullptr)
  395. mPassParams[i] = GpuParamsType::create(gfxPipeline);
  396. else
  397. {
  398. ComputePipelineStateType computePipeline = curPass->getComputePipelineState();
  399. mPassParams[i] = GpuParamsType::create(computePipeline);
  400. }
  401. }
  402. // Create and assign parameter block buffers
  403. Vector<SPtr<GpuParamDesc>> allParamDescs = getAllParamDescs(technique);
  404. //// Fill out various helper structures
  405. Vector<ShaderBlockDesc> paramBlockData = determineValidShareableParamBlocks(allParamDescs, shader->getParamBlocks());
  406. UnorderedMap<ValidParamKey, String> validParams = determineValidParameters(
  407. allParamDescs,
  408. shader->getDataParams(),
  409. shader->getTextureParams(),
  410. shader->getBufferParams(),
  411. shader->getSamplerParams());
  412. Map<String, ParamBlockPtrType> paramBlockBuffers;
  413. //// Create param blocks
  414. for (auto& paramBlock : paramBlockData)
  415. {
  416. ParamBlockPtrType newParamBlockBuffer;
  417. if (!paramBlock.external)
  418. newParamBlockBuffer = ParamBlockType::create(paramBlock.size, paramBlock.usage);
  419. paramBlock.sequentialIdx = (UINT32)mBlocks.size();
  420. paramBlockBuffers[paramBlock.name] = newParamBlockBuffer;
  421. mBlocks.push_back(BlockInfo(paramBlock.name, paramBlock.set, paramBlock.slot, newParamBlockBuffer, true));
  422. }
  423. //// Assign param block buffers and generate information about data parameters
  424. assert(numPasses < 64); // BlockInfo flags uses UINT64 for tracking usage
  425. for (UINT32 i = 0; i < numPasses; i++)
  426. {
  427. SPtr<GpuParamsType> paramPtr = mPassParams[i];
  428. for (UINT32 j = 0; j < NUM_STAGES; j++)
  429. {
  430. GpuProgramType progType = (GpuProgramType)j;
  431. // Assign shareable buffers
  432. for (auto& block : paramBlockData)
  433. {
  434. const String& paramBlockName = block.name;
  435. if (paramPtr->hasParamBlock(progType, paramBlockName))
  436. {
  437. ParamBlockPtrType blockBuffer = paramBlockBuffers[paramBlockName];
  438. paramPtr->setParamBlockBuffer(progType, paramBlockName, blockBuffer);
  439. }
  440. }
  441. // Create non-shareable ones (these are buffers defined by default by the RHI usually)
  442. SPtr<GpuParamDesc> desc = paramPtr->getParamDesc(progType);
  443. if (desc == nullptr)
  444. continue;
  445. for (auto iterBlockDesc = desc->paramBlocks.begin(); iterBlockDesc != desc->paramBlocks.end(); ++iterBlockDesc)
  446. {
  447. const GpuParamBlockDesc& blockDesc = iterBlockDesc->second;
  448. UINT32 globalBlockIdx = (UINT32)-1;
  449. if (!blockDesc.isShareable)
  450. {
  451. ParamBlockPtrType newParamBlockBuffer = ParamBlockType::create(blockDesc.blockSize * sizeof(UINT32));
  452. globalBlockIdx = (UINT32)mBlocks.size();
  453. paramPtr->setParamBlockBuffer(progType, iterBlockDesc->first, newParamBlockBuffer);
  454. mBlocks.emplace_back(iterBlockDesc->first, iterBlockDesc->second.set,
  455. iterBlockDesc->second.slot, newParamBlockBuffer, false);
  456. }
  457. else
  458. {
  459. auto iterFind = std::find_if(paramBlockData.begin(), paramBlockData.end(), [&](const auto& x)
  460. {
  461. return x.name == iterBlockDesc->first;
  462. });
  463. if(iterFind != paramBlockData.end())
  464. globalBlockIdx = iterFind->sequentialIdx;
  465. }
  466. // If this parameter block is valid, create data/struct mappings for it
  467. if (globalBlockIdx == (UINT32)-1)
  468. continue;
  469. for(auto& dataParam : desc->params)
  470. {
  471. if (dataParam.second.paramBlockSet != blockDesc.set || dataParam.second.paramBlockSlot != blockDesc.slot)
  472. continue;
  473. ValidParamKey key(dataParam.first, MaterialParams::ParamType::Data);
  474. auto iterFind = validParams.find(key);
  475. if (iterFind == validParams.end())
  476. continue;
  477. UINT32 paramIdx = params->getParamIndex(iterFind->second);
  478. // Parameter shouldn't be in the valid parameter list if it cannot be found
  479. assert(paramIdx != -1);
  480. mDataParamInfos.push_back(DataParamInfo());
  481. DataParamInfo& paramInfo = mDataParamInfos.back();
  482. paramInfo.paramIdx = paramIdx;
  483. paramInfo.blockIdx = globalBlockIdx;
  484. paramInfo.offset = dataParam.second.cpuMemOffset;
  485. }
  486. }
  487. }
  488. }
  489. // Add buffers defined in shader but not actually used by GPU programs (so we can check if user is providing a
  490. // valid buffer name)
  491. auto& allParamBlocks = shader->getParamBlocks();
  492. for (auto& entry : allParamBlocks)
  493. {
  494. auto iterFind = std::find_if(mBlocks.begin(), mBlocks.end(),
  495. [&](auto& x)
  496. {
  497. return x.name == entry.first;
  498. });
  499. if(iterFind == mBlocks.end())
  500. {
  501. mBlocks.push_back(BlockInfo(entry.first, 0, 0, nullptr, true));
  502. mBlocks.back().isUsed = false;
  503. }
  504. }
  505. // Generate information about object parameters
  506. bs_frame_mark();
  507. {
  508. FrameVector<ObjectParamInfo> objParamInfos;
  509. UINT32 offsetsSize = numPasses * NUM_STAGES * 4 * sizeof(UINT32);
  510. UINT32* offsets = (UINT32*)bs_frame_alloc(offsetsSize);
  511. memset(offsets, 0, offsetsSize);
  512. // First store all objects in temporary arrays since we don't know how many of them are
  513. UINT32 totalNumObjects = 0;
  514. UINT32* stageOffsets = offsets;
  515. for (UINT32 i = 0; i < numPasses; i++)
  516. {
  517. SPtr<GpuParamsType> paramPtr = mPassParams[i];
  518. for (UINT32 j = 0; j < NUM_STAGES; j++)
  519. {
  520. GpuProgramType progType = (GpuProgramType)j;
  521. auto processObjectParams = [&](const Map<String, GpuParamObjectDesc>& gpuParams,
  522. UINT32 stageIdx, MaterialParams::ParamType paramType)
  523. {
  524. for (auto& param : gpuParams)
  525. {
  526. ValidParamKey key(param.first, paramType);
  527. auto iterFind = validParams.find(key);
  528. if (iterFind == validParams.end())
  529. continue;
  530. UINT32 paramIdx;
  531. auto result = params->getParamIndex(iterFind->second, paramType, GPDT_UNKNOWN, 0, paramIdx);
  532. // Parameter shouldn't be in the valid parameter list if it cannot be found
  533. assert(result == MaterialParams::GetParamResult::Success);
  534. objParamInfos.push_back(ObjectParamInfo());
  535. ObjectParamInfo& paramInfo = objParamInfos.back();
  536. paramInfo.paramIdx = paramIdx;
  537. paramInfo.slotIdx = param.second.slot;
  538. paramInfo.setIdx = param.second.set;
  539. stageOffsets[stageIdx]++;
  540. totalNumObjects++;
  541. }
  542. };
  543. SPtr<GpuParamDesc> desc = paramPtr->getParamDesc(progType);
  544. if(desc == nullptr)
  545. {
  546. stageOffsets += 4;
  547. continue;
  548. }
  549. processObjectParams(desc->textures, 0, MaterialParams::ParamType::Texture);
  550. processObjectParams(desc->loadStoreTextures, 1, MaterialParams::ParamType::Texture);
  551. processObjectParams(desc->buffers, 2, MaterialParams::ParamType::Buffer);
  552. processObjectParams(desc->samplers, 3, MaterialParams::ParamType::Sampler);
  553. stageOffsets += 4;
  554. }
  555. }
  556. // Transfer all objects into their permanent storage
  557. UINT32 numBlocks = (UINT32)mBlocks.size();
  558. UINT32 blockBindingsSize = numBlocks * numPasses * sizeof(PassBlockBindings);
  559. UINT32 objectParamInfosSize = totalNumObjects * sizeof(ObjectParamInfo) + numPasses * sizeof(PassParamInfo);
  560. mData = (UINT8*)bs_alloc(objectParamInfosSize + blockBindingsSize);
  561. UINT8* dataIter = mData;
  562. mPassParamInfos = (PassParamInfo*)dataIter;
  563. memset(mPassParamInfos, 0, objectParamInfosSize);
  564. dataIter += objectParamInfosSize;
  565. StageParamInfo* stageInfos = (StageParamInfo*)mPassParamInfos;
  566. ObjectParamInfo* objInfos = (ObjectParamInfo*)(mPassParamInfos + numPasses);
  567. memcpy(objInfos, objParamInfos.data(), totalNumObjects * sizeof(ObjectParamInfo));
  568. UINT32 objInfoOffset = 0;
  569. stageOffsets = offsets;
  570. for (UINT32 i = 0; i < numPasses; i++)
  571. {
  572. for (UINT32 j = 0; j < NUM_STAGES; j++)
  573. {
  574. StageParamInfo& stage = stageInfos[i * NUM_STAGES + j];
  575. if(stageOffsets[0] > 0)
  576. {
  577. UINT32 numEntries = stageOffsets[0];
  578. stage.textures = objInfos + objInfoOffset;
  579. stage.numTextures = numEntries;
  580. objInfoOffset += numEntries;
  581. }
  582. if (stageOffsets[1] > 0)
  583. {
  584. UINT32 numEntries = stageOffsets[1];
  585. stage.loadStoreTextures = objInfos + objInfoOffset;
  586. stage.numLoadStoreTextures = numEntries;
  587. objInfoOffset += numEntries;
  588. }
  589. if (stageOffsets[2] > 0)
  590. {
  591. UINT32 numEntries = stageOffsets[2];
  592. stage.buffers = objInfos + objInfoOffset;
  593. stage.numBuffers = numEntries;
  594. objInfoOffset += numEntries;
  595. }
  596. if (stageOffsets[3] > 0)
  597. {
  598. UINT32 numEntries = stageOffsets[3];
  599. stage.samplerStates = objInfos + objInfoOffset;
  600. stage.numSamplerStates = numEntries;
  601. objInfoOffset += numEntries;
  602. }
  603. stageOffsets += 4;
  604. }
  605. }
  606. // Determine on which passes & stages are buffers used on
  607. for (auto& block : mBlocks)
  608. {
  609. block.passData = (PassBlockBindings*)dataIter;
  610. dataIter += sizeof(PassBlockBindings) * numPasses;
  611. }
  612. for (auto& block : mBlocks)
  613. {
  614. for (UINT32 i = 0; i < numPasses; i++)
  615. {
  616. SPtr<GpuParamsType> paramPtr = mPassParams[i];
  617. for (UINT32 j = 0; j < NUM_STAGES; j++)
  618. {
  619. GpuProgramType progType = (GpuProgramType)j;
  620. SPtr<GpuParamDesc> curDesc = paramPtr->getParamDesc(progType);
  621. if (curDesc == nullptr)
  622. {
  623. block.passData[i].bindings[j].set = -1;
  624. block.passData[i].bindings[j].slot = -1;
  625. continue;
  626. }
  627. auto iterFind = curDesc->paramBlocks.find(block.name);
  628. if (iterFind == curDesc->paramBlocks.end())
  629. {
  630. block.passData[i].bindings[j].set = -1;
  631. block.passData[i].bindings[j].slot = -1;
  632. continue;
  633. }
  634. block.passData[i].bindings[j].set = iterFind->second.set;
  635. block.passData[i].bindings[j].slot = iterFind->second.slot;
  636. }
  637. }
  638. }
  639. bs_frame_free(offsets);
  640. }
  641. bs_frame_clear();
  642. }
  643. template<bool Core>
  644. TGpuParamsSet<Core>::~TGpuParamsSet()
  645. {
  646. // All allocations share the same memory, so we just clear it all at once
  647. bs_free(mData);
  648. }
  649. template<bool Core>
  650. SPtr<typename TGpuParamsSet<Core>::GpuParamsType> TGpuParamsSet<Core>::getGpuParams(UINT32 passIdx)
  651. {
  652. if (passIdx >= mPassParams.size())
  653. return nullptr;
  654. return mPassParams[passIdx];
  655. }
  656. template<bool Core>
  657. UINT32 TGpuParamsSet<Core>::getParamBlockBufferIndex(const String& name) const
  658. {
  659. for (UINT32 i = 0; i < (UINT32)mBlocks.size(); i++)
  660. {
  661. const BlockInfo& block = mBlocks[i];
  662. if (block.name == name)
  663. return i;
  664. }
  665. return -1;
  666. }
  667. template<bool Core>
  668. void TGpuParamsSet<Core>::setParamBlockBuffer(UINT32 index, const ParamBlockPtrType& paramBlock,
  669. bool ignoreInUpdate)
  670. {
  671. BlockInfo& blockInfo = mBlocks[index];
  672. if (!blockInfo.shareable)
  673. {
  674. LOGERR("Cannot set parameter block buffer with the name \"" + blockInfo.name +
  675. "\". Buffer is not assignable. ");
  676. return;
  677. }
  678. if (!blockInfo.isUsed)
  679. return;
  680. blockInfo.allowUpdate = !ignoreInUpdate;
  681. if (blockInfo.buffer != paramBlock)
  682. {
  683. blockInfo.buffer = paramBlock;
  684. UINT32 numPasses = (UINT32)mPassParams.size();
  685. for (UINT32 j = 0; j < numPasses; j++)
  686. {
  687. SPtr<GpuParamsType> paramPtr = mPassParams[j];
  688. for (UINT32 i = 0; i < NUM_STAGES; i++)
  689. {
  690. GpuProgramType progType = (GpuProgramType)i;
  691. const BlockBinding& binding = blockInfo.passData[j].bindings[progType];
  692. if (binding.slot != -1)
  693. paramPtr->setParamBlockBuffer(binding.set, binding.slot, paramBlock);
  694. }
  695. }
  696. }
  697. }
  698. template<bool Core>
  699. void TGpuParamsSet<Core>::setParamBlockBuffer(const String& name, const ParamBlockPtrType& paramBlock,
  700. bool ignoreInUpdate)
  701. {
  702. UINT32 bufferIdx = getParamBlockBufferIndex(name);
  703. if(bufferIdx == (UINT32)-1)
  704. {
  705. LOGERR("Cannot set parameter block buffer with the name \"" + name + "\". Buffer name not found. ");
  706. return;
  707. }
  708. setParamBlockBuffer(bufferIdx, paramBlock, ignoreInUpdate);
  709. }
  710. template<bool Core>
  711. void TGpuParamsSet<Core>::update(const SPtr<MaterialParamsType>& params, bool updateAll)
  712. {
  713. // Note: Instead of iterating over every single parameter, it might be more efficient for @p params to keep
  714. // a ring buffer and a version number. Then we could just iterate over the ring buffer and only access dirty
  715. // parameters. If the version number is too high (larger than ring buffer can store), then we force update for all.
  716. // Update data params
  717. for(auto& paramInfo : mDataParamInfos)
  718. {
  719. ParamBlockPtrType paramBlock = mBlocks[paramInfo.blockIdx].buffer;
  720. if (paramBlock == nullptr || !mBlocks[paramInfo.blockIdx].allowUpdate)
  721. continue;
  722. const MaterialParams::ParamData* materialParamInfo = params->getParamData(paramInfo.paramIdx);
  723. if (materialParamInfo->version <= mParamVersion && !updateAll)
  724. continue;
  725. UINT32 arraySize = materialParamInfo->arraySize == 0 ? 1 : materialParamInfo->arraySize;
  726. const GpuParamDataTypeInfo& typeInfo = GpuParams::PARAM_SIZES.lookup[(int)materialParamInfo->dataType];
  727. UINT32 paramSize = typeInfo.numColumns * typeInfo.numRows * typeInfo.baseTypeSize;
  728. UINT8* data = params->getData(materialParamInfo->index);
  729. bool transposeMatrices = ct::RenderAPI::instance().getAPIInfo().isFlagSet(RenderAPIFeatureFlag::ColumnMajorMatrices);
  730. if (transposeMatrices)
  731. {
  732. auto writeTransposed = [&](auto& temp)
  733. {
  734. for (UINT32 i = 0; i < arraySize; i++)
  735. {
  736. UINT32 arrayOffset = i * paramSize;
  737. memcpy(&temp, data + arrayOffset, paramSize);
  738. temp = temp.transpose();
  739. paramBlock->write((paramInfo.offset + arrayOffset) * sizeof(UINT32), &temp, paramSize);
  740. }
  741. };
  742. switch (materialParamInfo->dataType)
  743. {
  744. case GPDT_MATRIX_2X2:
  745. {
  746. MatrixNxM<2, 2> matrix;
  747. writeTransposed(matrix);
  748. }
  749. break;
  750. case GPDT_MATRIX_2X3:
  751. {
  752. MatrixNxM<2, 3> matrix;
  753. writeTransposed(matrix);
  754. }
  755. break;
  756. case GPDT_MATRIX_2X4:
  757. {
  758. MatrixNxM<2, 4> matrix;
  759. writeTransposed(matrix);
  760. }
  761. break;
  762. case GPDT_MATRIX_3X2:
  763. {
  764. MatrixNxM<3, 2> matrix;
  765. writeTransposed(matrix);
  766. }
  767. break;
  768. case GPDT_MATRIX_3X3:
  769. {
  770. Matrix3 matrix;
  771. writeTransposed(matrix);
  772. }
  773. break;
  774. case GPDT_MATRIX_3X4:
  775. {
  776. MatrixNxM<3, 4> matrix;
  777. writeTransposed(matrix);
  778. }
  779. break;
  780. case GPDT_MATRIX_4X2:
  781. {
  782. MatrixNxM<4, 2> matrix;
  783. writeTransposed(matrix);
  784. }
  785. break;
  786. case GPDT_MATRIX_4X3:
  787. {
  788. MatrixNxM<4, 3> matrix;
  789. writeTransposed(matrix);
  790. }
  791. break;
  792. case GPDT_MATRIX_4X4:
  793. {
  794. Matrix4 matrix;
  795. writeTransposed(matrix);
  796. }
  797. break;
  798. default:
  799. {
  800. paramBlock->write(paramInfo.offset * sizeof(UINT32), data, paramSize * arraySize);
  801. break;
  802. }
  803. }
  804. }
  805. else
  806. paramBlock->write(paramInfo.offset * sizeof(UINT32), data, paramSize * arraySize);
  807. }
  808. // Update object params
  809. UINT32 numPasses = (UINT32)mPassParams.size();
  810. for(UINT32 i = 0; i < numPasses; i++)
  811. {
  812. SPtr<GpuParamsType> paramPtr = mPassParams[i];
  813. for(UINT32 j = 0; j < NUM_STAGES; j++)
  814. {
  815. GpuProgramType progType = (GpuProgramType)j;
  816. const StageParamInfo& stageInfo = mPassParamInfos[i].stages[j];
  817. for(UINT32 k = 0; k < stageInfo.numTextures; k++)
  818. {
  819. const ObjectParamInfo& paramInfo = stageInfo.textures[k];
  820. const MaterialParams::ParamData* materialParamInfo = params->getParamData(paramInfo.paramIdx);
  821. if (materialParamInfo->version <= mParamVersion && !updateAll)
  822. continue;
  823. TextureSurface surface;
  824. TextureType texture;
  825. params->getTexture(*materialParamInfo, texture, surface);
  826. paramPtr->setTexture(paramInfo.setIdx, paramInfo.slotIdx, texture, surface);
  827. }
  828. for (UINT32 k = 0; k < stageInfo.numLoadStoreTextures; k++)
  829. {
  830. const ObjectParamInfo& paramInfo = stageInfo.loadStoreTextures[k];
  831. const MaterialParams::ParamData* materialParamInfo = params->getParamData(paramInfo.paramIdx);
  832. if (materialParamInfo->version <= mParamVersion && !updateAll)
  833. continue;
  834. TextureSurface surface;
  835. TextureType texture;
  836. params->getLoadStoreTexture(*materialParamInfo, texture, surface);
  837. paramPtr->setLoadStoreTexture(paramInfo.setIdx, paramInfo.slotIdx, texture, surface);
  838. }
  839. for (UINT32 k = 0; k < stageInfo.numBuffers; k++)
  840. {
  841. const ObjectParamInfo& paramInfo = stageInfo.buffers[k];
  842. const MaterialParams::ParamData* materialParamInfo = params->getParamData(paramInfo.paramIdx);
  843. if (materialParamInfo->version <= mParamVersion && !updateAll)
  844. continue;
  845. BufferType buffer;
  846. params->getBuffer(*materialParamInfo, buffer);
  847. paramPtr->setBuffer(paramInfo.setIdx, paramInfo.slotIdx, buffer);
  848. }
  849. for (UINT32 k = 0; k < stageInfo.numSamplerStates; k++)
  850. {
  851. const ObjectParamInfo& paramInfo = stageInfo.samplerStates[k];
  852. const MaterialParams::ParamData* materialParamInfo = params->getParamData(paramInfo.paramIdx);
  853. if (materialParamInfo->version <= mParamVersion && !updateAll)
  854. continue;
  855. SamplerStateType samplerState;
  856. params->getSamplerState(*materialParamInfo, samplerState);
  857. paramPtr->setSamplerState(paramInfo.setIdx, paramInfo.slotIdx, samplerState);
  858. }
  859. }
  860. paramPtr->_markCoreDirty();
  861. }
  862. mParamVersion = params->getParamVersion();
  863. }
  864. template class TGpuParamsSet <false>;
  865. template class TGpuParamsSet <true>;
  866. }