layers:Check secondary command buffer renderArea
authorTobin Ehlis <tobine@google.com>
Mon, 12 Mar 2018 17:26:39 +0000 (11:26 -0600)
committerTobin Ehlis <tobine@google.com>
Fri, 16 Mar 2018 14:24:50 +0000 (08:24 -0600)
Fixes #2480
Fixes #1501

Add delayed function call to verify secondary command buffer renderArea
against vkCmdClearAttachments() rects at vkCmdExecuteCommands() time.

Updated the lambda function container for delayed secondary command
buffer checks to include a reference to the primary command buffer.
Add lambda call at vkCmdClearAttachments() for secondary command buffer
and pass in primary command buffer reference so that area restriction
can be appropriately checked at vkCmdExecuteCommands() time when
renderArea of renderPass is known.

layers/buffer_validation.cpp
layers/core_validation.cpp
layers/core_validation_types.h

index 52974e9..ac332d8 100644 (file)
@@ -2198,14 +2198,27 @@ bool PreCallValidateCmdClearAttachments(layer_data *device_data, VkCommandBuffer
                 for (uint32_t j = 0; j < rectCount; j++) {
                     // The rectangular region specified by a given element of pRects must be contained within the render area of
                     // the current render pass instance
-                    // TODO: This check should be moved to CmdExecuteCommands or QueueSubmit to cover secondary CB cases
-                    if ((cb_node->createInfo.level == VK_COMMAND_BUFFER_LEVEL_PRIMARY) &&
-                        (false == ContainsRect(cb_node->activeRenderPassBeginInfo.renderArea, pRects[j].rect))) {
-                        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                    if (cb_node->createInfo.level == VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
+                        if (false == ContainsRect(cb_node->activeRenderPassBeginInfo.renderArea, pRects[j].rect)) {
+                            skip |=
+                                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
                                         HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_18600020, "DS",
                                         "vkCmdClearAttachments(): The area defined by pRects[%d] is not contained in the area of "
                                         "the current render pass instance. %s",
                                         j, validation_error_map[VALIDATION_ERROR_18600020]);
+                        }
+                    } else {
+                        cb_node->cmd_execute_commands_functions.emplace_back([=](GLOBAL_CB_NODE *prim_cb, VkFramebuffer fb) {
+                            if (false == ContainsRect(prim_cb->activeRenderPassBeginInfo.renderArea, pRects[j].rect)) {
+                                return log_msg(
+                                    report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
+                                    HandleToUint64(commandBuffer), __LINE__, VALIDATION_ERROR_18600020, "DS",
+                                    "vkCmdClearAttachments(): The area defined by pRects[%d] is not contained in the area of "
+                                    "the current render pass instance. %s",
+                                    j, validation_error_map[VALIDATION_ERROR_18600020]);
+                            }
+                            return false;
+                        });
                     }
                     // The layers specified by a given element of pRects must be contained within every attachment that
                     // pAttachments refers to
index 4ecb82e..e0c4789 100644 (file)
@@ -7374,7 +7374,7 @@ static bool ValidateRenderPassImageBarriers(layer_data *device_data, const char
         if (VK_NULL_HANDLE == cb_state->activeFramebuffer) {
             assert(VK_COMMAND_BUFFER_LEVEL_SECONDARY == cb_state->createInfo.level);
             // Secondary CB case w/o FB specified delay validation
-            cb_state->cmd_execute_commands_functions.emplace_back([=](VkFramebuffer fb) {
+            cb_state->cmd_execute_commands_functions.emplace_back([=](GLOBAL_CB_NODE *primary_cb, VkFramebuffer fb) {
                 return ValidateImageBarrierImage(device_data, funcName, cb_state, fb, active_subpass, sub_desc, rp_handle, i,
                                                  img_barrier);
             });
@@ -9437,10 +9437,10 @@ VKAPI_ATTR void VKAPI_CALL CmdExecuteCommands(VkCommandBuffer commandBuffer, uin
                         //  If framebuffer for secondary CB is not NULL, then it must match active FB from primaryCB
                         skip |=
                             validateFramebuffer(dev_data, commandBuffer, pCB, pCommandBuffers[i], pSubCB, "vkCmdExecuteCommands()");
-                        if (VK_NULL_HANDLE == pSubCB->activeFramebuffer) {
+                        if (!pSubCB->cmd_execute_commands_functions.empty()) {
                             //  Inherit primary's activeFramebuffer and while running validate functions
                             for (auto &function : pSubCB->cmd_execute_commands_functions) {
-                                skip |= function(pCB->activeFramebuffer);
+                                skip |= function(pCB, pCB->activeFramebuffer);
                             }
                         }
                     }
index da0bfc9..e4371b8 100644 (file)
@@ -758,7 +758,7 @@ struct GLOBAL_CB_NODE : public BASE_NODE {
     // Validation functions run at primary CB queue submit time
     std::vector<std::function<bool()>> queue_submit_functions;
     // Validation functions run when secondary CB is executed in primary
-    std::vector<std::function<bool(VkFramebuffer)>> cmd_execute_commands_functions;
+    std::vector<std::function<bool(GLOBAL_CB_NODE *, VkFramebuffer)>> cmd_execute_commands_functions;
     std::unordered_set<VkDeviceMemory> memObjs;
     std::vector<std::function<bool(VkQueue)>> eventUpdates;
     std::vector<std::function<bool(VkQueue)>> queryUpdates;