BsD3D9GpuProgram.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. #include "BsD3D9GpuProgram.h"
  2. #include "BsMatrix4.h"
  3. #include "BsException.h"
  4. #include "BsD3D9Mappings.h"
  5. #include "BsD3D9RenderAPI.h"
  6. #include "BsD3D9ResourceManager.h"
  7. #include "BsGpuParams.h"
  8. #include "BsAsyncOp.h"
  9. #include "BsGpuProgramManager.h"
  10. #include "BsD3D9HLSLParamParser.h"
  11. #include "BsRenderStats.h"
  12. namespace BansheeEngine
  13. {
  14. D3D9GpuProgramCore::D3D9GpuProgramCore(const String& source, const String& entryPoint,
  15. GpuProgramType gptype, GpuProgramProfile profile)
  16. : GpuProgramCore(source, entryPoint, gptype, profile, false),
  17. mMicrocode(nullptr), mOptimisationLevel(OPT_DEFAULT)
  18. { }
  19. D3D9GpuProgramCore::~D3D9GpuProgramCore()
  20. {
  21. SAFE_RELEASE(mMicrocode);
  22. BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_GpuProgram);
  23. }
  24. void D3D9GpuProgramCore::initialize()
  25. {
  26. if (!isSupported())
  27. {
  28. mIsCompiled = false;
  29. mCompileError = "Specified program is not supported by the current render system.";
  30. GpuProgramCore::initialize();
  31. return;
  32. }
  33. // Populate preprocessor defines
  34. String stringBuffer;
  35. Vector<D3DXMACRO> defines;
  36. const D3DXMACRO* pDefines = 0;
  37. if (!mPreprocessorDefines.empty())
  38. {
  39. stringBuffer = mPreprocessorDefines;
  40. // Split preprocessor defines and build up macro array
  41. D3DXMACRO macro;
  42. String::size_type pos = 0;
  43. while (pos != String::npos)
  44. {
  45. macro.Name = &stringBuffer[pos];
  46. macro.Definition = 0;
  47. String::size_type start_pos = pos;
  48. // Find delims
  49. pos = stringBuffer.find_first_of(";,=", pos);
  50. if (start_pos == pos)
  51. {
  52. if (pos == stringBuffer.length())
  53. {
  54. break;
  55. }
  56. pos++;
  57. continue;
  58. }
  59. if (pos != String::npos)
  60. {
  61. // Check definition part
  62. if (stringBuffer[pos] == '=')
  63. {
  64. // Setup null character for macro name
  65. stringBuffer[pos++] = '\0';
  66. macro.Definition = &stringBuffer[pos];
  67. pos = stringBuffer.find_first_of(";,", pos);
  68. }
  69. else
  70. {
  71. // No definition part, define as "1"
  72. macro.Definition = "1";
  73. }
  74. if (pos != String::npos)
  75. {
  76. // Setup null character for macro name or definition
  77. stringBuffer[pos++] = '\0';
  78. }
  79. }
  80. else
  81. {
  82. macro.Definition = "1";
  83. }
  84. if (strlen(macro.Name) > 0)
  85. {
  86. defines.push_back(macro);
  87. }
  88. else
  89. {
  90. break;
  91. }
  92. }
  93. // Add NULL terminator
  94. macro.Name = 0;
  95. macro.Definition = 0;
  96. defines.push_back(macro);
  97. pDefines = &defines[0];
  98. }
  99. // Populate compile flags
  100. DWORD compileFlags = 0;
  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 = D3D9RenderAPI::instance().getCapabilities()->gpuProgProfileToRSSpecificProfile(getProperties().getProfile());
  130. String parsedSource = D3D9EmulatedParamBlockParser::parse(getProperties().getSource(), mBlocks);
  131. // Compile & assemble into microcode
  132. HRESULT hr = D3DXCompileShader(
  133. parsedSource.c_str(),
  134. static_cast<UINT>(parsedSource.length()),
  135. pDefines,
  136. nullptr,
  137. getProperties().getEntryPoint().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 < D3D9RenderAPI::getResourceCreationDeviceCount(); ++i)
  159. {
  160. IDirect3DDevice9* d3d9Device = D3D9RenderAPI::getResourceCreationDevice(i);
  161. loadFromMicrocode(d3d9Device, mMicrocode);
  162. }
  163. D3D9HLSLParamParser paramParser(constTable, mBlocks);
  164. mParametersDesc = paramParser.buildParameterDescriptions();
  165. mIsCompiled = true;
  166. mCompileError = "";
  167. SAFE_RELEASE(constTable);
  168. }
  169. BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_GpuProgram);
  170. GpuProgramCore::initialize();
  171. }
  172. D3D9GpuVertexProgramCore::D3D9GpuVertexProgramCore(const String& source, const String& entryPoint,
  173. GpuProgramProfile profile)
  174. : D3D9GpuProgramCore(source, entryPoint, GPT_VERTEX_PROGRAM, profile)
  175. {
  176. }
  177. D3D9GpuVertexProgramCore::~D3D9GpuVertexProgramCore()
  178. {
  179. auto it = mMapDeviceToVertexShader.begin();
  180. while (it != mMapDeviceToVertexShader.end())
  181. {
  182. SAFE_RELEASE(it->second);
  183. ++it;
  184. }
  185. mMapDeviceToVertexShader.clear();
  186. }
  187. void D3D9GpuVertexProgramCore::loadFromMicrocode(IDirect3DDevice9* d3d9Device, ID3DXBuffer* microcode)
  188. {
  189. auto it = mMapDeviceToVertexShader.find(d3d9Device);
  190. if (it != mMapDeviceToVertexShader.end())
  191. SAFE_RELEASE(it->second);
  192. // Create the shader
  193. IDirect3DVertexShader9* pVertexShader;
  194. HRESULT hr;
  195. hr = d3d9Device->CreateVertexShader(
  196. static_cast<DWORD*>(microcode->GetBufferPointer()),
  197. &pVertexShader);
  198. if (FAILED(hr))
  199. {
  200. BS_EXCEPT(RenderingAPIException, "Cannot create D3D9 vertex shader from microcode");
  201. }
  202. mMapDeviceToVertexShader[d3d9Device] = pVertexShader;
  203. }
  204. void D3D9GpuVertexProgramCore::notifyOnDeviceCreate(IDirect3DDevice9* d3d9Device)
  205. {
  206. }
  207. void D3D9GpuVertexProgramCore::notifyOnDeviceDestroy(IDirect3DDevice9* d3d9Device)
  208. {
  209. auto it = mMapDeviceToVertexShader.find(d3d9Device);
  210. // Case shader found -> release it and erase from map.
  211. if (it != mMapDeviceToVertexShader.end())
  212. {
  213. SAFE_RELEASE(it->second);
  214. mMapDeviceToVertexShader.erase(it);
  215. }
  216. }
  217. IDirect3DVertexShader9* D3D9GpuVertexProgramCore::getVertexShader()
  218. {
  219. if (!isCompiled())
  220. return nullptr;
  221. IDirect3DDevice9* d3d9Device = D3D9RenderAPI::getActiveD3D9Device();
  222. auto it = mMapDeviceToVertexShader.find(d3d9Device);
  223. // Shader was not found -> load it.
  224. if (it == mMapDeviceToVertexShader.end())
  225. {
  226. loadFromMicrocode(d3d9Device, mMicrocode);
  227. it = mMapDeviceToVertexShader.find(d3d9Device);
  228. }
  229. return it->second;
  230. }
  231. D3D9GpuFragmentProgramCore::D3D9GpuFragmentProgramCore(const String& source, const String& entryPoint,
  232. GpuProgramProfile profile)
  233. : D3D9GpuProgramCore(source, entryPoint, GPT_FRAGMENT_PROGRAM, profile)
  234. {
  235. }
  236. D3D9GpuFragmentProgramCore::~D3D9GpuFragmentProgramCore()
  237. {
  238. auto it = mMapDeviceToPixelShader.begin();
  239. while (it != mMapDeviceToPixelShader.end())
  240. {
  241. SAFE_RELEASE(it->second);
  242. ++it;
  243. }
  244. mMapDeviceToPixelShader.clear();
  245. }
  246. void D3D9GpuFragmentProgramCore::loadFromMicrocode(IDirect3DDevice9* d3d9Device, ID3DXBuffer* microcode)
  247. {
  248. auto it = mMapDeviceToPixelShader.find(d3d9Device);
  249. if (it != mMapDeviceToPixelShader.end())
  250. SAFE_RELEASE(it->second);
  251. // Create the shader
  252. IDirect3DPixelShader9* pPixelShader;
  253. HRESULT hr;
  254. hr = d3d9Device->CreatePixelShader(static_cast<DWORD*>(microcode->GetBufferPointer()), &pPixelShader);
  255. if (FAILED(hr))
  256. BS_EXCEPT(RenderingAPIException, "Cannot create D3D9 pixel shader from microcode.");
  257. mMapDeviceToPixelShader[d3d9Device] = pPixelShader;
  258. }
  259. void D3D9GpuFragmentProgramCore::notifyOnDeviceCreate(IDirect3DDevice9* d3d9Device)
  260. {
  261. }
  262. void D3D9GpuFragmentProgramCore::notifyOnDeviceDestroy(IDirect3DDevice9* d3d9Device)
  263. {
  264. auto it = mMapDeviceToPixelShader.find(d3d9Device);
  265. // Case shader found -> release it and erase from map.
  266. if (it != mMapDeviceToPixelShader.end())
  267. {
  268. SAFE_RELEASE(it->second);
  269. mMapDeviceToPixelShader.erase(it);
  270. }
  271. }
  272. IDirect3DPixelShader9* D3D9GpuFragmentProgramCore::getPixelShader()
  273. {
  274. if (!isCompiled())
  275. return nullptr;
  276. IDirect3DDevice9* d3d9Device = D3D9RenderAPI::getActiveD3D9Device();
  277. auto it = mMapDeviceToPixelShader.find(d3d9Device);
  278. // Shader was not found -> load it.
  279. if (it == mMapDeviceToPixelShader.end())
  280. {
  281. loadFromMicrocode(d3d9Device, mMicrocode);
  282. it = mMapDeviceToPixelShader.find(d3d9Device);
  283. }
  284. return it->second;
  285. }
  286. }