[idd] driver: improve display mode support and resolution switch

This commit is contained in:
Geoffrey McRae 2025-03-29 22:37:33 +00:00
parent 6396ff1e9c
commit 7afb9b93eb
10 changed files with 194 additions and 60 deletions

View File

@ -28,7 +28,8 @@ struct LGPipeMsg
unsigned size;
enum
{
SETCURSORPOS
SETCURSORPOS,
SETDISPLAYMODE
}
type;
union
@ -39,5 +40,12 @@ struct LGPipeMsg
uint32_t y;
}
curorPos;
struct
{
uint32_t width;
uint32_t height;
}
displayMode;
};
};

View File

@ -42,11 +42,58 @@ static const struct LGMPQueueConfig POINTER_QUEUE_CONFIG =
1000 //subTimeout
};
const DWORD DefaultDisplayModes[][3] =
{
{7680, 4800, 120}, {7680, 4320, 120}, {6016, 3384, 120}, {5760, 3600, 120},
{5760, 3240, 120}, {5120, 2800, 120}, {4096, 2560, 120}, {4096, 2304, 120},
{3840, 2400, 120}, {3840, 2160, 120}, {3200, 2400, 120}, {3200, 1800, 120},
{3008, 1692, 120}, {2880, 1800, 120}, {2880, 1620, 120}, {2560, 1600, 120},
{2560, 1440, 120}, {1920, 1440, 120}, {1920, 1200, 120}, {1920, 1080, 120},
{1600, 1200, 120}, {1600, 1024, 120}, {1600, 1050, 120}, {1600, 900 , 120},
{1440, 900 , 120}, {1400, 1050, 120}, {1366, 768 , 120}, {1360, 768 , 120},
{1280, 1024, 120}, {1280, 960 , 120}, {1280, 800 , 120}, {1280, 768 , 120},
{1280, 720 , 120}, {1280, 600 , 120}, {1152, 864 , 120}, {1024, 768 , 120},
{800 , 600 , 120}, {640 , 480 , 120}
};
static const BYTE EDID[] =
{
0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x30,0xE8,0x34,0x12,0xC9,0x07,0xCC,0x00,
0x01,0x21,0x01,0x04,0xA5,0x3C,0x22,0x78,0xFB,0x6C,0xE5,0xA5,0x55,0x50,0xA0,0x23,
0x0B,0x50,0x54,0x00,0x02,0x00,0xD1,0xC0,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
0x01,0x01,0x01,0x01,0x01,0x01,0x58,0xE3,0x00,0xA0,0xA0,0xA0,0x29,0x50,0x30,0x20,
0x35,0x00,0x55,0x50,0x21,0x00,0x00,0x1A,0x00,0x00,0x00,0xFF,0x00,0x4C,0x6F,0x6F,
0x6B,0x69,0x6E,0x67,0x47,0x6C,0x61,0x73,0x73,0x0A,0x00,0x00,0x00,0xFC,0x00,0x4C,
0x6F,0x6F,0x6B,0x69,0x6E,0x67,0x20,0x47,0x6C,0x61,0x73,0x73,0x00,0x00,0x00,0xFD,
0x00,0x28,0x9B,0xFA,0xFA,0x40,0x01,0x0A,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x4A
};
const DWORD DefaultPreferredDisplayMode = 19;
void CIndirectDeviceContext::PopulateDefaultModes(bool setDefaultMode)
{
m_displayModes.reserve(m_displayModes.size() +
ARRAYSIZE(DefaultDisplayModes));
for (int i = 0; i < ARRAYSIZE(DefaultDisplayModes); ++i)
{
DisplayMode m;
m.width = DefaultDisplayModes[i][0];
m.height = DefaultDisplayModes[i][1];
m.refresh = DefaultDisplayModes[i][2];
m.preferred = setDefaultMode && (i == DefaultPreferredDisplayMode);
m_displayModes.push_back(m);
}
}
void CIndirectDeviceContext::InitAdapter()
{
if (!m_ivshmem.Init() || !m_ivshmem.Open())
return;
m_displayModes.clear();
PopulateDefaultModes(true);
IDDCX_ADAPTER_CAPS caps = {};
caps.Size = sizeof(caps);
@ -114,30 +161,10 @@ void CIndirectDeviceContext::InitAdapter()
}
factory->Release();
// setup some default display modes
DisplayMode m;
m.refresh = 120;
m.width = 800 ; m.height = 600 ; m.preferred = false; m_displayModes.push_back(m);
m.width = 1024; m.height = 768 ; m.preferred = false; m_displayModes.push_back(m);
m.width = 1920; m.height = 1200; m.preferred = true ; m_displayModes.push_back(m);
auto * wrapper = WdfObjectGet_CIndirectDeviceContextWrapper(m_adapter);
wrapper->context = this;
}
static const BYTE EDID[] =
{
0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x30,0xE8,0x34,0x12,0xC9,0x07,0xCC,0x00,
0x01,0x21,0x01,0x04,0xA5,0x3C,0x22,0x78,0xFB,0x6C,0xE5,0xA5,0x55,0x50,0xA0,0x23,
0x0B,0x50,0x54,0x00,0x02,0x00,0xD1,0xC0,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
0x01,0x01,0x01,0x01,0x01,0x01,0x58,0xE3,0x00,0xA0,0xA0,0xA0,0x29,0x50,0x30,0x20,
0x35,0x00,0x55,0x50,0x21,0x00,0x00,0x1A,0x00,0x00,0x00,0xFF,0x00,0x4C,0x6F,0x6F,
0x6B,0x69,0x6E,0x67,0x47,0x6C,0x61,0x73,0x73,0x0A,0x00,0x00,0x00,0xFC,0x00,0x4C,
0x6F,0x6F,0x6B,0x69,0x6E,0x67,0x20,0x47,0x6C,0x61,0x73,0x73,0x00,0x00,0x00,0xFD,
0x00,0x28,0x9B,0xFA,0xFA,0x40,0x01,0x0A,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x4A
};
void CIndirectDeviceContext::FinishInit(UINT connectorIndex)
{
WDF_OBJECT_ATTRIBUTES attr;
@ -210,7 +237,16 @@ void CIndirectDeviceContext::ReplugMonitor()
}
}
void CIndirectDeviceContext::UnassignSwapChain()
void CIndirectDeviceContext::OnAssignSwapChain()
{
if (m_setCustomMode)
{
m_setCustomMode = false;
g_pipe.SetDisplayMode(m_customMode.width, m_customMode.height);
}
}
void CIndirectDeviceContext::OnUnassignedSwapChain()
{
if (m_replugMonitor)
{
@ -300,6 +336,89 @@ NTSTATUS CIndirectDeviceContext::MonitorQueryTargetModes(
return STATUS_SUCCESS;
}
void CIndirectDeviceContext::SetResolution(int width, int height)
{
m_displayModes.clear();
m_customMode.width = width;
m_customMode.height = height;
m_customMode.refresh = 120;
m_customMode.preferred = true;
m_displayModes.push_back(m_customMode);
PopulateDefaultModes(false);
m_setCustomMode = true;
#if 1
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)
{
// this may get called multiple times as we need to delay calling it until
@ -522,14 +641,7 @@ void CIndirectDeviceContext::LGMPTimer()
case KVMFR_MESSAGE_WINDOWSIZE:
{
KVMFRWindowSize* ws = (KVMFRWindowSize*)msg;
m_displayModes.clear();
DisplayMode m;
m.width = ws->w;
m.height = ws->h;
m.refresh = 120;
m.preferred = true;
m_displayModes.push_back(m);
ReplugMonitor();
SetResolution(ws->w, ws->h);
}
}

View File

@ -83,6 +83,8 @@ private:
bool preferred;
};
std::vector<DisplayMode> m_displayModes;
DisplayMode m_customMode = {};
bool m_setCustomMode = false;
public:
CIndirectDeviceContext(_In_ WDFDEVICE wdfDevice) :
@ -92,10 +94,13 @@ public:
bool SetupLGMP(size_t alignSize);
void PopulateDefaultModes(bool setDefaultMode);
void InitAdapter();
void FinishInit(UINT connectorIndex);
void ReplugMonitor();
void UnassignSwapChain();
void OnAssignSwapChain();
void OnUnassignedSwapChain();
NTSTATUS ParseMonitorDescription(
const IDARG_IN_PARSEMONITORDESCRIPTION* inArgs, IDARG_OUT_PARSEMONITORDESCRIPTION* outArgs);
@ -104,6 +109,8 @@ public:
NTSTATUS MonitorQueryTargetModes(
const IDARG_IN_QUERYTARGETMODES* inArgs, IDARG_OUT_QUERYTARGETMODES* outArgs);
void SetResolution(int width, int height);
size_t GetAlignSize() { return m_alignSize; }
size_t GetMaxFrameSize() { return m_maxFrameSize; }

View File

@ -40,7 +40,8 @@ CIndirectMonitorContext::~CIndirectMonitorContext()
void CIndirectMonitorContext::AssignSwapChain(IDDCX_SWAPCHAIN swapChain, LUID renderAdapter, HANDLE newFrameEvent)
{
reInit:
m_swapChain.reset();
UnassignSwapChain();
m_dx11Device = std::make_shared<CD3D11Device>(renderAdapter);
if (FAILED(m_dx11Device->Init()))
{

View File

@ -161,3 +161,16 @@ void CPipeServer::SetCursorPos(uint32_t x, uint32_t y)
msg.curorPos.y = y;
WriteMsg(msg);
}
void CPipeServer::SetDisplayMode(uint32_t width, uint32_t height)
{
if (!m_connected)
return;
LGPipeMsg msg;
msg.size = sizeof(msg);
msg.type = LGPipeMsg::SETDISPLAYMODE;
msg.displayMode.width = width;
msg.displayMode.height = height;
WriteMsg(msg);
}

View File

@ -54,6 +54,7 @@ class CPipeServer
void DeInit();
void SetCursorPos(uint32_t x, uint32_t y);
void SetDisplayMode(uint32_t width, uint32_t height);
};
extern CPipeServer g_pipe;

View File

@ -108,6 +108,7 @@ NTSTATUS LGIddMonitorAssignSwapChain(IDDCX_MONITOR monitor, const IDARG_IN_SETSW
auto * wrapper = WdfObjectGet_CIndirectMonitorContextWrapper(monitor);
wrapper->context->AssignSwapChain(
inArgs->hSwapChain, inArgs->RenderAdapterLuid, inArgs->hNextSurfaceAvailable);
wrapper->context->GetDeviceContext()->OnAssignSwapChain();
return STATUS_SUCCESS;
}
@ -115,7 +116,7 @@ NTSTATUS LGIddMonitorUnassignSwapChain(IDDCX_MONITOR monitor)
{
auto* wrapper = WdfObjectGet_CIndirectMonitorContextWrapper(monitor);
wrapper->context->UnassignSwapChain();
wrapper->context->GetDeviceContext()->UnassignSwapChain();
wrapper->context->GetDeviceContext()->OnUnassignedSwapChain();
return STATUS_SUCCESS;
}

View File

@ -24,33 +24,6 @@
#include <Windows.h>
#if 1
const DWORD DisplayModes[][3] =
{
{7680, 4800, 120}, {7680, 4320, 120}, {6016, 3384, 120}, {5760, 3600, 120},
{5760, 3240, 120}, {5120, 2800, 120}, {4096, 2560, 120}, {4096, 2304, 120},
{3840, 2400, 120}, {3840, 2160, 120}, {3200, 2400, 120}, {3200, 1800, 120},
{3008, 1692, 120}, {2880, 1800, 120}, {2880, 1620, 120}, {2560, 1600, 120},
{2560, 1440, 120}, {1920, 1440, 120}, {1920, 1200, 120}, {1920, 1080, 120},
{1600, 1200, 120}, {1600, 1024, 120}, {1600, 1050, 120}, {1600, 900 , 120},
{1440, 900 , 120}, {1400, 1050, 120}, {1366, 768 , 120}, {1360, 768 , 120},
{1280, 1024, 120}, {1280, 960 , 120}, {1280, 800 , 120}, {1280, 768 , 120},
{1280, 720 , 120}, {1280, 600 , 120}, {1152, 864 , 120}, {1024, 768 , 120},
{800 , 600 , 120}, {640 , 480 , 120}
};
const DWORD PreferredDisplayMode = 19;
#else
const DWORD DisplayModes[][3] =
{
{ 2560, 1440, 144 },
{ 1920, 1080, 60 },
{ 1024, 768, 60 },
};
const DWORD PreferredDisplayMode = 0;
#endif
typedef struct _DEVICE_CONTEXT
{
ULONG PrivateDeviceData; // just a placeholder

View File

@ -211,6 +211,10 @@ void CPipeClient::Thread()
HandleSetCursorPos(msg);
break;
case LGPipeMsg::SETDISPLAYMODE:
HandleSetDisplayMode(msg);
break;
default:
DEBUG_ERROR("Unknown message type %d", msg.type);
break;
@ -229,3 +233,16 @@ void CPipeClient::HandleSetCursorPos(const LGPipeMsg& msg)
SetActiveDesktop();
SetCursorPos(msg.curorPos.x, msg.curorPos.y);
}
void CPipeClient::HandleSetDisplayMode(const LGPipeMsg& msg)
{
DEVMODE dm = {};
dm.dmSize = sizeof(dm);
dm.dmPelsWidth = msg.displayMode.width;
dm.dmPelsHeight = msg.displayMode.height;
dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
LONG result = ChangeDisplaySettingsEx(NULL, &dm, NULL, CDS_UPDATEREGISTRY, NULL);
if (result != DISP_CHANGE_SUCCESSFUL)
DEBUG_ERROR("ChangeDisplaySettingsEx Failed (0x%08x)", result);
}

View File

@ -46,6 +46,7 @@ private:
void SetActiveDesktop();
void HandleSetCursorPos(const LGPipeMsg& msg);
void HandleSetDisplayMode(const LGPipeMsg& msg);
public:
~CPipeClient() { DeInit(); }