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
DrawInstancedIndirect
DrawIndexedInstancedIndirect
, 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 |