Partager via


ID3D12GraphicsCommandList::ExecuteIndirect, méthode (d3d12.h)

Les applications effectuent des tirages/distributions indirects à l’aide de la méthode ExecuteIndirect .

Syntaxe

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

Paramètres

[in] pCommandSignature

Type : ID3D12CommandSignature*

Spécifie un ID3D12CommandSignature. Les données référencées par pArgumentBuffer seront interprétées en fonction du contenu de la signature de commande. Reportez-vous à Dessin indirect pour les API utilisées pour créer une signature de commande.

[in] MaxCommandCount

Type : UINT

Il existe deux façons de spécifier le nombre de commandes :

  • Si pCountBuffer n’a pas la valeur NULL, MaxCommandCount spécifie le nombre maximal d’opérations qui seront effectuées. Le nombre réel d’opérations à effectuer est défini par le minimum de cette valeur et par un entier non signé 32 bits contenu dans pCountBuffer (au décalage d’octets spécifié par CountBufferOffset).
  • Si pCountBuffer a la valeur NULL, MaxCommandCount spécifie le nombre exact d’opérations qui seront effectuées.

[in] pArgumentBuffer

Type : ID3D12Resource*

Spécifie un ou plusieurs objets ID3D12Resource , contenant les arguments de commande.

[in] ArgumentBufferOffset

Type : UINT64

Spécifie un décalage dans pArgumentBuffer pour identifier le premier argument de commande.

[in, optional] pCountBuffer

Type : ID3D12Resource*

Spécifie un pointeur vers un ID3D12Resource.

[in] CountBufferOffset

Type : UINT64

Spécifie un UINT64 qui est le décalage dans pCountBuffer, identifiant le nombre d’arguments.

Valeur de retour

None

Notes

La sémantique de cette API est définie avec le pseudo-code suivant :

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

La couche de débogage émet une erreur si la mémoire tampon de nombre ou la mémoire tampon d’arguments ne sont pas dans l’état D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT. Le runtime principal valide :

  • CountBufferOffset et ArgumentBufferOffset sont alignés sur 4 octets
  • pCountBuffer et pArgumentBuffer sont des ressources de mémoire tampon (n’importe quel type de tas)
  • Le décalage impliqué par MaxCommandCount, ArgumentBufferOffset et la foulée du programme de dessin ne dépassent pas les limites de pArgumentBuffer (de la même façon pour la mémoire tampon de nombre)
  • La liste de commandes est une liste de commandes directes ou une liste de commandes de calcul (pas une liste de commandes de copie ou de décodage JPEG)
  • La signature racine de la liste de commandes correspond à la signature racine de la signature de commande
Les fonctionnalités de deux API des versions antérieures de Direct3D et DrawInstancedIndirectDrawIndexedInstancedIndirect, sont comprises dans ExecuteIndirect.

Paquets

ID3D12GraphicsCommandList::ExecuteIndirect est autorisé à l’intérieur des listes de commandes groupées uniquement si toutes les conditions suivantes sont remplies :
  • CountBuffer a la valeur NULL (nombre spécifié par le processeur uniquement).
  • La signature de commande contient exactement une opération. Cela implique que la signature de commande ne contient pas de modifications d’arguments racine, ni de modifications de liaison VB/IB.

Obtention d’adresses virtuelles de mémoire tampon

La méthode ID3D12Resource::GetGPUVirtualAddress permet à une application de récupérer l’adresse virtuelle GPU d’une mémoire tampon.

Les applications sont libres d’appliquer des décalages d’octets aux adresses virtuelles avant de les placer dans une mémoire tampon d’arguments indirects. Notez que toutes les exigences d’alignement D3D12 pour VB/IB/CB s’appliquent toujours à l’adresse virtuelle GPU résultante.

Exemples

L’exemple D3D12ExecuteIndirect utilise ID3D12GraphicsCommandList::ExecuteIndirect comme suit :

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

L’appel à ExecuteIndirect est proche de la fin de cette liste, sous le commentaire « Dessiner les triangles qui n’ont pas été abattus ».

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

Consultez l’exemple de code dans la référence D3D12.

Spécifications

   
Plateforme cible Windows
En-tête d3d12.h
Bibliothèque D3d12.lib
DLL D3d12.dll

Voir aussi

ID3D12GraphicsCommandList

Dessin indirect