Răsfoiți Sursa

win-capture: Add IDXGISwapChain1::Present1 hook support

Allows capturing games/programs that may be using Present1 instead of
the regular Present call for rendering.
jp9000 8 ani în urmă
părinte
comite
1ca9f8872e

+ 39 - 2
plugins/win-capture/get-graphics-offsets/dxgi-offsets.cpp

@@ -1,11 +1,13 @@
 #include <windows.h>
 #include <d3d10.h>
-#include <dxgi.h>
+#include <VersionHelpers.h>
+#include <dxgi1_2.h>
 #include "get-graphics-offsets.h"
 
 typedef HRESULT (WINAPI *d3d10create_t)(IDXGIAdapter*, D3D10_DRIVER_TYPE,
 		HMODULE, UINT, UINT, DXGI_SWAP_CHAIN_DESC*,
 		IDXGISwapChain**, IUnknown**);
+typedef HRESULT (WINAPI *create_fac_t)(IID *id, void**);
 
 struct dxgi_info {
 	HMODULE        module;
@@ -13,10 +15,16 @@ struct dxgi_info {
 	IDXGISwapChain *swap;
 };
 
+static const IID dxgiFactory2 =
+{0x50c83a1c, 0xe072, 0x4c48, {0x87, 0xb0, 0x36, 0x30, 0xfa, 0x36, 0xa6, 0xd0}};
+
 static inline bool dxgi_init(dxgi_info &info)
 {
 	HMODULE       d3d10_module;
 	d3d10create_t create;
+	create_fac_t  create_factory;
+	IDXGIFactory1 *factory;
+	IDXGIAdapter1 *adapter;
 	IUnknown      *device;
 	HRESULT       hr;
 
@@ -32,6 +40,9 @@ static inline bool dxgi_init(dxgi_info &info)
 		return false;
 	}
 
+	create_factory = (create_fac_t)GetProcAddress(info.module,
+			"CreateDXGIFactory1");
+
 	d3d10_module = LoadLibraryA("d3d10.dll");
 	if (!d3d10_module) {
 		return false;
@@ -43,6 +54,21 @@ static inline bool dxgi_init(dxgi_info &info)
 		return false;
 	}
 
+	IID factory_iid = IsWindows8OrGreater()
+		? dxgiFactory2
+		: __uuidof(IDXGIFactory1);
+
+	hr = create_factory(&factory_iid, (void**)&factory);
+	if (FAILED(hr)) {
+		return false;
+	}
+
+	hr = factory->EnumAdapters1(0, &adapter);
+	factory->Release();
+	if (FAILED(hr)) {
+		return false;
+	}
+
 	DXGI_SWAP_CHAIN_DESC desc = {};
 	desc.BufferCount          = 2;
 	desc.BufferDesc.Format    = DXGI_FORMAT_R8G8B8A8_UNORM;
@@ -53,8 +79,9 @@ static inline bool dxgi_init(dxgi_info &info)
 	desc.SampleDesc.Count     = 1;
 	desc.Windowed             = true;
 
-	hr = create(nullptr, D3D10_DRIVER_TYPE_NULL, nullptr, 0,
+	hr = create(adapter, D3D10_DRIVER_TYPE_HARDWARE, nullptr, 0,
 			D3D10_SDK_VERSION, &desc, &info.swap, &device);
+	adapter->Release();
 	if (FAILED(hr)) {
 		return false;
 	}
@@ -75,10 +102,20 @@ void get_dxgi_offsets(struct dxgi_offsets *offsets)
 {
 	dxgi_info info    = {};
 	bool      success = dxgi_init(info);
+	HRESULT   hr;
 
 	if (success) {
 		offsets->present = vtable_offset(info.module, info.swap, 8);
 		offsets->resize  = vtable_offset(info.module, info.swap, 13);
+
+		IDXGISwapChain1 *swap1;
+		hr = info.swap->QueryInterface(__uuidof(IDXGISwapChain1),
+				(void**)&swap1);
+		if (SUCCEEDED(hr)) {
+			offsets->present1 =
+				vtable_offset(info.module, swap1, 22);
+			swap1->Release();
+		}
 	}
 
 	dxgi_free(info);

+ 1 - 0
plugins/win-capture/get-graphics-offsets/get-graphics-offsets.c

@@ -34,6 +34,7 @@ int main(int argc, char *argv[])
 	printf("is_d3d9ex_clsoff=0x%"PRIx32"\n", d3d9.is_d3d9ex_clsoff);
 	printf("[dxgi]\n");
 	printf("present=0x%"PRIx32"\n", dxgi.present);
+	printf("present1=0x%"PRIx32"\n", dxgi.present1);
 	printf("resize=0x%"PRIx32"\n", dxgi.resize);
 
 	(void)argc;

+ 2 - 0
plugins/win-capture/graphics-hook-info.h

@@ -42,6 +42,8 @@ struct d3d9_offsets {
 struct dxgi_offsets {
 	uint32_t present;
 	uint32_t resize;
+
+	uint32_t present1;
 };
 
 struct ddraw_offsets {

+ 60 - 1
plugins/win-capture/graphics-hook/dxgi-capture.cpp

@@ -1,6 +1,6 @@
 #include <d3d10_1.h>
 #include <d3d11.h>
-#include <dxgi.h>
+#include <dxgi1_2.h>
 #include <d3dcompiler.h>
 
 #include "d3d1x_shaders.hpp"
@@ -14,9 +14,12 @@
 typedef HRESULT (STDMETHODCALLTYPE *resize_buffers_t)(IDXGISwapChain*, UINT,
 		UINT, UINT, DXGI_FORMAT, UINT);
 typedef HRESULT (STDMETHODCALLTYPE *present_t)(IDXGISwapChain*, UINT, UINT);
+typedef HRESULT (STDMETHODCALLTYPE *present1_t)(IDXGISwapChain1*, UINT, UINT,
+		const DXGI_PRESENT_PARAMETERS *);
 
 static struct func_hook resize_buffers;
 static struct func_hook present;
+static struct func_hook present1;
 
 struct dxgi_swap_data {
 	IDXGISwapChain *swap;
@@ -165,6 +168,53 @@ static HRESULT STDMETHODCALLTYPE hook_present(IDXGISwapChain *swap,
 	return hr;
 }
 
+static HRESULT STDMETHODCALLTYPE hook_present1(IDXGISwapChain1 *swap,
+		UINT sync_interval, UINT flags,
+		const DXGI_PRESENT_PARAMETERS *params)
+{
+	IUnknown *backbuffer = nullptr;
+	bool capture_overlay = global_hook_info->capture_overlay;
+	bool test_draw = (flags & DXGI_PRESENT_TEST) != 0;
+	bool capture;
+	HRESULT hr;
+
+	if (!data.swap && !capture_active()) {
+		setup_dxgi(swap);
+	}
+
+	capture = !test_draw && swap == data.swap && !!data.capture;
+	if (capture && !capture_overlay) {
+		backbuffer = get_dxgi_backbuffer(swap);
+
+		if (!!backbuffer) {
+			DXGI_SWAP_CHAIN_DESC1 desc;
+			swap->GetDesc1(&desc);
+			data.capture(swap, backbuffer, capture_overlay);
+			backbuffer->Release();
+		}
+	}
+
+	unhook(&present1);
+	present1_t call = (present1_t)present1.call_addr;
+	hr = call(swap, sync_interval, flags, params);
+	rehook(&present1);
+
+	if (capture && capture_overlay) {
+		if (resize_buffers_called) {
+			resize_buffers_called = false;
+		} else {
+			backbuffer = get_dxgi_backbuffer(swap);
+
+			if (!!backbuffer) {
+				data.capture(swap, backbuffer, capture_overlay);
+				backbuffer->Release();
+			}
+		}
+	}
+
+	return hr;
+}
+
 static pD3DCompile get_compiler(void)
 {
 	pD3DCompile compile = nullptr;
@@ -202,6 +252,7 @@ bool hook_dxgi(void)
 	HRESULT hr;
 	void *present_addr;
 	void *resize_addr;
+	void *present1_addr = nullptr;
 
 	if (!dxgi_module) {
 		return false;
@@ -251,14 +302,22 @@ bool hook_dxgi(void)
 			global_hook_info->offsets.dxgi.present);
 	resize_addr = get_offset_addr(dxgi_module,
 			global_hook_info->offsets.dxgi.resize);
+	if (global_hook_info->offsets.dxgi.present1)
+		present1_addr = get_offset_addr(dxgi_module,
+				global_hook_info->offsets.dxgi.present1);
 
 	hook_init(&present, present_addr, (void*)hook_present,
 			"IDXGISwapChain::Present");
 	hook_init(&resize_buffers, resize_addr, (void*)hook_resize_buffers,
 			"IDXGISwapChain::ResizeBuffers");
+	if (present1_addr)
+		hook_init(&present1, present1_addr, (void*)hook_present1,
+				"IDXGISwapChain1::Present1");
 
 	rehook(&resize_buffers);
 	rehook(&present);
+	if (present1_addr)
+		rehook(&present1);
 
 	hlog("Hooked DXGI");
 	return true;

+ 2 - 0
plugins/win-capture/load-graphics-offsets.c

@@ -36,6 +36,8 @@ static inline bool load_offsets_from_string(struct graphics_offsets *offsets,
 
 	offsets->dxgi.present =
 		(uint32_t)config_get_uint(config, "dxgi", "present");
+	offsets->dxgi.present1 =
+		(uint32_t)config_get_uint(config, "dxgi", "present1");
 	offsets->dxgi.resize =
 		(uint32_t)config_get_uint(config, "dxgi", "resize");