Skip to content

Commit 3750c5e

Browse files
Performance Optimization
Thread Management - Added: Explicit thread completion waiting in IndirectDeviceContext::AssignSwapChain() - Fixed: SwapChainProcessor destructor race conditions - Improved: Thread lifecycle logging and diagnostics Resource Management - Changed: Device cache from std::map<LUID, std::weak_ptr<Direct3DDevice>> to std::map<LUID, std::shared_ptr<Direct3DDevice>> - Added: Comprehensive LUID-based logging for device cache operations - Optimized: Cleanup frequency reduced from every assignment to every 10th assignment Error Handling - Implemented: 5-attempt retry limit with exponential backoff for DXGI_ERROR_ACCESS_LOST - Added: Device integrity validation before swap chain operations - Enhanced: Error logging with detailed HRESULT codes and context
1 parent 14d1e34 commit 3750c5e

2 files changed

Lines changed: 150 additions & 14 deletions

File tree

Virtual Display Driver (HDR)/MttVDD/Driver.cpp

Lines changed: 129 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,9 @@ const char* XorCursorSupportLevelToString(IDDCX_XOR_CURSOR_SUPPORT level) {
152152

153153
vector<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+
155158
struct IndirectDeviceContextWrapper
156159
{
157160
IndirectDeviceContext* pContext;
@@ -2185,6 +2188,10 @@ void SwapChainProcessor::Run()
21852188
void 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

24542563
IndirectDeviceContext::IndirectDeviceContext(_In_ WDFDEVICE WdfDevice) :
24552564
m_WdfDevice(WdfDevice)
@@ -2665,20 +2774,26 @@ void IndirectDeviceContext::CreateMonitor(unsigned int index) {
26652774

26662775
void 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.");

Virtual Display Driver (HDR)/MttVDD/Driver.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
#include <memory>
1616
#include <vector>
17+
#include <map>
18+
#include <mutex>
1719

1820
#include "Trace.h"
1921

@@ -72,6 +74,19 @@ namespace Microsoft
7274
Microsoft::WRL::Wrappers::Event m_hTerminateEvent;
7375
};
7476

77+
/// <summary>
78+
/// Custom comparator for LUID to be used in std::map
79+
/// </summary>
80+
struct LuidComparator
81+
{
82+
bool operator()(const LUID& a, const LUID& b) const
83+
{
84+
if (a.HighPart != b.HighPart)
85+
return a.HighPart < b.HighPart;
86+
return a.LowPart < b.LowPart;
87+
}
88+
};
89+
7590
/// <summary>
7691
/// Provides a sample implementation of an indirect display driver.
7792
/// </summary>
@@ -101,6 +116,12 @@ namespace Microsoft
101116
public:
102117
static const DISPLAYCONFIG_VIDEO_SIGNAL_INFO s_KnownMonitorModes[];
103118
static std::vector<BYTE> s_KnownMonitorEdid;
119+
120+
private:
121+
static std::map<LUID, std::shared_ptr<Direct3DDevice>, LuidComparator> s_DeviceCache;
122+
static std::mutex s_DeviceCacheMutex;
123+
static std::shared_ptr<Direct3DDevice> GetOrCreateDevice(LUID RenderAdapter);
124+
static void CleanupExpiredDevices();
104125
};
105126
}
106127
}

0 commit comments

Comments
 (0)