summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2008-05-20 10:48:36 -0700
committerEric Anholt <eric@anholt.net>2008-05-20 10:52:39 -0700
commit6c3ac484b049681f9f3e692f9a6238ed122a8191 (patch)
tree5cbe0ca9b9bc234ef7a0fa503d312ff5d0d6fad6
parent7dced2f33a952ad12aafb7a3e34747156020a3ae (diff)
[gem] Clean up active/inactive list handling using helper functions.
Additionally, a boolean active field is added to indicate which list an object is on, rather than smashing last_rendering_cookie to 0 to show inactive. This will help with flush-reduction later on, and makes the code clearer.
-rw-r--r--linux-core/i915_gem.c80
-rw-r--r--shared-core/i915_drv.h18
2 files changed, 61 insertions, 37 deletions
diff --git a/linux-core/i915_gem.c b/linux-core/i915_gem.c
index 144667a3..1a97fdef 100644
--- a/linux-core/i915_gem.c
+++ b/linux-core/i915_gem.c
@@ -81,6 +81,42 @@ i915_gem_object_free_page_list(struct drm_gem_object *obj)
}
static void
+i915_gem_object_move_to_active(struct drm_gem_object *obj)
+{
+ struct drm_device *dev = obj->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_gem_object *obj_priv = obj->driver_private;
+
+ /* Add a reference if we're newly entering the active list. */
+ if (!obj_priv->active) {
+ drm_gem_object_reference(obj);
+ obj_priv->active = 1;
+ }
+ /* Move from whatever list we were on to the tail of execution. */
+ list_move_tail(&obj_priv->list,
+ &dev_priv->mm.active_list);
+}
+
+static void
+i915_gem_object_move_to_inactive(struct drm_gem_object *obj)
+{
+ struct drm_device *dev = obj->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_gem_object *obj_priv = obj->driver_private;
+
+ if (obj_priv->pin_count != 0)
+ list_del_init(&obj_priv->list);
+ else
+ list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
+
+ if (obj_priv->active) {
+ obj_priv->active = 0;
+ drm_gem_object_unreference(obj);
+ }
+}
+
+
+static void
i915_gem_flush(struct drm_device *dev,
uint32_t invalidate_domains,
uint32_t flush_domains)
@@ -156,7 +192,6 @@ static int
i915_gem_object_wait_rendering(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;
- drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv = obj->driver_private;
int ret;
@@ -171,13 +206,7 @@ i915_gem_object_wait_rendering(struct drm_gem_object *obj)
i915_gem_flush(dev, 0, obj->write_domain);
obj->write_domain = 0;
- /* Add a reference since we're gaining a cookie. */
- if (obj_priv->last_rendering_cookie == 0)
- drm_gem_object_reference(obj);
- /* Move from whatever list we were on to the tail of execution.
- */
- list_move_tail(&obj_priv->list,
- &dev_priv->mm.active_list);
+ i915_gem_object_move_to_active(obj);
obj_priv->last_rendering_cookie = i915_emit_irq(dev);
BUG_ON(obj_priv->last_rendering_cookie == 0);
#if WATCH_LRU
@@ -187,7 +216,7 @@ i915_gem_object_wait_rendering(struct drm_gem_object *obj)
/* If there is rendering queued on the buffer being evicted, wait for
* it.
*/
- if (obj_priv->last_rendering_cookie != 0) {
+ if (obj_priv->active) {
#if WATCH_BUF
DRM_INFO("%s: object %p wait for cookie %08x\n",
__func__, obj, obj_priv->last_rendering_cookie);
@@ -196,23 +225,11 @@ i915_gem_object_wait_rendering(struct drm_gem_object *obj)
if (ret != 0)
return ret;
- /* Clear it now that we know it's passed. */
- obj_priv->last_rendering_cookie = 0;
-
- /* We were on the execution list since we had a cookie.
- * Move to the tail of the LRU list now since we're done.
- */
- if (obj_priv->pin_count == 0)
- list_move_tail(&obj_priv->list,
- &dev_priv->mm.inactive_list);
+ i915_gem_object_move_to_inactive(obj);
#if WATCH_LRU
DRM_INFO("%s: wait moves to lru list %p\n", __func__, obj);
#endif
- /* The cookie held a reference to the object, release that
- * now
- */
- drm_gem_object_unreference(obj);
}
return 0;
@@ -253,10 +270,10 @@ i915_gem_object_unbind(struct drm_gem_object *obj)
/* Remove ourselves from the LRU list if present. */
if (!list_empty(&obj_priv->list)) {
list_del_init(&obj_priv->list);
- if (obj_priv->last_rendering_cookie) {
+ if (obj_priv->active) {
DRM_ERROR("Failed to wait on buffer when unbinding, "
"continued anyway.\n");
- obj_priv->last_rendering_cookie = 0;
+ obj_priv->active = 0;
drm_gem_object_unreference(obj);
}
}
@@ -862,7 +879,6 @@ int
i915_gem_execbuffer(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_execbuffer *args = data;
struct drm_i915_gem_exec_object *validate_list = NULL;
struct drm_gem_object **object_list = NULL;
@@ -980,21 +996,13 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
* wait on when trying to clear up gtt space).
*/
cookie = i915_emit_irq(dev);
+ BUG_ON(cookie == 0);
for (i = 0; i < args->buffer_count; i++) {
struct drm_gem_object *obj = object_list[i];
struct drm_i915_gem_object *obj_priv = obj->driver_private;
- /*
- * Have the cookie hold a reference to this object
- * which is freed when the object is waited for
- */
- if (obj_priv->last_rendering_cookie == 0)
- drm_gem_object_reference(obj);
+ i915_gem_object_move_to_active(obj);
obj_priv->last_rendering_cookie = cookie;
- BUG_ON(obj_priv->last_rendering_cookie == 0);
- /* Move our buffer to the tail of the execution list. */
- list_move_tail(&obj_priv->list,
- &dev_priv->mm.active_list);
#if WATCH_LRU
DRM_INFO("%s: move to exec list %p\n", __func__, obj);
#endif
@@ -1172,7 +1180,7 @@ i915_gem_lastclose(struct drm_device *dev)
list);
list_del_init(&obj_priv->list);
- obj_priv->last_rendering_cookie = 0;
+ obj_priv->active = 0;
obj_priv->obj->write_domain = 0;
drm_gem_object_unreference(obj_priv->obj);
}
diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h
index 296e1823..870726c5 100644
--- a/shared-core/i915_drv.h
+++ b/shared-core/i915_drv.h
@@ -247,9 +247,18 @@ typedef struct drm_i915_private {
/**
* List of objects currently involved in rendering from the
* ringbuffer.
+ *
+ * A reference is held on the buffer while on this list.
*/
struct list_head active_list;
- /** LRU List of non-executing objects still in the GTT. */
+ /**
+ * LRU List of non-executing objects still in the GTT.
+ * There may still be dirty cachelines that need to be flushed
+ * before unbind.
+ * A reference is not held on the buffer while on this list,
+ * as merely being GTT-bound shouldn't prevent its being
+ * freed, and we'll pull it off the list in the free path.
+ */
struct list_head inactive_list;
} mm;
} drm_i915_private_t;
@@ -271,6 +280,13 @@ struct drm_i915_gem_object {
/** This object's place on the active or inactive lists */
struct list_head list;
+ /**
+ * This is set if the object is on the active list
+ * (has pending rendering), and is not set if it's on inactive (ready
+ * to be unbound).
+ */
+ int active;
+
/** AGP memory structure for our GTT binding. */
DRM_AGP_MEM *agp_mem;