无法让 DirectX 12 顶点缓冲区输出流工作(结果全是零)

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

我在尝试实现 DirectX 12 顶点缓冲区输出流以获取世界变换的顶点位置时遇到了麻烦。我几乎让它工作了——它做所有事情都没有错误,但它返回计数器 0 和输出流数据零。我从简单的代码开始,我可以分享这些代码以希望解决它。我用谷歌搜索,聊天 gpted,并使用 dxcpl.exe 强制打开调试消息。 我从 BzTut 04 开始: https://www.braynzasoft.net/viewtutorial/q16390-04-direct3d-12-drawing 最终结果是: https://github.com/ryan-de-boer/DirectX12SampleCode

这是一些代码,其中 counterValue 为零,streamOutputData 全部为零。

顶点着色器

struct VertexOutput // also in pixel shader as input
{
  float3 position : POSITION; // Stream out 3*4bytes
  float3 worldPos: WORLDPOS; // Stream out world pos position 3*4bytes
  float4 sv_position : SV_POSITION; // Stream out position 4*4bytes, total 40bytes
};

struct VertexInput
{
  float3 position : POSITION; // Stream out 3*4bytes
  float3 worldPos: WORLDPOS; // Stream out world pos position 3*4bytes
  float4 sv_position : SV_POSITION; // Stream out position 4*4bytes, total 40bytes
};

VertexOutput main(VertexInput input)
{
  VertexOutput vo;
  vo.worldPos = float3(1.1f, 1.2f, 1.3f); // I know this should be localPosition * world transform, but I want something simple working first.
  vo.position = input.position;
  vo.sv_position = float4(input.position, 1.0f);
  return vo;
}

主要:

    D3D12_STREAM_OUTPUT_BUFFER_VIEW streamOutputBufferView = {};
    streamOutputBufferView.BufferFilledSizeLocation = streamOutputBuffer->GetGPUVirtualAddress();
    streamOutputBufferView.BufferLocation = streamOutputBufferView.BufferFilledSizeLocation + sizeof(UINT64);
    streamOutputBufferView.SizeInBytes = bufferSize;/* Size of the buffer */;


    // Bind the output buffer to the stream-output stage

    commandList->SOSetTargets(0/* Start slot */, 1/* Number of views */, &streamOutputBufferView);


    commandList->DrawInstanced(3, 1, 0, 0); // finally draw 3 vertices (draw the triangle)


    // Transition the state of the source buffer to D3D12_RESOURCE_STATE_COPY_SOURCE
    CD3DX12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(
        streamOutputBuffer,                   // Resource
        D3D12_RESOURCE_STATE_STREAM_OUT,            // From state
        D3D12_RESOURCE_STATE_COPY_SOURCE           // To state
    );

    // Insert the barrier into the command list
    commandList->ResourceBarrier(1, &barrier);
    // Define the heap properties
    D3D12_HEAP_PROPERTIES heapProperties = {};
    heapProperties.Type = D3D12_HEAP_TYPE_UPLOAD; // Use UPLOAD type for CPU-accessible heap
    heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; // Specify CPU visibility
    heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; // Use default memory pool

    // Define the buffer description
    CD3DX12_RESOURCE_DESC bufferDesc = CD3DX12_RESOURCE_DESC::Buffer(totalBufferSize);

    // Create the destination buffer in the CPU-accessible heap
    ID3D12Resource* destinationBuffer;
    device->CreateCommittedResource(
        &heapProperties,                        // Heap properties
        D3D12_HEAP_FLAG_NONE,                   // Flags
        &bufferDesc,                            // Resource description
        D3D12_RESOURCE_STATE_GENERIC_READ,      // Initial resource state
        nullptr,                                // Clear value (unused for buffers)
        IID_PPV_ARGS(&destinationBuffer)        // Destination pointer
    );


    // Calculate the size of the counter (assuming UINT64)
    const UINT counterSize = sizeof(UINT64);

    // Calculate the total size of the data to copy
    const UINT totalDataSize = totalBufferSize;

    // Perform the copy
    commandList->CopyBufferRegion(
        destinationBuffer,     // Destination buffer
        0,                           // Destination offset
        streamOutputBuffer,    // Source buffer
        0,                           // Source offset
        totalDataSize                // Size to copy
    );


    // Map the destination buffer to CPU-accessible memory
    UINT8* mappedData = nullptr;
    CD3DX12_RANGE readRange(0, 0); // We'll read the entire buffer
  hr = destinationBuffer->Map(0, &readRange, reinterpret_cast<void**>(&mappedData));
    if (FAILED(hr))
    {
        OutputDebugString(L"MAP FAILED");
    }

    // Copy the data from the mapped memory
    // Assuming the first sizeof(UINT64) bytes contain the counter and the rest contain the stream output data
    UINT64 counterValue = *reinterpret_cast<UINT64*>(mappedData);
    BYTE* streamOutputData = mappedData + sizeof(UINT64);
    // Now you can use counterValue and streamOutputData as needed

    // Unmap the buffer
    destinationBuffer->Unmap(0, nullptr);


    commandList->SOSetTargets(0/* Start slot */, 0/* Number of views */, nullptr);

其余代码请参阅我的 github 链接,您可以使用 VS2022 进行编译。我还添加了在示例代码上运行的 PIX 的屏幕截图,您可以看到它知道如何在 VS 输出缓冲区中获取世界变换位置。

stream output buffer vertex directx-12
1个回答
0
投票

我修复了目标缓冲区充满零的问题。关键的解决方案是在从 CopyResource 读取缓冲区之前执行命令列表。

以下是我最近对 github 示例所做的更改:

  • 对于destinationBuffer而不是D3D12_RESOURCE_STATE_GENERIC_READ,我使用了D3D12_RESOURCE_STATE_COPY_DEST。
  • 我使用 CopyReource 代替 CopyBufferRegion。
  • 执行命令列表等待CopyResource完成。
  • 现在可以保存二进制数据了!

在我的 github 页面上查看 HxD 查看二进制数据的屏幕截图。

© www.soinside.com 2019 - 2024. All rights reserved.