• 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 	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