[host] made DXGI ReInitialization more robust on mode changes

DXGI doesn't like to restart too fast, com exceptions are logged and the
duplication device fails to create with an E_ACCESS_DENIED error. Adding
a 200ms sleep between teardown and re-init resolves this issue.
This commit is contained in:
Geoffrey McRae 2017-11-04 04:00:00 +11:00
parent 32d61023e5
commit 9287ec97eb
2 changed files with 46 additions and 20 deletions

View File

@ -118,22 +118,23 @@ bool DXGI::Initialize()
); );
adapter.Release(); adapter.Release();
if (FAILED(status)) if (FAILED(status) || !m_device)
{ {
DEBUG_ERROR("Failed to create D3D11 device"); DEBUG_ERROR("Failed to create D3D11 device");
DeInitialize(); DeInitialize();
return false; return false;
} }
CComQIPtr<IDXGIDevice1> device1 = m_device; // we try this twice just incase we still get an error
if (!device1) // on re-initialization
for(int i = 0; i < 2; ++i)
{ {
DEBUG_ERROR("Failed to get IDXGIDevice1"); status = m_output->DuplicateOutput(m_device, &m_dup);
DeInitialize(); if (SUCCEEDED(status))
return false; break;
Sleep(200);
} }
status = m_output->DuplicateOutput(m_device, &m_dup);
if (FAILED(status)) if (FAILED(status))
{ {
DEBUG_ERROR("DuplicateOutput Failed: %08x", status); DEBUG_ERROR("DuplicateOutput Failed: %08x", status);
@ -181,6 +182,7 @@ void DXGI::DeInitialize()
{ {
delete[] m_pointer; delete[] m_pointer;
m_pointer = NULL; m_pointer = NULL;
m_pointerBufSize = 0;
} }
if (m_texture) if (m_texture)
@ -204,6 +206,19 @@ void DXGI::DeInitialize()
m_initialized = false; m_initialized = false;
} }
bool DXGI::ReInitialize()
{
DeInitialize();
/*
DXGI needs some time when mode switches occur, failing to do so causes
failure to start and exceptions internal to DXGI
*/
Sleep(200);
return Initialize();
}
FrameType DXGI::GetFrameType() FrameType DXGI::GetFrameType()
{ {
if (!m_initialized) if (!m_initialized)
@ -230,6 +245,9 @@ size_t DXGI::GetMaxFrameSize()
bool DXGI::GrabFrame(FrameInfo & frame) bool DXGI::GrabFrame(FrameInfo & frame)
{ {
if (!m_initialized)
return false;
DXGI_OUTDUPL_FRAME_INFO frameInfo; DXGI_OUTDUPL_FRAME_INFO frameInfo;
CComPtr<IDXGIResource> res; CComPtr<IDXGIResource> res;
@ -239,27 +257,31 @@ bool DXGI::GrabFrame(FrameInfo & frame)
status = m_dup->AcquireNextFrame(INFINITE, &frameInfo, &res); status = m_dup->AcquireNextFrame(INFINITE, &frameInfo, &res);
if (SUCCEEDED(status)) if (SUCCEEDED(status))
break; break;
// desktop switch, mode change or switch DWM on or off switch (status)
if (status == DXGI_ERROR_ACCESS_LOST) {
{ case DXGI_ERROR_ACCESS_LOST: // desktop switch, mode change or switch DWM on or off
DeInitialize(); case WAIT_ABANDONED: // this can happen also during desktop switches, not documented by MS though
if (!Initialize())
{ {
DEBUG_ERROR("Failed to re-initialize after access was lost"); if (!ReInitialize())
return false; {
DEBUG_ERROR("Failed to re-initialize after access was lost");
return false;
}
continue;
} }
continue;
}
// unknown failure default:
DEBUG_INFO("AcquireNextFrame failed: %08x", status); // unknown failure
return false; DEBUG_INFO("AcquireNextFrame failed: %08x", status);
return false;
}
} }
// retry count exceeded // retry count exceeded
if (FAILED(status)) if (FAILED(status))
{ {
m_dup->ReleaseFrame();
DEBUG_ERROR("Failed to acquire next frame"); DEBUG_ERROR("Failed to acquire next frame");
return false; return false;
} }
@ -267,6 +289,7 @@ bool DXGI::GrabFrame(FrameInfo & frame)
CComQIPtr<ID3D11Texture2D> src = res; CComQIPtr<ID3D11Texture2D> src = res;
if (!src) if (!src)
{ {
m_dup->ReleaseFrame();
DEBUG_ERROR("Failed to get src ID3D11Texture2D"); DEBUG_ERROR("Failed to get src ID3D11Texture2D");
return false; return false;
} }
@ -290,6 +313,7 @@ bool DXGI::GrabFrame(FrameInfo & frame)
status = m_dup->GetFramePointerShape(m_pointerBufSize, m_pointer, &m_pointerSize, &m_shapeInfo); status = m_dup->GetFramePointerShape(m_pointerBufSize, m_pointer, &m_pointerSize, &m_shapeInfo);
if (!SUCCEEDED(status)) if (!SUCCEEDED(status))
{ {
m_dup->ReleaseFrame();
DEBUG_ERROR("Failed to get the new pointer shape: %08x", status); DEBUG_ERROR("Failed to get the new pointer shape: %08x", status);
return false; return false;
} }

View File

@ -42,6 +42,8 @@ namespace Capture
bool GrabFrame(struct FrameInfo & frame); bool GrabFrame(struct FrameInfo & frame);
private: private:
bool ReInitialize();
bool m_initialized; bool m_initialized;
MTMemcpy m_memcpy; MTMemcpy m_memcpy;
unsigned int m_width; unsigned int m_width;