Delen via


Descriptor-heaps aanmaken

Als u een descriptor heap wilt maken en configureren, moet u een heap-type descriptor selecteren, bepalen hoeveel descriptors het bevat en vlaggen instellen die aangeven of deze zichtbaar is voor de CPU en/of de shader.

Heap-typen descriptor

Het type heap wordt bepaald door één lid van de D3D12_DESCRIPTOR_HEAP_TYPE enumeratie.

typedef enum D3D12_DESCRIPTOR_HEAP_TYPE
{
    D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,    // Constant buffer/Shader resource/Unordered access views
    D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,        // Samplers
    D3D12_DESCRIPTOR_HEAP_TYPE_RTV,            // Render target view
    D3D12_DESCRIPTOR_HEAP_TYPE_DSV,            // Depth stencil view
    D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES       // Simply the number of descriptor heap types
} D3D12_DESCRIPTOR_HEAP_TYPE;

Descriptorheap-eigenschappen

Heap-eigenschappen worden ingesteld op de structuur D3D12_DESCRIPTOR_HEAP_DESC, die zowel verwijst naar de enumeraties D3D12_DESCRIPTOR_HEAP_TYPE als D3D12_DESCRIPTOR_HEAP_FLAGS.

De vlag D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE kan optioneel worden ingesteld op een descriptorheap om aan te geven dat deze wordt gebonden in een opdrachtlijst voor verwijzing door shaders. Descriptor-heaps die zijn gemaakt zonder met deze vlag kunnen toepassingen descriptors in het CPU-geheugen faseren voordat ze naar een arceringsbare descriptor heap worden gekopieerd. Maar het is ook prima voor toepassingen om rechtstreeks descriptors te maken in shader zichtbare descriptor-heaps zonder dat u iets hoeft te faseren op de CPU.

Deze vlag is alleen van toepassing op CBV, SRV, UAV en samplers. Het is niet van toepassing op andere descriptor heap-typen, omdat shaders niet rechtstreeks naar de andere typen verwijzen.

Beschrijf en maak bijvoorbeeld een sampler descriptor heap.

// Describe and create a sampler descriptor heap.
D3D12_DESCRIPTOR_HEAP_DESC samplerHeapDesc = {};
samplerHeapDesc.NumDescriptors = 1;
samplerHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER;
samplerHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
ThrowIfFailed(m_device->CreateDescriptorHeap(&samplerHeapDesc, IID_PPV_ARGS(&m_samplerHeap)));

Beschrijf en maak een constante bufferweergave (CBV), een shader-resourceweergave (SRV) en een niet-geordende toegangsweergave (UAV)-descriptorheap.

// Describe and create a shader resource view (SRV) and unordered
// access view (UAV) descriptor heap.
D3D12_DESCRIPTOR_HEAP_DESC srvUavHeapDesc = {};
srvUavHeapDesc.NumDescriptors = DescriptorCount;
srvUavHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
srvUavHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
ThrowIfFailed(m_device->CreateDescriptorHeap(&srvUavHeapDesc, IID_PPV_ARGS(&m_srvUavHeap)));

m_rtvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
m_srvUavDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);

Descriptorverwijzingen

De D3D12_GPU_DESCRIPTOR_HANDLE- en D3D12_CPU_DESCRIPTOR_HANDLE structuren identificeren specifieke descriptors in een descriptorheap. Een handle is een beetje zoals een pointer, maar de toepassing mag deze niet handmatig derefereren; anders is het gedrag ongedefinieerd. Het gebruik van de handlers moet via de API worden uitgevoerd. Een handle zelf kan vrij worden gekopieerd of worden doorgegeven aan API's die werken met descriptors. Er is geen referentietelling, dus de toepassing moet ervoor zorgen dat deze geen handle gebruikt nadat de onderliggende descriptor heap is gewist.

Toepassingen kunnen de incrementgrootte van de descriptors voor een gegeven type descriptorheap bepalen, zodat ze handles kunnen genereren naar elke locatie binnen een descriptorheap, beginnend vanaf de handle naar de basis. Toepassingen mogen nooit descriptor-handles ophardcoderen en moeten deze altijd opvragen voor een bepaalde apparaatexemplaar; anders is het gedrag ongedefinieerd. Toepassingen mogen ook niet gebruikmaken van de incrementele grootten en ingangen om hun eigen onderzoek of manipulatie van descriptor heap-gegevens uit te voeren, omdat de resultaten hiervan niet zijn gedefinieerd. De handles worden mogelijk niet daadwerkelijk gebruikt als aanwijzers, maar in plaats daarvan als proxy's voor aanwijzers om onbedoelde dereferencing te voorkomen.

Notitie

Er is een helperstructuur, CD3DX12_GPU_DESCRIPTOR_HANDLE, gedefinieerd in de header d3dx12.h, die de D3D12_GPU_DESCRIPTOR_HANDLE structuur over neemt en initialisatie en andere nuttige bewerkingen biedt. Op dezelfde manier wordt de CD3DX12_CPU_DESCRIPTOR_HANDLE helperstructuur gedefinieerd voor de D3D12_CPU_DESCRIPTOR_HANDLE structuur.

 

Beide helperstructuren worden gebruikt bij het invullen van opdrachtlijsten.

// Fill the command list with all the render commands and dependent state.
void D3D12nBodyGravity::PopulateCommandList()
{
    // Command list allocators can only be reset when the associated
    // command lists have finished execution on the GPU; apps should use
    // fences to determine GPU execution progress.
    ThrowIfFailed(m_commandAllocators[m_frameIndex]->Reset());

    // However, when ExecuteCommandList() is called on a particular command
    // list, that command list can then be reset at any time and must be before
    // re-recording.
    ThrowIfFailed(m_commandList->Reset(m_commandAllocators[m_frameIndex].Get(), m_pipelineState.Get()));

    // Set necessary state.
    m_commandList->SetPipelineState(m_pipelineState.Get());
    m_commandList->SetGraphicsRootSignature(m_rootSignature.Get());

    m_commandList->SetGraphicsRootConstantBufferView(RootParameterCB, m_constantBufferGS->GetGPUVirtualAddress() + m_frameIndex * sizeof(ConstantBufferGS));

    ID3D12DescriptorHeap* ppHeaps[] = { m_srvUavHeap.Get() };
    m_commandList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps);

    m_commandList->IASetVertexBuffers(0, 1, &m_vertexBufferView);
    m_commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_POINTLIST);
    m_commandList->RSSetScissorRects(1, &m_scissorRect);

    // Indicate that the back buffer will be used as a render target.
    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.0f, 0.0f, 0.1f, 0.0f };
    m_commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr);

    // Render the particles.
    float viewportHeight = static_cast<float>(static_cast<UINT>(m_viewport.Height) / m_heightInstances);
    float viewportWidth = static_cast<float>(static_cast<UINT>(m_viewport.Width) / m_widthInstances);
    for (UINT n = 0; n < ThreadCount; n++)
    {
        const UINT srvIndex = n + (m_srvIndex[n] == 0 ? SrvParticlePosVelo0 : SrvParticlePosVelo1);

        D3D12_VIEWPORT viewport;
        viewport.TopLeftX = (n % m_widthInstances) * viewportWidth;
        viewport.TopLeftY = (n / m_widthInstances) * viewportHeight;
        viewport.Width = viewportWidth;
        viewport.Height = viewportHeight;
        viewport.MinDepth = D3D12_MIN_DEPTH;
        viewport.MaxDepth = D3D12_MAX_DEPTH;
        m_commandList->RSSetViewports(1, &viewport);

        CD3DX12_GPU_DESCRIPTOR_HANDLE srvHandle(m_srvUavHeap->GetGPUDescriptorHandleForHeapStart(), srvIndex, m_srvUavDescriptorSize);
        m_commandList->SetGraphicsRootDescriptorTable(RootParameterSRV, srvHandle);

        m_commandList->DrawInstanced(ParticleCount, 1, 0, 0);
    }

    m_commandList->RSSetViewports(1, &m_viewport);

    // 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());
}

Descriptor Heap-methoden

Descriptor heaps (ID3D12DescriptorHeap) nemen over van ID3D12Pageable. Dit legt de verantwoordelijkheid op voor het verblijfsbeheer van descriptor heaps op toepassingen, net als resource-heaps. De methoden voor residentiebeheer zijn alleen van toepassing op shader-zichtbare heaps, omdat de niet shader-zichtbare heaps niet rechtstreeks zichtbaar zijn voor de GPU.

Met de methode ID3D12Device::GetDescriptorHandleIncrementSize kunnen toepassingen handgrepen handmatig verplaatsen binnen een heap, waardoor handgrepen naar willekeurige locaties in een descriptorheap kunnen worden geproduceerd. De handle van de beginlocatie van de heap is afkomstig van ID3D12DescriptorHeap::GetCPUDescriptorHandleForHeapStart/ID3D12DescriptorHeap::GetGPUDescriptorHandleForHeapStart. Verschuiving wordt uitgevoerd door de incrementele grootte * het aantal descriptors toe te voegen dat moet worden verschoven naar de heap-begin van de descriptor. Houd er rekening mee dat de incrementele grootte niet kan worden beschouwd als een bytegrootte, omdat toepassingen geen deductiegrepen mogen gebruiken alsof ze geheugen zijn. Het geheugen waarnaar wordt verwezen, heeft een niet-gestandaardiseerde indeling en kan zelfs variëren voor een bepaald apparaat.

GetCPUDescriptorHandleForHeapStart retourneert een CPU-handle voor CPU-zichtbare descriptor-heaps. Er wordt een NULL-ingang geretourneerd (en de foutopsporingslaag rapporteert een fout) als de heap van de descriptor niet zichtbaar is voor CPU.

GetGPUDescriptorHandleForHeapStart retourneert een GPU-handvat voor shader-zichtbare descriptor-heaps. Er wordt een NULL-handle geretourneerd (en de foutopsporingslaag rapporteert een fout) als de descriptorheap niet zichtbaar is voor de shader.

U kunt bijvoorbeeld rendertargets maken om D2D-tekst weer te geven met behulp van een 11-op-12-apparaat.

    // Create descriptor heaps.
    {
        // Describe and create a render target view (RTV) descriptor heap.
        D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {};
        rtvHeapDesc.NumDescriptors = FrameCount;
        rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
        rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
        ThrowIfFailed(m_d3d12Device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&m_rtvHeap)));

        m_rtvDescriptorSize = m_d3d12Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
    }

    // Create frame resources.
    {
        CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart());

        // Create a RTV, D2D render target, and a command allocator for each frame.
        for (UINT n = 0; n < FrameCount; n++)
        {
            ThrowIfFailed(m_swapChain->GetBuffer(n, IID_PPV_ARGS(&m_renderTargets[n])));
            m_d3d12Device->CreateRenderTargetView(m_renderTargets[n].Get(), nullptr, rtvHandle);

            // Create a wrapped 11On12 resource of this back buffer. Since we are 
            // rendering all D3D12 content first and then all D2D content, we specify 
            // the In resource state as RENDER_TARGET - because D3D12 will have last 
            // used it in this state - and the Out resource state as PRESENT. When 
            // ReleaseWrappedResources() is called on the 11On12 device, the resource 
            // will be transitioned to the PRESENT state.
            D3D11_RESOURCE_FLAGS d3d11Flags = { D3D11_BIND_RENDER_TARGET };
            ThrowIfFailed(m_d3d11On12Device->CreateWrappedResource(
                m_renderTargets[n].Get(),
                &d3d11Flags,
                D3D12_RESOURCE_STATE_RENDER_TARGET,
                D3D12_RESOURCE_STATE_PRESENT,
                IID_PPV_ARGS(&m_wrappedBackBuffers[n])
                ));

            // Create a render target for D2D to draw directly to this back buffer.
            ComPtr<IDXGISurface> surface;
            ThrowIfFailed(m_wrappedBackBuffers[n].As(&surface));
            ThrowIfFailed(m_d2dDeviceContext->CreateBitmapFromDxgiSurface(
                surface.Get(),
                &bitmapProperties,
                &m_d2dRenderTargets[n]
                ));

            rtvHandle.Offset(1, m_rtvDescriptorSize);

            ThrowIfFailed(m_d3d12Device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_commandAllocators[n])));
        }
    
    }

Minimale heap-wrapper voor descriptor

Toepassingsontwikkelaars willen waarschijnlijk hun eigen helpercode bouwen voor het beheren van descriptorhandgrepen en heaps. Hieronder ziet u een basisvoorbeeld. Meer geavanceerde wrappers kunnen bijvoorbeeld bijhouden welke typen descriptors zich in een heap bevinden en de argumenten voor het maken van de descriptor opslaan.

class CDescriptorHeapWrapper
{
public:
    CDescriptorHeapWrapper() { memset(this, 0, sizeof(*this)); }

    HRESULT Create(
        ID3D12Device* pDevice, 
        D3D12_DESCRIPTOR_HEAP_TYPE Type, 
        UINT NumDescriptors, 
        bool bShaderVisible = false)
    {
        D3D12_DESCRIPTOR_HEAP_DESC Desc;
        Desc.Type = Type;
        Desc.NumDescriptors = NumDescriptors;
        Desc.Flags = (bShaderVisible ? D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE : D3D12_DESCRIPTOR_HEAP_FLAG_NONE);
       
        HRESULT hr = pDevice->CreateDescriptorHeap(&Desc, 
                               __uuidof(ID3D12DescriptorHeap), 
                               (void**)&pDH);
        if (FAILED(hr)) return hr;

        hCPUHeapStart = pDH->GetCPUDescriptorHandleForHeapStart();
        hGPUHeapStart = pDH->GetGPUDescriptorHandleForHeapStart();

        HandleIncrementSize = pDevice->GetDescriptorHandleIncrementSize(Desc.Type);
        return hr;
    }
    operator ID3D12DescriptorHeap*() { return pDH; }

    D3D12_CPU_DESCRIPTOR_HANDLE hCPU(UINT index)
    {
        return hCPUHeapStart.MakeOffsetted(index,HandleIncrementSize); 
    }
    D3D12_GPU_DESCRIPTOR_HANDLE hGPU(UINT index) 
    {
        assert(Desc.Flags&D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE); 
        return hGPUHeapStart.MakeOffsetted(index,HandleIncrementSize); 
    }
    D3D12_DESCRIPTOR_HEAP_DESC Desc;
    CComPtr<ID3D12DescriptorHeap> pDH;
    D3D12_CPU_DESCRIPTOR_HANDLE hCPUHeapStart;
    D3D12_GPU_DESCRIPTOR_HANDLE hGPUHeapStart;
    UINT HandleIncrementSize;
};

Descriptor Heaps