nvk: Invalidate state after secondary command buffers

Today, the only thing that this really affects is descriptor sets and
dynamic state as everything else is re-emitted almost every time.
However, as we add more dirtying, we'll need to be more and more careful
about stale state leaking across secondary command buffer executions.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/27049>
This commit is contained in:
Faith Ekstrand
2024-01-08 09:33:32 -06:00
committed by Marge Bot
parent bc36dfdb5d
commit 2cab67a9f1
4 changed files with 52 additions and 0 deletions

View File

@@ -307,6 +307,9 @@ nvk_CmdExecuteCommands(VkCommandBuffer commandBuffer,
{
VK_FROM_HANDLE(nvk_cmd_buffer, cmd, commandBuffer);
if (commandBufferCount == 0)
return;
nvk_cmd_buffer_flush_push(cmd);
for (uint32_t i = 0; i < commandBufferCount; i++) {
@@ -327,6 +330,27 @@ nvk_CmdExecuteCommands(VkCommandBuffer commandBuffer,
*/
util_dynarray_append_dynarray(&cmd->pushes, &other->pushes);
}
/* From the Vulkan 1.3.275 spec:
*
* "When secondary command buffer(s) are recorded to execute on a
* primary command buffer, the secondary command buffer inherits no
* state from the primary command buffer, and all state of the primary
* command buffer is undefined after an execute secondary command buffer
* command is recorded. There is one exception to this rule - if the
* primary command buffer is inside a render pass instance, then the
* render pass and subpass state is not disturbed by executing secondary
* command buffers. For state dependent commands (such as draws and
* dispatches), any state consumed by those commands must not be
* undefined."
*
* Therefore, it's the client's job to reset all the state in the primary
* after the secondary executes. However, if we're doing any internal
* dirty tracking, we may miss the fact that a secondary has messed with
* GPU state if we don't invalidate all our internal tracking.
*/
nvk_cmd_invalidate_graphics_state(cmd);
nvk_cmd_invalidate_compute_state(cmd);
}
enum nvk_barrier {

View File

@@ -204,6 +204,9 @@ void nvk_cmd_buffer_begin_graphics(struct nvk_cmd_buffer *cmd,
void nvk_cmd_buffer_begin_compute(struct nvk_cmd_buffer *cmd,
const VkCommandBufferBeginInfo *pBeginInfo);
void nvk_cmd_invalidate_graphics_state(struct nvk_cmd_buffer *cmd);
void nvk_cmd_invalidate_compute_state(struct nvk_cmd_buffer *cmd);
void nvk_cmd_bind_graphics_pipeline(struct nvk_cmd_buffer *cmd,
struct nvk_graphics_pipeline *pipeline);
void nvk_cmd_bind_compute_pipeline(struct nvk_cmd_buffer *cmd,

View File

@@ -63,6 +63,12 @@ nvk_cmd_buffer_begin_compute(struct nvk_cmd_buffer *cmd,
}
}
void
nvk_cmd_invalidate_compute_state(struct nvk_cmd_buffer *cmd)
{
memset(&cmd->state.cs, 0, sizeof(cmd->state.cs));
}
static void
nva0c0_qmd_set_dispatch_size(UNUSED struct nvk_device *dev, uint32_t *qmd,
uint32_t x, uint32_t y, uint32_t z)

View File

@@ -512,6 +512,25 @@ nvk_cmd_buffer_begin_graphics(struct nvk_cmd_buffer *cmd,
}
}
void
nvk_cmd_invalidate_graphics_state(struct nvk_cmd_buffer *cmd)
{
vk_dynamic_graphics_state_dirty_all(&cmd->vk.dynamic_graphics_state);
/* From the Vulkan 1.3.275 spec:
*
* "...There is one exception to this rule - if the primary command
* buffer is inside a render pass instance, then the render pass and
* subpass state is not disturbed by executing secondary command
* buffers."
*
* We need to reset everything EXCEPT the render pass state.
*/
struct nvk_rendering_state render_save = cmd->state.gfx.render;
memset(&cmd->state.gfx, 0, sizeof(cmd->state.gfx));
cmd->state.gfx.render = render_save;
}
static void
nvk_attachment_init(struct nvk_attachment *att,
const VkRenderingAttachmentInfo *info)