From 3b5a30ce97cc8cbe38222081c9c65dc77f571fb2 Mon Sep 17 00:00:00 2001 From: jp9000 Date: Fri, 23 Dec 2016 01:45:31 -0800 Subject: [PATCH] win-capture: Capture all D3D12 backbuffers D3D12 capture does not take in to account when multiple backbuffers are in used. With previous versions of Direct3D there was no need to do this, but with D3D12 you must explicitly capture each specific backbuffer currently in use. --- .../graphics-hook/d3d10-capture.cpp | 2 +- .../graphics-hook/d3d11-capture.cpp | 2 +- .../graphics-hook/d3d12-capture.cpp | 142 +++++++++++++----- .../graphics-hook/dxgi-capture.cpp | 6 +- .../win-capture/graphics-hook/graphics-hook.h | 6 +- 5 files changed, 112 insertions(+), 46 deletions(-) diff --git a/plugins/win-capture/graphics-hook/d3d10-capture.cpp b/plugins/win-capture/graphics-hook/d3d10-capture.cpp index e7a3e0a2a..9f62ff9e1 100644 --- a/plugins/win-capture/graphics-hook/d3d10-capture.cpp +++ b/plugins/win-capture/graphics-hook/d3d10-capture.cpp @@ -771,7 +771,7 @@ static inline void d3d10_shmem_capture(ID3D10Resource *backbuffer) data.cur_tex = next_tex; } -void d3d10_capture(void *swap_ptr, void *backbuffer_ptr) +void d3d10_capture(void *swap_ptr, void *backbuffer_ptr, bool) { IDXGIResource *dxgi_backbuffer = (IDXGIResource*)backbuffer_ptr; IDXGISwapChain *swap = (IDXGISwapChain*)swap_ptr; diff --git a/plugins/win-capture/graphics-hook/d3d11-capture.cpp b/plugins/win-capture/graphics-hook/d3d11-capture.cpp index 7ebe3a558..ee0d7e162 100644 --- a/plugins/win-capture/graphics-hook/d3d11-capture.cpp +++ b/plugins/win-capture/graphics-hook/d3d11-capture.cpp @@ -813,7 +813,7 @@ static inline void d3d11_shmem_capture(ID3D11Resource *backbuffer) data.cur_tex = next_tex; } -void d3d11_capture(void *swap_ptr, void *backbuffer_ptr) +void d3d11_capture(void *swap_ptr, void *backbuffer_ptr, bool) { IDXGIResource *dxgi_backbuffer = (IDXGIResource*)backbuffer_ptr; IDXGISwapChain *swap = (IDXGISwapChain*)swap_ptr; diff --git a/plugins/win-capture/graphics-hook/d3d12-capture.cpp b/plugins/win-capture/graphics-hook/d3d12-capture.cpp index 6999b3ec4..01c31b32f 100644 --- a/plugins/win-capture/graphics-hook/d3d12-capture.cpp +++ b/plugins/win-capture/graphics-hook/d3d12-capture.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include #include "dxgi-helpers.hpp" #include "../funchook.h" @@ -20,6 +20,7 @@ struct d3d12_data { bool using_shtex : 1; bool using_scale : 1; bool multisampled : 1; + bool dxgi_1_4 : 1; ID3D11Device *device11; ID3D11DeviceContext *context11; @@ -28,7 +29,9 @@ struct d3d12_data { union { struct { struct shtex_data *shtex_info; - ID3D11Resource *backbuffer11; + ID3D11Resource *backbuffer11[3]; + UINT backbuffer_count; + UINT cur_backbuffer; ID3D11Texture2D *copy_tex; HANDLE handle; }; @@ -41,8 +44,10 @@ void d3d12_free(void) { if (data.copy_tex) data.copy_tex->Release(); - if (data.backbuffer11) - data.backbuffer11->Release(); + for (size_t i = 0; i < data.backbuffer_count; i++) { + if (data.backbuffer11[i]) + data.backbuffer11[i]->Release(); + } if (data.device11) data.device11->Release(); if (data.context11) @@ -57,20 +62,35 @@ void d3d12_free(void) hlog("----------------- d3d12 capture freed ----------------"); } -static bool create_d3d12_tex(ID3D12Resource *backbuffer) +static bool create_d3d12_tex(ID3D12Resource *backbuffer[3], UINT count) { D3D11_RESOURCE_FLAGS rf11 = {}; HRESULT hr; - hr = data.device11on12->CreateWrappedResource(backbuffer, &rf11, - D3D12_RESOURCE_STATE_COPY_SOURCE, - D3D12_RESOURCE_STATE_PRESENT, - __uuidof(ID3D11Resource), - (void**)&data.backbuffer11); - if (FAILED(hr)) { - hlog_hr("create_d3d12_tex: failed to create backbuffer11", - hr); + if (!count) return false; + + if (count > 3) { + hlog("Somehow it's using more than 3 backbuffers. " + "Not sure why anyone would do that."); + count = 3; + } + + data.backbuffer_count = count; + + for (UINT i = 0; i < count; i++) { + hr = data.device11on12->CreateWrappedResource( + backbuffer[i], + &rf11, + D3D12_RESOURCE_STATE_COPY_SOURCE, + D3D12_RESOURCE_STATE_PRESENT, + __uuidof(ID3D11Resource), + (void**)&data.backbuffer11[i]); + if (FAILED(hr)) { + hlog_hr("create_d3d12_tex: failed to create " + "backbuffer11", hr); + return false; + } } D3D11_TEXTURE2D_DESC desc11 = {}; @@ -90,7 +110,10 @@ static bool create_d3d12_tex(ID3D12Resource *backbuffer) return false; } - data.device11on12->ReleaseWrappedResources(&data.backbuffer11, 1); + for (UINT i = 0; i < count; i++) { + data.device11on12->ReleaseWrappedResources( + &data.backbuffer11[i], 1); + } IDXGIResource *dxgi_res; hr = data.copy_tex->QueryInterface(__uuidof(IDXGIResource), @@ -174,12 +197,13 @@ static bool d3d12_init_11on12(void) return true; } -static bool d3d12_shtex_init(HWND window, ID3D12Resource *backbuffer) +static bool d3d12_shtex_init(HWND window, ID3D12Resource *backbuffer[3], + UINT count) { if (!d3d12_init_11on12()) { return false; } - if (!create_d3d12_tex(backbuffer)) { + if (!create_d3d12_tex(backbuffer, count)) { return false; } if (!capture_init_shtex(&data.shtex_info, window, @@ -192,10 +216,13 @@ static bool d3d12_shtex_init(HWND window, ID3D12Resource *backbuffer) return true; } -static inline bool d3d12_init_format(IDXGISwapChain *swap, HWND &window) +static inline bool d3d12_init_format(IDXGISwapChain *swap, HWND &window, + ID3D12Resource *backbuffer[3], UINT *p_count) { DXGI_SWAP_CHAIN_DESC desc; + IDXGISwapChain3 *swap3; HRESULT hr; + UINT count; hr = swap->GetDesc(&desc); if (FAILED(hr)) { @@ -209,6 +236,31 @@ static inline bool d3d12_init_format(IDXGISwapChain *swap, HWND &window) data.base_cx = desc.BufferDesc.Width; data.base_cy = desc.BufferDesc.Height; + hr = swap->QueryInterface(__uuidof(IDXGISwapChain3), (void**)&swap3); + if (SUCCEEDED(hr)) { + data.dxgi_1_4 = true; + hlog("We're DXGI1.4 boys!"); + swap3->Release(); + } + + count = desc.SwapEffect == DXGI_SWAP_EFFECT_DISCARD + ? 1 : desc.BufferCount; + + for (UINT i = 0; i < count; i++) { + hr = swap->GetBuffer(i, __uuidof(ID3D12Resource), + (void**)&backbuffer[i]); + if (FAILED(hr)) { + if (i > 0) { + for (UINT j = 0; j < i; j++) { + backbuffer[j]->Release(); + } + } + return false; + } + } + + *p_count = count; + if (data.using_scale) { data.cx = global_hook_info->cx; data.cy = global_hook_info->cy; @@ -219,11 +271,13 @@ static inline bool d3d12_init_format(IDXGISwapChain *swap, HWND &window) return true; } -static void d3d12_init(IDXGISwapChain *swap, ID3D12Resource *backbuffer) +static void d3d12_init(IDXGISwapChain *swap) { + ID3D12Resource *backbuffer[3]; bool success = true; HWND window; HRESULT hr; + UINT count; data.using_scale = global_hook_info->use_scale; @@ -235,7 +289,7 @@ static void d3d12_init(IDXGISwapChain *swap, ID3D12Resource *backbuffer) data.device->Release(); - if (!d3d12_init_format(swap, window)) { + if (!d3d12_init_format(swap, window, backbuffer, &count)) { return; } if (data.using_scale) { @@ -247,7 +301,7 @@ static void d3d12_init(IDXGISwapChain *swap, ID3D12Resource *backbuffer) "unsupported; ignoring"); } - success = d3d12_shtex_init(window, backbuffer); + success = d3d12_shtex_init(window, backbuffer, count); } if (!success) @@ -263,37 +317,49 @@ static inline void d3d12_copy_texture(ID3D11Resource *dst, ID3D11Resource *src) } } -static inline void d3d12_shtex_capture() +static inline void d3d12_shtex_capture(IDXGISwapChain *swap, + bool capture_overlay) { - data.device11on12->AcquireWrappedResources(&data.backbuffer11, 1); - d3d12_copy_texture(data.copy_tex, data.backbuffer11); - data.device11on12->ReleaseWrappedResources(&data.backbuffer11, 1); + bool dxgi_1_4 = data.dxgi_1_4; + UINT cur_idx; + + if (dxgi_1_4) { + IDXGISwapChain3 *swap3 = + reinterpret_cast(swap); + cur_idx = swap3->GetCurrentBackBufferIndex(); + if (!capture_overlay) { + if (++cur_idx >= data.backbuffer_count) + cur_idx = 0; + } + } else { + cur_idx = data.cur_backbuffer; + } + + ID3D11Resource *backbuffer = data.backbuffer11[cur_idx]; + + data.device11on12->AcquireWrappedResources(&backbuffer, 1); + d3d12_copy_texture(data.copy_tex, backbuffer); + data.device11on12->ReleaseWrappedResources(&backbuffer, 1); data.context11->Flush(); + + if (!dxgi_1_4) { + if (++data.cur_backbuffer >= data.backbuffer_count) + data.cur_backbuffer = 0; + } } -void d3d12_capture(void *swap_ptr, void *backbuffer_ptr) +void d3d12_capture(void *swap_ptr, void*, bool capture_overlay) { - IUnknown *unk_backbuffer = (IUnknown*)backbuffer_ptr; IDXGISwapChain *swap = (IDXGISwapChain*)swap_ptr; - ID3D12Resource *backbuffer; - HRESULT hr; if (capture_should_stop()) { d3d12_free(); } if (capture_should_init()) { - hr = unk_backbuffer->QueryInterface(__uuidof(ID3D12Resource), - (void**)&backbuffer); - if (FAILED(hr)) { - hlog_hr("d3d12_capture: failed to get backbuffer", hr); - return; - } - - d3d12_init(swap, backbuffer); - backbuffer->Release(); + d3d12_init(swap); } if (capture_ready()) { - d3d12_shtex_capture(); + d3d12_shtex_capture(swap, capture_overlay); } } diff --git a/plugins/win-capture/graphics-hook/dxgi-capture.cpp b/plugins/win-capture/graphics-hook/dxgi-capture.cpp index c9891a56c..9cdea1b82 100644 --- a/plugins/win-capture/graphics-hook/dxgi-capture.cpp +++ b/plugins/win-capture/graphics-hook/dxgi-capture.cpp @@ -20,7 +20,7 @@ static struct func_hook present; struct dxgi_swap_data { IDXGISwapChain *swap; - void (*capture)(void*, void*); + void (*capture)(void*, void*, bool); void (*free)(void); }; @@ -131,7 +131,7 @@ static HRESULT STDMETHODCALLTYPE hook_present(IDXGISwapChain *swap, backbuffer = get_dxgi_backbuffer(swap); if (!!backbuffer) { - data.capture(swap, backbuffer); + data.capture(swap, backbuffer, capture_overlay); backbuffer->Release(); } } @@ -155,7 +155,7 @@ static HRESULT STDMETHODCALLTYPE hook_present(IDXGISwapChain *swap, backbuffer = get_dxgi_backbuffer(swap); if (!!backbuffer) { - data.capture(swap, backbuffer); + data.capture(swap, backbuffer, capture_overlay); backbuffer->Release(); } } diff --git a/plugins/win-capture/graphics-hook/graphics-hook.h b/plugins/win-capture/graphics-hook/graphics-hook.h index c9cd6c6d4..8baa76249 100644 --- a/plugins/win-capture/graphics-hook/graphics-hook.h +++ b/plugins/win-capture/graphics-hook/graphics-hook.h @@ -43,13 +43,13 @@ extern bool hook_d3d9(void); extern bool hook_dxgi(void); extern bool hook_gl(void); -extern void d3d10_capture(void *swap, void *backbuffer); +extern void d3d10_capture(void *swap, void *backbuffer, bool capture_overlay); extern void d3d10_free(void); -extern void d3d11_capture(void *swap, void *backbuffer); +extern void d3d11_capture(void *swap, void *backbuffer, bool capture_overlay); extern void d3d11_free(void); #if COMPILE_D3D12_HOOK -extern void d3d12_capture(void *swap, void *backbuffer); +extern void d3d12_capture(void *swap, void *backbuffer, bool capture_overlay); extern void d3d12_free(void); #endif -- GitLab