4
$\begingroup$

I can't really seem to figure out how to bind two constant buffers to my shaders. I have them described like so. One in slot b0 and the other in slot b1.

cbuffer WVPData : register(b0)
{
    matrix model;
    matrix view;
    matrix projection;
};

cbuffer DirLightData : register(b1)
{
   float4 Ambient;
   float4 Diffuse;
   float4 Specular;
   float3 Direction;
   float pad;
};

Then for the root signature it's described like so.

CD3DX12_DESCRIPTOR_RANGE range[2];
CD3DX12_ROOT_PARAMETER parameter[1];

range[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0);
range[1].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 1);
parameter[0].InitAsDescriptorTable(_countof(range), range, D3D12_SHADER_VISIBILITY_ALL);

D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags =
D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | // Only the input assembler stage needs access to the constant buffer.
D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |
D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS |
D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS;

CD3DX12_ROOT_SIGNATURE_DESC descRootSignature;
descRootSignature.Init(_countof(parameter), parameter, 0, nullptr, rootSignatureFlags);

ComPtr<ID3DBlob> pSignature;
ComPtr<ID3DBlob> pError;
DX::ThrowIfFailed(D3D12SerializeRootSignature(&descRootSignature, D3D_ROOT_SIGNATURE_VERSION_1, pSignature.GetAddressOf(), pError.GetAddressOf()));
DX::ThrowIfFailed(d3dDevice->CreateRootSignature(0, pSignature->GetBufferPointer(), pSignature->GetBufferSize(), IID_PPV_ARGS(&mRootSignature)));

I believe that's correct. I think the problem I have is when I create the constant buffer and the cbv below. Specifically right under the "Describe and create the constant buffer view." comment. I don't really understand what's going on.

// Create a descriptor heap for the constant buffers.
{
    D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {};
    heapDesc.NumDescriptors = 2;
    heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
    // This flag indicates that this descriptor heap can be bound to the pipeline and that descriptors contained in it can be referenced by a root table.
    heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
    DX::ThrowIfFailed(d3dDevice->CreateDescriptorHeap(&heapDesc, IID_PPV_ARGS(&mCbvHeap)));

    mCbvHeap->SetName(L"Constant Buffer View Descriptor Heap");
}

// Create the constant buffer.
DX::ThrowIfFailed(d3dDevice->CreateCommittedResource(
  &uploadHeapProperties,
  D3D12_HEAP_FLAG_NONE,
  &CD3DX12_RESOURCE_DESC::Buffer(CAlignedWVPDataSize),
  D3D12_RESOURCE_STATE_GENERIC_READ,
  nullptr,
  IID_PPV_ARGS(&mWVPConstantBuffer)));

DX::ThrowIfFailed(d3dDevice->CreateCommittedResource(
  &uploadHeapProperties,
  D3D12_HEAP_FLAG_NONE,
  &CD3DX12_RESOURCE_DESC::Buffer(CAlignedDirLightDataSize),
  D3D12_RESOURCE_STATE_GENERIC_READ,
  nullptr,
  IID_PPV_ARGS(&mDirLightConstantBuffer)));

// Describe and create a constant buffer view.
D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc[2];// = {};
cbvDesc[0].BufferLocation = mWVPConstantBuffer->GetGPUVirtualAddress();
cbvDesc[0].SizeInBytes = CAlignedWVPDataSize;
cbvDesc[1].BufferLocation = mDirLightConstantBuffer->GetGPUVirtualAddress();
cbvDesc[1].SizeInBytes = CAlignedDirLightDataSize;

CD3DX12_CPU_DESCRIPTOR_HANDLE cbvHandle0(mCbvHeap->GetCPUDescriptorHandleForHeapStart(), 0, 0);
d3dDevice->CreateConstantBufferView(cbvDesc, cbvHandle0);

CD3DX12_CPU_DESCRIPTOR_HANDLE cbvHandle1(mCbvHeap->GetCPUDescriptorHandleForHeapStart(), d3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV), 1);
d3dDevice->CreateConstantBufferView(cbvDesc, cbvHandle1);

// Initialize and map the constant buffers. We don't unmap this until the
// app closes. Keeping things mapped for the lifetime of the resource is okay.
DX::ThrowIfFailed(mWVPConstantBuffer->Map(0, nullptr, reinterpret_cast<void**>(&mMappedWVPBuffer)));
memcpy(mMappedWVPBuffer, &mWVPData, sizeof(mWVPData));  

DX::ThrowIfFailed(mDirLightConstantBuffer->Map(0, nullptr, reinterpret_cast<void**>(&mMappedDirLightBuffer)));
memcpy(mMappedDirLightBuffer, &mDirLightData, sizeof(mDirLightData));

Note: Slot b0 works perfect. I can change world view projection data just fine. But b1 does not work at all. What am I doing wrong?

$\endgroup$
3
$\begingroup$

The problem looks like it's in this line:

d3dDevice->CreateConstantBufferView(cbvDesc, cbvHandle1);

The first parameter should be &cbvDesc[1]. As it is now, you're setting up two copies of cbvDesc[0].

Also, it looks like you've reversed the second and third arguments to the cbvHandle1 constructor: the second argument should be the offset (1) and the third should be the increment size. Not that it really matters, since those two values just get multiplied together anyway.

By the way, I don't think you need to set up two separate descriptor ranges when creating the root signature; since they're contiguous, you could just use a single range of two descriptors. But it shouldn't make a difference to the results.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.