Add basic support for VK_EXT_debug_utils

This first implementation ignores all optional functionality, so
this is a very bare-bones implementation of VK_EXT_debug_utils.

Bug: b/119321052
Change-Id: I8ef189b957b6d1b433846de945b7852c3d6e8190
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/46968
Presubmit-Ready: Alexis Hétu <sugoi@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Vulkan/BUILD.gn b/src/Vulkan/BUILD.gn
index ec6cd2b..c3f503b 100644
--- a/src/Vulkan/BUILD.gn
+++ b/src/Vulkan/BUILD.gn
@@ -64,6 +64,7 @@
     "VkCommandBuffer.hpp",
     "VkCommandPool.hpp",
     "VkConfig.hpp",
+    "VkDebugUtilsMessenger.hpp",
     "VkDescriptorPool.hpp",
     "VkDescriptorSet.hpp",
     "VkDescriptorSetLayout.hpp",
@@ -111,6 +112,7 @@
     "VkBufferView.cpp",
     "VkCommandBuffer.cpp",
     "VkCommandPool.cpp",
+    "VkDebugUtilsMessenger.cpp",
     "VkDescriptorPool.cpp",
     "VkDescriptorSet.cpp",
     "VkDescriptorSetLayout.cpp",
diff --git a/src/Vulkan/CMakeLists.txt b/src/Vulkan/CMakeLists.txt
index 9944fa3..bbd53cd 100644
--- a/src/Vulkan/CMakeLists.txt
+++ b/src/Vulkan/CMakeLists.txt
@@ -31,6 +31,8 @@
     VkCommandPool.cpp
     VkCommandPool.hpp
     VkConfig.hpp
+    VkDebugUtilsMessenger.cpp
+    VkDebugUtilsMessenger.hpp
     VkDescriptorPool.cpp
     VkDescriptorPool.hpp
     VkDescriptorSet.cpp
diff --git a/src/Vulkan/VkCommandBuffer.cpp b/src/Vulkan/VkCommandBuffer.cpp
index ab9fb26..87ec112 100644
--- a/src/Vulkan/VkCommandBuffer.cpp
+++ b/src/Vulkan/VkCommandBuffer.cpp
@@ -1785,6 +1785,21 @@
 	addCommand<::CmdDrawIndexedIndirect>(buffer, offset, drawCount, stride);
 }
 
+void CommandBuffer::beginDebugUtilsLabel(const VkDebugUtilsLabelEXT *pLabelInfo)
+{
+	// Optional debug label region
+}
+
+void CommandBuffer::endDebugUtilsLabel()
+{
+	// Close debug label region opened with beginDebugUtilsLabel()
+}
+
+void CommandBuffer::insertDebugUtilsLabel(const VkDebugUtilsLabelEXT *pLabelInfo)
+{
+	// Optional single debug label
+}
+
 void CommandBuffer::submit(CommandBuffer::ExecutionState &executionState)
 {
 	// Perform recorded work
diff --git a/src/Vulkan/VkCommandBuffer.hpp b/src/Vulkan/VkCommandBuffer.hpp
index 10e2b06..9654514 100644
--- a/src/Vulkan/VkCommandBuffer.hpp
+++ b/src/Vulkan/VkCommandBuffer.hpp
@@ -133,6 +133,10 @@
 	void drawIndirect(Buffer *buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride);
 	void drawIndexedIndirect(Buffer *buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride);
 
+	void beginDebugUtilsLabel(const VkDebugUtilsLabelEXT *pLabelInfo);
+	void endDebugUtilsLabel();
+	void insertDebugUtilsLabel(const VkDebugUtilsLabelEXT *pLabelInfo);
+
 	// TODO(sugoi): Move ExecutionState out of CommandBuffer (possibly into Device)
 	struct ExecutionState
 	{
diff --git a/src/Vulkan/VkDebugUtilsMessenger.cpp b/src/Vulkan/VkDebugUtilsMessenger.cpp
new file mode 100644
index 0000000..777b7e6
--- /dev/null
+++ b/src/Vulkan/VkDebugUtilsMessenger.cpp
@@ -0,0 +1,41 @@
+// Copyright 2020 The SwiftShader Authors. All Rights Reserved.
+//
+// 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 "VkDebugUtilsMessenger.hpp"
+
+namespace vk {
+
+DebugUtilsMessenger::DebugUtilsMessenger(const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo, void *mem)
+    : messageSeverity(pCreateInfo->messageSeverity)
+    , messageType(pCreateInfo->messageType)
+    , pfnUserCallback(pCreateInfo->pfnUserCallback)
+    , pUserData(pCreateInfo->pUserData)
+{
+}
+
+void DebugUtilsMessenger::destroy(const VkAllocationCallbacks *pAllocator)
+{
+}
+
+size_t DebugUtilsMessenger::ComputeRequiredAllocationSize(const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo)
+{
+	return 0;
+}
+
+void DebugUtilsMessenger::submitMessage(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes, const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData)
+{
+	(*pfnUserCallback)(messageSeverity, messageTypes, pCallbackData, pUserData);
+}
+
+}  // namespace vk
diff --git a/src/Vulkan/VkDebugUtilsMessenger.hpp b/src/Vulkan/VkDebugUtilsMessenger.hpp
new file mode 100644
index 0000000..10e34e6
--- /dev/null
+++ b/src/Vulkan/VkDebugUtilsMessenger.hpp
@@ -0,0 +1,48 @@
+// Copyright 2020 The SwiftShader Authors. All Rights Reserved.
+//
+// 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.
+
+#ifndef VK_DEBUG_UTILS_MESSENGER_HPP_
+#define VK_DEBUG_UTILS_MESSENGER_HPP_
+
+#include "VkObject.hpp"
+
+namespace vk {
+
+class DeviceMemory;
+
+class DebugUtilsMessenger : public Object<DebugUtilsMessenger, VkDebugUtilsMessengerEXT>
+{
+public:
+	DebugUtilsMessenger(const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo, void *mem);
+	void destroy(const VkAllocationCallbacks *pAllocator);
+
+	static size_t ComputeRequiredAllocationSize(const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo);
+
+	void submitMessage(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes, const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData);
+
+private:
+	VkDebugUtilsMessageSeverityFlagsEXT messageSeverity = (VkDebugUtilsMessageSeverityFlagsEXT)0;
+	VkDebugUtilsMessageTypeFlagsEXT messageType = (VkDebugUtilsMessageTypeFlagsEXT)0;
+	PFN_vkDebugUtilsMessengerCallbackEXT pfnUserCallback = nullptr;
+	void *pUserData = nullptr;
+};
+
+static inline DebugUtilsMessenger *Cast(VkDebugUtilsMessengerEXT object)
+{
+	return DebugUtilsMessenger::Cast(object);
+}
+
+}  // namespace vk
+
+#endif  // VK_DEBUG_UTILS_MESSENGER_HPP_
diff --git a/src/Vulkan/VkDestroy.hpp b/src/Vulkan/VkDestroy.hpp
index 4b057a1..272ca14 100644
--- a/src/Vulkan/VkDestroy.hpp
+++ b/src/Vulkan/VkDestroy.hpp
@@ -16,6 +16,7 @@
 #include "VkBufferView.hpp"
 #include "VkCommandBuffer.hpp"
 #include "VkCommandPool.hpp"
+#include "VkDebugUtilsMessenger.hpp"
 #include "VkDevice.hpp"
 #include "VkDeviceMemory.hpp"
 #include "VkEvent.hpp"
diff --git a/src/Vulkan/VkDevice.cpp b/src/Vulkan/VkDevice.cpp
index 879b4e2..1c2f4e4 100644
--- a/src/Vulkan/VkDevice.cpp
+++ b/src/Vulkan/VkDevice.cpp
@@ -313,4 +313,16 @@
 	samplerIndexer->remove(samplerState);
 }
 
+VkResult Device::setDebugUtilsObjectName(const VkDebugUtilsObjectNameInfoEXT *pNameInfo)
+{
+	// Optionally maps user-friendly name to an object
+	return VK_SUCCESS;
+}
+
+VkResult Device::setDebugUtilsObjectTag(const VkDebugUtilsObjectTagInfoEXT *pTagInfo)
+{
+	// Optionally attach arbitrary data to an object
+	return VK_SUCCESS;
+}
+
 }  // namespace vk
diff --git a/src/Vulkan/VkDevice.hpp b/src/Vulkan/VkDevice.hpp
index 8d41499..f75f33f 100644
--- a/src/Vulkan/VkDevice.hpp
+++ b/src/Vulkan/VkDevice.hpp
@@ -160,6 +160,9 @@
 #endif  // ENABLE_VK_DEBUGGER
 	}
 
+	VkResult setDebugUtilsObjectName(const VkDebugUtilsObjectNameInfoEXT *pNameInfo);
+	VkResult setDebugUtilsObjectTag(const VkDebugUtilsObjectTagInfoEXT *pTagInfo);
+
 private:
 	PhysicalDevice *const physicalDevice = nullptr;
 	Queue *const queues = nullptr;
diff --git a/src/Vulkan/VkGetProcAddress.cpp b/src/Vulkan/VkGetProcAddress.cpp
index 81da95a..6819526 100644
--- a/src/Vulkan/VkGetProcAddress.cpp
+++ b/src/Vulkan/VkGetProcAddress.cpp
@@ -83,6 +83,18 @@
 	MAKE_VULKAN_INSTANCE_ENTRY(vkGetPhysicalDeviceQueueFamilyProperties2KHR),
 	MAKE_VULKAN_INSTANCE_ENTRY(vkGetPhysicalDeviceMemoryProperties2KHR),
 	MAKE_VULKAN_INSTANCE_ENTRY(vkGetPhysicalDeviceSparseImageFormatProperties2KHR),
+	// VK_EXT_debug_utils
+	MAKE_VULKAN_INSTANCE_ENTRY(vkCmdBeginDebugUtilsLabelEXT),
+	MAKE_VULKAN_INSTANCE_ENTRY(vkCmdEndDebugUtilsLabelEXT),
+	MAKE_VULKAN_INSTANCE_ENTRY(vkCmdInsertDebugUtilsLabelEXT),
+	MAKE_VULKAN_INSTANCE_ENTRY(vkCreateDebugUtilsMessengerEXT),
+	MAKE_VULKAN_INSTANCE_ENTRY(vkDestroyDebugUtilsMessengerEXT),
+	MAKE_VULKAN_INSTANCE_ENTRY(vkQueueBeginDebugUtilsLabelEXT),
+	MAKE_VULKAN_INSTANCE_ENTRY(vkQueueEndDebugUtilsLabelEXT),
+	MAKE_VULKAN_INSTANCE_ENTRY(vkQueueInsertDebugUtilsLabelEXT),
+	MAKE_VULKAN_INSTANCE_ENTRY(vkSetDebugUtilsObjectNameEXT),
+	MAKE_VULKAN_INSTANCE_ENTRY(vkSetDebugUtilsObjectTagEXT),
+	MAKE_VULKAN_INSTANCE_ENTRY(vkSubmitDebugUtilsMessageEXT),
 #ifndef __ANDROID__
 	// VK_KHR_surface
 	MAKE_VULKAN_INSTANCE_ENTRY(vkDestroySurfaceKHR),
@@ -261,6 +273,15 @@
 	MAKE_VULKAN_DEVICE_ENTRY(vkDestroyDescriptorUpdateTemplate),
 	MAKE_VULKAN_DEVICE_ENTRY(vkUpdateDescriptorSetWithTemplate),
 	MAKE_VULKAN_DEVICE_ENTRY(vkGetDescriptorSetLayoutSupport),
+	// Device level VK_EXT_debug_utils functions
+	MAKE_VULKAN_DEVICE_ENTRY(vkCmdBeginDebugUtilsLabelEXT),
+	MAKE_VULKAN_DEVICE_ENTRY(vkCmdEndDebugUtilsLabelEXT),
+	MAKE_VULKAN_DEVICE_ENTRY(vkCmdInsertDebugUtilsLabelEXT),
+	MAKE_VULKAN_DEVICE_ENTRY(vkQueueBeginDebugUtilsLabelEXT),
+	MAKE_VULKAN_DEVICE_ENTRY(vkQueueEndDebugUtilsLabelEXT),
+	MAKE_VULKAN_DEVICE_ENTRY(vkQueueInsertDebugUtilsLabelEXT),
+	MAKE_VULKAN_DEVICE_ENTRY(vkSetDebugUtilsObjectNameEXT),
+	MAKE_VULKAN_DEVICE_ENTRY(vkSetDebugUtilsObjectTagEXT),
 #ifdef __ANDROID__
 	MAKE_VULKAN_DEVICE_ENTRY(vkGetSwapchainGrallocUsageANDROID),
 	MAKE_VULKAN_DEVICE_ENTRY(vkGetSwapchainGrallocUsage2ANDROID),
diff --git a/src/Vulkan/VkInstance.cpp b/src/Vulkan/VkInstance.cpp
index 14f7142..3d78b8c 100644
--- a/src/Vulkan/VkInstance.cpp
+++ b/src/Vulkan/VkInstance.cpp
@@ -13,12 +13,14 @@
 // limitations under the License.
 
 #include "VkInstance.hpp"
+#include "VkDebugUtilsMessenger.hpp"
 #include "VkDestroy.hpp"
 
 namespace vk {
 
-Instance::Instance(const VkInstanceCreateInfo *pCreateInfo, void *mem, VkPhysicalDevice physicalDevice)
+Instance::Instance(const VkInstanceCreateInfo *pCreateInfo, void *mem, VkPhysicalDevice physicalDevice, DebugUtilsMessenger *messenger)
     : physicalDevice(physicalDevice)
+    , messenger(messenger)
 {
 }
 
@@ -68,4 +70,12 @@
 	return VK_SUCCESS;
 }
 
+void Instance::submitDebugUtilsMessage(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes, const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData)
+{
+	if(messenger)
+	{
+		messenger->submitMessage(messageSeverity, messageTypes, pCallbackData);
+	}
+}
+
 }  // namespace vk
diff --git a/src/Vulkan/VkInstance.hpp b/src/Vulkan/VkInstance.hpp
index 53d6764..129bde3 100644
--- a/src/Vulkan/VkInstance.hpp
+++ b/src/Vulkan/VkInstance.hpp
@@ -19,12 +19,14 @@
 
 namespace vk {
 
+class DebugUtilsMessenger;
+
 class Instance
 {
 public:
 	static constexpr VkSystemAllocationScope GetAllocationScope() { return VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE; }
 
-	Instance(const VkInstanceCreateInfo *pCreateInfo, void *mem, VkPhysicalDevice physicalDevice);
+	Instance(const VkInstanceCreateInfo *pCreateInfo, void *mem, VkPhysicalDevice physicalDevice, DebugUtilsMessenger *messenger);
 	void destroy(const VkAllocationCallbacks *pAllocator);
 
 	static size_t ComputeRequiredAllocationSize(const VkInstanceCreateInfo *) { return 0; }
@@ -33,8 +35,11 @@
 	VkResult getPhysicalDeviceGroups(uint32_t *pPhysicalDeviceGroupCount,
 	                                 VkPhysicalDeviceGroupProperties *pPhysicalDeviceGroupProperties) const;
 
+	void submitDebugUtilsMessage(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes, const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData);
+
 private:
 	VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
+	DebugUtilsMessenger *messenger = nullptr;
 };
 
 using DispatchableInstance = DispatchableObject<Instance, VkInstance>;
diff --git a/src/Vulkan/VkQueue.cpp b/src/Vulkan/VkQueue.cpp
index 136eafd..ccb8cfe 100644
--- a/src/Vulkan/VkQueue.cpp
+++ b/src/Vulkan/VkQueue.cpp
@@ -250,4 +250,19 @@
 }
 #endif
 
+void Queue::beginDebugUtilsLabel(const VkDebugUtilsLabelEXT *pLabelInfo)
+{
+	// Optional debug label region
+}
+
+void Queue::endDebugUtilsLabel()
+{
+	// Close debug label region opened with beginDebugUtilsLabel()
+}
+
+void Queue::insertDebugUtilsLabel(const VkDebugUtilsLabelEXT *pLabelInfo)
+{
+	// Optional single debug label
+}
+
 }  // namespace vk
diff --git a/src/Vulkan/VkQueue.hpp b/src/Vulkan/VkQueue.hpp
index af80df8..a436c8a 100644
--- a/src/Vulkan/VkQueue.hpp
+++ b/src/Vulkan/VkQueue.hpp
@@ -56,6 +56,10 @@
 	VkResult present(const VkPresentInfoKHR *presentInfo);
 #endif
 
+	void beginDebugUtilsLabel(const VkDebugUtilsLabelEXT *pLabelInfo);
+	void endDebugUtilsLabel();
+	void insertDebugUtilsLabel(const VkDebugUtilsLabelEXT *pLabelInfo);
+
 private:
 	struct Task
 	{
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp
index 7062103..2d11099 100644
--- a/src/Vulkan/libVulkan.cpp
+++ b/src/Vulkan/libVulkan.cpp
@@ -17,6 +17,7 @@
 #include "VkCommandBuffer.hpp"
 #include "VkCommandPool.hpp"
 #include "VkConfig.hpp"
+#include "VkDebugUtilsMessenger.hpp"
 #include "VkDescriptorPool.hpp"
 #include "VkDescriptorSetLayout.hpp"
 #include "VkDescriptorUpdateTemplate.hpp"
@@ -303,6 +304,7 @@
 	{ VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME, VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION },
 	{ VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME, VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_SPEC_VERSION },
 	{ VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_SPEC_VERSION },
+	{ VK_EXT_DEBUG_UTILS_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_SPEC_VERSION },
 #ifndef __ANDROID__
 	{ VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_SURFACE_SPEC_VERSION },
 #endif
@@ -411,11 +413,22 @@
 		}
 	}
 
+	VkDebugUtilsMessengerEXT messenger = { VK_NULL_HANDLE };
 	if(pCreateInfo->pNext)
 	{
 		const VkBaseInStructure *createInfo = reinterpret_cast<const VkBaseInStructure *>(pCreateInfo->pNext);
 		switch(createInfo->sType)
 		{
+			case VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT:
+			{
+				const VkDebugUtilsMessengerCreateInfoEXT *debugUtilsMessengerCreateInfoEXT = reinterpret_cast<const VkDebugUtilsMessengerCreateInfoEXT *>(createInfo);
+				VkResult result = vk::DebugUtilsMessenger::Create(pAllocator, debugUtilsMessengerCreateInfoEXT, &messenger);
+				if(result != VK_SUCCESS)
+				{
+					return result;
+				}
+			}
+			break;
 			case VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO:
 				// According to the Vulkan spec, section 2.7.2. Implicit Valid Usage:
 				// "The values VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO and
@@ -435,12 +448,14 @@
 	VkResult result = vk::DispatchablePhysicalDevice::Create(pAllocator, pCreateInfo, &physicalDevice);
 	if(result != VK_SUCCESS)
 	{
+		vk::destroy(messenger, pAllocator);
 		return result;
 	}
 
-	result = vk::DispatchableInstance::Create(pAllocator, pCreateInfo, pInstance, physicalDevice);
+	result = vk::DispatchableInstance::Create(pAllocator, pCreateInfo, pInstance, physicalDevice, vk::Cast(messenger));
 	if(result != VK_SUCCESS)
 	{
+		vk::destroy(messenger, pAllocator);
 		vk::destroy(physicalDevice, pAllocator);
 		return result;
 	}
@@ -3339,12 +3354,104 @@
 
 VKAPI_ATTR void VKAPI_CALL vkCmdSetLineStippleEXT(VkCommandBuffer commandBuffer, uint32_t lineStippleFactor, uint16_t lineStipplePattern)
 {
-	TRACE("(VkCommandBuffer commandBuffer = %p, uint32_t lineStippleFactor = %u, uint16_t lineStipplePattern = %u",
+	TRACE("(VkCommandBuffer commandBuffer = %p, uint32_t lineStippleFactor = %u, uint16_t lineStipplePattern = %u)",
 	      commandBuffer, lineStippleFactor, lineStipplePattern);
 
 	UNSUPPORTED("VkPhysicalDeviceLineRasterizationFeaturesEXT::stippled*Lines");
 }
 
+VKAPI_ATTR void VKAPI_CALL vkCmdBeginDebugUtilsLabelEXT(VkCommandBuffer commandBuffer, const VkDebugUtilsLabelEXT *pLabelInfo)
+{
+	TRACE("(VkCommandBuffer commandBuffer = %p, const VkDebugUtilsLabelEXT* pLabelInfo = %p)",
+	      commandBuffer, pLabelInfo);
+
+	vk::Cast(commandBuffer)->beginDebugUtilsLabel(pLabelInfo);
+}
+
+VKAPI_ATTR void VKAPI_CALL vkCmdEndDebugUtilsLabelEXT(VkCommandBuffer commandBuffer)
+{
+	TRACE("(VkCommandBuffer commandBuffer = %p)", commandBuffer);
+
+	vk::Cast(commandBuffer)->endDebugUtilsLabel();
+}
+
+VKAPI_ATTR void VKAPI_CALL vkCmdInsertDebugUtilsLabelEXT(VkCommandBuffer commandBuffer, const VkDebugUtilsLabelEXT *pLabelInfo)
+{
+	TRACE("(VkCommandBuffer commandBuffer = %p, const VkDebugUtilsLabelEXT* pLabelInfo = %p)",
+	      commandBuffer, pLabelInfo);
+
+	vk::Cast(commandBuffer)->insertDebugUtilsLabel(pLabelInfo);
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDebugUtilsMessengerEXT *pMessenger)
+{
+	TRACE("(VkInstance instance = %p, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo = %p, const VkAllocationCallbacks* pAllocator = %p, VkDebugUtilsMessengerEXT* pMessenger = %p)",
+	      instance, pCreateInfo, pAllocator, pMessenger);
+
+	if(pCreateInfo->flags != 0)
+	{
+		// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
+		UNSUPPORTED("pCreateInfo->flags %d", int(pCreateInfo->flags));
+	}
+
+	return vk::DebugUtilsMessenger::Create(pAllocator, pCreateInfo, pMessenger);
+}
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger, const VkAllocationCallbacks *pAllocator)
+{
+	TRACE("(VkInstance instance = %p, VkDebugUtilsMessengerEXT messenger = %p, const VkAllocationCallbacks* pAllocator = %p)",
+	      instance, static_cast<void *>(messenger), pAllocator);
+
+	vk::destroy(messenger, pAllocator);
+}
+
+VKAPI_ATTR void VKAPI_CALL vkQueueBeginDebugUtilsLabelEXT(VkQueue queue, const VkDebugUtilsLabelEXT *pLabelInfo)
+{
+	TRACE("(VkQueue queue = %p, const VkDebugUtilsLabelEXT* pLabelInfo = %p)",
+	      queue, pLabelInfo);
+
+	vk::Cast(queue)->beginDebugUtilsLabel(pLabelInfo);
+}
+
+VKAPI_ATTR void VKAPI_CALL vkQueueEndDebugUtilsLabelEXT(VkQueue queue)
+{
+	TRACE("(VkQueue queue = %p)", queue);
+
+	vk::Cast(queue)->endDebugUtilsLabel();
+}
+
+VKAPI_ATTR void VKAPI_CALL vkQueueInsertDebugUtilsLabelEXT(VkQueue queue, const VkDebugUtilsLabelEXT *pLabelInfo)
+{
+	TRACE("(VkQueue queue = %p, const VkDebugUtilsLabelEXT* pLabelInfo = %p)",
+	      queue, pLabelInfo);
+
+	vk::Cast(queue)->insertDebugUtilsLabel(pLabelInfo);
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL vkSetDebugUtilsObjectNameEXT(VkDevice device, const VkDebugUtilsObjectNameInfoEXT *pNameInfo)
+{
+	TRACE("(VkDevice device = %p, const VkDebugUtilsObjectNameInfoEXT* pNameInfo = %p)",
+	      device, pNameInfo);
+
+	return vk::Cast(device)->setDebugUtilsObjectName(pNameInfo);
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL vkSetDebugUtilsObjectTagEXT(VkDevice device, const VkDebugUtilsObjectTagInfoEXT *pTagInfo)
+{
+	TRACE("(VkDevice device = %p, const VkDebugUtilsObjectTagInfoEXT* pTagInfo = %p)",
+	      device, pTagInfo);
+
+	return vk::Cast(device)->setDebugUtilsObjectTag(pTagInfo);
+}
+
+VKAPI_ATTR void VKAPI_CALL vkSubmitDebugUtilsMessageEXT(VkInstance instance, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes, const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData)
+{
+	TRACE("(VkInstance instance = %p, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity = %d, VkDebugUtilsMessageTypeFlagsEXT messageTypes = %d, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData = %p)",
+	      instance, messageSeverity, messageTypes, pCallbackData);
+
+	vk::Cast(instance)->submitDebugUtilsMessage(messageSeverity, messageTypes, pCallbackData);
+}
+
 #ifdef VK_USE_PLATFORM_XCB_KHR
 VKAPI_ATTR VkResult VKAPI_CALL vkCreateXcbSurfaceKHR(VkInstance instance, const VkXcbSurfaceCreateInfoKHR *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface)
 {
diff --git a/src/Vulkan/vk_swiftshader.def b/src/Vulkan/vk_swiftshader.def
index c803e64..aba9696 100644
--- a/src/Vulkan/vk_swiftshader.def
+++ b/src/Vulkan/vk_swiftshader.def
@@ -201,6 +201,18 @@
 	vkGetPhysicalDeviceQueueFamilyProperties2KHR

 	vkGetPhysicalDeviceMemoryProperties2KHR

 	vkGetPhysicalDeviceSparseImageFormatProperties2KHR

+	; VK_EXT_debug_utils

+	vkCmdBeginDebugUtilsLabelEXT

+	vkCmdEndDebugUtilsLabelEXT

+	vkCmdInsertDebugUtilsLabelEXT

+	vkCreateDebugUtilsMessengerEXT

+	vkDestroyDebugUtilsMessengerEXT

+	vkQueueBeginDebugUtilsLabelEXT

+	vkQueueEndDebugUtilsLabelEXT

+	vkQueueInsertDebugUtilsLabelEXT

+	vkSetDebugUtilsObjectNameEXT

+	vkSetDebugUtilsObjectTagEXT

+	vkSubmitDebugUtilsMessageEXT

 	; VK_KHR_maintenance1

 	vkTrimCommandPoolKHR

 	; VK_KHR_maintenance3

diff --git a/src/Vulkan/vk_swiftshader.lds b/src/Vulkan/vk_swiftshader.lds
index fedd8c7..4344c41 100644
--- a/src/Vulkan/vk_swiftshader.lds
+++ b/src/Vulkan/vk_swiftshader.lds
@@ -201,6 +201,18 @@
 	vkGetPhysicalDeviceQueueFamilyProperties2KHR;
 	vkGetPhysicalDeviceMemoryProperties2KHR;
 	vkGetPhysicalDeviceSparseImageFormatProperties2KHR;
+	# VK_EXT_debug_utils;
+	vkCmdBeginDebugUtilsLabelEXT;
+	vkCmdEndDebugUtilsLabelEXT;
+	vkCmdInsertDebugUtilsLabelEXT;
+	vkCreateDebugUtilsMessengerEXT;
+	vkDestroyDebugUtilsMessengerEXT;
+	vkQueueBeginDebugUtilsLabelEXT;
+	vkQueueEndDebugUtilsLabelEXT;
+	vkQueueInsertDebugUtilsLabelEXT;
+	vkSetDebugUtilsObjectNameEXT;
+	vkSetDebugUtilsObjectTagEXT;
+	vkSubmitDebugUtilsMessageEXT;
 	# VK_KHR_maintenance1;
 	vkTrimCommandPoolKHR;
 	# VK_KHR_maintenance3;