Как привязать текстуры к другому регистру в dx12?

#hlsl #directx-12

#hlsl #directx-12

Вопрос:

У меня есть две текстуры и массив текстур. Я пытаюсь привязать две текстуры к t1, а массив текстур к t2. hlsl может понравиться это

 Texture2D    gDiffuseMap : register(t0);
Texture2DArray gDiffuseMaps : register(t1);
  

Я создаю диапазон дескрипторов, который имеет 2 дескриптора.

 CD3DX12_DESCRIPTOR_RANGE texTable;
texTable.Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 2, 0);
  

Но я не знаю, как привязать дескрипторы к регистрам.

Ответ №1:

Связь между шейдерами и графическим процессором для DirectX 12 обрабатывается через корневые подписи. Для двух текстур у вас есть два варианта, как их привязать.

Две текстуры в одной таблице дескрипторов

Первый — связать их вместе, но для этого требуется, чтобы целевые дескрипторы были непрерывными. Это то, что вы начали делать.

 // HLSL syntax
#define DualTextureRS 
"RootFlags ( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |" 
"            DENY_DOMAIN_SHADER_ROOT_ACCESS |" 
"            DENY_GEOMETRY_SHADER_ROOT_ACCESS |" 
"            DENY_HULL_SHADER_ROOT_ACCESS )," 
"DescriptorTable ( SRV(t0, numDescriptors = 2), visibility = SHADER_VISIBILITY_PIXEL )," 
"DescriptorTable ( Sampler(s0, numDescriptors = 2), visibility = SHADER_VISIBILITY_PIXEL )," 
"CBV(b0)"

// C   code built root-signature
enum RootParameterIndex
{
    TextureSRVBase,
    TextureSamplerBase,
    ConstantBuffer,
    RootParameterCount
};

{
    D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags =
        D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |
        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_PARAMETER rootParameters[RootParameterIndex::RootParameterCount] = {};
    rootParameters[RootParameterIndex::ConstantBuffer].InitAsConstantBufferView(0, 0, D3D12_SHADER_VISIBILITY_ALL);

    // Textures
    CD3DX12_DESCRIPTOR_RANGE textureRange(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 2, 0);
    CD3DX12_DESCRIPTOR_RANGE textureSamplerRange(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 2, 0);
    rootParameters[RootParameterIndex::TextureSRVBase].InitAsDescriptorTable(1, amp;textureRange, D3D12_SHADER_VISIBILITY_PIXEL);
    rootParameters[RootParameterIndex::TextureSamplerBase].InitAsDescriptorTable(1, amp;textureSamplerRange, D3D12_SHADER_VISIBILITY_PIXEL);

    // Create the root signature
    CD3DX12_ROOT_SIGNATURE_DESC rsigDesc = {};
    rsigDesc.Init(_countof(rootParameters), rootParameters, 0, nullptr, rootSignatureFlags);

    ComPtr<ID3D12RootSignature> rootSignature;
    ComPtr<ID3DBlob> pSignature;
    ComPtr<ID3DBlob> pError;
    HRESULT hr = D3D12SerializeRootSignature(amp;rsigDesc, D3D_ROOT_SIGNATURE_VERSION_1, pSignature.GetAddressOf(), pError.GetAddressOf());
    if (SUCCEEDED(hr))
    {
        hr = device->CreateRootSignature(0, pSignature->GetBufferPointer(), pSignature->GetBufferSize(),
            IID_PPV_ARGS(amp;rootSignature)
            );
    }
}
  

И тогда вы бы его привязали:

 commandList->SetGraphicsRootSignature(rootSignature.Get());
commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::TextureSRVBase, texture1); // Second texture will be (texture1 1)
commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::TextureSamplerBase, texture1Sampler); // Second sampler will be (texture1Sampler 1)
  

Две таблицы дескрипторов

Второй способ — связать их как два разных диапазона дескрипторов, чтобы вы могли привязать две произвольные текстуры:

 // HLSL syntax
#define DualTextureRS 
"RootFlags ( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |" 
"            DENY_DOMAIN_SHADER_ROOT_ACCESS |" 
"            DENY_GEOMETRY_SHADER_ROOT_ACCESS |" 
"            DENY_HULL_SHADER_ROOT_ACCESS )," 
"DescriptorTable ( SRV(t0), visibility = SHADER_VISIBILITY_PIXEL )," 
"DescriptorTable ( Sampler(s0), visibility = SHADER_VISIBILITY_PIXEL )," 
"DescriptorTable ( SRV(t1), visibility = SHADER_VISIBILITY_PIXEL )," 
"DescriptorTable ( Sampler(s1), visibility = SHADER_VISIBILITY_PIXEL )," 
"CBV(b0)"

// C   code built root-signature
enum RootParameterIndex
{
    Texture1SRV,
    Texture1Sampler,
    Texture2SRV,
    Texture2Sampler,
    ConstantBuffer,
    RootParameterCount
};

{
    D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags =
        D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |
        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_PARAMETER rootParameters[RootParameterIndex::RootParameterCount] = {};
    rootParameters[RootParameterIndex::ConstantBuffer].InitAsConstantBufferView(0, 0, D3D12_SHADER_VISIBILITY_ALL);

    // Texture 1
    CD3DX12_DESCRIPTOR_RANGE texture1Range(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0);
    CD3DX12_DESCRIPTOR_RANGE texture1SamplerRange(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 1, 0);
    rootParameters[RootParameterIndex::Texture1SRV].InitAsDescriptorTable(1, amp;texture1Range, D3D12_SHADER_VISIBILITY_PIXEL);
    rootParameters[RootParameterIndex::Texture1Sampler].InitAsDescriptorTable(1, amp;texture1SamplerRange, D3D12_SHADER_VISIBILITY_PIXEL);

    // Texture 2
    CD3DX12_DESCRIPTOR_RANGE texture2Range(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 1);
    CD3DX12_DESCRIPTOR_RANGE texture2SamplerRange(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 1, 1);
    rootParameters[RootParameterIndex::Texture2SRV].InitAsDescriptorTable(1, amp;texture2Range, D3D12_SHADER_VISIBILITY_PIXEL);
    rootParameters[RootParameterIndex::Texture2Sampler].InitAsDescriptorTable(1, amp;texture2SamplerRange, D3D12_SHADER_VISIBILITY_PIXEL);

    // Create the root signature
    CD3DX12_ROOT_SIGNATURE_DESC rsigDesc = {};
    rsigDesc.Init(_countof(rootParameters), rootParameters, 0, nullptr, rootSignatureFlags);

    ComPtr<ID3D12RootSignature> rootSignature;
    ComPtr<ID3DBlob> pSignature;
    ComPtr<ID3DBlob> pError;
    HRESULT hr = D3D12SerializeRootSignature(amp;rsigDesc, D3D_ROOT_SIGNATURE_VERSION_1, pSignature.GetAddressOf(), pError.GetAddressOf());
    if (SUCCEEDED(hr))
    {
        hr = device->CreateRootSignature(0, pSignature->GetBufferPointer(), pSignature->GetBufferSize(),
            IID_PPV_ARGS(amp;rootSignature)
            );
    }
}
  

И тогда вы бы его привязали:

 commandList->SetGraphicsRootSignature(rootSignature.Get());
commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::Texture1SRV, texture1);
commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::Texture1Sampler, texture1Sampler);
commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::Texture2SRV, texture2);
commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::Texture2Sampler, texture2Sampler);
  

Вторая форма — это та, которую я использую в наборе инструментов DirectX, потому что она более гибкая.