drm/i915: Rework execbuffer pinning

Avoid evicting buffers that will be used later in the batch in order to
make room for the initial buffers by pinning all bound buffers in a
single pass before binding (and evicting for) fresh buffer.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
Chris Wilson 2010-11-12 13:49:09 +00:00
parent 919926aeb3
commit a7a09aebe8
1 changed files with 58 additions and 23 deletions

View File

@ -3531,44 +3531,75 @@ i915_gem_execbuffer_reserve(struct drm_device *dev,
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
int ret, i, retry; int ret, i, retry;
/* 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:
*
* 1a. Unbind all objects that do not match the GTT constraints for
* the execbuffer (fenceable, mappable, alignment etc).
* 1b. Increment pin count for already bound objects.
* 2. Bind new objects.
* 3. Decrement pin count.
*
* This avoid unnecessary unbinding of later objects in order to makr
* room for the earlier objects *unless* we need to defragment.
*/
retry = 0; retry = 0;
do { do {
ret = 0; ret = 0;
/* Unbind any ill-fitting objects or pin. */
for (i = 0; i < count; i++) {
struct drm_i915_gem_object *obj = object_list[i];
struct drm_i915_gem_exec_object2 *entry = &exec_list[i];
bool need_fence, need_mappable;
if (!obj->gtt_space)
continue;
need_fence =
entry->flags & EXEC_OBJECT_NEEDS_FENCE &&
obj->tiling_mode != I915_TILING_NONE;
need_mappable =
entry->relocation_count ? true : need_fence;
if ((entry->alignment && obj->gtt_offset & (entry->alignment - 1)) ||
(need_mappable && !obj->map_and_fenceable))
ret = i915_gem_object_unbind(obj);
else
ret = i915_gem_object_pin(obj,
entry->alignment,
need_mappable);
if (ret) {
count = i;
goto err;
}
}
/* Bind fresh objects */
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
struct drm_i915_gem_exec_object2 *entry = &exec_list[i]; struct drm_i915_gem_exec_object2 *entry = &exec_list[i];
struct drm_i915_gem_object *obj = object_list[i]; struct drm_i915_gem_object *obj = object_list[i];
bool need_fence = bool need_fence;
need_fence =
entry->flags & EXEC_OBJECT_NEEDS_FENCE && entry->flags & EXEC_OBJECT_NEEDS_FENCE &&
obj->tiling_mode != I915_TILING_NONE; obj->tiling_mode != I915_TILING_NONE;
/* g33/pnv can't fence buffers in the unmappable part */ if (!obj->gtt_space) {
bool need_mappable = bool need_mappable =
entry->relocation_count ? true : need_fence; entry->relocation_count ? true : need_fence;
/* Check fence reg constraints and rebind if necessary */
if (need_mappable && !obj->map_and_fenceable) {
ret = i915_gem_object_unbind(obj);
if (ret)
break;
}
ret = i915_gem_object_pin(obj, ret = i915_gem_object_pin(obj,
entry->alignment, entry->alignment,
need_mappable); need_mappable);
if (ret) if (ret)
break; break;
}
/*
* Pre-965 chips need a fence register set up in order
* to properly handle blits to/from tiled surfaces.
*/
if (need_fence) { if (need_fence) {
ret = i915_gem_object_get_fence_reg(obj, true); ret = i915_gem_object_get_fence_reg(obj, true);
if (ret) { if (ret)
i915_gem_object_unpin(obj);
break; break;
}
dev_priv->fence_regs[obj->fence_reg].gpu = true; dev_priv->fence_regs[obj->fence_reg].gpu = true;
} }
@ -3576,8 +3607,12 @@ i915_gem_execbuffer_reserve(struct drm_device *dev,
entry->offset = obj->gtt_offset; entry->offset = obj->gtt_offset;
} }
while (i--) err: /* Decrement pin count for bound objects */
i915_gem_object_unpin(object_list[i]); for (i = 0; i < count; i++) {
struct drm_i915_gem_object *obj = object_list[i];
if (obj->gtt_space)
i915_gem_object_unpin(obj);
}
if (ret != -ENOSPC || retry > 1) if (ret != -ENOSPC || retry > 1)
return ret; return ret;