layers: Add debug report header

Enable output of a short message header containing definitions of
debug message types.

Change-Id: Ia84fb0e79d599b8d022b7d78267b7b6a0307823e
diff --git a/layers/VkLayer_utils.def b/layers/VkLayer_utils.def
index d2b5285..629c7d0 100644
--- a/layers/VkLayer_utils.def
+++ b/layers/VkLayer_utils.def
@@ -43,3 +43,5 @@
 layer_debug_actions
 util_GetExtensionProperties
 util_GetLayerProperties
+LogMessageInitialized
+SetLogMessageInitialized
diff --git a/layers/vk_layer_config.cpp b/layers/vk_layer_config.cpp
index 049ffdc..d1f61e1 100644
--- a/layers/vk_layer_config.cpp
+++ b/layers/vk_layer_config.cpp
@@ -32,6 +32,17 @@
 
 #define MAX_CHARS_PER_LINE 4096
 
+// Flag for ONE-TIME debug output initialization
+static bool log_message_initialized = false;
+
+// Accessor functions to ensure the correct instance of the shared flag gets used
+bool LogMessageInitialized() {
+    return log_message_initialized;
+}
+void SetLogMessageInitialized() {
+    log_message_initialized = true;
+}
+
 class ConfigFile {
   public:
     ConfigFile();
diff --git a/layers/vk_layer_config.h b/layers/vk_layer_config.h
index c4526db..097ba42 100644
--- a/layers/vk_layer_config.h
+++ b/layers/vk_layer_config.h
@@ -63,6 +63,8 @@
 
 void setLayerOption(const char *_option, const char *_val);
 void print_msg_flags(VkFlags msgFlags, char *msg_flags);
+bool LogMessageInitialized();
+void SetLogMessageInitialized();
 
 #ifdef __cplusplus
 }
diff --git a/layers/vk_layer_logging.h b/layers/vk_layer_logging.h
index 0328031..2836313 100644
--- a/layers/vk_layer_logging.h
+++ b/layers/vk_layer_logging.h
@@ -104,17 +104,55 @@
     *list_head = NULL;
 }
 
+static inline bool OutputLogMsgHeader(const debug_report_data *debug_data, VkFlags msgFlags) {
+    bool output = false;
+    VkLayerDbgFunctionNode *pTrav =
+        (debug_data->debug_callback_list != NULL) ? debug_data->debug_callback_list : debug_data->default_debug_callback_list;
+
+    while (pTrav) {
+        const char *message_header = "Legend:\n\n"
+                               "*******************************************************************************************\n"
+                               "* Vulkan Validation Layer Debug Output                                                    *\n"
+                               "*                                                                                         *\n"
+                               "* Debug Output Type Definitions:                                                          *\n"
+                               "* ------------------------------                                                          *\n"
+                               "* ERROR: Errors are output when a validation layer detects that some application behavior *\n"
+                               "*        has violated the Vulkan Specification.  When an error is encountered it is       *\n"
+                               "*        recommended that the user callback function return 'true' for optimal            *\n"
+                               "*        validation results. Any validation error may result in undefined behavior and    *\n"
+                               "*        errors should be corrected as they are encountered for best results.             *\n"
+                               "* WARN:  Warnings are output in cases where mistakes are commonly made and do NOT         *\n"
+                               "*        necessarily indicate that an app has violated the Vulkan Specification.          *\n"
+                               "*        Warnings basically translate to 'Did you really mean to do this?'                *\n"
+                               "* PERF:  Performance Warnings are output in cases where a possible inefficiency has been  *\n"
+                               "*        detected.  These also do NOT imply that the specification was violated.          *\n"
+                               "* INFO:  These log messages are for informational purposes only. For instance, the        *\n"
+                               "*        core_validation layer can print out lists of memory objects and their bindings   *\n"
+                               "*        which may help with debugging or improving application efficiency.               *\n"
+                               "*******************************************************************************************\n";
+
+        if (pTrav->msgFlags & msgFlags) {
+            pTrav->pfnMsgCallback(VK_DEBUG_REPORT_DEBUG_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT, 0, 0,
+                VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT, "", message_header, pTrav->pUserData);
+            output |= true;
+        }
+        pTrav = pTrav->pNext;
+    }
+    return output;
+}
+
 // 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) {
     bool bail = false;
-    VkLayerDbgFunctionNode *pTrav = NULL;
+    VkLayerDbgFunctionNode *pTrav =
+        (debug_data->debug_callback_list != NULL) ? debug_data->debug_callback_list : debug_data->default_debug_callback_list;
 
-    if (debug_data->debug_callback_list != NULL) {
-        pTrav = debug_data->debug_callback_list;
-    } else {
-        pTrav = debug_data->default_debug_callback_list;
+    if ((LogMessageInitialized() == false) && (strcmp(pLayerPrefix, "DebugReport") != 0)) {
+        if (OutputLogMsgHeader(debug_data, msgFlags) == true) {
+            SetLogMessageInitialized();
+        }
     }
 
     while (pTrav) {
@@ -151,6 +189,7 @@
             debug_data->g_DEBUG_REPORT = true;
         }
     }
+
     return debug_data;
 }