@@ -152,6 +152,9 @@ const char* XorCursorSupportLevelToString(IDDCX_XOR_CURSOR_SUPPORT level) {
152152
153153vector<unsigned char > Microsoft::IndirectDisp::IndirectDeviceContext::s_KnownMonitorEdid; // Changed to support static vector
154154
155+ std::map<LUID, std::shared_ptr<Direct3DDevice>, Microsoft::IndirectDisp::LuidComparator> Microsoft::IndirectDisp::IndirectDeviceContext::s_DeviceCache;
156+ std::mutex Microsoft::IndirectDisp::IndirectDeviceContext::s_DeviceCacheMutex;
157+
155158struct IndirectDeviceContextWrapper
156159{
157160 IndirectDeviceContext* pContext;
@@ -2185,6 +2188,10 @@ void SwapChainProcessor::Run()
21852188void SwapChainProcessor::RunCore ()
21862189{
21872190 stringstream logStream;
2191+ DWORD retryDelay = 1 ;
2192+ const DWORD maxRetryDelay = 100 ;
2193+ int retryCount = 0 ;
2194+ const int maxRetries = 5 ;
21882195
21892196 // Get the DXGI device interface
21902197 ComPtr<IDXGIDevice> DxgiDevice;
@@ -2199,6 +2206,12 @@ void SwapChainProcessor::RunCore()
21992206 // vddlog("d", logStream.str().c_str());
22002207
22012208
2209+ // Validate that our device is still valid before setting it
2210+ if (!m_Device || !m_Device->Device ) {
2211+ vddlog (" e" , " Direct3DDevice became invalid during SwapChain processing" );
2212+ return ;
2213+ }
2214+
22022215 IDARG_IN_SWAPCHAINSETDEVICE SetDevice = {};
22032216 SetDevice.pDevice = DxgiDevice.Get ();
22042217
@@ -2248,7 +2261,7 @@ void SwapChainProcessor::RunCore()
22482261 m_hAvailableBufferEvent,
22492262 m_hTerminateEvent.Get ()
22502263 };
2251- DWORD WaitResult = WaitForMultipleObjects (ARRAYSIZE (WaitHandles), WaitHandles, FALSE , 16 );
2264+ DWORD WaitResult = WaitForMultipleObjects (ARRAYSIZE (WaitHandles), WaitHandles, FALSE , 100 );
22522265
22532266 logStream << " Buffer acquisition pending. WaitResult: " << WaitResult;
22542267
@@ -2276,6 +2289,10 @@ void SwapChainProcessor::RunCore()
22762289 }
22772290 else if (SUCCEEDED (hr))
22782291 {
2292+ // Reset retry delay and count on successful buffer acquisition
2293+ retryDelay = 1 ;
2294+ retryCount = 0 ;
2295+
22792296 AcquiredBuffer.Attach (pSurface);
22802297
22812298 // ==============================
@@ -2307,10 +2324,29 @@ void SwapChainProcessor::RunCore()
23072324 else
23082325 {
23092326 logStream.str (" " ); // Clear the stream
2310- logStream << " Failed to acquire buffer. Exiting loop. The swap-chain was likely abandoned (e.g. DXGI_ERROR_ACCESS_LOST) - HRESULT: " << hr;
2311- vddlog (" e" , logStream.str ().c_str ());
2312- // The swap-chain was likely abandoned (e.g. DXGI_ERROR_ACCESS_LOST), so exit the processing loop
2313- break ;
2327+ if (hr == DXGI_ERROR_ACCESS_LOST && retryCount < maxRetries)
2328+ {
2329+ logStream << " DXGI_ERROR_ACCESS_LOST detected. Retry " << (retryCount + 1 ) << " /" << maxRetries << " after " << retryDelay << " ms delay." ;
2330+ vddlog (" w" , logStream.str ().c_str ());
2331+ Sleep (retryDelay);
2332+ retryDelay = min (retryDelay * 2 , maxRetryDelay);
2333+ retryCount++;
2334+ continue ;
2335+ }
2336+ else
2337+ {
2338+ if (hr == DXGI_ERROR_ACCESS_LOST)
2339+ {
2340+ logStream << " DXGI_ERROR_ACCESS_LOST: Maximum retries (" << maxRetries << " ) reached. Exiting loop." ;
2341+ }
2342+ else
2343+ {
2344+ logStream << " Failed to acquire buffer. Exiting loop. HRESULT: " << hr;
2345+ }
2346+ vddlog (" e" , logStream.str ().c_str ());
2347+ // The swap-chain was likely abandoned, so exit the processing loop
2348+ break ;
2349+ }
23142350 }
23152351 }
23162352}
@@ -2449,7 +2485,80 @@ int maincalc() {
24492485 return 0 ;
24502486}
24512487
2488+ std::shared_ptr<Direct3DDevice> IndirectDeviceContext::GetOrCreateDevice (LUID RenderAdapter)
2489+ {
2490+ std::shared_ptr<Direct3DDevice> Device;
2491+ stringstream logStream;
24522492
2493+ logStream << " GetOrCreateDevice called for LUID: " << RenderAdapter.HighPart << " -" << RenderAdapter.LowPart ;
2494+ vddlog (" d" , logStream.str ().c_str ());
2495+
2496+ {
2497+ std::lock_guard<std::mutex> lock (s_DeviceCacheMutex);
2498+
2499+ logStream.str (" " );
2500+ logStream << " Device cache size: " << s_DeviceCache.size ();
2501+ vddlog (" d" , logStream.str ().c_str ());
2502+
2503+ auto it = s_DeviceCache.find (RenderAdapter);
2504+ if (it != s_DeviceCache.end ()) {
2505+ Device = it->second ;
2506+ if (Device) {
2507+ logStream.str (" " );
2508+ logStream << " Reusing cached Direct3DDevice for LUID " << RenderAdapter.HighPart << " -" << RenderAdapter.LowPart ;
2509+ vddlog (" d" , logStream.str ().c_str ());
2510+ return Device;
2511+ } else {
2512+ logStream.str (" " );
2513+ logStream << " Cached Direct3DDevice is null for LUID " << RenderAdapter.HighPart << " -" << RenderAdapter.LowPart << " , removing from cache" ;
2514+ vddlog (" d" , logStream.str ().c_str ());
2515+ s_DeviceCache.erase (it);
2516+ }
2517+ }
2518+ }
2519+
2520+ logStream.str (" " );
2521+ logStream << " Creating new Direct3DDevice for LUID " << RenderAdapter.HighPart << " -" << RenderAdapter.LowPart ;
2522+ vddlog (" d" , logStream.str ().c_str ());
2523+
2524+ Device = make_shared<Direct3DDevice>(RenderAdapter);
2525+ if (FAILED (Device->Init ())) {
2526+ vddlog (" e" , " Failed to initialize new Direct3DDevice" );
2527+ return nullptr ;
2528+ }
2529+
2530+ {
2531+ std::lock_guard<std::mutex> lock (s_DeviceCacheMutex);
2532+ s_DeviceCache[RenderAdapter] = Device;
2533+ logStream.str (" " );
2534+ logStream << " Created and cached new Direct3DDevice for LUID " << RenderAdapter.HighPart << " -" << RenderAdapter.LowPart << " (cache size now: " << s_DeviceCache.size () << " )" ;
2535+ vddlog (" d" , logStream.str ().c_str ());
2536+ }
2537+
2538+ return Device;
2539+ }
2540+
2541+ void IndirectDeviceContext::CleanupExpiredDevices ()
2542+ {
2543+ std::lock_guard<std::mutex> lock (s_DeviceCacheMutex);
2544+
2545+ int removed = 0 ;
2546+ for (auto it = s_DeviceCache.begin (); it != s_DeviceCache.end ();) {
2547+ // With shared_ptr cache, we only remove null devices (shouldn't happen)
2548+ if (!it->second ) {
2549+ it = s_DeviceCache.erase (it);
2550+ removed++;
2551+ } else {
2552+ ++it;
2553+ }
2554+ }
2555+
2556+ if (removed > 0 ) {
2557+ stringstream logStream;
2558+ logStream << " Cleaned up " << removed << " null Direct3DDevice references from cache" ;
2559+ vddlog (" d" , logStream.str ().c_str ());
2560+ }
2561+ }
24532562
24542563IndirectDeviceContext::IndirectDeviceContext (_In_ WDFDEVICE WdfDevice) :
24552564 m_WdfDevice(WdfDevice)
@@ -2665,20 +2774,26 @@ void IndirectDeviceContext::CreateMonitor(unsigned int index) {
26652774
26662775void IndirectDeviceContext::AssignSwapChain (IDDCX_MONITOR& Monitor, IDDCX_SWAPCHAIN SwapChain, LUID RenderAdapter, HANDLE NewFrameEvent)
26672776{
2668- m_ProcessingThread.reset ();
2777+ // Properly wait for existing thread to complete before creating new one
2778+ if (m_ProcessingThread) {
2779+ vddlog (" d" , " Waiting for existing processing thread to complete before reassignment." );
2780+ m_ProcessingThread.reset (); // This will call destructor which waits for thread completion
2781+ vddlog (" d" , " Existing processing thread completed." );
2782+ }
2783+
2784+ // Only cleanup expired devices periodically, not on every assignment
2785+ static int assignmentCount = 0 ;
2786+ if (++assignmentCount % 10 == 0 ) {
2787+ CleanupExpiredDevices ();
2788+ }
26692789
2670- auto Device = make_shared<Direct3DDevice> (RenderAdapter);
2671- if (FAILED ( Device-> Init ()) )
2790+ auto Device = GetOrCreateDevice (RenderAdapter);
2791+ if (! Device)
26722792 {
2673- vddlog (" e" , " D3D Initialization failed , deleting existing swap-chain." );
2793+ vddlog (" e" , " Failed to get or create Direct3DDevice , deleting existing swap-chain." );
26742794 WdfObjectDelete (SwapChain);
26752795 return ;
26762796 }
2677- HRESULT hr = Device->Init ();
2678- if (FAILED (hr))
2679- {
2680- vddlog (" e" , " Failed to initialize Direct3DDevice." );
2681- }
26822797 else
26832798 {
26842799 vddlog (" d" , " Creating a new swap-chain processing thread." );
0 commit comments