CommandBufferD3D12: Iterate per pass

This commit is contained in:
Corentin Wallez 2018-07-09 18:55:21 +02:00 committed by Corentin Wallez
parent aa13be96e8
commit 2beeae3ad3
4 changed files with 368 additions and 324 deletions

View File

@ -44,116 +44,116 @@ namespace backend { namespace d3d12 {
UNREACHABLE(); UNREACHABLE();
} }
} }
} // anonymous namespace
struct BindGroupStateTracker { struct BindGroupStateTracker {
uint32_t cbvSrvUavDescriptorIndex = 0; uint32_t cbvSrvUavDescriptorIndex = 0;
uint32_t samplerDescriptorIndex = 0; uint32_t samplerDescriptorIndex = 0;
DescriptorHeapHandle cbvSrvUavCPUDescriptorHeap = {}; DescriptorHeapHandle cbvSrvUavCPUDescriptorHeap = {};
DescriptorHeapHandle samplerCPUDescriptorHeap = {}; DescriptorHeapHandle samplerCPUDescriptorHeap = {};
DescriptorHeapHandle cbvSrvUavGPUDescriptorHeap = {}; DescriptorHeapHandle cbvSrvUavGPUDescriptorHeap = {};
DescriptorHeapHandle samplerGPUDescriptorHeap = {}; DescriptorHeapHandle samplerGPUDescriptorHeap = {};
std::array<BindGroup*, kMaxBindGroups> bindGroups = {}; std::array<BindGroup*, kMaxBindGroups> bindGroups = {};
bool inCompute = false; bool inCompute = false;
Device* device; Device* device;
BindGroupStateTracker(Device* device) : device(device) { BindGroupStateTracker(Device* device) : device(device) {
}
void SetInComputePass(bool inCompute_) {
inCompute = inCompute_;
}
void TrackSetBindGroup(BindGroup* group, uint32_t index) {
if (bindGroups[index] != group) {
bindGroups[index] = group;
// Descriptors don't need to be recorded if they have already been recorded in
// the heap. Indices are only updated when descriptors are recorded
const uint64_t serial = device->GetSerial();
if (group->GetHeapSerial() != serial) {
group->RecordDescriptors(cbvSrvUavCPUDescriptorHeap, &cbvSrvUavDescriptorIndex,
samplerCPUDescriptorHeap, &samplerDescriptorIndex,
serial);
}
}
}
void TrackInheritedGroups(PipelineLayout* oldLayout, PipelineLayout* newLayout) {
if (oldLayout == nullptr) {
return;
} }
void SetInComputePass(bool inCompute_) { uint32_t inheritUntil = oldLayout->GroupsInheritUpTo(newLayout);
inCompute = inCompute_; for (uint32_t i = 0; i < inheritUntil; ++i) {
TrackSetBindGroup(bindGroups[i], i);
} }
}
void TrackSetBindGroup(BindGroup* group, uint32_t index) { void SetBindGroup(ComPtr<ID3D12GraphicsCommandList> commandList,
if (bindGroups[index] != group) { PipelineLayout* pipelineLayout,
bindGroups[index] = group; BindGroup* group,
uint32_t index,
bool force = false) {
if (bindGroups[index] != group || force) {
bindGroups[index] = group;
// Descriptors don't need to be recorded if they have already been recorded in uint32_t cbvUavSrvCount =
// the heap. Indices are only updated when descriptors are recorded ToBackend(group->GetLayout())->GetCbvUavSrvDescriptorCount();
const uint64_t serial = device->GetSerial(); uint32_t samplerCount = ToBackend(group->GetLayout())->GetSamplerDescriptorCount();
if (group->GetHeapSerial() != serial) {
group->RecordDescriptors( if (cbvUavSrvCount > 0) {
cbvSrvUavCPUDescriptorHeap, &cbvSrvUavDescriptorIndex, uint32_t parameterIndex = pipelineLayout->GetCbvUavSrvRootParameterIndex(index);
samplerCPUDescriptorHeap, &samplerDescriptorIndex, serial);
if (inCompute) {
commandList->SetComputeRootDescriptorTable(
parameterIndex, cbvSrvUavGPUDescriptorHeap.GetGPUHandle(
group->GetCbvUavSrvHeapOffset()));
} else {
commandList->SetGraphicsRootDescriptorTable(
parameterIndex, cbvSrvUavGPUDescriptorHeap.GetGPUHandle(
group->GetCbvUavSrvHeapOffset()));
}
}
if (samplerCount > 0) {
uint32_t parameterIndex = pipelineLayout->GetSamplerRootParameterIndex(index);
if (inCompute) {
commandList->SetComputeRootDescriptorTable(
parameterIndex,
samplerGPUDescriptorHeap.GetGPUHandle(group->GetSamplerHeapOffset()));
} else {
commandList->SetGraphicsRootDescriptorTable(
parameterIndex,
samplerGPUDescriptorHeap.GetGPUHandle(group->GetSamplerHeapOffset()));
} }
} }
} }
}
void TrackInheritedGroups(PipelineLayout* oldLayout, PipelineLayout* newLayout) { void SetInheritedBindGroups(ComPtr<ID3D12GraphicsCommandList> commandList,
if (oldLayout == nullptr) { PipelineLayout* oldLayout,
return; PipelineLayout* newLayout) {
} if (oldLayout == nullptr) {
return;
uint32_t inheritUntil = oldLayout->GroupsInheritUpTo(newLayout);
for (uint32_t i = 0; i < inheritUntil; ++i) {
TrackSetBindGroup(bindGroups[i], i);
}
} }
void SetBindGroup(ComPtr<ID3D12GraphicsCommandList> commandList, uint32_t inheritUntil = oldLayout->GroupsInheritUpTo(newLayout);
PipelineLayout* pipelineLayout, for (uint32_t i = 0; i < inheritUntil; ++i) {
BindGroup* group, SetBindGroup(commandList, newLayout, bindGroups[i], i, true);
uint32_t index,
bool force = false) {
if (bindGroups[index] != group || force) {
bindGroups[index] = group;
uint32_t cbvUavSrvCount =
ToBackend(group->GetLayout())->GetCbvUavSrvDescriptorCount();
uint32_t samplerCount =
ToBackend(group->GetLayout())->GetSamplerDescriptorCount();
if (cbvUavSrvCount > 0) {
uint32_t parameterIndex =
pipelineLayout->GetCbvUavSrvRootParameterIndex(index);
if (inCompute) {
commandList->SetComputeRootDescriptorTable(
parameterIndex, cbvSrvUavGPUDescriptorHeap.GetGPUHandle(
group->GetCbvUavSrvHeapOffset()));
} else {
commandList->SetGraphicsRootDescriptorTable(
parameterIndex, cbvSrvUavGPUDescriptorHeap.GetGPUHandle(
group->GetCbvUavSrvHeapOffset()));
}
}
if (samplerCount > 0) {
uint32_t parameterIndex =
pipelineLayout->GetSamplerRootParameterIndex(index);
if (inCompute) {
commandList->SetComputeRootDescriptorTable(
parameterIndex, samplerGPUDescriptorHeap.GetGPUHandle(
group->GetSamplerHeapOffset()));
} else {
commandList->SetGraphicsRootDescriptorTable(
parameterIndex, samplerGPUDescriptorHeap.GetGPUHandle(
group->GetSamplerHeapOffset()));
}
}
}
} }
}
void SetInheritedBindGroups(ComPtr<ID3D12GraphicsCommandList> commandList, void Reset() {
PipelineLayout* oldLayout, for (uint32_t i = 0; i < kMaxBindGroups; ++i) {
PipelineLayout* newLayout) { bindGroups[i] = nullptr;
if (oldLayout == nullptr) {
return;
}
uint32_t inheritUntil = oldLayout->GroupsInheritUpTo(newLayout);
for (uint32_t i = 0; i < inheritUntil; ++i) {
SetBindGroup(commandList, newLayout, bindGroups[i], i, true);
}
} }
}
};
void Reset() { namespace {
for (uint32_t i = 0; i < kMaxBindGroups; ++i) {
bindGroups[i] = nullptr;
}
}
};
void AllocateAndSetDescriptorHeaps(Device* device, void AllocateAndSetDescriptorHeaps(Device* device,
BindGroupStateTracker* bindingTracker, BindGroupStateTracker* bindingTracker,
@ -226,130 +226,54 @@ namespace backend { namespace d3d12 {
D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
} }
} }
} // namespace
CommandBuffer::CommandBuffer(Device* device, CommandBufferBuilder* builder) } // anonymous namespace
: CommandBufferBase(builder), mDevice(device), mCommands(builder->AcquireCommands()) {
CommandBuffer::CommandBuffer(CommandBufferBuilder* builder)
: CommandBufferBase(builder), mCommands(builder->AcquireCommands()) {
} }
CommandBuffer::~CommandBuffer() { CommandBuffer::~CommandBuffer() {
FreeCommands(&mCommands); FreeCommands(&mCommands);
} }
void CommandBuffer::FillCommands(ComPtr<ID3D12GraphicsCommandList> commandList) { void CommandBuffer::RecordCommands(ComPtr<ID3D12GraphicsCommandList> commandList) {
BindGroupStateTracker bindingTracker(mDevice); Device* device = ToBackend(GetDevice());
AllocateAndSetDescriptorHeaps(mDevice, &bindingTracker, &mCommands); BindGroupStateTracker bindingTracker(device);
bindingTracker.Reset();
ID3D12DescriptorHeap* descriptorHeaps[2] = {bindingTracker.cbvSrvUavGPUDescriptorHeap.Get(), // Precompute the allocation of bindgroups in descriptor heaps
bindingTracker.samplerGPUDescriptorHeap.Get()}; // TODO(cwallez@chromium.org): Iterating over all the commands here is inefficient. We
if (descriptorHeaps[0] && descriptorHeaps[1]) { // should have a system where commands and descriptors are recorded in parallel then the
commandList->SetDescriptorHeaps(2, descriptorHeaps); // heaps set using a small CommandList inserted just before the main CommandList.
} else if (descriptorHeaps[0]) { {
commandList->SetDescriptorHeaps(1, descriptorHeaps); AllocateAndSetDescriptorHeaps(device, &bindingTracker, &mCommands);
} else if (descriptorHeaps[1]) { bindingTracker.Reset();
commandList->SetDescriptorHeaps(2, &descriptorHeaps[1]);
ID3D12DescriptorHeap* descriptorHeaps[2] = {
bindingTracker.cbvSrvUavGPUDescriptorHeap.Get(),
bindingTracker.samplerGPUDescriptorHeap.Get()};
if (descriptorHeaps[0] && descriptorHeaps[1]) {
commandList->SetDescriptorHeaps(2, descriptorHeaps);
} else if (descriptorHeaps[0]) {
commandList->SetDescriptorHeaps(1, descriptorHeaps);
} else if (descriptorHeaps[1]) {
commandList->SetDescriptorHeaps(2, &descriptorHeaps[1]);
}
} }
Command type; Command type;
RenderPipeline* lastRenderPipeline = nullptr;
PipelineLayout* lastLayout = nullptr;
while (mCommands.NextCommandId(&type)) { while (mCommands.NextCommandId(&type)) {
switch (type) { switch (type) {
case Command::BeginComputePass: { case Command::BeginComputePass: {
mCommands.NextCommand<BeginComputePassCmd>(); mCommands.NextCommand<BeginComputePassCmd>();
bindingTracker.SetInComputePass(true); RecordComputePass(commandList, &bindingTracker);
} break; } break;
case Command::BeginRenderPass: { case Command::BeginRenderPass: {
BeginRenderPassCmd* beginRenderPassCmd = BeginRenderPassCmd* beginRenderPassCmd =
mCommands.NextCommand<BeginRenderPassCmd>(); mCommands.NextCommand<BeginRenderPassCmd>();
RenderPassDescriptor* info = ToBackend(beginRenderPassCmd->info.Get()); RecordRenderPass(commandList, &bindingTracker,
ToBackend(beginRenderPassCmd->info.Get()));
RenderPassDescriptor::OMSetRenderTargetArgs args =
info->GetSubpassOMSetRenderTargetArgs();
if (args.dsv.ptr) {
commandList->OMSetRenderTargets(args.numRTVs, args.RTVs.data(), FALSE,
&args.dsv);
} else {
commandList->OMSetRenderTargets(args.numRTVs, args.RTVs.data(), FALSE,
nullptr);
}
// Clear framebuffer attachments as needed and transition to render target
for (uint32_t i : IterateBitSet(info->GetColorAttachmentMask())) {
auto& attachmentInfo = info->GetColorAttachment(i);
Texture* texture = ToBackend(attachmentInfo.view->GetTexture());
// It's already validated that this texture is either frozen to the correct
// usage, or not frozen.
if (!texture->IsFrozen()) {
texture->TransitionUsageImpl(texture->GetUsage(),
nxt::TextureUsageBit::OutputAttachment);
texture->UpdateUsageInternal(nxt::TextureUsageBit::OutputAttachment);
}
// Load op - color
if (attachmentInfo.loadOp == nxt::LoadOp::Clear) {
D3D12_CPU_DESCRIPTOR_HANDLE handle = info->GetRTVDescriptor(i);
commandList->ClearRenderTargetView(
handle, attachmentInfo.clearColor.data(), 0, nullptr);
}
}
if (info->HasDepthStencilAttachment()) {
auto& attachmentInfo = info->GetDepthStencilAttachment();
Texture* texture = ToBackend(attachmentInfo.view->GetTexture());
// It's already validated that this texture is either frozen to the correct
// usage, or not frozen.
if (!texture->IsFrozen()) {
texture->TransitionUsageImpl(texture->GetUsage(),
nxt::TextureUsageBit::OutputAttachment);
texture->UpdateUsageInternal(nxt::TextureUsageBit::OutputAttachment);
}
// Load op - depth/stencil
bool doDepthClear = TextureFormatHasDepth(texture->GetFormat()) &&
(attachmentInfo.depthLoadOp == nxt::LoadOp::Clear);
bool doStencilClear = TextureFormatHasStencil(texture->GetFormat()) &&
(attachmentInfo.stencilLoadOp == nxt::LoadOp::Clear);
D3D12_CLEAR_FLAGS clearFlags = {};
if (doDepthClear) {
clearFlags |= D3D12_CLEAR_FLAG_DEPTH;
}
if (doStencilClear) {
clearFlags |= D3D12_CLEAR_FLAG_STENCIL;
}
if (clearFlags) {
auto handle = info->GetDSVDescriptor();
// TODO(kainino@chromium.org): investigate: should the NXT clear
// stencil type be uint8_t?
uint8_t clearStencil =
static_cast<uint8_t>(attachmentInfo.clearStencil);
commandList->ClearDepthStencilView(handle, clearFlags,
attachmentInfo.clearDepth,
clearStencil, 0, nullptr);
}
}
// Set up the default render pass dynamic state
uint32_t width = info->GetWidth();
uint32_t height = info->GetHeight();
D3D12_VIEWPORT viewport = {
0.f, 0.f, static_cast<float>(width), static_cast<float>(height), 0.f, 1.f};
D3D12_RECT scissorRect = {0, 0, static_cast<long>(width),
static_cast<long>(height)};
commandList->RSSetViewports(1, &viewport);
commandList->RSSetScissorRects(1, &scissorRect);
static constexpr std::array<float, 4> defaultBlendFactor = {0, 0, 0, 0};
commandList->OMSetBlendFactor(&defaultBlendFactor[0]);
} break; } break;
case Command::CopyBufferToBuffer: { case Command::CopyBufferToBuffer: {
@ -446,129 +370,6 @@ namespace backend { namespace d3d12 {
} }
} break; } break;
case Command::Dispatch: {
DispatchCmd* dispatch = mCommands.NextCommand<DispatchCmd>();
commandList->Dispatch(dispatch->x, dispatch->y, dispatch->z);
} break;
case Command::DrawArrays: {
DrawArraysCmd* draw = mCommands.NextCommand<DrawArraysCmd>();
commandList->DrawInstanced(draw->vertexCount, draw->instanceCount,
draw->firstVertex, draw->firstInstance);
} break;
case Command::DrawElements: {
DrawElementsCmd* draw = mCommands.NextCommand<DrawElementsCmd>();
commandList->DrawIndexedInstanced(draw->indexCount, draw->instanceCount,
draw->firstIndex, 0, draw->firstInstance);
} break;
case Command::EndComputePass: {
mCommands.NextCommand<EndComputePassCmd>();
bindingTracker.SetInComputePass(false);
} break;
case Command::EndRenderPass: {
mCommands.NextCommand<EndRenderPassCmd>();
} break;
case Command::SetComputePipeline: {
SetComputePipelineCmd* cmd = mCommands.NextCommand<SetComputePipelineCmd>();
ComputePipeline* pipeline = ToBackend(cmd->pipeline).Get();
PipelineLayout* layout = ToBackend(pipeline->GetLayout());
commandList->SetComputeRootSignature(layout->GetRootSignature().Get());
commandList->SetPipelineState(pipeline->GetPipelineState().Get());
// TODO(enga@google.com): Implement compute pipelines
bindingTracker.SetInheritedBindGroups(commandList, lastLayout, layout);
lastLayout = layout;
} break;
case Command::SetRenderPipeline: {
SetRenderPipelineCmd* cmd = mCommands.NextCommand<SetRenderPipelineCmd>();
RenderPipeline* pipeline = ToBackend(cmd->pipeline).Get();
PipelineLayout* layout = ToBackend(pipeline->GetLayout());
commandList->SetGraphicsRootSignature(layout->GetRootSignature().Get());
commandList->SetPipelineState(pipeline->GetPipelineState().Get());
commandList->IASetPrimitiveTopology(pipeline->GetD3D12PrimitiveTopology());
bindingTracker.SetInheritedBindGroups(commandList, lastLayout, layout);
lastRenderPipeline = pipeline;
lastLayout = layout;
} break;
case Command::SetPushConstants: {
mCommands.NextCommand<SetPushConstantsCmd>();
} break;
case Command::SetStencilReference: {
SetStencilReferenceCmd* cmd = mCommands.NextCommand<SetStencilReferenceCmd>();
commandList->OMSetStencilRef(cmd->reference);
} break;
case Command::SetScissorRect: {
SetScissorRectCmd* cmd = mCommands.NextCommand<SetScissorRectCmd>();
D3D12_RECT rect;
rect.left = cmd->x;
rect.top = cmd->y;
rect.right = cmd->x + cmd->width;
rect.bottom = cmd->y + cmd->height;
commandList->RSSetScissorRects(1, &rect);
} break;
case Command::SetBlendColor: {
SetBlendColorCmd* cmd = mCommands.NextCommand<SetBlendColorCmd>();
ASSERT(lastRenderPipeline);
commandList->OMSetBlendFactor(static_cast<const FLOAT*>(&cmd->r));
} break;
case Command::SetBindGroup: {
SetBindGroupCmd* cmd = mCommands.NextCommand<SetBindGroupCmd>();
BindGroup* group = ToBackend(cmd->group.Get());
bindingTracker.SetBindGroup(commandList, lastLayout, group, cmd->index);
} break;
case Command::SetIndexBuffer: {
SetIndexBufferCmd* cmd = mCommands.NextCommand<SetIndexBufferCmd>();
Buffer* buffer = ToBackend(cmd->buffer.Get());
D3D12_INDEX_BUFFER_VIEW bufferView;
bufferView.BufferLocation = buffer->GetVA() + cmd->offset;
bufferView.SizeInBytes = buffer->GetSize() - cmd->offset;
// TODO(cwallez@chromium.org): Make index buffers lazily applied, right now
// this will break if the pipeline is changed for one with a different index
// format after SetIndexBuffer
bufferView.Format = DXGIIndexFormat(lastRenderPipeline->GetIndexFormat());
commandList->IASetIndexBuffer(&bufferView);
} break;
case Command::SetVertexBuffers: {
SetVertexBuffersCmd* cmd = mCommands.NextCommand<SetVertexBuffersCmd>();
auto buffers = mCommands.NextData<Ref<BufferBase>>(cmd->count);
auto offsets = mCommands.NextData<uint32_t>(cmd->count);
auto inputState = ToBackend(lastRenderPipeline->GetInputState());
std::array<D3D12_VERTEX_BUFFER_VIEW, kMaxVertexInputs> d3d12BufferViews;
for (uint32_t i = 0; i < cmd->count; ++i) {
auto input = inputState->GetInput(cmd->startSlot + i);
Buffer* buffer = ToBackend(buffers[i].Get());
d3d12BufferViews[i].BufferLocation = buffer->GetVA() + offsets[i];
d3d12BufferViews[i].StrideInBytes = input.stride;
d3d12BufferViews[i].SizeInBytes = buffer->GetSize() - offsets[i];
}
commandList->IASetVertexBuffers(cmd->startSlot, cmd->count,
d3d12BufferViews.data());
} break;
case Command::TransitionBufferUsage: { case Command::TransitionBufferUsage: {
TransitionBufferUsageCmd* cmd = TransitionBufferUsageCmd* cmd =
mCommands.NextCommand<TransitionBufferUsageCmd>(); mCommands.NextCommand<TransitionBufferUsageCmd>();
@ -598,7 +399,242 @@ namespace backend { namespace d3d12 {
texture->UpdateUsageInternal(cmd->usage); texture->UpdateUsageInternal(cmd->usage);
} break; } break;
default: { UNREACHABLE(); } break;
} }
} }
} }
void CommandBuffer::RecordComputePass(ComPtr<ID3D12GraphicsCommandList> commandList,
BindGroupStateTracker* bindingTracker) {
PipelineLayout* lastLayout = nullptr;
Command type;
while (mCommands.NextCommandId(&type)) {
switch (type) {
case Command::Dispatch: {
DispatchCmd* dispatch = mCommands.NextCommand<DispatchCmd>();
commandList->Dispatch(dispatch->x, dispatch->y, dispatch->z);
} break;
case Command::EndComputePass: {
mCommands.NextCommand<EndComputePassCmd>();
return;
} break;
case Command::SetComputePipeline: {
SetComputePipelineCmd* cmd = mCommands.NextCommand<SetComputePipelineCmd>();
ComputePipeline* pipeline = ToBackend(cmd->pipeline).Get();
PipelineLayout* layout = ToBackend(pipeline->GetLayout());
commandList->SetComputeRootSignature(layout->GetRootSignature().Get());
commandList->SetPipelineState(pipeline->GetPipelineState().Get());
bindingTracker->SetInheritedBindGroups(commandList, lastLayout, layout);
lastLayout = layout;
} break;
case Command::SetBindGroup: {
SetBindGroupCmd* cmd = mCommands.NextCommand<SetBindGroupCmd>();
BindGroup* group = ToBackend(cmd->group.Get());
bindingTracker->SetBindGroup(commandList, lastLayout, group, cmd->index);
} break;
default: { UNREACHABLE(); } break;
}
}
}
void CommandBuffer::RecordRenderPass(ComPtr<ID3D12GraphicsCommandList> commandList,
BindGroupStateTracker* bindingTracker,
RenderPassDescriptor* renderPass) {
// Clear framebuffer attachments as needed and transition to render target
{
for (uint32_t i : IterateBitSet(renderPass->GetColorAttachmentMask())) {
auto& attachmentInfo = renderPass->GetColorAttachment(i);
Texture* texture = ToBackend(attachmentInfo.view->GetTexture());
// It's already validated that this texture is either frozen to the correct
// usage, or not frozen.
if (!texture->IsFrozen()) {
texture->TransitionUsageImpl(texture->GetUsage(),
nxt::TextureUsageBit::OutputAttachment);
texture->UpdateUsageInternal(nxt::TextureUsageBit::OutputAttachment);
}
// Load op - color
if (attachmentInfo.loadOp == nxt::LoadOp::Clear) {
D3D12_CPU_DESCRIPTOR_HANDLE handle = renderPass->GetRTVDescriptor(i);
commandList->ClearRenderTargetView(handle, attachmentInfo.clearColor.data(), 0,
nullptr);
}
}
if (renderPass->HasDepthStencilAttachment()) {
auto& attachmentInfo = renderPass->GetDepthStencilAttachment();
Texture* texture = ToBackend(attachmentInfo.view->GetTexture());
// It's already validated that this texture is either frozen to the correct
// usage, or not frozen.
if (!texture->IsFrozen()) {
texture->TransitionUsageImpl(texture->GetUsage(),
nxt::TextureUsageBit::OutputAttachment);
texture->UpdateUsageInternal(nxt::TextureUsageBit::OutputAttachment);
}
// Load op - depth/stencil
bool doDepthClear = TextureFormatHasDepth(texture->GetFormat()) &&
(attachmentInfo.depthLoadOp == nxt::LoadOp::Clear);
bool doStencilClear = TextureFormatHasStencil(texture->GetFormat()) &&
(attachmentInfo.stencilLoadOp == nxt::LoadOp::Clear);
D3D12_CLEAR_FLAGS clearFlags = {};
if (doDepthClear) {
clearFlags |= D3D12_CLEAR_FLAG_DEPTH;
}
if (doStencilClear) {
clearFlags |= D3D12_CLEAR_FLAG_STENCIL;
}
if (clearFlags) {
auto handle = renderPass->GetDSVDescriptor();
// TODO(kainino@chromium.org): investigate: should the NXT clear
// stencil type be uint8_t?
uint8_t clearStencil = static_cast<uint8_t>(attachmentInfo.clearStencil);
commandList->ClearDepthStencilView(
handle, clearFlags, attachmentInfo.clearDepth, clearStencil, 0, nullptr);
}
}
}
// Set up render targets
{
RenderPassDescriptor::OMSetRenderTargetArgs args =
renderPass->GetSubpassOMSetRenderTargetArgs();
if (args.dsv.ptr) {
commandList->OMSetRenderTargets(args.numRTVs, args.RTVs.data(), FALSE, &args.dsv);
} else {
commandList->OMSetRenderTargets(args.numRTVs, args.RTVs.data(), FALSE, nullptr);
}
}
// Set up default dynamic state
{
uint32_t width = renderPass->GetWidth();
uint32_t height = renderPass->GetHeight();
D3D12_VIEWPORT viewport = {
0.f, 0.f, static_cast<float>(width), static_cast<float>(height), 0.f, 1.f};
D3D12_RECT scissorRect = {0, 0, static_cast<long>(width), static_cast<long>(height)};
commandList->RSSetViewports(1, &viewport);
commandList->RSSetScissorRects(1, &scissorRect);
static constexpr std::array<float, 4> defaultBlendFactor = {0, 0, 0, 0};
commandList->OMSetBlendFactor(&defaultBlendFactor[0]);
}
RenderPipeline* lastPipeline = nullptr;
PipelineLayout* lastLayout = nullptr;
Command type;
while (mCommands.NextCommandId(&type)) {
switch (type) {
case Command::EndRenderPass: {
mCommands.NextCommand<EndRenderPassCmd>();
return;
} break;
case Command::DrawArrays: {
DrawArraysCmd* draw = mCommands.NextCommand<DrawArraysCmd>();
commandList->DrawInstanced(draw->vertexCount, draw->instanceCount,
draw->firstVertex, draw->firstInstance);
} break;
case Command::DrawElements: {
DrawElementsCmd* draw = mCommands.NextCommand<DrawElementsCmd>();
commandList->DrawIndexedInstanced(draw->indexCount, draw->instanceCount,
draw->firstIndex, 0, draw->firstInstance);
} break;
case Command::SetRenderPipeline: {
SetRenderPipelineCmd* cmd = mCommands.NextCommand<SetRenderPipelineCmd>();
RenderPipeline* pipeline = ToBackend(cmd->pipeline).Get();
PipelineLayout* layout = ToBackend(pipeline->GetLayout());
commandList->SetGraphicsRootSignature(layout->GetRootSignature().Get());
commandList->SetPipelineState(pipeline->GetPipelineState().Get());
commandList->IASetPrimitiveTopology(pipeline->GetD3D12PrimitiveTopology());
bindingTracker->SetInheritedBindGroups(commandList, lastLayout, layout);
lastPipeline = pipeline;
lastLayout = layout;
} break;
case Command::SetStencilReference: {
SetStencilReferenceCmd* cmd = mCommands.NextCommand<SetStencilReferenceCmd>();
commandList->OMSetStencilRef(cmd->reference);
} break;
case Command::SetScissorRect: {
SetScissorRectCmd* cmd = mCommands.NextCommand<SetScissorRectCmd>();
D3D12_RECT rect;
rect.left = cmd->x;
rect.top = cmd->y;
rect.right = cmd->x + cmd->width;
rect.bottom = cmd->y + cmd->height;
commandList->RSSetScissorRects(1, &rect);
} break;
case Command::SetBlendColor: {
SetBlendColorCmd* cmd = mCommands.NextCommand<SetBlendColorCmd>();
commandList->OMSetBlendFactor(static_cast<const FLOAT*>(&cmd->r));
} break;
case Command::SetBindGroup: {
SetBindGroupCmd* cmd = mCommands.NextCommand<SetBindGroupCmd>();
BindGroup* group = ToBackend(cmd->group.Get());
bindingTracker->SetBindGroup(commandList, lastLayout, group, cmd->index);
} break;
case Command::SetIndexBuffer: {
SetIndexBufferCmd* cmd = mCommands.NextCommand<SetIndexBufferCmd>();
Buffer* buffer = ToBackend(cmd->buffer.Get());
D3D12_INDEX_BUFFER_VIEW bufferView;
bufferView.BufferLocation = buffer->GetVA() + cmd->offset;
bufferView.SizeInBytes = buffer->GetSize() - cmd->offset;
// TODO(cwallez@chromium.org): Make index buffers lazily applied, right now
// this will break if the pipeline is changed for one with a different index
// format after SetIndexBuffer
bufferView.Format = DXGIIndexFormat(lastPipeline->GetIndexFormat());
commandList->IASetIndexBuffer(&bufferView);
} break;
case Command::SetVertexBuffers: {
SetVertexBuffersCmd* cmd = mCommands.NextCommand<SetVertexBuffersCmd>();
auto buffers = mCommands.NextData<Ref<BufferBase>>(cmd->count);
auto offsets = mCommands.NextData<uint32_t>(cmd->count);
auto inputState = ToBackend(lastPipeline->GetInputState());
std::array<D3D12_VERTEX_BUFFER_VIEW, kMaxVertexInputs> d3d12BufferViews;
for (uint32_t i = 0; i < cmd->count; ++i) {
auto input = inputState->GetInput(cmd->startSlot + i);
Buffer* buffer = ToBackend(buffers[i].Get());
d3d12BufferViews[i].BufferLocation = buffer->GetVA() + offsets[i];
d3d12BufferViews[i].StrideInBytes = input.stride;
d3d12BufferViews[i].SizeInBytes = buffer->GetSize() - offsets[i];
}
commandList->IASetVertexBuffers(cmd->startSlot, cmd->count,
d3d12BufferViews.data());
} break;
default: { UNREACHABLE(); } break;
}
}
}
}} // namespace backend::d3d12 }} // namespace backend::d3d12

View File

@ -23,16 +23,24 @@
namespace backend { namespace d3d12 { namespace backend { namespace d3d12 {
class Device; class Device;
class RenderPassDescriptor;
struct BindGroupStateTracker;
class CommandBuffer : public CommandBufferBase { class CommandBuffer : public CommandBufferBase {
public: public:
CommandBuffer(Device* device, CommandBufferBuilder* builder); CommandBuffer(CommandBufferBuilder* builder);
~CommandBuffer(); ~CommandBuffer();
void FillCommands(ComPtr<ID3D12GraphicsCommandList> commandList); void RecordCommands(ComPtr<ID3D12GraphicsCommandList> commandList);
private: private:
Device* mDevice; void RecordComputePass(ComPtr<ID3D12GraphicsCommandList> commandList,
BindGroupStateTracker* bindingTracker);
void RecordRenderPass(ComPtr<ID3D12GraphicsCommandList> commandList,
BindGroupStateTracker* bindingTracker,
RenderPassDescriptor* renderPass);
CommandIterator mCommands; CommandIterator mCommands;
}; };

View File

@ -280,7 +280,7 @@ namespace backend { namespace d3d12 {
return new BufferView(builder); return new BufferView(builder);
} }
CommandBufferBase* Device::CreateCommandBuffer(CommandBufferBuilder* builder) { CommandBufferBase* Device::CreateCommandBuffer(CommandBufferBuilder* builder) {
return new CommandBuffer(this, builder); return new CommandBuffer(builder);
} }
ComputePipelineBase* Device::CreateComputePipeline(ComputePipelineBuilder* builder) { ComputePipelineBase* Device::CreateComputePipeline(ComputePipelineBuilder* builder) {
return new ComputePipeline(builder); return new ComputePipeline(builder);

View File

@ -29,7 +29,7 @@ namespace backend { namespace d3d12 {
device->OpenCommandList(&mCommandList); device->OpenCommandList(&mCommandList);
for (uint32_t i = 0; i < numCommands; ++i) { for (uint32_t i = 0; i < numCommands; ++i) {
commands[i]->FillCommands(mCommandList); commands[i]->RecordCommands(mCommandList);
} }
ASSERT_SUCCESS(mCommandList->Close()); ASSERT_SUCCESS(mCommandList->Close());