directx-12 - 如何使用具有多个描述符堆的命令列表?

Rap*_*yer 3 c++ heap direct3d descriptor directx-12

目前通过microsofts示例,值得注意的是,每个命令列表只使用一个cbv_srv_uav堆(+可能在其他采样器堆上).

每个CommandList可以使用多个堆吗?

所以我设置堆和范围

this->mRSVHeap = new urd::DescriptorHeap(
    *this->mDevice,
    urd::DescriptorHeapType::CBV_SRV_UAV,
    1, // shader visible
    2); // space for 2 descriptors (2 textures)

this->mConstHeap = new urd::DescriptorHeap(
    *this->mDevice,
    urd::DescriptorHeapType::CBV_SRV_UAV,
    1, // shader visible
    1); // space for 1 descriptor

urd::DescriptorRange ranges[3];
ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 2, 0); // first and second descriptor in rsv heap (t0, t1)
ranges[1].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0); // first descriptor in cbv heap (b0)
ranges[2].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 2); // same texture used as first range (again first descriptor in rsv, accessable by t2)
Run Code Online (Sandbox Code Playgroud)

之后我定义了描述符表

rootParam[0].InitDescTable(1, &ranges[0], D3D12_SHADER_VISIBILITY_PIXEL);
rootParam[1].InitDescTable(1, &ranges[1], D3D12_SHADER_VISIBILITY_ALL);
rootParam[2].InitDescTable(1, &ranges[2], D3D12_SHADER_VISIBILITY_PIXEL);
Run Code Online (Sandbox Code Playgroud)

所以我在rsv堆中的cpu offset 0和1创建纹理1和2的shaderResourceViews,并在cbv堆中的cpu offset 0处创建常量缓冲区的constantbufferview

像这样:

D3D12_CPU_DESCRIPTOR_HANDLE handle = this->ConstHeap->GetCPUDescriptorHandleForHeapStart();
handle.ptr += index * SIZE_OF_ONE_DESCRIPTOR_CBV_SRV_UAV_TYPE;
CreateConstantBufferView(&desc, handle)
Run Code Online (Sandbox Code Playgroud)

现在是时候告诉命令列表引用那些堆了

ID3D12DescriptorHeap* ppHeaps[] = { this->mRSVHeap.Get(), this->mConstHeap.Get() };
this->mCommandList->GetRef()->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps);
Run Code Online (Sandbox Code Playgroud)

在此之后,关闭命令列表总是抛出.

ThrowIfFailed(this->mCommandList->Close());
Run Code Online (Sandbox Code Playgroud)

以下是我如何告诉命令列表哪个堆为哪个表:

this->mCommandList->GetRef()->SetGraphicsRootDescriptorTable(0, this->mRSVHeap->GetGPUHeapAddressAtOffset(0));
this->mCommandList->GetRef()->SetGraphicsRootDescriptorTable(1, this->mConstHeap->GetGPUHeapAddressAtOffset(0));
this->mCommandList->GetRef()->SetGraphicsRootDescriptorTable(2, this->mRSVHeap->GetGPUHeapAddressAtOffset(0));
Run Code Online (Sandbox Code Playgroud)

如果我将所有对象描述到一个单独的描述符堆中(如示例中所示)并且只使用该堆的不同偏移量,它就可以正常工作.

调试输出:

D3D12错误:ID3D12CommandList :: SetDescriptorHeaps:pDescriptorHeaps [1]设置先前在pDescriptorHeaps数组中出现的描述符堆类型.一次只能设置任何给定描述符堆类型中的一个.[EXECUTION ERROR#554:SET_DESCRIPTOR_HEAP_INVALID] D3D12错误:CCommandList :: SetGraphicsRootDescriptorTable:当前没有在命令列表上设置CBV_SRV_UAV描述符堆,因此设置CBV_SRV_UAV句柄的根描述符表无效.[EXECUTION ERROR#708:SET_DESCRIPTOR_TABLE_INVALID] D3D12错误:CCommandList :: SetGraphicsRootDescriptorTable:当前没有在命令列表上设置CBV_SRV_UAV描述符堆,因此设置CBV_SRV_UAV句柄的根描述符表无效.[EXECUTION ERROR#708:SET_DESCRIPTOR_TABLE_INVALID] D3D12错误:CCommandList :: SetGraphicsRootDescriptorTable:当前没有在命令列表上设置CBV_SRV_UAV描述符堆,因此设置CBV_SRV_UAV句柄的根描述符表无效.[EXECUTION ERROR#708:SET_DESCRIPTOR_TABLE_INVALID]

Ada*_*les 8

限制是每次只能设置一个堆(CBV/SRV/UAV和采样器)堆.因此,一次只能设置两个描述符堆.

但是,重要的是要注意,在命令列表期间,描述符堆集可能会有所不同.

  • 不建议更改命令列表中的描述符堆,因为它可能会对某些硬件造成严重的性能损失.正确的方法是分配一个大堆,并根据需要将描述符从非着色器可见堆复制到它. (2认同)