summaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
authorThomas Zimmermann <tzimmermann@suse.de>2022-03-13 20:29:52 +0100
committerDave Airlie <airlied@redhat.com>2022-03-25 09:55:54 +1000
commit2a81dba4b577099717cea86d429f053e85e74d96 (patch)
tree2ef8087a601aa83933d18a0a5347865ab31a51b1 /drivers/video
parent40faaf80c463b2c99a0351d28bd74d75d64ed017 (diff)
downloadlinux-2a81dba4b577099717cea86d429f053e85e74d96.tar.bz2
fbdev: Fix cfb_imageblit() for arbitrary image widths
Commit 0d03011894d2 ("fbdev: Improve performance of cfb_imageblit()") broke cfb_imageblit() for image widths that are not aligned to 8-bit boundaries. Fix this by handling the trailing pixels on each line separately. The performance improvements in the original commit do not regress by this change. Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de> Fixes: 0d03011894d2 ("fbdev: Improve performance of cfb_imageblit()") Reported-by: Marek Szyprowski <m.szyprowski@samsung.com> Cc: Thomas Zimmermann <tzimmermann@suse.de> Cc: Javier Martinez Canillas <javierm@redhat.com> Cc: Sam Ravnborg <sam@ravnborg.org> Tested-by: Marek Szyprowski <m.szyprowski@samsung.com> Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch> Reviewed-by: Javier Martinez Canillas <javierm@redhat.com> Tested-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Dave Airlie <airlied@redhat.com> Link: https://patchwork.freedesktop.org/patch/msgid/20220313192952.12058-3-tzimmermann@suse.de
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/fbdev/core/cfbimgblt.c28
1 files changed, 24 insertions, 4 deletions
diff --git a/drivers/video/fbdev/core/cfbimgblt.c b/drivers/video/fbdev/core/cfbimgblt.c
index 7361cfabdd85..9ebda4e0dc7a 100644
--- a/drivers/video/fbdev/core/cfbimgblt.c
+++ b/drivers/video/fbdev/core/cfbimgblt.c
@@ -218,7 +218,7 @@ static inline void fast_imageblit(const struct fb_image *image, struct fb_info *
{
u32 fgx = fgcolor, bgx = bgcolor, bpp = p->var.bits_per_pixel;
u32 ppw = 32/bpp, spitch = (image->width + 7)/8;
- u32 bit_mask, eorx;
+ u32 bit_mask, eorx, shift;
const char *s = image->data, *src;
u32 __iomem *dst;
const u32 *tab = NULL;
@@ -259,17 +259,23 @@ static inline void fast_imageblit(const struct fb_image *image, struct fb_info *
for (i = image->height; i--; ) {
dst = (u32 __iomem *)dst1;
+ shift = 8;
src = s;
+ /*
+ * Manually unroll the per-line copying loop for better
+ * performance. This works until we processed the last
+ * completely filled source byte (inclusive).
+ */
switch (ppw) {
case 4: /* 8 bpp */
- for (j = k; j; j -= 2, ++src) {
+ for (j = k; j >= 2; j -= 2, ++src) {
FB_WRITEL(colortab[(*src >> 4) & bit_mask], dst++);
FB_WRITEL(colortab[(*src >> 0) & bit_mask], dst++);
}
break;
case 2: /* 16 bpp */
- for (j = k; j; j -= 4, ++src) {
+ for (j = k; j >= 4; j -= 4, ++src) {
FB_WRITEL(colortab[(*src >> 6) & bit_mask], dst++);
FB_WRITEL(colortab[(*src >> 4) & bit_mask], dst++);
FB_WRITEL(colortab[(*src >> 2) & bit_mask], dst++);
@@ -277,7 +283,7 @@ static inline void fast_imageblit(const struct fb_image *image, struct fb_info *
}
break;
case 1: /* 32 bpp */
- for (j = k; j; j -= 8, ++src) {
+ for (j = k; j >= 8; j -= 8, ++src) {
FB_WRITEL(colortab[(*src >> 7) & bit_mask], dst++);
FB_WRITEL(colortab[(*src >> 6) & bit_mask], dst++);
FB_WRITEL(colortab[(*src >> 5) & bit_mask], dst++);
@@ -290,6 +296,20 @@ static inline void fast_imageblit(const struct fb_image *image, struct fb_info *
break;
}
+ /*
+ * For image widths that are not a multiple of 8, there
+ * are trailing pixels left on the current line. Print
+ * them as well.
+ */
+ for (; j--; ) {
+ shift -= ppw;
+ FB_WRITEL(colortab[(*src >> shift) & bit_mask], dst++);
+ if (!shift) {
+ shift = 8;
+ ++src;
+ }
+ }
+
dst1 += p->fix.line_length;
s += spitch;
}