UWP应用切换D3D12设备导致CreateSwapChainForCoreWindow调用失败
D3D12切换设备时创建交换链失败(E_ACCESSDENIED)的解决办法
问题根源
调试层提示的核心信息很明确:同一个窗口、IWindow或合成表面,同一时间只能绑定一个翻转模型交换链。旧交换链的延迟销毁未完成,就会导致新交换链创建失败并返回E_ACCESSDENIED。D3D11里靠ClearState()+Flush()触发销毁,D3D12的处理逻辑类似,但操作步骤不同。
D3D12的等效操作
按以下步骤确保旧交换链彻底销毁:
释放所有旧交换链的引用
清空所有指向旧交换链(包括其后台缓冲区)的指针:- C++中将交换链对象设为
nullptr,WinRT/C#中调用Dispose() - 检查是否有其他对象(如命令列表、资源视图)引用了交换链的缓冲区,一并释放或重置这些对象
- C++中将交换链对象设为
等待GPU完成所有未完成任务
D3D12需要显式等待GPU idle,才能确保旧交换链资源被彻底回收:- 使用
ID3D12CommandQueue::Signal()发送一个fence信号 - 配合
ID3DFence::SetEventOnCompletion()和WaitForSingleObject()等待GPU完成所有命令
示例代码:
UINT64 currentFenceValue = ++m_fenceValue; m_commandQueue->Signal(m_fence.Get(), currentFenceValue); if (m_fence->GetCompletedValue() < currentFenceValue) { HANDLE eventHandle = CreateEvent(nullptr, FALSE, FALSE, nullptr); m_fence->SetEventOnCompletion(currentFenceValue, eventHandle); WaitForSingleObject(eventHandle, INFINITE); CloseHandle(eventHandle); }- 使用
重置DXGI工厂(可选但推荐尝试)
如果前两步后仍失败,可以释放旧DXGI工厂并重新创建实例,彻底清除旧交换链的绑定关系。
额外提醒
- UWP中调用
CreateSwapChainForCoreWindow时,新交换链的参数(如格式、缓冲区数量)尽量与旧交换链兼容,减少不必要的冲突。 - 调试时可通过DXGI调试层检查是否有未释放的交换链引用,执行命令:
dxgiDebug->ReportLiveObjects(DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_ALL)
内容的提问来源于stack exchange,提问作者Christoph
相关产品推荐
相关产品推荐

