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