From: Dillon Amburgey <dillona@gmail.com>
To: Dave Airlie <airlied@redhat.com>, Gerd Hoffmann <kraxel@redhat.com>
Cc: Dillon Amburgey <dillona@gmail.com>,
dri-devel@lists.freedesktop.org, virtualization@lists.linux.dev,
spice-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
maarten.lankhorst@linux.intel.com, mripard@kernel.org,
tzimmermann@suse.de, airlied@gmail.com, simona@ffwll.ch,
christian.koenig@amd.com, krisman@collabora.co.uk,
noralf@tronnes.org
Subject: [PATCH v3 5/5] drm/qxl: pack dumb heads from their plane source rectangles
Date: Sat, 26 Sep 2026 12:31:23 -0400 [thread overview]
Message-ID: <20260926163123.39217-6-dillona@gmail.com> (raw)
In-Reply-To: <20260926163123.39217-1-dillona@gmail.com>
Packing a 1280x800 source from a 2048x1024 dumb framebuffer beside a
1024x768 head creates a 3072x1024 primary instead of 2304x800. Copying
the full framebuffer also paints pixels outside the visible source.
Size packed heads from their plane source rectangles and copy only those
rectangles to their packed origins. Publish the same origins without
adding the framebuffer source position a second time.
Intersect DirtyFB clips with every matching plane source and translate
each intersection to its packed origin. Apply both horizontal and
vertical offsets so separate framebuffers, shared framebuffers and
nonzero source coordinates use the same mapping for modesets and dirty
updates.
Fixes: 90adda2ce898 ("drm/qxl: cover all crtcs in shadow bo.")
Assisted-by: LLM sparse
Signed-off-by: Dillon Amburgey <dillona@gmail.com>
---
drivers/gpu/drm/qxl/qxl_display.c | 63 ++++++++++++++++++++++---------
drivers/gpu/drm/qxl/qxl_draw.c | 6 ++-
drivers/gpu/drm/qxl/qxl_drv.h | 2 +-
3 files changed, 51 insertions(+), 20 deletions(-)
diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
index af36d4d1ea57..1b12458ef7c9 100644
--- a/drivers/gpu/drm/qxl/qxl_display.c
+++ b/drivers/gpu/drm/qxl/qxl_display.c
@@ -369,8 +369,10 @@ static void qxl_crtc_update_monitors_config(struct drm_crtc *crtc,
head.y = crtc->y;
if (qdev->monitors_config->count < i + 1)
qdev->monitors_config->count = i + 1;
- if (to_qxl_plane_state(crtc->primary->state)->shadow)
- head.x += to_qxl_plane_state(crtc->primary->state)->x;
+ if (to_qxl_plane_state(crtc->primary->state)->shadow) {
+ head.x = to_qxl_plane_state(crtc->primary->state)->x;
+ head.y = 0;
+ }
} else {
head.width = 0;
head.height = 0;
@@ -484,23 +486,40 @@ static int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb,
drm_for_each_crtc(crtc, &qdev->ddev) {
struct drm_plane_state *st;
+ u32 sx, sy, sw, sh;
st = crtc->primary->state;
if (st->fb != fb || !crtc->state->active ||
!to_qxl_plane_state(st)->shadow ||
!to_qxl_plane_state(st)->shadow->is_primary)
continue;
+ sx = st->src_x >> 16;
+ sy = st->src_y >> 16;
+ sw = st->src_w >> 16;
+ sh = st->src_h >> 16;
for (n = 0; n < num_clips; n++) {
- struct drm_clip_rect c = clips[n * inc];
-
+ struct drm_clip_rect *in = clips + n * inc;
+ struct drm_clip_rect c;
+ u32 x1 = max_t(u32, in->x1, sx);
+ u32 y1 = max_t(u32, in->y1, sy);
+ u32 x2 = min_t(u32, in->x2, sx + sw);
+ u32 y2 = min_t(u32, in->y2, sy + sh);
+
+ if (x1 >= x2 || y1 >= y2)
+ continue;
+ c.x1 = x1;
+ c.y1 = y1;
+ c.x2 = x2;
+ c.y2 = y2;
qxl_draw_dirty_fb(qdev, fb, qobj, flags, color,
&c, 1, 1,
- to_qxl_plane_state(st)->x);
+ to_qxl_plane_state(st)->x - sx,
+ -(int)sy);
}
}
} else {
qxl_draw_dirty_fb(qdev, fb, qobj, flags, color,
- clips, num_clips, inc, 0);
+ clips, num_clips, inc, 0, 0);
}
out_lock_end:
@@ -741,12 +760,17 @@ static void qxl_primary_atomic_update(struct drm_plane *plane,
struct qxl_bo *bo = gem_to_qxl_bo(new_state->fb->obj[0]);
struct qxl_bo *primary;
struct drm_clip_rect norect = {
- .x1 = 0,
- .y1 = 0,
- .x2 = new_state->fb->width,
- .y2 = new_state->fb->height
+ .x1 = 0,
+ .y1 = 0,
+ .x2 = new_state->fb->width,
+ .y2 = new_state->fb->height,
};
uint32_t dumb_shadow_offset = 0;
+ int y_off = 0;
+ u32 src_x = new_state->src_x >> 16;
+ u32 src_y = new_state->src_y >> 16;
+ u32 src_w = new_state->src_w >> 16;
+ u32 src_h = new_state->src_h >> 16;
if (!qxl_primary_active(state, new_state)) {
qxl_primary_atomic_disable(plane, state);
@@ -762,11 +786,18 @@ static void qxl_primary_atomic_update(struct drm_plane *plane,
qxl_primary_apply_cursor(qdev, plane->state);
}
- if (bo->is_dumb)
- dumb_shadow_offset = to_qxl_plane_state(new_state)->x;
+ if (bo->is_dumb) {
+ norect.x1 = src_x;
+ norect.y1 = src_y;
+ norect.x2 = src_x + src_w;
+ norect.y2 = src_y + src_h;
+ dumb_shadow_offset =
+ to_qxl_plane_state(new_state)->x - src_x;
+ y_off = -(int)src_y;
+ }
qxl_draw_dirty_fb(qdev, new_state->fb, bo, 0, 0, &norect, 1, 1,
- dumb_shadow_offset);
+ dumb_shadow_offset, y_off);
}
static void qxl_cursor_atomic_update(struct drm_plane *plane,
@@ -838,7 +869,6 @@ static int qxl_prepare_shadow(struct drm_plane *plane,
drm_for_each_crtc(crtc, plane->dev) {
struct drm_plane_state *ps;
struct qxl_plane_state *other;
- struct qxl_bo *bo;
ps = drm_atomic_get_new_plane_state(state, crtc->primary);
if (!qxl_primary_active(state, ps) ||
@@ -847,9 +877,8 @@ static int qxl_prepare_shadow(struct drm_plane *plane,
other = to_qxl_plane_state(ps);
if (ps == new_state)
qps->x = surf.width;
- bo = gem_to_qxl_bo(ps->fb->obj[0]);
- surf.width += bo->surf.width;
- surf.height = max_t(u32, surf.height, bo->surf.height);
+ surf.width += ps->src_w >> 16;
+ surf.height = max_t(u32, surf.height, ps->src_h >> 16);
if (other->shadow)
shadow = other->shadow;
}
diff --git a/drivers/gpu/drm/qxl/qxl_draw.c b/drivers/gpu/drm/qxl/qxl_draw.c
index 3a3e127ce297..f99f4afa46d9 100644
--- a/drivers/gpu/drm/qxl/qxl_draw.c
+++ b/drivers/gpu/drm/qxl/qxl_draw.c
@@ -129,7 +129,7 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev,
unsigned int flags, unsigned int color,
struct drm_clip_rect *clips,
unsigned int num_clips, int inc,
- uint32_t dumb_shadow_offset)
+ u32 dumb_shadow_offset, int y_off)
{
/*
* TODO: if flags & DRM_MODE_FB_DIRTY_ANNOTATE_FILL then we should
@@ -160,6 +160,8 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev,
clips->x1 += dumb_shadow_offset;
clips->x2 += dumb_shadow_offset;
+ clips->y1 += y_off;
+ clips->y2 += y_off;
left = clips->x1;
right = clips->x2;
@@ -210,7 +212,7 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev,
ret = qxl_image_init(qdev, release, dimage, surface_base,
left - dumb_shadow_offset,
- top, width, height, depth, stride);
+ top - y_off, width, height, depth, stride);
qxl_bo_vunmap_locked(bo);
if (ret)
goto out_release_backoff;
diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h
index f29ce77eef7b..24137f934fa1 100644
--- a/drivers/gpu/drm/qxl/qxl_drv.h
+++ b/drivers/gpu/drm/qxl/qxl_drv.h
@@ -391,7 +391,7 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev,
unsigned int flags, unsigned int color,
struct drm_clip_rect *clips,
unsigned int num_clips, int inc,
- uint32_t dumb_shadow_offset);
+ u32 dumb_shadow_offset, int y_off);
void qxl_release_free(struct qxl_device *qdev,
struct qxl_release *release);
prev parent reply other threads:[~2026-09-26 16:31 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-26 16:31 [PATCH v3 0/5] drm/qxl: fix shared-primary lifetime and source packing Dillon Amburgey
2026-09-26 16:31 ` [PATCH v3 1/5] drm/qxl: unpin the framebuffer when plane preparation fails Dillon Amburgey
2026-09-26 16:31 ` [PATCH v3 2/5] drm/qxl: wait for pending commits before applying DirtyFB Dillon Amburgey
2026-09-26 16:31 ` [PATCH v3 3/5] drm/qxl: clear the monitor configuration for disabled head zero Dillon Amburgey
2026-09-26 16:31 ` [PATCH v3 4/5] drm/qxl: own packed primary shadows in atomic plane state Dillon Amburgey
2026-09-26 16:31 ` Dillon Amburgey [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260926163123.39217-6-dillona@gmail.com \
--to=dillona@gmail.com \
--cc=airlied@gmail.com \
--cc=airlied@redhat.com \
--cc=christian.koenig@amd.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=kraxel@redhat.com \
--cc=krisman@collabora.co.uk \
--cc=linux-kernel@vger.kernel.org \
--cc=maarten.lankhorst@linux.intel.com \
--cc=mripard@kernel.org \
--cc=noralf@tronnes.org \
--cc=simona@ffwll.ch \
--cc=spice-devel@lists.freedesktop.org \
--cc=tzimmermann@suse.de \
--cc=virtualization@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®