【问题标题】:Updating a vertex buffer causes a debug layer error更新顶点缓冲区会导致调试层错误
【发布时间】:2016-08-11 05:56:17
【问题描述】:

我将我的 Windows 10 更新到版本 1607,其中包括额外的 D3D 调试层检查。我的顶点缓冲区更新代码在更新之前没有警告/错误,但现在我在调用 CopyBufferRegion 时遇到错误:

资源的资源状态(0xAC3: D3D12_RESOURCE_STATE_GENERIC_READ) (0x000001DB301B9750:'') (子资源: 0) 是 用作目标缓冲区无效。预期状态位:0x400: D3D12_RESOURCE_STATE_COPY_DEST,实际状态:0xAC3: D3D12_RESOURCE_STATE_GENERIC_READ

如果我将 vb 转换为想要的状态 (D3D12_RESOURCE_STATE_COPY_DEST),则会收到如下错误:

D3D12 错误:ID3D12CommandList::ResourceBarrier:某些堆是 仅限于某些 D3D12_RESOURCE_STATES 状态,并且不能 改变了。 D3D12_HEAP_TYPE_UPLOAD 需要 D3D12_RESOURCE_STATE_GENERIC_READ。 D3D12_HEAP_TYPE_READBACK 需要 D3D12_RESOURCE_STATE_COPY_DEST。 [资源管理错误#741: RESOURCE_BARRIER_INVALID_HEAP]

这是我的代码。它创建一个顶点缓冲区并上传顶点数据,必要时调整缓冲区的大小:

void ae3d::VertexBuffer::UploadVB( void* faces, void* vertices, unsigned ibSize )
{
    D3D12_HEAP_PROPERTIES uploadProp = {};
    uploadProp.Type = D3D12_HEAP_TYPE_UPLOAD;
    uploadProp.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
    uploadProp.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
    uploadProp.CreationNodeMask = 1;
    uploadProp.VisibleNodeMask = 1;

    D3D12_RESOURCE_DESC bufferProp = {};
    bufferProp.Alignment = 0;
    bufferProp.DepthOrArraySize = 1;
    bufferProp.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
    bufferProp.Flags = D3D12_RESOURCE_FLAG_NONE;
    bufferProp.Format = DXGI_FORMAT_UNKNOWN;
    bufferProp.Height = 1;
    bufferProp.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
    bufferProp.MipLevels = 1;
    bufferProp.SampleDesc.Count = 1;
    bufferProp.SampleDesc.Quality = 0;
    bufferProp.Width = ibOffset + ibSize;

    // this branch resizes the buffer and causes validation errors.
    if (vb != nullptr && bufferProp.Width <= sizeBytes)
    {
        ID3D12Resource* stagingBuffer = nullptr;

        HRESULT hr = GfxDeviceGlobal::device->CreateCommittedResource( &uploadProp, D3D12_HEAP_FLAG_NONE, &bufferProp,
            D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS( &stagingBuffer ) );
        AE3D_CHECK_D3D( hr, "Failed to create vertex staging resource" );

        char* vbUploadPtr = nullptr;
        hr = stagingBuffer->Map( 0, nullptr, reinterpret_cast<void**>(&vbUploadPtr) );
        if (FAILED( hr ))
        {
            ae3d::System::Assert( false, "Unable to map vertex staging buffer!\n" );
            return;
        }

        memcpy_s( vbUploadPtr, ibOffset, vertices, ibOffset );
        memcpy_s( vbUploadPtr + ibOffset, ibSize, faces, ibSize );

        stagingBuffer->Unmap( 0, nullptr );


        // vb state is invalid at this point, needs D3D12_RESOURCE_STATE_COPY_DEST
        GfxDeviceGlobal::graphicsCommandList->CopyBufferRegion( vb, 0, stagingBuffer, 0, ibOffset + ibSize );

        Global::frameVBUploads.push_back( stagingBuffer );
        sizeBytes = ibOffset + ibSize;

        return;
    }

    sizeBytes = ibOffset + ibSize;

    HRESULT hr = GfxDeviceGlobal::device->CreateCommittedResource(
        &uploadProp,
        D3D12_HEAP_FLAG_NONE,
        &bufferProp,
        D3D12_RESOURCE_STATE_GENERIC_READ,
        nullptr,
        IID_PPV_ARGS( &vb ) );
    if (FAILED( hr ))
    {
        ae3d::System::Assert( false, "Unable to create vertex buffer!\n" );
        return;
    }

    Global::vbs.push_back( vb );

    char* vbUploadPtr = nullptr;
    hr = vb->Map( 0, nullptr, reinterpret_cast<void**>(&vbUploadPtr) );
    if (FAILED( hr ))
    {
        ae3d::System::Assert( false, "Unable to map vertex buffer!\n" );
        return;
    }

    memcpy_s( vbUploadPtr, ibOffset, vertices, ibOffset );
    memcpy_s( vbUploadPtr + ibOffset, ibSize, faces, ibSize );
    vb->Unmap( 0, nullptr );
}

如何修复这些调试层错误?

【问题讨论】:

    标签: c++ directx-12


    【解决方案1】:

    上传缓冲区只能处于D3D12_RESOURCE_STATE_GENERIC_READ 状态(link)。您需要创建一个具有D3D12_RESOURCE_STATE_COPY_DEST 状态的默认缓冲区。然后在 cpu 上映射上传堆后,您可以使用 ID3D12GraphicsCommandList::CopyBufferRegion() 方法将上传缓冲区的内容复制到 gpu 上的默认缓冲区。之后不要忘记将默认缓冲区转换为可用状态,并确保在 gpu 执行复制时上传堆仍然存在。

    【讨论】:

    • 谢谢,但您能否更具体地说明如何将其应用到我的问题代码中?特别是缓冲区和堆创建参数。我也不明白默认缓冲区的创建,我应该用它替换我当前代码的缓冲区之一还是创建一个新的缓冲区?
    • 你可以找到一个例子here。基本上你需要 2 个缓冲区 - 默认应该存在,直到你不再需要顶点缓冲区,并且上传应该存在,直到你从中复制。
    猜你喜欢
    • 1970-01-01
    • 2016-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多