layers: In DrawState, validate correct use of RenderPass
authorTobin Ehlis <tobin@lunarg.com>
Wed, 24 Jun 2015 21:53:07 +0000 (15:53 -0600)
committerTobin Ehlis <tobin@lunarg.com>
Thu, 25 Jun 2015 22:57:55 +0000 (16:57 -0600)
This change validates certain API calls are made inside of or outside of a RenderPass as appropriate. Exact restrictions included in this changelist are included below.

Also fixed cube and tri demos to Bind Pipeline & DescriptorSets within RenderPass and updated some layer validation tests.

The following calls must be within RenderPass:
vkCmdBindPipeline() w/ GFX pipelineBindPoint
vkCmdBindDescriptorSets() w/ GFX pipelineBindPoint
vkCmdBindDynamicStateObject()
vkCmdBindIndexBuffer()
vkCmdBindVertexBuffers()
vkCmdEndRenderPass()

The following calls must be outside of RenderPass:
vkCmdBindPipeline() w/ COMPUTE pipelineBindPoint
vkCmdBindDescriptorSets() w/ COMPUTE pipelineBindPoint
vkCmdBlitImage()
vkCmdResolveImage()
vkCmdBeginRenderPass()

demos/cube.c
demos/tri.c
layers/draw_state.cpp
layers/draw_state.h

index 53ac17b135b029c650821592282eaecb311ca1ae..13fbbbe145bc4deada93d120b339a319979f49dd 100644 (file)
@@ -509,6 +509,7 @@ static void demo_draw_build_cmd(struct demo *demo, VkCmdBuffer cmd_buf)
     err = vkBeginCommandBuffer(cmd_buf, &cmd_buf_info);
     assert(!err);
 
+    vkCmdBeginRenderPass(cmd_buf, &rp_begin);
     vkCmdBindPipeline(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS,
                                   demo->pipeline);
     vkCmdBindDescriptorSets(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, demo->pipeline_layout,
@@ -521,7 +522,6 @@ static void demo_draw_build_cmd(struct demo *demo, VkCmdBuffer cmd_buf)
     vkCmdBindDynamicStateObject(cmd_buf, VK_STATE_BIND_POINT_DEPTH_STENCIL,
                                      demo->depth_stencil);
 
-    vkCmdBeginRenderPass(cmd_buf, &rp_begin);
     clear_range.aspect = VK_IMAGE_ASPECT_DEPTH;
     clear_range.baseMipLevel = 0;
     clear_range.mipLevels = 1;
index 2f4ca97bed3167064272e25617d9323e7561e3c7..1855f559d3cdbfc2b3297fcae32bd26e25658c57 100644 (file)
@@ -320,6 +320,7 @@ static void demo_draw_build_cmd(struct demo *demo)
     err = vkBeginCommandBuffer(demo->draw_cmd, &cmd_buf_info);
     assert(!err);
 
+    vkCmdBeginRenderPass(demo->draw_cmd, &rp_begin);
     vkCmdBindPipeline(demo->draw_cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
                                   demo->pipeline);
     vkCmdBindDescriptorSets(demo->draw_cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, demo->pipeline_layout,
@@ -335,7 +336,6 @@ static void demo_draw_build_cmd(struct demo *demo)
     VkDeviceSize offsets[1] = {0};
     vkCmdBindVertexBuffers(demo->draw_cmd, VERTEX_BUFFER_BIND_ID, 1, &demo->vertices.buf, offsets);
 
-    vkCmdBeginRenderPass(demo->draw_cmd, &rp_begin);
     clear_range.aspect = VK_IMAGE_ASPECT_COLOR;
     clear_range.baseMipLevel = 0;
     clear_range.mipLevels = 1;
index c2e3cbf1e0b7e43f3e0ca8097f0bdefd33d59a79..543ecbe04a1705e8556f3b1e1efb35a0761043f2 100644 (file)
@@ -423,7 +423,7 @@ static bool32_t validate_draw_state(GLOBAL_CB_NODE* pCB, bool32_t indexedDraw) {
     bool32_t result = validate_draw_state_flags(pCB, indexedDraw);
     PIPELINE_NODE* pPipe = getPipeline(pCB->lastBoundPipeline);
     // Now complete other state checks
-    if (pCB->lastBoundPipelineLayout != pPipe->graphicsPipelineCI.layout) {
+    if (pPipe && (pCB->lastBoundPipelineLayout != pPipe->graphicsPipelineCI.layout)) {
         result = VK_FALSE;
         log_msg(mdd(pCB->cmdBuffer), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_PIPELINE_LAYOUT, pCB->lastBoundPipelineLayout, 0, DRAWSTATE_PIPELINE_LAYOUT_MISMATCH, "DS",
                 "Pipeline layout from last vkCmdBindDescriptorSets() (%s) does not match PSO Pipeline layout (%s)", pCB->lastBoundPipelineLayout, pPipe->graphicsPipelineCI.layout);
@@ -2098,19 +2098,23 @@ VK_LAYER_EXPORT void VKAPI vkCmdBindPipeline(VkCmdBuffer cmdBuffer, VkPipelineBi
             if ((VK_PIPELINE_BIND_POINT_COMPUTE == pipelineBindPoint) && (pCB->activeRenderPass)) {
                 log_msg(mdd(cmdBuffer), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_PIPELINE, pipeline, 0, DRAWSTATE_INVALID_RENDERPASS_CMD, "DS",
                         "Incorrectly binding compute pipeline (%p) during active RenderPass (%p)", (void*)pipeline, (void*)pCB->activeRenderPass);
-            }
-            PIPELINE_NODE* pPN = getPipeline(pipeline);
-            if (pPN) {
-                pCB->lastBoundPipeline = pipeline;
-                loader_platform_thread_lock_mutex(&globalLock);
-                set_cb_pso_status(pCB, pPN);
-                g_lastBoundPipeline = pPN;
-                loader_platform_thread_unlock_mutex(&globalLock);
-                validatePipelineState(pCB, pipelineBindPoint, pipeline);
-                get_dispatch_table(draw_state_device_table_map, cmdBuffer)->CmdBindPipeline(cmdBuffer, pipelineBindPoint, pipeline);
+            } else if ((VK_PIPELINE_BIND_POINT_GRAPHICS == pipelineBindPoint) && (!pCB->activeRenderPass)) {
+                log_msg(mdd(cmdBuffer), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_PIPELINE, pipeline, 0, DRAWSTATE_NO_ACTIVE_RENDERPASS, "DS",
+                        "Incorrectly binding graphics pipeline (%p) without an active RenderPass", (void*)pipeline);
             } else {
-                log_msg(mdd(cmdBuffer), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_PIPELINE, pipeline, 0, DRAWSTATE_INVALID_PIPELINE, "DS",
-                        "Attempt to bind Pipeline %p that doesn't exist!", (void*)pipeline);
+                PIPELINE_NODE* pPN = getPipeline(pipeline);
+                if (pPN) {
+                    pCB->lastBoundPipeline = pipeline;
+                    loader_platform_thread_lock_mutex(&globalLock);
+                    set_cb_pso_status(pCB, pPN);
+                    g_lastBoundPipeline = pPN;
+                    loader_platform_thread_unlock_mutex(&globalLock);
+                    validatePipelineState(pCB, pipelineBindPoint, pipeline);
+                    get_dispatch_table(draw_state_device_table_map, cmdBuffer)->CmdBindPipeline(cmdBuffer, pipelineBindPoint, pipeline);
+                } else {
+                    log_msg(mdd(cmdBuffer), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_PIPELINE, pipeline, 0, DRAWSTATE_INVALID_PIPELINE, "DS",
+                            "Attempt to bind Pipeline %p that doesn't exist!", (void*)pipeline);
+                }
             }
         } else {
             report_error_no_cb_begin(cmdBuffer, "vkCmdBindPipeline()");
@@ -2124,9 +2128,13 @@ VK_LAYER_EXPORT void VKAPI vkCmdBindDynamicStateObject(VkCmdBuffer cmdBuffer, Vk
     if (pCB) {
         if (pCB->state == CB_UPDATE_ACTIVE) {
             updateCBTracking(cmdBuffer);
+            addCmd(pCB, CMD_BINDDYNAMICSTATEOBJECT);
+            if (!pCB->activeRenderPass) {
+                log_msg(mdd(pCB->cmdBuffer), VK_DBG_REPORT_ERROR_BIT, (VkObjectType) 0, NULL, 0, DRAWSTATE_NO_ACTIVE_RENDERPASS, "DS",
+                        "Incorrect call to vkCmdBindDynamicStateObject() without an active RenderPass.");
+            }
             loader_platform_thread_lock_mutex(&globalLock);
             set_cb_dyn_status(pCB, stateBindPoint);
-            addCmd(pCB, CMD_BINDDYNAMICSTATEOBJECT);
             if (dynamicStateMap.find(state) == dynamicStateMap.end()) {
                 VkObjectType stateType;
                 switch (stateBindPoint) {
@@ -2166,7 +2174,13 @@ VK_LAYER_EXPORT void VKAPI vkCmdBindDescriptorSets(VkCmdBuffer cmdBuffer, VkPipe
         if (pCB->state == CB_UPDATE_ACTIVE) {
             updateCBTracking(cmdBuffer);
             addCmd(pCB, CMD_BINDDESCRIPTORSETS);
-            if (validateBoundPipeline(cmdBuffer)) {
+            if ((VK_PIPELINE_BIND_POINT_COMPUTE == pipelineBindPoint) && (pCB->activeRenderPass)) {
+                log_msg(mdd(cmdBuffer), VK_DBG_REPORT_ERROR_BIT, (VkObjectType) 0, NULL, 0, DRAWSTATE_INVALID_RENDERPASS_CMD, "DS",
+                        "Incorrectly binding compute DescriptorSets during active RenderPass (%p)", (void*)pCB->activeRenderPass);
+            } else if ((VK_PIPELINE_BIND_POINT_GRAPHICS == pipelineBindPoint) && (!pCB->activeRenderPass)) {
+                log_msg(mdd(cmdBuffer), VK_DBG_REPORT_ERROR_BIT, (VkObjectType) 0, NULL, 0, DRAWSTATE_NO_ACTIVE_RENDERPASS, "DS",
+                        "Incorrectly binding graphics DescriptorSets without an active RenderPass");
+            } else if (validateBoundPipeline(cmdBuffer)) {
                 for (uint32_t i=0; i<setCount; i++) {
                     if (getSetNode(pDescriptorSets[i])) {
                         loader_platform_thread_lock_mutex(&globalLock);
@@ -2197,9 +2211,14 @@ VK_LAYER_EXPORT void VKAPI vkCmdBindIndexBuffer(VkCmdBuffer cmdBuffer, VkBuffer
         if (pCB->state == CB_UPDATE_ACTIVE) {
             updateCBTracking(cmdBuffer);
             addCmd(pCB, CMD_BINDINDEXBUFFER);
-            // TODO : Can be more exact in tracking/validating details for Idx buffer, for now just make sure *something* was bound
-            pCB->status |= CBSTATUS_INDEX_BUFFER_BOUND;
-            get_dispatch_table(draw_state_device_table_map, cmdBuffer)->CmdBindIndexBuffer(cmdBuffer, buffer, offset, indexType);
+            if (!pCB->activeRenderPass) {
+                log_msg(mdd(pCB->cmdBuffer), VK_DBG_REPORT_ERROR_BIT, (VkObjectType) 0, NULL, 0, DRAWSTATE_NO_ACTIVE_RENDERPASS, "DS",
+                        "Incorrect call to vkCmdBindIndexBuffer() without an active RenderPass.");
+            } else {
+                // TODO : Can be more exact in tracking/validating details for Idx buffer, for now just make sure *something* was bound
+                pCB->status |= CBSTATUS_INDEX_BUFFER_BOUND;
+                get_dispatch_table(draw_state_device_table_map, cmdBuffer)->CmdBindIndexBuffer(cmdBuffer, buffer, offset, indexType);
+            }
         } else {
             report_error_no_cb_begin(cmdBuffer, "vkCmdBindIndexBuffer()");
         }
@@ -2219,9 +2238,14 @@ VK_LAYER_EXPORT void VKAPI vkCmdBindVertexBuffers(
             /* TODO: Need to track all the vertex buffers, not just last one */
             updateCBTracking(cmdBuffer);
             addCmd(pCB, CMD_BINDVERTEXBUFFER);
-            pCB->lastVtxBinding = startBinding + bindingCount -1;
-            if (validateBoundPipeline(cmdBuffer)) {
-                get_dispatch_table(draw_state_device_table_map, cmdBuffer)->CmdBindVertexBuffers(cmdBuffer, startBinding, bindingCount, pBuffers, pOffsets);
+            if (!pCB->activeRenderPass) {
+                log_msg(mdd(pCB->cmdBuffer), VK_DBG_REPORT_ERROR_BIT, (VkObjectType) 0, NULL, 0, DRAWSTATE_NO_ACTIVE_RENDERPASS, "DS",
+                        "Incorrect call to vkCmdBindVertexBuffers() without an active RenderPass.");
+            } else {
+                pCB->lastVtxBinding = startBinding + bindingCount -1;
+                if (validateBoundPipeline(cmdBuffer)) {
+                    get_dispatch_table(draw_state_device_table_map, cmdBuffer)->CmdBindVertexBuffers(cmdBuffer, startBinding, bindingCount, pBuffers, pOffsets);
+                }
             }
         } else {
             report_error_no_cb_begin(cmdBuffer, "vkCmdBindIndexBuffer()");
@@ -2393,7 +2417,8 @@ VK_LAYER_EXPORT void VKAPI vkCmdBlitImage(VkCmdBuffer cmdBuffer,
                 log_msg(mdd(cmdBuffer), VK_DBG_REPORT_ERROR_BIT, (VkObjectType) 0, NULL, 0, DRAWSTATE_INVALID_RENDERPASS_CMD, "DS",
                         "Incorrectly issuing CmdBlitImage during active RenderPass (%p)", (void*)pCB->activeRenderPass);
             }
-            get_dispatch_table(draw_state_device_table_map, cmdBuffer)->CmdBlitImage(cmdBuffer, srcImage, srcImageLayout, destImage, destImageLayout, regionCount, pRegions, filter);
+            else
+                get_dispatch_table(draw_state_device_table_map, cmdBuffer)->CmdBlitImage(cmdBuffer, srcImage, srcImageLayout, destImage, destImageLayout, regionCount, pRegions, filter);
         } else {
             report_error_no_cb_begin(cmdBuffer, "vkCmdBindIndexBuffer()");
         }
@@ -2507,7 +2532,12 @@ VK_LAYER_EXPORT void VKAPI vkCmdResolveImage(VkCmdBuffer cmdBuffer,
         if (pCB->state == CB_UPDATE_ACTIVE) {
             updateCBTracking(cmdBuffer);
             addCmd(pCB, CMD_RESOLVEIMAGE);
-            get_dispatch_table(draw_state_device_table_map, cmdBuffer)->CmdResolveImage(cmdBuffer, srcImage, srcImageLayout, destImage, destImageLayout, regionCount, pRegions);
+            if (pCB->activeRenderPass) {
+                log_msg(mdd(cmdBuffer), VK_DBG_REPORT_ERROR_BIT, (VkObjectType) 0, NULL, 0, DRAWSTATE_INVALID_RENDERPASS_CMD, "DS",
+                        "Cannot call vkCmdResolveImage() during an active RenderPass (%p).", (void*)pCB->activeRenderPass);
+            }
+            else
+                get_dispatch_table(draw_state_device_table_map, cmdBuffer)->CmdResolveImage(cmdBuffer, srcImage, srcImageLayout, destImage, destImageLayout, regionCount, pRegions);
         } else {
             report_error_no_cb_begin(cmdBuffer, "vkCmdBindIndexBuffer()");
         }
@@ -2715,20 +2745,24 @@ VK_LAYER_EXPORT void VKAPI vkCmdBeginRenderPass(VkCmdBuffer cmdBuffer, const VkR
     GLOBAL_CB_NODE* pCB = getCBNode(cmdBuffer);
     if (pCB) {
         if (pRenderPassBegin && pRenderPassBegin->renderPass) {
-            updateCBTracking(cmdBuffer);
-            addCmd(pCB, CMD_BEGINRENDERPASS);
-            pCB->activeRenderPass = pRenderPassBegin->renderPass;
-            pCB->framebuffer = pRenderPassBegin->framebuffer;
-            if (pCB->lastBoundPipeline) {
-                validatePipelineState(pCB, VK_PIPELINE_BIND_POINT_GRAPHICS, pCB->lastBoundPipeline);
+            if (pCB->activeRenderPass) {
+                log_msg(mdd(cmdBuffer), VK_DBG_REPORT_ERROR_BIT, (VkObjectType) 0, NULL, 0, DRAWSTATE_INVALID_RENDERPASS_CMD, "DS",
+                        "Cannot call vkCmdBeginRenderPass() during an active RenderPass (%p). You must first call vkCmdEndRenderPass().", (void*)pCB->activeRenderPass);
+            } else {
+                updateCBTracking(cmdBuffer);
+                addCmd(pCB, CMD_BEGINRENDERPASS);
+                pCB->activeRenderPass = pRenderPassBegin->renderPass;
+                pCB->framebuffer = pRenderPassBegin->framebuffer;
+                if (pCB->lastBoundPipeline) {
+                    validatePipelineState(pCB, VK_PIPELINE_BIND_POINT_GRAPHICS, pCB->lastBoundPipeline);
+                }
+                get_dispatch_table(draw_state_device_table_map, cmdBuffer)->CmdBeginRenderPass(cmdBuffer, pRenderPassBegin);
             }
-        }
-        else {
+        } else {
             log_msg(mdd(cmdBuffer), VK_DBG_REPORT_ERROR_BIT, (VkObjectType) 0, NULL, 0, DRAWSTATE_INVALID_RENDERPASS, "DS",
                     "You cannot use a NULL RenderPass object in vkCmdBeginRenderPass()");
         }
     }
-    get_dispatch_table(draw_state_device_table_map, cmdBuffer)->CmdBeginRenderPass(cmdBuffer, pRenderPassBegin);
 }
 
 VK_LAYER_EXPORT void VKAPI vkCmdEndRenderPass(VkCmdBuffer cmdBuffer, VkRenderPass renderPass)
@@ -2736,16 +2770,21 @@ VK_LAYER_EXPORT void VKAPI vkCmdEndRenderPass(VkCmdBuffer cmdBuffer, VkRenderPas
     GLOBAL_CB_NODE* pCB = getCBNode(cmdBuffer);
     if (pCB) {
         if (renderPass) {
-            updateCBTracking(cmdBuffer);
-            addCmd(pCB, CMD_ENDRENDERPASS);
-            pCB->activeRenderPass = 0;
+            if (!pCB->activeRenderPass) {
+                log_msg(mdd(pCB->cmdBuffer), VK_DBG_REPORT_ERROR_BIT, (VkObjectType) 0, NULL, 0, DRAWSTATE_NO_ACTIVE_RENDERPASS, "DS",
+                        "Incorrect call to vkCmdEndRenderPass() without an active RenderPass.");
+            } else {
+                updateCBTracking(cmdBuffer);
+                addCmd(pCB, CMD_ENDRENDERPASS);
+                pCB->activeRenderPass = 0;
+                get_dispatch_table(draw_state_device_table_map, cmdBuffer)->CmdEndRenderPass(cmdBuffer, renderPass);
+            }
         }
         else {
             log_msg(mdd(cmdBuffer), VK_DBG_REPORT_ERROR_BIT, (VkObjectType) 0, NULL, 0, DRAWSTATE_INVALID_RENDERPASS, "DS",
                     "You cannot use a NULL RenderPass object in vkCmdEndRenderPass()");
         }
     }
-    get_dispatch_table(draw_state_device_table_map, cmdBuffer)->CmdEndRenderPass(cmdBuffer, renderPass);
 }
 
 VK_LAYER_EXPORT VkResult VKAPI vkDbgCreateMsgCallback(
index 6d6e2e2a49c3c80fdd85b39bb92a201bfe71e3a3..6f8f016a6ebfea866c85b467d48449868053732d 100644 (file)
@@ -58,6 +58,7 @@ typedef enum _DRAW_STATE_ERROR
     DRAWSTATE_INVALID_RENDERPASS,               // Use of a NULL or otherwise invalid RenderPass object
     DRAWSTATE_INVALID_RENDERPASS_CMD,           // Invalid cmd submitted while a RenderPass is active
     DRAWSTATE_NO_ACTIVE_RENDERPASS,             // Rendering cmd submitted without an active RenderPass
+    DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED,       // DescriptorSet bound but it was never updated. This is a warning code.
     DRAWSTATE_INVALID_EXTENSION,
 } DRAW_STATE_ERROR;