linux/drivers/video/fbdev/core/sysimgblt.c
<<
>>
Prefs
   1/*
   2 *  Generic 1-bit or 8-bit source to 1-32 bit destination expansion
   3 *  for frame buffer located in system RAM with packed pixels of any depth.
   4 *
   5 *  Based almost entirely on cfbimgblt.c
   6 *
   7 *      Copyright (C)  April 2007 Antonino Daplas <adaplas@pol.net>
   8 *
   9 *  This file is subject to the terms and conditions of the GNU General Public
  10 *  License.  See the file COPYING in the main directory of this archive for
  11 *  more details.
  12 */
  13#include <linux/module.h>
  14#include <linux/string.h>
  15#include <linux/fb.h>
  16#include <asm/types.h>
  17
  18#define DEBUG
  19
  20#ifdef DEBUG
  21#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt,__func__,## args)
  22#else
  23#define DPRINTK(fmt, args...)
  24#endif
  25
  26static const u32 cfb_tab8_be[] = {
  27    0x00000000,0x000000ff,0x0000ff00,0x0000ffff,
  28    0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff,
  29    0xff000000,0xff0000ff,0xff00ff00,0xff00ffff,
  30    0xffff0000,0xffff00ff,0xffffff00,0xffffffff
  31};
  32
  33static const u32 cfb_tab8_le[] = {
  34    0x00000000,0xff000000,0x00ff0000,0xffff0000,
  35    0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00,
  36    0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff,
  37    0x0000ffff,0xff00ffff,0x00ffffff,0xffffffff
  38};
  39
  40static const u32 cfb_tab16_be[] = {
  41    0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
  42};
  43
  44static const u32 cfb_tab16_le[] = {
  45    0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff
  46};
  47
  48static const u32 cfb_tab32[] = {
  49        0x00000000, 0xffffffff
  50};
  51
  52static void color_imageblit(const struct fb_image *image, struct fb_info *p,
  53                            void *dst1, u32 start_index, u32 pitch_index)
  54{
  55        /* Draw the penguin */
  56        u32 *dst, *dst2;
  57        u32 color = 0, val, shift;
  58        int i, n, bpp = p->var.bits_per_pixel;
  59        u32 null_bits = 32 - bpp;
  60        u32 *palette = (u32 *) p->pseudo_palette;
  61        const u8 *src = image->data;
  62
  63        dst2 = dst1;
  64        for (i = image->height; i--; ) {
  65                n = image->width;
  66                dst = dst1;
  67                shift = 0;
  68                val = 0;
  69
  70                if (start_index) {
  71                        u32 start_mask = ~(FB_SHIFT_HIGH(p, ~(u32)0,
  72                                                         start_index));
  73                        val = *dst & start_mask;
  74                        shift = start_index;
  75                }
  76                while (n--) {
  77                        if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
  78                            p->fix.visual == FB_VISUAL_DIRECTCOLOR )
  79                                color = palette[*src];
  80                        else
  81                                color = *src;
  82                        color <<= FB_LEFT_POS(p, bpp);
  83                        val |= FB_SHIFT_HIGH(p, color, shift);
  84                        if (shift >= null_bits) {
  85                                *dst++ = val;
  86
  87                                val = (shift == null_bits) ? 0 :
  88                                        FB_SHIFT_LOW(p, color, 32 - shift);
  89                        }
  90                        shift += bpp;
  91                        shift &= (32 - 1);
  92                        src++;
  93                }
  94                if (shift) {
  95                        u32 end_mask = FB_SHIFT_HIGH(p, ~(u32)0, shift);
  96
  97                        *dst &= end_mask;
  98                        *dst |= val;
  99                }
 100                dst1 += p->fix.line_length;
 101                if (pitch_index) {
 102                        dst2 += p->fix.line_length;
 103                        dst1 = (u8 *)((long)dst2 & ~(sizeof(u32) - 1));
 104
 105                        start_index += pitch_index;
 106                        start_index &= 32 - 1;
 107                }
 108        }
 109}
 110
 111static void slow_imageblit(const struct fb_image *image, struct fb_info *p,
 112                                  void *dst1, u32 fgcolor, u32 bgcolor,
 113                                  u32 start_index, u32 pitch_index)
 114{
 115        u32 shift, color = 0, bpp = p->var.bits_per_pixel;
 116        u32 *dst, *dst2;
 117        u32 val, pitch = p->fix.line_length;
 118        u32 null_bits = 32 - bpp;
 119        u32 spitch = (image->width+7)/8;
 120        const u8 *src = image->data, *s;
 121        u32 i, j, l;
 122
 123        dst2 = dst1;
 124        fgcolor <<= FB_LEFT_POS(p, bpp);
 125        bgcolor <<= FB_LEFT_POS(p, bpp);
 126
 127        for (i = image->height; i--; ) {
 128                shift = val = 0;
 129                l = 8;
 130                j = image->width;
 131                dst = dst1;
 132                s = src;
 133
 134                /* write leading bits */
 135                if (start_index) {
 136                        u32 start_mask = ~(FB_SHIFT_HIGH(p, ~(u32)0,
 137                                                         start_index));
 138                        val = *dst & start_mask;
 139                        shift = start_index;
 140                }
 141
 142                while (j--) {
 143                        l--;
 144                        color = (*s & (1 << l)) ? fgcolor : bgcolor;
 145                        val |= FB_SHIFT_HIGH(p, color, shift);
 146
 147                        /* Did the bitshift spill bits to the next long? */
 148                        if (shift >= null_bits) {
 149                                *dst++ = val;
 150                                val = (shift == null_bits) ? 0 :
 151                                        FB_SHIFT_LOW(p, color, 32 - shift);
 152                        }
 153                        shift += bpp;
 154                        shift &= (32 - 1);
 155                        if (!l) { l = 8; s++; }
 156                }
 157
 158                /* write trailing bits */
 159                if (shift) {
 160                        u32 end_mask = FB_SHIFT_HIGH(p, ~(u32)0, shift);
 161
 162                        *dst &= end_mask;
 163                        *dst |= val;
 164                }
 165
 166                dst1 += pitch;
 167                src += spitch;
 168                if (pitch_index) {
 169                        dst2 += pitch;
 170                        dst1 = (u8 *)((long)dst2 & ~(sizeof(u32) - 1));
 171                        start_index += pitch_index;
 172                        start_index &= 32 - 1;
 173                }
 174
 175        }
 176}
 177
 178/*
 179 * fast_imageblit - optimized monochrome color expansion
 180 *
 181 * Only if:  bits_per_pixel == 8, 16, or 32
 182 *           image->width is divisible by pixel/dword (ppw);
 183 *           fix->line_legth is divisible by 4;
 184 *           beginning and end of a scanline is dword aligned
 185 */
 186static void fast_imageblit(const struct fb_image *image, struct fb_info *p,
 187                                  void *dst1, u32 fgcolor, u32 bgcolor)
 188{
 189        u32 fgx = fgcolor, bgx = bgcolor, bpp = p->var.bits_per_pixel;
 190        u32 ppw = 32/bpp, spitch = (image->width + 7)/8;
 191        u32 bit_mask, end_mask, eorx, shift;
 192        const char *s = image->data, *src;
 193        u32 *dst;
 194        const u32 *tab = NULL;
 195        int i, j, k;
 196
 197        switch (bpp) {
 198        case 8:
 199                tab = fb_be_math(p) ? cfb_tab8_be : cfb_tab8_le;
 200                break;
 201        case 16:
 202                tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le;
 203                break;
 204        case 32:
 205        default:
 206                tab = cfb_tab32;
 207                break;
 208        }
 209
 210        for (i = ppw-1; i--; ) {
 211                fgx <<= bpp;
 212                bgx <<= bpp;
 213                fgx |= fgcolor;
 214                bgx |= bgcolor;
 215        }
 216
 217        bit_mask = (1 << ppw) - 1;
 218        eorx = fgx ^ bgx;
 219        k = image->width/ppw;
 220
 221        for (i = image->height; i--; ) {
 222                dst = dst1;
 223                shift = 8;
 224                src = s;
 225
 226                for (j = k; j--; ) {
 227                        shift -= ppw;
 228                        end_mask = tab[(*src >> shift) & bit_mask];
 229                        *dst++ = (end_mask & eorx) ^ bgx;
 230                        if (!shift) {
 231                                shift = 8;
 232                                src++;
 233                        }
 234                }
 235                dst1 += p->fix.line_length;
 236                s += spitch;
 237        }
 238}
 239
 240void sys_imageblit(struct fb_info *p, const struct fb_image *image)
 241{
 242        u32 fgcolor, bgcolor, start_index, bitstart, pitch_index = 0;
 243        u32 bpl = sizeof(u32), bpp = p->var.bits_per_pixel;
 244        u32 width = image->width;
 245        u32 dx = image->dx, dy = image->dy;
 246        void *dst1;
 247
 248        if (p->state != FBINFO_STATE_RUNNING)
 249                return;
 250
 251        bitstart = (dy * p->fix.line_length * 8) + (dx * bpp);
 252        start_index = bitstart & (32 - 1);
 253        pitch_index = (p->fix.line_length & (bpl - 1)) * 8;
 254
 255        bitstart /= 8;
 256        bitstart &= ~(bpl - 1);
 257        dst1 = (void __force *)p->screen_base + bitstart;
 258
 259        if (p->fbops->fb_sync)
 260                p->fbops->fb_sync(p);
 261
 262        if (image->depth == 1) {
 263                if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
 264                    p->fix.visual == FB_VISUAL_DIRECTCOLOR) {
 265                        fgcolor = ((u32*)(p->pseudo_palette))[image->fg_color];
 266                        bgcolor = ((u32*)(p->pseudo_palette))[image->bg_color];
 267                } else {
 268                        fgcolor = image->fg_color;
 269                        bgcolor = image->bg_color;
 270                }
 271
 272                if (32 % bpp == 0 && !start_index && !pitch_index &&
 273                    ((width & (32/bpp-1)) == 0) &&
 274                    bpp >= 8 && bpp <= 32)
 275                        fast_imageblit(image, p, dst1, fgcolor, bgcolor);
 276                else
 277                        slow_imageblit(image, p, dst1, fgcolor, bgcolor,
 278                                        start_index, pitch_index);
 279        } else
 280                color_imageblit(image, p, dst1, start_index, pitch_index);
 281}
 282
 283EXPORT_SYMBOL(sys_imageblit);
 284
 285MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
 286MODULE_DESCRIPTION("1-bit/8-bit to 1-32 bit color expansion (sys-to-sys)");
 287MODULE_LICENSE("GPL");
 288
 289