From 1ca9f8872e48dcbe7e509fae8ad26669ee150b94 Mon Sep 17 00:00:00 2001 From: jp9000 Date: Mon, 19 Jun 2017 15:45:00 -0700 Subject: [PATCH] win-capture: Add IDXGISwapChain1::Present1 hook support Allows capturing games/programs that may be using Present1 instead of the regular Present call for rendering. --- .../get-graphics-offsets/dxgi-offsets.cpp | 41 ++++++++++++- .../get-graphics-offsets.c | 1 + plugins/win-capture/graphics-hook-info.h | 2 + .../graphics-hook/dxgi-capture.cpp | 61 ++++++++++++++++++- plugins/win-capture/load-graphics-offsets.c | 2 + 5 files changed, 104 insertions(+), 3 deletions(-) diff --git a/plugins/win-capture/get-graphics-offsets/dxgi-offsets.cpp b/plugins/win-capture/get-graphics-offsets/dxgi-offsets.cpp index ddc868692..12c879dca 100644 --- a/plugins/win-capture/get-graphics-offsets/dxgi-offsets.cpp +++ b/plugins/win-capture/get-graphics-offsets/dxgi-offsets.cpp @@ -1,11 +1,13 @@ #include #include -#include +#include +#include #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); diff --git a/plugins/win-capture/get-graphics-offsets/get-graphics-offsets.c b/plugins/win-capture/get-graphics-offsets/get-graphics-offsets.c index e06e5cc06..ea27588aa 100644 --- a/plugins/win-capture/get-graphics-offsets/get-graphics-offsets.c +++ b/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; diff --git a/plugins/win-capture/graphics-hook-info.h b/plugins/win-capture/graphics-hook-info.h index 0ef01aad0..7ce21f0fc 100644 --- a/plugins/win-capture/graphics-hook-info.h +++ b/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 { diff --git a/plugins/win-capture/graphics-hook/dxgi-capture.cpp b/plugins/win-capture/graphics-hook/dxgi-capture.cpp index 381b49105..063998b6e 100644 --- a/plugins/win-capture/graphics-hook/dxgi-capture.cpp +++ b/plugins/win-capture/graphics-hook/dxgi-capture.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include #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; diff --git a/plugins/win-capture/load-graphics-offsets.c b/plugins/win-capture/load-graphics-offsets.c index fafc682d0..4bf2f8c51 100644 --- a/plugins/win-capture/load-graphics-offsets.c +++ b/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"); -- GitLab