|
15 | 15 |
|
16 | 16 | #include "twin_private.h" |
17 | 17 |
|
| 18 | +/* Compositing Primitive Operations |
| 19 | + * |
| 20 | + * The following section contains low-level pixel compositing operations |
| 21 | + * that implement Porter-Duff compositing algebra for various pixel formats. |
| 22 | + * These functions are generated via C preprocessor macros to create all |
| 23 | + * combinations of source/mask/destination format operations. |
| 24 | + */ |
| 25 | + |
| 26 | +static inline twin_argb32_t in_over(twin_argb32_t dst, |
| 27 | + twin_argb32_t src, |
| 28 | + twin_a8_t msk) |
| 29 | +{ |
| 30 | + uint16_t t1, t2, t3, t4; |
| 31 | + twin_a8_t a; |
| 32 | + |
| 33 | + switch (msk) { |
| 34 | + case 0: |
| 35 | + return dst; |
| 36 | + case 0xff: |
| 37 | + break; |
| 38 | + default: |
| 39 | + src = (twin_in(src, 0, msk, t1) | twin_in(src, 8, msk, t2) | |
| 40 | + twin_in(src, 16, msk, t3) | twin_in(src, 24, msk, t4)); |
| 41 | + break; |
| 42 | + } |
| 43 | + if (!src) |
| 44 | + return dst; |
| 45 | + a = ~(src >> 24); |
| 46 | + switch (a) { |
| 47 | + case 0: |
| 48 | + return src; |
| 49 | + case 0xff: |
| 50 | + dst = (twin_add(src, dst, 0, t1) | twin_add(src, dst, 8, t2) | |
| 51 | + twin_add(src, dst, 16, t3) | twin_add(src, dst, 24, t4)); |
| 52 | + break; |
| 53 | + default: |
| 54 | + dst = (twin_over(src, dst, 0, a, t1) | twin_over(src, dst, 8, a, t2) | |
| 55 | + twin_over(src, dst, 16, a, t3) | twin_over(src, dst, 24, a, t4)); |
| 56 | + break; |
| 57 | + } |
| 58 | + return dst; |
| 59 | +} |
| 60 | + |
| 61 | +static inline twin_argb32_t in(twin_argb32_t src, twin_a8_t msk) |
| 62 | +{ |
| 63 | + uint16_t t1, t2, t3, t4; |
| 64 | + |
| 65 | + return (twin_in(src, 0, msk, t1) | twin_in(src, 8, msk, t2) | |
| 66 | + twin_in(src, 16, msk, t3) | twin_in(src, 24, msk, t4)); |
| 67 | +} |
| 68 | + |
| 69 | +static inline twin_argb32_t over(twin_argb32_t dst, twin_argb32_t src) |
| 70 | +{ |
| 71 | + uint16_t t1, t2, t3, t4; |
| 72 | + twin_a8_t a; |
| 73 | + |
| 74 | + if (!src) |
| 75 | + return dst; |
| 76 | + a = ~(src >> 24); |
| 77 | + switch (a) { |
| 78 | + case 0: |
| 79 | + return src; |
| 80 | + case 0xff: |
| 81 | + dst = (twin_add(src, dst, 0, t1) | twin_add(src, dst, 8, t2) | |
| 82 | + twin_add(src, dst, 16, t3) | twin_add(src, dst, 24, t4)); |
| 83 | + break; |
| 84 | + default: |
| 85 | + dst = (twin_over(src, dst, 0, a, t1) | twin_over(src, dst, 8, a, t2) | |
| 86 | + twin_over(src, dst, 16, a, t3) | twin_over(src, dst, 24, a, t4)); |
| 87 | + break; |
| 88 | + } |
| 89 | + return dst; |
| 90 | +} |
| 91 | + |
| 92 | +static inline twin_argb32_t rgb16_to_argb32(twin_rgb16_t v) |
| 93 | +{ |
| 94 | + return twin_rgb16_to_argb32(v); |
| 95 | +} |
| 96 | + |
| 97 | +static inline twin_argb32_t a8_to_argb32(twin_a8_t v) |
| 98 | +{ |
| 99 | + return v << 24; |
| 100 | +} |
| 101 | + |
| 102 | +static inline twin_rgb16_t argb32_to_rgb16(twin_argb32_t v) |
| 103 | +{ |
| 104 | + return twin_argb32_to_rgb16(v); |
| 105 | +} |
| 106 | + |
| 107 | +static inline twin_a8_t argb32_to_a8(twin_argb32_t v) |
| 108 | +{ |
| 109 | + return v >> 24; |
| 110 | +} |
| 111 | + |
| 112 | +/* Naming convention |
| 113 | + * |
| 114 | + * _twin_<src>_in_<msk>_op_<dst> |
| 115 | + * |
| 116 | + * Use 'c' for constant |
| 117 | + */ |
| 118 | + |
| 119 | +#define dst_argb32_get (*dst.argb32) |
| 120 | +#define dst_argb32_set (*dst.argb32++) = |
| 121 | +#define dst_rgb16_get (rgb16_to_argb32(*dst.rgb16)) |
| 122 | +#define dst_rgb16_set (*dst.rgb16++) = argb32_to_rgb16 |
| 123 | +#define dst_a8_get (a8_to_argb32(*dst.a8)) |
| 124 | +#define dst_a8_set (*dst.a8++) = argb32_to_a8 |
| 125 | + |
| 126 | +#define src_c (src.c) |
| 127 | +#define src_argb32 (*src.p.argb32++) |
| 128 | +#define src_rgb16 (rgb16_to_argb32(*src.p.rgb16++)) |
| 129 | +#define src_a8 (a8_to_argb32(*src.p.a8++)) |
| 130 | + |
| 131 | +#define msk_c (argb32_to_a8(msk.c)) |
| 132 | +#define msk_argb32 (argb32_to_a8(*msk.p.argb32++)) |
| 133 | +#define msk_rgb16 \ |
| 134 | + (0xff); \ |
| 135 | + (void) msk |
| 136 | +#define msk_a8 (*msk.p.a8++) |
| 137 | + |
| 138 | +#define CAT2(a, b) a##b |
| 139 | +#define CAT3(a, b, c) a##b##c |
| 140 | +#define CAT4(a, b, c, d) a##b##c##d |
| 141 | +#define CAT6(a, b, c, d, e, f) a##b##c##d##e##f |
| 142 | + |
| 143 | +#define _twin_in_op_name(src, op, msk, dst) \ |
| 144 | + CAT6(_twin_, src, _in_, msk, op, dst) |
| 145 | + |
| 146 | +#define _twin_op_name(src, op, dst) CAT4(_twin_, src, op, dst) |
| 147 | + |
| 148 | +#define MAKE_TWIN_in_over(__dst, __src, __msk) \ |
| 149 | + void _twin_in_op_name(__src, _over_, __msk, __dst)( \ |
| 150 | + twin_pointer_t dst, twin_source_u src, twin_source_u msk, int width) \ |
| 151 | + { \ |
| 152 | + twin_argb32_t dst32; \ |
| 153 | + twin_argb32_t src32; \ |
| 154 | + twin_a8_t msk8; \ |
| 155 | + while (width--) { \ |
| 156 | + dst32 = CAT3(dst_, __dst, _get); \ |
| 157 | + src32 = CAT2(src_, __src); \ |
| 158 | + msk8 = CAT2(msk_, __msk); \ |
| 159 | + dst32 = in_over(dst32, src32, msk8); \ |
| 160 | + CAT3(dst_, __dst, _set)(dst32); \ |
| 161 | + } \ |
| 162 | + } |
| 163 | + |
| 164 | +#define MAKE_TWIN_in_source(__dst, __src, __msk) \ |
| 165 | + void _twin_in_op_name(__src, _source_, __msk, __dst)( \ |
| 166 | + twin_pointer_t dst, twin_source_u src, twin_source_u msk, int width) \ |
| 167 | + { \ |
| 168 | + twin_argb32_t dst32; \ |
| 169 | + twin_argb32_t src32; \ |
| 170 | + twin_a8_t msk8; \ |
| 171 | + while (width--) { \ |
| 172 | + src32 = CAT2(src_, __src); \ |
| 173 | + msk8 = CAT2(msk_, __msk); \ |
| 174 | + dst32 = in(src32, msk8); \ |
| 175 | + CAT3(dst_, __dst, _set)(dst32); \ |
| 176 | + } \ |
| 177 | + } |
| 178 | + |
| 179 | +/* clang-format off */ |
| 180 | +#define MAKE_TWIN_in_op_msks(op, dst, src) \ |
| 181 | + CAT2(MAKE_TWIN_in_, op)(dst, src, argb32) \ |
| 182 | + CAT2(MAKE_TWIN_in_, op)(dst, src, rgb16) \ |
| 183 | + CAT2(MAKE_TWIN_in_, op)(dst, src, a8) \ |
| 184 | + CAT2(MAKE_TWIN_in_, op)(dst, src, c) |
| 185 | +/* clang-format on */ |
| 186 | + |
| 187 | +#define MAKE_TWIN_in_op_srcs_msks(op, dst) \ |
| 188 | + MAKE_TWIN_in_op_msks(op, dst, argb32) MAKE_TWIN_in_op_msks(op, dst, rgb16) \ |
| 189 | + MAKE_TWIN_in_op_msks(op, dst, a8) MAKE_TWIN_in_op_msks(op, dst, c) |
| 190 | + |
| 191 | +#define MAKE_TWIN_in_op_dsts_srcs_msks(op) \ |
| 192 | + MAKE_TWIN_in_op_srcs_msks(op, argb32) MAKE_TWIN_in_op_srcs_msks(op, rgb16) \ |
| 193 | + MAKE_TWIN_in_op_srcs_msks(op, a8) |
| 194 | + |
| 195 | +MAKE_TWIN_in_op_dsts_srcs_msks(over) MAKE_TWIN_in_op_dsts_srcs_msks(source) |
| 196 | + |
| 197 | +#define MAKE_TWIN_over(__dst, __src) \ |
| 198 | + void _twin_op_name(__src, _over_, __dst)(twin_pointer_t dst, \ |
| 199 | + twin_source_u src, int width) \ |
| 200 | + { \ |
| 201 | + twin_argb32_t dst32; \ |
| 202 | + twin_argb32_t src32; \ |
| 203 | + while (width--) { \ |
| 204 | + dst32 = CAT3(dst_, __dst, _get); \ |
| 205 | + src32 = CAT2(src_, __src); \ |
| 206 | + dst32 = over(dst32, src32); \ |
| 207 | + CAT3(dst_, __dst, _set)(dst32); \ |
| 208 | + } \ |
| 209 | + } |
| 210 | + |
| 211 | +#define MAKE_TWIN_source(__dst, __src) \ |
| 212 | + void _twin_op_name(__src, _source_, __dst)(twin_pointer_t dst, \ |
| 213 | + twin_source_u src, int width) \ |
| 214 | + { \ |
| 215 | + twin_argb32_t dst32; \ |
| 216 | + twin_argb32_t src32; \ |
| 217 | + while (width--) { \ |
| 218 | + src32 = CAT2(src_, __src); \ |
| 219 | + dst32 = src32; \ |
| 220 | + CAT3(dst_, __dst, _set)(dst32); \ |
| 221 | + } \ |
| 222 | + } |
| 223 | + |
| 224 | +/* clang-format off */ |
| 225 | +#define MAKE_TWIN_op_srcs(op, dst) \ |
| 226 | + CAT2(MAKE_TWIN_, op)(dst, argb32) \ |
| 227 | + CAT2(MAKE_TWIN_, op)(dst, rgb16) \ |
| 228 | + CAT2(MAKE_TWIN_, op)(dst, a8) \ |
| 229 | + CAT2(MAKE_TWIN_, op)(dst, c) |
| 230 | + |
| 231 | +#define MAKE_TWIN_op_dsts_srcs(op) \ |
| 232 | + MAKE_TWIN_op_srcs(op, argb32) \ |
| 233 | + MAKE_TWIN_op_srcs(op, rgb16) \ |
| 234 | + MAKE_TWIN_op_srcs(op, a8) |
| 235 | + |
| 236 | + MAKE_TWIN_op_dsts_srcs(over); |
| 237 | + MAKE_TWIN_op_dsts_srcs(source); |
| 238 | + |
| 239 | +/* clang-format on */ |
| 240 | + |
| 241 | +/* Built-in Renderer Implementation |
| 242 | + * |
| 243 | + * The following section implements the twin_composite() and twin_fill() |
| 244 | + * functions using the primitive operations defined above. |
| 245 | + */ |
| 246 | + |
18 | 247 | /* op, src, dst */ |
19 | 248 | static const twin_src_op comp2[2][4][3] = { |
20 | 249 | [TWIN_OVER] = |
|
0 commit comments