Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  *  Generic BitBLT function for frame buffer with packed pixels of any depth.
0003  *
0004  *      Copyright (C)  June 1999 James Simmons
0005  *
0006  *  This file is subject to the terms and conditions of the GNU General Public
0007  *  License.  See the file COPYING in the main directory of this archive for
0008  *  more details.
0009  *
0010  * NOTES:
0011  *
0012  *    This function copys a image from system memory to video memory. The
0013  *  image can be a bitmap where each 0 represents the background color and
0014  *  each 1 represents the foreground color. Great for font handling. It can
0015  *  also be a color image. This is determined by image_depth. The color image
0016  *  must be laid out exactly in the same format as the framebuffer. Yes I know
0017  *  their are cards with hardware that coverts images of various depths to the
0018  *  framebuffer depth. But not every card has this. All images must be rounded
0019  *  up to the nearest byte. For example a bitmap 12 bits wide must be two
0020  *  bytes width.
0021  *
0022  *  Tony:
0023  *  Incorporate mask tables similar to fbcon-cfb*.c in 2.4 API.  This speeds
0024  *  up the code significantly.
0025  *
0026  *  Code for depths not multiples of BITS_PER_LONG is still kludgy, which is
0027  *  still processed a bit at a time.
0028  *
0029  *  Also need to add code to deal with cards endians that are different than
0030  *  the native cpu endians. I also need to deal with MSB position in the word.
0031  */
0032 #include <linux/module.h>
0033 #include <linux/string.h>
0034 #include <linux/fb.h>
0035 #include <asm/types.h>
0036 #include "fb_draw.h"
0037 
0038 #define DEBUG
0039 
0040 #ifdef DEBUG
0041 #define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt,__func__,## args)
0042 #else
0043 #define DPRINTK(fmt, args...)
0044 #endif
0045 
0046 static const u32 cfb_tab8_be[] = {
0047     0x00000000,0x000000ff,0x0000ff00,0x0000ffff,
0048     0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff,
0049     0xff000000,0xff0000ff,0xff00ff00,0xff00ffff,
0050     0xffff0000,0xffff00ff,0xffffff00,0xffffffff
0051 };
0052 
0053 static const u32 cfb_tab8_le[] = {
0054     0x00000000,0xff000000,0x00ff0000,0xffff0000,
0055     0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00,
0056     0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff,
0057     0x0000ffff,0xff00ffff,0x00ffffff,0xffffffff
0058 };
0059 
0060 static const u32 cfb_tab16_be[] = {
0061     0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
0062 };
0063 
0064 static const u32 cfb_tab16_le[] = {
0065     0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff
0066 };
0067 
0068 static const u32 cfb_tab32[] = {
0069     0x00000000, 0xffffffff
0070 };
0071 
0072 #define FB_WRITEL fb_writel
0073 #define FB_READL  fb_readl
0074 
0075 static inline void color_imageblit(const struct fb_image *image,
0076                    struct fb_info *p, u8 __iomem *dst1,
0077                    u32 start_index,
0078                    u32 pitch_index)
0079 {
0080     /* Draw the penguin */
0081     u32 __iomem *dst, *dst2;
0082     u32 color = 0, val, shift;
0083     int i, n, bpp = p->var.bits_per_pixel;
0084     u32 null_bits = 32 - bpp;
0085     u32 *palette = (u32 *) p->pseudo_palette;
0086     const u8 *src = image->data;
0087     u32 bswapmask = fb_compute_bswapmask(p);
0088 
0089     dst2 = (u32 __iomem *) dst1;
0090     for (i = image->height; i--; ) {
0091         n = image->width;
0092         dst = (u32 __iomem *) dst1;
0093         shift = 0;
0094         val = 0;
0095 
0096         if (start_index) {
0097             u32 start_mask = ~fb_shifted_pixels_mask_u32(p,
0098                         start_index, bswapmask);
0099             val = FB_READL(dst) & start_mask;
0100             shift = start_index;
0101         }
0102         while (n--) {
0103             if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
0104                 p->fix.visual == FB_VISUAL_DIRECTCOLOR )
0105                 color = palette[*src];
0106             else
0107                 color = *src;
0108             color <<= FB_LEFT_POS(p, bpp);
0109             val |= FB_SHIFT_HIGH(p, color, shift ^ bswapmask);
0110             if (shift >= null_bits) {
0111                 FB_WRITEL(val, dst++);
0112 
0113                 val = (shift == null_bits) ? 0 :
0114                     FB_SHIFT_LOW(p, color, 32 - shift);
0115             }
0116             shift += bpp;
0117             shift &= (32 - 1);
0118             src++;
0119         }
0120         if (shift) {
0121             u32 end_mask = fb_shifted_pixels_mask_u32(p, shift,
0122                         bswapmask);
0123 
0124             FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
0125         }
0126         dst1 += p->fix.line_length;
0127         if (pitch_index) {
0128             dst2 += p->fix.line_length;
0129             dst1 = (u8 __iomem *)((long __force)dst2 & ~(sizeof(u32) - 1));
0130 
0131             start_index += pitch_index;
0132             start_index &= 32 - 1;
0133         }
0134     }
0135 }
0136 
0137 static inline void slow_imageblit(const struct fb_image *image, struct fb_info *p,
0138                   u8 __iomem *dst1, u32 fgcolor,
0139                   u32 bgcolor,
0140                   u32 start_index,
0141                   u32 pitch_index)
0142 {
0143     u32 shift, color = 0, bpp = p->var.bits_per_pixel;
0144     u32 __iomem *dst, *dst2;
0145     u32 val, pitch = p->fix.line_length;
0146     u32 null_bits = 32 - bpp;
0147     u32 spitch = (image->width+7)/8;
0148     const u8 *src = image->data, *s;
0149     u32 i, j, l;
0150     u32 bswapmask = fb_compute_bswapmask(p);
0151 
0152     dst2 = (u32 __iomem *) dst1;
0153     fgcolor <<= FB_LEFT_POS(p, bpp);
0154     bgcolor <<= FB_LEFT_POS(p, bpp);
0155 
0156     for (i = image->height; i--; ) {
0157         shift = val = 0;
0158         l = 8;
0159         j = image->width;
0160         dst = (u32 __iomem *) dst1;
0161         s = src;
0162 
0163         /* write leading bits */
0164         if (start_index) {
0165             u32 start_mask = ~fb_shifted_pixels_mask_u32(p,
0166                         start_index, bswapmask);
0167             val = FB_READL(dst) & start_mask;
0168             shift = start_index;
0169         }
0170 
0171         while (j--) {
0172             l--;
0173             color = (*s & (1 << l)) ? fgcolor : bgcolor;
0174             val |= FB_SHIFT_HIGH(p, color, shift ^ bswapmask);
0175 
0176             /* Did the bitshift spill bits to the next long? */
0177             if (shift >= null_bits) {
0178                 FB_WRITEL(val, dst++);
0179                 val = (shift == null_bits) ? 0 :
0180                     FB_SHIFT_LOW(p, color, 32 - shift);
0181             }
0182             shift += bpp;
0183             shift &= (32 - 1);
0184             if (!l) { l = 8; s++; }
0185         }
0186 
0187         /* write trailing bits */
0188         if (shift) {
0189             u32 end_mask = fb_shifted_pixels_mask_u32(p, shift,
0190                         bswapmask);
0191 
0192             FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
0193         }
0194 
0195         dst1 += pitch;
0196         src += spitch;
0197         if (pitch_index) {
0198             dst2 += pitch;
0199             dst1 = (u8 __iomem *)((long __force)dst2 & ~(sizeof(u32) - 1));
0200             start_index += pitch_index;
0201             start_index &= 32 - 1;
0202         }
0203 
0204     }
0205 }
0206 
0207 /*
0208  * fast_imageblit - optimized monochrome color expansion
0209  *
0210  * Only if:  bits_per_pixel == 8, 16, or 32
0211  *           image->width is divisible by pixel/dword (ppw);
0212  *           fix->line_legth is divisible by 4;
0213  *           beginning and end of a scanline is dword aligned
0214  */
0215 static inline void fast_imageblit(const struct fb_image *image, struct fb_info *p,
0216                   u8 __iomem *dst1, u32 fgcolor,
0217                   u32 bgcolor)
0218 {
0219     u32 fgx = fgcolor, bgx = bgcolor, bpp = p->var.bits_per_pixel;
0220     u32 ppw = 32/bpp, spitch = (image->width + 7)/8;
0221     u32 bit_mask, eorx, shift;
0222     const char *s = image->data, *src;
0223     u32 __iomem *dst;
0224     const u32 *tab = NULL;
0225     size_t tablen;
0226     u32 colortab[16];
0227     int i, j, k;
0228 
0229     switch (bpp) {
0230     case 8:
0231         tab = fb_be_math(p) ? cfb_tab8_be : cfb_tab8_le;
0232         tablen = 16;
0233         break;
0234     case 16:
0235         tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le;
0236         tablen = 4;
0237         break;
0238     case 32:
0239         tab = cfb_tab32;
0240         tablen = 2;
0241         break;
0242     default:
0243         return;
0244     }
0245 
0246     for (i = ppw-1; i--; ) {
0247         fgx <<= bpp;
0248         bgx <<= bpp;
0249         fgx |= fgcolor;
0250         bgx |= bgcolor;
0251     }
0252 
0253     bit_mask = (1 << ppw) - 1;
0254     eorx = fgx ^ bgx;
0255     k = image->width/ppw;
0256 
0257     for (i = 0; i < tablen; ++i)
0258         colortab[i] = (tab[i] & eorx) ^ bgx;
0259 
0260     for (i = image->height; i--; ) {
0261         dst = (u32 __iomem *)dst1;
0262         shift = 8;
0263         src = s;
0264 
0265         /*
0266          * Manually unroll the per-line copying loop for better
0267          * performance. This works until we processed the last
0268          * completely filled source byte (inclusive).
0269          */
0270         switch (ppw) {
0271         case 4: /* 8 bpp */
0272             for (j = k; j >= 2; j -= 2, ++src) {
0273                 FB_WRITEL(colortab[(*src >> 4) & bit_mask], dst++);
0274                 FB_WRITEL(colortab[(*src >> 0) & bit_mask], dst++);
0275             }
0276             break;
0277         case 2: /* 16 bpp */
0278             for (j = k; j >= 4; j -= 4, ++src) {
0279                 FB_WRITEL(colortab[(*src >> 6) & bit_mask], dst++);
0280                 FB_WRITEL(colortab[(*src >> 4) & bit_mask], dst++);
0281                 FB_WRITEL(colortab[(*src >> 2) & bit_mask], dst++);
0282                 FB_WRITEL(colortab[(*src >> 0) & bit_mask], dst++);
0283             }
0284             break;
0285         case 1: /* 32 bpp */
0286             for (j = k; j >= 8; j -= 8, ++src) {
0287                 FB_WRITEL(colortab[(*src >> 7) & bit_mask], dst++);
0288                 FB_WRITEL(colortab[(*src >> 6) & bit_mask], dst++);
0289                 FB_WRITEL(colortab[(*src >> 5) & bit_mask], dst++);
0290                 FB_WRITEL(colortab[(*src >> 4) & bit_mask], dst++);
0291                 FB_WRITEL(colortab[(*src >> 3) & bit_mask], dst++);
0292                 FB_WRITEL(colortab[(*src >> 2) & bit_mask], dst++);
0293                 FB_WRITEL(colortab[(*src >> 1) & bit_mask], dst++);
0294                 FB_WRITEL(colortab[(*src >> 0) & bit_mask], dst++);
0295             }
0296             break;
0297         }
0298 
0299         /*
0300          * For image widths that are not a multiple of 8, there
0301          * are trailing pixels left on the current line. Print
0302          * them as well.
0303          */
0304         for (; j--; ) {
0305             shift -= ppw;
0306             FB_WRITEL(colortab[(*src >> shift) & bit_mask], dst++);
0307             if (!shift) {
0308                 shift = 8;
0309                 ++src;
0310             }
0311         }
0312 
0313         dst1 += p->fix.line_length;
0314         s += spitch;
0315     }
0316 }
0317 
0318 void cfb_imageblit(struct fb_info *p, const struct fb_image *image)
0319 {
0320     u32 fgcolor, bgcolor, start_index, bitstart, pitch_index = 0;
0321     u32 bpl = sizeof(u32), bpp = p->var.bits_per_pixel;
0322     u32 width = image->width;
0323     u32 dx = image->dx, dy = image->dy;
0324     u8 __iomem *dst1;
0325 
0326     if (p->state != FBINFO_STATE_RUNNING)
0327         return;
0328 
0329     bitstart = (dy * p->fix.line_length * 8) + (dx * bpp);
0330     start_index = bitstart & (32 - 1);
0331     pitch_index = (p->fix.line_length & (bpl - 1)) * 8;
0332 
0333     bitstart /= 8;
0334     bitstart &= ~(bpl - 1);
0335     dst1 = p->screen_base + bitstart;
0336 
0337     if (p->fbops->fb_sync)
0338         p->fbops->fb_sync(p);
0339 
0340     if (image->depth == 1) {
0341         if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
0342             p->fix.visual == FB_VISUAL_DIRECTCOLOR) {
0343             fgcolor = ((u32*)(p->pseudo_palette))[image->fg_color];
0344             bgcolor = ((u32*)(p->pseudo_palette))[image->bg_color];
0345         } else {
0346             fgcolor = image->fg_color;
0347             bgcolor = image->bg_color;
0348         }
0349 
0350         if (32 % bpp == 0 && !start_index && !pitch_index &&
0351             ((width & (32/bpp-1)) == 0) &&
0352             bpp >= 8 && bpp <= 32)
0353             fast_imageblit(image, p, dst1, fgcolor, bgcolor);
0354         else
0355             slow_imageblit(image, p, dst1, fgcolor, bgcolor,
0356                     start_index, pitch_index);
0357     } else
0358         color_imageblit(image, p, dst1, start_index, pitch_index);
0359 }
0360 
0361 EXPORT_SYMBOL(cfb_imageblit);
0362 
0363 MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
0364 MODULE_DESCRIPTION("Generic software accelerated imaging drawing");
0365 MODULE_LICENSE("GPL");
0366