Skip to content

Commit 2a81dba

Browse files
Thomas Zimmermannairlied
authored andcommitted
fbdev: Fix cfb_imageblit() for arbitrary image widths
Commit 0d03011 ("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 <[email protected]> Fixes: 0d03011 ("fbdev: Improve performance of cfb_imageblit()") Reported-by: Marek Szyprowski <[email protected]> Cc: Thomas Zimmermann <[email protected]> Cc: Javier Martinez Canillas <[email protected]> Cc: Sam Ravnborg <[email protected]> Tested-by: Marek Szyprowski <[email protected]> Acked-by: Daniel Vetter <[email protected]> Reviewed-by: Javier Martinez Canillas <[email protected]> Tested-by: Guenter Roeck <[email protected]> Signed-off-by: Dave Airlie <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent 40faaf8 commit 2a81dba

File tree

1 file changed

+24
-4
lines changed

1 file changed

+24
-4
lines changed

drivers/video/fbdev/core/cfbimgblt.c

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ static inline void fast_imageblit(const struct fb_image *image, struct fb_info *
218218
{
219219
u32 fgx = fgcolor, bgx = bgcolor, bpp = p->var.bits_per_pixel;
220220
u32 ppw = 32/bpp, spitch = (image->width + 7)/8;
221-
u32 bit_mask, eorx;
221+
u32 bit_mask, eorx, shift;
222222
const char *s = image->data, *src;
223223
u32 __iomem *dst;
224224
const u32 *tab = NULL;
@@ -259,25 +259,31 @@ static inline void fast_imageblit(const struct fb_image *image, struct fb_info *
259259

260260
for (i = image->height; i--; ) {
261261
dst = (u32 __iomem *)dst1;
262+
shift = 8;
262263
src = s;
263264

265+
/*
266+
* Manually unroll the per-line copying loop for better
267+
* performance. This works until we processed the last
268+
* completely filled source byte (inclusive).
269+
*/
264270
switch (ppw) {
265271
case 4: /* 8 bpp */
266-
for (j = k; j; j -= 2, ++src) {
272+
for (j = k; j >= 2; j -= 2, ++src) {
267273
FB_WRITEL(colortab[(*src >> 4) & bit_mask], dst++);
268274
FB_WRITEL(colortab[(*src >> 0) & bit_mask], dst++);
269275
}
270276
break;
271277
case 2: /* 16 bpp */
272-
for (j = k; j; j -= 4, ++src) {
278+
for (j = k; j >= 4; j -= 4, ++src) {
273279
FB_WRITEL(colortab[(*src >> 6) & bit_mask], dst++);
274280
FB_WRITEL(colortab[(*src >> 4) & bit_mask], dst++);
275281
FB_WRITEL(colortab[(*src >> 2) & bit_mask], dst++);
276282
FB_WRITEL(colortab[(*src >> 0) & bit_mask], dst++);
277283
}
278284
break;
279285
case 1: /* 32 bpp */
280-
for (j = k; j; j -= 8, ++src) {
286+
for (j = k; j >= 8; j -= 8, ++src) {
281287
FB_WRITEL(colortab[(*src >> 7) & bit_mask], dst++);
282288
FB_WRITEL(colortab[(*src >> 6) & bit_mask], dst++);
283289
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 *
290296
break;
291297
}
292298

299+
/*
300+
* For image widths that are not a multiple of 8, there
301+
* are trailing pixels left on the current line. Print
302+
* them as well.
303+
*/
304+
for (; j--; ) {
305+
shift -= ppw;
306+
FB_WRITEL(colortab[(*src >> shift) & bit_mask], dst++);
307+
if (!shift) {
308+
shift = 8;
309+
++src;
310+
}
311+
}
312+
293313
dst1 += p->fix.line_length;
294314
s += spitch;
295315
}

0 commit comments

Comments
 (0)