1cc1dc7a3Sopenharmony_ci// SPDX-License-Identifier: Apache-2.0 2cc1dc7a3Sopenharmony_ci// ---------------------------------------------------------------------------- 3cc1dc7a3Sopenharmony_ci// Copyright 2011-2024 Arm Limited 4cc1dc7a3Sopenharmony_ci// 5cc1dc7a3Sopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License"); you may not 6cc1dc7a3Sopenharmony_ci// use this file except in compliance with the License. You may obtain a copy 7cc1dc7a3Sopenharmony_ci// of the License at: 8cc1dc7a3Sopenharmony_ci// 9cc1dc7a3Sopenharmony_ci// http://www.apache.org/licenses/LICENSE-2.0 10cc1dc7a3Sopenharmony_ci// 11cc1dc7a3Sopenharmony_ci// Unless required by applicable law or agreed to in writing, software 12cc1dc7a3Sopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13cc1dc7a3Sopenharmony_ci// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14cc1dc7a3Sopenharmony_ci// License for the specific language governing permissions and limitations 15cc1dc7a3Sopenharmony_ci// under the License. 16cc1dc7a3Sopenharmony_ci// ---------------------------------------------------------------------------- 17cc1dc7a3Sopenharmony_ci 18cc1dc7a3Sopenharmony_ci/** 19cc1dc7a3Sopenharmony_ci * @brief Functions for codec library front-end. 20cc1dc7a3Sopenharmony_ci */ 21cc1dc7a3Sopenharmony_ci 22cc1dc7a3Sopenharmony_ci#include "astcenc.h" 23cc1dc7a3Sopenharmony_ci#include "astcenccli_internal.h" 24cc1dc7a3Sopenharmony_ci 25cc1dc7a3Sopenharmony_ci#if defined(_WIN32) 26cc1dc7a3Sopenharmony_ci #include <io.h> 27cc1dc7a3Sopenharmony_ci #define isatty _isatty 28cc1dc7a3Sopenharmony_ci#else 29cc1dc7a3Sopenharmony_ci #include <unistd.h> 30cc1dc7a3Sopenharmony_ci#endif 31cc1dc7a3Sopenharmony_ci#include <cassert> 32cc1dc7a3Sopenharmony_ci#include <cstring> 33cc1dc7a3Sopenharmony_ci#include <functional> 34cc1dc7a3Sopenharmony_ci#include <string> 35cc1dc7a3Sopenharmony_ci#include <sstream> 36cc1dc7a3Sopenharmony_ci#include <vector> 37cc1dc7a3Sopenharmony_ci#include <memory> 38cc1dc7a3Sopenharmony_ci 39cc1dc7a3Sopenharmony_ci/* ============================================================================ 40cc1dc7a3Sopenharmony_ci Data structure definitions 41cc1dc7a3Sopenharmony_ci============================================================================ */ 42cc1dc7a3Sopenharmony_ci 43cc1dc7a3Sopenharmony_citypedef unsigned int astcenc_operation; 44cc1dc7a3Sopenharmony_ci 45cc1dc7a3Sopenharmony_cistruct mode_entry 46cc1dc7a3Sopenharmony_ci{ 47cc1dc7a3Sopenharmony_ci const char* opt; 48cc1dc7a3Sopenharmony_ci astcenc_operation operation; 49cc1dc7a3Sopenharmony_ci astcenc_profile decode_mode; 50cc1dc7a3Sopenharmony_ci}; 51cc1dc7a3Sopenharmony_ci 52cc1dc7a3Sopenharmony_ci/* ============================================================================ 53cc1dc7a3Sopenharmony_ci Constants and literals 54cc1dc7a3Sopenharmony_ci============================================================================ */ 55cc1dc7a3Sopenharmony_ci 56cc1dc7a3Sopenharmony_ci/** @brief Stage bit indicating we need to load a compressed image. */ 57cc1dc7a3Sopenharmony_cistatic const unsigned int ASTCENC_STAGE_LD_COMP = 1 << 0; 58cc1dc7a3Sopenharmony_ci 59cc1dc7a3Sopenharmony_ci/** @brief Stage bit indicating we need to store a compressed image. */ 60cc1dc7a3Sopenharmony_cistatic const unsigned int ASTCENC_STAGE_ST_COMP = 1 << 1; 61cc1dc7a3Sopenharmony_ci 62cc1dc7a3Sopenharmony_ci/** @brief Stage bit indicating we need to load an uncompressed image. */ 63cc1dc7a3Sopenharmony_cistatic const unsigned int ASTCENC_STAGE_LD_NCOMP = 1 << 2; 64cc1dc7a3Sopenharmony_ci 65cc1dc7a3Sopenharmony_ci/** @brief Stage bit indicating we need to store an uncompressed image. */ 66cc1dc7a3Sopenharmony_cistatic const unsigned int ASTCENC_STAGE_ST_NCOMP = 1 << 3; 67cc1dc7a3Sopenharmony_ci 68cc1dc7a3Sopenharmony_ci/** @brief Stage bit indicating we need compress an image. */ 69cc1dc7a3Sopenharmony_cistatic const unsigned int ASTCENC_STAGE_COMPRESS = 1 << 4; 70cc1dc7a3Sopenharmony_ci 71cc1dc7a3Sopenharmony_ci/** @brief Stage bit indicating we need to decompress an image. */ 72cc1dc7a3Sopenharmony_cistatic const unsigned int ASTCENC_STAGE_DECOMPRESS = 1 << 5; 73cc1dc7a3Sopenharmony_ci 74cc1dc7a3Sopenharmony_ci/** @brief Stage bit indicating we need to compare an image with the original input. */ 75cc1dc7a3Sopenharmony_cistatic const unsigned int ASTCENC_STAGE_COMPARE = 1 << 6; 76cc1dc7a3Sopenharmony_ci 77cc1dc7a3Sopenharmony_ci/** @brief Operation indicating an unknown request (should never happen). */ 78cc1dc7a3Sopenharmony_cistatic const astcenc_operation ASTCENC_OP_UNKNOWN = 0; 79cc1dc7a3Sopenharmony_ci 80cc1dc7a3Sopenharmony_ci/** @brief Operation indicating the user wants to print long-form help text and version info. */ 81cc1dc7a3Sopenharmony_cistatic const astcenc_operation ASTCENC_OP_HELP = 1 << 7; 82cc1dc7a3Sopenharmony_ci 83cc1dc7a3Sopenharmony_ci/** @brief Operation indicating the user wants to print short-form help text and version info. */ 84cc1dc7a3Sopenharmony_cistatic const astcenc_operation ASTCENC_OP_VERSION = 1 << 8; 85cc1dc7a3Sopenharmony_ci 86cc1dc7a3Sopenharmony_ci/** @brief Operation indicating the user wants to compress and store an image. */ 87cc1dc7a3Sopenharmony_cistatic const astcenc_operation ASTCENC_OP_COMPRESS = 88cc1dc7a3Sopenharmony_ci ASTCENC_STAGE_LD_NCOMP | 89cc1dc7a3Sopenharmony_ci ASTCENC_STAGE_COMPRESS | 90cc1dc7a3Sopenharmony_ci ASTCENC_STAGE_ST_COMP; 91cc1dc7a3Sopenharmony_ci 92cc1dc7a3Sopenharmony_ci/** @brief Operation indicating the user wants to decompress and store an image. */ 93cc1dc7a3Sopenharmony_cistatic const astcenc_operation ASTCENC_OP_DECOMPRESS = 94cc1dc7a3Sopenharmony_ci ASTCENC_STAGE_LD_COMP | 95cc1dc7a3Sopenharmony_ci ASTCENC_STAGE_DECOMPRESS | 96cc1dc7a3Sopenharmony_ci ASTCENC_STAGE_ST_NCOMP; 97cc1dc7a3Sopenharmony_ci 98cc1dc7a3Sopenharmony_ci/** @brief Operation indicating the user wants to test a compression setting on an image. */ 99cc1dc7a3Sopenharmony_cistatic const astcenc_operation ASTCENC_OP_TEST = 100cc1dc7a3Sopenharmony_ci ASTCENC_STAGE_LD_NCOMP | 101cc1dc7a3Sopenharmony_ci ASTCENC_STAGE_COMPRESS | 102cc1dc7a3Sopenharmony_ci ASTCENC_STAGE_DECOMPRESS | 103cc1dc7a3Sopenharmony_ci ASTCENC_STAGE_COMPARE | 104cc1dc7a3Sopenharmony_ci ASTCENC_STAGE_ST_NCOMP; 105cc1dc7a3Sopenharmony_ci 106cc1dc7a3Sopenharmony_ci/** 107cc1dc7a3Sopenharmony_ci * @brief Image preprocesing tasks prior to encoding. 108cc1dc7a3Sopenharmony_ci */ 109cc1dc7a3Sopenharmony_cienum astcenc_preprocess 110cc1dc7a3Sopenharmony_ci{ 111cc1dc7a3Sopenharmony_ci /** @brief No image preprocessing. */ 112cc1dc7a3Sopenharmony_ci ASTCENC_PP_NONE = 0, 113cc1dc7a3Sopenharmony_ci /** @brief Normal vector unit-length normalization. */ 114cc1dc7a3Sopenharmony_ci ASTCENC_PP_NORMALIZE, 115cc1dc7a3Sopenharmony_ci /** @brief Color data alpha premultiplication. */ 116cc1dc7a3Sopenharmony_ci ASTCENC_PP_PREMULTIPLY 117cc1dc7a3Sopenharmony_ci}; 118cc1dc7a3Sopenharmony_ci 119cc1dc7a3Sopenharmony_ci/** @brief Decode table for command line operation modes. */ 120cc1dc7a3Sopenharmony_cistatic const mode_entry modes[] { 121cc1dc7a3Sopenharmony_ci {"-cl", ASTCENC_OP_COMPRESS, ASTCENC_PRF_LDR}, 122cc1dc7a3Sopenharmony_ci {"-dl", ASTCENC_OP_DECOMPRESS, ASTCENC_PRF_LDR}, 123cc1dc7a3Sopenharmony_ci {"-tl", ASTCENC_OP_TEST, ASTCENC_PRF_LDR}, 124cc1dc7a3Sopenharmony_ci {"-cs", ASTCENC_OP_COMPRESS, ASTCENC_PRF_LDR_SRGB}, 125cc1dc7a3Sopenharmony_ci {"-ds", ASTCENC_OP_DECOMPRESS, ASTCENC_PRF_LDR_SRGB}, 126cc1dc7a3Sopenharmony_ci {"-ts", ASTCENC_OP_TEST, ASTCENC_PRF_LDR_SRGB}, 127cc1dc7a3Sopenharmony_ci {"-ch", ASTCENC_OP_COMPRESS, ASTCENC_PRF_HDR_RGB_LDR_A}, 128cc1dc7a3Sopenharmony_ci {"-dh", ASTCENC_OP_DECOMPRESS, ASTCENC_PRF_HDR_RGB_LDR_A}, 129cc1dc7a3Sopenharmony_ci {"-th", ASTCENC_OP_TEST, ASTCENC_PRF_HDR_RGB_LDR_A}, 130cc1dc7a3Sopenharmony_ci {"-cH", ASTCENC_OP_COMPRESS, ASTCENC_PRF_HDR}, 131cc1dc7a3Sopenharmony_ci {"-dH", ASTCENC_OP_DECOMPRESS, ASTCENC_PRF_HDR}, 132cc1dc7a3Sopenharmony_ci {"-tH", ASTCENC_OP_TEST, ASTCENC_PRF_HDR}, 133cc1dc7a3Sopenharmony_ci {"-h", ASTCENC_OP_HELP, ASTCENC_PRF_HDR}, 134cc1dc7a3Sopenharmony_ci {"-help", ASTCENC_OP_HELP, ASTCENC_PRF_HDR}, 135cc1dc7a3Sopenharmony_ci {"-v", ASTCENC_OP_VERSION, ASTCENC_PRF_HDR}, 136cc1dc7a3Sopenharmony_ci {"-version", ASTCENC_OP_VERSION, ASTCENC_PRF_HDR} 137cc1dc7a3Sopenharmony_ci}; 138cc1dc7a3Sopenharmony_ci 139cc1dc7a3Sopenharmony_ci/** 140cc1dc7a3Sopenharmony_ci * @brief Compression workload definition for worker threads. 141cc1dc7a3Sopenharmony_ci */ 142cc1dc7a3Sopenharmony_cistruct compression_workload 143cc1dc7a3Sopenharmony_ci{ 144cc1dc7a3Sopenharmony_ci astcenc_context* context; 145cc1dc7a3Sopenharmony_ci astcenc_image* image; 146cc1dc7a3Sopenharmony_ci astcenc_swizzle swizzle; 147cc1dc7a3Sopenharmony_ci uint8_t* data_out; 148cc1dc7a3Sopenharmony_ci size_t data_len; 149cc1dc7a3Sopenharmony_ci astcenc_error error; 150cc1dc7a3Sopenharmony_ci#if QUALITY_CONTROL 151cc1dc7a3Sopenharmony_ci bool calQualityEnable; 152cc1dc7a3Sopenharmony_ci int32_t *mse[RGBA_COM]; 153cc1dc7a3Sopenharmony_ci#endif 154cc1dc7a3Sopenharmony_ci}; 155cc1dc7a3Sopenharmony_ci 156cc1dc7a3Sopenharmony_ci/** 157cc1dc7a3Sopenharmony_ci * @brief Decompression workload definition for worker threads. 158cc1dc7a3Sopenharmony_ci */ 159cc1dc7a3Sopenharmony_cistruct decompression_workload 160cc1dc7a3Sopenharmony_ci{ 161cc1dc7a3Sopenharmony_ci astcenc_context* context; 162cc1dc7a3Sopenharmony_ci uint8_t* data; 163cc1dc7a3Sopenharmony_ci size_t data_len; 164cc1dc7a3Sopenharmony_ci astcenc_image* image_out; 165cc1dc7a3Sopenharmony_ci astcenc_swizzle swizzle; 166cc1dc7a3Sopenharmony_ci astcenc_error error; 167cc1dc7a3Sopenharmony_ci}; 168cc1dc7a3Sopenharmony_ci 169cc1dc7a3Sopenharmony_ci/** 170cc1dc7a3Sopenharmony_ci * @brief Callback emitting a progress bar 171cc1dc7a3Sopenharmony_ci */ 172cc1dc7a3Sopenharmony_ciextern "C" void progress_emitter( 173cc1dc7a3Sopenharmony_ci float value 174cc1dc7a3Sopenharmony_ci) { 175cc1dc7a3Sopenharmony_ci const unsigned int bar_size = 25; 176cc1dc7a3Sopenharmony_ci unsigned int parts = static_cast<int>(value / 4.0f); 177cc1dc7a3Sopenharmony_ci 178cc1dc7a3Sopenharmony_ci char buffer[bar_size + 3]; 179cc1dc7a3Sopenharmony_ci buffer[0] = '['; 180cc1dc7a3Sopenharmony_ci 181cc1dc7a3Sopenharmony_ci for (unsigned int i = 0; i < parts; i++) 182cc1dc7a3Sopenharmony_ci { 183cc1dc7a3Sopenharmony_ci buffer[i + 1] = '='; 184cc1dc7a3Sopenharmony_ci } 185cc1dc7a3Sopenharmony_ci 186cc1dc7a3Sopenharmony_ci for (unsigned int i = parts; i < bar_size; i++) 187cc1dc7a3Sopenharmony_ci { 188cc1dc7a3Sopenharmony_ci buffer[i + 1] = ' '; 189cc1dc7a3Sopenharmony_ci } 190cc1dc7a3Sopenharmony_ci 191cc1dc7a3Sopenharmony_ci buffer[bar_size + 1] = ']'; 192cc1dc7a3Sopenharmony_ci buffer[bar_size + 2] = '\0'; 193cc1dc7a3Sopenharmony_ci 194cc1dc7a3Sopenharmony_ci printf(" Progress: %s %03.1f%%\r", buffer, static_cast<double>(value)); 195cc1dc7a3Sopenharmony_ci fflush(stdout); 196cc1dc7a3Sopenharmony_ci} 197cc1dc7a3Sopenharmony_ci 198cc1dc7a3Sopenharmony_ci/** 199cc1dc7a3Sopenharmony_ci * @brief Test if a string argument is a well formed float. 200cc1dc7a3Sopenharmony_ci */ 201cc1dc7a3Sopenharmony_cistatic bool is_float( 202cc1dc7a3Sopenharmony_ci std::string target 203cc1dc7a3Sopenharmony_ci) { 204cc1dc7a3Sopenharmony_ci float test; 205cc1dc7a3Sopenharmony_ci std::istringstream stream(target); 206cc1dc7a3Sopenharmony_ci 207cc1dc7a3Sopenharmony_ci // Leading whitespace is an error 208cc1dc7a3Sopenharmony_ci stream >> std::noskipws >> test; 209cc1dc7a3Sopenharmony_ci 210cc1dc7a3Sopenharmony_ci // Ensure entire no remaining string in addition to parse failure 211cc1dc7a3Sopenharmony_ci return stream.eof() && !stream.fail(); 212cc1dc7a3Sopenharmony_ci} 213cc1dc7a3Sopenharmony_ci 214cc1dc7a3Sopenharmony_ci/** 215cc1dc7a3Sopenharmony_ci * @brief Test if a string ends with a given suffix. 216cc1dc7a3Sopenharmony_ci */ 217cc1dc7a3Sopenharmony_cistatic bool ends_with( 218cc1dc7a3Sopenharmony_ci const std::string& str, 219cc1dc7a3Sopenharmony_ci const std::string& suffix 220cc1dc7a3Sopenharmony_ci) { 221cc1dc7a3Sopenharmony_ci return (str.size() >= suffix.size()) && 222cc1dc7a3Sopenharmony_ci (0 == str.compare(str.size() - suffix.size(), suffix.size(), suffix)); 223cc1dc7a3Sopenharmony_ci} 224cc1dc7a3Sopenharmony_ci 225cc1dc7a3Sopenharmony_ci/** 226cc1dc7a3Sopenharmony_ci * @brief Runner callback function for a compression worker thread. 227cc1dc7a3Sopenharmony_ci * 228cc1dc7a3Sopenharmony_ci * @param thread_count The number of threads in the worker pool. 229cc1dc7a3Sopenharmony_ci * @param thread_id The index of this thread in the worker pool. 230cc1dc7a3Sopenharmony_ci * @param payload The parameters for this thread. 231cc1dc7a3Sopenharmony_ci */ 232cc1dc7a3Sopenharmony_cistatic void compression_workload_runner( 233cc1dc7a3Sopenharmony_ci int thread_count, 234cc1dc7a3Sopenharmony_ci int thread_id, 235cc1dc7a3Sopenharmony_ci void* payload 236cc1dc7a3Sopenharmony_ci) { 237cc1dc7a3Sopenharmony_ci (void)thread_count; 238cc1dc7a3Sopenharmony_ci 239cc1dc7a3Sopenharmony_ci compression_workload* work = static_cast<compression_workload*>(payload); 240cc1dc7a3Sopenharmony_ci astcenc_error error = astcenc_compress_image( 241cc1dc7a3Sopenharmony_ci work->context, work->image, &work->swizzle, 242cc1dc7a3Sopenharmony_ci work->data_out, work->data_len, 243cc1dc7a3Sopenharmony_ci#if QUALITY_CONTROL 244cc1dc7a3Sopenharmony_ci work->calQualityEnable, work->mse, 245cc1dc7a3Sopenharmony_ci#endif 246cc1dc7a3Sopenharmony_ci thread_id); 247cc1dc7a3Sopenharmony_ci 248cc1dc7a3Sopenharmony_ci // This is a racy update, so which error gets returned is a random, but it 249cc1dc7a3Sopenharmony_ci // will reliably report an error if an error occurs 250cc1dc7a3Sopenharmony_ci if (error != ASTCENC_SUCCESS) 251cc1dc7a3Sopenharmony_ci { 252cc1dc7a3Sopenharmony_ci work->error = error; 253cc1dc7a3Sopenharmony_ci } 254cc1dc7a3Sopenharmony_ci} 255cc1dc7a3Sopenharmony_ci 256cc1dc7a3Sopenharmony_ci/** 257cc1dc7a3Sopenharmony_ci * @brief Runner callback function for a decompression worker thread. 258cc1dc7a3Sopenharmony_ci * 259cc1dc7a3Sopenharmony_ci * @param thread_count The number of threads in the worker pool. 260cc1dc7a3Sopenharmony_ci * @param thread_id The index of this thread in the worker pool. 261cc1dc7a3Sopenharmony_ci * @param payload The parameters for this thread. 262cc1dc7a3Sopenharmony_ci */ 263cc1dc7a3Sopenharmony_cistatic void decompression_workload_runner( 264cc1dc7a3Sopenharmony_ci int thread_count, 265cc1dc7a3Sopenharmony_ci int thread_id, 266cc1dc7a3Sopenharmony_ci void* payload 267cc1dc7a3Sopenharmony_ci) { 268cc1dc7a3Sopenharmony_ci (void)thread_count; 269cc1dc7a3Sopenharmony_ci 270cc1dc7a3Sopenharmony_ci decompression_workload* work = static_cast<decompression_workload*>(payload); 271cc1dc7a3Sopenharmony_ci astcenc_error error = astcenc_decompress_image( 272cc1dc7a3Sopenharmony_ci work->context, work->data, work->data_len, 273cc1dc7a3Sopenharmony_ci work->image_out, &work->swizzle, thread_id); 274cc1dc7a3Sopenharmony_ci 275cc1dc7a3Sopenharmony_ci // This is a racy update, so which error gets returned is a random, but it 276cc1dc7a3Sopenharmony_ci // will reliably report an error if an error occurs 277cc1dc7a3Sopenharmony_ci if (error != ASTCENC_SUCCESS) 278cc1dc7a3Sopenharmony_ci { 279cc1dc7a3Sopenharmony_ci work->error = error; 280cc1dc7a3Sopenharmony_ci } 281cc1dc7a3Sopenharmony_ci} 282cc1dc7a3Sopenharmony_ci 283cc1dc7a3Sopenharmony_ci/** 284cc1dc7a3Sopenharmony_ci * @brief Utility to generate a slice file name from a pattern. 285cc1dc7a3Sopenharmony_ci * 286cc1dc7a3Sopenharmony_ci * Convert "foo/bar.png" in to "foo/bar_<slice>.png" 287cc1dc7a3Sopenharmony_ci * 288cc1dc7a3Sopenharmony_ci * @param basename The base pattern; must contain a file extension. 289cc1dc7a3Sopenharmony_ci * @param index The slice index. 290cc1dc7a3Sopenharmony_ci * @param error Set to true on success, false on error (no extension found). 291cc1dc7a3Sopenharmony_ci * 292cc1dc7a3Sopenharmony_ci * @return The slice file name. 293cc1dc7a3Sopenharmony_ci */ 294cc1dc7a3Sopenharmony_cistatic std::string get_slice_filename( 295cc1dc7a3Sopenharmony_ci const std::string& basename, 296cc1dc7a3Sopenharmony_ci unsigned int index, 297cc1dc7a3Sopenharmony_ci bool& error 298cc1dc7a3Sopenharmony_ci) { 299cc1dc7a3Sopenharmony_ci size_t sep = basename.find_last_of('.'); 300cc1dc7a3Sopenharmony_ci if (sep == std::string::npos) 301cc1dc7a3Sopenharmony_ci { 302cc1dc7a3Sopenharmony_ci error = true; 303cc1dc7a3Sopenharmony_ci return ""; 304cc1dc7a3Sopenharmony_ci } 305cc1dc7a3Sopenharmony_ci 306cc1dc7a3Sopenharmony_ci std::string base = basename.substr(0, sep); 307cc1dc7a3Sopenharmony_ci std::string ext = basename.substr(sep); 308cc1dc7a3Sopenharmony_ci std::string name = base + "_" + std::to_string(index) + ext; 309cc1dc7a3Sopenharmony_ci error = false; 310cc1dc7a3Sopenharmony_ci return name; 311cc1dc7a3Sopenharmony_ci} 312cc1dc7a3Sopenharmony_ci 313cc1dc7a3Sopenharmony_ci/** 314cc1dc7a3Sopenharmony_ci * @brief Load a non-astc image file from memory. 315cc1dc7a3Sopenharmony_ci * 316cc1dc7a3Sopenharmony_ci * @param filename The file to load, or a pattern for array loads. 317cc1dc7a3Sopenharmony_ci * @param dim_z The number of slices to load. 318cc1dc7a3Sopenharmony_ci * @param y_flip Should this image be Y flipped? 319cc1dc7a3Sopenharmony_ci * @param[out] is_hdr Is the loaded image HDR? 320cc1dc7a3Sopenharmony_ci * @param[out] component_count The number of components in the loaded image. 321cc1dc7a3Sopenharmony_ci * 322cc1dc7a3Sopenharmony_ci * @return The astc image file, or nullptr on error. 323cc1dc7a3Sopenharmony_ci */ 324cc1dc7a3Sopenharmony_cistatic astcenc_image* load_uncomp_file( 325cc1dc7a3Sopenharmony_ci const char* filename, 326cc1dc7a3Sopenharmony_ci unsigned int dim_z, 327cc1dc7a3Sopenharmony_ci bool y_flip, 328cc1dc7a3Sopenharmony_ci bool& is_hdr, 329cc1dc7a3Sopenharmony_ci unsigned int& component_count 330cc1dc7a3Sopenharmony_ci) { 331cc1dc7a3Sopenharmony_ci astcenc_image *image = nullptr; 332cc1dc7a3Sopenharmony_ci 333cc1dc7a3Sopenharmony_ci // For a 2D image just load the image directly 334cc1dc7a3Sopenharmony_ci if (dim_z == 1) 335cc1dc7a3Sopenharmony_ci { 336cc1dc7a3Sopenharmony_ci image = load_ncimage(filename, y_flip, is_hdr, component_count); 337cc1dc7a3Sopenharmony_ci } 338cc1dc7a3Sopenharmony_ci else 339cc1dc7a3Sopenharmony_ci { 340cc1dc7a3Sopenharmony_ci bool slice_is_hdr; 341cc1dc7a3Sopenharmony_ci unsigned int slice_component_count; 342cc1dc7a3Sopenharmony_ci astcenc_image* slice = nullptr; 343cc1dc7a3Sopenharmony_ci std::vector<astcenc_image*> slices; 344cc1dc7a3Sopenharmony_ci 345cc1dc7a3Sopenharmony_ci // For a 3D image load an array of slices 346cc1dc7a3Sopenharmony_ci for (unsigned int image_index = 0; image_index < dim_z; image_index++) 347cc1dc7a3Sopenharmony_ci { 348cc1dc7a3Sopenharmony_ci bool error; 349cc1dc7a3Sopenharmony_ci std::string slice_name = get_slice_filename(filename, image_index, error); 350cc1dc7a3Sopenharmony_ci if (error) 351cc1dc7a3Sopenharmony_ci { 352cc1dc7a3Sopenharmony_ci print_error("ERROR: Image pattern does not contain file extension: %s\n", filename); 353cc1dc7a3Sopenharmony_ci break; 354cc1dc7a3Sopenharmony_ci } 355cc1dc7a3Sopenharmony_ci 356cc1dc7a3Sopenharmony_ci slice = load_ncimage(slice_name.c_str(), y_flip, 357cc1dc7a3Sopenharmony_ci slice_is_hdr, slice_component_count); 358cc1dc7a3Sopenharmony_ci if (!slice) 359cc1dc7a3Sopenharmony_ci { 360cc1dc7a3Sopenharmony_ci break; 361cc1dc7a3Sopenharmony_ci } 362cc1dc7a3Sopenharmony_ci 363cc1dc7a3Sopenharmony_ci slices.push_back(slice); 364cc1dc7a3Sopenharmony_ci 365cc1dc7a3Sopenharmony_ci // Check it is not a 3D image 366cc1dc7a3Sopenharmony_ci if (slice->dim_z != 1) 367cc1dc7a3Sopenharmony_ci { 368cc1dc7a3Sopenharmony_ci print_error("ERROR: Image arrays do not support 3D sources: %s\n", slice_name.c_str()); 369cc1dc7a3Sopenharmony_ci break; 370cc1dc7a3Sopenharmony_ci } 371cc1dc7a3Sopenharmony_ci 372cc1dc7a3Sopenharmony_ci // Check slices are consistent with each other 373cc1dc7a3Sopenharmony_ci if (image_index != 0) 374cc1dc7a3Sopenharmony_ci { 375cc1dc7a3Sopenharmony_ci if ((is_hdr != slice_is_hdr) || (component_count != slice_component_count)) 376cc1dc7a3Sopenharmony_ci { 377cc1dc7a3Sopenharmony_ci print_error("ERROR: Image array[0] and [%d] are different formats\n", image_index); 378cc1dc7a3Sopenharmony_ci break; 379cc1dc7a3Sopenharmony_ci } 380cc1dc7a3Sopenharmony_ci 381cc1dc7a3Sopenharmony_ci if ((slices[0]->dim_x != slice->dim_x) || 382cc1dc7a3Sopenharmony_ci (slices[0]->dim_y != slice->dim_y) || 383cc1dc7a3Sopenharmony_ci (slices[0]->dim_z != slice->dim_z)) 384cc1dc7a3Sopenharmony_ci { 385cc1dc7a3Sopenharmony_ci print_error("ERROR: Image array[0] and [%d] are different dimensions\n", image_index); 386cc1dc7a3Sopenharmony_ci break; 387cc1dc7a3Sopenharmony_ci } 388cc1dc7a3Sopenharmony_ci } 389cc1dc7a3Sopenharmony_ci else 390cc1dc7a3Sopenharmony_ci { 391cc1dc7a3Sopenharmony_ci is_hdr = slice_is_hdr; 392cc1dc7a3Sopenharmony_ci component_count = slice_component_count; 393cc1dc7a3Sopenharmony_ci } 394cc1dc7a3Sopenharmony_ci } 395cc1dc7a3Sopenharmony_ci 396cc1dc7a3Sopenharmony_ci // If all slices loaded correctly then repack them into a single image 397cc1dc7a3Sopenharmony_ci if (slices.size() == dim_z) 398cc1dc7a3Sopenharmony_ci { 399cc1dc7a3Sopenharmony_ci unsigned int dim_x = slices[0]->dim_x; 400cc1dc7a3Sopenharmony_ci unsigned int dim_y = slices[0]->dim_y; 401cc1dc7a3Sopenharmony_ci int bitness = is_hdr ? 16 : 8; 402cc1dc7a3Sopenharmony_ci int slice_size = dim_x * dim_y; 403cc1dc7a3Sopenharmony_ci 404cc1dc7a3Sopenharmony_ci image = alloc_image(bitness, dim_x, dim_y, dim_z); 405cc1dc7a3Sopenharmony_ci 406cc1dc7a3Sopenharmony_ci // Combine 2D source images into one 3D image 407cc1dc7a3Sopenharmony_ci for (unsigned int z = 0; z < dim_z; z++) 408cc1dc7a3Sopenharmony_ci { 409cc1dc7a3Sopenharmony_ci if (image->data_type == ASTCENC_TYPE_U8) 410cc1dc7a3Sopenharmony_ci { 411cc1dc7a3Sopenharmony_ci uint8_t* data8 = static_cast<uint8_t*>(image->data[z]); 412cc1dc7a3Sopenharmony_ci uint8_t* data8src = static_cast<uint8_t*>(slices[z]->data[0]); 413cc1dc7a3Sopenharmony_ci size_t copy_size = slice_size * 4 * sizeof(uint8_t); 414cc1dc7a3Sopenharmony_ci memcpy(data8, data8src, copy_size); 415cc1dc7a3Sopenharmony_ci } 416cc1dc7a3Sopenharmony_ci else if (image->data_type == ASTCENC_TYPE_F16) 417cc1dc7a3Sopenharmony_ci { 418cc1dc7a3Sopenharmony_ci uint16_t* data16 = static_cast<uint16_t*>(image->data[z]); 419cc1dc7a3Sopenharmony_ci uint16_t* data16src = static_cast<uint16_t*>(slices[z]->data[0]); 420cc1dc7a3Sopenharmony_ci size_t copy_size = slice_size * 4 * sizeof(uint16_t); 421cc1dc7a3Sopenharmony_ci memcpy(data16, data16src, copy_size); 422cc1dc7a3Sopenharmony_ci } 423cc1dc7a3Sopenharmony_ci else // if (image->data_type == ASTCENC_TYPE_F32) 424cc1dc7a3Sopenharmony_ci { 425cc1dc7a3Sopenharmony_ci assert(image->data_type == ASTCENC_TYPE_F32); 426cc1dc7a3Sopenharmony_ci float* data32 = static_cast<float*>(image->data[z]); 427cc1dc7a3Sopenharmony_ci float* data32src = static_cast<float*>(slices[z]->data[0]); 428cc1dc7a3Sopenharmony_ci size_t copy_size = slice_size * 4 * sizeof(float); 429cc1dc7a3Sopenharmony_ci memcpy(data32, data32src, copy_size); 430cc1dc7a3Sopenharmony_ci } 431cc1dc7a3Sopenharmony_ci } 432cc1dc7a3Sopenharmony_ci } 433cc1dc7a3Sopenharmony_ci 434cc1dc7a3Sopenharmony_ci for (auto &i : slices) 435cc1dc7a3Sopenharmony_ci { 436cc1dc7a3Sopenharmony_ci free_image(i); 437cc1dc7a3Sopenharmony_ci } 438cc1dc7a3Sopenharmony_ci } 439cc1dc7a3Sopenharmony_ci 440cc1dc7a3Sopenharmony_ci return image; 441cc1dc7a3Sopenharmony_ci} 442cc1dc7a3Sopenharmony_ci 443cc1dc7a3Sopenharmony_ci/** 444cc1dc7a3Sopenharmony_ci * @brief Parse the command line. 445cc1dc7a3Sopenharmony_ci * 446cc1dc7a3Sopenharmony_ci * @param argc Command line argument count. 447cc1dc7a3Sopenharmony_ci * @param[in] argv Command line argument vector. 448cc1dc7a3Sopenharmony_ci * @param[out] operation Codec operation mode. 449cc1dc7a3Sopenharmony_ci * @param[out] profile Codec color profile. 450cc1dc7a3Sopenharmony_ci * 451cc1dc7a3Sopenharmony_ci * @return 0 if everything is okay, 1 if there is some error 452cc1dc7a3Sopenharmony_ci */ 453cc1dc7a3Sopenharmony_cistatic int parse_commandline_options( 454cc1dc7a3Sopenharmony_ci int argc, 455cc1dc7a3Sopenharmony_ci char **argv, 456cc1dc7a3Sopenharmony_ci astcenc_operation& operation, 457cc1dc7a3Sopenharmony_ci astcenc_profile& profile 458cc1dc7a3Sopenharmony_ci) { 459cc1dc7a3Sopenharmony_ci assert(argc >= 2); (void)argc; 460cc1dc7a3Sopenharmony_ci 461cc1dc7a3Sopenharmony_ci profile = ASTCENC_PRF_LDR; 462cc1dc7a3Sopenharmony_ci operation = ASTCENC_OP_UNKNOWN; 463cc1dc7a3Sopenharmony_ci 464cc1dc7a3Sopenharmony_ci int modes_count = sizeof(modes) / sizeof(modes[0]); 465cc1dc7a3Sopenharmony_ci for (int i = 0; i < modes_count; i++) 466cc1dc7a3Sopenharmony_ci { 467cc1dc7a3Sopenharmony_ci if (!strcmp(modes[i].opt, argv[1])) 468cc1dc7a3Sopenharmony_ci { 469cc1dc7a3Sopenharmony_ci operation = modes[i].operation; 470cc1dc7a3Sopenharmony_ci profile = modes[i].decode_mode; 471cc1dc7a3Sopenharmony_ci break; 472cc1dc7a3Sopenharmony_ci } 473cc1dc7a3Sopenharmony_ci } 474cc1dc7a3Sopenharmony_ci 475cc1dc7a3Sopenharmony_ci if (operation == ASTCENC_OP_UNKNOWN) 476cc1dc7a3Sopenharmony_ci { 477cc1dc7a3Sopenharmony_ci print_error("ERROR: Unrecognized operation '%s'\n", argv[1]); 478cc1dc7a3Sopenharmony_ci return 1; 479cc1dc7a3Sopenharmony_ci } 480cc1dc7a3Sopenharmony_ci 481cc1dc7a3Sopenharmony_ci return 0; 482cc1dc7a3Sopenharmony_ci} 483cc1dc7a3Sopenharmony_ci 484cc1dc7a3Sopenharmony_ci/** 485cc1dc7a3Sopenharmony_ci * @brief Initialize the astcenc_config 486cc1dc7a3Sopenharmony_ci * 487cc1dc7a3Sopenharmony_ci * @param argc Command line argument count. 488cc1dc7a3Sopenharmony_ci * @param[in] argv Command line argument vector. 489cc1dc7a3Sopenharmony_ci * @param operation Codec operation mode. 490cc1dc7a3Sopenharmony_ci * @param[out] profile Codec color profile. 491cc1dc7a3Sopenharmony_ci * @param comp_image Compressed image if a decompress operation. 492cc1dc7a3Sopenharmony_ci * @param[out] preprocess Image preprocess operation. 493cc1dc7a3Sopenharmony_ci * @param[out] config Codec configuration. 494cc1dc7a3Sopenharmony_ci * 495cc1dc7a3Sopenharmony_ci * @return 0 if everything is okay, 1 if there is some error 496cc1dc7a3Sopenharmony_ci */ 497cc1dc7a3Sopenharmony_cistatic int init_astcenc_config( 498cc1dc7a3Sopenharmony_ci int argc, 499cc1dc7a3Sopenharmony_ci char **argv, 500cc1dc7a3Sopenharmony_ci astcenc_profile profile, 501cc1dc7a3Sopenharmony_ci astcenc_operation operation, 502cc1dc7a3Sopenharmony_ci astc_compressed_image& comp_image, 503cc1dc7a3Sopenharmony_ci astcenc_preprocess& preprocess, 504cc1dc7a3Sopenharmony_ci astcenc_config& config 505cc1dc7a3Sopenharmony_ci) { 506cc1dc7a3Sopenharmony_ci unsigned int block_x = 0; 507cc1dc7a3Sopenharmony_ci unsigned int block_y = 0; 508cc1dc7a3Sopenharmony_ci unsigned int block_z = 1; 509cc1dc7a3Sopenharmony_ci 510cc1dc7a3Sopenharmony_ci // For decode the block size is set by the incoming image. 511cc1dc7a3Sopenharmony_ci if (operation == ASTCENC_OP_DECOMPRESS) 512cc1dc7a3Sopenharmony_ci { 513cc1dc7a3Sopenharmony_ci block_x = comp_image.block_x; 514cc1dc7a3Sopenharmony_ci block_y = comp_image.block_y; 515cc1dc7a3Sopenharmony_ci block_z = comp_image.block_z; 516cc1dc7a3Sopenharmony_ci } 517cc1dc7a3Sopenharmony_ci 518cc1dc7a3Sopenharmony_ci float quality = 0.0f; 519cc1dc7a3Sopenharmony_ci preprocess = ASTCENC_PP_NONE; 520cc1dc7a3Sopenharmony_ci 521cc1dc7a3Sopenharmony_ci // parse the command line's encoding options. 522cc1dc7a3Sopenharmony_ci int argidx = 4; 523cc1dc7a3Sopenharmony_ci if (operation & ASTCENC_STAGE_COMPRESS) 524cc1dc7a3Sopenharmony_ci { 525cc1dc7a3Sopenharmony_ci // Read and decode block size 526cc1dc7a3Sopenharmony_ci if (argc < 5) 527cc1dc7a3Sopenharmony_ci { 528cc1dc7a3Sopenharmony_ci print_error("ERROR: Block size must be specified\n"); 529cc1dc7a3Sopenharmony_ci return 1; 530cc1dc7a3Sopenharmony_ci } 531cc1dc7a3Sopenharmony_ci 532cc1dc7a3Sopenharmony_ci int cnt2D, cnt3D; 533cc1dc7a3Sopenharmony_ci int dimensions = sscanf(argv[4], "%ux%u%nx%u%n", 534cc1dc7a3Sopenharmony_ci &block_x, &block_y, &cnt2D, &block_z, &cnt3D); 535cc1dc7a3Sopenharmony_ci // Character after the last match should be a NUL 536cc1dc7a3Sopenharmony_ci if (!(((dimensions == 2) && !argv[4][cnt2D]) || ((dimensions == 3) && !argv[4][cnt3D]))) 537cc1dc7a3Sopenharmony_ci { 538cc1dc7a3Sopenharmony_ci print_error("ERROR: Block size '%s' is invalid\n", argv[4]); 539cc1dc7a3Sopenharmony_ci return 1; 540cc1dc7a3Sopenharmony_ci } 541cc1dc7a3Sopenharmony_ci 542cc1dc7a3Sopenharmony_ci // Read and decode search quality 543cc1dc7a3Sopenharmony_ci if (argc < 6) 544cc1dc7a3Sopenharmony_ci { 545cc1dc7a3Sopenharmony_ci print_error("ERROR: Search quality level must be specified\n"); 546cc1dc7a3Sopenharmony_ci return 1; 547cc1dc7a3Sopenharmony_ci } 548cc1dc7a3Sopenharmony_ci 549cc1dc7a3Sopenharmony_ci if (!strcmp(argv[5], "-fastest")) 550cc1dc7a3Sopenharmony_ci { 551cc1dc7a3Sopenharmony_ci quality = ASTCENC_PRE_FASTEST; 552cc1dc7a3Sopenharmony_ci } 553cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[5], "-fast")) 554cc1dc7a3Sopenharmony_ci { 555cc1dc7a3Sopenharmony_ci quality = ASTCENC_PRE_FAST; 556cc1dc7a3Sopenharmony_ci } 557cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[5], "-medium")) 558cc1dc7a3Sopenharmony_ci { 559cc1dc7a3Sopenharmony_ci quality = ASTCENC_PRE_MEDIUM; 560cc1dc7a3Sopenharmony_ci } 561cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[5], "-thorough")) 562cc1dc7a3Sopenharmony_ci { 563cc1dc7a3Sopenharmony_ci quality = ASTCENC_PRE_THOROUGH; 564cc1dc7a3Sopenharmony_ci } 565cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[5], "-verythorough")) 566cc1dc7a3Sopenharmony_ci { 567cc1dc7a3Sopenharmony_ci quality = ASTCENC_PRE_VERYTHOROUGH; 568cc1dc7a3Sopenharmony_ci } 569cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[5], "-exhaustive")) 570cc1dc7a3Sopenharmony_ci { 571cc1dc7a3Sopenharmony_ci quality = ASTCENC_PRE_EXHAUSTIVE; 572cc1dc7a3Sopenharmony_ci } 573cc1dc7a3Sopenharmony_ci else if (is_float(argv[5])) 574cc1dc7a3Sopenharmony_ci { 575cc1dc7a3Sopenharmony_ci quality = static_cast<float>(atof(argv[5])); 576cc1dc7a3Sopenharmony_ci } 577cc1dc7a3Sopenharmony_ci else 578cc1dc7a3Sopenharmony_ci { 579cc1dc7a3Sopenharmony_ci print_error("ERROR: Search quality/preset '%s' is invalid\n", argv[5]); 580cc1dc7a3Sopenharmony_ci return 1; 581cc1dc7a3Sopenharmony_ci } 582cc1dc7a3Sopenharmony_ci 583cc1dc7a3Sopenharmony_ci argidx = 6; 584cc1dc7a3Sopenharmony_ci } 585cc1dc7a3Sopenharmony_ci 586cc1dc7a3Sopenharmony_ci unsigned int flags = 0; 587cc1dc7a3Sopenharmony_ci 588cc1dc7a3Sopenharmony_ci // Gather the flags that we need 589cc1dc7a3Sopenharmony_ci while (argidx < argc) 590cc1dc7a3Sopenharmony_ci { 591cc1dc7a3Sopenharmony_ci if (!strcmp(argv[argidx], "-a")) 592cc1dc7a3Sopenharmony_ci { 593cc1dc7a3Sopenharmony_ci // Skip over the data value for now 594cc1dc7a3Sopenharmony_ci argidx++; 595cc1dc7a3Sopenharmony_ci flags |= ASTCENC_FLG_USE_ALPHA_WEIGHT; 596cc1dc7a3Sopenharmony_ci } 597cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-normal")) 598cc1dc7a3Sopenharmony_ci { 599cc1dc7a3Sopenharmony_ci flags |= ASTCENC_FLG_MAP_NORMAL; 600cc1dc7a3Sopenharmony_ci } 601cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-decode_unorm8")) 602cc1dc7a3Sopenharmony_ci { 603cc1dc7a3Sopenharmony_ci flags |= ASTCENC_FLG_USE_DECODE_UNORM8; 604cc1dc7a3Sopenharmony_ci } 605cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-rgbm")) 606cc1dc7a3Sopenharmony_ci { 607cc1dc7a3Sopenharmony_ci // Skip over the data value for now 608cc1dc7a3Sopenharmony_ci argidx++; 609cc1dc7a3Sopenharmony_ci flags |= ASTCENC_FLG_MAP_RGBM; 610cc1dc7a3Sopenharmony_ci } 611cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-perceptual")) 612cc1dc7a3Sopenharmony_ci { 613cc1dc7a3Sopenharmony_ci flags |= ASTCENC_FLG_USE_PERCEPTUAL; 614cc1dc7a3Sopenharmony_ci } 615cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-pp-normalize")) 616cc1dc7a3Sopenharmony_ci { 617cc1dc7a3Sopenharmony_ci if (preprocess != ASTCENC_PP_NONE) 618cc1dc7a3Sopenharmony_ci { 619cc1dc7a3Sopenharmony_ci print_error("ERROR: Only a single image preprocess can be used\n"); 620cc1dc7a3Sopenharmony_ci return 1; 621cc1dc7a3Sopenharmony_ci } 622cc1dc7a3Sopenharmony_ci preprocess = ASTCENC_PP_NORMALIZE; 623cc1dc7a3Sopenharmony_ci } 624cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-pp-premultiply")) 625cc1dc7a3Sopenharmony_ci { 626cc1dc7a3Sopenharmony_ci if (preprocess != ASTCENC_PP_NONE) 627cc1dc7a3Sopenharmony_ci { 628cc1dc7a3Sopenharmony_ci print_error("ERROR: Only a single image preprocess can be used\n"); 629cc1dc7a3Sopenharmony_ci return 1; 630cc1dc7a3Sopenharmony_ci } 631cc1dc7a3Sopenharmony_ci preprocess = ASTCENC_PP_PREMULTIPLY; 632cc1dc7a3Sopenharmony_ci } 633cc1dc7a3Sopenharmony_ci argidx ++; 634cc1dc7a3Sopenharmony_ci } 635cc1dc7a3Sopenharmony_ci 636cc1dc7a3Sopenharmony_ci#if defined(ASTCENC_DECOMPRESS_ONLY) 637cc1dc7a3Sopenharmony_ci flags |= ASTCENC_FLG_DECOMPRESS_ONLY; 638cc1dc7a3Sopenharmony_ci#else 639cc1dc7a3Sopenharmony_ci // Decompression can skip some memory allocation, but need full tables 640cc1dc7a3Sopenharmony_ci if (operation == ASTCENC_OP_DECOMPRESS) 641cc1dc7a3Sopenharmony_ci { 642cc1dc7a3Sopenharmony_ci flags |= ASTCENC_FLG_DECOMPRESS_ONLY; 643cc1dc7a3Sopenharmony_ci } 644cc1dc7a3Sopenharmony_ci // Compression and test passes can skip some decimation initialization 645cc1dc7a3Sopenharmony_ci // as we know we are decompressing images that were compressed using the 646cc1dc7a3Sopenharmony_ci // same settings and heuristics ... 647cc1dc7a3Sopenharmony_ci else 648cc1dc7a3Sopenharmony_ci { 649cc1dc7a3Sopenharmony_ci flags |= ASTCENC_FLG_SELF_DECOMPRESS_ONLY; 650cc1dc7a3Sopenharmony_ci } 651cc1dc7a3Sopenharmony_ci#endif 652cc1dc7a3Sopenharmony_ci 653cc1dc7a3Sopenharmony_ci astcenc_error status = astcenc_config_init(profile, block_x, block_y, block_z, 654cc1dc7a3Sopenharmony_ci quality, flags, &config); 655cc1dc7a3Sopenharmony_ci if (status == ASTCENC_ERR_BAD_BLOCK_SIZE) 656cc1dc7a3Sopenharmony_ci { 657cc1dc7a3Sopenharmony_ci print_error("ERROR: Block size '%s' is invalid\n", argv[4]); 658cc1dc7a3Sopenharmony_ci return 1; 659cc1dc7a3Sopenharmony_ci } 660cc1dc7a3Sopenharmony_ci else if (status == ASTCENC_ERR_BAD_DECODE_MODE) 661cc1dc7a3Sopenharmony_ci { 662cc1dc7a3Sopenharmony_ci print_error("ERROR: Decode_unorm8 is not supported by HDR profiles\n", argv[4]); 663cc1dc7a3Sopenharmony_ci return 1; 664cc1dc7a3Sopenharmony_ci } 665cc1dc7a3Sopenharmony_ci else if (status == ASTCENC_ERR_BAD_CPU_FLOAT) 666cc1dc7a3Sopenharmony_ci { 667cc1dc7a3Sopenharmony_ci print_error("ERROR: astcenc must not be compiled with -ffast-math\n"); 668cc1dc7a3Sopenharmony_ci return 1; 669cc1dc7a3Sopenharmony_ci } 670cc1dc7a3Sopenharmony_ci else if (status != ASTCENC_SUCCESS) 671cc1dc7a3Sopenharmony_ci { 672cc1dc7a3Sopenharmony_ci print_error("ERROR: Init config failed with %s\n", astcenc_get_error_string(status)); 673cc1dc7a3Sopenharmony_ci return 1; 674cc1dc7a3Sopenharmony_ci } 675cc1dc7a3Sopenharmony_ci 676cc1dc7a3Sopenharmony_ci return 0; 677cc1dc7a3Sopenharmony_ci} 678cc1dc7a3Sopenharmony_ci 679cc1dc7a3Sopenharmony_ci/** 680cc1dc7a3Sopenharmony_ci * @brief Edit the astcenc_config 681cc1dc7a3Sopenharmony_ci * 682cc1dc7a3Sopenharmony_ci * @param argc Command line argument count. 683cc1dc7a3Sopenharmony_ci * @param[in] argv Command line argument vector. 684cc1dc7a3Sopenharmony_ci * @param operation Codec operation. 685cc1dc7a3Sopenharmony_ci * @param[out] cli_config Command line config. 686cc1dc7a3Sopenharmony_ci * @param[in,out] config Codec configuration. 687cc1dc7a3Sopenharmony_ci * 688cc1dc7a3Sopenharmony_ci * @return 0 if everything is OK, 1 if there is some error 689cc1dc7a3Sopenharmony_ci */ 690cc1dc7a3Sopenharmony_cistatic int edit_astcenc_config( 691cc1dc7a3Sopenharmony_ci int argc, 692cc1dc7a3Sopenharmony_ci char **argv, 693cc1dc7a3Sopenharmony_ci const astcenc_operation operation, 694cc1dc7a3Sopenharmony_ci cli_config_options& cli_config, 695cc1dc7a3Sopenharmony_ci astcenc_config& config 696cc1dc7a3Sopenharmony_ci) { 697cc1dc7a3Sopenharmony_ci 698cc1dc7a3Sopenharmony_ci int argidx = (operation & ASTCENC_STAGE_COMPRESS) ? 6 : 4; 699cc1dc7a3Sopenharmony_ci config.privateProfile = HIGH_QUALITY_PROFILE; 700cc1dc7a3Sopenharmony_ci while (argidx < argc) 701cc1dc7a3Sopenharmony_ci { 702cc1dc7a3Sopenharmony_ci if (!strcmp(argv[argidx], "-silent")) 703cc1dc7a3Sopenharmony_ci { 704cc1dc7a3Sopenharmony_ci argidx++; 705cc1dc7a3Sopenharmony_ci cli_config.silentmode = 1; 706cc1dc7a3Sopenharmony_ci } 707cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-cw")) 708cc1dc7a3Sopenharmony_ci { 709cc1dc7a3Sopenharmony_ci argidx += 5; 710cc1dc7a3Sopenharmony_ci if (argidx > argc) 711cc1dc7a3Sopenharmony_ci { 712cc1dc7a3Sopenharmony_ci print_error("ERROR: -cw switch with less than 4 arguments\n"); 713cc1dc7a3Sopenharmony_ci return 1; 714cc1dc7a3Sopenharmony_ci } 715cc1dc7a3Sopenharmony_ci 716cc1dc7a3Sopenharmony_ci config.cw_r_weight = static_cast<float>(atof(argv[argidx - 4])); 717cc1dc7a3Sopenharmony_ci config.cw_g_weight = static_cast<float>(atof(argv[argidx - 3])); 718cc1dc7a3Sopenharmony_ci config.cw_b_weight = static_cast<float>(atof(argv[argidx - 2])); 719cc1dc7a3Sopenharmony_ci config.cw_a_weight = static_cast<float>(atof(argv[argidx - 1])); 720cc1dc7a3Sopenharmony_ci } 721cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-a")) 722cc1dc7a3Sopenharmony_ci { 723cc1dc7a3Sopenharmony_ci argidx += 2; 724cc1dc7a3Sopenharmony_ci if (argidx > argc) 725cc1dc7a3Sopenharmony_ci { 726cc1dc7a3Sopenharmony_ci print_error("ERROR: -a switch with no argument\n"); 727cc1dc7a3Sopenharmony_ci return 1; 728cc1dc7a3Sopenharmony_ci } 729cc1dc7a3Sopenharmony_ci 730cc1dc7a3Sopenharmony_ci config.a_scale_radius = atoi(argv[argidx - 1]); 731cc1dc7a3Sopenharmony_ci } 732cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-esw")) 733cc1dc7a3Sopenharmony_ci { 734cc1dc7a3Sopenharmony_ci argidx += 2; 735cc1dc7a3Sopenharmony_ci if (argidx > argc) 736cc1dc7a3Sopenharmony_ci { 737cc1dc7a3Sopenharmony_ci print_error("ERROR: -esw switch with no argument\n"); 738cc1dc7a3Sopenharmony_ci return 1; 739cc1dc7a3Sopenharmony_ci } 740cc1dc7a3Sopenharmony_ci 741cc1dc7a3Sopenharmony_ci if (strlen(argv[argidx - 1]) != 4) 742cc1dc7a3Sopenharmony_ci { 743cc1dc7a3Sopenharmony_ci print_error("ERROR: -esw pattern does not contain 4 characters\n"); 744cc1dc7a3Sopenharmony_ci return 1; 745cc1dc7a3Sopenharmony_ci } 746cc1dc7a3Sopenharmony_ci 747cc1dc7a3Sopenharmony_ci astcenc_swz swizzle_components[4]; 748cc1dc7a3Sopenharmony_ci for (int i = 0; i < 4; i++) 749cc1dc7a3Sopenharmony_ci { 750cc1dc7a3Sopenharmony_ci switch (argv[argidx - 1][i]) 751cc1dc7a3Sopenharmony_ci { 752cc1dc7a3Sopenharmony_ci case 'r': 753cc1dc7a3Sopenharmony_ci swizzle_components[i] = ASTCENC_SWZ_R; 754cc1dc7a3Sopenharmony_ci break; 755cc1dc7a3Sopenharmony_ci case 'g': 756cc1dc7a3Sopenharmony_ci swizzle_components[i] = ASTCENC_SWZ_G; 757cc1dc7a3Sopenharmony_ci break; 758cc1dc7a3Sopenharmony_ci case 'b': 759cc1dc7a3Sopenharmony_ci swizzle_components[i] = ASTCENC_SWZ_B; 760cc1dc7a3Sopenharmony_ci break; 761cc1dc7a3Sopenharmony_ci case 'a': 762cc1dc7a3Sopenharmony_ci swizzle_components[i] = ASTCENC_SWZ_A; 763cc1dc7a3Sopenharmony_ci break; 764cc1dc7a3Sopenharmony_ci case '0': 765cc1dc7a3Sopenharmony_ci swizzle_components[i] = ASTCENC_SWZ_0; 766cc1dc7a3Sopenharmony_ci break; 767cc1dc7a3Sopenharmony_ci case '1': 768cc1dc7a3Sopenharmony_ci swizzle_components[i] = ASTCENC_SWZ_1; 769cc1dc7a3Sopenharmony_ci break; 770cc1dc7a3Sopenharmony_ci default: 771cc1dc7a3Sopenharmony_ci print_error("ERROR: -esw component '%c' is not valid\n", argv[argidx - 1][i]); 772cc1dc7a3Sopenharmony_ci return 1; 773cc1dc7a3Sopenharmony_ci } 774cc1dc7a3Sopenharmony_ci } 775cc1dc7a3Sopenharmony_ci 776cc1dc7a3Sopenharmony_ci cli_config.swz_encode.r = swizzle_components[0]; 777cc1dc7a3Sopenharmony_ci cli_config.swz_encode.g = swizzle_components[1]; 778cc1dc7a3Sopenharmony_ci cli_config.swz_encode.b = swizzle_components[2]; 779cc1dc7a3Sopenharmony_ci cli_config.swz_encode.a = swizzle_components[3]; 780cc1dc7a3Sopenharmony_ci } 781cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-ssw")) 782cc1dc7a3Sopenharmony_ci { 783cc1dc7a3Sopenharmony_ci argidx += 2; 784cc1dc7a3Sopenharmony_ci if (argidx > argc) 785cc1dc7a3Sopenharmony_ci { 786cc1dc7a3Sopenharmony_ci print_error("ERROR: -ssw switch with no argument\n"); 787cc1dc7a3Sopenharmony_ci return 1; 788cc1dc7a3Sopenharmony_ci } 789cc1dc7a3Sopenharmony_ci 790cc1dc7a3Sopenharmony_ci size_t char_count = strlen(argv[argidx - 1]); 791cc1dc7a3Sopenharmony_ci if (char_count == 0) 792cc1dc7a3Sopenharmony_ci { 793cc1dc7a3Sopenharmony_ci print_error("ERROR: -ssw pattern contains no characters\n"); 794cc1dc7a3Sopenharmony_ci return 1; 795cc1dc7a3Sopenharmony_ci } 796cc1dc7a3Sopenharmony_ci 797cc1dc7a3Sopenharmony_ci if (char_count > 4) 798cc1dc7a3Sopenharmony_ci { 799cc1dc7a3Sopenharmony_ci print_error("ERROR: -ssw pattern contains more than 4 characters\n"); 800cc1dc7a3Sopenharmony_ci return 1; 801cc1dc7a3Sopenharmony_ci } 802cc1dc7a3Sopenharmony_ci 803cc1dc7a3Sopenharmony_ci bool found_r = false; 804cc1dc7a3Sopenharmony_ci bool found_g = false; 805cc1dc7a3Sopenharmony_ci bool found_b = false; 806cc1dc7a3Sopenharmony_ci bool found_a = false; 807cc1dc7a3Sopenharmony_ci 808cc1dc7a3Sopenharmony_ci for (size_t i = 0; i < char_count; i++) 809cc1dc7a3Sopenharmony_ci { 810cc1dc7a3Sopenharmony_ci switch (argv[argidx - 1][i]) 811cc1dc7a3Sopenharmony_ci { 812cc1dc7a3Sopenharmony_ci case 'r': 813cc1dc7a3Sopenharmony_ci found_r = true; 814cc1dc7a3Sopenharmony_ci break; 815cc1dc7a3Sopenharmony_ci case 'g': 816cc1dc7a3Sopenharmony_ci found_g = true; 817cc1dc7a3Sopenharmony_ci break; 818cc1dc7a3Sopenharmony_ci case 'b': 819cc1dc7a3Sopenharmony_ci found_b = true; 820cc1dc7a3Sopenharmony_ci break; 821cc1dc7a3Sopenharmony_ci case 'a': 822cc1dc7a3Sopenharmony_ci found_a = true; 823cc1dc7a3Sopenharmony_ci break; 824cc1dc7a3Sopenharmony_ci default: 825cc1dc7a3Sopenharmony_ci print_error("ERROR: -ssw component '%c' is not valid\n", argv[argidx - 1][i]); 826cc1dc7a3Sopenharmony_ci return 1; 827cc1dc7a3Sopenharmony_ci } 828cc1dc7a3Sopenharmony_ci } 829cc1dc7a3Sopenharmony_ci 830cc1dc7a3Sopenharmony_ci config.cw_r_weight = found_r ? 1.0f : 0.0f; 831cc1dc7a3Sopenharmony_ci config.cw_g_weight = found_g ? 1.0f : 0.0f; 832cc1dc7a3Sopenharmony_ci config.cw_b_weight = found_b ? 1.0f : 0.0f; 833cc1dc7a3Sopenharmony_ci config.cw_a_weight = found_a ? 1.0f : 0.0f; 834cc1dc7a3Sopenharmony_ci } 835cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-dsw")) 836cc1dc7a3Sopenharmony_ci { 837cc1dc7a3Sopenharmony_ci argidx += 2; 838cc1dc7a3Sopenharmony_ci if (argidx > argc) 839cc1dc7a3Sopenharmony_ci { 840cc1dc7a3Sopenharmony_ci print_error("ERROR: -dsw switch with no argument\n"); 841cc1dc7a3Sopenharmony_ci return 1; 842cc1dc7a3Sopenharmony_ci } 843cc1dc7a3Sopenharmony_ci 844cc1dc7a3Sopenharmony_ci if (strlen(argv[argidx - 1]) != 4) 845cc1dc7a3Sopenharmony_ci { 846cc1dc7a3Sopenharmony_ci print_error("ERROR: -dsw switch does not contain 4 characters\n"); 847cc1dc7a3Sopenharmony_ci return 1; 848cc1dc7a3Sopenharmony_ci } 849cc1dc7a3Sopenharmony_ci 850cc1dc7a3Sopenharmony_ci astcenc_swz swizzle_components[4]; 851cc1dc7a3Sopenharmony_ci for (int i = 0; i < 4; i++) 852cc1dc7a3Sopenharmony_ci { 853cc1dc7a3Sopenharmony_ci switch (argv[argidx - 1][i]) 854cc1dc7a3Sopenharmony_ci { 855cc1dc7a3Sopenharmony_ci case 'r': 856cc1dc7a3Sopenharmony_ci swizzle_components[i] = ASTCENC_SWZ_R; 857cc1dc7a3Sopenharmony_ci break; 858cc1dc7a3Sopenharmony_ci case 'g': 859cc1dc7a3Sopenharmony_ci swizzle_components[i] = ASTCENC_SWZ_G; 860cc1dc7a3Sopenharmony_ci break; 861cc1dc7a3Sopenharmony_ci case 'b': 862cc1dc7a3Sopenharmony_ci swizzle_components[i] = ASTCENC_SWZ_B; 863cc1dc7a3Sopenharmony_ci break; 864cc1dc7a3Sopenharmony_ci case 'a': 865cc1dc7a3Sopenharmony_ci swizzle_components[i] = ASTCENC_SWZ_A; 866cc1dc7a3Sopenharmony_ci break; 867cc1dc7a3Sopenharmony_ci case '0': 868cc1dc7a3Sopenharmony_ci swizzle_components[i] = ASTCENC_SWZ_0; 869cc1dc7a3Sopenharmony_ci break; 870cc1dc7a3Sopenharmony_ci case '1': 871cc1dc7a3Sopenharmony_ci swizzle_components[i] = ASTCENC_SWZ_1; 872cc1dc7a3Sopenharmony_ci break; 873cc1dc7a3Sopenharmony_ci case 'z': 874cc1dc7a3Sopenharmony_ci swizzle_components[i] = ASTCENC_SWZ_Z; 875cc1dc7a3Sopenharmony_ci break; 876cc1dc7a3Sopenharmony_ci default: 877cc1dc7a3Sopenharmony_ci print_error("ERROR: ERROR: -dsw component '%c' is not valid\n", argv[argidx - 1][i]); 878cc1dc7a3Sopenharmony_ci return 1; 879cc1dc7a3Sopenharmony_ci } 880cc1dc7a3Sopenharmony_ci } 881cc1dc7a3Sopenharmony_ci 882cc1dc7a3Sopenharmony_ci cli_config.swz_decode.r = swizzle_components[0]; 883cc1dc7a3Sopenharmony_ci cli_config.swz_decode.g = swizzle_components[1]; 884cc1dc7a3Sopenharmony_ci cli_config.swz_decode.b = swizzle_components[2]; 885cc1dc7a3Sopenharmony_ci cli_config.swz_decode.a = swizzle_components[3]; 886cc1dc7a3Sopenharmony_ci } 887cc1dc7a3Sopenharmony_ci // presets begin here 888cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-normal")) 889cc1dc7a3Sopenharmony_ci { 890cc1dc7a3Sopenharmony_ci argidx++; 891cc1dc7a3Sopenharmony_ci 892cc1dc7a3Sopenharmony_ci cli_config.swz_encode.r = ASTCENC_SWZ_R; 893cc1dc7a3Sopenharmony_ci cli_config.swz_encode.g = ASTCENC_SWZ_R; 894cc1dc7a3Sopenharmony_ci cli_config.swz_encode.b = ASTCENC_SWZ_R; 895cc1dc7a3Sopenharmony_ci cli_config.swz_encode.a = ASTCENC_SWZ_G; 896cc1dc7a3Sopenharmony_ci 897cc1dc7a3Sopenharmony_ci cli_config.swz_decode.r = ASTCENC_SWZ_R; 898cc1dc7a3Sopenharmony_ci cli_config.swz_decode.g = ASTCENC_SWZ_A; 899cc1dc7a3Sopenharmony_ci cli_config.swz_decode.b = ASTCENC_SWZ_Z; 900cc1dc7a3Sopenharmony_ci cli_config.swz_decode.a = ASTCENC_SWZ_1; 901cc1dc7a3Sopenharmony_ci } 902cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-rgbm")) 903cc1dc7a3Sopenharmony_ci { 904cc1dc7a3Sopenharmony_ci argidx += 2; 905cc1dc7a3Sopenharmony_ci if (argidx > argc) 906cc1dc7a3Sopenharmony_ci { 907cc1dc7a3Sopenharmony_ci print_error("ERROR: -rgbm switch with no argument\n"); 908cc1dc7a3Sopenharmony_ci return 1; 909cc1dc7a3Sopenharmony_ci } 910cc1dc7a3Sopenharmony_ci 911cc1dc7a3Sopenharmony_ci config.rgbm_m_scale = static_cast<float>(atof(argv[argidx - 1])); 912cc1dc7a3Sopenharmony_ci config.cw_a_weight = 2.0f * config.rgbm_m_scale; 913cc1dc7a3Sopenharmony_ci } 914cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-decode_unorm8")) 915cc1dc7a3Sopenharmony_ci { 916cc1dc7a3Sopenharmony_ci argidx++; 917cc1dc7a3Sopenharmony_ci } 918cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-perceptual")) 919cc1dc7a3Sopenharmony_ci { 920cc1dc7a3Sopenharmony_ci argidx++; 921cc1dc7a3Sopenharmony_ci } 922cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-pp-normalize")) 923cc1dc7a3Sopenharmony_ci { 924cc1dc7a3Sopenharmony_ci argidx++; 925cc1dc7a3Sopenharmony_ci } 926cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-pp-premultiply")) 927cc1dc7a3Sopenharmony_ci { 928cc1dc7a3Sopenharmony_ci argidx++; 929cc1dc7a3Sopenharmony_ci } 930cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-blockmodelimit")) 931cc1dc7a3Sopenharmony_ci { 932cc1dc7a3Sopenharmony_ci argidx += 2; 933cc1dc7a3Sopenharmony_ci if (argidx > argc) 934cc1dc7a3Sopenharmony_ci { 935cc1dc7a3Sopenharmony_ci print_error("ERROR: -blockmodelimit switch with no argument\n"); 936cc1dc7a3Sopenharmony_ci return 1; 937cc1dc7a3Sopenharmony_ci } 938cc1dc7a3Sopenharmony_ci 939cc1dc7a3Sopenharmony_ci config.tune_block_mode_limit = atoi(argv[argidx - 1]); 940cc1dc7a3Sopenharmony_ci } 941cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-partitioncountlimit")) 942cc1dc7a3Sopenharmony_ci { 943cc1dc7a3Sopenharmony_ci argidx += 2; 944cc1dc7a3Sopenharmony_ci if (argidx > argc) 945cc1dc7a3Sopenharmony_ci { 946cc1dc7a3Sopenharmony_ci print_error("ERROR: -partitioncountlimit switch with no argument\n"); 947cc1dc7a3Sopenharmony_ci return 1; 948cc1dc7a3Sopenharmony_ci } 949cc1dc7a3Sopenharmony_ci 950cc1dc7a3Sopenharmony_ci config.tune_partition_count_limit = atoi(argv[argidx - 1]); 951cc1dc7a3Sopenharmony_ci } 952cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-2partitionindexlimit")) 953cc1dc7a3Sopenharmony_ci { 954cc1dc7a3Sopenharmony_ci argidx += 2; 955cc1dc7a3Sopenharmony_ci if (argidx > argc) 956cc1dc7a3Sopenharmony_ci { 957cc1dc7a3Sopenharmony_ci print_error("ERROR: -2partitionindexlimit switch with no argument\n"); 958cc1dc7a3Sopenharmony_ci return 1; 959cc1dc7a3Sopenharmony_ci } 960cc1dc7a3Sopenharmony_ci 961cc1dc7a3Sopenharmony_ci config.tune_2partition_index_limit = atoi(argv[argidx - 1]); 962cc1dc7a3Sopenharmony_ci } 963cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-3partitionindexlimit")) 964cc1dc7a3Sopenharmony_ci { 965cc1dc7a3Sopenharmony_ci argidx += 2; 966cc1dc7a3Sopenharmony_ci if (argidx > argc) 967cc1dc7a3Sopenharmony_ci { 968cc1dc7a3Sopenharmony_ci print_error("ERROR: -3partitionindexlimit switch with no argument\n"); 969cc1dc7a3Sopenharmony_ci return 1; 970cc1dc7a3Sopenharmony_ci } 971cc1dc7a3Sopenharmony_ci 972cc1dc7a3Sopenharmony_ci config.tune_3partition_index_limit = atoi(argv[argidx - 1]); 973cc1dc7a3Sopenharmony_ci } 974cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-4partitionindexlimit")) 975cc1dc7a3Sopenharmony_ci { 976cc1dc7a3Sopenharmony_ci argidx += 2; 977cc1dc7a3Sopenharmony_ci if (argidx > argc) 978cc1dc7a3Sopenharmony_ci { 979cc1dc7a3Sopenharmony_ci print_error("ERROR: -4partitionindexlimit switch with no argument\n"); 980cc1dc7a3Sopenharmony_ci return 1; 981cc1dc7a3Sopenharmony_ci } 982cc1dc7a3Sopenharmony_ci 983cc1dc7a3Sopenharmony_ci config.tune_4partition_index_limit = atoi(argv[argidx - 1]); 984cc1dc7a3Sopenharmony_ci } 985cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-2partitioncandidatelimit")) 986cc1dc7a3Sopenharmony_ci { 987cc1dc7a3Sopenharmony_ci argidx += 2; 988cc1dc7a3Sopenharmony_ci if (argidx > argc) 989cc1dc7a3Sopenharmony_ci { 990cc1dc7a3Sopenharmony_ci print_error("ERROR: -2partitioncandidatelimit switch with no argument\n"); 991cc1dc7a3Sopenharmony_ci return 1; 992cc1dc7a3Sopenharmony_ci } 993cc1dc7a3Sopenharmony_ci 994cc1dc7a3Sopenharmony_ci config.tune_2partitioning_candidate_limit = atoi(argv[argidx - 1]); 995cc1dc7a3Sopenharmony_ci } 996cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-3partitioncandidatelimit")) 997cc1dc7a3Sopenharmony_ci { 998cc1dc7a3Sopenharmony_ci argidx += 2; 999cc1dc7a3Sopenharmony_ci if (argidx > argc) 1000cc1dc7a3Sopenharmony_ci { 1001cc1dc7a3Sopenharmony_ci print_error("ERROR: -3partitioncandidatelimit switch with no argument\n"); 1002cc1dc7a3Sopenharmony_ci return 1; 1003cc1dc7a3Sopenharmony_ci } 1004cc1dc7a3Sopenharmony_ci 1005cc1dc7a3Sopenharmony_ci config.tune_3partitioning_candidate_limit = atoi(argv[argidx - 1]); 1006cc1dc7a3Sopenharmony_ci } 1007cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-4partitioncandidatelimit")) 1008cc1dc7a3Sopenharmony_ci { 1009cc1dc7a3Sopenharmony_ci argidx += 2; 1010cc1dc7a3Sopenharmony_ci if (argidx > argc) 1011cc1dc7a3Sopenharmony_ci { 1012cc1dc7a3Sopenharmony_ci print_error("ERROR: -4partitioncandidatelimit switch with no argument\n"); 1013cc1dc7a3Sopenharmony_ci return 1; 1014cc1dc7a3Sopenharmony_ci } 1015cc1dc7a3Sopenharmony_ci 1016cc1dc7a3Sopenharmony_ci config.tune_4partitioning_candidate_limit = atoi(argv[argidx - 1]); 1017cc1dc7a3Sopenharmony_ci } 1018cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-dblimit")) 1019cc1dc7a3Sopenharmony_ci { 1020cc1dc7a3Sopenharmony_ci argidx += 2; 1021cc1dc7a3Sopenharmony_ci if (argidx > argc) 1022cc1dc7a3Sopenharmony_ci { 1023cc1dc7a3Sopenharmony_ci print_error("ERROR: -dblimit switch with no argument\n"); 1024cc1dc7a3Sopenharmony_ci return 1; 1025cc1dc7a3Sopenharmony_ci } 1026cc1dc7a3Sopenharmony_ci 1027cc1dc7a3Sopenharmony_ci if ((config.profile == ASTCENC_PRF_LDR) || (config.profile == ASTCENC_PRF_LDR_SRGB)) 1028cc1dc7a3Sopenharmony_ci { 1029cc1dc7a3Sopenharmony_ci config.tune_db_limit = static_cast<float>(atof(argv[argidx - 1])); 1030cc1dc7a3Sopenharmony_ci } 1031cc1dc7a3Sopenharmony_ci } 1032cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-2partitionlimitfactor")) 1033cc1dc7a3Sopenharmony_ci { 1034cc1dc7a3Sopenharmony_ci argidx += 2; 1035cc1dc7a3Sopenharmony_ci if (argidx > argc) 1036cc1dc7a3Sopenharmony_ci { 1037cc1dc7a3Sopenharmony_ci print_error("ERROR: -2partitionlimitfactor switch with no argument\n"); 1038cc1dc7a3Sopenharmony_ci return 1; 1039cc1dc7a3Sopenharmony_ci } 1040cc1dc7a3Sopenharmony_ci 1041cc1dc7a3Sopenharmony_ci config.tune_2partition_early_out_limit_factor = static_cast<float>(atof(argv[argidx - 1])); 1042cc1dc7a3Sopenharmony_ci } 1043cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-3partitionlimitfactor")) 1044cc1dc7a3Sopenharmony_ci { 1045cc1dc7a3Sopenharmony_ci argidx += 2; 1046cc1dc7a3Sopenharmony_ci if (argidx > argc) 1047cc1dc7a3Sopenharmony_ci { 1048cc1dc7a3Sopenharmony_ci print_error("ERROR: -3partitionlimitfactor switch with no argument\n"); 1049cc1dc7a3Sopenharmony_ci return 1; 1050cc1dc7a3Sopenharmony_ci } 1051cc1dc7a3Sopenharmony_ci 1052cc1dc7a3Sopenharmony_ci config.tune_3partition_early_out_limit_factor = static_cast<float>(atof(argv[argidx - 1])); 1053cc1dc7a3Sopenharmony_ci } 1054cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-2planelimitcorrelation")) 1055cc1dc7a3Sopenharmony_ci { 1056cc1dc7a3Sopenharmony_ci argidx += 2; 1057cc1dc7a3Sopenharmony_ci if (argidx > argc) 1058cc1dc7a3Sopenharmony_ci { 1059cc1dc7a3Sopenharmony_ci print_error("ERROR: -2planelimitcorrelation switch with no argument\n"); 1060cc1dc7a3Sopenharmony_ci return 1; 1061cc1dc7a3Sopenharmony_ci } 1062cc1dc7a3Sopenharmony_ci 1063cc1dc7a3Sopenharmony_ci config.tune_2plane_early_out_limit_correlation = static_cast<float>(atof(argv[argidx - 1])); 1064cc1dc7a3Sopenharmony_ci } 1065cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-refinementlimit")) 1066cc1dc7a3Sopenharmony_ci { 1067cc1dc7a3Sopenharmony_ci argidx += 2; 1068cc1dc7a3Sopenharmony_ci if (argidx > argc) 1069cc1dc7a3Sopenharmony_ci { 1070cc1dc7a3Sopenharmony_ci print_error("ERROR: -refinementlimit switch with no argument\n"); 1071cc1dc7a3Sopenharmony_ci return 1; 1072cc1dc7a3Sopenharmony_ci } 1073cc1dc7a3Sopenharmony_ci 1074cc1dc7a3Sopenharmony_ci config.tune_refinement_limit = atoi(argv[argidx - 1]); 1075cc1dc7a3Sopenharmony_ci } 1076cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-candidatelimit")) 1077cc1dc7a3Sopenharmony_ci { 1078cc1dc7a3Sopenharmony_ci argidx += 2; 1079cc1dc7a3Sopenharmony_ci if (argidx > argc) 1080cc1dc7a3Sopenharmony_ci { 1081cc1dc7a3Sopenharmony_ci print_error("ERROR: -candidatelimit switch with no argument\n"); 1082cc1dc7a3Sopenharmony_ci return 1; 1083cc1dc7a3Sopenharmony_ci } 1084cc1dc7a3Sopenharmony_ci 1085cc1dc7a3Sopenharmony_ci config.tune_candidate_limit = atoi(argv[argidx - 1]); 1086cc1dc7a3Sopenharmony_ci } 1087cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-j")) 1088cc1dc7a3Sopenharmony_ci { 1089cc1dc7a3Sopenharmony_ci argidx += 2; 1090cc1dc7a3Sopenharmony_ci if (argidx > argc) 1091cc1dc7a3Sopenharmony_ci { 1092cc1dc7a3Sopenharmony_ci print_error("ERROR: -j switch with no argument\n"); 1093cc1dc7a3Sopenharmony_ci return 1; 1094cc1dc7a3Sopenharmony_ci } 1095cc1dc7a3Sopenharmony_ci 1096cc1dc7a3Sopenharmony_ci cli_config.thread_count = atoi(argv[argidx - 1]); 1097cc1dc7a3Sopenharmony_ci } 1098cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-repeats")) 1099cc1dc7a3Sopenharmony_ci { 1100cc1dc7a3Sopenharmony_ci argidx += 2; 1101cc1dc7a3Sopenharmony_ci if (argidx > argc) 1102cc1dc7a3Sopenharmony_ci { 1103cc1dc7a3Sopenharmony_ci print_error("ERROR: -repeats switch with no argument\n"); 1104cc1dc7a3Sopenharmony_ci return 1; 1105cc1dc7a3Sopenharmony_ci } 1106cc1dc7a3Sopenharmony_ci 1107cc1dc7a3Sopenharmony_ci cli_config.repeat_count = atoi(argv[argidx - 1]); 1108cc1dc7a3Sopenharmony_ci if (cli_config.repeat_count <= 0) 1109cc1dc7a3Sopenharmony_ci { 1110cc1dc7a3Sopenharmony_ci print_error("ERROR: -repeats value must be at least one\n"); 1111cc1dc7a3Sopenharmony_ci return 1; 1112cc1dc7a3Sopenharmony_ci } 1113cc1dc7a3Sopenharmony_ci } 1114cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-yflip")) 1115cc1dc7a3Sopenharmony_ci { 1116cc1dc7a3Sopenharmony_ci argidx++; 1117cc1dc7a3Sopenharmony_ci cli_config.y_flip = 1; 1118cc1dc7a3Sopenharmony_ci } 1119cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-mpsnr")) 1120cc1dc7a3Sopenharmony_ci { 1121cc1dc7a3Sopenharmony_ci argidx += 3; 1122cc1dc7a3Sopenharmony_ci if (argidx > argc) 1123cc1dc7a3Sopenharmony_ci { 1124cc1dc7a3Sopenharmony_ci print_error("ERROR: -mpsnr switch with less than 2 arguments\n"); 1125cc1dc7a3Sopenharmony_ci return 1; 1126cc1dc7a3Sopenharmony_ci } 1127cc1dc7a3Sopenharmony_ci 1128cc1dc7a3Sopenharmony_ci cli_config.low_fstop = atoi(argv[argidx - 2]); 1129cc1dc7a3Sopenharmony_ci cli_config.high_fstop = atoi(argv[argidx - 1]); 1130cc1dc7a3Sopenharmony_ci if (cli_config.high_fstop < cli_config.low_fstop) 1131cc1dc7a3Sopenharmony_ci { 1132cc1dc7a3Sopenharmony_ci print_error("ERROR: -mpsnr switch <low> is greater than the <high>\n"); 1133cc1dc7a3Sopenharmony_ci return 1; 1134cc1dc7a3Sopenharmony_ci } 1135cc1dc7a3Sopenharmony_ci } 1136cc1dc7a3Sopenharmony_ci // Option: Encode a 3D image from a sequence of 2D images. 1137cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-zdim")) 1138cc1dc7a3Sopenharmony_ci { 1139cc1dc7a3Sopenharmony_ci // Only supports compressing 1140cc1dc7a3Sopenharmony_ci if (!(operation & ASTCENC_STAGE_COMPRESS)) 1141cc1dc7a3Sopenharmony_ci { 1142cc1dc7a3Sopenharmony_ci print_error("ERROR: -zdim switch is only valid for compression\n"); 1143cc1dc7a3Sopenharmony_ci return 1; 1144cc1dc7a3Sopenharmony_ci } 1145cc1dc7a3Sopenharmony_ci 1146cc1dc7a3Sopenharmony_ci // Image depth must be specified. 1147cc1dc7a3Sopenharmony_ci if (argidx + 2 > argc) 1148cc1dc7a3Sopenharmony_ci { 1149cc1dc7a3Sopenharmony_ci print_error("ERROR: -zdim switch with no argument\n"); 1150cc1dc7a3Sopenharmony_ci return 1; 1151cc1dc7a3Sopenharmony_ci } 1152cc1dc7a3Sopenharmony_ci argidx++; 1153cc1dc7a3Sopenharmony_ci 1154cc1dc7a3Sopenharmony_ci // Read array size (image depth). 1155cc1dc7a3Sopenharmony_ci if (!sscanf(argv[argidx], "%u", &cli_config.array_size) || cli_config.array_size == 0) 1156cc1dc7a3Sopenharmony_ci { 1157cc1dc7a3Sopenharmony_ci print_error("ERROR: -zdim size '%s' is invalid\n", argv[argidx]); 1158cc1dc7a3Sopenharmony_ci return 1; 1159cc1dc7a3Sopenharmony_ci } 1160cc1dc7a3Sopenharmony_ci 1161cc1dc7a3Sopenharmony_ci if ((cli_config.array_size > 1) && (config.block_z == 1)) 1162cc1dc7a3Sopenharmony_ci { 1163cc1dc7a3Sopenharmony_ci print_error("ERROR: -zdim with 3D input data for a 2D output format\n"); 1164cc1dc7a3Sopenharmony_ci return 1; 1165cc1dc7a3Sopenharmony_ci } 1166cc1dc7a3Sopenharmony_ci argidx++; 1167cc1dc7a3Sopenharmony_ci } 1168cc1dc7a3Sopenharmony_ci#if defined(ASTCENC_DIAGNOSTICS) 1169cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-dtrace")) 1170cc1dc7a3Sopenharmony_ci { 1171cc1dc7a3Sopenharmony_ci argidx += 2; 1172cc1dc7a3Sopenharmony_ci if (argidx > argc) 1173cc1dc7a3Sopenharmony_ci { 1174cc1dc7a3Sopenharmony_ci print_error("ERROR: -dtrace switch with no argument\n"); 1175cc1dc7a3Sopenharmony_ci return 1; 1176cc1dc7a3Sopenharmony_ci } 1177cc1dc7a3Sopenharmony_ci 1178cc1dc7a3Sopenharmony_ci config.trace_file_path = argv[argidx - 1]; 1179cc1dc7a3Sopenharmony_ci } 1180cc1dc7a3Sopenharmony_ci#endif 1181cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-privateProfile")) 1182cc1dc7a3Sopenharmony_ci { 1183cc1dc7a3Sopenharmony_ci argidx += 2; // skip 2 chatacters to get next parameter 1184cc1dc7a3Sopenharmony_ci config.privateProfile = static_cast<QualityProfile>(atoi(argv[argidx - 1])); 1185cc1dc7a3Sopenharmony_ci } 1186cc1dc7a3Sopenharmony_ci else if (!strcmp(argv[argidx], "-dimage")) 1187cc1dc7a3Sopenharmony_ci { 1188cc1dc7a3Sopenharmony_ci argidx += 1; 1189cc1dc7a3Sopenharmony_ci cli_config.diagnostic_images = true; 1190cc1dc7a3Sopenharmony_ci } 1191cc1dc7a3Sopenharmony_ci else // check others as well 1192cc1dc7a3Sopenharmony_ci { 1193cc1dc7a3Sopenharmony_ci print_error("ERROR: Argument '%s' not recognized\n", argv[argidx]); 1194cc1dc7a3Sopenharmony_ci return 1; 1195cc1dc7a3Sopenharmony_ci } 1196cc1dc7a3Sopenharmony_ci } 1197cc1dc7a3Sopenharmony_ci 1198cc1dc7a3Sopenharmony_ci if (cli_config.thread_count <= 0) 1199cc1dc7a3Sopenharmony_ci { 1200cc1dc7a3Sopenharmony_ci cli_config.thread_count = get_cpu_count(); 1201cc1dc7a3Sopenharmony_ci } 1202cc1dc7a3Sopenharmony_ci 1203cc1dc7a3Sopenharmony_ci#if defined(ASTCENC_DIAGNOSTICS) 1204cc1dc7a3Sopenharmony_ci // Force single threaded for diagnostic builds 1205cc1dc7a3Sopenharmony_ci cli_config.thread_count = 1; 1206cc1dc7a3Sopenharmony_ci 1207cc1dc7a3Sopenharmony_ci if (!config.trace_file_path) 1208cc1dc7a3Sopenharmony_ci { 1209cc1dc7a3Sopenharmony_ci print_error("ERROR: Diagnostics builds must set -dtrace\n"); 1210cc1dc7a3Sopenharmony_ci return 1; 1211cc1dc7a3Sopenharmony_ci } 1212cc1dc7a3Sopenharmony_ci#endif 1213cc1dc7a3Sopenharmony_ci 1214cc1dc7a3Sopenharmony_ci return 0; 1215cc1dc7a3Sopenharmony_ci} 1216cc1dc7a3Sopenharmony_ci 1217cc1dc7a3Sopenharmony_ci/** 1218cc1dc7a3Sopenharmony_ci * @brief Print the config settings in a human readable form. 1219cc1dc7a3Sopenharmony_ci * 1220cc1dc7a3Sopenharmony_ci * @param[in] cli_config Command line config. 1221cc1dc7a3Sopenharmony_ci * @param[in] config Codec configuration. 1222cc1dc7a3Sopenharmony_ci */ 1223cc1dc7a3Sopenharmony_cistatic void print_astcenc_config( 1224cc1dc7a3Sopenharmony_ci const cli_config_options& cli_config, 1225cc1dc7a3Sopenharmony_ci const astcenc_config& config 1226cc1dc7a3Sopenharmony_ci) { 1227cc1dc7a3Sopenharmony_ci // Print all encoding settings unless specifically told otherwise 1228cc1dc7a3Sopenharmony_ci if (!cli_config.silentmode) 1229cc1dc7a3Sopenharmony_ci { 1230cc1dc7a3Sopenharmony_ci printf("Compressor settings\n"); 1231cc1dc7a3Sopenharmony_ci printf("===================\n\n"); 1232cc1dc7a3Sopenharmony_ci 1233cc1dc7a3Sopenharmony_ci switch (config.profile) 1234cc1dc7a3Sopenharmony_ci { 1235cc1dc7a3Sopenharmony_ci case ASTCENC_PRF_LDR: 1236cc1dc7a3Sopenharmony_ci printf(" Color profile: LDR linear\n"); 1237cc1dc7a3Sopenharmony_ci break; 1238cc1dc7a3Sopenharmony_ci case ASTCENC_PRF_LDR_SRGB: 1239cc1dc7a3Sopenharmony_ci printf(" Color profile: LDR sRGB\n"); 1240cc1dc7a3Sopenharmony_ci break; 1241cc1dc7a3Sopenharmony_ci case ASTCENC_PRF_HDR_RGB_LDR_A: 1242cc1dc7a3Sopenharmony_ci printf(" Color profile: HDR RGB + LDR A\n"); 1243cc1dc7a3Sopenharmony_ci break; 1244cc1dc7a3Sopenharmony_ci case ASTCENC_PRF_HDR: 1245cc1dc7a3Sopenharmony_ci printf(" Color profile: HDR RGBA\n"); 1246cc1dc7a3Sopenharmony_ci break; 1247cc1dc7a3Sopenharmony_ci } 1248cc1dc7a3Sopenharmony_ci 1249cc1dc7a3Sopenharmony_ci if (config.block_z == 1) 1250cc1dc7a3Sopenharmony_ci { 1251cc1dc7a3Sopenharmony_ci printf(" Block size: %ux%u\n", config.block_x, config.block_y); 1252cc1dc7a3Sopenharmony_ci } 1253cc1dc7a3Sopenharmony_ci else 1254cc1dc7a3Sopenharmony_ci { 1255cc1dc7a3Sopenharmony_ci printf(" Block size: %ux%ux%u\n", config.block_x, config.block_y, config.block_z); 1256cc1dc7a3Sopenharmony_ci } 1257cc1dc7a3Sopenharmony_ci 1258cc1dc7a3Sopenharmony_ci printf(" Bitrate: %3.2f bpp\n", 128.0 / (config.block_x * config.block_y * config.block_z)); 1259cc1dc7a3Sopenharmony_ci printf(" RGB alpha scale weight: %d\n", (config.flags & ASTCENC_FLG_USE_ALPHA_WEIGHT)); 1260cc1dc7a3Sopenharmony_ci if ((config.flags & ASTCENC_FLG_USE_ALPHA_WEIGHT)) 1261cc1dc7a3Sopenharmony_ci { 1262cc1dc7a3Sopenharmony_ci printf(" Radius RGB alpha scale: %u texels\n", config.a_scale_radius); 1263cc1dc7a3Sopenharmony_ci } 1264cc1dc7a3Sopenharmony_ci 1265cc1dc7a3Sopenharmony_ci printf(" R component weight: %g\n", static_cast<double>(config.cw_r_weight)); 1266cc1dc7a3Sopenharmony_ci printf(" G component weight: %g\n", static_cast<double>(config.cw_g_weight)); 1267cc1dc7a3Sopenharmony_ci printf(" B component weight: %g\n", static_cast<double>(config.cw_b_weight)); 1268cc1dc7a3Sopenharmony_ci printf(" A component weight: %g\n", static_cast<double>(config.cw_a_weight)); 1269cc1dc7a3Sopenharmony_ci printf(" Partition cutoff: %u partitions\n", config.tune_partition_count_limit); 1270cc1dc7a3Sopenharmony_ci printf(" 2 partition index cutoff: %u partition ids\n", config.tune_2partition_index_limit); 1271cc1dc7a3Sopenharmony_ci printf(" 3 partition index cutoff: %u partition ids\n", config.tune_3partition_index_limit); 1272cc1dc7a3Sopenharmony_ci printf(" 4 partition index cutoff: %u partition ids\n", config.tune_4partition_index_limit); 1273cc1dc7a3Sopenharmony_ci printf(" PSNR cutoff: %g dB\n", static_cast<double>(config.tune_db_limit)); 1274cc1dc7a3Sopenharmony_ci printf(" 3 partition cutoff: %g\n", static_cast<double>(config.tune_2partition_early_out_limit_factor)); 1275cc1dc7a3Sopenharmony_ci printf(" 4 partition cutoff: %g\n", static_cast<double>(config.tune_3partition_early_out_limit_factor)); 1276cc1dc7a3Sopenharmony_ci printf(" 2 plane correlation cutoff: %g\n", static_cast<double>(config.tune_2plane_early_out_limit_correlation)); 1277cc1dc7a3Sopenharmony_ci printf(" Block mode centile cutoff: %g%%\n", static_cast<double>(config.tune_block_mode_limit)); 1278cc1dc7a3Sopenharmony_ci printf(" Candidate cutoff: %u candidates\n", config.tune_candidate_limit); 1279cc1dc7a3Sopenharmony_ci printf(" Refinement cutoff: %u iterations\n", config.tune_refinement_limit); 1280cc1dc7a3Sopenharmony_ci printf(" Compressor thread count: %d\n", cli_config.thread_count); 1281cc1dc7a3Sopenharmony_ci printf("\n"); 1282cc1dc7a3Sopenharmony_ci } 1283cc1dc7a3Sopenharmony_ci} 1284cc1dc7a3Sopenharmony_ci 1285cc1dc7a3Sopenharmony_ci/** 1286cc1dc7a3Sopenharmony_ci * @brief Get the value of a single pixel in an image. 1287cc1dc7a3Sopenharmony_ci * 1288cc1dc7a3Sopenharmony_ci * Note, this implementation is not particularly optimal as it puts format 1289cc1dc7a3Sopenharmony_ci * checks in the inner-most loop. For the CLI preprocess passes this is deemed 1290cc1dc7a3Sopenharmony_ci * acceptable as these are not performance critical paths. 1291cc1dc7a3Sopenharmony_ci * 1292cc1dc7a3Sopenharmony_ci * @param[in] img The output image. 1293cc1dc7a3Sopenharmony_ci * @param x The pixel x coordinate. 1294cc1dc7a3Sopenharmony_ci * @param y The pixel y coordinate. 1295cc1dc7a3Sopenharmony_ci * @param z The pixel z coordinate. 1296cc1dc7a3Sopenharmony_ci * 1297cc1dc7a3Sopenharmony_ci * @return pixel The pixel color value to write. 1298cc1dc7a3Sopenharmony_ci */ 1299cc1dc7a3Sopenharmony_cistatic vfloat4 image_get_pixel( 1300cc1dc7a3Sopenharmony_ci const astcenc_image& img, 1301cc1dc7a3Sopenharmony_ci unsigned int x, 1302cc1dc7a3Sopenharmony_ci unsigned int y, 1303cc1dc7a3Sopenharmony_ci unsigned int z 1304cc1dc7a3Sopenharmony_ci) { 1305cc1dc7a3Sopenharmony_ci // We should never escape bounds 1306cc1dc7a3Sopenharmony_ci assert(x < img.dim_x); 1307cc1dc7a3Sopenharmony_ci assert(y < img.dim_y); 1308cc1dc7a3Sopenharmony_ci assert(z < img.dim_z); 1309cc1dc7a3Sopenharmony_ci 1310cc1dc7a3Sopenharmony_ci if (img.data_type == ASTCENC_TYPE_U8) 1311cc1dc7a3Sopenharmony_ci { 1312cc1dc7a3Sopenharmony_ci uint8_t* data = static_cast<uint8_t*>(img.data[z]); 1313cc1dc7a3Sopenharmony_ci 1314cc1dc7a3Sopenharmony_ci float r = data[(4 * img.dim_x * y) + (4 * x )] / 255.0f; 1315cc1dc7a3Sopenharmony_ci float g = data[(4 * img.dim_x * y) + (4 * x + 1)] / 255.0f; 1316cc1dc7a3Sopenharmony_ci float b = data[(4 * img.dim_x * y) + (4 * x + 2)] / 255.0f; 1317cc1dc7a3Sopenharmony_ci float a = data[(4 * img.dim_x * y) + (4 * x + 3)] / 255.0f; 1318cc1dc7a3Sopenharmony_ci 1319cc1dc7a3Sopenharmony_ci return vfloat4(r, g, b, a); 1320cc1dc7a3Sopenharmony_ci } 1321cc1dc7a3Sopenharmony_ci else if (img.data_type == ASTCENC_TYPE_F16) 1322cc1dc7a3Sopenharmony_ci { 1323cc1dc7a3Sopenharmony_ci uint16_t* data = static_cast<uint16_t*>(img.data[z]); 1324cc1dc7a3Sopenharmony_ci 1325cc1dc7a3Sopenharmony_ci vint4 colori( 1326cc1dc7a3Sopenharmony_ci data[(4 * img.dim_x * y) + (4 * x )], 1327cc1dc7a3Sopenharmony_ci data[(4 * img.dim_x * y) + (4 * x + 1)], 1328cc1dc7a3Sopenharmony_ci data[(4 * img.dim_x * y) + (4 * x + 2)], 1329cc1dc7a3Sopenharmony_ci data[(4 * img.dim_x * y) + (4 * x + 3)] 1330cc1dc7a3Sopenharmony_ci ); 1331cc1dc7a3Sopenharmony_ci 1332cc1dc7a3Sopenharmony_ci return float16_to_float(colori); 1333cc1dc7a3Sopenharmony_ci } 1334cc1dc7a3Sopenharmony_ci else // if (img.data_type == ASTCENC_TYPE_F32) 1335cc1dc7a3Sopenharmony_ci { 1336cc1dc7a3Sopenharmony_ci assert(img.data_type == ASTCENC_TYPE_F32); 1337cc1dc7a3Sopenharmony_ci float* data = static_cast<float*>(img.data[z]); 1338cc1dc7a3Sopenharmony_ci 1339cc1dc7a3Sopenharmony_ci return vfloat4( 1340cc1dc7a3Sopenharmony_ci data[(4 * img.dim_x * y) + (4 * x )], 1341cc1dc7a3Sopenharmony_ci data[(4 * img.dim_x * y) + (4 * x + 1)], 1342cc1dc7a3Sopenharmony_ci data[(4 * img.dim_x * y) + (4 * x + 2)], 1343cc1dc7a3Sopenharmony_ci data[(4 * img.dim_x * y) + (4 * x + 3)] 1344cc1dc7a3Sopenharmony_ci ); 1345cc1dc7a3Sopenharmony_ci } 1346cc1dc7a3Sopenharmony_ci} 1347cc1dc7a3Sopenharmony_ci 1348cc1dc7a3Sopenharmony_ci/** 1349cc1dc7a3Sopenharmony_ci * @brief Set the value of a single pixel in an image. 1350cc1dc7a3Sopenharmony_ci * 1351cc1dc7a3Sopenharmony_ci * @param[out] img The output image; must use F32 texture components. 1352cc1dc7a3Sopenharmony_ci * @param x The pixel x coordinate. 1353cc1dc7a3Sopenharmony_ci * @param y The pixel y coordinate. 1354cc1dc7a3Sopenharmony_ci * @param z The pixel z coordinate. 1355cc1dc7a3Sopenharmony_ci * @param pixel The pixel color value to write. 1356cc1dc7a3Sopenharmony_ci */ 1357cc1dc7a3Sopenharmony_cistatic void image_set_pixel( 1358cc1dc7a3Sopenharmony_ci astcenc_image& img, 1359cc1dc7a3Sopenharmony_ci unsigned int x, 1360cc1dc7a3Sopenharmony_ci unsigned int y, 1361cc1dc7a3Sopenharmony_ci unsigned int z, 1362cc1dc7a3Sopenharmony_ci vfloat4 pixel 1363cc1dc7a3Sopenharmony_ci) { 1364cc1dc7a3Sopenharmony_ci // We should never escape bounds 1365cc1dc7a3Sopenharmony_ci assert(x < img.dim_x); 1366cc1dc7a3Sopenharmony_ci assert(y < img.dim_y); 1367cc1dc7a3Sopenharmony_ci assert(z < img.dim_z); 1368cc1dc7a3Sopenharmony_ci assert(img.data_type == ASTCENC_TYPE_F32); 1369cc1dc7a3Sopenharmony_ci 1370cc1dc7a3Sopenharmony_ci float* data = static_cast<float*>(img.data[z]); 1371cc1dc7a3Sopenharmony_ci 1372cc1dc7a3Sopenharmony_ci data[(4 * img.dim_x * y) + (4 * x )] = pixel.lane<0>(); 1373cc1dc7a3Sopenharmony_ci data[(4 * img.dim_x * y) + (4 * x + 1)] = pixel.lane<1>(); 1374cc1dc7a3Sopenharmony_ci data[(4 * img.dim_x * y) + (4 * x + 2)] = pixel.lane<2>(); 1375cc1dc7a3Sopenharmony_ci data[(4 * img.dim_x * y) + (4 * x + 3)] = pixel.lane<3>(); 1376cc1dc7a3Sopenharmony_ci} 1377cc1dc7a3Sopenharmony_ci 1378cc1dc7a3Sopenharmony_ci/** 1379cc1dc7a3Sopenharmony_ci * @brief Set the value of a single pixel in an image. 1380cc1dc7a3Sopenharmony_ci * 1381cc1dc7a3Sopenharmony_ci * @param[out] img The output image; must use F32 texture components. 1382cc1dc7a3Sopenharmony_ci * @param x The pixel x coordinate. 1383cc1dc7a3Sopenharmony_ci * @param y The pixel y coordinate. 1384cc1dc7a3Sopenharmony_ci * @param pixel The pixel color value to write. 1385cc1dc7a3Sopenharmony_ci */ 1386cc1dc7a3Sopenharmony_cistatic void image_set_pixel_u8( 1387cc1dc7a3Sopenharmony_ci astcenc_image& img, 1388cc1dc7a3Sopenharmony_ci size_t x, 1389cc1dc7a3Sopenharmony_ci size_t y, 1390cc1dc7a3Sopenharmony_ci vint4 pixel 1391cc1dc7a3Sopenharmony_ci) { 1392cc1dc7a3Sopenharmony_ci // We should never escape bounds 1393cc1dc7a3Sopenharmony_ci assert(x < img.dim_x); 1394cc1dc7a3Sopenharmony_ci assert(y < img.dim_y); 1395cc1dc7a3Sopenharmony_ci assert(img.data_type == ASTCENC_TYPE_U8); 1396cc1dc7a3Sopenharmony_ci 1397cc1dc7a3Sopenharmony_ci uint8_t* data = static_cast<uint8_t*>(img.data[0]); 1398cc1dc7a3Sopenharmony_ci pixel = pack_low_bytes(pixel); 1399cc1dc7a3Sopenharmony_ci store_nbytes(pixel, data + (4 * img.dim_x * y) + (4 * x )); 1400cc1dc7a3Sopenharmony_ci} 1401cc1dc7a3Sopenharmony_ci 1402cc1dc7a3Sopenharmony_ci/** 1403cc1dc7a3Sopenharmony_ci * @brief Create a copy of @c input with forced unit-length normal vectors. 1404cc1dc7a3Sopenharmony_ci * 1405cc1dc7a3Sopenharmony_ci * It is assumed that all normal vectors are stored in the RGB components, and 1406cc1dc7a3Sopenharmony_ci * stored in a packed unsigned range of [0,1] which must be unpacked prior 1407cc1dc7a3Sopenharmony_ci * normalization. Data must then be repacked into this form for handing over to 1408cc1dc7a3Sopenharmony_ci * the core codec. 1409cc1dc7a3Sopenharmony_ci * 1410cc1dc7a3Sopenharmony_ci * @param[in] input The input image. 1411cc1dc7a3Sopenharmony_ci * @param[out] output The output image, must use F32 components. 1412cc1dc7a3Sopenharmony_ci */ 1413cc1dc7a3Sopenharmony_cistatic void image_preprocess_normalize( 1414cc1dc7a3Sopenharmony_ci const astcenc_image& input, 1415cc1dc7a3Sopenharmony_ci astcenc_image& output 1416cc1dc7a3Sopenharmony_ci) { 1417cc1dc7a3Sopenharmony_ci for (unsigned int z = 0; z < input.dim_z; z++) 1418cc1dc7a3Sopenharmony_ci { 1419cc1dc7a3Sopenharmony_ci for (unsigned int y = 0; y < input.dim_y; y++) 1420cc1dc7a3Sopenharmony_ci { 1421cc1dc7a3Sopenharmony_ci for (unsigned int x = 0; x < input.dim_x; x++) 1422cc1dc7a3Sopenharmony_ci { 1423cc1dc7a3Sopenharmony_ci vfloat4 pixel = image_get_pixel(input, x, y, z); 1424cc1dc7a3Sopenharmony_ci 1425cc1dc7a3Sopenharmony_ci // Stash alpha component and zero 1426cc1dc7a3Sopenharmony_ci float a = pixel.lane<3>(); 1427cc1dc7a3Sopenharmony_ci pixel.set_lane<3>(0.0f); 1428cc1dc7a3Sopenharmony_ci 1429cc1dc7a3Sopenharmony_ci // Decode [0,1] normals to [-1,1] 1430cc1dc7a3Sopenharmony_ci pixel.set_lane<0>((pixel.lane<0>() * 2.0f) - 1.0f); 1431cc1dc7a3Sopenharmony_ci pixel.set_lane<1>((pixel.lane<1>() * 2.0f) - 1.0f); 1432cc1dc7a3Sopenharmony_ci pixel.set_lane<2>((pixel.lane<2>() * 2.0f) - 1.0f); 1433cc1dc7a3Sopenharmony_ci 1434cc1dc7a3Sopenharmony_ci // Normalize pixel and restore alpha 1435cc1dc7a3Sopenharmony_ci pixel = normalize(pixel); 1436cc1dc7a3Sopenharmony_ci pixel.set_lane<3>(a); 1437cc1dc7a3Sopenharmony_ci 1438cc1dc7a3Sopenharmony_ci // Encode [-1,1] normals to [0,1] 1439cc1dc7a3Sopenharmony_ci pixel.set_lane<0>((pixel.lane<0>() + 1.0f) / 2.0f); 1440cc1dc7a3Sopenharmony_ci pixel.set_lane<1>((pixel.lane<1>() + 1.0f) / 2.0f); 1441cc1dc7a3Sopenharmony_ci pixel.set_lane<2>((pixel.lane<2>() + 1.0f) / 2.0f); 1442cc1dc7a3Sopenharmony_ci 1443cc1dc7a3Sopenharmony_ci image_set_pixel(output, x, y, z, pixel); 1444cc1dc7a3Sopenharmony_ci } 1445cc1dc7a3Sopenharmony_ci } 1446cc1dc7a3Sopenharmony_ci } 1447cc1dc7a3Sopenharmony_ci} 1448cc1dc7a3Sopenharmony_ci 1449cc1dc7a3Sopenharmony_ci/** 1450cc1dc7a3Sopenharmony_ci * @brief Linearize an sRGB value. 1451cc1dc7a3Sopenharmony_ci * 1452cc1dc7a3Sopenharmony_ci * @return The linearized value. 1453cc1dc7a3Sopenharmony_ci */ 1454cc1dc7a3Sopenharmony_cistatic float srgb_to_linear( 1455cc1dc7a3Sopenharmony_ci float a 1456cc1dc7a3Sopenharmony_ci) { 1457cc1dc7a3Sopenharmony_ci if (a <= 0.04045f) 1458cc1dc7a3Sopenharmony_ci { 1459cc1dc7a3Sopenharmony_ci return a * (1.0f / 12.92f); 1460cc1dc7a3Sopenharmony_ci } 1461cc1dc7a3Sopenharmony_ci 1462cc1dc7a3Sopenharmony_ci return powf((a + 0.055f) * (1.0f / 1.055f), 2.4f); 1463cc1dc7a3Sopenharmony_ci} 1464cc1dc7a3Sopenharmony_ci 1465cc1dc7a3Sopenharmony_ci/** 1466cc1dc7a3Sopenharmony_ci * @brief sRGB gamma-encode a linear value. 1467cc1dc7a3Sopenharmony_ci * 1468cc1dc7a3Sopenharmony_ci * @return The gamma encoded value. 1469cc1dc7a3Sopenharmony_ci */ 1470cc1dc7a3Sopenharmony_cistatic float linear_to_srgb( 1471cc1dc7a3Sopenharmony_ci float a 1472cc1dc7a3Sopenharmony_ci) { 1473cc1dc7a3Sopenharmony_ci if (a <= 0.0031308f) 1474cc1dc7a3Sopenharmony_ci { 1475cc1dc7a3Sopenharmony_ci return a * 12.92f; 1476cc1dc7a3Sopenharmony_ci } 1477cc1dc7a3Sopenharmony_ci 1478cc1dc7a3Sopenharmony_ci return 1.055f * powf(a, 1.0f / 2.4f) - 0.055f; 1479cc1dc7a3Sopenharmony_ci} 1480cc1dc7a3Sopenharmony_ci 1481cc1dc7a3Sopenharmony_ci/** 1482cc1dc7a3Sopenharmony_ci * @brief Create a copy of @c input with premultiplied color data. 1483cc1dc7a3Sopenharmony_ci * 1484cc1dc7a3Sopenharmony_ci * If we are compressing sRGB data we linearize the data prior to 1485cc1dc7a3Sopenharmony_ci * premultiplication and re-gamma-encode afterwards. 1486cc1dc7a3Sopenharmony_ci * 1487cc1dc7a3Sopenharmony_ci * @param[in] input The input image. 1488cc1dc7a3Sopenharmony_ci * @param[out] output The output image, must use F32 components. 1489cc1dc7a3Sopenharmony_ci * @param profile The encoding profile. 1490cc1dc7a3Sopenharmony_ci */ 1491cc1dc7a3Sopenharmony_cistatic void image_preprocess_premultiply( 1492cc1dc7a3Sopenharmony_ci const astcenc_image& input, 1493cc1dc7a3Sopenharmony_ci astcenc_image& output, 1494cc1dc7a3Sopenharmony_ci astcenc_profile profile 1495cc1dc7a3Sopenharmony_ci) { 1496cc1dc7a3Sopenharmony_ci for (unsigned int z = 0; z < input.dim_z; z++) 1497cc1dc7a3Sopenharmony_ci { 1498cc1dc7a3Sopenharmony_ci for (unsigned int y = 0; y < input.dim_y; y++) 1499cc1dc7a3Sopenharmony_ci { 1500cc1dc7a3Sopenharmony_ci for (unsigned int x = 0; x < input.dim_x; x++) 1501cc1dc7a3Sopenharmony_ci { 1502cc1dc7a3Sopenharmony_ci vfloat4 pixel = image_get_pixel(input, x, y, z); 1503cc1dc7a3Sopenharmony_ci 1504cc1dc7a3Sopenharmony_ci // Linearize sRGB 1505cc1dc7a3Sopenharmony_ci if (profile == ASTCENC_PRF_LDR_SRGB) 1506cc1dc7a3Sopenharmony_ci { 1507cc1dc7a3Sopenharmony_ci pixel.set_lane<0>(srgb_to_linear(pixel.lane<0>())); 1508cc1dc7a3Sopenharmony_ci pixel.set_lane<1>(srgb_to_linear(pixel.lane<1>())); 1509cc1dc7a3Sopenharmony_ci pixel.set_lane<2>(srgb_to_linear(pixel.lane<2>())); 1510cc1dc7a3Sopenharmony_ci } 1511cc1dc7a3Sopenharmony_ci 1512cc1dc7a3Sopenharmony_ci // Premultiply pixel in linear-space 1513cc1dc7a3Sopenharmony_ci pixel.set_lane<0>(pixel.lane<0>() * pixel.lane<3>()); 1514cc1dc7a3Sopenharmony_ci pixel.set_lane<1>(pixel.lane<1>() * pixel.lane<3>()); 1515cc1dc7a3Sopenharmony_ci pixel.set_lane<2>(pixel.lane<2>() * pixel.lane<3>()); 1516cc1dc7a3Sopenharmony_ci 1517cc1dc7a3Sopenharmony_ci // Gamma-encode sRGB 1518cc1dc7a3Sopenharmony_ci if (profile == ASTCENC_PRF_LDR_SRGB) 1519cc1dc7a3Sopenharmony_ci { 1520cc1dc7a3Sopenharmony_ci pixel.set_lane<0>(linear_to_srgb(pixel.lane<0>())); 1521cc1dc7a3Sopenharmony_ci pixel.set_lane<1>(linear_to_srgb(pixel.lane<1>())); 1522cc1dc7a3Sopenharmony_ci pixel.set_lane<2>(linear_to_srgb(pixel.lane<2>())); 1523cc1dc7a3Sopenharmony_ci } 1524cc1dc7a3Sopenharmony_ci 1525cc1dc7a3Sopenharmony_ci image_set_pixel(output, x, y, z, pixel); 1526cc1dc7a3Sopenharmony_ci } 1527cc1dc7a3Sopenharmony_ci } 1528cc1dc7a3Sopenharmony_ci } 1529cc1dc7a3Sopenharmony_ci} 1530cc1dc7a3Sopenharmony_ci 1531cc1dc7a3Sopenharmony_ci/** 1532cc1dc7a3Sopenharmony_ci * @brief Populate a single diagnostic image showing aspects of the encoding. 1533cc1dc7a3Sopenharmony_ci * 1534cc1dc7a3Sopenharmony_ci * @param context The context to use. 1535cc1dc7a3Sopenharmony_ci * @param image The compressed image to analyze. 1536cc1dc7a3Sopenharmony_ci * @param diag_image The output visualization image to populate. 1537cc1dc7a3Sopenharmony_ci * @param texel_func The per-texel callback used to determine output color. 1538cc1dc7a3Sopenharmony_ci */ 1539cc1dc7a3Sopenharmony_cistatic void print_diagnostic_image( 1540cc1dc7a3Sopenharmony_ci astcenc_context* context, 1541cc1dc7a3Sopenharmony_ci const astc_compressed_image& image, 1542cc1dc7a3Sopenharmony_ci astcenc_image& diag_image, 1543cc1dc7a3Sopenharmony_ci std::function<vint4(astcenc_block_info&, size_t, size_t)> texel_func 1544cc1dc7a3Sopenharmony_ci) { 1545cc1dc7a3Sopenharmony_ci size_t block_cols = (image.dim_x + image.block_x - 1) / image.block_x; 1546cc1dc7a3Sopenharmony_ci size_t block_rows = (image.dim_y + image.block_y - 1) / image.block_y; 1547cc1dc7a3Sopenharmony_ci 1548cc1dc7a3Sopenharmony_ci uint8_t* data = image.data; 1549cc1dc7a3Sopenharmony_ci for (size_t block_y = 0; block_y < block_rows; block_y++) 1550cc1dc7a3Sopenharmony_ci { 1551cc1dc7a3Sopenharmony_ci for (size_t block_x = 0; block_x < block_cols; block_x++) 1552cc1dc7a3Sopenharmony_ci { 1553cc1dc7a3Sopenharmony_ci astcenc_block_info block_info; 1554cc1dc7a3Sopenharmony_ci astcenc_get_block_info(context, data, &block_info); 1555cc1dc7a3Sopenharmony_ci data += 16; 1556cc1dc7a3Sopenharmony_ci 1557cc1dc7a3Sopenharmony_ci size_t start_row = block_y * image.block_y; 1558cc1dc7a3Sopenharmony_ci size_t start_col = block_x * image.block_x; 1559cc1dc7a3Sopenharmony_ci 1560cc1dc7a3Sopenharmony_ci size_t end_row = astc::min(start_row + image.block_y, static_cast<size_t>(image.dim_y)); 1561cc1dc7a3Sopenharmony_ci size_t end_col = astc::min(start_col + image.block_x, static_cast<size_t>(image.dim_x)); 1562cc1dc7a3Sopenharmony_ci 1563cc1dc7a3Sopenharmony_ci for (size_t texel_y = start_row; texel_y < end_row; texel_y++) 1564cc1dc7a3Sopenharmony_ci { 1565cc1dc7a3Sopenharmony_ci for (size_t texel_x = start_col; texel_x < end_col; texel_x++) 1566cc1dc7a3Sopenharmony_ci { 1567cc1dc7a3Sopenharmony_ci vint4 color = texel_func(block_info, texel_x - start_col, texel_y - start_row); 1568cc1dc7a3Sopenharmony_ci image_set_pixel_u8(diag_image, texel_x, texel_y, color); 1569cc1dc7a3Sopenharmony_ci } 1570cc1dc7a3Sopenharmony_ci } 1571cc1dc7a3Sopenharmony_ci } 1572cc1dc7a3Sopenharmony_ci } 1573cc1dc7a3Sopenharmony_ci} 1574cc1dc7a3Sopenharmony_ci 1575cc1dc7a3Sopenharmony_ci/** 1576cc1dc7a3Sopenharmony_ci * @brief Print a set of diagnostic images showing aspects of the encoding. 1577cc1dc7a3Sopenharmony_ci * 1578cc1dc7a3Sopenharmony_ci * @param context The context to use. 1579cc1dc7a3Sopenharmony_ci * @param image The compressed image to analyze. 1580cc1dc7a3Sopenharmony_ci * @param output_file The output file name to use as a stem for new names. 1581cc1dc7a3Sopenharmony_ci */ 1582cc1dc7a3Sopenharmony_cistatic void print_diagnostic_images( 1583cc1dc7a3Sopenharmony_ci astcenc_context* context, 1584cc1dc7a3Sopenharmony_ci const astc_compressed_image& image, 1585cc1dc7a3Sopenharmony_ci const std::string& output_file 1586cc1dc7a3Sopenharmony_ci) { 1587cc1dc7a3Sopenharmony_ci if (image.dim_z != 1) 1588cc1dc7a3Sopenharmony_ci { 1589cc1dc7a3Sopenharmony_ci return; 1590cc1dc7a3Sopenharmony_ci } 1591cc1dc7a3Sopenharmony_ci 1592cc1dc7a3Sopenharmony_ci // Try to find a file extension we know about 1593cc1dc7a3Sopenharmony_ci size_t index = output_file.find_last_of("."); 1594cc1dc7a3Sopenharmony_ci std::string stem = output_file; 1595cc1dc7a3Sopenharmony_ci if (index != std::string::npos) 1596cc1dc7a3Sopenharmony_ci { 1597cc1dc7a3Sopenharmony_ci stem = stem.substr(0, index); 1598cc1dc7a3Sopenharmony_ci } 1599cc1dc7a3Sopenharmony_ci 1600cc1dc7a3Sopenharmony_ci auto diag_image = alloc_image(8, image.dim_x, image.dim_y, image.dim_z); 1601cc1dc7a3Sopenharmony_ci 1602cc1dc7a3Sopenharmony_ci // ---- ---- ---- ---- Partitioning ---- ---- ---- ---- 1603cc1dc7a3Sopenharmony_ci auto partition_func = [](astcenc_block_info& info, size_t texel_x, size_t texel_y) { 1604cc1dc7a3Sopenharmony_ci const vint4 colors[] { 1605cc1dc7a3Sopenharmony_ci vint4( 0, 0, 0, 255), 1606cc1dc7a3Sopenharmony_ci vint4(255, 0, 0, 255), 1607cc1dc7a3Sopenharmony_ci vint4( 0, 255, 0, 255), 1608cc1dc7a3Sopenharmony_ci vint4( 0, 0, 255, 255), 1609cc1dc7a3Sopenharmony_ci vint4(255, 255, 255, 255) 1610cc1dc7a3Sopenharmony_ci }; 1611cc1dc7a3Sopenharmony_ci 1612cc1dc7a3Sopenharmony_ci size_t texel_index = texel_y * info.block_x + texel_x; 1613cc1dc7a3Sopenharmony_ci 1614cc1dc7a3Sopenharmony_ci int partition { 0 }; 1615cc1dc7a3Sopenharmony_ci if (!info.is_constant_block) 1616cc1dc7a3Sopenharmony_ci { 1617cc1dc7a3Sopenharmony_ci partition = info.partition_assignment[texel_index] + 1; 1618cc1dc7a3Sopenharmony_ci } 1619cc1dc7a3Sopenharmony_ci 1620cc1dc7a3Sopenharmony_ci return colors[partition]; 1621cc1dc7a3Sopenharmony_ci }; 1622cc1dc7a3Sopenharmony_ci 1623cc1dc7a3Sopenharmony_ci print_diagnostic_image(context, image, *diag_image, partition_func); 1624cc1dc7a3Sopenharmony_ci std::string fname = stem + "_diag_partitioning.png"; 1625cc1dc7a3Sopenharmony_ci store_ncimage(diag_image, fname.c_str(), false); 1626cc1dc7a3Sopenharmony_ci 1627cc1dc7a3Sopenharmony_ci // ---- ---- ---- ---- Weight planes ---- ---- ---- ---- 1628cc1dc7a3Sopenharmony_ci auto texel_func1 = [](astcenc_block_info& info, size_t texel_x, size_t texel_y) { 1629cc1dc7a3Sopenharmony_ci (void)texel_x; 1630cc1dc7a3Sopenharmony_ci (void)texel_y; 1631cc1dc7a3Sopenharmony_ci 1632cc1dc7a3Sopenharmony_ci const vint4 colors[] { 1633cc1dc7a3Sopenharmony_ci vint4( 0, 0, 0, 255), 1634cc1dc7a3Sopenharmony_ci vint4(255, 0, 0, 255), 1635cc1dc7a3Sopenharmony_ci vint4( 0, 255, 0, 255), 1636cc1dc7a3Sopenharmony_ci vint4( 0, 0, 255, 255), 1637cc1dc7a3Sopenharmony_ci vint4(255, 255, 255, 255) 1638cc1dc7a3Sopenharmony_ci }; 1639cc1dc7a3Sopenharmony_ci 1640cc1dc7a3Sopenharmony_ci int component { 0 }; 1641cc1dc7a3Sopenharmony_ci if (info.is_dual_plane_block) 1642cc1dc7a3Sopenharmony_ci { 1643cc1dc7a3Sopenharmony_ci component = info.dual_plane_component + 1; 1644cc1dc7a3Sopenharmony_ci } 1645cc1dc7a3Sopenharmony_ci 1646cc1dc7a3Sopenharmony_ci return colors[component]; 1647cc1dc7a3Sopenharmony_ci }; 1648cc1dc7a3Sopenharmony_ci 1649cc1dc7a3Sopenharmony_ci print_diagnostic_image(context, image, *diag_image, texel_func1); 1650cc1dc7a3Sopenharmony_ci fname = stem + "_diag_weight_plane2.png"; 1651cc1dc7a3Sopenharmony_ci store_ncimage(diag_image, fname.c_str(), false); 1652cc1dc7a3Sopenharmony_ci 1653cc1dc7a3Sopenharmony_ci // ---- ---- ---- ---- Weight density ---- ---- ---- ---- 1654cc1dc7a3Sopenharmony_ci auto texel_func2 = [](astcenc_block_info& info, size_t texel_x, size_t texel_y) { 1655cc1dc7a3Sopenharmony_ci (void)texel_x; 1656cc1dc7a3Sopenharmony_ci (void)texel_y; 1657cc1dc7a3Sopenharmony_ci 1658cc1dc7a3Sopenharmony_ci float density = 0.0f; 1659cc1dc7a3Sopenharmony_ci if (!info.is_constant_block) 1660cc1dc7a3Sopenharmony_ci { 1661cc1dc7a3Sopenharmony_ci float texel_count = static_cast<float>(info.block_x * info.block_y); 1662cc1dc7a3Sopenharmony_ci float weight_count = static_cast<float>(info.weight_x * info.weight_y); 1663cc1dc7a3Sopenharmony_ci density = weight_count / texel_count; 1664cc1dc7a3Sopenharmony_ci } 1665cc1dc7a3Sopenharmony_ci 1666cc1dc7a3Sopenharmony_ci int densityi = static_cast<int>(255.0f * density); 1667cc1dc7a3Sopenharmony_ci return vint4(densityi, densityi, densityi, 255); 1668cc1dc7a3Sopenharmony_ci }; 1669cc1dc7a3Sopenharmony_ci 1670cc1dc7a3Sopenharmony_ci print_diagnostic_image(context, image, *diag_image, texel_func2); 1671cc1dc7a3Sopenharmony_ci fname = stem + "_diag_weight_density.png"; 1672cc1dc7a3Sopenharmony_ci store_ncimage(diag_image, fname.c_str(), false); 1673cc1dc7a3Sopenharmony_ci 1674cc1dc7a3Sopenharmony_ci // ---- ---- ---- ---- Weight quant ---- ---- ---- ---- 1675cc1dc7a3Sopenharmony_ci auto texel_func3 = [](astcenc_block_info& info, size_t texel_x, size_t texel_y) { 1676cc1dc7a3Sopenharmony_ci (void)texel_x; 1677cc1dc7a3Sopenharmony_ci (void)texel_y; 1678cc1dc7a3Sopenharmony_ci 1679cc1dc7a3Sopenharmony_ci int quant { 0 }; 1680cc1dc7a3Sopenharmony_ci if (!info.is_constant_block) 1681cc1dc7a3Sopenharmony_ci { 1682cc1dc7a3Sopenharmony_ci quant = info.weight_level_count - 1; 1683cc1dc7a3Sopenharmony_ci } 1684cc1dc7a3Sopenharmony_ci 1685cc1dc7a3Sopenharmony_ci return vint4(quant, quant, quant, 255); 1686cc1dc7a3Sopenharmony_ci }; 1687cc1dc7a3Sopenharmony_ci 1688cc1dc7a3Sopenharmony_ci print_diagnostic_image(context, image, *diag_image, texel_func3); 1689cc1dc7a3Sopenharmony_ci fname = stem + "_diag_weight_quant.png"; 1690cc1dc7a3Sopenharmony_ci store_ncimage(diag_image, fname.c_str(), false); 1691cc1dc7a3Sopenharmony_ci 1692cc1dc7a3Sopenharmony_ci // ---- ---- ---- ---- Color quant ---- ---- ---- ---- 1693cc1dc7a3Sopenharmony_ci auto texel_func4 = [](astcenc_block_info& info, size_t texel_x, size_t texel_y) { 1694cc1dc7a3Sopenharmony_ci (void)texel_x; 1695cc1dc7a3Sopenharmony_ci (void)texel_y; 1696cc1dc7a3Sopenharmony_ci 1697cc1dc7a3Sopenharmony_ci int quant { 0 }; 1698cc1dc7a3Sopenharmony_ci if (!info.is_constant_block) 1699cc1dc7a3Sopenharmony_ci { 1700cc1dc7a3Sopenharmony_ci quant = info.color_level_count - 1; 1701cc1dc7a3Sopenharmony_ci } 1702cc1dc7a3Sopenharmony_ci 1703cc1dc7a3Sopenharmony_ci return vint4(quant, quant, quant, 255); 1704cc1dc7a3Sopenharmony_ci }; 1705cc1dc7a3Sopenharmony_ci 1706cc1dc7a3Sopenharmony_ci print_diagnostic_image(context, image, *diag_image, texel_func4); 1707cc1dc7a3Sopenharmony_ci fname = stem + "_diag_color_quant.png"; 1708cc1dc7a3Sopenharmony_ci store_ncimage(diag_image, fname.c_str(), false); 1709cc1dc7a3Sopenharmony_ci 1710cc1dc7a3Sopenharmony_ci // ---- ---- ---- ---- Color endpoint mode: Index ---- ---- ---- ---- 1711cc1dc7a3Sopenharmony_ci auto texel_func5 = [](astcenc_block_info& info, size_t texel_x, size_t texel_y) { 1712cc1dc7a3Sopenharmony_ci (void)texel_x; 1713cc1dc7a3Sopenharmony_ci (void)texel_y; 1714cc1dc7a3Sopenharmony_ci 1715cc1dc7a3Sopenharmony_ci size_t texel_index = texel_y * info.block_x + texel_x; 1716cc1dc7a3Sopenharmony_ci 1717cc1dc7a3Sopenharmony_ci int cem { 255 }; 1718cc1dc7a3Sopenharmony_ci if (!info.is_constant_block) 1719cc1dc7a3Sopenharmony_ci { 1720cc1dc7a3Sopenharmony_ci uint8_t partition = info.partition_assignment[texel_index]; 1721cc1dc7a3Sopenharmony_ci cem = info.color_endpoint_modes[partition] * 16; 1722cc1dc7a3Sopenharmony_ci } 1723cc1dc7a3Sopenharmony_ci 1724cc1dc7a3Sopenharmony_ci return vint4(cem, cem, cem, 255); 1725cc1dc7a3Sopenharmony_ci }; 1726cc1dc7a3Sopenharmony_ci 1727cc1dc7a3Sopenharmony_ci print_diagnostic_image(context, image, *diag_image, texel_func5); 1728cc1dc7a3Sopenharmony_ci fname = stem + "_diag_cem_index.png"; 1729cc1dc7a3Sopenharmony_ci store_ncimage(diag_image, fname.c_str(), false); 1730cc1dc7a3Sopenharmony_ci 1731cc1dc7a3Sopenharmony_ci // ---- ---- ---- ---- Color endpoint mode: Components ---- ---- ---- ---- 1732cc1dc7a3Sopenharmony_ci auto texel_func6 = [](astcenc_block_info& info, size_t texel_x, size_t texel_y) { 1733cc1dc7a3Sopenharmony_ci (void)texel_x; 1734cc1dc7a3Sopenharmony_ci (void)texel_y; 1735cc1dc7a3Sopenharmony_ci 1736cc1dc7a3Sopenharmony_ci const vint4 colors[] { 1737cc1dc7a3Sopenharmony_ci vint4( 0, 0, 0, 255), 1738cc1dc7a3Sopenharmony_ci vint4(255, 0, 0, 255), 1739cc1dc7a3Sopenharmony_ci vint4( 0, 255, 0, 255), 1740cc1dc7a3Sopenharmony_ci vint4( 0, 0, 255, 255), 1741cc1dc7a3Sopenharmony_ci vint4(255, 255, 255, 255) 1742cc1dc7a3Sopenharmony_ci }; 1743cc1dc7a3Sopenharmony_ci 1744cc1dc7a3Sopenharmony_ci size_t texel_index = texel_y * info.block_x + texel_x; 1745cc1dc7a3Sopenharmony_ci 1746cc1dc7a3Sopenharmony_ci int components { 0 }; 1747cc1dc7a3Sopenharmony_ci if (!info.is_constant_block) 1748cc1dc7a3Sopenharmony_ci { 1749cc1dc7a3Sopenharmony_ci uint8_t partition = info.partition_assignment[texel_index]; 1750cc1dc7a3Sopenharmony_ci uint8_t cem = info.color_endpoint_modes[partition]; 1751cc1dc7a3Sopenharmony_ci 1752cc1dc7a3Sopenharmony_ci switch (cem) 1753cc1dc7a3Sopenharmony_ci { 1754cc1dc7a3Sopenharmony_ci case 0: 1755cc1dc7a3Sopenharmony_ci case 1: 1756cc1dc7a3Sopenharmony_ci case 2: 1757cc1dc7a3Sopenharmony_ci case 3: 1758cc1dc7a3Sopenharmony_ci components = 1; 1759cc1dc7a3Sopenharmony_ci break; 1760cc1dc7a3Sopenharmony_ci case 4: 1761cc1dc7a3Sopenharmony_ci case 5: 1762cc1dc7a3Sopenharmony_ci components = 2; 1763cc1dc7a3Sopenharmony_ci break; 1764cc1dc7a3Sopenharmony_ci case 6: 1765cc1dc7a3Sopenharmony_ci case 7: 1766cc1dc7a3Sopenharmony_ci case 8: 1767cc1dc7a3Sopenharmony_ci case 9: 1768cc1dc7a3Sopenharmony_ci case 11: 1769cc1dc7a3Sopenharmony_ci components = 3; 1770cc1dc7a3Sopenharmony_ci break; 1771cc1dc7a3Sopenharmony_ci default: 1772cc1dc7a3Sopenharmony_ci components = 4; 1773cc1dc7a3Sopenharmony_ci break; 1774cc1dc7a3Sopenharmony_ci } 1775cc1dc7a3Sopenharmony_ci } 1776cc1dc7a3Sopenharmony_ci 1777cc1dc7a3Sopenharmony_ci return colors[components]; 1778cc1dc7a3Sopenharmony_ci }; 1779cc1dc7a3Sopenharmony_ci 1780cc1dc7a3Sopenharmony_ci print_diagnostic_image(context, image, *diag_image, texel_func6); 1781cc1dc7a3Sopenharmony_ci fname = stem + "_diag_cem_components.png"; 1782cc1dc7a3Sopenharmony_ci store_ncimage(diag_image, fname.c_str(), false); 1783cc1dc7a3Sopenharmony_ci 1784cc1dc7a3Sopenharmony_ci // ---- ---- ---- ---- Color endpoint mode: Style ---- ---- ---- ---- 1785cc1dc7a3Sopenharmony_ci auto texel_func7 = [](astcenc_block_info& info, size_t texel_x, size_t texel_y) { 1786cc1dc7a3Sopenharmony_ci (void)texel_x; 1787cc1dc7a3Sopenharmony_ci (void)texel_y; 1788cc1dc7a3Sopenharmony_ci 1789cc1dc7a3Sopenharmony_ci const vint4 colors[] { 1790cc1dc7a3Sopenharmony_ci vint4( 0, 0, 0, 255), 1791cc1dc7a3Sopenharmony_ci vint4(255, 0, 0, 255), 1792cc1dc7a3Sopenharmony_ci vint4( 0, 255, 0, 255), 1793cc1dc7a3Sopenharmony_ci vint4( 0, 0, 255, 255), 1794cc1dc7a3Sopenharmony_ci }; 1795cc1dc7a3Sopenharmony_ci 1796cc1dc7a3Sopenharmony_ci size_t texel_index = texel_y * info.block_x + texel_x; 1797cc1dc7a3Sopenharmony_ci 1798cc1dc7a3Sopenharmony_ci int style { 0 }; 1799cc1dc7a3Sopenharmony_ci if (!info.is_constant_block) 1800cc1dc7a3Sopenharmony_ci { 1801cc1dc7a3Sopenharmony_ci uint8_t partition = info.partition_assignment[texel_index]; 1802cc1dc7a3Sopenharmony_ci uint8_t cem = info.color_endpoint_modes[partition]; 1803cc1dc7a3Sopenharmony_ci 1804cc1dc7a3Sopenharmony_ci switch (cem) 1805cc1dc7a3Sopenharmony_ci { 1806cc1dc7a3Sopenharmony_ci // Direct - two absolute endpoints 1807cc1dc7a3Sopenharmony_ci case 0: 1808cc1dc7a3Sopenharmony_ci case 1: 1809cc1dc7a3Sopenharmony_ci case 2: 1810cc1dc7a3Sopenharmony_ci case 3: 1811cc1dc7a3Sopenharmony_ci case 4: 1812cc1dc7a3Sopenharmony_ci case 8: 1813cc1dc7a3Sopenharmony_ci case 11: 1814cc1dc7a3Sopenharmony_ci case 12: 1815cc1dc7a3Sopenharmony_ci case 14: 1816cc1dc7a3Sopenharmony_ci case 15: 1817cc1dc7a3Sopenharmony_ci style = 1; 1818cc1dc7a3Sopenharmony_ci break; 1819cc1dc7a3Sopenharmony_ci // Offset - one absolute plus delta 1820cc1dc7a3Sopenharmony_ci case 5: 1821cc1dc7a3Sopenharmony_ci case 9: 1822cc1dc7a3Sopenharmony_ci case 13: 1823cc1dc7a3Sopenharmony_ci style = 2; 1824cc1dc7a3Sopenharmony_ci break; 1825cc1dc7a3Sopenharmony_ci // Scale - one absolute plus scale 1826cc1dc7a3Sopenharmony_ci case 6: 1827cc1dc7a3Sopenharmony_ci case 7: 1828cc1dc7a3Sopenharmony_ci case 10: 1829cc1dc7a3Sopenharmony_ci style = 3; 1830cc1dc7a3Sopenharmony_ci break; 1831cc1dc7a3Sopenharmony_ci // Shouldn't happen ... 1832cc1dc7a3Sopenharmony_ci default: 1833cc1dc7a3Sopenharmony_ci style = 0; 1834cc1dc7a3Sopenharmony_ci break; 1835cc1dc7a3Sopenharmony_ci } 1836cc1dc7a3Sopenharmony_ci } 1837cc1dc7a3Sopenharmony_ci 1838cc1dc7a3Sopenharmony_ci return colors[style]; 1839cc1dc7a3Sopenharmony_ci }; 1840cc1dc7a3Sopenharmony_ci 1841cc1dc7a3Sopenharmony_ci print_diagnostic_image(context, image, *diag_image, texel_func7); 1842cc1dc7a3Sopenharmony_ci fname = stem + "_diag_cem_style.png"; 1843cc1dc7a3Sopenharmony_ci store_ncimage(diag_image, fname.c_str(), false); 1844cc1dc7a3Sopenharmony_ci 1845cc1dc7a3Sopenharmony_ci // ---- ---- ---- ---- Color endpoint mode: Style ---- ---- ---- ---- 1846cc1dc7a3Sopenharmony_ci auto texel_func8 = [](astcenc_block_info& info, size_t texel_x, size_t texel_y) { 1847cc1dc7a3Sopenharmony_ci (void)texel_x; 1848cc1dc7a3Sopenharmony_ci (void)texel_y; 1849cc1dc7a3Sopenharmony_ci 1850cc1dc7a3Sopenharmony_ci size_t texel_index = texel_y * info.block_x + texel_x; 1851cc1dc7a3Sopenharmony_ci 1852cc1dc7a3Sopenharmony_ci int style { 0 }; 1853cc1dc7a3Sopenharmony_ci if (!info.is_constant_block) 1854cc1dc7a3Sopenharmony_ci { 1855cc1dc7a3Sopenharmony_ci uint8_t partition = info.partition_assignment[texel_index]; 1856cc1dc7a3Sopenharmony_ci uint8_t cem = info.color_endpoint_modes[partition]; 1857cc1dc7a3Sopenharmony_ci 1858cc1dc7a3Sopenharmony_ci switch (cem) 1859cc1dc7a3Sopenharmony_ci { 1860cc1dc7a3Sopenharmony_ci // LDR blocks 1861cc1dc7a3Sopenharmony_ci case 0: 1862cc1dc7a3Sopenharmony_ci case 1: 1863cc1dc7a3Sopenharmony_ci case 4: 1864cc1dc7a3Sopenharmony_ci case 5: 1865cc1dc7a3Sopenharmony_ci case 6: 1866cc1dc7a3Sopenharmony_ci case 8: 1867cc1dc7a3Sopenharmony_ci case 9: 1868cc1dc7a3Sopenharmony_ci case 10: 1869cc1dc7a3Sopenharmony_ci case 12: 1870cc1dc7a3Sopenharmony_ci case 13: 1871cc1dc7a3Sopenharmony_ci style = 128; 1872cc1dc7a3Sopenharmony_ci break; 1873cc1dc7a3Sopenharmony_ci // HDR blocks 1874cc1dc7a3Sopenharmony_ci default: 1875cc1dc7a3Sopenharmony_ci style = 155; 1876cc1dc7a3Sopenharmony_ci break; 1877cc1dc7a3Sopenharmony_ci } 1878cc1dc7a3Sopenharmony_ci } 1879cc1dc7a3Sopenharmony_ci 1880cc1dc7a3Sopenharmony_ci return vint4(style, style, style, 255); 1881cc1dc7a3Sopenharmony_ci }; 1882cc1dc7a3Sopenharmony_ci 1883cc1dc7a3Sopenharmony_ci print_diagnostic_image(context, image, *diag_image, texel_func8); 1884cc1dc7a3Sopenharmony_ci fname = stem + "_diag_cem_hdr.png"; 1885cc1dc7a3Sopenharmony_ci store_ncimage(diag_image, fname.c_str(), false); 1886cc1dc7a3Sopenharmony_ci 1887cc1dc7a3Sopenharmony_ci free_image(diag_image); 1888cc1dc7a3Sopenharmony_ci} 1889cc1dc7a3Sopenharmony_ci 1890cc1dc7a3Sopenharmony_ci#if QUALITY_CONTROL 1891cc1dc7a3Sopenharmony_ciconstexpr double MAX_PSNR = 99.9; 1892cc1dc7a3Sopenharmony_ciconstexpr double MAX_VALUE = 255; 1893cc1dc7a3Sopenharmony_ciconstexpr double THRESHOLD_R = 30.0; 1894cc1dc7a3Sopenharmony_ciconstexpr double THRESHOLD_G = 30.0; 1895cc1dc7a3Sopenharmony_ciconstexpr double THRESHOLD_B = 30.0; 1896cc1dc7a3Sopenharmony_ciconstexpr double THRESHOLD_A = 30.0; 1897cc1dc7a3Sopenharmony_ciconstexpr double THRESHOLD_RGB = 30.0; 1898cc1dc7a3Sopenharmony_ciconstexpr double LOG_BASE = 10.0; 1899cc1dc7a3Sopenharmony_ci 1900cc1dc7a3Sopenharmony_cibool CheckQuality(int32_t* mseIn[RGBA_COM], int blockNum, int blockXYZ) 1901cc1dc7a3Sopenharmony_ci{ 1902cc1dc7a3Sopenharmony_ci double psnr[RGBA_COM + 1]; 1903cc1dc7a3Sopenharmony_ci double threshold[RGBA_COM + 1] = { THRESHOLD_R, THRESHOLD_G, THRESHOLD_B, THRESHOLD_A, THRESHOLD_RGB}; 1904cc1dc7a3Sopenharmony_ci uint64_t mseTotal[RGBA_COM + 1] = { 0, 0, 0, 0, 0}; 1905cc1dc7a3Sopenharmony_ci for (int i = R_COM; i < RGBA_COM; i++) { 1906cc1dc7a3Sopenharmony_ci int32_t* mse = mseIn[i]; 1907cc1dc7a3Sopenharmony_ci for (int j = 0; j < blockNum; j++) { 1908cc1dc7a3Sopenharmony_ci mseTotal[i] += *mse; 1909cc1dc7a3Sopenharmony_ci if(i != A_COM) mseTotal[RGBA_COM] += *mse; 1910cc1dc7a3Sopenharmony_ci mse++; 1911cc1dc7a3Sopenharmony_ci } 1912cc1dc7a3Sopenharmony_ci } 1913cc1dc7a3Sopenharmony_ci for (int i = R_COM; i < RGBA_COM; i++) { 1914cc1dc7a3Sopenharmony_ci if (mseTotal[i] == 0) { 1915cc1dc7a3Sopenharmony_ci psnr[i] = MAX_PSNR; 1916cc1dc7a3Sopenharmony_ci continue; 1917cc1dc7a3Sopenharmony_ci } 1918cc1dc7a3Sopenharmony_ci double mseRgb = (double)mseTotal[i] / (blockNum * blockXYZ); 1919cc1dc7a3Sopenharmony_ci psnr[i] = LOG_BASE * log((double)(MAX_VALUE * MAX_VALUE) / mseRgb) / log(LOG_BASE); 1920cc1dc7a3Sopenharmony_ci } 1921cc1dc7a3Sopenharmony_ci if (mseTotal[RGBA_COM] == 0) { 1922cc1dc7a3Sopenharmony_ci psnr[RGBA_COM] = MAX_PSNR; 1923cc1dc7a3Sopenharmony_ci } 1924cc1dc7a3Sopenharmony_ci else { 1925cc1dc7a3Sopenharmony_ci double mseRgb = (double)mseTotal[RGBA_COM] / (blockNum * blockXYZ * (RGBA_COM - 1)); 1926cc1dc7a3Sopenharmony_ci psnr[RGBA_COM] = LOG_BASE * log((double)(MAX_VALUE * MAX_VALUE) / mseRgb) / log(LOG_BASE); 1927cc1dc7a3Sopenharmony_ci } 1928cc1dc7a3Sopenharmony_ci printf("astc psnr r%f g%f b%f a%f rgb%f\n", 1929cc1dc7a3Sopenharmony_ci psnr[R_COM], psnr[G_COM], psnr[B_COM], psnr[A_COM], 1930cc1dc7a3Sopenharmony_ci psnr[RGBA_COM]); 1931cc1dc7a3Sopenharmony_ci return (psnr[R_COM] > threshold[R_COM]) && (psnr[G_COM] > threshold[G_COM]) 1932cc1dc7a3Sopenharmony_ci && (psnr[B_COM] > threshold[B_COM]) && (psnr[A_COM] > threshold[A_COM]) 1933cc1dc7a3Sopenharmony_ci && (psnr[RGBA_COM] > threshold[RGBA_COM]); 1934cc1dc7a3Sopenharmony_ci} 1935cc1dc7a3Sopenharmony_ci#endif 1936cc1dc7a3Sopenharmony_ci 1937cc1dc7a3Sopenharmony_ci/** 1938cc1dc7a3Sopenharmony_ci * @brief The main entry point. 1939cc1dc7a3Sopenharmony_ci * 1940cc1dc7a3Sopenharmony_ci * @param argc The number of arguments. 1941cc1dc7a3Sopenharmony_ci * @param argv The vector of arguments. 1942cc1dc7a3Sopenharmony_ci * 1943cc1dc7a3Sopenharmony_ci * @return 0 on success, non-zero otherwise. 1944cc1dc7a3Sopenharmony_ci */ 1945cc1dc7a3Sopenharmony_ciint astcenc_main( 1946cc1dc7a3Sopenharmony_ci int argc, 1947cc1dc7a3Sopenharmony_ci char **argv 1948cc1dc7a3Sopenharmony_ci) { 1949cc1dc7a3Sopenharmony_ci double start_time = get_time(); 1950cc1dc7a3Sopenharmony_ci 1951cc1dc7a3Sopenharmony_ci if (argc < 2) 1952cc1dc7a3Sopenharmony_ci { 1953cc1dc7a3Sopenharmony_ci astcenc_print_shorthelp(); 1954cc1dc7a3Sopenharmony_ci return 0; 1955cc1dc7a3Sopenharmony_ci } 1956cc1dc7a3Sopenharmony_ci 1957cc1dc7a3Sopenharmony_ci astcenc_operation operation; 1958cc1dc7a3Sopenharmony_ci astcenc_profile profile; 1959cc1dc7a3Sopenharmony_ci int error = parse_commandline_options(argc, argv, operation, profile); 1960cc1dc7a3Sopenharmony_ci if (error) 1961cc1dc7a3Sopenharmony_ci { 1962cc1dc7a3Sopenharmony_ci return 1; 1963cc1dc7a3Sopenharmony_ci } 1964cc1dc7a3Sopenharmony_ci 1965cc1dc7a3Sopenharmony_ci switch (operation) 1966cc1dc7a3Sopenharmony_ci { 1967cc1dc7a3Sopenharmony_ci case ASTCENC_OP_HELP: 1968cc1dc7a3Sopenharmony_ci astcenc_print_longhelp(); 1969cc1dc7a3Sopenharmony_ci return 0; 1970cc1dc7a3Sopenharmony_ci case ASTCENC_OP_VERSION: 1971cc1dc7a3Sopenharmony_ci astcenc_print_header(); 1972cc1dc7a3Sopenharmony_ci return 0; 1973cc1dc7a3Sopenharmony_ci default: 1974cc1dc7a3Sopenharmony_ci break; 1975cc1dc7a3Sopenharmony_ci } 1976cc1dc7a3Sopenharmony_ci 1977cc1dc7a3Sopenharmony_ci std::string input_filename = argc >= 3 ? argv[2] : ""; 1978cc1dc7a3Sopenharmony_ci std::string output_filename = argc >= 4 ? argv[3] : ""; 1979cc1dc7a3Sopenharmony_ci 1980cc1dc7a3Sopenharmony_ci if (input_filename.empty()) 1981cc1dc7a3Sopenharmony_ci { 1982cc1dc7a3Sopenharmony_ci print_error("ERROR: Input file not specified\n"); 1983cc1dc7a3Sopenharmony_ci return 1; 1984cc1dc7a3Sopenharmony_ci } 1985cc1dc7a3Sopenharmony_ci 1986cc1dc7a3Sopenharmony_ci if (output_filename.empty()) 1987cc1dc7a3Sopenharmony_ci { 1988cc1dc7a3Sopenharmony_ci print_error("ERROR: Output file not specified\n"); 1989cc1dc7a3Sopenharmony_ci return 1; 1990cc1dc7a3Sopenharmony_ci } 1991cc1dc7a3Sopenharmony_ci 1992cc1dc7a3Sopenharmony_ci // TODO: Handle RAII resources so they get freed when out of scope 1993cc1dc7a3Sopenharmony_ci // Load the compressed input file if needed 1994cc1dc7a3Sopenharmony_ci 1995cc1dc7a3Sopenharmony_ci // This has to come first, as the block size is in the file header 1996cc1dc7a3Sopenharmony_ci astc_compressed_image image_comp {}; 1997cc1dc7a3Sopenharmony_ci if (operation & ASTCENC_STAGE_LD_COMP) 1998cc1dc7a3Sopenharmony_ci { 1999cc1dc7a3Sopenharmony_ci if (ends_with(input_filename, ".astc")) 2000cc1dc7a3Sopenharmony_ci { 2001cc1dc7a3Sopenharmony_ci error = load_cimage(input_filename.c_str(), image_comp); 2002cc1dc7a3Sopenharmony_ci if (error) 2003cc1dc7a3Sopenharmony_ci { 2004cc1dc7a3Sopenharmony_ci return 1; 2005cc1dc7a3Sopenharmony_ci } 2006cc1dc7a3Sopenharmony_ci } 2007cc1dc7a3Sopenharmony_ci else if (ends_with(input_filename, ".ktx")) 2008cc1dc7a3Sopenharmony_ci { 2009cc1dc7a3Sopenharmony_ci bool is_srgb; 2010cc1dc7a3Sopenharmony_ci error = load_ktx_compressed_image(input_filename.c_str(), is_srgb, image_comp); 2011cc1dc7a3Sopenharmony_ci if (error) 2012cc1dc7a3Sopenharmony_ci { 2013cc1dc7a3Sopenharmony_ci return 1; 2014cc1dc7a3Sopenharmony_ci } 2015cc1dc7a3Sopenharmony_ci 2016cc1dc7a3Sopenharmony_ci if (is_srgb && (profile != ASTCENC_PRF_LDR_SRGB)) 2017cc1dc7a3Sopenharmony_ci { 2018cc1dc7a3Sopenharmony_ci printf("WARNING: Input file is sRGB, but decompressing as linear\n"); 2019cc1dc7a3Sopenharmony_ci } 2020cc1dc7a3Sopenharmony_ci 2021cc1dc7a3Sopenharmony_ci if (!is_srgb && (profile == ASTCENC_PRF_LDR_SRGB)) 2022cc1dc7a3Sopenharmony_ci { 2023cc1dc7a3Sopenharmony_ci printf("WARNING: Input file is linear, but decompressing as sRGB\n"); 2024cc1dc7a3Sopenharmony_ci } 2025cc1dc7a3Sopenharmony_ci } 2026cc1dc7a3Sopenharmony_ci else 2027cc1dc7a3Sopenharmony_ci { 2028cc1dc7a3Sopenharmony_ci print_error("ERROR: Unknown compressed input file type\n"); 2029cc1dc7a3Sopenharmony_ci return 1; 2030cc1dc7a3Sopenharmony_ci } 2031cc1dc7a3Sopenharmony_ci } 2032cc1dc7a3Sopenharmony_ci 2033cc1dc7a3Sopenharmony_ci astcenc_config config {}; 2034cc1dc7a3Sopenharmony_ci astcenc_preprocess preprocess; 2035cc1dc7a3Sopenharmony_ci error = init_astcenc_config(argc, argv, profile, operation, image_comp, preprocess, config); 2036cc1dc7a3Sopenharmony_ci if (error) 2037cc1dc7a3Sopenharmony_ci { 2038cc1dc7a3Sopenharmony_ci return 1; 2039cc1dc7a3Sopenharmony_ci } 2040cc1dc7a3Sopenharmony_ci 2041cc1dc7a3Sopenharmony_ci // Initialize cli_config_options with default values 2042cc1dc7a3Sopenharmony_ci cli_config_options cli_config { 0, 1, 1, false, false, false, -10, 10, 2043cc1dc7a3Sopenharmony_ci { ASTCENC_SWZ_R, ASTCENC_SWZ_G, ASTCENC_SWZ_B, ASTCENC_SWZ_A }, 2044cc1dc7a3Sopenharmony_ci { ASTCENC_SWZ_R, ASTCENC_SWZ_G, ASTCENC_SWZ_B, ASTCENC_SWZ_A } }; 2045cc1dc7a3Sopenharmony_ci 2046cc1dc7a3Sopenharmony_ci error = edit_astcenc_config(argc, argv, operation, cli_config, config); 2047cc1dc7a3Sopenharmony_ci if (error) 2048cc1dc7a3Sopenharmony_ci { 2049cc1dc7a3Sopenharmony_ci return 1; 2050cc1dc7a3Sopenharmony_ci } 2051cc1dc7a3Sopenharmony_ci 2052cc1dc7a3Sopenharmony_ci // Enable progress callback if not in silent mode and using a terminal 2053cc1dc7a3Sopenharmony_ci #if defined(_WIN32) 2054cc1dc7a3Sopenharmony_ci int stdoutfno = _fileno(stdout); 2055cc1dc7a3Sopenharmony_ci #else 2056cc1dc7a3Sopenharmony_ci int stdoutfno = STDOUT_FILENO; 2057cc1dc7a3Sopenharmony_ci #endif 2058cc1dc7a3Sopenharmony_ci 2059cc1dc7a3Sopenharmony_ci if ((!cli_config.silentmode) && isatty(stdoutfno)) 2060cc1dc7a3Sopenharmony_ci { 2061cc1dc7a3Sopenharmony_ci config.progress_callback = progress_emitter; 2062cc1dc7a3Sopenharmony_ci } 2063cc1dc7a3Sopenharmony_ci 2064cc1dc7a3Sopenharmony_ci astcenc_image* image_uncomp_in = nullptr ; 2065cc1dc7a3Sopenharmony_ci unsigned int image_uncomp_in_component_count = 0; 2066cc1dc7a3Sopenharmony_ci bool image_uncomp_in_is_hdr = false; 2067cc1dc7a3Sopenharmony_ci astcenc_image* image_decomp_out = nullptr; 2068cc1dc7a3Sopenharmony_ci 2069cc1dc7a3Sopenharmony_ci // Determine decompression output bitness, if limited by file type 2070cc1dc7a3Sopenharmony_ci int out_bitness = 0; 2071cc1dc7a3Sopenharmony_ci if (operation & ASTCENC_STAGE_DECOMPRESS) 2072cc1dc7a3Sopenharmony_ci { 2073cc1dc7a3Sopenharmony_ci out_bitness = get_output_filename_enforced_bitness(output_filename.c_str()); 2074cc1dc7a3Sopenharmony_ci if (out_bitness == 0) 2075cc1dc7a3Sopenharmony_ci { 2076cc1dc7a3Sopenharmony_ci bool is_hdr = (config.profile == ASTCENC_PRF_HDR) || 2077cc1dc7a3Sopenharmony_ci (config.profile == ASTCENC_PRF_HDR_RGB_LDR_A); 2078cc1dc7a3Sopenharmony_ci out_bitness = is_hdr ? 16 : 8; 2079cc1dc7a3Sopenharmony_ci } 2080cc1dc7a3Sopenharmony_ci 2081cc1dc7a3Sopenharmony_ci // If decompressed output is unorm8 then force the decode_unorm8 heuristics for compression 2082cc1dc7a3Sopenharmony_ci if (out_bitness == 8) 2083cc1dc7a3Sopenharmony_ci { 2084cc1dc7a3Sopenharmony_ci config.flags |= ASTCENC_FLG_USE_DECODE_UNORM8; 2085cc1dc7a3Sopenharmony_ci } 2086cc1dc7a3Sopenharmony_ci } 2087cc1dc7a3Sopenharmony_ci 2088cc1dc7a3Sopenharmony_ci // TODO: Handle RAII resources so they get freed when out of scope 2089cc1dc7a3Sopenharmony_ci astcenc_error codec_status; 2090cc1dc7a3Sopenharmony_ci astcenc_context* codec_context; 2091cc1dc7a3Sopenharmony_ci 2092cc1dc7a3Sopenharmony_ci // Preflight - check we have valid extensions for storing a file 2093cc1dc7a3Sopenharmony_ci if (operation & ASTCENC_STAGE_ST_NCOMP) 2094cc1dc7a3Sopenharmony_ci { 2095cc1dc7a3Sopenharmony_ci int bitness = get_output_filename_enforced_bitness(output_filename.c_str()); 2096cc1dc7a3Sopenharmony_ci if (bitness < 0) 2097cc1dc7a3Sopenharmony_ci { 2098cc1dc7a3Sopenharmony_ci const char *eptr = strrchr(output_filename.c_str(), '.'); 2099cc1dc7a3Sopenharmony_ci eptr = eptr ? eptr : ""; 2100cc1dc7a3Sopenharmony_ci print_error("ERROR: Unknown uncompressed output file type '%s'\n", eptr); 2101cc1dc7a3Sopenharmony_ci return 1; 2102cc1dc7a3Sopenharmony_ci } 2103cc1dc7a3Sopenharmony_ci } 2104cc1dc7a3Sopenharmony_ci 2105cc1dc7a3Sopenharmony_ci if (operation & ASTCENC_STAGE_ST_COMP) 2106cc1dc7a3Sopenharmony_ci { 2107cc1dc7a3Sopenharmony_ci#if defined(_WIN32) 2108cc1dc7a3Sopenharmony_ci bool is_null = output_filename == "NUL" || output_filename == "nul"; 2109cc1dc7a3Sopenharmony_ci#else 2110cc1dc7a3Sopenharmony_ci bool is_null = output_filename == "/dev/null"; 2111cc1dc7a3Sopenharmony_ci#endif 2112cc1dc7a3Sopenharmony_ci 2113cc1dc7a3Sopenharmony_ci if (!(is_null || ends_with(output_filename, ".astc") || ends_with(output_filename, ".ktx"))) 2114cc1dc7a3Sopenharmony_ci { 2115cc1dc7a3Sopenharmony_ci const char *eptr = strrchr(output_filename.c_str(), '.'); 2116cc1dc7a3Sopenharmony_ci eptr = eptr ? eptr : ""; 2117cc1dc7a3Sopenharmony_ci print_error("ERROR: Unknown compressed output file type '%s'\n", eptr); 2118cc1dc7a3Sopenharmony_ci return 1; 2119cc1dc7a3Sopenharmony_ci } 2120cc1dc7a3Sopenharmony_ci } 2121cc1dc7a3Sopenharmony_ci 2122cc1dc7a3Sopenharmony_ci codec_status = astcenc_context_alloc(&config, cli_config.thread_count, &codec_context); 2123cc1dc7a3Sopenharmony_ci if (codec_status != ASTCENC_SUCCESS) 2124cc1dc7a3Sopenharmony_ci { 2125cc1dc7a3Sopenharmony_ci print_error("ERROR: Codec context alloc failed: %s\n", astcenc_get_error_string(codec_status)); 2126cc1dc7a3Sopenharmony_ci return 1; 2127cc1dc7a3Sopenharmony_ci } 2128cc1dc7a3Sopenharmony_ci 2129cc1dc7a3Sopenharmony_ci // Load the uncompressed input file if needed 2130cc1dc7a3Sopenharmony_ci if (operation & ASTCENC_STAGE_LD_NCOMP) 2131cc1dc7a3Sopenharmony_ci { 2132cc1dc7a3Sopenharmony_ci image_uncomp_in = load_uncomp_file( 2133cc1dc7a3Sopenharmony_ci input_filename.c_str(), cli_config.array_size, cli_config.y_flip, 2134cc1dc7a3Sopenharmony_ci image_uncomp_in_is_hdr, image_uncomp_in_component_count); 2135cc1dc7a3Sopenharmony_ci if (!image_uncomp_in) 2136cc1dc7a3Sopenharmony_ci { 2137cc1dc7a3Sopenharmony_ci print_error("ERROR: Failed to load uncompressed image file\n"); 2138cc1dc7a3Sopenharmony_ci return 1; 2139cc1dc7a3Sopenharmony_ci } 2140cc1dc7a3Sopenharmony_ci 2141cc1dc7a3Sopenharmony_ci 2142cc1dc7a3Sopenharmony_ci if (preprocess != ASTCENC_PP_NONE) 2143cc1dc7a3Sopenharmony_ci { 2144cc1dc7a3Sopenharmony_ci // Allocate a float image so we can avoid additional quantization, 2145cc1dc7a3Sopenharmony_ci // as e.g. premultiplication can result in fractional color values 2146cc1dc7a3Sopenharmony_ci astcenc_image* image_pp = alloc_image(32, 2147cc1dc7a3Sopenharmony_ci image_uncomp_in->dim_x, 2148cc1dc7a3Sopenharmony_ci image_uncomp_in->dim_y, 2149cc1dc7a3Sopenharmony_ci image_uncomp_in->dim_z); 2150cc1dc7a3Sopenharmony_ci if (!image_pp) 2151cc1dc7a3Sopenharmony_ci { 2152cc1dc7a3Sopenharmony_ci print_error("ERROR: Failed to allocate preprocessed image\n"); 2153cc1dc7a3Sopenharmony_ci return 1; 2154cc1dc7a3Sopenharmony_ci } 2155cc1dc7a3Sopenharmony_ci 2156cc1dc7a3Sopenharmony_ci if (preprocess == ASTCENC_PP_NORMALIZE) 2157cc1dc7a3Sopenharmony_ci { 2158cc1dc7a3Sopenharmony_ci image_preprocess_normalize(*image_uncomp_in, *image_pp); 2159cc1dc7a3Sopenharmony_ci } 2160cc1dc7a3Sopenharmony_ci 2161cc1dc7a3Sopenharmony_ci if (preprocess == ASTCENC_PP_PREMULTIPLY) 2162cc1dc7a3Sopenharmony_ci { 2163cc1dc7a3Sopenharmony_ci image_preprocess_premultiply(*image_uncomp_in, *image_pp, 2164cc1dc7a3Sopenharmony_ci config.profile); 2165cc1dc7a3Sopenharmony_ci } 2166cc1dc7a3Sopenharmony_ci 2167cc1dc7a3Sopenharmony_ci // Delete the original as we no longer need it 2168cc1dc7a3Sopenharmony_ci free_image(image_uncomp_in); 2169cc1dc7a3Sopenharmony_ci image_uncomp_in = image_pp; 2170cc1dc7a3Sopenharmony_ci } 2171cc1dc7a3Sopenharmony_ci 2172cc1dc7a3Sopenharmony_ci if (!cli_config.silentmode) 2173cc1dc7a3Sopenharmony_ci { 2174cc1dc7a3Sopenharmony_ci printf("Source image\n"); 2175cc1dc7a3Sopenharmony_ci printf("============\n\n"); 2176cc1dc7a3Sopenharmony_ci printf(" Source: %s\n", input_filename.c_str()); 2177cc1dc7a3Sopenharmony_ci printf(" Color profile: %s\n", image_uncomp_in_is_hdr ? "HDR" : "LDR"); 2178cc1dc7a3Sopenharmony_ci if (image_uncomp_in->dim_z > 1) 2179cc1dc7a3Sopenharmony_ci { 2180cc1dc7a3Sopenharmony_ci printf(" Dimensions: 3D, %ux%ux%u\n", 2181cc1dc7a3Sopenharmony_ci image_uncomp_in->dim_x, image_uncomp_in->dim_y, image_uncomp_in->dim_z); 2182cc1dc7a3Sopenharmony_ci } 2183cc1dc7a3Sopenharmony_ci else 2184cc1dc7a3Sopenharmony_ci { 2185cc1dc7a3Sopenharmony_ci printf(" Dimensions: 2D, %ux%u\n", 2186cc1dc7a3Sopenharmony_ci image_uncomp_in->dim_x, image_uncomp_in->dim_y); 2187cc1dc7a3Sopenharmony_ci } 2188cc1dc7a3Sopenharmony_ci printf(" Components: %d\n\n", image_uncomp_in_component_count); 2189cc1dc7a3Sopenharmony_ci } 2190cc1dc7a3Sopenharmony_ci } 2191cc1dc7a3Sopenharmony_ci 2192cc1dc7a3Sopenharmony_ci double image_size = 0.0; 2193cc1dc7a3Sopenharmony_ci if (image_uncomp_in) 2194cc1dc7a3Sopenharmony_ci { 2195cc1dc7a3Sopenharmony_ci image_size = static_cast<double>(image_uncomp_in->dim_x) * 2196cc1dc7a3Sopenharmony_ci static_cast<double>(image_uncomp_in->dim_y) * 2197cc1dc7a3Sopenharmony_ci static_cast<double>(image_uncomp_in->dim_z); 2198cc1dc7a3Sopenharmony_ci } 2199cc1dc7a3Sopenharmony_ci else 2200cc1dc7a3Sopenharmony_ci { 2201cc1dc7a3Sopenharmony_ci image_size = static_cast<double>(image_comp.dim_x) * 2202cc1dc7a3Sopenharmony_ci static_cast<double>(image_comp.dim_y) * 2203cc1dc7a3Sopenharmony_ci static_cast<double>(image_comp.dim_z); 2204cc1dc7a3Sopenharmony_ci } 2205cc1dc7a3Sopenharmony_ci 2206cc1dc7a3Sopenharmony_ci // Compress an image 2207cc1dc7a3Sopenharmony_ci double best_compression_time = 100000.0; 2208cc1dc7a3Sopenharmony_ci double total_compression_time = 0.0; 2209cc1dc7a3Sopenharmony_ci if (operation & ASTCENC_STAGE_COMPRESS) 2210cc1dc7a3Sopenharmony_ci { 2211cc1dc7a3Sopenharmony_ci print_astcenc_config(cli_config, config); 2212cc1dc7a3Sopenharmony_ci 2213cc1dc7a3Sopenharmony_ci unsigned int blocks_x = (image_uncomp_in->dim_x + config.block_x - 1) / config.block_x; 2214cc1dc7a3Sopenharmony_ci unsigned int blocks_y = (image_uncomp_in->dim_y + config.block_y - 1) / config.block_y; 2215cc1dc7a3Sopenharmony_ci unsigned int blocks_z = (image_uncomp_in->dim_z + config.block_z - 1) / config.block_z; 2216cc1dc7a3Sopenharmony_ci size_t buffer_size = blocks_x * blocks_y * blocks_z * 16; 2217cc1dc7a3Sopenharmony_ci uint8_t* buffer = new uint8_t[buffer_size]; 2218cc1dc7a3Sopenharmony_ci 2219cc1dc7a3Sopenharmony_ci compression_workload work; 2220cc1dc7a3Sopenharmony_ci work.context = codec_context; 2221cc1dc7a3Sopenharmony_ci image_uncomp_in->dim_stride = image_uncomp_in->dim_x; 2222cc1dc7a3Sopenharmony_ci work.image = image_uncomp_in; 2223cc1dc7a3Sopenharmony_ci work.swizzle = cli_config.swz_encode; 2224cc1dc7a3Sopenharmony_ci work.data_out = buffer; 2225cc1dc7a3Sopenharmony_ci work.data_len = buffer_size; 2226cc1dc7a3Sopenharmony_ci work.error = ASTCENC_SUCCESS; 2227cc1dc7a3Sopenharmony_ci#if QUALITY_CONTROL 2228cc1dc7a3Sopenharmony_ci work.calQualityEnable = true; 2229cc1dc7a3Sopenharmony_ci work.mse[R_COM] = work.mse[G_COM] = work.mse[B_COM] = work.mse[A_COM] = nullptr; 2230cc1dc7a3Sopenharmony_ci if (work.calQualityEnable) { 2231cc1dc7a3Sopenharmony_ci for (int i = R_COM; i < RGBA_COM; i++) { 2232cc1dc7a3Sopenharmony_ci work.mse[i] = (int32_t*)calloc(blocks_x * blocks_y, sizeof(int32_t)); 2233cc1dc7a3Sopenharmony_ci if (!work.mse[i]) { 2234cc1dc7a3Sopenharmony_ci printf("quality control calloc failed"); 2235cc1dc7a3Sopenharmony_ci return -1; 2236cc1dc7a3Sopenharmony_ci } 2237cc1dc7a3Sopenharmony_ci } 2238cc1dc7a3Sopenharmony_ci } 2239cc1dc7a3Sopenharmony_ci#endif 2240cc1dc7a3Sopenharmony_ci // Only launch worker threads for multi-threaded use - it makes basic 2241cc1dc7a3Sopenharmony_ci // single-threaded profiling and debugging a little less convoluted 2242cc1dc7a3Sopenharmony_ci double start_compression_time = get_time(); 2243cc1dc7a3Sopenharmony_ci for (unsigned int i = 0; i < cli_config.repeat_count; i++) 2244cc1dc7a3Sopenharmony_ci { 2245cc1dc7a3Sopenharmony_ci if (config.progress_callback) 2246cc1dc7a3Sopenharmony_ci { 2247cc1dc7a3Sopenharmony_ci printf("Compression\n"); 2248cc1dc7a3Sopenharmony_ci printf("===========\n"); 2249cc1dc7a3Sopenharmony_ci printf("\n"); 2250cc1dc7a3Sopenharmony_ci } 2251cc1dc7a3Sopenharmony_ci 2252cc1dc7a3Sopenharmony_ci double start_iter_time = get_time(); 2253cc1dc7a3Sopenharmony_ci if (cli_config.thread_count > 1) 2254cc1dc7a3Sopenharmony_ci { 2255cc1dc7a3Sopenharmony_ci launch_threads("Compression", cli_config.thread_count, compression_workload_runner, &work); 2256cc1dc7a3Sopenharmony_ci } 2257cc1dc7a3Sopenharmony_ci else 2258cc1dc7a3Sopenharmony_ci { 2259cc1dc7a3Sopenharmony_ci work.error = astcenc_compress_image( 2260cc1dc7a3Sopenharmony_ci work.context, work.image, &work.swizzle, 2261cc1dc7a3Sopenharmony_ci work.data_out, work.data_len, 2262cc1dc7a3Sopenharmony_ci#if QUALITY_CONTROL 2263cc1dc7a3Sopenharmony_ci work.calQualityEnable, work.mse, 2264cc1dc7a3Sopenharmony_ci#endif 2265cc1dc7a3Sopenharmony_ci 0); 2266cc1dc7a3Sopenharmony_ci } 2267cc1dc7a3Sopenharmony_ci 2268cc1dc7a3Sopenharmony_ci astcenc_compress_reset(codec_context); 2269cc1dc7a3Sopenharmony_ci 2270cc1dc7a3Sopenharmony_ci if (config.progress_callback) 2271cc1dc7a3Sopenharmony_ci { 2272cc1dc7a3Sopenharmony_ci printf("\n\n"); 2273cc1dc7a3Sopenharmony_ci } 2274cc1dc7a3Sopenharmony_ci 2275cc1dc7a3Sopenharmony_ci double iter_time = get_time() - start_iter_time; 2276cc1dc7a3Sopenharmony_ci best_compression_time = astc::min(iter_time, best_compression_time); 2277cc1dc7a3Sopenharmony_ci } 2278cc1dc7a3Sopenharmony_ci total_compression_time = get_time() - start_compression_time; 2279cc1dc7a3Sopenharmony_ci 2280cc1dc7a3Sopenharmony_ci if (work.error != ASTCENC_SUCCESS) 2281cc1dc7a3Sopenharmony_ci { 2282cc1dc7a3Sopenharmony_ci print_error("ERROR: Codec compress failed: %s\n", astcenc_get_error_string(work.error)); 2283cc1dc7a3Sopenharmony_ci return 1; 2284cc1dc7a3Sopenharmony_ci } 2285cc1dc7a3Sopenharmony_ci#if QUALITY_CONTROL 2286cc1dc7a3Sopenharmony_ci if (work.calQualityEnable && !CheckQuality(work.mse, blocks_x * blocks_y, config.block_x * config.block_y)) { 2287cc1dc7a3Sopenharmony_ci work.error = ASTCENC_ERR_BAD_QUALITY_CHECK; 2288cc1dc7a3Sopenharmony_ci } 2289cc1dc7a3Sopenharmony_ci if (work.calQualityEnable) { 2290cc1dc7a3Sopenharmony_ci for (int i = R_COM; i < RGBA_COM; i++) { 2291cc1dc7a3Sopenharmony_ci if (work.mse[i]) { 2292cc1dc7a3Sopenharmony_ci free(work.mse[i]); 2293cc1dc7a3Sopenharmony_ci } 2294cc1dc7a3Sopenharmony_ci } 2295cc1dc7a3Sopenharmony_ci } 2296cc1dc7a3Sopenharmony_ci#endif 2297cc1dc7a3Sopenharmony_ci image_comp.block_x = config.block_x; 2298cc1dc7a3Sopenharmony_ci image_comp.block_y = config.block_y; 2299cc1dc7a3Sopenharmony_ci image_comp.block_z = config.block_z; 2300cc1dc7a3Sopenharmony_ci image_comp.dim_x = image_uncomp_in->dim_x; 2301cc1dc7a3Sopenharmony_ci image_comp.dim_y = image_uncomp_in->dim_y; 2302cc1dc7a3Sopenharmony_ci image_comp.dim_z = image_uncomp_in->dim_z; 2303cc1dc7a3Sopenharmony_ci image_comp.data = buffer; 2304cc1dc7a3Sopenharmony_ci image_comp.data_len = buffer_size; 2305cc1dc7a3Sopenharmony_ci } 2306cc1dc7a3Sopenharmony_ci 2307cc1dc7a3Sopenharmony_ci // Decompress an image 2308cc1dc7a3Sopenharmony_ci double best_decompression_time = 100000.0; 2309cc1dc7a3Sopenharmony_ci double total_decompression_time = 0.0; 2310cc1dc7a3Sopenharmony_ci if (operation & ASTCENC_STAGE_DECOMPRESS) 2311cc1dc7a3Sopenharmony_ci { 2312cc1dc7a3Sopenharmony_ci image_decomp_out = alloc_image( 2313cc1dc7a3Sopenharmony_ci out_bitness, image_comp.dim_x, image_comp.dim_y, image_comp.dim_z); 2314cc1dc7a3Sopenharmony_ci 2315cc1dc7a3Sopenharmony_ci decompression_workload work; 2316cc1dc7a3Sopenharmony_ci work.context = codec_context; 2317cc1dc7a3Sopenharmony_ci work.data = image_comp.data; 2318cc1dc7a3Sopenharmony_ci work.data_len = image_comp.data_len; 2319cc1dc7a3Sopenharmony_ci work.image_out = image_decomp_out; 2320cc1dc7a3Sopenharmony_ci work.swizzle = cli_config.swz_decode; 2321cc1dc7a3Sopenharmony_ci work.error = ASTCENC_SUCCESS; 2322cc1dc7a3Sopenharmony_ci 2323cc1dc7a3Sopenharmony_ci // Only launch worker threads for multi-threaded use - it makes basic 2324cc1dc7a3Sopenharmony_ci // single-threaded profiling and debugging a little less convoluted 2325cc1dc7a3Sopenharmony_ci double start_decompression_time = get_time(); 2326cc1dc7a3Sopenharmony_ci for (unsigned int i = 0; i < cli_config.repeat_count; i++) 2327cc1dc7a3Sopenharmony_ci { 2328cc1dc7a3Sopenharmony_ci double start_iter_time = get_time(); 2329cc1dc7a3Sopenharmony_ci if (cli_config.thread_count > 1) 2330cc1dc7a3Sopenharmony_ci { 2331cc1dc7a3Sopenharmony_ci launch_threads("Decompression", cli_config.thread_count, decompression_workload_runner, &work); 2332cc1dc7a3Sopenharmony_ci } 2333cc1dc7a3Sopenharmony_ci else 2334cc1dc7a3Sopenharmony_ci { 2335cc1dc7a3Sopenharmony_ci work.error = astcenc_decompress_image( 2336cc1dc7a3Sopenharmony_ci work.context, work.data, work.data_len, 2337cc1dc7a3Sopenharmony_ci work.image_out, &work.swizzle, 0); 2338cc1dc7a3Sopenharmony_ci } 2339cc1dc7a3Sopenharmony_ci 2340cc1dc7a3Sopenharmony_ci astcenc_decompress_reset(codec_context); 2341cc1dc7a3Sopenharmony_ci 2342cc1dc7a3Sopenharmony_ci double iter_time = get_time() - start_iter_time; 2343cc1dc7a3Sopenharmony_ci best_decompression_time = astc::min(iter_time, best_decompression_time); 2344cc1dc7a3Sopenharmony_ci } 2345cc1dc7a3Sopenharmony_ci total_decompression_time = get_time() - start_decompression_time; 2346cc1dc7a3Sopenharmony_ci 2347cc1dc7a3Sopenharmony_ci if (work.error != ASTCENC_SUCCESS) 2348cc1dc7a3Sopenharmony_ci { 2349cc1dc7a3Sopenharmony_ci print_error("ERROR: Codec decompress failed: %s\n", astcenc_get_error_string(codec_status)); 2350cc1dc7a3Sopenharmony_ci return 1; 2351cc1dc7a3Sopenharmony_ci } 2352cc1dc7a3Sopenharmony_ci } 2353cc1dc7a3Sopenharmony_ci 2354cc1dc7a3Sopenharmony_ci#if defined(_WIN32) 2355cc1dc7a3Sopenharmony_ci bool is_null = output_filename == "NUL" || output_filename == "nul"; 2356cc1dc7a3Sopenharmony_ci#else 2357cc1dc7a3Sopenharmony_ci bool is_null = output_filename == "/dev/null"; 2358cc1dc7a3Sopenharmony_ci#endif 2359cc1dc7a3Sopenharmony_ci 2360cc1dc7a3Sopenharmony_ci // Print metrics in comparison mode 2361cc1dc7a3Sopenharmony_ci if (operation & ASTCENC_STAGE_COMPARE) 2362cc1dc7a3Sopenharmony_ci { 2363cc1dc7a3Sopenharmony_ci bool is_normal_map = config.flags & ASTCENC_FLG_MAP_NORMAL; 2364cc1dc7a3Sopenharmony_ci 2365cc1dc7a3Sopenharmony_ci compute_error_metrics( 2366cc1dc7a3Sopenharmony_ci image_uncomp_in_is_hdr, is_normal_map, image_uncomp_in_component_count, 2367cc1dc7a3Sopenharmony_ci image_uncomp_in, image_decomp_out, cli_config.low_fstop, cli_config.high_fstop); 2368cc1dc7a3Sopenharmony_ci } 2369cc1dc7a3Sopenharmony_ci 2370cc1dc7a3Sopenharmony_ci // Store compressed image 2371cc1dc7a3Sopenharmony_ci if (operation & ASTCENC_STAGE_ST_COMP) 2372cc1dc7a3Sopenharmony_ci { 2373cc1dc7a3Sopenharmony_ci if (ends_with(output_filename, ".astc")) 2374cc1dc7a3Sopenharmony_ci { 2375cc1dc7a3Sopenharmony_ci error = store_cimage(image_comp, output_filename.c_str()); 2376cc1dc7a3Sopenharmony_ci if (error) 2377cc1dc7a3Sopenharmony_ci { 2378cc1dc7a3Sopenharmony_ci print_error("ERROR: Failed to store compressed image\n"); 2379cc1dc7a3Sopenharmony_ci return 1; 2380cc1dc7a3Sopenharmony_ci } 2381cc1dc7a3Sopenharmony_ci } 2382cc1dc7a3Sopenharmony_ci else if (ends_with(output_filename, ".ktx")) 2383cc1dc7a3Sopenharmony_ci { 2384cc1dc7a3Sopenharmony_ci bool srgb = profile == ASTCENC_PRF_LDR_SRGB; 2385cc1dc7a3Sopenharmony_ci error = store_ktx_compressed_image(image_comp, output_filename.c_str(), srgb); 2386cc1dc7a3Sopenharmony_ci if (error) 2387cc1dc7a3Sopenharmony_ci { 2388cc1dc7a3Sopenharmony_ci print_error("ERROR: Failed to store compressed image\n"); 2389cc1dc7a3Sopenharmony_ci return 1; 2390cc1dc7a3Sopenharmony_ci } 2391cc1dc7a3Sopenharmony_ci } 2392cc1dc7a3Sopenharmony_ci else 2393cc1dc7a3Sopenharmony_ci { 2394cc1dc7a3Sopenharmony_ci if (!is_null) 2395cc1dc7a3Sopenharmony_ci { 2396cc1dc7a3Sopenharmony_ci print_error("ERROR: Unknown compressed output file type\n"); 2397cc1dc7a3Sopenharmony_ci return 1; 2398cc1dc7a3Sopenharmony_ci } 2399cc1dc7a3Sopenharmony_ci } 2400cc1dc7a3Sopenharmony_ci } 2401cc1dc7a3Sopenharmony_ci 2402cc1dc7a3Sopenharmony_ci // Store decompressed image 2403cc1dc7a3Sopenharmony_ci if (operation & ASTCENC_STAGE_ST_NCOMP) 2404cc1dc7a3Sopenharmony_ci { 2405cc1dc7a3Sopenharmony_ci if (!is_null) 2406cc1dc7a3Sopenharmony_ci { 2407cc1dc7a3Sopenharmony_ci bool store_result = store_ncimage(image_decomp_out, output_filename.c_str(), 2408cc1dc7a3Sopenharmony_ci cli_config.y_flip); 2409cc1dc7a3Sopenharmony_ci if (!store_result) 2410cc1dc7a3Sopenharmony_ci { 2411cc1dc7a3Sopenharmony_ci print_error("ERROR: Failed to write output image %s\n", output_filename.c_str()); 2412cc1dc7a3Sopenharmony_ci return 1; 2413cc1dc7a3Sopenharmony_ci } 2414cc1dc7a3Sopenharmony_ci } 2415cc1dc7a3Sopenharmony_ci } 2416cc1dc7a3Sopenharmony_ci 2417cc1dc7a3Sopenharmony_ci // Store diagnostic images 2418cc1dc7a3Sopenharmony_ci if (cli_config.diagnostic_images && !is_null) 2419cc1dc7a3Sopenharmony_ci { 2420cc1dc7a3Sopenharmony_ci print_diagnostic_images(codec_context, image_comp, output_filename); 2421cc1dc7a3Sopenharmony_ci } 2422cc1dc7a3Sopenharmony_ci 2423cc1dc7a3Sopenharmony_ci free_image(image_uncomp_in); 2424cc1dc7a3Sopenharmony_ci free_image(image_decomp_out); 2425cc1dc7a3Sopenharmony_ci astcenc_context_free(codec_context); 2426cc1dc7a3Sopenharmony_ci 2427cc1dc7a3Sopenharmony_ci delete[] image_comp.data; 2428cc1dc7a3Sopenharmony_ci 2429cc1dc7a3Sopenharmony_ci if ((operation & ASTCENC_STAGE_COMPARE) || (!cli_config.silentmode)) 2430cc1dc7a3Sopenharmony_ci { 2431cc1dc7a3Sopenharmony_ci double end_time = get_time(); 2432cc1dc7a3Sopenharmony_ci 2433cc1dc7a3Sopenharmony_ci double repeats = static_cast<double>(cli_config.repeat_count); 2434cc1dc7a3Sopenharmony_ci double avg_compression_time = total_compression_time / repeats; 2435cc1dc7a3Sopenharmony_ci double avg_decompression_time = total_decompression_time / repeats; 2436cc1dc7a3Sopenharmony_ci double total_time = (end_time - start_time) - ((repeats - 1.0) * avg_compression_time) - ((repeats - 1.0) * avg_decompression_time); 2437cc1dc7a3Sopenharmony_ci 2438cc1dc7a3Sopenharmony_ci printf("Performance metrics\n"); 2439cc1dc7a3Sopenharmony_ci printf("===================\n\n"); 2440cc1dc7a3Sopenharmony_ci printf(" Total time: %8.4f s\n", total_time); 2441cc1dc7a3Sopenharmony_ci 2442cc1dc7a3Sopenharmony_ci if (operation & ASTCENC_STAGE_COMPRESS) 2443cc1dc7a3Sopenharmony_ci { 2444cc1dc7a3Sopenharmony_ci double compression_rate = image_size / (best_compression_time * 1000000.0); 2445cc1dc7a3Sopenharmony_ci 2446cc1dc7a3Sopenharmony_ci printf(" Coding time: %8.4f s\n", best_compression_time); 2447cc1dc7a3Sopenharmony_ci printf(" Coding rate: %8.4f MT/s\n", compression_rate); 2448cc1dc7a3Sopenharmony_ci } 2449cc1dc7a3Sopenharmony_ci 2450cc1dc7a3Sopenharmony_ci if (operation & ASTCENC_STAGE_DECOMPRESS) 2451cc1dc7a3Sopenharmony_ci { 2452cc1dc7a3Sopenharmony_ci double decompression_rate = image_size / (best_decompression_time * 1000000.0); 2453cc1dc7a3Sopenharmony_ci printf(" Decoding time: %8.4f s\n", best_decompression_time); 2454cc1dc7a3Sopenharmony_ci printf(" Decoding rate: %8.4f MT/s\n", decompression_rate); 2455cc1dc7a3Sopenharmony_ci } 2456cc1dc7a3Sopenharmony_ci } 2457cc1dc7a3Sopenharmony_ci 2458cc1dc7a3Sopenharmony_ci return 0; 2459cc1dc7a3Sopenharmony_ci} 2460