v3dv: meta operations can happen outside a render pass
authorIago Toral Quiroga <itoral@igalia.com>
Tue, 21 Apr 2020 12:01:35 +0000 (14:01 +0200)
committerMarge Bot <eric+marge@anholt.net>
Tue, 13 Oct 2020 21:21:29 +0000 (21:21 +0000)
We were asserting that we had a valid subpass index, but we can have
meta operations that run outside a render pass, such as for blitting.

If we allow this, then we also need to account for the fact that
pipelines can be bound outside a render pass too.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6766>

src/broadcom/vulkan/v3dv_cmd_buffer.c

index 8a8783f..7707a7e 100644 (file)
@@ -2798,86 +2798,84 @@ emit_occlusion_query(struct v3dv_cmd_buffer *cmd_buffer)
    cmd_buffer->state.dirty &= ~V3DV_CMD_DIRTY_OCCLUSION_QUERY;
 }
 
-/* This stores command buffer state for the current subpass that we are
- * about to interrupt to emit a meta pass.
+/* This stores command buffer state that we might be about to stomp for
+ * a meta operation.
  */
 void
 v3dv_cmd_buffer_meta_state_push(struct v3dv_cmd_buffer *cmd_buffer)
 {
    struct v3dv_cmd_buffer_state *state = &cmd_buffer->state;
-   assert(state->subpass_idx != -1);
 
-   state->meta.pipeline = v3dv_pipeline_to_handle(state->pipeline);
-   state->meta.framebuffer = v3dv_framebuffer_to_handle(state->framebuffer);
-   state->meta.pass = v3dv_render_pass_to_handle(state->pass);
-   state->meta.subpass_idx = state->subpass_idx;
-
-   const uint32_t attachment_state_item_size =
-      sizeof(struct v3dv_cmd_buffer_attachment_state);
-   const uint32_t attachment_state_total_size =
-      attachment_state_item_size * state->attachment_count;
-   if (state->meta.attachment_alloc_count < state->attachment_count) {
-      if (state->meta.attachment_alloc_count > 0)
-         vk_free(&cmd_buffer->device->alloc, state->meta.attachments);
-
-      state->meta.attachments = vk_zalloc(&cmd_buffer->device->alloc,
-                                          attachment_state_total_size, 8,
-                                          VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
-      state->meta.attachment_alloc_count = state->attachment_count;
-   }
-   state->meta.attachment_count = state->attachment_count;
-   memcpy(state->meta.attachments, state->attachments,
-          attachment_state_total_size);
-
-   state->meta.tile_aligned_render_area = state->tile_aligned_render_area;
-   memcpy(&state->meta.render_area, &state->render_area, sizeof(VkRect2D));
+   if (state->subpass_idx != -1) {
+      state->meta.subpass_idx = state->subpass_idx;
+      state->meta.framebuffer = v3dv_framebuffer_to_handle(state->framebuffer);
+      state->meta.pass = v3dv_render_pass_to_handle(state->pass);
+
+      const uint32_t attachment_state_item_size =
+         sizeof(struct v3dv_cmd_buffer_attachment_state);
+      const uint32_t attachment_state_total_size =
+         attachment_state_item_size * state->attachment_count;
+      if (state->meta.attachment_alloc_count < state->attachment_count) {
+         if (state->meta.attachment_alloc_count > 0)
+            vk_free(&cmd_buffer->device->alloc, state->meta.attachments);
+
+         state->meta.attachments = vk_zalloc(&cmd_buffer->device->alloc,
+                                             attachment_state_total_size, 8,
+                                             VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
+         state->meta.attachment_alloc_count = state->attachment_count;
+      }
+      state->meta.attachment_count = state->attachment_count;
+      memcpy(state->meta.attachments, state->attachments,
+             attachment_state_total_size);
+
+      state->meta.tile_aligned_render_area = state->tile_aligned_render_area;
+      memcpy(&state->meta.render_area, &state->render_area, sizeof(VkRect2D));
+   }
 
+   state->meta.pipeline = v3dv_pipeline_to_handle(state->pipeline);
    if (state->meta.pipeline)
       memcpy(&state->meta.dynamic, &state->dynamic, sizeof(state->dynamic));
 }
 
-/* This resstores command buffer state for a subpass that we interrupted to
- * emit a meta pass.
+/* This restores command buffer state after a meta operation
  */
 void
 v3dv_cmd_buffer_meta_state_pop(struct v3dv_cmd_buffer *cmd_buffer,
                                uint32_t dirty_dynamic_state)
 {
    struct v3dv_cmd_buffer_state *state = &cmd_buffer->state;
-   assert(state->meta.subpass_idx != -1);
 
-   state->pass = v3dv_render_pass_from_handle(state->meta.pass);
-   state->framebuffer = v3dv_framebuffer_from_handle(state->meta.framebuffer);
+   if (state->meta.subpass_idx != -1) {
+      state->pass = v3dv_render_pass_from_handle(state->meta.pass);
+      state->framebuffer = v3dv_framebuffer_from_handle(state->meta.framebuffer);
 
-   assert(state->meta.attachment_count <= state->attachment_count);
-   const uint32_t attachment_state_item_size =
-      sizeof(struct v3dv_cmd_buffer_attachment_state);
-   const uint32_t attachment_state_total_size =
-      attachment_state_item_size * state->meta.attachment_count;
-   state->attachment_count = state->meta.attachment_count;
-   memcpy(state->attachments, state->meta.attachments,
-          attachment_state_total_size);
+      assert(state->meta.attachment_count <= state->attachment_count);
+      const uint32_t attachment_state_item_size =
+         sizeof(struct v3dv_cmd_buffer_attachment_state);
+      const uint32_t attachment_state_total_size =
+         attachment_state_item_size * state->meta.attachment_count;
+      state->attachment_count = state->meta.attachment_count;
+      memcpy(state->attachments, state->meta.attachments,
+             attachment_state_total_size);
 
-   state->tile_aligned_render_area = state->meta.tile_aligned_render_area;
-   memcpy(&state->render_area, &state->meta.render_area, sizeof(VkRect2D));
+      state->tile_aligned_render_area = state->meta.tile_aligned_render_area;
+      memcpy(&state->render_area, &state->meta.render_area, sizeof(VkRect2D));
 
-   struct v3dv_job *job =
       v3dv_cmd_buffer_subpass_resume(cmd_buffer, state->meta.subpass_idx);
-   if (job) {
-      if (state->meta.pipeline != VK_NULL_HANDLE) {
-         v3dv_CmdBindPipeline(v3dv_cmd_buffer_to_handle(cmd_buffer),
-                              VK_PIPELINE_BIND_POINT_GRAPHICS,
-                              state->meta.pipeline);
-         memcpy(&state->dynamic, &state->meta.dynamic, sizeof(state->dynamic));
-         state->dirty |= dirty_dynamic_state;
-      } else {
-         state->pipeline = VK_NULL_HANDLE;
-      }
    } else {
-      state->pipeline = VK_NULL_HANDLE;
       state->subpass_idx = -1;
    }
 
+   if (state->meta.pipeline != VK_NULL_HANDLE) {
+      v3dv_CmdBindPipeline(v3dv_cmd_buffer_to_handle(cmd_buffer),
+                           VK_PIPELINE_BIND_POINT_GRAPHICS,
+                           state->meta.pipeline);
+      memcpy(&state->dynamic, &state->meta.dynamic, sizeof(state->dynamic));
+      state->dirty |= dirty_dynamic_state;
+   } else {
+      state->pipeline = VK_NULL_HANDLE;
+   }
+
    state->meta.pipeline = VK_NULL_HANDLE;
    state->meta.framebuffer = VK_NULL_HANDLE;
    state->meta.pass = VK_NULL_HANDLE;