]> pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/video/sysfillrect.c
fbdev: add drawing functions for framebuffers in system RAM
[linux-2.6-omap-h63xx.git] / drivers / video / sysfillrect.c
1 /*
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
24 static inline unsigned long
25 comp(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
35 static inline unsigned long
36 pixel_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
60 static inline unsigned long
61 pixel_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
90 static void
91 bitfill_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
146 static void
147 bitfill_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      */
200 static void
201 bitfill_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
256 static void
257 bitfill_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
308 void 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
396 EXPORT_SYMBOL(sys_fillrect);
397
398 MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
399 MODULE_DESCRIPTION("Generic fill rectangle (sys-to-sys)");
400 MODULE_LICENSE("GPL");