ID3D12GraphicsCommandList::ExecuteIndirect メソッド (d3d12.h)

アプリは ExecuteIndirect メソッドを使用して間接描画/ディスパッチを実行します。

構文

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

パラメーター

[in] pCommandSignature

種類: ID3D12CommandSignature*

ID3D12CommandSignature を指定します。 pArgumentBuffer によって参照されるデータは、コマンド署名の内容に応じて解釈されます。 コマンド署名の作成に使用される API については、「 間接描画 」を参照してください。

[in] MaxCommandCount

型: UINT

コマンド数を指定する方法は 2 つあります。

  • pCountBuffer が NULL でない場合、MaxCommandCount は実行される操作の最大数を指定します。 実行される操作の実際の数は、この値の最小値と、 pCountBuffer に含まれる 32 ビット符号なし整数 ( CountBufferOffset で指定されたバイト オフセット) によって定義されます。
  • pCountBuffer が NULL の場合、MaxCommandCount は実行される操作の正確な数を指定します。

[in] pArgumentBuffer

種類: ID3D12Resource*

コマンド引数を含む 1 つ以上の ID3D12Resource オブジェクトを指定します。

[in] ArgumentBufferOffset

種類: UINT64

最初のコマンド引数を識別するために pArgumentBuffer へのオフセットを指定します。

[in, optional] pCountBuffer

種類: ID3D12Resource*

ID3D12Resource へのポインターを指定します。

[in] CountBufferOffset

種類: UINT64

引数数を識別する 、pCountBuffer へのオフセットである UINT64 を指定します。

戻り値

なし

解説

この API のセマンティクスは、次の擬似コードで定義されます。

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

カウント バッファーまたは引数バッファーのいずれかがD3D12_RESOURCE_STATE_INDIRECT_ARGUMENT状態でない場合、デバッグ レイヤーはエラーを発行します。 コア ランタイムでは、次の検証が行われます。

  • CountBufferOffsetArgumentBufferOffset は 4 バイトでアラインされています
  • pCountBufferpArgumentBuffer はバッファー リソース (任意のヒープの種類) です
  • MaxCommandCountArgumentBufferOffset、および描画プログラムストライドによって暗黙的に指定されたオフセットが、pArgumentBuffer の境界を超えないようにします (同様にカウント バッファーの場合)
  • コマンド リストは、直接コマンド リストまたはコンピューティング コマンド リストです (コピーまたは JPEG デコード コマンド リストではありません)
  • コマンド リストのルート署名は、コマンド署名のルート署名と一致します
以前のバージョンの Direct3D と DrawIndexedInstancedIndirectの 2 つの API の機能は、 DrawInstancedIndirectExecuteIndirect に含まれています。

バンドル

ID3D12GraphicsCommandList::ExecuteIndirect は、次のすべてが当てはまる場合にのみ、バンドル コマンド リスト内で使用できます。
  • CountBuffer は NULL (CPU 指定のカウントのみ) です。
  • コマンド シグネチャには、1 つの操作が含まれています。 これは、コマンド署名にルート引数の変更が含まれていないか、VB/IB バインドの変更が含まれていないことを意味します。

バッファー仮想アドレスの取得

ID3D12Resource::GetGPUVirtualAddress メソッドを使用すると、アプリはバッファーの GPU 仮想アドレスを取得できます。

アプリは、間接引数バッファーに配置する前に、仮想アドレスにバイト オフセットを自由に適用できます。 VB/IB/CB のすべての D3D12 アラインメント要件は、引き続き結果の GPU 仮想アドレスに適用されることに注意してください。

D3D12ExecuteIndirect サンプルでは、次のように ID3D12GraphicsCommandList::ExecuteIndirect を使用します。

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

ExecuteIndirect の呼び出しは、この一覧の最後近くで、"カリングされていない三角形を描画する" というコメントの下にあります。

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

「D3D12 リファレンス」のコード例を参照してください

要件

   
対象プラットフォーム Windows
ヘッダー d3d12.h
Library D3d12.lib
[DLL] D3d12.dll

関連項目

ID3D12GraphicsCommandList

間接的な描画