3 * Access pixel bytes, Get and PutPixel
4 * Do not include directly, use GP_Pixel.h
6 * Copyright (C) 2011-2014 Cyril Hrubis <metan@ucw.cz>
7 * Copyright (C) 2011 Tomas Gavenciak <gavento@ucw.cz>
12 Note about byte aligment
13 ~~~~~~~~~~~~~~~~~~~~~~~~
15 Unaligned access happens when instruction that works with multiple byte
16 value gets an address that is not divideable by the size of the value. Eg.
17 if 32 bit integer instruction gets an address that is not a multiple of 4.
18 On intel cpus this type of access works and is supported however the C
19 standard defines this as undefined behavior. This fails to work ARM and most
20 of the non intel cpus. So some more trickery must be done in order to write
21 unaligned multibyte values. First of all we must compute offset and number
22 of bytes to be accessed (which is cruicial for speed as we are going to read
23 the pixel value byte by byte).
25 The offsets (starting with the first one eg. pixel_size mod 8) forms subgroup
26 in the mod 8 cyclic group. The maximal count of bits, from the start of the
27 byte, then will be max from this subgroup + pixel_size. If this number is
28 less or equal to 8 * N, we could write such pixel by writing N bytes.
30 For example the offsets of 16 BPP forms subgroup only with {0} so we only
31 need 2 bytes to write it. As a matter of fact the 16 and 32 BPP are special
32 cases that are always aligned together with the 8 BPP (which is aligned
33 trivially). These three are coded as special cases which yields to faster
34 operations in case of 16 and 32 BPP. The 24 BPP is not aligned as there are
35 no instruction to operate 3 byte long numbers.
37 For second example take offsets of 20 BPP that forms subgroup {4, 0}
38 so the max + pixel_size = 24 and indeed we fit into 3 bytes.
40 If pixel_size is coprime to 8, the offsets generates whole group and so the
41 max + pixel_size = 7 + pixel_size. The 17 BPP fits into 24 bits and so 3
42 bytes are needed. The 19 BPP fits into 26 bits and because of that 4 bytes
45 Once we figure maximal number of bytes and the offset all that is to be done
46 is to fetch first and last byte to combine it together with given pixel value
47 and write the result back to the bitmap.
51 #include "GP_GetSetBits.h"
52 #include "GP_Pixmap.h"
54 @ for ps in pixelsizes:
56 * macro to get address of pixel in a {{ ps.suffix }} pixmap
58 #define GP_PIXEL_ADDR_{{ ps.suffix }}(pixmap, x, y) \
59 ((GP_Pixel*)(((void*)((pixmap)->pixels)) + (pixmap)->bytes_per_row * (y) + ({{ ps.size }} * (x)) / 8))
62 * macro to get bit-offset of pixel in {{ ps.suffix }} pixmap
64 #define GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x) \
65 @ if not ps.needs_bit_endian():
68 @ if ps.bit_endian == 'LE':
70 (((x) % {{ 8 // ps.size }}) * {{ ps.size }})
72 (({{ ps.size }} * (x)) % 8)
75 ({{ 8 - ps.size }} - ((x) % {{ 8 // ps.size }}) * {{ ps.size }})
77 {{ error('Insanity check: big bit-endian with >8 bpp. Are you sure?') }}
81 * GP_GetPixel for {{ ps.suffix }}
83 static inline GP_Pixel GP_GetPixel_Raw_{{ ps.suffix }}(const GP_Pixmap *c, int x, int y)
87 * 32 BPP is expected to have aligned pixels
89 return *((uint32_t*)GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y));
92 * 16 BPP is expected to have aligned pixels
94 return *((uint16_t*)GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y));
97 * 8 BPP is byte aligned
99 return *((uint8_t*)GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y));
100 @ elif ps.size == 1 or ps.size == 2 or ps.size == 4 or ps.size == 8:
102 * Whole pixel is stored only and only in one byte
104 * The full list = {1, 2, 4, 8}
106 return GP_GET_BITS1_ALIGNED(GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x), {{ ps.size }},
107 *(GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y)));
108 @ elif ps.size <= 10 or ps.size == 12 or ps.size == 16:
110 * The pixel is stored in one or two bytes
112 * The max from subgroup (of mod 8 factor group) generated by
113 * pixel_size mod 8 + pixel_size <= 16
115 * The full list = {3, 5, 6, 7, 9, 10, 12, 16}
117 * Hint: If the pixel size is coprime to 8 the group is generated by
118 * pixel_size mod 8 and maximal size thus is pixel_size + 7
120 return GP_GET_BITS2_ALIGNED(GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x), {{ ps.size }},
121 *(GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y)));
122 @ elif ps.size <= 18 or ps.size == 20 or ps.size == 24:
124 * The pixel is stored in two or three bytes
126 * The max from subgroup (of mod 8 factor group) generated by
127 * pixel_size mod 8 + pixel_size <= 24
129 * The full list = {11, 13, 14, 15, 17, 18, 20, 24}
131 * Hint: If the pixel size is coprime to 8 the group is generated by
132 * pixel_size mod 8 and maximal size thus is pixel_size + 7
134 return GP_GET_BITS3_ALIGNED(GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x), {{ ps.size }},
135 *(GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y)));
136 @ elif ps.size <= 23 or ps.size == 25 or ps.size == 26 or ps.size == 28 or ps.size == 32:
138 * The pixel is stored in three or four bytes
140 * The max from subgroup (of mod 8 factor group) generated by
141 * pixel_size mod 8 + pixel_size <= 32
143 * The full list = {19, 21, 22, 23, 25, 26, 28, 32}
145 * Hint: If the pixel size is coprime to 8 the group is generated by
146 * pixel_size mod 8 and maximal size thus is pixel_size + 7
148 return GP_GET_BITS4_ALIGNED(GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x), {{ ps.size }},
149 *(GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y)));
151 #error not implemented
156 * GP_PutPixel for {{ ps.suffix }}
158 static inline void GP_PutPixel_Raw_{{ ps.suffix }}(GP_Pixmap *c, int x, int y, GP_Pixel p)
162 * 32 BPP is expected to have aligned pixels
164 *((uint32_t*)GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y)) = p;
165 @ elif ps.size == 16:
167 * 16 BPP is expected to have aligned pixels
169 *((uint16_t*)GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y)) = p;
172 * 8 BPP is byte aligned
174 *((uint8_t*)GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y)) = p;
175 @ elif ps.size == 1 or ps.size == 2 or ps.size == 4 or ps.size == 8:
177 * Whole pixel is stored only and only in one byte
179 * The full list = {1, 2, 4, 8}
181 GP_SET_BITS1_ALIGNED(GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x), {{ ps.size }},
182 GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y), p);
183 @ elif ps.size <= 10 or ps.size == 12 or ps.size == 16:
185 * The pixel is stored in one or two bytes
187 * The max from subgroup (of mod 8 factor group) generated by
188 * pixel_size mod 8 + pixel_size <= 16
190 * The full list = {3, 5, 6, 7, 9, 10, 12, 16}
192 * Hint: If the pixel size is coprime to 8 the group is generated by
193 * pixel_size mod 8 and maximal size thus is pixel_size + 7
195 GP_SET_BITS2_ALIGNED(GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x), {{ ps.size }},
196 GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y), p);
197 @ elif ps.size <= 18 or ps.size == 20 or ps.size == 24:
199 * The pixel is stored in two or three bytes
201 * The max from subgroup (of mod 8 factor group) generated by
202 * pixel_size mod 8 + pixel_size <= 24
204 * The full list = {11, 13, 14, 15, 17, 18, 20, 24}
206 * Hint: If the pixel size is coprime to 8 the group is generated by
207 * pixel_size mod 8 and maximal size thus is pixel_size + 7
209 GP_SET_BITS3_ALIGNED(GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x), {{ ps.size }},
210 GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y), p);
211 @ elif ps.size <= 23 or ps.size == 25 or ps.size == 26 or ps.size == 28 or ps.size == 32:
213 * The pixel is stored in three or four bytes
215 * The max from subgroup (of mod 8 factor group) generated by
216 * pixel_size mod 8 + pixel_size <= 32
218 * The full list = {19, 21, 22, 23, 25, 26, 28, 32}
220 * Hint: If the pixel size is coprime to 8 the group is generated by
221 * pixel_size mod 8 and maximal size thus is pixel_size + 7
223 GP_SET_BITS4_ALIGNED(GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x), {{ ps.size }},
224 GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y), p);
226 #error not implemented
230 static inline void GP_PutPixel_Raw_Clipped_{{ ps.suffix }}(GP_Pixmap *c, GP_Coord x, GP_Coord y, GP_Pixel p)
232 if (GP_PIXEL_IS_CLIPPED(c, x, y))
235 GP_PutPixel_Raw_{{ ps.suffix }}(c, x, y, p);