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,unsigned int z_index)234 float* floatx4_array_from_astc_img(
235 const astcenc_image* img,
236 bool y_flip,
237 unsigned int z_index
238 ) {
239 unsigned int dim_x = img->dim_x;
240 unsigned int dim_y = img->dim_y;
241 float *buf = new float[4 * dim_x * dim_y];
242
243 assert(z_index < img->dim_z);
244
245 if (img->data_type == ASTCENC_TYPE_U8)
246 {
247 uint8_t* data8 = static_cast<uint8_t*>(img->data[z_index]);
248 for (unsigned int y = 0; y < dim_y; y++)
249 {
250 unsigned int ymod = y_flip ? dim_y - y - 1 : y;
251 float* dst = buf + y * dim_x * 4;
252
253 for (unsigned int x = 0; x < dim_x; x++)
254 {
255 dst[4 * x ] = data8[(4 * dim_x * ymod) + (4 * x )] * (1.0f / 255.0f);
256 dst[4 * x + 1] = data8[(4 * dim_x * ymod) + (4 * x + 1)] * (1.0f / 255.0f);
257 dst[4 * x + 2] = data8[(4 * dim_x * ymod) + (4 * x + 2)] * (1.0f / 255.0f);
258 dst[4 * x + 3] = data8[(4 * dim_x * ymod) + (4 * x + 3)] * (1.0f / 255.0f);
259 }
260 }
261 }
262 else if (img->data_type == ASTCENC_TYPE_F16)
263 {
264 uint16_t* data16 = static_cast<uint16_t*>(img->data[z_index]);
265 for (unsigned int y = 0; y < dim_y; y++)
266 {
267 unsigned int ymod = y_flip ? dim_y - y - 1 : y;
268 float *dst = buf + y * dim_x * 4;
269
270 for (unsigned int x = 0; x < dim_x; x++)
271 {
272 vint4 colori(
273 data16[(4 * dim_x * ymod) + (4 * x )],
274 data16[(4 * dim_x * ymod) + (4 * x + 1)],
275 data16[(4 * dim_x * ymod) + (4 * x + 2)],
276 data16[(4 * dim_x * ymod) + (4 * x + 3)]
277 );
278
279 vfloat4 color = float16_to_float(colori);
280 store(color, dst + 4 * x);
281 }
282 }
283 }
284 else // if (img->data_type == ASTCENC_TYPE_F32)
285 {
286 assert(img->data_type == ASTCENC_TYPE_F32);
287 float* data32 = static_cast<float*>(img->data[z_index]);
288 for (unsigned int y = 0; y < dim_y; y++)
289 {
290 unsigned int ymod = y_flip ? dim_y - y - 1 : y;
291 float *dst = buf + y * dim_x * 4;
292
293 for (unsigned int x = 0; x < dim_x; x++)
294 {
295 dst[4 * x ] = data32[(4 * dim_x * ymod) + (4 * x )];
296 dst[4 * x + 1] = data32[(4 * dim_x * ymod) + (4 * x + 1)];
297 dst[4 * x + 2] = data32[(4 * dim_x * ymod) + (4 * x + 2)];
298 dst[4 * x + 3] = data32[(4 * dim_x * ymod) + (4 * x + 3)];
299 }
300 }
301 }
302
303 return buf;
304 }
305
306 /* See header for documentation. */
unorm8x4_array_from_astc_img(const astcenc_image * img,bool y_flip)307 uint8_t* unorm8x4_array_from_astc_img(
308 const astcenc_image* img,
309 bool y_flip
310 ) {
311 unsigned int dim_x = img->dim_x;
312 unsigned int dim_y = img->dim_y;
313 uint8_t* buf = new uint8_t[4 * dim_x * dim_y];
314
315 if (img->data_type == ASTCENC_TYPE_U8)
316 {
317 uint8_t* data8 = static_cast<uint8_t*>(img->data[0]);
318 for (unsigned int y = 0; y < dim_y; y++)
319 {
320 unsigned int ymod = y_flip ? dim_y - y - 1 : y;
321 uint8_t* dst = buf + y * dim_x * 4;
322
323 for (unsigned int x = 0; x < dim_x; x++)
324 {
325 dst[4 * x ] = data8[(4 * dim_x * ymod) + (4 * x )];
326 dst[4 * x + 1] = data8[(4 * dim_x * ymod) + (4 * x + 1)];
327 dst[4 * x + 2] = data8[(4 * dim_x * ymod) + (4 * x + 2)];
328 dst[4 * x + 3] = data8[(4 * dim_x * ymod) + (4 * x + 3)];
329 }
330 }
331 }
332 else if (img->data_type == ASTCENC_TYPE_F16)
333 {
334 uint16_t* data16 = static_cast<uint16_t*>(img->data[0]);
335 for (unsigned int y = 0; y < dim_y; y++)
336 {
337 unsigned int ymod = y_flip ? dim_y - y - 1 : y;
338 uint8_t* dst = buf + y * dim_x * 4;
339
340 for (unsigned int x = 0; x < dim_x; x++)
341 {
342 vint4 colori(
343 data16[(4 * dim_x * ymod) + (4 * x )],
344 data16[(4 * dim_x * ymod) + (4 * x + 1)],
345 data16[(4 * dim_x * ymod) + (4 * x + 2)],
346 data16[(4 * dim_x * ymod) + (4 * x + 3)]
347 );
348
349 vfloat4 color = float16_to_float(colori);
350 color = clamp(0.0f, 1.0f, color) * 255.0f;
351
352 colori = float_to_int_rtn(color);
353 pack_low_bytes(colori);
354 store_nbytes(colori, dst + 4 * x);
355 }
356 }
357 }
358 else // if (img->data_type == ASTCENC_TYPE_F32)
359 {
360 assert(img->data_type == ASTCENC_TYPE_F32);
361 float* data32 = static_cast<float*>(img->data[0]);
362 for (unsigned int y = 0; y < dim_y; y++)
363 {
364 unsigned int ymod = y_flip ? dim_y - y - 1 : y;
365 uint8_t* dst = buf + y * dim_x * 4;
366
367 for (unsigned int x = 0; x < dim_x; x++)
368 {
369 dst[4 * x ] = static_cast<uint8_t>(astc::flt2int_rtn(astc::clamp1f(data32[(4 * dim_x * ymod) + (4 * x )]) * 255.0f));
370 dst[4 * x + 1] = static_cast<uint8_t>(astc::flt2int_rtn(astc::clamp1f(data32[(4 * dim_x * ymod) + (4 * x + 1)]) * 255.0f));
371 dst[4 * x + 2] = static_cast<uint8_t>(astc::flt2int_rtn(astc::clamp1f(data32[(4 * dim_x * ymod) + (4 * x + 2)]) * 255.0f));
372 dst[4 * x + 3] = static_cast<uint8_t>(astc::flt2int_rtn(astc::clamp1f(data32[(4 * dim_x * ymod) + (4 * x + 3)]) * 255.0f));
373 }
374 }
375 }
376
377 return buf;
378 }
379