1 // After editing this file, run "go generate" in the parent directory.
2
3 // Copyright 2017 The Wuffs Authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // https://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16
17 // ---------------- Images
18
19 const uint32_t wuffs_base__pixel_format__bits_per_channel[16] = {
20 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
21 0x08, 0x0A, 0x0C, 0x10, 0x18, 0x20, 0x30, 0x40,
22 };
23
24 static uint64_t //
wuffs_base__pixel_swizzler__copy_1_1(wuffs_base__slice_u8 dst,wuffs_base__slice_u8 dst_palette,wuffs_base__slice_u8 src)25 wuffs_base__pixel_swizzler__copy_1_1(wuffs_base__slice_u8 dst,
26 wuffs_base__slice_u8 dst_palette,
27 wuffs_base__slice_u8 src) {
28 return wuffs_base__slice_u8__copy_from_slice(dst, src);
29 }
30
31 static uint64_t //
wuffs_base__pixel_swizzler__copy_3_1(wuffs_base__slice_u8 dst,wuffs_base__slice_u8 dst_palette,wuffs_base__slice_u8 src)32 wuffs_base__pixel_swizzler__copy_3_1(wuffs_base__slice_u8 dst,
33 wuffs_base__slice_u8 dst_palette,
34 wuffs_base__slice_u8 src) {
35 if (dst_palette.len != 1024) {
36 return 0;
37 }
38 size_t dst_len3 = dst.len / 3;
39 size_t len = dst_len3 < src.len ? dst_len3 : src.len;
40 uint8_t* d = dst.ptr;
41 uint8_t* s = src.ptr;
42 size_t n = len;
43
44 // N is the loop unroll count.
45 const int N = 4;
46
47 // The comparison in the while condition is ">", not ">=", because with ">=",
48 // the last 4-byte store could write past the end of the dst slice.
49 //
50 // Each 4-byte store writes one too many bytes, but a subsequent store will
51 // overwrite that with the correct byte. There is always another store,
52 // whether a 4-byte store in this loop or a 1-byte store in the next loop.
53 while (n > N) {
54 wuffs_base__store_u32le(
55 d + (0 * 3),
56 wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[0]) * 4)));
57 wuffs_base__store_u32le(
58 d + (1 * 3),
59 wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[1]) * 4)));
60 wuffs_base__store_u32le(
61 d + (2 * 3),
62 wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[2]) * 4)));
63 wuffs_base__store_u32le(
64 d + (3 * 3),
65 wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[3]) * 4)));
66
67 s += 1 * N;
68 d += 3 * N;
69 n -= (size_t)(1 * N);
70 }
71
72 while (n >= 1) {
73 uint32_t color =
74 wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[0]) * 4));
75 d[0] = (uint8_t)(color >> 0);
76 d[1] = (uint8_t)(color >> 8);
77 d[2] = (uint8_t)(color >> 16);
78
79 s += 1 * 1;
80 d += 3 * 1;
81 n -= (size_t)(1 * 1);
82 }
83
84 return len;
85 }
86 static uint64_t //
wuffs_base__pixel_swizzler__copy_4_1(wuffs_base__slice_u8 dst,wuffs_base__slice_u8 dst_palette,wuffs_base__slice_u8 src)87 wuffs_base__pixel_swizzler__copy_4_1(wuffs_base__slice_u8 dst,
88 wuffs_base__slice_u8 dst_palette,
89 wuffs_base__slice_u8 src) {
90 if (dst_palette.len != 1024) {
91 return 0;
92 }
93 size_t dst_len4 = dst.len / 4;
94 size_t len = dst_len4 < src.len ? dst_len4 : src.len;
95 uint8_t* d = dst.ptr;
96 uint8_t* s = src.ptr;
97 size_t n = len;
98
99 // N is the loop unroll count.
100 const int N = 4;
101
102 while (n >= N) {
103 wuffs_base__store_u32le(
104 d + (0 * 4),
105 wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[0]) * 4)));
106 wuffs_base__store_u32le(
107 d + (1 * 4),
108 wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[1]) * 4)));
109 wuffs_base__store_u32le(
110 d + (2 * 4),
111 wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[2]) * 4)));
112 wuffs_base__store_u32le(
113 d + (3 * 4),
114 wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[3]) * 4)));
115
116 s += 1 * N;
117 d += 4 * N;
118 n -= (size_t)(1 * N);
119 }
120
121 while (n >= 1) {
122 wuffs_base__store_u32le(
123 d + (0 * 4),
124 wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[0]) * 4)));
125
126 s += 1 * 1;
127 d += 4 * 1;
128 n -= (size_t)(1 * 1);
129 }
130
131 return len;
132 }
133
134 static uint64_t //
wuffs_base__pixel_swizzler__swap_rgbx_bgrx(wuffs_base__slice_u8 dst,wuffs_base__slice_u8 src)135 wuffs_base__pixel_swizzler__swap_rgbx_bgrx(wuffs_base__slice_u8 dst,
136 wuffs_base__slice_u8 src) {
137 size_t len4 = (dst.len < src.len ? dst.len : src.len) / 4;
138 uint8_t* d = dst.ptr;
139 uint8_t* s = src.ptr;
140
141 size_t n = len4;
142 while (n--) {
143 uint8_t b0 = s[0];
144 uint8_t b1 = s[1];
145 uint8_t b2 = s[2];
146 uint8_t b3 = s[3];
147 d[0] = b2;
148 d[1] = b1;
149 d[2] = b0;
150 d[3] = b3;
151 s += 4;
152 d += 4;
153 }
154 return len4 * 4;
155 }
156
157 wuffs_base__status //
wuffs_base__pixel_swizzler__prepare(wuffs_base__pixel_swizzler * p,wuffs_base__pixel_format dst_format,wuffs_base__slice_u8 dst_palette,wuffs_base__pixel_format src_format,wuffs_base__slice_u8 src_palette)158 wuffs_base__pixel_swizzler__prepare(wuffs_base__pixel_swizzler* p,
159 wuffs_base__pixel_format dst_format,
160 wuffs_base__slice_u8 dst_palette,
161 wuffs_base__pixel_format src_format,
162 wuffs_base__slice_u8 src_palette) {
163 if (!p) {
164 return wuffs_base__error__bad_receiver;
165 }
166
167 // TODO: support many more formats.
168
169 uint64_t (*func)(wuffs_base__slice_u8 dst, wuffs_base__slice_u8 dst_palette,
170 wuffs_base__slice_u8 src) = NULL;
171
172 switch (src_format) {
173 case WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_BINARY:
174 switch (dst_format) {
175 case WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_NONPREMUL:
176 case WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_PREMUL:
177 case WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_BINARY:
178 if (wuffs_base__slice_u8__copy_from_slice(dst_palette, src_palette) !=
179 1024) {
180 break;
181 }
182 func = wuffs_base__pixel_swizzler__copy_1_1;
183 break;
184 case WUFFS_BASE__PIXEL_FORMAT__BGR:
185 if (wuffs_base__slice_u8__copy_from_slice(dst_palette, src_palette) !=
186 1024) {
187 break;
188 }
189 func = wuffs_base__pixel_swizzler__copy_3_1;
190 break;
191 case WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL:
192 case WUFFS_BASE__PIXEL_FORMAT__BGRA_PREMUL:
193 case WUFFS_BASE__PIXEL_FORMAT__BGRA_BINARY:
194 if (wuffs_base__slice_u8__copy_from_slice(dst_palette, src_palette) !=
195 1024) {
196 break;
197 }
198 func = wuffs_base__pixel_swizzler__copy_4_1;
199 break;
200 case WUFFS_BASE__PIXEL_FORMAT__RGB:
201 if (wuffs_base__pixel_swizzler__swap_rgbx_bgrx(dst_palette,
202 src_palette) != 1024) {
203 break;
204 }
205 func = wuffs_base__pixel_swizzler__copy_3_1;
206 break;
207 case WUFFS_BASE__PIXEL_FORMAT__RGBA_NONPREMUL:
208 case WUFFS_BASE__PIXEL_FORMAT__RGBA_PREMUL:
209 case WUFFS_BASE__PIXEL_FORMAT__RGBA_BINARY:
210 if (wuffs_base__pixel_swizzler__swap_rgbx_bgrx(dst_palette,
211 src_palette) != 1024) {
212 break;
213 }
214 func = wuffs_base__pixel_swizzler__copy_4_1;
215 break;
216 default:
217 break;
218 }
219 break;
220
221 default:
222 break;
223 }
224
225 p->private_impl.func = func;
226 return func ? NULL : wuffs_base__error__unsupported_option;
227 }
228
229 uint64_t //
wuffs_base__pixel_swizzler__swizzle_interleaved(const wuffs_base__pixel_swizzler * p,wuffs_base__slice_u8 dst,wuffs_base__slice_u8 dst_palette,wuffs_base__slice_u8 src)230 wuffs_base__pixel_swizzler__swizzle_interleaved(
231 const wuffs_base__pixel_swizzler* p,
232 wuffs_base__slice_u8 dst,
233 wuffs_base__slice_u8 dst_palette,
234 wuffs_base__slice_u8 src) {
235 if (p && p->private_impl.func) {
236 return (*(p->private_impl.func))(dst, dst_palette, src);
237 }
238 return 0;
239 }
240