Add Debug Label Functionality For D3D12/Vk Buffers & Textures

Adds a generic SetDebugName utility for D3D12 and Vulkan. Passes down
debug label set by user for buffers and textures to be labeled by the
appropriate backend method.

Bug: dawn:840
Change-Id: I7158b537a6e37fdf733645e6830dc33833ee683e
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/61588
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Brandon Jones (Intel) <brandon1.jones@intel.com>
This commit is contained in:
Brandon Jones 2021-08-19 20:47:28 +00:00 committed by Dawn LUCI CQ
parent ddd0a0a856
commit c95e574ce0
27 changed files with 263 additions and 17 deletions

View File

@ -279,6 +279,13 @@
{"name": "size", "type": "size_t", "default": 0}
]
},
{
"name": "set label",
"returns": "void",
"args": [
{"name": "label", "type": "char", "annotation": "const*", "length": "strlen"}
]
},
{
"name": "unmap"
},
@ -1864,6 +1871,13 @@
{"name": "descriptor", "type": "texture view descriptor", "annotation": "const*", "optional": true}
]
},
{
"name": "set label",
"returns": "void",
"args": [
{"name": "label", "type": "char", "annotation": "const*", "length": "strlen"}
]
},
{
"name": "destroy"
}

View File

@ -128,7 +128,7 @@ namespace dawn_native {
// Buffer
BufferBase::BufferBase(DeviceBase* device, const BufferDescriptor* descriptor)
: ObjectBase(device),
: ObjectBase(device, descriptor->label),
mSize(descriptor->size),
mUsage(descriptor->usage),
mState(BufferState::Unmapped) {

View File

@ -225,4 +225,9 @@ namespace dawn_native {
ExternalImageExportInfo::ExternalImageExportInfo(ExternalImageType type) : type(type) {
}
const char* GetObjectLabelForTesting(void* objectHandle) {
ObjectBase* object = reinterpret_cast<ObjectBase*>(objectHandle);
return object->GetLabel().c_str();
}
} // namespace dawn_native

View File

@ -22,10 +22,20 @@ namespace dawn_native {
ObjectBase::ObjectBase(DeviceBase* device) : RefCounted(kNotErrorPayload), mDevice(device) {
}
ObjectBase::ObjectBase(DeviceBase* device, const char* label) : ObjectBase(device) {
if (label) {
mLabel = label;
}
}
ObjectBase::ObjectBase(DeviceBase* device, ErrorTag)
: RefCounted(kErrorPayload), mDevice(device) {
}
const std::string& ObjectBase::GetLabel() {
return mLabel;
}
DeviceBase* ObjectBase::GetDevice() const {
return mDevice;
}
@ -34,4 +44,12 @@ namespace dawn_native {
return GetRefCountPayload() == kErrorPayload;
}
void ObjectBase::APISetLabel(const char* label) {
mLabel = label;
SetLabelImpl();
}
void ObjectBase::SetLabelImpl() {
}
} // namespace dawn_native

View File

@ -17,6 +17,8 @@
#include "common/RefCounted.h"
#include <string>
namespace dawn_native {
class DeviceBase;
@ -27,15 +29,21 @@ namespace dawn_native {
static constexpr ErrorTag kError = {};
ObjectBase(DeviceBase* device);
ObjectBase(DeviceBase* device, const char* label);
ObjectBase(DeviceBase* device, ErrorTag tag);
DeviceBase* GetDevice() const;
const std::string& GetLabel();
bool IsError() const;
protected:
~ObjectBase() override = default;
// Dawn API
void APISetLabel(const char* label);
private:
virtual void SetLabelImpl();
// TODO(dawn:840): Optimize memory footprint for objects that don't have labels.
std::string mLabel;
DeviceBase* mDevice;
};

View File

@ -433,7 +433,7 @@ namespace dawn_native {
TextureBase::TextureBase(DeviceBase* device,
const TextureDescriptor* descriptor,
TextureState state)
: ObjectBase(device),
: ObjectBase(device, descriptor->label),
mDimension(descriptor->dimension),
mFormat(device->GetValidInternalFormat(descriptor->format)),
mSize(descriptor->size),

View File

@ -212,6 +212,11 @@ namespace dawn_native {
{"disable_symbol_renaming",
"Disables the WGSL symbol renaming so that names are preserved.",
"https://crbug.com/dawn/1016"}},
{Toggle::UseUserDefinedLabelsInBackend,
{"use_user_defined_labels_in_backend",
"Enables calls to SetLabel to be forwarded to backend-specific APIs that label "
"objects.",
"https://crbug.com/dawn/840"}},
// Dummy comment to separate the }} so it is clearer what to copy-paste to add a toggle.
}};
} // anonymous namespace

View File

@ -58,6 +58,7 @@ namespace dawn_native {
ForceWGSLStep,
DisableWorkgroupInit,
DisableSymbolRenaming,
UseUserDefinedLabelsInBackend,
EnumCount,
InvalidEnum = EnumCount,

View File

@ -24,6 +24,7 @@
#include "dawn_native/d3d12/DeviceD3D12.h"
#include "dawn_native/d3d12/HeapD3D12.h"
#include "dawn_native/d3d12/ResidencyManagerD3D12.h"
#include "dawn_native/d3d12/UtilsD3D12.h"
namespace dawn_native { namespace d3d12 {
@ -155,7 +156,7 @@ namespace dawn_native { namespace d3d12 {
mResourceAllocation,
ToBackend(GetDevice())->AllocateMemory(heapType, resourceDescriptor, bufferUsage));
DAWN_TRY(mResourceAllocation.SetDebugName("Dawn_Buffer"));
SetLabelImpl();
// The buffers with mappedAtCreation == true will be initialized in
// BufferBase::MapAtCreation().
@ -446,6 +447,11 @@ namespace dawn_native { namespace d3d12 {
return {};
}
void Buffer::SetLabelImpl() {
SetDebugName(ToBackend(GetDevice()), mResourceAllocation.GetD3D12Resource(), "Dawn_Buffer",
GetLabel());
}
MaybeError Buffer::InitializeToZero(CommandRecordingContext* commandContext) {
ASSERT(GetDevice()->IsToggleEnabled(Toggle::LazyClearResourceOnFirstUse));
ASSERT(!IsDataInitialized());

View File

@ -48,6 +48,8 @@ namespace dawn_native { namespace d3d12 {
uint64_t size);
MaybeError EnsureDataInitializedAsDestination(CommandRecordingContext* commandContext,
const CopyTextureToBufferCmd* copy);
// Dawn API
void SetLabelImpl() override;
private:
Buffer(Device* device, const BufferDescriptor* descriptor);

View File

@ -40,11 +40,4 @@ namespace dawn_native { namespace d3d12 {
D3D12_GPU_VIRTUAL_ADDRESS ResourceHeapAllocation::GetGPUPointer() const {
return mResource->GetGPUVirtualAddress();
}
MaybeError ResourceHeapAllocation::SetDebugName(const char* name) {
DAWN_TRY(CheckHRESULT(
mResource->SetPrivateData(WKPDID_D3DDebugObjectName, std::strlen(name), name),
"ID3D12Resource::SetName"));
return {};
}
}} // namespace dawn_native::d3d12

View File

@ -35,7 +35,6 @@ namespace dawn_native { namespace d3d12 {
ResourceHeapAllocation& operator=(const ResourceHeapAllocation&) = default;
void Invalidate() override;
MaybeError SetDebugName(const char* name);
ID3D12Resource* GetD3D12Resource() const;
D3D12_GPU_VIRTUAL_ADDRESS GetGPUPointer() const;

View File

@ -17,6 +17,7 @@
#include "dawn_native/d3d12/DeviceD3D12.h"
#include "dawn_native/d3d12/HeapD3D12.h"
#include "dawn_native/d3d12/ResidencyManagerD3D12.h"
#include "dawn_native/d3d12/UtilsD3D12.h"
namespace dawn_native { namespace d3d12 {
@ -47,7 +48,7 @@ namespace dawn_native { namespace d3d12 {
DAWN_TRY(mDevice->GetResidencyManager()->LockAllocation(
ToBackend(mUploadHeap.GetResourceHeap())));
DAWN_TRY(mUploadHeap.SetDebugName("Dawn_StagingBuffer"));
SetDebugName(mDevice, GetResource(), "Dawn_StagingBuffer");
return CheckHRESULT(GetResource()->Map(0, nullptr, &mMappedPointer), "ID3D12Resource::Map");
}

View File

@ -482,7 +482,7 @@ namespace dawn_native { namespace d3d12 {
// memory management.
mResourceAllocation = {info, 0, std::move(d3d12Texture), nullptr};
DAWN_TRY(mResourceAllocation.SetDebugName("Dawn_ExternalTexture"));
SetLabelHelper("Dawn_ExternalTexture");
return {};
}
@ -521,7 +521,7 @@ namespace dawn_native { namespace d3d12 {
->AllocateMemory(D3D12_HEAP_TYPE_DEFAULT, resourceDescriptor,
D3D12_RESOURCE_STATE_COMMON));
DAWN_TRY(mResourceAllocation.SetDebugName("Dawn_InternalTexture"));
SetLabelImpl();
Device* device = ToBackend(GetDevice());
@ -544,7 +544,8 @@ namespace dawn_native { namespace d3d12 {
// memory management.
mResourceAllocation = {info, 0, std::move(d3d12Texture), nullptr};
DAWN_TRY(mResourceAllocation.SetDebugName("Dawn_SwapChainTexture"));
SetLabelHelper("Dawn_SwapChainTexture");
return {};
}
@ -1026,6 +1027,15 @@ namespace dawn_native { namespace d3d12 {
return {};
}
void Texture::SetLabelHelper(const char* prefix) {
SetDebugName(ToBackend(GetDevice()), mResourceAllocation.GetD3D12Resource(), prefix,
GetLabel());
}
void Texture::SetLabelImpl() {
SetLabelHelper("Dawn_InternalTexture");
}
void Texture::EnsureSubresourceContentInitialized(CommandRecordingContext* commandContext,
const SubresourceRange& range) {
if (!ToBackend(GetDevice())->IsToggleEnabled(Toggle::LazyClearResourceOnFirstUse)) {

View File

@ -98,8 +98,12 @@ namespace dawn_native { namespace d3d12 {
bool isSwapChainTexture);
MaybeError InitializeAsSwapChainTexture(ComPtr<ID3D12Resource> d3d12Texture);
void SetLabelHelper(const char* prefix);
// Dawn API
void SetLabelImpl() override;
void DestroyImpl() override;
MaybeError ClearTexture(CommandRecordingContext* commandContext,
const SubresourceRange& range,
TextureBase::ClearValue clearValue);

View File

@ -18,6 +18,8 @@
#include "dawn_native/Format.h"
#include "dawn_native/d3d12/BufferD3D12.h"
#include "dawn_native/d3d12/CommandRecordingContext.h"
#include "dawn_native/d3d12/D3D12Error.h"
#include "dawn_native/d3d12/DeviceD3D12.h"
#include <stringapiset.h>
@ -370,4 +372,16 @@ namespace dawn_native { namespace d3d12 {
}
}
void SetDebugName(Device* device, ID3D12Object* object, const char* prefix, std::string label) {
if (label.empty() || !device->IsToggleEnabled(Toggle::UseUserDefinedLabelsInBackend)) {
object->SetPrivateData(WKPDID_D3DDebugObjectName, strlen(prefix), prefix);
return;
}
std::string objectName = prefix;
objectName += "_";
objectName += label;
object->SetPrivateData(WKPDID_D3DDebugObjectName, objectName.length(), objectName.c_str());
}
}} // namespace dawn_native::d3d12

View File

@ -81,6 +81,11 @@ namespace dawn_native { namespace d3d12 {
Buffer* buffer,
const Extent3D& copySize);
void SetDebugName(Device* device,
ID3D12Object* object,
const char* prefix,
std::string label = "");
}} // namespace dawn_native::d3d12
#endif // DAWNNATIVE_D3D12_UTILSD3D12_H_

View File

@ -19,6 +19,7 @@
#include "dawn_native/vulkan/FencedDeleter.h"
#include "dawn_native/vulkan/ResourceHeapVk.h"
#include "dawn_native/vulkan/ResourceMemoryAllocatorVk.h"
#include "dawn_native/vulkan/UtilsVulkan.h"
#include "dawn_native/vulkan/VulkanError.h"
#include <cstring>
@ -229,6 +230,9 @@ namespace dawn_native { namespace vulkan {
ClearBuffer(recordingContext, 0, clearOffset, clearSize);
}
}
SetLabelImpl();
return {};
}
@ -374,6 +378,11 @@ namespace dawn_native { namespace vulkan {
}
}
void Buffer::SetLabelImpl() {
SetDebugName(ToBackend(GetDevice()), VK_OBJECT_TYPE_BUFFER,
reinterpret_cast<uint64_t&>(mHandle), "Dawn_Buffer", GetLabel());
}
void Buffer::InitializeToZero(CommandRecordingContext* recordingContext) {
ASSERT(GetDevice()->IsToggleEnabled(Toggle::LazyClearResourceOnFirstUse));
ASSERT(!IsDataInitialized());

View File

@ -49,6 +49,9 @@ namespace dawn_native { namespace vulkan {
void EnsureDataInitializedAsDestination(CommandRecordingContext* recordingContext,
const CopyTextureToBufferCmd* copy);
// Dawn API
void SetLabelImpl() override;
private:
~Buffer() override;
using BufferBase::BufferBase;

View File

@ -17,6 +17,7 @@
#include "dawn_native/vulkan/FencedDeleter.h"
#include "dawn_native/vulkan/ResourceHeapVk.h"
#include "dawn_native/vulkan/ResourceMemoryAllocatorVk.h"
#include "dawn_native/vulkan/UtilsVulkan.h"
#include "dawn_native/vulkan/VulkanError.h"
namespace dawn_native { namespace vulkan {
@ -57,6 +58,9 @@ namespace dawn_native { namespace vulkan {
return DAWN_INTERNAL_ERROR("Unable to map staging buffer.");
}
SetDebugName(mDevice, VK_OBJECT_TYPE_BUFFER, reinterpret_cast<uint64_t&>(mBuffer),
"Dawn_StagingBuffer");
return {};
}

View File

@ -577,6 +577,8 @@ namespace dawn_native { namespace vulkan {
GetAllSubresources(), TextureBase::ClearValue::NonZero));
}
SetLabelImpl();
return {};
}
@ -611,11 +613,15 @@ namespace dawn_native { namespace vulkan {
baseCreateInfo.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
DAWN_TRY_ASSIGN(mHandle, externalMemoryService->CreateImage(descriptor, baseCreateInfo));
SetLabelHelper("Dawn_ExternalTexture");
return {};
}
void Texture::InitializeForSwapChain(VkImage nativeImage) {
mHandle = nativeImage;
SetLabelHelper("Dawn_SwapChainTexture");
}
MaybeError Texture::BindExternalMemory(const ExternalImageDescriptorVk* descriptor,
@ -720,6 +726,15 @@ namespace dawn_native { namespace vulkan {
DestroyInternal();
}
void Texture::SetLabelHelper(const char* prefix) {
SetDebugName(ToBackend(GetDevice()), VK_OBJECT_TYPE_IMAGE,
reinterpret_cast<uint64_t&>(mHandle), prefix, GetLabel());
}
void Texture::SetLabelImpl() {
SetLabelHelper("Dawn_InternalTexture");
}
void Texture::DestroyImpl() {
if (GetTextureState() == TextureState::OwnedInternal) {
Device* device = ToBackend(GetDevice());

View File

@ -93,6 +93,11 @@ namespace dawn_native { namespace vulkan {
VkImageLayout* releasedOldLayout,
VkImageLayout* releasedNewLayout);
void SetLabelHelper(const char* prefix);
// Dawn API
void SetLabelImpl() override;
private:
~Texture() override;
Texture(Device* device, const TextureDescriptor* descriptor, TextureState state);

View File

@ -17,8 +17,10 @@
#include "common/Assert.h"
#include "dawn_native/EnumMaskIterator.h"
#include "dawn_native/Format.h"
#include "dawn_native/vulkan/DeviceVk.h"
#include "dawn_native/vulkan/Forward.h"
#include "dawn_native/vulkan/TextureVk.h"
#include "dawn_native/vulkan/VulkanError.h"
namespace dawn_native { namespace vulkan {
@ -162,4 +164,30 @@ namespace dawn_native { namespace vulkan {
return region;
}
void SetDebugName(Device* device,
VkObjectType objectType,
uint64_t objectHandle,
const char* prefix,
std::string label) {
if (device->GetGlobalInfo().HasExt(InstanceExt::DebugUtils)) {
VkDebugUtilsObjectNameInfoEXT objectNameInfo;
objectNameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
objectNameInfo.pNext = nullptr;
objectNameInfo.objectType = objectType;
objectNameInfo.objectHandle = objectHandle;
if (label.empty() || !device->IsToggleEnabled(Toggle::UseUserDefinedLabelsInBackend)) {
objectNameInfo.pObjectName = prefix;
device->fn.SetDebugUtilsObjectNameEXT(device->GetVkDevice(), &objectNameInfo);
return;
}
std::string objectName = prefix;
objectName += "_";
objectName += label;
objectNameInfo.pObjectName = objectName.c_str();
device->fn.SetDebugUtilsObjectNameEXT(device->GetVkDevice(), &objectNameInfo);
}
}
}} // namespace dawn_native::vulkan

View File

@ -21,6 +21,8 @@
namespace dawn_native { namespace vulkan {
class Device;
// A Helper type used to build a pNext chain of extension structs.
// Usage is:
// 1) Create instance, passing the address of the first struct in the
@ -99,6 +101,12 @@ namespace dawn_native { namespace vulkan {
const TextureCopy& textureCopy,
const Extent3D& copySize);
void SetDebugName(Device* device,
VkObjectType objectType,
uint64_t objectHandle,
const char* prefix,
std::string label = "");
}} // namespace dawn_native::vulkan
#endif // DAWNNATIVE_VULKAN_UTILSVULKAN_H_

View File

@ -248,6 +248,8 @@ namespace dawn_native {
ExternalImageExportInfo(ExternalImageType type);
};
DAWN_NATIVE_EXPORT const char* GetObjectLabelForTesting(void* objectHandle);
} // namespace dawn_native
#endif // DAWNNATIVE_DAWNNATIVE_H_

View File

@ -203,6 +203,7 @@ test("dawn_unittests") {
"unittests/validation/GetBindGroupLayoutValidationTests.cpp",
"unittests/validation/IndexBufferValidationTests.cpp",
"unittests/validation/InternalUsageValidationTests.cpp",
"unittests/validation/LabelTests.cpp",
"unittests/validation/MinimumBufferSizeValidationTests.cpp",
"unittests/validation/MultipleDeviceTests.cpp",
"unittests/validation/QueryValidationTests.cpp",

View File

@ -0,0 +1,86 @@
// Copyright 2021 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 WvecANTIES 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"
class LabelTest : public ValidationTest {};
TEST_F(LabelTest, Buffer) {
DAWN_SKIP_TEST_IF(UsesWire());
std::string label = "test";
wgpu::BufferDescriptor descriptor;
descriptor.size = 4;
descriptor.usage = wgpu::BufferUsage::Uniform;
// The label should be empty if one was not set.
{
wgpu::Buffer buffer = device.CreateBuffer(&descriptor);
std::string readbackLabel = dawn_native::GetObjectLabelForTesting(buffer.Get());
ASSERT_TRUE(readbackLabel.empty());
}
// Test setting a label through API
{
wgpu::Buffer buffer = device.CreateBuffer(&descriptor);
buffer.SetLabel(label.c_str());
std::string readbackLabel = dawn_native::GetObjectLabelForTesting(buffer.Get());
ASSERT_EQ(label, readbackLabel);
}
// Test setting a label through the descriptor.
{
descriptor.label = label.c_str();
wgpu::Buffer buffer = device.CreateBuffer(&descriptor);
std::string readbackLabel = dawn_native::GetObjectLabelForTesting(buffer.Get());
ASSERT_EQ(label, readbackLabel);
}
}
TEST_F(LabelTest, Texture) {
DAWN_SKIP_TEST_IF(UsesWire());
std::string label = "test";
wgpu::TextureDescriptor descriptor;
descriptor.size.width = 1;
descriptor.size.height = 1;
descriptor.size.depthOrArrayLayers = 1;
descriptor.mipLevelCount = 1;
descriptor.sampleCount = 1;
descriptor.dimension = wgpu::TextureDimension::e2D;
descriptor.format = wgpu::TextureFormat::RGBA8Uint;
descriptor.usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TextureBinding;
// The label should be empty if one was not set.
{
wgpu::Texture texture = device.CreateTexture(&descriptor);
std::string readbackLabel = dawn_native::GetObjectLabelForTesting(texture.Get());
ASSERT_TRUE(readbackLabel.empty());
}
// Test setting a label through API
{
wgpu::Texture texture = device.CreateTexture(&descriptor);
texture.SetLabel(label.c_str());
std::string readbackLabel = dawn_native::GetObjectLabelForTesting(texture.Get());
ASSERT_EQ(label, readbackLabel);
}
// Test setting a label through the descriptor.
{
descriptor.label = label.c_str();
wgpu::Texture texture = device.CreateTexture(&descriptor);
std::string readbackLabel = dawn_native::GetObjectLabelForTesting(texture.Get());
ASSERT_EQ(label, readbackLabel);
}
}