Branch data Line data Source code
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 : : #include "fb_draw.h"
19 : :
20 : : /*
21 : : * Aligned pattern fill using 32/64-bit memory accesses
22 : : */
23 : :
24 : : static void
25 : 0 : bitfill_aligned(struct fb_info *p, unsigned long *dst, int dst_idx,
26 : : unsigned long pat, unsigned n, int bits)
27 : : {
28 : 0 : unsigned long first, last;
29 : :
30 [ # # ]: 0 : if (!n)
31 : : return;
32 : :
33 [ # # ]: 0 : first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
34 : 0 : last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
35 : :
36 [ # # ]: 0 : if (dst_idx+n <= bits) {
37 : : /* Single word */
38 [ # # ]: 0 : if (last)
39 : 0 : first &= last;
40 : 0 : *dst = comp(pat, *dst, first);
41 : : } else {
42 : : /* Multiple destination words */
43 : :
44 : : /* Leading bits */
45 [ # # ]: 0 : if (first!= ~0UL) {
46 : 0 : *dst = comp(pat, *dst, first);
47 : 0 : dst++;
48 : 0 : n -= bits - dst_idx;
49 : : }
50 : :
51 : : /* Main chunk */
52 : 0 : n /= bits;
53 [ # # ]: 0 : while (n >= 8) {
54 : 0 : *dst++ = pat;
55 : 0 : *dst++ = pat;
56 : 0 : *dst++ = pat;
57 : 0 : *dst++ = pat;
58 : 0 : *dst++ = pat;
59 : 0 : *dst++ = pat;
60 : 0 : *dst++ = pat;
61 : 0 : *dst++ = pat;
62 : 0 : n -= 8;
63 : : }
64 [ # # ]: 0 : while (n--)
65 : 0 : *dst++ = pat;
66 : : /* Trailing bits */
67 [ # # ]: 0 : if (last)
68 : 0 : *dst = comp(pat, *dst, last);
69 : : }
70 : : }
71 : :
72 : :
73 : : /*
74 : : * Unaligned generic pattern fill using 32/64-bit memory accesses
75 : : * The pattern must have been expanded to a full 32/64-bit value
76 : : * Left/right are the appropriate shifts to convert to the pattern to be
77 : : * used for the next 32/64-bit word
78 : : */
79 : :
80 : : static void
81 : 0 : bitfill_unaligned(struct fb_info *p, unsigned long *dst, int dst_idx,
82 : : unsigned long pat, int left, int right, unsigned n, int bits)
83 : : {
84 : 0 : unsigned long first, last;
85 : :
86 [ # # ]: 0 : if (!n)
87 : : return;
88 : :
89 [ # # ]: 0 : first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
90 : 0 : last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
91 : :
92 [ # # ]: 0 : if (dst_idx+n <= bits) {
93 : : /* Single word */
94 [ # # ]: 0 : if (last)
95 : 0 : first &= last;
96 : 0 : *dst = comp(pat, *dst, first);
97 : : } else {
98 : : /* Multiple destination words */
99 : : /* Leading bits */
100 [ # # ]: 0 : if (first) {
101 : 0 : *dst = comp(pat, *dst, first);
102 : 0 : dst++;
103 : 0 : pat = pat << left | pat >> right;
104 : 0 : n -= bits - dst_idx;
105 : : }
106 : :
107 : : /* Main chunk */
108 : 0 : n /= bits;
109 [ # # ]: 0 : while (n >= 4) {
110 : 0 : *dst++ = pat;
111 : 0 : pat = pat << left | pat >> right;
112 : 0 : *dst++ = pat;
113 : 0 : pat = pat << left | pat >> right;
114 : 0 : *dst++ = pat;
115 : 0 : pat = pat << left | pat >> right;
116 : 0 : *dst++ = pat;
117 : 0 : pat = pat << left | pat >> right;
118 : 0 : n -= 4;
119 : : }
120 [ # # ]: 0 : while (n--) {
121 : 0 : *dst++ = pat;
122 : 0 : pat = pat << left | pat >> right;
123 : : }
124 : :
125 : : /* Trailing bits */
126 [ # # ]: 0 : if (last)
127 : 0 : *dst = comp(pat, *dst, last);
128 : : }
129 : : }
130 : :
131 : : /*
132 : : * Aligned pattern invert using 32/64-bit memory accesses
133 : : */
134 : : static void
135 : 0 : bitfill_aligned_rev(struct fb_info *p, unsigned long *dst, int dst_idx,
136 : : unsigned long pat, unsigned n, int bits)
137 : : {
138 : 0 : unsigned long val = pat;
139 : 0 : unsigned long first, last;
140 : :
141 [ # # ]: 0 : if (!n)
142 : : return;
143 : :
144 [ # # ]: 0 : first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
145 : 0 : last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
146 : :
147 [ # # ]: 0 : if (dst_idx+n <= bits) {
148 : : /* Single word */
149 [ # # ]: 0 : if (last)
150 : 0 : first &= last;
151 : 0 : *dst = comp(*dst ^ val, *dst, first);
152 : : } else {
153 : : /* Multiple destination words */
154 : : /* Leading bits */
155 [ # # ]: 0 : if (first!=0UL) {
156 : 0 : *dst = comp(*dst ^ val, *dst, first);
157 : 0 : dst++;
158 : 0 : n -= bits - dst_idx;
159 : : }
160 : :
161 : : /* Main chunk */
162 : 0 : n /= bits;
163 [ # # ]: 0 : while (n >= 8) {
164 : 0 : *dst++ ^= val;
165 : 0 : *dst++ ^= val;
166 : 0 : *dst++ ^= val;
167 : 0 : *dst++ ^= val;
168 : 0 : *dst++ ^= val;
169 : 0 : *dst++ ^= val;
170 : 0 : *dst++ ^= val;
171 : 0 : *dst++ ^= val;
172 : 0 : n -= 8;
173 : : }
174 [ # # ]: 0 : while (n--)
175 : 0 : *dst++ ^= val;
176 : : /* Trailing bits */
177 [ # # ]: 0 : if (last)
178 : 0 : *dst = comp(*dst ^ val, *dst, last);
179 : : }
180 : : }
181 : :
182 : :
183 : : /*
184 : : * Unaligned generic pattern invert using 32/64-bit memory accesses
185 : : * The pattern must have been expanded to a full 32/64-bit value
186 : : * Left/right are the appropriate shifts to convert to the pattern to be
187 : : * used for the next 32/64-bit word
188 : : */
189 : :
190 : : static void
191 : 0 : bitfill_unaligned_rev(struct fb_info *p, unsigned long *dst, int dst_idx,
192 : : unsigned long pat, int left, int right, unsigned n,
193 : : int bits)
194 : : {
195 : 0 : unsigned long first, last;
196 : :
197 [ # # ]: 0 : if (!n)
198 : : return;
199 : :
200 [ # # ]: 0 : first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
201 : 0 : last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
202 : :
203 [ # # ]: 0 : if (dst_idx+n <= bits) {
204 : : /* Single word */
205 [ # # ]: 0 : if (last)
206 : 0 : first &= last;
207 : 0 : *dst = comp(*dst ^ pat, *dst, first);
208 : : } else {
209 : : /* Multiple destination words */
210 : :
211 : : /* Leading bits */
212 [ # # ]: 0 : if (first != 0UL) {
213 : 0 : *dst = comp(*dst ^ pat, *dst, first);
214 : 0 : dst++;
215 : 0 : pat = pat << left | pat >> right;
216 : 0 : n -= bits - dst_idx;
217 : : }
218 : :
219 : : /* Main chunk */
220 : 0 : n /= bits;
221 [ # # ]: 0 : while (n >= 4) {
222 : 0 : *dst++ ^= pat;
223 : 0 : pat = pat << left | pat >> right;
224 : 0 : *dst++ ^= pat;
225 : 0 : pat = pat << left | pat >> right;
226 : 0 : *dst++ ^= pat;
227 : 0 : pat = pat << left | pat >> right;
228 : 0 : *dst++ ^= pat;
229 : 0 : pat = pat << left | pat >> right;
230 : 0 : n -= 4;
231 : : }
232 [ # # ]: 0 : while (n--) {
233 : 0 : *dst ^= pat;
234 : 0 : pat = pat << left | pat >> right;
235 : : }
236 : :
237 : : /* Trailing bits */
238 [ # # ]: 0 : if (last)
239 : 0 : *dst = comp(*dst ^ pat, *dst, last);
240 : : }
241 : : }
242 : :
243 : 0 : void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
244 : : {
245 : 0 : unsigned long pat, pat2, fg;
246 : 0 : unsigned long width = rect->width, height = rect->height;
247 : 0 : int bits = BITS_PER_LONG, bytes = bits >> 3;
248 : 0 : u32 bpp = p->var.bits_per_pixel;
249 : 0 : unsigned long *dst;
250 : 0 : int dst_idx, left;
251 : :
252 [ # # ]: 0 : if (p->state != FBINFO_STATE_RUNNING)
253 : : return;
254 : :
255 [ # # ]: 0 : if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
256 : : p->fix.visual == FB_VISUAL_DIRECTCOLOR )
257 : 0 : fg = ((u32 *) (p->pseudo_palette))[rect->color];
258 : : else
259 : 0 : fg = rect->color;
260 : :
261 : 0 : pat = pixel_to_pat( bpp, fg);
262 : :
263 : 0 : dst = (unsigned long *)((unsigned long)p->screen_base & ~(bytes-1));
264 : 0 : dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8;
265 : 0 : dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp;
266 : : /* FIXME For now we support 1-32 bpp only */
267 : 0 : left = bits % bpp;
268 [ # # ]: 0 : if (p->fbops->fb_sync)
269 : 0 : p->fbops->fb_sync(p);
270 [ # # ]: 0 : if (!left) {
271 : 0 : void (*fill_op32)(struct fb_info *p, unsigned long *dst,
272 : : int dst_idx, unsigned long pat, unsigned n,
273 : : int bits) = NULL;
274 : :
275 [ # # # ]: 0 : switch (rect->rop) {
276 : : case ROP_XOR:
277 : : fill_op32 = bitfill_aligned_rev;
278 : : break;
279 : 0 : case ROP_COPY:
280 : 0 : fill_op32 = bitfill_aligned;
281 : 0 : break;
282 : 0 : default:
283 : 0 : printk( KERN_ERR "cfb_fillrect(): unknown rop, "
284 : : "defaulting to ROP_COPY\n");
285 : 0 : fill_op32 = bitfill_aligned;
286 : 0 : break;
287 : : }
288 [ # # ]: 0 : while (height--) {
289 : 0 : dst += dst_idx >> (ffs(bits) - 1);
290 : 0 : dst_idx &= (bits - 1);
291 : 0 : fill_op32(p, dst, dst_idx, pat, width*bpp, bits);
292 : 0 : dst_idx += p->fix.line_length*8;
293 : : }
294 : : } else {
295 : 0 : int right, r;
296 : 0 : void (*fill_op)(struct fb_info *p, unsigned long *dst,
297 : : int dst_idx, unsigned long pat, int left,
298 : : int right, unsigned n, int bits) = NULL;
299 : : #ifdef __LITTLE_ENDIAN
300 : 0 : right = left;
301 : 0 : left = bpp - right;
302 : : #else
303 : : right = bpp - left;
304 : : #endif
305 [ # # # ]: 0 : switch (rect->rop) {
306 : : case ROP_XOR:
307 : : fill_op = bitfill_unaligned_rev;
308 : : break;
309 : 0 : case ROP_COPY:
310 : 0 : fill_op = bitfill_unaligned;
311 : 0 : break;
312 : 0 : default:
313 : 0 : printk(KERN_ERR "sys_fillrect(): unknown rop, "
314 : : "defaulting to ROP_COPY\n");
315 : 0 : fill_op = bitfill_unaligned;
316 : 0 : break;
317 : : }
318 [ # # ]: 0 : while (height--) {
319 : 0 : dst += dst_idx / bits;
320 : 0 : dst_idx &= (bits - 1);
321 : 0 : r = dst_idx % bpp;
322 : : /* rotate pattern to the correct start position */
323 : 0 : pat2 = le_long_to_cpu(rolx(cpu_to_le_long(pat), r, bpp));
324 : 0 : fill_op(p, dst, dst_idx, pat2, left, right,
325 : : width*bpp, bits);
326 : 0 : dst_idx += p->fix.line_length*8;
327 : : }
328 : : }
329 : : }
330 : :
331 : : EXPORT_SYMBOL(sys_fillrect);
332 : :
333 : : MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
334 : : MODULE_DESCRIPTION("Generic fill rectangle (sys-to-sys)");
335 : : MODULE_LICENSE("GPL");
|