[host] dxgi: re-send the last frame if capture times out

This change prevents the guest from stalling on startup if there are no
frames being captured
This commit is contained in:
Geoffrey McRae 2017-12-16 10:24:37 +11:00
parent 758b7af754
commit 7c5b2b5c1c
2 changed files with 54 additions and 22 deletions

View File

@ -31,6 +31,7 @@ DXGI::DXGI() :
m_deviceContext(), m_deviceContext(),
m_dup(), m_dup(),
m_texture(), m_texture(),
m_surface(),
m_pointer(NULL) m_pointer(NULL)
{ {
} }
@ -190,6 +191,15 @@ void DXGI::DeInitialize()
m_pointerBufSize = 0; m_pointerBufSize = 0;
} }
if (m_surfaceMapped)
{
m_surface->Unmap();
m_surfaceMapped = false;
}
if (m_surface)
m_surface.Release();
if (m_texture) if (m_texture)
m_texture.Release(); m_texture.Release();
@ -241,7 +251,22 @@ GrabStatus DXGI::GrabFrame(FrameInfo & frame)
{ {
while(true) while(true)
{ {
status = m_dup->AcquireNextFrame(INFINITE, &frameInfo, &res); status = m_dup->AcquireNextFrame(1000, &frameInfo, &res);
if (status == DXGI_ERROR_WAIT_TIMEOUT)
{
if (!m_surfaceMapped)
break;
// send the last frame again if we timeout to prevent the client stalling on restart
frame.width = m_desc.Width;
frame.height = m_desc.Height;
frame.stride = m_rect.Pitch / 4;
unsigned int size = m_height * m_rect.Pitch;
memcpySSE(frame.buffer, m_rect.pBits, size < frame.bufferSize ? size : frame.bufferSize);
return GRAB_STATUS_OK;
}
if (!SUCCEEDED(status)) if (!SUCCEEDED(status))
break; break;
@ -371,8 +396,7 @@ GrabStatus DXGI::GrabFrame(FrameInfo & frame)
return GRAB_STATUS_ERROR; return GRAB_STATUS_ERROR;
} }
D3D11_TEXTURE2D_DESC desc; src->GetDesc(&m_desc);
src->GetDesc(&desc);
m_deviceContext->CopyResource(m_texture, src); m_deviceContext->CopyResource(m_texture, src);
@ -380,38 +404,42 @@ GrabStatus DXGI::GrabFrame(FrameInfo & frame)
res.Release(); res.Release();
src.Release(); src.Release();
IDXGISurface1Ptr surface(m_texture); if (m_surfaceMapped)
if (!surface) {
status = m_surface->Unmap();
if (FAILED(status))
{
DEBUG_ERROR("Failed to unmap surface: %08x", (int)status);
return GRAB_STATUS_ERROR;
}
m_surfaceMapped = false;
m_surface.Release();
}
m_surface = m_texture;
if (!m_surface)
{ {
DEBUG_ERROR("Failed to get IDXGISurface1"); DEBUG_ERROR("Failed to get IDXGISurface1");
return GRAB_STATUS_ERROR; return GRAB_STATUS_ERROR;
} }
DXGI_MAPPED_RECT rect; status = m_surface->Map(&m_rect, DXGI_MAP_READ);
status = surface->Map(&rect, DXGI_MAP_READ);
if (FAILED(status)) if (FAILED(status))
{ {
DEBUG_ERROR("Failed to map surface: %08x", (int)status); DEBUG_ERROR("Failed to map surface: %08x", (int)status);
return GRAB_STATUS_ERROR; return GRAB_STATUS_ERROR;
} }
m_surfaceMapped = true;
m_width = desc.Width; m_width = m_desc.Width;
m_height = desc.Height; m_height = m_desc.Height;
frame.width = desc.Width; frame.width = m_desc.Width;
frame.height = desc.Height; frame.height = m_desc.Height;
frame.stride = rect.Pitch / 4; frame.stride = m_rect.Pitch / 4;
unsigned int size = m_height * rect.Pitch; unsigned int size = m_height * m_rect.Pitch;
memcpySSE(frame.buffer, rect.pBits, size < frame.bufferSize ? size : frame.bufferSize); memcpySSE(frame.buffer, m_rect.pBits, size < frame.bufferSize ? size : frame.bufferSize);
status = surface->Unmap();
if (FAILED(status))
{
DEBUG_ERROR("Failed to unmap surface: %08x", (int)status);
return GRAB_STATUS_ERROR;
}
return GRAB_STATUS_OK; return GRAB_STATUS_OK;
} }

View File

@ -80,6 +80,10 @@ namespace Capture
IDXGIOutput1Ptr m_output; IDXGIOutput1Ptr m_output;
IDXGIOutputDuplicationPtr m_dup; IDXGIOutputDuplicationPtr m_dup;
ID3D11Texture2DPtr m_texture; ID3D11Texture2DPtr m_texture;
IDXGISurface1Ptr m_surface;
D3D11_TEXTURE2D_DESC m_desc;
DXGI_MAPPED_RECT m_rect;
bool m_surfaceMapped;
BYTE * m_pointer; BYTE * m_pointer;
UINT m_pointerBufSize; UINT m_pointerBufSize;
UINT m_pointerSize; UINT m_pointerSize;