mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-06-05 06:14:25 +00:00
[idd] driver: improve resolution switching performance
This commit is contained in:
committed by
Geoffrey McRae
parent
a10efc9e23
commit
3211bc1d93
@@ -269,6 +269,8 @@ void CIndirectDeviceContext::ReplugMonitor()
|
||||
|
||||
void CIndirectDeviceContext::OnAssignSwapChain()
|
||||
{
|
||||
InterlockedExchange(&m_recoverModeUpdateSwapChain, 0);
|
||||
|
||||
if (m_doSetMode)
|
||||
{
|
||||
m_doSetMode = false;
|
||||
@@ -278,6 +280,9 @@ void CIndirectDeviceContext::OnAssignSwapChain()
|
||||
|
||||
void CIndirectDeviceContext::OnUnassignedSwapChain()
|
||||
{
|
||||
InterlockedExchange(&m_replugMonitorQueued, 0);
|
||||
InterlockedExchange(&m_recoverModeUpdateSwapChain, 0);
|
||||
|
||||
if (m_replugMonitor)
|
||||
{
|
||||
m_replugMonitor = false;
|
||||
@@ -285,6 +290,21 @@ void CIndirectDeviceContext::OnUnassignedSwapChain()
|
||||
}
|
||||
}
|
||||
|
||||
void CIndirectDeviceContext::OnSwapChainLost()
|
||||
{
|
||||
// A mode update normally keeps the swap chain alive. If Windows instead
|
||||
// reports the existing path disappeared before we see a frame at the new
|
||||
// size, recover by scheduling the old replug path from the LGMP timer so we
|
||||
// do not tear down the swap chain from one of its worker threads.
|
||||
if (!InterlockedCompareExchange(&m_recoverModeUpdateSwapChain, 0, 0))
|
||||
return;
|
||||
|
||||
if (InterlockedExchange(&m_replugMonitorQueued, 1))
|
||||
return;
|
||||
|
||||
DEBUG_WARN("Swap chain was lost after a mode update, falling back to monitor replug");
|
||||
}
|
||||
|
||||
static inline void FillSignalInfo(DISPLAYCONFIG_VIDEO_SIGNAL_INFO & mode, DWORD width, DWORD height, DWORD vsync, bool monitorMode)
|
||||
{
|
||||
mode.totalSize.cx = mode.activeSize.cx = width;
|
||||
@@ -421,6 +441,85 @@ NTSTATUS CIndirectDeviceContext::MonitorQueryTargetModes2(
|
||||
}
|
||||
#endif
|
||||
|
||||
bool CIndirectDeviceContext::UpdateMonitorModes()
|
||||
{
|
||||
if (!m_monitor)
|
||||
return false;
|
||||
|
||||
#if defined(IDDCX_VERSION_MAJOR) && defined(IDDCX_VERSION_MINOR) && \
|
||||
(IDDCX_VERSION_MAJOR > 1 || (IDDCX_VERSION_MAJOR == 1 && IDDCX_VERSION_MINOR >= 10))
|
||||
if (CanUseIddCx110DDIs())
|
||||
{
|
||||
IDDCX_TARGET_MODE2* modes = (IDDCX_TARGET_MODE2*)_malloca(
|
||||
m_displayModes.size() * sizeof(IDDCX_TARGET_MODE2));
|
||||
if (!modes)
|
||||
{
|
||||
DEBUG_WARN("Failed to allocate memory for the mode list");
|
||||
return false;
|
||||
}
|
||||
|
||||
ZeroMemory(modes, m_displayModes.size() * sizeof(IDDCX_TARGET_MODE2));
|
||||
|
||||
auto* mode = modes;
|
||||
for (auto it = m_displayModes.cbegin(); it != m_displayModes.cend(); ++it, ++mode)
|
||||
{
|
||||
mode->Size = sizeof(IDDCX_TARGET_MODE2);
|
||||
mode->RequiredBandwidth = (UINT64)it->width * it->height * it->refresh * 32;
|
||||
mode->BitsPerComponent = GetWireBitsPerComponent(CanUseIddCx110DDIs());
|
||||
FillSignalInfo(mode->TargetVideoSignalInfo.targetVideoSignalInfo, it->width, it->height, it->refresh, false);
|
||||
}
|
||||
|
||||
IDARG_IN_UPDATEMODES2 updateModes = {};
|
||||
updateModes.Reason = IDDCX_UPDATE_REASON_OTHER;
|
||||
updateModes.TargetModeCount = (UINT)m_displayModes.size();
|
||||
updateModes.pTargetModes = modes;
|
||||
|
||||
NTSTATUS status = IddCxMonitorUpdateModes2(m_monitor, &updateModes);
|
||||
_freea(modes);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_WARN("IddCxMonitorUpdateModes2 Failed (0x%08x)", status);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
IDDCX_TARGET_MODE* modes = (IDDCX_TARGET_MODE*)_malloca(
|
||||
m_displayModes.size() * sizeof(IDDCX_TARGET_MODE));
|
||||
if (!modes)
|
||||
{
|
||||
DEBUG_WARN("Failed to allocate memory for the mode list");
|
||||
return false;
|
||||
}
|
||||
|
||||
ZeroMemory(modes, m_displayModes.size() * sizeof(IDDCX_TARGET_MODE));
|
||||
|
||||
auto* mode = modes;
|
||||
for (auto it = m_displayModes.cbegin(); it != m_displayModes.cend(); ++it, ++mode)
|
||||
{
|
||||
mode->Size = sizeof(IDDCX_TARGET_MODE);
|
||||
mode->RequiredBandwidth = (UINT64)it->width * it->height * it->refresh * 32;
|
||||
FillSignalInfo(mode->TargetVideoSignalInfo.targetVideoSignalInfo, it->width, it->height, it->refresh, false);
|
||||
}
|
||||
|
||||
IDARG_IN_UPDATEMODES updateModes = {};
|
||||
updateModes.Reason = IDDCX_UPDATE_REASON_OTHER;
|
||||
updateModes.TargetModeCount = (UINT)m_displayModes.size();
|
||||
updateModes.pTargetModes = modes;
|
||||
|
||||
NTSTATUS status = IddCxMonitorUpdateModes(m_monitor, &updateModes);
|
||||
_freea(modes);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_WARN("IddCxMonitorUpdateModes Failed (0x%08x)", status);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CIndirectDeviceContext::SetResolution(int width, int height)
|
||||
{
|
||||
m_setMode.width = width;
|
||||
@@ -430,77 +529,20 @@ void CIndirectDeviceContext::SetResolution(int width, int height)
|
||||
g_settings.SetExtraMode(m_setMode);
|
||||
|
||||
PopulateDefaultModes();
|
||||
|
||||
if (UpdateMonitorModes())
|
||||
{
|
||||
DEBUG_TRACE("Updated monitor modes without replugging");
|
||||
m_doSetMode = false;
|
||||
InterlockedExchange(&m_recoverModeUpdateSwapChain, 1);
|
||||
g_pipe.SetDisplayMode(m_setMode.width, m_setMode.height, m_setMode.refresh);
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_TRACE("Falling back to monitor replug for mode update");
|
||||
m_doSetMode = true;
|
||||
|
||||
#if 1
|
||||
InterlockedExchange(&m_recoverModeUpdateSwapChain, 0);
|
||||
ReplugMonitor();
|
||||
#else
|
||||
|
||||
if (IDD_IS_FUNCTION_AVAILABLE(IddCxMonitorUpdateModes2))
|
||||
{
|
||||
IDDCX_TARGET_MODE2* modes = (IDDCX_TARGET_MODE2*)_malloca(
|
||||
m_displayModes.size() * sizeof(IDDCX_TARGET_MODE2));
|
||||
|
||||
if (!modes)
|
||||
{
|
||||
DEBUG_ERROR("Failed to allocate memory for the mode list");
|
||||
return;
|
||||
}
|
||||
|
||||
ZeroMemory(modes, m_displayModes.size() * sizeof(IDDCX_TARGET_MODE2));
|
||||
|
||||
IDARG_IN_UPDATEMODES2 um = {};
|
||||
um.Reason = IDDCX_UPDATE_REASON_OTHER;
|
||||
um.TargetModeCount = (UINT)m_displayModes.size();
|
||||
um.pTargetModes = modes;
|
||||
auto* mode = modes;
|
||||
for (auto it = m_displayModes.cbegin(); it != m_displayModes.cend(); ++it, ++mode)
|
||||
{
|
||||
mode->Size = sizeof(IDDCX_TARGET_MODE2);
|
||||
mode->RequiredBandwidth = (UINT64)(it->width * it->height * it->refresh * 32);
|
||||
mode->BitsPerComponent.Rgb = IDDCX_BITS_PER_COMPONENT_8;
|
||||
|
||||
FillSignalInfo(mode->TargetVideoSignalInfo.targetVideoSignalInfo, it->width, it->height, it->refresh, true);
|
||||
}
|
||||
|
||||
NTSTATUS status = IddCxMonitorUpdateModes2(m_monitor, &um);
|
||||
if (!NT_SUCCESS(status))
|
||||
DEBUG_ERROR("IddCxMonitorUpdateModes2 Failed (0x%08x)", status);
|
||||
|
||||
_freea(modes);
|
||||
}
|
||||
else
|
||||
{
|
||||
IDDCX_TARGET_MODE* modes = (IDDCX_TARGET_MODE*)_malloca(
|
||||
m_displayModes.size() * sizeof(IDDCX_TARGET_MODE));
|
||||
|
||||
if (!modes)
|
||||
{
|
||||
DEBUG_ERROR("Failed to allocate memory for the mode list");
|
||||
return;
|
||||
}
|
||||
|
||||
IDARG_IN_UPDATEMODES um = {};
|
||||
um.Reason = IDDCX_UPDATE_REASON_OTHER;
|
||||
um.TargetModeCount = (UINT)m_displayModes.size();
|
||||
um.pTargetModes = modes;
|
||||
|
||||
auto* mode = modes;
|
||||
for (auto it = m_displayModes.cbegin(); it != m_displayModes.cend(); ++it, ++mode)
|
||||
{
|
||||
mode->Size = sizeof(IDDCX_TARGET_MODE);
|
||||
mode->RequiredBandwidth = (UINT64)(it->width * it->height * it->refresh * 32);
|
||||
|
||||
FillSignalInfo(mode->TargetVideoSignalInfo.targetVideoSignalInfo, it->width, it->height, it->refresh, true);
|
||||
}
|
||||
|
||||
NTSTATUS status = IddCxMonitorUpdateModes(m_monitor, &um);
|
||||
if (!NT_SUCCESS(status))
|
||||
DEBUG_ERROR("IddCxMonitorUpdateModes Failed (0x%08x)", status);
|
||||
|
||||
_freea(modes);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CIndirectDeviceContext::SetupLGMP(size_t alignSize)
|
||||
@@ -704,6 +746,13 @@ void CIndirectDeviceContext::DeInitLGMP()
|
||||
|
||||
void CIndirectDeviceContext::LGMPTimer()
|
||||
{
|
||||
if (InterlockedExchange(&m_replugMonitorQueued, 0))
|
||||
{
|
||||
m_doSetMode = true;
|
||||
ReplugMonitor();
|
||||
return;
|
||||
}
|
||||
|
||||
LGMP_STATUS status;
|
||||
if ((status = lgmpHostProcess(m_lgmp)) != LGMP_OK)
|
||||
{
|
||||
@@ -753,13 +802,18 @@ void CIndirectDeviceContext::LGMPTimer()
|
||||
ResendCursor();
|
||||
}
|
||||
|
||||
CIndirectDeviceContext::PreparedFrameBuffer CIndirectDeviceContext::PrepareFrameBuffer(int width, int height, int pitch, DXGI_FORMAT format)
|
||||
CIndirectDeviceContext::PreparedFrameBuffer CIndirectDeviceContext::PrepareFrameBuffer(
|
||||
unsigned width, unsigned height, unsigned pitch, DXGI_FORMAT format)
|
||||
{
|
||||
PreparedFrameBuffer result = {};
|
||||
|
||||
if (!m_lgmp || !m_frameQueue)
|
||||
return result;
|
||||
|
||||
if (InterlockedCompareExchange(&m_recoverModeUpdateSwapChain, 0, 0) &&
|
||||
width == m_setMode.width && height == m_setMode.height)
|
||||
InterlockedExchange(&m_recoverModeUpdateSwapChain, 0);
|
||||
|
||||
if (m_width != width || m_height != height || m_pitch != pitch || m_format != format)
|
||||
{
|
||||
m_width = width;
|
||||
|
||||
@@ -79,9 +79,9 @@ private:
|
||||
KVMFRFrame * m_frame [LGMP_Q_FRAME_LEN] = {};
|
||||
FrameBuffer * m_frameBuffer[LGMP_Q_FRAME_LEN] = {};
|
||||
|
||||
int m_width = 0;
|
||||
int m_height = 0;
|
||||
int m_pitch = 0;
|
||||
unsigned m_width = 0;
|
||||
unsigned m_height = 0;
|
||||
unsigned m_pitch = 0;
|
||||
DXGI_FORMAT m_format = DXGI_FORMAT_UNKNOWN;
|
||||
bool m_hasFrame = false;
|
||||
|
||||
@@ -94,12 +94,15 @@ private:
|
||||
void DeInitLGMP();
|
||||
void LGMPTimer();
|
||||
void ResendCursor();
|
||||
bool UpdateMonitorModes();
|
||||
|
||||
CSettings::DisplayModes m_displayModes;
|
||||
CEdid m_edid;
|
||||
|
||||
CSettings::DisplayMode m_setMode;
|
||||
bool m_doSetMode;
|
||||
CSettings::DisplayMode m_setMode = {};
|
||||
bool m_doSetMode = false;
|
||||
volatile LONG m_replugMonitorQueued = 0;
|
||||
volatile LONG m_recoverModeUpdateSwapChain = 0;
|
||||
|
||||
public:
|
||||
CIndirectDeviceContext(_In_ WDFDEVICE wdfDevice) :
|
||||
@@ -116,6 +119,7 @@ public:
|
||||
|
||||
void OnAssignSwapChain();
|
||||
void OnUnassignedSwapChain();
|
||||
void OnSwapChainLost();
|
||||
|
||||
NTSTATUS ParseMonitorDescription(
|
||||
const IDARG_IN_PARSEMONITORDESCRIPTION* inArgs, IDARG_OUT_PARSEMONITORDESCRIPTION* outArgs);
|
||||
@@ -144,7 +148,7 @@ public:
|
||||
uint8_t* mem;
|
||||
};
|
||||
|
||||
PreparedFrameBuffer PrepareFrameBuffer(int width, int height, int pitch, DXGI_FORMAT format);
|
||||
PreparedFrameBuffer PrepareFrameBuffer(unsigned width, unsigned height, unsigned pitch, DXGI_FORMAT format);
|
||||
void WriteFrameBuffer(unsigned frameIndex, void* src, size_t offset, size_t len, bool setWritePos);
|
||||
void FinalizeFrameBuffer(unsigned frameIndex);
|
||||
|
||||
|
||||
@@ -130,6 +130,9 @@ void CSwapChainProcessor::SwapChainThreadCore()
|
||||
UINT lastFrameNumber = 0;
|
||||
for (;;)
|
||||
{
|
||||
if (WaitForSingleObject(m_terminateEvent.Get(), 0) == WAIT_OBJECT_0)
|
||||
break;
|
||||
|
||||
UINT frameNumber = 0;
|
||||
ComPtr<IDXGIResource> surface;
|
||||
|
||||
@@ -193,7 +196,10 @@ void CSwapChainProcessor::SwapChainThreadCore()
|
||||
hr = IddCxSwapChainFinishedProcessingFrame(m_hSwapChain);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DEBUG_ERROR_HR(hr, "IddCxSwapChainFinishedProcessingFrame Failed");
|
||||
if (hr == STATUS_GRAPHICS_PATH_NOT_IN_TOPOLOGY)
|
||||
m_devContext->OnSwapChainLost();
|
||||
else
|
||||
DEBUG_ERROR_HR(hr, "IddCxSwapChainFinishedProcessingFrame Failed");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -201,6 +207,8 @@ void CSwapChainProcessor::SwapChainThreadCore()
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hr == STATUS_GRAPHICS_PATH_NOT_IN_TOPOLOGY)
|
||||
m_devContext->OnSwapChainLost();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -349,8 +357,12 @@ bool CSwapChainProcessor::QueryHWCursor()
|
||||
if (FAILED(status))
|
||||
{
|
||||
// this occurs if the display went away (ie, screen blanking or disabled)
|
||||
if (status == ERROR_GRAPHICS_PATH_NOT_IN_TOPOLOGY)
|
||||
if (status == STATUS_GRAPHICS_PATH_NOT_IN_TOPOLOGY)
|
||||
{
|
||||
m_devContext->OnSwapChainLost();
|
||||
SetEvent(m_terminateEvent.Get());
|
||||
return false;
|
||||
}
|
||||
|
||||
DEBUG_ERROR("IddCxMonitorQueryHardwareCursor failed (0x%08x)", status);
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user