Implement RenderBundle in the backend
Bug: dawn:154
Change-Id: I45496fb2103150dabe32fbc7cb5856dc40c9339f
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/9222
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Commit-Queue: Austin Eng <enga@chromium.org>
diff --git a/BUILD.gn b/BUILD.gn
index 492ea22..fe9b67c 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -769,6 +769,7 @@
"src/tests/end2end/ObjectCachingTests.cpp",
"src/tests/end2end/OpArrayLengthTests.cpp",
"src/tests/end2end/PrimitiveTopologyTests.cpp",
+ "src/tests/end2end/RenderBundleTests.cpp",
"src/tests/end2end/RenderPassLoadOpTests.cpp",
"src/tests/end2end/RenderPassTests.cpp",
"src/tests/end2end/SamplerTests.cpp",
diff --git a/src/dawn_native/d3d12/CommandBufferD3D12.cpp b/src/dawn_native/d3d12/CommandBufferD3D12.cpp
index 095b410..150dd63 100644
--- a/src/dawn_native/d3d12/CommandBufferD3D12.cpp
+++ b/src/dawn_native/d3d12/CommandBufferD3D12.cpp
@@ -17,6 +17,7 @@
#include "common/Assert.h"
#include "dawn_native/CommandEncoder.h"
#include "dawn_native/Commands.h"
+#include "dawn_native/RenderBundle.h"
#include "dawn_native/d3d12/BindGroupD3D12.h"
#include "dawn_native/d3d12/BindGroupLayoutD3D12.h"
#include "dawn_native/d3d12/BufferD3D12.h"
@@ -398,7 +399,7 @@
Command type;
PipelineLayout* lastLayout = nullptr;
- while (commands->NextCommandId(&type)) {
+ auto HandleCommand = [&](CommandIterator* commands, Command type) {
switch (type) {
case Command::SetComputePipeline: {
SetComputePipelineCmd* cmd =
@@ -431,6 +432,26 @@
default:
SkipCommand(commands, type);
}
+ };
+
+ while (commands->NextCommandId(&type)) {
+ switch (type) {
+ case Command::ExecuteBundles: {
+ ExecuteBundlesCmd* cmd = commands->NextCommand<ExecuteBundlesCmd>();
+ auto bundles = commands->NextData<Ref<RenderBundleBase>>(cmd->count);
+
+ for (uint32_t i = 0; i < cmd->count; ++i) {
+ CommandIterator* commands = bundles[i]->GetCommands();
+ commands->Reset();
+ while (commands->NextCommandId(&type)) {
+ HandleCommand(commands, type);
+ }
+ }
+ } break;
+ default:
+ HandleCommand(commands, type);
+ break;
+ }
}
commands->Reset();
@@ -987,6 +1008,155 @@
PipelineLayout* lastLayout = nullptr;
VertexBuffersInfo vertexBuffersInfo = {};
+ auto EncodeRenderBundleCommand = [&](CommandIterator* iter, Command type) {
+ switch (type) {
+ case Command::Draw: {
+ DrawCmd* draw = iter->NextCommand<DrawCmd>();
+
+ FlushSetVertexBuffers(commandList, &vertexBuffersInfo, lastPipeline);
+ commandList->DrawInstanced(draw->vertexCount, draw->instanceCount,
+ draw->firstVertex, draw->firstInstance);
+ } break;
+
+ case Command::DrawIndexed: {
+ DrawIndexedCmd* draw = iter->NextCommand<DrawIndexedCmd>();
+
+ FlushSetVertexBuffers(commandList, &vertexBuffersInfo, lastPipeline);
+ commandList->DrawIndexedInstanced(draw->indexCount, draw->instanceCount,
+ draw->firstIndex, draw->baseVertex,
+ draw->firstInstance);
+ } break;
+
+ case Command::DrawIndirect: {
+ DrawIndirectCmd* draw = iter->NextCommand<DrawIndirectCmd>();
+
+ FlushSetVertexBuffers(commandList, &vertexBuffersInfo, lastPipeline);
+ Buffer* buffer = ToBackend(draw->indirectBuffer.Get());
+ ComPtr<ID3D12CommandSignature> signature =
+ ToBackend(GetDevice())->GetDrawIndirectSignature();
+ commandList->ExecuteIndirect(signature.Get(), 1,
+ buffer->GetD3D12Resource().Get(),
+ draw->indirectOffset, nullptr, 0);
+ } break;
+
+ case Command::DrawIndexedIndirect: {
+ DrawIndexedIndirectCmd* draw = iter->NextCommand<DrawIndexedIndirectCmd>();
+
+ FlushSetVertexBuffers(commandList, &vertexBuffersInfo, lastPipeline);
+ Buffer* buffer = ToBackend(draw->indirectBuffer.Get());
+ ComPtr<ID3D12CommandSignature> signature =
+ ToBackend(GetDevice())->GetDrawIndexedIndirectSignature();
+ commandList->ExecuteIndirect(signature.Get(), 1,
+ buffer->GetD3D12Resource().Get(),
+ draw->indirectOffset, nullptr, 0);
+ } break;
+
+ case Command::InsertDebugMarker: {
+ InsertDebugMarkerCmd* cmd = iter->NextCommand<InsertDebugMarkerCmd>();
+ const char* label = iter->NextData<char>(cmd->length + 1);
+
+ if (ToBackend(GetDevice())->GetFunctions()->IsPIXEventRuntimeLoaded()) {
+ // PIX color is 1 byte per channel in ARGB format
+ constexpr uint64_t kPIXBlackColor = 0xff000000;
+ ToBackend(GetDevice())
+ ->GetFunctions()
+ ->pixSetMarkerOnCommandList(commandList.Get(), kPIXBlackColor, label);
+ }
+ } break;
+
+ case Command::PopDebugGroup: {
+ iter->NextCommand<PopDebugGroupCmd>();
+
+ if (ToBackend(GetDevice())->GetFunctions()->IsPIXEventRuntimeLoaded()) {
+ ToBackend(GetDevice())
+ ->GetFunctions()
+ ->pixEndEventOnCommandList(commandList.Get());
+ }
+ } break;
+
+ case Command::PushDebugGroup: {
+ PushDebugGroupCmd* cmd = iter->NextCommand<PushDebugGroupCmd>();
+ const char* label = iter->NextData<char>(cmd->length + 1);
+
+ if (ToBackend(GetDevice())->GetFunctions()->IsPIXEventRuntimeLoaded()) {
+ // PIX color is 1 byte per channel in ARGB format
+ constexpr uint64_t kPIXBlackColor = 0xff000000;
+ ToBackend(GetDevice())
+ ->GetFunctions()
+ ->pixBeginEventOnCommandList(commandList.Get(), kPIXBlackColor, label);
+ }
+ } break;
+
+ case Command::SetRenderPipeline: {
+ SetRenderPipelineCmd* cmd = iter->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::SetBindGroup: {
+ SetBindGroupCmd* cmd = iter->NextCommand<SetBindGroupCmd>();
+ BindGroup* group = ToBackend(cmd->group.Get());
+ uint64_t* dynamicOffsets = nullptr;
+
+ if (cmd->dynamicOffsetCount > 0) {
+ dynamicOffsets = iter->NextData<uint64_t>(cmd->dynamicOffsetCount);
+ }
+
+ bindingTracker->SetBindGroup(commandList, lastLayout, group, cmd->index,
+ cmd->dynamicOffsetCount, dynamicOffsets);
+ } break;
+
+ case Command::SetIndexBuffer: {
+ SetIndexBufferCmd* cmd = iter->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->GetVertexInputDescriptor()->indexFormat);
+
+ commandList->IASetIndexBuffer(&bufferView);
+ } break;
+
+ case Command::SetVertexBuffers: {
+ SetVertexBuffersCmd* cmd = iter->NextCommand<SetVertexBuffersCmd>();
+ auto buffers = iter->NextData<Ref<BufferBase>>(cmd->count);
+ auto offsets = iter->NextData<uint64_t>(cmd->count);
+
+ vertexBuffersInfo.startSlot =
+ std::min(vertexBuffersInfo.startSlot, cmd->startSlot);
+ vertexBuffersInfo.endSlot =
+ std::max(vertexBuffersInfo.endSlot, cmd->startSlot + cmd->count);
+
+ for (uint32_t i = 0; i < cmd->count; ++i) {
+ Buffer* buffer = ToBackend(buffers[i].Get());
+ auto* d3d12BufferView =
+ &vertexBuffersInfo.d3d12BufferViews[cmd->startSlot + i];
+ d3d12BufferView->BufferLocation = buffer->GetVA() + offsets[i];
+ d3d12BufferView->SizeInBytes = buffer->GetSize() - offsets[i];
+ // The bufferView stride is set based on the input state before a draw.
+ }
+ } break;
+
+ default:
+ UNREACHABLE();
+ break;
+ }
+ };
+
Command type;
while (mCommands.NextCommandId(&type)) {
switch (type) {
@@ -1001,98 +1171,6 @@
return;
} break;
- case Command::Draw: {
- DrawCmd* draw = mCommands.NextCommand<DrawCmd>();
-
- FlushSetVertexBuffers(commandList, &vertexBuffersInfo, lastPipeline);
- commandList->DrawInstanced(draw->vertexCount, draw->instanceCount,
- draw->firstVertex, draw->firstInstance);
- } break;
-
- case Command::DrawIndexed: {
- DrawIndexedCmd* draw = mCommands.NextCommand<DrawIndexedCmd>();
-
- FlushSetVertexBuffers(commandList, &vertexBuffersInfo, lastPipeline);
- commandList->DrawIndexedInstanced(draw->indexCount, draw->instanceCount,
- draw->firstIndex, draw->baseVertex,
- draw->firstInstance);
- } break;
-
- case Command::DrawIndirect: {
- DrawIndirectCmd* draw = mCommands.NextCommand<DrawIndirectCmd>();
-
- FlushSetVertexBuffers(commandList, &vertexBuffersInfo, lastPipeline);
- Buffer* buffer = ToBackend(draw->indirectBuffer.Get());
- ComPtr<ID3D12CommandSignature> signature =
- ToBackend(GetDevice())->GetDrawIndirectSignature();
- commandList->ExecuteIndirect(signature.Get(), 1,
- buffer->GetD3D12Resource().Get(),
- draw->indirectOffset, nullptr, 0);
- } break;
-
- case Command::DrawIndexedIndirect: {
- DrawIndexedIndirectCmd* draw = mCommands.NextCommand<DrawIndexedIndirectCmd>();
-
- FlushSetVertexBuffers(commandList, &vertexBuffersInfo, lastPipeline);
- Buffer* buffer = ToBackend(draw->indirectBuffer.Get());
- ComPtr<ID3D12CommandSignature> signature =
- ToBackend(GetDevice())->GetDrawIndexedIndirectSignature();
- commandList->ExecuteIndirect(signature.Get(), 1,
- buffer->GetD3D12Resource().Get(),
- draw->indirectOffset, nullptr, 0);
- } break;
-
- case Command::InsertDebugMarker: {
- InsertDebugMarkerCmd* cmd = mCommands.NextCommand<InsertDebugMarkerCmd>();
- const char* label = mCommands.NextData<char>(cmd->length + 1);
-
- if (ToBackend(GetDevice())->GetFunctions()->IsPIXEventRuntimeLoaded()) {
- // PIX color is 1 byte per channel in ARGB format
- constexpr uint64_t kPIXBlackColor = 0xff000000;
- ToBackend(GetDevice())
- ->GetFunctions()
- ->pixSetMarkerOnCommandList(commandList.Get(), kPIXBlackColor, label);
- }
- } break;
-
- case Command::PopDebugGroup: {
- mCommands.NextCommand<PopDebugGroupCmd>();
-
- if (ToBackend(GetDevice())->GetFunctions()->IsPIXEventRuntimeLoaded()) {
- ToBackend(GetDevice())
- ->GetFunctions()
- ->pixEndEventOnCommandList(commandList.Get());
- }
- } break;
-
- case Command::PushDebugGroup: {
- PushDebugGroupCmd* cmd = mCommands.NextCommand<PushDebugGroupCmd>();
- const char* label = mCommands.NextData<char>(cmd->length + 1);
-
- if (ToBackend(GetDevice())->GetFunctions()->IsPIXEventRuntimeLoaded()) {
- // PIX color is 1 byte per channel in ARGB format
- constexpr uint64_t kPIXBlackColor = 0xff000000;
- ToBackend(GetDevice())
- ->GetFunctions()
- ->pixBeginEventOnCommandList(commandList.Get(), kPIXBlackColor, label);
- }
- } 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>();
@@ -1128,56 +1206,20 @@
commandList->OMSetBlendFactor(static_cast<const FLOAT*>(&cmd->color.r));
} break;
- case Command::SetBindGroup: {
- SetBindGroupCmd* cmd = mCommands.NextCommand<SetBindGroupCmd>();
- BindGroup* group = ToBackend(cmd->group.Get());
- uint64_t* dynamicOffsets = nullptr;
-
- if (cmd->dynamicOffsetCount > 0) {
- dynamicOffsets = mCommands.NextData<uint64_t>(cmd->dynamicOffsetCount);
- }
-
- bindingTracker->SetBindGroup(commandList, lastLayout, group, cmd->index,
- cmd->dynamicOffsetCount, dynamicOffsets);
- } 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->GetVertexInputDescriptor()->indexFormat);
-
- commandList->IASetIndexBuffer(&bufferView);
- } break;
-
- case Command::SetVertexBuffers: {
- SetVertexBuffersCmd* cmd = mCommands.NextCommand<SetVertexBuffersCmd>();
- auto buffers = mCommands.NextData<Ref<BufferBase>>(cmd->count);
- auto offsets = mCommands.NextData<uint64_t>(cmd->count);
-
- vertexBuffersInfo.startSlot =
- std::min(vertexBuffersInfo.startSlot, cmd->startSlot);
- vertexBuffersInfo.endSlot =
- std::max(vertexBuffersInfo.endSlot, cmd->startSlot + cmd->count);
+ 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) {
- Buffer* buffer = ToBackend(buffers[i].Get());
- auto* d3d12BufferView =
- &vertexBuffersInfo.d3d12BufferViews[cmd->startSlot + i];
- d3d12BufferView->BufferLocation = buffer->GetVA() + offsets[i];
- d3d12BufferView->SizeInBytes = buffer->GetSize() - offsets[i];
- // The bufferView stride is set based on the input state before a draw.
+ CommandIterator* iter = bundles[i]->GetCommands();
+ iter->Reset();
+ while (iter->NextCommandId(&type)) {
+ EncodeRenderBundleCommand(iter, type);
+ }
}
} break;
- default: { UNREACHABLE(); } break;
+ default: { EncodeRenderBundleCommand(&mCommands, type); } break;
}
}
}
diff --git a/src/dawn_native/metal/CommandBufferMTL.mm b/src/dawn_native/metal/CommandBufferMTL.mm
index a096073..3c79768 100644
--- a/src/dawn_native/metal/CommandBufferMTL.mm
+++ b/src/dawn_native/metal/CommandBufferMTL.mm
@@ -17,6 +17,7 @@
#include "dawn_native/BindGroup.h"
#include "dawn_native/CommandEncoder.h"
#include "dawn_native/Commands.h"
+#include "dawn_native/RenderBundle.h"
#include "dawn_native/metal/BufferMTL.h"
#include "dawn_native/metal/ComputePipelineMTL.h"
#include "dawn_native/metal/DeviceMTL.h"
@@ -871,17 +872,10 @@
id<MTLRenderCommandEncoder> encoder =
[commandBuffer renderCommandEncoderWithDescriptor:mtlRenderPass];
- Command type;
- while (mCommands.NextCommandId(&type)) {
+ auto EncodeRenderBundleCommand = [&](CommandIterator* iter, Command type) {
switch (type) {
- case Command::EndRenderPass: {
- mCommands.NextCommand<EndRenderPassCmd>();
- [encoder endEncoding];
- return;
- } break;
-
case Command::Draw: {
- DrawCmd* draw = mCommands.NextCommand<DrawCmd>();
+ DrawCmd* draw = iter->NextCommand<DrawCmd>();
vertexInputBuffers.Apply(encoder, lastPipeline);
storageBufferLengths.Apply(lastPipeline, encoder);
@@ -897,7 +891,7 @@
} break;
case Command::DrawIndexed: {
- DrawIndexedCmd* draw = mCommands.NextCommand<DrawIndexedCmd>();
+ DrawIndexedCmd* draw = iter->NextCommand<DrawIndexedCmd>();
size_t formatSize =
IndexFormatSize(lastPipeline->GetVertexInputDescriptor()->indexFormat);
@@ -919,7 +913,7 @@
} break;
case Command::DrawIndirect: {
- DrawIndirectCmd* draw = mCommands.NextCommand<DrawIndirectCmd>();
+ DrawIndirectCmd* draw = iter->NextCommand<DrawIndirectCmd>();
vertexInputBuffers.Apply(encoder, lastPipeline);
storageBufferLengths.Apply(lastPipeline, encoder);
@@ -932,7 +926,7 @@
} break;
case Command::DrawIndexedIndirect: {
- DrawIndirectCmd* draw = mCommands.NextCommand<DrawIndirectCmd>();
+ DrawIndirectCmd* draw = iter->NextCommand<DrawIndirectCmd>();
vertexInputBuffers.Apply(encoder, lastPipeline);
storageBufferLengths.Apply(lastPipeline, encoder);
@@ -948,8 +942,8 @@
} break;
case Command::InsertDebugMarker: {
- InsertDebugMarkerCmd* cmd = mCommands.NextCommand<InsertDebugMarkerCmd>();
- char* label = mCommands.NextData<char>(cmd->length + 1);
+ InsertDebugMarkerCmd* cmd = iter->NextCommand<InsertDebugMarkerCmd>();
+ char* label = iter->NextData<char>(cmd->length + 1);
NSString* mtlLabel = [[NSString alloc] initWithUTF8String:label];
[encoder insertDebugSignpost:mtlLabel];
@@ -957,14 +951,14 @@
} break;
case Command::PopDebugGroup: {
- mCommands.NextCommand<PopDebugGroupCmd>();
+ iter->NextCommand<PopDebugGroupCmd>();
[encoder popDebugGroup];
} break;
case Command::PushDebugGroup: {
- PushDebugGroupCmd* cmd = mCommands.NextCommand<PushDebugGroupCmd>();
- char* label = mCommands.NextData<char>(cmd->length + 1);
+ PushDebugGroupCmd* cmd = iter->NextCommand<PushDebugGroupCmd>();
+ char* label = iter->NextData<char>(cmd->length + 1);
NSString* mtlLabel = [[NSString alloc] initWithUTF8String:label];
[encoder pushDebugGroup:mtlLabel];
@@ -972,7 +966,7 @@
} break;
case Command::SetRenderPipeline: {
- SetRenderPipelineCmd* cmd = mCommands.NextCommand<SetRenderPipelineCmd>();
+ SetRenderPipelineCmd* cmd = iter->NextCommand<SetRenderPipelineCmd>();
RenderPipeline* newPipeline = ToBackend(cmd->pipeline).Get();
vertexInputBuffers.OnSetPipeline(lastPipeline, newPipeline);
@@ -984,6 +978,49 @@
lastPipeline = newPipeline;
} break;
+ case Command::SetBindGroup: {
+ SetBindGroupCmd* cmd = iter->NextCommand<SetBindGroupCmd>();
+ uint64_t* dynamicOffsets = nullptr;
+ if (cmd->dynamicOffsetCount > 0) {
+ dynamicOffsets = iter->NextData<uint64_t>(cmd->dynamicOffsetCount);
+ }
+
+ ApplyBindGroup(cmd->index, ToBackend(cmd->group.Get()), cmd->dynamicOffsetCount,
+ dynamicOffsets, ToBackend(lastPipeline->GetLayout()),
+ &storageBufferLengths, encoder, nil);
+ } break;
+
+ case Command::SetIndexBuffer: {
+ SetIndexBufferCmd* cmd = iter->NextCommand<SetIndexBufferCmd>();
+ auto b = ToBackend(cmd->buffer.Get());
+ indexBuffer = b->GetMTLBuffer();
+ indexBufferBaseOffset = cmd->offset;
+ } break;
+
+ case Command::SetVertexBuffers: {
+ SetVertexBuffersCmd* cmd = iter->NextCommand<SetVertexBuffersCmd>();
+ const Ref<BufferBase>* buffers = iter->NextData<Ref<BufferBase>>(cmd->count);
+ const uint64_t* offsets = iter->NextData<uint64_t>(cmd->count);
+
+ vertexInputBuffers.OnSetVertexBuffers(cmd->startSlot, cmd->count, buffers,
+ offsets);
+ } break;
+
+ default:
+ UNREACHABLE();
+ break;
+ }
+ };
+
+ Command type;
+ while (mCommands.NextCommandId(&type)) {
+ switch (type) {
+ case Command::EndRenderPass: {
+ mCommands.NextCommand<EndRenderPassCmd>();
+ [encoder endEncoding];
+ return;
+ } break;
+
case Command::SetStencilReference: {
SetStencilReferenceCmd* cmd = mCommands.NextCommand<SetStencilReferenceCmd>();
[encoder setStencilReferenceValue:cmd->reference];
@@ -1030,36 +1067,20 @@
alpha:cmd->color.a];
} break;
- case Command::SetBindGroup: {
- SetBindGroupCmd* cmd = mCommands.NextCommand<SetBindGroupCmd>();
- uint64_t* dynamicOffsets = nullptr;
- if (cmd->dynamicOffsetCount > 0) {
- dynamicOffsets = mCommands.NextData<uint64_t>(cmd->dynamicOffsetCount);
+ 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)) {
+ EncodeRenderBundleCommand(iter, type);
+ }
}
-
- ApplyBindGroup(cmd->index, ToBackend(cmd->group.Get()), cmd->dynamicOffsetCount,
- dynamicOffsets, ToBackend(lastPipeline->GetLayout()),
- &storageBufferLengths, encoder, nil);
} break;
- case Command::SetIndexBuffer: {
- SetIndexBufferCmd* cmd = mCommands.NextCommand<SetIndexBufferCmd>();
- auto b = ToBackend(cmd->buffer.Get());
- indexBuffer = b->GetMTLBuffer();
- indexBufferBaseOffset = cmd->offset;
- } break;
-
- case Command::SetVertexBuffers: {
- SetVertexBuffersCmd* cmd = mCommands.NextCommand<SetVertexBuffersCmd>();
- const Ref<BufferBase>* buffers =
- mCommands.NextData<Ref<BufferBase>>(cmd->count);
- const uint64_t* offsets = mCommands.NextData<uint64_t>(cmd->count);
-
- vertexInputBuffers.OnSetVertexBuffers(cmd->startSlot, cmd->count, buffers,
- offsets);
- } break;
-
- default: { UNREACHABLE(); } break;
+ default: { EncodeRenderBundleCommand(&mCommands, type); } break;
}
}
diff --git a/src/dawn_native/opengl/CommandBufferGL.cpp b/src/dawn_native/opengl/CommandBufferGL.cpp
index 32ee0bf..9fafb6f 100644
--- a/src/dawn_native/opengl/CommandBufferGL.cpp
+++ b/src/dawn_native/opengl/CommandBufferGL.cpp
@@ -17,6 +17,7 @@
#include "dawn_native/BindGroup.h"
#include "dawn_native/CommandEncoder.h"
#include "dawn_native/Commands.h"
+#include "dawn_native/RenderBundle.h"
#include "dawn_native/opengl/BufferGL.h"
#include "dawn_native/opengl/ComputePipelineGL.h"
#include "dawn_native/opengl/DeviceGL.h"
@@ -735,21 +736,10 @@
InputBufferTracker inputBuffers;
- Command type;
- while (mCommands.NextCommandId(&type)) {
+ auto DoRenderBundleCommand = [&](CommandIterator* iter, Command type) {
switch (type) {
- case Command::EndRenderPass: {
- mCommands.NextCommand<EndRenderPassCmd>();
-
- if (renderPass->attachmentState->GetSampleCount() > 1) {
- ResolveMultisampledRenderTargets(gl, renderPass);
- }
- gl.DeleteFramebuffers(1, &fbo);
- return;
- } break;
-
case Command::Draw: {
- DrawCmd* draw = mCommands.NextCommand<DrawCmd>();
+ DrawCmd* draw = iter->NextCommand<DrawCmd>();
inputBuffers.Apply(gl);
if (draw->firstInstance > 0) {
@@ -765,7 +755,7 @@
} break;
case Command::DrawIndexed: {
- DrawIndexedCmd* draw = mCommands.NextCommand<DrawIndexedCmd>();
+ DrawIndexedCmd* draw = iter->NextCommand<DrawIndexedCmd>();
inputBuffers.Apply(gl);
dawn::IndexFormat indexFormat =
@@ -790,7 +780,7 @@
} break;
case Command::DrawIndirect: {
- DrawIndirectCmd* draw = mCommands.NextCommand<DrawIndirectCmd>();
+ DrawIndirectCmd* draw = iter->NextCommand<DrawIndirectCmd>();
inputBuffers.Apply(gl);
uint64_t indirectBufferOffset = draw->indirectOffset;
@@ -803,7 +793,7 @@
} break;
case Command::DrawIndexedIndirect: {
- DrawIndexedIndirectCmd* draw = mCommands.NextCommand<DrawIndexedIndirectCmd>();
+ DrawIndexedIndirectCmd* draw = iter->NextCommand<DrawIndexedIndirectCmd>();
inputBuffers.Apply(gl);
dawn::IndexFormat indexFormat =
@@ -824,17 +814,60 @@
case Command::PushDebugGroup: {
// Due to lack of linux driver support for GL_EXT_debug_marker
// extension these functions are skipped.
- SkipCommand(&mCommands, type);
+ SkipCommand(iter, type);
} break;
case Command::SetRenderPipeline: {
- SetRenderPipelineCmd* cmd = mCommands.NextCommand<SetRenderPipelineCmd>();
+ SetRenderPipelineCmd* cmd = iter->NextCommand<SetRenderPipelineCmd>();
lastPipeline = ToBackend(cmd->pipeline).Get();
lastPipeline->ApplyNow(persistentPipelineState);
inputBuffers.OnSetPipeline(lastPipeline);
} break;
+ case Command::SetBindGroup: {
+ SetBindGroupCmd* cmd = iter->NextCommand<SetBindGroupCmd>();
+ uint64_t* dynamicOffsets = nullptr;
+ if (cmd->dynamicOffsetCount > 0) {
+ dynamicOffsets = iter->NextData<uint64_t>(cmd->dynamicOffsetCount);
+ }
+ ApplyBindGroup(gl, cmd->index, cmd->group.Get(),
+ ToBackend(lastPipeline->GetLayout()), lastPipeline,
+ cmd->dynamicOffsetCount, dynamicOffsets);
+ } break;
+
+ case Command::SetIndexBuffer: {
+ SetIndexBufferCmd* cmd = iter->NextCommand<SetIndexBufferCmd>();
+ indexBufferBaseOffset = cmd->offset;
+ inputBuffers.OnSetIndexBuffer(cmd->buffer.Get());
+ } break;
+
+ case Command::SetVertexBuffers: {
+ SetVertexBuffersCmd* cmd = iter->NextCommand<SetVertexBuffersCmd>();
+ auto buffers = iter->NextData<Ref<BufferBase>>(cmd->count);
+ auto offsets = iter->NextData<uint64_t>(cmd->count);
+ inputBuffers.OnSetVertexBuffers(cmd->startSlot, cmd->count, buffers, offsets);
+ } break;
+
+ default:
+ UNREACHABLE();
+ break;
+ }
+ };
+
+ Command type;
+ while (mCommands.NextCommandId(&type)) {
+ switch (type) {
+ case Command::EndRenderPass: {
+ mCommands.NextCommand<EndRenderPassCmd>();
+
+ if (renderPass->attachmentState->GetSampleCount() > 1) {
+ ResolveMultisampledRenderTargets(gl, renderPass);
+ }
+ gl.DeleteFramebuffers(1, &fbo);
+ return;
+ } break;
+
case Command::SetStencilReference: {
SetStencilReferenceCmd* cmd = mCommands.NextCommand<SetStencilReferenceCmd>();
persistentPipelineState.SetStencilReference(gl, cmd->reference);
@@ -856,31 +889,20 @@
gl.BlendColor(cmd->color.r, cmd->color.g, cmd->color.b, cmd->color.a);
} break;
- case Command::SetBindGroup: {
- SetBindGroupCmd* cmd = mCommands.NextCommand<SetBindGroupCmd>();
- uint64_t* dynamicOffsets = nullptr;
- if (cmd->dynamicOffsetCount > 0) {
- dynamicOffsets = mCommands.NextData<uint64_t>(cmd->dynamicOffsetCount);
+ 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)) {
+ DoRenderBundleCommand(iter, type);
+ }
}
- ApplyBindGroup(gl, cmd->index, cmd->group.Get(),
- ToBackend(lastPipeline->GetLayout()), lastPipeline,
- cmd->dynamicOffsetCount, dynamicOffsets);
} break;
- case Command::SetIndexBuffer: {
- SetIndexBufferCmd* cmd = mCommands.NextCommand<SetIndexBufferCmd>();
- indexBufferBaseOffset = cmd->offset;
- inputBuffers.OnSetIndexBuffer(cmd->buffer.Get());
- } break;
-
- case Command::SetVertexBuffers: {
- SetVertexBuffersCmd* cmd = mCommands.NextCommand<SetVertexBuffersCmd>();
- auto buffers = mCommands.NextData<Ref<BufferBase>>(cmd->count);
- auto offsets = mCommands.NextData<uint64_t>(cmd->count);
- inputBuffers.OnSetVertexBuffers(cmd->startSlot, cmd->count, buffers, offsets);
- } break;
-
- default: { UNREACHABLE(); } break;
+ default: { DoRenderBundleCommand(&mCommands, type); } break;
}
}
diff --git a/src/dawn_native/vulkan/CommandBufferVk.cpp b/src/dawn_native/vulkan/CommandBufferVk.cpp
index 28e9058..7b1c7fe 100644
--- a/src/dawn_native/vulkan/CommandBufferVk.cpp
+++ b/src/dawn_native/vulkan/CommandBufferVk.cpp
@@ -16,6 +16,7 @@
#include "dawn_native/CommandEncoder.h"
#include "dawn_native/Commands.h"
+#include "dawn_native/RenderBundle.h"
#include "dawn_native/vulkan/BindGroupVk.h"
#include "dawn_native/vulkan/BufferVk.h"
#include "dawn_native/vulkan/CommandRecordingContext.h"
@@ -671,17 +672,10 @@
DescriptorSetTracker descriptorSets;
RenderPipeline* lastPipeline = nullptr;
- Command type;
- while (mCommands.NextCommandId(&type)) {
+ auto EncodeRenderBundleCommand = [&](CommandIterator* iter, Command type) {
switch (type) {
- case Command::EndRenderPass: {
- mCommands.NextCommand<EndRenderPassCmd>();
- device->fn.CmdEndRenderPass(commands);
- return;
- } break;
-
case Command::Draw: {
- DrawCmd* draw = mCommands.NextCommand<DrawCmd>();
+ DrawCmd* draw = iter->NextCommand<DrawCmd>();
descriptorSets.Flush(device, commands, VK_PIPELINE_BIND_POINT_GRAPHICS);
device->fn.CmdDraw(commands, draw->vertexCount, draw->instanceCount,
@@ -689,7 +683,7 @@
} break;
case Command::DrawIndexed: {
- DrawIndexedCmd* draw = mCommands.NextCommand<DrawIndexedCmd>();
+ DrawIndexedCmd* draw = iter->NextCommand<DrawIndexedCmd>();
descriptorSets.Flush(device, commands, VK_PIPELINE_BIND_POINT_GRAPHICS);
device->fn.CmdDrawIndexed(commands, draw->indexCount, draw->instanceCount,
@@ -698,7 +692,7 @@
} break;
case Command::DrawIndirect: {
- DrawIndirectCmd* draw = mCommands.NextCommand<DrawIndirectCmd>();
+ DrawIndirectCmd* draw = iter->NextCommand<DrawIndirectCmd>();
VkBuffer indirectBuffer = ToBackend(draw->indirectBuffer)->GetHandle();
descriptorSets.Flush(device, commands, VK_PIPELINE_BIND_POINT_GRAPHICS);
@@ -708,7 +702,7 @@
} break;
case Command::DrawIndexedIndirect: {
- DrawIndirectCmd* draw = mCommands.NextCommand<DrawIndirectCmd>();
+ DrawIndirectCmd* draw = iter->NextCommand<DrawIndirectCmd>();
VkBuffer indirectBuffer = ToBackend(draw->indirectBuffer)->GetHandle();
descriptorSets.Flush(device, commands, VK_PIPELINE_BIND_POINT_GRAPHICS);
@@ -719,8 +713,8 @@
case Command::InsertDebugMarker: {
if (device->GetDeviceInfo().debugMarker) {
- InsertDebugMarkerCmd* cmd = mCommands.NextCommand<InsertDebugMarkerCmd>();
- const char* label = mCommands.NextData<char>(cmd->length + 1);
+ InsertDebugMarkerCmd* cmd = iter->NextCommand<InsertDebugMarkerCmd>();
+ const char* label = iter->NextData<char>(cmd->length + 1);
VkDebugMarkerMarkerInfoEXT markerInfo;
markerInfo.sType = VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT;
markerInfo.pNext = nullptr;
@@ -732,23 +726,23 @@
markerInfo.color[3] = 1.0;
device->fn.CmdDebugMarkerInsertEXT(commands, &markerInfo);
} else {
- SkipCommand(&mCommands, Command::InsertDebugMarker);
+ SkipCommand(iter, Command::InsertDebugMarker);
}
} break;
case Command::PopDebugGroup: {
if (device->GetDeviceInfo().debugMarker) {
- mCommands.NextCommand<PopDebugGroupCmd>();
+ iter->NextCommand<PopDebugGroupCmd>();
device->fn.CmdDebugMarkerEndEXT(commands);
} else {
- SkipCommand(&mCommands, Command::PopDebugGroup);
+ SkipCommand(iter, Command::PopDebugGroup);
}
} break;
case Command::PushDebugGroup: {
if (device->GetDeviceInfo().debugMarker) {
- PushDebugGroupCmd* cmd = mCommands.NextCommand<PushDebugGroupCmd>();
- const char* label = mCommands.NextData<char>(cmd->length + 1);
+ PushDebugGroupCmd* cmd = iter->NextCommand<PushDebugGroupCmd>();
+ const char* label = iter->NextData<char>(cmd->length + 1);
VkDebugMarkerMarkerInfoEXT markerInfo;
markerInfo.sType = VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT;
markerInfo.pNext = nullptr;
@@ -760,35 +754,24 @@
markerInfo.color[3] = 1.0;
device->fn.CmdDebugMarkerBeginEXT(commands, &markerInfo);
} else {
- SkipCommand(&mCommands, Command::PushDebugGroup);
+ SkipCommand(iter, Command::PushDebugGroup);
}
} break;
case Command::SetBindGroup: {
- SetBindGroupCmd* cmd = mCommands.NextCommand<SetBindGroupCmd>();
+ SetBindGroupCmd* cmd = iter->NextCommand<SetBindGroupCmd>();
VkDescriptorSet set = ToBackend(cmd->group.Get())->GetHandle();
uint64_t* dynamicOffsets = nullptr;
if (cmd->dynamicOffsetCount > 0) {
- dynamicOffsets = mCommands.NextData<uint64_t>(cmd->dynamicOffsetCount);
+ dynamicOffsets = iter->NextData<uint64_t>(cmd->dynamicOffsetCount);
}
descriptorSets.OnSetBindGroup(cmd->index, set, cmd->dynamicOffsetCount,
dynamicOffsets);
} break;
- case Command::SetBlendColor: {
- SetBlendColorCmd* cmd = mCommands.NextCommand<SetBlendColorCmd>();
- float blendConstants[4] = {
- cmd->color.r,
- cmd->color.g,
- cmd->color.b,
- cmd->color.a,
- };
- device->fn.CmdSetBlendConstants(commands, blendConstants);
- } break;
-
case Command::SetIndexBuffer: {
- SetIndexBufferCmd* cmd = mCommands.NextCommand<SetIndexBufferCmd>();
+ SetIndexBufferCmd* cmd = iter->NextCommand<SetIndexBufferCmd>();
VkBuffer indexBuffer = ToBackend(cmd->buffer)->GetHandle();
// TODO(cwallez@chromium.org): get the index type from the last render pipeline
@@ -801,7 +784,7 @@
} break;
case Command::SetRenderPipeline: {
- SetRenderPipelineCmd* cmd = mCommands.NextCommand<SetRenderPipelineCmd>();
+ SetRenderPipelineCmd* cmd = iter->NextCommand<SetRenderPipelineCmd>();
RenderPipeline* pipeline = ToBackend(cmd->pipeline).Get();
device->fn.CmdBindPipeline(commands, VK_PIPELINE_BIND_POINT_GRAPHICS,
@@ -811,6 +794,50 @@
descriptorSets.OnPipelineLayoutChange(ToBackend(pipeline->GetLayout()));
} break;
+ case Command::SetVertexBuffers: {
+ SetVertexBuffersCmd* cmd = iter->NextCommand<SetVertexBuffersCmd>();
+ auto buffers = iter->NextData<Ref<BufferBase>>(cmd->count);
+ auto offsets = iter->NextData<uint64_t>(cmd->count);
+
+ std::array<VkBuffer, kMaxVertexBuffers> vkBuffers;
+ std::array<VkDeviceSize, kMaxVertexBuffers> vkOffsets;
+
+ for (uint32_t i = 0; i < cmd->count; ++i) {
+ Buffer* buffer = ToBackend(buffers[i].Get());
+ vkBuffers[i] = buffer->GetHandle();
+ vkOffsets[i] = static_cast<VkDeviceSize>(offsets[i]);
+ }
+
+ device->fn.CmdBindVertexBuffers(commands, cmd->startSlot, cmd->count,
+ vkBuffers.data(), vkOffsets.data());
+ } break;
+
+ default:
+ UNREACHABLE();
+ break;
+ }
+ };
+
+ Command type;
+ while (mCommands.NextCommandId(&type)) {
+ switch (type) {
+ case Command::EndRenderPass: {
+ mCommands.NextCommand<EndRenderPassCmd>();
+ device->fn.CmdEndRenderPass(commands);
+ return;
+ } break;
+
+ case Command::SetBlendColor: {
+ SetBlendColorCmd* cmd = mCommands.NextCommand<SetBlendColorCmd>();
+ float blendConstants[4] = {
+ cmd->color.r,
+ cmd->color.g,
+ cmd->color.b,
+ cmd->color.a,
+ };
+ device->fn.CmdSetBlendConstants(commands, blendConstants);
+ } break;
+
case Command::SetStencilReference: {
SetStencilReferenceCmd* cmd = mCommands.NextCommand<SetStencilReferenceCmd>();
device->fn.CmdSetStencilReference(commands, VK_STENCIL_FRONT_AND_BACK,
@@ -841,25 +868,20 @@
device->fn.CmdSetScissor(commands, 0, 1, &rect);
} break;
- case Command::SetVertexBuffers: {
- SetVertexBuffersCmd* cmd = mCommands.NextCommand<SetVertexBuffersCmd>();
- auto buffers = mCommands.NextData<Ref<BufferBase>>(cmd->count);
- auto offsets = mCommands.NextData<uint64_t>(cmd->count);
-
- std::array<VkBuffer, kMaxVertexBuffers> vkBuffers;
- std::array<VkDeviceSize, kMaxVertexBuffers> vkOffsets;
+ 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) {
- Buffer* buffer = ToBackend(buffers[i].Get());
- vkBuffers[i] = buffer->GetHandle();
- vkOffsets[i] = static_cast<VkDeviceSize>(offsets[i]);
+ CommandIterator* iter = bundles[i]->GetCommands();
+ iter->Reset();
+ while (iter->NextCommandId(&type)) {
+ EncodeRenderBundleCommand(iter, type);
+ }
}
-
- device->fn.CmdBindVertexBuffers(commands, cmd->startSlot, cmd->count,
- vkBuffers.data(), vkOffsets.data());
} break;
- default: { UNREACHABLE(); } break;
+ default: { EncodeRenderBundleCommand(&mCommands, type); } break;
}
}
diff --git a/src/tests/end2end/RenderBundleTests.cpp b/src/tests/end2end/RenderBundleTests.cpp
new file mode 100644
index 0000000..ad2dd3c
--- /dev/null
+++ b/src/tests/end2end/RenderBundleTests.cpp
@@ -0,0 +1,210 @@
+// Copyright 2019 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "tests/DawnTest.h"
+
+#include "utils/ComboRenderBundleEncoderDescriptor.h"
+#include "utils/ComboRenderPipelineDescriptor.h"
+#include "utils/DawnHelpers.h"
+
+constexpr uint32_t kRTSize = 4;
+constexpr RGBA8 kColors[2] = {RGBA8(0, 255, 0, 255), RGBA8(0, 0, 255, 255)};
+
+// RenderBundleTest tests simple usage of RenderBundles to draw. The implementaiton
+// of RenderBundle is shared significantly with render pass execution which is
+// tested in all other rendering tests.
+class RenderBundleTest : public DawnTest {
+ protected:
+ void SetUp() override {
+ DawnTest::SetUp();
+
+ renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
+
+ dawn::ShaderModule vsModule =
+ utils::CreateShaderModule(device, utils::ShaderStage::Vertex, R"(
+ #version 450
+ layout(location = 0) in vec4 pos;
+ void main() {
+ gl_Position = pos;
+ })");
+
+ dawn::ShaderModule fsModule =
+ utils::CreateShaderModule(device, utils::ShaderStage::Fragment, R"(
+ #version 450
+ layout(location = 0) out vec4 fragColor;
+ layout (set = 0, binding = 0) uniform fragmentUniformBuffer {
+ vec4 color;
+ };
+ void main() {
+ fragColor = color;
+ })");
+
+ dawn::BindGroupLayout bgl = utils::MakeBindGroupLayout(
+ device, {{0, dawn::ShaderStageBit::Fragment, dawn::BindingType::UniformBuffer}});
+
+ float colors0[] = {kColors[0].r / 255.f, kColors[0].g / 255.f, kColors[0].b / 255.f,
+ kColors[0].a / 255.f};
+ float colors1[] = {kColors[1].r / 255.f, kColors[1].g / 255.f, kColors[1].b / 255.f,
+ kColors[1].a / 255.f};
+
+ dawn::Buffer buffer0 = utils::CreateBufferFromData(device, colors0, 4 * sizeof(float),
+ dawn::BufferUsageBit::Uniform);
+ dawn::Buffer buffer1 = utils::CreateBufferFromData(device, colors1, 4 * sizeof(float),
+ dawn::BufferUsageBit::Uniform);
+
+ bindGroups[0] = utils::MakeBindGroup(device, bgl, {{0, buffer0, 0, 4 * sizeof(float)}});
+ bindGroups[1] = utils::MakeBindGroup(device, bgl, {{0, buffer1, 0, 4 * sizeof(float)}});
+
+ dawn::PipelineLayoutDescriptor pipelineLayoutDesc;
+ pipelineLayoutDesc.bindGroupLayoutCount = 1;
+ pipelineLayoutDesc.bindGroupLayouts = &bgl;
+
+ dawn::PipelineLayout pipelineLayout = device.CreatePipelineLayout(&pipelineLayoutDesc);
+
+ utils::ComboRenderPipelineDescriptor descriptor(device);
+ descriptor.layout = pipelineLayout;
+ descriptor.cVertexStage.module = vsModule;
+ descriptor.cFragmentStage.module = fsModule;
+ descriptor.primitiveTopology = dawn::PrimitiveTopology::TriangleStrip;
+ descriptor.cVertexInput.bufferCount = 1;
+ descriptor.cVertexInput.cBuffers[0].stride = 4 * sizeof(float);
+ descriptor.cVertexInput.cBuffers[0].attributeCount = 1;
+ descriptor.cVertexInput.cAttributes[0].format = dawn::VertexFormat::Float4;
+ descriptor.cColorStates[0]->format = renderPass.colorFormat;
+
+ pipeline = device.CreateRenderPipeline(&descriptor);
+
+ vertexBuffer = utils::CreateBufferFromData<float>(
+ device, dawn::BufferUsageBit::Vertex,
+ {// The bottom left triangle
+ -1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f,
+
+ // The top right triangle
+ -1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f, 0.0f, 1.0f});
+ }
+
+ utils::BasicRenderPass renderPass;
+ dawn::RenderPipeline pipeline;
+ dawn::Buffer vertexBuffer;
+ dawn::BindGroup bindGroups[2];
+};
+
+// Basic test of RenderBundle.
+TEST_P(RenderBundleTest, Basic) {
+ utils::ComboRenderBundleEncoderDescriptor desc = {};
+ desc.colorFormatsCount = 1;
+ desc.cColorFormats[0] = renderPass.colorFormat;
+
+ dawn::RenderBundleEncoder renderBundleEncoder = device.CreateRenderBundleEncoder(&desc);
+
+ uint64_t zeroOffset = 0;
+ renderBundleEncoder.SetPipeline(pipeline);
+ renderBundleEncoder.SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset);
+ renderBundleEncoder.SetBindGroup(0, bindGroups[0], 0, nullptr);
+ renderBundleEncoder.Draw(6, 1, 0, 0);
+
+ dawn::RenderBundle renderBundle = renderBundleEncoder.Finish();
+
+ dawn::CommandEncoder encoder = device.CreateCommandEncoder();
+
+ dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
+ pass.ExecuteBundles(1, &renderBundle);
+ pass.EndPass();
+
+ dawn::CommandBuffer commands = encoder.Finish();
+ queue.Submit(1, &commands);
+
+ EXPECT_PIXEL_RGBA8_EQ(kColors[0], renderPass.color, 1, 3);
+ EXPECT_PIXEL_RGBA8_EQ(kColors[0], renderPass.color, 3, 1);
+}
+
+// Test execution of multiple render bundles
+TEST_P(RenderBundleTest, MultipleBundles) {
+ utils::ComboRenderBundleEncoderDescriptor desc = {};
+ desc.colorFormatsCount = 1;
+ desc.cColorFormats[0] = renderPass.colorFormat;
+
+ dawn::RenderBundle renderBundles[2];
+ uint64_t zeroOffset = 0;
+ {
+ dawn::RenderBundleEncoder renderBundleEncoder = device.CreateRenderBundleEncoder(&desc);
+
+ renderBundleEncoder.SetPipeline(pipeline);
+ renderBundleEncoder.SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset);
+ renderBundleEncoder.SetBindGroup(0, bindGroups[0], 0, nullptr);
+ renderBundleEncoder.Draw(3, 1, 0, 0);
+
+ renderBundles[0] = renderBundleEncoder.Finish();
+ }
+ {
+ dawn::RenderBundleEncoder renderBundleEncoder = device.CreateRenderBundleEncoder(&desc);
+
+ renderBundleEncoder.SetPipeline(pipeline);
+ renderBundleEncoder.SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset);
+ renderBundleEncoder.SetBindGroup(0, bindGroups[1], 0, nullptr);
+ renderBundleEncoder.Draw(3, 1, 3, 0);
+
+ renderBundles[1] = renderBundleEncoder.Finish();
+ }
+
+ dawn::CommandEncoder encoder = device.CreateCommandEncoder();
+
+ dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
+ pass.ExecuteBundles(2, renderBundles);
+ pass.EndPass();
+
+ dawn::CommandBuffer commands = encoder.Finish();
+ queue.Submit(1, &commands);
+
+ EXPECT_PIXEL_RGBA8_EQ(kColors[0], renderPass.color, 1, 3);
+ EXPECT_PIXEL_RGBA8_EQ(kColors[1], renderPass.color, 3, 1);
+}
+
+// Test execution of a bundle along with render pass commands.
+TEST_P(RenderBundleTest, BundleAndRenderPassCommands) {
+ utils::ComboRenderBundleEncoderDescriptor desc = {};
+ desc.colorFormatsCount = 1;
+ desc.cColorFormats[0] = renderPass.colorFormat;
+
+ dawn::RenderBundleEncoder renderBundleEncoder = device.CreateRenderBundleEncoder(&desc);
+
+ uint64_t zeroOffset = 0;
+ renderBundleEncoder.SetPipeline(pipeline);
+ renderBundleEncoder.SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset);
+ renderBundleEncoder.SetBindGroup(0, bindGroups[0], 0, nullptr);
+ renderBundleEncoder.Draw(3, 1, 0, 0);
+
+ dawn::RenderBundle renderBundle = renderBundleEncoder.Finish();
+
+ dawn::CommandEncoder encoder = device.CreateCommandEncoder();
+
+ dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
+ pass.ExecuteBundles(1, &renderBundle);
+
+ pass.SetPipeline(pipeline);
+ pass.SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset);
+ pass.SetBindGroup(0, bindGroups[1], 0, nullptr);
+ pass.Draw(3, 1, 3, 0);
+
+ pass.ExecuteBundles(1, &renderBundle);
+ pass.EndPass();
+
+ dawn::CommandBuffer commands = encoder.Finish();
+ queue.Submit(1, &commands);
+
+ EXPECT_PIXEL_RGBA8_EQ(kColors[0], renderPass.color, 1, 3);
+ EXPECT_PIXEL_RGBA8_EQ(kColors[1], renderPass.color, 3, 1);
+}
+
+DAWN_INSTANTIATE_TEST(RenderBundleTest, D3D12Backend, MetalBackend, OpenGLBackend, VulkanBackend);