| 1 | |
| 2 | *
|
| 3 | * Various common functions used by the framebuffer drawing code
|
| 4 | *
|
| 5 | * Copyright (C) 2025 Zsolt Kajtar ([email protected])
|
| 6 |
|
| 7 | #ifndef _FB_DRAW_H
|
| 8 | #define _FB_DRAW_H
|
| 9 |
|
| 10 |
|
| 11 | #define swab_long _swab_long(BITS_PER_LONG)
|
| 12 | #define _swab_long(x) __swab_long(x)
|
| 13 | #define __swab_long(x) swab##x
|
| 14 |
|
| 15 |
|
| 16 | static inline void fb_address_move_long(struct fb_address *adr, int offset)
|
| 17 | {
|
| 18 | adr->address += offset * (BITS_PER_LONG / BITS_PER_BYTE);
|
| 19 | }
|
| 20 |
|
| 21 |
|
| 22 | static inline void fb_address_forward(struct fb_address *adr, unsigned int offset)
|
| 23 | {
|
| 24 | unsigned int bits = (unsigned int)adr->bits + offset;
|
| 25 |
|
| 26 | adr->bits = bits & (BITS_PER_LONG - 1u);
|
| 27 | adr->address += (bits & ~(BITS_PER_LONG - 1u)) / BITS_PER_BYTE;
|
| 28 | }
|
| 29 |
|
| 30 |
|
| 31 | static inline void fb_address_backward(struct fb_address *adr, unsigned int offset)
|
| 32 | {
|
| 33 | int bits = adr->bits - (int)offset;
|
| 34 |
|
| 35 | adr->bits = bits & (BITS_PER_LONG - 1);
|
| 36 | if (bits < 0)
|
| 37 | adr->address -= (adr->bits - bits) / BITS_PER_BYTE;
|
| 38 | else
|
| 39 | adr->address += (bits - adr->bits) / BITS_PER_BYTE;
|
| 40 | }
|
| 41 |
|
| 42 |
|
| 43 | static inline unsigned long fb_comp(unsigned long set, unsigned long unset, unsigned long mask)
|
| 44 | {
|
| 45 | return ((set ^ unset) & mask) ^ unset;
|
| 46 | }
|
| 47 |
|
| 48 |
|
| 49 | static inline void fb_modify_offset(unsigned long val, unsigned long mask,
|
| 50 | int offset, const struct fb_address *dst)
|
| 51 | {
|
| 52 | fb_write_offset(fb_comp(val, fb_read_offset(offset, dst), mask), offset, dst);
|
| 53 | }
|
| 54 |
|
| 55 | |
| 56 | * get current palette, if applicable for visual
|
| 57 | *
|
| 58 | * The pseudo color table entries (and colors) are right justified and in the
|
| 59 | * same byte order as it's expected to be placed into a native ordered
|
| 60 | * framebuffer memory. What that means:
|
| 61 | *
|
| 62 | * Expected bytes in framebuffer memory (in native order):
|
| 63 | * RR GG BB RR GG BB RR GG BB ...
|
| 64 | *
|
| 65 | * Pseudo palette entry on little endian arch:
|
| 66 | * RR | GG << 8 | BB << 16
|
| 67 | *
|
| 68 | * Pseudo palette entry on a big endian arch:
|
| 69 | * RR << 16 | GG << 8 | BB
|
| 70 |
|
| 71 | static inline const u32 *fb_palette(struct fb_info *info)
|
| 72 | {
|
| 73 | return (info->fix.visual == FB_VISUAL_TRUECOLOR ||
|
| 74 | info->fix.visual == FB_VISUAL_DIRECTCOLOR) ? info->pseudo_palette : NULL;
|
| 75 | }
|
| 76 |
|
| 77 |
|
| 78 | static inline unsigned long fb_right(unsigned long value, int index)
|
| 79 | {
|
| 80 | #ifdef __LITTLE_ENDIAN
|
| 81 | return value << index;
|
| 82 | #else
|
| 83 | return value >> index;
|
| 84 | #endif
|
| 85 | }
|
| 86 |
|
| 87 |
|
| 88 | static inline unsigned long fb_left(unsigned long value, int index)
|
| 89 | {
|
| 90 | #ifdef __LITTLE_ENDIAN
|
| 91 | return value >> index;
|
| 92 | #else
|
| 93 | return value << index;
|
| 94 | #endif
|
| 95 | }
|
| 96 |
|
| 97 |
|
| 98 | struct fb_reverse {
|
| 99 | bool byte, pixel;
|
| 100 | };
|
| 101 |
|
| 102 |
|
| 103 | static inline unsigned long fb_reverse_bits_long(unsigned long val)
|
| 104 | {
|
| 105 | #if defined(CONFIG_HAVE_ARCH_BITREVERSE) && BITS_PER_LONG == 32
|
| 106 | return bitrev8x4(val);
|
| 107 | #else
|
| 108 | val = fb_comp(val >> 1, val << 1, ~0UL / 3);
|
| 109 | val = fb_comp(val >> 2, val << 2, ~0UL / 5);
|
| 110 | return fb_comp(val >> 4, val << 4, ~0UL / 17);
|
| 111 | #endif
|
| 112 | }
|
| 113 |
|
| 114 |
|
| 115 | static inline unsigned long fb_reverse_long(unsigned long val,
|
| 116 | struct fb_reverse reverse)
|
| 117 | {
|
| 118 | if (reverse.pixel)
|
| 119 | val = fb_reverse_bits_long(val);
|
| 120 | return reverse.byte ? swab_long(val) : val;
|
| 121 | }
|
| 122 |
|
| 123 |
|
| 124 | static inline unsigned long fb_pixel_mask(int index, struct fb_reverse reverse)
|
| 125 | {
|
| 126 | #ifdef FB_REV_PIXELS_IN_BYTE
|
| 127 | if (reverse.byte)
|
| 128 | return reverse.pixel ? fb_left(~0UL, index) : swab_long(fb_right(~0UL, index));
|
| 129 | else
|
| 130 | return reverse.pixel ? swab_long(fb_left(~0UL, index)) : fb_right(~0UL, index);
|
| 131 | #else
|
| 132 | return reverse.byte ? swab_long(fb_right(~0UL, index)) : fb_right(~0UL, index);
|
| 133 | #endif
|
| 134 | }
|
| 135 |
|
| 136 |
|
| 137 | |
| 138 | * initialise reversals based on info
|
| 139 | *
|
| 140 | * Normally the first byte is the low byte on little endian and in the high
|
| 141 | * on big endian. If it's the other way around then that's reverse byte order.
|
| 142 | *
|
| 143 | * Normally the first pixel is the LSB on little endian and the MSB on big
|
| 144 | * endian. If that's not the case that's reverse pixel order.
|
| 145 |
|
| 146 | static inline struct fb_reverse fb_reverse_init(struct fb_info *info)
|
| 147 | {
|
| 148 | struct fb_reverse reverse;
|
| 149 | #ifdef __LITTLE_ENDIAN
|
| 150 | reverse.byte = fb_be_math(info) != 0;
|
| 151 | #else
|
| 152 | reverse.byte = fb_be_math(info) == 0;
|
| 153 | #endif
|
| 154 | #ifdef FB_REV_PIXELS_IN_BYTE
|
| 155 | reverse.pixel = info->var.bits_per_pixel < BITS_PER_BYTE
|
| 156 | && (info->var.nonstd & FB_NONSTD_REV_PIX_IN_B);
|
| 157 | #else
|
| 158 | reverse.pixel = false;
|
| 159 | #endif
|
| 160 | return reverse;
|
| 161 | }
|
| 162 |
|
| 163 | #endif
|