d3d10-capture.cpp 20 KB

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