ID3D12GraphicsCommandList::Metode ExecuteIndirect (d3d12.h)

Aplikasi melakukan gambar/pengiriman tidak langsung menggunakan metode ExecuteIndirect .

Sintaks

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

Parameter

[in] pCommandSignature

Jenis: ID3D12CommandSignature*

Menentukan ID3D12CommandSignature. Data yang direferensikan oleh pArgumentBuffer akan ditafsirkan tergantung pada konten tanda tangan perintah. Lihat Gambar Tidak Langsung untuk API yang digunakan untuk membuat tanda tangan perintah.

[in] MaxCommandCount

Jenis: UINT

Ada dua cara agar jumlah perintah dapat ditentukan:

  • Jika pCountBuffer bukan NULL, maka MaxCommandCount menentukan jumlah maksimum operasi yang akan dilakukan. Jumlah aktual operasi yang akan dilakukan ditentukan oleh minimum nilai ini, dan bilangan bulat tidak bertanda 32-bit yang terkandung dalam pCountBuffer (pada offset byte yang ditentukan oleh CountBufferOffset).
  • Jika pCountBuffer adalah NULL, MaxCommandCount menentukan jumlah operasi yang tepat yang akan dilakukan.

[in] pArgumentBuffer

Jenis: ID3D12Resource*

Menentukan satu atau beberapa objek ID3D12Resource , yang berisi argumen perintah.

[in] ArgumentBufferOffset

Jenis: UINT64

Menentukan offset ke dalam pArgumentBuffer untuk mengidentifikasi argumen perintah pertama.

[in, optional] pCountBuffer

Jenis: ID3D12Resource*

Menentukan pointer ke ID3D12Resource.

[in] CountBufferOffset

Jenis: UINT64

Menentukan UINT64 yang merupakan offset ke dalam pCountBuffer, mengidentifikasi jumlah argumen.

Mengembalikan nilai

Tidak ada

Keterangan

Semantik API ini didefinisikan dengan kode semu berikut:

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

Lapisan debug akan mengeluarkan kesalahan jika buffer hitungan atau buffer argumen tidak dalam status D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT. Runtime inti akan memvalidasi:

  • CountBufferOffset dan ArgumentBufferOffset diratakan 4-byte
  • pCountBuffer dan pArgumentBuffer adalah sumber daya buffer (jenis heap apa pun)
  • Offset yang disiratkan oleh MaxCommandCount, ArgumentBufferOffset, dan langkah program menggambar tidak melebihi batas pArgumentBuffer (demikian pula untuk buffer hitungan)
  • Daftar perintah adalah daftar perintah langsung atau daftar perintah komputasi (bukan daftar perintah dekode salinan atau JPEG)
  • Tanda tangan akar dari daftar perintah cocok dengan tanda tangan akar tanda tangan perintah
Fungsionalitas dua API dari versi Direct3D sebelumnya, DrawInstancedIndirect dan DrawIndexedInstancedIndirect, dicakup oleh ExecuteIndirect.

Bundel

ID3D12GraphicsCommandList::ExecuteIndirect diizinkan di dalam daftar perintah bundel hanya jika semua hal berikut ini benar:
  • CountBuffer adalah NULL (hanya jumlah yang ditentukan CPU).
  • Tanda tangan perintah berisi tepat satu operasi. Ini menyiratkan bahwa tanda tangan perintah tidak berisi perubahan argumen akar, juga tidak berisi perubahan pengikatan VB/IB.

Mendapatkan alamat virtual buffer

Metode ID3D12Resource::GetGPUVirtualAddress memungkinkan aplikasi untuk mengambil alamat virtual GPU buffer.

Aplikasi bebas menerapkan offset byte ke alamat virtual sebelum menempatkannya dalam buffer argumen tidak langsung. Perhatikan bahwa semua persyaratan penyelarasan D3D12 untuk VB/IB/CB masih berlaku untuk alamat virtual GPU yang dihasilkan.

Contoh

Sampel D3D12ExecuteIndirect menggunakan ID3D12GraphicsCommandList::ExecuteIndirect sebagai berikut:

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

Panggilan ke ExecuteIndirect berada di dekat akhir daftar ini, di bawah komentar "Gambar segitiga yang belum dimusnahkan."

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

Lihat Contoh Kode dalam Referensi D3D12.

Persyaratan

   
Target Platform Windows
Header d3d12.h
Pustaka D3d12.lib
DLL D3d12.dll

Lihat juga

ID3D12GraphicsCommandList

Gambar Tidak Langsung