BsD3D9GpuProgram.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  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. #include "BsHardwareBufferManager.h"
  13. namespace BansheeEngine
  14. {
  15. D3D9GpuProgramCore::D3D9GpuProgramCore(const String& source, const String& entryPoint,
  16. GpuProgramType gptype, GpuProgramProfile profile)
  17. : GpuProgramCore(source, entryPoint, gptype, profile, false),
  18. mMicrocode(nullptr), mOptimisationLevel(OPT_DEFAULT)
  19. { }
  20. D3D9GpuProgramCore::~D3D9GpuProgramCore()
  21. {
  22. SAFE_RELEASE(mMicrocode);
  23. BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_GpuProgram);
  24. }
  25. void D3D9GpuProgramCore::initialize()
  26. {
  27. if (!isSupported())
  28. {
  29. mIsCompiled = false;
  30. mCompileError = "Specified program is not supported by the current render system.";
  31. GpuProgramCore::initialize();
  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. 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 = D3D9RenderAPI::instance().getCapabilities()->gpuProgProfileToRSSpecificProfile(getProperties().getProfile());
  131. String parsedSource = D3D9EmulatedParamBlockParser::parse(getProperties().getSource(), 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. getProperties().getEntryPoint().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 < D3D9RenderAPI::getResourceCreationDeviceCount(); ++i)
  160. {
  161. IDirect3DDevice9* d3d9Device = D3D9RenderAPI::getResourceCreationDevice(i);
  162. loadFromMicrocode(d3d9Device, mMicrocode);
  163. }
  164. D3D9HLSLParamParser paramParser(constTable, mBlocks);
  165. mParametersDesc = paramParser.buildParameterDescriptions();
  166. // Get input declaration
  167. if (mProperties.getType() == GPT_VERTEX_PROGRAM)
  168. {
  169. UINT32 numInputs = 0;
  170. D3DXGetShaderInputSemantics((DWORD*)mMicrocode->GetBufferPointer(), nullptr, &numInputs);
  171. List<VertexElement> elements;
  172. if (numInputs > 0)
  173. {
  174. D3DXSEMANTIC* semantics = bs_stack_alloc<D3DXSEMANTIC>(numInputs);
  175. for (UINT32 i = 0; i < numInputs; i++)
  176. {
  177. elements.push_back(VertexElement(0, 0, VET_FLOAT4,
  178. D3D9Mappings::get((D3DDECLUSAGE)semantics[i].Usage), semantics[i].UsageIndex));
  179. }
  180. bs_stack_free(semantics);
  181. }
  182. mInputDeclaration = HardwareBufferCoreManager::instance().createVertexDeclaration(elements);
  183. }
  184. mIsCompiled = true;
  185. mCompileError = "";
  186. SAFE_RELEASE(constTable);
  187. }
  188. BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_GpuProgram);
  189. GpuProgramCore::initialize();
  190. }
  191. D3D9GpuVertexProgramCore::D3D9GpuVertexProgramCore(const String& source, const String& entryPoint,
  192. GpuProgramProfile profile)
  193. : D3D9GpuProgramCore(source, entryPoint, GPT_VERTEX_PROGRAM, profile)
  194. {
  195. }
  196. D3D9GpuVertexProgramCore::~D3D9GpuVertexProgramCore()
  197. {
  198. auto it = mMapDeviceToVertexShader.begin();
  199. while (it != mMapDeviceToVertexShader.end())
  200. {
  201. SAFE_RELEASE(it->second);
  202. ++it;
  203. }
  204. mMapDeviceToVertexShader.clear();
  205. }
  206. void D3D9GpuVertexProgramCore::loadFromMicrocode(IDirect3DDevice9* d3d9Device, ID3DXBuffer* microcode)
  207. {
  208. auto it = mMapDeviceToVertexShader.find(d3d9Device);
  209. if (it != mMapDeviceToVertexShader.end())
  210. SAFE_RELEASE(it->second);
  211. // Create the shader
  212. IDirect3DVertexShader9* pVertexShader;
  213. HRESULT hr;
  214. hr = d3d9Device->CreateVertexShader(
  215. static_cast<DWORD*>(microcode->GetBufferPointer()),
  216. &pVertexShader);
  217. if (FAILED(hr))
  218. {
  219. BS_EXCEPT(RenderingAPIException, "Cannot create D3D9 vertex shader from microcode");
  220. }
  221. mMapDeviceToVertexShader[d3d9Device] = pVertexShader;
  222. }
  223. void D3D9GpuVertexProgramCore::notifyOnDeviceCreate(IDirect3DDevice9* d3d9Device)
  224. {
  225. }
  226. void D3D9GpuVertexProgramCore::notifyOnDeviceDestroy(IDirect3DDevice9* d3d9Device)
  227. {
  228. auto it = mMapDeviceToVertexShader.find(d3d9Device);
  229. // Case shader found -> release it and erase from map.
  230. if (it != mMapDeviceToVertexShader.end())
  231. {
  232. SAFE_RELEASE(it->second);
  233. mMapDeviceToVertexShader.erase(it);
  234. }
  235. }
  236. IDirect3DVertexShader9* D3D9GpuVertexProgramCore::getVertexShader()
  237. {
  238. if (!isCompiled())
  239. return nullptr;
  240. IDirect3DDevice9* d3d9Device = D3D9RenderAPI::getActiveD3D9Device();
  241. auto it = mMapDeviceToVertexShader.find(d3d9Device);
  242. // Shader was not found -> load it.
  243. if (it == mMapDeviceToVertexShader.end())
  244. {
  245. loadFromMicrocode(d3d9Device, mMicrocode);
  246. it = mMapDeviceToVertexShader.find(d3d9Device);
  247. }
  248. return it->second;
  249. }
  250. D3D9GpuFragmentProgramCore::D3D9GpuFragmentProgramCore(const String& source, const String& entryPoint,
  251. GpuProgramProfile profile)
  252. : D3D9GpuProgramCore(source, entryPoint, GPT_FRAGMENT_PROGRAM, profile)
  253. {
  254. }
  255. D3D9GpuFragmentProgramCore::~D3D9GpuFragmentProgramCore()
  256. {
  257. auto it = mMapDeviceToPixelShader.begin();
  258. while (it != mMapDeviceToPixelShader.end())
  259. {
  260. SAFE_RELEASE(it->second);
  261. ++it;
  262. }
  263. mMapDeviceToPixelShader.clear();
  264. }
  265. void D3D9GpuFragmentProgramCore::loadFromMicrocode(IDirect3DDevice9* d3d9Device, ID3DXBuffer* microcode)
  266. {
  267. auto it = mMapDeviceToPixelShader.find(d3d9Device);
  268. if (it != mMapDeviceToPixelShader.end())
  269. SAFE_RELEASE(it->second);
  270. // Create the shader
  271. IDirect3DPixelShader9* pPixelShader;
  272. HRESULT hr;
  273. hr = d3d9Device->CreatePixelShader(static_cast<DWORD*>(microcode->GetBufferPointer()), &pPixelShader);
  274. if (FAILED(hr))
  275. BS_EXCEPT(RenderingAPIException, "Cannot create D3D9 pixel shader from microcode.");
  276. mMapDeviceToPixelShader[d3d9Device] = pPixelShader;
  277. }
  278. void D3D9GpuFragmentProgramCore::notifyOnDeviceCreate(IDirect3DDevice9* d3d9Device)
  279. {
  280. }
  281. void D3D9GpuFragmentProgramCore::notifyOnDeviceDestroy(IDirect3DDevice9* d3d9Device)
  282. {
  283. auto it = mMapDeviceToPixelShader.find(d3d9Device);
  284. // Case shader found -> release it and erase from map.
  285. if (it != mMapDeviceToPixelShader.end())
  286. {
  287. SAFE_RELEASE(it->second);
  288. mMapDeviceToPixelShader.erase(it);
  289. }
  290. }
  291. IDirect3DPixelShader9* D3D9GpuFragmentProgramCore::getPixelShader()
  292. {
  293. if (!isCompiled())
  294. return nullptr;
  295. IDirect3DDevice9* d3d9Device = D3D9RenderAPI::getActiveD3D9Device();
  296. auto it = mMapDeviceToPixelShader.find(d3d9Device);
  297. // Shader was not found -> load it.
  298. if (it == mMapDeviceToPixelShader.end())
  299. {
  300. loadFromMicrocode(d3d9Device, mMicrocode);
  301. it = mMapDeviceToPixelShader.find(d3d9Device);
  302. }
  303. return it->second;
  304. }
  305. }