340 lines · c
1/*2 * Generic 1-bit or 8-bit source to 1-32 bit destination expansion3 * for frame buffer located in system RAM with packed pixels of any depth.4 *5 * Based almost entirely on cfbimgblt.c6 *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 Public10 * License. See the file COPYING in the main directory of this archive for11 * 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 DEBUG19 20#ifdef DEBUG21#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt,__func__,## args)22#else23#define DPRINTK(fmt, args...)24#endif25 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,0xffffffff31};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,0xffffffff38};39 40static const u32 cfb_tab16_be[] = {41 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff42};43 44static const u32 cfb_tab16_le[] = {45 0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff46};47 48static const u32 cfb_tab32[] = {49 0x00000000, 0xffffffff50};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 else81 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 expansion180 *181 * Only if: bits_per_pixel == 8, 16, or 32182 * 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 aligned185 */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, eorx, shift;192 const u8 *s = image->data, *src;193 u32 *dst;194 const u32 *tab;195 size_t tablen;196 u32 colortab[16];197 int i, j, k;198 199 switch (bpp) {200 case 8:201 tab = fb_be_math(p) ? cfb_tab8_be : cfb_tab8_le;202 tablen = 16;203 break;204 case 16:205 tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le;206 tablen = 4;207 break;208 case 32:209 tab = cfb_tab32;210 tablen = 2;211 break;212 default:213 return;214 }215 216 for (i = ppw-1; i--; ) {217 fgx <<= bpp;218 bgx <<= bpp;219 fgx |= fgcolor;220 bgx |= bgcolor;221 }222 223 bit_mask = (1 << ppw) - 1;224 eorx = fgx ^ bgx;225 k = image->width/ppw;226 227 for (i = 0; i < tablen; ++i)228 colortab[i] = (tab[i] & eorx) ^ bgx;229 230 for (i = image->height; i--; ) {231 dst = dst1;232 shift = 8;233 src = s;234 235 /*236 * Manually unroll the per-line copying loop for better237 * performance. This works until we processed the last238 * completely filled source byte (inclusive).239 */240 switch (ppw) {241 case 4: /* 8 bpp */242 for (j = k; j >= 2; j -= 2, ++src) {243 *dst++ = colortab[(*src >> 4) & bit_mask];244 *dst++ = colortab[(*src >> 0) & bit_mask];245 }246 break;247 case 2: /* 16 bpp */248 for (j = k; j >= 4; j -= 4, ++src) {249 *dst++ = colortab[(*src >> 6) & bit_mask];250 *dst++ = colortab[(*src >> 4) & bit_mask];251 *dst++ = colortab[(*src >> 2) & bit_mask];252 *dst++ = colortab[(*src >> 0) & bit_mask];253 }254 break;255 case 1: /* 32 bpp */256 for (j = k; j >= 8; j -= 8, ++src) {257 *dst++ = colortab[(*src >> 7) & bit_mask];258 *dst++ = colortab[(*src >> 6) & bit_mask];259 *dst++ = colortab[(*src >> 5) & bit_mask];260 *dst++ = colortab[(*src >> 4) & bit_mask];261 *dst++ = colortab[(*src >> 3) & bit_mask];262 *dst++ = colortab[(*src >> 2) & bit_mask];263 *dst++ = colortab[(*src >> 1) & bit_mask];264 *dst++ = colortab[(*src >> 0) & bit_mask];265 }266 break;267 }268 269 /*270 * For image widths that are not a multiple of 8, there271 * are trailing pixels left on the current line. Print272 * them as well.273 */274 for (; j--; ) {275 shift -= ppw;276 *dst++ = colortab[(*src >> shift) & bit_mask];277 if (!shift) {278 shift = 8;279 ++src;280 }281 }282 283 dst1 += p->fix.line_length;284 s += spitch;285 }286}287 288void sys_imageblit(struct fb_info *p, const struct fb_image *image)289{290 u32 fgcolor, bgcolor, start_index, bitstart, pitch_index = 0;291 u32 bpl = sizeof(u32), bpp = p->var.bits_per_pixel;292 u32 width = image->width;293 u32 dx = image->dx, dy = image->dy;294 void *dst1;295 296 if (p->state != FBINFO_STATE_RUNNING)297 return;298 299 if (!(p->flags & FBINFO_VIRTFB))300 fb_warn_once(p, "Framebuffer is not in virtual address space.");301 302 bitstart = (dy * p->fix.line_length * 8) + (dx * bpp);303 start_index = bitstart & (32 - 1);304 pitch_index = (p->fix.line_length & (bpl - 1)) * 8;305 306 bitstart /= 8;307 bitstart &= ~(bpl - 1);308 dst1 = (void __force *)p->screen_base + bitstart;309 310 if (p->fbops->fb_sync)311 p->fbops->fb_sync(p);312 313 if (image->depth == 1) {314 if (p->fix.visual == FB_VISUAL_TRUECOLOR ||315 p->fix.visual == FB_VISUAL_DIRECTCOLOR) {316 fgcolor = ((u32*)(p->pseudo_palette))[image->fg_color];317 bgcolor = ((u32*)(p->pseudo_palette))[image->bg_color];318 } else {319 fgcolor = image->fg_color;320 bgcolor = image->bg_color;321 }322 323 if (32 % bpp == 0 && !start_index && !pitch_index &&324 ((width & (32/bpp-1)) == 0) &&325 bpp >= 8 && bpp <= 32)326 fast_imageblit(image, p, dst1, fgcolor, bgcolor);327 else328 slow_imageblit(image, p, dst1, fgcolor, bgcolor,329 start_index, pitch_index);330 } else331 color_imageblit(image, p, dst1, start_index, pitch_index);332}333 334EXPORT_SYMBOL(sys_imageblit);335 336MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");337MODULE_DESCRIPTION("1-bit/8-bit to 1-32 bit color expansion (sys-to-sys)");338MODULE_LICENSE("GPL");339 340