[intel] Minor kludge -- wait for the ring to be nearly empty before queuing

No need to fill the ring that much; wait for it to become nearly empty
before adding the execbuffer request. A better fix will involve scheduling
ring insertion in the irq handler.
main
Keith Packard 2008-05-12 13:04:18 -07:00
parent 7e7ea313c4
commit 17e8000ac0
1 changed files with 49 additions and 18 deletions

View File

@ -463,9 +463,9 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
DRM_INFO("Binding object of size %d at 0x%08x\n", DRM_INFO("Binding object of size %d at 0x%08x\n",
obj->size, obj_priv->gtt_offset); obj->size, obj_priv->gtt_offset);
#endif #endif
ret = i915_gem_object_get_page_list (obj); ret = i915_gem_object_get_page_list(obj);
if (ret) { if (ret) {
drm_memrange_put_block (obj_priv->gtt_space); drm_memrange_put_block(obj_priv->gtt_space);
obj_priv->gtt_space = NULL; obj_priv->gtt_space = NULL;
return ret; return ret;
} }
@ -821,14 +821,43 @@ i915_dispatch_gem_execbuffer(struct drm_device *dev,
return 0; return 0;
} }
/*
* Kludge -- wait for almost all rendering to complete
* before queuing more. This uses interrupts, so the wakeup
* occurs without any delay.
*/
static int
i915_gem_wait_space(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
struct drm_i915_gem_object *obj_priv, *last_priv = NULL;
int ret = 0;
while (ring->space + 1024 < dev_priv->ring.Size &&
!list_empty(&dev_priv->mm.execution_list)) {
obj_priv = list_first_entry(&dev_priv->mm.execution_list,
struct drm_i915_gem_object,
gtt_lru_entry);
if (obj_priv == last_priv)
break;
ret = i915_gem_object_wait_rendering(obj_priv->obj);
if (ret)
break;
last_priv = obj_priv;
i915_kernel_lost_context(dev);
}
return ret;
}
int int
i915_gem_execbuffer(struct drm_device *dev, void *data, i915_gem_execbuffer(struct drm_device *dev, void *data,
struct drm_file *file_priv) struct drm_file *file_priv)
{ {
drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_execbuffer *args = data; struct drm_i915_gem_execbuffer *args = data;
struct drm_i915_gem_exec_object *validate_list; struct drm_i915_gem_exec_object *validate_list = NULL;
struct drm_gem_object **object_list; struct drm_gem_object **object_list = NULL;
struct drm_gem_object *batch_obj; struct drm_gem_object *batch_obj;
int ret, i; int ret, i;
uint64_t exec_offset; uint64_t exec_offset;
@ -842,6 +871,10 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
#endif #endif
i915_kernel_lost_context(dev); i915_kernel_lost_context(dev);
ret = i915_gem_wait_space(dev);
if (ret)
return ret;
/* Copy in the validate list from userland */ /* Copy in the validate list from userland */
validate_list = drm_calloc(sizeof(*validate_list), args->buffer_count, validate_list = drm_calloc(sizeof(*validate_list), args->buffer_count,
DRM_MEM_DRIVER); DRM_MEM_DRIVER);
@ -975,7 +1008,6 @@ err:
for (i = 0; i < args->buffer_count; i++) for (i = 0; i < args->buffer_count; i++)
drm_gem_object_unreference(object_list[i]); drm_gem_object_unreference(object_list[i]);
} }
drm_free(object_list, sizeof(*object_list) * args->buffer_count, drm_free(object_list, sizeof(*object_list) * args->buffer_count,
DRM_MEM_DRIVER); DRM_MEM_DRIVER);
drm_free(validate_list, sizeof(*validate_list) * args->buffer_count, drm_free(validate_list, sizeof(*validate_list) * args->buffer_count,
@ -1078,22 +1110,21 @@ i915_gem_flush_pwrite(struct drm_gem_object *obj,
{ {
struct drm_device *dev = obj->dev; struct drm_device *dev = obj->dev;
struct drm_i915_gem_object *obj_priv = obj->driver_private; struct drm_i915_gem_object *obj_priv = obj->driver_private;
/* /*
* As far as I can tell, writes of > 64 bytes will use non-temporal * For writes much less than the size of the object and
* stores which should obviate the need for this clflush. * which are already pinned in memory, do the flush right now
* It doesn't work for me though...
*/ */
/* if (size <= 64) */{
if (obj_priv->gtt_space == NULL) { if ((size < obj->size >> 1) && obj_priv->page_list != NULL) {
int ret = i915_gem_object_get_page_list (obj); unsigned long first_page = offset / PAGE_SIZE;
if (ret) unsigned long beyond_page = roundup(offset + size, PAGE_SIZE);
return ret;
} drm_ttm_cache_flush(obj_priv->page_list + first_page,
i915_gem_clflush_object(obj); beyond_page - first_page);
if (obj_priv->gtt_space == NULL)
i915_gem_object_free_page_list (obj);
}
drm_agp_chipset_flush(dev); drm_agp_chipset_flush(dev);
obj->write_domain = 0;
}
return 0; return 0;
} }