Implement initial VK_EXT_debug_utils changes

This affects the loader, scripts, and layers and introduces the
changes to support the VK_EXT_debug_utils extension.

Change-Id: Ia5336f63e85b00f1e59416c06aacd4ae331fd692
diff --git a/layers/core_validation.cpp b/layers/core_validation.cpp
index 1f1ec3b..51223dc 100644
--- a/layers/core_validation.cpp
+++ b/layers/core_validation.cpp
@@ -144,7 +144,8 @@
 struct instance_layer_data {
     VkInstance instance = VK_NULL_HANDLE;
     debug_report_data *report_data = nullptr;
-    std::vector<VkDebugReportCallbackEXT> logging_callback;
+    vector<VkDebugReportCallbackEXT> logging_callback;
+    vector<VkDebugUtilsMessengerEXT> logging_messenger;
     VkLayerInstanceDispatchTable dispatch_table;
 
     CALL_STATE vkEnumeratePhysicalDevicesState = UNCALLED;
@@ -2032,7 +2033,9 @@
 }
 
 static void init_core_validation(instance_layer_data *instance_data, const VkAllocationCallbacks *pAllocator) {
-    layer_debug_actions(instance_data->report_data, instance_data->logging_callback, pAllocator, "lunarg_core_validation");
+    layer_debug_report_actions(instance_data->report_data, instance_data->logging_callback, pAllocator, "lunarg_core_validation");
+    layer_debug_messenger_actions(instance_data->report_data, instance_data->logging_messenger, pAllocator,
+                                  "lunarg_core_validation");
 }
 
 // For the given ValidationCheck enum, set all relevant instance disabled flags to true
@@ -2070,7 +2073,7 @@
     instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(*pInstance), instance_layer_data_map);
     instance_data->instance = *pInstance;
     layer_init_instance_dispatch_table(*pInstance, &instance_data->dispatch_table, fpGetInstanceProcAddr);
-    instance_data->report_data = debug_report_create_instance(
+    instance_data->report_data = debug_utils_create_instance(
         &instance_data->dispatch_table, *pInstance, pCreateInfo->enabledExtensionCount, pCreateInfo->ppEnabledExtensionNames);
 
     instance_data->api_version = instance_data->extensions.InitFromInstanceCreateInfo(
@@ -2098,13 +2101,18 @@
 
     lock_guard_t lock(global_lock);
     // Clean up logging callback, if any
+    while (instance_data->logging_messenger.size() > 0) {
+        VkDebugUtilsMessengerEXT messenger = instance_data->logging_messenger.back();
+        layer_destroy_messenger_callback(instance_data->report_data, messenger, pAllocator);
+        instance_data->logging_messenger.pop_back();
+    }
     while (instance_data->logging_callback.size() > 0) {
         VkDebugReportCallbackEXT callback = instance_data->logging_callback.back();
-        layer_destroy_msg_callback(instance_data->report_data, callback, pAllocator);
+        layer_destroy_report_callback(instance_data->report_data, callback, pAllocator);
         instance_data->logging_callback.pop_back();
     }
 
-    layer_debug_report_destroy_instance(instance_data->report_data);
+    layer_debug_utils_destroy_instance(instance_data->report_data);
     FreeLayerDataPtr(key, instance_layer_data_map);
 }
 
@@ -2277,7 +2285,7 @@
     // Save PhysicalDevice handle
     device_data->physical_device = gpu;
 
-    device_data->report_data = layer_debug_report_create_device(instance_data->report_data, *pDevice);
+    device_data->report_data = layer_debug_utils_create_device(instance_data->report_data, *pDevice);
 
     // Get physical device limits for this device
     instance_data->dispatch_table.GetPhysicalDeviceProperties(gpu, &(device_data->phys_dev_properties.properties));
@@ -2342,7 +2350,7 @@
     // Queues persist until device is destroyed
     dev_data->queueMap.clear();
     // Report any memory leaks
-    layer_debug_report_destroy_device(device);
+    layer_debug_utils_destroy_device(device);
     lock.unlock();
 
 #if DISPATCH_MAP_DEBUG
@@ -11713,6 +11721,107 @@
     return result;
 }
 
+// VK_EXT_debug_utils commands
+VKAPI_ATTR VkResult VKAPI_CALL SetDebugUtilsObjectNameEXT(VkDevice device, const VkDebugUtilsObjectNameInfoEXT *pNameInfo) {
+    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    VkResult result = VK_SUCCESS;
+    if (pNameInfo->pObjectName) {
+        dev_data->report_data->debugUtilsObjectNameMap->insert(
+            std::make_pair<uint64_t, std::string>((uint64_t &&) pNameInfo->objectHandle, pNameInfo->pObjectName));
+    } else {
+        dev_data->report_data->debugUtilsObjectNameMap->erase(pNameInfo->objectHandle);
+    }
+    if (nullptr != dev_data->dispatch_table.SetDebugUtilsObjectNameEXT) {
+        result = dev_data->dispatch_table.SetDebugUtilsObjectNameEXT(device, pNameInfo);
+    }
+    return result;
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL SetDebugUtilsObjectTagEXT(VkDevice device, const VkDebugUtilsObjectTagInfoEXT *pTagInfo) {
+    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    VkResult result = VK_SUCCESS;
+    if (nullptr != dev_data->dispatch_table.SetDebugUtilsObjectTagEXT) {
+        result = dev_data->dispatch_table.SetDebugUtilsObjectTagEXT(device, pTagInfo);
+    }
+    return result;
+}
+
+VKAPI_ATTR void VKAPI_CALL QueueBeginDebugUtilsLabelEXT(VkQueue queue, const VkDebugUtilsLabelEXT *pLabelInfo) {
+    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
+    BeginQueueDebugUtilsLabel(dev_data->report_data, queue, pLabelInfo);
+    if (nullptr != dev_data->dispatch_table.QueueBeginDebugUtilsLabelEXT) {
+        dev_data->dispatch_table.QueueBeginDebugUtilsLabelEXT(queue, pLabelInfo);
+    }
+}
+
+VKAPI_ATTR void VKAPI_CALL QueueEndDebugUtilsLabelEXT(VkQueue queue) {
+    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
+    if (nullptr != dev_data->dispatch_table.QueueEndDebugUtilsLabelEXT) {
+        dev_data->dispatch_table.QueueEndDebugUtilsLabelEXT(queue);
+    }
+    EndQueueDebugUtilsLabel(dev_data->report_data, queue);
+}
+
+VKAPI_ATTR void VKAPI_CALL QueueInsertDebugUtilsLabelEXT(VkQueue queue, const VkDebugUtilsLabelEXT *pLabelInfo) {
+    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
+    InsertQueueDebugUtilsLabel(dev_data->report_data, queue, pLabelInfo);
+    if (nullptr != dev_data->dispatch_table.QueueInsertDebugUtilsLabelEXT) {
+        dev_data->dispatch_table.QueueInsertDebugUtilsLabelEXT(queue, pLabelInfo);
+    }
+}
+
+VKAPI_ATTR void VKAPI_CALL CmdBeginDebugUtilsLabelEXT(VkCommandBuffer commandBuffer, const VkDebugUtilsLabelEXT *pLabelInfo) {
+    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    BeginCmdDebugUtilsLabel(dev_data->report_data, commandBuffer, pLabelInfo);
+    if (nullptr != dev_data->dispatch_table.CmdBeginDebugUtilsLabelEXT) {
+        dev_data->dispatch_table.CmdBeginDebugUtilsLabelEXT(commandBuffer, pLabelInfo);
+    }
+}
+
+VKAPI_ATTR void VKAPI_CALL CmdEndDebugUtilsLabelEXT(VkCommandBuffer commandBuffer) {
+    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    if (nullptr != dev_data->dispatch_table.CmdEndDebugUtilsLabelEXT) {
+        dev_data->dispatch_table.CmdEndDebugUtilsLabelEXT(commandBuffer);
+    }
+    EndCmdDebugUtilsLabel(dev_data->report_data, commandBuffer);
+}
+
+VKAPI_ATTR void VKAPI_CALL CmdInsertDebugUtilsLabelEXT(VkCommandBuffer commandBuffer, const VkDebugUtilsLabelEXT *pLabelInfo) {
+    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    InsertCmdDebugUtilsLabel(dev_data->report_data, commandBuffer, pLabelInfo);
+    if (nullptr != dev_data->dispatch_table.CmdInsertDebugUtilsLabelEXT) {
+        dev_data->dispatch_table.CmdInsertDebugUtilsLabelEXT(commandBuffer, pLabelInfo);
+    }
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL CreateDebugUtilsMessengerEXT(VkInstance instance,
+                                                            const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,
+                                                            const VkAllocationCallbacks *pAllocator,
+                                                            VkDebugUtilsMessengerEXT *pMessenger) {
+    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
+    VkResult result = instance_data->dispatch_table.CreateDebugUtilsMessengerEXT(instance, pCreateInfo, pAllocator, pMessenger);
+
+    if (VK_SUCCESS == result) {
+        result = layer_create_messenger_callback(instance_data->report_data, false, pCreateInfo, pAllocator, pMessenger);
+    }
+    return result;
+}
+
+VKAPI_ATTR void VKAPI_CALL DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger,
+                                                         const VkAllocationCallbacks *pAllocator) {
+    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
+    instance_data->dispatch_table.DestroyDebugUtilsMessengerEXT(instance, messenger, pAllocator);
+    layer_destroy_messenger_callback(instance_data->report_data, messenger, pAllocator);
+}
+
+VKAPI_ATTR void VKAPI_CALL SubmitDebugUtilsMessageEXT(VkInstance instance, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
+                                                      VkDebugUtilsMessageTypeFlagsEXT messageTypes,
+                                                      const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData) {
+    instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
+    instance_data->dispatch_table.SubmitDebugUtilsMessageEXT(instance, messageSeverity, messageTypes, pCallbackData);
+}
+
+// VK_EXT_debug_report commands
 VKAPI_ATTR VkResult VKAPI_CALL CreateDebugReportCallbackEXT(VkInstance instance,
                                                             const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
                                                             const VkAllocationCallbacks *pAllocator,
@@ -11721,7 +11830,7 @@
     VkResult res = instance_data->dispatch_table.CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
     if (VK_SUCCESS == res) {
         lock_guard_t lock(global_lock);
-        res = layer_create_msg_callback(instance_data->report_data, false, pCreateInfo, pAllocator, pMsgCallback);
+        res = layer_create_report_callback(instance_data->report_data, false, pCreateInfo, pAllocator, pMsgCallback);
     }
     return res;
 }
@@ -11731,7 +11840,7 @@
     instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
     instance_data->dispatch_table.DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);
     lock_guard_t lock(global_lock);
-    layer_destroy_msg_callback(instance_data->report_data, msgCallback, pAllocator);
+    layer_destroy_report_callback(instance_data->report_data, msgCallback, pAllocator);
 }
 
 VKAPI_ATTR void VKAPI_CALL DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags,
@@ -12388,6 +12497,17 @@
     {"vkMergeValidationCachesEXT", (void *)MergeValidationCachesEXT},
     {"vkCmdSetDiscardRectangleEXT", (void *)CmdSetDiscardRectangleEXT},
     {"vkCmdSetSampleLocationsEXT", (void *)CmdSetSampleLocationsEXT},
+    {"vkSetDebugUtilsObjectNameEXT", (void *)SetDebugUtilsObjectNameEXT},
+    {"vkSetDebugUtilsObjectTagEXT", (void *)SetDebugUtilsObjectTagEXT},
+    {"vkQueueBeginDebugUtilsLabelEXT", (void *)QueueBeginDebugUtilsLabelEXT},
+    {"vkQueueEndDebugUtilsLabelEXT", (void *)QueueEndDebugUtilsLabelEXT},
+    {"vkQueueInsertDebugUtilsLabelEXT", (void *)QueueInsertDebugUtilsLabelEXT},
+    {"vkCmdBeginDebugUtilsLabelEXT", (void *)CmdBeginDebugUtilsLabelEXT},
+    {"vkCmdEndDebugUtilsLabelEXT", (void *)CmdEndDebugUtilsLabelEXT},
+    {"vkCmdInsertDebugUtilsLabelEXT", (void *)CmdInsertDebugUtilsLabelEXT},
+    {"vkCreateDebugUtilsMessengerEXT", (void *)CreateDebugUtilsMessengerEXT},
+    {"vkDestroyDebugUtilsMessengerEXT", (void *)DestroyDebugUtilsMessengerEXT},
+    {"vkSubmitDebugUtilsMessageEXT", (void *)SubmitDebugUtilsMessageEXT},
 };
 
 VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice device, const char *funcName) {
diff --git a/layers/object_tracker.h b/layers/object_tracker.h
index d9fdf8b..5a6f545 100644
--- a/layers/object_tracker.h
+++ b/layers/object_tracker.h
@@ -35,7 +35,6 @@
 #include "vk_layer_table.h"
 #include "vk_object_types.h"
 #include "vulkan/vk_layer.h"
-#include "vk_object_types.h"
 #include "vk_enum_string_helper.h"
 #include "vk_layer_extension_utils.h"
 #include "vk_layer_table.h"
@@ -96,11 +95,15 @@
 
     debug_report_data *report_data;
     std::vector<VkDebugReportCallbackEXT> logging_callback;
+    std::vector<VkDebugUtilsMessengerEXT> logging_messenger;
     // The following are for keeping track of the temporary callbacks that can
     // be used in vkCreateInstance and vkDestroyInstance:
-    uint32_t num_tmp_callbacks;
-    VkDebugReportCallbackCreateInfoEXT *tmp_dbg_create_infos;
-    VkDebugReportCallbackEXT *tmp_callbacks;
+    uint32_t num_tmp_report_callbacks;
+    VkDebugReportCallbackCreateInfoEXT *tmp_report_create_infos;
+    VkDebugReportCallbackEXT *tmp_report_callbacks;
+    uint32_t num_tmp_debug_messengers;
+    VkDebugUtilsMessengerCreateInfoEXT *tmp_messenger_create_infos;
+    VkDebugUtilsMessengerEXT *tmp_debug_messengers;
 
     std::vector<VkQueueFamilyProperties> queue_family_properties;
 
@@ -119,9 +122,12 @@
           num_objects{},
           num_total_objects(0),
           report_data(nullptr),
-          num_tmp_callbacks(0),
-          tmp_dbg_create_infos(nullptr),
-          tmp_callbacks(nullptr),
+          num_tmp_report_callbacks(0),
+          tmp_report_create_infos(nullptr),
+          tmp_report_callbacks(nullptr),
+          num_tmp_debug_messengers(0),
+          tmp_messenger_create_infos(nullptr),
+          tmp_debug_messengers(nullptr),
           object_map{},
           dispatch_table{} {
         object_map.resize(kVulkanObjectTypeMax + 1);
diff --git a/layers/object_tracker_utils.cpp b/layers/object_tracker_utils.cpp
index c9573dd..177c145 100644
--- a/layers/object_tracker_utils.cpp
+++ b/layers/object_tracker_utils.cpp
@@ -32,7 +32,8 @@
 uint32_t loader_layer_if_version = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
 
 void InitObjectTracker(layer_data *my_data, const VkAllocationCallbacks *pAllocator) {
-    layer_debug_actions(my_data->report_data, my_data->logging_callback, pAllocator, "lunarg_object_tracker");
+    layer_debug_report_actions(my_data->report_data, my_data->logging_callback, pAllocator, "lunarg_object_tracker");
+    layer_debug_messenger_actions(my_data->report_data, my_data->logging_messenger, pAllocator, "lunarg_object_tracker");
 }
 
 // Add new queue to head of global queue list
@@ -328,12 +329,13 @@
     layer_data *instance_data = GetLayerDataPtr(key, layer_data_map);
 
     // Enable the temporary callback(s) here to catch cleanup issues:
-    bool callback_setup = false;
-    if (instance_data->num_tmp_callbacks > 0) {
-        if (!layer_enable_tmp_callbacks(instance_data->report_data, instance_data->num_tmp_callbacks,
-                                        instance_data->tmp_dbg_create_infos, instance_data->tmp_callbacks)) {
-            callback_setup = true;
-        }
+    if (instance_data->num_tmp_debug_messengers > 0) {
+        layer_enable_tmp_debug_messengers(instance_data->report_data, instance_data->num_tmp_debug_messengers,
+                                          instance_data->tmp_messenger_create_infos, instance_data->tmp_debug_messengers);
+    }
+    if (instance_data->num_tmp_report_callbacks > 0) {
+        layer_enable_tmp_report_callbacks(instance_data->report_data, instance_data->num_tmp_report_callbacks,
+                                          instance_data->tmp_report_create_infos, instance_data->tmp_report_callbacks);
     }
 
     // TODO: The instance handle can not be validated here. The loader will likely have to validate it.
@@ -375,22 +377,32 @@
     pInstanceTable->DestroyInstance(instance, pAllocator);
 
     // Disable and cleanup the temporary callback(s):
-    if (callback_setup) {
-        layer_disable_tmp_callbacks(instance_data->report_data, instance_data->num_tmp_callbacks, instance_data->tmp_callbacks);
+    layer_disable_tmp_debug_messengers(instance_data->report_data, instance_data->num_tmp_debug_messengers,
+                                       instance_data->tmp_debug_messengers);
+    layer_disable_tmp_report_callbacks(instance_data->report_data, instance_data->num_tmp_report_callbacks,
+                                       instance_data->tmp_report_callbacks);
+    if (instance_data->num_tmp_debug_messengers > 0) {
+        layer_free_tmp_debug_messengers(instance_data->tmp_messenger_create_infos, instance_data->tmp_debug_messengers);
+        instance_data->num_tmp_debug_messengers = 0;
     }
-    if (instance_data->num_tmp_callbacks > 0) {
-        layer_free_tmp_callbacks(instance_data->tmp_dbg_create_infos, instance_data->tmp_callbacks);
-        instance_data->num_tmp_callbacks = 0;
+    if (instance_data->num_tmp_report_callbacks > 0) {
+        layer_free_tmp_report_callbacks(instance_data->tmp_report_create_infos, instance_data->tmp_report_callbacks);
+        instance_data->num_tmp_report_callbacks = 0;
     }
 
     // Clean up logging callback, if any
+    while (instance_data->logging_messenger.size() > 0) {
+        VkDebugUtilsMessengerEXT messenger = instance_data->logging_messenger.back();
+        layer_destroy_messenger_callback(instance_data->report_data, messenger, pAllocator);
+        instance_data->logging_messenger.pop_back();
+    }
     while (instance_data->logging_callback.size() > 0) {
         VkDebugReportCallbackEXT callback = instance_data->logging_callback.back();
-        layer_destroy_msg_callback(instance_data->report_data, callback, pAllocator);
+        layer_destroy_report_callback(instance_data->report_data, callback, pAllocator);
         instance_data->logging_callback.pop_back();
     }
 
-    layer_debug_report_destroy_instance(instance_data->report_data);
+    layer_debug_utils_destroy_instance(instance_data->report_data);
     FreeLayerDataPtr(key, layer_data_map);
 
     lock.unlock();
@@ -572,7 +584,7 @@
     VkResult result = pInstanceTable->CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pCallback);
     if (VK_SUCCESS == result) {
         layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map);
-        result = layer_create_msg_callback(instance_data->report_data, false, pCreateInfo, pAllocator, pCallback);
+        result = layer_create_report_callback(instance_data->report_data, false, pCreateInfo, pAllocator, pCallback);
         CreateObject(instance, *pCallback, kVulkanObjectTypeDebugReportCallbackEXT, pAllocator);
     }
     return result;
@@ -583,7 +595,7 @@
     VkLayerInstanceDispatchTable *pInstanceTable = get_dispatch_table(ot_instance_table_map, instance);
     pInstanceTable->DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);
     layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map);
-    layer_destroy_msg_callback(instance_data->report_data, msgCallback, pAllocator);
+    layer_destroy_report_callback(instance_data->report_data, msgCallback, pAllocator);
     DestroyObject(instance, msgCallback, kVulkanObjectTypeDebugReportCallbackEXT, pAllocator, VALIDATION_ERROR_242009b4,
                   VALIDATION_ERROR_242009b6);
 }
@@ -595,7 +607,159 @@
     pInstanceTable->DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, pMsg);
 }
 
-static const VkExtensionProperties instance_extensions[] = {{VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION}};
+// VK_EXT_debug_utils commands
+VKAPI_ATTR VkResult VKAPI_CALL SetDebugUtilsObjectNameEXT(VkDevice device, const VkDebugUtilsObjectNameInfoEXT *pNameInfo) {
+    bool skip = VK_FALSE;
+    std::unique_lock<std::mutex> lock(global_lock);
+    skip |= ValidateObject(device, device, kVulkanObjectTypeDevice, false, VALIDATION_ERROR_UNDEFINED, VALIDATION_ERROR_UNDEFINED);
+    lock.unlock();
+    if (skip) {
+        return VK_ERROR_VALIDATION_FAILED_EXT;
+    }
+    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    if (pNameInfo->pObjectName) {
+        dev_data->report_data->debugUtilsObjectNameMap->insert(
+            std::make_pair<uint64_t, std::string>((uint64_t &&) pNameInfo->objectHandle, pNameInfo->pObjectName));
+    } else {
+        dev_data->report_data->debugUtilsObjectNameMap->erase(pNameInfo->objectHandle);
+    }
+    VkResult result = dev_data->dispatch_table.SetDebugUtilsObjectNameEXT(device, pNameInfo);
+    return result;
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL SetDebugUtilsObjectTagEXT(VkDevice device, const VkDebugUtilsObjectTagInfoEXT *pTagInfo) {
+    bool skip = VK_FALSE;
+    std::unique_lock<std::mutex> lock(global_lock);
+    skip |= ValidateObject(device, device, kVulkanObjectTypeDevice, false, VALIDATION_ERROR_UNDEFINED, VALIDATION_ERROR_UNDEFINED);
+    lock.unlock();
+    if (skip) {
+        return VK_ERROR_VALIDATION_FAILED_EXT;
+    }
+    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    VkResult result = dev_data->dispatch_table.SetDebugUtilsObjectTagEXT(device, pTagInfo);
+    return result;
+}
+
+VKAPI_ATTR void VKAPI_CALL QueueBeginDebugUtilsLabelEXT(VkQueue queue, const VkDebugUtilsLabelEXT *pLabelInfo) {
+    bool skip = VK_FALSE;
+    std::unique_lock<std::mutex> lock(global_lock);
+    skip |= ValidateObject(queue, queue, kVulkanObjectTypeQueue, false, VALIDATION_ERROR_UNDEFINED, VALIDATION_ERROR_UNDEFINED);
+    lock.unlock();
+    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
+    if (!skip) {
+        BeginQueueDebugUtilsLabel(dev_data->report_data, queue, pLabelInfo);
+        if (dev_data->dispatch_table.QueueBeginDebugUtilsLabelEXT) {
+            dev_data->dispatch_table.QueueBeginDebugUtilsLabelEXT(queue, pLabelInfo);
+        }
+    }
+}
+
+VKAPI_ATTR void VKAPI_CALL QueueEndDebugUtilsLabelEXT(VkQueue queue) {
+    bool skip = VK_FALSE;
+    std::unique_lock<std::mutex> lock(global_lock);
+    skip |= ValidateObject(queue, queue, kVulkanObjectTypeQueue, false, VALIDATION_ERROR_UNDEFINED, VALIDATION_ERROR_UNDEFINED);
+    lock.unlock();
+    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
+    if (!skip) {
+        if (dev_data->dispatch_table.QueueEndDebugUtilsLabelEXT) {
+            dev_data->dispatch_table.QueueEndDebugUtilsLabelEXT(queue);
+        }
+        EndQueueDebugUtilsLabel(dev_data->report_data, queue);
+    }
+}
+
+VKAPI_ATTR void VKAPI_CALL QueueInsertDebugUtilsLabelEXT(VkQueue queue, const VkDebugUtilsLabelEXT *pLabelInfo) {
+    bool skip = VK_FALSE;
+    std::unique_lock<std::mutex> lock(global_lock);
+    skip |= ValidateObject(queue, queue, kVulkanObjectTypeQueue, false, VALIDATION_ERROR_UNDEFINED, VALIDATION_ERROR_UNDEFINED);
+    lock.unlock();
+    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
+    if (!skip) {
+        InsertQueueDebugUtilsLabel(dev_data->report_data, queue, pLabelInfo);
+        if (dev_data->dispatch_table.QueueInsertDebugUtilsLabelEXT) {
+            dev_data->dispatch_table.QueueInsertDebugUtilsLabelEXT(queue, pLabelInfo);
+        }
+    }
+}
+
+VKAPI_ATTR void VKAPI_CALL CmdBeginDebugUtilsLabelEXT(VkCommandBuffer commandBuffer, const VkDebugUtilsLabelEXT *pLabelInfo) {
+    bool skip = VK_FALSE;
+    std::unique_lock<std::mutex> lock(global_lock);
+    skip |= ValidateObject(commandBuffer, commandBuffer, kVulkanObjectTypeCommandBuffer, false, VALIDATION_ERROR_UNDEFINED,
+                           VALIDATION_ERROR_UNDEFINED);
+    lock.unlock();
+    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    if (!skip) {
+        BeginCmdDebugUtilsLabel(dev_data->report_data, commandBuffer, pLabelInfo);
+        if (dev_data->dispatch_table.CmdBeginDebugUtilsLabelEXT) {
+            dev_data->dispatch_table.CmdBeginDebugUtilsLabelEXT(commandBuffer, pLabelInfo);
+        }
+    }
+}
+
+VKAPI_ATTR void VKAPI_CALL CmdEndDebugUtilsLabelEXT(VkCommandBuffer commandBuffer) {
+    bool skip = VK_FALSE;
+    std::unique_lock<std::mutex> lock(global_lock);
+    skip |= ValidateObject(commandBuffer, commandBuffer, kVulkanObjectTypeCommandBuffer, false, VALIDATION_ERROR_UNDEFINED,
+                           VALIDATION_ERROR_UNDEFINED);
+    lock.unlock();
+    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    if (!skip) {
+        if (dev_data->dispatch_table.CmdEndDebugUtilsLabelEXT) {
+            dev_data->dispatch_table.CmdEndDebugUtilsLabelEXT(commandBuffer);
+        }
+        EndCmdDebugUtilsLabel(dev_data->report_data, commandBuffer);
+    }
+}
+
+VKAPI_ATTR void VKAPI_CALL CmdInsertDebugUtilsLabelEXT(VkCommandBuffer commandBuffer, const VkDebugUtilsLabelEXT *pLabelInfo) {
+    bool skip = VK_FALSE;
+    std::unique_lock<std::mutex> lock(global_lock);
+    skip |= ValidateObject(commandBuffer, commandBuffer, kVulkanObjectTypeCommandBuffer, false, VALIDATION_ERROR_UNDEFINED,
+                           VALIDATION_ERROR_UNDEFINED);
+    lock.unlock();
+    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map);
+    if (!skip) {
+        InsertCmdDebugUtilsLabel(dev_data->report_data, commandBuffer, pLabelInfo);
+        if (dev_data->dispatch_table.CmdInsertDebugUtilsLabelEXT) {
+            dev_data->dispatch_table.CmdInsertDebugUtilsLabelEXT(commandBuffer, pLabelInfo);
+        }
+    }
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL CreateDebugUtilsMessengerEXT(VkInstance instance,
+                                                            const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,
+                                                            const VkAllocationCallbacks *pAllocator,
+                                                            VkDebugUtilsMessengerEXT *pMessenger) {
+    VkLayerInstanceDispatchTable *pInstanceTable = get_dispatch_table(ot_instance_table_map, instance);
+    VkResult result = pInstanceTable->CreateDebugUtilsMessengerEXT(instance, pCreateInfo, pAllocator, pMessenger);
+    if (VK_SUCCESS == result) {
+        layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map);
+        result = layer_create_messenger_callback(instance_data->report_data, false, pCreateInfo, pAllocator, pMessenger);
+        CreateObject(instance, *pMessenger, kVulkanObjectTypeDebugUtilsMessengerEXT, pAllocator);
+    }
+    return result;
+}
+
+VKAPI_ATTR void VKAPI_CALL DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger,
+                                                         const VkAllocationCallbacks *pAllocator) {
+    VkLayerInstanceDispatchTable *pInstanceTable = get_dispatch_table(ot_instance_table_map, instance);
+    pInstanceTable->DestroyDebugUtilsMessengerEXT(instance, messenger, pAllocator);
+    layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map);
+    layer_destroy_messenger_callback(instance_data->report_data, messenger, pAllocator);
+    DestroyObject(instance, messenger, kVulkanObjectTypeDebugUtilsMessengerEXT, pAllocator, VALIDATION_ERROR_UNDEFINED,
+                  VALIDATION_ERROR_UNDEFINED);
+}
+
+VKAPI_ATTR void VKAPI_CALL SubmitDebugUtilsMessageEXT(VkInstance instance, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
+                                                      VkDebugUtilsMessageTypeFlagsEXT messageTypes,
+                                                      const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData) {
+    VkLayerInstanceDispatchTable *pInstanceTable = get_dispatch_table(ot_instance_table_map, instance);
+    pInstanceTable->SubmitDebugUtilsMessageEXT(instance, messageSeverity, messageTypes, pCallbackData);
+}
+
+static const VkExtensionProperties instance_extensions[] = {{VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION},
+                                                            {VK_EXT_DEBUG_UTILS_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_SPEC_VERSION}};
 
 static const VkLayerProperties globalLayerProps = {"VK_LAYER_LUNARG_object_tracker",
                                                    VK_LAYER_API_VERSION,  // specVersion
@@ -656,7 +820,7 @@
     }
 
     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(*pDevice), layer_data_map);
-    device_data->report_data = layer_debug_report_create_device(phy_dev_data->report_data, *pDevice);
+    device_data->report_data = layer_debug_utils_create_device(phy_dev_data->report_data, *pDevice);
     layer_init_device_dispatch_table(*pDevice, &device_data->dispatch_table, fpGetDeviceProcAddr);
 
     // Add link back to physDev
@@ -779,11 +943,13 @@
 
     // Look for one or more debug report create info structures, and copy the
     // callback(s) for each one found (for use by vkDestroyInstance)
-    layer_copy_tmp_callbacks(pCreateInfo->pNext, &instance_data->num_tmp_callbacks, &instance_data->tmp_dbg_create_infos,
-                             &instance_data->tmp_callbacks);
+    layer_copy_tmp_debug_messengers(pCreateInfo->pNext, &instance_data->num_tmp_debug_messengers,
+                                    &instance_data->tmp_messenger_create_infos, &instance_data->tmp_debug_messengers);
+    layer_copy_tmp_report_callbacks(pCreateInfo->pNext, &instance_data->num_tmp_report_callbacks,
+                                    &instance_data->tmp_report_create_infos, &instance_data->tmp_report_callbacks);
 
-    instance_data->report_data = debug_report_create_instance(pInstanceTable, *pInstance, pCreateInfo->enabledExtensionCount,
-                                                              pCreateInfo->ppEnabledExtensionNames);
+    instance_data->report_data = debug_utils_create_instance(pInstanceTable, *pInstance, pCreateInfo->enabledExtensionCount,
+                                                             pCreateInfo->ppEnabledExtensionNames);
 
     InitObjectTracker(instance_data, pAllocator);
 
diff --git a/layers/parameter_validation.h b/layers/parameter_validation.h
index 49ff279..d03152c 100644
--- a/layers/parameter_validation.h
+++ b/layers/parameter_validation.h
@@ -61,12 +61,17 @@
 
     debug_report_data *report_data = nullptr;
     std::vector<VkDebugReportCallbackEXT> logging_callback;
+    std::vector<VkDebugUtilsMessengerEXT> logging_messenger;
 
     // The following are for keeping track of the temporary callbacks that can
     // be used in vkCreateInstance and vkDestroyInstance:
-    uint32_t num_tmp_callbacks = 0;
-    VkDebugReportCallbackCreateInfoEXT *tmp_dbg_create_infos = nullptr;
-    VkDebugReportCallbackEXT *tmp_callbacks = nullptr;
+    uint32_t num_tmp_report_callbacks = 0;
+    VkDebugReportCallbackCreateInfoEXT *tmp_report_create_infos = nullptr;
+    VkDebugReportCallbackEXT *tmp_report_callbacks = nullptr;
+    uint32_t num_tmp_debug_messengers = 0;
+    VkDebugUtilsMessengerCreateInfoEXT *tmp_messenger_create_infos = nullptr;
+    VkDebugUtilsMessengerEXT *tmp_debug_messengers = nullptr;
+
     InstanceExtensions extensions = {};
     VkLayerInstanceDispatchTable dispatch_table = {};
     uint32_t api_version;
diff --git a/layers/parameter_validation_utils.cpp b/layers/parameter_validation_utils.cpp
index b818159..3dfd27c 100644
--- a/layers/parameter_validation_utils.cpp
+++ b/layers/parameter_validation_utils.cpp
@@ -79,6 +79,12 @@
                                                                 VkDebugReportCallbackEXT *pMsgCallback);
 extern bool parameter_validation_vkDestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT msgCallback,
                                                                  const VkAllocationCallbacks *pAllocator);
+extern bool parameter_validation_vkCreateDebugUtilsMessengerEXT(VkInstance instance,
+                                                                const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,
+                                                                const VkAllocationCallbacks *pAllocator,
+                                                                VkDebugUtilsMessengerEXT *pMessenger);
+extern bool parameter_validation_vkDestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger,
+                                                                 const VkAllocationCallbacks *pAllocator);
 extern bool parameter_validation_vkCreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo *pCreateInfo,
                                                      const VkAllocationCallbacks *pAllocator, VkCommandPool *pCommandPool);
 extern bool parameter_validation_vkCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
@@ -96,10 +102,14 @@
 void InitializeManualParameterValidationFunctionPointers(void);
 
 static void init_parameter_validation(instance_layer_data *instance_data, const VkAllocationCallbacks *pAllocator) {
-    layer_debug_actions(instance_data->report_data, instance_data->logging_callback, pAllocator, "lunarg_parameter_validation");
+    layer_debug_report_actions(instance_data->report_data, instance_data->logging_callback, pAllocator,
+                               "lunarg_parameter_validation");
+    layer_debug_messenger_actions(instance_data->report_data, instance_data->logging_messenger, pAllocator,
+                                  "lunarg_parameter_validation");
 }
 
-static const VkExtensionProperties instance_extensions[] = {{VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION}};
+static const VkExtensionProperties instance_extensions[] = {{VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION},
+                                                            {VK_EXT_DEBUG_UTILS_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_SPEC_VERSION}};
 
 static const VkLayerProperties global_layer = {
     "VK_LAYER_LUNARG_parameter_validation",
@@ -216,21 +226,39 @@
         layer_init_instance_dispatch_table(*pInstance, &my_instance_data->dispatch_table, fpGetInstanceProcAddr);
         my_instance_data->instance = *pInstance;
         my_instance_data->report_data =
-            debug_report_create_instance(&my_instance_data->dispatch_table, *pInstance, pCreateInfo->enabledExtensionCount,
-                pCreateInfo->ppEnabledExtensionNames);
+            debug_utils_create_instance(&my_instance_data->dispatch_table, *pInstance, pCreateInfo->enabledExtensionCount,
+                                        pCreateInfo->ppEnabledExtensionNames);
 
         // Look for one or more debug report create info structures
         // and setup a callback(s) for each one found.
-        if (!layer_copy_tmp_callbacks(pCreateInfo->pNext, &my_instance_data->num_tmp_callbacks,
-            &my_instance_data->tmp_dbg_create_infos, &my_instance_data->tmp_callbacks)) {
-            if (my_instance_data->num_tmp_callbacks > 0) {
+        if (!layer_copy_tmp_debug_messengers(pCreateInfo->pNext, &my_instance_data->num_tmp_debug_messengers,
+                                             &my_instance_data->tmp_messenger_create_infos,
+                                             &my_instance_data->tmp_debug_messengers)) {
+            if (my_instance_data->num_tmp_debug_messengers > 0) {
                 // Setup the temporary callback(s) here to catch early issues:
-                if (layer_enable_tmp_callbacks(my_instance_data->report_data, my_instance_data->num_tmp_callbacks,
-                    my_instance_data->tmp_dbg_create_infos, my_instance_data->tmp_callbacks)) {
+                if (layer_enable_tmp_debug_messengers(my_instance_data->report_data, my_instance_data->num_tmp_debug_messengers,
+                                                      my_instance_data->tmp_messenger_create_infos,
+                                                      my_instance_data->tmp_debug_messengers)) {
                     // Failure of setting up one or more of the callback.
                     // Therefore, clean up and don't use those callbacks:
-                    layer_free_tmp_callbacks(my_instance_data->tmp_dbg_create_infos, my_instance_data->tmp_callbacks);
-                    my_instance_data->num_tmp_callbacks = 0;
+                    layer_free_tmp_debug_messengers(my_instance_data->tmp_messenger_create_infos,
+                                                    my_instance_data->tmp_debug_messengers);
+                    my_instance_data->num_tmp_debug_messengers = 0;
+                }
+            }
+        }
+        if (!layer_copy_tmp_report_callbacks(pCreateInfo->pNext, &my_instance_data->num_tmp_report_callbacks,
+                                             &my_instance_data->tmp_report_create_infos, &my_instance_data->tmp_report_callbacks)) {
+            if (my_instance_data->num_tmp_report_callbacks > 0) {
+                // Setup the temporary callback(s) here to catch early issues:
+                if (layer_enable_tmp_report_callbacks(my_instance_data->report_data, my_instance_data->num_tmp_report_callbacks,
+                                                      my_instance_data->tmp_report_create_infos,
+                                                      my_instance_data->tmp_report_callbacks)) {
+                    // Failure of setting up one or more of the callback.
+                    // Therefore, clean up and don't use those callbacks:
+                    layer_free_tmp_report_callbacks(my_instance_data->tmp_report_create_infos,
+                                                    my_instance_data->tmp_report_callbacks);
+                    my_instance_data->num_tmp_report_callbacks = 0;
                 }
             }
         }
@@ -269,9 +297,13 @@
         }
 
         // Disable the tmp callbacks:
-        if (my_instance_data->num_tmp_callbacks > 0) {
-            layer_disable_tmp_callbacks(my_instance_data->report_data, my_instance_data->num_tmp_callbacks,
-                                        my_instance_data->tmp_callbacks);
+        if (my_instance_data->num_tmp_debug_messengers > 0) {
+            layer_disable_tmp_debug_messengers(my_instance_data->report_data, my_instance_data->num_tmp_debug_messengers,
+                                               my_instance_data->tmp_debug_messengers);
+        }
+        if (my_instance_data->num_tmp_report_callbacks > 0) {
+            layer_disable_tmp_report_callbacks(my_instance_data->report_data, my_instance_data->num_tmp_report_callbacks,
+                                               my_instance_data->tmp_report_callbacks);
         }
     }
 
@@ -286,9 +318,15 @@
 
     // Enable the temporary callback(s) here to catch vkDestroyInstance issues:
     bool callback_setup = false;
-    if (instance_data->num_tmp_callbacks > 0) {
-        if (!layer_enable_tmp_callbacks(instance_data->report_data, instance_data->num_tmp_callbacks,
-                                        instance_data->tmp_dbg_create_infos, instance_data->tmp_callbacks)) {
+    if (instance_data->num_tmp_debug_messengers > 0) {
+        if (!layer_enable_tmp_debug_messengers(instance_data->report_data, instance_data->num_tmp_debug_messengers,
+                                               instance_data->tmp_messenger_create_infos, instance_data->tmp_debug_messengers)) {
+            callback_setup = true;
+        }
+    }
+    if (instance_data->num_tmp_report_callbacks > 0) {
+        if (!layer_enable_tmp_report_callbacks(instance_data->report_data, instance_data->num_tmp_report_callbacks,
+                                               instance_data->tmp_report_create_infos, instance_data->tmp_report_callbacks)) {
             callback_setup = true;
         }
     }
@@ -297,24 +335,36 @@
 
     // Disable and cleanup the temporary callback(s):
     if (callback_setup) {
-        layer_disable_tmp_callbacks(instance_data->report_data, instance_data->num_tmp_callbacks, instance_data->tmp_callbacks);
+        layer_disable_tmp_debug_messengers(instance_data->report_data, instance_data->num_tmp_debug_messengers,
+                                           instance_data->tmp_debug_messengers);
+        layer_disable_tmp_report_callbacks(instance_data->report_data, instance_data->num_tmp_report_callbacks,
+                                           instance_data->tmp_report_callbacks);
     }
-    if (instance_data->num_tmp_callbacks > 0) {
-        layer_free_tmp_callbacks(instance_data->tmp_dbg_create_infos, instance_data->tmp_callbacks);
-        instance_data->num_tmp_callbacks = 0;
+    if (instance_data->num_tmp_debug_messengers > 0) {
+        layer_free_tmp_debug_messengers(instance_data->tmp_messenger_create_infos, instance_data->tmp_debug_messengers);
+        instance_data->num_tmp_debug_messengers = 0;
+    }
+    if (instance_data->num_tmp_report_callbacks > 0) {
+        layer_free_tmp_report_callbacks(instance_data->tmp_report_create_infos, instance_data->tmp_report_callbacks);
+        instance_data->num_tmp_report_callbacks = 0;
     }
 
     if (!skip) {
         instance_data->dispatch_table.DestroyInstance(instance, pAllocator);
 
         // Clean up logging callback, if any
+        while (instance_data->logging_messenger.size() > 0) {
+            VkDebugUtilsMessengerEXT messenger = instance_data->logging_messenger.back();
+            layer_destroy_messenger_callback(instance_data->report_data, messenger, pAllocator);
+            instance_data->logging_messenger.pop_back();
+        }
         while (instance_data->logging_callback.size() > 0) {
             VkDebugReportCallbackEXT callback = instance_data->logging_callback.back();
-            layer_destroy_msg_callback(instance_data->report_data, callback, pAllocator);
+            layer_destroy_report_callback(instance_data->report_data, callback, pAllocator);
             instance_data->logging_callback.pop_back();
         }
 
-        layer_debug_report_destroy_instance(instance_data->report_data);
+        layer_debug_utils_destroy_instance(instance_data->report_data);
     }
 
     FreeLayerDataPtr(key, instance_layer_data_map);
@@ -330,7 +380,11 @@
     auto instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
     VkResult result = instance_data->dispatch_table.CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
     if (result == VK_SUCCESS) {
-        result = layer_create_msg_callback(instance_data->report_data, false, pCreateInfo, pAllocator, pMsgCallback);
+        result = layer_create_report_callback(instance_data->report_data, false, pCreateInfo, pAllocator, pMsgCallback);
+        // If something happened during this call, clean up the message callback that was created earlier in the lower levels
+        if (VK_SUCCESS != result) {
+            instance_data->dispatch_table.DestroyDebugReportCallbackEXT(instance, *pMsgCallback, pAllocator);
+        }
     }
     return result;
 }
@@ -341,7 +395,36 @@
     if (!skip) {
         auto instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
         instance_data->dispatch_table.DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);
-        layer_destroy_msg_callback(instance_data->report_data, msgCallback, pAllocator);
+        layer_destroy_report_callback(instance_data->report_data, msgCallback, pAllocator);
+    }
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugUtilsMessengerEXT(VkInstance instance,
+                                                              const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,
+                                                              const VkAllocationCallbacks *pAllocator,
+                                                              VkDebugUtilsMessengerEXT *pMessenger) {
+    bool skip = parameter_validation_vkCreateDebugUtilsMessengerEXT(instance, pCreateInfo, pAllocator, pMessenger);
+    if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
+
+    auto instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
+    VkResult result = instance_data->dispatch_table.CreateDebugUtilsMessengerEXT(instance, pCreateInfo, pAllocator, pMessenger);
+    if (VK_SUCCESS == result) {
+        result = layer_create_messenger_callback(instance_data->report_data, false, pCreateInfo, pAllocator, pMessenger);
+        // If something happened during this call, clean up the message callback that was created earlier in the lower levels
+        if (VK_SUCCESS != result) {
+            instance_data->dispatch_table.DestroyDebugUtilsMessengerEXT(instance, *pMessenger, pAllocator);
+        }
+    }
+    return result;
+}
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger,
+                                                           const VkAllocationCallbacks *pAllocator) {
+    bool skip = parameter_validation_vkDestroyDebugUtilsMessengerEXT(instance, messenger, pAllocator);
+    if (!skip) {
+        auto instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
+        instance_data->dispatch_table.DestroyDebugUtilsMessengerEXT(instance, messenger, pAllocator);
+        layer_destroy_messenger_callback(instance_data->report_data, messenger, pAllocator);
     }
 }
 
@@ -472,7 +555,7 @@
             layer_data *my_device_data = GetLayerDataPtr(get_dispatch_key(*pDevice), layer_data_map);
             assert(my_device_data != nullptr);
 
-            my_device_data->report_data = layer_debug_report_create_device(my_instance_data->report_data, *pDevice);
+            my_device_data->report_data = layer_debug_utils_create_device(my_instance_data->report_data, *pDevice);
             layer_init_device_dispatch_table(*pDevice, &my_device_data->dispatch_table, fpGetDeviceProcAddr);
 
             // Query and save physical device limits for this device
@@ -533,7 +616,7 @@
     }
 
     if (!skip) {
-        layer_debug_report_destroy_device(device);
+        layer_debug_utils_destroy_device(device);
         device_data->dispatch_table.DestroyDevice(device, pAllocator);
     }
     FreeLayerDataPtr(key, layer_data_map);
diff --git a/layers/threading.cpp b/layers/threading.cpp
index d27d75f..ce5f8e3 100644
--- a/layers/threading.cpp
+++ b/layers/threading.cpp
@@ -42,7 +42,8 @@
 static uint32_t loader_layer_if_version = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
 
 static void initThreading(layer_data *my_data, const VkAllocationCallbacks *pAllocator) {
-    layer_debug_actions(my_data->report_data, my_data->logging_callback, pAllocator, "google_threading");
+    layer_debug_report_actions(my_data->report_data, my_data->logging_callback, pAllocator, "google_threading");
+    layer_debug_messenger_actions(my_data->report_data, my_data->logging_messenger, pAllocator, "google_threading");
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL CreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
@@ -67,14 +68,16 @@
     my_data->instance_dispatch_table = new VkLayerInstanceDispatchTable;
     layer_init_instance_dispatch_table(*pInstance, my_data->instance_dispatch_table, fpGetInstanceProcAddr);
 
-    my_data->report_data = debug_report_create_instance(my_data->instance_dispatch_table, *pInstance,
-                                                        pCreateInfo->enabledExtensionCount, pCreateInfo->ppEnabledExtensionNames);
+    my_data->report_data = debug_utils_create_instance(my_data->instance_dispatch_table, *pInstance,
+                                                       pCreateInfo->enabledExtensionCount, pCreateInfo->ppEnabledExtensionNames);
     initThreading(my_data, pAllocator);
 
     // Look for one or more debug report create info structures, and copy the
     // callback(s) for each one found (for use by vkDestroyInstance)
-    layer_copy_tmp_callbacks(pCreateInfo->pNext, &my_data->num_tmp_callbacks, &my_data->tmp_dbg_create_infos,
-                             &my_data->tmp_callbacks);
+    layer_copy_tmp_debug_messengers(pCreateInfo->pNext, &my_data->num_tmp_debug_messengers, &my_data->tmp_messenger_create_infos,
+                                    &my_data->tmp_debug_messengers);
+    layer_copy_tmp_report_callbacks(pCreateInfo->pNext, &my_data->num_tmp_report_callbacks, &my_data->tmp_report_create_infos,
+                                    &my_data->tmp_report_callbacks);
     return result;
 }
 
@@ -85,9 +88,15 @@
 
     // Enable the temporary callback(s) here to catch cleanup issues:
     bool callback_setup = false;
-    if (my_data->num_tmp_callbacks > 0) {
-        if (!layer_enable_tmp_callbacks(my_data->report_data, my_data->num_tmp_callbacks, my_data->tmp_dbg_create_infos,
-                                        my_data->tmp_callbacks)) {
+    if (my_data->num_tmp_debug_messengers > 0) {
+        if (!layer_enable_tmp_debug_messengers(my_data->report_data, my_data->num_tmp_debug_messengers,
+                                               my_data->tmp_messenger_create_infos, my_data->tmp_debug_messengers)) {
+            callback_setup = true;
+        }
+    }
+    if (my_data->num_tmp_report_callbacks > 0) {
+        if (!layer_enable_tmp_report_callbacks(my_data->report_data, my_data->num_tmp_report_callbacks,
+                                               my_data->tmp_report_create_infos, my_data->tmp_report_callbacks)) {
             callback_setup = true;
         }
     }
@@ -105,21 +114,31 @@
 
     // Disable and cleanup the temporary callback(s):
     if (callback_setup) {
-        layer_disable_tmp_callbacks(my_data->report_data, my_data->num_tmp_callbacks, my_data->tmp_callbacks);
+        layer_disable_tmp_debug_messengers(my_data->report_data, my_data->num_tmp_debug_messengers, my_data->tmp_debug_messengers);
+        layer_disable_tmp_report_callbacks(my_data->report_data, my_data->num_tmp_report_callbacks, my_data->tmp_report_callbacks);
     }
-    if (my_data->num_tmp_callbacks > 0) {
-        layer_free_tmp_callbacks(my_data->tmp_dbg_create_infos, my_data->tmp_callbacks);
-        my_data->num_tmp_callbacks = 0;
+    if (my_data->num_tmp_debug_messengers > 0) {
+        layer_free_tmp_debug_messengers(my_data->tmp_messenger_create_infos, my_data->tmp_debug_messengers);
+        my_data->num_tmp_debug_messengers = 0;
+    }
+    if (my_data->num_tmp_report_callbacks > 0) {
+        layer_free_tmp_report_callbacks(my_data->tmp_report_create_infos, my_data->tmp_report_callbacks);
+        my_data->num_tmp_report_callbacks = 0;
     }
 
-    // Clean up logging callback, if any
+    // Clean up logging callbacks, if any
+    while (my_data->logging_messenger.size() > 0) {
+        VkDebugUtilsMessengerEXT messenger = my_data->logging_messenger.back();
+        layer_destroy_messenger_callback(my_data->report_data, messenger, pAllocator);
+        my_data->logging_messenger.pop_back();
+    }
     while (my_data->logging_callback.size() > 0) {
         VkDebugReportCallbackEXT callback = my_data->logging_callback.back();
-        layer_destroy_msg_callback(my_data->report_data, callback, pAllocator);
+        layer_destroy_report_callback(my_data->report_data, callback, pAllocator);
         my_data->logging_callback.pop_back();
     }
 
-    layer_debug_report_destroy_instance(my_data->report_data);
+    layer_debug_utils_destroy_instance(my_data->report_data);
     delete my_data->instance_dispatch_table;
     FreeLayerDataPtr(key, layer_data_map);
 }
@@ -151,7 +170,7 @@
     my_device_data->device_dispatch_table = new VkLayerDispatchTable;
     layer_init_device_dispatch_table(*pDevice, my_device_data->device_dispatch_table, fpGetDeviceProcAddr);
 
-    my_device_data->report_data = layer_debug_report_create_device(my_instance_data->report_data, *pDevice);
+    my_device_data->report_data = layer_debug_utils_create_device(my_instance_data->report_data, *pDevice);
     return result;
 }
 
@@ -194,8 +213,8 @@
     return result;
 }
 
-static const VkExtensionProperties threading_extensions[] = {
-    {VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION}};
+static const VkExtensionProperties threading_extensions[] = {{VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION},
+                                                             {VK_EXT_DEBUG_UTILS_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_SPEC_VERSION}};
 
 static const VkLayerProperties layerProps = {
     "VK_LAYER_GOOGLE_threading",
@@ -272,6 +291,52 @@
     return pTable->GetPhysicalDeviceProcAddr(instance, funcName);
 }
 
+// VK_EXT_debug_utils commands
+VKAPI_ATTR VkResult VKAPI_CALL CreateDebugUtilsMessengerEXT(VkInstance instance,
+                                                            const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,
+                                                            const VkAllocationCallbacks *pAllocator,
+                                                            VkDebugUtilsMessengerEXT *pMessenger) {
+    layer_data *my_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map);
+    bool threadChecks = startMultiThread();
+    if (threadChecks) {
+        startReadObject(my_data, instance);
+    }
+    VkResult result = my_data->instance_dispatch_table->CreateDebugUtilsMessengerEXT(instance, pCreateInfo, pAllocator, pMessenger);
+
+    if (VK_SUCCESS == result) {
+        result = layer_create_messenger_callback(my_data->report_data, false, pCreateInfo, pAllocator, pMessenger);
+        // If something happened during this call, clean up the message callback that was created earlier in the lower levels
+        if (VK_SUCCESS != result) {
+            my_data->instance_dispatch_table->DestroyDebugUtilsMessengerEXT(instance, *pMessenger, pAllocator);
+        }
+    }
+    if (threadChecks) {
+        finishReadObject(my_data, instance);
+    } else {
+        finishMultiThread();
+    }
+    return result;
+}
+
+VKAPI_ATTR void VKAPI_CALL DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger,
+                                                         const VkAllocationCallbacks *pAllocator) {
+    layer_data *my_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map);
+    bool threadChecks = startMultiThread();
+    if (threadChecks) {
+        startReadObject(my_data, instance);
+        startWriteObject(my_data, messenger);
+    }
+    my_data->instance_dispatch_table->DestroyDebugUtilsMessengerEXT(instance, messenger, pAllocator);
+    layer_destroy_messenger_callback(my_data->report_data, messenger, pAllocator);
+    if (threadChecks) {
+        finishReadObject(my_data, instance);
+        finishWriteObject(my_data, messenger);
+    } else {
+        finishMultiThread();
+    }
+}
+
+// VK_EXT_debug_report commands
 VKAPI_ATTR VkResult VKAPI_CALL CreateDebugReportCallbackEXT(VkInstance instance,
                                                             const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
                                                             const VkAllocationCallbacks *pAllocator,
@@ -284,7 +349,11 @@
     VkResult result =
         my_data->instance_dispatch_table->CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
     if (VK_SUCCESS == result) {
-        result = layer_create_msg_callback(my_data->report_data, false, pCreateInfo, pAllocator, pMsgCallback);
+        result = layer_create_report_callback(my_data->report_data, false, pCreateInfo, pAllocator, pMsgCallback);
+        // If something happened during this call, clean up the message callback that was created earlier in the lower levels
+        if (VK_SUCCESS != result) {
+            my_data->instance_dispatch_table->DestroyDebugReportCallbackEXT(instance, *pMsgCallback, pAllocator);
+        }
     }
     if (threadChecks) {
         finishReadObject(my_data, instance);
@@ -303,7 +372,7 @@
         startWriteObject(my_data, callback);
     }
     my_data->instance_dispatch_table->DestroyDebugReportCallbackEXT(instance, callback, pAllocator);
-    layer_destroy_msg_callback(my_data->report_data, callback, pAllocator);
+    layer_destroy_report_callback(my_data->report_data, callback, pAllocator);
     if (threadChecks) {
         finishReadObject(my_data, instance);
         finishWriteObject(my_data, callback);
@@ -400,6 +469,23 @@
 }  // namespace threading
 
 // vk_layer_logging.h expects these to be defined
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugUtilsMessengerEXT(VkInstance instance,
+                                                              const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,
+                                                              const VkAllocationCallbacks *pAllocator,
+                                                              VkDebugUtilsMessengerEXT *pMessenger) {
+    return threading::CreateDebugUtilsMessengerEXT(instance, pCreateInfo, pAllocator, pMessenger);
+}
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger,
+                                                           const VkAllocationCallbacks *pAllocator) {
+    threading::DestroyDebugUtilsMessengerEXT(instance, messenger, pAllocator);
+}
+
+VKAPI_ATTR void VKAPI_CALL vkSubmitDebugUtilsMessageEXT(VkInstance instance, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
+                                                        VkDebugUtilsMessageTypeFlagsEXT messageTypes,
+                                                        const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData) {
+    threading::SubmitDebugUtilsMessageEXT(instance, messageSeverity, messageTypes, pCallbackData);
+}
 
 VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugReportCallbackEXT(VkInstance instance,
                                                               const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
diff --git a/layers/threading.h b/layers/threading.h
index e2301d0..70814a5 100644
--- a/layers/threading.h
+++ b/layers/threading.h
@@ -228,13 +228,19 @@
 
     debug_report_data *report_data;
     std::vector<VkDebugReportCallbackEXT> logging_callback;
+    std::vector<VkDebugUtilsMessengerEXT> logging_messenger;
     VkLayerDispatchTable *device_dispatch_table;
     VkLayerInstanceDispatchTable *instance_dispatch_table;
+
     // The following are for keeping track of the temporary callbacks that can
     // be used in vkCreateInstance and vkDestroyInstance:
-    uint32_t num_tmp_callbacks;
-    VkDebugReportCallbackCreateInfoEXT *tmp_dbg_create_infos;
-    VkDebugReportCallbackEXT *tmp_callbacks;
+    uint32_t num_tmp_report_callbacks;
+    VkDebugReportCallbackCreateInfoEXT *tmp_report_create_infos;
+    VkDebugReportCallbackEXT *tmp_report_callbacks;
+    uint32_t num_tmp_debug_messengers;
+    VkDebugUtilsMessengerCreateInfoEXT *tmp_messenger_create_infos;
+    VkDebugUtilsMessengerEXT *tmp_debug_messengers;
+
     counter<VkCommandBuffer> c_VkCommandBuffer;
     counter<VkDevice> c_VkDevice;
     counter<VkInstance> c_VkInstance;
@@ -270,15 +276,19 @@
     counter<VkDescriptorUpdateTemplateKHR> c_VkDescriptorUpdateTemplateKHR;
     counter<VkValidationCacheEXT> c_VkValidationCacheEXT;
     counter<VkSamplerYcbcrConversionKHR> c_VkSamplerYcbcrConversionKHR;
+    counter<VkDebugUtilsMessengerEXT> c_VkDebugUtilsMessengerEXT;
 #else   // DISTINCT_NONDISPATCHABLE_HANDLES
     counter<uint64_t> c_uint64_t;
 #endif  // DISTINCT_NONDISPATCHABLE_HANDLES
 
     layer_data()
         : report_data(nullptr),
-          num_tmp_callbacks(0),
-          tmp_dbg_create_infos(nullptr),
-          tmp_callbacks(nullptr),
+          num_tmp_report_callbacks(0),
+          tmp_report_create_infos(nullptr),
+          tmp_report_callbacks(nullptr),
+          num_tmp_debug_messengers(0),
+          tmp_messenger_create_infos(nullptr),
+          tmp_debug_messengers(nullptr),
           c_VkCommandBuffer("VkCommandBuffer", VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT),
           c_VkDevice("VkDevice", VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT),
           c_VkInstance("VkInstance", VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT),
@@ -314,7 +324,9 @@
           c_VkSwapchainKHR("VkSwapchainKHR", VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT),
           c_VkDescriptorUpdateTemplateKHR("VkDescriptorUpdateTemplateKHR",
                                           VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT),
-          c_VkSamplerYcbcrConversionKHR("VkSamplerYcbcrConversionKHR", VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR_EXT)
+          c_VkSamplerYcbcrConversionKHR("VkSamplerYcbcrConversionKHR",
+                                        VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR_EXT),
+          c_VkDebugUtilsMessengerEXT("VkDebugUtilsMessengerEXT", VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT)
 #else   // DISTINCT_NONDISPATCHABLE_HANDLES
           c_uint64_t("NON_DISPATCHABLE_HANDLE", VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT)
 #endif  // DISTINCT_NONDISPATCHABLE_HANDLES
@@ -365,6 +377,7 @@
 WRAPPER(VkDescriptorUpdateTemplateKHR)
 WRAPPER(VkValidationCacheEXT)
 WRAPPER(VkSamplerYcbcrConversionKHR)
+WRAPPER(VkDebugUtilsMessengerEXT)
 #else   // DISTINCT_NONDISPATCHABLE_HANDLES
 WRAPPER(uint64_t)
 #endif  // DISTINCT_NONDISPATCHABLE_HANDLES
diff --git a/layers/unique_objects.cpp b/layers/unique_objects.cpp
index 3700370..702f07b 100644
--- a/layers/unique_objects.cpp
+++ b/layers/unique_objects.cpp
@@ -59,7 +59,9 @@
 static uint32_t loader_layer_if_version = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
 
 static void initUniqueObjects(instance_layer_data *instance_data, const VkAllocationCallbacks *pAllocator) {
-    layer_debug_actions(instance_data->report_data, instance_data->logging_callback, pAllocator, "google_unique_objects");
+    layer_debug_report_actions(instance_data->report_data, instance_data->logging_callback, pAllocator, "google_unique_objects");
+    layer_debug_messenger_actions(instance_data->report_data, instance_data->logging_messenger, pAllocator,
+                                  "google_unique_objects");
 }
 
 // Check enabled instance extensions against supported instance extension whitelist
@@ -118,17 +120,27 @@
     layer_init_instance_dispatch_table(*pInstance, &instance_data->dispatch_table, fpGetInstanceProcAddr);
 
     instance_data->instance = *pInstance;
-    instance_data->report_data = debug_report_create_instance(
+    instance_data->report_data = debug_utils_create_instance(
         &instance_data->dispatch_table, *pInstance, pCreateInfo->enabledExtensionCount, pCreateInfo->ppEnabledExtensionNames);
 
     // Set up temporary debug callbacks to output messages at CreateInstance-time
-    if (!layer_copy_tmp_callbacks(pCreateInfo->pNext, &instance_data->num_tmp_callbacks, &instance_data->tmp_dbg_create_infos,
-                                  &instance_data->tmp_callbacks)) {
-        if (instance_data->num_tmp_callbacks > 0) {
-            if (layer_enable_tmp_callbacks(instance_data->report_data, instance_data->num_tmp_callbacks,
-                                           instance_data->tmp_dbg_create_infos, instance_data->tmp_callbacks)) {
-                layer_free_tmp_callbacks(instance_data->tmp_dbg_create_infos, instance_data->tmp_callbacks);
-                instance_data->num_tmp_callbacks = 0;
+    if (!layer_copy_tmp_debug_messengers(pCreateInfo->pNext, &instance_data->num_tmp_debug_messengers,
+                                         &instance_data->tmp_messenger_create_infos, &instance_data->tmp_debug_messengers)) {
+        if (instance_data->num_tmp_debug_messengers > 0) {
+            if (layer_enable_tmp_debug_messengers(instance_data->report_data, instance_data->num_tmp_debug_messengers,
+                                                  instance_data->tmp_messenger_create_infos, instance_data->tmp_debug_messengers)) {
+                layer_free_tmp_debug_messengers(instance_data->tmp_messenger_create_infos, instance_data->tmp_debug_messengers);
+                instance_data->num_tmp_debug_messengers = 0;
+            }
+        }
+    }
+    if (!layer_copy_tmp_report_callbacks(pCreateInfo->pNext, &instance_data->num_tmp_report_callbacks,
+                                         &instance_data->tmp_report_create_infos, &instance_data->tmp_report_callbacks)) {
+        if (instance_data->num_tmp_report_callbacks > 0) {
+            if (layer_enable_tmp_report_callbacks(instance_data->report_data, instance_data->num_tmp_report_callbacks,
+                                                  instance_data->tmp_report_create_infos, instance_data->tmp_report_callbacks)) {
+                layer_free_tmp_report_callbacks(instance_data->tmp_report_create_infos, instance_data->tmp_report_callbacks);
+                instance_data->num_tmp_report_callbacks = 0;
             }
         }
     }
@@ -137,10 +149,17 @@
     InstanceExtensionWhitelist(pCreateInfo, *pInstance);
 
     // Disable and free tmp callbacks, no longer necessary
-    if (instance_data->num_tmp_callbacks > 0) {
-        layer_disable_tmp_callbacks(instance_data->report_data, instance_data->num_tmp_callbacks, instance_data->tmp_callbacks);
-        layer_free_tmp_callbacks(instance_data->tmp_dbg_create_infos, instance_data->tmp_callbacks);
-        instance_data->num_tmp_callbacks = 0;
+    if (instance_data->num_tmp_debug_messengers > 0) {
+        layer_disable_tmp_debug_messengers(instance_data->report_data, instance_data->num_tmp_debug_messengers,
+                                           instance_data->tmp_debug_messengers);
+        layer_free_tmp_debug_messengers(instance_data->tmp_messenger_create_infos, instance_data->tmp_debug_messengers);
+        instance_data->num_tmp_debug_messengers = 0;
+    }
+    if (instance_data->num_tmp_report_callbacks > 0) {
+        layer_disable_tmp_report_callbacks(instance_data->report_data, instance_data->num_tmp_report_callbacks,
+                                           instance_data->tmp_report_callbacks);
+        layer_free_tmp_report_callbacks(instance_data->tmp_report_create_infos, instance_data->tmp_report_callbacks);
+        instance_data->num_tmp_report_callbacks = 0;
     }
 
     return result;
@@ -153,13 +172,18 @@
     disp_table->DestroyInstance(instance, pAllocator);
 
     // Clean up logging callback, if any
+    while (instance_data->logging_messenger.size() > 0) {
+        VkDebugUtilsMessengerEXT messenger = instance_data->logging_messenger.back();
+        layer_destroy_messenger_callback(instance_data->report_data, messenger, pAllocator);
+        instance_data->logging_messenger.pop_back();
+    }
     while (instance_data->logging_callback.size() > 0) {
         VkDebugReportCallbackEXT callback = instance_data->logging_callback.back();
-        layer_destroy_msg_callback(instance_data->report_data, callback, pAllocator);
+        layer_destroy_report_callback(instance_data->report_data, callback, pAllocator);
         instance_data->logging_callback.pop_back();
     }
 
-    layer_debug_report_destroy_instance(instance_data->report_data);
+    layer_debug_utils_destroy_instance(instance_data->report_data);
     FreeLayerDataPtr(key, instance_layer_data_map);
 }
 
@@ -185,7 +209,7 @@
     }
 
     layer_data *my_device_data = GetLayerDataPtr(get_dispatch_key(*pDevice), layer_data_map);
-    my_device_data->report_data = layer_debug_report_create_device(my_instance_data->report_data, *pDevice);
+    my_device_data->report_data = layer_debug_utils_create_device(my_instance_data->report_data, *pDevice);
 
     // Setup layer's device dispatch table
     layer_init_device_dispatch_table(*pDevice, &my_device_data->dispatch_table, fpGetDeviceProcAddr);
@@ -202,7 +226,7 @@
     dispatch_key key = get_dispatch_key(device);
     layer_data *dev_data = GetLayerDataPtr(key, layer_data_map);
 
-    layer_debug_report_destroy_device(device);
+    layer_debug_utils_destroy_device(device);
     dev_data->dispatch_table.DestroyDevice(device, pAllocator);
 
     FreeLayerDataPtr(key, layer_data_map);
@@ -877,6 +901,37 @@
     return result;
 }
 
+// VK_EXT_debug_utils
+VKAPI_ATTR VkResult VKAPI_CALL SetDebugUtilsObjectTagEXT(VkDevice device, const VkDebugUtilsObjectTagInfoEXT *pTagInfo) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    auto local_tag_info = new safe_VkDebugUtilsObjectTagInfoEXT(pTagInfo);
+    {
+        std::lock_guard<std::mutex> lock(global_lock);
+        auto it = device_data->unique_id_mapping.find(reinterpret_cast<uint64_t &>(local_tag_info->objectHandle));
+        if (it != device_data->unique_id_mapping.end()) {
+            local_tag_info->objectHandle = it->second;
+        }
+    }
+    VkResult result = device_data->dispatch_table.SetDebugUtilsObjectTagEXT(
+        device, reinterpret_cast<const VkDebugUtilsObjectTagInfoEXT *>(local_tag_info));
+    return result;
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL SetDebugUtilsObjectNameEXT(VkDevice device, const VkDebugUtilsObjectNameInfoEXT *pNameInfo) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    auto local_name_info = new safe_VkDebugUtilsObjectNameInfoEXT(pNameInfo);
+    {
+        std::lock_guard<std::mutex> lock(global_lock);
+        auto it = device_data->unique_id_mapping.find(reinterpret_cast<uint64_t &>(local_name_info->objectHandle));
+        if (it != device_data->unique_id_mapping.end()) {
+            local_name_info->objectHandle = it->second;
+        }
+    }
+    VkResult result = device_data->dispatch_table.SetDebugUtilsObjectNameEXT(
+        device, reinterpret_cast<const VkDebugUtilsObjectNameInfoEXT *>(local_name_info));
+    return result;
+}
+
 }  // namespace unique_objects
 
 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
diff --git a/layers/unique_objects.h b/layers/unique_objects.h
index 3dd3a79..0a03234 100644
--- a/layers/unique_objects.h
+++ b/layers/unique_objects.h
@@ -50,12 +50,17 @@
 
     debug_report_data *report_data;
     std::vector<VkDebugReportCallbackEXT> logging_callback;
+    std::vector<VkDebugUtilsMessengerEXT> logging_messenger;
     VkLayerInstanceDispatchTable dispatch_table = {};
 
-    // The following are for keeping track of the temporary callbacks that can be used in vkCreateInstance and vkDestroyInstance:
-    uint32_t num_tmp_callbacks;
-    VkDebugReportCallbackCreateInfoEXT *tmp_dbg_create_infos;
-    VkDebugReportCallbackEXT *tmp_callbacks;
+    // The following are for keeping track of the temporary callbacks that can
+    // be used in vkCreateInstance and vkDestroyInstance:
+    uint32_t num_tmp_report_callbacks;
+    VkDebugReportCallbackCreateInfoEXT *tmp_report_create_infos;
+    VkDebugReportCallbackEXT *tmp_report_callbacks;
+    uint32_t num_tmp_debug_messengers;
+    VkDebugUtilsMessengerCreateInfoEXT *tmp_messenger_create_infos;
+    VkDebugUtilsMessengerEXT *tmp_debug_messengers;
 };
 
 struct layer_data {
diff --git a/layers/vk_layer_config.cpp b/layers/vk_layer_config.cpp
index b1b09d4..51f4278 100644
--- a/layers/vk_layer_config.cpp
+++ b/layers/vk_layer_config.cpp
@@ -248,31 +248,74 @@
     }
 }
 
-VK_LAYER_EXPORT void print_msg_flags(VkFlags msgFlags, char *msg_flags) {
+VK_LAYER_EXPORT void PrintMessageFlags(VkFlags vk_flags, char *msg_flags) {
     bool separator = false;
 
     msg_flags[0] = 0;
-    if (msgFlags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) {
+    if (vk_flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) {
         strcat(msg_flags, "DEBUG");
         separator = true;
     }
-    if (msgFlags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) {
+    if (vk_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) {
         if (separator) strcat(msg_flags, ",");
         strcat(msg_flags, "INFO");
         separator = true;
     }
-    if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
+    if (vk_flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
         if (separator) strcat(msg_flags, ",");
         strcat(msg_flags, "WARN");
         separator = true;
     }
-    if (msgFlags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) {
+    if (vk_flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) {
         if (separator) strcat(msg_flags, ",");
         strcat(msg_flags, "PERF");
         separator = true;
     }
-    if (msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
+    if (vk_flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
         if (separator) strcat(msg_flags, ",");
         strcat(msg_flags, "ERROR");
     }
 }
+
+VK_LAYER_EXPORT void PrintMessageSeverity(VkFlags vk_flags, char *msg_flags) {
+    bool separator = false;
+
+    msg_flags[0] = 0;
+    if (vk_flags & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) {
+        strcat(msg_flags, "VERBOSE");
+        separator = true;
+    }
+    if (vk_flags & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) {
+        if (separator) strcat(msg_flags, ",");
+        strcat(msg_flags, "INFO");
+        separator = true;
+    }
+    if (vk_flags & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) {
+        if (separator) strcat(msg_flags, ",");
+        strcat(msg_flags, "WARN");
+        separator = true;
+    }
+    if (vk_flags & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
+        if (separator) strcat(msg_flags, ",");
+        strcat(msg_flags, "ERROR");
+    }
+}
+
+VK_LAYER_EXPORT void PrintMessageType(VkFlags vk_flags, char *msg_flags) {
+    bool separator = false;
+
+    msg_flags[0] = 0;
+    if (vk_flags & VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT) {
+        strcat(msg_flags, "GEN");
+        separator = true;
+    }
+    if (vk_flags & VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT) {
+        strcat(msg_flags, "SPEC");
+        separator = true;
+    }
+    if (vk_flags & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) {
+        if (separator) strcat(msg_flags, ",");
+        strcat(msg_flags, "PERF");
+        separator = true;
+    }
+}
diff --git a/layers/vk_layer_config.h b/layers/vk_layer_config.h
index b12ba50..e0b9d32 100644
--- a/layers/vk_layer_config.h
+++ b/layers/vk_layer_config.h
@@ -63,7 +63,9 @@
                                             uint32_t option_default);
 
 VK_LAYER_EXPORT void setLayerOption(const char *_option, const char *_val);
-VK_LAYER_EXPORT void print_msg_flags(VkFlags msgFlags, char *msg_flags);
+VK_LAYER_EXPORT void PrintMessageFlags(VkFlags vk_flags, char *msg_flags);
+VK_LAYER_EXPORT void PrintMessageSeverity(VkFlags vk_flags, char *msg_flags);
+VK_LAYER_EXPORT void PrintMessageType(VkFlags vk_flags, char *msg_flags);
 
 #ifdef __cplusplus
 }
diff --git a/layers/vk_layer_logging.h b/layers/vk_layer_logging.h
index 559b5a4..61e109a 100644
--- a/layers/vk_layer_logging.h
+++ b/layers/vk_layer_logging.h
@@ -1,6 +1,6 @@
-/* Copyright (c) 2015-2016 The Khronos Group Inc.
- * Copyright (c) 2015-2016 Valve Corporation
- * Copyright (c) 2015-2016 LunarG, Inc.
+/* Copyright (c) 2015-2017 The Khronos Group Inc.
+ * Copyright (c) 2015-2017 Valve Corporation
+ * Copyright (c) 2015-2017 LunarG, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
  *
  * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
  * Author: Tobin Ehlis <tobin@lunarg.com>
+ * Author: Mark Young <marky@lunarg.com>
  *
  */
 
@@ -28,6 +29,7 @@
 #include "vk_layer_table.h"
 #include "vk_loader_platform.h"
 #include "vulkan/vk_layer.h"
+#include "vk_object_types.h"
 #include <signal.h>
 #include <cinttypes>
 #include <stdarg.h>
@@ -35,51 +37,103 @@
 #include <stdio.h>
 #include <unordered_map>
 #include <vector>
+#include <sstream>
+#include <string>
+
+// TODO: Could be autogenerated for the specific handles for extra type safety...
+template <typename HANDLE_T>
+static inline uint64_t HandleToUint64(HANDLE_T *h) {
+    return reinterpret_cast<uint64_t>(h);
+}
+
+static inline uint64_t HandleToUint64(uint64_t h) { return h; }
+
+// Data we store per label for logging
+typedef struct _LoggingLabelData {
+    std::string name;
+    float color[4];
+} LoggingLabelData;
 
 typedef struct _debug_report_data {
     VkLayerDbgFunctionNode *debug_callback_list;
     VkLayerDbgFunctionNode *default_debug_callback_list;
-    VkFlags active_flags;
+    VkDebugUtilsMessageSeverityFlagsEXT active_severities;
+    VkDebugUtilsMessageTypeFlagsEXT active_types;
     bool g_DEBUG_REPORT;
+    bool g_DEBUG_UTILS;
     std::unordered_map<uint64_t, std::string> *debugObjectNameMap;
+    std::unordered_map<uint64_t, std::string> *debugUtilsObjectNameMap;
+    std::unordered_map<VkQueue, std::vector<LoggingLabelData>> *debugUtilsQueueLabels;
+    bool queueLabelHasInsert;
+    std::unordered_map<VkCommandBuffer, std::vector<LoggingLabelData>> *debugUtilsCmdBufLabels;
+    bool cmdBufLabelHasInsert;
 } debug_report_data;
 
 template debug_report_data *GetLayerDataPtr<debug_report_data>(void *data_key,
                                                                std::unordered_map<void *, debug_report_data *> &data_map);
 
+static inline void DebugReportFlagsToAnnotFlags(VkDebugReportFlagsEXT dr_flags, bool default_flag_is_spec,
+                                                VkDebugUtilsMessageSeverityFlagsEXT *da_severity,
+                                                VkDebugUtilsMessageTypeFlagsEXT *da_type) {
+    // All layer warnings are spec warnings currently.  At least as far as anything not specifically
+    // called out.  In the future, we'll label things using the new split severity and type values.
+    *da_type = VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
+    *da_severity = 0;
+    if ((dr_flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) != 0) {
+        *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
+        *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT;
+    }
+    if ((dr_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) != 0) {
+        *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
+        *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT;
+    }
+    if ((dr_flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) != 0) {
+        *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
+        *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
+    }
+    if ((dr_flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) != 0) {
+        *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
+    }
+    if ((dr_flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) != 0) {
+        *da_severity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
+    }
+}
+
 // Forward Declarations
-static inline bool debug_report_log_msg(const debug_report_data *debug_data, VkFlags msgFlags,
-                                        VkDebugReportObjectTypeEXT objectType, uint64_t srcObject, size_t location, int32_t msgCode,
-                                        const char *pLayerPrefix, const char *pMsg);
+static inline bool debug_log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type,
+                                 uint64_t src_object, size_t location, int32_t msg_code, const char *layer_prefix,
+                                 const char *message);
 
 // Add a debug message callback node structure to the specified callback linked list
-static inline void AddDebugMessageCallback(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head,
-                                           VkLayerDbgFunctionNode *new_node) {
+static inline void AddDebugCallbackNode(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head,
+                                        VkLayerDbgFunctionNode *new_node) {
     new_node->pNext = *list_head;
     *list_head = new_node;
 }
 
-// Remove specified debug message callback node structure from the specified callback linked list
-static inline void RemoveDebugMessageCallback(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head,
-                                              VkDebugReportCallbackEXT callback) {
+// Remove specified debug messenger node structure from the specified linked list
+static inline void RemoveDebugUtilsMessenger(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head,
+                                             VkDebugUtilsMessengerEXT messenger) {
     VkLayerDbgFunctionNode *cur_callback = *list_head;
     VkLayerDbgFunctionNode *prev_callback = cur_callback;
     bool matched = false;
-    VkFlags local_flags = 0;
+    VkFlags local_severities = 0;
+    VkFlags local_types = 0;
 
     while (cur_callback) {
-        if (cur_callback->msgCallback == callback) {
+        if (cur_callback->is_messenger && cur_callback->messenger.messenger == messenger) {
             matched = true;
             prev_callback->pNext = cur_callback->pNext;
             if (*list_head == cur_callback) {
                 *list_head = cur_callback->pNext;
             }
-            debug_report_log_msg(debug_data, VK_DEBUG_REPORT_DEBUG_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
-                                 reinterpret_cast<uint64_t &>(cur_callback->msgCallback), 0, 0, "DebugReport",
-                                 "Destroyed callback\n");
+            debug_log_msg(debug_data, VK_DEBUG_REPORT_DEBUG_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
+                          reinterpret_cast<uint64_t &>(cur_callback->messenger.messenger), 0, 0, "DebugUtilsMessenger",
+                          "Destroyed messenger\n");
         } else {
             matched = false;
-            local_flags |= cur_callback->msgFlags;
+            local_severities |= cur_callback->messenger.messageSeverity;
+            local_types |= cur_callback->messenger.messageType;
         }
         prev_callback = cur_callback;
         cur_callback = cur_callback->pNext;
@@ -87,7 +141,45 @@
             free(prev_callback);
         }
     }
-    debug_data->active_flags = local_flags;
+    debug_data->active_severities = local_severities;
+    debug_data->active_types = local_types;
+}
+
+// Remove specified debug message callback node structure from the specified callback linked list
+static inline void RemoveDebugUtilsMessageCallback(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head,
+                                                   VkDebugReportCallbackEXT callback) {
+    VkLayerDbgFunctionNode *cur_callback = *list_head;
+    VkLayerDbgFunctionNode *prev_callback = cur_callback;
+    bool matched = false;
+    VkFlags local_severities = 0;
+    VkFlags local_types = 0;
+
+    while (cur_callback) {
+        if (!cur_callback->is_messenger && cur_callback->report.msgCallback == callback) {
+            matched = true;
+            prev_callback->pNext = cur_callback->pNext;
+            if (*list_head == cur_callback) {
+                *list_head = cur_callback->pNext;
+            }
+            debug_log_msg(debug_data, VK_DEBUG_REPORT_DEBUG_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
+                          reinterpret_cast<uint64_t &>(cur_callback->report.msgCallback), 0, 0, "DebugReport",
+                          "Destroyed callback\n");
+        } else {
+            matched = false;
+            VkFlags this_severities = 0;
+            VkFlags this_types = 0;
+            DebugReportFlagsToAnnotFlags(cur_callback->report.msgFlags, true, &this_severities, &this_types);
+            local_severities |= this_severities;
+            local_types |= this_types;
+        }
+        prev_callback = cur_callback;
+        cur_callback = cur_callback->pNext;
+        if (matched) {
+            free(prev_callback);
+        }
+    }
+    debug_data->active_severities = local_severities;
+    debug_data->active_types = local_types;
 }
 
 // Removes all debug callback function nodes from the specified callback linked lists and frees their resources
@@ -97,9 +189,15 @@
 
     while (current_callback) {
         prev_callback = current_callback->pNext;
-        debug_report_log_msg(debug_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
-                             (uint64_t)current_callback->msgCallback, 0, 0, "DebugReport",
-                             "Debug Report callbacks not removed before DestroyInstance");
+        if (!current_callback->is_messenger) {
+            debug_log_msg(debug_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
+                          (uint64_t)current_callback->report.msgCallback, 0, 0, "DebugReport",
+                          "Debug Report callbacks not removed before DestroyInstance");
+        } else {
+            debug_log_msg(debug_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
+                          (uint64_t)current_callback->messenger.messenger, 0, 0, "Messenger",
+                          "Debug messengers not removed before DestroyInstance");
+        }
         free(current_callback);
         current_callback = prev_callback;
     }
@@ -107,46 +205,222 @@
 }
 
 // Utility function to handle reporting
-static inline bool debug_report_log_msg(const debug_report_data *debug_data, VkFlags msgFlags,
-                                        VkDebugReportObjectTypeEXT objectType, uint64_t srcObject, size_t location, int32_t msgCode,
-                                        const char *pLayerPrefix, const char *pMsg) {
+static inline bool debug_log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type,
+                                 uint64_t src_object, size_t location, int32_t msg_code, const char *layer_prefix,
+                                 const char *message) {
     bool bail = false;
-    VkLayerDbgFunctionNode *pTrav = NULL;
+    VkLayerDbgFunctionNode *layer_dbg_node = NULL;
 
     if (debug_data->debug_callback_list != NULL) {
-        pTrav = debug_data->debug_callback_list;
+        layer_dbg_node = debug_data->debug_callback_list;
     } else {
-        pTrav = debug_data->default_debug_callback_list;
+        layer_dbg_node = debug_data->default_debug_callback_list;
     }
 
-    while (pTrav) {
-        if (pTrav->msgFlags & msgFlags) {
-            auto it = debug_data->debugObjectNameMap->find(srcObject);
+    VkDebugUtilsMessageSeverityFlagsEXT severity;
+    VkDebugUtilsMessageTypeFlagsEXT types;
+    VkDebugUtilsMessengerCallbackDataEXT callback_data;
+    VkDebugUtilsObjectNameInfoEXT object_name_info;
+
+    // Convert the info to the VK_EXT_debug_utils form in case we need it.
+    DebugReportFlagsToAnnotFlags(msg_flags, true, &severity, &types);
+    object_name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
+    object_name_info.pNext = NULL;
+    object_name_info.objectType = convertDebugReportObjectToCoreObject(object_type);
+    object_name_info.objectHandle = (uint64_t)(uintptr_t)src_object;
+    object_name_info.pObjectName = NULL;
+
+    callback_data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT;
+    callback_data.pNext = NULL;
+    callback_data.flags = 0;
+    callback_data.pMessageIdName = layer_prefix;
+    callback_data.messageIdNumber = msg_code;
+    callback_data.pMessage = message;
+    callback_data.queueLabelCount = 0;
+    callback_data.pQueueLabels = NULL;
+    callback_data.cmdBufLabelCount = 0;
+    callback_data.pCmdBufLabels = NULL;
+    callback_data.objectCount = 1;
+    callback_data.pObjects = &object_name_info;
+
+    VkDebugUtilsLabelEXT *queue_labels = nullptr;
+    VkDebugUtilsLabelEXT *cmd_buf_labels = nullptr;
+    std::string new_debug_report_message = "";
+    std::ostringstream oss;
+    oss << "Object: 0x" << std::hex << src_object;
+
+    if (0 != src_object) {
+        // If this is a queue, add any queue labels to the callback data.
+        if (VK_OBJECT_TYPE_QUEUE == object_name_info.objectType) {
+            auto label_iter = debug_data->debugUtilsQueueLabels->find(reinterpret_cast<VkQueue>(src_object));
+            if (label_iter != debug_data->debugUtilsQueueLabels->end()) {
+                queue_labels = new VkDebugUtilsLabelEXT[label_iter->second.size()];
+                if (nullptr != queue_labels) {
+                    // Record the labels, but record them in reverse order since we want the
+                    // most recent at the top.
+                    uint32_t label_size = static_cast<uint32_t>(label_iter->second.size());
+                    uint32_t last_index = label_size - 1;
+                    for (uint32_t label = 0; label < label_size; ++label) {
+                        queue_labels[last_index - label].sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
+                        queue_labels[last_index - label].pNext = nullptr;
+                        queue_labels[last_index - label].pLabelName = label_iter->second[label].name.c_str();
+                        queue_labels[last_index - label].color[0] = label_iter->second[label].color[0];
+                        queue_labels[last_index - label].color[1] = label_iter->second[label].color[1];
+                        queue_labels[last_index - label].color[2] = label_iter->second[label].color[2];
+                        queue_labels[last_index - label].color[3] = label_iter->second[label].color[3];
+                    }
+                    callback_data.queueLabelCount = label_size;
+                    callback_data.pQueueLabels = queue_labels;
+                }
+            }
+            // If this is a command buffer, add any command buffer labels to the callback data.
+        } else if (VK_OBJECT_TYPE_COMMAND_BUFFER == object_name_info.objectType) {
+            auto label_iter = debug_data->debugUtilsCmdBufLabels->find(reinterpret_cast<VkCommandBuffer>(src_object));
+            if (label_iter != debug_data->debugUtilsCmdBufLabels->end()) {
+                cmd_buf_labels = new VkDebugUtilsLabelEXT[label_iter->second.size()];
+                if (nullptr != cmd_buf_labels) {
+                    // Record the labels, but record them in reverse order since we want the
+                    // most recent at the top.
+                    uint32_t label_size = static_cast<uint32_t>(label_iter->second.size());
+                    uint32_t last_index = label_size - 1;
+                    for (uint32_t label = 0; label < label_size; ++label) {
+                        cmd_buf_labels[last_index - label].sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
+                        cmd_buf_labels[last_index - label].pNext = nullptr;
+                        cmd_buf_labels[last_index - label].pLabelName = label_iter->second[label].name.c_str();
+                        cmd_buf_labels[last_index - label].color[0] = label_iter->second[label].color[0];
+                        cmd_buf_labels[last_index - label].color[1] = label_iter->second[label].color[1];
+                        cmd_buf_labels[last_index - label].color[2] = label_iter->second[label].color[2];
+                        cmd_buf_labels[last_index - label].color[3] = label_iter->second[label].color[3];
+                    }
+                    callback_data.cmdBufLabelCount = label_size;
+                    callback_data.pCmdBufLabels = cmd_buf_labels;
+                }
+            }
+        }
+        // Look for any debug utils or marker names to use for this object
+        callback_data.pObjects[0].pObjectName = NULL;
+        auto utils_name_iter = debug_data->debugUtilsObjectNameMap->find(src_object);
+        if (utils_name_iter != debug_data->debugUtilsObjectNameMap->end()) {
+            callback_data.pObjects[0].pObjectName = utils_name_iter->second.c_str();
+        } else {
+            auto marker_name_iter = debug_data->debugObjectNameMap->find(src_object);
+            if (marker_name_iter != debug_data->debugObjectNameMap->end()) {
+                callback_data.pObjects[0].pObjectName = marker_name_iter->second.c_str();
+            }
+        }
+        if (NULL != callback_data.pObjects[0].pObjectName) {
+            oss << " (Name = " << callback_data.pObjects[0].pObjectName << ")";
+        }
+    }
+    new_debug_report_message += oss.str();
+    new_debug_report_message += " | ";
+    new_debug_report_message += message;
+
+    while (layer_dbg_node) {
+        if (!layer_dbg_node->is_messenger && (layer_dbg_node->report.msgFlags & msg_flags) &&
+            layer_dbg_node->report.pfnMsgCallback(msg_flags, object_type, src_object, location, msg_code, layer_prefix,
+                                                  new_debug_report_message.c_str(), layer_dbg_node->pUserData)) {
+            bail = true;
+        } else if (layer_dbg_node->is_messenger && (layer_dbg_node->messenger.messageSeverity & severity) &&
+                   (layer_dbg_node->messenger.messageType & types) &&
+                   layer_dbg_node->messenger.pfnUserCallback(static_cast<VkDebugUtilsMessageSeverityFlagBitsEXT>(severity), types,
+                                                             &callback_data, layer_dbg_node->pUserData)) {
+            bail = true;
+        }
+        layer_dbg_node = layer_dbg_node->pNext;
+    }
+
+    if (nullptr != queue_labels) {
+        delete[] queue_labels;
+    }
+    if (nullptr != cmd_buf_labels) {
+        delete[] cmd_buf_labels;
+    }
+
+    return bail;
+}
+
+static inline void DebugAnnotFlagsToReportFlags(VkDebugUtilsMessageSeverityFlagBitsEXT da_severity,
+                                                VkDebugUtilsMessageTypeFlagsEXT da_type, VkDebugReportFlagsEXT *dr_flags) {
+    *dr_flags = 0;
+
+    if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) != 0) {
+        *dr_flags |= VK_DEBUG_REPORT_ERROR_BIT_EXT;
+    } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) != 0) {
+        if ((da_type & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) != 0) {
+            *dr_flags |= VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
+        } else {
+            *dr_flags |= VK_DEBUG_REPORT_WARNING_BIT_EXT;
+        }
+    } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) != 0) {
+        *dr_flags |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT;
+    } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) != 0) {
+        *dr_flags |= VK_DEBUG_REPORT_DEBUG_BIT_EXT;
+    }
+}
+
+static inline bool debug_messenger_log_msg(const debug_report_data *debug_data,
+                                           VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,
+                                           VkDebugUtilsMessageTypeFlagsEXT message_type,
+                                           VkDebugUtilsMessengerCallbackDataEXT *callback_data) {
+    bool bail = false;
+    VkLayerDbgFunctionNode *layer_dbg_node = NULL;
+
+    if (debug_data->debug_callback_list != NULL) {
+        layer_dbg_node = debug_data->debug_callback_list;
+    } else {
+        layer_dbg_node = debug_data->default_debug_callback_list;
+    }
+
+    VkDebugReportFlagsEXT object_flags = 0;
+
+    DebugAnnotFlagsToReportFlags(message_severity, message_type, &object_flags);
+
+    while (layer_dbg_node) {
+        if (layer_dbg_node->is_messenger && (layer_dbg_node->messenger.messageSeverity & message_severity) &&
+            (layer_dbg_node->messenger.messageType & message_type)) {
+            // Loop through each object and give it the proper name if it was set.
+            for (uint32_t obj = 0; obj < callback_data->objectCount; obj++) {
+                auto it = debug_data->debugUtilsObjectNameMap->find(callback_data->pObjects[obj].objectHandle);
+                if (it == debug_data->debugUtilsObjectNameMap->end()) {
+                    continue;
+                }
+                callback_data->pObjects[obj].pObjectName = it->second.c_str();
+            }
+            if (layer_dbg_node->messenger.pfnUserCallback(message_severity, message_type, callback_data,
+                                                          layer_dbg_node->pUserData)) {
+                bail = true;
+            }
+        } else if (!layer_dbg_node->is_messenger && layer_dbg_node->report.msgFlags & object_flags) {
+            auto it = debug_data->debugObjectNameMap->find(callback_data->pObjects[0].objectHandle);
+            VkDebugReportObjectTypeEXT object_type = get_debug_report_enum[callback_data->pObjects[0].objectType];
             if (it == debug_data->debugObjectNameMap->end()) {
-                if (pTrav->pfnMsgCallback(msgFlags, objectType, srcObject, location, msgCode, pLayerPrefix, pMsg,
-                                          pTrav->pUserData)) {
+                if (layer_dbg_node->report.pfnMsgCallback(object_flags, object_type, callback_data->pObjects[0].objectHandle, 0,
+                                                          callback_data->messageIdNumber, callback_data->pMessageIdName,
+                                                          callback_data->pMessage, layer_dbg_node->pUserData)) {
                     bail = true;
                 }
             } else {
                 std::string newMsg = "SrcObject name = ";
                 newMsg.append(it->second.c_str());
                 newMsg.append(" ");
-                newMsg.append(pMsg);
-                if (pTrav->pfnMsgCallback(msgFlags, objectType, srcObject, location, msgCode, pLayerPrefix, newMsg.c_str(),
-                                          pTrav->pUserData)) {
+                newMsg.append(callback_data->pMessage);
+                if (layer_dbg_node->report.pfnMsgCallback(object_flags, object_type, callback_data->pObjects[0].objectHandle, 0,
+                                                          callback_data->messageIdNumber, callback_data->pMessageIdName,
+                                                          newMsg.c_str(), layer_dbg_node->pUserData)) {
                     bail = true;
                 }
             }
         }
-        pTrav = pTrav->pNext;
+        layer_dbg_node = layer_dbg_node->pNext;
     }
 
     return bail;
 }
 
-static inline debug_report_data *debug_report_create_instance(
+static inline debug_report_data *debug_utils_create_instance(
     VkLayerInstanceDispatchTable *table, VkInstance inst, uint32_t extension_count,
-    const char *const *ppEnabledExtensions)  // layer or extension name to be enabled
+    const char *const *enabled_extensions)  // layer or extension name to be enabled
 {
     debug_report_data *debug_data = (debug_report_data *)malloc(sizeof(debug_report_data));
     if (!debug_data) return NULL;
@@ -154,78 +428,162 @@
     memset(debug_data, 0, sizeof(debug_report_data));
     for (uint32_t i = 0; i < extension_count; i++) {
         // TODO: Check other property fields
-        if (strcmp(ppEnabledExtensions[i], VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0) {
+        if (strcmp(enabled_extensions[i], VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0) {
             debug_data->g_DEBUG_REPORT = true;
+        } else if (strcmp(enabled_extensions[i], VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0) {
+            debug_data->g_DEBUG_UTILS = true;
         }
     }
     debug_data->debugObjectNameMap = new std::unordered_map<uint64_t, std::string>;
+    debug_data->debugUtilsObjectNameMap = new std::unordered_map<uint64_t, std::string>;
+    debug_data->debugUtilsQueueLabels = new std::unordered_map<VkQueue, std::vector<LoggingLabelData>>;
+    debug_data->debugUtilsCmdBufLabels = new std::unordered_map<VkCommandBuffer, std::vector<LoggingLabelData>>;
+    debug_data->queueLabelHasInsert = false;
+    debug_data->cmdBufLabelHasInsert = false;
     return debug_data;
 }
 
-static inline void layer_debug_report_destroy_instance(debug_report_data *debug_data) {
+static inline void layer_debug_utils_destroy_instance(debug_report_data *debug_data) {
     if (debug_data) {
         RemoveAllMessageCallbacks(debug_data, &debug_data->default_debug_callback_list);
         RemoveAllMessageCallbacks(debug_data, &debug_data->debug_callback_list);
         delete debug_data->debugObjectNameMap;
+        delete debug_data->debugUtilsObjectNameMap;
+        delete debug_data->debugUtilsQueueLabels;
+        delete debug_data->debugUtilsCmdBufLabels;
         free(debug_data);
     }
 }
 
-static inline debug_report_data *layer_debug_report_create_device(debug_report_data *instance_debug_data, VkDevice device) {
+static inline debug_report_data *layer_debug_utils_create_device(debug_report_data *instance_debug_data, VkDevice device) {
     // DEBUG_REPORT shares data between Instance and Device,
     // so just return instance's data pointer
     return instance_debug_data;
 }
 
-static inline void layer_debug_report_destroy_device(VkDevice device) {
+static inline void layer_debug_utils_destroy_device(VkDevice device) {
     // Nothing to do since we're using instance data record
 }
 
-static inline void layer_destroy_msg_callback(debug_report_data *debug_data, VkDebugReportCallbackEXT callback,
-                                              const VkAllocationCallbacks *pAllocator) {
-    RemoveDebugMessageCallback(debug_data, &debug_data->debug_callback_list, callback);
-    RemoveDebugMessageCallback(debug_data, &debug_data->default_debug_callback_list, callback);
+static inline void layer_destroy_messenger_callback(debug_report_data *debug_data, VkDebugUtilsMessengerEXT messenger,
+                                                    const VkAllocationCallbacks *allocator) {
+    RemoveDebugUtilsMessenger(debug_data, &debug_data->debug_callback_list, messenger);
+    RemoveDebugUtilsMessenger(debug_data, &debug_data->default_debug_callback_list, messenger);
 }
 
-static inline VkResult layer_create_msg_callback(debug_report_data *debug_data, bool default_callback,
-                                                 const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
-                                                 const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT *pCallback) {
+static inline VkResult layer_create_messenger_callback(debug_report_data *debug_data, bool default_callback,
+                                                       const VkDebugUtilsMessengerCreateInfoEXT *create_info,
+                                                       const VkAllocationCallbacks *allocator,
+                                                       VkDebugUtilsMessengerEXT *messenger) {
     VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode *)malloc(sizeof(VkLayerDbgFunctionNode));
     if (!pNewDbgFuncNode) return VK_ERROR_OUT_OF_HOST_MEMORY;
+    memset(pNewDbgFuncNode, 0, sizeof(VkLayerDbgFunctionNode));
+    pNewDbgFuncNode->is_messenger = true;
 
     // Handle of 0 is logging_callback so use allocated Node address as unique handle
-    if (!(*pCallback)) *pCallback = (VkDebugReportCallbackEXT)pNewDbgFuncNode;
-    pNewDbgFuncNode->msgCallback = *pCallback;
-    pNewDbgFuncNode->pfnMsgCallback = pCreateInfo->pfnCallback;
-    pNewDbgFuncNode->msgFlags = pCreateInfo->flags;
-    pNewDbgFuncNode->pUserData = pCreateInfo->pUserData;
+    if (!(*messenger)) *messenger = (VkDebugUtilsMessengerEXT)pNewDbgFuncNode;
+    pNewDbgFuncNode->messenger.messenger = *messenger;
+    pNewDbgFuncNode->messenger.pfnUserCallback = create_info->pfnUserCallback;
+    pNewDbgFuncNode->messenger.messageSeverity = create_info->messageSeverity;
+    pNewDbgFuncNode->messenger.messageType = create_info->messageType;
+    pNewDbgFuncNode->pUserData = create_info->pUserData;
 
+    debug_data->active_severities |= create_info->messageSeverity;
+    debug_data->active_types |= create_info->messageType;
     if (default_callback) {
-        AddDebugMessageCallback(debug_data, &debug_data->default_debug_callback_list, pNewDbgFuncNode);
-        debug_data->active_flags |= pCreateInfo->flags;
+        AddDebugCallbackNode(debug_data, &debug_data->default_debug_callback_list, pNewDbgFuncNode);
     } else {
-        AddDebugMessageCallback(debug_data, &debug_data->debug_callback_list, pNewDbgFuncNode);
-        debug_data->active_flags = pCreateInfo->flags;
+        AddDebugCallbackNode(debug_data, &debug_data->debug_callback_list, pNewDbgFuncNode);
     }
 
-    debug_report_log_msg(debug_data, VK_DEBUG_REPORT_DEBUG_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
-                         (uint64_t)*pCallback, 0, 0, "DebugReport", "Added callback");
+    VkDebugUtilsMessengerCallbackDataEXT callback_data = {};
+    VkDebugUtilsObjectNameInfoEXT blank_object = {};
+    callback_data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT;
+    callback_data.pNext = NULL;
+    callback_data.flags = 0;
+    callback_data.pMessageIdName = "Layer Internal Message";
+    callback_data.messageIdNumber = 0;
+    callback_data.pMessage = "Added messenger";
+    callback_data.queueLabelCount = 0;
+    callback_data.pQueueLabels = NULL;
+    callback_data.cmdBufLabelCount = 0;
+    callback_data.pCmdBufLabels = NULL;
+    callback_data.objectCount = 1;
+    callback_data.pObjects = &blank_object;
+    blank_object.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
+    blank_object.pNext = NULL;
+    blank_object.objectType = VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT;
+    blank_object.objectHandle = HandleToUint64(*messenger);
+    blank_object.pObjectName = NULL;
+    debug_messenger_log_msg(debug_data, VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT,
+                            VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT, &callback_data);
     return VK_SUCCESS;
 }
 
-static inline PFN_vkVoidFunction debug_report_get_instance_proc_addr(debug_report_data *debug_data, const char *funcName) {
-    if (!debug_data || !debug_data->g_DEBUG_REPORT) {
-        return NULL;
+static inline void layer_destroy_report_callback(debug_report_data *debug_data, VkDebugReportCallbackEXT callback,
+                                                 const VkAllocationCallbacks *allocator) {
+    RemoveDebugUtilsMessageCallback(debug_data, &debug_data->debug_callback_list, callback);
+    RemoveDebugUtilsMessageCallback(debug_data, &debug_data->default_debug_callback_list, callback);
+}
+
+static inline VkResult layer_create_report_callback(debug_report_data *debug_data, bool default_callback,
+                                                    const VkDebugReportCallbackCreateInfoEXT *create_info,
+                                                    const VkAllocationCallbacks *allocator, VkDebugReportCallbackEXT *callback) {
+    VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode *)malloc(sizeof(VkLayerDbgFunctionNode));
+    if (!pNewDbgFuncNode) {
+        return VK_ERROR_OUT_OF_HOST_MEMORY;
+    }
+    memset(pNewDbgFuncNode, 0, sizeof(VkLayerDbgFunctionNode));
+    pNewDbgFuncNode->is_messenger = false;
+
+    // Handle of 0 is logging_callback so use allocated Node address as unique handle
+    if (!(*callback)) *callback = (VkDebugReportCallbackEXT)pNewDbgFuncNode;
+    pNewDbgFuncNode->report.msgCallback = *callback;
+    pNewDbgFuncNode->report.pfnMsgCallback = create_info->pfnCallback;
+    pNewDbgFuncNode->report.msgFlags = create_info->flags;
+    pNewDbgFuncNode->pUserData = create_info->pUserData;
+
+    VkFlags local_severity = 0;
+    VkFlags local_type = 0;
+    DebugReportFlagsToAnnotFlags(create_info->flags, true, &local_severity, &local_type);
+    debug_data->active_severities |= local_severity;
+    debug_data->active_types |= local_type;
+    if (default_callback) {
+        AddDebugCallbackNode(debug_data, &debug_data->default_debug_callback_list, pNewDbgFuncNode);
+    } else {
+        AddDebugCallbackNode(debug_data, &debug_data->debug_callback_list, pNewDbgFuncNode);
     }
 
-    if (!strcmp(funcName, "vkCreateDebugReportCallbackEXT")) {
-        return (PFN_vkVoidFunction)vkCreateDebugReportCallbackEXT;
+    debug_log_msg(debug_data, VK_DEBUG_REPORT_DEBUG_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT, (uint64_t)*callback, 0,
+                  0, "DebugReport", "Added callback");
+    return VK_SUCCESS;
+}
+
+static inline PFN_vkVoidFunction debug_utils_get_instance_proc_addr(debug_report_data *debug_data, const char *func_name) {
+    if (!debug_data) {
+        return NULL;
     }
-    if (!strcmp(funcName, "vkDestroyDebugReportCallbackEXT")) {
-        return (PFN_vkVoidFunction)vkDestroyDebugReportCallbackEXT;
+    if (debug_data->g_DEBUG_REPORT) {
+        if (!strcmp(func_name, "vkCreateDebugReportCallbackEXT")) {
+            return (PFN_vkVoidFunction)vkCreateDebugReportCallbackEXT;
+        }
+        if (!strcmp(func_name, "vkDestroyDebugReportCallbackEXT")) {
+            return (PFN_vkVoidFunction)vkDestroyDebugReportCallbackEXT;
+        }
+        if (!strcmp(func_name, "vkDebugReportMessageEXT")) {
+            return (PFN_vkVoidFunction)vkDebugReportMessageEXT;
+        }
     }
-    if (!strcmp(funcName, "vkDebugReportMessageEXT")) {
-        return (PFN_vkVoidFunction)vkDebugReportMessageEXT;
+    if (debug_data->g_DEBUG_UTILS) {
+        if (!strcmp(func_name, "vkCreateDebugUtilsMessengerEXT")) {
+            return (PFN_vkVoidFunction)vkCreateDebugUtilsMessengerEXT;
+        }
+        if (!strcmp(func_name, "vkDestroyDebugUtilsMessengerEXT")) {
+            return (PFN_vkVoidFunction)vkDestroyDebugUtilsMessengerEXT;
+        }
+        if (!strcmp(func_name, "vkSubmitDebugUtilsMessageEXT")) {
+            return (PFN_vkVoidFunction)vkSubmitDebugUtilsMessageEXT;
+        }
     }
     return NULL;
 }
@@ -235,8 +593,9 @@
 // then allocates an array that can hold that many structs, as well as that
 // many VkDebugReportCallbackEXT handles.  It then copies each
 // VkDebugReportCallbackCreateInfoEXT, and initializes each handle.
-static inline VkResult layer_copy_tmp_callbacks(const void *pChain, uint32_t *num_callbacks,
-                                                VkDebugReportCallbackCreateInfoEXT **infos, VkDebugReportCallbackEXT **callbacks) {
+static inline VkResult layer_copy_tmp_report_callbacks(const void *pChain, uint32_t *num_callbacks,
+                                                       VkDebugReportCallbackCreateInfoEXT **infos,
+                                                       VkDebugReportCallbackEXT **callbacks) {
     uint32_t n = *num_callbacks = 0;
 
     const void *pNext = pChain;
@@ -279,22 +638,23 @@
     return VK_SUCCESS;
 }
 
-// This utility frees the arrays allocated by layer_copy_tmp_callbacks()
-static inline void layer_free_tmp_callbacks(VkDebugReportCallbackCreateInfoEXT *infos, VkDebugReportCallbackEXT *callbacks) {
+// This utility frees the arrays allocated by layer_copy_tmp_report_callbacks()
+static inline void layer_free_tmp_report_callbacks(VkDebugReportCallbackCreateInfoEXT *infos, VkDebugReportCallbackEXT *callbacks) {
     free(infos);
     free(callbacks);
 }
 
 // This utility enables all of the VkDebugReportCallbackCreateInfoEXT structs
-// that were copied by layer_copy_tmp_callbacks()
-static inline VkResult layer_enable_tmp_callbacks(debug_report_data *debug_data, uint32_t num_callbacks,
-                                                  VkDebugReportCallbackCreateInfoEXT *infos, VkDebugReportCallbackEXT *callbacks) {
+// that were copied by layer_copy_tmp_report_callbacks()
+static inline VkResult layer_enable_tmp_report_callbacks(debug_report_data *debug_data, uint32_t num_callbacks,
+                                                         VkDebugReportCallbackCreateInfoEXT *infos,
+                                                         VkDebugReportCallbackEXT *callbacks) {
     VkResult rtn = VK_SUCCESS;
     for (uint32_t i = 0; i < num_callbacks; i++) {
-        rtn = layer_create_msg_callback(debug_data, false, &infos[i], NULL, &callbacks[i]);
+        rtn = layer_create_report_callback(debug_data, false, &infos[i], NULL, &callbacks[i]);
         if (rtn != VK_SUCCESS) {
             for (uint32_t j = 0; j < i; j++) {
-                layer_destroy_msg_callback(debug_data, callbacks[j], NULL);
+                layer_destroy_report_callback(debug_data, callbacks[j], NULL);
             }
             return rtn;
         }
@@ -303,19 +663,104 @@
 }
 
 // This utility disables all of the VkDebugReportCallbackCreateInfoEXT structs
-// that were copied by layer_copy_tmp_callbacks()
-static inline void layer_disable_tmp_callbacks(debug_report_data *debug_data, uint32_t num_callbacks,
-                                               VkDebugReportCallbackEXT *callbacks) {
+// that were copied by layer_copy_tmp_report_callbacks()
+static inline void layer_disable_tmp_report_callbacks(debug_report_data *debug_data, uint32_t num_callbacks,
+                                                      VkDebugReportCallbackEXT *callbacks) {
     for (uint32_t i = 0; i < num_callbacks; i++) {
-        layer_destroy_msg_callback(debug_data, callbacks[i], NULL);
+        layer_destroy_report_callback(debug_data, callbacks[i], NULL);
+    }
+}
+
+// This utility (called at vkCreateInstance() time), looks at a pNext chain.
+// It counts any VkDebugUtilsMessengerCreateInfoEXT structs that it finds.  It
+// then allocates an array that can hold that many structs, as well as that
+// many VkDebugUtilsMessengerEXT handles.  It then copies each
+// VkDebugUtilsMessengerCreateInfoEXT, and initializes each handle.
+static VkResult layer_copy_tmp_debug_messengers(const void *pChain, uint32_t *num_messengers,
+                                                VkDebugUtilsMessengerCreateInfoEXT **infos, VkDebugUtilsMessengerEXT **messengers) {
+    uint32_t n = *num_messengers = 0;
+
+    const void *pNext = pChain;
+    while (pNext) {
+        // 1st, count the number VkDebugUtilsMessengerCreateInfoEXT:
+        if (((VkDebugUtilsMessengerCreateInfoEXT *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) {
+            n++;
+        }
+        pNext = (void *)((VkDebugUtilsMessengerCreateInfoEXT *)pNext)->pNext;
+    }
+    if (n == 0) {
+        return VK_SUCCESS;
+    }
+
+    // 2nd, allocate memory for each VkDebugUtilsMessengerCreateInfoEXT:
+    VkDebugUtilsMessengerCreateInfoEXT *pInfos = *infos =
+        ((VkDebugUtilsMessengerCreateInfoEXT *)malloc(n * sizeof(VkDebugUtilsMessengerCreateInfoEXT)));
+    if (!pInfos) {
+        return VK_ERROR_OUT_OF_HOST_MEMORY;
+    }
+    // 3rd, allocate memory for a unique handle for each messenger:
+    VkDebugUtilsMessengerEXT *pMessengers = *messengers =
+        ((VkDebugUtilsMessengerEXT *)malloc(n * sizeof(VkDebugUtilsMessengerEXT)));
+    if (!pMessengers) {
+        free(pInfos);
+        return VK_ERROR_OUT_OF_HOST_MEMORY;
+    }
+    // 4th, copy each VkDebugUtilsMessengerCreateInfoEXT for use by
+    // vkDestroyInstance, and assign a unique handle to each callback (just
+    // use the address of the copied VkDebugUtilsMessengerCreateInfoEXT):
+    pNext = pChain;
+    while (pNext) {
+        if (((VkInstanceCreateInfo *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) {
+            memcpy(pInfos, pNext, sizeof(VkDebugUtilsMessengerCreateInfoEXT));
+            *pMessengers++ = (VkDebugUtilsMessengerEXT)pInfos++;
+        }
+        pNext = (void *)((VkInstanceCreateInfo *)pNext)->pNext;
+    }
+
+    *num_messengers = n;
+    return VK_SUCCESS;
+}
+
+// This utility frees the arrays allocated by layer_copy_tmp_debug_messengers()
+static void layer_free_tmp_debug_messengers(VkDebugUtilsMessengerCreateInfoEXT *infos, VkDebugUtilsMessengerEXT *messengers) {
+    free(infos);
+    free(messengers);
+}
+
+// This utility enables all of the VkDebugUtilsMessengerCreateInfoEXT structs
+// that were copied by layer_copy_tmp_debug_messengers()
+static VkResult layer_enable_tmp_debug_messengers(debug_report_data *debug_data, uint32_t num_messengers,
+                                                  VkDebugUtilsMessengerCreateInfoEXT *infos, VkDebugUtilsMessengerEXT *messengers) {
+    VkResult rtn = VK_SUCCESS;
+    for (uint32_t i = 0; i < num_messengers; i++) {
+        rtn = layer_create_messenger_callback(debug_data, false, &infos[i], NULL, &messengers[i]);
+        if (rtn != VK_SUCCESS) {
+            for (uint32_t j = 0; j < i; j++) {
+                layer_destroy_messenger_callback(debug_data, messengers[j], NULL);
+            }
+            return rtn;
+        }
+    }
+    return rtn;
+}
+
+// This utility disables all of the VkDebugUtilsMessengerCreateInfoEXT structs
+// that were copied by layer_copy_tmp_debug_messengers()
+static void layer_disable_tmp_debug_messengers(debug_report_data *debug_data, uint32_t num_messengers,
+                                               VkDebugUtilsMessengerEXT *messengers) {
+    for (uint32_t i = 0; i < num_messengers; i++) {
+        layer_destroy_messenger_callback(debug_data, messengers[i], NULL);
     }
 }
 
 // Checks if the message will get logged.
 // Allows layer to defer collecting & formating data if the
 // message will be discarded.
-static inline bool will_log_msg(debug_report_data *debug_data, VkFlags msgFlags) {
-    if (!debug_data || !(debug_data->active_flags & msgFlags)) {
+static inline bool will_log_msg(debug_report_data *debug_data, VkFlags msg_flags) {
+    VkFlags local_severity = 0;
+    VkFlags local_type = 0;
+    DebugReportFlagsToAnnotFlags(msg_flags, true, &local_severity, &local_type);
+    if (!debug_data || !(debug_data->active_severities & local_severity) || !(debug_data->active_types & local_type)) {
         // Message is not wanted
         return false;
     }
@@ -358,14 +803,17 @@
 // Takes format and variable arg list so that output string
 // is only computed if a message needs to be logged
 #ifndef WIN32
-static inline bool log_msg(const debug_report_data *debug_data, VkFlags msgFlags, VkDebugReportObjectTypeEXT objectType,
-                           uint64_t srcObject, size_t location, int32_t msgCode, const char *pLayerPrefix, const char *format, ...)
-    __attribute__((format(printf, 8, 9)));
+static inline bool log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type,
+                           uint64_t src_object, size_t location, int32_t msg_code, const char *layer_prefix, const char *format,
+                           ...) __attribute__((format(printf, 8, 9)));
 #endif
-static inline bool log_msg(const debug_report_data *debug_data, VkFlags msgFlags, VkDebugReportObjectTypeEXT objectType,
-                           uint64_t srcObject, size_t location, int32_t msgCode, const char *pLayerPrefix, const char *format,
+static inline bool log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type,
+                           uint64_t src_object, size_t location, int32_t msg_code, const char *layer_prefix, const char *format,
                            ...) {
-    if (!debug_data || !(debug_data->active_flags & msgFlags)) {
+    VkFlags local_severity = 0;
+    VkFlags local_type = 0;
+    DebugReportFlagsToAnnotFlags(msg_flags, true, &local_severity, &local_type);
+    if (!debug_data || !(debug_data->active_severities & local_severity) || !(debug_data->active_types & local_type)) {
         // Message is not wanted
         return false;
     }
@@ -378,37 +826,38 @@
         str = nullptr;
     }
     va_end(argptr);
-    bool result = debug_report_log_msg(debug_data, msgFlags, objectType, srcObject, location, msgCode, pLayerPrefix,
-                                       str ? str : "Allocation failure");
+    bool result = debug_log_msg(debug_data, msg_flags, object_type, src_object, location, msg_code, layer_prefix,
+                                str ? str : "Allocation failure");
     free(str);
     return result;
 }
 
-static inline VKAPI_ATTR VkBool32 VKAPI_CALL log_callback(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject,
-                                                          size_t location, int32_t msgCode, const char *pLayerPrefix,
-                                                          const char *pMsg, void *pUserData) {
-    char msg_flags[30];
+static inline VKAPI_ATTR VkBool32 VKAPI_CALL report_log_callback(VkFlags msg_flags, VkDebugReportObjectTypeEXT obj_type,
+                                                                 uint64_t src_object, size_t location, int32_t msg_code,
+                                                                 const char *layer_prefix, const char *message, void *user_data) {
+    char msg_flag_string[30];
 
-    print_msg_flags(msgFlags, msg_flags);
+    PrintMessageFlags(msg_flags, msg_flag_string);
 
-    fprintf((FILE *)pUserData, "%s(%s): object: 0x%" PRIx64 " type: %d location: %lu msgCode: %d: %s\n", pLayerPrefix, msg_flags,
-            srcObject, objType, (unsigned long)location, msgCode, pMsg);
-    fflush((FILE *)pUserData);
+    fprintf((FILE *)user_data, "%s(%s): object: 0x%" PRIx64 " type: %d location: %lu msg_code: %d: %s\n", layer_prefix,
+            msg_flag_string, src_object, obj_type, (unsigned long)location, msg_code, message);
+    fflush((FILE *)user_data);
 
     return false;
 }
 
-static inline VKAPI_ATTR VkBool32 VKAPI_CALL win32_debug_output_msg(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType,
-                                                                    uint64_t srcObject, size_t location, int32_t msgCode,
-                                                                    const char *pLayerPrefix, const char *pMsg, void *pUserData) {
+static inline VKAPI_ATTR VkBool32 VKAPI_CALL report_win32_debug_output_msg(VkFlags msg_flags, VkDebugReportObjectTypeEXT obj_type,
+                                                                           uint64_t src_object, size_t location, int32_t msg_code,
+                                                                           const char *layer_prefix, const char *message,
+                                                                           void *user_data) {
 #ifdef WIN32
-    char msg_flags[30];
+    char msg_flag_string[30];
     char buf[2048];
 
-    print_msg_flags(msgFlags, msg_flags);
+    PrintMessageFlags(msg_flags, msg_flag_string);
     _snprintf(buf, sizeof(buf) - 1,
-              "%s (%s): object: 0x%" PRIxPTR " type: %d location: " PRINTF_SIZE_T_SPECIFIER " msgCode: %d: %s\n", pLayerPrefix,
-              msg_flags, (size_t)srcObject, objType, location, msgCode, pMsg);
+              "%s (%s): object: 0x%" PRIxPTR " type: %d location: " PRINTF_SIZE_T_SPECIFIER " msg_code: %d: %s\n", layer_prefix,
+              msg_flag_string, (size_t)src_object, obj_type, location, msg_code, message);
 
     OutputDebugString(buf);
 #endif
@@ -416,9 +865,9 @@
     return false;
 }
 
-static inline VKAPI_ATTR VkBool32 VKAPI_CALL DebugBreakCallback(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType,
-                                                                uint64_t srcObject, size_t location, int32_t msgCode,
-                                                                const char *pLayerPrefix, const char *pMsg, void *pUserData) {
+static inline VKAPI_ATTR VkBool32 VKAPI_CALL DebugBreakCallback(VkFlags msgFlags, VkDebugReportObjectTypeEXT obj_type,
+                                                                uint64_t src_object, size_t location, int32_t msg_code,
+                                                                const char *layer_prefix, const char *message, void *user_data) {
 #ifdef WIN32
     DebugBreak();
 #else
@@ -428,15 +877,177 @@
     return false;
 }
 
-// TODO: Could be autogenerated for the specific handles for extra type safety...
-template <typename HANDLE_T>
-static inline uint64_t HandleToUint64(HANDLE_T *h) {
-    return reinterpret_cast<uint64_t>(h);
+static inline VKAPI_ATTR VkBool32 VKAPI_CALL messenger_log_callback(VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,
+                                                                    VkDebugUtilsMessageTypeFlagsEXT message_type,
+                                                                    const VkDebugUtilsMessengerCallbackDataEXT *callback_data,
+                                                                    void *user_data) {
+    char msg_severity[30];
+    char msg_type[30];
+
+    PrintMessageSeverity(message_severity, msg_severity);
+    PrintMessageType(message_type, msg_type);
+
+    fprintf((FILE *)user_data, "%s(%s / %s): object: 0x%" PRIx64 " type: %d msgNum: %d - %s\n", callback_data->pMessageIdName,
+            msg_severity, msg_type, callback_data->pObjects[0].objectHandle, callback_data->pObjects[0].objectType,
+            callback_data->messageIdNumber, callback_data->pMessage);
+    fflush((FILE *)user_data);
+
+    return false;
 }
 
-template <typename HANDLE_T>
-uint64_t HandleToUint64(HANDLE_T h);
+static inline VKAPI_ATTR VkBool32 VKAPI_CALL messenger_win32_debug_output_msg(
+    VkDebugUtilsMessageSeverityFlagBitsEXT message_severity, VkDebugUtilsMessageTypeFlagsEXT message_type,
+    const VkDebugUtilsMessengerCallbackDataEXT *callback_data, void *user_data) {
+#ifdef WIN32
+    char buf[2048];
+    char msg_severity[30];
+    char msg_type[30];
 
-static inline uint64_t HandleToUint64(uint64_t h) { return h; }
+    PrintMessageSeverity(message_severity, msg_severity);
+    PrintMessageType(message_type, msg_type);
+
+    _snprintf(buf, sizeof(buf) - 1, "%s (%s / %s): object: 0x%" PRIxPTR " type: %d  msgNum: %d - %s\n",
+              callback_data->pMessageIdName, msg_severity, msg_type, callback_data->pObjects[0].objectHandle,
+              callback_data->pObjects[0].objectType, callback_data->messageIdNumber, callback_data->pMessage);
+
+    OutputDebugString(buf);
+#endif
+
+    return false;
+}
+
+// This utility converts from the VkDebugUtilsLabelEXT structure into the logging version of the structure.
+// In the logging version, we only record what we absolutely need to convey back to the callbacks.
+static inline void InsertLabelIntoLog(const VkDebugUtilsLabelEXT *utils_label, std::vector<LoggingLabelData> &log_vector) {
+    LoggingLabelData log_label_data = {};
+    log_label_data.name = utils_label->pLabelName;
+    log_label_data.color[0] = utils_label->color[0];
+    log_label_data.color[1] = utils_label->color[1];
+    log_label_data.color[2] = utils_label->color[2];
+    log_label_data.color[3] = utils_label->color[3];
+    log_vector.push_back(log_label_data);
+}
+
+static void BeginQueueDebugUtilsLabel(debug_report_data *report_data, VkQueue queue, const VkDebugUtilsLabelEXT *label_info) {
+    if (nullptr != label_info && nullptr != label_info->pLabelName) {
+        auto label_iter = report_data->debugUtilsQueueLabels->find(queue);
+        if (label_iter == report_data->debugUtilsQueueLabels->end()) {
+            std::vector<LoggingLabelData> new_queue_labels;
+            InsertLabelIntoLog(label_info, new_queue_labels);
+            report_data->debugUtilsQueueLabels->insert({queue, new_queue_labels});
+        } else {
+            // If the last thing was a label insert, we need to pop it off of the label vector before any
+            // changes. This is because a label added with "vkQueueInsertDebugUtilsLabelEXT" is only a
+            // temporary location that exists until the next operation occurs.  In this case, a new
+            // "vkQueueBeginDebugUtilsLabelEXT" has occurred erasing the previous inserted label.
+            if (report_data->queueLabelHasInsert) {
+                report_data->queueLabelHasInsert = false;
+                label_iter->second.pop_back();
+            }
+            InsertLabelIntoLog(label_info, label_iter->second);
+        }
+    }
+}
+
+static void EndQueueDebugUtilsLabel(debug_report_data *report_data, VkQueue queue) {
+    auto label_iter = report_data->debugUtilsQueueLabels->find(queue);
+    if (label_iter != report_data->debugUtilsQueueLabels->end()) {
+        // If the last thing was a label insert, we need to pop it off of the label vector before any
+        // changes. This is because a label added with "vkQueueInsertDebugUtilsLabelEXT" is only a
+        // temporary location that exists until the next operation occurs.  In this case, a
+        // "vkQueueEndDebugUtilsLabelEXT" has occurred erasing the inserted label.
+        if (report_data->queueLabelHasInsert) {
+            report_data->queueLabelHasInsert = false;
+            label_iter->second.pop_back();
+        }
+        // Now pop the normal item
+        label_iter->second.pop_back();
+    }
+}
+
+static void InsertQueueDebugUtilsLabel(debug_report_data *report_data, VkQueue queue, const VkDebugUtilsLabelEXT *label_info) {
+    if (nullptr != label_info && nullptr != label_info->pLabelName) {
+        auto label_iter = report_data->debugUtilsQueueLabels->find(queue);
+        if (label_iter == report_data->debugUtilsQueueLabels->end()) {
+            std::vector<LoggingLabelData> new_queue_labels;
+            InsertLabelIntoLog(label_info, new_queue_labels);
+            report_data->debugUtilsQueueLabels->insert({queue, new_queue_labels});
+        } else {
+            // If the last thing was a label insert, we need to pop it off of the label vector before any
+            // changes. This is because a label added with "vkQueueInsertDebugUtilsLabelEXT" is only a
+            // temporary location that exists until the next operation occurs.  In this case, a new
+            // "vkQueueInsertDebugUtilsLabelEXT" has occurred erasing the previous inserted label.
+            if (report_data->queueLabelHasInsert) {
+                label_iter->second.pop_back();
+            }
+            // Insert this new label and mark it as one that has been "inserted" so we can remove it on
+            // the next queue label operation.
+            InsertLabelIntoLog(label_info, label_iter->second);
+            report_data->queueLabelHasInsert = true;
+        }
+    }
+}
+
+static void BeginCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer,
+                                    const VkDebugUtilsLabelEXT *label_info) {
+    if (nullptr != label_info && nullptr != label_info->pLabelName) {
+        auto label_iter = report_data->debugUtilsCmdBufLabels->find(command_buffer);
+        if (label_iter == report_data->debugUtilsCmdBufLabels->end()) {
+            std::vector<LoggingLabelData> new_cmdbuf_labels;
+            InsertLabelIntoLog(label_info, new_cmdbuf_labels);
+            report_data->debugUtilsCmdBufLabels->insert({command_buffer, new_cmdbuf_labels});
+        } else {
+            // If the last thing was a label insert, we need to pop it off of the label vector before any
+            // changes. This is because a label added with "vkCmdInsertDebugUtilsLabelEXT" is only a
+            // temporary location that exists until the next operation occurs.  In this case, a
+            // "vkCmdBeginDebugUtilsLabelEXT" has occurred erasing the inserted label.
+            if (report_data->cmdBufLabelHasInsert) {
+                report_data->cmdBufLabelHasInsert = false;
+                label_iter->second.pop_back();
+            }
+            InsertLabelIntoLog(label_info, label_iter->second);
+        }
+    }
+}
+
+static void EndCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer) {
+    auto label_iter = report_data->debugUtilsCmdBufLabels->find(command_buffer);
+    if (label_iter != report_data->debugUtilsCmdBufLabels->end()) {
+        // If the last thing was a label insert, we need to pop it off of the label vector before any
+        // changes. This is because a label added with "vkCmdInsertDebugUtilsLabelEXT" is only a
+        // temporary location that exists until the next operation occurs.  In this case, a
+        // "vkCmdEndDebugUtilsLabelEXT" has occurred erasing the inserted label.
+        if (report_data->cmdBufLabelHasInsert) {
+            report_data->cmdBufLabelHasInsert = false;
+            label_iter->second.pop_back();
+        }
+        // Now pop the normal item
+        label_iter->second.pop_back();
+    }
+}
+
+static void InsertCmdDebugUtilsLabel(debug_report_data *report_data, VkCommandBuffer command_buffer,
+                                     const VkDebugUtilsLabelEXT *label_info) {
+    if (nullptr != label_info && nullptr != label_info->pLabelName) {
+        auto label_iter = report_data->debugUtilsCmdBufLabels->find(command_buffer);
+        if (label_iter == report_data->debugUtilsCmdBufLabels->end()) {
+            std::vector<LoggingLabelData> new_cmdbuf_labels;
+            InsertLabelIntoLog(label_info, new_cmdbuf_labels);
+            report_data->debugUtilsCmdBufLabels->insert({command_buffer, new_cmdbuf_labels});
+        } else {
+            // If the last thing was a label insert, we need to pop it off of the label vector before any
+            // changes. This is because a label added with "vkCmdInsertDebugUtilsLabelEXT" is only a
+            // temporary location that exists until the next operation occurs.  In this case, a new
+            // "vkCmdInsertDebugUtilsLabelEXT" has occurred erasing the previous inserted label.
+            if (report_data->cmdBufLabelHasInsert) {
+                label_iter->second.pop_back();
+            }
+            // Insert this new label and mark it as one that has been "inserted" so we can remove it on
+            // the next command buffer label operation.
+            InsertLabelIntoLog(label_info, label_iter->second);
+            report_data->cmdBufLabelHasInsert = true;
+        }
+    }
+}
 
 #endif  // LAYER_LOGGING_H
diff --git a/layers/vk_layer_utils.cpp b/layers/vk_layer_utils.cpp
index d788daf..629b19f 100644
--- a/layers/vk_layer_utils.cpp
+++ b/layers/vk_layer_utils.cpp
@@ -91,8 +91,9 @@
 // If a vk_layer_settings.txt file is present and an application defines a debug callback, both callbacks
 // will be active.  If no vk_layer_settings.txt file is present, creating an application-defined debug
 // callback will cause the default callbacks to be unregisterd and removed.
-VK_LAYER_EXPORT void layer_debug_actions(debug_report_data *report_data, std::vector<VkDebugReportCallbackEXT> &logging_callback,
-                                         const VkAllocationCallbacks *pAllocator, const char *layer_identifier) {
+VK_LAYER_EXPORT void layer_debug_report_actions(debug_report_data *report_data,
+                                                std::vector<VkDebugReportCallbackEXT> &logging_callback,
+                                                const VkAllocationCallbacks *pAllocator, const char *layer_identifier) {
     VkDebugReportCallbackEXT callback = VK_NULL_HANDLE;
 
     std::string report_flags_key = layer_identifier;
@@ -115,9 +116,9 @@
         memset(&dbgCreateInfo, 0, sizeof(dbgCreateInfo));
         dbgCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
         dbgCreateInfo.flags = report_flags;
-        dbgCreateInfo.pfnCallback = log_callback;
+        dbgCreateInfo.pfnCallback = report_log_callback;
         dbgCreateInfo.pUserData = (void *)log_output;
-        layer_create_msg_callback(report_data, default_layer_callback, &dbgCreateInfo, pAllocator, &callback);
+        layer_create_report_callback(report_data, default_layer_callback, &dbgCreateInfo, pAllocator, &callback);
         logging_callback.push_back(callback);
     }
 
@@ -128,9 +129,9 @@
         memset(&dbgCreateInfo, 0, sizeof(dbgCreateInfo));
         dbgCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
         dbgCreateInfo.flags = report_flags;
-        dbgCreateInfo.pfnCallback = win32_debug_output_msg;
+        dbgCreateInfo.pfnCallback = report_win32_debug_output_msg;
         dbgCreateInfo.pUserData = NULL;
-        layer_create_msg_callback(report_data, default_layer_callback, &dbgCreateInfo, pAllocator, &callback);
+        layer_create_report_callback(report_data, default_layer_callback, &dbgCreateInfo, pAllocator, &callback);
         logging_callback.push_back(callback);
     }
 
@@ -143,7 +144,64 @@
         dbgCreateInfo.flags = report_flags;
         dbgCreateInfo.pfnCallback = DebugBreakCallback;
         dbgCreateInfo.pUserData = NULL;
-        layer_create_msg_callback(report_data, default_layer_callback, &dbgCreateInfo, pAllocator, &callback);
+        layer_create_report_callback(report_data, default_layer_callback, &dbgCreateInfo, pAllocator, &callback);
         logging_callback.push_back(callback);
     }
 }
+
+VK_LAYER_EXPORT void layer_debug_messenger_actions(debug_report_data *report_data,
+                                                   std::vector<VkDebugUtilsMessengerEXT> &logging_messenger,
+                                                   const VkAllocationCallbacks *pAllocator, const char *layer_identifier) {
+    VkDebugUtilsMessengerEXT messenger = VK_NULL_HANDLE;
+
+    std::string report_flags_key = layer_identifier;
+    std::string debug_action_key = layer_identifier;
+    std::string log_filename_key = layer_identifier;
+    report_flags_key.append(".report_flags");
+    debug_action_key.append(".debug_action");
+    log_filename_key.append(".log_filename");
+
+    // Initialize layer options
+    VkDebugReportFlagsEXT report_flags = GetLayerOptionFlags(report_flags_key, report_flags_option_definitions, 0);
+    VkLayerDbgActionFlags debug_action = GetLayerOptionFlags(debug_action_key, debug_actions_option_definitions, 0);
+    // Flag as default if these settings are not from a vk_layer_settings.txt file
+    bool default_layer_callback = (debug_action & VK_DBG_LAYER_ACTION_DEFAULT) ? true : false;
+    VkDebugUtilsMessengerCreateInfoEXT dbgCreateInfo;
+    memset(&dbgCreateInfo, 0, sizeof(dbgCreateInfo));
+    dbgCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
+    dbgCreateInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
+    if (report_flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
+        dbgCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
+    }
+    if (report_flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
+        dbgCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
+    }
+    if (report_flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) {
+        dbgCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
+        dbgCreateInfo.messageType |= VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
+    }
+    if (report_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) {
+        dbgCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
+    }
+    if (report_flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) {
+        dbgCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
+    }
+
+    if (debug_action & VK_DBG_LAYER_ACTION_LOG_MSG) {
+        const char *log_filename = getLayerOption(log_filename_key.c_str());
+        FILE *log_output = getLayerLogOutput(log_filename, layer_identifier);
+        dbgCreateInfo.pfnUserCallback = messenger_log_callback;
+        dbgCreateInfo.pUserData = (void *)log_output;
+        layer_create_messenger_callback(report_data, default_layer_callback, &dbgCreateInfo, pAllocator, &messenger);
+        logging_messenger.push_back(messenger);
+    }
+
+    messenger = VK_NULL_HANDLE;
+
+    if (debug_action & VK_DBG_LAYER_ACTION_DEBUG_OUTPUT) {
+        dbgCreateInfo.pfnUserCallback = messenger_win32_debug_output_msg;
+        dbgCreateInfo.pUserData = NULL;
+        layer_create_messenger_callback(report_data, default_layer_callback, &dbgCreateInfo, pAllocator, &messenger);
+        logging_messenger.push_back(messenger);
+    }
+}
diff --git a/layers/vk_layer_utils.h b/layers/vk_layer_utils.h
index d1969c8..08574a5 100644
--- a/layers/vk_layer_utils.h
+++ b/layers/vk_layer_utils.h
@@ -37,10 +37,6 @@
 
 #define VK_LAYER_API_VERSION VK_MAKE_VERSION(1, 0, VK_HEADER_VERSION)
 
-
-
-
-
 typedef enum VkStringErrorFlagBits {
     VK_STRING_ERROR_NONE = 0x00000000,
     VK_STRING_ERROR_LENGTH = 0x00000001,
@@ -48,8 +44,13 @@
 } VkStringErrorFlagBits;
 typedef VkFlags VkStringErrorFlags;
 
-VK_LAYER_EXPORT void layer_debug_actions(debug_report_data *report_data, std::vector<VkDebugReportCallbackEXT> &logging_callback,
-                                         const VkAllocationCallbacks *pAllocator, const char *layer_identifier);
+VK_LAYER_EXPORT void layer_debug_report_actions(debug_report_data *report_data,
+                                                std::vector<VkDebugReportCallbackEXT> &logging_callback,
+                                                const VkAllocationCallbacks *pAllocator, const char *layer_identifier);
+
+VK_LAYER_EXPORT void layer_debug_messenger_actions(debug_report_data *report_data,
+                                                   std::vector<VkDebugUtilsMessengerEXT> &logging_messenger,
+                                                   const VkAllocationCallbacks *pAllocator, const char *layer_identifier);
 
 VK_LAYER_EXPORT VkStringErrorFlags vk_string_validate(const int max_length, const char *char_array);
 VK_LAYER_EXPORT bool white_list(const char *item, const char *whitelist);
diff --git a/loader/CMakeLists.txt b/loader/CMakeLists.txt
index 2f96665..f543f86 100644
--- a/loader/CMakeLists.txt
+++ b/loader/CMakeLists.txt
@@ -75,8 +75,8 @@
     trampoline.c
     wsi.c
     wsi.h
-    debug_report.c
-    debug_report.h
+    debug_utils.c
+    debug_utils.h
     gpa_helper.h
     cJSON.c
     cJSON.h
diff --git a/loader/debug_report.c b/loader/debug_report.c
deleted file mode 100644
index 04e55cc..0000000
--- a/loader/debug_report.c
+++ /dev/null
@@ -1,466 +0,0 @@
-/*
- * Copyright (c) 2015-2016 The Khronos Group Inc.
- * Copyright (c) 2015-2016 Valve Corporation
- * Copyright (c) 2015-2016 LunarG, Inc.
- * Copyright (C) 2015-2016 Google Inc.
- *
- * 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.
- *
- * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
- * Author: Jon Ashburn <jon@LunarG.com>
- *
- */
-
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <inttypes.h>
-#ifndef WIN32
-#include <signal.h>
-#else
-#endif
-#include "vk_loader_platform.h"
-#include "debug_report.h"
-#include "vulkan/vk_layer.h"
-
-typedef void(VKAPI_PTR *PFN_stringCallback)(char *message);
-
-static const VkExtensionProperties debug_report_extension_info = {
-    .extensionName = VK_EXT_DEBUG_REPORT_EXTENSION_NAME, .specVersion = VK_EXT_DEBUG_REPORT_SPEC_VERSION,
-};
-
-void debug_report_add_instance_extensions(const struct loader_instance *inst, struct loader_extension_list *ext_list) {
-    loader_add_to_ext_list(inst, ext_list, 1, &debug_report_extension_info);
-}
-
-void debug_report_create_instance(struct loader_instance *ptr_instance, const VkInstanceCreateInfo *pCreateInfo) {
-    ptr_instance->enabled_known_extensions.ext_debug_report = 0;
-
-    for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
-        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0) {
-            ptr_instance->enabled_known_extensions.ext_debug_report = 1;
-            return;
-        }
-    }
-}
-
-VkResult util_CreateDebugReportCallback(struct loader_instance *inst, VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
-                                        const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT callback) {
-    VkLayerDbgFunctionNode *pNewDbgFuncNode = NULL;
-
-#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
-    {
-#else
-    if (pAllocator != NULL) {
-        pNewDbgFuncNode = (VkLayerDbgFunctionNode *)pAllocator->pfnAllocation(pAllocator->pUserData, sizeof(VkLayerDbgFunctionNode),
-                                                                              sizeof(int *), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
-    } else {
-#endif
-        pNewDbgFuncNode = (VkLayerDbgFunctionNode *)loader_instance_heap_alloc(inst, sizeof(VkLayerDbgFunctionNode),
-                                                                               VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
-    }
-    if (!pNewDbgFuncNode) {
-        return VK_ERROR_OUT_OF_HOST_MEMORY;
-    }
-    memset(pNewDbgFuncNode, 0, sizeof(VkLayerDbgFunctionNode));
-
-    pNewDbgFuncNode->msgCallback = callback;
-    pNewDbgFuncNode->pfnMsgCallback = pCreateInfo->pfnCallback;
-    pNewDbgFuncNode->msgFlags = pCreateInfo->flags;
-    pNewDbgFuncNode->pUserData = pCreateInfo->pUserData;
-    pNewDbgFuncNode->pNext = inst->DbgFunctionHead;
-    inst->DbgFunctionHead = pNewDbgFuncNode;
-
-    return VK_SUCCESS;
-}
-
-static VKAPI_ATTR VkResult VKAPI_CALL
-debug_report_CreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
-                                          const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT *pCallback) {
-    struct loader_instance *inst = loader_get_instance(instance);
-    loader_platform_thread_lock_mutex(&loader_lock);
-    VkResult result = inst->disp->layer_inst_disp.CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pCallback);
-    loader_platform_thread_unlock_mutex(&loader_lock);
-    return result;
-}
-
-// Utility function to handle reporting
-VkBool32 util_DebugReportMessage(const struct loader_instance *inst, VkFlags msgFlags, VkDebugReportObjectTypeEXT objectType,
-                                 uint64_t srcObject, size_t location, int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
-    VkBool32 bail = false;
-    VkLayerDbgFunctionNode *pTrav = inst->DbgFunctionHead;
-    while (pTrav) {
-        if (pTrav->msgFlags & msgFlags) {
-            if (pTrav->pfnMsgCallback(msgFlags, objectType, srcObject, location, msgCode, pLayerPrefix, pMsg, pTrav->pUserData)) {
-                bail = true;
-            }
-        }
-        pTrav = pTrav->pNext;
-    }
-
-    return bail;
-}
-
-void util_DestroyDebugReportCallback(struct loader_instance *inst, VkDebugReportCallbackEXT callback,
-                                     const VkAllocationCallbacks *pAllocator) {
-    VkLayerDbgFunctionNode *pTrav = inst->DbgFunctionHead;
-    VkLayerDbgFunctionNode *pPrev = pTrav;
-
-    while (pTrav) {
-        if (pTrav->msgCallback == callback) {
-            pPrev->pNext = pTrav->pNext;
-            if (inst->DbgFunctionHead == pTrav) inst->DbgFunctionHead = pTrav->pNext;
-#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
-            {
-#else
-            if (pAllocator != NULL) {
-                pAllocator->pfnFree(pAllocator->pUserData, pTrav);
-            } else {
-#endif
-                loader_instance_heap_free(inst, pTrav);
-            }
-            break;
-        }
-        pPrev = pTrav;
-        pTrav = pTrav->pNext;
-    }
-}
-
-// This utility (used by vkInstanceCreateInfo(), looks at a pNext chain.  It
-// counts any VkDebugReportCallbackCreateInfoEXT structs that it finds.  It
-// then allocates array that can hold that many structs, as well as that many
-// VkDebugReportCallbackEXT handles.  It then copies each
-// VkDebugReportCallbackCreateInfoEXT, and initializes each handle.
-VkResult util_CopyDebugReportCreateInfos(const void *pChain, const VkAllocationCallbacks *pAllocator, uint32_t *num_callbacks,
-                                         VkDebugReportCallbackCreateInfoEXT **infos, VkDebugReportCallbackEXT **callbacks) {
-    uint32_t n = *num_callbacks = 0;
-    VkDebugReportCallbackCreateInfoEXT *pInfos = NULL;
-    VkDebugReportCallbackEXT *pCallbacks = NULL;
-
-    // NOTE: The loader is not using pAllocator, and so this function doesn't
-    // either.
-
-    const void *pNext = pChain;
-    while (pNext) {
-        // 1st, count the number VkDebugReportCallbackCreateInfoEXT:
-        if (((VkDebugReportCallbackCreateInfoEXT *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) {
-            n++;
-        }
-        pNext = (void *)((VkDebugReportCallbackCreateInfoEXT *)pNext)->pNext;
-    }
-    if (n == 0) {
-        return VK_SUCCESS;
-    }
-
-// 2nd, allocate memory for each VkDebugReportCallbackCreateInfoEXT:
-#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
-    {
-#else
-    if (pAllocator != NULL) {
-        pInfos = *infos = ((VkDebugReportCallbackCreateInfoEXT *)pAllocator->pfnAllocation(
-            pAllocator->pUserData, n * sizeof(VkDebugReportCallbackCreateInfoEXT), sizeof(void *),
-            VK_SYSTEM_ALLOCATION_SCOPE_OBJECT));
-    } else {
-#endif
-        pInfos = *infos = ((VkDebugReportCallbackCreateInfoEXT *)malloc(n * sizeof(VkDebugReportCallbackCreateInfoEXT)));
-    }
-    if (!pInfos) {
-        return VK_ERROR_OUT_OF_HOST_MEMORY;
-    }
-// 3rd, allocate memory for a unique handle for each callback:
-#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
-    {
-#else
-    if (pAllocator != NULL) {
-        pCallbacks = *callbacks = ((VkDebugReportCallbackEXT *)pAllocator->pfnAllocation(
-            pAllocator->pUserData, n * sizeof(VkDebugReportCallbackEXT), sizeof(void *), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT));
-        if (!pCallbacks) {
-            pAllocator->pfnFree(pAllocator->pUserData, pInfos);
-            return VK_ERROR_OUT_OF_HOST_MEMORY;
-        }
-    } else {
-#endif
-        pCallbacks = *callbacks = ((VkDebugReportCallbackEXT *)malloc(n * sizeof(VkDebugReportCallbackEXT)));
-        if (!pCallbacks) {
-            free(pInfos);
-            return VK_ERROR_OUT_OF_HOST_MEMORY;
-        }
-    }
-    // 4th, copy each VkDebugReportCallbackCreateInfoEXT for use by
-    // vkDestroyInstance, and assign a unique handle to each callback (just
-    // use the address of the copied VkDebugReportCallbackCreateInfoEXT):
-    pNext = pChain;
-    while (pNext) {
-        if (((VkInstanceCreateInfo *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) {
-            memcpy(pInfos, pNext, sizeof(VkDebugReportCallbackCreateInfoEXT));
-            *pCallbacks++ = (VkDebugReportCallbackEXT)(uintptr_t)pInfos++;
-        }
-        pNext = (void *)((VkInstanceCreateInfo *)pNext)->pNext;
-    }
-
-    *num_callbacks = n;
-    return VK_SUCCESS;
-}
-
-void util_FreeDebugReportCreateInfos(const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackCreateInfoEXT *infos,
-                                     VkDebugReportCallbackEXT *callbacks) {
-#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
-    {
-#else
-    if (pAllocator != NULL) {
-        pAllocator->pfnFree(pAllocator->pUserData, infos);
-        pAllocator->pfnFree(pAllocator->pUserData, callbacks);
-    } else {
-#endif
-        free(infos);
-        free(callbacks);
-    }
-}
-
-VkResult util_CreateDebugReportCallbacks(struct loader_instance *inst, const VkAllocationCallbacks *pAllocator,
-                                         uint32_t num_callbacks, VkDebugReportCallbackCreateInfoEXT *infos,
-                                         VkDebugReportCallbackEXT *callbacks) {
-    VkResult rtn = VK_SUCCESS;
-    for (uint32_t i = 0; i < num_callbacks; i++) {
-        rtn = util_CreateDebugReportCallback(inst, &infos[i], pAllocator, callbacks[i]);
-        if (rtn != VK_SUCCESS) {
-            for (uint32_t j = 0; j < i; j++) {
-                util_DestroyDebugReportCallback(inst, callbacks[j], pAllocator);
-            }
-            return rtn;
-        }
-    }
-    return rtn;
-}
-
-void util_DestroyDebugReportCallbacks(struct loader_instance *inst, const VkAllocationCallbacks *pAllocator, uint32_t num_callbacks,
-                                      VkDebugReportCallbackEXT *callbacks) {
-    for (uint32_t i = 0; i < num_callbacks; i++) {
-        util_DestroyDebugReportCallback(inst, callbacks[i], pAllocator);
-    }
-}
-
-static VKAPI_ATTR void VKAPI_CALL debug_report_DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback,
-                                                                             const VkAllocationCallbacks *pAllocator) {
-    struct loader_instance *inst = loader_get_instance(instance);
-    loader_platform_thread_lock_mutex(&loader_lock);
-
-    inst->disp->layer_inst_disp.DestroyDebugReportCallbackEXT(instance, callback, pAllocator);
-
-    util_DestroyDebugReportCallback(inst, callback, pAllocator);
-
-    loader_platform_thread_unlock_mutex(&loader_lock);
-}
-
-static VKAPI_ATTR void VKAPI_CALL debug_report_DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags,
-                                                                     VkDebugReportObjectTypeEXT objType, uint64_t object,
-                                                                     size_t location, int32_t msgCode, const char *pLayerPrefix,
-                                                                     const char *pMsg) {
-    struct loader_instance *inst = loader_get_instance(instance);
-
-    inst->disp->layer_inst_disp.DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, pMsg);
-}
-
-// This is the instance chain terminator function
-// for CreateDebugReportCallback
-VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDebugReportCallbackEXT(VkInstance instance,
-                                                                       const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
-                                                                       const VkAllocationCallbacks *pAllocator,
-                                                                       VkDebugReportCallbackEXT *pCallback) {
-    VkDebugReportCallbackEXT *icd_info = NULL;
-    const struct loader_icd_term *icd_term;
-    struct loader_instance *inst = (struct loader_instance *)instance;
-    VkResult res = VK_SUCCESS;
-    uint32_t storage_idx;
-    VkLayerDbgFunctionNode *pNewDbgFuncNode = NULL;
-
-#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
-    {
-#else
-    if (pAllocator != NULL) {
-        icd_info = ((VkDebugReportCallbackEXT *)pAllocator->pfnAllocation(pAllocator->pUserData,
-                                                                          inst->total_icd_count * sizeof(VkDebugReportCallbackEXT),
-                                                                          sizeof(void *), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT));
-        if (icd_info) {
-            memset(icd_info, 0, inst->total_icd_count * sizeof(VkDebugReportCallbackEXT));
-        }
-    } else {
-#endif
-        icd_info = calloc(sizeof(VkDebugReportCallbackEXT), inst->total_icd_count);
-    }
-    if (!icd_info) {
-        res = VK_ERROR_OUT_OF_HOST_MEMORY;
-        goto out;
-    }
-
-    storage_idx = 0;
-    for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) {
-        if (!icd_term->dispatch.CreateDebugReportCallbackEXT) {
-            continue;
-        }
-
-        res = icd_term->dispatch.CreateDebugReportCallbackEXT(icd_term->instance, pCreateInfo, pAllocator, &icd_info[storage_idx]);
-
-        if (res != VK_SUCCESS) {
-            goto out;
-        }
-        storage_idx++;
-    }
-
-// Setup the debug report callback in the terminator since a layer may want
-// to grab the information itself (RenderDoc) and then return back to the
-// user callback a sub-set of the messages.
-#if (DEBUG_DISABLE_APP_ALLOCATORS == 0)
-    if (pAllocator != NULL) {
-        pNewDbgFuncNode = (VkLayerDbgFunctionNode *)pAllocator->pfnAllocation(pAllocator->pUserData, sizeof(VkLayerDbgFunctionNode),
-                                                                              sizeof(int *), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
-    } else {
-#else
-    {
-#endif
-        pNewDbgFuncNode = (VkLayerDbgFunctionNode *)loader_instance_heap_alloc(inst, sizeof(VkLayerDbgFunctionNode),
-                                                                               VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
-    }
-    if (!pNewDbgFuncNode) {
-        res = VK_ERROR_OUT_OF_HOST_MEMORY;
-        goto out;
-    }
-    memset(pNewDbgFuncNode, 0, sizeof(VkLayerDbgFunctionNode));
-
-    pNewDbgFuncNode->pfnMsgCallback = pCreateInfo->pfnCallback;
-    pNewDbgFuncNode->msgFlags = pCreateInfo->flags;
-    pNewDbgFuncNode->pUserData = pCreateInfo->pUserData;
-    pNewDbgFuncNode->pNext = inst->DbgFunctionHead;
-    inst->DbgFunctionHead = pNewDbgFuncNode;
-
-    *(VkDebugReportCallbackEXT **)pCallback = icd_info;
-    pNewDbgFuncNode->msgCallback = *pCallback;
-
-out:
-
-    // Roll back on errors
-    if (VK_SUCCESS != res) {
-        storage_idx = 0;
-        for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) {
-            if (NULL == icd_term->dispatch.DestroyDebugReportCallbackEXT) {
-                continue;
-            }
-
-            if (icd_info && icd_info[storage_idx]) {
-                icd_term->dispatch.DestroyDebugReportCallbackEXT(icd_term->instance, icd_info[storage_idx], pAllocator);
-            }
-            storage_idx++;
-        }
-
-#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
-        {
-#else
-        if (pAllocator != NULL) {
-            if (NULL != pNewDbgFuncNode) {
-                pAllocator->pfnFree(pAllocator->pUserData, pNewDbgFuncNode);
-            }
-            if (NULL != icd_info) {
-                pAllocator->pfnFree(pAllocator->pUserData, icd_info);
-            }
-        } else {
-#endif
-            if (NULL != pNewDbgFuncNode) {
-                free(pNewDbgFuncNode);
-            }
-            if (NULL != icd_info) {
-                free(icd_info);
-            }
-        }
-    }
-
-    return res;
-}
-
-// This is the instance chain terminator function for DestroyDebugReportCallback
-VKAPI_ATTR void VKAPI_CALL terminator_DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback,
-                                                                    const VkAllocationCallbacks *pAllocator) {
-    uint32_t storage_idx;
-    VkDebugReportCallbackEXT *icd_info;
-    const struct loader_icd_term *icd_term;
-
-    struct loader_instance *inst = (struct loader_instance *)instance;
-    icd_info = *(VkDebugReportCallbackEXT **)&callback;
-    storage_idx = 0;
-    for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) {
-        if (NULL == icd_term->dispatch.DestroyDebugReportCallbackEXT) {
-            continue;
-        }
-
-        if (icd_info[storage_idx]) {
-            icd_term->dispatch.DestroyDebugReportCallbackEXT(icd_term->instance, icd_info[storage_idx], pAllocator);
-        }
-        storage_idx++;
-    }
-
-#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
-    {
-#else
-    if (pAllocator != NULL) {
-        pAllocator->pfnFree(pAllocator->pUserData, icd_info);
-    } else {
-#endif
-        free(icd_info);
-    }
-}
-
-// This is the instance chain terminator function for DebugReportMessage
-VKAPI_ATTR void VKAPI_CALL terminator_DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags,
-                                                            VkDebugReportObjectTypeEXT objType, uint64_t object, size_t location,
-                                                            int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
-    const struct loader_icd_term *icd_term;
-
-    struct loader_instance *inst = (struct loader_instance *)instance;
-
-    loader_platform_thread_lock_mutex(&loader_lock);
-    for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) {
-        if (icd_term->dispatch.DebugReportMessageEXT != NULL) {
-            icd_term->dispatch.DebugReportMessageEXT(icd_term->instance, flags, objType, object, location, msgCode, pLayerPrefix,
-                                                     pMsg);
-        }
-    }
-
-    // Now that all ICDs have seen the message, call the necessary callbacks.  Ignoring "bail" return value
-    // as there is nothing to bail from at this point.
-
-    util_DebugReportMessage(inst, flags, objType, object, location, msgCode, pLayerPrefix, pMsg);
-
-    loader_platform_thread_unlock_mutex(&loader_lock);
-}
-
-bool debug_report_instance_gpa(struct loader_instance *ptr_instance, const char *name, void **addr) {
-    // debug_report is currently advertised to be supported by the loader,
-    // so always return the entry points if name matches and it's enabled
-    *addr = NULL;
-
-    if (!strcmp("vkCreateDebugReportCallbackEXT", name)) {
-        *addr = (ptr_instance->enabled_known_extensions.ext_debug_report == 1) ? (void *)debug_report_CreateDebugReportCallbackEXT
-                                                                               : NULL;
-        return true;
-    }
-    if (!strcmp("vkDestroyDebugReportCallbackEXT", name)) {
-        *addr = (ptr_instance->enabled_known_extensions.ext_debug_report == 1) ? (void *)debug_report_DestroyDebugReportCallbackEXT
-                                                                               : NULL;
-        return true;
-    }
-    if (!strcmp("vkDebugReportMessageEXT", name)) {
-        *addr = (ptr_instance->enabled_known_extensions.ext_debug_report == 1) ? (void *)debug_report_DebugReportMessageEXT : NULL;
-        return true;
-    }
-    return false;
-}
diff --git a/loader/debug_report.h b/loader/debug_report.h
deleted file mode 100644
index 89074d7..0000000
--- a/loader/debug_report.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (c) 2015-2016 The Khronos Group Inc.
- * Copyright (c) 2015-2016 Valve Corporation
- * Copyright (c) 2015-2016 LunarG, Inc.
- * Copyright (C) 2015-2016 Google Inc.
- *
- * 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.
- *
- * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
- * Author: Jon Ashburn <jon@lunarg.com>
- *
- */
-
-#include "vk_loader_platform.h"
-#include "loader.h"
-
-// CreateMsgCallback is global and needs to be
-// applied to all layers and ICDs.
-// What happens if a layer is enabled on both the instance chain
-// as well as the device chain and a call to CreateMsgCallback is made?
-// Do we need to make sure that each layer / driver only gets called once?
-// Should a layer implementing support for CreateMsgCallback only be allowed (?)
-// to live on one chain? Or maybe make it the application's responsibility.
-// If the app enables DRAW_STATE on at both CreateInstance time and CreateDevice
-// time, CreateMsgCallback will call the DRAW_STATE layer twice. Once via
-// the instance chain and once via the device chain.
-// The loader should only return the DEBUG_REPORT extension as supported
-// for the GetGlobalExtensionSupport call. That should help eliminate one
-// duplication.
-// Since the instance chain requires us iterating over the available ICDs
-// and each ICD will have it's own unique MsgCallback object we need to
-// track those objects to give back the right one.
-// This also implies that the loader has to intercept vkDestroyObject and
-// if the extension is enabled and the object type is a MsgCallback then
-// we must translate the object into the proper ICD specific ones.
-// DestroyObject works on a device chain. Should not be what's destroying
-// the MsgCallback object. That needs to be an instance thing. So, since
-// we used an instance to create it, we need a custom Destroy that also
-// takes an instance. That way we can iterate over the ICDs properly.
-// Example use:
-// CreateInstance: DEBUG_REPORT
-//   Loader will create instance chain with enabled extensions.
-//   TODO: Should validation layers be enabled here? If not, they will not be in
-// the instance chain.
-// fn = GetProcAddr(INSTANCE, "vkCreateMsgCallback") -> point to loader's
-// vkCreateMsgCallback
-// App creates a callback object: fn(..., &MsgCallbackObject1)
-// Have only established the instance chain so far. Loader will call the
-// instance chain.
-// Each layer in the instance chain will call down to the next layer,
-// terminating with
-// the CreateMsgCallback loader terminator function that creates the actual
-// MsgCallbackObject1 object.
-// The loader CreateMsgCallback terminator will iterate over the ICDs.
-// Calling each ICD that supports vkCreateMsgCallback and collect answers in
-// icd_msg_callback_map here.
-// As result is sent back up the chain each layer has opportunity to record the
-// callback operation and
-// appropriate MsgCallback object.
-// ...
-// Any reports matching the flags set in MsgCallbackObject1 will generate the
-// defined callback behavior
-// in the layer / ICD that initiated that report.
-// ...
-// CreateDevice: MemTracker:...
-// App does not include DEBUG_REPORT as that is a global extension.
-// TODO: GetExtensionSupport must not report DEBUG_REPORT when using instance.
-// App MUST include any desired validation layers or they will not participate
-// in the device call chain.
-// App creates a callback object: fn(..., &MsgCallbackObject2)
-// Loader's vkCreateMsgCallback is called.
-// Loader sends call down instance chain - this is a global extension - any
-// validation layer that was
-// enabled at CreateInstance will be able to register the callback. Loader will
-// iterate over the ICDs and
-// will record the ICD's version of the MsgCallback2 object here.
-// ...
-// Any report will go to the layer's report function and it will check the flags
-// for MsgCallbackObject1
-// and MsgCallbackObject2 and take the appropriate action as indicated by the
-// app.
-// ...
-// App calls vkDestroyMsgCallback( MsgCallbackObject1 )
-// Loader's DestroyMsgCallback is where call starts. DestroyMsgCallback will be
-// sent down instance chain
-// ending in the loader's DestroyMsgCallback terminator which will iterate over
-// the ICD's destroying each
-// ICD version of that MsgCallback object and then destroy the loader's version
-// of the object.
-// Any reports generated after this will only have MsgCallbackObject2 available.
-
-void debug_report_add_instance_extensions(const struct loader_instance *inst, struct loader_extension_list *ext_list);
-
-void debug_report_create_instance(struct loader_instance *ptr_instance, const VkInstanceCreateInfo *pCreateInfo);
-
-bool debug_report_instance_gpa(struct loader_instance *ptr_instance, const char *name, void **addr);
-
-VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDebugReportCallbackEXT(VkInstance instance,
-                                                                       const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
-                                                                       const VkAllocationCallbacks *pAllocator,
-                                                                       VkDebugReportCallbackEXT *pCallback);
-
-VKAPI_ATTR void VKAPI_CALL terminator_DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback,
-                                                                    const VkAllocationCallbacks *pAllocator);
-
-VKAPI_ATTR void VKAPI_CALL terminator_DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags,
-                                                            VkDebugReportObjectTypeEXT objType, uint64_t object, size_t location,
-                                                            int32_t msgCode, const char *pLayerPrefix, const char *pMsg);
-
-VkResult util_CreateDebugReportCallback(struct loader_instance *inst, VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
-                                        const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT callback);
-
-void util_DestroyDebugReportCallback(struct loader_instance *inst, VkDebugReportCallbackEXT callback,
-                                     const VkAllocationCallbacks *pAllocator);
-
-VkResult util_CopyDebugReportCreateInfos(const void *pChain, const VkAllocationCallbacks *pAllocator, uint32_t *num_callbacks,
-                                         VkDebugReportCallbackCreateInfoEXT **infos, VkDebugReportCallbackEXT **callbacks);
-void util_FreeDebugReportCreateInfos(const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackCreateInfoEXT *infos,
-                                     VkDebugReportCallbackEXT *callbacks);
-VkResult util_CreateDebugReportCallbacks(struct loader_instance *inst, const VkAllocationCallbacks *pAllocator,
-                                         uint32_t num_callbacks, VkDebugReportCallbackCreateInfoEXT *infos,
-                                         VkDebugReportCallbackEXT *callbacks);
-
-void util_DestroyDebugReportCallbacks(struct loader_instance *inst, const VkAllocationCallbacks *pAllocator, uint32_t num_callbacks,
-                                      VkDebugReportCallbackEXT *callbacks);
-
-VkBool32 util_DebugReportMessage(const struct loader_instance *inst, VkFlags msgFlags, VkDebugReportObjectTypeEXT objectType,
-                                 uint64_t srcObject, size_t location, int32_t msgCode, const char *pLayerPrefix, const char *pMsg);
diff --git a/loader/debug_utils.c b/loader/debug_utils.c
new file mode 100644
index 0000000..3689131
--- /dev/null
+++ b/loader/debug_utils.c
@@ -0,0 +1,1004 @@
+/*
+ * Copyright (c) 2015-2017 The Khronos Group Inc.
+ * Copyright (c) 2015-2017 Valve Corporation
+ * Copyright (c) 2015-2017 LunarG, Inc.
+ * Copyright (C) 2015-2016 Google Inc.
+ *
+ * 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.
+ *
+ * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
+ * Author: Jon Ashburn <jon@LunarG.com>
+ * Author: Mark Young <marky@lunarg.com>
+ *
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#ifndef WIN32
+#include <signal.h>
+#else
+#endif
+#include "vk_loader_platform.h"
+#include "debug_utils.h"
+#include "vulkan/vk_layer.h"
+#include "vk_object_types.h"
+
+// VK_EXT_debug_report related items
+
+VkResult util_CreateDebugUtilsMessenger(struct loader_instance *inst, const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,
+                                        const VkAllocationCallbacks *pAllocator, VkDebugUtilsMessengerEXT messenger) {
+    VkLayerDbgFunctionNode *pNewDbgFuncNode = NULL;
+
+#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
+    {
+#else
+    if (pAllocator != NULL) {
+        pNewDbgFuncNode = (VkLayerDbgFunctionNode *)pAllocator->pfnAllocation(pAllocator->pUserData, sizeof(VkLayerDbgFunctionNode),
+                                                                              sizeof(int *), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+    } else {
+#endif
+        pNewDbgFuncNode = (VkLayerDbgFunctionNode *)loader_instance_heap_alloc(inst, sizeof(VkLayerDbgFunctionNode),
+                                                                               VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+    }
+    if (!pNewDbgFuncNode) {
+        return VK_ERROR_OUT_OF_HOST_MEMORY;
+    }
+    memset(pNewDbgFuncNode, 0, sizeof(VkLayerDbgFunctionNode));
+
+    pNewDbgFuncNode->is_messenger = true;
+    pNewDbgFuncNode->messenger.messenger = messenger;
+    pNewDbgFuncNode->messenger.pfnUserCallback = pCreateInfo->pfnUserCallback;
+    pNewDbgFuncNode->messenger.messageSeverity = pCreateInfo->messageSeverity;
+    pNewDbgFuncNode->messenger.messageType = pCreateInfo->messageType;
+    pNewDbgFuncNode->pUserData = pCreateInfo->pUserData;
+    pNewDbgFuncNode->pNext = inst->DbgFunctionHead;
+    inst->DbgFunctionHead = pNewDbgFuncNode;
+
+    return VK_SUCCESS;
+}
+
+static VKAPI_ATTR VkResult VKAPI_CALL
+debug_utils_CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,
+                                         const VkAllocationCallbacks *pAllocator, VkDebugUtilsMessengerEXT *pMessenger) {
+    struct loader_instance *inst = loader_get_instance(instance);
+    loader_platform_thread_lock_mutex(&loader_lock);
+    VkResult result = inst->disp->layer_inst_disp.CreateDebugUtilsMessengerEXT(instance, pCreateInfo, pAllocator, pMessenger);
+    loader_platform_thread_unlock_mutex(&loader_lock);
+    return result;
+}
+
+VkBool32 util_SubmitDebugUtilsMessageEXT(const struct loader_instance *inst, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
+                                         VkDebugUtilsMessageTypeFlagsEXT messageTypes,
+                                         const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData) {
+    VkBool32 bail = false;
+
+    if (NULL != pCallbackData && NULL != pCallbackData->pObjects && 0 < pCallbackData->objectCount) {
+        VkLayerDbgFunctionNode *pTrav = inst->DbgFunctionHead;
+        VkDebugReportObjectTypeEXT object_type;
+        VkDebugReportFlagsEXT object_flags = 0;
+        uint64_t object_handle;
+
+        debug_utils_AnnotFlagsToReportFlags(messageSeverity, messageTypes, &object_flags);
+        debug_utils_AnnotObjectToDebugReportObject(pCallbackData->pObjects, &object_type, &object_handle);
+
+        while (pTrav) {
+            if (pTrav->is_messenger && (pTrav->messenger.messageSeverity & messageSeverity) &&
+                (pTrav->messenger.messageType & messageTypes)) {
+                if (pTrav->messenger.pfnUserCallback(messageSeverity, messageTypes, pCallbackData, pTrav->pUserData)) {
+                    bail = true;
+                }
+            }
+            if (!pTrav->is_messenger && pTrav->report.msgFlags & object_flags) {
+                if (pTrav->report.pfnMsgCallback(object_flags, object_type, object_handle, 0, pCallbackData->messageIdNumber,
+                                                 pCallbackData->pMessageIdName, pCallbackData->pMessage, pTrav->pUserData)) {
+                    bail = true;
+                }
+            }
+
+            pTrav = pTrav->pNext;
+        }
+    }
+
+    return bail;
+}
+
+void util_DestroyDebugUtilsMessenger(struct loader_instance *inst, VkDebugUtilsMessengerEXT messenger,
+                                     const VkAllocationCallbacks *pAllocator) {
+    VkLayerDbgFunctionNode *pTrav = inst->DbgFunctionHead;
+    VkLayerDbgFunctionNode *pPrev = pTrav;
+
+    while (pTrav) {
+        if (pTrav->is_messenger && pTrav->messenger.messenger == messenger) {
+            pPrev->pNext = pTrav->pNext;
+            if (inst->DbgFunctionHead == pTrav) inst->DbgFunctionHead = pTrav->pNext;
+#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
+            {
+#else
+            if (pAllocator != NULL) {
+                pAllocator->pfnFree(pAllocator->pUserData, pTrav);
+            } else {
+#endif
+                loader_instance_heap_free(inst, pTrav);
+            }
+            break;
+        }
+        pPrev = pTrav;
+        pTrav = pTrav->pNext;
+    }
+}
+
+// This utility (used by vkInstanceCreateInfo(), looks at a pNext chain.  It
+// counts any VkDebugUtilsMessengerCreateInfoEXT structs that it finds.  It
+// then allocates array that can hold that many structs, as well as that many
+// VkDebugUtilsMessengerEXT handles.  It then copies each
+// VkDebugUtilsMessengerCreateInfoEXT, and initializes each handle.
+VkResult util_CopyDebugUtilsMessengerCreateInfos(const void *pChain, const VkAllocationCallbacks *pAllocator,
+                                                 uint32_t *num_messengers, VkDebugUtilsMessengerCreateInfoEXT **infos,
+                                                 VkDebugUtilsMessengerEXT **messengers) {
+    uint32_t n = *num_messengers = 0;
+    VkDebugUtilsMessengerCreateInfoEXT *pInfos = NULL;
+    VkDebugUtilsMessengerEXT *pMessengers = NULL;
+
+    const void *pNext = pChain;
+    while (pNext) {
+        // 1st, count the number VkDebugUtilsMessengerCreateInfoEXT:
+        if (((VkDebugUtilsMessengerCreateInfoEXT *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) {
+            n++;
+        }
+        pNext = (void *)((VkDebugUtilsMessengerCreateInfoEXT *)pNext)->pNext;
+    }
+    if (n == 0) {
+        return VK_SUCCESS;
+    }
+
+// 2nd, allocate memory for each VkDebugUtilsMessengerCreateInfoEXT:
+#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
+    {
+#else
+    if (pAllocator != NULL) {
+        pInfos = *infos = ((VkDebugUtilsMessengerCreateInfoEXT *)pAllocator->pfnAllocation(
+            pAllocator->pUserData, n * sizeof(VkDebugUtilsMessengerCreateInfoEXT), sizeof(void *),
+            VK_SYSTEM_ALLOCATION_SCOPE_OBJECT));
+    } else {
+#endif
+        pInfos = *infos = ((VkDebugUtilsMessengerCreateInfoEXT *)malloc(n * sizeof(VkDebugUtilsMessengerCreateInfoEXT)));
+    }
+    if (!pInfos) {
+        return VK_ERROR_OUT_OF_HOST_MEMORY;
+    }
+// 3rd, allocate memory for a unique handle for each callback:
+#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
+    {
+#else
+    if (pAllocator != NULL) {
+        pMessengers = *messengers = ((VkDebugUtilsMessengerEXT *)pAllocator->pfnAllocation(
+            pAllocator->pUserData, n * sizeof(VkDebugUtilsMessengerEXT), sizeof(void *), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT));
+        if (NULL == pMessengers) {
+            pAllocator->pfnFree(pAllocator->pUserData, pInfos);
+            return VK_ERROR_OUT_OF_HOST_MEMORY;
+        }
+    } else {
+#endif
+        pMessengers = *messengers = ((VkDebugUtilsMessengerEXT *)malloc(n * sizeof(VkDebugUtilsMessengerEXT)));
+        if (NULL == pMessengers) {
+            free(pInfos);
+            return VK_ERROR_OUT_OF_HOST_MEMORY;
+        }
+    }
+    // 4th, copy each VkDebugUtilsMessengerCreateInfoEXT for use by
+    // vkDestroyInstance, and assign a unique handle to each messenger (just
+    // use the address of the copied VkDebugUtilsMessengerCreateInfoEXT):
+    pNext = pChain;
+    while (pNext) {
+        if (((VkInstanceCreateInfo *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) {
+            memcpy(pInfos, pNext, sizeof(VkDebugUtilsMessengerCreateInfoEXT));
+            *pMessengers++ = (VkDebugUtilsMessengerEXT)(uintptr_t)pInfos++;
+        }
+        pNext = (void *)((VkInstanceCreateInfo *)pNext)->pNext;
+    }
+
+    *num_messengers = n;
+    return VK_SUCCESS;
+}
+
+void util_FreeDebugUtilsMessengerCreateInfos(const VkAllocationCallbacks *pAllocator, VkDebugUtilsMessengerCreateInfoEXT *infos,
+                                             VkDebugUtilsMessengerEXT *messengers) {
+#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
+    {
+#else
+    if (pAllocator != NULL) {
+        pAllocator->pfnFree(pAllocator->pUserData, infos);
+        pAllocator->pfnFree(pAllocator->pUserData, messengers);
+    } else {
+#endif
+        free(infos);
+        free(messengers);
+    }
+}
+
+VkResult util_CreateDebugUtilsMessengers(struct loader_instance *inst, const VkAllocationCallbacks *pAllocator,
+                                         uint32_t num_messengers, VkDebugUtilsMessengerCreateInfoEXT *infos,
+                                         VkDebugUtilsMessengerEXT *messengers) {
+    VkResult rtn = VK_SUCCESS;
+    for (uint32_t i = 0; i < num_messengers; i++) {
+        rtn = util_CreateDebugUtilsMessenger(inst, &infos[i], pAllocator, messengers[i]);
+        if (rtn != VK_SUCCESS) {
+            for (uint32_t j = 0; j < i; j++) {
+                util_DestroyDebugUtilsMessenger(inst, messengers[j], pAllocator);
+            }
+            return rtn;
+        }
+    }
+    return rtn;
+}
+
+void util_DestroyDebugUtilsMessengers(struct loader_instance *inst, const VkAllocationCallbacks *pAllocator,
+                                      uint32_t num_messengers, VkDebugUtilsMessengerEXT *messengers) {
+    for (uint32_t i = 0; i < num_messengers; i++) {
+        util_DestroyDebugUtilsMessenger(inst, messengers[i], pAllocator);
+    }
+}
+
+static VKAPI_ATTR void VKAPI_CALL debug_utils_SubmitDebugUtilsMessageEXT(
+    VkInstance instance, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes,
+    const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData) {
+    struct loader_instance *inst = loader_get_instance(instance);
+
+    inst->disp->layer_inst_disp.SubmitDebugUtilsMessageEXT(instance, messageSeverity, messageTypes, pCallbackData);
+}
+
+static VKAPI_ATTR void VKAPI_CALL debug_utils_DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger,
+                                                                            const VkAllocationCallbacks *pAllocator) {
+    struct loader_instance *inst = loader_get_instance(instance);
+    loader_platform_thread_lock_mutex(&loader_lock);
+
+    inst->disp->layer_inst_disp.DestroyDebugUtilsMessengerEXT(instance, messenger, pAllocator);
+
+    util_DestroyDebugUtilsMessenger(inst, messenger, pAllocator);
+
+    loader_platform_thread_unlock_mutex(&loader_lock);
+}
+
+// This is the instance chain terminator function for CreateDebugUtilsMessenger
+VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDebugUtilsMessengerEXT(VkInstance instance,
+                                                                       const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,
+                                                                       const VkAllocationCallbacks *pAllocator,
+                                                                       VkDebugUtilsMessengerEXT *pMessenger) {
+    VkDebugUtilsMessengerEXT *icd_info = NULL;
+    const struct loader_icd_term *icd_term;
+    struct loader_instance *inst = (struct loader_instance *)instance;
+    VkResult res = VK_SUCCESS;
+    uint32_t storage_idx;
+    VkLayerDbgFunctionNode *pNewDbgFuncNode = NULL;
+
+#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
+    {
+#else
+    if (pAllocator != NULL) {
+        icd_info = ((VkDebugUtilsMessengerEXT *)pAllocator->pfnAllocation(pAllocator->pUserData,
+                                                                          inst->total_icd_count * sizeof(VkDebugUtilsMessengerEXT),
+                                                                          sizeof(void *), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT));
+        if (icd_info) {
+            memset(icd_info, 0, inst->total_icd_count * sizeof(VkDebugUtilsMessengerEXT));
+        }
+    } else {
+#endif
+        icd_info = calloc(sizeof(VkDebugUtilsMessengerEXT), inst->total_icd_count);
+    }
+    if (!icd_info) {
+        res = VK_ERROR_OUT_OF_HOST_MEMORY;
+        goto out;
+    }
+
+    storage_idx = 0;
+    for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) {
+        if (!icd_term->dispatch.CreateDebugUtilsMessengerEXT) {
+            continue;
+        }
+
+        res = icd_term->dispatch.CreateDebugUtilsMessengerEXT(icd_term->instance, pCreateInfo, pAllocator, &icd_info[storage_idx]);
+
+        if (res != VK_SUCCESS) {
+            goto out;
+        }
+        storage_idx++;
+    }
+
+// Setup the debug report callback in the terminator since a layer may want
+// to grab the information itself (RenderDoc) and then return back to the
+// user callback a sub-set of the messages.
+#if (DEBUG_DISABLE_APP_ALLOCATORS == 0)
+    if (pAllocator != NULL) {
+        pNewDbgFuncNode = (VkLayerDbgFunctionNode *)pAllocator->pfnAllocation(pAllocator->pUserData, sizeof(VkLayerDbgFunctionNode),
+                                                                              sizeof(int *), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+    } else {
+#else
+    {
+#endif
+        pNewDbgFuncNode = (VkLayerDbgFunctionNode *)loader_instance_heap_alloc(inst, sizeof(VkLayerDbgFunctionNode),
+                                                                               VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+    }
+    if (!pNewDbgFuncNode) {
+        res = VK_ERROR_OUT_OF_HOST_MEMORY;
+        goto out;
+    }
+    memset(pNewDbgFuncNode, 0, sizeof(VkLayerDbgFunctionNode));
+
+    pNewDbgFuncNode->is_messenger = true;
+    pNewDbgFuncNode->messenger.pfnUserCallback = pCreateInfo->pfnUserCallback;
+    pNewDbgFuncNode->messenger.messageSeverity = pCreateInfo->messageSeverity;
+    pNewDbgFuncNode->messenger.messageType = pCreateInfo->messageType;
+    pNewDbgFuncNode->pUserData = pCreateInfo->pUserData;
+    pNewDbgFuncNode->pNext = inst->DbgFunctionHead;
+    inst->DbgFunctionHead = pNewDbgFuncNode;
+
+    *(VkDebugUtilsMessengerEXT **)pMessenger = icd_info;
+    pNewDbgFuncNode->messenger.messenger = *pMessenger;
+
+out:
+
+    // Roll back on errors
+    if (VK_SUCCESS != res) {
+        storage_idx = 0;
+        for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) {
+            if (NULL == icd_term->dispatch.DestroyDebugUtilsMessengerEXT) {
+                continue;
+            }
+
+            if (icd_info && icd_info[storage_idx]) {
+                icd_term->dispatch.DestroyDebugUtilsMessengerEXT(icd_term->instance, icd_info[storage_idx], pAllocator);
+            }
+            storage_idx++;
+        }
+
+#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
+        {
+#else
+        if (pAllocator != NULL) {
+            if (NULL != pNewDbgFuncNode) {
+                pAllocator->pfnFree(pAllocator->pUserData, pNewDbgFuncNode);
+            }
+            if (NULL != icd_info) {
+                pAllocator->pfnFree(pAllocator->pUserData, icd_info);
+            }
+        } else {
+#endif
+            if (NULL != pNewDbgFuncNode) {
+                free(pNewDbgFuncNode);
+            }
+            if (NULL != icd_info) {
+                free(icd_info);
+            }
+        }
+    }
+
+    return res;
+}
+
+// This is the instance chain terminator function for DestroyDebugUtilsMessenger
+VKAPI_ATTR void VKAPI_CALL terminator_DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger,
+                                                                    const VkAllocationCallbacks *pAllocator) {
+    uint32_t storage_idx;
+    VkDebugUtilsMessengerEXT *icd_info;
+    const struct loader_icd_term *icd_term;
+
+    struct loader_instance *inst = (struct loader_instance *)instance;
+    icd_info = *(VkDebugUtilsMessengerEXT **)&messenger;
+    storage_idx = 0;
+    for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) {
+        if (NULL == icd_term->dispatch.DestroyDebugUtilsMessengerEXT) {
+            continue;
+        }
+
+        if (icd_info[storage_idx]) {
+            icd_term->dispatch.DestroyDebugUtilsMessengerEXT(icd_term->instance, icd_info[storage_idx], pAllocator);
+        }
+        storage_idx++;
+    }
+
+#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
+    {
+#else
+    if (pAllocator != NULL) {
+        pAllocator->pfnFree(pAllocator->pUserData, icd_info);
+    } else {
+#endif
+        free(icd_info);
+    }
+}
+
+// This is the instance chain terminator function for SubmitDebugUtilsMessageEXT
+VKAPI_ATTR void VKAPI_CALL terminator_SubmitDebugUtilsMessageEXT(VkInstance instance,
+                                                                 VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
+                                                                 VkDebugUtilsMessageTypeFlagsEXT messageTypes,
+                                                                 const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData) {
+    const struct loader_icd_term *icd_term;
+
+    struct loader_instance *inst = (struct loader_instance *)instance;
+
+    loader_platform_thread_lock_mutex(&loader_lock);
+    for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) {
+        if (icd_term->dispatch.SubmitDebugUtilsMessageEXT != NULL) {
+            icd_term->dispatch.SubmitDebugUtilsMessageEXT(icd_term->instance, messageSeverity, messageTypes, pCallbackData);
+        }
+    }
+
+    // Now that all ICDs have seen the message, call the necessary callbacks.  Ignoring "bail" return value
+    // as there is nothing to bail from at this point.
+
+    util_SubmitDebugUtilsMessageEXT(inst, messageSeverity, messageTypes, pCallbackData);
+
+    loader_platform_thread_unlock_mutex(&loader_lock);
+}
+
+// VK_EXT_debug_report related items
+
+VkResult util_CreateDebugReportCallback(struct loader_instance *inst, VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
+                                        const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT callback) {
+    VkLayerDbgFunctionNode *pNewDbgFuncNode = NULL;
+
+#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
+    {
+#else
+    if (pAllocator != NULL) {
+        pNewDbgFuncNode = (VkLayerDbgFunctionNode *)pAllocator->pfnAllocation(pAllocator->pUserData, sizeof(VkLayerDbgFunctionNode),
+                                                                              sizeof(int *), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+    } else {
+#endif
+        pNewDbgFuncNode = (VkLayerDbgFunctionNode *)loader_instance_heap_alloc(inst, sizeof(VkLayerDbgFunctionNode),
+                                                                               VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+    }
+    if (!pNewDbgFuncNode) {
+        return VK_ERROR_OUT_OF_HOST_MEMORY;
+    }
+    memset(pNewDbgFuncNode, 0, sizeof(VkLayerDbgFunctionNode));
+
+    pNewDbgFuncNode->is_messenger = false;
+    pNewDbgFuncNode->report.msgCallback = callback;
+    pNewDbgFuncNode->report.pfnMsgCallback = pCreateInfo->pfnCallback;
+    pNewDbgFuncNode->report.msgFlags = pCreateInfo->flags;
+    pNewDbgFuncNode->pUserData = pCreateInfo->pUserData;
+    pNewDbgFuncNode->pNext = inst->DbgFunctionHead;
+    inst->DbgFunctionHead = pNewDbgFuncNode;
+
+    return VK_SUCCESS;
+}
+
+static VKAPI_ATTR VkResult VKAPI_CALL
+debug_utils_CreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
+                                         const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT *pCallback) {
+    struct loader_instance *inst = loader_get_instance(instance);
+    loader_platform_thread_lock_mutex(&loader_lock);
+    VkResult result = inst->disp->layer_inst_disp.CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pCallback);
+    loader_platform_thread_unlock_mutex(&loader_lock);
+    return result;
+}
+
+// Utility function to handle reporting
+VkBool32 util_DebugReportMessage(const struct loader_instance *inst, VkFlags msgFlags, VkDebugReportObjectTypeEXT objectType,
+                                 uint64_t srcObject, size_t location, int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
+    VkBool32 bail = false;
+    VkLayerDbgFunctionNode *pTrav = inst->DbgFunctionHead;
+    VkDebugUtilsMessageSeverityFlagBitsEXT severity;
+    VkDebugUtilsMessageTypeFlagsEXT types;
+    VkDebugUtilsMessengerCallbackDataEXT callback_data;
+    VkDebugUtilsObjectNameInfoEXT object_name;
+
+    debug_utils_ReportFlagsToAnnotFlags(msgFlags, false, &severity, &types);
+    debug_utils_ReportObjectToAnnotObject(objectType, srcObject, &object_name);
+
+    callback_data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT;
+    callback_data.pNext = NULL;
+    callback_data.flags = 0;
+    callback_data.pMessageIdName = pLayerPrefix;
+    callback_data.messageIdNumber = msgCode;
+    callback_data.pMessage = pMsg;
+    callback_data.cmdBufLabelCount = 0;
+    callback_data.pCmdBufLabels = NULL;
+    callback_data.queueLabelCount = 0;
+    callback_data.pQueueLabels = NULL;
+    callback_data.objectCount = 1;
+    callback_data.pObjects = &object_name;
+
+    while (pTrav) {
+        if (!pTrav->is_messenger && pTrav->report.msgFlags & msgFlags) {
+            if (pTrav->report.pfnMsgCallback(msgFlags, objectType, srcObject, location, msgCode, pLayerPrefix, pMsg,
+                                             pTrav->pUserData)) {
+                bail = true;
+            }
+        }
+        if (pTrav->is_messenger && (pTrav->messenger.messageSeverity & severity) && (pTrav->messenger.messageType & types)) {
+            if (pTrav->messenger.pfnUserCallback(severity, types, &callback_data, pTrav->pUserData)) {
+                bail = true;
+            }
+        }
+
+        pTrav = pTrav->pNext;
+    }
+
+    return bail;
+}
+
+void util_DestroyDebugReportCallback(struct loader_instance *inst, VkDebugReportCallbackEXT callback,
+                                     const VkAllocationCallbacks *pAllocator) {
+    VkLayerDbgFunctionNode *pTrav = inst->DbgFunctionHead;
+    VkLayerDbgFunctionNode *pPrev = pTrav;
+
+    while (pTrav) {
+        if (!pTrav->is_messenger && pTrav->report.msgCallback == callback) {
+            pPrev->pNext = pTrav->pNext;
+            if (inst->DbgFunctionHead == pTrav) inst->DbgFunctionHead = pTrav->pNext;
+#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
+            {
+#else
+            if (pAllocator != NULL) {
+                pAllocator->pfnFree(pAllocator->pUserData, pTrav);
+            } else {
+#endif
+                loader_instance_heap_free(inst, pTrav);
+            }
+            break;
+        }
+        pPrev = pTrav;
+        pTrav = pTrav->pNext;
+    }
+}
+
+// This utility (used by vkInstanceCreateInfo(), looks at a pNext chain.  It
+// counts any VkDebugReportCallbackCreateInfoEXT structs that it finds.  It
+// then allocates array that can hold that many structs, as well as that many
+// VkDebugReportCallbackEXT handles.  It then copies each
+// VkDebugReportCallbackCreateInfoEXT, and initializes each handle.
+VkResult util_CopyDebugReportCreateInfos(const void *pChain, const VkAllocationCallbacks *pAllocator, uint32_t *num_callbacks,
+                                         VkDebugReportCallbackCreateInfoEXT **infos, VkDebugReportCallbackEXT **callbacks) {
+    uint32_t n = *num_callbacks = 0;
+    VkDebugReportCallbackCreateInfoEXT *pInfos = NULL;
+    VkDebugReportCallbackEXT *pCallbacks = NULL;
+
+    const void *pNext = pChain;
+    while (pNext) {
+        // 1st, count the number VkDebugReportCallbackCreateInfoEXT:
+        if (((VkDebugReportCallbackCreateInfoEXT *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) {
+            n++;
+        }
+        pNext = (void *)((VkDebugReportCallbackCreateInfoEXT *)pNext)->pNext;
+    }
+    if (n == 0) {
+        return VK_SUCCESS;
+    }
+
+// 2nd, allocate memory for each VkDebugReportCallbackCreateInfoEXT:
+#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
+    {
+#else
+    if (pAllocator != NULL) {
+        pInfos = *infos = ((VkDebugReportCallbackCreateInfoEXT *)pAllocator->pfnAllocation(
+            pAllocator->pUserData, n * sizeof(VkDebugReportCallbackCreateInfoEXT), sizeof(void *),
+            VK_SYSTEM_ALLOCATION_SCOPE_OBJECT));
+    } else {
+#endif
+        pInfos = *infos = ((VkDebugReportCallbackCreateInfoEXT *)malloc(n * sizeof(VkDebugReportCallbackCreateInfoEXT)));
+    }
+    if (!pInfos) {
+        return VK_ERROR_OUT_OF_HOST_MEMORY;
+    }
+// 3rd, allocate memory for a unique handle for each callback:
+#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
+    {
+#else
+    if (pAllocator != NULL) {
+        pCallbacks = *callbacks = ((VkDebugReportCallbackEXT *)pAllocator->pfnAllocation(
+            pAllocator->pUserData, n * sizeof(VkDebugReportCallbackEXT), sizeof(void *), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT));
+        if (!pCallbacks) {
+            pAllocator->pfnFree(pAllocator->pUserData, pInfos);
+            return VK_ERROR_OUT_OF_HOST_MEMORY;
+        }
+    } else {
+#endif
+        pCallbacks = *callbacks = ((VkDebugReportCallbackEXT *)malloc(n * sizeof(VkDebugReportCallbackEXT)));
+        if (!pCallbacks) {
+            free(pInfos);
+            return VK_ERROR_OUT_OF_HOST_MEMORY;
+        }
+    }
+    // 4th, copy each VkDebugReportCallbackCreateInfoEXT for use by
+    // vkDestroyInstance, and assign a unique handle to each callback (just
+    // use the address of the copied VkDebugReportCallbackCreateInfoEXT):
+    pNext = pChain;
+    while (pNext) {
+        if (((VkInstanceCreateInfo *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) {
+            memcpy(pInfos, pNext, sizeof(VkDebugReportCallbackCreateInfoEXT));
+            *pCallbacks++ = (VkDebugReportCallbackEXT)(uintptr_t)pInfos++;
+        }
+        pNext = (void *)((VkInstanceCreateInfo *)pNext)->pNext;
+    }
+
+    *num_callbacks = n;
+    return VK_SUCCESS;
+}
+
+void util_FreeDebugReportCreateInfos(const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackCreateInfoEXT *infos,
+                                     VkDebugReportCallbackEXT *callbacks) {
+#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
+    {
+#else
+    if (pAllocator != NULL) {
+        pAllocator->pfnFree(pAllocator->pUserData, infos);
+        pAllocator->pfnFree(pAllocator->pUserData, callbacks);
+    } else {
+#endif
+        free(infos);
+        free(callbacks);
+    }
+}
+
+VkResult util_CreateDebugReportCallbacks(struct loader_instance *inst, const VkAllocationCallbacks *pAllocator,
+                                         uint32_t num_callbacks, VkDebugReportCallbackCreateInfoEXT *infos,
+                                         VkDebugReportCallbackEXT *callbacks) {
+    VkResult rtn = VK_SUCCESS;
+    for (uint32_t i = 0; i < num_callbacks; i++) {
+        rtn = util_CreateDebugReportCallback(inst, &infos[i], pAllocator, callbacks[i]);
+        if (rtn != VK_SUCCESS) {
+            for (uint32_t j = 0; j < i; j++) {
+                util_DestroyDebugReportCallback(inst, callbacks[j], pAllocator);
+            }
+            return rtn;
+        }
+    }
+    return rtn;
+}
+
+void util_DestroyDebugReportCallbacks(struct loader_instance *inst, const VkAllocationCallbacks *pAllocator, uint32_t num_callbacks,
+                                      VkDebugReportCallbackEXT *callbacks) {
+    for (uint32_t i = 0; i < num_callbacks; i++) {
+        util_DestroyDebugReportCallback(inst, callbacks[i], pAllocator);
+    }
+}
+
+static VKAPI_ATTR void VKAPI_CALL debug_utils_DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback,
+                                                                            const VkAllocationCallbacks *pAllocator) {
+    struct loader_instance *inst = loader_get_instance(instance);
+    loader_platform_thread_lock_mutex(&loader_lock);
+
+    inst->disp->layer_inst_disp.DestroyDebugReportCallbackEXT(instance, callback, pAllocator);
+
+    util_DestroyDebugReportCallback(inst, callback, pAllocator);
+
+    loader_platform_thread_unlock_mutex(&loader_lock);
+}
+
+static VKAPI_ATTR void VKAPI_CALL debug_utils_DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags,
+                                                                    VkDebugReportObjectTypeEXT objType, uint64_t object,
+                                                                    size_t location, int32_t msgCode, const char *pLayerPrefix,
+                                                                    const char *pMsg) {
+    struct loader_instance *inst = loader_get_instance(instance);
+
+    inst->disp->layer_inst_disp.DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, pMsg);
+}
+
+// This is the instance chain terminator function
+// for CreateDebugReportCallback
+VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDebugReportCallbackEXT(VkInstance instance,
+                                                                       const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
+                                                                       const VkAllocationCallbacks *pAllocator,
+                                                                       VkDebugReportCallbackEXT *pCallback) {
+    VkDebugReportCallbackEXT *icd_info = NULL;
+    const struct loader_icd_term *icd_term;
+    struct loader_instance *inst = (struct loader_instance *)instance;
+    VkResult res = VK_SUCCESS;
+    uint32_t storage_idx;
+    VkLayerDbgFunctionNode *pNewDbgFuncNode = NULL;
+
+#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
+    {
+#else
+    if (pAllocator != NULL) {
+        icd_info = ((VkDebugReportCallbackEXT *)pAllocator->pfnAllocation(pAllocator->pUserData,
+                                                                          inst->total_icd_count * sizeof(VkDebugReportCallbackEXT),
+                                                                          sizeof(void *), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT));
+        if (icd_info) {
+            memset(icd_info, 0, inst->total_icd_count * sizeof(VkDebugReportCallbackEXT));
+        }
+    } else {
+#endif
+        icd_info = calloc(sizeof(VkDebugReportCallbackEXT), inst->total_icd_count);
+    }
+    if (!icd_info) {
+        res = VK_ERROR_OUT_OF_HOST_MEMORY;
+        goto out;
+    }
+
+    storage_idx = 0;
+    for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) {
+        if (!icd_term->dispatch.CreateDebugReportCallbackEXT) {
+            continue;
+        }
+
+        res = icd_term->dispatch.CreateDebugReportCallbackEXT(icd_term->instance, pCreateInfo, pAllocator, &icd_info[storage_idx]);
+
+        if (res != VK_SUCCESS) {
+            goto out;
+        }
+        storage_idx++;
+    }
+
+// Setup the debug report callback in the terminator since a layer may want
+// to grab the information itself (RenderDoc) and then return back to the
+// user callback a sub-set of the messages.
+#if (DEBUG_DISABLE_APP_ALLOCATORS == 0)
+    if (pAllocator != NULL) {
+        pNewDbgFuncNode = (VkLayerDbgFunctionNode *)pAllocator->pfnAllocation(pAllocator->pUserData, sizeof(VkLayerDbgFunctionNode),
+                                                                              sizeof(int *), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+    } else {
+#else
+    {
+#endif
+        pNewDbgFuncNode = (VkLayerDbgFunctionNode *)loader_instance_heap_alloc(inst, sizeof(VkLayerDbgFunctionNode),
+                                                                               VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+    }
+    if (!pNewDbgFuncNode) {
+        res = VK_ERROR_OUT_OF_HOST_MEMORY;
+        goto out;
+    }
+    memset(pNewDbgFuncNode, 0, sizeof(VkLayerDbgFunctionNode));
+
+    pNewDbgFuncNode->is_messenger = false;
+    pNewDbgFuncNode->report.pfnMsgCallback = pCreateInfo->pfnCallback;
+    pNewDbgFuncNode->report.msgFlags = pCreateInfo->flags;
+    pNewDbgFuncNode->pUserData = pCreateInfo->pUserData;
+    pNewDbgFuncNode->pNext = inst->DbgFunctionHead;
+    inst->DbgFunctionHead = pNewDbgFuncNode;
+
+    *(VkDebugReportCallbackEXT **)pCallback = icd_info;
+    pNewDbgFuncNode->report.msgCallback = *pCallback;
+
+out:
+
+    // Roll back on errors
+    if (VK_SUCCESS != res) {
+        storage_idx = 0;
+        for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) {
+            if (NULL == icd_term->dispatch.DestroyDebugReportCallbackEXT) {
+                continue;
+            }
+
+            if (icd_info && icd_info[storage_idx]) {
+                icd_term->dispatch.DestroyDebugReportCallbackEXT(icd_term->instance, icd_info[storage_idx], pAllocator);
+            }
+            storage_idx++;
+        }
+
+#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
+        {
+#else
+        if (pAllocator != NULL) {
+            if (NULL != pNewDbgFuncNode) {
+                pAllocator->pfnFree(pAllocator->pUserData, pNewDbgFuncNode);
+            }
+            if (NULL != icd_info) {
+                pAllocator->pfnFree(pAllocator->pUserData, icd_info);
+            }
+        } else {
+#endif
+            if (NULL != pNewDbgFuncNode) {
+                free(pNewDbgFuncNode);
+            }
+            if (NULL != icd_info) {
+                free(icd_info);
+            }
+        }
+    }
+
+    return res;
+}
+
+// This is the instance chain terminator function for DestroyDebugReportCallback
+VKAPI_ATTR void VKAPI_CALL terminator_DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback,
+                                                                    const VkAllocationCallbacks *pAllocator) {
+    uint32_t storage_idx;
+    VkDebugReportCallbackEXT *icd_info;
+    const struct loader_icd_term *icd_term;
+
+    struct loader_instance *inst = (struct loader_instance *)instance;
+    icd_info = *(VkDebugReportCallbackEXT **)&callback;
+    storage_idx = 0;
+    for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) {
+        if (NULL == icd_term->dispatch.DestroyDebugReportCallbackEXT) {
+            continue;
+        }
+
+        if (icd_info[storage_idx]) {
+            icd_term->dispatch.DestroyDebugReportCallbackEXT(icd_term->instance, icd_info[storage_idx], pAllocator);
+        }
+        storage_idx++;
+    }
+
+#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
+    {
+#else
+    if (pAllocator != NULL) {
+        pAllocator->pfnFree(pAllocator->pUserData, icd_info);
+    } else {
+#endif
+        free(icd_info);
+    }
+}
+
+// This is the instance chain terminator function for DebugReportMessage
+VKAPI_ATTR void VKAPI_CALL terminator_DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags,
+                                                            VkDebugReportObjectTypeEXT objType, uint64_t object, size_t location,
+                                                            int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
+    const struct loader_icd_term *icd_term;
+
+    struct loader_instance *inst = (struct loader_instance *)instance;
+
+    loader_platform_thread_lock_mutex(&loader_lock);
+    for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) {
+        if (icd_term->dispatch.DebugReportMessageEXT != NULL) {
+            icd_term->dispatch.DebugReportMessageEXT(icd_term->instance, flags, objType, object, location, msgCode, pLayerPrefix,
+                                                     pMsg);
+        }
+    }
+
+    // Now that all ICDs have seen the message, call the necessary callbacks.  Ignoring "bail" return value
+    // as there is nothing to bail from at this point.
+
+    util_DebugReportMessage(inst, flags, objType, object, location, msgCode, pLayerPrefix, pMsg);
+
+    loader_platform_thread_unlock_mutex(&loader_lock);
+}
+
+// General utilities
+
+static const VkExtensionProperties debug_utils_extension_info[] = {
+    {VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION},
+    {VK_EXT_DEBUG_UTILS_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_SPEC_VERSION},
+};
+
+void debug_utils_AddInstanceExtensions(const struct loader_instance *inst, struct loader_extension_list *ext_list) {
+    loader_add_to_ext_list(inst, ext_list, sizeof(debug_utils_extension_info) / sizeof(VkExtensionProperties),
+                           debug_utils_extension_info);
+}
+
+void debug_utils_CreateInstance(struct loader_instance *ptr_instance, const VkInstanceCreateInfo *pCreateInfo) {
+    ptr_instance->enabled_known_extensions.ext_debug_report = 0;
+    ptr_instance->enabled_known_extensions.ext_debug_utils = 0;
+
+    for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
+        if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0) {
+            ptr_instance->enabled_known_extensions.ext_debug_report = 1;
+        } else if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0) {
+            ptr_instance->enabled_known_extensions.ext_debug_utils = 1;
+        }
+    }
+}
+
+bool debug_utils_InstanceGpa(struct loader_instance *ptr_instance, const char *name, void **addr) {
+    bool ret_type = false;
+
+    *addr = NULL;
+
+    if (ptr_instance->enabled_known_extensions.ext_debug_report == 1) {
+        if (!strcmp("vkCreateDebugReportCallbackEXT", name)) {
+            *addr = (void *)debug_utils_CreateDebugReportCallbackEXT;
+            ret_type = true;
+        } else if (!strcmp("vkDestroyDebugReportCallbackEXT", name)) {
+            *addr = (void *)debug_utils_DestroyDebugReportCallbackEXT;
+            ret_type = true;
+        } else if (!strcmp("vkDebugReportMessageEXT", name)) {
+            *addr = (void *)debug_utils_DebugReportMessageEXT;
+            return true;
+        }
+    }
+    if (ptr_instance->enabled_known_extensions.ext_debug_utils == 1) {
+        if (!strcmp("vkCreateDebugUtilsMessengerEXT", name)) {
+            *addr = (void *)debug_utils_CreateDebugUtilsMessengerEXT;
+            ret_type = true;
+        } else if (!strcmp("vkDestroyDebugUtilsMessengerEXT", name)) {
+            *addr = (void *)debug_utils_DestroyDebugUtilsMessengerEXT;
+            ret_type = true;
+        } else if (!strcmp("vkSubmitDebugUtilsMessageEXT", name)) {
+            *addr = (void *)debug_utils_SubmitDebugUtilsMessageEXT;
+            ret_type = true;
+        }
+    }
+
+    return ret_type;
+}
+
+bool debug_utils_ReportFlagsToAnnotFlags(VkDebugReportFlagsEXT dr_flags, bool default_flag_is_spec,
+                                         VkDebugUtilsMessageSeverityFlagBitsEXT *da_severity,
+                                         VkDebugUtilsMessageTypeFlagsEXT *da_type) {
+    bool type_set = false;
+    if (NULL == da_severity || NULL == da_type) {
+        return false;
+    }
+    *da_type = 0;
+
+    if ((dr_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) != 0) {
+        *da_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
+        *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT;
+        type_set = true;
+    } else if ((dr_flags & (VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT)) != 0) {
+        *da_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
+    } else if ((dr_flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) != 0) {
+        *da_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
+    } else if ((dr_flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) != 0) {
+        *da_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
+        *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT;
+        type_set = true;
+    }
+
+    if ((dr_flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) != 0) {
+        *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
+    } else if (!type_set) {
+        if (default_flag_is_spec) {
+            *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
+        } else {
+            *da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT;
+        }
+    }
+
+    return true;
+}
+
+bool debug_utils_AnnotFlagsToReportFlags(VkDebugUtilsMessageSeverityFlagBitsEXT da_severity,
+                                         VkDebugUtilsMessageTypeFlagsEXT da_type, VkDebugReportFlagsEXT *dr_flags) {
+    if (NULL == dr_flags) {
+        return false;
+    }
+
+    *dr_flags = 0;
+
+    if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) != 0) {
+        *dr_flags |= VK_DEBUG_REPORT_ERROR_BIT_EXT;
+    } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) != 0) {
+        if ((da_type & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) != 0) {
+            *dr_flags |= VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
+        } else {
+            *dr_flags |= VK_DEBUG_REPORT_WARNING_BIT_EXT;
+        }
+    } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) != 0) {
+        *dr_flags |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT;
+    } else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) != 0) {
+        *dr_flags |= VK_DEBUG_REPORT_DEBUG_BIT_EXT;
+    }
+
+    return true;
+}
+
+bool debug_utils_ReportObjectToAnnotObject(VkDebugReportObjectTypeEXT dr_object_type, uint64_t object_handle,
+                                           VkDebugUtilsObjectNameInfoEXT *da_object_name_info) {
+    if (NULL == da_object_name_info) {
+        return false;
+    }
+    da_object_name_info->sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
+    da_object_name_info->pNext = NULL;
+    da_object_name_info->objectHandle = (uint64_t)(uintptr_t)object_handle;
+    da_object_name_info->pObjectName = NULL;
+    da_object_name_info->objectType = convertDebugReportObjectToCoreObject(dr_object_type);
+    return true;
+}
+
+bool debug_utils_AnnotObjectToDebugReportObject(const VkDebugUtilsObjectNameInfoEXT *da_object_name_info,
+                                                VkDebugReportObjectTypeEXT *dr_object_type, uint64_t *dr_object_handle) {
+    if (NULL == da_object_name_info || NULL == dr_object_type || NULL == dr_object_handle) {
+        return false;
+    }
+    *dr_object_type = convertCoreObjectToDebugReportObject(da_object_name_info->objectType);
+    *dr_object_handle = da_object_name_info->objectHandle;
+    return true;
+}
diff --git a/loader/debug_utils.h b/loader/debug_utils.h
new file mode 100644
index 0000000..c33a6fc
--- /dev/null
+++ b/loader/debug_utils.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2015-2017 The Khronos Group Inc.
+ * Copyright (c) 2015-2017 Valve Corporation
+ * Copyright (c) 2015-2017 LunarG, Inc.
+ * Copyright (C) 2015-2016 Google Inc.
+ *
+ * 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.
+ *
+ * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
+ * Author: Jon Ashburn <jon@lunarg.com>
+ * Author: Mark Young <markyk@lunarg.com>
+ *
+ */
+
+#include "vk_loader_platform.h"
+#include "loader.h"
+
+// General utilities
+
+void debug_utils_AddInstanceExtensions(const struct loader_instance *inst, struct loader_extension_list *ext_list);
+void debug_utils_CreateInstance(struct loader_instance *ptr_instance, const VkInstanceCreateInfo *pCreateInfo);
+bool debug_utils_InstanceGpa(struct loader_instance *ptr_instance, const char *name, void **addr);
+bool debug_utils_ReportFlagsToAnnotFlags(VkDebugReportFlagsEXT dr_flags, bool default_flag_is_spec,
+                                         VkDebugUtilsMessageSeverityFlagBitsEXT *da_severity,
+                                         VkDebugUtilsMessageTypeFlagsEXT *da_type);
+bool debug_utils_AnnotFlagsToReportFlags(VkDebugUtilsMessageSeverityFlagBitsEXT da_severity,
+                                         VkDebugUtilsMessageTypeFlagsEXT da_type, VkDebugReportFlagsEXT *dr_flags);
+bool debug_utils_ReportObjectToAnnotObject(VkDebugReportObjectTypeEXT dr_object_type, uint64_t object_handle,
+                                           VkDebugUtilsObjectNameInfoEXT *da_object_name_info);
+bool debug_utils_AnnotObjectToDebugReportObject(const VkDebugUtilsObjectNameInfoEXT *da_object_name_info,
+                                                VkDebugReportObjectTypeEXT *dr_object_type, uint64_t *dr_object_handle);
+
+// VK_EXT_debug_utils related items
+
+VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDebugUtilsMessengerEXT(VkInstance instance,
+                                                                       const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,
+                                                                       const VkAllocationCallbacks *pAllocator,
+                                                                       VkDebugUtilsMessengerEXT *pMessenger);
+VKAPI_ATTR void VKAPI_CALL terminator_DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger,
+                                                                    const VkAllocationCallbacks *pAllocator);
+VKAPI_ATTR void VKAPI_CALL terminator_SubmitDebugUtilsMessageEXT(VkInstance instance,
+                                                                 VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
+                                                                 VkDebugUtilsMessageTypeFlagsEXT messageTypes,
+                                                                 const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData);
+VkResult util_CreateDebugUtilsMessenger(struct loader_instance *inst, const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,
+                                        const VkAllocationCallbacks *pAllocator, VkDebugUtilsMessengerEXT messenger);
+VkResult util_CreateDebugUtilsMessengers(struct loader_instance *inst, const VkAllocationCallbacks *pAllocator,
+                                         uint32_t num_messengers, VkDebugUtilsMessengerCreateInfoEXT *infos,
+                                         VkDebugUtilsMessengerEXT *messengers);
+VkBool32 util_SubmitDebugUtilsMessageEXT(const struct loader_instance *inst, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
+                                         VkDebugUtilsMessageTypeFlagsEXT messageTypes,
+                                         const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData);
+VkResult util_CopyDebugUtilsMessengerCreateInfos(const void *pChain, const VkAllocationCallbacks *pAllocator,
+                                                 uint32_t *num_messengers, VkDebugUtilsMessengerCreateInfoEXT **infos,
+                                                 VkDebugUtilsMessengerEXT **messengers);
+void util_DestroyDebugUtilsMessenger(struct loader_instance *inst, VkDebugUtilsMessengerEXT messenger,
+                                     const VkAllocationCallbacks *pAllocator);
+void util_DestroyDebugUtilsMessengers(struct loader_instance *inst, const VkAllocationCallbacks *pAllocator,
+                                      uint32_t num_messengers, VkDebugUtilsMessengerEXT *messengers);
+void util_FreeDebugUtilsMessengerCreateInfos(const VkAllocationCallbacks *pAllocator, VkDebugUtilsMessengerCreateInfoEXT *infos,
+                                             VkDebugUtilsMessengerEXT *messengers);
+
+// VK_EXT_debug_report related items
+
+VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDebugReportCallbackEXT(VkInstance instance,
+                                                                       const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
+                                                                       const VkAllocationCallbacks *pAllocator,
+                                                                       VkDebugReportCallbackEXT *pCallback);
+
+VKAPI_ATTR void VKAPI_CALL terminator_DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback,
+                                                                    const VkAllocationCallbacks *pAllocator);
+
+VKAPI_ATTR void VKAPI_CALL terminator_DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags,
+                                                            VkDebugReportObjectTypeEXT objType, uint64_t object, size_t location,
+                                                            int32_t msgCode, const char *pLayerPrefix, const char *pMsg);
+
+VkResult util_CreateDebugReportCallback(struct loader_instance *inst, VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
+                                        const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT callback);
+VkResult util_CreateDebugReportCallbacks(struct loader_instance *inst, const VkAllocationCallbacks *pAllocator,
+                                         uint32_t num_callbacks, VkDebugReportCallbackCreateInfoEXT *infos,
+                                         VkDebugReportCallbackEXT *callbacks);
+VkBool32 util_DebugReportMessage(const struct loader_instance *inst, VkFlags msgFlags, VkDebugReportObjectTypeEXT objectType,
+                                 uint64_t srcObject, size_t location, int32_t msgCode, const char *pLayerPrefix, const char *pMsg);
+VkResult util_CopyDebugReportCreateInfos(const void *pChain, const VkAllocationCallbacks *pAllocator, uint32_t *num_callbacks,
+                                         VkDebugReportCallbackCreateInfoEXT **infos, VkDebugReportCallbackEXT **callbacks);
+void util_DestroyDebugReportCallback(struct loader_instance *inst, VkDebugReportCallbackEXT callback,
+                                     const VkAllocationCallbacks *pAllocator);
+void util_DestroyDebugReportCallbacks(struct loader_instance *inst, const VkAllocationCallbacks *pAllocator, uint32_t num_callbacks,
+                                      VkDebugReportCallbackEXT *callbacks);
+void util_FreeDebugReportCreateInfos(const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackCreateInfoEXT *infos,
+                                     VkDebugReportCallbackEXT *callbacks);
diff --git a/loader/extension_manual.c b/loader/extension_manual.c
index 65c625e..2b70af7 100644
--- a/loader/extension_manual.c
+++ b/loader/extension_manual.c
@@ -28,7 +28,7 @@
 #include "vk_loader_extensions.h"
 #include <vulkan/vk_icd.h>
 #include "wsi.h"
-#include "debug_report.h"
+#include "debug_utils.h"
 
 // ---- Manually added trampoline/terminator functions
 
diff --git a/loader/gpa_helper.h b/loader/gpa_helper.h
index 463e352..1196edf 100644
--- a/loader/gpa_helper.h
+++ b/loader/gpa_helper.h
@@ -20,7 +20,7 @@
  */
 
 #include <string.h>
-#include "debug_report.h"
+#include "debug_utils.h"
 #include "wsi.h"
 
 static inline void *trampolineGetProcAddr(struct loader_instance *inst, const char *funcName) {
@@ -189,7 +189,7 @@
 
     // Instance extensions
     void *addr;
-    if (debug_report_instance_gpa(inst, funcName, &addr)) return addr;
+    if (debug_utils_InstanceGpa(inst, funcName, &addr)) return addr;
 
     if (wsi_swapchain_instance_gpa(inst, funcName, &addr)) return addr;
 
diff --git a/loader/loader.c b/loader/loader.c
index d4e0e02..92be90b 100644
--- a/loader/loader.c
+++ b/loader/loader.c
@@ -45,7 +45,7 @@
 #include "vk_loader_platform.h"
 #include "loader.h"
 #include "gpa_helper.h"
-#include "debug_report.h"
+#include "debug_utils.h"
 #include "wsi.h"
 #include "vulkan/vk_icd.h"
 #include "cJSON.h"
@@ -322,8 +322,46 @@
     va_end(ap);
 
     if (inst) {
-        util_DebugReportMessage(inst, msg_type, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, (uint64_t)(uintptr_t)inst, 0, msg_code,
-                                "loader", msg);
+        VkDebugUtilsMessageSeverityFlagBitsEXT severity;
+        VkDebugUtilsMessageTypeFlagsEXT type;
+        VkDebugUtilsMessengerCallbackDataEXT callback_data;
+        VkDebugUtilsObjectNameInfoEXT object_name;
+
+        if ((msg_type & LOADER_INFO_BIT) != 0) {
+            severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
+        } else if ((msg_type & LOADER_WARN_BIT) != 0) {
+            severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
+        } else if ((msg_type & LOADER_ERROR_BIT) != 0) {
+            severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
+        } else if ((msg_type & LOADER_DEBUG_BIT) != 0) {
+            severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
+        }
+
+        if ((msg_type & LOADER_PERF_BIT) != 0) {
+            type = VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
+        } else {
+            type = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT;
+        }
+
+        callback_data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT;
+        callback_data.pNext = NULL;
+        callback_data.flags = 0;
+        callback_data.pMessageIdName = "Loader Message";
+        callback_data.messageIdNumber = 0;
+        callback_data.pMessage = msg;
+        callback_data.queueLabelCount = 0;
+        callback_data.pQueueLabels = NULL;
+        callback_data.cmdBufLabelCount = 0;
+        callback_data.pCmdBufLabels = NULL;
+        callback_data.objectCount = 1;
+        callback_data.pObjects = &object_name;
+        object_name.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
+        object_name.pNext = NULL;
+        object_name.objectType = VK_OBJECT_TYPE_INSTANCE;
+        object_name.objectHandle = (uint64_t)(uintptr_t)inst;
+        object_name.pObjectName = NULL;
+
+        util_SubmitDebugUtilsMessageEXT(inst, severity, type, &callback_data);
     }
 
     if (!(msg_type & g_loader_log_msgs)) {
@@ -1608,7 +1646,7 @@
     };
 
     // Traverse loader's extensions, adding non-duplicate extensions to the list
-    debug_report_add_instance_extensions(inst, inst_exts);
+    debug_utils_AddInstanceExtensions(inst, inst_exts);
 
 out:
     return res;
diff --git a/loader/loader.h b/loader/loader.h
index ae928f9..9342e21 100644
--- a/loader/loader.h
+++ b/loader/loader.h
@@ -276,9 +276,12 @@
     union loader_instance_extension_enables enabled_known_extensions;
 
     VkLayerDbgFunctionNode *DbgFunctionHead;
-    uint32_t num_tmp_callbacks;
-    VkDebugReportCallbackCreateInfoEXT *tmp_dbg_create_infos;
-    VkDebugReportCallbackEXT *tmp_callbacks;
+    uint32_t num_tmp_report_callbacks;
+    VkDebugReportCallbackCreateInfoEXT *tmp_report_create_infos;
+    VkDebugReportCallbackEXT *tmp_report_callbacks;
+    uint32_t num_tmp_messengers;
+    VkDebugUtilsMessengerCreateInfoEXT *tmp_messenger_create_infos;
+    VkDebugUtilsMessengerEXT *tmp_messengers;
 
     VkAllocationCallbacks alloc_callbacks;
 
diff --git a/loader/trampoline.c b/loader/trampoline.c
index 7915006..6b0464d 100644
--- a/loader/trampoline.c
+++ b/loader/trampoline.c
@@ -28,7 +28,7 @@
 
 #include "vk_loader_platform.h"
 #include "loader.h"
-#include "debug_report.h"
+#include "debug_utils.h"
 #include "wsi.h"
 #include "vk_loader_extensions.h"
 #include "gpa_helper.h"
@@ -324,23 +324,42 @@
         ptr_instance->app_api_minor_version = VK_VERSION_MINOR(pCreateInfo->pApplicationInfo->apiVersion);
     }
 
-    // Look for one or more debug report create info structures
+    // Look for one or more VK_EXT_debug_report or VK_EXT_debug_utils create info structures
     // and setup a callback(s) for each one found.
-    ptr_instance->num_tmp_callbacks = 0;
-    ptr_instance->tmp_dbg_create_infos = NULL;
-    ptr_instance->tmp_callbacks = NULL;
-    if (util_CopyDebugReportCreateInfos(pCreateInfo->pNext, pAllocator, &ptr_instance->num_tmp_callbacks,
-                                        &ptr_instance->tmp_dbg_create_infos, &ptr_instance->tmp_callbacks)) {
-        // One or more were found, but allocation failed.  Therefore, clean up
-        // and fail this function:
+    ptr_instance->num_tmp_report_callbacks = 0;
+    ptr_instance->tmp_report_create_infos = NULL;
+    ptr_instance->tmp_report_callbacks = NULL;
+    ptr_instance->num_tmp_messengers = 0;
+    ptr_instance->tmp_messenger_create_infos = NULL;
+    ptr_instance->tmp_messengers = NULL;
+
+    // Handle cases of VK_EXT_debug_utils
+    if (util_CopyDebugUtilsMessengerCreateInfos(pCreateInfo->pNext, pAllocator, &ptr_instance->num_tmp_messengers,
+                                                &ptr_instance->tmp_messenger_create_infos, &ptr_instance->tmp_messengers)) {
+        // One or more were found, but allocation failed.  Therefore, clean up and fail this function:
         res = VK_ERROR_OUT_OF_HOST_MEMORY;
         goto out;
-    } else if (ptr_instance->num_tmp_callbacks > 0) {
+    } else if (ptr_instance->num_tmp_messengers > 0) {
+        // Setup the temporary messenger(s) here to catch early issues:
+        if (util_CreateDebugUtilsMessengers(ptr_instance, pAllocator, ptr_instance->num_tmp_messengers,
+                                            ptr_instance->tmp_messenger_create_infos, ptr_instance->tmp_messengers)) {
+            // Failure of setting up one or more of the messenger.  Therefore, clean up and fail this function:
+            res = VK_ERROR_OUT_OF_HOST_MEMORY;
+            goto out;
+        }
+    }
+
+    // Handle cases of VK_EXT_debug_report
+    if (util_CopyDebugReportCreateInfos(pCreateInfo->pNext, pAllocator, &ptr_instance->num_tmp_report_callbacks,
+                                        &ptr_instance->tmp_report_create_infos, &ptr_instance->tmp_report_callbacks)) {
+        // One or more were found, but allocation failed.  Therefore, clean up and fail this function:
+        res = VK_ERROR_OUT_OF_HOST_MEMORY;
+        goto out;
+    } else if (ptr_instance->num_tmp_report_callbacks > 0) {
         // Setup the temporary callback(s) here to catch early issues:
-        if (util_CreateDebugReportCallbacks(ptr_instance, pAllocator, ptr_instance->num_tmp_callbacks,
-                                            ptr_instance->tmp_dbg_create_infos, ptr_instance->tmp_callbacks)) {
-            // Failure of setting up one or more of the callback.  Therefore,
-            // clean up and fail this function:
+        if (util_CreateDebugReportCallbacks(ptr_instance, pAllocator, ptr_instance->num_tmp_report_callbacks,
+                                            ptr_instance->tmp_report_create_infos, ptr_instance->tmp_report_callbacks)) {
+            // Failure of setting up one or more of the callback.  Therefore, clean up and fail this function:
             res = VK_ERROR_OUT_OF_HOST_MEMORY;
             goto out;
         }
@@ -404,7 +423,7 @@
         memset(ptr_instance->enabled_known_extensions.padding, 0, sizeof(uint64_t) * 4);
 
         wsi_create_instance(ptr_instance, &ici);
-        debug_report_create_instance(ptr_instance, &ici);
+        debug_utils_CreateInstance(ptr_instance, &ici);
         extensions_create_instance(ptr_instance, &ici);
 
         *pInstance = created_instance;
@@ -426,10 +445,19 @@
             if (NULL != ptr_instance->disp) {
                 loader_instance_heap_free(ptr_instance, ptr_instance->disp);
             }
-            if (ptr_instance->num_tmp_callbacks > 0) {
-                util_DestroyDebugReportCallbacks(ptr_instance, pAllocator, ptr_instance->num_tmp_callbacks,
-                                                 ptr_instance->tmp_callbacks);
-                util_FreeDebugReportCreateInfos(pAllocator, ptr_instance->tmp_dbg_create_infos, ptr_instance->tmp_callbacks);
+            if (ptr_instance->num_tmp_report_callbacks > 0) {
+                // Remove temporary VK_EXT_debug_report items
+                util_DestroyDebugReportCallbacks(ptr_instance, pAllocator, ptr_instance->num_tmp_report_callbacks,
+                                                 ptr_instance->tmp_report_callbacks);
+                util_FreeDebugReportCreateInfos(pAllocator, ptr_instance->tmp_report_create_infos,
+                                                ptr_instance->tmp_report_callbacks);
+            }
+            if (ptr_instance->num_tmp_messengers > 0) {
+                // Remove temporary VK_EXT_debug_utils items
+                util_DestroyDebugUtilsMessengers(ptr_instance, pAllocator, ptr_instance->num_tmp_messengers,
+                                                 ptr_instance->tmp_messengers);
+                util_FreeDebugUtilsMessengerCreateInfos(pAllocator, ptr_instance->tmp_messenger_create_infos,
+                                                        ptr_instance->tmp_messengers);
             }
 
             if (NULL != ptr_instance->expanded_activated_layer_list.list) {
@@ -445,9 +473,11 @@
 
             loader_instance_heap_free(ptr_instance, ptr_instance);
         } else {
-            // Remove temporary debug_report callback
-            util_DestroyDebugReportCallbacks(ptr_instance, pAllocator, ptr_instance->num_tmp_callbacks,
-                                             ptr_instance->tmp_callbacks);
+            // Remove temporary VK_EXT_debug_report or VK_EXT_debug_utils items
+            util_DestroyDebugUtilsMessengers(ptr_instance, pAllocator, ptr_instance->num_tmp_messengers,
+                                             ptr_instance->tmp_messengers);
+            util_DestroyDebugReportCallbacks(ptr_instance, pAllocator, ptr_instance->num_tmp_report_callbacks,
+                                             ptr_instance->tmp_report_callbacks);
         }
 
         if (loaderLocked) {
@@ -462,6 +492,7 @@
     const VkLayerInstanceDispatchTable *disp;
     struct loader_instance *ptr_instance = NULL;
     bool callback_setup = false;
+    bool messenger_setup = false;
 
     if (instance == VK_NULL_HANDLE) {
         return;
@@ -477,10 +508,18 @@
         ptr_instance->alloc_callbacks = *pAllocator;
     }
 
-    if (ptr_instance->num_tmp_callbacks > 0) {
-        // Setup the temporary callback(s) here to catch cleanup issues:
-        if (!util_CreateDebugReportCallbacks(ptr_instance, pAllocator, ptr_instance->num_tmp_callbacks,
-                                             ptr_instance->tmp_dbg_create_infos, ptr_instance->tmp_callbacks)) {
+    if (ptr_instance->num_tmp_messengers > 0) {
+        // Setup the temporary VK_EXT_debug_utils messenger(s) here to catch cleanup issues:
+        if (!util_CreateDebugUtilsMessengers(ptr_instance, pAllocator, ptr_instance->num_tmp_messengers,
+                                             ptr_instance->tmp_messenger_create_infos, ptr_instance->tmp_messengers)) {
+            messenger_setup = true;
+        }
+    }
+
+    if (ptr_instance->num_tmp_report_callbacks > 0) {
+        // Setup the temporary VK_EXT_debug_report callback(s) here to catch cleanup issues:
+        if (!util_CreateDebugReportCallbacks(ptr_instance, pAllocator, ptr_instance->num_tmp_report_callbacks,
+                                             ptr_instance->tmp_report_create_infos, ptr_instance->tmp_report_callbacks)) {
             callback_setup = true;
         }
     }
@@ -508,9 +547,15 @@
         loader_instance_heap_free(ptr_instance, ptr_instance->phys_dev_groups_tramp);
     }
 
+    if (messenger_setup) {
+        util_DestroyDebugUtilsMessengers(ptr_instance, pAllocator, ptr_instance->num_tmp_messengers, ptr_instance->tmp_messengers);
+        util_FreeDebugUtilsMessengerCreateInfos(pAllocator, ptr_instance->tmp_messenger_create_infos, ptr_instance->tmp_messengers);
+    }
+
     if (callback_setup) {
-        util_DestroyDebugReportCallbacks(ptr_instance, pAllocator, ptr_instance->num_tmp_callbacks, ptr_instance->tmp_callbacks);
-        util_FreeDebugReportCreateInfos(pAllocator, ptr_instance->tmp_dbg_create_infos, ptr_instance->tmp_callbacks);
+        util_DestroyDebugReportCallbacks(ptr_instance, pAllocator, ptr_instance->num_tmp_report_callbacks,
+                                         ptr_instance->tmp_report_callbacks);
+        util_FreeDebugReportCreateInfos(pAllocator, ptr_instance->tmp_report_create_infos, ptr_instance->tmp_report_callbacks);
     }
     loader_instance_heap_free(ptr_instance, ptr_instance->disp);
     loader_instance_heap_free(ptr_instance, ptr_instance);
diff --git a/loader/vk_loader_layer.h b/loader/vk_loader_layer.h
index 425154d..dfcf5b2 100644
--- a/loader/vk_loader_layer.h
+++ b/loader/vk_loader_layer.h
@@ -21,11 +21,26 @@
 */
 #pragma once
 
-// Linked list node for tree of debug callback functions
-typedef struct VkLayerDbgFunctionNode_ {
+// Linked list node for tree of debug callbacks
+typedef struct VkDebugReportContent {
     VkDebugReportCallbackEXT msgCallback;
     PFN_vkDebugReportCallbackEXT pfnMsgCallback;
     VkFlags msgFlags;
+} VkDebugReportContent;
+
+typedef struct VkDebugUtilsMessengerContent {
+    VkDebugUtilsMessengerEXT messenger;
+    VkDebugUtilsMessageSeverityFlagsEXT messageSeverity;
+    VkDebugUtilsMessageTypeFlagsEXT messageType;
+    PFN_vkDebugUtilsMessengerCallbackEXT pfnUserCallback;
+} VkDebugUtilsMessengerContent;
+
+typedef struct VkLayerDbgFunctionNode_ {
+    bool is_messenger;
+    union {
+        VkDebugReportContent report;
+        VkDebugUtilsMessengerContent messenger;
+    };
     void *pUserData;
     struct VkLayerDbgFunctionNode_ *pNext;
 } VkLayerDbgFunctionNode;
diff --git a/scripts/helper_file_generator.py b/scripts/helper_file_generator.py
index fb519b6..e460f96 100644
--- a/scripts/helper_file_generator.py
+++ b/scripts/helper_file_generator.py
@@ -747,7 +747,8 @@
     #
     # Object types header: create object enum type header file
     def GenerateObjectTypesHeader(self):
-        object_types_header = '// Object Type enum for validation layer internal object handling\n'
+        object_types_header = ''
+        object_types_header += '// Object Type enum for validation layer internal object handling\n'
         object_types_header += 'typedef enum VulkanObjectType {\n'
         object_types_header += '    kVulkanObjectTypeUnknown = 0,\n'
         enum_num = 1
@@ -777,7 +778,7 @@
         object_types_header += '\n'
         object_types_header += '// Helper array to get Vulkan VK_EXT_debug_report object type enum from the internal layers version\n'
         object_types_header += 'const VkDebugReportObjectTypeEXT get_debug_report_enum[] = {\n'
-        object_types_header += '    VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, // No Match\n'
+        object_types_header += '    VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, // kVulkanObjectTypeUnknown\n'
         for object_type in type_list:
             search_type = object_type.replace("kVulkanObjectType", "").lower()
             for vk_object_type in self.debug_report_object_types:
@@ -793,7 +794,7 @@
         object_types_header += '\n'
         object_types_header += '// Helper array to get Official Vulkan VkObjectType enum from the internal layers version\n'
         object_types_header += 'const VkObjectType get_object_type_enum[] = {\n'
-        object_types_header += '    VK_OBJECT_TYPE_UNKNOWN, // No Match\n'
+        object_types_header += '    VK_OBJECT_TYPE_UNKNOWN, // kVulkanObjectTypeUnknown\n'
         for object_type in type_list:
             search_type = object_type.replace("kVulkanObjectType", "").lower()
             for vk_object_type in self.core_object_types:
@@ -804,6 +805,47 @@
                     break
         object_types_header += '};\n'
 
+        # Create a function to convert from VkDebugReportObjectTypeEXT to VkObjectType
+        object_types_header += '\n'
+        object_types_header += '// Helper function to convert from VkDebugReportObjectTypeEXT to VkObjectType\n'
+        object_types_header += 'static VkObjectType convertDebugReportObjectToCoreObject(VkDebugReportObjectTypeEXT debug_report_obj){\n'
+        object_types_header += '    if (debug_report_obj == VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT) {\n'
+        object_types_header += '        return VK_OBJECT_TYPE_UNKNOWN;\n'
+        for core_object_type in self.core_object_types:
+            core_target_type = core_object_type.replace("VK_OBJECT_TYPE_", "").lower()
+            core_target_type = core_target_type.replace("_", "")
+            for dr_object_type in self.debug_report_object_types:
+                dr_target_type = dr_object_type.replace("VK_DEBUG_REPORT_OBJECT_TYPE_", "").lower()
+                dr_target_type = dr_target_type[:-4]
+                dr_target_type = dr_target_type.replace("_", "")
+                if core_target_type == dr_target_type:
+                    object_types_header += '    } else if (debug_report_obj == %s) {\n' % dr_object_type
+                    object_types_header += '        return %s;\n' % core_object_type
+                    break
+        object_types_header += '    }\n'
+        object_types_header += '    return VK_OBJECT_TYPE_UNKNOWN;\n'
+        object_types_header += '}\n'
+
+        # Create a function to convert from VkObjectType to VkDebugReportObjectTypeEXT
+        object_types_header += '\n'
+        object_types_header += '// Helper function to convert from VkDebugReportObjectTypeEXT to VkObjectType\n'
+        object_types_header += 'static VkDebugReportObjectTypeEXT convertCoreObjectToDebugReportObject(VkObjectType core_report_obj){\n'
+        object_types_header += '    if (core_report_obj == VK_OBJECT_TYPE_UNKNOWN) {\n'
+        object_types_header += '        return VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT;\n'
+        for core_object_type in self.core_object_types:
+            core_target_type = core_object_type.replace("VK_OBJECT_TYPE_", "").lower()
+            core_target_type = core_target_type.replace("_", "")
+            for dr_object_type in self.debug_report_object_types:
+                dr_target_type = dr_object_type.replace("VK_DEBUG_REPORT_OBJECT_TYPE_", "").lower()
+                dr_target_type = dr_target_type[:-4]
+                dr_target_type = dr_target_type.replace("_", "")
+                if core_target_type == dr_target_type:
+                    object_types_header += '    } else if (core_report_obj == %s) {\n' % core_object_type
+                    object_types_header += '        return %s;\n' % dr_object_type
+                    break
+        object_types_header += '    }\n'
+        object_types_header += '    return VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT;\n'
+        object_types_header += '}\n'
         return object_types_header
     #
     # Determine if a structure needs a safe_struct helper function
diff --git a/scripts/loader_extension_generator.py b/scripts/loader_extension_generator.py
index a4a3f8f..ae2b3da 100644
--- a/scripts/loader_extension_generator.py
+++ b/scripts/loader_extension_generator.py
@@ -40,14 +40,25 @@
                  'VK_KHR_swapchain',
                  'VK_KHR_display_swapchain']
 
+ADD_INST_CMDS = ['vkCreateInstance',
+                 'vkEnumerateInstanceExtensionProperties',
+                 'vkEnumerateInstanceLayerProperties',
+                 'vkEnumerateInstanceVersion']
+
 AVOID_EXT_NAMES = ['VK_EXT_debug_report']
 
+AVOID_CMD_NAMES = ['vkCreateDebugUtilsMessengerEXT',
+                   'vkDestroyDebugUtilsMessengerEXT',
+                   'vkSubmitDebugUtilsMessageEXT']
+
 DEVICE_CMDS_NEED_TERM = ['vkGetDeviceProcAddr',
                          'vkCreateSwapchainKHR',
                          'vkCreateSharedSwapchainsKHR',
                          'vkGetDeviceGroupSurfacePresentModesKHR',
                          'vkDebugMarkerSetObjectTagEXT',
-                         'vkDebugMarkerSetObjectNameEXT']
+                         'vkDebugMarkerSetObjectNameEXT',
+                         'vkSetDebugUtilsObjectNameEXT',
+                         'vkSetDebugUtilsObjectTagEXT']
                          
 ALIASED_CMDS = {
     'vkEnumeratePhysicalDeviceGroupsKHR':                   'vkEnumeratePhysicalDeviceGroups',
@@ -176,7 +187,7 @@
             preamble += '#include "vk_loader_extensions.h"\n'
             preamble += '#include <vulkan/vk_icd.h>\n'
             preamble += '#include "wsi.h"\n'
-            preamble += '#include "debug_report.h"\n'
+            preamble += '#include "debug_utils.h"\n'
             preamble += '#include "extension_manual.h"\n'
 
         elif self.genOpts.filename == 'vk_layer_dispatch_table.h':
@@ -467,7 +478,9 @@
                 commands = self.ext_commands
 
             for cur_cmd in commands:
-                if cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice':
+                is_inst_handle_type = cur_cmd.name in ADD_INST_CMDS or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
+                if is_inst_handle_type:
+
                     if cur_cmd.ext_name != cur_extension_name:
                         if 'VK_VERSION_' in cur_cmd.ext_name:
                             table += '\n    // ---- Core %s commands\n' % cur_cmd.ext_name[11:]
@@ -506,7 +519,9 @@
                 commands = self.ext_commands
 
             for cur_cmd in commands:
-                if cur_cmd.handle_type != 'VkInstance' and cur_cmd.handle_type != 'VkPhysicalDevice':
+                is_inst_handle_type = cur_cmd.name in ADD_INST_CMDS or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
+                if not is_inst_handle_type:
+
                     if cur_cmd.ext_name != cur_extension_name:
                         if 'VK_VERSION_' in cur_cmd.ext_name:
                             table += '\n    // ---- Core %s commands\n' % cur_cmd.ext_name[11:]
@@ -545,7 +560,7 @@
                 commands = self.ext_commands
 
             for cur_cmd in commands:
-                is_inst_handle_type = cur_cmd.ext_type == 'instance' or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
+                is_inst_handle_type = cur_cmd.name in ADD_INST_CMDS or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
                 if ((is_inst_handle_type or cur_cmd.name in DEVICE_CMDS_NEED_TERM) and
                     (cur_cmd.name != 'vkGetInstanceProcAddr' and cur_cmd.name != 'vkEnumerateDeviceLayerProperties')):
 
@@ -607,7 +622,7 @@
 
             required = False
             for cur_cmd in commands:
-                is_inst_handle_type = cur_cmd.ext_type == 'instance' or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
+                is_inst_handle_type = cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
                 if ((is_inst_handle_type or cur_cmd.name in DEVICE_CMDS_NEED_TERM) and (cur_cmd.name not in skip_gipa_commands)):
 
                     if cur_cmd.ext_name != cur_extension_name:
@@ -666,7 +681,7 @@
         terminators += '// Loader core instance terminators\n'
 
         for cur_cmd in self.core_commands:
-            is_inst_handle_type = cur_cmd.ext_type == 'instance' or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
+            is_inst_handle_type = cur_cmd.name in ADD_INST_CMDS or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
             if is_inst_handle_type:
                 mod_string = ''
                 new_terminator = cur_cmd.cdecl
@@ -878,6 +893,7 @@
         for ext_cmd in self.ext_commands:
             if (ext_cmd.ext_name in WSI_EXT_NAMES or
                 ext_cmd.ext_name in AVOID_EXT_NAMES or
+                ext_cmd.name in AVOID_CMD_NAMES or
                 ext_cmd.name in manual_ext_commands):
                 continue
 
@@ -937,8 +953,9 @@
                 return_prefix += 'return '
                 has_return_type = True
 
-            if (ext_cmd.ext_type == 'instance' or ext_cmd.handle_type == 'VkPhysicalDevice' or
-                'DebugMarkerSetObject' in ext_cmd.name or ext_cmd.name in DEVICE_CMDS_NEED_TERM):
+            if (ext_cmd.handle_type == 'VkInstance' or ext_cmd.handle_type == 'VkPhysicalDevice' or
+                'DebugMarkerSetObject' in ext_cmd.name or 'SetDebugUtilsObject' in ext_cmd.name or
+                ext_cmd.name in DEVICE_CMDS_NEED_TERM):
                 requires_terminator = 1
 
             if requires_terminator == 1:
@@ -973,6 +990,22 @@
                     funcs += '        struct loader_physical_device_tramp *phys_dev_tramp = (struct loader_physical_device_tramp *)(uintptr_t)pTagInfo->object;\n'
                     funcs += '        local_tag_info.object = (uint64_t)(uintptr_t)phys_dev_tramp->phys_dev;\n'
                     funcs += '    }\n'
+                elif 'SetDebugUtilsObjectName' in ext_cmd.name:
+                    funcs += '    VkDebugUtilsObjectNameInfoEXT local_name_info;\n'
+                    funcs += '    memcpy(&local_name_info, pNameInfo, sizeof(VkDebugUtilsObjectNameInfoEXT));\n'
+                    funcs += '    // If this is a physical device, we have to replace it with the proper one for the next call.\n'
+                    funcs += '    if (pNameInfo->objectType == VK_OBJECT_TYPE_PHYSICAL_DEVICE) {\n'
+                    funcs += '        struct loader_physical_device_tramp *phys_dev_tramp = (struct loader_physical_device_tramp *)(uintptr_t)pNameInfo->objectHandle;\n'
+                    funcs += '        local_name_info.objectHandle = (uint64_t)(uintptr_t)phys_dev_tramp->phys_dev;\n'
+                    funcs += '    }\n'
+                elif 'SetDebugUtilsObjectTag' in ext_cmd.name:
+                    funcs += '    VkDebugUtilsObjectTagInfoEXT local_tag_info;\n'
+                    funcs += '    memcpy(&local_tag_info, pTagInfo, sizeof(VkDebugUtilsObjectTagInfoEXT));\n'
+                    funcs += '    // If this is a physical device, we have to replace it with the proper one for the next call.\n'
+                    funcs += '    if (pTagInfo->objectType == VK_OBJECT_TYPE_PHYSICAL_DEVICE) {\n'
+                    funcs += '        struct loader_physical_device_tramp *phys_dev_tramp = (struct loader_physical_device_tramp *)(uintptr_t)pTagInfo->objectHandle;\n'
+                    funcs += '        local_tag_info.objectHandle = (uint64_t)(uintptr_t)phys_dev_tramp->phys_dev;\n'
+                    funcs += '    }\n'
 
                 funcs += return_prefix
                 funcs += 'disp->'
@@ -985,9 +1018,9 @@
 
                     if param.type == 'VkPhysicalDevice':
                         funcs += 'unwrapped_phys_dev'
-                    elif 'DebugMarkerSetObject' in ext_cmd.name and param.name == 'pNameInfo':
+                    elif ('DebugMarkerSetObject' in ext_cmd.name or 'SetDebugUtilsObject' in ext_cmd.name) and param.name == 'pNameInfo':
                             funcs += '&local_name_info'
-                    elif 'DebugMarkerSetObject' in ext_cmd.name and param.name == 'pTagInfo':
+                    elif ('DebugMarkerSetObject' in ext_cmd.name or 'SetDebugUtilsObject' in ext_cmd.name) and param.name == 'pTagInfo':
                             funcs += '&local_tag_info'
                     else:
                         funcs += param.name
@@ -1059,7 +1092,7 @@
                         count += 1
                     funcs += ');\n'
 
-                elif has_surface == 1 and ext_cmd.ext_type == 'device':
+                elif has_surface == 1 and not (ext_cmd.handle_type == 'VkPhysicalDevice' or ext_cmd.handle_type == 'VkInstance'):
                     funcs += '    uint32_t icd_index = 0;\n'
                     funcs += '    struct loader_device *dev;\n'
                     funcs += '    struct loader_icd_term *icd_term = loader_get_icd_and_device(device, &dev, &icd_index);\n'
@@ -1096,7 +1129,7 @@
 
                 elif ext_cmd.handle_type == 'VkInstance':
                     funcs += '#error("Not implemented. Likely needs to be manually generated!");\n'
-                elif 'DebugMarkerSetObject' in ext_cmd.name:
+                elif 'DebugMarkerSetObject' in ext_cmd.name or 'SetDebugUtilsObject' in ext_cmd.name:
                     funcs += '    uint32_t icd_index = 0;\n'
                     funcs += '    struct loader_device *dev;\n'
                     funcs += '    struct loader_icd_term *icd_term = loader_get_icd_and_device(%s, &dev, &icd_index);\n' % (ext_cmd.params[0].name)
@@ -1131,6 +1164,45 @@
                         funcs += '                if (NULL != icd_surface->real_icd_surfaces) {\n'
                         funcs += '                    local_tag_info.object = (uint64_t)icd_surface->real_icd_surfaces[icd_index];\n'
                         funcs += '                }\n'
+                    elif 'SetDebugUtilsObjectName' in ext_cmd.name:
+                        funcs += '        VkDebugUtilsObjectNameInfoEXT local_name_info;\n'
+                        funcs += '        memcpy(&local_name_info, pNameInfo, sizeof(VkDebugUtilsObjectNameInfoEXT));\n'
+                        funcs += '        // If this is a physical device, we have to replace it with the proper one for the next call.\n'
+                        funcs += '        if (pNameInfo->objectType == VK_OBJECT_TYPE_PHYSICAL_DEVICE) {\n'
+                        funcs += '            struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)(uintptr_t)pNameInfo->objectHandle;\n'
+                        funcs += '            local_name_info.objectHandle = (uint64_t)(uintptr_t)phys_dev_term->phys_dev;\n'
+                        funcs += '        // If this is a KHR_surface, and the ICD has created its own, we have to replace it with the proper one for the next call.\n'
+                        funcs += '        } else if (pNameInfo->objectType == VK_OBJECT_TYPE_SURFACE_KHR) {\n'
+                        funcs += '            if (NULL != icd_term && NULL != icd_term->dispatch.CreateSwapchainKHR) {\n'
+                        funcs += '                VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)pNameInfo->objectHandle;\n'
+                        funcs += '                if (NULL != icd_surface->real_icd_surfaces) {\n'
+                        funcs += '                    local_name_info.objectHandle = (uint64_t)icd_surface->real_icd_surfaces[icd_index];\n'
+                        funcs += '                }\n'
+                    elif 'SetDebugUtilsObjectTag' in ext_cmd.name:
+                        funcs += '        VkDebugUtilsObjectTagInfoEXT local_tag_info;\n'
+                        funcs += '        memcpy(&local_tag_info, pTagInfo, sizeof(VkDebugUtilsObjectTagInfoEXT));\n'
+                        funcs += '        // If this is a physical device, we have to replace it with the proper one for the next call.\n'
+                        funcs += '        if (pTagInfo->objectType == VK_OBJECT_TYPE_PHYSICAL_DEVICE) {\n'
+                        funcs += '            struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)(uintptr_t)pTagInfo->objectHandle;\n'
+                        funcs += '            local_tag_info.objectHandle = (uint64_t)(uintptr_t)phys_dev_term->phys_dev;\n'
+                        funcs += '        // If this is a KHR_surface, and the ICD has created its own, we have to replace it with the proper one for the next call.\n'
+                        funcs += '        } else if (pTagInfo->objectType == VK_OBJECT_TYPE_SURFACE_KHR) {\n'
+                        funcs += '            if (NULL != icd_term && NULL != icd_term->dispatch.CreateSwapchainKHR) {\n'
+                        funcs += '                VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)pTagInfo->objectHandle;\n'
+                        funcs += '                if (NULL != icd_surface->real_icd_surfaces) {\n'
+                        funcs += '                    local_tag_info.objectHandle = (uint64_t)icd_surface->real_icd_surfaces[icd_index];\n'
+                        funcs += '                }\n'
+                    else:
+                        funcs += '        if (%s->objectType == VK_OBJECT_TYPE_PHYSICAL_DEVICE) {\n' % (ext_cmd.params[1].name)
+                        funcs += '            struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)(uintptr_t)%s->objectHandle;\n' % (ext_cmd.params[1].name)
+                        funcs += '            %s->objectHandle = (uint64_t)(uintptr_t)phys_dev_term->phys_dev;\n' % (ext_cmd.params[1].name)
+                        funcs += '        // If this is a KHR_surface, and the ICD has created its own, we have to replace it with the proper one for the next call.\n'
+                        funcs += '        } else if (%s->objectType == VK_OBJECT_TYPE_SURFACE_KHR) {\n' % (ext_cmd.params[1].name)
+                        funcs += '            if (NULL != icd_term && NULL != icd_term->dispatch.CreateSwapchainKHR) {\n'
+                        funcs += '                VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)%s->objectHandle;\n' % (ext_cmd.params[1].name)
+                        funcs += '                if (NULL != icd_surface->real_icd_surfaces) {\n'
+                        funcs += '                    %s->objectHandle = (uint64_t)icd_surface->real_icd_surfaces[icd_index];\n' % (ext_cmd.params[1].name)
+                        funcs += '                }\n'
                     funcs += '            }\n'
                     funcs += '        }\n'
                     funcs += '        return icd_term->dispatch.'
@@ -1145,9 +1217,9 @@
                             funcs += 'phys_dev_term->phys_dev'
                         elif param.type == 'VkSurfaceKHR':
                             funcs += 'icd_surface->real_icd_surfaces[icd_index]'
-                        elif 'DebugMarkerSetObject' in ext_cmd.name and param.name == 'pNameInfo':
+                        elif ('DebugMarkerSetObject' in ext_cmd.name or 'SetDebugUtilsObject' in ext_cmd.name) and param.name == 'pNameInfo':
                             funcs += '&local_name_info'
-                        elif 'DebugMarkerSetObject' in ext_cmd.name and param.name == 'pTagInfo':
+                        elif ('DebugMarkerSetObject' in ext_cmd.name or 'SetDebugUtilsObject' in ext_cmd.name) and param.name == 'pTagInfo':
                             funcs += '&local_tag_info'
                         else:
                             funcs += param.name
@@ -1202,7 +1274,8 @@
         for cur_cmd in self.ext_commands:
             if ('VK_VERSION_' in cur_cmd.ext_name or
                 cur_cmd.ext_name in WSI_EXT_NAMES or
-                cur_cmd.ext_name in AVOID_EXT_NAMES):
+                cur_cmd.ext_name in AVOID_EXT_NAMES or
+                cur_cmd.name in AVOID_CMD_NAMES ):
                 continue
 
             if cur_cmd.ext_name != cur_extension_name:
@@ -1252,8 +1325,8 @@
         create_func += '    for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {\n'
         for ext in entries:
             if ('VK_VERSION_' in ext.name or ext.name in WSI_EXT_NAMES or
-                ext.name in AVOID_EXT_NAMES or ext.type == 'device' or
-                ext.num_commands == 0):
+                ext.name in AVOID_EXT_NAMES or ext.name in AVOID_CMD_NAMES or
+                ext.type == 'device' or ext.num_commands == 0):
                 continue
 
             if ext.name != cur_extension_name:
diff --git a/scripts/object_tracker_generator.py b/scripts/object_tracker_generator.py
index 405a5b7..26c1105 100644
--- a/scripts/object_tracker_generator.py
+++ b/scripts/object_tracker_generator.py
@@ -172,6 +172,17 @@
             'vkGetDeviceQueue',
             'vkGetSwapchainImagesKHR',
             'vkCreateDescriptorSetLayout',
+            'vkCreateDebugUtilsMessengerEXT',
+            'vkDestroyDebugUtilsMessengerEXT',
+            'vkSubmitDebugUtilsMessageEXT',
+            'vkSetDebugUtilsObjectNameEXT',
+            'vkSetDebugUtilsObjectTagEXT',
+            'vkQueueBeginDebugUtilsLabelEXT',
+            'vkQueueEndDebugUtilsLabelEXT',
+            'vkQueueInsertDebugUtilsLabelEXT',
+            'vkCmdBeginDebugUtilsLabelEXT',
+            'vkCmdEndDebugUtilsLabelEXT',
+            'vkCmdInsertDebugUtilsLabelEXT',
             ]
         # These VUIDS are not implicit, but are best handled in this layer. Codegen for vkDestroy calls will generate a key
         # which is translated here into a good VU.  Saves ~40 checks.
diff --git a/scripts/parameter_validation_generator.py b/scripts/parameter_validation_generator.py
index edd49b5..4246eea 100644
--- a/scripts/parameter_validation_generator.py
+++ b/scripts/parameter_validation_generator.py
@@ -127,17 +127,12 @@
         self.blacklist = [
             'vkGetInstanceProcAddr',
             'vkGetDeviceProcAddr',
-            'vkEnumerateInstanceLayerProperties',
-            'vkEnumerateInstanceExtensionsProperties',
-            'vkEnumerateDeviceLayerProperties',
-            'vkEnumerateDeviceExtensionsProperties',
-            'vkCreateDebugReportCallbackKHR',
-            'vkDestroyDebugReportCallbackKHR',
+            'vkEnumerateInstanceVersion',
             'vkEnumerateInstanceLayerProperties',
             'vkEnumerateInstanceExtensionProperties',
             'vkEnumerateDeviceLayerProperties',
-            'vkCmdDebugMarkerEndEXT',
             'vkEnumerateDeviceExtensionProperties',
+            'vkCmdDebugMarkerEndEXT',
             ]
         self.validate_only = [
             'vkCreateInstance',
@@ -150,6 +145,8 @@
             'vkCreateCommandPool',
             'vkCreateRenderPass',
             'vkDestroyRenderPass',
+            'vkCreateDebugUtilsMessengerEXT',
+            'vkDestroyDebugUtilsMessengerEXT',
             ]
         # Structure fields to ignore
         self.structMemberBlacklist = { 'VkWriteDescriptorSet' : ['dstSet'] }
diff --git a/scripts/threading_generator.py b/scripts/threading_generator.py
index fd88909..4ac65d6 100644
--- a/scripts/threading_generator.py
+++ b/scripts/threading_generator.py
@@ -384,6 +384,8 @@
             'vkEnumerateInstanceExtensionProperties',
             'vkEnumerateDeviceLayerProperties',
             'vkEnumerateDeviceExtensionProperties',
+            'vkCreateDebugUtilsMessengerEXT',
+            'vkDestroyDebugUtilsMessengerEXT',
         ]
         if name in special_functions:
             decls = self.makeCDecls(cmdinfo.elem)
@@ -392,7 +394,7 @@
             self.appendSection('command', decls[0])
             self.intercepts += [ '    {"%s", (void*)%s},' % (name,name[2:]) ]
             return
-        if "QueuePresentKHR" in name or ("DebugMarker" in name and "EXT" in name):
+        if "QueuePresentKHR" in name or (("DebugMarker" in name or "DebugUtilsObject" in name) and "EXT" in name):
             self.appendSection('command', '// TODO - not wrapping EXT function ' + name)
             return
         # Determine first if this function needs to be intercepted
diff --git a/scripts/unique_objects_generator.py b/scripts/unique_objects_generator.py
index 78526a3..289a5bb 100644
--- a/scripts/unique_objects_generator.py
+++ b/scripts/unique_objects_generator.py
@@ -157,6 +157,8 @@
             'vkGetDisplayModeProperties2KHR',
             'vkCreateRenderPass',
             'vkDestroyRenderPass',
+            'vkSetDebugUtilsObjectNameEXT',
+            'vkSetDebugUtilsObjectTagEXT',
             ]
         # Commands shadowed by interface functions and are not implemented
         self.interface_functions = [
@@ -165,10 +167,14 @@
             'vkGetDisplayPlaneSupportedDisplaysKHR',
             'vkGetDisplayModePropertiesKHR',
             'vkGetDisplayPlaneCapabilitiesKHR',
-            # DebugReport APIs are hooked, but handled separately in the source file
+            # VK_EXT_debug_report APIs are hooked, but handled separately in the source file
             'vkCreateDebugReportCallbackEXT',
             'vkDestroyDebugReportCallbackEXT',
             'vkDebugReportMessageEXT',
+            # VK_EXT_debug_utils APIs are hooked, but handled separately in the source file
+            'vkCreateDebugUtilsMessengerEXT',
+            'vkDestroyDebugUtilsMessengerEXT',
+            'vkSubmitDebugUtilsMessageEXT',
             ]
         self.headerVersion = None
         # Internal state - accumulators for different inner block text
diff --git a/scripts/vuid_mapping.py b/scripts/vuid_mapping.py
index e3dbfdf..88df867 100644
--- a/scripts/vuid_mapping.py
+++ b/scripts/vuid_mapping.py
@@ -1104,7 +1104,7 @@
 # Convert a string VUID into numerical value
 #  See "VUID Mapping Details" comment above for more info
 def convertVUID(vuid_string):
-    """Convert a string-based VUID into a numberical value"""
+    """Convert a string-based VUID into a numerical value"""
     #func_struct_update = False
     #imp_param_update = False
     if vuid_string in ['', None]: