BsD3D9HLSLParamParser.h 11 KB

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