BsD3D9GpuProgram.cpp 11 KB

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