xref: /linux/drivers/video/fbdev/core/fb_imageblit.h (revision 4f9786035f9e519db41375818e1d0b5f20da2f10)
1*eabb0329SZsolt Kajtar /* SPDX-License-Identifier: GPL-2.0-only
2*eabb0329SZsolt Kajtar  *
3*eabb0329SZsolt Kajtar  *  Generic bitmap / 8 bpp image bitstreamer for packed pixel framebuffers
4*eabb0329SZsolt Kajtar  *
5*eabb0329SZsolt Kajtar  *	Rewritten by:
6*eabb0329SZsolt Kajtar  *	Copyright (C)  2025 Zsolt Kajtar (soci@c64.rulez.org)
7*eabb0329SZsolt Kajtar  *
8*eabb0329SZsolt Kajtar  *	Based on previous work of:
9*eabb0329SZsolt Kajtar  *	Copyright (C)  June 1999 James Simmons
10*eabb0329SZsolt Kajtar  *	Anton Vorontsov <avorontsov@ru.mvista.com>
11*eabb0329SZsolt Kajtar  *	Pavel Pisa <pisa@cmp.felk.cvut.cz>
12*eabb0329SZsolt Kajtar  *	Antonino A. Daplas <adaplas@gmail.com>
13*eabb0329SZsolt Kajtar  *	and others
14*eabb0329SZsolt Kajtar  *
15*eabb0329SZsolt Kajtar  * NOTES:
16*eabb0329SZsolt Kajtar  *
17*eabb0329SZsolt Kajtar  * Handles native and foreign byte order on both endians, standard and
18*eabb0329SZsolt Kajtar  * reverse pixel order in a byte (<8 BPP), word length of 32/64 bits,
19*eabb0329SZsolt Kajtar  * bits per pixel from 1 to the word length. Handles line lengths at byte
20*eabb0329SZsolt Kajtar  * granularity while maintaining aligned accesses.
21*eabb0329SZsolt Kajtar  *
22*eabb0329SZsolt Kajtar  * Optimized routines for word aligned 1, 2, 4 pixel per word for high
23*eabb0329SZsolt Kajtar  * bpp modes and 4 pixel at a time operation for low bpp.
24*eabb0329SZsolt Kajtar  *
25*eabb0329SZsolt Kajtar  * The color image is expected to be one byte per pixel, and values should
26*eabb0329SZsolt Kajtar  * not exceed the bitdepth or the pseudo palette (if used).
27*eabb0329SZsolt Kajtar  */
28*eabb0329SZsolt Kajtar #include "fb_draw.h"
29*eabb0329SZsolt Kajtar 
30*eabb0329SZsolt Kajtar /* bitmap image iterator, one pixel at a time */
31*eabb0329SZsolt Kajtar struct fb_bitmap_iter {
32*eabb0329SZsolt Kajtar 	const u8 *data;
33*eabb0329SZsolt Kajtar 	unsigned long colors[2];
34*eabb0329SZsolt Kajtar 	int width, i;
35*eabb0329SZsolt Kajtar };
36*eabb0329SZsolt Kajtar 
37*eabb0329SZsolt Kajtar static bool fb_bitmap_image(void *iterator, unsigned long *pixels, int *bits)
38*eabb0329SZsolt Kajtar {
39*eabb0329SZsolt Kajtar 	struct fb_bitmap_iter *iter = iterator;
40*eabb0329SZsolt Kajtar 
41*eabb0329SZsolt Kajtar 	if (iter->i < iter->width) {
42*eabb0329SZsolt Kajtar 		int bit = ~iter->i & (BITS_PER_BYTE-1);
43*eabb0329SZsolt Kajtar 		int byte = iter->i++ / BITS_PER_BYTE;
44*eabb0329SZsolt Kajtar 
45*eabb0329SZsolt Kajtar 		*pixels = iter->colors[(iter->data[byte] >> bit) & 1];
46*eabb0329SZsolt Kajtar 		return true;
47*eabb0329SZsolt Kajtar 	}
48*eabb0329SZsolt Kajtar 	iter->data += BITS_TO_BYTES(iter->width);
49*eabb0329SZsolt Kajtar 	iter->i = 0;
50*eabb0329SZsolt Kajtar 	return false;
51*eabb0329SZsolt Kajtar }
52*eabb0329SZsolt Kajtar 
53*eabb0329SZsolt Kajtar /* color image iterator, one pixel at a time */
54*eabb0329SZsolt Kajtar struct fb_color_iter {
55*eabb0329SZsolt Kajtar 	const u8 *data;
56*eabb0329SZsolt Kajtar 	const u32 *palette;
57*eabb0329SZsolt Kajtar 	struct fb_reverse reverse;
58*eabb0329SZsolt Kajtar 	int shift;
59*eabb0329SZsolt Kajtar 	int width, i;
60*eabb0329SZsolt Kajtar };
61*eabb0329SZsolt Kajtar 
62*eabb0329SZsolt Kajtar static bool fb_color_image(void *iterator, unsigned long *pixels, int *bits)
63*eabb0329SZsolt Kajtar {
64*eabb0329SZsolt Kajtar 	struct fb_color_iter *iter = iterator;
65*eabb0329SZsolt Kajtar 
66*eabb0329SZsolt Kajtar 	if (iter->i < iter->width) {
67*eabb0329SZsolt Kajtar 		unsigned long color = iter->data[iter->i++];
68*eabb0329SZsolt Kajtar 
69*eabb0329SZsolt Kajtar 		if (iter->palette)
70*eabb0329SZsolt Kajtar 			color = iter->palette[color];
71*eabb0329SZsolt Kajtar 		*pixels = color << iter->shift;
72*eabb0329SZsolt Kajtar 		if (iter->reverse.pixel)
73*eabb0329SZsolt Kajtar 			*pixels = fb_reverse_bits_long(*pixels);
74*eabb0329SZsolt Kajtar 		return true;
75*eabb0329SZsolt Kajtar 	}
76*eabb0329SZsolt Kajtar 	iter->data += iter->width;
77*eabb0329SZsolt Kajtar 	iter->i = 0;
78*eabb0329SZsolt Kajtar 	return false;
79*eabb0329SZsolt Kajtar }
80*eabb0329SZsolt Kajtar 
81*eabb0329SZsolt Kajtar /* bitmap image iterator, 4 pixels at a time */
82*eabb0329SZsolt Kajtar struct fb_bitmap4x_iter {
83*eabb0329SZsolt Kajtar 	const u8 *data;
84*eabb0329SZsolt Kajtar 	u32 fgxcolor, bgcolor;
85*eabb0329SZsolt Kajtar 	int width, i;
86*eabb0329SZsolt Kajtar 	const u32 *expand;
87*eabb0329SZsolt Kajtar 	int bpp;
88*eabb0329SZsolt Kajtar 	bool top;
89*eabb0329SZsolt Kajtar };
90*eabb0329SZsolt Kajtar 
91*eabb0329SZsolt Kajtar static bool fb_bitmap4x_image(void *iterator, unsigned long *pixels, int *bits)
92*eabb0329SZsolt Kajtar {
93*eabb0329SZsolt Kajtar 	struct fb_bitmap4x_iter *iter = iterator;
94*eabb0329SZsolt Kajtar 	u8 data;
95*eabb0329SZsolt Kajtar 
96*eabb0329SZsolt Kajtar 	if (iter->i >= BITS_PER_BYTE/2) {
97*eabb0329SZsolt Kajtar 		iter->i -= BITS_PER_BYTE/2;
98*eabb0329SZsolt Kajtar 		iter->top = !iter->top;
99*eabb0329SZsolt Kajtar 		if (iter->top)
100*eabb0329SZsolt Kajtar 			data = *iter->data++ >> BITS_PER_BYTE/2;
101*eabb0329SZsolt Kajtar 		else
102*eabb0329SZsolt Kajtar 			data = iter->data[-1] & ((1 << BITS_PER_BYTE/2)-1);
103*eabb0329SZsolt Kajtar 	} else if (iter->i != 0) {
104*eabb0329SZsolt Kajtar 		*bits = iter->bpp * iter->i;
105*eabb0329SZsolt Kajtar 		if (iter->top)
106*eabb0329SZsolt Kajtar 			data = iter->data[-1] & ((1 << BITS_PER_BYTE/2)-1);
107*eabb0329SZsolt Kajtar 		else
108*eabb0329SZsolt Kajtar 			data = *iter->data++ >> BITS_PER_BYTE/2;
109*eabb0329SZsolt Kajtar #ifndef __LITTLE_ENDIAN
110*eabb0329SZsolt Kajtar 		data >>= BITS_PER_BYTE/2 - iter->i;
111*eabb0329SZsolt Kajtar #endif
112*eabb0329SZsolt Kajtar 		iter->i = 0;
113*eabb0329SZsolt Kajtar 	} else {
114*eabb0329SZsolt Kajtar 		*bits = iter->bpp * BITS_PER_BYTE/2;
115*eabb0329SZsolt Kajtar 		iter->i = iter->width;
116*eabb0329SZsolt Kajtar 		iter->top = false;
117*eabb0329SZsolt Kajtar 		return false;
118*eabb0329SZsolt Kajtar 	}
119*eabb0329SZsolt Kajtar 	*pixels = (iter->fgxcolor & iter->expand[data]) ^ iter->bgcolor;
120*eabb0329SZsolt Kajtar #ifndef __LITTLE_ENDIAN
121*eabb0329SZsolt Kajtar 	*pixels <<= BITS_PER_LONG - *bits;
122*eabb0329SZsolt Kajtar #endif
123*eabb0329SZsolt Kajtar 	return true;
124*eabb0329SZsolt Kajtar }
125*eabb0329SZsolt Kajtar 
126*eabb0329SZsolt Kajtar /* draw a line a group of pixels at a time */
127*eabb0329SZsolt Kajtar static __always_inline void fb_bitblit(bool (*get)(void *iter, unsigned long *pixels,
128*eabb0329SZsolt Kajtar 						   int *bits),
129*eabb0329SZsolt Kajtar 				       void *iter, int bits, struct fb_address *dst,
130*eabb0329SZsolt Kajtar 				       struct fb_reverse reverse)
131*eabb0329SZsolt Kajtar {
132*eabb0329SZsolt Kajtar 	unsigned long pixels, val, mask, old;
133*eabb0329SZsolt Kajtar 	int offset = 0;
134*eabb0329SZsolt Kajtar 	int shift = dst->bits;
135*eabb0329SZsolt Kajtar 
136*eabb0329SZsolt Kajtar 	if (shift) {
137*eabb0329SZsolt Kajtar 		old = fb_read_offset(0, dst);
138*eabb0329SZsolt Kajtar 		val = fb_reverse_long(old, reverse);
139*eabb0329SZsolt Kajtar 		val &= ~fb_right(~0UL, shift);
140*eabb0329SZsolt Kajtar 	} else {
141*eabb0329SZsolt Kajtar 		old = 0;
142*eabb0329SZsolt Kajtar 		val = 0;
143*eabb0329SZsolt Kajtar 	}
144*eabb0329SZsolt Kajtar 
145*eabb0329SZsolt Kajtar 	while (get(iter, &pixels, &bits)) {
146*eabb0329SZsolt Kajtar 		val |= fb_right(pixels, shift);
147*eabb0329SZsolt Kajtar 		shift += bits;
148*eabb0329SZsolt Kajtar 
149*eabb0329SZsolt Kajtar 		if (shift < BITS_PER_LONG)
150*eabb0329SZsolt Kajtar 			continue;
151*eabb0329SZsolt Kajtar 
152*eabb0329SZsolt Kajtar 		val = fb_reverse_long(val, reverse);
153*eabb0329SZsolt Kajtar 		fb_write_offset(val, offset++, dst);
154*eabb0329SZsolt Kajtar 		shift &= BITS_PER_LONG - 1;
155*eabb0329SZsolt Kajtar 		val = !shift ? 0 : fb_left(pixels, bits - shift);
156*eabb0329SZsolt Kajtar 	}
157*eabb0329SZsolt Kajtar 
158*eabb0329SZsolt Kajtar 	if (shift) {
159*eabb0329SZsolt Kajtar 		mask = ~fb_pixel_mask(shift, reverse);
160*eabb0329SZsolt Kajtar 		val = fb_reverse_long(val, reverse);
161*eabb0329SZsolt Kajtar 		if (offset || !dst->bits)
162*eabb0329SZsolt Kajtar 			old = fb_read_offset(offset, dst);
163*eabb0329SZsolt Kajtar 		fb_write_offset(fb_comp(val, old, mask), offset, dst);
164*eabb0329SZsolt Kajtar 	}
165*eabb0329SZsolt Kajtar }
166*eabb0329SZsolt Kajtar 
167*eabb0329SZsolt Kajtar /* draw a color image a pixel at a time */
168*eabb0329SZsolt Kajtar static inline void fb_color_imageblit(const struct fb_image *image, struct fb_address *dst,
169*eabb0329SZsolt Kajtar 				      unsigned int bits_per_line, const u32 *palette, int bpp,
170*eabb0329SZsolt Kajtar 				      struct fb_reverse reverse)
171*eabb0329SZsolt Kajtar {
172*eabb0329SZsolt Kajtar 	struct fb_color_iter iter;
173*eabb0329SZsolt Kajtar 	u32 height;
174*eabb0329SZsolt Kajtar 
175*eabb0329SZsolt Kajtar 	iter.data = (const u8 *)image->data;
176*eabb0329SZsolt Kajtar 	iter.palette = palette;
177*eabb0329SZsolt Kajtar 	iter.reverse = reverse;
178*eabb0329SZsolt Kajtar #ifdef __LITTLE_ENDIAN
179*eabb0329SZsolt Kajtar 	if (reverse.pixel)
180*eabb0329SZsolt Kajtar 		iter.shift = BITS_PER_BYTE - bpp;
181*eabb0329SZsolt Kajtar 	else
182*eabb0329SZsolt Kajtar 		iter.shift = 0;
183*eabb0329SZsolt Kajtar #else
184*eabb0329SZsolt Kajtar 	if (reverse.pixel)
185*eabb0329SZsolt Kajtar 		iter.shift = BITS_PER_LONG - BITS_PER_BYTE;
186*eabb0329SZsolt Kajtar 	else
187*eabb0329SZsolt Kajtar 		iter.shift = BITS_PER_LONG - bpp;
188*eabb0329SZsolt Kajtar #endif
189*eabb0329SZsolt Kajtar 	iter.width = image->width;
190*eabb0329SZsolt Kajtar 	iter.i = 0;
191*eabb0329SZsolt Kajtar 
192*eabb0329SZsolt Kajtar 	height = image->height;
193*eabb0329SZsolt Kajtar 	while (height--) {
194*eabb0329SZsolt Kajtar 		fb_bitblit(fb_color_image, &iter, bpp, dst, reverse);
195*eabb0329SZsolt Kajtar 		fb_address_forward(dst, bits_per_line);
196*eabb0329SZsolt Kajtar 	}
197*eabb0329SZsolt Kajtar }
198*eabb0329SZsolt Kajtar 
199*eabb0329SZsolt Kajtar #ifdef __LITTLE_ENDIAN
200*eabb0329SZsolt Kajtar #define FB_GEN(a, b) (((a)/8+(((a)&4)<<((b)-2)) \
201*eabb0329SZsolt Kajtar 		       +(((a)&2)<<((b)*2-1))+(((a)&1u)<<((b)*3)))*((1<<(b))-1))
202*eabb0329SZsolt Kajtar #define FB_GEN1(a) ((a)/8+((a)&4)/2+((a)&2)*2+((a)&1)*8)
203*eabb0329SZsolt Kajtar #else
204*eabb0329SZsolt Kajtar #define FB_GEN(a, b) (((((a)/8)<<((b)*3))+(((a)&4)<<((b)*2-2)) \
205*eabb0329SZsolt Kajtar 		       +(((a)&2)<<(b-1))+((a)&1u))*((1<<(b))-1))
206*eabb0329SZsolt Kajtar #define FB_GEN1(a) (a)
207*eabb0329SZsolt Kajtar #endif
208*eabb0329SZsolt Kajtar 
209*eabb0329SZsolt Kajtar #define FB_GENx(a) { FB_GEN(0, (a)), FB_GEN(1, (a)), FB_GEN(2, (a)), FB_GEN(3, (a)),	\
210*eabb0329SZsolt Kajtar 	FB_GEN(4, (a)), FB_GEN(5, (a)), FB_GEN(6, (a)), FB_GEN(7, (a)),			\
211*eabb0329SZsolt Kajtar 	FB_GEN(8, (a)), FB_GEN(9, (a)), FB_GEN(10, (a)), FB_GEN(11, (a)),		\
212*eabb0329SZsolt Kajtar 	FB_GEN(12, (a)), FB_GEN(13, (a)), FB_GEN(14, (a)), FB_GEN(15, (a)) }
213*eabb0329SZsolt Kajtar 
214*eabb0329SZsolt Kajtar /* draw a 2 color image four pixels at a time (for 1-8 bpp only) */
215*eabb0329SZsolt Kajtar static inline void fb_bitmap4x_imageblit(const struct fb_image *image, struct fb_address *dst,
216*eabb0329SZsolt Kajtar 					 unsigned long fgcolor, unsigned long bgcolor, int bpp,
217*eabb0329SZsolt Kajtar 					 unsigned int bits_per_line, struct fb_reverse reverse)
218*eabb0329SZsolt Kajtar {
219*eabb0329SZsolt Kajtar 	static const u32 mul[BITS_PER_BYTE] = {
220*eabb0329SZsolt Kajtar 		0xf, 0x55, 0x249, 0x1111, 0x8421, 0x41041, 0x204081, 0x01010101
221*eabb0329SZsolt Kajtar 	};
222*eabb0329SZsolt Kajtar 	static const u32 expand[BITS_PER_BYTE][1 << 4] = {
223*eabb0329SZsolt Kajtar 		{
224*eabb0329SZsolt Kajtar 			FB_GEN1(0), FB_GEN1(1), FB_GEN1(2), FB_GEN1(3),
225*eabb0329SZsolt Kajtar 			FB_GEN1(4), FB_GEN1(5), FB_GEN1(6), FB_GEN1(7),
226*eabb0329SZsolt Kajtar 			FB_GEN1(8), FB_GEN1(9), FB_GEN1(10), FB_GEN1(11),
227*eabb0329SZsolt Kajtar 			FB_GEN1(12), FB_GEN1(13), FB_GEN1(14), FB_GEN1(15)
228*eabb0329SZsolt Kajtar 		},
229*eabb0329SZsolt Kajtar 		FB_GENx(2), FB_GENx(3), FB_GENx(4),
230*eabb0329SZsolt Kajtar 		FB_GENx(5), FB_GENx(6), FB_GENx(7), FB_GENx(8),
231*eabb0329SZsolt Kajtar 	};
232*eabb0329SZsolt Kajtar 	struct fb_bitmap4x_iter iter;
233*eabb0329SZsolt Kajtar 	u32 height;
234*eabb0329SZsolt Kajtar 
235*eabb0329SZsolt Kajtar 	iter.data = (const u8 *)image->data;
236*eabb0329SZsolt Kajtar 	if (reverse.pixel) {
237*eabb0329SZsolt Kajtar 		fgcolor = fb_reverse_bits_long(fgcolor << (BITS_PER_BYTE - bpp));
238*eabb0329SZsolt Kajtar 		bgcolor = fb_reverse_bits_long(bgcolor << (BITS_PER_BYTE - bpp));
239*eabb0329SZsolt Kajtar 	}
240*eabb0329SZsolt Kajtar 	iter.fgxcolor = (fgcolor ^ bgcolor) * mul[bpp-1];
241*eabb0329SZsolt Kajtar 	iter.bgcolor = bgcolor * mul[bpp-1];
242*eabb0329SZsolt Kajtar 	iter.width = image->width;
243*eabb0329SZsolt Kajtar 	iter.i = image->width;
244*eabb0329SZsolt Kajtar 	iter.expand = expand[bpp-1];
245*eabb0329SZsolt Kajtar 	iter.bpp = bpp;
246*eabb0329SZsolt Kajtar 	iter.top = false;
247*eabb0329SZsolt Kajtar 
248*eabb0329SZsolt Kajtar 	height = image->height;
249*eabb0329SZsolt Kajtar 	while (height--) {
250*eabb0329SZsolt Kajtar 		fb_bitblit(fb_bitmap4x_image, &iter, bpp * BITS_PER_BYTE/2, dst, reverse);
251*eabb0329SZsolt Kajtar 		fb_address_forward(dst, bits_per_line);
252*eabb0329SZsolt Kajtar 	}
253*eabb0329SZsolt Kajtar }
254*eabb0329SZsolt Kajtar 
255*eabb0329SZsolt Kajtar /* draw a bitmap image 1 pixel at a time (for >8 bpp) */
256*eabb0329SZsolt Kajtar static inline void fb_bitmap1x_imageblit(const struct fb_image *image, struct fb_address *dst,
257*eabb0329SZsolt Kajtar 					 unsigned long fgcolor, unsigned long bgcolor, int bpp,
258*eabb0329SZsolt Kajtar 					 unsigned int bits_per_line, struct fb_reverse reverse)
259*eabb0329SZsolt Kajtar {
260*eabb0329SZsolt Kajtar 	struct fb_bitmap_iter iter;
261*eabb0329SZsolt Kajtar 	u32 height;
262*eabb0329SZsolt Kajtar 
263*eabb0329SZsolt Kajtar 	iter.colors[0] = bgcolor;
264*eabb0329SZsolt Kajtar 	iter.colors[1] = fgcolor;
265*eabb0329SZsolt Kajtar #ifndef __LITTLE_ENDIAN
266*eabb0329SZsolt Kajtar 	iter.colors[0] <<= BITS_PER_LONG - bpp;
267*eabb0329SZsolt Kajtar 	iter.colors[1] <<= BITS_PER_LONG - bpp;
268*eabb0329SZsolt Kajtar #endif
269*eabb0329SZsolt Kajtar 	iter.data = (const u8 *)image->data;
270*eabb0329SZsolt Kajtar 	iter.width = image->width;
271*eabb0329SZsolt Kajtar 	iter.i = 0;
272*eabb0329SZsolt Kajtar 
273*eabb0329SZsolt Kajtar 	height = image->height;
274*eabb0329SZsolt Kajtar 	while (height--) {
275*eabb0329SZsolt Kajtar 		fb_bitblit(fb_bitmap_image, &iter, bpp, dst, reverse);
276*eabb0329SZsolt Kajtar 		fb_address_forward(dst, bits_per_line);
277*eabb0329SZsolt Kajtar 	}
278*eabb0329SZsolt Kajtar }
279*eabb0329SZsolt Kajtar 
280*eabb0329SZsolt Kajtar /* one pixel per word, 64/32 bpp blitting */
281*eabb0329SZsolt Kajtar static inline void fb_bitmap_1ppw(const struct fb_image *image, struct fb_address *dst,
282*eabb0329SZsolt Kajtar 				  unsigned long fgcolor, unsigned long bgcolor,
283*eabb0329SZsolt Kajtar 				  int words_per_line, struct fb_reverse reverse)
284*eabb0329SZsolt Kajtar {
285*eabb0329SZsolt Kajtar 	unsigned long tab[2];
286*eabb0329SZsolt Kajtar 	const u8 *src = (u8 *)image->data;
287*eabb0329SZsolt Kajtar 	int width = image->width;
288*eabb0329SZsolt Kajtar 	int offset;
289*eabb0329SZsolt Kajtar 	u32 height;
290*eabb0329SZsolt Kajtar 
291*eabb0329SZsolt Kajtar 	if (reverse.byte) {
292*eabb0329SZsolt Kajtar 		tab[0] = swab_long(bgcolor);
293*eabb0329SZsolt Kajtar 		tab[1] = swab_long(fgcolor);
294*eabb0329SZsolt Kajtar 	} else {
295*eabb0329SZsolt Kajtar 		tab[0] = bgcolor;
296*eabb0329SZsolt Kajtar 		tab[1] = fgcolor;
297*eabb0329SZsolt Kajtar 	}
298*eabb0329SZsolt Kajtar 
299*eabb0329SZsolt Kajtar 	height = image->height;
300*eabb0329SZsolt Kajtar 	while (height--) {
301*eabb0329SZsolt Kajtar 		for (offset = 0; offset + 8 <= width; offset += 8) {
302*eabb0329SZsolt Kajtar 			unsigned int srcbyte = *src++;
303*eabb0329SZsolt Kajtar 
304*eabb0329SZsolt Kajtar 			fb_write_offset(tab[(srcbyte >> 7) & 1], offset + 0, dst);
305*eabb0329SZsolt Kajtar 			fb_write_offset(tab[(srcbyte >> 6) & 1], offset + 1, dst);
306*eabb0329SZsolt Kajtar 			fb_write_offset(tab[(srcbyte >> 5) & 1], offset + 2, dst);
307*eabb0329SZsolt Kajtar 			fb_write_offset(tab[(srcbyte >> 4) & 1], offset + 3, dst);
308*eabb0329SZsolt Kajtar 			fb_write_offset(tab[(srcbyte >> 3) & 1], offset + 4, dst);
309*eabb0329SZsolt Kajtar 			fb_write_offset(tab[(srcbyte >> 2) & 1], offset + 5, dst);
310*eabb0329SZsolt Kajtar 			fb_write_offset(tab[(srcbyte >> 1) & 1], offset + 6, dst);
311*eabb0329SZsolt Kajtar 			fb_write_offset(tab[(srcbyte >> 0) & 1], offset + 7, dst);
312*eabb0329SZsolt Kajtar 		}
313*eabb0329SZsolt Kajtar 
314*eabb0329SZsolt Kajtar 		if (offset < width) {
315*eabb0329SZsolt Kajtar 			unsigned int srcbyte = *src++;
316*eabb0329SZsolt Kajtar 
317*eabb0329SZsolt Kajtar 			while (offset < width) {
318*eabb0329SZsolt Kajtar 				fb_write_offset(tab[(srcbyte >> 7) & 1], offset, dst);
319*eabb0329SZsolt Kajtar 				srcbyte <<= 1;
320*eabb0329SZsolt Kajtar 				offset++;
321*eabb0329SZsolt Kajtar 			}
322*eabb0329SZsolt Kajtar 		}
323*eabb0329SZsolt Kajtar 		fb_address_move_long(dst, words_per_line);
324*eabb0329SZsolt Kajtar 	}
325*eabb0329SZsolt Kajtar }
326*eabb0329SZsolt Kajtar 
327*eabb0329SZsolt Kajtar static inline unsigned long fb_pack(unsigned long left, unsigned long right, int bits)
328*eabb0329SZsolt Kajtar {
329*eabb0329SZsolt Kajtar #ifdef __LITTLE_ENDIAN
330*eabb0329SZsolt Kajtar 	return left | right << bits;
331*eabb0329SZsolt Kajtar #else
332*eabb0329SZsolt Kajtar 	return right | left << bits;
333*eabb0329SZsolt Kajtar #endif
334*eabb0329SZsolt Kajtar }
335*eabb0329SZsolt Kajtar 
336*eabb0329SZsolt Kajtar /* aligned 32/16 bpp blitting */
337*eabb0329SZsolt Kajtar static inline void fb_bitmap_2ppw(const struct fb_image *image, struct fb_address *dst,
338*eabb0329SZsolt Kajtar 				  unsigned long fgcolor, unsigned long bgcolor,
339*eabb0329SZsolt Kajtar 				  int words_per_line, struct fb_reverse reverse)
340*eabb0329SZsolt Kajtar {
341*eabb0329SZsolt Kajtar 	unsigned long tab[4];
342*eabb0329SZsolt Kajtar 	const u8 *src = (u8 *)image->data;
343*eabb0329SZsolt Kajtar 	int width = image->width / 2;
344*eabb0329SZsolt Kajtar 	int offset;
345*eabb0329SZsolt Kajtar 	u32 height;
346*eabb0329SZsolt Kajtar 
347*eabb0329SZsolt Kajtar 	tab[0] = fb_pack(bgcolor, bgcolor, BITS_PER_LONG/2);
348*eabb0329SZsolt Kajtar 	tab[1] = fb_pack(bgcolor, fgcolor, BITS_PER_LONG/2);
349*eabb0329SZsolt Kajtar 	tab[2] = fb_pack(fgcolor, bgcolor, BITS_PER_LONG/2);
350*eabb0329SZsolt Kajtar 	tab[3] = fb_pack(fgcolor, fgcolor, BITS_PER_LONG/2);
351*eabb0329SZsolt Kajtar 
352*eabb0329SZsolt Kajtar 	if (reverse.byte) {
353*eabb0329SZsolt Kajtar 		tab[0] = swab_long(tab[0]);
354*eabb0329SZsolt Kajtar 		tab[1] = swab_long(tab[1]);
355*eabb0329SZsolt Kajtar 		tab[2] = swab_long(tab[2]);
356*eabb0329SZsolt Kajtar 		tab[3] = swab_long(tab[3]);
357*eabb0329SZsolt Kajtar 	}
358*eabb0329SZsolt Kajtar 
359*eabb0329SZsolt Kajtar 	height = image->height;
360*eabb0329SZsolt Kajtar 	while (height--) {
361*eabb0329SZsolt Kajtar 		for (offset = 0; offset + 4 <= width; offset += 4) {
362*eabb0329SZsolt Kajtar 			unsigned int srcbyte = *src++;
363*eabb0329SZsolt Kajtar 
364*eabb0329SZsolt Kajtar 			fb_write_offset(tab[(srcbyte >> 6) & 3], offset + 0, dst);
365*eabb0329SZsolt Kajtar 			fb_write_offset(tab[(srcbyte >> 4) & 3], offset + 1, dst);
366*eabb0329SZsolt Kajtar 			fb_write_offset(tab[(srcbyte >> 2) & 3], offset + 2, dst);
367*eabb0329SZsolt Kajtar 			fb_write_offset(tab[(srcbyte >> 0) & 3], offset + 3, dst);
368*eabb0329SZsolt Kajtar 		}
369*eabb0329SZsolt Kajtar 
370*eabb0329SZsolt Kajtar 		if (offset < width) {
371*eabb0329SZsolt Kajtar 			unsigned int srcbyte = *src++;
372*eabb0329SZsolt Kajtar 
373*eabb0329SZsolt Kajtar 			while (offset < width) {
374*eabb0329SZsolt Kajtar 				fb_write_offset(tab[(srcbyte >> 6) & 3], offset, dst);
375*eabb0329SZsolt Kajtar 				srcbyte <<= 2;
376*eabb0329SZsolt Kajtar 				offset++;
377*eabb0329SZsolt Kajtar 			}
378*eabb0329SZsolt Kajtar 		}
379*eabb0329SZsolt Kajtar 		fb_address_move_long(dst, words_per_line);
380*eabb0329SZsolt Kajtar 	}
381*eabb0329SZsolt Kajtar }
382*eabb0329SZsolt Kajtar 
383*eabb0329SZsolt Kajtar #define FB_PATP(a, b) (((a)<<((b)*BITS_PER_LONG/4))*((1UL<<BITS_PER_LONG/4)-1UL))
384*eabb0329SZsolt Kajtar #define FB_PAT4(a) (FB_PATP((a)&1, 0)|FB_PATP(((a)&2)/2, 1)| \
385*eabb0329SZsolt Kajtar 	FB_PATP(((a)&4)/4, 2)|FB_PATP(((a)&8)/8, 3))
386*eabb0329SZsolt Kajtar 
387*eabb0329SZsolt Kajtar /* aligned 16/8 bpp blitting */
388*eabb0329SZsolt Kajtar static inline void fb_bitmap_4ppw(const struct fb_image *image, struct fb_address *dst,
389*eabb0329SZsolt Kajtar 				  unsigned long fgcolor, unsigned long bgcolor,
390*eabb0329SZsolt Kajtar 				  int words_per_line, struct fb_reverse reverse)
391*eabb0329SZsolt Kajtar {
392*eabb0329SZsolt Kajtar 	static const unsigned long tab16_be[] = {
393*eabb0329SZsolt Kajtar 		0, FB_PAT4(1UL), FB_PAT4(2UL), FB_PAT4(3UL),
394*eabb0329SZsolt Kajtar 		FB_PAT4(4UL), FB_PAT4(5UL), FB_PAT4(6UL), FB_PAT4(7UL),
395*eabb0329SZsolt Kajtar 		FB_PAT4(8UL), FB_PAT4(9UL), FB_PAT4(10UL), FB_PAT4(11UL),
396*eabb0329SZsolt Kajtar 		FB_PAT4(12UL), FB_PAT4(13UL), FB_PAT4(14UL), ~0UL
397*eabb0329SZsolt Kajtar 	};
398*eabb0329SZsolt Kajtar 	static const unsigned long tab16_le[] = {
399*eabb0329SZsolt Kajtar 		0, FB_PAT4(8UL), FB_PAT4(4UL), FB_PAT4(12UL),
400*eabb0329SZsolt Kajtar 		FB_PAT4(2UL), FB_PAT4(10UL), FB_PAT4(6UL), FB_PAT4(14UL),
401*eabb0329SZsolt Kajtar 		FB_PAT4(1UL), FB_PAT4(9UL), FB_PAT4(5UL), FB_PAT4(13UL),
402*eabb0329SZsolt Kajtar 		FB_PAT4(3UL), FB_PAT4(11UL), FB_PAT4(7UL), ~0UL
403*eabb0329SZsolt Kajtar 	};
404*eabb0329SZsolt Kajtar 	const unsigned long *tab;
405*eabb0329SZsolt Kajtar 	const u8 *src = (u8 *)image->data;
406*eabb0329SZsolt Kajtar 	int width = image->width / 4;
407*eabb0329SZsolt Kajtar 	int offset;
408*eabb0329SZsolt Kajtar 	u32 height;
409*eabb0329SZsolt Kajtar 
410*eabb0329SZsolt Kajtar 	fgcolor = fgcolor | fgcolor << BITS_PER_LONG/4;
411*eabb0329SZsolt Kajtar 	bgcolor = bgcolor | bgcolor << BITS_PER_LONG/4;
412*eabb0329SZsolt Kajtar 	fgcolor = fgcolor | fgcolor << BITS_PER_LONG/2;
413*eabb0329SZsolt Kajtar 	bgcolor = bgcolor | bgcolor << BITS_PER_LONG/2;
414*eabb0329SZsolt Kajtar 	fgcolor ^= bgcolor;
415*eabb0329SZsolt Kajtar 
416*eabb0329SZsolt Kajtar 	if (BITS_PER_LONG/4 > BITS_PER_BYTE && reverse.byte) {
417*eabb0329SZsolt Kajtar 		fgcolor = swab_long(fgcolor);
418*eabb0329SZsolt Kajtar 		bgcolor = swab_long(bgcolor);
419*eabb0329SZsolt Kajtar 	}
420*eabb0329SZsolt Kajtar 
421*eabb0329SZsolt Kajtar #ifdef __LITTLE_ENDIAN
422*eabb0329SZsolt Kajtar 	tab = reverse.byte ? tab16_be : tab16_le;
423*eabb0329SZsolt Kajtar #else
424*eabb0329SZsolt Kajtar 	tab = reverse.byte ? tab16_le : tab16_be;
425*eabb0329SZsolt Kajtar #endif
426*eabb0329SZsolt Kajtar 
427*eabb0329SZsolt Kajtar 	height = image->height;
428*eabb0329SZsolt Kajtar 	while (height--) {
429*eabb0329SZsolt Kajtar 		for (offset = 0; offset + 2 <= width; offset += 2, src++) {
430*eabb0329SZsolt Kajtar 			fb_write_offset((fgcolor & tab[*src >> 4]) ^ bgcolor, offset + 0, dst);
431*eabb0329SZsolt Kajtar 			fb_write_offset((fgcolor & tab[*src & 0xf]) ^ bgcolor, offset + 1, dst);
432*eabb0329SZsolt Kajtar 		}
433*eabb0329SZsolt Kajtar 
434*eabb0329SZsolt Kajtar 		if (offset < width)
435*eabb0329SZsolt Kajtar 			fb_write_offset((fgcolor & tab[*src++ >> 4]) ^ bgcolor, offset, dst);
436*eabb0329SZsolt Kajtar 
437*eabb0329SZsolt Kajtar 		fb_address_move_long(dst, words_per_line);
438*eabb0329SZsolt Kajtar 	}
439*eabb0329SZsolt Kajtar }
440*eabb0329SZsolt Kajtar 
441*eabb0329SZsolt Kajtar static inline void fb_bitmap_imageblit(const struct fb_image *image, struct fb_address *dst,
442*eabb0329SZsolt Kajtar 				       unsigned int bits_per_line, const u32 *palette, int bpp,
443*eabb0329SZsolt Kajtar 				       struct fb_reverse reverse)
444*eabb0329SZsolt Kajtar {
445*eabb0329SZsolt Kajtar 	unsigned long fgcolor, bgcolor;
446*eabb0329SZsolt Kajtar 
447*eabb0329SZsolt Kajtar 	if (palette) {
448*eabb0329SZsolt Kajtar 		fgcolor = palette[image->fg_color];
449*eabb0329SZsolt Kajtar 		bgcolor = palette[image->bg_color];
450*eabb0329SZsolt Kajtar 	} else {
451*eabb0329SZsolt Kajtar 		fgcolor = image->fg_color;
452*eabb0329SZsolt Kajtar 		bgcolor = image->bg_color;
453*eabb0329SZsolt Kajtar 	}
454*eabb0329SZsolt Kajtar 
455*eabb0329SZsolt Kajtar 	if (!dst->bits && !(bits_per_line & (BITS_PER_LONG-1))) {
456*eabb0329SZsolt Kajtar 		if (bpp == BITS_PER_LONG && BITS_PER_LONG == 32) {
457*eabb0329SZsolt Kajtar 			fb_bitmap_1ppw(image, dst, fgcolor, bgcolor,
458*eabb0329SZsolt Kajtar 				       bits_per_line / BITS_PER_LONG, reverse);
459*eabb0329SZsolt Kajtar 			return;
460*eabb0329SZsolt Kajtar 		}
461*eabb0329SZsolt Kajtar 		if (bpp == BITS_PER_LONG/2 && !(image->width & 1)) {
462*eabb0329SZsolt Kajtar 			fb_bitmap_2ppw(image, dst, fgcolor, bgcolor,
463*eabb0329SZsolt Kajtar 				       bits_per_line / BITS_PER_LONG, reverse);
464*eabb0329SZsolt Kajtar 			return;
465*eabb0329SZsolt Kajtar 		}
466*eabb0329SZsolt Kajtar 		if (bpp == BITS_PER_LONG/4 && !(image->width & 3)) {
467*eabb0329SZsolt Kajtar 			fb_bitmap_4ppw(image, dst, fgcolor, bgcolor,
468*eabb0329SZsolt Kajtar 				       bits_per_line / BITS_PER_LONG, reverse);
469*eabb0329SZsolt Kajtar 			return;
470*eabb0329SZsolt Kajtar 		}
471*eabb0329SZsolt Kajtar 	}
472*eabb0329SZsolt Kajtar 
473*eabb0329SZsolt Kajtar 	if (bpp > 0 && bpp <= BITS_PER_BYTE)
474*eabb0329SZsolt Kajtar 		fb_bitmap4x_imageblit(image, dst, fgcolor, bgcolor, bpp,
475*eabb0329SZsolt Kajtar 				     bits_per_line, reverse);
476*eabb0329SZsolt Kajtar 	else if (bpp > BITS_PER_BYTE && bpp <= BITS_PER_LONG)
477*eabb0329SZsolt Kajtar 		fb_bitmap1x_imageblit(image, dst, fgcolor, bgcolor, bpp,
478*eabb0329SZsolt Kajtar 				     bits_per_line, reverse);
479*eabb0329SZsolt Kajtar }
480*eabb0329SZsolt Kajtar 
481*eabb0329SZsolt Kajtar static inline void fb_imageblit(struct fb_info *p, const struct fb_image *image)
482*eabb0329SZsolt Kajtar {
483*eabb0329SZsolt Kajtar 	int bpp = p->var.bits_per_pixel;
484*eabb0329SZsolt Kajtar 	unsigned int bits_per_line = BYTES_TO_BITS(p->fix.line_length);
485*eabb0329SZsolt Kajtar 	struct fb_address dst = fb_address_init(p);
486*eabb0329SZsolt Kajtar 	struct fb_reverse reverse = fb_reverse_init(p);
487*eabb0329SZsolt Kajtar 	const u32 *palette = fb_palette(p);
488*eabb0329SZsolt Kajtar 
489*eabb0329SZsolt Kajtar 	fb_address_forward(&dst, image->dy * bits_per_line + image->dx * bpp);
490*eabb0329SZsolt Kajtar 
491*eabb0329SZsolt Kajtar 	if (image->depth == 1)
492*eabb0329SZsolt Kajtar 		fb_bitmap_imageblit(image, &dst, bits_per_line, palette, bpp, reverse);
493*eabb0329SZsolt Kajtar 	else
494*eabb0329SZsolt Kajtar 		fb_color_imageblit(image, &dst, bits_per_line, palette, bpp, reverse);
495*eabb0329SZsolt Kajtar }
496