win-capture: Add IDXGISwapChain1::Present1 hook support
Allows capturing games/programs that may be using Present1 instead of the regular Present call for rendering.
This commit is contained in:
parent
96f746ce41
commit
1ca9f8872e
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -42,6 +42,8 @@ struct d3d9_offsets {
|
||||
struct dxgi_offsets {
|
||||
uint32_t present;
|
||||
uint32_t resize;
|
||||
|
||||
uint32_t present1;
|
||||
};
|
||||
|
||||
struct ddraw_offsets {
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user