xf86-video-intel: 4 commits - src/sna/fb src/sna/kgem.c src/sna/kgem.h
Chris Wilson
ickle at kemper.freedesktop.org
Wed Jul 18 01:43:32 PDT 2012
src/sna/fb/fbbitmap.c | 11 +
src/sna/fb/fbblt.c | 5
src/sna/fb/fbclip.c | 13 +
src/sna/fb/fbclip.h | 25 +--
src/sna/fb/fbfill.c | 30 +--
src/sna/fb/fbtile.c | 27 +--
src/sna/kgem.c | 387 +++++++++++++++++++++++++++++++++++++-------------
src/sna/kgem.h | 2
8 files changed, 342 insertions(+), 158 deletions(-)
New commits:
commit bee1a14618797b3d3a1c1a20eb72644fa907c048
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Wed Jul 18 09:38:32 2012 +0100
sna: Fix processing of the last fallback box
The evil typo caused us to misalign the clip boxes and run over a
garbage array on 64-bit builds.
Reported-by: Edward Sheldrake <ejsheldrake at gmail.com>
Reported-by: Clemens Eisserer <linuxhippy at gmail.com>
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=52163
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
diff --git a/src/sna/fb/fbclip.c b/src/sna/fb/fbclip.c
index 5a71b0c..37011a7 100644
--- a/src/sna/fb/fbclip.c
+++ b/src/sna/fb/fbclip.c
@@ -73,7 +73,7 @@ fbClipBoxes(const RegionRec *region, const BoxRec *box, const BoxRec **end)
return ®ion->extents;
}
- c0 = (const BoxRec *)region->data + 1;
+ c0 = (const BoxRec *)(region->data + 1);
c1 = c0 + region->data->numRects;
if (c0->y2 <= box->y1) {
commit 88cb1968b6dbf3edfa885da9503e91124af46007
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Wed Jul 18 09:38:03 2012 +0100
sna: Add more DBG for fallback processing
Hunting the lost box...
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
diff --git a/src/sna/fb/fbbitmap.c b/src/sna/fb/fbbitmap.c
index fa5d032..0758728 100644
--- a/src/sna/fb/fbbitmap.c
+++ b/src/sna/fb/fbbitmap.c
@@ -37,6 +37,11 @@ static inline void add(RegionPtr region,
r->x1 = x1; r->y1 = y1;
r->x2 = x2; r->y2 = y2;
+ DBG(("%s[%d/%d]: (%d, %d), (%d, %d)\n",
+ __FUNCTION__,
+ region->data->numRects, region->data->size,
+ x1, y1, x2, y2));
+
if (x1 < region->extents.x1)
region->extents.x1 = x1;
if (x2 > region->extents.x2)
@@ -138,5 +143,11 @@ fbBitmapToRegion(PixmapPtr pixmap)
} else
region->extents.x1 = region->extents.x2 = 0;
+ DBG(("%s: region extents=(%d, %d), (%d, %d) x %d\n",
+ __FUNCTION__,
+ region->extents.x1, region->extents.y1,
+ region->extents.x2, region->extents.y2,
+ RegionNumRects(region)));
+
return region;
}
diff --git a/src/sna/fb/fbblt.c b/src/sna/fb/fbblt.c
index fd55c85..3b3fa48 100644
--- a/src/sna/fb/fbblt.c
+++ b/src/sna/fb/fbblt.c
@@ -285,7 +285,10 @@ fbBlt(FbBits *srcLine, FbStride srcStride, int srcX,
s += srcX >> 3;
d += dstX >> 3;
- DBG(("%s fast blt\n", __FUNCTION__));
+ DBG(("%s fast blt, src_stride=%d, dst_stride=%d, width=%d (offset=%d)\n",
+ __FUNCTION__,
+ srcStride, dstStride, width,
+ srcLine - dstLine));
if ((srcLine < dstLine && srcLine + width > dstLine) ||
(dstLine < srcLine && dstLine + width > srcLine))
diff --git a/src/sna/fb/fbclip.c b/src/sna/fb/fbclip.c
index 8d9c4db..5a71b0c 100644
--- a/src/sna/fb/fbclip.c
+++ b/src/sna/fb/fbclip.c
@@ -76,11 +76,16 @@ fbClipBoxes(const RegionRec *region, const BoxRec *box, const BoxRec **end)
c0 = (const BoxRec *)region->data + 1;
c1 = c0 + region->data->numRects;
- if (c0->y2 <= box->y1)
+ if (c0->y2 <= box->y1) {
+ DBG(("%s: first clip (%d, %d), (%d, %d) before box (%d, %d), (%d, %d)\n",
+ __FUNCTION__,
+ c0->x1, c0->y1, c0->x2, c0->y2,
+ box->x1, box->y1, box->x2, box->y2));
c0 = find_clip_row_for_y(c0, c1, box->y1);
+ }
- DBG(("%s: c0=(%d, %d),(%d, %d)\n",
- __FUNCTION__, c0->x1, c0->y1, c0->x2, c0->y2));
+ DBG(("%s: c0=(%d, %d),(%d, %d) x %ld\n",
+ __FUNCTION__, c0->x1, c0->y1, c0->x2, c0->y2, c1 - c0));
*end = c1;
return c0;
diff --git a/src/sna/fb/fbclip.h b/src/sna/fb/fbclip.h
index feb2d2c..f07e63c 100644
--- a/src/sna/fb/fbclip.h
+++ b/src/sna/fb/fbclip.h
@@ -46,6 +46,13 @@ box_intersect(BoxPtr a, const BoxRec *b)
return a->x1 < a->x2 && a->y1 < a->y2;
}
+#define run_box(b, c) \
+ DBG(("%s: box=(%d, %d), (%d, %d), clip=(%d, %d), (%d, %d)\n", \
+ __FUNCTION__, (b)->x1, (b)->y1, (b)->x2, (b)->y2, (c)->x1, (c)->y1, (c)->x2, (c)->y2)); \
+ if ((b)->y2 <= (c)->y1) break; \
+ if ((b)->x1 >= (c)->x2) continue; \
+ if ((b)->x2 <= (c)->x1) { if ((b)->y2 <= (c)->y2) break; continue; }
+
static inline void
fbDrawableRun(DrawablePtr d, GCPtr gc, const BoxRec *box,
void (*func)(DrawablePtr, GCPtr, const BoxRec *b, void *data),
@@ -55,14 +62,7 @@ fbDrawableRun(DrawablePtr d, GCPtr gc, const BoxRec *box,
for (c = fbClipBoxes(gc->pCompositeClip, box, &end); c != end; c++) {
BoxRec b;
- if (box->x1 >= c->x2)
- continue;
- if (box->x2 <= c->x1) {
- if (box->y2 <= c->y2)
- break;
- else
- continue;
- }
+ run_box(box, c);
b = *box;
if (box_intersect(&b, c))
@@ -77,14 +77,7 @@ fbDrawableRunUnclipped(DrawablePtr d, GCPtr gc, const BoxRec *box,
{
const BoxRec *c, *end;
for (c = fbClipBoxes(gc->pCompositeClip, box, &end); c != end; c++) {
- if (box->x1 >= c->x2)
- continue;
- if (box->x2 <= c->x1) {
- if (box->y2 <= c->y2)
- break;
- else
- continue;
- }
+ run_box(box, c);
func(d, gc, c, data);
}
}
diff --git a/src/sna/fb/fbfill.c b/src/sna/fb/fbfill.c
index 3df1f9c..a9ae2bc 100644
--- a/src/sna/fb/fbfill.c
+++ b/src/sna/fb/fbfill.c
@@ -141,28 +141,14 @@ fbFill(DrawablePtr drawable, GCPtr gc, int x, int y, int width, int height)
case FillTiled:
{
- PixmapPtr pTile = gc->tile.pixmap;
- FbBits *tile;
- FbStride tileStride;
- int tileBpp;
- int tileWidth;
- int tileHeight;
- _X_UNUSED int tileXoff, tileYoff;
-
- fbGetDrawable(&pTile->drawable, tile,
- tileStride, tileBpp, tileXoff, tileYoff);
- tileWidth = pTile->drawable.width;
- tileHeight = pTile->drawable.height;
- fbTile(dst + (y + dstYoff) * dstStride,
- dstStride,
- (x + dstXoff) * dstBpp,
- width * dstBpp, height,
- tile,
- tileStride,
- tileWidth * tileBpp,
- tileHeight,
- gc->alu, pgc->pm,
- dstBpp,
+ PixmapPtr tile = gc->tile.pixmap;
+
+ fbTile(dst + (y + dstYoff) * dstStride, dstStride,
+ (x + dstXoff) * dstBpp, width * dstBpp, height,
+ tile->devPrivate.ptr, tile->devKind / sizeof(FbBits),
+ tile->drawable.width * tile->drawable.bitsPerPixel,
+ tile->drawable.height,
+ gc->alu, pgc->pm, dstBpp,
(gc->patOrg.x + drawable->x + dstXoff) * dstBpp,
gc->patOrg.y + drawable->y - y);
break;
diff --git a/src/sna/fb/fbtile.c b/src/sna/fb/fbtile.c
index 5586553..c350671 100644
--- a/src/sna/fb/fbtile.c
+++ b/src/sna/fb/fbtile.c
@@ -99,30 +99,29 @@ fbOddTile(FbBits *dst, FbStride dstStride, int dstX,
int xRot, int yRot)
{
int tileX, tileY;
- int widthTmp;
- int h, w;
int x, y;
+ DBG(("%s tile=%dx%d, size=%dx%d\n", __FUNCTION__,
+ tileWidth, tileHeight, width, height));
+
modulus(-yRot, tileHeight, tileY);
y = 0;
while (height) {
- h = tileHeight - tileY;
+ int ww = width;
+ int h = tileHeight - tileY;
if (h > height)
h = height;
height -= h;
- widthTmp = width;
x = dstX;
modulus(dstX - xRot, tileWidth, tileX);
- while (widthTmp) {
- w = tileWidth - tileX;
- if (w > widthTmp)
- w = widthTmp;
- widthTmp -= w;
- fbBlt(tile + tileY * tileStride,
- tileStride,
- tileX,
- dst + y * dstStride,
- dstStride, x, w, h, alu, pm, bpp, FALSE, FALSE);
+ while (ww) {
+ int w = tileWidth - tileX;
+ if (w > ww)
+ w = ww;
+ ww -= w;
+ fbBlt(tile + tileY * tileStride, tileStride, tileX,
+ dst + y * dstStride, dstStride,
+ x, w, h, alu, pm, bpp, FALSE, FALSE);
x += w;
tileX = 0;
}
commit 36f2e46619598e9bca4fe1207aa2f157bfa1ecf4
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Wed Jul 18 00:45:54 2012 +0100
sna: Reuse the snoopable cache more frequently for upload buffers
Now that we are keeping a small cache of snoopable buffers, experiment
with using them for uploads more frequently.
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
diff --git a/src/sna/kgem.c b/src/sna/kgem.c
index d9e27e2..6327e49 100644
--- a/src/sna/kgem.c
+++ b/src/sna/kgem.c
@@ -3950,15 +3950,122 @@ static struct kgem_partial_bo *partial_bo_alloc(int num_pages)
static inline bool
use_snoopable_buffer(struct kgem *kgem, uint32_t flags)
{
- assert(kgem->gen != 40);
-
- if ((flags & KGEM_BUFFER_WRITE_INPLACE) == KGEM_BUFFER_WRITE_INPLACE)
- return true;
-
if ((flags & KGEM_BUFFER_WRITE) == 0)
return kgem->gen >= 30;
- return false;
+ return true;
+}
+
+static struct kgem_partial_bo *
+search_snoopable_buffer(struct kgem *kgem, unsigned alloc)
+{
+ struct kgem_partial_bo *bo;
+ struct kgem_bo *old;
+
+ old = search_vmap_cache(kgem, alloc, 0);
+ if (old) {
+ bo = malloc(sizeof(*bo));
+ if (bo == NULL)
+ return NULL;
+
+ memcpy(&bo->base, old, sizeof(*old));
+ if (old->rq)
+ list_replace(&old->request, &bo->base.request);
+ else
+ list_init(&bo->base.request);
+ list_replace(&old->vma, &bo->base.vma);
+ list_init(&bo->base.list);
+ free(old);
+
+ DBG(("%s: created CPU handle=%d for buffer, size %d\n",
+ __FUNCTION__, bo->base.handle, num_pages(&bo->base)));
+
+ assert(bo->base.vmap);
+ assert(bo->base.tiling == I915_TILING_NONE);
+ assert(num_pages(&bo->base) >= alloc);
+
+ bo->mem = kgem_bo_map__cpu(kgem, &bo->base);
+ if (bo->mem) {
+ bo->mmapped = true;
+ bo->need_io = false;
+ bo->base.io = true;
+ bo->base.refcnt = 1;
+
+ return bo;
+ } else
+ kgem_bo_free(kgem, &bo->base);
+ }
+
+ return NULL;
+}
+
+static struct kgem_partial_bo *
+create_snoopable_buffer(struct kgem *kgem, unsigned alloc)
+{
+ struct kgem_partial_bo *bo;
+
+ if (kgem->has_cache_level) {
+ uint32_t handle;
+
+ handle = gem_create(kgem->fd, alloc);
+ if (handle == 0)
+ return NULL;
+
+ if (!gem_set_cache_level(kgem->fd, handle, I915_CACHE_LLC)) {
+ gem_close(kgem->fd, handle);
+ return NULL;
+ }
+
+ bo = malloc(sizeof(*bo));
+ if (bo == NULL) {
+ gem_close(kgem->fd, handle);
+ return NULL;
+ }
+
+ debug_alloc(kgem, alloc);
+ __kgem_bo_init(&bo->base, handle, alloc);
+ DBG(("%s: created CPU handle=%d for buffer, size %d\n",
+ __FUNCTION__, bo->base.handle, alloc));
+
+ bo->base.reusable = false;
+ bo->base.vmap = true;
+
+ bo->mem = kgem_bo_map__cpu(kgem, &bo->base);
+ if (bo->mem) {
+ bo->mmapped = true;
+ bo->need_io = false;
+ bo->base.io = true;
+ return bo;
+ } else {
+ bo->base.refcnt = 0; /* for valgrind */
+ kgem_bo_free(kgem, &bo->base);
+ }
+ }
+
+ if (kgem->has_vmap) {
+ bo = partial_bo_alloc(alloc);
+ if (bo) {
+ uint32_t handle = gem_vmap(kgem->fd, bo->mem,
+ alloc * PAGE_SIZE, false);
+ if (handle == 0 ||
+ !__kgem_bo_init(&bo->base, handle, alloc)) {
+ free(bo);
+ } else {
+ DBG(("%s: created vmap handle=%d for buffer\n",
+ __FUNCTION__, bo->base.handle));
+
+ bo->base.io = true;
+ bo->base.vmap = true;
+ bo->base.map = MAKE_VMAP_MAP(bo);
+ bo->mmapped = true;
+ bo->need_io = false;
+
+ return bo;
+ }
+ }
+ }
+
+ return NULL;
}
struct kgem_bo *kgem_create_buffer(struct kgem *kgem,
@@ -4199,105 +4306,23 @@ struct kgem_bo *kgem_create_buffer(struct kgem *kgem,
}
}
#endif
- /* Be more parsimonious with pwrite/pread buffers */
+ /* Be more parsimonious with pwrite/pread/cacheable buffers */
if ((flags & KGEM_BUFFER_INPLACE) == 0)
alloc = NUM_PAGES(size);
if (use_snoopable_buffer(kgem, flags)) {
- old = search_vmap_cache(kgem, NUM_PAGES(size), 0);
- if (old) {
- bo = malloc(sizeof(*bo));
- if (bo == NULL)
- return NULL;
-
- memcpy(&bo->base, old, sizeof(*old));
- if (old->rq)
- list_replace(&old->request, &bo->base.request);
- else
- list_init(&bo->base.request);
- list_replace(&old->vma, &bo->base.vma);
- list_init(&bo->base.list);
- free(old);
-
- assert(bo->base.vmap);
- assert(bo->base.tiling == I915_TILING_NONE);
- assert(num_pages(&bo->base) >= NUM_PAGES(size));
-
- bo->mem = kgem_bo_map__cpu(kgem, &bo->base);
- if (bo->mem) {
- bo->mmapped = true;
- bo->need_io = false;
- bo->base.io = true;
- bo->base.refcnt = 1;
-
- alloc = num_pages(&bo->base);
- goto init;
- } else {
- kgem_bo_free(kgem, &bo->base);
- bo = NULL;
- }
- }
-
- if (kgem->has_cache_level) {
- uint32_t handle;
-
- handle = gem_create(kgem->fd, alloc);
- if (handle == 0)
- return NULL;
-
- if (!gem_set_cache_level(kgem->fd, handle, I915_CACHE_LLC)) {
- gem_close(kgem->fd, handle);
- return NULL;
- }
-
- bo = malloc(sizeof(*bo));
- if (bo == NULL) {
- gem_close(kgem->fd, handle);
- return NULL;
- }
-
- debug_alloc(kgem, alloc);
- __kgem_bo_init(&bo->base, handle, alloc);
- DBG(("%s: created CPU handle=%d for buffer, size %d\n",
- __FUNCTION__, bo->base.handle, alloc));
-
- bo->base.reusable = false;
- bo->base.vmap = true;
-
- bo->mem = kgem_bo_map__cpu(kgem, &bo->base);
- if (bo->mem) {
- bo->mmapped = true;
- bo->need_io = false;
- bo->base.io = true;
- goto init;
- } else {
- bo->base.refcnt = 0; /* for valgrind */
- kgem_bo_free(kgem, &bo->base);
- bo = NULL;
- }
+ bo = search_snoopable_buffer(kgem, alloc);
+ if (bo) {
+ flags &= ~KGEM_BUFFER_INPLACE;
+ alloc = num_pages(&bo->base);
+ goto init;
}
- if (kgem->has_vmap) {
- bo = partial_bo_alloc(alloc);
+ if ((flags & KGEM_BUFFER_WRITE_INPLACE) != KGEM_BUFFER_WRITE_INPLACE) {
+ bo = create_snoopable_buffer(kgem, alloc);
if (bo) {
- uint32_t handle = gem_vmap(kgem->fd, bo->mem,
- alloc * PAGE_SIZE, false);
- if (handle == 0 ||
- !__kgem_bo_init(&bo->base, handle, alloc)) {
- free(bo);
- bo = NULL;
- } else {
- DBG(("%s: created vmap handle=%d for buffer\n",
- __FUNCTION__, bo->base.handle));
-
- bo->base.io = true;
- bo->base.vmap = true;
- bo->base.map = MAKE_VMAP_MAP(bo);
- bo->mmapped = true;
- bo->need_io = false;
-
- goto init;
- }
+ flags &= ~KGEM_BUFFER_INPLACE;
+ goto init;
}
}
}
@@ -4331,6 +4356,12 @@ struct kgem_bo *kgem_create_buffer(struct kgem *kgem,
bo->need_io = flags & KGEM_BUFFER_WRITE;
bo->base.io = true;
} else {
+ if (use_snoopable_buffer(kgem, flags)) {
+ bo = create_snoopable_buffer(kgem, alloc);
+ if (bo)
+ goto init;
+ }
+
bo = malloc(sizeof(*bo));
if (bo == NULL)
return NULL;
commit 73f07abbd2d78418e5a66262f293b5ed80b7ccb4
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Wed Jul 18 00:19:49 2012 +0100
sna: Maintain a short-lived cache of snoopable CPU bo for older gen
Once again, we find that frequent buffer creation and manipulation of the
GTT is a painful experience leading to noticeable and frequent application
stalls. So mitigate the need for fresh pages by keeping a small stash of
recently freed and inactive bo.
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
diff --git a/src/sna/kgem.c b/src/sna/kgem.c
index 4c6ca57..d9e27e2 100644
--- a/src/sna/kgem.c
+++ b/src/sna/kgem.c
@@ -53,6 +53,9 @@
static struct kgem_bo *
search_linear_cache(struct kgem *kgem, unsigned int num_pages, unsigned flags);
+static struct kgem_bo *
+search_vmap_cache(struct kgem *kgem, unsigned int num_pages, unsigned flags);
+
#define DBG_NO_HW 0
#define DBG_NO_TILING 0
#define DBG_NO_CACHE 0
@@ -810,6 +813,7 @@ void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, int gen)
list_init(&kgem->flushing);
list_init(&kgem->sync_list);
list_init(&kgem->large);
+ list_init(&kgem->vmap);
for (i = 0; i < ARRAY_SIZE(kgem->inactive); i++)
list_init(&kgem->inactive[i]);
for (i = 0; i < ARRAY_SIZE(kgem->active); i++) {
@@ -1212,6 +1216,9 @@ static void kgem_bo_free(struct kgem *kgem, struct kgem_bo *bo)
inline static void kgem_bo_move_to_inactive(struct kgem *kgem,
struct kgem_bo *bo)
{
+ DBG(("%s: moving %d from flush to inactive\n",
+ __FUNCTION__, bo->handle));
+
assert(bo->reusable);
assert(bo->rq == NULL);
assert(bo->domain != DOMAIN_GPU);
@@ -1295,6 +1302,73 @@ static void _kgem_bo_delete_partial(struct kgem *kgem, struct kgem_bo *bo)
io->used = bo->delta;
}
+static void kgem_bo_move_to_vmap(struct kgem *kgem, struct kgem_bo *bo)
+{
+ if (num_pages(bo) > kgem->max_cpu_size >> 13) {
+ kgem_bo_free(kgem, bo);
+ return;
+ }
+
+ assert(bo->tiling == I915_TILING_NONE);
+ assert(bo->rq == NULL);
+ assert(!bo->io);
+
+ DBG(("%s: moving %d to vmap\n", __FUNCTION__, bo->handle));
+ list_add(&bo->list, &kgem->vmap);
+}
+
+static struct kgem_bo *
+search_vmap_cache(struct kgem *kgem, unsigned int num_pages, unsigned flags)
+{
+ struct kgem_bo *bo, *first = NULL;
+
+ DBG(("%s: num_pages=%d, flags=%x\n", __FUNCTION__, num_pages, flags));
+
+ if (list_is_empty(&kgem->vmap)) {
+ DBG(("%s: inactive and cache empty\n", __FUNCTION__));
+ if (!__kgem_throttle_retire(kgem, flags)) {
+ DBG(("%s: nothing retired\n", __FUNCTION__));
+ return NULL;
+ }
+ }
+
+ list_for_each_entry(bo, &kgem->vmap, list) {
+ assert(bo->refcnt == 0);
+ assert(bo->vmap);
+ assert(bo->tiling == I915_TILING_NONE);
+ assert(bo->rq == NULL);
+
+ if (num_pages > num_pages(bo))
+ continue;
+
+ if (num_pages(bo) > 2*num_pages) {
+ if (first == NULL)
+ first = bo;
+ continue;
+ }
+
+ list_del(&bo->list);
+ bo->pitch = 0;
+ bo->delta = 0;
+
+ DBG((" %s: found handle=%d (num_pages=%d) in vmap cache\n",
+ __FUNCTION__, bo->handle, num_pages(bo)));
+ return bo;
+ }
+
+ if (first) {
+ list_del(&first->list);
+ first->pitch = 0;
+ first->delta = 0;
+
+ DBG((" %s: found handle=%d (num_pages=%d) in vmap cache\n",
+ __FUNCTION__, first->handle, num_pages(first)));
+ return first;
+ }
+
+ return NULL;
+}
+
static void __kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo)
{
DBG(("%s: handle=%d\n", __FUNCTION__, bo->handle));
@@ -1309,22 +1383,6 @@ static void __kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo)
if (DBG_NO_CACHE)
goto destroy;
- if (bo->vmap) {
- assert(!bo->flush);
- DBG(("%s: handle=%d is vmapped, tracking until free\n",
- __FUNCTION__, bo->handle));
- if (bo->rq == NULL) {
- if (bo->needs_flush && kgem_busy(kgem, bo->handle)) {
- list_add(&bo->request, &kgem->flushing);
- bo->rq = &_kgem_static_request;
- } else
- kgem_bo_free(kgem, bo);
- } else {
- assert(!bo->sync);
- }
- return;
- }
-
if (bo->io) {
struct kgem_bo *base;
@@ -1344,6 +1402,21 @@ static void __kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo)
}
}
+ if (bo->vmap) {
+ assert(!bo->flush);
+ DBG(("%s: handle=%d is vmapped, tracking until free\n",
+ __FUNCTION__, bo->handle));
+ if (bo->rq == NULL) {
+ if (bo->needs_flush && kgem_busy(kgem, bo->handle)) {
+ list_add(&bo->request, &kgem->flushing);
+ bo->rq = &_kgem_static_request;
+ }
+ }
+ if (bo->rq == NULL)
+ kgem_bo_move_to_vmap(kgem, bo);
+ return;
+ }
+
if (!bo->reusable) {
DBG(("%s: handle=%d, not reusable\n",
__FUNCTION__, bo->handle));
@@ -1406,7 +1479,6 @@ static void __kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo)
__FUNCTION__, bo->handle));
}
- DBG(("%s: handle=%d -> inactive\n", __FUNCTION__, bo->handle));
kgem_bo_move_to_inactive(kgem, bo);
return;
@@ -1475,16 +1547,16 @@ static bool kgem_retire__flushing(struct kgem *kgem)
if (kgem_busy(kgem, bo->handle))
break;
- DBG(("%s: moving %d from flush to inactive\n",
- __FUNCTION__, bo->handle));
bo->needs_flush = false;
bo->domain = DOMAIN_NONE;
bo->rq = NULL;
list_del(&bo->request);
if (!bo->refcnt) {
- assert(bo->reusable);
- if (kgem_bo_set_purgeable(kgem, bo)) {
+ if (bo->vmap) {
+ kgem_bo_move_to_vmap(kgem, bo);
+ } else if (kgem_bo_set_purgeable(kgem, bo)) {
+ assert(bo->reusable);
kgem_bo_move_to_inactive(kgem, bo);
retired = true;
} else
@@ -1546,6 +1618,16 @@ static bool kgem_retire__requests(struct kgem *kgem)
if (bo->refcnt)
continue;
+ if (bo->vmap) {
+ if (bo->needs_flush) {
+ list_add(&bo->request, &kgem->flushing);
+ bo->rq = &_kgem_static_request;
+ } else {
+ kgem_bo_move_to_vmap(kgem, bo);
+ }
+ continue;
+ }
+
if (!bo->reusable) {
DBG(("%s: closing %d\n",
__FUNCTION__, bo->handle));
@@ -1555,8 +1637,6 @@ static bool kgem_retire__requests(struct kgem *kgem)
if (!bo->needs_flush) {
if (kgem_bo_set_purgeable(kgem, bo)) {
- DBG(("%s: moving %d to inactive\n",
- __FUNCTION__, bo->handle));
kgem_bo_move_to_inactive(kgem, bo);
retired = true;
} else {
@@ -2177,12 +2257,35 @@ bool kgem_expire_cache(struct kgem *kgem)
bool idle;
unsigned int i;
+ time(&now);
+
while (__kgem_freed_bo) {
bo = __kgem_freed_bo;
__kgem_freed_bo = *(struct kgem_bo **)bo;
free(bo);
}
+
+ expire = 0;
+ list_for_each_entry(bo, &kgem->vmap, list) {
+ if (bo->delta) {
+ expire = now - MAX_INACTIVE_TIME/2;
+ break;
+ }
+
+ bo->delta = now;
+ }
+ if (expire) {
+ while (!list_is_empty(&kgem->vmap)) {
+ bo = list_last_entry(&kgem->vmap, struct kgem_bo, list);
+
+ if (bo->delta > expire)
+ break;
+
+ kgem_bo_free(kgem, bo);
+ }
+ }
+
kgem_retire(kgem);
if (kgem->wedged)
kgem_cleanup(kgem);
@@ -2192,7 +2295,6 @@ bool kgem_expire_cache(struct kgem *kgem)
if (kgem->need_purge)
kgem_purge_cache(kgem);
- time(&now);
expire = 0;
idle = !kgem->need_retire;
@@ -2291,6 +2393,17 @@ void kgem_cleanup_cache(struct kgem *kgem)
struct kgem_bo, list));
}
+ while (!list_is_empty(&kgem->vmap))
+ kgem_bo_free(kgem,
+ list_last_entry(&kgem->vmap,
+ struct kgem_bo, list));
+
+ while (__kgem_freed_bo) {
+ struct kgem_bo *bo = __kgem_freed_bo;
+ __kgem_freed_bo = *(struct kgem_bo **)bo;
+ free(bo);
+ }
+
kgem->need_purge = false;
kgem->need_expire = false;
}
@@ -2743,9 +2856,6 @@ struct kgem_bo *kgem_create_2d(struct kgem *kgem,
size /= PAGE_SIZE;
bucket = cache_bucket(size);
- if (flags & CREATE_FORCE)
- goto create;
-
if (bucket >= NUM_CACHE_BUCKETS) {
DBG(("%s: large bo num pages=%d, bucket=%d\n",
__FUNCTION__, size, bucket));
@@ -3101,6 +3211,7 @@ struct kgem_bo *kgem_create_cpu_2d(struct kgem *kgem,
uint32_t flags)
{
struct kgem_bo *bo;
+ int stride, size;
DBG(("%s(%dx%d, bpp=%d)\n", __FUNCTION__, width, height, bpp));
@@ -3120,9 +3231,26 @@ struct kgem_bo *kgem_create_cpu_2d(struct kgem *kgem,
return bo;
}
+ assert(width > 0 && height > 0);
+ stride = ALIGN(width, 2) * bpp >> 3;
+ stride = ALIGN(stride, 4);
+ size = stride * ALIGN(height, 2);
+ assert(size >= PAGE_SIZE);
+
+ DBG(("%s: %dx%d, %d bpp, stride=%d\n",
+ __FUNCTION__, width, height, bpp, stride));
+
+ bo = search_vmap_cache(kgem, NUM_PAGES(size), 0);
+ if (bo) {
+ assert(bo->tiling == I915_TILING_NONE);
+ assert(bo->vmap);
+ bo->refcnt = 1;
+ bo->pitch = stride;
+ return bo;
+ }
+
if (kgem->has_cache_level) {
- bo = kgem_create_2d(kgem, width, height, bpp,
- I915_TILING_NONE, flags | CREATE_FORCE);
+ bo = kgem_create_linear(kgem, size, flags);
if (bo == NULL)
return NULL;
@@ -3136,19 +3264,13 @@ struct kgem_bo *kgem_create_cpu_2d(struct kgem *kgem,
return NULL;
}
+ bo->pitch = stride;
return bo;
}
if (kgem->has_vmap) {
- int stride, size;
void *ptr;
- stride = ALIGN(width, 2) * bpp >> 3;
- stride = ALIGN(stride, 4);
- size = ALIGN(height, 2) * stride;
-
- assert(size >= PAGE_SIZE);
-
/* XXX */
//if (posix_memalign(&ptr, 64, ALIGN(size, 64)))
if (posix_memalign(&ptr, PAGE_SIZE, ALIGN(size, PAGE_SIZE)))
@@ -4082,6 +4204,40 @@ struct kgem_bo *kgem_create_buffer(struct kgem *kgem,
alloc = NUM_PAGES(size);
if (use_snoopable_buffer(kgem, flags)) {
+ old = search_vmap_cache(kgem, NUM_PAGES(size), 0);
+ if (old) {
+ bo = malloc(sizeof(*bo));
+ if (bo == NULL)
+ return NULL;
+
+ memcpy(&bo->base, old, sizeof(*old));
+ if (old->rq)
+ list_replace(&old->request, &bo->base.request);
+ else
+ list_init(&bo->base.request);
+ list_replace(&old->vma, &bo->base.vma);
+ list_init(&bo->base.list);
+ free(old);
+
+ assert(bo->base.vmap);
+ assert(bo->base.tiling == I915_TILING_NONE);
+ assert(num_pages(&bo->base) >= NUM_PAGES(size));
+
+ bo->mem = kgem_bo_map__cpu(kgem, &bo->base);
+ if (bo->mem) {
+ bo->mmapped = true;
+ bo->need_io = false;
+ bo->base.io = true;
+ bo->base.refcnt = 1;
+
+ alloc = num_pages(&bo->base);
+ goto init;
+ } else {
+ kgem_bo_free(kgem, &bo->base);
+ bo = NULL;
+ }
+ }
+
if (kgem->has_cache_level) {
uint32_t handle;
@@ -4102,8 +4258,8 @@ struct kgem_bo *kgem_create_buffer(struct kgem *kgem,
debug_alloc(kgem, alloc);
__kgem_bo_init(&bo->base, handle, alloc);
- DBG(("%s: created handle=%d for buffer\n",
- __FUNCTION__, bo->base.handle));
+ DBG(("%s: created CPU handle=%d for buffer, size %d\n",
+ __FUNCTION__, bo->base.handle, alloc));
bo->base.reusable = false;
bo->base.vmap = true;
diff --git a/src/sna/kgem.h b/src/sna/kgem.h
index 63be218..b8d755c 100644
--- a/src/sna/kgem.h
+++ b/src/sna/kgem.h
@@ -125,6 +125,7 @@ struct kgem {
struct list large;
struct list active[NUM_CACHE_BUCKETS][3];
struct list inactive[NUM_CACHE_BUCKETS];
+ struct list vmap;
struct list batch_partials, active_partials;
struct list requests;
struct list sync_list;
@@ -243,7 +244,6 @@ enum {
CREATE_TEMPORARY = 0x20,
CREATE_NO_RETIRE = 0x40,
CREATE_NO_THROTTLE = 0x40,
- CREATE_FORCE = 0x80,
};
struct kgem_bo *kgem_create_2d(struct kgem *kgem,
int width,
More information about the xorg-commit
mailing list