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.
DrawInstancedIndirect
und DrawIndexedInstancedIndirect
umfasst 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 |