检索要通过网络发送的 ID3D11Texture2D 数据

Retrieving ID3D11Texture2D data to be sent over network

我正在修改桌面复制 api 示例 kindly provided by Microsoft 以捕获屏幕并通过网络将更新发送到我的应用程序。我知道如何实际发送数据;我的问题是从 ID3D11Texture2D 对象获取数据。

ID3D11Texture2D* m_AcquiredDesktopImage;
IDXGIResource* desktopResource = nullptr;
DXGI_OUTDUPL_FRAME_INFO FrameInfo;

// Get new frame
HRESULT hr = m_DeskDupl->AcquireNextFrame(500, &FrameInfo, &desktopResource);

// QI for IDXGIResource
hr = desktopResource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void **>(&m_AcquiredDesktopImage));

此时,我认为屏幕更新在 m_AcquiredDesktopImage。我需要通过网络传输这些数据(尽可能高效)。

This answer 似乎是在正确的轨道上,但我是 Windows 编程的新手,所以我需要一些额外的帮助。

这是我能想到的唯一利用 IDXGIObject::GetPrivateData

的解决方案

私人数据根本不是您要找的。它们只是在这里将自定义值附加到 d3d 对象。

一旦你有了需要从中读回图像的 ID3D11Texture2D 对象,你需要从 ID3D11Device 在暂存内存池中创建第二个对象(获取原始描述,更改池,并删除绑定)。

然后,您需要使用 ID3D11DeviceContext 将纹理复制到使用 CopyResource 的暂存纹理。然后你可以使用上下文 MapUnmap api 来读取图像。

我有一个很好的 link 可以做到这一点.. 寻找方法 SaveTextureToBmp

[...]

// map the texture
ComPtr<ID3D11Texture2D> mappedTexture;
D3D11_MAPPED_SUBRESOURCE mapInfo;
mapInfo.RowPitch;
hr = d3dContext->Map(
        Texture,
        0,  // Subresource
        D3D11_MAP_READ,
        0,  // MapFlags
        &mapInfo);

if (FAILED(hr)) {
    // If we failed to map the texture, copy it to a staging resource
    if (hr == E_INVALIDARG) {
        D3D11_TEXTURE2D_DESC desc2;
        desc2.Width = desc.Width;
        desc2.Height = desc.Height;
        desc2.MipLevels = desc.MipLevels;
        desc2.ArraySize = desc.ArraySize;
        desc2.Format = desc.Format;
        desc2.SampleDesc = desc.SampleDesc;
        desc2.Usage = D3D11_USAGE_STAGING;
        desc2.BindFlags = 0;
        desc2.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
        desc2.MiscFlags = 0;

        ComPtr<ID3D11Texture2D> stagingTexture;
        hr = d3dDevice->CreateTexture2D(&desc2, nullptr, &stagingTexture);
        if (FAILED(hr)) {
            throw MyException::Make(hr, L"Failed to create staging texture");
        }

        // copy the texture to a staging resource
        d3dContext->CopyResource(stagingTexture.Get(), Texture);

        // now, map the staging resource
        hr = d3dContext->Map(
                stagingTexture.Get(),
                0,
                D3D11_MAP_READ,
                0,
                &mapInfo);
        if (FAILED(hr)) {
            throw MyException::Make(hr, L"Failed to map staging texture");
        }

        mappedTexture = std::move(stagingTexture);
    } else {
        throw MyException::Make(hr, L"Failed to map texture.");
    }
} else {
    mappedTexture = Texture;
}
auto unmapResource = Finally([&] {
    d3dContext->Unmap(mappedTexture.Get(), 0);
    });

    [...]

    hr = frameEncode->WritePixels(
            desc.Height,
            mapInfo.RowPitch,
            desc.Height * mapInfo.RowPitch,
            reinterpret_cast<BYTE*>(mapInfo.pData));
    if (FAILED(hr)) {
        throw MyException::Make(hr, L"frameEncode->WritePixels(...) failed.");
    }