Freigeben über


ID3D12GraphicsCommandList::ExecuteIndirect-Methode (d3d12.h)

Apps führen indirekte Ziehungen/Versendungen mithilfe der ExecuteIndirect-Methode durch.

Syntax

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

Parameter

[in] pCommandSignature

Typ: ID3D12CommandSignature*

Gibt einen ID3D12CommandSignature an. Die von pArgumentBuffer referenzierten Daten werden abhängig vom Inhalt der Befehlssignatur interpretiert. Informationen zu den APIs, die zum Erstellen einer Befehlssignatur verwendet werden, finden Sie unter Indirekte Zeichnung .

[in] MaxCommandCount

Typ: UINT

Es gibt zwei Möglichkeiten, die Befehlsanzahl anzugeben:

  • Wenn pCountBuffer nicht NULL ist, gibt MaxCommandCount die maximale Anzahl von Vorgängen an, die ausgeführt werden. Die tatsächliche Anzahl der auszuführenden Vorgänge wird durch das Minimum dieses Werts und eine 32-Bit-Ganzzahl ohne Vorzeichen definiert, die in pCountBuffer enthalten ist (bei dem byte-Offset, der von CountBufferOffset angegeben wird).
  • Wenn pCountBuffer NULL ist, gibt maxCommandCount die genaue Anzahl von Vorgängen an, die ausgeführt werden.

[in] pArgumentBuffer

Typ: ID3D12Resource*

Gibt mindestens ein ID3D12Resource-Objekt an, das die Befehlsargumente enthält.

[in] ArgumentBufferOffset

Typ: UINT64

Gibt einen Offset in pArgumentBuffer an, um das erste Befehlsargument zu identifizieren.

[in, optional] pCountBuffer

Typ: ID3D12Resource*

Gibt einen Zeiger auf eine ID3D12Resource an.

[in] CountBufferOffset

Typ: UINT64

Gibt einen UINT64-Wert an, der den Offset in pCountBuffer darstellt, um die Argumentanzahl zu identifizieren.

Rückgabewert

Keine

Bemerkungen

Die Semantik dieser API wird mit dem folgenden Pseudocode definiert:

Nicht-NULL pCountBuffer:

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

Die Debugebene gibt einen Fehler aus, wenn sich entweder der Zählungspuffer oder der Argumentpuffer nicht im D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT Zustand befinden. Die Core Runtime überprüft Folgendes:

  • CountBufferOffset und ArgumentBufferOffset sind 4 Byte ausgerichtet.
  • pCountBuffer und pArgumentBuffer sind Pufferressourcen (beliebige Heaptypen)
  • Der von MaxCommandCount, ArgumentBufferOffset und dem Zeichnungsprogramm "stride" implizierte Offset überschreitet die Grenzen von pArgumentBuffer nicht (ähnlich für den Count-Puffer).
  • Die Befehlsliste ist eine direkte Befehlsliste oder eine Computebefehlsliste (keine Kopier- oder JPEG-Decodierungsbefehlsliste).
  • Die Stammsignatur der Befehlsliste entspricht der Stammsignatur der Befehlssignatur.
Die Funktionalität von zwei APIs aus früheren Versionen von Direct3D DrawInstancedIndirect und DrawIndexedInstancedIndirectumfasst ExecuteIndirect.

Bündel

ID3D12GraphicsCommandList::ExecuteIndirect ist in Bündelbefehlslisten nur zulässig, wenn alle folgenden Elemente zutrifft:
  • CountBuffer ist NULL (nur CPU-angegebene Anzahl).
  • Die Befehlssignatur enthält genau einen Vorgang. Dies bedeutet, dass die Befehlssignatur keine Änderungen an Stammargumenten enthält und keine VB/IB-Bindungsänderungen enthält.

Abrufen virtueller Pufferadressen

Mit der ID3D12Resource::GetGPUVirtualAddress-Methode kann eine App die virtuelle GPU-Adresse eines Puffers abrufen.

Apps können Byteoffsets auf virtuelle Adressen anwenden, bevor sie sie in einen indirekten Argumentpuffer legen. Beachten Sie, dass alle D3D12-Ausrichtungsanforderungen für VB/IB/CB weiterhin für die resultierende virtuelle GPU-Adresse gelten.

Beispiele

Das D3D12ExecuteIndirect-Beispiel verwendet ID3D12GraphicsCommandList::ExecuteIndirect wie folgt:

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

Der Aufruf von ExecuteIndirect befindet sich am Ende dieser Auflistung unter dem Kommentar "Zeichnen Sie die Dreiecke, die nicht gekullt wurden".

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

Siehe Beispielcode in der D3D12-Referenz.

Anforderungen

   
Zielplattform Windows
Kopfzeile d3d12.h
Bibliothek D3d12.lib
DLL D3d12.dll

Weitere Informationen

ID3D12GraphicsCommandList

Indirektes Zeichnen