BsGpuParamsSet.cpp 30 KB

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