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