Add Labels For Pipelines and ShaderModule for D3D12/Vk

Adds labels for Pipelines and ShaderModule. Includes tests. Backend
functionality is implemented for Pipelines, and completed to best effort
for ShaderModule.

Bug: dawn:840
Change-Id: I55024a83f66d9fc2fc0e8b79e4b9a7ebc6f3cf1c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/62860
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Brandon Jones (Intel) <brandon1.jones@intel.com>
diff --git a/src/dawn_native/ComputePipeline.cpp b/src/dawn_native/ComputePipeline.cpp
index ca173a5..d1a4a8d 100644
--- a/src/dawn_native/ComputePipeline.cpp
+++ b/src/dawn_native/ComputePipeline.cpp
@@ -76,6 +76,7 @@
                                              const ComputePipelineDescriptor* descriptor)
         : PipelineBase(device,
                        descriptor->layout,
+                       descriptor->label,
                        {{SingleShaderStage::Compute, descriptor->compute.module,
                          descriptor->compute.entryPoint}}) {
     }
diff --git a/src/dawn_native/Pipeline.cpp b/src/dawn_native/Pipeline.cpp
index d1aa665..77dd79e 100644
--- a/src/dawn_native/Pipeline.cpp
+++ b/src/dawn_native/Pipeline.cpp
@@ -50,8 +50,9 @@
 
     PipelineBase::PipelineBase(DeviceBase* device,
                                PipelineLayoutBase* layout,
+                               const char* label,
                                std::vector<StageAndDescriptor> stages)
-        : CachedObject(device, kLabelNotImplemented), mLayout(layout) {
+        : CachedObject(device, label), mLayout(layout) {
         ASSERT(!stages.empty());
 
         for (const StageAndDescriptor& stage : stages) {
diff --git a/src/dawn_native/Pipeline.h b/src/dawn_native/Pipeline.h
index 3ed80f1..baa2b2f 100644
--- a/src/dawn_native/Pipeline.h
+++ b/src/dawn_native/Pipeline.h
@@ -62,6 +62,7 @@
       protected:
         PipelineBase(DeviceBase* device,
                      PipelineLayoutBase* layout,
+                     const char* label,
                      std::vector<StageAndDescriptor> stages);
         PipelineBase(DeviceBase* device, ObjectBase::ErrorTag tag);
 
diff --git a/src/dawn_native/RenderPipeline.cpp b/src/dawn_native/RenderPipeline.cpp
index decde9c..0e8da0b 100644
--- a/src/dawn_native/RenderPipeline.cpp
+++ b/src/dawn_native/RenderPipeline.cpp
@@ -473,6 +473,7 @@
                                            const RenderPipelineDescriptor* descriptor)
         : PipelineBase(device,
                        descriptor->layout,
+                       descriptor->label,
                        {{SingleShaderStage::Vertex, descriptor->vertex.module,
                          descriptor->vertex.entryPoint},
                         {SingleShaderStage::Fragment, descriptor->fragment->module,
diff --git a/src/dawn_native/ShaderModule.cpp b/src/dawn_native/ShaderModule.cpp
index 4d9f173..f821606 100644
--- a/src/dawn_native/ShaderModule.cpp
+++ b/src/dawn_native/ShaderModule.cpp
@@ -1124,7 +1124,7 @@
     // ShaderModuleBase
 
     ShaderModuleBase::ShaderModuleBase(DeviceBase* device, const ShaderModuleDescriptor* descriptor)
-        : CachedObject(device, kLabelNotImplemented), mType(Type::Undefined) {
+        : CachedObject(device, descriptor->label), mType(Type::Undefined) {
         ASSERT(descriptor->nextInChain != nullptr);
         const ShaderModuleSPIRVDescriptor* spirvDesc = nullptr;
         FindInChain(descriptor->nextInChain, &spirvDesc);
diff --git a/src/dawn_native/d3d12/ComputePipelineD3D12.cpp b/src/dawn_native/d3d12/ComputePipelineD3D12.cpp
index 0682fd1..6649a47 100644
--- a/src/dawn_native/d3d12/ComputePipelineD3D12.cpp
+++ b/src/dawn_native/d3d12/ComputePipelineD3D12.cpp
@@ -57,6 +57,9 @@
         DAWN_TRY(CheckHRESULT(
             d3d12Device->CreateComputePipelineState(&d3dDesc, IID_PPV_ARGS(&mPipelineState)),
             "D3D12 creating pipeline state"));
+
+        SetLabelImpl();
+
         return {};
     }
 
@@ -68,6 +71,11 @@
         return mPipelineState.Get();
     }
 
+    void ComputePipeline::SetLabelImpl() {
+        SetDebugName(ToBackend(GetDevice()), GetPipelineState(), "Dawn_ComputePipeline",
+                     GetLabel());
+    }
+
     void ComputePipeline::CreateAsync(Device* device,
                                       std::unique_ptr<FlatComputePipelineDescriptor> descriptor,
                                       size_t blueprintHash,
diff --git a/src/dawn_native/d3d12/ComputePipelineD3D12.h b/src/dawn_native/d3d12/ComputePipelineD3D12.h
index 089c7af..ddb3ea0 100644
--- a/src/dawn_native/d3d12/ComputePipelineD3D12.h
+++ b/src/dawn_native/d3d12/ComputePipelineD3D12.h
@@ -37,6 +37,9 @@
 
         ID3D12PipelineState* GetPipelineState() const;
 
+        // Dawn API
+        void SetLabelImpl() override;
+
       private:
         ~ComputePipeline() override;
         using ComputePipelineBase::ComputePipelineBase;
diff --git a/src/dawn_native/d3d12/RenderPipelineD3D12.cpp b/src/dawn_native/d3d12/RenderPipelineD3D12.cpp
index d55e96b..20ef8c2 100644
--- a/src/dawn_native/d3d12/RenderPipelineD3D12.cpp
+++ b/src/dawn_native/d3d12/RenderPipelineD3D12.cpp
@@ -426,6 +426,9 @@
         DAWN_TRY(CheckHRESULT(device->GetD3D12Device()->CreateGraphicsPipelineState(
                                   &descriptorD3D12, IID_PPV_ARGS(&mPipelineState)),
                               "D3D12 create graphics pipeline state"));
+
+        SetLabelImpl();
+
         return {};
     }
 
@@ -445,6 +448,10 @@
         return mFirstOffsetInfo;
     }
 
+    void RenderPipeline::SetLabelImpl() {
+        SetDebugName(ToBackend(GetDevice()), GetPipelineState(), "Dawn_RenderPipeline", GetLabel());
+    }
+
     D3D12_INPUT_LAYOUT_DESC RenderPipeline::ComputeInputLayout(
         std::array<D3D12_INPUT_ELEMENT_DESC, kMaxVertexAttributes>* inputElementDescriptors) {
         unsigned int count = 0;
diff --git a/src/dawn_native/d3d12/RenderPipelineD3D12.h b/src/dawn_native/d3d12/RenderPipelineD3D12.h
index c99d0a1..67222f4 100644
--- a/src/dawn_native/d3d12/RenderPipelineD3D12.h
+++ b/src/dawn_native/d3d12/RenderPipelineD3D12.h
@@ -36,6 +36,9 @@
 
         const FirstOffsetInfo& GetFirstOffsetInfo() const;
 
+        // Dawn API
+        void SetLabelImpl() override;
+
       private:
         ~RenderPipeline() override;
         using RenderPipelineBase::RenderPipelineBase;
diff --git a/src/dawn_native/vulkan/ComputePipelineVk.cpp b/src/dawn_native/vulkan/ComputePipelineVk.cpp
index 90b2369..4cabbb1 100644
--- a/src/dawn_native/vulkan/ComputePipelineVk.cpp
+++ b/src/dawn_native/vulkan/ComputePipelineVk.cpp
@@ -68,10 +68,19 @@
                 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT);
         }
 
-        return CheckVkSuccess(
+        DAWN_TRY(CheckVkSuccess(
             device->fn.CreateComputePipelines(device->GetVkDevice(), ::VK_NULL_HANDLE, 1,
                                               &createInfo, nullptr, &*mHandle),
-            "CreateComputePipeline");
+            "CreateComputePipeline"));
+
+        SetLabelImpl();
+
+        return {};
+    }
+
+    void ComputePipeline::SetLabelImpl() {
+        SetDebugName(ToBackend(GetDevice()), VK_OBJECT_TYPE_PIPELINE,
+                     reinterpret_cast<uint64_t&>(mHandle), "Dawn_ComputePipeline", GetLabel());
     }
 
     ComputePipeline::~ComputePipeline() {
diff --git a/src/dawn_native/vulkan/ComputePipelineVk.h b/src/dawn_native/vulkan/ComputePipelineVk.h
index 221a358..7afe9cf 100644
--- a/src/dawn_native/vulkan/ComputePipelineVk.h
+++ b/src/dawn_native/vulkan/ComputePipelineVk.h
@@ -37,6 +37,9 @@
 
         VkPipeline GetHandle() const;
 
+        // Dawn API
+        void SetLabelImpl() override;
+
       private:
         ~ComputePipeline() override;
         using ComputePipelineBase::ComputePipelineBase;
diff --git a/src/dawn_native/vulkan/RenderPipelineVk.cpp b/src/dawn_native/vulkan/RenderPipelineVk.cpp
index 79dbb40..74a2a88 100644
--- a/src/dawn_native/vulkan/RenderPipelineVk.cpp
+++ b/src/dawn_native/vulkan/RenderPipelineVk.cpp
@@ -515,10 +515,19 @@
         createInfo.basePipelineHandle = VkPipeline{};
         createInfo.basePipelineIndex = -1;
 
-        return CheckVkSuccess(
+        DAWN_TRY(CheckVkSuccess(
             device->fn.CreateGraphicsPipelines(device->GetVkDevice(), VkPipelineCache{}, 1,
                                                &createInfo, nullptr, &*mHandle),
-            "CreateGraphicsPipeline");
+            "CreateGraphicsPipeline"));
+
+        SetLabelImpl();
+
+        return {};
+    }
+
+    void RenderPipeline::SetLabelImpl() {
+        SetDebugName(ToBackend(GetDevice()), VK_OBJECT_TYPE_PIPELINE,
+                     reinterpret_cast<uint64_t&>(mHandle), "Dawn_RenderPipeline", GetLabel());
     }
 
     VkPipelineVertexInputStateCreateInfo RenderPipeline::ComputeVertexInputDesc(
diff --git a/src/dawn_native/vulkan/RenderPipelineVk.h b/src/dawn_native/vulkan/RenderPipelineVk.h
index 7dfc468..9339bb6 100644
--- a/src/dawn_native/vulkan/RenderPipelineVk.h
+++ b/src/dawn_native/vulkan/RenderPipelineVk.h
@@ -32,6 +32,9 @@
 
         VkPipeline GetHandle() const;
 
+        // Dawn API
+        void SetLabelImpl() override;
+
       private:
         ~RenderPipeline() override;
         using RenderPipelineBase::RenderPipelineBase;
diff --git a/src/dawn_native/vulkan/ShaderModuleVk.cpp b/src/dawn_native/vulkan/ShaderModuleVk.cpp
index 798424e..cbc004b 100644
--- a/src/dawn_native/vulkan/ShaderModuleVk.cpp
+++ b/src/dawn_native/vulkan/ShaderModuleVk.cpp
@@ -20,6 +20,7 @@
 #include "dawn_native/vulkan/DeviceVk.h"
 #include "dawn_native/vulkan/FencedDeleter.h"
 #include "dawn_native/vulkan/PipelineLayoutVk.h"
+#include "dawn_native/vulkan/UtilsVulkan.h"
 #include "dawn_native/vulkan/VulkanError.h"
 
 #include <tint/tint.h>
@@ -187,6 +188,9 @@
                 mTransformedShaderModuleCache.AddOrGetCachedShaderModule(cacheKey, newHandle);
         }
 
+        SetDebugName(ToBackend(GetDevice()), VK_OBJECT_TYPE_SHADER_MODULE,
+                     reinterpret_cast<uint64_t&>(newHandle), "Dawn_ShaderModule", GetLabel());
+
         return newHandle;
     }
 
diff --git a/src/tests/unittests/validation/LabelTests.cpp b/src/tests/unittests/validation/LabelTests.cpp
index 4cb2a24..0208876 100644
--- a/src/tests/unittests/validation/LabelTests.cpp
+++ b/src/tests/unittests/validation/LabelTests.cpp
@@ -8,12 +8,14 @@
 //
 // Unless required by applicable law or agreed to in writing, software
 // distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WvecANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// 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 <string>
 #include "tests/unittests/validation/ValidationTest.h"
+#include "utils/ComboRenderPipelineDescriptor.h"
+#include "utils/WGPUHelpers.h"
 
 class LabelTest : public ValidationTest {};
 
@@ -83,4 +85,120 @@
         std::string readbackLabel = dawn_native::GetObjectLabelForTesting(texture.Get());
         ASSERT_EQ(label, readbackLabel);
     }
+}
+
+TEST_F(LabelTest, RenderPipeline) {
+    DAWN_SKIP_TEST_IF(UsesWire());
+    std::string label = "test";
+
+    wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, R"(
+            [[stage(vertex)]] fn main() -> [[builtin(position)]] vec4<f32> {
+                return vec4<f32>(0.0, 0.0, 0.0, 1.0);
+            })");
+
+    wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, R"(
+            [[stage(fragment)]] fn main() -> [[location(0)]] vec4<f32> {
+                return vec4<f32>(0.0, 1.0, 0.0, 1.0);
+            })");
+
+    utils::ComboRenderPipelineDescriptor descriptor;
+    descriptor.vertex.module = vsModule;
+    descriptor.cFragment.module = fsModule;
+
+    // The label should be empty if one was not set.
+    {
+        wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&descriptor);
+        std::string readbackLabel = dawn_native::GetObjectLabelForTesting(pipeline.Get());
+        ASSERT_TRUE(readbackLabel.empty());
+    }
+
+    // Test setting a label through API
+    {
+        wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&descriptor);
+        pipeline.SetLabel(label.c_str());
+        std::string readbackLabel = dawn_native::GetObjectLabelForTesting(pipeline.Get());
+        ASSERT_EQ(label, readbackLabel);
+    }
+
+    // Test setting a label through the descriptor.
+    {
+        descriptor.label = label.c_str();
+        wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&descriptor);
+        std::string readbackLabel = dawn_native::GetObjectLabelForTesting(pipeline.Get());
+        ASSERT_EQ(label, readbackLabel);
+    }
+}
+
+TEST_F(LabelTest, ComputePipeline) {
+    DAWN_SKIP_TEST_IF(UsesWire());
+    std::string label = "test";
+
+    wgpu::ShaderModule computeModule = utils::CreateShaderModule(device, R"(
+    [[stage(compute), workgroup_size(1)]] fn main() {
+    })");
+    wgpu::PipelineLayout pl = utils::MakeBasicPipelineLayout(device, nullptr);
+    wgpu::ComputePipelineDescriptor descriptor;
+    descriptor.layout = pl;
+    descriptor.compute.module = computeModule;
+    descriptor.compute.entryPoint = "main";
+
+    // The label should be empty if one was not set.
+    {
+        wgpu::ComputePipeline pipeline = device.CreateComputePipeline(&descriptor);
+        std::string readbackLabel = dawn_native::GetObjectLabelForTesting(pipeline.Get());
+        ASSERT_TRUE(readbackLabel.empty());
+    }
+
+    // Test setting a label through API
+    {
+        wgpu::ComputePipeline pipeline = device.CreateComputePipeline(&descriptor);
+        pipeline.SetLabel(label.c_str());
+        std::string readbackLabel = dawn_native::GetObjectLabelForTesting(pipeline.Get());
+        ASSERT_EQ(label, readbackLabel);
+    }
+
+    // Test setting a label through the descriptor.
+    {
+        descriptor.label = label.c_str();
+        wgpu::ComputePipeline pipeline = device.CreateComputePipeline(&descriptor);
+        std::string readbackLabel = dawn_native::GetObjectLabelForTesting(pipeline.Get());
+        ASSERT_EQ(label, readbackLabel);
+    }
+}
+
+TEST_F(LabelTest, ShaderModule) {
+    DAWN_SKIP_TEST_IF(UsesWire());
+    std::string label = "test";
+
+    const char* source = R"(
+    [[stage(compute), workgroup_size(1)]] fn main() {
+    })";
+
+    wgpu::ShaderModuleWGSLDescriptor wgslDesc;
+    wgslDesc.source = source;
+    wgpu::ShaderModuleDescriptor descriptor;
+    descriptor.nextInChain = &wgslDesc;
+
+    // The label should be empty if one was not set.
+    {
+        wgpu::ShaderModule shaderModule = device.CreateShaderModule(&descriptor);
+        std::string readbackLabel = dawn_native::GetObjectLabelForTesting(shaderModule.Get());
+        ASSERT_TRUE(readbackLabel.empty());
+    }
+
+    // Test setting a label through API
+    {
+        wgpu::ShaderModule shaderModule = device.CreateShaderModule(&descriptor);
+        shaderModule.SetLabel(label.c_str());
+        std::string readbackLabel = dawn_native::GetObjectLabelForTesting(shaderModule.Get());
+        ASSERT_EQ(label, readbackLabel);
+    }
+
+    // Test setting a label through the descriptor.
+    {
+        descriptor.label = label.c_str();
+        wgpu::ShaderModule shaderModule = device.CreateShaderModule(&descriptor);
+        std::string readbackLabel = dawn_native::GetObjectLabelForTesting(shaderModule.Get());
+        ASSERT_EQ(label, readbackLabel);
+    }
 }
\ No newline at end of file