@@ -102,6 +102,27 @@ bool preventManufacturerSpoof = false;
102102bool edidCeaOverride = false ;
103103bool sendLogsThroughPipe = true ;
104104
105+ constexpr DISPLAYCONFIG_VIDEO_SIGNAL_INFO dispinfo (UINT32 h, UINT32 v, UINT32 rn, UINT32 rd);
106+
107+ namespace
108+ {
109+ void RebuildKnownMonitorModesCache ()
110+ {
111+ s_KnownMonitorModes2.clear ();
112+ s_KnownMonitorModes2.reserve (monitorModes.size ());
113+
114+ for (const auto & mode : monitorModes)
115+ {
116+ s_KnownMonitorModes2.push_back (
117+ dispinfo (
118+ std::get<0 >(mode),
119+ std::get<1 >(mode),
120+ std::get<2 >(mode),
121+ std::get<3 >(mode)));
122+ }
123+ }
124+ }
125+
105126// Mouse settings
106127bool alphaCursorSupport = true ;
107128int CursorMaxX = 128 ;
@@ -1325,6 +1346,7 @@ bool ApplyEdidProfile(const EdidProfileData& profile) {
13251346 // Validate the final mode list
13261347 if (ValidateModeList (finalModes)) {
13271348 monitorModes = finalModes;
1349+ RebuildKnownMonitorModesCache ();
13281350
13291351 stringstream ss;
13301352 ss << " Enhanced mode management completed:\n "
@@ -1461,6 +1483,14 @@ void SendToPipe(const std::string& logMessage) {
14611483}
14621484
14631485void vddlog (const char * type, const char * message) {
1486+ if (!logsEnabled) {
1487+ return ;
1488+ }
1489+
1490+ if (type != nullptr && type[0 ] == ' d' && !debugLogs) {
1491+ return ;
1492+ }
1493+
14641494 FILE* logFile;
14651495 wstring logsDir = confpath + L" \\ Logs" ;
14661496
@@ -1473,30 +1503,8 @@ void vddlog(const char* type, const char* message) {
14731503
14741504 wstring logPath = logsDir + L" \\ log_" + date_str + L" .txt" ;
14751505
1476- if (logsEnabled) {
1477- if (!CreateDirectoryW (logsDir.c_str (), NULL ) && GetLastError () != ERROR_ALREADY_EXISTS) {
1478- // Just any errors here
1479- }
1480- }
1481- else {
1482- WIN32_FIND_DATAW findFileData;
1483- HANDLE hFind = FindFirstFileW ((logsDir + L" \\ *" ).c_str (), &findFileData);
1484-
1485- if (hFind != INVALID_HANDLE_VALUE) {
1486- do {
1487- const wstring fileOrDir = findFileData.cFileName ;
1488- if (fileOrDir != L" ." && fileOrDir != L" .." ) {
1489- wstring filePath = logsDir + L" \\ " + fileOrDir;
1490- if (!(findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
1491- DeleteFileW (filePath.c_str ());
1492- }
1493- }
1494- } while (FindNextFileW (hFind, &findFileData) != 0 );
1495- FindClose (hFind);
1496- }
1497-
1498- RemoveDirectoryW (logsDir.c_str ());
1499- return ;
1506+ if (!CreateDirectoryW (logsDir.c_str (), NULL ) && GetLastError () != ERROR_ALREADY_EXISTS) {
1507+ // Best effort only.
15001508 }
15011509
15021510 string narrow_logPath = WStringToString (logPath);
@@ -1506,8 +1514,9 @@ void vddlog(const char* type, const char* message) {
15061514 stringstream ss;
15071515 ss << put_time (&tm_buf, " %Y-%m-%d %X" );
15081516
1517+ const char logTypeCode = (type != nullptr ) ? type[0 ] : ' \0 ' ;
15091518 string logType;
1510- switch (type[ 0 ] ) {
1519+ switch (logTypeCode ) {
15111520 case ' e' :
15121521 logType = " ERROR" ;
15131522 break ;
@@ -1534,21 +1543,13 @@ void vddlog(const char* type, const char* message) {
15341543 break ;
15351544 }
15361545
1537- bool shouldLog = true ;
1538- if (logType == " DEBUG" && !debugLogs) {
1539- shouldLog = false ;
1540- }
1541- if (shouldLog) {
1542- fprintf (logFile, " [%s] [%s] %s\n " , ss.str ().c_str (), logType.c_str (), message);
1543- }
1546+ fprintf (logFile, " [%s] [%s] %s\n " , ss.str ().c_str (), logType.c_str (), message);
15441547
15451548 fclose (logFile);
15461549
15471550 if (sendLogsThroughPipe && g_pipeHandle != INVALID_HANDLE_VALUE) {
15481551 string logMessage = ss.str () + " [" + logType + " ] " + message + " \n " ;
1549- DWORD bytesWritten;
1550- DWORD logMessageSize = static_cast <DWORD>(logMessage.size ());
1551- WriteFile (g_pipeHandle, logMessage.c_str (), logMessageSize, &bytesWritten, NULL );
1552+ SendToPipe (logMessage);
15521553 }
15531554 }
15541555}
@@ -2685,6 +2686,7 @@ void loadSettings() {
26852686 numVirtualDisplays = monitorcount;
26862687 gpuname = gpuFriendlyName;
26872688 monitorModes = res;
2689+ RebuildKnownMonitorModesCache ();
26882690
26892691 // === APPLY EDID INTEGRATION ===
26902692 if (edidIntegrationEnabled && autoConfigureFromEdid) {
@@ -2726,6 +2728,7 @@ void loadSettings() {
27262728
27272729 vddlog (" i" , " Using option.txt" );
27282730 monitorModes = res;
2731+ RebuildKnownMonitorModesCache ();
27292732 for (const auto & mode : res) {
27302733 int width, height, vsync_num, vsync_den;
27312734 tie (width, height, vsync_num, vsync_den) = mode;
@@ -2800,6 +2803,7 @@ void loadSettings() {
28002803 }
28012804
28022805 monitorModes = res;
2806+ RebuildKnownMonitorModesCache ();
28032807 return ;
28042808
28052809}
@@ -3328,33 +3332,46 @@ void SwapChainProcessor::RunCore()
33283332 logStream.str (" " );
33293333 if (hr == E_PENDING)
33303334 {
3331- // We must wait for a new buffer
3332- HANDLE WaitHandles[] =
3335+ HANDLE waitHandles[2 ] = {};
3336+ DWORD waitHandleCount = 0 ;
3337+
3338+ if (m_hAvailableBufferEvent != nullptr && m_hAvailableBufferEvent != INVALID_HANDLE_VALUE)
3339+ {
3340+ waitHandles[waitHandleCount++] = m_hAvailableBufferEvent;
3341+ }
3342+
3343+ if (m_hTerminateEvent.Get ())
33333344 {
3334- m_hAvailableBufferEvent,
3335- m_hTerminateEvent.Get ()
3336- };
3337- DWORD WaitResult = WaitForMultipleObjects (ARRAYSIZE (WaitHandles), WaitHandles, FALSE , 100 );
3345+ waitHandles[waitHandleCount++] = m_hTerminateEvent.Get ();
3346+ }
3347+
3348+ if (waitHandleCount == 0 )
3349+ {
3350+ vddlog (" e" , " No valid wait handles available while waiting for the next frame." );
3351+ break ;
3352+ }
3353+
3354+ DWORD WaitResult = WaitForMultipleObjects (waitHandleCount, waitHandles, FALSE , INFINITE);
33383355
33393356 logStream << " Buffer acquisition pending. WaitResult: " << WaitResult;
33403357
3341- if (WaitResult == WAIT_OBJECT_0 || WaitResult == WAIT_TIMEOUT )
3358+ if (WaitResult == WAIT_OBJECT_0)
33423359 {
3343- // We have a new buffer, so try the AcquireBuffer again
3344- // vddlog("d", "New buffer trying aquire new buffer");
33453360 continue ;
33463361 }
3347- else if (WaitResult == WAIT_OBJECT_0 + 1 )
3362+ else if (waitHandleCount > 1 && WaitResult == WAIT_OBJECT_0 + 1 )
3363+ {
3364+ logStream << " Terminate event signaled. Exiting loop." ;
3365+ break ;
3366+ }
3367+ else if (waitHandleCount == 1 && waitHandles[0 ] == m_hTerminateEvent.Get () && WaitResult == WAIT_OBJECT_0)
33483368 {
3349- // We need to terminate
33503369 logStream << " Terminate event signaled. Exiting loop." ;
3351- // vddlog("d", logStream.str().c_str());
33523370 break ;
33533371 }
33543372 else
33553373 {
3356- // The wait was cancelled or something unexpected happened
3357- hr = HRESULT_FROM_WIN32 (WaitResult);
3374+ hr = HRESULT_FROM_WIN32 (WaitResult == WAIT_FAILED ? GetLastError () : WaitResult);
33583375 logStream << " Unexpected wait result. HRESULT: " << hr;
33593376 vddlog (" e" , logStream.str ().c_str ());
33603377 break ;
@@ -3649,14 +3666,18 @@ IndirectDeviceContext::IndirectDeviceContext(_In_ WDFDEVICE WdfDevice) :
36493666IndirectDeviceContext::~IndirectDeviceContext ()
36503667{
36513668 stringstream logStream;
3669+ std::map<IDDCX_MONITOR, std::unique_ptr<SwapChainProcessor>> processingThreads;
36523670
3653- logStream << " Destroying IndirectDeviceContext. Resetting processing thread ." ;
3671+ logStream << " Destroying IndirectDeviceContext. Releasing per-monitor processing threads ." ;
36543672 vddlog (" d" , logStream.str ().c_str ());
36553673
3656- m_ProcessingThread.reset ();
3674+ {
3675+ std::lock_guard<std::mutex> lock (m_ProcessingThreadsMutex);
3676+ processingThreads.swap (m_ProcessingThreads);
3677+ }
36573678
36583679 logStream.str (" " );
3659- logStream << " Processing thread has been reset ." ;
3680+ logStream << " Released " << processingThreads. size () << " monitor processing thread(s) ." ;
36603681 vddlog (" d" , logStream.str ().c_str ());
36613682}
36623683
@@ -3852,15 +3873,8 @@ void IndirectDeviceContext::CreateMonitor(unsigned int index) {
38523873 }
38533874}
38543875
3855- void IndirectDeviceContext::AssignSwapChain (IDDCX_MONITOR& Monitor, IDDCX_SWAPCHAIN SwapChain, LUID RenderAdapter, HANDLE NewFrameEvent)
3876+ void IndirectDeviceContext::AssignSwapChain (IDDCX_MONITOR Monitor, IDDCX_SWAPCHAIN SwapChain, LUID RenderAdapter, HANDLE NewFrameEvent)
38563877{
3857- // Properly wait for existing thread to complete before creating new one
3858- if (m_ProcessingThread) {
3859- vddlog (" d" , " Waiting for existing processing thread to complete before reassignment." );
3860- m_ProcessingThread.reset (); // This will call destructor which waits for thread completion
3861- vddlog (" d" , " Existing processing thread completed." );
3862- }
3863-
38643878 // Only cleanup expired devices periodically, not on every assignment
38653879 static int assignmentCount = 0 ;
38663880 if (++assignmentCount % 10 == 0 ) {
@@ -3876,8 +3890,22 @@ void IndirectDeviceContext::AssignSwapChain(IDDCX_MONITOR& Monitor, IDDCX_SWAPCH
38763890 }
38773891 else
38783892 {
3879- vddlog (" d" , " Creating a new swap-chain processing thread." );
3880- m_ProcessingThread.reset (new SwapChainProcessor (SwapChain, Device, NewFrameEvent));
3893+ std::unique_ptr<SwapChainProcessor> previousProcessor;
3894+ auto newProcessor = std::make_unique<SwapChainProcessor>(SwapChain, Device, NewFrameEvent);
3895+
3896+ {
3897+ std::lock_guard<std::mutex> lock (m_ProcessingThreadsMutex);
3898+ auto & processorSlot = m_ProcessingThreads[Monitor];
3899+ previousProcessor = std::move (processorSlot);
3900+ processorSlot = std::move (newProcessor);
3901+ }
3902+
3903+ if (previousProcessor) {
3904+ vddlog (" d" , " Replaced existing processing thread for this monitor only." );
3905+ }
3906+ else {
3907+ vddlog (" d" , " Created a new processing thread for this monitor." );
3908+ }
38813909
38823910 if (hardwareCursor){
38833911 HANDLE mouseEvent = CreateEventA (
@@ -3930,11 +3958,28 @@ void IndirectDeviceContext::AssignSwapChain(IDDCX_MONITOR& Monitor, IDDCX_SWAPCH
39303958}
39313959
39323960
3933- void IndirectDeviceContext::UnassignSwapChain ()
3961+ void IndirectDeviceContext::UnassignSwapChain (IDDCX_MONITOR Monitor )
39343962{
3935- // Stop processing the last swap-chain
3936- vddlog (" i" , " Unasigning Swapchain. Processing will be stopped." );
3937- m_ProcessingThread.reset ();
3963+ std::unique_ptr<SwapChainProcessor> processorToStop;
3964+
3965+ {
3966+ std::lock_guard<std::mutex> lock (m_ProcessingThreadsMutex);
3967+ auto it = m_ProcessingThreads.find (Monitor);
3968+ if (it != m_ProcessingThreads.end ())
3969+ {
3970+ processorToStop = std::move (it->second );
3971+ m_ProcessingThreads.erase (it);
3972+ }
3973+ }
3974+
3975+ if (processorToStop)
3976+ {
3977+ vddlog (" i" , " Unassigning swapchain for one monitor. Its processing thread will be stopped." );
3978+ }
3979+ else
3980+ {
3981+ vddlog (" w" , " UnassignSwapChain called for a monitor without an active processing thread." );
3982+ }
39383983}
39393984
39403985#pragma endregion
@@ -3993,9 +4038,7 @@ NTSTATUS VirtualDisplayDriverParseMonitorDescription(const IDARG_IN_PARSEMONITOR
39934038 logStream << " Parsing monitor description. Input buffer count: " << pInArgs->MonitorModeBufferInputCount ;
39944039 vddlog (" d" , logStream.str ().c_str ());
39954040
3996- for (int i = 0 ; i < monitorModes.size (); i++) {
3997- s_KnownMonitorModes2.push_back (dispinfo (std::get<0 >(monitorModes[i]), std::get<1 >(monitorModes[i]), std::get<2 >(monitorModes[i]), std::get<3 >(monitorModes[i])));
3998- }
4041+ RebuildKnownMonitorModesCache ();
39994042 pOutArgs->MonitorModeBufferOutputCount = (UINT)monitorModes.size ();
40004043
40014044 logStream.str (" " );
@@ -4194,7 +4237,7 @@ NTSTATUS VirtualDisplayDriverMonitorUnassignSwapChain(IDDCX_MONITOR MonitorObjec
41944237 logStream << " Unassigning swap chain for monitor object: " << MonitorObject;
41954238 vddlog (" d" , logStream.str ().c_str ());
41964239 auto * pContext = WdfObjectGet_IndirectDeviceContextWrapper (MonitorObject);
4197- pContext->pContext ->UnassignSwapChain ();
4240+ pContext->pContext ->UnassignSwapChain (MonitorObject );
41984241 vddlog (" d" , " Swap chain unassigned successfully." );
41994242 return STATUS_SUCCESS;
42004243}
@@ -4360,9 +4403,7 @@ NTSTATUS VirtualDisplayDriverEvtIddCxParseMonitorDescription2(
43604403 }
43614404 vddlog (" d" , logStream.str ().c_str ());
43624405
4363- for (int i = 0 ; i < monitorModes.size (); i++) {
4364- s_KnownMonitorModes2.push_back (dispinfo (std::get<0 >(monitorModes[i]), std::get<1 >(monitorModes[i]), std::get<2 >(monitorModes[i]), std::get<3 >(monitorModes[i])));
4365- }
4406+ RebuildKnownMonitorModesCache ();
43664407 pOutArgs->MonitorModeBufferOutputCount = (UINT)monitorModes.size ();
43674408
43684409 if (pInArgs->MonitorModeBufferInputCount < monitorModes.size ())
0 commit comments