2
0

BsGpuParamsSet.cpp 30 KB

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