layers: Fix img layout state in CmdExecuteCommands
authorAlex Smith <asmith@feralinteractive.com>
Wed, 16 Aug 2017 08:23:27 +0000 (09:23 +0100)
committerMark Lobodzinski <mark@lunarg.com>
Wed, 16 Aug 2017 18:16:09 +0000 (12:16 -0600)
Previously the layout state in the primary command buffer was just
overwritten with the state in the secondary command buffer.

This can lead to spurious errors upon submission of the primary CB, if
an image used in the secondary CB is used prior to CmdExecuteCommands
in the primary CB with a different initial layout. This is because the
initialLayout field for the image on the primary CB is overwritten
with that of the secondary CB.

An example case that was incorrectly erroring (these commands refer to
the same image, newly created):

  (primary buffer)
  vkCmdPipelineBarrier, transition UNDEFINED -> TRANSFER_DST_OPTIMAL
  vkCmdExecuteCommands
    (secondary buffer)
    ...
    vkCmdCopyBufferToImage, layout TRANSFER_DST_OPTIMAL

Just before the CmdExecuteCommands, the image had initialLayout =
UNDEFINED and layout = TRANSFER_DST_OPTIMAL on the primary CB, and
initialLayout = layout = TRANSFER_DST_OPTIMAL on the secondary.

After CmdExecuteCommands, the primary CB state is overwritten, so
it has initialLayout = layout = TRANSFER_DST_OPTIMAL. At submission,
this then errors because the global image layout is UNDEFINED.

Fix by only setting initialLayout on the primary CB from the secondary
if the image hasn't already been used on the primary.

Change-Id: Iae248ed09b1f87598fd192ba3d6f0bcf7ad38ada

layers/core_validation.cpp

index d3eee2b..7db168a 100644 (file)
@@ -8386,7 +8386,17 @@ VKAPI_ATTR void VKAPI_CALL CmdExecuteCommands(VkCommandBuffer commandBuffer, uin
             // TODO: separate validate from update! This is very tangled.
             // Propagate layout transitions to the primary cmd buffer
             for (auto ilm_entry : pSubCB->imageLayoutMap) {
-                SetLayout(dev_data, pCB, ilm_entry.first, ilm_entry.second);
+                if (pCB->imageLayoutMap.find(ilm_entry.first) != pCB->imageLayoutMap.end()) {
+                    pCB->imageLayoutMap[ilm_entry.first].layout = ilm_entry.second.layout;
+                } else {
+                    assert(ilm_entry.first.hasSubresource);
+                    IMAGE_CMD_BUF_LAYOUT_NODE node;
+                    if (!FindCmdBufLayout(dev_data, pCB, ilm_entry.first.image, ilm_entry.first.subresource, node)) {
+                        node.initialLayout = ilm_entry.second.initialLayout;
+                    }
+                    node.layout = ilm_entry.second.layout;
+                    SetLayout(dev_data, pCB, ilm_entry.first, node);
+                }
             }
             pSubCB->primaryCommandBuffer = pCB->commandBuffer;
             pCB->linkedCommandBuffers.insert(pSubCB);