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. */
28astcenc_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. */
72void 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. */
89int 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. */
171astcenc_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. */
205astcenc_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. */
234float* 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. */
307uint8_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