layers: Add DrawState check for Invalid PSO CreateInfo state

Report any violations in PSO restrictions as DRAWSTATE_INVALID_PIPELINE_CREATE_STATE error and don't call into driver.
Also fix a couple of broken error calls that had NULL dispatchable object parameter.
diff --git a/layers/draw_state.cpp b/layers/draw_state.cpp
index 27c40b9..c4bbd6b 100644
--- a/layers/draw_state.cpp
+++ b/layers/draw_state.cpp
@@ -437,11 +437,58 @@
     loader_platform_thread_unlock_mutex(&globalLock);
     return &sampleMap[sampler]->createInfo;
 }
-
+// Verify that create state for a pipeline is valid
+static bool32_t verifyPipelineCreateState(const VkDevice device, const PIPELINE_NODE* pPipeline)
+{
+    // VS is required
+    if (!(pPipeline->active_shaders & VK_SHADER_STAGE_VERTEX_BIT)) {
+        log_msg(mdd(device), VK_DBG_REPORT_ERROR_BIT, (VkObjectType) 0, VK_NULL_HANDLE, 0, DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
+                "Invalid Pipeline CreateInfo State: Vtx Shader required");
+        return VK_FALSE;
+    }
+    // Either both or neither TC/TE shaders should be defined
+    if (((pPipeline->active_shaders & VK_SHADER_STAGE_TESS_CONTROL_BIT) == 0) !=
+         ((pPipeline->active_shaders & VK_SHADER_STAGE_TESS_EVALUATION_BIT) == 0) ) {
+        log_msg(mdd(device), VK_DBG_REPORT_ERROR_BIT, (VkObjectType) 0, VK_NULL_HANDLE, 0, DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
+                "Invalid Pipeline CreateInfo State: TE and TC shaders must be included or excluded as a pair");
+        return VK_FALSE;
+    }
+    // Compute shaders should be specified independent of Gfx shaders
+    if ((pPipeline->active_shaders & VK_SHADER_STAGE_COMPUTE_BIT) &&
+        (pPipeline->active_shaders & (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_TESS_CONTROL_BIT |
+                                     VK_SHADER_STAGE_TESS_EVALUATION_BIT | VK_SHADER_STAGE_GEOMETRY_BIT |
+                                     VK_SHADER_STAGE_FRAGMENT_BIT))) {
+        log_msg(mdd(device), VK_DBG_REPORT_ERROR_BIT, (VkObjectType) 0, VK_NULL_HANDLE, 0, DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
+                "Invalid Pipeline CreateInfo State: Do not specify Compute Shader for Gfx Pipeline");
+        return VK_FALSE;
+    }
+    // VK_PRIMITIVE_TOPOLOGY_PATCH primitive topology is only valid for tessellation pipelines.
+    // Mismatching primitive topology and tessellation fails graphics pipeline creation.
+    if (pPipeline->active_shaders & (VK_SHADER_STAGE_TESS_CONTROL_BIT | VK_SHADER_STAGE_TESS_EVALUATION_BIT) &&
+        (pPipeline->iaStateCI.topology != VK_PRIMITIVE_TOPOLOGY_PATCH)) {
+        log_msg(mdd(device), VK_DBG_REPORT_ERROR_BIT, (VkObjectType) 0, VK_NULL_HANDLE, 0, DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
+                "Invalid Pipeline CreateInfo State: VK_PRIMITIVE_TOPOLOGY_PATCH must be set as IA topology for tessellation pipelines");
+        return VK_FALSE;
+    }
+    if ((pPipeline->iaStateCI.topology == VK_PRIMITIVE_TOPOLOGY_PATCH) &&
+        (~pPipeline->active_shaders & VK_SHADER_STAGE_TESS_CONTROL_BIT)) {
+        log_msg(mdd(device), VK_DBG_REPORT_ERROR_BIT, (VkObjectType) 0, VK_NULL_HANDLE, 0, DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
+                "Invalid Pipeline CreateInfo State: VK_PRIMITIVE_TOPOLOGY_PATCH primitive topology is only valid for tessellation pipelines");
+        return VK_FALSE;
+    }
+    return VK_TRUE;
+}
 // Init the pipeline mapping info based on pipeline create info LL tree
 //  Threading note : Calls to this function should wrapped in mutex
-static void initPipeline(PIPELINE_NODE* pPipeline, const VkGraphicsPipelineCreateInfo* pCreateInfo)
+static PIPELINE_NODE* initPipeline(const VkGraphicsPipelineCreateInfo* pCreateInfo, PIPELINE_NODE* pBasePipeline)
 {
+    PIPELINE_NODE* pPipeline = new PIPELINE_NODE;
+    if (pBasePipeline) {
+        memcpy((void*)pPipeline, (void*)pBasePipeline, sizeof(PIPELINE_NODE));
+    }
+    else {
+        memset((void*)pPipeline, 0, sizeof(PIPELINE_NODE));
+    }
     // First init create info, we'll shadow the structs as we go down the tree
     // TODO : Validate that no create info is incorrectly replicated
     memcpy(&pPipeline->graphicsPipelineCI, pCreateInfo, sizeof(VkGraphicsPipelineCreateInfo));
@@ -563,7 +610,7 @@
         }
         pTrav = (GENERIC_HEADER*)pTrav->pNext;
     }
-    pipelineMap[pPipeline->pipeline] = pPipeline;
+    return pPipeline;
 }
 // Free the Pipeline nodes
 static void deletePipelines()
@@ -652,7 +699,7 @@
     return layoutMap[layout];
 }
 // Return 1 if update struct is of valid type, 0 otherwise
-static bool32_t validUpdateStruct(const GENERIC_HEADER* pUpdateStruct)
+static bool32_t validUpdateStruct(const VkDevice device, const GENERIC_HEADER* pUpdateStruct)
 {
     char str[1024];
     switch (pUpdateStruct->sType)
@@ -661,13 +708,13 @@
         case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET:
             return 1;
         default:
-            log_msg(NULL, VK_DBG_REPORT_ERROR_BIT, (VkObjectType) 0, VK_NULL_HANDLE, 0, DRAWSTATE_INVALID_UPDATE_STRUCT, "DS",
+            log_msg(mdd(device), VK_DBG_REPORT_ERROR_BIT, (VkObjectType) 0, VK_NULL_HANDLE, 0, DRAWSTATE_INVALID_UPDATE_STRUCT, "DS",
                     "Unexpected UPDATE struct of type %s (value %u) in vkUpdateDescriptors() struct tree", string_VkStructureType(pUpdateStruct->sType), pUpdateStruct->sType);
             return 0;
     }
 }
 // For given update struct, return binding
-static uint32_t getUpdateBinding(const GENERIC_HEADER* pUpdateStruct)
+static uint32_t getUpdateBinding(const VkDevice device, const GENERIC_HEADER* pUpdateStruct)
 {
     char str[1024];
     switch (pUpdateStruct->sType)
@@ -677,13 +724,13 @@
         case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET:
             return ((VkCopyDescriptorSet*)pUpdateStruct)->destBinding;
         default:
-            log_msg(NULL, VK_DBG_REPORT_ERROR_BIT, (VkObjectType) 0, VK_NULL_HANDLE, 0, DRAWSTATE_INVALID_UPDATE_STRUCT, "DS",
+            log_msg(mdd(device), VK_DBG_REPORT_ERROR_BIT, (VkObjectType) 0, VK_NULL_HANDLE, 0, DRAWSTATE_INVALID_UPDATE_STRUCT, "DS",
                     "Unexpected UPDATE struct of type %s (value %u) in vkUpdateDescriptors() struct tree", string_VkStructureType(pUpdateStruct->sType), pUpdateStruct->sType);
             return 0xFFFFFFFF;
     }
 }
 // Return count for given update struct
-static uint32_t getUpdateArrayIndex(const GENERIC_HEADER* pUpdateStruct)
+static uint32_t getUpdateArrayIndex(const VkDevice device, const GENERIC_HEADER* pUpdateStruct)
 {
     char str[1024];
     switch (pUpdateStruct->sType)
@@ -694,13 +741,13 @@
             // TODO : Need to understand this case better and make sure code is correct
             return ((VkCopyDescriptorSet*)pUpdateStruct)->destArrayElement;
         default:
-            log_msg(NULL, VK_DBG_REPORT_ERROR_BIT, (VkObjectType) 0, VK_NULL_HANDLE, 0, DRAWSTATE_INVALID_UPDATE_STRUCT, "DS",
+            log_msg(mdd(device), VK_DBG_REPORT_ERROR_BIT, (VkObjectType) 0, VK_NULL_HANDLE, 0, DRAWSTATE_INVALID_UPDATE_STRUCT, "DS",
                     "Unexpected UPDATE struct of type %s (value %u) in vkUpdateDescriptors() struct tree", string_VkStructureType(pUpdateStruct->sType), pUpdateStruct->sType);
             return 0;
     }
 }
 // Return count for given update struct
-static uint32_t getUpdateCount(const GENERIC_HEADER* pUpdateStruct)
+static uint32_t getUpdateCount(const VkDevice device, const GENERIC_HEADER* pUpdateStruct)
 {
     char str[1024];
     switch (pUpdateStruct->sType)
@@ -711,7 +758,7 @@
             // TODO : Need to understand this case better and make sure code is correct
             return ((VkCopyDescriptorSet*)pUpdateStruct)->count;
         default:
-            log_msg(NULL, VK_DBG_REPORT_ERROR_BIT, (VkObjectType) 0, VK_NULL_HANDLE, 0, DRAWSTATE_INVALID_UPDATE_STRUCT, "DS",
+            log_msg(mdd(device), VK_DBG_REPORT_ERROR_BIT, (VkObjectType) 0, VK_NULL_HANDLE, 0, DRAWSTATE_INVALID_UPDATE_STRUCT, "DS",
                     "Unexpected UPDATE struct of type %s (value %u) in vkUpdateDescriptors() struct tree", string_VkStructureType(pUpdateStruct->sType), pUpdateStruct->sType);
             return 0;
     }
@@ -735,17 +782,17 @@
     return offsetIndex-1;
 }
 // For given layout and update, return the first overall index of the layout that is update
-static uint32_t getUpdateStartIndex(const LAYOUT_NODE* pLayout, const GENERIC_HEADER* pUpdateStruct)
+static uint32_t getUpdateStartIndex(const VkDevice device, const LAYOUT_NODE* pLayout, const GENERIC_HEADER* pUpdateStruct)
 {
-    return (getBindingStartIndex(pLayout, getUpdateBinding(pUpdateStruct))+getUpdateArrayIndex(pUpdateStruct));
+    return (getBindingStartIndex(pLayout, getUpdateBinding(device, pUpdateStruct))+getUpdateArrayIndex(device, pUpdateStruct));
 }
 // For given layout and update, return the last overall index of the layout that is update
-static uint32_t getUpdateEndIndex(const LAYOUT_NODE* pLayout, const GENERIC_HEADER* pUpdateStruct)
+static uint32_t getUpdateEndIndex(const VkDevice device, const LAYOUT_NODE* pLayout, const GENERIC_HEADER* pUpdateStruct)
 {
-    return (getBindingStartIndex(pLayout, getUpdateBinding(pUpdateStruct))+getUpdateArrayIndex(pUpdateStruct)+getUpdateCount(pUpdateStruct)-1);
+    return (getBindingStartIndex(pLayout, getUpdateBinding(device, pUpdateStruct))+getUpdateArrayIndex(device, pUpdateStruct)+getUpdateCount(device, pUpdateStruct)-1);
 }
 // Verify that the descriptor type in the update struct matches what's expected by the layout
-static bool32_t validateUpdateType(const LAYOUT_NODE* pLayout, const GENERIC_HEADER* pUpdateStruct)
+static bool32_t validateUpdateType(const VkDevice device, const LAYOUT_NODE* pLayout, const GENERIC_HEADER* pUpdateStruct)
 {
     // First get actual type of update
     VkDescriptorType actualType;
@@ -761,11 +808,11 @@
             return 1;
             break;
         default:
-            log_msg(NULL, VK_DBG_REPORT_ERROR_BIT, (VkObjectType) 0, VK_NULL_HANDLE, 0, DRAWSTATE_INVALID_UPDATE_STRUCT, "DS",
+            log_msg(mdd(device), VK_DBG_REPORT_ERROR_BIT, (VkObjectType) 0, VK_NULL_HANDLE, 0, DRAWSTATE_INVALID_UPDATE_STRUCT, "DS",
                     "Unexpected UPDATE struct of type %s (value %u) in vkUpdateDescriptors() struct tree", string_VkStructureType(pUpdateStruct->sType), pUpdateStruct->sType);
             return 0;
     }
-    for (i = getUpdateStartIndex(pLayout, pUpdateStruct); i <= getUpdateEndIndex(pLayout, pUpdateStruct); i++) {
+    for (i = getUpdateStartIndex(device, pLayout, pUpdateStruct); i <= getUpdateEndIndex(device, pLayout, pUpdateStruct); i++) {
         if (pLayout->pTypes[i] != actualType)
             return 0;
     }
@@ -774,7 +821,7 @@
 // Determine the update type, allocate a new struct of that type, shadow the given pUpdate
 //   struct into the new struct and return ptr to shadow struct cast as GENERIC_HEADER
 // NOTE : Calls to this function should be wrapped in mutex
-static GENERIC_HEADER* shadowUpdateNode(GENERIC_HEADER* pUpdate)
+static GENERIC_HEADER* shadowUpdateNode(const VkDevice device, GENERIC_HEADER* pUpdate)
 {
     GENERIC_HEADER* pNewNode = NULL;
     VkWriteDescriptorSet* pWDS = NULL;
@@ -800,7 +847,7 @@
             memcpy(pCDS, pUpdate, sizeof(VkCopyDescriptorSet));
             break;
         default:
-            log_msg(NULL, VK_DBG_REPORT_ERROR_BIT, (VkObjectType) 0, NULL, 0, DRAWSTATE_INVALID_UPDATE_STRUCT, "DS",
+            log_msg(mdd(device), VK_DBG_REPORT_ERROR_BIT, (VkObjectType) 0, NULL, 0, DRAWSTATE_INVALID_UPDATE_STRUCT, "DS",
                     "Unexpected UPDATE struct of type %s (value %u) in vkUpdateDescriptors() struct tree", string_VkStructureType(pUpdate->sType), pUpdate->sType);
             return NULL;
     }
@@ -832,29 +879,29 @@
         GENERIC_HEADER* pUpdate = (pWDS) ? (GENERIC_HEADER*) &pWDS[i] : (GENERIC_HEADER*) &pCDS[i];
         pLayout = pSet->pLayout;
         // First verify valid update struct
-        if (!validUpdateStruct(pUpdate)) {
+        if (!validUpdateStruct(device, pUpdate)) {
             result = 0;
             break;
         }
         // Make sure that binding is within bounds
-        if (pLayout->createInfo.count < getUpdateBinding(pUpdate)) {
+        if (pLayout->createInfo.count < getUpdateBinding(device, pUpdate)) {
             log_msg(mdd(device), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DESCRIPTOR_SET, ds, 0, DRAWSTATE_INVALID_UPDATE_INDEX, "DS",
-                    "Descriptor Set %p does not have binding to match update binding %u for update type %s!", ds, getUpdateBinding(pUpdate), string_VkStructureType(pUpdate->sType));
+                    "Descriptor Set %p does not have binding to match update binding %u for update type %s!", ds, getUpdateBinding(device, pUpdate), string_VkStructureType(pUpdate->sType));
             result = 0;
         }
         else {
             // Next verify that update falls within size of given binding
-            if (getBindingEndIndex(pLayout, getUpdateBinding(pUpdate)) < getUpdateEndIndex(pLayout, pUpdate)) {
+            if (getBindingEndIndex(pLayout, getUpdateBinding(device, pUpdate)) < getUpdateEndIndex(device, pLayout, pUpdate)) {
                 char str[48*1024]; // TODO : Keep count of layout CI structs and size this string dynamically based on that count
                 pLayoutCI = &pLayout->createInfo;
                 string DSstr = vk_print_vkdescriptorsetlayoutcreateinfo(pLayoutCI, "{DS}    ");
                 log_msg(mdd(device), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DESCRIPTOR_SET, ds, 0, DRAWSTATE_DESCRIPTOR_UPDATE_OUT_OF_BOUNDS, "DS",
-                        "Descriptor update type of %s is out of bounds for matching binding %u in Layout w/ CI:\n%s!", string_VkStructureType(pUpdate->sType), getUpdateBinding(pUpdate), DSstr.c_str());
+                        "Descriptor update type of %s is out of bounds for matching binding %u in Layout w/ CI:\n%s!", string_VkStructureType(pUpdate->sType), getUpdateBinding(device, pUpdate), DSstr.c_str());
                 result = 0;
             }
             else { // TODO : should we skip update on a type mismatch or force it?
                 // Layout bindings match w/ update ok, now verify that update is of the right type
-                if (!validateUpdateType(pLayout, pUpdate)) {
+                if (!validateUpdateType(device, pLayout, pUpdate)) {
                     log_msg(mdd(device), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DESCRIPTOR_SET, ds, 0, DRAWSTATE_DESCRIPTOR_TYPE_MISMATCH, "DS",
                             "Descriptor update type of %s does not match overlapping binding type!", string_VkStructureType(pUpdate->sType));
                     result = 0;
@@ -863,7 +910,7 @@
                     // Save the update info
                     // TODO : Info message that update successful
                     // Create new update struct for this set's shadow copy
-                    GENERIC_HEADER* pNewNode = shadowUpdateNode(pUpdate);
+                    GENERIC_HEADER* pNewNode = shadowUpdateNode(device, pUpdate);
                     if (NULL == pNewNode) {
                         log_msg(mdd(device), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DESCRIPTOR_SET, ds, 0, DRAWSTATE_OUT_OF_MEMORY, "DS",
                                 "Out of memory while attempting to allocate UPDATE struct in vkUpdateDescriptors()");
@@ -874,7 +921,7 @@
                         pNewNode->pNext = pSet->pUpdateStructs;
                         pSet->pUpdateStructs = pNewNode;
                         // Now update appropriate descriptor(s) to point to new Update node
-                        for (uint32_t j = getUpdateStartIndex(pLayout, pUpdate); j <= getUpdateEndIndex(pLayout, pUpdate); j++) {
+                        for (uint32_t j = getUpdateStartIndex(device, pLayout, pUpdate); j <= getUpdateEndIndex(device, pLayout, pUpdate); j++) {
                             assert(j<pSet->descriptorCount);
                             pSet->ppDescriptors[j] = pNewNode;
                         }
@@ -1778,23 +1825,35 @@
     return result;
 }
 
-static void track_pipeline(const VkGraphicsPipelineCreateInfo* pCreateInfo, VkPipeline* pPipeline)
-{
-    loader_platform_thread_lock_mutex(&globalLock);
-    PIPELINE_NODE* pPipeNode = new PIPELINE_NODE;
-    memset((void*)pPipeNode, 0, sizeof(PIPELINE_NODE));
-    pPipeNode->pipeline = *pPipeline;
-    initPipeline(pPipeNode, pCreateInfo);
-    loader_platform_thread_unlock_mutex(&globalLock);
-}
-
 VK_LAYER_EXPORT VkResult VKAPI vkCreateGraphicsPipeline(VkDevice device, const VkGraphicsPipelineCreateInfo* pCreateInfo, VkPipeline* pPipeline)
 {
-    VkResult result = get_dispatch_table(draw_state_device_table_map, device)->CreateGraphicsPipeline(device, pCreateInfo, pPipeline);
-    log_msg(mdd(device), VK_DBG_REPORT_INFO_BIT, VK_OBJECT_TYPE_PIPELINE, *pPipeline, 0, DRAWSTATE_NONE, "DS",
-            "Created Gfx Pipeline %p", (void*)*pPipeline);
-    track_pipeline(pCreateInfo, pPipeline);
-
+    VkResult result = VK_ERROR_BAD_PIPELINE_DATA;
+    // The order of operations here is a little convoluted but gets the job done
+    //  1. Pipeline create state is first shadowed into PIPELINE_NODE struct
+    //  2. Create state is then validated (which uses flags setup during shadowing)
+    //  3. If everything looks good, we'll then create the pipeline and add NODE to pipelineMap
+    loader_platform_thread_lock_mutex(&globalLock);
+    PIPELINE_NODE* pPipeNode = initPipeline(pCreateInfo, NULL);
+    bool32_t valid = verifyPipelineCreateState(device, pPipeNode);
+    loader_platform_thread_unlock_mutex(&globalLock);
+    if (VK_TRUE == valid) {
+        result = get_dispatch_table(draw_state_device_table_map, device)->CreateGraphicsPipeline(device, pCreateInfo, pPipeline);
+        log_msg(mdd(device), VK_DBG_REPORT_INFO_BIT, VK_OBJECT_TYPE_PIPELINE, *pPipeline, 0, DRAWSTATE_NONE, "DS",
+                "Created Gfx Pipeline %p", (void*)*pPipeline);
+        loader_platform_thread_lock_mutex(&globalLock);
+        pPipeNode->pipeline = *pPipeline;
+        pipelineMap[pPipeNode->pipeline] = pPipeNode;
+        loader_platform_thread_unlock_mutex(&globalLock);
+    }
+    else {
+        if (pPipeNode) {
+            // If we allocated a pipeNode, need to clean it up here
+            delete[] pPipeNode->pVertexBindingDescriptions;
+            delete[] pPipeNode->pVertexAttributeDescriptions;
+            delete[] pPipeNode->pAttachments;
+            delete pPipeNode;
+        }
+    }
     return result;
 }
 
@@ -1804,14 +1863,29 @@
         VkPipeline basePipeline,
         VkPipeline* pPipeline)
 {
-    VkResult result = get_dispatch_table(draw_state_device_table_map, device)->CreateGraphicsPipelineDerivative(device, pCreateInfo, basePipeline, pPipeline);
-    // Create LL HEAD for this Pipeline
-    log_msg(mdd(device), VK_DBG_REPORT_INFO_BIT, VK_OBJECT_TYPE_PIPELINE, *pPipeline, 0, DRAWSTATE_NONE, "DS",
-            "Created Gfx Pipeline %p (derived from pipeline %p)", (void*)*pPipeline, basePipeline);
-    track_pipeline(pCreateInfo, pPipeline);
-
+    VkResult result = VK_ERROR_BAD_PIPELINE_DATA;
+    loader_platform_thread_lock_mutex(&globalLock);
+    PIPELINE_NODE* pPipeNode = initPipeline(pCreateInfo, NULL);
+    bool32_t valid = verifyPipelineCreateState(device, pipelineMap[basePipeline]);
     loader_platform_thread_unlock_mutex(&globalLock);
-
+    if (VK_TRUE == valid) {
+        result = get_dispatch_table(draw_state_device_table_map, device)->CreateGraphicsPipelineDerivative(device, pCreateInfo, basePipeline, pPipeline);
+        log_msg(mdd(device), VK_DBG_REPORT_INFO_BIT, VK_OBJECT_TYPE_PIPELINE, *pPipeline, 0, DRAWSTATE_NONE, "DS",
+                "Created Gfx Pipeline %p (derived from pipeline %p)", (void*)*pPipeline, basePipeline);
+        loader_platform_thread_lock_mutex(&globalLock);
+        pPipeNode->pipeline = *pPipeline;
+        pipelineMap[pPipeNode->pipeline] = pPipeNode;
+        loader_platform_thread_unlock_mutex(&globalLock);
+    }
+    else { // Skipped pipeline creation due to bad CreateInfo data
+        if (pPipeNode) {
+            // If we allocated a pipeNode, need to clean it up here
+            delete[] pPipeNode->pVertexBindingDescriptions;
+            delete[] pPipeNode->pVertexAttributeDescriptions;
+            delete[] pPipeNode->pAttachments;
+            delete pPipeNode;
+        }
+    }
     return result;
 }
 
@@ -2667,11 +2741,11 @@
     cbDumpDotFile(outFileName);
 }
 
-void drawStateDumpPngFile(char* outFileName)
+void drawStateDumpPngFile(const VkDevice device, char* outFileName)
 {
 #if defined(_WIN32)
 // FIXME: NEED WINDOWS EQUIVALENT
-        log_msg(NULL, VK_DBG_REPORT_ERROR_BIT, (VkObjectType) 0, NULL, 0, DRAWSTATE_MISSING_DOT_PROGRAM, "DS",
+        log_msg(mdd(device), VK_DBG_REPORT_ERROR_BIT, (VkObjectType) 0, NULL, 0, DRAWSTATE_MISSING_DOT_PROGRAM, "DS",
                 "Cannot execute dot program yet on Windows.");
 #else // WIN32
     char dotExe[32] = "/usr/bin/dot";
@@ -2684,7 +2758,7 @@
         remove("/tmp/tmp.dot");
     }
     else {
-        log_msg(NULL, VK_DBG_REPORT_ERROR_BIT, (VkObjectType) 0, NULL, 0, DRAWSTATE_MISSING_DOT_PROGRAM, "DS",
+        log_msg(mdd(device), VK_DBG_REPORT_ERROR_BIT, (VkObjectType) 0, NULL, 0, DRAWSTATE_MISSING_DOT_PROGRAM, "DS",
                 "Cannot execute dot program at (%s) to dump requested %s file.", dotExe, outFileName);
     }
 #endif // WIN32