Condividi tramite


Metodo ID3D12GraphicsCommandList::ExecuteIndirect (d3d12.h)

Le app eseguono estrazioni/invii indiretti usando il metodo ExecuteIndirect .

Sintassi

void ExecuteIndirect(
  [in]           ID3D12CommandSignature *pCommandSignature,
  [in]           UINT                   MaxCommandCount,
  [in]           ID3D12Resource         *pArgumentBuffer,
  [in]           UINT64                 ArgumentBufferOffset,
  [in, optional] ID3D12Resource         *pCountBuffer,
  [in]           UINT64                 CountBufferOffset
);

Parametri

[in] pCommandSignature

Tipo: ID3D12CommandSignature*

Specifica un ID3D12CommandSignature. I dati a cui fa riferimento pArgumentBuffer verranno interpretati a seconda del contenuto della firma del comando. Fare riferimento a Disegno indiretto per le API usate per creare una firma di comando.

[in] MaxCommandCount

Tipo: UINT

È possibile specificare i conteggi dei comandi in due modi:

  • Se pCountBuffer non è NULL, MaxCommandCount specifica il numero massimo di operazioni che verranno eseguite. Il numero effettivo di operazioni da eseguire è definito dal valore minimo di questo valore e un intero senza segno a 32 bit contenuto in pCountBuffer (in corrispondenza dell'offset di byte specificato da CountBufferOffset).
  • Se pCountBuffer è NULL, MaxCommandCount specifica il numero esatto di operazioni che verranno eseguite.

[in] pArgumentBuffer

Tipo: ID3D12Resource*

Specifica uno o più oggetti ID3D12Resource contenenti gli argomenti del comando.

[in] ArgumentBufferOffset

Tipo: UINT64

Specifica un offset in pArgumentBuffer per identificare il primo argomento del comando.

[in, optional] pCountBuffer

Tipo: ID3D12Resource*

Specifica un puntatore a un OGGETTO ID3D12Resource.

[in] CountBufferOffset

Tipo: UINT64

Specifica un oggetto UINT64 che rappresenta l'offset in pCountBuffer, identificando il numero di argomenti.

Valore restituito

nessuno

Osservazioni

La semantica di questa API viene definita con lo pseudo-codice seguente:

PCountBuffer non NULL:

// Read draw count out of count buffer
UINT CommandCount = pCountBuffer->ReadUINT32(CountBufferOffset);

CommandCount = min(CommandCount, MaxCommandCount)

// Get pointer to first Commanding argument
BYTE* Arguments = pArgumentBuffer->GetBase() + ArgumentBufferOffset;

for(UINT CommandIndex = 0; CommandIndex < CommandCount; CommandIndex++)
{
  // Interpret the data contained in *Arguments
  // according to the command signature
  pCommandSignature->Interpret(Arguments);

  Arguments += pCommandSignature->GetByteStride();
}

NULL pCountBuffer:

// Get pointer to first Commanding argument
BYTE* Arguments = pArgumentBuffer->GetBase() + ArgumentBufferOffset;

for(UINT CommandIndex = 0; CommandIndex < MaxCommandCount; CommandIndex++)
{
  // Interpret the data contained in *Arguments
  // according to the command signature
  pCommandSignature->Interpret(Arguments);

  Arguments += pCommandSignature->GetByteStride();
}

Il livello di debug genera un errore se il buffer count o il buffer dell'argomento non sono nello stato D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT. Il runtime di base convaliderà:

  • CountBufferOffset e ArgumentBufferOffset sono allineati a 4 byte
  • pCountBuffer e pArgumentBuffer sono risorse buffer (qualsiasi tipo heap)
  • L'offset implicito da MaxCommandCount, ArgumentBufferOffset e lo stride del programma di disegno non superano i limiti di pArgumentBuffer (analogamente per il buffer di conteggio)
  • L'elenco dei comandi è un elenco di comandi diretto o un elenco di comandi di calcolo (non un elenco di comandi di decodifica JPEG o copia)
  • La firma radice dell'elenco di comandi corrisponde alla firma radice della firma del comando
Le funzionalità di due API delle versioni precedenti di Direct3D DrawInstancedIndirect e DrawIndexedInstancedIndirect, sono inclusi in ExecuteIndirect.

Pacchetti

ID3D12GraphicsCommandList::ExecuteIndirect è consentito all'interno degli elenchi di comandi bundle solo se tutte le condizioni seguenti sono vere:
  • CountBuffer è NULL (solo conteggio specificato dalla CPU).
  • La firma del comando contiene esattamente un'operazione. Ciò implica che la firma del comando non contiene modifiche agli argomenti radice, né contiene modifiche all'associazione VB/IB.

Recupero di indirizzi virtuali del buffer

Il metodo ID3D12Resource::GetGPUVirtualAddress consente a un'app di recuperare l'indirizzo virtuale GPU di un buffer.

Le app possono applicare offset di byte agli indirizzi virtuali prima di inserirli in un buffer di argomenti indiretti. Si noti che tutti i requisiti di allineamento D3D12 per VB/IB/CB si applicano comunque all'indirizzo virtuale GPU risultante.

Esempio

L'esempio D3D12ExecuteIndirect usa ID3D12GraphicsCommandList::ExecuteIndirect come indicato di seguito:

// Data structure to match the command signature used for ExecuteIndirect.
struct IndirectCommand
{
    D3D12_GPU_VIRTUAL_ADDRESS cbv;
    D3D12_DRAW_ARGUMENTS drawArguments;
};

La chiamata a ExecuteIndirect si trova vicino alla fine di questo elenco, sotto il commento "Disegnare i triangoli che non sono stati codificati".

// Fill the command list with all the render commands and dependent state.
void D3D12ExecuteIndirect::PopulateCommandLists()
{
    // 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_computeCommandAllocators[m_frameIndex]->Reset());
    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_computeCommandList->Reset(m_computeCommandAllocators[m_frameIndex].Get(), m_computeState.Get()));
    ThrowIfFailed(m_commandList->Reset(m_commandAllocators[m_frameIndex].Get(), m_pipelineState.Get()));

    // Record the compute commands that will cull triangles and prevent them from being processed by the vertex shader.
    if (m_enableCulling)
    {
        UINT frameDescriptorOffset = m_frameIndex * CbvSrvUavDescriptorCountPerFrame;
        D3D12_GPU_DESCRIPTOR_HANDLE cbvSrvUavHandle = m_cbvSrvUavHeap->GetGPUDescriptorHandleForHeapStart();

        m_computeCommandList->SetComputeRootSignature(m_computeRootSignature.Get());

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

        m_computeCommandList->SetComputeRootDescriptorTable(
            SrvUavTable,
            CD3DX12_GPU_DESCRIPTOR_HANDLE(cbvSrvUavHandle, CbvSrvOffset + frameDescriptorOffset, m_cbvSrvUavDescriptorSize));

        m_computeCommandList->SetComputeRoot32BitConstants(RootConstants, 4, reinterpret_cast<void*>(&m_csRootConstants), 0);

        // Reset the UAV counter for this frame.
        m_computeCommandList->CopyBufferRegion(m_processedCommandBuffers[m_frameIndex].Get(), CommandBufferSizePerFrame, m_processedCommandBufferCounterReset.Get(), 0, sizeof(UINT));

        D3D12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(m_processedCommandBuffers[m_frameIndex].Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
        m_computeCommandList->ResourceBarrier(1, &barrier);

        m_computeCommandList->Dispatch(static_cast<UINT>(ceil(TriangleCount / float(ComputeThreadBlockSize))), 1, 1);
    }

    ThrowIfFailed(m_computeCommandList->Close());

    // Record the rendering commands.
    {
        // Set necessary state.
        m_commandList->SetGraphicsRootSignature(m_rootSignature.Get());

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

        m_commandList->RSSetViewports(1, &m_viewport);
        m_commandList->RSSetScissorRects(1, m_enableCulling ? &m_cullingScissorRect : &m_scissorRect);

        // Indicate that the command buffer will be used for indirect drawing
        // and that the back buffer will be used as a render target.
        D3D12_RESOURCE_BARRIER barriers[2] = {
            CD3DX12_RESOURCE_BARRIER::Transition(
                m_enableCulling ? m_processedCommandBuffers[m_frameIndex].Get() : m_commandBuffer.Get(),
                m_enableCulling ? D3D12_RESOURCE_STATE_UNORDERED_ACCESS : D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
                D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT),
            CD3DX12_RESOURCE_BARRIER::Transition(
                m_renderTargets[m_frameIndex].Get(),
                D3D12_RESOURCE_STATE_PRESENT,
                D3D12_RESOURCE_STATE_RENDER_TARGET)
        };

        m_commandList->ResourceBarrier(_countof(barriers), barriers);

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

        // Record commands.
        const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f };
        m_commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr);
        m_commandList->ClearDepthStencilView(dsvHandle, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr);

        m_commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
        m_commandList->IASetVertexBuffers(0, 1, &m_vertexBufferView);

        if (m_enableCulling)
        {
            // Draw the triangles that have not been culled.
            m_commandList->ExecuteIndirect(
                m_commandSignature.Get(),
                TriangleCount,
                m_processedCommandBuffers[m_frameIndex].Get(),
                0,
                m_processedCommandBuffers[m_frameIndex].Get(),
                CommandBufferSizePerFrame);
        }
        else
        {
            // Draw all of the triangles.
            m_commandList->ExecuteIndirect(
                m_commandSignature.Get(),
                TriangleCount,
                m_commandBuffer.Get(),
                CommandBufferSizePerFrame * m_frameIndex,
                nullptr,
                0);
        }

        // Indicate that the command buffer may be used by the compute shader
        // and that the back buffer will now be used to present.
        barriers[0].Transition.StateBefore = D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT;
        barriers[0].Transition.StateAfter = m_enableCulling ? D3D12_RESOURCE_STATE_COPY_DEST : D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
        barriers[1].Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
        barriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;

        m_commandList->ResourceBarrier(_countof(barriers), barriers);

        ThrowIfFailed(m_commandList->Close());
    }
}

Vedere Codice di esempio nel riferimento D3D12.

Requisiti

   
Piattaforma di destinazione Windows
Intestazione d3d12.h
Libreria D3d12.lib
DLL D3d12.dll

Vedi anche

ID3D12GraphicsCommandList

Disegno indiretto