BsD3D9HLSLParamParser.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. #pragma once
  2. #include "BsD3D9Prerequisites.h"
  3. #include "BsD3D9GpuProgram.h"
  4. namespace BansheeEngine
  5. {
  6. /**
  7. * @brief Helper class that parses GPU program constant table and returns parameters used
  8. * by the program, as well as their type, size and other information.
  9. */
  10. class D3D9HLSLParamParser
  11. {
  12. public:
  13. /**
  14. * @brief Initializes the parameter parser with the specified constant table, and an optional list
  15. * of parameter blocks. DirectX 9 does not support parameter blocks internally, but
  16. * we can emulate the functionality by providing a list of user-defined blocks and
  17. * the parameters they contain.
  18. */
  19. D3D9HLSLParamParser(LPD3DXCONSTANTTABLE constTable, const Vector<D3D9EmulatedParamBlock>& blocks)
  20. :mpConstTable(constTable), mBlocks(blocks)
  21. { }
  22. /**
  23. * @brief Builds parameter descriptions and returns an object containing all relevant information.
  24. */
  25. GpuParamDescPtr buildParameterDescriptions();
  26. private:
  27. /**
  28. * @brief Determines information about the specified parameter and places it in the provided
  29. * parameter block, as well as any children of the parameter.
  30. *
  31. * @param blockDesc Parent block into which to add the new parameter.
  32. * @param paramName Name of the parameter.
  33. * @param constant Parameter handle in the constant table.
  34. * @param prefix Prefix to append to the parameter and any child parameters.
  35. */
  36. void processParameter(GpuParamBlockDesc& blockDesc, const String& paramName, D3DXHANDLE constant, String prefix);
  37. /**
  38. * @brief Populates information about the parameter in "memberDesc" from the data in d3dDesc. Esentially converts
  39. * DX9 parameter data to engine data.
  40. */
  41. void populateParamMemberDesc(GpuParamDataDesc& memberDesc, D3DXCONSTANT_DESC& d3dDesc);
  42. /**
  43. * @brief Returns the name of the parameter with the specified constant table handle.
  44. */
  45. String getParamName(D3DXHANDLE constant);
  46. private:
  47. LPD3DXCONSTANTTABLE mpConstTable;
  48. Vector<D3D9EmulatedParamBlock> mBlocks;
  49. GpuParamDescPtr mParamDesc;
  50. };
  51. String D3D9HLSLParamParser::getParamName(D3DXHANDLE constant)
  52. {
  53. D3DXCONSTANT_DESC desc;
  54. UINT32 numParams = 1;
  55. HRESULT hr = mpConstTable->GetConstantDesc(constant, &desc, &numParams);
  56. if (FAILED(hr))
  57. {
  58. BS_EXCEPT(InternalErrorException, "Cannot retrieve constant description from HLSL program.");
  59. }
  60. String paramName = desc.Name;
  61. // trim the odd '$' which appears at the start of the names in HLSL
  62. if (paramName.at(0) == '$')
  63. paramName.erase(paramName.begin());
  64. // Also trim the '[0]' suffix if it exists, we will add our own indexing later
  65. if (StringUtil::endsWith(paramName, "[0]", false))
  66. paramName.erase(paramName.size() - 3);
  67. return paramName;
  68. }
  69. GpuParamDescPtr D3D9HLSLParamParser::buildParameterDescriptions()
  70. {
  71. // Derive parameter names from const table
  72. assert(mpConstTable && "Program not loaded!");
  73. mParamDesc = bs_shared_ptr_new<GpuParamDesc>();
  74. // Get contents of the constant table
  75. D3DXCONSTANTTABLE_DESC desc;
  76. HRESULT hr = mpConstTable->GetDesc(&desc);
  77. if (FAILED(hr))
  78. BS_EXCEPT(InternalErrorException, "Cannot retrieve constant descriptions from HLSL program.");
  79. // DX9 has no concept of parameter blocks so we emulate them if needed
  80. String name = "BS_INTERNAL_Globals";
  81. mParamDesc->paramBlocks.insert(std::make_pair(name, GpuParamBlockDesc()));
  82. GpuParamBlockDesc& globalBlockDesc = mParamDesc->paramBlocks[name];
  83. globalBlockDesc.name = name;
  84. globalBlockDesc.slot = 0;
  85. globalBlockDesc.blockSize = 0;
  86. globalBlockDesc.isShareable = false;
  87. UnorderedMap<String, String> nonGlobalBlocks;
  88. UINT32 curSlot = 1;
  89. for (auto& block : mBlocks)
  90. {
  91. mParamDesc->paramBlocks.insert(std::make_pair(block.blockName, GpuParamBlockDesc()));
  92. GpuParamBlockDesc& blockDesc = mParamDesc->paramBlocks[block.blockName];
  93. blockDesc.name = block.blockName;
  94. blockDesc.slot = curSlot++;
  95. blockDesc.blockSize = 0;
  96. blockDesc.isShareable = true;
  97. for (auto& fieldName : block.paramNames)
  98. {
  99. nonGlobalBlocks.insert(std::make_pair(fieldName, block.blockName));
  100. }
  101. }
  102. // Iterate over the constants
  103. for (UINT32 i = 0; i < desc.Constants; ++i)
  104. {
  105. D3DXHANDLE constantHandle = mpConstTable->GetConstant(NULL, i);
  106. String paramName = getParamName(constantHandle);
  107. // Recursively descend through the structure levels
  108. auto findIter = nonGlobalBlocks.find(paramName);
  109. if (findIter == nonGlobalBlocks.end())
  110. processParameter(globalBlockDesc, paramName, constantHandle, "");
  111. else
  112. processParameter(mParamDesc->paramBlocks[findIter->second], paramName, constantHandle, "");
  113. }
  114. return mParamDesc;
  115. }
  116. void D3D9HLSLParamParser::processParameter(GpuParamBlockDesc& blockDesc, const String& paramName, D3DXHANDLE constant, String prefix)
  117. {
  118. // Since D3D HLSL doesn't deal with naming of array and struct parameters
  119. // automatically, we have to do it by hand
  120. D3DXCONSTANT_DESC desc;
  121. UINT32 numParams = 1;
  122. HRESULT hr = mpConstTable->GetConstantDesc(constant, &desc, &numParams);
  123. if (FAILED(hr))
  124. {
  125. BS_EXCEPT(InternalErrorException, "Cannot retrieve constant description from HLSL program.");
  126. }
  127. if (desc.Class == D3DXPC_STRUCT)
  128. {
  129. // work out a new prefix for nested members, if it's an array, we need an index
  130. prefix = prefix + paramName + ".";
  131. // Cascade into struct
  132. for (UINT32 i = 0; i < desc.StructMembers; ++i)
  133. {
  134. D3DXHANDLE childHandle = mpConstTable->GetConstant(constant, i);
  135. String childParamName = getParamName(childHandle);
  136. processParameter(blockDesc, childParamName, childHandle, prefix);
  137. }
  138. }
  139. else
  140. {
  141. // Process params
  142. if (desc.Type == D3DXPT_FLOAT || desc.Type == D3DXPT_INT || desc.Type == D3DXPT_BOOL)
  143. {
  144. GpuParamDataDesc memberDesc;
  145. memberDesc.gpuMemOffset = desc.RegisterIndex;
  146. memberDesc.cpuMemOffset = blockDesc.blockSize;
  147. memberDesc.paramBlockSlot = blockDesc.slot;
  148. memberDesc.arraySize = 1;
  149. String name = prefix + paramName;
  150. memberDesc.name = name;
  151. populateParamMemberDesc(memberDesc, desc);
  152. mParamDesc->params.insert(std::make_pair(name, memberDesc));
  153. blockDesc.blockSize += memberDesc.arrayElementStride * memberDesc.arraySize;
  154. }
  155. else if(desc.Type == D3DXPT_SAMPLER1D || desc.Type == D3DXPT_SAMPLER2D || desc.Type == D3DXPT_SAMPLER3D || desc.Type == D3DXPT_SAMPLERCUBE)
  156. {
  157. GpuParamObjectDesc samplerDesc;
  158. samplerDesc.name = paramName;
  159. samplerDesc.slot = desc.RegisterIndex;
  160. GpuParamObjectDesc textureDesc;
  161. textureDesc.name = paramName;
  162. textureDesc.slot = desc.RegisterIndex;
  163. switch(desc.Type)
  164. {
  165. case D3DXPT_SAMPLER1D:
  166. samplerDesc.type = GPOT_SAMPLER1D;
  167. textureDesc.type = GPOT_TEXTURE1D;
  168. break;
  169. case D3DXPT_SAMPLER2D:
  170. samplerDesc.type = GPOT_SAMPLER2D;
  171. textureDesc.type = GPOT_TEXTURE2D;
  172. break;
  173. case D3DXPT_SAMPLER3D:
  174. samplerDesc.type = GPOT_SAMPLER3D;
  175. textureDesc.type = GPOT_TEXTURE3D;
  176. break;
  177. case D3DXPT_SAMPLERCUBE:
  178. samplerDesc.type = GPOT_SAMPLERCUBE;
  179. textureDesc.type = GPOT_TEXTURECUBE;
  180. break;
  181. default:
  182. BS_EXCEPT(InternalErrorException, "Invalid sampler type: " + toString(desc.Type) + " for parameter " + paramName);
  183. }
  184. mParamDesc->samplers.insert(std::make_pair(paramName, samplerDesc));
  185. mParamDesc->textures.insert(std::make_pair(paramName, textureDesc));
  186. }
  187. else
  188. {
  189. BS_EXCEPT(InternalErrorException, "Invalid shader parameter type: " + toString(desc.Type) + " for parameter " + paramName);
  190. }
  191. }
  192. }
  193. void D3D9HLSLParamParser::populateParamMemberDesc(GpuParamDataDesc& memberDesc, D3DXCONSTANT_DESC& d3dDesc)
  194. {
  195. memberDesc.arraySize = d3dDesc.Elements;
  196. switch(d3dDesc.Type)
  197. {
  198. case D3DXPT_INT:
  199. switch(d3dDesc.Columns)
  200. {
  201. case 1:
  202. memberDesc.type = GPDT_INT1;
  203. memberDesc.elementSize = 4;
  204. memberDesc.arrayElementStride = 4;
  205. break;
  206. case 2:
  207. memberDesc.type = GPDT_INT2;
  208. memberDesc.elementSize = 4;
  209. memberDesc.arrayElementStride = 4;
  210. break;
  211. case 3:
  212. memberDesc.type = GPDT_INT3;
  213. memberDesc.elementSize = 4;
  214. memberDesc.arrayElementStride = 4;
  215. break;
  216. case 4:
  217. memberDesc.type = GPDT_INT4;
  218. memberDesc.elementSize = 4;
  219. memberDesc.arrayElementStride = 4;
  220. break;
  221. } // columns
  222. break;
  223. case D3DXPT_FLOAT:
  224. switch(d3dDesc.Class)
  225. {
  226. case D3DXPC_MATRIX_COLUMNS:
  227. case D3DXPC_MATRIX_ROWS:
  228. {
  229. int firstDim, secondDim;
  230. int firstActualDim; // Actual size might be less than requested because of optimization, we need to know both
  231. firstActualDim = d3dDesc.RegisterCount / d3dDesc.Elements;
  232. if (d3dDesc.Class == D3DXPC_MATRIX_ROWS)
  233. {
  234. firstDim = d3dDesc.Rows;
  235. secondDim = d3dDesc.Columns;
  236. }
  237. else
  238. {
  239. firstDim = d3dDesc.Columns;
  240. secondDim = d3dDesc.Rows;
  241. }
  242. switch (firstActualDim)
  243. {
  244. case 2:
  245. switch(secondDim)
  246. {
  247. case 2:
  248. memberDesc.elementSize = 8; // HLSL always packs
  249. memberDesc.arrayElementStride = 8;
  250. break;
  251. case 3:
  252. memberDesc.elementSize = 8; // HLSL always packs
  253. memberDesc.arrayElementStride = 8;
  254. break;
  255. case 4:
  256. memberDesc.elementSize = 8;
  257. memberDesc.arrayElementStride = 8;
  258. break;
  259. }
  260. break;
  261. case 3:
  262. switch(secondDim)
  263. {
  264. case 2:
  265. memberDesc.elementSize = 12; // HLSL always packs
  266. memberDesc.arrayElementStride = 12;
  267. break;
  268. case 3:
  269. memberDesc.elementSize = 12; // HLSL always packs
  270. memberDesc.arrayElementStride = 12;
  271. break;
  272. case 4:
  273. memberDesc.elementSize = 12;
  274. memberDesc.arrayElementStride = 12;
  275. break;
  276. }
  277. break;
  278. case 4:
  279. switch(secondDim)
  280. {
  281. case 2:
  282. memberDesc.elementSize = 16; // HLSL always packs
  283. memberDesc.arrayElementStride = 16;
  284. break;
  285. case 3:
  286. memberDesc.elementSize = 16; // HLSL always packs
  287. memberDesc.arrayElementStride = 16;
  288. break;
  289. case 4:
  290. memberDesc.elementSize = 16;
  291. memberDesc.arrayElementStride = 16;
  292. break;
  293. }
  294. break;
  295. }
  296. switch (firstDim)
  297. {
  298. case 2:
  299. switch (secondDim)
  300. {
  301. case 2:
  302. memberDesc.type = GPDT_MATRIX_2X2;
  303. break;
  304. case 3:
  305. memberDesc.type = GPDT_MATRIX_2X3;
  306. break;
  307. case 4:
  308. memberDesc.type = GPDT_MATRIX_2X4;
  309. break;
  310. }
  311. break;
  312. case 3:
  313. switch (secondDim)
  314. {
  315. case 2:
  316. memberDesc.type = GPDT_MATRIX_3X2;
  317. break;
  318. case 3:
  319. memberDesc.type = GPDT_MATRIX_3X3;
  320. break;
  321. case 4:
  322. memberDesc.type = GPDT_MATRIX_3X4;
  323. break;
  324. }
  325. break;
  326. case 4:
  327. switch (secondDim)
  328. {
  329. case 2:
  330. memberDesc.type = GPDT_MATRIX_4X2;
  331. break;
  332. case 3:
  333. memberDesc.type = GPDT_MATRIX_4X3;
  334. break;
  335. case 4:
  336. memberDesc.type = GPDT_MATRIX_4X4;
  337. break;
  338. }
  339. break;
  340. }
  341. }
  342. break;
  343. case D3DXPC_SCALAR:
  344. case D3DXPC_VECTOR:
  345. switch(d3dDesc.Columns)
  346. {
  347. case 1:
  348. memberDesc.type = GPDT_FLOAT1;
  349. memberDesc.elementSize = 4;
  350. memberDesc.arrayElementStride = 4;
  351. break;
  352. case 2:
  353. memberDesc.type = GPDT_FLOAT2;
  354. memberDesc.elementSize = 4;
  355. memberDesc.arrayElementStride = 4;
  356. break;
  357. case 3:
  358. memberDesc.type = GPDT_FLOAT3;
  359. memberDesc.elementSize = 4;
  360. memberDesc.arrayElementStride = 4;
  361. break;
  362. case 4:
  363. memberDesc.type = GPDT_FLOAT4;
  364. memberDesc.elementSize = 4;
  365. memberDesc.arrayElementStride = 4;
  366. break;
  367. } // columns
  368. break;
  369. }
  370. break;
  371. case D3DXPT_BOOL:
  372. memberDesc.type = GPDT_BOOL;
  373. memberDesc.elementSize = 1;
  374. memberDesc.arrayElementStride = 1;
  375. break;
  376. default:
  377. break;
  378. };
  379. }
  380. }