d3d11: CommandBuffer: implement render pass
Bug: dawn:1705
Change-Id: I21c6a8550f098cb1e97d5f0c9a93da53600fa8a3
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/127700
Reviewed-by: Austin Eng <enga@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Peng Huang <penghuang@chromium.org>
Auto-Submit: Peng Huang <penghuang@chromium.org>
diff --git a/src/dawn/native/d3d11/CommandBufferD3D11.cpp b/src/dawn/native/d3d11/CommandBufferD3D11.cpp
index 885638a..9fdd0a7 100644
--- a/src/dawn/native/d3d11/CommandBufferD3D11.cpp
+++ b/src/dawn/native/d3d11/CommandBufferD3D11.cpp
@@ -41,6 +41,17 @@
namespace dawn::native::d3d11 {
namespace {
+DXGI_FORMAT DXGIIndexFormat(wgpu::IndexFormat format) {
+ switch (format) {
+ case wgpu::IndexFormat::Uint16:
+ return DXGI_FORMAT_R16_UINT;
+ case wgpu::IndexFormat::Uint32:
+ return DXGI_FORMAT_R32_UINT;
+ default:
+ UNREACHABLE();
+ }
+}
+
class BindGroupTracker : public BindGroupTrackerBase<false, uint64_t> {
public:
MaybeError Apply(CommandRecordingContext* commandContext) {
@@ -245,6 +256,7 @@
};
size_t nextComputePassNumber = 0;
+ size_t nextRenderPassNumber = 0;
Command type;
while (mCommands.NextCommandId(&type)) {
@@ -262,8 +274,14 @@
}
case Command::BeginRenderPass: {
- [[maybe_unused]] auto* cmd = mCommands.NextCommand<BeginRenderPassCmd>();
- return DAWN_UNIMPLEMENTED_ERROR("Render pass not implemented");
+ auto* cmd = mCommands.NextCommand<BeginRenderPassCmd>();
+ DAWN_TRY(
+ LazyClearSyncScope(GetResourceUsages().renderPasses[nextRenderPassNumber]));
+ LazyClearRenderPassAttachments(cmd);
+ DAWN_TRY(ExecuteRenderPass(cmd, commandContext));
+
+ nextRenderPassNumber++;
+ break;
}
case Command::CopyBufferToBuffer: {
@@ -553,6 +571,285 @@
UNREACHABLE();
}
+MaybeError CommandBuffer::ExecuteRenderPass(BeginRenderPassCmd* renderPass,
+ CommandRecordingContext* commandContext) {
+ ID3D11DeviceContext1* d3d11DeviceContext1 = commandContext->GetD3D11DeviceContext1();
+
+ // Hold ID3D11RenderTargetView ComPtr to make attachments alive.
+ ityp::array<ColorAttachmentIndex, ComPtr<ID3D11RenderTargetView>, kMaxColorAttachments>
+ d3d11RenderTargetViews = {};
+ ityp::array<ColorAttachmentIndex, ID3D11RenderTargetView*, kMaxColorAttachments>
+ d3d11RenderTargetViewPtrs = {};
+ ColorAttachmentIndex attachmentCount(uint8_t(0));
+ for (ColorAttachmentIndex i :
+ IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) {
+ TextureView* colorTextureView = ToBackend(renderPass->colorAttachments[i].view.Get());
+ DAWN_TRY_ASSIGN(d3d11RenderTargetViews[i], colorTextureView->CreateD3D11RenderTargetView());
+ d3d11RenderTargetViewPtrs[i] = d3d11RenderTargetViews[i].Get();
+ if (renderPass->colorAttachments[i].loadOp == wgpu::LoadOp::Clear) {
+ d3d11DeviceContext1->ClearRenderTargetView(
+ d3d11RenderTargetViews[i].Get(),
+ ConvertToFloatColor(renderPass->colorAttachments[i].clearColor).data());
+ }
+ attachmentCount = i;
+ attachmentCount++;
+ }
+
+ ComPtr<ID3D11DepthStencilView> d3d11DepthStencilView;
+ if (renderPass->attachmentState->HasDepthStencilAttachment()) {
+ auto* attachmentInfo = &renderPass->depthStencilAttachment;
+ const Format& attachmentFormat = attachmentInfo->view->GetTexture()->GetFormat();
+
+ TextureView* depthStencilTextureView =
+ ToBackend(renderPass->depthStencilAttachment.view.Get());
+ DAWN_TRY_ASSIGN(d3d11DepthStencilView,
+ depthStencilTextureView->CreateD3D11DepthStencilView(false, false));
+ UINT clearFlags = 0;
+ if (attachmentFormat.HasDepth() &&
+ renderPass->depthStencilAttachment.depthLoadOp == wgpu::LoadOp::Clear) {
+ clearFlags |= D3D11_CLEAR_DEPTH;
+ }
+
+ if (attachmentFormat.HasStencil() &&
+ renderPass->depthStencilAttachment.stencilLoadOp == wgpu::LoadOp::Clear) {
+ clearFlags |= D3D11_CLEAR_STENCIL;
+ }
+
+ d3d11DeviceContext1->ClearDepthStencilView(d3d11DepthStencilView.Get(), clearFlags,
+ attachmentInfo->clearDepth,
+ attachmentInfo->clearStencil);
+ }
+
+ d3d11DeviceContext1->OMSetRenderTargets(static_cast<uint8_t>(attachmentCount),
+ d3d11RenderTargetViewPtrs.data(),
+ d3d11DepthStencilView.Get());
+
+ // Set viewport
+ D3D11_VIEWPORT viewport;
+ viewport.TopLeftX = 0;
+ viewport.TopLeftY = 0;
+ viewport.Width = renderPass->width;
+ viewport.Height = renderPass->height;
+ viewport.MinDepth = 0.0f;
+ viewport.MaxDepth = 1.0f;
+ d3d11DeviceContext1->RSSetViewports(1, &viewport);
+
+ // Set scissor
+ D3D11_RECT scissor;
+ scissor.left = 0;
+ scissor.top = 0;
+ scissor.right = renderPass->width;
+ scissor.bottom = renderPass->height;
+ d3d11DeviceContext1->RSSetScissorRects(1, &scissor);
+
+ RenderPipeline* lastPipeline = nullptr;
+ BindGroupTracker bindGroupTracker = {};
+ std::array<float, 4> blendColor = {0.0f, 0.0f, 0.0f, 0.0f};
+ uint32_t stencilReference = 0;
+
+ auto DoRenderBundleCommand = [&](CommandIterator* iter, Command type) -> MaybeError {
+ switch (type) {
+ case Command::Draw: {
+ DrawCmd* draw = iter->NextCommand<DrawCmd>();
+
+ DAWN_TRY(bindGroupTracker.Apply(commandContext));
+ DAWN_TRY(RecordFirstIndexOffset(lastPipeline, commandContext, draw->firstVertex,
+ draw->firstInstance));
+ commandContext->GetD3D11DeviceContext()->DrawInstanced(
+ draw->vertexCount, draw->instanceCount, draw->firstVertex, draw->firstInstance);
+
+ break;
+ }
+
+ case Command::DrawIndexed: {
+ DrawIndexedCmd* draw = iter->NextCommand<DrawIndexedCmd>();
+
+ DAWN_TRY(bindGroupTracker.Apply(commandContext));
+ DAWN_TRY(RecordFirstIndexOffset(lastPipeline, commandContext, draw->baseVertex,
+ draw->firstInstance));
+ commandContext->GetD3D11DeviceContext()->DrawIndexedInstanced(
+ draw->indexCount, draw->instanceCount, draw->firstIndex, draw->baseVertex,
+ draw->firstInstance);
+
+ break;
+ }
+
+ case Command::DrawIndirect: {
+ // TODO(dawn:1716): figure how to setup built-in variables for indirect draw.
+ DrawIndirectCmd* draw = iter->NextCommand<DrawIndirectCmd>();
+
+ DAWN_TRY(bindGroupTracker.Apply(commandContext));
+ uint64_t indirectBufferOffset = draw->indirectOffset;
+ Buffer* indirectBuffer = ToBackend(draw->indirectBuffer.Get());
+ ASSERT(indirectBuffer != nullptr);
+
+ commandContext->GetD3D11DeviceContext()->DrawInstancedIndirect(
+ indirectBuffer->GetD3D11Buffer(), indirectBufferOffset);
+
+ break;
+ }
+
+ case Command::DrawIndexedIndirect: {
+ // TODO(dawn:1716): figure how to setup built-in variables for indirect draw.
+ DrawIndexedIndirectCmd* draw = iter->NextCommand<DrawIndexedIndirectCmd>();
+
+ DAWN_TRY(bindGroupTracker.Apply(commandContext));
+
+ Buffer* indirectBuffer = ToBackend(draw->indirectBuffer.Get());
+ ASSERT(indirectBuffer != nullptr);
+
+ commandContext->GetD3D11DeviceContext()->DrawIndexedInstancedIndirect(
+ indirectBuffer->GetD3D11Buffer(), draw->indirectOffset);
+
+ break;
+ }
+
+ case Command::SetRenderPipeline: {
+ SetRenderPipelineCmd* cmd = iter->NextCommand<SetRenderPipelineCmd>();
+
+ lastPipeline = ToBackend(cmd->pipeline).Get();
+ lastPipeline->ApplyNow(commandContext, blendColor, stencilReference);
+ bindGroupTracker.OnSetPipeline(lastPipeline);
+
+ break;
+ }
+
+ case Command::SetBindGroup: {
+ SetBindGroupCmd* cmd = iter->NextCommand<SetBindGroupCmd>();
+
+ uint32_t* dynamicOffsets = nullptr;
+ if (cmd->dynamicOffsetCount > 0) {
+ dynamicOffsets = iter->NextData<uint32_t>(cmd->dynamicOffsetCount);
+ }
+ bindGroupTracker.OnSetBindGroup(cmd->index, cmd->group.Get(),
+ cmd->dynamicOffsetCount, dynamicOffsets);
+
+ break;
+ }
+
+ case Command::SetIndexBuffer: {
+ SetIndexBufferCmd* cmd = iter->NextCommand<SetIndexBufferCmd>();
+
+ UINT indexBufferBaseOffset = cmd->offset;
+ DXGI_FORMAT indexBufferFormat = DXGIIndexFormat(cmd->format);
+
+ commandContext->GetD3D11DeviceContext()->IASetIndexBuffer(
+ ToBackend(cmd->buffer)->GetD3D11Buffer(), indexBufferFormat,
+ indexBufferBaseOffset);
+
+ break;
+ }
+
+ case Command::SetVertexBuffer: {
+ SetVertexBufferCmd* cmd = iter->NextCommand<SetVertexBufferCmd>();
+ ASSERT(lastPipeline);
+ const VertexBufferInfo& info = lastPipeline->GetVertexBuffer(cmd->slot);
+
+ // TODO(dawn:1705): should we set vertex back to nullptr after the draw call?
+ UINT slot = static_cast<uint8_t>(cmd->slot);
+ ID3D11Buffer* buffer = ToBackend(cmd->buffer)->GetD3D11Buffer();
+ UINT arrayStride = info.arrayStride;
+ UINT offset = cmd->offset;
+ commandContext->GetD3D11DeviceContext()->IASetVertexBuffers(slot, 1, &buffer,
+ &arrayStride, &offset);
+
+ break;
+ }
+
+ case Command::InsertDebugMarker:
+ case Command::PopDebugGroup:
+ case Command::PushDebugGroup: {
+ HandleDebugCommands(commandContext, type);
+ break;
+ }
+
+ default:
+ UNREACHABLE();
+ break;
+ }
+
+ return {};
+ };
+
+ Command type;
+ while (mCommands.NextCommandId(&type)) {
+ switch (type) {
+ case Command::EndRenderPass: {
+ mCommands.NextCommand<EndRenderPassCmd>();
+ // TODO(dawn:1705): resolve MSAA
+ return {};
+ }
+
+ case Command::SetStencilReference: {
+ SetStencilReferenceCmd* cmd = mCommands.NextCommand<SetStencilReferenceCmd>();
+ stencilReference = cmd->reference;
+ return {};
+ }
+
+ case Command::SetViewport: {
+ SetViewportCmd* cmd = mCommands.NextCommand<SetViewportCmd>();
+
+ D3D11_VIEWPORT viewport;
+ viewport.TopLeftX = cmd->x;
+ viewport.TopLeftY = cmd->y;
+ viewport.Width = cmd->width;
+ viewport.Height = cmd->height;
+ viewport.MinDepth = cmd->minDepth;
+ viewport.MaxDepth = cmd->maxDepth;
+ commandContext->GetD3D11DeviceContext()->RSSetViewports(1, &viewport);
+ break;
+ }
+
+ case Command::SetScissorRect: {
+ SetScissorRectCmd* cmd = mCommands.NextCommand<SetScissorRectCmd>();
+
+ D3D11_RECT scissorRect = {static_cast<LONG>(cmd->x), static_cast<LONG>(cmd->y),
+ static_cast<LONG>(cmd->x + cmd->width),
+ static_cast<LONG>(cmd->y + cmd->height)};
+ commandContext->GetD3D11DeviceContext()->RSSetScissorRects(1, &scissorRect);
+ break;
+ }
+
+ case Command::SetBlendConstant: {
+ SetBlendConstantCmd* cmd = mCommands.NextCommand<SetBlendConstantCmd>();
+ blendColor = ConvertToFloatColor(cmd->color);
+ break;
+ }
+
+ case Command::ExecuteBundles: {
+ ExecuteBundlesCmd* cmd = mCommands.NextCommand<ExecuteBundlesCmd>();
+ auto bundles = mCommands.NextData<Ref<RenderBundleBase>>(cmd->count);
+ for (uint32_t i = 0; i < cmd->count; ++i) {
+ CommandIterator* iter = bundles[i]->GetCommands();
+ iter->Reset();
+ while (iter->NextCommandId(&type)) {
+ DAWN_TRY(DoRenderBundleCommand(iter, type));
+ }
+ }
+ break;
+ }
+
+ case Command::BeginOcclusionQuery: {
+ return DAWN_UNIMPLEMENTED_ERROR("BeginOcclusionQuery unimplemented.");
+ }
+
+ case Command::EndOcclusionQuery: {
+ return DAWN_UNIMPLEMENTED_ERROR("EndOcclusionQuery unimplemented.");
+ }
+
+ case Command::WriteTimestamp:
+ return DAWN_UNIMPLEMENTED_ERROR("WriteTimestamp unimplemented");
+
+ default: {
+ DAWN_TRY(DoRenderBundleCommand(&mCommands, type));
+ }
+ }
+ }
+
+ // EndRenderPass should have been called
+ UNREACHABLE();
+}
+
void CommandBuffer::HandleDebugCommands(CommandRecordingContext* commandContext, Command command) {
switch (command) {
case Command::InsertDebugMarker: {
@@ -579,6 +876,28 @@
}
}
+MaybeError CommandBuffer::RecordFirstIndexOffset(RenderPipeline* renderPipeline,
+ CommandRecordingContext* commandContext,
+ uint32_t firstVertex,
+ uint32_t firstInstance) {
+ if (!renderPipeline->GetUsesVertexOrInstanceIndex()) {
+ // Vertex and instance index are not used in shader, so we don't need to update the uniform
+ // buffer. The original value in the uniform buffer will not be used, so we don't need to
+ // clear it.
+ return {};
+ }
+
+ // TODO(dawn:1705): only update the uniform buffer when the value changes.
+ uint32_t offsets[] = {
+ firstVertex,
+ firstInstance,
+ };
+ DAWN_TRY(
+ commandContext->GetUniformBuffer()->Write(commandContext, 0, offsets, sizeof(offsets)));
+
+ return {};
+}
+
MaybeError CommandBuffer::RecordNumWorkgroupsForDispatch(ComputePipeline* computePipeline,
CommandRecordingContext* commandContext,
DispatchCmd* dispatchCmd) {
diff --git a/src/dawn/native/d3d11/CommandBufferD3D11.h b/src/dawn/native/d3d11/CommandBufferD3D11.h
index 4b56130..0fc370e 100644
--- a/src/dawn/native/d3d11/CommandBufferD3D11.h
+++ b/src/dawn/native/d3d11/CommandBufferD3D11.h
@@ -27,6 +27,7 @@
class CommandRecordingContext;
class ComputePipeline;
+class RenderPipeline;
class CommandBuffer final : public CommandBufferBase {
public:
@@ -38,8 +39,14 @@
using CommandBufferBase::CommandBufferBase;
MaybeError ExecuteComputePass(CommandRecordingContext* commandContext);
+ MaybeError ExecuteRenderPass(BeginRenderPassCmd* renderPass,
+ CommandRecordingContext* commandContext);
void HandleDebugCommands(CommandRecordingContext* commandContext, Command command);
+ MaybeError RecordFirstIndexOffset(RenderPipeline* renderPipeline,
+ CommandRecordingContext* commandContext,
+ uint32_t firstVertex,
+ uint32_t firstInstance);
MaybeError RecordNumWorkgroupsForDispatch(ComputePipeline* computePipeline,
CommandRecordingContext* commandContext,
DispatchCmd* dispatchCmd);