diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2011-01-10 12:35:37 -0500 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2011-01-11 17:55:48 -0500 |
commit | 6fe4f14044f181e146cdc15485428f95fa541ce8 (patch) | |
tree | c063724f6c4fc109a7af0c5f0799113e7527b2ae /drivers/gpu | |
parent | 809b63349ce6eb6603e7dab482c642f28135a2db (diff) |
drm/i915/execbuffer: Reorder binding of objects to favour restrictions
As the mappable portion of the aperture is always a small subset at the
start of the GTT, it is allocated preferentially by drm_mm. This is
useful in case we ever need to map an object later. However, if you have
a large object that can consume the entire mappable region of the
GTT this prevents the batchbuffer from fitting and so causing an error.
Instead allocate all those that require a mapping up front in order to
improve the likelihood of finding sufficient space to bind them.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_execbuffer.c | 72 |
2 files changed, 47 insertions, 26 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6130f77c26bf..385fc7ec39d3 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
@@ -796,6 +796,7 @@ struct drm_i915_gem_object { | |||
796 | */ | 796 | */ |
797 | struct hlist_node exec_node; | 797 | struct hlist_node exec_node; |
798 | unsigned long exec_handle; | 798 | unsigned long exec_handle; |
799 | struct drm_i915_gem_exec_object2 *exec_entry; | ||
799 | 800 | ||
800 | /** | 801 | /** |
801 | * Current offset of the object in GTT space. | 802 | * Current offset of the object in GTT space. |
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 0445770cc23c..e69834341ef0 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c | |||
@@ -268,7 +268,6 @@ eb_destroy(struct eb_objects *eb) | |||
268 | static int | 268 | static int |
269 | i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, | 269 | i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, |
270 | struct eb_objects *eb, | 270 | struct eb_objects *eb, |
271 | struct drm_i915_gem_exec_object2 *entry, | ||
272 | struct drm_i915_gem_relocation_entry *reloc) | 271 | struct drm_i915_gem_relocation_entry *reloc) |
273 | { | 272 | { |
274 | struct drm_device *dev = obj->base.dev; | 273 | struct drm_device *dev = obj->base.dev; |
@@ -411,10 +410,10 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, | |||
411 | 410 | ||
412 | static int | 411 | static int |
413 | i915_gem_execbuffer_relocate_object(struct drm_i915_gem_object *obj, | 412 | i915_gem_execbuffer_relocate_object(struct drm_i915_gem_object *obj, |
414 | struct eb_objects *eb, | 413 | struct eb_objects *eb) |
415 | struct drm_i915_gem_exec_object2 *entry) | ||
416 | { | 414 | { |
417 | struct drm_i915_gem_relocation_entry __user *user_relocs; | 415 | struct drm_i915_gem_relocation_entry __user *user_relocs; |
416 | struct drm_i915_gem_exec_object2 *entry = obj->exec_entry; | ||
418 | int i, ret; | 417 | int i, ret; |
419 | 418 | ||
420 | user_relocs = (void __user *)(uintptr_t)entry->relocs_ptr; | 419 | user_relocs = (void __user *)(uintptr_t)entry->relocs_ptr; |
@@ -426,7 +425,7 @@ i915_gem_execbuffer_relocate_object(struct drm_i915_gem_object *obj, | |||
426 | sizeof(reloc))) | 425 | sizeof(reloc))) |
427 | return -EFAULT; | 426 | return -EFAULT; |
428 | 427 | ||
429 | ret = i915_gem_execbuffer_relocate_entry(obj, eb, entry, &reloc); | 428 | ret = i915_gem_execbuffer_relocate_entry(obj, eb, &reloc); |
430 | if (ret) | 429 | if (ret) |
431 | return ret; | 430 | return ret; |
432 | 431 | ||
@@ -442,13 +441,13 @@ i915_gem_execbuffer_relocate_object(struct drm_i915_gem_object *obj, | |||
442 | static int | 441 | static int |
443 | i915_gem_execbuffer_relocate_object_slow(struct drm_i915_gem_object *obj, | 442 | i915_gem_execbuffer_relocate_object_slow(struct drm_i915_gem_object *obj, |
444 | struct eb_objects *eb, | 443 | struct eb_objects *eb, |
445 | struct drm_i915_gem_exec_object2 *entry, | ||
446 | struct drm_i915_gem_relocation_entry *relocs) | 444 | struct drm_i915_gem_relocation_entry *relocs) |
447 | { | 445 | { |
446 | const struct drm_i915_gem_exec_object2 *entry = obj->exec_entry; | ||
448 | int i, ret; | 447 | int i, ret; |
449 | 448 | ||
450 | for (i = 0; i < entry->relocation_count; i++) { | 449 | for (i = 0; i < entry->relocation_count; i++) { |
451 | ret = i915_gem_execbuffer_relocate_entry(obj, eb, entry, &relocs[i]); | 450 | ret = i915_gem_execbuffer_relocate_entry(obj, eb, &relocs[i]); |
452 | if (ret) | 451 | if (ret) |
453 | return ret; | 452 | return ret; |
454 | } | 453 | } |
@@ -459,8 +458,7 @@ i915_gem_execbuffer_relocate_object_slow(struct drm_i915_gem_object *obj, | |||
459 | static int | 458 | static int |
460 | i915_gem_execbuffer_relocate(struct drm_device *dev, | 459 | i915_gem_execbuffer_relocate(struct drm_device *dev, |
461 | struct eb_objects *eb, | 460 | struct eb_objects *eb, |
462 | struct list_head *objects, | 461 | struct list_head *objects) |
463 | struct drm_i915_gem_exec_object2 *exec) | ||
464 | { | 462 | { |
465 | struct drm_i915_gem_object *obj; | 463 | struct drm_i915_gem_object *obj; |
466 | int ret; | 464 | int ret; |
@@ -468,7 +466,7 @@ i915_gem_execbuffer_relocate(struct drm_device *dev, | |||
468 | list_for_each_entry(obj, objects, exec_list) { | 466 | list_for_each_entry(obj, objects, exec_list) { |
469 | obj->base.pending_read_domains = 0; | 467 | obj->base.pending_read_domains = 0; |
470 | obj->base.pending_write_domain = 0; | 468 | obj->base.pending_write_domain = 0; |
471 | ret = i915_gem_execbuffer_relocate_object(obj, eb, exec++); | 469 | ret = i915_gem_execbuffer_relocate_object(obj, eb); |
472 | if (ret) | 470 | if (ret) |
473 | return ret; | 471 | return ret; |
474 | } | 472 | } |
@@ -479,13 +477,36 @@ i915_gem_execbuffer_relocate(struct drm_device *dev, | |||
479 | static int | 477 | static int |
480 | i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, | 478 | i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, |
481 | struct drm_file *file, | 479 | struct drm_file *file, |
482 | struct list_head *objects, | 480 | struct list_head *objects) |
483 | struct drm_i915_gem_exec_object2 *exec) | ||
484 | { | 481 | { |
485 | struct drm_i915_gem_object *obj; | 482 | struct drm_i915_gem_object *obj; |
486 | struct drm_i915_gem_exec_object2 *entry; | ||
487 | int ret, retry; | 483 | int ret, retry; |
488 | bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4; | 484 | bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4; |
485 | struct list_head ordered_objects; | ||
486 | |||
487 | INIT_LIST_HEAD(&ordered_objects); | ||
488 | while (!list_empty(objects)) { | ||
489 | struct drm_i915_gem_exec_object2 *entry; | ||
490 | bool need_fence, need_mappable; | ||
491 | |||
492 | obj = list_first_entry(objects, | ||
493 | struct drm_i915_gem_object, | ||
494 | exec_list); | ||
495 | entry = obj->exec_entry; | ||
496 | |||
497 | need_fence = | ||
498 | has_fenced_gpu_access && | ||
499 | entry->flags & EXEC_OBJECT_NEEDS_FENCE && | ||
500 | obj->tiling_mode != I915_TILING_NONE; | ||
501 | need_mappable = | ||
502 | entry->relocation_count ? true : need_fence; | ||
503 | |||
504 | if (need_mappable) | ||
505 | list_move(&obj->exec_list, &ordered_objects); | ||
506 | else | ||
507 | list_move_tail(&obj->exec_list, &ordered_objects); | ||
508 | } | ||
509 | list_splice(&ordered_objects, objects); | ||
489 | 510 | ||
490 | /* Attempt to pin all of the buffers into the GTT. | 511 | /* Attempt to pin all of the buffers into the GTT. |
491 | * This is done in 3 phases: | 512 | * This is done in 3 phases: |
@@ -504,14 +525,11 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, | |||
504 | ret = 0; | 525 | ret = 0; |
505 | 526 | ||
506 | /* Unbind any ill-fitting objects or pin. */ | 527 | /* Unbind any ill-fitting objects or pin. */ |
507 | entry = exec; | ||
508 | list_for_each_entry(obj, objects, exec_list) { | 528 | list_for_each_entry(obj, objects, exec_list) { |
529 | struct drm_i915_gem_exec_object2 *entry = obj->exec_entry; | ||
509 | bool need_fence, need_mappable; | 530 | bool need_fence, need_mappable; |
510 | 531 | if (!obj->gtt_space) | |
511 | if (!obj->gtt_space) { | ||
512 | entry++; | ||
513 | continue; | 532 | continue; |
514 | } | ||
515 | 533 | ||
516 | need_fence = | 534 | need_fence = |
517 | has_fenced_gpu_access && | 535 | has_fenced_gpu_access && |
@@ -534,8 +552,8 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, | |||
534 | } | 552 | } |
535 | 553 | ||
536 | /* Bind fresh objects */ | 554 | /* Bind fresh objects */ |
537 | entry = exec; | ||
538 | list_for_each_entry(obj, objects, exec_list) { | 555 | list_for_each_entry(obj, objects, exec_list) { |
556 | struct drm_i915_gem_exec_object2 *entry = obj->exec_entry; | ||
539 | bool need_fence; | 557 | bool need_fence; |
540 | 558 | ||
541 | need_fence = | 559 | need_fence = |
@@ -570,7 +588,6 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, | |||
570 | } | 588 | } |
571 | 589 | ||
572 | entry->offset = obj->gtt_offset; | 590 | entry->offset = obj->gtt_offset; |
573 | entry++; | ||
574 | } | 591 | } |
575 | 592 | ||
576 | /* Decrement pin count for bound objects */ | 593 | /* Decrement pin count for bound objects */ |
@@ -680,10 +697,11 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, | |||
680 | 697 | ||
681 | list_add_tail(&obj->exec_list, objects); | 698 | list_add_tail(&obj->exec_list, objects); |
682 | obj->exec_handle = exec[i].handle; | 699 | obj->exec_handle = exec[i].handle; |
700 | obj->exec_entry = &exec[i]; | ||
683 | eb_add_object(eb, obj); | 701 | eb_add_object(eb, obj); |
684 | } | 702 | } |
685 | 703 | ||
686 | ret = i915_gem_execbuffer_reserve(ring, file, objects, exec); | 704 | ret = i915_gem_execbuffer_reserve(ring, file, objects); |
687 | if (ret) | 705 | if (ret) |
688 | goto err; | 706 | goto err; |
689 | 707 | ||
@@ -692,7 +710,6 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, | |||
692 | obj->base.pending_read_domains = 0; | 710 | obj->base.pending_read_domains = 0; |
693 | obj->base.pending_write_domain = 0; | 711 | obj->base.pending_write_domain = 0; |
694 | ret = i915_gem_execbuffer_relocate_object_slow(obj, eb, | 712 | ret = i915_gem_execbuffer_relocate_object_slow(obj, eb, |
695 | exec, | ||
696 | reloc + total); | 713 | reloc + total); |
697 | if (ret) | 714 | if (ret) |
698 | goto err; | 715 | goto err; |
@@ -1110,16 +1127,22 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, | |||
1110 | 1127 | ||
1111 | list_add_tail(&obj->exec_list, &objects); | 1128 | list_add_tail(&obj->exec_list, &objects); |
1112 | obj->exec_handle = exec[i].handle; | 1129 | obj->exec_handle = exec[i].handle; |
1130 | obj->exec_entry = &exec[i]; | ||
1113 | eb_add_object(eb, obj); | 1131 | eb_add_object(eb, obj); |
1114 | } | 1132 | } |
1115 | 1133 | ||
1134 | /* take note of the batch buffer before we might reorder the lists */ | ||
1135 | batch_obj = list_entry(objects.prev, | ||
1136 | struct drm_i915_gem_object, | ||
1137 | exec_list); | ||
1138 | |||
1116 | /* Move the objects en-masse into the GTT, evicting if necessary. */ | 1139 | /* Move the objects en-masse into the GTT, evicting if necessary. */ |
1117 | ret = i915_gem_execbuffer_reserve(ring, file, &objects, exec); | 1140 | ret = i915_gem_execbuffer_reserve(ring, file, &objects); |
1118 | if (ret) | 1141 | if (ret) |
1119 | goto err; | 1142 | goto err; |
1120 | 1143 | ||
1121 | /* The objects are in their final locations, apply the relocations. */ | 1144 | /* The objects are in their final locations, apply the relocations. */ |
1122 | ret = i915_gem_execbuffer_relocate(dev, eb, &objects, exec); | 1145 | ret = i915_gem_execbuffer_relocate(dev, eb, &objects); |
1123 | if (ret) { | 1146 | if (ret) { |
1124 | if (ret == -EFAULT) { | 1147 | if (ret == -EFAULT) { |
1125 | ret = i915_gem_execbuffer_relocate_slow(dev, file, ring, | 1148 | ret = i915_gem_execbuffer_relocate_slow(dev, file, ring, |
@@ -1133,9 +1156,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, | |||
1133 | } | 1156 | } |
1134 | 1157 | ||
1135 | /* Set the pending read domains for the batch buffer to COMMAND */ | 1158 | /* Set the pending read domains for the batch buffer to COMMAND */ |
1136 | batch_obj = list_entry(objects.prev, | ||
1137 | struct drm_i915_gem_object, | ||
1138 | exec_list); | ||
1139 | if (batch_obj->base.pending_write_domain) { | 1159 | if (batch_obj->base.pending_write_domain) { |
1140 | DRM_ERROR("Attempting to use self-modifying batch buffer\n"); | 1160 | DRM_ERROR("Attempting to use self-modifying batch buffer\n"); |
1141 | ret = -EINVAL; | 1161 | ret = -EINVAL; |