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