d3d11-capture.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847
  1. #define _CRT_SECURE_NO_WARNINGS
  2. #include <d3d11.h>
  3. #include <dxgi.h>
  4. #include "dxgi-helpers.hpp"
  5. #include "graphics-hook.h"
  6. #include "../funchook.h"
  7. struct d3d11_data {
  8. ID3D11Device *device; /* do not release */
  9. ID3D11DeviceContext *context; /* do not release */
  10. uint32_t base_cx;
  11. uint32_t base_cy;
  12. uint32_t cx;
  13. uint32_t cy;
  14. DXGI_FORMAT format;
  15. bool using_shtex : 1;
  16. bool using_scale : 1;
  17. bool multisampled : 1;
  18. ID3D11Texture2D *scale_tex;
  19. ID3D11ShaderResourceView *scale_resource;
  20. ID3D11VertexShader *vertex_shader;
  21. ID3D11InputLayout *vertex_layout;
  22. ID3D11PixelShader *pixel_shader;
  23. ID3D11SamplerState *sampler_state;
  24. ID3D11BlendState *blend_state;
  25. ID3D11DepthStencilState *zstencil_state;
  26. ID3D11RasterizerState *raster_state;
  27. ID3D11Buffer *vertex_buffer;
  28. union {
  29. /* shared texture */
  30. struct {
  31. struct shtex_data *shtex_info;
  32. ID3D11Texture2D *texture;
  33. ID3D11RenderTargetView *render_target;
  34. HANDLE handle;
  35. };
  36. /* shared memory */
  37. struct {
  38. ID3D11Texture2D *copy_surfaces[NUM_BUFFERS];
  39. ID3D11Texture2D *textures[NUM_BUFFERS];
  40. ID3D11RenderTargetView *render_targets[NUM_BUFFERS];
  41. bool texture_ready[NUM_BUFFERS];
  42. bool texture_mapped[NUM_BUFFERS];
  43. uint32_t pitch;
  44. struct shmem_data *shmem_info;
  45. int cur_tex;
  46. int copy_wait;
  47. };
  48. };
  49. };
  50. static struct d3d11_data data = {};
  51. void d3d11_free(void)
  52. {
  53. if (data.scale_tex)
  54. data.scale_tex->Release();
  55. if (data.scale_resource)
  56. data.scale_resource->Release();
  57. if (data.vertex_shader)
  58. data.vertex_shader->Release();
  59. if (data.vertex_layout)
  60. data.vertex_layout->Release();
  61. if (data.pixel_shader)
  62. data.pixel_shader->Release();
  63. if (data.sampler_state)
  64. data.sampler_state->Release();
  65. if (data.blend_state)
  66. data.blend_state->Release();
  67. if (data.zstencil_state)
  68. data.zstencil_state->Release();
  69. if (data.raster_state)
  70. data.raster_state->Release();
  71. if (data.vertex_buffer)
  72. data.vertex_buffer->Release();
  73. capture_free();
  74. if (data.using_shtex) {
  75. if (data.texture)
  76. data.texture->Release();
  77. if (data.render_target)
  78. data.render_target->Release();
  79. } else {
  80. for (size_t i = 0; i < NUM_BUFFERS; i++) {
  81. if (data.copy_surfaces[i]) {
  82. if (data.texture_mapped[i])
  83. data.context->Unmap(
  84. data.copy_surfaces[i],
  85. 0);
  86. data.copy_surfaces[i]->Release();
  87. }
  88. if (data.textures[i])
  89. data.textures[i]->Release();
  90. if (data.render_targets[i])
  91. data.render_targets[i]->Release();
  92. }
  93. }
  94. memset(&data, 0, sizeof(data));
  95. hlog("----------------- d3d11 capture freed ----------------");
  96. }
  97. static bool create_d3d11_stage_surface(ID3D11Texture2D **tex)
  98. {
  99. HRESULT hr;
  100. D3D11_TEXTURE2D_DESC desc = {};
  101. desc.Width = data.cx;
  102. desc.Height = data.cy;
  103. desc.Format = data.format;
  104. desc.MipLevels = 1;
  105. desc.ArraySize = 1;
  106. desc.SampleDesc.Count = 1;
  107. desc.Usage = D3D11_USAGE_STAGING;
  108. desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
  109. hr = data.device->CreateTexture2D(&desc, nullptr, tex);
  110. if (FAILED(hr)) {
  111. hlog_hr("create_d3d11_stage_surface: failed to create texture",
  112. hr);
  113. return false;
  114. }
  115. return true;
  116. }
  117. static bool create_d3d11_tex(uint32_t cx, uint32_t cy,
  118. ID3D11Texture2D **tex,
  119. ID3D11ShaderResourceView **resource,
  120. ID3D11RenderTargetView **render_target,
  121. HANDLE *handle)
  122. {
  123. UINT flags = 0;
  124. UINT misc_flags = 0;
  125. HRESULT hr;
  126. if (!!resource)
  127. flags |= D3D11_BIND_SHADER_RESOURCE;
  128. if (!!render_target)
  129. flags |= D3D11_BIND_RENDER_TARGET;
  130. if (!!handle)
  131. misc_flags |= D3D11_RESOURCE_MISC_SHARED;
  132. D3D11_TEXTURE2D_DESC desc = {};
  133. desc.Width = cx;
  134. desc.Height = cy;
  135. desc.MipLevels = 1;
  136. desc.ArraySize = 1;
  137. desc.Format = data.format;
  138. desc.BindFlags = flags;
  139. desc.SampleDesc.Count = 1;
  140. desc.Usage = D3D11_USAGE_DEFAULT;
  141. desc.MiscFlags = misc_flags;
  142. hr = data.device->CreateTexture2D(&desc, nullptr, tex);
  143. if (FAILED(hr)) {
  144. hlog_hr("create_d3d11_tex: failed to create texture", hr);
  145. return false;
  146. }
  147. if (!!resource) {
  148. D3D11_SHADER_RESOURCE_VIEW_DESC res_desc = {};
  149. res_desc.Format = data.format;
  150. res_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
  151. res_desc.Texture2D.MipLevels = 1;
  152. hr = data.device->CreateShaderResourceView(*tex, &res_desc,
  153. resource);
  154. if (FAILED(hr)) {
  155. hlog_hr("create_d3d11_tex: failed to create resource "
  156. "view", hr);
  157. return false;
  158. }
  159. }
  160. if (!!render_target) {
  161. hr = data.device->CreateRenderTargetView(*tex, nullptr,
  162. render_target);
  163. if (FAILED(hr)) {
  164. hlog_hr("create_d3d11_tex: failed to create render "
  165. "target view", hr);
  166. return false;
  167. }
  168. }
  169. if (!!handle) {
  170. IDXGIResource *dxgi_res;
  171. hr = (*tex)->QueryInterface(__uuidof(IDXGIResource),
  172. (void**)&dxgi_res);
  173. if (FAILED(hr)) {
  174. hlog_hr("create_d3d11_tex: failed to query "
  175. "IDXGIResource interface from texture", hr);
  176. return false;
  177. }
  178. hr = dxgi_res->GetSharedHandle(handle);
  179. dxgi_res->Release();
  180. if (FAILED(hr)) {
  181. hlog_hr("create_d3d11_tex: failed to get shared handle",
  182. hr);
  183. return false;
  184. }
  185. }
  186. return true;
  187. }
  188. static inline bool d3d11_init_format(IDXGISwapChain *swap, HWND &window)
  189. {
  190. DXGI_SWAP_CHAIN_DESC desc;
  191. HRESULT hr;
  192. hr = swap->GetDesc(&desc);
  193. if (FAILED(hr)) {
  194. hlog_hr("d3d11_init_format: swap->GetDesc failed", hr);
  195. return false;
  196. }
  197. data.format = fix_dxgi_format(desc.BufferDesc.Format);
  198. data.multisampled = desc.SampleDesc.Count > 1;
  199. window = desc.OutputWindow;
  200. data.base_cx = desc.BufferDesc.Width;
  201. data.base_cy = desc.BufferDesc.Height;
  202. if (data.using_scale) {
  203. data.cx = global_hook_info->cx;
  204. data.cy = global_hook_info->cy;
  205. } else {
  206. data.cx = desc.BufferDesc.Width;
  207. data.cy = desc.BufferDesc.Height;
  208. }
  209. return true;
  210. }
  211. static inline bool d3d11_init_vertex_shader(void)
  212. {
  213. D3D11_INPUT_ELEMENT_DESC desc[2];
  214. uint8_t *vs_data;
  215. size_t size;
  216. HRESULT hr;
  217. vs_data = get_d3d1x_vertex_shader(&size);
  218. hr = data.device->CreateVertexShader(vs_data, size, nullptr,
  219. &data.vertex_shader);
  220. if (FAILED(hr)) {
  221. hlog_hr("d3d11_init_vertex_shader: failed to create shader",
  222. hr);
  223. return false;
  224. }
  225. desc[0].SemanticName = "SV_Position";
  226. desc[0].SemanticIndex = 0;
  227. desc[0].Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
  228. desc[0].InputSlot = 0;
  229. desc[0].AlignedByteOffset = 0;
  230. desc[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
  231. desc[0].InstanceDataStepRate = 0;
  232. desc[1].SemanticName = "TEXCOORD";
  233. desc[1].SemanticIndex = 0;
  234. desc[1].Format = DXGI_FORMAT_R32G32_FLOAT;
  235. desc[1].InputSlot = 0;
  236. desc[1].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
  237. desc[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
  238. desc[1].InstanceDataStepRate = 0;
  239. hr = data.device->CreateInputLayout(desc, 2, vs_data, size,
  240. &data.vertex_layout);
  241. if (FAILED(hr)) {
  242. hlog_hr("d3d11_init_vertex_shader: failed to create layout",
  243. hr);
  244. return false;
  245. }
  246. return true;
  247. }
  248. static inline bool d3d11_init_pixel_shader(void)
  249. {
  250. uint8_t *ps_data;
  251. size_t size;
  252. HRESULT hr;
  253. ps_data = get_d3d1x_pixel_shader(&size);
  254. hr = data.device->CreatePixelShader(ps_data, size, nullptr,
  255. &data.pixel_shader);
  256. if (FAILED(hr)) {
  257. hlog_hr("d3d11_init_pixel_shader: failed to create shader", hr);
  258. return false;
  259. }
  260. return true;
  261. }
  262. static inline bool d3d11_init_sampler_state(void)
  263. {
  264. HRESULT hr;
  265. D3D11_SAMPLER_DESC desc = {};
  266. desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
  267. desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
  268. desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
  269. desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
  270. hr = data.device->CreateSamplerState(&desc, &data.sampler_state);
  271. if (FAILED(hr)) {
  272. hlog_hr("d3d11_init_sampler_state: failed to create sampler "
  273. "state", hr);
  274. return false;
  275. }
  276. return true;
  277. }
  278. static inline bool d3d11_init_blend_state(void)
  279. {
  280. D3D11_BLEND_DESC desc = {};
  281. HRESULT hr;
  282. for (size_t i = 0; i < 8; i++)
  283. desc.RenderTarget[i].RenderTargetWriteMask =
  284. D3D11_COLOR_WRITE_ENABLE_ALL;
  285. hr = data.device->CreateBlendState(&desc, &data.blend_state);
  286. if (FAILED(hr)) {
  287. hlog_hr("d3d11_init_blend_state: failed to create blend state",
  288. hr);
  289. return false;
  290. }
  291. return true;
  292. }
  293. static inline bool d3d11_init_zstencil_state(void)
  294. {
  295. D3D11_DEPTH_STENCIL_DESC desc = {}; /* defaults all to off */
  296. HRESULT hr;
  297. hr = data.device->CreateDepthStencilState(&desc, &data.zstencil_state);
  298. if (FAILED(hr)) {
  299. hlog_hr("d3d11_init_zstencil_state: failed to create "
  300. "zstencil state", hr);
  301. return false;
  302. }
  303. return true;
  304. }
  305. static inline bool d3d11_init_raster_state(void)
  306. {
  307. D3D11_RASTERIZER_DESC desc = {};
  308. HRESULT hr;
  309. desc.FillMode = D3D11_FILL_SOLID;
  310. desc.CullMode = D3D11_CULL_NONE;
  311. hr = data.device->CreateRasterizerState(&desc, &data.raster_state);
  312. if (FAILED(hr)) {
  313. hlog_hr("d3d11_init_raster_state: failed to create raster "
  314. "state", hr);
  315. return false;
  316. }
  317. return true;
  318. }
  319. #define NUM_VERTS 4
  320. static inline bool d3d11_init_vertex_buffer(void)
  321. {
  322. HRESULT hr;
  323. const vertex verts[NUM_VERTS] = {
  324. {{-1.0f, 1.0f, 0.0f, 1.0f}, {0.0f, 0.0f}},
  325. {{-1.0f, -1.0f, 0.0f, 1.0f}, {0.0f, 1.0f}},
  326. {{ 1.0f, 1.0f, 0.0f, 1.0f}, {1.0f, 0.0f}},
  327. {{ 1.0f, -1.0f, 0.0f, 1.0f}, {1.0f, 1.0f}}
  328. };
  329. D3D11_BUFFER_DESC desc;
  330. desc.ByteWidth = sizeof(vertex) * NUM_VERTS;
  331. desc.Usage = D3D11_USAGE_DEFAULT;
  332. desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
  333. desc.CPUAccessFlags = 0;
  334. desc.MiscFlags = 0;
  335. D3D11_SUBRESOURCE_DATA srd = {};
  336. srd.pSysMem = (const void*)verts;
  337. hr = data.device->CreateBuffer(&desc, &srd, &data.vertex_buffer);
  338. if (FAILED(hr)) {
  339. hlog_hr("d3d11_init_vertex_buffer: failed to create vertex "
  340. "buffer", hr);
  341. return false;
  342. }
  343. return true;
  344. }
  345. static bool d3d11_init_scaling(void)
  346. {
  347. bool success;
  348. success = create_d3d11_tex(data.base_cx, data.base_cy,
  349. &data.scale_tex, &data.scale_resource, nullptr,
  350. nullptr);
  351. if (!success) {
  352. hlog("d3d11_init_scaling: failed to create scale texture");
  353. return false;
  354. }
  355. if (!d3d11_init_vertex_shader()) {
  356. return false;
  357. }
  358. if (!d3d11_init_pixel_shader()) {
  359. return false;
  360. }
  361. if (!d3d11_init_sampler_state()) {
  362. return false;
  363. }
  364. if (!d3d11_init_blend_state()) {
  365. return false;
  366. }
  367. if (!d3d11_init_zstencil_state()) {
  368. return false;
  369. }
  370. if (!d3d11_init_raster_state()) {
  371. return false;
  372. }
  373. if (!d3d11_init_vertex_buffer()) {
  374. return false;
  375. }
  376. return true;
  377. }
  378. static bool d3d11_shmem_init_buffers(size_t idx)
  379. {
  380. bool success;
  381. success = create_d3d11_stage_surface(&data.copy_surfaces[idx]);
  382. if (!success) {
  383. hlog("d3d11_shmem_init_buffers: failed to create copy surface");
  384. return false;
  385. }
  386. if (idx == 0) {
  387. D3D11_MAPPED_SUBRESOURCE map = {};
  388. HRESULT hr;
  389. hr = data.context->Map(data.copy_surfaces[idx], 0,
  390. D3D11_MAP_READ, 0, &map);
  391. if (FAILED(hr)) {
  392. hlog_hr("d3d11_shmem_init_buffers: failed to get "
  393. "pitch", hr);
  394. return false;
  395. }
  396. data.pitch = map.RowPitch;
  397. data.context->Unmap(data.copy_surfaces[idx], 0);
  398. }
  399. success = create_d3d11_tex(data.cx, data.cy, &data.textures[idx],
  400. nullptr, &data.render_targets[idx], nullptr);
  401. if (!success) {
  402. hlog("d3d11_shmem_init_buffers: failed to create texture");
  403. return false;
  404. }
  405. return true;
  406. }
  407. static bool d3d11_shmem_init(HWND window)
  408. {
  409. data.using_shtex = false;
  410. for (size_t i = 0; i < NUM_BUFFERS; i++) {
  411. if (!d3d11_shmem_init_buffers(i)) {
  412. return false;
  413. }
  414. }
  415. if (!capture_init_shmem(&data.shmem_info, window,
  416. data.base_cx, data.base_cy, data.cx, data.cy,
  417. data.pitch, data.format, false)) {
  418. return false;
  419. }
  420. hlog("d3d11 memory capture successful");
  421. return true;
  422. }
  423. static bool d3d11_shtex_init(HWND window)
  424. {
  425. ID3D11ShaderResourceView *resource = nullptr;
  426. bool success;
  427. data.using_shtex = true;
  428. success = create_d3d11_tex(data.cx, data.cy, &data.texture, &resource,
  429. &data.render_target, &data.handle);
  430. if (resource)
  431. resource->Release();
  432. if (!success) {
  433. hlog("d3d11_shtex_init: failed to create texture");
  434. return false;
  435. }
  436. if (!capture_init_shtex(&data.shtex_info, window,
  437. data.base_cx, data.base_cy, data.cx, data.cy,
  438. data.format, false, (uintptr_t)data.handle)) {
  439. return false;
  440. }
  441. hlog("d3d11 shared texture capture successful");
  442. return true;
  443. }
  444. static void d3d11_init(IDXGISwapChain *swap)
  445. {
  446. bool success = true;
  447. HWND window;
  448. HRESULT hr;
  449. data.using_scale = global_hook_info->use_scale;
  450. hr = swap->GetDevice(__uuidof(ID3D11Device), (void**)&data.device);
  451. if (FAILED(hr)) {
  452. hlog_hr("d3d11_init: failed to get device from swap", hr);
  453. return;
  454. }
  455. data.device->Release();
  456. data.device->GetImmediateContext(&data.context);
  457. data.context->Release();
  458. if (!d3d11_init_format(swap, window)) {
  459. return;
  460. }
  461. if (data.using_scale && !d3d11_init_scaling()) {
  462. hlog("d3d11_init: failed to initialize scaling");
  463. success = false;
  464. }
  465. if (success) {
  466. if (global_hook_info->force_shmem) {
  467. success = d3d11_shmem_init(window);
  468. } else {
  469. success = d3d11_shtex_init(window);
  470. }
  471. }
  472. if (!success)
  473. d3d11_free();
  474. }
  475. #define MAX_RENDER_TARGETS D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT
  476. #define MAX_SO_TARGETS 4
  477. #define MAX_CLASS_INSTS 256
  478. struct d3d11_state {
  479. ID3D11GeometryShader *geom_shader;
  480. ID3D11InputLayout *vertex_layout;
  481. D3D11_PRIMITIVE_TOPOLOGY topology;
  482. ID3D11Buffer *vertex_buffer;
  483. UINT vb_stride;
  484. UINT vb_offset;
  485. ID3D11BlendState *blend_state;
  486. float blend_factor[4];
  487. UINT sample_mask;
  488. ID3D11DepthStencilState *zstencil_state;
  489. UINT zstencil_ref;
  490. ID3D11RenderTargetView *render_targets[MAX_RENDER_TARGETS];
  491. ID3D11DepthStencilView *zstencil_view;
  492. ID3D11SamplerState *sampler_state;
  493. ID3D11PixelShader *pixel_shader;
  494. ID3D11ShaderResourceView *resource;
  495. ID3D11RasterizerState *raster_state;
  496. UINT num_viewports;
  497. D3D11_VIEWPORT *viewports;
  498. ID3D11Buffer *stream_output_targets[MAX_SO_TARGETS];
  499. ID3D11VertexShader *vertex_shader;
  500. ID3D11ClassInstance *gs_class_instances[MAX_CLASS_INSTS];
  501. ID3D11ClassInstance *ps_class_instances[MAX_CLASS_INSTS];
  502. ID3D11ClassInstance *vs_class_instances[MAX_CLASS_INSTS];
  503. UINT gs_class_inst_count;
  504. UINT ps_class_inst_count;
  505. UINT vs_class_inst_count;
  506. };
  507. static inline void d3d11_save_state(struct d3d11_state *state)
  508. {
  509. state->gs_class_inst_count = MAX_CLASS_INSTS;
  510. state->ps_class_inst_count = MAX_CLASS_INSTS;
  511. state->vs_class_inst_count = MAX_CLASS_INSTS;
  512. data.context->GSGetShader(&state->geom_shader,
  513. state->gs_class_instances,
  514. &state->gs_class_inst_count);
  515. data.context->IAGetInputLayout(&state->vertex_layout);
  516. data.context->IAGetPrimitiveTopology(&state->topology);
  517. data.context->IAGetVertexBuffers(0, 1, &state->vertex_buffer,
  518. &state->vb_stride, &state->vb_offset);
  519. data.context->OMGetBlendState(&state->blend_state, state->blend_factor,
  520. &state->sample_mask);
  521. data.context->OMGetDepthStencilState(&state->zstencil_state,
  522. &state->zstencil_ref);
  523. data.context->OMGetRenderTargets(MAX_RENDER_TARGETS,
  524. state->render_targets, &state->zstencil_view);
  525. data.context->PSGetSamplers(0, 1, &state->sampler_state);
  526. data.context->PSGetShader(&state->pixel_shader,
  527. state->ps_class_instances,
  528. &state->ps_class_inst_count);
  529. data.context->PSGetShaderResources(0, 1, &state->resource);
  530. data.context->RSGetState(&state->raster_state);
  531. data.context->RSGetViewports(&state->num_viewports, nullptr);
  532. if (state->num_viewports) {
  533. state->viewports = (D3D11_VIEWPORT*)malloc(
  534. sizeof(D3D11_VIEWPORT) * state->num_viewports);
  535. data.context->RSGetViewports(&state->num_viewports,
  536. state->viewports);
  537. }
  538. data.context->SOGetTargets(MAX_SO_TARGETS,
  539. state->stream_output_targets);
  540. data.context->VSGetShader(&state->vertex_shader,
  541. state->vs_class_instances,
  542. &state->vs_class_inst_count);
  543. }
  544. static inline void safe_release(IUnknown *p)
  545. {
  546. if (p) p->Release();
  547. }
  548. #define SO_APPEND ((UINT)-1)
  549. static inline void d3d11_restore_state(struct d3d11_state *state)
  550. {
  551. UINT so_offsets[MAX_SO_TARGETS] =
  552. {SO_APPEND, SO_APPEND, SO_APPEND, SO_APPEND};
  553. data.context->GSSetShader(state->geom_shader,
  554. state->gs_class_instances,
  555. state->gs_class_inst_count);
  556. data.context->IASetInputLayout(state->vertex_layout);
  557. data.context->IASetPrimitiveTopology(state->topology);
  558. data.context->IASetVertexBuffers(0, 1, &state->vertex_buffer,
  559. &state->vb_stride, &state->vb_offset);
  560. data.context->OMSetBlendState(state->blend_state, state->blend_factor,
  561. state->sample_mask);
  562. data.context->OMSetDepthStencilState(state->zstencil_state,
  563. state->zstencil_ref);
  564. data.context->OMSetRenderTargets(MAX_RENDER_TARGETS,
  565. state->render_targets,
  566. state->zstencil_view);
  567. data.context->PSSetSamplers(0, 1, &state->sampler_state);
  568. data.context->PSSetShader(state->pixel_shader,
  569. state->ps_class_instances,
  570. state->ps_class_inst_count);
  571. data.context->PSSetShaderResources(0, 1, &state->resource);
  572. data.context->RSSetState(state->raster_state);
  573. data.context->RSSetViewports(state->num_viewports, state->viewports);
  574. data.context->SOSetTargets(MAX_SO_TARGETS,
  575. state->stream_output_targets, so_offsets);
  576. data.context->VSSetShader(state->vertex_shader,
  577. state->vs_class_instances,
  578. state->vs_class_inst_count);
  579. safe_release(state->geom_shader);
  580. safe_release(state->vertex_layout);
  581. safe_release(state->vertex_buffer);
  582. safe_release(state->blend_state);
  583. safe_release(state->zstencil_state);
  584. for (size_t i = 0; i < MAX_RENDER_TARGETS; i++)
  585. safe_release(state->render_targets[i]);
  586. safe_release(state->zstencil_view);
  587. safe_release(state->sampler_state);
  588. safe_release(state->pixel_shader);
  589. safe_release(state->resource);
  590. safe_release(state->raster_state);
  591. for (size_t i = 0; i < MAX_SO_TARGETS; i++)
  592. safe_release(state->stream_output_targets[i]);
  593. safe_release(state->vertex_shader);
  594. for (size_t i = 0; i < state->gs_class_inst_count; i++)
  595. state->gs_class_instances[i]->Release();
  596. for (size_t i = 0; i < state->ps_class_inst_count; i++)
  597. state->ps_class_instances[i]->Release();
  598. for (size_t i = 0; i < state->vs_class_inst_count; i++)
  599. state->vs_class_instances[i]->Release();
  600. free(state->viewports);
  601. memset(state, 0, sizeof(*state));
  602. }
  603. static inline void d3d11_setup_pipeline(ID3D11RenderTargetView *target,
  604. ID3D11ShaderResourceView *resource)
  605. {
  606. const float factor[4] = {1.0f, 1.0f, 1.0f, 1.0f};
  607. D3D11_VIEWPORT viewport = {0};
  608. UINT stride = sizeof(vertex);
  609. void *emptyptr = nullptr;
  610. UINT zero = 0;
  611. viewport.Width = (float)data.cx;
  612. viewport.Height = (float)data.cy;
  613. viewport.MaxDepth = 1.0f;
  614. data.context->GSSetShader(nullptr, nullptr, 0);
  615. data.context->IASetInputLayout(data.vertex_layout);
  616. data.context->IASetPrimitiveTopology(
  617. D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
  618. data.context->IASetVertexBuffers(0, 1, &data.vertex_buffer, &stride,
  619. &zero);
  620. data.context->OMSetBlendState(data.blend_state, factor, 0xFFFFFFFF);
  621. data.context->OMSetDepthStencilState(data.zstencil_state, 0);
  622. data.context->OMSetRenderTargets(1, &target, nullptr);
  623. data.context->PSSetSamplers(0, 1, &data.sampler_state);
  624. data.context->PSSetShader(data.pixel_shader, nullptr, 0);
  625. data.context->PSSetShaderResources(0, 1, &resource);
  626. data.context->RSSetState(data.raster_state);
  627. data.context->RSSetViewports(1, &viewport);
  628. data.context->SOSetTargets(1, (ID3D11Buffer**)&emptyptr, &zero);
  629. data.context->VSSetShader(data.vertex_shader, nullptr, 0);
  630. }
  631. static inline void d3d11_scale_texture(ID3D11RenderTargetView *target,
  632. ID3D11ShaderResourceView *resource)
  633. {
  634. static struct d3d11_state old_state = {0};
  635. d3d11_save_state(&old_state);
  636. d3d11_setup_pipeline(target, resource);
  637. data.context->Draw(4, 0);
  638. d3d11_restore_state(&old_state);
  639. }
  640. static inline void d3d11_copy_texture(ID3D11Resource *dst, ID3D11Resource *src)
  641. {
  642. if (data.multisampled) {
  643. data.context->ResolveSubresource(dst, 0, src, 0, data.format);
  644. } else {
  645. data.context->CopyResource(dst, src);
  646. }
  647. }
  648. static inline void d3d11_shtex_capture(ID3D11Resource *backbuffer)
  649. {
  650. if (data.using_scale) {
  651. d3d11_copy_texture(data.scale_tex, backbuffer);
  652. d3d11_scale_texture(data.render_target, data.scale_resource);
  653. } else {
  654. d3d11_copy_texture(data.texture, backbuffer);
  655. }
  656. }
  657. static inline void d3d11_shmem_queue_copy()
  658. {
  659. for (size_t i = 0; i < NUM_BUFFERS; i++) {
  660. D3D11_MAPPED_SUBRESOURCE map;
  661. HRESULT hr;
  662. if (data.texture_ready[i]) {
  663. data.texture_ready[i] = false;
  664. hr = data.context->Map(data.copy_surfaces[i], 0,
  665. D3D11_MAP_READ, 0, &map);
  666. if (SUCCEEDED(hr)) {
  667. data.texture_mapped[i] = true;
  668. shmem_copy_data(i, map.pData);
  669. }
  670. break;
  671. }
  672. }
  673. }
  674. static inline void d3d11_shmem_capture(ID3D11Resource *backbuffer)
  675. {
  676. int next_tex;
  677. d3d11_shmem_queue_copy();
  678. next_tex = (data.cur_tex == NUM_BUFFERS - 1) ? 0 : data.cur_tex + 1;
  679. if (data.using_scale) {
  680. d3d11_copy_texture(data.scale_tex, backbuffer);
  681. d3d11_scale_texture(data.render_targets[data.cur_tex],
  682. data.scale_resource);
  683. } else {
  684. d3d11_copy_texture(data.textures[data.cur_tex], backbuffer);
  685. }
  686. if (data.copy_wait < NUM_BUFFERS - 1) {
  687. data.copy_wait++;
  688. } else {
  689. ID3D11Texture2D *src = data.textures[next_tex];
  690. ID3D11Texture2D *dst = data.copy_surfaces[next_tex];
  691. if (shmem_texture_data_lock(next_tex)) {
  692. data.context->Unmap(dst, 0);
  693. data.texture_mapped[next_tex] = false;
  694. shmem_texture_data_unlock(next_tex);
  695. }
  696. d3d11_copy_texture(dst, src);
  697. data.texture_ready[next_tex] = true;
  698. }
  699. data.cur_tex = next_tex;
  700. }
  701. void d3d11_capture(void *swap_ptr, void *backbuffer_ptr)
  702. {
  703. IDXGIResource *dxgi_backbuffer = (IDXGIResource*)backbuffer_ptr;
  704. IDXGISwapChain *swap = (IDXGISwapChain*)swap_ptr;
  705. HRESULT hr;
  706. if (capture_should_stop()) {
  707. d3d11_free();
  708. }
  709. if (capture_should_init()) {
  710. d3d11_init(swap);
  711. }
  712. if (capture_ready()) {
  713. ID3D11Resource *backbuffer;
  714. hr = dxgi_backbuffer->QueryInterface(__uuidof(ID3D11Resource),
  715. (void**)&backbuffer);
  716. if (FAILED(hr)) {
  717. hlog_hr("d3d11_shtex_capture: failed to get "
  718. "backbuffer", hr);
  719. return;
  720. }
  721. if (data.using_shtex)
  722. d3d11_shtex_capture(backbuffer);
  723. else
  724. d3d11_shmem_capture(backbuffer);
  725. backbuffer->Release();
  726. }
  727. }