DirectX 11 屏幕截图、多重采样纹理、黑屏问题

问题描述 投票:0回答:0

我正在尝试通过 Present 挂钩获取 DirectX 11 屏幕截图。 Backbuffer 是多重采样的,我使用 ResolveSubresource 但仍然出现黑屏。尝试了 ResolveSubresource 调用的变体,结果相同。尝试启用调试层,没有有关 CopyResource 或 ResolveSubresource 调用的消息。这是代码,感谢任何帮助。

BOOL
D3D11CreateTextureCopyWithCPUAccess(
    __in ID3D11Device* dev,
    __in ID3D11Texture2D* texFrom,
    __out ID3D11Texture2D** cpuAccessTexOut
)
{
    BOOL result = FALSE;

    do {

        if (!dev || !texFrom || !cpuAccessTexOut) break;

        D3D11_TEXTURE2D_DESC texFromDesc{};

        texFrom->GetDesc(&texFromDesc);

        LOG_DEBUG(
            L"Texture format %d, sample count %d, usage %d, array size %d, mips levels %d, bind flags %.8x, misc flags %.8x.", 
            texFromDesc.Format, 
            texFromDesc.SampleDesc.Count,
            texFromDesc.Usage,
            texFromDesc.ArraySize,
            texFromDesc.MipLevels,
            texFromDesc.BindFlags,
            texFromDesc.MiscFlags
        );

        D3D11_TEXTURE2D_DESC cpuAccessTexDesc{};

        cpuAccessTexDesc.Width = texFromDesc.Width;
        cpuAccessTexDesc.Height = texFromDesc.Height;
        cpuAccessTexDesc.Format = texFromDesc.Format;
        cpuAccessTexDesc.ArraySize = 1;
        cpuAccessTexDesc.BindFlags = 0;
        cpuAccessTexDesc.MiscFlags = 0;
        cpuAccessTexDesc.SampleDesc.Count = 1;
        cpuAccessTexDesc.SampleDesc.Quality = 0;
        cpuAccessTexDesc.MipLevels = 1;
        cpuAccessTexDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
        cpuAccessTexDesc.Usage = D3D11_USAGE_STAGING;

        ID3D11Texture2D* cpuAccessTex = nullptr;

        HRESULT hr = dev->CreateTexture2D(&cpuAccessTexDesc, nullptr, &cpuAccessTex);

        if (FAILED(hr)) {
            LOG_ERROR(L"CreateTexture2D failed, result %.8x.", hr);
            break;
        }

        *cpuAccessTexOut = cpuAccessTex;

        result = TRUE;

    } while (FALSE);


    return result;
}

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;

        ID3D11Texture2D* texTo = NULL;

        HRESULT result = device->CreateTexture2D(&desc, NULL, &texTo);

        if (FAILED(result)) {
            LOG_ERROR(L"Failed to create temp texture, result %.8x.", result);
            break;
        }

        for (ULONG item = 0; item < desc.ArraySize; ++item) {
            for (ULONG level = 0; level < desc.MipLevels; ++level) {
                ULONG index = D3D11CalcSubresource(level, item, desc.MipLevels);
                context->ResolveSubresource(texTo, index, texFrom, index, desc.Format);
            }
        }

        //context->ResolveSubresource(texTo, 0, texFrom, 0, desc.Format);
        *texToOut = texTo;

        result = TRUE;

    } while (FALSE);

    return result;
}

BOOL
D3D11TakeScreenshot(
    IDXGISwapChain* swapChain,
    CAPTURE_HEADER** screenshotOut
)
{
    BOOL result = FALSE;
    ID3D11Device* device = NULL;
    ID3D11DeviceContext* context = NULL;
    ID3D11Texture2D* backBuffer = NULL;
    ID3D11Texture2D* tempTex = NULL;
    ID3D11Texture2D* cpuAccessTex = NULL;

    do {

        if (!swapChain) break;

        DXGI_SWAP_CHAIN_DESC swapChainDesc = {0};

        swapChain->GetDesc(&swapChainDesc);

        RECT rect = {0};

        GetClientRect(swapChainDesc.OutputWindow, &rect);

        UINT width = rect.right - rect.left;
        UINT height = rect.bottom - rect.top;

        HRESULT hr = swapChain->GetDevice(__uuidof(ID3D11Device), (void**)&device);

        if (FAILED(hr)) {
            LOG_ERROR(L"IDXGISwapChain::GetDevice failed, result %.8x.", hr);
            break;
        }

        device->GetImmediateContext(&context);

        hr = swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&backBuffer);

        if (FAILED(hr)) {
            LOG_ERROR(L"IDXGISwapChain::GetBuffer failed, result %.8x.", hr);
            break;
        }

        if (!D3D11CreateTextureCopyWithCPUAccess(device, backBuffer, &cpuAccessTex)) {
            LOG_ERROR(L"D3D11CreateTextureCopyWithCPUAccess failed.");
            break;
        }

        D3D11_TEXTURE2D_DESC desc = {0};

        backBuffer->GetDesc(&desc);

        if (desc.SampleDesc.Count > 1) {
            LOG_DEBUG(L"Multisampled source.");
            if (D3D11CopyMultisampledResource(device, context, backBuffer, &tempTex)) {
                context->CopyResource(cpuAccessTex, tempTex);
            }
        } else {
            context->CopyResource(cpuAccessTex, backBuffer);
        }

        D3D11_MAPPED_SUBRESOURCE res{};

        hr = context->Map(cpuAccessTex, 0, D3D11_MAP_READ, 0, &res);

        if (FAILED(hr)) {
            LOG_ERROR(L"Map failed, result %.8x", hr);
            break;
        }

        VOID* buf = MemAllocVirtual(
            NULL,
            sizeof(CAPTURE_HEADER) + height * res.RowPitch,
            MEM_COMMIT | MEM_RESERVE,
            PAGE_READWRITE
        );

        if (!buf) {
            LOG_ERROR(L"VirtualAlloc failed, error %.8x.", GetLastError());
            break;
        }

        CAPTURE_HEADER* hdr = (CAPTURE_HEADER*)buf;

        hdr->success = 1;
        hdr->type = CaptureType_DirectX;
        hdr->cx = width;
        hdr->cy = height;
        hdr->pitch = res.RowPitch;
        
        PUCHAR p = (PUCHAR)buf + sizeof(CAPTURE_HEADER);

        for (ULONG i = 0; i < height; i++) {
            for (ULONG j = 0; j < res.RowPitch / sizeof(ULONG); j++) {
                PUCHAR q = ((PUCHAR)res.pData + i * res.RowPitch + j * 4);
                *p++ = q[2];
                *p++ = q[1];
                *p++ = q[0];
                *p++ = q[3];
            }
        }

        LOG_DEBUG(L"DX11 Screenshot taken %d:%d.", width, height);

        *screenshotOut = hdr;

        result = TRUE;
        
    } while (FALSE);

    if (tempTex) tempTex->Release();

    if (cpuAccessTex) {
        if (context) context->Unmap(cpuAccessTex, 0);
        cpuAccessTex->Release();
    }

    if (backBuffer) {
        backBuffer->Release();
    }

    if (context) {
        context->Release();
    }

    if (device) {
        device->Release();
    }
    
    return result;
}

directx directx-11 screen-capture
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.