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>
This commit is contained in:
parent
809b63349c
commit
6fe4f14044
@ -796,6 +796,7 @@ struct drm_i915_gem_object {
|
|||||||
*/
|
*/
|
||||||
struct hlist_node exec_node;
|
struct hlist_node exec_node;
|
||||||
unsigned long exec_handle;
|
unsigned long exec_handle;
|
||||||
|
struct drm_i915_gem_exec_object2 *exec_entry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Current offset of the object in GTT space.
|
* Current offset of the object in GTT space.
|
||||||
|
@ -268,7 +268,6 @@ eb_destroy(struct eb_objects *eb)
|
|||||||
static int
|
static int
|
||||||
i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
|
i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
|
||||||
struct eb_objects *eb,
|
struct eb_objects *eb,
|
||||||
struct drm_i915_gem_exec_object2 *entry,
|
|
||||||
struct drm_i915_gem_relocation_entry *reloc)
|
struct drm_i915_gem_relocation_entry *reloc)
|
||||||
{
|
{
|
||||||
struct drm_device *dev = obj->base.dev;
|
struct drm_device *dev = obj->base.dev;
|
||||||
@ -411,10 +410,10 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
i915_gem_execbuffer_relocate_object(struct drm_i915_gem_object *obj,
|
i915_gem_execbuffer_relocate_object(struct drm_i915_gem_object *obj,
|
||||||
struct eb_objects *eb,
|
struct eb_objects *eb)
|
||||||
struct drm_i915_gem_exec_object2 *entry)
|
|
||||||
{
|
{
|
||||||
struct drm_i915_gem_relocation_entry __user *user_relocs;
|
struct drm_i915_gem_relocation_entry __user *user_relocs;
|
||||||
|
struct drm_i915_gem_exec_object2 *entry = obj->exec_entry;
|
||||||
int i, ret;
|
int i, ret;
|
||||||
|
|
||||||
user_relocs = (void __user *)(uintptr_t)entry->relocs_ptr;
|
user_relocs = (void __user *)(uintptr_t)entry->relocs_ptr;
|
||||||
@ -426,7 +425,7 @@ i915_gem_execbuffer_relocate_object(struct drm_i915_gem_object *obj,
|
|||||||
sizeof(reloc)))
|
sizeof(reloc)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
ret = i915_gem_execbuffer_relocate_entry(obj, eb, entry, &reloc);
|
ret = i915_gem_execbuffer_relocate_entry(obj, eb, &reloc);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -442,13 +441,13 @@ i915_gem_execbuffer_relocate_object(struct drm_i915_gem_object *obj,
|
|||||||
static int
|
static int
|
||||||
i915_gem_execbuffer_relocate_object_slow(struct drm_i915_gem_object *obj,
|
i915_gem_execbuffer_relocate_object_slow(struct drm_i915_gem_object *obj,
|
||||||
struct eb_objects *eb,
|
struct eb_objects *eb,
|
||||||
struct drm_i915_gem_exec_object2 *entry,
|
|
||||||
struct drm_i915_gem_relocation_entry *relocs)
|
struct drm_i915_gem_relocation_entry *relocs)
|
||||||
{
|
{
|
||||||
|
const struct drm_i915_gem_exec_object2 *entry = obj->exec_entry;
|
||||||
int i, ret;
|
int i, ret;
|
||||||
|
|
||||||
for (i = 0; i < entry->relocation_count; i++) {
|
for (i = 0; i < entry->relocation_count; i++) {
|
||||||
ret = i915_gem_execbuffer_relocate_entry(obj, eb, entry, &relocs[i]);
|
ret = i915_gem_execbuffer_relocate_entry(obj, eb, &relocs[i]);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -459,8 +458,7 @@ i915_gem_execbuffer_relocate_object_slow(struct drm_i915_gem_object *obj,
|
|||||||
static int
|
static int
|
||||||
i915_gem_execbuffer_relocate(struct drm_device *dev,
|
i915_gem_execbuffer_relocate(struct drm_device *dev,
|
||||||
struct eb_objects *eb,
|
struct eb_objects *eb,
|
||||||
struct list_head *objects,
|
struct list_head *objects)
|
||||||
struct drm_i915_gem_exec_object2 *exec)
|
|
||||||
{
|
{
|
||||||
struct drm_i915_gem_object *obj;
|
struct drm_i915_gem_object *obj;
|
||||||
int ret;
|
int ret;
|
||||||
@ -468,7 +466,7 @@ i915_gem_execbuffer_relocate(struct drm_device *dev,
|
|||||||
list_for_each_entry(obj, objects, exec_list) {
|
list_for_each_entry(obj, objects, exec_list) {
|
||||||
obj->base.pending_read_domains = 0;
|
obj->base.pending_read_domains = 0;
|
||||||
obj->base.pending_write_domain = 0;
|
obj->base.pending_write_domain = 0;
|
||||||
ret = i915_gem_execbuffer_relocate_object(obj, eb, exec++);
|
ret = i915_gem_execbuffer_relocate_object(obj, eb);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -479,13 +477,36 @@ i915_gem_execbuffer_relocate(struct drm_device *dev,
|
|||||||
static int
|
static int
|
||||||
i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring,
|
i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring,
|
||||||
struct drm_file *file,
|
struct drm_file *file,
|
||||||
struct list_head *objects,
|
struct list_head *objects)
|
||||||
struct drm_i915_gem_exec_object2 *exec)
|
|
||||||
{
|
{
|
||||||
struct drm_i915_gem_object *obj;
|
struct drm_i915_gem_object *obj;
|
||||||
struct drm_i915_gem_exec_object2 *entry;
|
|
||||||
int ret, retry;
|
int ret, retry;
|
||||||
bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4;
|
bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4;
|
||||||
|
struct list_head ordered_objects;
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&ordered_objects);
|
||||||
|
while (!list_empty(objects)) {
|
||||||
|
struct drm_i915_gem_exec_object2 *entry;
|
||||||
|
bool need_fence, need_mappable;
|
||||||
|
|
||||||
|
obj = list_first_entry(objects,
|
||||||
|
struct drm_i915_gem_object,
|
||||||
|
exec_list);
|
||||||
|
entry = obj->exec_entry;
|
||||||
|
|
||||||
|
need_fence =
|
||||||
|
has_fenced_gpu_access &&
|
||||||
|
entry->flags & EXEC_OBJECT_NEEDS_FENCE &&
|
||||||
|
obj->tiling_mode != I915_TILING_NONE;
|
||||||
|
need_mappable =
|
||||||
|
entry->relocation_count ? true : need_fence;
|
||||||
|
|
||||||
|
if (need_mappable)
|
||||||
|
list_move(&obj->exec_list, &ordered_objects);
|
||||||
|
else
|
||||||
|
list_move_tail(&obj->exec_list, &ordered_objects);
|
||||||
|
}
|
||||||
|
list_splice(&ordered_objects, objects);
|
||||||
|
|
||||||
/* Attempt to pin all of the buffers into the GTT.
|
/* Attempt to pin all of the buffers into the GTT.
|
||||||
* This is done in 3 phases:
|
* This is done in 3 phases:
|
||||||
@ -504,14 +525,11 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring,
|
|||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
/* Unbind any ill-fitting objects or pin. */
|
/* Unbind any ill-fitting objects or pin. */
|
||||||
entry = exec;
|
|
||||||
list_for_each_entry(obj, objects, exec_list) {
|
list_for_each_entry(obj, objects, exec_list) {
|
||||||
|
struct drm_i915_gem_exec_object2 *entry = obj->exec_entry;
|
||||||
bool need_fence, need_mappable;
|
bool need_fence, need_mappable;
|
||||||
|
if (!obj->gtt_space)
|
||||||
if (!obj->gtt_space) {
|
|
||||||
entry++;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
need_fence =
|
need_fence =
|
||||||
has_fenced_gpu_access &&
|
has_fenced_gpu_access &&
|
||||||
@ -534,8 +552,8 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Bind fresh objects */
|
/* Bind fresh objects */
|
||||||
entry = exec;
|
|
||||||
list_for_each_entry(obj, objects, exec_list) {
|
list_for_each_entry(obj, objects, exec_list) {
|
||||||
|
struct drm_i915_gem_exec_object2 *entry = obj->exec_entry;
|
||||||
bool need_fence;
|
bool need_fence;
|
||||||
|
|
||||||
need_fence =
|
need_fence =
|
||||||
@ -570,7 +588,6 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring,
|
|||||||
}
|
}
|
||||||
|
|
||||||
entry->offset = obj->gtt_offset;
|
entry->offset = obj->gtt_offset;
|
||||||
entry++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Decrement pin count for bound objects */
|
/* Decrement pin count for bound objects */
|
||||||
@ -680,10 +697,11 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
|
|||||||
|
|
||||||
list_add_tail(&obj->exec_list, objects);
|
list_add_tail(&obj->exec_list, objects);
|
||||||
obj->exec_handle = exec[i].handle;
|
obj->exec_handle = exec[i].handle;
|
||||||
|
obj->exec_entry = &exec[i];
|
||||||
eb_add_object(eb, obj);
|
eb_add_object(eb, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = i915_gem_execbuffer_reserve(ring, file, objects, exec);
|
ret = i915_gem_execbuffer_reserve(ring, file, objects);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
@ -692,7 +710,6 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
|
|||||||
obj->base.pending_read_domains = 0;
|
obj->base.pending_read_domains = 0;
|
||||||
obj->base.pending_write_domain = 0;
|
obj->base.pending_write_domain = 0;
|
||||||
ret = i915_gem_execbuffer_relocate_object_slow(obj, eb,
|
ret = i915_gem_execbuffer_relocate_object_slow(obj, eb,
|
||||||
exec,
|
|
||||||
reloc + total);
|
reloc + total);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err;
|
goto err;
|
||||||
@ -1110,16 +1127,22 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
|
|||||||
|
|
||||||
list_add_tail(&obj->exec_list, &objects);
|
list_add_tail(&obj->exec_list, &objects);
|
||||||
obj->exec_handle = exec[i].handle;
|
obj->exec_handle = exec[i].handle;
|
||||||
|
obj->exec_entry = &exec[i];
|
||||||
eb_add_object(eb, obj);
|
eb_add_object(eb, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* take note of the batch buffer before we might reorder the lists */
|
||||||
|
batch_obj = list_entry(objects.prev,
|
||||||
|
struct drm_i915_gem_object,
|
||||||
|
exec_list);
|
||||||
|
|
||||||
/* Move the objects en-masse into the GTT, evicting if necessary. */
|
/* Move the objects en-masse into the GTT, evicting if necessary. */
|
||||||
ret = i915_gem_execbuffer_reserve(ring, file, &objects, exec);
|
ret = i915_gem_execbuffer_reserve(ring, file, &objects);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
/* The objects are in their final locations, apply the relocations. */
|
/* The objects are in their final locations, apply the relocations. */
|
||||||
ret = i915_gem_execbuffer_relocate(dev, eb, &objects, exec);
|
ret = i915_gem_execbuffer_relocate(dev, eb, &objects);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (ret == -EFAULT) {
|
if (ret == -EFAULT) {
|
||||||
ret = i915_gem_execbuffer_relocate_slow(dev, file, ring,
|
ret = i915_gem_execbuffer_relocate_slow(dev, file, ring,
|
||||||
@ -1133,9 +1156,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Set the pending read domains for the batch buffer to COMMAND */
|
/* Set the pending read domains for the batch buffer to COMMAND */
|
||||||
batch_obj = list_entry(objects.prev,
|
|
||||||
struct drm_i915_gem_object,
|
|
||||||
exec_list);
|
|
||||||
if (batch_obj->base.pending_write_domain) {
|
if (batch_obj->base.pending_write_domain) {
|
||||||
DRM_ERROR("Attempting to use self-modifying batch buffer\n");
|
DRM_ERROR("Attempting to use self-modifying batch buffer\n");
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user