BsD3D9HLSLParamParser.h 11 KB

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