BsGpuParamsSet.cpp 28 KB

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