1*eabb0329SZsolt Kajtar /* SPDX-License-Identifier: GPL-2.0-only 2*eabb0329SZsolt Kajtar * 3*eabb0329SZsolt Kajtar * Generic bitmap / 8 bpp image bitstreamer for packed pixel framebuffers 4*eabb0329SZsolt Kajtar * 5*eabb0329SZsolt Kajtar * Rewritten by: 6*eabb0329SZsolt Kajtar * Copyright (C) 2025 Zsolt Kajtar (soci@c64.rulez.org) 7*eabb0329SZsolt Kajtar * 8*eabb0329SZsolt Kajtar * Based on previous work of: 9*eabb0329SZsolt Kajtar * Copyright (C) June 1999 James Simmons 10*eabb0329SZsolt Kajtar * Anton Vorontsov <avorontsov@ru.mvista.com> 11*eabb0329SZsolt Kajtar * Pavel Pisa <pisa@cmp.felk.cvut.cz> 12*eabb0329SZsolt Kajtar * Antonino A. Daplas <adaplas@gmail.com> 13*eabb0329SZsolt Kajtar * and others 14*eabb0329SZsolt Kajtar * 15*eabb0329SZsolt Kajtar * NOTES: 16*eabb0329SZsolt Kajtar * 17*eabb0329SZsolt Kajtar * Handles native and foreign byte order on both endians, standard and 18*eabb0329SZsolt Kajtar * reverse pixel order in a byte (<8 BPP), word length of 32/64 bits, 19*eabb0329SZsolt Kajtar * bits per pixel from 1 to the word length. Handles line lengths at byte 20*eabb0329SZsolt Kajtar * granularity while maintaining aligned accesses. 21*eabb0329SZsolt Kajtar * 22*eabb0329SZsolt Kajtar * Optimized routines for word aligned 1, 2, 4 pixel per word for high 23*eabb0329SZsolt Kajtar * bpp modes and 4 pixel at a time operation for low bpp. 24*eabb0329SZsolt Kajtar * 25*eabb0329SZsolt Kajtar * The color image is expected to be one byte per pixel, and values should 26*eabb0329SZsolt Kajtar * not exceed the bitdepth or the pseudo palette (if used). 27*eabb0329SZsolt Kajtar */ 28*eabb0329SZsolt Kajtar #include "fb_draw.h" 29*eabb0329SZsolt Kajtar 30*eabb0329SZsolt Kajtar /* bitmap image iterator, one pixel at a time */ 31*eabb0329SZsolt Kajtar struct fb_bitmap_iter { 32*eabb0329SZsolt Kajtar const u8 *data; 33*eabb0329SZsolt Kajtar unsigned long colors[2]; 34*eabb0329SZsolt Kajtar int width, i; 35*eabb0329SZsolt Kajtar }; 36*eabb0329SZsolt Kajtar 37*eabb0329SZsolt Kajtar static bool fb_bitmap_image(void *iterator, unsigned long *pixels, int *bits) 38*eabb0329SZsolt Kajtar { 39*eabb0329SZsolt Kajtar struct fb_bitmap_iter *iter = iterator; 40*eabb0329SZsolt Kajtar 41*eabb0329SZsolt Kajtar if (iter->i < iter->width) { 42*eabb0329SZsolt Kajtar int bit = ~iter->i & (BITS_PER_BYTE-1); 43*eabb0329SZsolt Kajtar int byte = iter->i++ / BITS_PER_BYTE; 44*eabb0329SZsolt Kajtar 45*eabb0329SZsolt Kajtar *pixels = iter->colors[(iter->data[byte] >> bit) & 1]; 46*eabb0329SZsolt Kajtar return true; 47*eabb0329SZsolt Kajtar } 48*eabb0329SZsolt Kajtar iter->data += BITS_TO_BYTES(iter->width); 49*eabb0329SZsolt Kajtar iter->i = 0; 50*eabb0329SZsolt Kajtar return false; 51*eabb0329SZsolt Kajtar } 52*eabb0329SZsolt Kajtar 53*eabb0329SZsolt Kajtar /* color image iterator, one pixel at a time */ 54*eabb0329SZsolt Kajtar struct fb_color_iter { 55*eabb0329SZsolt Kajtar const u8 *data; 56*eabb0329SZsolt Kajtar const u32 *palette; 57*eabb0329SZsolt Kajtar struct fb_reverse reverse; 58*eabb0329SZsolt Kajtar int shift; 59*eabb0329SZsolt Kajtar int width, i; 60*eabb0329SZsolt Kajtar }; 61*eabb0329SZsolt Kajtar 62*eabb0329SZsolt Kajtar static bool fb_color_image(void *iterator, unsigned long *pixels, int *bits) 63*eabb0329SZsolt Kajtar { 64*eabb0329SZsolt Kajtar struct fb_color_iter *iter = iterator; 65*eabb0329SZsolt Kajtar 66*eabb0329SZsolt Kajtar if (iter->i < iter->width) { 67*eabb0329SZsolt Kajtar unsigned long color = iter->data[iter->i++]; 68*eabb0329SZsolt Kajtar 69*eabb0329SZsolt Kajtar if (iter->palette) 70*eabb0329SZsolt Kajtar color = iter->palette[color]; 71*eabb0329SZsolt Kajtar *pixels = color << iter->shift; 72*eabb0329SZsolt Kajtar if (iter->reverse.pixel) 73*eabb0329SZsolt Kajtar *pixels = fb_reverse_bits_long(*pixels); 74*eabb0329SZsolt Kajtar return true; 75*eabb0329SZsolt Kajtar } 76*eabb0329SZsolt Kajtar iter->data += iter->width; 77*eabb0329SZsolt Kajtar iter->i = 0; 78*eabb0329SZsolt Kajtar return false; 79*eabb0329SZsolt Kajtar } 80*eabb0329SZsolt Kajtar 81*eabb0329SZsolt Kajtar /* bitmap image iterator, 4 pixels at a time */ 82*eabb0329SZsolt Kajtar struct fb_bitmap4x_iter { 83*eabb0329SZsolt Kajtar const u8 *data; 84*eabb0329SZsolt Kajtar u32 fgxcolor, bgcolor; 85*eabb0329SZsolt Kajtar int width, i; 86*eabb0329SZsolt Kajtar const u32 *expand; 87*eabb0329SZsolt Kajtar int bpp; 88*eabb0329SZsolt Kajtar bool top; 89*eabb0329SZsolt Kajtar }; 90*eabb0329SZsolt Kajtar 91*eabb0329SZsolt Kajtar static bool fb_bitmap4x_image(void *iterator, unsigned long *pixels, int *bits) 92*eabb0329SZsolt Kajtar { 93*eabb0329SZsolt Kajtar struct fb_bitmap4x_iter *iter = iterator; 94*eabb0329SZsolt Kajtar u8 data; 95*eabb0329SZsolt Kajtar 96*eabb0329SZsolt Kajtar if (iter->i >= BITS_PER_BYTE/2) { 97*eabb0329SZsolt Kajtar iter->i -= BITS_PER_BYTE/2; 98*eabb0329SZsolt Kajtar iter->top = !iter->top; 99*eabb0329SZsolt Kajtar if (iter->top) 100*eabb0329SZsolt Kajtar data = *iter->data++ >> BITS_PER_BYTE/2; 101*eabb0329SZsolt Kajtar else 102*eabb0329SZsolt Kajtar data = iter->data[-1] & ((1 << BITS_PER_BYTE/2)-1); 103*eabb0329SZsolt Kajtar } else if (iter->i != 0) { 104*eabb0329SZsolt Kajtar *bits = iter->bpp * iter->i; 105*eabb0329SZsolt Kajtar if (iter->top) 106*eabb0329SZsolt Kajtar data = iter->data[-1] & ((1 << BITS_PER_BYTE/2)-1); 107*eabb0329SZsolt Kajtar else 108*eabb0329SZsolt Kajtar data = *iter->data++ >> BITS_PER_BYTE/2; 109*eabb0329SZsolt Kajtar #ifndef __LITTLE_ENDIAN 110*eabb0329SZsolt Kajtar data >>= BITS_PER_BYTE/2 - iter->i; 111*eabb0329SZsolt Kajtar #endif 112*eabb0329SZsolt Kajtar iter->i = 0; 113*eabb0329SZsolt Kajtar } else { 114*eabb0329SZsolt Kajtar *bits = iter->bpp * BITS_PER_BYTE/2; 115*eabb0329SZsolt Kajtar iter->i = iter->width; 116*eabb0329SZsolt Kajtar iter->top = false; 117*eabb0329SZsolt Kajtar return false; 118*eabb0329SZsolt Kajtar } 119*eabb0329SZsolt Kajtar *pixels = (iter->fgxcolor & iter->expand[data]) ^ iter->bgcolor; 120*eabb0329SZsolt Kajtar #ifndef __LITTLE_ENDIAN 121*eabb0329SZsolt Kajtar *pixels <<= BITS_PER_LONG - *bits; 122*eabb0329SZsolt Kajtar #endif 123*eabb0329SZsolt Kajtar return true; 124*eabb0329SZsolt Kajtar } 125*eabb0329SZsolt Kajtar 126*eabb0329SZsolt Kajtar /* draw a line a group of pixels at a time */ 127*eabb0329SZsolt Kajtar static __always_inline void fb_bitblit(bool (*get)(void *iter, unsigned long *pixels, 128*eabb0329SZsolt Kajtar int *bits), 129*eabb0329SZsolt Kajtar void *iter, int bits, struct fb_address *dst, 130*eabb0329SZsolt Kajtar struct fb_reverse reverse) 131*eabb0329SZsolt Kajtar { 132*eabb0329SZsolt Kajtar unsigned long pixels, val, mask, old; 133*eabb0329SZsolt Kajtar int offset = 0; 134*eabb0329SZsolt Kajtar int shift = dst->bits; 135*eabb0329SZsolt Kajtar 136*eabb0329SZsolt Kajtar if (shift) { 137*eabb0329SZsolt Kajtar old = fb_read_offset(0, dst); 138*eabb0329SZsolt Kajtar val = fb_reverse_long(old, reverse); 139*eabb0329SZsolt Kajtar val &= ~fb_right(~0UL, shift); 140*eabb0329SZsolt Kajtar } else { 141*eabb0329SZsolt Kajtar old = 0; 142*eabb0329SZsolt Kajtar val = 0; 143*eabb0329SZsolt Kajtar } 144*eabb0329SZsolt Kajtar 145*eabb0329SZsolt Kajtar while (get(iter, &pixels, &bits)) { 146*eabb0329SZsolt Kajtar val |= fb_right(pixels, shift); 147*eabb0329SZsolt Kajtar shift += bits; 148*eabb0329SZsolt Kajtar 149*eabb0329SZsolt Kajtar if (shift < BITS_PER_LONG) 150*eabb0329SZsolt Kajtar continue; 151*eabb0329SZsolt Kajtar 152*eabb0329SZsolt Kajtar val = fb_reverse_long(val, reverse); 153*eabb0329SZsolt Kajtar fb_write_offset(val, offset++, dst); 154*eabb0329SZsolt Kajtar shift &= BITS_PER_LONG - 1; 155*eabb0329SZsolt Kajtar val = !shift ? 0 : fb_left(pixels, bits - shift); 156*eabb0329SZsolt Kajtar } 157*eabb0329SZsolt Kajtar 158*eabb0329SZsolt Kajtar if (shift) { 159*eabb0329SZsolt Kajtar mask = ~fb_pixel_mask(shift, reverse); 160*eabb0329SZsolt Kajtar val = fb_reverse_long(val, reverse); 161*eabb0329SZsolt Kajtar if (offset || !dst->bits) 162*eabb0329SZsolt Kajtar old = fb_read_offset(offset, dst); 163*eabb0329SZsolt Kajtar fb_write_offset(fb_comp(val, old, mask), offset, dst); 164*eabb0329SZsolt Kajtar } 165*eabb0329SZsolt Kajtar } 166*eabb0329SZsolt Kajtar 167*eabb0329SZsolt Kajtar /* draw a color image a pixel at a time */ 168*eabb0329SZsolt Kajtar static inline void fb_color_imageblit(const struct fb_image *image, struct fb_address *dst, 169*eabb0329SZsolt Kajtar unsigned int bits_per_line, const u32 *palette, int bpp, 170*eabb0329SZsolt Kajtar struct fb_reverse reverse) 171*eabb0329SZsolt Kajtar { 172*eabb0329SZsolt Kajtar struct fb_color_iter iter; 173*eabb0329SZsolt Kajtar u32 height; 174*eabb0329SZsolt Kajtar 175*eabb0329SZsolt Kajtar iter.data = (const u8 *)image->data; 176*eabb0329SZsolt Kajtar iter.palette = palette; 177*eabb0329SZsolt Kajtar iter.reverse = reverse; 178*eabb0329SZsolt Kajtar #ifdef __LITTLE_ENDIAN 179*eabb0329SZsolt Kajtar if (reverse.pixel) 180*eabb0329SZsolt Kajtar iter.shift = BITS_PER_BYTE - bpp; 181*eabb0329SZsolt Kajtar else 182*eabb0329SZsolt Kajtar iter.shift = 0; 183*eabb0329SZsolt Kajtar #else 184*eabb0329SZsolt Kajtar if (reverse.pixel) 185*eabb0329SZsolt Kajtar iter.shift = BITS_PER_LONG - BITS_PER_BYTE; 186*eabb0329SZsolt Kajtar else 187*eabb0329SZsolt Kajtar iter.shift = BITS_PER_LONG - bpp; 188*eabb0329SZsolt Kajtar #endif 189*eabb0329SZsolt Kajtar iter.width = image->width; 190*eabb0329SZsolt Kajtar iter.i = 0; 191*eabb0329SZsolt Kajtar 192*eabb0329SZsolt Kajtar height = image->height; 193*eabb0329SZsolt Kajtar while (height--) { 194*eabb0329SZsolt Kajtar fb_bitblit(fb_color_image, &iter, bpp, dst, reverse); 195*eabb0329SZsolt Kajtar fb_address_forward(dst, bits_per_line); 196*eabb0329SZsolt Kajtar } 197*eabb0329SZsolt Kajtar } 198*eabb0329SZsolt Kajtar 199*eabb0329SZsolt Kajtar #ifdef __LITTLE_ENDIAN 200*eabb0329SZsolt Kajtar #define FB_GEN(a, b) (((a)/8+(((a)&4)<<((b)-2)) \ 201*eabb0329SZsolt Kajtar +(((a)&2)<<((b)*2-1))+(((a)&1u)<<((b)*3)))*((1<<(b))-1)) 202*eabb0329SZsolt Kajtar #define FB_GEN1(a) ((a)/8+((a)&4)/2+((a)&2)*2+((a)&1)*8) 203*eabb0329SZsolt Kajtar #else 204*eabb0329SZsolt Kajtar #define FB_GEN(a, b) (((((a)/8)<<((b)*3))+(((a)&4)<<((b)*2-2)) \ 205*eabb0329SZsolt Kajtar +(((a)&2)<<(b-1))+((a)&1u))*((1<<(b))-1)) 206*eabb0329SZsolt Kajtar #define FB_GEN1(a) (a) 207*eabb0329SZsolt Kajtar #endif 208*eabb0329SZsolt Kajtar 209*eabb0329SZsolt Kajtar #define FB_GENx(a) { FB_GEN(0, (a)), FB_GEN(1, (a)), FB_GEN(2, (a)), FB_GEN(3, (a)), \ 210*eabb0329SZsolt Kajtar FB_GEN(4, (a)), FB_GEN(5, (a)), FB_GEN(6, (a)), FB_GEN(7, (a)), \ 211*eabb0329SZsolt Kajtar FB_GEN(8, (a)), FB_GEN(9, (a)), FB_GEN(10, (a)), FB_GEN(11, (a)), \ 212*eabb0329SZsolt Kajtar FB_GEN(12, (a)), FB_GEN(13, (a)), FB_GEN(14, (a)), FB_GEN(15, (a)) } 213*eabb0329SZsolt Kajtar 214*eabb0329SZsolt Kajtar /* draw a 2 color image four pixels at a time (for 1-8 bpp only) */ 215*eabb0329SZsolt Kajtar static inline void fb_bitmap4x_imageblit(const struct fb_image *image, struct fb_address *dst, 216*eabb0329SZsolt Kajtar unsigned long fgcolor, unsigned long bgcolor, int bpp, 217*eabb0329SZsolt Kajtar unsigned int bits_per_line, struct fb_reverse reverse) 218*eabb0329SZsolt Kajtar { 219*eabb0329SZsolt Kajtar static const u32 mul[BITS_PER_BYTE] = { 220*eabb0329SZsolt Kajtar 0xf, 0x55, 0x249, 0x1111, 0x8421, 0x41041, 0x204081, 0x01010101 221*eabb0329SZsolt Kajtar }; 222*eabb0329SZsolt Kajtar static const u32 expand[BITS_PER_BYTE][1 << 4] = { 223*eabb0329SZsolt Kajtar { 224*eabb0329SZsolt Kajtar FB_GEN1(0), FB_GEN1(1), FB_GEN1(2), FB_GEN1(3), 225*eabb0329SZsolt Kajtar FB_GEN1(4), FB_GEN1(5), FB_GEN1(6), FB_GEN1(7), 226*eabb0329SZsolt Kajtar FB_GEN1(8), FB_GEN1(9), FB_GEN1(10), FB_GEN1(11), 227*eabb0329SZsolt Kajtar FB_GEN1(12), FB_GEN1(13), FB_GEN1(14), FB_GEN1(15) 228*eabb0329SZsolt Kajtar }, 229*eabb0329SZsolt Kajtar FB_GENx(2), FB_GENx(3), FB_GENx(4), 230*eabb0329SZsolt Kajtar FB_GENx(5), FB_GENx(6), FB_GENx(7), FB_GENx(8), 231*eabb0329SZsolt Kajtar }; 232*eabb0329SZsolt Kajtar struct fb_bitmap4x_iter iter; 233*eabb0329SZsolt Kajtar u32 height; 234*eabb0329SZsolt Kajtar 235*eabb0329SZsolt Kajtar iter.data = (const u8 *)image->data; 236*eabb0329SZsolt Kajtar if (reverse.pixel) { 237*eabb0329SZsolt Kajtar fgcolor = fb_reverse_bits_long(fgcolor << (BITS_PER_BYTE - bpp)); 238*eabb0329SZsolt Kajtar bgcolor = fb_reverse_bits_long(bgcolor << (BITS_PER_BYTE - bpp)); 239*eabb0329SZsolt Kajtar } 240*eabb0329SZsolt Kajtar iter.fgxcolor = (fgcolor ^ bgcolor) * mul[bpp-1]; 241*eabb0329SZsolt Kajtar iter.bgcolor = bgcolor * mul[bpp-1]; 242*eabb0329SZsolt Kajtar iter.width = image->width; 243*eabb0329SZsolt Kajtar iter.i = image->width; 244*eabb0329SZsolt Kajtar iter.expand = expand[bpp-1]; 245*eabb0329SZsolt Kajtar iter.bpp = bpp; 246*eabb0329SZsolt Kajtar iter.top = false; 247*eabb0329SZsolt Kajtar 248*eabb0329SZsolt Kajtar height = image->height; 249*eabb0329SZsolt Kajtar while (height--) { 250*eabb0329SZsolt Kajtar fb_bitblit(fb_bitmap4x_image, &iter, bpp * BITS_PER_BYTE/2, dst, reverse); 251*eabb0329SZsolt Kajtar fb_address_forward(dst, bits_per_line); 252*eabb0329SZsolt Kajtar } 253*eabb0329SZsolt Kajtar } 254*eabb0329SZsolt Kajtar 255*eabb0329SZsolt Kajtar /* draw a bitmap image 1 pixel at a time (for >8 bpp) */ 256*eabb0329SZsolt Kajtar static inline void fb_bitmap1x_imageblit(const struct fb_image *image, struct fb_address *dst, 257*eabb0329SZsolt Kajtar unsigned long fgcolor, unsigned long bgcolor, int bpp, 258*eabb0329SZsolt Kajtar unsigned int bits_per_line, struct fb_reverse reverse) 259*eabb0329SZsolt Kajtar { 260*eabb0329SZsolt Kajtar struct fb_bitmap_iter iter; 261*eabb0329SZsolt Kajtar u32 height; 262*eabb0329SZsolt Kajtar 263*eabb0329SZsolt Kajtar iter.colors[0] = bgcolor; 264*eabb0329SZsolt Kajtar iter.colors[1] = fgcolor; 265*eabb0329SZsolt Kajtar #ifndef __LITTLE_ENDIAN 266*eabb0329SZsolt Kajtar iter.colors[0] <<= BITS_PER_LONG - bpp; 267*eabb0329SZsolt Kajtar iter.colors[1] <<= BITS_PER_LONG - bpp; 268*eabb0329SZsolt Kajtar #endif 269*eabb0329SZsolt Kajtar iter.data = (const u8 *)image->data; 270*eabb0329SZsolt Kajtar iter.width = image->width; 271*eabb0329SZsolt Kajtar iter.i = 0; 272*eabb0329SZsolt Kajtar 273*eabb0329SZsolt Kajtar height = image->height; 274*eabb0329SZsolt Kajtar while (height--) { 275*eabb0329SZsolt Kajtar fb_bitblit(fb_bitmap_image, &iter, bpp, dst, reverse); 276*eabb0329SZsolt Kajtar fb_address_forward(dst, bits_per_line); 277*eabb0329SZsolt Kajtar } 278*eabb0329SZsolt Kajtar } 279*eabb0329SZsolt Kajtar 280*eabb0329SZsolt Kajtar /* one pixel per word, 64/32 bpp blitting */ 281*eabb0329SZsolt Kajtar static inline void fb_bitmap_1ppw(const struct fb_image *image, struct fb_address *dst, 282*eabb0329SZsolt Kajtar unsigned long fgcolor, unsigned long bgcolor, 283*eabb0329SZsolt Kajtar int words_per_line, struct fb_reverse reverse) 284*eabb0329SZsolt Kajtar { 285*eabb0329SZsolt Kajtar unsigned long tab[2]; 286*eabb0329SZsolt Kajtar const u8 *src = (u8 *)image->data; 287*eabb0329SZsolt Kajtar int width = image->width; 288*eabb0329SZsolt Kajtar int offset; 289*eabb0329SZsolt Kajtar u32 height; 290*eabb0329SZsolt Kajtar 291*eabb0329SZsolt Kajtar if (reverse.byte) { 292*eabb0329SZsolt Kajtar tab[0] = swab_long(bgcolor); 293*eabb0329SZsolt Kajtar tab[1] = swab_long(fgcolor); 294*eabb0329SZsolt Kajtar } else { 295*eabb0329SZsolt Kajtar tab[0] = bgcolor; 296*eabb0329SZsolt Kajtar tab[1] = fgcolor; 297*eabb0329SZsolt Kajtar } 298*eabb0329SZsolt Kajtar 299*eabb0329SZsolt Kajtar height = image->height; 300*eabb0329SZsolt Kajtar while (height--) { 301*eabb0329SZsolt Kajtar for (offset = 0; offset + 8 <= width; offset += 8) { 302*eabb0329SZsolt Kajtar unsigned int srcbyte = *src++; 303*eabb0329SZsolt Kajtar 304*eabb0329SZsolt Kajtar fb_write_offset(tab[(srcbyte >> 7) & 1], offset + 0, dst); 305*eabb0329SZsolt Kajtar fb_write_offset(tab[(srcbyte >> 6) & 1], offset + 1, dst); 306*eabb0329SZsolt Kajtar fb_write_offset(tab[(srcbyte >> 5) & 1], offset + 2, dst); 307*eabb0329SZsolt Kajtar fb_write_offset(tab[(srcbyte >> 4) & 1], offset + 3, dst); 308*eabb0329SZsolt Kajtar fb_write_offset(tab[(srcbyte >> 3) & 1], offset + 4, dst); 309*eabb0329SZsolt Kajtar fb_write_offset(tab[(srcbyte >> 2) & 1], offset + 5, dst); 310*eabb0329SZsolt Kajtar fb_write_offset(tab[(srcbyte >> 1) & 1], offset + 6, dst); 311*eabb0329SZsolt Kajtar fb_write_offset(tab[(srcbyte >> 0) & 1], offset + 7, dst); 312*eabb0329SZsolt Kajtar } 313*eabb0329SZsolt Kajtar 314*eabb0329SZsolt Kajtar if (offset < width) { 315*eabb0329SZsolt Kajtar unsigned int srcbyte = *src++; 316*eabb0329SZsolt Kajtar 317*eabb0329SZsolt Kajtar while (offset < width) { 318*eabb0329SZsolt Kajtar fb_write_offset(tab[(srcbyte >> 7) & 1], offset, dst); 319*eabb0329SZsolt Kajtar srcbyte <<= 1; 320*eabb0329SZsolt Kajtar offset++; 321*eabb0329SZsolt Kajtar } 322*eabb0329SZsolt Kajtar } 323*eabb0329SZsolt Kajtar fb_address_move_long(dst, words_per_line); 324*eabb0329SZsolt Kajtar } 325*eabb0329SZsolt Kajtar } 326*eabb0329SZsolt Kajtar 327*eabb0329SZsolt Kajtar static inline unsigned long fb_pack(unsigned long left, unsigned long right, int bits) 328*eabb0329SZsolt Kajtar { 329*eabb0329SZsolt Kajtar #ifdef __LITTLE_ENDIAN 330*eabb0329SZsolt Kajtar return left | right << bits; 331*eabb0329SZsolt Kajtar #else 332*eabb0329SZsolt Kajtar return right | left << bits; 333*eabb0329SZsolt Kajtar #endif 334*eabb0329SZsolt Kajtar } 335*eabb0329SZsolt Kajtar 336*eabb0329SZsolt Kajtar /* aligned 32/16 bpp blitting */ 337*eabb0329SZsolt Kajtar static inline void fb_bitmap_2ppw(const struct fb_image *image, struct fb_address *dst, 338*eabb0329SZsolt Kajtar unsigned long fgcolor, unsigned long bgcolor, 339*eabb0329SZsolt Kajtar int words_per_line, struct fb_reverse reverse) 340*eabb0329SZsolt Kajtar { 341*eabb0329SZsolt Kajtar unsigned long tab[4]; 342*eabb0329SZsolt Kajtar const u8 *src = (u8 *)image->data; 343*eabb0329SZsolt Kajtar int width = image->width / 2; 344*eabb0329SZsolt Kajtar int offset; 345*eabb0329SZsolt Kajtar u32 height; 346*eabb0329SZsolt Kajtar 347*eabb0329SZsolt Kajtar tab[0] = fb_pack(bgcolor, bgcolor, BITS_PER_LONG/2); 348*eabb0329SZsolt Kajtar tab[1] = fb_pack(bgcolor, fgcolor, BITS_PER_LONG/2); 349*eabb0329SZsolt Kajtar tab[2] = fb_pack(fgcolor, bgcolor, BITS_PER_LONG/2); 350*eabb0329SZsolt Kajtar tab[3] = fb_pack(fgcolor, fgcolor, BITS_PER_LONG/2); 351*eabb0329SZsolt Kajtar 352*eabb0329SZsolt Kajtar if (reverse.byte) { 353*eabb0329SZsolt Kajtar tab[0] = swab_long(tab[0]); 354*eabb0329SZsolt Kajtar tab[1] = swab_long(tab[1]); 355*eabb0329SZsolt Kajtar tab[2] = swab_long(tab[2]); 356*eabb0329SZsolt Kajtar tab[3] = swab_long(tab[3]); 357*eabb0329SZsolt Kajtar } 358*eabb0329SZsolt Kajtar 359*eabb0329SZsolt Kajtar height = image->height; 360*eabb0329SZsolt Kajtar while (height--) { 361*eabb0329SZsolt Kajtar for (offset = 0; offset + 4 <= width; offset += 4) { 362*eabb0329SZsolt Kajtar unsigned int srcbyte = *src++; 363*eabb0329SZsolt Kajtar 364*eabb0329SZsolt Kajtar fb_write_offset(tab[(srcbyte >> 6) & 3], offset + 0, dst); 365*eabb0329SZsolt Kajtar fb_write_offset(tab[(srcbyte >> 4) & 3], offset + 1, dst); 366*eabb0329SZsolt Kajtar fb_write_offset(tab[(srcbyte >> 2) & 3], offset + 2, dst); 367*eabb0329SZsolt Kajtar fb_write_offset(tab[(srcbyte >> 0) & 3], offset + 3, dst); 368*eabb0329SZsolt Kajtar } 369*eabb0329SZsolt Kajtar 370*eabb0329SZsolt Kajtar if (offset < width) { 371*eabb0329SZsolt Kajtar unsigned int srcbyte = *src++; 372*eabb0329SZsolt Kajtar 373*eabb0329SZsolt Kajtar while (offset < width) { 374*eabb0329SZsolt Kajtar fb_write_offset(tab[(srcbyte >> 6) & 3], offset, dst); 375*eabb0329SZsolt Kajtar srcbyte <<= 2; 376*eabb0329SZsolt Kajtar offset++; 377*eabb0329SZsolt Kajtar } 378*eabb0329SZsolt Kajtar } 379*eabb0329SZsolt Kajtar fb_address_move_long(dst, words_per_line); 380*eabb0329SZsolt Kajtar } 381*eabb0329SZsolt Kajtar } 382*eabb0329SZsolt Kajtar 383*eabb0329SZsolt Kajtar #define FB_PATP(a, b) (((a)<<((b)*BITS_PER_LONG/4))*((1UL<<BITS_PER_LONG/4)-1UL)) 384*eabb0329SZsolt Kajtar #define FB_PAT4(a) (FB_PATP((a)&1, 0)|FB_PATP(((a)&2)/2, 1)| \ 385*eabb0329SZsolt Kajtar FB_PATP(((a)&4)/4, 2)|FB_PATP(((a)&8)/8, 3)) 386*eabb0329SZsolt Kajtar 387*eabb0329SZsolt Kajtar /* aligned 16/8 bpp blitting */ 388*eabb0329SZsolt Kajtar static inline void fb_bitmap_4ppw(const struct fb_image *image, struct fb_address *dst, 389*eabb0329SZsolt Kajtar unsigned long fgcolor, unsigned long bgcolor, 390*eabb0329SZsolt Kajtar int words_per_line, struct fb_reverse reverse) 391*eabb0329SZsolt Kajtar { 392*eabb0329SZsolt Kajtar static const unsigned long tab16_be[] = { 393*eabb0329SZsolt Kajtar 0, FB_PAT4(1UL), FB_PAT4(2UL), FB_PAT4(3UL), 394*eabb0329SZsolt Kajtar FB_PAT4(4UL), FB_PAT4(5UL), FB_PAT4(6UL), FB_PAT4(7UL), 395*eabb0329SZsolt Kajtar FB_PAT4(8UL), FB_PAT4(9UL), FB_PAT4(10UL), FB_PAT4(11UL), 396*eabb0329SZsolt Kajtar FB_PAT4(12UL), FB_PAT4(13UL), FB_PAT4(14UL), ~0UL 397*eabb0329SZsolt Kajtar }; 398*eabb0329SZsolt Kajtar static const unsigned long tab16_le[] = { 399*eabb0329SZsolt Kajtar 0, FB_PAT4(8UL), FB_PAT4(4UL), FB_PAT4(12UL), 400*eabb0329SZsolt Kajtar FB_PAT4(2UL), FB_PAT4(10UL), FB_PAT4(6UL), FB_PAT4(14UL), 401*eabb0329SZsolt Kajtar FB_PAT4(1UL), FB_PAT4(9UL), FB_PAT4(5UL), FB_PAT4(13UL), 402*eabb0329SZsolt Kajtar FB_PAT4(3UL), FB_PAT4(11UL), FB_PAT4(7UL), ~0UL 403*eabb0329SZsolt Kajtar }; 404*eabb0329SZsolt Kajtar const unsigned long *tab; 405*eabb0329SZsolt Kajtar const u8 *src = (u8 *)image->data; 406*eabb0329SZsolt Kajtar int width = image->width / 4; 407*eabb0329SZsolt Kajtar int offset; 408*eabb0329SZsolt Kajtar u32 height; 409*eabb0329SZsolt Kajtar 410*eabb0329SZsolt Kajtar fgcolor = fgcolor | fgcolor << BITS_PER_LONG/4; 411*eabb0329SZsolt Kajtar bgcolor = bgcolor | bgcolor << BITS_PER_LONG/4; 412*eabb0329SZsolt Kajtar fgcolor = fgcolor | fgcolor << BITS_PER_LONG/2; 413*eabb0329SZsolt Kajtar bgcolor = bgcolor | bgcolor << BITS_PER_LONG/2; 414*eabb0329SZsolt Kajtar fgcolor ^= bgcolor; 415*eabb0329SZsolt Kajtar 416*eabb0329SZsolt Kajtar if (BITS_PER_LONG/4 > BITS_PER_BYTE && reverse.byte) { 417*eabb0329SZsolt Kajtar fgcolor = swab_long(fgcolor); 418*eabb0329SZsolt Kajtar bgcolor = swab_long(bgcolor); 419*eabb0329SZsolt Kajtar } 420*eabb0329SZsolt Kajtar 421*eabb0329SZsolt Kajtar #ifdef __LITTLE_ENDIAN 422*eabb0329SZsolt Kajtar tab = reverse.byte ? tab16_be : tab16_le; 423*eabb0329SZsolt Kajtar #else 424*eabb0329SZsolt Kajtar tab = reverse.byte ? tab16_le : tab16_be; 425*eabb0329SZsolt Kajtar #endif 426*eabb0329SZsolt Kajtar 427*eabb0329SZsolt Kajtar height = image->height; 428*eabb0329SZsolt Kajtar while (height--) { 429*eabb0329SZsolt Kajtar for (offset = 0; offset + 2 <= width; offset += 2, src++) { 430*eabb0329SZsolt Kajtar fb_write_offset((fgcolor & tab[*src >> 4]) ^ bgcolor, offset + 0, dst); 431*eabb0329SZsolt Kajtar fb_write_offset((fgcolor & tab[*src & 0xf]) ^ bgcolor, offset + 1, dst); 432*eabb0329SZsolt Kajtar } 433*eabb0329SZsolt Kajtar 434*eabb0329SZsolt Kajtar if (offset < width) 435*eabb0329SZsolt Kajtar fb_write_offset((fgcolor & tab[*src++ >> 4]) ^ bgcolor, offset, dst); 436*eabb0329SZsolt Kajtar 437*eabb0329SZsolt Kajtar fb_address_move_long(dst, words_per_line); 438*eabb0329SZsolt Kajtar } 439*eabb0329SZsolt Kajtar } 440*eabb0329SZsolt Kajtar 441*eabb0329SZsolt Kajtar static inline void fb_bitmap_imageblit(const struct fb_image *image, struct fb_address *dst, 442*eabb0329SZsolt Kajtar unsigned int bits_per_line, const u32 *palette, int bpp, 443*eabb0329SZsolt Kajtar struct fb_reverse reverse) 444*eabb0329SZsolt Kajtar { 445*eabb0329SZsolt Kajtar unsigned long fgcolor, bgcolor; 446*eabb0329SZsolt Kajtar 447*eabb0329SZsolt Kajtar if (palette) { 448*eabb0329SZsolt Kajtar fgcolor = palette[image->fg_color]; 449*eabb0329SZsolt Kajtar bgcolor = palette[image->bg_color]; 450*eabb0329SZsolt Kajtar } else { 451*eabb0329SZsolt Kajtar fgcolor = image->fg_color; 452*eabb0329SZsolt Kajtar bgcolor = image->bg_color; 453*eabb0329SZsolt Kajtar } 454*eabb0329SZsolt Kajtar 455*eabb0329SZsolt Kajtar if (!dst->bits && !(bits_per_line & (BITS_PER_LONG-1))) { 456*eabb0329SZsolt Kajtar if (bpp == BITS_PER_LONG && BITS_PER_LONG == 32) { 457*eabb0329SZsolt Kajtar fb_bitmap_1ppw(image, dst, fgcolor, bgcolor, 458*eabb0329SZsolt Kajtar bits_per_line / BITS_PER_LONG, reverse); 459*eabb0329SZsolt Kajtar return; 460*eabb0329SZsolt Kajtar } 461*eabb0329SZsolt Kajtar if (bpp == BITS_PER_LONG/2 && !(image->width & 1)) { 462*eabb0329SZsolt Kajtar fb_bitmap_2ppw(image, dst, fgcolor, bgcolor, 463*eabb0329SZsolt Kajtar bits_per_line / BITS_PER_LONG, reverse); 464*eabb0329SZsolt Kajtar return; 465*eabb0329SZsolt Kajtar } 466*eabb0329SZsolt Kajtar if (bpp == BITS_PER_LONG/4 && !(image->width & 3)) { 467*eabb0329SZsolt Kajtar fb_bitmap_4ppw(image, dst, fgcolor, bgcolor, 468*eabb0329SZsolt Kajtar bits_per_line / BITS_PER_LONG, reverse); 469*eabb0329SZsolt Kajtar return; 470*eabb0329SZsolt Kajtar } 471*eabb0329SZsolt Kajtar } 472*eabb0329SZsolt Kajtar 473*eabb0329SZsolt Kajtar if (bpp > 0 && bpp <= BITS_PER_BYTE) 474*eabb0329SZsolt Kajtar fb_bitmap4x_imageblit(image, dst, fgcolor, bgcolor, bpp, 475*eabb0329SZsolt Kajtar bits_per_line, reverse); 476*eabb0329SZsolt Kajtar else if (bpp > BITS_PER_BYTE && bpp <= BITS_PER_LONG) 477*eabb0329SZsolt Kajtar fb_bitmap1x_imageblit(image, dst, fgcolor, bgcolor, bpp, 478*eabb0329SZsolt Kajtar bits_per_line, reverse); 479*eabb0329SZsolt Kajtar } 480*eabb0329SZsolt Kajtar 481*eabb0329SZsolt Kajtar static inline void fb_imageblit(struct fb_info *p, const struct fb_image *image) 482*eabb0329SZsolt Kajtar { 483*eabb0329SZsolt Kajtar int bpp = p->var.bits_per_pixel; 484*eabb0329SZsolt Kajtar unsigned int bits_per_line = BYTES_TO_BITS(p->fix.line_length); 485*eabb0329SZsolt Kajtar struct fb_address dst = fb_address_init(p); 486*eabb0329SZsolt Kajtar struct fb_reverse reverse = fb_reverse_init(p); 487*eabb0329SZsolt Kajtar const u32 *palette = fb_palette(p); 488*eabb0329SZsolt Kajtar 489*eabb0329SZsolt Kajtar fb_address_forward(&dst, image->dy * bits_per_line + image->dx * bpp); 490*eabb0329SZsolt Kajtar 491*eabb0329SZsolt Kajtar if (image->depth == 1) 492*eabb0329SZsolt Kajtar fb_bitmap_imageblit(image, &dst, bits_per_line, palette, bpp, reverse); 493*eabb0329SZsolt Kajtar else 494*eabb0329SZsolt Kajtar fb_color_imageblit(image, &dst, bits_per_line, palette, bpp, reverse); 495*eabb0329SZsolt Kajtar } 496