浏览代码

graphics-hook: Fix DXGI ref leak for D3D12 capture

Create ID3D11Resource dynamically to avoid reference inflation.
jpark37 1 年之前
父节点
当前提交
ea9df85512
共有 1 个文件被更改,包括 40 次插入59 次删除
  1. 40 59
      plugins/win-capture/graphics-hook/d3d12-capture.cpp

+ 40 - 59
plugins/win-capture/graphics-hook/d3d12-capture.cpp

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