SRV and CBV in DirectX12 Root Signature

Started by
4 comments, last by adam7 2 years, 1 month ago

Hi, I'm trying to learn DirectX12 using the MSDN samples and I am trying to create a shader that has a constant buffer and a shader resource. I create my root signature like this (the cbuffer and srv are bouund to slots b0 and t0 in the shader):

CD3DX12_DESCRIPTOR_RANGE1 ranges[2];
        ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC);
        ranges[1].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC);

        CD3DX12_ROOT_PARAMETER1 rootParameters[2];
        rootParameters[0].InitAsDescriptorTable(1, &ranges[0], D3D12_SHADER_VISIBILITY_PIXEL);
        rootParameters[1].InitAsDescriptorTable(1, &ranges[1], D3D12_SHADER_VISIBILITY_VERTEX);

        D3D12_STATIC_SAMPLER_DESC sampler = {};
        sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
        sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_BORDER;
        sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_BORDER;
        sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_BORDER;
        sampler.MipLODBias = 0;
        sampler.MaxAnisotropy = 0;
        sampler.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;
        sampler.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK;
        sampler.MinLOD = 0.0f;
        sampler.MaxLOD = D3D12_FLOAT32_MAX;
        sampler.ShaderRegister = 0;
        sampler.RegisterSpace = 0;
        sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;

        CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC rootSignatureDesc;
        rootSignatureDesc.Init_1_1(_countof(rootParameters), rootParameters, 1, &sampler, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);

And in my render loop I do this:

 m_commandList->SetGraphicsRootSignature(m_rootSignature.Get());

    auto heap = m_srvHeap.Get();
    m_commandList->SetDescriptorHeaps(1, &heap);
    m_commandList->SetGraphicsRootDescriptorTable(0, m_srvHeap->GetGPUDescriptorHandleForHeapStart());

    heap = m_cbvHeap.Get();
    m_commandList->SetDescriptorHeaps(1, &heap);
    m_commandList->SetGraphicsRootDescriptorTable(1, m_cbvHeap->GetGPUDescriptorHandleForHeapStart());
    
     m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_frameIndex].Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));

    CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart(), m_frameIndex, m_rtvDescriptorSize);
    m_commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, nullptr);

    // Record commands.
    const float clearColor[] = { 0.2f, 0.0f, 0.0f, 1.0f };
    m_commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr);
    m_commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
    m_commandList->IASetVertexBuffers(0, 1, &m_vertexBufferView);
    m_commandList->DrawInstanced(3, 1, 0, 0);

    // Indicate that the back buffer will now be used to present.
    m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_frameIndex].Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));

    ThrowIfFailed(m_commandList->Close());

My cbuffer works fine because my triangle moves across the screen like in the MSDN sample, however my texture no longer works, the triangle appears black. These are the errors that I get from the debug layer, they don't seem related to my issue, although they did not appear when my root signature only had an SRV:

D3D12 WARNING: ID3D12CommandList::ClearRenderTargetView: The application did not pass any clear value to resource creation. The clear operation is typically slower as a result; but will still clear to the desired value. [ EXECUTION WARNING #820: CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE]

D3D12 WARNING: ID3D12CommandList::ClearRenderTargetView: The application did not pass any clear value to resource creation. The clear operation is typically slower as a result; but will still clear to the desired value. [ EXECUTION WARNING #820: CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE]

D3D12 ERROR: ID3D12CommandQueue::ExecuteCommandLists: Using ResourceBarrier on Command List (0x00000191041D2E90:'Unnamed ID3D12GraphicsCommandList Object'): Before state (0x4: D3D12_RESOURCE_STATE_RENDER_TARGET) of resource (0x000001917F80FAC0:'Unnamed ID3D12Resource Object') (subresource: 0) specified by transition barrier does not match with the state (0x0: D3D12_RESOURCE_STATE_[COMMON|PRESENT]) specified in the previous call to ResourceBarrier [ RESOURCE_MANIPULATION ERROR #527: RESOURCE_BARRIER_BEFORE_AFTER_MISMATCH]

How can I correctly configure the root signature to accomodate a cbuffer and shader resource view? Thanks

Advertisement

You can only set one heap so, this line is incorrect and not required.


heap = m_cbvHeap.Get(); 
m_commandList->SetDescriptorHeaps(1, &heap); 
m_commandList->SetGraphicsRootDescriptorTable(1, m_cbvHeap->GetGPUDescriptorHandleForHeapStart());

instead, you need to make only one heap that contains both srv and cbv, and then pass the offseted handle to command list's set function …

which means OneSRVHeap = OneSRV + oneCBV

@enzio599 thanks for your response, I have tried to create one heap and offset the handle like you said, but I am unsure by which amount to offset the handle? This is how I currently do it:

 D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {};
        srvHeapDesc.NumDescriptors = 2;
        srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
        srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
        ThrowIfFailed(m_device->CreateDescriptorHeap(&srvHeapDesc, IID_PPV_ARGS(&m_srvHeap)));

And this is how I set my srv and buffer (I omitted some code which I think is not relevant)

CD3DX12_DESCRIPTOR_RANGE1 ranges[2];
ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC);
ranges[1].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC);

CD3DX12_ROOT_PARAMETER1 rootParameters[2];
rootParameters[0].InitAsDescriptorTable(1, &ranges[0], D3D12_SHADER_VISIBILITY_PIXEL);
rootParameters[1].InitAsDescriptorTable(1, &ranges[1], D3D12_SHADER_VISIBILITY_VERTEX);
        
CD3DX12_CPU_DESCRIPTOR_HANDLE hDescriptor(m_srvHeap->GetCPUDescriptorHandleForHeapStart());
m_device->CreateShaderResourceView(m_texture.Get(), &srvDesc, hDescriptor);

const UINT constantBufferSize = sizeof(PerFrameCB);   
ThrowIfFailed(m_device->CreateCommittedResource(
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
 D3D12_HEAP_FLAG_NONE,
 &CD3DX12_RESOURCE_DESC::Buffer(constantBufferSize), D3D12_RESOURCE_STATE_GENERIC_READ,
 nullptr,
 IID_PPV_ARGS(&m_constantBuffer)));


D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {};
cbvDesc.BufferLocation = m_constantBuffer->GetGPUVirtualAddress();
cbvDesc.SizeInBytes = constantBufferSize;

hDescriptor.ptr += GetRequiredIntermediateSize(m_texture.Get(), 0, 1);
m_device->CreateConstantBufferView(&cbvDesc, hDescriptor);


CD3DX12_RANGE readRange(0, 0);       
ThrowIfFailed(m_constantBuffer->Map(0, &readRange, reinterpret_cast<void**>(&m_pCbvDataBegin)));
memcpy(m_pCbvDataBegin, &m_constantBufferData, sizeof(m_constantBufferData));

As you can see I tried to offset the handle by the size of the texture, but I have also tried to use the size of the constant buffer, and both of them give this error:

D3D12 ERROR: ID3D12Device::CreateConstantBufferView: Specified CPU descriptor handle ptr=0x00000137B2C4BDDF does not refer to a location in a descriptor heap. [ EXECUTION ERROR #646: INVALID_DESCRIPTOR_HANDLE]

What is the correct offset to use in this case? Thanks

You need to call GetDescriptorHandleIncrementSize at runtime to find out the correct offset. It will likely be 32.

Note that this is the size of the descriptor, and not the size of the actual constant buffer data being pointed to by the descriptor. This is why you have to query the size: the descriptor is hardware/driver-specific and contains opaque data. You can basically think of it as a big fancy pointer, which ultimately points at the buffer/texture data.

@mjp thanks for your response, I managed to create the buffer using GetDescriptorHandleIncrementSize also I forgot to set the descriptor table that contained the CBV later on when populating the command list

This topic is closed to new replies.

Advertisement