layers: MR87, Adding validation for image validity
authorMichael Lentine <mlentine@google.com>
Tue, 24 Nov 2015 23:55:33 +0000 (17:55 -0600)
committerMark Lobodzinski <mark@lunarg.com>
Fri, 18 Dec 2015 21:18:51 +0000 (14:18 -0700)
Conflicts:
layers/mem_tracker.cpp

layers/mem_tracker.cpp
layers/mem_tracker.h

index dc0ffd3..58bbc00 100644 (file)
@@ -67,6 +67,9 @@ struct layer_data {
     unordered_map<VkQueue,             MT_QUEUE_INFO>            queueMap;
     unordered_map<VkSwapchainKHR,      MT_SWAP_CHAIN_INFO*>      swapchainMap;
     unordered_map<VkSemaphore,         MtSemaphoreState>         semaphoreMap;
+    unordered_map<VkFramebuffer,       MT_FB_INFO>               fbMap;
+    unordered_map<VkRenderPass,        MT_PASS_INFO>             passMap;
+    unordered_map<VkImageView,         MT_IMAGE_VIEW_INFO>       imageViewMap;
     // Images and Buffers are 2 objects that can have memory bound to them so they get special treatment
     unordered_map<uint64_t,            MT_OBJ_BINDING_INFO>      imageMap;
     unordered_map<uint64_t,            MT_OBJ_BINDING_INFO>      bufferMap;
@@ -253,6 +256,7 @@ add_object_create_info(
             auto pCI = &my_data->imageMap[handle];
             memset(pCI, 0, sizeof(MT_OBJ_BINDING_INFO));
             pCI->mem = MEMTRACKER_SWAP_CHAIN_IMAGE_KEY;
+            pCI->valid = false;
             pCI->create_info.image.usage =
                 const_cast<VkSwapchainCreateInfoKHR*>(static_cast<const VkSwapchainCreateInfoKHR *>(pCreateInfo))->imageUsage;
             break;
@@ -457,6 +461,39 @@ add_mem_obj_info(
     my_data->memObjMap[mem].memRange.size   = 0;
     my_data->memObjMap[mem].pData           = 0;
     my_data->memObjMap[mem].pDriverData     = 0;
+    my_data->memObjMap[mem].valid           = false;
+}
+
+static bool validate_memory_is_valid(layer_data *my_data, VkDeviceMemory mem, VkImage image = VK_NULL_HANDLE) {
+    if (mem == MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
+        MT_OBJ_BINDING_INFO* pBindInfo = get_object_binding_info(my_data, reinterpret_cast<uint64_t>(image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT);
+        if (pBindInfo && !pBindInfo->valid) {
+            return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, reinterpret_cast<uint64_t>(mem), 0, MEMTRACK_INVALID_USAGE_FLAG, "MEM",
+                           "Cannot read invalid swapchain image %" PRIx64 ", please fill the memory before using.", reinterpret_cast<uint64_t>(image));
+        }
+    }
+    else {
+        MT_MEM_OBJ_INFO *pMemObj = get_mem_obj_info(my_data, mem);
+        if (pMemObj && !pMemObj->valid) {
+            return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, reinterpret_cast<uint64_t>(mem), 0, MEMTRACK_INVALID_USAGE_FLAG, "MEM",
+                           "Cannot read invalid memory %" PRIx64 ", please fill the memory before using.", reinterpret_cast<uint64_t>(mem));
+        }
+    }
+    return false;
+}
+
+static void set_memory_valid(layer_data *my_data, VkDeviceMemory mem, bool valid, VkImage image = VK_NULL_HANDLE) {
+    if (mem == MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
+        MT_OBJ_BINDING_INFO* pBindInfo = get_object_binding_info(my_data, reinterpret_cast<uint64_t>(image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT);
+        if (pBindInfo) {
+            pBindInfo->valid = valid;
+        }
+    } else {
+        MT_MEM_OBJ_INFO *pMemObj = get_mem_obj_info(my_data, mem);
+        if (pMemObj) {
+            pMemObj->valid = valid;
+        }
+    }
 }
 
 // Find CB Info and add mem reference to list container
@@ -1483,12 +1520,15 @@ VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkMapMemory(
     VkBool32 skipCall   = VK_FALSE;
     VkResult result     = VK_ERROR_VALIDATION_FAILED_EXT;
     loader_platform_thread_lock_mutex(&globalLock);
-
     MT_MEM_OBJ_INFO *pMemObj = get_mem_obj_info(my_data, mem);
-    if (pMemObj && ((memProps.memoryTypes[pMemObj->allocInfo.memoryTypeIndex].propertyFlags &
-         VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0)) {
-        skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t) mem, 0, MEMTRACK_INVALID_STATE, "MEM",
-                       "Mapping Memory without VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT set: mem obj %#" PRIxLEAST64, (uint64_t) mem);
+    if (pMemObj) {
+        pMemObj->valid = true;
+        if ((memProps.memoryTypes[pMemObj->allocInfo.memoryTypeIndex].propertyFlags &
+             VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) {
+            skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
+                (uint64_t) mem, 0, MEMTRACK_INVALID_STATE, "MEM",
+                "Mapping Memory without VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT set: mem obj %#" PRIxLEAST64, (uint64_t) mem);
+        }
     }
     skipCall |= validateMemRange(my_data, mem, offset, size);
     storeMemRanges(my_data, mem, offset, size);
@@ -1958,6 +1998,7 @@ VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateImageView(
     VkResult result = my_data->device_dispatch_table->CreateImageView(device, pCreateInfo, pAllocator, pView);
     if (result == VK_SUCCESS) {
         loader_platform_thread_lock_mutex(&globalLock);
+        my_data->imageViewMap[*pView].image = pCreateInfo->image;
         // Validate that img has correct usage flags set
         validate_image_usage_flags(my_data, device, pCreateInfo->image,
                     VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
@@ -2226,8 +2267,16 @@ VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdBindVertexBuffers(
     const VkDeviceSize *pOffsets)
 {
     layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
+    bool skip_call = false;
+    for (int i = 0; i < bindingCount; ++i) {
+        VkDeviceMemory mem;
+        skip_call |= get_mem_binding_from_object(my_data, commandBuffer, reinterpret_cast<uint64_t>(pBuffers[i]),
+            VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
+        skip_call |= validate_memory_is_valid(my_data, mem);
+    }
     // TODO : Somewhere need to verify that VBs have correct usage state flagged
-    my_data->device_dispatch_table->CmdBindVertexBuffers(commandBuffer, startBinding, bindingCount, pBuffers, pOffsets);
+    if (!skip_call)
+        my_data->device_dispatch_table->CmdBindVertexBuffers(commandBuffer, startBinding, bindingCount, pBuffers, pOffsets);
 }
 
 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdBindIndexBuffer(
@@ -2237,8 +2286,12 @@ VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdBindIndexBuffer(
     VkIndexType     indexType)
 {
     layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
+    VkDeviceMemory mem;
+    bool skip_call = get_mem_binding_from_object(my_data, commandBuffer, reinterpret_cast<uint64_t>(buffer), VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
+    skip_call |= validate_memory_is_valid(my_data, mem);
     // TODO : Somewhere need to verify that IBs have correct usage state flagged
-    my_data->device_dispatch_table->CmdBindIndexBuffer(commandBuffer, buffer, offset, indexType);
+    if (!skip_call)
+        my_data->device_dispatch_table->CmdBindIndexBuffer(commandBuffer, buffer, offset, indexType);
 }
 
 VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirect(
@@ -2305,8 +2358,10 @@ VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdCopyBuffer(
     VkBool32       skipCall = VK_FALSE;
     loader_platform_thread_lock_mutex(&globalLock);
     skipCall  = get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)srcBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
+    skipCall |= validate_memory_is_valid(my_data, mem);
     skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdCopyBuffer");
     skipCall |= get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)dstBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
+    set_memory_valid(my_data, mem, true);
     skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdCopyBuffer");
     // Validate that SRC & DST buffers have correct usage flags set
     skipCall |= validate_buffer_usage_flags(my_data, commandBuffer, srcBuffer, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, true, "vkCmdCopyBuffer()", "VK_BUFFER_USAGE_TRANSFER_SRC_BIT");
@@ -2332,6 +2387,7 @@ VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdCopyQueryPoolResults(
     VkBool32       skipCall = VK_FALSE;
     loader_platform_thread_lock_mutex(&globalLock);
     skipCall |= get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)dstBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
+    set_memory_valid(my_data, mem, true);
     skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdCopyQueryPoolResults");
     // Validate that DST buffer has correct usage flags set
     skipCall |= validate_buffer_usage_flags(my_data, commandBuffer, dstBuffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, "vkCmdCopyQueryPoolResults()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
@@ -2356,8 +2412,10 @@ VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdCopyImage(
     loader_platform_thread_lock_mutex(&globalLock);
     // Validate that src & dst images have correct usage flags set
     skipCall  = get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)srcImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
+    skipCall |= validate_memory_is_valid(my_data, mem, srcImage);
     skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdCopyImage");
     skipCall |= get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)dstImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
+    set_memory_valid(my_data, mem, true, dstImage);
     skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdCopyImage");
     skipCall |= validate_image_usage_flags(my_data, commandBuffer, srcImage, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true, "vkCmdCopyImage()", "VK_IMAGE_USAGE_TRANSFER_SRC_BIT");
     skipCall |= validate_image_usage_flags(my_data, commandBuffer, dstImage, VK_IMAGE_USAGE_TRANSFER_DST_BIT, true, "vkCmdCopyImage()", "VK_IMAGE_USAGE_TRANSFER_DST_BIT");
@@ -2384,8 +2442,10 @@ VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdBlitImage(
     loader_platform_thread_lock_mutex(&globalLock);
     // Validate that src & dst images have correct usage flags set
     skipCall  = get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)srcImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
+    skipCall |= validate_memory_is_valid(my_data, mem, srcImage);
     skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdBlitImage");
     skipCall |= get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)dstImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
+    set_memory_valid(my_data, mem, true, dstImage);
     skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdBlitImage");
     skipCall |= validate_image_usage_flags(my_data, commandBuffer, srcImage, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true, "vkCmdBlitImage()", "VK_IMAGE_USAGE_TRANSFER_SRC_BIT");
     skipCall |= validate_image_usage_flags(my_data, commandBuffer, dstImage, VK_IMAGE_USAGE_TRANSFER_DST_BIT, true, "vkCmdBlitImage()", "VK_IMAGE_USAGE_TRANSFER_DST_BIT");
@@ -2409,8 +2469,10 @@ VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdCopyBufferToImage(
     VkBool32       skipCall = VK_FALSE;
     loader_platform_thread_lock_mutex(&globalLock);
     skipCall  = get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)dstImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
+    set_memory_valid(my_data, mem, true, dstImage);
     skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdCopyBufferToImage");
     skipCall |= get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)srcBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
+    skipCall |= validate_memory_is_valid(my_data, mem);
     skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdCopyBufferToImage");
     // Validate that src buff & dst image have correct usage flags set
     skipCall |= validate_buffer_usage_flags(my_data, commandBuffer, srcBuffer, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, true, "vkCmdCopyBufferToImage()", "VK_BUFFER_USAGE_TRANSFER_SRC_BIT");
@@ -2435,8 +2497,10 @@ VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdCopyImageToBuffer(
     VkBool32       skipCall = VK_FALSE;
     loader_platform_thread_lock_mutex(&globalLock);
     skipCall  = get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)srcImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
+    skipCall |= validate_memory_is_valid(my_data, mem, srcImage);
     skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdCopyImageToBuffer");
     skipCall |= get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)dstBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
+    set_memory_valid(my_data, mem, true);
     skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdCopyImageToBuffer");
     // Validate that dst buff & src image have correct usage flags set
     skipCall |= validate_image_usage_flags(my_data, commandBuffer, srcImage, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true, "vkCmdCopyImageToBuffer()", "VK_IMAGE_USAGE_TRANSFER_SRC_BIT");
@@ -2460,6 +2524,7 @@ VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdUpdateBuffer(
     VkBool32       skipCall = VK_FALSE;
     loader_platform_thread_lock_mutex(&globalLock);
     skipCall  = get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)dstBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
+    set_memory_valid(my_data, mem, true);
     skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdUpdateBuffer");
     // Validate that dst buff has correct usage flags set
     skipCall |= validate_buffer_usage_flags(my_data, commandBuffer, dstBuffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, "vkCmdUpdateBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
@@ -2481,6 +2546,7 @@ VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdFillBuffer(
     VkBool32       skipCall = VK_FALSE;
     loader_platform_thread_lock_mutex(&globalLock);
     skipCall  = get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)dstBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
+    set_memory_valid(my_data, mem, true);
     skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdFillBuffer");
     // Validate that dst buff has correct usage flags set
     skipCall |= validate_buffer_usage_flags(my_data, commandBuffer, dstBuffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, "vkCmdFillBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
@@ -2504,6 +2570,7 @@ VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdClearColorImage(
     VkBool32       skipCall = VK_FALSE;
     loader_platform_thread_lock_mutex(&globalLock);
     skipCall  = get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
+    set_memory_valid(my_data, mem, true, image);
     skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdClearColorImage");
     loader_platform_thread_unlock_mutex(&globalLock);
     if (VK_FALSE == skipCall) {
@@ -2525,6 +2592,7 @@ VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdClearDepthStencilImage(
     VkBool32       skipCall = VK_FALSE;
     loader_platform_thread_lock_mutex(&globalLock);
     skipCall  = get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
+    set_memory_valid(my_data, mem, true, image);
     skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdClearDepthStencilImage");
     loader_platform_thread_unlock_mutex(&globalLock);
     if (VK_FALSE == skipCall) {
@@ -2547,8 +2615,10 @@ VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdResolveImage(
     loader_platform_thread_lock_mutex(&globalLock);
     VkDeviceMemory mem;
     skipCall  = get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)srcImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
+    skipCall |= validate_memory_is_valid(my_data, mem, srcImage);
     skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdResolveImage");
     skipCall |= get_mem_binding_from_object(my_data, commandBuffer, (uint64_t)dstImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
+    set_memory_valid(my_data, mem, true, dstImage);
     skipCall |= update_cmd_buf_and_mem_references(my_data, commandBuffer, mem, "vkCmdResolveImage");
     loader_platform_thread_unlock_mutex(&globalLock);
     if (VK_FALSE == skipCall) {
@@ -2741,6 +2811,23 @@ VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImageKHR(
     return result;
 }
 
+VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkQueuePresentKHR(
+    VkQueue queue,
+    const VkPresentInfoKHR* pPresentInfo)
+{
+    layer_data *my_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map);
+    bool skip_call = false;
+    VkDeviceMemory mem;
+    for (int i = 0; i < pPresentInfo->swapchainCount; ++i) {
+        MT_SWAP_CHAIN_INFO *pInfo = my_data->swapchainMap[pPresentInfo->pSwapchains[i]];
+        VkImage image = pInfo->images[pPresentInfo->pImageIndices[i]];
+        skip_call |= get_mem_binding_from_object(my_data, queue, reinterpret_cast<uint64_t>(image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
+        skip_call |= validate_memory_is_valid(my_data, mem, image);
+    }
+    if (!skip_call)
+        return my_data->device_dispatch_table->QueuePresentKHR(queue, pPresentInfo);
+}
+
 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateSemaphore(
     VkDevice                     device,
     const VkSemaphoreCreateInfo *pCreateInfo,
@@ -2772,6 +2859,103 @@ VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroySemaphore(
     my_data->device_dispatch_table->DestroySemaphore(device, semaphore, pAllocator);
 }
 
+VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateFramebuffer(
+    VkDevice device,
+    const VkFramebufferCreateInfo* pCreateInfo,
+    const VkAllocationCallbacks* pAllocator,
+    VkFramebuffer* pFramebuffer)
+{
+    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
+    VkResult result = my_data->device_dispatch_table->CreateFramebuffer(device, pCreateInfo, pAllocator, pFramebuffer);
+    for (int i = 0; i < pCreateInfo->attachmentCount; ++i) {
+        VkImageView view = pCreateInfo->pAttachments[i];
+        loader_platform_thread_lock_mutex(&globalLock);
+        auto view_data = my_data->imageViewMap.find(view);
+        if (view_data == my_data->imageViewMap.end()) {
+            loader_platform_thread_unlock_mutex(&globalLock);
+            continue;
+        }
+        MT_FB_ATTACHMENT_INFO fb_info;
+        get_mem_binding_from_object(my_data, device, reinterpret_cast<uint64_t>(view_data->second.image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &fb_info.mem);
+        fb_info.image = view_data->second.image;
+        my_data->fbMap[*pFramebuffer].attachments.push_back(fb_info);
+        loader_platform_thread_unlock_mutex(&globalLock);
+    }
+    return result;
+}
+
+VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass(
+    VkDevice device,
+    const VkRenderPassCreateInfo* pCreateInfo,
+    const VkAllocationCallbacks* pAllocator,
+    VkRenderPass* pRenderPass)
+{
+    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
+    VkResult result = my_data->device_dispatch_table->CreateRenderPass(device, pCreateInfo, pAllocator, pRenderPass);
+    for (int i = 0; i < pCreateInfo->attachmentCount; ++i) {
+        VkAttachmentDescription desc = pCreateInfo->pAttachments[i];
+        MT_PASS_ATTACHMENT_INFO pass_info;
+        pass_info.load_op = desc.loadOp;
+        pass_info.store_op = desc.storeOp;
+        loader_platform_thread_lock_mutex(&globalLock);
+        my_data->passMap[*pRenderPass].attachments.push_back(pass_info);
+        loader_platform_thread_unlock_mutex(&globalLock);
+    }
+    return result;
+}
+
+VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdBeginRenderPass(
+    VkCommandBuffer cmdBuffer,
+    const VkRenderPassBeginInfo *pRenderPassBegin,
+    VkSubpassContents contents)
+{
+    layer_data *my_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map);
+    bool skip_call = false;
+    loader_platform_thread_lock_mutex(&globalLock);
+    auto pass_data = my_data->passMap.find(pRenderPassBegin->renderPass);
+    if (pass_data != my_data->passMap.end()) {
+        MT_PASS_INFO& pass_info = pass_data->second;
+        pass_info.fb = pRenderPassBegin->framebuffer;
+        for (int i = 0; i < pass_info.attachments.size(); ++i) {
+            MT_FB_ATTACHMENT_INFO& fb_info = my_data->fbMap[pass_info.fb].attachments[i];
+            if (pass_info.attachments[i].load_op == VK_ATTACHMENT_LOAD_OP_CLEAR) {
+                set_memory_valid(my_data, fb_info.mem, true, fb_info.image);
+            } else if (pass_info.attachments[i].load_op == VK_ATTACHMENT_LOAD_OP_LOAD) {
+                skip_call |= validate_memory_is_valid(my_data, fb_info.mem, fb_info.image);
+            }
+        }
+        auto cb_data = my_data->cbMap.find(cmdBuffer);
+        if (cb_data != my_data->cbMap.end()) {
+            cb_data->second.pass = pRenderPassBegin->renderPass;
+        }
+        loader_platform_thread_unlock_mutex(&globalLock);
+    }
+    if (!skip_call)
+        return my_data->device_dispatch_table->CmdBeginRenderPass(cmdBuffer, pRenderPassBegin, contents);
+}
+
+VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdEndRenderPass(
+    VkCommandBuffer cmdBuffer)
+{
+    layer_data *my_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map);
+    auto cb_data = my_data->cbMap.find(cmdBuffer);
+    if (cb_data != my_data->cbMap.end()) {
+        auto pass_data = my_data->passMap.find(cb_data->second.pass);
+        if (pass_data != my_data->passMap.end()) {
+            MT_PASS_INFO& pass_info = pass_data->second;
+            for (int i = 0; i < pass_info.attachments.size(); ++i) {
+                MT_FB_ATTACHMENT_INFO& fb_info = my_data->fbMap[pass_info.fb].attachments[i];
+                if (pass_info.attachments[i].store_op == VK_ATTACHMENT_STORE_OP_STORE) {
+                    set_memory_valid(my_data, fb_info.mem, true, fb_info.image);
+                } else if (pass_info.attachments[i].store_op == VK_ATTACHMENT_STORE_OP_DONT_CARE) {
+                    set_memory_valid(my_data, fb_info.mem, false, fb_info.image);
+                }
+            }
+        }
+    }
+    my_data->device_dispatch_table->CmdEndRenderPass(cmdBuffer);
+}
+
 VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(
     VkDevice    dev,
     const char *funcName)
@@ -2902,8 +3086,16 @@ VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(
         return (PFN_vkVoidFunction) vkCmdEndQuery;
     if (!strcmp(funcName, "vkCmdResetQueryPool"))
         return (PFN_vkVoidFunction) vkCmdResetQueryPool;
+    if (!strcmp(funcName, "vkCreateRenderPass"))
+        return (PFN_vkVoidFunction) vkCreateRenderPass;
+    if (!strcmp(funcName, "vkCmdBeginRenderPass"))
+        return (PFN_vkVoidFunction) vkCmdBeginRenderPass;
+    if (!strcmp(funcName, "vkCmdEndRenderPass"))
+        return (PFN_vkVoidFunction) vkCmdEndRenderPass;
     if (!strcmp(funcName, "vkGetDeviceQueue"))
         return (PFN_vkVoidFunction) vkGetDeviceQueue;
+    if (!strcmp(funcName, "vkCreateFramebuffer"))
+        return (PFN_vkVoidFunction) vkCreateFramebuffer;
 
     my_data = get_my_data_ptr(get_dispatch_key(dev), layer_data_map);
     if (my_data->wsi_enabled)
@@ -2916,6 +3108,8 @@ VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(
             return (PFN_vkVoidFunction) vkGetSwapchainImagesKHR;
         if (!strcmp(funcName, "vkAcquireNextImageKHR"))
             return (PFN_vkVoidFunction)vkAcquireNextImageKHR;
+        if (!strcmp(funcName, "vkQueuePresentKHR"))
+            return (PFN_vkVoidFunction)vkQueuePresentKHR;
     }
 
     VkLayerDispatchTable *pDisp = my_data->device_dispatch_table;
index e414cc4..1bf6ce5 100644 (file)
@@ -106,6 +106,7 @@ struct MT_OBJ_HANDLE_TYPE {
 struct MT_MEM_OBJ_INFO {
     void*                       object;                 // Dispatchable object used to create this memory (device of swapchain)
     uint32_t                    refCount;               // Count of references (obj bindings or CB use)
+    bool                        valid;                  // Stores if the memory has valid data or not
     VkDeviceMemory              mem;
     VkMemoryAllocateInfo        allocInfo;
     list<MT_OBJ_HANDLE_TYPE>    pObjBindings;           // list container of objects bound to this memory
@@ -117,6 +118,7 @@ struct MT_MEM_OBJ_INFO {
 // This only applies to Buffers and Images, which can have memory bound to them
 struct MT_OBJ_BINDING_INFO {
     VkDeviceMemory mem;
+    bool valid; //If this is a swapchain image backing memory is not a MT_MEM_OBJ_INFO so store it here.
     union create_info {
         VkImageCreateInfo  image;
         VkBufferCreateInfo buffer;
@@ -132,19 +134,42 @@ typedef struct _MT_CB_INFO {
     uint64_t                    fenceId;
     VkFence                     lastSubmittedFence;
     VkQueue                     lastSubmittedQueue;
+    VkRenderPass                pass;
     // Order dependent, stl containers must be at end of struct
     list<VkDeviceMemory>        pMemObjList; // List container of Mem objs referenced by this CB
     // Constructor
     _MT_CB_INFO():createInfo{},pipelines{},attachmentCount(0),fenceId(0),lastSubmittedFence{},lastSubmittedQueue{} {};
 } MT_CB_INFO;
 
-
 // Track command pools and their command buffers
 typedef struct _MT_CMD_POOL_INFO {
     VkCommandPoolCreateFlags    createFlags;
     list<VkCommandBuffer>       pCommandBuffers; // list container of cmd buffers allocated from this pool
 } MT_CMD_POOL_INFO;
 
+struct MT_IMAGE_VIEW_INFO {
+    VkImage image;
+};
+
+struct MT_FB_ATTACHMENT_INFO {
+    VkImage image;
+    VkDeviceMemory mem;
+};
+
+struct MT_FB_INFO {
+    std::vector<MT_FB_ATTACHMENT_INFO> attachments;
+};
+
+struct MT_PASS_ATTACHMENT_INFO {
+   VkAttachmentLoadOp load_op; 
+   VkAttachmentStoreOp store_op; 
+};
+
+struct MT_PASS_INFO {
+    VkFramebuffer fb;
+    std::vector<MT_PASS_ATTACHMENT_INFO> attachments;
+};
+
 // Associate fenceId with a fence object
 struct MT_FENCE_INFO {
     uint64_t          fenceId;          // Sequence number for fence at last submit