graphics-hook: Fix DXGI ref leak for D3D12 capture

Create ID3D11Resource dynamically to avoid reference inflation.
This commit is contained in:
jpark37 2023-11-27 21:39:19 -08:00 committed by Lain
parent 04788d30e2
commit ea9df85512

View File

@ -34,7 +34,6 @@ struct d3d12_data {
union { union {
struct { struct {
struct shtex_data *shtex_info; struct shtex_data *shtex_info;
ID3D11Resource *backbuffer11[MAX_BACKBUFFERS];
UINT backbuffer_count; UINT backbuffer_count;
UINT cur_backbuffer; UINT cur_backbuffer;
ID3D11Texture2D *copy_tex; ID3D11Texture2D *copy_tex;
@ -54,10 +53,6 @@ void d3d12_free(void)
{ {
if (data.copy_tex) if (data.copy_tex)
data.copy_tex->Release(); data.copy_tex->Release();
for (size_t i = 0; i < data.backbuffer_count; i++) {
if (data.backbuffer11[i])
data.backbuffer11[i]->Release();
}
if (data.device11) if (data.device11)
data.device11->Release(); data.device11->Release();
if (data.context11) if (data.context11)
@ -72,33 +67,14 @@ void d3d12_free(void)
hlog("----------------- d3d12 capture freed ----------------"); hlog("----------------- d3d12 capture freed ----------------");
} }
struct bb_info { static bool create_d3d12_tex(UINT count)
ID3D12Resource *backbuffer[MAX_BACKBUFFERS];
UINT count;
};
static bool create_d3d12_tex(bb_info &bb)
{ {
D3D11_RESOURCE_FLAGS rf11 = {};
HRESULT hr; HRESULT hr;
if (!bb.count) if (count == 0)
return false; return false;
data.backbuffer_count = bb.count; data.backbuffer_count = count;
for (UINT i = 0; i < bb.count; i++) {
hr = data.device11on12->CreateWrappedResource(
bb.backbuffer[i], &rf11, D3D12_RESOURCE_STATE_PRESENT,
D3D12_RESOURCE_STATE_PRESENT,
IID_PPV_ARGS(&data.backbuffer11[i]));
if (FAILED(hr)) {
hlog_hr("create_d3d12_tex: failed to create "
"backbuffer11",
hr);
return false;
}
}
D3D11_TEXTURE2D_DESC desc11 = {}; D3D11_TEXTURE2D_DESC desc11 = {};
desc11.Width = data.cx; desc11.Width = data.cx;
@ -206,12 +182,12 @@ static bool d3d12_init_11on12(ID3D12Device *device)
return true; return true;
} }
static bool d3d12_shtex_init(ID3D12Device *device, HWND window, bb_info &bb) static bool d3d12_shtex_init(ID3D12Device *device, HWND window, UINT count)
{ {
if (!d3d12_init_11on12(device)) { if (!d3d12_init_11on12(device)) {
return false; return false;
} }
if (!create_d3d12_tex(bb)) { if (!create_d3d12_tex(count)) {
return false; return false;
} }
if (!capture_init_shtex(&data.shtex_info, window, data.cx, data.cy, if (!capture_init_shtex(&data.shtex_info, window, data.cx, data.cy,
@ -223,8 +199,7 @@ static bool d3d12_shtex_init(ID3D12Device *device, HWND window, bb_info &bb)
return true; return true;
} }
static inline bool d3d12_init_format(IDXGISwapChain *swap, HWND &window, static inline UINT d3d12_init_format(IDXGISwapChain *swap, HWND &window)
bb_info &bb)
{ {
DXGI_SWAP_CHAIN_DESC desc; DXGI_SWAP_CHAIN_DESC desc;
IDXGISwapChain3 *swap3; IDXGISwapChain3 *swap3;
@ -233,7 +208,7 @@ static inline bool d3d12_init_format(IDXGISwapChain *swap, HWND &window,
hr = swap->GetDesc(&desc); hr = swap->GetDesc(&desc);
if (FAILED(hr)) { if (FAILED(hr)) {
hlog_hr("d3d12_init_format: swap->GetDesc failed", hr); hlog_hr("d3d12_init_format: swap->GetDesc failed", hr);
return false; return 0;
} }
print_swap_desc(&desc); print_swap_desc(&desc);
@ -251,30 +226,21 @@ static inline bool d3d12_init_format(IDXGISwapChain *swap, HWND &window,
swap3->Release(); swap3->Release();
} }
bb.count = desc.SwapEffect == DXGI_SWAP_EFFECT_DISCARD UINT count = desc.SwapEffect == DXGI_SWAP_EFFECT_DISCARD
? 1 ? 1
: desc.BufferCount; : desc.BufferCount;
if (bb.count == 1) if (count == 1)
data.dxgi_1_4 = false; data.dxgi_1_4 = false;
if (bb.count > MAX_BACKBUFFERS) { if (count > MAX_BACKBUFFERS) {
hlog("Somehow it's using more than the max backbuffers. " hlog("Somehow it's using more than the max backbuffers. "
"Not sure why anyone would do that."); "Not sure why anyone would do that.");
bb.count = 1; count = 1;
data.dxgi_1_4 = false; data.dxgi_1_4 = false;
} }
for (UINT i = 0; i < bb.count; i++) { return count;
hr = swap->GetBuffer(i, IID_PPV_ARGS(&bb.backbuffer[i]));
if (SUCCEEDED(hr)) {
bb.backbuffer[i]->Release();
} else {
return false;
}
}
return true;
} }
static void d3d12_init(IDXGISwapChain *swap) static void d3d12_init(IDXGISwapChain *swap)
@ -286,14 +252,14 @@ static void d3d12_init(IDXGISwapChain *swap)
(uint64_t)(uintptr_t)device); (uint64_t)(uintptr_t)device);
HWND window; HWND window;
bb_info bb = {}; UINT count = d3d12_init_format(swap, window);
if (d3d12_init_format(swap, window, bb)) { if (count > 0) {
if (global_hook_info->force_shmem) { if (global_hook_info->force_shmem) {
hlog("d3d12_init: shared memory capture currently " hlog("d3d12_init: shared memory capture currently "
"unsupported; ignoring"); "unsupported; ignoring");
} }
if (!d3d12_shtex_init(device, window, bb)) if (!d3d12_shtex_init(device, window, count))
d3d12_free(); d3d12_free();
} }
@ -325,16 +291,31 @@ static inline void d3d12_shtex_capture(IDXGISwapChain *swap)
cur_idx = data.cur_backbuffer; cur_idx = data.cur_backbuffer;
} }
ID3D11Resource *backbuffer = data.backbuffer11[cur_idx]; ID3D12Resource *backbuffer12;
if (SUCCEEDED(swap->GetBuffer(cur_idx, IID_PPV_ARGS(&backbuffer12)))) {
D3D11_RESOURCE_FLAGS rf11 = {};
ID3D11Resource *backbuffer;
if (SUCCEEDED(data.device11on12->CreateWrappedResource(
backbuffer12, &rf11, D3D12_RESOURCE_STATE_PRESENT,
D3D12_RESOURCE_STATE_PRESENT,
IID_PPV_ARGS(&backbuffer)))) {
data.device11on12->AcquireWrappedResources(&backbuffer,
1);
d3d12_copy_texture(data.copy_tex, backbuffer);
data.device11on12->ReleaseWrappedResources(&backbuffer,
1);
data.context11->Flush();
data.device11on12->AcquireWrappedResources(&backbuffer, 1); if (!dxgi_1_4) {
d3d12_copy_texture(data.copy_tex, backbuffer); if (++data.cur_backbuffer >=
data.device11on12->ReleaseWrappedResources(&backbuffer, 1); data.backbuffer_count)
data.context11->Flush(); data.cur_backbuffer = 0;
}
if (!dxgi_1_4) { backbuffer->Release();
if (++data.cur_backbuffer >= data.backbuffer_count) }
data.cur_backbuffer = 0;
backbuffer12->Release();
} }
} }