2
0

CmD3D9GpuProgram.cpp 10 KB

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