win_directx_helper.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. // This file is part of Desktop App Toolkit,
  2. // a set of libraries for developing nice desktop applications.
  3. //
  4. // For license and copyright information please follow this link:
  5. // https://github.com/desktop-app/legal/blob/master/LEGAL
  6. //
  7. #include <d3d9.h>
  8. #include <d3d11.h>
  9. #include <d3dcompiler.h>
  10. extern "C" {
  11. #include <openssl/sha.h>
  12. } // extern "C"
  13. #include <string>
  14. #include <vector>
  15. #include <array>
  16. #define LOAD_SYMBOL(handle, func) LoadSymbol(handle, #func, func)
  17. namespace DirectX {
  18. namespace {
  19. constexpr auto kMaxPathLong = 32767;
  20. using Handle = HINSTANCE;
  21. // d3dcompiler_47.dll
  22. HRESULT (__stdcall *D3DCompile)(
  23. LPCVOID pSrcData,
  24. SIZE_T SrcDataSize,
  25. LPCSTR pFileName,
  26. CONST D3D_SHADER_MACRO* pDefines,
  27. ID3DInclude* pInclude,
  28. LPCSTR pEntrypoint,
  29. LPCSTR pTarget,
  30. UINT Flags1,
  31. UINT Flags2,
  32. ID3DBlob** ppCode,
  33. ID3DBlob** ppErrorMsgs);
  34. HRESULT (__stdcall *D3DDisassemble)(
  35. _In_reads_bytes_(SrcDataSize) LPCVOID pSrcData,
  36. _In_ SIZE_T SrcDataSize,
  37. _In_ UINT Flags,
  38. _In_opt_ LPCSTR szComments,
  39. _Out_ ID3DBlob** ppDisassembly);
  40. // d3d9.dll
  41. IDirect3D9 * (__stdcall *Direct3DCreate9)(UINT SDKVersion);
  42. int (__stdcall *D3DPERF_BeginEvent)(D3DCOLOR col, LPCWSTR wszName);
  43. int (__stdcall *D3DPERF_EndEvent)(void);
  44. void (__stdcall *D3DPERF_SetMarker)(D3DCOLOR col, LPCWSTR wszName);
  45. DWORD (__stdcall *D3DPERF_GetStatus)(void);
  46. // d3d11.dll
  47. HRESULT (__stdcall *D3D11CreateDevice)(
  48. _In_opt_ IDXGIAdapter* pAdapter,
  49. D3D_DRIVER_TYPE DriverType,
  50. HMODULE Software,
  51. UINT Flags,
  52. _In_reads_opt_(FeatureLevels) CONST D3D_FEATURE_LEVEL* pFeatureLevels,
  53. UINT FeatureLevels,
  54. UINT SDKVersion,
  55. _COM_Outptr_opt_ ID3D11Device** ppDevice,
  56. _Out_opt_ D3D_FEATURE_LEVEL* pFeatureLevel,
  57. _COM_Outptr_opt_ ID3D11DeviceContext** ppImmediateContext);
  58. // dxgi.dll
  59. HRESULT (__stdcall *CreateDXGIFactory)(
  60. REFIID riid,
  61. _COM_Outptr_ void **ppFactory);
  62. HRESULT (__stdcall *CreateDXGIFactory1)(
  63. REFIID riid,
  64. _COM_Outptr_ void **ppFactory);
  65. template <typename Function>
  66. inline bool LoadSymbol(Handle handle, const char *name, Function &func) {
  67. func = handle
  68. ? reinterpret_cast<Function>(GetProcAddress(handle, name))
  69. : nullptr;
  70. return (func != nullptr);
  71. }
  72. // For win_directx_helper.
  73. std::string FileSha256(const wchar_t *path) {
  74. using uchar = unsigned char;
  75. constexpr auto kLimit = 10 * 1024 * 1024;
  76. auto buffer = std::vector<uchar>(kLimit);
  77. auto size = DWORD();
  78. const auto file = CreateFile(
  79. path,
  80. GENERIC_READ,
  81. FILE_SHARE_READ,
  82. nullptr,
  83. OPEN_EXISTING,
  84. FILE_ATTRIBUTE_NORMAL,
  85. nullptr);
  86. if (file == INVALID_HANDLE_VALUE) {
  87. return {};
  88. }
  89. const auto read = ReadFile(file, buffer.data(), kLimit, &size, nullptr);
  90. CloseHandle(file);
  91. if (!read || !size || size >= kLimit) {
  92. return {};
  93. }
  94. auto binary = std::array<uchar, SHA256_DIGEST_LENGTH>{};
  95. SHA256(buffer.data(), size, binary.data());
  96. const auto hex = [](uchar value) {
  97. return (value >= 10) ? ('a' + (value - 10)) : ('0' + value);
  98. };
  99. auto result = std::string();
  100. result.reserve(binary.size() * 2);
  101. for (const auto byte : binary) {
  102. result.push_back(hex(byte / 16));
  103. result.push_back(hex(byte % 16));
  104. }
  105. return result;
  106. }
  107. bool ResolveD3DCompiler(const wchar_t *path) {
  108. const auto d3dcompiler = LoadLibrary(path);
  109. return true
  110. && LOAD_SYMBOL(d3dcompiler, D3DCompile)
  111. && LOAD_SYMBOL(d3dcompiler, D3DDisassemble);
  112. }
  113. bool ResolveD3DCompiler() {
  114. static const auto loaded = [] {
  115. #ifdef DESKTOP_APP_D3DCOMPILER_HASH
  116. auto exePath = std::array<WCHAR, kMaxPathLong + 1>{ { 0 } };
  117. const auto exeLength = GetModuleFileName(
  118. nullptr,
  119. exePath.data(),
  120. kMaxPathLong + 1);
  121. if (!exeLength || exeLength >= kMaxPathLong + 1) {
  122. return false;
  123. }
  124. const auto exe = std::wstring(exePath.data());
  125. const auto last1 = exe.find_last_of('\\');
  126. const auto last2 = exe.find_last_of('/');
  127. const auto last = std::max(
  128. (last1 == std::wstring::npos) ? -1 : int(last1),
  129. (last2 == std::wstring::npos) ? -1 : int(last2));
  130. if (last < 0) {
  131. return false;
  132. }
  133. #if defined _WIN64
  134. const auto arch = L"x64";
  135. #elif defined _WIN32 // _WIN64
  136. const auto arch = L"x86";
  137. #else // _WIN64 || _WIN32
  138. #error "Invalid configuration."
  139. #endif // _WIN64 || _WIN32
  140. #define DESKTOP_APP_STRINGIFY2(x) #x
  141. #define DESKTOP_APP_STRINGIFY(x) DESKTOP_APP_STRINGIFY2(x)
  142. const auto hash = DESKTOP_APP_STRINGIFY(DESKTOP_APP_D3DCOMPILER_HASH);
  143. #undef DESKTOP_APP_STRINGIFY
  144. #undef DESKTOP_APP_STRINGIFY2
  145. const auto compiler = exe.substr(0, last + 1)
  146. + L"modules\\" + arch + L"\\d3d\\d3dcompiler_47.dll";
  147. const auto path = compiler.c_str();
  148. if (FileSha256(path) == hash && ResolveD3DCompiler(path)) {
  149. return true;
  150. }
  151. #elif defined WIN_DIRECTX_HELPER_SPECIAL_TARGET // DESKTOP_APP_D3DCOMPILER_HASH
  152. #error "Special target build should have d3dcompiler hash."
  153. #endif // !DESKTOP_APP_D3DCOMPILER_HASH && WIN_DIRECTX_HELPER_SPECIAL_TARGET
  154. return ResolveD3DCompiler(L"d3dcompiler_47.dll");
  155. }();
  156. return loaded;
  157. }
  158. bool ResolveD3D9() {
  159. static const auto loaded = [] {
  160. const auto d3d9 = LoadLibrary(L"d3d9.dll");
  161. LOAD_SYMBOL(d3d9, D3DPERF_BeginEvent);
  162. LOAD_SYMBOL(d3d9, D3DPERF_EndEvent);
  163. LOAD_SYMBOL(d3d9, D3DPERF_SetMarker);
  164. LOAD_SYMBOL(d3d9, D3DPERF_GetStatus);
  165. return ResolveD3DCompiler()
  166. && LOAD_SYMBOL(d3d9, Direct3DCreate9);
  167. }();
  168. return loaded;
  169. }
  170. bool ResolveD3D11() {
  171. static const auto loaded = [] {
  172. const auto d3d11 = LoadLibrary(L"d3d11.dll");
  173. return ResolveD3DCompiler()
  174. && LOAD_SYMBOL(d3d11, D3D11CreateDevice);
  175. }();
  176. return loaded;
  177. }
  178. bool ResolveDXGI() {
  179. static const auto loaded = [&] {
  180. const auto dxgi = LoadLibrary(L"dxgi.dll");
  181. LOAD_SYMBOL(dxgi, CreateDXGIFactory1);
  182. return true
  183. && LOAD_SYMBOL(dxgi, CreateDXGIFactory);
  184. }();
  185. return loaded;
  186. }
  187. } // namespace
  188. } // namespace DirectX
  189. bool DirectXResolveCompiler() {
  190. return DirectX::ResolveD3DCompiler();
  191. }
  192. namespace D = DirectX;
  193. extern "C" {
  194. IDirect3D9 * WINAPI Direct3DCreate9(UINT SDKVersion) {
  195. return D::ResolveD3D9()
  196. ? D::Direct3DCreate9(SDKVersion)
  197. : nullptr;
  198. }
  199. int WINAPI D3DPERF_BeginEvent(D3DCOLOR col, LPCWSTR wszName) {
  200. return (D::ResolveD3D9() && D::D3DPERF_BeginEvent)
  201. ? D::D3DPERF_BeginEvent(col, wszName)
  202. : -1;
  203. }
  204. int WINAPI D3DPERF_EndEvent(void) {
  205. return (D::ResolveD3D9() && D::D3DPERF_EndEvent)
  206. ? D::D3DPERF_EndEvent()
  207. : -1;
  208. }
  209. void WINAPI D3DPERF_SetMarker(D3DCOLOR col, LPCWSTR wszName) {
  210. if (D::ResolveD3D9() && D::D3DPERF_SetMarker) {
  211. D::D3DPERF_SetMarker(col, wszName);
  212. }
  213. }
  214. DWORD WINAPI D3DPERF_GetStatus(void) {
  215. return (D::ResolveD3D9() && D::D3DPERF_GetStatus)
  216. ? D::D3DPERF_GetStatus()
  217. : 0;
  218. }
  219. HRESULT WINAPI D3D11CreateDevice(
  220. _In_opt_ IDXGIAdapter* pAdapter,
  221. D3D_DRIVER_TYPE DriverType,
  222. HMODULE Software,
  223. UINT Flags,
  224. _In_reads_opt_(FeatureLevels) CONST D3D_FEATURE_LEVEL* pFeatureLevels,
  225. UINT FeatureLevels,
  226. UINT SDKVersion,
  227. _COM_Outptr_opt_ ID3D11Device** ppDevice,
  228. _Out_opt_ D3D_FEATURE_LEVEL* pFeatureLevel,
  229. _COM_Outptr_opt_ ID3D11DeviceContext** ppImmediateContext) {
  230. return D::ResolveD3D11()
  231. ? D::D3D11CreateDevice(
  232. pAdapter,
  233. DriverType,
  234. Software,
  235. Flags,
  236. pFeatureLevels,
  237. FeatureLevels,
  238. SDKVersion,
  239. ppDevice,
  240. pFeatureLevel,
  241. ppImmediateContext)
  242. : CO_E_DLLNOTFOUND;
  243. }
  244. HRESULT WINAPI CreateDXGIFactory(
  245. REFIID riid,
  246. _COM_Outptr_ void **ppFactory) {
  247. return D::ResolveDXGI()
  248. ? D::CreateDXGIFactory(riid, ppFactory)
  249. : CO_E_DLLNOTFOUND;
  250. }
  251. HRESULT WINAPI CreateDXGIFactory1(
  252. REFIID riid,
  253. _COM_Outptr_ void **ppFactory) {
  254. return (D::ResolveDXGI() && D::CreateDXGIFactory1)
  255. ? D::CreateDXGIFactory1(riid, ppFactory)
  256. : CO_E_DLLNOTFOUND;
  257. }
  258. } // extern "C"