d3d10-capture.cpp 21 KB

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