d3d12-capture.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. #define _CRT_SECURE_NO_WARNINGS
  2. #include <windows.h>
  3. #include "graphics-hook.h"
  4. #if COMPILE_D3D12_HOOK
  5. #include <d3d11on12.h>
  6. #include <d3d12.h>
  7. #include <dxgi1_2.h>
  8. #include "dxgi-helpers.hpp"
  9. #include "../funchook.h"
  10. struct d3d12_data {
  11. ID3D12Device *device; /* do not release */
  12. uint32_t base_cx;
  13. uint32_t base_cy;
  14. uint32_t cx;
  15. uint32_t cy;
  16. DXGI_FORMAT format;
  17. bool using_shtex : 1;
  18. bool using_scale : 1;
  19. bool multisampled : 1;
  20. ID3D11Device *device11;
  21. ID3D11DeviceContext *context11;
  22. ID3D11On12Device *device11on12;
  23. union {
  24. struct {
  25. struct shtex_data *shtex_info;
  26. ID3D11Resource *backbuffer11;
  27. ID3D11Texture2D *copy_tex;
  28. HANDLE handle;
  29. };
  30. };
  31. };
  32. static struct d3d12_data data = {};
  33. void d3d12_free(void)
  34. {
  35. if (data.copy_tex)
  36. data.copy_tex->Release();
  37. if (data.backbuffer11)
  38. data.backbuffer11->Release();
  39. if (data.device11)
  40. data.device11->Release();
  41. if (data.context11)
  42. data.context11->Release();
  43. if (data.device11on12)
  44. data.device11on12->Release();
  45. capture_free();
  46. memset(&data, 0, sizeof(data));
  47. hlog("----------------- d3d12 capture freed ----------------");
  48. }
  49. static bool create_d3d12_tex(ID3D12Resource *backbuffer)
  50. {
  51. D3D11_RESOURCE_FLAGS rf11 = {};
  52. HRESULT hr;
  53. hr = data.device11on12->CreateWrappedResource(backbuffer, &rf11,
  54. D3D12_RESOURCE_STATE_COPY_SOURCE,
  55. D3D12_RESOURCE_STATE_PRESENT,
  56. __uuidof(ID3D11Resource),
  57. (void**)&data.backbuffer11);
  58. if (FAILED(hr)) {
  59. hlog_hr("create_d3d12_tex: failed to create backbuffer11",
  60. hr);
  61. return false;
  62. }
  63. D3D11_TEXTURE2D_DESC desc11 = {};
  64. desc11.Width = data.cx;
  65. desc11.Height = data.cy;
  66. desc11.MipLevels = 1;
  67. desc11.ArraySize = 1;
  68. desc11.Format = data.format;
  69. desc11.SampleDesc.Count = 1;
  70. desc11.BindFlags = D3D11_BIND_SHADER_RESOURCE;
  71. desc11.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
  72. hr = data.device11->CreateTexture2D(&desc11, nullptr, &data.copy_tex);
  73. if (FAILED(hr)) {
  74. hlog_hr("create_d3d12_tex: creation of d3d11 copy tex failed",
  75. hr);
  76. return false;
  77. }
  78. data.device11on12->ReleaseWrappedResources(&data.backbuffer11, 1);
  79. IDXGIResource *dxgi_res;
  80. hr = data.copy_tex->QueryInterface(__uuidof(IDXGIResource),
  81. (void**)&dxgi_res);
  82. if (FAILED(hr)) {
  83. hlog_hr("create_d3d12_tex: failed to query "
  84. "IDXGIResource interface from texture", hr);
  85. return false;
  86. }
  87. hr = dxgi_res->GetSharedHandle(&data.handle);
  88. dxgi_res->Release();
  89. if (FAILED(hr)) {
  90. hlog_hr("create_d3d12_tex: failed to get shared handle", hr);
  91. return false;
  92. }
  93. return true;
  94. }
  95. typedef PFN_D3D11ON12_CREATE_DEVICE create_11_on_12_t;
  96. const static D3D_FEATURE_LEVEL feature_levels[] =
  97. {
  98. D3D_FEATURE_LEVEL_11_0,
  99. D3D_FEATURE_LEVEL_10_1,
  100. D3D_FEATURE_LEVEL_10_0,
  101. D3D_FEATURE_LEVEL_9_3,
  102. };
  103. static bool d3d12_init_11on12(void)
  104. {
  105. static HMODULE d3d11 = nullptr;
  106. static create_11_on_12_t create_11_on_12 = nullptr;
  107. static bool initialized_11 = false;
  108. static bool initialized_func = false;
  109. HRESULT hr;
  110. if (!initialized_11 && !d3d11) {
  111. d3d11 = load_system_library("d3d11.dll");
  112. if (!d3d11) {
  113. hlog("d3d12_init_11on12: failed to load d3d11");
  114. }
  115. initialized_11 = true;
  116. }
  117. if (!d3d11) {
  118. return false;
  119. }
  120. if (!initialized_func && !create_11_on_12) {
  121. create_11_on_12 = (create_11_on_12_t)GetProcAddress(d3d11,
  122. "D3D11On12CreateDevice");
  123. if (!create_11_on_12) {
  124. hlog("d3d12_init_11on12: Failed to get "
  125. "D3D11On12CreateDevice address");
  126. }
  127. initialized_func = true;
  128. }
  129. if (!create_11_on_12) {
  130. return false;
  131. }
  132. hr = create_11_on_12(data.device, 0, nullptr, 0,
  133. nullptr, 0, 0,
  134. &data.device11, &data.context11, nullptr);
  135. if (FAILED(hr)) {
  136. hlog_hr("d3d12_init_11on12: failed to create 11 device", hr);
  137. return false;
  138. }
  139. data.device11->QueryInterface(__uuidof(ID3D11On12Device),
  140. (void**)&data.device11on12);
  141. if (FAILED(hr)) {
  142. hlog_hr("d3d12_init_11on12: failed to query 11on12 device", hr);
  143. return false;
  144. }
  145. return true;
  146. }
  147. static bool d3d12_shtex_init(HWND window, ID3D12Resource *backbuffer)
  148. {
  149. if (!d3d12_init_11on12()) {
  150. return false;
  151. }
  152. if (!create_d3d12_tex(backbuffer)) {
  153. return false;
  154. }
  155. if (!capture_init_shtex(&data.shtex_info, window,
  156. data.base_cx, data.base_cy, data.cx, data.cy,
  157. data.format, false, (uintptr_t)data.handle)) {
  158. return false;
  159. }
  160. hlog("d3d12 shared texture capture successful");
  161. return true;
  162. }
  163. static inline bool d3d12_init_format(IDXGISwapChain *swap, HWND &window)
  164. {
  165. DXGI_SWAP_CHAIN_DESC desc;
  166. HRESULT hr;
  167. hr = swap->GetDesc(&desc);
  168. if (FAILED(hr)) {
  169. hlog_hr("d3d12_init_format: swap->GetDesc failed", hr);
  170. return false;
  171. }
  172. data.format = fix_dxgi_format(desc.BufferDesc.Format);
  173. data.multisampled = desc.SampleDesc.Count > 1;
  174. window = desc.OutputWindow;
  175. data.base_cx = desc.BufferDesc.Width;
  176. data.base_cy = desc.BufferDesc.Height;
  177. if (data.using_scale) {
  178. data.cx = global_hook_info->cx;
  179. data.cy = global_hook_info->cy;
  180. } else {
  181. data.cx = desc.BufferDesc.Width;
  182. data.cy = desc.BufferDesc.Height;
  183. }
  184. return true;
  185. }
  186. static void d3d12_init(IDXGISwapChain *swap, ID3D12Resource *backbuffer)
  187. {
  188. bool success = true;
  189. HWND window;
  190. HRESULT hr;
  191. data.using_scale = global_hook_info->use_scale;
  192. hr = swap->GetDevice(__uuidof(ID3D12Device), (void**)&data.device);
  193. if (FAILED(hr)) {
  194. hlog_hr("d3d12_init: failed to get device from swap", hr);
  195. return;
  196. }
  197. data.device->Release();
  198. if (!d3d12_init_format(swap, window)) {
  199. return;
  200. }
  201. if (data.using_scale) {
  202. hlog("d3d12_init: scaling currently unsupported; ignoring");
  203. }
  204. if (success) {
  205. if (global_hook_info->force_shmem) {
  206. hlog("d3d12_init: shared memory capture currently "
  207. "unsupported; ignoring");
  208. }
  209. success = d3d12_shtex_init(window, backbuffer);
  210. }
  211. if (!success)
  212. d3d12_free();
  213. }
  214. static inline void d3d12_copy_texture(ID3D11Resource *dst, ID3D11Resource *src)
  215. {
  216. if (data.multisampled) {
  217. data.context11->ResolveSubresource(dst, 0, src, 0, data.format);
  218. } else {
  219. data.context11->CopyResource(dst, src);
  220. }
  221. }
  222. static inline void d3d12_shtex_capture()
  223. {
  224. data.device11on12->AcquireWrappedResources(&data.backbuffer11, 1);
  225. d3d12_copy_texture(data.copy_tex, data.backbuffer11);
  226. data.device11on12->ReleaseWrappedResources(&data.backbuffer11, 1);
  227. data.context11->Flush();
  228. }
  229. void d3d12_capture(void *swap_ptr, void *backbuffer_ptr)
  230. {
  231. IUnknown *unk_backbuffer = (IUnknown*)backbuffer_ptr;
  232. IDXGISwapChain *swap = (IDXGISwapChain*)swap_ptr;
  233. ID3D12Resource *backbuffer;
  234. HRESULT hr;
  235. if (capture_should_stop()) {
  236. d3d12_free();
  237. }
  238. if (capture_should_init()) {
  239. hr = unk_backbuffer->QueryInterface(__uuidof(ID3D12Resource),
  240. (void**)&backbuffer);
  241. if (FAILED(hr)) {
  242. hlog_hr("d3d12_capture: failed to get backbuffer", hr);
  243. return;
  244. }
  245. d3d12_init(swap, backbuffer);
  246. backbuffer->Release();
  247. }
  248. if (capture_ready()) {
  249. d3d12_shtex_capture();
  250. }
  251. }
  252. #endif