mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-22 15:11:31 +00:00
[idd] recovery: restore fallback display
Add a protocol-independent recovery channel outside LGMP so clients can request a usable guest display even when transport versions differ. Synchronize recovery state with the helper across driver restarts and restore the configured topology without persisting temporary changes.
This commit is contained in:
@@ -44,8 +44,14 @@ CDeviceContext::CDeviceContext(WDFDEVICE wdfDevice) :
|
||||
|
||||
CDeviceContext::~CDeviceContext()
|
||||
{
|
||||
// Both callbacks dereference this context. Drain them before the subsystem
|
||||
// These callbacks dereference this context. Drain them before the subsystem
|
||||
// members are destroyed in frame, control, host order.
|
||||
if (m_recoveryHandlerSet)
|
||||
{
|
||||
g_pipe.ClearRecoveryHandler(this);
|
||||
m_recoveryHandlerSet = false;
|
||||
}
|
||||
|
||||
if (m_initTimer)
|
||||
{
|
||||
WdfTimerStop(m_initTimer, TRUE);
|
||||
@@ -379,8 +385,9 @@ void CDeviceContext::FinishInit(UINT connectorIndex)
|
||||
{
|
||||
CDisplayConfiguration::Description description =
|
||||
m_displayConfiguration.GetDescription();
|
||||
m_monitorManager.Create(
|
||||
connectorIndex, m_adapter, std::move(description.edid), this);
|
||||
if (m_monitorManager.Create(
|
||||
connectorIndex, m_adapter, std::move(description.edid), this))
|
||||
m_transport->SyncRecovery();
|
||||
}
|
||||
|
||||
void CDeviceContext::ReplugMonitor()
|
||||
@@ -460,7 +467,90 @@ void CDeviceContext::SetResolution(uint32_t width, uint32_t height)
|
||||
|
||||
bool CDeviceContext::InitializeTransport()
|
||||
{
|
||||
return m_transport && m_transport->Initialize();
|
||||
if (!m_transport)
|
||||
return false;
|
||||
|
||||
if (m_transportTimer)
|
||||
return true;
|
||||
|
||||
g_pipe.SetRecoveryHandler(
|
||||
[](void * opaque, uint64_t session, uint32_t serial, bool active,
|
||||
LGPipeMsg::Type result)
|
||||
{
|
||||
CDeviceContext * context =
|
||||
static_cast<CDeviceContext *>(opaque);
|
||||
|
||||
ITransport::Recovery state = ITransport::Recovery::FAILED;
|
||||
uint32_t error = ERROR_SUCCESS;
|
||||
switch (result)
|
||||
{
|
||||
case LGPipeMsg::RECOVERY_OFF:
|
||||
state = ITransport::Recovery::NORMAL;
|
||||
break;
|
||||
|
||||
case LGPipeMsg::RECOVERY_ON:
|
||||
state = ITransport::Recovery::ACTIVE;
|
||||
break;
|
||||
|
||||
case LGPipeMsg::RECOVERY_FAILED:
|
||||
error = ERROR_GEN_FAILURE;
|
||||
break;
|
||||
|
||||
case LGPipeMsg::RECOVERY_NO_DISPLAY:
|
||||
error = ERROR_NOT_FOUND;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
context->m_transport->RecoveryStatus(
|
||||
session, serial, active, state, error);
|
||||
},
|
||||
this);
|
||||
m_recoveryHandlerSet = true;
|
||||
|
||||
// Claim the pipe recovery channel before initializing the producer session
|
||||
// so no request cached by a prior device context can cross the handoff.
|
||||
if (!m_transport->Initialize())
|
||||
{
|
||||
g_pipe.ClearRecoveryHandler(this);
|
||||
m_recoveryHandlerSet = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
WDF_TIMER_CONFIG config;
|
||||
WDF_TIMER_CONFIG_INIT_PERIODIC(&config,
|
||||
[](WDFTIMER timer) -> void
|
||||
{
|
||||
WDFOBJECT parent = WdfTimerGetParentObject(timer);
|
||||
auto wrapper = WdfObjectGet_CDeviceContextWrapper(parent);
|
||||
wrapper->context->TransportTimer();
|
||||
},
|
||||
10);
|
||||
config.AutomaticSerialization = FALSE;
|
||||
|
||||
/**
|
||||
* Documentation states that Dispatch is not available under UMDF,
|
||||
* however using Passive returns a not-supported error and Dispatch works.
|
||||
*/
|
||||
WDF_OBJECT_ATTRIBUTES attribs;
|
||||
WDF_OBJECT_ATTRIBUTES_INIT(&attribs);
|
||||
attribs.ParentObject = m_wdfDevice;
|
||||
attribs.ExecutionLevel = WdfExecutionLevelDispatch;
|
||||
|
||||
NTSTATUS status = WdfTimerCreate(
|
||||
&config, &attribs, &m_transportTimer);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
g_pipe.ClearRecoveryHandler(this);
|
||||
m_recoveryHandlerSet = false;
|
||||
DEBUG_ERROR_HR(status, "Transport timer creation failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
WdfTimerStart(m_transportTimer, WDF_REL_TIMEOUT_IN_MS(10));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDeviceContext::SetupTransport(size_t alignSize)
|
||||
@@ -471,36 +561,6 @@ bool CDeviceContext::SetupTransport(size_t alignSize)
|
||||
{
|
||||
if (!InitializeTransport() || !m_transport->Setup(alignSize))
|
||||
return false;
|
||||
|
||||
WDF_TIMER_CONFIG config;
|
||||
WDF_TIMER_CONFIG_INIT_PERIODIC(&config,
|
||||
[](WDFTIMER timer) -> void
|
||||
{
|
||||
WDFOBJECT parent = WdfTimerGetParentObject(timer);
|
||||
auto wrapper = WdfObjectGet_CDeviceContextWrapper(parent);
|
||||
wrapper->context->TransportTimer();
|
||||
},
|
||||
10);
|
||||
config.AutomaticSerialization = FALSE;
|
||||
|
||||
/**
|
||||
* Documentation states that Dispatch is not available under UMDF,
|
||||
* however using Passive returns a not-supported error and Dispatch works.
|
||||
*/
|
||||
WDF_OBJECT_ATTRIBUTES attribs;
|
||||
WDF_OBJECT_ATTRIBUTES_INIT(&attribs);
|
||||
attribs.ParentObject = m_wdfDevice;
|
||||
attribs.ExecutionLevel = WdfExecutionLevelDispatch;
|
||||
|
||||
NTSTATUS status = WdfTimerCreate(
|
||||
&config, &attribs, &m_transportTimer);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR_HR(status, "Timer creation failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
WdfTimerStart(m_transportTimer, WDF_REL_TIMEOUT_IN_MS(10));
|
||||
}
|
||||
|
||||
IInputTransport * input = m_transport->Input();
|
||||
@@ -542,3 +602,9 @@ void CDeviceContext::OnSetResolution(uint32_t width, uint32_t height)
|
||||
{
|
||||
SetResolution(width, height);
|
||||
}
|
||||
|
||||
void CDeviceContext::OnRecoveryRequest(
|
||||
uint64_t session, uint32_t serial, bool active)
|
||||
{
|
||||
g_pipe.SetRecovery(this, session, serial, active);
|
||||
}
|
||||
|
||||
@@ -51,7 +51,8 @@ private:
|
||||
CDisplayConfiguration m_displayConfiguration;
|
||||
CMonitorManager m_monitorManager;
|
||||
|
||||
WDFTIMER m_transportTimer = nullptr;
|
||||
WDFTIMER m_transportTimer = nullptr;
|
||||
bool m_recoveryHandlerSet = false;
|
||||
|
||||
UINT m_iddCxVersion = 0;
|
||||
bool m_hasIddCx110DDIs = false;
|
||||
@@ -67,6 +68,8 @@ private:
|
||||
void TransportTimer();
|
||||
void OnSetCursorPos(int32_t x, int32_t y) override;
|
||||
void OnSetResolution(uint32_t width, uint32_t height) override;
|
||||
void OnRecoveryRequest(
|
||||
uint64_t session, uint32_t serial, bool active) override;
|
||||
void SetResolution(uint32_t width, uint32_t height);
|
||||
|
||||
public:
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "display/CMonitorContext.h"
|
||||
#include "CDebug.h"
|
||||
|
||||
void CMonitorManager::Create(UINT connectorIndex, IDDCX_ADAPTER adapter,
|
||||
bool CMonitorManager::Create(UINT connectorIndex, IDDCX_ADAPTER adapter,
|
||||
std::vector<BYTE> edid, CDeviceContext * owner)
|
||||
{
|
||||
DEBUG_INFO("Creating monitor on connector %u", connectorIndex);
|
||||
@@ -38,7 +38,7 @@ void CMonitorManager::Create(UINT connectorIndex, IDDCX_ADAPTER adapter,
|
||||
if (haveMonitor)
|
||||
{
|
||||
DEBUG_WARN("FinishInit skipped: a monitor already exists");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
WDF_OBJECT_ATTRIBUTES attr;
|
||||
@@ -61,7 +61,7 @@ void CMonitorManager::Create(UINT connectorIndex, IDDCX_ADAPTER adapter,
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DEBUG_ERROR_HR(hr, "Failed to create the monitor container ID");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
IDARG_IN_MONITORCREATE create = {};
|
||||
@@ -73,7 +73,7 @@ void CMonitorManager::Create(UINT connectorIndex, IDDCX_ADAPTER adapter,
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR_HR(status, "IddCxMonitorCreate Failed");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
DEBUG_INFO("Monitor object created (%p)", createOut.MonitorObject);
|
||||
@@ -91,10 +91,11 @@ void CMonitorManager::Create(UINT connectorIndex, IDDCX_ADAPTER adapter,
|
||||
if (FAILED(status))
|
||||
{
|
||||
DEBUG_ERROR_HR(status, "IddCxMonitorArrival Failed");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
DEBUG_INFO("Monitor arrival reported successfully");
|
||||
return true;
|
||||
}
|
||||
|
||||
CMonitorManager::ReplugAction CMonitorManager::Replug()
|
||||
|
||||
@@ -75,7 +75,7 @@ private:
|
||||
std::atomic<LONG> m_replugQueued = 0;
|
||||
|
||||
public:
|
||||
void Create(UINT connectorIndex, IDDCX_ADAPTER adapter,
|
||||
bool Create(UINT connectorIndex, IDDCX_ADAPTER adapter,
|
||||
std::vector<BYTE> edid, CDeviceContext * owner);
|
||||
ReplugAction Replug();
|
||||
void RequestMode(const CSettings::DisplayMode& mode);
|
||||
|
||||
Reference in New Issue
Block a user