1 // SPDX-License-Identifier: Apache-2.0
2 // ----------------------------------------------------------------------------
3 // Copyright 2011-2022 Arm Limited
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
6 // use this file except in compliance with the License. You may obtain a copy
7 // of the License at:
8 //
9 // http://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, WITHOUT
13 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 // License for the specific language governing permissions and limitations
15 // under the License.
16 // ----------------------------------------------------------------------------
17
18 /**
19 * @brief Functions for creating in-memory ASTC image structures.
20 */
21
22 #include <cassert>
23 #include <cstring>
24
25 #include "astcenccli_internal.h"
26
27 /* See header for documentation. */
alloc_image(unsigned int bitness,unsigned int dim_x,unsigned int dim_y,unsigned int dim_z)28 astcenc_image *alloc_image(
29 unsigned int bitness,
30 unsigned int dim_x,
31 unsigned int dim_y,
32 unsigned int dim_z
33 ) {
34 astcenc_image *img = new astcenc_image;
35 img->dim_x = dim_x;
36 img->dim_y = dim_y;
37 img->dim_z = dim_z;
38
39 void** data = new void*[dim_z];
40 img->data = data;
41
42 if (bitness == 8)
43 {
44 img->data_type = ASTCENC_TYPE_U8;
45 for (unsigned int z = 0; z < dim_z; z++)
46 {
47 data[z] = new uint8_t[dim_x * dim_y * 4];
48 }
49 }
50 else if (bitness == 16)
51 {
52 img->data_type = ASTCENC_TYPE_F16;
53 for (unsigned int z = 0; z < dim_z; z++)
54 {
55 data[z] = new uint16_t[dim_x * dim_y * 4];
56 }
57 }
58 else // if (bitness == 32)
59 {
60 assert(bitness == 32);
61 img->data_type = ASTCENC_TYPE_F32;
62 for (unsigned int z = 0; z < dim_z; z++)
63 {
64 data[z] = new float[dim_x * dim_y * 4];
65 }
66 }
67
68 return img;
69 }
70
71 /* See header for documentation. */
free_image(astcenc_image * img)72 void free_image(astcenc_image * img)
73 {
74 if (img == nullptr)
75 {
76 return;
77 }
78
79 for (unsigned int z = 0; z < img->dim_z; z++)
80 {
81 delete[] reinterpret_cast<char*>(img->data[z]);
82 }
83
84 delete[] img->data;
85 delete img;
86 }
87
88 /* See header for documentation. */
determine_image_components(const astcenc_image * img)89 int determine_image_components(const astcenc_image * img)
90 {
91 unsigned int dim_x = img->dim_x;
92 unsigned int dim_y = img->dim_y;
93 unsigned int dim_z = img->dim_z;
94
95 // Scan through the image data to determine how many color components the image has
96 bool is_luma = true;
97 bool has_alpha = false;
98
99 if (img->data_type == ASTCENC_TYPE_U8)
100 {
101 for (unsigned int z = 0; z < dim_z; z++)
102 {
103 uint8_t* data8 = static_cast<uint8_t*>(img->data[z]);
104
105 for (unsigned int y = 0; y < dim_y; y++)
106 {
107 for (unsigned int x = 0; x < dim_x; x++)
108 {
109 int r = data8[(4 * dim_x * y) + (4 * x )];
110 int g = data8[(4 * dim_x * y) + (4 * x + 1)];
111 int b = data8[(4 * dim_x * y) + (4 * x + 2)];
112 int a = data8[(4 * dim_x * y) + (4 * x + 3)];
113
114 is_luma = is_luma && (r == g) && (r == b);
115 has_alpha = has_alpha || (a != 0xFF);
116 }
117 }
118 }
119 }
120 else if (img->data_type == ASTCENC_TYPE_F16)
121 {
122 for (unsigned int z = 0; z < dim_z; z++)
123 {
124 uint16_t* data16 = static_cast<uint16_t*>(img->data[z]);
125
126 for (unsigned int y = 0; y < dim_y; y++)
127 {
128 for (unsigned int x = 0; x < dim_x; x++)
129 {
130 int r = data16[(4 * dim_x * y) + (4 * x )];
131 int g = data16[(4 * dim_x * y) + (4 * x + 1)];
132 int b = data16[(4 * dim_x * y) + (4 * x + 2)];
133 int a = data16[(4 * dim_x * y) + (4 * x + 3)];
134
135 is_luma = is_luma && (r == g) && (r == b);
136 has_alpha = has_alpha || ((a ^ 0xC3FF) != 0xFFFF);
137 // a ^ 0xC3FF returns FFFF if and only if the input is 1.0
138 }
139 }
140 }
141 }
142 else // if (img->data_type == ASTCENC_TYPE_F32)
143 {
144 assert(img->data_type == ASTCENC_TYPE_F32);
145
146 for (unsigned int z = 0; z < dim_z; z++)
147 {
148 float* data32 = static_cast<float*>(img->data[z]);
149
150 for (unsigned int y = 0; y < dim_y; y++)
151 {
152 for (unsigned int x = 0; x < dim_x; x++)
153 {
154 float r = data32[(4 * dim_x * y) + (4 * x )];
155 float g = data32[(4 * dim_x * y) + (4 * x + 1)];
156 float b = data32[(4 * dim_x * y) + (4 * x + 2)];
157 float a = data32[(4 * dim_x * y) + (4 * x + 3)];
158
159 is_luma = is_luma && (r == g) && (r == b);
160 has_alpha = has_alpha || (a != 1.0f);
161 }
162 }
163 }
164 }
165
166 int image_components = 1 + (is_luma == 0 ? 2 : 0) + (has_alpha ? 1 : 0);
167 return image_components;
168 }
169
170 /* See header for documentation. */
astc_img_from_floatx4_array(const float * data,unsigned int dim_x,unsigned int dim_y,bool y_flip)171 astcenc_image* astc_img_from_floatx4_array(
172 const float* data,
173 unsigned int dim_x,
174 unsigned int dim_y,
175 bool y_flip
176 ) {
177 astcenc_image* img = alloc_image(16, dim_x, dim_y, 1);
178
179 for (unsigned int y = 0; y < dim_y; y++)
180 {
181 uint16_t* data16 = static_cast<uint16_t*>(img->data[0]);
182 unsigned int y_src = y_flip ? (dim_y - y - 1) : y;
183 const float* src = data + 4 * dim_x * y_src;
184
185 for (unsigned int x = 0; x < dim_x; x++)
186 {
187 vint4 colorf16 = float_to_float16(vfloat4(
188 src[4 * x ],
189 src[4 * x + 1],
190 src[4 * x + 2],
191 src[4 * x + 3]
192 ));
193
194 data16[(4 * dim_x * y) + (4 * x )] = static_cast<uint16_t>(colorf16.lane<0>());
195 data16[(4 * dim_x * y) + (4 * x + 1)] = static_cast<uint16_t>(colorf16.lane<1>());
196 data16[(4 * dim_x * y) + (4 * x + 2)] = static_cast<uint16_t>(colorf16.lane<2>());
197 data16[(4 * dim_x * y) + (4 * x + 3)] = static_cast<uint16_t>(colorf16.lane<3>());
198 }
199 }
200
201 return img;
202 }
203
204 /* See header for documentation. */
astc_img_from_unorm8x4_array(const uint8_t * data,unsigned int dim_x,unsigned int dim_y,bool y_flip)205 astcenc_image* astc_img_from_unorm8x4_array(
206 const uint8_t* data,
207 unsigned int dim_x,
208 unsigned int dim_y,
209 bool y_flip
210 ) {
211 astcenc_image* img = alloc_image(8, dim_x, dim_y, 1);
212
213 for (unsigned int y = 0; y < dim_y; y++)
214 {
215 uint8_t* data8 = static_cast<uint8_t*>(img->data[0]);
216 unsigned int y_src = y_flip ? (dim_y - y - 1) : y;
217 const uint8_t* src = data + 4 * dim_x * y_src;
218
219 for (unsigned int x = 0; x < dim_x; x++)
220 {
221 data8[(4 * dim_x * y) + (4 * x )] = src[4 * x ];
222 data8[(4 * dim_x * y) + (4 * x + 1)] = src[4 * x + 1];
223 data8[(4 * dim_x * y) + (4 * x + 2)] = src[4 * x + 2];
224 data8[(4 * dim_x * y) + (4 * x + 3)] = src[4 * x + 3];
225 }
226 }
227
228 return img;
229 }
230
231 // initialize a flattened array of float values from an ASTC codec image
232 // The returned array is allocated with new[] and must be deleted with delete[].
233 /* See header for documentation. */
floatx4_array_from_astc_img(const astcenc_image * img,bool y_flip)234 float* floatx4_array_from_astc_img(
235 const astcenc_image* img,
236 bool y_flip
237 ) {
238 unsigned int dim_x = img->dim_x;
239 unsigned int dim_y = img->dim_y;
240 float *buf = new float[4 * dim_x * dim_y];
241
242 if (img->data_type == ASTCENC_TYPE_U8)
243 {
244 uint8_t* data8 = static_cast<uint8_t*>(img->data[0]);
245 for (unsigned int y = 0; y < dim_y; y++)
246 {
247 unsigned int ymod = y_flip ? dim_y - y - 1 : y;
248 float* dst = buf + y * dim_x * 4;
249
250 for (unsigned int x = 0; x < dim_x; x++)
251 {
252 dst[4 * x ] = data8[(4 * dim_x * ymod) + (4 * x )] * (1.0f / 255.0f);
253 dst[4 * x + 1] = data8[(4 * dim_x * ymod) + (4 * x + 1)] * (1.0f / 255.0f);
254 dst[4 * x + 2] = data8[(4 * dim_x * ymod) + (4 * x + 2)] * (1.0f / 255.0f);
255 dst[4 * x + 3] = data8[(4 * dim_x * ymod) + (4 * x + 3)] * (1.0f / 255.0f);
256 }
257 }
258 }
259 else if (img->data_type == ASTCENC_TYPE_F16)
260 {
261 uint16_t* data16 = static_cast<uint16_t*>(img->data[0]);
262 for (unsigned int y = 0; y < dim_y; y++)
263 {
264 unsigned int ymod = y_flip ? dim_y - y - 1 : y;
265 float *dst = buf + y * dim_x * 4;
266
267 for (unsigned int x = 0; x < dim_x; x++)
268 {
269 vint4 colori(
270 data16[(4 * dim_x * ymod) + (4 * x )],
271 data16[(4 * dim_x * ymod) + (4 * x + 1)],
272 data16[(4 * dim_x * ymod) + (4 * x + 2)],
273 data16[(4 * dim_x * ymod) + (4 * x + 3)]
274 );
275
276 vfloat4 color = float16_to_float(colori);
277 store(color, dst + 4 * x);
278 }
279 }
280 }
281 else // if (img->data_type == ASTCENC_TYPE_F32)
282 {
283 assert(img->data_type == ASTCENC_TYPE_F32);
284 float* data32 = static_cast<float*>(img->data[0]);
285 for (unsigned int y = 0; y < dim_y; y++)
286 {
287 unsigned int ymod = y_flip ? dim_y - y - 1 : y;
288 float *dst = buf + y * dim_x * 4;
289
290 for (unsigned int x = 0; x < dim_x; x++)
291 {
292 dst[4 * x ] = data32[(4 * dim_x * ymod) + (4 * x )];
293 dst[4 * x + 1] = data32[(4 * dim_x * ymod) + (4 * x + 1)];
294 dst[4 * x + 2] = data32[(4 * dim_x * ymod) + (4 * x + 2)];
295 dst[4 * x + 3] = data32[(4 * dim_x * ymod) + (4 * x + 3)];
296 }
297 }
298 }
299
300 return buf;
301 }
302
303 /* See header for documentation. */
unorm8x4_array_from_astc_img(const astcenc_image * img,bool y_flip)304 uint8_t* unorm8x4_array_from_astc_img(
305 const astcenc_image* img,
306 bool y_flip
307 ) {
308 unsigned int dim_x = img->dim_x;
309 unsigned int dim_y = img->dim_y;
310 uint8_t* buf = new uint8_t[4 * dim_x * dim_y];
311
312 if (img->data_type == ASTCENC_TYPE_U8)
313 {
314 uint8_t* data8 = static_cast<uint8_t*>(img->data[0]);
315 for (unsigned int y = 0; y < dim_y; y++)
316 {
317 unsigned int ymod = y_flip ? dim_y - y - 1 : y;
318 uint8_t* dst = buf + y * dim_x * 4;
319
320 for (unsigned int x = 0; x < dim_x; x++)
321 {
322 dst[4 * x ] = data8[(4 * dim_x * ymod) + (4 * x )];
323 dst[4 * x + 1] = data8[(4 * dim_x * ymod) + (4 * x + 1)];
324 dst[4 * x + 2] = data8[(4 * dim_x * ymod) + (4 * x + 2)];
325 dst[4 * x + 3] = data8[(4 * dim_x * ymod) + (4 * x + 3)];
326 }
327 }
328 }
329 else if (img->data_type == ASTCENC_TYPE_F16)
330 {
331 uint16_t* data16 = static_cast<uint16_t*>(img->data[0]);
332 for (unsigned int y = 0; y < dim_y; y++)
333 {
334 unsigned int ymod = y_flip ? dim_y - y - 1 : y;
335 uint8_t* dst = buf + y * dim_x * 4;
336
337 for (unsigned int x = 0; x < dim_x; x++)
338 {
339 vint4 colori(
340 data16[(4 * dim_x * ymod) + (4 * x )],
341 data16[(4 * dim_x * ymod) + (4 * x + 1)],
342 data16[(4 * dim_x * ymod) + (4 * x + 2)],
343 data16[(4 * dim_x * ymod) + (4 * x + 3)]
344 );
345
346 vfloat4 color = float16_to_float(colori);
347 color = clamp(0.0f, 1.0f, color) * 255.0f;
348
349 colori = float_to_int_rtn(color);
350 pack_low_bytes(colori);
351 store_nbytes(colori, dst + 4 * x);
352 }
353 }
354 }
355 else // if (img->data_type == ASTCENC_TYPE_F32)
356 {
357 assert(img->data_type == ASTCENC_TYPE_F32);
358 float* data32 = static_cast<float*>(img->data[0]);
359 for (unsigned int y = 0; y < dim_y; y++)
360 {
361 unsigned int ymod = y_flip ? dim_y - y - 1 : y;
362 uint8_t* dst = buf + y * dim_x * 4;
363
364 for (unsigned int x = 0; x < dim_x; x++)
365 {
366 dst[4 * x ] = static_cast<uint8_t>(astc::flt2int_rtn(astc::clamp1f(data32[(4 * dim_x * ymod) + (4 * x )]) * 255.0f));
367 dst[4 * x + 1] = static_cast<uint8_t>(astc::flt2int_rtn(astc::clamp1f(data32[(4 * dim_x * ymod) + (4 * x + 1)]) * 255.0f));
368 dst[4 * x + 2] = static_cast<uint8_t>(astc::flt2int_rtn(astc::clamp1f(data32[(4 * dim_x * ymod) + (4 * x + 2)]) * 255.0f));
369 dst[4 * x + 3] = static_cast<uint8_t>(astc::flt2int_rtn(astc::clamp1f(data32[(4 * dim_x * ymod) + (4 * x + 3)]) * 255.0f));
370 }
371 }
372 }
373
374 return buf;
375 }
376