BsD3D9GpuProgram.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. #include "BsD3D9GpuProgram.h"
  2. #include "BsMatrix4.h"
  3. #include "BsException.h"
  4. #include "BsD3D9Mappings.h"
  5. #include "BsD3D9RenderSystem.h"
  6. #include "BsD3D9ResourceManager.h"
  7. #include "BsGpuParams.h"
  8. #include "BsAsyncOp.h"
  9. #include "BsGpuProgramManager.h"
  10. #include "BsD3D9HLSLParamParser.h"
  11. #include "BsD3D9GpuProgramRTTI.h"
  12. #include "BsRenderStats.h"
  13. namespace BansheeEngine
  14. {
  15. D3D9GpuProgram::D3D9GpuProgram(const String& source, const String& entryPoint,
  16. GpuProgramType gptype, GpuProgramProfile profile, const Vector<HGpuProgInclude>* includes)
  17. : GpuProgram(source, entryPoint, gptype, profile, includes, false),
  18. mMicrocode(nullptr), mColumnMajorMatrices(false), mOptimisationLevel(OPT_DEFAULT)
  19. { }
  20. D3D9GpuProgram::~D3D9GpuProgram()
  21. { }
  22. void D3D9GpuProgram::initialize_internal()
  23. {
  24. if (!isSupported())
  25. {
  26. mIsCompiled = false;
  27. mCompileError = "Specified program is not supported by the current render system.";
  28. GpuProgram::initialize_internal();
  29. return;
  30. }
  31. // Populate preprocessor defines
  32. String stringBuffer;
  33. Vector<D3DXMACRO> defines;
  34. const D3DXMACRO* pDefines = 0;
  35. if (!mPreprocessorDefines.empty())
  36. {
  37. stringBuffer = mPreprocessorDefines;
  38. // Split preprocessor defines and build up macro array
  39. D3DXMACRO macro;
  40. String::size_type pos = 0;
  41. while (pos != String::npos)
  42. {
  43. macro.Name = &stringBuffer[pos];
  44. macro.Definition = 0;
  45. String::size_type start_pos = pos;
  46. // Find delims
  47. pos = stringBuffer.find_first_of(";,=", pos);
  48. if (start_pos == pos)
  49. {
  50. if (pos == stringBuffer.length())
  51. {
  52. break;
  53. }
  54. pos++;
  55. continue;
  56. }
  57. if (pos != String::npos)
  58. {
  59. // Check definition part
  60. if (stringBuffer[pos] == '=')
  61. {
  62. // Setup null character for macro name
  63. stringBuffer[pos++] = '\0';
  64. macro.Definition = &stringBuffer[pos];
  65. pos = stringBuffer.find_first_of(";,", pos);
  66. }
  67. else
  68. {
  69. // No definition part, define as "1"
  70. macro.Definition = "1";
  71. }
  72. if (pos != String::npos)
  73. {
  74. // Setup null character for macro name or definition
  75. stringBuffer[pos++] = '\0';
  76. }
  77. }
  78. else
  79. {
  80. macro.Definition = "1";
  81. }
  82. if (strlen(macro.Name) > 0)
  83. {
  84. defines.push_back(macro);
  85. }
  86. else
  87. {
  88. break;
  89. }
  90. }
  91. // Add NULL terminator
  92. macro.Name = 0;
  93. macro.Definition = 0;
  94. defines.push_back(macro);
  95. pDefines = &defines[0];
  96. }
  97. // Populate compile flags
  98. DWORD compileFlags = 0;
  99. if (mColumnMajorMatrices)
  100. compileFlags |= D3DXSHADER_PACKMATRIX_COLUMNMAJOR;
  101. else
  102. compileFlags |= D3DXSHADER_PACKMATRIX_ROWMAJOR;
  103. #if BS_DEBUG_MODE
  104. compileFlags |= D3DXSHADER_DEBUG;
  105. #endif
  106. switch (mOptimisationLevel)
  107. {
  108. case OPT_DEFAULT:
  109. compileFlags |= D3DXSHADER_OPTIMIZATION_LEVEL1;
  110. break;
  111. case OPT_NONE:
  112. compileFlags |= D3DXSHADER_SKIPOPTIMIZATION;
  113. break;
  114. case OPT_0:
  115. compileFlags |= D3DXSHADER_OPTIMIZATION_LEVEL0;
  116. break;
  117. case OPT_1:
  118. compileFlags |= D3DXSHADER_OPTIMIZATION_LEVEL1;
  119. break;
  120. case OPT_2:
  121. compileFlags |= D3DXSHADER_OPTIMIZATION_LEVEL2;
  122. break;
  123. case OPT_3:
  124. compileFlags |= D3DXSHADER_OPTIMIZATION_LEVEL3;
  125. break;
  126. }
  127. LPD3DXBUFFER errors = 0;
  128. // include handler
  129. LPD3DXCONSTANTTABLE constTable;
  130. String hlslProfile = D3D9RenderSystem::instance().getCapabilities()->gpuProgProfileToRSSpecificProfile(mProfile);
  131. String parsedSource = D3D9EmulatedParamBlockParser::parse(mSource, mBlocks);
  132. // Compile & assemble into microcode
  133. HRESULT hr = D3DXCompileShader(
  134. parsedSource.c_str(),
  135. static_cast<UINT>(parsedSource.length()),
  136. pDefines,
  137. nullptr,
  138. mEntryPoint.c_str(),
  139. hlslProfile.c_str(),
  140. compileFlags,
  141. &mMicrocode,
  142. &errors,
  143. &constTable);
  144. if (FAILED(hr))
  145. {
  146. String message = "Cannot compile D3D9 high-level shader ";
  147. if (errors)
  148. {
  149. message += String(" Errors:\n") + static_cast<const char*>(errors->GetBufferPointer());
  150. errors->Release();
  151. }
  152. mIsCompiled = false;
  153. mCompileError = message;
  154. SAFE_RELEASE(mMicrocode);
  155. mMicrocode = nullptr;
  156. }
  157. else
  158. {
  159. for (UINT32 i = 0; i < D3D9RenderSystem::getResourceCreationDeviceCount(); ++i)
  160. {
  161. IDirect3DDevice9* d3d9Device = D3D9RenderSystem::getResourceCreationDevice(i);
  162. loadFromMicrocode(d3d9Device, mMicrocode);
  163. }
  164. D3D9HLSLParamParser paramParser(constTable, mBlocks);
  165. mParametersDesc = paramParser.buildParameterDescriptions();
  166. mIsCompiled = true;
  167. mCompileError = "";
  168. SAFE_RELEASE(constTable);
  169. }
  170. BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_GpuProgram);
  171. GpuProgram::initialize_internal();
  172. }
  173. void D3D9GpuProgram::destroy_internal()
  174. {
  175. SAFE_RELEASE(mMicrocode);
  176. BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_GpuProgram);
  177. GpuProgram::destroy_internal();
  178. }
  179. GpuParamsPtr D3D9GpuProgram::createParameters()
  180. {
  181. GpuParamsPtr params = bs_shared_ptr<GpuParams, PoolAlloc>(std::ref(mParametersDesc), mColumnMajorMatrices);
  182. return params;
  183. }
  184. const String& D3D9GpuProgram::getLanguage() const
  185. {
  186. static const String language = "hlsl";
  187. return language;
  188. }
  189. /************************************************************************/
  190. /* SERIALIZATION */
  191. /************************************************************************/
  192. RTTITypeBase* D3D9GpuProgram::getRTTIStatic()
  193. {
  194. return D3D9GpuProgramRTTI::instance();
  195. }
  196. RTTITypeBase* D3D9GpuProgram::getRTTI() const
  197. {
  198. return D3D9GpuProgram::getRTTIStatic();
  199. }
  200. D3D9GpuVertexProgram::D3D9GpuVertexProgram(const String& source, const String& entryPoint,
  201. GpuProgramProfile profile, const Vector<HGpuProgInclude>* includes)
  202. : D3D9GpuProgram(source, entryPoint, GPT_VERTEX_PROGRAM, profile, includes)
  203. {
  204. }
  205. D3D9GpuVertexProgram::~D3D9GpuVertexProgram()
  206. {
  207. }
  208. void D3D9GpuVertexProgram::destroy_internal(void)
  209. {
  210. auto it = mMapDeviceToVertexShader.begin();
  211. while (it != mMapDeviceToVertexShader.end())
  212. {
  213. SAFE_RELEASE(it->second);
  214. ++it;
  215. }
  216. mMapDeviceToVertexShader.clear();
  217. D3D9GpuProgram::destroy_internal();
  218. }
  219. void D3D9GpuVertexProgram::loadFromMicrocode(IDirect3DDevice9* d3d9Device, ID3DXBuffer* microcode)
  220. {
  221. auto it = mMapDeviceToVertexShader.find(d3d9Device);
  222. if (it != mMapDeviceToVertexShader.end())
  223. SAFE_RELEASE(it->second);
  224. // Create the shader
  225. IDirect3DVertexShader9* pVertexShader;
  226. HRESULT hr;
  227. hr = d3d9Device->CreateVertexShader(
  228. static_cast<DWORD*>(microcode->GetBufferPointer()),
  229. &pVertexShader);
  230. if (FAILED(hr))
  231. {
  232. BS_EXCEPT(RenderingAPIException, "Cannot create D3D9 vertex shader from microcode");
  233. }
  234. mMapDeviceToVertexShader[d3d9Device] = pVertexShader;
  235. }
  236. void D3D9GpuVertexProgram::notifyOnDeviceCreate(IDirect3DDevice9* d3d9Device)
  237. {
  238. }
  239. void D3D9GpuVertexProgram::notifyOnDeviceDestroy(IDirect3DDevice9* d3d9Device)
  240. {
  241. auto it = mMapDeviceToVertexShader.find(d3d9Device);
  242. // Case shader found -> release it and erase from map.
  243. if (it != mMapDeviceToVertexShader.end())
  244. {
  245. SAFE_RELEASE(it->second);
  246. mMapDeviceToVertexShader.erase(it);
  247. }
  248. }
  249. IDirect3DVertexShader9* D3D9GpuVertexProgram::getVertexShader()
  250. {
  251. if (!isCompiled())
  252. return nullptr;
  253. IDirect3DDevice9* d3d9Device = D3D9RenderSystem::getActiveD3D9Device();
  254. auto it = mMapDeviceToVertexShader.find(d3d9Device);
  255. // Shader was not found -> load it.
  256. if (it == mMapDeviceToVertexShader.end())
  257. {
  258. loadFromMicrocode(d3d9Device, mMicrocode);
  259. it = mMapDeviceToVertexShader.find(d3d9Device);
  260. }
  261. return it->second;
  262. }
  263. /************************************************************************/
  264. /* SERIALIZATION */
  265. /************************************************************************/
  266. RTTITypeBase* D3D9GpuVertexProgram::getRTTIStatic()
  267. {
  268. return D3D9GpuVertexProgramRTTI::instance();
  269. }
  270. RTTITypeBase* D3D9GpuVertexProgram::getRTTI() const
  271. {
  272. return D3D9GpuVertexProgram::getRTTIStatic();
  273. }
  274. D3D9GpuFragmentProgram::D3D9GpuFragmentProgram(const String& source, const String& entryPoint,
  275. GpuProgramProfile profile, const Vector<HGpuProgInclude>* includes)
  276. : D3D9GpuProgram(source, entryPoint, GPT_FRAGMENT_PROGRAM, profile, includes)
  277. {
  278. }
  279. D3D9GpuFragmentProgram::~D3D9GpuFragmentProgram()
  280. {
  281. }
  282. void D3D9GpuFragmentProgram::destroy_internal()
  283. {
  284. auto it = mMapDeviceToPixelShader.begin();
  285. while (it != mMapDeviceToPixelShader.end())
  286. {
  287. SAFE_RELEASE(it->second);
  288. ++it;
  289. }
  290. mMapDeviceToPixelShader.clear();
  291. D3D9GpuProgram::destroy_internal();
  292. }
  293. void D3D9GpuFragmentProgram::loadFromMicrocode(IDirect3DDevice9* d3d9Device, ID3DXBuffer* microcode)
  294. {
  295. auto it = mMapDeviceToPixelShader.find(d3d9Device);
  296. if (it != mMapDeviceToPixelShader.end())
  297. SAFE_RELEASE(it->second);
  298. // Create the shader
  299. IDirect3DPixelShader9* pPixelShader;
  300. HRESULT hr;
  301. hr = d3d9Device->CreatePixelShader(static_cast<DWORD*>(microcode->GetBufferPointer()), &pPixelShader);
  302. if (FAILED(hr))
  303. BS_EXCEPT(RenderingAPIException, "Cannot create D3D9 pixel shader from microcode.");
  304. mMapDeviceToPixelShader[d3d9Device] = pPixelShader;
  305. }
  306. void D3D9GpuFragmentProgram::notifyOnDeviceCreate(IDirect3DDevice9* d3d9Device)
  307. {
  308. }
  309. void D3D9GpuFragmentProgram::notifyOnDeviceDestroy(IDirect3DDevice9* d3d9Device)
  310. {
  311. auto it = mMapDeviceToPixelShader.find(d3d9Device);
  312. // Case shader found -> release it and erase from map.
  313. if (it != mMapDeviceToPixelShader.end())
  314. {
  315. SAFE_RELEASE(it->second);
  316. mMapDeviceToPixelShader.erase(it);
  317. }
  318. }
  319. IDirect3DPixelShader9* D3D9GpuFragmentProgram::getPixelShader()
  320. {
  321. if (!isCompiled())
  322. return nullptr;
  323. IDirect3DDevice9* d3d9Device = D3D9RenderSystem::getActiveD3D9Device();
  324. auto it = mMapDeviceToPixelShader.find(d3d9Device);
  325. // Shader was not found -> load it.
  326. if (it == mMapDeviceToPixelShader.end())
  327. {
  328. loadFromMicrocode(d3d9Device, mMicrocode);
  329. it = mMapDeviceToPixelShader.find(d3d9Device);
  330. }
  331. return it->second;
  332. }
  333. /************************************************************************/
  334. /* SERIALIZATION */
  335. /************************************************************************/
  336. RTTITypeBase* D3D9GpuFragmentProgram::getRTTIStatic()
  337. {
  338. return D3D9GpuFragmentProgramRTTI::instance();
  339. }
  340. RTTITypeBase* D3D9GpuFragmentProgram::getRTTI() const
  341. {
  342. return D3D9GpuFragmentProgram::getRTTIStatic();
  343. }
  344. }