BsD3D9GpuProgram.cpp 9.2 KB

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