win-capture: Fix hook bug that could cause crashes
I had this issue where IDXGISwapChain::ResizeBuffers would fail in the hooks, causing games to crash when they resized their backbuffers because ResizeBuffers would return an 'invalid call' HRESULT value. In the ResizeBuffers documentation it says that it will only happen if a backbuffer currently has any outstanding references, but there's no way this would happen unless ResizeBuffers internally calls Present or vise versa. After ResizeBuffers has been called, the very first call to Present will somehow seemingly invalidate and/or destroy the current backbuffer. It's very strange, but that seems to be what's going on, at least for the game I was testing. So if you are performing a post-overlay capture, then you must ignore the capture on the very first call to Present. It's Microsoft's code so you can't really know what's going on, you just have to work around these strange issues seemingly in the dark.
This commit is contained in:
@@ -61,6 +61,8 @@ static bool setup_dxgi(IDXGISwapChain *swap)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool resize_buffers_called = false;
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE hook_resize_buffers(IDXGISwapChain *swap,
|
||||
UINT buffer_count, UINT width, UINT height, DXGI_FORMAT format,
|
||||
UINT flags)
|
||||
@@ -79,6 +81,8 @@ static HRESULT STDMETHODCALLTYPE hook_resize_buffers(IDXGISwapChain *swap,
|
||||
hr = call(swap, buffer_count, width, height, format, flags);
|
||||
rehook(&resize_buffers);
|
||||
|
||||
resize_buffers_called = true;
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
@@ -98,6 +102,7 @@ static HRESULT STDMETHODCALLTYPE hook_present(IDXGISwapChain *swap,
|
||||
UINT sync_interval, UINT flags)
|
||||
{
|
||||
IDXGIResource *backbuffer = nullptr;
|
||||
bool capture_overlay = global_hook_info->capture_overlay;
|
||||
bool test_draw = (flags & DXGI_PRESENT_TEST) != 0;
|
||||
bool capture;
|
||||
HRESULT hr;
|
||||
@@ -107,12 +112,13 @@ static HRESULT STDMETHODCALLTYPE hook_present(IDXGISwapChain *swap,
|
||||
}
|
||||
|
||||
capture = !test_draw && swap == data.swap && !!data.capture;
|
||||
if (capture) {
|
||||
if (capture && !capture_overlay) {
|
||||
backbuffer = get_dxgi_backbuffer(swap);
|
||||
capture = !!backbuffer;
|
||||
|
||||
if (capture && !global_hook_info->capture_overlay)
|
||||
if (!!backbuffer) {
|
||||
data.capture(swap, backbuffer);
|
||||
backbuffer->Release();
|
||||
}
|
||||
}
|
||||
|
||||
unhook(&present);
|
||||
@@ -120,11 +126,24 @@ static HRESULT STDMETHODCALLTYPE hook_present(IDXGISwapChain *swap,
|
||||
hr = call(swap, sync_interval, flags);
|
||||
rehook(&present);
|
||||
|
||||
if (capture) {
|
||||
if (global_hook_info->capture_overlay)
|
||||
data.capture(swap, backbuffer);
|
||||
if (capture && capture_overlay) {
|
||||
/*
|
||||
* It seems that the first call to Present after ResizeBuffers
|
||||
* will cause the backbuffer to be invalidated, so do not
|
||||
* perform the post-overlay capture if ResizeBuffers has
|
||||
* recently been called. (The backbuffer returned by
|
||||
* get_dxgi_backbuffer *will* be invalid otherwise)
|
||||
*/
|
||||
if (resize_buffers_called) {
|
||||
resize_buffers_called = false;
|
||||
} else {
|
||||
backbuffer = get_dxgi_backbuffer(swap);
|
||||
|
||||
backbuffer->Release();
|
||||
if (!!backbuffer) {
|
||||
data.capture(swap, backbuffer);
|
||||
backbuffer->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hr;
|
||||
|
Reference in New Issue
Block a user