diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2011-12-09 15:12:03 +0000 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2011-12-09 17:14:38 +0000 |
commit | c22197f25bc0419d9f2abfcc978df5ef439feb47 (patch) | |
tree | 7d93bf2a9024f610e0e0ee66c5d8398e40ebd43a | |
parent | 429a36f7481b9bfd5ed137642d2916d69a713557 (diff) |
sna: Discard bo for idle private pixmaps
If a pixmap lies around for a couple of minutes not being used, it is
unlikely to be used again in the near future. Reap the GPU buffers of
any of those idle pixmaps (copying to a more compact buffer in system
memory) in order to free up resources for use elsewhere. Any object
that is exposed via DRI is obviously exempt from this reaping.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r-- | src/sna/sna.h | 4 | ||||
-rw-r--r-- | src/sna/sna_accel.c | 93 |
2 files changed, 92 insertions, 5 deletions
diff --git a/src/sna/sna.h b/src/sna/sna.h index c0ac8882..bd6c8a19 100644 --- a/src/sna/sna.h +++ b/src/sna/sna.h @@ -135,6 +135,7 @@ struct sna_pixmap { struct sna_damage *gpu_damage, *cpu_damage; struct list list; + struct list inactive; #define SOURCE_BIAS 4 uint16_t source_count; @@ -212,6 +213,7 @@ enum { enum { FLUSH_TIMER = 0, EXPIRE_TIMER, + INACTIVE_TIMER, NUM_TIMERS }; @@ -229,6 +231,8 @@ struct sna { struct list deferred_free; struct list dirty_pixmaps; + struct list active_pixmaps; + struct list inactive_clock[2]; PixmapPtr front, shadow; PixmapPtr freed_pixmap; diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c index e1905d1d..cffac538 100644 --- a/src/sna/sna_accel.c +++ b/src/sna/sna_accel.c @@ -171,6 +171,8 @@ static void sna_pixmap_destroy_gpu_bo(struct sna *sna, struct sna_pixmap *priv) priv->gpu_bo = NULL; } + list_del(&priv->inactive); + /* and reset the upload counter */ priv->source_count = SOURCE_BIAS; } @@ -180,6 +182,7 @@ static Bool sna_destroy_private(PixmapPtr pixmap, struct sna_pixmap *priv) struct sna *sna = to_sna_from_pixmap(pixmap); list_del(&priv->list); + list_del(&priv->inactive); sna_damage_destroy(&priv->gpu_damage); sna_damage_destroy(&priv->cpu_damage); @@ -301,6 +304,7 @@ static struct sna_pixmap *_sna_pixmap_attach(PixmapPtr pixmap) return NULL; list_init(&priv->list); + list_init(&priv->inactive); priv->pixmap = pixmap; sna_set_pixmap(pixmap, priv); @@ -386,6 +390,7 @@ sna_pixmap_create_scratch(ScreenPtr screen, priv = sna_pixmap(pixmap); memset(priv, 0, sizeof(*priv)); list_init(&priv->list); + list_init(&priv->inactive); priv->pixmap = pixmap; } else { pixmap = create_pixmap(sna, screen, 0, 0, depth, @@ -818,6 +823,8 @@ sna_pixmap_move_area_to_gpu(PixmapPtr pixmap, BoxPtr box) done: if (priv->cpu_damage == NULL) list_del(&priv->list); + if (!priv->gpu_only && !priv->pinned) + list_move(&priv->inactive, &sna->active_pixmaps); } static inline Bool @@ -993,6 +1000,7 @@ sna_pixmap_create_upload(ScreenPtr screen, priv->pinned = 0; priv->mapped = 0; list_init(&priv->list); + list_init(&priv->inactive); priv->pixmap = pixmap; sna_set_pixmap(pixmap, priv); @@ -1128,6 +1136,8 @@ done: sna_damage_reduce_all(&priv->gpu_damage, pixmap->drawable.width, pixmap->drawable.height); list_del(&priv->list); + if (!priv->gpu_only && !priv->pinned) + list_move(&priv->inactive, &sna->active_pixmaps); priv->gpu = true; return priv; } @@ -8477,6 +8487,28 @@ static Bool sna_accel_do_expire(struct sna *sna) return FALSE; } +static Bool sna_accel_do_inactive(struct sna *sna) +{ + struct itimerspec to; + + return_if_timer_active(INACTIVE_TIMER); + + if (list_is_empty(&sna->active_pixmaps)) + return FALSE; + + if (sna->timer[INACTIVE_TIMER] == -1) + return FALSE; + + /* Periodic expiration after every 60s. */ + to.it_interval.tv_sec = 60; + to.it_interval.tv_nsec = 0; + to.it_value = to.it_interval; + timerfd_settime(sna->timer[INACTIVE_TIMER], 0, &to, NULL); + + sna->timer_active |= 1 << INACTIVE_TIMER; + return FALSE; +} + static void sna_accel_create_timers(struct sna *sna) { int id; @@ -8494,6 +8526,7 @@ static void sna_accel_create_timers(struct sna *sna) } static Bool sna_accel_do_flush(struct sna *sna) { return sna_accel_scanout(sna) != NULL; } static Bool sna_accel_do_expire(struct sna *sna) { return sna->kgem.need_expire; } +static Bool sna_accel_do_inactive(struct sna *sna) { return FALSE; } static void sna_accel_drain_timer(struct sna *sna, int id) { } static void _sna_accel_disarm_timer(struct sna *sna, int id) { } #endif @@ -8526,13 +8559,57 @@ static void sna_accel_expire(struct sna *sna) _sna_accel_disarm_timer(sna, EXPIRE_TIMER); } +static void sna_accel_inactive(struct sna *sna) +{ + DBG(("%s (time=%ld)\n", __FUNCTION__, (long)GetTimeInMillis())); + + /* clear out the oldest inactive pixmaps */ + while (!list_is_empty(&sna->inactive_clock[1])) { + struct sna_pixmap *priv; + + priv = list_first_entry(&sna->inactive_clock[1], + struct sna_pixmap, + inactive); + if (priv->pinned) { + list_del(&priv->inactive); + } else { + DBG(("%s: discarding GPU bo handle=%d\n", + __FUNCTION__, priv->gpu_bo->handle)); + sna_pixmap_move_to_cpu(priv->pixmap, true); + } + + /* XXX Rather than discarding the GPU buffer here, we + * could mark it purgeable and allow the shrinker to + * reap its storage only under memory pressure. + */ + } + + /* Age the current inactive pixmaps */ + sna->inactive_clock[1].next = sna->inactive_clock[0].next; + sna->inactive_clock[0].next->prev = &sna->inactive_clock[1]; + sna->inactive_clock[0].prev->next = &sna->inactive_clock[1]; + sna->inactive_clock[1].prev = sna->inactive_clock[0].prev; + + sna->inactive_clock[0].next = sna->active_pixmaps.next; + sna->active_pixmaps.next->prev = &sna->inactive_clock[0]; + sna->active_pixmaps.prev->next = &sna->inactive_clock[0]; + sna->inactive_clock[0].prev = sna->active_pixmaps.prev; + + list_init(&sna->active_pixmaps); + + if (list_is_empty(&sna->inactive_clock[1]) && + list_is_empty(&sna->inactive_clock[0])) + _sna_accel_disarm_timer(sna, INACTIVE_TIMER); +} + static void sna_accel_install_timers(struct sna *sna) { - if (sna->timer[FLUSH_TIMER] != -1) - AddGeneralSocket(sna->timer[FLUSH_TIMER]); + int n; - if (sna->timer[EXPIRE_TIMER] != -1) - AddGeneralSocket(sna->timer[EXPIRE_TIMER]); + for (n = 0; n < NUM_TIMERS; n++) { + if (sna->timer[n] != -1) + AddGeneralSocket(sna->timer[n]); + } } Bool sna_accel_pre_init(struct sna *sna) @@ -8552,8 +8629,11 @@ Bool sna_accel_init(ScreenPtr screen, struct sna *sna) screen->RealizeFont = sna_realize_font; screen->UnrealizeFont = sna_unrealize_font; - list_init(&sna->dirty_pixmaps); list_init(&sna->deferred_free); + list_init(&sna->dirty_pixmaps); + list_init(&sna->active_pixmaps); + list_init(&sna->inactive_clock[0]); + list_init(&sna->inactive_clock[1]); AddGeneralSocket(sna->kgem.fd); sna_accel_install_timers(sna); @@ -8673,6 +8753,9 @@ void sna_accel_block_handler(struct sna *sna) if (sna_accel_do_expire(sna)) sna_accel_expire(sna); + + if (sna_accel_do_inactive(sna)) + sna_accel_inactive(sna); } void sna_accel_wakeup_handler(struct sna *sna) |