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:
jp9000
2015-02-14 07:35:53 -08:00
parent 8b59b606c5
commit 104415d5c3

View File

@@ -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;