vk/cmd_buffer: Rework validate list creation

The algorighm we used previously required us to call add_bo in a particular
order in order to guarantee that we get the initial batch buffer as the
last element in the validate list.  The new algorighm does a recursive walk
over the buffers and then re-orders the list.  This should be much more
robust as we start to add circular dependancies in the relocations.
This commit is contained in:
Jason Ekstrand 2015-07-29 15:13:21 -07:00
parent 4fc7510a7c
commit 0f31c580bf

View file

@ -493,12 +493,16 @@ anv_cmd_buffer_add_bo(struct anv_cmd_buffer *cmd_buffer,
struct anv_bo *bo, struct anv_bo *bo,
struct anv_reloc_list *relocs) struct anv_reloc_list *relocs)
{ {
struct drm_i915_gem_exec_object2 *obj; struct drm_i915_gem_exec_object2 *obj = NULL;
if (bo->index < cmd_buffer->execbuf2.bo_count && if (bo->index < cmd_buffer->execbuf2.bo_count &&
cmd_buffer->execbuf2.bos[bo->index] == bo) cmd_buffer->execbuf2.bos[bo->index] == bo)
return VK_SUCCESS; obj = &cmd_buffer->execbuf2.objects[bo->index];
if (obj == NULL) {
/* We've never seen this one before. Add it to the list and assign
* an id that we can use later.
*/
if (cmd_buffer->execbuf2.bo_count >= cmd_buffer->execbuf2.array_length) { if (cmd_buffer->execbuf2.bo_count >= cmd_buffer->execbuf2.array_length) {
uint32_t new_len = cmd_buffer->execbuf2.objects ? uint32_t new_len = cmd_buffer->execbuf2.objects ?
cmd_buffer->execbuf2.array_length * 2 : 64; cmd_buffer->execbuf2.array_length * 2 : 64;
@ -543,23 +547,23 @@ anv_cmd_buffer_add_bo(struct anv_cmd_buffer *cmd_buffer,
obj->flags = 0; obj->flags = 0;
obj->rsvd1 = 0; obj->rsvd1 = 0;
obj->rsvd2 = 0; obj->rsvd2 = 0;
}
if (relocs) { if (relocs != NULL && obj->relocation_count == 0) {
/* This is the first time we've ever seen a list of relocations for
* this BO. Go ahead and set the relocations and then walk the list
* of relocations and add them all.
*/
obj->relocation_count = relocs->num_relocs; obj->relocation_count = relocs->num_relocs;
obj->relocs_ptr = (uintptr_t) relocs->relocs; obj->relocs_ptr = (uintptr_t) relocs->relocs;
for (size_t i = 0; i < relocs->num_relocs; i++)
anv_cmd_buffer_add_bo(cmd_buffer, relocs->reloc_bos[i], NULL);
} }
return VK_SUCCESS; return VK_SUCCESS;
} }
static void
anv_cmd_buffer_add_validate_bos(struct anv_cmd_buffer *cmd_buffer,
struct anv_reloc_list *list)
{
for (size_t i = 0; i < list->num_relocs; i++)
anv_cmd_buffer_add_bo(cmd_buffer, list->reloc_bos[i], NULL);
}
static void static void
anv_cmd_buffer_process_relocs(struct anv_cmd_buffer *cmd_buffer, anv_cmd_buffer_process_relocs(struct anv_cmd_buffer *cmd_buffer,
struct anv_reloc_list *list) struct anv_reloc_list *list)
@ -591,25 +595,53 @@ anv_cmd_buffer_prepare_execbuf(struct anv_cmd_buffer *cmd_buffer)
cmd_buffer->execbuf2.bo_count = 0; cmd_buffer->execbuf2.bo_count = 0;
cmd_buffer->execbuf2.need_reloc = false; cmd_buffer->execbuf2.need_reloc = false;
/* Add surface state bos first so we can add them with their relocs. */ list_for_each_entry(struct anv_batch_bo, bbo,
&cmd_buffer->batch_bos, link) {
anv_cmd_buffer_add_bo(cmd_buffer, &bbo->bo, &bbo->relocs);
}
list_for_each_entry(struct anv_batch_bo, bbo, list_for_each_entry(struct anv_batch_bo, bbo,
&cmd_buffer->surface_bos, link) { &cmd_buffer->surface_bos, link) {
anv_cmd_buffer_add_bo(cmd_buffer, &bbo->bo, &bbo->relocs); anv_cmd_buffer_add_bo(cmd_buffer, &bbo->bo, &bbo->relocs);
anv_cmd_buffer_add_validate_bos(cmd_buffer, &bbo->relocs);
anv_cmd_buffer_process_relocs(cmd_buffer, &bbo->relocs);
} }
/* Walk the list of batch buffers backwards and add each one. There are struct anv_batch_bo *first_batch_bo =
* two reasons for walking backwards. First, it guarantees that we add list_first_entry(&cmd_buffer->batch_bos, struct anv_batch_bo, link);
* a given batch bo before we process the relocation pointing to it from
* the MI_BATCH_BUFFER_START command. Second, thed kernel requires that /* The kernel requires that the last entry in the validation list be the
* the last bo on the list is the batch buffer to execute and walking * batch buffer to execute. We can simply swap the element
* backwards gives us this for free. * corresponding to the first batch_bo in the chain with the last
* element in the list.
*/ */
if (first_batch_bo->bo.index != cmd_buffer->execbuf2.bo_count - 1) {
uint32_t idx = first_batch_bo->bo.index;
struct drm_i915_gem_exec_object2 tmp_obj =
cmd_buffer->execbuf2.objects[idx];
assert(cmd_buffer->execbuf2.bos[idx] == &first_batch_bo->bo);
cmd_buffer->execbuf2.objects[idx] =
cmd_buffer->execbuf2.objects[cmd_buffer->execbuf2.bo_count - 1];
cmd_buffer->execbuf2.bos[idx] =
cmd_buffer->execbuf2.bos[cmd_buffer->execbuf2.bo_count - 1];
cmd_buffer->execbuf2.bos[idx]->index = idx;
cmd_buffer->execbuf2.objects[cmd_buffer->execbuf2.bo_count - 1] = tmp_obj;
cmd_buffer->execbuf2.bos[cmd_buffer->execbuf2.bo_count - 1] =
&first_batch_bo->bo;
first_batch_bo->bo.index = cmd_buffer->execbuf2.bo_count - 1;
}
/* Now we go through and fixup all of the relocation lists to point to
* the correct indices in the object array. We have to do this after we
* reorder the list above as some of the indices may have changed.
*/
list_for_each_entry(struct anv_batch_bo, bbo,
&cmd_buffer->surface_bos, link) {
anv_cmd_buffer_process_relocs(cmd_buffer, &bbo->relocs);
}
list_for_each_entry_rev(struct anv_batch_bo, bbo, list_for_each_entry_rev(struct anv_batch_bo, bbo,
&cmd_buffer->batch_bos, link) { &cmd_buffer->batch_bos, link) {
anv_cmd_buffer_add_validate_bos(cmd_buffer, &bbo->relocs);
anv_cmd_buffer_add_bo(cmd_buffer, &bbo->bo, &bbo->relocs);
anv_cmd_buffer_process_relocs(cmd_buffer, &bbo->relocs); anv_cmd_buffer_process_relocs(cmd_buffer, &bbo->relocs);
} }