blob: 10de70779a506b9ca71b821fdc667f423f3cee94 [file] [log] [blame]
Antonino A. Daplas68648ed2007-05-08 00:38:57 -07001/*
2 * Generic fillrect for frame buffers in system RAM with packed pixels of
3 * any depth.
4 *
5 * Based almost entirely from cfbfillrect.c (which is based almost entirely
6 * on Geert Uytterhoeven's fillrect routine)
7 *
8 * Copyright (C) 2007 Antonino Daplas <adaplas@pol.net>
9 *
10 * This file is subject to the terms and conditions of the GNU General Public
11 * License. See the file COPYING in the main directory of this archive for
12 * more details.
13 */
14#include <linux/module.h>
15#include <linux/string.h>
16#include <linux/fb.h>
17#include <asm/types.h>
18
19 /*
20 * Compose two values, using a bitmask as decision value
21 * This is equivalent to (a & mask) | (b & ~mask)
22 */
23
24static inline unsigned long
25comp(unsigned long a, unsigned long b, unsigned long mask)
26{
27 return ((a ^ b) & mask) ^ b;
28}
29
30 /*
31 * Create a pattern with the given pixel's color
32 */
33
34#if BITS_PER_LONG == 64
35static inline unsigned long
36pixel_to_pat( u32 bpp, u32 pixel)
37{
38 switch (bpp) {
39 case 1:
40 return 0xfffffffffffffffful*pixel;
41 case 2:
42 return 0x5555555555555555ul*pixel;
43 case 4:
44 return 0x1111111111111111ul*pixel;
45 case 8:
46 return 0x0101010101010101ul*pixel;
47 case 12:
48 return 0x0001001001001001ul*pixel;
49 case 16:
50 return 0x0001000100010001ul*pixel;
51 case 24:
52 return 0x0000000001000001ul*pixel;
53 case 32:
54 return 0x0000000100000001ul*pixel;
55 default:
56 panic("pixel_to_pat(): unsupported pixelformat\n");
57 }
58}
59#else
60static inline unsigned long
61pixel_to_pat( u32 bpp, u32 pixel)
62{
63 switch (bpp) {
64 case 1:
65 return 0xfffffffful*pixel;
66 case 2:
67 return 0x55555555ul*pixel;
68 case 4:
69 return 0x11111111ul*pixel;
70 case 8:
71 return 0x01010101ul*pixel;
72 case 12:
73 return 0x00001001ul*pixel;
74 case 16:
75 return 0x00010001ul*pixel;
76 case 24:
77 return 0x00000001ul*pixel;
78 case 32:
79 return 0x00000001ul*pixel;
80 default:
81 panic("pixel_to_pat(): unsupported pixelformat\n");
82 }
83}
84#endif
85
86 /*
87 * Aligned pattern fill using 32/64-bit memory accesses
88 */
89
90static void
91bitfill_aligned(unsigned long *dst, int dst_idx, unsigned long pat,
92 unsigned n, int bits)
93{
94 unsigned long first, last;
95
96 if (!n)
97 return;
98
99 first = FB_SHIFT_HIGH(~0UL, dst_idx);
100 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
101
102 if (dst_idx+n <= bits) {
103 /* Single word */
104 if (last)
105 first &= last;
106 *dst = comp(pat, *dst, first);
107 } else {
108 /* Multiple destination words */
109
110 /* Leading bits */
111 if (first!= ~0UL) {
112 *dst = comp(pat, *dst, first);
113 dst++;
114 n -= bits - dst_idx;
115 }
116
117 /* Main chunk */
118 n /= bits;
119 while (n >= 8) {
120 *dst++ = pat;
121 *dst++ = pat;
122 *dst++ = pat;
123 *dst++ = pat;
124 *dst++ = pat;
125 *dst++ = pat;
126 *dst++ = pat;
127 *dst++ = pat;
128 n -= 8;
129 }
130 while (n--)
131 *dst++ = pat;
132 /* Trailing bits */
133 if (last)
134 *dst = comp(pat, *dst, last);
135 }
136}
137
138
139 /*
140 * Unaligned generic pattern fill using 32/64-bit memory accesses
141 * The pattern must have been expanded to a full 32/64-bit value
142 * Left/right are the appropriate shifts to convert to the pattern to be
143 * used for the next 32/64-bit word
144 */
145
146static void
147bitfill_unaligned(unsigned long *dst, int dst_idx, unsigned long pat,
148 int left, int right, unsigned n, int bits)
149{
150 unsigned long first, last;
151
152 if (!n)
153 return;
154
155 first = FB_SHIFT_HIGH(~0UL, dst_idx);
156 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
157
158 if (dst_idx+n <= bits) {
159 /* Single word */
160 if (last)
161 first &= last;
162 *dst = comp(pat, *dst, first);
163 } else {
164 /* Multiple destination words */
165 /* Leading bits */
166 if (first) {
167 *dst = comp(pat, *dst, first);
168 dst++;
169 pat = pat << left | pat >> right;
170 n -= bits - dst_idx;
171 }
172
173 /* Main chunk */
174 n /= bits;
175 while (n >= 4) {
176 *dst++ = pat;
177 pat = pat << left | pat >> right;
178 *dst++ = pat;
179 pat = pat << left | pat >> right;
180 *dst++ = pat;
181 pat = pat << left | pat >> right;
182 *dst++ = pat;
183 pat = pat << left | pat >> right;
184 n -= 4;
185 }
186 while (n--) {
187 *dst++ = pat;
188 pat = pat << left | pat >> right;
189 }
190
191 /* Trailing bits */
192 if (last)
193 *dst = comp(pat, *dst, first);
194 }
195}
196
197 /*
198 * Aligned pattern invert using 32/64-bit memory accesses
199 */
200static void
201bitfill_aligned_rev(unsigned long *dst, int dst_idx, unsigned long pat,
202 unsigned n, int bits)
203{
204 unsigned long val = pat;
205 unsigned long first, last;
206
207 if (!n)
208 return;
209
210 first = FB_SHIFT_HIGH(~0UL, dst_idx);
211 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
212
213 if (dst_idx+n <= bits) {
214 /* Single word */
215 if (last)
216 first &= last;
217 *dst = comp(*dst ^ val, *dst, first);
218 } else {
219 /* Multiple destination words */
220 /* Leading bits */
221 if (first!=0UL) {
222 *dst = comp(*dst ^ val, *dst, first);
223 dst++;
224 n -= bits - dst_idx;
225 }
226
227 /* Main chunk */
228 n /= bits;
229 while (n >= 8) {
230 *dst++ ^= val;
231 *dst++ ^= val;
232 *dst++ ^= val;
233 *dst++ ^= val;
234 *dst++ ^= val;
235 *dst++ ^= val;
236 *dst++ ^= val;
237 *dst++ ^= val;
238 n -= 8;
239 }
240 while (n--)
241 *dst++ ^= val;
242 /* Trailing bits */
243 if (last)
244 *dst = comp(*dst ^ val, *dst, last);
245 }
246}
247
248
249 /*
250 * Unaligned generic pattern invert using 32/64-bit memory accesses
251 * The pattern must have been expanded to a full 32/64-bit value
252 * Left/right are the appropriate shifts to convert to the pattern to be
253 * used for the next 32/64-bit word
254 */
255
256static void
257bitfill_unaligned_rev(unsigned long *dst, int dst_idx, unsigned long pat,
258 int left, int right, unsigned n, int bits)
259{
260 unsigned long first, last;
261
262 if (!n)
263 return;
264
265 first = FB_SHIFT_HIGH(~0UL, dst_idx);
266 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
267
268 if (dst_idx+n <= bits) {
269 /* Single word */
270 if (last)
271 first &= last;
272 *dst = comp(*dst ^ pat, *dst, first);
273 } else {
274 /* Multiple destination words */
275
276 /* Leading bits */
277 if (first != 0UL) {
278 *dst = comp(*dst ^ pat, *dst, first);
279 dst++;
280 pat = pat << left | pat >> right;
281 n -= bits - dst_idx;
282 }
283
284 /* Main chunk */
285 n /= bits;
286 while (n >= 4) {
287 *dst++ ^= pat;
288 pat = pat << left | pat >> right;
289 *dst++ ^= pat;
290 pat = pat << left | pat >> right;
291 *dst++ ^= pat;
292 pat = pat << left | pat >> right;
293 *dst++ ^= pat;
294 pat = pat << left | pat >> right;
295 n -= 4;
296 }
297 while (n--) {
298 *dst ^= pat;
299 pat = pat << left | pat >> right;
300 }
301
302 /* Trailing bits */
303 if (last)
304 *dst = comp(*dst ^ pat, *dst, last);
305 }
306}
307
308void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
309{
310 unsigned long pat, fg;
311 unsigned long width = rect->width, height = rect->height;
312 int bits = BITS_PER_LONG, bytes = bits >> 3;
313 u32 bpp = p->var.bits_per_pixel;
314 unsigned long *dst;
315 int dst_idx, left;
316
317 if (p->state != FBINFO_STATE_RUNNING)
318 return;
319
320 if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
321 p->fix.visual == FB_VISUAL_DIRECTCOLOR )
322 fg = ((u32 *) (p->pseudo_palette))[rect->color];
323 else
324 fg = rect->color;
325
326 pat = pixel_to_pat( bpp, fg);
327
328 dst = (unsigned long *)((unsigned long)p->screen_base & ~(bytes-1));
329 dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8;
330 dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp;
331 /* FIXME For now we support 1-32 bpp only */
332 left = bits % bpp;
333 if (p->fbops->fb_sync)
334 p->fbops->fb_sync(p);
335 if (!left) {
336 void (*fill_op32)(unsigned long *dst, int dst_idx,
337 unsigned long pat, unsigned n, int bits) =
338 NULL;
339
340 switch (rect->rop) {
341 case ROP_XOR:
342 fill_op32 = bitfill_aligned_rev;
343 break;
344 case ROP_COPY:
345 fill_op32 = bitfill_aligned;
346 break;
347 default:
348 printk( KERN_ERR "cfb_fillrect(): unknown rop, "
349 "defaulting to ROP_COPY\n");
350 fill_op32 = bitfill_aligned;
351 break;
352 }
353 while (height--) {
354 dst += dst_idx >> (ffs(bits) - 1);
355 dst_idx &= (bits - 1);
356 fill_op32(dst, dst_idx, pat, width*bpp, bits);
357 dst_idx += p->fix.line_length*8;
358 }
359 } else {
360 int right;
361 int r;
362 int rot = (left-dst_idx) % bpp;
363 void (*fill_op)(unsigned long *dst, int dst_idx,
364 unsigned long pat, int left, int right,
365 unsigned n, int bits) = NULL;
366
367 /* rotate pattern to correct start position */
368 pat = pat << rot | pat >> (bpp-rot);
369
370 right = bpp-left;
371 switch (rect->rop) {
372 case ROP_XOR:
373 fill_op = bitfill_unaligned_rev;
374 break;
375 case ROP_COPY:
376 fill_op = bitfill_unaligned;
377 break;
378 default:
379 printk(KERN_ERR "cfb_fillrect(): unknown rop, "
380 "defaulting to ROP_COPY\n");
381 fill_op = bitfill_unaligned;
382 break;
383 }
384 while (height--) {
385 dst += dst_idx >> (ffs(bits) - 1);
386 dst_idx &= (bits - 1);
387 fill_op(dst, dst_idx, pat, left, right,
388 width*bpp, bits);
389 r = (p->fix.line_length*8) % bpp;
390 pat = pat << (bpp-r) | pat >> r;
391 dst_idx += p->fix.line_length*8;
392 }
393 }
394}
395
396EXPORT_SYMBOL(sys_fillrect);
397
398MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
399MODULE_DESCRIPTION("Generic fill rectangle (sys-to-sys)");
400MODULE_LICENSE("GPL");