Share via


Método ID3D12GraphicsCommandList::ExecuteIndirect (d3d12.h)

Las aplicaciones realizan draws/dispatches indirectos mediante el método ExecuteIndirect .

Sintaxis

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

Parámetros

[in] pCommandSignature

Tipo: ID3D12CommandSignature*

Especifica un id3D12CommandSignature. Los datos a los que hace referencia pArgumentBuffer se interpretarán en función del contenido de la firma del comando. Consulte Dibujo indirecto para las API que se usan para crear una firma de comando.

[in] MaxCommandCount

Tipo: UINT

Hay dos maneras de especificar los recuentos de comandos:

  • Si pCountBuffer no es NULL, MaxCommandCount especifica el número máximo de operaciones que se realizarán. El número real de operaciones que se van a realizar se define mediante el mínimo de este valor y un entero de 32 bits sin signo contenido en pCountBuffer (en el desplazamiento de bytes especificado por CountBufferOffset).
  • Si pCountBuffer es NULL, MaxCommandCount especifica el número exacto de operaciones que se realizarán.

[in] pArgumentBuffer

Tipo: ID3D12Resource*

Especifica uno o varios objetos ID3D12Resource , que contienen los argumentos de comando.

[in] ArgumentBufferOffset

Tipo: UINT64

Especifica un desplazamiento en pArgumentBuffer para identificar el primer argumento de comando.

[in, optional] pCountBuffer

Tipo: ID3D12Resource*

Especifica un puntero a un id3D12Resource.

[in] CountBufferOffset

Tipo: UINT64

Especifica un UINT64 que es el desplazamiento en pCountBuffer, que identifica el recuento de argumentos.

Valor devuelto

Ninguno

Observaciones

La semántica de esta API se define con el siguiente pseudocódigo:

PCountBuffer no 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 capa de depuración emitirá un error si el búfer de recuento o el búfer de argumentos no están en estado D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT. El entorno de ejecución principal validará:

  • CountBufferOffset y ArgumentBufferOffset están alineados con 4 bytes
  • pCountBuffer y pArgumentBuffer son recursos de búfer (cualquier tipo de montón)
  • El desplazamiento implícito en MaxCommandCount, ArgumentBufferOffset y el intervalo del programa de dibujo no superan los límites de pArgumentBuffer (de forma similar para el búfer de recuento)
  • La lista de comandos es una lista de comandos directa o una lista de comandos de proceso (no una lista de comandos de copia o descodificación JPEG)
  • La firma raíz de la lista de comandos coincide con la firma raíz de la firma del comando.
La funcionalidad de dos API de versiones anteriores de Direct3D DrawInstancedIndirect y DrawIndexedInstancedIndirect, se engloban en ExecuteIndirect.

Paquetes

ID3D12GraphicsCommandList::ExecuteIndirect se permite dentro de listas de comandos de agrupación solo si se cumplen todas las siguientes condiciones:
  • CountBuffer es NULL (solo recuento especificado por cpu).
  • La firma de comando contiene exactamente una operación. Esto implica que la firma del comando no contiene cambios de argumentos raíz, ni contiene cambios de enlace vb/IB.

Obtención de direcciones virtuales de búfer

El método ID3D12Resource::GetGPUVirtualAddress permite a una aplicación recuperar la dirección virtual de GPU de un búfer.

Las aplicaciones son gratuitas para aplicar desplazamientos de bytes a direcciones virtuales antes de colocarlas en un búfer de argumentos indirecto. Tenga en cuenta que todos los requisitos de alineación D3D12 para VB/IB/CB se siguen aplicando a la dirección virtual de GPU resultante.

Ejemplos

El ejemplo D3D12ExecuteIndirect usa ID3D12GraphicsCommandList::ExecuteIndirect de la siguiente manera:

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

La llamada a ExecuteIndirect está cerca del final de esta lista, debajo del comentario "Dibujar los triángulos que no se han eliminado".

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

Vea Código de ejemplo en la referencia D3D12.

Requisitos

   
Plataforma de destino Windows
Encabezado d3d12.h
Library D3d12.lib
Archivo DLL D3d12.dll

Consulte también

ID3D12GraphicsCommandList

Dibujo indirecto