• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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