DirectX 11多重采样纹理截图黑屏问题求助
问题排查与修复方案
1. 强制GPU同步,确保Resolve操作完成
调用ResolveSubresource后,GPU可能还没完成解析就执行了CopyResource,导致CPU读到空数据。必须添加同步逻辑:
在D3D11CopyMultisampledResource的Resolve调用后插入以下代码:
// 用Fence做精确同步 ID3D11Fence* fence = nullptr; UINT64 fenceValue = 1; if (SUCCEEDED(device->CreateFence(0, D3D11_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence)))) { context->Signal(fence, fenceValue); if (fence->GetCompletedValue() < fenceValue) { HANDLE event = CreateEvent(nullptr, FALSE, FALSE, nullptr); if (event) { fence->SetEventOnCompletion(fenceValue, event); WaitForSingleObject(event, INFINITE); CloseHandle(event); } } fence->Release(); }
2. 修正纹理尺寸获取逻辑
用GetClientRect取窗口尺寸会和实际Backbuffer尺寸不匹配(比如高DPI、窗口缩放场景),直接用SwapChain的BufferDesc获取真实尺寸:
在D3D11TakeScreenshot中替换尺寸获取代码:
// 删掉原窗口尺寸读取代码,替换为: UINT width = swapChainDesc.BufferDesc.Width; UINT height = swapChainDesc.BufferDesc.Height;
3. 调整临时纹理的创建参数
临时纹理需要正确的绑定标志才能支持Resolve操作,同时和CPU访问纹理保持一致的MipLevel数量:
在D3D11CopyMultisampledResource中修改临时纹理的Desc:
desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.MipLevels = 1; // 和CPU访问纹理保持一致 desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; // 必须添加的绑定标志 desc.Usage = D3D11_USAGE_DEFAULT; // 确保是默认用法,支持Resolve
4. 简化Resolve调用
Backbuffer通常是单数组、单MipLevel资源,没必要循环所有层级,直接调用:
context->ResolveSubresource(texTo, 0, texFrom, 0, desc.Format);
5. 确认Hook时机
如果是HookIDXGISwapChain::Present,要在原Present函数执行完成后再截图——Present会交换前后缓冲,此时后台缓冲才是刚渲染完成的帧,提前截图会拿到未完成的空数据。
完整修改后的关键代码片段
修改后的D3D11CopyMultisampledResource
BOOL D3D11CopyMultisampledResource( __in ID3D11Device* device, __in ID3D11DeviceContext* context, __in ID3D11Texture2D* texFrom, __out ID3D11Texture2D** texToOut ) { BOOL result = FALSE; do { D3D11_TEXTURE2D_DESC desc{}; texFrom->GetDesc(&desc); UINT support = NULL; device->CheckFormatSupport(desc.Format, &support); if (!(support & D3D11_FORMAT_SUPPORT_MULTISAMPLE_RESOLVE)) { LOG_ERROR(L"Multisample resolving is not supported."); break; } // 调整临时纹理参数 desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.MipLevels = 1; desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; desc.Usage = D3D11_USAGE_DEFAULT; ID3D11Texture2D* texTo = NULL; HRESULT hr = device->CreateTexture2D(&desc, NULL, &texTo); if (FAILED(hr)) { LOG_ERROR(L"Failed to create temp texture, result %.8x.", hr); break; } // 简化Resolve调用 context->ResolveSubresource(texTo, 0, texFrom, 0, desc.Format); // 同步GPU,确保Resolve完成 ID3D11Fence* fence = nullptr; UINT64 fenceValue = 1; if (SUCCEEDED(device->CreateFence(0, D3D11_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence)))) { context->Signal(fence, fenceValue); if (fence->GetCompletedValue() < fenceValue) { HANDLE event = CreateEvent(nullptr, FALSE, FALSE, nullptr); if (event) { fence->SetEventOnCompletion(fenceValue, event); WaitForSingleObject(event, INFINITE); CloseHandle(event); } } fence->Release(); } *texToOut = texTo; result = TRUE; } while (FALSE); return result; }
额外检查项
- 确保D3D11设备创建时带
D3D11_CREATE_DEVICE_DEBUG标志,调试层能捕获更多潜在错误 - 临时跳过颜色通道转换(直接复制
q[0]-q[3]),排查是否是通道顺序导致的黑屏 - 验证
CAPTURE_HEADER中的宽高和实际纹理尺寸一致,避免后续显示时尺寸不匹配
内容的提问来源于stack exchange,提问作者MoJaal
相关产品推荐
相关产品推荐

