Handle debug markers commands on command encoder

This CL adds support for InsertDebugMarker, PushDebugGroup, and
PopDebugGroup commands to CommandBuffer backends.

Bug: dawn:44

Change-Id: Iaf075023d3072534fca02b71c0e205cbaa46cd0f
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/28602
Reviewed-by: Austin Eng <enga@chromium.org>
Reviewed-by: Bryan Bernhart <bryan.bernhart@intel.com>
Commit-Queue: Enrico Galli <enrico.galli@intel.com>
diff --git a/src/dawn_native/d3d12/CommandBufferD3D12.cpp b/src/dawn_native/d3d12/CommandBufferD3D12.cpp
index c949e16..5ee8b0a 100644
--- a/src/dawn_native/d3d12/CommandBufferD3D12.cpp
+++ b/src/dawn_native/d3d12/CommandBufferD3D12.cpp
@@ -916,6 +916,44 @@
                     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, kPIXBlackColor, label);
+                    }
+                    break;
+                }
+
+                case Command::PopDebugGroup: {
+                    mCommands.NextCommand<PopDebugGroupCmd>();
+
+                    if (ToBackend(GetDevice())->GetFunctions()->IsPIXEventRuntimeLoaded()) {
+                        ToBackend(GetDevice())
+                            ->GetFunctions()
+                            ->pixEndEventOnCommandList(commandList);
+                    }
+                    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, kPIXBlackColor, label);
+                    }
+                    break;
+                }
                 default: {
                     UNREACHABLE();
                     break;
diff --git a/src/dawn_native/metal/CommandBufferMTL.mm b/src/dawn_native/metal/CommandBufferMTL.mm
index 79416b8..7aae8de 100644
--- a/src/dawn_native/metal/CommandBufferMTL.mm
+++ b/src/dawn_native/metal/CommandBufferMTL.mm
@@ -766,6 +766,34 @@
                     return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation.");
                 }
 
+                case Command::InsertDebugMarker: {
+                    // MTLCommandBuffer does not implement insertDebugSignpost
+                    SkipCommand(&mCommands, type);
+                    break;
+                }
+
+                case Command::PopDebugGroup: {
+                    mCommands.NextCommand<PopDebugGroupCmd>();
+
+                    if (@available(macos 10.13, *)) {
+                        [commandContext->GetCommands() popDebugGroup];
+                    }
+                    break;
+                }
+
+                case Command::PushDebugGroup: {
+                    PushDebugGroupCmd* cmd = mCommands.NextCommand<PushDebugGroupCmd>();
+                    char* label = mCommands.NextData<char>(cmd->length + 1);
+
+                    if (@available(macos 10.13, *)) {
+                        NSString* mtlLabel = [[NSString alloc] initWithUTF8String:label];
+                        [commandContext->GetCommands() pushDebugGroup:mtlLabel];
+                        [mtlLabel release];
+                    }
+
+                    break;
+                }
+
                 default: {
                     UNREACHABLE();
                     break;
diff --git a/src/dawn_native/opengl/CommandBufferGL.cpp b/src/dawn_native/opengl/CommandBufferGL.cpp
index f0705b9..d2cb6c2 100644
--- a/src/dawn_native/opengl/CommandBufferGL.cpp
+++ b/src/dawn_native/opengl/CommandBufferGL.cpp
@@ -734,6 +734,15 @@
                     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;
+                }
+
                 default: {
                     UNREACHABLE();
                     break;
diff --git a/src/dawn_native/vulkan/CommandBufferVk.cpp b/src/dawn_native/vulkan/CommandBufferVk.cpp
index c1bc5d4..3e37f5f 100644
--- a/src/dawn_native/vulkan/CommandBufferVk.cpp
+++ b/src/dawn_native/vulkan/CommandBufferVk.cpp
@@ -774,6 +774,54 @@
                     break;
                 }
 
+                case Command::InsertDebugMarker: {
+                    if (device->GetDeviceInfo().HasExt(DeviceExt::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.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().HasExt(DeviceExt::DebugMarker)) {
+                        mCommands.NextCommand<PopDebugGroupCmd>();
+                        device->fn.CmdDebugMarkerEndEXT(commands);
+                    } else {
+                        SkipCommand(&mCommands, Command::PopDebugGroup);
+                    }
+                    break;
+                }
+
+                case Command::PushDebugGroup: {
+                    if (device->GetDeviceInfo().HasExt(DeviceExt::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.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;
+                }
+
                 default: {
                     UNREACHABLE();
                     break;
diff --git a/src/tests/end2end/DebugMarkerTests.cpp b/src/tests/end2end/DebugMarkerTests.cpp
index d368a17..1ac1a01 100644
--- a/src/tests/end2end/DebugMarkerTests.cpp
+++ b/src/tests/end2end/DebugMarkerTests.cpp
@@ -23,6 +23,9 @@
     utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, 4, 4);
 
     wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+    encoder.PushDebugGroup("Event Start");
+    encoder.InsertDebugMarker("Marker");
+    encoder.PopDebugGroup();
     {
         wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
         pass.PushDebugGroup("Event Start");