vk: Add initial support for secondary command buffers
authorJason Ekstrand <jason.ekstrand@intel.com>
Thu, 30 Jul 2015 18:36:48 +0000 (11:36 -0700)
committerJason Ekstrand <jason.ekstrand@intel.com>
Thu, 30 Jul 2015 18:36:48 +0000 (11:36 -0700)
src/vulkan/anv_cmd_buffer.c
src/vulkan/anv_cmd_emit.c
src/vulkan/anv_device.c
src/vulkan/anv_private.h

index e7493d02839b76298109355f327be5398fca7ad2..cdde12a513b56d7e439fcf03349cfce0730742b6 100644 (file)
@@ -303,6 +303,16 @@ anv_batch_bo_start(struct anv_batch_bo *bbo, struct anv_batch *batch,
    bbo->relocs.num_relocs = 0;
 }
 
+static void
+anv_batch_bo_continue(struct anv_batch_bo *bbo, struct anv_batch *batch,
+                      size_t batch_padding)
+{
+   batch->start = bbo->bo.map;
+   batch->next = bbo->bo.map + bbo->length;
+   batch->end = bbo->bo.map + bbo->bo.size - batch_padding;
+   batch->relocs = &bbo->relocs;
+}
+
 static void
 anv_batch_bo_finish(struct anv_batch_bo *bbo, struct anv_batch *batch)
 {
@@ -618,17 +628,74 @@ anv_cmd_buffer_end_batch_buffer(struct anv_cmd_buffer *cmd_buffer)
    struct anv_batch_bo *surface_bbo =
       anv_cmd_buffer_current_surface_bbo(cmd_buffer);
 
-   anv_batch_emit(&cmd_buffer->batch, GEN8_MI_BATCH_BUFFER_END);
+   if (cmd_buffer->level == VK_CMD_BUFFER_LEVEL_PRIMARY) {
+      anv_batch_emit(&cmd_buffer->batch, GEN8_MI_BATCH_BUFFER_END);
 
-   /* Round batch up to an even number of dwords. */
-   if ((cmd_buffer->batch.next - cmd_buffer->batch.start) & 4)
-      anv_batch_emit(&cmd_buffer->batch, GEN8_MI_NOOP);
+      /* Round batch up to an even number of dwords. */
+      if ((cmd_buffer->batch.next - cmd_buffer->batch.start) & 4)
+         anv_batch_emit(&cmd_buffer->batch, GEN8_MI_NOOP);
+   }
 
    anv_batch_bo_finish(batch_bo, &cmd_buffer->batch);
 
    surface_bbo->length = cmd_buffer->surface_next;
 }
 
+static inline VkResult
+anv_cmd_buffer_add_seen_bbos(struct anv_cmd_buffer *cmd_buffer,
+                             struct list_head *list)
+{
+   list_for_each_entry(struct anv_batch_bo, bbo, list, link) {
+      struct anv_batch_bo **bbo_ptr = anv_vector_add(&cmd_buffer->seen_bbos);
+      if (bbo_ptr == NULL)
+         return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
+
+      *bbo_ptr = bbo;
+   }
+
+   return VK_SUCCESS;
+}
+
+void
+anv_cmd_buffer_add_secondary(struct anv_cmd_buffer *primary,
+                             struct anv_cmd_buffer *secondary)
+{
+   if ((secondary->batch_bos.next == secondary->batch_bos.prev) &&
+       anv_cmd_buffer_current_batch_bo(secondary)->length < ANV_CMD_BUFFER_BATCH_SIZE / 2) {
+      /* If the secondary has exactly one batch buffer in its list *and*
+       * that batch buffer is less than half of the maximum size, we're
+       * probably better of simply copying it into our batch.
+       */
+      anv_batch_emit_batch(&primary->batch, &secondary->batch);
+   } else {
+      struct list_head copy_list;
+      VkResult result = anv_batch_bo_list_clone(&secondary->batch_bos,
+                                                secondary->device,
+                                                &copy_list);
+      if (result != VK_SUCCESS)
+         return; /* FIXME */
+
+      anv_cmd_buffer_add_seen_bbos(primary, &copy_list);
+
+      struct anv_batch_bo *first_bbo =
+         list_first_entry(&copy_list, struct anv_batch_bo, link);
+      struct anv_batch_bo *last_bbo =
+         list_last_entry(&copy_list, struct anv_batch_bo, link);
+
+      cmd_buffer_chain_to_batch_bo(primary, first_bbo);
+
+      list_splicetail(&copy_list, &primary->batch_bos);
+
+      anv_batch_bo_continue(last_bbo, &primary->batch,
+                            GEN8_MI_BATCH_BUFFER_START_length * 4);
+
+      anv_cmd_buffer_emit_state_base_address(primary);
+   }
+
+   /* Mark the surface buffer from the secondary as seen */
+   anv_cmd_buffer_add_seen_bbos(primary, &secondary->surface_bos);
+}
+
 static VkResult
 anv_cmd_buffer_add_bo(struct anv_cmd_buffer *cmd_buffer,
                       struct anv_bo *bo,
index 62b3cda6cd7f42b0f3d53a71fdc0cc64270b521d..64acec82154946e7b77e287e412ac0286c78249d 100644 (file)
@@ -66,8 +66,6 @@ VkResult anv_CreateCommandBuffer(
    struct anv_cmd_buffer *cmd_buffer;
    VkResult result;
 
-   assert(pCreateInfo->level == VK_CMD_BUFFER_LEVEL_PRIMARY);
-
    cmd_buffer = anv_device_alloc(device, sizeof(*cmd_buffer), 8,
                                  VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
    if (cmd_buffer == NULL)
@@ -84,6 +82,9 @@ VkResult anv_CreateCommandBuffer(
    anv_state_stream_init(&cmd_buffer->dynamic_state_stream,
                          &device->dynamic_state_block_pool);
 
+   cmd_buffer->level = pCreateInfo->level;
+   cmd_buffer->opt_flags = 0;
+
    anv_cmd_state_init(&cmd_buffer->state);
 
    *pCmdBuffer = anv_cmd_buffer_to_handle(cmd_buffer);
@@ -210,6 +211,19 @@ VkResult anv_BeginCommandBuffer(
 {
    ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, cmdBuffer);
 
+   cmd_buffer->opt_flags = pBeginInfo->flags;
+
+   if (cmd_buffer->level == VK_CMD_BUFFER_LEVEL_SECONDARY) {
+      cmd_buffer->state.framebuffer =
+         anv_framebuffer_from_handle(pBeginInfo->framebuffer);
+      cmd_buffer->state.pass =
+         anv_render_pass_from_handle(pBeginInfo->renderPass);
+
+      /* FIXME: We shouldn't be starting on the first subpass */
+      anv_cmd_buffer_begin_subpass(cmd_buffer,
+                                   &cmd_buffer->state.pass->subpasses[0]);
+   }
+
    anv_cmd_buffer_emit_state_base_address(cmd_buffer);
    cmd_buffer->state.current_pipeline = UINT32_MAX;
 
@@ -224,13 +238,15 @@ VkResult anv_EndCommandBuffer(
 
    anv_cmd_buffer_end_batch_buffer(cmd_buffer);
 
-   /* The algorithm used to compute the validate list is not threadsafe as
-    * it uses the bo->index field.  We have to lock the device around it.
-    * Fortunately, the chances for contention here are probably very low.
-    */
-   pthread_mutex_lock(&device->mutex);
-   anv_cmd_buffer_prepare_execbuf(cmd_buffer);
-   pthread_mutex_unlock(&device->mutex);
+   if (cmd_buffer->level == VK_CMD_BUFFER_LEVEL_PRIMARY) {
+      /* The algorithm used to compute the validate list is not threadsafe as
+       * it uses the bo->index field.  We have to lock the device around it.
+       * Fortunately, the chances for contention here are probably very low.
+       */
+      pthread_mutex_lock(&device->mutex);
+      anv_cmd_buffer_prepare_execbuf(cmd_buffer);
+      pthread_mutex_unlock(&device->mutex);
+   }
 
    return VK_SUCCESS;
 }
@@ -1282,8 +1298,6 @@ void anv_CmdBeginRenderPass(
    ANV_FROM_HANDLE(anv_render_pass, pass, pRenderPassBegin->renderPass);
    ANV_FROM_HANDLE(anv_framebuffer, framebuffer, pRenderPassBegin->framebuffer);
 
-   assert(contents == VK_RENDER_PASS_CONTENTS_INLINE);
-
    cmd_buffer->state.framebuffer = framebuffer;
    cmd_buffer->state.pass = pass;
 
@@ -1311,7 +1325,7 @@ void anv_CmdNextSubpass(
 {
    ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, cmdBuffer);
 
-   assert(contents == VK_RENDER_PASS_CONTENTS_INLINE);
+   assert(cmd_buffer->level == VK_CMD_BUFFER_LEVEL_PRIMARY);
 
    anv_cmd_buffer_begin_subpass(cmd_buffer, cmd_buffer->state.subpass + 1);
 }
@@ -1341,5 +1355,17 @@ void anv_CmdExecuteCommands(
     uint32_t                                    cmdBuffersCount,
     const VkCmdBuffer*                          pCmdBuffers)
 {
-   stub();
+   ANV_FROM_HANDLE(anv_cmd_buffer, primary, cmdBuffer);
+
+   assert(primary->level == VK_CMD_BUFFER_LEVEL_PRIMARY);
+
+   anv_assert(primary->state.subpass == &primary->state.pass->subpasses[0]);
+
+   for (uint32_t i = 0; i < cmdBuffersCount; i++) {
+      ANV_FROM_HANDLE(anv_cmd_buffer, secondary, pCmdBuffers[i]);
+
+      assert(secondary->level == VK_CMD_BUFFER_LEVEL_SECONDARY);
+
+      anv_cmd_buffer_add_secondary(primary, secondary);
+   }
 }
index a12076f790d8fe0307ac584a148028b301ce9177..46e2d9b6d1bce75f630208e84a477ada89717579 100644 (file)
@@ -736,6 +736,8 @@ VkResult anv_QueueSubmit(
    for (uint32_t i = 0; i < cmdBufferCount; i++) {
       ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, pCmdBuffers[i]);
 
+      assert(cmd_buffer->level == VK_CMD_BUFFER_LEVEL_PRIMARY);
+
       if (device->dump_aub)
          anv_cmd_buffer_dump(cmd_buffer);
 
index 0437677de0aeb17bba0ba29e82db2cef35a40802..bece3bcec243a2e47dc29d713e8d57388febbc61 100644 (file)
@@ -736,6 +736,9 @@ struct anv_cmd_buffer {
    struct anv_state_stream                      surface_state_stream;
    struct anv_state_stream                      dynamic_state_stream;
 
+   VkCmdBufferOptimizeFlags                     opt_flags;
+   VkCmdBufferLevel                             level;
+
    struct anv_cmd_state                         state;
 };
 
@@ -743,6 +746,8 @@ VkResult anv_cmd_buffer_init_batch_bo_chain(struct anv_cmd_buffer *cmd_buffer);
 void anv_cmd_buffer_fini_batch_bo_chain(struct anv_cmd_buffer *cmd_buffer);
 void anv_cmd_buffer_reset_batch_bo_chain(struct anv_cmd_buffer *cmd_buffer);
 void anv_cmd_buffer_end_batch_buffer(struct anv_cmd_buffer *cmd_buffer);
+void anv_cmd_buffer_add_secondary(struct anv_cmd_buffer *primary,
+                                  struct anv_cmd_buffer *secondary);
 void anv_cmd_buffer_prepare_execbuf(struct anv_cmd_buffer *cmd_buffer);
 
 struct anv_bo *