diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2013-09-29 11:19:46 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2013-09-29 11:22:37 +0100 |
commit | 0dd20381364aabede2e1306945abe21d57c1d7b4 (patch) | |
tree | 875be6db3c8860f33065e71d49f0fc2c1d7db145 /src/sna/kgem.c | |
parent | 902ce98df10c221e136c416f981c3a2730410415 (diff) |
sna: Resize an existing framebuffer if possible
Sometimes we may have a compatible scanout cached, but of the wrong
size. Instead of throwing away the memory and creating a new scanout
from scratch, allow us to just resize the old scanout by destroying and
recreating its associated framebuffer.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'src/sna/kgem.c')
-rw-r--r-- | src/sna/kgem.c | 47 |
1 files changed, 45 insertions, 2 deletions
diff --git a/src/sna/kgem.c b/src/sna/kgem.c index 4bd12f6b..215d6076 100644 --- a/src/sna/kgem.c +++ b/src/sna/kgem.c @@ -3913,7 +3913,7 @@ struct kgem_bo *kgem_create_2d(struct kgem *kgem, bucket = cache_bucket(size); if (flags & CREATE_SCANOUT) { - struct kgem_bo *last = NULL; + struct kgem_bo *last = NULL, *first = NULL; list_for_each_entry_reverse(bo, &kgem->scanout, list) { assert(bo->scanout); @@ -3924,8 +3924,11 @@ struct kgem_bo *kgem_create_2d(struct kgem *kgem, if (size > num_pages(bo) || num_pages(bo) > 2*size) continue; - if (!check_scanout_size(kgem, bo, width, height)) + if (!check_scanout_size(kgem, bo, width, height)) { + if (first == NULL) + first = bo; continue; + } if (bo->tiling != tiling || (tiling != I915_TILING_NONE && bo->pitch != pitch)) { @@ -3965,6 +3968,46 @@ struct kgem_bo *kgem_create_2d(struct kgem *kgem, return last; } + if (first) { + ScrnInfoPtr scrn = + container_of(kgem, struct sna, kgem)->scrn; + + if (scrn->vtSema) { + DBG(("%s: recreate fb %dx%d@%d/%d\n", + __FUNCTION__, width, height, scrn->depth, scrn->bitsPerPixel)); + + if (bo->tiling != tiling || + (tiling != I915_TILING_NONE && bo->pitch != pitch)) { + if (gem_set_tiling(kgem->fd, bo->handle, + tiling, pitch)) { + bo->tiling = tiling; + bo->pitch = pitch; + } + } + + if (bo->tiling == tiling && bo->pitch == pitch) { + struct drm_mode_fb_cmd arg; + + VG_CLEAR(arg); + arg.width = width; + arg.height = height; + arg.pitch = bo->pitch; + arg.bpp = scrn->bitsPerPixel; + arg.depth = scrn->depth; + arg.handle = bo->handle; + + drmIoctl(kgem->fd, DRM_IOCTL_MODE_RMFB, &bo->delta); + if (drmIoctl(kgem->fd, DRM_IOCTL_MODE_ADDFB, &arg)) { + bo->scanout = false; + kgem_bo_free(kgem, bo); + } else { + bo->delta = arg.fb_id; + return bo; + } + } + } + } + bo = __kgem_bo_create_as_display(kgem, size, tiling, pitch); if (bo) return bo; |