Implementation of Debug Marker APIs
Introduces pushDebugGroup, popDebugGroup, and insertDebugMarker implementations
for Vulkan and Metal using VK_EXT_debug_marker and XCode, respectively.
Bug: dawn:44
Change-Id: I0ae56c4d67aa832123f27a1fcdddf65746261e57
Reviewed-on: https://dawn-review.googlesource.com/c/4241
Commit-Queue: Brandon Jones <brandon1.jones@intel.com>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
diff --git a/src/dawn_native/CommandEncoder.cpp b/src/dawn_native/CommandEncoder.cpp
index 7a5c81d..2498820 100644
--- a/src/dawn_native/CommandEncoder.cpp
+++ b/src/dawn_native/CommandEncoder.cpp
@@ -94,6 +94,29 @@
return {};
}
+ inline MaybeError PushDebugMarkerStack(unsigned int* counter) {
+ *counter += 1;
+ return {};
+ }
+
+ inline MaybeError PopDebugMarkerStack(unsigned int* counter) {
+ if (*counter == 0) {
+ return DAWN_VALIDATION_ERROR("Pop must be balanced by a corresponding Push.");
+ } else {
+ *counter -= 1;
+ }
+
+ return {};
+ }
+
+ inline MaybeError ValidateDebugGroups(const unsigned int counter) {
+ if (counter != 0) {
+ return DAWN_VALIDATION_ERROR("Each Push must be balanced by a corresponding Pop.");
+ }
+
+ return {};
+ }
+
MaybeError ComputeTextureCopyBufferSize(const Extent3D& copySize,
uint32_t rowPitch,
uint32_t imageHeight,
@@ -635,6 +658,8 @@
case Command::EndComputePass: {
mIterator.NextCommand<EndComputePassCmd>();
+ DAWN_TRY(ValidateDebugGroups(mDebugGroupStackSize));
+
DAWN_TRY(usageTracker.ValidateUsages(PassType::Compute));
mResourceUsages.perPass.push_back(usageTracker.AcquireResourceUsage());
return {};
@@ -645,6 +670,22 @@
DAWN_TRY(persistentState.ValidateCanDispatch());
} break;
+ case Command::InsertDebugMarker: {
+ InsertDebugMarkerCmd* cmd = mIterator.NextCommand<InsertDebugMarkerCmd>();
+ mIterator.NextData<char>(cmd->length + 1);
+ } break;
+
+ case Command::PopDebugGroup: {
+ mIterator.NextCommand<PopDebugGroupCmd>();
+ DAWN_TRY(PopDebugMarkerStack(&mDebugGroupStackSize));
+ } break;
+
+ case Command::PushDebugGroup: {
+ PushDebugGroupCmd* cmd = mIterator.NextCommand<PushDebugGroupCmd>();
+ mIterator.NextData<char>(cmd->length + 1);
+ DAWN_TRY(PushDebugMarkerStack(&mDebugGroupStackSize));
+ } break;
+
case Command::SetComputePipeline: {
SetComputePipelineCmd* cmd = mIterator.NextCommand<SetComputePipelineCmd>();
ComputePipelineBase* pipeline = cmd->pipeline.Get();
@@ -701,6 +742,8 @@
case Command::EndRenderPass: {
mIterator.NextCommand<EndRenderPassCmd>();
+ DAWN_TRY(ValidateDebugGroups(mDebugGroupStackSize));
+
DAWN_TRY(usageTracker.ValidateUsages(PassType::Render));
mResourceUsages.perPass.push_back(usageTracker.AcquireResourceUsage());
return {};
@@ -716,6 +759,22 @@
DAWN_TRY(persistentState.ValidateCanDrawIndexed());
} break;
+ case Command::InsertDebugMarker: {
+ InsertDebugMarkerCmd* cmd = mIterator.NextCommand<InsertDebugMarkerCmd>();
+ mIterator.NextData<char>(cmd->length + 1);
+ } break;
+
+ case Command::PopDebugGroup: {
+ mIterator.NextCommand<PopDebugGroupCmd>();
+ DAWN_TRY(PopDebugMarkerStack(&mDebugGroupStackSize));
+ } break;
+
+ case Command::PushDebugGroup: {
+ PushDebugGroupCmd* cmd = mIterator.NextCommand<PushDebugGroupCmd>();
+ mIterator.NextData<char>(cmd->length + 1);
+ DAWN_TRY(PushDebugMarkerStack(&mDebugGroupStackSize));
+ } break;
+
case Command::SetRenderPipeline: {
SetRenderPipelineCmd* cmd = mIterator.NextCommand<SetRenderPipelineCmd>();
RenderPipelineBase* pipeline = cmd->pipeline.Get();
diff --git a/src/dawn_native/CommandEncoder.h b/src/dawn_native/CommandEncoder.h
index 7ff5d1d..6935847 100644
--- a/src/dawn_native/CommandEncoder.h
+++ b/src/dawn_native/CommandEncoder.h
@@ -87,6 +87,8 @@
bool mWereResourceUsagesAcquired = false;
CommandBufferResourceUsage mResourceUsages;
+ unsigned int mDebugGroupStackSize = 0;
+
bool mGotError = false;
std::string mErrorMessage;
};
diff --git a/src/dawn_native/Commands.cpp b/src/dawn_native/Commands.cpp
index 6443fc8..816dd39 100644
--- a/src/dawn_native/Commands.cpp
+++ b/src/dawn_native/Commands.cpp
@@ -69,6 +69,20 @@
EndRenderPassCmd* cmd = commands->NextCommand<EndRenderPassCmd>();
cmd->~EndRenderPassCmd();
} break;
+ case Command::InsertDebugMarker: {
+ InsertDebugMarkerCmd* cmd = commands->NextCommand<InsertDebugMarkerCmd>();
+ commands->NextData<char>(cmd->length + 1);
+ cmd->~InsertDebugMarkerCmd();
+ } break;
+ case Command::PopDebugGroup: {
+ PopDebugGroupCmd* cmd = commands->NextCommand<PopDebugGroupCmd>();
+ cmd->~PopDebugGroupCmd();
+ } break;
+ case Command::PushDebugGroup: {
+ PushDebugGroupCmd* cmd = commands->NextCommand<PushDebugGroupCmd>();
+ commands->NextData<char>(cmd->length + 1);
+ cmd->~PushDebugGroupCmd();
+ } break;
case Command::SetComputePipeline: {
SetComputePipelineCmd* cmd = commands->NextCommand<SetComputePipelineCmd>();
cmd->~SetComputePipelineCmd();
@@ -158,6 +172,20 @@
commands->NextCommand<EndRenderPassCmd>();
break;
+ case Command::InsertDebugMarker: {
+ InsertDebugMarkerCmd* cmd = commands->NextCommand<InsertDebugMarkerCmd>();
+ commands->NextData<char>(cmd->length + 1);
+ } break;
+
+ case Command::PopDebugGroup:
+ commands->NextCommand<PopDebugGroupCmd>();
+ break;
+
+ case Command::PushDebugGroup: {
+ PushDebugGroupCmd* cmd = commands->NextCommand<PushDebugGroupCmd>();
+ commands->NextData<char>(cmd->length + 1);
+ } break;
+
case Command::SetComputePipeline:
commands->NextCommand<SetComputePipelineCmd>();
break;
diff --git a/src/dawn_native/Commands.h b/src/dawn_native/Commands.h
index afa006d..94e19c5 100644
--- a/src/dawn_native/Commands.h
+++ b/src/dawn_native/Commands.h
@@ -41,6 +41,9 @@
DrawIndexed,
EndComputePass,
EndRenderPass,
+ InsertDebugMarker,
+ PopDebugGroup,
+ PushDebugGroup,
SetComputePipeline,
SetRenderPipeline,
SetPushConstants,
@@ -140,6 +143,16 @@
struct EndRenderPassCmd {};
+ struct InsertDebugMarkerCmd {
+ uint32_t length;
+ };
+
+ struct PopDebugGroupCmd {};
+
+ struct PushDebugGroupCmd {
+ uint32_t length;
+ };
+
struct SetComputePipelineCmd {
Ref<ComputePipelineBase> pipeline;
};
diff --git a/src/dawn_native/ProgrammablePassEncoder.cpp b/src/dawn_native/ProgrammablePassEncoder.cpp
index 9f54ce5..0962ba5 100644
--- a/src/dawn_native/ProgrammablePassEncoder.cpp
+++ b/src/dawn_native/ProgrammablePassEncoder.cpp
@@ -38,6 +38,30 @@
mAllocator = nullptr;
}
+ void ProgrammablePassEncoder::InsertDebugMarker(const char* groupLabel) {
+ InsertDebugMarkerCmd* cmd =
+ mAllocator->Allocate<InsertDebugMarkerCmd>(Command::InsertDebugMarker);
+ new (cmd) InsertDebugMarkerCmd;
+ cmd->length = strlen(groupLabel);
+
+ char* label = mAllocator->AllocateData<char>(cmd->length + 1);
+ memcpy(label, groupLabel, cmd->length + 1);
+ }
+
+ void ProgrammablePassEncoder::PopDebugGroup() {
+ PopDebugGroupCmd* cmd = mAllocator->Allocate<PopDebugGroupCmd>(Command::PopDebugGroup);
+ new (cmd) PopDebugGroupCmd;
+ }
+
+ void ProgrammablePassEncoder::PushDebugGroup(const char* groupLabel) {
+ PushDebugGroupCmd* cmd = mAllocator->Allocate<PushDebugGroupCmd>(Command::PushDebugGroup);
+ new (cmd) PushDebugGroupCmd;
+ cmd->length = strlen(groupLabel);
+
+ char* label = mAllocator->AllocateData<char>(cmd->length + 1);
+ memcpy(label, groupLabel, cmd->length + 1);
+ }
+
void ProgrammablePassEncoder::SetBindGroup(uint32_t groupIndex, BindGroupBase* group) {
if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands()) ||
mTopLevelEncoder->ConsumedError(GetDevice()->ValidateObject(group))) {
diff --git a/src/dawn_native/ProgrammablePassEncoder.h b/src/dawn_native/ProgrammablePassEncoder.h
index c082dc0..4924c9c 100644
--- a/src/dawn_native/ProgrammablePassEncoder.h
+++ b/src/dawn_native/ProgrammablePassEncoder.h
@@ -35,6 +35,10 @@
void EndPass();
+ void InsertDebugMarker(const char* groupLabel);
+ void PopDebugGroup();
+ void PushDebugGroup(const char* groupLabel);
+
void SetBindGroup(uint32_t groupIndex, BindGroupBase* group);
void SetPushConstants(dawn::ShaderStageBit stages,
uint32_t offset,
diff --git a/src/dawn_native/d3d12/CommandBufferD3D12.cpp b/src/dawn_native/d3d12/CommandBufferD3D12.cpp
index d11be87..30bb086 100644
--- a/src/dawn_native/d3d12/CommandBufferD3D12.cpp
+++ b/src/dawn_native/d3d12/CommandBufferD3D12.cpp
@@ -696,6 +696,14 @@
draw->firstInstance);
} break;
+ case Command::InsertDebugMarker:
+ case Command::PopDebugGroup:
+ case Command::PushDebugGroup: {
+ // TODO(brandon1.jones@intel.com): Implement debug markers after PIX licensing
+ // issue is resolved.
+ SkipCommand(&mCommands, type);
+ } break;
+
case Command::SetRenderPipeline: {
SetRenderPipelineCmd* cmd = mCommands.NextCommand<SetRenderPipelineCmd>();
RenderPipeline* pipeline = ToBackend(cmd->pipeline).Get();
diff --git a/src/dawn_native/metal/CommandBufferMTL.mm b/src/dawn_native/metal/CommandBufferMTL.mm
index f6bc3ee..43090ef 100644
--- a/src/dawn_native/metal/CommandBufferMTL.mm
+++ b/src/dawn_native/metal/CommandBufferMTL.mm
@@ -435,6 +435,30 @@
}
} break;
+ case Command::InsertDebugMarker: {
+ InsertDebugMarkerCmd* cmd = mCommands.NextCommand<InsertDebugMarkerCmd>();
+ auto label = mCommands.NextData<char>(cmd->length + 1);
+ NSString* mtlLabel = [[NSString alloc] initWithUTF8String:label];
+
+ [encoder insertDebugSignpost:mtlLabel];
+ [mtlLabel release];
+ } break;
+
+ case Command::PopDebugGroup: {
+ mCommands.NextCommand<PopDebugGroupCmd>();
+
+ [encoder popDebugGroup];
+ } break;
+
+ case Command::PushDebugGroup: {
+ PushDebugGroupCmd* cmd = mCommands.NextCommand<PushDebugGroupCmd>();
+ auto label = mCommands.NextData<char>(cmd->length + 1);
+ NSString* mtlLabel = [[NSString alloc] initWithUTF8String:label];
+
+ [encoder pushDebugGroup:mtlLabel];
+ [mtlLabel release];
+ } break;
+
case Command::SetRenderPipeline: {
SetRenderPipelineCmd* cmd = mCommands.NextCommand<SetRenderPipelineCmd>();
lastPipeline = ToBackend(cmd->pipeline).Get();
diff --git a/src/dawn_native/opengl/CommandBufferGL.cpp b/src/dawn_native/opengl/CommandBufferGL.cpp
index d86be64..7acecc7 100644
--- a/src/dawn_native/opengl/CommandBufferGL.cpp
+++ b/src/dawn_native/opengl/CommandBufferGL.cpp
@@ -637,6 +637,14 @@
}
} break;
+ case Command::InsertDebugMarker:
+ case Command::PopDebugGroup:
+ case Command::PushDebugGroup: {
+ // Due to lack of linux driver support for GL_EXT_debug_marker
+ // extension these functions are skipped.
+ SkipCommand(&mCommands, type);
+ } break;
+
case Command::SetRenderPipeline: {
SetRenderPipelineCmd* cmd = mCommands.NextCommand<SetRenderPipelineCmd>();
lastPipeline = ToBackend(cmd->pipeline).Get();
diff --git a/src/dawn_native/vulkan/CommandBufferVk.cpp b/src/dawn_native/vulkan/CommandBufferVk.cpp
index 13107dd..92cc724 100644
--- a/src/dawn_native/vulkan/CommandBufferVk.cpp
+++ b/src/dawn_native/vulkan/CommandBufferVk.cpp
@@ -432,6 +432,53 @@
draw->firstInstance);
} break;
+ case Command::InsertDebugMarker: {
+ if (device->GetDeviceInfo().debugMarker) {
+ InsertDebugMarkerCmd* cmd = mCommands.NextCommand<InsertDebugMarkerCmd>();
+ const char* label = mCommands.NextData<char>(cmd->length + 1);
+ VkDebugMarkerMarkerInfoEXT markerInfo;
+ markerInfo.sType = VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT;
+ markerInfo.pNext = nullptr;
+ markerInfo.pMarkerName = label;
+ // Default color to black
+ markerInfo.color[0] = 0.0;
+ markerInfo.color[1] = 0.0;
+ markerInfo.color[2] = 0.0;
+ markerInfo.color[3] = 1.0;
+ device->fn.CmdDebugMarkerInsertEXT(commands, &markerInfo);
+ } else {
+ SkipCommand(&mCommands, Command::InsertDebugMarker);
+ }
+ } break;
+
+ case Command::PopDebugGroup: {
+ if (device->GetDeviceInfo().debugMarker) {
+ mCommands.NextCommand<PopDebugGroupCmd>();
+ device->fn.CmdDebugMarkerEndEXT(commands);
+ } else {
+ SkipCommand(&mCommands, Command::PopDebugGroup);
+ }
+ } break;
+
+ case Command::PushDebugGroup: {
+ if (device->GetDeviceInfo().debugMarker) {
+ PushDebugGroupCmd* cmd = mCommands.NextCommand<PushDebugGroupCmd>();
+ const char* label = mCommands.NextData<char>(cmd->length + 1);
+ VkDebugMarkerMarkerInfoEXT markerInfo;
+ markerInfo.sType = VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT;
+ markerInfo.pNext = nullptr;
+ markerInfo.pMarkerName = label;
+ // Default color to black
+ markerInfo.color[0] = 0.0;
+ markerInfo.color[1] = 0.0;
+ markerInfo.color[2] = 0.0;
+ markerInfo.color[3] = 1.0;
+ device->fn.CmdDebugMarkerBeginEXT(commands, &markerInfo);
+ } else {
+ SkipCommand(&mCommands, Command::PushDebugGroup);
+ }
+ } break;
+
case Command::SetBindGroup: {
SetBindGroupCmd* cmd = mCommands.NextCommand<SetBindGroupCmd>();
VkDescriptorSet set = ToBackend(cmd->group.Get())->GetHandle();
diff --git a/src/dawn_native/vulkan/DeviceVk.cpp b/src/dawn_native/vulkan/DeviceVk.cpp
index 0b6ff31..c6dae49 100644
--- a/src/dawn_native/vulkan/DeviceVk.cpp
+++ b/src/dawn_native/vulkan/DeviceVk.cpp
@@ -331,6 +331,11 @@
std::vector<const char*> extensionsToRequest;
std::vector<VkDeviceQueueCreateInfo> queuesToRequest;
+ if (mDeviceInfo.debugMarker) {
+ extensionsToRequest.push_back(kExtensionNameExtDebugMarker);
+ usedKnobs.debugMarker = true;
+ }
+
if (mDeviceInfo.swapchain) {
extensionsToRequest.push_back(kExtensionNameKhrSwapchain);
usedKnobs.swapchain = true;
diff --git a/src/dawn_native/vulkan/VulkanFunctions.cpp b/src/dawn_native/vulkan/VulkanFunctions.cpp
index 39f3a19..771c5d5 100644
--- a/src/dawn_native/vulkan/VulkanFunctions.cpp
+++ b/src/dawn_native/vulkan/VulkanFunctions.cpp
@@ -208,6 +208,12 @@
GET_DEVICE_PROC(UpdateDescriptorSets);
GET_DEVICE_PROC(WaitForFences);
+ if (usedKnobs.debugMarker) {
+ GET_DEVICE_PROC(CmdDebugMarkerBeginEXT);
+ GET_DEVICE_PROC(CmdDebugMarkerEndEXT);
+ GET_DEVICE_PROC(CmdDebugMarkerInsertEXT);
+ }
+
if (usedKnobs.swapchain) {
GET_DEVICE_PROC(CreateSwapchainKHR);
GET_DEVICE_PROC(DestroySwapchainKHR);
diff --git a/src/dawn_native/vulkan/VulkanFunctions.h b/src/dawn_native/vulkan/VulkanFunctions.h
index e229cb0..6dcfe7e 100644
--- a/src/dawn_native/vulkan/VulkanFunctions.h
+++ b/src/dawn_native/vulkan/VulkanFunctions.h
@@ -204,6 +204,11 @@
PFN_vkUpdateDescriptorSets UpdateDescriptorSets = nullptr;
PFN_vkWaitForFences WaitForFences = nullptr;
+ // VK_EXT_debug_marker
+ PFN_vkCmdDebugMarkerBeginEXT CmdDebugMarkerBeginEXT = nullptr;
+ PFN_vkCmdDebugMarkerEndEXT CmdDebugMarkerEndEXT = nullptr;
+ PFN_vkCmdDebugMarkerInsertEXT CmdDebugMarkerInsertEXT = nullptr;
+
// VK_KHR_swapchain
PFN_vkCreateSwapchainKHR CreateSwapchainKHR = nullptr;
PFN_vkDestroySwapchainKHR DestroySwapchainKHR = nullptr;
diff --git a/src/dawn_native/vulkan/VulkanInfo.cpp b/src/dawn_native/vulkan/VulkanInfo.cpp
index 4d7a30e..747202a 100644
--- a/src/dawn_native/vulkan/VulkanInfo.cpp
+++ b/src/dawn_native/vulkan/VulkanInfo.cpp
@@ -35,6 +35,7 @@
const char kLayerNameLunargVKTrace[] = "VK_LAYER_LUNARG_vktrace";
const char kLayerNameRenderDocCapture[] = "VK_LAYER_RENDERDOC_Capture";
+ const char kExtensionNameExtDebugMarker[] = "VK_EXT_debug_marker";
const char kExtensionNameExtDebugReport[] = "VK_EXT_debug_report";
const char kExtensionNameMvkMacosSurface[] = "VK_MVK_macos_surface";
const char kExtensionNameKhrSurface[] = "VK_KHR_surface";
@@ -207,6 +208,10 @@
}
for (const auto& extension : info.extensions) {
+ if (IsExtensionName(extension, kExtensionNameExtDebugMarker)) {
+ info.debugMarker = true;
+ }
+
if (IsExtensionName(extension, kExtensionNameKhrSwapchain)) {
info.swapchain = true;
}
diff --git a/src/dawn_native/vulkan/VulkanInfo.h b/src/dawn_native/vulkan/VulkanInfo.h
index 77971dc..4425de5 100644
--- a/src/dawn_native/vulkan/VulkanInfo.h
+++ b/src/dawn_native/vulkan/VulkanInfo.h
@@ -29,6 +29,7 @@
extern const char kLayerNameLunargVKTrace[];
extern const char kLayerNameRenderDocCapture[];
+ extern const char kExtensionNameExtDebugMarker[];
extern const char kExtensionNameExtDebugReport[];
extern const char kExtensionNameMvkMacosSurface[];
extern const char kExtensionNameKhrSurface[];
@@ -66,6 +67,7 @@
VkPhysicalDeviceFeatures features;
// Extensions
+ bool debugMarker = false;
bool swapchain = false;
};
diff --git a/src/tests/end2end/DebugMarkerTests.cpp b/src/tests/end2end/DebugMarkerTests.cpp
new file mode 100644
index 0000000..1a7f6e4
--- /dev/null
+++ b/src/tests/end2end/DebugMarkerTests.cpp
@@ -0,0 +1,38 @@
+// 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/DawnHelpers.h"
+
+class DebugMarkerTests : public DawnTest {};
+
+// Make sure that calling a marker API without a debugging tool attached doesn't cause a failure.
+TEST_P(DebugMarkerTests, NoFailureWithoutDebugToolAttached) {
+ utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, 4, 4);
+
+ dawn::CommandEncoder encoder = device.CreateCommandEncoder();
+ {
+ dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+ pass.PushDebugGroup("Event Start");
+ pass.InsertDebugMarker("Marker");
+ pass.PopDebugGroup();
+ pass.EndPass();
+ }
+
+ dawn::CommandBuffer commands = encoder.Finish();
+ queue.Submit(1, &commands);
+}
+
+DAWN_INSTANTIATE_TEST(DebugMarkerTests, D3D12Backend, MetalBackend, OpenGLBackend, VulkanBackend)
diff --git a/src/tests/unittests/validation/DebugMarkerValidationTests.cpp b/src/tests/unittests/validation/DebugMarkerValidationTests.cpp
new file mode 100644
index 0000000..7c0633a
--- /dev/null
+++ b/src/tests/unittests/validation/DebugMarkerValidationTests.cpp
@@ -0,0 +1,117 @@
+// 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/unittests/validation/ValidationTest.h"
+
+#include "utils/DawnHelpers.h"
+
+class DebugMarkerValidationTest : public ValidationTest {};
+
+// Correct usage of debug markers should succeed in render pass.
+TEST_F(DebugMarkerValidationTest, RenderSuccess) {
+ utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, 4, 4);
+
+ dawn::CommandEncoder encoder = device.CreateCommandEncoder();
+ {
+ dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+ pass.PushDebugGroup("Event Start");
+ pass.PushDebugGroup("Event Start");
+ pass.InsertDebugMarker("Marker");
+ pass.PopDebugGroup();
+ pass.PopDebugGroup();
+ pass.EndPass();
+ }
+
+ encoder.Finish();
+}
+
+// A PushDebugGroup call without a following PopDebugGroup produces an error in render pass.
+TEST_F(DebugMarkerValidationTest, RenderUnbalancedPush) {
+ utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, 4, 4);
+
+ dawn::CommandEncoder encoder = device.CreateCommandEncoder();
+ {
+ dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+ pass.PushDebugGroup("Event Start");
+ pass.PushDebugGroup("Event Start");
+ pass.InsertDebugMarker("Marker");
+ pass.PopDebugGroup();
+ pass.EndPass();
+ }
+
+ ASSERT_DEVICE_ERROR(encoder.Finish());
+}
+
+// A PopDebugGroup call without a preceding PushDebugGroup produces an error in render pass.
+TEST_F(DebugMarkerValidationTest, RenderUnbalancedPop) {
+ utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, 4, 4);
+
+ dawn::CommandEncoder encoder = device.CreateCommandEncoder();
+ {
+ dawn::RenderPassEncoder pass = encoder.BeginRenderPass(renderPass.renderPassInfo);
+ pass.PushDebugGroup("Event Start");
+ pass.InsertDebugMarker("Marker");
+ pass.PopDebugGroup();
+ pass.PopDebugGroup();
+ pass.EndPass();
+ }
+
+ ASSERT_DEVICE_ERROR(encoder.Finish());
+}
+
+// Correct usage of debug markers should succeed in compute pass.
+TEST_F(DebugMarkerValidationTest, ComputeSuccess) {
+ dawn::CommandEncoder encoder = device.CreateCommandEncoder();
+ {
+ dawn::ComputePassEncoder pass = encoder.BeginComputePass();
+ pass.PushDebugGroup("Event Start");
+ pass.PushDebugGroup("Event Start");
+ pass.InsertDebugMarker("Marker");
+ pass.PopDebugGroup();
+ pass.PopDebugGroup();
+ pass.EndPass();
+ }
+
+ encoder.Finish();
+}
+
+// A PushDebugGroup call without a following PopDebugGroup produces an error in compute pass.
+TEST_F(DebugMarkerValidationTest, ComputeUnbalancedPush) {
+ dawn::CommandEncoder encoder = device.CreateCommandEncoder();
+ {
+ dawn::ComputePassEncoder pass = encoder.BeginComputePass();
+ pass.PushDebugGroup("Event Start");
+ pass.PushDebugGroup("Event Start");
+ pass.InsertDebugMarker("Marker");
+ pass.PopDebugGroup();
+ pass.EndPass();
+ }
+
+ ASSERT_DEVICE_ERROR(encoder.Finish());
+}
+
+// A PopDebugGroup call without a preceding PushDebugGroup produces an error in compute pass.
+TEST_F(DebugMarkerValidationTest, ComputeUnbalancedPop) {
+ dawn::CommandEncoder encoder = device.CreateCommandEncoder();
+ {
+ dawn::ComputePassEncoder pass = encoder.BeginComputePass();
+ pass.PushDebugGroup("Event Start");
+ pass.InsertDebugMarker("Marker");
+ pass.PopDebugGroup();
+ pass.PopDebugGroup();
+ pass.EndPass();
+ }
+
+ ASSERT_DEVICE_ERROR(encoder.Finish());
+}
\ No newline at end of file