Метод 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
Количество команд можно указать двумя способами:
- Если pCountBuffer не имеет значение NULL, то MaxCommandCount указывает максимальное количество выполняемых операций. Фактическое число выполняемых операций определяется минимальным значением этого значения и 32-разрядным целым числом без знака, содержащимся в pCountBuffer (смещение байтов, заданное параметром CountBufferOffset).
- Если pCountBuffer имеет значение NULL, параметр MaxCommandCount указывает точное количество выполняемых операций.
[in] pArgumentBuffer
Тип: ID3D12Resource*
Указывает один или несколько объектов ID3D12Resource , содержащих аргументы команды.
[in] ArgumentBufferOffset
Тип: UINT64
Указывает смещение в pArgumentBuffer для определения первого аргумента команды.
[in, optional] pCountBuffer
Тип: ID3D12Resource*
Указывает указатель на ID3D12Resource.
[in] CountBufferOffset
Тип: UINT64
Указывает UINT64, который является смещением в pCountBuffer, идентифицируя число аргументов.
Возвращаемое значение
None
Remarks
Семантика этого API определяется с помощью следующего псевдокода:
PCountBuffer, отличный от 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();
}
Уровень отладки выдает ошибку, если буфер счетчика или буфер аргументов не находятся в D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT состоянии. Базовая среда выполнения проверит:
- CountBufferOffset и ArgumentBufferOffset выровнены по 4 байтам
- pCountBuffer и pArgumentBuffer — буферные ресурсы (любой тип кучи).
- Смещение, подразумеваемое MaxCommandCount, ArgumentBufferOffset и шагом программы рисования, не превышает границы pArgumentBuffer (аналогично для буфера count).
- Список команд является прямым списком команд или списком команд вычислений (а не списком команд копирования или декодирования JPEG).
- Корневая сигнатура списка команд соответствует корневой сигнатуре команды.
DrawInstancedIndirect
и DrawIndexedInstancedIndirect
, охватываются ExecuteIndirect.
Пакеты
ID3D12GraphicsCommandList::ExecuteIndirect разрешен в списках команд пакета, только если выполняются все перечисленные ниже условия:- CountBuffer имеет значение NULL (только количество, указанное ЦП).
- Сигнатура команды содержит ровно одну операцию. Это означает, что сигнатура команды не содержит изменения корневых аргументов и не содержит изменений привязки VB/IB.
Получение виртуальных адресов буфера
Метод ID3D12Resource::GetGPUVirtualAddress позволяет приложению получить виртуальный адрес GPU буфера.Приложения могут применять смещения байтов к виртуальным адресам, прежде чем помещать их в буфер косвенных аргументов. Обратите внимание, что все требования к выравниванию D3D12 для VB,IB/CB по-прежнему применяются к полученному виртуальному адресу 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 |
Header | d3d12.h |
Библиотека | D3d12.lib |
DLL | D3d12.dll |