通过 CPU 读取 GPU 资源数据

reading GPU resource data by CPU

最近在学习directx11。我一直停留在计算着色器部分。

所以我做了四个资源和三个对应的视图。

  1. 不可变输入缓冲区 = {1,1,1,1,1} / SRV
  2. 不可变输入缓冲区 = {2,2,2,2,2} / SRV
  3. 输出缓冲器/无人机
  4. 用于读取的暂存缓冲区/无视图

并且我成功地创建了所有东西,并调度了 cs 函数,并将数据从输出缓冲区复制到暂存缓冲区,并且我 read/check 数据。

// INPUT BUFFER1--------------------------------------------------
const int dataSize = 5;
    D3D11_BUFFER_DESC vb_dest;
    vb_dest.ByteWidth = sizeof(float) * dataSize;
    vb_dest.StructureByteStride = sizeof(float);
    vb_dest.BindFlags = D3D11_BIND_SHADER_RESOURCE;
    vb_dest.Usage = D3D11_USAGE_IMMUTABLE;
    vb_dest.CPUAccessFlags = 0;
    vb_dest.MiscFlags = 0;
    float v1_float[dataSize] = { 1,1,1,1,1 };
    D3D11_SUBRESOURCE_DATA v1_data;
    v1_data.pSysMem = static_cast<void*>(v1_float);
    device->CreateBuffer(
        &vb_dest,
        &v1_data,
        valueBuffer1.GetAddressOf());
    D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc;
    srv_desc.Format = DXGI_FORMAT_R32_FLOAT;
    srv_desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
    srv_desc.Buffer.FirstElement = 0;
    srv_desc.Buffer.NumElements = dataSize;
    srv_desc.Buffer.ElementWidth = sizeof(float);
    device->CreateShaderResourceView(
        valueBuffer1.Get(),
        &srv_desc,
        inputSRV1.GetAddressOf());

// INPUT BUFFER2-----------------------------------------------------------
    float v2_float[dataSize] = { 2,2,2,2,2 };
    D3D11_SUBRESOURCE_DATA v2_data;
    v2_data.pSysMem = static_cast<void*>(v2_float);
    device->CreateBuffer(
        &vb_dest,
        &v2_data,
        valueBuffer2.GetAddressOf());
    device->CreateShaderResourceView(
        valueBuffer2.Get(),
        &srv_desc,
        inputSRV2.GetAddressOf());

// OUTPUT BUFFER-----------------------------------------------------------
    D3D11_BUFFER_DESC ov_desc;
    ov_desc.ByteWidth = sizeof(float) * dataSize;
    ov_desc.StructureByteStride = sizeof(float);
    ov_desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS;
    ov_desc.Usage = D3D11_USAGE_DEFAULT;
    ov_desc.CPUAccessFlags = 0;
    ov_desc.MiscFlags = 0;
    device->CreateBuffer(
        &ov_desc,
        nullptr,
        outputResource.GetAddressOf());

    D3D11_UNORDERED_ACCESS_VIEW_DESC outputUAV_desc;
    outputUAV_desc.Format = DXGI_FORMAT_R32_FLOAT;
    outputUAV_desc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
    outputUAV_desc.Buffer.FirstElement = 0;
    outputUAV_desc.Buffer.NumElements = dataSize;
    outputUAV_desc.Buffer.Flags = 0;
    device->CreateUnorderedAccessView(
        outputResource.Get(),
        &outputUAV_desc,
        outputUAV.GetAddressOf());

// BUFFER FOR COPY-----------------------------------------------------------
    D3D11_BUFFER_DESC rb_desc;
    rb_desc.ByteWidth = sizeof(float) * dataSize;
    rb_desc.StructureByteStride = sizeof(float);
    rb_desc.Usage = D3D11_USAGE_STAGING;
    rb_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
    rb_desc.BindFlags = 0;
    rb_desc.MiscFlags = 0;
    device->CreateBuffer(
        &rb_desc,
        nullptr,
        readResource.GetAddressOf());

// DISPATCH and COPY and GET DATA
    dContext->CSSetShaderResources(0, 1, inputSRV1.GetAddressOf());
    dContext->CSSetShaderResources(1, 1, inputSRV2.GetAddressOf());
    dContext->CSSetUnorderedAccessViews(0, 1, outputUAV.GetAddressOf(), nullptr);
    dContext->CSSetShader(cs.Get(), nullptr, 0);
    dContext->Dispatch(1, 1, 1);

    dContext->CopyResource(readResource.Get(), outputResource.Get());
    D3D11_MAPPED_SUBRESOURCE mappedResource2;
    ZeroMemory(&mappedResource2, sizeof(D3D11_MAPPED_SUBRESOURCE));
    R_CHECK(dContext->Map(readResource.Get(), 0, D3D11_MAP_READ, 0, &mappedResource2));

    float* data = static_cast<float*>(mappedResource2.pData);

    for (int i = 0; i < 5; ++i)
    {
        int a = data[i];
    }

这是计算着色器代码


StructuredBuffer<float> inputA : register(t0);
StructuredBuffer<float> inputB : register(t1);

RWStructuredBuffer<float> output : register(u0);

[numthreads(5, 1, 1)]
void main(int3 id : SV_DispatchThreadID)
{
    output[id.x] = inputA[id.x] + inputB[id.x];
}

在 CS 中,它是将两个输入缓冲区数据相加并存储到输出缓冲区中。 所以预期的答案是{3,3,3,3,3}。

但结果是 {3,0,0,0,0} 只有第一个 idx 有正确答案。

任何建议都会很棒。

 dContext->CopyResource(readResource.Get(), outputResource.Get());
    D3D11_MAPPED_SUBRESOURCE mappedResource2;
    ZeroMemory(&mappedResource2, sizeof(D3D11_MAPPED_SUBRESOURCE));
    R_CHECK(dContext->Map(readResource.Get(), 0, D3D11_MAP_READ, 0, &mappedResource2));

    float* data = static_cast<float*>(mappedResource2.pData);

    for (int i = 0; i < 5; ++i)
    {
        int a = data[i];
    }

这段代码应该是这样的。

CopyResource();
Map();
Declare and allocate 'data'
zeromemory(data);
memcopy(data, resource's pointer);
unMap();

出于某种原因,我必须使用 memcopy 而不是直接使用从映射中获得的指针读取资源。