DIrectx12-常量缓冲区理解
常量的数据从CPU内存传给GPU,首先需要给常量数据建立一个描述符,让GPU知道这是一个什么资源,应该怎么处理。
描述符堆可以理解为描述符数组,取数据的时候通过“GetCPUDescriptorHandleForHeapStart”函数获取描述符堆的首地址,然后偏移描述符大小 * 要取描述符的索引
struct ObjectConstants { XMFLOAT4X4 WorldViewProj = MathHelper::Identity4x4(); float time; };
上传数据并创建缓冲区
mObjectCB = std::make_unique<UploadBuffer<ObjectConstants>>(md3dDevice.Get(), 1, true);//上传数据到GPU内存 UINT objCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(ObjectConstants)); //数据大小必须为256的倍数 D3D12_GPU_VIRTUAL_ADDRESS cbAddress = mObjectCB->Resource()->GetGPUVirtualAddress();//获取数据在GPU内存的地址 // 偏移到缓冲区中的第i个对象常量buffer。 int boxCBufIndex = 0; cbAddress += boxCBufIndex*objCBByteSize; //始化描述符 D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc; cbvDesc.BufferLocation = cbAddress; cbvDesc.SizeInBytes = d3dUtil::CalcConstantBufferByteSize(sizeof(ObjectConstants)); //创建常量缓冲区 md3dDevice->CreateConstantBufferView(&cbvDesc,mCbvHeap->GetCPUDescriptorHandleForHeapStart());
创建并描述缓冲堆
D3D12_DESCRIPTOR_HEAP_DESC cbvHeapDesc; cbvHeapDesc.NumDescriptors = 1; //缓冲区数量 cbvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;//缓冲区类型 CBV常量缓冲 SRV着色器 UAV无类型缓冲区 cbvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;//指示 该描述符应用于着色器阶段 cbvHeapDesc.NodeMask = 0;//对于单适配器操作,将此设置为零 ThrowIfFailed(md3dDevice->CreateDescriptorHeap(&cbvHeapDesc,IID_PPV_ARGS(&mCbvHeap)));//创建描述符堆
后面就到根签名发挥作用了,将着色器需要用到的数据绑定到对应的寄存器槽上,供着色器访问。
案例程序注释翻译:着色程序通常需要资源作为输入(常量缓冲,纹理,采样)。 根签名定义了着色程序期望的资源。 如果我们把着色器程序看作一个函数,把输入资源看作函数参数,那么根签名就可以看作是定义函数签名。
// 根参数可以是表、根描述符或根常量。
CD3DX12_ROOT_PARAMETER slotRootParameter[1];
// 创建一个CBV描述符表
CD3DX12_DESCRIPTOR_RANGE cbvTable; // 一个辅助结构,可以轻松初始化D3D12_DESCRIPTOR_RANGE结构
cbvTable.Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0);//类型 数量 着色器寄存器
slotRootParameter[0].InitAsDescriptorTable(1, &cbvTable);
// 根签名是一个根参数数组。
CD3DX12_ROOT_SIGNATURE_DESC rootSigDesc(1, slotRootParameter, 0, nullptr,
D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
// 创建一个带有单个插槽的根签名,它指向一个由单个常量缓冲区组成的描述符范围
ComPtr<ID3DBlob> serializedRootSig = nullptr;
ComPtr<ID3DBlob> errorBlob = nullptr;
HRESULT hr = D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1,
serializedRootSig.GetAddressOf(), errorBlob.GetAddressOf());
if(errorBlob != nullptr)
{
::OutputDebugStringA((char*)errorBlob->GetBufferPointer());
}
ThrowIfFailed(hr);
ThrowIfFailed(md3dDevice->CreateRootSignature(0, serializedRootSig->GetBufferPointer(),serializedRootSig->GetBufferSize(),IID_PPV_ARGS(&mRootSignature)));

浙公网安备 33010602011771号