From: Angelo Compagnucci <angelo.compagnucci@gmail.com>
To: Thomas Zimmermann <tzimmermann@suse.de>,
Maarten Lankhorst <maarten.lankhorst@linux.intel.com>,
Maxime Ripard <mripard@kernel.org>,
dri-devel@lists.freedesktop.org
Cc: David Airlie <airlied@gmail.com>, Simona Vetter <simona@ffwll.ch>,
Javier Martinez Canillas <javierm@redhat.com>,
Angelo Compagnucci <angelo.compagnucci@gmail.com>
Subject: [PATCH v2] drm/fbdev-dma: Copy the shadow buffer on unblank
Date: Fri, 13 Nov 2026 12:07:08 +0100 [thread overview]
Message-ID: <20261113110708.927665-1-angelo.compagnucci@gmail.com> (raw)
In-Reply-To: <20261112091630.3947184-1-angelo.compagnucci@gmail.com>
With a shadow buffer, what userspace draws in fbdev reaches the
framebuffer memory only when the damage worker runs. Turning the display
on shows the framebuffer memory as it is. So a program that draws its
first picture and then unblanks, such as a boot splash, shows an older
picture for a moment.
Seen on an ILI9341 panel (tinydrm ili9341): enabling the pipe sends the
whole framebuffer memory to the panel, still black, and the splash only
replaces it once the damage worker runs.
Nothing can be flushed to a display that is off. But the copy from the
shadow buffer into the framebuffer memory does not need the display. On
unblank, copy the whole shadow buffer into the framebuffer memory before
turning the display on. The damage worker still flushes the damage once
the display is on.
Signed-off-by: Angelo Compagnucci <angelo.compagnucci@gmail.com>
---
Changes v1 -> v2:
- Do not flush the damage before unblanking: nothing can reach a
display that is off. Instead, in fbdev-dma, copy the whole shadow
buffer into the framebuffer memory on unblank, which needs no
display [Thomas Zimmermann]
- The fbdev helpers are unchanged, so the title changed too; v1 was
"drm/fb-helper: flush damage before unblanking"
drivers/gpu/drm/drm_fbdev_dma.c | 44 ++++++++++++++++++++++++++-------
1 file changed, 35 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/drm_fbdev_dma.c b/drivers/gpu/drm/drm_fbdev_dma.c
index 452f84400350..cc8813538bd9 100644
--- a/drivers/gpu/drm/drm_fbdev_dma.c
+++ b/drivers/gpu/drm/drm_fbdev_dma.c
@@ -93,15 +93,6 @@ static void drm_fbdev_dma_shadowed_fb_destroy(struct fb_info *info)
drm_client_release(&fb_helper->client);
}
-static const struct fb_ops drm_fbdev_dma_shadowed_fb_ops = {
- .owner = THIS_MODULE,
- .fb_open = drm_fbdev_dma_fb_open,
- .fb_release = drm_fbdev_dma_fb_release,
- FB_DEFAULT_DEFERRED_OPS(drm_fbdev_dma_shadowed),
- DRM_FB_HELPER_DEFAULT_OPS,
- .fb_destroy = drm_fbdev_dma_shadowed_fb_destroy,
-};
-
/*
* struct drm_fb_helper
*/
@@ -196,6 +187,41 @@ static const struct drm_fb_helper_funcs drm_fbdev_dma_helper_funcs = {
* struct drm_fb_helper
*/
+static int drm_fbdev_dma_shadowed_fb_blank(int blank, struct fb_info *info)
+{
+ struct drm_fb_helper *fb_helper = info->par;
+ struct drm_clip_rect clip = {
+ .x2 = fb_helper->fb->width,
+ .y2 = fb_helper->fb->height,
+ };
+
+ /*
+ * Turning the display on shows the framebuffer memory. Copy the
+ * shadow buffer into it first, so it holds what was drawn. This
+ * does not need the display; the damage worker still flushes the
+ * damage once the display is on.
+ */
+ if (blank == FB_BLANK_UNBLANK)
+ drm_fbdev_dma_damage_blit(fb_helper, &clip);
+
+ return drm_fb_helper_blank(blank, info);
+}
+
+static const struct fb_ops drm_fbdev_dma_shadowed_fb_ops = {
+ .owner = THIS_MODULE,
+ .fb_open = drm_fbdev_dma_fb_open,
+ .fb_release = drm_fbdev_dma_fb_release,
+ FB_DEFAULT_DEFERRED_OPS(drm_fbdev_dma_shadowed),
+ /* DRM_FB_HELPER_DEFAULT_OPS, with a blank that copies the shadow */
+ .fb_check_var = drm_fb_helper_check_var,
+ .fb_set_par = drm_fb_helper_set_par,
+ .fb_setcmap = drm_fb_helper_setcmap,
+ .fb_blank = drm_fbdev_dma_shadowed_fb_blank,
+ .fb_pan_display = drm_fb_helper_pan_display,
+ .fb_ioctl = drm_fb_helper_ioctl,
+ .fb_destroy = drm_fbdev_dma_shadowed_fb_destroy,
+};
+
static int drm_fbdev_dma_driver_fbdev_probe_tail(struct drm_fb_helper *fb_helper,
struct drm_fb_helper_surface_size *sizes)
{
--
2.53.0
prev parent reply other threads:[~2026-11-14 16:25 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-12 9:16 [PATCH] drm/fb-helper: flush damage before unblanking Angelo Compagnucci
2026-11-13 9:03 ` Thomas Zimmermann
2026-11-13 11:07 ` Angelo Compagnucci [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=20261113110708.927665-1-angelo.compagnucci@gmail.com \
--to=angelo.compagnucci@gmail.com \
--cc=airlied@gmail.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=javierm@redhat.com \
--cc=maarten.lankhorst@linux.intel.com \
--cc=mripard@kernel.org \
--cc=simona@ffwll.ch \
--cc=tzimmermann@suse.de \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.