vk: Add initial support for secondary command buffers

This commit is contained in:
Jason Ekstrand
2015-07-30 11:36:48 -07:00
parent 5aee803b97
commit 21004f23bf
4 changed files with 117 additions and 17 deletions

View 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,

View 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);
}
}

View 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);

View 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 *