^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * Fast C2P (Chunky-to-Planar) Conversion
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 2003-2008 Geert Uytterhoeven
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * This file is subject to the terms and conditions of the GNU General Public
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * License. See the file COPYING in the main directory of this archive
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * for more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <asm/unaligned.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include "c2p.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include "c2p_core.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * Perform a full C2P step on 32 8-bit pixels, stored in 8 32-bit words
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * containing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * - 32 8-bit chunky pixels on input
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * - permutated planar data (1 plane per 32-bit word) on output
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) static void c2p_32x8(u32 d[8])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) transp8(d, 16, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) transp8(d, 8, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) transp8(d, 4, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) transp8(d, 2, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) transp8(d, 1, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * Array containing the permutation indices of the planar data after c2p
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) static const int perm_c2p_32x8[8] = { 7, 5, 3, 1, 6, 4, 2, 0 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * Store a full block of planar data after c2p conversion
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static inline void store_planar(void *dst, u32 dst_inc, u32 bpp, u32 d[8])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) for (i = 0; i < bpp; i++, dst += dst_inc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) put_unaligned_be32(d[perm_c2p_32x8[i]], dst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * Store a partial block of planar data after c2p conversion
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) static inline void store_planar_masked(void *dst, u32 dst_inc, u32 bpp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) u32 d[8], u32 mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) for (i = 0; i < bpp; i++, dst += dst_inc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) put_unaligned_be32(comp(d[perm_c2p_32x8[i]],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) get_unaligned_be32(dst), mask),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) dst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * c2p_planar - Copy 8-bit chunky image data to a planar frame buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) * @dst: Starting address of the planar frame buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) * @dx: Horizontal destination offset (in pixels)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) * @dy: Vertical destination offset (in pixels)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * @width: Image width (in pixels)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) * @height: Image height (in pixels)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) * @dst_nextline: Frame buffer offset to the next line (in bytes)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) * @dst_nextplane: Frame buffer offset to the next plane (in bytes)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) * @src_nextline: Image offset to the next line (in bytes)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) * @bpp: Bits per pixel of the planar frame buffer (1-8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) void c2p_planar(void *dst, const void *src, u32 dx, u32 dy, u32 width,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) u32 height, u32 dst_nextline, u32 dst_nextplane,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) u32 src_nextline, u32 bpp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) union {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) u8 pixels[32];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) u32 words[8];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) } d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) u32 dst_idx, first, last, w;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) const u8 *c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) void *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) dst += dy*dst_nextline+(dx & ~31);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) dst_idx = dx % 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) first = 0xffffffffU >> dst_idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) last = ~(0xffffffffU >> ((dst_idx+width) % 32));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) while (height--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) c = src;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) p = dst;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) w = width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) if (dst_idx+width <= 32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) /* Single destination word */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) first &= last;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) memset(d.pixels, 0, sizeof(d));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) memcpy(d.pixels+dst_idx, c, width);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) c += width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) c2p_32x8(d.words);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) store_planar_masked(p, dst_nextplane, bpp, d.words,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) first);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) p += 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) /* Multiple destination words */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) w = width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) /* Leading bits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) if (dst_idx) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) w = 32 - dst_idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) memset(d.pixels, 0, dst_idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) memcpy(d.pixels+dst_idx, c, w);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) c += w;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) c2p_32x8(d.words);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) store_planar_masked(p, dst_nextplane, bpp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) d.words, first);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) p += 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) w = width-w;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) /* Main chunk */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) while (w >= 32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) memcpy(d.pixels, c, 32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) c += 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) c2p_32x8(d.words);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) store_planar(p, dst_nextplane, bpp, d.words);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) p += 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) w -= 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) /* Trailing bits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) w %= 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) if (w > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) memcpy(d.pixels, c, w);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) memset(d.pixels+w, 0, 32-w);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) c2p_32x8(d.words);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) store_planar_masked(p, dst_nextplane, bpp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) d.words, last);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) src += src_nextline;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) dst += dst_nextline;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) EXPORT_SYMBOL_GPL(c2p_planar);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) MODULE_LICENSE("GPL");