Subversion Repositories shark

Rev

Rev 468 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
468 giacomo 1
/*
2
 *  Generic fillrect for frame buffers with packed pixels of any depth.
3
 *
4
 *      Copyright (C)  2000 James Simmons (jsimmons@linux-fbdev.org)
5
 *
6
 *  This file is subject to the terms and conditions of the GNU General Public
7
 *  License.  See the file COPYING in the main directory of this archive for
8
 *  more details.
9
 *
10
 * NOTES:
11
 *
12
 *  The code for depths like 24 that don't have integer number of pixels per
13
 *  long is broken and needs to be fixed. For now I turned these types of
14
 *  mode off.
15
 *
16
 *  Also need to add code to deal with cards endians that are different than
17
 *  the native cpu endians. I also need to deal with MSB position in the word.
18
 *
19
 */
20
 
21
#include <linuxcomp.h>
22
 
23
#include <linux/config.h>
24
#include <linux/module.h>
25
#include <linux/string.h>
26
#include <linux/fb.h>
27
#include <asm/types.h>
28
 
29
#if BITS_PER_LONG == 32
30
#define FB_WRITEL fb_writel
31
#define FB_READL  fb_readl
32
#define BYTES_PER_LONG 4
33
#define SHIFT_PER_LONG 5
34
#else
35
#define FB_WRITEL fb_writeq
36
#define FB_READL  fb_readq
37
#define BYTES_PER_LONG 8
38
#define SHIFT_PER_LONG 6
39
#endif
40
 
41
#define EXP1(x)         0xffffffffU*x
42
#define EXP2(x)         0x55555555U*x
43
#define EXP4(x)         0x11111111U*0x ## x
44
 
45
typedef u32 pixel_t;
46
 
47
static const u32 bpp1tab[2] = {
48
    EXP1(0), EXP1(1)
49
};
50
 
51
static const u32 bpp2tab[4] = {
52
    EXP2(0), EXP2(1), EXP2(2), EXP2(3)
53
};
54
 
55
static const u32 bpp4tab[16] = {
56
    EXP4(0), EXP4(1), EXP4(2), EXP4(3), EXP4(4), EXP4(5), EXP4(6), EXP4(7),
57
    EXP4(8), EXP4(9), EXP4(a), EXP4(b), EXP4(c), EXP4(d), EXP4(e), EXP4(f)
58
};
59
 
60
    /*
61
     *  Compose two values, using a bitmask as decision value
62
     *  This is equivalent to (a & mask) | (b & ~mask)
63
     */
64
 
65
static inline unsigned long comp(unsigned long a, unsigned long b,
66
                                 unsigned long mask)
67
{
68
    return ((a ^ b) & mask) ^ b;
69
}
70
 
71
static inline u32 pixel_to_pat32(const struct fb_info *p, pixel_t pixel)
72
{
73
    u32 pat = pixel;
74
 
75
    switch (p->var.bits_per_pixel) {
76
        case 1:
77
            pat = bpp1tab[pat];
78
            break;
79
 
80
        case 2:
81
            pat = bpp2tab[pat];
82
            break;
83
 
84
        case 4:
85
            pat = bpp4tab[pat];
86
            break;
87
 
88
        case 8:
89
            pat |= pat << 8;
90
            // Fall through
91
        case 16:
92
            pat |= pat << 16;
93
            // Fall through
94
        case 32:
95
            break;
96
    }
97
    return pat;
98
}
99
 
100
    /*
101
     *  Expand a pixel value to a generic 32/64-bit pattern and rotate it to
102
     *  the correct start position
103
     */
104
 
105
static inline unsigned long pixel_to_pat(const struct fb_info *p,
106
                                         pixel_t pixel, int left)
107
{
108
    unsigned long pat = pixel;
109
    u32 bpp = p->var.bits_per_pixel;
110
    int i;
111
 
112
    /* expand pixel value */
113
    for (i = bpp; i < BITS_PER_LONG; i *= 2)
114
        pat |= pat << i;
115
 
116
    /* rotate pattern to correct start position */
117
    pat = pat << left | pat >> (bpp-left);
118
    return pat;
119
}
120
 
121
    /*
122
     *  Unaligned 32-bit pattern fill using 32/64-bit memory accesses
123
     */
124
 
125
void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n)
126
{
127
        unsigned long val = pat;
128
        unsigned long first, last;
129
 
130
        if (!n)
131
                return;
132
 
133
#if BITS_PER_LONG == 64
134
        val |= val << 32;
135
#endif
136
 
137
        first = ~0UL >> dst_idx;
138
        last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
139
 
140
        if (dst_idx+n <= BITS_PER_LONG) {
141
                // Single word
142
                if (last)
143
                        first &= last;
144
                FB_WRITEL(comp(val, FB_READL(dst), first), dst);
145
        } else {
146
                // Multiple destination words
147
                // Leading bits
148
                if (first) {
149
                        FB_WRITEL(comp(val, FB_READL(dst), first), dst);
150
                        dst++;
151
                        n -= BITS_PER_LONG-dst_idx;
152
                }
153
 
154
                // Main chunk
155
                n /= BITS_PER_LONG;
156
                while (n >= 8) {
157
                        FB_WRITEL(val, dst++);
158
                        FB_WRITEL(val, dst++);
159
                        FB_WRITEL(val, dst++);
160
                        FB_WRITEL(val, dst++);
161
                        FB_WRITEL(val, dst++);
162
                        FB_WRITEL(val, dst++);
163
                        FB_WRITEL(val, dst++);
164
                        FB_WRITEL(val, dst++);
165
                        n -= 8;
166
                }
167
                while (n--)
168
                        FB_WRITEL(val, dst++);
169
 
170
                // Trailing bits
171
                if (last)
172
                        FB_WRITEL(comp(val, FB_READL(dst), first), dst);
173
        }
174
}
175
 
176
 
177
    /*
178
     *  Unaligned generic pattern fill using 32/64-bit memory accesses
179
     *  The pattern must have been expanded to a full 32/64-bit value
180
     *  Left/right are the appropriate shifts to convert to the pattern to be
181
     *  used for the next 32/64-bit word
182
     */
183
 
184
void bitfill(unsigned long *dst, int dst_idx, unsigned long pat, int left,
185
             int right, u32 n)
186
{
187
        unsigned long first, last;
188
 
189
        if (!n)
190
                return;
191
 
192
        first = ~0UL >> dst_idx;
193
        last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
194
 
195
        if (dst_idx+n <= BITS_PER_LONG) {
196
                // Single word
197
                if (last)
198
                        first &= last;
199
                FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
200
        } else {
201
                // Multiple destination words
202
                // Leading bits
203
                if (first) {
204
                        FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
205
                        dst++;
206
                        pat = pat << left | pat >> right;
207
                        n -= BITS_PER_LONG-dst_idx;
208
                }
209
 
210
                // Main chunk
211
                n /= BITS_PER_LONG;
212
                while (n >= 4) {
213
                        FB_WRITEL(pat, dst++);
214
                        pat = pat << left | pat >> right;
215
                        FB_WRITEL(pat, dst++);
216
                        pat = pat << left | pat >> right;
217
                        FB_WRITEL(pat, dst++);
218
                        pat = pat << left | pat >> right;
219
                        FB_WRITEL(pat, dst++);
220
                        pat = pat << left | pat >> right;
221
                        n -= 4;
222
                }
223
                while (n--) {
224
                        FB_WRITEL(pat, dst++);
225
                        pat = pat << left | pat >> right;
226
                }
227
 
228
                // Trailing bits
229
                if (last)
230
                        FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
231
        }
232
}
233
 
234
void bitfill32_rev(unsigned long *dst, int dst_idx, u32 pat, u32 n)
235
{
236
        unsigned long val = pat, dat;
237
        unsigned long first, last;
238
 
239
        if (!n)
240
                return;
241
 
242
#if BITS_PER_LONG == 64
243
        val |= val << 32;
244
#endif
245
 
246
        first = ~0UL >> dst_idx;
247
        last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
248
 
249
        if (dst_idx+n <= BITS_PER_LONG) {
250
                // Single word
251
                if (last)
252
                        first &= last;
253
                dat = FB_READL(dst);
254
                FB_WRITEL(comp(dat ^ val, dat, first), dst);
255
        } else {
256
                // Multiple destination words
257
                // Leading bits
258
                if (first) {
259
                        dat = FB_READL(dst);
260
                        FB_WRITEL(comp(dat ^ val, dat, first), dst);
261
                        dst++;
262
                        n -= BITS_PER_LONG-dst_idx;
263
                }
264
 
265
                // Main chunk
266
                n /= BITS_PER_LONG;
267
                while (n >= 8) {
268
                        FB_WRITEL(FB_READL(dst) ^ val, dst);
269
                        dst++;
270
                        FB_WRITEL(FB_READL(dst) ^ val, dst);
271
                        dst++;
272
                        FB_WRITEL(FB_READL(dst) ^ val, dst);
273
                        dst++;
274
                        FB_WRITEL(FB_READL(dst) ^ val, dst);
275
                        dst++;
276
                        FB_WRITEL(FB_READL(dst) ^ val, dst);
277
                        dst++;
278
                        FB_WRITEL(FB_READL(dst) ^ val, dst);
279
                        dst++;
280
                        FB_WRITEL(FB_READL(dst) ^ val, dst);
281
                        dst++;
282
                        FB_WRITEL(FB_READL(dst) ^ val, dst);
283
                        dst++;
284
                        n -= 8;
285
                }
286
                while (n--) {
287
                        FB_WRITEL(FB_READL(dst) ^ val, dst);
288
                        dst++;
289
                }              
290
                // Trailing bits
291
                if (last) {
292
                        dat = FB_READL(dst);
293
                        FB_WRITEL(comp(dat ^ val, dat, first), dst);
294
                }
295
        }
296
}
297
 
298
 
299
    /*
300
     *  Unaligned generic pattern fill using 32/64-bit memory accesses
301
     *  The pattern must have been expanded to a full 32/64-bit value
302
     *  Left/right are the appropriate shifts to convert to the pattern to be
303
     *  used for the next 32/64-bit word
304
     */
305
 
306
void bitfill_rev(unsigned long *dst, int dst_idx, unsigned long pat, int left,
307
             int right, u32 n)
308
{
309
        unsigned long first, last, dat;
310
 
311
        if (!n)
312
                return;
313
 
314
        first = ~0UL >> dst_idx;
315
        last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
316
 
317
        if (dst_idx+n <= BITS_PER_LONG) {
318
                // Single word
319
                if (last)
320
                        first &= last;
321
                dat = FB_READL(dst);
322
                FB_WRITEL(comp(dat ^ pat, dat, first), dst);
323
        } else {
324
                // Multiple destination words
325
                // Leading bits
326
                if (first) {
327
                        dat = FB_READL(dst);
328
                        FB_WRITEL(comp(dat ^ pat, dat, first), dst);
329
                        dst++;
330
                        pat = pat << left | pat >> right;
331
                        n -= BITS_PER_LONG-dst_idx;
332
                }
333
 
334
                // Main chunk
335
                n /= BITS_PER_LONG;
336
                while (n >= 4) {
337
                        FB_WRITEL(FB_READL(dst) ^ pat, dst);
338
                        dst++;
339
                        pat = pat << left | pat >> right;
340
                        FB_WRITEL(FB_READL(dst) ^ pat, dst);
341
                        dst++;
342
                        pat = pat << left | pat >> right;
343
                        FB_WRITEL(FB_READL(dst) ^ pat, dst);
344
                        dst++;
345
                        pat = pat << left | pat >> right;
346
                        FB_WRITEL(FB_READL(dst) ^ pat, dst);
347
                        dst++;
348
                        pat = pat << left | pat >> right;
349
                        n -= 4;
350
                }
351
                while (n--) {
352
                        FB_WRITEL(FB_READL(dst) ^ pat, dst);
353
                        dst++;
354
                        pat = pat << left | pat >> right;
355
                }
356
 
357
                // Trailing bits
358
                if (last) {
359
                        dat = FB_READL(dst);
360
                        FB_WRITEL(comp(dat ^ pat, dat, first), dst);
361
                }
362
        }
363
}
364
 
365
void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
366
{
367
        u32 bpp = p->var.bits_per_pixel;
368
        unsigned long x2, y2, vxres, vyres;
369
        unsigned long height, width, fg;
370
        unsigned long *dst;
371
        int dst_idx, left;
372
 
373
        /* We want rotation but lack hardware to do it for us. */
374
        if (!p->fbops->fb_rotate && p->var.rotate) {
375
        }      
376
 
377
        vxres = p->var.xres_virtual;
378
        vyres = p->var.yres_virtual;
379
 
380
        if (!rect->width || !rect->height ||
381
            rect->dx > vxres || rect->dy > vyres)
382
                return;
383
 
384
        /* We could use hardware clipping but on many cards you get around
385
         * hardware clipping by writing to framebuffer directly. */
386
 
387
        x2 = rect->dx + rect->width;
388
        y2 = rect->dy + rect->height;
389
        x2 = x2 < vxres ? x2 : vxres;
390
        y2 = y2 < vyres ? y2 : vyres;
391
        width = x2 - rect->dx;
392
        height = y2 - rect->dy;
393
 
487 giacomo 394
        if (!(p->fix.visual == FB_VISUAL_TRUECOLOR ||
395
            p->fix.visual == FB_VISUAL_DIRECTCOLOR ))
468 giacomo 396
                fg = ((u32 *) (p->pseudo_palette))[rect->color];
397
        else
398
                fg = rect->color;
399
 
400
        dst = (unsigned long *)((unsigned long)p->screen_base &
401
                                ~(BYTES_PER_LONG-1));
402
        dst_idx = ((unsigned long)p->screen_base & (BYTES_PER_LONG-1))*8;
403
        dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp;
404
        /* FIXME For now we support 1-32 bpp only */
405
        left = BITS_PER_LONG % bpp;
406
        if (p->fbops->fb_sync)
407
                p->fbops->fb_sync(p);
408
        if (!left) {
409
                u32 pat = pixel_to_pat32(p, fg);
410
                void (*fill_op32)(unsigned long *dst, int dst_idx, u32 pat,
411
                                  u32 n) = NULL;
412
 
413
                switch (rect->rop) {
414
                case ROP_XOR:
415
                        fill_op32 = bitfill32_rev;
416
                        break;
417
                case ROP_COPY:
418
                default:
419
                        fill_op32 = bitfill32;
420
                        break;
421
                }
422
                while (height--) {
423
                        dst += dst_idx >> SHIFT_PER_LONG;
424
                        dst_idx &= (BITS_PER_LONG-1);
425
                        fill_op32(dst, dst_idx, pat, width*bpp);
426
                        dst_idx += p->fix.line_length*8;
427
                }
428
        } else {
429
                unsigned long pat = pixel_to_pat(p, fg, (left-dst_idx) % bpp);
430
                int right = bpp-left;
431
                int r;
432
                void (*fill_op)(unsigned long *dst, int dst_idx,
433
                                unsigned long pat, int left, int right,
434
                                u32 n) = NULL;
435
 
436
                switch (rect->rop) {
437
                case ROP_XOR:
438
                        fill_op = bitfill_rev;
439
                        break;
440
                case ROP_COPY:
441
                default:
442
                        fill_op = bitfill;
443
                        break;
444
                }
445
                while (height--) {
446
                        dst += dst_idx >> SHIFT_PER_LONG;
447
                        dst_idx &= (BITS_PER_LONG-1);
448
                        fill_op(dst, dst_idx, pat, left, right,
449
                                width*bpp);
450
                        r = (p->fix.line_length*8) % bpp;
451
                        pat = pat << (bpp-r) | pat >> r;
452
                        dst_idx += p->fix.line_length*8;
453
                }
454
        }
455
}
456
 
457
EXPORT_SYMBOL(cfb_fillrect);
458
 
459
MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
460
MODULE_DESCRIPTION("Generic software accelerated fill rectangle");
461
MODULE_LICENSE("GPL");