BsD3D9GpuProgram.cpp 11 KB

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