summaryrefslogtreecommitdiff
path: root/src/sna/kgem.c
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2013-09-29 11:19:46 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2013-09-29 11:22:37 +0100
commit0dd20381364aabede2e1306945abe21d57c1d7b4 (patch)
tree875be6db3c8860f33065e71d49f0fc2c1d7db145 /src/sna/kgem.c
parent902ce98df10c221e136c416f981c3a2730410415 (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.c47
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;