You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 15:02:32